@postalsys/email-content 0.0.1

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.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +288 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/analyze.d.ts +91 -0
  5. package/dist/analyze.d.ts.map +1 -0
  6. package/dist/analyze.js +274 -0
  7. package/dist/analyze.js.map +1 -0
  8. package/dist/annotate/client.d.ts +64 -0
  9. package/dist/annotate/client.d.ts.map +1 -0
  10. package/dist/annotate/client.js +139 -0
  11. package/dist/annotate/client.js.map +1 -0
  12. package/dist/annotate/llm.d.ts +46 -0
  13. package/dist/annotate/llm.d.ts.map +1 -0
  14. package/dist/annotate/llm.js +107 -0
  15. package/dist/annotate/llm.js.map +1 -0
  16. package/dist/annotate/prompt.d.ts +38 -0
  17. package/dist/annotate/prompt.d.ts.map +1 -0
  18. package/dist/annotate/prompt.js +165 -0
  19. package/dist/annotate/prompt.js.map +1 -0
  20. package/dist/annotate/store.d.ts +43 -0
  21. package/dist/annotate/store.d.ts.map +1 -0
  22. package/dist/annotate/store.js +46 -0
  23. package/dist/annotate/store.js.map +1 -0
  24. package/dist/canonical/html.d.ts +33 -0
  25. package/dist/canonical/html.d.ts.map +1 -0
  26. package/dist/canonical/html.js +156 -0
  27. package/dist/canonical/html.js.map +1 -0
  28. package/dist/canonical/text.d.ts +75 -0
  29. package/dist/canonical/text.d.ts.map +1 -0
  30. package/dist/canonical/text.js +217 -0
  31. package/dist/canonical/text.js.map +1 -0
  32. package/dist/classify/confidence.d.ts +38 -0
  33. package/dist/classify/confidence.d.ts.map +1 -0
  34. package/dist/classify/confidence.js +59 -0
  35. package/dist/classify/confidence.js.map +1 -0
  36. package/dist/classify/reconcile.d.ts +52 -0
  37. package/dist/classify/reconcile.d.ts.map +1 -0
  38. package/dist/classify/reconcile.js +100 -0
  39. package/dist/classify/reconcile.js.map +1 -0
  40. package/dist/classify/rules.d.ts +51 -0
  41. package/dist/classify/rules.d.ts.map +1 -0
  42. package/dist/classify/rules.js +648 -0
  43. package/dist/classify/rules.js.map +1 -0
  44. package/dist/cli/annotate.d.ts +23 -0
  45. package/dist/cli/annotate.d.ts.map +1 -0
  46. package/dist/cli/annotate.js +328 -0
  47. package/dist/cli/annotate.js.map +1 -0
  48. package/dist/cli/args.d.ts +17 -0
  49. package/dist/cli/args.d.ts.map +1 -0
  50. package/dist/cli/args.js +72 -0
  51. package/dist/cli/args.js.map +1 -0
  52. package/dist/cli/benchmark.d.ts +13 -0
  53. package/dist/cli/benchmark.d.ts.map +1 -0
  54. package/dist/cli/benchmark.js +172 -0
  55. package/dist/cli/benchmark.js.map +1 -0
  56. package/dist/cli/corpus.d.ts +9 -0
  57. package/dist/cli/corpus.d.ts.map +1 -0
  58. package/dist/cli/corpus.js +152 -0
  59. package/dist/cli/corpus.js.map +1 -0
  60. package/dist/cli/disagreements.d.ts +14 -0
  61. package/dist/cli/disagreements.d.ts.map +1 -0
  62. package/dist/cli/disagreements.js +133 -0
  63. package/dist/cli/disagreements.js.map +1 -0
  64. package/dist/cli/evaluate.d.ts +15 -0
  65. package/dist/cli/evaluate.d.ts.map +1 -0
  66. package/dist/cli/evaluate.js +215 -0
  67. package/dist/cli/evaluate.js.map +1 -0
  68. package/dist/cli/extract.d.ts +10 -0
  69. package/dist/cli/extract.d.ts.map +1 -0
  70. package/dist/cli/extract.js +139 -0
  71. package/dist/cli/extract.js.map +1 -0
  72. package/dist/cli/main.d.ts +9 -0
  73. package/dist/cli/main.d.ts.map +1 -0
  74. package/dist/cli/main.js +147 -0
  75. package/dist/cli/main.js.map +1 -0
  76. package/dist/corpus/analyze.d.ts +66 -0
  77. package/dist/corpus/analyze.d.ts.map +1 -0
  78. package/dist/corpus/analyze.js +214 -0
  79. package/dist/corpus/analyze.js.map +1 -0
  80. package/dist/corpus/migrations/index.d.ts +14 -0
  81. package/dist/corpus/migrations/index.d.ts.map +1 -0
  82. package/dist/corpus/migrations/index.js +158 -0
  83. package/dist/corpus/migrations/index.js.map +1 -0
  84. package/dist/corpus/sample.d.ts +66 -0
  85. package/dist/corpus/sample.d.ts.map +1 -0
  86. package/dist/corpus/sample.js +98 -0
  87. package/dist/corpus/sample.js.map +1 -0
  88. package/dist/corpus/scanner.d.ts +79 -0
  89. package/dist/corpus/scanner.d.ts.map +1 -0
  90. package/dist/corpus/scanner.js +256 -0
  91. package/dist/corpus/scanner.js.map +1 -0
  92. package/dist/corpus/stats.d.ts +76 -0
  93. package/dist/corpus/stats.d.ts.map +1 -0
  94. package/dist/corpus/stats.js +240 -0
  95. package/dist/corpus/stats.js.map +1 -0
  96. package/dist/corpus/store.d.ts +67 -0
  97. package/dist/corpus/store.d.ts.map +1 -0
  98. package/dist/corpus/store.js +196 -0
  99. package/dist/corpus/store.js.map +1 -0
  100. package/dist/corpus/thread-index.d.ts +31 -0
  101. package/dist/corpus/thread-index.d.ts.map +1 -0
  102. package/dist/corpus/thread-index.js +182 -0
  103. package/dist/corpus/thread-index.js.map +1 -0
  104. package/dist/corpus/worker.d.ts +21 -0
  105. package/dist/corpus/worker.d.ts.map +1 -0
  106. package/dist/corpus/worker.js +74 -0
  107. package/dist/corpus/worker.js.map +1 -0
  108. package/dist/detect/client.d.ts +28 -0
  109. package/dist/detect/client.d.ts.map +1 -0
  110. package/dist/detect/client.js +121 -0
  111. package/dist/detect/client.js.map +1 -0
  112. package/dist/detect/disclaimer.d.ts +12 -0
  113. package/dist/detect/disclaimer.d.ts.map +1 -0
  114. package/dist/detect/disclaimer.js +28 -0
  115. package/dist/detect/disclaimer.js.map +1 -0
  116. package/dist/detect/forward-header.d.ts +10 -0
  117. package/dist/detect/forward-header.d.ts.map +1 -0
  118. package/dist/detect/forward-header.js +35 -0
  119. package/dist/detect/forward-header.js.map +1 -0
  120. package/dist/detect/patterns/disclaimers.json +113 -0
  121. package/dist/detect/patterns/forward-headers.json +40 -0
  122. package/dist/detect/patterns/html-clients.json +157 -0
  123. package/dist/detect/patterns/quoted-headers.json +41 -0
  124. package/dist/detect/patterns/reply-headers.json +139 -0
  125. package/dist/detect/patterns/signatures.json +58 -0
  126. package/dist/detect/patterns.d.ts +43 -0
  127. package/dist/detect/patterns.d.ts.map +1 -0
  128. package/dist/detect/patterns.js +125 -0
  129. package/dist/detect/patterns.js.map +1 -0
  130. package/dist/detect/reply-header.d.ts +44 -0
  131. package/dist/detect/reply-header.d.ts.map +1 -0
  132. package/dist/detect/reply-header.js +134 -0
  133. package/dist/detect/reply-header.js.map +1 -0
  134. package/dist/detect/signature.d.ts +28 -0
  135. package/dist/detect/signature.d.ts.map +1 -0
  136. package/dist/detect/signature.js +77 -0
  137. package/dist/detect/signature.js.map +1 -0
  138. package/dist/detect/traffic.d.ts +26 -0
  139. package/dist/detect/traffic.d.ts.map +1 -0
  140. package/dist/detect/traffic.js +98 -0
  141. package/dist/detect/traffic.js.map +1 -0
  142. package/dist/eval/metrics.d.ts +87 -0
  143. package/dist/eval/metrics.d.ts.map +1 -0
  144. package/dist/eval/metrics.js +185 -0
  145. package/dist/eval/metrics.js.map +1 -0
  146. package/dist/index.d.ts +54 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +163 -0
  149. package/dist/index.js.map +1 -0
  150. package/dist/match/history.d.ts +62 -0
  151. package/dist/match/history.d.ts.map +1 -0
  152. package/dist/match/history.js +128 -0
  153. package/dist/match/history.js.map +1 -0
  154. package/dist/match/normalize.d.ts +33 -0
  155. package/dist/match/normalize.d.ts.map +1 -0
  156. package/dist/match/normalize.js +63 -0
  157. package/dist/match/normalize.js.map +1 -0
  158. package/dist/match/shingle.d.ts +44 -0
  159. package/dist/match/shingle.d.ts.map +1 -0
  160. package/dist/match/shingle.js +78 -0
  161. package/dist/match/shingle.js.map +1 -0
  162. package/dist/mime/charset.d.ts +33 -0
  163. package/dist/mime/charset.d.ts.map +1 -0
  164. package/dist/mime/charset.js +118 -0
  165. package/dist/mime/charset.js.map +1 -0
  166. package/dist/mime/headers.d.ts +32 -0
  167. package/dist/mime/headers.d.ts.map +1 -0
  168. package/dist/mime/headers.js +127 -0
  169. package/dist/mime/headers.js.map +1 -0
  170. package/dist/mime/model.d.ts +111 -0
  171. package/dist/mime/model.d.ts.map +1 -0
  172. package/dist/mime/model.js +17 -0
  173. package/dist/mime/model.js.map +1 -0
  174. package/dist/mime/parse.d.ts +27 -0
  175. package/dist/mime/parse.d.ts.map +1 -0
  176. package/dist/mime/parse.js +343 -0
  177. package/dist/mime/parse.js.map +1 -0
  178. package/dist/segment/features.d.ts +29 -0
  179. package/dist/segment/features.d.ts.map +1 -0
  180. package/dist/segment/features.js +102 -0
  181. package/dist/segment/features.js.map +1 -0
  182. package/dist/segment/html-blocks.d.ts +28 -0
  183. package/dist/segment/html-blocks.d.ts.map +1 -0
  184. package/dist/segment/html-blocks.js +596 -0
  185. package/dist/segment/html-blocks.js.map +1 -0
  186. package/dist/segment/text-blocks.d.ts +30 -0
  187. package/dist/segment/text-blocks.d.ts.map +1 -0
  188. package/dist/segment/text-blocks.js +204 -0
  189. package/dist/segment/text-blocks.js.map +1 -0
  190. package/dist/segment/types.d.ts +88 -0
  191. package/dist/segment/types.d.ts.map +1 -0
  192. package/dist/segment/types.js +11 -0
  193. package/dist/segment/types.js.map +1 -0
  194. package/dist/types.d.ts +85 -0
  195. package/dist/types.d.ts.map +1 -0
  196. package/dist/types.js +17 -0
  197. package/dist/types.js.map +1 -0
  198. package/dist/util/hash.d.ts +49 -0
  199. package/dist/util/hash.d.ts.map +1 -0
  200. package/dist/util/hash.js +0 -0
  201. package/dist/util/hash.js.map +1 -0
  202. package/dist/util/lang.d.ts +25 -0
  203. package/dist/util/lang.d.ts.map +1 -0
  204. package/dist/util/lang.js +135 -0
  205. package/dist/util/lang.js.map +1 -0
  206. package/dist/util/worker-pool.d.ts +51 -0
  207. package/dist/util/worker-pool.d.ts.map +1 -0
  208. package/dist/util/worker-pool.js +155 -0
  209. package/dist/util/worker-pool.js.map +1 -0
  210. package/package.json +74 -0
