spamscanner 7.0.10 → 7.0.11

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/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import process4 from "node:process";
5
5
 
6
6
  // src/cli.js
7
- import { Buffer as Buffer14 } from "node:buffer";
7
+ import { Buffer as Buffer15 } from "node:buffer";
8
8
  import { spawn } from "node:child_process";
9
9
  import {
10
10
  createReadStream as createReadStream2,
@@ -1730,103 +1730,285 @@ var HomographDetector = class {
1730
1730
  }
1731
1731
  };
1732
1732
 
1733
+ // src/entities.js
1734
+ var NAMED = [
1735
+ "AElig=c6,AMP=26,Aacute=c1,Abreve=102,Acirc=c2,Acy=410,Afr=1d504,Agrave=c0,Alpha=391,Amacr=100,And=2a",
1736
+ "53,Aogon=104,Aopf=1d538,ApplyFunction=2061,Aring=c5,Ascr=1d49c,Assign=2254,Atilde=c3,Auml=c4,Backsla",
1737
+ "sh=2216,Barv=2ae7,Barwed=2306,Bcy=411,Because=2235,Bernoullis=212c,Beta=392,Bfr=1d505,Bopf=1d539,Bre",
1738
+ "ve=2d8,Bscr=212c,Bumpeq=224e,CHcy=427,COPY=a9,Cacute=106,Cap=22d2,CapitalDifferentialD=2145,Cayleys=",
1739
+ "212d,Ccaron=10c,Ccedil=c7,Ccirc=108,Cconint=2230,Cdot=10a,Cedilla=b8,CenterDot=b7,Cfr=212d,Chi=3a7,C",
1740
+ "ircleDot=2299,CircleMinus=2296,CirclePlus=2295,CircleTimes=2297,ClockwiseContourIntegral=2232,CloseC",
1741
+ "urlyDoubleQuote=201d,CloseCurlyQuote=2019,Colon=2237,Colone=2a74,Congruent=2261,Conint=222f,ContourI",
1742
+ "ntegral=222e,Copf=2102,Coproduct=2210,CounterClockwiseContourIntegral=2233,Cross=2a2f,Cscr=1d49e,Cup",
1743
+ "=22d3,CupCap=224d,DD=2145,DDotrahd=2911,DJcy=402,DScy=405,DZcy=40f,Dagger=2021,Darr=21a1,Dashv=2ae4,",
1744
+ "Dcaron=10e,Dcy=414,Del=2207,Delta=394,Dfr=1d507,DiacriticalAcute=b4,DiacriticalDot=2d9,DiacriticalDo",
1745
+ "ubleAcute=2dd,DiacriticalGrave=60,DiacriticalTilde=2dc,Diamond=22c4,DifferentialD=2146,Dopf=1d53b,Do",
1746
+ "t=a8,DotDot=20dc,DotEqual=2250,DoubleContourIntegral=222f,DoubleDot=a8,DoubleDownArrow=21d3,DoubleLe",
1747
+ "ftArrow=21d0,DoubleLeftRightArrow=21d4,DoubleLeftTee=2ae4,DoubleLongLeftArrow=27f8,DoubleLongLeftRig",
1748
+ "htArrow=27fa,DoubleLongRightArrow=27f9,DoubleRightArrow=21d2,DoubleRightTee=22a8,DoubleUpArrow=21d1,",
1749
+ "DoubleUpDownArrow=21d5,DoubleVerticalBar=2225,DownArrow=2193,DownArrowBar=2913,DownArrowUpArrow=21f5",
1750
+ ",DownBreve=311,DownLeftRightVector=2950,DownLeftTeeVector=295e,DownLeftVector=21bd,DownLeftVectorBar",
1751
+ "=2956,DownRightTeeVector=295f,DownRightVector=21c1,DownRightVectorBar=2957,DownTee=22a4,DownTeeArrow",
1752
+ "=21a7,Downarrow=21d3,Dscr=1d49f,Dstrok=110,ENG=14a,ETH=d0,Eacute=c9,Ecaron=11a,Ecirc=ca,Ecy=42d,Edot",
1753
+ "=116,Efr=1d508,Egrave=c8,Element=2208,Emacr=112,EmptySmallSquare=25fb,EmptyVerySmallSquare=25ab,Eogo",
1754
+ "n=118,Eopf=1d53c,Epsilon=395,Equal=2a75,EqualTilde=2242,Equilibrium=21cc,Escr=2130,Esim=2a73,Eta=397",
1755
+ ",Euml=cb,Exists=2203,ExponentialE=2147,Fcy=424,Ffr=1d509,FilledSmallSquare=25fc,FilledVerySmallSquar",
1756
+ "e=25aa,Fopf=1d53d,ForAll=2200,Fouriertrf=2131,Fscr=2131,GJcy=403,GT=3e,Gamma=393,Gammad=3dc,Gbreve=1",
1757
+ "1e,Gcedil=122,Gcirc=11c,Gcy=413,Gdot=120,Gfr=1d50a,Gg=22d9,Gopf=1d53e,GreaterEqual=2265,GreaterEqual",
1758
+ "Less=22db,GreaterFullEqual=2267,GreaterGreater=2aa2,GreaterLess=2277,GreaterSlantEqual=2a7e,GreaterT",
1759
+ "ilde=2273,Gscr=1d4a2,Gt=226b,HARDcy=42a,Hacek=2c7,Hat=5e,Hcirc=124,Hfr=210c,HilbertSpace=210b,Hopf=2",
1760
+ "10d,HorizontalLine=2500,Hscr=210b,Hstrok=126,HumpDownHump=224e,HumpEqual=224f,IEcy=415,IJlig=132,IOc",
1761
+ "y=401,Iacute=cd,Icirc=ce,Icy=418,Idot=130,Ifr=2111,Igrave=cc,Im=2111,Imacr=12a,ImaginaryI=2148,Impli",
1762
+ "es=21d2,Int=222c,Integral=222b,Intersection=22c2,InvisibleComma=2063,InvisibleTimes=2062,Iogon=12e,I",
1763
+ "opf=1d540,Iota=399,Iscr=2110,Itilde=128,Iukcy=406,Iuml=cf,Jcirc=134,Jcy=419,Jfr=1d50d,Jopf=1d541,Jsc",
1764
+ "r=1d4a5,Jsercy=408,Jukcy=404,KHcy=425,KJcy=40c,Kappa=39a,Kcedil=136,Kcy=41a,Kfr=1d50e,Kopf=1d542,Ksc",
1765
+ "r=1d4a6,LJcy=409,LT=3c,Lacute=139,Lambda=39b,Lang=27ea,Laplacetrf=2112,Larr=219e,Lcaron=13d,Lcedil=1",
1766
+ "3b,Lcy=41b,LeftAngleBracket=27e8,LeftArrow=2190,LeftArrowBar=21e4,LeftArrowRightArrow=21c6,LeftCeili",
1767
+ "ng=2308,LeftDoubleBracket=27e6,LeftDownTeeVector=2961,LeftDownVector=21c3,LeftDownVectorBar=2959,Lef",
1768
+ "tFloor=230a,LeftRightArrow=2194,LeftRightVector=294e,LeftTee=22a3,LeftTeeArrow=21a4,LeftTeeVector=29",
1769
+ "5a,LeftTriangle=22b2,LeftTriangleBar=29cf,LeftTriangleEqual=22b4,LeftUpDownVector=2951,LeftUpTeeVect",
1770
+ "or=2960,LeftUpVector=21bf,LeftUpVectorBar=2958,LeftVector=21bc,LeftVectorBar=2952,Leftarrow=21d0,Lef",
1771
+ "trightarrow=21d4,LessEqualGreater=22da,LessFullEqual=2266,LessGreater=2276,LessLess=2aa1,LessSlantEq",
1772
+ "ual=2a7d,LessTilde=2272,Lfr=1d50f,Ll=22d8,Lleftarrow=21da,Lmidot=13f,LongLeftArrow=27f5,LongLeftRigh",
1773
+ "tArrow=27f7,LongRightArrow=27f6,Longleftarrow=27f8,Longleftrightarrow=27fa,Longrightarrow=27f9,Lopf=",
1774
+ "1d543,LowerLeftArrow=2199,LowerRightArrow=2198,Lscr=2112,Lsh=21b0,Lstrok=141,Lt=226a,Map=2905,Mcy=41",
1775
+ "c,MediumSpace=205f,Mellintrf=2133,Mfr=1d510,MinusPlus=2213,Mopf=1d544,Mscr=2133,Mu=39c,NJcy=40a,Nacu",
1776
+ "te=143,Ncaron=147,Ncedil=145,Ncy=41d,NegativeMediumSpace=200b,NegativeThickSpace=200b,NegativeThinSp",
1777
+ "ace=200b,NegativeVeryThinSpace=200b,NestedGreaterGreater=226b,NestedLessLess=226a,NewLine=a,Nfr=1d51",
1778
+ "1,NoBreak=2060,NonBreakingSpace=a0,Nopf=2115,Not=2aec,NotCongruent=2262,NotCupCap=226d,NotDoubleVert",
1779
+ "icalBar=2226,NotElement=2209,NotEqual=2260,NotEqualTilde=2242.338,NotExists=2204,NotGreater=226f,Not",
1780
+ "GreaterEqual=2271,NotGreaterFullEqual=2267.338,NotGreaterGreater=226b.338,NotGreaterLess=2279,NotGre",
1781
+ "aterSlantEqual=2a7e.338,NotGreaterTilde=2275,NotHumpDownHump=224e.338,NotHumpEqual=224f.338,NotLeftT",
1782
+ "riangle=22ea,NotLeftTriangleBar=29cf.338,NotLeftTriangleEqual=22ec,NotLess=226e,NotLessEqual=2270,No",
1783
+ "tLessGreater=2278,NotLessLess=226a.338,NotLessSlantEqual=2a7d.338,NotLessTilde=2274,NotNestedGreater",
1784
+ "Greater=2aa2.338,NotNestedLessLess=2aa1.338,NotPrecedes=2280,NotPrecedesEqual=2aaf.338,NotPrecedesSl",
1785
+ "antEqual=22e0,NotReverseElement=220c,NotRightTriangle=22eb,NotRightTriangleBar=29d0.338,NotRightTria",
1786
+ "ngleEqual=22ed,NotSquareSubset=228f.338,NotSquareSubsetEqual=22e2,NotSquareSuperset=2290.338,NotSqua",
1787
+ "reSupersetEqual=22e3,NotSubset=2282.20d2,NotSubsetEqual=2288,NotSucceeds=2281,NotSucceedsEqual=2ab0.",
1788
+ "338,NotSucceedsSlantEqual=22e1,NotSucceedsTilde=227f.338,NotSuperset=2283.20d2,NotSupersetEqual=2289",
1789
+ ",NotTilde=2241,NotTildeEqual=2244,NotTildeFullEqual=2247,NotTildeTilde=2249,NotVerticalBar=2224,Nscr",
1790
+ "=1d4a9,Ntilde=d1,Nu=39d,OElig=152,Oacute=d3,Ocirc=d4,Ocy=41e,Odblac=150,Ofr=1d512,Ograve=d2,Omacr=14",
1791
+ "c,Omega=3a9,Omicron=39f,Oopf=1d546,OpenCurlyDoubleQuote=201c,OpenCurlyQuote=2018,Or=2a54,Oscr=1d4aa,",
1792
+ "Oslash=d8,Otilde=d5,Otimes=2a37,Ouml=d6,OverBar=203e,OverBrace=23de,OverBracket=23b4,OverParenthesis",
1793
+ "=23dc,PartialD=2202,Pcy=41f,Pfr=1d513,Phi=3a6,Pi=3a0,PlusMinus=b1,Poincareplane=210c,Popf=2119,Pr=2a",
1794
+ "bb,Precedes=227a,PrecedesEqual=2aaf,PrecedesSlantEqual=227c,PrecedesTilde=227e,Prime=2033,Product=22",
1795
+ "0f,Proportion=2237,Proportional=221d,Pscr=1d4ab,Psi=3a8,QUOT=22,Qfr=1d514,Qopf=211a,Qscr=1d4ac,RBarr",
1796
+ "=2910,REG=ae,Racute=154,Rang=27eb,Rarr=21a0,Rarrtl=2916,Rcaron=158,Rcedil=156,Rcy=420,Re=211c,Revers",
1797
+ "eElement=220b,ReverseEquilibrium=21cb,ReverseUpEquilibrium=296f,Rfr=211c,Rho=3a1,RightAngleBracket=2",
1798
+ "7e9,RightArrow=2192,RightArrowBar=21e5,RightArrowLeftArrow=21c4,RightCeiling=2309,RightDoubleBracket",
1799
+ "=27e7,RightDownTeeVector=295d,RightDownVector=21c2,RightDownVectorBar=2955,RightFloor=230b,RightTee=",
1800
+ "22a2,RightTeeArrow=21a6,RightTeeVector=295b,RightTriangle=22b3,RightTriangleBar=29d0,RightTriangleEq",
1801
+ "ual=22b5,RightUpDownVector=294f,RightUpTeeVector=295c,RightUpVector=21be,RightUpVectorBar=2954,Right",
1802
+ "Vector=21c0,RightVectorBar=2953,Rightarrow=21d2,Ropf=211d,RoundImplies=2970,Rrightarrow=21db,Rscr=21",
1803
+ "1b,Rsh=21b1,RuleDelayed=29f4,SHCHcy=429,SHcy=428,SOFTcy=42c,Sacute=15a,Sc=2abc,Scaron=160,Scedil=15e",
1804
+ ",Scirc=15c,Scy=421,Sfr=1d516,ShortDownArrow=2193,ShortLeftArrow=2190,ShortRightArrow=2192,ShortUpArr",
1805
+ "ow=2191,Sigma=3a3,SmallCircle=2218,Sopf=1d54a,Sqrt=221a,Square=25a1,SquareIntersection=2293,SquareSu",
1806
+ "bset=228f,SquareSubsetEqual=2291,SquareSuperset=2290,SquareSupersetEqual=2292,SquareUnion=2294,Sscr=",
1807
+ "1d4ae,Star=22c6,Sub=22d0,Subset=22d0,SubsetEqual=2286,Succeeds=227b,SucceedsEqual=2ab0,SucceedsSlant",
1808
+ "Equal=227d,SucceedsTilde=227f,SuchThat=220b,Sum=2211,Sup=22d1,Superset=2283,SupersetEqual=2287,Supse",
1809
+ "t=22d1,THORN=de,TRADE=2122,TSHcy=40b,TScy=426,Tab=9,Tau=3a4,Tcaron=164,Tcedil=162,Tcy=422,Tfr=1d517,",
1810
+ "Therefore=2234,Theta=398,ThickSpace=205f.200a,ThinSpace=2009,Tilde=223c,TildeEqual=2243,TildeFullEqu",
1811
+ "al=2245,TildeTilde=2248,Topf=1d54b,TripleDot=20db,Tscr=1d4af,Tstrok=166,Uacute=da,Uarr=219f,Uarrocir",
1812
+ "=2949,Ubrcy=40e,Ubreve=16c,Ucirc=db,Ucy=423,Udblac=170,Ufr=1d518,Ugrave=d9,Umacr=16a,UnderBar=5f,Und",
1813
+ "erBrace=23df,UnderBracket=23b5,UnderParenthesis=23dd,Union=22c3,UnionPlus=228e,Uogon=172,Uopf=1d54c,",
1814
+ "UpArrow=2191,UpArrowBar=2912,UpArrowDownArrow=21c5,UpDownArrow=2195,UpEquilibrium=296e,UpTee=22a5,Up",
1815
+ "TeeArrow=21a5,Uparrow=21d1,Updownarrow=21d5,UpperLeftArrow=2196,UpperRightArrow=2197,Upsi=3d2,Upsilo",
1816
+ "n=3a5,Uring=16e,Uscr=1d4b0,Utilde=168,Uuml=dc,VDash=22ab,Vbar=2aeb,Vcy=412,Vdash=22a9,Vdashl=2ae6,Ve",
1817
+ "e=22c1,Verbar=2016,Vert=2016,VerticalBar=2223,VerticalLine=7c,VerticalSeparator=2758,VerticalTilde=2",
1818
+ "240,VeryThinSpace=200a,Vfr=1d519,Vopf=1d54d,Vscr=1d4b1,Vvdash=22aa,Wcirc=174,Wedge=22c0,Wfr=1d51a,Wo",
1819
+ "pf=1d54e,Wscr=1d4b2,Xfr=1d51b,Xi=39e,Xopf=1d54f,Xscr=1d4b3,YAcy=42f,YIcy=407,YUcy=42e,Yacute=dd,Ycir",
1820
+ "c=176,Ycy=42b,Yfr=1d51c,Yopf=1d550,Yscr=1d4b4,Yuml=178,ZHcy=416,Zacute=179,Zcaron=17d,Zcy=417,Zdot=1",
1821
+ "7b,ZeroWidthSpace=200b,Zeta=396,Zfr=2128,Zopf=2124,Zscr=1d4b5,aacute=e1,abreve=103,ac=223e,acE=223e.",
1822
+ "333,acd=223f,acirc=e2,acute=b4,acy=430,aelig=e6,af=2061,afr=1d51e,agrave=e0,alefsym=2135,aleph=2135,",
1823
+ "alpha=3b1,amacr=101,amalg=2a3f,amp=26,and=2227,andand=2a55,andd=2a5c,andslope=2a58,andv=2a5a,ang=222",
1824
+ "0,ange=29a4,angle=2220,angmsd=2221,angmsdaa=29a8,angmsdab=29a9,angmsdac=29aa,angmsdad=29ab,angmsdae=",
1825
+ "29ac,angmsdaf=29ad,angmsdag=29ae,angmsdah=29af,angrt=221f,angrtvb=22be,angrtvbd=299d,angsph=2222,ang",
1826
+ "st=c5,angzarr=237c,aogon=105,aopf=1d552,ap=2248,apE=2a70,apacir=2a6f,ape=224a,apid=224b,apos=27,appr",
1827
+ "ox=2248,approxeq=224a,aring=e5,ascr=1d4b6,ast=2a,asymp=2248,asympeq=224d,atilde=e3,auml=e4,awconint=",
1828
+ "2233,awint=2a11,bNot=2aed,backcong=224c,backepsilon=3f6,backprime=2035,backsim=223d,backsimeq=22cd,b",
1829
+ "arvee=22bd,barwed=2305,barwedge=2305,bbrk=23b5,bbrktbrk=23b6,bcong=224c,bcy=431,bdquo=201e,becaus=22",
1830
+ "35,because=2235,bemptyv=29b0,bepsi=3f6,bernou=212c,beta=3b2,beth=2136,between=226c,bfr=1d51f,bigcap=",
1831
+ "22c2,bigcirc=25ef,bigcup=22c3,bigodot=2a00,bigoplus=2a01,bigotimes=2a02,bigsqcup=2a06,bigstar=2605,b",
1832
+ "igtriangledown=25bd,bigtriangleup=25b3,biguplus=2a04,bigvee=22c1,bigwedge=22c0,bkarow=290d,blackloze",
1833
+ "nge=29eb,blacksquare=25aa,blacktriangle=25b4,blacktriangledown=25be,blacktriangleleft=25c2,blacktria",
1834
+ "ngleright=25b8,blank=2423,blk12=2592,blk14=2591,blk34=2593,block=2588,bne=3d.20e5,bnequiv=2261.20e5,",
1835
+ "bnot=2310,bopf=1d553,bot=22a5,bottom=22a5,bowtie=22c8,boxDL=2557,boxDR=2554,boxDl=2556,boxDr=2553,bo",
1836
+ "xH=2550,boxHD=2566,boxHU=2569,boxHd=2564,boxHu=2567,boxUL=255d,boxUR=255a,boxUl=255c,boxUr=2559,boxV",
1837
+ "=2551,boxVH=256c,boxVL=2563,boxVR=2560,boxVh=256b,boxVl=2562,boxVr=255f,boxbox=29c9,boxdL=2555,boxdR",
1838
+ "=2552,boxdl=2510,boxdr=250c,boxh=2500,boxhD=2565,boxhU=2568,boxhd=252c,boxhu=2534,boxminus=229f,boxp",
1839
+ "lus=229e,boxtimes=22a0,boxuL=255b,boxuR=2558,boxul=2518,boxur=2514,boxv=2502,boxvH=256a,boxvL=2561,b",
1840
+ "oxvR=255e,boxvh=253c,boxvl=2524,boxvr=251c,bprime=2035,breve=2d8,brvbar=a6,bscr=1d4b7,bsemi=204f,bsi",
1841
+ "m=223d,bsime=22cd,bsol=5c,bsolb=29c5,bsolhsub=27c8,bull=2022,bullet=2022,bump=224e,bumpE=2aae,bumpe=",
1842
+ "224f,bumpeq=224f,cacute=107,cap=2229,capand=2a44,capbrcup=2a49,capcap=2a4b,capcup=2a47,capdot=2a40,c",
1843
+ "aps=2229.fe00,caret=2041,caron=2c7,ccaps=2a4d,ccaron=10d,ccedil=e7,ccirc=109,ccups=2a4c,ccupssm=2a50",
1844
+ ",cdot=10b,cedil=b8,cemptyv=29b2,cent=a2,centerdot=b7,cfr=1d520,chcy=447,check=2713,checkmark=2713,ch",
1845
+ "i=3c7,cir=25cb,cirE=29c3,circ=2c6,circeq=2257,circlearrowleft=21ba,circlearrowright=21bb,circledR=ae",
1846
+ ",circledS=24c8,circledast=229b,circledcirc=229a,circleddash=229d,cire=2257,cirfnint=2a10,cirmid=2aef",
1847
+ ",cirscir=29c2,clubs=2663,clubsuit=2663,colon=3a,colone=2254,coloneq=2254,comma=2c,commat=40,comp=220",
1848
+ "1,compfn=2218,complement=2201,complexes=2102,cong=2245,congdot=2a6d,conint=222e,copf=1d554,coprod=22",
1849
+ "10,copy=a9,copysr=2117,crarr=21b5,cross=2717,cscr=1d4b8,csub=2acf,csube=2ad1,csup=2ad0,csupe=2ad2,ct",
1850
+ "dot=22ef,cudarrl=2938,cudarrr=2935,cuepr=22de,cuesc=22df,cularr=21b6,cularrp=293d,cup=222a,cupbrcap=",
1851
+ "2a48,cupcap=2a46,cupcup=2a4a,cupdot=228d,cupor=2a45,cups=222a.fe00,curarr=21b7,curarrm=293c,curlyeqp",
1852
+ "rec=22de,curlyeqsucc=22df,curlyvee=22ce,curlywedge=22cf,curren=a4,curvearrowleft=21b6,curvearrowrigh",
1853
+ "t=21b7,cuvee=22ce,cuwed=22cf,cwconint=2232,cwint=2231,cylcty=232d,dArr=21d3,dHar=2965,dagger=2020,da",
1854
+ "leth=2138,darr=2193,dash=2010,dashv=22a3,dbkarow=290f,dblac=2dd,dcaron=10f,dcy=434,dd=2146,ddagger=2",
1855
+ "021,ddarr=21ca,ddotseq=2a77,deg=b0,delta=3b4,demptyv=29b1,dfisht=297f,dfr=1d521,dharl=21c3,dharr=21c",
1856
+ "2,diam=22c4,diamond=22c4,diamondsuit=2666,diams=2666,die=a8,digamma=3dd,disin=22f2,div=f7,divide=f7,",
1857
+ "divideontimes=22c7,divonx=22c7,djcy=452,dlcorn=231e,dlcrop=230d,dollar=24,dopf=1d555,dot=2d9,doteq=2",
1858
+ "250,doteqdot=2251,dotminus=2238,dotplus=2214,dotsquare=22a1,doublebarwedge=2306,downarrow=2193,downd",
1859
+ "ownarrows=21ca,downharpoonleft=21c3,downharpoonright=21c2,drbkarow=2910,drcorn=231f,drcrop=230c,dscr",
1860
+ "=1d4b9,dscy=455,dsol=29f6,dstrok=111,dtdot=22f1,dtri=25bf,dtrif=25be,duarr=21f5,duhar=296f,dwangle=2",
1861
+ "9a6,dzcy=45f,dzigrarr=27ff,eDDot=2a77,eDot=2251,eacute=e9,easter=2a6e,ecaron=11b,ecir=2256,ecirc=ea,",
1862
+ "ecolon=2255,ecy=44d,edot=117,ee=2147,efDot=2252,efr=1d522,eg=2a9a,egrave=e8,egs=2a96,egsdot=2a98,el=",
1863
+ "2a99,elinters=23e7,ell=2113,els=2a95,elsdot=2a97,emacr=113,empty=2205,emptyset=2205,emptyv=2205,emsp",
1864
+ "=2003,emsp13=2004,emsp14=2005,eng=14b,ensp=2002,eogon=119,eopf=1d556,epar=22d5,eparsl=29e3,eplus=2a7",
1865
+ "1,epsi=3b5,epsilon=3b5,epsiv=3f5,eqcirc=2256,eqcolon=2255,eqsim=2242,eqslantgtr=2a96,eqslantless=2a9",
1866
+ "5,equals=3d,equest=225f,equiv=2261,equivDD=2a78,eqvparsl=29e5,erDot=2253,erarr=2971,escr=212f,esdot=",
1867
+ "2250,esim=2242,eta=3b7,eth=f0,euml=eb,euro=20ac,excl=21,exist=2203,expectation=2130,exponentiale=214",
1868
+ "7,fallingdotseq=2252,fcy=444,female=2640,ffilig=fb03,fflig=fb00,ffllig=fb04,ffr=1d523,filig=fb01,fjl",
1869
+ "ig=66.6a,flat=266d,fllig=fb02,fltns=25b1,fnof=192,fopf=1d557,forall=2200,fork=22d4,forkv=2ad9,fparti",
1870
+ "nt=2a0d,frac12=bd,frac13=2153,frac14=bc,frac15=2155,frac16=2159,frac18=215b,frac23=2154,frac25=2156,",
1871
+ "frac34=be,frac35=2157,frac38=215c,frac45=2158,frac56=215a,frac58=215d,frac78=215e,frasl=2044,frown=2",
1872
+ "322,fscr=1d4bb,gE=2267,gEl=2a8c,gacute=1f5,gamma=3b3,gammad=3dd,gap=2a86,gbreve=11f,gcirc=11d,gcy=43",
1873
+ "3,gdot=121,ge=2265,gel=22db,geq=2265,geqq=2267,geqslant=2a7e,ges=2a7e,gescc=2aa9,gesdot=2a80,gesdoto",
1874
+ "=2a82,gesdotol=2a84,gesl=22db.fe00,gesles=2a94,gfr=1d524,gg=226b,ggg=22d9,gimel=2137,gjcy=453,gl=227",
1875
+ "7,glE=2a92,gla=2aa5,glj=2aa4,gnE=2269,gnap=2a8a,gnapprox=2a8a,gne=2a88,gneq=2a88,gneqq=2269,gnsim=22",
1876
+ "e7,gopf=1d558,grave=60,gscr=210a,gsim=2273,gsime=2a8e,gsiml=2a90,gt=3e,gtcc=2aa7,gtcir=2a7a,gtdot=22",
1877
+ "d7,gtlPar=2995,gtquest=2a7c,gtrapprox=2a86,gtrarr=2978,gtrdot=22d7,gtreqless=22db,gtreqqless=2a8c,gt",
1878
+ "rless=2277,gtrsim=2273,gvertneqq=2269.fe00,gvnE=2269.fe00,hArr=21d4,hairsp=200a,half=bd,hamilt=210b,",
1879
+ "hardcy=44a,harr=2194,harrcir=2948,harrw=21ad,hbar=210f,hcirc=125,hearts=2665,heartsuit=2665,hellip=2",
1880
+ "026,hercon=22b9,hfr=1d525,hksearow=2925,hkswarow=2926,hoarr=21ff,homtht=223b,hookleftarrow=21a9,hook",
1881
+ "rightarrow=21aa,hopf=1d559,horbar=2015,hscr=1d4bd,hslash=210f,hstrok=127,hybull=2043,hyphen=2010,iac",
1882
+ "ute=ed,ic=2063,icirc=ee,icy=438,iecy=435,iexcl=a1,iff=21d4,ifr=1d526,igrave=ec,ii=2148,iiiint=2a0c,i",
1883
+ "iint=222d,iinfin=29dc,iiota=2129,ijlig=133,imacr=12b,image=2111,imagline=2110,imagpart=2111,imath=13",
1884
+ "1,imof=22b7,imped=1b5,in=2208,incare=2105,infin=221e,infintie=29dd,inodot=131,int=222b,intcal=22ba,i",
1885
+ "ntegers=2124,intercal=22ba,intlarhk=2a17,intprod=2a3c,iocy=451,iogon=12f,iopf=1d55a,iota=3b9,iprod=2",
1886
+ "a3c,iquest=bf,iscr=1d4be,isin=2208,isinE=22f9,isindot=22f5,isins=22f4,isinsv=22f3,isinv=2208,it=2062",
1887
+ ",itilde=129,iukcy=456,iuml=ef,jcirc=135,jcy=439,jfr=1d527,jmath=237,jopf=1d55b,jscr=1d4bf,jsercy=458",
1888
+ ",jukcy=454,kappa=3ba,kappav=3f0,kcedil=137,kcy=43a,kfr=1d528,kgreen=138,khcy=445,kjcy=45c,kopf=1d55c",
1889
+ ",kscr=1d4c0,lAarr=21da,lArr=21d0,lAtail=291b,lBarr=290e,lE=2266,lEg=2a8b,lHar=2962,lacute=13a,laempt",
1890
+ "yv=29b4,lagran=2112,lambda=3bb,lang=2329,langd=2991,langle=27e8,lap=2a85,laquo=ab,larr=2190,larrb=21",
1891
+ "e4,larrbfs=291f,larrfs=291d,larrhk=21a9,larrlp=21ab,larrpl=2939,larrsim=2973,larrtl=21a2,lat=2aab,la",
1892
+ "tail=2919,late=2aad,lates=2aad.fe00,lbarr=290c,lbbrk=2772,lbrace=7b,lbrack=5b,lbrke=298b,lbrksld=298",
1893
+ "f,lbrkslu=298d,lcaron=13e,lcedil=13c,lceil=2308,lcub=7b,lcy=43b,ldca=2936,ldquo=201c,ldquor=201e,ldr",
1894
+ "dhar=2967,ldrushar=294b,ldsh=21b2,le=2264,leftarrow=2190,leftarrowtail=21a2,leftharpoondown=21bd,lef",
1895
+ "tharpoonup=21bc,leftleftarrows=21c7,leftrightarrow=2194,leftrightarrows=21c6,leftrightharpoons=21cb,",
1896
+ "leftrightsquigarrow=21ad,leftthreetimes=22cb,leg=22da,leq=2264,leqq=2266,leqslant=2a7d,les=2a7d,lesc",
1897
+ "c=2aa8,lesdot=2a7f,lesdoto=2a81,lesdotor=2a83,lesg=22da.fe00,lesges=2a93,lessapprox=2a85,lessdot=22d",
1898
+ "6,lesseqgtr=22da,lesseqqgtr=2a8b,lessgtr=2276,lesssim=2272,lfisht=297c,lfloor=230a,lfr=1d529,lg=2276",
1899
+ ",lgE=2a91,lhard=21bd,lharu=21bc,lharul=296a,lhblk=2584,ljcy=459,ll=226a,llarr=21c7,llcorner=231e,llh",
1900
+ "ard=296b,lltri=25fa,lmidot=140,lmoust=23b0,lmoustache=23b0,lnE=2268,lnap=2a89,lnapprox=2a89,lne=2a87",
1901
+ ",lneq=2a87,lneqq=2268,lnsim=22e6,loang=27ec,loarr=21fd,lobrk=27e6,longleftarrow=27f5,longleftrightar",
1902
+ "row=27f7,longmapsto=27fc,longrightarrow=27f6,looparrowleft=21ab,looparrowright=21ac,lopar=2985,lopf=",
1903
+ "1d55d,loplus=2a2d,lotimes=2a34,lowast=2217,lowbar=5f,loz=25ca,lozenge=25ca,lozf=29eb,lpar=28,lparlt=",
1904
+ "2993,lrarr=21c6,lrcorner=231f,lrhar=21cb,lrhard=296d,lrm=200e,lrtri=22bf,lsaquo=2039,lscr=1d4c1,lsh=",
1905
+ "21b0,lsim=2272,lsime=2a8d,lsimg=2a8f,lsqb=5b,lsquo=2018,lsquor=201a,lstrok=142,lt=3c,ltcc=2aa6,ltcir",
1906
+ "=2a79,ltdot=22d6,lthree=22cb,ltimes=22c9,ltlarr=2976,ltquest=2a7b,ltrPar=2996,ltri=25c3,ltrie=22b4,l",
1907
+ "trif=25c2,lurdshar=294a,luruhar=2966,lvertneqq=2268.fe00,lvnE=2268.fe00,mDDot=223a,macr=af,male=2642",
1908
+ ",malt=2720,maltese=2720,map=21a6,mapsto=21a6,mapstodown=21a7,mapstoleft=21a4,mapstoup=21a5,marker=25",
1909
+ "ae,mcomma=2a29,mcy=43c,mdash=2014,measuredangle=2221,mfr=1d52a,mho=2127,micro=b5,mid=2223,midast=2a,",
1910
+ "midcir=2af0,middot=b7,minus=2212,minusb=229f,minusd=2238,minusdu=2a2a,mlcp=2adb,mldr=2026,mnplus=221",
1911
+ "3,models=22a7,mopf=1d55e,mp=2213,mscr=1d4c2,mstpos=223e,mu=3bc,multimap=22b8,mumap=22b8,nGg=22d9.338",
1912
+ ",nGt=226b.20d2,nGtv=226b.338,nLeftarrow=21cd,nLeftrightarrow=21ce,nLl=22d8.338,nLt=226a.20d2,nLtv=22",
1913
+ "6a.338,nRightarrow=21cf,nVDash=22af,nVdash=22ae,nabla=2207,nacute=144,nang=2220.20d2,nap=2249,napE=2",
1914
+ "a70.338,napid=224b.338,napos=149,napprox=2249,natur=266e,natural=266e,naturals=2115,nbsp=a0,nbump=22",
1915
+ "4e.338,nbumpe=224f.338,ncap=2a43,ncaron=148,ncedil=146,ncong=2247,ncongdot=2a6d.338,ncup=2a42,ncy=43",
1916
+ "d,ndash=2013,ne=2260,neArr=21d7,nearhk=2924,nearr=2197,nearrow=2197,nedot=2250.338,nequiv=2262,nesea",
1917
+ "r=2928,nesim=2242.338,nexist=2204,nexists=2204,nfr=1d52b,ngE=2267.338,nge=2271,ngeq=2271,ngeqq=2267.",
1918
+ "338,ngeqslant=2a7e.338,nges=2a7e.338,ngsim=2275,ngt=226f,ngtr=226f,nhArr=21ce,nharr=21ae,nhpar=2af2,",
1919
+ "ni=220b,nis=22fc,nisd=22fa,niv=220b,njcy=45a,nlArr=21cd,nlE=2266.338,nlarr=219a,nldr=2025,nle=2270,n",
1920
+ "leftarrow=219a,nleftrightarrow=21ae,nleq=2270,nleqq=2266.338,nleqslant=2a7d.338,nles=2a7d.338,nless=",
1921
+ "226e,nlsim=2274,nlt=226e,nltri=22ea,nltrie=22ec,nmid=2224,nopf=1d55f,not=ac,notin=2209,notinE=22f9.3",
1922
+ "38,notindot=22f5.338,notinva=2209,notinvb=22f7,notinvc=22f6,notni=220c,notniva=220c,notnivb=22fe,not",
1923
+ "nivc=22fd,npar=2226,nparallel=2226,nparsl=2afd.20e5,npart=2202.338,npolint=2a14,npr=2280,nprcue=22e0",
1924
+ ",npre=2aaf.338,nprec=2280,npreceq=2aaf.338,nrArr=21cf,nrarr=219b,nrarrc=2933.338,nrarrw=219d.338,nri",
1925
+ "ghtarrow=219b,nrtri=22eb,nrtrie=22ed,nsc=2281,nsccue=22e1,nsce=2ab0.338,nscr=1d4c3,nshortmid=2224,ns",
1926
+ "hortparallel=2226,nsim=2241,nsime=2244,nsimeq=2244,nsmid=2224,nspar=2226,nsqsube=22e2,nsqsupe=22e3,n",
1927
+ "sub=2284,nsubE=2ac5.338,nsube=2288,nsubset=2282.20d2,nsubseteq=2288,nsubseteqq=2ac5.338,nsucc=2281,n",
1928
+ "succeq=2ab0.338,nsup=2285,nsupE=2ac6.338,nsupe=2289,nsupset=2283.20d2,nsupseteq=2289,nsupseteqq=2ac6",
1929
+ ".338,ntgl=2279,ntilde=f1,ntlg=2278,ntriangleleft=22ea,ntrianglelefteq=22ec,ntriangleright=22eb,ntria",
1930
+ "nglerighteq=22ed,nu=3bd,num=23,numero=2116,numsp=2007,nvDash=22ad,nvHarr=2904,nvap=224d.20d2,nvdash=",
1931
+ "22ac,nvge=2265.20d2,nvgt=3e.20d2,nvinfin=29de,nvlArr=2902,nvle=2264.20d2,nvlt=3c.20d2,nvltrie=22b4.2",
1932
+ "0d2,nvrArr=2903,nvrtrie=22b5.20d2,nvsim=223c.20d2,nwArr=21d6,nwarhk=2923,nwarr=2196,nwarrow=2196,nwn",
1933
+ "ear=2927,oS=24c8,oacute=f3,oast=229b,ocir=229a,ocirc=f4,ocy=43e,odash=229d,odblac=151,odiv=2a38,odot",
1934
+ "=2299,odsold=29bc,oelig=153,ofcir=29bf,ofr=1d52c,ogon=2db,ograve=f2,ogt=29c1,ohbar=29b5,ohm=3a9,oint",
1935
+ "=222e,olarr=21ba,olcir=29be,olcross=29bb,oline=203e,olt=29c0,omacr=14d,omega=3c9,omicron=3bf,omid=29",
1936
+ "b6,ominus=2296,oopf=1d560,opar=29b7,operp=29b9,oplus=2295,or=2228,orarr=21bb,ord=2a5d,order=2134,ord",
1937
+ "erof=2134,ordf=aa,ordm=ba,origof=22b6,oror=2a56,orslope=2a57,orv=2a5b,oscr=2134,oslash=f8,osol=2298,",
1938
+ "otilde=f5,otimes=2297,otimesas=2a36,ouml=f6,ovbar=233d,par=2225,para=b6,parallel=2225,parsim=2af3,pa",
1939
+ "rsl=2afd,part=2202,pcy=43f,percnt=25,period=2e,permil=2030,perp=22a5,pertenk=2031,pfr=1d52d,phi=3c6,",
1940
+ "phiv=3d5,phmmat=2133,phone=260e,pi=3c0,pitchfork=22d4,piv=3d6,planck=210f,planckh=210e,plankv=210f,p",
1941
+ "lus=2b,plusacir=2a23,plusb=229e,pluscir=2a22,plusdo=2214,plusdu=2a25,pluse=2a72,plusmn=b1,plussim=2a",
1942
+ "26,plustwo=2a27,pm=b1,pointint=2a15,popf=1d561,pound=a3,pr=227a,prE=2ab3,prap=2ab7,prcue=227c,pre=2a",
1943
+ "af,prec=227a,precapprox=2ab7,preccurlyeq=227c,preceq=2aaf,precnapprox=2ab9,precneqq=2ab5,precnsim=22",
1944
+ "e8,precsim=227e,prime=2032,primes=2119,prnE=2ab5,prnap=2ab9,prnsim=22e8,prod=220f,profalar=232e,prof",
1945
+ "line=2312,profsurf=2313,prop=221d,propto=221d,prsim=227e,prurel=22b0,pscr=1d4c5,psi=3c8,puncsp=2008,",
1946
+ "qfr=1d52e,qint=2a0c,qopf=1d562,qprime=2057,qscr=1d4c6,quaternions=210d,quatint=2a16,quest=3f,questeq",
1947
+ "=225f,quot=22,rAarr=21db,rArr=21d2,rAtail=291c,rBarr=290f,rHar=2964,race=223d.331,racute=155,radic=2",
1948
+ "21a,raemptyv=29b3,rang=232a,rangd=2992,range=29a5,rangle=27e9,raquo=bb,rarr=2192,rarrap=2975,rarrb=2",
1949
+ "1e5,rarrbfs=2920,rarrc=2933,rarrfs=291e,rarrhk=21aa,rarrlp=21ac,rarrpl=2945,rarrsim=2974,rarrtl=21a3",
1950
+ ",rarrw=219d,ratail=291a,ratio=2236,rationals=211a,rbarr=290d,rbbrk=2773,rbrace=7d,rbrack=5d,rbrke=29",
1951
+ "8c,rbrksld=298e,rbrkslu=2990,rcaron=159,rcedil=157,rceil=2309,rcub=7d,rcy=440,rdca=2937,rdldhar=2969",
1952
+ ",rdquo=201d,rdquor=201d,rdsh=21b3,real=211c,realine=211b,realpart=211c,reals=211d,rect=25ad,reg=ae,r",
1953
+ "fisht=297d,rfloor=230b,rfr=1d52f,rhard=21c1,rharu=21c0,rharul=296c,rho=3c1,rhov=3f1,rightarrow=2192,",
1954
+ "rightarrowtail=21a3,rightharpoondown=21c1,rightharpoonup=21c0,rightleftarrows=21c4,rightleftharpoons",
1955
+ "=21cc,rightrightarrows=21c9,rightsquigarrow=219d,rightthreetimes=22cc,ring=2da,risingdotseq=2253,rla",
1956
+ "rr=21c4,rlhar=21cc,rlm=200f,rmoust=23b1,rmoustache=23b1,rnmid=2aee,roang=27ed,roarr=21fe,robrk=27e7,",
1957
+ "ropar=2986,ropf=1d563,roplus=2a2e,rotimes=2a35,rpar=29,rpargt=2994,rppolint=2a12,rrarr=21c9,rsaquo=2",
1958
+ "03a,rscr=1d4c7,rsh=21b1,rsqb=5d,rsquo=2019,rsquor=2019,rthree=22cc,rtimes=22ca,rtri=25b9,rtrie=22b5,",
1959
+ "rtrif=25b8,rtriltri=29ce,ruluhar=2968,rx=211e,sacute=15b,sbquo=201a,sc=227b,scE=2ab4,scap=2ab8,scaro",
1960
+ "n=161,sccue=227d,sce=2ab0,scedil=15f,scirc=15d,scnE=2ab6,scnap=2aba,scnsim=22e9,scpolint=2a13,scsim=",
1961
+ "227f,scy=441,sdot=22c5,sdotb=22a1,sdote=2a66,seArr=21d8,searhk=2925,searr=2198,searrow=2198,sect=a7,",
1962
+ "semi=3b,seswar=2929,setminus=2216,setmn=2216,sext=2736,sfr=1d530,sfrown=2322,sharp=266f,shchcy=449,s",
1963
+ "hcy=448,shortmid=2223,shortparallel=2225,shy=ad,sigma=3c3,sigmaf=3c2,sigmav=3c2,sim=223c,simdot=2a6a",
1964
+ ",sime=2243,simeq=2243,simg=2a9e,simgE=2aa0,siml=2a9d,simlE=2a9f,simne=2246,simplus=2a24,simrarr=2972",
1965
+ ",slarr=2190,smallsetminus=2216,smashp=2a33,smeparsl=29e4,smid=2223,smile=2323,smt=2aaa,smte=2aac,smt",
1966
+ "es=2aac.fe00,softcy=44c,sol=2f,solb=29c4,solbar=233f,sopf=1d564,spades=2660,spadesuit=2660,spar=2225",
1967
+ ",sqcap=2293,sqcaps=2293.fe00,sqcup=2294,sqcups=2294.fe00,sqsub=228f,sqsube=2291,sqsubset=228f,sqsubs",
1968
+ "eteq=2291,sqsup=2290,sqsupe=2292,sqsupset=2290,sqsupseteq=2292,squ=25a1,square=25a1,squarf=25aa,squf",
1969
+ "=25aa,srarr=2192,sscr=1d4c8,ssetmn=2216,ssmile=2323,sstarf=22c6,star=2606,starf=2605,straightepsilon",
1970
+ "=3f5,straightphi=3d5,strns=af,sub=2282,subE=2ac5,subdot=2abd,sube=2286,subedot=2ac3,submult=2ac1,sub",
1971
+ "nE=2acb,subne=228a,subplus=2abf,subrarr=2979,subset=2282,subseteq=2286,subseteqq=2ac5,subsetneq=228a",
1972
+ ",subsetneqq=2acb,subsim=2ac7,subsub=2ad5,subsup=2ad3,succ=227b,succapprox=2ab8,succcurlyeq=227d,succ",
1973
+ "eq=2ab0,succnapprox=2aba,succneqq=2ab6,succnsim=22e9,succsim=227f,sum=2211,sung=266a,sup=2283,sup1=b",
1974
+ "9,sup2=b2,sup3=b3,supE=2ac6,supdot=2abe,supdsub=2ad8,supe=2287,supedot=2ac4,suphsol=27c9,suphsub=2ad",
1975
+ "7,suplarr=297b,supmult=2ac2,supnE=2acc,supne=228b,supplus=2ac0,supset=2283,supseteq=2287,supseteqq=2",
1976
+ "ac6,supsetneq=228b,supsetneqq=2acc,supsim=2ac8,supsub=2ad4,supsup=2ad6,swArr=21d9,swarhk=2926,swarr=",
1977
+ "2199,swarrow=2199,swnwar=292a,szlig=df,target=2316,tau=3c4,tbrk=23b4,tcaron=165,tcedil=163,tcy=442,t",
1978
+ "dot=20db,telrec=2315,tfr=1d531,there4=2234,therefore=2234,theta=3b8,thetasym=3d1,thetav=3d1,thickapp",
1979
+ "rox=2248,thicksim=223c,thinsp=2009,thkap=2248,thksim=223c,thorn=fe,tilde=2dc,times=d7,timesb=22a0,ti",
1980
+ "mesbar=2a31,timesd=2a30,tint=222d,toea=2928,top=22a4,topbot=2336,topcir=2af1,topf=1d565,topfork=2ada",
1981
+ ",tosa=2929,tprime=2034,trade=2122,triangle=25b5,triangledown=25bf,triangleleft=25c3,trianglelefteq=2",
1982
+ "2b4,triangleq=225c,triangleright=25b9,trianglerighteq=22b5,tridot=25ec,trie=225c,triminus=2a3a,tripl",
1983
+ "us=2a39,trisb=29cd,tritime=2a3b,trpezium=23e2,tscr=1d4c9,tscy=446,tshcy=45b,tstrok=167,twixt=226c,tw",
1984
+ "oheadleftarrow=219e,twoheadrightarrow=21a0,uArr=21d1,uHar=2963,uacute=fa,uarr=2191,ubrcy=45e,ubreve=",
1985
+ "16d,ucirc=fb,ucy=443,udarr=21c5,udblac=171,udhar=296e,ufisht=297e,ufr=1d532,ugrave=f9,uharl=21bf,uha",
1986
+ "rr=21be,uhblk=2580,ulcorn=231c,ulcorner=231c,ulcrop=230f,ultri=25f8,umacr=16b,uml=a8,uogon=173,uopf=",
1987
+ "1d566,uparrow=2191,updownarrow=2195,upharpoonleft=21bf,upharpoonright=21be,uplus=228e,upsi=3c5,upsih",
1988
+ "=3d2,upsilon=3c5,upuparrows=21c8,urcorn=231d,urcorner=231d,urcrop=230e,uring=16f,urtri=25f9,uscr=1d4",
1989
+ "ca,utdot=22f0,utilde=169,utri=25b5,utrif=25b4,uuarr=21c8,uuml=fc,uwangle=29a7,vArr=21d5,vBar=2ae8,vB",
1990
+ "arv=2ae9,vDash=22a8,vangrt=299c,varepsilon=3f5,varkappa=3f0,varnothing=2205,varphi=3d5,varpi=3d6,var",
1991
+ "propto=221d,varr=2195,varrho=3f1,varsigma=3c2,varsubsetneq=228a.fe00,varsubsetneqq=2acb.fe00,varsups",
1992
+ "etneq=228b.fe00,varsupsetneqq=2acc.fe00,vartheta=3d1,vartriangleleft=22b2,vartriangleright=22b3,vcy=",
1993
+ "432,vdash=22a2,vee=2228,veebar=22bb,veeeq=225a,vellip=22ee,verbar=7c,vert=7c,vfr=1d533,vltri=22b2,vn",
1994
+ "sub=2282.20d2,vnsup=2283.20d2,vopf=1d567,vprop=221d,vrtri=22b3,vscr=1d4cb,vsubnE=2acb.fe00,vsubne=22",
1995
+ "8a.fe00,vsupnE=2acc.fe00,vsupne=228b.fe00,vzigzag=299a,wcirc=175,wedbar=2a5f,wedge=2227,wedgeq=2259,",
1996
+ "weierp=2118,wfr=1d534,wopf=1d568,wp=2118,wr=2240,wreath=2240,wscr=1d4cc,xcap=22c2,xcirc=25ef,xcup=22",
1997
+ "c3,xdtri=25bd,xfr=1d535,xhArr=27fa,xharr=27f7,xi=3be,xlArr=27f8,xlarr=27f5,xmap=27fc,xnis=22fb,xodot",
1998
+ "=2a00,xopf=1d569,xoplus=2a01,xotime=2a02,xrArr=27f9,xrarr=27f6,xscr=1d4cd,xsqcup=2a06,xuplus=2a04,xu",
1999
+ "tri=25b3,xvee=22c1,xwedge=22c0,yacute=fd,yacy=44f,ycirc=177,ycy=44b,yen=a5,yfr=1d536,yicy=457,yopf=1",
2000
+ "d56a,yscr=1d4ce,yucy=44e,yuml=ff,zacute=17a,zcaron=17e,zcy=437,zdot=17c,zeetrf=2128,zeta=3b6,zfr=1d5",
2001
+ "37,zhcy=436,zigrarr=21dd,zopf=1d56b,zscr=1d4cf,zwj=200d,zwnj=200c"
2002
+ ].join("");
2003
+ var NAMED_REFERENCES = new Map(NAMED.split(",").map((entry) => {
2004
+ const [name, codes] = entry.split("=");
2005
+ return [name, String.fromCodePoint(...codes.split(".").map((code) => Number.parseInt(code, 16)))];
2006
+ }));
2007
+
1733
2008
  // src/html.js
