abb-opencode-local-rag 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/README.de.md +416 -0
- package/README.es.md +416 -0
- package/README.fr.md +416 -0
- package/README.md +491 -0
- package/README.pt-BR.md +416 -0
- package/README.zh-CN.md +416 -0
- package/dist/bin/install-skills.d.ts +20 -0
- package/dist/bin/install-skills.d.ts.map +1 -0
- package/dist/bin/install-skills.js +195 -0
- package/dist/bin/install-skills.js.map +1 -0
- package/dist/chunker/index.d.ts +24 -0
- package/dist/chunker/index.d.ts.map +1 -0
- package/dist/chunker/index.js +2 -0
- package/dist/chunker/index.js.map +1 -0
- package/dist/chunker/semantic-chunker.d.ts +97 -0
- package/dist/chunker/semantic-chunker.d.ts.map +1 -0
- package/dist/chunker/semantic-chunker.js +294 -0
- package/dist/chunker/semantic-chunker.js.map +1 -0
- package/dist/chunker/sentence-splitter.d.ts +28 -0
- package/dist/chunker/sentence-splitter.d.ts.map +1 -0
- package/dist/chunker/sentence-splitter.js +219 -0
- package/dist/chunker/sentence-splitter.js.map +1 -0
- package/dist/cli/common.d.ts +65 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +138 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/delete.d.ts +8 -0
- package/dist/cli/delete.d.ts.map +1 -0
- package/dist/cli/delete.js +173 -0
- package/dist/cli/delete.js.map +1 -0
- package/dist/cli/file-collection.d.ts +2 -0
- package/dist/cli/file-collection.d.ts.map +1 -0
- package/dist/cli/file-collection.js +53 -0
- package/dist/cli/file-collection.js.map +1 -0
- package/dist/cli/ingest.d.ts +100 -0
- package/dist/cli/ingest.d.ts.map +1 -0
- package/dist/cli/ingest.js +363 -0
- package/dist/cli/ingest.js.map +1 -0
- package/dist/cli/list.d.ts +35 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +210 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/options.d.ts +100 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +241 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/cli/query.d.ts +24 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +191 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/read-neighbors.d.ts +11 -0
- package/dist/cli/read-neighbors.d.ts.map +1 -0
- package/dist/cli/read-neighbors.js +224 -0
- package/dist/cli/read-neighbors.js.map +1 -0
- package/dist/cli/status.d.ts +8 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +80 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/sync.d.ts +8 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +244 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli-main.d.ts +12 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +63 -0
- package/dist/cli-main.js.map +1 -0
- package/dist/embedder/index.d.ts +85 -0
- package/dist/embedder/index.d.ts.map +1 -0
- package/dist/embedder/index.js +284 -0
- package/dist/embedder/index.js.map +1 -0
- package/dist/features/list.d.ts +37 -0
- package/dist/features/list.d.ts.map +1 -0
- package/dist/features/list.js +40 -0
- package/dist/features/list.js.map +1 -0
- package/dist/features/sync.d.ts +207 -0
- package/dist/features/sync.d.ts.map +1 -0
- package/dist/features/sync.js +380 -0
- package/dist/features/sync.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/compute.d.ts +86 -0
- package/dist/ingest/compute.d.ts.map +1 -0
- package/dist/ingest/compute.js +177 -0
- package/dist/ingest/compute.js.map +1 -0
- package/dist/ingest/file.d.ts +27 -0
- package/dist/ingest/file.d.ts.map +1 -0
- package/dist/ingest/file.js +67 -0
- package/dist/ingest/file.js.map +1 -0
- package/dist/ingest/visual.d.ts +45 -0
- package/dist/ingest/visual.d.ts.map +1 -0
- package/dist/ingest/visual.js +234 -0
- package/dist/ingest/visual.js.map +1 -0
- package/dist/parser/docx-parser.d.ts +12 -0
- package/dist/parser/docx-parser.d.ts.map +1 -0
- package/dist/parser/docx-parser.js +328 -0
- package/dist/parser/docx-parser.js.map +1 -0
- package/dist/parser/html-parser.d.ts +18 -0
- package/dist/parser/html-parser.d.ts.map +1 -0
- package/dist/parser/html-parser.js +102 -0
- package/dist/parser/html-parser.js.map +1 -0
- package/dist/parser/index.d.ts +214 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +454 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/pdf-extract.d.ts +81 -0
- package/dist/parser/pdf-extract.d.ts.map +1 -0
- package/dist/parser/pdf-extract.js +112 -0
- package/dist/parser/pdf-extract.js.map +1 -0
- package/dist/parser/pdf-filter.d.ts +117 -0
- package/dist/parser/pdf-filter.d.ts.map +1 -0
- package/dist/parser/pdf-filter.js +528 -0
- package/dist/parser/pdf-filter.js.map +1 -0
- package/dist/parser/title-extractor.d.ts +69 -0
- package/dist/parser/title-extractor.d.ts.map +1 -0
- package/dist/parser/title-extractor.js +145 -0
- package/dist/parser/title-extractor.js.map +1 -0
- package/dist/pdf-visual/captioner.d.ts +16 -0
- package/dist/pdf-visual/captioner.d.ts.map +1 -0
- package/dist/pdf-visual/captioner.js +63 -0
- package/dist/pdf-visual/captioner.js.map +1 -0
- package/dist/pdf-visual/captioners/fast.d.ts +7 -0
- package/dist/pdf-visual/captioners/fast.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/fast.js +103 -0
- package/dist/pdf-visual/captioners/fast.js.map +1 -0
- package/dist/pdf-visual/captioners/quality.d.ts +7 -0
- package/dist/pdf-visual/captioners/quality.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/quality.js +127 -0
- package/dist/pdf-visual/captioners/quality.js.map +1 -0
- package/dist/pdf-visual/captioners/shared.d.ts +44 -0
- package/dist/pdf-visual/captioners/shared.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/shared.js +104 -0
- package/dist/pdf-visual/captioners/shared.js.map +1 -0
- package/dist/pdf-visual/detector.d.ts +9 -0
- package/dist/pdf-visual/detector.d.ts.map +1 -0
- package/dist/pdf-visual/detector.js +234 -0
- package/dist/pdf-visual/detector.js.map +1 -0
- package/dist/pdf-visual/index.d.ts +13 -0
- package/dist/pdf-visual/index.d.ts.map +1 -0
- package/dist/pdf-visual/index.js +45 -0
- package/dist/pdf-visual/index.js.map +1 -0
- package/dist/pdf-visual/renderer.d.ts +9 -0
- package/dist/pdf-visual/renderer.d.ts.map +1 -0
- package/dist/pdf-visual/renderer.js +177 -0
- package/dist/pdf-visual/renderer.js.map +1 -0
- package/dist/pdf-visual/types.d.ts +62 -0
- package/dist/pdf-visual/types.d.ts.map +1 -0
- package/dist/pdf-visual/types.js +32 -0
- package/dist/pdf-visual/types.js.map +1 -0
- package/dist/server/error-utils.d.ts +79 -0
- package/dist/server/error-utils.d.ts.map +1 -0
- package/dist/server/error-utils.js +148 -0
- package/dist/server/error-utils.js.map +1 -0
- package/dist/server/index.d.ts +258 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1104 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/list-scanner.d.ts +52 -0
- package/dist/server/list-scanner.d.ts.map +1 -0
- package/dist/server/list-scanner.js +72 -0
- package/dist/server/list-scanner.js.map +1 -0
- package/dist/server/tool-definitions.d.ts +8 -0
- package/dist/server/tool-definitions.d.ts.map +1 -0
- package/dist/server/tool-definitions.js +181 -0
- package/dist/server/tool-definitions.js.map +1 -0
- package/dist/server/tool-input.d.ts +37 -0
- package/dist/server/tool-input.d.ts.map +1 -0
- package/dist/server/tool-input.js +216 -0
- package/dist/server/tool-input.js.map +1 -0
- package/dist/server/types.d.ts +331 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +3 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server-main.d.ts +46 -0
- package/dist/server-main.d.ts.map +1 -0
- package/dist/server-main.js +242 -0
- package/dist/server-main.js.map +1 -0
- package/dist/utils/base-dirs.d.ts +212 -0
- package/dist/utils/base-dirs.d.ts.map +1 -0
- package/dist/utils/base-dirs.js +422 -0
- package/dist/utils/base-dirs.js.map +1 -0
- package/dist/utils/errors.d.ts +24 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +53 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/limits.d.ts +26 -0
- package/dist/utils/limits.d.ts.map +1 -0
- package/dist/utils/limits.js +28 -0
- package/dist/utils/limits.js.map +1 -0
- package/dist/utils/list-sources.d.ts +47 -0
- package/dist/utils/list-sources.d.ts.map +1 -0
- package/dist/utils/list-sources.js +50 -0
- package/dist/utils/list-sources.js.map +1 -0
- package/dist/utils/raw-data-utils.d.ts +131 -0
- package/dist/utils/raw-data-utils.d.ts.map +1 -0
- package/dist/utils/raw-data-utils.js +255 -0
- package/dist/utils/raw-data-utils.js.map +1 -0
- package/dist/utils/scan.d.ts +126 -0
- package/dist/utils/scan.d.ts.map +1 -0
- package/dist/utils/scan.js +221 -0
- package/dist/utils/scan.js.map +1 -0
- package/dist/utils/scope-match.d.ts +43 -0
- package/dist/utils/scope-match.d.ts.map +1 -0
- package/dist/utils/scope-match.js +87 -0
- package/dist/utils/scope-match.js.map +1 -0
- package/dist/utils/sensitive-path.d.ts +23 -0
- package/dist/utils/sensitive-path.d.ts.map +1 -0
- package/dist/utils/sensitive-path.js +91 -0
- package/dist/utils/sensitive-path.js.map +1 -0
- package/dist/utils/sync-path-key.d.ts +20 -0
- package/dist/utils/sync-path-key.d.ts.map +1 -0
- package/dist/utils/sync-path-key.js +33 -0
- package/dist/utils/sync-path-key.js.map +1 -0
- package/dist/vectordb/index.d.ts +168 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +619 -0
- package/dist/vectordb/index.js.map +1 -0
- package/dist/vectordb/search-filters.d.ts +39 -0
- package/dist/vectordb/search-filters.d.ts.map +1 -0
- package/dist/vectordb/search-filters.js +136 -0
- package/dist/vectordb/search-filters.js.map +1 -0
- package/dist/vectordb/types.d.ts +196 -0
- package/dist/vectordb/types.d.ts.map +1 -0
- package/dist/vectordb/types.js +224 -0
- package/dist/vectordb/types.js.map +1 -0
- package/package.json +105 -0
- package/skills/mcp-local-rag/SKILL.md +308 -0
- package/skills/mcp-local-rag/references/cli-reference.md +175 -0
- package/skills/mcp-local-rag/references/html-ingestion.md +78 -0
- package/skills/mcp-local-rag/references/query-optimization.md +57 -0
- package/skills/mcp-local-rag/references/result-refinement.md +56 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
// PDF Header/Footer Filter
|
|
2
|
+
// - Detects and removes repeating patterns across pages
|
|
3
|
+
// - Semantic similarity-based header/footer detection (sentence-level)
|
|
4
|
+
import { splitIntoSentences } from '../chunker/sentence-splitter.js';
|
|
5
|
+
// ============================================
|
|
6
|
+
// Text Joining
|
|
7
|
+
// ============================================
|
|
8
|
+
/**
|
|
9
|
+
* Join page items into text
|
|
10
|
+
*
|
|
11
|
+
* Preserves the native item stream. `hasEOL` distinguishes fragments on the
|
|
12
|
+
* same native line from the next line; geometry is retained as placement
|
|
13
|
+
* metadata and is not used as a global reading-order comparator.
|
|
14
|
+
*/
|
|
15
|
+
function buildPageLayout(pageNum, items) {
|
|
16
|
+
let rawText = '';
|
|
17
|
+
let previousItem;
|
|
18
|
+
const rawFragments = [];
|
|
19
|
+
const fragmentCounts = new Map();
|
|
20
|
+
const orderedItems = [...items].sort((left, right) => Math.round(right.y) - Math.round(left.y) || left.x - right.x);
|
|
21
|
+
for (let itemIndex = 0; itemIndex < orderedItems.length; itemIndex++) {
|
|
22
|
+
const item = orderedItems[itemIndex];
|
|
23
|
+
if (!item || item.text.trim().length === 0)
|
|
24
|
+
continue;
|
|
25
|
+
if (previousItem) {
|
|
26
|
+
rawText += Math.round(previousItem.y) === Math.round(item.y) ? ' ' : '\n';
|
|
27
|
+
}
|
|
28
|
+
const rawStart = rawText.length;
|
|
29
|
+
rawText += item.text;
|
|
30
|
+
const rawEnd = rawText.length;
|
|
31
|
+
const blockOrdinal = item.blockOrdinal ?? 0;
|
|
32
|
+
const lineOrdinal = item.lineOrdinal ?? itemIndex;
|
|
33
|
+
const lineKey = `${blockOrdinal}:${lineOrdinal}`;
|
|
34
|
+
const fragmentOrdinal = fragmentCounts.get(lineKey) ?? 0;
|
|
35
|
+
fragmentCounts.set(lineKey, fragmentOrdinal + 1);
|
|
36
|
+
rawFragments.push({
|
|
37
|
+
pageNum,
|
|
38
|
+
blockOrdinal,
|
|
39
|
+
lineOrdinal,
|
|
40
|
+
fragmentOrdinal,
|
|
41
|
+
bbox: item.bbox ?? [item.x, item.y, item.x, item.y],
|
|
42
|
+
rawStart,
|
|
43
|
+
rawEnd,
|
|
44
|
+
});
|
|
45
|
+
previousItem = item;
|
|
46
|
+
}
|
|
47
|
+
const leadingWhitespace = rawText.length - rawText.trimStart().length;
|
|
48
|
+
const trailingBoundary = rawText.trimEnd().length;
|
|
49
|
+
const text = rawText.slice(leadingWhitespace, trailingBoundary);
|
|
50
|
+
const textFragments = [];
|
|
51
|
+
for (const fragment of rawFragments) {
|
|
52
|
+
const clippedStart = Math.max(fragment.rawStart, leadingWhitespace);
|
|
53
|
+
const clippedEnd = Math.min(fragment.rawEnd, trailingBoundary);
|
|
54
|
+
if (clippedStart >= clippedEnd)
|
|
55
|
+
continue;
|
|
56
|
+
const pageTextStart = clippedStart - leadingWhitespace;
|
|
57
|
+
const pageTextEnd = clippedEnd - leadingWhitespace;
|
|
58
|
+
textFragments.push({
|
|
59
|
+
pageNum: fragment.pageNum,
|
|
60
|
+
blockOrdinal: fragment.blockOrdinal,
|
|
61
|
+
lineOrdinal: fragment.lineOrdinal,
|
|
62
|
+
fragmentOrdinal: fragment.fragmentOrdinal,
|
|
63
|
+
bbox: fragment.bbox,
|
|
64
|
+
text: text.slice(pageTextStart, pageTextEnd),
|
|
65
|
+
pageTextStart,
|
|
66
|
+
pageTextEnd,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return { text, textFragments };
|
|
70
|
+
}
|
|
71
|
+
function buildSentenceLayout(pageNum, sentences, items) {
|
|
72
|
+
let text = '';
|
|
73
|
+
const textFragments = [];
|
|
74
|
+
for (const sentence of sentences) {
|
|
75
|
+
if (text)
|
|
76
|
+
text += ' ';
|
|
77
|
+
const start = text.length;
|
|
78
|
+
text += sentence.text;
|
|
79
|
+
const matchingItems = items.filter((item) => Math.round(item.y) === Math.round(sentence.y));
|
|
80
|
+
const first = matchingItems[0];
|
|
81
|
+
const boxes = matchingItems.map((item) => item.bbox ?? [item.x, item.y, item.x, item.y]);
|
|
82
|
+
const bbox = boxes.length
|
|
83
|
+
? [
|
|
84
|
+
Math.min(...boxes.map((box) => box[0])),
|
|
85
|
+
Math.min(...boxes.map((box) => box[1])),
|
|
86
|
+
Math.max(...boxes.map((box) => box[2])),
|
|
87
|
+
Math.max(...boxes.map((box) => box[3])),
|
|
88
|
+
]
|
|
89
|
+
: [0, 0, 0, 0];
|
|
90
|
+
textFragments.push({
|
|
91
|
+
pageNum,
|
|
92
|
+
blockOrdinal: first?.blockOrdinal ?? 0,
|
|
93
|
+
lineOrdinal: first?.lineOrdinal ?? textFragments.length,
|
|
94
|
+
fragmentOrdinal: 0,
|
|
95
|
+
bbox,
|
|
96
|
+
text: sentence.text,
|
|
97
|
+
pageTextStart: start,
|
|
98
|
+
pageTextEnd: text.length,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return { text, textFragments };
|
|
102
|
+
}
|
|
103
|
+
function joinPageItems(items) {
|
|
104
|
+
return buildPageLayout(0, items).text;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Join filtered pages into text
|
|
108
|
+
*
|
|
109
|
+
* @param pages - Filtered page data
|
|
110
|
+
* @returns Joined text with proper line breaks
|
|
111
|
+
*/
|
|
112
|
+
export function joinFilteredPages(pages) {
|
|
113
|
+
return pages
|
|
114
|
+
.map((page) => joinPageItems(page.items))
|
|
115
|
+
.filter((text) => text.length > 0)
|
|
116
|
+
.join('\n\n');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Split page items into sentences with Y coordinate
|
|
120
|
+
*
|
|
121
|
+
* 1. Join items into text (preserving item boundaries)
|
|
122
|
+
* 2. Split into sentences using splitIntoSentences
|
|
123
|
+
* 3. Map each sentence to the Y coordinate of its first item
|
|
124
|
+
* 4. Merge sentences with same Y coordinate
|
|
125
|
+
*
|
|
126
|
+
* @param items - Text items with position
|
|
127
|
+
* @returns Sentences with Y coordinate (merged by Y)
|
|
128
|
+
*/
|
|
129
|
+
function splitItemsIntoSentencesWithY(items) {
|
|
130
|
+
if (items.length === 0)
|
|
131
|
+
return [];
|
|
132
|
+
// Sort items by Y descending, then X ascending (reading order)
|
|
133
|
+
const sortedItems = [...items].sort((a, b) => {
|
|
134
|
+
const yDiff = b.y - a.y;
|
|
135
|
+
if (Math.abs(yDiff) > 1)
|
|
136
|
+
return yDiff;
|
|
137
|
+
return a.x - b.x;
|
|
138
|
+
});
|
|
139
|
+
// Build text and track character positions to item mapping
|
|
140
|
+
const charToItem = [];
|
|
141
|
+
let fullText = '';
|
|
142
|
+
let prevY = null;
|
|
143
|
+
for (const item of sortedItems) {
|
|
144
|
+
// Insert newline when Y coordinate changes (different line)
|
|
145
|
+
// This matches joinPageItems behavior: same Y = space, different Y = newline
|
|
146
|
+
if (prevY !== null && Math.abs(prevY - item.y) > 1) {
|
|
147
|
+
fullText = `${fullText.trimEnd()}\n`;
|
|
148
|
+
}
|
|
149
|
+
charToItem.push({ start: fullText.length, item });
|
|
150
|
+
fullText += `${item.text} `;
|
|
151
|
+
prevY = item.y;
|
|
152
|
+
}
|
|
153
|
+
// Split into sentences
|
|
154
|
+
const sentences = splitIntoSentences(fullText);
|
|
155
|
+
// Map each sentence to Y coordinate of its first character's item
|
|
156
|
+
const sentencesWithY = [];
|
|
157
|
+
let searchStart = 0;
|
|
158
|
+
for (const sentence of sentences) {
|
|
159
|
+
// Find where this sentence starts in fullText
|
|
160
|
+
const sentenceStart = fullText.indexOf(sentence.trim(), searchStart);
|
|
161
|
+
// Benign skip (not error masking): this builds the Y-coordinate map used
|
|
162
|
+
// only for header/footer boundary detection. A miss means this sentence
|
|
163
|
+
// is omitted from boundary detection — it does NOT drop the sentence from
|
|
164
|
+
// the document body (that text comes from `fullText`). Misses are expected
|
|
165
|
+
// when `splitIntoSentences` normalizes whitespace differently than the
|
|
166
|
+
// reconstructed `fullText`, so logging here would be noise, not signal.
|
|
167
|
+
if (sentenceStart === -1)
|
|
168
|
+
continue;
|
|
169
|
+
// Find the item that contains this position
|
|
170
|
+
let firstItemY = sortedItems[0]?.y ?? 0;
|
|
171
|
+
for (let i = charToItem.length - 1; i >= 0; i--) {
|
|
172
|
+
const entry = charToItem[i];
|
|
173
|
+
if (entry && entry.start <= sentenceStart) {
|
|
174
|
+
firstItemY = Math.round(entry.item.y);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
sentencesWithY.push({ text: sentence, y: firstItemY });
|
|
179
|
+
searchStart = sentenceStart + sentence.length;
|
|
180
|
+
}
|
|
181
|
+
// Merge sentences with same Y coordinate
|
|
182
|
+
return mergeSentencesByY(sentencesWithY);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Merge sentences with same Y coordinate
|
|
186
|
+
*
|
|
187
|
+
* @param sentences - Sentences with Y coordinate
|
|
188
|
+
* @returns Merged sentences (same Y = one sentence)
|
|
189
|
+
*/
|
|
190
|
+
function mergeSentencesByY(sentences) {
|
|
191
|
+
if (sentences.length === 0)
|
|
192
|
+
return [];
|
|
193
|
+
const merged = [];
|
|
194
|
+
let current = null;
|
|
195
|
+
for (const sentence of sentences) {
|
|
196
|
+
if (current === null) {
|
|
197
|
+
current = { ...sentence };
|
|
198
|
+
}
|
|
199
|
+
else if (current.y === sentence.y) {
|
|
200
|
+
// Same Y: merge text
|
|
201
|
+
current.text += ` ${sentence.text}`;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Different Y: push current and start new
|
|
205
|
+
merged.push(current);
|
|
206
|
+
current = { ...sentence };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (current !== null) {
|
|
210
|
+
merged.push(current);
|
|
211
|
+
}
|
|
212
|
+
return merged;
|
|
213
|
+
}
|
|
214
|
+
// ============================================
|
|
215
|
+
// Sentence-Level Header/Footer Detection
|
|
216
|
+
// ============================================
|
|
217
|
+
/**
|
|
218
|
+
* Calculate cosine similarity between two vectors
|
|
219
|
+
*/
|
|
220
|
+
function cosineSimilarity(vec1, vec2) {
|
|
221
|
+
if (vec1.length !== vec2.length || vec1.length === 0) {
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
let dotProduct = 0;
|
|
225
|
+
let norm1 = 0;
|
|
226
|
+
let norm2 = 0;
|
|
227
|
+
for (let i = 0; i < vec1.length; i++) {
|
|
228
|
+
const v1 = vec1[i] ?? 0;
|
|
229
|
+
const v2 = vec2[i] ?? 0;
|
|
230
|
+
dotProduct += v1 * v2;
|
|
231
|
+
norm1 += v1 * v1;
|
|
232
|
+
norm2 += v2 * v2;
|
|
233
|
+
}
|
|
234
|
+
const denominator = Math.sqrt(norm1) * Math.sqrt(norm2);
|
|
235
|
+
if (denominator === 0)
|
|
236
|
+
return 0;
|
|
237
|
+
return dotProduct / denominator;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Calculate median pairwise similarity for a list of embeddings
|
|
241
|
+
*
|
|
242
|
+
* Uses median instead of mean for robustness against outliers.
|
|
243
|
+
* This handles cases where some pages have different header content
|
|
244
|
+
* (e.g., chapter title changes) that would otherwise drag down the average.
|
|
245
|
+
*/
|
|
246
|
+
function medianPairwiseSimilarity(embeddings) {
|
|
247
|
+
if (embeddings.length < 2)
|
|
248
|
+
return 1.0;
|
|
249
|
+
const similarities = [];
|
|
250
|
+
for (let i = 0; i < embeddings.length; i++) {
|
|
251
|
+
for (let j = i + 1; j < embeddings.length; j++) {
|
|
252
|
+
const embI = embeddings[i];
|
|
253
|
+
const embJ = embeddings[j];
|
|
254
|
+
if (embI && embJ) {
|
|
255
|
+
similarities.push(cosineSimilarity(embI, embJ));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (similarities.length === 0)
|
|
260
|
+
return 0;
|
|
261
|
+
// Sort and find median
|
|
262
|
+
similarities.sort((a, b) => a - b);
|
|
263
|
+
const mid = Math.floor(similarities.length / 2);
|
|
264
|
+
if (similarities.length % 2 === 0) {
|
|
265
|
+
// Even: average of two middle values
|
|
266
|
+
return ((similarities[mid - 1] ?? 0) + (similarities[mid] ?? 0)) / 2;
|
|
267
|
+
}
|
|
268
|
+
// Odd: middle value
|
|
269
|
+
return similarities[mid] ?? 0;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Sample pages from the center of the document
|
|
273
|
+
*
|
|
274
|
+
* Center pages are guaranteed to be content (not cover, TOC, or index).
|
|
275
|
+
*/
|
|
276
|
+
function sampleCenterPages(pages, sampleSize) {
|
|
277
|
+
const centerIndex = Math.floor(pages.length / 2);
|
|
278
|
+
const halfSample = Math.floor(sampleSize / 2);
|
|
279
|
+
const startIndex = Math.max(0, centerIndex - halfSample);
|
|
280
|
+
const endIndex = Math.min(pages.length, startIndex + sampleSize);
|
|
281
|
+
return pages.slice(startIndex, endIndex);
|
|
282
|
+
}
|
|
283
|
+
/** Default configuration for sentence-level pattern detection */
|
|
284
|
+
const DEFAULT_SENTENCE_PATTERN_CONFIG = {
|
|
285
|
+
similarityThreshold: 0.85,
|
|
286
|
+
minPages: 3,
|
|
287
|
+
samplePages: 5,
|
|
288
|
+
boostedThreshold: 0.75,
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* Detect candidate header/footer lines based on font size and Y position
|
|
292
|
+
*
|
|
293
|
+
* Stage 1 of the 2-stage header/footer detection:
|
|
294
|
+
* 1. Sample center pages (same logic as detectSentencePatterns)
|
|
295
|
+
* 2. Calculate median font size from all items across sampled pages
|
|
296
|
+
* 3. Identify header candidates: fontSize < medianFontSize * 0.7 AND y > pageHeight * 0.9
|
|
297
|
+
* 4. Identify footer candidates: fontSize < medianFontSize * 0.7 AND y < pageHeight * 0.1
|
|
298
|
+
*
|
|
299
|
+
* @param pages - Array of page data
|
|
300
|
+
* @param config - Configuration options (minPages, samplePages)
|
|
301
|
+
* @returns Block attribute hints with candidate Y positions
|
|
302
|
+
*/
|
|
303
|
+
export function detectBlockAttributeCandidates(pages, config = {}) {
|
|
304
|
+
const cfg = { ...DEFAULT_SENTENCE_PATTERN_CONFIG, ...config };
|
|
305
|
+
const emptyResult = {
|
|
306
|
+
medianFontSize: 0,
|
|
307
|
+
headerCandidateYs: new Set(),
|
|
308
|
+
footerCandidateYs: new Set(),
|
|
309
|
+
};
|
|
310
|
+
if (pages.length < cfg.minPages)
|
|
311
|
+
return emptyResult;
|
|
312
|
+
const samplePages = sampleCenterPages(pages, cfg.samplePages);
|
|
313
|
+
// Collect all font sizes
|
|
314
|
+
const fontSizes = [];
|
|
315
|
+
for (const page of samplePages) {
|
|
316
|
+
for (const item of page.items) {
|
|
317
|
+
if (item.fontSize > 0)
|
|
318
|
+
fontSizes.push(item.fontSize);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (fontSizes.length === 0)
|
|
322
|
+
return emptyResult;
|
|
323
|
+
// Calculate median font size
|
|
324
|
+
fontSizes.sort((a, b) => a - b);
|
|
325
|
+
const mid = Math.floor(fontSizes.length / 2);
|
|
326
|
+
const medianFontSize = fontSizes.length % 2 === 0 ? (fontSizes[mid - 1] + fontSizes[mid]) / 2 : fontSizes[mid];
|
|
327
|
+
if (medianFontSize === 0)
|
|
328
|
+
return { ...emptyResult, medianFontSize };
|
|
329
|
+
// Use actual page height if available, otherwise estimate from max Y
|
|
330
|
+
const firstPageWithHeight = samplePages.find((p) => p.pageHeight != null);
|
|
331
|
+
let pageHeight;
|
|
332
|
+
if (firstPageWithHeight?.pageHeight) {
|
|
333
|
+
pageHeight = firstPageWithHeight.pageHeight;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
let maxY = 0;
|
|
337
|
+
for (const page of samplePages) {
|
|
338
|
+
for (const item of page.items) {
|
|
339
|
+
if (item.y > maxY)
|
|
340
|
+
maxY = item.y;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
pageHeight = maxY;
|
|
344
|
+
}
|
|
345
|
+
if (pageHeight === 0)
|
|
346
|
+
return { ...emptyResult, medianFontSize };
|
|
347
|
+
const fontSizeThreshold = medianFontSize * 0.7;
|
|
348
|
+
const headerCandidateYs = new Set();
|
|
349
|
+
const footerCandidateYs = new Set();
|
|
350
|
+
// Scan items: small font + extreme Y position = candidate
|
|
351
|
+
for (const page of samplePages) {
|
|
352
|
+
for (const item of page.items) {
|
|
353
|
+
if (item.fontSize >= fontSizeThreshold)
|
|
354
|
+
continue;
|
|
355
|
+
const roundedY = Math.round(item.y);
|
|
356
|
+
// Header: top 10% of page (large Y values, since Y is inverted)
|
|
357
|
+
if (item.y > pageHeight * 0.9) {
|
|
358
|
+
headerCandidateYs.add(roundedY);
|
|
359
|
+
}
|
|
360
|
+
// Footer: bottom 10% of page (small Y values)
|
|
361
|
+
if (item.y < pageHeight * 0.1) {
|
|
362
|
+
footerCandidateYs.add(roundedY);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return { medianFontSize, headerCandidateYs, footerCandidateYs };
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Detect header/footer patterns at sentence level
|
|
370
|
+
*
|
|
371
|
+
* Algorithm:
|
|
372
|
+
* 1. Sample pages from the CENTER of the document (guaranteed to be content pages)
|
|
373
|
+
* 2. Split each page into sentences with Y coordinate
|
|
374
|
+
* 3. Collect first/last sentences from sampled pages
|
|
375
|
+
* 4. Embed and calculate median pairwise similarity
|
|
376
|
+
* 5. If similarity > threshold, mark as header/footer
|
|
377
|
+
*
|
|
378
|
+
* Key insight: Middle pages are always content pages (cover, TOC, index are at edges).
|
|
379
|
+
* Using median instead of mean provides robustness against outliers.
|
|
380
|
+
*
|
|
381
|
+
* This approach handles variable content like page numbers ("7 of 75")
|
|
382
|
+
* by using semantic similarity instead of exact text matching.
|
|
383
|
+
*
|
|
384
|
+
* @param pages - Array of page data
|
|
385
|
+
* @param embedder - Embedder for generating embeddings
|
|
386
|
+
* @param config - Configuration options
|
|
387
|
+
* @returns Detection result
|
|
388
|
+
*/
|
|
389
|
+
/**
|
|
390
|
+
* Shared boundary-pattern detection for the header (first-sentence) and footer
|
|
391
|
+
* (last-sentence) cases of {@link detectSentencePatterns}. Embeds the sampled
|
|
392
|
+
* boundary sentences, computes their median pairwise similarity, applies the
|
|
393
|
+
* (optionally block-hint-boosted) threshold, logs on detection, and returns
|
|
394
|
+
* the similarity plus the detection flag. The divergent part — which sentence
|
|
395
|
+
* each page contributes and how its Y is derived — is computed by the caller
|
|
396
|
+
* and passed in via `sentences` / `sentenceYs`, so this helper is identical
|
|
397
|
+
* for both boundaries.
|
|
398
|
+
*/
|
|
399
|
+
async function detectBoundaryPattern(params) {
|
|
400
|
+
const { label, sentences, sentenceYs, candidateYs, similarityThreshold, boostedThreshold, embedder, startIndex, endIndex, } = params;
|
|
401
|
+
const embeddings = await embedder.embedBatch(sentences);
|
|
402
|
+
const medianSim = medianPairwiseSimilarity(embeddings);
|
|
403
|
+
// Determine effective threshold (boosted if block hints match)
|
|
404
|
+
let threshold = similarityThreshold;
|
|
405
|
+
if (candidateYs && sentenceYs.some((y) => candidateYs.has(y))) {
|
|
406
|
+
threshold = boostedThreshold ?? 0.75;
|
|
407
|
+
}
|
|
408
|
+
const detected = medianSim >= threshold;
|
|
409
|
+
if (detected) {
|
|
410
|
+
console.error(`Sentence ${label} detected: sampled ${sentences.length} center pages (${startIndex + 1}-${endIndex}), median similarity: ${medianSim.toFixed(3)}`);
|
|
411
|
+
}
|
|
412
|
+
return { similarity: medianSim, detected };
|
|
413
|
+
}
|
|
414
|
+
export async function detectSentencePatterns(pages, embedder, config = {}) {
|
|
415
|
+
const cfg = { ...DEFAULT_SENTENCE_PATTERN_CONFIG, ...config };
|
|
416
|
+
const result = {
|
|
417
|
+
removeFirstSentence: false,
|
|
418
|
+
removeLastSentence: false,
|
|
419
|
+
headerSimilarity: 0,
|
|
420
|
+
footerSimilarity: 0,
|
|
421
|
+
};
|
|
422
|
+
// Need minimum pages to detect patterns reliably
|
|
423
|
+
if (pages.length < cfg.minPages) {
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
426
|
+
// 1. Sample pages from the CENTER of the document
|
|
427
|
+
const samplePages = sampleCenterPages(pages, cfg.samplePages);
|
|
428
|
+
const startIndex = pages.indexOf(samplePages[0]);
|
|
429
|
+
const endIndex = startIndex + samplePages.length;
|
|
430
|
+
// 2. Split each page into sentences with Y coordinate (merged by Y)
|
|
431
|
+
const pageSentences = samplePages.map((page) => splitItemsIntoSentencesWithY(page.items));
|
|
432
|
+
// 3. Collect first and last sentences from sampled pages
|
|
433
|
+
const firstSentences = [];
|
|
434
|
+
const lastSentences = [];
|
|
435
|
+
for (const sentences of pageSentences) {
|
|
436
|
+
if (sentences.length > 0) {
|
|
437
|
+
firstSentences.push(sentences[0].text);
|
|
438
|
+
if (sentences.length > 1) {
|
|
439
|
+
lastSentences.push(sentences[sentences.length - 1].text);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// 5. Detect header pattern (sampled first sentences are semantically similar)
|
|
444
|
+
if (firstSentences.length >= cfg.minPages) {
|
|
445
|
+
const firstSentenceYs = pageSentences
|
|
446
|
+
.filter((s) => s.length > 0)
|
|
447
|
+
.map((s) => Math.round(s[0].y));
|
|
448
|
+
const { similarity, detected } = await detectBoundaryPattern({
|
|
449
|
+
label: 'header',
|
|
450
|
+
sentences: firstSentences,
|
|
451
|
+
sentenceYs: firstSentenceYs,
|
|
452
|
+
candidateYs: cfg.blockHints?.headerCandidateYs,
|
|
453
|
+
similarityThreshold: cfg.similarityThreshold,
|
|
454
|
+
boostedThreshold: cfg.boostedThreshold,
|
|
455
|
+
embedder,
|
|
456
|
+
startIndex,
|
|
457
|
+
endIndex,
|
|
458
|
+
});
|
|
459
|
+
result.headerSimilarity = similarity;
|
|
460
|
+
result.removeFirstSentence = detected;
|
|
461
|
+
}
|
|
462
|
+
// 6. Detect footer pattern (sampled last sentences are semantically similar)
|
|
463
|
+
if (lastSentences.length >= cfg.minPages) {
|
|
464
|
+
const lastSentenceYs = pageSentences
|
|
465
|
+
.filter((s) => s.length > 1)
|
|
466
|
+
.map((s) => Math.round(s[s.length - 1].y));
|
|
467
|
+
const { similarity, detected } = await detectBoundaryPattern({
|
|
468
|
+
label: 'footer',
|
|
469
|
+
sentences: lastSentences,
|
|
470
|
+
sentenceYs: lastSentenceYs,
|
|
471
|
+
candidateYs: cfg.blockHints?.footerCandidateYs,
|
|
472
|
+
similarityThreshold: cfg.similarityThreshold,
|
|
473
|
+
boostedThreshold: cfg.boostedThreshold,
|
|
474
|
+
embedder,
|
|
475
|
+
startIndex,
|
|
476
|
+
endIndex,
|
|
477
|
+
});
|
|
478
|
+
result.footerSimilarity = similarity;
|
|
479
|
+
result.removeLastSentence = detected;
|
|
480
|
+
}
|
|
481
|
+
return result;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Filter page boundary sentences and return per-page filtered text
|
|
485
|
+
*
|
|
486
|
+
* This is the main entry point for sentence-level header/footer filtering.
|
|
487
|
+
* It detects and removes repeating sentence patterns at page boundaries.
|
|
488
|
+
* Returns an array of filtered text per page, preserving page boundaries.
|
|
489
|
+
*
|
|
490
|
+
* Use this instead of joinFilteredPages when embedder is available.
|
|
491
|
+
*
|
|
492
|
+
* @param pages - Array of page data
|
|
493
|
+
* @param embedder - Embedder for generating embeddings
|
|
494
|
+
* @param config - Configuration options
|
|
495
|
+
* @returns Array of filtered text strings, one per page
|
|
496
|
+
*/
|
|
497
|
+
export async function filterPageBoundarySentences(pages, embedder, config = {}) {
|
|
498
|
+
return (await filterPageBoundaryLayouts(pages, embedder, config)).map((page) => page.text);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Filter page boundaries while retaining native provenance for every survivor.
|
|
502
|
+
*/
|
|
503
|
+
export async function filterPageBoundaryLayouts(pages, embedder, config = {}) {
|
|
504
|
+
const cfg = { ...DEFAULT_SENTENCE_PATTERN_CONFIG, ...config };
|
|
505
|
+
// Need minimum pages to detect patterns
|
|
506
|
+
if (pages.length < cfg.minPages) {
|
|
507
|
+
return pages.map((page) => buildPageLayout(page.pageNum, page.items));
|
|
508
|
+
}
|
|
509
|
+
// Detect block attribute candidates for boosted threshold
|
|
510
|
+
const blockHints = detectBlockAttributeCandidates(pages, cfg);
|
|
511
|
+
// Detect patterns (with block hints for boosted threshold)
|
|
512
|
+
const patterns = await detectSentencePatterns(pages, embedder, { ...cfg, blockHints });
|
|
513
|
+
// If no patterns detected, return normally joined text per page
|
|
514
|
+
if (!patterns.removeFirstSentence && !patterns.removeLastSentence) {
|
|
515
|
+
return pages.map((page) => buildPageLayout(page.pageNum, page.items));
|
|
516
|
+
}
|
|
517
|
+
// Split each page into sentences with Y coordinate (merged by Y)
|
|
518
|
+
const pageSentences = pages.map((page) => splitItemsIntoSentencesWithY(page.items));
|
|
519
|
+
return pages.map((page, pageIndex) => {
|
|
520
|
+
let cleaned = [...(pageSentences[pageIndex] ?? [])];
|
|
521
|
+
if (patterns.removeFirstSentence && cleaned.length > 0)
|
|
522
|
+
cleaned = cleaned.slice(1);
|
|
523
|
+
if (patterns.removeLastSentence && cleaned.length > 0)
|
|
524
|
+
cleaned = cleaned.slice(0, -1);
|
|
525
|
+
return buildSentenceLayout(page.pageNum, cleaned, page.items);
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
//# sourceMappingURL=pdf-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-filter.js","sourceRoot":"","sources":["../../src/parser/pdf-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result of title extraction, including how the title was determined
|
|
3
|
+
*/
|
|
4
|
+
export interface TitleExtractionResult {
|
|
5
|
+
title: string;
|
|
6
|
+
source: 'metadata' | 'content' | 'filename';
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Convert a file name to a human-readable title
|
|
10
|
+
* Strips the extension and replaces hyphens/underscores with spaces
|
|
11
|
+
*
|
|
12
|
+
* @param fileName - File name (e.g., "2024-annual-report.pdf")
|
|
13
|
+
* @returns Human-readable title (e.g., "2024 annual report")
|
|
14
|
+
*/
|
|
15
|
+
export declare function fileNameToTitle(fileName: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Extract title from Markdown content
|
|
18
|
+
* Priority: YAML frontmatter title -> first # H1 -> file name
|
|
19
|
+
*
|
|
20
|
+
* @param text - Markdown content
|
|
21
|
+
* @param fileName - File name for fallback
|
|
22
|
+
* @returns Title extraction result
|
|
23
|
+
*/
|
|
24
|
+
export declare function extractMarkdownTitle(text: string, fileName: string): TitleExtractionResult;
|
|
25
|
+
/**
|
|
26
|
+
* Extract title from plain text content
|
|
27
|
+
* Priority: first line followed by empty line -> file name
|
|
28
|
+
*
|
|
29
|
+
* @param text - Plain text content
|
|
30
|
+
* @param fileName - File name for fallback
|
|
31
|
+
* @returns Title extraction result
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractTxtTitle(text: string, fileName: string): TitleExtractionResult;
|
|
34
|
+
/**
|
|
35
|
+
* Extract title from HTML content (using Readability title)
|
|
36
|
+
* Priority: readability title -> file name
|
|
37
|
+
*
|
|
38
|
+
* @param readabilityTitle - Title extracted by Readability
|
|
39
|
+
* @param fileName - File name for fallback
|
|
40
|
+
* @returns Title extraction result
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractHtmlTitle(readabilityTitle: string, fileName: string): TitleExtractionResult;
|
|
43
|
+
/**
|
|
44
|
+
* Extract title from PDF metadata or first page chunk text
|
|
45
|
+
* Priority: PDF metadata /Title -> first page chunk 0 text -> file name
|
|
46
|
+
*
|
|
47
|
+
* Rejects metadata titles that look like file paths (contain / or \) or are empty/whitespace-only.
|
|
48
|
+
*
|
|
49
|
+
* @param metadataTitle - PDF metadata /Title value (may be undefined)
|
|
50
|
+
* @param firstPageChunkText - Text of chunk 0 from semantic chunking of page 1 (may be undefined)
|
|
51
|
+
* @param fileName - File name for fallback
|
|
52
|
+
* @param firstPageFontHint - Largest-font text item from page 1 (optional, used for title detection)
|
|
53
|
+
* @returns Title extraction result
|
|
54
|
+
*/
|
|
55
|
+
export declare function extractPdfTitle(metadataTitle: string | undefined, firstPageChunkText: string | undefined, fileName: string, firstPageFontHint?: {
|
|
56
|
+
text: string;
|
|
57
|
+
fontSize: number;
|
|
58
|
+
}): TitleExtractionResult;
|
|
59
|
+
/**
|
|
60
|
+
* Extract title from a parsed DOCX mammoth HTML document
|
|
61
|
+
* Priority: DOCX core title -> first non-empty <h1> from mammoth HTML -> file name
|
|
62
|
+
*
|
|
63
|
+
* @param document - Parsed HTML document generated from mammoth.convertToHtml()
|
|
64
|
+
* @param fileName - File name for fallback
|
|
65
|
+
* @param metadataTitle - Optional title extracted from docProps/core.xml
|
|
66
|
+
* @returns Title extraction result
|
|
67
|
+
*/
|
|
68
|
+
export declare function extractDocxTitle(document: Document, fileName: string, metadataTitle?: string): TitleExtractionResult;
|
|
69
|
+
//# sourceMappingURL=title-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title-extractor.d.ts","sourceRoot":"","sources":["../../src/parser/title-extractor.ts"],"names":[],"mappings":"AAcA;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CAAA;CAC5C;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMxD;AAMD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAe1F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAkBrF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,GACf,qBAAqB,CAOvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACrD,qBAAqB,CA0BvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACrB,qBAAqB,CAavB"}
|