@@ -0,0 +1,596 @@
1
+ "use strict";
2
+ /**
3
+ * Stage 3: HTML block segmentation.
4
+ *
5
+ * The DOM is walked with node-html-parser, which exposes a source `range` on every node. That is
6
+ * the reason it is used here rather than a faster tag stripper: a block that cannot point back at
7
+ * the exact source offsets it came from cannot be traced, and traceability is a requirement.
8
+ *
9
+ * Segmentation emits one block per run of inline content between block level elements. A container
10
+ * such as a Gmail quote wrapper does not become a block itself; instead every block inside it
11
+ * records its ancestry. That is deliberate, because interleaved replies put new content inside and
12
+ * between quote containers, and a container-level decision cannot express that.
13
+ *
14
+ * Blocks tile the source: each block's range is extended backwards to the end of the previous
15
+ * block, and the last block runs to the end of the document, so concatenating block texts
16
+ * reproduces the HTML exactly.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.isPathologicalHtml = isPathologicalHtml;
20
+ exports.segmentHtmlBlocks = segmentHtmlBlocks;
21
+ const node_html_parser_1 = require("node-html-parser");
22
+ const patterns_1 = require("../detect/patterns");
23
+ const reply_header_1 = require("../detect/reply-header");
24
+ const forward_header_1 = require("../detect/forward-header");
25
+ const signature_1 = require("../detect/signature");
26
+ const disclaimer_1 = require("../detect/disclaimer");
27
+ const html_1 = require("../canonical/html");
28
+ const features_1 = require("./features");
29
+ /** Elements that break a run of inline content. */
30
+ const BLOCK_TAGS = new Set([
31
+ 'address',
32
+ 'article',
33
+ 'aside',
34
+ 'blockquote',
35
+ 'body',
36
+ 'center',
37
+ 'dd',
38
+ 'div',
39
+ 'dl',
40
+ 'dt',
41
+ 'fieldset',
42
+ 'figcaption',
43
+ 'figure',
44
+ 'footer',
45
+ 'form',
46
+ 'h1',
47
+ 'h2',
48
+ 'h3',
49
+ 'h4',
50
+ 'h5',
51
+ 'h6',
52
+ 'header',
53
+ 'hr',
54
+ 'html',
55
+ 'li',
56
+ 'main',
57
+ 'nav',
58
+ 'ol',
59
+ 'p',
60
+ 'pre',
61
+ 'section',
62
+ 'table',
63
+ 'tbody',
64
+ 'td',
65
+ 'tfoot',
66
+ 'th',
67
+ 'thead',
68
+ 'tr',
69
+ 'ul'
70
+ ]);
71
+ /** Elements whose content is never visible text. */
72
+ const INVISIBLE_TAGS = new Set(['script', 'style', 'head', 'title', 'noscript', 'template', 'meta', 'link']);
73
+ /**
74
+ * Parse the simple selector forms used in html-clients.json.
75
+ *
76
+ * Only `tag`, `tag.class`, `tag#id`, `tag[attr=value]` and their bare forms are supported. A full
77
+ * CSS engine is not needed, and a hand written matcher makes the behaviour predictable, including
78
+ * the Outlook Web nesting rule below.
79
+ */
80
+ function parseSelector(selector) {
81
+ const attrMatch = selector.match(/^([a-z0-9-]*)\[([a-z-]+)=["']?([^\]"']+)["']?\]$/i);
82
+ if (attrMatch) {
83
+ return { tag: attrMatch[1] || null, className: null, id: null, attr: { name: attrMatch[2], value: attrMatch[3].toLowerCase() } };
84
+ }
85
+ const idMatch = selector.match(/^([a-z0-9-]*)#([\w-]+)$/i);
86
+ if (idMatch) {
87
+ return { tag: idMatch[1] || null, className: null, id: idMatch[2].toLowerCase(), attr: null };
88
+ }
89
+ const classMatch = selector.match(/^([a-z0-9-]*)\.([\w-]+)$/i);
90
+ if (classMatch) {
91
+ return { tag: classMatch[1] || null, className: classMatch[2].toLowerCase(), id: null, attr: null };
92
+ }
93
+ return { tag: selector.toLowerCase() || null, className: null, id: null, attr: null };
94
+ }
95
+ const SELECTOR_CACHE = new Map();
96
+ function selectorFor(selector) {
97
+ let parsed = SELECTOR_CACHE.get(selector);
98
+ if (!parsed) {
99
+ parsed = parseSelector(selector);
100
+ SELECTOR_CACHE.set(selector, parsed);
101
+ }
102
+ return parsed;
103
+ }
104
+ /**
105
+ * Class name comparison that tolerates the Outlook Web nesting prefix.
106
+ *
107
+ * When Outlook Web quotes a message it rewrites the quoted markup's class names with an `x_`
108
+ * prefix, so a quoted Gmail reply arrives as `x_gmail_quote`. Stripping the prefix keeps the
109
+ * detectors working one level deeper into the history, which is exactly where they are needed.
110
+ */
111
+ function classMatches(classNames, wanted) {
112
+ for (const name of classNames) {
113
+ const lowered = name.toLowerCase();
114
+ if (lowered === wanted || lowered.replace(/^x_/, '') === wanted) {
115
+ return true;
116
+ }
117
+ }
118
+ return false;
119
+ }
120
+ function elementMatches(element, selector) {
121
+ if (selector.tag && element.rawTagName?.toLowerCase() !== selector.tag) {
122
+ return false;
123
+ }
124
+ if (selector.className) {
125
+ const classes = String(element.getAttribute('class') || '')
126
+ .split(/\s+/)
127
+ .filter(Boolean);
128
+ if (!classMatches(classes, selector.className)) {
129
+ return false;
130
+ }
131
+ }
132
+ if (selector.id) {
133
+ const id = String(element.getAttribute('id') || '').toLowerCase();
134
+ if (id !== selector.id && id.replace(/^x_/, '') !== selector.id) {
135
+ return false;
136
+ }
137
+ }
138
+ if (selector.attr) {
139
+ const value = String(element.getAttribute(selector.attr.name) || '').toLowerCase();
140
+ if (value !== selector.attr.value) {
141
+ return false;
142
+ }
143
+ }
144
+ return true;
145
+ }
146
+ /** Outlook and Word mark a reply boundary with a top border on an otherwise empty element. */
147
+ function hasTopBorder(element) {
148
+ const style = String(element.getAttribute('style') || '');
149
+ return /border-top\s*:\s*(?!none)[^;]+/i.test(style);
150
+ }
151
+ function isElement(node) {
152
+ return node.nodeType === node_html_parser_1.NodeType.ELEMENT_NODE;
153
+ }
154
+ /**
155
+ * Markup that leaked into a text node.
156
+ *
157
+ * node-html-parser treats `<pre>` as a raw text element, so its children are never parsed and its
158
+ * markup arrives as literal text. Per the HTML specification `<pre>` content is ordinary parsed
159
+ * markup, and a browser renders a `<table>` inside a `<pre>` as a table, so the reader never saw
160
+ * those angle brackets. Leaving them in would put raw HTML into the extracted text, which is
161
+ * exactly what happened to Gmail signature tables wrapped in `<pre>`.
162
+ *
163
+ * Someone genuinely quoting HTML source escapes it as `&lt;table&gt;`, which is a text node with no
164
+ * tags in it and is therefore untouched by this.
165
+ */
166
+ const CONDITIONAL_COMMENT = /<!\[[^\]]*\]>/g;
167
+ const LEAKED_MARKUP = /<[a-z][a-z0-9]*(?:\s[^>]*)?>/i;
168
+ /** Leading lines of a block, for line anchored detectors. */
169
+ function firstLines(text, limit = 3) {
170
+ return text
171
+ .split('\n', limit)
172
+ .map(line => line.trim())
173
+ .filter(Boolean);
174
+ }
175
+ /** Text projection of an inline run, with <br> and block boundaries becoming newlines. */
176
+ function projectText(nodes) {
177
+ let out = '';
178
+ const visit = (node) => {
179
+ if (node.nodeType === node_html_parser_1.NodeType.TEXT_NODE) {
180
+ const raw = node.rawText ?? '';
181
+ const cleaned = raw.replace(CONDITIONAL_COMMENT, '');
182
+ out += LEAKED_MARKUP.test(cleaned) ? (0, html_1.stripTagsToText)(cleaned) : (0, html_1.decodeEntities)(cleaned);
183
+ return;
184
+ }
185
+ if (!isElement(node)) {
186
+ return;
187
+ }
188
+ const tag = node.rawTagName?.toLowerCase() ?? '';
189
+ if (INVISIBLE_TAGS.has(tag)) {
190
+ return;
191
+ }
192
+ if (tag === 'br') {
193
+ out += '\n';
194
+ return;
195
+ }
196
+ if (tag === 'img') {
197
+ return;
198
+ }
199
+ for (const child of node.childNodes) {
200
+ visit(child);
201
+ }
202
+ };
203
+ for (const node of nodes) {
204
+ visit(node);
205
+ }
206
+ // Collapse runs of spaces the way a renderer would, but keep explicit newlines.
207
+ return out
208
+ .replace(/\r\n?/g, '\n')
209
+ .replace(/[^\S\n]+/g, ' ')
210
+ .replace(/ *\n */g, '\n')
211
+ .replace(/\n{3,}/g, '\n\n')
212
+ .trim();
213
+ }
214
+ /** Descendant nodes inspected per block. Bounds per block work on pathological subtrees. */
215
+ const MAX_SCAN_NODES = 2000;
216
+ function countTag(nodes, tag) {
217
+ let count = 0;
218
+ let budget = MAX_SCAN_NODES;
219
+ const visit = (node) => {
220
+ if (budget-- <= 0) {
221
+ return;
222
+ }
223
+ if (isElement(node)) {
224
+ if (node.rawTagName?.toLowerCase() === tag) {
225
+ count++;
226
+ }
227
+ for (const child of node.childNodes) {
228
+ visit(child);
229
+ }
230
+ }
231
+ };
232
+ for (const node of nodes) {
233
+ visit(node);
234
+ }
235
+ return count;
236
+ }
237
+ function collectTagsAndClasses(nodes, ancestors) {
238
+ const tags = new Set();
239
+ const classes = new Set();
240
+ let budget = MAX_SCAN_NODES;
241
+ const addElement = (element) => {
242
+ const tag = element.rawTagName?.toLowerCase();
243
+ if (tag) {
244
+ tags.add(tag);
245
+ }
246
+ for (const name of String(element.getAttribute('class') || '').split(/\s+/)) {
247
+ if (name) {
248
+ classes.add(name.toLowerCase());
249
+ }
250
+ }
251
+ };
252
+ for (const ancestor of ancestors) {
253
+ addElement(ancestor.element);
254
+ }
255
+ const visit = (node) => {
256
+ if (budget-- <= 0) {
257
+ return;
258
+ }
259
+ if (isElement(node)) {
260
+ addElement(node);
261
+ for (const child of node.childNodes) {
262
+ visit(child);
263
+ }
264
+ }
265
+ };
266
+ for (const node of nodes) {
267
+ visit(node);
268
+ }
269
+ return { tags: [...tags], classes: [...classes] };
270
+ }
271
+ function evidenceFromAncestry(ancestors) {
272
+ const evidence = new Map();
273
+ for (const ancestor of ancestors) {
274
+ for (const pattern of ancestor.matches) {
275
+ const kind = pattern.role === 'quote'
276
+ ? 'quote-container'
277
+ : pattern.role === 'attribution'
278
+ ? 'attribution'
279
+ : pattern.role === 'separator'
280
+ ? 'separator'
281
+ : pattern.role === 'signature'
282
+ ? 'signature'
283
+ : pattern.role === 'new'
284
+ ? 'new-content'
285
+ : 'hint';
286
+ const id = `html:${pattern.id}`;
287
+ const existing = evidence.get(id);
288
+ if (!existing || existing.strength < pattern.strength) {
289
+ evidence.set(id, { id, kind, strength: pattern.strength });
290
+ }
291
+ }
292
+ }
293
+ return [...evidence.values()];
294
+ }
295
+ function kindFor(nodes, ancestors, text, evidence) {
296
+ if (!text.trim()) {
297
+ const onlyImages = nodes.some(node => isElement(node) && node.rawTagName?.toLowerCase() === 'img');
298
+ if (onlyImages) {
299
+ return 'image';
300
+ }
301
+ const onlyRule = nodes.some(node => isElement(node) && node.rawTagName?.toLowerCase() === 'hr');
302
+ return onlyRule ? 'separator' : 'blank';
303
+ }
304
+ // Checked before the embedded header block below, and the order matters: a forwarded message
305
+ // begins with its marker and then repeats the original From/Date/Subject/To fields, so a header
306
+ // block test would claim it first and turn every forward into reply history.
307
+ // A forward marker is the same thing in HTML as in plain text, and must open a forwarded region
308
+ // the same way. Without this, an HTML forward is invisible to the classifier and its contents
309
+ // fall through to the reply history rules, which is how forwarded mail was being hidden.
310
+ //
311
+ // Matched per line, not against the whole block. In HTML the marker and the forwarded message's
312
+ // headers usually collapse into one block, so a whole-block test against line anchored patterns
313
+ // never fires.
314
+ if (firstLines(text).some(line => (0, forward_header_1.detectForwardMarker)(line))) {
315
+ return 'forward_header';
316
+ }
317
+ // An embedded copy of the previous message's headers. Outlook and several webmail clients emit
318
+ // From/Sent/To/Subject as one block, with <br> between the fields. This was wired into the plain
319
+ // text segmenter only, so in HTML the strongest reply anchor there is went undetected and every
320
+ // block after it stayed NEW_CONTENT. It was the single largest error cell against the reference.
321
+ if ((0, reply_header_1.detectQuotedHeaderBlock)(text.split('\n').map(line => line.trim())) !== null) {
322
+ return 'quoted_header_block';
323
+ }
324
+ // A container the client marked as an attribution line, such as Gmail's gmail_attr, is the same
325
+ // thing as a plain text "On ... wrote:" line and must anchor the region the same way.
326
+ if (evidence.some(item => item.kind === 'attribution')) {
327
+ return 'reply_header';
328
+ }
329
+ // Clients that use no marker class still emit the attribution as its own short element.
330
+ if (text.length <= 300 && !text.includes('\n') && (0, reply_header_1.detectAttributionLine)(text)) {
331
+ return 'reply_header';
332
+ }
333
+ if (ancestors.some(ancestor => ancestor.element.rawTagName?.toLowerCase() === 'blockquote')) {
334
+ return 'quote';
335
+ }
336
+ const tags = new Set(ancestors.map(ancestor => ancestor.element.rawTagName?.toLowerCase()));
337
+ if (tags.has('li')) {
338
+ return 'list';
339
+ }
340
+ if (tags.has('td') || tags.has('th')) {
341
+ return 'table';
342
+ }
343
+ return 'paragraph';
344
+ }
345
+ /**
346
+ * Segment an HTML part into blocks.
347
+ *
348
+ * @param html decoded HTML source of the part
349
+ * @param mimePart part id for traceability
350
+ */
351
+ /**
352
+ * Unclosed block tags tolerated before the DOM parse is skipped.
353
+ *
354
+ * node-html-parser degrades badly on deeply unbalanced markup: 5,000 unclosed divs, which is only
355
+ * 25 KB, take six and a half seconds inside the parser itself, before any of this module's code
356
+ * runs. Size is not the signal, imbalance is. Real mail, including thoroughly broken real mail,
357
+ * does not come close to this threshold.
358
+ */
359
+ const MAX_UNCLOSED_TAGS = 500;
360
+ const OPEN_BLOCK_TAG = /<(?:div|table|tr|td|span|p|blockquote|ul|ol|li|font)\b/gi;
361
+ const CLOSE_BLOCK_TAG = /<\/(?:div|table|tr|td|span|p|blockquote|ul|ol|li|font)\b/gi;
362
+ function countPattern(text, regex) {
363
+ regex.lastIndex = 0;
364
+ let count = 0;
365
+ while (regex.exec(text) !== null) {
366
+ count++;
367
+ }
368
+ regex.lastIndex = 0;
369
+ return count;
370
+ }
371
+ /** True when markup is unbalanced enough that parsing it is not worth the time. */
372
+ function isPathologicalHtml(html) {
373
+ return countPattern(html, OPEN_BLOCK_TAG) - countPattern(html, CLOSE_BLOCK_TAG) > MAX_UNCLOSED_TAGS;
374
+ }
375
+ function segmentHtmlBlocks(html, mimePart) {
376
+ const patterns = (0, patterns_1.loadPatterns)();
377
+ let root;
378
+ try {
379
+ if (isPathologicalHtml(html)) {
380
+ // Degrade to a single visible block rather than spending seconds in the parser. Nothing
381
+ // is lost: the caller still receives the whole body, just unsegmented.
382
+ throw new Error('unbalanced markup');
383
+ }
384
+ root = (0, node_html_parser_1.parse)(html, { comment: false });
385
+ }
386
+ catch {
387
+ // A parse failure must still yield the content, as one unknown block.
388
+ return {
389
+ source: html,
390
+ degraded: true,
391
+ blocks: [
392
+ {
393
+ index: 0,
394
+ kind: 'unknown',
395
+ representation: 'html',
396
+ mimePart,
397
+ text: html,
398
+ content: '',
399
+ start: 0,
400
+ end: html.length,
401
+ html,
402
+ features: (0, features_1.computeFeatures)('', { index: 0, total: 1, start: 0, totalChars: html.length, quoteDepth: 0 }),
403
+ evidence: []
404
+ }
405
+ ]
406
+ };
407
+ }
408
+ const runs = [];
409
+ /**
410
+ * Depth cap.
411
+ *
412
+ * Real mail nests deeply: a long thread quoted by Outlook Web inside Gmail can reach thirty
413
+ * levels. Five thousand unclosed divs is not real mail, and walking it made the per block
414
+ * ancestor and descendant scans quadratic, taking six seconds. Beyond this depth the remaining
415
+ * subtree is emitted as a single run rather than descended into, so content is still returned.
416
+ */
417
+ const MAX_DEPTH = 150;
418
+ const walk = (node, ancestors, path) => {
419
+ if (ancestors.length > MAX_DEPTH) {
420
+ if (node.childNodes.length) {
421
+ runs.push({ run: { nodes: [...node.childNodes], ancestors: [...ancestors] }, domPath: path });
422
+ }
423
+ return;
424
+ }
425
+ let pending = [];
426
+ let pendingIndex = 0;
427
+ const flush = () => {
428
+ if (pending.length) {
429
+ runs.push({ run: { nodes: pending, ancestors: [...ancestors] }, domPath: `${path}/${pendingIndex}` });
430
+ pending = [];
431
+ }
432
+ };
433
+ node.childNodes.forEach((child, childIndex) => {
434
+ if (isElement(child)) {
435
+ const tag = child.rawTagName?.toLowerCase() ?? '';
436
+ if (INVISIBLE_TAGS.has(tag)) {
437
+ return;
438
+ }
439
+ if (BLOCK_TAGS.has(tag)) {
440
+ flush();
441
+ const matches = patterns.htmlSelectors.filter(pattern => elementMatches(child, selectorFor(pattern.selector)));
442
+ if (hasTopBorder(child)) {
443
+ matches.push({
444
+ id: 'outlook_border_separator',
445
+ client: 'outlook-desktop',
446
+ role: 'separator',
447
+ strength: 0.6,
448
+ selector: '[style*=border-top]',
449
+ prevalence: 0.03
450
+ });
451
+ }
452
+ walk(child, [...ancestors, { element: child, matches }], `${path}/${childIndex}`);
453
+ return;
454
+ }
455
+ }
456
+ if (!pending.length) {
457
+ pendingIndex = childIndex;
458
+ }
459
+ pending.push(child);
460
+ });
461
+ flush();
462
+ // An empty block element still carries structural meaning, for example an <hr> used as a
463
+ // reply separator, so it becomes a block of its own.
464
+ if (!node.childNodes.length) {
465
+ const tag = node.rawTagName?.toLowerCase();
466
+ if (tag === 'hr' || tag === 'br') {
467
+ runs.push({ run: { nodes: [node], ancestors: [...ancestors] }, domPath: path });
468
+ }
469
+ }
470
+ };
471
+ walk(root, [], '');
472
+ const blocks = [];
473
+ let previousEnd = 0;
474
+ for (const { run, domPath } of runs) {
475
+ const ranges = run.nodes.map(node => node.range).filter(Boolean);
476
+ if (!ranges.length) {
477
+ continue;
478
+ }
479
+ const nodeStart = Math.min(...ranges.map(range => range[0]));
480
+ const nodeEnd = Math.max(...ranges.map(range => range[1]));
481
+ if (nodeEnd <= previousEnd) {
482
+ continue;
483
+ }
484
+ // Extend backwards so that markup between blocks belongs to exactly one block.
485
+ const start = Math.min(previousEnd, nodeStart);
486
+ const text = projectText(run.nodes);
487
+ const { tags, classes } = collectTagsAndClasses(run.nodes, run.ancestors);
488
+ const blockquoteDepth = run.ancestors.filter(ancestor => ancestor.element.rawTagName?.toLowerCase() === 'blockquote').length;
489
+ const evidence = evidenceFromAncestry(run.ancestors);
490
+ const kind = kindFor(run.nodes, run.ancestors, text, evidence);
491
+ if (kind === 'reply_header' && !evidence.some(item => item.kind === 'reply-anchor' || item.kind === 'attribution')) {
492
+ const attribution = (0, reply_header_1.detectAttributionLine)(text);
493
+ if (attribution) {
494
+ evidence.push(attribution);
495
+ }
496
+ }
497
+ if (kind === 'quoted_header_block') {
498
+ const match = (0, reply_header_1.detectQuotedHeaderBlock)(text.split('\n').map(line => line.trim()));
499
+ if (match) {
500
+ evidence.push(match.evidence);
501
+ }
502
+ }
503
+ if (kind === 'forward_header') {
504
+ for (const line of firstLines(text)) {
505
+ const forward = (0, forward_header_1.detectForwardMarker)(line);
506
+ if (forward) {
507
+ evidence.push(forward);
508
+ break;
509
+ }
510
+ }
511
+ }
512
+ blocks.push({
513
+ index: blocks.length,
514
+ kind,
515
+ representation: 'html',
516
+ mimePart,
517
+ text: html.slice(start, nodeEnd),
518
+ content: text,
519
+ start,
520
+ end: nodeEnd,
521
+ html: html.slice(nodeStart, nodeEnd),
522
+ domPath,
523
+ features: (0, features_1.computeFeatures)(text, {
524
+ index: blocks.length,
525
+ total: runs.length,
526
+ start,
527
+ totalChars: html.length,
528
+ quoteDepth: blockquoteDepth,
529
+ blockquoteDepth,
530
+ elementCount: run.nodes.filter(isElement).length,
531
+ tags,
532
+ classes,
533
+ hasTopBorder: run.ancestors.some(ancestor => hasTopBorder(ancestor.element)),
534
+ linkCount: countTag(run.nodes, 'a'),
535
+ imageCount: countTag(run.nodes, 'img')
536
+ }),
537
+ evidence
538
+ });
539
+ previousEnd = nodeEnd;
540
+ }
541
+ // Trailing markup belongs to the last block, so that the blocks tile the whole document.
542
+ if (blocks.length) {
543
+ const last = blocks[blocks.length - 1];
544
+ if (last.end < html.length) {
545
+ last.end = html.length;
546
+ last.text = html.slice(last.start, html.length);
547
+ }
548
+ }
549
+ else if (html.length) {
550
+ blocks.push({
551
+ index: 0,
552
+ kind: 'blank',
553
+ representation: 'html',
554
+ mimePart,
555
+ text: html,
556
+ content: '',
557
+ start: 0,
558
+ end: html.length,
559
+ html,
560
+ features: (0, features_1.computeFeatures)('', { index: 0, total: 1, start: 0, totalChars: html.length, quoteDepth: 0 }),
561
+ evidence: []
562
+ });
563
+ }
564
+ // Block level footer evidence, once positions are known.
565
+ //
566
+ // These detectors were originally wired into the plain text segmenter only, which meant HTML
567
+ // blocks never received signature or disclaimer evidence at all. Since most messages are HTML
568
+ // primary, that alone accounted for signature recall of 2.5 percent and disclaimer recall of
569
+ // zero against the reference set.
570
+ for (const block of blocks) {
571
+ block.features.indexFromEnd = blocks.length - 1 - block.index;
572
+ if (block.kind === 'blank' || block.features.isAllBlank) {
573
+ continue;
574
+ }
575
+ const lines = block.content.split('\n');
576
+ for (const line of lines) {
577
+ const delimiter = (0, signature_1.detectSignatureDelimiter)(line.trim());
578
+ if (delimiter) {
579
+ block.evidence.push(delimiter);
580
+ break;
581
+ }
582
+ }
583
+ for (const evidence of (0, signature_1.detectSignaturePhrases)(lines)) {
584
+ block.evidence.push(evidence);
585
+ }
586
+ const shape = (0, signature_1.detectSignatureShape)(block.features);
587
+ if (shape) {
588
+ block.evidence.push(shape);
589
+ }
590
+ for (const evidence of (0, disclaimer_1.detectDisclaimer)(block.content, block.features)) {
591
+ block.evidence.push(evidence);
592
+ }
593
+ }
594
+ return { source: html, blocks, degraded: false };
595
+ }
596
+ //# sourceMappingURL=html-blocks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-blocks.js","sourceRoot":"","sources":["../../src/segment/html-blocks.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAmZH,gDAEC;AAED,8CAyOC;AA9nBD,uDAAgF;AAChF,iDAAwE;AACxE,yDAAwF;AACxF,6DAA+D;AAC/D,mDAA6G;AAC7G,qDAAwD;AACxD,4CAAoE;AACpE,yCAA6C;AAG7C,mDAAmD;AACnD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACvB,SAAS;IACT,SAAS;IACT,OAAO;IACP,YAAY;IACZ,MAAM;IACN,QAAQ;IACR,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,IAAI;IACJ,UAAU;IACV,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,QAAQ;IACR,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,MAAM;IACN,KAAK;IACL,IAAI;IACJ,GAAG;IACH,KAAK;IACL,SAAS;IACT,OAAO;IACP,OAAO;IACP,IAAI;IACJ,OAAO;IACP,IAAI;IACJ,OAAO;IACP,IAAI;IACJ,IAAI;CACP,CAAC,CAAC;AAEH,oDAAoD;AACpD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAS7G;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,QAAgB;IACnC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACtF,IAAI,SAAS,EAAE,CAAC;QACZ,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAW,EAAE,KAAK,EAAG,SAAS,CAAC,CAAC,CAAY,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC;IAC3J,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAC3D,IAAI,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAG,OAAO,CAAC,CAAC,CAAY,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9G,CAAC;IACD,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/D,IAAI,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,SAAS,EAAG,UAAU,CAAC,CAAC,CAAY,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACpH,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC1F,CAAC;AAED,MAAM,cAAc,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEzD,SAAS,WAAW,CAAC,QAAgB;IACjC,IAAI,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,UAA6B,EAAE,MAAc;IAC/D,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,MAAM,EAAE,CAAC;YAC9D,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,OAAoB,EAAE,QAAwB;IAClE,IAAI,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,QAAQ,CAAC,GAAG,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;aACtD,KAAK,CAAC,KAAK,CAAC;aACZ,MAAM,CAAC,OAAO,CAAC,CAAC;QACrB,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7C,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QACd,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAClE,IAAI,EAAE,KAAK,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,QAAQ,CAAC,EAAE,EAAE,CAAC;YAC9D,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACnF,IAAI,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChC,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED,8FAA8F;AAC9F,SAAS,YAAY,CAAC,OAAoB;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,OAAO,iCAAiC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAYD,SAAS,SAAS,CAAC,IAAU;IACzB,OAAO,IAAI,CAAC,QAAQ,KAAK,2BAAQ,CAAC,YAAY,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AAC7C,MAAM,aAAa,GAAG,+BAA+B,CAAC;AAEtD,6DAA6D;AAC7D,SAAS,UAAU,CAAC,IAAY,EAAE,KAAK,GAAG,CAAC;IACvC,OAAO,IAAI;SACN,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;SAClB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,0FAA0F;AAC1F,SAAS,WAAW,CAAC,KAAsB;IACvC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,MAAM,KAAK,GAAG,CAAC,IAAU,EAAE,EAAE;QACzB,IAAI,IAAI,CAAC,QAAQ,KAAK,2BAAQ,CAAC,SAAS,EAAE,CAAC;YACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;YACrD,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAA,sBAAe,EAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAc,EAAC,OAAO,CAAC,CAAC;YACxF,OAAO;QACX,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACnB,OAAO;QACX,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;QACjD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO;QACX,CAAC;QACD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACf,GAAG,IAAI,IAAI,CAAC;YACZ,OAAO;QACX,CAAC;QACD,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACL,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IACD,gFAAgF;IAChF,OAAO,GAAG;SACL,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC;SACvB,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;SACzB,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC;SACxB,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,4FAA4F;AAC5F,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,SAAS,QAAQ,CAAC,KAAsB,EAAE,GAAW;IACjD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,cAAc,CAAC;IAC5B,MAAM,KAAK,GAAG,CAAC,IAAU,EAAE,EAAE;QACzB,IAAI,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,IAAI,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,GAAG,EAAE,CAAC;gBACzC,KAAK,EAAE,CAAC;YACZ,CAAC;YACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAsB,EAAE,SAA8B;IACjF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,IAAI,MAAM,GAAG,cAAc,CAAC;IAC5B,MAAM,UAAU,GAAG,CAAC,OAAoB,EAAE,EAAE;QACxC,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,CAAC;QAC9C,IAAI,GAAG,EAAE,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClB,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1E,IAAI,IAAI,EAAE,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACpC,CAAC;QACL,CAAC;IACL,CAAC,CAAC;IACF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,IAAU,EAAE,EAAE;QACzB,IAAI,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YAChB,OAAO;QACX,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAClB,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBAClC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;QACL,CAAC;IACL,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,SAAS,oBAAoB,CAAC,SAA8B;IACxD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC7C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,GACN,OAAO,CAAC,IAAI,KAAK,OAAO;gBACpB,CAAC,CAAC,iBAAiB;gBACnB,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa;oBAC9B,CAAC,CAAC,aAAa;oBACf,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;wBAC5B,CAAC,CAAC,WAAW;wBACb,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;4BAC5B,CAAC,CAAC,WAAW;4BACb,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,KAAK;gCACtB,CAAC,CAAC,aAAa;gCACf,CAAC,CAAC,MAAM,CAAC;YACzB,MAAM,EAAE,GAAG,QAAQ,OAAO,CAAC,EAAE,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACpD,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC/D,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,OAAO,CAAC,KAAsB,EAAE,SAA8B,EAAE,IAAY,EAAE,QAA6B;IAChH,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;QACnG,IAAI,UAAU,EAAE,CAAC;YACb,OAAO,OAAO,CAAC;QACnB,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC,CAAC;QAChG,OAAO,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5C,CAAC;IACD,6FAA6F;IAC7F,gGAAgG;IAChG,6EAA6E;IAC7E,gGAAgG;IAChG,8FAA8F;IAC9F,yFAAyF;IACzF,EAAE;IACF,gGAAgG;IAChG,gGAAgG;IAChG,eAAe;IACf,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAA,oCAAmB,EAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC3D,OAAO,gBAAgB,CAAC;IAC5B,CAAC;IAED,+FAA+F;IAC/F,iGAAiG;IACjG,gGAAgG;IAChG,iGAAiG;IACjG,IAAI,IAAA,sCAAuB,EAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9E,OAAO,qBAAqB,CAAC;IACjC,CAAC;IAED,gGAAgG;IAChG,sFAAsF;IACtF,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC,EAAE,CAAC;QACrD,OAAO,cAAc,CAAC;IAC1B,CAAC;IACD,wFAAwF;IACxF,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAA,oCAAqB,EAAC,IAAI,CAAC,EAAE,CAAC;QAC5E,OAAO,cAAc,CAAC;IAC1B,CAAC;IACD,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,YAAY,CAAC,EAAE,CAAC;QAC1F,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;IAC5F,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,OAAO,MAAM,CAAC;IAClB,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,OAAO,OAAO,CAAC;IACnB,CAAC;IACD,OAAO,WAAW,CAAC;AACvB,CAAC;AAUD;;;;;GAKG;AACH;;;;;;;GAOG;AACH,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,MAAM,cAAc,GAAG,0DAA0D,CAAC;AAClF,MAAM,eAAe,GAAG,4DAA4D,CAAC;AAErF,SAAS,YAAY,CAAC,IAAY,EAAE,KAAa;IAC7C,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;IACpB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/B,KAAK,EAAE,CAAC;IACZ,CAAC;IACD,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC;IACpB,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,mFAAmF;AACnF,SAAgB,kBAAkB,CAAC,IAAY;IAC3C,OAAO,YAAY,CAAC,IAAI,EAAE,cAAc,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,eAAe,CAAC,GAAG,iBAAiB,CAAC;AACxG,CAAC;AAED,SAAgB,iBAAiB,CAAC,IAAY,EAAE,QAAgB;IAC5D,MAAM,QAAQ,GAAG,IAAA,uBAAY,GAAE,CAAC;IAEhC,IAAI,IAAiB,CAAC;IACtB,IAAI,CAAC;QACD,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,wFAAwF;YACxF,uEAAuE;YACvE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,GAAG,IAAA,wBAAK,EAAC,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACL,sEAAsE;QACtE,OAAO;YACH,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACJ;oBACI,KAAK,EAAE,CAAC;oBACR,IAAI,EAAE,SAAS;oBACf,cAAc,EAAE,MAAM;oBACtB,QAAQ;oBACR,IAAI,EAAE,IAAI;oBACV,OAAO,EAAE,EAAE;oBACX,KAAK,EAAE,CAAC;oBACR,GAAG,EAAE,IAAI,CAAC,MAAM;oBAChB,IAAI;oBACJ,QAAQ,EAAE,IAAA,0BAAe,EAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;oBACvG,QAAQ,EAAE,EAAE;iBACf;aACJ;SACJ,CAAC;IACN,CAAC;IAED,MAAM,IAAI,GAA0C,EAAE,CAAC;IAEvD;;;;;;;OAOG;IACH,MAAM,SAAS,GAAG,GAAG,CAAC;IAEtB,MAAM,IAAI,GAAG,CAAC,IAAiB,EAAE,SAAqB,EAAE,IAAY,EAAE,EAAE;QACpE,IAAI,SAAS,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YAClG,CAAC;YACD,OAAO;QACX,CAAC;QACD,IAAI,OAAO,GAAW,EAAE,CAAC;QACzB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,MAAM,KAAK,GAAG,GAAG,EAAE;YACf,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,IAAI,IAAI,YAAY,EAAE,EAAE,CAAC,CAAC;gBACtG,OAAO,GAAG,EAAE,CAAC;YACjB,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE;YAC1C,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnB,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;gBAClD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC1B,OAAO;gBACX,CAAC;gBACD,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtB,KAAK,EAAE,CAAC;oBACR,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;oBAC/G,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;wBACtB,OAAO,CAAC,IAAI,CAAC;4BACT,EAAE,EAAE,0BAA0B;4BAC9B,MAAM,EAAE,iBAAiB;4BACzB,IAAI,EAAE,WAAW;4BACjB,QAAQ,EAAE,GAAG;4BACb,QAAQ,EAAE,qBAAqB;4BAC/B,UAAU,EAAE,IAAI;yBACnB,CAAC,CAAC;oBACP,CAAC;oBACD,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC;oBAClF,OAAO;gBACX,CAAC;YACL,CAAC;YACD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAClB,YAAY,GAAG,UAAU,CAAC;YAC9B,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,KAAK,EAAE,CAAC;QAER,yFAAyF;QACzF,qDAAqD;QACrD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,CAAC;YAC3C,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACpF,CAAC;QACL,CAAC;IACL,CAAC,CAAC;IAEF,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAEnB,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAuB,CAAC;QACvF,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACjB,SAAS;QACb,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,IAAI,OAAO,IAAI,WAAW,EAAE,CAAC;YACzB,SAAS;QACb,CAAC;QACD,+EAA+E;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,qBAAqB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC1E,MAAM,eAAe,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,YAAY,CAAC,CAAC,MAAM,CAAC;QAC7H,MAAM,QAAQ,GAAG,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC/D,IAAI,IAAI,KAAK,cAAc,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC,EAAE,CAAC;YACjH,MAAM,WAAW,GAAG,IAAA,oCAAqB,EAAC,IAAI,CAAC,CAAC;YAChD,IAAI,WAAW,EAAE,CAAC;gBACd,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/B,CAAC;QACL,CAAC;QACD,IAAI,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,IAAA,sCAAuB,EAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACjF,IAAI,KAAK,EAAE,CAAC;gBACR,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAClC,CAAC;QACL,CAAC;QACD,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC5B,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAClC,MAAM,OAAO,GAAG,IAAA,oCAAmB,EAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,OAAO,EAAE,CAAC;oBACV,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACvB,MAAM;gBACV,CAAC;YACL,CAAC;QACL,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YACR,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,IAAI;YACJ,cAAc,EAAE,MAAM;YACtB,QAAQ;YACR,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC;YAChC,OAAO,EAAE,IAAI;YACb,KAAK;YACL,GAAG,EAAE,OAAO;YACZ,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC;YACpC,OAAO;YACP,QAAQ,EAAE,IAAA,0BAAe,EAAC,IAAI,EAAE;gBAC5B,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,KAAK,EAAE,IAAI,CAAC,MAAM;gBAClB,KAAK;gBACL,UAAU,EAAE,IAAI,CAAC,MAAM;gBACvB,UAAU,EAAE,eAAe;gBAC3B,eAAe;gBACf,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM;gBAChD,IAAI;gBACJ,OAAO;gBACP,YAAY,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBAC5E,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC;gBACnC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;aACzC,CAAC;YACF,QAAQ;SACX,CAAC,CAAC;QACH,WAAW,GAAG,OAAO,CAAC;IAC1B,CAAC;IAED,yFAAyF;IACzF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAU,CAAC;QAChD,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACzB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;YACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,CAAC;IACL,CAAC;SAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,CAAC;YACR,KAAK,EAAE,CAAC;YACR,IAAI,EAAE,OAAO;YACb,cAAc,EAAE,MAAM;YACtB,QAAQ;YACR,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,CAAC;YACR,GAAG,EAAE,IAAI,CAAC,MAAM;YAChB,IAAI;YACJ,QAAQ,EAAE,IAAA,0BAAe,EAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;YACvG,QAAQ,EAAE,EAAE;SACf,CAAC,CAAC;IACP,CAAC;IAED,yDAAyD;IACzD,EAAE;IACF,6FAA6F;IAC7F,8FAA8F;IAC9F,6FAA6F;IAC7F,kCAAkC;IAClC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACzB,KAAK,CAAC,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QAC9D,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtD,SAAS;QACb,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,IAAA,oCAAwB,EAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,IAAI,SAAS,EAAE,CAAC;gBACZ,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC/B,MAAM;YACV,CAAC;QACL,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,IAAA,kCAAsB,EAAC,KAAK,CAAC,EAAE,CAAC;YACnD,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,KAAK,GAAG,IAAA,gCAAoB,EAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,KAAK,EAAE,CAAC;YACR,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,MAAM,QAAQ,IAAI,IAAA,6BAAgB,EAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AACrD,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Stage 3: plain text block segmentation.
3
+ *
4
+ * Blocks tile the canonical text completely and without overlap. Every character belongs to exactly
5
+ * one block, including blank lines and trailing whitespace, so that concatenating block texts
6
+ * reproduces the input exactly. That is maintained by construction here, and asserted as a property
7
+ * test, because it is what guarantees content cannot vanish between stages.
8
+ *
9
+ * Boundaries are placed at:
10
+ * - a change of quote depth
11
+ * - a blank line, which separates paragraphs
12
+ * - a reply attribution line, which becomes its own block
13
+ * - a forward marker, which becomes its own block
14
+ * - a signature delimiter, which becomes its own block
15
+ * - a rule separator
16
+ * - the start of an embedded header block
17
+ */
18
+ import { type CanonicalText } from '../canonical/text';
19
+ import { type Block } from './types';
20
+ /**
21
+ * Segment a plain text part into blocks.
22
+ *
23
+ * @param raw decoded text of the part
24
+ * @param mimePart part id for traceability
25
+ */
26
+ export declare function segmentTextBlocks(raw: string, mimePart: string): {
27
+ canonical: CanonicalText;
28
+ blocks: Block[];
29
+ };
30
+ //# sourceMappingURL=text-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-blocks.d.ts","sourceRoot":"","sources":["../../src/segment/text-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAoB,KAAK,aAAa,EAAiB,MAAM,mBAAmB,CAAC;AAMxF,OAAO,EAAE,KAAK,KAAK,EAAiC,MAAM,SAAS,CAAC;AAkDpE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,KAAK,EAAE,CAAA;CAAE,CAiJ9G"}