1734
2009
  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(" ");
1735
- var ENTITIES = new Map([
1736
- ...LATIN1.map((name, index) => [name, String.fromCodePoint(160 + index)]),
1737
- ["amp", "&"],
1738
- ["lt", "<"],
1739
- ["gt", ">"],
1740
- ["quot", '"'],
1741
- ["apos", "'"],
1742
- ["AMP", "&"],
1743
- ["LT", "<"],
1744
- ["GT", ">"],
1745
- ["QUOT", '"'],
1746
- ["COPY", "\xA9"],
1747
- ["REG", "\xAE"],
1748
- ["OElig", "\u0152"],
1749
- ["oelig", "\u0153"],
1750
- ["Scaron", "\u0160"],
1751
- ["scaron", "\u0161"],
1752
- ["Yuml", "\u0178"],
1753
- ["fnof", "\u0192"],
1754
- ["circ", "\u02C6"],
1755
- ["tilde", "\u02DC"],
1756
- ["ensp", "\u2002"],
1757
- ["emsp", "\u2003"],
1758
- ["thinsp", "\u2009"],
1759
- ["zwnj", "\u200C"],
1760
- ["zwj", "\u200D"],
1761
- ["lrm", "\u200E"],
1762
- ["rlm", "\u200F"],
1763
- ["ndash", "\u2013"],
1764
- ["mdash", "\u2014"],
1765
- ["lsquo", "\u2018"],
1766
- ["rsquo", "\u2019"],
1767
- ["sbquo", "\u201A"],
1768
- ["ldquo", "\u201C"],
1769
- ["rdquo", "\u201D"],
1770
- ["bdquo", "\u201E"],
1771
- ["dagger", "\u2020"],
1772
- ["Dagger", "\u2021"],
1773
- ["bull", "\u2022"],
1774
- ["hellip", "\u2026"],
1775
- ["permil", "\u2030"],
1776
- ["prime", "\u2032"],
1777
- ["Prime", "\u2033"],
1778
- ["lsaquo", "\u2039"],
1779
- ["rsaquo", "\u203A"],
1780
- ["euro", "\u20AC"],
1781
- ["trade", "\u2122"],
1782
- ["larr", "\u2190"],
1783
- ["uarr", "\u2191"],
1784
- ["rarr", "\u2192"],
1785
- ["darr", "\u2193"],
1786
- ["hearts", "\u2665"],
1787
- ["check", "\u2713"],
1788
- // The punctuation of a web address, as browsers read these names
1789
- // ("https://bank.example&commat;evil.example/" goes to evil.example)
1790
- ["Tab", " "],
1791
- ["NewLine", "\n"],
1792
- ["excl", "!"],
1793
- ["num", "#"],
1794
- ["dollar", "$"],
1795
- ["percnt", "%"],
1796
- ["lpar", "("],
1797
- ["rpar", ")"],
1798
- ["ast", "*"],
1799
- ["midast", "*"],
1800
- ["plus", "+"],
1801
- ["comma", ","],
1802
- ["period", "."],
1803
- ["sol", "/"],
1804
- ["colon", ":"],
1805
- ["semi", ";"],
1806
- ["equals", "="],
1807
- ["quest", "?"],
1808
- ["commat", "@"],
1809
- ["lsqb", "["],
1810
- ["lbrack", "["],
1811
- ["bsol", "\\"],
1812
- ["rsqb", "]"],
1813
- ["rbrack", "]"],
1814
- ["Hat", "^"],
1815
- ["lowbar", "_"],
1816
- ["UnderBar", "_"],
1817
- ["grave", "`"],
1818
- ["DiacriticalGrave", "`"],
1819
- ["lcub", "{"],
1820
- ["lbrace", "{"],
1821
- ["verbar", "|"],
1822
- ["vert", "|"],
1823
- ["VerticalLine", "|"],
1824
- ["rcub", "}"],
1825
- ["rbrace", "}"]
1826
- ]);
1827
2010
  var LEGACY = /* @__PURE__ */ new Set([...LATIN1, "amp", "lt", "gt", "quot", "AMP", "LT", "GT", "QUOT", "COPY", "REG"]);
