spamscanner 7.0.13 → 7.0.15

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/dist/esm/arf.js CHANGED
@@ -1,13 +1,1149 @@
1
1
  // src/arf.js
2
- import { Buffer as Buffer2 } from "node:buffer";
2
+ import { Buffer as Buffer3 } from "node:buffer";
3
3
  import { randomBytes } from "node:crypto";
4
4
  import { isIP } from "node:net";
5
5
 
6
6
  // src/parse.js
7
- import { Buffer } from "node:buffer";
7
+ import { Buffer as Buffer2 } from "node:buffer";
8
8
  import { createHash } from "node:crypto";
9
9
  import { Readable } from "node:stream";
10
10
  import { MailParser, simpleParser } from "mailparser";
11
+
12
+ // src/attachments.js
13
+ import { Buffer } from "node:buffer";
14
+
15
+ // src/linear.js
16
+ import { createRequire } from "node:module";
17
+ function loadRe2(load = createRequire(import.meta.url)) {
18
+ try {
19
+ return load("re2");
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ var RE2 = loadRe2();
25
+ var BOUNDED = /^{([01]),\d{2,}}/;
26
+ var WHITESPACE = String.raw`\t\n\x0B\f\r \x{A0}\x{1680}\x{2000}-\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}\x{FEFF}`;
27
+ function re2Source(source) {
28
+ let out = "";
29
+ let inClass = false;
30
+ let unicodeClass = false;
31
+ let afterClass = false;
32
+ for (let i = 0; i < source.length; i++) {
33
+ const char = source[i];
34
+ const repeats = afterClass;
35
+ afterClass = false;
36
+ if (char === "{" && !inClass && repeats && unicodeClass) {
37
+ const bound = BOUNDED.exec(source.slice(i, i + 16));
38
+ if (bound) {
39
+ out += bound[1] === "0" ? "*" : "+";
40
+ i += bound[0].length - 1;
41
+ continue;
42
+ }
43
+ }
44
+ if (char === "\\") {
45
+ const next = source[++i] ?? "";
46
+ if (inClass && (next === "p" || next === "P")) {
47
+ unicodeClass = true;
48
+ }
49
+ if (next === "s") {
50
+ out += inClass ? WHITESPACE : `[${WHITESPACE}]`;
51
+ } else if (next === "S") {
52
+ if (inClass) {
53
+ throw new TypeError(String.raw`\S inside a character class has no RE2 equivalent here`);
54
+ }
55
+ out += `[^${WHITESPACE}]`;
56
+ } else {
57
+ out += `\\${next}`;
58
+ }
59
+ continue;
60
+ }
61
+ if (char === "[" && !inClass) {
62
+ inClass = true;
63
+ unicodeClass = false;
64
+ } else if (char === "]" && inClass) {
65
+ inClass = false;
66
+ afterClass = true;
67
+ }
68
+ out += char;
69
+ }
70
+ return out;
71
+ }
72
+ function linear(source, flags = "", Engine = RE2) {
73
+ return Engine ? new Engine(re2Source(source), flags) : new RegExp(source, flags);
74
+ }
75
+ function trimEndOf(value, characters) {
76
+ let end = value.length;
77
+ while (end > 0 && characters.includes(value[end - 1])) {
78
+ end--;
79
+ }
80
+ return value.slice(0, end);
81
+ }
82
+ function caseless(word) {
83
+ return [...word].map((letter) => `[${letter}${letter.toUpperCase()}]`).join("");
84
+ }
85
+ var OPENER = linear(String.raw`<(${caseless("script")}|${caseless("style")})\b`, "g");
86
+ var CLOSERS = {
87
+ script: linear(String.raw`<\/${caseless("script")}\s*>`, "g"),
88
+ style: linear(String.raw`<\/${caseless("style")}\s*>`, "g")
89
+ };
90
+
91
+ // src/tokenizer.js
92
+ import { parse as parseDomain2 } from "tldts";
93
+
94
+ // src/homograph.js
95
+ import { domainToUnicode } from "node:url";
96
+ import { parse as parseDomain } from "tldts";
97
+
98
+ // src/language.js
99
+ import { franc } from "franc";
100
+ var SCRIPTS = [
101
+ ["Latin", new RegExp("\\p{Script=Latin}", "u")],
102
+ ["Cyrillic", new RegExp("\\p{Script=Cyrillic}", "u")],
103
+ ["Greek", new RegExp("\\p{Script=Greek}", "u")],
104
+ ["Han", new RegExp("\\p{Script=Han}", "u")],
105
+ ["Hiragana", new RegExp("\\p{Script=Hiragana}", "u")],
106
+ ["Katakana", new RegExp("\\p{Script=Katakana}", "u")],
107
+ ["Hangul", new RegExp("\\p{Script=Hangul}", "u")],
108
+ ["Arabic", new RegExp("\\p{Script=Arabic}", "u")],
109
+ ["Hebrew", new RegExp("\\p{Script=Hebrew}", "u")],
110
+ ["Thai", new RegExp("\\p{Script=Thai}", "u")],
111
+ ["Devanagari", new RegExp("\\p{Script=Devanagari}", "u")],
112
+ ["Bengali", new RegExp("\\p{Script=Bengali}", "u")],
113
+ ["Tamil", new RegExp("\\p{Script=Tamil}", "u")],
114
+ ["Telugu", new RegExp("\\p{Script=Telugu}", "u")],
115
+ ["Gujarati", new RegExp("\\p{Script=Gujarati}", "u")],
116
+ ["Gurmukhi", new RegExp("\\p{Script=Gurmukhi}", "u")],
117
+ ["Kannada", new RegExp("\\p{Script=Kannada}", "u")],
118
+ ["Malayalam", new RegExp("\\p{Script=Malayalam}", "u")],
119
+ ["Armenian", new RegExp("\\p{Script=Armenian}", "u")],
120
+ ["Georgian", new RegExp("\\p{Script=Georgian}", "u")],
121
+ ["Ethiopic", new RegExp("\\p{Script=Ethiopic}", "u")],
122
+ ["Khmer", new RegExp("\\p{Script=Khmer}", "u")],
123
+ ["Lao", new RegExp("\\p{Script=Lao}", "u")],
124
+ ["Myanmar", new RegExp("\\p{Script=Myanmar}", "u")],
125
+ ["Sinhala", new RegExp("\\p{Script=Sinhala}", "u")]
126
+ ];
127
+ var LETTER = new RegExp("\\p{L}", "u");
128
+ function scriptOf(char) {
129
+ const entry = SCRIPTS.find(([, pattern]) => pattern.test(char));
130
+ return entry ? entry[0] : "Other";
131
+ }
132
+
133
+ // src/homograph.js
134
+ var INTERNATIONAL_BRANDS = [
135
+ "alipay",
136
+ "auspost",
137
+ "bancolombia",
138
+ "bnpparibas",
139
+ "bradesco",
140
+ "caixabank",
141
+ "canadapost",
142
+ "commerzbank",
143
+ "coupang",
144
+ "creditagricole",
145
+ "deutschebank",
146
+ "flipkart",
147
+ "gosuslugi",
148
+ "japanpost",
149
+ "kakaobank",
150
+ "klarna",
151
+ "kucoin",
152
+ "lazada",
153
+ "mercadolibre",
154
+ "mercadolivre",
155
+ "mercadopago",
156
+ "mercari",
157
+ "natwest",
158
+ "nubank",
159
+ "phonepe",
160
+ "postbank",
161
+ "rakuten",
162
+ "sberbank",
163
+ "swisscom",
164
+ "trustwallet",
165
+ "unicredit",
166
+ "vodafone",
167
+ "wechat",
168
+ "yandex"
169
+ ];
170
+ var BRANDS = [
171
+ "adobe",
172
+ "airbnb",
173
+ "alibaba",
174
+ "aliexpress",
175
+ "amazon",
176
+ "americanexpress",
177
+ "amex",
178
+ "apple",
179
+ "appleid",
180
+ "att",
181
+ "binance",
182
+ "bankofamerica",
183
+ "barclays",
184
+ "bestbuy",
185
+ "blockchain",
186
+ "booking",
187
+ "bybit",
188
+ "cashapp",
189
+ "chase",
190
+ "citibank",
191
+ "cloudflare",
192
+ "coinbase",
193
+ "comcast",
194
+ "costco",
195
+ "dhl",
196
+ "discord",
197
+ "docusign",
198
+ "dropbox",
199
+ "ebay",
200
+ "facebook",
201
+ "fedex",
202
+ "forwardemail",
203
+ "github",
204
+ "gitlab",
205
+ "gmail",
206
+ "godaddy",
207
+ "google",
208
+ "hmrc",
209
+ "hotmail",
210
+ "hsbc",
211
+ "icloud",
212
+ "instagram",
213
+ "intuit",
214
+ "irs",
215
+ "kraken",
216
+ "ledger",
217
+ "linkedin",
218
+ "mastercard",
219
+ "mcafee",
220
+ "metamask",
221
+ "microsoft",
222
+ "microsoftonline",
223
+ "namecheap",
224
+ "netflix",
225
+ "norton",
226
+ "office",
227
+ "office365",
228
+ "okta",
229
+ "onedrive",
230
+ "outlook",
231
+ "paypal",
232
+ "proton",
233
+ "protonmail",
234
+ "quickbooks",
235
+ "revolut",
236
+ "roblox",
237
+ "royalmail",
238
+ "salesforce",
239
+ "samsung",
240
+ "santander",
241
+ "sharepoint",
242
+ "shopify",
243
+ "skype",
244
+ "slack",
245
+ "sparkasse",
246
+ "spotify",
247
+ "steam",
248
+ "steampowered",
249
+ "stripe",
250
+ "telegram",
251
+ "tiktok",
252
+ "tmobile",
253
+ "trezor",
254
+ "tutanota",
255
+ "twitter",
256
+ "uber",
257
+ "ups",
258
+ "usps",
259
+ "venmo",
260
+ "verizon",
261
+ "visa",
262
+ "walmart",
263
+ "wellsfargo",
264
+ "whatsapp",
265
+ "wise",
266
+ "xfinity",
267
+ "yahoo",
268
+ "zelle",
269
+ "zoom",
270
+ ...INTERNATIONAL_BRANDS
271
+ ];
272
+ var WORD_BRANDS = /* @__PURE__ */ new Set(["apple", "blockchain", "booking", "chase", "discord", "kraken", "ledger", "office", "proton", "slack", "steam", "stripe"]);
273
+ var HELP_WORDS = ["help", "helpdesk", "support"];
274
+ var COMMON_WORD_BRANDS = /* @__PURE__ */ new Map([
275
+ ["blockchain", ["wallet", "wallets", ...HELP_WORDS]],
276
+ ["booking", []],
277
+ ["kraken", ["trade", "trading", "wallet", "wallets", ...HELP_WORDS]],
278
+ ["ledger", ["live", "wallet", "wallets", ...HELP_WORDS]],
279
+ ["office", []],
280
+ ["proton", ["pay", "wallet", ...HELP_WORDS]],
281
+ ["steam", ["community", "gift", "giftcard", "gifts", "trade", "trading", "wallet", ...HELP_WORDS]],
282
+ ["stripe", ["payment", "payments", ...HELP_WORDS]]
283
+ ]);
284
+ var TYPO_WORDS = /* @__PURE__ */ new Set([...WORD_BRANDS, "adobe", "binance", "fedex", "gmail", "icloud", "norton", "samsung", "tiktok", "tmobile", "trezor", "twitter", "venmo", "zelle"]);
285
+ var ASCII_TRICKS = [
286
+ [/rn/g, "m"],
287
+ [/vv/g, "w"],
288
+ [/cl/g, "d"],
289
+ [/0/g, "o"],
290
+ [/1/g, "l"],
291
+ [/3/g, "e"],
292
+ [/4/g, "a"],
293
+ [/5/g, "s"],
294
+ [/7/g, "t"],
295
+ [/8/g, "b"]
296
+ ];
297
+ var LETTER_TRICKS = ASCII_TRICKS.filter(([pattern]) => pattern.source === "cl" || pattern.source === "vv");
298
+
299
+ // src/entities.js
300
+ var NAMED = [
301
+ "AElig=c6,AMP=26,Aacute=c1,Abreve=102,Acirc=c2,Acy=410,Afr=1d504,Agrave=c0,Alpha=391,Amacr=100,And=2a",
302
+ "53,Aogon=104,Aopf=1d538,ApplyFunction=2061,Aring=c5,Ascr=1d49c,Assign=2254,Atilde=c3,Auml=c4,Backsla",
303
+ "sh=2216,Barv=2ae7,Barwed=2306,Bcy=411,Because=2235,Bernoullis=212c,Beta=392,Bfr=1d505,Bopf=1d539,Bre",
304
+ "ve=2d8,Bscr=212c,Bumpeq=224e,CHcy=427,COPY=a9,Cacute=106,Cap=22d2,CapitalDifferentialD=2145,Cayleys=",
305
+ "212d,Ccaron=10c,Ccedil=c7,Ccirc=108,Cconint=2230,Cdot=10a,Cedilla=b8,CenterDot=b7,Cfr=212d,Chi=3a7,C",
306
+ "ircleDot=2299,CircleMinus=2296,CirclePlus=2295,CircleTimes=2297,ClockwiseContourIntegral=2232,CloseC",
307
+ "urlyDoubleQuote=201d,CloseCurlyQuote=2019,Colon=2237,Colone=2a74,Congruent=2261,Conint=222f,ContourI",
308
+ "ntegral=222e,Copf=2102,Coproduct=2210,CounterClockwiseContourIntegral=2233,Cross=2a2f,Cscr=1d49e,Cup",
309
+ "=22d3,CupCap=224d,DD=2145,DDotrahd=2911,DJcy=402,DScy=405,DZcy=40f,Dagger=2021,Darr=21a1,Dashv=2ae4,",
310
+ "Dcaron=10e,Dcy=414,Del=2207,Delta=394,Dfr=1d507,DiacriticalAcute=b4,DiacriticalDot=2d9,DiacriticalDo",
311
+ "ubleAcute=2dd,DiacriticalGrave=60,DiacriticalTilde=2dc,Diamond=22c4,DifferentialD=2146,Dopf=1d53b,Do",
312
+ "t=a8,DotDot=20dc,DotEqual=2250,DoubleContourIntegral=222f,DoubleDot=a8,DoubleDownArrow=21d3,DoubleLe",
313
+ "ftArrow=21d0,DoubleLeftRightArrow=21d4,DoubleLeftTee=2ae4,DoubleLongLeftArrow=27f8,DoubleLongLeftRig",
314
+ "htArrow=27fa,DoubleLongRightArrow=27f9,DoubleRightArrow=21d2,DoubleRightTee=22a8,DoubleUpArrow=21d1,",
315
+ "DoubleUpDownArrow=21d5,DoubleVerticalBar=2225,DownArrow=2193,DownArrowBar=2913,DownArrowUpArrow=21f5",
316
+ ",DownBreve=311,DownLeftRightVector=2950,DownLeftTeeVector=295e,DownLeftVector=21bd,DownLeftVectorBar",
317
+ "=2956,DownRightTeeVector=295f,DownRightVector=21c1,DownRightVectorBar=2957,DownTee=22a4,DownTeeArrow",
318
+ "=21a7,Downarrow=21d3,Dscr=1d49f,Dstrok=110,ENG=14a,ETH=d0,Eacute=c9,Ecaron=11a,Ecirc=ca,Ecy=42d,Edot",
319
+ "=116,Efr=1d508,Egrave=c8,Element=2208,Emacr=112,EmptySmallSquare=25fb,EmptyVerySmallSquare=25ab,Eogo",
320
+ "n=118,Eopf=1d53c,Epsilon=395,Equal=2a75,EqualTilde=2242,Equilibrium=21cc,Escr=2130,Esim=2a73,Eta=397",
321
+ ",Euml=cb,Exists=2203,ExponentialE=2147,Fcy=424,Ffr=1d509,FilledSmallSquare=25fc,FilledVerySmallSquar",
322
+ "e=25aa,Fopf=1d53d,ForAll=2200,Fouriertrf=2131,Fscr=2131,GJcy=403,GT=3e,Gamma=393,Gammad=3dc,Gbreve=1",
323
+ "1e,Gcedil=122,Gcirc=11c,Gcy=413,Gdot=120,Gfr=1d50a,Gg=22d9,Gopf=1d53e,GreaterEqual=2265,GreaterEqual",
324
+ "Less=22db,GreaterFullEqual=2267,GreaterGreater=2aa2,GreaterLess=2277,GreaterSlantEqual=2a7e,GreaterT",
325
+ "ilde=2273,Gscr=1d4a2,Gt=226b,HARDcy=42a,Hacek=2c7,Hat=5e,Hcirc=124,Hfr=210c,HilbertSpace=210b,Hopf=2",
326
+ "10d,HorizontalLine=2500,Hscr=210b,Hstrok=126,HumpDownHump=224e,HumpEqual=224f,IEcy=415,IJlig=132,IOc",
327
+ "y=401,Iacute=cd,Icirc=ce,Icy=418,Idot=130,Ifr=2111,Igrave=cc,Im=2111,Imacr=12a,ImaginaryI=2148,Impli",
328
+ "es=21d2,Int=222c,Integral=222b,Intersection=22c2,InvisibleComma=2063,InvisibleTimes=2062,Iogon=12e,I",
329
+ "opf=1d540,Iota=399,Iscr=2110,Itilde=128,Iukcy=406,Iuml=cf,Jcirc=134,Jcy=419,Jfr=1d50d,Jopf=1d541,Jsc",
330
+ "r=1d4a5,Jsercy=408,Jukcy=404,KHcy=425,KJcy=40c,Kappa=39a,Kcedil=136,Kcy=41a,Kfr=1d50e,Kopf=1d542,Ksc",
331
+ "r=1d4a6,LJcy=409,LT=3c,Lacute=139,Lambda=39b,Lang=27ea,Laplacetrf=2112,Larr=219e,Lcaron=13d,Lcedil=1",
332
+ "3b,Lcy=41b,LeftAngleBracket=27e8,LeftArrow=2190,LeftArrowBar=21e4,LeftArrowRightArrow=21c6,LeftCeili",
333
+ "ng=2308,LeftDoubleBracket=27e6,LeftDownTeeVector=2961,LeftDownVector=21c3,LeftDownVectorBar=2959,Lef",
334
+ "tFloor=230a,LeftRightArrow=2194,LeftRightVector=294e,LeftTee=22a3,LeftTeeArrow=21a4,LeftTeeVector=29",
335
+ "5a,LeftTriangle=22b2,LeftTriangleBar=29cf,LeftTriangleEqual=22b4,LeftUpDownVector=2951,LeftUpTeeVect",
336
+ "or=2960,LeftUpVector=21bf,LeftUpVectorBar=2958,LeftVector=21bc,LeftVectorBar=2952,Leftarrow=21d0,Lef",
337
+ "trightarrow=21d4,LessEqualGreater=22da,LessFullEqual=2266,LessGreater=2276,LessLess=2aa1,LessSlantEq",
338
+ "ual=2a7d,LessTilde=2272,Lfr=1d50f,Ll=22d8,Lleftarrow=21da,Lmidot=13f,LongLeftArrow=27f5,LongLeftRigh",
339
+ "tArrow=27f7,LongRightArrow=27f6,Longleftarrow=27f8,Longleftrightarrow=27fa,Longrightarrow=27f9,Lopf=",
340
+ "1d543,LowerLeftArrow=2199,LowerRightArrow=2198,Lscr=2112,Lsh=21b0,Lstrok=141,Lt=226a,Map=2905,Mcy=41",
341
+ "c,MediumSpace=205f,Mellintrf=2133,Mfr=1d510,MinusPlus=2213,Mopf=1d544,Mscr=2133,Mu=39c,NJcy=40a,Nacu",
342
+ "te=143,Ncaron=147,Ncedil=145,Ncy=41d,NegativeMediumSpace=200b,NegativeThickSpace=200b,NegativeThinSp",
343
+ "ace=200b,NegativeVeryThinSpace=200b,NestedGreaterGreater=226b,NestedLessLess=226a,NewLine=a,Nfr=1d51",
344
+ "1,NoBreak=2060,NonBreakingSpace=a0,Nopf=2115,Not=2aec,NotCongruent=2262,NotCupCap=226d,NotDoubleVert",
345
+ "icalBar=2226,NotElement=2209,NotEqual=2260,NotEqualTilde=2242.338,NotExists=2204,NotGreater=226f,Not",
346
+ "GreaterEqual=2271,NotGreaterFullEqual=2267.338,NotGreaterGreater=226b.338,NotGreaterLess=2279,NotGre",
347
+ "aterSlantEqual=2a7e.338,NotGreaterTilde=2275,NotHumpDownHump=224e.338,NotHumpEqual=224f.338,NotLeftT",
348
+ "riangle=22ea,NotLeftTriangleBar=29cf.338,NotLeftTriangleEqual=22ec,NotLess=226e,NotLessEqual=2270,No",
349
+ "tLessGreater=2278,NotLessLess=226a.338,NotLessSlantEqual=2a7d.338,NotLessTilde=2274,NotNestedGreater",
350
+ "Greater=2aa2.338,NotNestedLessLess=2aa1.338,NotPrecedes=2280,NotPrecedesEqual=2aaf.338,NotPrecedesSl",
351
+ "antEqual=22e0,NotReverseElement=220c,NotRightTriangle=22eb,NotRightTriangleBar=29d0.338,NotRightTria",
352
+ "ngleEqual=22ed,NotSquareSubset=228f.338,NotSquareSubsetEqual=22e2,NotSquareSuperset=2290.338,NotSqua",
353
+ "reSupersetEqual=22e3,NotSubset=2282.20d2,NotSubsetEqual=2288,NotSucceeds=2281,NotSucceedsEqual=2ab0.",
354
+ "338,NotSucceedsSlantEqual=22e1,NotSucceedsTilde=227f.338,NotSuperset=2283.20d2,NotSupersetEqual=2289",
355
+ ",NotTilde=2241,NotTildeEqual=2244,NotTildeFullEqual=2247,NotTildeTilde=2249,NotVerticalBar=2224,Nscr",
356
+ "=1d4a9,Ntilde=d1,Nu=39d,OElig=152,Oacute=d3,Ocirc=d4,Ocy=41e,Odblac=150,Ofr=1d512,Ograve=d2,Omacr=14",
357
+ "c,Omega=3a9,Omicron=39f,Oopf=1d546,OpenCurlyDoubleQuote=201c,OpenCurlyQuote=2018,Or=2a54,Oscr=1d4aa,",
358
+ "Oslash=d8,Otilde=d5,Otimes=2a37,Ouml=d6,OverBar=203e,OverBrace=23de,OverBracket=23b4,OverParenthesis",
359
+ "=23dc,PartialD=2202,Pcy=41f,Pfr=1d513,Phi=3a6,Pi=3a0,PlusMinus=b1,Poincareplane=210c,Popf=2119,Pr=2a",
360
+ "bb,Precedes=227a,PrecedesEqual=2aaf,PrecedesSlantEqual=227c,PrecedesTilde=227e,Prime=2033,Product=22",
361
+ "0f,Proportion=2237,Proportional=221d,Pscr=1d4ab,Psi=3a8,QUOT=22,Qfr=1d514,Qopf=211a,Qscr=1d4ac,RBarr",
362
+ "=2910,REG=ae,Racute=154,Rang=27eb,Rarr=21a0,Rarrtl=2916,Rcaron=158,Rcedil=156,Rcy=420,Re=211c,Revers",
363
+ "eElement=220b,ReverseEquilibrium=21cb,ReverseUpEquilibrium=296f,Rfr=211c,Rho=3a1,RightAngleBracket=2",
364
+ "7e9,RightArrow=2192,RightArrowBar=21e5,RightArrowLeftArrow=21c4,RightCeiling=2309,RightDoubleBracket",
365
+ "=27e7,RightDownTeeVector=295d,RightDownVector=21c2,RightDownVectorBar=2955,RightFloor=230b,RightTee=",
366
+ "22a2,RightTeeArrow=21a6,RightTeeVector=295b,RightTriangle=22b3,RightTriangleBar=29d0,RightTriangleEq",
367
+ "ual=22b5,RightUpDownVector=294f,RightUpTeeVector=295c,RightUpVector=21be,RightUpVectorBar=2954,Right",
368
+ "Vector=21c0,RightVectorBar=2953,Rightarrow=21d2,Ropf=211d,RoundImplies=2970,Rrightarrow=21db,Rscr=21",
369
+ "1b,Rsh=21b1,RuleDelayed=29f4,SHCHcy=429,SHcy=428,SOFTcy=42c,Sacute=15a,Sc=2abc,Scaron=160,Scedil=15e",
370
+ ",Scirc=15c,Scy=421,Sfr=1d516,ShortDownArrow=2193,ShortLeftArrow=2190,ShortRightArrow=2192,ShortUpArr",
371
+ "ow=2191,Sigma=3a3,SmallCircle=2218,Sopf=1d54a,Sqrt=221a,Square=25a1,SquareIntersection=2293,SquareSu",
372
+ "bset=228f,SquareSubsetEqual=2291,SquareSuperset=2290,SquareSupersetEqual=2292,SquareUnion=2294,Sscr=",
373
+ "1d4ae,Star=22c6,Sub=22d0,Subset=22d0,SubsetEqual=2286,Succeeds=227b,SucceedsEqual=2ab0,SucceedsSlant",
374
+ "Equal=227d,SucceedsTilde=227f,SuchThat=220b,Sum=2211,Sup=22d1,Superset=2283,SupersetEqual=2287,Supse",
375
+ "t=22d1,THORN=de,TRADE=2122,TSHcy=40b,TScy=426,Tab=9,Tau=3a4,Tcaron=164,Tcedil=162,Tcy=422,Tfr=1d517,",
376
+ "Therefore=2234,Theta=398,ThickSpace=205f.200a,ThinSpace=2009,Tilde=223c,TildeEqual=2243,TildeFullEqu",
377
+ "al=2245,TildeTilde=2248,Topf=1d54b,TripleDot=20db,Tscr=1d4af,Tstrok=166,Uacute=da,Uarr=219f,Uarrocir",
378
+ "=2949,Ubrcy=40e,Ubreve=16c,Ucirc=db,Ucy=423,Udblac=170,Ufr=1d518,Ugrave=d9,Umacr=16a,UnderBar=5f,Und",
379
+ "erBrace=23df,UnderBracket=23b5,UnderParenthesis=23dd,Union=22c3,UnionPlus=228e,Uogon=172,Uopf=1d54c,",
380
+ "UpArrow=2191,UpArrowBar=2912,UpArrowDownArrow=21c5,UpDownArrow=2195,UpEquilibrium=296e,UpTee=22a5,Up",
381
+ "TeeArrow=21a5,Uparrow=21d1,Updownarrow=21d5,UpperLeftArrow=2196,UpperRightArrow=2197,Upsi=3d2,Upsilo",
382
+ "n=3a5,Uring=16e,Uscr=1d4b0,Utilde=168,Uuml=dc,VDash=22ab,Vbar=2aeb,Vcy=412,Vdash=22a9,Vdashl=2ae6,Ve",
383
+ "e=22c1,Verbar=2016,Vert=2016,VerticalBar=2223,VerticalLine=7c,VerticalSeparator=2758,VerticalTilde=2",
384
+ "240,VeryThinSpace=200a,Vfr=1d519,Vopf=1d54d,Vscr=1d4b1,Vvdash=22aa,Wcirc=174,Wedge=22c0,Wfr=1d51a,Wo",
385
+ "pf=1d54e,Wscr=1d4b2,Xfr=1d51b,Xi=39e,Xopf=1d54f,Xscr=1d4b3,YAcy=42f,YIcy=407,YUcy=42e,Yacute=dd,Ycir",
386
+ "c=176,Ycy=42b,Yfr=1d51c,Yopf=1d550,Yscr=1d4b4,Yuml=178,ZHcy=416,Zacute=179,Zcaron=17d,Zcy=417,Zdot=1",
387
+ "7b,ZeroWidthSpace=200b,Zeta=396,Zfr=2128,Zopf=2124,Zscr=1d4b5,aacute=e1,abreve=103,ac=223e,acE=223e.",
388
+ "333,acd=223f,acirc=e2,acute=b4,acy=430,aelig=e6,af=2061,afr=1d51e,agrave=e0,alefsym=2135,aleph=2135,",
389
+ "alpha=3b1,amacr=101,amalg=2a3f,amp=26,and=2227,andand=2a55,andd=2a5c,andslope=2a58,andv=2a5a,ang=222",
390
+ "0,ange=29a4,angle=2220,angmsd=2221,angmsdaa=29a8,angmsdab=29a9,angmsdac=29aa,angmsdad=29ab,angmsdae=",
391
+ "29ac,angmsdaf=29ad,angmsdag=29ae,angmsdah=29af,angrt=221f,angrtvb=22be,angrtvbd=299d,angsph=2222,ang",
392
+ "st=c5,angzarr=237c,aogon=105,aopf=1d552,ap=2248,apE=2a70,apacir=2a6f,ape=224a,apid=224b,apos=27,appr",
393
+ "ox=2248,approxeq=224a,aring=e5,ascr=1d4b6,ast=2a,asymp=2248,asympeq=224d,atilde=e3,auml=e4,awconint=",
394
+ "2233,awint=2a11,bNot=2aed,backcong=224c,backepsilon=3f6,backprime=2035,backsim=223d,backsimeq=22cd,b",
395
+ "arvee=22bd,barwed=2305,barwedge=2305,bbrk=23b5,bbrktbrk=23b6,bcong=224c,bcy=431,bdquo=201e,becaus=22",
396
+ "35,because=2235,bemptyv=29b0,bepsi=3f6,bernou=212c,beta=3b2,beth=2136,between=226c,bfr=1d51f,bigcap=",
397
+ "22c2,bigcirc=25ef,bigcup=22c3,bigodot=2a00,bigoplus=2a01,bigotimes=2a02,bigsqcup=2a06,bigstar=2605,b",
398
+ "igtriangledown=25bd,bigtriangleup=25b3,biguplus=2a04,bigvee=22c1,bigwedge=22c0,bkarow=290d,blackloze",
399
+ "nge=29eb,blacksquare=25aa,blacktriangle=25b4,blacktriangledown=25be,blacktriangleleft=25c2,blacktria",
400
+ "ngleright=25b8,blank=2423,blk12=2592,blk14=2591,blk34=2593,block=2588,bne=3d.20e5,bnequiv=2261.20e5,",
401
+ "bnot=2310,bopf=1d553,bot=22a5,bottom=22a5,bowtie=22c8,boxDL=2557,boxDR=2554,boxDl=2556,boxDr=2553,bo",
402
+ "xH=2550,boxHD=2566,boxHU=2569,boxHd=2564,boxHu=2567,boxUL=255d,boxUR=255a,boxUl=255c,boxUr=2559,boxV",
403
+ "=2551,boxVH=256c,boxVL=2563,boxVR=2560,boxVh=256b,boxVl=2562,boxVr=255f,boxbox=29c9,boxdL=2555,boxdR",
404
+ "=2552,boxdl=2510,boxdr=250c,boxh=2500,boxhD=2565,boxhU=2568,boxhd=252c,boxhu=2534,boxminus=229f,boxp",
405
+ "lus=229e,boxtimes=22a0,boxuL=255b,boxuR=2558,boxul=2518,boxur=2514,boxv=2502,boxvH=256a,boxvL=2561,b",
406
+ "oxvR=255e,boxvh=253c,boxvl=2524,boxvr=251c,bprime=2035,breve=2d8,brvbar=a6,bscr=1d4b7,bsemi=204f,bsi",
407
+ "m=223d,bsime=22cd,bsol=5c,bsolb=29c5,bsolhsub=27c8,bull=2022,bullet=2022,bump=224e,bumpE=2aae,bumpe=",
408
+ "224f,bumpeq=224f,cacute=107,cap=2229,capand=2a44,capbrcup=2a49,capcap=2a4b,capcup=2a47,capdot=2a40,c",
409
+ "aps=2229.fe00,caret=2041,caron=2c7,ccaps=2a4d,ccaron=10d,ccedil=e7,ccirc=109,ccups=2a4c,ccupssm=2a50",
410
+ ",cdot=10b,cedil=b8,cemptyv=29b2,cent=a2,centerdot=b7,cfr=1d520,chcy=447,check=2713,checkmark=2713,ch",
411
+ "i=3c7,cir=25cb,cirE=29c3,circ=2c6,circeq=2257,circlearrowleft=21ba,circlearrowright=21bb,circledR=ae",
412
+ ",circledS=24c8,circledast=229b,circledcirc=229a,circleddash=229d,cire=2257,cirfnint=2a10,cirmid=2aef",
413
+ ",cirscir=29c2,clubs=2663,clubsuit=2663,colon=3a,colone=2254,coloneq=2254,comma=2c,commat=40,comp=220",
414
+ "1,compfn=2218,complement=2201,complexes=2102,cong=2245,congdot=2a6d,conint=222e,copf=1d554,coprod=22",
415
+ "10,copy=a9,copysr=2117,crarr=21b5,cross=2717,cscr=1d4b8,csub=2acf,csube=2ad1,csup=2ad0,csupe=2ad2,ct",
416
+ "dot=22ef,cudarrl=2938,cudarrr=2935,cuepr=22de,cuesc=22df,cularr=21b6,cularrp=293d,cup=222a,cupbrcap=",
417
+ "2a48,cupcap=2a46,cupcup=2a4a,cupdot=228d,cupor=2a45,cups=222a.fe00,curarr=21b7,curarrm=293c,curlyeqp",
418
+ "rec=22de,curlyeqsucc=22df,curlyvee=22ce,curlywedge=22cf,curren=a4,curvearrowleft=21b6,curvearrowrigh",
419
+ "t=21b7,cuvee=22ce,cuwed=22cf,cwconint=2232,cwint=2231,cylcty=232d,dArr=21d3,dHar=2965,dagger=2020,da",
420
+ "leth=2138,darr=2193,dash=2010,dashv=22a3,dbkarow=290f,dblac=2dd,dcaron=10f,dcy=434,dd=2146,ddagger=2",
421
+ "021,ddarr=21ca,ddotseq=2a77,deg=b0,delta=3b4,demptyv=29b1,dfisht=297f,dfr=1d521,dharl=21c3,dharr=21c",
422
+ "2,diam=22c4,diamond=22c4,diamondsuit=2666,diams=2666,die=a8,digamma=3dd,disin=22f2,div=f7,divide=f7,",
423
+ "divideontimes=22c7,divonx=22c7,djcy=452,dlcorn=231e,dlcrop=230d,dollar=24,dopf=1d555,dot=2d9,doteq=2",
424
+ "250,doteqdot=2251,dotminus=2238,dotplus=2214,dotsquare=22a1,doublebarwedge=2306,downarrow=2193,downd",
425
+ "ownarrows=21ca,downharpoonleft=21c3,downharpoonright=21c2,drbkarow=2910,drcorn=231f,drcrop=230c,dscr",
426
+ "=1d4b9,dscy=455,dsol=29f6,dstrok=111,dtdot=22f1,dtri=25bf,dtrif=25be,duarr=21f5,duhar=296f,dwangle=2",
427
+ "9a6,dzcy=45f,dzigrarr=27ff,eDDot=2a77,eDot=2251,eacute=e9,easter=2a6e,ecaron=11b,ecir=2256,ecirc=ea,",
428
+ "ecolon=2255,ecy=44d,edot=117,ee=2147,efDot=2252,efr=1d522,eg=2a9a,egrave=e8,egs=2a96,egsdot=2a98,el=",
429
+ "2a99,elinters=23e7,ell=2113,els=2a95,elsdot=2a97,emacr=113,empty=2205,emptyset=2205,emptyv=2205,emsp",
430
+ "=2003,emsp13=2004,emsp14=2005,eng=14b,ensp=2002,eogon=119,eopf=1d556,epar=22d5,eparsl=29e3,eplus=2a7",
431
+ "1,epsi=3b5,epsilon=3b5,epsiv=3f5,eqcirc=2256,eqcolon=2255,eqsim=2242,eqslantgtr=2a96,eqslantless=2a9",
432
+ "5,equals=3d,equest=225f,equiv=2261,equivDD=2a78,eqvparsl=29e5,erDot=2253,erarr=2971,escr=212f,esdot=",
433
+ "2250,esim=2242,eta=3b7,eth=f0,euml=eb,euro=20ac,excl=21,exist=2203,expectation=2130,exponentiale=214",
434
+ "7,fallingdotseq=2252,fcy=444,female=2640,ffilig=fb03,fflig=fb00,ffllig=fb04,ffr=1d523,filig=fb01,fjl",
435
+ "ig=66.6a,flat=266d,fllig=fb02,fltns=25b1,fnof=192,fopf=1d557,forall=2200,fork=22d4,forkv=2ad9,fparti",
436
+ "nt=2a0d,frac12=bd,frac13=2153,frac14=bc,frac15=2155,frac16=2159,frac18=215b,frac23=2154,frac25=2156,",
437
+ "frac34=be,frac35=2157,frac38=215c,frac45=2158,frac56=215a,frac58=215d,frac78=215e,frasl=2044,frown=2",
438
+ "322,fscr=1d4bb,gE=2267,gEl=2a8c,gacute=1f5,gamma=3b3,gammad=3dd,gap=2a86,gbreve=11f,gcirc=11d,gcy=43",
439
+ "3,gdot=121,ge=2265,gel=22db,geq=2265,geqq=2267,geqslant=2a7e,ges=2a7e,gescc=2aa9,gesdot=2a80,gesdoto",
440
+ "=2a82,gesdotol=2a84,gesl=22db.fe00,gesles=2a94,gfr=1d524,gg=226b,ggg=22d9,gimel=2137,gjcy=453,gl=227",
441
+ "7,glE=2a92,gla=2aa5,glj=2aa4,gnE=2269,gnap=2a8a,gnapprox=2a8a,gne=2a88,gneq=2a88,gneqq=2269,gnsim=22",
442
+ "e7,gopf=1d558,grave=60,gscr=210a,gsim=2273,gsime=2a8e,gsiml=2a90,gt=3e,gtcc=2aa7,gtcir=2a7a,gtdot=22",
443
+ "d7,gtlPar=2995,gtquest=2a7c,gtrapprox=2a86,gtrarr=2978,gtrdot=22d7,gtreqless=22db,gtreqqless=2a8c,gt",
444
+ "rless=2277,gtrsim=2273,gvertneqq=2269.fe00,gvnE=2269.fe00,hArr=21d4,hairsp=200a,half=bd,hamilt=210b,",
445
+ "hardcy=44a,harr=2194,harrcir=2948,harrw=21ad,hbar=210f,hcirc=125,hearts=2665,heartsuit=2665,hellip=2",
446
+ "026,hercon=22b9,hfr=1d525,hksearow=2925,hkswarow=2926,hoarr=21ff,homtht=223b,hookleftarrow=21a9,hook",
447
+ "rightarrow=21aa,hopf=1d559,horbar=2015,hscr=1d4bd,hslash=210f,hstrok=127,hybull=2043,hyphen=2010,iac",
448
+ "ute=ed,ic=2063,icirc=ee,icy=438,iecy=435,iexcl=a1,iff=21d4,ifr=1d526,igrave=ec,ii=2148,iiiint=2a0c,i",
449
+ "iint=222d,iinfin=29dc,iiota=2129,ijlig=133,imacr=12b,image=2111,imagline=2110,imagpart=2111,imath=13",
450
+ "1,imof=22b7,imped=1b5,in=2208,incare=2105,infin=221e,infintie=29dd,inodot=131,int=222b,intcal=22ba,i",
451
+ "ntegers=2124,intercal=22ba,intlarhk=2a17,intprod=2a3c,iocy=451,iogon=12f,iopf=1d55a,iota=3b9,iprod=2",
452
+ "a3c,iquest=bf,iscr=1d4be,isin=2208,isinE=22f9,isindot=22f5,isins=22f4,isinsv=22f3,isinv=2208,it=2062",
453
+ ",itilde=129,iukcy=456,iuml=ef,jcirc=135,jcy=439,jfr=1d527,jmath=237,jopf=1d55b,jscr=1d4bf,jsercy=458",
454
+ ",jukcy=454,kappa=3ba,kappav=3f0,kcedil=137,kcy=43a,kfr=1d528,kgreen=138,khcy=445,kjcy=45c,kopf=1d55c",
455
+ ",kscr=1d4c0,lAarr=21da,lArr=21d0,lAtail=291b,lBarr=290e,lE=2266,lEg=2a8b,lHar=2962,lacute=13a,laempt",
456
+ "yv=29b4,lagran=2112,lambda=3bb,lang=27e8,langd=2991,langle=27e8,lap=2a85,laquo=ab,larr=2190,larrb=21",
457
+ "e4,larrbfs=291f,larrfs=291d,larrhk=21a9,larrlp=21ab,larrpl=2939,larrsim=2973,larrtl=21a2,lat=2aab,la",
458
+ "tail=2919,late=2aad,lates=2aad.fe00,lbarr=290c,lbbrk=2772,lbrace=7b,lbrack=5b,lbrke=298b,lbrksld=298",
459
+ "f,lbrkslu=298d,lcaron=13e,lcedil=13c,lceil=2308,lcub=7b,lcy=43b,ldca=2936,ldquo=201c,ldquor=201e,ldr",
460
+ "dhar=2967,ldrushar=294b,ldsh=21b2,le=2264,leftarrow=2190,leftarrowtail=21a2,leftharpoondown=21bd,lef",
461
+ "tharpoonup=21bc,leftleftarrows=21c7,leftrightarrow=2194,leftrightarrows=21c6,leftrightharpoons=21cb,",
462
+ "leftrightsquigarrow=21ad,leftthreetimes=22cb,leg=22da,leq=2264,leqq=2266,leqslant=2a7d,les=2a7d,lesc",
463
+ "c=2aa8,lesdot=2a7f,lesdoto=2a81,lesdotor=2a83,lesg=22da.fe00,lesges=2a93,lessapprox=2a85,lessdot=22d",
464
+ "6,lesseqgtr=22da,lesseqqgtr=2a8b,lessgtr=2276,lesssim=2272,lfisht=297c,lfloor=230a,lfr=1d529,lg=2276",
465
+ ",lgE=2a91,lhard=21bd,lharu=21bc,lharul=296a,lhblk=2584,ljcy=459,ll=226a,llarr=21c7,llcorner=231e,llh",
466
+ "ard=296b,lltri=25fa,lmidot=140,lmoust=23b0,lmoustache=23b0,lnE=2268,lnap=2a89,lnapprox=2a89,lne=2a87",
467
+ ",lneq=2a87,lneqq=2268,lnsim=22e6,loang=27ec,loarr=21fd,lobrk=27e6,longleftarrow=27f5,longleftrightar",
468
+ "row=27f7,longmapsto=27fc,longrightarrow=27f6,looparrowleft=21ab,looparrowright=21ac,lopar=2985,lopf=",
469
+ "1d55d,loplus=2a2d,lotimes=2a34,lowast=2217,lowbar=5f,loz=25ca,lozenge=25ca,lozf=29eb,lpar=28,lparlt=",
470
+ "2993,lrarr=21c6,lrcorner=231f,lrhar=21cb,lrhard=296d,lrm=200e,lrtri=22bf,lsaquo=2039,lscr=1d4c1,lsh=",
471
+ "21b0,lsim=2272,lsime=2a8d,lsimg=2a8f,lsqb=5b,lsquo=2018,lsquor=201a,lstrok=142,lt=3c,ltcc=2aa6,ltcir",
472
+ "=2a79,ltdot=22d6,lthree=22cb,ltimes=22c9,ltlarr=2976,ltquest=2a7b,ltrPar=2996,ltri=25c3,ltrie=22b4,l",
473
+ "trif=25c2,lurdshar=294a,luruhar=2966,lvertneqq=2268.fe00,lvnE=2268.fe00,mDDot=223a,macr=af,male=2642",
474
+ ",malt=2720,maltese=2720,map=21a6,mapsto=21a6,mapstodown=21a7,mapstoleft=21a4,mapstoup=21a5,marker=25",
475
+ "ae,mcomma=2a29,mcy=43c,mdash=2014,measuredangle=2221,mfr=1d52a,mho=2127,micro=b5,mid=2223,midast=2a,",
476
+ "midcir=2af0,middot=b7,minus=2212,minusb=229f,minusd=2238,minusdu=2a2a,mlcp=2adb,mldr=2026,mnplus=221",
477
+ "3,models=22a7,mopf=1d55e,mp=2213,mscr=1d4c2,mstpos=223e,mu=3bc,multimap=22b8,mumap=22b8,nGg=22d9.338",
478
+ ",nGt=226b.20d2,nGtv=226b.338,nLeftarrow=21cd,nLeftrightarrow=21ce,nLl=22d8.338,nLt=226a.20d2,nLtv=22",
479
+ "6a.338,nRightarrow=21cf,nVDash=22af,nVdash=22ae,nabla=2207,nacute=144,nang=2220.20d2,nap=2249,napE=2",
480
+ "a70.338,napid=224b.338,napos=149,napprox=2249,natur=266e,natural=266e,naturals=2115,nbsp=a0,nbump=22",
481
+ "4e.338,nbumpe=224f.338,ncap=2a43,ncaron=148,ncedil=146,ncong=2247,ncongdot=2a6d.338,ncup=2a42,ncy=43",
482
+ "d,ndash=2013,ne=2260,neArr=21d7,nearhk=2924,nearr=2197,nearrow=2197,nedot=2250.338,nequiv=2262,nesea",
483
+ "r=2928,nesim=2242.338,nexist=2204,nexists=2204,nfr=1d52b,ngE=2267.338,nge=2271,ngeq=2271,ngeqq=2267.",
484
+ "338,ngeqslant=2a7e.338,nges=2a7e.338,ngsim=2275,ngt=226f,ngtr=226f,nhArr=21ce,nharr=21ae,nhpar=2af2,",
485
+ "ni=220b,nis=22fc,nisd=22fa,niv=220b,njcy=45a,nlArr=21cd,nlE=2266.338,nlarr=219a,nldr=2025,nle=2270,n",
486
+ "leftarrow=219a,nleftrightarrow=21ae,nleq=2270,nleqq=2266.338,nleqslant=2a7d.338,nles=2a7d.338,nless=",
487
+ "226e,nlsim=2274,nlt=226e,nltri=22ea,nltrie=22ec,nmid=2224,nopf=1d55f,not=ac,notin=2209,notinE=22f9.3",
488
+ "38,notindot=22f5.338,notinva=2209,notinvb=22f7,notinvc=22f6,notni=220c,notniva=220c,notnivb=22fe,not",
489
+ "nivc=22fd,npar=2226,nparallel=2226,nparsl=2afd.20e5,npart=2202.338,npolint=2a14,npr=2280,nprcue=22e0",
490
+ ",npre=2aaf.338,nprec=2280,npreceq=2aaf.338,nrArr=21cf,nrarr=219b,nrarrc=2933.338,nrarrw=219d.338,nri",
491
+ "ghtarrow=219b,nrtri=22eb,nrtrie=22ed,nsc=2281,nsccue=22e1,nsce=2ab0.338,nscr=1d4c3,nshortmid=2224,ns",
492
+ "hortparallel=2226,nsim=2241,nsime=2244,nsimeq=2244,nsmid=2224,nspar=2226,nsqsube=22e2,nsqsupe=22e3,n",
493
+ "sub=2284,nsubE=2ac5.338,nsube=2288,nsubset=2282.20d2,nsubseteq=2288,nsubseteqq=2ac5.338,nsucc=2281,n",
494
+ "succeq=2ab0.338,nsup=2285,nsupE=2ac6.338,nsupe=2289,nsupset=2283.20d2,nsupseteq=2289,nsupseteqq=2ac6",
495
+ ".338,ntgl=2279,ntilde=f1,ntlg=2278,ntriangleleft=22ea,ntrianglelefteq=22ec,ntriangleright=22eb,ntria",
496
+ "nglerighteq=22ed,nu=3bd,num=23,numero=2116,numsp=2007,nvDash=22ad,nvHarr=2904,nvap=224d.20d2,nvdash=",
497
+ "22ac,nvge=2265.20d2,nvgt=3e.20d2,nvinfin=29de,nvlArr=2902,nvle=2264.20d2,nvlt=3c.20d2,nvltrie=22b4.2",
498
+ "0d2,nvrArr=2903,nvrtrie=22b5.20d2,nvsim=223c.20d2,nwArr=21d6,nwarhk=2923,nwarr=2196,nwarrow=2196,nwn",
499
+ "ear=2927,oS=24c8,oacute=f3,oast=229b,ocir=229a,ocirc=f4,ocy=43e,odash=229d,odblac=151,odiv=2a38,odot",
500
+ "=2299,odsold=29bc,oelig=153,ofcir=29bf,ofr=1d52c,ogon=2db,ograve=f2,ogt=29c1,ohbar=29b5,ohm=3a9,oint",
501
+ "=222e,olarr=21ba,olcir=29be,olcross=29bb,oline=203e,olt=29c0,omacr=14d,omega=3c9,omicron=3bf,omid=29",
502
+ "b6,ominus=2296,oopf=1d560,opar=29b7,operp=29b9,oplus=2295,or=2228,orarr=21bb,ord=2a5d,order=2134,ord",
503
+ "erof=2134,ordf=aa,ordm=ba,origof=22b6,oror=2a56,orslope=2a57,orv=2a5b,oscr=2134,oslash=f8,osol=2298,",
504
+ "otilde=f5,otimes=2297,otimesas=2a36,ouml=f6,ovbar=233d,par=2225,para=b6,parallel=2225,parsim=2af3,pa",
505
+ "rsl=2afd,part=2202,pcy=43f,percnt=25,period=2e,permil=2030,perp=22a5,pertenk=2031,pfr=1d52d,phi=3c6,",
506
+ "phiv=3d5,phmmat=2133,phone=260e,pi=3c0,pitchfork=22d4,piv=3d6,planck=210f,planckh=210e,plankv=210f,p",
507
+ "lus=2b,plusacir=2a23,plusb=229e,pluscir=2a22,plusdo=2214,plusdu=2a25,pluse=2a72,plusmn=b1,plussim=2a",
508
+ "26,plustwo=2a27,pm=b1,pointint=2a15,popf=1d561,pound=a3,pr=227a,prE=2ab3,prap=2ab7,prcue=227c,pre=2a",
509
+ "af,prec=227a,precapprox=2ab7,preccurlyeq=227c,preceq=2aaf,precnapprox=2ab9,precneqq=2ab5,precnsim=22",
510
+ "e8,precsim=227e,prime=2032,primes=2119,prnE=2ab5,prnap=2ab9,prnsim=22e8,prod=220f,profalar=232e,prof",
511
+ "line=2312,profsurf=2313,prop=221d,propto=221d,prsim=227e,prurel=22b0,pscr=1d4c5,psi=3c8,puncsp=2008,",
512
+ "qfr=1d52e,qint=2a0c,qopf=1d562,qprime=2057,qscr=1d4c6,quaternions=210d,quatint=2a16,quest=3f,questeq",
513
+ "=225f,quot=22,rAarr=21db,rArr=21d2,rAtail=291c,rBarr=290f,rHar=2964,race=223d.331,racute=155,radic=2",
514
+ "21a,raemptyv=29b3,rang=27e9,rangd=2992,range=29a5,rangle=27e9,raquo=bb,rarr=2192,rarrap=2975,rarrb=2",
515
+ "1e5,rarrbfs=2920,rarrc=2933,rarrfs=291e,rarrhk=21aa,rarrlp=21ac,rarrpl=2945,rarrsim=2974,rarrtl=21a3",
516
+ ",rarrw=219d,ratail=291a,ratio=2236,rationals=211a,rbarr=290d,rbbrk=2773,rbrace=7d,rbrack=5d,rbrke=29",
517
+ "8c,rbrksld=298e,rbrkslu=2990,rcaron=159,rcedil=157,rceil=2309,rcub=7d,rcy=440,rdca=2937,rdldhar=2969",
518
+ ",rdquo=201d,rdquor=201d,rdsh=21b3,real=211c,realine=211b,realpart=211c,reals=211d,rect=25ad,reg=ae,r",
519
+ "fisht=297d,rfloor=230b,rfr=1d52f,rhard=21c1,rharu=21c0,rharul=296c,rho=3c1,rhov=3f1,rightarrow=2192,",
520
+ "rightarrowtail=21a3,rightharpoondown=21c1,rightharpoonup=21c0,rightleftarrows=21c4,rightleftharpoons",
521
+ "=21cc,rightrightarrows=21c9,rightsquigarrow=219d,rightthreetimes=22cc,ring=2da,risingdotseq=2253,rla",
522
+ "rr=21c4,rlhar=21cc,rlm=200f,rmoust=23b1,rmoustache=23b1,rnmid=2aee,roang=27ed,roarr=21fe,robrk=27e7,",
523
+ "ropar=2986,ropf=1d563,roplus=2a2e,rotimes=2a35,rpar=29,rpargt=2994,rppolint=2a12,rrarr=21c9,rsaquo=2",
524
+ "03a,rscr=1d4c7,rsh=21b1,rsqb=5d,rsquo=2019,rsquor=2019,rthree=22cc,rtimes=22ca,rtri=25b9,rtrie=22b5,",
525
+ "rtrif=25b8,rtriltri=29ce,ruluhar=2968,rx=211e,sacute=15b,sbquo=201a,sc=227b,scE=2ab4,scap=2ab8,scaro",
526
+ "n=161,sccue=227d,sce=2ab0,scedil=15f,scirc=15d,scnE=2ab6,scnap=2aba,scnsim=22e9,scpolint=2a13,scsim=",
527
+ "227f,scy=441,sdot=22c5,sdotb=22a1,sdote=2a66,seArr=21d8,searhk=2925,searr=2198,searrow=2198,sect=a7,",
528
+ "semi=3b,seswar=2929,setminus=2216,setmn=2216,sext=2736,sfr=1d530,sfrown=2322,sharp=266f,shchcy=449,s",
529
+ "hcy=448,shortmid=2223,shortparallel=2225,shy=ad,sigma=3c3,sigmaf=3c2,sigmav=3c2,sim=223c,simdot=2a6a",
530
+ ",sime=2243,simeq=2243,simg=2a9e,simgE=2aa0,siml=2a9d,simlE=2a9f,simne=2246,simplus=2a24,simrarr=2972",
531
+ ",slarr=2190,smallsetminus=2216,smashp=2a33,smeparsl=29e4,smid=2223,smile=2323,smt=2aaa,smte=2aac,smt",
532
+ "es=2aac.fe00,softcy=44c,sol=2f,solb=29c4,solbar=233f,sopf=1d564,spades=2660,spadesuit=2660,spar=2225",
533
+ ",sqcap=2293,sqcaps=2293.fe00,sqcup=2294,sqcups=2294.fe00,sqsub=228f,sqsube=2291,sqsubset=228f,sqsubs",
534
+ "eteq=2291,sqsup=2290,sqsupe=2292,sqsupset=2290,sqsupseteq=2292,squ=25a1,square=25a1,squarf=25aa,squf",
535
+ "=25aa,srarr=2192,sscr=1d4c8,ssetmn=2216,ssmile=2323,sstarf=22c6,star=2606,starf=2605,straightepsilon",
536
+ "=3f5,straightphi=3d5,strns=af,sub=2282,subE=2ac5,subdot=2abd,sube=2286,subedot=2ac3,submult=2ac1,sub",
537
+ "nE=2acb,subne=228a,subplus=2abf,subrarr=2979,subset=2282,subseteq=2286,subseteqq=2ac5,subsetneq=228a",
538
+ ",subsetneqq=2acb,subsim=2ac7,subsub=2ad5,subsup=2ad3,succ=227b,succapprox=2ab8,succcurlyeq=227d,succ",
539
+ "eq=2ab0,succnapprox=2aba,succneqq=2ab6,succnsim=22e9,succsim=227f,sum=2211,sung=266a,sup=2283,sup1=b",
540
+ "9,sup2=b2,sup3=b3,supE=2ac6,supdot=2abe,supdsub=2ad8,supe=2287,supedot=2ac4,suphsol=27c9,suphsub=2ad",
541
+ "7,suplarr=297b,supmult=2ac2,supnE=2acc,supne=228b,supplus=2ac0,supset=2283,supseteq=2287,supseteqq=2",
542
+ "ac6,supsetneq=228b,supsetneqq=2acc,supsim=2ac8,supsub=2ad4,supsup=2ad6,swArr=21d9,swarhk=2926,swarr=",
543
+ "2199,swarrow=2199,swnwar=292a,szlig=df,target=2316,tau=3c4,tbrk=23b4,tcaron=165,tcedil=163,tcy=442,t",
544
+ "dot=20db,telrec=2315,tfr=1d531,there4=2234,therefore=2234,theta=3b8,thetasym=3d1,thetav=3d1,thickapp",
545
+ "rox=2248,thicksim=223c,thinsp=2009,thkap=2248,thksim=223c,thorn=fe,tilde=2dc,times=d7,timesb=22a0,ti",
546
+ "mesbar=2a31,timesd=2a30,tint=222d,toea=2928,top=22a4,topbot=2336,topcir=2af1,topf=1d565,topfork=2ada",
547
+ ",tosa=2929,tprime=2034,trade=2122,triangle=25b5,triangledown=25bf,triangleleft=25c3,trianglelefteq=2",
548
+ "2b4,triangleq=225c,triangleright=25b9,trianglerighteq=22b5,tridot=25ec,trie=225c,triminus=2a3a,tripl",
549
+ "us=2a39,trisb=29cd,tritime=2a3b,trpezium=23e2,tscr=1d4c9,tscy=446,tshcy=45b,tstrok=167,twixt=226c,tw",
550
+ "oheadleftarrow=219e,twoheadrightarrow=21a0,uArr=21d1,uHar=2963,uacute=fa,uarr=2191,ubrcy=45e,ubreve=",
551
+ "16d,ucirc=fb,ucy=443,udarr=21c5,udblac=171,udhar=296e,ufisht=297e,ufr=1d532,ugrave=f9,uharl=21bf,uha",
552
+ "rr=21be,uhblk=2580,ulcorn=231c,ulcorner=231c,ulcrop=230f,ultri=25f8,umacr=16b,uml=a8,uogon=173,uopf=",
553
+ "1d566,uparrow=2191,updownarrow=2195,upharpoonleft=21bf,upharpoonright=21be,uplus=228e,upsi=3c5,upsih",
554
+ "=3d2,upsilon=3c5,upuparrows=21c8,urcorn=231d,urcorner=231d,urcrop=230e,uring=16f,urtri=25f9,uscr=1d4",
555
+ "ca,utdot=22f0,utilde=169,utri=25b5,utrif=25b4,uuarr=21c8,uuml=fc,uwangle=29a7,vArr=21d5,vBar=2ae8,vB",
556
+ "arv=2ae9,vDash=22a8,vangrt=299c,varepsilon=3f5,varkappa=3f0,varnothing=2205,varphi=3d5,varpi=3d6,var",
557
+ "propto=221d,varr=2195,varrho=3f1,varsigma=3c2,varsubsetneq=228a.fe00,varsubsetneqq=2acb.fe00,varsups",
558
+ "etneq=228b.fe00,varsupsetneqq=2acc.fe00,vartheta=3d1,vartriangleleft=22b2,vartriangleright=22b3,vcy=",
559
+ "432,vdash=22a2,vee=2228,veebar=22bb,veeeq=225a,vellip=22ee,verbar=7c,vert=7c,vfr=1d533,vltri=22b2,vn",
560
+ "sub=2282.20d2,vnsup=2283.20d2,vopf=1d567,vprop=221d,vrtri=22b3,vscr=1d4cb,vsubnE=2acb.fe00,vsubne=22",
561
+ "8a.fe00,vsupnE=2acc.fe00,vsupne=228b.fe00,vzigzag=299a,wcirc=175,wedbar=2a5f,wedge=2227,wedgeq=2259,",
562
+ "weierp=2118,wfr=1d534,wopf=1d568,wp=2118,wr=2240,wreath=2240,wscr=1d4cc,xcap=22c2,xcirc=25ef,xcup=22",
563
+ "c3,xdtri=25bd,xfr=1d535,xhArr=27fa,xharr=27f7,xi=3be,xlArr=27f8,xlarr=27f5,xmap=27fc,xnis=22fb,xodot",
564
+ "=2a00,xopf=1d569,xoplus=2a01,xotime=2a02,xrArr=27f9,xrarr=27f6,xscr=1d4cd,xsqcup=2a06,xuplus=2a04,xu",
565
+ "tri=25b3,xvee=22c1,xwedge=22c0,yacute=fd,yacy=44f,ycirc=177,ycy=44b,yen=a5,yfr=1d536,yicy=457,yopf=1",
566
+ "d56a,yscr=1d4ce,yucy=44e,yuml=ff,zacute=17a,zcaron=17e,zcy=437,zdot=17c,zeetrf=2128,zeta=3b6,zfr=1d5",
567
+ "37,zhcy=436,zigrarr=21dd,zopf=1d56b,zscr=1d4cf,zwj=200d,zwnj=200c"
568
+ ].join("");
569
+ var NAMED_REFERENCES = new Map(NAMED.split(",").map((entry) => {
570
+ const [name, codes] = entry.split("=");
571
+ return [name, String.fromCodePoint(...codes.split(".").map((code) => Number.parseInt(code, 16)))];
572
+ }));
573
+
574
+ // src/html.js
575
+ var LATIN1 = "nbsp iexcl cent pound curren yen brvbar sect uml copy ordf laquo not shy reg macr deg plusmn sup2 sup3 acute micro para middot cedil sup1 ordm raquo frac14 frac12 frac34 iquest Agrave Aacute Acirc Atilde Auml Aring AElig Ccedil Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml ETH Ntilde Ograve Oacute Ocirc Otilde Ouml times Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig agrave aacute acirc atilde auml aring aelig ccedil egrave eacute ecirc euml igrave iacute icirc iuml eth ntilde ograve oacute ocirc otilde ouml divide oslash ugrave uacute ucirc uuml yacute thorn yuml".split(" ");
576
+ var LEGACY = /* @__PURE__ */ new Set([...LATIN1, "amp", "lt", "gt", "quot", "AMP", "LT", "GT", "QUOT", "COPY", "REG"]);
577
+ var LEGACY_LONGEST = Math.max(...[...LEGACY].map((name) => name.length));
578
+ var UNSHOWN = /* @__PURE__ */ new Set(["script", "style", "title", "noembed", "noframes", "iframe"]);
579
+ var RAW_SHOWN = /* @__PURE__ */ new Set(["textarea", "xmp"]);
580
+ var RAW_END = Object.fromEntries([...UNSHOWN, ...RAW_SHOWN].map((name) => [name, linear(String.raw`<\/${caseless(name)}[\s/>]`, "g")]));
581
+ var CLOSES_PARAGRAPH = /* @__PURE__ */ new Set(["address", "article", "aside", "blockquote", "center", "dd", "details", "dialog", "dir", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "li", "listing", "main", "menu", "nav", "ol", "p", "plaintext", "pre", "search", "section", "summary", "table", "ul", "xmp"]);
582
+ var PARTS_OF_TABLE = /* @__PURE__ */ new Set(["caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr"]);
583
+ var TABLE_STRUCTURE = [...PARTS_OF_TABLE, "table", "template"];
584
+ var NOT_REOPENING = /* @__PURE__ */ new Set([...CLOSES_PARAGRAPH, "base", "basefont", "bgsound", "body", "caption", "col", "colgroup", "frame", "frameset", "head", "html", "iframe", "link", "meta", "noembed", "noframes", "script", "style", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "title", "tr"]);
585
+ var COMMENT_END = linear("--!?>", "g");
586
+ var LABEL_END = linear(String.raw`<\/${caseless("label")}[\s/>]`);
587
+ var UNITS = {
588
+ px: 1,
589
+ pt: 4 / 3,
590
+ pc: 16,
591
+ in: 96,
592
+ cm: 96 / 2.54,
593
+ mm: 96 / 25.4,
594
+ q: 96 / 101.6,
595
+ rem: 16
596
+ };
597
+
598
+ // src/tokenizer.js
599
+ function characterClass(ranges, flags = "gu") {
600
+ const hex = (code) => `\\u{${code.toString(16)}}`;
601
+ return new RegExp(`[${ranges.map(([first, last]) => last ? `${hex(first)}-${hex(last)}` : hex(first)).join("")}]`, flags);
602
+ }
603
+ var INVISIBLE = [[173], [847], [4447, 4448], [6068, 6069], [6158], [8203], [8206, 8207], [8234, 8238], [8288, 8292], [8294, 8297], [12644], [65279], [65440]];
604
+ var OBFUSCATING = characterClass(INVISIBLE);
605
+ var JOINERS = characterClass([[8204, 8205], [65024, 65039]]);
606
+ var INVISIBLE_OR_JOINER = characterClass([...INVISIBLE, [8204, 8205]]);
607
+ var LATIN_END = new RegExp("\\p{Script=Latin}$", "u");
608
+ var LATIN_START = new RegExp("^\\p{Script=Latin}", "u");
609
+ var ZWSP_SCRIPTS = String.raw`\p{Script=Thai}\p{Script=Lao}\p{Script=Khmer}\p{Script=Myanmar}\p{Script=Tibetan}`;
610
+ var ZWSP_SCRIPT_END = new RegExp(`[${ZWSP_SCRIPTS}]$`, "u");
611
+ var ZWSP_SCRIPT_START = new RegExp(`^[${ZWSP_SCRIPTS}]`, "u");
612
+ var BIDI = characterClass([[8206, 8207], [8234, 8236], [8294, 8297]], "u");
613
+ var DIGIT_END = new RegExp("\\p{N}$", "u");
614
+ var DIGIT_START = new RegExp("^\\p{N}", "u");
615
+ var STYLED_LETTERS = characterClass([[119808, 120831], [127280, 127305]], "u");
616
+ var WIDE_LETTERS = characterClass([[9312, 9471], [65313, 65338], [65345, 65370]], "u");
617
+ var LOOKALIKES = {
618
+ \u0430: "a",
619
+ \u0432: "b",
620
+ \u0435: "e",
621
+ \u0451: "e",
622
+ \u043A: "k",
623
+ \u043C: "m",
624
+ \u043D: "h",
625
+ \u043E: "o",
626
+ \u0440: "p",
627
+ \u0441: "c",
628
+ \u0442: "t",
629
+ \u0443: "y",
630
+ \u0445: "x",
631
+ \u0455: "s",
632
+ \u0456: "i",
633
+ \u0457: "i",
634
+ \u0458: "j",
635
+ "\u0501": "d",
636
+ "\u051B": "q",
637
+ "\u051D": "w",
638
+ \u04BB: "h",
639
+ "\u04CF": "l",
640
+ \u0261: "g",
641
+ \u044C: "b",
642
+ \u043F: "n",
643
+ \u0433: "r",
644
+ \u03B1: "a",
645
+ \u03B2: "b",
646
+ \u03B5: "e",
647
+ \u03B7: "n",
648
+ \u03B9: "i",
649
+ \u03BA: "k",
650
+ \u03BD: "v",
651
+ \u03BF: "o",
652
+ \u03C1: "p",
653
+ \u03C4: "t",
654
+ \u03C5: "u",
655
+ \u03C7: "x",
656
+ \u03C9: "w",
657
+ \u03B3: "y",
658
+ \u03BC: "u"
659
+ };
660
+ var LEET_DIGITS = new RegExp("\\p{L}[0134578]{1,2}\\p{L}", "u");
661
+ var URL_PATTERN = linear(String.raw`\b(?:https?:\/\/|www\.)[^\s<>"'\x60]+|\b[a-z\d][a-z\d-]{0,62}(?:\.[a-z\d-]{1,63}){0,10}\.[a-z]{2,24}\/[^\s<>"'\x60]*`, "giu");
662
+ var EMAIL_SOURCE = String.raw`[\p{L}\p{N}._%+-]{1,64}@([\p{L}\p{N}-]{1,63}(?:\.[\p{L}\p{N}-]{1,63}){0,10}\.\p{L}{2,24})`;
663
+ var EMAIL_PATTERN = linear(EMAIL_SOURCE, "gu");
664
+ var PHONE_PATTERN = linear(String.raw`(?:\+|0{2})\d[\d\s().-]{7,}\d|\(\d{3}\)\s?\d{3}[\s.-]\d{4}|\b(?:\d{3}[.-]){2}\d{4}\b`, "g");
665
+ var IP_PATTERN = linear(String.raw`\b(?:25[0-5]|2[0-4]\d|1?\d?\d)(?:\.(?:25[0-5]|2[0-4]\d|1?\d?\d)){3}\b`, "g");
666
+ var MONEY_PATTERN = linear(String.raw`[$€£¥₹₽₩₺₦]\s?\d|\d\s?(?:[$€£¥₹₽₩₺₦]|usd|eur|gbp|dollars?|euros?)\b`, "giu");
667
+ var BITCOIN_PATTERN = linear(String.raw`\b(?:bc1[ac-hj-np-z02-9]{25,60}|[13][a-km-zA-HJ-NP-Z1-9]{25,34})\b`, "g");
668
+ var CARD_PATTERN = linear(String.raw`\b(?:\d[ -]?){13,19}\b`, "g");
669
+ var ANCHOR_START = linear(String.raw`<a[\t\n\f\r />]`, "gi");
670
+ var SHOWN_URL = linear(String.raw`^(?:https?:\/\/|www\.)\S+$|^[a-z\d-]{1,63}(?:\.[a-z\d-]{1,63}){1,10}(?:\/\S*)?$`, "i");
671
+ var IMG_PIXEL = linear(String.raw`<img\b[^<>]*\b(?:width|height)\s*=\s*["']?[01]["'\s>]`, "i");
672
+ var IMG = linear(String.raw`<img\b`, "gi");
673
+ var BARE_HOST = linear(String.raw`\b[a-z\d][a-z\d-]{0,62}(?:\.[a-z\d-]{1,63}){0,9}\.[a-z]{2,24}\b`, "gi");
674
+ var BRAND_NAMES = new Set(BRANDS);
675
+ var LATIN_LOOKALIKES = { Cyrillic: {}, Greek: {} };
676
+ for (const [char, latin] of Object.entries(LOOKALIKES)) {
677
+ const target = LATIN_LOOKALIKES[scriptOf(char)];
678
+ if (target && !target[latin]) {
679
+ target[latin] = char;
680
+ }
681
+ }
682
+ var LATIN = new RegExp("\\p{Script=Latin}", "u");
683
+ var ADDRESS_SOURCE = String.raw`[\p{L}\p{N}._%+-]{1,64}@([\p{L}\p{N}-]{1,63}(?:\.[\p{L}\p{N}-]{1,63}){1,10})`;
684
+ var NAMED_ADDRESS = linear(ADDRESS_SOURCE, "u");
685
+
686
+ // src/attachments.js
687
+ var EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
688
+ "ade",
689
+ "adp",
690
+ "apk",
691
+ "app",
692
+ "appimage",
693
+ "appinstaller",
694
+ "application",
695
+ "appref-ms",
696
+ "appx",
697
+ "appxbundle",
698
+ "asp",
699
+ "aspx",
700
+ "asx",
701
+ "bas",
702
+ "bat",
703
+ "bgi",
704
+ "cab",
705
+ "chm",
706
+ "cmd",
707
+ "cnt",
708
+ "com",
709
+ "command",
710
+ "cpl",
711
+ "csh",
712
+ "diagcab",
713
+ "dll",
714
+ "dmg",
715
+ "docm",
716
+ "dotm",
717
+ "elf",
718
+ "exe",
719
+ "fxp",
720
+ "gadget",
721
+ "grp",
722
+ "hlp",
723
+ "hpj",
724
+ "hta",
725
+ "htc",
726
+ "img",
727
+ "inf",
728
+ "ins",
729
+ "ipa",
730
+ "iqy",
731
+ "iso",
732
+ "isp",
733
+ "its",
734
+ "jar",
735
+ "jnlp",
736
+ "js",
737
+ "jse",
738
+ "ksh",
739
+ "library-ms",
740
+ "lnk",
741
+ "mad",
742
+ "maf",
743
+ "mag",
744
+ "mam",
745
+ "maq",
746
+ "mar",
747
+ "mas",
748
+ "mau",
749
+ "mav",
750
+ "maw",
751
+ "mcf",
752
+ "mda",
753
+ "mde",
754
+ "mdt",
755
+ "mdw",
756
+ "mdz",
757
+ "msc",
758
+ "msh",
759
+ "msh1",
760
+ "msh1xml",
761
+ "msh2",
762
+ "msh2xml",
763
+ "mshxml",
764
+ "msi",
765
+ "msix",
766
+ "msixbundle",
767
+ "msp",
768
+ "mst",
769
+ "msu",
770
+ "nsh",
771
+ "one",
772
+ "onepkg",
773
+ "ops",
774
+ "osd",
775
+ "pcd",
776
+ "pif",
777
+ "pkg",
778
+ "pl",
779
+ "plg",
780
+ "potm",
781
+ "ppam",
782
+ "ppsm",
783
+ "pptm",
784
+ "prf",
785
+ "prg",
786
+ "ps1",
787
+ "ps1xml",
788
+ "ps2",
789
+ "ps2xml",
790
+ "psc1",
791
+ "psc2",
792
+ "py",
793
+ "pyc",
794
+ "pyo",
795
+ "pyw",
796
+ "pyz",
797
+ "pyzw",
798
+ "reg",
799
+ "scf",
800
+ "scpt",
801
+ "scr",
802
+ "sct",
803
+ "search-ms",
804
+ "searchconnector-ms",
805
+ "settingcontent-ms",
806
+ "sh",
807
+ "shb",
808
+ "shs",
809
+ "slk",
810
+ "sys",
811
+ "vb",
812
+ "vbe",
813
+ "vbp",
814
+ "vbs",
815
+ "vhd",
816
+ "vhdx",
817
+ "vsmacros",
818
+ "vsw",
819
+ "webpnp",
820
+ "website",
821
+ "ws",
822
+ "wsb",
823
+ "wsc",
824
+ "wsf",
825
+ "wsh",
826
+ "xbap",
827
+ "xlam",
828
+ "xll",
829
+ "xlsm",
830
+ "xltm",
831
+ "xnk"
832
+ ]);
833
+ var RISKY_EXTENSIONS = /* @__PURE__ */ new Set(["cer", "der", "mat", "pst", "theme", "tmp", "url"]);
834
+ var SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set(["asp", "aspx", "csh", "js", "ksh", "pl", "py", "pyc", "pyo", "pyw", "pyz", "pyzw", "sh"]);
835
+ var MACRO_EXTENSIONS = /* @__PURE__ */ new Set(["docm", "dotm", "xlsm", "xltm", "xlam", "pptm", "potm", "ppsm", "ppam", "sldm"]);
836
+ var DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set(["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf", "jpg", "jpeg", "png", "gif", "zip", "csv", "odt", "ods", "html", "htm", "mp3", "mp4", "mov", "wav", "eml", "msg", "xml", "json"]);
837
+ var TEMPORARY_EXTENSIONS = /* @__PURE__ */ new Set(["tmp"]);
838
+ var BIDI_CONTROLS = characterClass([[8234, 8238], [8294, 8297]], "u");
839
+ var ALL_BIDI_CONTROLS = characterClass([[8234, 8238], [8294, 8297]], "gu");
840
+ var ARCHIVE_TYPES = /* @__PURE__ */ new Set(["zip", "rar", "7z", "gz", "bz2", "xz", "cab", "iso", "tar", "zst", "lzh", "ace", "arj"]);
841
+ function sniff(buffer) {
842
+ if (!Buffer.isBuffer(buffer) || buffer.length < 4) {
843
+ return null;
844
+ }
845
+ const at = (offset, bytes) => buffer.length >= offset + bytes.length && bytes.every((byte, i) => buffer[offset + i] === byte);
846
+ const ascii = (offset, text) => at(offset, [...Buffer.from(text, "latin1")]);
847
+ const result = (type, executable = false) => ({ type, executable, archive: ARCHIVE_TYPES.has(type) });
848
+ if (ascii(0, "MZ") && buffer.length >= 64 && at(buffer.readUInt32LE(60), [80, 69, 0, 0])) {
849
+ return result("exe", true);
850
+ }
851
+ if (at(0, [127, 69, 76, 70])) {
852
+ return result("elf", true);
853
+ }
854
+ const magic = buffer.readUInt32BE(0);
855
+ if ([4277009102, 4277009103, 3472551422, 3489328638].includes(magic)) {
856
+ return result("macho", true);
857
+ }
858
+ if (magic === 3405691582) {
859
+ return result("macho", true);
860
+ }
861
+ if (at(0, [76, 0, 0, 0, 1, 20, 2, 0])) {
862
+ return result("lnk", true);
863
+ }
864
+ if (at(0, [208, 207, 17, 224, 161, 177, 26, 225])) {
865
+ return result("ole");
866
+ }
867
+ if (at(0, [80, 75, 3, 4]) || at(0, [80, 75, 5, 6])) {
868
+ const names = entriesOf(buffer).map((entry) => entry.name);
869
+ if (names.includes("AndroidManifest.xml") || names.includes("classes.dex")) {
870
+ return result("apk", true);
871
+ }
872
+ if (names.includes("META-INF/MANIFEST.MF") && names.some((name) => name.endsWith(".class"))) {
873
+ return result("jar", true);
874
+ }
875
+ if (names.some((name) => name.startsWith("word/"))) {
876
+ return result("docx");
877
+ }
878
+ if (names.some((name) => name.startsWith("xl/"))) {
879
+ return result("xlsx");
880
+ }
881
+ if (names.some((name) => name.startsWith("ppt/"))) {
882
+ return result("pptx");
883
+ }
884
+ return result("zip");
885
+ }
886
+ if (ascii(0, "Rar!")) {
887
+ return result("rar");
888
+ }
889
+ if (at(0, [55, 122, 188, 175, 39, 28])) {
890
+ return result("7z");
891
+ }
892
+ if (at(0, [31, 139])) {
893
+ return result("gz");
894
+ }
895
+ if (ascii(0, "MSCF")) {
896
+ return result("cab");
897
+ }
898
+ if (ascii(32769, "CD001") || ascii(34817, "CD001") || ascii(36865, "CD001")) {
899
+ return result("iso");
900
+ }
901
+ if (ascii(0, "conectix") || ascii(0, "vhdxfile")) {
902
+ return result("vhd", true);
903
+ }
904
+ if (ascii(0, "%PDF")) {
905
+ return result("pdf");
906
+ }
907
+ if (ascii(0, String.raw`{\rt`)) {
908
+ return result("rtf");
909
+ }
910
+ if (at(0, [137, 80, 78, 71])) {
911
+ return result("png");
912
+ }
913
+ if (at(0, [255, 216, 255])) {
914
+ return result("jpg");
915
+ }
916
+ if (ascii(0, "GIF8")) {
917
+ return result("gif");
918
+ }
919
+ if (ascii(0, "RIFF") && ascii(8, "WEBP")) {
920
+ return result("webp");
921
+ }
922
+ if (ascii(0, "#!")) {
923
+ return result("script", true);
924
+ }
925
+ const head = buffer.subarray(0, 1024).toString("utf8").replace(/^\uFEFF/u, "").trimStart().toLowerCase();
926
+ if (head.startsWith("<svg") || head.startsWith("<?xml") && head.includes("<svg")) {
927
+ return result("svg");
928
+ }
929
+ if (head.startsWith("<!doctype html") || head.startsWith("<html") || head.startsWith("<head") || head.startsWith("<script")) {
930
+ return result("html");
931
+ }
932
+ return null;
933
+ }
934
+ var ZIP_FAMILY = /* @__PURE__ */ new Set(["zip", "docx", "xlsx", "pptx"]);
935
+ var OFFICE_TYPES = /* @__PURE__ */ new Set(["docx", "xlsx", "pptx"]);
936
+ var OFFICE_EMBEDDED = MACRO_EXTENSIONS;
937
+ var ENTRIES = /* @__PURE__ */ new WeakMap();
938
+ function entriesOf(buffer) {
939
+ let entries = ENTRIES.get(buffer);
940
+ if (!entries) {
941
+ entries = zipEntries(buffer);
942
+ ENTRIES.set(buffer, entries);
943
+ }
944
+ return entries;
945
+ }
946
+ function zipEntries(buffer, limit = 2e3) {
947
+ const start = Math.max(0, buffer.length - 65557);
948
+ const records = [];
949
+ for (let i = buffer.length - 22; i >= start; i--) {
950
+ if (buffer.readUInt32LE(i) === 101010256 && (records.length === 0 || i + 22 + buffer.readUInt16LE(i + 20) === buffer.length)) {
951
+ records.push(i);
952
+ }
953
+ }
954
+ const state = {
955
+ entries: [],
956
+ limit,
957
+ read: /* @__PURE__ */ new Set(),
958
+ names: MAX_NAME_BYTES
959
+ };
960
+ for (const eocd of records) {
961
+ const offset = directoryOf(buffer, eocd);
962
+ if (offset !== -1) {
963
+ readDirectory(buffer, offset, state);
964
+ }
965
+ }
966
+ return state.entries;
967
+ }
968
+ var MAX_NAME_LENGTH = 1024;
969
+ var MAX_NAME_BYTES = 1024 * 1024;
970
+ var DIRECTORY = 33639248;
971
+ var isDirectory = (buffer, offset) => offset >= 0 && offset + 46 <= buffer.length && buffer.readUInt32LE(offset) === DIRECTORY;
972
+ function directoryOf(buffer, eocd) {
973
+ let offset = buffer.readUInt32LE(eocd + 16);
974
+ let size = buffer.readUInt32LE(eocd + 12);
975
+ const locator = eocd - 20;
976
+ if ((offset === 4294967295 || size === 4294967295) && locator >= 0 && buffer.readUInt32LE(locator) === 117853008) {
977
+ const stated = Number(buffer.readBigUInt64LE(locator + 8));
978
+ const isRecord = (at) => at >= 0 && at + 56 <= locator && buffer.readUInt32LE(at) === 101075792;
979
+ const record = isRecord(stated) ? stated : locator - 56;
980
+ if (isRecord(record)) {
981
+ size = Number(buffer.readBigUInt64LE(record + 40));
982
+ offset = Number(buffer.readBigUInt64LE(record + 48));
983
+ }
984
+ }
985
+ if (isDirectory(buffer, offset)) {
986
+ return offset;
987
+ }
988
+ for (const end of [eocd, locator - 56]) {
989
+ const directory = end - size;
990
+ if (directory < end && isDirectory(buffer, directory)) {
991
+ return directory;
992
+ }
993
+ }
994
+ return -1;
995
+ }
996
+ function readDirectory(buffer, offset, state) {
997
+ while (state.entries.length < state.limit && isDirectory(buffer, offset) && !state.read.has(offset)) {
998
+ state.read.add(offset);
999
+ const flags = buffer.readUInt16LE(offset + 8);
1000
+ const size = buffer.readUInt32LE(offset + 24);
1001
+ const nameLength = buffer.readUInt16LE(offset + 28);
1002
+ const extraLength = buffer.readUInt16LE(offset + 30);
1003
+ const commentLength = buffer.readUInt16LE(offset + 32);
1004
+ const encoding = flags & 2048 ? "utf8" : "latin1";
1005
+ const start = offset + 46;
1006
+ const end = Math.min(buffer.length, start + nameLength);
1007
+ const kept = Math.min(end - start, MAX_NAME_LENGTH);
1008
+ state.names -= kept;
1009
+ if (state.names < 0) {
1010
+ return;
1011
+ }
1012
+ const half = MAX_NAME_LENGTH / 2;
1013
+ const name = end - start > MAX_NAME_LENGTH ? `${buffer.toString(encoding, start, start + half)}\u2026${buffer.toString(encoding, end - half, end)}` : buffer.toString(encoding, start, end);
1014
+ state.entries.push({ name, encrypted: (flags & 1) === 1, size });
1015
+ offset += 46 + nameLength + extraLength + commentLength;
1016
+ }
1017
+ }
1018
+ function shorten(name, max = 100) {
1019
+ const characters = [...name];
1020
+ return characters.length <= max ? name : `${characters.slice(0, max - 41).join("")}\u2026${characters.slice(-40).join("")}`;
1021
+ }
1022
+ function extensionOf(name) {
1023
+ const base = trimEndOf(String(name).toLowerCase().replace(ALL_BIDI_CONTROLS, "").split(/[/\\]/).pop(), ". ");
1024
+ const whole = lastExtension(base);
1025
+ const file = base.replace(/^[a-z]:/, "");
1026
+ const colon = file.indexOf(":");
1027
+ if (colon !== -1 && /^(?::?\$data)?$/.test(file.slice(colon + 1))) {
1028
+ return lastExtension(trimEndOf(file.slice(0, colon), ". "));
1029
+ }
1030
+ return whole;
1031
+ }
1032
+ var COMPRESSED_EXTENSIONS = /* @__PURE__ */ new Set(["gz", "bz2", "xz", "zst"]);
1033
+ function uncompressedName(name) {
1034
+ if (!COMPRESSED_EXTENSIONS.has(extensionOf(name))) {
1035
+ return String(name);
1036
+ }
1037
+ const trimmed = trimEndOf(String(name).replace(ALL_BIDI_CONTROLS, ""), ". ");
1038
+ return trimmed.slice(0, trimmed.lastIndexOf("."));
1039
+ }
1040
+ function lastExtension(base) {
1041
+ const dot = base.lastIndexOf(".");
1042
+ return dot === -1 ? "" : base.slice(dot + 1).trim();
1043
+ }
1044
+ var VBA_NAMES = /* @__PURE__ */ new Set(["vba", "_vba_project", "_vba_project_cur", "macros"]);
1045
+ function oleHasMacros(buffer) {
1046
+ for (let offset = 512; offset + 128 <= buffer.length; offset += 128) {
1047
+ const length = buffer.readUInt16LE(offset + 64);
1048
+ const type = buffer[offset + 66];
1049
+ if ((type === 1 || type === 2) && length >= 4 && length <= 64 && length % 2 === 0 && VBA_NAMES.has(buffer.subarray(offset, offset + length - 2).toString("utf16le").toLowerCase())) {
1050
+ return true;
1051
+ }
1052
+ }
1053
+ return false;
1054
+ }
1055
+ var PDF_ACTIVE = linear(String.raw`\/(?:JavaScript|JS|Launch)\b`);
1056
+ var escaped = (character) => {
1057
+ const hex = character.codePointAt(0).toString(16);
1058
+ return `(?:${character}|#${hex[0]}[${hex[1].toLowerCase()}${hex[1].toUpperCase()}])`;
1059
+ };
1060
+ var WORD_ESCAPE = String.raw`#(?:3\d|4[1-9a-fA-F]|5[\daA]|5[fF]|6[1-9a-fA-F]|7[\daA])`;
1061
+ var PDF_ACTIVE_ESCAPED = new RegExp(`/(?:${["JavaScript", "JS", "Launch"].map((name) => [...name].map((character) => escaped(character)).join("")).join("|")})(?![\\w]|${WORD_ESCAPE})`);
1062
+ var pdfActive = (text) => PDF_ACTIVE.test(text) || PDF_ACTIVE_ESCAPED.test(text);
1063
+ function inspectAttachments(attachments = []) {
1064
+ const findings = [];
1065
+ for (const attachment of attachments) {
1066
+ const filename = typeof attachment.filename === "string" ? attachment.filename : "";
1067
+ const name = filename || "unnamed attachment";
1068
+ const content = Buffer.isBuffer(attachment.content) ? attachment.content : null;
1069
+ const extension = extensionOf(filename);
1070
+ const detected = content ? sniff(content) : null;
1071
+ const add = (type, message, extra = {}) => findings.push({
1072
+ type,
1073
+ filename: name,
1074
+ message,
1075
+ ...extra
1076
+ });
1077
+ if (BIDI_CONTROLS.test(filename)) {
1078
+ add("rtl_override", `Attachment "${name}" uses a right-to-left override to hide its real extension`);
1079
+ }
1080
+ const parts = trimEndOf(filename.toLowerCase(), ". ").split(".");
1081
+ if (parts.length >= 3 && (EXECUTABLE_EXTENSIONS.has(extension) || RISKY_EXTENSIONS.has(extension)) && !TEMPORARY_EXTENSIONS.has(extension) && DOCUMENT_EXTENSIONS.has(parts.at(-2).trim())) {
1082
+ add("double_extension", `Attachment "${name}" has a document extension followed by a program extension`, { extension });
1083
+ }
1084
+ const byName = EXECUTABLE_EXTENSIONS.has(extension) && !MACRO_EXTENSIONS.has(extension);
1085
+ if (detected?.executable && (detected.type !== "script" || !byName)) {
1086
+ add(extension && !EXECUTABLE_EXTENSIONS.has(extension) ? "disguised_executable" : "executable", `Attachment "${name}" contains a program (${detected.type})${extension && extension !== detected.type ? ` but is named .${extension}` : ""}`, { extension: detected.type });
1087
+ } else if (byName) {
1088
+ add("executable", `Attachment "${name}" is a file type that runs code (.${extension})`, { extension });
1089
+ } else if (RISKY_EXTENSIONS.has(extension)) {
1090
+ add("risky_attachment", `Attachment "${name}" is a risky file type (.${extension})`, { extension });
1091
+ }
1092
+ const held = COMPRESSED_EXTENSIONS.has(extension) ? extensionOf(uncompressedName(filename)) : "";
1093
+ if (EXECUTABLE_EXTENSIONS.has(held)) {
1094
+ const script = SCRIPT_EXTENSIONS.has(held);
1095
+ add(script ? "script_in_archive" : "executable_in_archive", `Archive "${name}" contains ${script ? "a script" : "a program"} (${shorten(uncompressedName(filename).split(/[/\\]/).pop())})`, { extension: held, extensions: [held] });
1096
+ }
1097
+ const webPage = detected?.type === "html" || detected?.type === "svg" || ["htm", "html", "mht", "mhtml", "shtml", "xht", "xhtml", "svg"].includes(extension);
1098
+ const addWebPage = () => {
1099
+ const active = content !== null && /<script\b|<form\b|\bon(?:load|error|click)\s*=|javascript:|window\.location|document\.location|atob\(/i.test(content.subarray(0, 2e5).toString("utf8"));
1100
+ add("html_attachment", `Attachment "${name}" is ${detected?.type === "svg" || extension === "svg" ? "an SVG image" : "a web page"}${active ? " with scripts or forms" : ""}`, { extension: extension || detected?.type, active });
1101
+ };
1102
+ if (!content) {
1103
+ if (webPage) {
1104
+ addWebPage();
1105
+ }
1106
+ continue;
1107
+ }
1108
+ const zipFamily = ZIP_FAMILY.has(detected?.type) || extension === "zip" && !detected?.executable && entriesOf(content).length > 0;
1109
+ if (zipFamily) {
1110
+ const entries = entriesOf(content);
1111
+ const office = OFFICE_TYPES.has(detected?.type);
1112
+ if (entries.some((entry) => /(?:^|\/)vbaproject\.bin$/i.test(entry.name))) {
1113
+ add("macro", `Attachment "${name}" is an Office document with a VBA macro project`, { extension });
1114
+ } else if (office && entries.some((entry) => MACRO_EXTENSIONS.has(extensionOf(entry.name)))) {
1115
+ add("macro", `Attachment "${name}" is an Office document holding another with macros`, { extension });
1116
+ }
1117
+ const inner = entries.filter((entry) => EXECUTABLE_EXTENSIONS.has(extensionOf(uncompressedName(entry.name))) && !(office && OFFICE_EMBEDDED.has(extensionOf(entry.name))));
1118
+ const details = { extension: extensionOf(uncompressedName(inner[0]?.name ?? "")), extensions: [...new Set(inner.map((entry) => extensionOf(uncompressedName(entry.name))))] };
1119
+ const listed = inner.slice(0, 3).map((entry) => shorten(entry.name.split("/").pop())).join(", ");
1120
+ if (inner.some((entry) => !SCRIPT_EXTENSIONS.has(extensionOf(uncompressedName(entry.name))))) {
1121
+ add("executable_in_archive", `Archive "${name}" contains ${inner.length === 1 ? "a program" : `${inner.length} programs`} (${listed})`, details);
1122
+ } else if (inner.length > 0) {
1123
+ add("script_in_archive", `Archive "${name}" contains ${inner.length === 1 ? "a script" : `${inner.length} scripts`} (${listed})`, details);
1124
+ }
1125
+ if ((detected?.type === "zip" || !ZIP_FAMILY.has(detected?.type)) && entries.some((entry) => entry.encrypted)) {
1126
+ add("encrypted_archive", `Archive "${name}" is password protected, so its contents cannot be scanned`, { extension });
1127
+ }
1128
+ } else if (detected?.type === "ole") {
1129
+ if (oleHasMacros(content)) {
1130
+ add("macro", `Attachment "${name}" is an Office document with a VBA macro project`, { extension });
1131
+ }
1132
+ } else if (detected?.type === "pdf" || extension === "pdf") {
1133
+ if (pdfActive(content.toString("latin1"))) {
1134
+ add("pdf_active", `PDF "${name}" contains JavaScript or a launch action`, { extension: "pdf" });
1135
+ }
1136
+ } else if (detected?.type === "rtf" && /\\object\b|\\objdata\b|\\objupdate\b/.test(content.toString("latin1"))) {
1137
+ add("rtf_object", `RTF document "${name}" embeds an OLE object`, { extension: "rtf" });
1138
+ }
1139
+ if (webPage) {
1140
+ addWebPage();
1141
+ }
1142
+ }
1143
+ return findings;
1144
+ }
1145
+
1146
+ // src/parse.js
11
1147
  var ADDRESS_FIELDS = /* @__PURE__ */ new Set(["from", "to", "cc", "bcc", "sender", "reply-to", "delivered-to", "return-path", "disposition-notification-to"]);
12
1148
  var MAX_ADDRESS_FIELD = 16 * 1024;
13
1149
  var MAX_ADDRESS_SEPARATORS = 2e3;
@@ -16,21 +1152,21 @@ var MAX_ADDRESS_TOTAL = 64 * 1024;
16
1152
  var ADDRESS_OPERATORS = /* @__PURE__ */ new Map([['"', '"'], ["(", ")"], ["<", ">"], [",", ""], [":", ";"], [";", ""]]);
17
1153
  var SINGLE_FIELDS = /* @__PURE__ */ new Set(["message-id", "content-id", "from", "sender", "in-reply-to", "reply-to", "subject", "date", "content-disposition", "content-type", "content-transfer-encoding", "priority", "mime-version", "content-description", "precedence", "errors-to", "disposition-notification-to"]);
18
1154
  var PRIORITY_FIELDS = /* @__PURE__ */ new Set(["priority", "x-priority", "x-msmail-priority", "importance"]);
19
- var BOUNDED = /* @__PURE__ */ Symbol("bounded address fields");
1155
+ var BOUNDED2 = /* @__PURE__ */ Symbol("bounded address fields");
20
1156
  var ROOM = /* @__PURE__ */ Symbol("room left for address fields");
21
1157
  var PARSER_OPTIONS = {
22
1158
  skipHtmlToText: true,
23
1159
  skipImageLinks: true,
24
1160
  skipTextToHtml: true,
25
1161
  skipTextLinks: true,
26
- [BOUNDED]: true
1162
+ [BOUNDED2]: true
27
1163
  };
28
1164
  function boundAddressField(line, room) {
29
1165
  const start = line.indexOf(":") + 1;
30
1166
  const limit = Math.min(line.length, MAX_ADDRESS_FIELD, room);
31
1167
  let end = start;
32
1168
  let expecting = "";
33
- let escaped = false;
1169
+ let escaped2 = false;
34
1170
  let separators = 0;
35
1171
  let groups = 0;
36
1172
  let index = start;
@@ -39,8 +1175,8 @@ function boundAddressField(line, room) {
39
1175
  if ((chr === "," || chr === ";") && ++separators > MAX_ADDRESS_SEPARATORS) {
40
1176
  break;
41
1177
  }
42
- if (escaped) {
43
- escaped = false;
1178
+ if (escaped2) {
1179
+ escaped2 = false;
44
1180
  } else if (expecting !== "" && chr === expecting) {
45
1181
  expecting = "";
46
1182
  end = chr === ";" ? index + 1 : end;
@@ -48,7 +1184,7 @@ function boundAddressField(line, room) {
48
1184
  expecting = ADDRESS_OPERATORS.get(chr);
49
1185
  end = chr === "," || chr === ";" ? index : end;
50
1186
  } else if (expecting === '"' && chr === "\\") {
51
- escaped = true;
1187
+ escaped2 = true;
52
1188
  }
53
1189
  if (chr === ":" && expecting === ";" && ++groups > MAX_ADDRESS_GROUPS) {
54
1190
  break;
@@ -74,7 +1210,7 @@ function boundAddressLines(lines, budget, only = null) {
74
1210
  }
75
1211
  var { processHeaders } = MailParser.prototype;
76
1212
  MailParser.prototype.processHeaders = function(lines) {
77
- if (!this.options[BOUNDED]) {
1213
+ if (!this.options[BOUNDED2]) {
78
1214
  return processHeaders.call(this, lines);
79
1215
  }
80
1216
  this[ROOM] ??= { room: MAX_ADDRESS_TOTAL };
@@ -120,18 +1256,103 @@ var KEPT_FIELDS = /* @__PURE__ */ new Set([
120
1256
  var AUTH_FIELDS = /* @__PURE__ */ new Set([...KEPT_FIELDS, "arc-seal", "arc-message-signature"]);
121
1257
  var MAX_NESTED_BYTES = 25 * 1024 * 1024;
122
1258
  var PARSE_TIMEOUT = 6e4;
1259
+ var NAMED_TEXT = /* @__PURE__ */ Symbol("named text parts");
1260
+ var ENCODED_FILES = /^(?:begin [0-7]{3,4} |=ybegin\b[^\r\n\u2028\u2029]*?\bname=)([^\r\n\u2028\u2029]+)\r?$/gm;
1261
+ var MAX_ENCODED_FILES = 1e3;
1262
+ var foundIn = /* @__PURE__ */ new WeakMap();
1263
+ function addFinding(list, part) {
1264
+ const found = foundIn.get(list) ?? /* @__PURE__ */ new Set();
1265
+ foundIn.set(list, found);
1266
+ const types = inspectAttachments([part]).map((finding) => finding.type);
1267
+ if (types.some((type) => !found.has(type))) {
1268
+ list.push(part);
1269
+ for (const type of types) {
1270
+ found.add(type);
1271
+ }
1272
+ }
1273
+ }
1274
+ function parametersOf(value) {
1275
+ const parameters = [];
1276
+ let start = -1;
1277
+ let quoted = false;
1278
+ for (let i = 0; i < value.length; i++) {
1279
+ if (quoted && value[i] === "\\") {
1280
+ i++;
1281
+ } else if (value[i] === '"') {
1282
+ quoted = !quoted;
1283
+ } else if (value[i] === ";" && !quoted) {
1284
+ if (start !== -1) {
1285
+ parameters.push(value.slice(start, i));
1286
+ }
1287
+ start = i + 1;
1288
+ }
1289
+ }
1290
+ if (start !== -1) {
1291
+ parameters.push(value.slice(start));
1292
+ }
1293
+ return parameters;
1294
+ }
1295
+ var MAX_NAME_FIELDS = 8;
1296
+ var MAX_NAME_PARAMETERS = 32;
1297
+ function repeatedNames(node) {
1298
+ const names = [];
1299
+ const { headers, libmime } = node ?? {};
1300
+ if (typeof headers?.get !== "function" || typeof libmime?.parseHeaderValue !== "function") {
1301
+ return names;
1302
+ }
1303
+ const read = (value, parameter) => {
1304
+ let name = "";
1305
+ try {
1306
+ name = libmime.decodeWords(String(libmime.parseHeaderValue(value, { stripComments: true }).params[parameter] ?? "")).trim();
1307
+ } catch {
1308
+ }
1309
+ if (name !== "") {
1310
+ names.push(name);
1311
+ }
1312
+ };
1313
+ for (const [field, parameter] of [["content-disposition", "filename"], ["content-type", "name"]]) {
1314
+ const values = headers.get(field).slice(0, MAX_NAME_FIELDS);
1315
+ for (const value of values) {
1316
+ const parameters = parametersOf(value).slice(0, MAX_NAME_PARAMETERS).map((text) => ({ text, key: text.slice(0, Math.max(0, text.indexOf("="))).trim().toLowerCase() }));
1317
+ const repeated = parameters.filter(({ key }) => (key === parameter || key.startsWith(`${parameter}*`)) && parameters.filter((other) => other.key === key).length > 1);
1318
+ if (values.length > 1) {
1319
+ read(value, parameter);
1320
+ }
1321
+ for (const { text } of repeated) {
1322
+ read(`x;${text}`, text.slice(0, text.indexOf("=")).trim().toLowerCase().replace(/\*.*$/, ""));
1323
+ }
1324
+ }
1325
+ }
1326
+ return names;
1327
+ }
123
1328
  async function simpleParse(raw, { timeout = PARSE_TIMEOUT, parser = simpleParser } = {}) {
124
1329
  const input = Readable.from([finishable(unfoldHeaders(raw))], { objectMode: false, autoDestroy: false });
125
1330
  input.on("error", () => {
126
1331
  });
1332
+ const named = [];
127
1333
  const { pipe } = input;
128
1334
  input.pipe = function(parser2, options) {
129
1335
  parser2.splitter?.on("error", (error) => input.destroy(error));
1336
+ const { createNode } = parser2;
1337
+ if (typeof createNode === "function") {
1338
+ parser2.createNode = function(node) {
1339
+ const created = createNode.call(this, node);
1340
+ if (created?.isAttachment === false && node?.filename) {
1341
+ addFinding(named, { filename: String(node.filename), contentType: created.contentType, content: null });
1342
+ }
1343
+ for (const filename of repeatedNames(node)) {
1344
+ if (filename !== node?.filename) {
1345
+ addFinding(named, { filename, contentType: created?.contentType || "application/octet-stream", content: null });
1346
+ }
1347
+ }
1348
+ return created;
1349
+ };
1350
+ }
130
1351
  return pipe.call(this, parser2, options);
131
1352
  };
132
1353
  let timer;
133
1354
  try {
134
- return await Promise.race([
1355
+ const mail = await Promise.race([
135
1356
  parser(input, PARSER_OPTIONS),
136
1357
  new Promise((resolve, reject) => {
137
1358
  timer = setTimeout(() => {
@@ -141,14 +1362,25 @@ async function simpleParse(raw, { timeout = PARSE_TIMEOUT, parser = simpleParser
141
1362
  }, timeout);
142
1363
  })
143
1364
  ]);
1365
+ if (mail && typeof mail === "object") {
1366
+ let count = 0;
1367
+ for (const [, filename] of String(mail.text ?? "").matchAll(ENCODED_FILES)) {
1368
+ addFinding(named, { filename: filename.trim(), contentType: "application/octet-stream", content: null });
1369
+ if (++count >= MAX_ENCODED_FILES) {
1370
+ break;
1371
+ }
1372
+ }
1373
+ Object.defineProperty(mail, NAMED_TEXT, { value: named });
1374
+ }
1375
+ return mail;
144
1376
  } finally {
145
1377
  clearTimeout(timer);
146
1378
  input.destroy();
147
1379
  }
148
1380
  }
149
1381
  function finishable(raw) {
150
- const buffer = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
151
- return Buffer.concat([buffer, Buffer.from(buffer.at(-1) === 10 ? "\r\n\r\n" : "\r\n\r\n\r\n")]);
1382
+ const buffer = Buffer2.isBuffer(raw) ? raw : Buffer2.from(raw);
1383
+ return Buffer2.concat([buffer, Buffer2.from(buffer.at(-1) === 10 ? "\r\n\r\n" : "\r\n\r\n\r\n")]);
152
1384
  }
153
1385
  var MAX_FOLDS = 256;
154
1386
  function headerValue(line) {
@@ -156,18 +1388,18 @@ function headerValue(line) {
156
1388
  let key = null;
157
1389
  let inKey = false;
158
1390
  let quoted = false;
159
- let escaped = false;
1391
+ let escaped2 = false;
160
1392
  let value = "";
161
1393
  for (const chr of line.slice(line.indexOf(":") + 1).replaceAll(/\r?\n[ \t]*/g, " ")) {
162
1394
  if (inKey && chr === "=") {
163
1395
  key = value.trim().toLowerCase();
164
1396
  inKey = false;
165
1397
  value = "";
166
- } else if (inKey || escaped) {
1398
+ } else if (inKey || escaped2) {
167
1399
  value += chr;
168
- escaped = false;
1400
+ escaped2 = false;
169
1401
  } else if (chr === "\\") {
170
- escaped = true;
1402
+ escaped2 = true;
171
1403
  } else if (chr === '"') {
172
1404
  quoted = !quoted;
173
1405
  } else if (chr === ";" && !quoted) {
@@ -213,7 +1445,7 @@ function unfoldHeaders(raw) {
213
1445
  const type = first.get("content-type") ?? { value: "", boundary: "" };
214
1446
  const encoding = (first.get("content-transfer-encoding")?.value ?? "").replaceAll(/\(.*\)/g, "").trim();
215
1447
  if (blank && type.boundary) {
216
- boundaries.push(Buffer.from(type.boundary));
1448
+ boundaries.push(Buffer2.from(type.boundary));
217
1449
  }
218
1450
  head = blank && ["message/rfc822", "message/global"].includes(type.value) && ["", "7bit", "8bit", "binary"].includes(encoding) && first.get("content-disposition")?.value === "inline";
219
1451
  };
@@ -247,11 +1479,11 @@ function unfoldHeaders(raw) {
247
1479
  const chunks = [];
248
1480
  let copied = 0;
249
1481
  for (const field of unfold) {
250
- chunks.push(raw.subarray(copied, field.start), Buffer.from(raw.toString("latin1", field.start, field.end).replaceAll(/\r?\n[ \t]*/g, " "), "latin1"));
1482
+ chunks.push(raw.subarray(copied, field.start), Buffer2.from(raw.toString("latin1", field.start, field.end).replaceAll(/\r?\n[ \t]*/g, " "), "latin1"));
251
1483
  copied = field.end;
252
1484
  }
253
1485
  chunks.push(raw.subarray(copied));
254
- return Buffer.concat(chunks);
1486
+ return Buffer2.concat(chunks);
255
1487
  }
256
1488
 
257
1489
  // src/arf.js
@@ -311,7 +1543,7 @@ function parseReportingMta(value) {
311
1543
  }
312
1544
  function decodeQuotedPrintable(text) {
313
1545
  const soft = text.replaceAll(/=\r?\n/g, "");
314
- const bytes = Buffer2.allocUnsafe(soft.length);
1546
+ const bytes = Buffer3.allocUnsafe(soft.length);
315
1547
  let length = 0;
316
1548
  for (let i = 0; i < soft.length; i++) {
317
1549
  if (soft[i] === "=" && /^[\da-f]{2}$/i.test(soft.slice(i + 1, i + 3))) {
@@ -324,8 +1556,8 @@ function decodeQuotedPrintable(text) {
324
1556
  return bytes.subarray(0, length);
325
1557
  }
326
1558
  function findPart(raw, boundary, types) {
327
- const escaped = boundary.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
328
- const parts = raw.split(new RegExp(String.raw`\r?\n--${escaped}(?:--)?[ \t]*(?=\r?\n|$)`));
1559
+ const escaped2 = boundary.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
1560
+ const parts = raw.split(new RegExp(String.raw`\r?\n--${escaped2}(?:--)?[ \t]*(?=\r?\n|$)`));
329
1561
  for (const part of parts.slice(1)) {
330
1562
  const match = /^\r?\n((?:[^\r\n]+\r?\n)*)\r?\n([\s\S]*)$/.exec(part);
331
1563
  if (!match) {
@@ -339,11 +1571,11 @@ function findPart(raw, boundary, types) {
339
1571
  const encoding = (/^content-transfer-encoding:\s*(\S+)/im.exec(headers)?.[1] || "").toLowerCase();
340
1572
  let content;
341
1573
  if (encoding === "base64") {
342
- content = Buffer2.from(match[2], "base64");
1574
+ content = Buffer3.from(match[2], "base64");
343
1575
  } else if (encoding === "quoted-printable") {
344
1576
  content = decodeQuotedPrintable(match[2]);
345
1577
  } else {
346
- content = Buffer2.from(match[2], "latin1");
1578
+ content = Buffer3.from(match[2], "latin1");
347
1579
  }
348
1580
  return { type, content };
349
1581
  }
@@ -359,7 +1591,7 @@ function isArfMessage(parsed) {
359
1591
  return /^multipart\/report\b/i.test(String(value)) && type.toLowerCase() === "feedback-report";
360
1592
  }
361
1593
  async function parse(message) {
362
- const source = message instanceof Uint8Array && !Buffer2.isBuffer(message) ? Buffer2.from(message.buffer, message.byteOffset, message.byteLength) : message;
1594
+ const source = message instanceof Uint8Array && !Buffer3.isBuffer(message) ? Buffer3.from(message.buffer, message.byteOffset, message.byteLength) : message;
363
1595
  const parsed = await simpleParse(source);
364
1596
  if (!isArfMessage(parsed)) {
365
1597
  throw new Error("Not an ARF report: expected multipart/report with report-type=feedback-report");
@@ -404,7 +1636,7 @@ async function parse(message) {
404
1636
  originalHeaders: null,
405
1637
  rawFeedbackReport: raw
406
1638
  };
407
- const text = (Buffer2.isBuffer(source) ? source : Buffer2.from(String(source))).toString("latin1");
1639
+ const text = (Buffer3.isBuffer(source) ? source : Buffer3.from(String(source))).toString("latin1");
408
1640
  const { boundary } = parsed.headers.get("content-type").params;
409
1641
  const human = findPart(text, boundary, ["text/plain"]);
410
1642
  result.humanReadable = human ? human.content.toString("utf8").trim() || null : null;
@@ -504,9 +1736,9 @@ function create(options = {}) {
504
1736
  const tail = `\r
505
1737
  --${boundary}--\r
506
1738
  `;
507
- if (Buffer2.isBuffer(originalMessage)) {
1739
+ if (Buffer3.isBuffer(originalMessage)) {
508
1740
  const end = originalMessage.at(-1) === 10 ? originalMessage.at(-2) === 13 ? 2 : 1 : 0;
509
- return Buffer2.concat([Buffer2.from(head), originalMessage.subarray(0, originalMessage.length - end), Buffer2.from(tail)]);
1741
+ return Buffer3.concat([Buffer3.from(head), originalMessage.subarray(0, originalMessage.length - end), Buffer3.from(tail)]);
510
1742
  }
511
1743
  return head + String(originalMessage).replace(/\r?\n$/, "") + tail;
512
1744
  }
@@ -517,14 +1749,14 @@ function encodeWords(text) {
517
1749
  const words = [];
518
1750
  let word = "";
519
1751
  for (const character of text) {
520
- if (Buffer2.byteLength(word + character) > 45) {
1752
+ if (Buffer3.byteLength(word + character) > 45) {
521
1753
  words.push(word);
522
1754
  word = "";
523
1755
  }
524
1756
  word += character;
525
1757
  }
526
1758
  words.push(word);
527
- return words.map((part) => `=?UTF-8?B?${Buffer2.from(part).toString("base64")}?=`).join("\r\n ");
1759
+ return words.map((part) => `=?UTF-8?B?${Buffer3.from(part).toString("base64")}?=`).join("\r\n ");
528
1760
  }
529
1761
  var ArfParser = {
530
1762
  isArfMessage,