@ni-c/imap-mcp 0.2.0 → 0.4.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/README.md +142 -35
- package/dist/analyze.d.ts +54 -6
- package/dist/analyze.js +295 -27
- package/dist/analyze.js.map +1 -1
- package/dist/attachments.d.ts +36 -0
- package/dist/attachments.js +21 -3
- package/dist/attachments.js.map +1 -1
- package/dist/audit.d.ts +7 -0
- package/dist/audit.js +11 -3
- package/dist/audit.js.map +1 -1
- package/dist/config.d.ts +32 -0
- package/dist/config.js +65 -6
- package/dist/config.js.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/extract/child.d.ts +1 -0
- package/dist/extract/child.js +83 -0
- package/dist/extract/child.js.map +1 -0
- package/dist/extract/index.d.ts +41 -0
- package/dist/extract/index.js +183 -0
- package/dist/extract/index.js.map +1 -0
- package/dist/extract/ooxml.d.ts +35 -0
- package/dist/extract/ooxml.js +627 -0
- package/dist/extract/ooxml.js.map +1 -0
- package/dist/extract/pdf.d.ts +62 -0
- package/dist/extract/pdf.js +539 -0
- package/dist/extract/pdf.js.map +1 -0
- package/dist/extract/types.d.ts +56 -0
- package/dist/extract/types.js +13 -0
- package/dist/extract/types.js.map +1 -0
- package/dist/imap.js.map +1 -1
- package/dist/index.js +32 -5
- package/dist/index.js.map +1 -1
- package/dist/output-schema.d.ts +63 -0
- package/dist/output-schema.js +87 -0
- package/dist/output-schema.js.map +1 -0
- package/dist/resources.d.ts +1 -1
- package/dist/resources.js +5 -2
- package/dist/resources.js.map +1 -1
- package/dist/result.d.ts +39 -6
- package/dist/result.js +142 -29
- package/dist/result.js.map +1 -1
- package/dist/schema.d.ts +13 -1
- package/dist/schema.js +20 -2
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +30 -5
- package/dist/server.js.map +1 -1
- package/dist/tools/annotations.d.ts +32 -0
- package/dist/tools/annotations.js +33 -0
- package/dist/tools/annotations.js.map +1 -0
- package/dist/tools/catalogue.d.ts +2 -2
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.js +743 -87
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +3 -3
- package/dist/tools/write.js +174 -39
- package/dist/tools/write.js.map +1 -1
- package/package.json +17 -11
- package/dist/approval.d.ts +0 -45
- package/dist/approval.js +0 -69
- package/dist/approval.js.map +0 -1
- package/dist/confirm.d.ts +0 -59
- package/dist/confirm.js +0 -92
- package/dist/confirm.js.map +0 -1
- package/dist/tool-filter.d.ts +0 -45
- package/dist/tool-filter.js +0 -171
- package/dist/tool-filter.js.map +0 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ExtractResponse } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* How far one compressed stream may expand, and how far all of them may
|
|
4
|
+
* together, before the document is refused without a parser seeing it.
|
|
5
|
+
*
|
|
6
|
+
* This is the memory guard for PDFs, and it has to live here because nothing
|
|
7
|
+
* else bounds it. PDF.js inflates a stream into memory in full, and that memory
|
|
8
|
+
* is a typed array — external to the V8 heap, so no heap limit applies to it.
|
|
9
|
+
* Measured: a 3.4 MB file whose one content stream inflates to 1 GB took the
|
|
10
|
+
* process to 2.1 GB of resident memory within a second, and the extraction
|
|
11
|
+
* timeout only decides when that stops growing, not how far it gets. Deflate
|
|
12
|
+
* reaches roughly 1000:1 on repetitive input, so the 10 MB the size limit
|
|
13
|
+
* admits by default could stand for 10 GB.
|
|
14
|
+
*
|
|
15
|
+
* Every honest document is far below both numbers: a content stream is tens of
|
|
16
|
+
* kilobytes to a few megabytes, an embedded font a few hundred kilobytes.
|
|
17
|
+
*/
|
|
18
|
+
export declare const MAX_STREAM_BYTES: number;
|
|
19
|
+
export declare const MAX_TOTAL_STREAM_BYTES: number;
|
|
20
|
+
/**
|
|
21
|
+
* Reads the text layer of a PDF.
|
|
22
|
+
*
|
|
23
|
+
* The API surface used here is deliberately five calls wide — `getDocument`,
|
|
24
|
+
* `getPage`, `getTextContent`, `view`, `destroy` — and it must stay that way.
|
|
25
|
+
* `getJSActions` surfaces the document's own JavaScript, `getAttachments`
|
|
26
|
+
* returns embedded files (a PDF can carry an executable past `sniffContent`,
|
|
27
|
+
* which only ever looks at the outer `%PDF`), and `getAnnotations` carries
|
|
28
|
+
* actions and URIs. None of them is needed to read text, and each is a door.
|
|
29
|
+
*
|
|
30
|
+
* Nothing here reaches the network, and that is worth stating because it is one
|
|
31
|
+
* careless line away from being false. unpdf only sets `standardFontDataUrl`
|
|
32
|
+
* and `cMapUrl` when it can resolve `pdfjs-dist`, which is not a dependency of
|
|
33
|
+
* this package, so both stay unset; the document is passed as bytes, never as a
|
|
34
|
+
* URL, so pdf.js never constructs its network stream. **Do not "fix" a missing
|
|
35
|
+
* font or CMap by pointing either option at a CDN.** It is the most-suggested
|
|
36
|
+
* workaround on the internet, and it would hand this server its first outbound
|
|
37
|
+
* HTTP client — the one property SECURITY.md is built on. The cost of leaving
|
|
38
|
+
* them unset is known and accepted: a PDF whose text needs a predefined CJK
|
|
39
|
+
* CMap does not extract.
|
|
40
|
+
*/
|
|
41
|
+
export declare function extractPdf(bytes: Uint8Array, maxChars: number): Promise<ExtractResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the document's compressed streams expand past the limits above.
|
|
44
|
+
*
|
|
45
|
+
* One forward pass over the file, finding every `stream … endstream` and
|
|
46
|
+
* decoding the ones whose filter can grow: Flate, LZW and RunLength, each
|
|
47
|
+
* optionally behind an ASCIIHex or ASCII85 wrapper. The decoders stop the
|
|
48
|
+
* moment they cross the remaining budget, so the work this costs is bounded by
|
|
49
|
+
* the budget plus one stream, whatever the file holds — and a decoder that
|
|
50
|
+
* hits a corrupt byte counts what it produced up to there, which is also what
|
|
51
|
+
* pdf.js would have got.
|
|
52
|
+
*
|
|
53
|
+
* The data is delimited the way pdf.js delimits it: by `/Length` where the
|
|
54
|
+
* number is direct or a resolvable reference and actually lands on
|
|
55
|
+
* `endstream`, and by the first `endstream` otherwise. Using only the keyword
|
|
56
|
+
* would let a sender end the scan early by writing the word inside their own
|
|
57
|
+
* compressed bytes.
|
|
58
|
+
*
|
|
59
|
+
* Image codecs — DCT, JPX, JBIG2, CCITT — are not decoded here, because text
|
|
60
|
+
* extraction never decodes them either.
|
|
61
|
+
*/
|
|
62
|
+
export declare function expandsTooFar(bytes: Uint8Array): Promise<boolean>;
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import { createInflate } from 'node:zlib';
|
|
2
|
+
/**
|
|
3
|
+
* Pages read at most, however many the document claims.
|
|
4
|
+
*
|
|
5
|
+
* A mail attachment that needs more than this is not a document anyone is going
|
|
6
|
+
* to read in a chat window, and the page loop is the one part of extraction
|
|
7
|
+
* whose cost scales with something the sender chose.
|
|
8
|
+
*/
|
|
9
|
+
const MAX_PAGES = 100;
|
|
10
|
+
/** Below this many points, text is not there for a reader. */
|
|
11
|
+
const TINY_FONT_POINTS = 2;
|
|
12
|
+
/**
|
|
13
|
+
* How far one compressed stream may expand, and how far all of them may
|
|
14
|
+
* together, before the document is refused without a parser seeing it.
|
|
15
|
+
*
|
|
16
|
+
* This is the memory guard for PDFs, and it has to live here because nothing
|
|
17
|
+
* else bounds it. PDF.js inflates a stream into memory in full, and that memory
|
|
18
|
+
* is a typed array — external to the V8 heap, so no heap limit applies to it.
|
|
19
|
+
* Measured: a 3.4 MB file whose one content stream inflates to 1 GB took the
|
|
20
|
+
* process to 2.1 GB of resident memory within a second, and the extraction
|
|
21
|
+
* timeout only decides when that stops growing, not how far it gets. Deflate
|
|
22
|
+
* reaches roughly 1000:1 on repetitive input, so the 10 MB the size limit
|
|
23
|
+
* admits by default could stand for 10 GB.
|
|
24
|
+
*
|
|
25
|
+
* Every honest document is far below both numbers: a content stream is tens of
|
|
26
|
+
* kilobytes to a few megabytes, an embedded font a few hundred kilobytes.
|
|
27
|
+
*/
|
|
28
|
+
export const MAX_STREAM_BYTES = 32 * 1024 * 1024;
|
|
29
|
+
export const MAX_TOTAL_STREAM_BYTES = 128 * 1024 * 1024;
|
|
30
|
+
/**
|
|
31
|
+
* pdf.js options, every one of them load-bearing.
|
|
32
|
+
*
|
|
33
|
+
* `isEvalSupported` reads like a performance knob and is not one: it gates
|
|
34
|
+
* pdf.js's construction of `Function` objects for font and PostScript-calculator
|
|
35
|
+
* programs taken from the document. That is the primitive that turned a parser
|
|
36
|
+
* bug into remote code execution in CVE-2024-4367. Text extraction never needs
|
|
37
|
+
* it.
|
|
38
|
+
*
|
|
39
|
+
* `useSystemFonts` overrides unpdf's own default of `true`. Nothing about
|
|
40
|
+
* reading text needs the host's font configuration consulted on behalf of a
|
|
41
|
+
* stranger's file.
|
|
42
|
+
*
|
|
43
|
+
* `verbosity` silences pdf.js's own logging. This matters more here than it
|
|
44
|
+
* looks: the server's transport is stdio JSON-RPC, and a stray `console.log`
|
|
45
|
+
* reaching the parent's stdout corrupts the framing and hangs the session. The
|
|
46
|
+
* child process is also started with its stdout discarded, because one guard
|
|
47
|
+
* is not a guard.
|
|
48
|
+
*/
|
|
49
|
+
const PDFJS_OPTIONS = {
|
|
50
|
+
isEvalSupported: false,
|
|
51
|
+
enableXfa: false,
|
|
52
|
+
useSystemFonts: false,
|
|
53
|
+
disableFontFace: true,
|
|
54
|
+
verbosity: 0,
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Reads the text layer of a PDF.
|
|
58
|
+
*
|
|
59
|
+
* The API surface used here is deliberately five calls wide — `getDocument`,
|
|
60
|
+
* `getPage`, `getTextContent`, `view`, `destroy` — and it must stay that way.
|
|
61
|
+
* `getJSActions` surfaces the document's own JavaScript, `getAttachments`
|
|
62
|
+
* returns embedded files (a PDF can carry an executable past `sniffContent`,
|
|
63
|
+
* which only ever looks at the outer `%PDF`), and `getAnnotations` carries
|
|
64
|
+
* actions and URIs. None of them is needed to read text, and each is a door.
|
|
65
|
+
*
|
|
66
|
+
* Nothing here reaches the network, and that is worth stating because it is one
|
|
67
|
+
* careless line away from being false. unpdf only sets `standardFontDataUrl`
|
|
68
|
+
* and `cMapUrl` when it can resolve `pdfjs-dist`, which is not a dependency of
|
|
69
|
+
* this package, so both stay unset; the document is passed as bytes, never as a
|
|
70
|
+
* URL, so pdf.js never constructs its network stream. **Do not "fix" a missing
|
|
71
|
+
* font or CMap by pointing either option at a CDN.** It is the most-suggested
|
|
72
|
+
* workaround on the internet, and it would hand this server its first outbound
|
|
73
|
+
* HTTP client — the one property SECURITY.md is built on. The cost of leaving
|
|
74
|
+
* them unset is known and accepted: a PDF whose text needs a predefined CJK
|
|
75
|
+
* CMap does not extract.
|
|
76
|
+
*/
|
|
77
|
+
export async function extractPdf(bytes, maxChars) {
|
|
78
|
+
// Before the parser, not inside it: by the time pdf.js has inflated a stream
|
|
79
|
+
// the memory is spent, and there is no option that makes it stop earlier.
|
|
80
|
+
if (await expandsTooFar(bytes))
|
|
81
|
+
return { ok: false, reason: 'too-large' };
|
|
82
|
+
const { getDocumentProxy } = await import('unpdf');
|
|
83
|
+
let pdf;
|
|
84
|
+
try {
|
|
85
|
+
// Normalised, not passed through. A Node `Buffer` is a `Uint8Array`, so it
|
|
86
|
+
// satisfies the signature — but it is a view into a shared allocation pool
|
|
87
|
+
// at a non-zero `byteOffset`, and pdf.js reaches for the underlying
|
|
88
|
+
// `ArrayBuffer`. Handed a Buffer it reads the pool instead of the document
|
|
89
|
+
// and reports a corrupt file, which is a bug that looks exactly like a bad
|
|
90
|
+
// attachment. `set` on a fresh array is the copy that ends it.
|
|
91
|
+
const owned = new Uint8Array(bytes.byteLength);
|
|
92
|
+
owned.set(bytes);
|
|
93
|
+
pdf = await getDocumentProxy(owned, PDFJS_OPTIONS);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return { ok: false, reason: reasonFor(error) };
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const declared = pdf.numPages;
|
|
100
|
+
const pageCount = Math.min(declared, MAX_PAGES);
|
|
101
|
+
const parts = [];
|
|
102
|
+
let length = 0;
|
|
103
|
+
// Set only by the character cap. It used to be initialised from
|
|
104
|
+
// `declared > pageCount`, and since the loop below ran only while it was
|
|
105
|
+
// false, a document with more than a hundred pages was never read at all
|
|
106
|
+
// and came back as "no text layer" — the diagnosis for a scan, on a long
|
|
107
|
+
// contract. The page count the walk stopped short of is reported
|
|
108
|
+
// separately, as `declaredUnitCount`.
|
|
109
|
+
let clipped = false;
|
|
110
|
+
let hiddenRuns = 0;
|
|
111
|
+
let totalRuns = 0;
|
|
112
|
+
// Sequentially, not `Promise.all` over the page count — which is what
|
|
113
|
+
// unpdf's own `extractText` does. That form allocates an array as long as
|
|
114
|
+
// the document claims to be and holds every page's text content live at
|
|
115
|
+
// once, both sized by a number the sender wrote.
|
|
116
|
+
for (let page = 1; page <= pageCount; page += 1) {
|
|
117
|
+
const proxy = await pdf.getPage(page);
|
|
118
|
+
const box = proxy.view;
|
|
119
|
+
const content = await proxy.getTextContent();
|
|
120
|
+
const line = [];
|
|
121
|
+
for (const item of content.items) {
|
|
122
|
+
if (!('str' in item))
|
|
123
|
+
continue;
|
|
124
|
+
totalRuns += 1;
|
|
125
|
+
if (isHidden(item, box))
|
|
126
|
+
hiddenRuns += 1;
|
|
127
|
+
line.push(item.str);
|
|
128
|
+
if (item.hasEOL)
|
|
129
|
+
line.push('\n');
|
|
130
|
+
}
|
|
131
|
+
const text = line.join('');
|
|
132
|
+
if (length + text.length >= maxChars) {
|
|
133
|
+
parts.push(text.slice(0, maxChars - length));
|
|
134
|
+
clipped = true;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
parts.push(text, '\n');
|
|
138
|
+
length += text.length + 1;
|
|
139
|
+
}
|
|
140
|
+
const text = parts.join('');
|
|
141
|
+
// Trimmed, because an image-only PDF still yields the page separators this
|
|
142
|
+
// loop writes. `text !== ''` would call a scanned invoice a text document.
|
|
143
|
+
if (text.trim() === '')
|
|
144
|
+
return { ok: false, reason: 'no-text-layer' };
|
|
145
|
+
return {
|
|
146
|
+
ok: true,
|
|
147
|
+
text,
|
|
148
|
+
unitLabel: 'pages',
|
|
149
|
+
unitCount: pageCount,
|
|
150
|
+
...(declared > pageCount ? { declaredUnitCount: declared } : {}),
|
|
151
|
+
clipped,
|
|
152
|
+
hiddenRuns,
|
|
153
|
+
totalRuns,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return { ok: false, reason: reasonFor(error) };
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
// Releases the parsing state. The process is about to exit anyway, but a
|
|
161
|
+
// document that fails on page 3 of 100 should not hold its object graph
|
|
162
|
+
// while the remaining pages are abandoned. `destroy` is on the loading
|
|
163
|
+
// task, not on the document proxy — the proxy only has `cleanup`, which
|
|
164
|
+
// keeps the transport alive.
|
|
165
|
+
await pdf.loadingTask.destroy().catch(() => undefined);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Whether a text run is drawn where a reader will not find it.
|
|
170
|
+
*
|
|
171
|
+
* A signal, never a filter — the same position this server takes on suspicious
|
|
172
|
+
* mail. Two of the four ways to hide text in a PDF are visible from here (off
|
|
173
|
+
* the page, and set microscopically small) and two are not: fill colour is not
|
|
174
|
+
* exposed by the text-content API at all, and text render mode 3 is exactly how
|
|
175
|
+
* every OCR'd scan stores the text layer over its own image, so treating it as
|
|
176
|
+
* hidden would reject the main thing this feature exists to read.
|
|
177
|
+
*
|
|
178
|
+
* So the count goes into a note, the text goes to the model either way, and the
|
|
179
|
+
* result header says plainly that some of what follows is text a person opening
|
|
180
|
+
* the document would not see.
|
|
181
|
+
*
|
|
182
|
+
* "Off the page" is measured against the page's own box, not against the
|
|
183
|
+
* origin: a MediaBox need not start at 0,0, and text past the right or top
|
|
184
|
+
* edge is as invisible as text past the left one.
|
|
185
|
+
*/
|
|
186
|
+
function isHidden(item, box) {
|
|
187
|
+
const t = item.transform;
|
|
188
|
+
if (Array.isArray(t) && t.length >= 6) {
|
|
189
|
+
const x = Number(t[4]);
|
|
190
|
+
const y = Number(t[5]);
|
|
191
|
+
const [x0, y0, x1, y1] = box;
|
|
192
|
+
// Measured against pdf.js 6: a run placed *entirely* off the page produces
|
|
193
|
+
// no text item at all, so this catches the half that hangs over an edge
|
|
194
|
+
// and the other half never arrives — which is the better outcome and not
|
|
195
|
+
// one to undo.
|
|
196
|
+
if (Number.isFinite(x) &&
|
|
197
|
+
Number.isFinite(y) &&
|
|
198
|
+
(x < (x0 ?? 0) ||
|
|
199
|
+
y < (y0 ?? 0) ||
|
|
200
|
+
x > (x1 ?? Infinity) ||
|
|
201
|
+
y > (y1 ?? Infinity))) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const size = item.height ?? 0;
|
|
206
|
+
return size > 0 && size < TINY_FONT_POINTS;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Maps a pdf.js rejection to a reason code.
|
|
210
|
+
*
|
|
211
|
+
* On the name, never the message. The message is a pdf.js implementation
|
|
212
|
+
* detail that changes between releases, and it quotes the document.
|
|
213
|
+
*/
|
|
214
|
+
function reasonFor(error) {
|
|
215
|
+
const name = error?.name;
|
|
216
|
+
return name === 'PasswordException' ? 'encrypted' : 'corrupt';
|
|
217
|
+
}
|
|
218
|
+
/* ------------------------------------------------------------ pre-scan -- */
|
|
219
|
+
/**
|
|
220
|
+
* Whether the document's compressed streams expand past the limits above.
|
|
221
|
+
*
|
|
222
|
+
* One forward pass over the file, finding every `stream … endstream` and
|
|
223
|
+
* decoding the ones whose filter can grow: Flate, LZW and RunLength, each
|
|
224
|
+
* optionally behind an ASCIIHex or ASCII85 wrapper. The decoders stop the
|
|
225
|
+
* moment they cross the remaining budget, so the work this costs is bounded by
|
|
226
|
+
* the budget plus one stream, whatever the file holds — and a decoder that
|
|
227
|
+
* hits a corrupt byte counts what it produced up to there, which is also what
|
|
228
|
+
* pdf.js would have got.
|
|
229
|
+
*
|
|
230
|
+
* The data is delimited the way pdf.js delimits it: by `/Length` where the
|
|
231
|
+
* number is direct or a resolvable reference and actually lands on
|
|
232
|
+
* `endstream`, and by the first `endstream` otherwise. Using only the keyword
|
|
233
|
+
* would let a sender end the scan early by writing the word inside their own
|
|
234
|
+
* compressed bytes.
|
|
235
|
+
*
|
|
236
|
+
* Image codecs — DCT, JPX, JBIG2, CCITT — are not decoded here, because text
|
|
237
|
+
* extraction never decodes them either.
|
|
238
|
+
*/
|
|
239
|
+
export async function expandsTooFar(bytes) {
|
|
240
|
+
const data = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
241
|
+
// latin1 keeps a one-to-one mapping between string index and byte offset.
|
|
242
|
+
const text = data.toString('latin1');
|
|
243
|
+
let total = 0;
|
|
244
|
+
let cursor = 0;
|
|
245
|
+
for (;;) {
|
|
246
|
+
const at = text.indexOf('stream', cursor);
|
|
247
|
+
if (at < 0)
|
|
248
|
+
return false;
|
|
249
|
+
cursor = at + 6;
|
|
250
|
+
// A keyword, not the tail of `endstream` or part of a name.
|
|
251
|
+
const before = at === 0 ? ' ' : text[at - 1];
|
|
252
|
+
if (!/[\s>]/.test(before))
|
|
253
|
+
continue;
|
|
254
|
+
let start = at + 6;
|
|
255
|
+
if (text[start] === '\r')
|
|
256
|
+
start += 1;
|
|
257
|
+
if (text[start] === '\n')
|
|
258
|
+
start += 1;
|
|
259
|
+
const objAt = text.lastIndexOf('obj', at);
|
|
260
|
+
const dict = text.slice(Math.max(objAt, cursor - 6 - 4096, 0), at);
|
|
261
|
+
const end = streamEnd(text, dict, start);
|
|
262
|
+
if (end < 0)
|
|
263
|
+
return false;
|
|
264
|
+
cursor = end + 9;
|
|
265
|
+
const filters = filtersOf(dict);
|
|
266
|
+
if (!filters.some((name) => EXPANDING.has(name)))
|
|
267
|
+
continue;
|
|
268
|
+
const limit = Math.min(MAX_STREAM_BYTES, MAX_TOTAL_STREAM_BYTES - total);
|
|
269
|
+
const size = await expansionOf(data.subarray(start, end), filters, /\/EarlyChange\s+0\b/.test(dict) ? 0 : 1, limit);
|
|
270
|
+
if (size > limit)
|
|
271
|
+
return true;
|
|
272
|
+
total += size;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const EXPANDING = new Set([
|
|
276
|
+
'FlateDecode',
|
|
277
|
+
'Fl',
|
|
278
|
+
'LZWDecode',
|
|
279
|
+
'LZW',
|
|
280
|
+
'RunLengthDecode',
|
|
281
|
+
'RL',
|
|
282
|
+
]);
|
|
283
|
+
/** Where the stream's data ends: by a trustworthy `/Length`, else by keyword. */
|
|
284
|
+
function streamEnd(text, dict, start) {
|
|
285
|
+
const length = /\/Length\s+(\d+)(?:\s+(\d+)\s+R)?/.exec(dict);
|
|
286
|
+
if (length !== null) {
|
|
287
|
+
let declared;
|
|
288
|
+
if (length[2] === undefined) {
|
|
289
|
+
declared = Number(length[1]);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
const object = new RegExp(`(?:^|\\s)${length[1]}\\s+${length[2]}\\s+obj\\s*(\\d+)`).exec(text);
|
|
293
|
+
if (object !== null)
|
|
294
|
+
declared = Number(object[1]);
|
|
295
|
+
}
|
|
296
|
+
if (declared !== undefined && Number.isSafeInteger(declared)) {
|
|
297
|
+
let after = start + declared;
|
|
298
|
+
if (text[after] === '\r')
|
|
299
|
+
after += 1;
|
|
300
|
+
if (text[after] === '\n')
|
|
301
|
+
after += 1;
|
|
302
|
+
if (text.startsWith('endstream', after))
|
|
303
|
+
return start + declared;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return text.indexOf('endstream', start);
|
|
307
|
+
}
|
|
308
|
+
/** The `/Filter` names of a stream dictionary, in application order. */
|
|
309
|
+
function filtersOf(dict) {
|
|
310
|
+
const match = /\/Filter\s*(?:\[([^\]]*)\]|\/([A-Za-z0-9]+))/.exec(dict);
|
|
311
|
+
if (match === null)
|
|
312
|
+
return [];
|
|
313
|
+
if (match[2] !== undefined)
|
|
314
|
+
return [match[2]];
|
|
315
|
+
return [...match[1].matchAll(/\/([A-Za-z0-9]+)/g)].map((name) => name[1]);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Bytes the filter chain produces, or any number past `limit` once it does.
|
|
319
|
+
*
|
|
320
|
+
* Flate is materialised, because a second filter may follow it; LZW and
|
|
321
|
+
* RunLength only count, and end the chain, because nothing honest stacks
|
|
322
|
+
* another expanding filter behind them.
|
|
323
|
+
*/
|
|
324
|
+
async function expansionOf(raw, filters, earlyChange, limit) {
|
|
325
|
+
let current = raw;
|
|
326
|
+
for (const filter of filters) {
|
|
327
|
+
switch (filter) {
|
|
328
|
+
case 'ASCIIHexDecode':
|
|
329
|
+
case 'AHx':
|
|
330
|
+
current = hexDecode(current);
|
|
331
|
+
break;
|
|
332
|
+
case 'ASCII85Decode':
|
|
333
|
+
case 'A85':
|
|
334
|
+
current = ascii85Decode(current);
|
|
335
|
+
break;
|
|
336
|
+
case 'FlateDecode':
|
|
337
|
+
case 'Fl': {
|
|
338
|
+
const inflated = await inflate(current, limit);
|
|
339
|
+
if (inflated === undefined)
|
|
340
|
+
return limit + 1;
|
|
341
|
+
current = inflated;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
case 'LZWDecode':
|
|
345
|
+
case 'LZW':
|
|
346
|
+
return lzwLength(current, earlyChange, limit);
|
|
347
|
+
case 'RunLengthDecode':
|
|
348
|
+
case 'RL':
|
|
349
|
+
return runLengthLength(current, limit);
|
|
350
|
+
default:
|
|
351
|
+
// An image codec, or something unknown: the chain stops producing
|
|
352
|
+
// anything text extraction would read.
|
|
353
|
+
return current === raw ? 0 : current.length;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return current === raw ? 0 : current.length;
|
|
357
|
+
}
|
|
358
|
+
/** Inflates up to `limit` bytes; `undefined` once the output would pass it. */
|
|
359
|
+
function inflate(data, limit) {
|
|
360
|
+
return new Promise((resolve) => {
|
|
361
|
+
const chunks = [];
|
|
362
|
+
let produced = 0;
|
|
363
|
+
let settled = false;
|
|
364
|
+
const stream = createInflate();
|
|
365
|
+
const finish = (value) => {
|
|
366
|
+
if (settled)
|
|
367
|
+
return;
|
|
368
|
+
settled = true;
|
|
369
|
+
stream.destroy();
|
|
370
|
+
resolve(value);
|
|
371
|
+
};
|
|
372
|
+
stream.on('data', (chunk) => {
|
|
373
|
+
if (settled)
|
|
374
|
+
return;
|
|
375
|
+
produced += chunk.length;
|
|
376
|
+
if (produced > limit) {
|
|
377
|
+
finish(undefined);
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
chunks.push(chunk);
|
|
381
|
+
});
|
|
382
|
+
// A corrupt stream yields what it decoded before the bad byte, which is
|
|
383
|
+
// also what pdf.js gets from it. The listener stays attached after
|
|
384
|
+
// settling so a late error has somewhere to go.
|
|
385
|
+
stream.on('error', () => finish(Buffer.concat(chunks)));
|
|
386
|
+
stream.on('end', () => finish(Buffer.concat(chunks)));
|
|
387
|
+
stream.end(data);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Output length of a PDF LZW stream, without building a single string.
|
|
392
|
+
*
|
|
393
|
+
* Every dictionary entry is one byte longer than the entry it extends, so the
|
|
394
|
+
* length of any code is known from lengths alone — which is all the question
|
|
395
|
+
* needs. Codes are 9 to 12 bits, MSB first; 256 clears, 257 ends; the width
|
|
396
|
+
* grows one code early under the default `EarlyChange`.
|
|
397
|
+
*/
|
|
398
|
+
function lzwLength(data, earlyChange, limit) {
|
|
399
|
+
let produced = 0;
|
|
400
|
+
let bits = 0;
|
|
401
|
+
let held = 0;
|
|
402
|
+
let pos = 0;
|
|
403
|
+
let width = 9;
|
|
404
|
+
let lengths = [];
|
|
405
|
+
let previous = 0;
|
|
406
|
+
let hasPrevious = false;
|
|
407
|
+
while (produced <= limit) {
|
|
408
|
+
while (held < width && pos < data.length) {
|
|
409
|
+
bits = (bits << 8) | data[pos];
|
|
410
|
+
pos += 1;
|
|
411
|
+
held += 8;
|
|
412
|
+
}
|
|
413
|
+
if (held < width)
|
|
414
|
+
break;
|
|
415
|
+
const code = (bits >>> (held - width)) & ((1 << width) - 1);
|
|
416
|
+
held -= width;
|
|
417
|
+
bits &= (1 << held) - 1;
|
|
418
|
+
if (code === 256) {
|
|
419
|
+
lengths = [];
|
|
420
|
+
width = 9;
|
|
421
|
+
hasPrevious = false;
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (code === 257)
|
|
425
|
+
break;
|
|
426
|
+
let length;
|
|
427
|
+
if (code < 256)
|
|
428
|
+
length = 1;
|
|
429
|
+
else if (code - 258 < lengths.length)
|
|
430
|
+
length = lengths[code - 258];
|
|
431
|
+
else if (code - 258 === lengths.length && hasPrevious)
|
|
432
|
+
length = previous + 1;
|
|
433
|
+
else
|
|
434
|
+
break;
|
|
435
|
+
produced += length;
|
|
436
|
+
if (hasPrevious)
|
|
437
|
+
lengths.push(previous + 1);
|
|
438
|
+
previous = length;
|
|
439
|
+
hasPrevious = true;
|
|
440
|
+
if (width < 12 && 258 + lengths.length + earlyChange >= 1 << width)
|
|
441
|
+
width += 1;
|
|
442
|
+
}
|
|
443
|
+
return produced;
|
|
444
|
+
}
|
|
445
|
+
/** Output length of a RunLength stream. */
|
|
446
|
+
function runLengthLength(data, limit) {
|
|
447
|
+
let produced = 0;
|
|
448
|
+
let i = 0;
|
|
449
|
+
while (i < data.length && produced <= limit) {
|
|
450
|
+
const marker = data[i];
|
|
451
|
+
i += 1;
|
|
452
|
+
if (marker === 128)
|
|
453
|
+
break;
|
|
454
|
+
if (marker < 128) {
|
|
455
|
+
produced += marker + 1;
|
|
456
|
+
i += marker + 1;
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
produced += 257 - marker;
|
|
460
|
+
i += 1;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return produced;
|
|
464
|
+
}
|
|
465
|
+
function hexDecode(data) {
|
|
466
|
+
const out = new Uint8Array(Math.ceil(data.length / 2));
|
|
467
|
+
let n = 0;
|
|
468
|
+
let pending = -1;
|
|
469
|
+
for (const byte of data) {
|
|
470
|
+
if (byte === 0x3e)
|
|
471
|
+
break; // '>'
|
|
472
|
+
const digit = byte >= 0x30 && byte <= 0x39
|
|
473
|
+
? byte - 0x30
|
|
474
|
+
: byte >= 0x41 && byte <= 0x46
|
|
475
|
+
? byte - 0x37
|
|
476
|
+
: byte >= 0x61 && byte <= 0x66
|
|
477
|
+
? byte - 0x57
|
|
478
|
+
: -1;
|
|
479
|
+
if (digit < 0)
|
|
480
|
+
continue;
|
|
481
|
+
if (pending < 0) {
|
|
482
|
+
pending = digit;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
out[n] = pending * 16 + digit;
|
|
486
|
+
n += 1;
|
|
487
|
+
pending = -1;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
if (pending >= 0) {
|
|
491
|
+
out[n] = pending * 16;
|
|
492
|
+
n += 1;
|
|
493
|
+
}
|
|
494
|
+
return out.subarray(0, n);
|
|
495
|
+
}
|
|
496
|
+
function ascii85Decode(data) {
|
|
497
|
+
const out = new Uint8Array(Math.ceil(data.length / 5) * 4 + 4);
|
|
498
|
+
let n = 0;
|
|
499
|
+
const group = [];
|
|
500
|
+
let i = 0;
|
|
501
|
+
if (data[0] === 0x3c && data[1] === 0x7e)
|
|
502
|
+
i = 2; // '<~'
|
|
503
|
+
const flush = (count) => {
|
|
504
|
+
while (group.length < 5)
|
|
505
|
+
group.push(84);
|
|
506
|
+
let value = 0;
|
|
507
|
+
for (const digit of group)
|
|
508
|
+
value = value * 85 + digit;
|
|
509
|
+
const bytes = [
|
|
510
|
+
value >>> 24,
|
|
511
|
+
(value >>> 16) & 255,
|
|
512
|
+
(value >>> 8) & 255,
|
|
513
|
+
value & 255,
|
|
514
|
+
];
|
|
515
|
+
for (let k = 0; k < count - 1; k += 1) {
|
|
516
|
+
out[n] = bytes[k];
|
|
517
|
+
n += 1;
|
|
518
|
+
}
|
|
519
|
+
group.length = 0;
|
|
520
|
+
};
|
|
521
|
+
for (; i < data.length; i += 1) {
|
|
522
|
+
const byte = data[i];
|
|
523
|
+
if (byte === 0x7e)
|
|
524
|
+
break; // '~' of '~>'
|
|
525
|
+
if (byte === 0x7a && group.length === 0) {
|
|
526
|
+
n += 4; // 'z' is four zero bytes
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
if (byte < 0x21 || byte > 0x75)
|
|
530
|
+
continue;
|
|
531
|
+
group.push(byte - 0x21);
|
|
532
|
+
if (group.length === 5)
|
|
533
|
+
flush(5);
|
|
534
|
+
}
|
|
535
|
+
if (group.length > 1)
|
|
536
|
+
flush(group.length);
|
|
537
|
+
return out.subarray(0, n);
|
|
538
|
+
}
|
|
539
|
+
//# sourceMappingURL=pdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/extract/pdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAI1C;;;;;;GAMG;AACH,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,8DAA8D;AAC9D,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACjD,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AAExD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,aAAa,GAAG;IACpB,eAAe,EAAE,KAAK;IACtB,SAAS,EAAE,KAAK;IAChB,cAAc,EAAE,KAAK;IACrB,eAAe,EAAE,IAAI;IACrB,SAAS,EAAE,CAAC;CACJ,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAiB,EACjB,QAAgB;IAEhB,6EAA6E;IAC7E,0EAA0E;IAC1E,IAAI,MAAM,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAE1E,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnD,IAAI,GAAG,CAAC;IACR,IAAI,CAAC;QACH,2EAA2E;QAC3E,2EAA2E;QAC3E,oEAAoE;QACpE,2EAA2E;QAC3E,2EAA2E;QAC3E,+DAA+D;QAC/D,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/C,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjB,GAAG,GAAG,MAAM,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;IACjD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAChD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,gEAAgE;QAChE,yEAAyE;QACzE,yEAAyE;QACzE,yEAAyE;QACzE,iEAAiE;QACjE,sCAAsC;QACtC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,sEAAsE;QACtE,0EAA0E;QAC1E,wEAAwE;QACxE,iDAAiD;QACjD,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,SAAS,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACtC,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;YACvB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAa,EAAE,CAAC;YAC1B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBACjC,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC;oBAAE,SAAS;gBAC/B,SAAS,IAAI,CAAC,CAAC;gBACf,IAAI,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;oBAAE,UAAU,IAAI,CAAC,CAAC;gBACzC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACpB,IAAI,IAAI,CAAC,MAAM;oBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3B,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;gBACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC;gBAC7C,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM;YACR,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACvB,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5B,CAAC;QAED,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5B,2EAA2E;QAC3E,2EAA2E;QAC3E,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QAEtE,OAAO;YACL,EAAE,EAAE,IAAI;YACR,IAAI;YACJ,SAAS,EAAE,OAAO;YAClB,SAAS,EAAE,SAAS;YACpB,GAAG,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,OAAO;YACP,UAAU;YACV,SAAS;SACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;IACjD,CAAC;YAAS,CAAC;QACT,yEAAyE;QACzE,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,6BAA6B;QAC7B,MAAM,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAS,QAAQ,CACf,IAA8C,EAC9C,GAAa;IAEb,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;IACzB,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC;QAC7B,2EAA2E;QAC3E,wEAAwE;QACxE,yEAAyE;QACzE,eAAe;QACf,IACE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAClB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;gBACZ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;gBACb,CAAC,GAAG,CAAC,EAAE,IAAI,QAAQ,CAAC;gBACpB,CAAC,GAAG,CAAC,EAAE,IAAI,QAAQ,CAAC,CAAC,EACvB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAC9B,OAAO,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,gBAAgB,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,SAAS,SAAS,CAAC,KAAc;IAC/B,MAAM,IAAI,GAAI,KAAmC,EAAE,IAAI,CAAC;IACxD,OAAO,IAAI,KAAK,mBAAmB,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAiB;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3E,0EAA0E;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,SAAS,CAAC;QACR,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,EAAE,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACzB,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC;QAChB,4DAA4D;QAC5D,MAAM,MAAM,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAY,CAAC;QACzD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,SAAS;QAEpC,IAAI,KAAK,GAAG,EAAE,GAAG,CAAC,CAAC;QACnB,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI;YAAE,KAAK,IAAI,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI;YAAE,KAAK,IAAI,CAAC,CAAC;QAErC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACzC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC;QAEjB,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QAE3D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,KAAK,CAAC,CAAC;QACzE,MAAM,IAAI,GAAG,MAAM,WAAW,CAC5B,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,EACzB,OAAO,EACP,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EACxC,KAAK,CACN,CAAC;QACF,IAAI,IAAI,GAAG,KAAK;YAAE,OAAO,IAAI,CAAC;QAC9B,KAAK,IAAI,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,aAAa;IACb,IAAI;IACJ,WAAW;IACX,KAAK;IACL,iBAAiB;IACjB,IAAI;CACL,CAAC,CAAC;AAEH,iFAAiF;AACjF,SAAS,SAAS,CAAC,IAAY,EAAE,IAAY,EAAE,KAAa;IAC1D,MAAM,MAAM,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,IAAI,QAA4B,CAAC;QACjC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAC5B,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,YAAY,MAAM,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,mBAAmB,CACzD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACb,IAAI,MAAM,KAAK,IAAI;gBAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7D,IAAI,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;YAC7B,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI;gBAAE,KAAK,IAAI,CAAC,CAAC;YACrC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI;gBAAE,KAAK,IAAI,CAAC,CAAC;YACrC,IAAI,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC;gBAAE,OAAO,KAAK,GAAG,QAAQ,CAAC;QACnE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED,wEAAwE;AACxE,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,8CAA8C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC9B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAI,KAAK,CAAC,CAAC,CAAY,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAChE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAW,CAC5B,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,WAAW,CACxB,GAAe,EACf,OAAiB,EACjB,WAAmB,EACnB,KAAa;IAEb,IAAI,OAAO,GAAG,GAAG,CAAC;IAClB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,gBAAgB,CAAC;YACtB,KAAK,KAAK;gBACR,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,eAAe,CAAC;YACrB,KAAK,KAAK;gBACR,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;gBACjC,MAAM;YACR,KAAK,aAAa,CAAC;YACnB,KAAK,IAAI,EAAE,CAAC;gBACV,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBAC/C,IAAI,QAAQ,KAAK,SAAS;oBAAE,OAAO,KAAK,GAAG,CAAC,CAAC;gBAC7C,OAAO,GAAG,QAAQ,CAAC;gBACnB,MAAM;YACR,CAAC;YACD,KAAK,WAAW,CAAC;YACjB,KAAK,KAAK;gBACR,OAAO,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YAChD,KAAK,iBAAiB,CAAC;YACvB,KAAK,IAAI;gBACP,OAAO,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzC;gBACE,kEAAkE;gBAClE,uCAAuC;gBACvC,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QAChD,CAAC;IACH,CAAC;IACD,OAAO,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;AAC9C,CAAC;AAED,+EAA+E;AAC/E,SAAS,OAAO,CACd,IAAgB,EAChB,KAAa;IAEb,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,CAAC,KAA6B,EAAQ,EAAE;YACrD,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC;QACF,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAClC,IAAI,OAAO;gBAAE,OAAO;YACpB,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC;YACzB,IAAI,QAAQ,GAAG,KAAK,EAAE,CAAC;gBACrB,MAAM,CAAC,SAAS,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QACH,wEAAwE;QACxE,mEAAmE;QACnE,gDAAgD;QAChD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,SAAS,CAChB,IAAgB,EAChB,WAAmB,EACnB,KAAa;IAEb,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,WAAW,GAAG,KAAK,CAAC;IAExB,OAAO,QAAQ,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,IAAI,GAAG,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,GAAI,IAAI,CAAC,GAAG,CAAY,CAAC;YAC3C,GAAG,IAAI,CAAC,CAAC;YACT,IAAI,IAAI,CAAC,CAAC;QACZ,CAAC;QACD,IAAI,IAAI,GAAG,KAAK;YAAE,MAAM;QACxB,MAAM,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5D,IAAI,IAAI,KAAK,CAAC;QACd,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAExB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,OAAO,GAAG,EAAE,CAAC;YACb,KAAK,GAAG,CAAC,CAAC;YACV,WAAW,GAAG,KAAK,CAAC;YACpB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,GAAG;YAAE,MAAM;QAExB,IAAI,MAAc,CAAC;QACnB,IAAI,IAAI,GAAG,GAAG;YAAE,MAAM,GAAG,CAAC,CAAC;aACtB,IAAI,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM;YAClC,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,GAAG,CAAW,CAAC;aACpC,IAAI,IAAI,GAAG,GAAG,KAAK,OAAO,CAAC,MAAM,IAAI,WAAW;YACnD,MAAM,GAAG,QAAQ,GAAG,CAAC,CAAC;;YACnB,MAAM;QAEX,QAAQ,IAAI,MAAM,CAAC;QACnB,IAAI,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC5C,QAAQ,GAAG,MAAM,CAAC;QAClB,WAAW,GAAG,IAAI,CAAC;QACnB,IAAI,KAAK,GAAG,EAAE,IAAI,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,WAAW,IAAI,CAAC,IAAI,KAAK;YAChE,KAAK,IAAI,CAAC,CAAC;IACf,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,2CAA2C;AAC3C,SAAS,eAAe,CAAC,IAAgB,EAAE,KAAa;IACtD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;QACjC,CAAC,IAAI,CAAC,CAAC;QACP,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM;QAC1B,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;YACjB,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAC;YACvB,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,QAAQ,IAAI,GAAG,GAAG,MAAM,CAAC;YACzB,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAAC,IAAgB;IACjC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,KAAK,IAAI;YAAE,MAAM,CAAC,MAAM;QAChC,MAAM,KAAK,GACT,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;YAC1B,CAAC,CAAC,IAAI,GAAG,IAAI;YACb,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;gBAC5B,CAAC,CAAC,IAAI,GAAG,IAAI;gBACb,CAAC,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;oBAC5B,CAAC,CAAC,IAAI,GAAG,IAAI;oBACb,CAAC,CAAC,CAAC,CAAC,CAAC;QACb,IAAI,KAAK,GAAG,CAAC;YAAE,SAAS;QACxB,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC;YAC9B,CAAC,IAAI,CAAC,CAAC;YACP,OAAO,GAAG,CAAC,CAAC,CAAC;QACf,CAAC;IACH,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,EAAE,CAAC;QACtB,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IACD,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,aAAa,CAAC,IAAgB;IACrC,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO;IACxD,MAAM,KAAK,GAAG,CAAC,KAAa,EAAQ,EAAE;QACpC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,KAAK;YAAE,KAAK,GAAG,KAAK,GAAG,EAAE,GAAG,KAAK,CAAC;QACtD,MAAM,KAAK,GAAG;YACZ,KAAK,KAAK,EAAE;YACZ,CAAC,KAAK,KAAK,EAAE,CAAC,GAAG,GAAG;YACpB,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,GAAG;YACnB,KAAK,GAAG,GAAG;SACZ,CAAC;QACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAW,CAAC;YAC5B,CAAC,IAAI,CAAC,CAAC;QACT,CAAC;QACD,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC;IACF,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;QAC/B,IAAI,IAAI,KAAK,IAAI;YAAE,MAAM,CAAC,cAAc;QACxC,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxC,CAAC,IAAI,CAAC,CAAC,CAAC,yBAAyB;YACjC,SAAS;QACX,CAAC;QACD,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,IAAI;YAAE,SAAS;QACzC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QACxB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC5B,CAAC"}
|