1828
2011
  var LEGACY_LONGEST = Math.max(...[...LEGACY].map((name) => name.length));
1829
- var LONGER_NAMES = new Set("centerdot copysr divideontimes gtcc gtcir gtdot gtlPar gtquest gtrapprox gtrarr gtrdot gtreqless gtreqqless gtrless gtrsim ltcc ltcir ltdot lthree ltimes ltlarr ltquest ltrPar ltri ltrie ltrif notin notinE notindot notinva notinvb notinvc notni notniva notnivb notnivc parallel timesb timesbar timesd".split(" "));
1830
2012
  var WINDOWS_1252 = [8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141, 381, 143, 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250, 339, 157, 382, 376];
1831
2013
  var REFERENCE = /&(?:#([xX])([\da-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z\d]{0,31}))(;?)/g;
1832
2014
  function fromCode(code) {
@@ -1844,8 +2026,8 @@ function decodeEntities(value, { attribute = false } = {}) {
1844
2026
  if (hex !== void 0 || decimal !== void 0) {
1845
2027
  return fromCode(hex === void 0 ? Number.parseInt(decimal, 10) : Number.parseInt(hex, 16));
1846
2028
  }
1847
- if (semicolon && (ENTITIES.has(name) || LONGER_NAMES.has(name))) {
1848
- return ENTITIES.get(name) ?? match;
2029
+ if (semicolon && NAMED_REFERENCES.has(name)) {
2030
+ return NAMED_REFERENCES.get(name);
1849
2031
  }
1850
2032
  let legacy;
1851
2033
  for (let length = Math.min(name.length, LEGACY_LONGEST); length >= 2 && legacy === void 0; length--) {
@@ -1859,7 +2041,7 @@ function decodeEntities(value, { attribute = false } = {}) {
1859
2041
  if (attribute && /[\da-zA-Z=]/.test(next)) {
1860
2042
  return match;
1861
2043
  }
1862
- return ENTITIES.get(legacy) + rest;
2044
+ return NAMED_REFERENCES.get(legacy) + rest;
1863
2045
  });
1864
2046
  }
1865
2047
  var UNSHOWN = /* @__PURE__ */ new Set(["script", "style", "title", "noembed", "noframes", "iframe"]);
@@ -3005,7 +3187,7 @@ function endsInsideTag(html, end, link) {
3005
3187
  return joined !== host && (!isHost(host) || isHost(joined) && registrableDomain(joined) !== registrableDomain(host));
3006
3188
  }
3007
3189
  var MAX_SHOWN_HTML = 2e5;
3008
- function extractLinks(text, html, { maxLength = 5e5, bareHosts = false } = {}) {
3190
+ function extractLinks(text, html, { maxLength = 5e5, bareHosts: bareHosts2 = false } = {}) {
3009
3191
  text = typeof text === "string" ? foldToAscii(text) : text;
3010
3192
  html = typeof html === "string" ? foldToAscii(html) : html;
3011
3193
  const links = [];
@@ -3072,7 +3254,7 @@ ${shown || ""}`;
3072
3254
  }
3073
3255
  add(link);
3074
3256
  }
3075
- if (bareHosts && index < 2) {
3257
+ if (bareHosts2 && index < 2) {
3076
3258
  bareLinkHosts(read, (host) => {
3077
3259
  bareFound.push(host);
3078
3260
  });
@@ -5160,7 +5342,8 @@ async function parseWithin(raw, parse = parseMessage, deadline = Date.now() + PA
5160
5342
  }
5161
5343
  }
5162
5344
  }
5163
- async function expandAttachments(attachments = [], errors = [], parse = parseMessage, unopened = []) {
5345
+ async function expandAttachments(attachments = [], errors = [], parse = parseMessage, gets = {}) {
5346
+ const { unopened = [], mails = [] } = Array.isArray(gets) ? { unopened: gets } : gets;
5164
5347
  const all = [];
5165
5348
  const deadline = Date.now() + PARSE_TIMEOUT;
5166
5349
  let budget = MAX_NESTED_BYTES;
@@ -5209,6 +5392,7 @@ async function expandAttachments(attachments = [], errors = [], parse = parseMes
5209
5392
  if (inner.error) {
5210
5393
  errors.push(inner.error);
5211
5394
  }
5395
+ mails.push(inner.mail);
5212
5396
  await visit(inner.mail.attachments, prefix ? `${prefix}/${name}` : name || "attached message", depth + 1);
5213
5397
  }
5214
5398
  }
@@ -6089,7 +6273,7 @@ import net from "node:net";
6089
6273
  var package_default = {
6090
6274
  name: "spamscanner",
6091
6275
  description: "Spam, phishing and malware filter for email in any language: a trainable classifier, link and attachment checks, SPF/DKIM/DMARC, and an optional AI second opinion from any LLM, including local Ollama models. Works as a library, CLI, Postfix milter or HTTP API.",
6092
- version: "7.0.10",
6276
+ version: "7.0.11",
6093
6277
  author: "Forward Email (https://forwardemail.net)",
6094
6278
  bin: {
6095
6279
  spamscanner: "./dist/esm/cli.js"
@@ -7629,7 +7813,7 @@ async function evaluate(classifier, examples) {
7629
7813
  }
7630
7814
 
7631
7815
  // src/index.js
7632
- import { Buffer as Buffer13 } from "node:buffer";
7816
+ import { Buffer as Buffer14 } from "node:buffer";
7633
7817
  import { readFile } from "node:fs/promises";
7634
7818
  import { debuglog as debuglog2 } from "node:util";
7635
7819
 
@@ -8130,8 +8314,917 @@ async function scanBuffer(buffer, options = {}) {
8130
8314
  throw new Error(`clamd: ${reply2 || "no reply"}`);
8131
8315
  }
8132
8316
 
8133
- // src/is-arbitrary.js
8317
+ // src/links.js
8318
+ import { Buffer as Buffer13 } from "node:buffer";
8319
+ import { isIP as isIP3 } from "node:net";
8134
8320
  import { parse as parseDomain3 } from "tldts";
8321
+ var LINK_ATTRIBUTES = /* @__PURE__ */ new Set([
8322
+ "href",
8323
+ "src",
8324
+ "srcset",
8325
+ "background",
8326
+ "action",
8327
+ "formaction",
8328
+ "poster",
8329
+ "cite",
8330
+ "longdesc",
8331
+ "xlink:href",
8332
+ "style",
8333
+ "data",
8334
+ "ping",
8335
+ // (of a <meta> refresh: "0;url=https://example.com/")
8336
+ "content",
8337
+ // (a document of its own, see linksOf)
8338
+ "srcdoc"
8339
+ ]);
8340
+ var TAG_START = /<[a-z][^\s/>]*/gi;
8341
+ var URL_START = /\b(?:https?:\/\/|www\.)[^\s<>"'`]+/gi;
8342
+ var CSS_URL = /url\(\s*["']?([^()"']*)/gi;
8343
+ var CSS_IMPORT = /@import\s+["']([^"'<>]*)/gi;
8344
+ var LENIENT = /[\s"'/<](href|src|srcset|background|action|formaction|poster|cite|longdesc|xlink:href|style|data|ping|content|srcdoc)\s*=\s*/gi;
8345
+ var IN_WORD2 = /[\p{L}\p{N}\p{M}_%]/u;
8346
+ var NAMESPACES = /* @__PURE__ */ new Set(["www.w3.org", "w3.org"]);
8347
+ var MAX_HOST = 760;
8348
+ var MAX_SEEN = 1e5;
8349
+ var TRAILING = /* @__PURE__ */ new Set([")", ".", ",", ";", ":", "!", "?", "'", '"', "]"]);
8350
+ var DECODE_CHUNK = 1024 * 1024;
8351
+ var CHUNK_OVERLAP = 4096;
8352
+ var MAX_EMBED_DEPTH = 3;
8353
+ var MAX_EMBEDDED = 1e3;
8354
+ var MAX_EMBEDDED_LENGTH = 10 * 1024 * 1024;
8355
+ var MAX_ATTACHED = 100;
8356
+ var MAX_ATTACHED_BYTES = 50 * 1024 * 1024;
8357
+ var MAX_READ_TIME = 5e3;
8358
+ var MAX_SHOWN_BYTES = 4 * 1024 * 1024;
8359
+ function isHostCode2(code) {
8360
+ return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 45 || code === 46;
8361
+ }
8362
+ function isSpace(code) {
8363
+ return code === 32 || code >= 9 && code <= 13;
8364
+ }
8365
+ function urlOf(value) {
8366
+ let href = value.replaceAll(/[\t\n\r]/g, "");
8367
+ let start = 0;
8368
+ let end = href.length;
8369
+ while (start < end && href.codePointAt(start) <= 32) {
8370
+ start++;
8371
+ }
8372
+ while (end > start && href.codePointAt(end - 1) <= 32) {
8373
+ end--;
8374
+ }
8375
+ while (end > start && TRAILING.has(href[end - 1])) {
8376
+ end--;
8377
+ }
8378
+ href = href.slice(start, end);
8379
+ if (/^[\\/]{2}/.test(href)) {
8380
+ href = `https://${href.slice(2)}`;
8381
+ } else if (/^www\./i.test(href)) {
8382
+ href = `http://${href}`;
8383
+ } else if (!/^https?:/i.test(href)) {
8384
+ return null;
8385
+ }
8386
+ try {
8387
+ return new URL(href);
8388
+ } catch {
8389
+ return null;
8390
+ }
8391
+ }
8392
+ function hostOfUrl(url) {
8393
+ let host = url.hostname.toLowerCase();
8394
+ let dots = host.length;
8395
+ while (dots > 0 && host[dots - 1] === ".") {
8396
+ dots--;
8397
+ }
8398
+ host = host.slice(0, dots);
8399
+ if (host.startsWith("[") && host.endsWith("]")) {
8400
+ host = host.slice(1, -1);
8401
+ }
8402
+ if (!host || NAMESPACES.has(host)) {
8403
+ return null;
8404
+ }
8405
+ return isIP3(host) ? host : lookupName(host);
8406
+ }
8407
+ function hostsOf(value) {
8408
+ const url = urlOf(value);
8409
+ if (!url) {
8410
+ return [];
8411
+ }
8412
+ const host = hostOfUrl(url);
8413
+ const hosts = host ? [host] : [];
8414
+ const target = unwrapLink(url.href);
8415
+ if (target && target.href !== url.href) {
8416
+ const targetHost = hostOfUrl(target);
8417
+ if (targetHost && targetHost !== host) {
8418
+ hosts.push(targetHost);
8419
+ }
8420
+ const further = unwrapLink(target.href);
8421
+ if (further && further.href !== target.href) {
8422
+ hosts.unresolved = true;
8423
+ }
8424
+ }
8425
+ return hosts;
8426
+ }
8427
+ function* attributesOf(html) {
8428
+ TAG_START.lastIndex = 0;
8429
+ let match;
8430
+ while ((match = TAG_START.exec(html)) !== null) {
8431
+ let i = match.index + match[0].length;
8432
+ while (i < html.length && html[i] !== ">") {
8433
+ if (isSpace(html.codePointAt(i)) || html[i] === "/") {
8434
+ i++;
8435
+ continue;
8436
+ }
8437
+ let j = i;
8438
+ while (j < html.length && html[j] !== "=" && html[j] !== ">" && html[j] !== "/" && !isSpace(html.codePointAt(j))) {
8439
+ j++;
8440
+ }
8441
+ const name = html.slice(i, j).toLowerCase();
8442
+ if (j === i) {
8443
+ j++;
8444
+ }
8445
+ while (j < html.length && isSpace(html.codePointAt(j))) {
8446
+ j++;
8447
+ }
8448
+ if (html[j] !== "=") {
8449
+ i = j;
8450
+ continue;
8451
+ }
8452
+ j++;
8453
+ while (j < html.length && isSpace(html.codePointAt(j))) {
8454
+ j++;
8455
+ }
8456
+ let value;
8457
+ if (html[j] === '"' || html[j] === "'") {
8458
+ const close = html.indexOf(html[j], j + 1);
8459
+ const stop = close === -1 ? html.length : close;
8460
+ value = html.slice(j + 1, stop);
8461
+ j = stop + 1;
8462
+ } else {
8463
+ const start = j;
8464
+ while (j < html.length && html[j] !== ">" && !isSpace(html.codePointAt(j))) {
8465
+ j++;
8466
+ }
8467
+ value = html.slice(start, j);
8468
+ }
8469
+ if (name) {
8470
+ yield [name, value];
8471
+ }
8472
+ i = j;
8473
+ }
8474
+ TAG_START.lastIndex = Math.max(i, match.index + 1);
8475
+ }
8476
+ }
8477
+ function linksOf(name, value, add, embed) {
8478
+ const decoded = decodeEntities(value, { attribute: true });
8479
+ switch (name) {
8480
+ case "srcdoc": {
8481
+ embed(decoded);
8482
+ break;
8483
+ }
8484
+ case "style": {
8485
+ for (const [, link] of decoded.matchAll(CSS_URL)) {
8486
+ add(link);
8487
+ }
8488
+ break;
8489
+ }
8490
+ case "srcset": {
8491
+ for (const candidate of decoded.split(",")) {
8492
+ add(candidate.trim().split(/\s/, 1)[0]);
8493
+ }
8494
+ break;
8495
+ }
8496
+ // (several, separated by spaces)
8497
+ case "ping": {
8498
+ for (const link of decoded.split(/\s+/)) {
8499
+ add(link);
8500
+ }
8501
+ break;
8502
+ }
8503
+ // (only the address of a refresh)
8504
+ case "content": {
8505
+ const match = /(?:^|[\s;,])url\s*=\s*["']?([^\s"';]+)/i.exec(decoded.slice(0, 4096));
8506
+ if (match) {
8507
+ add(match[1]);
8508
+ }
8509
+ break;
8510
+ }
8511
+ default: {
8512
+ add(decoded);
8513
+ }
8514
+ }
8515
+ }
8516
+ var MAX_LENIENT_VALUE = 4096;
8517
+ var UNQUOTED_END = /* @__PURE__ */ new Set(["<", ">", '"', "'", "`", "="]);
8518
+ function lenientLinks(html, add, done, embed) {
8519
+ LENIENT.lastIndex = 0;
8520
+ let match;
8521
+ while (!done() && (match = LENIENT.exec(html)) !== null) {
8522
+ const name = match[1].toLowerCase();
8523
+ let i = LENIENT.lastIndex;
8524
+ let end = i;
8525
+ if (html[i] === '"' || html[i] === "'") {
8526
+ const quote = html[i];
8527
+ i++;
8528
+ end = i;
8529
+ while (end < html.length && html[end] !== quote && html[end] !== "<" && html[end] !== ">") {
8530
+ end++;
8531
+ }
8532
+ if (end < html.length && html[end] !== quote) {
8533
+ const close = html.indexOf(quote, end);
8534
+ if (close !== -1 && close - i <= MAX_LENIENT_VALUE) {
8535
+ linksOf(name, html.slice(i, close), add, embed);
8536
+ }
8537
+ }
8538
+ } else {
8539
+ while (end < html.length && !isSpace(html.codePointAt(end)) && !UNQUOTED_END.has(html[end])) {
8540
+ end++;
8541
+ }
8542
+ }
8543
+ linksOf(name, html.slice(i, end), add, embed);
8544
+ }
8545
+ }
8546
+ function endsLink2(text, i) {
8547
+ const code = text.codePointAt(i);
8548
+ if (code < 128) {
8549
+ return isSpace(code) || code === 34 || code === 39 || code === 60 || code === 62 || code === 96;
8550
+ }
8551
+ return /\s/u.test(text[i]);
8552
+ }
8553
+ function linkReader(text) {
8554
+ let read = 0;
8555
+ let space = -1;
8556
+ let scheme = -1;
8557
+ return (start) => {
8558
+ for (; read < start; read++) {
8559
+ if (endsLink2(text, read)) {
8560
+ space = read;
8561
+ } else if (text[read] === "/" && text[read - 1] === "/" && text[read - 2] === ":") {
8562
+ scheme = read;
8563
+ }
8564
+ }
8565
+ return scheme > space;
8566
+ };
8567
+ }
8568
+ function isSchemeless(text, start) {
8569
+ if (start < 2 || text[start - 2] !== "/") {
8570
+ return false;
8571
+ }
8572
+ if (start === 2) {
8573
+ return true;
8574
+ }
8575
+ const before = text[start - 3];
8576
+ return !(before === ":" || before === "/" || isHostCode2(text.codePointAt(start - 3)));
8577
+ }
8578
+ function bareName(name) {
8579
+ const labels = name.split(".");
8580
+ const tld = labels.pop();
8581
+ if (!/^(?:[a-z]{2,24}|xn--[a-z\d-]{1,59})$/i.test(tld)) {
8582
+ return null;
8583
+ }
8584
+ const names = [];
8585
+ while (labels.length > 0 && names.length < 11) {
8586
+ const label = labels.pop();
8587
+ if (!/^[a-z\d-]{1,63}$/i.test(label)) {
8588
+ break;
8589
+ }
8590
+ names.unshift(label);
8591
+ }
8592
+ if (names.length === 0) {
8593
+ return null;
8594
+ }
8595
+ names[0] = names[0].replace(/^-+/, "");
8596
+ if (!names[0]) {
8597
+ return null;
8598
+ }
8599
+ return `${names.join(".")}.${tld}`.toLowerCase();
8600
+ }
8601
+ function isRealName(host) {
8602
+ const parsed = parseDomain3(host);
8603
+ return Boolean(parsed.isIcann && parsed.domain);
8604
+ }
8605
+ function bareHosts(text, add, { done, seen, from = 0, cutEnd = false }) {
8606
+ let previous = -1;
8607
+ const inLink = linkReader(text);
8608
+ for (let slash = text.indexOf("/"); slash !== -1; slash = text.indexOf("/", slash + 1)) {
8609
+ if (done()) {
8610
+ return;
8611
+ }
8612
+ const floor = Math.max(previous + 1, slash - MAX_HOST);
8613
+ previous = slash;
8614
+ let end = slash;
8615
+ while (end > floor && text.codePointAt(end - 1) >= 48 && text.codePointAt(end - 1) <= 57) {
8616
+ end--;
8617
+ }
8618
+ end = end > floor && text[end - 1] === ":" ? end - 1 : slash;
8619
+ let start = end;
8620
+ while (start > floor && isHostCode2(text.codePointAt(start - 1))) {
8621
+ start--;
8622
+ }
8623
+ if (start === end || start < from || cutEnd && slash === text.length - 1) {
8624
+ continue;
8625
+ }
8626
+ if (start > 0 && (IN_WORD2.test(text[start - 1]) || text[start - 1] === "/" && !isSchemeless(text, start)) || inLink(start)) {
8627
+ continue;
8628
+ }
8629
+ while (end > start && text[end - 1] === ".") {
8630
+ end--;
8631
+ }
8632
+ const host = bareName(text.slice(start, end));
8633
+ if (!host || seen.has(host)) {
8634
+ continue;
8635
+ }
8636
+ if (seen.size < MAX_SEEN) {
8637
+ seen.add(host);
8638
+ }
8639
+ if (isRealName(host)) {
8640
+ add(`http://${host}/`);
8641
+ }
8642
+ }
8643
+ }
8644
+ function looseHosts(text, add, { from = 0, cutEnd = false, seen, done }) {
8645
+ const inLink = linkReader(text);
8646
+ const { length } = text;
8647
+ let i = 0;
8648
+ while (i < length) {
8649
+ if (!isHostCode2(text.codePointAt(i))) {
8650
+ i++;
8651
+ continue;
8652
+ }
8653
+ const start = i;
8654
+ while (i < length && isHostCode2(text.codePointAt(i))) {
8655
+ i++;
8656
+ }
8657
+ let end = i;
8658
+ if (end - start > MAX_HOST || start < from || cutEnd && end === length) {
8659
+ continue;
8660
+ }
8661
+ while (end > start && text[end - 1] === ".") {
8662
+ end--;
8663
+ }
8664
+ const before = start > 0 ? text[start - 1] : "";
8665
+ const after = end < length ? text[end] : "";
8666
+ if (after === "/" || after === "@" || before === "@") {
8667
+ continue;
8668
+ }
8669
+ if (before && (IN_WORD2.test(before) || before === "/" || before === "\\" || before === "&" || before === "#")) {
8670
+ continue;
8671
+ }
8672
+ if (after && after !== "." && IN_WORD2.test(after)) {
8673
+ continue;
8674
+ }
8675
+ const name = text.slice(start, end);
8676
+ if (!name.includes(".") || inLink(start)) {
8677
+ continue;
8678
+ }
8679
+ const lower = name.toLowerCase();
8680
+ if (seen.has(lower)) {
8681
+ continue;
8682
+ }
8683
+ if (seen.size < MAX_SEEN) {
8684
+ seen.add(lower);
8685
+ }
8686
+ if (done()) {
8687
+ return;
8688
+ }
8689
+ const host = bareName(name);
8690
+ if (host && isRealName(host)) {
8691
+ add(host);
8692
+ }
8693
+ }
8694
+ }
8695
+ function* chunksOf(html) {
8696
+ let start = 0;
8697
+ let cutStart = false;
8698
+ while (start < html.length) {
8699
+ const end = Math.min(html.length, start + DECODE_CHUNK);
8700
+ if (end < html.length) {
8701
+ let cut = end;
8702
+ while (cut > end - 65536 && cut > start) {
8703
+ if (html[cut] === "<" || isSpace(html.codePointAt(cut))) {
8704
+ break;
8705
+ }
8706
+ cut--;
8707
+ }
8708
+ if (cut > start && cut > end - 65536) {
8709
+ yield { text: html.slice(start, cut), cutStart, cutEnd: false };
8710
+ start = cut;
8711
+ cutStart = false;
8712
+ continue;
8713
+ }
8714
+ yield { text: html.slice(start, end), cutStart, cutEnd: true };
8715
+ start = end - CHUNK_OVERLAP;
8716
+ cutStart = true;
8717
+ continue;
8718
+ }
8719
+ yield { text: html.slice(start, end), cutStart, cutEnd: false };
8720
+ start = end;
8721
+ }
8722
+ }
8723
+ function withoutNul(text) {
8724
+ return text.includes("\0") ? `${text}
8725
+ ${text.replaceAll("\0", "")}` : text;
8726
+ }
8727
+ function hexValue(code) {
8728
+ if (code >= 48 && code <= 57) {
8729
+ return code - 48;
8730
+ }
8731
+ if (code >= 65 && code <= 70) {
8732
+ return code - 55;
8733
+ }
8734
+ if (code >= 97 && code <= 102) {
8735
+ return code - 87;
8736
+ }
8737
+ return -1;
8738
+ }
8739
+ function percentDecoded(text) {
8740
+ const input = Buffer13.from(text);
8741
+ const output = Buffer13.allocUnsafe(input.length);
8742
+ let length = 0;
8743
+ for (let i = 0; i < input.length; i++) {
8744
+ const high = input[i] === 37 ? hexValue(input[i + 1]) : -1;
8745
+ const low = high === -1 ? -1 : hexValue(input[i + 2]);
8746
+ if (low === -1) {
8747
+ output[length++] = input[i];
8748
+ continue;
8749
+ }
8750
+ output[length++] = high * 16 + low;
8751
+ i += 2;
8752
+ }
8753
+ return output.subarray(0, length);
8754
+ }
8755
+ var UTF16LE = /* @__PURE__ */ new Set(["csunicode", "iso-10646-ucs-2", "ucs-2", "unicode", "unicodefeff", "utf-16", "utf-16le"]);
8756
+ var UTF16BE = /* @__PURE__ */ new Set(["unicodefffe", "utf-16be"]);
8757
+ function swapped(bytes) {
8758
+ return Buffer13.from(bytes.subarray(0, bytes.length - bytes.length % 2)).swap16().toString("utf16le");
8759
+ }
8760
+ function decodeText(content, charset = "") {
8761
+ if (content[0] === 255 && content[1] === 254) {
8762
+ return content.subarray(2).toString("utf16le");
8763
+ }
8764
+ if (content[0] === 254 && content[1] === 255) {
8765
+ return swapped(content.subarray(2));
8766
+ }
8767
+ if (UTF16LE.has(charset)) {
8768
+ return content.toString("utf16le");
8769
+ }
8770
+ return UTF16BE.has(charset) ? swapped(content) : content.toString("utf8");
8771
+ }
8772
+ var DATA_DOCUMENT = /^\s*data:\s*(?:text\/html|application\/xhtml\+xml|image\/svg\+xml|text\/xml|application\/xml)\b([^,]*),/i;
8773
+ function dataDocument(value) {
8774
+ const match = DATA_DOCUMENT.exec(value.slice(0, 1024));
8775
+ if (!match) {
8776
+ return null;
8777
+ }
8778
+ const bytes = percentDecoded(value.slice(match[0].length));
8779
+ const content = /;\s*base64\s*$/i.test(match[1]) ? Buffer13.from(bytes.toString("latin1"), "base64") : bytes;
8780
+ const charset = /;\s*charset\s*=\s*"?([^;"\s]+)/i.exec(match[1]);
8781
+ return decodeText(content, charset ? charset[1].toLowerCase() : "");
8782
+ }
8783
+ var LINE_BREAK = /\r\n?|\n/;
8784
+ var FOLD = /(?:\r\n?|\n)[ \t]/g;
8785
+ var QUOTED_PRINTABLE = /;\s*(?:encoding\s*=\s*)?"?quoted-printable"?\s*(?:;|$)/i;
8786
+ var MEDIA_PROPERTIES = /* @__PURE__ */ new Set(["photo", "logo", "sound", "key", "attach"]);
8787
+ var HTML_PROPERTIES = /^(?:x-alt-desc|styled-description|description|comment)[;:]/i;
8788
+ function readEscapes(text, lenient = false) {
8789
+ let index = text.indexOf("\\");
8790
+ if (index === -1) {
8791
+ return text;
8792
+ }
8793
+ let out = "";
8794
+ let parts = [];
8795
+ let start = 0;
8796
+ while (index !== -1 && index + 1 < text.length) {
8797
+ const next = text[index + 1];
8798
+ if (lenient || "nN,;\\".includes(next)) {
8799
+ parts.push(text.slice(start, index), next === "n" || next === "N" ? "\n" : next);
8800
+ start = index + 2;
8801
+ index = text.indexOf("\\", start);
8802
+ if (parts.length >= 65536) {
8803
+ out += parts.join("");
8804
+ parts = [];
8805
+ }
8806
+ } else {
8807
+ index = text.indexOf("\\", index + 1);
8808
+ }
8809
+ }
8810
+ parts.push(text.slice(start));
8811
+ return out + parts.join("");
8812
+ }
8813
+ function valueColon(line) {
8814
+ let colon = line.indexOf(":");
8815
+ let from = 0;
8816
+ for (; ; ) {
8817
+ const quote = line.indexOf('"', from);
8818
+ if (quote === -1 || colon === -1 || colon < quote) {
8819
+ return colon;
8820
+ }
8821
+ const end = line.indexOf('"', quote + 1);
8822
+ if (end === -1) {
8823
+ return -1;
8824
+ }
8825
+ from = end + 1;
8826
+ if (colon < from) {
8827
+ colon = line.indexOf(":", from);
8828
+ }
8829
+ }
8830
+ }
8831
+ function trimSpaceEnd(text) {
8832
+ let end = text.length;
8833
+ while (end > 0 && (text[end - 1] === " " || text[end - 1] === " ")) {
8834
+ end--;
8835
+ }
8836
+ return end === text.length ? text : text.slice(0, end);
8837
+ }
8838
+ function decodeQuotedPrintable(value, charset) {
8839
+ let decoder;
8840
+ try {
8841
+ decoder = new TextDecoder(charset || "utf8");
8842
+ } catch {
8843
+ decoder = new TextDecoder("utf8");
8844
+ }
8845
+ if (!/[\u0080-\u{10FFFF}]/u.test(value)) {
8846
+ const bytes = Buffer13.from(value, "latin1");
8847
+ let length = 0;
8848
+ for (let index = 0; index < bytes.length; index++) {
8849
+ const hex = bytes[index] === 61 ? value.slice(index + 1, index + 3) : "";
8850
+ if (/^[\da-f]{2}$/i.test(hex)) {
8851
+ bytes[length++] = Number.parseInt(hex, 16);
8852
+ index += 2;
8853
+ } else {
8854
+ bytes[length++] = bytes[index];
8855
+ }
8856
+ }
8857
+ return decoder.decode(bytes.subarray(0, length));
8858
+ }
8859
+ return value.replaceAll(/(?:=[\da-f]{2})+/gi, (run) => decoder.decode(Buffer13.from(run.replaceAll("=", ""), "hex")));
8860
+ }
8861
+ function quotedPrintableValues(text) {
8862
+ if (!/quoted-printable/i.test(text)) {
8863
+ return text;
8864
+ }
8865
+ const lines2 = text.split(LINE_BREAK);
8866
+ const out = [];
8867
+ for (let i = 0; i < lines2.length; i++) {
8868
+ const line = lines2[i];
8869
+ const colon = valueColon(line);
8870
+ const parameters = colon === -1 ? "" : line.slice(0, colon);
8871
+ if (colon === -1 || !QUOTED_PRINTABLE.test(parameters)) {
8872
+ out.push(line);
8873
+ continue;
8874
+ }
8875
+ const charset = /;\s*charset\s*=\s*"?([\w.:-]+)/i.exec(parameters)?.[1];
8876
+ const parts = [trimSpaceEnd(line.slice(colon + 1))];
8877
+ while (parts.at(-1).endsWith("=") && i + 1 < lines2.length) {
8878
+ parts[parts.length - 1] = parts.at(-1).slice(0, -1);
8879
+ parts.push(trimSpaceEnd(lines2[++i]));
8880
+ }
8881
+ out.push(line.slice(0, colon + 1) + decodeQuotedPrintable(parts.join(""), charset));
8882
+ }
8883
+ return out.join("\n");
8884
+ }
8885
+ function hasQuotedPrintable(text) {
8886
+ const unfolded = text.replaceAll(FOLD, "");
8887
+ if (!/quoted-printable/i.test(unfolded)) {
8888
+ return false;
8889
+ }
8890
+ return unfolded.split(LINE_BREAK).some((line) => {
8891
+ const colon = valueColon(line);
8892
+ return colon !== -1 && QUOTED_PRINTABLE.test(line.slice(0, colon));
8893
+ });
8894
+ }
8895
+ function shownText(text, full = true) {
8896
+ const unfolded = text.replaceAll(FOLD, "");
8897
+ const shown = /* @__PURE__ */ new Set([text, readEscapes(unfolded)]);
8898
+ let decoded = unfolded;
8899
+ if (full) {
8900
+ decoded = quotedPrintableValues(unfolded);
8901
+ if (decoded !== unfolded) {
8902
+ shown.add(readEscapes(decoded));
8903
+ if (unfolded !== text) {
8904
+ shown.add(quotedPrintableValues(text));
8905
+ }
8906
+ }
8907
+ }
8908
+ if (/\\[^nN,;\\]/.test(decoded)) {
8909
+ shown.add(readEscapes(decoded, true));
8910
+ }
8911
+ return [...shown].reverse().join("\n");
8912
+ }
8913
+ function htmlDescriptions(text) {
8914
+ if (!/[<&]|altrep/i.test(text)) {
8915
+ return "";
8916
+ }
8917
+ const html = [];
8918
+ for (const line of text.replaceAll(FOLD, "").split(LINE_BREAK)) {
8919
+ const colon = valueColon(line);
8920
+ if (colon === -1) {
8921
+ continue;
8922
+ }
8923
+ const altrep = /;\s*altrep\s*=\s*"([^"]*)"/i.exec(line.slice(0, colon))?.[1];
8924
+ if (altrep) {
8925
+ html.push(`<iframe src="${altrep.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;")}"></iframe>`);
8926
+ }
8927
+ if (!HTML_PROPERTIES.test(line)) {
8928
+ continue;
8929
+ }
8930
+ const value = readEscapes(line.slice(colon + 1));
8931
+ if (/[<&]/.test(value)) {
8932
+ html.push(value);
8933
+ }
8934
+ }
8935
+ return html.join("\n");
8936
+ }
8937
+ var BINARY = /;\s*(?:(?:encoding\s*=\s*)?"?(?:b|base64)"?|value\s*=\s*"?binary"?)\s*(?:;|$)/i;
8938
+ function withoutBinaryValues(text) {
8939
+ if (!/base64|binary|encoding\s*=\s*"?b|;\s*b\s*[;:]/i.test(text)) {
8940
+ return text;
8941
+ }
8942
+ const lines2 = text.split(LINE_BREAK);
8943
+ const out = [];
8944
+ for (let i = 0; i < lines2.length; i++) {
8945
+ const line = lines2[i];
8946
+ const colon = valueColon(line);
8947
+ if (colon === -1 || !BINARY.test(line.slice(0, colon))) {
8948
+ out.push(line);
8949
+ continue;
8950
+ }
8951
+ const value = [line.slice(colon + 1)];
8952
+ let next = i + 1;
8953
+ while (next < lines2.length && (lines2[next].startsWith(" ") || lines2[next].startsWith(" "))) {
8954
+ value.push(lines2[next++]);
8955
+ }
8956
+ if (!value.every((part) => /^[\w+/=\s]*$/.test(part))) {
8957
+ for (let index = i; index < next; index++) {
8958
+ out.push(lines2[index]);
8959
+ }
8960
+ i = next - 1;
8961
+ continue;
8962
+ }
8963
+ while (next < lines2.length && lines2[next] !== "" && /^[\w+/=]+$/.test(lines2[next])) {
8964
+ value.push(lines2[next++]);
8965
+ }
8966
+ if (next < lines2.length && lines2[next] === "") {
8967
+ next++;
8968
+ }
8969
+ i = next - 1;
8970
+ const name = line.slice(0, colon).split(";")[0].split(".").pop().trim().toLowerCase();
8971
+ out.push(MEDIA_PROPERTIES.has(name) ? line.slice(0, colon + 1) : line.slice(0, colon + 1) + Buffer13.from(value.join("").replaceAll(/\s/g, ""), "base64").toString("utf8"));
8972
+ }
8973
+ return out.join("\n");
8974
+ }
8975
+ var HTML_TYPES = /* @__PURE__ */ new Set(["text/html", "application/xhtml+xml", "image/svg+xml", "text/xml", "application/xml"]);
8976
+ var HTML_EXTENSIONS = /* @__PURE__ */ new Set(["html", "htm", "shtml", "xhtml", "xht", "svg", "xml"]);
8977
+ var CARD_TYPES = /* @__PURE__ */ new Set(["text/calendar", "text/x-vcalendar", "application/ics", "text/vcard", "text/x-vcard", "text/directory"]);
8978
+ var CARD_EXTENSIONS = /* @__PURE__ */ new Set(["ics", "ical", "ifb", "vcs", "vcf", "vcard"]);
8979
+ var MESSAGE_TYPES = /* @__PURE__ */ new Set(["message/rfc822", "message/global"]);
8980
+ function extensionOf2(filename) {
8981
+ let end = filename.length;
8982
+ while (end > 0 && (filename[end - 1] === "." || filename[end - 1] === " ")) {
8983
+ end--;
8984
+ }
8985
+ const name = filename.slice(0, end).trim().toLowerCase();
8986
+ const index = name.lastIndexOf(".");
8987
+ return index !== -1 && index < name.length - 1 ? name.slice(index + 1) : null;
8988
+ }
8989
+ function extensionsOf(attachment) {
8990
+ const names = [];
8991
+ if (typeof attachment.filename === "string") {
8992
+ names.push(attachment.filename);
8993
+ }
8994
+ const { headers } = attachment;
8995
+ if (headers && typeof headers.get === "function") {
8996
+ for (const [field, parameter] of [["content-type", "name"], ["content-disposition", "filename"]]) {
8997
+ const value = headers.get(field)?.params?.[parameter];
8998
+ if (typeof value === "string" && value !== "") {
8999
+ names.push(value);
9000
+ }
9001
+ }
9002
+ }
9003
+ return new Set(names.flatMap((name) => [extensionOf2(name), extensionOf(name)]).filter(Boolean));
9004
+ }
9005
+ function charsetOf(attachment) {
9006
+ const { headers } = attachment;
9007
+ const charset = headers && typeof headers.get === "function" ? headers.get("content-type")?.params?.charset : null;
9008
+ return typeof charset === "string" ? charset.toLowerCase() : "";
9009
+ }
9010
+ function documentsOf(attachments, until) {
9011
+ const documents = [];
9012
+ let bytes = 0;
9013
+ let opened = 0;
9014
+ for (const attachment of attachments) {
9015
+ const { content } = attachment ?? {};
9016
+ if (!Buffer13.isBuffer(content) || content.length === 0) {
9017
+ continue;
9018
+ }
9019
+ const type = typeof attachment.contentType === "string" ? attachment.contentType.toLowerCase() : "";
9020
+ const extensions = extensionsOf(attachment);
9021
+ const has = (set) => [...extensions].some((name) => set.has(name));
9022
+ if (MESSAGE_TYPES.has(type) || extensions.has("eml") || extensions.has("u8msg")) {
9023
+ continue;
9024
+ }
9025
+ const isHtml = HTML_TYPES.has(type) || has(HTML_EXTENSIONS);
9026
+ const isCard = !isHtml && (CARD_TYPES.has(type) || has(CARD_EXTENSIONS));
9027
+ const isText = isCard || !isHtml && type === "text/plain";
9028
+ if (!isHtml && !isText) {
9029
+ continue;
9030
+ }
9031
+ if (!isText && ++opened > MAX_ATTACHED || bytes + content.length > MAX_ATTACHED_BYTES) {
9032
+ documents.tooComplex = true;
9033
+ return documents;
9034
+ }
9035
+ if (Date.now() > until) {
9036
+ documents.incomplete = true;
9037
+ return documents;
9038
+ }
9039
+ bytes += content.length;
9040
+ const text = decodeText(content, charsetOf(attachment));
9041
+ if (isHtml) {
9042
+ documents.push({ html: text });
9043
+ continue;
9044
+ }
9045
+ if (!isCard) {
9046
+ documents.push({ text });
9047
+ continue;
9048
+ }
9049
+ const readable = withoutBinaryValues(text);
9050
+ const full = readable.length <= MAX_SHOWN_BYTES;
9051
+ if (!full && hasQuotedPrintable(readable)) {
9052
+ documents.tooComplex = true;
9053
+ continue;
9054
+ }
9055
+ documents.push({ text: shownText(readable, full) });
9056
+ const html = htmlDescriptions(readable);
9057
+ if (html !== "") {
9058
+ documents.push({ html });
9059
+ }
9060
+ }
9061
+ return documents;
9062
+ }
9063
+ function carriedLinkHosts(mail, {
9064
+ mails = [],
9065
+ attachments = [],
9066
+ maxHosts = 250,
9067
+ hostsInText = false
9068
+ } = {}) {
9069
+ const hosts = /* @__PURE__ */ new Set();
9070
+ const loose = /* @__PURE__ */ new Set();
9071
+ const seen = /* @__PURE__ */ new Set();
9072
+ const seenBare = /* @__PURE__ */ new Set();
9073
+ const seenLoose = /* @__PURE__ */ new Set();
9074
+ let more = false;
9075
+ let tooComplex = false;
9076
+ const done = () => more;
9077
+ const looseDone = () => more || loose.size > maxHosts;
9078
+ const addLoose = (host) => {
9079
+ if (!looseDone()) {
9080
+ loose.add(host);
9081
+ }
9082
+ };
9083
+ const until = Date.now() + MAX_READ_TIME;
9084
+ let incomplete = false;
9085
+ const late = () => {
9086
+ if (!incomplete && Date.now() > until) {
9087
+ incomplete = true;
9088
+ }
9089
+ return incomplete;
9090
+ };
9091
+ const carried = documentsOf(attachments, until);
9092
+ tooComplex = Boolean(carried.tooComplex);
9093
+ incomplete = Boolean(carried.incomplete);
9094
+ const queue = [mail, ...mails, ...carried].map((document) => ({ document, depth: 0 }));
9095
+ let depth = 0;
9096
+ let embedded = 0;
9097
+ let embeddedLength = 0;
9098
+ const embed = (html) => {
9099
+ if (depth >= MAX_EMBED_DEPTH || embedded >= MAX_EMBEDDED || embeddedLength + html.length > MAX_EMBEDDED_LENGTH) {
9100
+ tooComplex = true;
9101
+ return;
9102
+ }
9103
+ embedded++;
9104
+ embeddedLength += html.length;
9105
+ queue.push({ document: { html }, depth: depth + 1 });
9106
+ };
9107
+ const add = (value) => {
9108
+ if (more || typeof value !== "string" || value === "" || seen.has(value)) {
9109
+ return;
9110
+ }
9111
+ if (seen.size < MAX_SEEN) {
9112
+ seen.add(value);
9113
+ }
9114
+ if (/^\s*data:/i.test(value)) {
9115
+ const html = dataDocument(value);
9116
+ if (html !== null) {
9117
+ embed(html);
9118
+ }
9119
+ return;
9120
+ }
9121
+ const found = hostsOf(value);
9122
+ if (found.unresolved) {
9123
+ tooComplex = true;
9124
+ }
9125
+ for (const host of found) {
9126
+ if (hosts.has(host)) {
9127
+ continue;
9128
+ }
9129
+ if (hosts.size >= maxHosts) {
9130
+ more = true;
9131
+ return;
9132
+ }
9133
+ hosts.add(host);
9134
+ }
9135
+ };
9136
+ const readText = (source, { cutStart = false, cutEnd = false } = {}) => {
9137
+ for (const match of source.matchAll(URL_START)) {
9138
+ if (more) {
9139
+ break;
9140
+ }
9141
+ if (cutStart && match.index === 0) {
9142
+ continue;
9143
+ }
9144
+ if (cutEnd && match.index + match[0].length === source.length) {
9145
+ const value = match[0];
9146
+ const at = /^www\./i.test(value) ? 0 : value.indexOf("//") + 2;
9147
+ if (/[/?#\\]/.test(value.slice(at))) {
9148
+ add(value);
9149
+ } else if (source.length - match.index > CHUNK_OVERLAP) {
9150
+ tooComplex = true;
9151
+ }
9152
+ continue;
9153
+ }
9154
+ add(match[0]);
9155
+ }
9156
+ const from = cutStart ? 1 : 0;
9157
+ bareHosts(source, add, {
9158
+ done,
9159
+ seen: seenBare,
9160
+ from,
9161
+ cutEnd
9162
+ });
9163
+ if (hostsInText && !looseDone()) {
9164
+ looseHosts(source, addLoose, {
9165
+ from,
9166
+ cutEnd,
9167
+ seen: seenLoose,
9168
+ done: looseDone
9169
+ });
9170
+ }
9171
+ };
9172
+ for (const element of queue) {
9173
+ if (more || late()) {
9174
+ break;
9175
+ }
9176
+ ({ depth } = element);
9177
+ const { document } = element;
9178
+ const html = withoutNul(typeof document?.html === "string" ? document.html : "");
9179
+ const text = withoutNul(typeof document?.text === "string" ? document.text : "");
9180
+ for (const [name, value] of attributesOf(html)) {
9181
+ if (more) {
9182
+ break;
9183
+ }
9184
+ if (LINK_ATTRIBUTES.has(name)) {
9185
+ linksOf(name, value, add, embed);
9186
+ }
9187
+ }
9188
+ lenientLinks(html, add, done, embed);
9189
+ for (const pattern of [CSS_URL, CSS_IMPORT]) {
9190
+ for (const [, link] of html.matchAll(pattern)) {
9191
+ if (more) {
9192
+ break;
9193
+ }
9194
+ add(decodeEntities(link, { attribute: true }));
9195
+ }
9196
+ }
9197
+ if (!more) {
9198
+ readText(text);
9199
+ }
9200
+ for (const chunk2 of chunksOf(html)) {
9201
+ if (more || late()) {
9202
+ break;
9203
+ }
9204
+ readText(decodeEntities(chunk2.text), chunk2);
9205
+ }
9206
+ }
9207
+ if (!more && !incomplete) {
9208
+ for (const name of loose) {
9209
+ if (hosts.size >= maxHosts) {
9210
+ break;
9211
+ }
9212
+ const [host] = hostsOf(`http://${name}/`);
9213
+ if (host) {
9214
+ hosts.add(host);
9215
+ }
9216
+ }
9217
+ }
9218
+ return {
9219
+ hosts: [...hosts],
9220
+ more,
9221
+ tooComplex,
9222
+ incomplete
9223
+ };
9224
+ }
9225
+
9226
+ // src/is-arbitrary.js
9227
+ import { parse as parseDomain4 } from "tldts";
8135
9228
  var GTUBE = "XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X";
8136
9229
  var BLOCKED_SUBJECT = /cheecck y0ur acc0untt|\brecorded\s+you\s+(?:masturbating|jerking|touching\s+yourself|watching\s+porn)\b|personal data has leaked|private information has been stolen/i;
8137
9230
  var HACKED_SUBJECT = /\byou['’]ve been hacked\b|\baccount is hacked\b|\b(?:i|we)(?:\s+have|['’]ve)?\s+recorded\s+you\b|\brecorded\s+you\s+(?:doing|while|watching|through|on\s+(?:cam|camera|video|webcam))\b/i;
@@ -8322,13 +9415,13 @@ function joinsDisplay(brand, display, name) {
8322
9415
  return false;
8323
9416
  }
8324
9417
  function isOfficial({ brand, official }, domain, display, shared = true) {
8325
- const parsed = parseDomain3(domain);
9418
+ const parsed = parseDomain4(domain);
8326
9419
  const name = parsed.domainWithoutSuffix ?? "";
8327
9420
  const compact = brand.replaceAll(" ", "");
8328
9421
  if (parsed.publicSuffix === compact || compact.length >= 5 && joinsDisplay(brand, display, name) && !JOINED_WORDS.some((word) => name.slice(compact.length).includes(word))) {
8329
9422
  return true;
8330
9423
  }
8331
- return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || parseDomain3(entry).domain !== null) && (domain === entry || domain.endsWith(`.${entry}`)) : name === entry);
9424
+ return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || parseDomain4(entry).domain !== null) && (domain === entry || domain.endsWith(`.${entry}`)) : name === entry);
8332
9425
  }
8333
9426
  function headerString(mail, name) {
8334
9427
  const value = mail.headers?.get?.(name);
@@ -8430,7 +9523,7 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
8430
9523
  }
8431
9524
  } else if (claimed && isWholeName(name, claimed)) {
8432
9525
  const domain = claimed[1];
8433
- const brand = MAILBOXES.has(parseDomain3(domain).domainWithoutSuffix) ? null : DISPLAY_BRANDS.find((entry) => isOfficial(entry, domain, "", false) && !isOfficial(entry, session.originalFromAddressDomain, ""));
9526
+ const brand = MAILBOXES.has(parseDomain4(domain).domainWithoutSuffix) ? null : DISPLAY_BRANDS.find((entry) => isOfficial(entry, domain, "", false) && !isOfficial(entry, session.originalFromAddressDomain, ""));
8434
9527
  if (brand) {
8435
9528
  hit("FROM_NAME_BRAND", 2, `Display name is an address of "${brand.brand}" but the message is from ${fromRoot}`, "PHISHING");
8436
9529
  }
@@ -8701,21 +9794,21 @@ async function withTimeout(promise, ms, fallback) {
8701
9794
  }
8702
9795
  }
8703
9796
  async function toBuffer(source) {
8704
- if (Buffer13.isBuffer(source)) {
9797
+ if (Buffer14.isBuffer(source)) {
8705
9798
  return source;
8706
9799
  }
8707
9800
  if (typeof source === "string") {
8708
- return Buffer13.from(source, "utf8");
9801
+ return Buffer14.from(source, "utf8");
8709
9802
  }
8710
9803
  if (source instanceof Uint8Array) {
8711
- return Buffer13.from(source);
9804
+ return Buffer14.from(source);
8712
9805
  }
8713
9806
  if (source && typeof source[Symbol.asyncIterator] === "function") {
8714
9807
  const chunks = [];
8715
9808
  for await (const chunk2 of source) {
8716
- chunks.push(Buffer13.isBuffer(chunk2) ? chunk2 : Buffer13.from(chunk2));
9809
+ chunks.push(Buffer14.isBuffer(chunk2) ? chunk2 : Buffer14.from(chunk2));
8717
9810
  }
8718
- return Buffer13.concat(chunks);
9811
+ return Buffer14.concat(chunks);
8719
9812
  }
8720
9813
  throw new TypeError("A message must be a Buffer, a string, a Uint8Array or a readable stream");
8721
9814
  }
@@ -8737,6 +9830,19 @@ var DEFAULTS2 = {
8737
9830
  cloudflare: true,
8738
9831
  adult: true,
8739
9832
  maxHosts: 25,
9833
+ // Also read the links of the whole message and of what it carries
9834
+ // (attached messages, HTML, SVG and XML files, text files, invitations
9835
+ // and contact cards, documents in iframes and data: URLs) when link
9836
+ // hosts are looked up, for at most five seconds: off by default, as it
9837
+ // reads all of it, up to 50 MB of attachments.
9838
+ attachments: false,
9839
+ // Milliseconds the link lookups may take in all (default: timeout).
9840
+ timeout: void 0,
9841
+ // Also look up host names written in the text without a link or a path
9842
+ // ("evil.example"), which mail clients make links of, as far as there is
9843
+ // room: off by default, as a quoted reply or a signature may name any
9844
+ // site (they are checked for lookalikes either way).
9845
+ hostsInText: false,
8740
9846
  // Characters of text read for links (twice as many of HTML): more than
8741
9847
  // for the classifier (maxLength), as a link anywhere in a message may be
8742
9848
  // followed; a longer message sets results.linksTruncated.
@@ -8849,7 +9955,7 @@ function fromDomain(mail) {
8849
9955
  function withHeader(raw) {
8850
9956
  const first = raw.subarray(0, 1e3).toString("latin1");
8851
9957
  const headerless = raw.length > 0 && !/^(?:[!-9;-~]+[ \t]*:|From |[\r\n])/.test(first);
8852
- return headerless ? Buffer13.concat([Buffer13.from("\r\n"), raw]) : raw;
9958
+ return headerless ? Buffer14.concat([Buffer14.from("\r\n"), raw]) : raw;
8853
9959
  }
8854
9960
  var SpamScanner = class {
8855
9961
  /**
@@ -9011,7 +10117,10 @@ var SpamScanner = class {
9011
10117
  async scanFile(file, options) {
9012
10118
  return this.scan(await readFile(file), options);
9013
10119
  }
9014
- async checkLinks(links, config, hosts = [], from = "") {
10120
+ // (`from`: the sender's domain; `carried`: the link hosts of the whole
10121
+ // message and of what it carries, see carriedLinkHosts)
10122
+ async checkLinks(links, config, hosts = [], options = {}) {
10123
+ const { from = "", carried = null } = typeof options === "string" ? { from: options } : options;
9015
10124
  const phishing = [];
9016
10125
  const homographs = [];
9017
10126
  const seenHosts = /* @__PURE__ */ new Set();
@@ -9067,7 +10176,11 @@ var SpamScanner = class {
9067
10176
  for (const host of hosts) {
9068
10177
  lookalike(host, { source: "text" });
9069
10178
  }
9070
- const ordered = [...new Set([...found.filter((link) => link.text), ...found.filter((link) => !link.text), ...bare].map((link) => lookupName(destination(link))).filter(Boolean))];
10179
+ const carriedHosts = (carried?.hosts ?? []).map((host) => lookupName(host)).filter(Boolean);
10180
+ for (const host of carriedHosts) {
10181
+ seenHosts.add(host);
10182
+ }
10183
+ const ordered = [.../* @__PURE__ */ new Set([...[...found.filter((link) => link.text), ...found.filter((link) => !link.text), ...bare].map((link) => lookupName(destination(link))).filter(Boolean), ...carriedHosts])];
9071
10184
  const firsts = /* @__PURE__ */ new Map();
9072
10185
  for (const host of ordered) {
9073
10186
  const domain = registrableDomain(host);
@@ -9079,6 +10192,7 @@ var SpamScanner = class {
9079
10192
  const domains = [...new Set(checked.map((host) => registrableDomain(host)))];
9080
10193
  const blocked = [];
9081
10194
  let answered = 0;
10195
+ const linkTimeout = Number(config.phishing.timeout) > 0 ? Number(config.phishing.timeout) : config.timeout;
9082
10196
  const cloudflare = async () => {
9083
10197
  await withTimeout(Promise.all(checked.map(async (host) => {
9084
10198
  const found2 = await this.dns.checkCloudflare([host], { adult: config.phishing.adult });
@@ -9086,12 +10200,12 @@ var SpamScanner = class {
9086
10200
  if (!found2.unanswered?.length) {
9087
10201
  answered++;
9088
10202
  }
9089
- })), config.timeout, null);
10203
+ })), linkTimeout, null);
9090
10204
  return { found: [...blocked], unanswered: checked.length - answered };
9091
10205
  };
9092
10206
  const [cloudflareResult, listed] = await Promise.all([
9093
10207
  config.phishing.cloudflare && checked.length > 0 ? cloudflare() : { found: [], unanswered: 0 },
9094
- config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain), config.timeout, []) : []
10208
+ config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain), linkTimeout, []) : []
9095
10209
  ]);
9096
10210
  for (const { host, category } of cloudflareResult.found) {
9097
10211
  phishing.push(finding(category === "malware" ? { type: "malicious_domain", domain: host, message: `Link hostname ${host} is blocked by Cloudflare's malware filtering as phishing or malware` } : { type: "adult_domain", domain: host, message: `Link hostname ${host} was detected by Cloudflare's family filtering to contain adult-related content` }));
@@ -9107,7 +10221,8 @@ var SpamScanner = class {
9107
10221
  return {
9108
10222
  phishing,
9109
10223
  homographs,
9110
- uncheckedHosts: seenHosts.size - checked.length,
10224
+ // (at least one when the message has more hosts than were read)
10225
+ uncheckedHosts: Math.max(seenHosts.size - checked.length, carried?.more ? 1 : 0),
9111
10226
  timedOutHosts: cloudflareResult.unanswered
9112
10227
  };
9113
10228
  }
@@ -9279,10 +10394,17 @@ ${visibleText(html.slice(0, config.maxLength * 2)).text}`, { maxLength: config.m
9279
10394
  styled: plainObfuscation.styled || shownObfuscation.styled
9280
10395
  };
9281
10396
  const unopened = [];
9282
- const attached = await expandAttachments(mail.attachments, parseErrors, void 0, unopened);
10397
+ const opened = [];
10398
+ const attached = await expandAttachments(mail.attachments, parseErrors, void 0, { unopened, mails: opened });
10399
+ const carried = config.phishing.attachments === true && (config.phishing.cloudflare || config.dnsbl.domain?.length > 0) ? carriedLinkHosts(mail, {
10400
+ mails: opened,
10401
+ attachments: attached,
10402
+ maxHosts: config.phishing.maxHosts,
10403
+ hostsInText: config.phishing.hostsInText === true
10404
+ }) : null;
9283
10405
  const attachments = config.attachments === false ? [] : inspectAttachments(attached).filter((item) => config.macros !== false || !["macro", "pdf_active", "rtf_object"].includes(item.type)).map((item) => finding(item));
9284
10406
  const [links, authentication, checkedReputation, dnsbl, virusScan, toxicity, nsfw] = await Promise.all([
9285
- this.checkLinks(checkedLinks, config, extracted.hosts, fromDomain(mail)),
10407
+ this.checkLinks(checkedLinks, config, extracted.hosts, { from: fromDomain(mail), carried }),
9286
10408
  config.authenticationResults && typeof config.authenticationResults === "object" ? normalizeAuthOutput(config.authenticationResults) : config.authentication && session.remoteAddress ? withTimeout(authenticate(raw, {
9287
10409
  timeout: config.timeout,
9288
10410
  ...typeof config.authentication === "object" ? config.authentication : {},
@@ -9410,6 +10532,14 @@ ${visibleText(html.slice(0, config.maxLength * 2)).text}`, { maxLength: config.m
9410
10532
  // Whether the message has more text than phishing.maxLength, whose
9411
10533
  // links were not read.
9412
10534
  linksTruncated,
10535
+ // Whether a link host of the message or of what it carries was
10536
+ // never read whole (it runs past where long text is cut to be
10537
+ // read, it goes through more security gateways than are
10538
+ // unwrapped, or it is in more documents than are read), and whether
10539
+ // an attachment was left unread for time: in either case not every
10540
+ // link was checked (see phishing.attachments).
10541
+ linksTooComplex: Boolean(carried?.tooComplex),
10542
+ linksIncomplete: Boolean(carried?.incomplete),
9413
10543
  idnHomographAttack: {
9414
10544
  detected: links.homographs.length > 0,
9415
10545
  domains: links.homographs,
@@ -9421,6 +10551,9 @@ ${visibleText(html.slice(0, config.maxLength * 2)).text}`, { maxLength: config.m
9421
10551
  language: extracted.language,
9422
10552
  tokens: extracted.words,
9423
10553
  mail,
10554
+ // (the attachments of the message and of its attached messages, as
10555
+ // read, an attached message's named after it)
10556
+ attached,
9424
10557
  version: VERSION,
9425
10558
  metrics: { totalTime: time }
9426
10559
  };
@@ -9773,13 +10906,13 @@ async function readMessage(stream, maxSize) {
9773
10906
  for (; ; ) {
9774
10907
  const { value, done } = await iterator.next();
9775
10908
  if (done) {
9776
- return { data: Buffer14.concat(chunks), complete: true, rest: iterator };
10909
+ return { data: Buffer15.concat(chunks), complete: true, rest: iterator };
9777
10910
  }
9778
- const chunk2 = Buffer14.from(value);
10911
+ const chunk2 = Buffer15.from(value);
9779
10912
  chunks.push(chunk2);
9780
10913
  size += chunk2.length;
9781
10914
  if (size > maxSize) {
9782
- return { data: Buffer14.concat(chunks), complete: false, rest: iterator };
10915
+ return { data: Buffer15.concat(chunks), complete: false, rest: iterator };
9783
10916
  }
9784
10917
  }
9785
10918
  }