!?,pfof`w=Bvpwqbojb!#`obpp>!pjwvbwjlmbvwklqjwzelooltjmdsqjnbqjozlsfqbwjlm`kboofmdfgfufolsfgbmlmznlvpevm`wjlm#evm`wjlmp`lnsbmjfppwqv`wvqfbdqffnfmw!#wjwof>!slwfmwjbofgv`bwjlmbqdvnfmwppf`lmgbqz`lszqjdkwobmdvbdfpf{`ovpjuf`lmgjwjlm?,elqn=\x0E\tpwbwfnfmwbwwfmwjlmAjldqbskz~#fopf#x\tplovwjlmptkfm#wkf#Bmbozwj`pwfnsobwfpgbmdfqlvppbwfoojwfgl`vnfmwpsvaojpkfqjnslqwbmwsqlwlwzsfjmeovfm`f%qbrvl8?,feef`wjufdfmfqboozwqbmpelqnafbvwjevowqbmpslqwlqdbmjyfgsvaojpkfgsqlnjmfmwvmwjo#wkfwkvnambjoMbwjlmbo#-el`vp+*8lufq#wkf#njdqbwjlmbmmlvm`fgellwfq!=\tf{`fswjlmofpp#wkbmf{sfmpjufelqnbwjlmeqbnftlqhwfqqjwlqzmgj`bwjlm`vqqfmwoz`obppMbnf`qjwj`jpnwqbgjwjlmfopftkfqfBof{bmgfqbssljmwfgnbwfqjbopaqlbg`bpwnfmwjlmfgbeejojbwf?,lswjlm=wqfbwnfmwgjeefqfmw,gfebvow-Sqfpjgfmwlm`oj`h>!ajldqbskzlwkfqtjpfsfqnbmfmwEqbm/KbjpKlooztllgf{sbmpjlmpwbmgbqgp?,pwzof=\tqfgv`wjlmGf`fnafq#sqfefqqfg@bnaqjgdflsslmfmwpAvpjmfpp#`lmevpjlm=\t?wjwof=sqfpfmwfgf{sobjmfgglfp#mlw#tlqogtjgfjmwfqeb`fslpjwjlmpmftpsbsfq?,wbaof=\tnlvmwbjmpojhf#wkf#fppfmwjboejmbm`jbopfof`wjlmb`wjlm>!,babmglmfgFgv`bwjlmsbqpfJmw+pwbajojwzvmbaof#wl?,wjwof=\tqfobwjlmpMlwf#wkbwfeej`jfmwsfqelqnfgwtl#zfbqpPjm`f#wkfwkfqfelqftqbssfq!=bowfqmbwfjm`qfbpfgAbwwof#lesfq`fjufgwqzjmd#wlmf`fppbqzslqwqbzfgfof`wjlmpFojybafwk?,jeqbnf=gjp`lufqzjmpvqbm`fp-ofmdwk8ofdfmgbqzDfldqbskz`bmgjgbwf`lqslqbwfplnfwjnfppfquj`fp-jmkfqjwfg?,pwqlmd=@lnnvmjwzqfojdjlvpol`bwjlmp@lnnjwwffavjogjmdpwkf#tlqogml#olmdfqafdjmmjmdqfefqfm`f`bmmlw#afeqfrvfm`zwzsj`boozjmwl#wkf#qfobwjuf8qf`lqgjmdsqfpjgfmwjmjwjboozwf`kmjrvfwkf#lwkfqjw#`bm#aff{jpwfm`fvmgfqojmfwkjp#wjnfwfofsklmfjwfnp`lsfsqb`wj`fpbgubmwbdf*8qfwvqm#Elq#lwkfqsqlujgjmdgfnl`qb`zalwk#wkf#f{wfmpjufpveefqjmdpvsslqwfg`lnsvwfqp#evm`wjlmsqb`wj`bopbjg#wkbwjw#nbz#afFmdojpk?,eqln#wkf#p`kfgvofggltmolbgp?,obafo=\tpvpsf`wfgnbqdjm9#3psjqjwvbo?,kfbg=\t\tnj`qlplewdqbgvboozgjp`vppfgkf#af`bnff{f`vwjufirvfqz-ipklvpfklog`lmejqnfgsvq`kbpfgojwfqboozgfpwqlzfgvs#wl#wkfubqjbwjlmqfnbjmjmdjw#jp#mlw`fmwvqjfpIbsbmfpf#bnlmd#wkf`lnsofwfgbodlqjwknjmwfqfpwpqfafoojlmvmgfejmfgfm`lvqbdfqfpjybaofjmuloujmdpfmpjwjufvmjufqpbosqlujpjlm+bowklvdkefbwvqjmd`lmgv`wfg*/#tkj`k#`lmwjmvfg.kfbgfq!=Efaqvbqz#mvnfqlvp#lufqeolt9`lnslmfmweqbdnfmwpf{`foofmw`lopsbm>!wf`kmj`bomfbq#wkf#Bgubm`fg#plvq`f#lef{sqfppfgKlmd#Hlmd#Eb`fallhnvowjsof#nf`kbmjpnfofubwjlmleefmpjuf?,elqn=\t\npslmplqfggl`vnfmw-lq#%rvlw8wkfqf#bqfwklpf#tklnlufnfmwpsql`fppfpgjeej`vowpvanjwwfgqf`lnnfmg`lmujm`fgsqlnlwjmd!#tjgwk>!-qfsob`f+`obppj`bo`lbojwjlmkjp#ejqpwgf`jpjlmpbppjpwbmwjmgj`bwfgfulovwjlm.tqbssfq!fmlvdk#wlbolmd#wkfgfojufqfg..=\x0E\t?\"..Bnfqj`bm#sqlwf`wfgMlufnafq#?,pwzof=?evqmjwvqfJmwfqmfw##lmaovq>!pvpsfmgfgqf`jsjfmwabpfg#lm#Nlqflufq/balojpkfg`loof`wfgtfqf#nbgffnlwjlmbofnfqdfm`zmbqqbwjufbgul`bwfps{8alqgfq`lnnjwwfggjq>!owq!fnsolzffpqfpfbq`k-#pfof`wfgpv``fpplq`vpwlnfqpgjpsobzfgPfswfnafqbgg@obpp+Eb`fallh#pvddfpwfgbmg#obwfqlsfqbwjmdfobalqbwfPlnfwjnfpJmpwjwvwf`fqwbjmozjmpwboofgelooltfqpIfqvpbofnwkfz#kbuf`lnsvwjmddfmfqbwfgsqlujm`fpdvbqbmwffbqajwqbqzqf`ldmjyftbmwfg#wls{8tjgwk9wkflqz#leafkbujlvqTkjof#wkffpwjnbwfgafdbm#wl#jw#af`bnfnbdmjwvgfnvpw#kbufnlqf#wkbmGjqf`wlqzf{wfmpjlmpf`qfwbqzmbwvqboozl``vqqjmdubqjbaofpdjufm#wkfsobwelqn-?,obafo=?ebjofg#wl`lnslvmgphjmgp#le#pl`jfwjfpbolmdpjgf#..%dw8\t\tplvwktfpwwkf#qjdkwqbgjbwjlmnbz#kbuf#vmfp`bsf+pslhfm#jm!#kqfe>!,sqldqbnnflmoz#wkf#`lnf#eqlngjqf`wlqzavqjfg#jmb#pjnjobqwkfz#tfqf?,elmw=?,Mlqtfdjbmpsf`jejfgsqlgv`jmdsbppfmdfq+mft#Gbwfwfnslqbqzej`wjlmboBewfq#wkffrvbwjlmpgltmolbg-qfdvobqozgfufolsfqbaluf#wkfojmhfg#wlskfmlnfmbsfqjlg#lewllowjs!=pvapwbm`fbvwlnbwj`bpsf`w#leBnlmd#wkf`lmmf`wfgfpwjnbwfpBjq#Elq`fpzpwfn#lelaif`wjufjnnfgjbwfnbhjmd#jwsbjmwjmdp`lmrvfqfgbqf#pwjoosql`fgvqfdqltwk#lekfbgfg#azFvqlsfbm#gjujpjlmpnlof`vofpeqbm`kjpfjmwfmwjlmbwwqb`wfg`kjogkllgbopl#vpfggfgj`bwfgpjmdbslqfgfdqff#leebwkfq#le`lmeoj`wp?,b=?,s=\t`bnf#eqlntfqf#vpfgmlwf#wkbwqf`fjujmdF{f`vwjuffufm#nlqfb``fpp#wl`lnnbmgfqSlojwj`bonvpj`jbmpgfoj`jlvpsqjplmfqpbgufmw#leVWE.;!#,=?\"X@GBWBX!=@lmwb`wPlvwkfqm#ad`lolq>!pfqjfp#le-#Jw#tbp#jm#Fvqlsfsfqnjwwfgubojgbwf-bssfbqjmdleej`jboppfqjlvpoz.obmdvbdfjmjwjbwfgf{wfmgjmdolmd.wfqnjmeobwjlmpv`k#wkbwdfw@llhjfnbqhfg#az?,avwwlm=jnsofnfmwavw#jw#jpjm`qfbpfpgltm#wkf#qfrvjqjmdgfsfmgfmw..=\t?\"..#jmwfqujftTjwk#wkf#`lsjfp#le`lmpfmpvptbp#avjowUfmfyvfob+elqnfqozwkf#pwbwfsfqplmmfopwqbwfdj`ebulvq#lejmufmwjlmTjhjsfgjb`lmwjmfmwujqwvbooztkj`k#tbpsqjm`jsof@lnsofwf#jgfmwj`bopklt#wkbwsqjnjwjufbtbz#eqlnnlof`vobqsqf`jpfozgjpploufgVmgfq#wkfufqpjlm>!=%maps8?,Jw#jp#wkf#Wkjp#jp#tjoo#kbuflqdbmjpnpplnf#wjnfEqjfgqj`ktbp#ejqpwwkf#lmoz#eb`w#wkbwelqn#jg>!sqf`fgjmdWf`kmj`boskzpj`jpwl``vqp#jmmbujdbwlqpf`wjlm!=psbm#jg>!plvdkw#wlafolt#wkfpvqujujmd~?,pwzof=kjp#gfbwkbp#jm#wkf`bvpfg#azsbqwjboozf{jpwjmd#vpjmd#wkftbp#djufmb#ojpw#leofufop#lemlwjlm#leLeej`jbo#gjpnjppfgp`jfmwjpwqfpfnaofpgvsoj`bwff{solpjufqf`lufqfgboo#lwkfqdboofqjfpxsbggjmd9sflsof#leqfdjlm#lebggqfppfpbppl`jbwfjnd#bow>!jm#nlgfqmpklvog#afnfwklg#leqfslqwjmdwjnfpwbnsmffgfg#wlwkf#Dqfbwqfdbqgjmdpffnfg#wlujftfg#bpjnsb`w#lmjgfb#wkbwwkf#Tlqogkfjdkw#lef{sbmgjmdWkfpf#bqf`vqqfmw!=`bqfevooznbjmwbjmp`kbqdf#le@obppj`bobggqfppfgsqfgj`wfgltmfqpkjs?gju#jg>!qjdkw!=\x0E\tqfpjgfm`fofbuf#wkf`lmwfmw!=bqf#lewfm##~*+*8\x0E\tsqlabaoz#Sqlefpplq.avwwlm!#qfpslmgfgpbzp#wkbwkbg#wl#afsob`fg#jmKvmdbqjbmpwbwvp#lepfqufp#bpVmjufqpbof{f`vwjlmbddqfdbwfelq#tkj`kjmef`wjlmbdqffg#wlkltfufq/#slsvobq!=sob`fg#lm`lmpwqv`wfof`wlqbopznalo#lejm`ovgjmdqfwvqm#wlbq`kjwf`w@kqjpwjbmsqfujlvp#ojujmd#jmfbpjfq#wlsqlefpplq\t%ow8\"..#feef`w#lebmbozwj`ptbp#wbhfmtkfqf#wkfwllh#lufqafojfe#jmBeqjhbbmpbp#ebq#bpsqfufmwfgtlqh#tjwkb#psf`jbo?ejfogpfw@kqjpwnbpQfwqjfufg\t\tJm#wkf#ab`h#jmwlmlqwkfbpwnbdbyjmfp=?pwqlmd=`lnnjwwffdlufqmjmddqlvsp#lepwlqfg#jmfpwbaojpkb#dfmfqbojwp#ejqpwwkfjq#ltmslsvobwfgbm#laif`w@bqjaafbmboolt#wkfgjpwqj`wptjp`lmpjmol`bwjlm-8#tjgwk9#jmkbajwfgPl`jbojpwIbmvbqz#2?,ellwfq=pjnjobqoz`klj`f#lewkf#pbnf#psf`jej`#avpjmfpp#Wkf#ejqpw-ofmdwk8#gfpjqf#wlgfbo#tjwkpjm`f#wkfvpfqBdfmw`lm`fjufgjmgf{-sksbp#%rvlw8fmdbdf#jmqf`fmwoz/eft#zfbqptfqf#bopl\t?kfbg=\t?fgjwfg#azbqf#hmltm`jwjfp#jmb``fpphfz`lmgfnmfgbopl#kbufpfquj`fp/ebnjoz#leP`kllo#le`lmufqwfgmbwvqf#le#obmdvbdfnjmjpwfqp?,laif`w=wkfqf#jp#b#slsvobqpfrvfm`fpbgul`bwfgWkfz#tfqfbmz#lwkfqol`bwjlm>fmwfq#wkfnv`k#nlqfqfeof`wfgtbp#mbnfglqjdjmbo#b#wzsj`botkfm#wkfzfmdjmffqp`lvog#mlwqfpjgfmwptfgmfpgbzwkf#wkjqg#sqlgv`wpIbmvbqz#1tkbw#wkfzb#`fqwbjmqfb`wjlmpsql`fpplqbewfq#kjpwkf#obpw#`lmwbjmfg!=?,gju=\t?,b=?,wg=gfsfmg#lmpfbq`k!=\tsjf`fp#le`lnsfwjmdQfefqfm`fwfmmfppfftkj`k#kbp#ufqpjlm>?,psbm=#??,kfbgfq=djufp#wkfkjpwlqjbmubovf>!!=sbggjmd93ujft#wkbwwldfwkfq/wkf#nlpw#tbp#elvmgpvapfw#lebwwb`h#lm`kjogqfm/sljmwp#lesfqplmbo#slpjwjlm9boofdfgoz@ofufobmgtbp#obwfqbmg#bewfqbqf#djufmtbp#pwjoop`qloojmdgfpjdm#lenbhfp#wkfnv`k#ofppBnfqj`bmp-\t\tBewfq#/#avw#wkfNvpfvn#leolvjpjbmb+eqln#wkfnjmmfplwbsbqwj`ofpb#sql`fppGlnjmj`bmulovnf#leqfwvqmjmdgfefmpjuf33s{\x7Fqjdknbgf#eqlnnlvpflufq!#pwzof>!pwbwfp#le+tkj`k#jp`lmwjmvfpEqbm`jp`lavjogjmd#tjwklvw#btjwk#plnftkl#tlvogb#elqn#leb#sbqw#leafelqf#jwhmltm#bp##Pfquj`fpol`bwjlm#bmg#lewfmnfbpvqjmdbmg#jw#jpsbsfqab`hubovfp#le\x0E\t?wjwof=>#tjmglt-gfwfqnjmffq%rvlw8#sobzfg#azbmg#fbqoz?,`fmwfq=eqln#wkjpwkf#wkqffsltfq#bmgle#%rvlw8jmmfqKWNO?b#kqfe>!z9jmojmf8@kvq`k#lewkf#fufmwufqz#kjdkleej`jbo#.kfjdkw9#`lmwfmw>!,`dj.ajm,wl#`qfbwfbeqjhbbmpfpsfqbmwleqbm/Kbjpobwujf)Mvojfwvuj)_(`f)Mwjmb(af)Mwjmb\fUh\fT{\fTN\n{I\np@\x04Fr\x0BBl\bQ\x7F\tA{\x0BUm\x05Gx\tA{\x01yp\x06YA\0zX\bTV\bWl\bUd\x04BM\x0BB{\npV\x0B@x\x04B\\\np@\x04Db\x04Gz\tal\npa\tfM\tuD\bV~\x04mx\x0BQ}\ndS\tp\\\bVK\bS]\bU|\x05oD\tkV\x0Bed\x0BHR\nb~\x04M`\nJp\x05oD\x04|Q\nLP\x04Sw\bTl\nAI\nxC\bWt\tBq\x05F`\x04Cm\x0BLm\tKx\t}t\bPv\ny\\\naB\tV\x7F\nZd\x04XU\x04li\tfr\ti@\tBH\x04BD\x04BV\t`V\n[]\tp_\tTn\n~A\nxR\tuD\t`{\bV@\tTn\tHK\tAJ\x0Bxs\x04Zf\nqI\x04Zf\x0BBM\x0B|j\t}t\bSM\nmC\x0BQ}pfquj`jlpbqw/A`volbqdfmwjmbabq`folmb`vborvjfqsvaoj`bglsqlgv`wlpslo/Awj`bqfpsvfpwbtjhjsfgjbpjdvjfmwfa/Vprvfgb`lnvmjgbgpfdvqjgbgsqjm`jsbosqfdvmwbp`lmwfmjglqfpslmgfqufmfyvfobsqlaofnbpgj`jfnaqfqfob`j/_mmlujfnaqfpjnjobqfpsqlzf`wlpsqldqbnbpjmpwjwvwlb`wjujgbgfm`vfmwqbf`lmln/Abjn/Mdfmfp`lmwb`wbqgfp`bqdbqmf`fpbqjlbwfm`j/_mwfo/Eelml`lnjpj/_m`bm`jlmfp`bsb`jgbgfm`lmwqbqbm/Mojpjpebulqjwlpw/Eqnjmlpsqlujm`jbfwjrvfwbpfofnfmwlpevm`jlmfpqfpvowbgl`bq/M`wfqsqlsjfgbgsqjm`jsjlmf`fpjgbgnvmj`jsbo`qfb`j/_mgfp`bqdbpsqfpfm`jb`lnfq`jbolsjmjlmfpfifq`j`jlfgjwlqjbopbobnbm`bdlmy/Mofygl`vnfmwlsfo/A`vobqf`jfmwfpdfmfqbofpwbqqbdlmbsq/M`wj`bmlufgbgfpsqlsvfpwbsb`jfmwfpw/E`mj`bplaifwjulp`lmwb`wlp\fHB\fIk\fHn\fH^\fHS\fHc\fHU\fId\fHn\fH{\fHC\fHR\fHT\fHR\fHI\fHc\fHY\fHn\fH\\\fHU\fIk\fHy\fIg\fHd\fHy\fIm\fHw\fH\\\fHU\fHR\fH@\fHR\fHJ\fHy\fHU\fHR\fHT\fHA\fIl\fHU\fIm\fHc\fH\\\fHU\fIl\fHB\fId\fHn\fHJ\fHS\fHD\fH@\fHR\fHHgjsolgl`p\fHT\fHB\fHC\fH\\\fIn\fHF\fHD\fHR\fHB\fHF\fHH\fHR\fHG\fHS\fH\\\fHx\fHT\fHH\fHH\fH\\\fHU\fH^\fIg\fH{\fHU\fIm\fHj\fH@\fHR\fH\\\fHJ\fIk\fHZ\fHU\fIm\fHd\fHz\fIk\fH^\fHC\fHJ\fHS\fHy\fHR\fHB\fHY\fIk\fH@\fHH\fIl\fHD\fH@\fIl\fHv\fHB\fI`\fHH\fHT\fHR\fH^\fH^\fIk\fHz\fHp\fIe\fH@\fHB\fHJ\fHJ\fHH\fHI\fHR\fHD\fHU\fIl\fHZ\fHU\fH\\\fHi\fH^\fH{\fHy\fHA\fIl\fHD\fH{\fH\\\fHF\fHR\fHT\fH\\\fHR\fHH\fHy\fHS\fHc\fHe\fHT\fIk\fH{\fHC\fIl\fHU\fIn\fHm\fHj\fH{\fIk\fHs\fIl\fHB\fHz\fIg\fHp\fHy\fHR\fH\\\fHi\fHA\fIl\fH{\fHC\fIk\fHH\fIm\fHB\fHY\fIg\fHs\fHJ\fIk\fHn\fHi\fH{\fH\\\fH|\fHT\fIk\fHB\fIk\fH^\fH^\fH{\fHR\fHU\fHR\fH^\fHf\fHF\fH\\\fHv\fHR\fH\\\fH|\fHT\fHR\fHJ\fIk\fH\\\fHp\fHS\fHT\fHJ\fHS\fH^\fH@\fHn\fHJ\fH@\fHD\fHR\fHU\fIn\fHn\fH^\fHR\fHz\fHp\fIl\fHH\fH@\fHs\fHD\fHB\fHS\fH^\fHk\fHT\fIk\fHj\fHD\fIk\fHD\fHC\fHR\fHy\fIm\fH^\fH^\fIe\fH{\fHA\fHR\fH{\fH\\\fIk\fH^\fHp\fH{\fHU\fH\\\fHR\fHB\fH^\fH{\fIk\fHF\fIk\fHp\fHU\fHR\fHI\fHk\fHT\fIl\fHT\fHU\fIl\fHy\fH^\fHR\fHL\fIl\fHy\fHU\fHR\fHm\fHJ\fIn\fH\\\fHH\fHU\fHH\fHT\fHR\fHH\fHC\fHR\fHJ\fHj\fHC\fHR\fHF\fHR\fHy\fHy\fI`\fHD\fHZ\fHR\fHB\fHJ\fIk\fHz\fHC\fHU\fIl\fH\\\fHR\fHC\fHz\fIm\fHJ\fH^\fH{\fIl`bwfdlqjfpf{sfqjfm`f?,wjwof=\x0E\t@lszqjdkw#ibubp`qjsw`lmgjwjlmpfufqzwkjmd?s#`obpp>!wf`kmloldzab`hdqlvmg?b#`obpp>!nbmbdfnfmw%`lsz8#132ibubP`qjsw`kbqb`wfqpaqfbg`qvnawkfnpfoufpklqjylmwbodlufqmnfmw@bojelqmjbb`wjujwjfpgjp`lufqfgMbujdbwjlmwqbmpjwjlm`lmmf`wjlmmbujdbwjlmbssfbqbm`f?,wjwof=?n`kf`hal{!#wf`kmjrvfpsqlwf`wjlmbssbqfmwozbp#tfoo#bpvmw$/#$VB.qfplovwjlmlsfqbwjlmpwfofujpjlmwqbmpobwfgTbpkjmdwlmmbujdbwlq-#>#tjmglt-jnsqfppjlm%ow8aq%dw8ojwfqbwvqfslsvobwjlmad`lolq>! fpsf`jbooz#`lmwfmw>!sqlgv`wjlmmftpofwwfqsqlsfqwjfpgfejmjwjlmofbgfqpkjsWf`kmloldzSbqojbnfmw`lnsbqjplmvo#`obpp>!-jmgf{Le+!`lm`ovpjlmgjp`vppjlm`lnslmfmwpajloldj`boQfulovwjlm\\`lmwbjmfqvmgfqpwllgmlp`qjsw=?sfqnjppjlmfb`k#lwkfqbwnlpskfqf#lmel`vp>!?elqn#jg>!sql`fppjmdwkjp-ubovfdfmfqbwjlm@lmefqfm`fpvapfrvfmwtfoo.hmltmubqjbwjlmpqfsvwbwjlmskfmlnfmlmgjp`jsojmfoldl-smd!#+gl`vnfmw/alvmgbqjfpf{sqfppjlmpfwwofnfmwAb`hdqlvmglvw#le#wkffmwfqsqjpf+!kwwsp9!#vmfp`bsf+!sbpptlqg!#gfnl`qbwj`?b#kqfe>!,tqbssfq!=\tnfnafqpkjsojmdvjpwj`s{8sbggjmdskjolplskzbppjpwbm`fvmjufqpjwzeb`jojwjfpqf`ldmjyfgsqfefqfm`fje#+wzsflenbjmwbjmfgul`bavobqzkzslwkfpjp-pvanjw+*8%bns8maps8bmmlwbwjlmafkjmg#wkfElvmgbwjlmsvaojpkfq!bppvnswjlmjmwqlgv`fg`lqqvswjlmp`jfmwjpwpf{soj`jwozjmpwfbg#legjnfmpjlmp#lm@oj`h>!`lmpjgfqfggfsbqwnfmwl``vsbwjlmpllm#bewfqjmufpwnfmwsqlmlvm`fgjgfmwjejfgf{sfqjnfmwNbmbdfnfmwdfldqbskj`!#kfjdkw>!ojmh#qfo>!-qfsob`f+,gfsqfppjlm`lmefqfm`fsvmjpknfmwfojnjmbwfgqfpjpwbm`fbgbswbwjlmlsslpjwjlmtfoo#hmltmpvssofnfmwgfwfqnjmfgk2#`obpp>!3s{8nbqdjmnf`kbmj`bopwbwjpwj`p`fofaqbwfgDlufqmnfmw\t\tGvqjmd#wgfufolsfqpbqwjej`jbofrvjubofmwlqjdjmbwfg@lnnjppjlmbwwb`knfmw?psbm#jg>!wkfqf#tfqfMfgfqobmgpafzlmg#wkfqfdjpwfqfgilvqmbojpweqfrvfmwozboo#le#wkfobmd>!fm!#?,pwzof=\x0E\tbaplovwf8#pvsslqwjmdf{wqfnfoz#nbjmpwqfbn?,pwqlmd=#slsvobqjwzfnsolznfmw?,wbaof=\x0E\t#`lopsbm>!?,elqn=\t##`lmufqpjlmbalvw#wkf#?,s=?,gju=jmwfdqbwfg!#obmd>!fmSlqwvdvfpfpvapwjwvwfjmgjujgvbojnslppjaofnvowjnfgjbbonlpw#boos{#plojg# bsbqw#eqlnpvaif`w#wljm#Fmdojpk`qjwj`jyfgf{`fsw#elqdvjgfojmfplqjdjmboozqfnbqhbaofwkf#pf`lmgk1#`obpp>!?b#wjwof>!+jm`ovgjmdsbqbnfwfqpsqlkjajwfg>#!kwws9,,gj`wjlmbqzsfq`fswjlmqfulovwjlmelvmgbwjlms{8kfjdkw9pv``fppevopvsslqwfqpnjoofmmjvnkjp#ebwkfqwkf#%rvlw8ml.qfsfbw8`lnnfq`jbojmgvpwqjbofm`lvqbdfgbnlvmw#le#vmleej`jbofeej`jfm`zQfefqfm`fp`llqgjmbwfgjp`objnfqf{sfgjwjlmgfufolsjmd`bo`vobwfgpjnsojejfgofdjwjnbwfpvapwqjmd+3!#`obpp>!`lnsofwfozjoovpwqbwfejuf#zfbqpjmpwqvnfmwSvaojpkjmd2!#`obpp>!spz`kloldz`lmejgfm`fmvnafq#le#bapfm`f#leel`vpfg#lmiljmfg#wkfpwqv`wvqfpsqfujlvpoz=?,jeqbnf=lm`f#bdbjmavw#qbwkfqjnnjdqbmwple#`lvqpf/b#dqlvs#leOjwfqbwvqfVmojhf#wkf?,b=%maps8\tevm`wjlm#jw#tbp#wkf@lmufmwjlmbvwlnlajofSqlwfpwbmwbddqfppjufbewfq#wkf#Pjnjobqoz/!#,=?,gju=`loof`wjlm\x0E\tevm`wjlmujpjajojwzwkf#vpf#leulovmwffqpbwwqb`wjlmvmgfq#wkf#wkqfbwfmfg)?\"X@GBWBXjnslqwbm`fjm#dfmfqbowkf#obwwfq?,elqn=\t?,-jmgf{Le+$j#>#38#j#?gjeefqfm`fgfulwfg#wlwqbgjwjlmppfbq`k#elqvowjnbwfozwlvqmbnfmwbwwqjavwfppl.`boofg#~\t?,pwzof=fubovbwjlmfnskbpjyfgb``fppjaof?,pf`wjlm=pv``fppjlmbolmd#tjwkNfbmtkjof/jmgvpwqjfp?,b=?aq#,=kbp#af`lnfbpsf`wp#leWfofujpjlmpveej`jfmwabphfwabooalwk#pjgfp`lmwjmvjmdbm#bqwj`of?jnd#bow>!bgufmwvqfpkjp#nlwkfqnbm`kfpwfqsqjm`jsofpsbqwj`vobq`lnnfmwbqzfeef`wp#legf`jgfg#wl!=?pwqlmd=svaojpkfqpIlvqmbo#legjeej`vowzeb`jojwbwfb``fswbaofpwzof-`pp!\nevm`wjlm#jmmlubwjlm=@lszqjdkwpjwvbwjlmptlvog#kbufavpjmfppfpGj`wjlmbqzpwbwfnfmwplewfm#vpfgsfqpjpwfmwjm#Ibmvbqz`lnsqjpjmd?,wjwof=\t\ngjsolnbwj``lmwbjmjmdsfqelqnjmdf{wfmpjlmpnbz#mlw#af`lm`fsw#le#lm`oj`h>!Jw#jp#boplejmbm`jbo#nbhjmd#wkfOv{fnalvqdbggjwjlmbobqf#`boofgfmdbdfg#jm!p`qjsw!*8avw#jw#tbpfof`wqlmj`lmpvanjw>!\t?\"..#Fmg#fof`wqj`boleej`jboozpvddfpwjlmwls#le#wkfvmojhf#wkfBvpwqbojbmLqjdjmboozqfefqfm`fp\t?,kfbg=\x0E\tqf`ldmjpfgjmjwjbojyfojnjwfg#wlBof{bmgqjbqfwjqfnfmwBgufmwvqfpelvq#zfbqp\t\t%ow8\"..#jm`qfbpjmdgf`lqbwjlmk0#`obpp>!lqjdjmp#lelaojdbwjlmqfdvobwjlm`obppjejfg+evm`wjlm+bgubmwbdfpafjmd#wkf#kjpwlqjbmp?abpf#kqfeqfsfbwfgoztjoojmd#wl`lnsbqbaofgfpjdmbwfgmlnjmbwjlmevm`wjlmbojmpjgf#wkfqfufobwjlmfmg#le#wkfp#elq#wkf#bvwklqjyfgqfevpfg#wlwbhf#sob`fbvwlmlnlvp`lnsqlnjpfslojwj`bo#qfpwbvqbmwwtl#le#wkfEfaqvbqz#1rvbojwz#leptelaif`w-vmgfqpwbmgmfbqoz#bootqjwwfm#azjmwfqujftp!#tjgwk>!2tjwkgqbtboeolbw9ofewjp#vpvbooz`bmgjgbwfpmftpsbsfqpnzpwfqjlvpGfsbqwnfmwafpw#hmltmsbqojbnfmwpvssqfppfg`lmufmjfmwqfnfnafqfggjeefqfmw#pzpwfnbwj`kbp#ofg#wlsqlsbdbmgb`lmwqloofgjmeovfm`fp`fqfnlmjbosql`objnfgSqlwf`wjlmoj#`obpp>!P`jfmwjej``obpp>!ml.wqbgfnbqhpnlqf#wkbm#tjgfpsqfbgOjafqbwjlmwllh#sob`fgbz#le#wkfbp#olmd#bpjnsqjplmfgBggjwjlmbo\t?kfbg=\t?nObalqbwlqzMlufnafq#1f{`fswjlmpJmgvpwqjboubqjfwz#leeolbw9#ofeGvqjmd#wkfbppfppnfmwkbuf#affm#gfbop#tjwkPwbwjpwj`pl``vqqfm`f,vo=?,gju=`ofbqej{!=wkf#svaoj`nbmz#zfbqptkj`k#tfqflufq#wjnf/pzmlmznlvp`lmwfmw!=\tsqfpvnbaozkjp#ebnjozvpfqBdfmw-vmf{sf`wfgjm`ovgjmd#`kboofmdfgb#njmlqjwzvmgfejmfg!afolmdp#wlwbhfm#eqlnjm#L`wlafqslpjwjlm9#pbjg#wl#afqfojdjlvp#Efgfqbwjlm#qltpsbm>!lmoz#b#eftnfbmw#wkbwofg#wl#wkf..=\x0E\t?gju#?ejfogpfw=Bq`kajpkls#`obpp>!mlafjmd#vpfgbssqlb`kfpsqjujofdfpmlp`qjsw=\tqfpvowp#jmnbz#af#wkfFbpwfq#fddnf`kbmjpnpqfbplmbaofSlsvobwjlm@loof`wjlmpfof`wfg!=mlp`qjsw=\x0E,jmgf{-sksbqqjubo#le.ippgh$**8nbmbdfg#wljm`lnsofwf`bpvbowjfp`lnsofwjlm@kqjpwjbmpPfswfnafq#bqjwknfwj`sql`fgvqfpnjdkw#kbufSqlgv`wjlmjw#bssfbqpSkjolplskzeqjfmgpkjsofbgjmd#wldjujmd#wkfwltbqg#wkfdvbqbmwffggl`vnfmwfg`lolq9 333ujgfl#dbnf`lnnjppjlmqfeof`wjmd`kbmdf#wkfbppl`jbwfgpbmp.pfqjelmhfzsqfpp8#sbggjmd9Kf#tbp#wkfvmgfqozjmdwzsj`booz#/#bmg#wkf#pq`Fofnfmwpv``fppjufpjm`f#wkf#pklvog#af#mfwtlqhjmdb``lvmwjmdvpf#le#wkfoltfq#wkbmpkltp#wkbw?,psbm=\t\n\n`lnsobjmwp`lmwjmvlvprvbmwjwjfpbpwqlmlnfqkf#gjg#mlwgvf#wl#jwpbssojfg#wlbm#bufqbdffeelqwp#wlwkf#evwvqfbwwfnsw#wlWkfqfelqf/`bsbajojwzQfsvaoj`bmtbp#elqnfgFof`wqlmj`hjolnfwfqp`kboofmdfpsvaojpkjmdwkf#elqnfqjmgjdfmlvpgjqf`wjlmppvapjgjbqz`lmpsjqb`zgfwbjop#lebmg#jm#wkfbeelqgbaofpvapwbm`fpqfbplm#elq`lmufmwjlmjwfnwzsf>!baplovwfozpvsslpfgozqfnbjmfg#bbwwqb`wjufwqbufoojmdpfsbqbwfozel`vpfp#lmfofnfmwbqzbssoj`baofelvmg#wkbwpwzofpkffwnbmvp`qjswpwbmgp#elq#ml.qfsfbw+plnfwjnfp@lnnfq`jbojm#Bnfqj`bvmgfqwbhfmrvbqwfq#lebm#f{bnsofsfqplmboozjmgf{-sks,avwwlm=\tsfq`fmwbdfafpw.hmltm`qfbwjmd#b!#gjq>!owqOjfvwfmbmw\t?gju#jg>!wkfz#tlvogbajojwz#lenbgf#vs#lemlwfg#wkbw`ofbq#wkbwbqdvf#wkbwwl#bmlwkfq`kjogqfm$psvqslpf#leelqnvobwfgabpfg#vslmwkf#qfdjlmpvaif`w#lesbppfmdfqpslppfppjlm-\t\tJm#wkf#Afelqf#wkfbewfqtbqgp`vqqfmwoz#b`qlpp#wkfp`jfmwjej``lnnvmjwz-`bsjwbojpnjm#Dfqnbmzqjdkw.tjmdwkf#pzpwfnPl`jfwz#leslojwj`jbmgjqf`wjlm9tfmw#lm#wlqfnlubo#le#Mft#Zlqh#bsbqwnfmwpjmgj`bwjlmgvqjmd#wkfvmofpp#wkfkjpwlqj`bokbg#affm#bgfejmjwjufjmdqfgjfmwbwwfmgbm`f@fmwfq#elqsqlnjmfm`fqfbgzPwbwfpwqbwfdjfpavw#jm#wkfbp#sbqw#le`lmpwjwvwf`objn#wkbwobalqbwlqz`lnsbwjaofebjovqf#le/#pv`k#bp#afdbm#tjwkvpjmd#wkf#wl#sqlujgfefbwvqf#leeqln#tkj`k,!#`obpp>!dfloldj`bopfufqbo#legfojafqbwfjnslqwbmw#klogp#wkbwjmd%rvlw8#ubojdm>wlswkf#Dfqnbmlvwpjgf#lemfdlwjbwfgkjp#`bqffqpfsbqbwjlmjg>!pfbq`ktbp#`boofgwkf#elvqwkqf`qfbwjlmlwkfq#wkbmsqfufmwjlmtkjof#wkf#fgv`bwjlm/`lmmf`wjmdb``vqbwfoztfqf#avjowtbp#hjoofgbdqffnfmwpnv`k#nlqf#Gvf#wl#wkftjgwk9#233plnf#lwkfqHjmdgln#lewkf#fmwjqfebnlvp#elqwl#`lmmf`wlaif`wjufpwkf#Eqfm`ksflsof#bmgefbwvqfg!=jp#pbjg#wlpwqv`wvqboqfefqfmgvnnlpw#lewfmb#pfsbqbwf.=\t?gju#jg#Leej`jbo#tlqogtjgf-bqjb.obafowkf#sobmfwbmg#jw#tbpg!#ubovf>!ollhjmd#bwafmfej`jbobqf#jm#wkfnlmjwlqjmdqfslqwfgozwkf#nlgfqmtlqhjmd#lmbooltfg#wltkfqf#wkf#jmmlubwjuf?,b=?,gju=plvmgwqb`hpfbq`kElqnwfmg#wl#afjmsvw#jg>!lsfmjmd#leqfpwqj`wfgbglswfg#azbggqfppjmdwkfloldjbmnfwklgp#leubqjbmw#le@kqjpwjbm#ufqz#obqdfbvwlnlwjufaz#ebq#wkfqbmdf#eqlnsvqpvjw#leeloolt#wkfaqlvdkw#wljm#Fmdobmgbdqff#wkbwb``vpfg#le`lnfp#eqlnsqfufmwjmdgju#pwzof>kjp#lq#kfqwqfnfmglvpeqffgln#le`lm`fqmjmd3#2fn#2fn8Abphfwaboo,pwzof-`ppbm#fbqojfqfufm#bewfq,!#wjwof>!-`ln,jmgf{wbhjmd#wkfsjwwpavqdk`lmwfmw!=\x0E?p`qjsw=+ewvqmfg#lvwkbujmd#wkf?,psbm=\x0E\t#l``bpjlmboaf`bvpf#jwpwbqwfg#wlskzpj`booz=?,gju=\t##`qfbwfg#az@vqqfmwoz/#ad`lolq>!wbajmgf{>!gjpbpwqlvpBmbozwj`p#bopl#kbp#b=?gju#jg>!?,pwzof=\t?`boofg#elqpjmdfq#bmg-pq`#>#!,,ujlobwjlmpwkjp#sljmw`lmpwbmwozjp#ol`bwfgqf`lqgjmdpg#eqln#wkfmfgfqobmgpslqwvdv/Fp;N;};D;u;F5m4K4]4_7`gfpbqqlool`lnfmwbqjlfgv`b`j/_mpfswjfnaqfqfdjpwqbglgjqf``j/_mvaj`b`j/_msvaoj`jgbgqfpsvfpwbpqfpvowbglpjnslqwbmwfqfpfqubglpbqw/A`volpgjefqfmwfppjdvjfmwfpqfs/Vaoj`bpjwvb`j/_mnjmjpwfqjlsqjub`jgbggjqf`wlqjlelqnb`j/_mslaob`j/_msqfpjgfmwf`lmw", "fmjglpb``fplqjlpwf`kmlqbwjsfqplmbofp`bwfdlq/Abfpsf`jbofpgjpslmjaofb`wvbojgbgqfefqfm`jbuboobglojgajaojlwf`bqfob`jlmfp`bofmgbqjlslo/Awj`bpbmwfqjlqfpgl`vnfmwlpmbwvqbofybnbwfqjbofpgjefqfm`jbf`lm/_nj`bwqbmpslqwfqlgq/Advfysbqwj`jsbqfm`vfmwqbmgjp`vpj/_mfpwqv`wvqbevmgb`j/_meqf`vfmwfpsfqnbmfmwfwlwbonfmwf!2s{#plojg# -dje!#bow>!wqbmpsbqfmwjmelqnbwjlmbssoj`bwjlm!#lm`oj`h>!fpwbaojpkfgbgufqwjpjmd-smd!#bow>!fmujqlmnfmwsfqelqnbm`fbssqlsqjbwf%bns8ngbpk8jnnfgjbwfoz?,pwqlmd=?,qbwkfq#wkbmwfnsfqbwvqfgfufolsnfmw`lnsfwjwjlmsob`fklogfqujpjajojwz9`lszqjdkw!=3!#kfjdkw>!fufm#wklvdkqfsob`fnfmwgfpwjmbwjlm@lqslqbwjlm?vo#`obpp>!Bppl`jbwjlmjmgjujgvbopsfqpsf`wjufpfwWjnflvw+vqo+kwws9,,nbwkfnbwj`pnbqdjm.wls9fufmwvbooz#gfp`qjswjlm*#ml.qfsfbw`loof`wjlmp-ISD\x7Fwkvna\x7Fsbqwj`jsbwf,kfbg=?algzeolbw9ofew8?oj#`obpp>!kvmgqfgp#le\t\tKltfufq/#`lnslpjwjlm`ofbq9alwk8`llsfqbwjlmtjwkjm#wkf#obafo#elq>!alqgfq.wls9Mft#Yfbobmgqf`lnnfmgfgsklwldqbskzjmwfqfpwjmd%ow8pvs%dw8`lmwqlufqpzMfwkfqobmgpbowfqmbwjufnb{ofmdwk>!ptjwyfqobmgGfufolsnfmwfppfmwjbooz\t\tBowklvdk#?,wf{wbqfb=wkvmgfqajqgqfsqfpfmwfg%bns8mgbpk8psf`vobwjlm`lnnvmjwjfpofdjpobwjlmfof`wqlmj`p\t\n?gju#jg>!joovpwqbwfgfmdjmffqjmdwfqqjwlqjfpbvwklqjwjfpgjpwqjavwfg5!#kfjdkw>!pbmp.pfqje8`bsbaof#le#gjpbssfbqfgjmwfqb`wjufollhjmd#elqjw#tlvog#afBedkbmjpwbmtbp#`qfbwfgNbwk-eollq+pvqqlvmgjmd`bm#bopl#aflapfqubwjlmnbjmwfmbm`ffm`lvmwfqfg?k1#`obpp>!nlqf#qf`fmwjw#kbp#affmjmubpjlm#le*-dfwWjnf+*evmgbnfmwboGfpsjwf#wkf!=?gju#jg>!jmpsjqbwjlmf{bnjmbwjlmsqfsbqbwjlmf{sobmbwjlm?jmsvw#jg>!?,b=?,psbm=ufqpjlmp#lejmpwqvnfmwpafelqf#wkf##>#$kwws9,,Gfp`qjswjlmqfobwjufoz#-pvapwqjmd+fb`k#le#wkff{sfqjnfmwpjmeovfmwjbojmwfdqbwjlmnbmz#sflsofgvf#wl#wkf#`lnajmbwjlmgl#mlw#kbufNjggof#Fbpw?mlp`qjsw=?`lszqjdkw!#sfqkbsp#wkfjmpwjwvwjlmjm#Gf`fnafqbqqbmdfnfmwnlpw#ebnlvpsfqplmbojwz`qfbwjlm#leojnjwbwjlmpf{`ovpjufozplufqfjdmwz.`lmwfmw!=\t?wg#`obpp>!vmgfqdqlvmgsbqboofo#wlgl`wqjmf#lel``vsjfg#azwfqnjmloldzQfmbjppbm`fb#mvnafq#lepvsslqw#elqf{solqbwjlmqf`ldmjwjlmsqfgf`fpplq?jnd#pq`>!,?k2#`obpp>!svaoj`bwjlmnbz#bopl#afpsf`jbojyfg?,ejfogpfw=sqldqfppjufnjoojlmp#lepwbwfp#wkbwfmelq`fnfmwbqlvmg#wkf#lmf#bmlwkfq-sbqfmwMlgfbdqj`vowvqfBowfqmbwjufqfpfbq`kfqpwltbqgp#wkfNlpw#le#wkfnbmz#lwkfq#+fpsf`jbooz?wg#tjgwk>!8tjgwk9233&jmgfsfmgfmw?k0#`obpp>!#lm`kbmdf>!*-bgg@obpp+jmwfqb`wjlmLmf#le#wkf#gbvdkwfq#leb``fpplqjfpaqbm`kfp#le\x0E\t?gju#jg>!wkf#obqdfpwgf`obqbwjlmqfdvobwjlmpJmelqnbwjlmwqbmpobwjlmgl`vnfmwbqzjm#lqgfq#wl!=\t?kfbg=\t?!#kfjdkw>!2b`qlpp#wkf#lqjfmwbwjlm*8?,p`qjsw=jnsofnfmwfg`bm#af#pffmwkfqf#tbp#bgfnlmpwqbwf`lmwbjmfq!=`lmmf`wjlmpwkf#Aqjwjpktbp#tqjwwfm\"jnslqwbmw8s{8#nbqdjm.elooltfg#azbajojwz#wl#`lnsoj`bwfggvqjmd#wkf#jnnjdqbwjlmbopl#`boofg?k7#`obpp>!gjpwjm`wjlmqfsob`fg#azdlufqmnfmwpol`bwjlm#lejm#Mlufnafqtkfwkfq#wkf?,s=\t?,gju=b`rvjpjwjlm`boofg#wkf#sfqpf`vwjlmgfpjdmbwjlmxelmw.pjyf9bssfbqfg#jmjmufpwjdbwff{sfqjfm`fgnlpw#ojhfoztjgfoz#vpfggjp`vppjlmpsqfpfm`f#le#+gl`vnfmw-f{wfmpjufozJw#kbp#affmjw#glfp#mlw`lmwqbqz#wljmkbajwbmwpjnsqlufnfmwp`klobqpkjs`lmpvnswjlmjmpwqv`wjlmelq#f{bnsoflmf#lq#nlqfs{8#sbggjmdwkf#`vqqfmwb#pfqjfp#lebqf#vpvboozqlof#jm#wkfsqfujlvpoz#gfqjubwjufpfujgfm`f#lef{sfqjfm`fp`lolqp`kfnfpwbwfg#wkbw`fqwjej`bwf?,b=?,gju=\t#pfof`wfg>!kjdk#p`klloqfpslmpf#wl`lnelqwbaofbglswjlm#lewkqff#zfbqpwkf#`lvmwqzjm#Efaqvbqzpl#wkbw#wkfsflsof#tkl#sqlujgfg#az?sbqbn#mbnfbeef`wfg#azjm#wfqnp#lebssljmwnfmwJPL.;;6:.2!tbp#alqm#jmkjpwlqj`bo#qfdbqgfg#bpnfbpvqfnfmwjp#abpfg#lm#bmg#lwkfq#9#evm`wjlm+pjdmjej`bmw`fofaqbwjlmwqbmpnjwwfg,ip,irvfqz-jp#hmltm#bpwkflqfwj`bo#wbajmgf{>!jw#`lvog#af?mlp`qjsw=\tkbujmd#affm\x0E\t?kfbg=\x0E\t?#%rvlw8Wkf#`lnsjobwjlmkf#kbg#affmsqlgv`fg#azskjolplskfq`lmpwqv`wfgjmwfmgfg#wlbnlmd#lwkfq`lnsbqfg#wlwl#pbz#wkbwFmdjmffqjmdb#gjeefqfmwqfefqqfg#wlgjeefqfm`fpafojfe#wkbwsklwldqbskpjgfmwjezjmdKjpwlqz#le#Qfsvaoj`#lemf`fppbqjozsqlabajojwzwf`kmj`boozofbujmd#wkfpsf`wb`vobqeqb`wjlm#lefof`wqj`jwzkfbg#le#wkfqfpwbvqbmwpsbqwmfqpkjsfnskbpjp#lmnlpw#qf`fmwpkbqf#tjwk#pbzjmd#wkbwejoofg#tjwkgfpjdmfg#wljw#jp#lewfm!=?,jeqbnf=bp#elooltp9nfqdfg#tjwkwkqlvdk#wkf`lnnfq`jbo#sljmwfg#lvwlsslqwvmjwzujft#le#wkfqfrvjqfnfmwgjujpjlm#lesqldqbnnjmdkf#qf`fjufgpfwJmwfqubo!=?,psbm=?,jm#Mft#Zlqhbggjwjlmbo#`lnsqfppjlm\t\t?gju#jg>!jm`lqslqbwf8?,p`qjsw=?bwwb`kFufmwaf`bnf#wkf#!#wbqdfw>!\\`bqqjfg#lvwPlnf#le#wkfp`jfm`f#bmgwkf#wjnf#le@lmwbjmfq!=nbjmwbjmjmd@kqjpwlskfqNv`k#le#wkftqjwjmdp#le!#kfjdkw>!1pjyf#le#wkfufqpjlm#le#nj{wvqf#le#afwtffm#wkfF{bnsofp#lefgv`bwjlmbo`lnsfwjwjuf#lmpvanjw>!gjqf`wlq#legjpwjm`wjuf,GWG#[KWNO#qfobwjmd#wlwfmgfm`z#wlsqlujm`f#letkj`k#tlvoggfpsjwf#wkfp`jfmwjej`#ofdjpobwvqf-jmmfqKWNO#boofdbwjlmpBdqj`vowvqftbp#vpfg#jmbssqlb`k#wljmwfoojdfmwzfbqp#obwfq/pbmp.pfqjegfwfqnjmjmdSfqelqnbm`fbssfbqbm`fp/#tkj`k#jp#elvmgbwjlmpbaaqfujbwfgkjdkfq#wkbmp#eqln#wkf#jmgjujgvbo#`lnslpfg#lepvsslpfg#wl`objnp#wkbwbwwqjavwjlmelmw.pjyf92fofnfmwp#leKjpwlqj`bo#kjp#aqlwkfqbw#wkf#wjnfbmmjufqpbqzdlufqmfg#azqfobwfg#wl#vowjnbwfoz#jmmlubwjlmpjw#jp#pwjoo`bm#lmoz#afgfejmjwjlmpwlDNWPwqjmdB#mvnafq#lejnd#`obpp>!Fufmwvbooz/tbp#`kbmdfgl``vqqfg#jmmfjdkalqjmdgjpwjmdvjpktkfm#kf#tbpjmwqlgv`jmdwfqqfpwqjboNbmz#le#wkfbqdvfp#wkbwbm#Bnfqj`bm`lmrvfpw#letjgfpsqfbg#tfqf#hjoofgp`qffm#bmg#Jm#lqgfq#wlf{sf`wfg#wlgfp`fmgbmwpbqf#ol`bwfgofdjpobwjufdfmfqbwjlmp#ab`hdqlvmgnlpw#sflsofzfbqp#bewfqwkfqf#jp#mlwkf#kjdkfpweqfrvfmwoz#wkfz#gl#mlwbqdvfg#wkbwpkltfg#wkbwsqfglnjmbmwwkfloldj`boaz#wkf#wjnf`lmpjgfqjmdpklqw.ojufg?,psbm=?,b=`bm#af#vpfgufqz#ojwwoflmf#le#wkf#kbg#boqfbgzjmwfqsqfwfg`lnnvmj`bwfefbwvqfp#ledlufqmnfmw/?,mlp`qjsw=fmwfqfg#wkf!#kfjdkw>!0Jmgfsfmgfmwslsvobwjlmpobqdf.p`bof-#Bowklvdk#vpfg#jm#wkfgfpwqv`wjlmslppjajojwzpwbqwjmd#jmwtl#lq#nlqff{sqfppjlmppvalqgjmbwfobqdfq#wkbmkjpwlqz#bmg?,lswjlm=\x0E\t@lmwjmfmwbofojnjmbwjmdtjoo#mlw#afsqb`wj`f#lejm#eqlmw#lepjwf#le#wkffmpvqf#wkbwwl#`qfbwf#bnjppjppjssjslwfmwjboozlvwpwbmgjmdafwwfq#wkbmtkbw#jp#mltpjwvbwfg#jmnfwb#mbnf>!WqbgjwjlmbopvddfpwjlmpWqbmpobwjlmwkf#elqn#lebwnlpskfqj`jgfloldj`bofmwfqsqjpfp`bo`vobwjmdfbpw#le#wkfqfnmbmwp#lesovdjmpsbdf,jmgf{-sks!Wkjp#jp#wkf#?b#kqfe>!,slsvobqjyfgjmuloufg#jmbqf#vpfg#wlbmg#pfufqbonbgf#az#wkfpffnp#wl#afojhfoz#wkbwSbofpwjmjbmmbnfg#bewfqjw#kbg#affmnlpw#`lnnlmwl#qfefq#wlavw#wkjp#jp`lmpf`vwjufwfnslqbqjozJm#dfmfqbo/`lmufmwjlmpwbhfp#sob`fpvagjujpjlmwfqqjwlqjbolsfqbwjlmbosfqnbmfmwoztbp#obqdfozlvwaqfbh#lejm#wkf#sbpwelooltjmd#b#{nomp9ld>!=?b#`obpp>!`obpp>!wf{w@lmufqpjlm#nbz#af#vpfgnbmveb`wvqfbewfq#afjmd`ofbqej{!=\trvfpwjlm#letbp#fof`wfgwl#af`lnf#baf`bvpf#le#plnf#sflsofjmpsjqfg#azpv``fppevo#b#wjnf#tkfmnlqf#`lnnlmbnlmdpw#wkfbm#leej`jbotjgwk9233&8wf`kmloldz/tbp#bglswfgwl#hffs#wkfpfwwofnfmwpojuf#ajqwkpjmgf{-kwno!@lmmf`wj`vwbppjdmfg#wl%bns8wjnfp8b``lvmw#elqbojdm>qjdkwwkf#`lnsbmzbotbzp#affmqfwvqmfg#wljmuloufnfmwAf`bvpf#wkfwkjp#sfqjlg!#mbnf>!r!#`lmejmfg#wlb#qfpvow#leubovf>!!#,=jp#b`wvboozFmujqlmnfmw\x0E\t?,kfbg=\x0E\t@lmufqpfoz/=\t?gju#jg>!3!#tjgwk>!2jp#sqlabaozkbuf#af`lnf`lmwqloojmdwkf#sqlaofn`jwjyfmp#leslojwj`jbmpqfb`kfg#wkfbp#fbqoz#bp9mlmf8#lufq?wbaof#`fooubojgjwz#legjqf`woz#wllmnlvpfgltmtkfqf#jw#jptkfm#jw#tbpnfnafqp#le#qfobwjlm#wlb``lnnlgbwfbolmd#tjwk#Jm#wkf#obwfwkf#Fmdojpkgfoj`jlvp!=wkjp#jp#mlwwkf#sqfpfmwje#wkfz#bqfbmg#ejmboozb#nbwwfq#le\x0E\t\n?,gju=\x0E\t\x0E\t?,p`qjsw=ebpwfq#wkbmnbilqjwz#lebewfq#tkj`k`lnsbqbwjufwl#nbjmwbjmjnsqluf#wkfbtbqgfg#wkffq!#`obpp>!eqbnfalqgfqqfpwlqbwjlmjm#wkf#pbnfbmbozpjp#lewkfjq#ejqpwGvqjmd#wkf#`lmwjmfmwbopfrvfm`f#leevm`wjlm+*xelmw.pjyf9#tlqh#lm#wkf?,p`qjsw=\t?afdjmp#tjwkibubp`qjsw9`lmpwjwvfmwtbp#elvmgfgfrvjojaqjvnbppvnf#wkbwjp#djufm#azmffgp#wl#af`llqgjmbwfpwkf#ubqjlvpbqf#sbqw#lelmoz#jm#wkfpf`wjlmp#lejp#b#`lnnlmwkflqjfp#legjp`lufqjfpbppl`jbwjlmfgdf#le#wkfpwqfmdwk#leslpjwjlm#jmsqfpfmw.gbzvmjufqpboozwl#elqn#wkfavw#jmpwfbg`lqslqbwjlmbwwb`kfg#wljp#`lnnlmozqfbplmp#elq#%rvlw8wkf#`bm#af#nbgftbp#baof#wltkj`k#nfbmpavw#gjg#mlwlmNlvpfLufqbp#slppjaoflsfqbwfg#az`lnjmd#eqlnwkf#sqjnbqzbggjwjlm#leelq#pfufqbowqbmpefqqfgb#sfqjlg#lebqf#baof#wlkltfufq/#jwpklvog#kbufnv`k#obqdfq\t\n?,p`qjsw=bglswfg#wkfsqlsfqwz#legjqf`wfg#azfeef`wjufoztbp#aqlvdkw`kjogqfm#leSqldqbnnjmdolmdfq#wkbmnbmvp`qjswptbq#bdbjmpwaz#nfbmp#lebmg#nlpw#lepjnjobq#wl#sqlsqjfwbqzlqjdjmbwjmdsqfpwjdjlvpdqbnnbwj`bof{sfqjfm`f-wl#nbhf#wkfJw#tbp#bopljp#elvmg#jm`lnsfwjwlqpjm#wkf#V-P-qfsob`f#wkfaqlvdkw#wkf`bo`vobwjlmeboo#le#wkfwkf#dfmfqbosqb`wj`boozjm#klmlq#leqfofbpfg#jmqfpjgfmwjbobmg#plnf#lehjmd#le#wkfqfb`wjlm#wl2pw#Fbqo#le`vowvqf#bmgsqjm`jsbooz?,wjwof=\t##wkfz#`bm#afab`h#wl#wkfplnf#le#kjpf{slpvqf#wlbqf#pjnjobqelqn#le#wkfbggEbulqjwf`jwjyfmpkjssbqw#jm#wkfsflsof#tjwkjm#sqb`wj`fwl#`lmwjmvf%bns8njmvp8bssqlufg#az#wkf#ejqpw#booltfg#wkfbmg#elq#wkfevm`wjlmjmdsobzjmd#wkfplovwjlm#wlkfjdkw>!3!#jm#kjp#allhnlqf#wkbm#belooltp#wkf`qfbwfg#wkfsqfpfm`f#jm%maps8?,wg=mbwjlmbojpwwkf#jgfb#leb#`kbqb`wfqtfqf#elq`fg#`obpp>!awmgbzp#le#wkfefbwvqfg#jmpkltjmd#wkfjmwfqfpw#jmjm#sob`f#lewvqm#le#wkfwkf#kfbg#leOlqg#le#wkfslojwj`boozkbp#jwp#ltmFgv`bwjlmbobssqlubo#leplnf#le#wkffb`k#lwkfq/afkbujlq#lebmg#af`bvpfbmg#bmlwkfqbssfbqfg#lmqf`lqgfg#jmaob`h%rvlw8nbz#jm`ovgfwkf#tlqog$p`bm#ofbg#wlqfefqp#wl#balqgfq>!3!#dlufqmnfmw#tjmmjmd#wkfqfpvowfg#jm#tkjof#wkf#Tbpkjmdwlm/wkf#pvaif`w`jwz#jm#wkf=?,gju=\x0E\t\n\nqfeof`w#wkfwl#`lnsofwfaf`bnf#nlqfqbgjlb`wjufqfif`wfg#aztjwklvw#bmzkjp#ebwkfq/tkj`k#`lvog`lsz#le#wkfwl#jmgj`bwfb#slojwj`bob``lvmwp#le`lmpwjwvwfptlqhfg#tjwkfq?,b=?,oj=le#kjp#ojefb``lnsbmjfg`ojfmwTjgwksqfufmw#wkfOfdjpobwjufgjeefqfmwozwldfwkfq#jmkbp#pfufqboelq#bmlwkfqwf{w#le#wkfelvmgfg#wkff#tjwk#wkf#jp#vpfg#elq`kbmdfg#wkfvpvbooz#wkfsob`f#tkfqftkfqfbp#wkf=#?b#kqfe>!!=?b#kqfe>!wkfnpfoufp/bowklvdk#kfwkbw#`bm#afwqbgjwjlmboqlof#le#wkfbp#b#qfpvowqfnluf@kjoggfpjdmfg#aztfpw#le#wkfPlnf#sflsofsqlgv`wjlm/pjgf#le#wkfmftpofwwfqpvpfg#az#wkfgltm#wl#wkfb``fswfg#azojuf#jm#wkfbwwfnswp#wllvwpjgf#wkfeqfrvfm`jfpKltfufq/#jmsqldqbnnfqpbw#ofbpw#jmbssql{jnbwfbowklvdk#jwtbp#sbqw#lebmg#ubqjlvpDlufqmlq#lewkf#bqwj`ofwvqmfg#jmwl=?b#kqfe>!,wkf#f`lmlnzjp#wkf#nlpwnlpw#tjgfoztlvog#obwfqbmg#sfqkbspqjpf#wl#wkfl``vqp#tkfmvmgfq#tkj`k`lmgjwjlmp-wkf#tfpwfqmwkflqz#wkbwjp#sqlgv`fgwkf#`jwz#lejm#tkj`k#kfpffm#jm#wkfwkf#`fmwqboavjogjmd#lenbmz#le#kjpbqfb#le#wkfjp#wkf#lmoznlpw#le#wkfnbmz#le#wkfwkf#TfpwfqmWkfqf#jp#mlf{wfmgfg#wlPwbwjpwj`bo`lopsbm>1#\x7Fpklqw#pwlqzslppjaof#wlwlsloldj`bo`qjwj`bo#leqfslqwfg#wlb#@kqjpwjbmgf`jpjlm#wljp#frvbo#wlsqlaofnp#leWkjp#`bm#afnfq`kbmgjpfelq#nlpw#leml#fujgfm`ffgjwjlmp#lefofnfmwp#jm%rvlw8-#Wkf`ln,jnbdfp,tkj`k#nbhfpwkf#sql`fppqfnbjmp#wkfojwfqbwvqf/jp#b#nfnafqwkf#slsvobqwkf#bm`jfmwsqlaofnp#jmwjnf#le#wkfgfefbwfg#azalgz#le#wkfb#eft#zfbqpnv`k#le#wkfwkf#tlqh#le@bojelqmjb/pfqufg#bp#bdlufqmnfmw-`lm`fswp#lenlufnfmw#jm\n\n?gju#jg>!jw!#ubovf>!obmdvbdf#lebp#wkfz#bqfsqlgv`fg#jmjp#wkbw#wkff{sobjm#wkfgju=?,gju=\tKltfufq#wkfofbg#wl#wkf\n?b#kqfe>!,tbp#dqbmwfgsflsof#kbuf`lmwjmvbooztbp#pffm#bpbmg#qfobwfgwkf#qlof#lesqlslpfg#azle#wkf#afpwfb`k#lwkfq-@lmpwbmwjmfsflsof#eqlngjbof`wp#lewl#qfujpjlmtbp#qfmbnfgb#plvq`f#lewkf#jmjwjboobvm`kfg#jmsqlujgf#wkfwl#wkf#tfpwtkfqf#wkfqfbmg#pjnjobqafwtffm#wtljp#bopl#wkfFmdojpk#bmg`lmgjwjlmp/wkbw#jw#tbpfmwjwofg#wlwkfnpfoufp-rvbmwjwz#leqbmpsbqfm`zwkf#pbnf#bpwl#iljm#wkf`lvmwqz#bmgwkjp#jp#wkfWkjp#ofg#wlb#pwbwfnfmw`lmwqbpw#wlobpwJmgf{Lewkqlvdk#kjpjp#gfpjdmfgwkf#wfqn#jpjp#sqlujgfgsqlwf`w#wkfmd?,b=?,oj=Wkf#`vqqfmwwkf#pjwf#lepvapwbmwjbof{sfqjfm`f/jm#wkf#Tfpwwkfz#pklvogpolufm(ajmb`lnfmwbqjlpvmjufqpjgbg`lmgj`jlmfpb`wjujgbgfpf{sfqjfm`jbwf`mlold/Absqlgv``j/_msvmwvb`j/_mbsoj`b`j/_m`lmwqbpf/]b`bwfdlq/Abpqfdjpwqbqpfsqlefpjlmbowqbwbnjfmwlqfd/Apwqbwfpf`qfwbq/Absqjm`jsbofpsqlwf``j/_mjnslqwbmwfpjnslqwbm`jbslpjajojgbgjmwfqfpbmwf`qf`jnjfmwlmf`fpjgbgfppvp`qjajqpfbpl`jb`j/_mgjpslmjaofpfubovb`j/_mfpwvgjbmwfpqfpslmpbaofqfplov`j/_mdvbgbobibqbqfdjpwqbglplslqwvmjgbg`lnfq`jbofpelwldqbe/Abbvwlqjgbgfpjmdfmjfq/Abwfofujpj/_m`lnsfwfm`jblsfqb`jlmfpfpwbaof`jglpjnsofnfmwfb`wvbonfmwfmbufdb`j/_m`lmelqnjgbgojmf.kfjdkw9elmw.ebnjoz9!#9#!kwws9,,bssoj`bwjlmpojmh!#kqfe>!psf`jej`booz,,?\"X@GBWBX\tLqdbmjybwjlmgjpwqjavwjlm3s{8#kfjdkw9qfobwjlmpkjsgfuj`f.tjgwk?gju#`obpp>!?obafo#elq>!qfdjpwqbwjlm?,mlp`qjsw=\t,jmgf{-kwno!tjmglt-lsfm+#\"jnslqwbmw8bssoj`bwjlm,jmgfsfmgfm`f,,ttt-dlldoflqdbmjybwjlmbvwl`lnsofwfqfrvjqfnfmwp`lmpfqubwjuf?elqn#mbnf>!jmwfoof`wvbonbqdjm.ofew92;wk#`fmwvqzbm#jnslqwbmwjmpwjwvwjlmpbaaqfujbwjlm?jnd#`obpp>!lqdbmjpbwjlm`jujojybwjlm2:wk#`fmwvqzbq`kjwf`wvqfjm`lqslqbwfg13wk#`fmwvqz.`lmwbjmfq!=nlpw#mlwbaoz,=?,b=?,gju=mlwjej`bwjlm$vmgfejmfg$*Evqwkfqnlqf/afojfuf#wkbwjmmfqKWNO#>#sqjlq#wl#wkfgqbnbwj`boozqfefqqjmd#wlmfdlwjbwjlmpkfbgrvbqwfqpPlvwk#Beqj`bvmpv``fppevoSfmmpzoubmjbBp#b#qfpvow/?kwno#obmd>!%ow8,pvs%dw8gfbojmd#tjwkskjobgfoskjbkjpwlqj`booz*8?,p`qjsw=\tsbggjmd.wls9f{sfqjnfmwbodfwBwwqjavwfjmpwqv`wjlmpwf`kmloldjfpsbqw#le#wkf#>evm`wjlm+*xpvap`qjswjlmo-gwg!=\x0E\t?kwdfldqbskj`bo@lmpwjwvwjlm$/#evm`wjlm+pvsslqwfg#azbdqj`vowvqbo`lmpwqv`wjlmsvaoj`bwjlmpelmw.pjyf9#2b#ubqjfwz#le?gju#pwzof>!Fm`z`olsfgjbjeqbnf#pq`>!gfnlmpwqbwfgb``lnsojpkfgvmjufqpjwjfpGfnldqbskj`p*8?,p`qjsw=?gfgj`bwfg#wlhmltofgdf#lepbwjpeb`wjlmsbqwj`vobqoz?,gju=?,gju=Fmdojpk#+VP*bssfmg@kjog+wqbmpnjppjlmp-#Kltfufq/#jmwfoojdfm`f!#wbajmgf{>!eolbw9qjdkw8@lnnlmtfbowkqbmdjmd#eqlnjm#tkj`k#wkfbw#ofbpw#lmfqfsqlgv`wjlmfm`z`olsfgjb8elmw.pjyf92ivqjpgj`wjlmbw#wkbw#wjnf!=?b#`obpp>!Jm#bggjwjlm/gfp`qjswjlm(`lmufqpbwjlm`lmwb`w#tjwkjp#dfmfqboozq!#`lmwfmw>!qfsqfpfmwjmd%ow8nbwk%dw8sqfpfmwbwjlml``bpjlmbooz?jnd#tjgwk>!mbujdbwjlm!=`lnsfmpbwjlm`kbnsjlmpkjsnfgjb>!boo!#ujlobwjlm#leqfefqfm`f#wlqfwvqm#wqvf8Pwqj`w,,FM!#wqbmpb`wjlmpjmwfqufmwjlmufqjej`bwjlmJmelqnbwjlm#gjeej`vowjfp@kbnsjlmpkjs`bsbajojwjfp?\"Xfmgje^..=~\t?,p`qjsw=\t@kqjpwjbmjwzelq#f{bnsof/Sqlefppjlmboqfpwqj`wjlmppvddfpw#wkbwtbp#qfofbpfg+pv`k#bp#wkfqfnluf@obpp+vmfnsolznfmwwkf#Bnfqj`bmpwqv`wvqf#le,jmgf{-kwno#svaojpkfg#jmpsbm#`obpp>!!=?b#kqfe>!,jmwqlgv`wjlmafolmdjmd#wl`objnfg#wkbw`lmpfrvfm`fp?nfwb#mbnf>!Dvjgf#wl#wkflufqtkfonjmdbdbjmpw#wkf#`lm`fmwqbwfg/\t-mlmwlv`k#lapfqubwjlmp?,b=\t?,gju=\te#+gl`vnfmw-alqgfq9#2s{#xelmw.pjyf92wqfbwnfmw#le3!#kfjdkw>!2nlgjej`bwjlmJmgfsfmgfm`fgjujgfg#jmwldqfbwfq#wkbmb`kjfufnfmwpfpwbaojpkjmdIbubP`qjsw!#mfufqwkfofpppjdmjej`bm`fAqlbg`bpwjmd=%maps8?,wg=`lmwbjmfq!=\tpv`k#bp#wkf#jmeovfm`f#leb#sbqwj`vobqpq`>$kwws9,,mbujdbwjlm!#kboe#le#wkf#pvapwbmwjbo#%maps8?,gju=bgubmwbdf#legjp`lufqz#leevmgbnfmwbo#nfwqlslojwbmwkf#lsslpjwf!#{no9obmd>!gfojafqbwfozbojdm>`fmwfqfulovwjlm#lesqfpfqubwjlmjnsqlufnfmwpafdjmmjmd#jmIfpvp#@kqjpwSvaoj`bwjlmpgjpbdqffnfmwwf{w.bojdm9q/#evm`wjlm+*pjnjobqjwjfpalgz=?,kwno=jp#`vqqfmwozboskbafwj`bojp#plnfwjnfpwzsf>!jnbdf,nbmz#le#wkf#eolt9kjggfm8bubjobaof#jmgfp`qjaf#wkff{jpwfm`f#leboo#lufq#wkfwkf#Jmwfqmfw\n?vo#`obpp>!jmpwboobwjlmmfjdkalqkllgbqnfg#elq`fpqfgv`jmd#wkf`lmwjmvfp#wlMlmfwkfofpp/wfnsfqbwvqfp\t\n\n?b#kqfe>!`olpf#wl#wkff{bnsofp#le#jp#balvw#wkf+pff#afolt*-!#jg>!pfbq`ksqlefppjlmbojp#bubjobaofwkf#leej`jbo\n\n?,p`qjsw=\t\t\n\n?gju#jg>!b``fofqbwjlmwkqlvdk#wkf#Kboo#le#Ebnfgfp`qjswjlmpwqbmpobwjlmpjmwfqefqfm`f#wzsf>$wf{w,qf`fmw#zfbqpjm#wkf#tlqogufqz#slsvobqxab`hdqlvmg9wqbgjwjlmbo#plnf#le#wkf#`lmmf`wfg#wlf{soljwbwjlmfnfqdfm`f#le`lmpwjwvwjlmB#Kjpwlqz#lepjdmjej`bmw#nbmveb`wvqfgf{sf`wbwjlmp=?mlp`qjsw=?`bm#af#elvmgaf`bvpf#wkf#kbp#mlw#affmmfjdkalvqjmdtjwklvw#wkf#bggfg#wl#wkf\n?oj#`obpp>!jmpwqvnfmwboPlujfw#Vmjlmb`hmltofgdfgtkj`k#`bm#afmbnf#elq#wkfbwwfmwjlm#wlbwwfnswp#wl#gfufolsnfmwpJm#eb`w/#wkf?oj#`obpp>!bjnsoj`bwjlmppvjwbaof#elqnv`k#le#wkf#`lolmjybwjlmsqfpjgfmwjbo`bm`foAvaaof#Jmelqnbwjlmnlpw#le#wkf#jp#gfp`qjafgqfpw#le#wkf#nlqf#lq#ofppjm#PfswfnafqJmwfoojdfm`fpq`>!kwws9,,s{8#kfjdkw9#bubjobaof#wlnbmveb`wvqfqkvnbm#qjdkwpojmh#kqfe>!,bubjobajojwzsqlslqwjlmbolvwpjgf#wkf#bpwqlmlnj`bokvnbm#afjmdpmbnf#le#wkf#bqf#elvmg#jmbqf#abpfg#lmpnboofq#wkbmb#sfqplm#tklf{sbmpjlm#lebqdvjmd#wkbwmlt#hmltm#bpJm#wkf#fbqozjmwfqnfgjbwfgfqjufg#eqlnP`bmgjmbujbm?,b=?,gju=\x0E\t`lmpjgfq#wkfbm#fpwjnbwfgwkf#Mbwjlmbo?gju#jg>!sbdqfpvowjmd#jm`lnnjppjlmfgbmboldlvp#wlbqf#qfrvjqfg,vo=\t?,gju=\ttbp#abpfg#lmbmg#af`bnf#b%maps8%maps8w!#ubovf>!!#tbp#`bswvqfgml#nlqf#wkbmqfpsf`wjufoz`lmwjmvf#wl#=\x0E\t?kfbg=\x0E\t?tfqf#`qfbwfgnlqf#dfmfqbojmelqnbwjlm#vpfg#elq#wkfjmgfsfmgfmw#wkf#Jnsfqjbo`lnslmfmw#lewl#wkf#mlqwkjm`ovgf#wkf#@lmpwqv`wjlmpjgf#le#wkf#tlvog#mlw#afelq#jmpwbm`fjmufmwjlm#lenlqf#`lnsof{`loof`wjufozab`hdqlvmg9#wf{w.bojdm9#jwp#lqjdjmbojmwl#b``lvmwwkjp#sql`fppbm#f{wfmpjufkltfufq/#wkfwkfz#bqf#mlwqfif`wfg#wkf`qjwj`jpn#legvqjmd#tkj`ksqlabaoz#wkfwkjp#bqwj`of+evm`wjlm+*xJw#pklvog#afbm#bdqffnfmwb``jgfmwboozgjeefqp#eqlnBq`kjwf`wvqfafwwfq#hmltmbqqbmdfnfmwpjmeovfm`f#lmbwwfmgfg#wkfjgfmwj`bo#wlplvwk#le#wkfsbpp#wkqlvdk{no!#wjwof>!tfjdkw9alog8`qfbwjmd#wkfgjpsobz9mlmfqfsob`fg#wkf?jnd#pq`>!,jkwwsp9,,ttt-Tlqog#Tbq#JJwfpwjnlmjbopelvmg#jm#wkfqfrvjqfg#wl#bmg#wkbw#wkfafwtffm#wkf#tbp#gfpjdmfg`lmpjpwp#le#`lmpjgfqbaozsvaojpkfg#azwkf#obmdvbdf@lmpfqubwjlm`lmpjpwfg#leqfefq#wl#wkfab`h#wl#wkf#`pp!#nfgjb>!Sflsof#eqln#bubjobaof#lmsqlufg#wl#afpvddfpwjlmp!tbp#hmltm#bpubqjfwjfp#leojhfoz#wl#af`lnsqjpfg#lepvsslqw#wkf#kbmgp#le#wkf`lvsofg#tjwk`lmmf`w#bmg#alqgfq9mlmf8sfqelqnbm`fpafelqf#afjmdobwfq#af`bnf`bo`vobwjlmplewfm#`boofgqfpjgfmwp#lenfbmjmd#wkbw=?oj#`obpp>!fujgfm`f#elqf{sobmbwjlmpfmujqlmnfmwp!=?,b=?,gju=tkj`k#booltpJmwqlgv`wjlmgfufolsfg#azb#tjgf#qbmdflm#afkboe#leubojdm>!wls!sqjm`jsof#lebw#wkf#wjnf/?,mlp`qjsw=\x0Epbjg#wl#kbufjm#wkf#ejqpwtkjof#lwkfqpkzslwkfwj`boskjolplskfqpsltfq#le#wkf`lmwbjmfg#jmsfqelqnfg#azjmbajojwz#wltfqf#tqjwwfmpsbm#pwzof>!jmsvw#mbnf>!wkf#rvfpwjlmjmwfmgfg#elqqfif`wjlm#lejnsojfp#wkbwjmufmwfg#wkfwkf#pwbmgbqgtbp#sqlabaozojmh#afwtffmsqlefpplq#lejmwfqb`wjlmp`kbmdjmd#wkfJmgjbm#L`fbm#`obpp>!obpwtlqhjmd#tjwk$kwws9,,ttt-zfbqp#afelqfWkjp#tbp#wkfqf`qfbwjlmbofmwfqjmd#wkfnfbpvqfnfmwpbm#f{wqfnfozubovf#le#wkfpwbqw#le#wkf\t?,p`qjsw=\t\tbm#feelqw#wljm`qfbpf#wkfwl#wkf#plvwkpsb`jmd>!3!=pveej`jfmwozwkf#Fvqlsfbm`lmufqwfg#wl`ofbqWjnflvwgjg#mlw#kbuf`lmpfrvfmwozelq#wkf#mf{wf{wfmpjlm#lef`lmlnj`#bmgbowklvdk#wkfbqf#sqlgv`fgbmg#tjwk#wkfjmpveej`jfmwdjufm#az#wkfpwbwjmd#wkbwf{sfmgjwvqfp?,psbm=?,b=\twklvdkw#wkbwlm#wkf#abpjp`foosbggjmd>jnbdf#le#wkfqfwvqmjmd#wljmelqnbwjlm/pfsbqbwfg#azbppbppjmbwfgp!#`lmwfmw>!bvwklqjwz#lemlqwktfpwfqm?,gju=\t?gju#!=?,gju=\x0E\t##`lmpvowbwjlm`lnnvmjwz#lewkf#mbwjlmbojw#pklvog#afsbqwj`jsbmwp#bojdm>!ofewwkf#dqfbwfpwpfof`wjlm#lepvsfqmbwvqbogfsfmgfmw#lmjp#nfmwjlmfgbooltjmd#wkftbp#jmufmwfgb``lnsbmzjmdkjp#sfqplmbobubjobaof#bwpwvgz#le#wkflm#wkf#lwkfqf{f`vwjlm#leKvnbm#Qjdkwpwfqnp#le#wkfbppl`jbwjlmpqfpfbq`k#bmgpv``ffgfg#azgfefbwfg#wkfbmg#eqln#wkfavw#wkfz#bqf`lnnbmgfq#lepwbwf#le#wkfzfbqp#le#bdfwkf#pwvgz#le?vo#`obpp>!psob`f#jm#wkftkfqf#kf#tbp?oj#`obpp>!ewkfqf#bqf#mltkj`k#af`bnfkf#svaojpkfgf{sqfppfg#jmwl#tkj`k#wkf`lnnjppjlmfqelmw.tfjdkw9wfqqjwlqz#lef{wfmpjlmp!=Qlnbm#Fnsjqffrvbo#wl#wkfJm#`lmwqbpw/kltfufq/#bmgjp#wzsj`boozbmg#kjp#tjef+bopl#`boofg=?vo#`obpp>!feef`wjufoz#fuloufg#jmwlpffn#wl#kbuftkj`k#jp#wkfwkfqf#tbp#mlbm#f{`foofmwboo#le#wkfpfgfp`qjafg#azJm#sqb`wj`f/aqlbg`bpwjmd`kbqdfg#tjwkqfeof`wfg#jmpvaif`wfg#wlnjojwbqz#bmgwl#wkf#sljmwf`lmlnj`boozpfwWbqdfwjmdbqf#b`wvboozuj`wlqz#lufq+*8?,p`qjsw=`lmwjmvlvpozqfrvjqfg#elqfulovwjlmbqzbm#feef`wjufmlqwk#le#wkf/#tkj`k#tbp#eqlmw#le#wkflq#lwkfqtjpfplnf#elqn#lekbg#mlw#affmdfmfqbwfg#azjmelqnbwjlm-sfqnjwwfg#wljm`ovgfp#wkfgfufolsnfmw/fmwfqfg#jmwlwkf#sqfujlvp`lmpjpwfmwozbqf#hmltm#bpwkf#ejfog#lewkjp#wzsf#ledjufm#wl#wkfwkf#wjwof#le`lmwbjmp#wkfjmpwbm`fp#lejm#wkf#mlqwkgvf#wl#wkfjqbqf#gfpjdmfg`lqslqbwjlmptbp#wkbw#wkflmf#le#wkfpfnlqf#slsvobqpv``ffgfg#jmpvsslqw#eqlnjm#gjeefqfmwglnjmbwfg#azgfpjdmfg#elqltmfqpkjs#lebmg#slppjaozpwbmgbqgjyfgqfpslmpfWf{wtbp#jmwfmgfgqf`fjufg#wkfbppvnfg#wkbwbqfbp#le#wkfsqjnbqjoz#jmwkf#abpjp#lejm#wkf#pfmpfb``lvmwp#elqgfpwqlzfg#azbw#ofbpw#wtltbp#gf`obqfg`lvog#mlw#afPf`qfwbqz#lebssfbq#wl#afnbqdjm.wls92,]_p(\x7F_p(',df*xwkqlt#f~8wkf#pwbqw#lewtl#pfsbqbwfobmdvbdf#bmgtkl#kbg#affmlsfqbwjlm#legfbwk#le#wkfqfbo#mvnafqp\n?ojmh#qfo>!sqlujgfg#wkfwkf#pwlqz#le`lnsfwjwjlmpfmdojpk#+VH*fmdojpk#+VP*#evm`wjlm+*-isd!#tjgwk>!`lmejdvqbwjlm-smd!#tjgwk>!?algz#`obpp>!Nbwk-qbmgln+*`lmwfnslqbqz#Vmjwfg#Pwbwfp`jq`vnpwbm`fp-bssfmg@kjog+lqdbmjybwjlmp?psbm#`obpp>!!=?jnd#pq`>!,gjpwjmdvjpkfgwklvpbmgp#le#`lnnvmj`bwjlm`ofbq!=?,gju=jmufpwjdbwjlmebuj`lm-j`l!#nbqdjm.qjdkw9abpfg#lm#wkf#Nbppb`kvpfwwpwbaof#alqgfq>jmwfqmbwjlmbobopl#hmltm#bpsqlmvm`jbwjlmab`hdqlvmg9 esbggjmd.ofew9Elq#f{bnsof/#njp`foobmflvp%ow8,nbwk%dw8spz`kloldj`bojm#sbqwj`vobqfbq`k!#wzsf>!elqn#nfwklg>!bp#lsslpfg#wlPvsqfnf#@lvqwl``bpjlmbooz#Bggjwjlmbooz/Mlqwk#Bnfqj`bs{8ab`hdqlvmglsslqwvmjwjfpFmwfqwbjmnfmw-wlOltfq@bpf+nbmveb`wvqjmdsqlefppjlmbo#`lnajmfg#tjwkElq#jmpwbm`f/`lmpjpwjmd#le!#nb{ofmdwk>!qfwvqm#ebopf8`lmp`jlvpmfppNfgjwfqqbmfbmf{wqblqgjmbqzbppbppjmbwjlmpvapfrvfmwoz#avwwlm#wzsf>!wkf#mvnafq#lewkf#lqjdjmbo#`lnsqfkfmpjufqfefqp#wl#wkf?,vo=\t?,gju=\tskjolplskj`bool`bwjlm-kqfetbp#svaojpkfgPbm#Eqbm`jp`l+evm`wjlm+*x\t?gju#jg>!nbjmplskjpwj`bwfgnbwkfnbwj`bo#,kfbg=\x0E\t?algzpvddfpwp#wkbwgl`vnfmwbwjlm`lm`fmwqbwjlmqfobwjlmpkjspnbz#kbuf#affm+elq#f{bnsof/Wkjp#bqwj`of#jm#plnf#`bpfpsbqwp#le#wkf#gfejmjwjlm#leDqfbw#Aqjwbjm#`foosbggjmd>frvjubofmw#wlsob`fklogfq>!8#elmw.pjyf9#ivpwjej`bwjlmafojfufg#wkbwpveefqfg#eqlnbwwfnswfg#wl#ofbgfq#le#wkf`qjsw!#pq`>!,+evm`wjlm+*#xbqf#bubjobaof\t\n?ojmh#qfo>!#pq`>$kwws9,,jmwfqfpwfg#jm`lmufmwjlmbo#!#bow>!!#,=?,bqf#dfmfqboozkbp#bopl#affmnlpw#slsvobq#`lqqfpslmgjmd`qfgjwfg#tjwkwzof>!alqgfq9?,b=?,psbm=?,-dje!#tjgwk>!?jeqbnf#pq`>!wbaof#`obpp>!jmojmf.aol`h8b``lqgjmd#wl#wldfwkfq#tjwkbssql{jnbwfozsbqojbnfmwbqznlqf#bmg#nlqfgjpsobz9mlmf8wqbgjwjlmboozsqfglnjmbmwoz%maps8\x7F%maps8%maps8?,psbm=#`foopsb`jmd>?jmsvw#mbnf>!lq!#`lmwfmw>!`lmwqlufqpjbosqlsfqwz>!ld9,{.pkl`htbuf.gfnlmpwqbwjlmpvqqlvmgfg#azMfufqwkfofpp/tbp#wkf#ejqpw`lmpjgfqbaof#Bowklvdk#wkf#`loobalqbwjlmpklvog#mlw#afsqlslqwjlm#le?psbm#pwzof>!hmltm#bp#wkf#pklqwoz#bewfqelq#jmpwbm`f/gfp`qjafg#bp#,kfbg=\t?algz#pwbqwjmd#tjwkjm`qfbpjmdoz#wkf#eb`w#wkbwgjp`vppjlm#lenjggof#le#wkfbm#jmgjujgvbogjeej`vow#wl#sljmw#le#ujftklnlpf{vbojwzb``fswbm`f#le?,psbm=?,gju=nbmveb`wvqfqplqjdjm#le#wkf`lnnlmoz#vpfgjnslqwbm`f#legfmlnjmbwjlmpab`hdqlvmg9# ofmdwk#le#wkfgfwfqnjmbwjlmb#pjdmjej`bmw!#alqgfq>!3!=qfulovwjlmbqzsqjm`jsofp#lejp#`lmpjgfqfgtbp#gfufolsfgJmgl.Fvqlsfbmuvomfqbaof#wlsqlslmfmwp#lebqf#plnfwjnfp`olpfq#wl#wkfMft#Zlqh#@jwz#mbnf>!pfbq`kbwwqjavwfg#wl`lvqpf#le#wkfnbwkfnbwj`jbmaz#wkf#fmg#lebw#wkf#fmg#le!#alqgfq>!3!#wf`kmloldj`bo-qfnluf@obpp+aqbm`k#le#wkffujgfm`f#wkbw\"Xfmgje^..=\x0E\tJmpwjwvwf#le#jmwl#b#pjmdofqfpsf`wjufoz-bmg#wkfqfelqfsqlsfqwjfp#lejp#ol`bwfg#jmplnf#le#tkj`kWkfqf#jp#bopl`lmwjmvfg#wl#bssfbqbm`f#le#%bns8mgbpk8#gfp`qjafp#wkf`lmpjgfqbwjlmbvwklq#le#wkfjmgfsfmgfmwozfrvjssfg#tjwkglfp#mlw#kbuf?,b=?b#kqfe>!`lmevpfg#tjwk?ojmh#kqfe>!,bw#wkf#bdf#lebssfbq#jm#wkfWkfpf#jm`ovgfqfdbqgofpp#le`lvog#af#vpfg#pwzof>%rvlw8pfufqbo#wjnfpqfsqfpfmw#wkfalgz=\t?,kwno=wklvdkw#wl#afslsvobwjlm#leslppjajojwjfpsfq`fmwbdf#leb``fpp#wl#wkfbm#bwwfnsw#wlsqlgv`wjlm#leirvfqz,irvfqzwtl#gjeefqfmwafolmd#wl#wkffpwbaojpknfmwqfsob`jmd#wkfgfp`qjswjlm!#gfwfqnjmf#wkfbubjobaof#elqB``lqgjmd#wl#tjgf#qbmdf#le\n?gju#`obpp>!nlqf#`lnnlmozlqdbmjpbwjlmpevm`wjlmbojwztbp#`lnsofwfg#%bns8ngbpk8#sbqwj`jsbwjlmwkf#`kbqb`wfqbm#bggjwjlmbobssfbqp#wl#afeb`w#wkbw#wkfbm#f{bnsof#lepjdmjej`bmwozlmnlvpflufq>!af`bvpf#wkfz#bpzm`#>#wqvf8sqlaofnp#tjwkpffnp#wl#kbufwkf#qfpvow#le#pq`>!kwws9,,ebnjojbq#tjwkslppfppjlm#leevm`wjlm#+*#xwllh#sob`f#jmbmg#plnfwjnfppvapwbmwjbooz?psbm=?,psbm=jp#lewfm#vpfgjm#bm#bwwfnswdqfbw#gfbo#leFmujqlmnfmwbopv``fppevooz#ujqwvbooz#boo13wk#`fmwvqz/sqlefppjlmbopmf`fppbqz#wl#gfwfqnjmfg#az`lnsbwjajojwzaf`bvpf#jw#jpGj`wjlmbqz#lenlgjej`bwjlmpWkf#elooltjmdnbz#qfefq#wl9@lmpfrvfmwoz/Jmwfqmbwjlmbobowklvdk#plnfwkbw#tlvog#aftlqog$p#ejqpw`obppjejfg#bpalwwln#le#wkf+sbqwj`vobqozbojdm>!ofew!#nlpw#`lnnlmozabpjp#elq#wkfelvmgbwjlm#le`lmwqjavwjlmpslsvobqjwz#le`fmwfq#le#wkfwl#qfgv`f#wkfivqjpgj`wjlmpbssql{jnbwjlm#lmnlvpflvw>!Mft#Wfpwbnfmw`loof`wjlm#le?,psbm=?,b=?,jm#wkf#Vmjwfgejon#gjqf`wlq.pwqj`w-gwg!=kbp#affm#vpfgqfwvqm#wl#wkfbowklvdk#wkjp`kbmdf#jm#wkfpfufqbo#lwkfqavw#wkfqf#bqfvmsqf`fgfmwfgjp#pjnjobq#wlfpsf`jbooz#jmtfjdkw9#alog8jp#`boofg#wkf`lnsvwbwjlmbojmgj`bwf#wkbwqfpwqj`wfg#wl\n?nfwb#mbnf>!bqf#wzsj`booz`lmeoj`w#tjwkKltfufq/#wkf#Bm#f{bnsof#le`lnsbqfg#tjwkrvbmwjwjfp#leqbwkfq#wkbm#b`lmpwfoobwjlmmf`fppbqz#elqqfslqwfg#wkbwpsf`jej`bwjlmslojwj`bo#bmg%maps8%maps8?qfefqfm`fp#wlwkf#pbnf#zfbqDlufqmnfmw#ledfmfqbwjlm#lekbuf#mlw#affmpfufqbo#zfbqp`lnnjwnfmw#wl\n\n?vo#`obpp>!ujpvbojybwjlm2:wk#`fmwvqz/sqb`wjwjlmfqpwkbw#kf#tlvogbmg#`lmwjmvfgl``vsbwjlm#lejp#gfejmfg#bp`fmwqf#le#wkfwkf#bnlvmw#le=?gju#pwzof>!frvjubofmw#legjeefqfmwjbwfaqlvdkw#balvwnbqdjm.ofew9#bvwlnbwj`boozwklvdkw#le#bpPlnf#le#wkfpf\t?gju#`obpp>!jmsvw#`obpp>!qfsob`fg#tjwkjp#lmf#le#wkffgv`bwjlm#bmgjmeovfm`fg#azqfsvwbwjlm#bp\t?nfwb#mbnf>!b``lnnlgbwjlm?,gju=\t?,gju=obqdf#sbqw#leJmpwjwvwf#elqwkf#pl.`boofg#bdbjmpw#wkf#Jm#wkjp#`bpf/tbp#bssljmwfg`objnfg#wl#afKltfufq/#wkjpGfsbqwnfmw#lewkf#qfnbjmjmdfeef`w#lm#wkfsbqwj`vobqoz#gfbo#tjwk#wkf\t?gju#pwzof>!bonlpw#botbzpbqf#`vqqfmwozf{sqfppjlm#leskjolplskz#leelq#nlqf#wkbm`jujojybwjlmplm#wkf#jpobmgpfof`wfgJmgf{`bm#qfpvow#jm!#ubovf>!!#,=wkf#pwqv`wvqf#,=?,b=?,gju=Nbmz#le#wkfpf`bvpfg#az#wkfle#wkf#Vmjwfgpsbm#`obpp>!n`bm#af#wqb`fgjp#qfobwfg#wlaf`bnf#lmf#lejp#eqfrvfmwozojujmd#jm#wkfwkflqfwj`boozElooltjmd#wkfQfulovwjlmbqzdlufqmnfmw#jmjp#gfwfqnjmfgwkf#slojwj`bojmwqlgv`fg#jmpveej`jfmw#wlgfp`qjswjlm!=pklqw#pwlqjfppfsbqbwjlm#lebp#wl#tkfwkfqhmltm#elq#jwptbp#jmjwjboozgjpsobz9aol`hjp#bm#f{bnsofwkf#sqjm`jsbo`lmpjpwp#le#bqf`ldmjyfg#bp,algz=?,kwno=b#pvapwbmwjboqf`lmpwqv`wfgkfbg#le#pwbwfqfpjpwbm`f#wlvmgfqdqbgvbwfWkfqf#bqf#wtldqbujwbwjlmbobqf#gfp`qjafgjmwfmwjlmboozpfqufg#bp#wkf`obpp>!kfbgfqlsslpjwjlm#wlevmgbnfmwboozglnjmbwfg#wkfbmg#wkf#lwkfqboojbm`f#tjwktbp#elq`fg#wlqfpsf`wjufoz/bmg#slojwj`bojm#pvsslqw#lesflsof#jm#wkf13wk#`fmwvqz-bmg#svaojpkfgolbg@kbqwafbwwl#vmgfqpwbmgnfnafq#pwbwfpfmujqlmnfmwboejqpw#kboe#le`lvmwqjfp#bmgbq`kjwf`wvqboaf#`lmpjgfqfg`kbqb`wfqjyfg`ofbqJmwfqubobvwklqjwbwjufEfgfqbwjlm#letbp#pv``ffgfgbmg#wkfqf#bqfb#`lmpfrvfm`fwkf#Sqfpjgfmwbopl#jm`ovgfgeqff#plewtbqfpv``fppjlm#legfufolsfg#wkftbp#gfpwqlzfgbtbz#eqln#wkf8\t?,p`qjsw=\t?bowklvdk#wkfzelooltfg#az#bnlqf#sltfqevoqfpvowfg#jm#bVmjufqpjwz#leKltfufq/#nbmzwkf#sqfpjgfmwKltfufq/#plnfjp#wklvdkw#wlvmwjo#wkf#fmgtbp#bmmlvm`fgbqf#jnslqwbmwbopl#jm`ovgfp=?jmsvw#wzsf>wkf#`fmwfq#le#GL#MLW#BOWFQvpfg#wl#qfefqwkfnfp,wkbw#kbg#affmwkf#abpjp#elqkbp#gfufolsfgjm#wkf#pvnnfq`lnsbqbwjufozgfp`qjafg#wkfpv`k#bp#wklpfwkf#qfpvowjmdjp#jnslppjaofubqjlvp#lwkfqPlvwk#Beqj`bmkbuf#wkf#pbnffeef`wjufmfppjm#tkj`k#`bpf8#wf{w.bojdm9pwqv`wvqf#bmg8#ab`hdqlvmg9qfdbqgjmd#wkfpvsslqwfg#wkfjp#bopl#hmltmpwzof>!nbqdjmjm`ovgjmd#wkfabkbpb#Nfobzvmlqph#alhn/Iomlqph#mzmlqphpolufm)M(ajmbjmwfqmb`jlmbo`bojej`b`j/_m`lnvmj`b`j/_m`lmpwqv``j/_m!=?gju#`obpp>!gjpbnajdvbwjlmGlnbjmMbnf$/#$bgnjmjpwqbwjlmpjnvowbmflvpozwqbmpslqwbwjlmJmwfqmbwjlmbo#nbqdjm.alwwln9qfpslmpjajojwz?\"Xfmgje^..=\t?,=?nfwb#mbnf>!jnsofnfmwbwjlmjmeqbpwqv`wvqfqfsqfpfmwbwjlmalqgfq.alwwln9?,kfbg=\t?algz=>kwws&0B&1E&1E?elqn#nfwklg>!nfwklg>!slpw!#,ebuj`lm-j`l!#~*8\t?,p`qjsw=\t-pfwBwwqjavwf+Bgnjmjpwqbwjlm>#mft#Bqqbz+*8?\"Xfmgje^..=\x0E\tgjpsobz9aol`h8Vmelqwvmbwfoz/!=%maps8?,gju=,ebuj`lm-j`l!=>$pwzofpkffw$#jgfmwjej`bwjlm/#elq#f{bnsof/?oj=?b#kqfe>!,bm#bowfqmbwjufbp#b#qfpvow#lesw!=?,p`qjsw=\twzsf>!pvanjw!#\t+evm`wjlm+*#xqf`lnnfmgbwjlmelqn#b`wjlm>!,wqbmpelqnbwjlmqf`lmpwqv`wjlm-pwzof-gjpsobz#B``lqgjmd#wl#kjggfm!#mbnf>!bolmd#tjwk#wkfgl`vnfmw-algz-bssql{jnbwfoz#@lnnvmj`bwjlmpslpw!#b`wjlm>!nfbmjmd#%rvlw8..?\"Xfmgje^..=Sqjnf#Njmjpwfq`kbqb`wfqjpwj`?,b=#?b#`obpp>wkf#kjpwlqz#le#lmnlvpflufq>!wkf#dlufqmnfmwkqfe>!kwwsp9,,tbp#lqjdjmbooztbp#jmwqlgv`fg`obppjej`bwjlmqfsqfpfmwbwjufbqf#`lmpjgfqfg?\"Xfmgje^..=\t\tgfsfmgp#lm#wkfVmjufqpjwz#le#jm#`lmwqbpw#wl#sob`fklogfq>!jm#wkf#`bpf#lejmwfqmbwjlmbo#`lmpwjwvwjlmbopwzof>!alqgfq.9#evm`wjlm+*#xAf`bvpf#le#wkf.pwqj`w-gwg!=\t?wbaof#`obpp>!b``lnsbmjfg#azb``lvmw#le#wkf?p`qjsw#pq`>!,mbwvqf#le#wkf#wkf#sflsof#jm#jm#bggjwjlm#wlp*8#ip-jg#>#jg!#tjgwk>!233&!qfdbqgjmd#wkf#Qlnbm#@bwkloj`bm#jmgfsfmgfmwelooltjmd#wkf#-dje!#tjgwk>!2wkf#elooltjmd#gjp`qjnjmbwjlmbq`kbfloldj`bosqjnf#njmjpwfq-ip!=?,p`qjsw=`lnajmbwjlm#le#nbqdjmtjgwk>!`qfbwfFofnfmw+t-bwwb`kFufmw+?,b=?,wg=?,wq=pq`>!kwwsp9,,bJm#sbqwj`vobq/#bojdm>!ofew!#@yf`k#Qfsvaoj`Vmjwfg#Hjmdgln`lqqfpslmgfm`f`lm`ovgfg#wkbw-kwno!#wjwof>!+evm`wjlm#+*#x`lnfp#eqln#wkfbssoj`bwjlm#le?psbm#`obpp>!pafojfufg#wl#affnfmw+$p`qjsw$?,b=\t?,oj=\t?ojufqz#gjeefqfmw=?psbm#`obpp>!lswjlm#ubovf>!+bopl#hmltm#bp\n?oj=?b#kqfe>!=?jmsvw#mbnf>!pfsbqbwfg#eqlnqfefqqfg#wl#bp#ubojdm>!wls!=elvmgfq#le#wkfbwwfnswjmd#wl#`bqalm#gjl{jgf\t\t?gju#`obpp>!`obpp>!pfbq`k.,algz=\t?,kwno=lsslqwvmjwz#wl`lnnvmj`bwjlmp?,kfbg=\x0E\t?algz#pwzof>!tjgwk9Wj\rVSmd#Uj\rWkw`kbmdfp#jm#wkfalqgfq.`lolq9 3!#alqgfq>!3!#?,psbm=?,gju=?tbp#gjp`lufqfg!#wzsf>!wf{w!#*8\t?,p`qjsw=\t\tGfsbqwnfmw#le#f``ofpjbpwj`bowkfqf#kbp#affmqfpvowjmd#eqln?,algz=?,kwno=kbp#mfufq#affmwkf#ejqpw#wjnfjm#qfpslmpf#wlbvwlnbwj`booz#?,gju=\t\t?gju#jtbp#`lmpjgfqfgsfq`fmw#le#wkf!#,=?,b=?,gju=`loof`wjlm#le#gfp`fmgfg#eqlnpf`wjlm#le#wkfb``fsw.`kbqpfwwl#af#`lmevpfgnfnafq#le#wkf#sbggjmd.qjdkw9wqbmpobwjlm#lejmwfqsqfwbwjlm#kqfe>$kwws9,,tkfwkfq#lq#mlwWkfqf#bqf#boplwkfqf#bqf#nbmzb#pnboo#mvnafqlwkfq#sbqwp#lejnslppjaof#wl##`obpp>!avwwlmol`bwfg#jm#wkf-#Kltfufq/#wkfbmg#fufmwvboozBw#wkf#fmg#le#af`bvpf#le#jwpqfsqfpfmwp#wkf?elqn#b`wjlm>!#nfwklg>!slpw!jw#jp#slppjaofnlqf#ojhfoz#wlbm#jm`qfbpf#jmkbuf#bopl#affm`lqqfpslmgp#wlbmmlvm`fg#wkbwbojdm>!qjdkw!=nbmz#`lvmwqjfpelq#nbmz#zfbqpfbqojfpw#hmltmaf`bvpf#jw#tbpsw!=?,p`qjsw=\x0E#ubojdm>!wls!#jmkbajwbmwp#leelooltjmd#zfbq\x0E\t?gju#`obpp>!njoojlm#sflsof`lmwqlufqpjbo#`lm`fqmjmd#wkfbqdvf#wkbw#wkfdlufqmnfmw#bmgb#qfefqfm`f#wlwqbmpefqqfg#wlgfp`qjajmd#wkf#pwzof>!`lolq9bowklvdk#wkfqfafpw#hmltm#elqpvanjw!#mbnf>!nvowjsoj`bwjlmnlqf#wkbm#lmf#qf`ldmjwjlm#le@lvm`jo#le#wkffgjwjlm#le#wkf##?nfwb#mbnf>!Fmwfqwbjmnfmw#btbz#eqln#wkf#8nbqdjm.qjdkw9bw#wkf#wjnf#lejmufpwjdbwjlmp`lmmf`wfg#tjwkbmg#nbmz#lwkfqbowklvdk#jw#jpafdjmmjmd#tjwk#?psbm#`obpp>!gfp`fmgbmwp#le?psbm#`obpp>!j#bojdm>!qjdkw!?,kfbg=\t?algz#bpsf`wp#le#wkfkbp#pjm`f#affmFvqlsfbm#Vmjlmqfnjmjp`fmw#lenlqf#gjeej`vowUj`f#Sqfpjgfmw`lnslpjwjlm#lesbppfg#wkqlvdknlqf#jnslqwbmwelmw.pjyf922s{f{sobmbwjlm#lewkf#`lm`fsw#letqjwwfm#jm#wkf\n?psbm#`obpp>!jp#lmf#le#wkf#qfpfnaobm`f#wllm#wkf#dqlvmgptkj`k#`lmwbjmpjm`ovgjmd#wkf#gfejmfg#az#wkfsvaoj`bwjlm#lenfbmp#wkbw#wkflvwpjgf#le#wkfpvsslqw#le#wkf?jmsvw#`obpp>!?psbm#`obpp>!w+Nbwk-qbmgln+*nlpw#sqlnjmfmwgfp`qjswjlm#le@lmpwbmwjmlsoftfqf#svaojpkfg?gju#`obpp>!pfbssfbqp#jm#wkf2!#kfjdkw>!2!#nlpw#jnslqwbmwtkj`k#jm`ovgfptkj`k#kbg#affmgfpwqv`wjlm#lewkf#slsvobwjlm\t\n?gju#`obpp>!slppjajojwz#leplnfwjnfp#vpfgbssfbq#wl#kbufpv``fpp#le#wkfjmwfmgfg#wl#afsqfpfmw#jm#wkfpwzof>!`ofbq9a\x0E\t?,p`qjsw=\x0E\t?tbp#elvmgfg#jmjmwfqujft#tjwk\\jg!#`lmwfmw>!`bsjwbo#le#wkf\x0E\t?ojmh#qfo>!pqfofbpf#le#wkfsljmw#lvw#wkbw{NOKwwsQfrvfpwbmg#pvapfrvfmwpf`lmg#obqdfpwufqz#jnslqwbmwpsf`jej`bwjlmppvqeb`f#le#wkfbssojfg#wl#wkfelqfjdm#sloj`z\\pfwGlnbjmMbnffpwbaojpkfg#jmjp#afojfufg#wlJm#bggjwjlm#wlnfbmjmd#le#wkfjp#mbnfg#bewfqwl#sqlwf`w#wkfjp#qfsqfpfmwfgGf`obqbwjlm#lenlqf#feej`jfmw@obppjej`bwjlmlwkfq#elqnp#lekf#qfwvqmfg#wl?psbm#`obpp>!`sfqelqnbm`f#le+evm`wjlm+*#x\x0Eje#bmg#lmoz#jeqfdjlmp#le#wkfofbgjmd#wl#wkfqfobwjlmp#tjwkVmjwfg#Mbwjlmppwzof>!kfjdkw9lwkfq#wkbm#wkfzsf!#`lmwfmw>!Bppl`jbwjlm#le\t?,kfbg=\t?algzol`bwfg#lm#wkfjp#qfefqqfg#wl+jm`ovgjmd#wkf`lm`fmwqbwjlmpwkf#jmgjujgvbobnlmd#wkf#nlpwwkbm#bmz#lwkfq,=\t?ojmh#qfo>!#qfwvqm#ebopf8wkf#svqslpf#lewkf#bajojwz#wl8`lolq9 eee~\t-\t?psbm#`obpp>!wkf#pvaif`w#legfejmjwjlmp#le=\x0E\t?ojmh#qfo>!`objn#wkbw#wkfkbuf#gfufolsfg?wbaof#tjgwk>!`fofaqbwjlm#leElooltjmd#wkf#wl#gjpwjmdvjpk?psbm#`obpp>!awbhfp#sob`f#jmvmgfq#wkf#mbnfmlwfg#wkbw#wkf=?\"Xfmgje^..=\tpwzof>!nbqdjm.jmpwfbg#le#wkfjmwqlgv`fg#wkfwkf#sql`fpp#lejm`qfbpjmd#wkfgjeefqfm`fp#jmfpwjnbwfg#wkbwfpsf`jbooz#wkf,gju=?gju#jg>!tbp#fufmwvboozwkqlvdklvw#kjpwkf#gjeefqfm`fplnfwkjmd#wkbwpsbm=?,psbm=?,pjdmjej`bmwoz#=?,p`qjsw=\x0E\t\x0E\tfmujqlmnfmwbo#wl#sqfufmw#wkfkbuf#affm#vpfgfpsf`jbooz#elqvmgfqpwbmg#wkfjp#fppfmwjbooztfqf#wkf#ejqpwjp#wkf#obqdfpwkbuf#affm#nbgf!#pq`>!kwws9,,jmwfqsqfwfg#bppf`lmg#kboe#le`qloojmd>!ml!#jp#`lnslpfg#leJJ/#Kloz#Qlnbmjp#f{sf`wfg#wlkbuf#wkfjq#ltmgfejmfg#bp#wkfwqbgjwjlmbooz#kbuf#gjeefqfmwbqf#lewfm#vpfgwl#fmpvqf#wkbwbdqffnfmw#tjwk`lmwbjmjmd#wkfbqf#eqfrvfmwozjmelqnbwjlm#lmf{bnsof#jp#wkfqfpvowjmd#jm#b?,b=?,oj=?,vo=#`obpp>!ellwfqbmg#fpsf`jboozwzsf>!avwwlm!#?,psbm=?,psbm=tkj`k#jm`ovgfg=\t?nfwb#mbnf>!`lmpjgfqfg#wkf`bqqjfg#lvw#azKltfufq/#jw#jpaf`bnf#sbqw#lejm#qfobwjlm#wlslsvobq#jm#wkfwkf#`bsjwbo#letbp#leej`jbooztkj`k#kbp#affmwkf#Kjpwlqz#lebowfqmbwjuf#wlgjeefqfmw#eqlnwl#pvsslqw#wkfpvddfpwfg#wkbwjm#wkf#sql`fpp##?gju#`obpp>!wkf#elvmgbwjlmaf`bvpf#le#kjp`lm`fqmfg#tjwkwkf#vmjufqpjwzlsslpfg#wl#wkfwkf#`lmwf{w#le?psbm#`obpp>!swf{w!#mbnf>!r!\n\n?gju#`obpp>!wkf#p`jfmwjej`qfsqfpfmwfg#aznbwkfnbwj`jbmpfof`wfg#az#wkfwkbw#kbuf#affm=?gju#`obpp>!`gju#jg>!kfbgfqjm#sbqwj`vobq/`lmufqwfg#jmwl*8\t?,p`qjsw=\t?skjolplskj`bo#pqsphlkqubwphjwj\rVSmd#Uj\rWkw!kwws9,,!=?psbm#`obpp>!nfnafqp#le#wkf#tjmglt-ol`bwjlmufqwj`bo.bojdm9,b=#\x7F#?b#kqfe>!?\"gl`wzsf#kwno=nfgjb>!p`qffm!#?lswjlm#ubovf>!ebuj`lm-j`l!#,=\t\n\n?gju#`obpp>!`kbqb`wfqjpwj`p!#nfwklg>!dfw!#,algz=\t?,kwno=\tpklqw`vw#j`lm!#gl`vnfmw-tqjwf+sbggjmd.alwwln9qfsqfpfmwbwjufppvanjw!#ubovf>!bojdm>!`fmwfq!#wkqlvdklvw#wkf#p`jfm`f#ej`wjlm\t##?gju#`obpp>!pvanjw!#`obpp>!lmf#le#wkf#nlpw#ubojdm>!wls!=?tbp#fpwbaojpkfg*8\x0E\t?,p`qjsw=\x0E\tqfwvqm#ebopf8!=*-pwzof-gjpsobzaf`bvpf#le#wkf#gl`vnfmw-`llhjf?elqn#b`wjlm>!,~algzxnbqdjm938Fm`z`olsfgjb#leufqpjlm#le#wkf#-`qfbwfFofnfmw+mbnf!#`lmwfmw>!?,gju=\t?,gju=\t\tbgnjmjpwqbwjuf#?,algz=\t?,kwno=kjpwlqz#le#wkf#!=?jmsvw#wzsf>!slqwjlm#le#wkf#bp#sbqw#le#wkf#%maps8?b#kqfe>!lwkfq#`lvmwqjfp!=\t?gju#`obpp>!?,psbm=?,psbm=?Jm#lwkfq#tlqgp/gjpsobz9#aol`h8`lmwqlo#le#wkf#jmwqlgv`wjlm#le,=\t?nfwb#mbnf>!bp#tfoo#bp#wkf#jm#qf`fmw#zfbqp\x0E\t\n?gju#`obpp>!?,gju=\t\n?,gju=\tjmpsjqfg#az#wkfwkf#fmg#le#wkf#`lnsbwjaof#tjwkaf`bnf#hmltm#bp#pwzof>!nbqdjm9-ip!=?,p`qjsw=?#Jmwfqmbwjlmbo#wkfqf#kbuf#affmDfqnbm#obmdvbdf#pwzof>!`lolq9 @lnnvmjpw#Sbqwz`lmpjpwfmw#tjwkalqgfq>!3!#`foo#nbqdjmkfjdkw>!wkf#nbilqjwz#le!#bojdm>!`fmwfqqfobwfg#wl#wkf#nbmz#gjeefqfmw#Lqwklgl{#@kvq`kpjnjobq#wl#wkf#,=\t?ojmh#qfo>!ptbp#lmf#le#wkf#vmwjo#kjp#gfbwk~*+*8\t?,p`qjsw=lwkfq#obmdvbdfp`lnsbqfg#wl#wkfslqwjlmp#le#wkfwkf#Mfwkfqobmgpwkf#nlpw#`lnnlmab`hdqlvmg9vqo+bqdvfg#wkbw#wkfp`qloojmd>!ml!#jm`ovgfg#jm#wkfMlqwk#Bnfqj`bm#wkf#mbnf#le#wkfjmwfqsqfwbwjlmpwkf#wqbgjwjlmbogfufolsnfmw#le#eqfrvfmwoz#vpfgb#`loof`wjlm#leufqz#pjnjobq#wlpvqqlvmgjmd#wkff{bnsof#le#wkjpbojdm>!`fmwfq!=tlvog#kbuf#affmjnbdf\\`bswjlm#>bwwb`kfg#wl#wkfpvddfpwjmd#wkbwjm#wkf#elqn#le#jmuloufg#jm#wkfjp#gfqjufg#eqlnmbnfg#bewfq#wkfJmwqlgv`wjlm#wlqfpwqj`wjlmp#lm#pwzof>!tjgwk9#`bm#af#vpfg#wl#wkf#`qfbwjlm#lenlpw#jnslqwbmw#jmelqnbwjlm#bmgqfpvowfg#jm#wkf`loobspf#le#wkfWkjp#nfbmp#wkbwfofnfmwp#le#wkftbp#qfsob`fg#azbmbozpjp#le#wkfjmpsjqbwjlm#elqqfdbqgfg#bp#wkfnlpw#pv``fppevohmltm#bp#%rvlw8b#`lnsqfkfmpjufKjpwlqz#le#wkf#tfqf#`lmpjgfqfgqfwvqmfg#wl#wkfbqf#qfefqqfg#wlVmplvq`fg#jnbdf=\t\n?gju#`obpp>!`lmpjpwp#le#wkfpwlsSqlsbdbwjlmjmwfqfpw#jm#wkfbubjobajojwz#lebssfbqp#wl#kbuffof`wqlnbdmfwj`fmbaofPfquj`fp+evm`wjlm#le#wkfJw#jp#jnslqwbmw?,p`qjsw=?,gju=evm`wjlm+*xubq#qfobwjuf#wl#wkfbp#b#qfpvow#le#wkf#slpjwjlm#leElq#f{bnsof/#jm#nfwklg>!slpw!#tbp#elooltfg#az%bns8ngbpk8#wkfwkf#bssoj`bwjlmip!=?,p`qjsw=\x0E\tvo=?,gju=?,gju=bewfq#wkf#gfbwktjwk#qfpsf`w#wlpwzof>!sbggjmd9jp#sbqwj`vobqozgjpsobz9jmojmf8#wzsf>!pvanjw!#jp#gjujgfg#jmwl\bTA\nzk#+\x0BBl\bQ\x7F*qfpslmpbajojgbgbgnjmjpwqb`j/_mjmwfqmb`jlmbofp`lqqfpslmgjfmwf\fHe\fHF\fHC\fIg\fH{\fHF\fIn\fH\\\fIa\fHY\fHU\fHB\fHR\fH\\\fIk\fH^\fIg\fH{\fIg\fHn\fHv\fIm\fHD\fHR\fHY\fH^\fIk\fHy\fHS\fHD\fHT\fH\\\fHy\fHR\fH\\\fHF\fIm\fH^\fHS\fHT\fHz\fIg\fHp\fIk\fHn\fHv\fHR\fHU\fHS\fHc\fHA\fIk\fHp\fIk\fHn\fHZ\fHR\fHB\fHS\fH^\fHU\fHB\fHR\fH\\\fIl\fHp\fHR\fH{\fH\\\fHO\fH@\fHD\fHR\fHD\fIk\fHy\fIm\fHB\fHR\fH\\\fH@\fIa\fH^\fIe\fH{\fHB\fHR\fH^\fHS\fHy\fHB\fHU\fHS\fH^\fHR\fHF\fIo\fH[\fIa\fHL\fH@\fHN\fHP\fHH\fIk\fHA\fHR\fHp\fHF\fHR\fHy\fIa\fH^\fHS\fHy\fHs\fIa\fH\\\fIk\fHD\fHz\fHS\fH^\fHR\fHG\fHJ\fI`\fH\\\fHR\fHD\fHB\fHR\fHB\fH^\fIk\fHB\fHH\fHJ\fHR\fHD\fH@\fHR\fHp\fHR\fH\\\fHY\fHS\fHy\fHR\fHT\fHy\fIa\fHC\fIg\fHn\fHv\fHR\fHU\fHH\fIk\fHF\fHU\fIm\fHm\fHv\fH@\fHH\fHR\fHC\fHR\fHT\fHn\fHY\fHR\fHJ\fHJ\fIk\fHz\fHD\fIk\fHF\fHS\fHw\fH^\fIk\fHY\fHS\fHZ\fIk\fH[\fH\\\fHR\fHp\fIa\fHC\fHe\fHH\fIa\fHH\fH\\\fHB\fIm\fHn\fH@\fHd\fHJ\fIg\fHD\fIg\fHn\fHe\fHF\fHy\fH\\\fHO\fHF\fHN\fHP\fIk\fHn\fHT\fIa\fHI\fHS\fHH\fHG\fHS\fH^\fIa\fHB\fHB\fIm\fHz\fIa\fHC\fHi\fHv\fIa\fHw\fHR\fHw\fIn\fHs\fHH\fIl\fHT\fHn\fH{\fIl\fHH\fHp\fHR\fHc\fH{\fHR\fHY\fHS\fHA\fHR\fH{\fHt\fHO\fIa\fHs\fIk\fHJ\fIn\fHT\fH\\\fIk\fHJ\fHS\fHD\fIg\fHn\fHU\fHH\fIa\fHC\fHR\fHT\fIk\fHy\fIa\fHT\fH{\fHR\fHn\fHK\fIl\fHY\fHS\fHZ\fIa\fHY\fH\\\fHR\fHH\fIk\fHn\fHJ\fId\fHs\fIa\fHT\fHD\fHy\fIa\fHZ\fHR\fHT\fHR\fHB\fHD\fIk\fHi\fHJ\fHR\fH^\fHH\fH@\fHS\fHp\fH^\fIl\fHF\fIm\fH\\\fIn\fH[\fHU\fHS\fHn\fHJ\fIl\fHB\fHS\fHH\fIa\fH\\\fHy\fHY\fHS\fHH\fHR\fH\\\fIm\fHF\fHC\fIk\fHT\fIa\fHI\fHR\fHD\fHy\fH\\\fIg\fHM\fHP\fHB\fIm\fHy\fIa\fHH\fHC\fIg\fHp\fHD\fHR\fHy\fIo\fHF\fHC\fHR\fHF\fIg\fHT\fIa\fHs\fHt\fH\\\fIk\fH^\fIn\fHy\fHR\fH\\\fIa\fHC\fHY\fHS\fHv\fHR\fH\\\fHT\fIn\fHv\fHD\fHR\fHB\fIn\fH^\fIa\fHC\fHJ\fIk\fHz\fIk\fHn\fHU\fHB\fIk\fHZ\fHR\fHT\fIa\fHy\fIn\fH^\fHB\fId\fHn\fHD\fIk\fHH\fId\fHC\fHR\fH\\\fHp\fHS\fHT\fHy\fIkqpp({no!#wjwof>!.wzsf!#`lmwfmw>!wjwof!#`lmwfmw>!bw#wkf#pbnf#wjnf-ip!=?,p`qjsw=\t?!#nfwklg>!slpw!#?,psbm=?,b=?,oj=ufqwj`bo.bojdm9w,irvfqz-njm-ip!=-`oj`h+evm`wjlm+#pwzof>!sbggjmd.~*+*8\t?,p`qjsw=\t?,psbm=?b#kqfe>!?b#kqfe>!kwws9,,*8#qfwvqm#ebopf8wf{w.gf`lqbwjlm9#p`qloojmd>!ml!#alqgfq.`loobspf9bppl`jbwfg#tjwk#Abkbpb#JmglmfpjbFmdojpk#obmdvbdf?wf{w#{no9psb`f>-dje!#alqgfq>!3!?,algz=\t?,kwno=\tlufqeolt9kjggfm8jnd#pq`>!kwws9,,bggFufmwOjpwfmfqqfpslmpjaof#elq#p-ip!=?,p`qjsw=\t,ebuj`lm-j`l!#,=lsfqbwjmd#pzpwfn!#pwzof>!tjgwk92wbqdfw>!\\aobmh!=Pwbwf#Vmjufqpjwzwf{w.bojdm9ofew8\tgl`vnfmw-tqjwf+/#jm`ovgjmd#wkf#bqlvmg#wkf#tlqog*8\x0E\t?,p`qjsw=\x0E\t?!#pwzof>!kfjdkw98lufqeolt9kjggfmnlqf#jmelqnbwjlmbm#jmwfqmbwjlmbob#nfnafq#le#wkf#lmf#le#wkf#ejqpw`bm#af#elvmg#jm#?,gju=\t\n\n?,gju=\tgjpsobz9#mlmf8!=!#,=\t?ojmh#qfo>!\t##+evm`wjlm+*#xwkf#26wk#`fmwvqz-sqfufmwGfebvow+obqdf#mvnafq#le#Azybmwjmf#Fnsjqf-isd\x7Fwkvna\x7Fofew\x7Fubpw#nbilqjwz#lenbilqjwz#le#wkf##bojdm>!`fmwfq!=Vmjufqpjwz#Sqfppglnjmbwfg#az#wkfPf`lmg#Tlqog#Tbqgjpwqjavwjlm#le#pwzof>!slpjwjlm9wkf#qfpw#le#wkf#`kbqb`wfqjyfg#az#qfo>!mleloolt!=gfqjufp#eqln#wkfqbwkfq#wkbm#wkf#b#`lnajmbwjlm#lepwzof>!tjgwk9233Fmdojpk.psfbhjmd`lnsvwfq#p`jfm`falqgfq>!3!#bow>!wkf#f{jpwfm`f#leGfnl`qbwj`#Sbqwz!#pwzof>!nbqdjm.Elq#wkjp#qfbplm/-ip!=?,p`qjsw=\t\npAzWbdMbnf+p*X3^ip!=?,p`qjsw=\x0E\t?-ip!=?,p`qjsw=\x0E\tojmh#qfo>!j`lm!#$#bow>$$#`obpp>$elqnbwjlm#le#wkfufqpjlmp#le#wkf#?,b=?,gju=?,gju=,sbdf=\t##?sbdf=\t?gju#`obpp>!`lmwaf`bnf#wkf#ejqpwabkbpb#Jmglmfpjbfmdojpk#+pjnsof*\"y\"W\"W\"[\"Q\"U\"V\"@=i=l<^<\\=n=m!?gju#jg>!ellwfq!=wkf#Vmjwfg#Pwbwfp?jnd#pq`>!kwws9,,-isd\x7Fqjdkw\x7Fwkvna\x7F-ip!=?,p`qjsw=\x0E\t?ol`bwjlm-sqlwl`loeqbnfalqgfq>!3!#p!#,=\t?nfwb#mbnf>!?,b=?,gju=?,gju=?elmw.tfjdkw9alog8%rvlw8#bmg#%rvlw8gfsfmgjmd#lm#wkf#nbqdjm938sbggjmd9!#qfo>!mleloolt!#Sqfpjgfmw#le#wkf#wtfmwjfwk#`fmwvqzfujpjlm=\t##?,sbdfJmwfqmfw#F{solqfqb-bpzm`#>#wqvf8\x0E\tjmelqnbwjlm#balvw?gju#jg>!kfbgfq!=!#b`wjlm>!kwws9,,?b#kqfe>!kwwsp9,,?gju#jg>!`lmwfmw!?,gju=\x0E\t?,gju=\x0E\t?gfqjufg#eqln#wkf#?jnd#pq`>$kwws9,,b``lqgjmd#wl#wkf#\t?,algz=\t?,kwno=\tpwzof>!elmw.pjyf9p`qjsw#obmdvbdf>!Bqjbo/#Kfoufwj`b/?,b=?psbm#`obpp>!?,p`qjsw=?p`qjsw#slojwj`bo#sbqwjfpwg=?,wq=?,wbaof=?kqfe>!kwws9,,ttt-jmwfqsqfwbwjlm#leqfo>!pwzofpkffw!#gl`vnfmw-tqjwf+$?`kbqpfw>!vwe.;!=\tafdjmmjmd#le#wkf#qfufbofg#wkbw#wkfwfofujpjlm#pfqjfp!#qfo>!mleloolt!=#wbqdfw>!\\aobmh!=`objnjmd#wkbw#wkfkwws&0B&1E&1Ettt-nbmjefpwbwjlmp#leSqjnf#Njmjpwfq#lejmeovfm`fg#az#wkf`obpp>!`ofbqej{!=,gju=\x0E\t?,gju=\x0E\t\x0E\twkqff.gjnfmpjlmbo@kvq`k#le#Fmdobmgle#Mlqwk#@bqlojmbprvbqf#hjolnfwqfp-bggFufmwOjpwfmfqgjpwjm`w#eqln#wkf`lnnlmoz#hmltm#bpSklmfwj`#Boskbafwgf`obqfg#wkbw#wkf`lmwqloofg#az#wkfAfmibnjm#Eqbmhojmqlof.sobzjmd#dbnfwkf#Vmjufqpjwz#lejm#Tfpwfqm#Fvqlsfsfqplmbo#`lnsvwfqSqlif`w#Dvwfmafqdqfdbqgofpp#le#wkfkbp#affm#sqlslpfgwldfwkfq#tjwk#wkf=?,oj=?oj#`obpp>!jm#plnf#`lvmwqjfpnjm-ip!=?,p`qjsw=le#wkf#slsvobwjlmleej`jbo#obmdvbdf?jnd#pq`>!jnbdfp,jgfmwjejfg#az#wkfmbwvqbo#qfplvq`fp`obppjej`bwjlm#le`bm#af#`lmpjgfqfgrvbmwvn#nf`kbmj`pMfufqwkfofpp/#wkfnjoojlm#zfbqp#bdl?,algz=\x0E\t?,kwno=\x0E\"y\"W\"W\"[\"Q\"U\"V\"@\twbhf#bgubmwbdf#lebmg/#b``lqgjmd#wlbwwqjavwfg#wl#wkfNj`qlplew#Tjmgltpwkf#ejqpw#`fmwvqzvmgfq#wkf#`lmwqlogju#`obpp>!kfbgfqpklqwoz#bewfq#wkfmlwbaof#f{`fswjlmwfmp#le#wklvpbmgppfufqbo#gjeefqfmwbqlvmg#wkf#tlqog-qfb`kjmd#njojwbqzjplobwfg#eqln#wkflsslpjwjlm#wl#wkfwkf#Log#WfpwbnfmwBeqj`bm#Bnfqj`bmpjmpfqwfg#jmwl#wkfpfsbqbwf#eqln#wkfnfwqlslojwbm#bqfbnbhfp#jw#slppjaofb`hmltofgdfg#wkbwbqdvbaoz#wkf#nlpwwzsf>!wf{w,`pp!=\twkf#JmwfqmbwjlmboB``lqgjmd#wl#wkf#sf>!wf{w,`pp!#,=\t`ljm`jgf#tjwk#wkfwtl.wkjqgp#le#wkfGvqjmd#wkjp#wjnf/gvqjmd#wkf#sfqjlgbmmlvm`fg#wkbw#kfwkf#jmwfqmbwjlmbobmg#nlqf#qf`fmwozafojfufg#wkbw#wkf`lmp`jlvpmfpp#bmgelqnfqoz#hmltm#bppvqqlvmgfg#az#wkfejqpw#bssfbqfg#jml``bpjlmbooz#vpfgslpjwjlm9baplovwf8!#wbqdfw>!\\aobmh!#slpjwjlm9qfobwjuf8wf{w.bojdm9`fmwfq8ib{,ojap,irvfqz,2-ab`hdqlvmg.`lolq9 wzsf>!bssoj`bwjlm,bmdvbdf!#`lmwfmw>!?nfwb#kwws.frvju>!Sqjub`z#Sloj`z?,b=f+!&0@p`qjsw#pq`>$!#wbqdfw>!\\aobmh!=Lm#wkf#lwkfq#kbmg/-isd\x7Fwkvna\x7Fqjdkw\x7F1?,gju=?gju#`obpp>!?gju#pwzof>!eolbw9mjmfwffmwk#`fmwvqz?,algz=\x0E\t?,kwno=\x0E\t?jnd#pq`>!kwws9,,p8wf{w.bojdm9`fmwfqelmw.tfjdkw9#alog8#B``lqgjmd#wl#wkf#gjeefqfm`f#afwtffm!#eqbnfalqgfq>!3!#!#pwzof>!slpjwjlm9ojmh#kqfe>!kwws9,,kwno7,ollpf-gwg!=\tgvqjmd#wkjp#sfqjlg?,wg=?,wq=?,wbaof=`olpfoz#qfobwfg#wlelq#wkf#ejqpw#wjnf8elmw.tfjdkw9alog8jmsvw#wzsf>!wf{w!#?psbm#pwzof>!elmw.lmqfbgzpwbwf`kbmdf\n?gju#`obpp>!`ofbqgl`vnfmw-ol`bwjlm-#Elq#f{bnsof/#wkf#b#tjgf#ubqjfwz#le#?\"GL@WZSF#kwno=\x0E\t?%maps8%maps8%maps8!=?b#kqfe>!kwws9,,pwzof>!eolbw9ofew8`lm`fqmfg#tjwk#wkf>kwws&0B&1E&1Ettt-jm#slsvobq#`vowvqfwzsf>!wf{w,`pp!#,=jw#jp#slppjaof#wl#Kbqubqg#Vmjufqpjwzwzofpkffw!#kqfe>!,wkf#nbjm#`kbqb`wfqL{elqg#Vmjufqpjwz##mbnf>!hfztlqgp!#`pwzof>!wf{w.bojdm9wkf#Vmjwfg#Hjmdglnefgfqbo#dlufqmnfmw?gju#pwzof>!nbqdjm#gfsfmgjmd#lm#wkf#gfp`qjswjlm#le#wkf?gju#`obpp>!kfbgfq-njm-ip!=?,p`qjsw=gfpwqv`wjlm#le#wkfpojdkwoz#gjeefqfmwjm#b``lqgbm`f#tjwkwfof`lnnvmj`bwjlmpjmgj`bwfp#wkbw#wkfpklqwoz#wkfqfbewfqfpsf`jbooz#jm#wkf#Fvqlsfbm#`lvmwqjfpKltfufq/#wkfqf#bqfpq`>!kwws9,,pwbwj`pvddfpwfg#wkbw#wkf!#pq`>!kwws9,,ttt-b#obqdf#mvnafq#le#Wfof`lnnvmj`bwjlmp!#qfo>!mleloolt!#wKloz#Qlnbm#Fnsfqlqbonlpw#f{`ovpjufoz!#alqgfq>!3!#bow>!Pf`qfwbqz#le#Pwbwf`vonjmbwjmd#jm#wkf@JB#Tlqog#Eb`wallhwkf#nlpw#jnslqwbmwbmmjufqpbqz#le#wkfpwzof>!ab`hdqlvmg.?oj=?fn=?b#kqfe>!,wkf#Bwobmwj`#L`fbmpwqj`woz#psfbhjmd/pklqwoz#afelqf#wkfgjeefqfmw#wzsfp#lewkf#Lwwlnbm#Fnsjqf=?jnd#pq`>!kwws9,,Bm#Jmwqlgv`wjlm#wl`lmpfrvfm`f#le#wkfgfsbqwvqf#eqln#wkf@lmefgfqbwf#Pwbwfpjmgjdfmlvp#sflsofpSql`ffgjmdp#le#wkfjmelqnbwjlm#lm#wkfwkflqjfp#kbuf#affmjmuloufnfmw#jm#wkfgjujgfg#jmwl#wkqffbgib`fmw#`lvmwqjfpjp#qfpslmpjaof#elqgjpplovwjlm#le#wkf`loobalqbwjlm#tjwktjgfoz#qfdbqgfg#bpkjp#`lmwfnslqbqjfpelvmgjmd#nfnafq#leGlnjmj`bm#Qfsvaoj`dfmfqbooz#b``fswfgwkf#slppjajojwz#lebqf#bopl#bubjobaofvmgfq#`lmpwqv`wjlmqfpwlqbwjlm#le#wkfwkf#dfmfqbo#svaoj`jp#bonlpw#fmwjqfozsbppfp#wkqlvdk#wkfkbp#affm#pvddfpwfg`lnsvwfq#bmg#ujgflDfqnbmj`#obmdvbdfp#b``lqgjmd#wl#wkf#gjeefqfmw#eqln#wkfpklqwoz#bewfqtbqgpkqfe>!kwwsp9,,ttt-qf`fmw#gfufolsnfmwAlbqg#le#Gjqf`wlqp?gju#`obpp>!pfbq`k\x7F#?b#kqfe>!kwws9,,Jm#sbqwj`vobq/#wkfNvowjsof#ellwmlwfplq#lwkfq#pvapwbm`fwklvpbmgp#le#zfbqpwqbmpobwjlm#le#wkf?,gju=\x0E\t?,gju=\x0E\t\x0E\t?b#kqfe>!jmgf{-skstbp#fpwbaojpkfg#jmnjm-ip!=?,p`qjsw=\tsbqwj`jsbwf#jm#wkfb#pwqlmd#jmeovfm`fpwzof>!nbqdjm.wls9qfsqfpfmwfg#az#wkfdqbgvbwfg#eqln#wkfWqbgjwjlmbooz/#wkfFofnfmw+!p`qjsw!*8Kltfufq/#pjm`f#wkf,gju=\t?,gju=\t?gju#ofew8#nbqdjm.ofew9sqlwf`wjlm#bdbjmpw38#ufqwj`bo.bojdm9Vmelqwvmbwfoz/#wkfwzsf>!jnbdf,{.j`lm,gju=\t?gju#`obpp>!#`obpp>!`ofbqej{!=?gju#`obpp>!ellwfq\n\n?,gju=\t\n\n?,gju=\twkf#nlwjlm#sj`wvqf<}=f!t0-lqd,2:::,{kwno!=?b#wbqdfw>!\\aobmh!#wf{w,kwno8#`kbqpfw>!#wbqdfw>!\\aobmh!=?wbaof#`foosbggjmd>!bvwl`lnsofwf>!lee!#wf{w.bojdm9#`fmwfq8wl#obpw#ufqpjlm#az#ab`hdqlvmg.`lolq9# !#kqfe>!kwws9,,ttt-,gju=?,gju=?gju#jg>?b#kqfe>! !#`obpp>!!=?jnd#pq`>!kwws9,,`qjsw!#pq`>!kwws9,,\t?p`qjsw#obmdvbdf>!,,FM!#!kwws9,,ttt-tfm`lgfVQJ@lnslmfmw+!#kqfe>!ibubp`qjsw9?gju#`obpp>!`lmwfmwgl`vnfmw-tqjwf+$?p`slpjwjlm9#baplovwf8p`qjsw#pq`>!kwws9,,#pwzof>!nbqdjm.wls9-njm-ip!=?,p`qjsw=\t?,gju=\t?gju#`obpp>!t0-lqd,2:::,{kwno!#\t\x0E\t?,algz=\x0E\t?,kwno=gjpwjm`wjlm#afwtffm,!#wbqdfw>!\\aobmh!=?ojmh#kqfe>!kwws9,,fm`lgjmd>!vwe.;!<=\tt-bggFufmwOjpwfmfq!kwws9,,ttt-j`lm!#kqfe>!kwws9,,#pwzof>!ab`hdqlvmg9wzsf>!wf{w,`pp!#,=\tnfwb#sqlsfqwz>!ld9w?jmsvw#wzsf>!wf{w!##pwzof>!wf{w.bojdm9wkf#gfufolsnfmw#le#wzofpkffw!#wzsf>!wfkwno8#`kbqpfw>vwe.;jp#`lmpjgfqfg#wl#afwbaof#tjgwk>!233&!#Jm#bggjwjlm#wl#wkf#`lmwqjavwfg#wl#wkf#gjeefqfm`fp#afwtffmgfufolsnfmw#le#wkf#Jw#jp#jnslqwbmw#wl#?,p`qjsw=\t\t?p`qjsw##pwzof>!elmw.pjyf92=?,psbm=?psbm#jg>daOjaqbqz#le#@lmdqfpp?jnd#pq`>!kwws9,,jnFmdojpk#wqbmpobwjlmB`bgfnz#le#P`jfm`fpgju#pwzof>!gjpsobz9`lmpwqv`wjlm#le#wkf-dfwFofnfmwAzJg+jg*jm#`lmivm`wjlm#tjwkFofnfmw+$p`qjsw$*8#?nfwb#sqlsfqwz>!ld9<}=f!wf{w!#mbnf>!=Sqjub`z#Sloj`z?,b=bgnjmjpwfqfg#az#wkffmbaofPjmdofQfrvfpwpwzof>%rvlw8nbqdjm9?,gju=?,gju=?,gju=?=?jnd#pq`>!kwws9,,j#pwzof>%rvlw8eolbw9qfefqqfg#wl#bp#wkf#wlwbo#slsvobwjlm#lejm#Tbpkjmdwlm/#G-@-#pwzof>!ab`hdqlvmg.bnlmd#lwkfq#wkjmdp/lqdbmjybwjlm#le#wkfsbqwj`jsbwfg#jm#wkfwkf#jmwqlgv`wjlm#lejgfmwjejfg#tjwk#wkfej`wjlmbo#`kbqb`wfq#L{elqg#Vmjufqpjwz#njpvmgfqpwbmgjmd#leWkfqf#bqf/#kltfufq/pwzofpkffw!#kqfe>!,@lovnajb#Vmjufqpjwzf{sbmgfg#wl#jm`ovgfvpvbooz#qfefqqfg#wljmgj`bwjmd#wkbw#wkfkbuf#pvddfpwfg#wkbwbeejojbwfg#tjwk#wkf`lqqfobwjlm#afwtffmmvnafq#le#gjeefqfmw=?,wg=?,wq=?,wbaof=Qfsvaoj`#le#Jqfobmg\t?,p`qjsw=\t?p`qjsw#vmgfq#wkf#jmeovfm`f`lmwqjavwjlm#wl#wkfLeej`jbo#tfapjwf#lekfbgrvbqwfqp#le#wkf`fmwfqfg#bqlvmg#wkfjnsoj`bwjlmp#le#wkfkbuf#affm#gfufolsfgEfgfqbo#Qfsvaoj`#leaf`bnf#jm`qfbpjmdoz`lmwjmvbwjlm#le#wkfMlwf/#kltfufq/#wkbwpjnjobq#wl#wkbw#le#`bsbajojwjfp#le#wkfb``lqgbm`f#tjwk#wkfsbqwj`jsbmwp#jm#wkfevqwkfq#gfufolsnfmwvmgfq#wkf#gjqf`wjlmjp#lewfm#`lmpjgfqfgkjp#zlvmdfq#aqlwkfq?,wg=?,wq=?,wbaof=?b#kwws.frvju>![.VB.skzpj`bo#sqlsfqwjfple#Aqjwjpk#@lovnajbkbp#affm#`qjwj`jyfg+tjwk#wkf#f{`fswjlmrvfpwjlmp#balvw#wkfsbppjmd#wkqlvdk#wkf3!#`foosbggjmd>!3!#wklvpbmgp#le#sflsofqfgjqf`wp#kfqf-#Elqkbuf#`kjogqfm#vmgfq&0F&0@,p`qjsw&0F!**8?b#kqfe>!kwws9,,ttt-?oj=?b#kqfe>!kwws9,,pjwf\\mbnf!#`lmwfmw>!wf{w.gf`lqbwjlm9mlmfpwzof>!gjpsobz9#mlmf?nfwb#kwws.frvju>![.mft#Gbwf+*-dfwWjnf+*#wzsf>!jnbdf,{.j`lm!?,psbm=?psbm#`obpp>!obmdvbdf>!ibubp`qjswtjmglt-ol`bwjlm-kqfe?b#kqfe>!ibubp`qjsw9..=\x0E\t?p`qjsw#wzsf>!w?b#kqfe>$kwws9,,ttt-klqw`vw#j`lm!#kqfe>!?,gju=\x0E\t?gju#`obpp>!?p`qjsw#pq`>!kwws9,,!#qfo>!pwzofpkffw!#w?,gju=\t?p`qjsw#wzsf>,b=#?b#kqfe>!kwws9,,#booltWqbmpsbqfm`z>![.VB.@lnsbwjaof!#`lmqfobwjlmpkjs#afwtffm\t?,p`qjsw=\x0E\t?p`qjsw#?,b=?,oj=?,vo=?,gju=bppl`jbwfg#tjwk#wkf#sqldqbnnjmd#obmdvbdf?,b=?b#kqfe>!kwws9,,?,b=?,oj=?oj#`obpp>!elqn#b`wjlm>!kwws9,,?gju#pwzof>!gjpsobz9wzsf>!wf{w!#mbnf>!r!?wbaof#tjgwk>!233&!#ab`hdqlvmg.slpjwjlm9!#alqgfq>!3!#tjgwk>!qfo>!pklqw`vw#j`lm!#k5=?vo=?oj=?b#kqfe>!##?nfwb#kwws.frvju>!`pp!#nfgjb>!p`qffm!#qfpslmpjaof#elq#wkf#!#wzsf>!bssoj`bwjlm,!#pwzof>!ab`hdqlvmg.kwno8#`kbqpfw>vwe.;!#booltwqbmpsbqfm`z>!pwzofpkffw!#wzsf>!wf\x0E\t?nfwb#kwws.frvju>!=?,psbm=?psbm#`obpp>!3!#`foopsb`jmd>!3!=8\t?,p`qjsw=\t?p`qjsw#plnfwjnfp#`boofg#wkfglfp#mlw#mf`fppbqjozElq#nlqf#jmelqnbwjlmbw#wkf#afdjmmjmd#le#?\"GL@WZSF#kwno=?kwnosbqwj`vobqoz#jm#wkf#wzsf>!kjggfm!#mbnf>!ibubp`qjsw9uljg+3*8!feef`wjufmfpp#le#wkf#bvwl`lnsofwf>!lee!#dfmfqbooz#`lmpjgfqfg=?jmsvw#wzsf>!wf{w!#!=?,p`qjsw=\x0E\t?p`qjswwkqlvdklvw#wkf#tlqog`lnnlm#njp`lm`fswjlmbppl`jbwjlm#tjwk#wkf?,gju=\t?,gju=\t?gju#`gvqjmd#kjp#ojefwjnf/`lqqfpslmgjmd#wl#wkfwzsf>!jnbdf,{.j`lm!#bm#jm`qfbpjmd#mvnafqgjsolnbwj`#qfobwjlmpbqf#lewfm#`lmpjgfqfgnfwb#`kbqpfw>!vwe.;!#?jmsvw#wzsf>!wf{w!#f{bnsofp#jm`ovgf#wkf!=?jnd#pq`>!kwws9,,jsbqwj`jsbwjlm#jm#wkfwkf#fpwbaojpknfmw#le\t?,gju=\t?gju#`obpp>!%bns8maps8%bns8maps8wl#gfwfqnjmf#tkfwkfqrvjwf#gjeefqfmw#eqlnnbqhfg#wkf#afdjmmjmdgjpwbm`f#afwtffm#wkf`lmwqjavwjlmp#wl#wkf`lmeoj`w#afwtffm#wkftjgfoz#`lmpjgfqfg#wltbp#lmf#le#wkf#ejqpwtjwk#ubqzjmd#gfdqffpkbuf#psf`vobwfg#wkbw+gl`vnfmw-dfwFofnfmwsbqwj`jsbwjmd#jm#wkflqjdjmbooz#gfufolsfgfwb#`kbqpfw>!vwe.;!=#wzsf>!wf{w,`pp!#,=\tjmwfq`kbmdfbaoz#tjwknlqf#`olpfoz#qfobwfgpl`jbo#bmg#slojwj`bowkbw#tlvog#lwkfqtjpfsfqsfmgj`vobq#wl#wkfpwzof#wzsf>!wf{w,`ppwzsf>!pvanjw!#mbnf>!ebnjojfp#qfpjgjmd#jmgfufolsjmd#`lvmwqjfp`lnsvwfq#sqldqbnnjmdf`lmlnj`#gfufolsnfmwgfwfqnjmbwjlm#le#wkfelq#nlqf#jmelqnbwjlmlm#pfufqbo#l``bpjlmpslqwvdv/Fp#+Fvqlsfv*VWE.;!#pfwWjnflvw+evm`wjlm+*gjpsobz9jmojmf.aol`h8?jmsvw#wzsf>!pvanjw!#wzsf#>#$wf{w,ibubp`qj?jnd#pq`>!kwws9,,ttt-!#!kwws9,,ttt-t0-lqd,pklqw`vw#j`lm!#kqfe>!!#bvwl`lnsofwf>!lee!#?,b=?,gju=?gju#`obpp>?,b=?,oj=\t?oj#`obpp>!`pp!#wzsf>!wf{w,`pp!#?elqn#b`wjlm>!kwws9,,{w,`pp!#kqfe>!kwws9,,ojmh#qfo>!bowfqmbwf!#\x0E\t?p`qjsw#wzsf>!wf{w,#lm`oj`h>!ibubp`qjsw9+mft#Gbwf*-dfwWjnf+*~kfjdkw>!2!#tjgwk>!2!#Sflsof$p#Qfsvaoj`#le##?b#kqfe>!kwws9,,ttt-wf{w.gf`lqbwjlm9vmgfqwkf#afdjmmjmd#le#wkf#?,gju=\t?,gju=\t?,gju=\tfpwbaojpknfmw#le#wkf#?,gju=?,gju=?,gju=?,g ujftslqwxnjm.kfjdkw9\t?p`qjsw#pq`>!kwws9,,lswjlm=?lswjlm#ubovf>lewfm#qfefqqfg#wl#bp#,lswjlm=\t?lswjlm#ubov?\"GL@WZSF#kwno=\t?\"..XJmwfqmbwjlmbo#Bjqslqw=\t?b#kqfe>!kwws9,,ttt?,b=?b#kqfe>!kwws9,,t\fTL\fT^\fTE\fT^\fUh\fT{\fTN\roI\ro|\roL\ro{\roO\rov\rot\nAO\x05Gx\bTA\nzk#+\x0BUm\x05Gx*\fHD\fHS\fH\\\fIa\fHJ\fIk\fHZ\fHM\fHR\fHe\fHD\fH^\fIg\fHM\fHy\fIa\fH[\fIk\fHH\fIa\fH\\\fHp\fHR\fHD\fHy\fHR\fH\\\fIl\fHT\fHn\fH@\fHn\fHK\fHS\fHH\fHT\fIa\fHI\fHR\fHF\fHD\fHR\fHT\fIa\fHY\fIl\fHy\fHR\fH\\\fHT\fHn\fHT\fIa\fHy\fH\\\fHO\fHT\fHR\fHB\fH{\fIa\fH\\\fIl\fHv\fHS\fHs\fIa\fHL\fIg\fHn\fHY\fHS\fHp\fIa\fHr\fHR\fHD\fHi\fHB\fIk\fH\\\fHS\fHy\fHR\fHY\fHS\fHA\fHS\fHD\fIa\fHD\fH{\fHR\fHM\fHS\fHC\fHR\fHm\fHy\fIa\fHC\fIg\fHn\fHy\fHS\fHT\fIm\fH\\\fHy\fIa\fH[\fHR\fHF\fHU\fIm\fHm\fHv\fHH\fIl\fHF\fIa\fH\\\fH@\fHn\fHK\fHD\fHs\fHS\fHF\fIa\fHF\fHO\fIl\fHy\fIa\fH\\\fHS\fHy\fIk\fHs\fHF\fIa\fH\\\fHR\fH\\\fHn\fHA\fHF\fIa\fH\\\fHR\fHF\fIa\fHH\fHB\fHR\fH^\fHS\fHy\fIg\fHn\fH\\\fHG\fHP\fIa\fHH\fHR\fH\\\fHD\fHS\fH\\\fIa\fHB\fHR\fHO\fH^\fHS\fHB\fHS\fHs\fIk\fHMgfp`qjswjlm!#`lmwfmw>!gl`vnfmw-ol`bwjlm-sqlw-dfwFofnfmwpAzWbdMbnf+?\"GL@WZSF#kwno=\t?kwno#?nfwb#`kbqpfw>!vwe.;!=9vqo!#`lmwfmw>!kwws9,,-`pp!#qfo>!pwzofpkffw!pwzof#wzsf>!wf{w,`pp!=wzsf>!wf{w,`pp!#kqfe>!t0-lqd,2:::,{kwno!#{nowzsf>!wf{w,ibubp`qjsw!#nfwklg>!dfw!#b`wjlm>!ojmh#qfo>!pwzofpkffw!##>#gl`vnfmw-dfwFofnfmwwzsf>!jnbdf,{.j`lm!#,=`foosbggjmd>!3!#`foops-`pp!#wzsf>!wf{w,`pp!#?,b=?,oj=?oj=?b#kqfe>!!#tjgwk>!2!#kfjdkw>!2!!=?b#kqfe>!kwws9,,ttt-pwzof>!gjpsobz9mlmf8!=bowfqmbwf!#wzsf>!bssoj.,,T0@,,GWG#[KWNO#2-3#foopsb`jmd>!3!#`foosbg#wzsf>!kjggfm!#ubovf>!,b=%maps8?psbm#qlof>!p\t?jmsvw#wzsf>!kjggfm!#obmdvbdf>!IbubP`qjsw!##gl`vnfmw-dfwFofnfmwpAd>!3!#`foopsb`jmd>!3!#zsf>!wf{w,`pp!#nfgjb>!wzsf>$wf{w,ibubp`qjsw$tjwk#wkf#f{`fswjlm#le#zsf>!wf{w,`pp!#qfo>!pw#kfjdkw>!2!#tjgwk>!2!#>$(fm`lgfVQJ@lnslmfmw+?ojmh#qfo>!bowfqmbwf!#\talgz/#wq/#jmsvw/#wf{wnfwb#mbnf>!qlalwp!#`lmnfwklg>!slpw!#b`wjlm>!=\t?b#kqfe>!kwws9,,ttt-`pp!#qfo>!pwzofpkffw!#?,gju=?,gju=?gju#`obppobmdvbdf>!ibubp`qjsw!=bqjb.kjggfm>!wqvf!=.[?qjsw!#wzsf>!wf{w,ibubpo>38~*+*8\t+evm`wjlm+*xab`hdqlvmg.jnbdf9#vqo+,b=?,oj=?oj=?b#kqfe>!k\n\n?oj=?b#kqfe>!kwws9,,bwlq!#bqjb.kjggfm>!wqv=#?b#kqfe>!kwws9,,ttt-obmdvbdf>!ibubp`qjsw!#,lswjlm=\t?lswjlm#ubovf,gju=?,gju=?gju#`obpp>qbwlq!#bqjb.kjggfm>!wqf>+mft#Gbwf*-dfwWjnf+*slqwvdv/Fp#+gl#Aqbpjo*!wf{w,?nfwb#kwws.frvju>!@lmwfqbmpjwjlmbo,,FM!#!kwws9?kwno#{nomp>!kwws9,,ttt.,,T0@,,GWG#[KWNO#2-3#WGWG,{kwno2.wqbmpjwjlmbo,,ttt-t0-lqd,WQ,{kwno2,sf#>#$wf{w,ibubp`qjsw$8?nfwb#mbnf>!gfp`qjswjlmsbqfmwMlgf-jmpfqwAfelqf?jmsvw#wzsf>!kjggfm!#mbip!#wzsf>!wf{w,ibubp`qj+gl`vnfmw*-qfbgz+evm`wjp`qjsw#wzsf>!wf{w,ibubpjnbdf!#`lmwfmw>!kwws9,,VB.@lnsbwjaof!#`lmwfmw>wno8#`kbqpfw>vwe.;!#,=\tojmh#qfo>!pklqw`vw#j`lm?ojmh#qfo>!pwzofpkffw!#?,p`qjsw=\t?p`qjsw#wzsf>>#gl`vnfmw-`qfbwfFofnfm?b#wbqdfw>!\\aobmh!#kqfe>#gl`vnfmw-dfwFofnfmwpAjmsvw#wzsf>!wf{w!#mbnf>b-wzsf#>#$wf{w,ibubp`qjmsvw#wzsf>!kjggfm!#mbnfkwno8#`kbqpfw>vwe.;!#,=gwg!=\t?kwno#{nomp>!kwws.,,T0@,,GWG#KWNO#7-32#WfmwpAzWbdMbnf+$p`qjsw$*jmsvw#wzsf>!kjggfm!#mbn?p`qjsw#wzsf>!wf{w,ibubp!#pwzof>!gjpsobz9mlmf8!=gl`vnfmw-dfwFofnfmwAzJg+>gl`vnfmw-`qfbwfFofnfmw+$#wzsf>$wf{w,ibubp`qjsw$jmsvw#wzsf>!wf{w!#mbnf>!g-dfwFofnfmwpAzWbdMbnf+pmj`bo!#kqfe>!kwws9,,ttt-@,,GWG#KWNO#7-32#Wqbmpjw?pwzof#wzsf>!wf{w,`pp!=\t\t?pwzof#wzsf>!wf{w,`pp!=jlmbo-gwg!=\t?kwno#{nomp>kwws.frvju>!@lmwfmw.Wzsfgjmd>!3!#`foopsb`jmd>!3!kwno8#`kbqpfw>vwe.;!#,=\t#pwzof>!gjpsobz9mlmf8!=??oj=?b#kqfe>!kwws9,,ttt-#wzsf>$wf{w,ibubp`qjsw$=&*&'&^&\x88\u0178\u0C3E&\u01AD&\u0192&)&^&%&'&\x82&P&1&\xB1&3&]&m&u&E&t&C&\xCF&V&V&/&>&6&\u0F76\u177Co&p&@&E&M&P&x&@&F&e&\xCC&7&:&(&D&0&C&)&.&F&-&1&(&L&F&1\u025E*\u03EA\u21F3&\u1372&K&;&)&E&H&P&0&?&9&V&\x81&-&v&a&,&E&)&?&=&'&'&B&\u0D2E&\u0503&\u0316*&*8&%&%&&&%,)&\x9A&>&\x86&7&]&F&2&>&J&6&n&2&%&?&\x8E&2&6&J&g&-&0&,&*&J&*&O&)&6&(&<&B&N&.&P&@&2&.&W&M&%\u053C\x84(,(<&,&\u03DA&\u18C7&-&,(%&(&%&(\u013B0&X&D&\x81&j&'&J&(&.&B&3&Z&R&h&3&E&E&<\xC6-\u0360\u1EF3&%8?&@&,&Z&@&0&J&,&^&x&_&6&C&6&C\u072C\u2A25&f&-&-&-&-&,&J&2&8&z&8&C&Y&8&-&d&\u1E78\xCC-&7&1&F&7&t&W&7&I&.&.&^&=\u0F9C\u19D3&8(>&/&/&\u077B')'\u1065')'%@/&0&%\u043E\u09C0*&*@&C\u053D\u05D4\u0274\u05EB4\u0DD7\u071A\u04D16\u0D84&/\u0178\u0303Z&*%\u0246\u03FF&\u0134&1\xA8\u04B4\u0174", dictionarySizeBits, "AAAAKKLLKKKKKJJIHHIHHGGFF");
+ setData(dictionaryData, dictionarySizeBits);
+ function InputStream(data) {
+ this.data = new Int8Array(0);
+ this.offset = 0;
+ this.data = data;
+ }
+ function readInput(s, dst, offset, length) {
+ if (s.input === null) {
+ return -1;
+ }
+ const src = s.input;
+ const end = Math.min(src.offset + length, src.data.length);
+ const bytesRead = end - src.offset;
+ dst.set(src.data.subarray(src.offset, end), offset);
+ src.offset += bytesRead;
+ return bytesRead;
+ }
+ function closeInput(s) {
+ s.input = new InputStream(new Int8Array(0));
+ }
+ function toUsAsciiBytes(src) {
+ const n = src.length;
+ const result = new Int8Array(n);
+ for (let i = 0; i < n; ++i) {
+ result[i] = src.charCodeAt(i);
+ }
+ return result;
+ }
+ function toUtf8Runes(src) {
+ const n = src.length;
+ const result = new Int32Array(n);
+ for (let i = 0; i < n; ++i) {
+ result[i] = src.charCodeAt(i);
+ }
+ return result;
+ }
+ function makeError(s, code) {
+ if (code >= 0) {
+ return code;
+ }
+ if (s.runningState >= 0) {
+ s.runningState = code;
+ }
+ throw new Error("Brotli error code: " + code);
+ }
+ let ByteBuffer;
+ function decode(bytes, options) {
+ let s = new State();
+ s.input = new InputStream(bytes);
+ initState(s);
+ if (options) {
+ let customDictionary = options["customDictionary"];
+ if (customDictionary) attachDictionaryChunk(s, customDictionary);
+ }
+ let totalOutput = 0;
+ let chunks = [];
+ while (true) {
+ let chunk = new Int8Array(16384);
+ chunks.push(chunk);
+ s.output = chunk;
+ s.outputOffset = 0;
+ s.outputLength = 16384;
+ s.outputUsed = 0;
+ decompress(s);
+ totalOutput += s.outputUsed;
+ if (s.outputUsed < 16384) break;
+ }
+ close(s);
+ closeInput(s);
+ let result = new Int8Array(totalOutput);
+ let offset = 0;
+ for (let i = 0; i < chunks.length; ++i) {
+ let chunk = chunks[i];
+ let end = Math.min(totalOutput, offset + 16384);
+ let len = end - offset;
+ if (len < 16384) {
+ result.set(chunk.subarray(0, len), offset);
+ } else {
+ result.set(chunk, offset);
+ }
+ offset += len;
+ }
+ return result;
+ }
+ return decode;
+};
+let BrotliDecode = makeBrotliDecode();
+;// ./src/core/brotli_stream.js
+
+
+
+
+
+
+
+
+class BrotliStream extends DecodeStream {
+ #isAsync = true;
+ constructor(stream, maybeLength) {
+ super(maybeLength);
+ this.stream = stream;
+ this.dict = stream.dict;
+ }
+ readBlock() {
+ const bytes = this.stream.getBytes();
+ const decodedData = BrotliDecode(new Int8Array(bytes.buffer, bytes.byteOffset, bytes.length));
+ this.buffer = new Uint8Array(decodedData.buffer, decodedData.byteOffset, decodedData.length);
+ this.bufferLength = this.buffer.length;
+ this.eof = true;
+ }
+ async getImageData(length, _decoderOptions) {
+ const data = await this.asyncGetBytes();
+ if (!data) {
+ return this.getBytes(length);
+ }
+ if (data.length <= length) {
+ return data;
+ }
+ return data.subarray(0, length);
+ }
+ async asyncGetBytes() {
+ const {
+ decompressed,
+ compressed
+ } = await this.asyncGetBytesFromDecompressionStream("brotli");
+ if (decompressed) {
+ return decompressed;
+ }
+ this.#isAsync = false;
+ this.stream = new Stream(compressed, 0, compressed.length, this.stream.dict);
+ this.reset();
+ return null;
+ }
+ get isAsync() {
+ return this.#isAsync;
+ }
+}
+
+;// ./external/jbig2/jbig2.js
+
+
+
+
+
+
+async function JBig2(moduleArg = {}) {
+ var moduleRtn;
+ var Module = moduleArg;
+ var ENVIRONMENT_IS_WEB = true;
+ var ENVIRONMENT_IS_WORKER = false;
+ var arguments_ = [];
+ var thisProgram = "./this.program";
+ var quit_ = (status, toThrow) => {
+ throw toThrow;
+ };
+ var _scriptName = import.meta.url;
+ var scriptDirectory = "";
+ var readAsync, readBinary;
+ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+ try {
+ scriptDirectory = new URL(".", _scriptName).href;
+ } catch {}
+ readAsync = async url => {
+ var response = await fetch(url, {
+ credentials: "same-origin"
+ });
+ if (response.ok) {
+ return response.arrayBuffer();
+ }
+ throw new Error(response.status + " : " + response.url);
+ };
+ } else {}
+ var out = console.log.bind(console);
+ var err = console.error.bind(console);
+ var wasmBinary;
+ var ABORT = false;
+ var EXITSTATUS;
+ var readyPromiseResolve, readyPromiseReject;
+ var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64;
+ var HEAP64, HEAPU64;
+ var runtimeInitialized = false;
+ function updateMemoryViews() {
+ var b = wasmMemory.buffer;
+ HEAP8 = new Int8Array(b);
+ HEAP16 = new Int16Array(b);
+ HEAPU8 = new Uint8Array(b);
+ HEAPU16 = new Uint16Array(b);
+ HEAP32 = new Int32Array(b);
+ HEAPU32 = new Uint32Array(b);
+ HEAPF32 = new Float32Array(b);
+ HEAPF64 = new Float64Array(b);
+ HEAP64 = new BigInt64Array(b);
+ HEAPU64 = new BigUint64Array(b);
+ }
+ function preRun() {
+ if (Module["preRun"]) {
+ if (typeof Module["preRun"] == "function") Module["preRun"] = [Module["preRun"]];
+ while (Module["preRun"].length) {
+ addOnPreRun(Module["preRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(onPreRuns);
+ }
+ function initRuntime() {
+ runtimeInitialized = true;
+ wasmExports["j"]();
+ }
+ function postRun() {
+ if (Module["postRun"]) {
+ if (typeof Module["postRun"] == "function") Module["postRun"] = [Module["postRun"]];
+ while (Module["postRun"].length) {
+ addOnPostRun(Module["postRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(onPostRuns);
+ }
+ function abort(what) {
+ Module["onAbort"]?.(what);
+ what = "Aborted(" + what + ")";
+ err(what);
+ ABORT = true;
+ what += ". Build with -sASSERTIONS for more info.";
+ var e = new WebAssembly.RuntimeError(what);
+ readyPromiseReject?.(e);
+ throw e;
+ }
+ var wasmBinaryFile;
+ function getWasmImports() {
+ var imports = {
+ a: wasmImports
+ };
+ return imports;
+ }
+ async function createWasm() {
+ function receiveInstance(instance, module) {
+ wasmExports = instance.exports;
+ assignWasmExports(wasmExports);
+ updateMemoryViews();
+ return wasmExports;
+ }
+ var info = getWasmImports();
+ return new Promise((resolve, reject) => {
+ Module["instantiateWasm"](info, (inst, mod) => {
+ resolve(receiveInstance(inst, mod));
+ });
+ });
+ }
+ class ExitStatus {
+ name = "ExitStatus";
+ constructor(status) {
+ this.message = `Program terminated with exit(${status})`;
+ this.status = status;
+ }
+ }
+ var callRuntimeCallbacks = callbacks => {
+ while (callbacks.length > 0) {
+ callbacks.shift()(Module);
+ }
+ };
+ var onPostRuns = [];
+ var addOnPostRun = cb => onPostRuns.push(cb);
+ var onPreRuns = [];
+ var addOnPreRun = cb => onPreRuns.push(cb);
+ var noExitRuntime = true;
+ var __abort_js = () => abort("");
+ var runtimeKeepaliveCounter = 0;
+ var __emscripten_runtime_keepalive_clear = () => {
+ noExitRuntime = false;
+ runtimeKeepaliveCounter = 0;
+ };
+ var timers = {};
+ var handleException = e => {
+ if (e instanceof ExitStatus || e == "unwind") {
+ return EXITSTATUS;
+ }
+ quit_(1, e);
+ };
+ var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
+ var _proc_exit = code => {
+ EXITSTATUS = code;
+ if (!keepRuntimeAlive()) {
+ Module["onExit"]?.(code);
+ ABORT = true;
+ }
+ quit_(code, new ExitStatus(code));
+ };
+ var exitJS = (status, implicit) => {
+ EXITSTATUS = status;
+ _proc_exit(status);
+ };
+ var _exit = exitJS;
+ var maybeExit = () => {
+ if (!keepRuntimeAlive()) {
+ try {
+ _exit(EXITSTATUS);
+ } catch (e) {
+ handleException(e);
+ }
+ }
+ };
+ var callUserCallback = func => {
+ if (ABORT) {
+ return;
+ }
+ try {
+ return func();
+ } catch (e) {
+ handleException(e);
+ } finally {
+ maybeExit();
+ }
+ };
+ var _emscripten_get_now = () => performance.now();
+ var __setitimer_js = (which, timeout_ms) => {
+ if (timers[which]) {
+ clearTimeout(timers[which].id);
+ delete timers[which];
+ }
+ if (!timeout_ms) return 0;
+ var id = setTimeout(() => {
+ delete timers[which];
+ callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now()));
+ }, timeout_ms);
+ timers[which] = {
+ id,
+ timeout_ms
+ };
+ return 0;
+ };
+ function _createImageData(size) {
+ Module.imageData = new Uint8Array(size);
+ }
+ var getHeapMax = () => 2147483648;
+ var alignMemory = (size, alignment) => Math.ceil(size / alignment) * alignment;
+ var growMemory = size => {
+ var oldHeapSize = wasmMemory.buffer.byteLength;
+ var pages = (size - oldHeapSize + 65535) / 65536 | 0;
+ try {
+ wasmMemory.grow(pages);
+ updateMemoryViews();
+ return 1;
+ } catch (e) {}
+ };
+ var _emscripten_resize_heap = requestedSize => {
+ var oldSize = HEAPU8.length;
+ requestedSize >>>= 0;
+ var maxHeapSize = getHeapMax();
+ if (requestedSize > maxHeapSize) {
+ return false;
+ }
+ for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
+ var overGrownHeapSize = oldSize * (1 + .2 / cutDown);
+ overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
+ var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536));
+ var replacement = growMemory(newSize);
+ if (replacement) {
+ return true;
+ }
+ }
+ return false;
+ };
+ function _setImageData(array_ptr, pitch8, pitch32, height) {
+ if (pitch32 === pitch8) {
+ Module.imageData = new Uint8ClampedArray(HEAPU8.subarray(array_ptr, array_ptr + pitch32 * height));
+ return;
+ }
+ const destSize = pitch8 * height;
+ const imageData = Module.imageData = new Uint8ClampedArray(destSize);
+ for (let srcStart = array_ptr, destStart = 0; destStart < destSize; srcStart += pitch32, destStart += pitch8) {
+ imageData.set(HEAPU8.subarray(srcStart, srcStart + pitch8), destStart);
+ }
+ }
+ function _setLineData(line_ptr, pitch8, offset) {
+ Module.imageData.set(HEAPU8.subarray(line_ptr, line_ptr + pitch8), offset);
+ }
+ var writeArrayToMemory = (array, buffer) => {
+ HEAP8.set(array, buffer);
+ };
+ if (Module["noExitRuntime"]) noExitRuntime = Module["noExitRuntime"];
+ if (Module["print"]) out = Module["print"];
+ if (Module["printErr"]) err = Module["printErr"];
+ if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"];
+ if (Module["arguments"]) arguments_ = Module["arguments"];
+ if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
+ if (Module["preInit"]) {
+ if (typeof Module["preInit"] == "function") Module["preInit"] = [Module["preInit"]];
+ while (Module["preInit"].length > 0) {
+ Module["preInit"].shift()();
+ }
+ }
+ Module["writeArrayToMemory"] = writeArrayToMemory;
+ var _malloc, _free, _jbig2_decode, _ccitt_decode, __emscripten_timeout, memory, __indirect_function_table, wasmMemory;
+ function assignWasmExports(wasmExports) {
+ _malloc = Module["_malloc"] = wasmExports["k"];
+ _free = Module["_free"] = wasmExports["l"];
+ _jbig2_decode = Module["_jbig2_decode"] = wasmExports["m"];
+ _ccitt_decode = Module["_ccitt_decode"] = wasmExports["n"];
+ __emscripten_timeout = wasmExports["o"];
+ memory = wasmMemory = wasmExports["i"];
+ __indirect_function_table = wasmExports["__indirect_function_table"];
+ }
+ var wasmImports = {
+ e: __abort_js,
+ b: __emscripten_runtime_keepalive_clear,
+ c: __setitimer_js,
+ g: _createImageData,
+ d: _emscripten_resize_heap,
+ a: _proc_exit,
+ h: _setImageData,
+ f: _setLineData
+ };
+ function run() {
+ preRun();
+ function doRun() {
+ Module["calledRun"] = true;
+ if (ABORT) return;
+ initRuntime();
+ readyPromiseResolve?.(Module);
+ Module["onRuntimeInitialized"]?.();
+ postRun();
+ }
+ if (Module["setStatus"]) {
+ Module["setStatus"]("Running...");
+ setTimeout(() => {
+ setTimeout(() => Module["setStatus"](""), 1);
+ doRun();
+ }, 1);
+ } else {
+ doRun();
+ }
+ }
+ var wasmExports;
+ wasmExports = await createWasm();
+ run();
+ if (runtimeInitialized) {
+ moduleRtn = Module;
+ } else {
+ moduleRtn = new Promise((resolve, reject) => {
+ readyPromiseResolve = resolve;
+ readyPromiseReject = reject;
+ });
+ }
+ return moduleRtn;
+}
+/* harmony default export */ const jbig2 = (JBig2);
+;// ./src/core/wasm_image.js
+
+
+
+
+
+
+
+
+
+
+class WasmImage {
+ static #handler = null;
+ static #instances = new Set();
+ static #useWasm = true;
+ static #useWorkerFetch = true;
+ static #wasmUrl = null;
+ #buffer = null;
+ #modulePromise = null;
+ _filename = null;
+ _noWasmFilename = null;
+ static setOptions({
+ handler,
+ useWasm,
+ useWorkerFetch,
+ wasmUrl
+ }) {
+ WasmImage.#useWasm = useWasm;
+ WasmImage.#useWorkerFetch = useWorkerFetch;
+ WasmImage.#wasmUrl = wasmUrl;
+ if (!useWorkerFetch) {
+ WasmImage.#handler = handler;
+ }
+ }
+ static get instance() {
+ unreachable("Abstract getter `instance` accessed");
+ }
+ static cleanup() {
+ for (const instance of WasmImage.#instances) {
+ instance.#modulePromise = null;
+ }
+ }
+ constructor(trackInstance = false) {
+ if (trackInstance) {
+ WasmImage.#instances.add(this);
+ }
+ }
+ async #getJsModule(fallbackCallback) {
+ let instance = null;
+ try {
+ const mod = await import(
+ /*webpackIgnore: true*/
+ /*@vite-ignore*/
+ `${WasmImage.#wasmUrl}${this._noWasmFilename}`);
+ instance = mod.default();
+ } catch (ex) {
+ warn(`#getJsModule: ${ex}`);
+ }
+ fallbackCallback(instance);
+ }
+ async #instantiateWasm(fallbackCallback, imports, successCallback) {
+ try {
+ if (!this.#buffer) {
+ if (WasmImage.#useWorkerFetch) {
+ this.#buffer = await fetchBinaryData(`${WasmImage.#wasmUrl}${this._filename}`);
+ } else {
+ this.#buffer = await WasmImage.#handler.sendWithPromise("FetchBinaryData", {
+ kind: "wasmUrl",
+ filename: this._filename
+ });
+ }
+ }
+ const results = await WebAssembly.instantiate(this.#buffer, imports);
+ return successCallback(results.instance);
+ } catch (ex) {
+ warn(`#instantiateWasm: ${ex}`);
+ this.#getJsModule(fallbackCallback);
+ return null;
+ }
+ }
+ _getModule(ImageDecoder) {
+ if (!this.#modulePromise) {
+ const {
+ promise,
+ resolve
+ } = Promise.withResolvers();
+ const promises = [promise];
+ if (!WasmImage.#useWasm) {
+ this.#getJsModule(resolve);
+ } else {
+ promises.push(ImageDecoder({
+ warn: warn,
+ instantiateWasm: this.#instantiateWasm.bind(this, resolve)
+ }));
+ }
+ this.#modulePromise = Promise.race(promises);
+ }
+ return this.#modulePromise;
+ }
+ async decode(bytes, _params) {
+ unreachable("Abstract method `decode` called");
+ }
+}
+
+;// ./src/core/jbig2_ccittFax.js
+
+
+
+class Jbig2Error extends BaseException {
+ constructor(msg) {
+ super(msg, "Jbig2Error");
+ }
+}
+class JBig2CCITTFaxImage extends WasmImage {
+ _filename = "jbig2.wasm";
+ _noWasmFilename = "jbig2_nowasm_fallback.js";
+ static get instance() {
+ return shadow(this, "instance", new JBig2CCITTFaxImage(true));
+ }
+ async decode(bytes, width, height, globals, CCITTOptions) {
+ const module = await this._getModule(jbig2);
+ if (!module) {
+ throw new Jbig2Error("JBig2 failed to initialize");
+ }
+ let ptr, globalsPtr;
+ try {
+ const size = bytes.length;
+ ptr = module._malloc(size);
+ module.writeArrayToMemory(bytes, ptr);
+ if (CCITTOptions) {
+ module._ccitt_decode(ptr, size, width, height, CCITTOptions.K, CCITTOptions.EndOfLine ? 1 : 0, CCITTOptions.EncodedByteAlign ? 1 : 0, CCITTOptions.BlackIs1 ? 1 : 0, CCITTOptions.Columns, CCITTOptions.Rows);
+ } else {
+ const globalsSize = globals ? globals.length : 0;
+ if (globalsSize > 0) {
+ globalsPtr = module._malloc(globalsSize);
+ module.writeArrayToMemory(globals, globalsPtr);
+ }
+ module._jbig2_decode(ptr, size, width, height, globalsPtr, globalsSize);
+ }
+ if (!module.imageData) {
+ throw new Jbig2Error("Unknown error");
+ }
+ const {
+ imageData
+ } = module;
+ module.imageData = null;
+ return imageData;
+ } finally {
+ if (ptr) {
+ module._free(ptr);
+ }
+ if (globalsPtr) {
+ module._free(globalsPtr);
+ }
+ }
+ }
+}
+
+;// ./src/core/ccitt_stream.js
+
+
+
+
+class CCITTFaxStream extends DecodeStream {
+ constructor(str, maybeLength, params) {
+ super(maybeLength);
+ this.stream = str;
+ this.maybeLength = maybeLength;
+ this.dict = str.dict;
+ if (!(params instanceof Dict)) {
+ params = Dict.empty;
+ }
+ this.params = {
+ K: params.get("K") || 0,
+ EndOfLine: !!params.get("EndOfLine"),
+ EncodedByteAlign: !!params.get("EncodedByteAlign"),
+ Columns: params.get("Columns") || 1728,
+ Rows: params.get("Rows") || 0,
+ EndOfBlock: !!(params.get("EndOfBlock") ?? true),
+ BlackIs1: !!params.get("BlackIs1")
+ };
+ }
+ get bytes() {
+ return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
+ }
+ get isImageStream() {
+ return true;
+ }
+ get isAsyncDecoder() {
+ return true;
+ }
+ async decodeImage(bytes, length, _decoderOptions) {
+ if (this.eof) {
+ return this.buffer;
+ }
+ bytes ??= this.stream.isAsync ? (await this.stream.asyncGetBytes()) || this.bytes : this.bytes;
+ this.buffer = await JBig2CCITTFaxImage.instance.decode(bytes, this.dict.get("W", "Width"), this.dict.get("H", "Height"), null, this.params);
+ this.bufferLength = this.buffer.length;
+ this.eof = true;
+ return this.buffer;
+ }
+}
+
+;// ./src/core/flate_stream.js
+
+
+
+
+
+
+
+
+const codeLenCodeMap = new Int32Array([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
+const lengthDecode = new Int32Array([0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a, 0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f, 0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073, 0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102]);
+const distDecode = new Int32Array([0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d, 0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1, 0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01, 0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001]);
+const fixedLitCodeTab = [new Int32Array([0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0, 0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0, 0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0, 0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8, 0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8, 0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8, 0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4, 0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4, 0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4, 0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc, 0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec, 0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc, 0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2, 0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2, 0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2, 0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca, 0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea, 0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da, 0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6, 0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6, 0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6, 0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce, 0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee, 0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de, 0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe, 0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1, 0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1, 0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1, 0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1, 0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9, 0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9, 0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9, 0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9, 0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5, 0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5, 0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5, 0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5, 0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd, 0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed, 0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd, 0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd, 0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3, 0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3, 0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3, 0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3, 0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb, 0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb, 0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db, 0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb, 0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7, 0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7, 0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7, 0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7, 0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf, 0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef, 0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df, 0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff]), 9];
+const fixedDistCodeTab = [new Int32Array([0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c, 0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000, 0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d, 0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000]), 5];
+class FlateStream extends DecodeStream {
+ #isAsync = true;
+ constructor(str, maybeLength) {
+ super(maybeLength);
+ this.stream = str;
+ this.dict = str.dict;
+ const cmf = str.getByte();
+ const flg = str.getByte();
+ if (cmf === -1 || flg === -1) {
+ throw new FormatError(`Invalid header in flate stream: ${cmf}, ${flg}`);
+ }
+ if ((cmf & 0x0f) !== 0x08) {
+ throw new FormatError(`Unknown compression method in flate stream: ${cmf}, ${flg}`);
+ }
+ if (((cmf << 8) + flg) % 31 !== 0) {
+ throw new FormatError(`Bad FCHECK in flate stream: ${cmf}, ${flg}`);
+ }
+ if (flg & 0x20) {
+ throw new FormatError(`FDICT bit set in flate stream: ${cmf}, ${flg}`);
+ }
+ this.codeSize = 0;
+ this.codeBuf = 0;
+ }
+ async getImageData(length, _decoderOptions) {
+ const data = await this.asyncGetBytes();
+ if (!data) {
+ return this.getBytes(length);
+ }
+ if (data.length <= length) {
+ return data;
+ }
+ return data.subarray(0, length);
+ }
+ async asyncGetBytes() {
+ const {
+ decompressed,
+ compressed
+ } = await this.asyncGetBytesFromDecompressionStream("deflate");
+ if (decompressed) {
+ return decompressed;
+ }
+ this.#isAsync = false;
+ this.stream = new Stream(compressed, 2, compressed.length, this.stream.dict);
+ this.reset();
+ return null;
+ }
+ get isAsync() {
+ return this.#isAsync;
+ }
+ getBits(bits) {
+ const str = this.stream;
+ let codeSize = this.codeSize;
+ let codeBuf = this.codeBuf;
+ let b;
+ while (codeSize < bits) {
+ if ((b = str.getByte()) === -1) {
+ throw new FormatError("Bad encoding in flate stream");
+ }
+ codeBuf |= b << codeSize;
+ codeSize += 8;
+ }
+ b = codeBuf & (1 << bits) - 1;
+ this.codeBuf = codeBuf >> bits;
+ this.codeSize = codeSize -= bits;
+ return b;
+ }
+ getCode(table) {
+ const str = this.stream;
+ const codes = table[0];
+ const maxLen = table[1];
+ let codeSize = this.codeSize;
+ let codeBuf = this.codeBuf;
+ let b;
+ while (codeSize < maxLen) {
+ if ((b = str.getByte()) === -1) {
+ break;
+ }
+ codeBuf |= b << codeSize;
+ codeSize += 8;
+ }
+ const code = codes[codeBuf & (1 << maxLen) - 1];
+ const codeLen = code >> 16;
+ const codeVal = code & 0xffff;
+ if (codeLen < 1 || codeSize < codeLen) {
+ throw new FormatError("Bad encoding in flate stream");
+ }
+ this.codeBuf = codeBuf >> codeLen;
+ this.codeSize = codeSize - codeLen;
+ return codeVal;
+ }
+ generateHuffmanTable(lengths) {
+ const n = lengths.length;
+ let maxLen = 0;
+ let i;
+ for (i = 0; i < n; ++i) {
+ if (lengths[i] > maxLen) {
+ maxLen = lengths[i];
+ }
+ }
+ const size = 1 << maxLen;
+ const codes = new Int32Array(size);
+ for (let len = 1, code = 0, skip = 2; len <= maxLen; ++len, code <<= 1, skip <<= 1) {
+ for (let val = 0; val < n; ++val) {
+ if (lengths[val] === len) {
+ let code2 = 0;
+ let t = code;
+ for (i = 0; i < len; ++i) {
+ code2 = code2 << 1 | t & 1;
+ t >>= 1;
+ }
+ for (i = code2; i < size; i += skip) {
+ codes[i] = len << 16 | val;
+ }
+ ++code;
+ }
+ }
+ }
+ return [codes, maxLen];
+ }
+ #endsStreamOnError(err) {
+ info(err);
+ this.eof = true;
+ }
+ readBlock() {
+ let buffer, hdr, len;
+ const str = this.stream;
+ try {
+ hdr = this.getBits(3);
+ } catch (ex) {
+ this.#endsStreamOnError(ex.message);
+ return;
+ }
+ if (hdr & 1) {
+ this.eof = true;
+ }
+ hdr >>= 1;
+ if (hdr === 0) {
+ let b;
+ if ((b = str.getByte()) === -1) {
+ this.#endsStreamOnError("Bad block header in flate stream");
+ return;
+ }
+ let blockLen = b;
+ if ((b = str.getByte()) === -1) {
+ this.#endsStreamOnError("Bad block header in flate stream");
+ return;
+ }
+ blockLen |= b << 8;
+ if ((b = str.getByte()) === -1) {
+ this.#endsStreamOnError("Bad block header in flate stream");
+ return;
+ }
+ let check = b;
+ if ((b = str.getByte()) === -1) {
+ this.#endsStreamOnError("Bad block header in flate stream");
+ return;
+ }
+ check |= b << 8;
+ if (check !== (~blockLen & 0xffff) && (blockLen !== 0 || check !== 0)) {
+ throw new FormatError("Bad uncompressed block length in flate stream");
+ }
+ this.codeBuf = 0;
+ this.codeSize = 0;
+ const bufferLength = this.bufferLength,
+ end = bufferLength + blockLen;
+ buffer = this.ensureBuffer(end);
+ this.bufferLength = end;
+ if (blockLen === 0) {
+ if (str.peekByte() === -1) {
+ this.eof = true;
+ }
+ } else {
+ const block = str.getBytes(blockLen);
+ buffer.set(block, bufferLength);
+ if (block.length < blockLen) {
+ this.eof = true;
+ }
+ }
+ return;
+ }
+ let litCodeTable;
+ let distCodeTable;
+ if (hdr === 1) {
+ litCodeTable = fixedLitCodeTab;
+ distCodeTable = fixedDistCodeTab;
+ } else if (hdr === 2) {
+ const numLitCodes = this.getBits(5) + 257;
+ const numDistCodes = this.getBits(5) + 1;
+ const numCodeLenCodes = this.getBits(4) + 4;
+ const codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
+ let i;
+ for (i = 0; i < numCodeLenCodes; ++i) {
+ codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3);
+ }
+ const codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
+ len = 0;
+ i = 0;
+ const codes = numLitCodes + numDistCodes;
+ const codeLengths = new Uint8Array(codes);
+ let bitsLength, bitsOffset, what;
+ while (i < codes) {
+ const code = this.getCode(codeLenCodeTab);
+ if (code === 16) {
+ bitsLength = 2;
+ bitsOffset = 3;
+ what = len;
+ } else if (code === 17) {
+ bitsLength = 3;
+ bitsOffset = 3;
+ what = len = 0;
+ } else if (code === 18) {
+ bitsLength = 7;
+ bitsOffset = 11;
+ what = len = 0;
+ } else {
+ codeLengths[i++] = len = code;
+ continue;
+ }
+ let repeatLength = this.getBits(bitsLength) + bitsOffset;
+ while (repeatLength-- > 0) {
+ codeLengths[i++] = what;
+ }
+ }
+ litCodeTable = this.generateHuffmanTable(codeLengths.subarray(0, numLitCodes));
+ distCodeTable = this.generateHuffmanTable(codeLengths.subarray(numLitCodes, codes));
+ } else {
+ throw new FormatError("Unknown block type in flate stream");
+ }
+ buffer = this.buffer;
+ let limit = buffer ? buffer.length : 0;
+ let pos = this.bufferLength;
+ while (true) {
+ let code1 = this.getCode(litCodeTable);
+ if (code1 < 256) {
+ if (pos + 1 >= limit) {
+ buffer = this.ensureBuffer(pos + 1);
+ limit = buffer.length;
+ }
+ buffer[pos++] = code1;
+ continue;
+ }
+ if (code1 === 256) {
+ this.bufferLength = pos;
+ return;
+ }
+ code1 -= 257;
+ code1 = lengthDecode[code1];
+ let code2 = code1 >> 16;
+ if (code2 > 0) {
+ code2 = this.getBits(code2);
+ }
+ len = (code1 & 0xffff) + code2;
+ code1 = this.getCode(distCodeTable);
+ code1 = distDecode[code1];
+ code2 = code1 >> 16;
+ if (code2 > 0) {
+ code2 = this.getBits(code2);
+ }
+ const dist = (code1 & 0xffff) + code2;
+ if (pos + len >= limit) {
+ buffer = this.ensureBuffer(pos + len);
+ limit = buffer.length;
+ }
+ for (let k = 0; k < len; ++k, ++pos) {
+ buffer[pos] = buffer[pos - dist];
+ }
+ }
+ }
+}
+
+;// ./src/core/jbig2_stream.js
+
+
+
+
+
+class Jbig2Stream extends DecodeStream {
+ constructor(stream, maybeLength, params) {
+ super(maybeLength);
+ this.stream = stream;
+ this.dict = stream.dict;
+ this.maybeLength = maybeLength;
+ this.params = params;
+ }
+ get bytes() {
+ return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
+ }
+ ensureBuffer(requested) {}
+ get isAsyncDecoder() {
+ return true;
+ }
+ get isImageStream() {
+ return true;
+ }
+ static stripFileHeader(bytes) {
+ if (bytes.length >= 9 && bytes[0] === 0x97 && bytes[1] === 0x4a && bytes[2] === 0x42 && bytes[3] === 0x32 && bytes[4] === 0x0d && bytes[5] === 0x0a && bytes[6] === 0x1a && bytes[7] === 0x0a) {
+ const headerLength = (bytes[8] & 2) === 0 ? 13 : 9;
+ return bytes.subarray(headerLength);
+ }
+ return bytes;
+ }
+ async decodeImage(bytes, length, _decoderOptions) {
+ if (this.eof) {
+ return this.buffer;
+ }
+ bytes = Jbig2Stream.stripFileHeader(bytes || this.bytes);
+ let globals = null;
+ if (this.params instanceof Dict) {
+ const globalsStream = this.params.get("JBIG2Globals");
+ if (globalsStream instanceof BaseStream) {
+ globals = Jbig2Stream.stripFileHeader(globalsStream.getBytes());
+ }
+ }
+ this.buffer = await JBig2CCITTFaxImage.instance.decode(bytes, this.dict.get("Width"), this.dict.get("Height"), globals);
+ this.bufferLength = this.buffer.length;
+ this.eof = true;
+ return this.buffer;
+ }
+ get canAsyncDecodeImageFromBuffer() {
+ return this.stream.isAsync;
+ }
+}
+
+;// ./external/openjpeg/openjpeg.js
+
+
+
+
+
+
+async function OpenJPEG(moduleArg = {}) {
+ var moduleRtn;
+ var Module = moduleArg;
+ var ENVIRONMENT_IS_WEB = true;
+ var ENVIRONMENT_IS_WORKER = false;
+ var arguments_ = [];
+ var thisProgram = "./this.program";
+ var quit_ = (status, toThrow) => {
+ throw toThrow;
+ };
+ var _scriptName = import.meta.url;
+ var scriptDirectory = "";
+ var readAsync, readBinary;
+ if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
+ try {
+ scriptDirectory = new URL(".", _scriptName).href;
+ } catch {}
+ readAsync = async url => {
+ var response = await fetch(url, {
+ credentials: "same-origin"
+ });
+ if (response.ok) {
+ return response.arrayBuffer();
+ }
+ throw new Error(response.status + " : " + response.url);
+ };
+ } else {}
+ var out = console.log.bind(console);
+ var err = console.error.bind(console);
+ var wasmBinary;
+ var ABORT = false;
+ var EXITSTATUS;
+ class EmscriptenEH {}
+ class EmscriptenSjLj extends EmscriptenEH {}
+ var readyPromiseResolve, readyPromiseReject;
+ var runtimeInitialized = false;
+ function updateMemoryViews() {
+ var b = wasmMemory.buffer;
+ HEAP8 = new Int8Array(b);
+ HEAP16 = new Int16Array(b);
+ HEAPU8 = new Uint8Array(b);
+ HEAPU16 = new Uint16Array(b);
+ HEAP32 = new Int32Array(b);
+ HEAPU32 = new Uint32Array(b);
+ HEAPF32 = new Float32Array(b);
+ HEAPF64 = new Float64Array(b);
+ HEAP64 = new BigInt64Array(b);
+ HEAPU64 = new BigUint64Array(b);
+ }
+ function preRun() {
+ if (Module["preRun"]) {
+ if (typeof Module["preRun"] == "function") Module["preRun"] = [Module["preRun"]];
+ while (Module["preRun"].length) {
+ addOnPreRun(Module["preRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(onPreRuns);
+ }
+ function initRuntime() {
+ runtimeInitialized = true;
+ wasmExports["s"]();
+ }
+ function postRun() {
+ if (Module["postRun"]) {
+ if (typeof Module["postRun"] == "function") Module["postRun"] = [Module["postRun"]];
+ while (Module["postRun"].length) {
+ addOnPostRun(Module["postRun"].shift());
+ }
+ }
+ callRuntimeCallbacks(onPostRuns);
+ }
+ function abort(what) {
+ Module["onAbort"]?.(what);
+ what = `Aborted(${what})`;
+ err(what);
+ ABORT = true;
+ what += ". Build with -sASSERTIONS for more info.";
+ var e = new WebAssembly.RuntimeError(what);
+ readyPromiseReject?.(e);
+ throw e;
+ }
+ var wasmBinaryFile;
+ function getWasmImports() {
+ var imports = {
+ a: wasmImports
+ };
+ return imports;
+ }
+ async function createWasm() {
+ function receiveInstance(instance, module) {
+ wasmExports = instance.exports;
+ assignWasmExports(wasmExports);
+ updateMemoryViews();
+ return wasmExports;
+ }
+ var info = getWasmImports();
+ return new Promise((resolve, reject) => {
+ Module["instantiateWasm"](info, (inst, mod) => {
+ resolve(receiveInstance(inst, mod));
+ });
+ });
+ }
+ class ExitStatus {
+ name = "ExitStatus";
+ constructor(status) {
+ this.message = `Program terminated with exit(${status})`;
+ this.status = status;
+ }
+ }
+ var HEAP16;
+ var HEAP32;
+ var HEAP64;
+ var HEAP8;
+ var HEAPF32;
+ var HEAPF64;
+ var HEAPU16;
+ var HEAPU32;
+ var HEAPU64;
+ var HEAPU8;
+ var callRuntimeCallbacks = callbacks => {
+ while (callbacks.length > 0) {
+ callbacks.shift()(Module);
+ }
+ };
+ var onPostRuns = [];
+ var addOnPostRun = cb => onPostRuns.push(cb);
+ var onPreRuns = [];
+ var addOnPreRun = cb => onPreRuns.push(cb);
+ var noExitRuntime = true;
+ var __abort_js = () => abort("");
+ var runtimeKeepaliveCounter = 0;
+ var __emscripten_runtime_keepalive_clear = () => {
+ noExitRuntime = false;
+ runtimeKeepaliveCounter = 0;
+ };
+ var timers = {};
+ var handleException = e => {
+ if (e instanceof ExitStatus || e == "unwind") {
+ return EXITSTATUS;
+ }
+ quit_(1, e);
+ };
+ var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
+ var _proc_exit = code => {
+ EXITSTATUS = code;
+ if (!keepRuntimeAlive()) {
+ Module["onExit"]?.(code);
+ ABORT = true;
+ }
+ quit_(code, new ExitStatus(code));
+ };
+ var exitJS = (status, implicit) => {
+ EXITSTATUS = status;
+ _proc_exit(status);
+ };
+ var _exit = exitJS;
+ var maybeExit = () => {
+ if (!keepRuntimeAlive()) {
+ try {
+ _exit(EXITSTATUS);
+ } catch (e) {
+ handleException(e);
+ }
+ }
+ };
+ var callUserCallback = func => {
+ if (ABORT) {
+ return;
+ }
+ try {
+ return func();
+ } catch (e) {
+ handleException(e);
+ } finally {
+ maybeExit();
+ }
+ };
+ var _emscripten_get_now = () => performance.now();
+ var __setitimer_js = (which, timeout_ms) => {
+ if (timers[which]) {
+ clearTimeout(timers[which].id);
+ delete timers[which];
+ }
+ if (!timeout_ms) return 0;
+ var id = setTimeout(() => {
+ delete timers[which];
+ callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now()));
+ }, timeout_ms);
+ timers[which] = {
+ id,
+ timeout_ms
+ };
+ return 0;
+ };
+ function _copy_pixels_1(compG_ptr, nb_pixels) {
+ compG_ptr >>= 2;
+ const imageData = Module.imageData = new Uint8ClampedArray(nb_pixels);
+ const compG = HEAP32.subarray(compG_ptr, compG_ptr + nb_pixels);
+ imageData.set(compG);
+ }
+ function _copy_pixels_3(compR_ptr, compG_ptr, compB_ptr, nb_pixels) {
+ compR_ptr >>= 2;
+ compG_ptr >>= 2;
+ compB_ptr >>= 2;
+ const imageData = Module.imageData = new Uint8ClampedArray(nb_pixels * 3);
+ const compR = HEAP32.subarray(compR_ptr, compR_ptr + nb_pixels);
+ const compG = HEAP32.subarray(compG_ptr, compG_ptr + nb_pixels);
+ const compB = HEAP32.subarray(compB_ptr, compB_ptr + nb_pixels);
+ for (let i = 0; i < nb_pixels; i++) {
+ imageData[3 * i] = compR[i];
+ imageData[3 * i + 1] = compG[i];
+ imageData[3 * i + 2] = compB[i];
+ }
+ }
+ function _copy_pixels_4(compR_ptr, compG_ptr, compB_ptr, compA_ptr, nb_pixels) {
+ compR_ptr >>= 2;
+ compG_ptr >>= 2;
+ compB_ptr >>= 2;
+ compA_ptr >>= 2;
+ const imageData = Module.imageData = new Uint8ClampedArray(nb_pixels * 4);
+ const compR = HEAP32.subarray(compR_ptr, compR_ptr + nb_pixels);
+ const compG = HEAP32.subarray(compG_ptr, compG_ptr + nb_pixels);
+ const compB = HEAP32.subarray(compB_ptr, compB_ptr + nb_pixels);
+ const compA = HEAP32.subarray(compA_ptr, compA_ptr + nb_pixels);
+ for (let i = 0; i < nb_pixels; i++) {
+ imageData[4 * i] = compR[i];
+ imageData[4 * i + 1] = compG[i];
+ imageData[4 * i + 2] = compB[i];
+ imageData[4 * i + 3] = compA[i];
+ }
+ }
+ var getHeapMax = () => 2147483648;
+ var alignMemory = (size, alignment) => Math.ceil(size / alignment) * alignment;
+ var growMemory = size => {
+ var oldHeapSize = wasmMemory.buffer.byteLength;
+ var pages = (size - oldHeapSize + 65535) / 65536 | 0;
+ try {
+ wasmMemory.grow(pages);
+ updateMemoryViews();
+ return 1;
+ } catch (e) {}
+ };
+ var _emscripten_resize_heap = requestedSize => {
+ var oldSize = HEAPU8.length;
+ requestedSize >>>= 0;
+ var maxHeapSize = getHeapMax();
+ if (requestedSize > maxHeapSize) {
+ return false;
+ }
+ for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
+ var overGrownHeapSize = oldSize * (1 + .2 / cutDown);
+ overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296);
+ var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536));
+ var replacement = growMemory(newSize);
+ if (replacement) {
+ return true;
+ }
+ }
+ return false;
+ };
+ var ENV = {};
+ var getExecutableName = () => thisProgram || "./this.program";
+ var getEnvStrings = () => {
+ if (!getEnvStrings.strings) {
+ var lang = (globalThis.navigator?.language ?? "C").replace("-", "_") + ".UTF-8";
+ var env = {
+ USER: "web_user",
+ LOGNAME: "web_user",
+ PATH: "/",
+ PWD: "/",
+ HOME: "/home/web_user",
+ LANG: lang,
+ _: getExecutableName()
+ };
+ for (var x in ENV) {
+ if (ENV[x] === undefined) delete env[x];else env[x] = ENV[x];
+ }
+ var strings = [];
+ for (var x in env) {
+ strings.push(`${x}=${env[x]}`);
+ }
+ getEnvStrings.strings = strings;
+ }
+ return getEnvStrings.strings;
+ };
+ var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
+ if (!(maxBytesToWrite > 0)) return 0;
+ var startIdx = outIdx;
+ var endIdx = outIdx + maxBytesToWrite - 1;
+ for (var i = 0; i < str.length; ++i) {
+ var u = str.codePointAt(i);
+ if (u <= 127) {
+ if (outIdx >= endIdx) break;
+ heap[outIdx++] = u;
+ } else if (u <= 2047) {
+ if (outIdx + 1 >= endIdx) break;
+ heap[outIdx++] = 192 | u >> 6;
+ heap[outIdx++] = 128 | u & 63;
+ } else if (u <= 65535) {
+ if (outIdx + 2 >= endIdx) break;
+ heap[outIdx++] = 224 | u >> 12;
+ heap[outIdx++] = 128 | u >> 6 & 63;
+ heap[outIdx++] = 128 | u & 63;
+ } else {
+ if (outIdx + 3 >= endIdx) break;
+ heap[outIdx++] = 240 | u >> 18;
+ heap[outIdx++] = 128 | u >> 12 & 63;
+ heap[outIdx++] = 128 | u >> 6 & 63;
+ heap[outIdx++] = 128 | u & 63;
+ i++;
+ }
+ }
+ heap[outIdx] = 0;
+ return outIdx - startIdx;
+ };
+ var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
+ var _environ_get = (__environ, environ_buf) => {
+ var bufSize = 0;
+ var envp = 0;
+ for (var string of getEnvStrings()) {
+ var ptr = environ_buf + bufSize;
+ HEAPU32[__environ + envp >> 2] = ptr;
+ bufSize += stringToUTF8(string, ptr, Infinity) + 1;
+ envp += 4;
+ }
+ return 0;
+ };
+ var lengthBytesUTF8 = str => {
+ var len = 0;
+ for (var i = 0; i < str.length; ++i) {
+ var c = str.charCodeAt(i);
+ if (c <= 127) {
+ len++;
+ } else if (c <= 2047) {
+ len += 2;
+ } else if (c >= 55296 && c <= 57343) {
+ len += 4;
+ ++i;
+ } else {
+ len += 3;
+ }
+ }
+ return len;
+ };
+ var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
+ var strings = getEnvStrings();
+ HEAPU32[penviron_count >> 2] = strings.length;
+ var bufSize = 0;
+ for (var string of strings) {
+ bufSize += lengthBytesUTF8(string) + 1;
+ }
+ HEAPU32[penviron_buf_size >> 2] = bufSize;
+ return 0;
+ };
+ var INT53_MAX = 9007199254740992;
+ var INT53_MIN = -9007199254740992;
+ var bigintToI53Checked = num => num < INT53_MIN || num > INT53_MAX ? NaN : Number(num);
+ function _fd_seek(fd, offset, whence, newOffset) {
+ offset = bigintToI53Checked(offset);
+ return 70;
+ }
+ var printCharBuffers = [null, [], []];
+ var UTF8Decoder = globalThis.TextDecoder && new TextDecoder();
+ var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => {
+ var maxIdx = idx + maxBytesToRead;
+ if (ignoreNul) return maxIdx;
+ while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx;
+ return idx;
+ };
+ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead, ignoreNul) => {
+ var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead, ignoreNul);
+ if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
+ return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
+ }
+ var str = "";
+ while (idx < endPtr) {
+ var u0 = heapOrArray[idx++];
+ if (!(u0 & 128)) {
+ str += String.fromCharCode(u0);
+ continue;
+ }
+ var u1 = heapOrArray[idx++] & 63;
+ if ((u0 & 224) == 192) {
+ str += String.fromCharCode((u0 & 31) << 6 | u1);
+ continue;
+ }
+ var u2 = heapOrArray[idx++] & 63;
+ if ((u0 & 240) == 224) {
+ u0 = (u0 & 15) << 12 | u1 << 6 | u2;
+ } else {
+ u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heapOrArray[idx++] & 63;
+ }
+ if (u0 < 65536) {
+ str += String.fromCharCode(u0);
+ } else {
+ var ch = u0 - 65536;
+ str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023);
+ }
+ }
+ return str;
+ };
+ var printChar = (stream, curr) => {
+ var buffer = printCharBuffers[stream];
+ if (curr === 0 || curr === 10) {
+ (stream === 1 ? out : err)(UTF8ArrayToString(buffer));
+ buffer.length = 0;
+ } else {
+ buffer.push(curr);
+ }
+ };
+ var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead, ignoreNul) : "";
+ var _fd_write = (fd, iov, iovcnt, pnum) => {
+ var num = 0;
+ for (var i = 0; i < iovcnt; i++) {
+ var ptr = HEAPU32[iov >> 2];
+ var len = HEAPU32[iov + 4 >> 2];
+ iov += 8;
+ for (var j = 0; j < len; j++) {
+ printChar(fd, HEAPU8[ptr + j]);
+ }
+ num += len;
+ }
+ HEAPU32[pnum >> 2] = num;
+ return 0;
+ };
+ function _gray_to_rgba(compG_ptr, nb_pixels) {
+ compG_ptr >>= 2;
+ const imageData = Module.imageData = new Uint8ClampedArray(nb_pixels * 4);
+ const compG = HEAP32.subarray(compG_ptr, compG_ptr + nb_pixels);
+ for (let i = 0; i < nb_pixels; i++) {
+ imageData[4 * i] = imageData[4 * i + 1] = imageData[4 * i + 2] = compG[i];
+ imageData[4 * i + 3] = 255;
+ }
+ }
+ function _graya_to_rgba(compG_ptr, compA_ptr, nb_pixels) {
+ compG_ptr >>= 2;
+ compA_ptr >>= 2;
+ const imageData = Module.imageData = new Uint8ClampedArray(nb_pixels * 4);
+ const compG = HEAP32.subarray(compG_ptr, compG_ptr + nb_pixels);
+ const compA = HEAP32.subarray(compA_ptr, compA_ptr + nb_pixels);
+ for (let i = 0; i < nb_pixels; i++) {
+ imageData[4 * i] = imageData[4 * i + 1] = imageData[4 * i + 2] = compG[i];
+ imageData[4 * i + 3] = compA[i];
+ }
+ }
+ function _jsPrintWarning(message_ptr) {
+ const message = UTF8ToString(message_ptr);
+ (Module.warn || console.warn)(`OpenJPEG: ${message}`);
+ }
+ function _rgb_to_rgba(compR_ptr, compG_ptr, compB_ptr, nb_pixels) {
+ compR_ptr >>= 2;
+ compG_ptr >>= 2;
+ compB_ptr >>= 2;
+ const imageData = Module.imageData = new Uint8ClampedArray(nb_pixels * 4);
+ const compR = HEAP32.subarray(compR_ptr, compR_ptr + nb_pixels);
+ const compG = HEAP32.subarray(compG_ptr, compG_ptr + nb_pixels);
+ const compB = HEAP32.subarray(compB_ptr, compB_ptr + nb_pixels);
+ for (let i = 0; i < nb_pixels; i++) {
+ imageData[4 * i] = compR[i];
+ imageData[4 * i + 1] = compG[i];
+ imageData[4 * i + 2] = compB[i];
+ imageData[4 * i + 3] = 255;
+ }
+ }
+ function _storeErrorMessage(message_ptr) {
+ const message = UTF8ToString(message_ptr);
+ if (!Module.errorMessages) {
+ Module.errorMessages = message;
+ } else {
+ Module.errorMessages += "\n" + message;
+ }
+ }
+ var writeArrayToMemory = (array, buffer) => {
+ HEAP8.set(array, buffer);
+ };
+ if (Module["noExitRuntime"]) noExitRuntime = Module["noExitRuntime"];
+ if (Module["print"]) out = Module["print"];
+ if (Module["printErr"]) err = Module["printErr"];
+ if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"];
+ if (Module["arguments"]) arguments_ = Module["arguments"];
+ if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
+ if (Module["preInit"]) {
+ if (typeof Module["preInit"] == "function") Module["preInit"] = [Module["preInit"]];
+ while (Module["preInit"].length > 0) {
+ Module["preInit"].shift()();
+ }
+ }
+ Module["writeArrayToMemory"] = writeArrayToMemory;
+ var _malloc, _free, _jp2_decode, __emscripten_timeout, memory, __indirect_function_table, wasmMemory;
+ function assignWasmExports(wasmExports) {
+ _malloc = Module["_malloc"] = wasmExports["t"];
+ _free = Module["_free"] = wasmExports["u"];
+ _jp2_decode = Module["_jp2_decode"] = wasmExports["v"];
+ __emscripten_timeout = wasmExports["w"];
+ memory = wasmMemory = wasmExports["r"];
+ __indirect_function_table = wasmExports["__indirect_function_table"];
+ }
+ var wasmImports = {
+ m: __abort_js,
+ l: __emscripten_runtime_keepalive_clear,
+ i: __setitimer_js,
+ f: _copy_pixels_1,
+ e: _copy_pixels_3,
+ d: _copy_pixels_4,
+ j: _emscripten_resize_heap,
+ o: _environ_get,
+ p: _environ_sizes_get,
+ n: _fd_seek,
+ b: _fd_write,
+ q: _gray_to_rgba,
+ h: _graya_to_rgba,
+ c: _jsPrintWarning,
+ k: _proc_exit,
+ g: _rgb_to_rgba,
+ a: _storeErrorMessage
+ };
+ function run() {
+ preRun();
+ function doRun() {
+ Module["calledRun"] = true;
+ if (ABORT) return;
+ initRuntime();
+ readyPromiseResolve?.(Module);
+ Module["onRuntimeInitialized"]?.();
+ postRun();
+ }
+ if (Module["setStatus"]) {
+ Module["setStatus"]("Running...");
+ setTimeout(() => {
+ setTimeout(() => Module["setStatus"](""), 1);
+ doRun();
+ }, 1);
+ } else {
+ doRun();
+ }
+ }
+ var wasmExports;
+ wasmExports = await createWasm();
+ run();
+ if (runtimeInitialized) {
+ moduleRtn = Module;
+ } else {
+ moduleRtn = new Promise((resolve, reject) => {
+ readyPromiseResolve = resolve;
+ readyPromiseReject = reject;
+ });
+ }
+ return moduleRtn;
+}
+/* harmony default export */ const openjpeg = (OpenJPEG);
+;// ./src/core/jpx.js
+
+
+
+
+class JpxError extends BaseException {
+ constructor(msg) {
+ super(msg, "JpxError");
+ }
+}
+class JpxImage extends WasmImage {
+ _filename = "openjpeg.wasm";
+ _noWasmFilename = "openjpeg_nowasm_fallback.js";
+ static get instance() {
+ return shadow(this, "instance", new JpxImage(true));
+ }
+ async decode(bytes, {
+ numComponents = 4,
+ isIndexedColormap = false,
+ smaskInData = false,
+ reducePower = 0
+ } = {}) {
+ const module = await this._getModule(openjpeg);
+ if (!module) {
+ throw new JpxError("OpenJPEG failed to initialize");
+ }
+ let ptr;
+ try {
+ const size = bytes.length;
+ ptr = module._malloc(size);
+ module.writeArrayToMemory(bytes, ptr);
+ const ret = module._jp2_decode(ptr, size, numComponents > 0 ? numComponents : 0, !!isIndexedColormap, !!smaskInData, reducePower);
+ if (ret) {
+ const {
+ errorMessages
+ } = module;
+ if (errorMessages) {
+ delete module.errorMessages;
+ throw new JpxError(errorMessages);
+ }
+ throw new JpxError("Unknown error");
+ }
+ const {
+ imageData
+ } = module;
+ module.imageData = null;
+ return imageData;
+ } finally {
+ if (ptr) {
+ module._free(ptr);
+ }
+ }
+ }
+ static parseImageProperties(stream) {
+ let newByte = stream.getByte();
+ while (newByte >= 0) {
+ const oldByte = newByte;
+ newByte = stream.getByte();
+ const code = oldByte << 8 | newByte;
+ if (code === 0xff51) {
+ stream.skip(4);
+ const Xsiz = stream.getInt32() >>> 0;
+ const Ysiz = stream.getInt32() >>> 0;
+ const XOsiz = stream.getInt32() >>> 0;
+ const YOsiz = stream.getInt32() >>> 0;
+ stream.skip(16);
+ const Csiz = stream.getUint16();
+ return {
+ width: Xsiz - XOsiz,
+ height: Ysiz - YOsiz,
+ bitsPerComponent: 8,
+ componentsCount: Csiz
+ };
+ }
+ }
+ throw new JpxError("No size marker found in JPX stream");
+ }
+}
+
+;// ./src/core/jpx_stream.js
+
+
+
+class JpxStream extends DecodeStream {
+ constructor(stream, maybeLength) {
+ super(maybeLength);
+ this.stream = stream;
+ this.dict = stream.dict;
+ this.maybeLength = maybeLength;
+ }
+ get bytes() {
+ return shadow(this, "bytes", this.stream.getBytes(this.maybeLength));
+ }
+ ensureBuffer(requested) {}
+ get isAsyncDecoder() {
+ return true;
+ }
+ async decodeImage(bytes, _length, decoderOptions) {
+ if (this.eof) {
+ return this.buffer;
+ }
+ bytes ||= this.bytes;
+ this.buffer = await JpxImage.instance.decode(bytes, decoderOptions);
+ this.bufferLength = this.buffer.length;
+ this.eof = true;
+ return this.buffer;
+ }
+ get canAsyncDecodeImageFromBuffer() {
+ return this.stream.isAsync;
+ }
+ get isImageStream() {
+ return true;
+ }
+}
+
+;// ./src/core/lzw_stream.js
+
+
+
+
+
+
+class LZWStream extends DecodeStream {
+ constructor(str, maybeLength, earlyChange) {
+ super(maybeLength);
+ this.stream = str;
+ this.dict = str.dict;
+ this.cachedData = 0;
+ this.bitsCached = 0;
+ const maxLzwDictionarySize = 4096;
+ const lzwState = {
+ earlyChange,
+ codeLength: 9,
+ nextCode: 258,
+ dictionaryValues: new Uint8Array(maxLzwDictionarySize),
+ dictionaryLengths: new Uint16Array(maxLzwDictionarySize),
+ dictionaryPrevCodes: new Uint16Array(maxLzwDictionarySize),
+ currentSequence: new Uint8Array(maxLzwDictionarySize),
+ currentSequenceLength: 0
+ };
+ for (let i = 0; i < 256; ++i) {
+ lzwState.dictionaryValues[i] = i;
+ lzwState.dictionaryLengths[i] = 1;
+ }
+ this.lzwState = lzwState;
+ }
+ readBits(n) {
+ let bitsCached = this.bitsCached;
+ let cachedData = this.cachedData;
+ while (bitsCached < n) {
+ const c = this.stream.getByte();
+ if (c === -1) {
+ this.eof = true;
+ return null;
+ }
+ cachedData = cachedData << 8 | c;
+ bitsCached += 8;
+ }
+ this.bitsCached = bitsCached -= n;
+ this.cachedData = cachedData;
+ return cachedData >>> bitsCached & (1 << n) - 1;
+ }
+ readBlock() {
+ const blockSize = 512,
+ decodedSizeDelta = blockSize;
+ let estimatedDecodedSize = blockSize * 2;
+ let i, j, q;
+ const {
+ lzwState
+ } = this;
+ const earlyChange = lzwState.earlyChange;
+ let nextCode = lzwState.nextCode;
+ const dictionaryValues = lzwState.dictionaryValues;
+ const dictionaryLengths = lzwState.dictionaryLengths;
+ const dictionaryPrevCodes = lzwState.dictionaryPrevCodes;
+ let codeLength = lzwState.codeLength;
+ let prevCode = lzwState.prevCode;
+ const currentSequence = lzwState.currentSequence;
+ let currentSequenceLength = lzwState.currentSequenceLength;
+ let decodedLength = 0;
+ let currentBufferLength = this.bufferLength;
+ let buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
+ for (i = 0; i < blockSize; i++) {
+ const code = this.readBits(codeLength);
+ const hasPrev = currentSequenceLength > 0;
+ if (code < 256) {
+ currentSequence[0] = code;
+ currentSequenceLength = 1;
+ } else if (code >= 258) {
+ if (code < nextCode) {
+ currentSequenceLength = dictionaryLengths[code];
+ for (j = currentSequenceLength - 1, q = code; j >= 0; j--) {
+ currentSequence[j] = dictionaryValues[q];
+ q = dictionaryPrevCodes[q];
+ }
+ } else {
+ currentSequence[currentSequenceLength++] = currentSequence[0];
+ }
+ } else if (code === 256) {
+ codeLength = 9;
+ nextCode = 258;
+ currentSequenceLength = 0;
+ continue;
+ } else {
+ this.eof = true;
+ delete this.lzwState;
+ break;
+ }
+ if (hasPrev) {
+ dictionaryPrevCodes[nextCode] = prevCode;
+ dictionaryLengths[nextCode] = dictionaryLengths[prevCode] + 1;
+ dictionaryValues[nextCode] = currentSequence[0];
+ nextCode++;
+ codeLength = nextCode + earlyChange & nextCode + earlyChange - 1 ? codeLength : Math.min(Math.log(nextCode + earlyChange) / 0.6931471805599453 + 1, 12) | 0;
+ }
+ prevCode = code;
+ decodedLength += currentSequenceLength;
+ if (estimatedDecodedSize < decodedLength) {
+ do {
+ estimatedDecodedSize += decodedSizeDelta;
+ } while (estimatedDecodedSize < decodedLength);
+ buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
+ }
+ for (j = 0; j < currentSequenceLength; j++) {
+ buffer[currentBufferLength++] = currentSequence[j];
+ }
+ }
+ lzwState.nextCode = nextCode;
+ lzwState.codeLength = codeLength;
+ lzwState.prevCode = prevCode;
+ lzwState.currentSequenceLength = currentSequenceLength;
+ this.bufferLength = currentBufferLength;
+ }
+}
+
+;// ./src/core/predictor_stream.js
+
+
+
+
+
+
+
+
+class PredictorStream extends DecodeStream {
+ constructor(str, maybeLength, params) {
+ super(maybeLength);
+ if (!(params instanceof Dict)) {
+ return str;
+ }
+ const predictor = this.predictor = params.get("Predictor") || 1;
+ if (predictor <= 1) {
+ return str;
+ }
+ if (predictor !== 2 && (predictor < 10 || predictor > 15)) {
+ throw new FormatError(`Unsupported predictor: ${predictor}`);
+ }
+ this.readBlock = predictor === 2 ? this.readBlockTiff : this.readBlockPng;
+ this.stream = str;
+ this.dict = str.dict;
+ const colors = this.colors = params.get("Colors") || 1;
+ const bits = this.bits = params.get("BPC", "BitsPerComponent") || 8;
+ const columns = this.columns = params.get("Columns") || 1;
+ this.pixBytes = colors * bits + 7 >> 3;
+ this.rowBytes = columns * colors * bits + 7 >> 3;
+ return this;
+ }
+ readBlockTiff() {
+ const rowBytes = this.rowBytes;
+ const bufferLength = this.bufferLength;
+ const buffer = this.ensureBuffer(bufferLength + rowBytes);
+ const bits = this.bits;
+ const colors = this.colors;
+ const rawBytes = this.stream.getBytes(rowBytes);
+ this.eof = !rawBytes.length;
+ if (this.eof) {
+ return;
+ }
+ let inbuf = 0,
+ outbuf = 0;
+ let inbits = 0,
+ outbits = 0;
+ let pos = bufferLength;
+ let i;
+ if (bits === 1 && colors === 1) {
+ for (i = 0; i < rowBytes; ++i) {
+ let c = rawBytes[i] ^ inbuf;
+ c ^= c >> 1;
+ c ^= c >> 2;
+ c ^= c >> 4;
+ inbuf = (c & 1) << 7;
+ buffer[pos++] = c;
+ }
+ } else if (bits === 8) {
+ for (i = 0; i < colors; ++i) {
+ buffer[pos++] = rawBytes[i];
+ }
+ for (; i < rowBytes; ++i) {
+ buffer[pos] = buffer[pos - colors] + rawBytes[i];
+ pos++;
+ }
+ } else if (bits === 16) {
+ const bytesPerPixel = colors * 2;
+ for (i = 0; i < bytesPerPixel; ++i) {
+ buffer[pos++] = rawBytes[i];
+ }
+ for (; i < rowBytes; i += 2) {
+ const sum = ((rawBytes[i] & 0xff) << 8) + (rawBytes[i + 1] & 0xff) + ((buffer[pos - bytesPerPixel] & 0xff) << 8) + (buffer[pos - bytesPerPixel + 1] & 0xff);
+ buffer[pos++] = sum >> 8 & 0xff;
+ buffer[pos++] = sum & 0xff;
+ }
+ } else {
+ const compArray = new Uint8Array(colors + 1);
+ const bitMask = (1 << bits) - 1;
+ let j = 0,
+ k = bufferLength;
+ const columns = this.columns;
+ for (i = 0; i < columns; ++i) {
+ for (let kk = 0; kk < colors; ++kk) {
+ if (inbits < bits) {
+ inbuf = inbuf << 8 | rawBytes[j++] & 0xff;
+ inbits += 8;
+ }
+ compArray[kk] = compArray[kk] + (inbuf >> inbits - bits) & bitMask;
+ inbits -= bits;
+ outbuf = outbuf << bits | compArray[kk];
+ outbits += bits;
+ if (outbits >= 8) {
+ buffer[k++] = outbuf >> outbits - 8 & 0xff;
+ outbits -= 8;
+ }
+ }
+ }
+ if (outbits > 0) {
+ buffer[k++] = (outbuf << 8 - outbits) + (inbuf & (1 << 8 - outbits) - 1);
+ }
+ }
+ this.bufferLength += rowBytes;
+ }
+ readBlockPng() {
+ const rowBytes = this.rowBytes;
+ const pixBytes = this.pixBytes;
+ const predictor = this.stream.getByte();
+ const rawBytes = this.stream.getBytes(rowBytes);
+ this.eof = !rawBytes.length;
+ if (this.eof) {
+ return;
+ }
+ const bufferLength = this.bufferLength;
+ const buffer = this.ensureBuffer(bufferLength + rowBytes);
+ let prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
+ if (prevRow.length === 0) {
+ prevRow = new Uint8Array(rowBytes);
+ }
+ let i,
+ j = bufferLength,
+ up,
+ c;
+ switch (predictor) {
+ case 0:
+ for (i = 0; i < rowBytes; ++i) {
+ buffer[j++] = rawBytes[i];
+ }
+ break;
+ case 1:
+ for (i = 0; i < pixBytes; ++i) {
+ buffer[j++] = rawBytes[i];
+ }
+ for (; i < rowBytes; ++i) {
+ buffer[j] = buffer[j - pixBytes] + rawBytes[i] & 0xff;
+ j++;
+ }
+ break;
+ case 2:
+ for (i = 0; i < rowBytes; ++i) {
+ buffer[j++] = prevRow[i] + rawBytes[i] & 0xff;
+ }
+ break;
+ case 3:
+ for (i = 0; i < pixBytes; ++i) {
+ buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
+ }
+ for (; i < rowBytes; ++i) {
+ buffer[j] = (prevRow[i] + buffer[j - pixBytes] >> 1) + rawBytes[i] & 0xff;
+ j++;
+ }
+ break;
+ case 4:
+ for (i = 0; i < pixBytes; ++i) {
+ up = prevRow[i];
+ c = rawBytes[i];
+ buffer[j++] = up + c;
+ }
+ for (; i < rowBytes; ++i) {
+ up = prevRow[i];
+ const upLeft = prevRow[i - pixBytes];
+ const left = buffer[j - pixBytes];
+ const p = left + up - upLeft;
+ let pa = p - left;
+ if (pa < 0) {
+ pa = -pa;
+ }
+ let pb = p - up;
+ if (pb < 0) {
+ pb = -pb;
+ }
+ let pc = p - upLeft;
+ if (pc < 0) {
+ pc = -pc;
+ }
+ c = rawBytes[i];
+ if (pa <= pb && pa <= pc) {
+ buffer[j++] = left + c;
+ } else if (pb <= pc) {
+ buffer[j++] = up + c;
+ } else {
+ buffer[j++] = upLeft + c;
+ }
+ }
+ break;
+ default:
+ throw new FormatError(`Unsupported predictor: ${predictor}`);
+ }
+ this.bufferLength += rowBytes;
+ }
+}
+
+;// ./src/core/run_length_stream.js
+
+class RunLengthStream extends DecodeStream {
+ constructor(str, maybeLength) {
+ super(maybeLength);
+ this.stream = str;
+ this.dict = str.dict;
+ }
+ readBlock() {
+ const repeatHeader = this.stream.getBytes(2);
+ if (repeatHeader.length < 2 || repeatHeader[0] === 128) {
+ this.eof = true;
+ return;
+ }
+ let buffer;
+ let bufferLength = this.bufferLength;
+ let n = repeatHeader[0];
+ if (n < 128) {
+ buffer = this.ensureBuffer(bufferLength + n + 1);
+ buffer[bufferLength++] = repeatHeader[1];
+ if (n > 0) {
+ const source = this.stream.getBytes(n);
+ buffer.set(source, bufferLength);
+ bufferLength += n;
+ }
+ } else {
+ n = 257 - n;
+ buffer = this.ensureBuffer(bufferLength + n + 1);
+ buffer.fill(repeatHeader[1], bufferLength, bufferLength + n);
+ bufferLength += n;
+ }
+ this.bufferLength = bufferLength;
+ }
+}
+
+;// ./src/core/parser.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const MAX_LENGTH_TO_CACHE = 1000;
+function getInlineImageCacheKey(bytes) {
+ const strBuf = [],
+ ii = bytes.length;
+ let i = 0;
+ while (i < ii - 1) {
+ strBuf.push(bytes[i++] << 8 | bytes[i++]);
+ }
+ if (i < ii) {
+ strBuf.push(bytes[i]);
+ }
+ return ii + "_" + String.fromCharCode.apply(null, strBuf);
+}
+class Parser {
+ #imageCache = null;
+ #imageId = 0;
+ constructor({
+ lexer,
+ xref,
+ allowStreams = false,
+ recoveryMode = false
+ }) {
+ this.lexer = lexer;
+ this.xref = xref;
+ this.allowStreams = allowStreams;
+ this.recoveryMode = recoveryMode;
+ this.refill();
+ }
+ refill() {
+ this.buf1 = this.lexer.getObj();
+ this.buf2 = this.lexer.getObj();
+ }
+ shift() {
+ if (this.buf2 instanceof Cmd && this.buf2.cmd === "ID") {
+ this.buf1 = this.buf2;
+ this.buf2 = null;
+ } else {
+ this.buf1 = this.buf2;
+ this.buf2 = this.lexer.getObj();
+ }
+ }
+ tryShift() {
+ try {
+ this.shift();
+ return true;
+ } catch (e) {
+ if (e instanceof MissingDataException) {
+ throw e;
+ }
+ return false;
+ }
+ }
+ getObj(cipherTransform = null) {
+ const buf1 = this.buf1;
+ this.shift();
+ if (buf1 instanceof Cmd) {
+ switch (buf1.cmd) {
+ case "BI":
+ return this.makeInlineImage(cipherTransform);
+ case "[":
+ const array = [];
+ while (!isCmd(this.buf1, "]") && this.buf1 !== EOF) {
+ array.push(this.getObj(cipherTransform));
+ }
+ if (this.buf1 === EOF) {
+ if (this.recoveryMode) {
+ return array;
+ }
+ throw new ParserEOFException("End of file inside array.");
+ }
+ this.shift();
+ return array;
+ case "<<":
+ const dict = new Dict(this.xref);
+ while (!isCmd(this.buf1, ">>") && this.buf1 !== EOF) {
+ if (!(this.buf1 instanceof Name)) {
+ info("Malformed dictionary: key must be a name object");
+ this.shift();
+ continue;
+ }
+ const key = this.buf1.name;
+ this.shift();
+ if (this.buf1 === EOF) {
+ break;
+ }
+ dict.set(key, this.getObj(cipherTransform));
+ }
+ if (this.buf1 === EOF) {
+ if (this.recoveryMode) {
+ return dict;
+ }
+ throw new ParserEOFException("End of file inside dictionary.");
+ }
+ if (isCmd(this.buf2, "stream")) {
+ return this.allowStreams ? this.makeStream(dict, cipherTransform) : dict;
+ }
+ this.shift();
+ return dict;
+ default:
+ return buf1;
+ }
+ }
+ if (Number.isInteger(buf1)) {
+ if (Number.isInteger(this.buf1) && isCmd(this.buf2, "R")) {
+ const ref = Ref.get(buf1, this.buf1);
+ this.shift();
+ this.shift();
+ return ref;
+ }
+ return buf1;
+ }
+ if (typeof buf1 === "string") {
+ return cipherTransform ? cipherTransform.decryptString(buf1) : buf1;
+ }
+ return buf1;
+ }
+ findDefaultInlineStreamEnd(stream) {
+ const E = 0x45,
+ I = 0x49,
+ SPACE = 0x20,
+ LF = 0xa,
+ CR = 0xd,
+ NUL = 0x0;
+ const {
+ knownCommands
+ } = this.lexer,
+ startPos = stream.pos,
+ n = 15;
+ let state = 0,
+ ch,
+ maybeEIPos;
+ while ((ch = stream.getByte()) !== -1) {
+ if (state === 0) {
+ state = ch === E ? 1 : 0;
+ } else if (state === 1) {
+ state = ch === I ? 2 : 0;
+ } else {
+ if (ch === SPACE || ch === LF || ch === CR) {
+ maybeEIPos = stream.pos;
+ const followingBytes = stream.peekBytes(n);
+ const ii = followingBytes.length;
+ if (ii === 0) {
+ break;
+ }
+ for (let i = 0; i < ii; i++) {
+ ch = followingBytes[i];
+ if (ch === NUL && followingBytes[i + 1] !== NUL) {
+ continue;
+ }
+ if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7f)) {
+ state = 0;
+ break;
+ }
+ }
+ if (state !== 2) {
+ continue;
+ }
+ if (!knownCommands) {
+ warn("findDefaultInlineStreamEnd - `lexer.knownCommands` is undefined.");
+ continue;
+ }
+ const tmpLexer = new Lexer(new Stream(stream.peekBytes(5 * n)), knownCommands);
+ tmpLexer._hexStringWarn = () => {};
+ let numArgs = 0;
+ while (true) {
+ const nextObj = tmpLexer.getObj();
+ if (nextObj === EOF) {
+ state = 0;
+ break;
+ }
+ if (nextObj instanceof Cmd) {
+ const knownCommand = knownCommands[nextObj.cmd];
+ if (!knownCommand) {
+ state = 0;
+ break;
+ } else if (knownCommand.variableArgs ? numArgs <= knownCommand.numArgs : numArgs === knownCommand.numArgs) {
+ break;
+ }
+ numArgs = 0;
+ continue;
+ }
+ numArgs++;
+ }
+ if (state === 2) {
+ break;
+ }
+ } else {
+ state = 0;
+ }
+ }
+ }
+ if (ch === -1) {
+ warn("findDefaultInlineStreamEnd: " + "Reached the end of the stream without finding a valid EI marker");
+ if (maybeEIPos) {
+ warn('... trying to recover by using the last "EI" occurrence.');
+ stream.skip(-(stream.pos - maybeEIPos));
+ }
+ }
+ let endOffset = 4;
+ stream.skip(-endOffset);
+ ch = stream.peekByte();
+ stream.skip(endOffset);
+ if (!isWhiteSpace(ch)) {
+ endOffset--;
+ }
+ return stream.pos - endOffset - startPos;
+ }
+ findDCTDecodeInlineStreamEnd(stream) {
+ const startPos = stream.pos;
+ let foundEOI = false,
+ b,
+ markerLength;
+ while ((b = stream.getByte()) !== -1) {
+ if (b !== 0xff) {
+ continue;
+ }
+ switch (stream.getByte()) {
+ case 0x00:
+ break;
+ case 0xff:
+ stream.skip(-1);
+ break;
+ case 0xd9:
+ foundEOI = true;
+ break;
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ case 0xc4:
+ case 0xcc:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ case 0xfe:
+ markerLength = stream.getUint16();
+ if (markerLength > 2) {
+ stream.skip(markerLength - 2);
+ } else {
+ stream.skip(-2);
+ }
+ break;
+ }
+ if (foundEOI) {
+ break;
+ }
+ }
+ const length = stream.pos - startPos;
+ if (b === -1) {
+ warn("Inline DCTDecode image stream: " + "EOI marker not found, searching for /EI/ instead.");
+ stream.skip(-length);
+ return this.findDefaultInlineStreamEnd(stream);
+ }
+ this.inlineStreamSkipEI(stream);
+ return length;
+ }
+ findASCII85DecodeInlineStreamEnd(stream) {
+ const TILDE = 0x7e,
+ GT = 0x3e;
+ const startPos = stream.pos;
+ let ch;
+ while ((ch = stream.getByte()) !== -1) {
+ if (ch === TILDE) {
+ const tildePos = stream.pos;
+ ch = stream.peekByte();
+ while (isWhiteSpace(ch)) {
+ stream.skip();
+ ch = stream.peekByte();
+ }
+ if (ch === GT) {
+ stream.skip();
+ break;
+ }
+ if (stream.pos > tildePos) {
+ const maybeEI = stream.peekBytes(2);
+ if (maybeEI[0] === 0x45 && maybeEI[1] === 0x49) {
+ break;
+ }
+ }
+ }
+ }
+ const length = stream.pos - startPos;
+ if (ch === -1) {
+ warn("Inline ASCII85Decode image stream: " + "EOD marker not found, searching for /EI/ instead.");
+ stream.skip(-length);
+ return this.findDefaultInlineStreamEnd(stream);
+ }
+ this.inlineStreamSkipEI(stream);
+ return length;
+ }
+ findASCIIHexDecodeInlineStreamEnd(stream) {
+ const GT = 0x3e;
+ const startPos = stream.pos;
+ let ch;
+ while ((ch = stream.getByte()) !== -1) {
+ if (ch === GT) {
+ break;
+ }
+ }
+ const length = stream.pos - startPos;
+ if (ch === -1) {
+ warn("Inline ASCIIHexDecode image stream: " + "EOD marker not found, searching for /EI/ instead.");
+ stream.skip(-length);
+ return this.findDefaultInlineStreamEnd(stream);
+ }
+ this.inlineStreamSkipEI(stream);
+ return length;
+ }
+ inlineStreamSkipEI(stream) {
+ const E = 0x45,
+ I = 0x49;
+ let state = 0,
+ ch;
+ while ((ch = stream.getByte()) !== -1) {
+ if (state === 0) {
+ state = ch === E ? 1 : 0;
+ } else if (state === 1) {
+ state = ch === I ? 2 : 0;
+ } else if (state === 2) {
+ break;
+ }
+ }
+ }
+ makeInlineImage(cipherTransform) {
+ const lexer = this.lexer;
+ const stream = lexer.stream;
+ const dict = new Dict(this.xref);
+ let dictLength;
+ while (!isCmd(this.buf1, "ID") && this.buf1 !== EOF) {
+ if (!(this.buf1 instanceof Name)) {
+ throw new FormatError("Dictionary key must be a name object");
+ }
+ const key = this.buf1.name;
+ this.shift();
+ if (this.buf1 === EOF) {
+ break;
+ }
+ dict.set(key, this.getObj(cipherTransform));
+ }
+ if (lexer.beginInlineImagePos !== -1) {
+ dictLength = stream.pos - lexer.beginInlineImagePos;
+ }
+ const filter = dict.get("F", "Filter");
+ let filterName;
+ if (filter instanceof Name) {
+ filterName = filter.name;
+ } else if (Array.isArray(filter)) {
+ const filterZero = this.#fetchIfRef(filter[0]);
+ if (filterZero instanceof Name) {
+ filterName = filterZero.name;
+ }
+ }
+ const startPos = stream.pos;
+ let length;
+ switch (filterName) {
+ case "DCT":
+ case "DCTDecode":
+ length = this.findDCTDecodeInlineStreamEnd(stream);
+ break;
+ case "A85":
+ case "ASCII85Decode":
+ length = this.findASCII85DecodeInlineStreamEnd(stream);
+ break;
+ case "AHx":
+ case "ASCIIHexDecode":
+ length = this.findASCIIHexDecodeInlineStreamEnd(stream);
+ break;
+ default:
+ length = this.findDefaultInlineStreamEnd(stream);
+ }
+ let cacheKey;
+ if (length < MAX_LENGTH_TO_CACHE && dictLength > 0) {
+ const initialStreamPos = stream.pos;
+ stream.pos = lexer.beginInlineImagePos;
+ cacheKey = getInlineImageCacheKey(stream.getBytes(dictLength + length));
+ stream.pos = initialStreamPos;
+ const cacheEntry = this.#imageCache?.get(cacheKey);
+ if (cacheEntry) {
+ this.buf2 = Cmd.get("EI");
+ this.shift();
+ cacheEntry.reset();
+ return cacheEntry;
+ }
+ }
+ let imageStream = stream.makeSubStream(startPos, length, dict);
+ if (cipherTransform && !this.#hasCryptFilter(filter)) {
+ imageStream = cipherTransform.createStream(imageStream, length);
+ }
+ imageStream = this.filter(imageStream, dict, length, cipherTransform);
+ imageStream.dict = dict;
+ if (cacheKey) {
+ imageStream.cacheKey = `inline_img_${++this.#imageId}`;
+ (this.#imageCache ??= new Map()).set(cacheKey, imageStream);
+ }
+ this.buf2 = Cmd.get("EI");
+ this.shift();
+ return imageStream;
+ }
+ #fetchIfRef(obj) {
+ return this.xref ? this.xref.fetchIfRef(obj) : obj;
+ }
+ #hasCryptFilter(filter) {
+ return Array.isArray(filter) ? filter.some(f => isName(this.#fetchIfRef(f), "Crypt")) : isName(filter, "Crypt");
+ }
+ #findStreamLength(startPos) {
+ const {
+ stream
+ } = this.lexer;
+ stream.pos = startPos;
+ const SCAN_BLOCK_LENGTH = 2048;
+ const signatureLength = "endstream".length;
+ const END_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64]);
+ const endLength = END_SIGNATURE.length;
+ const PARTIAL_SIGNATURE = [new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61, 0x6d]), new Uint8Array([0x73, 0x74, 0x65, 0x61, 0x6d]), new Uint8Array([0x73, 0x74, 0x72, 0x65, 0x61])];
+ const normalLength = signatureLength - endLength;
+ while (stream.pos < stream.end) {
+ const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH);
+ const scanLength = scanBytes.length - signatureLength;
+ if (scanLength <= 0) {
+ break;
+ }
+ let pos = 0;
+ while (pos < scanLength) {
+ let j = 0;
+ while (j < endLength && scanBytes[pos + j] === END_SIGNATURE[j]) {
+ j++;
+ }
+ if (j >= endLength) {
+ let found = false;
+ for (const part of PARTIAL_SIGNATURE) {
+ const partLen = part.length;
+ let k = 0;
+ while (k < partLen && scanBytes[pos + j + k] === part[k]) {
+ k++;
+ }
+ if (k >= normalLength) {
+ found = true;
+ break;
+ }
+ if (k >= partLen) {
+ const lastByte = scanBytes[pos + j + k];
+ if (isWhiteSpace(lastByte)) {
+ info(`Found "${bytesToString([...END_SIGNATURE, ...part])}" when ` + "searching for endstream command.");
+ found = true;
+ }
+ break;
+ }
+ }
+ if (found) {
+ stream.pos += pos;
+ return stream.pos - startPos;
+ }
+ }
+ pos++;
+ }
+ stream.pos += scanLength;
+ }
+ return -1;
+ }
+ makeStream(dict, cipherTransform) {
+ const lexer = this.lexer;
+ let stream = lexer.stream;
+ lexer.skipToNextLine();
+ const startPos = stream.pos - 1;
+ let length = dict.get("Length");
+ if (!Number.isInteger(length)) {
+ info(`Bad length "${length && length.toString()}" in stream.`);
+ length = 0;
+ }
+ stream.pos = startPos + length;
+ lexer.nextChar();
+ if (this.tryShift() && isCmd(this.buf2, "endstream")) {
+ this.shift();
+ } else {
+ length = this.#findStreamLength(startPos);
+ if (length < 0) {
+ throw new FormatError("Missing endstream command.");
+ }
+ lexer.nextChar();
+ this.shift();
+ this.shift();
+ }
+ this.shift();
+ stream = stream.makeSubStream(startPos, length, dict);
+ const filter = dict.get("F", "Filter");
+ if (cipherTransform && !this.#hasCryptFilter(filter)) {
+ stream = cipherTransform.createStream(stream, length);
+ }
+ stream = this.filter(stream, dict, length, cipherTransform);
+ stream.dict = dict;
+ return stream;
+ }
+ filter(stream, dict, length, cipherTransform = null) {
+ let filter = dict.get("F", "Filter");
+ let params = dict.get("DP", "DecodeParms");
+ if (filter instanceof Name) {
+ if (Array.isArray(params)) {
+ warn("/DecodeParms should not be an Array, when /Filter is a Name.");
+ }
+ return this.makeFilter(stream, filter.name, length, params, cipherTransform);
+ }
+ let maybeLength = length;
+ if (Array.isArray(filter)) {
+ const filterArray = filter;
+ const paramsArray = params;
+ for (let i = 0, ii = filterArray.length; i < ii; ++i) {
+ filter = this.#fetchIfRef(filterArray[i]);
+ if (!(filter instanceof Name)) {
+ throw new FormatError(`Bad filter name "${filter}"`);
+ }
+ params = null;
+ if (Array.isArray(paramsArray) && i in paramsArray) {
+ params = this.#fetchIfRef(paramsArray[i]);
+ }
+ stream = this.makeFilter(stream, filter.name, maybeLength, params, cipherTransform);
+ maybeLength = null;
+ }
+ }
+ return stream;
+ }
+ makeFilter(stream, name, maybeLength, params, cipherTransform = null) {
+ if (maybeLength === 0) {
+ warn(`Empty "${name}" stream.`);
+ return new NullStream();
+ }
+ try {
+ switch (name) {
+ case "Fl":
+ case "FlateDecode":
+ if (params) {
+ return new PredictorStream(new FlateStream(stream, maybeLength), maybeLength, params);
+ }
+ return new FlateStream(stream, maybeLength);
+ case "LZW":
+ case "LZWDecode":
+ let earlyChange = 1;
+ if (params) {
+ if (params.has("EarlyChange")) {
+ earlyChange = params.get("EarlyChange");
+ }
+ return new PredictorStream(new LZWStream(stream, maybeLength, earlyChange), maybeLength, params);
+ }
+ return new LZWStream(stream, maybeLength, earlyChange);
+ case "DCT":
+ case "DCTDecode":
+ return new JpegStream(stream, maybeLength, params);
+ case "JPX":
+ case "JPXDecode":
+ return new JpxStream(stream, maybeLength);
+ case "A85":
+ case "ASCII85Decode":
+ return new Ascii85Stream(stream, maybeLength);
+ case "AHx":
+ case "ASCIIHexDecode":
+ return new AsciiHexStream(stream, maybeLength);
+ case "CCF":
+ case "CCITTFaxDecode":
+ return new CCITTFaxStream(stream, maybeLength, params);
+ case "RL":
+ case "RunLengthDecode":
+ return new RunLengthStream(stream, maybeLength);
+ case "JBIG2Decode":
+ return new Jbig2Stream(stream, maybeLength, params);
+ case "BrotliDecode":
+ return new BrotliStream(stream, maybeLength);
+ case "Crypt":
+ {
+ if (!cipherTransform) {
+ warn('Filter "Crypt" is missing a cipher transform.');
+ return stream;
+ }
+ const param = params instanceof Dict ? params.get("Name") : null;
+ const cryptName = param instanceof Name ? param : Name.get("Identity");
+ return cipherTransform.createStream(stream, maybeLength, cryptName);
+ }
+ }
+ warn(`Filter "${name}" is not supported.`);
+ return stream;
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`Invalid stream: "${ex}"`);
+ return new NullStream();
+ }
+ }
+}
+const specialChars = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+function toHexDigit(ch) {
+ if (ch >= 0x30 && ch <= 0x39) {
+ return ch & 0x0f;
+ }
+ if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) {
+ return (ch & 0x0f) + 9;
+ }
+ return -1;
+}
+class Lexer {
+ constructor(stream, knownCommands = null) {
+ this.stream = stream;
+ this.nextChar();
+ this.strBuf = [];
+ this.knownCommands = knownCommands;
+ this._hexStringNumWarn = 0;
+ this.beginInlineImagePos = -1;
+ }
+ nextChar() {
+ return this.currentChar = this.stream.getByte();
+ }
+ peekChar() {
+ return this.stream.peekByte();
+ }
+ getNumber() {
+ let ch = this.currentChar;
+ let divideBy = 0;
+ let sign = 1;
+ if (ch === 0x2d) {
+ sign = -1;
+ ch = this.nextChar();
+ if (ch === 0x2d) {
+ ch = this.nextChar();
+ }
+ } else if (ch === 0x2b) {
+ ch = this.nextChar();
+ }
+ if (ch === 0x0a || ch === 0x0d) {
+ do {
+ ch = this.nextChar();
+ } while (ch === 0x0a || ch === 0x0d);
+ }
+ if (ch === 0x2e) {
+ divideBy = 10;
+ ch = this.nextChar();
+ }
+ if (ch < 0x30 || ch > 0x39) {
+ const msg = `Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`;
+ if (isWhiteSpace(ch) || ch === 0x28 || ch === 0x3c || ch === -1) {
+ info(`Lexer.getNumber - "${msg}".`);
+ return 0;
+ }
+ throw new FormatError(msg);
+ }
+ let baseValue = ch - 0x30;
+ while ((ch = this.nextChar()) >= 0) {
+ if (ch >= 0x30 && ch <= 0x39) {
+ const currentDigit = ch - 0x30;
+ if (divideBy !== 0) {
+ divideBy *= 10;
+ }
+ baseValue = baseValue * 10 + currentDigit;
+ } else if (ch === 0x2e) {
+ if (divideBy === 0) {
+ divideBy = 1;
+ } else {
+ break;
+ }
+ } else if (ch === 0x2d) {
+ warn("Badly formatted number: minus sign in the middle");
+ } else {
+ break;
+ }
+ }
+ if (divideBy !== 0) {
+ baseValue /= divideBy;
+ }
+ return sign * baseValue;
+ }
+ getString() {
+ let numParen = 1;
+ let done = false;
+ const strBuf = this.strBuf;
+ strBuf.length = 0;
+ let ch = this.nextChar();
+ while (true) {
+ let charBuffered = false;
+ switch (ch | 0) {
+ case -1:
+ warn("Unterminated string");
+ done = true;
+ break;
+ case 0x28:
+ ++numParen;
+ strBuf.push("(");
+ break;
+ case 0x29:
+ if (--numParen === 0) {
+ this.nextChar();
+ done = true;
+ } else {
+ strBuf.push(")");
+ }
+ break;
+ case 0x5c:
+ ch = this.nextChar();
+ switch (ch) {
+ case -1:
+ warn("Unterminated string");
+ done = true;
+ break;
+ case 0x6e:
+ strBuf.push("\n");
+ break;
+ case 0x72:
+ strBuf.push("\r");
+ break;
+ case 0x74:
+ strBuf.push("\t");
+ break;
+ case 0x62:
+ strBuf.push("\b");
+ break;
+ case 0x66:
+ strBuf.push("\f");
+ break;
+ case 0x5c:
+ case 0x28:
+ case 0x29:
+ strBuf.push(String.fromCharCode(ch));
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ let x = ch & 0x0f;
+ ch = this.nextChar();
+ charBuffered = true;
+ if (ch >= 0x30 && ch <= 0x37) {
+ x = (x << 3) + (ch & 0x0f);
+ ch = this.nextChar();
+ if (ch >= 0x30 && ch <= 0x37) {
+ charBuffered = false;
+ x = (x << 3) + (ch & 0x0f);
+ }
+ }
+ strBuf.push(String.fromCharCode(x));
+ break;
+ case 0x0d:
+ if (this.peekChar() === 0x0a) {
+ this.nextChar();
+ }
+ break;
+ case 0x0a:
+ break;
+ default:
+ strBuf.push(String.fromCharCode(ch));
+ break;
+ }
+ break;
+ default:
+ strBuf.push(String.fromCharCode(ch));
+ break;
+ }
+ if (done) {
+ break;
+ }
+ if (!charBuffered) {
+ ch = this.nextChar();
+ }
+ }
+ return strBuf.join("");
+ }
+ getName() {
+ let ch, previousCh;
+ const strBuf = this.strBuf;
+ strBuf.length = 0;
+ while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
+ if (ch === 0x23) {
+ ch = this.nextChar();
+ if (specialChars[ch]) {
+ warn("Lexer_getName: " + "NUMBER SIGN (#) should be followed by a hexadecimal number.");
+ strBuf.push("#");
+ break;
+ }
+ const x = toHexDigit(ch);
+ if (x !== -1) {
+ previousCh = ch;
+ ch = this.nextChar();
+ const x2 = toHexDigit(ch);
+ if (x2 === -1) {
+ warn(`Lexer_getName: Illegal digit (${String.fromCharCode(ch)}) ` + "in hexadecimal number.");
+ strBuf.push("#", String.fromCharCode(previousCh));
+ if (specialChars[ch]) {
+ break;
+ }
+ strBuf.push(String.fromCharCode(ch));
+ continue;
+ }
+ strBuf.push(String.fromCharCode(x << 4 | x2));
+ } else {
+ strBuf.push("#", String.fromCharCode(ch));
+ }
+ } else {
+ strBuf.push(String.fromCharCode(ch));
+ }
+ }
+ if (strBuf.length > 127) {
+ warn(`Name token is longer than allowed by the spec: ${strBuf.length}`);
+ }
+ return Name.get(strBuf.join(""));
+ }
+ _hexStringWarn(ch) {
+ const MAX_HEX_STRING_NUM_WARN = 5;
+ if (this._hexStringNumWarn++ === MAX_HEX_STRING_NUM_WARN) {
+ warn("getHexString - ignoring additional invalid characters.");
+ return;
+ }
+ if (this._hexStringNumWarn > MAX_HEX_STRING_NUM_WARN) {
+ return;
+ }
+ warn(`getHexString - ignoring invalid character: ${ch}`);
+ }
+ getHexString() {
+ const strBuf = this.strBuf;
+ strBuf.length = 0;
+ let ch = this.currentChar;
+ let firstDigit = -1,
+ digit = -1;
+ this._hexStringNumWarn = 0;
+ while (true) {
+ if (ch < 0) {
+ warn("Unterminated hex string");
+ break;
+ } else if (ch === 0x3e) {
+ this.nextChar();
+ break;
+ } else if (specialChars[ch] === 1) {
+ ch = this.nextChar();
+ continue;
+ } else {
+ digit = toHexDigit(ch);
+ if (digit === -1) {
+ this._hexStringWarn(ch);
+ } else if (firstDigit === -1) {
+ firstDigit = digit;
+ } else {
+ strBuf.push(String.fromCharCode(firstDigit << 4 | digit));
+ firstDigit = -1;
+ }
+ ch = this.nextChar();
+ }
+ }
+ if (firstDigit !== -1) {
+ strBuf.push(String.fromCharCode(firstDigit << 4));
+ }
+ return strBuf.join("");
+ }
+ getObj() {
+ let comment = false;
+ let ch = this.currentChar;
+ while (true) {
+ if (ch < 0) {
+ return EOF;
+ }
+ if (comment) {
+ if (ch === 0x0a || ch === 0x0d) {
+ comment = false;
+ }
+ } else if (ch === 0x25) {
+ comment = true;
+ } else if (specialChars[ch] !== 1) {
+ break;
+ }
+ ch = this.nextChar();
+ }
+ switch (ch | 0) {
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x2b:
+ case 0x2d:
+ case 0x2e:
+ return this.getNumber();
+ case 0x28:
+ return this.getString();
+ case 0x2f:
+ return this.getName();
+ case 0x5b:
+ this.nextChar();
+ return Cmd.get("[");
+ case 0x5d:
+ this.nextChar();
+ return Cmd.get("]");
+ case 0x3c:
+ ch = this.nextChar();
+ if (ch === 0x3c) {
+ this.nextChar();
+ return Cmd.get("<<");
+ }
+ return this.getHexString();
+ case 0x3e:
+ ch = this.nextChar();
+ if (ch === 0x3e) {
+ this.nextChar();
+ return Cmd.get(">>");
+ }
+ return Cmd.get(">");
+ case 0x7b:
+ this.nextChar();
+ return Cmd.get("{");
+ case 0x7d:
+ this.nextChar();
+ return Cmd.get("}");
+ case 0x29:
+ this.nextChar();
+ throw new FormatError(`Illegal character: ${ch}`);
+ }
+ let str = String.fromCharCode(ch);
+ if (ch < 0x20 || ch > 0x7f) {
+ const nextCh = this.peekChar();
+ if (nextCh >= 0x20 && nextCh <= 0x7f) {
+ this.nextChar();
+ return Cmd.get(str);
+ }
+ }
+ const knownCommands = this.knownCommands;
+ let knownCommandFound = knownCommands?.[str] !== undefined;
+ while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
+ const possibleCommand = str + String.fromCharCode(ch);
+ if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
+ break;
+ }
+ if (str.length === 128) {
+ throw new FormatError(`Command token too long: ${str.length}`);
+ }
+ str = possibleCommand;
+ knownCommandFound = knownCommands?.[str] !== undefined;
+ }
+ if (str === "true") {
+ return true;
+ }
+ if (str === "false") {
+ return false;
+ }
+ if (str === "null") {
+ return null;
+ }
+ if (str === "BI") {
+ this.beginInlineImagePos = this.stream.pos;
+ }
+ return Cmd.get(str);
+ }
+ skipToNextLine() {
+ let ch = this.currentChar;
+ while (ch >= 0) {
+ if (ch === 0x0d) {
+ ch = this.nextChar();
+ if (ch === 0x0a) {
+ this.nextChar();
+ }
+ break;
+ } else if (ch === 0x0a) {
+ this.nextChar();
+ break;
+ }
+ ch = this.nextChar();
+ }
+ }
+}
+class Linearization {
+ static create(stream) {
+ function getInt(linDict, name, allowZeroValue = false) {
+ const obj = linDict.get(name);
+ if (Number.isInteger(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
+ return obj;
+ }
+ throw new Error(`The "${name}" parameter in the linearization ` + "dictionary is invalid.");
+ }
+ function getHints(linDict) {
+ const hints = linDict.get("H");
+ let hintsLength;
+ if (Array.isArray(hints) && ((hintsLength = hints.length) === 2 || hintsLength === 4)) {
+ for (let index = 0; index < hintsLength; index++) {
+ const hint = hints[index];
+ if (!(Number.isInteger(hint) && hint > 0)) {
+ throw new Error(`Hint (${index}) in the linearization dictionary is invalid.`);
+ }
+ }
+ return hints;
+ }
+ throw new Error("Hint array in the linearization dictionary is invalid.");
+ }
+ const parser = new Parser({
+ lexer: new Lexer(stream),
+ xref: null
+ });
+ const obj1 = parser.getObj();
+ const obj2 = parser.getObj();
+ const obj3 = parser.getObj();
+ const linDict = parser.getObj();
+ let obj, length;
+ if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && isCmd(obj3, "obj") && linDict instanceof Dict && typeof (obj = linDict.get("Linearized")) === "number" && obj > 0)) {
+ return null;
+ } else if ((length = getInt(linDict, "L")) !== stream.length) {
+ throw new Error('The "L" parameter in the linearization dictionary ' + "does not equal the stream length.");
+ }
+ return {
+ length,
+ hints: getHints(linDict),
+ objectNumberFirst: getInt(linDict, "O"),
+ endFirst: getInt(linDict, "E"),
+ numPages: getInt(linDict, "N"),
+ mainXRefEntriesOffset: getInt(linDict, "T"),
+ pageFirst: linDict.has("P") ? getInt(linDict, "P", true) : 0
+ };
+ }
+}
+
+;// ./src/core/cmap.js
+
+
+
+
+
+
+
+
+
+
+
+const BUILT_IN_CMAPS = ["Adobe-GB1-UCS2", "Adobe-CNS1-UCS2", "Adobe-Japan1-UCS2", "Adobe-Korea1-UCS2", "78-EUC-H", "78-EUC-V", "78-H", "78-RKSJ-H", "78-RKSJ-V", "78-V", "78ms-RKSJ-H", "78ms-RKSJ-V", "83pv-RKSJ-H", "90ms-RKSJ-H", "90ms-RKSJ-V", "90msp-RKSJ-H", "90msp-RKSJ-V", "90pv-RKSJ-H", "90pv-RKSJ-V", "Add-H", "Add-RKSJ-H", "Add-RKSJ-V", "Add-V", "Adobe-CNS1-0", "Adobe-CNS1-1", "Adobe-CNS1-2", "Adobe-CNS1-3", "Adobe-CNS1-4", "Adobe-CNS1-5", "Adobe-CNS1-6", "Adobe-GB1-0", "Adobe-GB1-1", "Adobe-GB1-2", "Adobe-GB1-3", "Adobe-GB1-4", "Adobe-GB1-5", "Adobe-Japan1-0", "Adobe-Japan1-1", "Adobe-Japan1-2", "Adobe-Japan1-3", "Adobe-Japan1-4", "Adobe-Japan1-5", "Adobe-Japan1-6", "Adobe-Korea1-0", "Adobe-Korea1-1", "Adobe-Korea1-2", "B5-H", "B5-V", "B5pc-H", "B5pc-V", "CNS-EUC-H", "CNS-EUC-V", "CNS1-H", "CNS1-V", "CNS2-H", "CNS2-V", "ETHK-B5-H", "ETHK-B5-V", "ETen-B5-H", "ETen-B5-V", "ETenms-B5-H", "ETenms-B5-V", "EUC-H", "EUC-V", "Ext-H", "Ext-RKSJ-H", "Ext-RKSJ-V", "Ext-V", "GB-EUC-H", "GB-EUC-V", "GB-H", "GB-V", "GBK-EUC-H", "GBK-EUC-V", "GBK2K-H", "GBK2K-V", "GBKp-EUC-H", "GBKp-EUC-V", "GBT-EUC-H", "GBT-EUC-V", "GBT-H", "GBT-V", "GBTpc-EUC-H", "GBTpc-EUC-V", "GBpc-EUC-H", "GBpc-EUC-V", "H", "HKdla-B5-H", "HKdla-B5-V", "HKdlb-B5-H", "HKdlb-B5-V", "HKgccs-B5-H", "HKgccs-B5-V", "HKm314-B5-H", "HKm314-B5-V", "HKm471-B5-H", "HKm471-B5-V", "HKscs-B5-H", "HKscs-B5-V", "Hankaku", "Hiragana", "KSC-EUC-H", "KSC-EUC-V", "KSC-H", "KSC-Johab-H", "KSC-Johab-V", "KSC-V", "KSCms-UHC-H", "KSCms-UHC-HW-H", "KSCms-UHC-HW-V", "KSCms-UHC-V", "KSCpc-EUC-H", "KSCpc-EUC-V", "Katakana", "NWP-H", "NWP-V", "RKSJ-H", "RKSJ-V", "Roman", "UniCNS-UCS2-H", "UniCNS-UCS2-V", "UniCNS-UTF16-H", "UniCNS-UTF16-V", "UniCNS-UTF32-H", "UniCNS-UTF32-V", "UniCNS-UTF8-H", "UniCNS-UTF8-V", "UniGB-UCS2-H", "UniGB-UCS2-V", "UniGB-UTF16-H", "UniGB-UTF16-V", "UniGB-UTF32-H", "UniGB-UTF32-V", "UniGB-UTF8-H", "UniGB-UTF8-V", "UniJIS-UCS2-H", "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V", "UniJIS-UCS2-V", "UniJIS-UTF16-H", "UniJIS-UTF16-V", "UniJIS-UTF32-H", "UniJIS-UTF32-V", "UniJIS-UTF8-H", "UniJIS-UTF8-V", "UniJIS2004-UTF16-H", "UniJIS2004-UTF16-V", "UniJIS2004-UTF32-H", "UniJIS2004-UTF32-V", "UniJIS2004-UTF8-H", "UniJIS2004-UTF8-V", "UniJISPro-UCS2-HW-V", "UniJISPro-UCS2-V", "UniJISPro-UTF8-V", "UniJISX0213-UTF32-H", "UniJISX0213-UTF32-V", "UniJISX02132004-UTF32-H", "UniJISX02132004-UTF32-V", "UniKS-UCS2-H", "UniKS-UCS2-V", "UniKS-UTF16-H", "UniKS-UTF16-V", "UniKS-UTF32-H", "UniKS-UTF32-V", "UniKS-UTF8-H", "UniKS-UTF8-V", "V", "WP-Symbol"];
+const MAX_MAP_RANGE = 2 ** 24 - 1;
+class CMap {
+ constructor(builtInCMap = false) {
+ this.codespaceRanges = [[], [], [], []];
+ this.numCodespaceRanges = 0;
+ this._map = [];
+ this.name = "";
+ this.vertical = false;
+ this.useCMap = null;
+ this.builtInCMap = builtInCMap;
+ }
+ addCodespaceRange(n, low, high) {
+ this.codespaceRanges[n - 1].push(low, high);
+ this.numCodespaceRanges++;
+ }
+ mapCidRange(low, high, dstLow) {
+ if (high - low > MAX_MAP_RANGE) {
+ throw new Error("mapCidRange - ignoring data above MAX_MAP_RANGE.");
+ }
+ while (low <= high) {
+ this._map[low++] = dstLow++;
+ }
+ }
+ mapBfRange(low, high, dstLow) {
+ if (high - low > MAX_MAP_RANGE) {
+ throw new Error("mapBfRange - ignoring data above MAX_MAP_RANGE.");
+ }
+ const lastByte = dstLow.length - 1;
+ while (low <= high) {
+ this._map[low++] = dstLow;
+ const nextCharCode = dstLow.charCodeAt(lastByte) + 1;
+ if (nextCharCode > 0xff) {
+ dstLow = dstLow.substring(0, lastByte - 1) + String.fromCharCode(dstLow.charCodeAt(lastByte - 1) + 1) + "\x00";
+ continue;
+ }
+ dstLow = dstLow.substring(0, lastByte) + String.fromCharCode(nextCharCode);
+ }
+ }
+ mapBfRangeToArray(low, high, array) {
+ if (high - low > MAX_MAP_RANGE) {
+ throw new Error("mapBfRangeToArray - ignoring data above MAX_MAP_RANGE.");
+ }
+ const ii = array.length;
+ let i = 0;
+ while (low <= high && i < ii) {
+ this._map[low] = array[i++];
+ ++low;
+ }
+ }
+ mapOne(src, dst) {
+ this._map[src] = dst;
+ }
+ lookup(code) {
+ return this._map[code];
+ }
+ contains(code) {
+ return this._map[code] !== undefined;
+ }
+ forEach(callback) {
+ const map = this._map;
+ const length = map.length;
+ if (length <= 0x10000) {
+ for (let i = 0; i < length; i++) {
+ if (map[i] !== undefined) {
+ callback(i, map[i]);
+ }
+ }
+ } else {
+ for (const i in map) {
+ callback(i, map[i]);
+ }
+ }
+ }
+ charCodeOf(value) {
+ const map = this._map;
+ if (map.length <= 0x10000) {
+ return map.indexOf(value);
+ }
+ for (const charCode in map) {
+ if (map[charCode] === value) {
+ return charCode | 0;
+ }
+ }
+ return -1;
+ }
+ getMap() {
+ return this._map;
+ }
+ readCharCode(str, offset, out) {
+ let c = 0;
+ const codespaceRanges = this.codespaceRanges;
+ for (let n = 0, nn = codespaceRanges.length; n < nn; n++) {
+ c = (c << 8 | str.charCodeAt(offset + n)) >>> 0;
+ const codespaceRange = codespaceRanges[n];
+ for (let k = 0, kk = codespaceRange.length; k < kk;) {
+ const low = codespaceRange[k++];
+ const high = codespaceRange[k++];
+ if (c >= low && c <= high) {
+ out.charcode = c;
+ out.length = n + 1;
+ return;
+ }
+ }
+ }
+ out.charcode = 0;
+ out.length = 1;
+ }
+ getCharCodeLength(charCode) {
+ const codespaceRanges = this.codespaceRanges;
+ for (let n = 0, nn = codespaceRanges.length; n < nn; n++) {
+ const codespaceRange = codespaceRanges[n];
+ for (let k = 0, kk = codespaceRange.length; k < kk;) {
+ const low = codespaceRange[k++];
+ const high = codespaceRange[k++];
+ if (charCode >= low && charCode <= high) {
+ return n + 1;
+ }
+ }
+ }
+ return 1;
+ }
+ get length() {
+ return this._map.length;
+ }
+ get isIdentityCMap() {
+ if (!(this.name === "Identity-H" || this.name === "Identity-V")) {
+ return false;
+ }
+ if (this._map.length !== 0x10000) {
+ return false;
+ }
+ for (let i = 0; i < 0x10000; i++) {
+ if (this._map[i] !== i) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+class IdentityCMap extends CMap {
+ constructor(vertical, n) {
+ super();
+ this.vertical = vertical;
+ this.addCodespaceRange(n, 0, 0xffff);
+ }
+ mapCidRange(low, high, dstLow) {
+ unreachable("should not call mapCidRange");
+ }
+ mapBfRange(low, high, dstLow) {
+ unreachable("should not call mapBfRange");
+ }
+ mapBfRangeToArray(low, high, array) {
+ unreachable("should not call mapBfRangeToArray");
+ }
+ mapOne(src, dst) {
+ unreachable("should not call mapCidOne");
+ }
+ lookup(code) {
+ return Number.isInteger(code) && code <= 0xffff ? code : undefined;
+ }
+ contains(code) {
+ return Number.isInteger(code) && code <= 0xffff;
+ }
+ forEach(callback) {
+ for (let i = 0; i <= 0xffff; i++) {
+ callback(i, i);
+ }
+ }
+ charCodeOf(value) {
+ return Number.isInteger(value) && value <= 0xffff ? value : -1;
+ }
+ getMap() {
+ const map = new Array(0x10000);
+ for (let i = 0; i <= 0xffff; i++) {
+ map[i] = i;
+ }
+ return map;
+ }
+ get length() {
+ return 0x10000;
+ }
+ get isIdentityCMap() {
+ unreachable("should not access .isIdentityCMap");
+ }
+}
+function strToInt(str) {
+ let a = 0;
+ for (let i = 0; i < str.length; i++) {
+ a = a << 8 | str.charCodeAt(i);
+ }
+ return a >>> 0;
+}
+function expectString(obj) {
+ if (typeof obj !== "string") {
+ throw new FormatError("Malformed CMap: expected string.");
+ }
+}
+function expectInt(obj) {
+ if (!Number.isInteger(obj)) {
+ throw new FormatError("Malformed CMap: expected int.");
+ }
+}
+function parseBfChar(cMap, lexer) {
+ while (true) {
+ let obj = lexer.getObj();
+ if (obj === EOF) {
+ break;
+ }
+ if (isCmd(obj, "endbfchar")) {
+ return;
+ }
+ expectString(obj);
+ const src = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ const dst = obj;
+ cMap.mapOne(src, dst);
+ }
+}
+function parseBfRange(cMap, lexer) {
+ while (true) {
+ let obj = lexer.getObj();
+ if (obj === EOF) {
+ break;
+ }
+ if (isCmd(obj, "endbfrange")) {
+ return;
+ }
+ expectString(obj);
+ const low = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ const high = strToInt(obj);
+ obj = lexer.getObj();
+ if (Number.isInteger(obj) || typeof obj === "string") {
+ const dstLow = Number.isInteger(obj) ? String.fromCharCode(obj) : obj;
+ cMap.mapBfRange(low, high, dstLow);
+ } else if (isCmd(obj, "[")) {
+ obj = lexer.getObj();
+ const array = [];
+ while (!isCmd(obj, "]") && obj !== EOF) {
+ array.push(obj);
+ obj = lexer.getObj();
+ }
+ cMap.mapBfRangeToArray(low, high, array);
+ } else {
+ break;
+ }
+ }
+ throw new FormatError("Invalid bf range.");
+}
+function parseCidChar(cMap, lexer) {
+ while (true) {
+ let obj = lexer.getObj();
+ if (obj === EOF) {
+ break;
+ }
+ if (isCmd(obj, "endcidchar")) {
+ return;
+ }
+ expectString(obj);
+ const src = strToInt(obj);
+ obj = lexer.getObj();
+ expectInt(obj);
+ const dst = obj;
+ cMap.mapOne(src, dst);
+ }
+}
+function parseCidRange(cMap, lexer) {
+ while (true) {
+ let obj = lexer.getObj();
+ if (obj === EOF) {
+ break;
+ }
+ if (isCmd(obj, "endcidrange")) {
+ return;
+ }
+ expectString(obj);
+ const low = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ const high = strToInt(obj);
+ obj = lexer.getObj();
+ expectInt(obj);
+ const dstLow = obj;
+ cMap.mapCidRange(low, high, dstLow);
+ }
+}
+function parseCodespaceRange(cMap, lexer) {
+ while (true) {
+ let obj = lexer.getObj();
+ if (obj === EOF) {
+ break;
+ }
+ if (isCmd(obj, "endcodespacerange")) {
+ return;
+ }
+ if (typeof obj !== "string") {
+ break;
+ }
+ const low = strToInt(obj);
+ obj = lexer.getObj();
+ if (typeof obj !== "string") {
+ break;
+ }
+ const high = strToInt(obj);
+ cMap.addCodespaceRange(obj.length, low, high);
+ }
+ throw new FormatError("Invalid codespace range.");
+}
+function parseWMode(cMap, lexer) {
+ const obj = lexer.getObj();
+ if (Number.isInteger(obj)) {
+ cMap.vertical = !!obj;
+ }
+}
+function parseCMapName(cMap, lexer) {
+ const obj = lexer.getObj();
+ if (obj instanceof Name) {
+ cMap.name = obj.name;
+ }
+}
+async function parseCMap(cMap, lexer, fetchBuiltInCMap, useCMap) {
+ let previous, embeddedUseCMap;
+ objLoop: while (true) {
+ try {
+ const obj = lexer.getObj();
+ if (obj === EOF) {
+ break;
+ } else if (obj instanceof Name) {
+ if (obj.name === "WMode") {
+ parseWMode(cMap, lexer);
+ } else if (obj.name === "CMapName") {
+ parseCMapName(cMap, lexer);
+ }
+ previous = obj;
+ } else if (obj instanceof Cmd) {
+ switch (obj.cmd) {
+ case "endcmap":
+ break objLoop;
+ case "usecmap":
+ if (previous instanceof Name) {
+ embeddedUseCMap = previous.name;
+ }
+ break;
+ case "begincodespacerange":
+ parseCodespaceRange(cMap, lexer);
+ break;
+ case "beginbfchar":
+ parseBfChar(cMap, lexer);
+ break;
+ case "begincidchar":
+ parseCidChar(cMap, lexer);
+ break;
+ case "beginbfrange":
+ parseBfRange(cMap, lexer);
+ break;
+ case "begincidrange":
+ parseCidRange(cMap, lexer);
+ break;
+ }
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Invalid cMap data: " + ex);
+ continue;
+ }
+ }
+ if (!useCMap && embeddedUseCMap) {
+ useCMap = embeddedUseCMap;
+ }
+ if (useCMap) {
+ return extendCMap(cMap, fetchBuiltInCMap, useCMap);
+ }
+ return cMap;
+}
+async function extendCMap(cMap, fetchBuiltInCMap, useCMap) {
+ cMap.useCMap = await createBuiltInCMap(useCMap, fetchBuiltInCMap);
+ if (cMap.numCodespaceRanges === 0) {
+ const useCodespaceRanges = cMap.useCMap.codespaceRanges;
+ for (let i = 0; i < useCodespaceRanges.length; i++) {
+ cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
+ }
+ cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
+ }
+ cMap.useCMap.forEach(function (key, value) {
+ if (!cMap.contains(key)) {
+ cMap.mapOne(key, value);
+ }
+ });
+ return cMap;
+}
+async function createBuiltInCMap(name, fetchBuiltInCMap) {
+ if (name === "Identity-H") {
+ return new IdentityCMap(false, 2);
+ } else if (name === "Identity-V") {
+ return new IdentityCMap(true, 2);
+ }
+ if (!BUILT_IN_CMAPS.includes(name)) {
+ throw new Error("Unknown CMap name: " + name);
+ }
+ if (!fetchBuiltInCMap) {
+ throw new Error("Built-in CMap parameters are not provided.");
+ }
+ const {
+ cMapData,
+ isCompressed
+ } = await fetchBuiltInCMap(name);
+ const cMap = new CMap(true);
+ if (isCompressed) {
+ return new BinaryCMapReader().process(cMapData, cMap, useCMap => extendCMap(cMap, fetchBuiltInCMap, useCMap));
+ }
+ const lexer = new Lexer(new Stream(cMapData));
+ return parseCMap(cMap, lexer, fetchBuiltInCMap, null);
+}
+class CMapFactory {
+ static async create({
+ encoding,
+ fetchBuiltInCMap,
+ useCMap
+ }) {
+ if (encoding instanceof Name) {
+ return createBuiltInCMap(encoding.name, fetchBuiltInCMap);
+ } else if (encoding instanceof BaseStream) {
+ if (encoding.isAsync) {
+ const bytes = await encoding.asyncGetBytes();
+ if (bytes) {
+ encoding = new Stream(bytes, 0, bytes.length, encoding.dict);
+ }
+ }
+ const parsedCMap = await parseCMap(new CMap(), new Lexer(encoding), fetchBuiltInCMap, useCMap);
+ if (parsedCMap.isIdentityCMap) {
+ return createBuiltInCMap(parsedCMap.name, fetchBuiltInCMap);
+ }
+ return parsedCMap;
+ }
+ throw new Error("Encoding required.");
+ }
+}
+
+;// ./src/core/encodings.js
+const ExpertEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclamsmall", "Hungarumlautsmall", "", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "", "", "", "isuperior", "", "", "lsuperior", "msuperior", "nsuperior", "osuperior", "", "", "rsuperior", "ssuperior", "tsuperior", "", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "exclamdownsmall", "centoldstyle", "Lslashsmall", "", "", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "", "Dotaccentsmall", "", "", "Macronsmall", "", "", "figuredash", "hypheninferior", "", "", "Ogoneksmall", "Ringsmall", "Cedillasmall", "", "", "", "onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "", "", "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall"];
+const MacExpertEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclamsmall", "Hungarumlautsmall", "centoldstyle", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "", "threequartersemdash", "", "questionsmall", "", "", "", "", "Ethsmall", "", "", "onequarter", "onehalf", "threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "", "", "", "", "", "", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "", "parenrightinferior", "Circumflexsmall", "hypheninferior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "", "", "asuperior", "centsuperior", "", "", "", "", "Aacutesmall", "Agravesmall", "Acircumflexsmall", "Adieresissmall", "Atildesmall", "Aringsmall", "Ccedillasmall", "Eacutesmall", "Egravesmall", "Ecircumflexsmall", "Edieresissmall", "Iacutesmall", "Igravesmall", "Icircumflexsmall", "Idieresissmall", "Ntildesmall", "Oacutesmall", "Ogravesmall", "Ocircumflexsmall", "Odieresissmall", "Otildesmall", "Uacutesmall", "Ugravesmall", "Ucircumflexsmall", "Udieresissmall", "", "eightsuperior", "fourinferior", "threeinferior", "sixinferior", "eightinferior", "seveninferior", "Scaronsmall", "", "centinferior", "twoinferior", "", "Dieresissmall", "", "Caronsmall", "osuperior", "fiveinferior", "", "commainferior", "periodinferior", "Yacutesmall", "", "dollarinferior", "", "", "Thornsmall", "", "nineinferior", "zeroinferior", "Zcaronsmall", "AEsmall", "Oslashsmall", "questiondownsmall", "oneinferior", "Lslashsmall", "", "", "", "", "", "", "Cedillasmall", "", "", "", "", "", "OEsmall", "figuredash", "hyphensuperior", "", "", "", "", "exclamdownsmall", "", "Ydieresissmall", "", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "ninesuperior", "zerosuperior", "", "esuperior", "rsuperior", "tsuperior", "", "", "isuperior", "ssuperior", "dsuperior", "", "", "", "", "", "lsuperior", "Ogoneksmall", "Brevesmall", "Macronsmall", "bsuperior", "nsuperior", "msuperior", "commasuperior", "periodsuperior", "Dotaccentsmall", "Ringsmall", "", "", "", ""];
+const MacRomanEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", "ellipsis", "space", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron"];
+const StandardEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "", "endash", "dagger", "daggerdbl", "periodcentered", "", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "", "questiondown", "", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "", "ring", "cedilla", "", "hungarumlaut", "ogonek", "caron", "emdash", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "AE", "", "ordfeminine", "", "", "", "", "Lslash", "Oslash", "OE", "ordmasculine", "", "", "", "", "", "ae", "", "", "", "dotlessi", "", "", "lslash", "oslash", "oe", "germandbls", "", "", "", ""];
+const WinAnsiEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "bullet", "Euro", "bullet", "quotesinglbase", "florin", "quotedblbase", "ellipsis", "dagger", "daggerdbl", "circumflex", "perthousand", "Scaron", "guilsinglleft", "OE", "bullet", "Zcaron", "bullet", "bullet", "quoteleft", "quoteright", "quotedblleft", "quotedblright", "bullet", "endash", "emdash", "tilde", "trademark", "scaron", "guilsinglright", "oe", "bullet", "zcaron", "Ydieresis", "space", "exclamdown", "cent", "sterling", "currency", "yen", "brokenbar", "section", "dieresis", "copyright", "ordfeminine", "guillemotleft", "logicalnot", "hyphen", "registered", "macron", "degree", "plusminus", "twosuperior", "threesuperior", "acute", "mu", "paragraph", "periodcentered", "cedilla", "onesuperior", "ordmasculine", "guillemotright", "onequarter", "onehalf", "threequarters", "questiondown", "Agrave", "Aacute", "Acircumflex", "Atilde", "Adieresis", "Aring", "AE", "Ccedilla", "Egrave", "Eacute", "Ecircumflex", "Edieresis", "Igrave", "Iacute", "Icircumflex", "Idieresis", "Eth", "Ntilde", "Ograve", "Oacute", "Ocircumflex", "Otilde", "Odieresis", "multiply", "Oslash", "Ugrave", "Uacute", "Ucircumflex", "Udieresis", "Yacute", "Thorn", "germandbls", "agrave", "aacute", "acircumflex", "atilde", "adieresis", "aring", "ae", "ccedilla", "egrave", "eacute", "ecircumflex", "edieresis", "igrave", "iacute", "icircumflex", "idieresis", "eth", "ntilde", "ograve", "oacute", "ocircumflex", "otilde", "odieresis", "divide", "oslash", "ugrave", "uacute", "ucircumflex", "udieresis", "yacute", "thorn", "ydieresis"];
+const SymbolSetEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "exclam", "universal", "numbersign", "existential", "percent", "ampersand", "suchthat", "parenleft", "parenright", "asteriskmath", "plus", "comma", "minus", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "congruent", "Alpha", "Beta", "Chi", "Delta", "Epsilon", "Phi", "Gamma", "Eta", "Iota", "theta1", "Kappa", "Lambda", "Mu", "Nu", "Omicron", "Pi", "Theta", "Rho", "Sigma", "Tau", "Upsilon", "sigma1", "Omega", "Xi", "Psi", "Zeta", "bracketleft", "therefore", "bracketright", "perpendicular", "underscore", "radicalex", "alpha", "beta", "chi", "delta", "epsilon", "phi", "gamma", "eta", "iota", "phi1", "kappa", "lambda", "mu", "nu", "omicron", "pi", "theta", "rho", "sigma", "tau", "upsilon", "omega1", "omega", "xi", "psi", "zeta", "braceleft", "bar", "braceright", "similar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Euro", "Upsilon1", "minute", "lessequal", "fraction", "infinity", "florin", "club", "diamond", "heart", "spade", "arrowboth", "arrowleft", "arrowup", "arrowright", "arrowdown", "degree", "plusminus", "second", "greaterequal", "multiply", "proportional", "partialdiff", "bullet", "divide", "notequal", "equivalence", "approxequal", "ellipsis", "arrowvertex", "arrowhorizex", "carriagereturn", "aleph", "Ifraktur", "Rfraktur", "weierstrass", "circlemultiply", "circleplus", "emptyset", "intersection", "union", "propersuperset", "reflexsuperset", "notsubset", "propersubset", "reflexsubset", "element", "notelement", "angle", "gradient", "registerserif", "copyrightserif", "trademarkserif", "product", "radical", "dotmath", "logicalnot", "logicaland", "logicalor", "arrowdblboth", "arrowdblleft", "arrowdblup", "arrowdblright", "arrowdbldown", "lozenge", "angleleft", "registersans", "copyrightsans", "trademarksans", "summation", "parenlefttp", "parenleftex", "parenleftbt", "bracketlefttp", "bracketleftex", "bracketleftbt", "bracelefttp", "braceleftmid", "braceleftbt", "braceex", "", "angleright", "integral", "integraltp", "integralex", "integralbt", "parenrighttp", "parenrightex", "parenrightbt", "bracketrighttp", "bracketrightex", "bracketrightbt", "bracerighttp", "bracerightmid", "bracerightbt", ""];
+const ZapfDingbatsEncoding = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "space", "a1", "a2", "a202", "a3", "a4", "a5", "a119", "a118", "a117", "a11", "a12", "a13", "a14", "a15", "a16", "a105", "a17", "a18", "a19", "a20", "a21", "a22", "a23", "a24", "a25", "a26", "a27", "a28", "a6", "a7", "a8", "a9", "a10", "a29", "a30", "a31", "a32", "a33", "a34", "a35", "a36", "a37", "a38", "a39", "a40", "a41", "a42", "a43", "a44", "a45", "a46", "a47", "a48", "a49", "a50", "a51", "a52", "a53", "a54", "a55", "a56", "a57", "a58", "a59", "a60", "a61", "a62", "a63", "a64", "a65", "a66", "a67", "a68", "a69", "a70", "a71", "a72", "a73", "a74", "a203", "a75", "a204", "a76", "a77", "a78", "a79", "a81", "a82", "a83", "a84", "a97", "a98", "a99", "a100", "", "a89", "a90", "a93", "a94", "a91", "a92", "a205", "a85", "a206", "a86", "a87", "a88", "a95", "a96", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "a101", "a102", "a103", "a104", "a106", "a107", "a108", "a112", "a111", "a110", "a109", "a120", "a121", "a122", "a123", "a124", "a125", "a126", "a127", "a128", "a129", "a130", "a131", "a132", "a133", "a134", "a135", "a136", "a137", "a138", "a139", "a140", "a141", "a142", "a143", "a144", "a145", "a146", "a147", "a148", "a149", "a150", "a151", "a152", "a153", "a154", "a155", "a156", "a157", "a158", "a159", "a160", "a161", "a163", "a164", "a196", "a165", "a192", "a166", "a167", "a168", "a169", "a170", "a171", "a172", "a173", "a162", "a174", "a175", "a176", "a177", "a178", "a179", "a193", "a180", "a199", "a181", "a200", "a182", "", "a201", "a183", "a184", "a197", "a185", "a194", "a198", "a186", "a195", "a187", "a188", "a189", "a190", "a191", ""];
+function getEncoding(encodingName) {
+ switch (encodingName) {
+ case "WinAnsiEncoding":
+ return WinAnsiEncoding;
+ case "StandardEncoding":
+ return StandardEncoding;
+ case "MacRomanEncoding":
+ return MacRomanEncoding;
+ case "SymbolSetEncoding":
+ return SymbolSetEncoding;
+ case "ZapfDingbatsEncoding":
+ return ZapfDingbatsEncoding;
+ case "ExpertEncoding":
+ return ExpertEncoding;
+ case "MacExpertEncoding":
+ return MacExpertEncoding;
+ default:
+ return null;
+ }
+}
+
+;// ./src/core/glyphlist.js
+
+const getGlyphsUnicode = getLookupTableFactory(function (t) {
+ t.A = 0x0041;
+ t.AE = 0x00c6;
+ t.AEacute = 0x01fc;
+ t.AEmacron = 0x01e2;
+ t.AEsmall = 0xf7e6;
+ t.Aacute = 0x00c1;
+ t.Aacutesmall = 0xf7e1;
+ t.Abreve = 0x0102;
+ t.Abreveacute = 0x1eae;
+ t.Abrevecyrillic = 0x04d0;
+ t.Abrevedotbelow = 0x1eb6;
+ t.Abrevegrave = 0x1eb0;
+ t.Abrevehookabove = 0x1eb2;
+ t.Abrevetilde = 0x1eb4;
+ t.Acaron = 0x01cd;
+ t.Acircle = 0x24b6;
+ t.Acircumflex = 0x00c2;
+ t.Acircumflexacute = 0x1ea4;
+ t.Acircumflexdotbelow = 0x1eac;
+ t.Acircumflexgrave = 0x1ea6;
+ t.Acircumflexhookabove = 0x1ea8;
+ t.Acircumflexsmall = 0xf7e2;
+ t.Acircumflextilde = 0x1eaa;
+ t.Acute = 0xf6c9;
+ t.Acutesmall = 0xf7b4;
+ t.Acyrillic = 0x0410;
+ t.Adblgrave = 0x0200;
+ t.Adieresis = 0x00c4;
+ t.Adieresiscyrillic = 0x04d2;
+ t.Adieresismacron = 0x01de;
+ t.Adieresissmall = 0xf7e4;
+ t.Adotbelow = 0x1ea0;
+ t.Adotmacron = 0x01e0;
+ t.Agrave = 0x00c0;
+ t.Agravesmall = 0xf7e0;
+ t.Ahookabove = 0x1ea2;
+ t.Aiecyrillic = 0x04d4;
+ t.Ainvertedbreve = 0x0202;
+ t.Alpha = 0x0391;
+ t.Alphatonos = 0x0386;
+ t.Amacron = 0x0100;
+ t.Amonospace = 0xff21;
+ t.Aogonek = 0x0104;
+ t.Aring = 0x00c5;
+ t.Aringacute = 0x01fa;
+ t.Aringbelow = 0x1e00;
+ t.Aringsmall = 0xf7e5;
+ t.Asmall = 0xf761;
+ t.Atilde = 0x00c3;
+ t.Atildesmall = 0xf7e3;
+ t.Aybarmenian = 0x0531;
+ t.B = 0x0042;
+ t.Bcircle = 0x24b7;
+ t.Bdotaccent = 0x1e02;
+ t.Bdotbelow = 0x1e04;
+ t.Becyrillic = 0x0411;
+ t.Benarmenian = 0x0532;
+ t.Beta = 0x0392;
+ t.Bhook = 0x0181;
+ t.Blinebelow = 0x1e06;
+ t.Bmonospace = 0xff22;
+ t.Brevesmall = 0xf6f4;
+ t.Bsmall = 0xf762;
+ t.Btopbar = 0x0182;
+ t.C = 0x0043;
+ t.Caarmenian = 0x053e;
+ t.Cacute = 0x0106;
+ t.Caron = 0xf6ca;
+ t.Caronsmall = 0xf6f5;
+ t.Ccaron = 0x010c;
+ t.Ccedilla = 0x00c7;
+ t.Ccedillaacute = 0x1e08;
+ t.Ccedillasmall = 0xf7e7;
+ t.Ccircle = 0x24b8;
+ t.Ccircumflex = 0x0108;
+ t.Cdot = 0x010a;
+ t.Cdotaccent = 0x010a;
+ t.Cedillasmall = 0xf7b8;
+ t.Chaarmenian = 0x0549;
+ t.Cheabkhasiancyrillic = 0x04bc;
+ t.Checyrillic = 0x0427;
+ t.Chedescenderabkhasiancyrillic = 0x04be;
+ t.Chedescendercyrillic = 0x04b6;
+ t.Chedieresiscyrillic = 0x04f4;
+ t.Cheharmenian = 0x0543;
+ t.Chekhakassiancyrillic = 0x04cb;
+ t.Cheverticalstrokecyrillic = 0x04b8;
+ t.Chi = 0x03a7;
+ t.Chook = 0x0187;
+ t.Circumflexsmall = 0xf6f6;
+ t.Cmonospace = 0xff23;
+ t.Coarmenian = 0x0551;
+ t.Csmall = 0xf763;
+ t.D = 0x0044;
+ t.DZ = 0x01f1;
+ t.DZcaron = 0x01c4;
+ t.Daarmenian = 0x0534;
+ t.Dafrican = 0x0189;
+ t.Dcaron = 0x010e;
+ t.Dcedilla = 0x1e10;
+ t.Dcircle = 0x24b9;
+ t.Dcircumflexbelow = 0x1e12;
+ t.Dcroat = 0x0110;
+ t.Ddotaccent = 0x1e0a;
+ t.Ddotbelow = 0x1e0c;
+ t.Decyrillic = 0x0414;
+ t.Deicoptic = 0x03ee;
+ t.Delta = 0x2206;
+ t.Deltagreek = 0x0394;
+ t.Dhook = 0x018a;
+ t.Dieresis = 0xf6cb;
+ t.DieresisAcute = 0xf6cc;
+ t.DieresisGrave = 0xf6cd;
+ t.Dieresissmall = 0xf7a8;
+ t.Digammagreek = 0x03dc;
+ t.Djecyrillic = 0x0402;
+ t.Dlinebelow = 0x1e0e;
+ t.Dmonospace = 0xff24;
+ t.Dotaccentsmall = 0xf6f7;
+ t.Dslash = 0x0110;
+ t.Dsmall = 0xf764;
+ t.Dtopbar = 0x018b;
+ t.Dz = 0x01f2;
+ t.Dzcaron = 0x01c5;
+ t.Dzeabkhasiancyrillic = 0x04e0;
+ t.Dzecyrillic = 0x0405;
+ t.Dzhecyrillic = 0x040f;
+ t.E = 0x0045;
+ t.Eacute = 0x00c9;
+ t.Eacutesmall = 0xf7e9;
+ t.Ebreve = 0x0114;
+ t.Ecaron = 0x011a;
+ t.Ecedillabreve = 0x1e1c;
+ t.Echarmenian = 0x0535;
+ t.Ecircle = 0x24ba;
+ t.Ecircumflex = 0x00ca;
+ t.Ecircumflexacute = 0x1ebe;
+ t.Ecircumflexbelow = 0x1e18;
+ t.Ecircumflexdotbelow = 0x1ec6;
+ t.Ecircumflexgrave = 0x1ec0;
+ t.Ecircumflexhookabove = 0x1ec2;
+ t.Ecircumflexsmall = 0xf7ea;
+ t.Ecircumflextilde = 0x1ec4;
+ t.Ecyrillic = 0x0404;
+ t.Edblgrave = 0x0204;
+ t.Edieresis = 0x00cb;
+ t.Edieresissmall = 0xf7eb;
+ t.Edot = 0x0116;
+ t.Edotaccent = 0x0116;
+ t.Edotbelow = 0x1eb8;
+ t.Efcyrillic = 0x0424;
+ t.Egrave = 0x00c8;
+ t.Egravesmall = 0xf7e8;
+ t.Eharmenian = 0x0537;
+ t.Ehookabove = 0x1eba;
+ t.Eightroman = 0x2167;
+ t.Einvertedbreve = 0x0206;
+ t.Eiotifiedcyrillic = 0x0464;
+ t.Elcyrillic = 0x041b;
+ t.Elevenroman = 0x216a;
+ t.Emacron = 0x0112;
+ t.Emacronacute = 0x1e16;
+ t.Emacrongrave = 0x1e14;
+ t.Emcyrillic = 0x041c;
+ t.Emonospace = 0xff25;
+ t.Encyrillic = 0x041d;
+ t.Endescendercyrillic = 0x04a2;
+ t.Eng = 0x014a;
+ t.Enghecyrillic = 0x04a4;
+ t.Enhookcyrillic = 0x04c7;
+ t.Eogonek = 0x0118;
+ t.Eopen = 0x0190;
+ t.Epsilon = 0x0395;
+ t.Epsilontonos = 0x0388;
+ t.Ercyrillic = 0x0420;
+ t.Ereversed = 0x018e;
+ t.Ereversedcyrillic = 0x042d;
+ t.Escyrillic = 0x0421;
+ t.Esdescendercyrillic = 0x04aa;
+ t.Esh = 0x01a9;
+ t.Esmall = 0xf765;
+ t.Eta = 0x0397;
+ t.Etarmenian = 0x0538;
+ t.Etatonos = 0x0389;
+ t.Eth = 0x00d0;
+ t.Ethsmall = 0xf7f0;
+ t.Etilde = 0x1ebc;
+ t.Etildebelow = 0x1e1a;
+ t.Euro = 0x20ac;
+ t.Ezh = 0x01b7;
+ t.Ezhcaron = 0x01ee;
+ t.Ezhreversed = 0x01b8;
+ t.F = 0x0046;
+ t.Fcircle = 0x24bb;
+ t.Fdotaccent = 0x1e1e;
+ t.Feharmenian = 0x0556;
+ t.Feicoptic = 0x03e4;
+ t.Fhook = 0x0191;
+ t.Fitacyrillic = 0x0472;
+ t.Fiveroman = 0x2164;
+ t.Fmonospace = 0xff26;
+ t.Fourroman = 0x2163;
+ t.Fsmall = 0xf766;
+ t.G = 0x0047;
+ t.GBsquare = 0x3387;
+ t.Gacute = 0x01f4;
+ t.Gamma = 0x0393;
+ t.Gammaafrican = 0x0194;
+ t.Gangiacoptic = 0x03ea;
+ t.Gbreve = 0x011e;
+ t.Gcaron = 0x01e6;
+ t.Gcedilla = 0x0122;
+ t.Gcircle = 0x24bc;
+ t.Gcircumflex = 0x011c;
+ t.Gcommaaccent = 0x0122;
+ t.Gdot = 0x0120;
+ t.Gdotaccent = 0x0120;
+ t.Gecyrillic = 0x0413;
+ t.Ghadarmenian = 0x0542;
+ t.Ghemiddlehookcyrillic = 0x0494;
+ t.Ghestrokecyrillic = 0x0492;
+ t.Gheupturncyrillic = 0x0490;
+ t.Ghook = 0x0193;
+ t.Gimarmenian = 0x0533;
+ t.Gjecyrillic = 0x0403;
+ t.Gmacron = 0x1e20;
+ t.Gmonospace = 0xff27;
+ t.Grave = 0xf6ce;
+ t.Gravesmall = 0xf760;
+ t.Gsmall = 0xf767;
+ t.Gsmallhook = 0x029b;
+ t.Gstroke = 0x01e4;
+ t.H = 0x0048;
+ t.H18533 = 0x25cf;
+ t.H18543 = 0x25aa;
+ t.H18551 = 0x25ab;
+ t.H22073 = 0x25a1;
+ t.HPsquare = 0x33cb;
+ t.Haabkhasiancyrillic = 0x04a8;
+ t.Hadescendercyrillic = 0x04b2;
+ t.Hardsigncyrillic = 0x042a;
+ t.Hbar = 0x0126;
+ t.Hbrevebelow = 0x1e2a;
+ t.Hcedilla = 0x1e28;
+ t.Hcircle = 0x24bd;
+ t.Hcircumflex = 0x0124;
+ t.Hdieresis = 0x1e26;
+ t.Hdotaccent = 0x1e22;
+ t.Hdotbelow = 0x1e24;
+ t.Hmonospace = 0xff28;
+ t.Hoarmenian = 0x0540;
+ t.Horicoptic = 0x03e8;
+ t.Hsmall = 0xf768;
+ t.Hungarumlaut = 0xf6cf;
+ t.Hungarumlautsmall = 0xf6f8;
+ t.Hzsquare = 0x3390;
+ t.I = 0x0049;
+ t.IAcyrillic = 0x042f;
+ t.IJ = 0x0132;
+ t.IUcyrillic = 0x042e;
+ t.Iacute = 0x00cd;
+ t.Iacutesmall = 0xf7ed;
+ t.Ibreve = 0x012c;
+ t.Icaron = 0x01cf;
+ t.Icircle = 0x24be;
+ t.Icircumflex = 0x00ce;
+ t.Icircumflexsmall = 0xf7ee;
+ t.Icyrillic = 0x0406;
+ t.Idblgrave = 0x0208;
+ t.Idieresis = 0x00cf;
+ t.Idieresisacute = 0x1e2e;
+ t.Idieresiscyrillic = 0x04e4;
+ t.Idieresissmall = 0xf7ef;
+ t.Idot = 0x0130;
+ t.Idotaccent = 0x0130;
+ t.Idotbelow = 0x1eca;
+ t.Iebrevecyrillic = 0x04d6;
+ t.Iecyrillic = 0x0415;
+ t.Ifraktur = 0x2111;
+ t.Igrave = 0x00cc;
+ t.Igravesmall = 0xf7ec;
+ t.Ihookabove = 0x1ec8;
+ t.Iicyrillic = 0x0418;
+ t.Iinvertedbreve = 0x020a;
+ t.Iishortcyrillic = 0x0419;
+ t.Imacron = 0x012a;
+ t.Imacroncyrillic = 0x04e2;
+ t.Imonospace = 0xff29;
+ t.Iniarmenian = 0x053b;
+ t.Iocyrillic = 0x0401;
+ t.Iogonek = 0x012e;
+ t.Iota = 0x0399;
+ t.Iotaafrican = 0x0196;
+ t.Iotadieresis = 0x03aa;
+ t.Iotatonos = 0x038a;
+ t.Ismall = 0xf769;
+ t.Istroke = 0x0197;
+ t.Itilde = 0x0128;
+ t.Itildebelow = 0x1e2c;
+ t.Izhitsacyrillic = 0x0474;
+ t.Izhitsadblgravecyrillic = 0x0476;
+ t.J = 0x004a;
+ t.Jaarmenian = 0x0541;
+ t.Jcircle = 0x24bf;
+ t.Jcircumflex = 0x0134;
+ t.Jecyrillic = 0x0408;
+ t.Jheharmenian = 0x054b;
+ t.Jmonospace = 0xff2a;
+ t.Jsmall = 0xf76a;
+ t.K = 0x004b;
+ t.KBsquare = 0x3385;
+ t.KKsquare = 0x33cd;
+ t.Kabashkircyrillic = 0x04a0;
+ t.Kacute = 0x1e30;
+ t.Kacyrillic = 0x041a;
+ t.Kadescendercyrillic = 0x049a;
+ t.Kahookcyrillic = 0x04c3;
+ t.Kappa = 0x039a;
+ t.Kastrokecyrillic = 0x049e;
+ t.Kaverticalstrokecyrillic = 0x049c;
+ t.Kcaron = 0x01e8;
+ t.Kcedilla = 0x0136;
+ t.Kcircle = 0x24c0;
+ t.Kcommaaccent = 0x0136;
+ t.Kdotbelow = 0x1e32;
+ t.Keharmenian = 0x0554;
+ t.Kenarmenian = 0x053f;
+ t.Khacyrillic = 0x0425;
+ t.Kheicoptic = 0x03e6;
+ t.Khook = 0x0198;
+ t.Kjecyrillic = 0x040c;
+ t.Klinebelow = 0x1e34;
+ t.Kmonospace = 0xff2b;
+ t.Koppacyrillic = 0x0480;
+ t.Koppagreek = 0x03de;
+ t.Ksicyrillic = 0x046e;
+ t.Ksmall = 0xf76b;
+ t.L = 0x004c;
+ t.LJ = 0x01c7;
+ t.LL = 0xf6bf;
+ t.Lacute = 0x0139;
+ t.Lambda = 0x039b;
+ t.Lcaron = 0x013d;
+ t.Lcedilla = 0x013b;
+ t.Lcircle = 0x24c1;
+ t.Lcircumflexbelow = 0x1e3c;
+ t.Lcommaaccent = 0x013b;
+ t.Ldot = 0x013f;
+ t.Ldotaccent = 0x013f;
+ t.Ldotbelow = 0x1e36;
+ t.Ldotbelowmacron = 0x1e38;
+ t.Liwnarmenian = 0x053c;
+ t.Lj = 0x01c8;
+ t.Ljecyrillic = 0x0409;
+ t.Llinebelow = 0x1e3a;
+ t.Lmonospace = 0xff2c;
+ t.Lslash = 0x0141;
+ t.Lslashsmall = 0xf6f9;
+ t.Lsmall = 0xf76c;
+ t.M = 0x004d;
+ t.MBsquare = 0x3386;
+ t.Macron = 0xf6d0;
+ t.Macronsmall = 0xf7af;
+ t.Macute = 0x1e3e;
+ t.Mcircle = 0x24c2;
+ t.Mdotaccent = 0x1e40;
+ t.Mdotbelow = 0x1e42;
+ t.Menarmenian = 0x0544;
+ t.Mmonospace = 0xff2d;
+ t.Msmall = 0xf76d;
+ t.Mturned = 0x019c;
+ t.Mu = 0x039c;
+ t.N = 0x004e;
+ t.NJ = 0x01ca;
+ t.Nacute = 0x0143;
+ t.Ncaron = 0x0147;
+ t.Ncedilla = 0x0145;
+ t.Ncircle = 0x24c3;
+ t.Ncircumflexbelow = 0x1e4a;
+ t.Ncommaaccent = 0x0145;
+ t.Ndotaccent = 0x1e44;
+ t.Ndotbelow = 0x1e46;
+ t.Nhookleft = 0x019d;
+ t.Nineroman = 0x2168;
+ t.Nj = 0x01cb;
+ t.Njecyrillic = 0x040a;
+ t.Nlinebelow = 0x1e48;
+ t.Nmonospace = 0xff2e;
+ t.Nowarmenian = 0x0546;
+ t.Nsmall = 0xf76e;
+ t.Ntilde = 0x00d1;
+ t.Ntildesmall = 0xf7f1;
+ t.Nu = 0x039d;
+ t.O = 0x004f;
+ t.OE = 0x0152;
+ t.OEsmall = 0xf6fa;
+ t.Oacute = 0x00d3;
+ t.Oacutesmall = 0xf7f3;
+ t.Obarredcyrillic = 0x04e8;
+ t.Obarreddieresiscyrillic = 0x04ea;
+ t.Obreve = 0x014e;
+ t.Ocaron = 0x01d1;
+ t.Ocenteredtilde = 0x019f;
+ t.Ocircle = 0x24c4;
+ t.Ocircumflex = 0x00d4;
+ t.Ocircumflexacute = 0x1ed0;
+ t.Ocircumflexdotbelow = 0x1ed8;
+ t.Ocircumflexgrave = 0x1ed2;
+ t.Ocircumflexhookabove = 0x1ed4;
+ t.Ocircumflexsmall = 0xf7f4;
+ t.Ocircumflextilde = 0x1ed6;
+ t.Ocyrillic = 0x041e;
+ t.Odblacute = 0x0150;
+ t.Odblgrave = 0x020c;
+ t.Odieresis = 0x00d6;
+ t.Odieresiscyrillic = 0x04e6;
+ t.Odieresissmall = 0xf7f6;
+ t.Odotbelow = 0x1ecc;
+ t.Ogoneksmall = 0xf6fb;
+ t.Ograve = 0x00d2;
+ t.Ogravesmall = 0xf7f2;
+ t.Oharmenian = 0x0555;
+ t.Ohm = 0x2126;
+ t.Ohookabove = 0x1ece;
+ t.Ohorn = 0x01a0;
+ t.Ohornacute = 0x1eda;
+ t.Ohorndotbelow = 0x1ee2;
+ t.Ohorngrave = 0x1edc;
+ t.Ohornhookabove = 0x1ede;
+ t.Ohorntilde = 0x1ee0;
+ t.Ohungarumlaut = 0x0150;
+ t.Oi = 0x01a2;
+ t.Oinvertedbreve = 0x020e;
+ t.Omacron = 0x014c;
+ t.Omacronacute = 0x1e52;
+ t.Omacrongrave = 0x1e50;
+ t.Omega = 0x2126;
+ t.Omegacyrillic = 0x0460;
+ t.Omegagreek = 0x03a9;
+ t.Omegaroundcyrillic = 0x047a;
+ t.Omegatitlocyrillic = 0x047c;
+ t.Omegatonos = 0x038f;
+ t.Omicron = 0x039f;
+ t.Omicrontonos = 0x038c;
+ t.Omonospace = 0xff2f;
+ t.Oneroman = 0x2160;
+ t.Oogonek = 0x01ea;
+ t.Oogonekmacron = 0x01ec;
+ t.Oopen = 0x0186;
+ t.Oslash = 0x00d8;
+ t.Oslashacute = 0x01fe;
+ t.Oslashsmall = 0xf7f8;
+ t.Osmall = 0xf76f;
+ t.Ostrokeacute = 0x01fe;
+ t.Otcyrillic = 0x047e;
+ t.Otilde = 0x00d5;
+ t.Otildeacute = 0x1e4c;
+ t.Otildedieresis = 0x1e4e;
+ t.Otildesmall = 0xf7f5;
+ t.P = 0x0050;
+ t.Pacute = 0x1e54;
+ t.Pcircle = 0x24c5;
+ t.Pdotaccent = 0x1e56;
+ t.Pecyrillic = 0x041f;
+ t.Peharmenian = 0x054a;
+ t.Pemiddlehookcyrillic = 0x04a6;
+ t.Phi = 0x03a6;
+ t.Phook = 0x01a4;
+ t.Pi = 0x03a0;
+ t.Piwrarmenian = 0x0553;
+ t.Pmonospace = 0xff30;
+ t.Psi = 0x03a8;
+ t.Psicyrillic = 0x0470;
+ t.Psmall = 0xf770;
+ t.Q = 0x0051;
+ t.Qcircle = 0x24c6;
+ t.Qmonospace = 0xff31;
+ t.Qsmall = 0xf771;
+ t.R = 0x0052;
+ t.Raarmenian = 0x054c;
+ t.Racute = 0x0154;
+ t.Rcaron = 0x0158;
+ t.Rcedilla = 0x0156;
+ t.Rcircle = 0x24c7;
+ t.Rcommaaccent = 0x0156;
+ t.Rdblgrave = 0x0210;
+ t.Rdotaccent = 0x1e58;
+ t.Rdotbelow = 0x1e5a;
+ t.Rdotbelowmacron = 0x1e5c;
+ t.Reharmenian = 0x0550;
+ t.Rfraktur = 0x211c;
+ t.Rho = 0x03a1;
+ t.Ringsmall = 0xf6fc;
+ t.Rinvertedbreve = 0x0212;
+ t.Rlinebelow = 0x1e5e;
+ t.Rmonospace = 0xff32;
+ t.Rsmall = 0xf772;
+ t.Rsmallinverted = 0x0281;
+ t.Rsmallinvertedsuperior = 0x02b6;
+ t.S = 0x0053;
+ t.SF010000 = 0x250c;
+ t.SF020000 = 0x2514;
+ t.SF030000 = 0x2510;
+ t.SF040000 = 0x2518;
+ t.SF050000 = 0x253c;
+ t.SF060000 = 0x252c;
+ t.SF070000 = 0x2534;
+ t.SF080000 = 0x251c;
+ t.SF090000 = 0x2524;
+ t.SF100000 = 0x2500;
+ t.SF110000 = 0x2502;
+ t.SF190000 = 0x2561;
+ t.SF200000 = 0x2562;
+ t.SF210000 = 0x2556;
+ t.SF220000 = 0x2555;
+ t.SF230000 = 0x2563;
+ t.SF240000 = 0x2551;
+ t.SF250000 = 0x2557;
+ t.SF260000 = 0x255d;
+ t.SF270000 = 0x255c;
+ t.SF280000 = 0x255b;
+ t.SF360000 = 0x255e;
+ t.SF370000 = 0x255f;
+ t.SF380000 = 0x255a;
+ t.SF390000 = 0x2554;
+ t.SF400000 = 0x2569;
+ t.SF410000 = 0x2566;
+ t.SF420000 = 0x2560;
+ t.SF430000 = 0x2550;
+ t.SF440000 = 0x256c;
+ t.SF450000 = 0x2567;
+ t.SF460000 = 0x2568;
+ t.SF470000 = 0x2564;
+ t.SF480000 = 0x2565;
+ t.SF490000 = 0x2559;
+ t.SF500000 = 0x2558;
+ t.SF510000 = 0x2552;
+ t.SF520000 = 0x2553;
+ t.SF530000 = 0x256b;
+ t.SF540000 = 0x256a;
+ t.Sacute = 0x015a;
+ t.Sacutedotaccent = 0x1e64;
+ t.Sampigreek = 0x03e0;
+ t.Scaron = 0x0160;
+ t.Scarondotaccent = 0x1e66;
+ t.Scaronsmall = 0xf6fd;
+ t.Scedilla = 0x015e;
+ t.Schwa = 0x018f;
+ t.Schwacyrillic = 0x04d8;
+ t.Schwadieresiscyrillic = 0x04da;
+ t.Scircle = 0x24c8;
+ t.Scircumflex = 0x015c;
+ t.Scommaaccent = 0x0218;
+ t.Sdotaccent = 0x1e60;
+ t.Sdotbelow = 0x1e62;
+ t.Sdotbelowdotaccent = 0x1e68;
+ t.Seharmenian = 0x054d;
+ t.Sevenroman = 0x2166;
+ t.Shaarmenian = 0x0547;
+ t.Shacyrillic = 0x0428;
+ t.Shchacyrillic = 0x0429;
+ t.Sheicoptic = 0x03e2;
+ t.Shhacyrillic = 0x04ba;
+ t.Shimacoptic = 0x03ec;
+ t.Sigma = 0x03a3;
+ t.Sixroman = 0x2165;
+ t.Smonospace = 0xff33;
+ t.Softsigncyrillic = 0x042c;
+ t.Ssmall = 0xf773;
+ t.Stigmagreek = 0x03da;
+ t.T = 0x0054;
+ t.Tau = 0x03a4;
+ t.Tbar = 0x0166;
+ t.Tcaron = 0x0164;
+ t.Tcedilla = 0x0162;
+ t.Tcircle = 0x24c9;
+ t.Tcircumflexbelow = 0x1e70;
+ t.Tcommaaccent = 0x0162;
+ t.Tdotaccent = 0x1e6a;
+ t.Tdotbelow = 0x1e6c;
+ t.Tecyrillic = 0x0422;
+ t.Tedescendercyrillic = 0x04ac;
+ t.Tenroman = 0x2169;
+ t.Tetsecyrillic = 0x04b4;
+ t.Theta = 0x0398;
+ t.Thook = 0x01ac;
+ t.Thorn = 0x00de;
+ t.Thornsmall = 0xf7fe;
+ t.Threeroman = 0x2162;
+ t.Tildesmall = 0xf6fe;
+ t.Tiwnarmenian = 0x054f;
+ t.Tlinebelow = 0x1e6e;
+ t.Tmonospace = 0xff34;
+ t.Toarmenian = 0x0539;
+ t.Tonefive = 0x01bc;
+ t.Tonesix = 0x0184;
+ t.Tonetwo = 0x01a7;
+ t.Tretroflexhook = 0x01ae;
+ t.Tsecyrillic = 0x0426;
+ t.Tshecyrillic = 0x040b;
+ t.Tsmall = 0xf774;
+ t.Twelveroman = 0x216b;
+ t.Tworoman = 0x2161;
+ t.U = 0x0055;
+ t.Uacute = 0x00da;
+ t.Uacutesmall = 0xf7fa;
+ t.Ubreve = 0x016c;
+ t.Ucaron = 0x01d3;
+ t.Ucircle = 0x24ca;
+ t.Ucircumflex = 0x00db;
+ t.Ucircumflexbelow = 0x1e76;
+ t.Ucircumflexsmall = 0xf7fb;
+ t.Ucyrillic = 0x0423;
+ t.Udblacute = 0x0170;
+ t.Udblgrave = 0x0214;
+ t.Udieresis = 0x00dc;
+ t.Udieresisacute = 0x01d7;
+ t.Udieresisbelow = 0x1e72;
+ t.Udieresiscaron = 0x01d9;
+ t.Udieresiscyrillic = 0x04f0;
+ t.Udieresisgrave = 0x01db;
+ t.Udieresismacron = 0x01d5;
+ t.Udieresissmall = 0xf7fc;
+ t.Udotbelow = 0x1ee4;
+ t.Ugrave = 0x00d9;
+ t.Ugravesmall = 0xf7f9;
+ t.Uhookabove = 0x1ee6;
+ t.Uhorn = 0x01af;
+ t.Uhornacute = 0x1ee8;
+ t.Uhorndotbelow = 0x1ef0;
+ t.Uhorngrave = 0x1eea;
+ t.Uhornhookabove = 0x1eec;
+ t.Uhorntilde = 0x1eee;
+ t.Uhungarumlaut = 0x0170;
+ t.Uhungarumlautcyrillic = 0x04f2;
+ t.Uinvertedbreve = 0x0216;
+ t.Ukcyrillic = 0x0478;
+ t.Umacron = 0x016a;
+ t.Umacroncyrillic = 0x04ee;
+ t.Umacrondieresis = 0x1e7a;
+ t.Umonospace = 0xff35;
+ t.Uogonek = 0x0172;
+ t.Upsilon = 0x03a5;
+ t.Upsilon1 = 0x03d2;
+ t.Upsilonacutehooksymbolgreek = 0x03d3;
+ t.Upsilonafrican = 0x01b1;
+ t.Upsilondieresis = 0x03ab;
+ t.Upsilondieresishooksymbolgreek = 0x03d4;
+ t.Upsilonhooksymbol = 0x03d2;
+ t.Upsilontonos = 0x038e;
+ t.Uring = 0x016e;
+ t.Ushortcyrillic = 0x040e;
+ t.Usmall = 0xf775;
+ t.Ustraightcyrillic = 0x04ae;
+ t.Ustraightstrokecyrillic = 0x04b0;
+ t.Utilde = 0x0168;
+ t.Utildeacute = 0x1e78;
+ t.Utildebelow = 0x1e74;
+ t.V = 0x0056;
+ t.Vcircle = 0x24cb;
+ t.Vdotbelow = 0x1e7e;
+ t.Vecyrillic = 0x0412;
+ t.Vewarmenian = 0x054e;
+ t.Vhook = 0x01b2;
+ t.Vmonospace = 0xff36;
+ t.Voarmenian = 0x0548;
+ t.Vsmall = 0xf776;
+ t.Vtilde = 0x1e7c;
+ t.W = 0x0057;
+ t.Wacute = 0x1e82;
+ t.Wcircle = 0x24cc;
+ t.Wcircumflex = 0x0174;
+ t.Wdieresis = 0x1e84;
+ t.Wdotaccent = 0x1e86;
+ t.Wdotbelow = 0x1e88;
+ t.Wgrave = 0x1e80;
+ t.Wmonospace = 0xff37;
+ t.Wsmall = 0xf777;
+ t.X = 0x0058;
+ t.Xcircle = 0x24cd;
+ t.Xdieresis = 0x1e8c;
+ t.Xdotaccent = 0x1e8a;
+ t.Xeharmenian = 0x053d;
+ t.Xi = 0x039e;
+ t.Xmonospace = 0xff38;
+ t.Xsmall = 0xf778;
+ t.Y = 0x0059;
+ t.Yacute = 0x00dd;
+ t.Yacutesmall = 0xf7fd;
+ t.Yatcyrillic = 0x0462;
+ t.Ycircle = 0x24ce;
+ t.Ycircumflex = 0x0176;
+ t.Ydieresis = 0x0178;
+ t.Ydieresissmall = 0xf7ff;
+ t.Ydotaccent = 0x1e8e;
+ t.Ydotbelow = 0x1ef4;
+ t.Yericyrillic = 0x042b;
+ t.Yerudieresiscyrillic = 0x04f8;
+ t.Ygrave = 0x1ef2;
+ t.Yhook = 0x01b3;
+ t.Yhookabove = 0x1ef6;
+ t.Yiarmenian = 0x0545;
+ t.Yicyrillic = 0x0407;
+ t.Yiwnarmenian = 0x0552;
+ t.Ymonospace = 0xff39;
+ t.Ysmall = 0xf779;
+ t.Ytilde = 0x1ef8;
+ t.Yusbigcyrillic = 0x046a;
+ t.Yusbigiotifiedcyrillic = 0x046c;
+ t.Yuslittlecyrillic = 0x0466;
+ t.Yuslittleiotifiedcyrillic = 0x0468;
+ t.Z = 0x005a;
+ t.Zaarmenian = 0x0536;
+ t.Zacute = 0x0179;
+ t.Zcaron = 0x017d;
+ t.Zcaronsmall = 0xf6ff;
+ t.Zcircle = 0x24cf;
+ t.Zcircumflex = 0x1e90;
+ t.Zdot = 0x017b;
+ t.Zdotaccent = 0x017b;
+ t.Zdotbelow = 0x1e92;
+ t.Zecyrillic = 0x0417;
+ t.Zedescendercyrillic = 0x0498;
+ t.Zedieresiscyrillic = 0x04de;
+ t.Zeta = 0x0396;
+ t.Zhearmenian = 0x053a;
+ t.Zhebrevecyrillic = 0x04c1;
+ t.Zhecyrillic = 0x0416;
+ t.Zhedescendercyrillic = 0x0496;
+ t.Zhedieresiscyrillic = 0x04dc;
+ t.Zlinebelow = 0x1e94;
+ t.Zmonospace = 0xff3a;
+ t.Zsmall = 0xf77a;
+ t.Zstroke = 0x01b5;
+ t.a = 0x0061;
+ t.aabengali = 0x0986;
+ t.aacute = 0x00e1;
+ t.aadeva = 0x0906;
+ t.aagujarati = 0x0a86;
+ t.aagurmukhi = 0x0a06;
+ t.aamatragurmukhi = 0x0a3e;
+ t.aarusquare = 0x3303;
+ t.aavowelsignbengali = 0x09be;
+ t.aavowelsigndeva = 0x093e;
+ t.aavowelsigngujarati = 0x0abe;
+ t.abbreviationmarkarmenian = 0x055f;
+ t.abbreviationsigndeva = 0x0970;
+ t.abengali = 0x0985;
+ t.abopomofo = 0x311a;
+ t.abreve = 0x0103;
+ t.abreveacute = 0x1eaf;
+ t.abrevecyrillic = 0x04d1;
+ t.abrevedotbelow = 0x1eb7;
+ t.abrevegrave = 0x1eb1;
+ t.abrevehookabove = 0x1eb3;
+ t.abrevetilde = 0x1eb5;
+ t.acaron = 0x01ce;
+ t.acircle = 0x24d0;
+ t.acircumflex = 0x00e2;
+ t.acircumflexacute = 0x1ea5;
+ t.acircumflexdotbelow = 0x1ead;
+ t.acircumflexgrave = 0x1ea7;
+ t.acircumflexhookabove = 0x1ea9;
+ t.acircumflextilde = 0x1eab;
+ t.acute = 0x00b4;
+ t.acutebelowcmb = 0x0317;
+ t.acutecmb = 0x0301;
+ t.acutecomb = 0x0301;
+ t.acutedeva = 0x0954;
+ t.acutelowmod = 0x02cf;
+ t.acutetonecmb = 0x0341;
+ t.acyrillic = 0x0430;
+ t.adblgrave = 0x0201;
+ t.addakgurmukhi = 0x0a71;
+ t.adeva = 0x0905;
+ t.adieresis = 0x00e4;
+ t.adieresiscyrillic = 0x04d3;
+ t.adieresismacron = 0x01df;
+ t.adotbelow = 0x1ea1;
+ t.adotmacron = 0x01e1;
+ t.ae = 0x00e6;
+ t.aeacute = 0x01fd;
+ t.aekorean = 0x3150;
+ t.aemacron = 0x01e3;
+ t.afii00208 = 0x2015;
+ t.afii08941 = 0x20a4;
+ t.afii10017 = 0x0410;
+ t.afii10018 = 0x0411;
+ t.afii10019 = 0x0412;
+ t.afii10020 = 0x0413;
+ t.afii10021 = 0x0414;
+ t.afii10022 = 0x0415;
+ t.afii10023 = 0x0401;
+ t.afii10024 = 0x0416;
+ t.afii10025 = 0x0417;
+ t.afii10026 = 0x0418;
+ t.afii10027 = 0x0419;
+ t.afii10028 = 0x041a;
+ t.afii10029 = 0x041b;
+ t.afii10030 = 0x041c;
+ t.afii10031 = 0x041d;
+ t.afii10032 = 0x041e;
+ t.afii10033 = 0x041f;
+ t.afii10034 = 0x0420;
+ t.afii10035 = 0x0421;
+ t.afii10036 = 0x0422;
+ t.afii10037 = 0x0423;
+ t.afii10038 = 0x0424;
+ t.afii10039 = 0x0425;
+ t.afii10040 = 0x0426;
+ t.afii10041 = 0x0427;
+ t.afii10042 = 0x0428;
+ t.afii10043 = 0x0429;
+ t.afii10044 = 0x042a;
+ t.afii10045 = 0x042b;
+ t.afii10046 = 0x042c;
+ t.afii10047 = 0x042d;
+ t.afii10048 = 0x042e;
+ t.afii10049 = 0x042f;
+ t.afii10050 = 0x0490;
+ t.afii10051 = 0x0402;
+ t.afii10052 = 0x0403;
+ t.afii10053 = 0x0404;
+ t.afii10054 = 0x0405;
+ t.afii10055 = 0x0406;
+ t.afii10056 = 0x0407;
+ t.afii10057 = 0x0408;
+ t.afii10058 = 0x0409;
+ t.afii10059 = 0x040a;
+ t.afii10060 = 0x040b;
+ t.afii10061 = 0x040c;
+ t.afii10062 = 0x040e;
+ t.afii10063 = 0xf6c4;
+ t.afii10064 = 0xf6c5;
+ t.afii10065 = 0x0430;
+ t.afii10066 = 0x0431;
+ t.afii10067 = 0x0432;
+ t.afii10068 = 0x0433;
+ t.afii10069 = 0x0434;
+ t.afii10070 = 0x0435;
+ t.afii10071 = 0x0451;
+ t.afii10072 = 0x0436;
+ t.afii10073 = 0x0437;
+ t.afii10074 = 0x0438;
+ t.afii10075 = 0x0439;
+ t.afii10076 = 0x043a;
+ t.afii10077 = 0x043b;
+ t.afii10078 = 0x043c;
+ t.afii10079 = 0x043d;
+ t.afii10080 = 0x043e;
+ t.afii10081 = 0x043f;
+ t.afii10082 = 0x0440;
+ t.afii10083 = 0x0441;
+ t.afii10084 = 0x0442;
+ t.afii10085 = 0x0443;
+ t.afii10086 = 0x0444;
+ t.afii10087 = 0x0445;
+ t.afii10088 = 0x0446;
+ t.afii10089 = 0x0447;
+ t.afii10090 = 0x0448;
+ t.afii10091 = 0x0449;
+ t.afii10092 = 0x044a;
+ t.afii10093 = 0x044b;
+ t.afii10094 = 0x044c;
+ t.afii10095 = 0x044d;
+ t.afii10096 = 0x044e;
+ t.afii10097 = 0x044f;
+ t.afii10098 = 0x0491;
+ t.afii10099 = 0x0452;
+ t.afii10100 = 0x0453;
+ t.afii10101 = 0x0454;
+ t.afii10102 = 0x0455;
+ t.afii10103 = 0x0456;
+ t.afii10104 = 0x0457;
+ t.afii10105 = 0x0458;
+ t.afii10106 = 0x0459;
+ t.afii10107 = 0x045a;
+ t.afii10108 = 0x045b;
+ t.afii10109 = 0x045c;
+ t.afii10110 = 0x045e;
+ t.afii10145 = 0x040f;
+ t.afii10146 = 0x0462;
+ t.afii10147 = 0x0472;
+ t.afii10148 = 0x0474;
+ t.afii10192 = 0xf6c6;
+ t.afii10193 = 0x045f;
+ t.afii10194 = 0x0463;
+ t.afii10195 = 0x0473;
+ t.afii10196 = 0x0475;
+ t.afii10831 = 0xf6c7;
+ t.afii10832 = 0xf6c8;
+ t.afii10846 = 0x04d9;
+ t.afii299 = 0x200e;
+ t.afii300 = 0x200f;
+ t.afii301 = 0x200d;
+ t.afii57381 = 0x066a;
+ t.afii57388 = 0x060c;
+ t.afii57392 = 0x0660;
+ t.afii57393 = 0x0661;
+ t.afii57394 = 0x0662;
+ t.afii57395 = 0x0663;
+ t.afii57396 = 0x0664;
+ t.afii57397 = 0x0665;
+ t.afii57398 = 0x0666;
+ t.afii57399 = 0x0667;
+ t.afii57400 = 0x0668;
+ t.afii57401 = 0x0669;
+ t.afii57403 = 0x061b;
+ t.afii57407 = 0x061f;
+ t.afii57409 = 0x0621;
+ t.afii57410 = 0x0622;
+ t.afii57411 = 0x0623;
+ t.afii57412 = 0x0624;
+ t.afii57413 = 0x0625;
+ t.afii57414 = 0x0626;
+ t.afii57415 = 0x0627;
+ t.afii57416 = 0x0628;
+ t.afii57417 = 0x0629;
+ t.afii57418 = 0x062a;
+ t.afii57419 = 0x062b;
+ t.afii57420 = 0x062c;
+ t.afii57421 = 0x062d;
+ t.afii57422 = 0x062e;
+ t.afii57423 = 0x062f;
+ t.afii57424 = 0x0630;
+ t.afii57425 = 0x0631;
+ t.afii57426 = 0x0632;
+ t.afii57427 = 0x0633;
+ t.afii57428 = 0x0634;
+ t.afii57429 = 0x0635;
+ t.afii57430 = 0x0636;
+ t.afii57431 = 0x0637;
+ t.afii57432 = 0x0638;
+ t.afii57433 = 0x0639;
+ t.afii57434 = 0x063a;
+ t.afii57440 = 0x0640;
+ t.afii57441 = 0x0641;
+ t.afii57442 = 0x0642;
+ t.afii57443 = 0x0643;
+ t.afii57444 = 0x0644;
+ t.afii57445 = 0x0645;
+ t.afii57446 = 0x0646;
+ t.afii57448 = 0x0648;
+ t.afii57449 = 0x0649;
+ t.afii57450 = 0x064a;
+ t.afii57451 = 0x064b;
+ t.afii57452 = 0x064c;
+ t.afii57453 = 0x064d;
+ t.afii57454 = 0x064e;
+ t.afii57455 = 0x064f;
+ t.afii57456 = 0x0650;
+ t.afii57457 = 0x0651;
+ t.afii57458 = 0x0652;
+ t.afii57470 = 0x0647;
+ t.afii57505 = 0x06a4;
+ t.afii57506 = 0x067e;
+ t.afii57507 = 0x0686;
+ t.afii57508 = 0x0698;
+ t.afii57509 = 0x06af;
+ t.afii57511 = 0x0679;
+ t.afii57512 = 0x0688;
+ t.afii57513 = 0x0691;
+ t.afii57514 = 0x06ba;
+ t.afii57519 = 0x06d2;
+ t.afii57534 = 0x06d5;
+ t.afii57636 = 0x20aa;
+ t.afii57645 = 0x05be;
+ t.afii57658 = 0x05c3;
+ t.afii57664 = 0x05d0;
+ t.afii57665 = 0x05d1;
+ t.afii57666 = 0x05d2;
+ t.afii57667 = 0x05d3;
+ t.afii57668 = 0x05d4;
+ t.afii57669 = 0x05d5;
+ t.afii57670 = 0x05d6;
+ t.afii57671 = 0x05d7;
+ t.afii57672 = 0x05d8;
+ t.afii57673 = 0x05d9;
+ t.afii57674 = 0x05da;
+ t.afii57675 = 0x05db;
+ t.afii57676 = 0x05dc;
+ t.afii57677 = 0x05dd;
+ t.afii57678 = 0x05de;
+ t.afii57679 = 0x05df;
+ t.afii57680 = 0x05e0;
+ t.afii57681 = 0x05e1;
+ t.afii57682 = 0x05e2;
+ t.afii57683 = 0x05e3;
+ t.afii57684 = 0x05e4;
+ t.afii57685 = 0x05e5;
+ t.afii57686 = 0x05e6;
+ t.afii57687 = 0x05e7;
+ t.afii57688 = 0x05e8;
+ t.afii57689 = 0x05e9;
+ t.afii57690 = 0x05ea;
+ t.afii57694 = 0xfb2a;
+ t.afii57695 = 0xfb2b;
+ t.afii57700 = 0xfb4b;
+ t.afii57705 = 0xfb1f;
+ t.afii57716 = 0x05f0;
+ t.afii57717 = 0x05f1;
+ t.afii57718 = 0x05f2;
+ t.afii57723 = 0xfb35;
+ t.afii57793 = 0x05b4;
+ t.afii57794 = 0x05b5;
+ t.afii57795 = 0x05b6;
+ t.afii57796 = 0x05bb;
+ t.afii57797 = 0x05b8;
+ t.afii57798 = 0x05b7;
+ t.afii57799 = 0x05b0;
+ t.afii57800 = 0x05b2;
+ t.afii57801 = 0x05b1;
+ t.afii57802 = 0x05b3;
+ t.afii57803 = 0x05c2;
+ t.afii57804 = 0x05c1;
+ t.afii57806 = 0x05b9;
+ t.afii57807 = 0x05bc;
+ t.afii57839 = 0x05bd;
+ t.afii57841 = 0x05bf;
+ t.afii57842 = 0x05c0;
+ t.afii57929 = 0x02bc;
+ t.afii61248 = 0x2105;
+ t.afii61289 = 0x2113;
+ t.afii61352 = 0x2116;
+ t.afii61573 = 0x202c;
+ t.afii61574 = 0x202d;
+ t.afii61575 = 0x202e;
+ t.afii61664 = 0x200c;
+ t.afii63167 = 0x066d;
+ t.afii64937 = 0x02bd;
+ t.agrave = 0x00e0;
+ t.agujarati = 0x0a85;
+ t.agurmukhi = 0x0a05;
+ t.ahiragana = 0x3042;
+ t.ahookabove = 0x1ea3;
+ t.aibengali = 0x0990;
+ t.aibopomofo = 0x311e;
+ t.aideva = 0x0910;
+ t.aiecyrillic = 0x04d5;
+ t.aigujarati = 0x0a90;
+ t.aigurmukhi = 0x0a10;
+ t.aimatragurmukhi = 0x0a48;
+ t.ainarabic = 0x0639;
+ t.ainfinalarabic = 0xfeca;
+ t.aininitialarabic = 0xfecb;
+ t.ainmedialarabic = 0xfecc;
+ t.ainvertedbreve = 0x0203;
+ t.aivowelsignbengali = 0x09c8;
+ t.aivowelsigndeva = 0x0948;
+ t.aivowelsigngujarati = 0x0ac8;
+ t.akatakana = 0x30a2;
+ t.akatakanahalfwidth = 0xff71;
+ t.akorean = 0x314f;
+ t.alef = 0x05d0;
+ t.alefarabic = 0x0627;
+ t.alefdageshhebrew = 0xfb30;
+ t.aleffinalarabic = 0xfe8e;
+ t.alefhamzaabovearabic = 0x0623;
+ t.alefhamzaabovefinalarabic = 0xfe84;
+ t.alefhamzabelowarabic = 0x0625;
+ t.alefhamzabelowfinalarabic = 0xfe88;
+ t.alefhebrew = 0x05d0;
+ t.aleflamedhebrew = 0xfb4f;
+ t.alefmaddaabovearabic = 0x0622;
+ t.alefmaddaabovefinalarabic = 0xfe82;
+ t.alefmaksuraarabic = 0x0649;
+ t.alefmaksurafinalarabic = 0xfef0;
+ t.alefmaksurainitialarabic = 0xfef3;
+ t.alefmaksuramedialarabic = 0xfef4;
+ t.alefpatahhebrew = 0xfb2e;
+ t.alefqamatshebrew = 0xfb2f;
+ t.aleph = 0x2135;
+ t.allequal = 0x224c;
+ t.alpha = 0x03b1;
+ t.alphatonos = 0x03ac;
+ t.amacron = 0x0101;
+ t.amonospace = 0xff41;
+ t.ampersand = 0x0026;
+ t.ampersandmonospace = 0xff06;
+ t.ampersandsmall = 0xf726;
+ t.amsquare = 0x33c2;
+ t.anbopomofo = 0x3122;
+ t.angbopomofo = 0x3124;
+ t.angbracketleft = 0x3008;
+ t.angbracketright = 0x3009;
+ t.angkhankhuthai = 0x0e5a;
+ t.angle = 0x2220;
+ t.anglebracketleft = 0x3008;
+ t.anglebracketleftvertical = 0xfe3f;
+ t.anglebracketright = 0x3009;
+ t.anglebracketrightvertical = 0xfe40;
+ t.angleleft = 0x2329;
+ t.angleright = 0x232a;
+ t.angstrom = 0x212b;
+ t.anoteleia = 0x0387;
+ t.anudattadeva = 0x0952;
+ t.anusvarabengali = 0x0982;
+ t.anusvaradeva = 0x0902;
+ t.anusvaragujarati = 0x0a82;
+ t.aogonek = 0x0105;
+ t.apaatosquare = 0x3300;
+ t.aparen = 0x249c;
+ t.apostrophearmenian = 0x055a;
+ t.apostrophemod = 0x02bc;
+ t.apple = 0xf8ff;
+ t.approaches = 0x2250;
+ t.approxequal = 0x2248;
+ t.approxequalorimage = 0x2252;
+ t.approximatelyequal = 0x2245;
+ t.araeaekorean = 0x318e;
+ t.araeakorean = 0x318d;
+ t.arc = 0x2312;
+ t.arighthalfring = 0x1e9a;
+ t.aring = 0x00e5;
+ t.aringacute = 0x01fb;
+ t.aringbelow = 0x1e01;
+ t.arrowboth = 0x2194;
+ t.arrowdashdown = 0x21e3;
+ t.arrowdashleft = 0x21e0;
+ t.arrowdashright = 0x21e2;
+ t.arrowdashup = 0x21e1;
+ t.arrowdblboth = 0x21d4;
+ t.arrowdbldown = 0x21d3;
+ t.arrowdblleft = 0x21d0;
+ t.arrowdblright = 0x21d2;
+ t.arrowdblup = 0x21d1;
+ t.arrowdown = 0x2193;
+ t.arrowdownleft = 0x2199;
+ t.arrowdownright = 0x2198;
+ t.arrowdownwhite = 0x21e9;
+ t.arrowheaddownmod = 0x02c5;
+ t.arrowheadleftmod = 0x02c2;
+ t.arrowheadrightmod = 0x02c3;
+ t.arrowheadupmod = 0x02c4;
+ t.arrowhorizex = 0xf8e7;
+ t.arrowleft = 0x2190;
+ t.arrowleftdbl = 0x21d0;
+ t.arrowleftdblstroke = 0x21cd;
+ t.arrowleftoverright = 0x21c6;
+ t.arrowleftwhite = 0x21e6;
+ t.arrowright = 0x2192;
+ t.arrowrightdblstroke = 0x21cf;
+ t.arrowrightheavy = 0x279e;
+ t.arrowrightoverleft = 0x21c4;
+ t.arrowrightwhite = 0x21e8;
+ t.arrowtableft = 0x21e4;
+ t.arrowtabright = 0x21e5;
+ t.arrowup = 0x2191;
+ t.arrowupdn = 0x2195;
+ t.arrowupdnbse = 0x21a8;
+ t.arrowupdownbase = 0x21a8;
+ t.arrowupleft = 0x2196;
+ t.arrowupleftofdown = 0x21c5;
+ t.arrowupright = 0x2197;
+ t.arrowupwhite = 0x21e7;
+ t.arrowvertex = 0xf8e6;
+ t.asciicircum = 0x005e;
+ t.asciicircummonospace = 0xff3e;
+ t.asciitilde = 0x007e;
+ t.asciitildemonospace = 0xff5e;
+ t.ascript = 0x0251;
+ t.ascriptturned = 0x0252;
+ t.asmallhiragana = 0x3041;
+ t.asmallkatakana = 0x30a1;
+ t.asmallkatakanahalfwidth = 0xff67;
+ t.asterisk = 0x002a;
+ t.asteriskaltonearabic = 0x066d;
+ t.asteriskarabic = 0x066d;
+ t.asteriskmath = 0x2217;
+ t.asteriskmonospace = 0xff0a;
+ t.asterisksmall = 0xfe61;
+ t.asterism = 0x2042;
+ t.asuperior = 0xf6e9;
+ t.asymptoticallyequal = 0x2243;
+ t.at = 0x0040;
+ t.atilde = 0x00e3;
+ t.atmonospace = 0xff20;
+ t.atsmall = 0xfe6b;
+ t.aturned = 0x0250;
+ t.aubengali = 0x0994;
+ t.aubopomofo = 0x3120;
+ t.audeva = 0x0914;
+ t.augujarati = 0x0a94;
+ t.augurmukhi = 0x0a14;
+ t.aulengthmarkbengali = 0x09d7;
+ t.aumatragurmukhi = 0x0a4c;
+ t.auvowelsignbengali = 0x09cc;
+ t.auvowelsigndeva = 0x094c;
+ t.auvowelsigngujarati = 0x0acc;
+ t.avagrahadeva = 0x093d;
+ t.aybarmenian = 0x0561;
+ t.ayin = 0x05e2;
+ t.ayinaltonehebrew = 0xfb20;
+ t.ayinhebrew = 0x05e2;
+ t.b = 0x0062;
+ t.babengali = 0x09ac;
+ t.backslash = 0x005c;
+ t.backslashmonospace = 0xff3c;
+ t.badeva = 0x092c;
+ t.bagujarati = 0x0aac;
+ t.bagurmukhi = 0x0a2c;
+ t.bahiragana = 0x3070;
+ t.bahtthai = 0x0e3f;
+ t.bakatakana = 0x30d0;
+ t.bar = 0x007c;
+ t.barmonospace = 0xff5c;
+ t.bbopomofo = 0x3105;
+ t.bcircle = 0x24d1;
+ t.bdotaccent = 0x1e03;
+ t.bdotbelow = 0x1e05;
+ t.beamedsixteenthnotes = 0x266c;
+ t.because = 0x2235;
+ t.becyrillic = 0x0431;
+ t.beharabic = 0x0628;
+ t.behfinalarabic = 0xfe90;
+ t.behinitialarabic = 0xfe91;
+ t.behiragana = 0x3079;
+ t.behmedialarabic = 0xfe92;
+ t.behmeeminitialarabic = 0xfc9f;
+ t.behmeemisolatedarabic = 0xfc08;
+ t.behnoonfinalarabic = 0xfc6d;
+ t.bekatakana = 0x30d9;
+ t.benarmenian = 0x0562;
+ t.bet = 0x05d1;
+ t.beta = 0x03b2;
+ t.betasymbolgreek = 0x03d0;
+ t.betdagesh = 0xfb31;
+ t.betdageshhebrew = 0xfb31;
+ t.bethebrew = 0x05d1;
+ t.betrafehebrew = 0xfb4c;
+ t.bhabengali = 0x09ad;
+ t.bhadeva = 0x092d;
+ t.bhagujarati = 0x0aad;
+ t.bhagurmukhi = 0x0a2d;
+ t.bhook = 0x0253;
+ t.bihiragana = 0x3073;
+ t.bikatakana = 0x30d3;
+ t.bilabialclick = 0x0298;
+ t.bindigurmukhi = 0x0a02;
+ t.birusquare = 0x3331;
+ t.blackcircle = 0x25cf;
+ t.blackdiamond = 0x25c6;
+ t.blackdownpointingtriangle = 0x25bc;
+ t.blackleftpointingpointer = 0x25c4;
+ t.blackleftpointingtriangle = 0x25c0;
+ t.blacklenticularbracketleft = 0x3010;
+ t.blacklenticularbracketleftvertical = 0xfe3b;
+ t.blacklenticularbracketright = 0x3011;
+ t.blacklenticularbracketrightvertical = 0xfe3c;
+ t.blacklowerlefttriangle = 0x25e3;
+ t.blacklowerrighttriangle = 0x25e2;
+ t.blackrectangle = 0x25ac;
+ t.blackrightpointingpointer = 0x25ba;
+ t.blackrightpointingtriangle = 0x25b6;
+ t.blacksmallsquare = 0x25aa;
+ t.blacksmilingface = 0x263b;
+ t.blacksquare = 0x25a0;
+ t.blackstar = 0x2605;
+ t.blackupperlefttriangle = 0x25e4;
+ t.blackupperrighttriangle = 0x25e5;
+ t.blackuppointingsmalltriangle = 0x25b4;
+ t.blackuppointingtriangle = 0x25b2;
+ t.blank = 0x2423;
+ t.blinebelow = 0x1e07;
+ t.block = 0x2588;
+ t.bmonospace = 0xff42;
+ t.bobaimaithai = 0x0e1a;
+ t.bohiragana = 0x307c;
+ t.bokatakana = 0x30dc;
+ t.bparen = 0x249d;
+ t.bqsquare = 0x33c3;
+ t.braceex = 0xf8f4;
+ t.braceleft = 0x007b;
+ t.braceleftbt = 0xf8f3;
+ t.braceleftmid = 0xf8f2;
+ t.braceleftmonospace = 0xff5b;
+ t.braceleftsmall = 0xfe5b;
+ t.bracelefttp = 0xf8f1;
+ t.braceleftvertical = 0xfe37;
+ t.braceright = 0x007d;
+ t.bracerightbt = 0xf8fe;
+ t.bracerightmid = 0xf8fd;
+ t.bracerightmonospace = 0xff5d;
+ t.bracerightsmall = 0xfe5c;
+ t.bracerighttp = 0xf8fc;
+ t.bracerightvertical = 0xfe38;
+ t.bracketleft = 0x005b;
+ t.bracketleftbt = 0xf8f0;
+ t.bracketleftex = 0xf8ef;
+ t.bracketleftmonospace = 0xff3b;
+ t.bracketlefttp = 0xf8ee;
+ t.bracketright = 0x005d;
+ t.bracketrightbt = 0xf8fb;
+ t.bracketrightex = 0xf8fa;
+ t.bracketrightmonospace = 0xff3d;
+ t.bracketrighttp = 0xf8f9;
+ t.breve = 0x02d8;
+ t.brevebelowcmb = 0x032e;
+ t.brevecmb = 0x0306;
+ t.breveinvertedbelowcmb = 0x032f;
+ t.breveinvertedcmb = 0x0311;
+ t.breveinverteddoublecmb = 0x0361;
+ t.bridgebelowcmb = 0x032a;
+ t.bridgeinvertedbelowcmb = 0x033a;
+ t.brokenbar = 0x00a6;
+ t.bstroke = 0x0180;
+ t.bsuperior = 0xf6ea;
+ t.btopbar = 0x0183;
+ t.buhiragana = 0x3076;
+ t.bukatakana = 0x30d6;
+ t.bullet = 0x2022;
+ t.bulletinverse = 0x25d8;
+ t.bulletoperator = 0x2219;
+ t.bullseye = 0x25ce;
+ t.c = 0x0063;
+ t.caarmenian = 0x056e;
+ t.cabengali = 0x099a;
+ t.cacute = 0x0107;
+ t.cadeva = 0x091a;
+ t.cagujarati = 0x0a9a;
+ t.cagurmukhi = 0x0a1a;
+ t.calsquare = 0x3388;
+ t.candrabindubengali = 0x0981;
+ t.candrabinducmb = 0x0310;
+ t.candrabindudeva = 0x0901;
+ t.candrabindugujarati = 0x0a81;
+ t.capslock = 0x21ea;
+ t.careof = 0x2105;
+ t.caron = 0x02c7;
+ t.caronbelowcmb = 0x032c;
+ t.caroncmb = 0x030c;
+ t.carriagereturn = 0x21b5;
+ t.cbopomofo = 0x3118;
+ t.ccaron = 0x010d;
+ t.ccedilla = 0x00e7;
+ t.ccedillaacute = 0x1e09;
+ t.ccircle = 0x24d2;
+ t.ccircumflex = 0x0109;
+ t.ccurl = 0x0255;
+ t.cdot = 0x010b;
+ t.cdotaccent = 0x010b;
+ t.cdsquare = 0x33c5;
+ t.cedilla = 0x00b8;
+ t.cedillacmb = 0x0327;
+ t.cent = 0x00a2;
+ t.centigrade = 0x2103;
+ t.centinferior = 0xf6df;
+ t.centmonospace = 0xffe0;
+ t.centoldstyle = 0xf7a2;
+ t.centsuperior = 0xf6e0;
+ t.chaarmenian = 0x0579;
+ t.chabengali = 0x099b;
+ t.chadeva = 0x091b;
+ t.chagujarati = 0x0a9b;
+ t.chagurmukhi = 0x0a1b;
+ t.chbopomofo = 0x3114;
+ t.cheabkhasiancyrillic = 0x04bd;
+ t.checkmark = 0x2713;
+ t.checyrillic = 0x0447;
+ t.chedescenderabkhasiancyrillic = 0x04bf;
+ t.chedescendercyrillic = 0x04b7;
+ t.chedieresiscyrillic = 0x04f5;
+ t.cheharmenian = 0x0573;
+ t.chekhakassiancyrillic = 0x04cc;
+ t.cheverticalstrokecyrillic = 0x04b9;
+ t.chi = 0x03c7;
+ t.chieuchacirclekorean = 0x3277;
+ t.chieuchaparenkorean = 0x3217;
+ t.chieuchcirclekorean = 0x3269;
+ t.chieuchkorean = 0x314a;
+ t.chieuchparenkorean = 0x3209;
+ t.chochangthai = 0x0e0a;
+ t.chochanthai = 0x0e08;
+ t.chochingthai = 0x0e09;
+ t.chochoethai = 0x0e0c;
+ t.chook = 0x0188;
+ t.cieucacirclekorean = 0x3276;
+ t.cieucaparenkorean = 0x3216;
+ t.cieuccirclekorean = 0x3268;
+ t.cieuckorean = 0x3148;
+ t.cieucparenkorean = 0x3208;
+ t.cieucuparenkorean = 0x321c;
+ t.circle = 0x25cb;
+ t.circlecopyrt = 0x00a9;
+ t.circlemultiply = 0x2297;
+ t.circleot = 0x2299;
+ t.circleplus = 0x2295;
+ t.circlepostalmark = 0x3036;
+ t.circlewithlefthalfblack = 0x25d0;
+ t.circlewithrighthalfblack = 0x25d1;
+ t.circumflex = 0x02c6;
+ t.circumflexbelowcmb = 0x032d;
+ t.circumflexcmb = 0x0302;
+ t.clear = 0x2327;
+ t.clickalveolar = 0x01c2;
+ t.clickdental = 0x01c0;
+ t.clicklateral = 0x01c1;
+ t.clickretroflex = 0x01c3;
+ t.club = 0x2663;
+ t.clubsuitblack = 0x2663;
+ t.clubsuitwhite = 0x2667;
+ t.cmcubedsquare = 0x33a4;
+ t.cmonospace = 0xff43;
+ t.cmsquaredsquare = 0x33a0;
+ t.coarmenian = 0x0581;
+ t.colon = 0x003a;
+ t.colonmonetary = 0x20a1;
+ t.colonmonospace = 0xff1a;
+ t.colonsign = 0x20a1;
+ t.colonsmall = 0xfe55;
+ t.colontriangularhalfmod = 0x02d1;
+ t.colontriangularmod = 0x02d0;
+ t.comma = 0x002c;
+ t.commaabovecmb = 0x0313;
+ t.commaaboverightcmb = 0x0315;
+ t.commaaccent = 0xf6c3;
+ t.commaarabic = 0x060c;
+ t.commaarmenian = 0x055d;
+ t.commainferior = 0xf6e1;
+ t.commamonospace = 0xff0c;
+ t.commareversedabovecmb = 0x0314;
+ t.commareversedmod = 0x02bd;
+ t.commasmall = 0xfe50;
+ t.commasuperior = 0xf6e2;
+ t.commaturnedabovecmb = 0x0312;
+ t.commaturnedmod = 0x02bb;
+ t.compass = 0x263c;
+ t.congruent = 0x2245;
+ t.contourintegral = 0x222e;
+ t.control = 0x2303;
+ t.controlACK = 0x0006;
+ t.controlBEL = 0x0007;
+ t.controlBS = 0x0008;
+ t.controlCAN = 0x0018;
+ t.controlCR = 0x000d;
+ t.controlDC1 = 0x0011;
+ t.controlDC2 = 0x0012;
+ t.controlDC3 = 0x0013;
+ t.controlDC4 = 0x0014;
+ t.controlDEL = 0x007f;
+ t.controlDLE = 0x0010;
+ t.controlEM = 0x0019;
+ t.controlENQ = 0x0005;
+ t.controlEOT = 0x0004;
+ t.controlESC = 0x001b;
+ t.controlETB = 0x0017;
+ t.controlETX = 0x0003;
+ t.controlFF = 0x000c;
+ t.controlFS = 0x001c;
+ t.controlGS = 0x001d;
+ t.controlHT = 0x0009;
+ t.controlLF = 0x000a;
+ t.controlNAK = 0x0015;
+ t.controlNULL = 0x0000;
+ t.controlRS = 0x001e;
+ t.controlSI = 0x000f;
+ t.controlSO = 0x000e;
+ t.controlSOT = 0x0002;
+ t.controlSTX = 0x0001;
+ t.controlSUB = 0x001a;
+ t.controlSYN = 0x0016;
+ t.controlUS = 0x001f;
+ t.controlVT = 0x000b;
+ t.copyright = 0x00a9;
+ t.copyrightsans = 0xf8e9;
+ t.copyrightserif = 0xf6d9;
+ t.cornerbracketleft = 0x300c;
+ t.cornerbracketlefthalfwidth = 0xff62;
+ t.cornerbracketleftvertical = 0xfe41;
+ t.cornerbracketright = 0x300d;
+ t.cornerbracketrighthalfwidth = 0xff63;
+ t.cornerbracketrightvertical = 0xfe42;
+ t.corporationsquare = 0x337f;
+ t.cosquare = 0x33c7;
+ t.coverkgsquare = 0x33c6;
+ t.cparen = 0x249e;
+ t.cruzeiro = 0x20a2;
+ t.cstretched = 0x0297;
+ t.curlyand = 0x22cf;
+ t.curlyor = 0x22ce;
+ t.currency = 0x00a4;
+ t.cyrBreve = 0xf6d1;
+ t.cyrFlex = 0xf6d2;
+ t.cyrbreve = 0xf6d4;
+ t.cyrflex = 0xf6d5;
+ t.d = 0x0064;
+ t.daarmenian = 0x0564;
+ t.dabengali = 0x09a6;
+ t.dadarabic = 0x0636;
+ t.dadeva = 0x0926;
+ t.dadfinalarabic = 0xfebe;
+ t.dadinitialarabic = 0xfebf;
+ t.dadmedialarabic = 0xfec0;
+ t.dagesh = 0x05bc;
+ t.dageshhebrew = 0x05bc;
+ t.dagger = 0x2020;
+ t.daggerdbl = 0x2021;
+ t.dagujarati = 0x0aa6;
+ t.dagurmukhi = 0x0a26;
+ t.dahiragana = 0x3060;
+ t.dakatakana = 0x30c0;
+ t.dalarabic = 0x062f;
+ t.dalet = 0x05d3;
+ t.daletdagesh = 0xfb33;
+ t.daletdageshhebrew = 0xfb33;
+ t.dalethebrew = 0x05d3;
+ t.dalfinalarabic = 0xfeaa;
+ t.dammaarabic = 0x064f;
+ t.dammalowarabic = 0x064f;
+ t.dammatanaltonearabic = 0x064c;
+ t.dammatanarabic = 0x064c;
+ t.danda = 0x0964;
+ t.dargahebrew = 0x05a7;
+ t.dargalefthebrew = 0x05a7;
+ t.dasiapneumatacyrilliccmb = 0x0485;
+ t.dblGrave = 0xf6d3;
+ t.dblanglebracketleft = 0x300a;
+ t.dblanglebracketleftvertical = 0xfe3d;
+ t.dblanglebracketright = 0x300b;
+ t.dblanglebracketrightvertical = 0xfe3e;
+ t.dblarchinvertedbelowcmb = 0x032b;
+ t.dblarrowleft = 0x21d4;
+ t.dblarrowright = 0x21d2;
+ t.dbldanda = 0x0965;
+ t.dblgrave = 0xf6d6;
+ t.dblgravecmb = 0x030f;
+ t.dblintegral = 0x222c;
+ t.dbllowline = 0x2017;
+ t.dbllowlinecmb = 0x0333;
+ t.dbloverlinecmb = 0x033f;
+ t.dblprimemod = 0x02ba;
+ t.dblverticalbar = 0x2016;
+ t.dblverticallineabovecmb = 0x030e;
+ t.dbopomofo = 0x3109;
+ t.dbsquare = 0x33c8;
+ t.dcaron = 0x010f;
+ t.dcedilla = 0x1e11;
+ t.dcircle = 0x24d3;
+ t.dcircumflexbelow = 0x1e13;
+ t.dcroat = 0x0111;
+ t.ddabengali = 0x09a1;
+ t.ddadeva = 0x0921;
+ t.ddagujarati = 0x0aa1;
+ t.ddagurmukhi = 0x0a21;
+ t.ddalarabic = 0x0688;
+ t.ddalfinalarabic = 0xfb89;
+ t.dddhadeva = 0x095c;
+ t.ddhabengali = 0x09a2;
+ t.ddhadeva = 0x0922;
+ t.ddhagujarati = 0x0aa2;
+ t.ddhagurmukhi = 0x0a22;
+ t.ddotaccent = 0x1e0b;
+ t.ddotbelow = 0x1e0d;
+ t.decimalseparatorarabic = 0x066b;
+ t.decimalseparatorpersian = 0x066b;
+ t.decyrillic = 0x0434;
+ t.degree = 0x00b0;
+ t.dehihebrew = 0x05ad;
+ t.dehiragana = 0x3067;
+ t.deicoptic = 0x03ef;
+ t.dekatakana = 0x30c7;
+ t.deleteleft = 0x232b;
+ t.deleteright = 0x2326;
+ t.delta = 0x03b4;
+ t.deltaturned = 0x018d;
+ t.denominatorminusonenumeratorbengali = 0x09f8;
+ t.dezh = 0x02a4;
+ t.dhabengali = 0x09a7;
+ t.dhadeva = 0x0927;
+ t.dhagujarati = 0x0aa7;
+ t.dhagurmukhi = 0x0a27;
+ t.dhook = 0x0257;
+ t.dialytikatonos = 0x0385;
+ t.dialytikatonoscmb = 0x0344;
+ t.diamond = 0x2666;
+ t.diamondsuitwhite = 0x2662;
+ t.dieresis = 0x00a8;
+ t.dieresisacute = 0xf6d7;
+ t.dieresisbelowcmb = 0x0324;
+ t.dieresiscmb = 0x0308;
+ t.dieresisgrave = 0xf6d8;
+ t.dieresistonos = 0x0385;
+ t.dihiragana = 0x3062;
+ t.dikatakana = 0x30c2;
+ t.dittomark = 0x3003;
+ t.divide = 0x00f7;
+ t.divides = 0x2223;
+ t.divisionslash = 0x2215;
+ t.djecyrillic = 0x0452;
+ t.dkshade = 0x2593;
+ t.dlinebelow = 0x1e0f;
+ t.dlsquare = 0x3397;
+ t.dmacron = 0x0111;
+ t.dmonospace = 0xff44;
+ t.dnblock = 0x2584;
+ t.dochadathai = 0x0e0e;
+ t.dodekthai = 0x0e14;
+ t.dohiragana = 0x3069;
+ t.dokatakana = 0x30c9;
+ t.dollar = 0x0024;
+ t.dollarinferior = 0xf6e3;
+ t.dollarmonospace = 0xff04;
+ t.dollaroldstyle = 0xf724;
+ t.dollarsmall = 0xfe69;
+ t.dollarsuperior = 0xf6e4;
+ t.dong = 0x20ab;
+ t.dorusquare = 0x3326;
+ t.dotaccent = 0x02d9;
+ t.dotaccentcmb = 0x0307;
+ t.dotbelowcmb = 0x0323;
+ t.dotbelowcomb = 0x0323;
+ t.dotkatakana = 0x30fb;
+ t.dotlessi = 0x0131;
+ t.dotlessj = 0xf6be;
+ t.dotlessjstrokehook = 0x0284;
+ t.dotmath = 0x22c5;
+ t.dottedcircle = 0x25cc;
+ t.doubleyodpatah = 0xfb1f;
+ t.doubleyodpatahhebrew = 0xfb1f;
+ t.downtackbelowcmb = 0x031e;
+ t.downtackmod = 0x02d5;
+ t.dparen = 0x249f;
+ t.dsuperior = 0xf6eb;
+ t.dtail = 0x0256;
+ t.dtopbar = 0x018c;
+ t.duhiragana = 0x3065;
+ t.dukatakana = 0x30c5;
+ t.dz = 0x01f3;
+ t.dzaltone = 0x02a3;
+ t.dzcaron = 0x01c6;
+ t.dzcurl = 0x02a5;
+ t.dzeabkhasiancyrillic = 0x04e1;
+ t.dzecyrillic = 0x0455;
+ t.dzhecyrillic = 0x045f;
+ t.e = 0x0065;
+ t.eacute = 0x00e9;
+ t.earth = 0x2641;
+ t.ebengali = 0x098f;
+ t.ebopomofo = 0x311c;
+ t.ebreve = 0x0115;
+ t.ecandradeva = 0x090d;
+ t.ecandragujarati = 0x0a8d;
+ t.ecandravowelsigndeva = 0x0945;
+ t.ecandravowelsigngujarati = 0x0ac5;
+ t.ecaron = 0x011b;
+ t.ecedillabreve = 0x1e1d;
+ t.echarmenian = 0x0565;
+ t.echyiwnarmenian = 0x0587;
+ t.ecircle = 0x24d4;
+ t.ecircumflex = 0x00ea;
+ t.ecircumflexacute = 0x1ebf;
+ t.ecircumflexbelow = 0x1e19;
+ t.ecircumflexdotbelow = 0x1ec7;
+ t.ecircumflexgrave = 0x1ec1;
+ t.ecircumflexhookabove = 0x1ec3;
+ t.ecircumflextilde = 0x1ec5;
+ t.ecyrillic = 0x0454;
+ t.edblgrave = 0x0205;
+ t.edeva = 0x090f;
+ t.edieresis = 0x00eb;
+ t.edot = 0x0117;
+ t.edotaccent = 0x0117;
+ t.edotbelow = 0x1eb9;
+ t.eegurmukhi = 0x0a0f;
+ t.eematragurmukhi = 0x0a47;
+ t.efcyrillic = 0x0444;
+ t.egrave = 0x00e8;
+ t.egujarati = 0x0a8f;
+ t.eharmenian = 0x0567;
+ t.ehbopomofo = 0x311d;
+ t.ehiragana = 0x3048;
+ t.ehookabove = 0x1ebb;
+ t.eibopomofo = 0x311f;
+ t.eight = 0x0038;
+ t.eightarabic = 0x0668;
+ t.eightbengali = 0x09ee;
+ t.eightcircle = 0x2467;
+ t.eightcircleinversesansserif = 0x2791;
+ t.eightdeva = 0x096e;
+ t.eighteencircle = 0x2471;
+ t.eighteenparen = 0x2485;
+ t.eighteenperiod = 0x2499;
+ t.eightgujarati = 0x0aee;
+ t.eightgurmukhi = 0x0a6e;
+ t.eighthackarabic = 0x0668;
+ t.eighthangzhou = 0x3028;
+ t.eighthnotebeamed = 0x266b;
+ t.eightideographicparen = 0x3227;
+ t.eightinferior = 0x2088;
+ t.eightmonospace = 0xff18;
+ t.eightoldstyle = 0xf738;
+ t.eightparen = 0x247b;
+ t.eightperiod = 0x248f;
+ t.eightpersian = 0x06f8;
+ t.eightroman = 0x2177;
+ t.eightsuperior = 0x2078;
+ t.eightthai = 0x0e58;
+ t.einvertedbreve = 0x0207;
+ t.eiotifiedcyrillic = 0x0465;
+ t.ekatakana = 0x30a8;
+ t.ekatakanahalfwidth = 0xff74;
+ t.ekonkargurmukhi = 0x0a74;
+ t.ekorean = 0x3154;
+ t.elcyrillic = 0x043b;
+ t.element = 0x2208;
+ t.elevencircle = 0x246a;
+ t.elevenparen = 0x247e;
+ t.elevenperiod = 0x2492;
+ t.elevenroman = 0x217a;
+ t.ellipsis = 0x2026;
+ t.ellipsisvertical = 0x22ee;
+ t.emacron = 0x0113;
+ t.emacronacute = 0x1e17;
+ t.emacrongrave = 0x1e15;
+ t.emcyrillic = 0x043c;
+ t.emdash = 0x2014;
+ t.emdashvertical = 0xfe31;
+ t.emonospace = 0xff45;
+ t.emphasismarkarmenian = 0x055b;
+ t.emptyset = 0x2205;
+ t.enbopomofo = 0x3123;
+ t.encyrillic = 0x043d;
+ t.endash = 0x2013;
+ t.endashvertical = 0xfe32;
+ t.endescendercyrillic = 0x04a3;
+ t.eng = 0x014b;
+ t.engbopomofo = 0x3125;
+ t.enghecyrillic = 0x04a5;
+ t.enhookcyrillic = 0x04c8;
+ t.enspace = 0x2002;
+ t.eogonek = 0x0119;
+ t.eokorean = 0x3153;
+ t.eopen = 0x025b;
+ t.eopenclosed = 0x029a;
+ t.eopenreversed = 0x025c;
+ t.eopenreversedclosed = 0x025e;
+ t.eopenreversedhook = 0x025d;
+ t.eparen = 0x24a0;
+ t.epsilon = 0x03b5;
+ t.epsilontonos = 0x03ad;
+ t.equal = 0x003d;
+ t.equalmonospace = 0xff1d;
+ t.equalsmall = 0xfe66;
+ t.equalsuperior = 0x207c;
+ t.equivalence = 0x2261;
+ t.erbopomofo = 0x3126;
+ t.ercyrillic = 0x0440;
+ t.ereversed = 0x0258;
+ t.ereversedcyrillic = 0x044d;
+ t.escyrillic = 0x0441;
+ t.esdescendercyrillic = 0x04ab;
+ t.esh = 0x0283;
+ t.eshcurl = 0x0286;
+ t.eshortdeva = 0x090e;
+ t.eshortvowelsigndeva = 0x0946;
+ t.eshreversedloop = 0x01aa;
+ t.eshsquatreversed = 0x0285;
+ t.esmallhiragana = 0x3047;
+ t.esmallkatakana = 0x30a7;
+ t.esmallkatakanahalfwidth = 0xff6a;
+ t.estimated = 0x212e;
+ t.esuperior = 0xf6ec;
+ t.eta = 0x03b7;
+ t.etarmenian = 0x0568;
+ t.etatonos = 0x03ae;
+ t.eth = 0x00f0;
+ t.etilde = 0x1ebd;
+ t.etildebelow = 0x1e1b;
+ t.etnahtafoukhhebrew = 0x0591;
+ t.etnahtafoukhlefthebrew = 0x0591;
+ t.etnahtahebrew = 0x0591;
+ t.etnahtalefthebrew = 0x0591;
+ t.eturned = 0x01dd;
+ t.eukorean = 0x3161;
+ t.euro = 0x20ac;
+ t.evowelsignbengali = 0x09c7;
+ t.evowelsigndeva = 0x0947;
+ t.evowelsigngujarati = 0x0ac7;
+ t.exclam = 0x0021;
+ t.exclamarmenian = 0x055c;
+ t.exclamdbl = 0x203c;
+ t.exclamdown = 0x00a1;
+ t.exclamdownsmall = 0xf7a1;
+ t.exclammonospace = 0xff01;
+ t.exclamsmall = 0xf721;
+ t.existential = 0x2203;
+ t.ezh = 0x0292;
+ t.ezhcaron = 0x01ef;
+ t.ezhcurl = 0x0293;
+ t.ezhreversed = 0x01b9;
+ t.ezhtail = 0x01ba;
+ t.f = 0x0066;
+ t.fadeva = 0x095e;
+ t.fagurmukhi = 0x0a5e;
+ t.fahrenheit = 0x2109;
+ t.fathaarabic = 0x064e;
+ t.fathalowarabic = 0x064e;
+ t.fathatanarabic = 0x064b;
+ t.fbopomofo = 0x3108;
+ t.fcircle = 0x24d5;
+ t.fdotaccent = 0x1e1f;
+ t.feharabic = 0x0641;
+ t.feharmenian = 0x0586;
+ t.fehfinalarabic = 0xfed2;
+ t.fehinitialarabic = 0xfed3;
+ t.fehmedialarabic = 0xfed4;
+ t.feicoptic = 0x03e5;
+ t.female = 0x2640;
+ t.ff = 0xfb00;
+ t.f_f = 0xfb00;
+ t.ffi = 0xfb03;
+ t.f_f_i = 0xfb03;
+ t.ffl = 0xfb04;
+ t.f_f_l = 0xfb04;
+ t.fi = 0xfb01;
+ t.f_i = 0xfb01;
+ t.fifteencircle = 0x246e;
+ t.fifteenparen = 0x2482;
+ t.fifteenperiod = 0x2496;
+ t.figuredash = 0x2012;
+ t.filledbox = 0x25a0;
+ t.filledrect = 0x25ac;
+ t.finalkaf = 0x05da;
+ t.finalkafdagesh = 0xfb3a;
+ t.finalkafdageshhebrew = 0xfb3a;
+ t.finalkafhebrew = 0x05da;
+ t.finalmem = 0x05dd;
+ t.finalmemhebrew = 0x05dd;
+ t.finalnun = 0x05df;
+ t.finalnunhebrew = 0x05df;
+ t.finalpe = 0x05e3;
+ t.finalpehebrew = 0x05e3;
+ t.finaltsadi = 0x05e5;
+ t.finaltsadihebrew = 0x05e5;
+ t.firsttonechinese = 0x02c9;
+ t.fisheye = 0x25c9;
+ t.fitacyrillic = 0x0473;
+ t.five = 0x0035;
+ t.fivearabic = 0x0665;
+ t.fivebengali = 0x09eb;
+ t.fivecircle = 0x2464;
+ t.fivecircleinversesansserif = 0x278e;
+ t.fivedeva = 0x096b;
+ t.fiveeighths = 0x215d;
+ t.fivegujarati = 0x0aeb;
+ t.fivegurmukhi = 0x0a6b;
+ t.fivehackarabic = 0x0665;
+ t.fivehangzhou = 0x3025;
+ t.fiveideographicparen = 0x3224;
+ t.fiveinferior = 0x2085;
+ t.fivemonospace = 0xff15;
+ t.fiveoldstyle = 0xf735;
+ t.fiveparen = 0x2478;
+ t.fiveperiod = 0x248c;
+ t.fivepersian = 0x06f5;
+ t.fiveroman = 0x2174;
+ t.fivesuperior = 0x2075;
+ t.fivethai = 0x0e55;
+ t.fl = 0xfb02;
+ t.f_l = 0xfb02;
+ t.florin = 0x0192;
+ t.fmonospace = 0xff46;
+ t.fmsquare = 0x3399;
+ t.fofanthai = 0x0e1f;
+ t.fofathai = 0x0e1d;
+ t.fongmanthai = 0x0e4f;
+ t.forall = 0x2200;
+ t.four = 0x0034;
+ t.fourarabic = 0x0664;
+ t.fourbengali = 0x09ea;
+ t.fourcircle = 0x2463;
+ t.fourcircleinversesansserif = 0x278d;
+ t.fourdeva = 0x096a;
+ t.fourgujarati = 0x0aea;
+ t.fourgurmukhi = 0x0a6a;
+ t.fourhackarabic = 0x0664;
+ t.fourhangzhou = 0x3024;
+ t.fourideographicparen = 0x3223;
+ t.fourinferior = 0x2084;
+ t.fourmonospace = 0xff14;
+ t.fournumeratorbengali = 0x09f7;
+ t.fouroldstyle = 0xf734;
+ t.fourparen = 0x2477;
+ t.fourperiod = 0x248b;
+ t.fourpersian = 0x06f4;
+ t.fourroman = 0x2173;
+ t.foursuperior = 0x2074;
+ t.fourteencircle = 0x246d;
+ t.fourteenparen = 0x2481;
+ t.fourteenperiod = 0x2495;
+ t.fourthai = 0x0e54;
+ t.fourthtonechinese = 0x02cb;
+ t.fparen = 0x24a1;
+ t.fraction = 0x2044;
+ t.franc = 0x20a3;
+ t.g = 0x0067;
+ t.gabengali = 0x0997;
+ t.gacute = 0x01f5;
+ t.gadeva = 0x0917;
+ t.gafarabic = 0x06af;
+ t.gaffinalarabic = 0xfb93;
+ t.gafinitialarabic = 0xfb94;
+ t.gafmedialarabic = 0xfb95;
+ t.gagujarati = 0x0a97;
+ t.gagurmukhi = 0x0a17;
+ t.gahiragana = 0x304c;
+ t.gakatakana = 0x30ac;
+ t.gamma = 0x03b3;
+ t.gammalatinsmall = 0x0263;
+ t.gammasuperior = 0x02e0;
+ t.gangiacoptic = 0x03eb;
+ t.gbopomofo = 0x310d;
+ t.gbreve = 0x011f;
+ t.gcaron = 0x01e7;
+ t.gcedilla = 0x0123;
+ t.gcircle = 0x24d6;
+ t.gcircumflex = 0x011d;
+ t.gcommaaccent = 0x0123;
+ t.gdot = 0x0121;
+ t.gdotaccent = 0x0121;
+ t.gecyrillic = 0x0433;
+ t.gehiragana = 0x3052;
+ t.gekatakana = 0x30b2;
+ t.geometricallyequal = 0x2251;
+ t.gereshaccenthebrew = 0x059c;
+ t.gereshhebrew = 0x05f3;
+ t.gereshmuqdamhebrew = 0x059d;
+ t.germandbls = 0x00df;
+ t.gershayimaccenthebrew = 0x059e;
+ t.gershayimhebrew = 0x05f4;
+ t.getamark = 0x3013;
+ t.ghabengali = 0x0998;
+ t.ghadarmenian = 0x0572;
+ t.ghadeva = 0x0918;
+ t.ghagujarati = 0x0a98;
+ t.ghagurmukhi = 0x0a18;
+ t.ghainarabic = 0x063a;
+ t.ghainfinalarabic = 0xfece;
+ t.ghaininitialarabic = 0xfecf;
+ t.ghainmedialarabic = 0xfed0;
+ t.ghemiddlehookcyrillic = 0x0495;
+ t.ghestrokecyrillic = 0x0493;
+ t.gheupturncyrillic = 0x0491;
+ t.ghhadeva = 0x095a;
+ t.ghhagurmukhi = 0x0a5a;
+ t.ghook = 0x0260;
+ t.ghzsquare = 0x3393;
+ t.gihiragana = 0x304e;
+ t.gikatakana = 0x30ae;
+ t.gimarmenian = 0x0563;
+ t.gimel = 0x05d2;
+ t.gimeldagesh = 0xfb32;
+ t.gimeldageshhebrew = 0xfb32;
+ t.gimelhebrew = 0x05d2;
+ t.gjecyrillic = 0x0453;
+ t.glottalinvertedstroke = 0x01be;
+ t.glottalstop = 0x0294;
+ t.glottalstopinverted = 0x0296;
+ t.glottalstopmod = 0x02c0;
+ t.glottalstopreversed = 0x0295;
+ t.glottalstopreversedmod = 0x02c1;
+ t.glottalstopreversedsuperior = 0x02e4;
+ t.glottalstopstroke = 0x02a1;
+ t.glottalstopstrokereversed = 0x02a2;
+ t.gmacron = 0x1e21;
+ t.gmonospace = 0xff47;
+ t.gohiragana = 0x3054;
+ t.gokatakana = 0x30b4;
+ t.gparen = 0x24a2;
+ t.gpasquare = 0x33ac;
+ t.gradient = 0x2207;
+ t.grave = 0x0060;
+ t.gravebelowcmb = 0x0316;
+ t.gravecmb = 0x0300;
+ t.gravecomb = 0x0300;
+ t.gravedeva = 0x0953;
+ t.gravelowmod = 0x02ce;
+ t.gravemonospace = 0xff40;
+ t.gravetonecmb = 0x0340;
+ t.greater = 0x003e;
+ t.greaterequal = 0x2265;
+ t.greaterequalorless = 0x22db;
+ t.greatermonospace = 0xff1e;
+ t.greaterorequivalent = 0x2273;
+ t.greaterorless = 0x2277;
+ t.greateroverequal = 0x2267;
+ t.greatersmall = 0xfe65;
+ t.gscript = 0x0261;
+ t.gstroke = 0x01e5;
+ t.guhiragana = 0x3050;
+ t.guillemotleft = 0x00ab;
+ t.guillemotright = 0x00bb;
+ t.guilsinglleft = 0x2039;
+ t.guilsinglright = 0x203a;
+ t.gukatakana = 0x30b0;
+ t.guramusquare = 0x3318;
+ t.gysquare = 0x33c9;
+ t.h = 0x0068;
+ t.haabkhasiancyrillic = 0x04a9;
+ t.haaltonearabic = 0x06c1;
+ t.habengali = 0x09b9;
+ t.hadescendercyrillic = 0x04b3;
+ t.hadeva = 0x0939;
+ t.hagujarati = 0x0ab9;
+ t.hagurmukhi = 0x0a39;
+ t.haharabic = 0x062d;
+ t.hahfinalarabic = 0xfea2;
+ t.hahinitialarabic = 0xfea3;
+ t.hahiragana = 0x306f;
+ t.hahmedialarabic = 0xfea4;
+ t.haitusquare = 0x332a;
+ t.hakatakana = 0x30cf;
+ t.hakatakanahalfwidth = 0xff8a;
+ t.halantgurmukhi = 0x0a4d;
+ t.hamzaarabic = 0x0621;
+ t.hamzalowarabic = 0x0621;
+ t.hangulfiller = 0x3164;
+ t.hardsigncyrillic = 0x044a;
+ t.harpoonleftbarbup = 0x21bc;
+ t.harpoonrightbarbup = 0x21c0;
+ t.hasquare = 0x33ca;
+ t.hatafpatah = 0x05b2;
+ t.hatafpatah16 = 0x05b2;
+ t.hatafpatah23 = 0x05b2;
+ t.hatafpatah2f = 0x05b2;
+ t.hatafpatahhebrew = 0x05b2;
+ t.hatafpatahnarrowhebrew = 0x05b2;
+ t.hatafpatahquarterhebrew = 0x05b2;
+ t.hatafpatahwidehebrew = 0x05b2;
+ t.hatafqamats = 0x05b3;
+ t.hatafqamats1b = 0x05b3;
+ t.hatafqamats28 = 0x05b3;
+ t.hatafqamats34 = 0x05b3;
+ t.hatafqamatshebrew = 0x05b3;
+ t.hatafqamatsnarrowhebrew = 0x05b3;
+ t.hatafqamatsquarterhebrew = 0x05b3;
+ t.hatafqamatswidehebrew = 0x05b3;
+ t.hatafsegol = 0x05b1;
+ t.hatafsegol17 = 0x05b1;
+ t.hatafsegol24 = 0x05b1;
+ t.hatafsegol30 = 0x05b1;
+ t.hatafsegolhebrew = 0x05b1;
+ t.hatafsegolnarrowhebrew = 0x05b1;
+ t.hatafsegolquarterhebrew = 0x05b1;
+ t.hatafsegolwidehebrew = 0x05b1;
+ t.hbar = 0x0127;
+ t.hbopomofo = 0x310f;
+ t.hbrevebelow = 0x1e2b;
+ t.hcedilla = 0x1e29;
+ t.hcircle = 0x24d7;
+ t.hcircumflex = 0x0125;
+ t.hdieresis = 0x1e27;
+ t.hdotaccent = 0x1e23;
+ t.hdotbelow = 0x1e25;
+ t.he = 0x05d4;
+ t.heart = 0x2665;
+ t.heartsuitblack = 0x2665;
+ t.heartsuitwhite = 0x2661;
+ t.hedagesh = 0xfb34;
+ t.hedageshhebrew = 0xfb34;
+ t.hehaltonearabic = 0x06c1;
+ t.heharabic = 0x0647;
+ t.hehebrew = 0x05d4;
+ t.hehfinalaltonearabic = 0xfba7;
+ t.hehfinalalttwoarabic = 0xfeea;
+ t.hehfinalarabic = 0xfeea;
+ t.hehhamzaabovefinalarabic = 0xfba5;
+ t.hehhamzaaboveisolatedarabic = 0xfba4;
+ t.hehinitialaltonearabic = 0xfba8;
+ t.hehinitialarabic = 0xfeeb;
+ t.hehiragana = 0x3078;
+ t.hehmedialaltonearabic = 0xfba9;
+ t.hehmedialarabic = 0xfeec;
+ t.heiseierasquare = 0x337b;
+ t.hekatakana = 0x30d8;
+ t.hekatakanahalfwidth = 0xff8d;
+ t.hekutaarusquare = 0x3336;
+ t.henghook = 0x0267;
+ t.herutusquare = 0x3339;
+ t.het = 0x05d7;
+ t.hethebrew = 0x05d7;
+ t.hhook = 0x0266;
+ t.hhooksuperior = 0x02b1;
+ t.hieuhacirclekorean = 0x327b;
+ t.hieuhaparenkorean = 0x321b;
+ t.hieuhcirclekorean = 0x326d;
+ t.hieuhkorean = 0x314e;
+ t.hieuhparenkorean = 0x320d;
+ t.hihiragana = 0x3072;
+ t.hikatakana = 0x30d2;
+ t.hikatakanahalfwidth = 0xff8b;
+ t.hiriq = 0x05b4;
+ t.hiriq14 = 0x05b4;
+ t.hiriq21 = 0x05b4;
+ t.hiriq2d = 0x05b4;
+ t.hiriqhebrew = 0x05b4;
+ t.hiriqnarrowhebrew = 0x05b4;
+ t.hiriqquarterhebrew = 0x05b4;
+ t.hiriqwidehebrew = 0x05b4;
+ t.hlinebelow = 0x1e96;
+ t.hmonospace = 0xff48;
+ t.hoarmenian = 0x0570;
+ t.hohipthai = 0x0e2b;
+ t.hohiragana = 0x307b;
+ t.hokatakana = 0x30db;
+ t.hokatakanahalfwidth = 0xff8e;
+ t.holam = 0x05b9;
+ t.holam19 = 0x05b9;
+ t.holam26 = 0x05b9;
+ t.holam32 = 0x05b9;
+ t.holamhebrew = 0x05b9;
+ t.holamnarrowhebrew = 0x05b9;
+ t.holamquarterhebrew = 0x05b9;
+ t.holamwidehebrew = 0x05b9;
+ t.honokhukthai = 0x0e2e;
+ t.hookabovecomb = 0x0309;
+ t.hookcmb = 0x0309;
+ t.hookpalatalizedbelowcmb = 0x0321;
+ t.hookretroflexbelowcmb = 0x0322;
+ t.hoonsquare = 0x3342;
+ t.horicoptic = 0x03e9;
+ t.horizontalbar = 0x2015;
+ t.horncmb = 0x031b;
+ t.hotsprings = 0x2668;
+ t.house = 0x2302;
+ t.hparen = 0x24a3;
+ t.hsuperior = 0x02b0;
+ t.hturned = 0x0265;
+ t.huhiragana = 0x3075;
+ t.huiitosquare = 0x3333;
+ t.hukatakana = 0x30d5;
+ t.hukatakanahalfwidth = 0xff8c;
+ t.hungarumlaut = 0x02dd;
+ t.hungarumlautcmb = 0x030b;
+ t.hv = 0x0195;
+ t.hyphen = 0x002d;
+ t.hypheninferior = 0xf6e5;
+ t.hyphenmonospace = 0xff0d;
+ t.hyphensmall = 0xfe63;
+ t.hyphensuperior = 0xf6e6;
+ t.hyphentwo = 0x2010;
+ t.i = 0x0069;
+ t.iacute = 0x00ed;
+ t.iacyrillic = 0x044f;
+ t.ibengali = 0x0987;
+ t.ibopomofo = 0x3127;
+ t.ibreve = 0x012d;
+ t.icaron = 0x01d0;
+ t.icircle = 0x24d8;
+ t.icircumflex = 0x00ee;
+ t.icyrillic = 0x0456;
+ t.idblgrave = 0x0209;
+ t.ideographearthcircle = 0x328f;
+ t.ideographfirecircle = 0x328b;
+ t.ideographicallianceparen = 0x323f;
+ t.ideographiccallparen = 0x323a;
+ t.ideographiccentrecircle = 0x32a5;
+ t.ideographicclose = 0x3006;
+ t.ideographiccomma = 0x3001;
+ t.ideographiccommaleft = 0xff64;
+ t.ideographiccongratulationparen = 0x3237;
+ t.ideographiccorrectcircle = 0x32a3;
+ t.ideographicearthparen = 0x322f;
+ t.ideographicenterpriseparen = 0x323d;
+ t.ideographicexcellentcircle = 0x329d;
+ t.ideographicfestivalparen = 0x3240;
+ t.ideographicfinancialcircle = 0x3296;
+ t.ideographicfinancialparen = 0x3236;
+ t.ideographicfireparen = 0x322b;
+ t.ideographichaveparen = 0x3232;
+ t.ideographichighcircle = 0x32a4;
+ t.ideographiciterationmark = 0x3005;
+ t.ideographiclaborcircle = 0x3298;
+ t.ideographiclaborparen = 0x3238;
+ t.ideographicleftcircle = 0x32a7;
+ t.ideographiclowcircle = 0x32a6;
+ t.ideographicmedicinecircle = 0x32a9;
+ t.ideographicmetalparen = 0x322e;
+ t.ideographicmoonparen = 0x322a;
+ t.ideographicnameparen = 0x3234;
+ t.ideographicperiod = 0x3002;
+ t.ideographicprintcircle = 0x329e;
+ t.ideographicreachparen = 0x3243;
+ t.ideographicrepresentparen = 0x3239;
+ t.ideographicresourceparen = 0x323e;
+ t.ideographicrightcircle = 0x32a8;
+ t.ideographicsecretcircle = 0x3299;
+ t.ideographicselfparen = 0x3242;
+ t.ideographicsocietyparen = 0x3233;
+ t.ideographicspace = 0x3000;
+ t.ideographicspecialparen = 0x3235;
+ t.ideographicstockparen = 0x3231;
+ t.ideographicstudyparen = 0x323b;
+ t.ideographicsunparen = 0x3230;
+ t.ideographicsuperviseparen = 0x323c;
+ t.ideographicwaterparen = 0x322c;
+ t.ideographicwoodparen = 0x322d;
+ t.ideographiczero = 0x3007;
+ t.ideographmetalcircle = 0x328e;
+ t.ideographmooncircle = 0x328a;
+ t.ideographnamecircle = 0x3294;
+ t.ideographsuncircle = 0x3290;
+ t.ideographwatercircle = 0x328c;
+ t.ideographwoodcircle = 0x328d;
+ t.ideva = 0x0907;
+ t.idieresis = 0x00ef;
+ t.idieresisacute = 0x1e2f;
+ t.idieresiscyrillic = 0x04e5;
+ t.idotbelow = 0x1ecb;
+ t.iebrevecyrillic = 0x04d7;
+ t.iecyrillic = 0x0435;
+ t.ieungacirclekorean = 0x3275;
+ t.ieungaparenkorean = 0x3215;
+ t.ieungcirclekorean = 0x3267;
+ t.ieungkorean = 0x3147;
+ t.ieungparenkorean = 0x3207;
+ t.igrave = 0x00ec;
+ t.igujarati = 0x0a87;
+ t.igurmukhi = 0x0a07;
+ t.ihiragana = 0x3044;
+ t.ihookabove = 0x1ec9;
+ t.iibengali = 0x0988;
+ t.iicyrillic = 0x0438;
+ t.iideva = 0x0908;
+ t.iigujarati = 0x0a88;
+ t.iigurmukhi = 0x0a08;
+ t.iimatragurmukhi = 0x0a40;
+ t.iinvertedbreve = 0x020b;
+ t.iishortcyrillic = 0x0439;
+ t.iivowelsignbengali = 0x09c0;
+ t.iivowelsigndeva = 0x0940;
+ t.iivowelsigngujarati = 0x0ac0;
+ t.ij = 0x0133;
+ t.ikatakana = 0x30a4;
+ t.ikatakanahalfwidth = 0xff72;
+ t.ikorean = 0x3163;
+ t.ilde = 0x02dc;
+ t.iluyhebrew = 0x05ac;
+ t.imacron = 0x012b;
+ t.imacroncyrillic = 0x04e3;
+ t.imageorapproximatelyequal = 0x2253;
+ t.imatragurmukhi = 0x0a3f;
+ t.imonospace = 0xff49;
+ t.increment = 0x2206;
+ t.infinity = 0x221e;
+ t.iniarmenian = 0x056b;
+ t.integral = 0x222b;
+ t.integralbottom = 0x2321;
+ t.integralbt = 0x2321;
+ t.integralex = 0xf8f5;
+ t.integraltop = 0x2320;
+ t.integraltp = 0x2320;
+ t.intersection = 0x2229;
+ t.intisquare = 0x3305;
+ t.invbullet = 0x25d8;
+ t.invcircle = 0x25d9;
+ t.invsmileface = 0x263b;
+ t.iocyrillic = 0x0451;
+ t.iogonek = 0x012f;
+ t.iota = 0x03b9;
+ t.iotadieresis = 0x03ca;
+ t.iotadieresistonos = 0x0390;
+ t.iotalatin = 0x0269;
+ t.iotatonos = 0x03af;
+ t.iparen = 0x24a4;
+ t.irigurmukhi = 0x0a72;
+ t.ismallhiragana = 0x3043;
+ t.ismallkatakana = 0x30a3;
+ t.ismallkatakanahalfwidth = 0xff68;
+ t.issharbengali = 0x09fa;
+ t.istroke = 0x0268;
+ t.isuperior = 0xf6ed;
+ t.iterationhiragana = 0x309d;
+ t.iterationkatakana = 0x30fd;
+ t.itilde = 0x0129;
+ t.itildebelow = 0x1e2d;
+ t.iubopomofo = 0x3129;
+ t.iucyrillic = 0x044e;
+ t.ivowelsignbengali = 0x09bf;
+ t.ivowelsigndeva = 0x093f;
+ t.ivowelsigngujarati = 0x0abf;
+ t.izhitsacyrillic = 0x0475;
+ t.izhitsadblgravecyrillic = 0x0477;
+ t.j = 0x006a;
+ t.jaarmenian = 0x0571;
+ t.jabengali = 0x099c;
+ t.jadeva = 0x091c;
+ t.jagujarati = 0x0a9c;
+ t.jagurmukhi = 0x0a1c;
+ t.jbopomofo = 0x3110;
+ t.jcaron = 0x01f0;
+ t.jcircle = 0x24d9;
+ t.jcircumflex = 0x0135;
+ t.jcrossedtail = 0x029d;
+ t.jdotlessstroke = 0x025f;
+ t.jecyrillic = 0x0458;
+ t.jeemarabic = 0x062c;
+ t.jeemfinalarabic = 0xfe9e;
+ t.jeeminitialarabic = 0xfe9f;
+ t.jeemmedialarabic = 0xfea0;
+ t.jeharabic = 0x0698;
+ t.jehfinalarabic = 0xfb8b;
+ t.jhabengali = 0x099d;
+ t.jhadeva = 0x091d;
+ t.jhagujarati = 0x0a9d;
+ t.jhagurmukhi = 0x0a1d;
+ t.jheharmenian = 0x057b;
+ t.jis = 0x3004;
+ t.jmonospace = 0xff4a;
+ t.jparen = 0x24a5;
+ t.jsuperior = 0x02b2;
+ t.k = 0x006b;
+ t.kabashkircyrillic = 0x04a1;
+ t.kabengali = 0x0995;
+ t.kacute = 0x1e31;
+ t.kacyrillic = 0x043a;
+ t.kadescendercyrillic = 0x049b;
+ t.kadeva = 0x0915;
+ t.kaf = 0x05db;
+ t.kafarabic = 0x0643;
+ t.kafdagesh = 0xfb3b;
+ t.kafdageshhebrew = 0xfb3b;
+ t.kaffinalarabic = 0xfeda;
+ t.kafhebrew = 0x05db;
+ t.kafinitialarabic = 0xfedb;
+ t.kafmedialarabic = 0xfedc;
+ t.kafrafehebrew = 0xfb4d;
+ t.kagujarati = 0x0a95;
+ t.kagurmukhi = 0x0a15;
+ t.kahiragana = 0x304b;
+ t.kahookcyrillic = 0x04c4;
+ t.kakatakana = 0x30ab;
+ t.kakatakanahalfwidth = 0xff76;
+ t.kappa = 0x03ba;
+ t.kappasymbolgreek = 0x03f0;
+ t.kapyeounmieumkorean = 0x3171;
+ t.kapyeounphieuphkorean = 0x3184;
+ t.kapyeounpieupkorean = 0x3178;
+ t.kapyeounssangpieupkorean = 0x3179;
+ t.karoriisquare = 0x330d;
+ t.kashidaautoarabic = 0x0640;
+ t.kashidaautonosidebearingarabic = 0x0640;
+ t.kasmallkatakana = 0x30f5;
+ t.kasquare = 0x3384;
+ t.kasraarabic = 0x0650;
+ t.kasratanarabic = 0x064d;
+ t.kastrokecyrillic = 0x049f;
+ t.katahiraprolongmarkhalfwidth = 0xff70;
+ t.kaverticalstrokecyrillic = 0x049d;
+ t.kbopomofo = 0x310e;
+ t.kcalsquare = 0x3389;
+ t.kcaron = 0x01e9;
+ t.kcedilla = 0x0137;
+ t.kcircle = 0x24da;
+ t.kcommaaccent = 0x0137;
+ t.kdotbelow = 0x1e33;
+ t.keharmenian = 0x0584;
+ t.kehiragana = 0x3051;
+ t.kekatakana = 0x30b1;
+ t.kekatakanahalfwidth = 0xff79;
+ t.kenarmenian = 0x056f;
+ t.kesmallkatakana = 0x30f6;
+ t.kgreenlandic = 0x0138;
+ t.khabengali = 0x0996;
+ t.khacyrillic = 0x0445;
+ t.khadeva = 0x0916;
+ t.khagujarati = 0x0a96;
+ t.khagurmukhi = 0x0a16;
+ t.khaharabic = 0x062e;
+ t.khahfinalarabic = 0xfea6;
+ t.khahinitialarabic = 0xfea7;
+ t.khahmedialarabic = 0xfea8;
+ t.kheicoptic = 0x03e7;
+ t.khhadeva = 0x0959;
+ t.khhagurmukhi = 0x0a59;
+ t.khieukhacirclekorean = 0x3278;
+ t.khieukhaparenkorean = 0x3218;
+ t.khieukhcirclekorean = 0x326a;
+ t.khieukhkorean = 0x314b;
+ t.khieukhparenkorean = 0x320a;
+ t.khokhaithai = 0x0e02;
+ t.khokhonthai = 0x0e05;
+ t.khokhuatthai = 0x0e03;
+ t.khokhwaithai = 0x0e04;
+ t.khomutthai = 0x0e5b;
+ t.khook = 0x0199;
+ t.khorakhangthai = 0x0e06;
+ t.khzsquare = 0x3391;
+ t.kihiragana = 0x304d;
+ t.kikatakana = 0x30ad;
+ t.kikatakanahalfwidth = 0xff77;
+ t.kiroguramusquare = 0x3315;
+ t.kiromeetorusquare = 0x3316;
+ t.kirosquare = 0x3314;
+ t.kiyeokacirclekorean = 0x326e;
+ t.kiyeokaparenkorean = 0x320e;
+ t.kiyeokcirclekorean = 0x3260;
+ t.kiyeokkorean = 0x3131;
+ t.kiyeokparenkorean = 0x3200;
+ t.kiyeoksioskorean = 0x3133;
+ t.kjecyrillic = 0x045c;
+ t.klinebelow = 0x1e35;
+ t.klsquare = 0x3398;
+ t.kmcubedsquare = 0x33a6;
+ t.kmonospace = 0xff4b;
+ t.kmsquaredsquare = 0x33a2;
+ t.kohiragana = 0x3053;
+ t.kohmsquare = 0x33c0;
+ t.kokaithai = 0x0e01;
+ t.kokatakana = 0x30b3;
+ t.kokatakanahalfwidth = 0xff7a;
+ t.kooposquare = 0x331e;
+ t.koppacyrillic = 0x0481;
+ t.koreanstandardsymbol = 0x327f;
+ t.koroniscmb = 0x0343;
+ t.kparen = 0x24a6;
+ t.kpasquare = 0x33aa;
+ t.ksicyrillic = 0x046f;
+ t.ktsquare = 0x33cf;
+ t.kturned = 0x029e;
+ t.kuhiragana = 0x304f;
+ t.kukatakana = 0x30af;
+ t.kukatakanahalfwidth = 0xff78;
+ t.kvsquare = 0x33b8;
+ t.kwsquare = 0x33be;
+ t.l = 0x006c;
+ t.labengali = 0x09b2;
+ t.lacute = 0x013a;
+ t.ladeva = 0x0932;
+ t.lagujarati = 0x0ab2;
+ t.lagurmukhi = 0x0a32;
+ t.lakkhangyaothai = 0x0e45;
+ t.lamaleffinalarabic = 0xfefc;
+ t.lamalefhamzaabovefinalarabic = 0xfef8;
+ t.lamalefhamzaaboveisolatedarabic = 0xfef7;
+ t.lamalefhamzabelowfinalarabic = 0xfefa;
+ t.lamalefhamzabelowisolatedarabic = 0xfef9;
+ t.lamalefisolatedarabic = 0xfefb;
+ t.lamalefmaddaabovefinalarabic = 0xfef6;
+ t.lamalefmaddaaboveisolatedarabic = 0xfef5;
+ t.lamarabic = 0x0644;
+ t.lambda = 0x03bb;
+ t.lambdastroke = 0x019b;
+ t.lamed = 0x05dc;
+ t.lameddagesh = 0xfb3c;
+ t.lameddageshhebrew = 0xfb3c;
+ t.lamedhebrew = 0x05dc;
+ t.lamfinalarabic = 0xfede;
+ t.lamhahinitialarabic = 0xfcca;
+ t.laminitialarabic = 0xfedf;
+ t.lamjeeminitialarabic = 0xfcc9;
+ t.lamkhahinitialarabic = 0xfccb;
+ t.lamlamhehisolatedarabic = 0xfdf2;
+ t.lammedialarabic = 0xfee0;
+ t.lammeemhahinitialarabic = 0xfd88;
+ t.lammeeminitialarabic = 0xfccc;
+ t.largecircle = 0x25ef;
+ t.lbar = 0x019a;
+ t.lbelt = 0x026c;
+ t.lbopomofo = 0x310c;
+ t.lcaron = 0x013e;
+ t.lcedilla = 0x013c;
+ t.lcircle = 0x24db;
+ t.lcircumflexbelow = 0x1e3d;
+ t.lcommaaccent = 0x013c;
+ t.ldot = 0x0140;
+ t.ldotaccent = 0x0140;
+ t.ldotbelow = 0x1e37;
+ t.ldotbelowmacron = 0x1e39;
+ t.leftangleabovecmb = 0x031a;
+ t.lefttackbelowcmb = 0x0318;
+ t.less = 0x003c;
+ t.lessequal = 0x2264;
+ t.lessequalorgreater = 0x22da;
+ t.lessmonospace = 0xff1c;
+ t.lessorequivalent = 0x2272;
+ t.lessorgreater = 0x2276;
+ t.lessoverequal = 0x2266;
+ t.lesssmall = 0xfe64;
+ t.lezh = 0x026e;
+ t.lfblock = 0x258c;
+ t.lhookretroflex = 0x026d;
+ t.lira = 0x20a4;
+ t.liwnarmenian = 0x056c;
+ t.lj = 0x01c9;
+ t.ljecyrillic = 0x0459;
+ t.ll = 0xf6c0;
+ t.lladeva = 0x0933;
+ t.llagujarati = 0x0ab3;
+ t.llinebelow = 0x1e3b;
+ t.llladeva = 0x0934;
+ t.llvocalicbengali = 0x09e1;
+ t.llvocalicdeva = 0x0961;
+ t.llvocalicvowelsignbengali = 0x09e3;
+ t.llvocalicvowelsigndeva = 0x0963;
+ t.lmiddletilde = 0x026b;
+ t.lmonospace = 0xff4c;
+ t.lmsquare = 0x33d0;
+ t.lochulathai = 0x0e2c;
+ t.logicaland = 0x2227;
+ t.logicalnot = 0x00ac;
+ t.logicalnotreversed = 0x2310;
+ t.logicalor = 0x2228;
+ t.lolingthai = 0x0e25;
+ t.longs = 0x017f;
+ t.lowlinecenterline = 0xfe4e;
+ t.lowlinecmb = 0x0332;
+ t.lowlinedashed = 0xfe4d;
+ t.lozenge = 0x25ca;
+ t.lparen = 0x24a7;
+ t.lslash = 0x0142;
+ t.lsquare = 0x2113;
+ t.lsuperior = 0xf6ee;
+ t.ltshade = 0x2591;
+ t.luthai = 0x0e26;
+ t.lvocalicbengali = 0x098c;
+ t.lvocalicdeva = 0x090c;
+ t.lvocalicvowelsignbengali = 0x09e2;
+ t.lvocalicvowelsigndeva = 0x0962;
+ t.lxsquare = 0x33d3;
+ t.m = 0x006d;
+ t.mabengali = 0x09ae;
+ t.macron = 0x00af;
+ t.macronbelowcmb = 0x0331;
+ t.macroncmb = 0x0304;
+ t.macronlowmod = 0x02cd;
+ t.macronmonospace = 0xffe3;
+ t.macute = 0x1e3f;
+ t.madeva = 0x092e;
+ t.magujarati = 0x0aae;
+ t.magurmukhi = 0x0a2e;
+ t.mahapakhhebrew = 0x05a4;
+ t.mahapakhlefthebrew = 0x05a4;
+ t.mahiragana = 0x307e;
+ t.maichattawalowleftthai = 0xf895;
+ t.maichattawalowrightthai = 0xf894;
+ t.maichattawathai = 0x0e4b;
+ t.maichattawaupperleftthai = 0xf893;
+ t.maieklowleftthai = 0xf88c;
+ t.maieklowrightthai = 0xf88b;
+ t.maiekthai = 0x0e48;
+ t.maiekupperleftthai = 0xf88a;
+ t.maihanakatleftthai = 0xf884;
+ t.maihanakatthai = 0x0e31;
+ t.maitaikhuleftthai = 0xf889;
+ t.maitaikhuthai = 0x0e47;
+ t.maitholowleftthai = 0xf88f;
+ t.maitholowrightthai = 0xf88e;
+ t.maithothai = 0x0e49;
+ t.maithoupperleftthai = 0xf88d;
+ t.maitrilowleftthai = 0xf892;
+ t.maitrilowrightthai = 0xf891;
+ t.maitrithai = 0x0e4a;
+ t.maitriupperleftthai = 0xf890;
+ t.maiyamokthai = 0x0e46;
+ t.makatakana = 0x30de;
+ t.makatakanahalfwidth = 0xff8f;
+ t.male = 0x2642;
+ t.mansyonsquare = 0x3347;
+ t.maqafhebrew = 0x05be;
+ t.mars = 0x2642;
+ t.masoracirclehebrew = 0x05af;
+ t.masquare = 0x3383;
+ t.mbopomofo = 0x3107;
+ t.mbsquare = 0x33d4;
+ t.mcircle = 0x24dc;
+ t.mcubedsquare = 0x33a5;
+ t.mdotaccent = 0x1e41;
+ t.mdotbelow = 0x1e43;
+ t.meemarabic = 0x0645;
+ t.meemfinalarabic = 0xfee2;
+ t.meeminitialarabic = 0xfee3;
+ t.meemmedialarabic = 0xfee4;
+ t.meemmeeminitialarabic = 0xfcd1;
+ t.meemmeemisolatedarabic = 0xfc48;
+ t.meetorusquare = 0x334d;
+ t.mehiragana = 0x3081;
+ t.meizierasquare = 0x337e;
+ t.mekatakana = 0x30e1;
+ t.mekatakanahalfwidth = 0xff92;
+ t.mem = 0x05de;
+ t.memdagesh = 0xfb3e;
+ t.memdageshhebrew = 0xfb3e;
+ t.memhebrew = 0x05de;
+ t.menarmenian = 0x0574;
+ t.merkhahebrew = 0x05a5;
+ t.merkhakefulahebrew = 0x05a6;
+ t.merkhakefulalefthebrew = 0x05a6;
+ t.merkhalefthebrew = 0x05a5;
+ t.mhook = 0x0271;
+ t.mhzsquare = 0x3392;
+ t.middledotkatakanahalfwidth = 0xff65;
+ t.middot = 0x00b7;
+ t.mieumacirclekorean = 0x3272;
+ t.mieumaparenkorean = 0x3212;
+ t.mieumcirclekorean = 0x3264;
+ t.mieumkorean = 0x3141;
+ t.mieumpansioskorean = 0x3170;
+ t.mieumparenkorean = 0x3204;
+ t.mieumpieupkorean = 0x316e;
+ t.mieumsioskorean = 0x316f;
+ t.mihiragana = 0x307f;
+ t.mikatakana = 0x30df;
+ t.mikatakanahalfwidth = 0xff90;
+ t.minus = 0x2212;
+ t.minusbelowcmb = 0x0320;
+ t.minuscircle = 0x2296;
+ t.minusmod = 0x02d7;
+ t.minusplus = 0x2213;
+ t.minute = 0x2032;
+ t.miribaarusquare = 0x334a;
+ t.mirisquare = 0x3349;
+ t.mlonglegturned = 0x0270;
+ t.mlsquare = 0x3396;
+ t.mmcubedsquare = 0x33a3;
+ t.mmonospace = 0xff4d;
+ t.mmsquaredsquare = 0x339f;
+ t.mohiragana = 0x3082;
+ t.mohmsquare = 0x33c1;
+ t.mokatakana = 0x30e2;
+ t.mokatakanahalfwidth = 0xff93;
+ t.molsquare = 0x33d6;
+ t.momathai = 0x0e21;
+ t.moverssquare = 0x33a7;
+ t.moverssquaredsquare = 0x33a8;
+ t.mparen = 0x24a8;
+ t.mpasquare = 0x33ab;
+ t.mssquare = 0x33b3;
+ t.msuperior = 0xf6ef;
+ t.mturned = 0x026f;
+ t.mu = 0x00b5;
+ t.mu1 = 0x00b5;
+ t.muasquare = 0x3382;
+ t.muchgreater = 0x226b;
+ t.muchless = 0x226a;
+ t.mufsquare = 0x338c;
+ t.mugreek = 0x03bc;
+ t.mugsquare = 0x338d;
+ t.muhiragana = 0x3080;
+ t.mukatakana = 0x30e0;
+ t.mukatakanahalfwidth = 0xff91;
+ t.mulsquare = 0x3395;
+ t.multiply = 0x00d7;
+ t.mumsquare = 0x339b;
+ t.munahhebrew = 0x05a3;
+ t.munahlefthebrew = 0x05a3;
+ t.musicalnote = 0x266a;
+ t.musicalnotedbl = 0x266b;
+ t.musicflatsign = 0x266d;
+ t.musicsharpsign = 0x266f;
+ t.mussquare = 0x33b2;
+ t.muvsquare = 0x33b6;
+ t.muwsquare = 0x33bc;
+ t.mvmegasquare = 0x33b9;
+ t.mvsquare = 0x33b7;
+ t.mwmegasquare = 0x33bf;
+ t.mwsquare = 0x33bd;
+ t.n = 0x006e;
+ t.nabengali = 0x09a8;
+ t.nabla = 0x2207;
+ t.nacute = 0x0144;
+ t.nadeva = 0x0928;
+ t.nagujarati = 0x0aa8;
+ t.nagurmukhi = 0x0a28;
+ t.nahiragana = 0x306a;
+ t.nakatakana = 0x30ca;
+ t.nakatakanahalfwidth = 0xff85;
+ t.napostrophe = 0x0149;
+ t.nasquare = 0x3381;
+ t.nbopomofo = 0x310b;
+ t.nbspace = 0x00a0;
+ t.ncaron = 0x0148;
+ t.ncedilla = 0x0146;
+ t.ncircle = 0x24dd;
+ t.ncircumflexbelow = 0x1e4b;
+ t.ncommaaccent = 0x0146;
+ t.ndotaccent = 0x1e45;
+ t.ndotbelow = 0x1e47;
+ t.nehiragana = 0x306d;
+ t.nekatakana = 0x30cd;
+ t.nekatakanahalfwidth = 0xff88;
+ t.newsheqelsign = 0x20aa;
+ t.nfsquare = 0x338b;
+ t.ngabengali = 0x0999;
+ t.ngadeva = 0x0919;
+ t.ngagujarati = 0x0a99;
+ t.ngagurmukhi = 0x0a19;
+ t.ngonguthai = 0x0e07;
+ t.nhiragana = 0x3093;
+ t.nhookleft = 0x0272;
+ t.nhookretroflex = 0x0273;
+ t.nieunacirclekorean = 0x326f;
+ t.nieunaparenkorean = 0x320f;
+ t.nieuncieuckorean = 0x3135;
+ t.nieuncirclekorean = 0x3261;
+ t.nieunhieuhkorean = 0x3136;
+ t.nieunkorean = 0x3134;
+ t.nieunpansioskorean = 0x3168;
+ t.nieunparenkorean = 0x3201;
+ t.nieunsioskorean = 0x3167;
+ t.nieuntikeutkorean = 0x3166;
+ t.nihiragana = 0x306b;
+ t.nikatakana = 0x30cb;
+ t.nikatakanahalfwidth = 0xff86;
+ t.nikhahitleftthai = 0xf899;
+ t.nikhahitthai = 0x0e4d;
+ t.nine = 0x0039;
+ t.ninearabic = 0x0669;
+ t.ninebengali = 0x09ef;
+ t.ninecircle = 0x2468;
+ t.ninecircleinversesansserif = 0x2792;
+ t.ninedeva = 0x096f;
+ t.ninegujarati = 0x0aef;
+ t.ninegurmukhi = 0x0a6f;
+ t.ninehackarabic = 0x0669;
+ t.ninehangzhou = 0x3029;
+ t.nineideographicparen = 0x3228;
+ t.nineinferior = 0x2089;
+ t.ninemonospace = 0xff19;
+ t.nineoldstyle = 0xf739;
+ t.nineparen = 0x247c;
+ t.nineperiod = 0x2490;
+ t.ninepersian = 0x06f9;
+ t.nineroman = 0x2178;
+ t.ninesuperior = 0x2079;
+ t.nineteencircle = 0x2472;
+ t.nineteenparen = 0x2486;
+ t.nineteenperiod = 0x249a;
+ t.ninethai = 0x0e59;
+ t.nj = 0x01cc;
+ t.njecyrillic = 0x045a;
+ t.nkatakana = 0x30f3;
+ t.nkatakanahalfwidth = 0xff9d;
+ t.nlegrightlong = 0x019e;
+ t.nlinebelow = 0x1e49;
+ t.nmonospace = 0xff4e;
+ t.nmsquare = 0x339a;
+ t.nnabengali = 0x09a3;
+ t.nnadeva = 0x0923;
+ t.nnagujarati = 0x0aa3;
+ t.nnagurmukhi = 0x0a23;
+ t.nnnadeva = 0x0929;
+ t.nohiragana = 0x306e;
+ t.nokatakana = 0x30ce;
+ t.nokatakanahalfwidth = 0xff89;
+ t.nonbreakingspace = 0x00a0;
+ t.nonenthai = 0x0e13;
+ t.nonuthai = 0x0e19;
+ t.noonarabic = 0x0646;
+ t.noonfinalarabic = 0xfee6;
+ t.noonghunnaarabic = 0x06ba;
+ t.noonghunnafinalarabic = 0xfb9f;
+ t.nooninitialarabic = 0xfee7;
+ t.noonjeeminitialarabic = 0xfcd2;
+ t.noonjeemisolatedarabic = 0xfc4b;
+ t.noonmedialarabic = 0xfee8;
+ t.noonmeeminitialarabic = 0xfcd5;
+ t.noonmeemisolatedarabic = 0xfc4e;
+ t.noonnoonfinalarabic = 0xfc8d;
+ t.notcontains = 0x220c;
+ t.notelement = 0x2209;
+ t.notelementof = 0x2209;
+ t.notequal = 0x2260;
+ t.notgreater = 0x226f;
+ t.notgreaternorequal = 0x2271;
+ t.notgreaternorless = 0x2279;
+ t.notidentical = 0x2262;
+ t.notless = 0x226e;
+ t.notlessnorequal = 0x2270;
+ t.notparallel = 0x2226;
+ t.notprecedes = 0x2280;
+ t.notsubset = 0x2284;
+ t.notsucceeds = 0x2281;
+ t.notsuperset = 0x2285;
+ t.nowarmenian = 0x0576;
+ t.nparen = 0x24a9;
+ t.nssquare = 0x33b1;
+ t.nsuperior = 0x207f;
+ t.ntilde = 0x00f1;
+ t.nu = 0x03bd;
+ t.nuhiragana = 0x306c;
+ t.nukatakana = 0x30cc;
+ t.nukatakanahalfwidth = 0xff87;
+ t.nuktabengali = 0x09bc;
+ t.nuktadeva = 0x093c;
+ t.nuktagujarati = 0x0abc;
+ t.nuktagurmukhi = 0x0a3c;
+ t.numbersign = 0x0023;
+ t.numbersignmonospace = 0xff03;
+ t.numbersignsmall = 0xfe5f;
+ t.numeralsigngreek = 0x0374;
+ t.numeralsignlowergreek = 0x0375;
+ t.numero = 0x2116;
+ t.nun = 0x05e0;
+ t.nundagesh = 0xfb40;
+ t.nundageshhebrew = 0xfb40;
+ t.nunhebrew = 0x05e0;
+ t.nvsquare = 0x33b5;
+ t.nwsquare = 0x33bb;
+ t.nyabengali = 0x099e;
+ t.nyadeva = 0x091e;
+ t.nyagujarati = 0x0a9e;
+ t.nyagurmukhi = 0x0a1e;
+ t.o = 0x006f;
+ t.oacute = 0x00f3;
+ t.oangthai = 0x0e2d;
+ t.obarred = 0x0275;
+ t.obarredcyrillic = 0x04e9;
+ t.obarreddieresiscyrillic = 0x04eb;
+ t.obengali = 0x0993;
+ t.obopomofo = 0x311b;
+ t.obreve = 0x014f;
+ t.ocandradeva = 0x0911;
+ t.ocandragujarati = 0x0a91;
+ t.ocandravowelsigndeva = 0x0949;
+ t.ocandravowelsigngujarati = 0x0ac9;
+ t.ocaron = 0x01d2;
+ t.ocircle = 0x24de;
+ t.ocircumflex = 0x00f4;
+ t.ocircumflexacute = 0x1ed1;
+ t.ocircumflexdotbelow = 0x1ed9;
+ t.ocircumflexgrave = 0x1ed3;
+ t.ocircumflexhookabove = 0x1ed5;
+ t.ocircumflextilde = 0x1ed7;
+ t.ocyrillic = 0x043e;
+ t.odblacute = 0x0151;
+ t.odblgrave = 0x020d;
+ t.odeva = 0x0913;
+ t.odieresis = 0x00f6;
+ t.odieresiscyrillic = 0x04e7;
+ t.odotbelow = 0x1ecd;
+ t.oe = 0x0153;
+ t.oekorean = 0x315a;
+ t.ogonek = 0x02db;
+ t.ogonekcmb = 0x0328;
+ t.ograve = 0x00f2;
+ t.ogujarati = 0x0a93;
+ t.oharmenian = 0x0585;
+ t.ohiragana = 0x304a;
+ t.ohookabove = 0x1ecf;
+ t.ohorn = 0x01a1;
+ t.ohornacute = 0x1edb;
+ t.ohorndotbelow = 0x1ee3;
+ t.ohorngrave = 0x1edd;
+ t.ohornhookabove = 0x1edf;
+ t.ohorntilde = 0x1ee1;
+ t.ohungarumlaut = 0x0151;
+ t.oi = 0x01a3;
+ t.oinvertedbreve = 0x020f;
+ t.okatakana = 0x30aa;
+ t.okatakanahalfwidth = 0xff75;
+ t.okorean = 0x3157;
+ t.olehebrew = 0x05ab;
+ t.omacron = 0x014d;
+ t.omacronacute = 0x1e53;
+ t.omacrongrave = 0x1e51;
+ t.omdeva = 0x0950;
+ t.omega = 0x03c9;
+ t.omega1 = 0x03d6;
+ t.omegacyrillic = 0x0461;
+ t.omegalatinclosed = 0x0277;
+ t.omegaroundcyrillic = 0x047b;
+ t.omegatitlocyrillic = 0x047d;
+ t.omegatonos = 0x03ce;
+ t.omgujarati = 0x0ad0;
+ t.omicron = 0x03bf;
+ t.omicrontonos = 0x03cc;
+ t.omonospace = 0xff4f;
+ t.one = 0x0031;
+ t.onearabic = 0x0661;
+ t.onebengali = 0x09e7;
+ t.onecircle = 0x2460;
+ t.onecircleinversesansserif = 0x278a;
+ t.onedeva = 0x0967;
+ t.onedotenleader = 0x2024;
+ t.oneeighth = 0x215b;
+ t.onefitted = 0xf6dc;
+ t.onegujarati = 0x0ae7;
+ t.onegurmukhi = 0x0a67;
+ t.onehackarabic = 0x0661;
+ t.onehalf = 0x00bd;
+ t.onehangzhou = 0x3021;
+ t.oneideographicparen = 0x3220;
+ t.oneinferior = 0x2081;
+ t.onemonospace = 0xff11;
+ t.onenumeratorbengali = 0x09f4;
+ t.oneoldstyle = 0xf731;
+ t.oneparen = 0x2474;
+ t.oneperiod = 0x2488;
+ t.onepersian = 0x06f1;
+ t.onequarter = 0x00bc;
+ t.oneroman = 0x2170;
+ t.onesuperior = 0x00b9;
+ t.onethai = 0x0e51;
+ t.onethird = 0x2153;
+ t.oogonek = 0x01eb;
+ t.oogonekmacron = 0x01ed;
+ t.oogurmukhi = 0x0a13;
+ t.oomatragurmukhi = 0x0a4b;
+ t.oopen = 0x0254;
+ t.oparen = 0x24aa;
+ t.openbullet = 0x25e6;
+ t.option = 0x2325;
+ t.ordfeminine = 0x00aa;
+ t.ordmasculine = 0x00ba;
+ t.orthogonal = 0x221f;
+ t.oshortdeva = 0x0912;
+ t.oshortvowelsigndeva = 0x094a;
+ t.oslash = 0x00f8;
+ t.oslashacute = 0x01ff;
+ t.osmallhiragana = 0x3049;
+ t.osmallkatakana = 0x30a9;
+ t.osmallkatakanahalfwidth = 0xff6b;
+ t.ostrokeacute = 0x01ff;
+ t.osuperior = 0xf6f0;
+ t.otcyrillic = 0x047f;
+ t.otilde = 0x00f5;
+ t.otildeacute = 0x1e4d;
+ t.otildedieresis = 0x1e4f;
+ t.oubopomofo = 0x3121;
+ t.overline = 0x203e;
+ t.overlinecenterline = 0xfe4a;
+ t.overlinecmb = 0x0305;
+ t.overlinedashed = 0xfe49;
+ t.overlinedblwavy = 0xfe4c;
+ t.overlinewavy = 0xfe4b;
+ t.overscore = 0x00af;
+ t.ovowelsignbengali = 0x09cb;
+ t.ovowelsigndeva = 0x094b;
+ t.ovowelsigngujarati = 0x0acb;
+ t.p = 0x0070;
+ t.paampssquare = 0x3380;
+ t.paasentosquare = 0x332b;
+ t.pabengali = 0x09aa;
+ t.pacute = 0x1e55;
+ t.padeva = 0x092a;
+ t.pagedown = 0x21df;
+ t.pageup = 0x21de;
+ t.pagujarati = 0x0aaa;
+ t.pagurmukhi = 0x0a2a;
+ t.pahiragana = 0x3071;
+ t.paiyannoithai = 0x0e2f;
+ t.pakatakana = 0x30d1;
+ t.palatalizationcyrilliccmb = 0x0484;
+ t.palochkacyrillic = 0x04c0;
+ t.pansioskorean = 0x317f;
+ t.paragraph = 0x00b6;
+ t.parallel = 0x2225;
+ t.parenleft = 0x0028;
+ t.parenleftaltonearabic = 0xfd3e;
+ t.parenleftbt = 0xf8ed;
+ t.parenleftex = 0xf8ec;
+ t.parenleftinferior = 0x208d;
+ t.parenleftmonospace = 0xff08;
+ t.parenleftsmall = 0xfe59;
+ t.parenleftsuperior = 0x207d;
+ t.parenlefttp = 0xf8eb;
+ t.parenleftvertical = 0xfe35;
+ t.parenright = 0x0029;
+ t.parenrightaltonearabic = 0xfd3f;
+ t.parenrightbt = 0xf8f8;
+ t.parenrightex = 0xf8f7;
+ t.parenrightinferior = 0x208e;
+ t.parenrightmonospace = 0xff09;
+ t.parenrightsmall = 0xfe5a;
+ t.parenrightsuperior = 0x207e;
+ t.parenrighttp = 0xf8f6;
+ t.parenrightvertical = 0xfe36;
+ t.partialdiff = 0x2202;
+ t.paseqhebrew = 0x05c0;
+ t.pashtahebrew = 0x0599;
+ t.pasquare = 0x33a9;
+ t.patah = 0x05b7;
+ t.patah11 = 0x05b7;
+ t.patah1d = 0x05b7;
+ t.patah2a = 0x05b7;
+ t.patahhebrew = 0x05b7;
+ t.patahnarrowhebrew = 0x05b7;
+ t.patahquarterhebrew = 0x05b7;
+ t.patahwidehebrew = 0x05b7;
+ t.pazerhebrew = 0x05a1;
+ t.pbopomofo = 0x3106;
+ t.pcircle = 0x24df;
+ t.pdotaccent = 0x1e57;
+ t.pe = 0x05e4;
+ t.pecyrillic = 0x043f;
+ t.pedagesh = 0xfb44;
+ t.pedageshhebrew = 0xfb44;
+ t.peezisquare = 0x333b;
+ t.pefinaldageshhebrew = 0xfb43;
+ t.peharabic = 0x067e;
+ t.peharmenian = 0x057a;
+ t.pehebrew = 0x05e4;
+ t.pehfinalarabic = 0xfb57;
+ t.pehinitialarabic = 0xfb58;
+ t.pehiragana = 0x307a;
+ t.pehmedialarabic = 0xfb59;
+ t.pekatakana = 0x30da;
+ t.pemiddlehookcyrillic = 0x04a7;
+ t.perafehebrew = 0xfb4e;
+ t.percent = 0x0025;
+ t.percentarabic = 0x066a;
+ t.percentmonospace = 0xff05;
+ t.percentsmall = 0xfe6a;
+ t.period = 0x002e;
+ t.periodarmenian = 0x0589;
+ t.periodcentered = 0x00b7;
+ t.periodhalfwidth = 0xff61;
+ t.periodinferior = 0xf6e7;
+ t.periodmonospace = 0xff0e;
+ t.periodsmall = 0xfe52;
+ t.periodsuperior = 0xf6e8;
+ t.perispomenigreekcmb = 0x0342;
+ t.perpendicular = 0x22a5;
+ t.perthousand = 0x2030;
+ t.peseta = 0x20a7;
+ t.pfsquare = 0x338a;
+ t.phabengali = 0x09ab;
+ t.phadeva = 0x092b;
+ t.phagujarati = 0x0aab;
+ t.phagurmukhi = 0x0a2b;
+ t.phi = 0x03c6;
+ t.phi1 = 0x03d5;
+ t.phieuphacirclekorean = 0x327a;
+ t.phieuphaparenkorean = 0x321a;
+ t.phieuphcirclekorean = 0x326c;
+ t.phieuphkorean = 0x314d;
+ t.phieuphparenkorean = 0x320c;
+ t.philatin = 0x0278;
+ t.phinthuthai = 0x0e3a;
+ t.phisymbolgreek = 0x03d5;
+ t.phook = 0x01a5;
+ t.phophanthai = 0x0e1e;
+ t.phophungthai = 0x0e1c;
+ t.phosamphaothai = 0x0e20;
+ t.pi = 0x03c0;
+ t.pieupacirclekorean = 0x3273;
+ t.pieupaparenkorean = 0x3213;
+ t.pieupcieuckorean = 0x3176;
+ t.pieupcirclekorean = 0x3265;
+ t.pieupkiyeokkorean = 0x3172;
+ t.pieupkorean = 0x3142;
+ t.pieupparenkorean = 0x3205;
+ t.pieupsioskiyeokkorean = 0x3174;
+ t.pieupsioskorean = 0x3144;
+ t.pieupsiostikeutkorean = 0x3175;
+ t.pieupthieuthkorean = 0x3177;
+ t.pieuptikeutkorean = 0x3173;
+ t.pihiragana = 0x3074;
+ t.pikatakana = 0x30d4;
+ t.pisymbolgreek = 0x03d6;
+ t.piwrarmenian = 0x0583;
+ t.planckover2pi = 0x210f;
+ t.planckover2pi1 = 0x210f;
+ t.plus = 0x002b;
+ t.plusbelowcmb = 0x031f;
+ t.pluscircle = 0x2295;
+ t.plusminus = 0x00b1;
+ t.plusmod = 0x02d6;
+ t.plusmonospace = 0xff0b;
+ t.plussmall = 0xfe62;
+ t.plussuperior = 0x207a;
+ t.pmonospace = 0xff50;
+ t.pmsquare = 0x33d8;
+ t.pohiragana = 0x307d;
+ t.pointingindexdownwhite = 0x261f;
+ t.pointingindexleftwhite = 0x261c;
+ t.pointingindexrightwhite = 0x261e;
+ t.pointingindexupwhite = 0x261d;
+ t.pokatakana = 0x30dd;
+ t.poplathai = 0x0e1b;
+ t.postalmark = 0x3012;
+ t.postalmarkface = 0x3020;
+ t.pparen = 0x24ab;
+ t.precedes = 0x227a;
+ t.prescription = 0x211e;
+ t.primemod = 0x02b9;
+ t.primereversed = 0x2035;
+ t.product = 0x220f;
+ t.projective = 0x2305;
+ t.prolongedkana = 0x30fc;
+ t.propellor = 0x2318;
+ t.propersubset = 0x2282;
+ t.propersuperset = 0x2283;
+ t.proportion = 0x2237;
+ t.proportional = 0x221d;
+ t.psi = 0x03c8;
+ t.psicyrillic = 0x0471;
+ t.psilipneumatacyrilliccmb = 0x0486;
+ t.pssquare = 0x33b0;
+ t.puhiragana = 0x3077;
+ t.pukatakana = 0x30d7;
+ t.pvsquare = 0x33b4;
+ t.pwsquare = 0x33ba;
+ t.q = 0x0071;
+ t.qadeva = 0x0958;
+ t.qadmahebrew = 0x05a8;
+ t.qafarabic = 0x0642;
+ t.qaffinalarabic = 0xfed6;
+ t.qafinitialarabic = 0xfed7;
+ t.qafmedialarabic = 0xfed8;
+ t.qamats = 0x05b8;
+ t.qamats10 = 0x05b8;
+ t.qamats1a = 0x05b8;
+ t.qamats1c = 0x05b8;
+ t.qamats27 = 0x05b8;
+ t.qamats29 = 0x05b8;
+ t.qamats33 = 0x05b8;
+ t.qamatsde = 0x05b8;
+ t.qamatshebrew = 0x05b8;
+ t.qamatsnarrowhebrew = 0x05b8;
+ t.qamatsqatanhebrew = 0x05b8;
+ t.qamatsqatannarrowhebrew = 0x05b8;
+ t.qamatsqatanquarterhebrew = 0x05b8;
+ t.qamatsqatanwidehebrew = 0x05b8;
+ t.qamatsquarterhebrew = 0x05b8;
+ t.qamatswidehebrew = 0x05b8;
+ t.qarneyparahebrew = 0x059f;
+ t.qbopomofo = 0x3111;
+ t.qcircle = 0x24e0;
+ t.qhook = 0x02a0;
+ t.qmonospace = 0xff51;
+ t.qof = 0x05e7;
+ t.qofdagesh = 0xfb47;
+ t.qofdageshhebrew = 0xfb47;
+ t.qofhebrew = 0x05e7;
+ t.qparen = 0x24ac;
+ t.quarternote = 0x2669;
+ t.qubuts = 0x05bb;
+ t.qubuts18 = 0x05bb;
+ t.qubuts25 = 0x05bb;
+ t.qubuts31 = 0x05bb;
+ t.qubutshebrew = 0x05bb;
+ t.qubutsnarrowhebrew = 0x05bb;
+ t.qubutsquarterhebrew = 0x05bb;
+ t.qubutswidehebrew = 0x05bb;
+ t.question = 0x003f;
+ t.questionarabic = 0x061f;
+ t.questionarmenian = 0x055e;
+ t.questiondown = 0x00bf;
+ t.questiondownsmall = 0xf7bf;
+ t.questiongreek = 0x037e;
+ t.questionmonospace = 0xff1f;
+ t.questionsmall = 0xf73f;
+ t.quotedbl = 0x0022;
+ t.quotedblbase = 0x201e;
+ t.quotedblleft = 0x201c;
+ t.quotedblmonospace = 0xff02;
+ t.quotedblprime = 0x301e;
+ t.quotedblprimereversed = 0x301d;
+ t.quotedblright = 0x201d;
+ t.quoteleft = 0x2018;
+ t.quoteleftreversed = 0x201b;
+ t.quotereversed = 0x201b;
+ t.quoteright = 0x2019;
+ t.quoterightn = 0x0149;
+ t.quotesinglbase = 0x201a;
+ t.quotesingle = 0x0027;
+ t.quotesinglemonospace = 0xff07;
+ t.r = 0x0072;
+ t.raarmenian = 0x057c;
+ t.rabengali = 0x09b0;
+ t.racute = 0x0155;
+ t.radeva = 0x0930;
+ t.radical = 0x221a;
+ t.radicalex = 0xf8e5;
+ t.radoverssquare = 0x33ae;
+ t.radoverssquaredsquare = 0x33af;
+ t.radsquare = 0x33ad;
+ t.rafe = 0x05bf;
+ t.rafehebrew = 0x05bf;
+ t.ragujarati = 0x0ab0;
+ t.ragurmukhi = 0x0a30;
+ t.rahiragana = 0x3089;
+ t.rakatakana = 0x30e9;
+ t.rakatakanahalfwidth = 0xff97;
+ t.ralowerdiagonalbengali = 0x09f1;
+ t.ramiddlediagonalbengali = 0x09f0;
+ t.ramshorn = 0x0264;
+ t.ratio = 0x2236;
+ t.rbopomofo = 0x3116;
+ t.rcaron = 0x0159;
+ t.rcedilla = 0x0157;
+ t.rcircle = 0x24e1;
+ t.rcommaaccent = 0x0157;
+ t.rdblgrave = 0x0211;
+ t.rdotaccent = 0x1e59;
+ t.rdotbelow = 0x1e5b;
+ t.rdotbelowmacron = 0x1e5d;
+ t.referencemark = 0x203b;
+ t.reflexsubset = 0x2286;
+ t.reflexsuperset = 0x2287;
+ t.registered = 0x00ae;
+ t.registersans = 0xf8e8;
+ t.registerserif = 0xf6da;
+ t.reharabic = 0x0631;
+ t.reharmenian = 0x0580;
+ t.rehfinalarabic = 0xfeae;
+ t.rehiragana = 0x308c;
+ t.rekatakana = 0x30ec;
+ t.rekatakanahalfwidth = 0xff9a;
+ t.resh = 0x05e8;
+ t.reshdageshhebrew = 0xfb48;
+ t.reshhebrew = 0x05e8;
+ t.reversedtilde = 0x223d;
+ t.reviahebrew = 0x0597;
+ t.reviamugrashhebrew = 0x0597;
+ t.revlogicalnot = 0x2310;
+ t.rfishhook = 0x027e;
+ t.rfishhookreversed = 0x027f;
+ t.rhabengali = 0x09dd;
+ t.rhadeva = 0x095d;
+ t.rho = 0x03c1;
+ t.rhook = 0x027d;
+ t.rhookturned = 0x027b;
+ t.rhookturnedsuperior = 0x02b5;
+ t.rhosymbolgreek = 0x03f1;
+ t.rhotichookmod = 0x02de;
+ t.rieulacirclekorean = 0x3271;
+ t.rieulaparenkorean = 0x3211;
+ t.rieulcirclekorean = 0x3263;
+ t.rieulhieuhkorean = 0x3140;
+ t.rieulkiyeokkorean = 0x313a;
+ t.rieulkiyeoksioskorean = 0x3169;
+ t.rieulkorean = 0x3139;
+ t.rieulmieumkorean = 0x313b;
+ t.rieulpansioskorean = 0x316c;
+ t.rieulparenkorean = 0x3203;
+ t.rieulphieuphkorean = 0x313f;
+ t.rieulpieupkorean = 0x313c;
+ t.rieulpieupsioskorean = 0x316b;
+ t.rieulsioskorean = 0x313d;
+ t.rieulthieuthkorean = 0x313e;
+ t.rieultikeutkorean = 0x316a;
+ t.rieulyeorinhieuhkorean = 0x316d;
+ t.rightangle = 0x221f;
+ t.righttackbelowcmb = 0x0319;
+ t.righttriangle = 0x22bf;
+ t.rihiragana = 0x308a;
+ t.rikatakana = 0x30ea;
+ t.rikatakanahalfwidth = 0xff98;
+ t.ring = 0x02da;
+ t.ringbelowcmb = 0x0325;
+ t.ringcmb = 0x030a;
+ t.ringhalfleft = 0x02bf;
+ t.ringhalfleftarmenian = 0x0559;
+ t.ringhalfleftbelowcmb = 0x031c;
+ t.ringhalfleftcentered = 0x02d3;
+ t.ringhalfright = 0x02be;
+ t.ringhalfrightbelowcmb = 0x0339;
+ t.ringhalfrightcentered = 0x02d2;
+ t.rinvertedbreve = 0x0213;
+ t.rittorusquare = 0x3351;
+ t.rlinebelow = 0x1e5f;
+ t.rlongleg = 0x027c;
+ t.rlonglegturned = 0x027a;
+ t.rmonospace = 0xff52;
+ t.rohiragana = 0x308d;
+ t.rokatakana = 0x30ed;
+ t.rokatakanahalfwidth = 0xff9b;
+ t.roruathai = 0x0e23;
+ t.rparen = 0x24ad;
+ t.rrabengali = 0x09dc;
+ t.rradeva = 0x0931;
+ t.rragurmukhi = 0x0a5c;
+ t.rreharabic = 0x0691;
+ t.rrehfinalarabic = 0xfb8d;
+ t.rrvocalicbengali = 0x09e0;
+ t.rrvocalicdeva = 0x0960;
+ t.rrvocalicgujarati = 0x0ae0;
+ t.rrvocalicvowelsignbengali = 0x09c4;
+ t.rrvocalicvowelsigndeva = 0x0944;
+ t.rrvocalicvowelsigngujarati = 0x0ac4;
+ t.rsuperior = 0xf6f1;
+ t.rtblock = 0x2590;
+ t.rturned = 0x0279;
+ t.rturnedsuperior = 0x02b4;
+ t.ruhiragana = 0x308b;
+ t.rukatakana = 0x30eb;
+ t.rukatakanahalfwidth = 0xff99;
+ t.rupeemarkbengali = 0x09f2;
+ t.rupeesignbengali = 0x09f3;
+ t.rupiah = 0xf6dd;
+ t.ruthai = 0x0e24;
+ t.rvocalicbengali = 0x098b;
+ t.rvocalicdeva = 0x090b;
+ t.rvocalicgujarati = 0x0a8b;
+ t.rvocalicvowelsignbengali = 0x09c3;
+ t.rvocalicvowelsigndeva = 0x0943;
+ t.rvocalicvowelsigngujarati = 0x0ac3;
+ t.s = 0x0073;
+ t.sabengali = 0x09b8;
+ t.sacute = 0x015b;
+ t.sacutedotaccent = 0x1e65;
+ t.sadarabic = 0x0635;
+ t.sadeva = 0x0938;
+ t.sadfinalarabic = 0xfeba;
+ t.sadinitialarabic = 0xfebb;
+ t.sadmedialarabic = 0xfebc;
+ t.sagujarati = 0x0ab8;
+ t.sagurmukhi = 0x0a38;
+ t.sahiragana = 0x3055;
+ t.sakatakana = 0x30b5;
+ t.sakatakanahalfwidth = 0xff7b;
+ t.sallallahoualayhewasallamarabic = 0xfdfa;
+ t.samekh = 0x05e1;
+ t.samekhdagesh = 0xfb41;
+ t.samekhdageshhebrew = 0xfb41;
+ t.samekhhebrew = 0x05e1;
+ t.saraaathai = 0x0e32;
+ t.saraaethai = 0x0e41;
+ t.saraaimaimalaithai = 0x0e44;
+ t.saraaimaimuanthai = 0x0e43;
+ t.saraamthai = 0x0e33;
+ t.saraathai = 0x0e30;
+ t.saraethai = 0x0e40;
+ t.saraiileftthai = 0xf886;
+ t.saraiithai = 0x0e35;
+ t.saraileftthai = 0xf885;
+ t.saraithai = 0x0e34;
+ t.saraothai = 0x0e42;
+ t.saraueeleftthai = 0xf888;
+ t.saraueethai = 0x0e37;
+ t.saraueleftthai = 0xf887;
+ t.sarauethai = 0x0e36;
+ t.sarauthai = 0x0e38;
+ t.sarauuthai = 0x0e39;
+ t.sbopomofo = 0x3119;
+ t.scaron = 0x0161;
+ t.scarondotaccent = 0x1e67;
+ t.scedilla = 0x015f;
+ t.schwa = 0x0259;
+ t.schwacyrillic = 0x04d9;
+ t.schwadieresiscyrillic = 0x04db;
+ t.schwahook = 0x025a;
+ t.scircle = 0x24e2;
+ t.scircumflex = 0x015d;
+ t.scommaaccent = 0x0219;
+ t.sdotaccent = 0x1e61;
+ t.sdotbelow = 0x1e63;
+ t.sdotbelowdotaccent = 0x1e69;
+ t.seagullbelowcmb = 0x033c;
+ t.second = 0x2033;
+ t.secondtonechinese = 0x02ca;
+ t.section = 0x00a7;
+ t.seenarabic = 0x0633;
+ t.seenfinalarabic = 0xfeb2;
+ t.seeninitialarabic = 0xfeb3;
+ t.seenmedialarabic = 0xfeb4;
+ t.segol = 0x05b6;
+ t.segol13 = 0x05b6;
+ t.segol1f = 0x05b6;
+ t.segol2c = 0x05b6;
+ t.segolhebrew = 0x05b6;
+ t.segolnarrowhebrew = 0x05b6;
+ t.segolquarterhebrew = 0x05b6;
+ t.segoltahebrew = 0x0592;
+ t.segolwidehebrew = 0x05b6;
+ t.seharmenian = 0x057d;
+ t.sehiragana = 0x305b;
+ t.sekatakana = 0x30bb;
+ t.sekatakanahalfwidth = 0xff7e;
+ t.semicolon = 0x003b;
+ t.semicolonarabic = 0x061b;
+ t.semicolonmonospace = 0xff1b;
+ t.semicolonsmall = 0xfe54;
+ t.semivoicedmarkkana = 0x309c;
+ t.semivoicedmarkkanahalfwidth = 0xff9f;
+ t.sentisquare = 0x3322;
+ t.sentosquare = 0x3323;
+ t.seven = 0x0037;
+ t.sevenarabic = 0x0667;
+ t.sevenbengali = 0x09ed;
+ t.sevencircle = 0x2466;
+ t.sevencircleinversesansserif = 0x2790;
+ t.sevendeva = 0x096d;
+ t.seveneighths = 0x215e;
+ t.sevengujarati = 0x0aed;
+ t.sevengurmukhi = 0x0a6d;
+ t.sevenhackarabic = 0x0667;
+ t.sevenhangzhou = 0x3027;
+ t.sevenideographicparen = 0x3226;
+ t.seveninferior = 0x2087;
+ t.sevenmonospace = 0xff17;
+ t.sevenoldstyle = 0xf737;
+ t.sevenparen = 0x247a;
+ t.sevenperiod = 0x248e;
+ t.sevenpersian = 0x06f7;
+ t.sevenroman = 0x2176;
+ t.sevensuperior = 0x2077;
+ t.seventeencircle = 0x2470;
+ t.seventeenparen = 0x2484;
+ t.seventeenperiod = 0x2498;
+ t.seventhai = 0x0e57;
+ t.sfthyphen = 0x00ad;
+ t.shaarmenian = 0x0577;
+ t.shabengali = 0x09b6;
+ t.shacyrillic = 0x0448;
+ t.shaddaarabic = 0x0651;
+ t.shaddadammaarabic = 0xfc61;
+ t.shaddadammatanarabic = 0xfc5e;
+ t.shaddafathaarabic = 0xfc60;
+ t.shaddakasraarabic = 0xfc62;
+ t.shaddakasratanarabic = 0xfc5f;
+ t.shade = 0x2592;
+ t.shadedark = 0x2593;
+ t.shadelight = 0x2591;
+ t.shademedium = 0x2592;
+ t.shadeva = 0x0936;
+ t.shagujarati = 0x0ab6;
+ t.shagurmukhi = 0x0a36;
+ t.shalshelethebrew = 0x0593;
+ t.shbopomofo = 0x3115;
+ t.shchacyrillic = 0x0449;
+ t.sheenarabic = 0x0634;
+ t.sheenfinalarabic = 0xfeb6;
+ t.sheeninitialarabic = 0xfeb7;
+ t.sheenmedialarabic = 0xfeb8;
+ t.sheicoptic = 0x03e3;
+ t.sheqel = 0x20aa;
+ t.sheqelhebrew = 0x20aa;
+ t.sheva = 0x05b0;
+ t.sheva115 = 0x05b0;
+ t.sheva15 = 0x05b0;
+ t.sheva22 = 0x05b0;
+ t.sheva2e = 0x05b0;
+ t.shevahebrew = 0x05b0;
+ t.shevanarrowhebrew = 0x05b0;
+ t.shevaquarterhebrew = 0x05b0;
+ t.shevawidehebrew = 0x05b0;
+ t.shhacyrillic = 0x04bb;
+ t.shimacoptic = 0x03ed;
+ t.shin = 0x05e9;
+ t.shindagesh = 0xfb49;
+ t.shindageshhebrew = 0xfb49;
+ t.shindageshshindot = 0xfb2c;
+ t.shindageshshindothebrew = 0xfb2c;
+ t.shindageshsindot = 0xfb2d;
+ t.shindageshsindothebrew = 0xfb2d;
+ t.shindothebrew = 0x05c1;
+ t.shinhebrew = 0x05e9;
+ t.shinshindot = 0xfb2a;
+ t.shinshindothebrew = 0xfb2a;
+ t.shinsindot = 0xfb2b;
+ t.shinsindothebrew = 0xfb2b;
+ t.shook = 0x0282;
+ t.sigma = 0x03c3;
+ t.sigma1 = 0x03c2;
+ t.sigmafinal = 0x03c2;
+ t.sigmalunatesymbolgreek = 0x03f2;
+ t.sihiragana = 0x3057;
+ t.sikatakana = 0x30b7;
+ t.sikatakanahalfwidth = 0xff7c;
+ t.siluqhebrew = 0x05bd;
+ t.siluqlefthebrew = 0x05bd;
+ t.similar = 0x223c;
+ t.sindothebrew = 0x05c2;
+ t.siosacirclekorean = 0x3274;
+ t.siosaparenkorean = 0x3214;
+ t.sioscieuckorean = 0x317e;
+ t.sioscirclekorean = 0x3266;
+ t.sioskiyeokkorean = 0x317a;
+ t.sioskorean = 0x3145;
+ t.siosnieunkorean = 0x317b;
+ t.siosparenkorean = 0x3206;
+ t.siospieupkorean = 0x317d;
+ t.siostikeutkorean = 0x317c;
+ t.six = 0x0036;
+ t.sixarabic = 0x0666;
+ t.sixbengali = 0x09ec;
+ t.sixcircle = 0x2465;
+ t.sixcircleinversesansserif = 0x278f;
+ t.sixdeva = 0x096c;
+ t.sixgujarati = 0x0aec;
+ t.sixgurmukhi = 0x0a6c;
+ t.sixhackarabic = 0x0666;
+ t.sixhangzhou = 0x3026;
+ t.sixideographicparen = 0x3225;
+ t.sixinferior = 0x2086;
+ t.sixmonospace = 0xff16;
+ t.sixoldstyle = 0xf736;
+ t.sixparen = 0x2479;
+ t.sixperiod = 0x248d;
+ t.sixpersian = 0x06f6;
+ t.sixroman = 0x2175;
+ t.sixsuperior = 0x2076;
+ t.sixteencircle = 0x246f;
+ t.sixteencurrencydenominatorbengali = 0x09f9;
+ t.sixteenparen = 0x2483;
+ t.sixteenperiod = 0x2497;
+ t.sixthai = 0x0e56;
+ t.slash = 0x002f;
+ t.slashmonospace = 0xff0f;
+ t.slong = 0x017f;
+ t.slongdotaccent = 0x1e9b;
+ t.smileface = 0x263a;
+ t.smonospace = 0xff53;
+ t.sofpasuqhebrew = 0x05c3;
+ t.softhyphen = 0x00ad;
+ t.softsigncyrillic = 0x044c;
+ t.sohiragana = 0x305d;
+ t.sokatakana = 0x30bd;
+ t.sokatakanahalfwidth = 0xff7f;
+ t.soliduslongoverlaycmb = 0x0338;
+ t.solidusshortoverlaycmb = 0x0337;
+ t.sorusithai = 0x0e29;
+ t.sosalathai = 0x0e28;
+ t.sosothai = 0x0e0b;
+ t.sosuathai = 0x0e2a;
+ t.space = 0x0020;
+ t.spacehackarabic = 0x0020;
+ t.spade = 0x2660;
+ t.spadesuitblack = 0x2660;
+ t.spadesuitwhite = 0x2664;
+ t.sparen = 0x24ae;
+ t.squarebelowcmb = 0x033b;
+ t.squarecc = 0x33c4;
+ t.squarecm = 0x339d;
+ t.squarediagonalcrosshatchfill = 0x25a9;
+ t.squarehorizontalfill = 0x25a4;
+ t.squarekg = 0x338f;
+ t.squarekm = 0x339e;
+ t.squarekmcapital = 0x33ce;
+ t.squareln = 0x33d1;
+ t.squarelog = 0x33d2;
+ t.squaremg = 0x338e;
+ t.squaremil = 0x33d5;
+ t.squaremm = 0x339c;
+ t.squaremsquared = 0x33a1;
+ t.squareorthogonalcrosshatchfill = 0x25a6;
+ t.squareupperlefttolowerrightfill = 0x25a7;
+ t.squareupperrighttolowerleftfill = 0x25a8;
+ t.squareverticalfill = 0x25a5;
+ t.squarewhitewithsmallblack = 0x25a3;
+ t.srsquare = 0x33db;
+ t.ssabengali = 0x09b7;
+ t.ssadeva = 0x0937;
+ t.ssagujarati = 0x0ab7;
+ t.ssangcieuckorean = 0x3149;
+ t.ssanghieuhkorean = 0x3185;
+ t.ssangieungkorean = 0x3180;
+ t.ssangkiyeokkorean = 0x3132;
+ t.ssangnieunkorean = 0x3165;
+ t.ssangpieupkorean = 0x3143;
+ t.ssangsioskorean = 0x3146;
+ t.ssangtikeutkorean = 0x3138;
+ t.ssuperior = 0xf6f2;
+ t.sterling = 0x00a3;
+ t.sterlingmonospace = 0xffe1;
+ t.strokelongoverlaycmb = 0x0336;
+ t.strokeshortoverlaycmb = 0x0335;
+ t.subset = 0x2282;
+ t.subsetnotequal = 0x228a;
+ t.subsetorequal = 0x2286;
+ t.succeeds = 0x227b;
+ t.suchthat = 0x220b;
+ t.suhiragana = 0x3059;
+ t.sukatakana = 0x30b9;
+ t.sukatakanahalfwidth = 0xff7d;
+ t.sukunarabic = 0x0652;
+ t.summation = 0x2211;
+ t.sun = 0x263c;
+ t.superset = 0x2283;
+ t.supersetnotequal = 0x228b;
+ t.supersetorequal = 0x2287;
+ t.svsquare = 0x33dc;
+ t.syouwaerasquare = 0x337c;
+ t.t = 0x0074;
+ t.tabengali = 0x09a4;
+ t.tackdown = 0x22a4;
+ t.tackleft = 0x22a3;
+ t.tadeva = 0x0924;
+ t.tagujarati = 0x0aa4;
+ t.tagurmukhi = 0x0a24;
+ t.taharabic = 0x0637;
+ t.tahfinalarabic = 0xfec2;
+ t.tahinitialarabic = 0xfec3;
+ t.tahiragana = 0x305f;
+ t.tahmedialarabic = 0xfec4;
+ t.taisyouerasquare = 0x337d;
+ t.takatakana = 0x30bf;
+ t.takatakanahalfwidth = 0xff80;
+ t.tatweelarabic = 0x0640;
+ t.tau = 0x03c4;
+ t.tav = 0x05ea;
+ t.tavdages = 0xfb4a;
+ t.tavdagesh = 0xfb4a;
+ t.tavdageshhebrew = 0xfb4a;
+ t.tavhebrew = 0x05ea;
+ t.tbar = 0x0167;
+ t.tbopomofo = 0x310a;
+ t.tcaron = 0x0165;
+ t.tccurl = 0x02a8;
+ t.tcedilla = 0x0163;
+ t.tcheharabic = 0x0686;
+ t.tchehfinalarabic = 0xfb7b;
+ t.tchehinitialarabic = 0xfb7c;
+ t.tchehmedialarabic = 0xfb7d;
+ t.tcircle = 0x24e3;
+ t.tcircumflexbelow = 0x1e71;
+ t.tcommaaccent = 0x0163;
+ t.tdieresis = 0x1e97;
+ t.tdotaccent = 0x1e6b;
+ t.tdotbelow = 0x1e6d;
+ t.tecyrillic = 0x0442;
+ t.tedescendercyrillic = 0x04ad;
+ t.teharabic = 0x062a;
+ t.tehfinalarabic = 0xfe96;
+ t.tehhahinitialarabic = 0xfca2;
+ t.tehhahisolatedarabic = 0xfc0c;
+ t.tehinitialarabic = 0xfe97;
+ t.tehiragana = 0x3066;
+ t.tehjeeminitialarabic = 0xfca1;
+ t.tehjeemisolatedarabic = 0xfc0b;
+ t.tehmarbutaarabic = 0x0629;
+ t.tehmarbutafinalarabic = 0xfe94;
+ t.tehmedialarabic = 0xfe98;
+ t.tehmeeminitialarabic = 0xfca4;
+ t.tehmeemisolatedarabic = 0xfc0e;
+ t.tehnoonfinalarabic = 0xfc73;
+ t.tekatakana = 0x30c6;
+ t.tekatakanahalfwidth = 0xff83;
+ t.telephone = 0x2121;
+ t.telephoneblack = 0x260e;
+ t.telishagedolahebrew = 0x05a0;
+ t.telishaqetanahebrew = 0x05a9;
+ t.tencircle = 0x2469;
+ t.tenideographicparen = 0x3229;
+ t.tenparen = 0x247d;
+ t.tenperiod = 0x2491;
+ t.tenroman = 0x2179;
+ t.tesh = 0x02a7;
+ t.tet = 0x05d8;
+ t.tetdagesh = 0xfb38;
+ t.tetdageshhebrew = 0xfb38;
+ t.tethebrew = 0x05d8;
+ t.tetsecyrillic = 0x04b5;
+ t.tevirhebrew = 0x059b;
+ t.tevirlefthebrew = 0x059b;
+ t.thabengali = 0x09a5;
+ t.thadeva = 0x0925;
+ t.thagujarati = 0x0aa5;
+ t.thagurmukhi = 0x0a25;
+ t.thalarabic = 0x0630;
+ t.thalfinalarabic = 0xfeac;
+ t.thanthakhatlowleftthai = 0xf898;
+ t.thanthakhatlowrightthai = 0xf897;
+ t.thanthakhatthai = 0x0e4c;
+ t.thanthakhatupperleftthai = 0xf896;
+ t.theharabic = 0x062b;
+ t.thehfinalarabic = 0xfe9a;
+ t.thehinitialarabic = 0xfe9b;
+ t.thehmedialarabic = 0xfe9c;
+ t.thereexists = 0x2203;
+ t.therefore = 0x2234;
+ t.theta = 0x03b8;
+ t.theta1 = 0x03d1;
+ t.thetasymbolgreek = 0x03d1;
+ t.thieuthacirclekorean = 0x3279;
+ t.thieuthaparenkorean = 0x3219;
+ t.thieuthcirclekorean = 0x326b;
+ t.thieuthkorean = 0x314c;
+ t.thieuthparenkorean = 0x320b;
+ t.thirteencircle = 0x246c;
+ t.thirteenparen = 0x2480;
+ t.thirteenperiod = 0x2494;
+ t.thonangmonthothai = 0x0e11;
+ t.thook = 0x01ad;
+ t.thophuthaothai = 0x0e12;
+ t.thorn = 0x00fe;
+ t.thothahanthai = 0x0e17;
+ t.thothanthai = 0x0e10;
+ t.thothongthai = 0x0e18;
+ t.thothungthai = 0x0e16;
+ t.thousandcyrillic = 0x0482;
+ t.thousandsseparatorarabic = 0x066c;
+ t.thousandsseparatorpersian = 0x066c;
+ t.three = 0x0033;
+ t.threearabic = 0x0663;
+ t.threebengali = 0x09e9;
+ t.threecircle = 0x2462;
+ t.threecircleinversesansserif = 0x278c;
+ t.threedeva = 0x0969;
+ t.threeeighths = 0x215c;
+ t.threegujarati = 0x0ae9;
+ t.threegurmukhi = 0x0a69;
+ t.threehackarabic = 0x0663;
+ t.threehangzhou = 0x3023;
+ t.threeideographicparen = 0x3222;
+ t.threeinferior = 0x2083;
+ t.threemonospace = 0xff13;
+ t.threenumeratorbengali = 0x09f6;
+ t.threeoldstyle = 0xf733;
+ t.threeparen = 0x2476;
+ t.threeperiod = 0x248a;
+ t.threepersian = 0x06f3;
+ t.threequarters = 0x00be;
+ t.threequartersemdash = 0xf6de;
+ t.threeroman = 0x2172;
+ t.threesuperior = 0x00b3;
+ t.threethai = 0x0e53;
+ t.thzsquare = 0x3394;
+ t.tihiragana = 0x3061;
+ t.tikatakana = 0x30c1;
+ t.tikatakanahalfwidth = 0xff81;
+ t.tikeutacirclekorean = 0x3270;
+ t.tikeutaparenkorean = 0x3210;
+ t.tikeutcirclekorean = 0x3262;
+ t.tikeutkorean = 0x3137;
+ t.tikeutparenkorean = 0x3202;
+ t.tilde = 0x02dc;
+ t.tildebelowcmb = 0x0330;
+ t.tildecmb = 0x0303;
+ t.tildecomb = 0x0303;
+ t.tildedoublecmb = 0x0360;
+ t.tildeoperator = 0x223c;
+ t.tildeoverlaycmb = 0x0334;
+ t.tildeverticalcmb = 0x033e;
+ t.timescircle = 0x2297;
+ t.tipehahebrew = 0x0596;
+ t.tipehalefthebrew = 0x0596;
+ t.tippigurmukhi = 0x0a70;
+ t.titlocyrilliccmb = 0x0483;
+ t.tiwnarmenian = 0x057f;
+ t.tlinebelow = 0x1e6f;
+ t.tmonospace = 0xff54;
+ t.toarmenian = 0x0569;
+ t.tohiragana = 0x3068;
+ t.tokatakana = 0x30c8;
+ t.tokatakanahalfwidth = 0xff84;
+ t.tonebarextrahighmod = 0x02e5;
+ t.tonebarextralowmod = 0x02e9;
+ t.tonebarhighmod = 0x02e6;
+ t.tonebarlowmod = 0x02e8;
+ t.tonebarmidmod = 0x02e7;
+ t.tonefive = 0x01bd;
+ t.tonesix = 0x0185;
+ t.tonetwo = 0x01a8;
+ t.tonos = 0x0384;
+ t.tonsquare = 0x3327;
+ t.topatakthai = 0x0e0f;
+ t.tortoiseshellbracketleft = 0x3014;
+ t.tortoiseshellbracketleftsmall = 0xfe5d;
+ t.tortoiseshellbracketleftvertical = 0xfe39;
+ t.tortoiseshellbracketright = 0x3015;
+ t.tortoiseshellbracketrightsmall = 0xfe5e;
+ t.tortoiseshellbracketrightvertical = 0xfe3a;
+ t.totaothai = 0x0e15;
+ t.tpalatalhook = 0x01ab;
+ t.tparen = 0x24af;
+ t.trademark = 0x2122;
+ t.trademarksans = 0xf8ea;
+ t.trademarkserif = 0xf6db;
+ t.tretroflexhook = 0x0288;
+ t.triagdn = 0x25bc;
+ t.triaglf = 0x25c4;
+ t.triagrt = 0x25ba;
+ t.triagup = 0x25b2;
+ t.ts = 0x02a6;
+ t.tsadi = 0x05e6;
+ t.tsadidagesh = 0xfb46;
+ t.tsadidageshhebrew = 0xfb46;
+ t.tsadihebrew = 0x05e6;
+ t.tsecyrillic = 0x0446;
+ t.tsere = 0x05b5;
+ t.tsere12 = 0x05b5;
+ t.tsere1e = 0x05b5;
+ t.tsere2b = 0x05b5;
+ t.tserehebrew = 0x05b5;
+ t.tserenarrowhebrew = 0x05b5;
+ t.tserequarterhebrew = 0x05b5;
+ t.tserewidehebrew = 0x05b5;
+ t.tshecyrillic = 0x045b;
+ t.tsuperior = 0xf6f3;
+ t.ttabengali = 0x099f;
+ t.ttadeva = 0x091f;
+ t.ttagujarati = 0x0a9f;
+ t.ttagurmukhi = 0x0a1f;
+ t.tteharabic = 0x0679;
+ t.ttehfinalarabic = 0xfb67;
+ t.ttehinitialarabic = 0xfb68;
+ t.ttehmedialarabic = 0xfb69;
+ t.tthabengali = 0x09a0;
+ t.tthadeva = 0x0920;
+ t.tthagujarati = 0x0aa0;
+ t.tthagurmukhi = 0x0a20;
+ t.tturned = 0x0287;
+ t.tuhiragana = 0x3064;
+ t.tukatakana = 0x30c4;
+ t.tukatakanahalfwidth = 0xff82;
+ t.tusmallhiragana = 0x3063;
+ t.tusmallkatakana = 0x30c3;
+ t.tusmallkatakanahalfwidth = 0xff6f;
+ t.twelvecircle = 0x246b;
+ t.twelveparen = 0x247f;
+ t.twelveperiod = 0x2493;
+ t.twelveroman = 0x217b;
+ t.twentycircle = 0x2473;
+ t.twentyhangzhou = 0x5344;
+ t.twentyparen = 0x2487;
+ t.twentyperiod = 0x249b;
+ t.two = 0x0032;
+ t.twoarabic = 0x0662;
+ t.twobengali = 0x09e8;
+ t.twocircle = 0x2461;
+ t.twocircleinversesansserif = 0x278b;
+ t.twodeva = 0x0968;
+ t.twodotenleader = 0x2025;
+ t.twodotleader = 0x2025;
+ t.twodotleadervertical = 0xfe30;
+ t.twogujarati = 0x0ae8;
+ t.twogurmukhi = 0x0a68;
+ t.twohackarabic = 0x0662;
+ t.twohangzhou = 0x3022;
+ t.twoideographicparen = 0x3221;
+ t.twoinferior = 0x2082;
+ t.twomonospace = 0xff12;
+ t.twonumeratorbengali = 0x09f5;
+ t.twooldstyle = 0xf732;
+ t.twoparen = 0x2475;
+ t.twoperiod = 0x2489;
+ t.twopersian = 0x06f2;
+ t.tworoman = 0x2171;
+ t.twostroke = 0x01bb;
+ t.twosuperior = 0x00b2;
+ t.twothai = 0x0e52;
+ t.twothirds = 0x2154;
+ t.u = 0x0075;
+ t.uacute = 0x00fa;
+ t.ubar = 0x0289;
+ t.ubengali = 0x0989;
+ t.ubopomofo = 0x3128;
+ t.ubreve = 0x016d;
+ t.ucaron = 0x01d4;
+ t.ucircle = 0x24e4;
+ t.ucircumflex = 0x00fb;
+ t.ucircumflexbelow = 0x1e77;
+ t.ucyrillic = 0x0443;
+ t.udattadeva = 0x0951;
+ t.udblacute = 0x0171;
+ t.udblgrave = 0x0215;
+ t.udeva = 0x0909;
+ t.udieresis = 0x00fc;
+ t.udieresisacute = 0x01d8;
+ t.udieresisbelow = 0x1e73;
+ t.udieresiscaron = 0x01da;
+ t.udieresiscyrillic = 0x04f1;
+ t.udieresisgrave = 0x01dc;
+ t.udieresismacron = 0x01d6;
+ t.udotbelow = 0x1ee5;
+ t.ugrave = 0x00f9;
+ t.ugujarati = 0x0a89;
+ t.ugurmukhi = 0x0a09;
+ t.uhiragana = 0x3046;
+ t.uhookabove = 0x1ee7;
+ t.uhorn = 0x01b0;
+ t.uhornacute = 0x1ee9;
+ t.uhorndotbelow = 0x1ef1;
+ t.uhorngrave = 0x1eeb;
+ t.uhornhookabove = 0x1eed;
+ t.uhorntilde = 0x1eef;
+ t.uhungarumlaut = 0x0171;
+ t.uhungarumlautcyrillic = 0x04f3;
+ t.uinvertedbreve = 0x0217;
+ t.ukatakana = 0x30a6;
+ t.ukatakanahalfwidth = 0xff73;
+ t.ukcyrillic = 0x0479;
+ t.ukorean = 0x315c;
+ t.umacron = 0x016b;
+ t.umacroncyrillic = 0x04ef;
+ t.umacrondieresis = 0x1e7b;
+ t.umatragurmukhi = 0x0a41;
+ t.umonospace = 0xff55;
+ t.underscore = 0x005f;
+ t.underscoredbl = 0x2017;
+ t.underscoremonospace = 0xff3f;
+ t.underscorevertical = 0xfe33;
+ t.underscorewavy = 0xfe4f;
+ t.union = 0x222a;
+ t.universal = 0x2200;
+ t.uogonek = 0x0173;
+ t.uparen = 0x24b0;
+ t.upblock = 0x2580;
+ t.upperdothebrew = 0x05c4;
+ t.upsilon = 0x03c5;
+ t.upsilondieresis = 0x03cb;
+ t.upsilondieresistonos = 0x03b0;
+ t.upsilonlatin = 0x028a;
+ t.upsilontonos = 0x03cd;
+ t.uptackbelowcmb = 0x031d;
+ t.uptackmod = 0x02d4;
+ t.uragurmukhi = 0x0a73;
+ t.uring = 0x016f;
+ t.ushortcyrillic = 0x045e;
+ t.usmallhiragana = 0x3045;
+ t.usmallkatakana = 0x30a5;
+ t.usmallkatakanahalfwidth = 0xff69;
+ t.ustraightcyrillic = 0x04af;
+ t.ustraightstrokecyrillic = 0x04b1;
+ t.utilde = 0x0169;
+ t.utildeacute = 0x1e79;
+ t.utildebelow = 0x1e75;
+ t.uubengali = 0x098a;
+ t.uudeva = 0x090a;
+ t.uugujarati = 0x0a8a;
+ t.uugurmukhi = 0x0a0a;
+ t.uumatragurmukhi = 0x0a42;
+ t.uuvowelsignbengali = 0x09c2;
+ t.uuvowelsigndeva = 0x0942;
+ t.uuvowelsigngujarati = 0x0ac2;
+ t.uvowelsignbengali = 0x09c1;
+ t.uvowelsigndeva = 0x0941;
+ t.uvowelsigngujarati = 0x0ac1;
+ t.v = 0x0076;
+ t.vadeva = 0x0935;
+ t.vagujarati = 0x0ab5;
+ t.vagurmukhi = 0x0a35;
+ t.vakatakana = 0x30f7;
+ t.vav = 0x05d5;
+ t.vavdagesh = 0xfb35;
+ t.vavdagesh65 = 0xfb35;
+ t.vavdageshhebrew = 0xfb35;
+ t.vavhebrew = 0x05d5;
+ t.vavholam = 0xfb4b;
+ t.vavholamhebrew = 0xfb4b;
+ t.vavvavhebrew = 0x05f0;
+ t.vavyodhebrew = 0x05f1;
+ t.vcircle = 0x24e5;
+ t.vdotbelow = 0x1e7f;
+ t.vecyrillic = 0x0432;
+ t.veharabic = 0x06a4;
+ t.vehfinalarabic = 0xfb6b;
+ t.vehinitialarabic = 0xfb6c;
+ t.vehmedialarabic = 0xfb6d;
+ t.vekatakana = 0x30f9;
+ t.venus = 0x2640;
+ t.verticalbar = 0x007c;
+ t.verticallineabovecmb = 0x030d;
+ t.verticallinebelowcmb = 0x0329;
+ t.verticallinelowmod = 0x02cc;
+ t.verticallinemod = 0x02c8;
+ t.vewarmenian = 0x057e;
+ t.vhook = 0x028b;
+ t.vikatakana = 0x30f8;
+ t.viramabengali = 0x09cd;
+ t.viramadeva = 0x094d;
+ t.viramagujarati = 0x0acd;
+ t.visargabengali = 0x0983;
+ t.visargadeva = 0x0903;
+ t.visargagujarati = 0x0a83;
+ t.vmonospace = 0xff56;
+ t.voarmenian = 0x0578;
+ t.voicediterationhiragana = 0x309e;
+ t.voicediterationkatakana = 0x30fe;
+ t.voicedmarkkana = 0x309b;
+ t.voicedmarkkanahalfwidth = 0xff9e;
+ t.vokatakana = 0x30fa;
+ t.vparen = 0x24b1;
+ t.vtilde = 0x1e7d;
+ t.vturned = 0x028c;
+ t.vuhiragana = 0x3094;
+ t.vukatakana = 0x30f4;
+ t.w = 0x0077;
+ t.wacute = 0x1e83;
+ t.waekorean = 0x3159;
+ t.wahiragana = 0x308f;
+ t.wakatakana = 0x30ef;
+ t.wakatakanahalfwidth = 0xff9c;
+ t.wakorean = 0x3158;
+ t.wasmallhiragana = 0x308e;
+ t.wasmallkatakana = 0x30ee;
+ t.wattosquare = 0x3357;
+ t.wavedash = 0x301c;
+ t.wavyunderscorevertical = 0xfe34;
+ t.wawarabic = 0x0648;
+ t.wawfinalarabic = 0xfeee;
+ t.wawhamzaabovearabic = 0x0624;
+ t.wawhamzaabovefinalarabic = 0xfe86;
+ t.wbsquare = 0x33dd;
+ t.wcircle = 0x24e6;
+ t.wcircumflex = 0x0175;
+ t.wdieresis = 0x1e85;
+ t.wdotaccent = 0x1e87;
+ t.wdotbelow = 0x1e89;
+ t.wehiragana = 0x3091;
+ t.weierstrass = 0x2118;
+ t.wekatakana = 0x30f1;
+ t.wekorean = 0x315e;
+ t.weokorean = 0x315d;
+ t.wgrave = 0x1e81;
+ t.whitebullet = 0x25e6;
+ t.whitecircle = 0x25cb;
+ t.whitecircleinverse = 0x25d9;
+ t.whitecornerbracketleft = 0x300e;
+ t.whitecornerbracketleftvertical = 0xfe43;
+ t.whitecornerbracketright = 0x300f;
+ t.whitecornerbracketrightvertical = 0xfe44;
+ t.whitediamond = 0x25c7;
+ t.whitediamondcontainingblacksmalldiamond = 0x25c8;
+ t.whitedownpointingsmalltriangle = 0x25bf;
+ t.whitedownpointingtriangle = 0x25bd;
+ t.whiteleftpointingsmalltriangle = 0x25c3;
+ t.whiteleftpointingtriangle = 0x25c1;
+ t.whitelenticularbracketleft = 0x3016;
+ t.whitelenticularbracketright = 0x3017;
+ t.whiterightpointingsmalltriangle = 0x25b9;
+ t.whiterightpointingtriangle = 0x25b7;
+ t.whitesmallsquare = 0x25ab;
+ t.whitesmilingface = 0x263a;
+ t.whitesquare = 0x25a1;
+ t.whitestar = 0x2606;
+ t.whitetelephone = 0x260f;
+ t.whitetortoiseshellbracketleft = 0x3018;
+ t.whitetortoiseshellbracketright = 0x3019;
+ t.whiteuppointingsmalltriangle = 0x25b5;
+ t.whiteuppointingtriangle = 0x25b3;
+ t.wihiragana = 0x3090;
+ t.wikatakana = 0x30f0;
+ t.wikorean = 0x315f;
+ t.wmonospace = 0xff57;
+ t.wohiragana = 0x3092;
+ t.wokatakana = 0x30f2;
+ t.wokatakanahalfwidth = 0xff66;
+ t.won = 0x20a9;
+ t.wonmonospace = 0xffe6;
+ t.wowaenthai = 0x0e27;
+ t.wparen = 0x24b2;
+ t.wring = 0x1e98;
+ t.wsuperior = 0x02b7;
+ t.wturned = 0x028d;
+ t.wynn = 0x01bf;
+ t.x = 0x0078;
+ t.xabovecmb = 0x033d;
+ t.xbopomofo = 0x3112;
+ t.xcircle = 0x24e7;
+ t.xdieresis = 0x1e8d;
+ t.xdotaccent = 0x1e8b;
+ t.xeharmenian = 0x056d;
+ t.xi = 0x03be;
+ t.xmonospace = 0xff58;
+ t.xparen = 0x24b3;
+ t.xsuperior = 0x02e3;
+ t.y = 0x0079;
+ t.yaadosquare = 0x334e;
+ t.yabengali = 0x09af;
+ t.yacute = 0x00fd;
+ t.yadeva = 0x092f;
+ t.yaekorean = 0x3152;
+ t.yagujarati = 0x0aaf;
+ t.yagurmukhi = 0x0a2f;
+ t.yahiragana = 0x3084;
+ t.yakatakana = 0x30e4;
+ t.yakatakanahalfwidth = 0xff94;
+ t.yakorean = 0x3151;
+ t.yamakkanthai = 0x0e4e;
+ t.yasmallhiragana = 0x3083;
+ t.yasmallkatakana = 0x30e3;
+ t.yasmallkatakanahalfwidth = 0xff6c;
+ t.yatcyrillic = 0x0463;
+ t.ycircle = 0x24e8;
+ t.ycircumflex = 0x0177;
+ t.ydieresis = 0x00ff;
+ t.ydotaccent = 0x1e8f;
+ t.ydotbelow = 0x1ef5;
+ t.yeharabic = 0x064a;
+ t.yehbarreearabic = 0x06d2;
+ t.yehbarreefinalarabic = 0xfbaf;
+ t.yehfinalarabic = 0xfef2;
+ t.yehhamzaabovearabic = 0x0626;
+ t.yehhamzaabovefinalarabic = 0xfe8a;
+ t.yehhamzaaboveinitialarabic = 0xfe8b;
+ t.yehhamzaabovemedialarabic = 0xfe8c;
+ t.yehinitialarabic = 0xfef3;
+ t.yehmedialarabic = 0xfef4;
+ t.yehmeeminitialarabic = 0xfcdd;
+ t.yehmeemisolatedarabic = 0xfc58;
+ t.yehnoonfinalarabic = 0xfc94;
+ t.yehthreedotsbelowarabic = 0x06d1;
+ t.yekorean = 0x3156;
+ t.yen = 0x00a5;
+ t.yenmonospace = 0xffe5;
+ t.yeokorean = 0x3155;
+ t.yeorinhieuhkorean = 0x3186;
+ t.yerahbenyomohebrew = 0x05aa;
+ t.yerahbenyomolefthebrew = 0x05aa;
+ t.yericyrillic = 0x044b;
+ t.yerudieresiscyrillic = 0x04f9;
+ t.yesieungkorean = 0x3181;
+ t.yesieungpansioskorean = 0x3183;
+ t.yesieungsioskorean = 0x3182;
+ t.yetivhebrew = 0x059a;
+ t.ygrave = 0x1ef3;
+ t.yhook = 0x01b4;
+ t.yhookabove = 0x1ef7;
+ t.yiarmenian = 0x0575;
+ t.yicyrillic = 0x0457;
+ t.yikorean = 0x3162;
+ t.yinyang = 0x262f;
+ t.yiwnarmenian = 0x0582;
+ t.ymonospace = 0xff59;
+ t.yod = 0x05d9;
+ t.yoddagesh = 0xfb39;
+ t.yoddageshhebrew = 0xfb39;
+ t.yodhebrew = 0x05d9;
+ t.yodyodhebrew = 0x05f2;
+ t.yodyodpatahhebrew = 0xfb1f;
+ t.yohiragana = 0x3088;
+ t.yoikorean = 0x3189;
+ t.yokatakana = 0x30e8;
+ t.yokatakanahalfwidth = 0xff96;
+ t.yokorean = 0x315b;
+ t.yosmallhiragana = 0x3087;
+ t.yosmallkatakana = 0x30e7;
+ t.yosmallkatakanahalfwidth = 0xff6e;
+ t.yotgreek = 0x03f3;
+ t.yoyaekorean = 0x3188;
+ t.yoyakorean = 0x3187;
+ t.yoyakthai = 0x0e22;
+ t.yoyingthai = 0x0e0d;
+ t.yparen = 0x24b4;
+ t.ypogegrammeni = 0x037a;
+ t.ypogegrammenigreekcmb = 0x0345;
+ t.yr = 0x01a6;
+ t.yring = 0x1e99;
+ t.ysuperior = 0x02b8;
+ t.ytilde = 0x1ef9;
+ t.yturned = 0x028e;
+ t.yuhiragana = 0x3086;
+ t.yuikorean = 0x318c;
+ t.yukatakana = 0x30e6;
+ t.yukatakanahalfwidth = 0xff95;
+ t.yukorean = 0x3160;
+ t.yusbigcyrillic = 0x046b;
+ t.yusbigiotifiedcyrillic = 0x046d;
+ t.yuslittlecyrillic = 0x0467;
+ t.yuslittleiotifiedcyrillic = 0x0469;
+ t.yusmallhiragana = 0x3085;
+ t.yusmallkatakana = 0x30e5;
+ t.yusmallkatakanahalfwidth = 0xff6d;
+ t.yuyekorean = 0x318b;
+ t.yuyeokorean = 0x318a;
+ t.yyabengali = 0x09df;
+ t.yyadeva = 0x095f;
+ t.z = 0x007a;
+ t.zaarmenian = 0x0566;
+ t.zacute = 0x017a;
+ t.zadeva = 0x095b;
+ t.zagurmukhi = 0x0a5b;
+ t.zaharabic = 0x0638;
+ t.zahfinalarabic = 0xfec6;
+ t.zahinitialarabic = 0xfec7;
+ t.zahiragana = 0x3056;
+ t.zahmedialarabic = 0xfec8;
+ t.zainarabic = 0x0632;
+ t.zainfinalarabic = 0xfeb0;
+ t.zakatakana = 0x30b6;
+ t.zaqefgadolhebrew = 0x0595;
+ t.zaqefqatanhebrew = 0x0594;
+ t.zarqahebrew = 0x0598;
+ t.zayin = 0x05d6;
+ t.zayindagesh = 0xfb36;
+ t.zayindageshhebrew = 0xfb36;
+ t.zayinhebrew = 0x05d6;
+ t.zbopomofo = 0x3117;
+ t.zcaron = 0x017e;
+ t.zcircle = 0x24e9;
+ t.zcircumflex = 0x1e91;
+ t.zcurl = 0x0291;
+ t.zdot = 0x017c;
+ t.zdotaccent = 0x017c;
+ t.zdotbelow = 0x1e93;
+ t.zecyrillic = 0x0437;
+ t.zedescendercyrillic = 0x0499;
+ t.zedieresiscyrillic = 0x04df;
+ t.zehiragana = 0x305c;
+ t.zekatakana = 0x30bc;
+ t.zero = 0x0030;
+ t.zeroarabic = 0x0660;
+ t.zerobengali = 0x09e6;
+ t.zerodeva = 0x0966;
+ t.zerogujarati = 0x0ae6;
+ t.zerogurmukhi = 0x0a66;
+ t.zerohackarabic = 0x0660;
+ t.zeroinferior = 0x2080;
+ t.zeromonospace = 0xff10;
+ t.zerooldstyle = 0xf730;
+ t.zeropersian = 0x06f0;
+ t.zerosuperior = 0x2070;
+ t.zerothai = 0x0e50;
+ t.zerowidthjoiner = 0xfeff;
+ t.zerowidthnonjoiner = 0x200c;
+ t.zerowidthspace = 0x200b;
+ t.zeta = 0x03b6;
+ t.zhbopomofo = 0x3113;
+ t.zhearmenian = 0x056a;
+ t.zhebrevecyrillic = 0x04c2;
+ t.zhecyrillic = 0x0436;
+ t.zhedescendercyrillic = 0x0497;
+ t.zhedieresiscyrillic = 0x04dd;
+ t.zihiragana = 0x3058;
+ t.zikatakana = 0x30b8;
+ t.zinorhebrew = 0x05ae;
+ t.zlinebelow = 0x1e95;
+ t.zmonospace = 0xff5a;
+ t.zohiragana = 0x305e;
+ t.zokatakana = 0x30be;
+ t.zparen = 0x24b5;
+ t.zretroflexhook = 0x0290;
+ t.zstroke = 0x01b6;
+ t.zuhiragana = 0x305a;
+ t.zukatakana = 0x30ba;
+ t[".notdef"] = 0x0000;
+ t.angbracketleftbig = 0x2329;
+ t.angbracketleftBig = 0x2329;
+ t.angbracketleftbigg = 0x2329;
+ t.angbracketleftBigg = 0x2329;
+ t.angbracketrightBig = 0x232a;
+ t.angbracketrightbig = 0x232a;
+ t.angbracketrightBigg = 0x232a;
+ t.angbracketrightbigg = 0x232a;
+ t.arrowhookleft = 0x21aa;
+ t.arrowhookright = 0x21a9;
+ t.arrowlefttophalf = 0x21bc;
+ t.arrowleftbothalf = 0x21bd;
+ t.arrownortheast = 0x2197;
+ t.arrownorthwest = 0x2196;
+ t.arrowrighttophalf = 0x21c0;
+ t.arrowrightbothalf = 0x21c1;
+ t.arrowsoutheast = 0x2198;
+ t.arrowsouthwest = 0x2199;
+ t.backslashbig = 0x2216;
+ t.backslashBig = 0x2216;
+ t.backslashBigg = 0x2216;
+ t.backslashbigg = 0x2216;
+ t.bardbl = 0x2016;
+ t.bracehtipdownleft = 0xfe37;
+ t.bracehtipdownright = 0xfe37;
+ t.bracehtipupleft = 0xfe38;
+ t.bracehtipupright = 0xfe38;
+ t.braceleftBig = 0x007b;
+ t.braceleftbig = 0x007b;
+ t.braceleftbigg = 0x007b;
+ t.braceleftBigg = 0x007b;
+ t.bracerightBig = 0x007d;
+ t.bracerightbig = 0x007d;
+ t.bracerightbigg = 0x007d;
+ t.bracerightBigg = 0x007d;
+ t.bracketleftbig = 0x005b;
+ t.bracketleftBig = 0x005b;
+ t.bracketleftbigg = 0x005b;
+ t.bracketleftBigg = 0x005b;
+ t.bracketrightBig = 0x005d;
+ t.bracketrightbig = 0x005d;
+ t.bracketrightbigg = 0x005d;
+ t.bracketrightBigg = 0x005d;
+ t.ceilingleftbig = 0x2308;
+ t.ceilingleftBig = 0x2308;
+ t.ceilingleftBigg = 0x2308;
+ t.ceilingleftbigg = 0x2308;
+ t.ceilingrightbig = 0x2309;
+ t.ceilingrightBig = 0x2309;
+ t.ceilingrightbigg = 0x2309;
+ t.ceilingrightBigg = 0x2309;
+ t.circledotdisplay = 0x2299;
+ t.circledottext = 0x2299;
+ t.circlemultiplydisplay = 0x2297;
+ t.circlemultiplytext = 0x2297;
+ t.circleplusdisplay = 0x2295;
+ t.circleplustext = 0x2295;
+ t.contintegraldisplay = 0x222e;
+ t.contintegraltext = 0x222e;
+ t.coproductdisplay = 0x2210;
+ t.coproducttext = 0x2210;
+ t.floorleftBig = 0x230a;
+ t.floorleftbig = 0x230a;
+ t.floorleftbigg = 0x230a;
+ t.floorleftBigg = 0x230a;
+ t.floorrightbig = 0x230b;
+ t.floorrightBig = 0x230b;
+ t.floorrightBigg = 0x230b;
+ t.floorrightbigg = 0x230b;
+ t.hatwide = 0x0302;
+ t.hatwider = 0x0302;
+ t.hatwidest = 0x0302;
+ t.intercal = 0x1d40;
+ t.integraldisplay = 0x222b;
+ t.integraltext = 0x222b;
+ t.intersectiondisplay = 0x22c2;
+ t.intersectiontext = 0x22c2;
+ t.logicalanddisplay = 0x2227;
+ t.logicalandtext = 0x2227;
+ t.logicalordisplay = 0x2228;
+ t.logicalortext = 0x2228;
+ t.parenleftBig = 0x0028;
+ t.parenleftbig = 0x0028;
+ t.parenleftBigg = 0x0028;
+ t.parenleftbigg = 0x0028;
+ t.parenrightBig = 0x0029;
+ t.parenrightbig = 0x0029;
+ t.parenrightBigg = 0x0029;
+ t.parenrightbigg = 0x0029;
+ t.prime = 0x2032;
+ t.productdisplay = 0x220f;
+ t.producttext = 0x220f;
+ t.radicalbig = 0x221a;
+ t.radicalBig = 0x221a;
+ t.radicalBigg = 0x221a;
+ t.radicalbigg = 0x221a;
+ t.radicalbt = 0x221a;
+ t.radicaltp = 0x221a;
+ t.radicalvertex = 0x221a;
+ t.slashbig = 0x002f;
+ t.slashBig = 0x002f;
+ t.slashBigg = 0x002f;
+ t.slashbigg = 0x002f;
+ t.summationdisplay = 0x2211;
+ t.summationtext = 0x2211;
+ t.tildewide = 0x02dc;
+ t.tildewider = 0x02dc;
+ t.tildewidest = 0x02dc;
+ t.uniondisplay = 0x22c3;
+ t.unionmultidisplay = 0x228e;
+ t.unionmultitext = 0x228e;
+ t.unionsqdisplay = 0x2294;
+ t.unionsqtext = 0x2294;
+ t.uniontext = 0x22c3;
+ t.vextenddouble = 0x2225;
+ t.vextendsingle = 0x2223;
+});
+const getDingbatsGlyphsUnicode = getLookupTableFactory(function (t) {
+ t.space = 0x0020;
+ t.a1 = 0x2701;
+ t.a2 = 0x2702;
+ t.a202 = 0x2703;
+ t.a3 = 0x2704;
+ t.a4 = 0x260e;
+ t.a5 = 0x2706;
+ t.a119 = 0x2707;
+ t.a118 = 0x2708;
+ t.a117 = 0x2709;
+ t.a11 = 0x261b;
+ t.a12 = 0x261e;
+ t.a13 = 0x270c;
+ t.a14 = 0x270d;
+ t.a15 = 0x270e;
+ t.a16 = 0x270f;
+ t.a105 = 0x2710;
+ t.a17 = 0x2711;
+ t.a18 = 0x2712;
+ t.a19 = 0x2713;
+ t.a20 = 0x2714;
+ t.a21 = 0x2715;
+ t.a22 = 0x2716;
+ t.a23 = 0x2717;
+ t.a24 = 0x2718;
+ t.a25 = 0x2719;
+ t.a26 = 0x271a;
+ t.a27 = 0x271b;
+ t.a28 = 0x271c;
+ t.a6 = 0x271d;
+ t.a7 = 0x271e;
+ t.a8 = 0x271f;
+ t.a9 = 0x2720;
+ t.a10 = 0x2721;
+ t.a29 = 0x2722;
+ t.a30 = 0x2723;
+ t.a31 = 0x2724;
+ t.a32 = 0x2725;
+ t.a33 = 0x2726;
+ t.a34 = 0x2727;
+ t.a35 = 0x2605;
+ t.a36 = 0x2729;
+ t.a37 = 0x272a;
+ t.a38 = 0x272b;
+ t.a39 = 0x272c;
+ t.a40 = 0x272d;
+ t.a41 = 0x272e;
+ t.a42 = 0x272f;
+ t.a43 = 0x2730;
+ t.a44 = 0x2731;
+ t.a45 = 0x2732;
+ t.a46 = 0x2733;
+ t.a47 = 0x2734;
+ t.a48 = 0x2735;
+ t.a49 = 0x2736;
+ t.a50 = 0x2737;
+ t.a51 = 0x2738;
+ t.a52 = 0x2739;
+ t.a53 = 0x273a;
+ t.a54 = 0x273b;
+ t.a55 = 0x273c;
+ t.a56 = 0x273d;
+ t.a57 = 0x273e;
+ t.a58 = 0x273f;
+ t.a59 = 0x2740;
+ t.a60 = 0x2741;
+ t.a61 = 0x2742;
+ t.a62 = 0x2743;
+ t.a63 = 0x2744;
+ t.a64 = 0x2745;
+ t.a65 = 0x2746;
+ t.a66 = 0x2747;
+ t.a67 = 0x2748;
+ t.a68 = 0x2749;
+ t.a69 = 0x274a;
+ t.a70 = 0x274b;
+ t.a71 = 0x25cf;
+ t.a72 = 0x274d;
+ t.a73 = 0x25a0;
+ t.a74 = 0x274f;
+ t.a203 = 0x2750;
+ t.a75 = 0x2751;
+ t.a204 = 0x2752;
+ t.a76 = 0x25b2;
+ t.a77 = 0x25bc;
+ t.a78 = 0x25c6;
+ t.a79 = 0x2756;
+ t.a81 = 0x25d7;
+ t.a82 = 0x2758;
+ t.a83 = 0x2759;
+ t.a84 = 0x275a;
+ t.a97 = 0x275b;
+ t.a98 = 0x275c;
+ t.a99 = 0x275d;
+ t.a100 = 0x275e;
+ t.a101 = 0x2761;
+ t.a102 = 0x2762;
+ t.a103 = 0x2763;
+ t.a104 = 0x2764;
+ t.a106 = 0x2765;
+ t.a107 = 0x2766;
+ t.a108 = 0x2767;
+ t.a112 = 0x2663;
+ t.a111 = 0x2666;
+ t.a110 = 0x2665;
+ t.a109 = 0x2660;
+ t.a120 = 0x2460;
+ t.a121 = 0x2461;
+ t.a122 = 0x2462;
+ t.a123 = 0x2463;
+ t.a124 = 0x2464;
+ t.a125 = 0x2465;
+ t.a126 = 0x2466;
+ t.a127 = 0x2467;
+ t.a128 = 0x2468;
+ t.a129 = 0x2469;
+ t.a130 = 0x2776;
+ t.a131 = 0x2777;
+ t.a132 = 0x2778;
+ t.a133 = 0x2779;
+ t.a134 = 0x277a;
+ t.a135 = 0x277b;
+ t.a136 = 0x277c;
+ t.a137 = 0x277d;
+ t.a138 = 0x277e;
+ t.a139 = 0x277f;
+ t.a140 = 0x2780;
+ t.a141 = 0x2781;
+ t.a142 = 0x2782;
+ t.a143 = 0x2783;
+ t.a144 = 0x2784;
+ t.a145 = 0x2785;
+ t.a146 = 0x2786;
+ t.a147 = 0x2787;
+ t.a148 = 0x2788;
+ t.a149 = 0x2789;
+ t.a150 = 0x278a;
+ t.a151 = 0x278b;
+ t.a152 = 0x278c;
+ t.a153 = 0x278d;
+ t.a154 = 0x278e;
+ t.a155 = 0x278f;
+ t.a156 = 0x2790;
+ t.a157 = 0x2791;
+ t.a158 = 0x2792;
+ t.a159 = 0x2793;
+ t.a160 = 0x2794;
+ t.a161 = 0x2192;
+ t.a163 = 0x2194;
+ t.a164 = 0x2195;
+ t.a196 = 0x2798;
+ t.a165 = 0x2799;
+ t.a192 = 0x279a;
+ t.a166 = 0x279b;
+ t.a167 = 0x279c;
+ t.a168 = 0x279d;
+ t.a169 = 0x279e;
+ t.a170 = 0x279f;
+ t.a171 = 0x27a0;
+ t.a172 = 0x27a1;
+ t.a173 = 0x27a2;
+ t.a162 = 0x27a3;
+ t.a174 = 0x27a4;
+ t.a175 = 0x27a5;
+ t.a176 = 0x27a6;
+ t.a177 = 0x27a7;
+ t.a178 = 0x27a8;
+ t.a179 = 0x27a9;
+ t.a193 = 0x27aa;
+ t.a180 = 0x27ab;
+ t.a199 = 0x27ac;
+ t.a181 = 0x27ad;
+ t.a200 = 0x27ae;
+ t.a182 = 0x27af;
+ t.a201 = 0x27b1;
+ t.a183 = 0x27b2;
+ t.a184 = 0x27b3;
+ t.a197 = 0x27b4;
+ t.a185 = 0x27b5;
+ t.a194 = 0x27b6;
+ t.a198 = 0x27b7;
+ t.a186 = 0x27b8;
+ t.a195 = 0x27b9;
+ t.a187 = 0x27ba;
+ t.a188 = 0x27bb;
+ t.a189 = 0x27bc;
+ t.a190 = 0x27bd;
+ t.a191 = 0x27be;
+ t.a89 = 0x2768;
+ t.a90 = 0x2769;
+ t.a93 = 0x276a;
+ t.a94 = 0x276b;
+ t.a91 = 0x276c;
+ t.a92 = 0x276d;
+ t.a205 = 0x276e;
+ t.a85 = 0x276f;
+ t.a206 = 0x2770;
+ t.a86 = 0x2771;
+ t.a87 = 0x2772;
+ t.a88 = 0x2773;
+ t.a95 = 0x2774;
+ t.a96 = 0x2775;
+ t[".notdef"] = 0x0000;
+});
+
+;// ./src/core/unicode.js
+
+
+
+const getSpecialPUASymbols = getLookupTableFactory(function (t) {
+ t[63721] = 0x00a9;
+ t[63193] = 0x00a9;
+ t[63720] = 0x00ae;
+ t[63194] = 0x00ae;
+ t[63722] = 0x2122;
+ t[63195] = 0x2122;
+ t[63718] = 0x23d0;
+ t[63719] = 0x23af;
+ t[63733] = 0x23ae;
+ t[63729] = 0x23a7;
+ t[63730] = 0x23a8;
+ t[63731] = 0x23a9;
+ t[63740] = 0x23ab;
+ t[63741] = 0x23ac;
+ t[63742] = 0x23ad;
+ t[63726] = 0x23a1;
+ t[63727] = 0x23a2;
+ t[63728] = 0x23a3;
+ t[63737] = 0x23a4;
+ t[63738] = 0x23a5;
+ t[63739] = 0x23a6;
+ t[63723] = 0x239b;
+ t[63724] = 0x239c;
+ t[63725] = 0x239d;
+ t[63734] = 0x239e;
+ t[63735] = 0x239f;
+ t[63736] = 0x23a0;
+});
+function mapSpecialUnicodeValues(code) {
+ if (code >= 0xfff0 && code <= 0xffff) {
+ return 0;
+ } else if (code >= 0xf600 && code <= 0xf8ff) {
+ return getSpecialPUASymbols()[code] || code;
+ } else if (code === 0x00ad) {
+ return 0x002d;
+ }
+ return code;
+}
+function getUnicodeForGlyph(name, glyphsUnicodeMap) {
+ let unicode = glyphsUnicodeMap[name];
+ if (unicode !== undefined) {
+ return unicode;
+ }
+ if (!name) {
+ return -1;
+ }
+ if (name[0] === "u") {
+ const nameLen = name.length;
+ let hexStr;
+ if (nameLen === 7 && name[1] === "n" && name[2] === "i") {
+ hexStr = name.substring(3);
+ } else if (nameLen >= 5 && nameLen <= 7) {
+ hexStr = name.substring(1);
+ } else {
+ return -1;
+ }
+ if (hexStr === hexStr.toUpperCase()) {
+ unicode = parseInt(hexStr, 16);
+ if (unicode >= 0) {
+ return unicode;
+ }
+ }
+ }
+ return -1;
+}
+const UnicodeRanges = [[0x0000, 0x007f], [0x0080, 0x00ff], [0x0100, 0x017f], [0x0180, 0x024f], [0x0250, 0x02af, 0x1d00, 0x1d7f, 0x1d80, 0x1dbf], [0x02b0, 0x02ff, 0xa700, 0xa71f], [0x0300, 0x036f, 0x1dc0, 0x1dff], [0x0370, 0x03ff], [0x2c80, 0x2cff], [0x0400, 0x04ff, 0x0500, 0x052f, 0x2de0, 0x2dff, 0xa640, 0xa69f], [0x0530, 0x058f], [0x0590, 0x05ff], [0xa500, 0xa63f], [0x0600, 0x06ff, 0x0750, 0x077f], [0x07c0, 0x07ff], [0x0900, 0x097f], [0x0980, 0x09ff], [0x0a00, 0x0a7f], [0x0a80, 0x0aff], [0x0b00, 0x0b7f], [0x0b80, 0x0bff], [0x0c00, 0x0c7f], [0x0c80, 0x0cff], [0x0d00, 0x0d7f], [0x0e00, 0x0e7f], [0x0e80, 0x0eff], [0x10a0, 0x10ff, 0x2d00, 0x2d2f], [0x1b00, 0x1b7f], [0x1100, 0x11ff], [0x1e00, 0x1eff, 0x2c60, 0x2c7f, 0xa720, 0xa7ff], [0x1f00, 0x1fff], [0x2000, 0x206f, 0x2e00, 0x2e7f], [0x2070, 0x209f], [0x20a0, 0x20cf], [0x20d0, 0x20ff], [0x2100, 0x214f], [0x2150, 0x218f], [0x2190, 0x21ff, 0x27f0, 0x27ff, 0x2900, 0x297f, 0x2b00, 0x2bff], [0x2200, 0x22ff, 0x2a00, 0x2aff, 0x27c0, 0x27ef, 0x2980, 0x29ff], [0x2300, 0x23ff], [0x2400, 0x243f], [0x2440, 0x245f], [0x2460, 0x24ff], [0x2500, 0x257f], [0x2580, 0x259f], [0x25a0, 0x25ff], [0x2600, 0x26ff], [0x2700, 0x27bf], [0x3000, 0x303f], [0x3040, 0x309f], [0x30a0, 0x30ff, 0x31f0, 0x31ff], [0x3100, 0x312f, 0x31a0, 0x31bf], [0x3130, 0x318f], [0xa840, 0xa87f], [0x3200, 0x32ff], [0x3300, 0x33ff], [0xac00, 0xd7af], [0xd800, 0xdfff], [0x10900, 0x1091f], [0x4e00, 0x9fff, 0x2e80, 0x2eff, 0x2f00, 0x2fdf, 0x2ff0, 0x2fff, 0x3400, 0x4dbf, 0x20000, 0x2a6df, 0x3190, 0x319f], [0xe000, 0xf8ff], [0x31c0, 0x31ef, 0xf900, 0xfaff, 0x2f800, 0x2fa1f], [0xfb00, 0xfb4f], [0xfb50, 0xfdff], [0xfe20, 0xfe2f], [0xfe10, 0xfe1f], [0xfe50, 0xfe6f], [0xfe70, 0xfeff], [0xff00, 0xffef], [0xfff0, 0xffff], [0x0f00, 0x0fff], [0x0700, 0x074f], [0x0780, 0x07bf], [0x0d80, 0x0dff], [0x1000, 0x109f], [0x1200, 0x137f, 0x1380, 0x139f, 0x2d80, 0x2ddf], [0x13a0, 0x13ff], [0x1400, 0x167f], [0x1680, 0x169f], [0x16a0, 0x16ff], [0x1780, 0x17ff], [0x1800, 0x18af], [0x2800, 0x28ff], [0xa000, 0xa48f], [0x1700, 0x171f, 0x1720, 0x173f, 0x1740, 0x175f, 0x1760, 0x177f], [0x10300, 0x1032f], [0x10330, 0x1034f], [0x10400, 0x1044f], [0x1d000, 0x1d0ff, 0x1d100, 0x1d1ff, 0x1d200, 0x1d24f], [0x1d400, 0x1d7ff], [0xff000, 0xffffd], [0xfe00, 0xfe0f, 0xe0100, 0xe01ef], [0xe0000, 0xe007f], [0x1900, 0x194f], [0x1950, 0x197f], [0x1980, 0x19df], [0x1a00, 0x1a1f], [0x2c00, 0x2c5f], [0x2d30, 0x2d7f], [0x4dc0, 0x4dff], [0xa800, 0xa82f], [0x10000, 0x1007f, 0x10080, 0x100ff, 0x10100, 0x1013f], [0x10140, 0x1018f], [0x10380, 0x1039f], [0x103a0, 0x103df], [0x10450, 0x1047f], [0x10480, 0x104af], [0x10800, 0x1083f], [0x10a00, 0x10a5f], [0x1d300, 0x1d35f], [0x12000, 0x123ff, 0x12400, 0x1247f], [0x1d360, 0x1d37f], [0x1b80, 0x1bbf], [0x1c00, 0x1c4f], [0x1c50, 0x1c7f], [0xa880, 0xa8df], [0xa900, 0xa92f], [0xa930, 0xa95f], [0xaa00, 0xaa5f], [0x10190, 0x101cf], [0x101d0, 0x101ff], [0x102a0, 0x102df, 0x10280, 0x1029f, 0x10920, 0x1093f], [0x1f030, 0x1f09f, 0x1f000, 0x1f02f]];
+function getUnicodeRangeFor(value, lastPosition = -1) {
+ if (lastPosition !== -1) {
+ const range = UnicodeRanges[lastPosition];
+ for (let i = 0, ii = range.length; i < ii; i += 2) {
+ if (value >= range[i] && value <= range[i + 1]) {
+ return lastPosition;
+ }
+ }
+ }
+ for (let i = 0, ii = UnicodeRanges.length; i < ii; i++) {
+ const range = UnicodeRanges[i];
+ for (let j = 0, jj = range.length; j < jj; j += 2) {
+ if (value >= range[j] && value <= range[j + 1]) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+const SpecialCharRegExp = /^(\s)|(\p{Mn})|(\p{Cf})$/u;
+const CategoryCache = new Map();
+function getCharUnicodeCategory(char) {
+ const cachedCategory = CategoryCache.get(char);
+ if (cachedCategory) {
+ return cachedCategory;
+ }
+ const groups = char.match(SpecialCharRegExp);
+ const category = {
+ isWhitespace: !!groups?.[1],
+ isZeroWidthDiacritic: !!groups?.[2],
+ isInvisibleFormatMark: !!groups?.[3]
+ };
+ CategoryCache.set(char, category);
+ return category;
+}
+function clearUnicodeCaches() {
+ CategoryCache.clear();
+}
+
+;// ./src/core/fonts_utils.js
+
+
+
+
+
+
+
+
+
+
+
+const SEAC_ANALYSIS_ENABLED = true;
+const FontFlags = {
+ FixedPitch: 1,
+ Serif: 2,
+ Symbolic: 4,
+ Script: 8,
+ Nonsymbolic: 32,
+ Italic: 64,
+ AllCap: 65536,
+ SmallCap: 131072,
+ ForceBold: 262144
+};
+const MacStandardGlyphOrdering = [".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dcroat"];
+function recoverGlyphName(name, glyphsUnicodeMap) {
+ if (glyphsUnicodeMap[name] !== undefined) {
+ return name;
+ }
+ const unicode = getUnicodeForGlyph(name, glyphsUnicodeMap);
+ if (unicode !== -1) {
+ for (const key in glyphsUnicodeMap) {
+ if (glyphsUnicodeMap[key] === unicode) {
+ return key;
+ }
+ }
+ }
+ info("Unable to recover a standard glyph name for: " + name);
+ return name;
+}
+function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
+ const charCodeToGlyphId = Object.create(null);
+ let glyphId, charCode, baseEncoding;
+ const isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
+ if (properties.isInternalFont) {
+ baseEncoding = builtInEncoding;
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ charCodeToGlyphId[charCode] = glyphId >= 0 ? glyphId : 0;
+ }
+ } else if (properties.baseEncodingName) {
+ baseEncoding = getEncoding(properties.baseEncodingName);
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ charCodeToGlyphId[charCode] = glyphId >= 0 ? glyphId : 0;
+ }
+ } else if (isSymbolicFont) {
+ for (charCode in builtInEncoding) {
+ charCodeToGlyphId[charCode] = builtInEncoding[charCode];
+ }
+ } else {
+ baseEncoding = StandardEncoding;
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ charCodeToGlyphId[charCode] = glyphId >= 0 ? glyphId : 0;
+ }
+ }
+ const differences = properties.differences;
+ let glyphsUnicodeMap;
+ if (differences) {
+ for (charCode in differences) {
+ const glyphName = differences[charCode];
+ glyphId = glyphNames.indexOf(glyphName);
+ if (glyphId === -1) {
+ glyphsUnicodeMap ??= getGlyphsUnicode();
+ const standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);
+ if (standardGlyphName !== glyphName) {
+ glyphId = glyphNames.indexOf(standardGlyphName);
+ }
+ }
+ charCodeToGlyphId[charCode] = glyphId >= 0 ? glyphId : 0;
+ }
+ }
+ return charCodeToGlyphId;
+}
+function normalizeFontName(name) {
+ return name.replaceAll(/[,_]/g, "-").replaceAll(/\s/g, "");
+}
+const getVerticalPresentationForm = getLookupTableFactory(t => {
+ t[0x2013] = 0xfe32;
+ t[0x2014] = 0xfe31;
+ t[0x2025] = 0xfe30;
+ t[0x2026] = 0xfe19;
+ t[0x3001] = 0xfe11;
+ t[0x3002] = 0xfe12;
+ t[0x3008] = 0xfe3f;
+ t[0x3009] = 0xfe40;
+ t[0x300a] = 0xfe3d;
+ t[0x300b] = 0xfe3e;
+ t[0x300c] = 0xfe41;
+ t[0x300d] = 0xfe42;
+ t[0x300e] = 0xfe43;
+ t[0x300f] = 0xfe44;
+ t[0x3010] = 0xfe3b;
+ t[0x3011] = 0xfe3c;
+ t[0x3014] = 0xfe39;
+ t[0x3015] = 0xfe3a;
+ t[0x3016] = 0xfe17;
+ t[0x3017] = 0xfe18;
+ t[0xfe4f] = 0xfe34;
+ t[0xff01] = 0xfe15;
+ t[0xff08] = 0xfe35;
+ t[0xff09] = 0xfe36;
+ t[0xff0c] = 0xfe10;
+ t[0xff1a] = 0xfe13;
+ t[0xff1b] = 0xfe14;
+ t[0xff1f] = 0xfe16;
+ t[0xff3b] = 0xfe47;
+ t[0xff3d] = 0xfe48;
+ t[0xff3f] = 0xfe33;
+ t[0xff5b] = 0xfe37;
+ t[0xff5d] = 0xfe38;
+});
+const MAX_SIZE_TO_COMPILE = 1000;
+function compileType3Glyph({
+ data: img,
+ width,
+ height
+}) {
+ if (width > MAX_SIZE_TO_COMPILE || height > MAX_SIZE_TO_COMPILE) {
+ return null;
+ }
+ const POINT_TO_PROCESS_LIMIT = 1000;
+ const POINT_TYPES = new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
+ const width1 = width + 1;
+ const points = new Uint8Array(width1 * (height + 1));
+ let i, j, j0;
+ const lineSize = width + 7 & ~7;
+ const data = new Uint8Array(lineSize * height);
+ let pos = 0;
+ for (const elem of img) {
+ let mask = 128;
+ while (mask > 0) {
+ data[pos++] = elem & mask ? 0 : 255;
+ mask >>= 1;
+ }
+ }
+ let count = 0;
+ pos = 0;
+ if (data[pos] !== 0) {
+ points[0] = 1;
+ ++count;
+ }
+ for (j = 1; j < width; j++) {
+ if (data[pos] !== data[pos + 1]) {
+ points[j] = data[pos] ? 2 : 1;
+ ++count;
+ }
+ pos++;
+ }
+ if (data[pos] !== 0) {
+ points[j] = 2;
+ ++count;
+ }
+ for (i = 1; i < height; i++) {
+ pos = i * lineSize;
+ j0 = i * width1;
+ if (data[pos - lineSize] !== data[pos]) {
+ points[j0] = data[pos] ? 1 : 8;
+ ++count;
+ }
+ let sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
+ for (j = 1; j < width; j++) {
+ sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) + (data[pos - lineSize + 1] ? 8 : 0);
+ if (POINT_TYPES[sum]) {
+ points[j0 + j] = POINT_TYPES[sum];
+ ++count;
+ }
+ pos++;
+ }
+ if (data[pos - lineSize] !== data[pos]) {
+ points[j0 + j] = data[pos] ? 2 : 4;
+ ++count;
+ }
+ if (count > POINT_TO_PROCESS_LIMIT) {
+ return null;
+ }
+ }
+ pos = lineSize * (height - 1);
+ j0 = i * width1;
+ if (data[pos] !== 0) {
+ points[j0] = 8;
+ ++count;
+ }
+ for (j = 1; j < width; j++) {
+ if (data[pos] !== data[pos + 1]) {
+ points[j0 + j] = data[pos] ? 4 : 8;
+ ++count;
+ }
+ pos++;
+ }
+ if (data[pos] !== 0) {
+ points[j0 + j] = 4;
+ ++count;
+ }
+ if (count > POINT_TO_PROCESS_LIMIT) {
+ return null;
+ }
+ const steps = new Int32Array([0, width1, -1, 0, -width1, 0, 0, 0, 1]);
+ const pathBuf = [];
+ const {
+ a,
+ b,
+ c,
+ d,
+ e,
+ f
+ } = new DOMMatrix().scaleSelf(1 / width, -1 / height).translateSelf(0, -height);
+ for (i = 0; count && i <= height; i++) {
+ let p = i * width1;
+ const end = p + width;
+ while (p < end && !points[p]) {
+ p++;
+ }
+ if (p === end) {
+ continue;
+ }
+ let x = p % width1;
+ let y = i;
+ pathBuf.push(DrawOPS.moveTo, a * x + c * y + e, b * x + d * y + f);
+ const p0 = p;
+ let type = points[p];
+ do {
+ const step = steps[type];
+ do {
+ p += step;
+ } while (!points[p]);
+ const pp = points[p];
+ if (pp !== 5 && pp !== 10) {
+ type = pp;
+ points[p] = 0;
+ } else {
+ type = pp & 0x33 * type >> 4;
+ points[p] &= type >> 2 | type << 2;
+ }
+ x = p % width1;
+ y = p / width1 | 0;
+ pathBuf.push(DrawOPS.lineTo, a * x + c * y + e, b * x + d * y + f);
+ if (!points[p]) {
+ --count;
+ }
+ } while (p0 !== p);
+ --i;
+ }
+ return [OPS.rawFillPath, [new Float32Array(pathBuf)], new Float32Array([0, 0, width, height])];
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.to-array.js
+var es_iterator_to_array = __webpack_require__(1806);
+;// ./src/core/charsets.js
+const ISOAdobeCharset = [".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron"];
+const ExpertCharset = [".notdef", "space", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall"];
+const ExpertSubsetCharset = [".notdef", "space", "dollaroldstyle", "dollarsuperior", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "hyphensuperior", "colonmonetary", "onefitted", "rupiah", "centoldstyle", "figuredash", "hypheninferior", "onequarter", "onehalf", "threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior"];
+
+;// ./src/core/data_builder.js
+
+
+
+
+
+
+
+class DataBuilder {
+ #buf;
+ #bufLength = 1024;
+ #hasExactLength = false;
+ #pos = 0;
+ #view;
+ constructor({
+ exactLength = 0,
+ minLength = 0
+ }) {
+ this.#hasExactLength = !!exactLength;
+ this.#initBuf(exactLength || minLength);
+ }
+ #initBuf(minLength) {
+ if (this.#hasExactLength) {
+ this.#bufLength = minLength;
+ } else {
+ while (this.#bufLength < minLength) {
+ this.#bufLength *= 2;
+ }
+ }
+ const newBuf = new Uint8Array(this.#bufLength);
+ if (this.#buf) {
+ newBuf.set(this.#buf, 0);
+ }
+ this.#buf = newBuf;
+ this.#view = new DataView(newBuf.buffer);
+ }
+ get data() {
+ return this.#buf.subarray(0, this.#pos);
+ }
+ get length() {
+ return this.#pos;
+ }
+ skip(n) {
+ this.#pos += n;
+ }
+ setArray(arr) {
+ const newPos = this.#pos + arr.length;
+ if (!this.#hasExactLength && newPos > this.#bufLength) {
+ this.#initBuf(newPos);
+ }
+ this.#buf.set(arr, this.#pos);
+ this.#pos = newPos;
+ }
+ setInt16(val) {
+ const newPos = this.#pos + 2;
+ if (!this.#hasExactLength && newPos > this.#bufLength) {
+ this.#initBuf(newPos);
+ }
+ this.#view.setInt16(this.#pos, val);
+ this.#pos = newPos;
+ }
+ setSafeInt16(val) {
+ const newPos = this.#pos + 2;
+ if (!this.#hasExactLength && newPos > this.#bufLength) {
+ this.#initBuf(newPos);
+ }
+ this.#view.setInt16(this.#pos, MathClamp(val, -0x8000, 0x7fff));
+ this.#pos = newPos;
+ }
+ setInt32(val) {
+ const newPos = this.#pos + 4;
+ if (!this.#hasExactLength && newPos > this.#bufLength) {
+ this.#initBuf(newPos);
+ }
+ this.#view.setInt32(this.#pos, val);
+ this.#pos = newPos;
+ }
+}
+
+;// ./src/core/cff_parser.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const MAX_SUBR_NESTING = 10;
+function looksLikeUnsigned16BitNegative(coord) {
+ return coord > 0x7fff && coord <= 0xffff;
+}
+function recoverSigned16BitBBox(bbox, onlyLowerLeft = false) {
+ return Util.normalizeRect(bbox.map((coord, i) => (!onlyLowerLeft || i < 2) && looksLikeUnsigned16BitNegative(coord) ? coord - 0x10000 : coord));
+}
+const CFFStandardStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"];
+const NUM_STANDARD_CFF_STRINGS = 391;
+const DEFAULT_BLUE_SCALE = 0.039625;
+const DEFAULT_BLUE_SHIFT = 7;
+const DEFAULT_BLUE_FUZZ = 1;
+const DEFAULT_EXPANSION_FACTOR = 0.06;
+const CharstringValidationData = [null, {
+ id: "hstem",
+ min: 2,
+ stackClearing: true,
+ stem: true
+}, null, {
+ id: "vstem",
+ min: 2,
+ stackClearing: true,
+ stem: true
+}, {
+ id: "vmoveto",
+ min: 1,
+ stackClearing: true
+}, {
+ id: "rlineto",
+ min: 2,
+ resetStack: true
+}, {
+ id: "hlineto",
+ min: 1,
+ resetStack: true
+}, {
+ id: "vlineto",
+ min: 1,
+ resetStack: true
+}, {
+ id: "rrcurveto",
+ min: 6,
+ resetStack: true
+}, null, {
+ id: "callsubr",
+ min: 1
+}, {
+ id: "return",
+ min: 0
+}, null, null, {
+ id: "endchar",
+ min: 0,
+ stackClearing: true
+}, null, null, null, {
+ id: "hstemhm",
+ min: 2,
+ stackClearing: true,
+ stem: true
+}, {
+ id: "hintmask",
+ min: 0,
+ stackClearing: true
+}, {
+ id: "cntrmask",
+ min: 0,
+ stackClearing: true
+}, {
+ id: "rmoveto",
+ min: 2,
+ stackClearing: true
+}, {
+ id: "hmoveto",
+ min: 1,
+ stackClearing: true
+}, {
+ id: "vstemhm",
+ min: 2,
+ stackClearing: true,
+ stem: true
+}, {
+ id: "rcurveline",
+ min: 8,
+ resetStack: true
+}, {
+ id: "rlinecurve",
+ min: 8,
+ resetStack: true
+}, {
+ id: "vvcurveto",
+ min: 4,
+ resetStack: true
+}, {
+ id: "hhcurveto",
+ min: 4,
+ resetStack: true
+}, null, {
+ id: "callgsubr",
+ min: 1
+}, {
+ id: "vhcurveto",
+ min: 4,
+ resetStack: true
+}, {
+ id: "hvcurveto",
+ min: 4,
+ resetStack: true
+}];
+const CharstringValidationData12 = [null, null, null, {
+ id: "and",
+ min: 2,
+ stackDelta: -1
+}, {
+ id: "or",
+ min: 2,
+ stackDelta: -1
+}, {
+ id: "not",
+ min: 1,
+ stackDelta: 0
+}, null, null, null, {
+ id: "abs",
+ min: 1,
+ stackDelta: 0
+}, {
+ id: "add",
+ min: 2,
+ stackDelta: -1,
+ stackFn(stack, index) {
+ stack[index - 2] = stack[index - 2] + stack[index - 1];
+ }
+}, {
+ id: "sub",
+ min: 2,
+ stackDelta: -1,
+ stackFn(stack, index) {
+ stack[index - 2] = stack[index - 2] - stack[index - 1];
+ }
+}, {
+ id: "div",
+ min: 2,
+ stackDelta: -1,
+ stackFn(stack, index) {
+ stack[index - 2] = stack[index - 2] / stack[index - 1];
+ }
+}, null, {
+ id: "neg",
+ min: 1,
+ stackDelta: 0,
+ stackFn(stack, index) {
+ stack[index - 1] = -stack[index - 1];
+ }
+}, {
+ id: "eq",
+ min: 2,
+ stackDelta: -1
+}, null, null, {
+ id: "drop",
+ min: 1,
+ stackDelta: -1
+}, null, {
+ id: "put",
+ min: 2,
+ stackDelta: -2
+}, {
+ id: "get",
+ min: 1,
+ stackDelta: 0
+}, {
+ id: "ifelse",
+ min: 4,
+ stackDelta: -3
+}, {
+ id: "random",
+ min: 0,
+ stackDelta: 1
+}, {
+ id: "mul",
+ min: 2,
+ stackDelta: -1,
+ stackFn(stack, index) {
+ stack[index - 2] = stack[index - 2] * stack[index - 1];
+ }
+}, null, {
+ id: "sqrt",
+ min: 1,
+ stackDelta: 0
+}, {
+ id: "dup",
+ min: 1,
+ stackDelta: 1
+}, {
+ id: "exch",
+ min: 2,
+ stackDelta: 0
+}, {
+ id: "index",
+ min: 2,
+ stackDelta: 0
+}, {
+ id: "roll",
+ min: 3,
+ stackDelta: -2
+}, null, null, null, {
+ id: "hflex",
+ min: 7,
+ resetStack: true
+}, {
+ id: "flex",
+ min: 13,
+ resetStack: true
+}, {
+ id: "hflex1",
+ min: 9,
+ resetStack: true
+}, {
+ id: "flex1",
+ min: 11,
+ resetStack: true
+}];
+class CFFParser {
+ constructor(file, properties, seacAnalysisEnabled) {
+ this.bytes = file.getBytes();
+ this.properties = properties;
+ this.seacAnalysisEnabled = !!seacAnalysisEnabled;
+ }
+ parse() {
+ const properties = this.properties;
+ const cff = new CFF(this.bytes.length);
+ this.cff = cff;
+ const header = this.parseHeader();
+ const nameIndex = this.parseIndex(header.endPos);
+ const topDictIndex = this.parseIndex(nameIndex.endPos);
+ const stringIndex = this.parseIndex(topDictIndex.endPos);
+ const globalSubrIndex = this.parseIndex(stringIndex.endPos);
+ const topDictParsed = this.parseDict(topDictIndex.obj.get(0));
+ const topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);
+ cff.header = header.obj;
+ cff.names = this.parseNameIndex(nameIndex.obj);
+ cff.strings = this.parseStringIndex(stringIndex.obj);
+ cff.topDict = topDict;
+ cff.globalSubrIndex = globalSubrIndex.obj;
+ this.parsePrivateDict(cff.topDict);
+ cff.isCIDFont = topDict.hasName("ROS");
+ const charStringOffset = topDict.getByName("CharStrings");
+ const charStringIndex = this.parseIndex(charStringOffset).obj;
+ cff.charStringCount = charStringIndex.count;
+ const fontMatrix = topDict.getByName("FontMatrix");
+ if (fontMatrix) {
+ properties.fontMatrix = fontMatrix;
+ }
+ let fontBBox = topDict.getByName("FontBBox");
+ const descriptorBBox = properties.bbox?.some(coord => coord !== 0) ? recoverSigned16BitBBox(properties.bbox) : null;
+ const cffBBoxHasUnsignedLowerLeft = fontBBox?.slice(0, 2).some(looksLikeUnsigned16BitNegative);
+ const cffBBoxHasUnsignedCoords = fontBBox?.some(looksLikeUnsigned16BitNegative);
+ if (fontBBox?.every(coord => coord === 0) && descriptorBBox) {
+ fontBBox = descriptorBBox;
+ topDict.setByName("FontBBox", fontBBox);
+ } else if (cffBBoxHasUnsignedCoords) {
+ const recoveredFontBBox = recoverSigned16BitBBox(fontBBox);
+ const descriptorCorroborates = descriptorBBox && properties.bbox.some(coord => coord < 0) && !properties.bbox.some(looksLikeUnsigned16BitNegative) && isArrayEqual(recoveredFontBBox, descriptorBBox);
+ if (descriptorCorroborates || cffBBoxHasUnsignedLowerLeft) {
+ fontBBox = descriptorCorroborates ? recoveredFontBBox : recoverSigned16BitBBox(fontBBox, true);
+ topDict.setByName("FontBBox", fontBBox);
+ }
+ }
+ if (fontBBox?.some(coord => coord !== 0)) {
+ properties.ascent = Math.max(fontBBox[3], fontBBox[1]);
+ properties.descent = Math.min(fontBBox[1], fontBBox[3]);
+ properties.ascentScaled = true;
+ }
+ let charset, encoding;
+ if (cff.isCIDFont) {
+ const fdArrayIndex = this.parseIndex(topDict.getByName("FDArray")).obj;
+ for (let i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
+ const dictRaw = fdArrayIndex.get(i);
+ const fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw), cff.strings);
+ this.parsePrivateDict(fontDict);
+ cff.fdArray.push(fontDict);
+ }
+ encoding = null;
+ charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, true);
+ cff.fdSelect = this.parseFDSelect(topDict.getByName("FDSelect"), charStringIndex.count);
+ } else {
+ charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, false);
+ encoding = this.parseEncoding(topDict.getByName("Encoding"), properties, cff.strings, charset.charset);
+ }
+ cff.charset = charset;
+ cff.encoding = encoding;
+ const charStringsAndSeacs = this.parseCharStrings({
+ charStrings: charStringIndex,
+ localSubrIndex: topDict.privateDict.subrsIndex,
+ globalSubrIndex: globalSubrIndex.obj,
+ fdSelect: cff.fdSelect,
+ fdArray: cff.fdArray,
+ privateDict: topDict.privateDict
+ });
+ cff.charStrings = charStringsAndSeacs.charStrings;
+ cff.seacs = charStringsAndSeacs.seacs;
+ cff.widths = charStringsAndSeacs.widths;
+ return cff;
+ }
+ parseHeader() {
+ let bytes = this.bytes;
+ const bytesLength = bytes.length;
+ let offset = 0;
+ while (offset < bytesLength && bytes[offset] !== 1) {
+ ++offset;
+ }
+ if (offset >= bytesLength) {
+ throw new FormatError("Invalid CFF header");
+ }
+ if (offset !== 0) {
+ info("cff data is shifted");
+ bytes = bytes.subarray(offset);
+ this.bytes = bytes;
+ }
+ const major = bytes[0];
+ const minor = bytes[1];
+ const hdrSize = bytes[2];
+ const offSize = bytes[3];
+ const header = new CFFHeader(major, minor, hdrSize, offSize);
+ return {
+ obj: header,
+ endPos: hdrSize
+ };
+ }
+ parseDict(dict) {
+ const view = new DataView(dict.buffer, dict.byteOffset, dict.bytesLength);
+ let pos = 0;
+ function parseOperand() {
+ let value = dict[pos++];
+ if (value === 30) {
+ return parseFloatOperand();
+ } else if (value === 28) {
+ value = view.getInt16(pos);
+ pos += 2;
+ return value;
+ } else if (value === 29) {
+ value = view.getInt32(pos);
+ pos += 4;
+ return value;
+ } else if (value >= 32 && value <= 246) {
+ return value - 139;
+ } else if (value >= 247 && value <= 250) {
+ return (value - 247) * 256 + dict[pos++] + 108;
+ } else if (value >= 251 && value <= 254) {
+ return -((value - 251) * 256) - dict[pos++] - 108;
+ }
+ warn(`CFFParser.parseDict: "${value}" is a reserved command.`);
+ return NaN;
+ }
+ function parseFloatOperand() {
+ let str = "";
+ const eof = 15;
+ const lookup = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "E", "E-", null, "-"];
+ const length = dict.length;
+ while (pos < length) {
+ const b = dict[pos++];
+ const b1 = b >> 4;
+ const b2 = b & 15;
+ if (b1 === eof) {
+ break;
+ }
+ str += lookup[b1];
+ if (b2 === eof) {
+ break;
+ }
+ str += lookup[b2];
+ }
+ return parseFloat(str);
+ }
+ let operands = [];
+ const entries = [];
+ pos = 0;
+ const end = dict.length;
+ while (pos < end) {
+ let b = dict[pos];
+ if (b <= 21) {
+ if (b === 12) {
+ b = b << 8 | dict[++pos];
+ }
+ entries.push([b, operands]);
+ operands = [];
+ ++pos;
+ } else {
+ operands.push(parseOperand());
+ }
+ }
+ return entries;
+ }
+ parseIndex(pos) {
+ const cffIndex = new CFFIndex();
+ const bytes = this.bytes;
+ const count = bytes[pos++] << 8 | bytes[pos++];
+ const offsets = [];
+ let end = pos;
+ let i, ii;
+ if (count !== 0) {
+ const offsetSize = bytes[pos++];
+ const startPos = pos + (count + 1) * offsetSize - 1;
+ for (i = 0, ii = count + 1; i < ii; ++i) {
+ let offset = 0;
+ for (let j = 0; j < offsetSize; ++j) {
+ offset <<= 8;
+ offset += bytes[pos++];
+ }
+ offsets.push(startPos + offset);
+ }
+ end = offsets[count];
+ }
+ for (i = 0, ii = offsets.length - 1; i < ii; ++i) {
+ const offsetStart = offsets[i];
+ const offsetEnd = offsets[i + 1];
+ cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
+ }
+ return {
+ obj: cffIndex,
+ endPos: end
+ };
+ }
+ parseNameIndex(index) {
+ const names = [];
+ for (let i = 0, ii = index.count; i < ii; ++i) {
+ const name = index.get(i);
+ names.push(bytesToString(name));
+ }
+ return names;
+ }
+ parseStringIndex(index) {
+ const strings = new CFFStrings();
+ for (let i = 0, ii = index.count; i < ii; ++i) {
+ const data = index.get(i);
+ strings.add(bytesToString(data));
+ }
+ return strings;
+ }
+ createDict(Type, dict, strings) {
+ const cffDict = new Type(strings);
+ for (const [key, value] of dict) {
+ cffDict.setByKey(key, value);
+ }
+ return cffDict;
+ }
+ parseCharString(state, data, localSubrIndex, globalSubrIndex) {
+ if (!data || state.callDepth > MAX_SUBR_NESTING) {
+ return false;
+ }
+ const view = new DataView(data.buffer, data.byteOffset, data.bytesLength);
+ let stackSize = state.stackSize;
+ const stack = state.stack;
+ let length = data.length;
+ for (let j = 0; j < length;) {
+ const value = data[j++];
+ let validationCommand = null;
+ if (value === 12) {
+ const q = data[j++];
+ if (q === 0) {
+ data[j - 2] = 139;
+ data[j - 1] = 22;
+ stackSize = 0;
+ } else {
+ validationCommand = CharstringValidationData12[q];
+ }
+ } else if (value === 28) {
+ stack[stackSize] = view.getInt16(j);
+ j += 2;
+ stackSize++;
+ } else if (value === 14) {
+ if (stackSize >= 4) {
+ stackSize -= 4;
+ if (this.seacAnalysisEnabled) {
+ state.seac = stack.slice(stackSize, stackSize + 4);
+ return false;
+ }
+ }
+ validationCommand = CharstringValidationData[value];
+ } else if (value >= 32 && value <= 246) {
+ stack[stackSize] = value - 139;
+ stackSize++;
+ } else if (value >= 247 && value <= 254) {
+ stack[stackSize] = value < 251 ? (value - 247 << 8) + data[j] + 108 : -(value - 251 << 8) - data[j] - 108;
+ j++;
+ stackSize++;
+ } else if (value === 255) {
+ stack[stackSize] = view.getInt32(j) / 65536;
+ j += 4;
+ stackSize++;
+ } else if (value === 19 || value === 20) {
+ state.hints += stackSize >> 1;
+ if (state.hints === 0) {
+ data.copyWithin(j - 1, j, -1);
+ j -= 1;
+ length -= 1;
+ continue;
+ }
+ j += state.hints + 7 >> 3;
+ stackSize %= 2;
+ validationCommand = CharstringValidationData[value];
+ } else if (value === 10 || value === 29) {
+ const subrsIndex = value === 10 ? localSubrIndex : globalSubrIndex;
+ if (!subrsIndex) {
+ validationCommand = CharstringValidationData[value];
+ warn("Missing subrsIndex for " + validationCommand.id);
+ return false;
+ }
+ let bias = 32768;
+ if (subrsIndex.count < 1240) {
+ bias = 107;
+ } else if (subrsIndex.count < 33900) {
+ bias = 1131;
+ }
+ const subrNumber = stack[--stackSize] + bias;
+ if (subrNumber < 0 || subrNumber >= subrsIndex.count || isNaN(subrNumber)) {
+ validationCommand = CharstringValidationData[value];
+ warn("Out of bounds subrIndex for " + validationCommand.id);
+ return false;
+ }
+ state.stackSize = stackSize;
+ state.callDepth++;
+ const valid = this.parseCharString(state, subrsIndex.get(subrNumber), localSubrIndex, globalSubrIndex);
+ if (!valid) {
+ return false;
+ }
+ state.callDepth--;
+ stackSize = state.stackSize;
+ continue;
+ } else if (value === 11) {
+ state.stackSize = stackSize;
+ return true;
+ } else if (value === 0 && j === data.length) {
+ data[j - 1] = 14;
+ validationCommand = CharstringValidationData[14];
+ } else if (value === 9) {
+ data.copyWithin(j - 1, j, -1);
+ j -= 1;
+ length -= 1;
+ continue;
+ } else {
+ validationCommand = CharstringValidationData[value];
+ }
+ if (validationCommand) {
+ if (validationCommand.stem) {
+ state.hints += stackSize >> 1;
+ if (value === 3 || value === 23) {
+ state.hasVStems = true;
+ } else if (state.hasVStems && (value === 1 || value === 18)) {
+ warn("CFF stem hints are in wrong order");
+ data[j - 1] = value === 1 ? 3 : 23;
+ }
+ }
+ if (stackSize < validationCommand.min) {
+ warn("Not enough parameters for " + validationCommand.id + "; actual: " + stackSize + ", expected: " + validationCommand.min);
+ if (stackSize === 0) {
+ data[j - 1] = 14;
+ return true;
+ }
+ return false;
+ }
+ if (state.firstStackClearing && validationCommand.stackClearing) {
+ state.firstStackClearing = false;
+ stackSize -= validationCommand.min;
+ if (stackSize >= 2 && validationCommand.stem) {
+ stackSize %= 2;
+ } else if (stackSize > 1) {
+ warn("Found too many parameters for stack-clearing command");
+ }
+ if (stackSize > 0) {
+ state.width = stack[stackSize - 1];
+ }
+ }
+ if ("stackDelta" in validationCommand) {
+ if ("stackFn" in validationCommand) {
+ validationCommand.stackFn(stack, stackSize);
+ }
+ stackSize += validationCommand.stackDelta;
+ } else if (validationCommand.stackClearing || validationCommand.resetStack) {
+ stackSize = 0;
+ }
+ }
+ }
+ if (length < data.length) {
+ data.fill(14, length);
+ }
+ state.stackSize = stackSize;
+ return true;
+ }
+ parseCharStrings({
+ charStrings,
+ localSubrIndex,
+ globalSubrIndex,
+ fdSelect,
+ fdArray,
+ privateDict
+ }) {
+ const seacs = [];
+ const widths = [];
+ const count = charStrings.count;
+ for (let i = 0; i < count; i++) {
+ const charstring = charStrings.get(i);
+ const state = {
+ callDepth: 0,
+ stackSize: 0,
+ stack: [],
+ hints: 0,
+ firstStackClearing: true,
+ seac: null,
+ width: null,
+ hasVStems: false
+ };
+ let valid = true;
+ let localSubrToUse = null;
+ let privateDictToUse = privateDict;
+ if (fdSelect && fdArray.length) {
+ const fdIndex = fdSelect.getFDIndex(i);
+ if (fdIndex === -1) {
+ warn("Glyph index is not in fd select.");
+ valid = false;
+ }
+ if (fdIndex >= fdArray.length) {
+ warn("Invalid fd index for glyph index.");
+ valid = false;
+ }
+ if (valid) {
+ privateDictToUse = fdArray[fdIndex].privateDict;
+ localSubrToUse = privateDictToUse.subrsIndex;
+ }
+ } else if (localSubrIndex) {
+ localSubrToUse = localSubrIndex;
+ }
+ valid &&= this.parseCharString(state, charstring, localSubrToUse, globalSubrIndex);
+ if (state.width !== null) {
+ const nominalWidth = privateDictToUse.getByName("nominalWidthX");
+ widths[i] = nominalWidth + state.width;
+ } else {
+ const defaultWidth = privateDictToUse.getByName("defaultWidthX");
+ widths[i] = defaultWidth;
+ }
+ if (state.seac !== null) {
+ seacs[i] = state.seac;
+ }
+ if (!valid) {
+ charStrings.set(i, new Uint8Array([14]));
+ }
+ }
+ return {
+ charStrings,
+ seacs,
+ widths
+ };
+ }
+ emptyPrivateDictionary(parentDict) {
+ const privateDict = this.createDict(CFFPrivateDict, [], parentDict.strings);
+ parentDict.setByKey(18, [0, 0]);
+ parentDict.privateDict = privateDict;
+ }
+ parsePrivateDict(parentDict) {
+ if (!parentDict.hasName("Private")) {
+ this.emptyPrivateDictionary(parentDict);
+ return;
+ }
+ const privateOffset = parentDict.getByName("Private");
+ if (!Array.isArray(privateOffset) || privateOffset.length !== 2) {
+ parentDict.removeByName("Private");
+ return;
+ }
+ const size = privateOffset[0];
+ const offset = privateOffset[1];
+ if (size === 0 || offset >= this.bytes.length) {
+ this.emptyPrivateDictionary(parentDict);
+ return;
+ }
+ if (offset + size > this.bytes.length) {
+ throw new FormatError("CFF Private DICT extends past end of font");
+ }
+ const privateDictEnd = offset + size;
+ const dictData = this.bytes.subarray(offset, privateDictEnd);
+ const dict = this.parseDict(dictData);
+ const privateDict = this.createDict(CFFPrivateDict, dict, parentDict.strings);
+ parentDict.privateDict = privateDict;
+ const blueScale = privateDict.getByName("BlueScale");
+ const blueShift = privateDict.getByName("BlueShift");
+ const blueFuzz = privateDict.getByName("BlueFuzz");
+ const expansionFactor = privateDict.getByName("ExpansionFactor");
+ if (blueScale === 0 && blueShift === 0 && blueFuzz === 0 && expansionFactor === 0) {
+ privateDict.setByName("BlueScale", DEFAULT_BLUE_SCALE);
+ privateDict.setByName("BlueShift", DEFAULT_BLUE_SHIFT);
+ privateDict.setByName("BlueFuzz", DEFAULT_BLUE_FUZZ);
+ }
+ if (expansionFactor === 0) {
+ privateDict.setByName("ExpansionFactor", DEFAULT_EXPANSION_FACTOR);
+ }
+ if (blueScale > 0) {
+ let maxZoneHeight = 0;
+ for (const zones of [privateDict.getByName("BlueValues"), privateDict.getByName("OtherBlues")]) {
+ if (!zones) {
+ continue;
+ }
+ for (let i = 1; i < zones.length; i += 2) {
+ if (zones[i] > maxZoneHeight) {
+ maxZoneHeight = zones[i];
+ }
+ }
+ }
+ if (maxZoneHeight > 0) {
+ const PRECISION = 1e5;
+ const lowerBound = 0.5 / maxZoneHeight;
+ const minBlueScale = lowerBound <= DEFAULT_BLUE_SCALE ? Math.ceil(lowerBound * PRECISION) / PRECISION : -Infinity;
+ const maxBlueScale = Math.floor(PRECISION / maxZoneHeight) / PRECISION;
+ const clamped = MathClamp(blueScale, minBlueScale, maxBlueScale);
+ if (clamped !== blueScale) {
+ privateDict.setByName("BlueScale", clamped);
+ }
+ }
+ }
+ if (!privateDict.getByName("Subrs")) {
+ return;
+ }
+ const subrsOffset = privateDict.getByName("Subrs");
+ const relativeOffset = offset + subrsOffset;
+ if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
+ this.emptyPrivateDictionary(parentDict);
+ return;
+ }
+ const subrsIndex = this.parseIndex(relativeOffset);
+ privateDict.subrsIndex = subrsIndex.obj;
+ }
+ parseCharsets(pos, length, strings, cid) {
+ if (pos === 0) {
+ return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE, ISOAdobeCharset);
+ } else if (pos === 1) {
+ return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT, ExpertCharset);
+ } else if (pos === 2) {
+ return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET, ExpertSubsetCharset);
+ }
+ const {
+ bytes
+ } = this;
+ const format = bytes[pos++];
+ const charset = [cid ? 0 : ".notdef"];
+ let id, count, i;
+ length -= 1;
+ switch (format) {
+ case 0:
+ for (i = 0; i < length; i++) {
+ id = bytes[pos++] << 8 | bytes[pos++];
+ charset.push(cid ? id : strings.get(id));
+ }
+ break;
+ case 1:
+ while (charset.length <= length) {
+ id = bytes[pos++] << 8 | bytes[pos++];
+ count = bytes[pos++];
+ for (i = 0; i <= count; i++) {
+ charset.push(cid ? id++ : strings.get(id++));
+ }
+ }
+ break;
+ case 2:
+ while (charset.length <= length) {
+ id = bytes[pos++] << 8 | bytes[pos++];
+ count = bytes[pos++] << 8 | bytes[pos++];
+ for (i = 0; i <= count; i++) {
+ charset.push(cid ? id++ : strings.get(id++));
+ }
+ }
+ break;
+ default:
+ throw new FormatError("Unknown charset format");
+ }
+ return new CFFCharset(false, format, charset);
+ }
+ parseEncoding(pos, properties, strings, charset) {
+ const encoding = Object.create(null);
+ const bytes = this.bytes;
+ let predefined = false;
+ let format, i, ii;
+ let raw = null;
+ function readSupplement() {
+ const supplementsCount = bytes[pos++];
+ for (i = 0; i < supplementsCount; i++) {
+ const code = bytes[pos++];
+ const sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
+ encoding[code] = charset.indexOf(strings.get(sid));
+ }
+ }
+ if (pos === 0 || pos === 1) {
+ predefined = true;
+ format = pos;
+ const baseEncoding = pos ? ExpertEncoding : StandardEncoding;
+ for (i = 0, ii = charset.length; i < ii; i++) {
+ const index = baseEncoding.indexOf(charset[i]);
+ if (index !== -1) {
+ encoding[index] = i;
+ }
+ }
+ } else {
+ const dataStart = pos;
+ format = bytes[pos++];
+ switch (format & 0x7f) {
+ case 0:
+ const glyphsCount = bytes[pos++];
+ for (i = 1; i <= glyphsCount; i++) {
+ encoding[bytes[pos++]] = i;
+ }
+ break;
+ case 1:
+ const rangesCount = bytes[pos++];
+ let gid = 1;
+ for (i = 0; i < rangesCount; i++) {
+ const start = bytes[pos++];
+ const left = bytes[pos++];
+ for (let j = start; j <= start + left; j++) {
+ encoding[j] = gid++;
+ }
+ }
+ break;
+ default:
+ throw new FormatError(`Unknown encoding format: ${format} in CFF`);
+ }
+ const dataEnd = pos;
+ if (format & 0x80) {
+ bytes[dataStart] &= 0x7f;
+ readSupplement();
+ }
+ raw = bytes.subarray(dataStart, dataEnd);
+ }
+ format &= 0x7f;
+ return new CFFEncoding(predefined, format, encoding, raw);
+ }
+ parseFDSelect(pos, length) {
+ const bytes = this.bytes;
+ const format = bytes[pos++];
+ const fdSelect = [];
+ let i;
+ switch (format) {
+ case 0:
+ for (i = 0; i < length; ++i) {
+ const id = bytes[pos++];
+ fdSelect.push(id);
+ }
+ break;
+ case 3:
+ const rangesCount = bytes[pos++] << 8 | bytes[pos++];
+ for (i = 0; i < rangesCount; ++i) {
+ let first = bytes[pos++] << 8 | bytes[pos++];
+ if (i === 0 && first !== 0) {
+ warn("parseFDSelect: The first range must have a first GID of 0" + " -- trying to recover.");
+ first = 0;
+ }
+ const fdIndex = bytes[pos++];
+ const next = bytes[pos] << 8 | bytes[pos + 1];
+ for (let j = first; j < next; ++j) {
+ fdSelect.push(fdIndex);
+ }
+ }
+ pos += 2;
+ break;
+ default:
+ throw new FormatError(`parseFDSelect: Unknown format "${format}".`);
+ }
+ if (fdSelect.length !== length) {
+ throw new FormatError("parseFDSelect: Invalid font data.");
+ }
+ return new CFFFDSelect(format, fdSelect);
+ }
+}
+class CFF {
+ header = null;
+ names = [];
+ topDict = null;
+ strings = new CFFStrings();
+ globalSubrIndex = null;
+ encoding = null;
+ charset = null;
+ charStrings = null;
+ fdArray = [];
+ fdSelect = null;
+ isCIDFont = false;
+ charStringCount = 0;
+ constructor(rawFileLength = 0) {
+ this.rawFileLength = rawFileLength;
+ }
+ duplicateFirstGlyph() {
+ if (this.charStrings.count >= 65535) {
+ warn("Not enough space in charstrings to duplicate first glyph.");
+ return;
+ }
+ const glyphZero = this.charStrings.get(0);
+ this.charStrings.add(glyphZero);
+ if (this.isCIDFont) {
+ this.fdSelect.fdSelect.push(this.fdSelect.fdSelect[0]);
+ }
+ }
+ hasGlyphId(id) {
+ if (id < 0 || id >= this.charStrings.count) {
+ return false;
+ }
+ const glyph = this.charStrings.get(id);
+ return glyph.length > 0;
+ }
+}
+class CFFHeader {
+ constructor(major, minor, hdrSize, offSize) {
+ this.major = major;
+ this.minor = minor;
+ this.hdrSize = hdrSize;
+ this.offSize = offSize;
+ }
+}
+class CFFStrings {
+ strings = [];
+ get(index) {
+ if (index >= 0 && index <= NUM_STANDARD_CFF_STRINGS - 1) {
+ return CFFStandardStrings[index];
+ }
+ if (index - NUM_STANDARD_CFF_STRINGS <= this.strings.length) {
+ return this.strings[index - NUM_STANDARD_CFF_STRINGS];
+ }
+ return CFFStandardStrings[0];
+ }
+ getSID(str) {
+ let index = CFFStandardStrings.indexOf(str);
+ if (index !== -1) {
+ return index;
+ }
+ index = this.strings.indexOf(str);
+ if (index !== -1) {
+ return index + NUM_STANDARD_CFF_STRINGS;
+ }
+ return -1;
+ }
+ add(value) {
+ this.strings.push(value);
+ }
+ get count() {
+ return this.strings.length;
+ }
+}
+class CFFIndex {
+ objects = [];
+ length = 0;
+ add(data) {
+ this.length += data.length;
+ this.objects.push(data);
+ }
+ set(index, data) {
+ this.length += data.length - this.objects[index].length;
+ this.objects[index] = data;
+ }
+ get(index) {
+ return this.objects[index];
+ }
+ get count() {
+ return this.objects.length;
+ }
+}
+class CFFDict {
+ constructor(tables, strings) {
+ this.keyToNameMap = tables.keyToNameMap;
+ this.nameToKeyMap = tables.nameToKeyMap;
+ this.defaults = tables.defaults;
+ this.types = tables.types;
+ this.opcodes = tables.opcodes;
+ this.order = tables.order;
+ this.strings = strings;
+ this.values = Object.create(null);
+ }
+ setByKey(key, value) {
+ if (!(key in this.keyToNameMap)) {
+ return false;
+ }
+ if (value.length === 0) {
+ return true;
+ }
+ for (const val of value) {
+ if (isNaN(val)) {
+ warn(`Invalid CFFDict value: "${value}" for key "${key}".`);
+ return true;
+ }
+ }
+ const type = this.types[key];
+ if (type === "num" || type === "sid" || type === "offset") {
+ value = value[0];
+ }
+ this.values[key] = value;
+ return true;
+ }
+ setByName(name, value) {
+ if (!(name in this.nameToKeyMap)) {
+ throw new FormatError(`Invalid dictionary name "${name}"`);
+ }
+ this.values[this.nameToKeyMap[name]] = value;
+ }
+ hasName(name) {
+ return this.nameToKeyMap[name] in this.values;
+ }
+ getByName(name) {
+ if (!(name in this.nameToKeyMap)) {
+ throw new FormatError(`Invalid dictionary name ${name}"`);
+ }
+ const key = this.nameToKeyMap[name];
+ if (!(key in this.values)) {
+ return this.defaults[key];
+ }
+ return this.values[key];
+ }
+ removeByName(name) {
+ delete this.values[this.nameToKeyMap[name]];
+ }
+ static createTables(layout) {
+ const tables = {
+ keyToNameMap: {},
+ nameToKeyMap: {},
+ defaults: {},
+ types: {},
+ opcodes: {},
+ order: []
+ };
+ for (const entry of layout) {
+ const key = Array.isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];
+ tables.keyToNameMap[key] = entry[1];
+ tables.nameToKeyMap[entry[1]] = key;
+ tables.types[key] = entry[2];
+ tables.defaults[key] = entry[3];
+ tables.opcodes[key] = Array.isArray(entry[0]) ? entry[0] : [entry[0]];
+ tables.order.push(key);
+ }
+ return tables;
+ }
+}
+const CFFTopDictLayout = [[[12, 30], "ROS", ["sid", "sid", "num"], null], [[12, 20], "SyntheticBase", "num", null], [0, "version", "sid", null], [1, "Notice", "sid", null], [[12, 0], "Copyright", "sid", null], [2, "FullName", "sid", null], [3, "FamilyName", "sid", null], [4, "Weight", "sid", null], [[12, 1], "isFixedPitch", "num", 0], [[12, 2], "ItalicAngle", "num", 0], [[12, 3], "UnderlinePosition", "num", -100], [[12, 4], "UnderlineThickness", "num", 50], [[12, 5], "PaintType", "num", 0], [[12, 6], "CharstringType", "num", 2], [[12, 7], "FontMatrix", ["num", "num", "num", "num", "num", "num"], [0.001, 0, 0, 0.001, 0, 0]], [13, "UniqueID", "num", null], [5, "FontBBox", ["num", "num", "num", "num"], [0, 0, 0, 0]], [[12, 8], "StrokeWidth", "num", 0], [14, "XUID", "array", null], [15, "charset", "offset", 0], [16, "Encoding", "offset", 0], [17, "CharStrings", "offset", 0], [18, "Private", ["offset", "offset"], null], [[12, 21], "PostScript", "sid", null], [[12, 22], "BaseFontName", "sid", null], [[12, 23], "BaseFontBlend", "delta", null], [[12, 31], "CIDFontVersion", "num", 0], [[12, 32], "CIDFontRevision", "num", 0], [[12, 33], "CIDFontType", "num", 0], [[12, 34], "CIDCount", "num", 8720], [[12, 35], "UIDBase", "num", null], [[12, 37], "FDSelect", "offset", null], [[12, 36], "FDArray", "offset", null], [[12, 38], "FontName", "sid", null]];
+class CFFTopDict extends CFFDict {
+ static get tables() {
+ return shadow(this, "tables", this.createTables(CFFTopDictLayout));
+ }
+ constructor(strings) {
+ super(CFFTopDict.tables, strings);
+ this.privateDict = null;
+ }
+}
+const CFFPrivateDictLayout = [[6, "BlueValues", "delta", null], [7, "OtherBlues", "delta", null], [8, "FamilyBlues", "delta", null], [9, "FamilyOtherBlues", "delta", null], [[12, 9], "BlueScale", "num", DEFAULT_BLUE_SCALE], [[12, 10], "BlueShift", "num", DEFAULT_BLUE_SHIFT], [[12, 11], "BlueFuzz", "num", DEFAULT_BLUE_FUZZ], [10, "StdHW", "num", null], [11, "StdVW", "num", null], [[12, 12], "StemSnapH", "delta", null], [[12, 13], "StemSnapV", "delta", null], [[12, 14], "ForceBold", "num", 0], [[12, 17], "LanguageGroup", "num", 0], [[12, 18], "ExpansionFactor", "num", DEFAULT_EXPANSION_FACTOR], [[12, 19], "initialRandomSeed", "num", 0], [20, "defaultWidthX", "num", 0], [21, "nominalWidthX", "num", 0], [19, "Subrs", "offset", null]];
+class CFFPrivateDict extends CFFDict {
+ static get tables() {
+ return shadow(this, "tables", this.createTables(CFFPrivateDictLayout));
+ }
+ constructor(strings) {
+ super(CFFPrivateDict.tables, strings);
+ this.subrsIndex = null;
+ }
+}
+const CFFCharsetPredefinedTypes = {
+ ISO_ADOBE: 0,
+ EXPERT: 1,
+ EXPERT_SUBSET: 2
+};
+class CFFCharset {
+ constructor(predefined, format, charset) {
+ this.predefined = predefined;
+ this.format = format;
+ this.charset = charset;
+ }
+}
+class CFFEncoding {
+ constructor(predefined, format, encoding, raw) {
+ this.predefined = predefined;
+ this.format = format;
+ this.encoding = encoding;
+ this.raw = raw;
+ }
+}
+class CFFFDSelect {
+ constructor(format, fdSelect) {
+ this.format = format;
+ this.fdSelect = fdSelect;
+ }
+ getFDIndex(glyphIndex) {
+ return glyphIndex < 0 || glyphIndex >= this.fdSelect.length ? -1 : this.fdSelect[glyphIndex];
+ }
+}
+class CFFOffsetTracker {
+ offsets = Object.create(null);
+ isTracking(key) {
+ return key in this.offsets;
+ }
+ track(key, location) {
+ if (key in this.offsets) {
+ throw new FormatError(`Already tracking location of ${key}`);
+ }
+ this.offsets[key] = location;
+ }
+ offset(value) {
+ for (const key in this.offsets) {
+ this.offsets[key] += value;
+ }
+ }
+ setEntryLocation(key, values, output) {
+ if (!(key in this.offsets)) {
+ throw new FormatError(`Not tracking location of ${key}`);
+ }
+ const data = output.data;
+ const dataOffset = this.offsets[key];
+ const size = 5;
+ for (let i = 0, ii = values.length; i < ii; ++i) {
+ const offset0 = i * size + dataOffset;
+ const offset1 = offset0 + 1;
+ const offset2 = offset0 + 2;
+ const offset3 = offset0 + 3;
+ const offset4 = offset0 + 4;
+ if (data[offset0] !== 0x1d || data[offset1] !== 0 || data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {
+ throw new FormatError("writing to an offset that is not empty");
+ }
+ const value = values[i];
+ data[offset0] = 0x1d;
+ data[offset1] = value >> 24 & 0xff;
+ data[offset2] = value >> 16 & 0xff;
+ data[offset3] = value >> 8 & 0xff;
+ data[offset4] = value & 0xff;
+ }
+ }
+}
+class CFFCompiler {
+ constructor(cff) {
+ this.cff = cff;
+ }
+ compile() {
+ const cff = this.cff;
+ const output = new DataBuilder({
+ minLength: cff.rawFileLength
+ });
+ const header = this.compileHeader(cff.header);
+ output.setArray(header);
+ const nameIndex = this.compileNameIndex(cff.names);
+ output.setArray(nameIndex);
+ if (cff.isCIDFont) {
+ if (cff.topDict.hasName("FontMatrix")) {
+ const base = cff.topDict.getByName("FontMatrix");
+ cff.topDict.removeByName("FontMatrix");
+ for (const subDict of cff.fdArray) {
+ let matrix = base.slice(0);
+ if (subDict.hasName("FontMatrix")) {
+ matrix = Util.transform(matrix, subDict.getByName("FontMatrix"));
+ }
+ subDict.setByName("FontMatrix", matrix);
+ }
+ }
+ }
+ const xuid = cff.topDict.getByName("XUID");
+ if (xuid?.length > 16) {
+ cff.topDict.removeByName("XUID");
+ }
+ cff.topDict.setByName("charset", 0);
+ let compiled = this.compileTopDicts([cff.topDict], output.length, cff.isCIDFont);
+ output.setArray(compiled.output);
+ const topDictTracker = compiled.trackers[0];
+ const stringIndex = this.compileStringIndex(cff.strings.strings);
+ output.setArray(stringIndex);
+ const globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
+ output.setArray(globalSubrIndex);
+ if (cff.encoding && cff.topDict.hasName("Encoding")) {
+ if (cff.encoding.predefined) {
+ topDictTracker.setEntryLocation("Encoding", [cff.encoding.format], output);
+ } else {
+ const encoding = this.compileEncoding(cff.encoding);
+ topDictTracker.setEntryLocation("Encoding", [output.length], output);
+ output.setArray(encoding);
+ }
+ }
+ const charset = this.compileCharset(cff.charset, cff.charStrings.count, cff.strings, cff.isCIDFont);
+ topDictTracker.setEntryLocation("charset", [output.length], output);
+ output.setArray(charset);
+ const charStrings = this.compileCharStrings(cff.charStrings);
+ topDictTracker.setEntryLocation("CharStrings", [output.length], output);
+ output.setArray(charStrings);
+ if (cff.isCIDFont) {
+ topDictTracker.setEntryLocation("FDSelect", [output.length], output);
+ const fdSelect = this.compileFDSelect(cff.fdSelect);
+ output.setArray(fdSelect);
+ compiled = this.compileTopDicts(cff.fdArray, output.length, true);
+ topDictTracker.setEntryLocation("FDArray", [output.length], output);
+ output.setArray(compiled.output);
+ const fontDictTrackers = compiled.trackers;
+ this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
+ }
+ this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
+ output.setArray([0]);
+ return output.data;
+ }
+ encodeNumber(value) {
+ if (Number.isInteger(value)) {
+ return this.encodeInteger(value);
+ }
+ return this.encodeFloat(value);
+ }
+ static get EncodeFloatRegExp() {
+ return shadow(this, "EncodeFloatRegExp", /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/);
+ }
+ encodeFloat(num) {
+ let value = num.toString();
+ const m = CFFCompiler.EncodeFloatRegExp.exec(value);
+ if (m) {
+ const epsilon = parseFloat("1e" + ((m[2] ? +m[2] : 0) + m[1].length));
+ value = (Math.round(num * epsilon) / epsilon).toString();
+ }
+ let nibbles = "";
+ let i, ii;
+ for (i = 0, ii = value.length; i < ii; ++i) {
+ const a = value[i];
+ if (a === "e") {
+ nibbles += value[++i] === "-" ? "c" : "b";
+ } else if (a === ".") {
+ nibbles += "a";
+ } else if (a === "-") {
+ nibbles += "e";
+ } else {
+ nibbles += a;
+ }
+ }
+ nibbles += nibbles.length & 1 ? "f" : "ff";
+ const out = [30];
+ for (i = 0, ii = nibbles.length; i < ii; i += 2) {
+ out.push(parseInt(nibbles.substring(i, i + 2), 16));
+ }
+ return out;
+ }
+ encodeInteger(value) {
+ let code;
+ if (value >= -107 && value <= 107) {
+ code = [value + 139];
+ } else if (value >= 108 && value <= 1131) {
+ value -= 108;
+ code = [(value >> 8) + 247, value & 0xff];
+ } else if (value >= -1131 && value <= -108) {
+ value = -value - 108;
+ code = [(value >> 8) + 251, value & 0xff];
+ } else if (value >= -32768 && value <= 32767) {
+ code = [0x1c, value >> 8 & 0xff, value & 0xff];
+ } else {
+ code = [0x1d, value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff];
+ }
+ return code;
+ }
+ compileHeader(header) {
+ return [header.major, header.minor, 4, header.offSize];
+ }
+ compileNameIndex(names) {
+ const nameIndex = new CFFIndex();
+ for (const name of names) {
+ const length = Math.min(name.length, 127);
+ let sanitizedName = new Array(length);
+ for (let j = 0; j < length; j++) {
+ let char = name[j];
+ if (char < "!" || char > "~" || char === "[" || char === "]" || char === "(" || char === ")" || char === "{" || char === "}" || char === "<" || char === ">" || char === "/" || char === "%") {
+ char = "_";
+ }
+ sanitizedName[j] = char;
+ }
+ sanitizedName = sanitizedName.join("");
+ if (sanitizedName === "") {
+ sanitizedName = "Bad_Font_Name";
+ }
+ nameIndex.add(stringToBytes(sanitizedName));
+ }
+ return this.compileIndex(nameIndex);
+ }
+ compileTopDicts(dicts, length, removeCidKeys) {
+ const fontDictTrackers = [];
+ let fdArrayIndex = new CFFIndex();
+ for (const fontDict of dicts) {
+ if (removeCidKeys) {
+ fontDict.removeByName("CIDFontVersion");
+ fontDict.removeByName("CIDFontRevision");
+ fontDict.removeByName("CIDFontType");
+ fontDict.removeByName("CIDCount");
+ fontDict.removeByName("UIDBase");
+ }
+ const fontDictTracker = new CFFOffsetTracker();
+ const fontDictData = this.compileDict(fontDict, fontDictTracker);
+ fontDictTrackers.push(fontDictTracker);
+ fdArrayIndex.add(fontDictData);
+ fontDictTracker.offset(length);
+ }
+ fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
+ return {
+ trackers: fontDictTrackers,
+ output: fdArrayIndex
+ };
+ }
+ compilePrivateDicts(dicts, trackers, output) {
+ for (let i = 0, ii = dicts.length; i < ii; ++i) {
+ const fontDict = dicts[i];
+ const privateDict = fontDict.privateDict;
+ if (!privateDict || !fontDict.hasName("Private")) {
+ throw new FormatError("There must be a private dictionary.");
+ }
+ const privateDictTracker = new CFFOffsetTracker();
+ const privateDictData = this.compileDict(privateDict, privateDictTracker);
+ let outputLength = output.length;
+ privateDictTracker.offset(outputLength);
+ if (!privateDictData.length) {
+ outputLength = 0;
+ }
+ trackers[i].setEntryLocation("Private", [privateDictData.length, outputLength], output);
+ output.setArray(privateDictData);
+ if (privateDict.subrsIndex && privateDict.hasName("Subrs")) {
+ const subrs = this.compileIndex(privateDict.subrsIndex);
+ privateDictTracker.setEntryLocation("Subrs", [privateDictData.length], output);
+ output.setArray(subrs);
+ }
+ }
+ }
+ compileDict(dict, offsetTracker) {
+ const out = [];
+ for (const key of dict.order) {
+ if (!(key in dict.values)) {
+ continue;
+ }
+ let values = dict.values[key];
+ let types = dict.types[key];
+ if (!Array.isArray(types)) {
+ types = [types];
+ }
+ if (!Array.isArray(values)) {
+ values = [values];
+ }
+ if (values.length === 0) {
+ continue;
+ }
+ for (let j = 0, jj = types.length; j < jj; ++j) {
+ const type = types[j];
+ const value = values[j];
+ switch (type) {
+ case "num":
+ case "sid":
+ out.push(...this.encodeNumber(value));
+ break;
+ case "offset":
+ const name = dict.keyToNameMap[key];
+ if (!offsetTracker.isTracking(name)) {
+ offsetTracker.track(name, out.length);
+ }
+ out.push(0x1d, 0, 0, 0, 0);
+ break;
+ case "array":
+ case "delta":
+ out.push(...this.encodeNumber(value));
+ for (let k = 1, kk = values.length; k < kk; ++k) {
+ out.push(...this.encodeNumber(values[k]));
+ }
+ break;
+ default:
+ throw new FormatError(`Unknown data type of ${type}`);
+ }
+ }
+ out.push(...dict.opcodes[key]);
+ }
+ return out;
+ }
+ compileStringIndex(strings) {
+ const stringIndex = new CFFIndex();
+ for (const string of strings) {
+ stringIndex.add(stringToBytes(string));
+ }
+ return this.compileIndex(stringIndex);
+ }
+ compileCharStrings(charStrings) {
+ const charStringsIndex = new CFFIndex();
+ for (let i = 0; i < charStrings.count; i++) {
+ const glyph = charStrings.get(i);
+ if (glyph.length === 0) {
+ charStringsIndex.add(new Uint8Array([0x8b, 0x0e]));
+ continue;
+ }
+ charStringsIndex.add(glyph);
+ }
+ return this.compileIndex(charStringsIndex);
+ }
+ compileCharset(charset, numGlyphs, strings, isCIDFont) {
+ let out;
+ const numGlyphsLessNotDef = numGlyphs - 1;
+ if (isCIDFont) {
+ const nLeft = numGlyphsLessNotDef - 1;
+ out = new Uint8Array([2, 0, 1, nLeft >> 8 & 0xff, nLeft & 0xff]);
+ } else {
+ const length = 1 + numGlyphsLessNotDef * 2;
+ out = new Uint8Array(length);
+ let charsetIndex = 0;
+ const numCharsets = charset.charset.length;
+ let warned = false;
+ for (let i = 1; i < out.length; i += 2) {
+ let sid = 0;
+ if (charsetIndex < numCharsets) {
+ const name = charset.charset[charsetIndex++];
+ sid = strings.getSID(name);
+ if (sid === -1) {
+ sid = 0;
+ if (!warned) {
+ warned = true;
+ warn(`Couldn't find ${name} in CFF strings`);
+ }
+ }
+ }
+ out[i] = sid >> 8 & 0xff;
+ out[i + 1] = sid & 0xff;
+ }
+ }
+ return out;
+ }
+ compileEncoding(encoding) {
+ return encoding.raw;
+ }
+ compileFDSelect(fdSelect) {
+ const format = fdSelect.format;
+ let out, i;
+ switch (format) {
+ case 0:
+ out = new Uint8Array(1 + fdSelect.fdSelect.length);
+ out[0] = format;
+ out.set(fdSelect.fdSelect, 1);
+ break;
+ case 3:
+ const start = 0;
+ let lastFD = fdSelect.fdSelect[0];
+ const ranges = [format, 0, 0, start >> 8 & 0xff, start & 0xff, lastFD];
+ for (i = 1; i < fdSelect.fdSelect.length; i++) {
+ const currentFD = fdSelect.fdSelect[i];
+ if (currentFD !== lastFD) {
+ ranges.push(i >> 8 & 0xff, i & 0xff, currentFD);
+ lastFD = currentFD;
+ }
+ }
+ const numRanges = (ranges.length - 3) / 3;
+ ranges[1] = numRanges >> 8 & 0xff;
+ ranges[2] = numRanges & 0xff;
+ ranges.push(i >> 8 & 0xff, i & 0xff);
+ out = new Uint8Array(ranges);
+ break;
+ }
+ return out;
+ }
+ compileIndex(index, trackers = []) {
+ const objects = index.objects;
+ const count = objects.length;
+ if (count === 0) {
+ return new Uint8Array(2);
+ }
+ let lastOffset = 1,
+ i;
+ for (i = 0; i < count; ++i) {
+ lastOffset += objects[i].length;
+ }
+ let offsetSize;
+ if (lastOffset < 0x100) {
+ offsetSize = 1;
+ } else if (lastOffset < 0x10000) {
+ offsetSize = 2;
+ } else if (lastOffset < 0x1000000) {
+ offsetSize = 3;
+ } else {
+ offsetSize = 4;
+ }
+ const data = new Uint8Array(2 + offsetSize * (count + 1) + lastOffset);
+ let pos = 0;
+ data[pos++] = count >> 8 & 0xff;
+ data[pos++] = count & 0xff;
+ data[pos++] = offsetSize;
+ let relativeOffset = 1;
+ for (i = 0; i < count + 1; i++) {
+ if (offsetSize === 1) {
+ data[pos++] = relativeOffset & 0xff;
+ } else if (offsetSize === 2) {
+ data[pos++] = relativeOffset >> 8 & 0xff;
+ data[pos++] = relativeOffset & 0xff;
+ } else if (offsetSize === 3) {
+ data[pos++] = relativeOffset >> 16 & 0xff;
+ data[pos++] = relativeOffset >> 8 & 0xff;
+ data[pos++] = relativeOffset & 0xff;
+ } else {
+ data[pos++] = relativeOffset >>> 24 & 0xff;
+ data[pos++] = relativeOffset >> 16 & 0xff;
+ data[pos++] = relativeOffset >> 8 & 0xff;
+ data[pos++] = relativeOffset & 0xff;
+ }
+ if (objects[i]) {
+ relativeOffset += objects[i].length;
+ }
+ }
+ for (i = 0; i < count; i++) {
+ trackers[i]?.offset(pos);
+ data.set(objects[i], pos);
+ pos += objects[i].length;
+ }
+ return data;
+ }
+}
+
+;// ./src/core/standard_fonts.js
+
+
+
+const getStdFontMap = getLookupTableFactory(function (t) {
+ t["Times-Roman"] = "Times-Roman";
+ t.Helvetica = "Helvetica";
+ t.Courier = "Courier";
+ t.Symbol = "Symbol";
+ t["Times-Bold"] = "Times-Bold";
+ t["Helvetica-Bold"] = "Helvetica-Bold";
+ t["Courier-Bold"] = "Courier-Bold";
+ t.ZapfDingbats = "ZapfDingbats";
+ t["Times-Italic"] = "Times-Italic";
+ t["Helvetica-Oblique"] = "Helvetica-Oblique";
+ t["Courier-Oblique"] = "Courier-Oblique";
+ t["Times-BoldItalic"] = "Times-BoldItalic";
+ t["Helvetica-BoldOblique"] = "Helvetica-BoldOblique";
+ t["Courier-BoldOblique"] = "Courier-BoldOblique";
+ t.ArialNarrow = "Helvetica";
+ t["ArialNarrow-Bold"] = "Helvetica-Bold";
+ t["ArialNarrow-BoldItalic"] = "Helvetica-BoldOblique";
+ t["ArialNarrow-Italic"] = "Helvetica-Oblique";
+ t.ArialBlack = "Helvetica";
+ t["ArialBlack-Bold"] = "Helvetica-Bold";
+ t["ArialBlack-BoldItalic"] = "Helvetica-BoldOblique";
+ t["ArialBlack-Italic"] = "Helvetica-Oblique";
+ t["Arial-Black"] = "Helvetica";
+ t["Arial-Black-Bold"] = "Helvetica-Bold";
+ t["Arial-Black-BoldItalic"] = "Helvetica-BoldOblique";
+ t["Arial-Black-Italic"] = "Helvetica-Oblique";
+ t.Arial = "Helvetica";
+ t["Arial-Bold"] = "Helvetica-Bold";
+ t["Arial-BoldItalic"] = "Helvetica-BoldOblique";
+ t["Arial-Italic"] = "Helvetica-Oblique";
+ t.ArialMT = "Helvetica";
+ t["Arial-BoldItalicMT"] = "Helvetica-BoldOblique";
+ t["Arial-BoldMT"] = "Helvetica-Bold";
+ t["Arial-ItalicMT"] = "Helvetica-Oblique";
+ t["Arial-BoldItalicMT-BoldItalic"] = "Helvetica-BoldOblique";
+ t["Arial-BoldMT-Bold"] = "Helvetica-Bold";
+ t["Arial-ItalicMT-Italic"] = "Helvetica-Oblique";
+ t.ArialUnicodeMS = "Helvetica";
+ t["ArialUnicodeMS-Bold"] = "Helvetica-Bold";
+ t["ArialUnicodeMS-BoldItalic"] = "Helvetica-BoldOblique";
+ t["ArialUnicodeMS-Italic"] = "Helvetica-Oblique";
+ t["Courier-BoldItalic"] = "Courier-BoldOblique";
+ t["Courier-Italic"] = "Courier-Oblique";
+ t.CourierNew = "Courier";
+ t["CourierNew-Bold"] = "Courier-Bold";
+ t["CourierNew-BoldItalic"] = "Courier-BoldOblique";
+ t["CourierNew-Italic"] = "Courier-Oblique";
+ t["CourierNewPS-BoldItalicMT"] = "Courier-BoldOblique";
+ t["CourierNewPS-BoldMT"] = "Courier-Bold";
+ t["CourierNewPS-ItalicMT"] = "Courier-Oblique";
+ t.CourierNewPSMT = "Courier";
+ t["Helvetica-BoldItalic"] = "Helvetica-BoldOblique";
+ t["Helvetica-Italic"] = "Helvetica-Oblique";
+ t["HelveticaLTStd-Bold"] = "Helvetica-Bold";
+ t["Symbol-Bold"] = "Symbol";
+ t["Symbol-BoldItalic"] = "Symbol";
+ t["Symbol-Italic"] = "Symbol";
+ t.TimesNewRoman = "Times-Roman";
+ t["TimesNewRoman-Bold"] = "Times-Bold";
+ t["TimesNewRoman-BoldItalic"] = "Times-BoldItalic";
+ t["TimesNewRoman-Italic"] = "Times-Italic";
+ t.TimesNewRomanPS = "Times-Roman";
+ t["TimesNewRomanPS-Bold"] = "Times-Bold";
+ t["TimesNewRomanPS-BoldItalic"] = "Times-BoldItalic";
+ t["TimesNewRomanPS-BoldItalicMT"] = "Times-BoldItalic";
+ t["TimesNewRomanPS-BoldMT"] = "Times-Bold";
+ t["TimesNewRomanPS-Italic"] = "Times-Italic";
+ t["TimesNewRomanPS-ItalicMT"] = "Times-Italic";
+ t.TimesNewRomanPSMT = "Times-Roman";
+ t["TimesNewRomanPSMT-Bold"] = "Times-Bold";
+ t["TimesNewRomanPSMT-BoldItalic"] = "Times-BoldItalic";
+ t["TimesNewRomanPSMT-Italic"] = "Times-Italic";
+});
+const getFontNameToFileMap = getLookupTableFactory(function (t) {
+ t.Courier = "FoxitFixed.pfb";
+ t["Courier-Bold"] = "FoxitFixedBold.pfb";
+ t["Courier-BoldOblique"] = "FoxitFixedBoldItalic.pfb";
+ t["Courier-Oblique"] = "FoxitFixedItalic.pfb";
+ t.Helvetica = "LiberationSans-Regular.ttf";
+ t["Helvetica-Bold"] = "LiberationSans-Bold.ttf";
+ t["Helvetica-BoldOblique"] = "LiberationSans-BoldItalic.ttf";
+ t["Helvetica-Oblique"] = "LiberationSans-Italic.ttf";
+ t["Times-Roman"] = "FoxitSerif.pfb";
+ t["Times-Bold"] = "FoxitSerifBold.pfb";
+ t["Times-BoldItalic"] = "FoxitSerifBoldItalic.pfb";
+ t["Times-Italic"] = "FoxitSerifItalic.pfb";
+ t.Symbol = "FoxitSymbol.pfb";
+ t.ZapfDingbats = "FoxitDingbats.pfb";
+ t["LiberationSans-Regular"] = "LiberationSans-Regular.ttf";
+ t["LiberationSans-Bold"] = "LiberationSans-Bold.ttf";
+ t["LiberationSans-Italic"] = "LiberationSans-Italic.ttf";
+ t["LiberationSans-BoldItalic"] = "LiberationSans-BoldItalic.ttf";
+});
+const getNonStdFontMap = getLookupTableFactory(function (t) {
+ t.Calibri = "Helvetica";
+ t["Calibri-Bold"] = "Helvetica-Bold";
+ t["Calibri-BoldItalic"] = "Helvetica-BoldOblique";
+ t["Calibri-Italic"] = "Helvetica-Oblique";
+ t.CenturyGothic = "Helvetica";
+ t["CenturyGothic-Bold"] = "Helvetica-Bold";
+ t["CenturyGothic-BoldItalic"] = "Helvetica-BoldOblique";
+ t["CenturyGothic-Italic"] = "Helvetica-Oblique";
+ t.ComicSansMS = "Comic Sans MS";
+ t["ComicSansMS-Bold"] = "Comic Sans MS-Bold";
+ t["ComicSansMS-BoldItalic"] = "Comic Sans MS-BoldItalic";
+ t["ComicSansMS-Italic"] = "Comic Sans MS-Italic";
+ t.GillSansMT = "Helvetica";
+ t["GillSansMT-Bold"] = "Helvetica-Bold";
+ t["GillSansMT-BoldItalic"] = "Helvetica-BoldOblique";
+ t["GillSansMT-Italic"] = "Helvetica-Oblique";
+ t.Impact = "Helvetica";
+ t["ItcSymbol-Bold"] = "Helvetica-Bold";
+ t["ItcSymbol-BoldItalic"] = "Helvetica-BoldOblique";
+ t["ItcSymbol-Book"] = "Helvetica";
+ t["ItcSymbol-BookItalic"] = "Helvetica-Oblique";
+ t["ItcSymbol-Medium"] = "Helvetica";
+ t["ItcSymbol-MediumItalic"] = "Helvetica-Oblique";
+ t.LucidaConsole = "Courier";
+ t["LucidaConsole-Bold"] = "Courier-Bold";
+ t["LucidaConsole-BoldItalic"] = "Courier-BoldOblique";
+ t["LucidaConsole-Italic"] = "Courier-Oblique";
+ t["LucidaSans-Demi"] = "Helvetica-Bold";
+ t["MS-Gothic"] = "MS Gothic";
+ t["MS-Gothic-Bold"] = "MS Gothic-Bold";
+ t["MS-Gothic-BoldItalic"] = "MS Gothic-BoldItalic";
+ t["MS-Gothic-Italic"] = "MS Gothic-Italic";
+ t["MS-Mincho"] = "MS Mincho";
+ t["MS-Mincho-Bold"] = "MS Mincho-Bold";
+ t["MS-Mincho-BoldItalic"] = "MS Mincho-BoldItalic";
+ t["MS-Mincho-Italic"] = "MS Mincho-Italic";
+ t["MS-PGothic"] = "MS PGothic";
+ t["MS-PGothic-Bold"] = "MS PGothic-Bold";
+ t["MS-PGothic-BoldItalic"] = "MS PGothic-BoldItalic";
+ t["MS-PGothic-Italic"] = "MS PGothic-Italic";
+ t["MS-PMincho"] = "MS PMincho";
+ t["MS-PMincho-Bold"] = "MS PMincho-Bold";
+ t["MS-PMincho-BoldItalic"] = "MS PMincho-BoldItalic";
+ t["MS-PMincho-Italic"] = "MS PMincho-Italic";
+ t.NuptialScript = "Times-Italic";
+ t.SegoeUISymbol = "Helvetica";
+ t.TrebuchetMS = "Helvetica";
+ t["TrebuchetMS-Bold"] = "Helvetica-Bold";
+ t["TrebuchetMS-BoldItalic"] = "Helvetica-BoldOblique";
+ t["TrebuchetMS-Italic"] = "Helvetica-Oblique";
+});
+const getSerifFonts = getLookupTableFactory(function (t) {
+ t["Adobe Jenson"] = true;
+ t["Adobe Text"] = true;
+ t.Albertus = true;
+ t.Aldus = true;
+ t.Alexandria = true;
+ t.Algerian = true;
+ t["American Typewriter"] = true;
+ t.Antiqua = true;
+ t.Apex = true;
+ t.Arno = true;
+ t.Aster = true;
+ t.Aurora = true;
+ t.Baskerville = true;
+ t.Bell = true;
+ t.Bembo = true;
+ t["Bembo Schoolbook"] = true;
+ t.Benguiat = true;
+ t["Berkeley Old Style"] = true;
+ t["Bernhard Modern"] = true;
+ t["Berthold City"] = true;
+ t.Bodoni = true;
+ t["Bauer Bodoni"] = true;
+ t["Book Antiqua"] = true;
+ t.Bookman = true;
+ t["Bordeaux Roman"] = true;
+ t["Californian FB"] = true;
+ t.Calisto = true;
+ t.Calvert = true;
+ t.Capitals = true;
+ t.Cambria = true;
+ t.Cartier = true;
+ t.Caslon = true;
+ t.Catull = true;
+ t.Centaur = true;
+ t["Century Old Style"] = true;
+ t["Century Schoolbook"] = true;
+ t.Chaparral = true;
+ t["Charis SIL"] = true;
+ t.Cheltenham = true;
+ t["Cholla Slab"] = true;
+ t.Clarendon = true;
+ t.Clearface = true;
+ t.Cochin = true;
+ t.Colonna = true;
+ t["Computer Modern"] = true;
+ t["Concrete Roman"] = true;
+ t.Constantia = true;
+ t["Cooper Black"] = true;
+ t.Corona = true;
+ t.Ecotype = true;
+ t.Egyptienne = true;
+ t.Elephant = true;
+ t.Excelsior = true;
+ t.Fairfield = true;
+ t["FF Scala"] = true;
+ t.Folkard = true;
+ t.Footlight = true;
+ t.FreeSerif = true;
+ t["Friz Quadrata"] = true;
+ t.Garamond = true;
+ t.Gentium = true;
+ t.Georgia = true;
+ t.Gloucester = true;
+ t["Goudy Old Style"] = true;
+ t["Goudy Schoolbook"] = true;
+ t["Goudy Pro Font"] = true;
+ t.Granjon = true;
+ t["Guardian Egyptian"] = true;
+ t.Heather = true;
+ t.Hercules = true;
+ t["High Tower Text"] = true;
+ t.Hiroshige = true;
+ t["Hoefler Text"] = true;
+ t["Humana Serif"] = true;
+ t.Imprint = true;
+ t["Ionic No. 5"] = true;
+ t.Janson = true;
+ t.Joanna = true;
+ t.Korinna = true;
+ t.Lexicon = true;
+ t.LiberationSerif = true;
+ t["Liberation Serif"] = true;
+ t["Linux Libertine"] = true;
+ t.Literaturnaya = true;
+ t.Lucida = true;
+ t["Lucida Bright"] = true;
+ t.Melior = true;
+ t.Memphis = true;
+ t.Miller = true;
+ t.Minion = true;
+ t.Modern = true;
+ t["Mona Lisa"] = true;
+ t["Mrs Eaves"] = true;
+ t["MS Serif"] = true;
+ t["Museo Slab"] = true;
+ t["New York"] = true;
+ t["Nimbus Roman"] = true;
+ t["NPS Rawlinson Roadway"] = true;
+ t.NuptialScript = true;
+ t.Palatino = true;
+ t.Perpetua = true;
+ t.Plantin = true;
+ t["Plantin Schoolbook"] = true;
+ t.Playbill = true;
+ t["Poor Richard"] = true;
+ t["Rawlinson Roadway"] = true;
+ t.Renault = true;
+ t.Requiem = true;
+ t.Rockwell = true;
+ t.Roman = true;
+ t["Rotis Serif"] = true;
+ t.Sabon = true;
+ t.Scala = true;
+ t.Seagull = true;
+ t.Sistina = true;
+ t.Souvenir = true;
+ t.STIX = true;
+ t["Stone Informal"] = true;
+ t["Stone Serif"] = true;
+ t.Sylfaen = true;
+ t.Times = true;
+ t.Trajan = true;
+ t["Trinité"] = true;
+ t["Trump Mediaeval"] = true;
+ t.Utopia = true;
+ t["Vale Type"] = true;
+ t["Bitstream Vera"] = true;
+ t["Vera Serif"] = true;
+ t.Versailles = true;
+ t.Wanted = true;
+ t.Weiss = true;
+ t["Wide Latin"] = true;
+ t.Windsor = true;
+ t.XITS = true;
+});
+const getSymbolsFonts = getLookupTableFactory(function (t) {
+ t.Dingbats = true;
+ t.Symbol = true;
+ t.ZapfDingbats = true;
+ t.Wingdings = true;
+ t["Wingdings-Bold"] = true;
+ t["Wingdings-Regular"] = true;
+});
+const getGlyphMapForMacOrderedFonts = getLookupTableFactory(function (t) {
+ const glyphsUnicode = getGlyphsUnicode();
+ t[2] = 10;
+ for (let gid = 3; gid < MacStandardGlyphOrdering.length; gid++) {
+ const unicode = glyphsUnicode[MacStandardGlyphOrdering[gid]];
+ if (unicode !== undefined) {
+ t[gid] = unicode;
+ }
+ }
+});
+const getGlyphMapForStandardFonts = getLookupTableFactory(function (t) {
+ t[2] = 10;
+ t[3] = 32;
+ t[4] = 33;
+ t[5] = 34;
+ t[6] = 35;
+ t[7] = 36;
+ t[8] = 37;
+ t[9] = 38;
+ t[10] = 39;
+ t[11] = 40;
+ t[12] = 41;
+ t[13] = 42;
+ t[14] = 43;
+ t[15] = 44;
+ t[16] = 45;
+ t[17] = 46;
+ t[18] = 47;
+ t[19] = 48;
+ t[20] = 49;
+ t[21] = 50;
+ t[22] = 51;
+ t[23] = 52;
+ t[24] = 53;
+ t[25] = 54;
+ t[26] = 55;
+ t[27] = 56;
+ t[28] = 57;
+ t[29] = 58;
+ t[30] = 894;
+ t[31] = 60;
+ t[32] = 61;
+ t[33] = 62;
+ t[34] = 63;
+ t[35] = 64;
+ t[36] = 65;
+ t[37] = 66;
+ t[38] = 67;
+ t[39] = 68;
+ t[40] = 69;
+ t[41] = 70;
+ t[42] = 71;
+ t[43] = 72;
+ t[44] = 73;
+ t[45] = 74;
+ t[46] = 75;
+ t[47] = 76;
+ t[48] = 77;
+ t[49] = 78;
+ t[50] = 79;
+ t[51] = 80;
+ t[52] = 81;
+ t[53] = 82;
+ t[54] = 83;
+ t[55] = 84;
+ t[56] = 85;
+ t[57] = 86;
+ t[58] = 87;
+ t[59] = 88;
+ t[60] = 89;
+ t[61] = 90;
+ t[62] = 91;
+ t[63] = 92;
+ t[64] = 93;
+ t[65] = 94;
+ t[66] = 95;
+ t[67] = 96;
+ t[68] = 97;
+ t[69] = 98;
+ t[70] = 99;
+ t[71] = 100;
+ t[72] = 101;
+ t[73] = 102;
+ t[74] = 103;
+ t[75] = 104;
+ t[76] = 105;
+ t[77] = 106;
+ t[78] = 107;
+ t[79] = 108;
+ t[80] = 109;
+ t[81] = 110;
+ t[82] = 111;
+ t[83] = 112;
+ t[84] = 113;
+ t[85] = 114;
+ t[86] = 115;
+ t[87] = 116;
+ t[88] = 117;
+ t[89] = 118;
+ t[90] = 119;
+ t[91] = 120;
+ t[92] = 121;
+ t[93] = 122;
+ t[94] = 123;
+ t[95] = 124;
+ t[96] = 125;
+ t[97] = 126;
+ t[98] = 196;
+ t[99] = 197;
+ t[100] = 199;
+ t[101] = 201;
+ t[102] = 209;
+ t[103] = 214;
+ t[104] = 220;
+ t[105] = 225;
+ t[106] = 224;
+ t[107] = 226;
+ t[108] = 228;
+ t[109] = 227;
+ t[110] = 229;
+ t[111] = 231;
+ t[112] = 233;
+ t[113] = 232;
+ t[114] = 234;
+ t[115] = 235;
+ t[116] = 237;
+ t[117] = 236;
+ t[118] = 238;
+ t[119] = 239;
+ t[120] = 241;
+ t[121] = 243;
+ t[122] = 242;
+ t[123] = 244;
+ t[124] = 246;
+ t[125] = 245;
+ t[126] = 250;
+ t[127] = 249;
+ t[128] = 251;
+ t[129] = 252;
+ t[130] = 8224;
+ t[131] = 176;
+ t[132] = 162;
+ t[133] = 163;
+ t[134] = 167;
+ t[135] = 8226;
+ t[136] = 182;
+ t[137] = 223;
+ t[138] = 174;
+ t[139] = 169;
+ t[140] = 8482;
+ t[141] = 180;
+ t[142] = 168;
+ t[143] = 8800;
+ t[144] = 198;
+ t[145] = 216;
+ t[146] = 8734;
+ t[147] = 177;
+ t[148] = 8804;
+ t[149] = 8805;
+ t[150] = 165;
+ t[151] = 181;
+ t[152] = 8706;
+ t[153] = 8721;
+ t[154] = 8719;
+ t[156] = 8747;
+ t[157] = 170;
+ t[158] = 186;
+ t[159] = 8486;
+ t[160] = 230;
+ t[161] = 248;
+ t[162] = 191;
+ t[163] = 161;
+ t[164] = 172;
+ t[165] = 8730;
+ t[166] = 402;
+ t[167] = 8776;
+ t[168] = 8710;
+ t[169] = 171;
+ t[170] = 187;
+ t[171] = 8230;
+ t[179] = 8220;
+ t[180] = 8221;
+ t[181] = 8216;
+ t[182] = 8217;
+ t[200] = 193;
+ t[203] = 205;
+ t[207] = 211;
+ t[210] = 218;
+ t[223] = 711;
+ t[224] = 321;
+ t[225] = 322;
+ t[226] = 352;
+ t[227] = 353;
+ t[228] = 381;
+ t[229] = 382;
+ t[233] = 221;
+ t[234] = 253;
+ t[252] = 263;
+ t[253] = 268;
+ t[254] = 269;
+ t[258] = 258;
+ t[260] = 260;
+ t[261] = 261;
+ t[265] = 280;
+ t[266] = 281;
+ t[267] = 282;
+ t[268] = 283;
+ t[269] = 313;
+ t[275] = 323;
+ t[276] = 324;
+ t[278] = 328;
+ t[283] = 344;
+ t[284] = 345;
+ t[285] = 346;
+ t[286] = 347;
+ t[292] = 367;
+ t[295] = 377;
+ t[296] = 378;
+ t[298] = 380;
+ t[305] = 963;
+ t[306] = 964;
+ t[307] = 966;
+ t[308] = 8215;
+ t[309] = 8252;
+ t[310] = 8319;
+ t[311] = 8359;
+ t[312] = 8592;
+ t[313] = 8593;
+ t[337] = 9552;
+ t[493] = 1039;
+ t[494] = 1040;
+ t[570] = 1040;
+ t[571] = 1041;
+ t[572] = 1042;
+ t[573] = 1043;
+ t[574] = 1044;
+ t[575] = 1045;
+ t[576] = 1046;
+ t[577] = 1047;
+ t[578] = 1048;
+ t[579] = 1049;
+ t[580] = 1050;
+ t[581] = 1051;
+ t[582] = 1052;
+ t[583] = 1053;
+ t[584] = 1054;
+ t[585] = 1055;
+ t[586] = 1056;
+ t[587] = 1057;
+ t[588] = 1058;
+ t[589] = 1059;
+ t[590] = 1060;
+ t[591] = 1061;
+ t[592] = 1062;
+ t[593] = 1063;
+ t[594] = 1064;
+ t[595] = 1065;
+ t[596] = 1066;
+ t[597] = 1067;
+ t[598] = 1068;
+ t[599] = 1069;
+ t[600] = 1070;
+ t[601] = 1071;
+ t[602] = 1072;
+ t[603] = 1073;
+ t[604] = 1074;
+ t[605] = 1075;
+ t[606] = 1076;
+ t[607] = 1077;
+ t[608] = 1078;
+ t[609] = 1079;
+ t[610] = 1080;
+ t[611] = 1081;
+ t[612] = 1082;
+ t[613] = 1083;
+ t[614] = 1084;
+ t[615] = 1085;
+ t[616] = 1086;
+ t[617] = 1087;
+ t[618] = 1088;
+ t[619] = 1089;
+ t[620] = 1090;
+ t[621] = 1091;
+ t[622] = 1092;
+ t[623] = 1093;
+ t[624] = 1094;
+ t[625] = 1095;
+ t[626] = 1096;
+ t[627] = 1097;
+ t[628] = 1098;
+ t[629] = 1099;
+ t[630] = 1100;
+ t[631] = 1101;
+ t[632] = 1102;
+ t[633] = 1103;
+ t[672] = 1488;
+ t[673] = 1489;
+ t[674] = 1490;
+ t[675] = 1491;
+ t[676] = 1492;
+ t[677] = 1493;
+ t[678] = 1494;
+ t[679] = 1495;
+ t[680] = 1496;
+ t[681] = 1497;
+ t[682] = 1498;
+ t[683] = 1499;
+ t[684] = 1500;
+ t[685] = 1501;
+ t[686] = 1502;
+ t[687] = 1503;
+ t[688] = 1504;
+ t[689] = 1505;
+ t[690] = 1506;
+ t[691] = 1507;
+ t[692] = 1508;
+ t[693] = 1509;
+ t[694] = 1510;
+ t[695] = 1511;
+ t[696] = 1512;
+ t[697] = 1513;
+ t[698] = 1514;
+ t[705] = 1524;
+ t[706] = 8362;
+ t[710] = 64288;
+ t[711] = 64298;
+ t[759] = 1617;
+ t[761] = 1776;
+ t[763] = 1778;
+ t[775] = 1652;
+ t[777] = 1764;
+ t[778] = 1780;
+ t[779] = 1781;
+ t[780] = 1782;
+ t[782] = 771;
+ t[783] = 64726;
+ t[786] = 8363;
+ t[788] = 8532;
+ t[790] = 768;
+ t[791] = 769;
+ t[792] = 768;
+ t[795] = 803;
+ t[797] = 64336;
+ t[798] = 64337;
+ t[799] = 64342;
+ t[800] = 64343;
+ t[801] = 64344;
+ t[802] = 64345;
+ t[803] = 64362;
+ t[804] = 64363;
+ t[805] = 64364;
+ t[2424] = 7821;
+ t[2425] = 7822;
+ t[2426] = 7823;
+ t[2427] = 7824;
+ t[2428] = 7825;
+ t[2429] = 7826;
+ t[2430] = 7827;
+ t[2433] = 7682;
+ t[2678] = 8045;
+ t[2679] = 8046;
+ t[2830] = 1552;
+ t[2838] = 686;
+ t[2840] = 751;
+ t[2842] = 753;
+ t[2843] = 754;
+ t[2844] = 755;
+ t[2846] = 757;
+ t[2856] = 767;
+ t[2857] = 848;
+ t[2858] = 849;
+ t[2862] = 853;
+ t[2863] = 854;
+ t[2864] = 855;
+ t[2865] = 861;
+ t[2866] = 862;
+ t[2906] = 7460;
+ t[2908] = 7462;
+ t[2909] = 7463;
+ t[2910] = 7464;
+ t[2912] = 7466;
+ t[2913] = 7467;
+ t[2914] = 7468;
+ t[2916] = 7470;
+ t[2917] = 7471;
+ t[2918] = 7472;
+ t[2920] = 7474;
+ t[2921] = 7475;
+ t[2922] = 7476;
+ t[2924] = 7478;
+ t[2925] = 7479;
+ t[2926] = 7480;
+ t[2928] = 7482;
+ t[2929] = 7483;
+ t[2930] = 7484;
+ t[2932] = 7486;
+ t[2933] = 7487;
+ t[2934] = 7488;
+ t[2936] = 7490;
+ t[2937] = 7491;
+ t[2938] = 7492;
+ t[2940] = 7494;
+ t[2941] = 7495;
+ t[2942] = 7496;
+ t[2944] = 7498;
+ t[2946] = 7500;
+ t[2948] = 7502;
+ t[2950] = 7504;
+ t[2951] = 7505;
+ t[2952] = 7506;
+ t[2954] = 7508;
+ t[2955] = 7509;
+ t[2956] = 7510;
+ t[2958] = 7512;
+ t[2959] = 7513;
+ t[2960] = 7514;
+ t[2962] = 7516;
+ t[2963] = 7517;
+ t[2964] = 7518;
+ t[2966] = 7520;
+ t[2967] = 7521;
+ t[2968] = 7522;
+ t[2970] = 7524;
+ t[2971] = 7525;
+ t[2972] = 7526;
+ t[2974] = 7528;
+ t[2975] = 7529;
+ t[2976] = 7530;
+ t[2978] = 1537;
+ t[2979] = 1538;
+ t[2980] = 1539;
+ t[2982] = 1549;
+ t[2983] = 1551;
+ t[2984] = 1552;
+ t[2986] = 1554;
+ t[2987] = 1555;
+ t[2988] = 1556;
+ t[2990] = 1623;
+ t[2991] = 1624;
+ t[2995] = 1775;
+ t[2999] = 1791;
+ t[3002] = 64290;
+ t[3003] = 64291;
+ t[3004] = 64292;
+ t[3006] = 64294;
+ t[3007] = 64295;
+ t[3008] = 64296;
+ t[3011] = 1900;
+ t[3014] = 8223;
+ t[3015] = 8244;
+ t[3017] = 7532;
+ t[3018] = 7533;
+ t[3019] = 7534;
+ t[3075] = 7590;
+ t[3076] = 7591;
+ t[3079] = 7594;
+ t[3080] = 7595;
+ t[3083] = 7598;
+ t[3084] = 7599;
+ t[3087] = 7602;
+ t[3088] = 7603;
+ t[3091] = 7606;
+ t[3092] = 7607;
+ t[3095] = 7610;
+ t[3096] = 7611;
+ t[3099] = 7614;
+ t[3100] = 7615;
+ t[3103] = 7618;
+ t[3104] = 7619;
+ t[3107] = 8337;
+ t[3108] = 8338;
+ t[3116] = 1884;
+ t[3119] = 1885;
+ t[3120] = 1885;
+ t[3123] = 1886;
+ t[3124] = 1886;
+ t[3127] = 1887;
+ t[3128] = 1887;
+ t[3131] = 1888;
+ t[3132] = 1888;
+ t[3135] = 1889;
+ t[3136] = 1889;
+ t[3139] = 1890;
+ t[3140] = 1890;
+ t[3143] = 1891;
+ t[3144] = 1891;
+ t[3147] = 1892;
+ t[3148] = 1892;
+ t[3153] = 580;
+ t[3154] = 581;
+ t[3157] = 584;
+ t[3158] = 585;
+ t[3161] = 588;
+ t[3162] = 589;
+ t[3165] = 891;
+ t[3166] = 892;
+ t[3169] = 1274;
+ t[3170] = 1275;
+ t[3173] = 1278;
+ t[3174] = 1279;
+ t[3181] = 7622;
+ t[3182] = 7623;
+ t[3282] = 11799;
+ t[3316] = 578;
+ t[3379] = 42785;
+ t[3393] = 1159;
+ t[3416] = 8377;
+});
+const getSupplementalGlyphMapForTrebuchetMS = getLookupTableFactory(function (t) {
+ t[151] = 956;
+ t[159] = 937;
+ t[168] = 916;
+ t[189] = 8364;
+ t[195] = 8729;
+ t[218] = 713;
+ t[236] = 222;
+ t[237] = 254;
+ t[238] = 8722;
+ t[239] = 185;
+ t[240] = 178;
+ t[241] = 179;
+ t[242] = 189;
+ t[243] = 188;
+ t[244] = 190;
+ t[245] = 181;
+ t[246] = 8486;
+ t[247] = 8710;
+ t[248] = 253;
+ t[249] = 215;
+ t[250] = 173;
+ t[253] = 8355;
+ t[254] = 286;
+ t[255] = 287;
+ t[256] = 304;
+ t[257] = 350;
+ t[258] = 351;
+ t[259] = 262;
+ t[260] = 263;
+ t[261] = 268;
+ t[262] = 269;
+ t[263] = 273;
+ t[264] = 175;
+ t[266] = 183;
+ t[267] = 258;
+ t[268] = 259;
+ t[269] = 260;
+ t[270] = 261;
+ t[271] = 270;
+ t[272] = 271;
+ t[273] = 272;
+ t[274] = 280;
+ t[275] = 281;
+ t[276] = 282;
+ t[277] = 283;
+ t[278] = 313;
+ t[279] = 314;
+ t[280] = 317;
+ t[281] = 318;
+ t[282] = 319;
+ t[283] = 320;
+ t[284] = 323;
+ t[285] = 324;
+ t[286] = 327;
+ t[287] = 328;
+ t[288] = 336;
+ t[289] = 337;
+ t[290] = 340;
+ t[291] = 341;
+ t[292] = 344;
+ t[293] = 345;
+ t[294] = 346;
+ t[295] = 347;
+ t[296] = 538;
+ t[297] = 539;
+ t[298] = 356;
+ t[299] = 357;
+ t[300] = 366;
+ t[301] = 367;
+ t[302] = 368;
+ t[303] = 369;
+ t[304] = 377;
+ t[305] = 378;
+ t[306] = 379;
+ t[307] = 380;
+});
+const getSupplementalGlyphMapForArialBlack = getLookupTableFactory(function (t) {
+ t[227] = 322;
+ t[264] = 261;
+ t[291] = 346;
+});
+const getSupplementalGlyphMapForCalibri = getLookupTableFactory(function (t) {
+ t[1] = 32;
+ t[4] = 65;
+ t[5] = 192;
+ t[6] = 193;
+ t[9] = 196;
+ t[17] = 66;
+ t[18] = 67;
+ t[21] = 268;
+ t[24] = 68;
+ t[28] = 69;
+ t[29] = 200;
+ t[30] = 201;
+ t[32] = 282;
+ t[38] = 70;
+ t[39] = 71;
+ t[44] = 72;
+ t[47] = 73;
+ t[48] = 204;
+ t[49] = 205;
+ t[58] = 74;
+ t[60] = 75;
+ t[62] = 76;
+ t[68] = 77;
+ t[69] = 78;
+ t[75] = 79;
+ t[76] = 210;
+ t[80] = 214;
+ t[87] = 80;
+ t[89] = 81;
+ t[90] = 82;
+ t[92] = 344;
+ t[94] = 83;
+ t[97] = 352;
+ t[100] = 84;
+ t[104] = 85;
+ t[109] = 220;
+ t[115] = 86;
+ t[116] = 87;
+ t[121] = 88;
+ t[122] = 89;
+ t[124] = 221;
+ t[127] = 90;
+ t[129] = 381;
+ t[258] = 97;
+ t[259] = 224;
+ t[260] = 225;
+ t[263] = 228;
+ t[268] = 261;
+ t[271] = 98;
+ t[272] = 99;
+ t[273] = 263;
+ t[275] = 269;
+ t[282] = 100;
+ t[286] = 101;
+ t[287] = 232;
+ t[288] = 233;
+ t[290] = 283;
+ t[295] = 281;
+ t[296] = 102;
+ t[336] = 103;
+ t[346] = 104;
+ t[349] = 105;
+ t[350] = 236;
+ t[351] = 237;
+ t[361] = 106;
+ t[364] = 107;
+ t[367] = 108;
+ t[371] = 322;
+ t[373] = 109;
+ t[374] = 110;
+ t[381] = 111;
+ t[382] = 242;
+ t[383] = 243;
+ t[386] = 246;
+ t[393] = 112;
+ t[395] = 113;
+ t[396] = 114;
+ t[398] = 345;
+ t[400] = 115;
+ t[401] = 347;
+ t[403] = 353;
+ t[410] = 116;
+ t[437] = 117;
+ t[442] = 252;
+ t[448] = 118;
+ t[449] = 119;
+ t[454] = 120;
+ t[455] = 121;
+ t[457] = 253;
+ t[460] = 122;
+ t[462] = 382;
+ t[463] = 380;
+ t[853] = 44;
+ t[855] = 58;
+ t[856] = 46;
+ t[876] = 47;
+ t[878] = 45;
+ t[882] = 45;
+ t[894] = 40;
+ t[895] = 41;
+ t[896] = 91;
+ t[897] = 93;
+ t[923] = 64;
+ t[940] = 163;
+ t[1004] = 48;
+ t[1005] = 49;
+ t[1006] = 50;
+ t[1007] = 51;
+ t[1008] = 52;
+ t[1009] = 53;
+ t[1010] = 54;
+ t[1011] = 55;
+ t[1012] = 56;
+ t[1013] = 57;
+ t[1081] = 37;
+ t[1085] = 43;
+ t[1086] = 45;
+});
+function getStandardFontName(name) {
+ const fontName = normalizeFontName(name);
+ const stdFontMap = getStdFontMap();
+ return stdFontMap[fontName];
+}
+function isKnownFontName(name) {
+ const fontName = normalizeFontName(name);
+ return !!(getStdFontMap()[fontName] || getNonStdFontMap()[fontName] || getSerifFonts()[fontName] || getSymbolsFonts()[fontName]);
+}
+
+;// ./src/core/glyf.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const ON_CURVE_POINT = 1 << 0;
+const X_SHORT_VECTOR = 1 << 1;
+const Y_SHORT_VECTOR = 1 << 2;
+const REPEAT_FLAG = 1 << 3;
+const X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 1 << 4;
+const Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 1 << 5;
+const OVERLAP_SIMPLE = 1 << 6;
+const ARG_1_AND_2_ARE_WORDS = 1 << 0;
+const ARGS_ARE_XY_VALUES = 1 << 1;
+const WE_HAVE_A_SCALE = 1 << 3;
+const MORE_COMPONENTS = 1 << 5;
+const WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
+const WE_HAVE_A_TWO_BY_TWO = 1 << 7;
+const WE_HAVE_INSTRUCTIONS = 1 << 8;
+const GLYPH_HEADER_SIZE = 10;
+class GlyfTable {
+ constructor({
+ glyfTable,
+ isGlyphLocationsLong,
+ locaTable,
+ numGlyphs
+ }) {
+ this.glyphs = [];
+ const loca = new DataView(locaTable.buffer, locaTable.byteOffset, locaTable.byteLength);
+ const glyf = new DataView(glyfTable.buffer, glyfTable.byteOffset, glyfTable.byteLength);
+ const offsetSize = isGlyphLocationsLong ? 4 : 2;
+ let prev = isGlyphLocationsLong ? loca.getUint32(0) : 2 * loca.getUint16(0);
+ let pos = 0;
+ for (let i = 0; i < numGlyphs; i++) {
+ pos += offsetSize;
+ const next = isGlyphLocationsLong ? loca.getUint32(pos) : 2 * loca.getUint16(pos);
+ if (next === prev) {
+ this.glyphs.push(new Glyph({}));
+ continue;
+ }
+ const glyph = Glyph.parse(prev, glyf);
+ this.glyphs.push(glyph);
+ prev = next;
+ }
+ }
+ getSize() {
+ return Math.sumPrecise(this.glyphs.map(g => g.getSize() + 3 & ~3));
+ }
+ write() {
+ const totalSize = this.getSize();
+ const glyfTable = new DataView(new ArrayBuffer(totalSize));
+ const isLocationLong = totalSize > 0x1fffe;
+ const offsetSize = isLocationLong ? 4 : 2;
+ const locaTable = new DataView(new ArrayBuffer((this.glyphs.length + 1) * offsetSize));
+ if (isLocationLong) {
+ locaTable.setUint32(0, 0);
+ } else {
+ locaTable.setUint16(0, 0);
+ }
+ let pos = 0;
+ let locaIndex = 0;
+ for (const glyph of this.glyphs) {
+ pos += glyph.write(pos, glyfTable);
+ pos = pos + 3 & ~3;
+ locaIndex += offsetSize;
+ if (isLocationLong) {
+ locaTable.setUint32(locaIndex, pos);
+ } else {
+ locaTable.setUint16(locaIndex, pos >> 1);
+ }
+ }
+ return {
+ isLocationLong,
+ loca: new Uint8Array(locaTable.buffer),
+ glyf: new Uint8Array(glyfTable.buffer)
+ };
+ }
+ scale(factors) {
+ for (let i = 0, ii = this.glyphs.length; i < ii; i++) {
+ this.glyphs[i].scale(factors[i]);
+ }
+ }
+}
+class Glyph {
+ constructor({
+ header = null,
+ simple = null,
+ composites = null
+ }) {
+ this.header = header;
+ this.simple = simple;
+ this.composites = composites;
+ }
+ static parse(pos, glyf) {
+ const [read, header] = GlyphHeader.parse(pos, glyf);
+ pos += read;
+ if (header.numberOfContours < 0) {
+ const composites = [];
+ while (true) {
+ const [n, composite] = CompositeGlyph.parse(pos, glyf);
+ pos += n;
+ composites.push(composite);
+ if (!(composite.flags & MORE_COMPONENTS)) {
+ break;
+ }
+ }
+ return new Glyph({
+ header,
+ composites
+ });
+ }
+ const simple = SimpleGlyph.parse(pos, glyf, header.numberOfContours);
+ return new Glyph({
+ header,
+ simple
+ });
+ }
+ getSize() {
+ if (!this.header) {
+ return 0;
+ }
+ const size = this.simple ? this.simple.getSize() : Math.sumPrecise(this.composites.map(c => c.getSize()));
+ return this.header.getSize() + size;
+ }
+ write(pos, buf) {
+ if (!this.header) {
+ return 0;
+ }
+ const spos = pos;
+ pos += this.header.write(pos, buf);
+ if (this.simple) {
+ pos += this.simple.write(pos, buf);
+ } else {
+ for (const composite of this.composites) {
+ pos += composite.write(pos, buf);
+ }
+ }
+ return pos - spos;
+ }
+ scale(factor) {
+ if (!this.header) {
+ return;
+ }
+ const xMiddle = (this.header.xMin + this.header.xMax) / 2;
+ this.header.scale(xMiddle, factor);
+ if (this.simple) {
+ this.simple.scale(xMiddle, factor);
+ } else {
+ for (const composite of this.composites) {
+ composite.scale(xMiddle, factor);
+ }
+ }
+ }
+}
+class GlyphHeader {
+ constructor({
+ numberOfContours,
+ xMin,
+ yMin,
+ xMax,
+ yMax
+ }) {
+ this.numberOfContours = numberOfContours;
+ this.xMin = xMin;
+ this.yMin = yMin;
+ this.xMax = xMax;
+ this.yMax = yMax;
+ }
+ static parse(pos, glyf) {
+ return [GLYPH_HEADER_SIZE, new GlyphHeader({
+ numberOfContours: glyf.getInt16(pos),
+ xMin: glyf.getInt16(pos + 2),
+ yMin: glyf.getInt16(pos + 4),
+ xMax: glyf.getInt16(pos + 6),
+ yMax: glyf.getInt16(pos + 8)
+ })];
+ }
+ getSize() {
+ return GLYPH_HEADER_SIZE;
+ }
+ write(pos, buf) {
+ buf.setInt16(pos, this.numberOfContours);
+ buf.setInt16(pos + 2, this.xMin);
+ buf.setInt16(pos + 4, this.yMin);
+ buf.setInt16(pos + 6, this.xMax);
+ buf.setInt16(pos + 8, this.yMax);
+ return GLYPH_HEADER_SIZE;
+ }
+ scale(x, factor) {
+ this.xMin = Math.round(x + (this.xMin - x) * factor);
+ this.xMax = Math.round(x + (this.xMax - x) * factor);
+ }
+}
+class Contour {
+ constructor({
+ flags,
+ xCoordinates,
+ yCoordinates
+ }) {
+ this.xCoordinates = xCoordinates;
+ this.yCoordinates = yCoordinates;
+ this.flags = flags;
+ }
+}
+class SimpleGlyph {
+ constructor({
+ contours,
+ instructions
+ }) {
+ this.contours = contours;
+ this.instructions = instructions;
+ }
+ static parse(pos, glyf, numberOfContours) {
+ const endPtsOfContours = [];
+ for (let i = 0; i < numberOfContours; i++) {
+ const endPt = glyf.getUint16(pos);
+ pos += 2;
+ endPtsOfContours.push(endPt);
+ }
+ const numberOfPt = endPtsOfContours[numberOfContours - 1] + 1;
+ const instructionLength = glyf.getUint16(pos);
+ pos += 2;
+ const instructions = new Uint8Array(glyf).slice(pos, pos + instructionLength);
+ pos += instructionLength;
+ const flags = [];
+ for (let i = 0; i < numberOfPt; pos++, i++) {
+ let flag = glyf.getUint8(pos);
+ flags.push(flag);
+ if (flag & REPEAT_FLAG) {
+ const count = glyf.getUint8(++pos);
+ flag ^= REPEAT_FLAG;
+ for (let m = 0; m < count; m++) {
+ flags.push(flag);
+ }
+ i += count;
+ }
+ }
+ const allXCoordinates = [];
+ let xCoordinates = [];
+ let yCoordinates = [];
+ let pointFlags = [];
+ const contours = [];
+ let endPtsOfContoursIndex = 0;
+ let lastCoordinate = 0;
+ for (let i = 0; i < numberOfPt; i++) {
+ const flag = flags[i];
+ if (flag & X_SHORT_VECTOR) {
+ const x = glyf.getUint8(pos++);
+ lastCoordinate += flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR ? x : -x;
+ xCoordinates.push(lastCoordinate);
+ } else if (flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
+ xCoordinates.push(lastCoordinate);
+ } else {
+ lastCoordinate += glyf.getInt16(pos);
+ pos += 2;
+ xCoordinates.push(lastCoordinate);
+ }
+ if (endPtsOfContours[endPtsOfContoursIndex] === i) {
+ endPtsOfContoursIndex++;
+ allXCoordinates.push(xCoordinates);
+ xCoordinates = [];
+ }
+ }
+ lastCoordinate = 0;
+ endPtsOfContoursIndex = 0;
+ for (let i = 0; i < numberOfPt; i++) {
+ const flag = flags[i];
+ if (flag & Y_SHORT_VECTOR) {
+ const y = glyf.getUint8(pos++);
+ lastCoordinate += flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR ? y : -y;
+ yCoordinates.push(lastCoordinate);
+ } else if (flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
+ yCoordinates.push(lastCoordinate);
+ } else {
+ lastCoordinate += glyf.getInt16(pos);
+ pos += 2;
+ yCoordinates.push(lastCoordinate);
+ }
+ pointFlags.push(flag & ON_CURVE_POINT | flag & OVERLAP_SIMPLE);
+ if (endPtsOfContours[endPtsOfContoursIndex] === i) {
+ xCoordinates = allXCoordinates[endPtsOfContoursIndex];
+ endPtsOfContoursIndex++;
+ contours.push(new Contour({
+ flags: pointFlags,
+ xCoordinates,
+ yCoordinates
+ }));
+ yCoordinates = [];
+ pointFlags = [];
+ }
+ }
+ return new SimpleGlyph({
+ contours,
+ instructions
+ });
+ }
+ getSize() {
+ let size = this.contours.length * 2 + 2 + this.instructions.length;
+ let lastX = 0;
+ let lastY = 0;
+ for (const contour of this.contours) {
+ size += contour.flags.length;
+ for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
+ const x = contour.xCoordinates[i];
+ const y = contour.yCoordinates[i];
+ let abs = Math.abs(x - lastX);
+ if (abs > 255) {
+ size += 2;
+ } else if (abs > 0) {
+ size += 1;
+ }
+ lastX = x;
+ abs = Math.abs(y - lastY);
+ if (abs > 255) {
+ size += 2;
+ } else if (abs > 0) {
+ size += 1;
+ }
+ lastY = y;
+ }
+ }
+ return size;
+ }
+ write(pos, buf) {
+ const spos = pos;
+ const xCoordinates = [];
+ const yCoordinates = [];
+ const flags = [];
+ let lastX = 0;
+ let lastY = 0;
+ for (const contour of this.contours) {
+ for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
+ let flag = contour.flags[i];
+ const x = contour.xCoordinates[i];
+ let delta = x - lastX;
+ if (delta === 0) {
+ flag |= X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR;
+ xCoordinates.push(0);
+ } else {
+ const abs = Math.abs(delta);
+ if (abs <= 255) {
+ flag |= delta >= 0 ? X_SHORT_VECTOR | X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR : X_SHORT_VECTOR;
+ xCoordinates.push(abs);
+ } else {
+ xCoordinates.push(delta);
+ }
+ }
+ lastX = x;
+ const y = contour.yCoordinates[i];
+ delta = y - lastY;
+ if (delta === 0) {
+ flag |= Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR;
+ yCoordinates.push(0);
+ } else {
+ const abs = Math.abs(delta);
+ if (abs <= 255) {
+ flag |= delta >= 0 ? Y_SHORT_VECTOR | Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR : Y_SHORT_VECTOR;
+ yCoordinates.push(abs);
+ } else {
+ yCoordinates.push(delta);
+ }
+ }
+ lastY = y;
+ flags.push(flag);
+ }
+ buf.setUint16(pos, xCoordinates.length - 1);
+ pos += 2;
+ }
+ buf.setUint16(pos, this.instructions.length);
+ pos += 2;
+ if (this.instructions.length) {
+ new Uint8Array(buf.buffer, 0, buf.buffer.byteLength).set(this.instructions, pos);
+ pos += this.instructions.length;
+ }
+ for (const flag of flags) {
+ buf.setUint8(pos++, flag);
+ }
+ for (let i = 0, ii = xCoordinates.length; i < ii; i++) {
+ const x = xCoordinates[i];
+ const flag = flags[i];
+ if (flag & X_SHORT_VECTOR) {
+ buf.setUint8(pos++, x);
+ } else if (!(flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR)) {
+ buf.setInt16(pos, x);
+ pos += 2;
+ }
+ }
+ for (let i = 0, ii = yCoordinates.length; i < ii; i++) {
+ const y = yCoordinates[i];
+ const flag = flags[i];
+ if (flag & Y_SHORT_VECTOR) {
+ buf.setUint8(pos++, y);
+ } else if (!(flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR)) {
+ buf.setInt16(pos, y);
+ pos += 2;
+ }
+ }
+ return pos - spos;
+ }
+ scale(x, factor) {
+ for (const contour of this.contours) {
+ if (contour.xCoordinates.length === 0) {
+ continue;
+ }
+ for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
+ contour.xCoordinates[i] = Math.round(x + (contour.xCoordinates[i] - x) * factor);
+ }
+ }
+ }
+}
+class CompositeGlyph {
+ constructor({
+ flags,
+ glyphIndex,
+ argument1,
+ argument2,
+ transf,
+ instructions
+ }) {
+ this.flags = flags;
+ this.glyphIndex = glyphIndex;
+ this.argument1 = argument1;
+ this.argument2 = argument2;
+ this.transf = transf;
+ this.instructions = instructions;
+ }
+ static parse(pos, glyf) {
+ const spos = pos;
+ const transf = [];
+ let flags = glyf.getUint16(pos);
+ const glyphIndex = glyf.getUint16(pos + 2);
+ pos += 4;
+ let argument1, argument2;
+ if (flags & ARG_1_AND_2_ARE_WORDS) {
+ if (flags & ARGS_ARE_XY_VALUES) {
+ argument1 = glyf.getInt16(pos);
+ argument2 = glyf.getInt16(pos + 2);
+ } else {
+ argument1 = glyf.getUint16(pos);
+ argument2 = glyf.getUint16(pos + 2);
+ }
+ pos += 4;
+ flags ^= ARG_1_AND_2_ARE_WORDS;
+ } else {
+ if (flags & ARGS_ARE_XY_VALUES) {
+ argument1 = glyf.getInt8(pos);
+ argument2 = glyf.getInt8(pos + 1);
+ } else {
+ argument1 = glyf.getUint8(pos);
+ argument2 = glyf.getUint8(pos + 1);
+ }
+ pos += 2;
+ }
+ if (flags & WE_HAVE_A_SCALE) {
+ transf.push(glyf.getUint16(pos));
+ pos += 2;
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+ transf.push(glyf.getUint16(pos), glyf.getUint16(pos + 2));
+ pos += 4;
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+ transf.push(glyf.getUint16(pos), glyf.getUint16(pos + 2), glyf.getUint16(pos + 4), glyf.getUint16(pos + 6));
+ pos += 8;
+ }
+ let instructions = null;
+ if (flags & WE_HAVE_INSTRUCTIONS) {
+ const instructionLength = glyf.getUint16(pos);
+ pos += 2;
+ instructions = new Uint8Array(glyf).slice(pos, pos + instructionLength);
+ pos += instructionLength;
+ }
+ return [pos - spos, new CompositeGlyph({
+ flags,
+ glyphIndex,
+ argument1,
+ argument2,
+ transf,
+ instructions
+ })];
+ }
+ getSize() {
+ let size = 2 + 2 + this.transf.length * 2;
+ if (this.flags & WE_HAVE_INSTRUCTIONS) {
+ size += 2 + this.instructions.length;
+ }
+ size += 2;
+ if (this.flags & 2) {
+ if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) {
+ size += 2;
+ }
+ } else if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) {
+ size += 2;
+ }
+ return size;
+ }
+ write(pos, buf) {
+ const spos = pos;
+ if (this.flags & ARGS_ARE_XY_VALUES) {
+ if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) {
+ this.flags |= ARG_1_AND_2_ARE_WORDS;
+ }
+ } else if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) {
+ this.flags |= ARG_1_AND_2_ARE_WORDS;
+ }
+ buf.setUint16(pos, this.flags);
+ buf.setUint16(pos + 2, this.glyphIndex);
+ pos += 4;
+ if (this.flags & ARG_1_AND_2_ARE_WORDS) {
+ if (this.flags & ARGS_ARE_XY_VALUES) {
+ buf.setInt16(pos, this.argument1);
+ buf.setInt16(pos + 2, this.argument2);
+ } else {
+ buf.setUint16(pos, this.argument1);
+ buf.setUint16(pos + 2, this.argument2);
+ }
+ pos += 4;
+ } else {
+ buf.setUint8(pos, this.argument1);
+ buf.setUint8(pos + 1, this.argument2);
+ pos += 2;
+ }
+ if (this.flags & WE_HAVE_INSTRUCTIONS) {
+ buf.setUint16(pos, this.instructions.length);
+ pos += 2;
+ if (this.instructions.length) {
+ new Uint8Array(buf.buffer, 0, buf.buffer.byteLength).set(this.instructions, pos);
+ pos += this.instructions.length;
+ }
+ }
+ return pos - spos;
+ }
+ scale(x, factor) {}
+}
+function pruneCompositeGlyphCycles(glyfTable, locaEntries, numGlyphs) {
+ const glyf = new DataView(glyfTable.buffer, glyfTable.byteOffset, glyfTable.byteLength);
+ const components = new Array(numGlyphs);
+ for (let i = 0; i < numGlyphs; i++) {
+ const offset = locaEntries[i].offset;
+ const endOffset = Math.min(locaEntries[i].endOffset, glyf.byteLength);
+ if (endOffset - offset <= GLYPH_HEADER_SIZE || glyf.getInt16(offset) >= 0) {
+ continue;
+ }
+ const comps = [];
+ let p = offset + GLYPH_HEADER_SIZE;
+ while (p + 4 <= endOffset) {
+ const flags = glyf.getUint16(p);
+ const gid = glyf.getUint16(p + 2);
+ let size = 4 + (flags & ARG_1_AND_2_ARE_WORDS ? 4 : 2);
+ if (flags & WE_HAVE_A_SCALE) {
+ size += 2;
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+ size += 4;
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+ size += 8;
+ }
+ comps.push({
+ gid,
+ offset: p,
+ size,
+ flags
+ });
+ p += size;
+ if (!(flags & MORE_COMPONENTS)) {
+ break;
+ }
+ }
+ if (comps.length) {
+ components[i] = comps;
+ }
+ }
+ const WHITE = 0,
+ GRAY = 1,
+ BLACK = 2;
+ const state = new Uint8Array(numGlyphs);
+ const backEdges = new Map();
+ for (let start = 0; start < numGlyphs; start++) {
+ if (state[start] !== WHITE || !components[start]) {
+ continue;
+ }
+ const stack = [{
+ node: start,
+ idx: 0
+ }];
+ state[start] = GRAY;
+ while (stack.length > 0) {
+ const top = stack.at(-1);
+ const comps = components[top.node];
+ if (!comps || top.idx >= comps.length) {
+ state[top.node] = BLACK;
+ stack.pop();
+ continue;
+ }
+ const compIdx = top.idx++;
+ const next = comps[compIdx].gid;
+ if (next >= numGlyphs || state[next] === BLACK) {
+ continue;
+ }
+ if (state[next] === WHITE) {
+ state[next] = GRAY;
+ stack.push({
+ node: next,
+ idx: 0
+ });
+ continue;
+ }
+ backEdges.getOrInsertComputed(top.node, makeSet).add(compIdx);
+ }
+ }
+ const droppedGlyphs = new Set();
+ for (const [gIdx, removeSet] of backEdges) {
+ const comps = components[gIdx];
+ const remaining = [];
+ for (let ci = 0; ci < comps.length; ci++) {
+ if (!removeSet.has(ci)) {
+ remaining.push(comps[ci]);
+ }
+ }
+ if (remaining.length === 0) {
+ droppedGlyphs.add(gIdx);
+ continue;
+ }
+ const start = locaEntries[gIdx].offset;
+ const endOffset = Math.min(locaEntries[gIdx].endOffset, glyf.byteLength);
+ let writePos = start + GLYPH_HEADER_SIZE;
+ for (let ci = 0; ci < remaining.length; ci++) {
+ const c = remaining[ci];
+ const isLast = ci === remaining.length - 1;
+ let newFlags = c.flags & ~WE_HAVE_INSTRUCTIONS;
+ newFlags = isLast ? newFlags & ~MORE_COMPONENTS : newFlags | MORE_COMPONENTS;
+ if (writePos !== c.offset) {
+ glyfTable.copyWithin(writePos, c.offset, c.offset + c.size);
+ }
+ glyf.setUint16(writePos, newFlags);
+ writePos += c.size;
+ }
+ if (writePos < endOffset) {
+ glyfTable.fill(0, writePos, endOffset);
+ }
+ }
+ return droppedGlyphs;
+}
+
+;// ./src/core/to_unicode_map.js
+
+class ToUnicodeMap {
+ constructor(cmap = []) {
+ this._map = cmap;
+ }
+ get length() {
+ return this._map.length;
+ }
+ forEach(callback) {
+ for (const charCode in this._map) {
+ callback(charCode, this._map[charCode].codePointAt(0));
+ }
+ }
+ has(i) {
+ return this._map[i] !== undefined;
+ }
+ get(i) {
+ return this._map[i];
+ }
+ charCodeOf(value) {
+ const map = this._map;
+ if (map.length <= 0x10000) {
+ return map.indexOf(value);
+ }
+ for (const charCode in map) {
+ if (map[charCode] === value) {
+ return charCode | 0;
+ }
+ }
+ return -1;
+ }
+ amend(map) {
+ for (const charCode in map) {
+ this._map[charCode] = map[charCode];
+ }
+ }
+}
+class IdentityToUnicodeMap {
+ constructor(firstChar, lastChar) {
+ this.firstChar = firstChar;
+ this.lastChar = lastChar;
+ }
+ get length() {
+ return this.lastChar + 1 - this.firstChar;
+ }
+ forEach(callback) {
+ for (let i = this.firstChar, ii = this.lastChar; i <= ii; i++) {
+ callback(i, i);
+ }
+ }
+ has(i) {
+ return this.firstChar <= i && i <= this.lastChar;
+ }
+ get(i) {
+ return this.firstChar <= i && i <= this.lastChar ? String.fromCharCode(i) : undefined;
+ }
+ charCodeOf(v) {
+ return Number.isInteger(v) && v >= this.firstChar && v <= this.lastChar ? v : -1;
+ }
+ amend(map) {
+ unreachable("Should not call amend()");
+ }
+}
+
+;// ./src/core/cff_font.js
+
+
+
+class CFFFont {
+ constructor(file, properties) {
+ this.properties = properties;
+ const parser = new CFFParser(file, properties, (/* inlined export .SEAC_ANALYSIS_ENABLED */true));
+ this.cff = parser.parse();
+ this.cff.duplicateFirstGlyph();
+ const compiler = new CFFCompiler(this.cff);
+ this.seacs = this.cff.seacs;
+ try {
+ this.data = compiler.compile();
+ } catch (ex) {
+ warn(`Failed to compile font "${properties.loadedName}": "${ex}".`);
+ file.reset();
+ this.data = file.getBytes();
+ }
+ this._createBuiltInEncoding();
+ }
+ get numGlyphs() {
+ return this.cff.charStrings.count;
+ }
+ getCharset() {
+ return this.cff.charset.charset;
+ }
+ getGlyphMapping() {
+ const cff = this.cff;
+ const properties = this.properties;
+ const {
+ cidToGidMap,
+ cMap
+ } = properties;
+ const charsets = cff.charset.charset;
+ let charCodeToGlyphId;
+ let glyphId;
+ if (properties.composite) {
+ let invCidToGidMap;
+ if (cidToGidMap?.length > 0) {
+ invCidToGidMap = Object.create(null);
+ for (let i = 0, ii = cidToGidMap.length; i < ii; i++) {
+ const gid = cidToGidMap[i];
+ if (gid !== undefined) {
+ invCidToGidMap[gid] = i;
+ }
+ }
+ }
+ charCodeToGlyphId = Object.create(null);
+ let charCode;
+ if (cff.isCIDFont) {
+ for (glyphId = 0; glyphId < charsets.length; glyphId++) {
+ const cid = charsets[glyphId];
+ charCode = cMap.charCodeOf(cid);
+ if (invCidToGidMap?.[charCode] !== undefined) {
+ charCode = invCidToGidMap[charCode];
+ }
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ } else {
+ for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
+ charCode = cMap.charCodeOf(glyphId);
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ }
+ return charCodeToGlyphId;
+ }
+ let encoding = cff.encoding ? cff.encoding.encoding : null;
+ if (properties.isInternalFont) {
+ encoding = properties.defaultEncoding;
+ }
+ charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
+ return charCodeToGlyphId;
+ }
+ hasGlyphId(id) {
+ return this.cff.hasGlyphId(id);
+ }
+ _createBuiltInEncoding() {
+ const {
+ charset,
+ encoding
+ } = this.cff;
+ if (!charset || !encoding) {
+ return;
+ }
+ const charsets = charset.charset,
+ encodings = encoding.encoding;
+ const map = [];
+ for (const charCode in encodings) {
+ const glyphId = encodings[charCode];
+ if (glyphId >= 0) {
+ const glyphName = charsets[glyphId];
+ if (glyphName) {
+ map[charCode] = glyphName;
+ }
+ }
+ }
+ if (map.length > 0) {
+ this.properties.builtInEncoding = map;
+ }
+ }
+}
+
+;// ./src/shared/obj_bin_transform_utils.js
+
+class CSS_FONT_INFO {
+ static strings = ["fontFamily", "fontWeight", "italicAngle"];
+}
+class SYSTEM_FONT_INFO {
+ static strings = ["css", "loadedName", "baseFontName", "src"];
+}
+class FONT_INFO {
+ static bools = ["black", "bold", "disableFontFace", "fontExtraProperties", "isInvalidPDFjsFont", "isType3Font", "italic", "missingFile", "remeasure", "vertical"];
+ static numbers = ["ascent", "defaultWidth", "descent"];
+ static strings = ["fallbackName", "loadedName", "mimetype", "name"];
+ static OFFSET_NUMBERS = Math.ceil(this.bools.length * 2 / 8);
+ static OFFSET_BBOX = this.OFFSET_NUMBERS + this.numbers.length * 8;
+ static OFFSET_FONT_MATRIX = this.OFFSET_BBOX + 1 + 2 * 4;
+ static OFFSET_DEFAULT_VMETRICS = this.OFFSET_FONT_MATRIX + 1 + 8 * 6;
+ static OFFSET_STRINGS = this.OFFSET_DEFAULT_VMETRICS + 1 + 2 * 3;
+}
+class PATTERN_INFO {
+ static KIND = 0;
+ static HAS_BBOX = 1;
+ static HAS_BACKGROUND = 2;
+ static SHADING_TYPE = 3;
+ static N_COORD = 4;
+ static N_COLOR = 8;
+ static N_STOP = 12;
+ static N_FIGURES = 16;
+}
+class InfoUtils {
+ static get decoder() {
+ return shadow(this, "decoder", new TextDecoder());
+ }
+ static get encoder() {
+ return shadow(this, "encoder", new TextEncoder());
+ }
+}
+
+;// ./src/core/obj_bin_transform_core.js
+
+
+
+
+
+
+
+
+function compileCssFontInfo(info) {
+ const {
+ encoder
+ } = InfoUtils;
+ const encodedStrings = {};
+ let stringsLength = 0;
+ for (const prop of CSS_FONT_INFO.strings) {
+ const encoded = encoder.encode(info[prop]);
+ encodedStrings[prop] = encoded;
+ stringsLength += 4 + encoded.length;
+ }
+ const buffer = new ArrayBuffer(stringsLength);
+ const data = new Uint8Array(buffer);
+ const view = new DataView(buffer);
+ let offset = 0;
+ for (const prop of CSS_FONT_INFO.strings) {
+ const encoded = encodedStrings[prop];
+ const length = encoded.length;
+ view.setUint32(offset, length);
+ data.set(encoded, offset + 4);
+ offset += 4 + length;
+ }
+ assert(offset === buffer.byteLength, "compileCssFontInfo: Buffer overflow");
+ return buffer;
+}
+function compileSystemFontInfo(info) {
+ const {
+ encoder
+ } = InfoUtils;
+ const encodedStrings = {};
+ let stringsLength = 0;
+ for (const prop of SYSTEM_FONT_INFO.strings) {
+ const encoded = encoder.encode(info[prop]);
+ encodedStrings[prop] = encoded;
+ stringsLength += 4 + encoded.length;
+ }
+ stringsLength += 4;
+ let encodedStyleStyle,
+ encodedStyleWeight,
+ lengthEstimate = 1 + stringsLength;
+ if (info.style) {
+ encodedStyleStyle = encoder.encode(info.style.style);
+ encodedStyleWeight = encoder.encode(info.style.weight);
+ lengthEstimate += 4 + encodedStyleStyle.length + 4 + encodedStyleWeight.length;
+ }
+ const buffer = new ArrayBuffer(lengthEstimate);
+ const data = new Uint8Array(buffer);
+ const view = new DataView(buffer);
+ let offset = 0;
+ view.setUint8(offset++, info.guessFallback ? 1 : 0);
+ view.setUint32(offset, 0);
+ offset += 4;
+ stringsLength = 0;
+ for (const prop of SYSTEM_FONT_INFO.strings) {
+ const encoded = encodedStrings[prop];
+ const length = encoded.length;
+ stringsLength += 4 + length;
+ view.setUint32(offset, length);
+ data.set(encoded, offset + 4);
+ offset += 4 + length;
+ }
+ view.setUint32(offset - stringsLength - 4, stringsLength);
+ if (info.style) {
+ view.setUint32(offset, encodedStyleStyle.length);
+ data.set(encodedStyleStyle, offset + 4);
+ offset += 4 + encodedStyleStyle.length;
+ view.setUint32(offset, encodedStyleWeight.length);
+ data.set(encodedStyleWeight, offset + 4);
+ offset += 4 + encodedStyleWeight.length;
+ }
+ assert(offset <= buffer.byteLength, "compileSystemFontInfo: Buffer overflow");
+ return buffer.transferToFixedLength(offset);
+}
+function compileFontInfo(font) {
+ const systemFontInfoBuffer = font.systemFontInfo ? compileSystemFontInfo(font.systemFontInfo) : null;
+ const cssFontInfoBuffer = font.cssFontInfo ? compileCssFontInfo(font.cssFontInfo) : null;
+ const {
+ encoder
+ } = InfoUtils;
+ const encodedStrings = {};
+ let stringsLength = 0;
+ for (const prop of FONT_INFO.strings) {
+ encodedStrings[prop] = encoder.encode(font[prop]);
+ stringsLength += 4 + encodedStrings[prop].length;
+ }
+ const lengthEstimate = FONT_INFO.OFFSET_STRINGS + 4 + stringsLength + 4 + (systemFontInfoBuffer?.byteLength ?? 0) + 4 + (cssFontInfoBuffer?.byteLength ?? 0) + 4 + (font.data?.length ?? 0);
+ const buffer = new ArrayBuffer(lengthEstimate);
+ const data = new Uint8Array(buffer);
+ const view = new DataView(buffer);
+ let offset = 0;
+ const numBools = FONT_INFO.bools.length;
+ let boolByte = 0,
+ boolBit = 0;
+ for (let i = 0; i < numBools; i++) {
+ const value = font[FONT_INFO.bools[i]];
+ const bits = value === undefined ? 0x00 : value ? 0x02 : 0x01;
+ boolByte |= bits << boolBit;
+ boolBit += 2;
+ if (boolBit === 8 || i === numBools - 1) {
+ view.setUint8(offset++, boolByte);
+ boolByte = 0;
+ boolBit = 0;
+ }
+ }
+ assert(offset === FONT_INFO.OFFSET_NUMBERS, "compileFontInfo: Boolean properties offset mismatch");
+ for (const prop of FONT_INFO.numbers) {
+ view.setFloat64(offset, font[prop]);
+ offset += 8;
+ }
+ assert(offset === FONT_INFO.OFFSET_BBOX, "compileFontInfo: Number properties offset mismatch");
+ if (font.bbox) {
+ view.setUint8(offset++, 4);
+ for (const coord of font.bbox) {
+ view.setInt16(offset, coord, true);
+ offset += 2;
+ }
+ } else {
+ view.setUint8(offset++, 0);
+ offset += 2 * 4;
+ }
+ assert(offset === FONT_INFO.OFFSET_FONT_MATRIX, "compileFontInfo: BBox properties offset mismatch");
+ if (font.fontMatrix) {
+ view.setUint8(offset++, 6);
+ for (const point of font.fontMatrix) {
+ view.setFloat64(offset, point, true);
+ offset += 8;
+ }
+ } else {
+ view.setUint8(offset++, 0);
+ offset += 8 * 6;
+ }
+ assert(offset === FONT_INFO.OFFSET_DEFAULT_VMETRICS, "compileFontInfo: FontMatrix properties offset mismatch");
+ if (font.defaultVMetrics) {
+ view.setUint8(offset++, 3);
+ for (const metric of font.defaultVMetrics) {
+ view.setInt16(offset, metric, true);
+ offset += 2;
+ }
+ } else {
+ view.setUint8(offset++, 0);
+ offset += 3 * 2;
+ }
+ assert(offset === FONT_INFO.OFFSET_STRINGS, "compileFontInfo: DefaultVMetrics properties offset mismatch");
+ view.setUint32(FONT_INFO.OFFSET_STRINGS, 0);
+ offset += 4;
+ for (const prop of FONT_INFO.strings) {
+ const encoded = encodedStrings[prop];
+ const length = encoded.length;
+ view.setUint32(offset, length);
+ data.set(encoded, offset + 4);
+ offset += 4 + length;
+ }
+ view.setUint32(FONT_INFO.OFFSET_STRINGS, offset - FONT_INFO.OFFSET_STRINGS - 4);
+ if (!systemFontInfoBuffer) {
+ view.setUint32(offset, 0);
+ offset += 4;
+ } else {
+ const length = systemFontInfoBuffer.byteLength;
+ view.setUint32(offset, length);
+ assert(offset + 4 + length <= buffer.byteLength, "compileFontInfo: Buffer overflow at systemFontInfo");
+ data.set(new Uint8Array(systemFontInfoBuffer), offset + 4);
+ offset += 4 + length;
+ }
+ if (!cssFontInfoBuffer) {
+ view.setUint32(offset, 0);
+ offset += 4;
+ } else {
+ const length = cssFontInfoBuffer.byteLength;
+ view.setUint32(offset, length);
+ assert(offset + 4 + length <= buffer.byteLength, "compileFontInfo: Buffer overflow at cssFontInfo");
+ data.set(new Uint8Array(cssFontInfoBuffer), offset + 4);
+ offset += 4 + length;
+ }
+ if (font.data === undefined) {
+ view.setUint32(offset, 0);
+ offset += 4;
+ } else {
+ view.setUint32(offset, font.data.length);
+ data.set(font.data, offset + 4);
+ offset += 4 + font.data.length;
+ }
+ assert(offset <= buffer.byteLength, "compileFontInfo: Buffer overflow");
+ return buffer.transferToFixedLength(offset);
+}
+function compilePatternInfo(ir) {
+ let kind,
+ bbox = null,
+ coords = [],
+ colors = [],
+ colorStops = [],
+ shadingType = null,
+ background = null;
+ switch (ir[0]) {
+ case "RadialAxial":
+ kind = ir[1] === "axial" ? 1 : 2;
+ bbox = ir[2];
+ colorStops = ir[3];
+ if (kind === 1) {
+ coords.push(...ir[4], ...ir[5]);
+ } else {
+ coords.push(ir[4][0], ir[4][1], ir[6], ir[5][0], ir[5][1], ir[7]);
+ }
+ break;
+ case "Mesh":
+ kind = 3;
+ shadingType = ir[1];
+ coords = ir[2];
+ colors = ir[3];
+ bbox = ir[6];
+ background = ir[7];
+ break;
+ default:
+ throw new Error(`Unsupported pattern type: ${ir[0]}`);
+ }
+ const nCoord = Math.floor(coords.length / 2);
+ const nColor = Math.floor(colors.length / 4);
+ const nStop = colorStops.length;
+ const byteLen = 20 + nCoord * 8 + nColor * 4 + nStop * 8 + (bbox ? 16 : 0) + (background ? 3 : 0);
+ const buffer = new ArrayBuffer(byteLen);
+ const dataView = new DataView(buffer);
+ const u8data = new Uint8Array(buffer);
+ dataView.setUint8(PATTERN_INFO.KIND, kind);
+ dataView.setUint8(PATTERN_INFO.HAS_BBOX, bbox ? 1 : 0);
+ dataView.setUint8(PATTERN_INFO.HAS_BACKGROUND, background ? 1 : 0);
+ dataView.setUint8(PATTERN_INFO.SHADING_TYPE, shadingType);
+ dataView.setUint32(PATTERN_INFO.N_COORD, nCoord, true);
+ dataView.setUint32(PATTERN_INFO.N_COLOR, nColor, true);
+ dataView.setUint32(PATTERN_INFO.N_STOP, nStop, true);
+ dataView.setUint32(PATTERN_INFO.N_FIGURES, 0, true);
+ let offset = 20;
+ const coordsView = new Float32Array(buffer, offset, nCoord * 2);
+ coordsView.set(coords);
+ offset += nCoord * 8;
+ u8data.set(colors, offset);
+ offset += nColor * 4;
+ for (const [pos, hex] of colorStops) {
+ dataView.setFloat32(offset, pos, true);
+ offset += 4;
+ dataView.setUint32(offset, parseInt(hex.slice(1), 16), true);
+ offset += 4;
+ }
+ if (bbox) {
+ for (const v of bbox) {
+ dataView.setFloat32(offset, v, true);
+ offset += 4;
+ }
+ }
+ if (background) {
+ u8data.set(background, offset);
+ }
+ return buffer;
+}
+function compileFontPathInfo(path) {
+ return path.slice().buffer;
+}
+
+;// ./src/core/font_renderer.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+function getFloat214(view, offset) {
+ return view.getInt16(offset) / 16384;
+}
+function getSubroutineBias(subrs) {
+ const numSubrs = subrs.length;
+ if (numSubrs >= 33900) {
+ return 32768;
+ }
+ return numSubrs < 1240 ? 107 : 1131;
+}
+function parseCmap(data, start, end) {
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
+ const offset = view.getUint16(start + 2) === 1 ? view.getUint32(start + 8) : view.getUint32(start + 16);
+ const format = view.getUint16(start + offset);
+ let ranges, p, i;
+ if (format === 4) {
+ const segCount = view.getUint16(start + offset + 6) >> 1;
+ p = start + offset + 14;
+ ranges = [];
+ for (i = 0; i < segCount; i++, p += 2) {
+ ranges[i] = {
+ end: view.getUint16(p)
+ };
+ }
+ p += 2;
+ for (i = 0; i < segCount; i++, p += 2) {
+ ranges[i].start = view.getUint16(p);
+ }
+ for (i = 0; i < segCount; i++, p += 2) {
+ ranges[i].idDelta = view.getUint16(p);
+ }
+ for (i = 0; i < segCount; i++, p += 2) {
+ let idOffset = view.getUint16(p);
+ if (idOffset === 0) {
+ continue;
+ }
+ ranges[i].ids = [];
+ for (let j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
+ ranges[i].ids[j] = view.getUint16(p + idOffset);
+ idOffset += 2;
+ }
+ }
+ return ranges;
+ } else if (format === 12) {
+ const groups = view.getUint32(start + offset + 12);
+ p = start + offset + 16;
+ ranges = [];
+ for (i = 0; i < groups; i++) {
+ start = view.getUint32(p);
+ ranges.push({
+ start,
+ end: view.getUint32(p + 4),
+ idDelta: view.getUint32(p + 8) - start
+ });
+ p += 12;
+ }
+ return ranges;
+ }
+ throw new FormatError(`unsupported cmap: ${format}`);
+}
+function parseCff(data, start, end, seacAnalysisEnabled) {
+ const properties = {};
+ const parser = new CFFParser(new Stream(data, start, end - start), properties, seacAnalysisEnabled);
+ const cff = parser.parse();
+ return {
+ glyphs: cff.charStrings.objects,
+ subrs: cff.topDict.privateDict?.subrsIndex?.objects,
+ gsubrs: cff.globalSubrIndex?.objects,
+ isCFFCIDFont: cff.isCIDFont,
+ fdSelect: cff.fdSelect,
+ fdArray: cff.fdArray
+ };
+}
+function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
+ const view = new DataView(loca.buffer, loca.byteOffset, loca.byteLength);
+ let itemSize, itemDecode;
+ if (isGlyphLocationsLong) {
+ itemSize = 4;
+ itemDecode = (dv, offset) => dv.getUint32(offset);
+ } else {
+ itemSize = 2;
+ itemDecode = (dv, offset) => 2 * dv.getUint16(offset);
+ }
+ const glyphs = [];
+ let startOffset = itemDecode(view, 0);
+ for (let j = itemSize; j < loca.length; j += itemSize) {
+ const endOffset = itemDecode(view, j);
+ glyphs.push(glyf.subarray(startOffset, endOffset));
+ startOffset = endOffset;
+ }
+ return glyphs;
+}
+function lookupCmap(ranges, unicode) {
+ const code = unicode.codePointAt(0);
+ let gid = 0,
+ l = 0,
+ r = ranges.length - 1;
+ while (l < r) {
+ const c = l + r + 1 >> 1;
+ if (code < ranges[c].start) {
+ r = c - 1;
+ } else {
+ l = c;
+ }
+ }
+ if (ranges[l].start <= code && code <= ranges[l].end) {
+ gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xffff;
+ }
+ return {
+ charCode: code,
+ glyphId: gid
+ };
+}
+function compileGlyf(code, cmds, font, visitedGlyphs = new Set()) {
+ if (!code?.length) {
+ return;
+ }
+ if (visitedGlyphs.has(code)) {
+ warn("compileGlyf: skipping recursive composite glyph reference.");
+ return;
+ }
+ visitedGlyphs.add(code);
+ function moveTo(x, y) {
+ if (firstPoint) {
+ cmds.add(DrawOPS.lineTo, firstPoint);
+ }
+ firstPoint = [x, y];
+ cmds.add(DrawOPS.moveTo, [x, y]);
+ }
+ function lineTo(x, y) {
+ cmds.add(DrawOPS.lineTo, [x, y]);
+ }
+ function quadraticCurveTo(xa, ya, x, y) {
+ cmds.add(DrawOPS.quadraticCurveTo, [xa, ya, x, y]);
+ }
+ const view = new DataView(code.buffer, code.byteOffset, code.byteLength);
+ let i = 0;
+ const numberOfContours = view.getInt16(i);
+ let flags;
+ let firstPoint = null;
+ let x = 0,
+ y = 0;
+ i += 10;
+ if (numberOfContours < 0) {
+ do {
+ flags = view.getUint16(i);
+ const glyphIndex = view.getUint16(i + 2);
+ i += 4;
+ let arg1, arg2;
+ if (flags & 0x01) {
+ if (flags & 0x02) {
+ arg1 = view.getInt16(i);
+ arg2 = view.getInt16(i + 2);
+ } else {
+ arg1 = view.getUint16(i);
+ arg2 = view.getUint16(i + 2);
+ }
+ i += 4;
+ } else if (flags & 0x02) {
+ arg1 = view.getInt8(i++);
+ arg2 = view.getInt8(i++);
+ } else {
+ arg1 = code[i++];
+ arg2 = code[i++];
+ }
+ if (flags & 0x02) {
+ x = arg1;
+ y = arg2;
+ } else {
+ x = 0;
+ y = 0;
+ }
+ let scaleX = 1,
+ scaleY = 1,
+ scale01 = 0,
+ scale10 = 0;
+ if (flags & 0x08) {
+ scaleX = scaleY = getFloat214(view, i);
+ i += 2;
+ } else if (flags & 0x40) {
+ scaleX = getFloat214(view, i);
+ scaleY = getFloat214(view, i + 2);
+ i += 4;
+ } else if (flags & 0x80) {
+ scaleX = getFloat214(view, i);
+ scale01 = getFloat214(view, i + 2);
+ scale10 = getFloat214(view, i + 4);
+ scaleY = getFloat214(view, i + 6);
+ i += 8;
+ }
+ const subglyph = font.glyphs[glyphIndex];
+ if (subglyph) {
+ cmds.save();
+ cmds.transform([scaleX, scale01, scale10, scaleY, x, y]);
+ if (!(flags & 0x02)) {}
+ compileGlyf(subglyph, cmds, font, visitedGlyphs);
+ cmds.restore();
+ }
+ } while (flags & 0x20);
+ } else {
+ const endPtsOfContours = [];
+ let j, jj;
+ for (j = 0; j < numberOfContours; j++) {
+ endPtsOfContours.push(view.getUint16(i));
+ i += 2;
+ }
+ const instructionLength = view.getUint16(i);
+ i += 2 + instructionLength;
+ const numberOfPoints = endPtsOfContours.at(-1) + 1;
+ const points = [];
+ while (points.length < numberOfPoints) {
+ flags = code[i++];
+ let repeat = 1;
+ if (flags & 0x08) {
+ repeat += code[i++];
+ }
+ while (repeat-- > 0) {
+ points.push({
+ flags
+ });
+ }
+ }
+ for (j = 0; j < numberOfPoints; j++) {
+ switch (points[j].flags & 0x12) {
+ case 0x00:
+ x += view.getInt16(i);
+ i += 2;
+ break;
+ case 0x02:
+ x -= code[i++];
+ break;
+ case 0x12:
+ x += code[i++];
+ break;
+ }
+ points[j].x = x;
+ }
+ for (j = 0; j < numberOfPoints; j++) {
+ switch (points[j].flags & 0x24) {
+ case 0x00:
+ y += view.getInt16(i);
+ i += 2;
+ break;
+ case 0x04:
+ y -= code[i++];
+ break;
+ case 0x24:
+ y += code[i++];
+ break;
+ }
+ points[j].y = y;
+ }
+ let startPoint = 0;
+ for (i = 0; i < numberOfContours; i++) {
+ const endPoint = endPtsOfContours[i];
+ const contour = points.slice(startPoint, endPoint + 1);
+ if (contour[0].flags & 1) {
+ contour.push(contour[0]);
+ } else if (contour.at(-1).flags & 1) {
+ contour.unshift(contour.at(-1));
+ } else {
+ const p = {
+ flags: 1,
+ x: (contour[0].x + contour.at(-1).x) / 2,
+ y: (contour[0].y + contour.at(-1).y) / 2
+ };
+ contour.unshift(p);
+ contour.push(p);
+ }
+ moveTo(contour[0].x, contour[0].y);
+ for (j = 1, jj = contour.length; j < jj; j++) {
+ if (contour[j].flags & 1) {
+ lineTo(contour[j].x, contour[j].y);
+ } else if (contour[j + 1].flags & 1) {
+ quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y);
+ j++;
+ } else {
+ quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2);
+ }
+ }
+ startPoint = endPoint + 1;
+ }
+ }
+ visitedGlyphs.delete(code);
+}
+function compileCharString(charStringCode, cmds, font, glyphId) {
+ function moveTo(x, y) {
+ if (firstPoint) {
+ cmds.add(DrawOPS.lineTo, firstPoint);
+ }
+ firstPoint = [x, y];
+ cmds.add(DrawOPS.moveTo, [x, y]);
+ }
+ function lineTo(x, y) {
+ cmds.add(DrawOPS.lineTo, [x, y]);
+ }
+ function bezierCurveTo(x1, y1, x2, y2, x, y) {
+ cmds.add(DrawOPS.curveTo, [x1, y1, x2, y2, x, y]);
+ }
+ const stack = [];
+ let x = 0,
+ y = 0;
+ let stems = 0;
+ let firstPoint = null;
+ function parse(code) {
+ const view = new DataView(code.buffer, code.byteOffset, code.byteLength);
+ let i = 0;
+ while (i < code.length) {
+ let stackClean = false;
+ let v = code[i++];
+ let xa, xb, ya, yb, y1, y2, y3, n, subrCode;
+ switch (v) {
+ case 1:
+ stems += stack.length >> 1;
+ stackClean = true;
+ break;
+ case 3:
+ stems += stack.length >> 1;
+ stackClean = true;
+ break;
+ case 4:
+ y += stack.pop();
+ moveTo(x, y);
+ stackClean = true;
+ break;
+ case 5:
+ while (stack.length > 0) {
+ x += stack.shift();
+ y += stack.shift();
+ lineTo(x, y);
+ }
+ break;
+ case 6:
+ while (stack.length > 0) {
+ x += stack.shift();
+ lineTo(x, y);
+ if (stack.length === 0) {
+ break;
+ }
+ y += stack.shift();
+ lineTo(x, y);
+ }
+ break;
+ case 7:
+ while (stack.length > 0) {
+ y += stack.shift();
+ lineTo(x, y);
+ if (stack.length === 0) {
+ break;
+ }
+ x += stack.shift();
+ lineTo(x, y);
+ }
+ break;
+ case 8:
+ while (stack.length > 0) {
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ }
+ break;
+ case 10:
+ n = stack.pop();
+ subrCode = null;
+ if (font.isCFFCIDFont) {
+ const fdIndex = font.fdSelect.getFDIndex(glyphId);
+ if (fdIndex >= 0 && fdIndex < font.fdArray.length) {
+ const fontDict = font.fdArray[fdIndex];
+ let subrs;
+ if (fontDict.privateDict?.subrsIndex) {
+ subrs = fontDict.privateDict.subrsIndex.objects;
+ }
+ if (subrs) {
+ n += getSubroutineBias(subrs);
+ subrCode = subrs[n];
+ }
+ } else {
+ warn("Invalid fd index for glyph index.");
+ }
+ } else {
+ subrCode = font.subrs[n + font.subrsBias];
+ }
+ if (subrCode) {
+ parse(subrCode);
+ }
+ break;
+ case 11:
+ return;
+ case 12:
+ v = code[i++];
+ switch (v) {
+ case 34:
+ xa = x + stack.shift();
+ xb = xa + stack.shift();
+ y1 = y + stack.shift();
+ x = xb + stack.shift();
+ bezierCurveTo(xa, y, xb, y1, x, y1);
+ xa = x + stack.shift();
+ xb = xa + stack.shift();
+ x = xb + stack.shift();
+ bezierCurveTo(xa, y1, xb, y, x, y);
+ break;
+ case 35:
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ stack.pop();
+ break;
+ case 36:
+ xa = x + stack.shift();
+ y1 = y + stack.shift();
+ xb = xa + stack.shift();
+ y2 = y1 + stack.shift();
+ x = xb + stack.shift();
+ bezierCurveTo(xa, y1, xb, y2, x, y2);
+ xa = x + stack.shift();
+ xb = xa + stack.shift();
+ y3 = y2 + stack.shift();
+ x = xb + stack.shift();
+ bezierCurveTo(xa, y2, xb, y3, x, y);
+ break;
+ case 37:
+ const x0 = x,
+ y0 = y;
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb;
+ y = yb;
+ if (Math.abs(x - x0) > Math.abs(y - y0)) {
+ x += stack.shift();
+ } else {
+ y += stack.shift();
+ }
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ break;
+ default:
+ throw new FormatError(`unknown operator: 12 ${v}`);
+ }
+ break;
+ case 14:
+ if (stack.length >= 4) {
+ const achar = stack.pop();
+ const bchar = stack.pop();
+ y = stack.pop();
+ x = stack.pop();
+ cmds.save();
+ cmds.translate(x, y);
+ let cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[StandardEncoding[achar]]));
+ compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
+ cmds.restore();
+ cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[StandardEncoding[bchar]]));
+ compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
+ }
+ return;
+ case 18:
+ stems += stack.length >> 1;
+ stackClean = true;
+ break;
+ case 19:
+ stems += stack.length >> 1;
+ i += stems + 7 >> 3;
+ stackClean = true;
+ break;
+ case 20:
+ stems += stack.length >> 1;
+ i += stems + 7 >> 3;
+ stackClean = true;
+ break;
+ case 21:
+ y += stack.pop();
+ x += stack.pop();
+ moveTo(x, y);
+ stackClean = true;
+ break;
+ case 22:
+ x += stack.pop();
+ moveTo(x, y);
+ stackClean = true;
+ break;
+ case 23:
+ stems += stack.length >> 1;
+ stackClean = true;
+ break;
+ case 24:
+ while (stack.length > 2) {
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ }
+ x += stack.shift();
+ y += stack.shift();
+ lineTo(x, y);
+ break;
+ case 25:
+ while (stack.length > 6) {
+ x += stack.shift();
+ y += stack.shift();
+ lineTo(x, y);
+ }
+ xa = x + stack.shift();
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ break;
+ case 26:
+ if (stack.length % 2) {
+ x += stack.shift();
+ }
+ while (stack.length > 0) {
+ xa = x;
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb;
+ y = yb + stack.shift();
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ }
+ break;
+ case 27:
+ if (stack.length % 2) {
+ y += stack.shift();
+ }
+ while (stack.length > 0) {
+ xa = x + stack.shift();
+ ya = y;
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb;
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ }
+ break;
+ case 28:
+ stack.push(view.getInt16(i));
+ i += 2;
+ break;
+ case 29:
+ n = stack.pop() + font.gsubrsBias;
+ subrCode = font.gsubrs[n];
+ if (subrCode) {
+ parse(subrCode);
+ }
+ break;
+ case 30:
+ while (stack.length > 0) {
+ xa = x;
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + (stack.length === 1 ? stack.shift() : 0);
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ if (stack.length === 0) {
+ break;
+ }
+ xa = x + stack.shift();
+ ya = y;
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ y = yb + stack.shift();
+ x = xb + (stack.length === 1 ? stack.shift() : 0);
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ }
+ break;
+ case 31:
+ while (stack.length > 0) {
+ xa = x + stack.shift();
+ ya = y;
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ y = yb + stack.shift();
+ x = xb + (stack.length === 1 ? stack.shift() : 0);
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ if (stack.length === 0) {
+ break;
+ }
+ xa = x;
+ ya = y + stack.shift();
+ xb = xa + stack.shift();
+ yb = ya + stack.shift();
+ x = xb + stack.shift();
+ y = yb + (stack.length === 1 ? stack.shift() : 0);
+ bezierCurveTo(xa, ya, xb, yb, x, y);
+ }
+ break;
+ default:
+ if (v < 32) {
+ throw new FormatError(`unknown operator: ${v}`);
+ }
+ if (v < 247) {
+ stack.push(v - 139);
+ } else if (v < 251) {
+ stack.push((v - 247) * 256 + code[i++] + 108);
+ } else if (v < 255) {
+ stack.push(-(v - 251) * 256 - code[i++] - 108);
+ } else {
+ stack.push(view.getInt32(i) / 65536);
+ i += 4;
+ }
+ break;
+ }
+ if (stackClean) {
+ stack.length = 0;
+ }
+ }
+ }
+ parse(charStringCode);
+}
+class Commands {
+ cmds = [];
+ transformStack = [];
+ currentTransform = [1, 0, 0, 1, 0, 0];
+ add(cmd, args) {
+ if (args) {
+ const {
+ currentTransform
+ } = this;
+ for (let i = 0, ii = args.length; i < ii; i += 2) {
+ Util.applyTransform(args, currentTransform, i);
+ }
+ this.cmds.push(cmd, ...args);
+ } else {
+ this.cmds.push(cmd);
+ }
+ }
+ transform(transf) {
+ this.currentTransform = Util.transform(this.currentTransform, transf);
+ }
+ translate(x, y) {
+ this.transform([1, 0, 0, 1, x, y]);
+ }
+ save() {
+ this.transformStack.push(this.currentTransform.slice());
+ }
+ restore() {
+ this.currentTransform = this.transformStack.pop() || [1, 0, 0, 1, 0, 0];
+ }
+ getPath() {
+ if (FeatureTest.isFloat16ArraySupported) {
+ return new Float16Array(this.cmds);
+ }
+ return new Float32Array(this.cmds);
+ }
+}
+class CompiledFont {
+ #compiledCharCodes = new Set();
+ #compiledGlyphs = new Map();
+ constructor(fontMatrix) {
+ this.fontMatrix = fontMatrix;
+ }
+ static get NOOP() {
+ return shadow(this, "NOOP", FeatureTest.isFloat16ArraySupported ? new Float16Array(0) : new Float32Array(0));
+ }
+ getPath(unicode) {
+ const {
+ charCode,
+ glyphId
+ } = lookupCmap(this.cmap, unicode);
+ if (this.#compiledGlyphs.has(glyphId) && this.#compiledCharCodes.has(charCode)) {
+ return null;
+ }
+ const path = this.#compiledGlyphs.getOrInsertComputed(glyphId, () => {
+ try {
+ return this.compileGlyph(this.glyphs[glyphId], glyphId);
+ } catch (ex) {
+ return ex;
+ }
+ });
+ this.#compiledCharCodes.add(charCode);
+ if (path instanceof Error) {
+ throw path;
+ }
+ return compileFontPathInfo(path);
+ }
+ compileGlyph(code, glyphId) {
+ if (!code?.length || code[0] === 14) {
+ return CompiledFont.NOOP;
+ }
+ let fontMatrix = this.fontMatrix;
+ if (this.isCFFCIDFont) {
+ const fdIndex = this.fdSelect.getFDIndex(glyphId);
+ if (fdIndex >= 0 && fdIndex < this.fdArray.length) {
+ const fontDict = this.fdArray[fdIndex];
+ fontMatrix = fontDict.getByName("FontMatrix") || FONT_IDENTITY_MATRIX;
+ } else {
+ warn("Invalid fd index for glyph index.");
+ }
+ }
+ assert(isNumberArray(fontMatrix, 6), "Expected a valid fontMatrix.");
+ const cmds = new Commands();
+ cmds.transform(fontMatrix.slice());
+ this.compileGlyphImpl(code, cmds, glyphId);
+ cmds.add(DrawOPS.closePath);
+ return cmds.getPath();
+ }
+ compileGlyphImpl() {
+ unreachable("Children classes should implement this.");
+ }
+}
+class TrueTypeCompiled extends CompiledFont {
+ constructor(glyphs, cmap, fontMatrix) {
+ super(fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]);
+ this.glyphs = glyphs;
+ this.cmap = cmap;
+ }
+ compileGlyphImpl(code, cmds) {
+ compileGlyf(code, cmds, this);
+ }
+}
+class Type2Compiled extends CompiledFont {
+ constructor(cffInfo, cmap, fontMatrix) {
+ super(fontMatrix || [0.001, 0, 0, 0.001, 0, 0]);
+ this.glyphs = cffInfo.glyphs;
+ this.gsubrs = cffInfo.gsubrs || [];
+ this.subrs = cffInfo.subrs || [];
+ this.cmap = cmap;
+ this.glyphNameMap = getGlyphsUnicode();
+ this.gsubrsBias = getSubroutineBias(this.gsubrs);
+ this.subrsBias = getSubroutineBias(this.subrs);
+ this.isCFFCIDFont = cffInfo.isCFFCIDFont;
+ this.fdSelect = cffInfo.fdSelect;
+ this.fdArray = cffInfo.fdArray;
+ }
+ compileGlyphImpl(code, cmds, glyphId) {
+ compileCharString(code, cmds, this, glyphId);
+ }
+}
+class FontRendererFactory {
+ static create(font, seacAnalysisEnabled) {
+ const data = new Uint8Array(font.data),
+ view = new DataView(data.buffer);
+ let cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
+ const numTables = view.getUint16(4);
+ for (let i = 0, p = 12; i < numTables; i++, p += 16) {
+ const tag = bytesToString(data.subarray(p, p + 4));
+ const offset = view.getUint32(p + 8);
+ const length = view.getUint32(p + 12);
+ switch (tag) {
+ case "cmap":
+ cmap = parseCmap(data, offset, offset + length);
+ break;
+ case "glyf":
+ glyf = data.subarray(offset, offset + length);
+ break;
+ case "loca":
+ loca = data.subarray(offset, offset + length);
+ break;
+ case "head":
+ unitsPerEm = view.getUint16(offset + 18);
+ indexToLocFormat = view.getUint16(offset + 50);
+ break;
+ case "CFF ":
+ cff = parseCff(data, offset, offset + length, seacAnalysisEnabled);
+ break;
+ }
+ }
+ if (glyf) {
+ const fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
+ return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
+ }
+ return new Type2Compiled(cff, cmap, font.fontMatrix);
+ }
+}
+
+;// ./src/core/metrics.js
+
+const getMetrics = getLookupTableFactory(function (t) {
+ t.Courier = 600;
+ t["Courier-Bold"] = 600;
+ t["Courier-BoldOblique"] = 600;
+ t["Courier-Oblique"] = 600;
+ t.Helvetica = getLookupTableFactory(function (t) {
+ t.space = 278;
+ t.exclam = 278;
+ t.quotedbl = 355;
+ t.numbersign = 556;
+ t.dollar = 556;
+ t.percent = 889;
+ t.ampersand = 667;
+ t.quoteright = 222;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 389;
+ t.plus = 584;
+ t.comma = 278;
+ t.hyphen = 333;
+ t.period = 278;
+ t.slash = 278;
+ t.zero = 556;
+ t.one = 556;
+ t.two = 556;
+ t.three = 556;
+ t.four = 556;
+ t.five = 556;
+ t.six = 556;
+ t.seven = 556;
+ t.eight = 556;
+ t.nine = 556;
+ t.colon = 278;
+ t.semicolon = 278;
+ t.less = 584;
+ t.equal = 584;
+ t.greater = 584;
+ t.question = 556;
+ t.at = 1015;
+ t.A = 667;
+ t.B = 667;
+ t.C = 722;
+ t.D = 722;
+ t.E = 667;
+ t.F = 611;
+ t.G = 778;
+ t.H = 722;
+ t.I = 278;
+ t.J = 500;
+ t.K = 667;
+ t.L = 556;
+ t.M = 833;
+ t.N = 722;
+ t.O = 778;
+ t.P = 667;
+ t.Q = 778;
+ t.R = 722;
+ t.S = 667;
+ t.T = 611;
+ t.U = 722;
+ t.V = 667;
+ t.W = 944;
+ t.X = 667;
+ t.Y = 667;
+ t.Z = 611;
+ t.bracketleft = 278;
+ t.backslash = 278;
+ t.bracketright = 278;
+ t.asciicircum = 469;
+ t.underscore = 556;
+ t.quoteleft = 222;
+ t.a = 556;
+ t.b = 556;
+ t.c = 500;
+ t.d = 556;
+ t.e = 556;
+ t.f = 278;
+ t.g = 556;
+ t.h = 556;
+ t.i = 222;
+ t.j = 222;
+ t.k = 500;
+ t.l = 222;
+ t.m = 833;
+ t.n = 556;
+ t.o = 556;
+ t.p = 556;
+ t.q = 556;
+ t.r = 333;
+ t.s = 500;
+ t.t = 278;
+ t.u = 556;
+ t.v = 500;
+ t.w = 722;
+ t.x = 500;
+ t.y = 500;
+ t.z = 500;
+ t.braceleft = 334;
+ t.bar = 260;
+ t.braceright = 334;
+ t.asciitilde = 584;
+ t.exclamdown = 333;
+ t.cent = 556;
+ t.sterling = 556;
+ t.fraction = 167;
+ t.yen = 556;
+ t.florin = 556;
+ t.section = 556;
+ t.currency = 556;
+ t.quotesingle = 191;
+ t.quotedblleft = 333;
+ t.guillemotleft = 556;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 500;
+ t.fl = 500;
+ t.endash = 556;
+ t.dagger = 556;
+ t.daggerdbl = 556;
+ t.periodcentered = 278;
+ t.paragraph = 537;
+ t.bullet = 350;
+ t.quotesinglbase = 222;
+ t.quotedblbase = 333;
+ t.quotedblright = 333;
+ t.guillemotright = 556;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 611;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 1000;
+ t.ordfeminine = 370;
+ t.Lslash = 556;
+ t.Oslash = 778;
+ t.OE = 1000;
+ t.ordmasculine = 365;
+ t.ae = 889;
+ t.dotlessi = 278;
+ t.lslash = 222;
+ t.oslash = 611;
+ t.oe = 944;
+ t.germandbls = 611;
+ t.Idieresis = 278;
+ t.eacute = 556;
+ t.abreve = 556;
+ t.uhungarumlaut = 556;
+ t.ecaron = 556;
+ t.Ydieresis = 667;
+ t.divide = 584;
+ t.Yacute = 667;
+ t.Acircumflex = 667;
+ t.aacute = 556;
+ t.Ucircumflex = 722;
+ t.yacute = 500;
+ t.scommaaccent = 500;
+ t.ecircumflex = 556;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 556;
+ t.Uacute = 722;
+ t.uogonek = 556;
+ t.Edieresis = 667;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 737;
+ t.Emacron = 667;
+ t.ccaron = 500;
+ t.aring = 556;
+ t.Ncommaaccent = 722;
+ t.lacute = 222;
+ t.agrave = 556;
+ t.Tcommaaccent = 611;
+ t.Cacute = 722;
+ t.atilde = 556;
+ t.Edotaccent = 667;
+ t.scaron = 500;
+ t.scedilla = 500;
+ t.iacute = 278;
+ t.lozenge = 471;
+ t.Rcaron = 722;
+ t.Gcommaaccent = 778;
+ t.ucircumflex = 556;
+ t.acircumflex = 556;
+ t.Amacron = 667;
+ t.rcaron = 333;
+ t.ccedilla = 500;
+ t.Zdotaccent = 611;
+ t.Thorn = 667;
+ t.Omacron = 778;
+ t.Racute = 722;
+ t.Sacute = 667;
+ t.dcaron = 643;
+ t.Umacron = 722;
+ t.uring = 556;
+ t.threesuperior = 333;
+ t.Ograve = 778;
+ t.Agrave = 667;
+ t.Abreve = 667;
+ t.multiply = 584;
+ t.uacute = 556;
+ t.Tcaron = 611;
+ t.partialdiff = 476;
+ t.ydieresis = 500;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 667;
+ t.adieresis = 556;
+ t.edieresis = 556;
+ t.cacute = 500;
+ t.nacute = 556;
+ t.umacron = 556;
+ t.Ncaron = 722;
+ t.Iacute = 278;
+ t.plusminus = 584;
+ t.brokenbar = 260;
+ t.registered = 737;
+ t.Gbreve = 778;
+ t.Idotaccent = 278;
+ t.summation = 600;
+ t.Egrave = 667;
+ t.racute = 333;
+ t.omacron = 556;
+ t.Zacute = 611;
+ t.Zcaron = 611;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 722;
+ t.lcommaaccent = 222;
+ t.tcaron = 317;
+ t.eogonek = 556;
+ t.Uogonek = 722;
+ t.Aacute = 667;
+ t.Adieresis = 667;
+ t.egrave = 556;
+ t.zacute = 500;
+ t.iogonek = 222;
+ t.Oacute = 778;
+ t.oacute = 556;
+ t.amacron = 556;
+ t.sacute = 500;
+ t.idieresis = 278;
+ t.Ocircumflex = 778;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 556;
+ t.twosuperior = 333;
+ t.Odieresis = 778;
+ t.mu = 556;
+ t.igrave = 278;
+ t.ohungarumlaut = 556;
+ t.Eogonek = 667;
+ t.dcroat = 556;
+ t.threequarters = 834;
+ t.Scedilla = 667;
+ t.lcaron = 299;
+ t.Kcommaaccent = 667;
+ t.Lacute = 556;
+ t.trademark = 1000;
+ t.edotaccent = 556;
+ t.Igrave = 278;
+ t.Imacron = 278;
+ t.Lcaron = 556;
+ t.onehalf = 834;
+ t.lessequal = 549;
+ t.ocircumflex = 556;
+ t.ntilde = 556;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 667;
+ t.emacron = 556;
+ t.gbreve = 556;
+ t.onequarter = 834;
+ t.Scaron = 667;
+ t.Scommaaccent = 667;
+ t.Ohungarumlaut = 778;
+ t.degree = 400;
+ t.ograve = 556;
+ t.Ccaron = 722;
+ t.ugrave = 556;
+ t.radical = 453;
+ t.Dcaron = 722;
+ t.rcommaaccent = 333;
+ t.Ntilde = 722;
+ t.otilde = 556;
+ t.Rcommaaccent = 722;
+ t.Lcommaaccent = 556;
+ t.Atilde = 667;
+ t.Aogonek = 667;
+ t.Aring = 667;
+ t.Otilde = 778;
+ t.zdotaccent = 500;
+ t.Ecaron = 667;
+ t.Iogonek = 278;
+ t.kcommaaccent = 500;
+ t.minus = 584;
+ t.Icircumflex = 278;
+ t.ncaron = 556;
+ t.tcommaaccent = 278;
+ t.logicalnot = 584;
+ t.odieresis = 556;
+ t.udieresis = 556;
+ t.notequal = 549;
+ t.gcommaaccent = 556;
+ t.eth = 556;
+ t.zcaron = 500;
+ t.ncommaaccent = 556;
+ t.onesuperior = 333;
+ t.imacron = 278;
+ t.Euro = 556;
+ });
+ t["Helvetica-Bold"] = getLookupTableFactory(function (t) {
+ t.space = 278;
+ t.exclam = 333;
+ t.quotedbl = 474;
+ t.numbersign = 556;
+ t.dollar = 556;
+ t.percent = 889;
+ t.ampersand = 722;
+ t.quoteright = 278;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 389;
+ t.plus = 584;
+ t.comma = 278;
+ t.hyphen = 333;
+ t.period = 278;
+ t.slash = 278;
+ t.zero = 556;
+ t.one = 556;
+ t.two = 556;
+ t.three = 556;
+ t.four = 556;
+ t.five = 556;
+ t.six = 556;
+ t.seven = 556;
+ t.eight = 556;
+ t.nine = 556;
+ t.colon = 333;
+ t.semicolon = 333;
+ t.less = 584;
+ t.equal = 584;
+ t.greater = 584;
+ t.question = 611;
+ t.at = 975;
+ t.A = 722;
+ t.B = 722;
+ t.C = 722;
+ t.D = 722;
+ t.E = 667;
+ t.F = 611;
+ t.G = 778;
+ t.H = 722;
+ t.I = 278;
+ t.J = 556;
+ t.K = 722;
+ t.L = 611;
+ t.M = 833;
+ t.N = 722;
+ t.O = 778;
+ t.P = 667;
+ t.Q = 778;
+ t.R = 722;
+ t.S = 667;
+ t.T = 611;
+ t.U = 722;
+ t.V = 667;
+ t.W = 944;
+ t.X = 667;
+ t.Y = 667;
+ t.Z = 611;
+ t.bracketleft = 333;
+ t.backslash = 278;
+ t.bracketright = 333;
+ t.asciicircum = 584;
+ t.underscore = 556;
+ t.quoteleft = 278;
+ t.a = 556;
+ t.b = 611;
+ t.c = 556;
+ t.d = 611;
+ t.e = 556;
+ t.f = 333;
+ t.g = 611;
+ t.h = 611;
+ t.i = 278;
+ t.j = 278;
+ t.k = 556;
+ t.l = 278;
+ t.m = 889;
+ t.n = 611;
+ t.o = 611;
+ t.p = 611;
+ t.q = 611;
+ t.r = 389;
+ t.s = 556;
+ t.t = 333;
+ t.u = 611;
+ t.v = 556;
+ t.w = 778;
+ t.x = 556;
+ t.y = 556;
+ t.z = 500;
+ t.braceleft = 389;
+ t.bar = 280;
+ t.braceright = 389;
+ t.asciitilde = 584;
+ t.exclamdown = 333;
+ t.cent = 556;
+ t.sterling = 556;
+ t.fraction = 167;
+ t.yen = 556;
+ t.florin = 556;
+ t.section = 556;
+ t.currency = 556;
+ t.quotesingle = 238;
+ t.quotedblleft = 500;
+ t.guillemotleft = 556;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 611;
+ t.fl = 611;
+ t.endash = 556;
+ t.dagger = 556;
+ t.daggerdbl = 556;
+ t.periodcentered = 278;
+ t.paragraph = 556;
+ t.bullet = 350;
+ t.quotesinglbase = 278;
+ t.quotedblbase = 500;
+ t.quotedblright = 500;
+ t.guillemotright = 556;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 611;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 1000;
+ t.ordfeminine = 370;
+ t.Lslash = 611;
+ t.Oslash = 778;
+ t.OE = 1000;
+ t.ordmasculine = 365;
+ t.ae = 889;
+ t.dotlessi = 278;
+ t.lslash = 278;
+ t.oslash = 611;
+ t.oe = 944;
+ t.germandbls = 611;
+ t.Idieresis = 278;
+ t.eacute = 556;
+ t.abreve = 556;
+ t.uhungarumlaut = 611;
+ t.ecaron = 556;
+ t.Ydieresis = 667;
+ t.divide = 584;
+ t.Yacute = 667;
+ t.Acircumflex = 722;
+ t.aacute = 556;
+ t.Ucircumflex = 722;
+ t.yacute = 556;
+ t.scommaaccent = 556;
+ t.ecircumflex = 556;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 556;
+ t.Uacute = 722;
+ t.uogonek = 611;
+ t.Edieresis = 667;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 737;
+ t.Emacron = 667;
+ t.ccaron = 556;
+ t.aring = 556;
+ t.Ncommaaccent = 722;
+ t.lacute = 278;
+ t.agrave = 556;
+ t.Tcommaaccent = 611;
+ t.Cacute = 722;
+ t.atilde = 556;
+ t.Edotaccent = 667;
+ t.scaron = 556;
+ t.scedilla = 556;
+ t.iacute = 278;
+ t.lozenge = 494;
+ t.Rcaron = 722;
+ t.Gcommaaccent = 778;
+ t.ucircumflex = 611;
+ t.acircumflex = 556;
+ t.Amacron = 722;
+ t.rcaron = 389;
+ t.ccedilla = 556;
+ t.Zdotaccent = 611;
+ t.Thorn = 667;
+ t.Omacron = 778;
+ t.Racute = 722;
+ t.Sacute = 667;
+ t.dcaron = 743;
+ t.Umacron = 722;
+ t.uring = 611;
+ t.threesuperior = 333;
+ t.Ograve = 778;
+ t.Agrave = 722;
+ t.Abreve = 722;
+ t.multiply = 584;
+ t.uacute = 611;
+ t.Tcaron = 611;
+ t.partialdiff = 494;
+ t.ydieresis = 556;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 667;
+ t.adieresis = 556;
+ t.edieresis = 556;
+ t.cacute = 556;
+ t.nacute = 611;
+ t.umacron = 611;
+ t.Ncaron = 722;
+ t.Iacute = 278;
+ t.plusminus = 584;
+ t.brokenbar = 280;
+ t.registered = 737;
+ t.Gbreve = 778;
+ t.Idotaccent = 278;
+ t.summation = 600;
+ t.Egrave = 667;
+ t.racute = 389;
+ t.omacron = 611;
+ t.Zacute = 611;
+ t.Zcaron = 611;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 722;
+ t.lcommaaccent = 278;
+ t.tcaron = 389;
+ t.eogonek = 556;
+ t.Uogonek = 722;
+ t.Aacute = 722;
+ t.Adieresis = 722;
+ t.egrave = 556;
+ t.zacute = 500;
+ t.iogonek = 278;
+ t.Oacute = 778;
+ t.oacute = 611;
+ t.amacron = 556;
+ t.sacute = 556;
+ t.idieresis = 278;
+ t.Ocircumflex = 778;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 611;
+ t.twosuperior = 333;
+ t.Odieresis = 778;
+ t.mu = 611;
+ t.igrave = 278;
+ t.ohungarumlaut = 611;
+ t.Eogonek = 667;
+ t.dcroat = 611;
+ t.threequarters = 834;
+ t.Scedilla = 667;
+ t.lcaron = 400;
+ t.Kcommaaccent = 722;
+ t.Lacute = 611;
+ t.trademark = 1000;
+ t.edotaccent = 556;
+ t.Igrave = 278;
+ t.Imacron = 278;
+ t.Lcaron = 611;
+ t.onehalf = 834;
+ t.lessequal = 549;
+ t.ocircumflex = 611;
+ t.ntilde = 611;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 667;
+ t.emacron = 556;
+ t.gbreve = 611;
+ t.onequarter = 834;
+ t.Scaron = 667;
+ t.Scommaaccent = 667;
+ t.Ohungarumlaut = 778;
+ t.degree = 400;
+ t.ograve = 611;
+ t.Ccaron = 722;
+ t.ugrave = 611;
+ t.radical = 549;
+ t.Dcaron = 722;
+ t.rcommaaccent = 389;
+ t.Ntilde = 722;
+ t.otilde = 611;
+ t.Rcommaaccent = 722;
+ t.Lcommaaccent = 611;
+ t.Atilde = 722;
+ t.Aogonek = 722;
+ t.Aring = 722;
+ t.Otilde = 778;
+ t.zdotaccent = 500;
+ t.Ecaron = 667;
+ t.Iogonek = 278;
+ t.kcommaaccent = 556;
+ t.minus = 584;
+ t.Icircumflex = 278;
+ t.ncaron = 611;
+ t.tcommaaccent = 333;
+ t.logicalnot = 584;
+ t.odieresis = 611;
+ t.udieresis = 611;
+ t.notequal = 549;
+ t.gcommaaccent = 611;
+ t.eth = 611;
+ t.zcaron = 500;
+ t.ncommaaccent = 611;
+ t.onesuperior = 333;
+ t.imacron = 278;
+ t.Euro = 556;
+ });
+ t["Helvetica-BoldOblique"] = getLookupTableFactory(function (t) {
+ t.space = 278;
+ t.exclam = 333;
+ t.quotedbl = 474;
+ t.numbersign = 556;
+ t.dollar = 556;
+ t.percent = 889;
+ t.ampersand = 722;
+ t.quoteright = 278;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 389;
+ t.plus = 584;
+ t.comma = 278;
+ t.hyphen = 333;
+ t.period = 278;
+ t.slash = 278;
+ t.zero = 556;
+ t.one = 556;
+ t.two = 556;
+ t.three = 556;
+ t.four = 556;
+ t.five = 556;
+ t.six = 556;
+ t.seven = 556;
+ t.eight = 556;
+ t.nine = 556;
+ t.colon = 333;
+ t.semicolon = 333;
+ t.less = 584;
+ t.equal = 584;
+ t.greater = 584;
+ t.question = 611;
+ t.at = 975;
+ t.A = 722;
+ t.B = 722;
+ t.C = 722;
+ t.D = 722;
+ t.E = 667;
+ t.F = 611;
+ t.G = 778;
+ t.H = 722;
+ t.I = 278;
+ t.J = 556;
+ t.K = 722;
+ t.L = 611;
+ t.M = 833;
+ t.N = 722;
+ t.O = 778;
+ t.P = 667;
+ t.Q = 778;
+ t.R = 722;
+ t.S = 667;
+ t.T = 611;
+ t.U = 722;
+ t.V = 667;
+ t.W = 944;
+ t.X = 667;
+ t.Y = 667;
+ t.Z = 611;
+ t.bracketleft = 333;
+ t.backslash = 278;
+ t.bracketright = 333;
+ t.asciicircum = 584;
+ t.underscore = 556;
+ t.quoteleft = 278;
+ t.a = 556;
+ t.b = 611;
+ t.c = 556;
+ t.d = 611;
+ t.e = 556;
+ t.f = 333;
+ t.g = 611;
+ t.h = 611;
+ t.i = 278;
+ t.j = 278;
+ t.k = 556;
+ t.l = 278;
+ t.m = 889;
+ t.n = 611;
+ t.o = 611;
+ t.p = 611;
+ t.q = 611;
+ t.r = 389;
+ t.s = 556;
+ t.t = 333;
+ t.u = 611;
+ t.v = 556;
+ t.w = 778;
+ t.x = 556;
+ t.y = 556;
+ t.z = 500;
+ t.braceleft = 389;
+ t.bar = 280;
+ t.braceright = 389;
+ t.asciitilde = 584;
+ t.exclamdown = 333;
+ t.cent = 556;
+ t.sterling = 556;
+ t.fraction = 167;
+ t.yen = 556;
+ t.florin = 556;
+ t.section = 556;
+ t.currency = 556;
+ t.quotesingle = 238;
+ t.quotedblleft = 500;
+ t.guillemotleft = 556;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 611;
+ t.fl = 611;
+ t.endash = 556;
+ t.dagger = 556;
+ t.daggerdbl = 556;
+ t.periodcentered = 278;
+ t.paragraph = 556;
+ t.bullet = 350;
+ t.quotesinglbase = 278;
+ t.quotedblbase = 500;
+ t.quotedblright = 500;
+ t.guillemotright = 556;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 611;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 1000;
+ t.ordfeminine = 370;
+ t.Lslash = 611;
+ t.Oslash = 778;
+ t.OE = 1000;
+ t.ordmasculine = 365;
+ t.ae = 889;
+ t.dotlessi = 278;
+ t.lslash = 278;
+ t.oslash = 611;
+ t.oe = 944;
+ t.germandbls = 611;
+ t.Idieresis = 278;
+ t.eacute = 556;
+ t.abreve = 556;
+ t.uhungarumlaut = 611;
+ t.ecaron = 556;
+ t.Ydieresis = 667;
+ t.divide = 584;
+ t.Yacute = 667;
+ t.Acircumflex = 722;
+ t.aacute = 556;
+ t.Ucircumflex = 722;
+ t.yacute = 556;
+ t.scommaaccent = 556;
+ t.ecircumflex = 556;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 556;
+ t.Uacute = 722;
+ t.uogonek = 611;
+ t.Edieresis = 667;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 737;
+ t.Emacron = 667;
+ t.ccaron = 556;
+ t.aring = 556;
+ t.Ncommaaccent = 722;
+ t.lacute = 278;
+ t.agrave = 556;
+ t.Tcommaaccent = 611;
+ t.Cacute = 722;
+ t.atilde = 556;
+ t.Edotaccent = 667;
+ t.scaron = 556;
+ t.scedilla = 556;
+ t.iacute = 278;
+ t.lozenge = 494;
+ t.Rcaron = 722;
+ t.Gcommaaccent = 778;
+ t.ucircumflex = 611;
+ t.acircumflex = 556;
+ t.Amacron = 722;
+ t.rcaron = 389;
+ t.ccedilla = 556;
+ t.Zdotaccent = 611;
+ t.Thorn = 667;
+ t.Omacron = 778;
+ t.Racute = 722;
+ t.Sacute = 667;
+ t.dcaron = 743;
+ t.Umacron = 722;
+ t.uring = 611;
+ t.threesuperior = 333;
+ t.Ograve = 778;
+ t.Agrave = 722;
+ t.Abreve = 722;
+ t.multiply = 584;
+ t.uacute = 611;
+ t.Tcaron = 611;
+ t.partialdiff = 494;
+ t.ydieresis = 556;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 667;
+ t.adieresis = 556;
+ t.edieresis = 556;
+ t.cacute = 556;
+ t.nacute = 611;
+ t.umacron = 611;
+ t.Ncaron = 722;
+ t.Iacute = 278;
+ t.plusminus = 584;
+ t.brokenbar = 280;
+ t.registered = 737;
+ t.Gbreve = 778;
+ t.Idotaccent = 278;
+ t.summation = 600;
+ t.Egrave = 667;
+ t.racute = 389;
+ t.omacron = 611;
+ t.Zacute = 611;
+ t.Zcaron = 611;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 722;
+ t.lcommaaccent = 278;
+ t.tcaron = 389;
+ t.eogonek = 556;
+ t.Uogonek = 722;
+ t.Aacute = 722;
+ t.Adieresis = 722;
+ t.egrave = 556;
+ t.zacute = 500;
+ t.iogonek = 278;
+ t.Oacute = 778;
+ t.oacute = 611;
+ t.amacron = 556;
+ t.sacute = 556;
+ t.idieresis = 278;
+ t.Ocircumflex = 778;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 611;
+ t.twosuperior = 333;
+ t.Odieresis = 778;
+ t.mu = 611;
+ t.igrave = 278;
+ t.ohungarumlaut = 611;
+ t.Eogonek = 667;
+ t.dcroat = 611;
+ t.threequarters = 834;
+ t.Scedilla = 667;
+ t.lcaron = 400;
+ t.Kcommaaccent = 722;
+ t.Lacute = 611;
+ t.trademark = 1000;
+ t.edotaccent = 556;
+ t.Igrave = 278;
+ t.Imacron = 278;
+ t.Lcaron = 611;
+ t.onehalf = 834;
+ t.lessequal = 549;
+ t.ocircumflex = 611;
+ t.ntilde = 611;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 667;
+ t.emacron = 556;
+ t.gbreve = 611;
+ t.onequarter = 834;
+ t.Scaron = 667;
+ t.Scommaaccent = 667;
+ t.Ohungarumlaut = 778;
+ t.degree = 400;
+ t.ograve = 611;
+ t.Ccaron = 722;
+ t.ugrave = 611;
+ t.radical = 549;
+ t.Dcaron = 722;
+ t.rcommaaccent = 389;
+ t.Ntilde = 722;
+ t.otilde = 611;
+ t.Rcommaaccent = 722;
+ t.Lcommaaccent = 611;
+ t.Atilde = 722;
+ t.Aogonek = 722;
+ t.Aring = 722;
+ t.Otilde = 778;
+ t.zdotaccent = 500;
+ t.Ecaron = 667;
+ t.Iogonek = 278;
+ t.kcommaaccent = 556;
+ t.minus = 584;
+ t.Icircumflex = 278;
+ t.ncaron = 611;
+ t.tcommaaccent = 333;
+ t.logicalnot = 584;
+ t.odieresis = 611;
+ t.udieresis = 611;
+ t.notequal = 549;
+ t.gcommaaccent = 611;
+ t.eth = 611;
+ t.zcaron = 500;
+ t.ncommaaccent = 611;
+ t.onesuperior = 333;
+ t.imacron = 278;
+ t.Euro = 556;
+ });
+ t["Helvetica-Oblique"] = getLookupTableFactory(function (t) {
+ t.space = 278;
+ t.exclam = 278;
+ t.quotedbl = 355;
+ t.numbersign = 556;
+ t.dollar = 556;
+ t.percent = 889;
+ t.ampersand = 667;
+ t.quoteright = 222;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 389;
+ t.plus = 584;
+ t.comma = 278;
+ t.hyphen = 333;
+ t.period = 278;
+ t.slash = 278;
+ t.zero = 556;
+ t.one = 556;
+ t.two = 556;
+ t.three = 556;
+ t.four = 556;
+ t.five = 556;
+ t.six = 556;
+ t.seven = 556;
+ t.eight = 556;
+ t.nine = 556;
+ t.colon = 278;
+ t.semicolon = 278;
+ t.less = 584;
+ t.equal = 584;
+ t.greater = 584;
+ t.question = 556;
+ t.at = 1015;
+ t.A = 667;
+ t.B = 667;
+ t.C = 722;
+ t.D = 722;
+ t.E = 667;
+ t.F = 611;
+ t.G = 778;
+ t.H = 722;
+ t.I = 278;
+ t.J = 500;
+ t.K = 667;
+ t.L = 556;
+ t.M = 833;
+ t.N = 722;
+ t.O = 778;
+ t.P = 667;
+ t.Q = 778;
+ t.R = 722;
+ t.S = 667;
+ t.T = 611;
+ t.U = 722;
+ t.V = 667;
+ t.W = 944;
+ t.X = 667;
+ t.Y = 667;
+ t.Z = 611;
+ t.bracketleft = 278;
+ t.backslash = 278;
+ t.bracketright = 278;
+ t.asciicircum = 469;
+ t.underscore = 556;
+ t.quoteleft = 222;
+ t.a = 556;
+ t.b = 556;
+ t.c = 500;
+ t.d = 556;
+ t.e = 556;
+ t.f = 278;
+ t.g = 556;
+ t.h = 556;
+ t.i = 222;
+ t.j = 222;
+ t.k = 500;
+ t.l = 222;
+ t.m = 833;
+ t.n = 556;
+ t.o = 556;
+ t.p = 556;
+ t.q = 556;
+ t.r = 333;
+ t.s = 500;
+ t.t = 278;
+ t.u = 556;
+ t.v = 500;
+ t.w = 722;
+ t.x = 500;
+ t.y = 500;
+ t.z = 500;
+ t.braceleft = 334;
+ t.bar = 260;
+ t.braceright = 334;
+ t.asciitilde = 584;
+ t.exclamdown = 333;
+ t.cent = 556;
+ t.sterling = 556;
+ t.fraction = 167;
+ t.yen = 556;
+ t.florin = 556;
+ t.section = 556;
+ t.currency = 556;
+ t.quotesingle = 191;
+ t.quotedblleft = 333;
+ t.guillemotleft = 556;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 500;
+ t.fl = 500;
+ t.endash = 556;
+ t.dagger = 556;
+ t.daggerdbl = 556;
+ t.periodcentered = 278;
+ t.paragraph = 537;
+ t.bullet = 350;
+ t.quotesinglbase = 222;
+ t.quotedblbase = 333;
+ t.quotedblright = 333;
+ t.guillemotright = 556;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 611;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 1000;
+ t.ordfeminine = 370;
+ t.Lslash = 556;
+ t.Oslash = 778;
+ t.OE = 1000;
+ t.ordmasculine = 365;
+ t.ae = 889;
+ t.dotlessi = 278;
+ t.lslash = 222;
+ t.oslash = 611;
+ t.oe = 944;
+ t.germandbls = 611;
+ t.Idieresis = 278;
+ t.eacute = 556;
+ t.abreve = 556;
+ t.uhungarumlaut = 556;
+ t.ecaron = 556;
+ t.Ydieresis = 667;
+ t.divide = 584;
+ t.Yacute = 667;
+ t.Acircumflex = 667;
+ t.aacute = 556;
+ t.Ucircumflex = 722;
+ t.yacute = 500;
+ t.scommaaccent = 500;
+ t.ecircumflex = 556;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 556;
+ t.Uacute = 722;
+ t.uogonek = 556;
+ t.Edieresis = 667;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 737;
+ t.Emacron = 667;
+ t.ccaron = 500;
+ t.aring = 556;
+ t.Ncommaaccent = 722;
+ t.lacute = 222;
+ t.agrave = 556;
+ t.Tcommaaccent = 611;
+ t.Cacute = 722;
+ t.atilde = 556;
+ t.Edotaccent = 667;
+ t.scaron = 500;
+ t.scedilla = 500;
+ t.iacute = 278;
+ t.lozenge = 471;
+ t.Rcaron = 722;
+ t.Gcommaaccent = 778;
+ t.ucircumflex = 556;
+ t.acircumflex = 556;
+ t.Amacron = 667;
+ t.rcaron = 333;
+ t.ccedilla = 500;
+ t.Zdotaccent = 611;
+ t.Thorn = 667;
+ t.Omacron = 778;
+ t.Racute = 722;
+ t.Sacute = 667;
+ t.dcaron = 643;
+ t.Umacron = 722;
+ t.uring = 556;
+ t.threesuperior = 333;
+ t.Ograve = 778;
+ t.Agrave = 667;
+ t.Abreve = 667;
+ t.multiply = 584;
+ t.uacute = 556;
+ t.Tcaron = 611;
+ t.partialdiff = 476;
+ t.ydieresis = 500;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 667;
+ t.adieresis = 556;
+ t.edieresis = 556;
+ t.cacute = 500;
+ t.nacute = 556;
+ t.umacron = 556;
+ t.Ncaron = 722;
+ t.Iacute = 278;
+ t.plusminus = 584;
+ t.brokenbar = 260;
+ t.registered = 737;
+ t.Gbreve = 778;
+ t.Idotaccent = 278;
+ t.summation = 600;
+ t.Egrave = 667;
+ t.racute = 333;
+ t.omacron = 556;
+ t.Zacute = 611;
+ t.Zcaron = 611;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 722;
+ t.lcommaaccent = 222;
+ t.tcaron = 317;
+ t.eogonek = 556;
+ t.Uogonek = 722;
+ t.Aacute = 667;
+ t.Adieresis = 667;
+ t.egrave = 556;
+ t.zacute = 500;
+ t.iogonek = 222;
+ t.Oacute = 778;
+ t.oacute = 556;
+ t.amacron = 556;
+ t.sacute = 500;
+ t.idieresis = 278;
+ t.Ocircumflex = 778;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 556;
+ t.twosuperior = 333;
+ t.Odieresis = 778;
+ t.mu = 556;
+ t.igrave = 278;
+ t.ohungarumlaut = 556;
+ t.Eogonek = 667;
+ t.dcroat = 556;
+ t.threequarters = 834;
+ t.Scedilla = 667;
+ t.lcaron = 299;
+ t.Kcommaaccent = 667;
+ t.Lacute = 556;
+ t.trademark = 1000;
+ t.edotaccent = 556;
+ t.Igrave = 278;
+ t.Imacron = 278;
+ t.Lcaron = 556;
+ t.onehalf = 834;
+ t.lessequal = 549;
+ t.ocircumflex = 556;
+ t.ntilde = 556;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 667;
+ t.emacron = 556;
+ t.gbreve = 556;
+ t.onequarter = 834;
+ t.Scaron = 667;
+ t.Scommaaccent = 667;
+ t.Ohungarumlaut = 778;
+ t.degree = 400;
+ t.ograve = 556;
+ t.Ccaron = 722;
+ t.ugrave = 556;
+ t.radical = 453;
+ t.Dcaron = 722;
+ t.rcommaaccent = 333;
+ t.Ntilde = 722;
+ t.otilde = 556;
+ t.Rcommaaccent = 722;
+ t.Lcommaaccent = 556;
+ t.Atilde = 667;
+ t.Aogonek = 667;
+ t.Aring = 667;
+ t.Otilde = 778;
+ t.zdotaccent = 500;
+ t.Ecaron = 667;
+ t.Iogonek = 278;
+ t.kcommaaccent = 500;
+ t.minus = 584;
+ t.Icircumflex = 278;
+ t.ncaron = 556;
+ t.tcommaaccent = 278;
+ t.logicalnot = 584;
+ t.odieresis = 556;
+ t.udieresis = 556;
+ t.notequal = 549;
+ t.gcommaaccent = 556;
+ t.eth = 556;
+ t.zcaron = 500;
+ t.ncommaaccent = 556;
+ t.onesuperior = 333;
+ t.imacron = 278;
+ t.Euro = 556;
+ });
+ t.Symbol = getLookupTableFactory(function (t) {
+ t.space = 250;
+ t.exclam = 333;
+ t.universal = 713;
+ t.numbersign = 500;
+ t.existential = 549;
+ t.percent = 833;
+ t.ampersand = 778;
+ t.suchthat = 439;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asteriskmath = 500;
+ t.plus = 549;
+ t.comma = 250;
+ t.minus = 549;
+ t.period = 250;
+ t.slash = 278;
+ t.zero = 500;
+ t.one = 500;
+ t.two = 500;
+ t.three = 500;
+ t.four = 500;
+ t.five = 500;
+ t.six = 500;
+ t.seven = 500;
+ t.eight = 500;
+ t.nine = 500;
+ t.colon = 278;
+ t.semicolon = 278;
+ t.less = 549;
+ t.equal = 549;
+ t.greater = 549;
+ t.question = 444;
+ t.congruent = 549;
+ t.Alpha = 722;
+ t.Beta = 667;
+ t.Chi = 722;
+ t.Delta = 612;
+ t.Epsilon = 611;
+ t.Phi = 763;
+ t.Gamma = 603;
+ t.Eta = 722;
+ t.Iota = 333;
+ t.theta1 = 631;
+ t.Kappa = 722;
+ t.Lambda = 686;
+ t.Mu = 889;
+ t.Nu = 722;
+ t.Omicron = 722;
+ t.Pi = 768;
+ t.Theta = 741;
+ t.Rho = 556;
+ t.Sigma = 592;
+ t.Tau = 611;
+ t.Upsilon = 690;
+ t.sigma1 = 439;
+ t.Omega = 768;
+ t.Xi = 645;
+ t.Psi = 795;
+ t.Zeta = 611;
+ t.bracketleft = 333;
+ t.therefore = 863;
+ t.bracketright = 333;
+ t.perpendicular = 658;
+ t.underscore = 500;
+ t.radicalex = 500;
+ t.alpha = 631;
+ t.beta = 549;
+ t.chi = 549;
+ t.delta = 494;
+ t.epsilon = 439;
+ t.phi = 521;
+ t.gamma = 411;
+ t.eta = 603;
+ t.iota = 329;
+ t.phi1 = 603;
+ t.kappa = 549;
+ t.lambda = 549;
+ t.mu = 576;
+ t.nu = 521;
+ t.omicron = 549;
+ t.pi = 549;
+ t.theta = 521;
+ t.rho = 549;
+ t.sigma = 603;
+ t.tau = 439;
+ t.upsilon = 576;
+ t.omega1 = 713;
+ t.omega = 686;
+ t.xi = 493;
+ t.psi = 686;
+ t.zeta = 494;
+ t.braceleft = 480;
+ t.bar = 200;
+ t.braceright = 480;
+ t.similar = 549;
+ t.Euro = 750;
+ t.Upsilon1 = 620;
+ t.minute = 247;
+ t.lessequal = 549;
+ t.fraction = 167;
+ t.infinity = 713;
+ t.florin = 500;
+ t.club = 753;
+ t.diamond = 753;
+ t.heart = 753;
+ t.spade = 753;
+ t.arrowboth = 1042;
+ t.arrowleft = 987;
+ t.arrowup = 603;
+ t.arrowright = 987;
+ t.arrowdown = 603;
+ t.degree = 400;
+ t.plusminus = 549;
+ t.second = 411;
+ t.greaterequal = 549;
+ t.multiply = 549;
+ t.proportional = 713;
+ t.partialdiff = 494;
+ t.bullet = 460;
+ t.divide = 549;
+ t.notequal = 549;
+ t.equivalence = 549;
+ t.approxequal = 549;
+ t.ellipsis = 1000;
+ t.arrowvertex = 603;
+ t.arrowhorizex = 1000;
+ t.carriagereturn = 658;
+ t.aleph = 823;
+ t.Ifraktur = 686;
+ t.Rfraktur = 795;
+ t.weierstrass = 987;
+ t.circlemultiply = 768;
+ t.circleplus = 768;
+ t.emptyset = 823;
+ t.intersection = 768;
+ t.union = 768;
+ t.propersuperset = 713;
+ t.reflexsuperset = 713;
+ t.notsubset = 713;
+ t.propersubset = 713;
+ t.reflexsubset = 713;
+ t.element = 713;
+ t.notelement = 713;
+ t.angle = 768;
+ t.gradient = 713;
+ t.registerserif = 790;
+ t.copyrightserif = 790;
+ t.trademarkserif = 890;
+ t.product = 823;
+ t.radical = 549;
+ t.dotmath = 250;
+ t.logicalnot = 713;
+ t.logicaland = 603;
+ t.logicalor = 603;
+ t.arrowdblboth = 1042;
+ t.arrowdblleft = 987;
+ t.arrowdblup = 603;
+ t.arrowdblright = 987;
+ t.arrowdbldown = 603;
+ t.lozenge = 494;
+ t.angleleft = 329;
+ t.registersans = 790;
+ t.copyrightsans = 790;
+ t.trademarksans = 786;
+ t.summation = 713;
+ t.parenlefttp = 384;
+ t.parenleftex = 384;
+ t.parenleftbt = 384;
+ t.bracketlefttp = 384;
+ t.bracketleftex = 384;
+ t.bracketleftbt = 384;
+ t.bracelefttp = 494;
+ t.braceleftmid = 494;
+ t.braceleftbt = 494;
+ t.braceex = 494;
+ t.angleright = 329;
+ t.integral = 274;
+ t.integraltp = 686;
+ t.integralex = 686;
+ t.integralbt = 686;
+ t.parenrighttp = 384;
+ t.parenrightex = 384;
+ t.parenrightbt = 384;
+ t.bracketrighttp = 384;
+ t.bracketrightex = 384;
+ t.bracketrightbt = 384;
+ t.bracerighttp = 494;
+ t.bracerightmid = 494;
+ t.bracerightbt = 494;
+ t.apple = 790;
+ });
+ t["Times-Roman"] = getLookupTableFactory(function (t) {
+ t.space = 250;
+ t.exclam = 333;
+ t.quotedbl = 408;
+ t.numbersign = 500;
+ t.dollar = 500;
+ t.percent = 833;
+ t.ampersand = 778;
+ t.quoteright = 333;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 500;
+ t.plus = 564;
+ t.comma = 250;
+ t.hyphen = 333;
+ t.period = 250;
+ t.slash = 278;
+ t.zero = 500;
+ t.one = 500;
+ t.two = 500;
+ t.three = 500;
+ t.four = 500;
+ t.five = 500;
+ t.six = 500;
+ t.seven = 500;
+ t.eight = 500;
+ t.nine = 500;
+ t.colon = 278;
+ t.semicolon = 278;
+ t.less = 564;
+ t.equal = 564;
+ t.greater = 564;
+ t.question = 444;
+ t.at = 921;
+ t.A = 722;
+ t.B = 667;
+ t.C = 667;
+ t.D = 722;
+ t.E = 611;
+ t.F = 556;
+ t.G = 722;
+ t.H = 722;
+ t.I = 333;
+ t.J = 389;
+ t.K = 722;
+ t.L = 611;
+ t.M = 889;
+ t.N = 722;
+ t.O = 722;
+ t.P = 556;
+ t.Q = 722;
+ t.R = 667;
+ t.S = 556;
+ t.T = 611;
+ t.U = 722;
+ t.V = 722;
+ t.W = 944;
+ t.X = 722;
+ t.Y = 722;
+ t.Z = 611;
+ t.bracketleft = 333;
+ t.backslash = 278;
+ t.bracketright = 333;
+ t.asciicircum = 469;
+ t.underscore = 500;
+ t.quoteleft = 333;
+ t.a = 444;
+ t.b = 500;
+ t.c = 444;
+ t.d = 500;
+ t.e = 444;
+ t.f = 333;
+ t.g = 500;
+ t.h = 500;
+ t.i = 278;
+ t.j = 278;
+ t.k = 500;
+ t.l = 278;
+ t.m = 778;
+ t.n = 500;
+ t.o = 500;
+ t.p = 500;
+ t.q = 500;
+ t.r = 333;
+ t.s = 389;
+ t.t = 278;
+ t.u = 500;
+ t.v = 500;
+ t.w = 722;
+ t.x = 500;
+ t.y = 500;
+ t.z = 444;
+ t.braceleft = 480;
+ t.bar = 200;
+ t.braceright = 480;
+ t.asciitilde = 541;
+ t.exclamdown = 333;
+ t.cent = 500;
+ t.sterling = 500;
+ t.fraction = 167;
+ t.yen = 500;
+ t.florin = 500;
+ t.section = 500;
+ t.currency = 500;
+ t.quotesingle = 180;
+ t.quotedblleft = 444;
+ t.guillemotleft = 500;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 556;
+ t.fl = 556;
+ t.endash = 500;
+ t.dagger = 500;
+ t.daggerdbl = 500;
+ t.periodcentered = 250;
+ t.paragraph = 453;
+ t.bullet = 350;
+ t.quotesinglbase = 333;
+ t.quotedblbase = 444;
+ t.quotedblright = 444;
+ t.guillemotright = 500;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 444;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 889;
+ t.ordfeminine = 276;
+ t.Lslash = 611;
+ t.Oslash = 722;
+ t.OE = 889;
+ t.ordmasculine = 310;
+ t.ae = 667;
+ t.dotlessi = 278;
+ t.lslash = 278;
+ t.oslash = 500;
+ t.oe = 722;
+ t.germandbls = 500;
+ t.Idieresis = 333;
+ t.eacute = 444;
+ t.abreve = 444;
+ t.uhungarumlaut = 500;
+ t.ecaron = 444;
+ t.Ydieresis = 722;
+ t.divide = 564;
+ t.Yacute = 722;
+ t.Acircumflex = 722;
+ t.aacute = 444;
+ t.Ucircumflex = 722;
+ t.yacute = 500;
+ t.scommaaccent = 389;
+ t.ecircumflex = 444;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 444;
+ t.Uacute = 722;
+ t.uogonek = 500;
+ t.Edieresis = 611;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 760;
+ t.Emacron = 611;
+ t.ccaron = 444;
+ t.aring = 444;
+ t.Ncommaaccent = 722;
+ t.lacute = 278;
+ t.agrave = 444;
+ t.Tcommaaccent = 611;
+ t.Cacute = 667;
+ t.atilde = 444;
+ t.Edotaccent = 611;
+ t.scaron = 389;
+ t.scedilla = 389;
+ t.iacute = 278;
+ t.lozenge = 471;
+ t.Rcaron = 667;
+ t.Gcommaaccent = 722;
+ t.ucircumflex = 500;
+ t.acircumflex = 444;
+ t.Amacron = 722;
+ t.rcaron = 333;
+ t.ccedilla = 444;
+ t.Zdotaccent = 611;
+ t.Thorn = 556;
+ t.Omacron = 722;
+ t.Racute = 667;
+ t.Sacute = 556;
+ t.dcaron = 588;
+ t.Umacron = 722;
+ t.uring = 500;
+ t.threesuperior = 300;
+ t.Ograve = 722;
+ t.Agrave = 722;
+ t.Abreve = 722;
+ t.multiply = 564;
+ t.uacute = 500;
+ t.Tcaron = 611;
+ t.partialdiff = 476;
+ t.ydieresis = 500;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 611;
+ t.adieresis = 444;
+ t.edieresis = 444;
+ t.cacute = 444;
+ t.nacute = 500;
+ t.umacron = 500;
+ t.Ncaron = 722;
+ t.Iacute = 333;
+ t.plusminus = 564;
+ t.brokenbar = 200;
+ t.registered = 760;
+ t.Gbreve = 722;
+ t.Idotaccent = 333;
+ t.summation = 600;
+ t.Egrave = 611;
+ t.racute = 333;
+ t.omacron = 500;
+ t.Zacute = 611;
+ t.Zcaron = 611;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 667;
+ t.lcommaaccent = 278;
+ t.tcaron = 326;
+ t.eogonek = 444;
+ t.Uogonek = 722;
+ t.Aacute = 722;
+ t.Adieresis = 722;
+ t.egrave = 444;
+ t.zacute = 444;
+ t.iogonek = 278;
+ t.Oacute = 722;
+ t.oacute = 500;
+ t.amacron = 444;
+ t.sacute = 389;
+ t.idieresis = 278;
+ t.Ocircumflex = 722;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 500;
+ t.twosuperior = 300;
+ t.Odieresis = 722;
+ t.mu = 500;
+ t.igrave = 278;
+ t.ohungarumlaut = 500;
+ t.Eogonek = 611;
+ t.dcroat = 500;
+ t.threequarters = 750;
+ t.Scedilla = 556;
+ t.lcaron = 344;
+ t.Kcommaaccent = 722;
+ t.Lacute = 611;
+ t.trademark = 980;
+ t.edotaccent = 444;
+ t.Igrave = 333;
+ t.Imacron = 333;
+ t.Lcaron = 611;
+ t.onehalf = 750;
+ t.lessequal = 549;
+ t.ocircumflex = 500;
+ t.ntilde = 500;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 611;
+ t.emacron = 444;
+ t.gbreve = 500;
+ t.onequarter = 750;
+ t.Scaron = 556;
+ t.Scommaaccent = 556;
+ t.Ohungarumlaut = 722;
+ t.degree = 400;
+ t.ograve = 500;
+ t.Ccaron = 667;
+ t.ugrave = 500;
+ t.radical = 453;
+ t.Dcaron = 722;
+ t.rcommaaccent = 333;
+ t.Ntilde = 722;
+ t.otilde = 500;
+ t.Rcommaaccent = 667;
+ t.Lcommaaccent = 611;
+ t.Atilde = 722;
+ t.Aogonek = 722;
+ t.Aring = 722;
+ t.Otilde = 722;
+ t.zdotaccent = 444;
+ t.Ecaron = 611;
+ t.Iogonek = 333;
+ t.kcommaaccent = 500;
+ t.minus = 564;
+ t.Icircumflex = 333;
+ t.ncaron = 500;
+ t.tcommaaccent = 278;
+ t.logicalnot = 564;
+ t.odieresis = 500;
+ t.udieresis = 500;
+ t.notequal = 549;
+ t.gcommaaccent = 500;
+ t.eth = 500;
+ t.zcaron = 444;
+ t.ncommaaccent = 500;
+ t.onesuperior = 300;
+ t.imacron = 278;
+ t.Euro = 500;
+ });
+ t["Times-Bold"] = getLookupTableFactory(function (t) {
+ t.space = 250;
+ t.exclam = 333;
+ t.quotedbl = 555;
+ t.numbersign = 500;
+ t.dollar = 500;
+ t.percent = 1000;
+ t.ampersand = 833;
+ t.quoteright = 333;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 500;
+ t.plus = 570;
+ t.comma = 250;
+ t.hyphen = 333;
+ t.period = 250;
+ t.slash = 278;
+ t.zero = 500;
+ t.one = 500;
+ t.two = 500;
+ t.three = 500;
+ t.four = 500;
+ t.five = 500;
+ t.six = 500;
+ t.seven = 500;
+ t.eight = 500;
+ t.nine = 500;
+ t.colon = 333;
+ t.semicolon = 333;
+ t.less = 570;
+ t.equal = 570;
+ t.greater = 570;
+ t.question = 500;
+ t.at = 930;
+ t.A = 722;
+ t.B = 667;
+ t.C = 722;
+ t.D = 722;
+ t.E = 667;
+ t.F = 611;
+ t.G = 778;
+ t.H = 778;
+ t.I = 389;
+ t.J = 500;
+ t.K = 778;
+ t.L = 667;
+ t.M = 944;
+ t.N = 722;
+ t.O = 778;
+ t.P = 611;
+ t.Q = 778;
+ t.R = 722;
+ t.S = 556;
+ t.T = 667;
+ t.U = 722;
+ t.V = 722;
+ t.W = 1000;
+ t.X = 722;
+ t.Y = 722;
+ t.Z = 667;
+ t.bracketleft = 333;
+ t.backslash = 278;
+ t.bracketright = 333;
+ t.asciicircum = 581;
+ t.underscore = 500;
+ t.quoteleft = 333;
+ t.a = 500;
+ t.b = 556;
+ t.c = 444;
+ t.d = 556;
+ t.e = 444;
+ t.f = 333;
+ t.g = 500;
+ t.h = 556;
+ t.i = 278;
+ t.j = 333;
+ t.k = 556;
+ t.l = 278;
+ t.m = 833;
+ t.n = 556;
+ t.o = 500;
+ t.p = 556;
+ t.q = 556;
+ t.r = 444;
+ t.s = 389;
+ t.t = 333;
+ t.u = 556;
+ t.v = 500;
+ t.w = 722;
+ t.x = 500;
+ t.y = 500;
+ t.z = 444;
+ t.braceleft = 394;
+ t.bar = 220;
+ t.braceright = 394;
+ t.asciitilde = 520;
+ t.exclamdown = 333;
+ t.cent = 500;
+ t.sterling = 500;
+ t.fraction = 167;
+ t.yen = 500;
+ t.florin = 500;
+ t.section = 500;
+ t.currency = 500;
+ t.quotesingle = 278;
+ t.quotedblleft = 500;
+ t.guillemotleft = 500;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 556;
+ t.fl = 556;
+ t.endash = 500;
+ t.dagger = 500;
+ t.daggerdbl = 500;
+ t.periodcentered = 250;
+ t.paragraph = 540;
+ t.bullet = 350;
+ t.quotesinglbase = 333;
+ t.quotedblbase = 500;
+ t.quotedblright = 500;
+ t.guillemotright = 500;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 500;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 1000;
+ t.ordfeminine = 300;
+ t.Lslash = 667;
+ t.Oslash = 778;
+ t.OE = 1000;
+ t.ordmasculine = 330;
+ t.ae = 722;
+ t.dotlessi = 278;
+ t.lslash = 278;
+ t.oslash = 500;
+ t.oe = 722;
+ t.germandbls = 556;
+ t.Idieresis = 389;
+ t.eacute = 444;
+ t.abreve = 500;
+ t.uhungarumlaut = 556;
+ t.ecaron = 444;
+ t.Ydieresis = 722;
+ t.divide = 570;
+ t.Yacute = 722;
+ t.Acircumflex = 722;
+ t.aacute = 500;
+ t.Ucircumflex = 722;
+ t.yacute = 500;
+ t.scommaaccent = 389;
+ t.ecircumflex = 444;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 500;
+ t.Uacute = 722;
+ t.uogonek = 556;
+ t.Edieresis = 667;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 747;
+ t.Emacron = 667;
+ t.ccaron = 444;
+ t.aring = 500;
+ t.Ncommaaccent = 722;
+ t.lacute = 278;
+ t.agrave = 500;
+ t.Tcommaaccent = 667;
+ t.Cacute = 722;
+ t.atilde = 500;
+ t.Edotaccent = 667;
+ t.scaron = 389;
+ t.scedilla = 389;
+ t.iacute = 278;
+ t.lozenge = 494;
+ t.Rcaron = 722;
+ t.Gcommaaccent = 778;
+ t.ucircumflex = 556;
+ t.acircumflex = 500;
+ t.Amacron = 722;
+ t.rcaron = 444;
+ t.ccedilla = 444;
+ t.Zdotaccent = 667;
+ t.Thorn = 611;
+ t.Omacron = 778;
+ t.Racute = 722;
+ t.Sacute = 556;
+ t.dcaron = 672;
+ t.Umacron = 722;
+ t.uring = 556;
+ t.threesuperior = 300;
+ t.Ograve = 778;
+ t.Agrave = 722;
+ t.Abreve = 722;
+ t.multiply = 570;
+ t.uacute = 556;
+ t.Tcaron = 667;
+ t.partialdiff = 494;
+ t.ydieresis = 500;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 667;
+ t.adieresis = 500;
+ t.edieresis = 444;
+ t.cacute = 444;
+ t.nacute = 556;
+ t.umacron = 556;
+ t.Ncaron = 722;
+ t.Iacute = 389;
+ t.plusminus = 570;
+ t.brokenbar = 220;
+ t.registered = 747;
+ t.Gbreve = 778;
+ t.Idotaccent = 389;
+ t.summation = 600;
+ t.Egrave = 667;
+ t.racute = 444;
+ t.omacron = 500;
+ t.Zacute = 667;
+ t.Zcaron = 667;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 722;
+ t.lcommaaccent = 278;
+ t.tcaron = 416;
+ t.eogonek = 444;
+ t.Uogonek = 722;
+ t.Aacute = 722;
+ t.Adieresis = 722;
+ t.egrave = 444;
+ t.zacute = 444;
+ t.iogonek = 278;
+ t.Oacute = 778;
+ t.oacute = 500;
+ t.amacron = 500;
+ t.sacute = 389;
+ t.idieresis = 278;
+ t.Ocircumflex = 778;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 556;
+ t.twosuperior = 300;
+ t.Odieresis = 778;
+ t.mu = 556;
+ t.igrave = 278;
+ t.ohungarumlaut = 500;
+ t.Eogonek = 667;
+ t.dcroat = 556;
+ t.threequarters = 750;
+ t.Scedilla = 556;
+ t.lcaron = 394;
+ t.Kcommaaccent = 778;
+ t.Lacute = 667;
+ t.trademark = 1000;
+ t.edotaccent = 444;
+ t.Igrave = 389;
+ t.Imacron = 389;
+ t.Lcaron = 667;
+ t.onehalf = 750;
+ t.lessequal = 549;
+ t.ocircumflex = 500;
+ t.ntilde = 556;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 667;
+ t.emacron = 444;
+ t.gbreve = 500;
+ t.onequarter = 750;
+ t.Scaron = 556;
+ t.Scommaaccent = 556;
+ t.Ohungarumlaut = 778;
+ t.degree = 400;
+ t.ograve = 500;
+ t.Ccaron = 722;
+ t.ugrave = 556;
+ t.radical = 549;
+ t.Dcaron = 722;
+ t.rcommaaccent = 444;
+ t.Ntilde = 722;
+ t.otilde = 500;
+ t.Rcommaaccent = 722;
+ t.Lcommaaccent = 667;
+ t.Atilde = 722;
+ t.Aogonek = 722;
+ t.Aring = 722;
+ t.Otilde = 778;
+ t.zdotaccent = 444;
+ t.Ecaron = 667;
+ t.Iogonek = 389;
+ t.kcommaaccent = 556;
+ t.minus = 570;
+ t.Icircumflex = 389;
+ t.ncaron = 556;
+ t.tcommaaccent = 333;
+ t.logicalnot = 570;
+ t.odieresis = 500;
+ t.udieresis = 556;
+ t.notequal = 549;
+ t.gcommaaccent = 500;
+ t.eth = 500;
+ t.zcaron = 444;
+ t.ncommaaccent = 556;
+ t.onesuperior = 300;
+ t.imacron = 278;
+ t.Euro = 500;
+ });
+ t["Times-BoldItalic"] = getLookupTableFactory(function (t) {
+ t.space = 250;
+ t.exclam = 389;
+ t.quotedbl = 555;
+ t.numbersign = 500;
+ t.dollar = 500;
+ t.percent = 833;
+ t.ampersand = 778;
+ t.quoteright = 333;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 500;
+ t.plus = 570;
+ t.comma = 250;
+ t.hyphen = 333;
+ t.period = 250;
+ t.slash = 278;
+ t.zero = 500;
+ t.one = 500;
+ t.two = 500;
+ t.three = 500;
+ t.four = 500;
+ t.five = 500;
+ t.six = 500;
+ t.seven = 500;
+ t.eight = 500;
+ t.nine = 500;
+ t.colon = 333;
+ t.semicolon = 333;
+ t.less = 570;
+ t.equal = 570;
+ t.greater = 570;
+ t.question = 500;
+ t.at = 832;
+ t.A = 667;
+ t.B = 667;
+ t.C = 667;
+ t.D = 722;
+ t.E = 667;
+ t.F = 667;
+ t.G = 722;
+ t.H = 778;
+ t.I = 389;
+ t.J = 500;
+ t.K = 667;
+ t.L = 611;
+ t.M = 889;
+ t.N = 722;
+ t.O = 722;
+ t.P = 611;
+ t.Q = 722;
+ t.R = 667;
+ t.S = 556;
+ t.T = 611;
+ t.U = 722;
+ t.V = 667;
+ t.W = 889;
+ t.X = 667;
+ t.Y = 611;
+ t.Z = 611;
+ t.bracketleft = 333;
+ t.backslash = 278;
+ t.bracketright = 333;
+ t.asciicircum = 570;
+ t.underscore = 500;
+ t.quoteleft = 333;
+ t.a = 500;
+ t.b = 500;
+ t.c = 444;
+ t.d = 500;
+ t.e = 444;
+ t.f = 333;
+ t.g = 500;
+ t.h = 556;
+ t.i = 278;
+ t.j = 278;
+ t.k = 500;
+ t.l = 278;
+ t.m = 778;
+ t.n = 556;
+ t.o = 500;
+ t.p = 500;
+ t.q = 500;
+ t.r = 389;
+ t.s = 389;
+ t.t = 278;
+ t.u = 556;
+ t.v = 444;
+ t.w = 667;
+ t.x = 500;
+ t.y = 444;
+ t.z = 389;
+ t.braceleft = 348;
+ t.bar = 220;
+ t.braceright = 348;
+ t.asciitilde = 570;
+ t.exclamdown = 389;
+ t.cent = 500;
+ t.sterling = 500;
+ t.fraction = 167;
+ t.yen = 500;
+ t.florin = 500;
+ t.section = 500;
+ t.currency = 500;
+ t.quotesingle = 278;
+ t.quotedblleft = 500;
+ t.guillemotleft = 500;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 556;
+ t.fl = 556;
+ t.endash = 500;
+ t.dagger = 500;
+ t.daggerdbl = 500;
+ t.periodcentered = 250;
+ t.paragraph = 500;
+ t.bullet = 350;
+ t.quotesinglbase = 333;
+ t.quotedblbase = 500;
+ t.quotedblright = 500;
+ t.guillemotright = 500;
+ t.ellipsis = 1000;
+ t.perthousand = 1000;
+ t.questiondown = 500;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 1000;
+ t.AE = 944;
+ t.ordfeminine = 266;
+ t.Lslash = 611;
+ t.Oslash = 722;
+ t.OE = 944;
+ t.ordmasculine = 300;
+ t.ae = 722;
+ t.dotlessi = 278;
+ t.lslash = 278;
+ t.oslash = 500;
+ t.oe = 722;
+ t.germandbls = 500;
+ t.Idieresis = 389;
+ t.eacute = 444;
+ t.abreve = 500;
+ t.uhungarumlaut = 556;
+ t.ecaron = 444;
+ t.Ydieresis = 611;
+ t.divide = 570;
+ t.Yacute = 611;
+ t.Acircumflex = 667;
+ t.aacute = 500;
+ t.Ucircumflex = 722;
+ t.yacute = 444;
+ t.scommaaccent = 389;
+ t.ecircumflex = 444;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 500;
+ t.Uacute = 722;
+ t.uogonek = 556;
+ t.Edieresis = 667;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 747;
+ t.Emacron = 667;
+ t.ccaron = 444;
+ t.aring = 500;
+ t.Ncommaaccent = 722;
+ t.lacute = 278;
+ t.agrave = 500;
+ t.Tcommaaccent = 611;
+ t.Cacute = 667;
+ t.atilde = 500;
+ t.Edotaccent = 667;
+ t.scaron = 389;
+ t.scedilla = 389;
+ t.iacute = 278;
+ t.lozenge = 494;
+ t.Rcaron = 667;
+ t.Gcommaaccent = 722;
+ t.ucircumflex = 556;
+ t.acircumflex = 500;
+ t.Amacron = 667;
+ t.rcaron = 389;
+ t.ccedilla = 444;
+ t.Zdotaccent = 611;
+ t.Thorn = 611;
+ t.Omacron = 722;
+ t.Racute = 667;
+ t.Sacute = 556;
+ t.dcaron = 608;
+ t.Umacron = 722;
+ t.uring = 556;
+ t.threesuperior = 300;
+ t.Ograve = 722;
+ t.Agrave = 667;
+ t.Abreve = 667;
+ t.multiply = 570;
+ t.uacute = 556;
+ t.Tcaron = 611;
+ t.partialdiff = 494;
+ t.ydieresis = 444;
+ t.Nacute = 722;
+ t.icircumflex = 278;
+ t.Ecircumflex = 667;
+ t.adieresis = 500;
+ t.edieresis = 444;
+ t.cacute = 444;
+ t.nacute = 556;
+ t.umacron = 556;
+ t.Ncaron = 722;
+ t.Iacute = 389;
+ t.plusminus = 570;
+ t.brokenbar = 220;
+ t.registered = 747;
+ t.Gbreve = 722;
+ t.Idotaccent = 389;
+ t.summation = 600;
+ t.Egrave = 667;
+ t.racute = 389;
+ t.omacron = 500;
+ t.Zacute = 611;
+ t.Zcaron = 611;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 667;
+ t.lcommaaccent = 278;
+ t.tcaron = 366;
+ t.eogonek = 444;
+ t.Uogonek = 722;
+ t.Aacute = 667;
+ t.Adieresis = 667;
+ t.egrave = 444;
+ t.zacute = 389;
+ t.iogonek = 278;
+ t.Oacute = 722;
+ t.oacute = 500;
+ t.amacron = 500;
+ t.sacute = 389;
+ t.idieresis = 278;
+ t.Ocircumflex = 722;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 500;
+ t.twosuperior = 300;
+ t.Odieresis = 722;
+ t.mu = 576;
+ t.igrave = 278;
+ t.ohungarumlaut = 500;
+ t.Eogonek = 667;
+ t.dcroat = 500;
+ t.threequarters = 750;
+ t.Scedilla = 556;
+ t.lcaron = 382;
+ t.Kcommaaccent = 667;
+ t.Lacute = 611;
+ t.trademark = 1000;
+ t.edotaccent = 444;
+ t.Igrave = 389;
+ t.Imacron = 389;
+ t.Lcaron = 611;
+ t.onehalf = 750;
+ t.lessequal = 549;
+ t.ocircumflex = 500;
+ t.ntilde = 556;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 667;
+ t.emacron = 444;
+ t.gbreve = 500;
+ t.onequarter = 750;
+ t.Scaron = 556;
+ t.Scommaaccent = 556;
+ t.Ohungarumlaut = 722;
+ t.degree = 400;
+ t.ograve = 500;
+ t.Ccaron = 667;
+ t.ugrave = 556;
+ t.radical = 549;
+ t.Dcaron = 722;
+ t.rcommaaccent = 389;
+ t.Ntilde = 722;
+ t.otilde = 500;
+ t.Rcommaaccent = 667;
+ t.Lcommaaccent = 611;
+ t.Atilde = 667;
+ t.Aogonek = 667;
+ t.Aring = 667;
+ t.Otilde = 722;
+ t.zdotaccent = 389;
+ t.Ecaron = 667;
+ t.Iogonek = 389;
+ t.kcommaaccent = 500;
+ t.minus = 606;
+ t.Icircumflex = 389;
+ t.ncaron = 556;
+ t.tcommaaccent = 278;
+ t.logicalnot = 606;
+ t.odieresis = 500;
+ t.udieresis = 556;
+ t.notequal = 549;
+ t.gcommaaccent = 500;
+ t.eth = 500;
+ t.zcaron = 389;
+ t.ncommaaccent = 556;
+ t.onesuperior = 300;
+ t.imacron = 278;
+ t.Euro = 500;
+ });
+ t["Times-Italic"] = getLookupTableFactory(function (t) {
+ t.space = 250;
+ t.exclam = 333;
+ t.quotedbl = 420;
+ t.numbersign = 500;
+ t.dollar = 500;
+ t.percent = 833;
+ t.ampersand = 778;
+ t.quoteright = 333;
+ t.parenleft = 333;
+ t.parenright = 333;
+ t.asterisk = 500;
+ t.plus = 675;
+ t.comma = 250;
+ t.hyphen = 333;
+ t.period = 250;
+ t.slash = 278;
+ t.zero = 500;
+ t.one = 500;
+ t.two = 500;
+ t.three = 500;
+ t.four = 500;
+ t.five = 500;
+ t.six = 500;
+ t.seven = 500;
+ t.eight = 500;
+ t.nine = 500;
+ t.colon = 333;
+ t.semicolon = 333;
+ t.less = 675;
+ t.equal = 675;
+ t.greater = 675;
+ t.question = 500;
+ t.at = 920;
+ t.A = 611;
+ t.B = 611;
+ t.C = 667;
+ t.D = 722;
+ t.E = 611;
+ t.F = 611;
+ t.G = 722;
+ t.H = 722;
+ t.I = 333;
+ t.J = 444;
+ t.K = 667;
+ t.L = 556;
+ t.M = 833;
+ t.N = 667;
+ t.O = 722;
+ t.P = 611;
+ t.Q = 722;
+ t.R = 611;
+ t.S = 500;
+ t.T = 556;
+ t.U = 722;
+ t.V = 611;
+ t.W = 833;
+ t.X = 611;
+ t.Y = 556;
+ t.Z = 556;
+ t.bracketleft = 389;
+ t.backslash = 278;
+ t.bracketright = 389;
+ t.asciicircum = 422;
+ t.underscore = 500;
+ t.quoteleft = 333;
+ t.a = 500;
+ t.b = 500;
+ t.c = 444;
+ t.d = 500;
+ t.e = 444;
+ t.f = 278;
+ t.g = 500;
+ t.h = 500;
+ t.i = 278;
+ t.j = 278;
+ t.k = 444;
+ t.l = 278;
+ t.m = 722;
+ t.n = 500;
+ t.o = 500;
+ t.p = 500;
+ t.q = 500;
+ t.r = 389;
+ t.s = 389;
+ t.t = 278;
+ t.u = 500;
+ t.v = 444;
+ t.w = 667;
+ t.x = 444;
+ t.y = 444;
+ t.z = 389;
+ t.braceleft = 400;
+ t.bar = 275;
+ t.braceright = 400;
+ t.asciitilde = 541;
+ t.exclamdown = 389;
+ t.cent = 500;
+ t.sterling = 500;
+ t.fraction = 167;
+ t.yen = 500;
+ t.florin = 500;
+ t.section = 500;
+ t.currency = 500;
+ t.quotesingle = 214;
+ t.quotedblleft = 556;
+ t.guillemotleft = 500;
+ t.guilsinglleft = 333;
+ t.guilsinglright = 333;
+ t.fi = 500;
+ t.fl = 500;
+ t.endash = 500;
+ t.dagger = 500;
+ t.daggerdbl = 500;
+ t.periodcentered = 250;
+ t.paragraph = 523;
+ t.bullet = 350;
+ t.quotesinglbase = 333;
+ t.quotedblbase = 556;
+ t.quotedblright = 556;
+ t.guillemotright = 500;
+ t.ellipsis = 889;
+ t.perthousand = 1000;
+ t.questiondown = 500;
+ t.grave = 333;
+ t.acute = 333;
+ t.circumflex = 333;
+ t.tilde = 333;
+ t.macron = 333;
+ t.breve = 333;
+ t.dotaccent = 333;
+ t.dieresis = 333;
+ t.ring = 333;
+ t.cedilla = 333;
+ t.hungarumlaut = 333;
+ t.ogonek = 333;
+ t.caron = 333;
+ t.emdash = 889;
+ t.AE = 889;
+ t.ordfeminine = 276;
+ t.Lslash = 556;
+ t.Oslash = 722;
+ t.OE = 944;
+ t.ordmasculine = 310;
+ t.ae = 667;
+ t.dotlessi = 278;
+ t.lslash = 278;
+ t.oslash = 500;
+ t.oe = 667;
+ t.germandbls = 500;
+ t.Idieresis = 333;
+ t.eacute = 444;
+ t.abreve = 500;
+ t.uhungarumlaut = 500;
+ t.ecaron = 444;
+ t.Ydieresis = 556;
+ t.divide = 675;
+ t.Yacute = 556;
+ t.Acircumflex = 611;
+ t.aacute = 500;
+ t.Ucircumflex = 722;
+ t.yacute = 444;
+ t.scommaaccent = 389;
+ t.ecircumflex = 444;
+ t.Uring = 722;
+ t.Udieresis = 722;
+ t.aogonek = 500;
+ t.Uacute = 722;
+ t.uogonek = 500;
+ t.Edieresis = 611;
+ t.Dcroat = 722;
+ t.commaaccent = 250;
+ t.copyright = 760;
+ t.Emacron = 611;
+ t.ccaron = 444;
+ t.aring = 500;
+ t.Ncommaaccent = 667;
+ t.lacute = 278;
+ t.agrave = 500;
+ t.Tcommaaccent = 556;
+ t.Cacute = 667;
+ t.atilde = 500;
+ t.Edotaccent = 611;
+ t.scaron = 389;
+ t.scedilla = 389;
+ t.iacute = 278;
+ t.lozenge = 471;
+ t.Rcaron = 611;
+ t.Gcommaaccent = 722;
+ t.ucircumflex = 500;
+ t.acircumflex = 500;
+ t.Amacron = 611;
+ t.rcaron = 389;
+ t.ccedilla = 444;
+ t.Zdotaccent = 556;
+ t.Thorn = 611;
+ t.Omacron = 722;
+ t.Racute = 611;
+ t.Sacute = 500;
+ t.dcaron = 544;
+ t.Umacron = 722;
+ t.uring = 500;
+ t.threesuperior = 300;
+ t.Ograve = 722;
+ t.Agrave = 611;
+ t.Abreve = 611;
+ t.multiply = 675;
+ t.uacute = 500;
+ t.Tcaron = 556;
+ t.partialdiff = 476;
+ t.ydieresis = 444;
+ t.Nacute = 667;
+ t.icircumflex = 278;
+ t.Ecircumflex = 611;
+ t.adieresis = 500;
+ t.edieresis = 444;
+ t.cacute = 444;
+ t.nacute = 500;
+ t.umacron = 500;
+ t.Ncaron = 667;
+ t.Iacute = 333;
+ t.plusminus = 675;
+ t.brokenbar = 275;
+ t.registered = 760;
+ t.Gbreve = 722;
+ t.Idotaccent = 333;
+ t.summation = 600;
+ t.Egrave = 611;
+ t.racute = 389;
+ t.omacron = 500;
+ t.Zacute = 556;
+ t.Zcaron = 556;
+ t.greaterequal = 549;
+ t.Eth = 722;
+ t.Ccedilla = 667;
+ t.lcommaaccent = 278;
+ t.tcaron = 300;
+ t.eogonek = 444;
+ t.Uogonek = 722;
+ t.Aacute = 611;
+ t.Adieresis = 611;
+ t.egrave = 444;
+ t.zacute = 389;
+ t.iogonek = 278;
+ t.Oacute = 722;
+ t.oacute = 500;
+ t.amacron = 500;
+ t.sacute = 389;
+ t.idieresis = 278;
+ t.Ocircumflex = 722;
+ t.Ugrave = 722;
+ t.Delta = 612;
+ t.thorn = 500;
+ t.twosuperior = 300;
+ t.Odieresis = 722;
+ t.mu = 500;
+ t.igrave = 278;
+ t.ohungarumlaut = 500;
+ t.Eogonek = 611;
+ t.dcroat = 500;
+ t.threequarters = 750;
+ t.Scedilla = 500;
+ t.lcaron = 300;
+ t.Kcommaaccent = 667;
+ t.Lacute = 556;
+ t.trademark = 980;
+ t.edotaccent = 444;
+ t.Igrave = 333;
+ t.Imacron = 333;
+ t.Lcaron = 611;
+ t.onehalf = 750;
+ t.lessequal = 549;
+ t.ocircumflex = 500;
+ t.ntilde = 500;
+ t.Uhungarumlaut = 722;
+ t.Eacute = 611;
+ t.emacron = 444;
+ t.gbreve = 500;
+ t.onequarter = 750;
+ t.Scaron = 500;
+ t.Scommaaccent = 500;
+ t.Ohungarumlaut = 722;
+ t.degree = 400;
+ t.ograve = 500;
+ t.Ccaron = 667;
+ t.ugrave = 500;
+ t.radical = 453;
+ t.Dcaron = 722;
+ t.rcommaaccent = 389;
+ t.Ntilde = 667;
+ t.otilde = 500;
+ t.Rcommaaccent = 611;
+ t.Lcommaaccent = 556;
+ t.Atilde = 611;
+ t.Aogonek = 611;
+ t.Aring = 611;
+ t.Otilde = 722;
+ t.zdotaccent = 389;
+ t.Ecaron = 611;
+ t.Iogonek = 333;
+ t.kcommaaccent = 444;
+ t.minus = 675;
+ t.Icircumflex = 333;
+ t.ncaron = 500;
+ t.tcommaaccent = 278;
+ t.logicalnot = 675;
+ t.odieresis = 500;
+ t.udieresis = 500;
+ t.notequal = 549;
+ t.gcommaaccent = 500;
+ t.eth = 500;
+ t.zcaron = 389;
+ t.ncommaaccent = 500;
+ t.onesuperior = 300;
+ t.imacron = 278;
+ t.Euro = 500;
+ });
+ t.ZapfDingbats = getLookupTableFactory(function (t) {
+ t.space = 278;
+ t.a1 = 974;
+ t.a2 = 961;
+ t.a202 = 974;
+ t.a3 = 980;
+ t.a4 = 719;
+ t.a5 = 789;
+ t.a119 = 790;
+ t.a118 = 791;
+ t.a117 = 690;
+ t.a11 = 960;
+ t.a12 = 939;
+ t.a13 = 549;
+ t.a14 = 855;
+ t.a15 = 911;
+ t.a16 = 933;
+ t.a105 = 911;
+ t.a17 = 945;
+ t.a18 = 974;
+ t.a19 = 755;
+ t.a20 = 846;
+ t.a21 = 762;
+ t.a22 = 761;
+ t.a23 = 571;
+ t.a24 = 677;
+ t.a25 = 763;
+ t.a26 = 760;
+ t.a27 = 759;
+ t.a28 = 754;
+ t.a6 = 494;
+ t.a7 = 552;
+ t.a8 = 537;
+ t.a9 = 577;
+ t.a10 = 692;
+ t.a29 = 786;
+ t.a30 = 788;
+ t.a31 = 788;
+ t.a32 = 790;
+ t.a33 = 793;
+ t.a34 = 794;
+ t.a35 = 816;
+ t.a36 = 823;
+ t.a37 = 789;
+ t.a38 = 841;
+ t.a39 = 823;
+ t.a40 = 833;
+ t.a41 = 816;
+ t.a42 = 831;
+ t.a43 = 923;
+ t.a44 = 744;
+ t.a45 = 723;
+ t.a46 = 749;
+ t.a47 = 790;
+ t.a48 = 792;
+ t.a49 = 695;
+ t.a50 = 776;
+ t.a51 = 768;
+ t.a52 = 792;
+ t.a53 = 759;
+ t.a54 = 707;
+ t.a55 = 708;
+ t.a56 = 682;
+ t.a57 = 701;
+ t.a58 = 826;
+ t.a59 = 815;
+ t.a60 = 789;
+ t.a61 = 789;
+ t.a62 = 707;
+ t.a63 = 687;
+ t.a64 = 696;
+ t.a65 = 689;
+ t.a66 = 786;
+ t.a67 = 787;
+ t.a68 = 713;
+ t.a69 = 791;
+ t.a70 = 785;
+ t.a71 = 791;
+ t.a72 = 873;
+ t.a73 = 761;
+ t.a74 = 762;
+ t.a203 = 762;
+ t.a75 = 759;
+ t.a204 = 759;
+ t.a76 = 892;
+ t.a77 = 892;
+ t.a78 = 788;
+ t.a79 = 784;
+ t.a81 = 438;
+ t.a82 = 138;
+ t.a83 = 277;
+ t.a84 = 415;
+ t.a97 = 392;
+ t.a98 = 392;
+ t.a99 = 668;
+ t.a100 = 668;
+ t.a89 = 390;
+ t.a90 = 390;
+ t.a93 = 317;
+ t.a94 = 317;
+ t.a91 = 276;
+ t.a92 = 276;
+ t.a205 = 509;
+ t.a85 = 509;
+ t.a206 = 410;
+ t.a86 = 410;
+ t.a87 = 234;
+ t.a88 = 234;
+ t.a95 = 334;
+ t.a96 = 334;
+ t.a101 = 732;
+ t.a102 = 544;
+ t.a103 = 544;
+ t.a104 = 910;
+ t.a106 = 667;
+ t.a107 = 760;
+ t.a108 = 760;
+ t.a112 = 776;
+ t.a111 = 595;
+ t.a110 = 694;
+ t.a109 = 626;
+ t.a120 = 788;
+ t.a121 = 788;
+ t.a122 = 788;
+ t.a123 = 788;
+ t.a124 = 788;
+ t.a125 = 788;
+ t.a126 = 788;
+ t.a127 = 788;
+ t.a128 = 788;
+ t.a129 = 788;
+ t.a130 = 788;
+ t.a131 = 788;
+ t.a132 = 788;
+ t.a133 = 788;
+ t.a134 = 788;
+ t.a135 = 788;
+ t.a136 = 788;
+ t.a137 = 788;
+ t.a138 = 788;
+ t.a139 = 788;
+ t.a140 = 788;
+ t.a141 = 788;
+ t.a142 = 788;
+ t.a143 = 788;
+ t.a144 = 788;
+ t.a145 = 788;
+ t.a146 = 788;
+ t.a147 = 788;
+ t.a148 = 788;
+ t.a149 = 788;
+ t.a150 = 788;
+ t.a151 = 788;
+ t.a152 = 788;
+ t.a153 = 788;
+ t.a154 = 788;
+ t.a155 = 788;
+ t.a156 = 788;
+ t.a157 = 788;
+ t.a158 = 788;
+ t.a159 = 788;
+ t.a160 = 894;
+ t.a161 = 838;
+ t.a163 = 1016;
+ t.a164 = 458;
+ t.a196 = 748;
+ t.a165 = 924;
+ t.a192 = 748;
+ t.a166 = 918;
+ t.a167 = 927;
+ t.a168 = 928;
+ t.a169 = 928;
+ t.a170 = 834;
+ t.a171 = 873;
+ t.a172 = 828;
+ t.a173 = 924;
+ t.a162 = 924;
+ t.a174 = 917;
+ t.a175 = 930;
+ t.a176 = 931;
+ t.a177 = 463;
+ t.a178 = 883;
+ t.a179 = 836;
+ t.a193 = 836;
+ t.a180 = 867;
+ t.a199 = 867;
+ t.a181 = 696;
+ t.a200 = 696;
+ t.a182 = 874;
+ t.a201 = 874;
+ t.a183 = 760;
+ t.a184 = 946;
+ t.a197 = 771;
+ t.a185 = 865;
+ t.a194 = 771;
+ t.a198 = 888;
+ t.a186 = 967;
+ t.a195 = 888;
+ t.a187 = 831;
+ t.a188 = 873;
+ t.a189 = 927;
+ t.a190 = 970;
+ t.a191 = 918;
+ });
+});
+const getFontBasicMetrics = getLookupTableFactory(function (t) {
+ t.Courier = {
+ ascent: 629,
+ descent: -157,
+ capHeight: 562,
+ xHeight: -426
+ };
+ t["Courier-Bold"] = {
+ ascent: 629,
+ descent: -157,
+ capHeight: 562,
+ xHeight: 439
+ };
+ t["Courier-Oblique"] = {
+ ascent: 629,
+ descent: -157,
+ capHeight: 562,
+ xHeight: 426
+ };
+ t["Courier-BoldOblique"] = {
+ ascent: 629,
+ descent: -157,
+ capHeight: 562,
+ xHeight: 426
+ };
+ t.Helvetica = {
+ ascent: 718,
+ descent: -207,
+ capHeight: 718,
+ xHeight: 523
+ };
+ t["Helvetica-Bold"] = {
+ ascent: 718,
+ descent: -207,
+ capHeight: 718,
+ xHeight: 532
+ };
+ t["Helvetica-Oblique"] = {
+ ascent: 718,
+ descent: -207,
+ capHeight: 718,
+ xHeight: 523
+ };
+ t["Helvetica-BoldOblique"] = {
+ ascent: 718,
+ descent: -207,
+ capHeight: 718,
+ xHeight: 532
+ };
+ t["Times-Roman"] = {
+ ascent: 683,
+ descent: -217,
+ capHeight: 662,
+ xHeight: 450
+ };
+ t["Times-Bold"] = {
+ ascent: 683,
+ descent: -217,
+ capHeight: 676,
+ xHeight: 461
+ };
+ t["Times-Italic"] = {
+ ascent: 683,
+ descent: -217,
+ capHeight: 653,
+ xHeight: 441
+ };
+ t["Times-BoldItalic"] = {
+ ascent: 683,
+ descent: -217,
+ capHeight: 669,
+ xHeight: 462
+ };
+ t.Symbol = {
+ ascent: Math.NaN,
+ descent: Math.NaN,
+ capHeight: Math.NaN,
+ xHeight: Math.NaN
+ };
+ t.ZapfDingbats = {
+ ascent: Math.NaN,
+ descent: Math.NaN,
+ capHeight: Math.NaN,
+ xHeight: Math.NaN
+ };
+});
+
+;// ./src/core/opentype_file_builder.js
+
+
+
+
+
+
+
+
+
+const OTF_HEADER_SIZE = 12;
+const OTF_TABLE_ENTRY_SIZE = 16;
+class OpenTypeFileBuilder {
+ #tables = new Map();
+ constructor(sfnt) {
+ this.sfnt = sfnt;
+ }
+ static getSearchParams(entriesCount, entrySize) {
+ let maxPower2 = 1,
+ log2 = 0;
+ while ((maxPower2 ^ entriesCount) > maxPower2) {
+ maxPower2 <<= 1;
+ log2++;
+ }
+ const searchRange = maxPower2 * entrySize;
+ return {
+ range: searchRange,
+ entry: log2,
+ rangeShift: entrySize * entriesCount - searchRange
+ };
+ }
+ toArray() {
+ let sfnt = this.sfnt;
+ const tables = this.#tables;
+ const tablesNames = [...tables.keys()].sort();
+ const numTables = tablesNames.length;
+ let offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE;
+ const tableOffsets = [offset];
+ for (let i = 0; i < numTables; i++) {
+ const table = tables.get(tablesNames[i]);
+ const paddedLength = (table.length + 3 & ~3) >>> 0;
+ offset += paddedLength;
+ tableOffsets.push(offset);
+ }
+ const file = new Uint8Array(offset),
+ view = new DataView(file.buffer);
+ for (let i = 0; i < numTables; i++) {
+ const table = tables.get(tablesNames[i]);
+ file.set(table, tableOffsets[i]);
+ }
+ if (sfnt === "true") {
+ sfnt = "\x00\x01\x00\x00";
+ }
+ file.set(stringToBytes(sfnt), 0);
+ view.setInt16(4, numTables);
+ const searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16);
+ view.setInt16(6, searchParams.range);
+ view.setInt16(8, searchParams.entry);
+ view.setInt16(10, searchParams.rangeShift);
+ offset = OTF_HEADER_SIZE;
+ for (let i = 0; i < numTables; i++) {
+ const tableName = tablesNames[i];
+ file.set(stringToBytes(tableName), offset);
+ let checksum = 0;
+ for (let j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) {
+ const quad = view.getUint32(j);
+ checksum = checksum + quad >>> 0;
+ }
+ view.setInt32(offset + 4, checksum);
+ view.setInt32(offset + 8, tableOffsets[i]);
+ view.setInt32(offset + 12, tables.get(tableName).length);
+ offset += OTF_TABLE_ENTRY_SIZE;
+ }
+ this.#tables.clear();
+ return file;
+ }
+ addTable(tag, data) {
+ if (this.#tables.has(tag)) {
+ throw new Error(`Table ${tag} already exists`);
+ }
+ this.#tables.set(tag, data);
+ }
+}
+
+;// ./src/core/type1_parser.js
+
+
+
+
+
+
+
+
+
+
+
+
+const HINTING_ENABLED = false;
+const COMMAND_MAP = {
+ hstem: [1],
+ vstem: [3],
+ vmoveto: [4],
+ rlineto: [5],
+ hlineto: [6],
+ vlineto: [7],
+ rrcurveto: [8],
+ callsubr: [10],
+ flex: [12, 35],
+ drop: [12, 18],
+ endchar: [14],
+ rmoveto: [21],
+ hmoveto: [22],
+ vhcurveto: [30],
+ hvcurveto: [31]
+};
+class Type1CharString {
+ width = 0;
+ lsb = 0;
+ flexing = false;
+ output = [];
+ stack = [];
+ convert(encoded, subrs, seacAnalysisEnabled) {
+ const count = encoded.length;
+ let error = false;
+ let wx, sbx, subrNumber;
+ for (let i = 0; i < count; i++) {
+ let value = encoded[i];
+ if (value < 32) {
+ if (value === 12) {
+ value = (value << 8) + encoded[++i];
+ }
+ switch (value) {
+ case 1:
+ if (true) {
+ this.stack = [];
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.hstem);
+ break;
+ case 3:
+ if (true) {
+ this.stack = [];
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.vstem);
+ break;
+ case 4:
+ if (this.flexing) {
+ if (this.stack.length < 1) {
+ error = true;
+ break;
+ }
+ const dy = this.stack.pop();
+ this.stack.push(0, dy);
+ break;
+ }
+ error = this.executeCommand(1, COMMAND_MAP.vmoveto);
+ break;
+ case 5:
+ error = this.executeCommand(2, COMMAND_MAP.rlineto);
+ break;
+ case 6:
+ error = this.executeCommand(1, COMMAND_MAP.hlineto);
+ break;
+ case 7:
+ error = this.executeCommand(1, COMMAND_MAP.vlineto);
+ break;
+ case 8:
+ error = this.executeCommand(6, COMMAND_MAP.rrcurveto);
+ break;
+ case 9:
+ this.stack = [];
+ break;
+ case 10:
+ if (this.stack.length < 1) {
+ error = true;
+ break;
+ }
+ subrNumber = this.stack.pop();
+ if (!subrs[subrNumber]) {
+ error = true;
+ break;
+ }
+ error = this.convert(subrs[subrNumber], subrs, seacAnalysisEnabled);
+ break;
+ case 11:
+ return error;
+ case 13:
+ if (this.stack.length < 2) {
+ error = true;
+ break;
+ }
+ wx = this.stack.pop();
+ sbx = this.stack.pop();
+ this.lsb = sbx;
+ this.width = wx;
+ this.stack.push(wx, sbx);
+ error = this.executeCommand(2, COMMAND_MAP.hmoveto);
+ break;
+ case 14:
+ this.output.push(COMMAND_MAP.endchar[0]);
+ break;
+ case 21:
+ if (this.flexing) {
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.rmoveto);
+ break;
+ case 22:
+ if (this.flexing) {
+ this.stack.push(0);
+ break;
+ }
+ error = this.executeCommand(1, COMMAND_MAP.hmoveto);
+ break;
+ case 30:
+ error = this.executeCommand(4, COMMAND_MAP.vhcurveto);
+ break;
+ case 31:
+ error = this.executeCommand(4, COMMAND_MAP.hvcurveto);
+ break;
+ case (12 << 8) + 0:
+ this.stack = [];
+ break;
+ case (12 << 8) + 1:
+ if (true) {
+ this.stack = [];
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.vstem);
+ break;
+ case (12 << 8) + 2:
+ if (true) {
+ this.stack = [];
+ break;
+ }
+ error = this.executeCommand(2, COMMAND_MAP.hstem);
+ break;
+ case (12 << 8) + 6:
+ if (seacAnalysisEnabled) {
+ const asb = this.stack.at(-5);
+ this.seac = this.stack.splice(-4, 4);
+ this.seac[0] += this.lsb - asb;
+ error = this.executeCommand(0, COMMAND_MAP.endchar);
+ } else {
+ error = this.executeCommand(4, COMMAND_MAP.endchar);
+ }
+ break;
+ case (12 << 8) + 7:
+ if (this.stack.length < 4) {
+ error = true;
+ break;
+ }
+ this.stack.pop();
+ wx = this.stack.pop();
+ const sby = this.stack.pop();
+ sbx = this.stack.pop();
+ this.lsb = sbx;
+ this.width = wx;
+ this.stack.push(wx, sbx, sby);
+ error = this.executeCommand(3, COMMAND_MAP.rmoveto);
+ break;
+ case (12 << 8) + 12:
+ if (this.stack.length < 2) {
+ error = true;
+ break;
+ }
+ const num2 = this.stack.pop();
+ const num1 = this.stack.pop();
+ this.stack.push(num1 / num2);
+ break;
+ case (12 << 8) + 16:
+ if (this.stack.length < 2) {
+ error = true;
+ break;
+ }
+ subrNumber = this.stack.pop();
+ const numArgs = this.stack.pop();
+ if (subrNumber === 0 && numArgs === 3) {
+ const flexArgs = this.stack.splice(-17, 17);
+ this.stack.push(flexArgs[2] + flexArgs[0], flexArgs[3] + flexArgs[1], flexArgs[4], flexArgs[5], flexArgs[6], flexArgs[7], flexArgs[8], flexArgs[9], flexArgs[10], flexArgs[11], flexArgs[12], flexArgs[13], flexArgs[14]);
+ error = this.executeCommand(13, COMMAND_MAP.flex, true);
+ this.flexing = false;
+ this.stack.push(flexArgs[15], flexArgs[16]);
+ } else if (subrNumber === 1 && numArgs === 0) {
+ this.flexing = true;
+ }
+ break;
+ case (12 << 8) + 17:
+ break;
+ case (12 << 8) + 33:
+ this.stack = [];
+ break;
+ default:
+ warn('Unknown type 1 charstring command of "' + value + '"');
+ break;
+ }
+ if (error) {
+ break;
+ }
+ continue;
+ } else if (value <= 246) {
+ value -= 139;
+ } else if (value <= 250) {
+ value = (value - 247) * 256 + encoded[++i] + 108;
+ } else if (value <= 254) {
+ value = -((value - 251) * 256) - encoded[++i] - 108;
+ } else {
+ value = (encoded[++i] & 0xff) << 24 | (encoded[++i] & 0xff) << 16 | (encoded[++i] & 0xff) << 8 | (encoded[++i] & 0xff) << 0;
+ }
+ this.stack.push(value);
+ }
+ return error;
+ }
+ executeCommand(howManyArgs, command, keepStack) {
+ const stackLength = this.stack.length;
+ if (howManyArgs > stackLength) {
+ return true;
+ }
+ const start = stackLength - howManyArgs;
+ for (let i = start; i < stackLength; i++) {
+ let value = this.stack[i];
+ if (Number.isInteger(value)) {
+ this.output.push(28, value >> 8 & 0xff, value & 0xff);
+ } else {
+ value = 65536 * value | 0;
+ this.output.push(255, value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff);
+ }
+ }
+ this.output.push(...command);
+ if (keepStack) {
+ this.stack.splice(start, howManyArgs);
+ } else {
+ this.stack.length = 0;
+ }
+ return false;
+ }
+}
+const EEXEC_ENCRYPT_KEY = 55665;
+const CHAR_STRS_ENCRYPT_KEY = 4330;
+function isHexDigit(code) {
+ return code >= 48 && code <= 57 || code >= 65 && code <= 70 || code >= 97 && code <= 102;
+}
+function decrypt(data, key, discardNumber) {
+ if (discardNumber >= data.length) {
+ return new Uint8Array(0);
+ }
+ const c1 = 52845,
+ c2 = 22719;
+ let r = key | 0,
+ i,
+ j;
+ for (i = 0; i < discardNumber; i++) {
+ r = (data[i] + r) * c1 + c2 & (1 << 16) - 1;
+ }
+ const count = data.length - discardNumber;
+ const decrypted = new Uint8Array(count);
+ for (i = discardNumber, j = 0; j < count; i++, j++) {
+ const value = data[i];
+ decrypted[j] = value ^ r >> 8;
+ r = (value + r) * c1 + c2 & (1 << 16) - 1;
+ }
+ return decrypted;
+}
+function decryptAscii(data, key, discardNumber) {
+ const c1 = 52845,
+ c2 = 22719;
+ let r = key | 0;
+ const count = data.length,
+ maybeLength = count >>> 1;
+ const decrypted = new Uint8Array(maybeLength);
+ let i, j;
+ for (i = 0, j = 0; i < count; i++) {
+ const digit1 = data[i];
+ if (!isHexDigit(digit1)) {
+ continue;
+ }
+ i++;
+ let digit2;
+ while (i < count && !isHexDigit(digit2 = data[i])) {
+ i++;
+ }
+ if (i < count) {
+ const value = parseInt(String.fromCharCode(digit1, digit2), 16);
+ decrypted[j++] = value ^ r >> 8;
+ r = (value + r) * c1 + c2 & (1 << 16) - 1;
+ }
+ }
+ return decrypted.slice(discardNumber, j);
+}
+function isSpecial(c) {
+ return c === 0x2f || c === 0x5b || c === 0x5d || c === 0x7b || c === 0x7d || c === 0x28 || c === 0x29;
+}
+class Type1Parser {
+ constructor(stream, encrypted, seacAnalysisEnabled) {
+ if (encrypted) {
+ const data = stream.getBytes();
+ const isBinary = !((isHexDigit(data[0]) || isWhiteSpace(data[0])) && isHexDigit(data[1]) && isHexDigit(data[2]) && isHexDigit(data[3]) && isHexDigit(data[4]) && isHexDigit(data[5]) && isHexDigit(data[6]) && isHexDigit(data[7]));
+ stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) : decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
+ }
+ this.seacAnalysisEnabled = !!seacAnalysisEnabled;
+ this.stream = stream;
+ this.nextChar();
+ }
+ readNumberArray() {
+ this.getToken();
+ const array = [];
+ while (true) {
+ const token = this.getToken();
+ if (token === null || token === "]" || token === "}") {
+ break;
+ }
+ array.push(parseFloat(token || 0));
+ }
+ return array;
+ }
+ readNumber() {
+ const token = this.getToken();
+ return parseFloat(token || 0);
+ }
+ readInt() {
+ const token = this.getToken();
+ return parseInt(token || 0, 10) | 0;
+ }
+ readBoolean() {
+ const token = this.getToken();
+ return token === "true" ? 1 : 0;
+ }
+ nextChar() {
+ return this.currentChar = this.stream.getByte();
+ }
+ prevChar() {
+ this.stream.skip(-2);
+ return this.currentChar = this.stream.getByte();
+ }
+ getToken() {
+ let comment = false;
+ let ch = this.currentChar;
+ while (true) {
+ if (ch === -1) {
+ return null;
+ }
+ if (comment) {
+ if (ch === 0x0a || ch === 0x0d) {
+ comment = false;
+ }
+ } else if (ch === 0x25) {
+ comment = true;
+ } else if (!isWhiteSpace(ch)) {
+ break;
+ }
+ ch = this.nextChar();
+ }
+ if (isSpecial(ch)) {
+ this.nextChar();
+ return String.fromCharCode(ch);
+ }
+ let token = "";
+ do {
+ token += String.fromCharCode(ch);
+ ch = this.nextChar();
+ } while (ch >= 0 && !isWhiteSpace(ch) && !isSpecial(ch));
+ return token;
+ }
+ readCharStrings(bytes, lenIV) {
+ if (lenIV === -1) {
+ return bytes;
+ }
+ return decrypt(bytes, CHAR_STRS_ENCRYPT_KEY, lenIV);
+ }
+ extractFontProgram(properties) {
+ const stream = this.stream;
+ const subrs = [],
+ charstrings = [];
+ const privateData = new Map([["lenIV", 4]]);
+ const program = {
+ subrs: [],
+ charstrings: [],
+ properties: {
+ privateData
+ }
+ };
+ let token, length, data;
+ let subrsParsed = false;
+ let charStringsParsed = false;
+ while ((token = this.getToken()) !== null) {
+ if (token !== "/") {
+ continue;
+ }
+ token = this.getToken();
+ switch (token) {
+ case "CharStrings":
+ if (charStringsParsed) {
+ break;
+ }
+ charStringsParsed = true;
+ this.getToken();
+ this.getToken();
+ this.getToken();
+ this.getToken();
+ while (true) {
+ token = this.getToken();
+ if (token === null || token === "end") {
+ break;
+ }
+ if (token !== "/") {
+ continue;
+ }
+ const glyph = this.getToken();
+ length = this.readInt();
+ this.getToken();
+ data = length > 0 ? stream.getBytes(length) : new Uint8Array(0);
+ const encoded = this.readCharStrings(data, privateData.get("lenIV"));
+ this.nextChar();
+ token = this.getToken();
+ if (token === "noaccess") {
+ this.getToken();
+ } else if (token === "/") {
+ this.prevChar();
+ }
+ charstrings.push({
+ glyph,
+ encoded
+ });
+ }
+ break;
+ case "Subrs":
+ if (subrsParsed) {
+ break;
+ }
+ subrsParsed = true;
+ this.readInt();
+ this.getToken();
+ while (this.getToken() === "dup") {
+ const index = this.readInt();
+ length = this.readInt();
+ this.getToken();
+ data = length > 0 ? stream.getBytes(length) : new Uint8Array(0);
+ const encoded = this.readCharStrings(data, privateData.get("lenIV"));
+ this.nextChar();
+ token = this.getToken();
+ if (token === "noaccess") {
+ this.getToken();
+ }
+ subrs[index] = encoded;
+ }
+ break;
+ case "BlueValues":
+ case "OtherBlues":
+ case "FamilyBlues":
+ case "FamilyOtherBlues":
+ const blueArray = this.readNumberArray();
+ if (false) // removed by dead control flow
+{}
+ break;
+ case "StemSnapH":
+ case "StemSnapV":
+ privateData.set(token, this.readNumberArray());
+ break;
+ case "StdHW":
+ case "StdVW":
+ privateData.set(token, this.readNumberArray()[0]);
+ break;
+ case "BlueShift":
+ case "lenIV":
+ case "BlueFuzz":
+ case "BlueScale":
+ case "LanguageGroup":
+ privateData.set(token, this.readNumber());
+ break;
+ case "ExpansionFactor":
+ privateData.set(token, this.readNumber() || 0.06);
+ break;
+ case "ForceBold":
+ privateData.set(token, this.readBoolean());
+ break;
+ }
+ }
+ for (const {
+ encoded,
+ glyph
+ } of charstrings) {
+ const charString = new Type1CharString();
+ const error = charString.convert(encoded, subrs, this.seacAnalysisEnabled);
+ const output = !error ? charString.output : [14];
+ const charStringObject = {
+ glyphName: glyph,
+ charstring: output,
+ width: charString.width,
+ lsb: charString.lsb,
+ seac: charString.seac
+ };
+ if (glyph === ".notdef") {
+ program.charstrings.unshift(charStringObject);
+ } else {
+ program.charstrings.push(charStringObject);
+ }
+ if (properties.builtInEncoding) {
+ const index = properties.builtInEncoding.indexOf(glyph);
+ if (index > -1 && properties.widths[index] === undefined && index >= properties.firstChar && index <= properties.lastChar) {
+ properties.widths[index] = charString.width;
+ }
+ }
+ }
+ return program;
+ }
+ extractCidKeyedFontProgram(properties) {
+ const stream = this.stream;
+ const privateData = new Map([["lenIV", 4]]);
+ const program = {
+ subrs: [],
+ charstrings: [],
+ properties: {
+ privateData
+ }
+ };
+ let cidCount = 0;
+ let cidMapOffset = -1;
+ let fdBytes = 1;
+ let gdBytes = 0;
+ let subrMapOffset = -1;
+ let sdBytes = 0;
+ let subrCount = 0;
+ let startDataLength = 0;
+ let startDataIsHex = false;
+ let foundStartData = false;
+ const previousTokens = [];
+ function rememberToken(value) {
+ previousTokens.push(value);
+ if (previousTokens.length > 4) {
+ previousTokens.shift();
+ }
+ }
+ let token;
+ while ((token = this.getToken()) !== null) {
+ if (token === "StartData") {
+ const dataType = previousTokens.at(-3);
+ const dataLength = previousTokens.at(-1);
+ if (previousTokens.at(-4) !== "(" || previousTokens.at(-2) !== ")" || dataType !== "Binary" && dataType !== "Hex" || !/^\d+$/.test(dataLength)) {
+ return null;
+ }
+ startDataLength = parseInt(dataLength, 10);
+ if (startDataLength <= 0) {
+ return null;
+ }
+ startDataIsHex = dataType === "Hex";
+ foundStartData = true;
+ break;
+ }
+ rememberToken(token);
+ if (token !== "/") {
+ continue;
+ }
+ token = this.getToken();
+ rememberToken(token);
+ switch (token) {
+ case "FontMatrix":
+ properties.fontMatrix = this.readNumberArray();
+ break;
+ case "FontBBox":
+ const fontBBox = this.readNumberArray();
+ properties.ascent = Math.max(fontBBox[3], fontBBox[1]);
+ properties.descent = Math.min(fontBBox[1], fontBBox[3]);
+ properties.ascentScaled = true;
+ break;
+ case "CIDCount":
+ cidCount = this.readInt();
+ break;
+ case "CIDMapOffset":
+ cidMapOffset = this.readInt();
+ break;
+ case "FDBytes":
+ fdBytes = this.readInt();
+ break;
+ case "GDBytes":
+ gdBytes = this.readInt();
+ break;
+ case "SubrMapOffset":
+ subrMapOffset = this.readInt();
+ break;
+ case "SDBytes":
+ sdBytes = this.readInt();
+ break;
+ case "SubrCount":
+ subrCount = this.readInt();
+ break;
+ case "BlueValues":
+ case "OtherBlues":
+ case "FamilyBlues":
+ case "FamilyOtherBlues":
+ this.readNumberArray();
+ break;
+ case "StemSnapH":
+ case "StemSnapV":
+ privateData.set(token, this.readNumberArray());
+ break;
+ case "StdHW":
+ case "StdVW":
+ privateData.set(token, this.readNumberArray()[0]);
+ break;
+ case "BlueShift":
+ case "lenIV":
+ case "BlueFuzz":
+ case "BlueScale":
+ case "LanguageGroup":
+ privateData.set(token, this.readNumber());
+ break;
+ case "ExpansionFactor":
+ privateData.set(token, this.readNumber() || 0.06);
+ break;
+ case "ForceBold":
+ privateData.set(token, this.readBoolean());
+ break;
+ }
+ }
+ if (!foundStartData || cidCount <= 0 || cidMapOffset < 0 || fdBytes < 0 || fdBytes > 4 || gdBytes < 1 || gdBytes > 4) {
+ return null;
+ }
+ const maxLength = stream.end - stream.pos;
+ if (startDataLength > maxLength) {
+ if (!startDataIsHex) {
+ startDataLength = maxLength;
+ } else if (startDataLength > 2 * maxLength) {
+ return null;
+ }
+ }
+ let binary = stream.getBytes(startDataIsHex ? undefined : startDataLength);
+ if (startDataIsHex) {
+ const decoded = new Uint8Array(startDataLength);
+ let digit1 = -1,
+ j = 0;
+ for (let i = 0, ii = binary.length; i < ii && j < startDataLength; i++) {
+ const digit = binary[i];
+ if (!isHexDigit(digit)) {
+ continue;
+ }
+ if (digit1 < 0) {
+ digit1 = digit;
+ continue;
+ }
+ decoded[j++] = parseInt(String.fromCharCode(digit1, digit), 16);
+ digit1 = -1;
+ }
+ if (j !== startDataLength) {
+ return null;
+ }
+ binary = decoded;
+ }
+ const lenIV = privateData.get("lenIV");
+ const cidEntrySize = fdBytes + gdBytes;
+ const subrs = [];
+ function readUint(offset, byteCount) {
+ let n = 0;
+ for (let i = 0; i < byteCount; i++) {
+ n = n << 8 | binary[offset + i];
+ }
+ return n >>> 0;
+ }
+ if (cidMapOffset + (cidCount + 1) * cidEntrySize > binary.length || subrCount > 0 && (subrMapOffset < 0 || sdBytes < 1 || sdBytes > 4 || subrMapOffset + (subrCount + 1) * sdBytes > binary.length)) {
+ return null;
+ }
+ if (fdBytes > 0) {
+ for (let cid = 0; cid < cidCount; cid++) {
+ if (readUint(cidMapOffset + cid * cidEntrySize, fdBytes) !== 0) {
+ return null;
+ }
+ }
+ }
+ if (subrCount > 0) {
+ const subrOffsets = new Array(subrCount + 1);
+ for (let i = 0; i <= subrCount; i++) {
+ subrOffsets[i] = readUint(subrMapOffset + i * sdBytes, sdBytes);
+ }
+ for (let i = 0; i < subrCount; i++) {
+ const start = subrOffsets[i];
+ const end = subrOffsets[i + 1];
+ if (end > binary.length || end < start) {
+ subrs[i] = new Uint8Array(0);
+ continue;
+ }
+ subrs[i] = this.readCharStrings(binary.subarray(start, end), lenIV);
+ }
+ }
+ const charstrings = [];
+ let prevOffset = readUint(cidMapOffset + fdBytes, gdBytes);
+ for (let cid = 0; cid < cidCount; cid++) {
+ const nextOffset = readUint(cidMapOffset + (cid + 1) * cidEntrySize + fdBytes, gdBytes);
+ const glyphName = cid === 0 ? ".notdef" : `cid${cid}`;
+ if (nextOffset > prevOffset && nextOffset <= binary.length) {
+ const encoded = this.readCharStrings(binary.subarray(prevOffset, nextOffset), lenIV);
+ const charString = new Type1CharString();
+ const error = charString.convert(encoded, subrs, this.seacAnalysisEnabled);
+ charstrings.push({
+ glyphName,
+ charstring: error ? [14] : charString.output,
+ width: charString.width,
+ lsb: charString.lsb,
+ seac: charString.seac
+ });
+ } else {
+ const notDef = charstrings[0];
+ charstrings.push({
+ glyphName,
+ charstring: notDef?.charstring.slice() || [0x8b, 0x0e],
+ width: notDef?.width || 0,
+ lsb: notDef?.lsb || 0
+ });
+ }
+ prevOffset = nextOffset;
+ }
+ program.subrs = subrs;
+ program.charstrings = charstrings;
+ return program;
+ }
+ extractFontHeader(properties) {
+ let token;
+ while ((token = this.getToken()) !== null) {
+ if (token !== "/") {
+ continue;
+ }
+ token = this.getToken();
+ switch (token) {
+ case "FontMatrix":
+ const matrix = this.readNumberArray();
+ properties.fontMatrix = matrix;
+ break;
+ case "Encoding":
+ const encodingArg = this.getToken();
+ let encoding;
+ if (!/^\d+$/.test(encodingArg)) {
+ encoding = getEncoding(encodingArg);
+ } else {
+ encoding = [];
+ const size = parseInt(encodingArg, 10) | 0;
+ this.getToken();
+ for (let j = 0; j < size; j++) {
+ token = this.getToken();
+ while (token !== "dup" && token !== "def") {
+ token = this.getToken();
+ if (token === null) {
+ return;
+ }
+ }
+ if (token === "def") {
+ break;
+ }
+ const index = this.readInt();
+ this.getToken();
+ const glyph = this.getToken();
+ encoding[index] = glyph;
+ this.getToken();
+ }
+ }
+ properties.builtInEncoding = encoding;
+ break;
+ case "FontBBox":
+ const fontBBox = this.readNumberArray();
+ properties.ascent = Math.max(fontBBox[3], fontBBox[1]);
+ properties.descent = Math.min(fontBBox[1], fontBBox[3]);
+ properties.ascentScaled = true;
+ break;
+ }
+ }
+ }
+}
+
+;// ./src/core/type1_font.js
+
+
+
+
+
+
+
+
+function findBlock(streamBytes, signature, startIndex) {
+ const streamBytesLength = streamBytes.length;
+ const signatureLength = signature.length;
+ const scanLength = streamBytesLength - signatureLength;
+ let i = startIndex,
+ found = false;
+ while (i < scanLength) {
+ let j = 0;
+ while (j < signatureLength && streamBytes[i + j] === signature[j]) {
+ j++;
+ }
+ if (j >= signatureLength) {
+ i += j;
+ while (i < streamBytesLength && isWhiteSpace(streamBytes[i])) {
+ i++;
+ }
+ found = true;
+ break;
+ }
+ i++;
+ }
+ return {
+ found,
+ length: i
+ };
+}
+function getHeaderBlock(stream, suggestedLength) {
+ const EEXEC_SIGNATURE = [0x65, 0x65, 0x78, 0x65, 0x63];
+ const streamStartPos = stream.pos;
+ let headerBytes, headerBytesLength, block;
+ try {
+ headerBytes = stream.getBytes(suggestedLength);
+ headerBytesLength = headerBytes.length;
+ } catch {}
+ if (headerBytesLength === suggestedLength) {
+ block = findBlock(headerBytes, EEXEC_SIGNATURE, suggestedLength - 2 * EEXEC_SIGNATURE.length);
+ if (block.found && block.length === suggestedLength) {
+ return {
+ stream: new Stream(headerBytes),
+ length: suggestedLength
+ };
+ }
+ }
+ warn('Invalid "Length1" property in Type1 font -- trying to recover.');
+ stream.pos = streamStartPos;
+ const SCAN_BLOCK_LENGTH = 2048;
+ let actualLength;
+ while (true) {
+ const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH);
+ block = findBlock(scanBytes, EEXEC_SIGNATURE, 0);
+ if (block.length === 0) {
+ break;
+ }
+ stream.pos += block.length;
+ if (block.found) {
+ actualLength = stream.pos - streamStartPos;
+ break;
+ }
+ }
+ stream.pos = streamStartPos;
+ if (actualLength) {
+ return {
+ stream: new Stream(stream.getBytes(actualLength)),
+ length: actualLength
+ };
+ }
+ warn('Unable to recover "Length1" property in Type1 font -- using as is.');
+ return {
+ stream: new Stream(stream.getBytes(suggestedLength)),
+ length: suggestedLength
+ };
+}
+function getEexecBlock(stream, suggestedLength) {
+ const eexecBytes = stream.getBytes();
+ if (eexecBytes.length === 0) {
+ throw new FormatError("getEexecBlock - no font program found.");
+ }
+ return {
+ stream: new Stream(eexecBytes),
+ length: eexecBytes.length
+ };
+}
+function isCidKeyedType1File(file) {
+ const sample = file.peekBytes(2048);
+ if (sample.length < 2 || sample[0] !== 0x25 || sample[1] !== 0x21) {
+ return false;
+ }
+ const text = bytesToString(sample);
+ return text.includes("Resource-CIDFont") || /\/CIDFontType\s+0\b/.test(text);
+}
+class Type1Font {
+ #rawFileLength;
+ constructor(name, file, properties) {
+ let data;
+ if (properties.composite && isCidKeyedType1File(file)) {
+ data = this.#parseCidKeyedType1(file, properties);
+ }
+ data ||= this.#parseType1(file, properties);
+ for (const key in data.properties) {
+ properties[key] = data.properties[key];
+ }
+ const charstrings = data.charstrings;
+ const type2Charstrings = this.getType2Charstrings(charstrings);
+ const subrs = this.getType2Subrs(data.subrs);
+ this.charstrings = charstrings;
+ this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties);
+ this.seacs = this.getSeacs(data.charstrings);
+ }
+ #parseType1(file, properties) {
+ const PFB_HEADER_SIZE = 6;
+ let headerBlockLength = properties.length1;
+ let eexecBlockLength = properties.length2;
+ let pfbHeader = file.peekBytes(PFB_HEADER_SIZE);
+ const pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01;
+ if (pfbHeaderPresent) {
+ file.skip(PFB_HEADER_SIZE);
+ headerBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2];
+ }
+ const headerBlock = getHeaderBlock(file, headerBlockLength);
+ const headerBlockParser = new Type1Parser(headerBlock.stream, false, (/* inlined export .SEAC_ANALYSIS_ENABLED */true));
+ headerBlockParser.extractFontHeader(properties);
+ if (pfbHeaderPresent) {
+ pfbHeader = file.getBytes(PFB_HEADER_SIZE);
+ eexecBlockLength = pfbHeader[5] << 24 | pfbHeader[4] << 16 | pfbHeader[3] << 8 | pfbHeader[2];
+ }
+ const eexecBlock = getEexecBlock(file, eexecBlockLength);
+ const eexecBlockParser = new Type1Parser(eexecBlock.stream, true, (/* inlined export .SEAC_ANALYSIS_ENABLED */true));
+ const data = eexecBlockParser.extractFontProgram(properties);
+ this.#rawFileLength = headerBlock.length + eexecBlock.length;
+ return data;
+ }
+ #parseCidKeyedType1(file, properties) {
+ const fileStart = file.pos;
+ const length = file.end - fileStart;
+ const parser = new Type1Parser(file, false, (/* inlined export .SEAC_ANALYSIS_ENABLED */true));
+ const data = parser.extractCidKeyedFontProgram(properties);
+ if (!data) {
+ file.pos = fileStart;
+ warn("Type1Font: unable to parse CID-keyed Type 1 font.");
+ return null;
+ }
+ this.#rawFileLength = length;
+ return data;
+ }
+ get numGlyphs() {
+ return this.charstrings.length + 1;
+ }
+ getCharset() {
+ const charset = [".notdef"];
+ for (const {
+ glyphName
+ } of this.charstrings) {
+ charset.push(glyphName);
+ }
+ return charset;
+ }
+ getGlyphMapping(properties) {
+ const charstrings = this.charstrings;
+ if (properties.composite) {
+ const charCodeToGlyphId = Object.create(null);
+ for (let glyphId = 0, charstringsLen = charstrings.length; glyphId < charstringsLen; glyphId++) {
+ const charCode = properties.cMap.charCodeOf(glyphId);
+ charCodeToGlyphId[charCode] = glyphId + 1;
+ }
+ return charCodeToGlyphId;
+ }
+ const glyphNames = [".notdef"];
+ let builtInEncoding, glyphId;
+ for (glyphId = 0; glyphId < charstrings.length; glyphId++) {
+ glyphNames.push(charstrings[glyphId].glyphName);
+ }
+ const encoding = properties.builtInEncoding;
+ if (encoding) {
+ builtInEncoding = Object.create(null);
+ for (const charCode in encoding) {
+ glyphId = glyphNames.indexOf(encoding[charCode]);
+ if (glyphId >= 0) {
+ builtInEncoding[charCode] = glyphId;
+ }
+ }
+ }
+ return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);
+ }
+ hasGlyphId(id) {
+ if (id < 0 || id >= this.numGlyphs) {
+ return false;
+ }
+ if (id === 0) {
+ return true;
+ }
+ const glyph = this.charstrings[id - 1];
+ return glyph.charstring.length > 0;
+ }
+ getSeacs(charstrings) {
+ const seacMap = [];
+ for (let i = 0, ii = charstrings.length; i < ii; i++) {
+ const charstring = charstrings[i];
+ if (charstring.seac) {
+ seacMap[i + 1] = charstring.seac;
+ }
+ }
+ return seacMap;
+ }
+ getType2Charstrings(type1Charstrings) {
+ const type2Charstrings = [];
+ for (const type1Charstring of type1Charstrings) {
+ type2Charstrings.push(type1Charstring.charstring);
+ }
+ return type2Charstrings;
+ }
+ getType2Subrs(type1Subrs) {
+ let bias = 0;
+ const count = type1Subrs.length;
+ if (count < 1133) {
+ bias = 107;
+ } else if (count < 33769) {
+ bias = 1131;
+ } else {
+ bias = 32768;
+ }
+ const type2Subrs = [];
+ let i;
+ for (i = 0; i < bias; i++) {
+ type2Subrs.push([0x0b]);
+ }
+ for (i = 0; i < count; i++) {
+ type2Subrs.push(type1Subrs[i]);
+ }
+ return type2Subrs;
+ }
+ wrap(name, glyphs, charstrings, subrs, properties) {
+ const cff = new CFF(this.#rawFileLength);
+ cff.header = new CFFHeader(1, 0, 4, 4);
+ cff.names = [name];
+ const topDict = new CFFTopDict();
+ topDict.setByName("version", 391);
+ topDict.setByName("Notice", 392);
+ topDict.setByName("FullName", 393);
+ topDict.setByName("FamilyName", 394);
+ topDict.setByName("Weight", 395);
+ topDict.setByName("Encoding", null);
+ topDict.setByName("FontMatrix", properties.fontMatrix);
+ topDict.setByName("FontBBox", properties.bbox);
+ topDict.setByName("charset", null);
+ topDict.setByName("CharStrings", null);
+ topDict.setByName("Private", null);
+ cff.topDict = topDict;
+ const strings = new CFFStrings();
+ strings.add("Version 0.11");
+ strings.add("See original notice");
+ strings.add(name);
+ strings.add(name);
+ strings.add("Medium");
+ cff.strings = strings;
+ cff.globalSubrIndex = new CFFIndex();
+ const count = glyphs.length;
+ const charsetArray = [".notdef"];
+ for (let i = 0; i < count; i++) {
+ const {
+ glyphName
+ } = charstrings[i];
+ const index = CFFStandardStrings.indexOf(glyphName);
+ if (index === -1) {
+ strings.add(glyphName);
+ }
+ charsetArray.push(glyphName);
+ }
+ cff.charset = new CFFCharset(false, 0, charsetArray);
+ const charStringsIndex = new CFFIndex();
+ charStringsIndex.add([0x8b, 0x0e]);
+ for (let i = 0; i < count; i++) {
+ charStringsIndex.add(glyphs[i]);
+ }
+ cff.charStrings = charStringsIndex;
+ const privateDict = new CFFPrivateDict();
+ privateDict.setByName("Subrs", null);
+ const fields = ["BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StemSnapH", "StemSnapV", "BlueShift", "BlueFuzz", "BlueScale", "LanguageGroup", "ExpansionFactor", "ForceBold", "StdHW", "StdVW"];
+ for (const field of fields) {
+ if (!properties.privateData.has(field)) {
+ continue;
+ }
+ const value = properties.privateData.get(field);
+ if (Array.isArray(value)) {
+ for (let j = value.length - 1; j > 0; j--) {
+ value[j] -= value[j - 1];
+ }
+ }
+ privateDict.setByName(field, value);
+ }
+ cff.topDict.privateDict = privateDict;
+ const subrIndex = new CFFIndex();
+ for (const subr of subrs) {
+ subrIndex.add(subr);
+ }
+ privateDict.subrsIndex = subrIndex;
+ const compiler = new CFFCompiler(cff);
+ return compiler.compile();
+ }
+}
+
+;// ./src/core/fonts.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const PRIVATE_USE_AREAS = [[0xe000, 0xf8ff], [0x100000, 0x10fffd]];
+const PDF_GLYPH_SPACE_UNITS = 1000;
+const EXPORT_DATA_PROPERTIES = ["ascent", "bbox", "black", "bold", "cssFontInfo", "data", "defaultVMetrics", "defaultWidth", "descent", "disableFontFace", "fallbackName", "fontExtraProperties", "fontMatrix", "isInvalidPDFjsFont", "isType3Font", "italic", "loadedName", "mimetype", "missingFile", "name", "remeasure", "systemFontInfo", "vertical"];
+const EXPORT_DATA_EXTRA_PROPERTIES = ["cMap", "composite", "defaultEncoding", "differences", "isMonospace", "isSerifFont", "isSymbolicFont", "seacMap", "subtype", "toFontChar", "toUnicode", "type", "vmetrics", "widths"];
+function adjustWidths(properties) {
+ if (!properties.fontMatrix) {
+ return;
+ }
+ if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
+ return;
+ }
+ const scale = 0.001 / properties.fontMatrix[0];
+ const glyphsWidths = properties.widths;
+ for (const glyph in glyphsWidths) {
+ glyphsWidths[glyph] *= scale;
+ }
+ properties.defaultWidth *= scale;
+}
+function adjustTrueTypeToUnicode(properties, isSymbolicFont, nameRecords) {
+ if (properties.isInternalFont) {
+ return;
+ }
+ if (properties.hasIncludedToUnicodeMap) {
+ return;
+ }
+ if (properties.hasEncoding) {
+ return;
+ }
+ if (properties.toUnicode instanceof IdentityToUnicodeMap) {
+ return;
+ }
+ if (!isSymbolicFont) {
+ return;
+ }
+ if (nameRecords.length === 0) {
+ return;
+ }
+ if (properties.defaultEncoding === WinAnsiEncoding) {
+ return;
+ }
+ for (const r of nameRecords) {
+ if (!isWinNameRecord(r)) {
+ return;
+ }
+ }
+ const encoding = WinAnsiEncoding;
+ const toUnicode = [],
+ glyphsUnicodeMap = getGlyphsUnicode();
+ for (const charCode in encoding) {
+ const glyphName = encoding[charCode];
+ if (glyphName === "") {
+ continue;
+ }
+ const unicode = glyphsUnicodeMap[glyphName];
+ if (unicode === undefined) {
+ continue;
+ }
+ toUnicode[charCode] = String.fromCharCode(unicode);
+ }
+ if (toUnicode.length > 0) {
+ properties.toUnicode.amend(toUnicode);
+ }
+}
+function adjustType1ToUnicode(properties, builtInEncoding) {
+ if (properties.isInternalFont) {
+ return;
+ }
+ if (properties.hasIncludedToUnicodeMap) {
+ return;
+ }
+ if (builtInEncoding === properties.defaultEncoding) {
+ return;
+ }
+ if (properties.toUnicode instanceof IdentityToUnicodeMap) {
+ return;
+ }
+ const toUnicode = [],
+ glyphsUnicodeMap = getGlyphsUnicode();
+ for (const charCode in builtInEncoding) {
+ if (properties.hasEncoding) {
+ if (properties.baseEncodingName || properties.differences[charCode] !== undefined) {
+ continue;
+ }
+ }
+ const glyphName = builtInEncoding[charCode];
+ const unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);
+ if (unicode !== -1) {
+ toUnicode[charCode] = String.fromCharCode(unicode);
+ }
+ }
+ if (toUnicode.length > 0) {
+ properties.toUnicode.amend(toUnicode);
+ }
+}
+function amendFallbackToUnicode(properties) {
+ if (!properties.fallbackToUnicode) {
+ return;
+ }
+ if (properties.toUnicode instanceof IdentityToUnicodeMap) {
+ return;
+ }
+ const toUnicode = [];
+ for (const charCode in properties.fallbackToUnicode) {
+ if (properties.toUnicode.has(charCode)) {
+ continue;
+ }
+ toUnicode[charCode] = properties.fallbackToUnicode[charCode];
+ }
+ if (toUnicode.length > 0) {
+ properties.toUnicode.amend(toUnicode);
+ }
+}
+class fonts_Glyph {
+ constructor(originalCharCode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont) {
+ this.originalCharCode = originalCharCode;
+ this.fontChar = fontChar;
+ this.unicode = unicode;
+ this.accent = accent;
+ this.width = width;
+ this.vmetric = vmetric;
+ this.operatorListId = operatorListId;
+ this.isSpace = isSpace;
+ this.isInFont = isInFont;
+ }
+ get category() {
+ return shadow(this, "category", getCharUnicodeCategory(this.unicode), true);
+ }
+}
+function int16(b0, b1) {
+ return (b0 << 8) + b1;
+}
+function writeSignedInt16(bytes, index, value) {
+ bytes[index + 1] = value;
+ bytes[index] = value >>> 8;
+}
+function signedInt16(b0, b1) {
+ const value = (b0 << 8) + b1;
+ return value & 1 << 15 ? value - 0x10000 : value;
+}
+function writeUint32(bytes, index, value) {
+ bytes[index + 3] = value & 0xff;
+ bytes[index + 2] = value >>> 8;
+ bytes[index + 1] = value >>> 16;
+ bytes[index] = value >>> 24;
+}
+function isTrueTypeFile(file) {
+ const header = file.peekBytes(4),
+ str = bytesToString(header);
+ return str === "\x00\x01\x00\x00" || str === "true";
+}
+function isTrueTypeCollectionFile(file) {
+ const header = file.peekBytes(4);
+ return bytesToString(header) === "ttcf";
+}
+function isOpenTypeFile(file) {
+ const header = file.peekBytes(4);
+ return bytesToString(header) === "OTTO";
+}
+function isType1File(file) {
+ const header = file.peekBytes(2);
+ if (header[0] === 0x25 && header[1] === 0x21) {
+ return true;
+ }
+ if (header[0] === 0x80 && header[1] === 0x01) {
+ return true;
+ }
+ return false;
+}
+function isCFFFile(file) {
+ const header = file.peekBytes(4);
+ if (header[0] >= 1 && header[3] >= 1 && header[3] <= 4) {
+ return true;
+ }
+ return false;
+}
+function getFontFileType(file, {
+ type,
+ subtype,
+ composite
+}) {
+ let fileType, fileSubtype;
+ if (isTrueTypeFile(file) || isTrueTypeCollectionFile(file)) {
+ fileType = composite ? "CIDFontType2" : "TrueType";
+ } else if (isOpenTypeFile(file)) {
+ fileType = composite ? "CIDFontType2" : "OpenType";
+ } else if (isType1File(file)) {
+ if (composite) {
+ fileType = "CIDFontType0";
+ } else {
+ fileType = type === "MMType1" ? "MMType1" : "Type1";
+ }
+ } else if (isCFFFile(file)) {
+ if (composite) {
+ fileType = "CIDFontType0";
+ fileSubtype = "CIDFontType0C";
+ } else {
+ fileType = type === "MMType1" ? "MMType1" : "Type1";
+ fileSubtype = "Type1C";
+ }
+ } else {
+ warn("getFontFileType: Unable to detect correct font file Type/Subtype.");
+ fileType = type;
+ fileSubtype = subtype;
+ }
+ return [fileType, fileSubtype];
+}
+function applyStandardFontGlyphMap(map, glyphMap) {
+ for (const charCode in glyphMap) {
+ map[+charCode] = glyphMap[charCode];
+ }
+}
+const getSymbolGlyphIdEncoding = getLookupTableFactory(t => {
+ let glyphId = 3;
+ for (const [firstCharCode, lastCharCode] of [[0x20, 0x7e], [0xa1, 0xfe]]) {
+ for (let charCode = firstCharCode; charCode <= lastCharCode; charCode++) {
+ t[glyphId++] = SymbolSetEncoding[charCode];
+ }
+ }
+}, true);
+function buildToFontChar(encoding, glyphsUnicodeMap, differences) {
+ const toFontChar = [];
+ let unicode;
+ for (let i = 0, ii = encoding.length; i < ii; i++) {
+ unicode = getUnicodeForGlyph(encoding[i], glyphsUnicodeMap);
+ if (unicode !== -1) {
+ toFontChar[i] = unicode;
+ }
+ }
+ for (const charCode in differences) {
+ unicode = getUnicodeForGlyph(differences[charCode], glyphsUnicodeMap);
+ if (unicode !== -1) {
+ toFontChar[+charCode] = unicode;
+ }
+ }
+ return toFontChar;
+}
+function isMacNameRecord(r) {
+ return r.platform === 1 && r.encoding === 0 && r.language === 0;
+}
+function isWinNameRecord(r) {
+ return r.platform === 3 && r.encoding === 1 && r.language === 0x409;
+}
+function convertCidString(charCode, cid, shouldThrow = false) {
+ switch (cid.length) {
+ case 1:
+ return cid.charCodeAt(0);
+ case 2:
+ return cid.charCodeAt(0) << 8 | cid.charCodeAt(1);
+ }
+ const msg = `Unsupported CID string (charCode ${charCode}): "${cid}".`;
+ if (shouldThrow) {
+ throw new FormatError(msg);
+ }
+ warn(msg);
+ return cid;
+}
+function adjustMapping(charCodeToGlyphId, hasGlyph, newGlyphZeroId, toUnicode) {
+ const newMap = Object.create(null);
+ const toUnicodeExtraMap = new Map();
+ const toFontChar = [];
+ const usedGlyphIds = new Set();
+ let privateUseAreaIndex = 0;
+ const privateUseOffetStart = PRIVATE_USE_AREAS[privateUseAreaIndex][0];
+ let nextAvailableFontCharCode = privateUseOffetStart;
+ let privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1];
+ const isInPrivateArea = code => PRIVATE_USE_AREAS[0][0] <= code && code <= PRIVATE_USE_AREAS[0][1] || PRIVATE_USE_AREAS[1][0] <= code && code <= PRIVATE_USE_AREAS[1][1];
+ let LIGATURE_TO_UNICODE = null;
+ for (const originalCharCode in charCodeToGlyphId) {
+ let glyphId = charCodeToGlyphId[originalCharCode];
+ if (!hasGlyph(glyphId)) {
+ continue;
+ }
+ if (nextAvailableFontCharCode > privateUseOffetEnd) {
+ privateUseAreaIndex++;
+ if (privateUseAreaIndex >= PRIVATE_USE_AREAS.length) {
+ warn("Ran out of space in font private use area.");
+ break;
+ }
+ nextAvailableFontCharCode = PRIVATE_USE_AREAS[privateUseAreaIndex][0];
+ privateUseOffetEnd = PRIVATE_USE_AREAS[privateUseAreaIndex][1];
+ }
+ const fontCharCode = nextAvailableFontCharCode++;
+ if (glyphId === 0) {
+ glyphId = newGlyphZeroId;
+ }
+ let unicode = toUnicode.get(originalCharCode);
+ if (typeof unicode === "string") {
+ if (unicode.length === 1) {
+ unicode = unicode.codePointAt(0);
+ } else {
+ if (!LIGATURE_TO_UNICODE) {
+ LIGATURE_TO_UNICODE = new Map();
+ for (let i = 0xfb00; i <= 0xfb4f; i++) {
+ const normalized = String.fromCharCode(i).normalize("NFKD");
+ if (normalized.length > 1) {
+ LIGATURE_TO_UNICODE.set(normalized, i);
+ }
+ }
+ }
+ unicode = LIGATURE_TO_UNICODE.get(unicode) || unicode.codePointAt(0);
+ }
+ }
+ if (unicode && !isInPrivateArea(unicode) && !usedGlyphIds.has(glyphId)) {
+ toUnicodeExtraMap.set(unicode, glyphId);
+ usedGlyphIds.add(glyphId);
+ }
+ newMap[fontCharCode] = glyphId;
+ toFontChar[originalCharCode] = fontCharCode;
+ }
+ return {
+ toFontChar,
+ charCodeToGlyphId: newMap,
+ toUnicodeExtraMap,
+ nextAvailableFontCharCode
+ };
+}
+function getRanges(glyphs, toUnicodeExtraMap, numGlyphs) {
+ const codes = [];
+ for (const charCode in glyphs) {
+ if (glyphs[charCode] >= numGlyphs) {
+ continue;
+ }
+ codes.push({
+ fontCharCode: charCode | 0,
+ glyphId: glyphs[charCode]
+ });
+ }
+ if (toUnicodeExtraMap) {
+ for (const [unicode, glyphId] of toUnicodeExtraMap) {
+ if (glyphId >= numGlyphs) {
+ continue;
+ }
+ codes.push({
+ fontCharCode: unicode,
+ glyphId
+ });
+ }
+ }
+ if (codes.length === 0) {
+ codes.push({
+ fontCharCode: 0,
+ glyphId: 0
+ });
+ }
+ codes.sort((a, b) => a.fontCharCode - b.fontCharCode);
+ const ranges = [];
+ const length = codes.length;
+ for (let n = 0; n < length;) {
+ const start = codes[n].fontCharCode;
+ const codeIndices = [codes[n].glyphId];
+ ++n;
+ let end = start;
+ while (n < length && end + 1 === codes[n].fontCharCode) {
+ codeIndices.push(codes[n].glyphId);
+ ++end;
+ ++n;
+ if (end === 0xffff) {
+ break;
+ }
+ }
+ ranges.push([start, end, codeIndices]);
+ }
+ return ranges;
+}
+function createCmapTable(glyphs, toUnicodeExtraMap, numGlyphs) {
+ const ranges = getRanges(glyphs, toUnicodeExtraMap, numGlyphs);
+ const hasNonBmp = ranges.at(-1)[1] > 0xffff;
+ let i, ii, j, jj;
+ for (i = ranges.length - 1; i >= 0; --i) {
+ if (ranges[i][0] <= 0xffff) {
+ break;
+ }
+ }
+ const bmpLength = i + 1;
+ if (ranges[i][0] < 0xffff && ranges[i][1] === 0xffff) {
+ ranges[i][1] = 0xfffe;
+ }
+ const trailingRangesCount = ranges[i][1] < 0xffff ? 1 : 0;
+ const segCount = bmpLength + trailingRangesCount;
+ const searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
+ const segmentsLength = bmpLength * 2 + trailingRangesCount * 2;
+ const startCount = new DataBuilder({
+ exactLength: segmentsLength
+ }),
+ endCount = new DataBuilder({
+ exactLength: segmentsLength
+ }),
+ idDeltas = new DataBuilder({
+ exactLength: segmentsLength
+ }),
+ idRangeOffsets = new DataBuilder({
+ exactLength: segmentsLength
+ }),
+ glyphsIds = new DataBuilder({});
+ let bias = 0;
+ let format4Overflow = false;
+ for (i = 0, ii = bmpLength; i < ii; i++) {
+ const [start, end, codes] = ranges[i];
+ startCount.setInt16(start);
+ endCount.setInt16(end);
+ let contiguous = true;
+ for (j = 1, jj = codes.length; j < jj; ++j) {
+ if (codes[j] !== codes[j - 1] + 1) {
+ contiguous = false;
+ break;
+ }
+ }
+ if (!contiguous) {
+ const offset = (segCount - i) * 2 + bias * 2;
+ bias += end - start + 1;
+ idDeltas.skip(2);
+ if (offset > 0xffff) {
+ format4Overflow = true;
+ idRangeOffsets.skip(2);
+ } else {
+ idRangeOffsets.setInt16(offset);
+ }
+ for (j = 0, jj = codes.length; j < jj; ++j) {
+ glyphsIds.setInt16(codes[j]);
+ }
+ } else {
+ const startCode = codes[0];
+ idDeltas.setInt16(startCode - start & 0xffff);
+ idRangeOffsets.skip(2);
+ }
+ }
+ if (trailingRangesCount > 0) {
+ endCount.setArray([0xff, 0xff]);
+ startCount.setArray([0xff, 0xff]);
+ idDeltas.setArray([0x00, 0x01]);
+ idRangeOffsets.skip(2);
+ }
+ const format314 = new DataBuilder({
+ exactLength: 12 + startCount.length + endCount.length + idDeltas.length + idRangeOffsets.length + glyphsIds.length
+ });
+ format314.skip(2);
+ format314.setInt16(2 * segCount);
+ format314.setInt16(searchParams.range);
+ format314.setInt16(searchParams.entry);
+ format314.setInt16(searchParams.rangeShift);
+ format314.setArray(endCount.data);
+ format314.skip(2);
+ format314.setArray(startCount.data);
+ format314.setArray(idDeltas.data);
+ format314.setArray(idRangeOffsets.data);
+ format314.setArray(glyphsIds.data);
+ const useFormat4 = !format4Overflow && format314.length + 4 <= 0xffff;
+ const useFormat12 = hasNonBmp || !useFormat4;
+ const numTables = (useFormat4 ? 1 : 0) + (useFormat12 ? 1 : 0);
+ let format31012 = null,
+ header31012 = null;
+ if (useFormat12) {
+ format31012 = new DataBuilder({});
+ for (const range of ranges) {
+ let start = range[0];
+ const codes = range[2];
+ let code = codes[0];
+ for (j = 1, jj = codes.length; j < jj; ++j) {
+ if (codes[j] !== codes[j - 1] + 1) {
+ const end = range[0] + j - 1;
+ format31012.setInt32(start);
+ format31012.setInt32(end);
+ format31012.setInt32(code);
+ start = end + 1;
+ code = codes[j];
+ }
+ }
+ format31012.setInt32(start);
+ format31012.setInt32(range[1]);
+ format31012.setInt32(code);
+ }
+ header31012 = new DataBuilder({
+ exactLength: 16
+ });
+ header31012.setArray([0x00, 0x0c]);
+ header31012.skip(2);
+ header31012.setInt32(format31012.length + 16);
+ header31012.skip(4);
+ header31012.setInt32(format31012.length / 12);
+ }
+ const headerLength = 4 + numTables * 8;
+ const format4Length = useFormat4 ? 4 + format314.length : 0;
+ const cmap = new DataBuilder({
+ exactLength: headerLength
+ });
+ cmap.skip(2);
+ cmap.setInt16(numTables);
+ let tableOffset = headerLength;
+ if (useFormat4) {
+ cmap.setArray([0x00, 0x03]);
+ cmap.setArray([0x00, 0x01]);
+ cmap.setInt32(tableOffset);
+ tableOffset += format4Length;
+ }
+ if (useFormat12) {
+ cmap.setArray([0x00, 0x03]);
+ cmap.setArray([0x00, 0x0a]);
+ cmap.setInt32(tableOffset);
+ }
+ const table = new DataBuilder({
+ exactLength: cmap.length + format4Length + (header31012?.length ?? 0) + (format31012?.length ?? 0)
+ });
+ table.setArray(cmap.data);
+ if (useFormat4) {
+ table.setArray([0x00, 0x04]);
+ table.setInt16(format314.length + 4);
+ table.setArray(format314.data);
+ }
+ if (useFormat12) {
+ table.setArray(header31012.data);
+ table.setArray(format31012.data);
+ }
+ return table.data;
+}
+function validateOS2Table(os2, file) {
+ file.pos = (file.start || 0) + os2.offset;
+ const version = file.getUint16();
+ const minLength = [78, 86, 96, 96, 96, 100][version];
+ if (minLength === undefined || os2.length < minLength) {
+ return false;
+ }
+ file.skip(60);
+ const selection = file.getUint16();
+ if (version < 4 && selection & 0x0300) {
+ return false;
+ }
+ const firstChar = file.getUint16();
+ const lastChar = file.getUint16();
+ if (firstChar > lastChar) {
+ return false;
+ }
+ file.skip(6);
+ const usWinAscent = file.getUint16();
+ if (usWinAscent === 0) {
+ return false;
+ }
+ os2.data[8] = os2.data[9] = 0;
+ return true;
+}
+function createOS2Table(properties, charstrings, override) {
+ override ||= {
+ unitsPerEm: 0,
+ yMax: 0,
+ yMin: 0,
+ ascent: 0,
+ descent: 0
+ };
+ let ulUnicodeRange1 = 0;
+ let ulUnicodeRange2 = 0;
+ let ulUnicodeRange3 = 0;
+ let ulUnicodeRange4 = 0;
+ let firstCharIndex = null;
+ let lastCharIndex = 0;
+ let position = -1;
+ if (charstrings) {
+ for (let code in charstrings) {
+ code |= 0;
+ if (firstCharIndex > code || !firstCharIndex) {
+ firstCharIndex = code;
+ }
+ if (lastCharIndex < code) {
+ lastCharIndex = code;
+ }
+ position = getUnicodeRangeFor(code, position);
+ if (position < 32) {
+ ulUnicodeRange1 |= 1 << position;
+ } else if (position < 64) {
+ ulUnicodeRange2 |= 1 << position - 32;
+ } else if (position < 96) {
+ ulUnicodeRange3 |= 1 << position - 64;
+ } else if (position < 123) {
+ ulUnicodeRange4 |= 1 << position - 96;
+ } else {
+ throw new FormatError("Unicode ranges Bits > 123 are reserved for internal usage");
+ }
+ }
+ if (lastCharIndex > 0xffff) {
+ lastCharIndex = 0xffff;
+ }
+ } else {
+ firstCharIndex = 0;
+ lastCharIndex = 255;
+ }
+ const bbox = properties.bbox || [0, 0, 0, 0];
+ const unitsPerEm = override.unitsPerEm || (properties.fontMatrix ? 1 / Math.max(...properties.fontMatrix.slice(0, 4).map(Math.abs)) : 1000);
+ const scale = properties.ascentScaled ? 1.0 : unitsPerEm / PDF_GLYPH_SPACE_UNITS;
+ const typoAscent = override.ascent || Math.round(scale * (properties.ascent || bbox[3]));
+ let typoDescent = override.descent || Math.round(scale * (properties.descent || bbox[1]));
+ if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
+ typoDescent = -typoDescent;
+ }
+ const winAscent = override.yMax || typoAscent;
+ const winDescent = -override.yMin || -typoDescent;
+ const os2 = new DataBuilder({
+ exactLength: 96
+ });
+ os2.setArray([0x00, 0x03]);
+ os2.setArray([0x02, 0x24]);
+ os2.setArray([0x01, 0xf4]);
+ os2.setArray([0x00, 0x05]);
+ os2.skip(2);
+ os2.setArray([0x02, 0x8a]);
+ os2.setArray([0x02, 0xbb]);
+ os2.skip(2);
+ os2.setArray([0x00, 0x8c]);
+ os2.setArray([0x02, 0x8a]);
+ os2.setArray([0x02, 0xbb]);
+ os2.skip(2);
+ os2.setArray([0x01, 0xdf]);
+ os2.setArray([0x00, 0x31]);
+ os2.setArray([0x01, 0x02]);
+ os2.skip(2);
+ os2.setArray([0x00, 0x00, 0x06, properties.fixedPitch ? 0x09 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
+ os2.setInt32(ulUnicodeRange1);
+ os2.setInt32(ulUnicodeRange2);
+ os2.setInt32(ulUnicodeRange3);
+ os2.setInt32(ulUnicodeRange4);
+ os2.setArray([0x2a, 0x32, 0x31, 0x2a]);
+ os2.setInt16(properties.italicAngle ? 1 : 0);
+ os2.setInt16(firstCharIndex || properties.firstChar);
+ os2.setInt16(lastCharIndex || properties.lastChar);
+ os2.setInt16(typoAscent);
+ os2.setInt16(typoDescent);
+ os2.setArray([0x00, 0x64]);
+ os2.setInt16(winAscent);
+ os2.setInt16(winDescent);
+ os2.skip(4 + 4);
+ os2.setInt16(properties.xHeight);
+ os2.setInt16(properties.capHeight);
+ os2.skip(2);
+ os2.setInt16(firstCharIndex || properties.firstChar);
+ os2.setArray([0x00, 0x03]);
+ return os2.data;
+}
+function createPostTable(properties) {
+ const post = new DataBuilder({
+ exactLength: 32
+ });
+ post.setArray([0x00, 0x03, 0x00, 0x00]);
+ post.setInt32(Math.floor(properties.italicAngle * 2 ** 16));
+ post.skip(2 + 2);
+ post.setInt32(properties.fixedPitch ? 1 : 0);
+ post.skip(4 + 4 + 4 + 4);
+ return post.data;
+}
+function createPostscriptName(name) {
+ return name.replaceAll(/[^\x21-\x7E]|[[\](){}<>/%]/g, "").slice(0, 63);
+}
+function createNameTable(name, proto) {
+ proto ||= [[], []];
+ const strings = [proto[0][0] || "Original licence", proto[0][1] || name, proto[0][2] || "Unknown", proto[0][3] || "uniqueID", proto[0][4] || name, proto[0][5] || "Version 0.11", proto[0][6] || createPostscriptName(name), proto[0][7] || "Unknown", proto[0][8] || "Unknown", proto[0][9] || "Unknown"];
+ const stringsBytes = strings.map(stringToBytes);
+ const stringsUnicodeBytes = new Array(strings.length);
+ let i, ii, j, jj, str;
+ for (i = 0, ii = strings.length; i < ii; i++) {
+ str = proto[1][i] || strings[i];
+ const strUnicode = new DataBuilder({
+ exactLength: str.length * 2
+ });
+ for (j = 0, jj = str.length; j < jj; j++) {
+ strUnicode.setInt16(str.charCodeAt(j));
+ }
+ stringsUnicodeBytes[i] = strUnicode.data;
+ }
+ const namesBytes = [stringsBytes, stringsUnicodeBytes];
+ const platformsBytes = [[0x00, 0x01], [0x00, 0x03]];
+ const encodingsBytes = [[0x00, 0x00], [0x00, 0x01]];
+ const languagesBytes = [[0x00, 0x00], [0x04, 0x09]];
+ const nameRecords = [];
+ let strOffset = 0;
+ for (i = 0, ii = platformsBytes.length; i < ii; i++) {
+ const strs = namesBytes[i];
+ for (j = 0, jj = strs.length; j < jj; j++) {
+ str = strs[j];
+ const nameRecord = new DataBuilder({
+ exactLength: 6 + platformsBytes[i].length + encodingsBytes[i].length + languagesBytes[i].length
+ });
+ nameRecord.setArray(platformsBytes[i]);
+ nameRecord.setArray(encodingsBytes[i]);
+ nameRecord.setArray(languagesBytes[i]);
+ nameRecord.setInt16(j);
+ nameRecord.setInt16(str.length);
+ nameRecord.setInt16(strOffset);
+ nameRecords.push(nameRecord.data);
+ strOffset += str.length;
+ }
+ }
+ const namesRecordCount = stringsBytes.length * platformsBytes.length;
+ const nameTable = new DataBuilder({
+ exactLength: 6 + Math.sumPrecise(nameRecords.map(arr => arr.length)) + Math.sumPrecise(stringsBytes.map(arr => arr.length)) + Math.sumPrecise(stringsUnicodeBytes.map(arr => arr.length))
+ });
+ nameTable.skip(2);
+ nameTable.setInt16(namesRecordCount);
+ nameTable.setInt16(namesRecordCount * 12 + 6);
+ for (const arr of nameRecords) {
+ nameTable.setArray(arr);
+ }
+ for (const arr of stringsBytes) {
+ nameTable.setArray(arr);
+ }
+ for (const arr of stringsUnicodeBytes) {
+ nameTable.setArray(arr);
+ }
+ return nameTable.data;
+}
+class Font {
+ #charsCache = new Map();
+ #glyphCache = new Map();
+ charProcOperatorList;
+ constructor(name, file, properties, evaluatorOptions) {
+ this.name = name;
+ this.psName = null;
+ this.mimetype = null;
+ this.disableFontFace = evaluatorOptions.disableFontFace;
+ this.fontExtraProperties = evaluatorOptions.fontExtraProperties;
+ this.loadedName = properties.loadedName;
+ this.isType3Font = properties.isType3Font;
+ this.missingFile = false;
+ this.cssFontInfo = properties.cssFontInfo;
+ let isSerifFont = !!(properties.flags & FontFlags.Serif);
+ if (!isSerifFont && !properties.isSimulatedFlags) {
+ const stdFontMap = getStdFontMap(),
+ nonStdFontMap = getNonStdFontMap(),
+ serifFonts = getSerifFonts();
+ for (const namePart of name.split("+")) {
+ let fontName = normalizeFontName(namePart);
+ fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
+ fontName = fontName.split("-", 1)[0];
+ if (serifFonts[fontName]) {
+ isSerifFont = true;
+ break;
+ }
+ }
+ }
+ this.isSerifFont = isSerifFont;
+ this.isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
+ this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
+ let {
+ type,
+ subtype
+ } = properties;
+ this.type = type;
+ this.subtype = subtype;
+ this.systemFontInfo = properties.systemFontInfo;
+ const matches = name.match(/^InvalidPDFjsFont_(.*)_\d+$/);
+ this.isInvalidPDFjsFont = !!matches;
+ if (this.isInvalidPDFjsFont) {
+ this.fallbackName = matches[1];
+ } else if (this.isMonospace) {
+ this.fallbackName = "monospace";
+ } else if (this.isSerifFont) {
+ this.fallbackName = "serif";
+ } else {
+ this.fallbackName = "sans-serif";
+ }
+ if (this.systemFontInfo?.guessFallback) {
+ this.systemFontInfo.guessFallback = false;
+ this.systemFontInfo.css += `,${this.fallbackName}`;
+ }
+ this.differences = properties.differences;
+ this.widths = properties.widths;
+ this.defaultWidth = properties.defaultWidth;
+ this.composite = properties.composite;
+ this.cMap = properties.cMap;
+ this.capHeight = properties.capHeight / PDF_GLYPH_SPACE_UNITS;
+ this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
+ this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
+ this.lineHeight = this.ascent - this.descent;
+ this.fontMatrix = properties.fontMatrix;
+ this.bbox = properties.bbox;
+ this.defaultEncoding = properties.defaultEncoding;
+ this.toUnicode = properties.toUnicode;
+ this.toFontChar = [];
+ if (properties.type === "Type3") {
+ for (let charCode = 0; charCode < 256; charCode++) {
+ this.toFontChar[charCode] = this.differences[charCode] || properties.defaultEncoding[charCode];
+ }
+ return;
+ }
+ this.cidEncoding = properties.cidEncoding || "";
+ this.vertical = !!properties.vertical;
+ if (this.vertical) {
+ this.vmetrics = properties.vmetrics;
+ this.defaultVMetrics = properties.defaultVMetrics;
+ }
+ if (!file || file.isEmpty) {
+ if (file) {
+ warn('Font file is empty in "' + name + '" (' + this.loadedName + ")");
+ }
+ this.fallbackToSystemFont(properties);
+ return;
+ }
+ [type, subtype] = getFontFileType(file, properties);
+ if (type !== this.type || subtype !== this.subtype) {
+ info("Inconsistent font file Type/SubType, expected: " + `${this.type}/${this.subtype} but found: ${type}/${subtype}.`);
+ }
+ let data;
+ try {
+ switch (type) {
+ case "MMType1":
+ info("MMType1 font (" + name + "), falling back to Type1.");
+ case "Type1":
+ case "CIDFontType0":
+ this.mimetype = "font/opentype";
+ const cff = subtype === "Type1C" || subtype === "CIDFontType0C" ? new CFFFont(file, properties) : new Type1Font(name, file, properties);
+ adjustWidths(properties);
+ data = this.convert(name, cff, properties);
+ break;
+ case "OpenType":
+ case "TrueType":
+ case "CIDFontType2":
+ this.mimetype = "font/opentype";
+ data = this.checkAndRepair(name, file, properties);
+ adjustWidths(properties);
+ if (this.isOpenType) {
+ type = "OpenType";
+ }
+ break;
+ default:
+ throw new FormatError(`Font ${type} is not supported`);
+ }
+ } catch (e) {
+ warn(e);
+ this.fallbackToSystemFont(properties);
+ return;
+ }
+ amendFallbackToUnicode(properties);
+ this.data = data;
+ this.type = type;
+ this.subtype = subtype;
+ this.fontMatrix = properties.fontMatrix;
+ this.widths = properties.widths;
+ this.defaultWidth = properties.defaultWidth;
+ this.toUnicode = properties.toUnicode;
+ this.seacMap = properties.seacMap;
+ }
+ get renderer() {
+ const renderer = FontRendererFactory.create(this, (/* inlined export .SEAC_ANALYSIS_ENABLED */true));
+ return shadow(this, "renderer", renderer);
+ }
+ #getExportData(props) {
+ const data = Object.create(null);
+ for (const prop of props) {
+ const value = this[prop];
+ if (value !== undefined) {
+ data[prop] = value;
+ }
+ }
+ return data;
+ }
+ exportData() {
+ return {
+ buffer: compileFontInfo(this.#getExportData(EXPORT_DATA_PROPERTIES)),
+ charProcOperatorList: this.charProcOperatorList,
+ extra: this.fontExtraProperties ? this.#getExportData(EXPORT_DATA_EXTRA_PROPERTIES) : undefined
+ };
+ }
+ fallbackToSystemFont(properties) {
+ this.missingFile = true;
+ const {
+ name,
+ type
+ } = this;
+ let fontName = normalizeFontName(name);
+ const stdFontMap = getStdFontMap(),
+ nonStdFontMap = getNonStdFontMap();
+ const isStandardFont = !!stdFontMap[fontName];
+ const isMappedToStandardFont = !!(nonStdFontMap[fontName] && stdFontMap[nonStdFontMap[fontName]]);
+ fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
+ const fontBasicMetricsMap = getFontBasicMetrics();
+ const metrics = fontBasicMetricsMap[fontName];
+ if (metrics) {
+ if (isNaN(this.ascent)) {
+ this.ascent = metrics.ascent / PDF_GLYPH_SPACE_UNITS;
+ }
+ if (isNaN(this.descent)) {
+ this.descent = metrics.descent / PDF_GLYPH_SPACE_UNITS;
+ }
+ if (isNaN(this.capHeight)) {
+ this.capHeight = metrics.capHeight / PDF_GLYPH_SPACE_UNITS;
+ }
+ }
+ this.bold = /bold/i.test(fontName);
+ this.italic = /oblique|italic/i.test(fontName);
+ this.black = /Black/.test(name);
+ const isNarrow = /Narrow/.test(name);
+ this.remeasure = (!isStandardFont || isNarrow) && Object.keys(this.widths).length > 0;
+ if ((isStandardFont || isMappedToStandardFont) && type === "CIDFontType2" && this.cidEncoding.startsWith("Identity-")) {
+ const cidToGidMap = properties.cidToGidMap;
+ const map = [];
+ if (/Trebuchet/i.test(name)) {
+ applyStandardFontGlyphMap(map, getGlyphMapForMacOrderedFonts());
+ applyStandardFontGlyphMap(map, getSupplementalGlyphMapForTrebuchetMS());
+ } else {
+ applyStandardFontGlyphMap(map, getGlyphMapForStandardFonts());
+ if (/Arial-?Black/i.test(name)) {
+ applyStandardFontGlyphMap(map, getSupplementalGlyphMapForArialBlack());
+ } else if (/Calibri/i.test(name)) {
+ applyStandardFontGlyphMap(map, getSupplementalGlyphMapForCalibri());
+ }
+ }
+ if (cidToGidMap) {
+ for (const charCode in map) {
+ const cid = map[charCode];
+ if (cidToGidMap[cid] !== undefined) {
+ map[+charCode] = cidToGidMap[cid];
+ }
+ }
+ if (cidToGidMap.length !== this.toUnicode.length && properties.hasIncludedToUnicodeMap && this.toUnicode instanceof IdentityToUnicodeMap) {
+ this.toUnicode.forEach(function (charCode, unicodeCharCode) {
+ const cid = map[charCode];
+ if (cidToGidMap[cid] === undefined) {
+ map[+charCode] = unicodeCharCode;
+ }
+ });
+ }
+ }
+ if (!(this.toUnicode instanceof IdentityToUnicodeMap)) {
+ this.toUnicode.forEach(function (charCode, unicodeCharCode) {
+ map[+charCode] = unicodeCharCode;
+ });
+ }
+ this.toFontChar = map;
+ this.toUnicode = new ToUnicodeMap(map);
+ } else if (/Symbol/i.test(fontName)) {
+ const isCidKeyed = this.composite && this.cidEncoding.startsWith("Identity-");
+ this.toFontChar = buildToFontChar(isCidKeyed ? getSymbolGlyphIdEncoding() : SymbolSetEncoding, getGlyphsUnicode(), this.differences);
+ } else if (/Dingbats/i.test(fontName)) {
+ this.toFontChar = buildToFontChar(ZapfDingbatsEncoding, getDingbatsGlyphsUnicode(), this.differences);
+ } else if (isStandardFont || isMappedToStandardFont) {
+ const map = buildToFontChar(this.defaultEncoding, getGlyphsUnicode(), this.differences);
+ if (type === "CIDFontType2" && !this.cidEncoding.startsWith("Identity-") && !(this.toUnicode instanceof IdentityToUnicodeMap)) {
+ this.toUnicode.forEach(function (charCode, unicodeCharCode) {
+ map[+charCode] = unicodeCharCode;
+ });
+ }
+ this.toFontChar = map;
+ } else {
+ const glyphsUnicodeMap = getGlyphsUnicode();
+ const map = [];
+ this.toUnicode.forEach((charCode, unicodeCharCode) => {
+ if (!this.composite) {
+ const glyphName = this.differences[charCode] || this.defaultEncoding[charCode];
+ const unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);
+ if (unicode !== -1) {
+ unicodeCharCode = unicode;
+ }
+ }
+ map[+charCode] = unicodeCharCode;
+ });
+ if (this.composite && this.toUnicode instanceof IdentityToUnicodeMap) {
+ if (/Tahoma|Verdana/i.test(name)) {
+ applyStandardFontGlyphMap(map, getGlyphMapForStandardFonts());
+ }
+ }
+ this.toFontChar = map;
+ }
+ amendFallbackToUnicode(properties);
+ this.loadedName = fontName.split("-", 1)[0];
+ }
+ checkAndRepair(name, font, properties) {
+ const VALID_TABLES = ["OS/2", "cmap", "head", "hhea", "hmtx", "maxp", "name", "post", "loca", "glyf", "fpgm", "prep", "cvt ", "CFF "];
+ function readTables(file, numTables) {
+ const tables = Object.create(null);
+ tables["OS/2"] = null;
+ tables.cmap = null;
+ tables.head = null;
+ tables.hhea = null;
+ tables.hmtx = null;
+ tables.maxp = null;
+ tables.name = null;
+ tables.post = null;
+ for (let i = 0; i < numTables; i++) {
+ const table = readTableEntry(file);
+ if (!VALID_TABLES.includes(table.tag)) {
+ continue;
+ }
+ if (table.length === 0) {
+ continue;
+ }
+ tables[table.tag] = table;
+ }
+ return tables;
+ }
+ function readTableEntry(file) {
+ const tag = file.getString(4);
+ const checksum = file.getInt32() >>> 0;
+ const offset = file.getInt32() >>> 0;
+ const length = file.getInt32() >>> 0;
+ const previousPosition = file.pos;
+ file.pos = file.start || 0;
+ file.skip(offset);
+ const data = file.getBytes(length);
+ file.pos = previousPosition;
+ if (tag === "head") {
+ data[8] = data[9] = data[10] = data[11] = 0;
+ data[17] |= 0x20;
+ }
+ const view = tag === "CFF " ? null : new DataView(data.buffer, data.byteOffset, data.byteLength);
+ return {
+ tag,
+ checksum,
+ length,
+ offset,
+ data,
+ view
+ };
+ }
+ function readOpenTypeHeader(ttf) {
+ return {
+ version: ttf.getString(4),
+ numTables: ttf.getUint16(),
+ searchRange: ttf.getUint16(),
+ entrySelector: ttf.getUint16(),
+ rangeShift: ttf.getUint16()
+ };
+ }
+ function readTrueTypeCollectionHeader(ttc) {
+ const ttcTag = ttc.getString(4);
+ assert(ttcTag === "ttcf", "Must be a TrueType Collection font.");
+ const majorVersion = ttc.getUint16();
+ const minorVersion = ttc.getUint16();
+ const numFonts = ttc.getInt32() >>> 0;
+ const offsetTable = [];
+ for (let i = 0; i < numFonts; i++) {
+ offsetTable.push(ttc.getInt32() >>> 0);
+ }
+ const header = {
+ ttcTag,
+ majorVersion,
+ minorVersion,
+ numFonts,
+ offsetTable
+ };
+ switch (majorVersion) {
+ case 1:
+ return header;
+ case 2:
+ header.dsigTag = ttc.getInt32() >>> 0;
+ header.dsigLength = ttc.getInt32() >>> 0;
+ header.dsigOffset = ttc.getInt32() >>> 0;
+ return header;
+ }
+ throw new FormatError(`Invalid TrueType Collection majorVersion: ${majorVersion}.`);
+ }
+ function readTrueTypeCollectionData(ttc, fontName) {
+ const {
+ numFonts,
+ offsetTable
+ } = readTrueTypeCollectionHeader(ttc);
+ const fontNameParts = fontName.split("+");
+ let fallbackData;
+ for (let i = 0; i < numFonts; i++) {
+ ttc.pos = (ttc.start || 0) + offsetTable[i];
+ const potentialHeader = readOpenTypeHeader(ttc);
+ const potentialTables = readTables(ttc, potentialHeader.numTables);
+ if (!potentialTables.name) {
+ throw new FormatError('TrueType Collection font must contain a "name" table.');
+ }
+ const [nameTable] = readNameTable(potentialTables.name);
+ for (const nameArr of nameTable) {
+ for (const entry of nameArr) {
+ const nameEntry = entry?.replaceAll(/\s/g, "");
+ if (!nameEntry) {
+ continue;
+ }
+ if (nameEntry === fontName) {
+ return {
+ header: potentialHeader,
+ tables: potentialTables
+ };
+ }
+ if (fontNameParts.length < 2) {
+ continue;
+ }
+ for (const part of fontNameParts) {
+ if (nameEntry === part) {
+ fallbackData = {
+ name: part,
+ header: potentialHeader,
+ tables: potentialTables
+ };
+ }
+ }
+ }
+ }
+ }
+ if (fallbackData) {
+ warn(`TrueType Collection does not contain "${fontName}" font, ` + `falling back to "${fallbackData.name}" font instead.`);
+ return {
+ header: fallbackData.header,
+ tables: fallbackData.tables
+ };
+ }
+ throw new FormatError(`TrueType Collection does not contain "${fontName}" font.`);
+ }
+ function readCmapTable(cmap, file, isSymbolicFont, hasEncoding) {
+ if (!cmap) {
+ warn("No cmap table available.");
+ return {
+ platformId: -1,
+ encodingId: -1,
+ mappings: [],
+ hasShortCmap: false
+ };
+ }
+ let segment;
+ let start = (file.start || 0) + cmap.offset;
+ file.pos = start;
+ file.skip(2);
+ const numTables = file.getUint16();
+ let potentialTable;
+ let canBreak = false;
+ for (let i = 0; i < numTables; i++) {
+ const platformId = file.getUint16();
+ const encodingId = file.getUint16();
+ const offset = file.getInt32() >>> 0;
+ let useTable = false;
+ if (potentialTable?.platformId === platformId && potentialTable?.encodingId === encodingId) {
+ continue;
+ }
+ if (platformId === 0 && (encodingId === 0 || encodingId === 1 || encodingId === 3)) {
+ useTable = true;
+ } else if (platformId === 1 && encodingId === 0) {
+ useTable = true;
+ } else if (platformId === 3 && encodingId === 1 && (hasEncoding || !potentialTable)) {
+ useTable = true;
+ if (!isSymbolicFont) {
+ canBreak = true;
+ }
+ } else if (isSymbolicFont && platformId === 3 && encodingId === 0) {
+ useTable = true;
+ let correctlySorted = true;
+ if (i < numTables - 1) {
+ const nextBytes = file.peekBytes(2),
+ nextPlatformId = int16(nextBytes[0], nextBytes[1]);
+ if (nextPlatformId < platformId) {
+ correctlySorted = false;
+ }
+ }
+ if (correctlySorted) {
+ canBreak = true;
+ }
+ }
+ if (useTable) {
+ potentialTable = {
+ platformId,
+ encodingId,
+ offset
+ };
+ }
+ if (canBreak) {
+ break;
+ }
+ }
+ if (potentialTable) {
+ file.pos = start + potentialTable.offset;
+ }
+ if (!potentialTable || file.peekByte() === -1) {
+ warn("Could not find a preferred cmap table.");
+ return {
+ platformId: -1,
+ encodingId: -1,
+ mappings: [],
+ hasShortCmap: false
+ };
+ }
+ const format = file.getUint16();
+ let hasShortCmap = false;
+ const mappings = [];
+ let j, glyphId;
+ if (format === 0) {
+ file.skip(2 + 2);
+ for (j = 0; j < 256; j++) {
+ const index = file.getByte();
+ if (!index) {
+ continue;
+ }
+ mappings.push({
+ charCode: j,
+ glyphId: index
+ });
+ }
+ hasShortCmap = true;
+ } else if (format === 2) {
+ file.skip(2 + 2);
+ const subHeaderKeys = [];
+ let maxSubHeaderKey = 0;
+ for (let i = 0; i < 256; i++) {
+ const subHeaderKey = file.getUint16() >> 3;
+ subHeaderKeys.push(subHeaderKey);
+ maxSubHeaderKey = Math.max(subHeaderKey, maxSubHeaderKey);
+ }
+ const subHeaders = [];
+ for (let i = 0; i <= maxSubHeaderKey; i++) {
+ subHeaders.push({
+ firstCode: file.getUint16(),
+ entryCount: file.getUint16(),
+ idDelta: signedInt16(file.getByte(), file.getByte()),
+ idRangePos: file.pos + file.getUint16()
+ });
+ }
+ for (let i = 0; i < 256; i++) {
+ if (subHeaderKeys[i] === 0) {
+ file.pos = subHeaders[0].idRangePos + 2 * i;
+ glyphId = file.getUint16();
+ mappings.push({
+ charCode: i,
+ glyphId
+ });
+ } else {
+ const s = subHeaders[subHeaderKeys[i]];
+ for (j = 0; j < s.entryCount; j++) {
+ const charCode = (i << 8) + j + s.firstCode;
+ file.pos = s.idRangePos + 2 * j;
+ glyphId = file.getUint16();
+ if (glyphId !== 0) {
+ glyphId = (glyphId + s.idDelta) % 65536;
+ }
+ mappings.push({
+ charCode,
+ glyphId
+ });
+ }
+ }
+ }
+ } else if (format === 4) {
+ file.skip(2 + 2);
+ const segCount = file.getUint16() >> 1;
+ file.skip(6);
+ const segments = [];
+ let segIndex;
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segments.push({
+ end: file.getUint16()
+ });
+ }
+ file.skip(2);
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segments[segIndex].start = file.getUint16();
+ }
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segments[segIndex].delta = file.getUint16();
+ }
+ let offsetsCount = 0,
+ offsetIndex;
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segment = segments[segIndex];
+ const rangeOffset = file.getUint16();
+ if (!rangeOffset) {
+ segment.offsetIndex = -1;
+ continue;
+ }
+ offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
+ segment.offsetIndex = offsetIndex;
+ offsetsCount = Math.max(offsetsCount, offsetIndex + segment.end - segment.start + 1);
+ }
+ const offsets = [];
+ for (j = 0; j < offsetsCount; j++) {
+ offsets.push(file.getUint16());
+ }
+ for (segIndex = 0; segIndex < segCount; segIndex++) {
+ segment = segments[segIndex];
+ start = segment.start;
+ const end = segment.end;
+ const delta = segment.delta;
+ offsetIndex = segment.offsetIndex;
+ for (j = start; j <= end; j++) {
+ if (j === 0xffff) {
+ continue;
+ }
+ glyphId = offsetIndex < 0 ? j : offsets[offsetIndex + j - start];
+ glyphId = glyphId + delta & 0xffff;
+ mappings.push({
+ charCode: j,
+ glyphId
+ });
+ }
+ }
+ } else if (format === 6) {
+ file.skip(2 + 2);
+ const firstCode = file.getUint16();
+ const entryCount = file.getUint16();
+ for (j = 0; j < entryCount; j++) {
+ glyphId = file.getUint16();
+ const charCode = firstCode + j;
+ mappings.push({
+ charCode,
+ glyphId
+ });
+ }
+ } else if (format === 12) {
+ file.skip(2 + 4 + 4);
+ const nGroups = file.getInt32() >>> 0;
+ for (j = 0; j < nGroups; j++) {
+ const startCharCode = file.getInt32() >>> 0;
+ const endCharCode = file.getInt32() >>> 0;
+ let glyphCode = file.getInt32() >>> 0;
+ for (let charCode = startCharCode; charCode <= endCharCode; charCode++) {
+ mappings.push({
+ charCode,
+ glyphId: glyphCode++
+ });
+ }
+ }
+ } else {
+ warn("cmap table has unsupported format: " + format);
+ return {
+ platformId: -1,
+ encodingId: -1,
+ mappings: [],
+ hasShortCmap: false
+ };
+ }
+ const finalMappings = [],
+ seenCharCodes = new Set();
+ for (const map of mappings) {
+ const {
+ charCode
+ } = map;
+ if (seenCharCodes.has(charCode)) {
+ continue;
+ }
+ seenCharCodes.add(charCode);
+ finalMappings.push(map);
+ }
+ return {
+ platformId: potentialTable.platformId,
+ encodingId: potentialTable.encodingId,
+ mappings: finalMappings.sort((a, b) => a.charCode - b.charCode),
+ hasShortCmap
+ };
+ }
+ function sanitizeMetrics(file, header, metrics, headTable, numGlyphs, dupFirstEntry) {
+ if (!header) {
+ if (metrics) {
+ metrics.data = null;
+ }
+ return;
+ }
+ file.pos = (file.start || 0) + header.offset;
+ file.pos += 4;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ file.pos += 2;
+ const caretOffset = file.getUint16();
+ file.pos += 8;
+ file.pos += 2;
+ let numOfMetrics = file.getUint16();
+ if (caretOffset !== 0) {
+ const macStyle = int16(headTable.data[44], headTable.data[45]);
+ if (!(macStyle & 2)) {
+ header.data[22] = 0;
+ header.data[23] = 0;
+ }
+ }
+ if (numOfMetrics > numGlyphs) {
+ info(`The numOfMetrics (${numOfMetrics}) should not be ` + `greater than the numGlyphs (${numGlyphs}).`);
+ numOfMetrics = numGlyphs;
+ header.data[34] = (numOfMetrics & 0xff00) >> 8;
+ header.data[35] = numOfMetrics & 0x00ff;
+ }
+ const numOfSidebearings = numGlyphs - numOfMetrics;
+ const numMissing = numOfSidebearings - (metrics.length - numOfMetrics * 4 >> 1);
+ if (numMissing > 0) {
+ const entries = new Uint8Array(metrics.length + numMissing * 2);
+ entries.set(metrics.data);
+ if (dupFirstEntry) {
+ entries[metrics.length] = metrics.data[2];
+ entries[metrics.length + 1] = metrics.data[3];
+ }
+ metrics.data = entries;
+ }
+ }
+ function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, hintsValid) {
+ const glyphProfile = {
+ length: 0,
+ sizeOfInstructions: 0
+ };
+ if (sourceStart < 0 || sourceStart >= source.length || sourceEnd > source.length || sourceEnd - sourceStart <= 12) {
+ return glyphProfile;
+ }
+ const glyf = source.subarray(sourceStart, sourceEnd);
+ const xMin = signedInt16(glyf[2], glyf[3]);
+ const yMin = signedInt16(glyf[4], glyf[5]);
+ const xMax = signedInt16(glyf[6], glyf[7]);
+ const yMax = signedInt16(glyf[8], glyf[9]);
+ if (xMin > xMax) {
+ writeSignedInt16(glyf, 2, xMax);
+ writeSignedInt16(glyf, 6, xMin);
+ }
+ if (yMin > yMax) {
+ writeSignedInt16(glyf, 4, yMax);
+ writeSignedInt16(glyf, 8, yMin);
+ }
+ const contoursCount = signedInt16(glyf[0], glyf[1]);
+ if (contoursCount < 0) {
+ if (contoursCount < -1) {
+ return glyphProfile;
+ }
+ dest.set(glyf, destStart);
+ glyphProfile.length = glyf.length;
+ return glyphProfile;
+ }
+ let i,
+ j = 10,
+ flagsCount = 0;
+ for (i = 0; i < contoursCount; i++) {
+ const endPoint = glyf[j] << 8 | glyf[j + 1];
+ flagsCount = endPoint + 1;
+ j += 2;
+ }
+ const instructionsStart = j;
+ const instructionsLength = glyf[j] << 8 | glyf[j + 1];
+ glyphProfile.sizeOfInstructions = instructionsLength;
+ j += 2 + instructionsLength;
+ const instructionsEnd = j;
+ let coordinatesLength = 0;
+ for (i = 0; i < flagsCount; i++) {
+ const flag = glyf[j++];
+ if (flag & 0xc0) {
+ glyf[j - 1] = flag & 0x3f;
+ }
+ let xLength = 2;
+ if (flag & 2) {
+ xLength = 1;
+ } else if (flag & 16) {
+ xLength = 0;
+ }
+ let yLength = 2;
+ if (flag & 4) {
+ yLength = 1;
+ } else if (flag & 32) {
+ yLength = 0;
+ }
+ const xyLength = xLength + yLength;
+ coordinatesLength += xyLength;
+ if (flag & 8) {
+ const repeat = glyf[j++];
+ if (repeat === 0) {
+ glyf[j - 1] ^= 8;
+ }
+ i += repeat;
+ coordinatesLength += repeat * xyLength;
+ }
+ }
+ if (coordinatesLength === 0) {
+ return glyphProfile;
+ }
+ let glyphDataLength = j + coordinatesLength;
+ if (glyphDataLength > glyf.length) {
+ return glyphProfile;
+ }
+ if (!hintsValid && instructionsLength > 0) {
+ dest.set(glyf.subarray(0, instructionsStart), destStart);
+ dest.set([0, 0], destStart + instructionsStart);
+ dest.set(glyf.subarray(instructionsEnd, glyphDataLength), destStart + instructionsStart + 2);
+ glyphDataLength -= instructionsLength;
+ if (glyf.length - glyphDataLength > 3) {
+ glyphDataLength = glyphDataLength + 3 & ~3;
+ }
+ glyphProfile.length = glyphDataLength;
+ return glyphProfile;
+ }
+ if (glyf.length - glyphDataLength > 3) {
+ glyphDataLength = glyphDataLength + 3 & ~3;
+ dest.set(glyf.subarray(0, glyphDataLength), destStart);
+ glyphProfile.length = glyphDataLength;
+ return glyphProfile;
+ }
+ dest.set(glyf, destStart);
+ glyphProfile.length = glyf.length;
+ return glyphProfile;
+ }
+ function sanitizeHead(head, numGlyphs, locaLength) {
+ const {
+ data,
+ view
+ } = head;
+ const version = view.getInt32(0);
+ if (version >> 16 !== 1) {
+ info("Attempting to fix invalid version in head table: " + version);
+ view.setInt32(0, 0x00010000);
+ }
+ const indexToLocFormat = signedInt16(data[50], data[51]);
+ if (indexToLocFormat < 0 || indexToLocFormat > 1) {
+ info("Attempting to fix invalid indexToLocFormat in head table: " + indexToLocFormat);
+ const numGlyphsPlusOne = numGlyphs + 1;
+ if (locaLength === numGlyphsPlusOne << 1) {
+ data[50] = 0;
+ data[51] = 0;
+ } else if (locaLength === numGlyphsPlusOne << 2) {
+ data[50] = 0;
+ data[51] = 1;
+ } else {
+ throw new FormatError("Could not fix indexToLocFormat: " + indexToLocFormat);
+ }
+ }
+ }
+ function sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions) {
+ let itemSize, itemDecode, itemEncode;
+ if (isGlyphLocationsLong) {
+ itemSize = 4;
+ itemDecode = function fontItemDecodeLong(data, offset) {
+ return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
+ };
+ itemEncode = function fontItemEncodeLong(data, offset, value) {
+ data[offset] = value >>> 24 & 0xff;
+ data[offset + 1] = value >> 16 & 0xff;
+ data[offset + 2] = value >> 8 & 0xff;
+ data[offset + 3] = value & 0xff;
+ };
+ } else {
+ itemSize = 2;
+ itemDecode = function fontItemDecode(data, offset) {
+ return data[offset] << 9 | data[offset + 1] << 1;
+ };
+ itemEncode = function fontItemEncode(data, offset, value) {
+ data[offset] = value >> 9 & 0xff;
+ data[offset + 1] = value >> 1 & 0xff;
+ };
+ }
+ const numGlyphsOut = dupFirstEntry ? numGlyphs + 1 : numGlyphs;
+ const locaDataSize = itemSize * (1 + numGlyphsOut);
+ const locaData = new Uint8Array(locaDataSize);
+ locaData.set(loca.data.subarray(0, locaDataSize));
+ loca.data = locaData;
+ const oldGlyfData = glyf.data;
+ const oldGlyfDataLength = oldGlyfData.length;
+ const newGlyfData = new Uint8Array(oldGlyfDataLength);
+ let i, j;
+ const locaEntries = [];
+ for (i = 0, j = 0; i < numGlyphs + 1; i++, j += itemSize) {
+ let offset = itemDecode(locaData, j);
+ if (offset > oldGlyfDataLength) {
+ offset = oldGlyfDataLength;
+ }
+ locaEntries.push({
+ index: i,
+ offset,
+ endOffset: 0
+ });
+ }
+ locaEntries.sort((a, b) => a.offset - b.offset);
+ for (i = 0; i < numGlyphs; i++) {
+ locaEntries[i].endOffset = locaEntries[i + 1].offset;
+ }
+ locaEntries.sort((a, b) => a.index - b.index);
+ for (i = 0; i < numGlyphs; i++) {
+ const {
+ offset,
+ endOffset
+ } = locaEntries[i];
+ if (offset !== 0 || endOffset !== 0) {
+ break;
+ }
+ const nextOffset = locaEntries[i + 1].offset;
+ if (nextOffset === 0) {
+ continue;
+ }
+ locaEntries[i].endOffset = nextOffset;
+ break;
+ }
+ const last = locaEntries.at(-2);
+ if (last.offset !== 0 && last.endOffset === 0) {
+ last.endOffset = oldGlyfDataLength;
+ }
+ const droppedGlyphs = pruneCompositeGlyphCycles(oldGlyfData, locaEntries, numGlyphs);
+ const missingGlyphs = Object.create(null);
+ let writeOffset = 0;
+ itemEncode(locaData, 0, writeOffset);
+ for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
+ const glyphProfile = droppedGlyphs.has(i) ? {
+ length: 0,
+ sizeOfInstructions: 0
+ } : sanitizeGlyph(oldGlyfData, locaEntries[i].offset, locaEntries[i].endOffset, newGlyfData, writeOffset, hintsValid);
+ const newLength = glyphProfile.length;
+ if (newLength === 0) {
+ missingGlyphs[i] = true;
+ }
+ if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) {
+ maxSizeOfInstructions = glyphProfile.sizeOfInstructions;
+ }
+ writeOffset += newLength;
+ itemEncode(locaData, j, writeOffset);
+ }
+ if (writeOffset === 0) {
+ const simpleGlyph = new Uint8Array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
+ for (i = 0, j = itemSize; i < numGlyphsOut; i++, j += itemSize) {
+ itemEncode(locaData, j, simpleGlyph.length);
+ }
+ glyf.data = simpleGlyph;
+ } else if (dupFirstEntry) {
+ const firstEntryLength = itemDecode(locaData, itemSize);
+ if (newGlyfData.length > firstEntryLength + writeOffset) {
+ glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);
+ } else {
+ glyf.data = new Uint8Array(firstEntryLength + writeOffset);
+ glyf.data.set(newGlyfData.subarray(0, writeOffset));
+ }
+ glyf.data.set(newGlyfData.subarray(0, firstEntryLength), writeOffset);
+ itemEncode(loca.data, locaData.length - itemSize, writeOffset + firstEntryLength);
+ } else {
+ glyf.data = newGlyfData.subarray(0, writeOffset);
+ }
+ return {
+ missingGlyphs,
+ maxSizeOfInstructions
+ };
+ }
+ function readPostScriptTable(post, propertiesObj, maxpNumGlyphs) {
+ const start = (font.start || 0) + post.offset;
+ font.pos = start;
+ const length = post.length,
+ end = start + length;
+ const version = font.getInt32();
+ font.skip(28);
+ let glyphNames;
+ let valid = true;
+ let i;
+ switch (version) {
+ case 0x00010000:
+ glyphNames = MacStandardGlyphOrdering;
+ break;
+ case 0x00020000:
+ const numGlyphs = font.getUint16();
+ if (numGlyphs !== maxpNumGlyphs) {
+ valid = false;
+ break;
+ }
+ const glyphNameIndexes = [];
+ for (i = 0; i < numGlyphs; ++i) {
+ const index = font.getUint16();
+ if (index >= 32768) {
+ valid = false;
+ break;
+ }
+ glyphNameIndexes.push(index);
+ }
+ if (!valid) {
+ break;
+ }
+ const customNames = [];
+ while (font.pos < end) {
+ const strLen = font.getByte(),
+ str = font.getString(strLen);
+ customNames.push(str);
+ }
+ glyphNames = [];
+ for (i = 0; i < numGlyphs; ++i) {
+ const j = glyphNameIndexes[i];
+ if (j < 258) {
+ glyphNames.push(MacStandardGlyphOrdering[j]);
+ continue;
+ }
+ glyphNames.push(customNames[j - 258]);
+ }
+ break;
+ case 0x00030000:
+ break;
+ default:
+ warn("Unknown/unsupported post table version " + version);
+ valid = false;
+ if (propertiesObj.defaultEncoding) {
+ glyphNames = propertiesObj.defaultEncoding;
+ }
+ break;
+ }
+ propertiesObj.glyphNames = glyphNames;
+ return valid;
+ }
+ function readNameTable(nameTable) {
+ const start = (font.start || 0) + nameTable.offset;
+ font.pos = start;
+ const names = [[], []],
+ records = [];
+ const length = nameTable.length,
+ end = start + length;
+ const format = font.getUint16();
+ const FORMAT_0_HEADER_LENGTH = 6;
+ if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
+ return [names, records];
+ }
+ const numRecords = font.getUint16();
+ const stringsStart = font.getUint16();
+ const NAME_RECORD_LENGTH = 12;
+ let i, ii;
+ for (i = 0; i < numRecords && font.pos + NAME_RECORD_LENGTH <= end; i++) {
+ const r = {
+ platform: font.getUint16(),
+ encoding: font.getUint16(),
+ language: font.getUint16(),
+ name: font.getUint16(),
+ length: font.getUint16(),
+ offset: font.getUint16()
+ };
+ if (isMacNameRecord(r) || isWinNameRecord(r)) {
+ records.push(r);
+ }
+ }
+ for (i = 0, ii = records.length; i < ii; i++) {
+ const record = records[i];
+ if (record.length <= 0) {
+ continue;
+ }
+ const pos = start + stringsStart + record.offset;
+ if (pos + record.length > end) {
+ continue;
+ }
+ font.pos = pos;
+ const nameIndex = record.name;
+ if (record.encoding) {
+ let str = "";
+ for (let j = 0, jj = record.length; j < jj; j += 2) {
+ str += String.fromCharCode(font.getUint16());
+ }
+ names[1][nameIndex] = str;
+ } else {
+ names[0][nameIndex] = font.getString(record.length);
+ }
+ }
+ return [names, records];
+ }
+ const TTOpsStackDeltas = [0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1, 1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1, 0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2, 0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1, -999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];
+ function sanitizeTTProgram(table, ttContext) {
+ let data = table.data;
+ let i = 0,
+ j,
+ n,
+ b,
+ funcId,
+ pc,
+ lastEndf = 0,
+ lastDeff = 0;
+ const stack = [];
+ const callstack = [];
+ const functionsCalled = [];
+ let tooComplexToFollowFunctions = ttContext.tooComplexToFollowFunctions;
+ let inFDEF = false,
+ ifLevel = 0,
+ inELSE = 0;
+ for (let ii = data.length; i < ii;) {
+ const op = data[i++];
+ if (op === 0x40) {
+ n = data[i++];
+ if (inFDEF || inELSE) {
+ i += n;
+ } else {
+ for (j = 0; j < n; j++) {
+ stack.push(data[i++]);
+ }
+ }
+ } else if (op === 0x41) {
+ n = data[i++];
+ if (inFDEF || inELSE) {
+ i += n * 2;
+ } else {
+ for (j = 0; j < n; j++) {
+ b = data[i++];
+ stack.push(signedInt16(b, data[i++]));
+ }
+ }
+ } else if ((op & 0xf8) === 0xb0) {
+ n = op - 0xb0 + 1;
+ if (inFDEF || inELSE) {
+ i += n;
+ } else {
+ for (j = 0; j < n; j++) {
+ stack.push(data[i++]);
+ }
+ }
+ } else if ((op & 0xf8) === 0xb8) {
+ n = op - 0xb8 + 1;
+ if (inFDEF || inELSE) {
+ i += n * 2;
+ } else {
+ for (j = 0; j < n; j++) {
+ b = data[i++];
+ stack.push(signedInt16(b, data[i++]));
+ }
+ }
+ } else if (op === 0x2b && !tooComplexToFollowFunctions) {
+ if (!inFDEF && !inELSE) {
+ funcId = stack.at(-1);
+ if (isNaN(funcId)) {
+ info("TT: CALL empty stack (or invalid entry).");
+ } else {
+ ttContext.functionsUsed[funcId] = true;
+ if (funcId in ttContext.functionsStackDeltas) {
+ const newStackLength = stack.length + ttContext.functionsStackDeltas[funcId];
+ if (newStackLength < 0) {
+ warn("TT: CALL invalid functions stack delta.");
+ ttContext.hintsValid = false;
+ return;
+ }
+ stack.length = newStackLength;
+ } else if (funcId in ttContext.functionsDefined && !functionsCalled.includes(funcId)) {
+ callstack.push({
+ data,
+ i,
+ stackTop: stack.length - 1
+ });
+ functionsCalled.push(funcId);
+ pc = ttContext.functionsDefined[funcId];
+ if (!pc) {
+ warn("TT: CALL non-existent function");
+ ttContext.hintsValid = false;
+ return;
+ }
+ data = pc.data;
+ i = pc.i;
+ }
+ }
+ }
+ } else if (op === 0x2c && !tooComplexToFollowFunctions) {
+ if (inFDEF || inELSE) {
+ warn("TT: nested FDEFs not allowed");
+ tooComplexToFollowFunctions = true;
+ }
+ inFDEF = true;
+ lastDeff = i;
+ funcId = stack.pop();
+ ttContext.functionsDefined[funcId] = {
+ data,
+ i
+ };
+ } else if (op === 0x2d) {
+ if (inFDEF) {
+ inFDEF = false;
+ lastEndf = i;
+ } else {
+ pc = callstack.pop();
+ if (!pc) {
+ warn("TT: ENDF bad stack");
+ ttContext.hintsValid = false;
+ return;
+ }
+ funcId = functionsCalled.pop();
+ data = pc.data;
+ i = pc.i;
+ ttContext.functionsStackDeltas[funcId] = stack.length - pc.stackTop;
+ }
+ } else if (op === 0x89) {
+ if (inFDEF || inELSE) {
+ warn("TT: nested IDEFs not allowed");
+ tooComplexToFollowFunctions = true;
+ }
+ inFDEF = true;
+ lastDeff = i;
+ } else if (op === 0x58) {
+ ++ifLevel;
+ } else if (op === 0x1b) {
+ inELSE = ifLevel;
+ } else if (op === 0x59) {
+ if (inELSE === ifLevel) {
+ inELSE = 0;
+ }
+ --ifLevel;
+ } else if (op === 0x1c) {
+ if (!inFDEF && !inELSE) {
+ const offset = stack.at(-1);
+ if (offset > 0) {
+ i += offset - 1;
+ }
+ }
+ }
+ if (!inFDEF && !inELSE) {
+ let stackDelta = 0;
+ if (op <= 0x8e) {
+ stackDelta = TTOpsStackDeltas[op];
+ } else if (op >= 0xc0 && op <= 0xdf) {
+ stackDelta = -1;
+ } else if (op >= 0xe0) {
+ stackDelta = -2;
+ }
+ if (op >= 0x71 && op <= 0x75) {
+ n = stack.pop();
+ if (!isNaN(n)) {
+ stackDelta = -n * 2;
+ }
+ }
+ while (stackDelta < 0 && stack.length > 0) {
+ stack.pop();
+ stackDelta++;
+ }
+ while (stackDelta > 0) {
+ stack.push(NaN);
+ stackDelta--;
+ }
+ }
+ }
+ ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
+ const content = [data];
+ if (i > data.length) {
+ content.push(new Uint8Array(i - data.length));
+ }
+ if (lastDeff > lastEndf) {
+ warn("TT: complementing a missing function tail");
+ content.push(new Uint8Array([0x22, 0x2d]));
+ }
+ foldTTTable(table, content);
+ }
+ function checkInvalidFunctions(ttContext, maxFunctionDefs) {
+ if (ttContext.tooComplexToFollowFunctions) {
+ return;
+ }
+ if (ttContext.functionsDefined.length > maxFunctionDefs) {
+ warn("TT: more functions defined than expected");
+ ttContext.hintsValid = false;
+ return;
+ }
+ for (let j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
+ if (j > maxFunctionDefs) {
+ warn("TT: invalid function id: " + j);
+ ttContext.hintsValid = false;
+ return;
+ }
+ if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
+ warn("TT: undefined function: " + j);
+ ttContext.hintsValid = false;
+ return;
+ }
+ }
+ }
+ function foldTTTable(table, content) {
+ if (content.length > 1) {
+ let newLength = 0;
+ let j, jj;
+ for (j = 0, jj = content.length; j < jj; j++) {
+ newLength += content[j].length;
+ }
+ newLength = newLength + 3 & ~3;
+ const result = new Uint8Array(newLength);
+ let pos = 0;
+ for (j = 0, jj = content.length; j < jj; j++) {
+ result.set(content[j], pos);
+ pos += content[j].length;
+ }
+ table.data = result;
+ table.length = newLength;
+ }
+ }
+ function sanitizeTTPrograms(fpgm, prep, cvt, maxFunctionDefs) {
+ const ttContext = {
+ functionsDefined: [],
+ functionsUsed: [],
+ functionsStackDeltas: [],
+ tooComplexToFollowFunctions: false,
+ hintsValid: true
+ };
+ if (fpgm) {
+ sanitizeTTProgram(fpgm, ttContext);
+ }
+ if (prep) {
+ sanitizeTTProgram(prep, ttContext);
+ }
+ if (fpgm) {
+ checkInvalidFunctions(ttContext, maxFunctionDefs);
+ }
+ if (cvt && cvt.length & 1) {
+ const cvtData = new Uint8Array(cvt.length + 1);
+ cvtData.set(cvt.data);
+ cvt.data = cvtData;
+ }
+ return ttContext.hintsValid;
+ }
+ font = new Stream(new Uint8Array(font.getBytes()));
+ let header, tables;
+ if (isTrueTypeCollectionFile(font)) {
+ const ttcData = readTrueTypeCollectionData(font, this.name);
+ header = ttcData.header;
+ tables = ttcData.tables;
+ } else {
+ header = readOpenTypeHeader(font);
+ tables = readTables(font, header.numTables);
+ }
+ const isTrueType = !tables["CFF "];
+ let parsedCff = null;
+ if (!isTrueType) {
+ try {
+ parsedCff = new CFFParser(new Stream(tables["CFF "].data), properties, (/* inlined export .SEAC_ANALYSIS_ENABLED */true)).parse();
+ } catch {
+ warn("Failed to parse font " + properties.loadedName);
+ }
+ if (header.version === "OTTO" && (!properties.composite || properties.fontFileN === "FontFile3" && parsedCff?.isCIDFont) || !tables.head || !tables.hhea || !tables.maxp || !tables.post) {
+ return this.convert(name, new CFFFont(new Stream(tables["CFF "].data), properties), properties);
+ }
+ delete tables.glyf;
+ delete tables.loca;
+ delete tables.fpgm;
+ delete tables.prep;
+ delete tables["cvt "];
+ this.isOpenType = true;
+ } else {
+ if (!tables.loca) {
+ throw new FormatError('Required "loca" table is not found');
+ }
+ if (!tables.glyf) {
+ warn('Required "glyf" table is not found -- trying to recover.');
+ tables.glyf = {
+ tag: "glyf",
+ data: new Uint8Array(0)
+ };
+ }
+ this.isOpenType = false;
+ }
+ if (!tables.maxp) {
+ throw new FormatError('Required "maxp" table is not found');
+ }
+ let numGlyphsFromCFF;
+ if (parsedCff) {
+ try {
+ parsedCff.duplicateFirstGlyph();
+ tables["CFF "].data = new CFFCompiler(parsedCff).compile();
+ numGlyphsFromCFF = parsedCff.charStringCount;
+ } catch {
+ warn("Failed to compile font " + properties.loadedName);
+ }
+ }
+ font.pos = (font.start || 0) + tables.maxp.offset;
+ let version = font.getInt32();
+ const numGlyphs = numGlyphsFromCFF ?? font.getUint16();
+ if (version === 0x00005000 && tables.maxp.length !== 6) {
+ tables.maxp.data = tables.maxp.data.subarray(0, 6);
+ tables.maxp.length = 6;
+ }
+ if (version !== 0x00010000 && version !== 0x00005000) {
+ if (tables.maxp.length === 6) {
+ version = 0x0005000;
+ } else if (tables.maxp.length >= 32) {
+ version = 0x00010000;
+ } else {
+ throw new FormatError(`"maxp" table has a wrong version number`);
+ }
+ writeUint32(tables.maxp.data, 0, version);
+ }
+ let isGlyphLocationsLong = int16(tables.head.data[50], tables.head.data[51]);
+ if (tables.loca) {
+ const locaLength = isGlyphLocationsLong ? (numGlyphs + 1) * 4 : (numGlyphs + 1) * 2;
+ if (tables.loca.length !== locaLength) {
+ warn("Incorrect 'loca' table length -- attempting to fix it.");
+ const sortedTables = Object.values(tables).filter(Boolean).sort((a, b) => a.offset - b.offset);
+ const locaIndex = sortedTables.indexOf(tables.loca);
+ const nextTable = sortedTables[locaIndex + 1] || null;
+ if (nextTable && tables.loca.offset + locaLength < nextTable.offset) {
+ const previousPos = font.pos;
+ font.pos = font.start || 0;
+ font.skip(tables.loca.offset);
+ tables.loca.data = font.getBytes(locaLength);
+ tables.loca.length = locaLength;
+ font.pos = previousPos;
+ }
+ }
+ }
+ if (properties.scaleFactors?.length === numGlyphs && isTrueType) {
+ const {
+ scaleFactors
+ } = properties;
+ const glyphs = new GlyfTable({
+ glyfTable: tables.glyf.data,
+ isGlyphLocationsLong,
+ locaTable: tables.loca.data,
+ numGlyphs
+ });
+ glyphs.scale(scaleFactors);
+ const {
+ glyf,
+ loca,
+ isLocationLong
+ } = glyphs.write();
+ tables.glyf.data = glyf;
+ tables.loca.data = loca;
+ if (isLocationLong !== !!isGlyphLocationsLong) {
+ tables.head.data[50] = 0;
+ isGlyphLocationsLong = tables.head.data[51] = isLocationLong ? 1 : 0;
+ }
+ const metrics = tables.hmtx.data;
+ for (let i = 0; i < numGlyphs; i++) {
+ const j = 4 * i;
+ const advanceWidth = Math.round(scaleFactors[i] * int16(metrics[j], metrics[j + 1]));
+ metrics[j] = advanceWidth >> 8 & 0xff;
+ metrics[j + 1] = advanceWidth & 0xff;
+ const lsb = Math.round(scaleFactors[i] * signedInt16(metrics[j + 2], metrics[j + 3]));
+ writeSignedInt16(metrics, j + 2, lsb);
+ }
+ }
+ let numGlyphsOut = numGlyphs + 1;
+ let dupFirstEntry = true;
+ if (numGlyphsOut > 0xffff) {
+ dupFirstEntry = false;
+ numGlyphsOut = numGlyphs;
+ warn("Not enough space in glyfs to duplicate first glyph.");
+ }
+ let maxFunctionDefs = 0;
+ let maxSizeOfInstructions = 0;
+ if (version >= 0x00010000 && tables.maxp.length >= 32) {
+ font.pos += 8;
+ const maxZones = font.getUint16();
+ if (maxZones > 2) {
+ tables.maxp.data[14] = 0;
+ tables.maxp.data[15] = 2;
+ }
+ font.pos += 4;
+ maxFunctionDefs = font.getUint16();
+ font.pos += 4;
+ maxSizeOfInstructions = font.getUint16();
+ } else if (isTrueType && version === 0x00005000) {
+ const newMaxp = new Uint8Array(32);
+ writeUint32(newMaxp, 0, 0x00010000);
+ newMaxp[4] = numGlyphs >> 8 & 0xff;
+ newMaxp[5] = numGlyphs & 0xff;
+ newMaxp.fill(0xff, 6, 14);
+ newMaxp[15] = 2;
+ newMaxp[28] = 0xff;
+ newMaxp[29] = 0xff;
+ newMaxp[31] = 0x10;
+ tables.maxp.data = newMaxp;
+ tables.maxp.length = 32;
+ version = 0x00010000;
+ }
+ tables.maxp.data[4] = numGlyphsOut >> 8;
+ tables.maxp.data[5] = numGlyphsOut & 255;
+ const hintsValid = sanitizeTTPrograms(tables.fpgm, tables.prep, tables["cvt "], maxFunctionDefs);
+ if (!hintsValid) {
+ delete tables.fpgm;
+ delete tables.prep;
+ delete tables["cvt "];
+ }
+ sanitizeMetrics(font, tables.hhea, tables.hmtx, tables.head, numGlyphsOut, dupFirstEntry);
+ if (!tables.head) {
+ throw new FormatError('Required "head" table is not found');
+ }
+ sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
+ let missingGlyphs = Object.create(null);
+ if (isTrueType) {
+ const glyphsInfo = sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs, isGlyphLocationsLong, hintsValid, dupFirstEntry, maxSizeOfInstructions);
+ missingGlyphs = glyphsInfo.missingGlyphs;
+ if (version >= 0x00010000 && tables.maxp.length >= 32) {
+ tables.maxp.data[26] = glyphsInfo.maxSizeOfInstructions >> 8;
+ tables.maxp.data[27] = glyphsInfo.maxSizeOfInstructions & 255;
+ }
+ }
+ if (!tables.hhea) {
+ throw new FormatError('Required "hhea" table is not found');
+ }
+ if (tables.hhea.data[10] === 0 && tables.hhea.data[11] === 0) {
+ tables.hhea.data[10] = 0xff;
+ tables.hhea.data[11] = 0xff;
+ }
+ const metricsOverride = {
+ unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),
+ yMax: signedInt16(tables.head.data[42], tables.head.data[43]),
+ yMin: signedInt16(tables.head.data[38], tables.head.data[39]),
+ ascent: signedInt16(tables.hhea.data[4], tables.hhea.data[5]),
+ descent: signedInt16(tables.hhea.data[6], tables.hhea.data[7]),
+ lineGap: signedInt16(tables.hhea.data[8], tables.hhea.data[9])
+ };
+ this.ascent = metricsOverride.ascent / metricsOverride.unitsPerEm;
+ this.descent = metricsOverride.descent / metricsOverride.unitsPerEm;
+ this.lineGap = metricsOverride.lineGap / metricsOverride.unitsPerEm;
+ if (this.cssFontInfo?.lineHeight) {
+ this.lineHeight = this.cssFontInfo.metrics.lineHeight;
+ this.lineGap = this.cssFontInfo.metrics.lineGap;
+ } else {
+ this.lineHeight = this.ascent - this.descent + this.lineGap;
+ }
+ if (tables.post) {
+ readPostScriptTable(tables.post, properties, numGlyphs);
+ }
+ tables.post = {
+ tag: "post",
+ data: createPostTable(properties)
+ };
+ const charCodeToGlyphId = Object.create(null);
+ function hasGlyph(glyphId) {
+ return !missingGlyphs[glyphId];
+ }
+ if (properties.composite) {
+ const cidToGidMap = properties.cidToGidMap || [];
+ const isCidToGidMapEmpty = cidToGidMap.length === 0;
+ properties.cMap.forEach(function (charCode, cid) {
+ if (typeof cid === "string") {
+ cid = convertCidString(charCode, cid, true);
+ }
+ if (cid > 0xffff) {
+ throw new FormatError("Max size of CID is 65,535");
+ }
+ let glyphId = -1;
+ if (isCidToGidMapEmpty) {
+ glyphId = cid;
+ } else if (cidToGidMap[cid] !== undefined) {
+ glyphId = cidToGidMap[cid];
+ }
+ if (glyphId >= 0 && glyphId < numGlyphs && hasGlyph(glyphId)) {
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ });
+ } else {
+ const cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont, properties.hasEncoding);
+ const cmapPlatformId = cmapTable.platformId;
+ const cmapEncodingId = cmapTable.encodingId;
+ const cmapMappings = cmapTable.mappings;
+ let baseEncoding = [],
+ forcePostTable = false;
+ if (properties.hasEncoding && (properties.baseEncodingName === "MacRomanEncoding" || properties.baseEncodingName === "WinAnsiEncoding")) {
+ baseEncoding = getEncoding(properties.baseEncodingName);
+ }
+ if (properties.hasEncoding && !this.isSymbolicFont && (cmapPlatformId === 3 && cmapEncodingId === 1 || cmapPlatformId === 1 && cmapEncodingId === 0)) {
+ const glyphsUnicodeMap = getGlyphsUnicode();
+ for (let charCode = 0; charCode < 256; charCode++) {
+ let glyphName;
+ if (this.differences[charCode] !== undefined) {
+ glyphName = this.differences[charCode];
+ } else if (baseEncoding.length && baseEncoding[charCode] !== "") {
+ glyphName = baseEncoding[charCode];
+ } else {
+ glyphName = StandardEncoding[charCode];
+ }
+ if (!glyphName) {
+ continue;
+ }
+ const standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);
+ let unicodeOrCharCode;
+ if (cmapPlatformId === 3 && cmapEncodingId === 1) {
+ unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName];
+ } else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
+ unicodeOrCharCode = MacRomanEncoding.indexOf(standardGlyphName);
+ }
+ if (unicodeOrCharCode === undefined) {
+ if (!properties.glyphNames && properties.hasIncludedToUnicodeMap && !(this.toUnicode instanceof IdentityToUnicodeMap)) {
+ const unicode = this.toUnicode.get(charCode);
+ if (unicode) {
+ unicodeOrCharCode = unicode.codePointAt(0);
+ }
+ }
+ if (unicodeOrCharCode === undefined) {
+ continue;
+ }
+ }
+ for (const mapping of cmapMappings) {
+ if (mapping.charCode !== unicodeOrCharCode) {
+ continue;
+ }
+ charCodeToGlyphId[charCode] = mapping.glyphId;
+ break;
+ }
+ }
+ } else if (cmapPlatformId === 0) {
+ for (const mapping of cmapMappings) {
+ charCodeToGlyphId[mapping.charCode] = mapping.glyphId;
+ }
+ forcePostTable = true;
+ } else if (cmapPlatformId === 3 && cmapEncodingId === 0) {
+ for (const mapping of cmapMappings) {
+ let charCode = mapping.charCode;
+ if (charCode >= 0xf000 && charCode <= 0xf0ff) {
+ charCode &= 0xff;
+ }
+ charCodeToGlyphId[charCode] = mapping.glyphId;
+ }
+ } else {
+ for (const mapping of cmapMappings) {
+ charCodeToGlyphId[mapping.charCode] = mapping.glyphId;
+ }
+ }
+ if (properties.glyphNames && (baseEncoding.length || this.differences.length)) {
+ for (let i = 0; i < 256; ++i) {
+ if (!forcePostTable && charCodeToGlyphId[i] !== undefined) {
+ continue;
+ }
+ const glyphName = this.differences[i] || baseEncoding[i];
+ if (!glyphName) {
+ continue;
+ }
+ const glyphId = properties.glyphNames.indexOf(glyphName);
+ if (glyphId > 0 && hasGlyph(glyphId)) {
+ charCodeToGlyphId[i] = glyphId;
+ }
+ }
+ }
+ if (!properties.isInternalFont && charCodeToGlyphId[0] === undefined && hasGlyph(0)) {
+ charCodeToGlyphId[0] = 0;
+ }
+ }
+ if (charCodeToGlyphId.length === 0) {
+ charCodeToGlyphId[0] = 0;
+ }
+ const glyphZeroId = dupFirstEntry ? numGlyphsOut - 1 : 0;
+ if (!properties.cssFontInfo) {
+ const newMapping = adjustMapping(charCodeToGlyphId, hasGlyph, glyphZeroId, this.toUnicode);
+ this.toFontChar = newMapping.toFontChar;
+ tables.cmap = {
+ tag: "cmap",
+ data: createCmapTable(newMapping.charCodeToGlyphId, newMapping.toUnicodeExtraMap, numGlyphsOut)
+ };
+ if (!tables["OS/2"] || !validateOS2Table(tables["OS/2"], font)) {
+ tables["OS/2"] = {
+ tag: "OS/2",
+ data: createOS2Table(properties, newMapping.charCodeToGlyphId, metricsOverride)
+ };
+ }
+ }
+ if (!tables.name) {
+ tables.name = {
+ tag: "name",
+ data: createNameTable(this.name)
+ };
+ } else {
+ const [namePrototype, nameRecords] = readNameTable(tables.name);
+ tables.name.data = createNameTable(name, namePrototype);
+ this.psName = namePrototype[0][6] || null;
+ if (!properties.composite) {
+ adjustTrueTypeToUnicode(properties, this.isSymbolicFont, nameRecords);
+ }
+ }
+ const builder = new OpenTypeFileBuilder(header.version);
+ for (const tableTag in tables) {
+ builder.addTable(tableTag, tables[tableTag].data);
+ }
+ return builder.toArray();
+ }
+ convert(fontName, font, properties) {
+ properties.fixedPitch = false;
+ if (properties.builtInEncoding) {
+ adjustType1ToUnicode(properties, properties.builtInEncoding);
+ }
+ const glyphZeroId = font instanceof CFFFont ? font.numGlyphs - 1 : 1;
+ const mapping = font.getGlyphMapping(properties);
+ let newMapping = null;
+ let newCharCodeToGlyphId = mapping;
+ let toUnicodeExtraMap = null;
+ if (!properties.cssFontInfo) {
+ newMapping = adjustMapping(mapping, font.hasGlyphId.bind(font), glyphZeroId, this.toUnicode);
+ this.toFontChar = newMapping.toFontChar;
+ newCharCodeToGlyphId = newMapping.charCodeToGlyphId;
+ toUnicodeExtraMap = newMapping.toUnicodeExtraMap;
+ }
+ const numGlyphs = font.numGlyphs;
+ function getCharCodes(charCodeToGlyphId, glyphId) {
+ let charCodes = null;
+ for (const charCode in charCodeToGlyphId) {
+ if (glyphId === charCodeToGlyphId[charCode]) {
+ (charCodes ||= []).push(charCode | 0);
+ }
+ }
+ return charCodes;
+ }
+ function createCharCode(charCodeToGlyphId, glyphId) {
+ for (const charCode in charCodeToGlyphId) {
+ if (glyphId === charCodeToGlyphId[charCode]) {
+ return charCode | 0;
+ }
+ }
+ newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] = glyphId;
+ return newMapping.nextAvailableFontCharCode++;
+ }
+ const seacs = font.seacs;
+ if (newMapping && (/* inlined export .SEAC_ANALYSIS_ENABLED */true) && seacs?.length) {
+ const matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX;
+ const charset = font.getCharset();
+ const seacMap = Object.create(null);
+ for (let glyphId in seacs) {
+ glyphId |= 0;
+ const seac = seacs[glyphId];
+ const baseGlyphName = StandardEncoding[seac[2]];
+ const accentGlyphName = StandardEncoding[seac[3]];
+ const baseGlyphId = charset.indexOf(baseGlyphName);
+ const accentGlyphId = charset.indexOf(accentGlyphName);
+ if (baseGlyphId < 0 || accentGlyphId < 0) {
+ continue;
+ }
+ const accentOffset = {
+ x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],
+ y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5]
+ };
+ const charCodes = getCharCodes(mapping, glyphId);
+ if (!charCodes) {
+ continue;
+ }
+ for (const charCode of charCodes) {
+ const charCodeToGlyphId = newMapping.charCodeToGlyphId;
+ const baseFontCharCode = createCharCode(charCodeToGlyphId, baseGlyphId);
+ const accentFontCharCode = createCharCode(charCodeToGlyphId, accentGlyphId);
+ seacMap[charCode] = {
+ baseFontCharCode,
+ accentFontCharCode,
+ accentOffset
+ };
+ }
+ }
+ properties.seacMap = seacMap;
+ }
+ const unitsPerEm = properties.fontMatrix ? 1 / Math.max(...properties.fontMatrix.slice(0, 4).map(Math.abs)) : 1000;
+ const builder = new OpenTypeFileBuilder("\x4F\x54\x54\x4F");
+ builder.addTable("CFF ", font.data);
+ builder.addTable("OS/2", createOS2Table(properties, newCharCodeToGlyphId));
+ builder.addTable("cmap", createCmapTable(newCharCodeToGlyphId, toUnicodeExtraMap, numGlyphs));
+ builder.addTable("head", function fontTableHead() {
+ const dateArr = [0x00, 0x00, 0x00, 0x00, 0x9e, 0x0b, 0x7e, 0x27];
+ const head = new DataBuilder({
+ exactLength: 54
+ });
+ head.setArray([0x00, 0x01, 0x00, 0x00]);
+ head.setArray([0x00, 0x00, 0x10, 0x00]);
+ head.skip(4);
+ head.setArray([0x5f, 0x0f, 0x3c, 0xf5]);
+ head.skip(2);
+ head.setSafeInt16(unitsPerEm);
+ head.setArray(dateArr);
+ head.setArray(dateArr);
+ head.skip(2);
+ head.setSafeInt16(properties.descent);
+ head.setArray([0x0f, 0xff]);
+ head.setSafeInt16(properties.ascent);
+ head.setInt16(properties.italicAngle ? 2 : 0);
+ head.setArray([0x00, 0x11]);
+ head.skip(2 + 2 + 2);
+ return head.data;
+ }());
+ builder.addTable("hhea", function fontTableHhea() {
+ const hhea = new DataBuilder({
+ exactLength: 36
+ });
+ hhea.setArray([0x00, 0x01, 0x00, 0x00]);
+ hhea.setSafeInt16(properties.ascent);
+ hhea.setSafeInt16(properties.descent);
+ hhea.skip(2);
+ hhea.setArray([0xff, 0xff]);
+ hhea.skip(2 + 2 + 2);
+ hhea.setSafeInt16(properties.capHeight);
+ hhea.setSafeInt16(Math.tan(properties.italicAngle) * properties.xHeight);
+ hhea.skip(2 + 2 + 2 + 2 + 2 + 2);
+ hhea.setInt16(numGlyphs);
+ return hhea.data;
+ }());
+ builder.addTable("hmtx", function fontTableHmtx() {
+ const charstrings = font.charstrings;
+ const cffWidths = font.cff?.widths ?? null;
+ const hmtx = new DataBuilder({
+ exactLength: numGlyphs * 4
+ });
+ hmtx.skip(4);
+ for (let i = 1, ii = numGlyphs; i < ii; i++) {
+ let width = 0;
+ if (charstrings) {
+ width = charstrings[i - 1].width || 0;
+ } else if (cffWidths) {
+ width = Math.ceil(cffWidths[i] || 0);
+ }
+ hmtx.setInt16(width);
+ hmtx.skip(2);
+ }
+ return hmtx.data;
+ }());
+ builder.addTable("maxp", function fontTableMaxp() {
+ const maxp = new DataBuilder({
+ exactLength: 6
+ });
+ maxp.setArray([0x00, 0x00, 0x50, 0x00]);
+ maxp.setInt16(numGlyphs);
+ return maxp.data;
+ }());
+ builder.addTable("name", createNameTable(fontName));
+ builder.addTable("post", createPostTable(properties));
+ return builder.toArray();
+ }
+ get _spaceWidth() {
+ const possibleSpaceReplacements = ["space", "minus", "one", "i", "I"];
+ let width;
+ for (const glyphName of possibleSpaceReplacements) {
+ if (glyphName in this.widths) {
+ width = this.widths[glyphName];
+ break;
+ }
+ const glyphsUnicodeMap = getGlyphsUnicode();
+ const glyphUnicode = glyphsUnicodeMap[glyphName];
+ let charcode = 0;
+ if (this.composite && this.cMap.contains(glyphUnicode)) {
+ charcode = this.cMap.lookup(glyphUnicode);
+ if (typeof charcode === "string") {
+ charcode = convertCidString(glyphUnicode, charcode);
+ }
+ }
+ if (!charcode && this.toUnicode) {
+ charcode = this.toUnicode.charCodeOf(glyphUnicode);
+ }
+ if (charcode <= 0) {
+ charcode = glyphUnicode;
+ }
+ width = this.widths[charcode];
+ if (width) {
+ break;
+ }
+ }
+ return shadow(this, "_spaceWidth", width || this.defaultWidth);
+ }
+ _charToGlyph(charcode, isSpace = false) {
+ let glyph = this.#glyphCache.get(charcode);
+ if (glyph?.isSpace === isSpace) {
+ return glyph;
+ }
+ let fontCharCode, width, operatorListId;
+ let widthCode = charcode;
+ if (this.cMap?.contains(charcode)) {
+ widthCode = this.cMap.lookup(charcode);
+ if (typeof widthCode === "string") {
+ widthCode = convertCidString(charcode, widthCode);
+ }
+ }
+ width = this.widths[widthCode];
+ if (typeof width !== "number") {
+ width = this.defaultWidth;
+ }
+ const vmetric = this.vmetrics?.[widthCode] || this.defaultVMetrics;
+ let unicode = this.toUnicode.get(charcode) || charcode;
+ if (typeof unicode === "number") {
+ unicode = String.fromCharCode(unicode);
+ }
+ let isInFont = this.toFontChar[charcode] !== undefined;
+ fontCharCode = this.toFontChar[charcode] || charcode;
+ if (this.missingFile) {
+ const glyphName = this.differences[charcode] || this.defaultEncoding[charcode];
+ if ((glyphName === ".notdef" || glyphName === "") && this.type === "Type1") {
+ fontCharCode = 0x20;
+ if (glyphName === "") {
+ width ||= this._spaceWidth;
+ unicode = String.fromCharCode(fontCharCode);
+ }
+ }
+ fontCharCode = mapSpecialUnicodeValues(fontCharCode);
+ }
+ if (this.isType3Font) {
+ operatorListId = fontCharCode;
+ }
+ let accent = null;
+ if (this.seacMap?.[charcode]) {
+ isInFont = true;
+ const seac = this.seacMap[charcode];
+ fontCharCode = seac.baseFontCharCode;
+ accent = {
+ fontChar: String.fromCodePoint(seac.accentFontCharCode),
+ offset: seac.accentOffset
+ };
+ }
+ let fontChar = "";
+ if (typeof fontCharCode === "number") {
+ if (fontCharCode <= 0x10ffff) {
+ fontChar = String.fromCodePoint(fontCharCode);
+ } else {
+ warn(`charToGlyph - invalid fontCharCode: ${fontCharCode}`);
+ }
+ }
+ if (this.missingFile && this.vertical && fontChar.length === 1) {
+ const vertical = getVerticalPresentationForm()[fontChar.charCodeAt(0)];
+ if (vertical) {
+ fontChar = unicode = String.fromCharCode(vertical);
+ }
+ }
+ glyph = new fonts_Glyph(charcode, fontChar, unicode, accent, width, vmetric, operatorListId, isSpace, isInFont);
+ this.#glyphCache.set(charcode, glyph);
+ return glyph;
+ }
+ charsToGlyphs(chars) {
+ let glyphs = this.#charsCache.get(chars);
+ if (glyphs) {
+ return glyphs;
+ }
+ glyphs = [];
+ if (this.cMap) {
+ const c = Object.create(null),
+ ii = chars.length;
+ let i = 0;
+ while (i < ii) {
+ this.cMap.readCharCode(chars, i, c);
+ const {
+ charcode,
+ length
+ } = c;
+ i += length;
+ const glyph = this._charToGlyph(charcode, length === 1 && chars.charCodeAt(i - 1) === 0x20);
+ glyphs.push(glyph);
+ }
+ } else {
+ for (let i = 0, ii = chars.length; i < ii; ++i) {
+ const charcode = chars.charCodeAt(i);
+ const glyph = this._charToGlyph(charcode, charcode === 0x20);
+ glyphs.push(glyph);
+ }
+ }
+ this.#charsCache.set(chars, glyphs);
+ return glyphs;
+ }
+ getCharPositions(chars) {
+ const positions = [];
+ if (this.cMap) {
+ const c = Object.create(null);
+ let i = 0;
+ while (i < chars.length) {
+ this.cMap.readCharCode(chars, i, c);
+ const length = c.length;
+ positions.push([i, i + length]);
+ i += length;
+ }
+ } else {
+ for (let i = 0, ii = chars.length; i < ii; ++i) {
+ positions.push([i, i + 1]);
+ }
+ }
+ return positions;
+ }
+ get glyphCacheValues() {
+ return this.#glyphCache.values();
+ }
+ encodeString(str) {
+ const buffers = [];
+ const currentBuf = [];
+ const hasCurrentBufErrors = () => buffers.length % 2 === 1;
+ const getCharCode = this.toUnicode instanceof IdentityToUnicodeMap ? unicode => this.toUnicode.charCodeOf(unicode) : unicode => this.toUnicode.charCodeOf(String.fromCodePoint(unicode));
+ for (let i = 0, ii = str.length; i < ii; i++) {
+ const unicode = str.codePointAt(i);
+ if (unicode > 0xffff) {
+ i++;
+ }
+ if (this.toUnicode) {
+ const charCode = getCharCode(unicode);
+ if (charCode !== -1) {
+ if (hasCurrentBufErrors()) {
+ buffers.push(currentBuf.join(""));
+ currentBuf.length = 0;
+ }
+ const charCodeLength = this.cMap ? this.cMap.getCharCodeLength(charCode) : 1;
+ for (let j = charCodeLength - 1; j >= 0; j--) {
+ currentBuf.push(String.fromCharCode(charCode >> 8 * j & 0xff));
+ }
+ continue;
+ }
+ }
+ if (!hasCurrentBufErrors()) {
+ buffers.push(currentBuf.join(""));
+ currentBuf.length = 0;
+ }
+ currentBuf.push(String.fromCodePoint(unicode));
+ }
+ buffers.push(currentBuf.join(""));
+ return buffers;
+ }
+}
+class ErrorFont {
+ constructor(error) {
+ this.error = error;
+ this.loadedName = "g_font_error";
+ this.missingFile = true;
+ }
+ charsToGlyphs() {
+ return [];
+ }
+ encodeString(chars) {
+ return [chars];
+ }
+ exportData() {
+ return {
+ error: this.error
+ };
+ }
+}
+
+;// ./src/core/calibri_factors.js
+const CalibriBoldFactors = [1.3877, 1, 1, 1, 0.97801, 0.92482, 0.89552, 0.91133, 0.81988, 0.97566, 0.98152, 0.93548, 0.93548, 1.2798, 0.85284, 0.92794, 1, 0.96134, 1.54657, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.82845, 0.82845, 0.85284, 0.85284, 0.85284, 0.75859, 0.92138, 0.83908, 0.7762, 0.73293, 0.87289, 0.73133, 0.7514, 0.81921, 0.87356, 0.95958, 0.59526, 0.75727, 0.69225, 1.04924, 0.9121, 0.86943, 0.79795, 0.88198, 0.77958, 0.70864, 0.81055, 0.90399, 0.88653, 0.96017, 0.82577, 0.77892, 0.78257, 0.97507, 1.54657, 0.97507, 0.85284, 0.89552, 0.90176, 0.88762, 0.8785, 0.75241, 0.8785, 0.90518, 0.95015, 0.77618, 0.8785, 0.88401, 0.91916, 0.86304, 0.88401, 0.91488, 0.8785, 0.8801, 0.8785, 0.8785, 0.91343, 0.7173, 1.04106, 0.8785, 0.85075, 0.95794, 0.82616, 0.85162, 0.79492, 0.88331, 1.69808, 0.88331, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.7801, 0.89552, 1.24487, 1.13254, 1.12401, 0.96839, 0.85284, 0.68787, 0.70645, 0.85592, 0.90747, 1.01466, 1.0088, 0.90323, 1, 1.07463, 1, 0.91056, 0.75806, 1.19118, 0.96839, 0.78864, 0.82845, 0.84133, 0.75859, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.77539, 0.73293, 0.73133, 0.73133, 0.73133, 0.73133, 0.95958, 0.95958, 0.95958, 0.95958, 0.88506, 0.9121, 0.86943, 0.86943, 0.86943, 0.86943, 0.86943, 0.85284, 0.87508, 0.90399, 0.90399, 0.90399, 0.90399, 0.77892, 0.79795, 0.90807, 0.88762, 0.88762, 0.88762, 0.88762, 0.88762, 0.88762, 0.8715, 0.75241, 0.90518, 0.90518, 0.90518, 0.90518, 0.88401, 0.88401, 0.88401, 0.88401, 0.8785, 0.8785, 0.8801, 0.8801, 0.8801, 0.8801, 0.8801, 0.90747, 0.89049, 0.8785, 0.8785, 0.8785, 0.8785, 0.85162, 0.8785, 0.85162, 0.83908, 0.88762, 0.83908, 0.88762, 0.83908, 0.88762, 0.73293, 0.75241, 0.73293, 0.75241, 0.73293, 0.75241, 0.73293, 0.75241, 0.87289, 0.83016, 0.88506, 0.93125, 0.73133, 0.90518, 0.73133, 0.90518, 0.73133, 0.90518, 0.73133, 0.90518, 0.73133, 0.90518, 0.81921, 0.77618, 0.81921, 0.77618, 0.81921, 0.77618, 1, 1, 0.87356, 0.8785, 0.91075, 0.89608, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.76229, 0.90167, 0.59526, 0.91916, 1, 1, 0.86304, 0.69225, 0.88401, 1, 1, 0.70424, 0.79468, 0.91926, 0.88175, 0.70823, 0.94903, 0.9121, 0.8785, 1, 1, 0.9121, 0.8785, 0.87802, 0.88656, 0.8785, 0.86943, 0.8801, 0.86943, 0.8801, 0.86943, 0.8801, 0.87402, 0.89291, 0.77958, 0.91343, 1, 1, 0.77958, 0.91343, 0.70864, 0.7173, 0.70864, 0.7173, 0.70864, 0.7173, 0.70864, 0.7173, 1, 1, 0.81055, 0.75841, 0.81055, 1.06452, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.90399, 0.8785, 0.96017, 0.95794, 0.77892, 0.85162, 0.77892, 0.78257, 0.79492, 0.78257, 0.79492, 0.78257, 0.79492, 0.9297, 0.56892, 0.83908, 0.88762, 0.77539, 0.8715, 0.87508, 0.89049, 1, 1, 0.81055, 1.04106, 1.20528, 1.20528, 1, 1.15543, 0.70674, 0.98387, 0.94721, 1.33431, 1.45894, 0.95161, 1.06303, 0.83908, 0.80352, 0.57184, 0.6965, 0.56289, 0.82001, 0.56029, 0.81235, 1.02988, 0.83908, 0.7762, 0.68156, 0.80367, 0.73133, 0.78257, 0.87356, 0.86943, 0.95958, 0.75727, 0.89019, 1.04924, 0.9121, 0.7648, 0.86943, 0.87356, 0.79795, 0.78275, 0.81055, 0.77892, 0.9762, 0.82577, 0.99819, 0.84896, 0.95958, 0.77892, 0.96108, 1.01407, 0.89049, 1.02988, 0.94211, 0.96108, 0.8936, 0.84021, 0.87842, 0.96399, 0.79109, 0.89049, 1.00813, 1.02988, 0.86077, 0.87445, 0.92099, 0.84723, 0.86513, 0.8801, 0.75638, 0.85714, 0.78216, 0.79586, 0.87965, 0.94211, 0.97747, 0.78287, 0.97926, 0.84971, 1.02988, 0.94211, 0.8801, 0.94211, 0.84971, 0.73133, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90264, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90518, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90548, 1, 1, 1, 1, 1, 1, 0.96017, 0.95794, 0.96017, 0.95794, 0.96017, 0.95794, 0.77892, 0.85162, 1, 1, 0.89552, 0.90527, 1, 0.90363, 0.92794, 0.92794, 0.92794, 0.92794, 0.87012, 0.87012, 0.87012, 0.89552, 0.89552, 1.42259, 0.71143, 1.06152, 1, 1, 1.03372, 1.03372, 0.97171, 1.4956, 2.2807, 0.93835, 0.83406, 0.91133, 0.84107, 0.91133, 1, 1, 1, 0.72021, 1, 1.23108, 0.83489, 0.88525, 0.88525, 0.81499, 0.90527, 1.81055, 0.90527, 1.81055, 1.31006, 1.53711, 0.94434, 1.08696, 1, 0.95018, 0.77192, 0.85284, 0.90747, 1.17534, 0.69825, 0.9716, 1.37077, 0.90747, 0.90747, 0.85356, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.08004, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90727, 0.90727, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const CalibriBoldMetrics = {
+ lineHeight: 1.2207,
+ lineGap: 0.2207
+};
+const CalibriBoldItalicFactors = [1.3877, 1, 1, 1, 0.97801, 0.92482, 0.89552, 0.91133, 0.81988, 0.97566, 0.98152, 0.93548, 0.93548, 1.2798, 0.85284, 0.92794, 1, 0.96134, 1.56239, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.82845, 0.82845, 0.85284, 0.85284, 0.85284, 0.75859, 0.92138, 0.83908, 0.7762, 0.71805, 0.87289, 0.73133, 0.7514, 0.81921, 0.87356, 0.95958, 0.59526, 0.75727, 0.69225, 1.04924, 0.90872, 0.85938, 0.79795, 0.87068, 0.77958, 0.69766, 0.81055, 0.90399, 0.88653, 0.96068, 0.82577, 0.77892, 0.78257, 0.97507, 1.529, 0.97507, 0.85284, 0.89552, 0.90176, 0.94908, 0.86411, 0.74012, 0.86411, 0.88323, 0.95015, 0.86411, 0.86331, 0.88401, 0.91916, 0.86304, 0.88401, 0.9039, 0.86331, 0.86331, 0.86411, 0.86411, 0.90464, 0.70852, 1.04106, 0.86331, 0.84372, 0.95794, 0.82616, 0.84548, 0.79492, 0.88331, 1.69808, 0.88331, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.7801, 0.89552, 1.24487, 1.13254, 1.19129, 0.96839, 0.85284, 0.68787, 0.70645, 0.85592, 0.90747, 1.01466, 1.0088, 0.90323, 1, 1.07463, 1, 0.91056, 0.75806, 1.19118, 0.96839, 0.78864, 0.82845, 0.84133, 0.75859, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.83908, 0.77539, 0.71805, 0.73133, 0.73133, 0.73133, 0.73133, 0.95958, 0.95958, 0.95958, 0.95958, 0.88506, 0.90872, 0.85938, 0.85938, 0.85938, 0.85938, 0.85938, 0.85284, 0.87068, 0.90399, 0.90399, 0.90399, 0.90399, 0.77892, 0.79795, 0.90807, 0.94908, 0.94908, 0.94908, 0.94908, 0.94908, 0.94908, 0.85887, 0.74012, 0.88323, 0.88323, 0.88323, 0.88323, 0.88401, 0.88401, 0.88401, 0.88401, 0.8785, 0.86331, 0.86331, 0.86331, 0.86331, 0.86331, 0.86331, 0.90747, 0.89049, 0.86331, 0.86331, 0.86331, 0.86331, 0.84548, 0.86411, 0.84548, 0.83908, 0.94908, 0.83908, 0.94908, 0.83908, 0.94908, 0.71805, 0.74012, 0.71805, 0.74012, 0.71805, 0.74012, 0.71805, 0.74012, 0.87289, 0.79538, 0.88506, 0.92726, 0.73133, 0.88323, 0.73133, 0.88323, 0.73133, 0.88323, 0.73133, 0.88323, 0.73133, 0.88323, 0.81921, 0.86411, 0.81921, 0.86411, 0.81921, 0.86411, 1, 1, 0.87356, 0.86331, 0.91075, 0.8777, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.95958, 0.88401, 0.76467, 0.90167, 0.59526, 0.91916, 1, 1, 0.86304, 0.69225, 0.88401, 1, 1, 0.70424, 0.77312, 0.91926, 0.88175, 0.70823, 0.94903, 0.90872, 0.86331, 1, 1, 0.90872, 0.86331, 0.86906, 0.88116, 0.86331, 0.85938, 0.86331, 0.85938, 0.86331, 0.85938, 0.86331, 0.87402, 0.86549, 0.77958, 0.90464, 1, 1, 0.77958, 0.90464, 0.69766, 0.70852, 0.69766, 0.70852, 0.69766, 0.70852, 0.69766, 0.70852, 1, 1, 0.81055, 0.75841, 0.81055, 1.06452, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.90399, 0.86331, 0.96068, 0.95794, 0.77892, 0.84548, 0.77892, 0.78257, 0.79492, 0.78257, 0.79492, 0.78257, 0.79492, 0.9297, 0.56892, 0.83908, 0.94908, 0.77539, 0.85887, 0.87068, 0.89049, 1, 1, 0.81055, 1.04106, 1.20528, 1.20528, 1, 1.15543, 0.70088, 0.98387, 0.94721, 1.33431, 1.45894, 0.95161, 1.48387, 0.83908, 0.80352, 0.57118, 0.6965, 0.56347, 0.79179, 0.55853, 0.80346, 1.02988, 0.83908, 0.7762, 0.67174, 0.86036, 0.73133, 0.78257, 0.87356, 0.86441, 0.95958, 0.75727, 0.89019, 1.04924, 0.90872, 0.74889, 0.85938, 0.87891, 0.79795, 0.7957, 0.81055, 0.77892, 0.97447, 0.82577, 0.97466, 0.87179, 0.95958, 0.77892, 0.94252, 0.95612, 0.8753, 1.02988, 0.92733, 0.94252, 0.87411, 0.84021, 0.8728, 0.95612, 0.74081, 0.8753, 1.02189, 1.02988, 0.84814, 0.87445, 0.91822, 0.84723, 0.85668, 0.86331, 0.81344, 0.87581, 0.76422, 0.82046, 0.96057, 0.92733, 0.99375, 0.78022, 0.95452, 0.86015, 1.02988, 0.92733, 0.86331, 0.92733, 0.86015, 0.73133, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90631, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.88323, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.85174, 1, 1, 1, 1, 1, 1, 0.96068, 0.95794, 0.96068, 0.95794, 0.96068, 0.95794, 0.77892, 0.84548, 1, 1, 0.89552, 0.90527, 1, 0.90363, 0.92794, 0.92794, 0.92794, 0.89807, 0.87012, 0.87012, 0.87012, 0.89552, 0.89552, 1.42259, 0.71094, 1.06152, 1, 1, 1.03372, 1.03372, 0.97171, 1.4956, 2.2807, 0.92972, 0.83406, 0.91133, 0.83326, 0.91133, 1, 1, 1, 0.72021, 1, 1.23108, 0.83489, 0.88525, 0.88525, 0.81499, 0.90616, 1.81055, 0.90527, 1.81055, 1.3107, 1.53711, 0.94434, 1.08696, 1, 0.95018, 0.77192, 0.85284, 0.90747, 1.17534, 0.69825, 0.9716, 1.37077, 0.90747, 0.90747, 0.85356, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.08004, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90727, 0.90727, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const CalibriBoldItalicMetrics = {
+ lineHeight: 1.2207,
+ lineGap: 0.2207
+};
+const CalibriItalicFactors = [1.3877, 1, 1, 1, 1.17223, 1.1293, 0.89552, 0.91133, 0.80395, 1.02269, 1.15601, 0.91056, 0.91056, 1.2798, 0.85284, 0.89807, 1, 0.90861, 1.39543, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.96309, 0.96309, 0.85284, 0.85284, 0.85284, 0.83319, 0.88071, 0.8675, 0.81552, 0.72346, 0.85193, 0.73206, 0.7522, 0.81105, 0.86275, 0.90685, 0.6377, 0.77892, 0.75593, 1.02638, 0.89249, 0.84118, 0.77452, 0.85374, 0.75186, 0.67789, 0.79776, 0.88844, 0.85066, 0.94309, 0.77818, 0.7306, 0.76659, 1.10369, 1.38313, 1.10369, 1.06139, 0.89552, 0.8739, 0.9245, 0.9245, 0.83203, 0.9245, 0.85865, 1.09842, 0.9245, 0.9245, 1.03297, 1.07692, 0.90918, 1.03297, 0.94959, 0.9245, 0.92274, 0.9245, 0.9245, 1.02933, 0.77832, 1.20562, 0.9245, 0.8916, 0.98986, 0.86621, 0.89453, 0.79004, 0.94152, 1.77256, 0.94152, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.91729, 0.89552, 1.17889, 1.13254, 1.16359, 0.92098, 0.85284, 0.68787, 0.71353, 0.84737, 0.90747, 1.0088, 1.0044, 0.87683, 1, 1.09091, 1, 0.92229, 0.739, 1.15642, 0.92098, 0.76288, 0.80504, 0.80972, 0.75859, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.76318, 0.72346, 0.73206, 0.73206, 0.73206, 0.73206, 0.90685, 0.90685, 0.90685, 0.90685, 0.86477, 0.89249, 0.84118, 0.84118, 0.84118, 0.84118, 0.84118, 0.85284, 0.84557, 0.88844, 0.88844, 0.88844, 0.88844, 0.7306, 0.77452, 0.86331, 0.9245, 0.9245, 0.9245, 0.9245, 0.9245, 0.9245, 0.84843, 0.83203, 0.85865, 0.85865, 0.85865, 0.85865, 0.82601, 0.82601, 0.82601, 0.82601, 0.94469, 0.9245, 0.92274, 0.92274, 0.92274, 0.92274, 0.92274, 0.90747, 0.86651, 0.9245, 0.9245, 0.9245, 0.9245, 0.89453, 0.9245, 0.89453, 0.8675, 0.9245, 0.8675, 0.9245, 0.8675, 0.9245, 0.72346, 0.83203, 0.72346, 0.83203, 0.72346, 0.83203, 0.72346, 0.83203, 0.85193, 0.8875, 0.86477, 0.99034, 0.73206, 0.85865, 0.73206, 0.85865, 0.73206, 0.85865, 0.73206, 0.85865, 0.73206, 0.85865, 0.81105, 0.9245, 0.81105, 0.9245, 0.81105, 0.9245, 1, 1, 0.86275, 0.9245, 0.90872, 0.93591, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 1.03297, 0.90685, 0.82601, 0.77896, 1.05611, 0.6377, 1.07692, 1, 1, 0.90918, 0.75593, 1.03297, 1, 1, 0.76032, 0.9375, 0.98156, 0.93407, 0.77261, 1.11429, 0.89249, 0.9245, 1, 1, 0.89249, 0.9245, 0.92534, 0.86698, 0.9245, 0.84118, 0.92274, 0.84118, 0.92274, 0.84118, 0.92274, 0.8667, 0.86291, 0.75186, 1.02933, 1, 1, 0.75186, 1.02933, 0.67789, 0.77832, 0.67789, 0.77832, 0.67789, 0.77832, 0.67789, 0.77832, 1, 1, 0.79776, 0.97655, 0.79776, 1.23023, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.88844, 0.9245, 0.94309, 0.98986, 0.7306, 0.89453, 0.7306, 0.76659, 0.79004, 0.76659, 0.79004, 0.76659, 0.79004, 1.09231, 0.54873, 0.8675, 0.9245, 0.76318, 0.84843, 0.84557, 0.86651, 1, 1, 0.79776, 1.20562, 1.18622, 1.18622, 1, 1.1437, 0.67009, 0.96334, 0.93695, 1.35191, 1.40909, 0.95161, 1.48387, 0.8675, 0.90861, 0.6192, 0.7363, 0.64824, 0.82411, 0.56321, 0.85696, 1.23516, 0.8675, 0.81552, 0.7286, 0.84134, 0.73206, 0.76659, 0.86275, 0.84369, 0.90685, 0.77892, 0.85871, 1.02638, 0.89249, 0.75828, 0.84118, 0.85984, 0.77452, 0.76466, 0.79776, 0.7306, 0.90782, 0.77818, 0.903, 0.87291, 0.90685, 0.7306, 0.99058, 1.03667, 0.94635, 1.23516, 0.9849, 0.99058, 0.92393, 0.8916, 0.942, 1.03667, 0.75026, 0.94635, 1.0297, 1.23516, 0.90918, 0.94048, 0.98217, 0.89746, 0.84153, 0.92274, 0.82507, 0.88832, 0.84438, 0.88178, 1.03525, 0.9849, 1.00225, 0.78086, 0.97248, 0.89404, 1.23516, 0.9849, 0.92274, 0.9849, 0.89404, 0.73206, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.89693, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.85865, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.90933, 1, 1, 1, 1, 1, 1, 0.94309, 0.98986, 0.94309, 0.98986, 0.94309, 0.98986, 0.7306, 0.89453, 1, 1, 0.89552, 0.90527, 1, 0.90186, 1.12308, 1.12308, 1.12308, 1.12308, 1.2566, 1.2566, 1.2566, 0.89552, 0.89552, 1.42259, 0.68994, 1.03809, 1, 1, 1.0176, 1.0176, 1.11523, 1.4956, 2.01462, 0.97858, 0.82616, 0.91133, 0.83437, 0.91133, 1, 1, 1, 0.70508, 1, 1.23108, 0.79801, 0.84426, 0.84426, 0.774, 0.90572, 1.81055, 0.90749, 1.81055, 1.28809, 1.55469, 0.94434, 1.07806, 1, 0.97094, 0.7589, 0.85284, 0.90747, 1.19658, 0.69825, 0.97622, 1.33512, 0.90747, 0.90747, 0.85284, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.0336, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05859, 1.05859, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const CalibriItalicMetrics = {
+ lineHeight: 1.2207,
+ lineGap: 0.2207
+};
+const CalibriRegularFactors = [1.3877, 1, 1, 1, 1.17223, 1.1293, 0.89552, 0.91133, 0.80395, 1.02269, 1.15601, 0.91056, 0.91056, 1.2798, 0.85284, 0.89807, 1, 0.90861, 1.39016, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.91133, 0.96309, 0.96309, 0.85284, 0.85284, 0.85284, 0.83319, 0.88071, 0.8675, 0.81552, 0.73834, 0.85193, 0.73206, 0.7522, 0.81105, 0.86275, 0.90685, 0.6377, 0.77892, 0.75593, 1.02638, 0.89385, 0.85122, 0.77452, 0.86503, 0.75186, 0.68887, 0.79776, 0.88844, 0.85066, 0.94258, 0.77818, 0.7306, 0.76659, 1.10369, 1.39016, 1.10369, 1.06139, 0.89552, 0.8739, 0.86128, 0.94469, 0.8457, 0.94469, 0.89464, 1.09842, 0.84636, 0.94469, 1.03297, 1.07692, 0.90918, 1.03297, 0.95897, 0.94469, 0.9482, 0.94469, 0.94469, 1.04692, 0.78223, 1.20562, 0.94469, 0.90332, 0.98986, 0.86621, 0.90527, 0.79004, 0.94152, 1.77256, 0.94152, 0.85284, 0.97801, 0.89552, 0.91133, 0.89552, 0.91133, 1.91729, 0.89552, 1.17889, 1.13254, 1.08707, 0.92098, 0.85284, 0.68787, 0.71353, 0.84737, 0.90747, 1.0088, 1.0044, 0.87683, 1, 1.09091, 1, 0.92229, 0.739, 1.15642, 0.92098, 0.76288, 0.80504, 0.80972, 0.75859, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.8675, 0.76318, 0.73834, 0.73206, 0.73206, 0.73206, 0.73206, 0.90685, 0.90685, 0.90685, 0.90685, 0.86477, 0.89385, 0.85122, 0.85122, 0.85122, 0.85122, 0.85122, 0.85284, 0.85311, 0.88844, 0.88844, 0.88844, 0.88844, 0.7306, 0.77452, 0.86331, 0.86128, 0.86128, 0.86128, 0.86128, 0.86128, 0.86128, 0.8693, 0.8457, 0.89464, 0.89464, 0.89464, 0.89464, 0.82601, 0.82601, 0.82601, 0.82601, 0.94469, 0.94469, 0.9482, 0.9482, 0.9482, 0.9482, 0.9482, 0.90747, 0.86651, 0.94469, 0.94469, 0.94469, 0.94469, 0.90527, 0.94469, 0.90527, 0.8675, 0.86128, 0.8675, 0.86128, 0.8675, 0.86128, 0.73834, 0.8457, 0.73834, 0.8457, 0.73834, 0.8457, 0.73834, 0.8457, 0.85193, 0.92454, 0.86477, 0.9921, 0.73206, 0.89464, 0.73206, 0.89464, 0.73206, 0.89464, 0.73206, 0.89464, 0.73206, 0.89464, 0.81105, 0.84636, 0.81105, 0.84636, 0.81105, 0.84636, 1, 1, 0.86275, 0.94469, 0.90872, 0.95786, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 0.82601, 0.90685, 1.03297, 0.90685, 0.82601, 0.77741, 1.05611, 0.6377, 1.07692, 1, 1, 0.90918, 0.75593, 1.03297, 1, 1, 0.76032, 0.90452, 0.98156, 1.11842, 0.77261, 1.11429, 0.89385, 0.94469, 1, 1, 0.89385, 0.94469, 0.95877, 0.86901, 0.94469, 0.85122, 0.9482, 0.85122, 0.9482, 0.85122, 0.9482, 0.8667, 0.90016, 0.75186, 1.04692, 1, 1, 0.75186, 1.04692, 0.68887, 0.78223, 0.68887, 0.78223, 0.68887, 0.78223, 0.68887, 0.78223, 1, 1, 0.79776, 0.92188, 0.79776, 1.23023, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.88844, 0.94469, 0.94258, 0.98986, 0.7306, 0.90527, 0.7306, 0.76659, 0.79004, 0.76659, 0.79004, 0.76659, 0.79004, 1.09231, 0.54873, 0.8675, 0.86128, 0.76318, 0.8693, 0.85311, 0.86651, 1, 1, 0.79776, 1.20562, 1.18622, 1.18622, 1, 1.1437, 0.67742, 0.96334, 0.93695, 1.35191, 1.40909, 0.95161, 1.48387, 0.86686, 0.90861, 0.62267, 0.74359, 0.65649, 0.85498, 0.56963, 0.88254, 1.23516, 0.8675, 0.81552, 0.75443, 0.84503, 0.73206, 0.76659, 0.86275, 0.85122, 0.90685, 0.77892, 0.85746, 1.02638, 0.89385, 0.75657, 0.85122, 0.86275, 0.77452, 0.74171, 0.79776, 0.7306, 0.95165, 0.77818, 0.89772, 0.88831, 0.90685, 0.7306, 0.98142, 1.02191, 0.96576, 1.23516, 0.99018, 0.98142, 0.9236, 0.89258, 0.94035, 1.02191, 0.78848, 0.96576, 0.9561, 1.23516, 0.90918, 0.92578, 0.95424, 0.89746, 0.83969, 0.9482, 0.80113, 0.89442, 0.85208, 0.86155, 0.98022, 0.99018, 1.00452, 0.81209, 0.99247, 0.89181, 1.23516, 0.99018, 0.9482, 0.99018, 0.89181, 0.73206, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.88844, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.89464, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.96766, 1, 1, 1, 1, 1, 1, 0.94258, 0.98986, 0.94258, 0.98986, 0.94258, 0.98986, 0.7306, 0.90527, 1, 1, 0.89552, 0.90527, 1, 0.90186, 1.12308, 1.12308, 1.12308, 1.12308, 1.2566, 1.2566, 1.2566, 0.89552, 0.89552, 1.42259, 0.69043, 1.03809, 1, 1, 1.0176, 1.0176, 1.11523, 1.4956, 2.01462, 0.99331, 0.82616, 0.91133, 0.84286, 0.91133, 1, 1, 1, 0.70508, 1, 1.23108, 0.79801, 0.84426, 0.84426, 0.774, 0.90527, 1.81055, 0.90527, 1.81055, 1.28809, 1.55469, 0.94434, 1.07806, 1, 0.97094, 0.7589, 0.85284, 0.90747, 1.19658, 0.69825, 0.97622, 1.33512, 0.90747, 0.90747, 0.85356, 0.90747, 0.90747, 1.44947, 0.85284, 0.8941, 0.8941, 0.70572, 0.8, 0.70572, 0.70572, 0.70572, 0.70572, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.99862, 0.99862, 1, 1, 1, 1, 1, 1.0336, 0.91027, 1, 1, 1, 0.99862, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05859, 1.05859, 1, 1, 1, 1.07185, 0.99413, 0.96334, 1.08065, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const CalibriRegularMetrics = {
+ lineHeight: 1.2207,
+ lineGap: 0.2207
+};
+
+;// ./src/core/helvetica_factors.js
+const HelveticaBoldFactors = [0.76116, 1, 1, 1.0006, 0.99998, 0.99974, 0.99973, 0.99973, 0.99982, 0.99977, 1.00087, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.00003, 1.00003, 1.00003, 1.00026, 0.9999, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 0.99973, 0.99977, 1.00026, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 0.99998, 1.0006, 0.99998, 1.00003, 0.99973, 0.99998, 0.99973, 1.00026, 0.99973, 1.00026, 0.99973, 0.99998, 1.00026, 1.00026, 1.0006, 1.0006, 0.99973, 1.0006, 0.99982, 1.00026, 1.00026, 1.00026, 1.00026, 0.99959, 0.99973, 0.99998, 1.00026, 0.99973, 1.00022, 0.99973, 0.99973, 1, 0.99959, 1.00077, 0.99959, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.00077, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.99973, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.06409, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 0.99973, 1.00026, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 1.03374, 0.99977, 1.00026, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.00042, 0.99973, 0.99973, 1.0006, 0.99977, 0.99973, 0.99973, 1.00026, 1.0006, 1.00026, 1.0006, 1.00026, 1.03828, 1.00026, 0.99999, 1.00026, 1.0006, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.9993, 0.9998, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1, 1.00016, 0.99977, 0.99959, 0.99977, 0.99959, 0.99977, 0.99959, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00026, 0.99998, 1.00026, 0.8121, 1.00026, 0.99998, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.00016, 1.00022, 1.00001, 0.99973, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 1.0006, 0.99973, 0.99977, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 0.99973, 1.00026, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 1.00034, 0.99977, 1, 0.99997, 1.00026, 1.00078, 1.00036, 0.99973, 1.00013, 1.0006, 0.99977, 0.99977, 0.99988, 0.85148, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 0.99977, 1.00001, 0.99999, 0.99977, 1.00069, 1.00022, 0.99977, 1.00001, 0.99984, 1.00026, 1.00001, 1.00024, 1.00001, 0.9999, 1, 1.0006, 1.00001, 1.00041, 0.99962, 1.00026, 1.0006, 0.99995, 1.00041, 0.99942, 0.99973, 0.99927, 1.00082, 0.99902, 1.00026, 1.00087, 1.0006, 1.00069, 0.99973, 0.99867, 0.99973, 0.9993, 1.00026, 1.00049, 1.00056, 1, 0.99988, 0.99935, 0.99995, 0.99954, 1.00055, 0.99945, 1.00032, 1.0006, 0.99995, 1.00026, 0.99995, 1.00032, 1.00001, 1.00008, 0.99971, 1.00019, 0.9994, 1.00001, 1.0006, 1.00044, 0.99973, 1.00023, 1.00047, 1, 0.99942, 0.99561, 0.99989, 1.00035, 0.99977, 1.00035, 0.99977, 1.00019, 0.99944, 1.00001, 1.00021, 0.99926, 1.00035, 1.00035, 0.99942, 1.00048, 0.99999, 0.99977, 1.00022, 1.00035, 1.00001, 0.99977, 1.00026, 0.99989, 1.00057, 1.00001, 0.99936, 1.00052, 1.00012, 0.99996, 1.00043, 1, 1.00035, 0.9994, 0.99976, 1.00035, 0.99973, 1.00052, 1.00041, 1.00119, 1.00037, 0.99973, 1.00002, 0.99986, 1.00041, 1.00041, 0.99902, 0.9996, 1.00034, 0.99999, 1.00026, 0.99999, 1.00026, 0.99973, 1.00052, 0.99973, 1, 0.99973, 1.00041, 1.00075, 0.9994, 1.0003, 0.99999, 1, 1.00041, 0.99955, 1, 0.99915, 0.99973, 0.99973, 1.00026, 1.00119, 0.99955, 0.99973, 1.0006, 0.99911, 1.0006, 1.00026, 0.99972, 1.00026, 0.99902, 1.00041, 0.99973, 0.99999, 1, 1, 1.00038, 1.0005, 1.00016, 1.00022, 1.00016, 1.00022, 1.00016, 1.00022, 1.00001, 0.99973, 1, 1, 0.99973, 1, 1, 0.99955, 1.0006, 1.0006, 1.0006, 1.0006, 1, 1, 1, 0.99973, 0.99973, 0.99972, 1, 1, 1.00106, 0.99999, 0.99998, 0.99998, 0.99999, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1.00023, 0.99973, 0.99971, 1.00047, 1.00023, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1, 1, 1, 1, 1, 1, 1, 0.99972, 1, 1.20985, 1.39713, 1.00003, 1.00031, 1.00015, 1, 0.99561, 1.00027, 1.00031, 1.00031, 0.99915, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.99972, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 0.99998, 0.99998, 0.99998, 0.99998, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const HelveticaBoldMetrics = {
+ lineHeight: 1.2,
+ lineGap: 0.2
+};
+const HelveticaBoldItalicFactors = [0.76116, 1, 1, 1.0006, 0.99998, 0.99974, 0.99973, 0.99973, 0.99982, 0.99977, 1.00087, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.00003, 1.00003, 1.00003, 1.00026, 0.9999, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 0.99973, 0.99977, 1.00026, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 0.99998, 1.0006, 0.99998, 1.00003, 0.99973, 0.99998, 0.99973, 1.00026, 0.99973, 1.00026, 0.99973, 0.99998, 1.00026, 1.00026, 1.0006, 1.0006, 0.99973, 1.0006, 0.99982, 1.00026, 1.00026, 1.00026, 1.00026, 0.99959, 0.99973, 0.99998, 1.00026, 0.99973, 1.00022, 0.99973, 0.99973, 1, 0.99959, 1.00077, 0.99959, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.00077, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.99973, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 0.99977, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 1.06409, 1.00026, 1.00026, 1.00026, 1.00026, 1.00026, 0.99973, 1.00026, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 1.0044, 0.99977, 1.00026, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 0.99971, 0.99973, 0.99973, 1.0006, 0.99977, 0.99973, 0.99973, 1.00026, 1.0006, 1.00026, 1.0006, 1.00026, 1.01011, 1.00026, 0.99999, 1.00026, 1.0006, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.9993, 0.9998, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1.00022, 1.00026, 1, 1.00016, 0.99977, 0.99959, 0.99977, 0.99959, 0.99977, 0.99959, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00026, 0.99998, 1.00026, 0.8121, 1.00026, 0.99998, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 0.99977, 1.00026, 1.00016, 1.00022, 1.00001, 0.99973, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 1.0006, 0.99973, 0.99977, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 0.99973, 1.00026, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99977, 1, 1, 1.00026, 0.99969, 0.99972, 0.99981, 0.9998, 1.0006, 0.99977, 0.99977, 1.00022, 0.91155, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 0.99977, 1.00001, 0.99999, 0.99977, 0.99966, 1.00022, 1.00032, 1.00001, 0.99944, 1.00026, 1.00001, 0.99968, 1.00001, 1.00047, 1, 1.0006, 1.00001, 0.99981, 1.00101, 1.00026, 1.0006, 0.99948, 0.99981, 1.00064, 0.99973, 0.99942, 1.00101, 1.00061, 1.00026, 1.00069, 1.0006, 1.00014, 0.99973, 1.01322, 0.99973, 1.00065, 1.00026, 1.00012, 0.99923, 1, 1.00064, 1.00076, 0.99948, 1.00055, 1.00063, 1.00007, 0.99943, 1.0006, 0.99948, 1.00026, 0.99948, 0.99943, 1.00001, 1.00001, 1.00029, 1.00038, 1.00035, 1.00001, 1.0006, 1.0006, 0.99973, 0.99978, 1.00001, 1.00057, 0.99989, 0.99967, 0.99964, 0.99967, 0.99977, 0.99999, 0.99977, 1.00038, 0.99977, 1.00001, 0.99973, 1.00066, 0.99967, 0.99967, 1.00041, 0.99998, 0.99999, 0.99977, 1.00022, 0.99967, 1.00001, 0.99977, 1.00026, 0.99964, 1.00031, 1.00001, 0.99999, 0.99999, 1, 1.00023, 1, 1, 0.99999, 1.00035, 1.00001, 0.99999, 0.99973, 0.99977, 0.99999, 1.00058, 0.99973, 0.99973, 0.99955, 0.9995, 1.00026, 1.00026, 1.00032, 0.99989, 1.00034, 0.99999, 1.00026, 1.00026, 1.00026, 0.99973, 0.45998, 0.99973, 1.00026, 0.99973, 1.00001, 0.99999, 0.99982, 0.99994, 0.99996, 1, 1.00042, 1.00044, 1.00029, 1.00023, 0.99973, 0.99973, 1.00026, 0.99949, 1.00002, 0.99973, 1.0006, 1.0006, 1.0006, 0.99975, 1.00026, 1.00026, 1.00032, 0.98685, 0.99973, 1.00026, 1, 1, 0.99966, 1.00044, 1.00016, 1.00022, 1.00016, 1.00022, 1.00016, 1.00022, 1.00001, 0.99973, 1, 1, 0.99973, 1, 1, 0.99955, 1.0006, 1.0006, 1.0006, 1.0006, 1, 1, 1, 0.99973, 0.99973, 0.99972, 1, 1, 1.00106, 0.99999, 0.99998, 0.99998, 0.99999, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1, 0.99973, 0.99971, 0.99978, 1, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1.00098, 1, 1, 1, 1.00049, 1, 1, 0.99972, 1, 1.20985, 1.39713, 1.00003, 1.00031, 1.00015, 1, 0.99561, 1.00027, 1.00031, 1.00031, 0.99915, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.99972, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 0.99998, 0.99998, 0.99998, 0.99998, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const HelveticaBoldItalicMetrics = {
+ lineHeight: 1.35,
+ lineGap: 0.2
+};
+const HelveticaItalicFactors = [0.76116, 1, 1, 1.0006, 1.0006, 1.00006, 0.99973, 0.99973, 0.99982, 1.00001, 1.00043, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1, 1.00003, 1.00003, 1.00003, 0.99973, 0.99987, 1.00001, 1.00001, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 1, 1.00001, 0.99973, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 1.0006, 1.0006, 1.0006, 0.99949, 0.99973, 0.99998, 0.99973, 0.99973, 1, 0.99973, 0.99973, 1.0006, 0.99973, 0.99973, 0.99924, 0.99924, 1, 0.99924, 0.99999, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.0006, 0.99973, 1, 0.99977, 1, 1, 1, 1.00005, 1.0009, 1.00005, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.0009, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.9998, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 1, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.06409, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 1, 0.99973, 1, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1.0288, 0.99977, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 0.99924, 1.0006, 1.0006, 0.99946, 1.00034, 1, 0.99924, 1.00001, 1, 1, 0.99973, 0.99924, 0.99973, 0.99924, 0.99973, 1.06311, 0.99973, 1.00024, 0.99973, 0.99924, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.00041, 0.9998, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1, 1.00016, 0.99977, 0.99998, 0.99977, 0.99998, 0.99977, 0.99998, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00026, 1.0006, 1.00026, 0.89547, 1.00026, 1.0006, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.00016, 0.99977, 1.00001, 1, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 0.99924, 0.99973, 1.00001, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 1, 1.00026, 1.0006, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 1.00001, 1, 1.00054, 0.99977, 1.00084, 1.00007, 0.99973, 1.00013, 0.99924, 1.00001, 1.00001, 0.99945, 0.91221, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 1.00001, 1.00001, 0.99999, 0.99977, 0.99933, 1.00022, 1.00054, 1.00001, 1.00065, 1.00026, 1.00001, 1.0001, 1.00001, 1.00052, 1, 1.0006, 1.00001, 0.99945, 0.99897, 0.99968, 0.99924, 1.00036, 0.99945, 0.99949, 1, 1.0006, 0.99897, 0.99918, 0.99968, 0.99911, 0.99924, 1, 0.99962, 1.01487, 1, 1.0005, 0.99973, 1.00012, 1.00043, 1, 0.99995, 0.99994, 1.00036, 0.99947, 1.00019, 1.00063, 1.00025, 0.99924, 1.00036, 0.99973, 1.00036, 1.00025, 1.00001, 1.00001, 1.00027, 1.0001, 1.00068, 1.00001, 1.0006, 1.0006, 1, 1.00008, 0.99957, 0.99972, 0.9994, 0.99954, 0.99975, 1.00051, 1.00001, 1.00019, 1.00001, 1.0001, 0.99986, 1.00001, 1.00001, 1.00038, 0.99954, 0.99954, 0.9994, 1.00066, 0.99999, 0.99977, 1.00022, 1.00054, 1.00001, 0.99977, 1.00026, 0.99975, 1.0001, 1.00001, 0.99993, 0.9995, 0.99955, 1.00016, 0.99978, 0.99974, 1.00019, 1.00022, 0.99955, 1.00053, 0.99973, 1.00089, 1.00005, 0.99967, 1.00048, 0.99973, 1.00002, 1.00034, 0.99973, 0.99973, 0.99964, 1.00006, 1.00066, 0.99947, 0.99973, 0.98894, 0.99973, 1, 0.44898, 1, 0.99946, 1, 1.00039, 1.00082, 0.99991, 0.99991, 0.99985, 1.00022, 1.00023, 1.00061, 1.00006, 0.99966, 0.99973, 0.99973, 0.99973, 1.00019, 1.0008, 1, 0.99924, 0.99924, 0.99924, 0.99983, 1.00044, 0.99973, 0.99964, 0.98332, 1, 0.99973, 1, 1, 0.99962, 0.99895, 1.00016, 0.99977, 1.00016, 0.99977, 1.00016, 0.99977, 1.00001, 1, 1, 1, 0.99973, 1, 1, 0.99955, 0.99924, 0.99924, 0.99924, 0.99924, 0.99998, 0.99998, 0.99998, 0.99973, 0.99973, 0.99972, 1, 1, 1.00267, 0.99999, 0.99998, 0.99998, 1, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1.00023, 0.99973, 1.00423, 0.99925, 0.99999, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1.00049, 1, 1.00245, 1, 1, 1, 1, 0.96329, 1, 1.20985, 1.39713, 1.00003, 0.8254, 1.00015, 1, 1.00035, 1.00027, 1.00031, 1.00031, 1.00003, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.95317, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 0.99998, 0.99998, 0.99998, 0.99998, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const HelveticaItalicMetrics = {
+ lineHeight: 1.35,
+ lineGap: 0.2
+};
+const HelveticaRegularFactors = [0.76116, 1, 1, 1.0006, 1.0006, 1.00006, 0.99973, 0.99973, 0.99982, 1.00001, 1.00043, 0.99998, 0.99998, 0.99959, 1.00003, 1.0006, 0.99998, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1, 1.00003, 1.00003, 1.00003, 0.99973, 0.99987, 1.00001, 1.00001, 0.99977, 0.99977, 1.00001, 1.00026, 1.00022, 0.99977, 1.0006, 1, 1.00001, 0.99973, 0.99999, 0.99977, 1.00022, 1.00001, 1.00022, 0.99977, 1.00001, 1.00026, 0.99977, 1.00001, 1.00016, 1.00001, 1.00001, 1.00026, 1.0006, 1.0006, 1.0006, 0.99949, 0.99973, 0.99998, 0.99973, 0.99973, 1, 0.99973, 0.99973, 1.0006, 0.99973, 0.99973, 0.99924, 0.99924, 1, 0.99924, 0.99999, 0.99973, 0.99973, 0.99973, 0.99973, 0.99998, 1, 1.0006, 0.99973, 1, 0.99977, 1, 1, 1, 1.00005, 1.0009, 1.00005, 1.00003, 0.99998, 0.99973, 0.99973, 0.99973, 0.99973, 1.0009, 0.99973, 0.99998, 1.00025, 0.99968, 0.99973, 1.00003, 1.00025, 0.60299, 1.00024, 1.06409, 1, 1, 0.99998, 1, 0.9998, 1.0006, 0.99998, 1, 0.99936, 0.99973, 1.00002, 1.00002, 1.00002, 1.00026, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1.00001, 1, 0.99977, 1.00001, 1.00001, 1.00001, 1.00001, 1.0006, 1.0006, 1.0006, 1.0006, 0.99977, 0.99977, 1.00022, 1.00022, 1.00022, 1.00022, 1.00022, 1.00003, 1.00022, 0.99977, 0.99977, 0.99977, 0.99977, 1.00001, 1.00001, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99982, 1, 0.99973, 0.99973, 0.99973, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 0.99973, 1.06409, 1.00026, 0.99973, 0.99973, 0.99973, 0.99973, 1, 0.99973, 1, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1, 0.99977, 1.04596, 0.99977, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00001, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 1.0006, 0.99924, 1.0006, 1.0006, 1.00019, 1.00034, 1, 0.99924, 1.00001, 1, 1, 0.99973, 0.99924, 0.99973, 0.99924, 0.99973, 1.02572, 0.99973, 1.00005, 0.99973, 0.99924, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99999, 0.9998, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1.00022, 0.99973, 1, 1.00016, 0.99977, 0.99998, 0.99977, 0.99998, 0.99977, 0.99998, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00001, 1, 1.00026, 1.0006, 1.00026, 0.84533, 1.00026, 1.0006, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 0.99977, 0.99973, 1.00016, 0.99977, 1.00001, 1, 1.00001, 1.00026, 1, 1.00026, 1, 1.00026, 1, 0.99924, 0.99973, 1.00001, 0.99973, 1, 0.99982, 1.00022, 1.00026, 1.00001, 1, 1.00026, 1.0006, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99998, 0.99928, 1, 0.99977, 1.00013, 1.00055, 0.99947, 0.99945, 0.99941, 0.99924, 1.00001, 1.00001, 1.0004, 0.91621, 1.00001, 1.00026, 0.99977, 1.00022, 1.0006, 1.00001, 1.00005, 0.99999, 0.99977, 1.00015, 1.00022, 0.99977, 1.00001, 0.99973, 1.00026, 1.00001, 1.00019, 1.00001, 0.99946, 1, 1.0006, 1.00001, 0.99978, 1.00045, 0.99973, 0.99924, 1.00023, 0.99978, 0.99966, 1, 1.00065, 1.00045, 1.00019, 0.99973, 0.99973, 0.99924, 1, 1, 0.96499, 1, 1.00055, 0.99973, 1.00008, 1.00027, 1, 0.9997, 0.99995, 1.00023, 0.99933, 1.00019, 1.00015, 1.00031, 0.99924, 1.00023, 0.99973, 1.00023, 1.00031, 1.00001, 0.99928, 1.00029, 1.00092, 1.00035, 1.00001, 1.0006, 1.0006, 1, 0.99988, 0.99975, 1, 1.00082, 0.99561, 0.9996, 1.00035, 1.00001, 0.99962, 1.00001, 1.00092, 0.99964, 1.00001, 0.99963, 0.99999, 1.00035, 1.00035, 1.00082, 0.99962, 0.99999, 0.99977, 1.00022, 1.00035, 1.00001, 0.99977, 1.00026, 0.9996, 0.99967, 1.00001, 1.00034, 1.00074, 1.00054, 1.00053, 1.00063, 0.99971, 0.99962, 1.00035, 0.99975, 0.99977, 0.99973, 1.00043, 0.99953, 1.0007, 0.99915, 0.99973, 1.00008, 0.99892, 1.00073, 1.00073, 1.00114, 0.99915, 1.00073, 0.99955, 0.99973, 1.00092, 0.99973, 1, 0.99998, 1, 1.0003, 1, 1.00043, 1.00001, 0.99969, 1.0003, 1, 1.00035, 1.00001, 0.9995, 1, 1.00092, 0.99973, 0.99973, 0.99973, 1.0007, 0.9995, 1, 0.99924, 1.0006, 0.99924, 0.99972, 1.00062, 0.99973, 1.00114, 1.00073, 1, 0.99955, 1, 1, 1.00047, 0.99968, 1.00016, 0.99977, 1.00016, 0.99977, 1.00016, 0.99977, 1.00001, 1, 1, 1, 0.99973, 1, 1, 0.99955, 0.99924, 0.99924, 0.99924, 0.99924, 0.99998, 0.99998, 0.99998, 0.99973, 0.99973, 0.99972, 1, 1, 1.00267, 0.99999, 0.99998, 0.99998, 1, 0.99998, 1.66475, 1, 0.99973, 0.99973, 1.00023, 0.99973, 0.99971, 0.99925, 1.00023, 1, 0.99991, 0.99984, 1.00002, 1.00002, 1.00002, 1.00002, 1, 1, 1, 1, 1, 1, 1, 0.96329, 1, 1.20985, 1.39713, 1.00003, 0.8254, 1.00015, 1, 1.00035, 1.00027, 1.00031, 1.00031, 0.99915, 1.00031, 1.00031, 0.99999, 1.00003, 0.99999, 0.99999, 1.41144, 1.6, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.41144, 1.40579, 1.40579, 1.36625, 0.99999, 1, 0.99861, 0.99861, 1, 1.00026, 1.00026, 1.00026, 1.00026, 0.95317, 0.99999, 0.99999, 0.99999, 0.99999, 1.40483, 1, 0.99977, 1.00054, 1, 1, 0.99953, 0.99962, 1.00042, 0.9995, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const HelveticaRegularMetrics = {
+ lineHeight: 1.2,
+ lineGap: 0.2
+};
+
+;// ./src/core/liberationsans_widths.js
+const LiberationSansBoldWidths = [365, 0, 333, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 549, 611, 611, 611, 611, 611, 556, 611, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 719, 722, 611, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 611, 778, 611, 778, 611, 778, 611, 722, 611, 722, 611, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 785, 556, 556, 278, 722, 556, 556, 611, 278, 611, 278, 611, 385, 611, 479, 611, 278, 722, 611, 722, 611, 722, 611, 708, 723, 611, 778, 611, 778, 611, 778, 611, 1000, 944, 722, 389, 722, 389, 722, 389, 667, 556, 667, 556, 667, 556, 667, 556, 611, 333, 611, 479, 611, 333, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 944, 778, 667, 556, 667, 611, 500, 611, 500, 611, 500, 278, 556, 722, 556, 1000, 889, 778, 611, 667, 556, 611, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 465, 722, 333, 853, 906, 474, 825, 927, 838, 278, 722, 722, 601, 719, 667, 611, 722, 778, 278, 722, 667, 833, 722, 644, 778, 722, 667, 600, 611, 667, 821, 667, 809, 802, 278, 667, 615, 451, 611, 278, 582, 615, 610, 556, 606, 475, 460, 611, 541, 278, 558, 556, 612, 556, 445, 611, 766, 619, 520, 684, 446, 582, 715, 576, 753, 845, 278, 582, 611, 582, 845, 667, 669, 885, 567, 711, 667, 278, 276, 556, 1094, 1062, 875, 610, 722, 622, 719, 722, 719, 722, 567, 712, 667, 904, 626, 719, 719, 610, 702, 833, 722, 778, 719, 667, 722, 611, 622, 854, 667, 730, 703, 1005, 1019, 870, 979, 719, 711, 1031, 719, 556, 618, 615, 417, 635, 556, 709, 497, 615, 615, 500, 635, 740, 604, 611, 604, 611, 556, 490, 556, 875, 556, 615, 581, 833, 844, 729, 854, 615, 552, 854, 583, 556, 556, 611, 417, 552, 556, 278, 281, 278, 969, 906, 611, 500, 615, 556, 604, 778, 611, 487, 447, 944, 778, 944, 778, 944, 778, 667, 556, 333, 333, 556, 1000, 1000, 552, 278, 278, 278, 278, 500, 500, 500, 556, 556, 350, 1000, 1000, 240, 479, 333, 333, 604, 333, 167, 396, 556, 556, 1094, 556, 885, 489, 1115, 1000, 768, 600, 834, 834, 834, 834, 1000, 500, 1000, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 722, 274, 549, 549, 583, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 611, 611, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 333, 333, 333, 333, 333, 333, 333, 333];
+const LiberationSansBoldMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
+const LiberationSansBoldItalicWidths = [365, 0, 333, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 549, 611, 611, 611, 611, 611, 556, 611, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 740, 722, 611, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 611, 778, 611, 778, 611, 778, 611, 722, 611, 722, 611, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 782, 556, 556, 278, 722, 556, 556, 611, 278, 611, 278, 611, 396, 611, 479, 611, 278, 722, 611, 722, 611, 722, 611, 708, 723, 611, 778, 611, 778, 611, 778, 611, 1000, 944, 722, 389, 722, 389, 722, 389, 667, 556, 667, 556, 667, 556, 667, 556, 611, 333, 611, 479, 611, 333, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 722, 611, 944, 778, 667, 556, 667, 611, 500, 611, 500, 611, 500, 278, 556, 722, 556, 1000, 889, 778, 611, 667, 556, 611, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 722, 333, 854, 906, 473, 844, 930, 847, 278, 722, 722, 610, 671, 667, 611, 722, 778, 278, 722, 667, 833, 722, 657, 778, 718, 667, 590, 611, 667, 822, 667, 829, 781, 278, 667, 620, 479, 611, 278, 591, 620, 621, 556, 610, 479, 492, 611, 558, 278, 566, 556, 603, 556, 450, 611, 712, 605, 532, 664, 409, 591, 704, 578, 773, 834, 278, 591, 611, 591, 834, 667, 667, 886, 614, 719, 667, 278, 278, 556, 1094, 1042, 854, 622, 719, 677, 719, 722, 708, 722, 614, 722, 667, 927, 643, 719, 719, 615, 687, 833, 722, 778, 719, 667, 722, 611, 677, 781, 667, 729, 708, 979, 989, 854, 1000, 708, 719, 1042, 729, 556, 619, 604, 534, 618, 556, 736, 510, 611, 611, 507, 622, 740, 604, 611, 611, 611, 556, 889, 556, 885, 556, 646, 583, 889, 935, 707, 854, 594, 552, 865, 589, 556, 556, 611, 469, 563, 556, 278, 278, 278, 969, 906, 611, 507, 619, 556, 611, 778, 611, 575, 467, 944, 778, 944, 778, 944, 778, 667, 556, 333, 333, 556, 1000, 1000, 552, 278, 278, 278, 278, 500, 500, 500, 556, 556, 350, 1000, 1000, 240, 479, 333, 333, 604, 333, 167, 396, 556, 556, 1104, 556, 885, 516, 1146, 1000, 768, 600, 834, 834, 834, 834, 999, 500, 1000, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 722, 274, 549, 549, 583, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 611, 611, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 333, 333, 333, 333, 333, 333, 333, 333];
+const LiberationSansBoldItalicMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
+const LiberationSansItalicWidths = [365, 0, 333, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 549, 611, 556, 556, 556, 556, 500, 556, 500, 667, 556, 667, 556, 667, 556, 722, 500, 722, 500, 722, 500, 722, 500, 722, 625, 722, 556, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 556, 778, 556, 778, 556, 778, 556, 722, 556, 722, 556, 278, 278, 278, 278, 278, 278, 278, 222, 278, 278, 733, 444, 500, 222, 667, 500, 500, 556, 222, 556, 222, 556, 281, 556, 400, 556, 222, 722, 556, 722, 556, 722, 556, 615, 723, 556, 778, 556, 778, 556, 778, 556, 1000, 944, 722, 333, 722, 333, 722, 333, 667, 500, 667, 500, 667, 500, 667, 500, 611, 278, 611, 354, 611, 278, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 944, 722, 667, 500, 667, 611, 500, 611, 500, 611, 500, 222, 556, 667, 556, 1000, 889, 778, 611, 667, 500, 611, 278, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 667, 278, 789, 846, 389, 794, 865, 775, 222, 667, 667, 570, 671, 667, 611, 722, 778, 278, 667, 667, 833, 722, 648, 778, 725, 667, 600, 611, 667, 837, 667, 831, 761, 278, 667, 570, 439, 555, 222, 550, 570, 571, 500, 556, 439, 463, 555, 542, 222, 500, 492, 548, 500, 447, 556, 670, 573, 486, 603, 374, 550, 652, 546, 728, 779, 222, 550, 556, 550, 779, 667, 667, 843, 544, 708, 667, 278, 278, 500, 1066, 982, 844, 589, 715, 639, 724, 667, 651, 667, 544, 704, 667, 917, 614, 715, 715, 589, 686, 833, 722, 778, 725, 667, 722, 611, 639, 795, 667, 727, 673, 920, 923, 805, 886, 651, 694, 1022, 682, 556, 562, 522, 493, 553, 556, 688, 465, 556, 556, 472, 564, 686, 550, 556, 556, 556, 500, 833, 500, 835, 500, 572, 518, 830, 851, 621, 736, 526, 492, 752, 534, 556, 556, 556, 378, 496, 500, 222, 222, 222, 910, 828, 556, 472, 565, 500, 556, 778, 556, 492, 339, 944, 722, 944, 722, 944, 722, 667, 500, 333, 333, 556, 1000, 1000, 552, 222, 222, 222, 222, 333, 333, 333, 556, 556, 350, 1000, 1000, 188, 354, 333, 333, 500, 333, 167, 365, 556, 556, 1094, 556, 885, 323, 1083, 1000, 768, 600, 834, 834, 834, 834, 1000, 500, 998, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 719, 274, 549, 549, 584, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 500, 500, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 294, 294, 324, 324, 316, 328, 398, 285];
+const LiberationSansItalicMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
+const LiberationSansRegularWidths = [365, 0, 333, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 737, 552, 400, 549, 333, 333, 333, 576, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 549, 611, 556, 556, 556, 556, 500, 556, 500, 667, 556, 667, 556, 667, 556, 722, 500, 722, 500, 722, 500, 722, 500, 722, 615, 722, 556, 667, 556, 667, 556, 667, 556, 667, 556, 667, 556, 778, 556, 778, 556, 778, 556, 778, 556, 722, 556, 722, 556, 278, 278, 278, 278, 278, 278, 278, 222, 278, 278, 735, 444, 500, 222, 667, 500, 500, 556, 222, 556, 222, 556, 292, 556, 334, 556, 222, 722, 556, 722, 556, 722, 556, 604, 723, 556, 778, 556, 778, 556, 778, 556, 1000, 944, 722, 333, 722, 333, 722, 333, 667, 500, 667, 500, 667, 500, 667, 500, 611, 278, 611, 375, 611, 278, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 722, 556, 944, 722, 667, 500, 667, 611, 500, 611, 500, 611, 500, 222, 556, 667, 556, 1000, 889, 778, 611, 667, 500, 611, 278, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 333, 667, 278, 784, 838, 384, 774, 855, 752, 222, 667, 667, 551, 668, 667, 611, 722, 778, 278, 667, 668, 833, 722, 650, 778, 722, 667, 618, 611, 667, 798, 667, 835, 748, 278, 667, 578, 446, 556, 222, 547, 578, 575, 500, 557, 446, 441, 556, 556, 222, 500, 500, 576, 500, 448, 556, 690, 569, 482, 617, 395, 547, 648, 525, 713, 781, 222, 547, 556, 547, 781, 667, 667, 865, 542, 719, 667, 278, 278, 500, 1057, 1010, 854, 583, 722, 635, 719, 667, 656, 667, 542, 677, 667, 923, 604, 719, 719, 583, 656, 833, 722, 778, 719, 667, 722, 611, 635, 760, 667, 740, 667, 917, 938, 792, 885, 656, 719, 1010, 722, 556, 573, 531, 365, 583, 556, 669, 458, 559, 559, 438, 583, 688, 552, 556, 542, 556, 500, 458, 500, 823, 500, 573, 521, 802, 823, 625, 719, 521, 510, 750, 542, 556, 556, 556, 365, 510, 500, 222, 278, 222, 906, 812, 556, 438, 559, 500, 552, 778, 556, 489, 411, 944, 722, 944, 722, 944, 722, 667, 500, 333, 333, 556, 1000, 1000, 552, 222, 222, 222, 222, 333, 333, 333, 556, 556, 350, 1000, 1000, 188, 354, 333, 333, 500, 333, 167, 365, 556, 556, 1094, 556, 885, 323, 1073, 1000, 768, 600, 834, 834, 834, 834, 1000, 500, 1000, 500, 1000, 500, 500, 494, 612, 823, 713, 584, 549, 713, 979, 719, 274, 549, 549, 583, 549, 549, 604, 584, 604, 604, 708, 625, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 708, 729, 604, 604, 354, 354, 1000, 990, 990, 990, 990, 494, 604, 604, 604, 604, 354, 1021, 1052, 917, 750, 750, 531, 656, 594, 510, 500, 750, 750, 500, 500, 333, 333, 333, 333, 333, 333, 333, 333, 222, 222, 294, 294, 324, 324, 316, 328, 398, 285];
+const LiberationSansRegularMapping = [-1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 402, 506, 507, 508, 509, 510, 511, 536, 537, 538, 539, 710, 711, 713, 728, 729, 730, 731, 732, 733, 900, 901, 902, 903, 904, 905, 906, 908, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1138, 1139, 1168, 1169, 7808, 7809, 7810, 7811, 7812, 7813, 7922, 7923, 8208, 8209, 8211, 8212, 8213, 8215, 8216, 8217, 8218, 8219, 8220, 8221, 8222, 8224, 8225, 8226, 8230, 8240, 8242, 8243, 8249, 8250, 8252, 8254, 8260, 8319, 8355, 8356, 8359, 8364, 8453, 8467, 8470, 8482, 8486, 8494, 8539, 8540, 8541, 8542, 8592, 8593, 8594, 8595, 8596, 8597, 8616, 8706, 8710, 8719, 8721, 8722, 8730, 8734, 8735, 8745, 8747, 8776, 8800, 8801, 8804, 8805, 8962, 8976, 8992, 8993, 9472, 9474, 9484, 9488, 9492, 9496, 9500, 9508, 9516, 9524, 9532, 9552, 9553, 9554, 9555, 9556, 9557, 9558, 9559, 9560, 9561, 9562, 9563, 9564, 9565, 9566, 9567, 9568, 9569, 9570, 9571, 9572, 9573, 9574, 9575, 9576, 9577, 9578, 9579, 9580, 9600, 9604, 9608, 9612, 9616, 9617, 9618, 9619, 9632, 9633, 9642, 9643, 9644, 9650, 9658, 9660, 9668, 9674, 9675, 9679, 9688, 9689, 9702, 9786, 9787, 9788, 9792, 9794, 9824, 9827, 9829, 9830, 9834, 9835, 9836, 61441, 61442, 61445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1];
+
+;// ./src/core/myriadpro_factors.js
+const MyriadProBoldFactors = [1.36898, 1, 1, 0.72706, 0.80479, 0.83734, 0.98894, 0.99793, 0.9897, 0.93884, 0.86209, 0.94292, 0.94292, 1.16661, 1.02058, 0.93582, 0.96694, 0.93582, 1.19137, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.99793, 0.78076, 0.78076, 1.02058, 1.02058, 1.02058, 0.72851, 0.78966, 0.90838, 0.83637, 0.82391, 0.96376, 0.80061, 0.86275, 0.8768, 0.95407, 1.0258, 0.73901, 0.85022, 0.83655, 1.0156, 0.95546, 0.92179, 0.87107, 0.92179, 0.82114, 0.8096, 0.89713, 0.94438, 0.95353, 0.94083, 0.91905, 0.90406, 0.9446, 0.94292, 1.18777, 0.94292, 1.02058, 0.89903, 0.90088, 0.94938, 0.97898, 0.81093, 0.97571, 0.94938, 1.024, 0.9577, 0.95933, 0.98621, 1.0474, 0.97455, 0.98981, 0.9672, 0.95933, 0.9446, 0.97898, 0.97407, 0.97646, 0.78036, 1.10208, 0.95442, 0.95298, 0.97579, 0.9332, 0.94039, 0.938, 0.80687, 1.01149, 0.80687, 1.02058, 0.80479, 0.99793, 0.99793, 0.99793, 0.99793, 1.01149, 1.00872, 0.90088, 0.91882, 1.0213, 0.8361, 1.02058, 0.62295, 0.54324, 0.89022, 1.08595, 1, 1, 0.90088, 1, 0.97455, 0.93582, 0.90088, 1, 1.05686, 0.8361, 0.99642, 0.99642, 0.99642, 0.72851, 0.90838, 0.90838, 0.90838, 0.90838, 0.90838, 0.90838, 0.868, 0.82391, 0.80061, 0.80061, 0.80061, 0.80061, 1.0258, 1.0258, 1.0258, 1.0258, 0.97484, 0.95546, 0.92179, 0.92179, 0.92179, 0.92179, 0.92179, 1.02058, 0.92179, 0.94438, 0.94438, 0.94438, 0.94438, 0.90406, 0.86958, 0.98225, 0.94938, 0.94938, 0.94938, 0.94938, 0.94938, 0.94938, 0.9031, 0.81093, 0.94938, 0.94938, 0.94938, 0.94938, 0.98621, 0.98621, 0.98621, 0.98621, 0.93969, 0.95933, 0.9446, 0.9446, 0.9446, 0.9446, 0.9446, 1.08595, 0.9446, 0.95442, 0.95442, 0.95442, 0.95442, 0.94039, 0.97898, 0.94039, 0.90838, 0.94938, 0.90838, 0.94938, 0.90838, 0.94938, 0.82391, 0.81093, 0.82391, 0.81093, 0.82391, 0.81093, 0.82391, 0.81093, 0.96376, 0.84313, 0.97484, 0.97571, 0.80061, 0.94938, 0.80061, 0.94938, 0.80061, 0.94938, 0.80061, 0.94938, 0.80061, 0.94938, 0.8768, 0.9577, 0.8768, 0.9577, 0.8768, 0.9577, 1, 1, 0.95407, 0.95933, 0.97069, 0.95933, 1.0258, 0.98621, 1.0258, 0.98621, 1.0258, 0.98621, 1.0258, 0.98621, 1.0258, 0.98621, 0.887, 1.01591, 0.73901, 1.0474, 1, 1, 0.97455, 0.83655, 0.98981, 1, 1, 0.83655, 0.73977, 0.83655, 0.73903, 0.84638, 1.033, 0.95546, 0.95933, 1, 1, 0.95546, 0.95933, 0.8271, 0.95417, 0.95933, 0.92179, 0.9446, 0.92179, 0.9446, 0.92179, 0.9446, 0.936, 0.91964, 0.82114, 0.97646, 1, 1, 0.82114, 0.97646, 0.8096, 0.78036, 0.8096, 0.78036, 1, 1, 0.8096, 0.78036, 1, 1, 0.89713, 0.77452, 0.89713, 1.10208, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94438, 0.95442, 0.94083, 0.97579, 0.90406, 0.94039, 0.90406, 0.9446, 0.938, 0.9446, 0.938, 0.9446, 0.938, 1, 0.99793, 0.90838, 0.94938, 0.868, 0.9031, 0.92179, 0.9446, 1, 1, 0.89713, 1.10208, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90989, 0.9358, 0.91945, 0.83181, 0.75261, 0.87992, 0.82976, 0.96034, 0.83689, 0.97268, 1.0078, 0.90838, 0.83637, 0.8019, 0.90157, 0.80061, 0.9446, 0.95407, 0.92436, 1.0258, 0.85022, 0.97153, 1.0156, 0.95546, 0.89192, 0.92179, 0.92361, 0.87107, 0.96318, 0.89713, 0.93704, 0.95638, 0.91905, 0.91709, 0.92796, 1.0258, 0.93704, 0.94836, 1.0373, 0.95933, 1.0078, 0.95871, 0.94836, 0.96174, 0.92601, 0.9498, 0.98607, 0.95776, 0.95933, 1.05453, 1.0078, 0.98275, 0.9314, 0.95617, 0.91701, 1.05993, 0.9446, 0.78367, 0.9553, 1, 0.86832, 1.0128, 0.95871, 0.99394, 0.87548, 0.96361, 0.86774, 1.0078, 0.95871, 0.9446, 0.95871, 0.86774, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.94083, 0.97579, 0.94083, 0.97579, 0.94083, 0.97579, 0.90406, 0.94039, 0.96694, 1, 0.89903, 1, 1, 1, 0.93582, 0.93582, 0.93582, 1, 0.908, 0.908, 0.918, 0.94219, 0.94219, 0.96544, 1, 1.285, 1, 1, 0.81079, 0.81079, 1, 1, 0.74854, 1, 1, 1, 1, 0.99793, 1, 1, 1, 0.65, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.17173, 1, 0.80535, 0.76169, 1.02058, 1.0732, 1.05486, 1, 1, 1.30692, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.16161, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const MyriadProBoldMetrics = {
+ lineHeight: 1.2,
+ lineGap: 0.2
+};
+const MyriadProBoldItalicFactors = [1.36898, 1, 1, 0.66227, 0.80779, 0.81625, 0.97276, 0.97276, 0.97733, 0.92222, 0.83266, 0.94292, 0.94292, 1.16148, 1.02058, 0.93582, 0.96694, 0.93582, 1.17337, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.97276, 0.78076, 0.78076, 1.02058, 1.02058, 1.02058, 0.71541, 0.76813, 0.85576, 0.80591, 0.80729, 0.94299, 0.77512, 0.83655, 0.86523, 0.92222, 0.98621, 0.71743, 0.81698, 0.79726, 0.98558, 0.92222, 0.90637, 0.83809, 0.90637, 0.80729, 0.76463, 0.86275, 0.90699, 0.91605, 0.9154, 0.85308, 0.85458, 0.90531, 0.94292, 1.21296, 0.94292, 1.02058, 0.89903, 1.18616, 0.99613, 0.91677, 0.78216, 0.91677, 0.90083, 0.98796, 0.9135, 0.92168, 0.95381, 0.98981, 0.95298, 0.95381, 0.93459, 0.92168, 0.91513, 0.92004, 0.91677, 0.95077, 0.748, 1.04502, 0.91677, 0.92061, 0.94236, 0.89544, 0.89364, 0.9, 0.80687, 0.8578, 0.80687, 1.02058, 0.80779, 0.97276, 0.97276, 0.97276, 0.97276, 0.8578, 0.99973, 1.18616, 0.91339, 1.08074, 0.82891, 1.02058, 0.55509, 0.71526, 0.89022, 1.08595, 1, 1, 1.18616, 1, 0.96736, 0.93582, 1.18616, 1, 1.04864, 0.82711, 0.99043, 0.99043, 0.99043, 0.71541, 0.85576, 0.85576, 0.85576, 0.85576, 0.85576, 0.85576, 0.845, 0.80729, 0.77512, 0.77512, 0.77512, 0.77512, 0.98621, 0.98621, 0.98621, 0.98621, 0.95961, 0.92222, 0.90637, 0.90637, 0.90637, 0.90637, 0.90637, 1.02058, 0.90251, 0.90699, 0.90699, 0.90699, 0.90699, 0.85458, 0.83659, 0.94951, 0.99613, 0.99613, 0.99613, 0.99613, 0.99613, 0.99613, 0.85811, 0.78216, 0.90083, 0.90083, 0.90083, 0.90083, 0.95381, 0.95381, 0.95381, 0.95381, 0.9135, 0.92168, 0.91513, 0.91513, 0.91513, 0.91513, 0.91513, 1.08595, 0.91677, 0.91677, 0.91677, 0.91677, 0.91677, 0.89364, 0.92332, 0.89364, 0.85576, 0.99613, 0.85576, 0.99613, 0.85576, 0.99613, 0.80729, 0.78216, 0.80729, 0.78216, 0.80729, 0.78216, 0.80729, 0.78216, 0.94299, 0.76783, 0.95961, 0.91677, 0.77512, 0.90083, 0.77512, 0.90083, 0.77512, 0.90083, 0.77512, 0.90083, 0.77512, 0.90083, 0.86523, 0.9135, 0.86523, 0.9135, 0.86523, 0.9135, 1, 1, 0.92222, 0.92168, 0.92222, 0.92168, 0.98621, 0.95381, 0.98621, 0.95381, 0.98621, 0.95381, 0.98621, 0.95381, 0.98621, 0.95381, 0.86036, 0.97096, 0.71743, 0.98981, 1, 1, 0.95298, 0.79726, 0.95381, 1, 1, 0.79726, 0.6894, 0.79726, 0.74321, 0.81691, 1.0006, 0.92222, 0.92168, 1, 1, 0.92222, 0.92168, 0.79464, 0.92098, 0.92168, 0.90637, 0.91513, 0.90637, 0.91513, 0.90637, 0.91513, 0.909, 0.87514, 0.80729, 0.95077, 1, 1, 0.80729, 0.95077, 0.76463, 0.748, 0.76463, 0.748, 1, 1, 0.76463, 0.748, 1, 1, 0.86275, 0.72651, 0.86275, 1.04502, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.90699, 0.91677, 0.9154, 0.94236, 0.85458, 0.89364, 0.85458, 0.90531, 0.9, 0.90531, 0.9, 0.90531, 0.9, 1, 0.97276, 0.85576, 0.99613, 0.845, 0.85811, 0.90251, 0.91677, 1, 1, 0.86275, 1.04502, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.18616, 1.00899, 1.30628, 0.85576, 0.80178, 0.66862, 0.7927, 0.69323, 0.88127, 0.72459, 0.89711, 0.95381, 0.85576, 0.80591, 0.7805, 0.94729, 0.77512, 0.90531, 0.92222, 0.90637, 0.98621, 0.81698, 0.92655, 0.98558, 0.92222, 0.85359, 0.90637, 0.90976, 0.83809, 0.94523, 0.86275, 0.83509, 0.93157, 0.85308, 0.83392, 0.92346, 0.98621, 0.83509, 0.92886, 0.91324, 0.92168, 0.95381, 0.90646, 0.92886, 0.90557, 0.86847, 0.90276, 0.91324, 0.86842, 0.92168, 0.99531, 0.95381, 0.9224, 0.85408, 0.92699, 0.86847, 1.0051, 0.91513, 0.80487, 0.93481, 1, 0.88159, 1.05214, 0.90646, 0.97355, 0.81539, 0.89398, 0.85923, 0.95381, 0.90646, 0.91513, 0.90646, 0.85923, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9154, 0.94236, 0.9154, 0.94236, 0.9154, 0.94236, 0.85458, 0.89364, 0.96694, 1, 0.89903, 1, 1, 1, 0.91782, 0.91782, 0.91782, 1, 0.896, 0.896, 0.896, 0.9332, 0.9332, 0.95973, 1, 1.26, 1, 1, 0.80479, 0.80178, 1, 1, 0.85633, 1, 1, 1, 1, 0.97276, 1, 1, 1, 0.698, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.14542, 1, 0.79199, 0.78694, 1.02058, 1.03493, 1.05486, 1, 1, 1.23026, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.20006, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const MyriadProBoldItalicMetrics = {
+ lineHeight: 1.2,
+ lineGap: 0.2
+};
+const MyriadProItalicFactors = [1.36898, 1, 1, 0.65507, 0.84943, 0.85639, 0.88465, 0.88465, 0.86936, 0.88307, 0.86948, 0.85283, 0.85283, 1.06383, 1.02058, 0.75945, 0.9219, 0.75945, 1.17337, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.88465, 0.75945, 0.75945, 1.02058, 1.02058, 1.02058, 0.69046, 0.70926, 0.85158, 0.77812, 0.76852, 0.89591, 0.70466, 0.76125, 0.80094, 0.86822, 0.83864, 0.728, 0.77212, 0.79475, 0.93637, 0.87514, 0.8588, 0.76013, 0.8588, 0.72421, 0.69866, 0.77598, 0.85991, 0.80811, 0.87832, 0.78112, 0.77512, 0.8562, 1.0222, 1.18417, 1.0222, 1.27014, 0.89903, 1.15012, 0.93859, 0.94399, 0.846, 0.94399, 0.81453, 1.0186, 0.94219, 0.96017, 1.03075, 1.02175, 0.912, 1.03075, 0.96998, 0.96017, 0.93859, 0.94399, 0.94399, 0.95493, 0.746, 1.12658, 0.94578, 0.91, 0.979, 0.882, 0.882, 0.83, 0.85034, 0.83537, 0.85034, 1.02058, 0.70869, 0.88465, 0.88465, 0.88465, 0.88465, 0.83537, 0.90083, 1.15012, 0.9161, 0.94565, 0.73541, 1.02058, 0.53609, 0.69353, 0.79519, 1.08595, 1, 1, 1.15012, 1, 0.91974, 0.75945, 1.15012, 1, 0.9446, 0.73361, 0.9005, 0.9005, 0.9005, 0.62864, 0.85158, 0.85158, 0.85158, 0.85158, 0.85158, 0.85158, 0.773, 0.76852, 0.70466, 0.70466, 0.70466, 0.70466, 0.83864, 0.83864, 0.83864, 0.83864, 0.90561, 0.87514, 0.8588, 0.8588, 0.8588, 0.8588, 0.8588, 1.02058, 0.85751, 0.85991, 0.85991, 0.85991, 0.85991, 0.77512, 0.76013, 0.88075, 0.93859, 0.93859, 0.93859, 0.93859, 0.93859, 0.93859, 0.8075, 0.846, 0.81453, 0.81453, 0.81453, 0.81453, 0.82424, 0.82424, 0.82424, 0.82424, 0.9278, 0.96017, 0.93859, 0.93859, 0.93859, 0.93859, 0.93859, 1.08595, 0.8562, 0.94578, 0.94578, 0.94578, 0.94578, 0.882, 0.94578, 0.882, 0.85158, 0.93859, 0.85158, 0.93859, 0.85158, 0.93859, 0.76852, 0.846, 0.76852, 0.846, 0.76852, 0.846, 0.76852, 0.846, 0.89591, 0.8544, 0.90561, 0.94399, 0.70466, 0.81453, 0.70466, 0.81453, 0.70466, 0.81453, 0.70466, 0.81453, 0.70466, 0.81453, 0.80094, 0.94219, 0.80094, 0.94219, 0.80094, 0.94219, 1, 1, 0.86822, 0.96017, 0.86822, 0.96017, 0.83864, 0.82424, 0.83864, 0.82424, 0.83864, 0.82424, 0.83864, 1.03075, 0.83864, 0.82424, 0.81402, 1.02738, 0.728, 1.02175, 1, 1, 0.912, 0.79475, 1.03075, 1, 1, 0.79475, 0.83911, 0.79475, 0.66266, 0.80553, 1.06676, 0.87514, 0.96017, 1, 1, 0.87514, 0.96017, 0.86865, 0.87396, 0.96017, 0.8588, 0.93859, 0.8588, 0.93859, 0.8588, 0.93859, 0.867, 0.84759, 0.72421, 0.95493, 1, 1, 0.72421, 0.95493, 0.69866, 0.746, 0.69866, 0.746, 1, 1, 0.69866, 0.746, 1, 1, 0.77598, 0.88417, 0.77598, 1.12658, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.85991, 0.94578, 0.87832, 0.979, 0.77512, 0.882, 0.77512, 0.8562, 0.83, 0.8562, 0.83, 0.8562, 0.83, 1, 0.88465, 0.85158, 0.93859, 0.773, 0.8075, 0.85751, 0.8562, 1, 1, 0.77598, 1.12658, 1.15012, 1.15012, 1.15012, 1.15012, 1.15012, 1.15313, 1.15012, 1.15012, 1.15012, 1.08106, 1.03901, 0.85158, 0.77025, 0.62264, 0.7646, 0.65351, 0.86026, 0.69461, 0.89947, 1.03075, 0.85158, 0.77812, 0.76449, 0.88836, 0.70466, 0.8562, 0.86822, 0.8588, 0.83864, 0.77212, 0.85308, 0.93637, 0.87514, 0.82352, 0.8588, 0.85701, 0.76013, 0.89058, 0.77598, 0.8156, 0.82565, 0.78112, 0.77899, 0.89386, 0.83864, 0.8156, 0.9486, 0.92388, 0.96186, 1.03075, 0.91123, 0.9486, 0.93298, 0.878, 0.93942, 0.92388, 0.84596, 0.96186, 0.95119, 1.03075, 0.922, 0.88787, 0.95829, 0.88, 0.93559, 0.93859, 0.78815, 0.93758, 1, 0.89217, 1.03737, 0.91123, 0.93969, 0.77487, 0.85769, 0.86799, 1.03075, 0.91123, 0.93859, 0.91123, 0.86799, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87832, 0.979, 0.87832, 0.979, 0.87832, 0.979, 0.77512, 0.882, 0.9219, 1, 0.89903, 1, 1, 1, 0.87321, 0.87321, 0.87321, 1, 1.027, 1.027, 1.027, 0.86847, 0.86847, 0.79121, 1, 1.124, 1, 1, 0.73572, 0.73572, 1, 1, 0.85034, 1, 1, 1, 1, 0.88465, 1, 1, 1, 0.669, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.04828, 1, 0.74948, 0.75187, 1.02058, 0.98391, 1.02119, 1, 1, 1.06233, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05233, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const MyriadProItalicMetrics = {
+ lineHeight: 1.2,
+ lineGap: 0.2
+};
+const MyriadProRegularFactors = [1.36898, 1, 1, 0.76305, 0.82784, 0.94935, 0.89364, 0.92241, 0.89073, 0.90706, 0.98472, 0.85283, 0.85283, 1.0664, 1.02058, 0.74505, 0.9219, 0.74505, 1.23456, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.92241, 0.74505, 0.74505, 1.02058, 1.02058, 1.02058, 0.73002, 0.72601, 0.91755, 0.8126, 0.80314, 0.92222, 0.73764, 0.79726, 0.83051, 0.90284, 0.86023, 0.74, 0.8126, 0.84869, 0.96518, 0.91115, 0.8858, 0.79761, 0.8858, 0.74498, 0.73914, 0.81363, 0.89591, 0.83659, 0.89633, 0.85608, 0.8111, 0.90531, 1.0222, 1.22736, 1.0222, 1.27014, 0.89903, 0.90088, 0.86667, 1.0231, 0.896, 1.01411, 0.90083, 1.05099, 1.00512, 0.99793, 1.05326, 1.09377, 0.938, 1.06226, 1.00119, 0.99793, 0.98714, 1.0231, 1.01231, 0.98196, 0.792, 1.19137, 0.99074, 0.962, 1.01915, 0.926, 0.942, 0.856, 0.85034, 0.92006, 0.85034, 1.02058, 0.69067, 0.92241, 0.92241, 0.92241, 0.92241, 0.92006, 0.9332, 0.90088, 0.91882, 0.93484, 0.75339, 1.02058, 0.56866, 0.54324, 0.79519, 1.08595, 1, 1, 0.90088, 1, 0.95325, 0.74505, 0.90088, 1, 0.97198, 0.75339, 0.91009, 0.91009, 0.91009, 0.66466, 0.91755, 0.91755, 0.91755, 0.91755, 0.91755, 0.91755, 0.788, 0.80314, 0.73764, 0.73764, 0.73764, 0.73764, 0.86023, 0.86023, 0.86023, 0.86023, 0.92915, 0.91115, 0.8858, 0.8858, 0.8858, 0.8858, 0.8858, 1.02058, 0.8858, 0.89591, 0.89591, 0.89591, 0.89591, 0.8111, 0.79611, 0.89713, 0.86667, 0.86667, 0.86667, 0.86667, 0.86667, 0.86667, 0.86936, 0.896, 0.90083, 0.90083, 0.90083, 0.90083, 0.84224, 0.84224, 0.84224, 0.84224, 0.97276, 0.99793, 0.98714, 0.98714, 0.98714, 0.98714, 0.98714, 1.08595, 0.89876, 0.99074, 0.99074, 0.99074, 0.99074, 0.942, 1.0231, 0.942, 0.91755, 0.86667, 0.91755, 0.86667, 0.91755, 0.86667, 0.80314, 0.896, 0.80314, 0.896, 0.80314, 0.896, 0.80314, 0.896, 0.92222, 0.93372, 0.92915, 1.01411, 0.73764, 0.90083, 0.73764, 0.90083, 0.73764, 0.90083, 0.73764, 0.90083, 0.73764, 0.90083, 0.83051, 1.00512, 0.83051, 1.00512, 0.83051, 1.00512, 1, 1, 0.90284, 0.99793, 0.90976, 0.99793, 0.86023, 0.84224, 0.86023, 0.84224, 0.86023, 0.84224, 0.86023, 1.05326, 0.86023, 0.84224, 0.82873, 1.07469, 0.74, 1.09377, 1, 1, 0.938, 0.84869, 1.06226, 1, 1, 0.84869, 0.83704, 0.84869, 0.81441, 0.85588, 1.08927, 0.91115, 0.99793, 1, 1, 0.91115, 0.99793, 0.91887, 0.90991, 0.99793, 0.8858, 0.98714, 0.8858, 0.98714, 0.8858, 0.98714, 0.894, 0.91434, 0.74498, 0.98196, 1, 1, 0.74498, 0.98196, 0.73914, 0.792, 0.73914, 0.792, 1, 1, 0.73914, 0.792, 1, 1, 0.81363, 0.904, 0.81363, 1.19137, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89591, 0.99074, 0.89633, 1.01915, 0.8111, 0.942, 0.8111, 0.90531, 0.856, 0.90531, 0.856, 0.90531, 0.856, 1, 0.92241, 0.91755, 0.86667, 0.788, 0.86936, 0.8858, 0.89876, 1, 1, 0.81363, 1.19137, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90088, 0.90388, 1.03901, 0.92138, 0.78105, 0.7154, 0.86169, 0.80513, 0.94007, 0.82528, 0.98612, 1.06226, 0.91755, 0.8126, 0.81884, 0.92819, 0.73764, 0.90531, 0.90284, 0.8858, 0.86023, 0.8126, 0.91172, 0.96518, 0.91115, 0.83089, 0.8858, 0.87791, 0.79761, 0.89297, 0.81363, 0.88157, 0.89992, 0.85608, 0.81992, 0.94307, 0.86023, 0.88157, 0.95308, 0.98699, 0.99793, 1.06226, 0.95817, 0.95308, 0.97358, 0.928, 0.98088, 0.98699, 0.92761, 0.99793, 0.96017, 1.06226, 0.986, 0.944, 0.95978, 0.938, 0.96705, 0.98714, 0.80442, 0.98972, 1, 0.89762, 1.04552, 0.95817, 0.99007, 0.87064, 0.91879, 0.88888, 1.06226, 0.95817, 0.98714, 0.95817, 0.88888, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.89633, 1.01915, 0.89633, 1.01915, 0.89633, 1.01915, 0.8111, 0.942, 0.9219, 1, 0.89903, 1, 1, 1, 0.93173, 0.93173, 0.93173, 1, 1.06304, 1.06304, 1.06904, 0.89903, 0.89903, 0.80549, 1, 1.156, 1, 1, 0.76575, 0.76575, 1, 1, 0.72458, 1, 1, 1, 1, 0.92241, 1, 1, 1, 0.619, 1, 1.36145, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.07257, 1, 0.74705, 0.71119, 1.02058, 1.024, 1.02119, 1, 1, 1.1536, 1.08595, 1.08595, 1, 1.08595, 1.08595, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.05638, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const MyriadProRegularMetrics = {
+ lineHeight: 1.2,
+ lineGap: 0.2
+};
+
+;// ./src/core/segoeui_factors.js
+const SegoeuiBoldFactors = [1.76738, 1, 1, 0.99297, 0.9824, 1.04016, 1.06497, 1.03424, 0.97529, 1.17647, 1.23203, 1.1085, 1.1085, 1.16939, 1.2107, 0.9754, 1.21408, 0.9754, 1.59578, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 1.03424, 0.81378, 0.81378, 1.2107, 1.2107, 1.2107, 0.71703, 0.97847, 0.97363, 0.88776, 0.8641, 1.02096, 0.79795, 0.85132, 0.914, 1.06085, 1.1406, 0.8007, 0.89858, 0.83693, 1.14889, 1.09398, 0.97489, 0.92094, 0.97489, 0.90399, 0.84041, 0.95923, 1.00135, 1, 1.06467, 0.98243, 0.90996, 0.99361, 1.1085, 1.56942, 1.1085, 1.2107, 0.74627, 0.94282, 0.96752, 1.01519, 0.86304, 1.01359, 0.97278, 1.15103, 1.01359, 0.98561, 1.02285, 1.02285, 1.00527, 1.02285, 1.0302, 0.99041, 1.0008, 1.01519, 1.01359, 1.02258, 0.79104, 1.16862, 0.99041, 0.97454, 1.02511, 0.99298, 0.96752, 0.95801, 0.94856, 1.16579, 0.94856, 1.2107, 0.9824, 1.03424, 1.03424, 1, 1.03424, 1.16579, 0.8727, 1.3871, 1.18622, 1.10818, 1.04478, 1.2107, 1.18622, 0.75155, 0.94994, 1.28826, 1.21408, 1.21408, 0.91056, 1, 0.91572, 0.9754, 0.64663, 1.18328, 1.24866, 1.04478, 1.14169, 1.15749, 1.17389, 0.71703, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.93506, 0.8641, 0.79795, 0.79795, 0.79795, 0.79795, 1.1406, 1.1406, 1.1406, 1.1406, 1.02096, 1.09398, 0.97426, 0.97426, 0.97426, 0.97426, 0.97426, 1.2107, 0.97489, 1.00135, 1.00135, 1.00135, 1.00135, 0.90996, 0.92094, 1.02798, 0.96752, 0.96752, 0.96752, 0.96752, 0.96752, 0.96752, 0.93136, 0.86304, 0.97278, 0.97278, 0.97278, 0.97278, 1.02285, 1.02285, 1.02285, 1.02285, 0.97122, 0.99041, 1, 1, 1, 1, 1, 1.28826, 1.0008, 0.99041, 0.99041, 0.99041, 0.99041, 0.96752, 1.01519, 0.96752, 0.97363, 0.96752, 0.97363, 0.96752, 0.97363, 0.96752, 0.8641, 0.86304, 0.8641, 0.86304, 0.8641, 0.86304, 0.8641, 0.86304, 1.02096, 1.03057, 1.02096, 1.03517, 0.79795, 0.97278, 0.79795, 0.97278, 0.79795, 0.97278, 0.79795, 0.97278, 0.79795, 0.97278, 0.914, 1.01359, 0.914, 1.01359, 0.914, 1.01359, 1, 1, 1.06085, 0.98561, 1.06085, 1.00879, 1.1406, 1.02285, 1.1406, 1.02285, 1.1406, 1.02285, 1.1406, 1.02285, 1.1406, 1.02285, 0.97138, 1.08692, 0.8007, 1.02285, 1, 1, 1.00527, 0.83693, 1.02285, 1, 1, 0.83693, 0.9455, 0.83693, 0.90418, 0.83693, 1.13005, 1.09398, 0.99041, 1, 1, 1.09398, 0.99041, 0.96692, 1.09251, 0.99041, 0.97489, 1.0008, 0.97489, 1.0008, 0.97489, 1.0008, 0.93994, 0.97931, 0.90399, 1.02258, 1, 1, 0.90399, 1.02258, 0.84041, 0.79104, 0.84041, 0.79104, 0.84041, 0.79104, 0.84041, 0.79104, 1, 1, 0.95923, 1.07034, 0.95923, 1.16862, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.00135, 0.99041, 1.06467, 1.02511, 0.90996, 0.96752, 0.90996, 0.99361, 0.95801, 0.99361, 0.95801, 0.99361, 0.95801, 1.07733, 1.03424, 0.97363, 0.96752, 0.93506, 0.93136, 0.97489, 1.0008, 1, 1, 0.95923, 1.16862, 1.15103, 1.15103, 1.01173, 1.03959, 0.75953, 0.81378, 0.79912, 1.15103, 1.21994, 0.95161, 0.87815, 1.01149, 0.81525, 0.7676, 0.98167, 1.01134, 1.02546, 0.84097, 1.03089, 1.18102, 0.97363, 0.88776, 0.85134, 0.97826, 0.79795, 0.99361, 1.06085, 0.97489, 1.1406, 0.89858, 1.0388, 1.14889, 1.09398, 0.86039, 0.97489, 1.0595, 0.92094, 0.94793, 0.95923, 0.90996, 0.99346, 0.98243, 1.02112, 0.95493, 1.1406, 0.90996, 1.03574, 1.02597, 1.0008, 1.18102, 1.06628, 1.03574, 1.0192, 1.01932, 1.00886, 0.97531, 1.0106, 1.0008, 1.13189, 1.18102, 1.02277, 0.98683, 1.0016, 0.99561, 1.07237, 1.0008, 0.90434, 0.99921, 0.93803, 0.8965, 1.23085, 1.06628, 1.04983, 0.96268, 1.0499, 0.98439, 1.18102, 1.06628, 1.0008, 1.06628, 0.98439, 0.79795, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.09466, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.97278, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.02065, 1, 1, 1, 1, 1, 1, 1.06467, 1.02511, 1.06467, 1.02511, 1.06467, 1.02511, 0.90996, 0.96752, 1, 1.21408, 0.89903, 1, 1, 0.75155, 1.04394, 1.04394, 1.04394, 1.04394, 0.98633, 0.98633, 0.98633, 0.73047, 0.73047, 1.20642, 0.91211, 1.25635, 1.222, 1.02956, 1.03372, 1.03372, 0.96039, 1.24633, 1, 1.12454, 0.93503, 1.03424, 1.19687, 1.03424, 1, 1, 1, 0.771, 1, 1, 1.15749, 1.15749, 1.15749, 1.10948, 0.86279, 0.94434, 0.86279, 0.94434, 0.86182, 1, 1, 1.16897, 1, 0.96085, 0.90137, 1.2107, 1.18416, 1.13973, 0.69825, 0.9716, 2.10339, 1.29004, 1.29004, 1.21172, 1.29004, 1.29004, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.18874, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.09193, 1.09193, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const SegoeuiBoldMetrics = {
+ lineHeight: 1.33008,
+ lineGap: 0
+};
+const SegoeuiBoldItalicFactors = [1.76738, 1, 1, 0.98946, 1.03959, 1.04016, 1.02809, 1.036, 0.97639, 1.10953, 1.23203, 1.11144, 1.11144, 1.16939, 1.21237, 0.9754, 1.21261, 0.9754, 1.59754, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 1.036, 0.81378, 0.81378, 1.21237, 1.21237, 1.21237, 0.73541, 0.97847, 0.97363, 0.89723, 0.87897, 1.0426, 0.79429, 0.85292, 0.91149, 1.05815, 1.1406, 0.79631, 0.90128, 0.83853, 1.04396, 1.10615, 0.97552, 0.94436, 0.97552, 0.88641, 0.80527, 0.96083, 1.00135, 1, 1.06777, 0.9817, 0.91142, 0.99361, 1.11144, 1.57293, 1.11144, 1.21237, 0.74627, 1.31818, 1.06585, 0.97042, 0.83055, 0.97042, 0.93503, 1.1261, 0.97042, 0.97922, 1.14236, 0.94552, 1.01054, 1.14236, 1.02471, 0.97922, 0.94165, 0.97042, 0.97042, 1.0276, 0.78929, 1.1261, 0.97922, 0.95874, 1.02197, 0.98507, 0.96752, 0.97168, 0.95107, 1.16579, 0.95107, 1.21237, 1.03959, 1.036, 1.036, 1, 1.036, 1.16579, 0.87357, 1.31818, 1.18754, 1.26781, 1.05356, 1.21237, 1.18622, 0.79487, 0.94994, 1.29004, 1.24047, 1.24047, 1.31818, 1, 0.91484, 0.9754, 1.31818, 1.1349, 1.24866, 1.05356, 1.13934, 1.15574, 1.17389, 0.73541, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.97363, 0.94385, 0.87897, 0.79429, 0.79429, 0.79429, 0.79429, 1.1406, 1.1406, 1.1406, 1.1406, 1.0426, 1.10615, 0.97552, 0.97552, 0.97552, 0.97552, 0.97552, 1.21237, 0.97552, 1.00135, 1.00135, 1.00135, 1.00135, 0.91142, 0.94436, 0.98721, 1.06585, 1.06585, 1.06585, 1.06585, 1.06585, 1.06585, 0.96705, 0.83055, 0.93503, 0.93503, 0.93503, 0.93503, 1.14236, 1.14236, 1.14236, 1.14236, 0.93125, 0.97922, 0.94165, 0.94165, 0.94165, 0.94165, 0.94165, 1.29004, 0.94165, 0.97922, 0.97922, 0.97922, 0.97922, 0.96752, 0.97042, 0.96752, 0.97363, 1.06585, 0.97363, 1.06585, 0.97363, 1.06585, 0.87897, 0.83055, 0.87897, 0.83055, 0.87897, 0.83055, 0.87897, 0.83055, 1.0426, 1.0033, 1.0426, 0.97042, 0.79429, 0.93503, 0.79429, 0.93503, 0.79429, 0.93503, 0.79429, 0.93503, 0.79429, 0.93503, 0.91149, 0.97042, 0.91149, 0.97042, 0.91149, 0.97042, 1, 1, 1.05815, 0.97922, 1.05815, 0.97922, 1.1406, 1.14236, 1.1406, 1.14236, 1.1406, 1.14236, 1.1406, 1.14236, 1.1406, 1.14236, 0.97441, 1.04302, 0.79631, 1.01582, 1, 1, 1.01054, 0.83853, 1.14236, 1, 1, 0.83853, 1.09125, 0.83853, 0.90418, 0.83853, 1.19508, 1.10615, 0.97922, 1, 1, 1.10615, 0.97922, 1.01034, 1.10466, 0.97922, 0.97552, 0.94165, 0.97552, 0.94165, 0.97552, 0.94165, 0.91602, 0.91981, 0.88641, 1.0276, 1, 1, 0.88641, 1.0276, 0.80527, 0.78929, 0.80527, 0.78929, 0.80527, 0.78929, 0.80527, 0.78929, 1, 1, 0.96083, 1.05403, 0.95923, 1.16862, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.00135, 0.97922, 1.06777, 1.02197, 0.91142, 0.96752, 0.91142, 0.99361, 0.97168, 0.99361, 0.97168, 0.99361, 0.97168, 1.23199, 1.036, 0.97363, 1.06585, 0.94385, 0.96705, 0.97552, 0.94165, 1, 1, 0.96083, 1.1261, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 1.31818, 0.95161, 1.27126, 1.00811, 0.83284, 0.77702, 0.99137, 0.95253, 1.0347, 0.86142, 1.07205, 1.14236, 0.97363, 0.89723, 0.86869, 1.09818, 0.79429, 0.99361, 1.05815, 0.97552, 1.1406, 0.90128, 1.06662, 1.04396, 1.10615, 0.84918, 0.97552, 1.04694, 0.94436, 0.98015, 0.96083, 0.91142, 1.00356, 0.9817, 1.01945, 0.98999, 1.1406, 0.91142, 1.04961, 0.9898, 1.00639, 1.14236, 1.07514, 1.04961, 0.99607, 1.02897, 1.008, 0.9898, 0.95134, 1.00639, 1.11121, 1.14236, 1.00518, 0.97981, 1.02186, 1, 1.08578, 0.94165, 0.99314, 0.98387, 0.93028, 0.93377, 1.35125, 1.07514, 1.10687, 0.93491, 1.04232, 1.00351, 1.14236, 1.07514, 0.94165, 1.07514, 1.00351, 0.79429, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.09097, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.93503, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.96609, 1, 1, 1, 1, 1, 1, 1.06777, 1.02197, 1.06777, 1.02197, 1.06777, 1.02197, 0.91142, 0.96752, 1, 1.21261, 0.89903, 1, 1, 0.75155, 1.04745, 1.04745, 1.04745, 1.04394, 0.98633, 0.98633, 0.98633, 0.72959, 0.72959, 1.20502, 0.91406, 1.26514, 1.222, 1.02956, 1.03372, 1.03372, 0.96039, 1.24633, 1, 1.09125, 0.93327, 1.03336, 1.16541, 1.036, 1, 1, 1, 0.771, 1, 1, 1.15574, 1.15574, 1.15574, 1.15574, 0.86364, 0.94434, 0.86279, 0.94434, 0.86224, 1, 1, 1.16798, 1, 0.96085, 0.90068, 1.21237, 1.18416, 1.13904, 0.69825, 0.9716, 2.10339, 1.29004, 1.29004, 1.21339, 1.29004, 1.29004, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.18775, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.13269, 1.13269, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const SegoeuiBoldItalicMetrics = {
+ lineHeight: 1.33008,
+ lineGap: 0
+};
+const SegoeuiItalicFactors = [1.76738, 1, 1, 0.98946, 1.14763, 1.05365, 1.06234, 0.96927, 0.92586, 1.15373, 1.18414, 0.91349, 0.91349, 1.07403, 1.17308, 0.78383, 1.20088, 0.78383, 1.42531, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.78383, 0.78383, 1.17308, 1.17308, 1.17308, 0.77349, 0.94565, 0.94729, 0.85944, 0.88506, 0.9858, 0.74817, 0.80016, 0.88449, 0.98039, 0.95782, 0.69238, 0.89898, 0.83231, 0.98183, 1.03989, 0.96924, 0.86237, 0.96924, 0.80595, 0.74524, 0.86091, 0.95402, 0.94143, 0.98448, 0.8858, 0.83089, 0.93285, 1.0949, 1.39016, 1.0949, 1.45994, 0.74627, 1.04839, 0.97454, 0.97454, 0.87207, 0.97454, 0.87533, 1.06151, 0.97454, 1.00176, 1.16484, 1.08132, 0.98047, 1.16484, 1.02989, 1.01054, 0.96225, 0.97454, 0.97454, 1.06598, 0.79004, 1.16344, 1.00351, 0.94629, 0.9973, 0.91016, 0.96777, 0.9043, 0.91082, 0.92481, 0.91082, 1.17308, 0.95748, 0.96927, 0.96927, 1, 0.96927, 0.92481, 0.80597, 1.04839, 1.23393, 1.1781, 0.9245, 1.17308, 1.20808, 0.63218, 0.94261, 1.24822, 1.09971, 1.09971, 1.04839, 1, 0.85273, 0.78032, 1.04839, 1.09971, 1.22326, 0.9245, 1.09836, 1.13525, 1.15222, 0.70424, 0.94729, 0.94729, 0.94729, 0.94729, 0.94729, 0.94729, 0.85498, 0.88506, 0.74817, 0.74817, 0.74817, 0.74817, 0.95782, 0.95782, 0.95782, 0.95782, 0.9858, 1.03989, 0.96924, 0.96924, 0.96924, 0.96924, 0.96924, 1.17308, 0.96924, 0.95402, 0.95402, 0.95402, 0.95402, 0.83089, 0.86237, 0.88409, 0.97454, 0.97454, 0.97454, 0.97454, 0.97454, 0.97454, 0.92916, 0.87207, 0.87533, 0.87533, 0.87533, 0.87533, 0.93146, 0.93146, 0.93146, 0.93146, 0.93854, 1.01054, 0.96225, 0.96225, 0.96225, 0.96225, 0.96225, 1.24822, 0.8761, 1.00351, 1.00351, 1.00351, 1.00351, 0.96777, 0.97454, 0.96777, 0.94729, 0.97454, 0.94729, 0.97454, 0.94729, 0.97454, 0.88506, 0.87207, 0.88506, 0.87207, 0.88506, 0.87207, 0.88506, 0.87207, 0.9858, 0.95391, 0.9858, 0.97454, 0.74817, 0.87533, 0.74817, 0.87533, 0.74817, 0.87533, 0.74817, 0.87533, 0.74817, 0.87533, 0.88449, 0.97454, 0.88449, 0.97454, 0.88449, 0.97454, 1, 1, 0.98039, 1.00176, 0.98039, 1.00176, 0.95782, 0.93146, 0.95782, 0.93146, 0.95782, 0.93146, 0.95782, 1.16484, 0.95782, 0.93146, 0.84421, 1.12761, 0.69238, 1.08132, 1, 1, 0.98047, 0.83231, 1.16484, 1, 1, 0.84723, 1.04861, 0.84723, 0.78755, 0.83231, 1.23736, 1.03989, 1.01054, 1, 1, 1.03989, 1.01054, 0.9857, 1.03849, 1.01054, 0.96924, 0.96225, 0.96924, 0.96225, 0.96924, 0.96225, 0.92383, 0.90171, 0.80595, 1.06598, 1, 1, 0.80595, 1.06598, 0.74524, 0.79004, 0.74524, 0.79004, 0.74524, 0.79004, 0.74524, 0.79004, 1, 1, 0.86091, 1.02759, 0.85771, 1.16344, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.95402, 1.00351, 0.98448, 0.9973, 0.83089, 0.96777, 0.83089, 0.93285, 0.9043, 0.93285, 0.9043, 0.93285, 0.9043, 1.31868, 0.96927, 0.94729, 0.97454, 0.85498, 0.92916, 0.96924, 0.8761, 1, 1, 0.86091, 1.16344, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 1.04839, 0.81965, 0.81965, 0.94729, 0.78032, 0.71022, 0.90883, 0.84171, 0.99877, 0.77596, 1.05734, 1.2, 0.94729, 0.85944, 0.82791, 0.9607, 0.74817, 0.93285, 0.98039, 0.96924, 0.95782, 0.89898, 0.98316, 0.98183, 1.03989, 0.78614, 0.96924, 0.97642, 0.86237, 0.86075, 0.86091, 0.83089, 0.90082, 0.8858, 0.97296, 1.01284, 0.95782, 0.83089, 1.0976, 1.04, 1.03342, 1.2, 1.0675, 1.0976, 0.98205, 1.03809, 1.05097, 1.04, 0.95364, 1.03342, 1.05401, 1.2, 1.02148, 1.0119, 1.04724, 1.0127, 1.02732, 0.96225, 0.8965, 0.97783, 0.93574, 0.94818, 1.30679, 1.0675, 1.11826, 0.99821, 1.0557, 1.0326, 1.2, 1.0675, 0.96225, 1.0675, 1.0326, 0.74817, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.03754, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.87533, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.98705, 1, 1, 1, 1, 1, 1, 0.98448, 0.9973, 0.98448, 0.9973, 0.98448, 0.9973, 0.83089, 0.96777, 1, 1.20088, 0.89903, 1, 1, 0.75155, 0.94945, 0.94945, 0.94945, 0.94945, 1.12317, 1.12317, 1.12317, 0.67603, 0.67603, 1.15621, 0.73584, 1.21191, 1.22135, 1.06483, 0.94868, 0.94868, 0.95996, 1.24633, 1, 1.07497, 0.87709, 0.96927, 1.01473, 0.96927, 1, 1, 1, 0.77295, 1, 1, 1.09836, 1.09836, 1.09836, 1.01522, 0.86321, 0.94434, 0.8649, 0.94434, 0.86182, 1, 1, 1.083, 1, 0.91578, 0.86438, 1.17308, 1.18416, 1.14589, 0.69825, 0.97622, 1.96791, 1.24822, 1.24822, 1.17308, 1.24822, 1.24822, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.17984, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.10742, 1.10742, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const SegoeuiItalicMetrics = {
+ lineHeight: 1.33008,
+ lineGap: 0
+};
+const SegoeuiRegularFactors = [1.76738, 1, 1, 0.98594, 1.02285, 1.10454, 1.06234, 0.96927, 0.92037, 1.19985, 1.2046, 0.90616, 0.90616, 1.07152, 1.1714, 0.78032, 1.20088, 0.78032, 1.40246, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.96927, 0.78032, 0.78032, 1.1714, 1.1714, 1.1714, 0.80597, 0.94084, 0.96706, 0.85944, 0.85734, 0.97093, 0.75842, 0.79936, 0.88198, 0.9831, 0.95782, 0.71387, 0.86969, 0.84636, 1.07796, 1.03584, 0.96924, 0.83968, 0.96924, 0.82826, 0.79649, 0.85771, 0.95132, 0.93119, 0.98965, 0.88433, 0.8287, 0.93365, 1.08612, 1.3638, 1.08612, 1.45786, 0.74627, 0.80499, 0.91484, 1.05707, 0.92383, 1.05882, 0.9403, 1.12654, 1.05882, 1.01756, 1.09011, 1.09011, 0.99414, 1.09011, 1.034, 1.01756, 1.05356, 1.05707, 1.05882, 1.04399, 0.84863, 1.21968, 1.01756, 0.95801, 1.00068, 0.91797, 0.96777, 0.9043, 0.90351, 0.92105, 0.90351, 1.1714, 0.85337, 0.96927, 0.96927, 0.99912, 0.96927, 0.92105, 0.80597, 1.2434, 1.20808, 1.05937, 0.90957, 1.1714, 1.20808, 0.75155, 0.94261, 1.24644, 1.09971, 1.09971, 0.84751, 1, 0.85273, 0.78032, 0.61584, 1.05425, 1.17914, 0.90957, 1.08665, 1.11593, 1.14169, 0.73381, 0.96706, 0.96706, 0.96706, 0.96706, 0.96706, 0.96706, 0.86035, 0.85734, 0.75842, 0.75842, 0.75842, 0.75842, 0.95782, 0.95782, 0.95782, 0.95782, 0.97093, 1.03584, 0.96924, 0.96924, 0.96924, 0.96924, 0.96924, 1.1714, 0.96924, 0.95132, 0.95132, 0.95132, 0.95132, 0.8287, 0.83968, 0.89049, 0.91484, 0.91484, 0.91484, 0.91484, 0.91484, 0.91484, 0.93575, 0.92383, 0.9403, 0.9403, 0.9403, 0.9403, 0.8717, 0.8717, 0.8717, 0.8717, 1.00527, 1.01756, 1.05356, 1.05356, 1.05356, 1.05356, 1.05356, 1.24644, 0.95923, 1.01756, 1.01756, 1.01756, 1.01756, 0.96777, 1.05707, 0.96777, 0.96706, 0.91484, 0.96706, 0.91484, 0.96706, 0.91484, 0.85734, 0.92383, 0.85734, 0.92383, 0.85734, 0.92383, 0.85734, 0.92383, 0.97093, 1.0969, 0.97093, 1.05882, 0.75842, 0.9403, 0.75842, 0.9403, 0.75842, 0.9403, 0.75842, 0.9403, 0.75842, 0.9403, 0.88198, 1.05882, 0.88198, 1.05882, 0.88198, 1.05882, 1, 1, 0.9831, 1.01756, 0.9831, 1.01756, 0.95782, 0.8717, 0.95782, 0.8717, 0.95782, 0.8717, 0.95782, 1.09011, 0.95782, 0.8717, 0.84784, 1.11551, 0.71387, 1.09011, 1, 1, 0.99414, 0.84636, 1.09011, 1, 1, 0.84636, 1.0536, 0.84636, 0.94298, 0.84636, 1.23297, 1.03584, 1.01756, 1, 1, 1.03584, 1.01756, 1.00323, 1.03444, 1.01756, 0.96924, 1.05356, 0.96924, 1.05356, 0.96924, 1.05356, 0.93066, 0.98293, 0.82826, 1.04399, 1, 1, 0.82826, 1.04399, 0.79649, 0.84863, 0.79649, 0.84863, 0.79649, 0.84863, 0.79649, 0.84863, 1, 1, 0.85771, 1.17318, 0.85771, 1.21968, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.95132, 1.01756, 0.98965, 1.00068, 0.8287, 0.96777, 0.8287, 0.93365, 0.9043, 0.93365, 0.9043, 0.93365, 0.9043, 1.08571, 0.96927, 0.96706, 0.91484, 0.86035, 0.93575, 0.96924, 0.95923, 1, 1, 0.85771, 1.21968, 1.11437, 1.11437, 0.93109, 0.91202, 0.60411, 0.84164, 0.55572, 1.01173, 0.97361, 0.81818, 0.81818, 0.96635, 0.78032, 0.72727, 0.92366, 0.98601, 1.03405, 0.77968, 1.09799, 1.2, 0.96706, 0.85944, 0.85638, 0.96491, 0.75842, 0.93365, 0.9831, 0.96924, 0.95782, 0.86969, 0.94152, 1.07796, 1.03584, 0.78437, 0.96924, 0.98715, 0.83968, 0.83491, 0.85771, 0.8287, 0.94492, 0.88433, 0.9287, 1.0098, 0.95782, 0.8287, 1.0625, 0.98248, 1.03424, 1.2, 1.01071, 1.0625, 0.95246, 1.03809, 1.04912, 0.98248, 1.00221, 1.03424, 1.05443, 1.2, 1.04785, 0.99609, 1.00169, 1.05176, 0.99346, 1.05356, 0.9087, 1.03004, 0.95542, 0.93117, 1.23362, 1.01071, 1.07831, 1.02512, 1.05205, 1.03502, 1.2, 1.01071, 1.05356, 1.01071, 1.03502, 0.75842, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.03719, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.9403, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.04021, 1, 1, 1, 1, 1, 1, 0.98965, 1.00068, 0.98965, 1.00068, 0.98965, 1.00068, 0.8287, 0.96777, 1, 1.20088, 0.89903, 1, 1, 0.75155, 1.03077, 1.03077, 1.03077, 1.03077, 1.13196, 1.13196, 1.13196, 0.67428, 0.67428, 1.16039, 0.73291, 1.20996, 1.22135, 1.06483, 0.94868, 0.94868, 0.95996, 1.24633, 1, 1.07497, 0.87796, 0.96927, 1.01518, 0.96927, 1, 1, 1, 0.77295, 1, 1, 1.10539, 1.10539, 1.11358, 1.06967, 0.86279, 0.94434, 0.86279, 0.94434, 0.86182, 1, 1, 1.083, 1, 0.91578, 0.86507, 1.1714, 1.18416, 1.14589, 0.69825, 0.97622, 1.9697, 1.24822, 1.24822, 1.17238, 1.24822, 1.24822, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1.42603, 1, 0.99862, 0.99862, 1, 0.87025, 0.87025, 0.87025, 0.87025, 1.18083, 1.42603, 1, 1.42603, 1.42603, 0.99862, 1, 1, 1, 1, 1, 1.2886, 1.04315, 1.15296, 1.34163, 1, 1, 1, 1.10938, 1.10938, 1, 1, 1, 1.05425, 1.09971, 1.09971, 1.09971, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
+const SegoeuiRegularMetrics = {
+ lineHeight: 1.33008,
+ lineGap: 0
+};
+
+;// ./src/core/xfa_fonts.js
+
+
+
+
+
+
+
+
+
+
+
+const getXFAFontMap = getLookupTableFactory(function (t) {
+ t["MyriadPro-Regular"] = t["PdfJS-Fallback-Regular"] = {
+ name: "LiberationSans-Regular",
+ factors: MyriadProRegularFactors,
+ baseWidths: LiberationSansRegularWidths,
+ baseMapping: LiberationSansRegularMapping,
+ metrics: MyriadProRegularMetrics
+ };
+ t["MyriadPro-Bold"] = t["PdfJS-Fallback-Bold"] = {
+ name: "LiberationSans-Bold",
+ factors: MyriadProBoldFactors,
+ baseWidths: LiberationSansBoldWidths,
+ baseMapping: LiberationSansBoldMapping,
+ metrics: MyriadProBoldMetrics
+ };
+ t["MyriadPro-It"] = t["MyriadPro-Italic"] = t["PdfJS-Fallback-Italic"] = {
+ name: "LiberationSans-Italic",
+ factors: MyriadProItalicFactors,
+ baseWidths: LiberationSansItalicWidths,
+ baseMapping: LiberationSansItalicMapping,
+ metrics: MyriadProItalicMetrics
+ };
+ t["MyriadPro-BoldIt"] = t["MyriadPro-BoldItalic"] = t["PdfJS-Fallback-BoldItalic"] = {
+ name: "LiberationSans-BoldItalic",
+ factors: MyriadProBoldItalicFactors,
+ baseWidths: LiberationSansBoldItalicWidths,
+ baseMapping: LiberationSansBoldItalicMapping,
+ metrics: MyriadProBoldItalicMetrics
+ };
+ t.ArialMT = t.Arial = t["Arial-Regular"] = {
+ name: "LiberationSans-Regular",
+ baseWidths: LiberationSansRegularWidths,
+ baseMapping: LiberationSansRegularMapping
+ };
+ t["Arial-BoldMT"] = t["Arial-Bold"] = {
+ name: "LiberationSans-Bold",
+ baseWidths: LiberationSansBoldWidths,
+ baseMapping: LiberationSansBoldMapping
+ };
+ t["Arial-ItalicMT"] = t["Arial-Italic"] = {
+ name: "LiberationSans-Italic",
+ baseWidths: LiberationSansItalicWidths,
+ baseMapping: LiberationSansItalicMapping
+ };
+ t["Arial-BoldItalicMT"] = t["Arial-BoldItalic"] = {
+ name: "LiberationSans-BoldItalic",
+ baseWidths: LiberationSansBoldItalicWidths,
+ baseMapping: LiberationSansBoldItalicMapping
+ };
+ t["Calibri-Regular"] = {
+ name: "LiberationSans-Regular",
+ factors: CalibriRegularFactors,
+ baseWidths: LiberationSansRegularWidths,
+ baseMapping: LiberationSansRegularMapping,
+ metrics: CalibriRegularMetrics
+ };
+ t["Calibri-Bold"] = {
+ name: "LiberationSans-Bold",
+ factors: CalibriBoldFactors,
+ baseWidths: LiberationSansBoldWidths,
+ baseMapping: LiberationSansBoldMapping,
+ metrics: CalibriBoldMetrics
+ };
+ t["Calibri-Italic"] = {
+ name: "LiberationSans-Italic",
+ factors: CalibriItalicFactors,
+ baseWidths: LiberationSansItalicWidths,
+ baseMapping: LiberationSansItalicMapping,
+ metrics: CalibriItalicMetrics
+ };
+ t["Calibri-BoldItalic"] = {
+ name: "LiberationSans-BoldItalic",
+ factors: CalibriBoldItalicFactors,
+ baseWidths: LiberationSansBoldItalicWidths,
+ baseMapping: LiberationSansBoldItalicMapping,
+ metrics: CalibriBoldItalicMetrics
+ };
+ t["Segoeui-Regular"] = {
+ name: "LiberationSans-Regular",
+ factors: SegoeuiRegularFactors,
+ baseWidths: LiberationSansRegularWidths,
+ baseMapping: LiberationSansRegularMapping,
+ metrics: SegoeuiRegularMetrics
+ };
+ t["Segoeui-Bold"] = {
+ name: "LiberationSans-Bold",
+ factors: SegoeuiBoldFactors,
+ baseWidths: LiberationSansBoldWidths,
+ baseMapping: LiberationSansBoldMapping,
+ metrics: SegoeuiBoldMetrics
+ };
+ t["Segoeui-Italic"] = {
+ name: "LiberationSans-Italic",
+ factors: SegoeuiItalicFactors,
+ baseWidths: LiberationSansItalicWidths,
+ baseMapping: LiberationSansItalicMapping,
+ metrics: SegoeuiItalicMetrics
+ };
+ t["Segoeui-BoldItalic"] = {
+ name: "LiberationSans-BoldItalic",
+ factors: SegoeuiBoldItalicFactors,
+ baseWidths: LiberationSansBoldItalicWidths,
+ baseMapping: LiberationSansBoldItalicMapping,
+ metrics: SegoeuiBoldItalicMetrics
+ };
+ t["Helvetica-Regular"] = t.Helvetica = {
+ name: "LiberationSans-Regular",
+ factors: HelveticaRegularFactors,
+ baseWidths: LiberationSansRegularWidths,
+ baseMapping: LiberationSansRegularMapping,
+ metrics: HelveticaRegularMetrics
+ };
+ t["Helvetica-Bold"] = {
+ name: "LiberationSans-Bold",
+ factors: HelveticaBoldFactors,
+ baseWidths: LiberationSansBoldWidths,
+ baseMapping: LiberationSansBoldMapping,
+ metrics: HelveticaBoldMetrics
+ };
+ t["Helvetica-Italic"] = {
+ name: "LiberationSans-Italic",
+ factors: HelveticaItalicFactors,
+ baseWidths: LiberationSansItalicWidths,
+ baseMapping: LiberationSansItalicMapping,
+ metrics: HelveticaItalicMetrics
+ };
+ t["Helvetica-BoldItalic"] = {
+ name: "LiberationSans-BoldItalic",
+ factors: HelveticaBoldItalicFactors,
+ baseWidths: LiberationSansBoldItalicWidths,
+ baseMapping: LiberationSansBoldItalicMapping,
+ metrics: HelveticaBoldItalicMetrics
+ };
+});
+function getXfaFontName(name) {
+ const fontName = normalizeFontName(name);
+ const fontMap = getXFAFontMap();
+ return fontMap[fontName];
+}
+function getXfaFontWidths(name) {
+ const info = getXfaFontName(name);
+ if (!info) {
+ return null;
+ }
+ const {
+ baseWidths,
+ baseMapping,
+ factors
+ } = info;
+ const rescaledBaseWidths = !factors ? baseWidths : baseWidths.map((w, i) => w * factors[i]);
+ let currentCode = -2;
+ let currentArray;
+ const newWidths = [];
+ for (const [unicode, glyphIndex] of baseMapping.map((charUnicode, index) => [charUnicode, index]).sort(([unicode1], [unicode2]) => unicode1 - unicode2)) {
+ if (unicode === -1) {
+ continue;
+ }
+ if (unicode === currentCode + 1) {
+ currentArray.push(rescaledBaseWidths[glyphIndex]);
+ currentCode += 1;
+ } else {
+ currentCode = unicode;
+ currentArray = [rescaledBaseWidths[glyphIndex]];
+ newWidths.push(unicode, currentArray);
+ }
+ }
+ return newWidths;
+}
+function getXfaFontDict(name) {
+ const widths = getXfaFontWidths(name);
+ const dict = new Dict(null);
+ dict.set("BaseFont", Name.get(name));
+ dict.set("Type", Name.get("Font"));
+ dict.set("Subtype", Name.get("CIDFontType2"));
+ dict.set("Encoding", Name.get("Identity-H"));
+ dict.set("CIDToGIDMap", Name.get("Identity"));
+ dict.set("W", widths);
+ dict.set("FirstChar", widths[0]);
+ dict.set("LastChar", widths.at(-2) + widths.at(-1).length - 1);
+ const descriptor = new Dict(null);
+ dict.set("FontDescriptor", descriptor);
+ const systemInfo = new Dict(null);
+ systemInfo.set("Ordering", "Identity");
+ systemInfo.set("Registry", "Adobe");
+ systemInfo.set("Supplement", 0);
+ dict.set("CIDSystemInfo", systemInfo);
+ return dict;
+}
+
+;// ./src/core/postscript/lexer.js
+const TOKEN = {
+ number: 0,
+ lbrace: 1,
+ rbrace: 2,
+ true: 3,
+ false: 4,
+ add: 5,
+ sub: 6,
+ mul: 7,
+ div: 8,
+ idiv: 9,
+ mod: 10,
+ exp: 11,
+ eq: 12,
+ ne: 13,
+ gt: 14,
+ ge: 15,
+ lt: 16,
+ le: 17,
+ and: 18,
+ or: 19,
+ xor: 20,
+ bitshift: 21,
+ abs: 22,
+ neg: 23,
+ ceiling: 24,
+ floor: 25,
+ round: 26,
+ truncate: 27,
+ not: 28,
+ sqrt: 29,
+ sin: 30,
+ cos: 31,
+ ln: 32,
+ log: 33,
+ atan: 34,
+ cvi: 35,
+ cvr: 36,
+ dup: 37,
+ exch: 38,
+ pop: 39,
+ copy: 40,
+ index: 41,
+ roll: 42,
+ if: 43,
+ ifelse: 44,
+ eof: 45,
+ min: 46,
+ max: 47
+};
+class Token {
+ constructor(id, value = null) {
+ this.id = id;
+ this.value = value;
+ }
+}
+class lexer_Lexer {
+ static #singletons = null;
+ static #operatorSingletons = null;
+ static #initSingletons() {
+ const singletons = Object.create(null);
+ const operatorSingletons = Object.create(null);
+ for (const [name, id] of Object.entries(TOKEN)) {
+ if (name === "number") {
+ continue;
+ }
+ const isOperator = id >= TOKEN.true && id <= TOKEN.ifelse;
+ const token = new Token(id, isOperator ? name : null);
+ singletons[name] = token;
+ if (isOperator) {
+ operatorSingletons[name] = token;
+ }
+ }
+ this.#singletons = singletons;
+ this.#operatorSingletons = operatorSingletons;
+ }
+ constructor(data) {
+ if (!lexer_Lexer.#singletons) {
+ lexer_Lexer.#initSingletons();
+ }
+ this.data = data;
+ this.pos = 0;
+ this.len = data.length;
+ this._numberPattern = /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/iy;
+ this._identifierPattern = /[a-z]+/y;
+ }
+ _skipComment() {
+ const lf = this.data.indexOf("\n", this.pos);
+ const cr = this.data.indexOf("\r", this.pos);
+ const eol = Math.min(lf < 0 ? this.len : lf, cr < 0 ? this.len : cr);
+ this.pos = Math.min(eol + 1, this.len);
+ }
+ _getNumber() {
+ this._numberPattern.lastIndex = this.pos;
+ const match = this._numberPattern.exec(this.data);
+ if (!match) {
+ return new Token(TOKEN.number, 0);
+ }
+ const number = parseFloat(match[0]);
+ if (!Number.isFinite(number)) {
+ return new Token(TOKEN.number, 0);
+ }
+ this.pos = this._numberPattern.lastIndex;
+ return new Token(TOKEN.number, number);
+ }
+ _getOperator() {
+ this._identifierPattern.lastIndex = this.pos;
+ const match = this._identifierPattern.exec(this.data);
+ if (!match) {
+ return new Token(TOKEN.number, 0);
+ }
+ this.pos = this._identifierPattern.lastIndex;
+ const op = match[0];
+ const token = lexer_Lexer.#operatorSingletons[op];
+ if (!token) {
+ return new Token(TOKEN.number, 0);
+ }
+ return token;
+ }
+ next() {
+ while (this.pos < this.len) {
+ const ch = this.data.charCodeAt(this.pos++);
+ switch (ch) {
+ case 0x00:
+ case 0x09:
+ case 0x0a:
+ case 0x0c:
+ case 0x0d:
+ case 0x20:
+ break;
+ case 0x25:
+ this._skipComment();
+ break;
+ case 0x7b:
+ return lexer_Lexer.#singletons.lbrace;
+ case 0x7d:
+ return lexer_Lexer.#singletons.rbrace;
+ case 0x2b:
+ case 0x2d:
+ this.pos--;
+ return this._getNumber();
+ case 0x2e:
+ this.pos--;
+ return this._getNumber();
+ default:
+ if (ch >= 0x30 && ch <= 0x39) {
+ this.pos--;
+ return this._getNumber();
+ }
+ if (ch >= 0x61 && ch <= 0x7a) {
+ this.pos--;
+ return this._getOperator();
+ }
+ return new Token(TOKEN.number, 0);
+ }
+ }
+ return lexer_Lexer.#singletons.eof;
+ }
+}
+
+;// ./src/core/postscript/ast.js
+
+
+
+
+
+
+
+
+
+
+
+
+const PS_VALUE_TYPE = {
+ numeric: 0,
+ boolean: 1,
+ unknown: 2
+};
+const PS_NODE = {
+ program: 0,
+ block: 1,
+ number: 2,
+ operator: 3,
+ if: 4,
+ ifelse: 5,
+ arg: 6,
+ const: 7,
+ unary: 8,
+ binary: 9,
+ ternary: 10
+};
+class PsNode {
+ constructor(type) {
+ this.type = type;
+ }
+}
+class PsProgram extends PsNode {
+ constructor(body) {
+ super(PS_NODE.program);
+ this.body = body;
+ }
+}
+class PsBlock extends PsNode {
+ constructor(instructions) {
+ super(PS_NODE.block);
+ this.instructions = instructions;
+ }
+}
+class PsNumber extends PsNode {
+ constructor(value) {
+ super(PS_NODE.number);
+ this.value = value;
+ }
+}
+class PsOperator extends PsNode {
+ constructor(op) {
+ super(PS_NODE.operator);
+ this.op = op;
+ }
+}
+class PsIf extends PsNode {
+ constructor(then) {
+ super(PS_NODE.if);
+ this.then = then;
+ }
+}
+class PsIfElse extends PsNode {
+ constructor(then, otherwise) {
+ super(PS_NODE.ifelse);
+ this.then = then;
+ this.otherwise = otherwise;
+ }
+}
+class PsArgNode extends PsNode {
+ constructor(index) {
+ super(PS_NODE.arg);
+ this.index = index;
+ this.valueType = PS_VALUE_TYPE.numeric;
+ }
+}
+class PsConstNode extends PsNode {
+ constructor(value) {
+ super(PS_NODE.const);
+ this.value = value;
+ this.valueType = typeof value === "boolean" ? PS_VALUE_TYPE.boolean : PS_VALUE_TYPE.numeric;
+ }
+}
+class PsUnaryNode extends PsNode {
+ constructor(op, operand, valueType = PS_VALUE_TYPE.unknown) {
+ super(PS_NODE.unary);
+ this.op = op;
+ this.operand = operand;
+ this.valueType = valueType;
+ }
+}
+class PsBinaryNode extends PsNode {
+ constructor(op, first, second, valueType = PS_VALUE_TYPE.unknown) {
+ super(PS_NODE.binary);
+ this.op = op;
+ this.first = first;
+ this.second = second;
+ this.valueType = valueType;
+ }
+}
+class PsTernaryNode extends PsNode {
+ constructor(cond, then, otherwise, valueType = PS_VALUE_TYPE.unknown) {
+ super(PS_NODE.ternary);
+ this.cond = cond;
+ this.then = then;
+ this.otherwise = otherwise;
+ this.valueType = valueType;
+ }
+}
+class ast_Parser {
+ constructor(lexer) {
+ this.lexer = lexer;
+ this._token = null;
+ }
+ static _isRegularOperator(id) {
+ return id >= TOKEN.true && id < TOKEN.if;
+ }
+ _advance() {
+ this._token = this.lexer.next();
+ }
+ _expect(id) {
+ if (this._token.id !== id) {
+ throw new FormatError(`PostScript function: expected token id ${id}, got ${this._token.id}.`);
+ }
+ const tok = this._token;
+ this._advance();
+ return tok;
+ }
+ parse() {
+ this._advance();
+ this._expect(TOKEN.lbrace);
+ const block = this._parseBlock();
+ this._expect(TOKEN.rbrace);
+ if (this._token.id !== TOKEN.eof) {
+ warn("PostScript function: unexpected content after closing brace.");
+ }
+ return new PsProgram(block);
+ }
+ _parseBlock() {
+ const instructions = [];
+ while (true) {
+ const tok = this._token;
+ switch (tok.id) {
+ case TOKEN.number:
+ instructions.push(new PsNumber(tok.value));
+ this._advance();
+ break;
+ case TOKEN.lbrace:
+ {
+ this._advance();
+ const thenBlock = this._parseBlock();
+ this._expect(TOKEN.rbrace);
+ if (this._token.id === TOKEN.if) {
+ this._advance();
+ instructions.push(new PsIf(thenBlock));
+ } else if (this._token.id === TOKEN.lbrace) {
+ this._advance();
+ const elseBlock = this._parseBlock();
+ this._expect(TOKEN.rbrace);
+ this._expect(TOKEN.ifelse);
+ instructions.push(new PsIfElse(thenBlock, elseBlock));
+ } else {
+ throw new FormatError("PostScript function: a procedure block must be followed by 'if' or '{…} ifelse'.");
+ }
+ break;
+ }
+ case TOKEN.rbrace:
+ case TOKEN.eof:
+ return new PsBlock(instructions);
+ case TOKEN.if:
+ case TOKEN.ifelse:
+ throw new FormatError(`PostScript function: unexpected '${tok.value}' operator.`);
+ default:
+ if (ast_Parser._isRegularOperator(tok.id)) {
+ instructions.push(new PsOperator(tok.id));
+ this._advance();
+ break;
+ }
+ throw new FormatError(`PostScript function: unexpected token id ${tok.id}.`);
+ }
+ }
+ }
+}
+function parsePostScriptFunction(source) {
+ return new ast_Parser(new lexer_Lexer(source)).parse();
+}
+function _nodesEqual(a, b) {
+ if (a === b) {
+ return true;
+ }
+ if (a.type !== b.type) {
+ return false;
+ }
+ switch (a.type) {
+ case PS_NODE.arg:
+ return a.index === b.index;
+ case PS_NODE.const:
+ return a.value === b.value;
+ case PS_NODE.unary:
+ return a.op === b.op && _nodesEqual(a.operand, b.operand);
+ case PS_NODE.binary:
+ return a.op === b.op && _nodesEqual(a.first, b.first) && _nodesEqual(a.second, b.second);
+ case PS_NODE.ternary:
+ return _nodesEqual(a.cond, b.cond) && _nodesEqual(a.then, b.then) && _nodesEqual(a.otherwise, b.otherwise);
+ default:
+ return false;
+ }
+}
+function _evalBinaryConst(op, a, b) {
+ switch (op) {
+ case TOKEN.add:
+ return a + b;
+ case TOKEN.sub:
+ return a - b;
+ case TOKEN.mul:
+ return a * b;
+ case TOKEN.div:
+ return b !== 0 ? a / b : 0;
+ case TOKEN.idiv:
+ return b !== 0 ? Math.trunc(a / b) : 0;
+ case TOKEN.mod:
+ return b !== 0 ? a - Math.trunc(a / b) * b : 0;
+ case TOKEN.exp:
+ {
+ const r = a ** b;
+ return Number.isFinite(r) ? r : undefined;
+ }
+ case TOKEN.atan:
+ {
+ let deg = Math.atan2(a, b) * (180 / Math.PI);
+ if (deg < 0) {
+ deg += 360;
+ }
+ return deg;
+ }
+ case TOKEN.eq:
+ return a === b;
+ case TOKEN.ne:
+ return a !== b;
+ case TOKEN.gt:
+ return a > b;
+ case TOKEN.ge:
+ return a >= b;
+ case TOKEN.lt:
+ return a < b;
+ case TOKEN.le:
+ return a <= b;
+ case TOKEN.and:
+ return typeof a === "boolean" ? a && b : a & b | 0;
+ case TOKEN.or:
+ return typeof a === "boolean" ? a || b : a | b | 0;
+ case TOKEN.xor:
+ return typeof a === "boolean" ? a !== b : a ^ b | 0;
+ case TOKEN.bitshift:
+ return b >= 0 ? a << b | 0 : a >> -b | 0;
+ case TOKEN.min:
+ return Math.min(a, b);
+ case TOKEN.max:
+ return Math.max(a, b);
+ default:
+ return undefined;
+ }
+}
+function _evalUnaryConst(op, v) {
+ switch (op) {
+ case TOKEN.abs:
+ return Math.abs(v);
+ case TOKEN.neg:
+ return -v;
+ case TOKEN.ceiling:
+ return Math.ceil(v);
+ case TOKEN.floor:
+ return Math.floor(v);
+ case TOKEN.round:
+ return Math.round(v);
+ case TOKEN.truncate:
+ return Math.trunc(v);
+ case TOKEN.sqrt:
+ {
+ const r = Math.sqrt(v);
+ return Number.isFinite(r) ? r : undefined;
+ }
+ case TOKEN.sin:
+ return Math.sin(v % 360 * Math.PI / 180);
+ case TOKEN.cos:
+ return Math.cos(v % 360 * Math.PI / 180);
+ case TOKEN.ln:
+ {
+ const r = Math.log(v);
+ return Number.isFinite(r) ? r : undefined;
+ }
+ case TOKEN.log:
+ {
+ const r = Math.log10(v);
+ return Number.isFinite(r) ? r : undefined;
+ }
+ case TOKEN.cvi:
+ return Math.trunc(v);
+ case TOKEN.cvr:
+ return v;
+ case TOKEN.not:
+ return typeof v === "boolean" ? !v : ~v;
+ default:
+ return undefined;
+ }
+}
+const MAX_STACK_SIZE = 100;
+function _unaryValueType(op, operandType) {
+ return op === TOKEN.not ? operandType : PS_VALUE_TYPE.numeric;
+}
+function _binaryValueType(op, firstType, secondType) {
+ switch (op) {
+ case TOKEN.eq:
+ case TOKEN.ne:
+ case TOKEN.gt:
+ case TOKEN.ge:
+ case TOKEN.lt:
+ case TOKEN.le:
+ return PS_VALUE_TYPE.boolean;
+ case TOKEN.and:
+ case TOKEN.or:
+ case TOKEN.xor:
+ return firstType === secondType && firstType !== PS_VALUE_TYPE.unknown ? firstType : PS_VALUE_TYPE.unknown;
+ default:
+ return PS_VALUE_TYPE.numeric;
+ }
+}
+class PSStackToTree {
+ static #binaryOps = null;
+ static #unaryOps = null;
+ static #idempotentUnary = null;
+ static #negatedComparison = null;
+ static #init() {
+ this.#binaryOps = new Set([TOKEN.add, TOKEN.sub, TOKEN.mul, TOKEN.div, TOKEN.idiv, TOKEN.mod, TOKEN.exp, TOKEN.atan, TOKEN.eq, TOKEN.ne, TOKEN.gt, TOKEN.ge, TOKEN.lt, TOKEN.le, TOKEN.and, TOKEN.or, TOKEN.xor, TOKEN.bitshift]);
+ this.#unaryOps = new Set([TOKEN.abs, TOKEN.neg, TOKEN.ceiling, TOKEN.floor, TOKEN.round, TOKEN.truncate, TOKEN.sqrt, TOKEN.sin, TOKEN.cos, TOKEN.ln, TOKEN.log, TOKEN.cvi, TOKEN.cvr, TOKEN.not]);
+ this.#idempotentUnary = new Set([TOKEN.abs, TOKEN.ceiling, TOKEN.cvi, TOKEN.cvr, TOKEN.floor, TOKEN.round, TOKEN.truncate]);
+ this.#negatedComparison = new Map([[TOKEN.eq, TOKEN.ne], [TOKEN.ne, TOKEN.eq], [TOKEN.lt, TOKEN.ge], [TOKEN.le, TOKEN.gt], [TOKEN.gt, TOKEN.le], [TOKEN.ge, TOKEN.lt]]);
+ }
+ evaluate(program, numInputs) {
+ if (!PSStackToTree.#binaryOps) {
+ PSStackToTree.#init();
+ }
+ this._failed = false;
+ if (numInputs > MAX_STACK_SIZE) {
+ return null;
+ }
+ const stack = [];
+ for (let i = 0; i < numInputs; i++) {
+ stack.push(new PsArgNode(i));
+ }
+ this._evalBlock(program.body, stack);
+ if (this._failed) {
+ return null;
+ }
+ PSStackToTree.#markShared(stack);
+ return stack;
+ }
+ static #markShared(outputs) {
+ const refCount = new Map();
+ const visit = node => {
+ if (!node || node.type === PS_NODE.arg || node.type === PS_NODE.const) {
+ return;
+ }
+ const prev = refCount.get(node) ?? 0;
+ refCount.set(node, prev + 1);
+ if (prev > 0) {
+ return;
+ }
+ switch (node.type) {
+ case PS_NODE.unary:
+ visit(node.operand);
+ break;
+ case PS_NODE.binary:
+ visit(node.first);
+ visit(node.second);
+ break;
+ case PS_NODE.ternary:
+ visit(node.cond);
+ visit(node.then);
+ visit(node.otherwise);
+ break;
+ }
+ };
+ for (const output of outputs) {
+ visit(output);
+ }
+ for (const [node, count] of refCount) {
+ if (count > 1) {
+ node.shared = true;
+ node.sharedCount = count;
+ }
+ }
+ }
+ _evalBlock(block, stack) {
+ this._evalBlockFrom(block.instructions, 0, stack);
+ }
+ _evalBlockFrom(instructions, startIdx, stack) {
+ for (let idx = startIdx; idx < instructions.length; idx++) {
+ if (this._failed) {
+ break;
+ }
+ const instr = instructions[idx];
+ switch (instr.type) {
+ case PS_NODE.number:
+ stack.push(new PsConstNode(instr.value));
+ if (stack.length > MAX_STACK_SIZE) {
+ this._failed = true;
+ }
+ break;
+ case PS_NODE.operator:
+ this._evalOp(instr.op, stack);
+ break;
+ case PS_NODE.if:
+ {
+ if (stack.length < 1) {
+ this._failed = true;
+ break;
+ }
+ const cond = stack.pop();
+ const saved = stack.slice();
+ this._evalBlock(instr.then, stack);
+ if (this._failed) {
+ break;
+ }
+ if (stack.length === saved.length) {
+ for (let i = 0; i < stack.length; i++) {
+ if (stack[i] !== saved[i]) {
+ stack[i] = this._makeTernary(cond, stack[i], saved[i]);
+ }
+ }
+ } else if (stack.length > saved.length) {
+ if (cond.type === PS_NODE.const) {
+ if (!cond.value) {
+ stack.length = 0;
+ stack.push(...saved);
+ }
+ break;
+ }
+ const trueStack = stack.slice();
+ this._evalBlockFrom(instructions, idx + 1, trueStack);
+ if (this._failed) {
+ break;
+ }
+ const falseStack = saved;
+ this._evalBlockFrom(instructions, idx + 1, falseStack);
+ if (this._failed) {
+ break;
+ }
+ if (trueStack.length !== falseStack.length) {
+ const zero = new PsConstNode(0);
+ while (trueStack.length < falseStack.length) {
+ trueStack.push(zero);
+ }
+ while (falseStack.length < trueStack.length) {
+ falseStack.push(zero);
+ }
+ }
+ stack.length = 0;
+ for (let i = 0; i < trueStack.length; i++) {
+ stack.push(this._makeTernary(cond, trueStack[i], falseStack[i]));
+ }
+ return;
+ } else {
+ this._failed = true;
+ }
+ break;
+ }
+ case PS_NODE.ifelse:
+ {
+ if (stack.length < 1) {
+ this._failed = true;
+ break;
+ }
+ const cond = stack.pop();
+ const snapshot = stack.slice();
+ const thenStack = snapshot.slice();
+ this._evalBlock(instr.then, thenStack);
+ if (this._failed) {
+ break;
+ }
+ const elseStack = snapshot.slice();
+ this._evalBlock(instr.otherwise, elseStack);
+ if (this._failed) {
+ break;
+ }
+ if (thenStack.length !== elseStack.length) {
+ const zero = new PsConstNode(0);
+ while (thenStack.length < elseStack.length) {
+ thenStack.push(zero);
+ }
+ while (elseStack.length < thenStack.length) {
+ elseStack.push(zero);
+ }
+ }
+ stack.length = 0;
+ for (let i = 0; i < thenStack.length; i++) {
+ stack.push(this._makeTernary(cond, thenStack[i], elseStack[i]));
+ }
+ break;
+ }
+ }
+ }
+ }
+ _evalOp(op, stack) {
+ if (PSStackToTree.#binaryOps.has(op)) {
+ if (stack.length < 2) {
+ this._failed = true;
+ return;
+ }
+ const first = stack.pop();
+ const second = stack.pop();
+ stack.push(this._makeBinary(op, first, second));
+ return;
+ }
+ if (PSStackToTree.#unaryOps.has(op)) {
+ if (stack.length < 1) {
+ this._failed = true;
+ return;
+ }
+ stack.push(this._makeUnary(op, stack.pop()));
+ return;
+ }
+ switch (op) {
+ case TOKEN.true:
+ stack.push(new PsConstNode(true));
+ if (stack.length > MAX_STACK_SIZE) {
+ this._failed = true;
+ }
+ break;
+ case TOKEN.false:
+ stack.push(new PsConstNode(false));
+ if (stack.length > MAX_STACK_SIZE) {
+ this._failed = true;
+ }
+ break;
+ case TOKEN.dup:
+ if (stack.length < 1) {
+ this._failed = true;
+ break;
+ }
+ stack.push(stack.at(-1));
+ if (stack.length > MAX_STACK_SIZE) {
+ this._failed = true;
+ }
+ break;
+ case TOKEN.exch:
+ {
+ if (stack.length < 2) {
+ this._failed = true;
+ break;
+ }
+ const a = stack.pop();
+ const b = stack.pop();
+ stack.push(a, b);
+ break;
+ }
+ case TOKEN.pop:
+ if (stack.length < 1) {
+ this._failed = true;
+ break;
+ }
+ stack.pop();
+ break;
+ case TOKEN.copy:
+ {
+ if (stack.length < 1) {
+ this._failed = true;
+ break;
+ }
+ const nNode = stack.pop();
+ if (nNode.type === PS_NODE.const) {
+ const n = nNode.value | 0;
+ if (n === 0) {} else if (n < 0 || n > stack.length) {
+ this._failed = true;
+ } else {
+ stack.push(...stack.slice(-n));
+ if (stack.length > MAX_STACK_SIZE) {
+ this._failed = true;
+ }
+ }
+ } else {
+ this._failed = true;
+ }
+ break;
+ }
+ case TOKEN.index:
+ {
+ if (stack.length < 1) {
+ this._failed = true;
+ break;
+ }
+ const nNode = stack.pop();
+ if (nNode.type === PS_NODE.const) {
+ const n = nNode.value | 0;
+ if (n < 0 || n >= stack.length) {
+ this._failed = true;
+ } else {
+ stack.push(stack.at(-n - 1));
+ }
+ } else {
+ this._failed = true;
+ }
+ break;
+ }
+ case TOKEN.roll:
+ {
+ if (stack.length < 2) {
+ this._failed = true;
+ break;
+ }
+ const jNode = stack.pop();
+ const nNode = stack.pop();
+ if (nNode.type === PS_NODE.const && jNode.type === PS_NODE.const) {
+ const n = nNode.value | 0;
+ if (n === 0) {} else if (n < 0 || n > stack.length) {
+ this._failed = true;
+ } else {
+ const j = ((jNode.value | 0) % n + n) % n;
+ if (j > 0) {
+ const slice = stack.splice(-n, n);
+ stack.push(...slice.slice(n - j), ...slice.slice(0, n - j));
+ }
+ }
+ } else {
+ this._failed = true;
+ }
+ break;
+ }
+ default:
+ this._failed = true;
+ break;
+ }
+ }
+ _makeBinary(op, first, second) {
+ if (first.type === PS_NODE.const && second.type === PS_NODE.const) {
+ const v = _evalBinaryConst(op, second.value, first.value);
+ if (v !== undefined) {
+ return new PsConstNode(v);
+ }
+ }
+ if (_nodesEqual(first, second)) {
+ switch (op) {
+ case TOKEN.sub:
+ return new PsConstNode(0);
+ case TOKEN.xor:
+ return new PsConstNode(first.valueType === PS_VALUE_TYPE.boolean ? false : 0);
+ case TOKEN.and:
+ case TOKEN.or:
+ return first;
+ case TOKEN.min:
+ case TOKEN.max:
+ return first;
+ case TOKEN.eq:
+ case TOKEN.ge:
+ case TOKEN.le:
+ return new PsConstNode(true);
+ case TOKEN.ne:
+ case TOKEN.gt:
+ case TOKEN.lt:
+ return new PsConstNode(false);
+ }
+ }
+ if (first.type === PS_NODE.const) {
+ const b = first.value;
+ switch (op) {
+ case TOKEN.add:
+ if (b === 0) {
+ return second;
+ }
+ break;
+ case TOKEN.sub:
+ if (b === 0) {
+ return second;
+ }
+ break;
+ case TOKEN.mul:
+ if (b === 1) {
+ return second;
+ }
+ if (b === 0) {
+ return first;
+ }
+ if (b === -1) {
+ return this._makeUnary(TOKEN.neg, second);
+ }
+ break;
+ case TOKEN.div:
+ if (b !== 0) {
+ return this._makeBinary(TOKEN.mul, new PsConstNode(1 / b), second);
+ }
+ break;
+ case TOKEN.idiv:
+ if (b === 1) {
+ return second;
+ }
+ break;
+ case TOKEN.exp:
+ if (b === 1) {
+ return second;
+ }
+ if (b === -1) {
+ return this._makeBinary(TOKEN.div, second, new PsConstNode(1));
+ }
+ if (b === 0.5) {
+ return this._makeUnary(TOKEN.sqrt, second);
+ }
+ if (b === 0.25) {
+ const sqrtOnce = this._makeUnary(TOKEN.sqrt, second);
+ return this._makeUnary(TOKEN.sqrt, sqrtOnce);
+ }
+ if (b === 2) {
+ return this._makeBinary(TOKEN.mul, second, second);
+ }
+ if (b === 3) {
+ return this._makeBinary(TOKEN.mul, this._makeBinary(TOKEN.mul, second, second), second);
+ }
+ if (b === 4) {
+ const square = this._makeBinary(TOKEN.mul, second, second);
+ return this._makeBinary(TOKEN.mul, square, square);
+ }
+ if (b === 0) {
+ return new PsConstNode(1);
+ }
+ break;
+ case TOKEN.and:
+ if (b === true) {
+ return second;
+ }
+ if (b === false) {
+ return first;
+ }
+ break;
+ case TOKEN.or:
+ if (b === false) {
+ return second;
+ }
+ if (b === true) {
+ return first;
+ }
+ break;
+ case TOKEN.min:
+ if (second.type === PS_NODE.binary && second.op === TOKEN.max && second.first.type === PS_NODE.const && second.first.value >= b) {
+ return first;
+ }
+ break;
+ case TOKEN.max:
+ if (second.type === PS_NODE.binary && second.op === TOKEN.min && second.first.type === PS_NODE.const && second.first.value <= b) {
+ return first;
+ }
+ break;
+ }
+ }
+ if (second.type === PS_NODE.const) {
+ const a = second.value;
+ switch (op) {
+ case TOKEN.add:
+ if (a === 0) {
+ return first;
+ }
+ break;
+ case TOKEN.sub:
+ if (a === 0) {
+ return this._makeUnary(TOKEN.neg, first);
+ }
+ break;
+ case TOKEN.mul:
+ if (a === 1) {
+ return first;
+ }
+ if (a === 0) {
+ return second;
+ }
+ if (a === -1) {
+ return this._makeUnary(TOKEN.neg, first);
+ }
+ break;
+ case TOKEN.and:
+ if (a === true) {
+ return first;
+ }
+ if (a === false) {
+ return second;
+ }
+ break;
+ case TOKEN.or:
+ if (a === false) {
+ return first;
+ }
+ if (a === true) {
+ return second;
+ }
+ break;
+ }
+ }
+ return new PsBinaryNode(op, first, second, _binaryValueType(op, first.valueType, second.valueType));
+ }
+ _makeUnary(op, operand) {
+ if (operand.type === PS_NODE.const) {
+ const v = _evalUnaryConst(op, operand.value);
+ if (v !== undefined) {
+ return new PsConstNode(v);
+ }
+ }
+ if (op === TOKEN.not && operand.type === PS_NODE.binary) {
+ const negated = PSStackToTree.#negatedComparison.get(operand.op);
+ if (negated !== undefined) {
+ return new PsBinaryNode(negated, operand.first, operand.second, PS_VALUE_TYPE.boolean);
+ }
+ }
+ if (op === TOKEN.neg && operand.type === PS_NODE.binary && operand.op === TOKEN.sub) {
+ return this._makeBinary(TOKEN.sub, operand.second, operand.first);
+ }
+ if (operand.type === PS_NODE.unary) {
+ if (op === TOKEN.neg && operand.op === TOKEN.neg || op === TOKEN.not && operand.op === TOKEN.not) {
+ return operand.operand;
+ }
+ if (op === TOKEN.abs && operand.op === TOKEN.neg) {
+ return this._makeUnary(TOKEN.abs, operand.operand);
+ }
+ if (PSStackToTree.#idempotentUnary.has(op) && op === operand.op) {
+ return operand;
+ }
+ }
+ return new PsUnaryNode(op, operand, _unaryValueType(op, operand.valueType));
+ }
+ _makeTernary(cond, then, otherwise) {
+ if (cond.type === PS_NODE.const) {
+ return cond.value ? then : otherwise;
+ }
+ if (_nodesEqual(then, otherwise)) {
+ return then;
+ }
+ if (then.type === PS_NODE.const && otherwise.type === PS_NODE.const) {
+ if (then.value === true && otherwise.value === false) {
+ return cond;
+ }
+ if (then.value === false && otherwise.value === true) {
+ return this._makeUnary(TOKEN.not, cond);
+ }
+ }
+ if (cond.type === PS_NODE.binary) {
+ const {
+ op: cop,
+ first: cf,
+ second: cs
+ } = cond;
+ if (cop === TOKEN.gt || cop === TOKEN.ge) {
+ if (_nodesEqual(then, cf) && _nodesEqual(otherwise, cs)) {
+ return this._makeBinary(TOKEN.min, cf, cs);
+ }
+ if (_nodesEqual(then, cs) && _nodesEqual(otherwise, cf)) {
+ return this._makeBinary(TOKEN.max, cf, cs);
+ }
+ } else if (cop === TOKEN.lt || cop === TOKEN.le) {
+ if (_nodesEqual(then, cf) && _nodesEqual(otherwise, cs)) {
+ return this._makeBinary(TOKEN.max, cf, cs);
+ }
+ if (_nodesEqual(then, cs) && _nodesEqual(otherwise, cf)) {
+ return this._makeBinary(TOKEN.min, cf, cs);
+ }
+ }
+ }
+ return new PsTernaryNode(cond, then, otherwise, then.valueType === otherwise.valueType ? then.valueType : PS_VALUE_TYPE.unknown);
+ }
+}
+
+;// ./src/core/postscript/js_evaluator.js
+
+
+
+
+
+
+
+const OP = {
+ ARG: 0,
+ CONST: 1,
+ STORE: 2,
+ IF: 3,
+ JUMP: 4,
+ ABS: 5,
+ NEG: 6,
+ CEIL: 7,
+ FLOOR: 8,
+ ROUND: 9,
+ TRUNC: 10,
+ NOT_B: 11,
+ NOT_N: 12,
+ SQRT: 13,
+ SIN: 14,
+ COS: 15,
+ LN: 16,
+ LOG10: 17,
+ CVI: 18,
+ SHIFT: 19,
+ ADD: 20,
+ SUB: 21,
+ MUL: 22,
+ DIV: 23,
+ IDIV: 24,
+ MOD: 25,
+ POW: 26,
+ EQ: 27,
+ NE: 28,
+ GT: 29,
+ GE: 30,
+ LT: 31,
+ LE: 32,
+ AND: 33,
+ OR: 34,
+ XOR: 35,
+ ATAN: 36,
+ MIN: 37,
+ MAX: 38,
+ TEE_TMP: 39,
+ LOAD_TMP: 40
+};
+const _DEG_TO_RAD = Math.PI / 180;
+const _RAD_TO_DEG = 180 / Math.PI;
+class PsJsCompiler {
+ static #stack = new Float64Array(64);
+ static #tmp = new Float64Array(64);
+ constructor(domain, range) {
+ this.nIn = domain.length >> 1;
+ this.nOut = range.length >> 1;
+ this.range = range;
+ this.ir = [];
+ this._tmpMap = new Map();
+ this._nextTmp = 0;
+ }
+ _compileNode(node) {
+ if (node.shared) {
+ const cached = this._tmpMap.get(node);
+ if (cached !== undefined) {
+ this.ir.push(OP.LOAD_TMP, cached);
+ return true;
+ }
+ if (!this._compileNodeImpl(node)) {
+ return false;
+ }
+ const slot = this._nextTmp++;
+ this._tmpMap.set(node, slot);
+ this.ir.push(OP.TEE_TMP, slot);
+ return true;
+ }
+ return this._compileNodeImpl(node);
+ }
+ _compileNodeImpl(node) {
+ switch (node.type) {
+ case PS_NODE.arg:
+ this.ir.push(OP.ARG, node.index);
+ return true;
+ case PS_NODE.const:
+ {
+ const v = node.value;
+ this.ir.push(OP.CONST, typeof v === "boolean" ? Number(v) : v);
+ return true;
+ }
+ case PS_NODE.unary:
+ return this._compileUnary(node);
+ case PS_NODE.binary:
+ return this._compileBinary(node);
+ case PS_NODE.ternary:
+ return this._compileTernary(node);
+ default:
+ return false;
+ }
+ }
+ _compileUnary(node) {
+ const {
+ op,
+ operand,
+ valueType
+ } = node;
+ if (op === TOKEN.cvr) {
+ return this._compileNode(operand);
+ }
+ if (!this._compileNode(operand)) {
+ return false;
+ }
+ switch (op) {
+ case TOKEN.abs:
+ this.ir.push(OP.ABS);
+ break;
+ case TOKEN.neg:
+ this.ir.push(OP.NEG);
+ break;
+ case TOKEN.ceiling:
+ this.ir.push(OP.CEIL);
+ break;
+ case TOKEN.floor:
+ this.ir.push(OP.FLOOR);
+ break;
+ case TOKEN.round:
+ this.ir.push(OP.ROUND);
+ break;
+ case TOKEN.truncate:
+ this.ir.push(OP.TRUNC);
+ break;
+ case TOKEN.sqrt:
+ this.ir.push(OP.SQRT);
+ break;
+ case TOKEN.sin:
+ this.ir.push(OP.SIN);
+ break;
+ case TOKEN.cos:
+ this.ir.push(OP.COS);
+ break;
+ case TOKEN.ln:
+ this.ir.push(OP.LN);
+ break;
+ case TOKEN.log:
+ this.ir.push(OP.LOG10);
+ break;
+ case TOKEN.cvi:
+ this.ir.push(OP.CVI);
+ break;
+ case TOKEN.not:
+ if (valueType === PS_VALUE_TYPE.boolean) {
+ this.ir.push(OP.NOT_B);
+ } else if (valueType === PS_VALUE_TYPE.numeric) {
+ this.ir.push(OP.NOT_N);
+ } else {
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ _compileBinary(node) {
+ const {
+ op,
+ first,
+ second
+ } = node;
+ if (op === TOKEN.bitshift) {
+ if (first.type !== PS_NODE.const || !Number.isInteger(first.value)) {
+ return false;
+ }
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ this.ir.push(OP.SHIFT, first.value);
+ return true;
+ }
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ switch (op) {
+ case TOKEN.add:
+ this.ir.push(OP.ADD);
+ break;
+ case TOKEN.sub:
+ this.ir.push(OP.SUB);
+ break;
+ case TOKEN.mul:
+ this.ir.push(OP.MUL);
+ break;
+ case TOKEN.div:
+ this.ir.push(OP.DIV);
+ break;
+ case TOKEN.idiv:
+ this.ir.push(OP.IDIV);
+ break;
+ case TOKEN.mod:
+ this.ir.push(OP.MOD);
+ break;
+ case TOKEN.exp:
+ this.ir.push(OP.POW);
+ break;
+ case TOKEN.eq:
+ this.ir.push(OP.EQ);
+ break;
+ case TOKEN.ne:
+ this.ir.push(OP.NE);
+ break;
+ case TOKEN.gt:
+ this.ir.push(OP.GT);
+ break;
+ case TOKEN.ge:
+ this.ir.push(OP.GE);
+ break;
+ case TOKEN.lt:
+ this.ir.push(OP.LT);
+ break;
+ case TOKEN.le:
+ this.ir.push(OP.LE);
+ break;
+ case TOKEN.and:
+ this.ir.push(OP.AND);
+ break;
+ case TOKEN.or:
+ this.ir.push(OP.OR);
+ break;
+ case TOKEN.xor:
+ this.ir.push(OP.XOR);
+ break;
+ case TOKEN.atan:
+ this.ir.push(OP.ATAN);
+ break;
+ case TOKEN.min:
+ this.ir.push(OP.MIN);
+ break;
+ case TOKEN.max:
+ this.ir.push(OP.MAX);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ _compileTernary(node) {
+ if (!this._compileNode(node.cond)) {
+ return false;
+ }
+ this.ir.push(OP.IF, 0);
+ const ifPatch = this.ir.length - 1;
+ if (!this._compileNode(node.then)) {
+ return false;
+ }
+ this.ir.push(OP.JUMP, 0);
+ const jumpPatch = this.ir.length - 1;
+ this.ir[ifPatch] = this.ir.length;
+ if (!this._compileNode(node.otherwise)) {
+ return false;
+ }
+ this.ir[jumpPatch] = this.ir.length;
+ return true;
+ }
+ compile(program) {
+ const outputs = new PSStackToTree().evaluate(program, this.nIn);
+ if (!outputs || outputs.length < this.nOut) {
+ return null;
+ }
+ for (let i = 0; i < this.nOut; i++) {
+ if (!this._compileNode(outputs[i])) {
+ return null;
+ }
+ const min = this.range[i * 2];
+ const max = this.range[i * 2 + 1];
+ this.ir.push(OP.STORE, i, min, max);
+ }
+ return new Float64Array(this.ir);
+ }
+ static execute(ir, src, srcOffset, dest, destOffset) {
+ let ip = 0,
+ sp = 0;
+ const n = ir.length;
+ const stack = this.#stack;
+ const tmp = this.#tmp;
+ while (ip < n) {
+ switch (ir[ip++] | 0) {
+ case OP.ARG:
+ stack[sp++] = src[srcOffset + (ir[ip++] | 0)];
+ break;
+ case OP.CONST:
+ stack[sp++] = ir[ip++];
+ break;
+ case OP.STORE:
+ {
+ const slot = ir[ip++] | 0;
+ const min = ir[ip++];
+ const max = ir[ip++];
+ dest[destOffset + slot] = MathClamp(stack[--sp], min, max);
+ break;
+ }
+ case OP.IF:
+ {
+ const tgt = ir[ip++];
+ if (stack[--sp] === 0) {
+ ip = tgt;
+ }
+ break;
+ }
+ case OP.JUMP:
+ ip = ir[ip];
+ break;
+ case OP.ABS:
+ stack[sp - 1] = Math.abs(stack[sp - 1]);
+ break;
+ case OP.NEG:
+ stack[sp - 1] = -stack[sp - 1];
+ break;
+ case OP.CEIL:
+ stack[sp - 1] = Math.ceil(stack[sp - 1]);
+ break;
+ case OP.FLOOR:
+ stack[sp - 1] = Math.floor(stack[sp - 1]);
+ break;
+ case OP.ROUND:
+ stack[sp - 1] = Math.floor(stack[sp - 1] + 0.5);
+ break;
+ case OP.TRUNC:
+ stack[sp - 1] = Math.trunc(stack[sp - 1]);
+ break;
+ case OP.NOT_B:
+ stack[sp - 1] = stack[sp - 1] !== 0 ? 0 : 1;
+ break;
+ case OP.NOT_N:
+ stack[sp - 1] = ~(stack[sp - 1] | 0);
+ break;
+ case OP.SQRT:
+ stack[sp - 1] = Math.sqrt(stack[sp - 1]);
+ break;
+ case OP.SIN:
+ stack[sp - 1] = Math.sin(stack[sp - 1] % 360 * _DEG_TO_RAD);
+ break;
+ case OP.COS:
+ stack[sp - 1] = Math.cos(stack[sp - 1] % 360 * _DEG_TO_RAD);
+ break;
+ case OP.LN:
+ stack[sp - 1] = Math.log(stack[sp - 1]);
+ break;
+ case OP.LOG10:
+ stack[sp - 1] = Math.log10(stack[sp - 1]);
+ break;
+ case OP.CVI:
+ stack[sp - 1] = Math.trunc(stack[sp - 1]) | 0;
+ break;
+ case OP.SHIFT:
+ {
+ const amt = ir[ip++];
+ const v = stack[sp - 1] | 0;
+ if (amt > 0) {
+ stack[sp - 1] = v << amt;
+ } else if (amt < 0) {
+ stack[sp - 1] = v >> -amt;
+ } else {
+ stack[sp - 1] = v;
+ }
+ break;
+ }
+ case OP.ADD:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] += b;
+ break;
+ }
+ case OP.SUB:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] -= b;
+ break;
+ }
+ case OP.MUL:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] *= b;
+ break;
+ }
+ case OP.DIV:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = b !== 0 ? stack[sp - 1] / b : 0;
+ break;
+ }
+ case OP.IDIV:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = b !== 0 ? Math.trunc(stack[sp - 1] / b) : 0;
+ break;
+ }
+ case OP.MOD:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = b !== 0 ? stack[sp - 1] % b : 0;
+ break;
+ }
+ case OP.POW:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] **= b;
+ break;
+ }
+ case OP.EQ:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = stack[sp - 1] === b ? 1 : 0;
+ break;
+ }
+ case OP.NE:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = stack[sp - 1] !== b ? 1 : 0;
+ break;
+ }
+ case OP.GT:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = stack[sp - 1] > b ? 1 : 0;
+ break;
+ }
+ case OP.GE:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = stack[sp - 1] >= b ? 1 : 0;
+ break;
+ }
+ case OP.LT:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = stack[sp - 1] < b ? 1 : 0;
+ break;
+ }
+ case OP.LE:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = stack[sp - 1] <= b ? 1 : 0;
+ break;
+ }
+ case OP.AND:
+ {
+ const b = stack[--sp] | 0;
+ stack[sp - 1] = (stack[sp - 1] | 0) & b;
+ break;
+ }
+ case OP.OR:
+ {
+ const b = stack[--sp] | 0;
+ stack[sp - 1] = stack[sp - 1] | 0 | b;
+ break;
+ }
+ case OP.XOR:
+ {
+ const b = stack[--sp] | 0;
+ stack[sp - 1] = (stack[sp - 1] | 0) ^ b;
+ break;
+ }
+ case OP.ATAN:
+ {
+ const b = stack[--sp];
+ const deg = Math.atan2(stack[sp - 1], b) * _RAD_TO_DEG;
+ stack[sp - 1] = deg < 0 ? deg + 360 : deg;
+ break;
+ }
+ case OP.MIN:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = Math.min(stack[sp - 1], b);
+ break;
+ }
+ case OP.MAX:
+ {
+ const b = stack[--sp];
+ stack[sp - 1] = Math.max(stack[sp - 1], b);
+ break;
+ }
+ case OP.TEE_TMP:
+ tmp[ir[ip++] | 0] = stack[sp - 1];
+ break;
+ case OP.LOAD_TMP:
+ stack[sp++] = tmp[ir[ip++] | 0];
+ break;
+ }
+ }
+ }
+}
+class PSStackBasedInterpreter {
+ static #stack = new Float64Array(100);
+ static #sp = 0;
+ static #push(v) {
+ if (this.#sp < this.#stack.length) {
+ this.#stack[this.#sp++] = v;
+ }
+ }
+ static #execOp(op) {
+ const stack = this.#stack;
+ switch (op) {
+ case TOKEN.true:
+ this.#push(1);
+ break;
+ case TOKEN.false:
+ this.#push(0);
+ break;
+ case TOKEN.abs:
+ stack[this.#sp - 1] = Math.abs(stack[this.#sp - 1]);
+ break;
+ case TOKEN.neg:
+ stack[this.#sp - 1] = -stack[this.#sp - 1];
+ break;
+ case TOKEN.ceiling:
+ stack[this.#sp - 1] = Math.ceil(stack[this.#sp - 1]);
+ break;
+ case TOKEN.floor:
+ stack[this.#sp - 1] = Math.floor(stack[this.#sp - 1]);
+ break;
+ case TOKEN.round:
+ stack[this.#sp - 1] = Math.floor(stack[this.#sp - 1] + 0.5);
+ break;
+ case TOKEN.truncate:
+ stack[this.#sp - 1] = Math.trunc(stack[this.#sp - 1]);
+ break;
+ case TOKEN.sqrt:
+ stack[this.#sp - 1] = Math.sqrt(stack[this.#sp - 1]);
+ break;
+ case TOKEN.sin:
+ stack[this.#sp - 1] = Math.sin(stack[this.#sp - 1] % 360 * _DEG_TO_RAD);
+ break;
+ case TOKEN.cos:
+ stack[this.#sp - 1] = Math.cos(stack[this.#sp - 1] % 360 * _DEG_TO_RAD);
+ break;
+ case TOKEN.ln:
+ stack[this.#sp - 1] = Math.log(stack[this.#sp - 1]);
+ break;
+ case TOKEN.log:
+ stack[this.#sp - 1] = Math.log10(stack[this.#sp - 1]);
+ break;
+ case TOKEN.cvi:
+ stack[this.#sp - 1] = Math.trunc(stack[this.#sp - 1]) | 0;
+ break;
+ case TOKEN.cvr:
+ break;
+ case TOKEN.not:
+ {
+ const v = stack[this.#sp - 1];
+ stack[this.#sp - 1] = v === 0 || v === 1 ? 1 - v : ~(v | 0);
+ break;
+ }
+ case TOKEN.add:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] += b;
+ break;
+ }
+ case TOKEN.sub:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] -= b;
+ break;
+ }
+ case TOKEN.mul:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] *= b;
+ break;
+ }
+ case TOKEN.div:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = b !== 0 ? stack[this.#sp - 1] / b : 0;
+ break;
+ }
+ case TOKEN.idiv:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = b !== 0 ? Math.trunc(stack[this.#sp - 1] / b) : 0;
+ break;
+ }
+ case TOKEN.mod:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = b !== 0 ? stack[this.#sp - 1] % b : 0;
+ break;
+ }
+ case TOKEN.exp:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] **= b;
+ break;
+ }
+ case TOKEN.atan:
+ {
+ const dx = stack[--this.#sp];
+ const deg = Math.atan2(stack[this.#sp - 1], dx) * _RAD_TO_DEG;
+ stack[this.#sp - 1] = deg < 0 ? deg + 360 : deg;
+ break;
+ }
+ case TOKEN.eq:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = stack[this.#sp - 1] === b ? 1 : 0;
+ break;
+ }
+ case TOKEN.ne:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = stack[this.#sp - 1] !== b ? 1 : 0;
+ break;
+ }
+ case TOKEN.gt:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = stack[this.#sp - 1] > b ? 1 : 0;
+ break;
+ }
+ case TOKEN.ge:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = stack[this.#sp - 1] >= b ? 1 : 0;
+ break;
+ }
+ case TOKEN.lt:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = stack[this.#sp - 1] < b ? 1 : 0;
+ break;
+ }
+ case TOKEN.le:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = stack[this.#sp - 1] <= b ? 1 : 0;
+ break;
+ }
+ case TOKEN.and:
+ {
+ const b = stack[--this.#sp] | 0;
+ stack[this.#sp - 1] = (stack[this.#sp - 1] | 0) & b;
+ break;
+ }
+ case TOKEN.or:
+ {
+ const b = stack[--this.#sp] | 0;
+ stack[this.#sp - 1] = stack[this.#sp - 1] | 0 | b;
+ break;
+ }
+ case TOKEN.xor:
+ {
+ const b = stack[--this.#sp] | 0;
+ stack[this.#sp - 1] = (stack[this.#sp - 1] | 0) ^ b;
+ break;
+ }
+ case TOKEN.bitshift:
+ {
+ const amt = stack[--this.#sp] | 0;
+ const v = stack[this.#sp - 1] | 0;
+ stack[this.#sp - 1] = amt > 0 ? v << amt : v >> -amt;
+ break;
+ }
+ case TOKEN.min:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = Math.min(stack[this.#sp - 1], b);
+ break;
+ }
+ case TOKEN.max:
+ {
+ const b = stack[--this.#sp];
+ stack[this.#sp - 1] = Math.max(stack[this.#sp - 1], b);
+ break;
+ }
+ case TOKEN.dup:
+ this.#push(stack[this.#sp - 1]);
+ break;
+ case TOKEN.exch:
+ {
+ const a = stack[--this.#sp];
+ const b = stack[--this.#sp];
+ this.#push(a);
+ this.#push(b);
+ break;
+ }
+ case TOKEN.pop:
+ this.#sp--;
+ break;
+ case TOKEN.copy:
+ {
+ const n = Math.trunc(stack[--this.#sp]);
+ const base = this.#sp - n;
+ for (let k = 0; k < n; k++) {
+ this.#push(stack[base + k]);
+ }
+ break;
+ }
+ case TOKEN.index:
+ {
+ const i = Math.trunc(stack[--this.#sp]);
+ this.#push(stack[this.#sp - 1 - i]);
+ break;
+ }
+ case TOKEN.roll:
+ {
+ const j = Math.trunc(stack[--this.#sp]);
+ const n = Math.trunc(stack[--this.#sp]);
+ if (n > 1 && j !== 0) {
+ const mod = (j % n + n) % n;
+ if (mod !== 0) {
+ const base = this.#sp - n;
+ const sub = stack.slice(base, this.#sp);
+ for (let k = 0; k < n; k++) {
+ stack[base + k] = sub[(k - mod + n) % n];
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ static #execBlock(instructions) {
+ for (const instr of instructions) {
+ switch (instr.type) {
+ case PS_NODE.number:
+ this.#push(instr.value);
+ break;
+ case PS_NODE.operator:
+ this.#execOp(instr.op);
+ break;
+ case PS_NODE.if:
+ if (this.#stack[--this.#sp] !== 0) {
+ this.#execBlock(instr.then.instructions);
+ }
+ break;
+ case PS_NODE.ifelse:
+ if (this.#stack[--this.#sp] !== 0) {
+ this.#execBlock(instr.then.instructions);
+ } else {
+ this.#execBlock(instr.otherwise.instructions);
+ }
+ break;
+ }
+ }
+ }
+ static build(program, domain, range) {
+ const nIn = domain.length >> 1;
+ const nOut = range.length >> 1;
+ const {
+ instructions
+ } = program.body;
+ return (src, srcOffset, dest, destOffset) => {
+ this.#sp = 0;
+ for (let i = 0; i < nIn; i++) {
+ this.#push(src[srcOffset + i]);
+ }
+ this.#execBlock(instructions);
+ const base = this.#sp - nOut;
+ for (let i = 0; i < nOut; i++) {
+ const v = base + i >= 0 ? this.#stack[base + i] : 0;
+ dest[destOffset + i] = MathClamp(v, range[i * 2], range[i * 2 + 1]);
+ }
+ };
+ }
+}
+function buildPostScriptJsFunction(source, domain, range, forceInterpreter = false) {
+ const program = parsePostScriptFunction(source);
+ const ir = !forceInterpreter && new PsJsCompiler(domain, range).compile(program);
+ if (ir) {
+ return (src, srcOffset, dest, destOffset) => {
+ PsJsCompiler.execute(ir, src, srcOffset, dest, destOffset);
+ };
+ }
+ return PSStackBasedInterpreter.build(program, domain, range);
+}
+
+;// ./src/core/postscript/wasm_compiler.js
+
+
+
+
+
+
+
+
+
+
+
+const wasm_compiler_OP = {
+ if: 0x04,
+ else: 0x05,
+ end: 0x0b,
+ select: 0x1b,
+ call: 0x10,
+ local_get: 0x20,
+ local_set: 0x21,
+ local_tee: 0x22,
+ i32_const: 0x41,
+ i32_eqz: 0x45,
+ i32_and: 0x71,
+ i32_or: 0x72,
+ i32_xor: 0x73,
+ i32_shl: 0x74,
+ i32_shr_s: 0x75,
+ i32_trunc_f64_s: 0xaa,
+ f64_const: 0x44,
+ f64_eq: 0x61,
+ f64_ne: 0x62,
+ f64_lt: 0x63,
+ f64_gt: 0x64,
+ f64_le: 0x65,
+ f64_ge: 0x66,
+ f64_abs: 0x99,
+ f64_neg: 0x9a,
+ f64_ceil: 0x9b,
+ f64_floor: 0x9c,
+ f64_trunc: 0x9d,
+ f64_nearest: 0x9e,
+ f64_sqrt: 0x9f,
+ f64_add: 0xa0,
+ f64_sub: 0xa1,
+ f64_mul: 0xa2,
+ f64_div: 0xa3,
+ f64_min: 0xa4,
+ f64_max: 0xa5,
+ f64_convert_i32_s: 0xb7,
+ f64_store: 0x39
+};
+const FUNC_TYPE = 0x60;
+const F64 = 0x7c;
+const SECTION = {
+ type: 0x01,
+ import: 0x02,
+ function: 0x03,
+ memory: 0x05,
+ export: 0x07,
+ code: 0x0a
+};
+const EXTERN_FUNC = 0x00;
+const EXTERN_MEM = 0x02;
+function unsignedLEB128(n) {
+ const out = [];
+ do {
+ let byte = n & 0x7f;
+ n >>>= 7;
+ if (n !== 0) {
+ byte |= 0x80;
+ }
+ out.push(byte);
+ } while (n !== 0);
+ return out;
+}
+function encodeASCIIString(s) {
+ return [...unsignedLEB128(s.length), ...stringToBytes(s)];
+}
+function section(id, data) {
+ return [id, ...unsignedLEB128(data.length), ...data];
+}
+function vec(items) {
+ const out = unsignedLEB128(items.length);
+ for (const item of items) {
+ if (typeof item === "number") {
+ out.push(item);
+ continue;
+ }
+ for (const byte of item) {
+ out.push(byte);
+ }
+ }
+ return out;
+}
+const MATH_IMPORTS = [["sin", "Math", "sin", [F64], [F64]], ["cos", "Math", "cos", [F64], [F64]], ["atan2", "Math", "atan2", [F64, F64], [F64]], ["log", "Math", "log", [F64], [F64]], ["log10", "Math", "log10", [F64], [F64]], ["pow", "Math", "pow", [F64, F64], [F64]]];
+const _mathImportObject = {
+ Math: Object.fromEntries(MATH_IMPORTS.map(([name]) => [name, Math[name]]))
+};
+class PsWasmCompiler {
+ static #initialized = false;
+ static #comparisonToOp = null;
+ static #importIdx = null;
+ static #degToRad = 0;
+ static #radToDeg = 0;
+ static #importTypeEntries = null;
+ static #importSection = null;
+ static #functionSection = null;
+ static #memorySection = null;
+ static #exportSection = null;
+ static #wasmMagicVersion = null;
+ static #f64View = null;
+ static #f64Arr = null;
+ static #init() {
+ this.#comparisonToOp = new Map([[TOKEN.eq, wasm_compiler_OP.f64_eq], [TOKEN.ne, wasm_compiler_OP.f64_ne], [TOKEN.lt, wasm_compiler_OP.f64_lt], [TOKEN.le, wasm_compiler_OP.f64_le], [TOKEN.gt, wasm_compiler_OP.f64_gt], [TOKEN.ge, wasm_compiler_OP.f64_ge]]);
+ this.#importIdx = Object.create(null);
+ for (let i = 0; i < MATH_IMPORTS.length; i++) {
+ this.#importIdx[MATH_IMPORTS[i][0]] = i;
+ }
+ this.#degToRad = Math.PI / 180;
+ this.#radToDeg = 180 / Math.PI;
+ this.#importTypeEntries = MATH_IMPORTS.map(([,,, params, results]) => [FUNC_TYPE, ...vec(params), ...vec(results)]);
+ this.#importSection = new Uint8Array(section(SECTION.import, vec(MATH_IMPORTS.map(([, mod, field], i) => [...encodeASCIIString(mod), ...encodeASCIIString(field), EXTERN_FUNC, ...unsignedLEB128(i + 1)]))));
+ this.#functionSection = new Uint8Array(section(SECTION.function, vec([[0]])));
+ this.#memorySection = new Uint8Array(section(SECTION.memory, vec([[0x00, 0x01]])));
+ this.#exportSection = new Uint8Array(section(SECTION.export, vec([[...encodeASCIIString("fn"), EXTERN_FUNC, ...unsignedLEB128(MATH_IMPORTS.length)], [...encodeASCIIString("mem"), EXTERN_MEM, 0x00]])));
+ this.#wasmMagicVersion = new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]);
+ const f64Buf = new ArrayBuffer(8);
+ this.#f64View = new DataView(f64Buf);
+ this.#f64Arr = new Uint8Array(f64Buf);
+ this.#initialized = true;
+ }
+ constructor(domain, range) {
+ if (!PsWasmCompiler.#initialized) {
+ PsWasmCompiler.#init();
+ }
+ this._nIn = domain.length >> 1;
+ this._nOut = range.length >> 1;
+ this._range = range;
+ this._code = [];
+ this._nextLocal = this._nIn;
+ this._freeLocals = [];
+ this._sharedLocals = new Map();
+ }
+ _allocLocal() {
+ return this._freeLocals.pop() ?? this._nextLocal++;
+ }
+ _releaseLocal(idx) {
+ this._freeLocals.push(idx);
+ }
+ _emitULEB128(n) {
+ do {
+ let b = n & 0x7f;
+ n >>>= 7;
+ if (n !== 0) {
+ b |= 0x80;
+ }
+ this._code.push(b);
+ } while (n !== 0);
+ }
+ _emitSLEB128(n) {
+ for (;;) {
+ const b = n & 0x7f;
+ n >>= 7;
+ if (n === 0 && (b & 0x40) === 0 || n === -1 && (b & 0x40) !== 0) {
+ this._code.push(b);
+ return;
+ }
+ this._code.push(b | 0x80);
+ }
+ }
+ _emitF64Const(value) {
+ this._code.push(wasm_compiler_OP.f64_const);
+ PsWasmCompiler.#f64View.setFloat64(0, value, true);
+ for (let i = 0; i < 8; i++) {
+ this._code.push(PsWasmCompiler.#f64Arr[i]);
+ }
+ }
+ _emitLocalGet(idx) {
+ this._code.push(wasm_compiler_OP.local_get);
+ this._emitULEB128(idx);
+ }
+ _emitLocalSet(idx) {
+ this._code.push(wasm_compiler_OP.local_set);
+ this._emitULEB128(idx);
+ }
+ _emitLocalTee(idx) {
+ this._code.push(wasm_compiler_OP.local_tee);
+ this._emitULEB128(idx);
+ }
+ _compileNode(node) {
+ if (node.shared) {
+ const entry = this._sharedLocals.get(node);
+ if (entry !== undefined) {
+ this._emitLocalGet(entry.local);
+ if (--entry.remaining === 0) {
+ this._releaseLocal(entry.local);
+ }
+ return true;
+ }
+ if (!this._compileNodeImpl(node)) {
+ return false;
+ }
+ const local = this._allocLocal();
+ this._sharedLocals.set(node, {
+ local,
+ remaining: node.sharedCount - 1
+ });
+ this._emitLocalTee(local);
+ return true;
+ }
+ return this._compileNodeImpl(node);
+ }
+ _compileNodeImpl(node) {
+ switch (node.type) {
+ case PS_NODE.arg:
+ this._emitLocalGet(node.index);
+ return true;
+ case PS_NODE.const:
+ {
+ let v = node.value;
+ if (typeof v === "boolean") {
+ v = v ? 1 : 0;
+ }
+ this._emitF64Const(v);
+ return true;
+ }
+ case PS_NODE.unary:
+ return this._compileUnaryNode(node);
+ case PS_NODE.binary:
+ return this._compileBinaryNode(node);
+ case PS_NODE.ternary:
+ return this._compileTernaryNode(node);
+ default:
+ return false;
+ }
+ }
+ _compileSinCosNode(node) {
+ const local = this._allocLocal();
+ try {
+ if (!this._compileNode(node.operand)) {
+ return false;
+ }
+ const code = this._code;
+ this._emitLocalSet(local);
+ this._emitLocalGet(local);
+ this._emitLocalGet(local);
+ this._emitF64Const(360);
+ code.push(wasm_compiler_OP.f64_div, wasm_compiler_OP.f64_trunc);
+ this._emitF64Const(360);
+ code.push(wasm_compiler_OP.f64_mul, wasm_compiler_OP.f64_sub);
+ this._emitF64Const(PsWasmCompiler.#degToRad);
+ code.push(wasm_compiler_OP.f64_mul, wasm_compiler_OP.call);
+ this._emitULEB128(PsWasmCompiler.#importIdx[node.op === TOKEN.sin ? "sin" : "cos"]);
+ return true;
+ } finally {
+ this._releaseLocal(local);
+ }
+ }
+ _compileUnaryNode(node) {
+ const code = this._code;
+ if (node.op === TOKEN.sin || node.op === TOKEN.cos) {
+ return this._compileSinCosNode(node);
+ }
+ if (node.op === TOKEN.not) {
+ if (node.valueType === PS_VALUE_TYPE.boolean) {
+ if (!this._compileNodeAsBoolI32(node.operand)) {
+ return false;
+ }
+ code.push(wasm_compiler_OP.i32_eqz, wasm_compiler_OP.f64_convert_i32_s);
+ return true;
+ }
+ if (node.valueType === PS_VALUE_TYPE.numeric) {
+ if (!this._compileNode(node.operand)) {
+ return false;
+ }
+ code.push(wasm_compiler_OP.i32_trunc_f64_s, wasm_compiler_OP.i32_const, 0x7f, wasm_compiler_OP.i32_xor, wasm_compiler_OP.f64_convert_i32_s);
+ return true;
+ }
+ return false;
+ }
+ if (!this._compileNode(node.operand)) {
+ return false;
+ }
+ switch (node.op) {
+ case TOKEN.abs:
+ code.push(wasm_compiler_OP.f64_abs);
+ break;
+ case TOKEN.neg:
+ code.push(wasm_compiler_OP.f64_neg);
+ break;
+ case TOKEN.sqrt:
+ code.push(wasm_compiler_OP.f64_sqrt);
+ break;
+ case TOKEN.floor:
+ code.push(wasm_compiler_OP.f64_floor);
+ break;
+ case TOKEN.ceiling:
+ code.push(wasm_compiler_OP.f64_ceil);
+ break;
+ case TOKEN.round:
+ this._emitF64Const(0.5);
+ code.push(wasm_compiler_OP.f64_add, wasm_compiler_OP.f64_floor);
+ break;
+ case TOKEN.truncate:
+ code.push(wasm_compiler_OP.f64_trunc);
+ break;
+ case TOKEN.cvi:
+ code.push(wasm_compiler_OP.i32_trunc_f64_s, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.cvr:
+ break;
+ case TOKEN.ln:
+ code.push(wasm_compiler_OP.call);
+ this._emitULEB128(PsWasmCompiler.#importIdx.log);
+ break;
+ case TOKEN.log:
+ code.push(wasm_compiler_OP.call);
+ this._emitULEB128(PsWasmCompiler.#importIdx.log10);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ _compileSafeDivNode(first, second) {
+ const tmp = this._allocLocal();
+ try {
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ const code = this._code;
+ this._emitLocalTee(tmp);
+ code.push(wasm_compiler_OP.f64_div);
+ this._emitF64Const(0);
+ this._emitLocalGet(tmp);
+ this._emitF64Const(0);
+ code.push(wasm_compiler_OP.f64_ne, wasm_compiler_OP.select);
+ return true;
+ } finally {
+ this._releaseLocal(tmp);
+ }
+ }
+ _compileSafeIdivNode(first, second) {
+ const tmp = this._allocLocal();
+ try {
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ const code = this._code;
+ this._emitLocalTee(tmp);
+ code.push(wasm_compiler_OP.f64_div, wasm_compiler_OP.f64_trunc);
+ this._emitF64Const(0);
+ this._emitLocalGet(tmp);
+ this._emitF64Const(0);
+ code.push(wasm_compiler_OP.f64_ne, wasm_compiler_OP.select);
+ return true;
+ } finally {
+ this._releaseLocal(tmp);
+ }
+ }
+ _compileBitshiftNode(first, second) {
+ if (first.type !== PS_NODE.const || !Number.isInteger(first.value)) {
+ return false;
+ }
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ const code = this._code;
+ code.push(wasm_compiler_OP.i32_trunc_f64_s);
+ const shift = first.value;
+ if (shift > 0) {
+ code.push(wasm_compiler_OP.i32_const);
+ this._emitSLEB128(shift);
+ code.push(wasm_compiler_OP.i32_shl);
+ } else if (shift < 0) {
+ code.push(wasm_compiler_OP.i32_const);
+ this._emitSLEB128(-shift);
+ code.push(wasm_compiler_OP.i32_shr_s);
+ }
+ code.push(wasm_compiler_OP.f64_convert_i32_s);
+ return true;
+ }
+ _compileModNode(first, second) {
+ if (first.type === PS_NODE.const && first.value === 0) {
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ this._code.push(wasm_compiler_OP.drop);
+ this._emitF64Const(0);
+ return true;
+ }
+ const localA = this._allocLocal();
+ try {
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ this._emitLocalTee(localA);
+ const code = this._code;
+ if (first.type === PS_NODE.const) {
+ this._emitLocalGet(localA);
+ this._emitF64Const(first.value);
+ code.push(wasm_compiler_OP.f64_div, wasm_compiler_OP.f64_trunc);
+ this._emitF64Const(first.value);
+ code.push(wasm_compiler_OP.f64_mul, wasm_compiler_OP.f64_sub);
+ } else {
+ const localB = this._allocLocal();
+ try {
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ this._emitLocalSet(localB);
+ this._emitLocalGet(localA);
+ this._emitLocalGet(localB);
+ code.push(wasm_compiler_OP.f64_div, wasm_compiler_OP.f64_trunc);
+ this._emitLocalGet(localB);
+ code.push(wasm_compiler_OP.f64_mul, wasm_compiler_OP.f64_sub);
+ this._emitF64Const(0);
+ this._emitLocalGet(localB);
+ this._emitF64Const(0);
+ code.push(wasm_compiler_OP.f64_ne, wasm_compiler_OP.select);
+ } finally {
+ this._releaseLocal(localB);
+ }
+ }
+ return true;
+ } finally {
+ this._releaseLocal(localA);
+ }
+ }
+ _compileAtanNode(first, second) {
+ const localR = this._allocLocal();
+ try {
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ const code = this._code;
+ code.push(wasm_compiler_OP.call);
+ this._emitULEB128(PsWasmCompiler.#importIdx.atan2);
+ this._emitF64Const(PsWasmCompiler.#radToDeg);
+ code.push(wasm_compiler_OP.f64_mul);
+ this._emitLocalTee(localR);
+ this._emitF64Const(0);
+ code.push(wasm_compiler_OP.f64_lt, wasm_compiler_OP.if, F64);
+ this._emitLocalGet(localR);
+ this._emitF64Const(360);
+ code.push(wasm_compiler_OP.f64_add, wasm_compiler_OP.else);
+ this._emitLocalGet(localR);
+ code.push(wasm_compiler_OP.end);
+ return true;
+ } finally {
+ this._releaseLocal(localR);
+ }
+ }
+ _compileBitwiseNode(op, first, second) {
+ if (!this._compileBitwiseOperandI32(second)) {
+ return false;
+ }
+ if (!this._compileBitwiseOperandI32(first)) {
+ return false;
+ }
+ const code = this._code;
+ switch (op) {
+ case TOKEN.and:
+ code.push(wasm_compiler_OP.i32_and);
+ break;
+ case TOKEN.or:
+ code.push(wasm_compiler_OP.i32_or);
+ break;
+ case TOKEN.xor:
+ code.push(wasm_compiler_OP.i32_xor);
+ break;
+ default:
+ return false;
+ }
+ code.push(wasm_compiler_OP.f64_convert_i32_s);
+ return true;
+ }
+ _compileBitwiseOperandI32(node) {
+ if (node.valueType === PS_VALUE_TYPE.boolean) {
+ return this._compileNodeAsBoolI32(node);
+ }
+ if (!this._compileNode(node)) {
+ return false;
+ }
+ this._code.push(wasm_compiler_OP.i32_trunc_f64_s);
+ return true;
+ }
+ _compileStandardBinaryNode(op, first, second) {
+ if (first === second && first.type !== PS_NODE.arg && first.type !== PS_NODE.const && !first.shared) {
+ const tmp = this._allocLocal();
+ try {
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ this._emitLocalTee(tmp);
+ this._emitLocalGet(tmp);
+ } finally {
+ this._releaseLocal(tmp);
+ }
+ } else {
+ if (!this._compileNode(second)) {
+ return false;
+ }
+ if (!this._compileNode(first)) {
+ return false;
+ }
+ }
+ const code = this._code;
+ switch (op) {
+ case TOKEN.add:
+ code.push(wasm_compiler_OP.f64_add);
+ break;
+ case TOKEN.sub:
+ code.push(wasm_compiler_OP.f64_sub);
+ break;
+ case TOKEN.mul:
+ code.push(wasm_compiler_OP.f64_mul);
+ break;
+ case TOKEN.exp:
+ code.push(wasm_compiler_OP.call);
+ this._emitULEB128(PsWasmCompiler.#importIdx.pow);
+ break;
+ case TOKEN.eq:
+ code.push(wasm_compiler_OP.f64_eq, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.ne:
+ code.push(wasm_compiler_OP.f64_ne, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.lt:
+ code.push(wasm_compiler_OP.f64_lt, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.le:
+ code.push(wasm_compiler_OP.f64_le, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.gt:
+ code.push(wasm_compiler_OP.f64_gt, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.ge:
+ code.push(wasm_compiler_OP.f64_ge, wasm_compiler_OP.f64_convert_i32_s);
+ break;
+ case TOKEN.min:
+ code.push(wasm_compiler_OP.f64_min);
+ break;
+ case TOKEN.max:
+ code.push(wasm_compiler_OP.f64_max);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ _compileBinaryNode(node) {
+ const {
+ op,
+ first,
+ second
+ } = node;
+ if (op === TOKEN.bitshift) {
+ return this._compileBitshiftNode(first, second);
+ }
+ if (op === TOKEN.div) {
+ return this._compileSafeDivNode(first, second);
+ }
+ if (op === TOKEN.idiv) {
+ return this._compileSafeIdivNode(first, second);
+ }
+ if (op === TOKEN.mod) {
+ return this._compileModNode(first, second);
+ }
+ if (op === TOKEN.atan) {
+ return this._compileAtanNode(first, second);
+ }
+ if (op === TOKEN.and || op === TOKEN.or || op === TOKEN.xor) {
+ return this._compileBitwiseNode(op, first, second);
+ }
+ return this._compileStandardBinaryNode(op, first, second);
+ }
+ _compileNodeAsBoolI32(node) {
+ if (node.type === PS_NODE.binary) {
+ const wasmOp = PsWasmCompiler.#comparisonToOp.get(node.op);
+ if (wasmOp !== undefined) {
+ if (!this._compileNode(node.second)) {
+ return false;
+ }
+ if (!this._compileNode(node.first)) {
+ return false;
+ }
+ this._code.push(wasmOp);
+ return true;
+ }
+ if (node.valueType === PS_VALUE_TYPE.boolean && (node.op === TOKEN.and || node.op === TOKEN.or || node.op === TOKEN.xor)) {
+ if (!this._compileNodeAsBoolI32(node.second)) {
+ return false;
+ }
+ if (!this._compileNodeAsBoolI32(node.first)) {
+ return false;
+ }
+ switch (node.op) {
+ case TOKEN.and:
+ this._code.push(wasm_compiler_OP.i32_and);
+ break;
+ case TOKEN.or:
+ this._code.push(wasm_compiler_OP.i32_or);
+ break;
+ case TOKEN.xor:
+ this._code.push(wasm_compiler_OP.i32_xor);
+ break;
+ }
+ return true;
+ }
+ }
+ if (node.type === PS_NODE.unary && node.op === TOKEN.not && node.valueType === PS_VALUE_TYPE.boolean) {
+ if (!this._compileNodeAsBoolI32(node.operand)) {
+ return false;
+ }
+ this._code.push(wasm_compiler_OP.i32_eqz);
+ return true;
+ }
+ if (!this._compileNode(node)) {
+ return false;
+ }
+ if (node.valueType === PS_VALUE_TYPE.boolean) {
+ this._code.push(wasm_compiler_OP.i32_trunc_f64_s);
+ } else {
+ this._emitF64Const(0);
+ this._code.push(wasm_compiler_OP.f64_ne);
+ }
+ return true;
+ }
+ _compileTernaryNode(node) {
+ if (!this._compileNodeAsBoolI32(node.cond)) {
+ return false;
+ }
+ this._code.push(wasm_compiler_OP.if, F64);
+ if (!this._compileNode(node.then)) {
+ return false;
+ }
+ this._code.push(wasm_compiler_OP.else);
+ if (!this._compileNode(node.otherwise)) {
+ return false;
+ }
+ this._code.push(wasm_compiler_OP.end);
+ return true;
+ }
+ compile(program) {
+ const outputs = new PSStackToTree().evaluate(program, this._nIn);
+ if (!outputs || outputs.length < this._nOut) {
+ return null;
+ }
+ const code = this._code;
+ for (let i = 0; i < this._nOut; i++) {
+ const min = this._range[i * 2];
+ const max = this._range[i * 2 + 1];
+ code.push(wasm_compiler_OP.i32_const);
+ this._emitSLEB128(i * 8);
+ if (!this._compileNode(outputs[i])) {
+ return null;
+ }
+ this._emitF64Const(max);
+ code.push(wasm_compiler_OP.f64_min);
+ this._emitF64Const(min);
+ code.push(wasm_compiler_OP.f64_max, wasm_compiler_OP.f64_store, 0x03, 0x00);
+ }
+ code.push(wasm_compiler_OP.end);
+ const nIn = this._nIn;
+ const nLocals = this._nextLocal - nIn;
+ const paramTypes = Array(nIn).fill(F64);
+ const resultTypes = [];
+ const funcType = [FUNC_TYPE, ...vec(paramTypes), ...vec(resultTypes)];
+ const typeSectionBytes = new Uint8Array(section(SECTION.type, vec([funcType, ...PsWasmCompiler.#importTypeEntries])));
+ const localDecls = nLocals > 0 ? vec([[...unsignedLEB128(nLocals), F64]]) : vec([]);
+ const funcBodyLen = localDecls.length + code.length;
+ const codeSectionBytes = new Uint8Array(section(SECTION.code, vec([[...unsignedLEB128(funcBodyLen), ...localDecls, ...code]])));
+ const magicVersion = PsWasmCompiler.#wasmMagicVersion;
+ const importSection = PsWasmCompiler.#importSection;
+ const functionSection = PsWasmCompiler.#functionSection;
+ const memorySection = PsWasmCompiler.#memorySection;
+ const exportSection = PsWasmCompiler.#exportSection;
+ const totalLen = magicVersion.length + typeSectionBytes.length + importSection.length + functionSection.length + memorySection.length + exportSection.length + codeSectionBytes.length;
+ const result = new Uint8Array(totalLen);
+ let off = 0;
+ result.set(magicVersion, off);
+ off += magicVersion.length;
+ result.set(typeSectionBytes, off);
+ off += typeSectionBytes.length;
+ result.set(importSection, off);
+ off += importSection.length;
+ result.set(functionSection, off);
+ off += functionSection.length;
+ result.set(memorySection, off);
+ off += memorySection.length;
+ result.set(exportSection, off);
+ off += exportSection.length;
+ result.set(codeSectionBytes, off);
+ return result;
+ }
+}
+function compilePostScriptToWasm(source, domain, range) {
+ return new PsWasmCompiler(domain, range).compile(parsePostScriptFunction(source));
+}
+function _makeWrapper(exports, nIn, nOut) {
+ const {
+ fn,
+ mem
+ } = exports;
+ const outView = new Float64Array(mem.buffer, 0, nOut);
+ let writeOut;
+ switch (nOut) {
+ case 1:
+ writeOut = (dest, destOffset) => {
+ dest[destOffset] = outView[0];
+ };
+ break;
+ case 2:
+ writeOut = (dest, destOffset) => {
+ dest[destOffset] = outView[0];
+ dest[destOffset + 1] = outView[1];
+ };
+ break;
+ case 3:
+ writeOut = (dest, destOffset) => {
+ dest[destOffset] = outView[0];
+ dest[destOffset + 1] = outView[1];
+ dest[destOffset + 2] = outView[2];
+ };
+ break;
+ case 4:
+ writeOut = (dest, destOffset) => {
+ dest[destOffset] = outView[0];
+ dest[destOffset + 1] = outView[1];
+ dest[destOffset + 2] = outView[2];
+ dest[destOffset + 3] = outView[3];
+ };
+ break;
+ default:
+ writeOut = (dest, destOffset) => {
+ for (let i = 0; i < nOut; i++) {
+ dest[destOffset + i] = outView[i];
+ }
+ };
+ }
+ switch (nIn) {
+ case 1:
+ return (src, srcOffset, dest, destOffset) => {
+ fn(src[srcOffset]);
+ writeOut(dest, destOffset);
+ };
+ case 2:
+ return (src, srcOffset, dest, destOffset) => {
+ fn(src[srcOffset], src[srcOffset + 1]);
+ writeOut(dest, destOffset);
+ };
+ case 3:
+ return (src, srcOffset, dest, destOffset) => {
+ fn(src[srcOffset], src[srcOffset + 1], src[srcOffset + 2]);
+ writeOut(dest, destOffset);
+ };
+ case 4:
+ return (src, srcOffset, dest, destOffset) => {
+ fn(src[srcOffset], src[srcOffset + 1], src[srcOffset + 2], src[srcOffset + 3]);
+ writeOut(dest, destOffset);
+ };
+ default:
+ {
+ const inBuf = new Float64Array(nIn);
+ return (src, srcOffset, dest, destOffset) => {
+ for (let i = 0; i < nIn; i++) {
+ inBuf[i] = src[srcOffset + i];
+ }
+ fn(...inBuf);
+ writeOut(dest, destOffset);
+ };
+ }
+ }
+}
+function buildPostScriptWasmFunction(source, domain, range) {
+ const bytes = compilePostScriptToWasm(source, domain, range);
+ if (!bytes) {
+ return null;
+ }
+ try {
+ const instance = new WebAssembly.Instance(new WebAssembly.Module(bytes), _mathImportObject);
+ return _makeWrapper(instance.exports, domain.length >> 1, range.length >> 1);
+ } catch {
+ return null;
+ }
+}
+
+;// ./src/core/image_utils.js
+
+
+
+
+class BaseLocalCache {
+ constructor(options) {
+ this._onlyRefs = options?.onlyRefs === true;
+ if (!this._onlyRefs) {
+ this._nameRefMap = new Map();
+ this._imageMap = new Map();
+ }
+ this._imageCache = new RefMap();
+ }
+ getByName(name) {
+ if (this._onlyRefs) {
+ unreachable("Should not call `getByName` method.");
+ }
+ const ref = this._nameRefMap.get(name);
+ if (ref) {
+ return this.getByRef(ref);
+ }
+ return this._imageMap.get(name) || null;
+ }
+ getByRef(ref) {
+ return this._imageCache.get(ref) || null;
+ }
+ set(name, ref, data) {
+ unreachable("Abstract method `set` called.");
+ }
+}
+class LocalImageCache extends BaseLocalCache {
+ set(name, ref = null, data) {
+ if (typeof name !== "string") {
+ throw new Error('LocalImageCache.set - expected "name" argument.');
+ }
+ if (ref) {
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ this._nameRefMap.set(name, ref);
+ this._imageCache.put(ref, data);
+ return;
+ }
+ if (this._imageMap.has(name)) {
+ return;
+ }
+ this._imageMap.set(name, data);
+ }
+}
+class LocalColorSpaceCache extends BaseLocalCache {
+ set(name = null, ref = null, data) {
+ if (typeof name !== "string" && !ref) {
+ throw new Error('LocalColorSpaceCache.set - expected "name" and/or "ref" argument.');
+ }
+ if (ref) {
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ if (name !== null) {
+ this._nameRefMap.set(name, ref);
+ }
+ this._imageCache.put(ref, data);
+ return;
+ }
+ if (this._imageMap.has(name)) {
+ return;
+ }
+ this._imageMap.set(name, data);
+ }
+}
+class LocalFunctionCache extends BaseLocalCache {
+ constructor(options) {
+ super({
+ onlyRefs: true
+ });
+ }
+ set(name = null, ref, data) {
+ if (!ref) {
+ throw new Error('LocalFunctionCache.set - expected "ref" argument.');
+ }
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ this._imageCache.put(ref, data);
+ }
+}
+class LocalGStateCache extends BaseLocalCache {
+ set(name, ref = null, data) {
+ if (typeof name !== "string") {
+ throw new Error('LocalGStateCache.set - expected "name" argument.');
+ }
+ if (ref) {
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ this._nameRefMap.set(name, ref);
+ this._imageCache.put(ref, data);
+ return;
+ }
+ if (this._imageMap.has(name)) {
+ return;
+ }
+ this._imageMap.set(name, data);
+ }
+}
+class LocalTilingPatternCache extends BaseLocalCache {
+ constructor(options) {
+ super({
+ onlyRefs: true
+ });
+ }
+ set(name = null, ref, data) {
+ if (!ref) {
+ throw new Error('LocalTilingPatternCache.set - expected "ref" argument.');
+ }
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ this._imageCache.put(ref, data);
+ }
+}
+class RegionalImageCache extends BaseLocalCache {
+ constructor(options) {
+ super({
+ onlyRefs: true
+ });
+ }
+ set(name = null, ref, data) {
+ if (!ref) {
+ throw new Error('RegionalImageCache.set - expected "ref" argument.');
+ }
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ this._imageCache.put(ref, data);
+ }
+}
+class GlobalColorSpaceCache extends BaseLocalCache {
+ constructor(options) {
+ super({
+ onlyRefs: true
+ });
+ }
+ set(name = null, ref, data) {
+ if (!ref) {
+ throw new Error('GlobalColorSpaceCache.set - expected "ref" argument.');
+ }
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ this._imageCache.put(ref, data);
+ }
+ clear() {
+ this._imageCache.clear();
+ }
+}
+class GlobalImageCache {
+ static NUM_PAGES_THRESHOLD = 2;
+ static MIN_IMAGES_TO_CACHE = 10;
+ static MAX_BYTE_SIZE = 5e7;
+ #decodeFailedSet = new RefSet();
+ constructor() {
+ this._refCache = new RefMap();
+ this._imageCache = new RefMap();
+ }
+ get #byteSize() {
+ let byteSize = 0;
+ for (const imageData of this._imageCache) {
+ byteSize += imageData.byteSize;
+ }
+ return byteSize;
+ }
+ get #cacheLimitReached() {
+ if (this._imageCache.size < GlobalImageCache.MIN_IMAGES_TO_CACHE) {
+ return false;
+ }
+ if (this.#byteSize < GlobalImageCache.MAX_BYTE_SIZE) {
+ return false;
+ }
+ return true;
+ }
+ shouldCache(ref, pageIndex) {
+ const pageIndexSet = this._refCache.getOrPutComputed(ref, makeSet);
+ pageIndexSet.add(pageIndex);
+ if (pageIndexSet.size < GlobalImageCache.NUM_PAGES_THRESHOLD) {
+ return false;
+ }
+ if (!this._imageCache.has(ref) && this.#cacheLimitReached) {
+ return false;
+ }
+ return true;
+ }
+ addDecodeFailed(ref) {
+ this.#decodeFailedSet.put(ref);
+ }
+ hasDecodeFailed(ref) {
+ return this.#decodeFailedSet.has(ref);
+ }
+ addByteSize(ref, byteSize) {
+ const imageData = this._imageCache.get(ref);
+ if (!imageData) {
+ return;
+ }
+ if (imageData.byteSize) {
+ return;
+ }
+ imageData.byteSize = byteSize;
+ }
+ getData(ref, pageIndex) {
+ const pageIndexSet = this._refCache.get(ref);
+ if (!pageIndexSet) {
+ return null;
+ }
+ if (pageIndexSet.size < GlobalImageCache.NUM_PAGES_THRESHOLD) {
+ return null;
+ }
+ const imageData = this._imageCache.get(ref);
+ if (!imageData) {
+ return null;
+ }
+ pageIndexSet.add(pageIndex);
+ return imageData;
+ }
+ setData(ref, data) {
+ if (!this._refCache.has(ref)) {
+ throw new Error('GlobalImageCache.setData - expected "shouldCache" to have been called.');
+ }
+ if (this._imageCache.has(ref)) {
+ return;
+ }
+ if (this.#cacheLimitReached) {
+ warn("GlobalImageCache.setData - cache limit reached.");
+ return;
+ }
+ this._imageCache.put(ref, data);
+ }
+ clear(onlyData = false) {
+ if (!onlyData) {
+ this.#decodeFailedSet.clear();
+ this._refCache.clear();
+ }
+ this._imageCache.clear();
+ }
+}
+
+;// ./src/core/function.js
+
+
+
+
+
+
+
+
+
+
+
+
+const FunctionType = {
+ SAMPLED: 0,
+ EXPONENTIAL_INTERPOLATION: 2,
+ STITCHING: 3,
+ POSTSCRIPT_CALCULATOR: 4
+};
+class PDFFunctionFactory {
+ static #useWasm = true;
+ static setOptions({
+ useWasm
+ }) {
+ this.#useWasm = useWasm;
+ }
+ constructor({
+ xref
+ }) {
+ this.xref = xref;
+ }
+ get useWasm() {
+ return PDFFunctionFactory.#useWasm;
+ }
+ create(fn, parseArray = false) {
+ let fnRef, parsedFn;
+ if (fn instanceof Ref) {
+ fnRef = fn;
+ } else if (fn instanceof Dict) {
+ fnRef = fn.objId;
+ } else if (fn instanceof BaseStream) {
+ fnRef = fn.dict?.objId;
+ }
+ if (fnRef) {
+ const cachedFn = this._localFunctionCache.getByRef(fnRef);
+ if (cachedFn) {
+ return cachedFn;
+ }
+ }
+ const fnObj = this.xref.fetchIfRef(fn);
+ if (Array.isArray(fnObj)) {
+ if (!parseArray) {
+ throw new Error('PDFFunctionFactory.create - expected "parseArray" argument.');
+ }
+ parsedFn = PDFFunction.parseArray(this, fnObj);
+ } else {
+ parsedFn = PDFFunction.parse(this, fnObj);
+ }
+ if (fnRef) {
+ this._localFunctionCache.set(null, fnRef, parsedFn);
+ }
+ return parsedFn;
+ }
+ get _localFunctionCache() {
+ return shadow(this, "_localFunctionCache", new LocalFunctionCache());
+ }
+}
+function toNumberArray(arr) {
+ if (!Array.isArray(arr)) {
+ return null;
+ }
+ if (!isNumberArray(arr, null)) {
+ return arr.map(x => +x);
+ }
+ return arr;
+}
+class PDFFunction {
+ static getSampleArray(size, outputSize, bps, stream) {
+ let length = outputSize;
+ for (const s of size) {
+ length *= s;
+ }
+ const array = new Array(length);
+ let codeSize = 0;
+ let codeBuf = 0;
+ const sampleMul = 1.0 / (2.0 ** bps - 1);
+ const strBytes = stream.getBytes((length * bps + 7) / 8);
+ let strIdx = 0;
+ for (let i = 0; i < length; i++) {
+ while (codeSize < bps) {
+ codeBuf <<= 8;
+ codeBuf |= strBytes[strIdx++];
+ codeSize += 8;
+ }
+ codeSize -= bps;
+ array[i] = (codeBuf >> codeSize) * sampleMul;
+ codeBuf &= (1 << codeSize) - 1;
+ }
+ return array;
+ }
+ static parse(factory, fn) {
+ const dict = fn.dict || fn;
+ const typeNum = dict.get("FunctionType");
+ switch (typeNum) {
+ case FunctionType.SAMPLED:
+ return this.constructSampled(factory, fn, dict);
+ case FunctionType.EXPONENTIAL_INTERPOLATION:
+ return this.constructInterpolated(factory, dict);
+ case FunctionType.STITCHING:
+ return this.constructStiched(factory, dict);
+ case FunctionType.POSTSCRIPT_CALCULATOR:
+ return this.constructPostScript(factory, fn, dict);
+ }
+ throw new FormatError(`Unknown function type: ${typeNum}`);
+ }
+ static parseArray(factory, fnObj) {
+ const {
+ xref
+ } = factory;
+ const fnArray = [];
+ for (const fn of fnObj) {
+ fnArray.push(this.parse(factory, xref.fetchIfRef(fn)));
+ }
+ return function (src, srcOffset, dest, destOffset) {
+ for (let i = 0, ii = fnArray.length; i < ii; i++) {
+ fnArray[i](src, srcOffset, dest, destOffset + i);
+ }
+ };
+ }
+ static constructSampled(factory, fn, dict) {
+ function interpolate(x, xmin, xmax, ymin, ymax) {
+ return ymin + (x - xmin) * ((ymax - ymin) / (xmax - xmin));
+ }
+ const domain = toNumberArray(dict.getArray("Domain"));
+ const range = toNumberArray(dict.getArray("Range"));
+ if (!domain || !range) {
+ throw new FormatError("No domain or range");
+ }
+ const inputSize = domain.length / 2;
+ const outputSize = range.length / 2;
+ const size = toNumberArray(dict.getArray("Size"));
+ const bps = dict.get("BitsPerSample");
+ const order = dict.get("Order") || 1;
+ if (order !== 1) {
+ info("No support for cubic spline interpolation: " + order);
+ }
+ let encode = toNumberArray(dict.getArray("Encode"));
+ if (!encode) {
+ encode = [];
+ for (let i = 0; i < inputSize; ++i) {
+ encode.push(0, size[i] - 1);
+ }
+ }
+ const decode = toNumberArray(dict.getArray("Decode")) || range;
+ const samples = this.getSampleArray(size, outputSize, bps, fn);
+ return function constructSampledFn(src, srcOffset, dest, destOffset) {
+ const cubeVertices = 1 << inputSize;
+ const cubeN = new Float64Array(cubeVertices).fill(1);
+ const cubeVertex = new Uint32Array(cubeVertices);
+ let i, j;
+ let k = outputSize,
+ pos = 1;
+ for (i = 0; i < inputSize; ++i) {
+ const domain_2i = domain[2 * i];
+ const domain_2i_1 = domain[2 * i + 1];
+ const xi = MathClamp(src[srcOffset + i], domain_2i, domain_2i_1);
+ let e = interpolate(xi, domain_2i, domain_2i_1, encode[2 * i], encode[2 * i + 1]);
+ const size_i = size[i];
+ e = MathClamp(e, 0, size_i - 1);
+ const e0 = e < size_i - 1 ? Math.floor(e) : e - 1;
+ const n0 = e0 + 1 - e;
+ const n1 = e - e0;
+ const offset0 = e0 * k;
+ const offset1 = offset0 + k;
+ for (j = 0; j < cubeVertices; j++) {
+ if (j & pos) {
+ cubeN[j] *= n1;
+ cubeVertex[j] += offset1;
+ } else {
+ cubeN[j] *= n0;
+ cubeVertex[j] += offset0;
+ }
+ }
+ k *= size_i;
+ pos <<= 1;
+ }
+ for (j = 0; j < outputSize; ++j) {
+ let rj = 0;
+ for (i = 0; i < cubeVertices; i++) {
+ rj += samples[cubeVertex[i] + j] * cubeN[i];
+ }
+ rj = interpolate(rj, 0, 1, decode[2 * j], decode[2 * j + 1]);
+ dest[destOffset + j] = MathClamp(rj, range[2 * j], range[2 * j + 1]);
+ }
+ };
+ }
+ static constructInterpolated(factory, dict) {
+ const c0 = toNumberArray(dict.getArray("C0")) || [0];
+ const c1 = toNumberArray(dict.getArray("C1")) || [1];
+ const n = dict.get("N");
+ const diff = [];
+ for (let i = 0, ii = c0.length; i < ii; ++i) {
+ diff.push(c1[i] - c0[i]);
+ }
+ const length = diff.length;
+ return function constructInterpolatedFn(src, srcOffset, dest, destOffset) {
+ const x = n === 1 ? src[srcOffset] : src[srcOffset] ** n;
+ for (let j = 0; j < length; ++j) {
+ dest[destOffset + j] = c0[j] + x * diff[j];
+ }
+ };
+ }
+ static constructStiched(factory, dict) {
+ const domain = toNumberArray(dict.getArray("Domain"));
+ if (!domain) {
+ throw new FormatError("No domain");
+ }
+ const inputSize = domain.length / 2;
+ if (inputSize !== 1) {
+ throw new FormatError("Bad domain for stiched function");
+ }
+ const {
+ xref
+ } = factory;
+ const fns = [];
+ for (const fn of dict.get("Functions")) {
+ fns.push(this.parse(factory, xref.fetchIfRef(fn)));
+ }
+ const bounds = toNumberArray(dict.getArray("Bounds"));
+ const encode = toNumberArray(dict.getArray("Encode"));
+ const tmpBuf = new Float32Array(1);
+ return function constructStichedFn(src, srcOffset, dest, destOffset) {
+ const v = MathClamp(src[srcOffset], domain[0], domain[1]);
+ const length = bounds.length;
+ let i;
+ for (i = 0; i < length; ++i) {
+ if (v < bounds[i]) {
+ break;
+ }
+ }
+ const dmin = i > 0 ? bounds[i - 1] : domain[0];
+ const dmax = i < length ? bounds[i] : domain[1];
+ const rmin = encode[2 * i];
+ const rmax = encode[2 * i + 1];
+ tmpBuf[0] = dmin === dmax ? rmin : rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
+ fns[i](tmpBuf, 0, dest, destOffset);
+ };
+ }
+ static constructPostScript(factory, fn, dict) {
+ const domain = toNumberArray(dict.getArray("Domain"));
+ const range = toNumberArray(dict.getArray("Range"));
+ if (!domain) {
+ throw new FormatError("No domain.");
+ }
+ if (!range) {
+ throw new FormatError("No range.");
+ }
+ const psCode = fn.getString();
+ try {
+ if (factory.useWasm) {
+ const wasmFn = buildPostScriptWasmFunction(psCode, domain, range);
+ if (wasmFn) {
+ return wasmFn;
+ }
+ }
+ } catch {}
+ warn("Failed to compile PostScript function to wasm, falling back to JS");
+ return buildPostScriptJsFunction(psCode, domain, range);
+ }
+}
+function isPDFFunction(v) {
+ let fnDict;
+ if (v instanceof Dict) {
+ fnDict = v;
+ } else if (v instanceof BaseStream) {
+ fnDict = v.dict;
+ } else {
+ return false;
+ }
+ return fnDict.has("FunctionType");
+}
+
+;// ./src/core/evaluator_utils.js
+
+
+
+function textSinkWrapper(sink) {
+ const TEXT_CONTENT_CHUNK_SIZE = 100;
+ const resolved = sink ? null : Promise.resolve();
+ return {
+ enqueueInvoked: false,
+ enqueue(chunk, size) {
+ this.enqueueInvoked = true;
+ sink?.enqueue(chunk, size);
+ },
+ get desiredSize() {
+ return sink?.desiredSize ?? TEXT_CONTENT_CHUNK_SIZE;
+ },
+ get ready() {
+ return sink?.ready ?? resolved;
+ }
+ };
+}
+function _parseVisibilityExpression(xref, array, nestingCounter, currentResult) {
+ const MAX_NESTING = 10;
+ if (++nestingCounter > MAX_NESTING) {
+ warn("Visibility expression is too deeply nested");
+ return;
+ }
+ const length = array.length;
+ const operator = xref.fetchIfRef(array[0]);
+ if (length < 2 || !(operator instanceof Name)) {
+ warn("Invalid visibility expression");
+ return;
+ }
+ switch (operator.name) {
+ case "And":
+ case "Or":
+ case "Not":
+ currentResult.push(operator.name);
+ break;
+ default:
+ warn(`Invalid operator ${operator.name} in visibility expression`);
+ return;
+ }
+ for (let i = 1; i < length; i++) {
+ const raw = array[i];
+ const object = xref.fetchIfRef(raw);
+ if (Array.isArray(object)) {
+ const nestedResult = [];
+ currentResult.push(nestedResult);
+ _parseVisibilityExpression(xref, object, nestingCounter, nestedResult);
+ } else if (raw instanceof Ref) {
+ currentResult.push(raw.toString());
+ }
+ }
+}
+function parseMarkedContentProps(xref, contentProperties, resources) {
+ let optionalContent;
+ if (contentProperties instanceof Name) {
+ const properties = resources.get("Properties");
+ optionalContent = properties.get(contentProperties.name);
+ } else if (contentProperties instanceof Dict) {
+ optionalContent = contentProperties;
+ } else {
+ throw new FormatError("Optional content properties malformed.");
+ }
+ const optionalContentType = optionalContent.get("Type")?.name;
+ if (optionalContentType === "OCG") {
+ return {
+ type: optionalContentType,
+ id: optionalContent.objId
+ };
+ } else if (optionalContentType === "OCMD") {
+ const expression = optionalContent.get("VE");
+ if (Array.isArray(expression)) {
+ const result = [];
+ _parseVisibilityExpression(xref, expression, 0, result);
+ if (result.length > 0) {
+ return {
+ type: "OCMD",
+ expression: result
+ };
+ }
+ }
+ const optionalContentGroups = optionalContent.get("OCGs");
+ if (Array.isArray(optionalContentGroups) || optionalContentGroups instanceof Dict) {
+ const groupIds = [];
+ if (Array.isArray(optionalContentGroups)) {
+ for (const ocg of optionalContentGroups) {
+ groupIds.push(ocg.toString());
+ }
+ } else {
+ groupIds.push(optionalContentGroups.objId);
+ }
+ const p = optionalContent.get("P");
+ return {
+ type: optionalContentType,
+ ids: groupIds,
+ policy: p instanceof Name ? p.name : null,
+ expression: null
+ };
+ } else if (optionalContentGroups instanceof Ref) {
+ return {
+ type: optionalContentType,
+ id: optionalContentGroups.toString()
+ };
+ }
+ }
+ return null;
+}
+
+;// ./src/core/bidi.js
+
+const baseTypes = ["BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "S", "B", "S", "WS", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "B", "B", "B", "S", "WS", "ON", "ON", "ET", "ET", "ET", "ON", "ON", "ON", "ON", "ON", "ES", "CS", "ES", "CS", "CS", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "CS", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "ON", "ON", "ON", "BN", "BN", "BN", "BN", "BN", "BN", "B", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "BN", "CS", "ON", "ET", "ET", "ET", "ET", "ON", "ON", "ON", "ON", "L", "ON", "ON", "BN", "ON", "ON", "ET", "ET", "EN", "EN", "ON", "L", "ON", "ON", "ON", "EN", "L", "ON", "ON", "ON", "ON", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "L", "ON", "L", "L", "L", "L", "L", "L", "L", "L"];
+const arabicTypes = ["AN", "AN", "AN", "AN", "AN", "AN", "ON", "ON", "AL", "ET", "ET", "AL", "CS", "AL", "ON", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "AN", "ET", "AN", "AN", "AL", "AL", "AL", "NSM", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "AL", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AN", "ON", "NSM", "NSM", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "NSM", "NSM", "ON", "NSM", "NSM", "NSM", "NSM", "AL", "AL", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "EN", "AL", "AL", "AL", "AL", "AL", "AL"];
+function isOdd(i) {
+ return (i & 1) !== 0;
+}
+function isEven(i) {
+ return (i & 1) === 0;
+}
+function findUnequal(arr, start, value) {
+ let j, jj;
+ for (j = start, jj = arr.length; j < jj; ++j) {
+ if (arr[j] !== value) {
+ return j;
+ }
+ }
+ return j;
+}
+function reverseValues(arr, start, end) {
+ for (let i = start, j = end - 1; i < j; ++i, --j) {
+ const temp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = temp;
+ }
+}
+function createBidiText(str, isLTR, vertical = false) {
+ let dir = "ltr";
+ if (vertical) {
+ dir = "ttb";
+ } else if (!isLTR) {
+ dir = "rtl";
+ }
+ return {
+ str,
+ dir
+ };
+}
+const chars = [];
+const types = [];
+function bidi(str, startLevel = -1, vertical = false) {
+ let isLTR = true;
+ const strLength = str.length;
+ if (strLength === 0 || vertical) {
+ return createBidiText(str, isLTR, vertical);
+ }
+ chars.length = strLength;
+ types.length = strLength;
+ let numBidi = 0;
+ let i, ii;
+ for (i = 0; i < strLength; ++i) {
+ chars[i] = str.charAt(i);
+ const charCode = str.charCodeAt(i);
+ let charType = "L";
+ if (charCode <= 0x00ff) {
+ charType = baseTypes[charCode];
+ } else if (0x0590 <= charCode && charCode <= 0x05f4) {
+ charType = "R";
+ } else if (0x0600 <= charCode && charCode <= 0x06ff) {
+ charType = arabicTypes[charCode & 0xff];
+ if (!charType) {
+ warn("Bidi: invalid Unicode character " + charCode.toString(16));
+ }
+ } else if (0x0700 <= charCode && charCode <= 0x08ac || 0xfb50 <= charCode && charCode <= 0xfdff || 0xfe70 <= charCode && charCode <= 0xfeff) {
+ charType = "AL";
+ }
+ if (charType === "R" || charType === "AL" || charType === "AN") {
+ numBidi++;
+ }
+ types[i] = charType;
+ }
+ if (numBidi === 0) {
+ isLTR = true;
+ return createBidiText(str, isLTR);
+ }
+ if (startLevel === -1) {
+ if (numBidi / strLength < 0.3 && strLength > 4) {
+ isLTR = true;
+ startLevel = 0;
+ } else {
+ isLTR = false;
+ startLevel = 1;
+ }
+ }
+ const levels = [];
+ for (i = 0; i < strLength; ++i) {
+ levels[i] = startLevel;
+ }
+ const e = isOdd(startLevel) ? "R" : "L";
+ const sor = e;
+ const eor = sor;
+ let lastType = sor;
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === "NSM") {
+ types[i] = lastType;
+ } else {
+ lastType = types[i];
+ }
+ }
+ lastType = sor;
+ let t;
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === "EN") {
+ types[i] = lastType === "AL" ? "AN" : "EN";
+ } else if (t === "R" || t === "L" || t === "AL") {
+ lastType = t;
+ }
+ }
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === "AL") {
+ types[i] = "R";
+ }
+ }
+ for (i = 1; i < strLength - 1; ++i) {
+ if (types[i] === "ES" && types[i - 1] === "EN" && types[i + 1] === "EN") {
+ types[i] = "EN";
+ }
+ if (types[i] === "CS" && (types[i - 1] === "EN" || types[i - 1] === "AN") && types[i + 1] === types[i - 1]) {
+ types[i] = types[i - 1];
+ }
+ }
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === "EN") {
+ for (let j = i - 1; j >= 0; --j) {
+ if (types[j] !== "ET") {
+ break;
+ }
+ types[j] = "EN";
+ }
+ for (let j = i + 1; j < strLength; ++j) {
+ if (types[j] !== "ET") {
+ break;
+ }
+ types[j] = "EN";
+ }
+ }
+ }
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === "WS" || t === "ES" || t === "ET" || t === "CS") {
+ types[i] = "ON";
+ }
+ }
+ lastType = sor;
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === "EN") {
+ types[i] = lastType === "L" ? "L" : "EN";
+ } else if (t === "R" || t === "L") {
+ lastType = t;
+ }
+ }
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === "ON") {
+ const end = findUnequal(types, i + 1, "ON");
+ let before = sor;
+ for (let j = i - 1; j >= 0; j--) {
+ const tt = types[j];
+ if (tt === "L") {
+ before = "L";
+ break;
+ }
+ if (tt === "R" || tt === "EN" || tt === "AN") {
+ before = "R";
+ break;
+ }
+ }
+ let after = eor;
+ for (let j = end; j < strLength; j++) {
+ const tt = types[j];
+ if (tt === "L") {
+ after = "L";
+ break;
+ }
+ if (tt === "R" || tt === "EN" || tt === "AN") {
+ after = "R";
+ break;
+ }
+ }
+ if (before === after) {
+ types.fill(before, i, end);
+ }
+ i = end - 1;
+ }
+ }
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === "ON") {
+ types[i] = e;
+ }
+ }
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (isEven(levels[i])) {
+ if (t === "R") {
+ levels[i] += 1;
+ } else if (t === "AN" || t === "EN") {
+ levels[i] += 2;
+ }
+ } else if (t === "L" || t === "AN" || t === "EN") {
+ levels[i] += 1;
+ }
+ }
+ let highestLevel = -1;
+ let lowestOddLevel = 99;
+ let level;
+ for (i = 0, ii = levels.length; i < ii; ++i) {
+ level = levels[i];
+ if (highestLevel < level) {
+ highestLevel = level;
+ }
+ if (lowestOddLevel > level && isOdd(level)) {
+ lowestOddLevel = level;
+ }
+ }
+ for (level = highestLevel; level >= lowestOddLevel; --level) {
+ let start = -1;
+ for (i = 0, ii = levels.length; i < ii; ++i) {
+ if (levels[i] < level) {
+ if (start >= 0) {
+ reverseValues(chars, start, i);
+ start = -1;
+ }
+ } else if (start < 0) {
+ start = i;
+ }
+ }
+ if (start >= 0) {
+ reverseValues(chars, start, levels.length);
+ }
+ }
+ for (i = 0, ii = chars.length; i < ii; ++i) {
+ const ch = chars[i];
+ if (ch === "<" || ch === ">") {
+ chars[i] = "";
+ }
+ }
+ return createBidiText(chars.join(""), isLTR);
+}
+
+;// ./src/core/font_substitutions.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const NORMAL = {
+ style: "normal",
+ weight: "normal"
+};
+const MEDIUM = {
+ style: "normal",
+ weight: "500"
+};
+const BOLD = {
+ style: "normal",
+ weight: "bold"
+};
+const ITALIC = {
+ style: "italic",
+ weight: "normal"
+};
+const BOLDITALIC = {
+ style: "italic",
+ weight: "bold"
+};
+const substitutionMap = new Map([["Times-Roman", {
+ local: ["Times New Roman", "Times-Roman", "Times", "Liberation Serif", "Nimbus Roman", "Nimbus Roman L", "Tinos", "Thorndale", "TeX Gyre Termes", "FreeSerif", "Linux Libertine O", "Libertinus Serif", "PT Astra Serif", "DejaVu Serif", "Bitstream Vera Serif", "Ubuntu"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["Times-Bold", {
+ alias: "Times-Roman",
+ style: BOLD,
+ ultimate: "serif"
+}], ["Times-Italic", {
+ alias: "Times-Roman",
+ style: ITALIC,
+ ultimate: "serif"
+}], ["Times-BoldItalic", {
+ alias: "Times-Roman",
+ style: BOLDITALIC,
+ ultimate: "serif"
+}], ["Helvetica", {
+ local: ["Helvetica", "Helvetica Neue", "Arial", "Arial Nova", "Liberation Sans", "Arimo", "Nimbus Sans", "Nimbus Sans L", "A030", "TeX Gyre Heros", "FreeSans", "DejaVu Sans", "Albany", "Bitstream Vera Sans", "Arial Unicode MS", "Microsoft Sans Serif", "Apple Symbols", "Cantarell"],
+ path: "LiberationSans-Regular.ttf",
+ style: NORMAL,
+ ultimate: "sans-serif"
+}], ["Helvetica-Bold", {
+ alias: "Helvetica",
+ path: "LiberationSans-Bold.ttf",
+ style: BOLD,
+ ultimate: "sans-serif"
+}], ["Helvetica-Oblique", {
+ alias: "Helvetica",
+ path: "LiberationSans-Italic.ttf",
+ style: ITALIC,
+ ultimate: "sans-serif"
+}], ["Helvetica-BoldOblique", {
+ alias: "Helvetica",
+ path: "LiberationSans-BoldItalic.ttf",
+ style: BOLDITALIC,
+ ultimate: "sans-serif"
+}], ["Courier", {
+ local: ["Courier", "Courier New", "Liberation Mono", "Nimbus Mono", "Nimbus Mono L", "Cousine", "Cumberland", "TeX Gyre Cursor", "FreeMono", "Linux Libertine Mono O", "Libertinus Mono"],
+ style: NORMAL,
+ ultimate: "monospace"
+}], ["Courier-Bold", {
+ alias: "Courier",
+ style: BOLD,
+ ultimate: "monospace"
+}], ["Courier-Oblique", {
+ alias: "Courier",
+ style: ITALIC,
+ ultimate: "monospace"
+}], ["Courier-BoldOblique", {
+ alias: "Courier",
+ style: BOLDITALIC,
+ ultimate: "monospace"
+}], ["ArialBlack", {
+ local: ["Arial Black"],
+ style: {
+ style: "normal",
+ weight: "900"
+ },
+ fallback: "Helvetica-Bold"
+}], ["ArialBlack-Bold", {
+ alias: "ArialBlack"
+}], ["ArialBlack-Italic", {
+ alias: "ArialBlack",
+ style: {
+ style: "italic",
+ weight: "900"
+ },
+ fallback: "Helvetica-BoldOblique"
+}], ["ArialBlack-BoldItalic", {
+ alias: "ArialBlack-Italic"
+}], ["ArialNarrow", {
+ local: ["Arial Narrow", "Liberation Sans Narrow", "Helvetica Condensed", "Nimbus Sans Narrow", "TeX Gyre Heros Cn"],
+ style: NORMAL,
+ fallback: "Helvetica"
+}], ["ArialNarrow-Bold", {
+ alias: "ArialNarrow",
+ style: BOLD,
+ fallback: "Helvetica-Bold"
+}], ["ArialNarrow-Italic", {
+ alias: "ArialNarrow",
+ style: ITALIC,
+ fallback: "Helvetica-Oblique"
+}], ["ArialNarrow-BoldItalic", {
+ alias: "ArialNarrow",
+ style: BOLDITALIC,
+ fallback: "Helvetica-BoldOblique"
+}], ["Calibri", {
+ local: ["Calibri", "Carlito"],
+ style: NORMAL,
+ fallback: "Helvetica"
+}], ["Calibri-Bold", {
+ alias: "Calibri",
+ style: BOLD,
+ fallback: "Helvetica-Bold"
+}], ["Calibri-Italic", {
+ alias: "Calibri",
+ style: ITALIC,
+ fallback: "Helvetica-Oblique"
+}], ["Calibri-BoldItalic", {
+ alias: "Calibri",
+ style: BOLDITALIC,
+ fallback: "Helvetica-BoldOblique"
+}], ["Wingdings", {
+ local: ["Wingdings", "URW Dingbats"],
+ style: NORMAL
+}], ["Wingdings-Regular", {
+ alias: "Wingdings"
+}], ["Wingdings-Bold", {
+ alias: "Wingdings"
+}], ["\xCB\xCE\xCC\xE5", {
+ local: ["SimSun", "SimSun Regular", "NSimSun"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["\xBA\xDA\xCC\xE5", {
+ local: ["SimHei", "SimHei Regular"],
+ style: NORMAL,
+ ultimate: "sans-serif"
+}], ["\xBF\xAC\xCC\xE5", {
+ local: ["KaiTi", "SimKai", "SimKai Regular"],
+ style: NORMAL,
+ ultimate: "sans-serif"
+}], ["\xB7\xC2\xCB\xCE", {
+ local: ["FangSong", "SimFang", "SimFang Regular"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["\xBF\xAC\xCC\xE5_GB2312", {
+ alias: "\xBF\xAC\xCC\xE5"
+}], ["\xB7\xC2\xCB\xCE_GB2312", {
+ alias: "\xB7\xC2\xCB\xCE"
+}], ["\xC1\xA5\xCA\xE9", {
+ local: ["SimLi", "SimLi Regular"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["\xD0\xC2\xCB\xCE", {
+ alias: "\xCB\xCE\xCC\xE5"
+}], ["HeiseiMin-W3", {
+ local: ["Hiragino Mincho ProN", "Hiragino Mincho Pro", "Yu Mincho", "YuMincho", "Source Han Serif JP", "Noto Serif JP", "Noto Serif CJK JP", "IPAexMincho", "IPAMincho", "Takao Mincho", "MS Mincho", "MS PMincho"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["HeiseiKakuGo-W5", {
+ local: ["Hiragino Kaku Gothic ProN", "Hiragino Kaku Gothic Pro", "Hiragino Sans", "Yu Gothic", "YuGothic", "Source Han Sans JP", "Noto Sans JP", "Noto Sans CJK JP", "IPAexGothic", "IPAGothic", "Takao Gothic", "Meiryo", "MS Gothic", "MS PGothic"],
+ style: MEDIUM,
+ ultimate: "sans-serif"
+}], ["HeiseiMin-W3-Acro", {
+ alias: "HeiseiMin-W3"
+}], ["HeiseiKakuGo-W5-Acro", {
+ alias: "HeiseiKakuGo-W5"
+}], ["KozMinPro-Regular", {
+ alias: "HeiseiMin-W3"
+}], ["KozMinProVI-Regular", {
+ alias: "HeiseiMin-W3"
+}], ["KozMinPr6N-Regular", {
+ alias: "HeiseiMin-W3"
+}], ["KozGoPro-Regular", {
+ alias: "HeiseiKakuGo-W5"
+}], ["KozGoProVI-Regular", {
+ alias: "HeiseiKakuGo-W5"
+}], ["KozGoPr6N-Regular", {
+ alias: "HeiseiKakuGo-W5"
+}], ["STSong-Light", {
+ local: ["STSong", "Songti SC", "Source Han Serif SC", "Source Han Serif CN", "Noto Serif SC", "Noto Serif CJK SC", "AR PL UMing CN", "SimSun", "NSimSun"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["STHeiti-Regular", {
+ local: ["STHeiti", "Heiti SC", "PingFang SC", "Source Han Sans SC", "Source Han Sans CN", "Noto Sans SC", "Noto Sans CJK SC", "Microsoft YaHei", "SimHei", "WenQuanYi Zen Hei"],
+ style: NORMAL,
+ ultimate: "sans-serif"
+}], ["STSongStd-Light", {
+ alias: "STSong-Light"
+}], ["AdobeSongStd-Light", {
+ alias: "STSong-Light"
+}], ["AdobeHeitiStd-Regular", {
+ alias: "STHeiti-Regular"
+}], ["AdobeKaitiStd-Regular", {
+ alias: "\xBF\xAC\xCC\xE5"
+}], ["AdobeFangsongStd-Regular", {
+ alias: "\xB7\xC2\xCB\xCE"
+}], ["MSung-Light", {
+ local: ["Songti TC", "LiSong Pro", "Source Han Serif TC", "Source Han Serif TW", "Noto Serif TC", "Noto Serif CJK TC", "AR PL UMing TW", "PMingLiU", "MingLiU", "MingLiU_HKSCS"],
+ style: NORMAL,
+ ultimate: "serif"
+}], ["MHei-Medium", {
+ local: ["Heiti TC", "STHeiti", "Source Han Sans TC", "Source Han Sans TW", "Noto Sans TC", "Noto Sans CJK TC", "PingFang TC", "Microsoft JhengHei"],
+ style: MEDIUM,
+ ultimate: "sans-serif"
+}], ["MSungStd-Light", {
+ alias: "MSung-Light"
+}], ["AdobeMingStd-Light", {
+ alias: "MSung-Light"
+}], ["HYSMyeongJo-Medium", {
+ local: ["AppleMyungjo", "Source Han Serif KR", "Noto Serif KR", "Noto Serif CJK KR", "Nanum Myeongjo", "Batang"],
+ style: MEDIUM,
+ ultimate: "serif"
+}], ["HYGoThic-Medium", {
+ local: ["Apple SD Gothic Neo", "AppleGothic", "Source Han Sans KR", "Noto Sans KR", "Noto Sans CJK KR", "Nanum Gothic", "Malgun Gothic", "Dotum", "Gulim"],
+ style: MEDIUM,
+ ultimate: "sans-serif"
+}], ["HYSMyeongJoStd-Medium", {
+ alias: "HYSMyeongJo-Medium"
+}], ["AdobeMyungjoStd-Medium", {
+ alias: "HYSMyeongJo-Medium"
+}], ["HYGoThic-Bold", {
+ alias: "HYGoThic-Medium",
+ style: BOLD
+}], ["AdobeGothicStd-Bold", {
+ alias: "HYGoThic-Medium",
+ style: BOLD
+}]]);
+const fontAliases = new Map([["Arial-Black", "ArialBlack"]]);
+function getStyleToAppend(style) {
+ switch (style) {
+ case BOLD:
+ return "Bold";
+ case ITALIC:
+ return "Italic";
+ case BOLDITALIC:
+ return "Bold Italic";
+ default:
+ if (style?.weight === "bold") {
+ return "Bold";
+ }
+ if (style?.style === "italic") {
+ return "Italic";
+ }
+ }
+ return "";
+}
+function getFamilyName(str) {
+ const keywords = new Set(["thin", "extralight", "ultralight", "demilight", "semilight", "light", "book", "regular", "normal", "medium", "demibold", "semibold", "bold", "extrabold", "ultrabold", "black", "heavy", "extrablack", "ultrablack", "roman", "italic", "oblique", "ultracondensed", "extracondensed", "condensed", "semicondensed", "normal", "semiexpanded", "expanded", "extraexpanded", "ultraexpanded", "bolditalic"]);
+ return str.split(/[- ,+]+/g).filter(tok => !keywords.has(tok.toLowerCase())).join(" ");
+}
+function generateFont({
+ alias,
+ local,
+ path,
+ fallback,
+ style,
+ ultimate
+}, src, localFontPath, useFallback = true, usePath = true, append = "") {
+ const result = {
+ style: null,
+ ultimate: null
+ };
+ if (local) {
+ const extra = append ? ` ${append}` : "";
+ for (const name of local) {
+ src.push(`local(${name}${extra})`);
+ }
+ }
+ if (alias) {
+ const substitution = substitutionMap.get(alias);
+ const aliasAppend = append || getStyleToAppend(style);
+ Object.assign(result, generateFont(substitution, src, localFontPath, useFallback && !fallback, usePath && !path, aliasAppend));
+ }
+ if (style) {
+ result.style = style;
+ }
+ if (ultimate) {
+ result.ultimate = ultimate;
+ }
+ if (useFallback && fallback) {
+ const fallbackInfo = substitutionMap.get(fallback);
+ const {
+ ultimate: fallbackUltimate
+ } = generateFont(fallbackInfo, src, localFontPath, useFallback, usePath && !path, append);
+ result.ultimate ||= fallbackUltimate;
+ }
+ if (usePath && path && localFontPath) {
+ src.push(`url(${localFontPath}${path})`);
+ }
+ return result;
+}
+function getFontSubstitution(systemFontCache, idFactory, localFontPath, baseFontName, standardFontName, type) {
+ if (baseFontName.startsWith("InvalidPDFjsFont_")) {
+ return null;
+ }
+ if ((type === "TrueType" || type === "Type1") && /^[A-Z]{6}\+/.test(baseFontName)) {
+ baseFontName = baseFontName.slice(7);
+ }
+ baseFontName = normalizeFontName(baseFontName);
+ const key = baseFontName;
+ let substitutionInfo = systemFontCache.get(key);
+ if (substitutionInfo) {
+ return substitutionInfo;
+ }
+ let substitution = substitutionMap.get(baseFontName);
+ if (!substitution) {
+ for (const [alias, subst] of fontAliases) {
+ if (baseFontName.startsWith(alias)) {
+ baseFontName = `${subst}${baseFontName.substring(alias.length)}`;
+ substitution = substitutionMap.get(baseFontName);
+ break;
+ }
+ }
+ }
+ let mustAddBaseFont = false;
+ if (!substitution) {
+ substitution = substitutionMap.get(standardFontName);
+ mustAddBaseFont = true;
+ }
+ const loadedName = `${idFactory.getDocId()}_s${idFactory.createFontId()}`;
+ if (!substitution) {
+ if (!validateFontName(baseFontName)) {
+ warn(`Cannot substitute the font because of its name: ${baseFontName}`);
+ systemFontCache.set(key, null);
+ return null;
+ }
+ const bold = /bold/i.test(baseFontName);
+ const italic = /oblique|italic/i.test(baseFontName);
+ const style = bold && italic && BOLDITALIC || bold && BOLD || italic && ITALIC || NORMAL;
+ substitutionInfo = {
+ css: `"${getFamilyName(baseFontName)}",${loadedName}`,
+ guessFallback: true,
+ loadedName,
+ baseFontName,
+ src: `local(${baseFontName})`,
+ style
+ };
+ systemFontCache.set(key, substitutionInfo);
+ return substitutionInfo;
+ }
+ const src = [];
+ if (mustAddBaseFont && validateFontName(baseFontName)) {
+ src.push(`local(${baseFontName})`);
+ }
+ const {
+ style,
+ ultimate
+ } = generateFont(substitution, src, localFontPath);
+ const guessFallback = ultimate === null;
+ const fallback = guessFallback ? "" : `,${ultimate}`;
+ substitutionInfo = {
+ css: `"${getFamilyName(baseFontName)}",${loadedName}${fallback}`,
+ guessFallback,
+ loadedName,
+ baseFontName,
+ src: src.join(","),
+ style
+ };
+ systemFontCache.set(key, substitutionInfo);
+ return substitutionInfo;
+}
+
+;// ./src/shared/murmurhash3.js
+
+
+
+
+
+const SEED = 0xc3d2e1f0;
+const MASK_HIGH = 0xffff0000;
+const MASK_LOW = 0xffff;
+class MurmurHash3_64 {
+ constructor(seed) {
+ this.h1 = seed ? seed & 0xffffffff : SEED;
+ this.h2 = seed ? seed & 0xffffffff : SEED;
+ }
+ update(input) {
+ let data, length;
+ if (typeof input === "string") {
+ data = new Uint8Array(input.length * 2);
+ length = 0;
+ for (let i = 0, ii = input.length; i < ii; i++) {
+ const code = input.charCodeAt(i);
+ if (code <= 0xff) {
+ data[length++] = code;
+ } else {
+ data[length++] = code >>> 8;
+ data[length++] = code & 0xff;
+ }
+ }
+ } else if (ArrayBuffer.isView(input)) {
+ data = input.slice();
+ length = data.byteLength;
+ } else {
+ throw new Error("Invalid data format, must be a string or TypedArray.");
+ }
+ const blockCounts = length >> 2;
+ const tailLength = length - blockCounts * 4;
+ const dataUint32 = new Uint32Array(data.buffer, 0, blockCounts);
+ let k1 = 0,
+ k2 = 0;
+ let h1 = this.h1,
+ h2 = this.h2;
+ const C1 = 0xcc9e2d51,
+ C2 = 0x1b873593;
+ const C1_LOW = C1 & MASK_LOW,
+ C2_LOW = C2 & MASK_LOW;
+ for (let i = 0; i < blockCounts; i++) {
+ if (i & 1) {
+ k1 = dataUint32[i];
+ k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
+ k1 = k1 << 15 | k1 >>> 17;
+ k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
+ h1 ^= k1;
+ h1 = h1 << 13 | h1 >>> 19;
+ h1 = h1 * 5 + 0xe6546b64;
+ } else {
+ k2 = dataUint32[i];
+ k2 = k2 * C1 & MASK_HIGH | k2 * C1_LOW & MASK_LOW;
+ k2 = k2 << 15 | k2 >>> 17;
+ k2 = k2 * C2 & MASK_HIGH | k2 * C2_LOW & MASK_LOW;
+ h2 ^= k2;
+ h2 = h2 << 13 | h2 >>> 19;
+ h2 = h2 * 5 + 0xe6546b64;
+ }
+ }
+ k1 = 0;
+ switch (tailLength) {
+ case 3:
+ k1 ^= data[blockCounts * 4 + 2] << 16;
+ case 2:
+ k1 ^= data[blockCounts * 4 + 1] << 8;
+ case 1:
+ k1 ^= data[blockCounts * 4];
+ k1 = k1 * C1 & MASK_HIGH | k1 * C1_LOW & MASK_LOW;
+ k1 = k1 << 15 | k1 >>> 17;
+ k1 = k1 * C2 & MASK_HIGH | k1 * C2_LOW & MASK_LOW;
+ if (blockCounts & 1) {
+ h1 ^= k1;
+ } else {
+ h2 ^= k1;
+ }
+ }
+ this.h1 = h1;
+ this.h2 = h2;
+ }
+ hexdigest() {
+ let h1 = this.h1,
+ h2 = this.h2;
+ h1 ^= h2 >>> 1;
+ h1 = h1 * 0xed558ccd & MASK_HIGH | h1 * 0x8ccd & MASK_LOW;
+ h2 = h2 * 0xff51afd7 & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16;
+ h1 ^= h2 >>> 1;
+ h1 = h1 * 0x1a85ec53 & MASK_HIGH | h1 * 0xec53 & MASK_LOW;
+ h2 = h2 * 0xc4ceb9fe & MASK_HIGH | ((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16;
+ h1 ^= h2 >>> 1;
+ return (h1 >>> 0).toString(16).padStart(8, "0") + (h2 >>> 0).toString(16).padStart(8, "0");
+ }
+}
+
+;// ./src/core/image.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class PDFImage {
+ constructor({
+ xref,
+ res,
+ image,
+ isInline = false,
+ smask = null,
+ mask = null,
+ isMask = false,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ }) {
+ this.image = image;
+ const dict = image.dict;
+ const filter = dict.get("F", "Filter");
+ let filterName;
+ if (filter instanceof Name) {
+ filterName = filter.name;
+ } else if (Array.isArray(filter)) {
+ const filterZero = xref.fetchIfRef(filter[0]);
+ if (filterZero instanceof Name) {
+ filterName = filterZero.name;
+ }
+ }
+ switch (filterName) {
+ case "JPXDecode":
+ ({
+ width: image.width,
+ height: image.height,
+ componentsCount: image.numComps,
+ bitsPerComponent: image.bitsPerComponent
+ } = JpxImage.parseImageProperties(image.stream));
+ image.stream.reset();
+ const reducePower = ImageResizer.getReducePowerForJPX(image.width, image.height, image.numComps);
+ this.jpxDecoderOptions = {
+ numComponents: 0,
+ isIndexedColormap: false,
+ smaskInData: dict.get("SMaskInData") >= 1,
+ reducePower
+ };
+ if (reducePower) {
+ const factor = 2 ** reducePower;
+ image.width = Math.ceil(image.width / factor);
+ image.height = Math.ceil(image.height / factor);
+ }
+ break;
+ case "JBIG2Decode":
+ image.bitsPerComponent = 1;
+ image.numComps = 1;
+ break;
+ }
+ let width = dict.get("W", "Width");
+ let height = dict.get("H", "Height");
+ if (Number.isInteger(image.width) && image.width > 0 && Number.isInteger(image.height) && image.height > 0 && (image.width !== width || image.height !== height)) {
+ warn("PDFImage - using the Width/Height of the image data, " + "rather than the image dictionary.");
+ width = image.width;
+ height = image.height;
+ } else {
+ const validWidth = typeof width === "number" && width > 0,
+ validHeight = typeof height === "number" && height > 0;
+ if (!validWidth || !validHeight) {
+ if (!image.fallbackDims) {
+ throw new FormatError(`Invalid image width: ${width} or height: ${height}`);
+ }
+ warn("PDFImage - using the Width/Height of the parent image, for SMask/Mask data.");
+ if (!validWidth) {
+ width = image.fallbackDims.width;
+ }
+ if (!validHeight) {
+ height = image.fallbackDims.height;
+ }
+ }
+ }
+ this.width = width;
+ this.height = height;
+ this.interpolate = dict.get("I", "Interpolate");
+ this.imageMask = dict.get("IM", "ImageMask") || false;
+ this.matte = dict.get("Matte") || false;
+ let bitsPerComponent = image.bitsPerComponent;
+ if (!bitsPerComponent) {
+ bitsPerComponent = dict.get("BPC", "BitsPerComponent");
+ if (!bitsPerComponent) {
+ if (this.imageMask) {
+ bitsPerComponent = 1;
+ } else {
+ throw new FormatError(`Bits per component missing in image: ${this.imageMask}`);
+ }
+ }
+ }
+ this.bpc = bitsPerComponent;
+ if (!this.imageMask) {
+ let colorSpace = dict.getRaw("CS") || dict.getRaw("ColorSpace");
+ const hasColorSpace = !!colorSpace;
+ if (this.jpxDecoderOptions?.smaskInData && dict.get("SMaskInData") === 2) {
+ this.jpxPremultiplied = true;
+ if (this.matte) {
+ const matteColorSpace = ColorSpaceUtils.parse({
+ cs: hasColorSpace ? colorSpace : Name.get("DeviceRGB"),
+ xref,
+ resources: isInline ? res : null,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ });
+ this.preblendMatte = matteColorSpace.getRgb(this.matte, 0);
+ }
+ }
+ if (!hasColorSpace) {
+ if (this.jpxDecoderOptions) {
+ colorSpace = Name.get("DeviceRGBA");
+ } else {
+ switch (image.numComps) {
+ case 1:
+ colorSpace = Name.get("DeviceGray");
+ break;
+ case 3:
+ colorSpace = Name.get("DeviceRGB");
+ break;
+ case 4:
+ colorSpace = Name.get("DeviceCMYK");
+ break;
+ default:
+ throw new Error(`Images with ${image.numComps} color components not supported.`);
+ }
+ }
+ } else if (this.jpxDecoderOptions?.smaskInData) {
+ colorSpace = Name.get("DeviceRGBA");
+ }
+ this.colorSpace = ColorSpaceUtils.parse({
+ cs: colorSpace,
+ xref,
+ resources: isInline ? res : null,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ });
+ this.numComps = this.colorSpace.numComps;
+ if (this.jpxDecoderOptions) {
+ this.jpxDecoderOptions.numComponents = hasColorSpace ? this.numComps : 0;
+ this.jpxDecoderOptions.isIndexedColormap = this.colorSpace.name === "Indexed";
+ }
+ } else {
+ this.numComps = 1;
+ }
+ this.decode = dict.getArray("D", "Decode");
+ this.needsDecode = false;
+ if (this.decode && (this.colorSpace && !this.colorSpace.isDefaultDecode(this.decode, bitsPerComponent) || isMask && !ColorSpace.isDefaultDecode(this.decode, 1))) {
+ this.needsDecode = true;
+ const max = (1 << bitsPerComponent) - 1;
+ this.decodeCoefficients = [];
+ this.decodeAddends = [];
+ const isIndexed = this.colorSpace?.name === "Indexed";
+ for (let i = 0, j = 0; i < this.decode.length; i += 2, ++j) {
+ const dmin = this.decode[i];
+ const dmax = this.decode[i + 1];
+ this.decodeCoefficients[j] = isIndexed ? (dmax - dmin) / max : dmax - dmin;
+ this.decodeAddends[j] = isIndexed ? dmin : max * dmin;
+ }
+ }
+ if (smask) {
+ smask.fallbackDims ??= {
+ width,
+ height
+ };
+ this.smask = new PDFImage({
+ xref,
+ res,
+ image: smask,
+ isInline,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ });
+ } else if (mask) {
+ if (mask instanceof BaseStream) {
+ const maskDict = mask.dict,
+ imageMask = maskDict.get("IM", "ImageMask");
+ if (!imageMask) {
+ warn("Ignoring /Mask in image without /ImageMask.");
+ } else {
+ mask.fallbackDims ??= {
+ width,
+ height
+ };
+ this.mask = new PDFImage({
+ xref,
+ res,
+ image: mask,
+ isInline,
+ isMask: true,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ });
+ }
+ } else {
+ this.mask = mask;
+ }
+ }
+ }
+ static async buildImage({
+ xref,
+ res,
+ image,
+ isInline = false,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ }) {
+ const imageData = image;
+ let smaskData = null;
+ let maskData = null;
+ const smask = image.dict.get("SMask");
+ const mask = image.dict.get("Mask");
+ if (smask) {
+ if (smask instanceof BaseStream) {
+ smaskData = smask;
+ } else {
+ warn("Unsupported /SMask format.");
+ }
+ } else if (mask) {
+ if (mask instanceof BaseStream || Array.isArray(mask)) {
+ maskData = mask;
+ } else {
+ warn("Unsupported /Mask format.");
+ }
+ }
+ return new PDFImage({
+ xref,
+ res,
+ image: imageData,
+ isInline,
+ smask: smaskData,
+ mask: maskData,
+ pdfFunctionFactory,
+ globalColorSpaceCache,
+ localColorSpaceCache
+ });
+ }
+ static async createMask({
+ image,
+ isOffscreenCanvasSupported = false
+ }) {
+ const {
+ dict
+ } = image;
+ const width = dict.get("W", "Width");
+ const height = dict.get("H", "Height");
+ const interpolate = dict.get("I", "Interpolate");
+ const decode = dict.getArray("D", "Decode");
+ const inverseDecode = decode?.[0] > 0;
+ const computedLength = (width + 7 >> 3) * height;
+ const imgArray = await image.getImageData(computedLength);
+ const isSingleOpaquePixel = width === 1 && height === 1 && inverseDecode === (imgArray.length === 0 || !!(imgArray[0] & 128));
+ if (isSingleOpaquePixel) {
+ return {
+ isSingleOpaquePixel
+ };
+ }
+ if (isOffscreenCanvasSupported) {
+ if (ImageResizer.needsToBeResized(width, height)) {
+ const data = new Uint8ClampedArray(width * height * 4);
+ convertBlackAndWhiteToRGBA({
+ src: imgArray,
+ dest: data,
+ width,
+ height,
+ nonBlackColor: 0,
+ inverseDecode
+ });
+ return ImageResizer.createImage({
+ kind: ImageKind.RGBA_32BPP,
+ data,
+ width,
+ height,
+ interpolate
+ });
+ }
+ const canvas = new OffscreenCanvas(width, height);
+ const ctx = canvas.getContext("2d");
+ const imgData = ctx.createImageData(width, height);
+ convertBlackAndWhiteToRGBA({
+ src: imgArray,
+ dest: imgData.data,
+ width,
+ height,
+ nonBlackColor: 0,
+ inverseDecode
+ });
+ ctx.putImageData(imgData, 0, 0);
+ const bitmap = canvas.transferToImageBitmap();
+ return {
+ data: null,
+ width,
+ height,
+ interpolate,
+ bitmap
+ };
+ }
+ const actualLength = imgArray.byteLength;
+ const haveFullData = computedLength === actualLength;
+ let data;
+ if (image instanceof DecodeStream && (!inverseDecode || haveFullData)) {
+ data = imgArray;
+ } else if (!inverseDecode) {
+ data = new Uint8Array(imgArray);
+ } else {
+ data = new Uint8Array(computedLength);
+ data.set(imgArray);
+ data.fill(0xff, actualLength);
+ }
+ if (inverseDecode) {
+ for (let i = 0; i < actualLength; i++) {
+ data[i] ^= 0xff;
+ }
+ }
+ return {
+ data,
+ width,
+ height,
+ interpolate
+ };
+ }
+ get drawWidth() {
+ return Math.max(this.width, this.smask?.width || 0, this.mask?.width || 0);
+ }
+ get drawHeight() {
+ return Math.max(this.height, this.smask?.height || 0, this.mask?.height || 0);
+ }
+ decodeBuffer(buffer) {
+ const bpc = this.bpc;
+ const numComps = this.numComps;
+ const decodeAddends = this.decodeAddends;
+ const decodeCoefficients = this.decodeCoefficients;
+ const max = (1 << bpc) - 1;
+ let i, ii;
+ if (bpc === 1) {
+ for (i = 0, ii = buffer.length; i < ii; i++) {
+ buffer[i] = +!buffer[i];
+ }
+ return;
+ }
+ let index = 0;
+ for (i = 0, ii = this.width * this.height; i < ii; i++) {
+ for (let j = 0; j < numComps; j++) {
+ buffer[index] = MathClamp(decodeAddends[j] + buffer[index] * decodeCoefficients[j], 0, max);
+ index++;
+ }
+ }
+ }
+ getComponents(buffer) {
+ const bpc = this.bpc;
+ if (bpc === 8) {
+ return buffer;
+ }
+ const width = this.width;
+ const height = this.height;
+ const numComps = this.numComps;
+ const length = width * height * numComps;
+ let bufferPos = 0;
+ let output;
+ if (bpc <= 8) {
+ output = new Uint8Array(length);
+ } else if (bpc <= 16) {
+ output = new Uint16Array(length);
+ } else {
+ output = new Uint32Array(length);
+ }
+ const rowComps = width * numComps;
+ const max = (1 << bpc) - 1;
+ let i = 0,
+ ii,
+ buf;
+ if (bpc === 1) {
+ let mask, loop1End, loop2End;
+ for (let j = 0; j < height; j++) {
+ loop1End = i + (rowComps & ~7);
+ loop2End = i + rowComps;
+ while (i < loop1End) {
+ buf = buffer[bufferPos++];
+ output[i] = buf >> 7 & 1;
+ output[i + 1] = buf >> 6 & 1;
+ output[i + 2] = buf >> 5 & 1;
+ output[i + 3] = buf >> 4 & 1;
+ output[i + 4] = buf >> 3 & 1;
+ output[i + 5] = buf >> 2 & 1;
+ output[i + 6] = buf >> 1 & 1;
+ output[i + 7] = buf & 1;
+ i += 8;
+ }
+ if (i < loop2End) {
+ buf = buffer[bufferPos++];
+ mask = 128;
+ while (i < loop2End) {
+ output[i++] = +!!(buf & mask);
+ mask >>= 1;
+ }
+ }
+ }
+ } else {
+ let bits = 0;
+ buf = 0;
+ for (i = 0, ii = length; i < ii; ++i) {
+ if (i % rowComps === 0) {
+ buf = 0;
+ bits = 0;
+ }
+ while (bits < bpc) {
+ buf = buf << 8 | buffer[bufferPos++];
+ bits += 8;
+ }
+ const remainingBits = bits - bpc;
+ output[i] = MathClamp(buf >> remainingBits, 0, max);
+ buf &= (1 << remainingBits) - 1;
+ bits = remainingBits;
+ }
+ }
+ return output;
+ }
+ async fillOpacity(rgbaBuf, width, height, actualHeight, image) {
+ let apply;
+ if (this.smask) {
+ apply = (buffer, options) => this.smask.fillGrayBuffer(buffer, {
+ ...options,
+ destWidth: width,
+ destHeight: height
+ });
+ } else if (this.mask) {
+ if (this.mask instanceof PDFImage) {
+ apply = (buffer, options) => this.mask.fillGrayBuffer(buffer, {
+ ...options,
+ invertOutput: true,
+ destWidth: width,
+ destHeight: height
+ });
+ } else if (Array.isArray(this.mask)) {
+ apply = (buffer, {
+ maxRows,
+ offset,
+ stride
+ }) => {
+ for (let i = 0, ii = width * maxRows; i < ii; ++i) {
+ let opacity = 0;
+ const imageOffset = i * this.numComps;
+ for (let j = 0; j < this.numComps; ++j) {
+ const color = image[imageOffset + j];
+ const maskOffset = j * 2;
+ if (color < this.mask[maskOffset] || color > this.mask[maskOffset + 1]) {
+ opacity = 255;
+ break;
+ }
+ }
+ buffer[i * stride + offset] = opacity;
+ }
+ };
+ } else {
+ throw new FormatError("Unknown mask format.");
+ }
+ } else {
+ apply = (buffer, {
+ maxRows,
+ offset,
+ stride
+ }) => {
+ for (let i = 0, ii = width * maxRows; i < ii; ++i) {
+ buffer[i * stride + offset] = 255;
+ }
+ };
+ }
+ await apply(rgbaBuf, {
+ maxRows: actualHeight,
+ offset: 3,
+ stride: 4
+ });
+ }
+ static #undoPreblend(buffer, length, matteR, matteG, matteB) {
+ for (let i = 0; i < length; i += 4) {
+ const alpha = buffer[i + 3];
+ if (alpha === 0) {
+ buffer[i] = 255;
+ buffer[i + 1] = 255;
+ buffer[i + 2] = 255;
+ continue;
+ }
+ const k = 255 / alpha;
+ buffer[i] = (buffer[i] - matteR) * k + matteR;
+ buffer[i + 1] = (buffer[i + 1] - matteG) * k + matteG;
+ buffer[i + 2] = (buffer[i + 2] - matteB) * k + matteB;
+ }
+ }
+ undoPreblend(buffer, width, height) {
+ const matte = this.smask?.matte;
+ if (!matte) {
+ return;
+ }
+ const matteRgb = this.colorSpace.getRgb(matte, 0);
+ PDFImage.#undoPreblend(buffer, width * height * 4, matteRgb[0], matteRgb[1], matteRgb[2]);
+ }
+ async createImageData(forceRGBA = false, isOffscreenCanvasSupported = false) {
+ const drawWidth = this.drawWidth;
+ const drawHeight = this.drawHeight;
+ const imgData = {
+ width: drawWidth,
+ height: drawHeight,
+ interpolate: this.interpolate,
+ kind: 0,
+ data: null
+ };
+ const numComps = this.numComps;
+ const originalWidth = this.width;
+ const originalHeight = this.height;
+ const bpc = this.bpc;
+ const rowBytes = originalWidth * numComps * bpc + 7 >> 3;
+ const mustBeResized = isOffscreenCanvasSupported && ImageResizer.needsToBeResized(drawWidth, drawHeight);
+ if (!this.smask && !this.mask && this.colorSpace.name === "DeviceRGBA") {
+ imgData.kind = ImageKind.RGBA_32BPP;
+ const imgArray = imgData.data = await this.getImageBytes(originalHeight * originalWidth * 4, {
+ internal: isOffscreenCanvasSupported && mustBeResized
+ });
+ if (this.jpxPremultiplied) {
+ const matteRgb = this.preblendMatte;
+ PDFImage.#undoPreblend(imgArray, imgArray.length, matteRgb?.[0] ?? 0, matteRgb?.[1] ?? 0, matteRgb?.[2] ?? 0);
+ }
+ if (isOffscreenCanvasSupported) {
+ if (!mustBeResized) {
+ return this.createBitmap(ImageKind.RGBA_32BPP, drawWidth, drawHeight, imgArray);
+ }
+ return ImageResizer.createImage(imgData, false);
+ }
+ return imgData;
+ }
+ if (!forceRGBA && !this.smask && !this.mask) {
+ let kind;
+ if (this.colorSpace.name === "DeviceGray" && bpc === 1) {
+ kind = ImageKind.GRAYSCALE_1BPP;
+ } else if (this.colorSpace.name === "DeviceRGB" && bpc === 8 && !this.needsDecode) {
+ kind = ImageKind.RGB_24BPP;
+ }
+ if (kind && drawWidth === originalWidth && drawHeight === originalHeight) {
+ const image = await this.#getImage(originalWidth, originalHeight);
+ if (image) {
+ return image;
+ }
+ const data = await this.getImageBytes(originalHeight * rowBytes, {
+ internal: isOffscreenCanvasSupported && mustBeResized
+ });
+ if (isOffscreenCanvasSupported) {
+ if (mustBeResized) {
+ return ImageResizer.createImage({
+ data,
+ kind,
+ width: drawWidth,
+ height: drawHeight,
+ interpolate: this.interpolate
+ }, this.needsDecode);
+ }
+ return this.createBitmap(kind, originalWidth, originalHeight, data);
+ }
+ imgData.kind = kind;
+ imgData.data = data;
+ if (this.needsDecode) {
+ assert(kind === ImageKind.GRAYSCALE_1BPP, "PDFImage.createImageData: The image must be grayscale.");
+ const buffer = imgData.data;
+ for (let i = 0, ii = buffer.length; i < ii; i++) {
+ buffer[i] ^= 0xff;
+ }
+ }
+ return imgData;
+ }
+ if (this.image instanceof JpegStream && !this.needsDecode) {
+ let isHandled = false;
+ switch (this.colorSpace.name) {
+ case "DeviceGray":
+ case "DeviceRGB":
+ case "DeviceCMYK":
+ isHandled = true;
+ break;
+ }
+ if (isHandled) {
+ if (isOffscreenCanvasSupported) {
+ const image = await this.#getImage(drawWidth, drawHeight);
+ if (image) {
+ return image;
+ }
+ }
+ let imageLength = originalHeight * rowBytes;
+ if (isOffscreenCanvasSupported && !mustBeResized) {
+ switch (this.colorSpace.name) {
+ case "DeviceGray":
+ imageLength *= 4;
+ break;
+ case "DeviceRGB":
+ imageLength = imageLength / 3 * 4;
+ break;
+ }
+ const rgba = await this.getImageBytes(imageLength, {
+ drawWidth,
+ drawHeight,
+ forceRGBA: true,
+ internal: true
+ });
+ return this.createBitmap(ImageKind.RGBA_32BPP, drawWidth, drawHeight, rgba);
+ }
+ if (this.colorSpace.name === "DeviceGray") {
+ imageLength *= 3;
+ }
+ imgData.kind = ImageKind.RGB_24BPP;
+ imgData.data = await this.getImageBytes(imageLength, {
+ drawWidth,
+ drawHeight,
+ forceRGB: true,
+ internal: mustBeResized
+ });
+ if (mustBeResized) {
+ return ImageResizer.createImage(imgData);
+ }
+ return imgData;
+ }
+ }
+ }
+ const imgArray = await this.getImageBytes(originalHeight * rowBytes, {
+ internal: true
+ });
+ const actualHeight = 0 | imgArray.length / rowBytes * drawHeight / originalHeight;
+ const comps = this.getComponents(imgArray);
+ let alpha01, maybeUndoPreblend;
+ let canvas, ctx, canvasImgData, data;
+ if (isOffscreenCanvasSupported && !mustBeResized) {
+ canvas = new OffscreenCanvas(drawWidth, drawHeight);
+ ctx = canvas.getContext("2d");
+ canvasImgData = ctx.createImageData(drawWidth, drawHeight);
+ data = canvasImgData.data;
+ }
+ imgData.kind = ImageKind.RGBA_32BPP;
+ if (!forceRGBA && !this.smask && !this.mask) {
+ if (!isOffscreenCanvasSupported || mustBeResized) {
+ imgData.kind = ImageKind.RGB_24BPP;
+ data = new Uint8ClampedArray(drawWidth * drawHeight * 3);
+ alpha01 = 0;
+ } else {
+ const arr = new Uint32Array(data.buffer);
+ arr.fill(FeatureTest.isLittleEndian ? 0xff000000 : 0x000000ff);
+ alpha01 = 1;
+ }
+ maybeUndoPreblend = false;
+ } else {
+ if (!isOffscreenCanvasSupported || mustBeResized) {
+ data = new Uint8ClampedArray(drawWidth * drawHeight * 4);
+ }
+ alpha01 = 1;
+ maybeUndoPreblend = true;
+ await this.fillOpacity(data, drawWidth, drawHeight, actualHeight, comps);
+ }
+ if (this.needsDecode) {
+ this.decodeBuffer(comps);
+ }
+ this.colorSpace.fillRgb(data, originalWidth, originalHeight, drawWidth, drawHeight, actualHeight, bpc, comps, alpha01);
+ if (maybeUndoPreblend) {
+ this.undoPreblend(data, drawWidth, actualHeight);
+ }
+ if (isOffscreenCanvasSupported && !mustBeResized) {
+ ctx.putImageData(canvasImgData, 0, 0);
+ const bitmap = canvas.transferToImageBitmap();
+ return {
+ data: null,
+ width: drawWidth,
+ height: drawHeight,
+ bitmap,
+ interpolate: this.interpolate
+ };
+ }
+ imgData.data = data;
+ if (mustBeResized) {
+ return ImageResizer.createImage(imgData);
+ }
+ return imgData;
+ }
+ async fillGrayBuffer(buffer, {
+ destWidth,
+ destHeight,
+ invertOutput,
+ maxRows,
+ offset = 0,
+ stride = 1
+ } = {}) {
+ const numComps = this.numComps;
+ if (numComps !== 1) {
+ throw new FormatError(`Reading gray scale from a color image: ${numComps}`);
+ }
+ const srcWidth = this.width;
+ const srcHeight = this.height;
+ const bpc = this.bpc;
+ const rowBytes = srcWidth * numComps * bpc + 7 >> 3;
+ const imgArray = await this.getImageBytes(srcHeight * rowBytes, {
+ internal: true
+ });
+ const comps = this.getComponents(imgArray);
+ const resolvedDestWidth = destWidth ?? srcWidth;
+ const resolvedDestHeight = destHeight ?? srcHeight;
+ const needsResampling = resolvedDestWidth !== srcWidth || resolvedDestHeight !== srcHeight;
+ const rows = maxRows === undefined ? resolvedDestHeight : Math.min(resolvedDestHeight, maxRows);
+ let outputWidth = srcWidth;
+ let yRatio = 0;
+ let xScaled = null;
+ if (needsResampling) {
+ outputWidth = resolvedDestWidth;
+ yRatio = srcHeight / resolvedDestHeight;
+ const xRatio = srcWidth / resolvedDestWidth;
+ xScaled = new Uint32Array(resolvedDestWidth);
+ for (let i = 0; i < resolvedDestWidth; i++) {
+ xScaled[i] = Math.floor(i * xRatio);
+ }
+ }
+ const mask = invertOutput ? 0xff : 0;
+ if (bpc === 1) {
+ if (xScaled) {
+ const xMap = xScaled;
+ let destIndex = offset;
+ if (this.needsDecode) {
+ for (let row = 0; row < rows; row++) {
+ const py = Math.floor(row * yRatio) * srcWidth;
+ for (let col = 0; col < outputWidth; col++) {
+ buffer[destIndex] = comps[py + xMap[col]] - 1 & 255 ^ mask;
+ destIndex += stride;
+ }
+ }
+ } else {
+ for (let row = 0; row < rows; row++) {
+ const py = Math.floor(row * yRatio) * srcWidth;
+ for (let col = 0; col < outputWidth; col++) {
+ buffer[destIndex] = -comps[py + xMap[col]] & 255 ^ mask;
+ destIndex += stride;
+ }
+ }
+ }
+ } else {
+ const length = outputWidth * rows;
+ if (this.needsDecode) {
+ for (let i = 0; i < length; ++i) {
+ buffer[i * stride + offset] = comps[i] - 1 & 255 ^ mask;
+ }
+ } else {
+ for (let i = 0; i < length; ++i) {
+ buffer[i * stride + offset] = -comps[i] & 255 ^ mask;
+ }
+ }
+ }
+ return;
+ }
+ if (this.needsDecode) {
+ this.decodeBuffer(comps);
+ }
+ const scale = 255 / ((1 << bpc) - 1);
+ if (xScaled) {
+ const xMap = xScaled;
+ let destIndex = offset;
+ for (let row = 0; row < rows; row++) {
+ const py = Math.floor(row * yRatio) * srcWidth;
+ for (let col = 0; col < outputWidth; col++) {
+ buffer[destIndex] = scale * comps[py + xMap[col]] ^ mask;
+ destIndex += stride;
+ }
+ }
+ } else {
+ const length = outputWidth * rows;
+ for (let i = 0; i < length; ++i) {
+ buffer[i * stride + offset] = scale * comps[i] ^ mask;
+ }
+ }
+ }
+ createBitmap(kind, width, height, src) {
+ const canvas = new OffscreenCanvas(width, height);
+ const ctx = canvas.getContext("2d");
+ let imgData;
+ if (kind === ImageKind.RGBA_32BPP) {
+ imgData = new ImageData(src, width, height);
+ } else {
+ imgData = ctx.createImageData(width, height);
+ convertToRGBA({
+ kind,
+ src,
+ dest: new Uint32Array(imgData.data.buffer),
+ width,
+ height,
+ inverseDecode: this.needsDecode
+ });
+ }
+ ctx.putImageData(imgData, 0, 0);
+ const bitmap = canvas.transferToImageBitmap();
+ return {
+ data: null,
+ width,
+ height,
+ bitmap,
+ interpolate: this.interpolate
+ };
+ }
+ async #getImage(width, height) {
+ const bitmap = await this.image.getTransferableImage(width, height);
+ if (!bitmap) {
+ return null;
+ }
+ return {
+ data: null,
+ width: bitmap.displayWidth ?? width,
+ height: bitmap.displayHeight ?? height,
+ bitmap,
+ interpolate: this.interpolate
+ };
+ }
+ async getImageBytes(length, {
+ drawWidth,
+ drawHeight,
+ forceRGBA = false,
+ forceRGB = false,
+ internal = false
+ }) {
+ this.image.reset();
+ this.image.drawWidth = drawWidth || this.width;
+ this.image.drawHeight = drawHeight || this.height;
+ this.image.forceRGBA = !!forceRGBA;
+ this.image.forceRGB = !!forceRGB;
+ const imageBytes = await this.image.getImageData(length, this.jpxDecoderOptions);
+ if (internal || this.image instanceof DecodeStream) {
+ return imageBytes;
+ }
+ assert(imageBytes instanceof Uint8Array, 'PDFImage.getImageBytes: Unsupported "imageBytes" type.');
+ return new Uint8Array(imageBytes);
+ }
+}
+
+;// ./src/core/evaluator.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const DefaultPartialEvaluatorOptions = Object.freeze({
+ maxImageSize: -1,
+ disableFontFace: false,
+ ignoreErrors: false,
+ isOffscreenCanvasSupported: false,
+ isImageDecoderSupported: false,
+ canvasMaxAreaInBytes: -1,
+ fontExtraProperties: false,
+ useSystemFonts: true,
+ useWasm: true,
+ useWorkerFetch: true,
+ cMapUrl: null,
+ cMapPacked: true,
+ iccUrl: null,
+ standardFontDataUrl: null,
+ wasmUrl: null,
+ hasGPU: false
+});
+const PatternType = {
+ TILING: 1,
+ SHADING: 2
+};
+const TEXT_CHUNK_BATCH_SIZE = 10;
+const deferred = Promise.resolve();
+function normalizeBlendMode(value, parsingArray = false) {
+ if (Array.isArray(value)) {
+ for (const val of value) {
+ const maybeBM = normalizeBlendMode(val, true);
+ if (maybeBM) {
+ return maybeBM;
+ }
+ }
+ warn(`Unsupported blend mode Array: ${value}`);
+ return "source-over";
+ }
+ if (value instanceof Name) {
+ switch (value.name) {
+ case "Normal":
+ case "Compatible":
+ return "source-over";
+ case "Multiply":
+ return "multiply";
+ case "Screen":
+ return "screen";
+ case "Overlay":
+ return "overlay";
+ case "Darken":
+ return "darken";
+ case "Lighten":
+ return "lighten";
+ case "ColorDodge":
+ return "color-dodge";
+ case "ColorBurn":
+ return "color-burn";
+ case "HardLight":
+ return "hard-light";
+ case "SoftLight":
+ return "soft-light";
+ case "Difference":
+ return "difference";
+ case "Exclusion":
+ return "exclusion";
+ case "Hue":
+ return "hue";
+ case "Saturation":
+ return "saturation";
+ case "Color":
+ return "color";
+ case "Luminosity":
+ return "luminosity";
+ }
+ warn(`Unsupported blend mode: ${value.name}`);
+ }
+ return parsingArray ? null : "source-over";
+}
+function addCachedImageOps(opList, {
+ objId,
+ fn,
+ args,
+ optionalContent,
+ hasMask
+}) {
+ if (objId) {
+ opList.addDependency(objId);
+ }
+ opList.addImageOps(fn, args, optionalContent, hasMask);
+ if (fn === OPS.paintImageMaskXObject && args[0]?.count > 0) {
+ args[0].count++;
+ }
+}
+class TimeSlotManager {
+ static TIME_SLOT_DURATION_MS = 20;
+ static CHECK_TIME_EVERY = 100;
+ constructor() {
+ this.reset();
+ }
+ check() {
+ if (++this.checked < TimeSlotManager.CHECK_TIME_EVERY) {
+ return false;
+ }
+ this.checked = 0;
+ return this.endTime <= Date.now();
+ }
+ reset() {
+ this.endTime = Date.now() + TimeSlotManager.TIME_SLOT_DURATION_MS;
+ this.checked = 0;
+ }
+}
+class PartialEvaluator {
+ constructor({
+ xref,
+ handler,
+ pageIndex,
+ idFactory,
+ fontCache,
+ builtInCMapCache,
+ standardFontDataCache,
+ globalColorSpaceCache,
+ globalImageCache,
+ systemFontCache,
+ options = null
+ }) {
+ this.xref = xref;
+ this.handler = handler;
+ this.pageIndex = pageIndex;
+ this.idFactory = idFactory;
+ this.fontCache = fontCache;
+ this.builtInCMapCache = builtInCMapCache;
+ this.standardFontDataCache = standardFontDataCache;
+ this.globalColorSpaceCache = globalColorSpaceCache;
+ this.globalImageCache = globalImageCache;
+ this.systemFontCache = systemFontCache;
+ this.options = options || DefaultPartialEvaluatorOptions;
+ this.type3FontRefs = null;
+ this._regionalImageCache = new RegionalImageCache();
+ this._fetchBuiltInCMapBound = this.fetchBuiltInCMap.bind(this);
+ }
+ get _pdfFunctionFactory() {
+ return shadow(this, "_pdfFunctionFactory", new PDFFunctionFactory({
+ xref: this.xref
+ }));
+ }
+ get parsingType3Font() {
+ return !!this.type3FontRefs;
+ }
+ clone(newOptions = null) {
+ const newEvaluator = Object.create(this);
+ newEvaluator.options = Object.assign(Object.create(null), this.options, newOptions);
+ return newEvaluator;
+ }
+ hasBlendModes(resources, nonBlendModesSet) {
+ if (!(resources instanceof Dict)) {
+ return false;
+ }
+ if (resources.objId && nonBlendModesSet.has(resources.objId)) {
+ return false;
+ }
+ const processed = new RefSet(nonBlendModesSet);
+ if (resources.objId) {
+ processed.put(resources.objId);
+ }
+ const nodes = [resources],
+ xref = this.xref;
+ while (nodes.length) {
+ const node = nodes.shift();
+ const graphicStates = node.get("ExtGState");
+ if (graphicStates instanceof Dict) {
+ for (let graphicState of graphicStates.getRawValues()) {
+ if (graphicState instanceof Ref) {
+ if (processed.has(graphicState)) {
+ continue;
+ }
+ try {
+ graphicState = xref.fetch(graphicState);
+ } catch (ex) {
+ processed.put(graphicState);
+ info(`hasBlendModes - ignoring ExtGState: "${ex}".`);
+ continue;
+ }
+ }
+ if (!(graphicState instanceof Dict)) {
+ continue;
+ }
+ if (graphicState.objId) {
+ processed.put(graphicState.objId);
+ }
+ const bm = graphicState.get("BM");
+ if (bm instanceof Name) {
+ if (bm.name !== "Normal") {
+ return true;
+ }
+ continue;
+ }
+ if (bm !== undefined && Array.isArray(bm)) {
+ for (const element of bm) {
+ if (element instanceof Name && element.name !== "Normal") {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ const xObjects = node.get("XObject");
+ if (!(xObjects instanceof Dict)) {
+ continue;
+ }
+ for (let xObject of xObjects.getRawValues()) {
+ if (xObject instanceof Ref) {
+ if (processed.has(xObject)) {
+ continue;
+ }
+ try {
+ xObject = xref.fetch(xObject);
+ } catch (ex) {
+ processed.put(xObject);
+ info(`hasBlendModes - ignoring XObject: "${ex}".`);
+ continue;
+ }
+ }
+ if (!(xObject instanceof BaseStream)) {
+ continue;
+ }
+ if (xObject.dict.objId) {
+ processed.put(xObject.dict.objId);
+ }
+ const xResources = xObject.dict.get("Resources");
+ if (!(xResources instanceof Dict)) {
+ continue;
+ }
+ if (xResources.objId && processed.has(xResources.objId)) {
+ continue;
+ }
+ nodes.push(xResources);
+ if (xResources.objId) {
+ processed.put(xResources.objId);
+ }
+ }
+ }
+ for (const ref of processed) {
+ nonBlendModesSet.put(ref);
+ }
+ return false;
+ }
+ async fetchBuiltInCMap(name) {
+ const cachedData = this.builtInCMapCache.get(name);
+ if (cachedData) {
+ return cachedData;
+ }
+ let data;
+ if (this.options.useWorkerFetch) {
+ data = {
+ cMapData: await fetchBinaryData(`${this.options.cMapUrl}${name}.bcmap`),
+ isCompressed: true
+ };
+ } else {
+ data = {
+ cMapData: await this.handler.sendWithPromise("FetchBinaryData", {
+ kind: "cMapUrl",
+ filename: `${name}${this.options.cMapPacked ? ".bcmap" : ""}`
+ }),
+ isCompressed: this.options.cMapPacked
+ };
+ }
+ this.builtInCMapCache.set(name, data);
+ return data;
+ }
+ async fetchStandardFontData(name) {
+ const cachedData = this.standardFontDataCache.get(name);
+ if (cachedData) {
+ return new Stream(cachedData);
+ }
+ if (this.options.useSystemFonts && name !== "Symbol" && name !== "ZapfDingbats") {
+ return null;
+ }
+ const standardFontNameToFileName = getFontNameToFileMap(),
+ filename = standardFontNameToFileName[name];
+ let data;
+ try {
+ if (this.options.useWorkerFetch) {
+ data = await fetchBinaryData(`${this.options.standardFontDataUrl}${filename}`);
+ } else {
+ data = await this.handler.sendWithPromise("FetchBinaryData", {
+ kind: "standardFontDataUrl",
+ filename
+ });
+ }
+ } catch (ex) {
+ warn(ex);
+ return null;
+ }
+ this.standardFontDataCache.set(name, data);
+ return new Stream(data);
+ }
+ async buildFormXObject(resources, xobj, smask, operatorList, task, initialState, localColorSpaceCache, seenRefs) {
+ const {
+ dict
+ } = xobj;
+ const matrix = lookupMatrix(dict.getArray("Matrix"), null);
+ const bbox = lookupNormalRect(dict.getArray("BBox"), null);
+ let f32bbox = bbox && new Float32Array(bbox);
+ if (f32bbox?.some(x => !isFinite(x))) {
+ f32bbox = null;
+ }
+ let optionalContent, groupOptions;
+ if (dict.has("OC")) {
+ optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources);
+ }
+ if (optionalContent !== undefined) {
+ operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
+ }
+ const group = dict.get("Group");
+ let newOpList;
+ const f32matrix = matrix && new Float32Array(matrix);
+ const args = [f32matrix, !group && f32bbox || null];
+ const localResources = dict.get("Resources");
+ if (group) {
+ groupOptions = {
+ matrix,
+ bbox: f32bbox,
+ smask,
+ isolated: false,
+ knockout: false,
+ needsIsolation: false,
+ hasSoftMask: false,
+ isGray: false
+ };
+ const groupSubtype = group.get("S");
+ let colorSpace = null;
+ if (isName(groupSubtype, "Transparency")) {
+ groupOptions.isolated = group.get("I") || false;
+ groupOptions.knockout = group.get("K") || false;
+ if (group.has("CS")) {
+ const cs = this._getColorSpace(group.getRaw("CS"), resources, localColorSpaceCache);
+ colorSpace = cs instanceof ColorSpace ? cs : await this._handleColorSpace(cs);
+ }
+ }
+ groupOptions.isGray = colorSpace?.numComps === 1;
+ if (smask?.backdrop) {
+ colorSpace ||= ColorSpaceUtils.rgb;
+ smask.backdrop = colorSpace.getRgbHex(smask.backdrop, 0);
+ } else if (smask?.subtype === "Luminosity") {
+ smask.backdrop = "#000000";
+ }
+ newOpList = new CheckedOperatorList();
+ } else {
+ newOpList = operatorList;
+ operatorList.addOp(OPS.paintFormXObjectBegin, args);
+ }
+ await this.getOperatorList({
+ stream: xobj,
+ task,
+ resources: localResources instanceof Dict ? localResources : resources,
+ operatorList: newOpList,
+ initialState,
+ prevRefs: seenRefs
+ });
+ if (group) {
+ groupOptions.needsIsolation = newOpList.needsIsolation || !!smask;
+ groupOptions.hasSoftMask = newOpList.hasSoftMask || !!smask;
+ operatorList.addOp(OPS.beginGroup, [groupOptions]);
+ operatorList.addOp(OPS.paintFormXObjectBegin, args);
+ operatorList.addOpList(newOpList);
+ operatorList.addOp(OPS.paintFormXObjectEnd, []);
+ operatorList.addOp(OPS.endGroup, [groupOptions]);
+ } else {
+ operatorList.addOp(OPS.paintFormXObjectEnd, []);
+ }
+ if (optionalContent !== undefined) {
+ operatorList.addOp(OPS.endMarkedContent, []);
+ }
+ }
+ _sendImgData(objId, imgData, cacheGlobally = false) {
+ const transfers = imgData ? [imgData.bitmap || imgData.data.buffer] : null;
+ if (this.parsingType3Font || cacheGlobally) {
+ return this.handler.send("commonobj", [objId, "Image", imgData], transfers);
+ }
+ return this.handler.send("obj", [objId, this.pageIndex, "Image", imgData], transfers);
+ }
+ async buildPaintImageXObject({
+ resources,
+ image,
+ isInline = false,
+ operatorList,
+ cacheKey,
+ localImageCache,
+ localColorSpaceCache
+ }) {
+ const {
+ maxImageSize,
+ ignoreErrors,
+ isOffscreenCanvasSupported
+ } = this.options;
+ const {
+ dict
+ } = image;
+ const imageRef = dict.objId;
+ const w = dict.get("W", "Width");
+ const h = dict.get("H", "Height");
+ if (!(w && typeof w === "number") || !(h && typeof h === "number")) {
+ warn("Image dimensions are missing, or not numbers.");
+ return;
+ }
+ if (maxImageSize !== -1 && w * h > maxImageSize) {
+ const msg = "Image exceeded maximum allowed size and was removed.";
+ if (!ignoreErrors) {
+ throw new Error(msg);
+ }
+ warn(msg);
+ return;
+ }
+ let optionalContent;
+ if (dict.has("OC")) {
+ optionalContent = await this.parseMarkedContentProps(dict.get("OC"), resources);
+ }
+ const imageMask = dict.get("IM", "ImageMask") || false;
+ let imgData, fn, args;
+ if (imageMask) {
+ imgData = await PDFImage.createMask({
+ image,
+ isOffscreenCanvasSupported: isOffscreenCanvasSupported && !this.parsingType3Font
+ });
+ if (imgData.isSingleOpaquePixel) {
+ fn = OPS.paintSolidColorImageMask;
+ args = [];
+ operatorList.addImageOps(fn, args, optionalContent);
+ if (cacheKey) {
+ const cacheData = {
+ fn,
+ args,
+ optionalContent
+ };
+ localImageCache.set(cacheKey, imageRef, cacheData);
+ if (imageRef) {
+ this._regionalImageCache.set(null, imageRef, cacheData);
+ }
+ }
+ return;
+ }
+ if (this.parsingType3Font) {
+ args = compileType3Glyph(imgData);
+ if (args) {
+ operatorList.addImageOps(OPS.constructPath, args, optionalContent);
+ return;
+ }
+ warn("Cannot compile Type3 glyph.");
+ operatorList.addImageOps(OPS.paintImageMaskXObject, [imgData], optionalContent);
+ return;
+ }
+ const objId = `mask_${this.idFactory.createObjId()}`;
+ operatorList.addDependency(objId);
+ imgData.dataLen = imgData.bitmap ? imgData.width * imgData.height * 4 : imgData.data.length;
+ this._sendImgData(objId, imgData);
+ fn = OPS.paintImageMaskXObject;
+ args = [{
+ data: objId,
+ width: imgData.width,
+ height: imgData.height,
+ interpolate: imgData.interpolate,
+ count: 1
+ }];
+ operatorList.addImageOps(fn, args, optionalContent);
+ if (cacheKey) {
+ const cacheData = {
+ objId,
+ fn,
+ args,
+ optionalContent
+ };
+ localImageCache.set(cacheKey, imageRef, cacheData);
+ if (imageRef) {
+ this._regionalImageCache.set(null, imageRef, cacheData);
+ }
+ }
+ return;
+ }
+ const SMALL_IMAGE_DIMENSIONS = 200;
+ const hasMask = dict.has("SMask") || dict.has("Mask");
+ if (isInline && w + h < SMALL_IMAGE_DIMENSIONS && !hasMask) {
+ try {
+ const imageObj = new PDFImage({
+ xref: this.xref,
+ res: resources,
+ image,
+ isInline,
+ pdfFunctionFactory: this._pdfFunctionFactory,
+ globalColorSpaceCache: this.globalColorSpaceCache,
+ localColorSpaceCache
+ });
+ imgData = await imageObj.createImageData(true, false);
+ operatorList.addImageOps(OPS.paintInlineImageXObject, [imgData], optionalContent);
+ } catch (reason) {
+ const msg = `Unable to decode inline image: "${reason}".`;
+ if (!ignoreErrors) {
+ throw new Error(msg);
+ }
+ warn(msg);
+ }
+ return;
+ }
+ let objId = `img_${this.idFactory.createObjId()}`,
+ cacheGlobally = false,
+ globalCacheData = null;
+ if (this.parsingType3Font) {
+ objId = `${this.idFactory.getDocId()}_type3_${objId}`;
+ } else if (cacheKey && imageRef) {
+ cacheGlobally = this.globalImageCache.shouldCache(imageRef, this.pageIndex);
+ if (cacheGlobally) {
+ assert(!isInline, "Cannot cache an inline image globally.");
+ objId = `${this.idFactory.getDocId()}_${objId}`;
+ }
+ }
+ operatorList.addDependency(objId);
+ fn = OPS.paintImageXObject;
+ args = [objId, w, h];
+ operatorList.addImageOps(fn, args, optionalContent, hasMask);
+ if (cacheGlobally) {
+ globalCacheData = {
+ objId,
+ fn,
+ args,
+ optionalContent,
+ hasMask,
+ byteSize: 0
+ };
+ if (this.globalImageCache.hasDecodeFailed(imageRef)) {
+ this.globalImageCache.setData(imageRef, globalCacheData);
+ this._sendImgData(objId, null, cacheGlobally);
+ return;
+ }
+ if (w * h > 250000 || hasMask) {
+ const localLength = await this.handler.sendWithPromise("commonobj", [objId, "CopyLocalImage", {
+ imageRef
+ }]);
+ if (localLength) {
+ this.globalImageCache.setData(imageRef, globalCacheData);
+ this.globalImageCache.addByteSize(imageRef, localLength);
+ return;
+ }
+ }
+ }
+ PDFImage.buildImage({
+ xref: this.xref,
+ res: resources,
+ image,
+ isInline,
+ pdfFunctionFactory: this._pdfFunctionFactory,
+ globalColorSpaceCache: this.globalColorSpaceCache,
+ localColorSpaceCache
+ }).then(async imageObj => {
+ imgData = await imageObj.createImageData(false, isOffscreenCanvasSupported);
+ imgData.dataLen = imgData.bitmap ? imgData.width * imgData.height * 4 : imgData.data.length;
+ imgData.ref = imageRef;
+ if (cacheGlobally) {
+ this.globalImageCache.addByteSize(imageRef, imgData.dataLen);
+ }
+ return this._sendImgData(objId, imgData, cacheGlobally);
+ }).catch(reason => {
+ warn(`Unable to decode image "${objId}": "${reason}".`);
+ if (imageRef) {
+ this.globalImageCache.addDecodeFailed(imageRef);
+ }
+ return this._sendImgData(objId, null, cacheGlobally);
+ });
+ if (cacheKey) {
+ const cacheData = {
+ objId,
+ fn,
+ args,
+ optionalContent,
+ hasMask
+ };
+ localImageCache.set(cacheKey, imageRef, cacheData);
+ if (imageRef) {
+ this._regionalImageCache.set(null, imageRef, cacheData);
+ if (cacheGlobally) {
+ assert(globalCacheData, "The global cache-data must be available.");
+ this.globalImageCache.setData(imageRef, globalCacheData);
+ }
+ }
+ }
+ }
+ #createTransferMap(fn) {
+ const transferFn = this._pdfFunctionFactory.create(fn),
+ tmp = new Float32Array(1);
+ return Uint8Array.from({
+ length: 256
+ }, (_, i) => {
+ tmp[0] = i / 255;
+ transferFn(tmp, 0, tmp, 0);
+ return tmp[0] * 255 | 0;
+ });
+ }
+ handleSMask(smask, resources, operatorList, task, stateManager, localColorSpaceCache, seenRefs) {
+ const smaskContent = smask.get("G");
+ const smaskOptions = {
+ subtype: smask.get("S").name,
+ backdrop: smask.get("BC")
+ };
+ const transferObj = smask.get("TR");
+ if (isPDFFunction(transferObj)) {
+ smaskOptions.transferMap = this.#createTransferMap(transferObj);
+ }
+ return this.buildFormXObject(resources, smaskContent, smaskOptions, operatorList, task, stateManager.state.clone({
+ newPath: true
+ }), localColorSpaceCache, seenRefs);
+ }
+ handleTransferFunction(tr) {
+ let transferArray;
+ if (Array.isArray(tr)) {
+ transferArray = tr.length > 1 && tr.every(map => map === tr[0]) ? [tr[0]] : tr;
+ } else if (isPDFFunction(tr)) {
+ transferArray = [tr];
+ } else {
+ return null;
+ }
+ const transferMaps = [];
+ let numFns = 0,
+ numEffectfulFns = 0;
+ for (const entry of transferArray) {
+ const transferObj = this.xref.fetchIfRef(entry);
+ numFns++;
+ if (isName(transferObj, "Identity")) {
+ transferMaps.push(null);
+ continue;
+ } else if (!isPDFFunction(transferObj)) {
+ return null;
+ }
+ transferMaps.push(this.#createTransferMap(transferObj));
+ numEffectfulFns++;
+ }
+ if (!(numFns === 1 || numFns === 4)) {
+ return null;
+ }
+ if (numEffectfulFns === 0) {
+ return null;
+ }
+ return transferMaps;
+ }
+ handleTilingType(fn, color, resources, pattern, patternDict, operatorList, task, localTilingPatternCache, seenRefs) {
+ const tilingOpList = new CheckedOperatorList();
+ const patternResources = Dict.merge({
+ xref: this.xref,
+ dictArray: [patternDict.get("Resources"), resources]
+ });
+ return this.getOperatorList({
+ stream: pattern,
+ task,
+ resources: patternResources,
+ operatorList: tilingOpList,
+ prevRefs: seenRefs
+ }).then(function () {
+ const operatorListIR = tilingOpList.getIR();
+ const {
+ needsIsolation
+ } = tilingOpList;
+ const tilingPatternIR = getTilingPatternIR(operatorListIR, patternDict, color, needsIsolation);
+ operatorList.addDependencies(tilingOpList.dependencies);
+ operatorList.addOp(fn, tilingPatternIR);
+ if (patternDict.objId) {
+ localTilingPatternCache.set(null, patternDict.objId, {
+ operatorListIR,
+ needsIsolation,
+ dict: patternDict
+ });
+ }
+ }).catch(reason => {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (this.options.ignoreErrors) {
+ warn(`handleTilingType - ignoring pattern: "${reason}".`);
+ return;
+ }
+ throw reason;
+ });
+ }
+ async handleSetFont(resources, fontArgs, fontRef, operatorList, task, state, fallbackFontDict = null, cssFontInfo = null, seenRefs = null) {
+ const fontName = fontArgs?.[0] instanceof Name ? fontArgs[0].name : null;
+ const translated = await this.loadFont(fontName, fontRef, resources, task, fallbackFontDict, cssFontInfo, seenRefs);
+ if (translated.font.isType3Font) {
+ operatorList.addDependencies(translated.type3Dependencies);
+ }
+ state.font = translated.font;
+ translated.send(this.handler);
+ return translated.loadedName;
+ }
+ handleText(chars, state) {
+ const font = state.font;
+ const glyphs = font.charsToGlyphs(chars);
+ if (font.data) {
+ const isAddToPathSet = !!(state.textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG);
+ if (isAddToPathSet || state.fillColorSpace.name === "Pattern" || state.strokeColorSpace.name === "Pattern" || font.disableFontFace) {
+ PartialEvaluator.buildFontPaths(font, glyphs, this.handler, this.options);
+ }
+ }
+ return glyphs;
+ }
+ ensureStateFont(state) {
+ if (state.font) {
+ return;
+ }
+ const reason = new FormatError("Missing setFont (Tf) operator before text rendering operator.");
+ if (this.options.ignoreErrors) {
+ warn(`ensureStateFont: "${reason}".`);
+ return;
+ }
+ throw reason;
+ }
+ async setGState({
+ resources,
+ gState,
+ operatorList,
+ cacheKey,
+ task,
+ stateManager,
+ localGStateCache,
+ localColorSpaceCache,
+ seenRefs
+ }) {
+ const gStateRef = gState.objId;
+ let isSimpleGState = true;
+ const gStateObj = [];
+ let promise = Promise.resolve();
+ for (const [key, value] of gState) {
+ switch (key) {
+ case "Type":
+ break;
+ case "LW":
+ if (typeof value !== "number") {
+ warn(`Invalid LW (line width): ${value}`);
+ break;
+ }
+ gStateObj.push([key, Math.abs(value)]);
+ break;
+ case "LC":
+ case "LJ":
+ case "ML":
+ case "D":
+ case "RI":
+ case "FL":
+ case "CA":
+ case "ca":
+ gStateObj.push([key, value]);
+ break;
+ case "Font":
+ isSimpleGState = false;
+ promise = promise.then(() => this.handleSetFont(resources, null, value[0], operatorList, task, stateManager.state, null, null, seenRefs).then(function (loadedName) {
+ operatorList.addDependency(loadedName);
+ gStateObj.push([key, [loadedName, value[1]]]);
+ }));
+ break;
+ case "BM":
+ gStateObj.push([key, normalizeBlendMode(value)]);
+ break;
+ case "SMask":
+ if (isName(value, "None")) {
+ gStateObj.push([key, false]);
+ break;
+ }
+ if (value instanceof Dict) {
+ isSimpleGState = false;
+ promise = promise.then(() => this.handleSMask(value, resources, operatorList, task, stateManager, localColorSpaceCache, seenRefs));
+ gStateObj.push([key, true]);
+ } else {
+ warn("Unsupported SMask type");
+ }
+ break;
+ case "TR":
+ if (gState.has("TR2")) {
+ break;
+ }
+ case "TR2":
+ {
+ const transferMaps = this.handleTransferFunction(value);
+ gStateObj.push(["TR", transferMaps]);
+ break;
+ }
+ case "OP":
+ case "op":
+ case "OPM":
+ case "BG":
+ case "BG2":
+ case "UCR":
+ case "UCR2":
+ case "HT":
+ case "SM":
+ case "SA":
+ case "AIS":
+ case "TK":
+ info("graphic state operator " + key);
+ break;
+ default:
+ info("Unknown graphic state operator " + key);
+ break;
+ }
+ }
+ await promise;
+ if (gStateObj.length > 0) {
+ operatorList.addOp(OPS.setGState, [gStateObj]);
+ }
+ if (isSimpleGState) {
+ localGStateCache.set(cacheKey, gStateRef, gStateObj);
+ }
+ }
+ loadFont(fontName, font, resources, task, fallbackFontDict = null, cssFontInfo = null, seenRefs = null) {
+ const errorFont = async () => new TranslatedFont({
+ loadedName: "g_font_error",
+ font: new ErrorFont(`Font "${fontName}" is not available.`),
+ dict: font
+ });
+ let fontRef;
+ if (font) {
+ if (font instanceof Ref) {
+ fontRef = font;
+ }
+ } else {
+ const fontRes = resources.get("Font");
+ if (fontRes) {
+ fontRef = fontRes.getRaw(fontName);
+ }
+ }
+ if (fontRef) {
+ if (this.type3FontRefs?.has(fontRef)) {
+ return errorFont();
+ }
+ if (this.fontCache.has(fontRef)) {
+ return this.fontCache.get(fontRef);
+ }
+ try {
+ font = this.xref.fetchIfRef(fontRef);
+ } catch (ex) {
+ warn(`loadFont - lookup failed: "${ex}".`);
+ }
+ }
+ if (!(font instanceof Dict)) {
+ if (!this.options.ignoreErrors && !this.parsingType3Font) {
+ warn(`Font "${fontName}" is not available.`);
+ return errorFont();
+ }
+ warn(`Font "${fontName}" is not available -- attempting to fallback to a default font.`);
+ font = fallbackFontDict || PartialEvaluator.fallbackFontDict;
+ }
+ if (font.cacheKey && this.fontCache.has(font.cacheKey)) {
+ return this.fontCache.get(font.cacheKey);
+ }
+ const {
+ promise,
+ resolve
+ } = Promise.withResolvers();
+ let preEvaluatedFont;
+ try {
+ preEvaluatedFont = this.preEvaluateFont(font);
+ preEvaluatedFont.cssFontInfo = cssFontInfo;
+ } catch (reason) {
+ warn(`loadFont - preEvaluateFont failed: "${reason}".`);
+ return errorFont();
+ }
+ const {
+ descriptor,
+ hash
+ } = preEvaluatedFont;
+ const fontRefIsRef = fontRef instanceof Ref;
+ let fontID;
+ if (hash && descriptor instanceof Dict) {
+ const fontAliases = descriptor.fontAliases ||= Object.create(null);
+ if (fontAliases[hash]) {
+ const aliasFontRef = fontAliases[hash].aliasRef;
+ if (fontRefIsRef && aliasFontRef && this.fontCache.has(aliasFontRef)) {
+ this.fontCache.putAlias(fontRef, aliasFontRef);
+ return this.fontCache.get(fontRef);
+ }
+ } else {
+ fontAliases[hash] = {
+ fontID: this.idFactory.createFontId()
+ };
+ }
+ if (fontRefIsRef) {
+ fontAliases[hash].aliasRef = fontRef;
+ }
+ fontID = fontAliases[hash].fontID;
+ } else {
+ fontID = this.idFactory.createFontId();
+ }
+ assert(fontID?.startsWith("f"), 'The "fontID" must be (correctly) defined.');
+ if (fontRefIsRef) {
+ this.fontCache.put(fontRef, promise);
+ } else {
+ font.cacheKey = `cacheKey_${fontID}`;
+ this.fontCache.put(font.cacheKey, promise);
+ }
+ font.loadedName = `${this.idFactory.getDocId()}_${fontID}`;
+ this.translateFont(preEvaluatedFont).then(async translatedFont => {
+ const translated = new TranslatedFont({
+ loadedName: font.loadedName,
+ font: translatedFont,
+ dict: font
+ });
+ if (translatedFont.isType3Font) {
+ try {
+ await translated.loadType3Data(this, resources, task, seenRefs);
+ } catch (reason) {
+ throw new Error(`Type3 font load error: ${reason}`);
+ }
+ }
+ resolve(translated);
+ }).catch(reason => {
+ warn(`loadFont - translateFont failed: "${reason}".`);
+ resolve(new TranslatedFont({
+ loadedName: font.loadedName,
+ font: new ErrorFont(reason?.message),
+ dict: font
+ }));
+ });
+ return promise;
+ }
+ buildPath(fn, args, state) {
+ const {
+ pathMinMax: minMax,
+ pathBuffer
+ } = state;
+ switch (fn | 0) {
+ case OPS.rectangle:
+ {
+ const x = state.currentPointX = args[0];
+ const y = state.currentPointY = args[1];
+ const width = args[2];
+ const height = args[3];
+ const xw = x + width;
+ const yh = y + height;
+ if (width === 0 || height === 0) {
+ pathBuffer.push(DrawOPS.moveTo, x, y, DrawOPS.lineTo, xw, yh, DrawOPS.closePath);
+ } else {
+ pathBuffer.push(DrawOPS.moveTo, x, y, DrawOPS.lineTo, xw, y, DrawOPS.lineTo, xw, yh, DrawOPS.lineTo, x, yh, DrawOPS.closePath);
+ }
+ Util.rectBoundingBox(x, y, xw, yh, minMax);
+ break;
+ }
+ case OPS.moveTo:
+ {
+ const x = state.currentPointX = args[0];
+ const y = state.currentPointY = args[1];
+ pathBuffer.push(DrawOPS.moveTo, x, y);
+ Util.pointBoundingBox(x, y, minMax);
+ break;
+ }
+ case OPS.lineTo:
+ {
+ const x = state.currentPointX = args[0];
+ const y = state.currentPointY = args[1];
+ pathBuffer.push(DrawOPS.lineTo, x, y);
+ Util.pointBoundingBox(x, y, minMax);
+ break;
+ }
+ case OPS.curveTo:
+ {
+ const startX = state.currentPointX;
+ const startY = state.currentPointY;
+ const [x1, y1, x2, y2, x, y] = args;
+ state.currentPointX = x;
+ state.currentPointY = y;
+ pathBuffer.push(DrawOPS.curveTo, x1, y1, x2, y2, x, y);
+ Util.bezierBoundingBox(startX, startY, x1, y1, x2, y2, x, y, minMax);
+ break;
+ }
+ case OPS.curveTo2:
+ {
+ const startX = state.currentPointX;
+ const startY = state.currentPointY;
+ const [x1, y1, x, y] = args;
+ state.currentPointX = x;
+ state.currentPointY = y;
+ pathBuffer.push(DrawOPS.curveTo, startX, startY, x1, y1, x, y);
+ Util.bezierBoundingBox(startX, startY, startX, startY, x1, y1, x, y, minMax);
+ break;
+ }
+ case OPS.curveTo3:
+ {
+ const startX = state.currentPointX;
+ const startY = state.currentPointY;
+ const [x1, y1, x, y] = args;
+ state.currentPointX = x;
+ state.currentPointY = y;
+ pathBuffer.push(DrawOPS.curveTo, x1, y1, x, y, x, y);
+ Util.bezierBoundingBox(startX, startY, x1, y1, x, y, x, y, minMax);
+ break;
+ }
+ case OPS.closePath:
+ pathBuffer.push(DrawOPS.closePath);
+ break;
+ }
+ }
+ _getColorSpace(cs, resources, localColorSpaceCache) {
+ return ColorSpaceUtils.parse({
+ cs,
+ xref: this.xref,
+ resources,
+ pdfFunctionFactory: this._pdfFunctionFactory,
+ globalColorSpaceCache: this.globalColorSpaceCache,
+ localColorSpaceCache,
+ asyncIfNotCached: true
+ });
+ }
+ async _handleColorSpace(csPromise) {
+ try {
+ return await csPromise;
+ } catch (ex) {
+ if (ex instanceof AbortException) {
+ return null;
+ }
+ if (this.options.ignoreErrors) {
+ warn(`_handleColorSpace - ignoring ColorSpace: "${ex}".`);
+ return null;
+ }
+ throw ex;
+ }
+ }
+ parseShading({
+ shading,
+ resources,
+ localColorSpaceCache,
+ localShadingPatternCache
+ }) {
+ let id = localShadingPatternCache.get(shading);
+ if (id) {
+ return id;
+ }
+ let patternIR;
+ try {
+ const shadingFill = Pattern.parseShading(shading, this.xref, resources, this._pdfFunctionFactory, this.globalColorSpaceCache, localColorSpaceCache);
+ patternIR = shadingFill.getIR();
+ } catch (reason) {
+ if (reason instanceof AbortException) {
+ return null;
+ }
+ if (this.options.ignoreErrors) {
+ warn(`parseShading - ignoring shading: "${reason}".`);
+ localShadingPatternCache.set(shading, null);
+ return null;
+ }
+ throw reason;
+ }
+ id = `pattern_${this.idFactory.createObjId()}`;
+ if (this.parsingType3Font) {
+ id = `${this.idFactory.getDocId()}_type3_${id}`;
+ }
+ localShadingPatternCache.set(shading, id);
+ if (this.parsingType3Font) {
+ const buffer = compilePatternInfo(patternIR);
+ this.handler.send("commonobj", [id, "Pattern", buffer], [buffer]);
+ } else {
+ this.handler.send("obj", [id, this.pageIndex, "Pattern", patternIR]);
+ }
+ return id;
+ }
+ handleColorN(operatorList, fn, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache, localShadingPatternCache, seenRefs) {
+ const patternName = args.pop();
+ if (patternName instanceof Name) {
+ const rawPattern = patterns.getRaw(patternName.name);
+ const localTilingPattern = rawPattern instanceof Ref && localTilingPatternCache.getByRef(rawPattern);
+ if (localTilingPattern) {
+ try {
+ const color = cs.base ? cs.base.getRgbHex(args, 0) : null;
+ const tilingPatternIR = getTilingPatternIR(localTilingPattern.operatorListIR, localTilingPattern.dict, color, localTilingPattern.needsIsolation);
+ operatorList.addOp(fn, tilingPatternIR);
+ return undefined;
+ } catch {}
+ }
+ const pattern = this.xref.fetchIfRef(rawPattern);
+ if (pattern) {
+ const dict = pattern instanceof BaseStream ? pattern.dict : pattern;
+ const typeNum = dict.get("PatternType");
+ if (typeNum === PatternType.TILING) {
+ const color = cs.base ? cs.base.getRgbHex(args, 0) : null;
+ return this.handleTilingType(fn, color, resources, pattern, dict, operatorList, task, localTilingPatternCache, seenRefs);
+ } else if (typeNum === PatternType.SHADING) {
+ const shading = dict.get("Shading");
+ const objId = this.parseShading({
+ shading,
+ resources,
+ localColorSpaceCache,
+ localShadingPatternCache
+ });
+ if (objId) {
+ const matrix = lookupMatrix(dict.getArray("Matrix"), null);
+ operatorList.addOp(fn, ["Shading", objId, matrix]);
+ }
+ return undefined;
+ }
+ throw new FormatError(`Unknown PatternType: ${typeNum}`);
+ }
+ }
+ throw new FormatError(`Unknown PatternName: ${patternName}`);
+ }
+ async parseMarkedContentProps(contentProperties, resources) {
+ return parseMarkedContentProps(this.xref, contentProperties, resources);
+ }
+ async getOperatorList({
+ stream,
+ task,
+ resources,
+ operatorList,
+ initialState = null,
+ fallbackFontDict = null,
+ prevRefs = null
+ }) {
+ if (stream.isAsync) {
+ const bytes = await stream.asyncGetBytes();
+ if (bytes) {
+ stream = new Stream(bytes, 0, bytes.length, stream.dict);
+ }
+ }
+ const objId = stream.dict?.objId;
+ const seenRefs = new RefSet(prevRefs);
+ if (objId) {
+ if (prevRefs?.has(objId)) {
+ throw new Error(`getOperatorList - ignoring circular reference: ${objId}`);
+ }
+ seenRefs.put(objId);
+ }
+ resources ||= Dict.empty;
+ initialState ||= new EvalState();
+ if (!operatorList) {
+ throw new Error('getOperatorList: missing "operatorList" parameter');
+ }
+ const self = this;
+ const xref = this.xref;
+ const localImageCache = new LocalImageCache();
+ const localColorSpaceCache = new LocalColorSpaceCache();
+ const localGStateCache = new LocalGStateCache();
+ const localTilingPatternCache = new LocalTilingPatternCache();
+ const localShadingPatternCache = new Map();
+ const xobjs = resources.get("XObject") || Dict.empty;
+ const patterns = resources.get("Pattern") || Dict.empty;
+ const stateManager = new StateManager(initialState);
+ const preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
+ const timeSlotManager = new TimeSlotManager();
+ let markedContentLevel = 0;
+ function closePendingRestoreOPS(argument) {
+ for (let i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
+ operatorList.addOp(OPS.restore, []);
+ }
+ }
+ function closePendingMarkedContentOPS() {
+ for (; markedContentLevel > 0; markedContentLevel--) {
+ operatorList.addOp(OPS.endMarkedContent, []);
+ }
+ }
+ return new Promise(function promiseBody(resolve, reject) {
+ const next = function (promise) {
+ Promise.all([promise, operatorList.ready]).then(function () {
+ try {
+ promiseBody(resolve, reject);
+ } catch (ex) {
+ reject(ex);
+ }
+ }, reject);
+ };
+ task.ensureNotTerminated();
+ timeSlotManager.reset();
+ const operation = {};
+ let stop, cs, name, isValidName;
+ while (!(stop = timeSlotManager.check())) {
+ operation.args = null;
+ if (!preprocessor.read(operation)) {
+ break;
+ }
+ let args = operation.args;
+ let fn = operation.fn;
+ switch (fn | 0) {
+ case OPS.paintXObject:
+ isValidName = args[0] instanceof Name;
+ name = args[0].name;
+ if (isValidName) {
+ const localImage = localImageCache.getByName(name);
+ if (localImage) {
+ addCachedImageOps(operatorList, localImage);
+ args = null;
+ continue;
+ }
+ }
+ next(new Promise(function (resolveXObject, rejectXObject) {
+ if (!isValidName) {
+ throw new FormatError("XObject must be referred to by name.");
+ }
+ let xobj = xobjs.getRaw(name);
+ if (xobj instanceof Ref) {
+ const cachedImage = localImageCache.getByRef(xobj) || self._regionalImageCache.getByRef(xobj) || self.globalImageCache.getData(xobj, self.pageIndex);
+ if (cachedImage) {
+ addCachedImageOps(operatorList, cachedImage);
+ resolveXObject();
+ return;
+ }
+ xobj = xref.fetch(xobj);
+ }
+ if (!(xobj instanceof BaseStream)) {
+ throw new FormatError("XObject should be a stream");
+ }
+ const type = xobj.dict.get("Subtype");
+ if (!(type instanceof Name)) {
+ throw new FormatError("XObject should have a Name subtype");
+ }
+ if (type.name === "Form") {
+ stateManager.save();
+ self.buildFormXObject(resources, xobj, null, operatorList, task, stateManager.state.clone({
+ newPath: true
+ }), localColorSpaceCache, seenRefs).then(function () {
+ stateManager.restore();
+ resolveXObject();
+ }, rejectXObject);
+ return;
+ } else if (type.name === "Image") {
+ self.buildPaintImageXObject({
+ resources,
+ image: xobj,
+ operatorList,
+ cacheKey: name,
+ localImageCache,
+ localColorSpaceCache
+ }).then(resolveXObject, rejectXObject);
+ return;
+ } else if (type.name === "PS") {
+ info("Ignored XObject subtype PS");
+ } else {
+ throw new FormatError(`Unhandled XObject subtype ${type.name}`);
+ }
+ resolveXObject();
+ }).catch(function (reason) {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (self.options.ignoreErrors) {
+ warn(`getOperatorList - ignoring XObject: "${reason}".`);
+ return;
+ }
+ throw reason;
+ }));
+ return;
+ case OPS.setFont:
+ const fontSize = args[1];
+ next(self.handleSetFont(resources, args, null, operatorList, task, stateManager.state, fallbackFontDict, null, seenRefs).then(function (loadedName) {
+ operatorList.addDependency(loadedName);
+ operatorList.addOp(OPS.setFont, [loadedName, fontSize]);
+ }));
+ return;
+ case OPS.endInlineImage:
+ const cacheKey = args[0].cacheKey;
+ if (cacheKey) {
+ const localImage = localImageCache.getByName(cacheKey);
+ if (localImage) {
+ addCachedImageOps(operatorList, localImage);
+ args = null;
+ continue;
+ }
+ }
+ next(self.buildPaintImageXObject({
+ resources,
+ image: args[0],
+ isInline: true,
+ operatorList,
+ cacheKey,
+ localImageCache,
+ localColorSpaceCache
+ }));
+ return;
+ case OPS.showText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ args[0] = self.handleText(args[0], stateManager.state);
+ break;
+ case OPS.showSpacedText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ const combinedGlyphs = [],
+ state = stateManager.state;
+ for (const arrItem of args[0]) {
+ if (typeof arrItem === "string") {
+ combinedGlyphs.push(...self.handleText(arrItem, state));
+ } else if (typeof arrItem === "number") {
+ combinedGlyphs.push(arrItem);
+ }
+ }
+ args[0] = combinedGlyphs;
+ fn = OPS.showText;
+ break;
+ case OPS.nextLineShowText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ operatorList.addOp(OPS.nextLine);
+ args[0] = self.handleText(args[0], stateManager.state);
+ fn = OPS.showText;
+ break;
+ case OPS.nextLineSetSpacingShowText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ operatorList.addOp(OPS.nextLine);
+ operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
+ operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
+ args[0] = self.handleText(args[0], stateManager.state);
+ fn = OPS.showText;
+ break;
+ case OPS.setTextRenderingMode:
+ stateManager.state.textRenderingMode = args[0];
+ break;
+ case OPS.setFillColorSpace:
+ {
+ const fillCS = self._getColorSpace(args[0], resources, localColorSpaceCache);
+ if (fillCS instanceof ColorSpace) {
+ stateManager.state.fillColorSpace = fillCS;
+ continue;
+ }
+ next(self._handleColorSpace(fillCS).then(colorSpace => {
+ stateManager.state.fillColorSpace = colorSpace || ColorSpaceUtils.gray;
+ }));
+ return;
+ }
+ case OPS.setStrokeColorSpace:
+ {
+ const strokeCS = self._getColorSpace(args[0], resources, localColorSpaceCache);
+ if (strokeCS instanceof ColorSpace) {
+ stateManager.state.strokeColorSpace = strokeCS;
+ continue;
+ }
+ next(self._handleColorSpace(strokeCS).then(colorSpace => {
+ stateManager.state.strokeColorSpace = colorSpace || ColorSpaceUtils.gray;
+ }));
+ return;
+ }
+ case OPS.setFillColor:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ cs = stateManager.state.fillColorSpace;
+ args = [cs.getRgbHex(args, 0)];
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeColor:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ cs = stateManager.state.strokeColorSpace;
+ args = [cs.getRgbHex(args, 0)];
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillGray:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ stateManager.state.fillColorSpace = ColorSpaceUtils.gray;
+ args = [ColorSpaceUtils.gray.getRgbHex(args, 0)];
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeGray:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ stateManager.state.strokeColorSpace = ColorSpaceUtils.gray;
+ args = [ColorSpaceUtils.gray.getRgbHex(args, 0)];
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillCMYKColor:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ stateManager.state.fillColorSpace = ColorSpaceUtils.cmyk;
+ args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)];
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeCMYKColor:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ stateManager.state.strokeColorSpace = ColorSpaceUtils.cmyk;
+ args = [ColorSpaceUtils.cmyk.getRgbHex(args, 0)];
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillRGBColor:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ stateManager.state.fillColorSpace = ColorSpaceUtils.rgb;
+ args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)];
+ break;
+ case OPS.setStrokeRGBColor:
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ stateManager.state.strokeColorSpace = ColorSpaceUtils.rgb;
+ args = [ColorSpaceUtils.rgb.getRgbHex(args, 0)];
+ break;
+ case OPS.setFillColorN:
+ cs = stateManager.state.patternFillColorSpace;
+ if (!cs) {
+ if (isNumberArray(args, null)) {
+ args = [ColorSpaceUtils.gray.getRgbHex(args, 0)];
+ fn = OPS.setFillRGBColor;
+ break;
+ }
+ args = [];
+ fn = OPS.setFillTransparent;
+ break;
+ }
+ if (cs.name === "Pattern") {
+ if (!Array.isArray(args)) {
+ continue;
+ }
+ next(self.handleColorN(operatorList, OPS.setFillColorN, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache, localShadingPatternCache, seenRefs));
+ return;
+ }
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ args = [cs.getRgbHex(args, 0)];
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeColorN:
+ cs = stateManager.state.patternStrokeColorSpace;
+ if (!cs) {
+ if (isNumberArray(args, null)) {
+ args = [ColorSpaceUtils.gray.getRgbHex(args, 0)];
+ fn = OPS.setStrokeRGBColor;
+ break;
+ }
+ args = [];
+ fn = OPS.setStrokeTransparent;
+ break;
+ }
+ if (cs.name === "Pattern") {
+ if (!Array.isArray(args)) {
+ continue;
+ }
+ next(self.handleColorN(operatorList, OPS.setStrokeColorN, args, cs, patterns, resources, task, localColorSpaceCache, localTilingPatternCache, localShadingPatternCache, seenRefs));
+ return;
+ }
+ if (!isNumberArray(args, null)) {
+ continue;
+ }
+ args = [cs.getRgbHex(args, 0)];
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.shadingFill:
+ let shading;
+ try {
+ const shadingRes = resources.get("Shading");
+ if (!shadingRes) {
+ throw new FormatError("No shading resource found");
+ }
+ shading = shadingRes.get(args[0].name);
+ if (!shading) {
+ throw new FormatError("No shading object found");
+ }
+ } catch (reason) {
+ if (reason instanceof AbortException) {
+ continue;
+ }
+ if (self.options.ignoreErrors) {
+ warn(`getOperatorList - ignoring Shading: "${reason}".`);
+ continue;
+ }
+ throw reason;
+ }
+ const patternId = self.parseShading({
+ shading,
+ resources,
+ localColorSpaceCache,
+ localShadingPatternCache
+ });
+ if (!patternId) {
+ continue;
+ }
+ args = [patternId];
+ fn = OPS.shadingFill;
+ break;
+ case OPS.setGState:
+ isValidName = args[0] instanceof Name;
+ name = args[0].name;
+ if (isValidName) {
+ const localGStateObj = localGStateCache.getByName(name);
+ if (localGStateObj) {
+ if (localGStateObj.length > 0) {
+ operatorList.addOp(OPS.setGState, [localGStateObj]);
+ }
+ args = null;
+ continue;
+ }
+ }
+ next(new Promise(function (resolveGState, rejectGState) {
+ if (!isValidName) {
+ throw new FormatError("GState must be referred to by name.");
+ }
+ const extGState = resources.get("ExtGState");
+ if (!(extGState instanceof Dict)) {
+ throw new FormatError("ExtGState should be a dictionary.");
+ }
+ const gState = extGState.get(name);
+ if (!(gState instanceof Dict)) {
+ throw new FormatError("GState should be a dictionary.");
+ }
+ self.setGState({
+ resources,
+ gState,
+ operatorList,
+ cacheKey: name,
+ task,
+ stateManager,
+ localGStateCache,
+ localColorSpaceCache,
+ seenRefs
+ }).then(resolveGState, rejectGState);
+ }).catch(function (reason) {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (self.options.ignoreErrors) {
+ warn(`getOperatorList - ignoring ExtGState: "${reason}".`);
+ return;
+ }
+ throw reason;
+ }));
+ return;
+ case OPS.setLineWidth:
+ {
+ const [thickness] = args;
+ if (typeof thickness !== "number") {
+ warn(`Invalid setLineWidth: ${thickness}`);
+ continue;
+ }
+ args[0] = Math.abs(thickness);
+ break;
+ }
+ case OPS.setDash:
+ {
+ const dashPhase = args[1];
+ if (typeof dashPhase !== "number") {
+ warn(`Invalid setDash: ${dashPhase}`);
+ continue;
+ }
+ const dashArray = args[0];
+ if (!Array.isArray(dashArray)) {
+ warn(`Invalid setDash: ${dashArray}`);
+ continue;
+ }
+ if (dashArray.some(x => typeof x !== "number")) {
+ args[0] = dashArray.filter(x => typeof x === "number");
+ }
+ break;
+ }
+ case OPS.moveTo:
+ case OPS.lineTo:
+ case OPS.curveTo:
+ case OPS.curveTo2:
+ case OPS.curveTo3:
+ case OPS.closePath:
+ case OPS.rectangle:
+ self.buildPath(fn, args, stateManager.state);
+ continue;
+ case OPS.stroke:
+ case OPS.closeStroke:
+ case OPS.fill:
+ case OPS.eoFill:
+ case OPS.fillStroke:
+ case OPS.eoFillStroke:
+ case OPS.closeFillStroke:
+ case OPS.closeEOFillStroke:
+ case OPS.endPath:
+ {
+ const {
+ state: {
+ pathBuffer,
+ pathMinMax
+ }
+ } = stateManager;
+ if (fn === OPS.closeStroke || fn === OPS.closeFillStroke || fn === OPS.closeEOFillStroke) {
+ pathBuffer.push(DrawOPS.closePath);
+ }
+ if (pathBuffer.length === 0) {
+ operatorList.addOp(OPS.constructPath, [fn, [null], null]);
+ } else {
+ operatorList.addOp(OPS.constructPath, [fn, [new Float32Array(pathBuffer)], pathMinMax.slice()]);
+ pathBuffer.length = 0;
+ pathMinMax.set(BBOX_INIT, 0);
+ }
+ continue;
+ }
+ case OPS.setTextMatrix:
+ operatorList.addOp(fn, [new Float32Array(args)]);
+ continue;
+ case OPS.markPoint:
+ case OPS.markPointProps:
+ case OPS.beginCompat:
+ case OPS.endCompat:
+ continue;
+ case OPS.beginMarkedContentProps:
+ markedContentLevel++;
+ if (!(args[0] instanceof Name)) {
+ warn(`Expected name for beginMarkedContentProps arg0=${args[0]}`);
+ operatorList.addOp(OPS.beginMarkedContentProps, ["OC", null]);
+ continue;
+ }
+ if (args[0].name === "OC") {
+ next(self.parseMarkedContentProps(args[1], resources).then(data => {
+ operatorList.addOp(OPS.beginMarkedContentProps, ["OC", data]);
+ }).catch(reason => {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (self.options.ignoreErrors) {
+ warn(`getOperatorList - ignoring beginMarkedContentProps: "${reason}".`);
+ operatorList.addOp(OPS.beginMarkedContentProps, ["OC", null]);
+ return;
+ }
+ throw reason;
+ }));
+ return;
+ }
+ args = [args[0].name, args[1] instanceof Dict ? args[1].get("MCID") : null];
+ break;
+ case OPS.beginMarkedContent:
+ if (args?.some(arg => arg instanceof Dict)) {
+ warn(`getOperatorList - ignoring operator: ${fn}`);
+ continue;
+ }
+ markedContentLevel++;
+ break;
+ case OPS.endMarkedContent:
+ if (args?.some(arg => arg instanceof Dict)) {
+ warn(`getOperatorList - ignoring operator: ${fn}`);
+ continue;
+ }
+ if (markedContentLevel === 0) {
+ continue;
+ }
+ markedContentLevel--;
+ break;
+ default:
+ if (args?.some(arg => arg instanceof Dict)) {
+ warn(`getOperatorList - ignoring operator: ${fn}`);
+ continue;
+ }
+ }
+ operatorList.addOp(fn, args);
+ }
+ if (stop) {
+ next(deferred);
+ return;
+ }
+ closePendingMarkedContentOPS();
+ closePendingRestoreOPS();
+ resolve();
+ }).catch(reason => {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (this.options.ignoreErrors) {
+ warn(`getOperatorList - ignoring errors during "${task.name}" ` + `task: "${reason}".`);
+ closePendingMarkedContentOPS();
+ closePendingRestoreOPS();
+ return;
+ }
+ throw reason;
+ });
+ }
+ async getTextContent({
+ stream,
+ task,
+ resources,
+ stateManager = null,
+ includeMarkedContent = false,
+ sink,
+ seenStyles = new Set(),
+ viewBox,
+ lang = null,
+ disableNormalization = false,
+ keepWhiteSpace = false,
+ prevRefs = null,
+ intersector = null
+ }) {
+ if (stream.isAsync) {
+ const bytes = await stream.asyncGetBytes();
+ if (bytes) {
+ stream = new Stream(bytes, 0, bytes.length, stream.dict);
+ }
+ }
+ sink ??= textSinkWrapper(null);
+ const objId = stream.dict?.objId;
+ const seenRefs = new RefSet(prevRefs);
+ if (objId) {
+ if (prevRefs?.has(objId)) {
+ throw new Error(`getTextContent - ignoring circular reference: ${objId}`);
+ }
+ seenRefs.put(objId);
+ }
+ resources ||= Dict.empty;
+ stateManager ||= new StateManager(new TextState());
+ let markedContentLevel = 0;
+ let textMarkedContentLevel = null;
+ const textContent = {
+ items: [],
+ styles: Object.create(null),
+ lang
+ };
+ const textContentItem = {
+ initialized: false,
+ str: [],
+ totalWidth: 0,
+ totalHeight: 0,
+ width: 0,
+ height: 0,
+ vertical: false,
+ prevTransform: null,
+ prevTextRise: 0,
+ textAdvanceScale: 0,
+ spaceInFlowMin: 0,
+ spaceInFlowMax: 0,
+ trackingSpaceMin: Infinity,
+ negativeSpaceMax: -Infinity,
+ notASpace: -Infinity,
+ transform: null,
+ fontName: null,
+ hasEOL: false
+ };
+ const twoLastChars = [" ", " "];
+ let twoLastCharsPos = 0;
+ function saveLastChar(char) {
+ const nextPos = (twoLastCharsPos + 1) % 2;
+ const ret = twoLastChars[twoLastCharsPos] !== " " && twoLastChars[nextPos] === " ";
+ twoLastChars[twoLastCharsPos] = char;
+ twoLastCharsPos = nextPos;
+ return !keepWhiteSpace && ret;
+ }
+ function shouldAddWhitepsace() {
+ return !keepWhiteSpace && twoLastChars[twoLastCharsPos] !== " " && twoLastChars[(twoLastCharsPos + 1) % 2] === " ";
+ }
+ function resetLastChars() {
+ twoLastChars[0] = twoLastChars[1] = " ";
+ twoLastCharsPos = 0;
+ }
+ const TRACKING_SPACE_FACTOR = 0.102;
+ const NOT_A_SPACE_FACTOR = 0.03;
+ const NEGATIVE_SPACE_FACTOR = -0.2;
+ const SPACE_IN_FLOW_MIN_FACTOR = 0.102;
+ const SPACE_IN_FLOW_MAX_FACTOR = 0.6;
+ const VERTICAL_SHIFT_RATIO = 0.25;
+ const self = this;
+ const xref = this.xref;
+ const showSpacedTextBuffer = [];
+ let xobjs = null;
+ const emptyXObjectCache = new LocalImageCache();
+ const emptyGStateCache = new LocalGStateCache();
+ const preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
+ let textState, currentTextState;
+ function pushWhitespace({
+ width = 0,
+ height = 0,
+ transform = textContentItem.prevTransform,
+ fontName = textContentItem.fontName
+ }) {
+ intersector?.addExtraChar(" ");
+ textContent.items.push({
+ str: " ",
+ dir: "ltr",
+ width,
+ height,
+ transform,
+ fontName,
+ hasEOL: false
+ });
+ }
+ function getCurrentTextTransform() {
+ const font = textState.font;
+ const tsm = [textState.fontSize * textState.textHScale, 0, 0, textState.fontSize, 0, textState.textRise];
+ if (font.isType3Font && (textState.fontSize <= 1 || font.isCharBBox) && !isArrayEqual(textState.fontMatrix, FONT_IDENTITY_MATRIX)) {
+ const glyphHeight = font.bbox[3] - font.bbox[1];
+ if (glyphHeight > 0) {
+ tsm[3] *= glyphHeight * textState.fontMatrix[3];
+ }
+ }
+ return Util.transform(textState.ctm, Util.transform(textState.textMatrix, tsm));
+ }
+ function ensureTextContentItem() {
+ if (textContentItem.initialized) {
+ return textContentItem;
+ }
+ const {
+ font,
+ loadedName
+ } = textState;
+ if (!seenStyles.has(loadedName)) {
+ seenStyles.add(loadedName);
+ textContent.styles[loadedName] = {
+ fontFamily: font.fallbackName,
+ ascent: font.ascent,
+ descent: font.descent,
+ vertical: font.vertical
+ };
+ if (self.options.fontExtraProperties && font.systemFontInfo) {
+ const style = textContent.styles[loadedName];
+ style.fontSubstitution = font.systemFontInfo.css;
+ style.fontSubstitutionLoadedName = font.systemFontInfo.loadedName;
+ }
+ }
+ textContentItem.fontName = loadedName;
+ const trm = textContentItem.transform = getCurrentTextTransform();
+ if (!font.vertical) {
+ textContentItem.width = textContentItem.totalWidth = 0;
+ textContentItem.height = textContentItem.totalHeight = Math.hypot(trm[2], trm[3]);
+ textContentItem.vertical = false;
+ } else {
+ textContentItem.width = textContentItem.totalWidth = Math.hypot(trm[0], trm[1]);
+ textContentItem.height = textContentItem.totalHeight = 0;
+ textContentItem.vertical = true;
+ }
+ const scaleLineX = Math.hypot(textState.textLineMatrix[0], textState.textLineMatrix[1]);
+ const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]);
+ textContentItem.textAdvanceScale = scaleCtmX * scaleLineX;
+ const {
+ fontSize
+ } = textState;
+ textContentItem.trackingSpaceMin = fontSize * TRACKING_SPACE_FACTOR;
+ textContentItem.notASpace = fontSize * NOT_A_SPACE_FACTOR;
+ textContentItem.negativeSpaceMax = fontSize * NEGATIVE_SPACE_FACTOR;
+ textContentItem.spaceInFlowMin = fontSize * SPACE_IN_FLOW_MIN_FACTOR;
+ textContentItem.spaceInFlowMax = fontSize * SPACE_IN_FLOW_MAX_FACTOR;
+ textContentItem.hasEOL = false;
+ textContentItem.initialized = true;
+ return textContentItem;
+ }
+ function updateAdvanceScale() {
+ if (!textContentItem.initialized) {
+ return;
+ }
+ const scaleLineX = Math.hypot(textState.textLineMatrix[0], textState.textLineMatrix[1]);
+ const scaleCtmX = Math.hypot(textState.ctm[0], textState.ctm[1]);
+ const scaleFactor = scaleCtmX * scaleLineX;
+ if (scaleFactor === textContentItem.textAdvanceScale) {
+ return;
+ }
+ if (!textContentItem.vertical) {
+ textContentItem.totalWidth += textContentItem.width * textContentItem.textAdvanceScale;
+ textContentItem.width = 0;
+ } else {
+ textContentItem.totalHeight += textContentItem.height * textContentItem.textAdvanceScale;
+ textContentItem.height = 0;
+ }
+ textContentItem.textAdvanceScale = scaleFactor;
+ }
+ function runBidiTransform(textChunk) {
+ let text = textChunk.str.join("");
+ if (!disableNormalization) {
+ text = normalizeUnicode(text);
+ }
+ const bidiResult = bidi(text, -1, textChunk.vertical);
+ return {
+ str: bidiResult.str,
+ dir: bidiResult.dir,
+ width: Math.abs(textChunk.totalWidth),
+ height: Math.abs(textChunk.totalHeight),
+ transform: textChunk.transform,
+ fontName: textChunk.fontName,
+ hasEOL: textChunk.hasEOL
+ };
+ }
+ async function handleSetFont(fontName, fontRef) {
+ const translated = await self.loadFont(fontName, fontRef, resources, task, null, null, seenRefs);
+ textState.loadedName = translated.loadedName;
+ textState.font = translated.font;
+ textState.fontMatrix = translated.font.fontMatrix || FONT_IDENTITY_MATRIX;
+ }
+ function applyInverseRotation(x, y, matrix) {
+ const scale = Math.hypot(matrix[0], matrix[1]);
+ return [(matrix[0] * x + matrix[1] * y) / scale, (matrix[2] * x + matrix[3] * y) / scale];
+ }
+ function compareWithLastPosition(glyphWidth) {
+ const currentTransform = getCurrentTextTransform();
+ let posX = currentTransform[4];
+ let posY = currentTransform[5];
+ if (textState.font?.vertical) {
+ if (posX < viewBox[0] || posX > viewBox[2] || posY + glyphWidth < viewBox[1] || posY > viewBox[3]) {
+ return false;
+ }
+ } else if (posX + glyphWidth < viewBox[0] || posX > viewBox[2] || posY < viewBox[1] || posY > viewBox[3]) {
+ return false;
+ }
+ if (!textState.font || !textContentItem.prevTransform) {
+ return true;
+ }
+ let lastPosX = textContentItem.prevTransform[4];
+ let lastPosY = textContentItem.prevTransform[5];
+ if (lastPosX === posX && lastPosY === posY) {
+ return true;
+ }
+ let rotate = -1;
+ if (currentTransform[0] && currentTransform[1] === 0 && currentTransform[2] === 0) {
+ rotate = currentTransform[0] > 0 ? 0 : 180;
+ } else if (currentTransform[1] && currentTransform[0] === 0 && currentTransform[3] === 0) {
+ rotate = currentTransform[1] > 0 ? 90 : 270;
+ }
+ switch (rotate) {
+ case 0:
+ break;
+ case 90:
+ [posX, posY] = [posY, posX];
+ [lastPosX, lastPosY] = [lastPosY, lastPosX];
+ break;
+ case 180:
+ [posX, posY, lastPosX, lastPosY] = [-posX, -posY, -lastPosX, -lastPosY];
+ break;
+ case 270:
+ [posX, posY] = [-posY, -posX];
+ [lastPosX, lastPosY] = [-lastPosY, -lastPosX];
+ break;
+ default:
+ [posX, posY] = applyInverseRotation(posX, posY, currentTransform);
+ [lastPosX, lastPosY] = applyInverseRotation(lastPosX, lastPosY, textContentItem.prevTransform);
+ }
+ if (textState.font.vertical) {
+ const advanceY = (lastPosY - posY) / textContentItem.textAdvanceScale;
+ const advanceX = posX - lastPosX;
+ const textOrientation = Math.sign(textContentItem.height || textContentItem.totalHeight);
+ if (advanceY < textOrientation * textContentItem.negativeSpaceMax) {
+ if (Math.abs(advanceX) > 0.5 * textContentItem.width) {
+ appendEOL();
+ return true;
+ }
+ resetLastChars();
+ flushTextContentItem();
+ return true;
+ }
+ if (Math.abs(advanceX) > textContentItem.width) {
+ appendEOL();
+ return true;
+ }
+ if (advanceY <= textOrientation * textContentItem.notASpace) {
+ resetLastChars();
+ }
+ if (advanceY <= textOrientation * textContentItem.trackingSpaceMin) {
+ if (shouldAddWhitepsace()) {
+ resetLastChars();
+ flushTextContentItem();
+ pushWhitespace({
+ height: Math.abs(advanceY)
+ });
+ } else {
+ textContentItem.height += advanceY;
+ }
+ } else if (!addFakeSpaces(advanceY, textContentItem.prevTransform, textOrientation)) {
+ if (textContentItem.str.length === 0) {
+ resetLastChars();
+ pushWhitespace({
+ height: Math.abs(advanceY)
+ });
+ } else {
+ textContentItem.height += advanceY;
+ }
+ }
+ if (Math.abs(advanceX) > textContentItem.width * VERTICAL_SHIFT_RATIO) {
+ flushTextContentItem();
+ }
+ return true;
+ }
+ const advanceX = (posX - lastPosX) / textContentItem.textAdvanceScale;
+ const advanceY = posY - lastPosY;
+ const textOrientation = Math.sign(textContentItem.width || textContentItem.totalWidth);
+ if (advanceX < textOrientation * textContentItem.negativeSpaceMax) {
+ if (Math.abs(advanceY) > 0.5 * textContentItem.height) {
+ appendEOL();
+ return true;
+ }
+ resetLastChars();
+ flushTextContentItem();
+ return true;
+ }
+ const textRiseDelta = textState.textRise - textContentItem.prevTextRise;
+ const advanceYCorrected = textRiseDelta === 0 ? advanceY : advanceY - currentTransform[3] / textState.fontSize * textRiseDelta;
+ if (Math.abs(advanceYCorrected) > textContentItem.height) {
+ appendEOL();
+ return true;
+ }
+ if (advanceX <= textOrientation * textContentItem.notASpace) {
+ resetLastChars();
+ }
+ if (advanceX <= textOrientation * textContentItem.trackingSpaceMin) {
+ if (shouldAddWhitepsace()) {
+ resetLastChars();
+ flushTextContentItem();
+ pushWhitespace({
+ width: Math.abs(advanceX)
+ });
+ } else {
+ textContentItem.width += advanceX;
+ }
+ } else if (!addFakeSpaces(advanceX, textContentItem.prevTransform, textOrientation)) {
+ if (textContentItem.str.length === 0) {
+ resetLastChars();
+ pushWhitespace({
+ width: Math.abs(advanceX)
+ });
+ } else {
+ textContentItem.width += advanceX;
+ }
+ }
+ if (Math.abs(advanceY) > textContentItem.height * VERTICAL_SHIFT_RATIO) {
+ flushTextContentItem();
+ }
+ return true;
+ }
+ function buildTextContentItem({
+ chars,
+ extraSpacing
+ }) {
+ if (currentTextState !== textState && (currentTextState.fontSize !== textState.fontSize || currentTextState.fontName !== textState.fontName && (currentTextState.font.name !== textState.font.name || currentTextState.font.vertical !== textState.font.vertical))) {
+ flushTextContentItem();
+ currentTextState = textState.clone();
+ }
+ const font = textState.font;
+ const baseCharSpacing = font.vertical ? -textState.charSpacing : textState.charSpacing;
+ if (!chars) {
+ const charSpacing = baseCharSpacing + extraSpacing;
+ if (charSpacing) {
+ if (!font.vertical) {
+ textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
+ } else {
+ textState.translateTextMatrix(0, -charSpacing);
+ }
+ }
+ if (keepWhiteSpace) {
+ compareWithLastPosition(0);
+ }
+ return;
+ }
+ const glyphs = font.charsToGlyphs(chars);
+ const scale = textState.fontMatrix[0] * textState.fontSize;
+ for (let i = 0, ii = glyphs.length; i < ii; i++) {
+ const glyph = glyphs[i];
+ const {
+ category,
+ originalCharCode
+ } = glyph;
+ if (category.isInvisibleFormatMark) {
+ continue;
+ }
+ let charSpacing = baseCharSpacing + (i + 1 === ii ? extraSpacing : 0);
+ let glyphWidth = glyph.width;
+ if (font.vertical) {
+ glyphWidth = glyph.vmetric ? glyph.vmetric[0] : -glyphWidth;
+ }
+ let scaledDim = glyphWidth * scale;
+ if (originalCharCode === 0x20) {
+ charSpacing += textState.wordSpacing;
+ }
+ if (!keepWhiteSpace && category.isWhitespace) {
+ if (!font.vertical) {
+ charSpacing += scaledDim;
+ textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
+ } else {
+ charSpacing += -scaledDim;
+ textState.translateTextMatrix(0, -charSpacing);
+ }
+ saveLastChar(" ");
+ continue;
+ }
+ if (!category.isZeroWidthDiacritic && !compareWithLastPosition(scaledDim)) {
+ if (!font.vertical) {
+ textState.translateTextMatrix(scaledDim * textState.textHScale, 0);
+ } else {
+ textState.translateTextMatrix(0, scaledDim);
+ }
+ continue;
+ }
+ const textChunk = ensureTextContentItem();
+ if (category.isZeroWidthDiacritic) {
+ scaledDim = 0;
+ }
+ if (!font.vertical) {
+ scaledDim *= textState.textHScale;
+ intersector?.addGlyph(getCurrentTextTransform(), scaledDim, 0, glyph.unicode);
+ textState.translateTextMatrix(scaledDim, 0);
+ textChunk.width += scaledDim;
+ } else {
+ intersector?.addGlyph(getCurrentTextTransform(), 0, scaledDim, glyph.unicode);
+ textState.translateTextMatrix(0, scaledDim);
+ scaledDim = Math.abs(scaledDim);
+ textChunk.height += scaledDim;
+ }
+ if (scaledDim) {
+ textChunk.prevTransform = getCurrentTextTransform();
+ textChunk.prevTextRise = textState.textRise;
+ }
+ const glyphUnicode = glyph.unicode;
+ if (saveLastChar(glyphUnicode)) {
+ textChunk.str.push(" ");
+ intersector?.addExtraChar(" ");
+ }
+ if (!intersector) {
+ textChunk.str.push(glyphUnicode);
+ }
+ if (charSpacing) {
+ if (!font.vertical) {
+ textState.translateTextMatrix(charSpacing * textState.textHScale, 0);
+ } else {
+ textState.translateTextMatrix(0, -charSpacing);
+ }
+ }
+ }
+ }
+ function appendEOL() {
+ intersector?.addExtraChar("\n");
+ resetLastChars();
+ if (textContentItem.initialized) {
+ textContentItem.hasEOL = true;
+ flushTextContentItem();
+ } else {
+ textContent.items.push({
+ str: "",
+ dir: "ltr",
+ width: 0,
+ height: 0,
+ transform: getCurrentTextTransform(),
+ fontName: textState.loadedName,
+ hasEOL: true
+ });
+ }
+ }
+ function addFakeSpaces(width, transf, textOrientation) {
+ if (textOrientation * textContentItem.spaceInFlowMin <= width && width <= textOrientation * textContentItem.spaceInFlowMax) {
+ if (textContentItem.initialized) {
+ resetLastChars();
+ textContentItem.str.push(" ");
+ intersector?.addExtraChar(" ");
+ }
+ return false;
+ }
+ const fontName = textContentItem.fontName;
+ let height = 0;
+ if (textContentItem.vertical) {
+ height = width;
+ width = 0;
+ }
+ flushTextContentItem();
+ resetLastChars();
+ pushWhitespace({
+ width: Math.abs(width),
+ height: Math.abs(height),
+ transform: transf || getCurrentTextTransform(),
+ fontName
+ });
+ return true;
+ }
+ function flushTextContentItem() {
+ if (!textContentItem.initialized || !textContentItem.str) {
+ return;
+ }
+ if (!textContentItem.vertical) {
+ textContentItem.totalWidth += textContentItem.width * textContentItem.textAdvanceScale;
+ } else {
+ textContentItem.totalHeight += textContentItem.height * textContentItem.textAdvanceScale;
+ }
+ textContent.items.push(runBidiTransform(textContentItem));
+ textContentItem.initialized = false;
+ textContentItem.str.length = 0;
+ }
+ function closePendingMarkedContentItems(level = 0) {
+ if (!includeMarkedContent || markedContentLevel <= level) {
+ return;
+ }
+ flushTextContentItem();
+ for (; markedContentLevel > level; markedContentLevel--) {
+ textContent.items.push({
+ type: "endMarkedContent"
+ });
+ }
+ }
+ function enqueueChunk(batch = false) {
+ const length = textContent.items.length;
+ if (length === 0) {
+ return;
+ }
+ if (batch && length < TEXT_CHUNK_BATCH_SIZE) {
+ return;
+ }
+ sink.enqueue(textContent, length);
+ textContent.items = [];
+ textContent.styles = Object.create(null);
+ }
+ const timeSlotManager = new TimeSlotManager();
+ return new Promise(function promiseBody(resolve, reject) {
+ const next = function (promise) {
+ enqueueChunk(true);
+ Promise.all([promise, sink.ready]).then(function () {
+ try {
+ promiseBody(resolve, reject);
+ } catch (ex) {
+ reject(ex);
+ }
+ }, reject);
+ };
+ task.ensureNotTerminated();
+ timeSlotManager.reset();
+ const operation = {};
+ let stop,
+ name,
+ isValidName,
+ args = [];
+ while (!(stop = timeSlotManager.check())) {
+ args.length = 0;
+ operation.args = args;
+ if (!preprocessor.read(operation)) {
+ break;
+ }
+ textState = stateManager.state;
+ currentTextState ||= textState.clone();
+ const fn = operation.fn;
+ args = operation.args;
+ switch (fn | 0) {
+ case OPS.setFont:
+ const fontNameArg = args[0].name,
+ fontSizeArg = args[1];
+ if (textState.font && fontNameArg === textState.fontName && fontSizeArg === textState.fontSize) {
+ break;
+ }
+ textState.fontName = fontNameArg;
+ textState.fontSize = fontSizeArg;
+ next(handleSetFont(fontNameArg, null));
+ return;
+ case OPS.setTextRise:
+ textState.textRise = args[0];
+ break;
+ case OPS.setHScale:
+ textState.textHScale = args[0] / 100;
+ break;
+ case OPS.setLeading:
+ textState.leading = args[0];
+ break;
+ case OPS.moveText:
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
+ break;
+ case OPS.setLeadingMoveText:
+ textState.leading = -args[1];
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
+ break;
+ case OPS.nextLine:
+ textState.carriageReturn();
+ break;
+ case OPS.setTextMatrix:
+ textState.setTextMatrix(args[0], args[1], args[2], args[3], args[4], args[5]);
+ textState.setTextLineMatrix(args[0], args[1], args[2], args[3], args[4], args[5]);
+ updateAdvanceScale();
+ break;
+ case OPS.setCharSpacing:
+ textState.charSpacing = args[0];
+ break;
+ case OPS.setWordSpacing:
+ textState.wordSpacing = args[0];
+ break;
+ case OPS.beginText:
+ textState.textMatrix = IDENTITY_MATRIX.slice();
+ textState.textLineMatrix = IDENTITY_MATRIX.slice();
+ textMarkedContentLevel = markedContentLevel;
+ break;
+ case OPS.endText:
+ if (textMarkedContentLevel !== null) {
+ closePendingMarkedContentItems(textMarkedContentLevel);
+ textMarkedContentLevel = null;
+ }
+ break;
+ case OPS.showSpacedText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ const spaceFactor = (textState.font.vertical ? 1 : -1) * textState.fontSize / 1000;
+ for (const item of args[0]) {
+ if (typeof item === "string") {
+ showSpacedTextBuffer.push(item);
+ } else if (typeof item === "number" && item !== 0) {
+ const str = showSpacedTextBuffer.join("");
+ showSpacedTextBuffer.length = 0;
+ buildTextContentItem({
+ chars: str,
+ extraSpacing: item * spaceFactor
+ });
+ }
+ }
+ if (showSpacedTextBuffer.length > 0) {
+ const str = showSpacedTextBuffer.join("");
+ showSpacedTextBuffer.length = 0;
+ buildTextContentItem({
+ chars: str,
+ extraSpacing: 0
+ });
+ }
+ break;
+ case OPS.showText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ buildTextContentItem({
+ chars: args[0],
+ extraSpacing: 0
+ });
+ break;
+ case OPS.nextLineShowText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ textState.carriageReturn();
+ buildTextContentItem({
+ chars: args[0],
+ extraSpacing: 0
+ });
+ break;
+ case OPS.nextLineSetSpacingShowText:
+ if (!stateManager.state.font) {
+ self.ensureStateFont(stateManager.state);
+ continue;
+ }
+ textState.wordSpacing = args[0];
+ textState.charSpacing = args[1];
+ textState.carriageReturn();
+ buildTextContentItem({
+ chars: args[2],
+ extraSpacing: 0
+ });
+ break;
+ case OPS.paintXObject:
+ flushTextContentItem();
+ xobjs ??= resources.get("XObject") || Dict.empty;
+ isValidName = args[0] instanceof Name;
+ name = args[0].name;
+ if (isValidName && emptyXObjectCache.getByName(name)) {
+ break;
+ }
+ next(new Promise(function (resolveXObject, rejectXObject) {
+ if (!isValidName) {
+ throw new FormatError("XObject must be referred to by name.");
+ }
+ let xobj = xobjs.getRaw(name);
+ if (xobj instanceof Ref) {
+ if (emptyXObjectCache.getByRef(xobj)) {
+ resolveXObject();
+ return;
+ }
+ const globalImage = self.globalImageCache.getData(xobj, self.pageIndex);
+ if (globalImage) {
+ resolveXObject();
+ return;
+ }
+ xobj = xref.fetch(xobj);
+ }
+ if (!(xobj instanceof BaseStream)) {
+ throw new FormatError("XObject should be a stream");
+ }
+ const {
+ dict
+ } = xobj;
+ const type = dict.get("Subtype");
+ if (!(type instanceof Name)) {
+ throw new FormatError("XObject should have a Name subtype");
+ }
+ if (type.name !== "Form") {
+ emptyXObjectCache.set(name, dict.objId, true);
+ resolveXObject();
+ return;
+ }
+ const currentState = stateManager.state.clone();
+ const xObjStateManager = new StateManager(currentState);
+ const matrix = lookupMatrix(dict.getArray("Matrix"), null);
+ if (matrix) {
+ xObjStateManager.transform(matrix);
+ }
+ const localResources = dict.get("Resources");
+ enqueueChunk();
+ const sinkWrapper = textSinkWrapper(sink);
+ self.getTextContent({
+ stream: xobj,
+ task,
+ resources: localResources instanceof Dict ? localResources : resources,
+ stateManager: xObjStateManager,
+ includeMarkedContent,
+ sink: sinkWrapper,
+ seenStyles,
+ viewBox,
+ lang,
+ disableNormalization,
+ keepWhiteSpace,
+ prevRefs: seenRefs
+ }).then(function () {
+ if (!sinkWrapper.enqueueInvoked) {
+ emptyXObjectCache.set(name, dict.objId, true);
+ }
+ resolveXObject();
+ }, rejectXObject);
+ }).catch(function (reason) {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (self.options.ignoreErrors) {
+ warn(`getTextContent - ignoring XObject: "${reason}".`);
+ return;
+ }
+ throw reason;
+ }));
+ return;
+ case OPS.setGState:
+ isValidName = args[0] instanceof Name;
+ name = args[0].name;
+ if (isValidName && emptyGStateCache.getByName(name)) {
+ break;
+ }
+ next(new Promise(function (resolveGState, rejectGState) {
+ if (!isValidName) {
+ throw new FormatError("GState must be referred to by name.");
+ }
+ const extGState = resources.get("ExtGState");
+ if (!(extGState instanceof Dict)) {
+ throw new FormatError("ExtGState should be a dictionary.");
+ }
+ const gState = extGState.get(name);
+ if (!(gState instanceof Dict)) {
+ throw new FormatError("GState should be a dictionary.");
+ }
+ const gStateFont = gState.get("Font");
+ if (!gStateFont) {
+ emptyGStateCache.set(name, gState.objId, true);
+ resolveGState();
+ return;
+ }
+ flushTextContentItem();
+ textState.fontName = null;
+ textState.fontSize = gStateFont[1];
+ handleSetFont(null, gStateFont[0]).then(resolveGState, rejectGState);
+ }).catch(function (reason) {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (self.options.ignoreErrors) {
+ warn(`getTextContent - ignoring ExtGState: "${reason}".`);
+ return;
+ }
+ throw reason;
+ }));
+ return;
+ case OPS.beginMarkedContent:
+ flushTextContentItem();
+ if (includeMarkedContent) {
+ markedContentLevel++;
+ textContent.items.push({
+ type: "beginMarkedContent",
+ tag: args[0] instanceof Name ? args[0].name : null
+ });
+ }
+ break;
+ case OPS.beginMarkedContentProps:
+ flushTextContentItem();
+ if (includeMarkedContent) {
+ markedContentLevel++;
+ const mcid = args[1] instanceof Dict ? args[1].get("MCID") : null;
+ textContent.items.push({
+ type: "beginMarkedContentProps",
+ id: Number.isInteger(mcid) ? `${self.idFactory.getPageObjId()}_mc${mcid}` : null,
+ tag: args[0] instanceof Name ? args[0].name : null
+ });
+ }
+ break;
+ case OPS.endMarkedContent:
+ flushTextContentItem();
+ if (includeMarkedContent) {
+ if (markedContentLevel === 0) {
+ break;
+ }
+ markedContentLevel--;
+ textContent.items.push({
+ type: "endMarkedContent"
+ });
+ }
+ break;
+ }
+ if (textContent.items.length >= sink.desiredSize) {
+ stop = true;
+ break;
+ }
+ }
+ if (stop) {
+ next(deferred);
+ return;
+ }
+ flushTextContentItem();
+ closePendingMarkedContentItems();
+ enqueueChunk();
+ resolve();
+ }).catch(reason => {
+ if (reason instanceof AbortException) {
+ return;
+ }
+ if (this.options.ignoreErrors) {
+ warn(`getTextContent - ignoring errors during "${task.name}" ` + `task: "${reason}".`);
+ flushTextContentItem();
+ closePendingMarkedContentItems();
+ enqueueChunk();
+ return;
+ }
+ throw reason;
+ });
+ }
+ async extractDataStructures(dict, properties) {
+ const xref = this.xref;
+ let cidToGidBytes;
+ const toUnicodePromise = this.readToUnicode(properties.toUnicode);
+ if (properties.composite) {
+ const cidSystemInfo = dict.get("CIDSystemInfo");
+ if (cidSystemInfo instanceof Dict && !properties.cidSystemInfo) {
+ properties.cidSystemInfo = {
+ registry: stringToPDFString(cidSystemInfo.get("Registry")),
+ ordering: stringToPDFString(cidSystemInfo.get("Ordering")),
+ supplement: cidSystemInfo.get("Supplement")
+ };
+ }
+ try {
+ const cidToGidMap = dict.get("CIDToGIDMap");
+ if (cidToGidMap instanceof BaseStream) {
+ cidToGidBytes = cidToGidMap.getBytes();
+ }
+ } catch (ex) {
+ if (!this.options.ignoreErrors) {
+ throw ex;
+ }
+ warn(`extractDataStructures - ignoring CIDToGIDMap data: "${ex}".`);
+ }
+ }
+ const differences = [];
+ let baseEncodingName = null;
+ let encoding;
+ if (dict.has("Encoding")) {
+ encoding = dict.get("Encoding");
+ if (encoding instanceof Dict) {
+ baseEncodingName = encoding.get("BaseEncoding");
+ baseEncodingName = baseEncodingName instanceof Name ? baseEncodingName.name : null;
+ if (encoding.has("Differences")) {
+ const diffEncoding = encoding.get("Differences");
+ let index = 0;
+ for (const entry of diffEncoding) {
+ const data = xref.fetchIfRef(entry);
+ if (typeof data === "number") {
+ index = data;
+ } else if (data instanceof Name) {
+ differences[index++] = data.name;
+ } else {
+ throw new FormatError(`Invalid entry in 'Differences' array: ${data}`);
+ }
+ }
+ }
+ } else if (encoding instanceof Name) {
+ baseEncodingName = encoding.name;
+ } else {
+ const msg = "Encoding is not a Name nor a Dict";
+ if (!this.options.ignoreErrors) {
+ throw new FormatError(msg);
+ }
+ warn(msg);
+ }
+ if (baseEncodingName !== "MacRomanEncoding" && baseEncodingName !== "MacExpertEncoding" && baseEncodingName !== "WinAnsiEncoding") {
+ baseEncodingName = null;
+ }
+ }
+ const nonEmbeddedFont = !properties.file || properties.isInternalFont,
+ isSymbolsFontName = getSymbolsFonts()[properties.name];
+ if (baseEncodingName && nonEmbeddedFont && isSymbolsFontName) {
+ baseEncodingName = null;
+ }
+ if (baseEncodingName === "WinAnsiEncoding" && nonEmbeddedFont && properties.name?.charCodeAt(0) >= 0xb7) {
+ const fontName = properties.name;
+ const chineseFontNames = ["\xCB\xCE\xCC\xE5", "\xBA\xDA\xCC\xE5", "\xBF\xAC\xCC\xE5", "\xB7\xC2\xCB\xCE", "\xBF\xAC\xCC\xE5_GB2312", "\xB7\xC2\xCB\xCE_GB2312", "\xC1\xA5\xCA\xE9", "\xD0\xC2\xCB\xCE", "\xB7\xC2\xCB\xCE\xCC\xE5", "\xD0\xA1\xB1\xEA\xCB\xCE"];
+ if (chineseFontNames.includes(fontName)) {
+ baseEncodingName = null;
+ properties.defaultEncoding = "Adobe-GB1-UCS2";
+ properties.composite = true;
+ properties.cidEncoding = Name.get("GBK-EUC-H");
+ const cMap = await CMapFactory.create({
+ encoding: properties.cidEncoding,
+ fetchBuiltInCMap: this._fetchBuiltInCMapBound,
+ useCMap: null
+ });
+ properties.cMap = cMap;
+ properties.vertical = properties.cMap.vertical;
+ properties.cidSystemInfo = {
+ registry: "Adobe",
+ ordering: "GB1",
+ supplement: 0
+ };
+ }
+ }
+ if (baseEncodingName) {
+ properties.defaultEncoding = getEncoding(baseEncodingName);
+ } else {
+ let isSymbolicFont = !!(properties.flags & FontFlags.Symbolic);
+ const isNonsymbolicFont = !!(properties.flags & FontFlags.Nonsymbolic);
+ if (properties.type === "TrueType" && isSymbolicFont && isNonsymbolicFont && differences.length !== 0) {
+ properties.flags &= ~FontFlags.Symbolic;
+ isSymbolicFont = false;
+ }
+ encoding = StandardEncoding;
+ if (properties.type === "TrueType" && !isNonsymbolicFont) {
+ encoding = WinAnsiEncoding;
+ }
+ if (isSymbolicFont || isSymbolsFontName) {
+ encoding = MacRomanEncoding;
+ if (nonEmbeddedFont) {
+ if (/Symbol/i.test(properties.name)) {
+ encoding = SymbolSetEncoding;
+ } else if (/Dingbats/i.test(properties.name)) {
+ encoding = ZapfDingbatsEncoding;
+ } else if (/Wingdings/i.test(properties.name)) {
+ encoding = WinAnsiEncoding;
+ }
+ }
+ }
+ properties.defaultEncoding = encoding;
+ }
+ properties.differences = differences;
+ properties.baseEncodingName = baseEncodingName;
+ properties.hasEncoding = !!baseEncodingName || differences.length > 0;
+ properties.dict = dict;
+ properties.toUnicode = await toUnicodePromise;
+ const builtToUnicode = await this.buildToUnicode(properties);
+ properties.toUnicode = builtToUnicode;
+ if (cidToGidBytes) {
+ properties.cidToGidMap = this.readCidToGidMap(cidToGidBytes, builtToUnicode);
+ }
+ return properties;
+ }
+ _simpleFontToUnicode(properties, forceGlyphs = false) {
+ assert(!properties.composite, "Must be a simple font.");
+ const toUnicode = [];
+ const encoding = properties.defaultEncoding.slice();
+ const baseEncodingName = properties.baseEncodingName;
+ const differences = properties.differences;
+ for (const charcode in differences) {
+ const glyphName = differences[charcode];
+ if (glyphName === ".notdef") {
+ continue;
+ }
+ encoding[charcode] = glyphName;
+ }
+ const glyphsUnicodeMap = getGlyphsUnicode();
+ for (const charcode in encoding) {
+ let glyphName = encoding[charcode];
+ if (glyphName === "") {
+ continue;
+ }
+ let unicode = glyphsUnicodeMap[glyphName];
+ if (unicode !== undefined) {
+ toUnicode[charcode] = String.fromCharCode(unicode);
+ continue;
+ }
+ let code = 0;
+ switch (glyphName[0]) {
+ case "G":
+ if (glyphName.length === 3) {
+ code = parseInt(glyphName.substring(1), 16);
+ }
+ break;
+ case "g":
+ if (glyphName.length === 5) {
+ code = parseInt(glyphName.substring(1), 16);
+ }
+ break;
+ case "C":
+ case "c":
+ if (glyphName.length >= 3 && glyphName.length <= 4) {
+ const codeStr = glyphName.substring(1);
+ if (forceGlyphs) {
+ code = parseInt(codeStr, 16);
+ break;
+ }
+ code = +codeStr;
+ if (Number.isNaN(code) && Number.isInteger(parseInt(codeStr, 16))) {
+ return this._simpleFontToUnicode(properties, true);
+ }
+ }
+ break;
+ case "u":
+ unicode = getUnicodeForGlyph(glyphName, glyphsUnicodeMap);
+ if (unicode !== -1) {
+ code = unicode;
+ }
+ break;
+ default:
+ switch (glyphName) {
+ case "f_h":
+ case "f_t":
+ case "T_h":
+ toUnicode[charcode] = glyphName.replaceAll("_", "");
+ continue;
+ }
+ break;
+ }
+ if (code > 0 && code <= 0x10ffff && Number.isInteger(code)) {
+ if (baseEncodingName && code === +charcode) {
+ const baseEncoding = getEncoding(baseEncodingName);
+ if (baseEncoding && (glyphName = baseEncoding[charcode])) {
+ toUnicode[charcode] = String.fromCharCode(glyphsUnicodeMap[glyphName]);
+ continue;
+ }
+ }
+ toUnicode[charcode] = String.fromCodePoint(code);
+ }
+ }
+ return toUnicode;
+ }
+ async buildToUnicode(properties) {
+ properties.hasIncludedToUnicodeMap = properties.toUnicode?.length > 0;
+ if (properties.hasIncludedToUnicodeMap) {
+ if (!properties.composite && properties.hasEncoding) {
+ properties.fallbackToUnicode = this._simpleFontToUnicode(properties);
+ }
+ return properties.toUnicode;
+ }
+ if (!properties.composite) {
+ return new ToUnicodeMap(this._simpleFontToUnicode(properties));
+ }
+ if (properties.composite && (properties.cMap.builtInCMap && !(properties.cMap instanceof IdentityCMap) || properties.cidSystemInfo?.registry === "Adobe" && (properties.cidSystemInfo.ordering === "GB1" || properties.cidSystemInfo.ordering === "CNS1" || properties.cidSystemInfo.ordering === "Japan1" || properties.cidSystemInfo.ordering === "Korea1"))) {
+ const {
+ registry,
+ ordering
+ } = properties.cidSystemInfo;
+ const ucs2CMapName = Name.get(`${registry}-${ordering}-UCS2`);
+ const ucs2CMap = await CMapFactory.create({
+ encoding: ucs2CMapName,
+ fetchBuiltInCMap: this._fetchBuiltInCMapBound,
+ useCMap: null
+ });
+ const toUnicode = [],
+ buf = [];
+ properties.cMap.forEach(function (charcode, cid) {
+ if (cid > 0xffff) {
+ throw new FormatError("Max size of CID is 65,535");
+ }
+ const ucs2 = ucs2CMap.lookup(cid);
+ if (ucs2) {
+ buf.length = 0;
+ for (let i = 0, ii = ucs2.length; i < ii; i += 2) {
+ buf.push((ucs2.charCodeAt(i) << 8) + ucs2.charCodeAt(i + 1));
+ }
+ toUnicode[charcode] = String.fromCharCode(...buf);
+ }
+ });
+ return new ToUnicodeMap(toUnicode);
+ }
+ return new IdentityToUnicodeMap(properties.firstChar, properties.lastChar);
+ }
+ async readToUnicode(cmapObj) {
+ if (!cmapObj) {
+ return null;
+ }
+ if (cmapObj instanceof Name) {
+ const cmap = await CMapFactory.create({
+ encoding: cmapObj,
+ fetchBuiltInCMap: this._fetchBuiltInCMapBound,
+ useCMap: null
+ });
+ if (cmap instanceof IdentityCMap) {
+ return new IdentityToUnicodeMap(0, 0xffff);
+ }
+ return new ToUnicodeMap(cmap.getMap());
+ }
+ if (cmapObj instanceof BaseStream) {
+ try {
+ const cmap = await CMapFactory.create({
+ encoding: cmapObj,
+ fetchBuiltInCMap: this._fetchBuiltInCMapBound,
+ useCMap: null
+ });
+ if (cmap instanceof IdentityCMap) {
+ return new IdentityToUnicodeMap(0, 0xffff);
+ }
+ const map = new Array(cmap.length);
+ cmap.forEach(function (charCode, token) {
+ if (typeof token === "number") {
+ map[charCode] = String.fromCodePoint(token);
+ return;
+ }
+ if (token.length % 2 !== 0) {
+ token = "\u0000" + token;
+ }
+ const str = [];
+ for (let k = 0; k < token.length; k += 2) {
+ const w1 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1);
+ if ((w1 & 0xf800) !== 0xd800) {
+ str.push(w1);
+ continue;
+ }
+ k += 2;
+ const w2 = token.charCodeAt(k) << 8 | token.charCodeAt(k + 1);
+ str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000);
+ }
+ map[charCode] = String.fromCodePoint(...str);
+ });
+ return new ToUnicodeMap(map);
+ } catch (reason) {
+ if (reason instanceof AbortException) {
+ return null;
+ }
+ if (this.options.ignoreErrors) {
+ warn(`readToUnicode - ignoring ToUnicode data: "${reason}".`);
+ return null;
+ }
+ throw reason;
+ }
+ }
+ return null;
+ }
+ readCidToGidMap(glyphsData, toUnicode) {
+ const result = [];
+ for (let j = 0, jj = glyphsData.length; j < jj; j++) {
+ const glyphID = glyphsData[j++] << 8 | glyphsData[j];
+ const code = j >> 1;
+ if (glyphID === 0 && !toUnicode.has(code)) {
+ continue;
+ }
+ result[code] = glyphID;
+ }
+ return result;
+ }
+ extractWidths(dict, descriptor, properties) {
+ const xref = this.xref;
+ let glyphsWidths = [];
+ let defaultWidth = 0;
+ const glyphsVMetrics = [];
+ let defaultVMetrics;
+ if (properties.composite) {
+ const dw = dict.get("DW");
+ defaultWidth = typeof dw === "number" ? Math.ceil(dw) : 1000;
+ const widths = dict.get("W");
+ if (Array.isArray(widths)) {
+ for (let i = 0, ii = widths.length; i < ii; i++) {
+ let start = xref.fetchIfRef(widths[i++]);
+ if (!Number.isInteger(start)) {
+ break;
+ }
+ const code = xref.fetchIfRef(widths[i]);
+ if (Array.isArray(code)) {
+ for (const c of code) {
+ const width = xref.fetchIfRef(c);
+ if (typeof width === "number") {
+ glyphsWidths[start] = width;
+ }
+ start++;
+ }
+ } else if (Number.isInteger(code)) {
+ const width = xref.fetchIfRef(widths[++i]);
+ if (typeof width !== "number") {
+ continue;
+ }
+ for (let j = start; j <= code; j++) {
+ glyphsWidths[j] = width;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ if (properties.vertical) {
+ const dw2 = dict.getArray("DW2");
+ let vmetrics = isNumberArray(dw2, 2) ? dw2 : [880, -1000];
+ defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
+ vmetrics = dict.get("W2");
+ if (Array.isArray(vmetrics)) {
+ for (let i = 0, ii = vmetrics.length; i < ii; i++) {
+ let start = xref.fetchIfRef(vmetrics[i++]);
+ if (!Number.isInteger(start)) {
+ break;
+ }
+ const code = xref.fetchIfRef(vmetrics[i]);
+ if (Array.isArray(code)) {
+ for (let j = 0, jj = code.length; j < jj; j++) {
+ const vmetric = [xref.fetchIfRef(code[j++]), xref.fetchIfRef(code[j++]), xref.fetchIfRef(code[j])];
+ if (isNumberArray(vmetric, null)) {
+ glyphsVMetrics[start] = vmetric;
+ }
+ start++;
+ }
+ } else if (Number.isInteger(code)) {
+ const vmetric = [xref.fetchIfRef(vmetrics[++i]), xref.fetchIfRef(vmetrics[++i]), xref.fetchIfRef(vmetrics[++i])];
+ if (!isNumberArray(vmetric, null)) {
+ continue;
+ }
+ for (let j = start; j <= code; j++) {
+ glyphsVMetrics[j] = vmetric;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ const widths = dict.get("Widths");
+ if (Array.isArray(widths)) {
+ let j = properties.firstChar;
+ for (const w of widths) {
+ const width = xref.fetchIfRef(w);
+ if (typeof width === "number") {
+ glyphsWidths[j] = width;
+ }
+ j++;
+ }
+ const missingWidth = descriptor.get("MissingWidth");
+ defaultWidth = typeof missingWidth === "number" ? missingWidth : 0;
+ } else {
+ const baseFontName = dict.get("BaseFont");
+ if (baseFontName instanceof Name) {
+ const metrics = this.getBaseFontMetrics(baseFontName.name);
+ glyphsWidths = this.buildCharCodeToWidth(metrics.widths, properties);
+ defaultWidth = metrics.defaultWidth;
+ }
+ }
+ }
+ let isMonospace = true;
+ let firstWidth = defaultWidth;
+ for (const glyph in glyphsWidths) {
+ const glyphWidth = glyphsWidths[glyph];
+ if (!glyphWidth) {
+ continue;
+ }
+ if (!firstWidth) {
+ firstWidth = glyphWidth;
+ continue;
+ }
+ if (firstWidth !== glyphWidth) {
+ isMonospace = false;
+ break;
+ }
+ }
+ if (isMonospace) {
+ properties.flags |= FontFlags.FixedPitch;
+ } else {
+ properties.flags &= ~FontFlags.FixedPitch;
+ }
+ properties.defaultWidth = defaultWidth;
+ properties.widths = glyphsWidths;
+ properties.defaultVMetrics = defaultVMetrics;
+ properties.vmetrics = glyphsVMetrics;
+ }
+ isSerifFont(baseFontName) {
+ const fontNameWoStyle = baseFontName.split("-", 1)[0];
+ return fontNameWoStyle in getSerifFonts() || /serif/i.test(fontNameWoStyle);
+ }
+ getBaseFontMetrics(name) {
+ let defaultWidth = 0;
+ let widths = Object.create(null);
+ let monospace = false;
+ let fontName = normalizeFontName(name);
+ const stdFontMap = getStdFontMap();
+ fontName = stdFontMap[fontName] || fontName;
+ const Metrics = getMetrics();
+ const glyphWidths = Metrics[fontName] ?? Metrics[this.isSerifFont(name) ? "Times-Roman" : "Helvetica"];
+ if (typeof glyphWidths === "number") {
+ defaultWidth = glyphWidths;
+ monospace = true;
+ } else {
+ widths = glyphWidths();
+ }
+ return {
+ defaultWidth,
+ monospace,
+ widths
+ };
+ }
+ buildCharCodeToWidth(widthsByGlyphName, properties) {
+ const widths = Object.create(null);
+ const differences = properties.differences;
+ const encoding = properties.defaultEncoding;
+ for (let charCode = 0; charCode < 256; charCode++) {
+ if (charCode in differences && widthsByGlyphName[differences[charCode]]) {
+ widths[charCode] = widthsByGlyphName[differences[charCode]];
+ continue;
+ }
+ if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) {
+ widths[charCode] = widthsByGlyphName[encoding[charCode]];
+ continue;
+ }
+ }
+ return widths;
+ }
+ preEvaluateFont(dict) {
+ const baseDict = dict;
+ let type = dict.get("Subtype");
+ if (!(type instanceof Name)) {
+ throw new FormatError("invalid font Subtype");
+ }
+ let composite = false;
+ let hash;
+ if (type.name === "Type0") {
+ const df = dict.get("DescendantFonts");
+ if (!df) {
+ throw new FormatError("Descendant fonts are not specified");
+ }
+ dict = Array.isArray(df) ? this.xref.fetchIfRef(df[0]) : df;
+ if (!(dict instanceof Dict)) {
+ throw new FormatError("Descendant font is not a dictionary.");
+ }
+ type = dict.get("Subtype");
+ if (!(type instanceof Name)) {
+ throw new FormatError("invalid font Subtype");
+ }
+ composite = true;
+ }
+ let firstChar = dict.get("FirstChar");
+ if (!Number.isInteger(firstChar)) {
+ firstChar = 0;
+ }
+ let lastChar = dict.get("LastChar");
+ if (!Number.isInteger(lastChar)) {
+ lastChar = composite ? 0xffff : 0xff;
+ }
+ const descriptor = dict.get("FontDescriptor");
+ const toUnicode = dict.get("ToUnicode") || baseDict.get("ToUnicode");
+ if (descriptor) {
+ hash = new MurmurHash3_64();
+ const encoding = baseDict.getRaw("Encoding");
+ if (encoding instanceof Name) {
+ hash.update(encoding.name);
+ } else if (encoding instanceof Ref) {
+ hash.update(encoding.toString());
+ } else if (encoding instanceof Dict) {
+ for (const entry of encoding.getRawValues()) {
+ if (entry instanceof Name) {
+ hash.update(entry.name);
+ } else if (entry instanceof Ref) {
+ hash.update(entry.toString());
+ } else if (Array.isArray(entry)) {
+ const diffLength = entry.length,
+ diffBuf = new Array(diffLength);
+ for (let j = 0; j < diffLength; j++) {
+ const diffEntry = entry[j];
+ if (diffEntry instanceof Name) {
+ diffBuf[j] = diffEntry.name;
+ } else if (typeof diffEntry === "number" || diffEntry instanceof Ref) {
+ diffBuf[j] = diffEntry.toString();
+ }
+ }
+ hash.update(diffBuf.join());
+ }
+ }
+ }
+ hash.update(`${firstChar}-${lastChar}`);
+ if (toUnicode instanceof BaseStream) {
+ const stream = toUnicode.stream || toUnicode;
+ const uint8array = stream.buffer ? new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) : new Uint8Array(stream.bytes.buffer, stream.start, stream.end - stream.start);
+ hash.update(uint8array);
+ } else if (toUnicode instanceof Name) {
+ hash.update(toUnicode.name);
+ }
+ const widths = dict.get("Widths") || baseDict.get("Widths");
+ if (Array.isArray(widths)) {
+ const widthsBuf = [];
+ for (const entry of widths) {
+ if (typeof entry === "number" || entry instanceof Ref) {
+ widthsBuf.push(entry.toString());
+ }
+ }
+ hash.update(widthsBuf.join());
+ }
+ if (composite) {
+ hash.update("compositeFont");
+ const compositeWidths = dict.get("W") || baseDict.get("W");
+ if (Array.isArray(compositeWidths)) {
+ const widthsBuf = [];
+ for (const entry of compositeWidths) {
+ if (typeof entry === "number" || entry instanceof Ref) {
+ widthsBuf.push(entry.toString());
+ } else if (Array.isArray(entry)) {
+ const subWidthsBuf = [];
+ for (const element of entry) {
+ if (typeof element === "number" || element instanceof Ref) {
+ subWidthsBuf.push(element.toString());
+ }
+ }
+ widthsBuf.push(`[${subWidthsBuf.join()}]`);
+ }
+ }
+ hash.update(widthsBuf.join());
+ }
+ const cidToGidMap = dict.getRaw("CIDToGIDMap") || baseDict.getRaw("CIDToGIDMap");
+ if (cidToGidMap instanceof Name) {
+ hash.update(cidToGidMap.name);
+ } else if (cidToGidMap instanceof Ref) {
+ hash.update(cidToGidMap.toString());
+ } else if (cidToGidMap instanceof BaseStream) {
+ hash.update(cidToGidMap.peekBytes());
+ }
+ }
+ if (type.name === "Type3") {
+ const charProcs = baseDict.get("CharProcs");
+ if (charProcs instanceof Dict) {
+ for (const [key, entry] of charProcs.getRawEntries()) {
+ hash.update(entry instanceof Ref ? `${key}\0${entry}` : key);
+ }
+ }
+ }
+ }
+ return {
+ descriptor,
+ dict,
+ baseDict,
+ composite,
+ type: type.name,
+ firstChar,
+ lastChar,
+ toUnicode,
+ hash: hash ? hash.hexdigest() : ""
+ };
+ }
+ async translateFont({
+ descriptor,
+ dict,
+ baseDict,
+ composite,
+ type,
+ firstChar,
+ lastChar,
+ toUnicode,
+ cssFontInfo
+ }) {
+ const isType3Font = type === "Type3";
+ if (!descriptor) {
+ if (isType3Font) {
+ descriptor = Dict.empty;
+ } else if (composite) {
+ descriptor = Dict.empty;
+ } else {
+ let baseFontName = dict.get("BaseFont");
+ if (!(baseFontName instanceof Name)) {
+ throw new FormatError("Base font is not specified");
+ }
+ baseFontName = normalizeFontName(baseFontName.name);
+ const metrics = this.getBaseFontMetrics(baseFontName);
+ const fontNameWoStyle = baseFontName.split("-", 1)[0];
+ const flags = (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) | (metrics.monospace ? FontFlags.FixedPitch : 0) | (getSymbolsFonts()[fontNameWoStyle] ? FontFlags.Symbolic : FontFlags.Nonsymbolic);
+ const properties = {
+ type,
+ name: baseFontName,
+ loadedName: baseDict.loadedName,
+ systemFontInfo: null,
+ widths: metrics.widths,
+ defaultWidth: metrics.defaultWidth,
+ isSimulatedFlags: true,
+ flags,
+ firstChar,
+ lastChar,
+ toUnicode,
+ xHeight: 0,
+ capHeight: 0,
+ italicAngle: 0,
+ isType3Font
+ };
+ const widths = dict.get("Widths");
+ const standardFontName = getStandardFontName(baseFontName);
+ let file = null;
+ if (standardFontName) {
+ file = await this.fetchStandardFontData(standardFontName);
+ properties.isInternalFont = !!file;
+ }
+ if (!properties.isInternalFont && this.options.useSystemFonts) {
+ properties.systemFontInfo = getFontSubstitution(this.systemFontCache, this.idFactory, this.options.standardFontDataUrl, baseFontName, standardFontName, type);
+ }
+ const newProperties = await this.extractDataStructures(dict, properties);
+ if (Array.isArray(widths)) {
+ const glyphWidths = [];
+ let j = firstChar;
+ for (const w of widths) {
+ const width = this.xref.fetchIfRef(w);
+ if (typeof width === "number") {
+ glyphWidths[j] = width;
+ }
+ j++;
+ }
+ newProperties.widths = glyphWidths;
+ } else {
+ newProperties.widths = this.buildCharCodeToWidth(metrics.widths, newProperties);
+ }
+ return new Font(baseFontName, file, newProperties, this.options);
+ }
+ }
+ let fontName = descriptor.get("FontName");
+ let baseFont = dict.get("BaseFont");
+ if (typeof fontName === "string") {
+ fontName = Name.get(fontName);
+ }
+ if (typeof baseFont === "string") {
+ baseFont = Name.get(baseFont);
+ }
+ const fontNameStr = fontName?.name;
+ const baseFontStr = baseFont?.name;
+ if (isType3Font) {
+ if (!fontNameStr) {
+ fontName = Name.get(type);
+ }
+ } else if (fontNameStr !== baseFontStr) {
+ info(`The FontDescriptor's FontName is "${fontNameStr}" but ` + `should be the same as the Font's BaseFont "${baseFontStr}".`);
+ if (fontNameStr && baseFontStr && (baseFontStr.startsWith(fontNameStr) || !isKnownFontName(fontNameStr) && isKnownFontName(baseFontStr))) {
+ fontName = null;
+ }
+ fontName ||= baseFont;
+ }
+ if (!(fontName instanceof Name)) {
+ throw new FormatError("invalid font name");
+ }
+ let fontFile, fontFileN, subtype, length1, length2, length3;
+ try {
+ for (const n of ["FontFile", "FontFile2", "FontFile3"]) {
+ fontFile = descriptor.get(n);
+ if (fontFile) {
+ fontFileN = n;
+ break;
+ }
+ }
+ if (fontFile) {
+ if (!(fontFile instanceof BaseStream)) {
+ throw new FormatError("FontFile should be a stream");
+ } else {
+ if (fontFile.isAsync) {
+ const bytes = await fontFile.asyncGetBytes();
+ if (bytes) {
+ fontFile = new Stream(bytes, 0, bytes.length, fontFile.dict);
+ }
+ }
+ if (fontFile.isEmpty) {
+ throw new FormatError("FontFile is empty");
+ }
+ }
+ }
+ } catch (ex) {
+ if (!this.options.ignoreErrors) {
+ throw ex;
+ }
+ warn(`translateFont - fetching "${fontName.name}" font file: "${ex}".`);
+ fontFile = null;
+ }
+ let isInternalFont = false;
+ let glyphScaleFactors = null;
+ let systemFontInfo = null;
+ if (fontFile) {
+ if (fontFile.dict) {
+ const subtypeEntry = fontFile.dict.get("Subtype");
+ if (subtypeEntry instanceof Name) {
+ subtype = subtypeEntry.name;
+ }
+ length1 = fontFile.dict.get("Length1");
+ length2 = fontFile.dict.get("Length2");
+ length3 = fontFile.dict.get("Length3");
+ }
+ } else if (cssFontInfo) {
+ const standardFontName = getXfaFontName(fontName.name);
+ if (standardFontName) {
+ cssFontInfo.fontFamily = `${cssFontInfo.fontFamily}-PdfJS-XFA`;
+ cssFontInfo.metrics = standardFontName.metrics || null;
+ glyphScaleFactors = standardFontName.factors || null;
+ fontFile = await this.fetchStandardFontData(standardFontName.name);
+ isInternalFont = !!fontFile;
+ baseDict = dict = getXfaFontDict(fontName.name);
+ composite = true;
+ }
+ } else if (!isType3Font) {
+ const standardFontName = getStandardFontName(fontName.name);
+ if (standardFontName) {
+ fontFile = await this.fetchStandardFontData(standardFontName);
+ isInternalFont = !!fontFile;
+ }
+ if (!isInternalFont && this.options.useSystemFonts) {
+ systemFontInfo = getFontSubstitution(this.systemFontCache, this.idFactory, this.options.standardFontDataUrl, fontName.name, standardFontName, type);
+ }
+ }
+ const fontMatrix = lookupMatrix(dict.getArray("FontMatrix"), FONT_IDENTITY_MATRIX);
+ const bbox = lookupNormalRect(descriptor.getArray("FontBBox") || dict.getArray("FontBBox"), isType3Font ? [0, 0, 0, 0] : undefined);
+ let ascent = descriptor.get("Ascent");
+ if (typeof ascent !== "number") {
+ ascent = undefined;
+ }
+ let descent = descriptor.get("Descent");
+ if (typeof descent !== "number") {
+ descent = undefined;
+ }
+ let xHeight = descriptor.get("XHeight");
+ if (typeof xHeight !== "number") {
+ xHeight = 0;
+ }
+ let capHeight = descriptor.get("CapHeight");
+ if (typeof capHeight !== "number") {
+ capHeight = 0;
+ }
+ let flags = descriptor.get("Flags");
+ if (!Number.isInteger(flags)) {
+ flags = 0;
+ }
+ let italicAngle = descriptor.get("ItalicAngle");
+ if (typeof italicAngle !== "number") {
+ italicAngle = 0;
+ }
+ const properties = {
+ type,
+ name: fontName.name,
+ subtype,
+ file: fontFile,
+ fontFileN,
+ length1,
+ length2,
+ length3,
+ isInternalFont,
+ loadedName: baseDict.loadedName,
+ composite,
+ fixedPitch: false,
+ fontMatrix,
+ firstChar,
+ lastChar,
+ toUnicode,
+ bbox,
+ ascent,
+ descent,
+ xHeight,
+ capHeight,
+ flags,
+ italicAngle,
+ isType3Font,
+ cssFontInfo,
+ scaleFactors: glyphScaleFactors,
+ systemFontInfo
+ };
+ if (composite) {
+ const cidEncoding = baseDict.get("Encoding");
+ if (cidEncoding instanceof Name) {
+ properties.cidEncoding = cidEncoding.name;
+ }
+ const cMap = await CMapFactory.create({
+ encoding: cidEncoding,
+ fetchBuiltInCMap: this._fetchBuiltInCMapBound,
+ useCMap: null
+ });
+ properties.cMap = cMap;
+ properties.vertical = properties.cMap.vertical;
+ }
+ const newProperties = await this.extractDataStructures(dict, properties);
+ this.extractWidths(dict, descriptor, newProperties);
+ const font = new Font(fontName.name, fontFile, newProperties, this.options);
+ if (font.missingFile && !font.systemFontInfo && !isType3Font && this.options.useSystemFonts) {
+ const standardFontName = getStandardFontName(fontName.name);
+ const substitution = getFontSubstitution(this.systemFontCache, this.idFactory, this.options.standardFontDataUrl, fontName.name, standardFontName, type);
+ if (substitution) {
+ if (substitution.guessFallback) {
+ substitution.guessFallback = false;
+ substitution.css += `,${font.fallbackName}`;
+ }
+ font.systemFontInfo = substitution;
+ }
+ }
+ return font;
+ }
+ static buildFontPaths(font, glyphs, handler, evaluatorOptions) {
+ function buildPath(fontChar) {
+ const glyphName = `${font.loadedName}_path_${fontChar}`;
+ try {
+ const buffer = font.renderer.getPath(fontChar);
+ if (!buffer) {
+ return;
+ }
+ handler.send("commonobj", [glyphName, "FontPath", buffer], [buffer]);
+ } catch (reason) {
+ if (evaluatorOptions.ignoreErrors) {
+ warn(`buildFontPaths - ignoring ${glyphName} glyph: "${reason}".`);
+ return;
+ }
+ throw reason;
+ }
+ }
+ for (const glyph of glyphs) {
+ buildPath(glyph.fontChar);
+ const accent = glyph.accent;
+ if (accent?.fontChar) {
+ buildPath(accent.fontChar);
+ }
+ }
+ }
+ static get fallbackFontDict() {
+ const dict = new Dict();
+ dict.set("BaseFont", Name.get("Helvetica"));
+ dict.set("Type", Name.get("FallbackType"));
+ dict.set("Subtype", Name.get("FallbackType"));
+ dict.set("Encoding", Name.get("WinAnsiEncoding"));
+ return shadow(this, "fallbackFontDict", dict);
+ }
+}
+class TranslatedFont {
+ #sent = false;
+ #type3Loaded = null;
+ constructor({
+ loadedName,
+ font,
+ dict
+ }) {
+ this.loadedName = loadedName;
+ this.font = font;
+ this.dict = dict;
+ this.type3Dependencies = font.isType3Font ? new Set() : null;
+ }
+ send(handler) {
+ if (this.#sent) {
+ return;
+ }
+ this.#sent = true;
+ const fontData = this.font.exportData(),
+ transfers = fontData.buffer ? [fontData.buffer] : null;
+ handler.send("commonobj", [this.loadedName, "Font", fontData], transfers);
+ }
+ fallback(handler, evaluatorOptions) {
+ if (!this.font.data) {
+ return;
+ }
+ this.font.disableFontFace = true;
+ PartialEvaluator.buildFontPaths(this.font, this.font.glyphCacheValues, handler, evaluatorOptions);
+ }
+ async loadType3Data(evaluator, resources, task, seenRefs = null) {
+ if (this.#type3Loaded) {
+ return this.#type3Loaded;
+ }
+ const {
+ dict,
+ font,
+ type3Dependencies
+ } = this;
+ assert(font.isType3Font, "Must be a Type3 font.");
+ const {
+ promise,
+ resolve
+ } = Promise.withResolvers();
+ this.#type3Loaded = promise;
+ const type3Evaluator = evaluator.clone({
+ ignoreErrors: false
+ });
+ const type3FontRefs = new RefSet(evaluator.type3FontRefs);
+ if (dict.objId) {
+ type3FontRefs.put(dict.objId);
+ }
+ type3Evaluator.type3FontRefs = type3FontRefs;
+ const charProcs = dict.get("CharProcs");
+ const fontResources = dict.get("Resources") || resources;
+ const charProcOperatorList = new Map();
+ const [x0, y0, x1, y1] = font.bbox;
+ const fontBBoxSize = Math.hypot(x1 - x0, y1 - y0);
+ for (const key of charProcs.getKeys()) {
+ try {
+ const operatorList = new OperatorList();
+ await type3Evaluator.getOperatorList({
+ stream: charProcs.get(key),
+ task,
+ resources: fontResources,
+ operatorList,
+ prevRefs: seenRefs
+ });
+ switch (operatorList.fnArray[0]) {
+ case OPS.setCharWidthAndBounds:
+ this.#removeType3ColorOperators(operatorList, fontBBoxSize);
+ break;
+ case OPS.setCharWidth:
+ if (!fontBBoxSize) {
+ this.#guessType3FontBBox(operatorList);
+ }
+ break;
+ }
+ charProcOperatorList.set(key, operatorList.getIR());
+ for (const dependency of operatorList.dependencies) {
+ type3Dependencies.add(dependency);
+ }
+ } catch {
+ warn(`Type3 font resource "${key}" is not available.`);
+ charProcOperatorList.set(key, new OperatorList().getIR());
+ }
+ }
+ font.charProcOperatorList = charProcOperatorList;
+ if (this._bbox) {
+ font.isCharBBox = true;
+ font.bbox = this._bbox;
+ }
+ resolve();
+ return this.#type3Loaded;
+ }
+ #removeType3ColorOperators(operatorList, fontBBoxSize = NaN) {
+ const charBBox = Util.normalizeRect(operatorList.argsArray[0].slice(2)),
+ width = charBBox[2] - charBBox[0],
+ height = charBBox[3] - charBBox[1];
+ const charBBoxSize = Math.hypot(width, height);
+ if (width === 0 || height === 0) {
+ operatorList.fnArray.splice(0, 1);
+ operatorList.argsArray.splice(0, 1);
+ } else if (fontBBoxSize === 0 || Math.round(charBBoxSize / fontBBoxSize) >= 10) {
+ this._bbox ??= BBOX_INIT.slice();
+ Util.rectBoundingBox(...charBBox, this._bbox);
+ }
+ let i = 0,
+ ii = operatorList.length;
+ while (i < ii) {
+ switch (operatorList.fnArray[i]) {
+ case OPS.setCharWidthAndBounds:
+ break;
+ case OPS.setStrokeColorSpace:
+ case OPS.setFillColorSpace:
+ case OPS.setStrokeColor:
+ case OPS.setStrokeColorN:
+ case OPS.setFillColor:
+ case OPS.setFillColorN:
+ case OPS.setStrokeGray:
+ case OPS.setFillGray:
+ case OPS.setStrokeRGBColor:
+ case OPS.setFillRGBColor:
+ case OPS.setStrokeCMYKColor:
+ case OPS.setFillCMYKColor:
+ case OPS.shadingFill:
+ case OPS.setRenderingIntent:
+ operatorList.fnArray.splice(i, 1);
+ operatorList.argsArray.splice(i, 1);
+ ii--;
+ continue;
+ case OPS.setGState:
+ const [gStateObj] = operatorList.argsArray[i];
+ let j = 0,
+ jj = gStateObj.length;
+ while (j < jj) {
+ const [gStateKey] = gStateObj[j];
+ switch (gStateKey) {
+ case "TR":
+ case "TR2":
+ case "HT":
+ case "BG":
+ case "BG2":
+ case "UCR":
+ case "UCR2":
+ gStateObj.splice(j, 1);
+ jj--;
+ continue;
+ }
+ j++;
+ }
+ break;
+ }
+ i++;
+ }
+ }
+ #guessType3FontBBox(operatorList) {
+ let i = 1;
+ const ii = operatorList.length;
+ while (i < ii) {
+ switch (operatorList.fnArray[i]) {
+ case OPS.constructPath:
+ const minMax = operatorList.argsArray[i][2];
+ this._bbox ??= BBOX_INIT.slice();
+ Util.rectBoundingBox(...minMax, this._bbox);
+ break;
+ }
+ i++;
+ }
+ }
+}
+class StateManager {
+ constructor(initialState = new EvalState()) {
+ this.state = initialState;
+ this.stateStack = [];
+ }
+ save() {
+ const old = this.state;
+ this.stateStack.push(this.state);
+ this.state = old.clone();
+ }
+ restore() {
+ const prev = this.stateStack.pop();
+ if (prev) {
+ this.state = prev;
+ }
+ }
+ transform(args) {
+ this.state.ctm = Util.transform(this.state.ctm, args);
+ }
+}
+class TextState {
+ ctm = new Float32Array(IDENTITY_MATRIX);
+ fontName = null;
+ fontSize = 0;
+ loadedName = null;
+ font = null;
+ fontMatrix = FONT_IDENTITY_MATRIX;
+ textMatrix = IDENTITY_MATRIX.slice();
+ textLineMatrix = IDENTITY_MATRIX.slice();
+ charSpacing = 0;
+ wordSpacing = 0;
+ leading = 0;
+ textHScale = 1;
+ textRise = 0;
+ setTextMatrix(a, b, c, d, e, f) {
+ const m = this.textMatrix;
+ m[0] = a;
+ m[1] = b;
+ m[2] = c;
+ m[3] = d;
+ m[4] = e;
+ m[5] = f;
+ }
+ setTextLineMatrix(a, b, c, d, e, f) {
+ const m = this.textLineMatrix;
+ m[0] = a;
+ m[1] = b;
+ m[2] = c;
+ m[3] = d;
+ m[4] = e;
+ m[5] = f;
+ }
+ translateTextMatrix(x, y) {
+ const m = this.textMatrix;
+ m[4] = m[0] * x + m[2] * y + m[4];
+ m[5] = m[1] * x + m[3] * y + m[5];
+ }
+ translateTextLineMatrix(x, y) {
+ const m = this.textLineMatrix;
+ m[4] = m[0] * x + m[2] * y + m[4];
+ m[5] = m[1] * x + m[3] * y + m[5];
+ }
+ carriageReturn() {
+ this.translateTextLineMatrix(0, -this.leading);
+ this.textMatrix = this.textLineMatrix.slice();
+ }
+ clone() {
+ const clone = Object.assign(Object.create(this), this);
+ clone.textMatrix = this.textMatrix.slice();
+ clone.textLineMatrix = this.textLineMatrix.slice();
+ clone.fontMatrix = this.fontMatrix.slice();
+ return clone;
+ }
+}
+class EvalState {
+ ctm = new Float32Array(IDENTITY_MATRIX);
+ font = null;
+ textRenderingMode = TextRenderingMode.FILL;
+ _fillColorSpace = ColorSpaceUtils.gray;
+ _strokeColorSpace = ColorSpaceUtils.gray;
+ patternFillColorSpace = null;
+ patternStrokeColorSpace = null;
+ currentPointX = 0;
+ currentPointY = 0;
+ pathMinMax = F32_BBOX_INIT.slice();
+ pathBuffer = [];
+ get fillColorSpace() {
+ return this._fillColorSpace;
+ }
+ set fillColorSpace(colorSpace) {
+ this._fillColorSpace = this.patternFillColorSpace = colorSpace;
+ }
+ get strokeColorSpace() {
+ return this._strokeColorSpace;
+ }
+ set strokeColorSpace(colorSpace) {
+ this._strokeColorSpace = this.patternStrokeColorSpace = colorSpace;
+ }
+ clone({
+ newPath = false
+ } = {}) {
+ const clone = Object.create(this);
+ if (newPath) {
+ clone.pathBuffer = [];
+ clone.pathMinMax = F32_BBOX_INIT.slice();
+ }
+ return clone;
+ }
+}
+class EvaluatorPreprocessor {
+ static get opMap() {
+ return shadow(this, "opMap", Object.assign(Object.create(null), {
+ w: {
+ id: OPS.setLineWidth,
+ numArgs: 1,
+ variableArgs: false
+ },
+ J: {
+ id: OPS.setLineCap,
+ numArgs: 1,
+ variableArgs: false
+ },
+ j: {
+ id: OPS.setLineJoin,
+ numArgs: 1,
+ variableArgs: false
+ },
+ M: {
+ id: OPS.setMiterLimit,
+ numArgs: 1,
+ variableArgs: false
+ },
+ d: {
+ id: OPS.setDash,
+ numArgs: 2,
+ variableArgs: false
+ },
+ ri: {
+ id: OPS.setRenderingIntent,
+ numArgs: 1,
+ variableArgs: false
+ },
+ i: {
+ id: OPS.setFlatness,
+ numArgs: 1,
+ variableArgs: false
+ },
+ gs: {
+ id: OPS.setGState,
+ numArgs: 1,
+ variableArgs: false
+ },
+ q: {
+ id: OPS.save,
+ numArgs: 0,
+ variableArgs: false
+ },
+ Q: {
+ id: OPS.restore,
+ numArgs: 0,
+ variableArgs: false
+ },
+ cm: {
+ id: OPS.transform,
+ numArgs: 6,
+ variableArgs: false
+ },
+ m: {
+ id: OPS.moveTo,
+ numArgs: 2,
+ variableArgs: false
+ },
+ l: {
+ id: OPS.lineTo,
+ numArgs: 2,
+ variableArgs: false
+ },
+ c: {
+ id: OPS.curveTo,
+ numArgs: 6,
+ variableArgs: false
+ },
+ v: {
+ id: OPS.curveTo2,
+ numArgs: 4,
+ variableArgs: false
+ },
+ y: {
+ id: OPS.curveTo3,
+ numArgs: 4,
+ variableArgs: false
+ },
+ h: {
+ id: OPS.closePath,
+ numArgs: 0,
+ variableArgs: false
+ },
+ re: {
+ id: OPS.rectangle,
+ numArgs: 4,
+ variableArgs: false
+ },
+ S: {
+ id: OPS.stroke,
+ numArgs: 0,
+ variableArgs: false
+ },
+ s: {
+ id: OPS.closeStroke,
+ numArgs: 0,
+ variableArgs: false
+ },
+ f: {
+ id: OPS.fill,
+ numArgs: 0,
+ variableArgs: false
+ },
+ F: {
+ id: OPS.fill,
+ numArgs: 0,
+ variableArgs: false
+ },
+ "f*": {
+ id: OPS.eoFill,
+ numArgs: 0,
+ variableArgs: false
+ },
+ B: {
+ id: OPS.fillStroke,
+ numArgs: 0,
+ variableArgs: false
+ },
+ "B*": {
+ id: OPS.eoFillStroke,
+ numArgs: 0,
+ variableArgs: false
+ },
+ b: {
+ id: OPS.closeFillStroke,
+ numArgs: 0,
+ variableArgs: false
+ },
+ "b*": {
+ id: OPS.closeEOFillStroke,
+ numArgs: 0,
+ variableArgs: false
+ },
+ n: {
+ id: OPS.endPath,
+ numArgs: 0,
+ variableArgs: false
+ },
+ W: {
+ id: OPS.clip,
+ numArgs: 0,
+ variableArgs: false
+ },
+ "W*": {
+ id: OPS.eoClip,
+ numArgs: 0,
+ variableArgs: false
+ },
+ BT: {
+ id: OPS.beginText,
+ numArgs: 0,
+ variableArgs: false
+ },
+ ET: {
+ id: OPS.endText,
+ numArgs: 0,
+ variableArgs: false
+ },
+ Tc: {
+ id: OPS.setCharSpacing,
+ numArgs: 1,
+ variableArgs: false
+ },
+ Tw: {
+ id: OPS.setWordSpacing,
+ numArgs: 1,
+ variableArgs: false
+ },
+ Tz: {
+ id: OPS.setHScale,
+ numArgs: 1,
+ variableArgs: false
+ },
+ TL: {
+ id: OPS.setLeading,
+ numArgs: 1,
+ variableArgs: false
+ },
+ Tf: {
+ id: OPS.setFont,
+ numArgs: 2,
+ variableArgs: false
+ },
+ Tr: {
+ id: OPS.setTextRenderingMode,
+ numArgs: 1,
+ variableArgs: false
+ },
+ Ts: {
+ id: OPS.setTextRise,
+ numArgs: 1,
+ variableArgs: false
+ },
+ Td: {
+ id: OPS.moveText,
+ numArgs: 2,
+ variableArgs: false
+ },
+ TD: {
+ id: OPS.setLeadingMoveText,
+ numArgs: 2,
+ variableArgs: false
+ },
+ Tm: {
+ id: OPS.setTextMatrix,
+ numArgs: 6,
+ variableArgs: false
+ },
+ "T*": {
+ id: OPS.nextLine,
+ numArgs: 0,
+ variableArgs: false
+ },
+ Tj: {
+ id: OPS.showText,
+ numArgs: 1,
+ variableArgs: false
+ },
+ TJ: {
+ id: OPS.showSpacedText,
+ numArgs: 1,
+ variableArgs: false
+ },
+ "'": {
+ id: OPS.nextLineShowText,
+ numArgs: 1,
+ variableArgs: false
+ },
+ '"': {
+ id: OPS.nextLineSetSpacingShowText,
+ numArgs: 3,
+ variableArgs: false
+ },
+ d0: {
+ id: OPS.setCharWidth,
+ numArgs: 2,
+ variableArgs: false
+ },
+ d1: {
+ id: OPS.setCharWidthAndBounds,
+ numArgs: 6,
+ variableArgs: false
+ },
+ CS: {
+ id: OPS.setStrokeColorSpace,
+ numArgs: 1,
+ variableArgs: false
+ },
+ cs: {
+ id: OPS.setFillColorSpace,
+ numArgs: 1,
+ variableArgs: false
+ },
+ SC: {
+ id: OPS.setStrokeColor,
+ numArgs: 4,
+ variableArgs: true
+ },
+ SCN: {
+ id: OPS.setStrokeColorN,
+ numArgs: 33,
+ variableArgs: true
+ },
+ sc: {
+ id: OPS.setFillColor,
+ numArgs: 4,
+ variableArgs: true
+ },
+ scn: {
+ id: OPS.setFillColorN,
+ numArgs: 33,
+ variableArgs: true
+ },
+ G: {
+ id: OPS.setStrokeGray,
+ numArgs: 1,
+ variableArgs: false
+ },
+ g: {
+ id: OPS.setFillGray,
+ numArgs: 1,
+ variableArgs: false
+ },
+ RG: {
+ id: OPS.setStrokeRGBColor,
+ numArgs: 3,
+ variableArgs: false
+ },
+ rg: {
+ id: OPS.setFillRGBColor,
+ numArgs: 3,
+ variableArgs: false
+ },
+ K: {
+ id: OPS.setStrokeCMYKColor,
+ numArgs: 4,
+ variableArgs: false
+ },
+ k: {
+ id: OPS.setFillCMYKColor,
+ numArgs: 4,
+ variableArgs: false
+ },
+ sh: {
+ id: OPS.shadingFill,
+ numArgs: 1,
+ variableArgs: false
+ },
+ BI: {
+ id: OPS.beginInlineImage,
+ numArgs: 0,
+ variableArgs: false
+ },
+ ID: {
+ id: OPS.beginImageData,
+ numArgs: 0,
+ variableArgs: false
+ },
+ EI: {
+ id: OPS.endInlineImage,
+ numArgs: 1,
+ variableArgs: false
+ },
+ Do: {
+ id: OPS.paintXObject,
+ numArgs: 1,
+ variableArgs: false
+ },
+ MP: {
+ id: OPS.markPoint,
+ numArgs: 1,
+ variableArgs: false
+ },
+ DP: {
+ id: OPS.markPointProps,
+ numArgs: 2,
+ variableArgs: false
+ },
+ BMC: {
+ id: OPS.beginMarkedContent,
+ numArgs: 1,
+ variableArgs: false
+ },
+ BDC: {
+ id: OPS.beginMarkedContentProps,
+ numArgs: 2,
+ variableArgs: false
+ },
+ EMC: {
+ id: OPS.endMarkedContent,
+ numArgs: 0,
+ variableArgs: false
+ },
+ BX: {
+ id: OPS.beginCompat,
+ numArgs: 0,
+ variableArgs: false
+ },
+ EX: {
+ id: OPS.endCompat,
+ numArgs: 0,
+ variableArgs: false
+ },
+ BM: null,
+ BD: null,
+ true: null,
+ fa: null,
+ fal: null,
+ fals: null,
+ false: null,
+ nu: null,
+ nul: null,
+ null: null
+ }));
+ }
+ static MAX_INVALID_PATH_OPS = 10;
+ constructor(stream, xref, stateManager = new StateManager()) {
+ this.parser = new Parser({
+ lexer: new Lexer(stream, EvaluatorPreprocessor.opMap),
+ xref
+ });
+ this.stateManager = stateManager;
+ this.nonProcessedArgs = [];
+ this._isPathOp = false;
+ this._numInvalidPathOPS = 0;
+ }
+ get savedStatesDepth() {
+ return this.stateManager.stateStack.length;
+ }
+ read(operation) {
+ let args = operation.args;
+ while (true) {
+ const obj = this.parser.getObj();
+ if (obj instanceof Cmd) {
+ const cmd = obj.cmd;
+ const opSpec = EvaluatorPreprocessor.opMap[cmd];
+ if (!opSpec) {
+ warn(`Unknown command "${cmd}".`);
+ continue;
+ }
+ const fn = opSpec.id;
+ const numArgs = opSpec.numArgs;
+ let argsLength = args !== null ? args.length : 0;
+ if (!this._isPathOp) {
+ this._numInvalidPathOPS = 0;
+ }
+ this._isPathOp = fn >= OPS.moveTo && fn <= OPS.endPath;
+ if (!opSpec.variableArgs) {
+ if (argsLength !== numArgs) {
+ const nonProcessedArgs = this.nonProcessedArgs;
+ while (argsLength > numArgs) {
+ nonProcessedArgs.push(args.shift());
+ argsLength--;
+ }
+ while (argsLength < numArgs && nonProcessedArgs.length !== 0) {
+ if (args === null) {
+ args = [];
+ }
+ args.unshift(nonProcessedArgs.pop());
+ argsLength++;
+ }
+ }
+ if (argsLength < numArgs) {
+ const partialMsg = `command ${cmd}: expected ${numArgs} args, ` + `but received ${argsLength} args.`;
+ if (this._isPathOp && ++this._numInvalidPathOPS > EvaluatorPreprocessor.MAX_INVALID_PATH_OPS) {
+ throw new FormatError(`Invalid ${partialMsg}`);
+ }
+ warn(`Skipping ${partialMsg}`);
+ if (args !== null) {
+ args.length = 0;
+ }
+ continue;
+ }
+ } else if (argsLength > numArgs) {
+ info(`Command ${cmd}: expected [0, ${numArgs}] args, ` + `but received ${argsLength} args.`);
+ }
+ this.preprocessCommand(fn, args);
+ operation.fn = fn;
+ operation.args = args;
+ return true;
+ }
+ if (obj === EOF) {
+ return false;
+ }
+ if (obj !== null) {
+ if (args === null) {
+ args = [];
+ }
+ args.push(obj);
+ if (args.length > 33) {
+ throw new FormatError("Too many arguments");
+ }
+ }
+ }
+ }
+ preprocessCommand(fn, args) {
+ switch (fn | 0) {
+ case OPS.save:
+ this.stateManager.save();
+ break;
+ case OPS.restore:
+ this.stateManager.restore();
+ break;
+ case OPS.transform:
+ this.stateManager.transform(args);
+ break;
+ }
+ }
+}
+
+;// ./src/core/default_appearance.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+class DefaultAppearanceEvaluator extends EvaluatorPreprocessor {
+ constructor(str) {
+ super(new StringStream(str));
+ }
+ parse() {
+ const operation = {
+ fn: 0,
+ args: []
+ };
+ const result = {
+ fontSize: 0,
+ fontName: "",
+ fontColor: new Uint8ClampedArray(3)
+ };
+ try {
+ while (true) {
+ operation.args.length = 0;
+ if (!this.read(operation)) {
+ break;
+ }
+ if (this.savedStatesDepth !== 0) {
+ continue;
+ }
+ const {
+ fn,
+ args
+ } = operation;
+ switch (fn | 0) {
+ case OPS.setFont:
+ const [fontName, fontSize] = args;
+ if (fontName instanceof Name) {
+ result.fontName = fontName.name;
+ }
+ if (typeof fontSize === "number" && fontSize > 0) {
+ result.fontSize = fontSize;
+ }
+ break;
+ case OPS.setFillRGBColor:
+ ColorSpaceUtils.rgb.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ case OPS.setFillGray:
+ ColorSpaceUtils.gray.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ case OPS.setFillCMYKColor:
+ ColorSpaceUtils.cmyk.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ }
+ }
+ } catch (reason) {
+ warn(`parseDefaultAppearance - ignoring errors: "${reason}".`);
+ }
+ return result;
+ }
+}
+function parseDefaultAppearance(str) {
+ return new DefaultAppearanceEvaluator(str).parse();
+}
+class AppearanceStreamEvaluator extends EvaluatorPreprocessor {
+ constructor(stream, xref, globalColorSpaceCache) {
+ super(stream);
+ this.stream = stream;
+ this.xref = xref;
+ this.globalColorSpaceCache = globalColorSpaceCache;
+ this.resources = stream.dict?.get("Resources");
+ }
+ parse() {
+ const operation = {
+ fn: 0,
+ args: []
+ };
+ let result = {
+ scaleFactor: 1,
+ fontSize: 0,
+ fontName: "",
+ fontColor: new Uint8ClampedArray(3),
+ fillColorSpace: ColorSpaceUtils.gray
+ };
+ let breakLoop = false;
+ const stack = [];
+ try {
+ while (true) {
+ operation.args.length = 0;
+ if (breakLoop || !this.read(operation)) {
+ break;
+ }
+ const {
+ fn,
+ args
+ } = operation;
+ switch (fn | 0) {
+ case OPS.save:
+ stack.push({
+ scaleFactor: result.scaleFactor,
+ fontSize: result.fontSize,
+ fontName: result.fontName,
+ fontColor: result.fontColor.slice(),
+ fillColorSpace: result.fillColorSpace
+ });
+ break;
+ case OPS.restore:
+ result = stack.pop() || result;
+ break;
+ case OPS.setTextMatrix:
+ const tm = Util.transform(this.stateManager.state.ctm, args);
+ result.scaleFactor *= Math.hypot(tm[0], tm[1]);
+ break;
+ case OPS.setFont:
+ const [fontName, fontSize] = args;
+ if (fontName instanceof Name) {
+ result.fontName = fontName.name;
+ }
+ if (typeof fontSize === "number" && fontSize > 0) {
+ result.fontSize = fontSize;
+ }
+ break;
+ case OPS.setFillColorSpace:
+ result.fillColorSpace = ColorSpaceUtils.parse({
+ cs: args[0],
+ xref: this.xref,
+ resources: this.resources,
+ pdfFunctionFactory: this._pdfFunctionFactory,
+ globalColorSpaceCache: this.globalColorSpaceCache,
+ localColorSpaceCache: this._localColorSpaceCache
+ });
+ break;
+ case OPS.setFillColor:
+ const cs = result.fillColorSpace;
+ cs.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ case OPS.setFillRGBColor:
+ ColorSpaceUtils.rgb.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ case OPS.setFillGray:
+ ColorSpaceUtils.gray.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ case OPS.setFillCMYKColor:
+ ColorSpaceUtils.cmyk.getRgbItem(args, 0, result.fontColor, 0);
+ break;
+ case OPS.showText:
+ case OPS.showSpacedText:
+ case OPS.nextLineShowText:
+ case OPS.nextLineSetSpacingShowText:
+ result.fontSize *= result.scaleFactor;
+ breakLoop = true;
+ break;
+ }
+ }
+ } catch (reason) {
+ warn(`parseAppearanceStream - ignoring errors: "${reason}".`);
+ }
+ this.stream.reset();
+ delete result.scaleFactor;
+ delete result.fillColorSpace;
+ return result;
+ }
+ get _localColorSpaceCache() {
+ return shadow(this, "_localColorSpaceCache", new LocalColorSpaceCache());
+ }
+ get _pdfFunctionFactory() {
+ return shadow(this, "_pdfFunctionFactory", new PDFFunctionFactory({
+ xref: this.xref
+ }));
+ }
+}
+function parseAppearanceStream(stream, xref, globalColorSpaceCache) {
+ return new AppearanceStreamEvaluator(stream, xref, globalColorSpaceCache).parse();
+}
+function getPdfColor(color, isFill) {
+ if (color[0] === color[1] && color[1] === color[2]) {
+ const gray = color[0] / 255;
+ return `${numberToString(gray)} ${isFill ? "g" : "G"}`;
+ }
+ return Array.from(color, c => numberToString(c / 255)).join(" ") + ` ${isFill ? "rg" : "RG"}`;
+}
+function createDefaultAppearance({
+ fontSize,
+ fontName,
+ fontColor
+}) {
+ return `/${escapePDFName(fontName)} ${fontSize} Tf ${getPdfColor(fontColor, true)}`;
+}
+class FakeUnicodeFont {
+ static #fontNameId = 1;
+ constructor(xref, fontFamily) {
+ this.xref = xref;
+ this.widths = null;
+ this.firstChar = Infinity;
+ this.lastChar = -Infinity;
+ this.fontFamily = fontFamily;
+ const canvas = new OffscreenCanvas(1, 1);
+ this.ctxMeasure = canvas.getContext("2d", {
+ willReadFrequently: true
+ });
+ this.fontName = Name.get(`InvalidPDFjsFont_${fontFamily}_${FakeUnicodeFont.#fontNameId++}`);
+ }
+ get fontDescriptorRef() {
+ if (!FakeUnicodeFont._fontDescriptorRef) {
+ const fontDescriptor = new Dict(this.xref);
+ fontDescriptor.setIfName("Type", "FontDescriptor");
+ fontDescriptor.set("FontName", this.fontName);
+ fontDescriptor.set("FontFamily", "MyriadPro Regular");
+ fontDescriptor.set("FontBBox", [0, 0, 0, 0]);
+ fontDescriptor.setIfName("FontStretch", "Normal");
+ fontDescriptor.set("FontWeight", 400);
+ fontDescriptor.set("ItalicAngle", 0);
+ FakeUnicodeFont._fontDescriptorRef = this.xref.getNewPersistentRef(fontDescriptor);
+ }
+ return FakeUnicodeFont._fontDescriptorRef;
+ }
+ get descendantFontRef() {
+ const descendantFont = new Dict(this.xref);
+ descendantFont.set("BaseFont", this.fontName);
+ descendantFont.setIfName("Type", "Font");
+ descendantFont.setIfName("Subtype", "CIDFontType0");
+ descendantFont.setIfName("CIDToGIDMap", "Identity");
+ descendantFont.set("FirstChar", this.firstChar);
+ descendantFont.set("LastChar", this.lastChar);
+ descendantFont.set("FontDescriptor", this.fontDescriptorRef);
+ descendantFont.set("DW", 1000);
+ const widths = [];
+ const chars = [...this.widths].sort();
+ let currentChar = null;
+ let currentWidths = null;
+ for (const [char, width] of chars) {
+ if (!currentChar) {
+ currentChar = char;
+ currentWidths = [width];
+ continue;
+ }
+ if (char === currentChar + currentWidths.length) {
+ currentWidths.push(width);
+ } else {
+ widths.push(currentChar, currentWidths);
+ currentChar = char;
+ currentWidths = [width];
+ }
+ }
+ if (currentChar) {
+ widths.push(currentChar, currentWidths);
+ }
+ descendantFont.set("W", widths);
+ const cidSystemInfo = new Dict(this.xref);
+ cidSystemInfo.set("Ordering", "Identity");
+ cidSystemInfo.set("Registry", "Adobe");
+ cidSystemInfo.set("Supplement", 0);
+ descendantFont.set("CIDSystemInfo", cidSystemInfo);
+ return this.xref.getNewPersistentRef(descendantFont);
+ }
+ get baseFontRef() {
+ const baseFont = new Dict(this.xref);
+ baseFont.set("BaseFont", this.fontName);
+ baseFont.setIfName("Type", "Font");
+ baseFont.setIfName("Subtype", "Type0");
+ baseFont.setIfName("Encoding", "Identity-H");
+ baseFont.set("DescendantFonts", [this.descendantFontRef]);
+ baseFont.setIfName("ToUnicode", "Identity-H");
+ return this.xref.getNewPersistentRef(baseFont);
+ }
+ get resources() {
+ const resources = new Dict(this.xref);
+ const font = new Dict(this.xref);
+ font.set(this.fontName.name, this.baseFontRef);
+ resources.set("Font", font);
+ return resources;
+ }
+ _createContext() {
+ this.widths = new Map();
+ this.ctxMeasure.font = `1000px ${this.fontFamily}`;
+ return this.ctxMeasure;
+ }
+ createFontResources(text) {
+ const ctx = this._createContext();
+ for (const line of text.split(/\r\n?|\n/)) {
+ for (const char of line.split("")) {
+ const code = char.charCodeAt(0);
+ if (this.widths.has(code)) {
+ continue;
+ }
+ const metrics = ctx.measureText(char);
+ const width = Math.ceil(metrics.width);
+ this.widths.set(code, width);
+ this.firstChar = Math.min(code, this.firstChar);
+ this.lastChar = Math.max(code, this.lastChar);
+ }
+ }
+ return this.resources;
+ }
+ static getFirstPositionInfo(rect, rotation, fontSize) {
+ const [x1, y1, x2, y2] = rect;
+ let w = x2 - x1;
+ let h = y2 - y1;
+ if (rotation % 180 !== 0) {
+ [w, h] = [h, w];
+ }
+ const lineHeight = (/* inlined export .LINE_FACTOR */1.35) * fontSize;
+ const lineDescent = (/* inlined export .LINE_DESCENT_FACTOR */0.35) * fontSize;
+ return {
+ coords: [0, h + lineDescent - lineHeight],
+ bbox: [0, 0, w, h],
+ matrix: rotation !== 0 ? getRotationMatrix(rotation, h, lineHeight) : undefined
+ };
+ }
+ createAppearance(text, rect, rotation, fontSize, bgColor, strokeAlpha) {
+ const ctx = this._createContext();
+ const lines = [];
+ let maxWidth = -Infinity;
+ for (const line of text.split(/\r\n?|\n/)) {
+ lines.push(line);
+ const lineWidth = ctx.measureText(line).width;
+ maxWidth = Math.max(maxWidth, lineWidth);
+ for (const code of codePointIter(line)) {
+ const char = String.fromCodePoint(code);
+ let width = this.widths.get(code);
+ if (width === undefined) {
+ const metrics = ctx.measureText(char);
+ width = Math.ceil(metrics.width);
+ this.widths.set(code, width);
+ this.firstChar = Math.min(code, this.firstChar);
+ this.lastChar = Math.max(code, this.lastChar);
+ }
+ }
+ }
+ maxWidth *= fontSize / 1000;
+ const [x1, y1, x2, y2] = rect;
+ let w = x2 - x1;
+ let h = y2 - y1;
+ if (rotation % 180 !== 0) {
+ [w, h] = [h, w];
+ }
+ const hscale = maxWidth > w ? w / maxWidth : 1;
+ let vscale = 1;
+ const lineHeight = (/* inlined export .LINE_FACTOR */1.35) * fontSize;
+ const lineDescent = (/* inlined export .LINE_DESCENT_FACTOR */0.35) * fontSize;
+ const maxHeight = lineHeight * lines.length;
+ if (maxHeight > h) {
+ vscale = h / maxHeight;
+ }
+ const fscale = Math.min(hscale, vscale);
+ const newFontSize = fontSize * fscale;
+ const buffer = ["q", `0 0 ${numberToString(w)} ${numberToString(h)} re W n`, `BT`, `1 0 0 1 0 ${numberToString(h + lineDescent)} Tm 0 Tc ${getPdfColor(bgColor, true)}`, `/${this.fontName.name} ${numberToString(newFontSize)} Tf`];
+ const {
+ resources
+ } = this;
+ strokeAlpha = typeof strokeAlpha === "number" && strokeAlpha >= 0 && strokeAlpha <= 1 ? strokeAlpha : 1;
+ if (strokeAlpha !== 1) {
+ buffer.push("/R0 gs");
+ const extGState = new Dict(this.xref);
+ const r0 = new Dict(this.xref);
+ r0.set("ca", strokeAlpha);
+ r0.set("CA", strokeAlpha);
+ r0.setIfName("Type", "ExtGState");
+ extGState.set("R0", r0);
+ resources.set("ExtGState", extGState);
+ }
+ const vShift = numberToString(lineHeight);
+ for (const line of lines) {
+ buffer.push(`0 -${vShift} Td <${stringToUTF16HexString(line)}> Tj`);
+ }
+ buffer.push("ET", "Q");
+ const appearance = buffer.join("\n");
+ const appearanceStreamDict = new Dict(this.xref);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", [0, 0, w, h]);
+ appearanceStreamDict.set("Length", appearance.length);
+ appearanceStreamDict.set("Resources", resources);
+ if (rotation) {
+ const matrix = getRotationMatrix(rotation, w, h);
+ appearanceStreamDict.set("Matrix", matrix);
+ }
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+}
+
+;// ./src/shared/scripting_utils.js
+/* unused harmony import specifier */ var scripting_utils_MathClamp;
+
+
+
+function makeColorComp(n) {
+ return Math.floor(scripting_utils_MathClamp(n, 0, 1) * 255).toString(16).padStart(2, "0");
+}
+function scaleAndClamp(x) {
+ return scripting_utils_MathClamp(x, 0, 1) * 255;
+}
+class ColorConverters {
+ static CMYK_G([c, y, m, k]) {
+ return ["G", 1 - Math.min(1, 0.3 * c + 0.59 * m + 0.11 * y + k)];
+ }
+ static G_CMYK([g]) {
+ return ["CMYK", 0, 0, 0, 1 - g];
+ }
+ static G_RGB([g]) {
+ return ["RGB", g, g, g];
+ }
+ static G_rgb([g]) {
+ g = scaleAndClamp(g);
+ return [g, g, g];
+ }
+ static G_HTML([g]) {
+ const G = makeColorComp(g);
+ return `#${G}${G}${G}`;
+ }
+ static RGB_G([r, g, b]) {
+ return ["G", 0.3 * r + 0.59 * g + 0.11 * b];
+ }
+ static RGB_rgb(color) {
+ return color.map(scaleAndClamp);
+ }
+ static RGB_HTML(color) {
+ return `#${color.map(makeColorComp).join("")}`;
+ }
+ static T_HTML() {
+ return "#00000000";
+ }
+ static T_rgb() {
+ return [null];
+ }
+ static CMYK_RGB([c, y, m, k]) {
+ return ["RGB", 1 - Math.min(1, c + k), 1 - Math.min(1, m + k), 1 - Math.min(1, y + k)];
+ }
+ static CMYK_rgb([c, y, m, k]) {
+ return [scaleAndClamp(1 - Math.min(1, c + k)), scaleAndClamp(1 - Math.min(1, m + k)), scaleAndClamp(1 - Math.min(1, y + k))];
+ }
+ static CMYK_HTML(components) {
+ const rgb = this.CMYK_RGB(components).slice(1);
+ return this.RGB_HTML(rgb);
+ }
+ static RGB_CMYK([r, g, b]) {
+ const c = 1 - r;
+ const m = 1 - g;
+ const y = 1 - b;
+ const k = Math.min(c, m, y);
+ return ["CMYK", c, m, y, k];
+ }
+}
+const DateFormats = ["m/d", "m/d/yy", "mm/dd/yy", "mm/yy", "d-mmm", "d-mmm-yy", "dd-mmm-yy", "yy-mm-dd", "mmm-yy", "mmmm-yy", "mmm d, yyyy", "mmmm d, yyyy", "m/d/yy h:MM tt", "m/d/yy HH:MM"];
+const TimeFormats = ["HH:MM", "h:MM tt", "HH:MM:ss", "h:MM:ss tt"];
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.json.stringify.js
+var es_json_stringify = __webpack_require__(3110);
+;// ./src/core/name_number_tree.js
+
+
+
+
+
+class NameOrNumberTree {
+ constructor(root, xref, type) {
+ this.root = root;
+ this.xref = xref;
+ this._type = type;
+ }
+ getAll(isRaw = false) {
+ const map = new Map();
+ if (!this.root) {
+ return map;
+ }
+ const xref = this.xref;
+ const processed = new RefSet();
+ if (this.root instanceof Ref) {
+ processed.put(this.root);
+ }
+ const queue = [this.root];
+ for (const node of queue) {
+ const obj = xref.fetchIfRef(node);
+ if (!(obj instanceof Dict)) {
+ continue;
+ }
+ if (obj.has("Kids")) {
+ const kids = obj.get("Kids");
+ if (!Array.isArray(kids)) {
+ continue;
+ }
+ for (const kid of kids) {
+ if (kid instanceof Ref) {
+ if (processed.has(kid)) {
+ throw new FormatError(`Duplicate entry in "${this._type}" tree.`);
+ }
+ processed.put(kid);
+ }
+ queue.push(kid);
+ }
+ continue;
+ }
+ const entries = obj.get(this._type);
+ if (!Array.isArray(entries)) {
+ continue;
+ }
+ for (let i = 0, ii = entries.length; i < ii; i += 2) {
+ map.set(isRaw ? entries[i] : xref.fetchIfRef(entries[i]), isRaw ? entries[i + 1] : xref.fetchIfRef(entries[i + 1]));
+ }
+ }
+ return map;
+ }
+ getRaw(key) {
+ if (!this.root) {
+ return null;
+ }
+ const xref = this.xref;
+ let kidsOrEntries = xref.fetchIfRef(this.root);
+ let loopCount = 0;
+ const MAX_LEVELS = 10;
+ while (kidsOrEntries.has("Kids")) {
+ if (++loopCount > MAX_LEVELS) {
+ warn(`Search depth limit reached for "${this._type}" tree.`);
+ return null;
+ }
+ const kids = kidsOrEntries.get("Kids");
+ if (!Array.isArray(kids)) {
+ return null;
+ }
+ let l = 0,
+ r = kids.length - 1;
+ while (l <= r) {
+ const m = l + r >> 1;
+ const kid = xref.fetchIfRef(kids[m]);
+ const limits = kid.get("Limits");
+ if (key < xref.fetchIfRef(limits[0])) {
+ r = m - 1;
+ } else if (key > xref.fetchIfRef(limits[1])) {
+ l = m + 1;
+ } else {
+ kidsOrEntries = kid;
+ break;
+ }
+ }
+ if (l > r) {
+ return null;
+ }
+ }
+ const entries = kidsOrEntries.get(this._type);
+ if (Array.isArray(entries)) {
+ let l = 0,
+ r = entries.length - 2;
+ while (l <= r) {
+ const tmp = l + r >> 1,
+ m = tmp + (tmp & 1);
+ const currentKey = xref.fetchIfRef(entries[m]);
+ if (key < currentKey) {
+ r = m - 2;
+ } else if (key > currentKey) {
+ l = m + 2;
+ } else {
+ return entries[m + 1];
+ }
+ }
+ }
+ return null;
+ }
+ get(key) {
+ return this.xref.fetchIfRef(this.getRaw(key));
+ }
+}
+class NameTree extends NameOrNumberTree {
+ constructor(root, xref) {
+ super(root, xref, "Names");
+ }
+}
+class NumberTree extends NameOrNumberTree {
+ constructor(root, xref) {
+ super(root, xref, "Nums");
+ }
+}
+
+;// ./src/core/cleanup_helper.js
+
+
+
+
+function clearGlobalCaches() {
+ clearPatternCaches();
+ clearPrimitiveCaches();
+ clearUnicodeCaches();
+ WasmImage.cleanup();
+}
+
+;// ./src/core/file_spec.js
+
+
+
+
+class FileSpec {
+ constructor(root) {
+ if (!(root instanceof Dict)) {
+ return;
+ }
+ this.root = root;
+ if (root.has("RF")) {
+ warn("Related file specifications are not supported");
+ }
+ }
+ get filename() {
+ const item = FileSpec.pickPlatformItem(this.root);
+ if (item && typeof item === "string") {
+ return stringToPDFString(item, true).replaceAll("\\\\", "\\").replaceAll("\\/", "/").replaceAll("\\", "/");
+ }
+ return "";
+ }
+ get description() {
+ const desc = this.root?.get("Desc");
+ if (desc && typeof desc === "string") {
+ return stringToPDFString(desc);
+ }
+ return "";
+ }
+ get serializable() {
+ const {
+ filename,
+ description
+ } = this;
+ return {
+ rawFilename: filename,
+ filename: stripPath(filename) || "unnamed",
+ description
+ };
+ }
+ static pickPlatformItem(dict, raw = false) {
+ if (dict instanceof Dict) {
+ for (const key of ["UF", "F", "Unix", "Mac", "DOS"]) {
+ if (dict.has(key)) {
+ return raw ? dict.getRaw(key) : dict.get(key);
+ }
+ }
+ }
+ return null;
+ }
+ static hasEmbeddedFile(fileSpecDict) {
+ return this.pickPlatformItem(fileSpecDict.get("EF")) instanceof BaseStream;
+ }
+ static readContent(dict) {
+ if (!(dict instanceof Dict)) {
+ return null;
+ }
+ const ef = this.pickPlatformItem(dict.get("EF"));
+ if (!(ef instanceof BaseStream)) {
+ warn("Embedded file specification points to non-existing/invalid content");
+ return null;
+ }
+ return this.readStreamContent(ef);
+ }
+ static readStreamContent(stream) {
+ const encrypt = stream.dict?.xref?.encrypt;
+ if (encrypt?.encryptionKey === null) {
+ throw new PasswordException("No password given", PasswordResponses.NEED_PASSWORD);
+ }
+ return stream.getBytes();
+ }
+}
+
+;// ./src/core/xml_parser.js
+
+
+
+
+
+const XMLParserErrorCode = {
+ NoError: 0,
+ EndOfDocument: -1,
+ UnterminatedCdat: -2,
+ UnterminatedXmlDeclaration: -3,
+ UnterminatedDoctypeDeclaration: -4,
+ UnterminatedComment: -5,
+ MalformedElement: -6,
+ OutOfMemory: -7,
+ UnterminatedAttributeValue: -8,
+ UnterminatedElement: -9,
+ ElementNeverBegun: -10
+};
+function isWhitespace(s, index) {
+ const ch = s[index];
+ return ch === " " || ch === "\n" || ch === "\r" || ch === "\t";
+}
+function isWhitespaceString(s) {
+ for (let i = 0, ii = s.length; i < ii; i++) {
+ if (!isWhitespace(s, i)) {
+ return false;
+ }
+ }
+ return true;
+}
+class XMLParserBase {
+ static get _entityRegex() {
+ return shadow(this, "_entityRegex", /&(?:#x([^;&]+)|#([^;&]+)|([^;&]+));/g);
+ }
+ _resolveEntities(s) {
+ return s.replaceAll(XMLParserBase._entityRegex, (all, hex, dec, entity) => {
+ if (hex || dec) {
+ const code = hex ? parseInt(hex, 16) : parseInt(dec, 10);
+ return code >= 0 && code <= 0x10ffff ? String.fromCodePoint(code) : all;
+ }
+ switch (entity) {
+ case "lt":
+ return "<";
+ case "gt":
+ return ">";
+ case "amp":
+ return "&";
+ case "quot":
+ return '"';
+ case "apos":
+ return "'";
+ }
+ return this.onResolveEntity(entity);
+ });
+ }
+ _parseContent(s, start) {
+ const attributes = [];
+ let pos = start;
+ function skipWs() {
+ while (pos < s.length && isWhitespace(s, pos)) {
+ ++pos;
+ }
+ }
+ while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== ">" && s[pos] !== "/") {
+ ++pos;
+ }
+ const name = s.substring(start, pos);
+ skipWs();
+ while (pos < s.length && s[pos] !== ">" && s[pos] !== "/" && s[pos] !== "?") {
+ skipWs();
+ let attrName = "",
+ attrValue = "";
+ while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== "=") {
+ attrName += s[pos];
+ ++pos;
+ }
+ skipWs();
+ if (s[pos] !== "=") {
+ return null;
+ }
+ ++pos;
+ skipWs();
+ const attrEndChar = s[pos];
+ if (attrEndChar !== '"' && attrEndChar !== "'") {
+ return null;
+ }
+ const attrEndIndex = s.indexOf(attrEndChar, ++pos);
+ if (attrEndIndex < 0) {
+ return null;
+ }
+ attrValue = s.substring(pos, attrEndIndex);
+ attributes.push({
+ name: attrName,
+ value: this._resolveEntities(attrValue)
+ });
+ pos = attrEndIndex + 1;
+ skipWs();
+ }
+ return {
+ name,
+ attributes,
+ parsed: pos - start
+ };
+ }
+ _parseProcessingInstruction(s, start) {
+ let pos = start;
+ function skipWs() {
+ while (pos < s.length && isWhitespace(s, pos)) {
+ ++pos;
+ }
+ }
+ while (pos < s.length && !isWhitespace(s, pos) && s[pos] !== ">" && s[pos] !== "?" && s[pos] !== "/") {
+ ++pos;
+ }
+ const name = s.substring(start, pos);
+ skipWs();
+ const attrStart = pos;
+ while (pos < s.length && (s[pos] !== "?" || s[pos + 1] !== ">")) {
+ ++pos;
+ }
+ const value = s.substring(attrStart, pos);
+ return {
+ name,
+ value,
+ parsed: pos - start
+ };
+ }
+ parseXml(s) {
+ let i = 0;
+ while (i < s.length) {
+ const ch = s[i];
+ let j = i;
+ if (ch === "<") {
+ ++j;
+ const ch2 = s[j];
+ let q;
+ switch (ch2) {
+ case "/":
+ ++j;
+ q = s.indexOf(">", j);
+ if (q < 0) {
+ this.onError(XMLParserErrorCode.UnterminatedElement);
+ return;
+ }
+ this.onEndElement(s.substring(j, q));
+ j = q + 1;
+ break;
+ case "?":
+ ++j;
+ const pi = this._parseProcessingInstruction(s, j);
+ if (s.substring(j + pi.parsed, j + pi.parsed + 2) !== "?>") {
+ this.onError(XMLParserErrorCode.UnterminatedXmlDeclaration);
+ return;
+ }
+ this.onPi(pi.name, pi.value);
+ j += pi.parsed + 2;
+ break;
+ case "!":
+ if (s.substring(j + 1, j + 3) === "--") {
+ q = s.indexOf("-->", j + 3);
+ if (q < 0) {
+ this.onError(XMLParserErrorCode.UnterminatedComment);
+ return;
+ }
+ this.onComment(s.substring(j + 3, q));
+ j = q + 3;
+ } else if (s.substring(j + 1, j + 8) === "[CDATA[") {
+ q = s.indexOf("]]>", j + 8);
+ if (q < 0) {
+ this.onError(XMLParserErrorCode.UnterminatedCdat);
+ return;
+ }
+ this.onCdata(s.substring(j + 8, q));
+ j = q + 3;
+ } else if (s.substring(j + 1, j + 8) === "DOCTYPE") {
+ const q2 = s.indexOf("[", j + 8);
+ let complexDoctype = false;
+ q = s.indexOf(">", j + 8);
+ if (q < 0) {
+ this.onError(XMLParserErrorCode.UnterminatedDoctypeDeclaration);
+ return;
+ }
+ if (q2 > 0 && q > q2) {
+ q = s.indexOf("]>", j + 8);
+ if (q < 0) {
+ this.onError(XMLParserErrorCode.UnterminatedDoctypeDeclaration);
+ return;
+ }
+ complexDoctype = true;
+ }
+ const doctypeContent = s.substring(j + 8, q + (complexDoctype ? 1 : 0));
+ this.onDoctype(doctypeContent);
+ j = q + (complexDoctype ? 2 : 1);
+ } else {
+ this.onError(XMLParserErrorCode.MalformedElement);
+ return;
+ }
+ break;
+ default:
+ const content = this._parseContent(s, j);
+ if (content === null) {
+ this.onError(XMLParserErrorCode.MalformedElement);
+ return;
+ }
+ let isClosed = false;
+ if (s.substring(j + content.parsed, j + content.parsed + 2) === "/>") {
+ isClosed = true;
+ } else if (s.substring(j + content.parsed, j + content.parsed + 1) !== ">") {
+ this.onError(XMLParserErrorCode.UnterminatedElement);
+ return;
+ }
+ this.onBeginElement(content.name, content.attributes, isClosed);
+ j += content.parsed + (isClosed ? 2 : 1);
+ break;
+ }
+ } else {
+ while (j < s.length && s[j] !== "<") {
+ j++;
+ }
+ const text = s.substring(i, j);
+ this.onText(this._resolveEntities(text));
+ }
+ i = j;
+ }
+ }
+ onResolveEntity(name) {
+ return `&${name};`;
+ }
+ onPi(name, value) {}
+ onComment(text) {}
+ onCdata(text) {}
+ onDoctype(doctypeContent) {}
+ onText(text) {}
+ onBeginElement(name, attributes, isEmpty) {}
+ onEndElement(name) {}
+ onError(code) {}
+}
+class SimpleDOMNode {
+ constructor(nodeName, nodeValue) {
+ this.nodeName = nodeName;
+ this.nodeValue = nodeValue;
+ Object.defineProperty(this, "parentNode", {
+ value: null,
+ writable: true
+ });
+ }
+ get firstChild() {
+ return this.childNodes?.[0];
+ }
+ get nextSibling() {
+ const childNodes = this.parentNode.childNodes;
+ if (!childNodes) {
+ return undefined;
+ }
+ const index = childNodes.indexOf(this);
+ if (index === -1) {
+ return undefined;
+ }
+ return childNodes[index + 1];
+ }
+ get textContent() {
+ return !this.childNodes ? this.nodeValue || "" : this.childNodes.map(child => child.textContent).join("");
+ }
+ get children() {
+ return this.childNodes || [];
+ }
+ hasChildNodes() {
+ return this.childNodes?.length > 0;
+ }
+ searchNode(paths, pos) {
+ if (pos >= paths.length) {
+ return this;
+ }
+ const component = paths[pos];
+ if (component.name.startsWith("#") && pos < paths.length - 1) {
+ return this.searchNode(paths, pos + 1);
+ }
+ const stack = [];
+ let node = this;
+ while (true) {
+ if (component.name === node.nodeName) {
+ if (component.pos === 0) {
+ const res = node.searchNode(paths, pos + 1);
+ if (res !== null) {
+ return res;
+ }
+ } else if (stack.length === 0) {
+ return null;
+ } else {
+ const [parent] = stack.pop();
+ let siblingPos = 0;
+ for (const child of parent.childNodes) {
+ if (component.name === child.nodeName) {
+ if (siblingPos === component.pos) {
+ return child.searchNode(paths, pos + 1);
+ }
+ siblingPos++;
+ }
+ }
+ return node.searchNode(paths, pos + 1);
+ }
+ }
+ if (node.childNodes?.length > 0) {
+ stack.push([node, 0]);
+ node = node.childNodes[0];
+ } else if (stack.length === 0) {
+ return null;
+ } else {
+ while (stack.length !== 0) {
+ const [parent, currentPos] = stack.pop();
+ const newPos = currentPos + 1;
+ if (newPos < parent.childNodes.length) {
+ stack.push([parent, newPos]);
+ node = parent.childNodes[newPos];
+ break;
+ }
+ }
+ if (stack.length === 0) {
+ return null;
+ }
+ }
+ }
+ }
+ dump(buffer) {
+ if (this.nodeName === "#text") {
+ buffer.push(encodeToXmlString(this.nodeValue));
+ return;
+ }
+ buffer.push(`<${this.nodeName}`);
+ if (this.attributes) {
+ for (const attribute of this.attributes) {
+ buffer.push(` ${attribute.name}="${encodeToXmlString(attribute.value)}"`);
+ }
+ }
+ if (this.hasChildNodes()) {
+ buffer.push(">");
+ for (const child of this.childNodes) {
+ child.dump(buffer);
+ }
+ buffer.push(`${this.nodeName}>`);
+ } else if (this.nodeValue) {
+ buffer.push(`>${encodeToXmlString(this.nodeValue)}${this.nodeName}>`);
+ } else {
+ buffer.push("/>");
+ }
+ }
+}
+class SimpleXMLParser extends XMLParserBase {
+ constructor({
+ hasAttributes = false,
+ lowerCaseName = false
+ }) {
+ super();
+ this._currentFragment = null;
+ this._stack = null;
+ this._errorCode = XMLParserErrorCode.NoError;
+ this._hasAttributes = hasAttributes;
+ this._lowerCaseName = lowerCaseName;
+ }
+ parseFromString(data) {
+ this._currentFragment = [];
+ this._stack = [];
+ this._errorCode = XMLParserErrorCode.NoError;
+ this.parseXml(data);
+ if (this._errorCode !== XMLParserErrorCode.NoError) {
+ return undefined;
+ }
+ const [documentElement] = this._currentFragment;
+ if (!documentElement) {
+ return undefined;
+ }
+ return {
+ documentElement
+ };
+ }
+ onText(text) {
+ if (isWhitespaceString(text)) {
+ return;
+ }
+ const node = new SimpleDOMNode("#text", text);
+ this._currentFragment.push(node);
+ }
+ onCdata(text) {
+ const node = new SimpleDOMNode("#text", text);
+ this._currentFragment.push(node);
+ }
+ onBeginElement(name, attributes, isEmpty) {
+ if (this._lowerCaseName) {
+ name = name.toLowerCase();
+ }
+ const node = new SimpleDOMNode(name);
+ node.childNodes = [];
+ if (this._hasAttributes) {
+ node.attributes = attributes;
+ }
+ this._currentFragment.push(node);
+ if (isEmpty) {
+ return;
+ }
+ this._stack.push(this._currentFragment);
+ this._currentFragment = node.childNodes;
+ }
+ onEndElement(name) {
+ this._currentFragment = this._stack.pop() || [];
+ const lastElement = this._currentFragment.at(-1);
+ if (!lastElement) {
+ return null;
+ }
+ for (const childNode of lastElement.childNodes) {
+ childNode.parentNode = lastElement;
+ }
+ return lastElement;
+ }
+ onError(code) {
+ this._errorCode = code;
+ }
+}
+
+;// ./src/core/metadata_parser.js
+
+
+
+
+
+
+
+class MetadataParser {
+ constructor(data) {
+ data = this._repair(data);
+ const parser = new SimpleXMLParser({
+ lowerCaseName: true
+ });
+ const xmlDocument = parser.parseFromString(data);
+ this._metadataMap = new Map();
+ this._data = data;
+ if (xmlDocument) {
+ this._parse(xmlDocument);
+ }
+ }
+ _repair(data) {
+ return data.replace(/^[^<]+/, "").replaceAll(/>\\376\\377([^<]+)/g, function (all, codes) {
+ const bytes = codes.replaceAll(/\\([0-3])([0-7])([0-7])/g, function (code, d1, d2, d3) {
+ return String.fromCharCode(d1 * 64 + d2 * 8 + d3 * 1);
+ }).replaceAll(/&(amp|apos|gt|lt|quot);/g, function (str, name) {
+ switch (name) {
+ case "amp":
+ return "&";
+ case "apos":
+ return "'";
+ case "gt":
+ return ">";
+ case "lt":
+ return "<";
+ case "quot":
+ return '"';
+ }
+ throw new Error(`_repair: ${name} isn't defined.`);
+ });
+ const charBuf = [">"];
+ for (let i = 0, ii = bytes.length; i < ii; i += 2) {
+ const code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
+ if (code >= 32 && code < 127 && code !== 60 && code !== 62 && code !== 38) {
+ charBuf.push(String.fromCharCode(code));
+ } else {
+ charBuf.push("" + (0x10000 + code).toString(16).substring(1) + ";");
+ }
+ }
+ return charBuf.join("");
+ });
+ }
+ _getSequence(entry) {
+ const name = entry.nodeName;
+ if (name !== "rdf:bag" && name !== "rdf:seq" && name !== "rdf:alt") {
+ return null;
+ }
+ return entry.childNodes.filter(node => node.nodeName === "rdf:li");
+ }
+ _parseArray(entry) {
+ if (!entry.hasChildNodes()) {
+ return;
+ }
+ const [seqNode] = entry.childNodes;
+ const sequence = this._getSequence(seqNode) || [];
+ this._metadataMap.set(entry.nodeName, sequence.map(node => node.textContent.trim()));
+ }
+ _parse(xmlDocument) {
+ let rdf = xmlDocument.documentElement;
+ if (rdf.nodeName !== "rdf:rdf") {
+ rdf = rdf.firstChild;
+ while (rdf && rdf.nodeName !== "rdf:rdf") {
+ rdf = rdf.nextSibling;
+ }
+ }
+ if (!rdf || rdf.nodeName !== "rdf:rdf" || !rdf.hasChildNodes()) {
+ return;
+ }
+ for (const desc of rdf.childNodes) {
+ if (desc.nodeName !== "rdf:description") {
+ continue;
+ }
+ for (const entry of desc.childNodes) {
+ const name = entry.nodeName;
+ switch (name) {
+ case "#text":
+ continue;
+ case "dc:creator":
+ case "dc:subject":
+ this._parseArray(entry);
+ continue;
+ }
+ this._metadataMap.set(name, entry.textContent.trim());
+ }
+ }
+ }
+ get serializable() {
+ return {
+ parsedData: this._metadataMap,
+ rawData: this._data
+ };
+ }
+}
+
+;// ./src/core/sound.js
+
+
+
+
+
+
+
+const WAV_HEADER_SIZE = 44;
+function getSoundFormat(dict) {
+ if (!dict || dict.has("CO")) {
+ return null;
+ }
+ const sampleRate = dict.get("R");
+ if (!Number.isInteger(sampleRate) || sampleRate <= 0) {
+ return null;
+ }
+ const channels = dict.get("C") ?? 1;
+ if (!Number.isInteger(channels) || channels < 1 || channels > 2) {
+ return null;
+ }
+ const bitsPerSample = dict.get("B") ?? 8;
+ if (bitsPerSample !== 8 && bitsPerSample !== 16) {
+ return null;
+ }
+ const e = dict.get("E");
+ let encoding = "Raw";
+ if (e !== undefined) {
+ encoding = e instanceof Name ? e.name : null;
+ }
+ if (encoding !== "Raw" && encoding !== "Signed") {
+ return null;
+ }
+ return {
+ channels,
+ sampleRate,
+ bitsPerSample,
+ encoding
+ };
+}
+function soundStreamToWav(stream, samples) {
+ const format = getSoundFormat(stream.dict);
+ if (!format) {
+ return null;
+ }
+ const {
+ channels,
+ sampleRate,
+ bitsPerSample,
+ encoding
+ } = format;
+ const blockAlign = channels * (bitsPerSample >> 3);
+ const dataLength = samples.length - samples.length % blockAlign;
+ if (dataLength === 0) {
+ return null;
+ }
+ const wav = new Uint8Array(WAV_HEADER_SIZE + dataLength);
+ const view = new DataView(wav.buffer);
+ wav.set(stringToBytes("RIFF"), 0);
+ view.setUint32(4, WAV_HEADER_SIZE - 8 + dataLength, true);
+ wav.set(stringToBytes("WAVE"), 8);
+ wav.set(stringToBytes("fmt "), 12);
+ view.setUint32(16, 16, true);
+ view.setUint16(20, 1, true);
+ view.setUint16(22, channels, true);
+ view.setUint32(24, sampleRate, true);
+ view.setUint32(28, sampleRate * blockAlign, true);
+ view.setUint16(32, blockAlign, true);
+ view.setUint16(34, bitsPerSample, true);
+ wav.set(stringToBytes("data"), 36);
+ view.setUint32(40, dataLength, true);
+ if (bitsPerSample === 16) {
+ const signed = encoding === "Signed";
+ for (let i = 0; i < dataLength; i += 2) {
+ let value = samples[i] << 8 | samples[i + 1];
+ if (signed) {
+ if (value >= 0x8000) {
+ value -= 0x10000;
+ }
+ } else {
+ value -= 0x8000;
+ }
+ view.setInt16(WAV_HEADER_SIZE + i, value, true);
+ }
+ } else if (encoding === "Signed") {
+ for (let i = 0; i < dataLength; i++) {
+ wav[WAV_HEADER_SIZE + i] = samples[i] + 128 & 0xff;
+ }
+ } else {
+ wav.set(samples.subarray(0, dataLength), WAV_HEADER_SIZE);
+ }
+ return wav;
+}
+
+;// ./src/core/struct_tree.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const MAX_DEPTH = 40;
+const TABLE_SPAN_ATTRIBUTES = [["RowSpan", "rowSpan"], ["ColSpan", "colSpan"]];
+const StructElementType = {
+ PAGE_CONTENT: 1,
+ STREAM_CONTENT: 2,
+ OBJECT: 3,
+ ANNOTATION: 4,
+ ELEMENT: 5
+};
+class StructTreeRoot {
+ kidRefToPosition = undefined;
+ parentTree = null;
+ roleMap = new Map();
+ structParentIds = null;
+ constructor(xref, rootDict, rootRef) {
+ this.xref = xref;
+ this.dict = rootDict;
+ this.ref = rootRef instanceof Ref ? rootRef : null;
+ const roleMap = rootDict.get("RoleMap");
+ if (roleMap instanceof Dict) {
+ for (const [key, value] of roleMap) {
+ if (value instanceof Name) {
+ this.roleMap.set(key, value.name);
+ }
+ }
+ }
+ const parentTree = rootDict.getRaw("ParentTree");
+ if (parentTree) {
+ this.parentTree = new NumberTree(parentTree, xref);
+ }
+ }
+ getKidPosition(kidRef) {
+ if (this.kidRefToPosition === undefined) {
+ const obj = this.dict.get("K");
+ if (Array.isArray(obj)) {
+ const map = this.kidRefToPosition = new Map();
+ for (let i = 0, ii = obj.length; i < ii; i++) {
+ const ref = obj[i];
+ if (ref) {
+ map.set(ref.toString(), i);
+ }
+ }
+ } else if (obj instanceof Dict) {
+ this.kidRefToPosition = new Map([[obj.objId, 0]]);
+ } else if (!obj) {
+ this.kidRefToPosition = new Map();
+ } else {
+ this.kidRefToPosition = null;
+ }
+ }
+ return this.kidRefToPosition ? this.kidRefToPosition.get(kidRef) ?? NaN : -1;
+ }
+ #addIdToPage(pageRef, id, type, objId) {
+ if (!(pageRef instanceof Ref) || id < 0) {
+ return;
+ }
+ (this.structParentIds ??= new RefMap()).getOrPutComputed(pageRef, makeArr).push([id, type, objId]);
+ }
+ addAnnotationIdToPage(pageRef, id, ref) {
+ this.#addIdToPage(pageRef, id, StructElementType.ANNOTATION, ref instanceof Ref ? ref.toString() : null);
+ }
+ static async canCreateStructureTree({
+ catalogRef,
+ pdfManager,
+ newAnnotationsByPage
+ }) {
+ if (!(catalogRef instanceof Ref)) {
+ warn("Cannot save the struct tree: no catalog reference.");
+ return false;
+ }
+ let nextKey = 0;
+ let hasNothingToUpdate = true;
+ for (const [pageIndex, elements] of newAnnotationsByPage) {
+ const {
+ ref: pageRef
+ } = await pdfManager.getPage(pageIndex);
+ if (!(pageRef instanceof Ref)) {
+ warn(`Cannot save the struct tree: page ${pageIndex} has no ref.`);
+ hasNothingToUpdate = true;
+ break;
+ }
+ for (const element of elements) {
+ if (element.accessibilityData?.type) {
+ element.parentTreeId = nextKey++;
+ hasNothingToUpdate = false;
+ }
+ }
+ }
+ if (hasNothingToUpdate) {
+ for (const elements of newAnnotationsByPage.values()) {
+ for (const element of elements) {
+ delete element.parentTreeId;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+ static async createStructureTree({
+ newAnnotationsByPage,
+ xref,
+ catalogRef,
+ pdfManager,
+ changes
+ }) {
+ const root = await pdfManager.ensureCatalog("cloneDict");
+ const cache = new RefMap();
+ cache.put(catalogRef, root);
+ const structTreeRootRef = xref.getNewTemporaryRef();
+ root.set("StructTreeRoot", structTreeRootRef);
+ const structTreeRoot = new Dict(xref);
+ structTreeRoot.set("Type", Name.get("StructTreeRoot"));
+ const parentTreeRef = xref.getNewTemporaryRef();
+ structTreeRoot.set("ParentTree", parentTreeRef);
+ const kids = [];
+ structTreeRoot.set("K", kids);
+ cache.put(structTreeRootRef, structTreeRoot);
+ const parentTree = new Dict(xref);
+ const nums = [];
+ parentTree.set("Nums", nums);
+ const nextKey = await this.#writeKids({
+ newAnnotationsByPage,
+ structTreeRootRef,
+ structTreeRoot: null,
+ kids,
+ nums,
+ xref,
+ pdfManager,
+ changes,
+ cache
+ });
+ structTreeRoot.set("ParentTreeNextKey", nextKey);
+ cache.put(parentTreeRef, parentTree);
+ for (const [ref, obj] of cache.items()) {
+ changes.put(ref, {
+ data: obj
+ });
+ }
+ }
+ async canUpdateStructTree({
+ pdfManager,
+ newAnnotationsByPage
+ }) {
+ if (!this.ref) {
+ warn("Cannot update the struct tree: no root reference.");
+ return false;
+ }
+ let nextKey = this.dict.get("ParentTreeNextKey");
+ if (!Number.isInteger(nextKey) || nextKey < 0) {
+ warn("Cannot update the struct tree: invalid next key.");
+ return false;
+ }
+ const parentTree = this.dict.get("ParentTree");
+ if (!(parentTree instanceof Dict)) {
+ warn("Cannot update the struct tree: ParentTree isn't a dict.");
+ return false;
+ }
+ const nums = parentTree.get("Nums");
+ if (!Array.isArray(nums)) {
+ warn("Cannot update the struct tree: nums isn't an array.");
+ return false;
+ }
+ const numberTree = new NumberTree(parentTree, this.xref);
+ for (const pageIndex of newAnnotationsByPage.keys()) {
+ const {
+ pageDict
+ } = await pdfManager.getPage(pageIndex);
+ if (!pageDict.has("StructParents")) {
+ continue;
+ }
+ const id = pageDict.get("StructParents");
+ if (!Number.isInteger(id) || !Array.isArray(numberTree.get(id))) {
+ warn(`Cannot save the struct tree: page ${pageIndex} has a wrong id.`);
+ return false;
+ }
+ }
+ let hasNothingToUpdate = true;
+ for (const [pageIndex, elements] of newAnnotationsByPage) {
+ const {
+ pageDict
+ } = await pdfManager.getPage(pageIndex);
+ StructTreeRoot.#collectParents({
+ elements,
+ xref: this.xref,
+ pageDict,
+ numberTree
+ });
+ for (const element of elements) {
+ if (element.accessibilityData?.type) {
+ if (!(element.accessibilityData.structParent >= 0)) {
+ element.parentTreeId = nextKey++;
+ }
+ hasNothingToUpdate = false;
+ }
+ }
+ }
+ if (hasNothingToUpdate) {
+ for (const elements of newAnnotationsByPage.values()) {
+ for (const element of elements) {
+ delete element.parentTreeId;
+ delete element.structTreeParent;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+ async updateStructureTree({
+ newAnnotationsByPage,
+ pdfManager,
+ changes
+ }) {
+ const {
+ ref: structTreeRootRef,
+ xref
+ } = this;
+ const structTreeRoot = this.dict.clone();
+ const cache = new RefMap();
+ cache.put(structTreeRootRef, structTreeRoot);
+ let parentTreeRef = structTreeRoot.getRaw("ParentTree");
+ let parentTree;
+ if (parentTreeRef instanceof Ref) {
+ parentTree = xref.fetch(parentTreeRef);
+ } else {
+ parentTree = parentTreeRef;
+ parentTreeRef = xref.getNewTemporaryRef();
+ structTreeRoot.set("ParentTree", parentTreeRef);
+ }
+ parentTree = parentTree.clone();
+ cache.put(parentTreeRef, parentTree);
+ let nums = parentTree.getRaw("Nums");
+ let numsRef = null;
+ if (nums instanceof Ref) {
+ numsRef = nums;
+ nums = xref.fetch(numsRef);
+ }
+ nums = nums.slice();
+ if (!numsRef) {
+ parentTree.set("Nums", nums);
+ }
+ const newNextKey = await StructTreeRoot.#writeKids({
+ newAnnotationsByPage,
+ structTreeRootRef,
+ structTreeRoot: this,
+ kids: null,
+ nums,
+ xref,
+ pdfManager,
+ changes,
+ cache
+ });
+ if (newNextKey === -1) {
+ return;
+ }
+ structTreeRoot.set("ParentTreeNextKey", newNextKey);
+ if (numsRef) {
+ cache.put(numsRef, nums);
+ }
+ for (const [ref, obj] of cache.items()) {
+ changes.put(ref, {
+ data: obj
+ });
+ }
+ }
+ static async #writeKids({
+ newAnnotationsByPage,
+ structTreeRootRef,
+ structTreeRoot,
+ kids,
+ nums,
+ xref,
+ pdfManager,
+ changes,
+ cache
+ }) {
+ const objr = Name.get("OBJR");
+ let nextKey = -1;
+ let structTreePageObjs;
+ for (const [pageIndex, elements] of newAnnotationsByPage) {
+ const page = await pdfManager.getPage(pageIndex);
+ const {
+ ref: pageRef
+ } = page;
+ const isPageRef = pageRef instanceof Ref;
+ for (const {
+ accessibilityData,
+ ref,
+ parentTreeId,
+ structTreeParent
+ } of elements) {
+ if (!accessibilityData?.type) {
+ continue;
+ }
+ const {
+ structParent
+ } = accessibilityData;
+ if (structTreeRoot && Number.isInteger(structParent) && structParent >= 0) {
+ let objs = (structTreePageObjs ||= new Map()).get(pageIndex);
+ if (objs === undefined) {
+ const structTreePage = new StructTreePage(structTreeRoot, page.pageDict);
+ objs = structTreePage.collectObjects(pageRef);
+ structTreePageObjs.set(pageIndex, objs);
+ }
+ const objRef = objs?.get(structParent);
+ if (objRef) {
+ const tagDict = xref.fetch(objRef).clone();
+ StructTreeRoot.#writeProperties(tagDict, accessibilityData);
+ changes.put(objRef, {
+ data: tagDict
+ });
+ continue;
+ }
+ }
+ nextKey = Math.max(nextKey, parentTreeId);
+ const tagRef = xref.getNewTemporaryRef();
+ const tagDict = new Dict(xref);
+ StructTreeRoot.#writeProperties(tagDict, accessibilityData);
+ await this.#updateParentTag({
+ structTreeParent,
+ tagDict,
+ newTagRef: tagRef,
+ structTreeRootRef,
+ fallbackKids: kids,
+ xref,
+ cache
+ });
+ const objDict = new Dict(xref);
+ tagDict.set("K", objDict);
+ objDict.set("Type", objr);
+ if (isPageRef) {
+ objDict.set("Pg", pageRef);
+ }
+ objDict.set("Obj", ref);
+ cache.put(tagRef, tagDict);
+ nums.push(parentTreeId, tagRef);
+ }
+ }
+ return nextKey + 1;
+ }
+ static #writeProperties(tagDict, {
+ type,
+ title,
+ lang,
+ alt,
+ expanded,
+ actualText
+ }) {
+ tagDict.set("S", Name.get(type));
+ if (title) {
+ tagDict.set("T", stringToAsciiOrUTF16BE(title));
+ }
+ if (lang) {
+ tagDict.set("Lang", stringToAsciiOrUTF16BE(lang));
+ }
+ if (alt) {
+ tagDict.set("Alt", stringToAsciiOrUTF16BE(alt));
+ }
+ if (expanded) {
+ tagDict.set("E", stringToAsciiOrUTF16BE(expanded));
+ }
+ if (actualText) {
+ tagDict.set("ActualText", stringToAsciiOrUTF16BE(actualText));
+ }
+ }
+ static #collectParents({
+ elements,
+ xref,
+ pageDict,
+ numberTree
+ }) {
+ const idToElements = new Map();
+ for (const element of elements) {
+ if (element.structTreeParentId) {
+ const id = parseInt(element.structTreeParentId.split("_mc")[1], 10);
+ idToElements.getOrInsertComputed(id, makeArr).push(element);
+ }
+ }
+ const id = pageDict.get("StructParents");
+ if (!Number.isInteger(id)) {
+ return;
+ }
+ const parentArray = numberTree.get(id);
+ const updateElement = (kid, pageKid, kidRef) => {
+ const elems = idToElements.get(kid);
+ if (elems) {
+ const parentRef = pageKid.getRaw("P");
+ const parentDict = xref.fetchIfRef(parentRef);
+ if (parentRef instanceof Ref && parentDict instanceof Dict) {
+ const params = {
+ ref: kidRef,
+ dict: pageKid
+ };
+ for (const element of elems) {
+ element.structTreeParent = params;
+ }
+ }
+ return true;
+ }
+ return false;
+ };
+ for (const kidRef of parentArray) {
+ if (!(kidRef instanceof Ref)) {
+ continue;
+ }
+ const pageKid = xref.fetch(kidRef);
+ const k = pageKid.get("K");
+ if (Number.isInteger(k)) {
+ updateElement(k, pageKid, kidRef);
+ continue;
+ }
+ if (!Array.isArray(k)) {
+ continue;
+ }
+ for (let kid of k) {
+ kid = xref.fetchIfRef(kid);
+ if (Number.isInteger(kid) && updateElement(kid, pageKid, kidRef)) {
+ break;
+ }
+ if (!(kid instanceof Dict)) {
+ continue;
+ }
+ if (!isName(kid.get("Type"), "MCR")) {
+ break;
+ }
+ const mcid = kid.get("MCID");
+ if (Number.isInteger(mcid) && updateElement(mcid, pageKid, kidRef)) {
+ break;
+ }
+ }
+ }
+ }
+ static async #updateParentTag({
+ structTreeParent,
+ tagDict,
+ newTagRef,
+ structTreeRootRef,
+ fallbackKids,
+ xref,
+ cache
+ }) {
+ let ref = null;
+ let parentRef;
+ if (structTreeParent) {
+ ({
+ ref
+ } = structTreeParent);
+ parentRef = structTreeParent.dict.getRaw("P") || structTreeRootRef;
+ } else {
+ parentRef = structTreeRootRef;
+ }
+ tagDict.set("P", parentRef);
+ const parentDict = xref.fetchIfRef(parentRef);
+ if (!parentDict) {
+ fallbackKids.push(newTagRef);
+ return;
+ }
+ const cachedParentDict = cache.getOrPutComputed(parentRef, () => parentDict.clone());
+ const parentKidsRaw = cachedParentDict.getRaw("K");
+ let cachedParentKids = parentKidsRaw instanceof Ref ? cache.get(parentKidsRaw) : null;
+ if (!cachedParentKids) {
+ cachedParentKids = xref.fetchIfRef(parentKidsRaw);
+ cachedParentKids = Array.isArray(cachedParentKids) ? cachedParentKids.slice() : [parentKidsRaw];
+ const parentKidsRef = xref.getNewTemporaryRef();
+ cachedParentDict.set("K", parentKidsRef);
+ cache.put(parentKidsRef, cachedParentKids);
+ }
+ const index = cachedParentKids.indexOf(ref);
+ cachedParentKids.splice(index >= 0 ? index + 1 : cachedParentKids.length, 0, newTagRef);
+ }
+}
+class StructElementNode {
+ constructor(tree, dict) {
+ this.tree = tree;
+ this.xref = tree.xref;
+ this.dict = dict;
+ this.kids = [];
+ this.parseKids();
+ }
+ get role() {
+ const nameObj = this.dict.get("S");
+ const name = nameObj instanceof Name ? nameObj.name : "";
+ const {
+ root
+ } = this.tree;
+ return root.roleMap.get(name) ?? name;
+ }
+ get mathML() {
+ let AFs = this.dict.get("AF") || [];
+ if (!Array.isArray(AFs)) {
+ AFs = [AFs];
+ }
+ for (let af of AFs) {
+ af = this.xref.fetchIfRef(af);
+ if (!isDict(af, "Filespec") || !isName(af.get("AFRelationship"), "Supplement")) {
+ continue;
+ }
+ const fileStream = FileSpec.pickPlatformItem(af.get("EF"));
+ if (!(fileStream instanceof BaseStream) || !isDict(fileStream.dict, "EmbeddedFile") || !isName(fileStream.dict.get("Subtype"), "application/mathml+xml")) {
+ continue;
+ }
+ return stringToUTF8String(fileStream.getString());
+ }
+ for (const attributes of this.attributes) {
+ if (isName(attributes.get("O"), "MSFT_Office")) {
+ const mathml = attributes.get("MSFT_MathML");
+ return mathml ? stringToPDFString(mathml) : null;
+ }
+ }
+ return null;
+ }
+ #collectAttributes(value, attributes) {
+ const pending = [value];
+ const visited = new RefSet();
+ while (pending.length > 0) {
+ value = pending.pop();
+ if (value instanceof Ref) {
+ if (visited.has(value)) {
+ continue;
+ }
+ visited.put(value);
+ value = this.xref.fetch(value);
+ }
+ if (value instanceof BaseStream) {
+ value = value.dict;
+ }
+ if (value instanceof Dict) {
+ attributes.push(value);
+ continue;
+ }
+ if (!Array.isArray(value)) {
+ continue;
+ }
+ for (let i = value.length - 1; i >= 0; i--) {
+ if (!Number.isInteger(value[i])) {
+ pending.push(value[i]);
+ }
+ }
+ }
+ }
+ get attributes() {
+ const attributes = [];
+ const classes = this.dict.getArray("C");
+ if (classes !== undefined) {
+ const classMap = this.tree.rootDict?.get("ClassMap");
+ if (classMap instanceof Dict) {
+ for (const className of Array.isArray(classes) ? classes : [classes]) {
+ if (className instanceof Name) {
+ this.#collectAttributes(classMap.getRaw(className.name), attributes);
+ }
+ }
+ }
+ }
+ this.#collectAttributes(this.dict.getRaw("A"), attributes);
+ return shadow(this, "attributes", attributes);
+ }
+ get tableAttributes() {
+ const {
+ role
+ } = this;
+ if (role !== "Table" && role !== "TH" && role !== "TD") {
+ return null;
+ }
+ const map = new Map();
+ for (const attributes of this.attributes) {
+ if (!isName(attributes.get("O"), "Table")) {
+ continue;
+ }
+ if (role === "Table") {
+ if (attributes.has("Summary")) {
+ const summary = attributes.get("Summary");
+ if (typeof summary === "string" && summary) {
+ map.set("summary", stringToPDFString(summary));
+ } else {
+ map.delete("summary");
+ }
+ }
+ continue;
+ }
+ for (const [key, name] of TABLE_SPAN_ATTRIBUTES) {
+ if (!attributes.has(key)) {
+ continue;
+ }
+ const value = attributes.get(key);
+ if (Number.isInteger(value) && value > 1) {
+ map.set(name, value);
+ } else {
+ map.delete(name);
+ }
+ }
+ if (attributes.has("Headers")) {
+ map.delete("headers");
+ const headers = attributes.getArray("Headers");
+ if (Array.isArray(headers)) {
+ const ids = headers.filter(header => typeof header === "string").map(stringToPDFString);
+ if (ids.length > 0) {
+ map.set("headers", ids);
+ }
+ }
+ }
+ if (role === "TH" && attributes.has("Scope")) {
+ map.delete("scope");
+ const scope = attributes.get("Scope");
+ if (scope instanceof Name && ["Row", "Column", "Both"].includes(scope.name)) {
+ map.set("scope", scope.name);
+ }
+ }
+ if (role === "TH" && attributes.has("Short")) {
+ map.delete("short");
+ const short = attributes.get("Short");
+ if (typeof short === "string" && short) {
+ map.set("short", stringToPDFString(short));
+ }
+ }
+ }
+ return map.size ? map : null;
+ }
+ parseKids() {
+ let pageObjId = null;
+ const objRef = this.dict.getRaw("Pg");
+ if (objRef instanceof Ref) {
+ pageObjId = objRef.toString();
+ }
+ const kids = this.dict.get("K");
+ if (Array.isArray(kids)) {
+ for (const kid of kids) {
+ const element = this.parseKid(pageObjId, this.xref.fetchIfRef(kid));
+ if (element) {
+ this.kids.push(element);
+ }
+ }
+ } else {
+ const element = this.parseKid(pageObjId, kids);
+ if (element) {
+ this.kids.push(element);
+ }
+ }
+ }
+ parseKid(pageObjId, kid) {
+ if (Number.isInteger(kid)) {
+ if (this.tree.pageDict.objId !== pageObjId) {
+ return null;
+ }
+ return new StructElement({
+ type: StructElementType.PAGE_CONTENT,
+ mcid: kid,
+ pageObjId
+ });
+ }
+ if (!(kid instanceof Dict)) {
+ return null;
+ }
+ const pageRef = kid.getRaw("Pg");
+ if (pageRef instanceof Ref) {
+ pageObjId = pageRef.toString();
+ }
+ const type = kid.get("Type") instanceof Name ? kid.get("Type").name : null;
+ if (type === "MCR") {
+ if (this.tree.pageDict.objId !== pageObjId) {
+ return null;
+ }
+ const kidRef = kid.getRaw("Stm");
+ return new StructElement({
+ type: StructElementType.STREAM_CONTENT,
+ refObjId: kidRef instanceof Ref ? kidRef.toString() : null,
+ pageObjId,
+ mcid: kid.get("MCID")
+ });
+ }
+ if (type === "OBJR") {
+ if (this.tree.pageDict.objId !== pageObjId) {
+ return null;
+ }
+ const kidRef = kid.getRaw("Obj");
+ return new StructElement({
+ type: StructElementType.OBJECT,
+ refObjId: kidRef instanceof Ref ? kidRef.toString() : null,
+ pageObjId
+ });
+ }
+ return new StructElement({
+ type: StructElementType.ELEMENT,
+ dict: kid
+ });
+ }
+}
+class StructElement {
+ constructor({
+ type,
+ dict = null,
+ mcid = null,
+ pageObjId = null,
+ refObjId = null
+ }) {
+ this.type = type;
+ this.dict = dict;
+ this.mcid = mcid;
+ this.pageObjId = pageObjId;
+ this.refObjId = refObjId;
+ this.parentNode = null;
+ }
+}
+class StructTreePage {
+ constructor(structTreeRoot, pageDict) {
+ this.root = structTreeRoot;
+ this.xref = structTreeRoot?.xref ?? null;
+ this.rootDict = structTreeRoot?.dict ?? null;
+ this.pageDict = pageDict;
+ this.nodes = [];
+ }
+ collectObjects(pageRef) {
+ if (!this.root || !this.rootDict || !(pageRef instanceof Ref)) {
+ return null;
+ }
+ const parentTree = this.rootDict.get("ParentTree");
+ if (!parentTree) {
+ return null;
+ }
+ const ids = this.root.structParentIds?.get(pageRef);
+ if (!ids) {
+ return null;
+ }
+ const map = new Map();
+ const numberTree = new NumberTree(parentTree, this.xref);
+ for (const [elemId] of ids) {
+ const obj = numberTree.getRaw(elemId);
+ if (obj instanceof Ref) {
+ map.set(elemId, obj);
+ }
+ }
+ return map;
+ }
+ parse(pageRef) {
+ if (!this.root || !this.rootDict || !(pageRef instanceof Ref)) {
+ return;
+ }
+ const {
+ parentTree
+ } = this.root;
+ if (!parentTree) {
+ return;
+ }
+ const id = this.pageDict.get("StructParents");
+ const ids = this.root.structParentIds?.get(pageRef);
+ if (!Number.isInteger(id) && !ids) {
+ return;
+ }
+ const map = new Map();
+ if (Number.isInteger(id)) {
+ const parentArray = parentTree.get(id);
+ if (Array.isArray(parentArray)) {
+ for (const ref of parentArray) {
+ if (ref instanceof Ref) {
+ this.addNode(this.xref.fetch(ref), map);
+ }
+ }
+ }
+ }
+ if (!ids) {
+ return;
+ }
+ for (const [elemId, type, objId] of ids) {
+ const obj = parentTree.get(elemId);
+ if (!obj) {
+ continue;
+ }
+ const elem = this.addNode(this.xref.fetchIfRef(obj), map);
+ if (!elem || !objId) {
+ continue;
+ }
+ for (const kid of elem.kids) {
+ if (kid.type === StructElementType.OBJECT && kid.refObjId === objId) {
+ kid.type = type;
+ }
+ }
+ }
+ }
+ addNode(dict, map, level = 0) {
+ if (level > MAX_DEPTH) {
+ warn("StructTree MAX_DEPTH reached.");
+ return null;
+ }
+ if (!(dict instanceof Dict)) {
+ return null;
+ }
+ if (map.has(dict)) {
+ return map.get(dict);
+ }
+ const element = new StructElementNode(this, dict);
+ map.set(dict, element);
+ switch (element.role) {
+ case "L":
+ case "LBody":
+ case "LI":
+ case "Table":
+ case "THead":
+ case "TBody":
+ case "TFoot":
+ case "TR":
+ {
+ for (const kid of element.kids) {
+ if (kid.type === StructElementType.ELEMENT) {
+ this.addNode(kid.dict, map, level - 1);
+ }
+ }
+ }
+ }
+ const parent = dict.get("P");
+ if (!(parent instanceof Dict) || isName(parent.get("Type"), "StructTreeRoot")) {
+ if (!this.addTopLevelNode(dict, element)) {
+ map.delete(dict);
+ }
+ return element;
+ }
+ const parentNode = this.addNode(parent, map, level + 1);
+ if (!parentNode) {
+ return element;
+ }
+ let save = false;
+ for (const kid of parentNode.kids) {
+ if (kid.type === StructElementType.ELEMENT && kid.dict === dict) {
+ kid.parentNode = element;
+ save = true;
+ }
+ }
+ if (!save) {
+ map.delete(dict);
+ }
+ return element;
+ }
+ addTopLevelNode(dict, element) {
+ const index = this.root.getKidPosition(dict.objId);
+ if (isNaN(index)) {
+ return false;
+ }
+ if (index !== -1) {
+ this.nodes[index] = element;
+ }
+ return true;
+ }
+ get serializable() {
+ function nodeToSerializable(node, parent, level = 0) {
+ if (level > MAX_DEPTH) {
+ warn("StructTree too deep to be fully serialized.");
+ return;
+ }
+ const obj = Object.create(null);
+ obj.role = node.role;
+ obj.children = [];
+ parent.children.push(obj);
+ let alt = node.dict.get("Alt");
+ if (typeof alt !== "string") {
+ alt = node.dict.get("ActualText");
+ }
+ if (typeof alt === "string") {
+ obj.alt = stringToPDFString(alt);
+ }
+ const structId = node.dict.get("ID");
+ if (obj.role === "TH" && typeof structId === "string" && structId) {
+ obj.structId = stringToPDFString(structId);
+ }
+ node.tableAttributes?.forEach((val, key) => {
+ obj[key] = val;
+ });
+ if (obj.role === "Formula") {
+ try {
+ const {
+ mathML
+ } = node;
+ if (mathML) {
+ obj.mathML = mathML;
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`Ignoring mathML: "${ex}".`);
+ }
+ }
+ let bbox = null,
+ size = null;
+ for (const a of node.attributes) {
+ bbox = lookupNormalRect(a.getArray("BBox"), bbox);
+ const width = a.get("Width");
+ const height = a.get("Height");
+ if (typeof width === "number" && width > 0 && typeof height === "number" && height > 0) {
+ size = [0, 0, width, height];
+ }
+ }
+ if (bbox || size) {
+ obj.bbox = bbox ?? size;
+ }
+ const lang = node.dict.get("Lang");
+ if (typeof lang === "string") {
+ obj.lang = stringToPDFString(lang);
+ }
+ for (const kid of node.kids) {
+ const kidElement = kid.type === StructElementType.ELEMENT ? kid.parentNode : null;
+ if (kidElement) {
+ nodeToSerializable(kidElement, obj, level + 1);
+ continue;
+ } else if (kid.type === StructElementType.PAGE_CONTENT || kid.type === StructElementType.STREAM_CONTENT) {
+ obj.children.push({
+ type: "content",
+ id: `p${kid.pageObjId}_mc${kid.mcid}`
+ });
+ } else if (kid.type === StructElementType.OBJECT) {
+ obj.children.push({
+ type: "object",
+ id: kid.refObjId
+ });
+ } else if (kid.type === StructElementType.ANNOTATION) {
+ obj.children.push({
+ type: "annotation",
+ id: `${AnnotationPrefix}${kid.refObjId}`
+ });
+ }
+ }
+ }
+ const root = Object.create(null);
+ root.children = [];
+ root.role = "Root";
+ for (const child of this.nodes) {
+ if (!child) {
+ continue;
+ }
+ nodeToSerializable(child, root);
+ }
+ return root;
+ }
+}
+
+;// ./src/core/catalog.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const isRef = v => v instanceof Ref;
+const isValidExplicitDest = _isValidExplicitDest.bind(null, isRef, isName);
+function fetchDest(dest) {
+ if (dest instanceof Dict) {
+ dest = dest.get("D");
+ }
+ return isValidExplicitDest(dest) ? dest : null;
+}
+function fetchRemoteDest(action) {
+ let dest = action.get("D");
+ if (dest) {
+ if (dest instanceof Name) {
+ dest = dest.name;
+ }
+ if (typeof dest === "string") {
+ return stringToPDFString(dest, true);
+ } else if (isValidExplicitDest(dest)) {
+ return JSON.stringify(dest);
+ }
+ }
+ return null;
+}
+class Catalog {
+ #actualNumPages = null;
+ #annotationAttachmentIdByRef = new RefMap();
+ #annotationAttachmentRefById = new Map();
+ #soundAttachmentIds = new Set();
+ #catDict = null;
+ builtInCMapCache = new Map();
+ fontCache = new RefMap();
+ globalColorSpaceCache = new GlobalColorSpaceCache();
+ globalImageCache = new GlobalImageCache();
+ nonBlendModesSet = new RefSet();
+ pageDictCache = new RefMap();
+ pageIndexCache = new RefMap();
+ pageKidsCountCache = new RefMap();
+ standardFontDataCache = new Map();
+ systemFontCache = new Map();
+ constructor(pdfManager, xref) {
+ this.pdfManager = pdfManager;
+ this.xref = xref;
+ this.#catDict = xref.getCatalogObj();
+ if (!(this.#catDict instanceof Dict)) {
+ throw new FormatError("Catalog object is not a dictionary.");
+ }
+ this.toplevelPagesDict;
+ }
+ cloneDict() {
+ return this.#catDict.clone();
+ }
+ getAttachmentIdForAnnotation(ref, isSound = false) {
+ let id = this.#annotationAttachmentIdByRef.get(ref);
+ if (!id) {
+ const baseId = `attachmentRef:${ref.toString()}`;
+ id = baseId;
+ let i = 1;
+ while (this.#annotationAttachmentRefById.has(id) || this.attachments?.has(id)) {
+ id = `${baseId}-${i++}`;
+ }
+ this.#annotationAttachmentIdByRef.put(ref, id);
+ this.#annotationAttachmentRefById.set(id, ref);
+ }
+ if (isSound) {
+ this.#soundAttachmentIds.add(id);
+ }
+ return id;
+ }
+ get version() {
+ const version = this.#catDict.get("Version");
+ if (version instanceof Name) {
+ if (PDF_VERSION_REGEXP.test(version.name)) {
+ return shadow(this, "version", version.name);
+ }
+ warn(`Invalid PDF catalog version: ${version.name}`);
+ }
+ return shadow(this, "version", null);
+ }
+ get lang() {
+ const lang = this.#catDict.get("Lang");
+ return shadow(this, "lang", lang && typeof lang === "string" ? stringToPDFString(lang) : null);
+ }
+ get needsRendering() {
+ const needsRendering = this.#catDict.get("NeedsRendering");
+ return shadow(this, "needsRendering", typeof needsRendering === "boolean" ? needsRendering : false);
+ }
+ get collection() {
+ let collection = null;
+ try {
+ const obj = this.#catDict.get("Collection");
+ if (obj instanceof Dict && obj.size > 0) {
+ collection = obj;
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ info("Cannot fetch Collection entry; assuming no collection is present.");
+ }
+ return shadow(this, "collection", collection);
+ }
+ get acroForm() {
+ let acroForm = null;
+ try {
+ const obj = this.#catDict.get("AcroForm");
+ if (obj instanceof Dict && obj.size > 0) {
+ acroForm = obj;
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ info("Cannot fetch AcroForm entry; assuming no forms are present.");
+ }
+ return shadow(this, "acroForm", acroForm);
+ }
+ get acroFormRef() {
+ const value = this.#catDict.getRaw("AcroForm");
+ return shadow(this, "acroFormRef", value instanceof Ref ? value : null);
+ }
+ get metadata() {
+ const streamRef = this.#catDict.getRaw("Metadata");
+ if (!(streamRef instanceof Ref)) {
+ return shadow(this, "metadata", null);
+ }
+ let metadata = null;
+ try {
+ const stream = this.xref.fetch(streamRef, !this.xref.encrypt?.encryptMetadata);
+ if (stream instanceof BaseStream && isDict(stream.dict, "Metadata") && isName(stream.dict.get("Subtype"), "XML")) {
+ const data = stringToUTF8String(stream.getString());
+ if (data) {
+ metadata = new MetadataParser(data).serializable;
+ }
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ info(`Skipping invalid Metadata: "${ex}".`);
+ }
+ return shadow(this, "metadata", metadata);
+ }
+ get markInfo() {
+ let markInfo = null;
+ try {
+ markInfo = this.#readMarkInfo();
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Unable to read mark info.");
+ }
+ return shadow(this, "markInfo", markInfo);
+ }
+ #readMarkInfo() {
+ const obj = this.#catDict.get("MarkInfo");
+ if (!(obj instanceof Dict)) {
+ return null;
+ }
+ const markInfo = new Map();
+ for (const key of ["Marked", "UserProperties", "Suspects"]) {
+ const val = obj.get(key);
+ markInfo.set(key, typeof val === "boolean" ? val : false);
+ }
+ return markInfo;
+ }
+ get hasStructTree() {
+ return this.#catDict.has("StructTreeRoot");
+ }
+ get structTreeRoot() {
+ let structTree = null;
+ try {
+ structTree = this.#readStructTreeRoot();
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Unable read to structTreeRoot info.");
+ }
+ return shadow(this, "structTreeRoot", structTree);
+ }
+ #readStructTreeRoot() {
+ const rawObj = this.#catDict.getRaw("StructTreeRoot"),
+ obj = this.xref.fetchIfRef(rawObj);
+ return obj instanceof Dict ? new StructTreeRoot(this.xref, obj, rawObj) : null;
+ }
+ get toplevelPagesDict() {
+ const pagesObj = this.#catDict.get("Pages");
+ if (!(pagesObj instanceof Dict)) {
+ throw new FormatError("Invalid top-level pages dictionary.");
+ }
+ return shadow(this, "toplevelPagesDict", pagesObj);
+ }
+ get documentOutline() {
+ let obj = null;
+ try {
+ obj = this.#readDocumentOutline();
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Unable to read document outline.");
+ }
+ return shadow(this, "documentOutline", obj);
+ }
+ #readDocumentOutline(options = {}) {
+ let obj = this.#catDict.get("Outlines");
+ if (!(obj instanceof Dict)) {
+ return null;
+ }
+ obj = obj.getRaw("First");
+ if (!(obj instanceof Ref)) {
+ return null;
+ }
+ const root = {
+ items: []
+ };
+ const queue = [{
+ obj,
+ parent: root
+ }];
+ const processed = new RefSet();
+ processed.put(obj);
+ const xref = this.xref,
+ blackColor = new Uint8ClampedArray(3);
+ while (queue.length > 0) {
+ const i = queue.shift();
+ const outlineDict = xref.fetchIfRef(i.obj);
+ if (outlineDict === null) {
+ continue;
+ }
+ if (!outlineDict.has("Title")) {
+ warn("Invalid outline item encountered.");
+ }
+ const data = {
+ url: null,
+ dest: null,
+ action: null
+ };
+ Catalog.parseDestDictionary({
+ destDict: outlineDict,
+ resultObj: data,
+ docBaseUrl: this.baseUrl,
+ docAttachments: this.attachments
+ });
+ const title = outlineDict.get("Title");
+ const flags = outlineDict.get("F") || 0;
+ const color = outlineDict.getArray("C");
+ const count = outlineDict.get("Count");
+ let rgbColor = blackColor;
+ if (isNumberArray(color, 3) && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
+ rgbColor = ColorSpaceUtils.rgb.getRgb(color, 0);
+ }
+ const outlineItem = {
+ action: data.action,
+ attachmentId: data.attachmentId,
+ attachment: data.attachment,
+ dest: data.dest,
+ url: data.url,
+ unsafeUrl: data.unsafeUrl,
+ newWindow: data.newWindow,
+ setOCGState: data.setOCGState,
+ title: typeof title === "string" ? stringToPDFString(title) : "",
+ color: rgbColor,
+ count: Number.isInteger(count) ? count : undefined,
+ bold: !!(flags & 2),
+ italic: !!(flags & 1),
+ items: []
+ };
+ if (options.keepRawDict) {
+ outlineItem.rawDict = outlineDict;
+ }
+ i.parent.items.push(outlineItem);
+ obj = outlineDict.getRaw("First");
+ if (obj instanceof Ref && !processed.has(obj)) {
+ queue.push({
+ obj,
+ parent: outlineItem
+ });
+ processed.put(obj);
+ }
+ obj = outlineDict.getRaw("Next");
+ if (obj instanceof Ref && !processed.has(obj)) {
+ queue.push({
+ obj,
+ parent: i.parent
+ });
+ processed.put(obj);
+ }
+ }
+ return root.items.length > 0 ? root.items : null;
+ }
+ get documentOutlineForEditor() {
+ let obj = null;
+ try {
+ obj = this.#readDocumentOutline({
+ keepRawDict: true
+ });
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Unable to read document outline.");
+ }
+ return shadow(this, "documentOutlineForEditor", obj);
+ }
+ get permissions() {
+ let permissions = null;
+ try {
+ permissions = this.#readPermissions();
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Unable to read permissions.");
+ }
+ return shadow(this, "permissions", permissions);
+ }
+ #readPermissions() {
+ const encrypt = this.xref.trailer.get("Encrypt");
+ if (!(encrypt instanceof Dict)) {
+ return null;
+ }
+ let flags = encrypt.get("P");
+ if (typeof flags !== "number") {
+ return null;
+ }
+ flags += 2 ** 32;
+ const permissions = new Set();
+ for (const value of Object.values(PermissionFlag)) {
+ if (flags & value) {
+ permissions.add(value);
+ }
+ }
+ return permissions;
+ }
+ get optionalContentConfig() {
+ let config = null;
+ try {
+ const properties = this.#catDict.get("OCProperties");
+ if (!properties) {
+ return shadow(this, "optionalContentConfig", null);
+ }
+ const defaultConfig = properties.get("D");
+ if (!defaultConfig) {
+ return shadow(this, "optionalContentConfig", null);
+ }
+ const groupsData = properties.get("OCGs");
+ if (!Array.isArray(groupsData)) {
+ return shadow(this, "optionalContentConfig", null);
+ }
+ const groupRefCache = new RefMap();
+ for (const groupRef of groupsData) {
+ if (!(groupRef instanceof Ref) || groupRefCache.has(groupRef)) {
+ continue;
+ }
+ groupRefCache.put(groupRef, this.#readOptionalContentGroup(groupRef));
+ }
+ config = this.#readOptionalContentConfig(defaultConfig, groupRefCache);
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`Unable to read optional content config: ${ex}`);
+ }
+ return shadow(this, "optionalContentConfig", config);
+ }
+ #readOptionalContentGroup(groupRef) {
+ const group = this.xref.fetch(groupRef);
+ const obj = {
+ id: groupRef.toString(),
+ name: null,
+ intent: null,
+ usage: {
+ print: null,
+ view: null
+ },
+ rbGroups: []
+ };
+ const name = group.get("Name");
+ if (typeof name === "string") {
+ obj.name = stringToPDFString(name);
+ }
+ let intent = group.getArray("Intent");
+ if (!Array.isArray(intent)) {
+ intent = [intent];
+ }
+ if (intent.every(i => i instanceof Name)) {
+ obj.intent = intent.map(i => i.name);
+ }
+ const usage = group.get("Usage");
+ if (!(usage instanceof Dict)) {
+ return obj;
+ }
+ const usageObj = obj.usage;
+ const print = usage.get("Print");
+ if (print instanceof Dict) {
+ const printState = print.get("PrintState");
+ if (printState instanceof Name) {
+ switch (printState.name) {
+ case "ON":
+ case "OFF":
+ usageObj.print = {
+ printState: printState.name
+ };
+ }
+ }
+ }
+ const view = usage.get("View");
+ if (view instanceof Dict) {
+ const viewState = view.get("ViewState");
+ if (viewState instanceof Name) {
+ switch (viewState.name) {
+ case "ON":
+ case "OFF":
+ usageObj.view = {
+ viewState: viewState.name
+ };
+ }
+ }
+ }
+ return obj;
+ }
+ #readOptionalContentConfig(config, groupRefCache) {
+ function parseOnOff(refs) {
+ const onParsed = [];
+ if (Array.isArray(refs)) {
+ for (const value of refs) {
+ if (value instanceof Ref && groupRefCache.has(value)) {
+ onParsed.push(value.toString());
+ }
+ }
+ }
+ return onParsed;
+ }
+ function parseOrder(refs, nestedLevels = 0) {
+ if (!Array.isArray(refs)) {
+ return null;
+ }
+ const order = [];
+ for (const value of refs) {
+ if (value instanceof Ref && groupRefCache.has(value)) {
+ parsedOrderRefs.put(value);
+ order.push(value.toString());
+ continue;
+ }
+ const nestedOrder = parseNestedOrder(value, nestedLevels);
+ if (nestedOrder) {
+ order.push(nestedOrder);
+ }
+ }
+ if (nestedLevels > 0) {
+ return order;
+ }
+ const hiddenGroups = [];
+ for (const [groupRef] of groupRefCache.items()) {
+ if (parsedOrderRefs.has(groupRef)) {
+ continue;
+ }
+ hiddenGroups.push(groupRef.toString());
+ }
+ if (hiddenGroups.length) {
+ order.push({
+ name: null,
+ order: hiddenGroups
+ });
+ }
+ return order;
+ }
+ function parseNestedOrder(ref, nestedLevels) {
+ if (++nestedLevels > MAX_NESTED_LEVELS) {
+ warn("parseNestedOrder - reached MAX_NESTED_LEVELS.");
+ return null;
+ }
+ const value = xref.fetchIfRef(ref);
+ if (!Array.isArray(value)) {
+ return null;
+ }
+ const nestedName = xref.fetchIfRef(value[0]);
+ if (typeof nestedName !== "string") {
+ return null;
+ }
+ const nestedOrder = parseOrder(value.slice(1), nestedLevels);
+ if (!nestedOrder?.length) {
+ return null;
+ }
+ return {
+ name: stringToPDFString(nestedName),
+ order: nestedOrder
+ };
+ }
+ function parseRBGroups(rbGroups) {
+ if (!Array.isArray(rbGroups)) {
+ return;
+ }
+ for (const value of rbGroups) {
+ const rbGroup = xref.fetchIfRef(value);
+ if (!Array.isArray(rbGroup) || !rbGroup.length) {
+ continue;
+ }
+ const parsedRbGroup = new Set();
+ for (const ref of rbGroup) {
+ if (ref instanceof Ref && groupRefCache.has(ref) && !parsedRbGroup.has(ref.toString())) {
+ parsedRbGroup.add(ref.toString());
+ groupRefCache.get(ref).rbGroups.push(parsedRbGroup);
+ }
+ }
+ }
+ }
+ const xref = this.xref,
+ parsedOrderRefs = new RefSet(),
+ MAX_NESTED_LEVELS = 10;
+ parseRBGroups(config.get("RBGroups"));
+ return {
+ name: typeof config.get("Name") === "string" ? stringToPDFString(config.get("Name")) : null,
+ creator: typeof config.get("Creator") === "string" ? stringToPDFString(config.get("Creator")) : null,
+ baseState: config.get("BaseState") instanceof Name ? config.get("BaseState").name : null,
+ on: parseOnOff(config.get("ON")),
+ off: parseOnOff(config.get("OFF")),
+ order: parseOrder(config.get("Order")),
+ groups: [...groupRefCache]
+ };
+ }
+ setActualNumPages(num = null) {
+ this.#actualNumPages = num;
+ }
+ get hasActualNumPages() {
+ return this.#actualNumPages !== null;
+ }
+ get _pagesCount() {
+ const obj = this.toplevelPagesDict.get("Count");
+ if (!Number.isInteger(obj)) {
+ throw new FormatError("Page count in top-level pages dictionary is not an integer.");
+ }
+ return shadow(this, "_pagesCount", obj);
+ }
+ get numPages() {
+ return this.#actualNumPages ?? this._pagesCount;
+ }
+ get destinations() {
+ const dests = new Map();
+ for (const obj of this.#readDests()) {
+ if (obj instanceof NameTree) {
+ for (const [key, value] of obj.getAll()) {
+ const dest = fetchDest(value);
+ if (dest) {
+ dests.set(stringToPDFString(key, true), dest);
+ }
+ }
+ } else if (obj instanceof Dict) {
+ for (const [key, value] of obj) {
+ const dest = fetchDest(value);
+ if (dest) {
+ dests.getOrInsert(stringToPDFString(key, true), dest);
+ }
+ }
+ }
+ }
+ return shadow(this, "destinations", dests);
+ }
+ getDestination(id) {
+ if (Object.hasOwn(this, "destinations")) {
+ return this.destinations.get(id) ?? null;
+ }
+ for (const obj of this.#readDests()) {
+ if (obj instanceof NameTree || obj instanceof Dict) {
+ const dest = fetchDest(obj.get(id));
+ if (dest) {
+ return dest;
+ }
+ }
+ }
+ return this.destinations.get(id) ?? null;
+ }
+ #readDests() {
+ const obj = this.#catDict.get("Names");
+ const rawDests = [];
+ if (obj?.has("Dests")) {
+ rawDests.push(new NameTree(obj.getRaw("Dests"), this.xref));
+ }
+ if (this.#catDict.has("Dests")) {
+ rawDests.push(this.#catDict.get("Dests"));
+ }
+ return rawDests;
+ }
+ get rawPageLabels() {
+ const obj = this.#catDict.getRaw("PageLabels");
+ if (!obj) {
+ return null;
+ }
+ const numberTree = new NumberTree(obj, this.xref);
+ return numberTree.getAll();
+ }
+ get pageLabels() {
+ let obj = null;
+ try {
+ obj = this.#readPageLabels();
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn("Unable to read page labels.");
+ }
+ return shadow(this, "pageLabels", obj);
+ }
+ #readPageLabels() {
+ const nums = this.rawPageLabels;
+ if (!nums) {
+ return null;
+ }
+ const pageLabels = new Array(this.numPages);
+ let style = null,
+ prefix = "";
+ let currentLabel = "",
+ currentIndex = 1;
+ for (let i = 0, ii = this.numPages; i < ii; i++) {
+ const labelDict = nums.get(i);
+ if (labelDict !== undefined) {
+ if (!(labelDict instanceof Dict)) {
+ throw new FormatError("PageLabel is not a dictionary.");
+ }
+ if (labelDict.has("Type") && !isName(labelDict.get("Type"), "PageLabel")) {
+ throw new FormatError("Invalid type in PageLabel dictionary.");
+ }
+ if (labelDict.has("S")) {
+ const s = labelDict.get("S");
+ if (!(s instanceof Name)) {
+ throw new FormatError("Invalid style in PageLabel dictionary.");
+ }
+ style = s.name;
+ } else {
+ style = null;
+ }
+ if (labelDict.has("P")) {
+ const p = labelDict.get("P");
+ if (typeof p !== "string") {
+ throw new FormatError("Invalid prefix in PageLabel dictionary.");
+ }
+ prefix = stringToPDFString(p);
+ } else {
+ prefix = "";
+ }
+ if (labelDict.has("St")) {
+ const st = labelDict.get("St");
+ if (!(Number.isInteger(st) && st >= 1)) {
+ throw new FormatError("Invalid start in PageLabel dictionary.");
+ }
+ currentIndex = st;
+ } else {
+ currentIndex = 1;
+ }
+ }
+ switch (style) {
+ case "D":
+ currentLabel = currentIndex;
+ break;
+ case "R":
+ case "r":
+ currentLabel = toRomanNumerals(currentIndex, style === "r");
+ break;
+ case "A":
+ case "a":
+ const LIMIT = 26;
+ const letterIndex = currentIndex - 1;
+ const character = String.fromCharCode(style.charCodeAt(0) + letterIndex % LIMIT);
+ currentLabel = character.repeat(Math.floor(letterIndex / LIMIT) + 1);
+ break;
+ default:
+ if (style) {
+ throw new FormatError(`Invalid style "${style}" in PageLabel dictionary.`);
+ }
+ currentLabel = "";
+ }
+ pageLabels[i] = prefix + currentLabel;
+ currentIndex++;
+ }
+ return pageLabels;
+ }
+ get pageLayout() {
+ const obj = this.#catDict.get("PageLayout");
+ let pageLayout = "";
+ if (obj instanceof Name) {
+ switch (obj.name) {
+ case "SinglePage":
+ case "OneColumn":
+ case "TwoColumnLeft":
+ case "TwoColumnRight":
+ case "TwoPageLeft":
+ case "TwoPageRight":
+ pageLayout = obj.name;
+ }
+ }
+ return shadow(this, "pageLayout", pageLayout);
+ }
+ get pageMode() {
+ const obj = this.#catDict.get("PageMode");
+ let pageMode = "UseNone";
+ if (obj instanceof Name) {
+ switch (obj.name) {
+ case "UseNone":
+ case "UseOutlines":
+ case "UseThumbs":
+ case "FullScreen":
+ case "UseOC":
+ case "UseAttachments":
+ pageMode = obj.name;
+ }
+ }
+ return shadow(this, "pageMode", pageMode);
+ }
+ get viewerPreferences() {
+ const obj = this.#catDict.get("ViewerPreferences");
+ if (!(obj instanceof Dict)) {
+ return shadow(this, "viewerPreferences", null);
+ }
+ let prefs = null;
+ for (const [key, value] of obj) {
+ let prefValue;
+ switch (key) {
+ case "HideToolbar":
+ case "HideMenubar":
+ case "HideWindowUI":
+ case "FitWindow":
+ case "CenterWindow":
+ case "DisplayDocTitle":
+ case "PickTrayByPDFSize":
+ if (typeof value === "boolean") {
+ prefValue = value;
+ }
+ break;
+ case "NonFullScreenPageMode":
+ if (value instanceof Name) {
+ switch (value.name) {
+ case "UseNone":
+ case "UseOutlines":
+ case "UseThumbs":
+ case "UseOC":
+ prefValue = value.name;
+ break;
+ default:
+ prefValue = "UseNone";
+ }
+ }
+ break;
+ case "Direction":
+ if (value instanceof Name) {
+ switch (value.name) {
+ case "L2R":
+ case "R2L":
+ prefValue = value.name;
+ break;
+ default:
+ prefValue = "L2R";
+ }
+ }
+ break;
+ case "ViewArea":
+ case "ViewClip":
+ case "PrintArea":
+ case "PrintClip":
+ if (value instanceof Name) {
+ switch (value.name) {
+ case "MediaBox":
+ case "CropBox":
+ case "BleedBox":
+ case "TrimBox":
+ case "ArtBox":
+ prefValue = value.name;
+ break;
+ default:
+ prefValue = "CropBox";
+ }
+ }
+ break;
+ case "PrintScaling":
+ if (value instanceof Name) {
+ switch (value.name) {
+ case "None":
+ case "AppDefault":
+ prefValue = value.name;
+ break;
+ default:
+ prefValue = "AppDefault";
+ }
+ }
+ break;
+ case "Duplex":
+ if (value instanceof Name) {
+ switch (value.name) {
+ case "Simplex":
+ case "DuplexFlipShortEdge":
+ case "DuplexFlipLongEdge":
+ prefValue = value.name;
+ break;
+ default:
+ prefValue = "None";
+ }
+ }
+ break;
+ case "PrintPageRange":
+ if (Array.isArray(value) && value.length % 2 === 0 && value.every((page, i, arr) => Number.isInteger(page) && page > 0 && (i === 0 || page >= arr[i - 1]) && page <= this.numPages)) {
+ prefValue = value;
+ }
+ break;
+ case "NumCopies":
+ if (Number.isInteger(value) && value > 0) {
+ prefValue = value;
+ }
+ break;
+ default:
+ warn(`Ignoring non-standard key in ViewerPreferences: ${key}.`);
+ continue;
+ }
+ if (prefValue === undefined) {
+ warn(`Bad value, for key "${key}", in ViewerPreferences: ${value}.`);
+ continue;
+ }
+ (prefs ??= new Map()).set(key, prefValue);
+ }
+ return shadow(this, "viewerPreferences", prefs);
+ }
+ get openAction() {
+ const obj = this.#catDict.get("OpenAction");
+ const openAction = new Map();
+ if (obj instanceof Dict) {
+ const destDict = new Dict(this.xref);
+ destDict.set("A", obj);
+ const resultObj = {
+ url: null,
+ dest: null,
+ action: null
+ };
+ Catalog.parseDestDictionary({
+ destDict,
+ resultObj
+ });
+ if (Array.isArray(resultObj.dest)) {
+ openAction.set("dest", resultObj.dest);
+ } else if (resultObj.action) {
+ openAction.set("action", resultObj.action);
+ }
+ } else if (isValidExplicitDest(obj)) {
+ openAction.set("dest", obj);
+ }
+ return shadow(this, "openAction", openAction.size ? openAction : null);
+ }
+ get attachments() {
+ const obj = this.#catDict.get("Names");
+ let attachments = null;
+ if (obj instanceof Dict && obj.has("EmbeddedFiles")) {
+ const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
+ for (const [key, value] of nameTree.getAll()) {
+ (attachments ??= new Map()).set(stringToPDFString(key, true), new FileSpec(value).serializable);
+ }
+ }
+ return shadow(this, "attachments", attachments);
+ }
+ #attachmentContentByName(id) {
+ const obj = this.#catDict.get("Names");
+ if (obj instanceof Dict && obj.has("EmbeddedFiles")) {
+ const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
+ for (const [key, value] of nameTree.getAll()) {
+ if (stringToPDFString(key, true) === id) {
+ return FileSpec.readContent(value);
+ }
+ }
+ }
+ return undefined;
+ }
+ attachmentContent(id) {
+ const namedContent = this.#attachmentContentByName(id);
+ if (namedContent !== undefined) {
+ return namedContent;
+ }
+ const ref = this.#annotationAttachmentRefById.get(id);
+ if (ref) {
+ const target = this.xref.fetch(ref);
+ if (target instanceof BaseStream) {
+ const content = FileSpec.readStreamContent(target);
+ if (this.#soundAttachmentIds.has(id)) {
+ return soundStreamToWav(target, content) ?? content;
+ }
+ return content;
+ }
+ return target instanceof Dict ? FileSpec.readContent(target) : null;
+ }
+ return null;
+ }
+ get rawEmbeddedFiles() {
+ const obj = this.#catDict.get("Names");
+ if (!(obj instanceof Dict) || !obj.has("EmbeddedFiles")) {
+ return null;
+ }
+ const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
+ return nameTree.getAll(true);
+ }
+ get xfaImages() {
+ const obj = this.#catDict.get("Names");
+ let xfaImages = null;
+ if (obj instanceof Dict && obj.has("XFAImages")) {
+ const nameTree = new NameTree(obj.getRaw("XFAImages"), this.xref);
+ for (const [key, value] of nameTree.getAll()) {
+ if (value instanceof BaseStream) {
+ xfaImages ??= new Map();
+ xfaImages.set(stringToPDFString(key, true), value.getBytes());
+ }
+ }
+ }
+ return shadow(this, "xfaImages", xfaImages);
+ }
+ #collectJavaScript() {
+ const obj = this.#catDict.get("Names");
+ let javaScript = null;
+ function appendIfJavaScriptDict(name, jsDict) {
+ if (!(jsDict instanceof Dict) || !isName(jsDict.get("S"), "JavaScript")) {
+ return;
+ }
+ let js = jsDict.get("JS");
+ if (js instanceof BaseStream) {
+ js = js.getString();
+ } else if (typeof js !== "string") {
+ return;
+ }
+ js = stringToPDFString(js, true).replaceAll("\x00", "");
+ if (js) {
+ (javaScript ??= new Map()).set(name, js);
+ }
+ }
+ if (obj instanceof Dict && obj.has("JavaScript")) {
+ const nameTree = new NameTree(obj.getRaw("JavaScript"), this.xref);
+ for (const [key, value] of nameTree.getAll()) {
+ appendIfJavaScriptDict(stringToPDFString(key, true), value);
+ }
+ }
+ const openAction = this.#catDict.get("OpenAction");
+ if (openAction) {
+ appendIfJavaScriptDict("OpenAction", openAction);
+ }
+ return javaScript;
+ }
+ get jsActions() {
+ const javaScript = this.#collectJavaScript();
+ let actions = collectActions(this.xref, this.#catDict, DocumentActionEventType);
+ if (javaScript) {
+ actions ??= new Map();
+ for (const [key, val] of javaScript) {
+ actions.getOrInsertComputed(key, makeArr).push(val);
+ }
+ }
+ return shadow(this, "jsActions", actions);
+ }
+ async cleanup(manuallyTriggered = false) {
+ clearGlobalCaches();
+ this.globalColorSpaceCache.clear();
+ this.globalImageCache.clear(manuallyTriggered);
+ this.pageKidsCountCache.clear();
+ this.pageIndexCache.clear();
+ this.pageDictCache.clear();
+ this.nonBlendModesSet.clear();
+ for (const {
+ dict
+ } of await Promise.all(this.fontCache)) {
+ delete dict.cacheKey;
+ }
+ this.fontCache.clear();
+ this.builtInCMapCache.clear();
+ this.standardFontDataCache.clear();
+ this.systemFontCache.clear();
+ }
+ async getPageDict(pageIndex) {
+ const nodesToVisit = [this.toplevelPagesDict];
+ const visitedNodes = new RefSet();
+ const pagesRef = this.#catDict.getRaw("Pages");
+ if (pagesRef instanceof Ref) {
+ visitedNodes.put(pagesRef);
+ }
+ const xref = this.xref,
+ pageKidsCountCache = this.pageKidsCountCache,
+ pageIndexCache = this.pageIndexCache,
+ pageDictCache = this.pageDictCache;
+ let currentPageIndex = 0;
+ while (nodesToVisit.length) {
+ const currentNode = nodesToVisit.pop();
+ if (currentNode instanceof Ref) {
+ const count = pageKidsCountCache.get(currentNode);
+ if (count >= 0 && currentPageIndex + count <= pageIndex) {
+ currentPageIndex += count;
+ continue;
+ }
+ if (visitedNodes.has(currentNode)) {
+ throw new FormatError("Pages tree contains circular reference.");
+ }
+ visitedNodes.put(currentNode);
+ const obj = await (pageDictCache.get(currentNode) || xref.fetchAsync(currentNode));
+ if (obj instanceof Dict) {
+ let type = obj.getRaw("Type");
+ if (type instanceof Ref) {
+ type = await xref.fetchAsync(type);
+ }
+ if (isName(type, "Page") || !obj.has("Kids")) {
+ if (!pageKidsCountCache.has(currentNode)) {
+ pageKidsCountCache.put(currentNode, 1);
+ }
+ if (!pageIndexCache.has(currentNode)) {
+ pageIndexCache.put(currentNode, currentPageIndex);
+ }
+ if (currentPageIndex === pageIndex) {
+ return [obj, currentNode];
+ }
+ currentPageIndex++;
+ continue;
+ }
+ }
+ nodesToVisit.push(obj);
+ continue;
+ }
+ if (!(currentNode instanceof Dict)) {
+ throw new FormatError("Page dictionary kid reference points to wrong type of object.");
+ }
+ const {
+ objId
+ } = currentNode;
+ let count = currentNode.getRaw("Count");
+ if (count instanceof Ref) {
+ count = await xref.fetchAsync(count);
+ }
+ if (Number.isInteger(count) && count >= 0) {
+ if (objId && !pageKidsCountCache.has(objId)) {
+ pageKidsCountCache.put(objId, count);
+ }
+ if (currentPageIndex + count <= pageIndex) {
+ currentPageIndex += count;
+ continue;
+ }
+ }
+ let kids = currentNode.getRaw("Kids");
+ if (kids instanceof Ref) {
+ kids = await xref.fetchAsync(kids);
+ }
+ if (!Array.isArray(kids)) {
+ let type = currentNode.getRaw("Type");
+ if (type instanceof Ref) {
+ type = await xref.fetchAsync(type);
+ }
+ if (isName(type, "Page") || !currentNode.has("Kids")) {
+ if (currentPageIndex === pageIndex) {
+ return [currentNode, null];
+ }
+ currentPageIndex++;
+ continue;
+ }
+ throw new FormatError("Page dictionary kids object is not an array.");
+ }
+ for (let last = kids.length - 1; last >= 0; last--) {
+ const lastKid = kids[last];
+ nodesToVisit.push(lastKid);
+ if (currentNode === this.toplevelPagesDict && lastKid instanceof Ref && !pageDictCache.has(lastKid)) {
+ pageDictCache.put(lastKid, xref.fetchAsync(lastKid));
+ }
+ }
+ }
+ throw new Error(`Page index ${pageIndex} not found.`);
+ }
+ async getAllPageDicts(recoveryMode = false) {
+ const {
+ ignoreErrors
+ } = this.pdfManager.evaluatorOptions;
+ const queue = [{
+ currentNode: this.toplevelPagesDict,
+ posInKids: 0
+ }];
+ const visitedNodes = new RefSet();
+ const pagesRef = this.#catDict.getRaw("Pages");
+ if (pagesRef instanceof Ref) {
+ visitedNodes.put(pagesRef);
+ }
+ const map = new Map(),
+ xref = this.xref,
+ pageIndexCache = this.pageIndexCache;
+ let pageIndex = 0;
+ function addPageDict(pageDict, pageRef) {
+ if (pageRef && !pageIndexCache.has(pageRef)) {
+ pageIndexCache.put(pageRef, pageIndex);
+ }
+ map.set(pageIndex++, [pageDict, pageRef]);
+ }
+ function addPageError(error) {
+ if (error instanceof XRefEntryException && !recoveryMode) {
+ throw error;
+ }
+ if (recoveryMode && ignoreErrors && pageIndex === 0) {
+ warn(`getAllPageDicts - Skipping invalid first page: "${error}".`);
+ error = Dict.empty;
+ }
+ map.set(pageIndex++, [error, null]);
+ }
+ while (queue.length > 0) {
+ const queueItem = queue.at(-1);
+ const {
+ currentNode,
+ posInKids
+ } = queueItem;
+ let kids = currentNode.getRaw("Kids");
+ if (kids instanceof Ref) {
+ try {
+ kids = await xref.fetchAsync(kids);
+ } catch (ex) {
+ addPageError(ex);
+ break;
+ }
+ }
+ if (!Array.isArray(kids)) {
+ let type = currentNode.getRaw("Type");
+ if (type instanceof Ref) {
+ try {
+ type = await xref.fetchAsync(type);
+ } catch (ex) {
+ addPageError(ex);
+ break;
+ }
+ }
+ if (isName(type, "Page") || !currentNode.has("Kids")) {
+ addPageDict(currentNode, null);
+ break;
+ }
+ addPageError(new FormatError("Page dictionary kids object is not an array."));
+ break;
+ }
+ if (posInKids >= kids.length) {
+ queue.pop();
+ continue;
+ }
+ const kidObj = kids[posInKids];
+ let obj;
+ if (kidObj instanceof Ref) {
+ if (visitedNodes.has(kidObj)) {
+ addPageError(new FormatError("Pages tree contains circular reference."));
+ break;
+ }
+ visitedNodes.put(kidObj);
+ try {
+ obj = await xref.fetchAsync(kidObj);
+ } catch (ex) {
+ addPageError(ex);
+ break;
+ }
+ } else {
+ obj = kidObj;
+ }
+ if (!(obj instanceof Dict)) {
+ addPageError(new FormatError("Page dictionary kid reference points to wrong type of object."));
+ break;
+ }
+ let type = obj.getRaw("Type");
+ if (type instanceof Ref) {
+ try {
+ type = await xref.fetchAsync(type);
+ } catch (ex) {
+ addPageError(ex);
+ break;
+ }
+ }
+ if (isName(type, "Page") || !obj.has("Kids")) {
+ addPageDict(obj, kidObj instanceof Ref ? kidObj : null);
+ } else {
+ queue.push({
+ currentNode: obj,
+ posInKids: 0
+ });
+ }
+ queueItem.posInKids++;
+ }
+ return map;
+ }
+ async getPageIndex(pageRef) {
+ const cachedPageIndex = this.pageIndexCache.get(pageRef);
+ if (cachedPageIndex !== undefined) {
+ return cachedPageIndex;
+ }
+ const xref = this.xref;
+ let total = 0,
+ ref = pageRef;
+ const visited = new RefSet();
+ visited.put(pageRef);
+ while (true) {
+ const node = await xref.fetchAsync(ref);
+ if (isRefsEqual(ref, pageRef) && !isDict(node, "Page") && !(node instanceof Dict && !node.has("Type") && node.has("Contents"))) {
+ throw new FormatError("The reference does not point to a /Page dictionary.");
+ }
+ if (!node) {
+ break;
+ }
+ if (!(node instanceof Dict)) {
+ throw new FormatError("Node must be a dictionary.");
+ }
+ const parentRef = node.getRaw("Parent");
+ if (parentRef instanceof Ref) {
+ if (visited.has(parentRef)) {
+ throw new FormatError("Pages tree contains circular reference.");
+ }
+ visited.put(parentRef);
+ }
+ const parent = await node.getAsync("Parent");
+ if (!parent) {
+ break;
+ }
+ if (!(parent instanceof Dict)) {
+ throw new FormatError("Parent must be a dictionary.");
+ }
+ const kids = await parent.getAsync("Kids");
+ if (!kids) {
+ break;
+ }
+ if (!Array.isArray(kids)) {
+ throw new FormatError("Kids must be an array.");
+ }
+ const kidPromises = [];
+ let found = false;
+ for (const kid of kids) {
+ if (!(kid instanceof Ref)) {
+ throw new FormatError("Kid must be a reference.");
+ }
+ if (isRefsEqual(kid, ref)) {
+ found = true;
+ break;
+ }
+ kidPromises.push(xref.fetchAsync(kid).then(obj => {
+ if (!(obj instanceof Dict)) {
+ throw new FormatError("Kid node must be a dictionary.");
+ }
+ if (obj.has("Count")) {
+ const count = obj.get("Count");
+ if (Number.isInteger(count) && count >= 0) {
+ total += count;
+ return;
+ }
+ throw new FormatError("Count must be a (positive) integer.");
+ }
+ total++;
+ }));
+ }
+ if (!found) {
+ throw new FormatError("Kid reference not found in parent's kids.");
+ }
+ await Promise.all(kidPromises);
+ ref = parentRef;
+ }
+ this.pageIndexCache.put(pageRef, total);
+ return total;
+ }
+ get baseUrl() {
+ const uri = this.#catDict.get("URI");
+ if (uri instanceof Dict) {
+ const base = uri.get("Base");
+ if (typeof base === "string") {
+ const absoluteUrl = createValidAbsoluteUrl(base, null, {
+ tryConvertEncoding: true
+ });
+ if (absoluteUrl) {
+ return shadow(this, "baseUrl", absoluteUrl.href);
+ }
+ }
+ }
+ return shadow(this, "baseUrl", this.pdfManager.docBaseUrl);
+ }
+ static #getDestFromStructElement(xref, seRef) {
+ const seDict = xref.fetchIfRef(seRef);
+ if (!(seDict instanceof Dict)) {
+ return null;
+ }
+ let pageRef = null;
+ const directPg = seDict.getRaw("Pg");
+ if (directPg instanceof Ref) {
+ pageRef = directPg;
+ }
+ if (!pageRef) {
+ const queue = [seDict];
+ const visited = new RefSet();
+ visited.put(seRef);
+ while (queue.length > 0 && !pageRef) {
+ const node = queue.shift();
+ let kids = node.getRaw("K");
+ if (kids instanceof Ref) {
+ if (visited.has(kids)) {
+ continue;
+ }
+ visited.put(kids);
+ kids = xref.fetch(kids);
+ }
+ let kidsArr;
+ if (Array.isArray(kids)) {
+ kidsArr = kids;
+ } else if (kids) {
+ kidsArr = [kids];
+ } else {
+ continue;
+ }
+ for (const kid of kidsArr) {
+ if (kid instanceof Ref) {
+ if (visited.has(kid)) {
+ continue;
+ }
+ visited.put(kid);
+ }
+ const kidObj = xref.fetchIfRef(kid);
+ if (!(kidObj instanceof Dict)) {
+ continue;
+ }
+ const pg = kidObj.getRaw("Pg");
+ if (pg instanceof Ref) {
+ pageRef = pg;
+ break;
+ }
+ queue.push(kidObj);
+ }
+ }
+ }
+ if (!pageRef) {
+ const MAX_DEPTH = 40;
+ let current = seDict;
+ for (let depth = 0; depth < MAX_DEPTH; depth++) {
+ const parentRaw = current.getRaw("P");
+ if (!(parentRaw instanceof Ref)) {
+ break;
+ }
+ const parentDict = xref.fetch(parentRaw);
+ if (!(parentDict instanceof Dict)) {
+ break;
+ }
+ if (isName(parentDict.get("Type"), "StructTreeRoot")) {
+ break;
+ }
+ const pg = parentDict.getRaw("Pg");
+ if (pg instanceof Ref) {
+ pageRef = pg;
+ break;
+ }
+ current = parentDict;
+ }
+ }
+ if (!pageRef) {
+ return null;
+ }
+ let x = null,
+ y = null;
+ const attrs = seDict.get("A");
+ if (attrs instanceof Dict) {
+ const bbox = lookupRect(attrs.getArray("BBox"), null);
+ if (bbox) {
+ x = bbox[0];
+ y = bbox[3];
+ }
+ }
+ return [pageRef, {
+ name: "XYZ"
+ }, x, y, null];
+ }
+ static parseDestDictionary({
+ destDict,
+ resultObj,
+ docBaseUrl = null,
+ docAttachments = null
+ }) {
+ if (!(destDict instanceof Dict)) {
+ warn("parseDestDictionary: `destDict` must be a dictionary.");
+ return;
+ }
+ let action = destDict.get("A"),
+ url,
+ dest;
+ if (!(action instanceof Dict)) {
+ if (destDict.has("Dest")) {
+ action = destDict.get("Dest");
+ } else {
+ action = destDict.get("AA");
+ if (action instanceof Dict) {
+ if (action.has("D")) {
+ action = action.get("D");
+ } else if (action.has("U")) {
+ action = action.get("U");
+ }
+ }
+ }
+ }
+ if (action instanceof Dict) {
+ const actionType = action.get("S");
+ if (!(actionType instanceof Name)) {
+ warn("parseDestDictionary: Invalid type in Action dictionary.");
+ return;
+ }
+ const actionName = actionType.name;
+ switch (actionName) {
+ case "ResetForm":
+ const flags = action.get("Flags");
+ const include = ((typeof flags === "number" ? flags : 0) & 1) === 0;
+ const fields = [];
+ const refs = [];
+ for (const obj of action.get("Fields") || []) {
+ if (obj instanceof Ref) {
+ refs.push(obj.toString());
+ } else if (typeof obj === "string") {
+ fields.push(stringToPDFString(obj));
+ }
+ }
+ resultObj.resetForm = {
+ fields,
+ refs,
+ include
+ };
+ break;
+ case "URI":
+ url = action.get("URI");
+ if (url instanceof Name) {
+ url = "/" + url.name;
+ }
+ break;
+ case "GoTo":
+ dest = action.get("D");
+ break;
+ case "Launch":
+ case "GoToR":
+ const urlDict = action.get("F");
+ if (urlDict instanceof Dict) {
+ url = new FileSpec(urlDict).filename;
+ } else if (typeof urlDict === "string") {
+ url = urlDict;
+ } else {
+ break;
+ }
+ const remoteDest = fetchRemoteDest(action);
+ if (remoteDest) {
+ url = url.split("#", 1)[0] + "#" + remoteDest;
+ }
+ const newWindow = action.get("NewWindow");
+ if (typeof newWindow === "boolean") {
+ resultObj.newWindow = newWindow;
+ }
+ break;
+ case "GoToE":
+ const target = action.get("T");
+ let id = null;
+ if (target instanceof Dict) {
+ const relationship = target.get("R");
+ const name = target.get("N");
+ if (isName(relationship, "C") && typeof name === "string") {
+ id = stringToPDFString(name, true);
+ }
+ }
+ if (docAttachments && id) {
+ resultObj.attachmentId = id;
+ resultObj.attachment = docAttachments.get(id);
+ const attachmentDest = fetchRemoteDest(action);
+ if (attachmentDest) {
+ resultObj.attachmentDest = attachmentDest;
+ }
+ } else {
+ warn(`parseDestDictionary - unimplemented "GoToE" action.`);
+ }
+ break;
+ case "Named":
+ const namedAction = action.get("N");
+ if (namedAction instanceof Name) {
+ resultObj.action = namedAction.name;
+ }
+ break;
+ case "SetOCGState":
+ const state = action.get("State");
+ const preserveRB = action.get("PreserveRB");
+ if (!Array.isArray(state) || state.length === 0) {
+ break;
+ }
+ const stateArr = [];
+ for (const elem of state) {
+ if (elem instanceof Name) {
+ switch (elem.name) {
+ case "ON":
+ case "OFF":
+ case "Toggle":
+ stateArr.push(elem.name);
+ break;
+ }
+ } else if (elem instanceof Ref) {
+ stateArr.push(elem.toString());
+ }
+ }
+ if (stateArr.length !== state.length) {
+ break;
+ }
+ resultObj.setOCGState = {
+ state: stateArr,
+ preserveRB: typeof preserveRB === "boolean" ? preserveRB : true
+ };
+ break;
+ case "JavaScript":
+ const jsAction = action.get("JS");
+ let js;
+ if (jsAction instanceof BaseStream) {
+ js = jsAction.getString();
+ } else if (typeof jsAction === "string") {
+ js = jsAction;
+ }
+ const jsURL = js && recoverJsURL(stringToPDFString(js, true));
+ if (jsURL) {
+ url = jsURL.url;
+ resultObj.newWindow = jsURL.newWindow;
+ break;
+ }
+ default:
+ if (actionName === "JavaScript" || actionName === "SubmitForm") {
+ break;
+ }
+ warn(`parseDestDictionary - unsupported action: "${actionName}".`);
+ break;
+ }
+ } else if (destDict.has("Dest")) {
+ dest = destDict.get("Dest");
+ }
+ if (typeof url === "string") {
+ const absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl, {
+ addDefaultProtocol: true,
+ tryConvertEncoding: true
+ });
+ if (absoluteUrl) {
+ resultObj.url = absoluteUrl.href;
+ }
+ resultObj.unsafeUrl = url;
+ }
+ if (dest) {
+ if (dest instanceof Name) {
+ dest = dest.name;
+ }
+ if (typeof dest === "string") {
+ resultObj.dest = stringToPDFString(dest, true);
+ } else if (isValidExplicitDest(dest)) {
+ resultObj.dest = dest;
+ }
+ }
+ if (!resultObj.dest && !resultObj.url && !resultObj.action && !resultObj.attachment && !resultObj.setOCGState && !resultObj.resetForm) {
+ const seRef = destDict.getRaw("SE");
+ if (seRef instanceof Ref) {
+ try {
+ const seDest = Catalog.#getDestFromStructElement(destDict.xref, seRef);
+ if (seDest) {
+ resultObj.dest = seDest;
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ info("SE parsing failed.");
+ }
+ }
+ }
+ }
+}
+
+;// ./src/core/editor/pdf_images.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const FLATE_COLOR_COUNT_THRESHOLD = 16384;
+function createImageDict(xref, width, height, colorSpace) {
+ const image = new Dict(xref);
+ image.set("Type", Name.get("XObject"));
+ image.set("Subtype", Name.get("Image"));
+ image.set("BitsPerComponent", 8);
+ image.setIfName("ColorSpace", colorSpace);
+ image.set("Width", width);
+ image.set("Height", height);
+ return image;
+}
+function createRawImage(buffer, dict) {
+ return new Stream(buffer, 0, buffer.length, dict);
+}
+function paethPredictor(left, above, upperLeft) {
+ const p = left + above - upperLeft;
+ const pa = Math.abs(p - left);
+ const pb = Math.abs(p - above);
+ const pc = Math.abs(p - upperLeft);
+ if (pa <= pb && pa <= pc) {
+ return left;
+ }
+ return pb <= pc ? above : upperLeft;
+}
+function applyPNGOptimumFilter(data, width, height, bytesPerPixel) {
+ const rowSize = width * bytesPerPixel;
+ const out = new Uint8Array(height * (rowSize + 1));
+ const candidates = [new Uint8Array(rowSize), new Uint8Array(rowSize), new Uint8Array(rowSize), new Uint8Array(rowSize), new Uint8Array(rowSize)];
+ for (let y = 0; y < height; y++) {
+ const rowOffset = y * rowSize;
+ const prevRowOffset = rowOffset - rowSize;
+ const scores = [0, 0, 0, 0, 0];
+ for (let x = 0; x < rowSize; x++) {
+ const offset = rowOffset + x;
+ const cur = data[offset];
+ const left = x >= bytesPerPixel ? data[offset - bytesPerPixel] : 0;
+ const above = y > 0 ? data[prevRowOffset + x] : 0;
+ const upperLeft = y > 0 && x >= bytesPerPixel ? data[prevRowOffset + x - bytesPerPixel] : 0;
+ candidates[0][x] = cur;
+ candidates[1][x] = cur - left & 0xff;
+ candidates[2][x] = cur - above & 0xff;
+ candidates[3][x] = cur - (left + above >> 1) & 0xff;
+ candidates[4][x] = cur - paethPredictor(left, above, upperLeft) & 0xff;
+ for (let f = 0; f < 5; f++) {
+ const v = candidates[f][x];
+ scores[f] += v < 128 ? v : 256 - v;
+ }
+ }
+ let bestFilter = 0;
+ for (let f = 1; f < 5; f++) {
+ if (scores[f] < scores[bestFilter]) {
+ bestFilter = f;
+ }
+ }
+ const outOffset = y * (rowSize + 1);
+ out[outOffset] = bestFilter;
+ out.set(candidates[bestFilter], outOffset + 1);
+ }
+ return out;
+}
+async function deflate(bytes) {
+ const cs = new CompressionStream("deflate");
+ const writer = cs.writable.getWriter();
+ const writePromise = (async () => {
+ try {
+ await writer.ready;
+ await writer.write(bytes);
+ await writer.ready;
+ await writer.close();
+ } catch (reason) {
+ await writer.abort(reason).catch(() => {});
+ throw reason;
+ }
+ })();
+ const [compressed] = await Promise.all([new Response(cs.readable).bytes(), writePromise.then(() => null)]);
+ return compressed;
+}
+async function createPNGLikeImage(buffer, width, height, dict) {
+ const bytesPerPixel = buffer.length / (width * height);
+ let compressed;
+ if (typeof CompressionStream === "function") {
+ try {
+ const filtered = applyPNGOptimumFilter(buffer, width, height, bytesPerPixel);
+ compressed = await deflate(filtered);
+ } catch {}
+ }
+ if (!compressed) {
+ return createRawImage(buffer, dict);
+ }
+ dict.setIfName("Filter", "FlateDecode");
+ const decodeParms = new Dict(dict.xref);
+ decodeParms.set("Predictor", 15);
+ decodeParms.set("Columns", width);
+ decodeParms.set("Colors", bytesPerPixel);
+ decodeParms.set("BitsPerComponent", 8);
+ dict.set("DecodeParms", decodeParms);
+ return createRawImage(compressed, dict);
+}
+async function createImage(bitmap, xref, {
+ closeBitmap = false
+} = {}) {
+ const {
+ width,
+ height
+ } = bitmap;
+ if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {
+ if (closeBitmap) {
+ bitmap.close?.();
+ }
+ throw new Error(`createImage: invalid bitmap dimensions ${width}x${height}`);
+ }
+ const canvas = new OffscreenCanvas(width, height);
+ const ctx = canvas.getContext("2d", {
+ alpha: true,
+ willReadFrequently: true
+ });
+ let data;
+ try {
+ ctx.drawImage(bitmap, 0, 0);
+ data = ctx.getImageData(0, 0, width, height).data;
+ } finally {
+ if (closeBitmap) {
+ bitmap.close?.();
+ }
+ }
+ const buf32 = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);
+ const isLE = FeatureTest.isLittleEndian;
+ const rgbMask = isLE ? 0x00ffffff : 0xffffff00;
+ const colorCounter = new Set();
+ let hasAlpha = false;
+ let useFlate = true;
+ for (const v of buf32) {
+ if ((isLE ? v >>> 24 : v & 0xff) !== 0xff) {
+ hasAlpha = true;
+ break;
+ }
+ if (useFlate) {
+ colorCounter.add((v & rgbMask) >>> 0);
+ if (colorCounter.size > FLATE_COLOR_COUNT_THRESHOLD) {
+ useFlate = false;
+ colorCounter.clear();
+ }
+ }
+ }
+ if (hasAlpha) {
+ useFlate = true;
+ }
+ const image = createImageDict(xref, width, height, "DeviceRGB");
+ let imageStreamPromise;
+ let imageRenderStream = null;
+ if (useFlate) {
+ const rgbBuffer = new Uint8Array(width * height * 3);
+ for (let i = 0, j = 0, ii = data.length; i < ii; i += 4, j += 3) {
+ rgbBuffer[j] = data[i];
+ rgbBuffer[j + 1] = data[i + 1];
+ rgbBuffer[j + 2] = data[i + 2];
+ }
+ imageStreamPromise = createPNGLikeImage(rgbBuffer, width, height, image);
+ imageRenderStream = createRawImage(rgbBuffer, createImageDict(xref, width, height, "DeviceRGB"));
+ } else {
+ image.setIfName("Filter", "DCTDecode");
+ imageStreamPromise = canvas.convertToBlob({
+ type: "image/jpeg",
+ quality: 1
+ }).then(blob => blob.bytes()).then(bytes => createRawImage(bytes, image));
+ }
+ let smaskStreamPromise = Promise.resolve(null);
+ let smaskRenderStream = null;
+ if (hasAlpha) {
+ const alphaBuffer = new Uint8Array(buf32.length);
+ if (isLE) {
+ for (let i = 0, ii = buf32.length; i < ii; i++) {
+ alphaBuffer[i] = buf32[i] >>> 24;
+ }
+ } else {
+ for (let i = 0, ii = buf32.length; i < ii; i++) {
+ alphaBuffer[i] = buf32[i] & 0xff;
+ }
+ }
+ const smask = createImageDict(xref, width, height, "DeviceGray");
+ const smaskRenderDict = createImageDict(xref, width, height, "DeviceGray");
+ smaskStreamPromise = createPNGLikeImage(alphaBuffer, width, height, smask);
+ smaskRenderStream = createRawImage(alphaBuffer, smaskRenderDict);
+ }
+ const [imageStream, smaskStream] = await Promise.all([imageStreamPromise, smaskStreamPromise]);
+ return {
+ imageStream,
+ imageRenderStream,
+ smaskStream,
+ smaskRenderStream,
+ width,
+ height
+ };
+}
+
+;// ./src/core/object_loader.js
+
+
+
+
+
+function mayHaveChildren(value) {
+ return value instanceof Ref || value instanceof Dict || value instanceof BaseStream || Array.isArray(value);
+}
+function addChildren(node, nodesToVisit) {
+ if (node instanceof Dict) {
+ node = node.getRawValues();
+ } else if (node instanceof BaseStream) {
+ node = node.dict.getRawValues();
+ } else if (!Array.isArray(node)) {
+ return;
+ }
+ for (const rawValue of node) {
+ if (mayHaveChildren(rawValue)) {
+ nodesToVisit.push(rawValue);
+ }
+ }
+}
+class ObjectLoader {
+ refSet = new RefSet();
+ constructor(dict, keys, xref) {
+ this.dict = dict;
+ this.keys = keys;
+ this.xref = xref;
+ }
+ async load() {
+ const {
+ keys,
+ dict
+ } = this;
+ const nodesToVisit = [];
+ for (const key of keys) {
+ const rawValue = dict.getRaw(key);
+ if (rawValue !== undefined) {
+ nodesToVisit.push(rawValue);
+ }
+ }
+ await this.#walk(nodesToVisit);
+ this.refSet = null;
+ }
+ async #walk(nodesToVisit) {
+ const nodesToRevisit = [];
+ const pendingRequests = [];
+ while (nodesToVisit.length) {
+ let currentNode = nodesToVisit.pop();
+ if (currentNode instanceof Ref) {
+ if (this.refSet.has(currentNode)) {
+ continue;
+ }
+ try {
+ this.refSet.put(currentNode);
+ currentNode = this.xref.fetch(currentNode);
+ } catch (ex) {
+ if (!(ex instanceof MissingDataException)) {
+ warn(`ObjectLoader.#walk - requesting all data: "${ex}".`);
+ await this.xref.stream.manager.requestAllChunks();
+ return;
+ }
+ nodesToRevisit.push(currentNode);
+ pendingRequests.push({
+ begin: ex.begin,
+ end: ex.end
+ });
+ }
+ }
+ if (currentNode instanceof BaseStream) {
+ const baseStreams = currentNode.getBaseStreams();
+ if (baseStreams) {
+ let foundMissingData = false;
+ for (const stream of baseStreams) {
+ if (stream.isDataLoaded) {
+ continue;
+ }
+ foundMissingData = true;
+ pendingRequests.push({
+ begin: stream.start,
+ end: stream.end
+ });
+ }
+ if (foundMissingData) {
+ nodesToRevisit.push(currentNode);
+ }
+ }
+ }
+ addChildren(currentNode, nodesToVisit);
+ }
+ if (pendingRequests.length) {
+ await this.xref.stream.manager.requestRanges(pendingRequests);
+ for (const node of nodesToRevisit) {
+ if (node instanceof Ref) {
+ this.refSet.remove(node);
+ }
+ }
+ await this.#walk(nodesToRevisit);
+ }
+ }
+ static async load(obj, keys, xref) {
+ if (xref.stream.isDataLoaded) {
+ return;
+ }
+ const objLoader = new ObjectLoader(obj, keys, xref);
+ await objLoader.load();
+ }
+}
+
+;// ./src/core/xfa/symbol_utils.js
+const $acceptWhitespace = Symbol();
+const $addHTML = Symbol();
+const $appendChild = Symbol();
+const $childrenToHTML = Symbol();
+const $clean = Symbol();
+const $cleanPage = Symbol();
+const $cleanup = Symbol();
+const $clone = Symbol();
+const $consumed = Symbol();
+const $content = Symbol("content");
+const $data = Symbol("data");
+const $dump = Symbol();
+const $extra = Symbol("extra");
+const $finalize = Symbol();
+const $flushHTML = Symbol();
+const $getAttributeIt = Symbol();
+const $getAttributes = Symbol();
+const $getAvailableSpace = Symbol();
+const $getChildrenByClass = Symbol();
+const $getChildrenByName = Symbol();
+const $getChildrenByNameIt = Symbol();
+const $getDataValue = Symbol();
+const $getExtra = Symbol();
+const $getRealChildrenByNameIt = Symbol();
+const $getChildren = Symbol();
+const $getContainedChildren = Symbol();
+const $getNextPage = Symbol();
+const $getSubformParent = Symbol();
+const $getParent = Symbol();
+const $getTemplateRoot = Symbol();
+const $globalData = Symbol();
+const $hasSettableValue = Symbol();
+const $ids = Symbol();
+const $indexOf = Symbol();
+const $insertAt = Symbol();
+const $isCDATAXml = Symbol();
+const $isBindable = Symbol();
+const $isDataValue = Symbol();
+const $isDescendent = Symbol();
+const $isNsAgnostic = Symbol();
+const $isSplittable = Symbol();
+const $isThereMoreWidth = Symbol();
+const $isTransparent = Symbol();
+const $isUsable = Symbol();
+const $lastAttribute = Symbol();
+const $namespaceId = Symbol("namespaceId");
+const $nodeName = Symbol("nodeName");
+const $nsAttributes = Symbol();
+const $onChild = Symbol();
+const $onChildCheck = Symbol();
+const $onText = Symbol();
+const $pushGlyphs = Symbol();
+const $popPara = Symbol();
+const $pushPara = Symbol();
+const $removeChild = Symbol();
+const $root = Symbol("root");
+const $resolvePrototypes = Symbol();
+const $searchNode = Symbol();
+const $setId = Symbol();
+const $setSetAttributes = Symbol();
+const $setValue = Symbol();
+const $tabIndex = Symbol();
+const $text = Symbol();
+const $toPages = Symbol();
+const $toHTML = Symbol();
+const $toString = Symbol();
+const $toStyle = Symbol();
+const $uid = Symbol("uid");
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.flat-map.js
+var es_iterator_flat_map = __webpack_require__(531);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.uint8-array.from-base64.js
+var es_uint8_array_from_base64 = __webpack_require__(5213);
+;// ./src/core/xfa/namespaces.js
+const $buildXFAObject = Symbol();
+const NamespaceIds = {
+ config: {
+ id: 0,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xci/")
+ },
+ connectionSet: {
+ id: 1,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-connection-set/")
+ },
+ datasets: {
+ id: 2,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-data/")
+ },
+ form: {
+ id: 3,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-form/")
+ },
+ localeSet: {
+ id: 4,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-locale-set/")
+ },
+ pdf: {
+ id: 5,
+ check: ns => ns === "http://ns.adobe.com/xdp/pdf/"
+ },
+ signature: {
+ id: 6,
+ check: ns => ns === "http://www.w3.org/2000/09/xmldsig#"
+ },
+ sourceSet: {
+ id: 7,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-source-set/")
+ },
+ stylesheet: {
+ id: 8,
+ check: ns => ns === "http://www.w3.org/1999/XSL/Transform"
+ },
+ template: {
+ id: 9,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xfa-template/")
+ },
+ xdc: {
+ id: 10,
+ check: ns => ns.startsWith("http://www.xfa.org/schema/xdc/")
+ },
+ xdp: {
+ id: 11,
+ check: ns => ns === "http://ns.adobe.com/xdp/"
+ },
+ xfdf: {
+ id: 12,
+ check: ns => ns === "http://ns.adobe.com/xfdf/"
+ },
+ xhtml: {
+ id: 13,
+ check: ns => ns === "http://www.w3.org/1999/xhtml"
+ },
+ xmpmeta: {
+ id: 14,
+ check: ns => ns === "http://ns.adobe.com/xmpmeta/"
+ }
+};
+
+;// ./src/core/xfa/utils.js
+
+
+
+
+
+
+
+const dimConverters = {
+ pt: x => x,
+ cm: x => x / 2.54 * 72,
+ mm: x => x / (10 * 2.54) * 72,
+ in: x => x * 72,
+ px: x => x
+};
+const measurementPattern = /([+-]?\d+\.?\d*)(.*)/;
+function stripQuotes(str) {
+ if (str.startsWith("'") || str.startsWith('"')) {
+ return str.slice(1, -1);
+ }
+ return str;
+}
+function getInteger({
+ data,
+ defaultValue,
+ validate
+}) {
+ if (!data) {
+ return defaultValue;
+ }
+ data = data.trim();
+ const n = parseInt(data, 10);
+ if (!isNaN(n) && validate(n)) {
+ return n;
+ }
+ return defaultValue;
+}
+function getFloat({
+ data,
+ defaultValue,
+ validate
+}) {
+ if (!data) {
+ return defaultValue;
+ }
+ data = data.trim();
+ const n = parseFloat(data);
+ if (!isNaN(n) && validate(n)) {
+ return n;
+ }
+ return defaultValue;
+}
+function getKeyword({
+ data,
+ defaultValue,
+ validate
+}) {
+ if (!data) {
+ return defaultValue;
+ }
+ data = data.trim();
+ if (validate(data)) {
+ return data;
+ }
+ return defaultValue;
+}
+function getStringOption(data, options) {
+ return getKeyword({
+ data,
+ defaultValue: options[0],
+ validate: k => options.includes(k)
+ });
+}
+function getMeasurement(str, def = "0") {
+ def ||= "0";
+ if (!str) {
+ return getMeasurement(def);
+ }
+ const match = str.trim().match(measurementPattern);
+ if (!match) {
+ return getMeasurement(def);
+ }
+ const [, valueStr, unit] = match;
+ const value = parseFloat(valueStr);
+ if (isNaN(value)) {
+ return getMeasurement(def);
+ }
+ if (value === 0) {
+ return 0;
+ }
+ const conv = dimConverters[unit];
+ if (conv) {
+ return conv(value);
+ }
+ return value;
+}
+function getRatio(data) {
+ if (!data) {
+ return {
+ num: 1,
+ den: 1
+ };
+ }
+ const ratio = data.split(":", 2).map(x => parseFloat(x.trim())).filter(x => !isNaN(x));
+ if (ratio.length === 1) {
+ ratio.push(1);
+ }
+ if (ratio.length === 0) {
+ return {
+ num: 1,
+ den: 1
+ };
+ }
+ const [num, den] = ratio;
+ return {
+ num,
+ den
+ };
+}
+function getRelevant(data) {
+ if (!data) {
+ return [];
+ }
+ return data.trim().split(/\s+/).map(e => ({
+ excluded: e[0] === "-",
+ viewname: e.substring(1)
+ }));
+}
+function getColor(data, def = [0, 0, 0]) {
+ let [r, g, b] = def;
+ if (!data) {
+ return {
+ r,
+ g,
+ b
+ };
+ }
+ const color = data.split(",", 3).map(c => {
+ c = parseInt(c.trim(), 10);
+ return isNaN(c) ? 0 : MathClamp(c, 0, 255);
+ });
+ if (color.length < 3) {
+ return {
+ r,
+ g,
+ b
+ };
+ }
+ [r, g, b] = color;
+ return {
+ r,
+ g,
+ b
+ };
+}
+function getBBox(data) {
+ const def = -1;
+ if (!data) {
+ return {
+ x: def,
+ y: def,
+ width: def,
+ height: def
+ };
+ }
+ const bbox = data.split(",", 4).map(m => getMeasurement(m.trim(), "-1"));
+ if (bbox.length < 4 || bbox[2] < 0 || bbox[3] < 0) {
+ return {
+ x: def,
+ y: def,
+ width: def,
+ height: def
+ };
+ }
+ const [x, y, width, height] = bbox;
+ return {
+ x,
+ y,
+ width,
+ height
+ };
+}
+class HTMLResult {
+ static get FAILURE() {
+ return shadow(this, "FAILURE", new HTMLResult(false, null, null, null));
+ }
+ static get EMPTY() {
+ return shadow(this, "EMPTY", new HTMLResult(true, null, null, null));
+ }
+ constructor(success, html, bbox, breakNode) {
+ this.success = success;
+ this.html = html;
+ this.bbox = bbox;
+ this.breakNode = breakNode;
+ }
+ isBreak() {
+ return !!this.breakNode;
+ }
+ static breakNode(node) {
+ return new HTMLResult(false, null, null, node);
+ }
+ static success(html, bbox = null) {
+ return new HTMLResult(true, html, bbox, null);
+ }
+}
+
+;// ./src/core/xfa/fonts.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class FontFinder {
+ constructor(pdfFonts) {
+ this.fonts = new Map();
+ this.cache = new Map();
+ this.warned = new Set();
+ this.defaultFont = null;
+ this.add(pdfFonts);
+ }
+ add(pdfFonts, reallyMissingFonts = null) {
+ for (const pdfFont of pdfFonts) {
+ this.addPdfFont(pdfFont);
+ }
+ for (const pdfFont of this.fonts.values()) {
+ pdfFont.regular ||= pdfFont.italic || pdfFont.bold || pdfFont.bolditalic;
+ }
+ if (!reallyMissingFonts || reallyMissingFonts.size === 0) {
+ return;
+ }
+ const myriad = this.fonts.get("PdfJS-Fallback-PdfJS-XFA");
+ for (const missing of reallyMissingFonts) {
+ this.fonts.set(missing, myriad);
+ }
+ }
+ addPdfFont(pdfFont) {
+ const cssFontInfo = pdfFont.cssFontInfo;
+ const name = cssFontInfo.fontFamily;
+ const font = this.fonts.getOrInsertComputed(name, makeObj);
+ this.defaultFont ??= font;
+ let property = "";
+ const fontWeight = parseFloat(cssFontInfo.fontWeight);
+ if (parseFloat(cssFontInfo.italicAngle) !== 0) {
+ property = fontWeight >= 700 ? "bolditalic" : "italic";
+ } else if (fontWeight >= 700) {
+ property = "bold";
+ }
+ if (!property) {
+ if (pdfFont.name.includes("Bold") || pdfFont.psName?.includes("Bold")) {
+ property = "bold";
+ }
+ if (pdfFont.name.includes("Italic") || pdfFont.name.endsWith("It") || pdfFont.psName?.includes("Italic") || pdfFont.psName?.endsWith("It")) {
+ property += "italic";
+ }
+ }
+ property ||= "regular";
+ font[property] = pdfFont;
+ }
+ getDefault() {
+ return this.defaultFont;
+ }
+ find(fontName, mustWarn = true) {
+ let font = this.fonts.get(fontName) || this.cache.get(fontName);
+ if (font) {
+ return font;
+ }
+ const pattern = /[,\-_ ]|bolditalic|bold|italic|regular|it/gi;
+ let name = fontName.replaceAll(pattern, "");
+ font = this.fonts.get(name);
+ if (font) {
+ this.cache.set(fontName, font);
+ return font;
+ }
+ name = name.toLowerCase();
+ const maybe = [];
+ for (const [family, pdfFont] of this.fonts) {
+ if (family.replaceAll(pattern, "").toLowerCase().startsWith(name)) {
+ maybe.push(pdfFont);
+ }
+ }
+ if (maybe.length === 0) {
+ for (const pdfFont of this.fonts.values()) {
+ if (pdfFont.regular.name?.replaceAll(pattern, "").toLowerCase().startsWith(name)) {
+ maybe.push(pdfFont);
+ }
+ }
+ }
+ if (maybe.length === 0) {
+ name = name.replaceAll(/psmt|mt/gi, "");
+ for (const [family, pdfFont] of this.fonts) {
+ if (family.replaceAll(pattern, "").toLowerCase().startsWith(name)) {
+ maybe.push(pdfFont);
+ }
+ }
+ }
+ if (maybe.length === 0) {
+ for (const pdfFont of this.fonts.values()) {
+ if (pdfFont.regular.name?.replaceAll(pattern, "").toLowerCase().startsWith(name)) {
+ maybe.push(pdfFont);
+ }
+ }
+ }
+ if (maybe.length >= 1) {
+ if (maybe.length !== 1 && mustWarn) {
+ warn(`XFA - Too many choices to guess the correct font: ${fontName}`);
+ }
+ this.cache.set(fontName, maybe[0]);
+ return maybe[0];
+ }
+ if (mustWarn && !this.warned.has(fontName)) {
+ this.warned.add(fontName);
+ warn(`XFA - Cannot find the font: ${fontName}`);
+ }
+ return null;
+ }
+}
+function selectFont(xfaFont, typeface) {
+ if (xfaFont.posture === "italic") {
+ return xfaFont.weight === "bold" ? typeface.bolditalic : typeface.italic;
+ } else if (xfaFont.weight === "bold") {
+ return typeface.bold;
+ }
+ return typeface.regular;
+}
+function fonts_getMetrics(xfaFont, real = false) {
+ let pdfFont = null;
+ if (xfaFont) {
+ const name = stripQuotes(xfaFont.typeface);
+ const typeface = xfaFont[$globalData].fontFinder.find(name);
+ pdfFont = selectFont(xfaFont, typeface);
+ }
+ if (!pdfFont) {
+ return {
+ lineHeight: 12,
+ lineGap: 2,
+ lineNoGap: 10
+ };
+ }
+ const size = xfaFont.size || 10;
+ const lineHeight = pdfFont.lineHeight ? Math.max(real ? 0 : 1.2, pdfFont.lineHeight) : 1.2;
+ const lineGap = pdfFont.lineGap === undefined ? 0.2 : pdfFont.lineGap;
+ return {
+ lineHeight: lineHeight * size,
+ lineGap: lineGap * size,
+ lineNoGap: Math.max(1, lineHeight - lineGap) * size
+ };
+}
+
+;// ./src/core/xfa/text.js
+
+
+
+
+const WIDTH_FACTOR = 1.02;
+class FontInfo {
+ constructor(xfaFont, margin, lineHeight, fontFinder) {
+ this.lineHeight = lineHeight;
+ this.paraMargin = margin || {
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0
+ };
+ if (!xfaFont) {
+ [this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder);
+ return;
+ }
+ this.xfaFont = {
+ typeface: xfaFont.typeface,
+ posture: xfaFont.posture,
+ weight: xfaFont.weight,
+ size: xfaFont.size,
+ letterSpacing: xfaFont.letterSpacing
+ };
+ const typeface = fontFinder.find(xfaFont.typeface);
+ if (!typeface) {
+ [this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder);
+ return;
+ }
+ this.pdfFont = selectFont(xfaFont, typeface);
+ if (!this.pdfFont) {
+ [this.pdfFont, this.xfaFont] = this.defaultFont(fontFinder);
+ }
+ }
+ defaultFont(fontFinder) {
+ const font = fontFinder.find("Helvetica", false) || fontFinder.find("Myriad Pro", false) || fontFinder.find("Arial", false) || fontFinder.getDefault();
+ if (font?.regular) {
+ const pdfFont = font.regular;
+ const info = pdfFont.cssFontInfo;
+ const xfaFont = {
+ typeface: info.fontFamily,
+ posture: "normal",
+ weight: "normal",
+ size: 10,
+ letterSpacing: 0
+ };
+ return [pdfFont, xfaFont];
+ }
+ const xfaFont = {
+ typeface: "Courier",
+ posture: "normal",
+ weight: "normal",
+ size: 10,
+ letterSpacing: 0
+ };
+ return [null, xfaFont];
+ }
+}
+class FontSelector {
+ constructor(defaultXfaFont, defaultParaMargin, defaultLineHeight, fontFinder) {
+ this.fontFinder = fontFinder;
+ this.stack = [new FontInfo(defaultXfaFont, defaultParaMargin, defaultLineHeight, fontFinder)];
+ }
+ pushData(xfaFont, margin, lineHeight) {
+ const lastFont = this.stack.at(-1);
+ for (const name of ["typeface", "posture", "weight", "size", "letterSpacing"]) {
+ xfaFont[name] ||= lastFont.xfaFont[name];
+ }
+ for (const name of ["top", "bottom", "left", "right"]) {
+ if (isNaN(margin[name])) {
+ margin[name] = lastFont.paraMargin[name];
+ }
+ }
+ const fontInfo = new FontInfo(xfaFont, margin, lineHeight || lastFont.lineHeight, this.fontFinder);
+ fontInfo.pdfFont ||= lastFont.pdfFont;
+ this.stack.push(fontInfo);
+ }
+ popFont() {
+ this.stack.pop();
+ }
+ topFont() {
+ return this.stack.at(-1);
+ }
+}
+class TextMeasure {
+ constructor(defaultXfaFont, defaultParaMargin, defaultLineHeight, fonts) {
+ this.glyphs = [];
+ this.fontSelector = new FontSelector(defaultXfaFont, defaultParaMargin, defaultLineHeight, fonts);
+ this.extraHeight = 0;
+ }
+ pushData(xfaFont, margin, lineHeight) {
+ this.fontSelector.pushData(xfaFont, margin, lineHeight);
+ }
+ popFont(xfaFont) {
+ return this.fontSelector.popFont();
+ }
+ addPara() {
+ const lastFont = this.fontSelector.topFont();
+ this.extraHeight += lastFont.paraMargin.top + lastFont.paraMargin.bottom;
+ }
+ addString(str) {
+ if (!str) {
+ return;
+ }
+ const lastFont = this.fontSelector.topFont();
+ const fontSize = lastFont.xfaFont.size;
+ if (lastFont.pdfFont) {
+ const letterSpacing = lastFont.xfaFont.letterSpacing;
+ const pdfFont = lastFont.pdfFont;
+ const fontLineHeight = pdfFont.lineHeight || 1.2;
+ const lineHeight = lastFont.lineHeight || Math.max(1.2, fontLineHeight) * fontSize;
+ const lineGap = pdfFont.lineGap === undefined ? 0.2 : pdfFont.lineGap;
+ const noGap = fontLineHeight - lineGap;
+ const firstLineHeight = Math.max(1, noGap) * fontSize;
+ const scale = fontSize / 1000;
+ const fallbackWidth = pdfFont.defaultWidth || pdfFont.charsToGlyphs(" ")[0].width;
+ for (const line of str.split(/[\u2029\n]/)) {
+ const encodedLine = pdfFont.encodeString(line).join("");
+ const glyphs = pdfFont.charsToGlyphs(encodedLine);
+ for (const glyph of glyphs) {
+ const width = glyph.width || fallbackWidth;
+ this.glyphs.push([width * scale + letterSpacing, lineHeight, firstLineHeight, glyph.unicode, false]);
+ }
+ this.glyphs.push([0, 0, 0, "\n", true]);
+ }
+ this.glyphs.pop();
+ return;
+ }
+ for (const line of str.split(/[\u2029\n]/)) {
+ for (const char of line.split("")) {
+ this.glyphs.push([fontSize, 1.2 * fontSize, fontSize, char, false]);
+ }
+ this.glyphs.push([0, 0, 0, "\n", true]);
+ }
+ this.glyphs.pop();
+ }
+ compute(maxWidth) {
+ let lastSpacePos = -1,
+ lastSpaceWidth = 0,
+ width = 0,
+ height = 0,
+ currentLineWidth = 0,
+ currentLineHeight = 0;
+ let isBroken = false;
+ let isFirstLine = true;
+ for (let i = 0, ii = this.glyphs.length; i < ii; i++) {
+ const [glyphWidth, lineHeight, firstLineHeight, char, isEOL] = this.glyphs[i];
+ const isSpace = char === " ";
+ const glyphHeight = isFirstLine ? firstLineHeight : lineHeight;
+ if (isEOL) {
+ width = Math.max(width, currentLineWidth);
+ currentLineWidth = 0;
+ height += currentLineHeight;
+ currentLineHeight = glyphHeight;
+ lastSpacePos = -1;
+ lastSpaceWidth = 0;
+ isFirstLine = false;
+ continue;
+ }
+ if (isSpace) {
+ if (currentLineWidth + glyphWidth > maxWidth) {
+ width = Math.max(width, currentLineWidth);
+ currentLineWidth = 0;
+ height += currentLineHeight;
+ currentLineHeight = glyphHeight;
+ lastSpacePos = -1;
+ lastSpaceWidth = 0;
+ isBroken = true;
+ isFirstLine = false;
+ } else {
+ currentLineHeight = Math.max(glyphHeight, currentLineHeight);
+ lastSpaceWidth = currentLineWidth;
+ currentLineWidth += glyphWidth;
+ lastSpacePos = i;
+ }
+ continue;
+ }
+ if (currentLineWidth + glyphWidth > maxWidth) {
+ height += currentLineHeight;
+ currentLineHeight = glyphHeight;
+ if (lastSpacePos !== -1) {
+ i = lastSpacePos;
+ width = Math.max(width, lastSpaceWidth);
+ currentLineWidth = 0;
+ lastSpacePos = -1;
+ lastSpaceWidth = 0;
+ } else {
+ width = Math.max(width, currentLineWidth);
+ currentLineWidth = glyphWidth;
+ }
+ isBroken = true;
+ isFirstLine = false;
+ continue;
+ }
+ currentLineWidth += glyphWidth;
+ currentLineHeight = Math.max(glyphHeight, currentLineHeight);
+ }
+ width = Math.max(width, currentLineWidth);
+ height += currentLineHeight + this.extraHeight;
+ return {
+ width: WIDTH_FACTOR * width,
+ height,
+ isBroken
+ };
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.weak-map.get-or-insert.js
+var es_weak_map_get_or_insert = __webpack_require__(8454);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.weak-map.get-or-insert-computed.js
+var es_weak_map_get_or_insert_computed = __webpack_require__(9452);
+;// ./src/core/xfa/som.js
+
+
+
+
+
+
+
+
+
+
+const namePattern = /^[^.[]+/;
+const indexPattern = /^[^\]]+/;
+const operators = {
+ dot: 0,
+ dotDot: 1,
+ dotHash: 2,
+ dotBracket: 3,
+ dotParen: 4
+};
+const shortcuts = new Map([["$data", (root, current) => root.datasets ? root.datasets.data : root], ["$record", (root, current) => (root.datasets ? root.datasets.data : root)[$getChildren]()[0]], ["$template", (root, current) => root.template], ["$connectionSet", (root, current) => root.connectionSet], ["$form", (root, current) => root.form], ["$layout", (root, current) => root.layout], ["$host", (root, current) => root.host], ["$dataWindow", (root, current) => root.dataWindow], ["$event", (root, current) => root.event], ["!", (root, current) => root.datasets], ["$xfa", (root, current) => root], ["xfa", (root, current) => root], ["$", (root, current) => current]]);
+const somCache = new WeakMap();
+function parseIndex(index) {
+ index = index.trim();
+ if (index === "*") {
+ return Infinity;
+ }
+ return parseInt(index, 10) || 0;
+}
+function parseExpression(expr, dotDotAllowed, noExpr = true) {
+ let match = expr.match(namePattern);
+ if (!match) {
+ return null;
+ }
+ let [name] = match;
+ const parsed = [{
+ name,
+ cacheName: "." + name,
+ index: 0,
+ js: null,
+ formCalc: null,
+ operator: operators.dot
+ }];
+ let pos = name.length;
+ while (pos < expr.length) {
+ const spos = pos;
+ const char = expr.charAt(pos++);
+ if (char === "[") {
+ match = expr.slice(pos).match(indexPattern);
+ if (!match) {
+ warn("XFA - Invalid index in SOM expression");
+ return null;
+ }
+ parsed.at(-1).index = parseIndex(match[0]);
+ pos += match[0].length + 1;
+ continue;
+ }
+ let operator;
+ switch (expr.charAt(pos)) {
+ case ".":
+ if (!dotDotAllowed) {
+ return null;
+ }
+ pos++;
+ operator = operators.dotDot;
+ break;
+ case "#":
+ pos++;
+ operator = operators.dotHash;
+ break;
+ case "[":
+ if (noExpr) {
+ warn("XFA - SOM expression contains a FormCalc subexpression which is not supported for now.");
+ return null;
+ }
+ operator = operators.dotBracket;
+ break;
+ case "(":
+ if (noExpr) {
+ warn("XFA - SOM expression contains a JavaScript subexpression which is not supported for now.");
+ return null;
+ }
+ operator = operators.dotParen;
+ break;
+ default:
+ operator = operators.dot;
+ break;
+ }
+ match = expr.slice(pos).match(namePattern);
+ if (!match) {
+ break;
+ }
+ [name] = match;
+ pos += name.length;
+ parsed.push({
+ name,
+ cacheName: expr.slice(spos, pos),
+ operator,
+ index: 0,
+ js: null,
+ formCalc: null
+ });
+ }
+ return parsed;
+}
+function searchNode(root, container, expr, dotDotAllowed = true, useCache = true) {
+ const parsed = parseExpression(expr, dotDotAllowed);
+ if (!parsed) {
+ return null;
+ }
+ const fn = shortcuts.get(parsed[0].name);
+ let i = 0;
+ let isQualified;
+ if (fn) {
+ isQualified = true;
+ root = [fn(root, container)];
+ i = 1;
+ } else {
+ isQualified = container === null;
+ root = [container || root];
+ }
+ for (let ii = parsed.length; i < ii; i++) {
+ const {
+ name,
+ cacheName,
+ operator,
+ index
+ } = parsed[i];
+ const nodes = [];
+ for (const node of root) {
+ if (!node.isXFAObject) {
+ continue;
+ }
+ let children, cached;
+ if (useCache) {
+ cached = somCache.getOrInsertComputed(node, makeMap);
+ children = cached.get(cacheName);
+ }
+ if (!children) {
+ switch (operator) {
+ case operators.dot:
+ children = node[$getChildrenByName](name, false);
+ break;
+ case operators.dotDot:
+ children = node[$getChildrenByName](name, true);
+ break;
+ case operators.dotHash:
+ children = node[$getChildrenByClass](name);
+ children = children.isXFAObjectArray ? children.children : [children];
+ break;
+ default:
+ break;
+ }
+ if (useCache) {
+ cached.set(cacheName, children);
+ }
+ }
+ if (children.length > 0) {
+ nodes.push(children);
+ }
+ }
+ if (nodes.length === 0 && !isQualified && i === 0) {
+ const parent = container[$getParent]();
+ container = parent;
+ if (!container) {
+ return null;
+ }
+ i = -1;
+ root = [container];
+ continue;
+ }
+ root = isFinite(index) ? nodes.filter(node => index < node.length).map(node => node[index]) : nodes.flat();
+ }
+ if (root.length === 0) {
+ return null;
+ }
+ return root;
+}
+function createDataNode(root, container, expr) {
+ const parsed = parseExpression(expr);
+ if (!parsed) {
+ return null;
+ }
+ if (parsed.some(x => x.operator === operators.dotDot)) {
+ return null;
+ }
+ const fn = shortcuts.get(parsed[0].name);
+ let i = 0;
+ if (fn) {
+ root = fn(root, container);
+ i = 1;
+ } else {
+ root = container || root;
+ }
+ for (let ii = parsed.length; i < ii; i++) {
+ const {
+ name,
+ operator,
+ index
+ } = parsed[i];
+ if (!isFinite(index)) {
+ parsed[i].index = 0;
+ return root.createNodes(parsed.slice(i));
+ }
+ let children;
+ switch (operator) {
+ case operators.dot:
+ children = root[$getChildrenByName](name, false);
+ break;
+ case operators.dotDot:
+ children = root[$getChildrenByName](name, true);
+ break;
+ case operators.dotHash:
+ children = root[$getChildrenByClass](name);
+ children = children.isXFAObjectArray ? children.children : [children];
+ break;
+ default:
+ break;
+ }
+ if (children.length === 0) {
+ return root.createNodes(parsed.slice(i));
+ }
+ if (index < children.length) {
+ const child = children[index];
+ if (!child.isXFAObject) {
+ warn(`XFA - Cannot create a node.`);
+ return null;
+ }
+ root = child;
+ } else {
+ parsed[i].index = index - children.length;
+ return root.createNodes(parsed.slice(i));
+ }
+ }
+ return null;
+}
+
+;// ./src/core/xfa/xfa_object.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const _applyPrototype = Symbol();
+const _attributes = Symbol();
+const _attributeNames = Symbol();
+const _children = Symbol("_children");
+const _cloneAttribute = Symbol();
+const _dataValue = Symbol();
+const _defaultValue = Symbol();
+const _filteredChildrenGenerator = Symbol();
+const _getPrototype = Symbol();
+const _getUnsetAttributes = Symbol();
+const _hasChildren = Symbol();
+const _max = Symbol();
+const _options = Symbol();
+const _parent = Symbol("parent");
+const _resolvePrototypesHelper = Symbol();
+const _setAttributes = Symbol();
+const _validator = Symbol();
+let uid = 0;
+const NS_DATASETS = NamespaceIds.datasets.id;
+class XFAObject {
+ constructor(nsId, name, hasChildren = false) {
+ this[$namespaceId] = nsId;
+ this[$nodeName] = name;
+ this[_hasChildren] = hasChildren;
+ this[_parent] = null;
+ this[_children] = [];
+ this[$uid] = `${name}${uid++}`;
+ this[$globalData] = null;
+ }
+ get isXFAObject() {
+ return true;
+ }
+ get isXFAObjectArray() {
+ return false;
+ }
+ createNodes(path) {
+ let root = this,
+ node = null;
+ for (const {
+ name,
+ index
+ } of path) {
+ for (let i = 0, ii = isFinite(index) ? index : 0; i <= ii; i++) {
+ const nsId = root[$namespaceId] === NS_DATASETS ? -1 : root[$namespaceId];
+ node = new XmlObject(nsId, name);
+ root[$appendChild](node);
+ }
+ root = node;
+ }
+ return node;
+ }
+ [$onChild](child) {
+ if (!this[_hasChildren] || !this[$onChildCheck](child)) {
+ return false;
+ }
+ const name = child[$nodeName];
+ const node = this[name];
+ if (node instanceof XFAObjectArray) {
+ if (node.push(child)) {
+ this[$appendChild](child);
+ return true;
+ }
+ } else {
+ if (node !== null) {
+ this[$removeChild](node);
+ }
+ this[name] = child;
+ this[$appendChild](child);
+ return true;
+ }
+ let id = "";
+ if (this.id) {
+ id = ` (id: ${this.id})`;
+ } else if (this.name) {
+ id = ` (name: ${this.name} ${this.h.value})`;
+ }
+ warn(`XFA - node "${this[$nodeName]}"${id} has already enough "${name}"!`);
+ return false;
+ }
+ [$onChildCheck](child) {
+ return Object.hasOwn(this, child[$nodeName]) && child[$namespaceId] === this[$namespaceId];
+ }
+ [$isNsAgnostic]() {
+ return false;
+ }
+ [$acceptWhitespace]() {
+ return false;
+ }
+ [$isCDATAXml]() {
+ return false;
+ }
+ [$isBindable]() {
+ return false;
+ }
+ [$popPara]() {
+ if (this.para) {
+ this[$getTemplateRoot]()[$extra].paraStack.pop();
+ }
+ }
+ [$pushPara]() {
+ this[$getTemplateRoot]()[$extra].paraStack.push(this.para);
+ }
+ [$setId](ids) {
+ if (this.id && this[$namespaceId] === NamespaceIds.template.id) {
+ ids.set(this.id, this);
+ }
+ }
+ [$getTemplateRoot]() {
+ return this[$globalData].template;
+ }
+ [$isSplittable]() {
+ return false;
+ }
+ [$isThereMoreWidth]() {
+ return false;
+ }
+ [$appendChild](child) {
+ child[_parent] = this;
+ this[_children].push(child);
+ if (!child[$globalData] && this[$globalData]) {
+ child[$globalData] = this[$globalData];
+ }
+ }
+ [$removeChild](child) {
+ const i = this[_children].indexOf(child);
+ this[_children].splice(i, 1);
+ }
+ [$hasSettableValue]() {
+ return Object.hasOwn(this, "value");
+ }
+ [$setValue](_) {}
+ [$onText](_) {}
+ [$finalize]() {}
+ [$clean](builder) {
+ delete this[_hasChildren];
+ if (this[$cleanup]) {
+ builder.clean(this[$cleanup]);
+ delete this[$cleanup];
+ }
+ }
+ [$indexOf](child) {
+ return this[_children].indexOf(child);
+ }
+ [$insertAt](i, child) {
+ child[_parent] = this;
+ this[_children].splice(i, 0, child);
+ if (!child[$globalData] && this[$globalData]) {
+ child[$globalData] = this[$globalData];
+ }
+ }
+ [$isTransparent]() {
+ return !this.name;
+ }
+ [$lastAttribute]() {
+ return "";
+ }
+ [$text]() {
+ return this[_children].length === 0 ? this[$content] : this[_children].map(c => c[$text]()).join("");
+ }
+ get [_attributeNames]() {
+ const proto = Object.getPrototypeOf(this);
+ if (!proto._attributes) {
+ const attributes = proto._attributes = new Set();
+ for (const name of Object.getOwnPropertyNames(this)) {
+ if (this[name] === null || this[name] instanceof XFAObject || this[name] instanceof XFAObjectArray) {
+ break;
+ }
+ attributes.add(name);
+ }
+ }
+ return shadow(this, _attributeNames, proto._attributes);
+ }
+ [$isDescendent](parent) {
+ let node = this;
+ while (node) {
+ if (node === parent) {
+ return true;
+ }
+ node = node[$getParent]();
+ }
+ return false;
+ }
+ [$getParent]() {
+ return this[_parent];
+ }
+ [$getSubformParent]() {
+ return this[$getParent]();
+ }
+ [$dump]() {
+ const dumped = Object.create(null);
+ if (this[$content]) {
+ dumped.$content = this[$content];
+ }
+ for (const name of Object.getOwnPropertyNames(this)) {
+ const value = this[name];
+ if (value === null) {
+ continue;
+ }
+ if (value instanceof XFAObject) {
+ dumped[name] = value[$dump]();
+ } else if (value instanceof XFAObjectArray) {
+ if (!value.isEmpty()) {
+ dumped[name] = value.dump();
+ }
+ } else {
+ dumped[name] = value;
+ }
+ }
+ return dumped;
+ }
+ [$toStyle]() {
+ return null;
+ }
+ [$toHTML]() {
+ return HTMLResult.EMPTY;
+ }
+ *[$getContainedChildren]() {
+ for (const node of this[$getChildren]()) {
+ yield node;
+ }
+ }
+ *[_filteredChildrenGenerator](filter, include) {
+ for (const node of this[$getContainedChildren]()) {
+ if (!filter || include === filter.has(node[$nodeName])) {
+ const availableSpace = this[$getAvailableSpace]();
+ const res = node[$toHTML](availableSpace);
+ if (!res.success) {
+ this[$extra].failingNode = node;
+ }
+ yield res;
+ }
+ }
+ }
+ [$flushHTML]() {
+ return null;
+ }
+ [$addHTML](html, bbox) {
+ this[$extra].children.push(html);
+ }
+ [$getAvailableSpace]() {}
+ [$childrenToHTML]({
+ filter = null,
+ include = true
+ }) {
+ if (!this[$extra].generator) {
+ this[$extra].generator = this[_filteredChildrenGenerator](filter, include);
+ } else {
+ const availableSpace = this[$getAvailableSpace]();
+ const res = this[$extra].failingNode[$toHTML](availableSpace);
+ if (!res.success) {
+ return res;
+ }
+ if (res.html) {
+ this[$addHTML](res.html, res.bbox);
+ }
+ delete this[$extra].failingNode;
+ }
+ while (true) {
+ const gen = this[$extra].generator.next();
+ if (gen.done) {
+ break;
+ }
+ const res = gen.value;
+ if (!res.success) {
+ return res;
+ }
+ if (res.html) {
+ this[$addHTML](res.html, res.bbox);
+ }
+ }
+ this[$extra].generator = null;
+ return HTMLResult.EMPTY;
+ }
+ [$setSetAttributes](attributes) {
+ this[_setAttributes] = new Set(Object.keys(attributes));
+ }
+ [_getUnsetAttributes](protoAttributes) {
+ const allAttr = this[_attributeNames];
+ const setAttr = this[_setAttributes];
+ return protoAttributes.keys().filter(x => allAttr.has(x) && !setAttr.has(x)).toArray();
+ }
+ [$resolvePrototypes](ids, ancestors = new Set()) {
+ for (const child of this[_children]) {
+ child[_resolvePrototypesHelper](ids, ancestors);
+ }
+ }
+ [_resolvePrototypesHelper](ids, ancestors) {
+ const proto = this[_getPrototype](ids, ancestors);
+ if (proto) {
+ this[_applyPrototype](proto, ids, ancestors);
+ } else {
+ this[$resolvePrototypes](ids, ancestors);
+ }
+ }
+ [_getPrototype](ids, ancestors) {
+ const {
+ use,
+ usehref
+ } = this;
+ if (!use && !usehref) {
+ return null;
+ }
+ let proto = null;
+ let somExpression = null;
+ let id = null;
+ let ref = use;
+ if (usehref) {
+ ref = usehref;
+ if (usehref.startsWith("#som(") && usehref.endsWith(")")) {
+ somExpression = usehref.slice("#som(".length, -1);
+ } else if (usehref.startsWith(".#som(") && usehref.endsWith(")")) {
+ somExpression = usehref.slice(".#som(".length, -1);
+ } else if (usehref.startsWith("#")) {
+ id = usehref.slice(1);
+ } else if (usehref.startsWith(".#")) {
+ id = usehref.slice(2);
+ }
+ } else if (use.startsWith("#")) {
+ id = use.slice(1);
+ } else {
+ somExpression = use;
+ }
+ this.use = this.usehref = "";
+ if (id) {
+ proto = ids.get(id);
+ } else {
+ proto = searchNode(ids.get($root), this, somExpression, true, false);
+ proto &&= proto[0];
+ }
+ if (!proto) {
+ warn(`XFA - Invalid prototype reference: ${ref}.`);
+ return null;
+ }
+ if (proto[$nodeName] !== this[$nodeName]) {
+ warn(`XFA - Incompatible prototype: ${proto[$nodeName]} !== ${this[$nodeName]}.`);
+ return null;
+ }
+ if (ancestors.has(proto)) {
+ warn(`XFA - Cycle detected in prototypes use.`);
+ return null;
+ }
+ ancestors.add(proto);
+ const protoProto = proto[_getPrototype](ids, ancestors);
+ if (protoProto) {
+ proto[_applyPrototype](protoProto, ids, ancestors);
+ }
+ proto[$resolvePrototypes](ids, ancestors);
+ ancestors.delete(proto);
+ return proto;
+ }
+ [_applyPrototype](proto, ids, ancestors) {
+ if (ancestors.has(proto)) {
+ warn(`XFA - Cycle detected in prototypes use.`);
+ return;
+ }
+ if (!this[$content] && proto[$content]) {
+ this[$content] = proto[$content];
+ }
+ const newAncestors = new Set(ancestors);
+ newAncestors.add(proto);
+ for (const unsetAttrName of this[_getUnsetAttributes](proto[_setAttributes])) {
+ this[unsetAttrName] = proto[unsetAttrName];
+ if (this[_setAttributes]) {
+ this[_setAttributes].add(unsetAttrName);
+ }
+ }
+ for (const name of Object.getOwnPropertyNames(this)) {
+ if (this[_attributeNames].has(name)) {
+ continue;
+ }
+ const value = this[name];
+ const protoValue = proto[name];
+ if (value instanceof XFAObjectArray) {
+ for (const child of value[_children]) {
+ child[_resolvePrototypesHelper](ids, ancestors);
+ }
+ for (let i = value[_children].length, ii = protoValue[_children].length; i < ii; i++) {
+ const child = proto[_children][i][$clone]();
+ if (value.push(child)) {
+ child[_parent] = this;
+ this[_children].push(child);
+ child[_resolvePrototypesHelper](ids, ancestors);
+ } else {
+ break;
+ }
+ }
+ continue;
+ }
+ if (value !== null) {
+ value[$resolvePrototypes](ids, ancestors);
+ if (protoValue) {
+ value[_applyPrototype](protoValue, ids, ancestors);
+ }
+ continue;
+ }
+ if (protoValue !== null) {
+ const child = protoValue[$clone]();
+ child[_parent] = this;
+ this[name] = child;
+ this[_children].push(child);
+ child[_resolvePrototypesHelper](ids, ancestors);
+ }
+ }
+ }
+ static [_cloneAttribute](obj) {
+ if (Array.isArray(obj)) {
+ return obj.map(x => XFAObject[_cloneAttribute](x));
+ }
+ if (typeof obj === "object" && obj !== null) {
+ return Object.assign({}, obj);
+ }
+ return obj;
+ }
+ [$clone]() {
+ const clone = Object.create(Object.getPrototypeOf(this));
+ for (const $symbol of Object.getOwnPropertySymbols(this)) {
+ try {
+ clone[$symbol] = this[$symbol];
+ } catch {
+ shadow(clone, $symbol, this[$symbol]);
+ }
+ }
+ clone[$uid] = `${clone[$nodeName]}${uid++}`;
+ clone[_children] = [];
+ for (const name of Object.getOwnPropertyNames(this)) {
+ if (this[_attributeNames].has(name)) {
+ clone[name] = XFAObject[_cloneAttribute](this[name]);
+ continue;
+ }
+ const value = this[name];
+ clone[name] = value instanceof XFAObjectArray ? new XFAObjectArray(value[_max]) : null;
+ }
+ for (const child of this[_children]) {
+ const name = child[$nodeName];
+ const clonedChild = child[$clone]();
+ clone[_children].push(clonedChild);
+ clonedChild[_parent] = clone;
+ if (clone[name] === null) {
+ clone[name] = clonedChild;
+ } else {
+ clone[name][_children].push(clonedChild);
+ }
+ }
+ return clone;
+ }
+ [$getChildren](name = null) {
+ return !name ? this[_children] : this[_children].filter(c => c[$nodeName] === name);
+ }
+ [$getChildrenByClass](name) {
+ return this[name];
+ }
+ [$getChildrenByName](name, allTransparent, first = true) {
+ return Array.from(this[$getChildrenByNameIt](name, allTransparent, first));
+ }
+ *[$getChildrenByNameIt](name, allTransparent, first = true) {
+ if (name === "parent") {
+ yield this[_parent];
+ return;
+ }
+ for (const child of this[_children]) {
+ if (child[$nodeName] === name) {
+ yield child;
+ }
+ if (child.name === name) {
+ yield child;
+ }
+ if (allTransparent || child[$isTransparent]()) {
+ yield* child[$getChildrenByNameIt](name, allTransparent, false);
+ }
+ }
+ if (first && this[_attributeNames].has(name)) {
+ yield new XFAAttribute(this, name, this[name]);
+ }
+ }
+}
+class XFAObjectArray {
+ constructor(max = Infinity) {
+ this[_max] = max;
+ this[_children] = [];
+ }
+ get isXFAObject() {
+ return false;
+ }
+ get isXFAObjectArray() {
+ return true;
+ }
+ push(child) {
+ const len = this[_children].length;
+ if (len <= this[_max]) {
+ this[_children].push(child);
+ return true;
+ }
+ warn(`XFA - node "${child[$nodeName]}" accepts no more than ${this[_max]} children`);
+ return false;
+ }
+ isEmpty() {
+ return this[_children].length === 0;
+ }
+ dump() {
+ return this[_children].length === 1 ? this[_children][0][$dump]() : this[_children].map(x => x[$dump]());
+ }
+ [$clone]() {
+ const clone = new XFAObjectArray(this[_max]);
+ clone[_children] = this[_children].map(c => c[$clone]());
+ return clone;
+ }
+ get children() {
+ return this[_children];
+ }
+ clear() {
+ this[_children].length = 0;
+ }
+}
+class XFAAttribute {
+ constructor(node, name, value) {
+ this[_parent] = node;
+ this[$nodeName] = name;
+ this[$content] = value;
+ this[$consumed] = false;
+ this[$uid] = `attribute${uid++}`;
+ }
+ [$getParent]() {
+ return this[_parent];
+ }
+ [$isDataValue]() {
+ return true;
+ }
+ [$getDataValue]() {
+ return this[$content].trim();
+ }
+ [$setValue](value) {
+ value = value.value || "";
+ this[$content] = value.toString();
+ }
+ [$text]() {
+ return this[$content];
+ }
+ [$isDescendent](parent) {
+ return this[_parent] === parent || this[_parent][$isDescendent](parent);
+ }
+}
+class XmlObject extends XFAObject {
+ constructor(nsId, name, attributes = {}) {
+ super(nsId, name);
+ this[$content] = "";
+ this[_dataValue] = null;
+ if (name !== "#text") {
+ const map = new Map();
+ this[_attributes] = map;
+ for (const [attrName, value] of Object.entries(attributes)) {
+ map.set(attrName, new XFAAttribute(this, attrName, value));
+ }
+ if (Object.hasOwn(attributes, $nsAttributes)) {
+ const dataNode = attributes[$nsAttributes].xfa.dataNode;
+ if (dataNode !== undefined) {
+ if (dataNode === "dataGroup") {
+ this[_dataValue] = false;
+ } else if (dataNode === "dataValue") {
+ this[_dataValue] = true;
+ }
+ }
+ }
+ }
+ this[$consumed] = false;
+ }
+ [$toString](buf) {
+ const tagName = this[$nodeName];
+ if (tagName === "#text") {
+ buf.push(encodeToXmlString(this[$content]));
+ return;
+ }
+ const utf8TagName = utf8StringToString(tagName);
+ const prefix = this[$namespaceId] === NS_DATASETS ? "xfa:" : "";
+ buf.push(`<${prefix}${utf8TagName}`);
+ for (const [name, value] of this[_attributes]) {
+ const utf8Name = utf8StringToString(name);
+ buf.push(` ${utf8Name}="${encodeToXmlString(value[$content])}"`);
+ }
+ if (this[_dataValue] !== null) {
+ if (this[_dataValue]) {
+ buf.push(` xfa:dataNode="dataValue"`);
+ } else {
+ buf.push(` xfa:dataNode="dataGroup"`);
+ }
+ }
+ if (!this[$content] && this[_children].length === 0) {
+ buf.push("/>");
+ return;
+ }
+ buf.push(">");
+ if (this[$content]) {
+ if (typeof this[$content] === "string") {
+ buf.push(encodeToXmlString(this[$content]));
+ } else {
+ this[$content][$toString](buf);
+ }
+ } else {
+ for (const child of this[_children]) {
+ child[$toString](buf);
+ }
+ }
+ buf.push(`${prefix}${utf8TagName}>`);
+ }
+ [$onChild](child) {
+ if (this[$content]) {
+ const node = new XmlObject(this[$namespaceId], "#text");
+ this[$appendChild](node);
+ node[$content] = this[$content];
+ this[$content] = "";
+ }
+ this[$appendChild](child);
+ return true;
+ }
+ [$onText](str) {
+ this[$content] += str;
+ }
+ [$finalize]() {
+ if (this[$content] && this[_children].length > 0) {
+ const node = new XmlObject(this[$namespaceId], "#text");
+ this[$appendChild](node);
+ node[$content] = this[$content];
+ delete this[$content];
+ }
+ }
+ [$toHTML]() {
+ if (this[$nodeName] === "#text") {
+ return HTMLResult.success({
+ name: "#text",
+ value: this[$content]
+ });
+ }
+ return HTMLResult.EMPTY;
+ }
+ [$getAttributes]() {
+ return this[_attributes];
+ }
+ [$getChildrenByClass](name) {
+ const value = this[_attributes].get(name);
+ if (value !== undefined) {
+ return value;
+ }
+ return this[$getChildren](name);
+ }
+ *[$getChildrenByNameIt](name, allTransparent) {
+ const value = this[_attributes].get(name);
+ if (value) {
+ yield value;
+ }
+ for (const child of this[_children]) {
+ if (child[$nodeName] === name) {
+ yield child;
+ }
+ if (allTransparent) {
+ yield* child[$getChildrenByNameIt](name, allTransparent);
+ }
+ }
+ }
+ *[$getAttributeIt](name, skipConsumed) {
+ const value = this[_attributes].get(name);
+ if (value && (!skipConsumed || !value[$consumed])) {
+ yield value;
+ }
+ for (const child of this[_children]) {
+ yield* child[$getAttributeIt](name, skipConsumed);
+ }
+ }
+ *[$getRealChildrenByNameIt](name, allTransparent, skipConsumed) {
+ for (const child of this[_children]) {
+ if (child[$nodeName] === name && (!skipConsumed || !child[$consumed])) {
+ yield child;
+ }
+ if (allTransparent) {
+ yield* child[$getRealChildrenByNameIt](name, allTransparent, skipConsumed);
+ }
+ }
+ }
+ [$isDataValue]() {
+ if (this[_dataValue] === null) {
+ return this[_children].length === 0 || this[_children][0][$namespaceId] === NamespaceIds.xhtml.id;
+ }
+ return this[_dataValue];
+ }
+ [$getDataValue]() {
+ if (this[_dataValue] === null) {
+ if (this[_children].length === 0) {
+ return this[$content].trim();
+ }
+ if (this[_children][0][$namespaceId] === NamespaceIds.xhtml.id) {
+ return this[_children][0][$text]().trim();
+ }
+ return null;
+ }
+ return this[$content].trim();
+ }
+ [$setValue](value) {
+ value = value.value || "";
+ this[$content] = value.toString();
+ }
+ [$dump](hasNS = false) {
+ const dumped = Object.create(null);
+ if (hasNS) {
+ dumped.$ns = this[$namespaceId];
+ }
+ if (this[$content]) {
+ dumped.$content = this[$content];
+ }
+ dumped.$name = this[$nodeName];
+ dumped.children = [];
+ for (const child of this[_children]) {
+ dumped.children.push(child[$dump](hasNS));
+ }
+ dumped.attributes = Object.create(null);
+ for (const [name, value] of this[_attributes]) {
+ dumped.attributes[name] = value[$content];
+ }
+ return dumped;
+ }
+}
+class ContentObject extends XFAObject {
+ constructor(nsId, name) {
+ super(nsId, name);
+ this[$content] = "";
+ }
+ [$onText](text) {
+ this[$content] += text;
+ }
+ [$finalize]() {}
+}
+class OptionObject extends ContentObject {
+ constructor(nsId, name, options) {
+ super(nsId, name);
+ this[_options] = options;
+ }
+ [$finalize]() {
+ this[$content] = getKeyword({
+ data: this[$content],
+ defaultValue: this[_options][0],
+ validate: k => this[_options].includes(k)
+ });
+ }
+ [$clean](builder) {
+ super[$clean](builder);
+ delete this[_options];
+ }
+}
+class StringObject extends ContentObject {
+ [$finalize]() {
+ this[$content] = this[$content].trim();
+ }
+}
+class IntegerObject extends ContentObject {
+ constructor(nsId, name, defaultValue, validator) {
+ super(nsId, name);
+ this[_defaultValue] = defaultValue;
+ this[_validator] = validator;
+ }
+ [$finalize]() {
+ this[$content] = getInteger({
+ data: this[$content],
+ defaultValue: this[_defaultValue],
+ validate: this[_validator]
+ });
+ }
+ [$clean](builder) {
+ super[$clean](builder);
+ delete this[_defaultValue];
+ delete this[_validator];
+ }
+}
+class Option01 extends IntegerObject {
+ constructor(nsId, name) {
+ super(nsId, name, 0, n => n === 1);
+ }
+}
+class Option10 extends IntegerObject {
+ constructor(nsId, name) {
+ super(nsId, name, 1, n => n === 0);
+ }
+}
+
+;// ./src/core/xfa/html_utils.js
+
+
+
+
+
+
+
+
+
+
+
+
+function measureToString(m) {
+ if (typeof m === "string") {
+ return "0px";
+ }
+ return Number.isInteger(m) ? `${m}px` : `${m.toFixed(2)}px`;
+}
+const converters = {
+ anchorType(node, style) {
+ const parent = node[$getSubformParent]();
+ if (!parent || parent.layout && parent.layout !== "position") {
+ return;
+ }
+ if (!("transform" in style)) {
+ style.transform = "";
+ }
+ switch (node.anchorType) {
+ case "bottomCenter":
+ style.transform += "translate(-50%, -100%)";
+ break;
+ case "bottomLeft":
+ style.transform += "translate(0,-100%)";
+ break;
+ case "bottomRight":
+ style.transform += "translate(-100%,-100%)";
+ break;
+ case "middleCenter":
+ style.transform += "translate(-50%,-50%)";
+ break;
+ case "middleLeft":
+ style.transform += "translate(0,-50%)";
+ break;
+ case "middleRight":
+ style.transform += "translate(-100%,-50%)";
+ break;
+ case "topCenter":
+ style.transform += "translate(-50%,0)";
+ break;
+ case "topRight":
+ style.transform += "translate(-100%,0)";
+ break;
+ }
+ },
+ dimensions(node, style) {
+ const parent = node[$getSubformParent]();
+ let width = node.w;
+ const height = node.h;
+ if (parent.layout?.includes("row")) {
+ const extra = parent[$extra];
+ const colSpan = node.colSpan;
+ let w;
+ if (colSpan === -1) {
+ w = Math.sumPrecise(extra.columnWidths.slice(extra.currentColumn));
+ extra.currentColumn = 0;
+ } else {
+ w = Math.sumPrecise(extra.columnWidths.slice(extra.currentColumn, extra.currentColumn + colSpan));
+ extra.currentColumn = (extra.currentColumn + node.colSpan) % extra.columnWidths.length;
+ }
+ if (!isNaN(w)) {
+ width = node.w = w;
+ }
+ }
+ style.width = width !== "" ? measureToString(width) : "auto";
+ style.height = height !== "" ? measureToString(height) : "auto";
+ },
+ position(node, style) {
+ const parent = node[$getSubformParent]();
+ if (parent?.layout && parent.layout !== "position") {
+ return;
+ }
+ style.position = "absolute";
+ style.left = measureToString(node.x);
+ style.top = measureToString(node.y);
+ },
+ rotate(node, style) {
+ if (node.rotate) {
+ if (!("transform" in style)) {
+ style.transform = "";
+ }
+ style.transform += `rotate(-${node.rotate}deg)`;
+ style.transformOrigin = "top left";
+ }
+ },
+ presence(node, style) {
+ switch (node.presence) {
+ case "invisible":
+ style.visibility = "hidden";
+ break;
+ case "hidden":
+ case "inactive":
+ style.display = "none";
+ break;
+ }
+ },
+ hAlign(node, style) {
+ if (node[$nodeName] === "para") {
+ switch (node.hAlign) {
+ case "justifyAll":
+ style.textAlign = "justify-all";
+ break;
+ case "radix":
+ style.textAlign = "left";
+ break;
+ default:
+ style.textAlign = node.hAlign;
+ }
+ } else {
+ switch (node.hAlign) {
+ case "left":
+ style.alignSelf = "start";
+ break;
+ case "center":
+ style.alignSelf = "center";
+ break;
+ case "right":
+ style.alignSelf = "end";
+ break;
+ }
+ }
+ },
+ margin(node, style) {
+ if (node.margin) {
+ style.margin = node.margin[$toStyle]().margin;
+ }
+ }
+};
+function setMinMaxDimensions(node, style) {
+ const parent = node[$getSubformParent]();
+ if (parent.layout === "position") {
+ if (node.minW > 0) {
+ style.minWidth = measureToString(node.minW);
+ }
+ if (node.maxW > 0) {
+ style.maxWidth = measureToString(node.maxW);
+ }
+ if (node.minH > 0) {
+ style.minHeight = measureToString(node.minH);
+ }
+ if (node.maxH > 0) {
+ style.maxHeight = measureToString(node.maxH);
+ }
+ }
+}
+function layoutText(text, xfaFont, margin, lineHeight, fontFinder, width) {
+ const measure = new TextMeasure(xfaFont, margin, lineHeight, fontFinder);
+ if (typeof text === "string") {
+ measure.addString(text);
+ } else {
+ text[$pushGlyphs](measure);
+ }
+ return measure.compute(width);
+}
+function layoutNode(node, availableSpace) {
+ let height = null;
+ let width = null;
+ let isBroken = false;
+ if ((!node.w || !node.h) && node.value) {
+ let marginH = 0;
+ let marginV = 0;
+ if (node.margin) {
+ marginH = node.margin.leftInset + node.margin.rightInset;
+ marginV = node.margin.topInset + node.margin.bottomInset;
+ }
+ let lineHeight = null;
+ let margin = null;
+ if (node.para) {
+ margin = Object.create(null);
+ lineHeight = node.para.lineHeight === "" ? null : node.para.lineHeight;
+ margin.top = node.para.spaceAbove === "" ? 0 : node.para.spaceAbove;
+ margin.bottom = node.para.spaceBelow === "" ? 0 : node.para.spaceBelow;
+ margin.left = node.para.marginLeft === "" ? 0 : node.para.marginLeft;
+ margin.right = node.para.marginRight === "" ? 0 : node.para.marginRight;
+ }
+ let font = node.font;
+ if (!font) {
+ const root = node[$getTemplateRoot]();
+ let parent = node[$getParent]();
+ while (parent && parent !== root) {
+ if (parent.font) {
+ font = parent.font;
+ break;
+ }
+ parent = parent[$getParent]();
+ }
+ }
+ const maxWidth = (node.w || availableSpace.width) - marginH;
+ const fontFinder = node[$globalData].fontFinder;
+ if (node.value.exData && node.value.exData[$content] && node.value.exData.contentType === "text/html") {
+ const res = layoutText(node.value.exData[$content], font, margin, lineHeight, fontFinder, maxWidth);
+ width = res.width;
+ height = res.height;
+ isBroken = res.isBroken;
+ } else {
+ const text = node.value[$text]();
+ if (text) {
+ const res = layoutText(text, font, margin, lineHeight, fontFinder, maxWidth);
+ width = res.width;
+ height = res.height;
+ isBroken = res.isBroken;
+ }
+ }
+ if (width !== null && !node.w) {
+ width += marginH;
+ }
+ if (height !== null && !node.h) {
+ height += marginV;
+ }
+ }
+ return {
+ w: width,
+ h: height,
+ isBroken
+ };
+}
+function computeBbox(node, html, availableSpace) {
+ let bbox;
+ if (node.w !== "" && node.h !== "") {
+ bbox = [node.x, node.y, node.w, node.h];
+ } else {
+ if (!availableSpace) {
+ return null;
+ }
+ let width = node.w;
+ if (width === "") {
+ if (node.maxW === 0) {
+ const parent = node[$getSubformParent]();
+ width = parent.layout === "position" && parent.w !== "" ? 0 : node.minW;
+ } else {
+ width = Math.min(node.maxW, availableSpace.width);
+ }
+ html.attributes.style.width = measureToString(width);
+ }
+ let height = node.h;
+ if (height === "") {
+ if (node.maxH === 0) {
+ const parent = node[$getSubformParent]();
+ height = parent.layout === "position" && parent.h !== "" ? 0 : node.minH;
+ } else {
+ height = Math.min(node.maxH, availableSpace.height);
+ }
+ html.attributes.style.height = measureToString(height);
+ }
+ bbox = [node.x, node.y, width, height];
+ }
+ return bbox;
+}
+function fixDimensions(node) {
+ const parent = node[$getSubformParent]();
+ if (parent.layout?.includes("row")) {
+ const extra = parent[$extra];
+ const colSpan = node.colSpan;
+ let width;
+ if (colSpan === -1) {
+ width = Math.sumPrecise(extra.columnWidths.slice(extra.currentColumn));
+ } else {
+ width = Math.sumPrecise(extra.columnWidths.slice(extra.currentColumn, extra.currentColumn + colSpan));
+ }
+ if (!isNaN(width)) {
+ node.w = width;
+ }
+ }
+ if (parent.layout && parent.layout !== "position") {
+ node.x = node.y = 0;
+ }
+ if (node.layout === "table") {
+ if (node.w === "" && Array.isArray(node.columnWidths)) {
+ node.w = Math.sumPrecise(node.columnWidths);
+ }
+ }
+}
+function layoutClass(node) {
+ switch (node.layout) {
+ case "position":
+ return "xfaPosition";
+ case "lr-tb":
+ return "xfaLrTb";
+ case "rl-row":
+ return "xfaRlRow";
+ case "rl-tb":
+ return "xfaRlTb";
+ case "row":
+ return "xfaRow";
+ case "table":
+ return "xfaTable";
+ case "tb":
+ return "xfaTb";
+ default:
+ return "xfaPosition";
+ }
+}
+function toStyle(node, ...names) {
+ const style = Object.create(null);
+ for (const name of names) {
+ const value = node[name];
+ if (value === null) {
+ continue;
+ }
+ if (Object.hasOwn(converters, name)) {
+ converters[name](node, style);
+ continue;
+ }
+ if (value instanceof XFAObject) {
+ const newStyle = value[$toStyle]();
+ if (newStyle) {
+ Object.assign(style, newStyle);
+ } else {
+ warn(`(DEBUG) - XFA - style for ${name} not implemented yet`);
+ }
+ }
+ }
+ return style;
+}
+function createWrapper(node, html) {
+ const {
+ attributes
+ } = html;
+ const {
+ style
+ } = attributes;
+ const wrapper = {
+ name: "div",
+ attributes: {
+ class: ["xfaWrapper"],
+ style: Object.create(null)
+ },
+ children: []
+ };
+ attributes.class.push("xfaWrapped");
+ if (node.border) {
+ const {
+ widths,
+ insets
+ } = node.border[$extra];
+ let width, height;
+ let top = insets[0];
+ let left = insets[3];
+ const insetsH = insets[0] + insets[2];
+ const insetsW = insets[1] + insets[3];
+ switch (node.border.hand) {
+ case "even":
+ top -= widths[0] / 2;
+ left -= widths[3] / 2;
+ width = `calc(100% + ${(widths[1] + widths[3]) / 2 - insetsW}px)`;
+ height = `calc(100% + ${(widths[0] + widths[2]) / 2 - insetsH}px)`;
+ break;
+ case "left":
+ top -= widths[0];
+ left -= widths[3];
+ width = `calc(100% + ${widths[1] + widths[3] - insetsW}px)`;
+ height = `calc(100% + ${widths[0] + widths[2] - insetsH}px)`;
+ break;
+ case "right":
+ width = insetsW ? `calc(100% - ${insetsW}px)` : "100%";
+ height = insetsH ? `calc(100% - ${insetsH}px)` : "100%";
+ break;
+ }
+ const classNames = ["xfaBorder"];
+ if (isPrintOnly(node.border)) {
+ classNames.push("xfaPrintOnly");
+ }
+ const border = {
+ name: "div",
+ attributes: {
+ class: classNames,
+ style: {
+ top: `${top}px`,
+ left: `${left}px`,
+ width,
+ height
+ }
+ },
+ children: []
+ };
+ for (const key of ["border", "borderWidth", "borderColor", "borderRadius", "borderStyle"]) {
+ if (style[key] !== undefined) {
+ border.attributes.style[key] = style[key];
+ delete style[key];
+ }
+ }
+ wrapper.children.push(border, html);
+ } else {
+ wrapper.children.push(html);
+ }
+ for (const key of ["background", "backgroundClip", "top", "left", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "transform", "transformOrigin", "visibility"]) {
+ if (style[key] !== undefined) {
+ wrapper.attributes.style[key] = style[key];
+ delete style[key];
+ }
+ }
+ wrapper.attributes.style.position = style.position === "absolute" ? "absolute" : "relative";
+ delete style.position;
+ if (style.alignSelf) {
+ wrapper.attributes.style.alignSelf = style.alignSelf;
+ delete style.alignSelf;
+ }
+ return wrapper;
+}
+function fixTextIndent(styles) {
+ const indent = getMeasurement(styles.textIndent, "0px");
+ if (indent >= 0) {
+ return;
+ }
+ const align = styles.textAlign === "right" ? "right" : "left";
+ const name = "padding" + (align === "left" ? "Left" : "Right");
+ const padding = getMeasurement(styles[name], "0px");
+ styles[name] = `${padding - indent}px`;
+}
+function setAccess(node, classNames) {
+ switch (node.access) {
+ case "nonInteractive":
+ classNames.push("xfaNonInteractive");
+ break;
+ case "readOnly":
+ classNames.push("xfaReadOnly");
+ break;
+ case "protected":
+ classNames.push("xfaDisabled");
+ break;
+ }
+}
+function isPrintOnly(node) {
+ return node.relevant.length > 0 && !node.relevant[0].excluded && node.relevant[0].viewname === "print";
+}
+function getCurrentPara(node) {
+ const stack = node[$getTemplateRoot]()[$extra].paraStack;
+ return stack.length ? stack.at(-1) : null;
+}
+function setPara(node, nodeStyle, value) {
+ if (value.attributes.class?.includes("xfaRich")) {
+ if (nodeStyle) {
+ if (node.h === "") {
+ nodeStyle.height = "auto";
+ }
+ if (node.w === "") {
+ nodeStyle.width = "auto";
+ }
+ }
+ const para = getCurrentPara(node);
+ if (para) {
+ const valueStyle = value.attributes.style;
+ valueStyle.display = "flex";
+ valueStyle.flexDirection = "column";
+ switch (para.vAlign) {
+ case "top":
+ valueStyle.justifyContent = "start";
+ break;
+ case "bottom":
+ valueStyle.justifyContent = "end";
+ break;
+ case "middle":
+ valueStyle.justifyContent = "center";
+ break;
+ }
+ const paraStyle = para[$toStyle]();
+ for (const [key, val] of Object.entries(paraStyle)) {
+ if (!(key in valueStyle)) {
+ valueStyle[key] = val;
+ }
+ }
+ }
+ }
+}
+function setFontFamily(xfaFont, node, fontFinder, style) {
+ if (!fontFinder) {
+ delete style.fontFamily;
+ return;
+ }
+ const name = stripQuotes(xfaFont.typeface);
+ style.fontFamily = serializeFontFamily(name);
+ const typeface = fontFinder.find(name);
+ if (typeface) {
+ const {
+ fontFamily
+ } = typeface.regular.cssFontInfo;
+ if (fontFamily !== name) {
+ style.fontFamily = serializeFontFamily(fontFamily);
+ }
+ const para = getCurrentPara(node);
+ if (para && para.lineHeight !== "") {
+ return;
+ }
+ if (style.lineHeight) {
+ return;
+ }
+ const pdfFont = selectFont(xfaFont, typeface);
+ if (pdfFont) {
+ style.lineHeight = Math.max(1.2, pdfFont.lineHeight);
+ }
+ }
+}
+function fixURL(str) {
+ const absoluteUrl = createValidAbsoluteUrl(str, null, {
+ addDefaultProtocol: true,
+ tryConvertEncoding: true
+ });
+ return absoluteUrl ? absoluteUrl.href : null;
+}
+
+;// ./src/core/xfa/layout.js
+
+
+
+
+
+function createLine(node, children) {
+ return {
+ name: "div",
+ attributes: {
+ class: [node.layout === "lr-tb" ? "xfaLr" : "xfaRl"]
+ },
+ children
+ };
+}
+function flushHTML(node) {
+ if (!node[$extra]) {
+ return null;
+ }
+ const attributes = node[$extra].attributes;
+ const html = {
+ name: "div",
+ attributes,
+ children: node[$extra].children
+ };
+ if (node[$extra].failingNode) {
+ const htmlFromFailing = node[$extra].failingNode[$flushHTML]();
+ if (htmlFromFailing) {
+ if (node.layout.endsWith("-tb")) {
+ html.children.push(createLine(node, [htmlFromFailing]));
+ } else {
+ html.children.push(htmlFromFailing);
+ }
+ }
+ }
+ if (html.children.length === 0) {
+ return null;
+ }
+ return html;
+}
+function addHTML(node, html, bbox) {
+ const extra = node[$extra];
+ const availableSpace = extra.availableSpace;
+ const [x, y, w, h] = bbox;
+ switch (node.layout) {
+ case "position":
+ {
+ extra.width = Math.max(extra.width, x + w);
+ extra.height = Math.max(extra.height, y + h);
+ extra.children.push(html);
+ break;
+ }
+ case "lr-tb":
+ case "rl-tb":
+ if (!extra.line || extra.attempt === 1) {
+ extra.line = createLine(node, []);
+ extra.children.push(extra.line);
+ extra.numberInLine = 0;
+ }
+ extra.numberInLine += 1;
+ extra.line.children.push(html);
+ if (extra.attempt === 0) {
+ extra.currentWidth += w;
+ extra.height = Math.max(extra.height, extra.prevHeight + h);
+ } else {
+ extra.currentWidth = w;
+ extra.prevHeight = extra.height;
+ extra.height += h;
+ extra.attempt = 0;
+ }
+ extra.width = Math.max(extra.width, extra.currentWidth);
+ break;
+ case "rl-row":
+ case "row":
+ {
+ extra.children.push(html);
+ extra.width += w;
+ extra.height = Math.max(extra.height, h);
+ const height = measureToString(extra.height);
+ for (const child of extra.children) {
+ child.attributes.style.height = height;
+ }
+ break;
+ }
+ case "table":
+ {
+ extra.width = MathClamp(w, extra.width, availableSpace.width);
+ extra.height += h;
+ extra.children.push(html);
+ break;
+ }
+ case "tb":
+ {
+ extra.width = MathClamp(w, extra.width, availableSpace.width);
+ extra.height += h;
+ extra.children.push(html);
+ break;
+ }
+ }
+}
+function getAvailableSpace(node) {
+ const availableSpace = node[$extra].availableSpace;
+ const marginV = node.margin ? node.margin.topInset + node.margin.bottomInset : 0;
+ const marginH = node.margin ? node.margin.leftInset + node.margin.rightInset : 0;
+ switch (node.layout) {
+ case "lr-tb":
+ case "rl-tb":
+ if (node[$extra].attempt === 0) {
+ return {
+ width: availableSpace.width - marginH - node[$extra].currentWidth,
+ height: availableSpace.height - marginV - node[$extra].prevHeight
+ };
+ }
+ return {
+ width: availableSpace.width - marginH,
+ height: availableSpace.height - marginV - node[$extra].height
+ };
+ case "rl-row":
+ case "row":
+ const width = Math.sumPrecise(node[$extra].columnWidths.slice(node[$extra].currentColumn));
+ return {
+ width,
+ height: availableSpace.height - marginH
+ };
+ case "table":
+ case "tb":
+ return {
+ width: availableSpace.width - marginH,
+ height: availableSpace.height - marginV - node[$extra].height
+ };
+ case "position":
+ default:
+ return availableSpace;
+ }
+}
+function getTransformedBBox(node) {
+ let w = node.w === "" ? NaN : node.w;
+ let h = node.h === "" ? NaN : node.h;
+ let [centerX, centerY] = [0, 0];
+ switch (node.anchorType || "") {
+ case "bottomCenter":
+ [centerX, centerY] = [w / 2, h];
+ break;
+ case "bottomLeft":
+ [centerX, centerY] = [0, h];
+ break;
+ case "bottomRight":
+ [centerX, centerY] = [w, h];
+ break;
+ case "middleCenter":
+ [centerX, centerY] = [w / 2, h / 2];
+ break;
+ case "middleLeft":
+ [centerX, centerY] = [0, h / 2];
+ break;
+ case "middleRight":
+ [centerX, centerY] = [w, h / 2];
+ break;
+ case "topCenter":
+ [centerX, centerY] = [w / 2, 0];
+ break;
+ case "topRight":
+ [centerX, centerY] = [w, 0];
+ break;
+ }
+ let x, y;
+ switch (node.rotate || 0) {
+ case 0:
+ [x, y] = [-centerX, -centerY];
+ break;
+ case 90:
+ [x, y] = [-centerY, centerX];
+ [w, h] = [h, -w];
+ break;
+ case 180:
+ [x, y] = [centerX, centerY];
+ [w, h] = [-w, -h];
+ break;
+ case 270:
+ [x, y] = [centerY, -centerX];
+ [w, h] = [-h, w];
+ break;
+ }
+ return [node.x + x + Math.min(0, w), node.y + y + Math.min(0, h), Math.abs(w), Math.abs(h)];
+}
+function checkDimensions(node, space) {
+ if (node[$getTemplateRoot]()[$extra].firstUnsplittable === null) {
+ return true;
+ }
+ if (node.w === 0 || node.h === 0) {
+ return true;
+ }
+ const ERROR = 2;
+ const parent = node[$getSubformParent]();
+ const attempt = parent[$extra]?.attempt || 0;
+ const [, y, w, h] = getTransformedBBox(node);
+ switch (parent.layout) {
+ case "lr-tb":
+ case "rl-tb":
+ if (attempt === 0) {
+ if (!node[$getTemplateRoot]()[$extra].noLayoutFailure) {
+ if (node.h !== "" && Math.round(h - space.height) > ERROR) {
+ return false;
+ }
+ if (node.w !== "") {
+ if (Math.round(w - space.width) <= ERROR) {
+ return true;
+ }
+ if (parent[$extra].numberInLine === 0) {
+ return space.height > ERROR;
+ }
+ return false;
+ }
+ return space.width > ERROR;
+ }
+ if (node.w !== "") {
+ return Math.round(w - space.width) <= ERROR;
+ }
+ return space.width > ERROR;
+ }
+ if (node[$getTemplateRoot]()[$extra].noLayoutFailure) {
+ return true;
+ }
+ if (node.h !== "" && Math.round(h - space.height) > ERROR) {
+ return false;
+ }
+ if (node.w === "" || Math.round(w - space.width) <= ERROR) {
+ return space.height > ERROR;
+ }
+ if (parent[$isThereMoreWidth]()) {
+ return false;
+ }
+ return space.height > ERROR;
+ case "table":
+ case "tb":
+ if (node[$getTemplateRoot]()[$extra].noLayoutFailure) {
+ return true;
+ }
+ if (node.h !== "" && !node[$isSplittable]()) {
+ return Math.round(h - space.height) <= ERROR;
+ }
+ if (node.w === "" || Math.round(w - space.width) <= ERROR) {
+ return space.height > ERROR;
+ }
+ if (parent[$isThereMoreWidth]()) {
+ return false;
+ }
+ return space.height > ERROR;
+ case "position":
+ if (node[$getTemplateRoot]()[$extra].noLayoutFailure) {
+ return true;
+ }
+ if (node.h === "" || Math.round(h + y - space.height) <= ERROR) {
+ return true;
+ }
+ const area = node[$getTemplateRoot]()[$extra].currentContentArea;
+ return h + y > area.h;
+ case "rl-row":
+ case "row":
+ if (node[$getTemplateRoot]()[$extra].noLayoutFailure) {
+ return true;
+ }
+ if (node.h !== "") {
+ return Math.round(h - space.height) <= ERROR;
+ }
+ return true;
+ default:
+ return true;
+ }
+}
+
+;// ./src/core/xfa/template.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const TEMPLATE_NS_ID = NamespaceIds.template.id;
+const MAX_ATTEMPTS_FOR_LRTB_LAYOUT = 2;
+const MAX_EMPTY_PAGES = 3;
+const DEFAULT_TAB_INDEX = 5000;
+const HEADING_PATTERN = /^H(\d+)$/;
+const MIMES = new Set(["image/gif", "image/jpeg", "image/jpg", "image/pjpeg", "image/png", "image/apng", "image/x-png", "image/bmp", "image/x-ms-bmp", "image/tiff", "image/tif", "application/octet-stream"]);
+const IMAGES_HEADERS = [[[0x42, 0x4d], "image/bmp"], [[0xff, 0xd8, 0xff], "image/jpeg"], [[0x49, 0x49, 0x2a, 0x00], "image/tiff"], [[0x4d, 0x4d, 0x00, 0x2a], "image/tiff"], [[0x47, 0x49, 0x46, 0x38, 0x39, 0x61], "image/gif"], [[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], "image/png"]];
+function getBorderDims(node) {
+ if (!node || !node.border) {
+ return {
+ w: 0,
+ h: 0
+ };
+ }
+ const borderExtra = node.border[$getExtra]();
+ if (!borderExtra) {
+ return {
+ w: 0,
+ h: 0
+ };
+ }
+ return {
+ w: borderExtra.widths[0] + borderExtra.widths[2] + borderExtra.insets[0] + borderExtra.insets[2],
+ h: borderExtra.widths[1] + borderExtra.widths[3] + borderExtra.insets[1] + borderExtra.insets[3]
+ };
+}
+function hasMargin(node) {
+ return node.margin && (node.margin.topInset || node.margin.rightInset || node.margin.bottomInset || node.margin.leftInset);
+}
+function _setValue(templateNode, value) {
+ if (!templateNode.value) {
+ const nodeValue = new Value({});
+ templateNode[$appendChild](nodeValue);
+ templateNode.value = nodeValue;
+ }
+ templateNode.value[$setValue](value);
+}
+function* getContainedChildren(node) {
+ for (const child of node[$getChildren]()) {
+ if (child instanceof SubformSet) {
+ yield* child[$getContainedChildren]();
+ continue;
+ }
+ yield child;
+ }
+}
+function isRequired(node) {
+ return node.validate?.nullTest === "error";
+}
+function setTabIndex(node) {
+ while (node) {
+ if (!node.traversal) {
+ node[$tabIndex] = node[$getParent]()[$tabIndex];
+ return;
+ }
+ if (node[$tabIndex]) {
+ return;
+ }
+ let next = null;
+ for (const child of node.traversal[$getChildren]()) {
+ if (child.operation === "next") {
+ next = child;
+ break;
+ }
+ }
+ if (!next || !next.ref) {
+ node[$tabIndex] = node[$getParent]()[$tabIndex];
+ return;
+ }
+ const root = node[$getTemplateRoot]();
+ node[$tabIndex] = ++root[$tabIndex];
+ const ref = root[$searchNode](next.ref, node);
+ if (!ref) {
+ return;
+ }
+ node = ref[0];
+ }
+}
+function applyAssist(obj, attributes) {
+ const assist = obj.assist;
+ if (assist) {
+ const assistTitle = assist[$toHTML]();
+ if (assistTitle) {
+ attributes.title = assistTitle;
+ }
+ const role = assist.role;
+ const match = role.match(HEADING_PATTERN);
+ if (match) {
+ const ariaRole = "heading";
+ const ariaLevel = match[1];
+ attributes.role = ariaRole;
+ attributes["aria-level"] = ariaLevel;
+ }
+ }
+ if (obj.layout === "table") {
+ attributes.role = "table";
+ } else if (obj.layout === "row") {
+ attributes.role = "row";
+ } else {
+ const parent = obj[$getParent]();
+ if (parent.layout === "row") {
+ attributes.role = parent.assist?.role === "TH" ? "columnheader" : "cell";
+ }
+ }
+}
+function ariaLabel(obj) {
+ if (!obj.assist) {
+ return null;
+ }
+ const assist = obj.assist;
+ if (assist.speak && assist.speak[$content] !== "") {
+ return assist.speak[$content];
+ }
+ if (assist.toolTip) {
+ return assist.toolTip[$content];
+ }
+ return null;
+}
+function valueToHtml(value) {
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ class: ["xfaRich"],
+ style: Object.create(null)
+ },
+ children: [{
+ name: "span",
+ attributes: {
+ style: Object.create(null)
+ },
+ value
+ }]
+ });
+}
+function setFirstUnsplittable(node) {
+ const root = node[$getTemplateRoot]();
+ if (root[$extra].firstUnsplittable === null) {
+ root[$extra].firstUnsplittable = node;
+ root[$extra].noLayoutFailure = true;
+ }
+}
+function unsetFirstUnsplittable(node) {
+ const root = node[$getTemplateRoot]();
+ if (root[$extra].firstUnsplittable === node) {
+ root[$extra].noLayoutFailure = false;
+ }
+}
+function handleBreak(node) {
+ if (node[$extra]) {
+ return false;
+ }
+ node[$extra] = Object.create(null);
+ if (node.targetType === "auto") {
+ return false;
+ }
+ const root = node[$getTemplateRoot]();
+ let target = null;
+ if (node.target) {
+ target = root[$searchNode](node.target, node[$getParent]());
+ if (!target) {
+ return false;
+ }
+ target = target[0];
+ }
+ const {
+ currentPageArea,
+ currentContentArea
+ } = root[$extra];
+ if (node.targetType === "pageArea") {
+ if (!(target instanceof PageArea)) {
+ target = null;
+ }
+ if (node.startNew) {
+ node[$extra].target = target || currentPageArea;
+ return true;
+ } else if (target && target !== currentPageArea) {
+ node[$extra].target = target;
+ return true;
+ }
+ return false;
+ }
+ if (!(target instanceof ContentArea)) {
+ target = null;
+ }
+ const pageArea = target && target[$getParent]();
+ let index;
+ let nextPageArea = pageArea;
+ if (node.startNew) {
+ if (target) {
+ const contentAreas = pageArea.contentArea.children;
+ const indexForCurrent = contentAreas.indexOf(currentContentArea);
+ const indexForTarget = contentAreas.indexOf(target);
+ if (indexForCurrent !== -1 && indexForCurrent < indexForTarget) {
+ nextPageArea = null;
+ }
+ index = indexForTarget - 1;
+ } else {
+ index = currentPageArea.contentArea.children.indexOf(currentContentArea);
+ }
+ } else if (target && target !== currentContentArea) {
+ const contentAreas = pageArea.contentArea.children;
+ index = contentAreas.indexOf(target) - 1;
+ nextPageArea = pageArea === currentPageArea ? null : pageArea;
+ } else {
+ return false;
+ }
+ node[$extra].target = nextPageArea;
+ node[$extra].index = index;
+ return true;
+}
+function handleOverflow(node, extraNode, space) {
+ const root = node[$getTemplateRoot]();
+ const saved = root[$extra].noLayoutFailure;
+ const savedMethod = extraNode[$getSubformParent];
+ extraNode[$getSubformParent] = () => node;
+ root[$extra].noLayoutFailure = true;
+ const res = extraNode[$toHTML](space);
+ node[$addHTML](res.html, res.bbox);
+ root[$extra].noLayoutFailure = saved;
+ extraNode[$getSubformParent] = savedMethod;
+}
+class AppearanceFilter extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "appearanceFilter");
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Arc extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "arc", true);
+ this.circular = getInteger({
+ data: attributes.circular,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.hand = getStringOption(attributes.hand, ["even", "left", "right"]);
+ this.id = attributes.id || "";
+ this.startAngle = getFloat({
+ data: attributes.startAngle,
+ defaultValue: 0,
+ validate: x => true
+ });
+ this.sweepAngle = getFloat({
+ data: attributes.sweepAngle,
+ defaultValue: 360,
+ validate: x => true
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.edge = null;
+ this.fill = null;
+ }
+ [$toHTML]() {
+ const edge = this.edge || new Edge({});
+ const edgeStyle = edge[$toStyle]();
+ const style = Object.create(null);
+ if (this.fill?.presence === "visible") {
+ Object.assign(style, this.fill[$toStyle]());
+ } else {
+ style.fill = "transparent";
+ }
+ style.strokeWidth = measureToString(edge.presence === "visible" ? edge.thickness : 0);
+ style.stroke = edgeStyle.color;
+ let arc;
+ const attributes = {
+ xmlns: SVG_NS,
+ style: {
+ width: "100%",
+ height: "100%",
+ overflow: "visible"
+ }
+ };
+ if (this.sweepAngle === 360) {
+ arc = {
+ name: "ellipse",
+ attributes: {
+ xmlns: SVG_NS,
+ cx: "50%",
+ cy: "50%",
+ rx: "50%",
+ ry: "50%",
+ style
+ }
+ };
+ } else {
+ const startAngle = this.startAngle * Math.PI / 180;
+ const sweepAngle = this.sweepAngle * Math.PI / 180;
+ const largeArc = this.sweepAngle > 180 ? 1 : 0;
+ const [x1, y1, x2, y2] = [50 * (1 + Math.cos(startAngle)), 50 * (1 - Math.sin(startAngle)), 50 * (1 + Math.cos(startAngle + sweepAngle)), 50 * (1 - Math.sin(startAngle + sweepAngle))];
+ arc = {
+ name: "path",
+ attributes: {
+ xmlns: SVG_NS,
+ d: `M ${x1} ${y1} A 50 50 0 ${largeArc} 0 ${x2} ${y2}`,
+ vectorEffect: "non-scaling-stroke",
+ style
+ }
+ };
+ Object.assign(attributes, {
+ viewBox: "0 0 100 100",
+ preserveAspectRatio: "none"
+ });
+ }
+ const svg = {
+ name: "svg",
+ children: [arc],
+ attributes
+ };
+ const parent = this[$getParent]()[$getParent]();
+ if (hasMargin(parent)) {
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ style: {
+ display: "inline",
+ width: "100%",
+ height: "100%"
+ }
+ },
+ children: [svg]
+ });
+ }
+ svg.attributes.style.position = "absolute";
+ return HTMLResult.success(svg);
+ }
+}
+class Area extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "area", true);
+ this.colSpan = getInteger({
+ data: attributes.colSpan,
+ defaultValue: 1,
+ validate: n => n >= 1 || n === -1
+ });
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.x = getMeasurement(attributes.x, "0pt");
+ this.y = getMeasurement(attributes.y, "0pt");
+ this.desc = null;
+ this.extras = null;
+ this.area = new XFAObjectArray();
+ this.draw = new XFAObjectArray();
+ this.exObject = new XFAObjectArray();
+ this.exclGroup = new XFAObjectArray();
+ this.field = new XFAObjectArray();
+ this.subform = new XFAObjectArray();
+ this.subformSet = new XFAObjectArray();
+ }
+ *[$getContainedChildren]() {
+ yield* getContainedChildren(this);
+ }
+ [$isTransparent]() {
+ return true;
+ }
+ [$isBindable]() {
+ return true;
+ }
+ [$addHTML](html, bbox) {
+ const [x, y, w, h] = bbox;
+ this[$extra].width = Math.max(this[$extra].width, x + w);
+ this[$extra].height = Math.max(this[$extra].height, y + h);
+ this[$extra].children.push(html);
+ }
+ [$getAvailableSpace]() {
+ return this[$extra].availableSpace;
+ }
+ [$toHTML](availableSpace) {
+ const style = toStyle(this, "position");
+ const attributes = {
+ style,
+ id: this[$uid],
+ class: ["xfaArea"]
+ };
+ if (isPrintOnly(this)) {
+ attributes.class.push("xfaPrintOnly");
+ }
+ if (this.name) {
+ attributes.xfaName = this.name;
+ }
+ const children = [];
+ this[$extra] = {
+ children,
+ width: 0,
+ height: 0,
+ availableSpace
+ };
+ const result = this[$childrenToHTML]({
+ filter: new Set(["area", "draw", "field", "exclGroup", "subform", "subformSet"]),
+ include: true
+ });
+ if (!result.success) {
+ if (result.isBreak()) {
+ return result;
+ }
+ delete this[$extra];
+ return HTMLResult.FAILURE;
+ }
+ style.width = measureToString(this[$extra].width);
+ style.height = measureToString(this[$extra].height);
+ const html = {
+ name: "div",
+ attributes,
+ children
+ };
+ const bbox = [this.x, this.y, this[$extra].width, this[$extra].height];
+ delete this[$extra];
+ return HTMLResult.success(html, bbox);
+ }
+}
+class Assist extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "assist", true);
+ this.id = attributes.id || "";
+ this.role = attributes.role || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.speak = null;
+ this.toolTip = null;
+ }
+ [$toHTML]() {
+ return this.toolTip?.[$content] || null;
+ }
+}
+class Barcode extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "barcode", true);
+ this.charEncoding = getKeyword({
+ data: attributes.charEncoding ? attributes.charEncoding.toLowerCase() : "",
+ defaultValue: "",
+ validate: k => ["utf-8", "big-five", "fontspecific", "gbk", "gb-18030", "gb-2312", "ksc-5601", "none", "shift-jis", "ucs-2", "utf-16"].includes(k) || k.match(/iso-8859-\d{2}/)
+ });
+ this.checksum = getStringOption(attributes.checksum, ["none", "1mod10", "1mod10_1mod11", "2mod10", "auto"]);
+ this.dataColumnCount = getInteger({
+ data: attributes.dataColumnCount,
+ defaultValue: -1,
+ validate: x => x >= 0
+ });
+ this.dataLength = getInteger({
+ data: attributes.dataLength,
+ defaultValue: -1,
+ validate: x => x >= 0
+ });
+ this.dataPrep = getStringOption(attributes.dataPrep, ["none", "flateCompress"]);
+ this.dataRowCount = getInteger({
+ data: attributes.dataRowCount,
+ defaultValue: -1,
+ validate: x => x >= 0
+ });
+ this.endChar = attributes.endChar || "";
+ this.errorCorrectionLevel = getInteger({
+ data: attributes.errorCorrectionLevel,
+ defaultValue: -1,
+ validate: x => x >= 0 && x <= 8
+ });
+ this.id = attributes.id || "";
+ this.moduleHeight = getMeasurement(attributes.moduleHeight, "5mm");
+ this.moduleWidth = getMeasurement(attributes.moduleWidth, "0.25mm");
+ this.printCheckDigit = getInteger({
+ data: attributes.printCheckDigit,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.rowColumnRatio = getRatio(attributes.rowColumnRatio);
+ this.startChar = attributes.startChar || "";
+ this.textLocation = getStringOption(attributes.textLocation, ["below", "above", "aboveEmbedded", "belowEmbedded", "none"]);
+ this.truncate = getInteger({
+ data: attributes.truncate,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.type = getStringOption(attributes.type ? attributes.type.toLowerCase() : "", ["aztec", "codabar", "code2of5industrial", "code2of5interleaved", "code2of5matrix", "code2of5standard", "code3of9", "code3of9extended", "code11", "code49", "code93", "code128", "code128a", "code128b", "code128c", "code128sscc", "datamatrix", "ean8", "ean8add2", "ean8add5", "ean13", "ean13add2", "ean13add5", "ean13pwcd", "fim", "logmars", "maxicode", "msi", "pdf417", "pdf417macro", "plessey", "postauscust2", "postauscust3", "postausreplypaid", "postausstandard", "postukrm4scc", "postusdpbc", "postusimb", "postusstandard", "postus5zip", "qrcode", "rfid", "rss14", "rss14expanded", "rss14limited", "rss14stacked", "rss14stackedomni", "rss14truncated", "telepen", "ucc128", "ucc128random", "ucc128sscc", "upca", "upcaadd2", "upcaadd5", "upcapwcd", "upce", "upceadd2", "upceadd5", "upcean2", "upcean5", "upsmaxicode"]);
+ this.upsMode = getStringOption(attributes.upsMode, ["usCarrier", "internationalCarrier", "secureSymbol", "standardSymbol"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.wideNarrowRatio = getRatio(attributes.wideNarrowRatio);
+ this.encrypt = null;
+ this.extras = null;
+ }
+}
+class Bind extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "bind", true);
+ this.match = getStringOption(attributes.match, ["once", "dataRef", "global", "none"]);
+ this.ref = attributes.ref || "";
+ this.picture = null;
+ }
+}
+class BindItems extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "bindItems");
+ this.connection = attributes.connection || "";
+ this.labelRef = attributes.labelRef || "";
+ this.ref = attributes.ref || "";
+ this.valueRef = attributes.valueRef || "";
+ }
+}
+class Bookend extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "bookend");
+ this.id = attributes.id || "";
+ this.leader = attributes.leader || "";
+ this.trailer = attributes.trailer || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class BooleanElement extends Option01 {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "boolean");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] === 1 ? "1" : "0");
+ }
+}
+class Border extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "border", true);
+ this.break = getStringOption(attributes.break, ["close", "open"]);
+ this.hand = getStringOption(attributes.hand, ["even", "left", "right"]);
+ this.id = attributes.id || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.corner = new XFAObjectArray(4);
+ this.edge = new XFAObjectArray(4);
+ this.extras = null;
+ this.fill = null;
+ this.margin = null;
+ }
+ [$getExtra]() {
+ if (!this[$extra]) {
+ const edges = this.edge.children.slice();
+ if (edges.length < 4) {
+ const defaultEdge = edges.at(-1) || new Edge({});
+ for (let i = edges.length; i < 4; i++) {
+ edges.push(defaultEdge);
+ }
+ }
+ const widths = edges.map(edge => edge.thickness);
+ const insets = [0, 0, 0, 0];
+ if (this.margin) {
+ insets[0] = this.margin.topInset;
+ insets[1] = this.margin.rightInset;
+ insets[2] = this.margin.bottomInset;
+ insets[3] = this.margin.leftInset;
+ }
+ this[$extra] = {
+ widths,
+ insets,
+ edges
+ };
+ }
+ return this[$extra];
+ }
+ [$toStyle]() {
+ const {
+ edges
+ } = this[$getExtra]();
+ const edgeStyles = edges.map(node => {
+ const style = node[$toStyle]();
+ style.color ||= "#000000";
+ return style;
+ });
+ const style = Object.create(null);
+ if (this.margin) {
+ Object.assign(style, this.margin[$toStyle]());
+ }
+ if (this.fill?.presence === "visible") {
+ Object.assign(style, this.fill[$toStyle]());
+ }
+ if (this.corner.children.some(node => node.radius !== 0)) {
+ const cornerStyles = this.corner.children.map(node => node[$toStyle]());
+ if (cornerStyles.length === 2 || cornerStyles.length === 3) {
+ const last = cornerStyles.at(-1);
+ for (let i = cornerStyles.length; i < 4; i++) {
+ cornerStyles.push(last);
+ }
+ }
+ style.borderRadius = cornerStyles.map(s => s.radius).join(" ");
+ }
+ switch (this.presence) {
+ case "invisible":
+ case "hidden":
+ style.borderStyle = "";
+ break;
+ case "inactive":
+ style.borderStyle = "none";
+ break;
+ default:
+ style.borderStyle = edgeStyles.map(s => s.style).join(" ");
+ break;
+ }
+ style.borderWidth = edgeStyles.map(s => s.width).join(" ");
+ style.borderColor = edgeStyles.map(s => s.color).join(" ");
+ return style;
+ }
+}
+class Break extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "break", true);
+ this.after = getStringOption(attributes.after, ["auto", "contentArea", "pageArea", "pageEven", "pageOdd"]);
+ this.afterTarget = attributes.afterTarget || "";
+ this.before = getStringOption(attributes.before, ["auto", "contentArea", "pageArea", "pageEven", "pageOdd"]);
+ this.beforeTarget = attributes.beforeTarget || "";
+ this.bookendLeader = attributes.bookendLeader || "";
+ this.bookendTrailer = attributes.bookendTrailer || "";
+ this.id = attributes.id || "";
+ this.overflowLeader = attributes.overflowLeader || "";
+ this.overflowTarget = attributes.overflowTarget || "";
+ this.overflowTrailer = attributes.overflowTrailer || "";
+ this.startNew = getInteger({
+ data: attributes.startNew,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+}
+class BreakAfter extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "breakAfter", true);
+ this.id = attributes.id || "";
+ this.leader = attributes.leader || "";
+ this.startNew = getInteger({
+ data: attributes.startNew,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.target = attributes.target || "";
+ this.targetType = getStringOption(attributes.targetType, ["auto", "contentArea", "pageArea"]);
+ this.trailer = attributes.trailer || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.script = null;
+ }
+}
+class BreakBefore extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "breakBefore", true);
+ this.id = attributes.id || "";
+ this.leader = attributes.leader || "";
+ this.startNew = getInteger({
+ data: attributes.startNew,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.target = attributes.target || "";
+ this.targetType = getStringOption(attributes.targetType, ["auto", "contentArea", "pageArea"]);
+ this.trailer = attributes.trailer || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.script = null;
+ }
+ [$toHTML](availableSpace) {
+ this[$extra] = {};
+ return HTMLResult.FAILURE;
+ }
+}
+class Button extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "button", true);
+ this.highlight = getStringOption(attributes.highlight, ["inverted", "none", "outline", "push"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+ [$toHTML](availableSpace) {
+ const parent = this[$getParent]();
+ const grandpa = parent[$getParent]();
+ const htmlButton = {
+ name: "button",
+ attributes: {
+ id: this[$uid],
+ class: ["xfaButton"],
+ style: {}
+ },
+ children: []
+ };
+ for (const event of grandpa.event.children) {
+ if (event.activity !== "click" || !event.script) {
+ continue;
+ }
+ const jsURL = recoverJsURL(event.script[$content]);
+ if (!jsURL) {
+ continue;
+ }
+ const href = fixURL(jsURL.url);
+ if (!href) {
+ continue;
+ }
+ htmlButton.children.push({
+ name: "a",
+ attributes: {
+ id: "link" + this[$uid],
+ href,
+ newWindow: jsURL.newWindow,
+ class: ["xfaLink"],
+ style: {}
+ },
+ children: []
+ });
+ }
+ return HTMLResult.success(htmlButton);
+ }
+}
+class Calculate extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "calculate", true);
+ this.id = attributes.id || "";
+ this.override = getStringOption(attributes.override, ["disabled", "error", "ignore", "warning"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.message = null;
+ this.script = null;
+ }
+}
+class Caption extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "caption", true);
+ this.id = attributes.id || "";
+ this.placement = getStringOption(attributes.placement, ["left", "bottom", "inline", "right", "top"]);
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.reserve = Math.ceil(getMeasurement(attributes.reserve));
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.font = null;
+ this.margin = null;
+ this.para = null;
+ this.value = null;
+ }
+ [$setValue](value) {
+ _setValue(this, value);
+ }
+ [$getExtra](availableSpace) {
+ if (!this[$extra]) {
+ let {
+ width,
+ height
+ } = availableSpace;
+ switch (this.placement) {
+ case "left":
+ case "right":
+ case "inline":
+ width = this.reserve <= 0 ? width : this.reserve;
+ break;
+ case "top":
+ case "bottom":
+ height = this.reserve <= 0 ? height : this.reserve;
+ break;
+ }
+ this[$extra] = layoutNode(this, {
+ width,
+ height
+ });
+ }
+ return this[$extra];
+ }
+ [$toHTML](availableSpace) {
+ if (!this.value) {
+ return HTMLResult.EMPTY;
+ }
+ this[$pushPara]();
+ const value = this.value[$toHTML](availableSpace).html;
+ if (!value) {
+ this[$popPara]();
+ return HTMLResult.EMPTY;
+ }
+ const savedReserve = this.reserve;
+ if (this.reserve <= 0) {
+ const {
+ w,
+ h
+ } = this[$getExtra](availableSpace);
+ switch (this.placement) {
+ case "left":
+ case "right":
+ case "inline":
+ this.reserve = w;
+ break;
+ case "top":
+ case "bottom":
+ this.reserve = h;
+ break;
+ }
+ }
+ const children = [];
+ if (typeof value === "string") {
+ children.push({
+ name: "#text",
+ value
+ });
+ } else {
+ children.push(value);
+ }
+ const style = toStyle(this, "font", "margin", "visibility");
+ switch (this.placement) {
+ case "left":
+ case "right":
+ if (this.reserve > 0) {
+ style.width = measureToString(this.reserve);
+ }
+ break;
+ case "top":
+ case "bottom":
+ if (this.reserve > 0) {
+ style.height = measureToString(this.reserve);
+ }
+ break;
+ }
+ setPara(this, null, value);
+ this[$popPara]();
+ this.reserve = savedReserve;
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ style,
+ class: ["xfaCaption"]
+ },
+ children
+ });
+ }
+}
+class Certificate extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "certificate");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Certificates extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "certificates", true);
+ this.credentialServerPolicy = getStringOption(attributes.credentialServerPolicy, ["optional", "required"]);
+ this.id = attributes.id || "";
+ this.url = attributes.url || "";
+ this.urlPolicy = attributes.urlPolicy || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.encryption = null;
+ this.issuers = null;
+ this.keyUsage = null;
+ this.oids = null;
+ this.signing = null;
+ this.subjectDNs = null;
+ }
+}
+class CheckButton extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "checkButton", true);
+ this.id = attributes.id || "";
+ this.mark = getStringOption(attributes.mark, ["default", "check", "circle", "cross", "diamond", "square", "star"]);
+ this.shape = getStringOption(attributes.shape, ["square", "round"]);
+ this.size = getMeasurement(attributes.size, "10pt");
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.extras = null;
+ this.margin = null;
+ }
+ [$toHTML](availableSpace) {
+ const style = toStyle(this, "margin");
+ const size = measureToString(this.size);
+ style.width = style.height = size;
+ let type;
+ let className;
+ let groupId;
+ const field = this[$getParent]()[$getParent]();
+ const items = field.items.children.length && field.items.children[0][$toHTML]().html || [];
+ const exportedValue = {
+ on: (items[0] !== undefined ? items[0] : "on").toString(),
+ off: (items[1] !== undefined ? items[1] : "off").toString()
+ };
+ const value = field.value?.[$text]() || "off";
+ const checked = value === exportedValue.on || undefined;
+ const container = field[$getSubformParent]();
+ const fieldId = field[$uid];
+ let dataId;
+ if (container instanceof ExclGroup) {
+ groupId = container[$uid];
+ type = "radio";
+ className = "xfaRadio";
+ dataId = container[$data]?.[$uid] || container[$uid];
+ } else {
+ type = "checkbox";
+ className = "xfaCheckbox";
+ dataId = field[$data]?.[$uid] || field[$uid];
+ }
+ const input = {
+ name: "input",
+ attributes: {
+ class: [className],
+ style,
+ fieldId,
+ dataId,
+ type,
+ checked,
+ xfaOn: exportedValue.on,
+ xfaOff: exportedValue.off,
+ "aria-label": ariaLabel(field),
+ "aria-required": false
+ }
+ };
+ if (groupId) {
+ input.attributes.name = groupId;
+ }
+ if (isRequired(field)) {
+ input.attributes["aria-required"] = true;
+ input.attributes.required = true;
+ }
+ return HTMLResult.success({
+ name: "label",
+ attributes: {
+ class: ["xfaLabel"]
+ },
+ children: [input]
+ });
+ }
+}
+class ChoiceList extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "choiceList", true);
+ this.commitOn = getStringOption(attributes.commitOn, ["select", "exit"]);
+ this.id = attributes.id || "";
+ this.open = getStringOption(attributes.open, ["userControl", "always", "multiSelect", "onEntry"]);
+ this.textEntry = getInteger({
+ data: attributes.textEntry,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.extras = null;
+ this.margin = null;
+ }
+ [$toHTML](availableSpace) {
+ const style = toStyle(this, "border", "margin");
+ const ui = this[$getParent]();
+ const field = ui[$getParent]();
+ const fontSize = field.font?.size || 10;
+ const optionStyle = {
+ fontSize: `calc(${fontSize}px * var(--total-scale-factor))`
+ };
+ const children = [];
+ if (field.items.children.length > 0) {
+ const items = field.items;
+ let displayedIndex = 0;
+ let saveIndex = 0;
+ if (items.children.length === 2) {
+ displayedIndex = items.children[0].save;
+ saveIndex = 1 - displayedIndex;
+ }
+ const displayed = items.children[displayedIndex][$toHTML]().html;
+ const values = items.children[saveIndex][$toHTML]().html;
+ let selected = false;
+ const value = field.value?.[$text]() || "";
+ for (let i = 0, ii = displayed.length; i < ii; i++) {
+ const option = {
+ name: "option",
+ attributes: {
+ value: values[i] || displayed[i],
+ style: optionStyle
+ },
+ value: displayed[i]
+ };
+ if (values[i] === value) {
+ option.attributes.selected = selected = true;
+ }
+ children.push(option);
+ }
+ if (!selected) {
+ children.splice(0, 0, {
+ name: "option",
+ attributes: {
+ hidden: true,
+ selected: true
+ },
+ value: " "
+ });
+ }
+ }
+ const selectAttributes = {
+ class: ["xfaSelect"],
+ fieldId: field[$uid],
+ dataId: field[$data]?.[$uid] || field[$uid],
+ style,
+ "aria-label": ariaLabel(field),
+ "aria-required": false
+ };
+ if (isRequired(field)) {
+ selectAttributes["aria-required"] = true;
+ selectAttributes.required = true;
+ }
+ if (this.open === "multiSelect") {
+ selectAttributes.multiple = true;
+ }
+ return HTMLResult.success({
+ name: "label",
+ attributes: {
+ class: ["xfaLabel"]
+ },
+ children: [{
+ name: "select",
+ children,
+ attributes: selectAttributes
+ }]
+ });
+ }
+}
+class Color extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "color", true);
+ this.cSpace = getStringOption(attributes.cSpace, ["SRGB"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.value = attributes.value ? getColor(attributes.value) : "";
+ this.extras = null;
+ }
+ [$hasSettableValue]() {
+ return false;
+ }
+ [$toStyle]() {
+ return this.value ? Util.makeHexColor(this.value.r, this.value.g, this.value.b) : null;
+ }
+}
+class Comb extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "comb");
+ this.id = attributes.id || "";
+ this.numberOfCells = getInteger({
+ data: attributes.numberOfCells,
+ defaultValue: 0,
+ validate: x => x >= 0
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Connect extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "connect", true);
+ this.connection = attributes.connection || "";
+ this.id = attributes.id || "";
+ this.ref = attributes.ref || "";
+ this.usage = getStringOption(attributes.usage, ["exportAndImport", "exportOnly", "importOnly"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.picture = null;
+ }
+}
+class ContentArea extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "contentArea", true);
+ this.h = getMeasurement(attributes.h);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.w = getMeasurement(attributes.w);
+ this.x = getMeasurement(attributes.x, "0pt");
+ this.y = getMeasurement(attributes.y, "0pt");
+ this.desc = null;
+ this.extras = null;
+ }
+ [$toHTML](availableSpace) {
+ const left = measureToString(this.x);
+ const top = measureToString(this.y);
+ const style = {
+ left,
+ top,
+ width: measureToString(this.w),
+ height: measureToString(this.h)
+ };
+ const classNames = ["xfaContentarea"];
+ if (isPrintOnly(this)) {
+ classNames.push("xfaPrintOnly");
+ }
+ return HTMLResult.success({
+ name: "div",
+ children: [],
+ attributes: {
+ style,
+ class: classNames,
+ id: this[$uid]
+ }
+ });
+ }
+}
+class Corner extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "corner", true);
+ this.id = attributes.id || "";
+ this.inverted = getInteger({
+ data: attributes.inverted,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.join = getStringOption(attributes.join, ["square", "round"]);
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.radius = getMeasurement(attributes.radius);
+ this.stroke = getStringOption(attributes.stroke, ["solid", "dashDot", "dashDotDot", "dashed", "dotted", "embossed", "etched", "lowered", "raised"]);
+ this.thickness = getMeasurement(attributes.thickness, "0.5pt");
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ }
+ [$toStyle]() {
+ const style = toStyle(this, "visibility");
+ style.radius = measureToString(this.join === "square" ? 0 : this.radius);
+ return style;
+ }
+}
+class DateElement extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "date");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ const date = this[$content].trim();
+ this[$content] = date ? new Date(date) : null;
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] ? this[$content].toString() : "");
+ }
+}
+class DateTime extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "dateTime");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ const date = this[$content].trim();
+ this[$content] = date ? new Date(date) : null;
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] ? this[$content].toString() : "");
+ }
+}
+class DateTimeEdit extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "dateTimeEdit", true);
+ this.hScrollPolicy = getStringOption(attributes.hScrollPolicy, ["auto", "off", "on"]);
+ this.id = attributes.id || "";
+ this.picker = getStringOption(attributes.picker, ["host", "none"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.comb = null;
+ this.extras = null;
+ this.margin = null;
+ }
+ [$toHTML](availableSpace) {
+ const style = toStyle(this, "border", "font", "margin");
+ const field = this[$getParent]()[$getParent]();
+ const html = {
+ name: "input",
+ attributes: {
+ type: "text",
+ fieldId: field[$uid],
+ dataId: field[$data]?.[$uid] || field[$uid],
+ class: ["xfaTextfield"],
+ style,
+ "aria-label": ariaLabel(field),
+ "aria-required": false
+ }
+ };
+ if (isRequired(field)) {
+ html.attributes["aria-required"] = true;
+ html.attributes.required = true;
+ }
+ return HTMLResult.success({
+ name: "label",
+ attributes: {
+ class: ["xfaLabel"]
+ },
+ children: [html]
+ });
+ }
+}
+class Decimal extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "decimal");
+ this.fracDigits = getInteger({
+ data: attributes.fracDigits,
+ defaultValue: 2,
+ validate: x => true
+ });
+ this.id = attributes.id || "";
+ this.leadDigits = getInteger({
+ data: attributes.leadDigits,
+ defaultValue: -1,
+ validate: x => true
+ });
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ const number = parseFloat(this[$content].trim());
+ this[$content] = isNaN(number) ? null : number;
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] !== null ? this[$content].toString() : "");
+ }
+}
+class DefaultUi extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "defaultUi", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+}
+class Desc extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "desc", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.boolean = new XFAObjectArray();
+ this.date = new XFAObjectArray();
+ this.dateTime = new XFAObjectArray();
+ this.decimal = new XFAObjectArray();
+ this.exData = new XFAObjectArray();
+ this.float = new XFAObjectArray();
+ this.image = new XFAObjectArray();
+ this.integer = new XFAObjectArray();
+ this.text = new XFAObjectArray();
+ this.time = new XFAObjectArray();
+ }
+}
+class DigestMethod extends OptionObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "digestMethod", ["", "SHA1", "SHA256", "SHA512", "RIPEMD160"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class DigestMethods extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "digestMethods", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.digestMethod = new XFAObjectArray();
+ }
+}
+class Draw extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "draw", true);
+ this.anchorType = getStringOption(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]);
+ this.colSpan = getInteger({
+ data: attributes.colSpan,
+ defaultValue: 1,
+ validate: n => n >= 1 || n === -1
+ });
+ this.h = attributes.h ? getMeasurement(attributes.h) : "";
+ this.hAlign = getStringOption(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]);
+ this.id = attributes.id || "";
+ this.locale = attributes.locale || "";
+ this.maxH = getMeasurement(attributes.maxH, "0pt");
+ this.maxW = getMeasurement(attributes.maxW, "0pt");
+ this.minH = getMeasurement(attributes.minH, "0pt");
+ this.minW = getMeasurement(attributes.minW, "0pt");
+ this.name = attributes.name || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.rotate = getInteger({
+ data: attributes.rotate,
+ defaultValue: 0,
+ validate: x => x % 90 === 0
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.w = attributes.w ? getMeasurement(attributes.w) : "";
+ this.x = getMeasurement(attributes.x, "0pt");
+ this.y = getMeasurement(attributes.y, "0pt");
+ this.assist = null;
+ this.border = null;
+ this.caption = null;
+ this.desc = null;
+ this.extras = null;
+ this.font = null;
+ this.keep = null;
+ this.margin = null;
+ this.para = null;
+ this.traversal = null;
+ this.ui = null;
+ this.value = null;
+ this.setProperty = new XFAObjectArray();
+ }
+ [$setValue](value) {
+ _setValue(this, value);
+ }
+ [$toHTML](availableSpace) {
+ setTabIndex(this);
+ if (this.presence === "hidden" || this.presence === "inactive") {
+ return HTMLResult.EMPTY;
+ }
+ fixDimensions(this);
+ this[$pushPara]();
+ const savedW = this.w;
+ const savedH = this.h;
+ const {
+ w,
+ h,
+ isBroken
+ } = layoutNode(this, availableSpace);
+ if (w && this.w === "") {
+ if (isBroken && this[$getSubformParent]()[$isThereMoreWidth]()) {
+ this[$popPara]();
+ return HTMLResult.FAILURE;
+ }
+ this.w = w;
+ }
+ if (h && this.h === "") {
+ this.h = h;
+ }
+ setFirstUnsplittable(this);
+ if (!checkDimensions(this, availableSpace)) {
+ this.w = savedW;
+ this.h = savedH;
+ this[$popPara]();
+ return HTMLResult.FAILURE;
+ }
+ unsetFirstUnsplittable(this);
+ const style = toStyle(this, "font", "hAlign", "dimensions", "position", "presence", "rotate", "anchorType", "border", "margin");
+ setMinMaxDimensions(this, style);
+ if (style.margin) {
+ style.padding = style.margin;
+ delete style.margin;
+ }
+ const classNames = ["xfaDraw"];
+ if (this.font) {
+ classNames.push("xfaFont");
+ }
+ if (isPrintOnly(this)) {
+ classNames.push("xfaPrintOnly");
+ }
+ const attributes = {
+ style,
+ id: this[$uid],
+ class: classNames
+ };
+ if (this.name) {
+ attributes.xfaName = this.name;
+ }
+ const html = {
+ name: "div",
+ attributes,
+ children: []
+ };
+ applyAssist(this, attributes);
+ const bbox = computeBbox(this, html, availableSpace);
+ const value = this.value ? this.value[$toHTML](availableSpace).html : null;
+ if (value === null) {
+ this.w = savedW;
+ this.h = savedH;
+ this[$popPara]();
+ return HTMLResult.success(createWrapper(this, html), bbox);
+ }
+ html.children.push(value);
+ setPara(this, style, value);
+ this.w = savedW;
+ this.h = savedH;
+ this[$popPara]();
+ return HTMLResult.success(createWrapper(this, html), bbox);
+ }
+}
+class Edge extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "edge", true);
+ this.cap = getStringOption(attributes.cap, ["square", "butt", "round"]);
+ this.id = attributes.id || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.stroke = getStringOption(attributes.stroke, ["solid", "dashDot", "dashDotDot", "dashed", "dotted", "embossed", "etched", "lowered", "raised"]);
+ this.thickness = getMeasurement(attributes.thickness, "0.5pt");
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ }
+ [$toStyle]() {
+ const style = toStyle(this, "visibility");
+ Object.assign(style, {
+ linecap: this.cap,
+ width: measureToString(this.thickness),
+ color: this.color ? this.color[$toStyle]() : "#000000",
+ style: ""
+ });
+ if (this.presence !== "visible") {
+ style.style = "none";
+ } else {
+ switch (this.stroke) {
+ case "solid":
+ style.style = "solid";
+ break;
+ case "dashDot":
+ style.style = "dashed";
+ break;
+ case "dashDotDot":
+ style.style = "dashed";
+ break;
+ case "dashed":
+ style.style = "dashed";
+ break;
+ case "dotted":
+ style.style = "dotted";
+ break;
+ case "embossed":
+ style.style = "ridge";
+ break;
+ case "etched":
+ style.style = "groove";
+ break;
+ case "lowered":
+ style.style = "inset";
+ break;
+ case "raised":
+ style.style = "outset";
+ break;
+ }
+ }
+ return style;
+ }
+}
+class Encoding extends OptionObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encoding", ["adbe.x509.rsa_sha1", "adbe.pkcs7.detached", "adbe.pkcs7.sha1"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Encodings extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encodings", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.encoding = new XFAObjectArray();
+ }
+}
+class Encrypt extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encrypt", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.certificate = null;
+ }
+}
+class EncryptData extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encryptData", true);
+ this.id = attributes.id || "";
+ this.operation = getStringOption(attributes.operation, ["encrypt", "decrypt"]);
+ this.target = attributes.target || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.filter = null;
+ this.manifest = null;
+ }
+}
+class Encryption extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encryption", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.certificate = new XFAObjectArray();
+ }
+}
+class EncryptionMethod extends OptionObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encryptionMethod", ["", "AES256-CBC", "TRIPLEDES-CBC", "AES128-CBC", "AES192-CBC"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class EncryptionMethods extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "encryptionMethods", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.encryptionMethod = new XFAObjectArray();
+ }
+}
+class Event extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "event", true);
+ this.activity = getStringOption(attributes.activity, ["click", "change", "docClose", "docReady", "enter", "exit", "full", "indexChange", "initialize", "mouseDown", "mouseEnter", "mouseExit", "mouseUp", "postExecute", "postOpen", "postPrint", "postSave", "postSign", "postSubmit", "preExecute", "preOpen", "prePrint", "preSave", "preSign", "preSubmit", "ready", "validationState"]);
+ this.id = attributes.id || "";
+ this.listen = getStringOption(attributes.listen, ["refOnly", "refAndDescendents"]);
+ this.name = attributes.name || "";
+ this.ref = attributes.ref || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.encryptData = null;
+ this.execute = null;
+ this.script = null;
+ this.signData = null;
+ this.submit = null;
+ }
+}
+class ExData extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "exData");
+ this.contentType = attributes.contentType || "";
+ this.href = attributes.href || "";
+ this.id = attributes.id || "";
+ this.maxLength = getInteger({
+ data: attributes.maxLength,
+ defaultValue: -1,
+ validate: x => x >= -1
+ });
+ this.name = attributes.name || "";
+ this.rid = attributes.rid || "";
+ this.transferEncoding = getStringOption(attributes.transferEncoding, ["none", "base64", "package"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$isCDATAXml]() {
+ return this.contentType === "text/html";
+ }
+ [$onChild](child) {
+ if (this.contentType === "text/html" && child[$namespaceId] === NamespaceIds.xhtml.id) {
+ this[$content] = child;
+ return true;
+ }
+ if (this.contentType === "text/xml") {
+ this[$content] = child;
+ return true;
+ }
+ return false;
+ }
+ [$toHTML](availableSpace) {
+ if (this.contentType !== "text/html" || !this[$content]) {
+ return HTMLResult.EMPTY;
+ }
+ return this[$content][$toHTML](availableSpace);
+ }
+}
+class ExObject extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "exObject", true);
+ this.archive = attributes.archive || "";
+ this.classId = attributes.classId || "";
+ this.codeBase = attributes.codeBase || "";
+ this.codeType = attributes.codeType || "";
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.boolean = new XFAObjectArray();
+ this.date = new XFAObjectArray();
+ this.dateTime = new XFAObjectArray();
+ this.decimal = new XFAObjectArray();
+ this.exData = new XFAObjectArray();
+ this.exObject = new XFAObjectArray();
+ this.float = new XFAObjectArray();
+ this.image = new XFAObjectArray();
+ this.integer = new XFAObjectArray();
+ this.text = new XFAObjectArray();
+ this.time = new XFAObjectArray();
+ }
+}
+class ExclGroup extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "exclGroup", true);
+ this.access = getStringOption(attributes.access, ["open", "nonInteractive", "protected", "readOnly"]);
+ this.accessKey = attributes.accessKey || "";
+ this.anchorType = getStringOption(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]);
+ this.colSpan = getInteger({
+ data: attributes.colSpan,
+ defaultValue: 1,
+ validate: n => n >= 1 || n === -1
+ });
+ this.h = attributes.h ? getMeasurement(attributes.h) : "";
+ this.hAlign = getStringOption(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]);
+ this.id = attributes.id || "";
+ this.layout = getStringOption(attributes.layout, ["position", "lr-tb", "rl-row", "rl-tb", "row", "table", "tb"]);
+ this.maxH = getMeasurement(attributes.maxH, "0pt");
+ this.maxW = getMeasurement(attributes.maxW, "0pt");
+ this.minH = getMeasurement(attributes.minH, "0pt");
+ this.minW = getMeasurement(attributes.minW, "0pt");
+ this.name = attributes.name || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.w = attributes.w ? getMeasurement(attributes.w) : "";
+ this.x = getMeasurement(attributes.x, "0pt");
+ this.y = getMeasurement(attributes.y, "0pt");
+ this.assist = null;
+ this.bind = null;
+ this.border = null;
+ this.calculate = null;
+ this.caption = null;
+ this.desc = null;
+ this.extras = null;
+ this.margin = null;
+ this.para = null;
+ this.traversal = null;
+ this.validate = null;
+ this.connect = new XFAObjectArray();
+ this.event = new XFAObjectArray();
+ this.field = new XFAObjectArray();
+ this.setProperty = new XFAObjectArray();
+ }
+ [$isBindable]() {
+ return true;
+ }
+ [$hasSettableValue]() {
+ return true;
+ }
+ [$setValue](value) {
+ for (const field of this.field.children) {
+ if (!field.value) {
+ const nodeValue = new Value({});
+ field[$appendChild](nodeValue);
+ field.value = nodeValue;
+ }
+ field.value[$setValue](value);
+ }
+ }
+ [$isThereMoreWidth]() {
+ return this.layout.endsWith("-tb") && this[$extra].attempt === 0 && this[$extra].numberInLine > 0 || this[$getParent]()[$isThereMoreWidth]();
+ }
+ [$isSplittable]() {
+ const parent = this[$getSubformParent]();
+ if (!parent[$isSplittable]()) {
+ return false;
+ }
+ if (this[$extra]._isSplittable !== undefined) {
+ return this[$extra]._isSplittable;
+ }
+ if (this.layout === "position" || this.layout.includes("row")) {
+ this[$extra]._isSplittable = false;
+ return false;
+ }
+ if (parent.layout?.endsWith("-tb") && parent[$extra].numberInLine !== 0) {
+ return false;
+ }
+ this[$extra]._isSplittable = true;
+ return true;
+ }
+ [$flushHTML]() {
+ return flushHTML(this);
+ }
+ [$addHTML](html, bbox) {
+ addHTML(this, html, bbox);
+ }
+ [$getAvailableSpace]() {
+ return getAvailableSpace(this);
+ }
+ [$toHTML](availableSpace) {
+ setTabIndex(this);
+ if (this.presence === "hidden" || this.presence === "inactive" || this.h === 0 || this.w === 0) {
+ return HTMLResult.EMPTY;
+ }
+ fixDimensions(this);
+ const children = [];
+ const attributes = {
+ id: this[$uid],
+ class: []
+ };
+ setAccess(this, attributes.class);
+ this[$extra] ||= Object.create(null);
+ Object.assign(this[$extra], {
+ children,
+ attributes,
+ attempt: 0,
+ line: null,
+ numberInLine: 0,
+ availableSpace: {
+ width: Math.min(this.w || Infinity, availableSpace.width),
+ height: Math.min(this.h || Infinity, availableSpace.height)
+ },
+ width: 0,
+ height: 0,
+ prevHeight: 0,
+ currentWidth: 0
+ });
+ const isSplittable = this[$isSplittable]();
+ if (!isSplittable) {
+ setFirstUnsplittable(this);
+ }
+ if (!checkDimensions(this, availableSpace)) {
+ return HTMLResult.FAILURE;
+ }
+ const filter = new Set(["field"]);
+ if (this.layout.includes("row")) {
+ const columnWidths = this[$getSubformParent]().columnWidths;
+ if (Array.isArray(columnWidths) && columnWidths.length > 0) {
+ this[$extra].columnWidths = columnWidths;
+ this[$extra].currentColumn = 0;
+ }
+ }
+ const style = toStyle(this, "anchorType", "dimensions", "position", "presence", "border", "margin", "hAlign");
+ const classNames = ["xfaExclgroup"];
+ const cl = layoutClass(this);
+ if (cl) {
+ classNames.push(cl);
+ }
+ if (isPrintOnly(this)) {
+ classNames.push("xfaPrintOnly");
+ }
+ attributes.style = style;
+ attributes.class = classNames;
+ if (this.name) {
+ attributes.xfaName = this.name;
+ }
+ this[$pushPara]();
+ const isLrTb = this.layout === "lr-tb" || this.layout === "rl-tb";
+ const maxRun = isLrTb ? MAX_ATTEMPTS_FOR_LRTB_LAYOUT : 1;
+ for (; this[$extra].attempt < maxRun; this[$extra].attempt++) {
+ if (isLrTb && this[$extra].attempt === MAX_ATTEMPTS_FOR_LRTB_LAYOUT - 1) {
+ this[$extra].numberInLine = 0;
+ }
+ const result = this[$childrenToHTML]({
+ filter,
+ include: true
+ });
+ if (result.success) {
+ break;
+ }
+ if (result.isBreak()) {
+ this[$popPara]();
+ return result;
+ }
+ if (isLrTb && this[$extra].attempt === 0 && this[$extra].numberInLine === 0 && !this[$getTemplateRoot]()[$extra].noLayoutFailure) {
+ this[$extra].attempt = maxRun;
+ break;
+ }
+ }
+ this[$popPara]();
+ if (!isSplittable) {
+ unsetFirstUnsplittable(this);
+ }
+ if (this[$extra].attempt === maxRun) {
+ if (!isSplittable) {
+ delete this[$extra];
+ }
+ return HTMLResult.FAILURE;
+ }
+ let marginH = 0;
+ let marginV = 0;
+ if (this.margin) {
+ marginH = this.margin.leftInset + this.margin.rightInset;
+ marginV = this.margin.topInset + this.margin.bottomInset;
+ }
+ const width = Math.max(this[$extra].width + marginH, this.w || 0);
+ const height = Math.max(this[$extra].height + marginV, this.h || 0);
+ const bbox = [this.x, this.y, width, height];
+ if (this.w === "") {
+ style.width = measureToString(width);
+ }
+ if (this.h === "") {
+ style.height = measureToString(height);
+ }
+ const html = {
+ name: "div",
+ attributes,
+ children
+ };
+ applyAssist(this, attributes);
+ delete this[$extra];
+ return HTMLResult.success(createWrapper(this, html), bbox);
+ }
+}
+class Execute extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "execute");
+ this.connection = attributes.connection || "";
+ this.executeType = getStringOption(attributes.executeType, ["import", "remerge"]);
+ this.id = attributes.id || "";
+ this.runAt = getStringOption(attributes.runAt, ["client", "both", "server"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Extras extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "extras", true);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.boolean = new XFAObjectArray();
+ this.date = new XFAObjectArray();
+ this.dateTime = new XFAObjectArray();
+ this.decimal = new XFAObjectArray();
+ this.exData = new XFAObjectArray();
+ this.extras = new XFAObjectArray();
+ this.float = new XFAObjectArray();
+ this.image = new XFAObjectArray();
+ this.integer = new XFAObjectArray();
+ this.text = new XFAObjectArray();
+ this.time = new XFAObjectArray();
+ }
+}
+class Field extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "field", true);
+ this.access = getStringOption(attributes.access, ["open", "nonInteractive", "protected", "readOnly"]);
+ this.accessKey = attributes.accessKey || "";
+ this.anchorType = getStringOption(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]);
+ this.colSpan = getInteger({
+ data: attributes.colSpan,
+ defaultValue: 1,
+ validate: n => n >= 1 || n === -1
+ });
+ this.h = attributes.h ? getMeasurement(attributes.h) : "";
+ this.hAlign = getStringOption(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]);
+ this.id = attributes.id || "";
+ this.locale = attributes.locale || "";
+ this.maxH = getMeasurement(attributes.maxH, "0pt");
+ this.maxW = getMeasurement(attributes.maxW, "0pt");
+ this.minH = getMeasurement(attributes.minH, "0pt");
+ this.minW = getMeasurement(attributes.minW, "0pt");
+ this.name = attributes.name || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.rotate = getInteger({
+ data: attributes.rotate,
+ defaultValue: 0,
+ validate: x => x % 90 === 0
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.w = attributes.w ? getMeasurement(attributes.w) : "";
+ this.x = getMeasurement(attributes.x, "0pt");
+ this.y = getMeasurement(attributes.y, "0pt");
+ this.assist = null;
+ this.bind = null;
+ this.border = null;
+ this.calculate = null;
+ this.caption = null;
+ this.desc = null;
+ this.extras = null;
+ this.font = null;
+ this.format = null;
+ this.items = new XFAObjectArray(2);
+ this.keep = null;
+ this.margin = null;
+ this.para = null;
+ this.traversal = null;
+ this.ui = null;
+ this.validate = null;
+ this.value = null;
+ this.bindItems = new XFAObjectArray();
+ this.connect = new XFAObjectArray();
+ this.event = new XFAObjectArray();
+ this.setProperty = new XFAObjectArray();
+ }
+ [$isBindable]() {
+ return true;
+ }
+ [$setValue](value) {
+ _setValue(this, value);
+ }
+ [$toHTML](availableSpace) {
+ setTabIndex(this);
+ if (!this.ui) {
+ this.ui = new Ui({});
+ this.ui[$globalData] = this[$globalData];
+ this[$appendChild](this.ui);
+ let node;
+ switch (this.items.children.length) {
+ case 0:
+ node = new TextEdit({});
+ this.ui.textEdit = node;
+ break;
+ case 1:
+ node = new CheckButton({});
+ this.ui.checkButton = node;
+ break;
+ case 2:
+ node = new ChoiceList({});
+ this.ui.choiceList = node;
+ break;
+ }
+ this.ui[$appendChild](node);
+ }
+ if (!this.ui || this.presence === "hidden" || this.presence === "inactive" || this.h === 0 || this.w === 0) {
+ return HTMLResult.EMPTY;
+ }
+ if (this.caption) {
+ delete this.caption[$extra];
+ }
+ this[$pushPara]();
+ const caption = this.caption ? this.caption[$toHTML](availableSpace).html : null;
+ const savedW = this.w;
+ const savedH = this.h;
+ let marginH = 0;
+ let marginV = 0;
+ if (this.margin) {
+ marginH = this.margin.leftInset + this.margin.rightInset;
+ marginV = this.margin.topInset + this.margin.bottomInset;
+ }
+ let borderDims = null;
+ if (this.w === "" || this.h === "") {
+ let width = null;
+ let height = null;
+ let uiW = 0;
+ let uiH = 0;
+ if (this.ui.checkButton) {
+ uiW = uiH = this.ui.checkButton.size;
+ } else {
+ const {
+ w,
+ h
+ } = layoutNode(this, availableSpace);
+ if (w !== null) {
+ uiW = w;
+ uiH = h;
+ } else {
+ uiH = fonts_getMetrics(this.font, true).lineNoGap;
+ }
+ }
+ borderDims = getBorderDims(this.ui[$getExtra]());
+ uiW += borderDims.w;
+ uiH += borderDims.h;
+ if (this.caption) {
+ const {
+ w,
+ h,
+ isBroken
+ } = this.caption[$getExtra](availableSpace);
+ if (isBroken && this[$getSubformParent]()[$isThereMoreWidth]()) {
+ this[$popPara]();
+ return HTMLResult.FAILURE;
+ }
+ width = w;
+ height = h;
+ switch (this.caption.placement) {
+ case "left":
+ case "right":
+ case "inline":
+ width += uiW;
+ break;
+ case "top":
+ case "bottom":
+ height += uiH;
+ break;
+ }
+ } else {
+ width = uiW;
+ height = uiH;
+ }
+ if (width && this.w === "") {
+ width += marginH;
+ this.w = Math.min(this.maxW <= 0 ? Infinity : this.maxW, this.minW + 1 < width ? width : this.minW);
+ }
+ if (height && this.h === "") {
+ height += marginV;
+ this.h = Math.min(this.maxH <= 0 ? Infinity : this.maxH, this.minH + 1 < height ? height : this.minH);
+ }
+ }
+ this[$popPara]();
+ fixDimensions(this);
+ setFirstUnsplittable(this);
+ if (!checkDimensions(this, availableSpace)) {
+ this.w = savedW;
+ this.h = savedH;
+ this[$popPara]();
+ return HTMLResult.FAILURE;
+ }
+ unsetFirstUnsplittable(this);
+ const style = toStyle(this, "font", "dimensions", "position", "rotate", "anchorType", "presence", "margin", "hAlign");
+ setMinMaxDimensions(this, style);
+ const classNames = ["xfaField"];
+ if (this.font) {
+ classNames.push("xfaFont");
+ }
+ if (isPrintOnly(this)) {
+ classNames.push("xfaPrintOnly");
+ }
+ const attributes = {
+ style,
+ id: this[$uid],
+ class: classNames
+ };
+ if (style.margin) {
+ style.padding = style.margin;
+ delete style.margin;
+ }
+ setAccess(this, classNames);
+ if (this.name) {
+ attributes.xfaName = this.name;
+ }
+ const children = [];
+ const html = {
+ name: "div",
+ attributes,
+ children
+ };
+ applyAssist(this, attributes);
+ const borderStyle = this.border ? this.border[$toStyle]() : null;
+ const bbox = computeBbox(this, html, availableSpace);
+ const ui = this.ui[$toHTML]().html;
+ if (!ui) {
+ Object.assign(style, borderStyle);
+ return HTMLResult.success(createWrapper(this, html), bbox);
+ }
+ if (this[$tabIndex]) {
+ if (ui.children?.[0]) {
+ ui.children[0].attributes.tabindex = this[$tabIndex];
+ } else {
+ ui.attributes.tabindex = this[$tabIndex];
+ }
+ }
+ ui.attributes.style ||= Object.create(null);
+ let aElement = null;
+ if (this.ui.button) {
+ if (ui.children.length === 1) {
+ [aElement] = ui.children.splice(0, 1);
+ }
+ Object.assign(ui.attributes.style, borderStyle);
+ } else {
+ Object.assign(style, borderStyle);
+ }
+ children.push(ui);
+ if (this.value) {
+ if (this.ui.imageEdit) {
+ ui.children.push(this.value[$toHTML]().html);
+ } else if (!this.ui.button) {
+ let value = "";
+ if (this.value.exData) {
+ value = this.value.exData[$text]();
+ } else if (this.value.text) {
+ value = this.value.text[$getExtra]();
+ } else {
+ const htmlValue = this.value[$toHTML]().html;
+ if (htmlValue !== null) {
+ value = htmlValue.children[0].value;
+ }
+ }
+ if (this.ui.textEdit && this.value.text?.maxChars) {
+ ui.children[0].attributes.maxLength = this.value.text.maxChars;
+ }
+ if (value) {
+ if (this.ui.numericEdit) {
+ value = parseFloat(value);
+ value = isNaN(value) ? "" : value.toString();
+ }
+ if (ui.children[0].name === "textarea") {
+ ui.children[0].attributes.textContent = value;
+ } else {
+ ui.children[0].attributes.value = value;
+ }
+ }
+ }
+ }
+ if (!this.ui.imageEdit && ui.children?.[0] && this.h) {
+ borderDims ||= getBorderDims(this.ui[$getExtra]());
+ let captionHeight = 0;
+ if (this.caption && ["top", "bottom"].includes(this.caption.placement)) {
+ captionHeight = this.caption.reserve;
+ if (captionHeight <= 0) {
+ captionHeight = this.caption[$getExtra](availableSpace).h;
+ }
+ const inputHeight = this.h - captionHeight - marginV - borderDims.h;
+ ui.children[0].attributes.style.height = measureToString(inputHeight);
+ } else {
+ ui.children[0].attributes.style.height = "100%";
+ }
+ }
+ if (aElement) {
+ ui.children.push(aElement);
+ }
+ if (!caption) {
+ if (ui.attributes.class) {
+ ui.attributes.class.push("xfaLeft");
+ }
+ this.w = savedW;
+ this.h = savedH;
+ return HTMLResult.success(createWrapper(this, html), bbox);
+ }
+ if (this.ui.button) {
+ if (style.padding) {
+ delete style.padding;
+ }
+ if (caption.name === "div") {
+ caption.name = "span";
+ }
+ ui.children.push(caption);
+ return HTMLResult.success(html, bbox);
+ } else if (this.ui.checkButton) {
+ caption.attributes.class[0] = "xfaCaptionForCheckButton";
+ }
+ ui.attributes.class ||= [];
+ ui.children.splice(0, 0, caption);
+ switch (this.caption.placement) {
+ case "left":
+ ui.attributes.class.push("xfaLeft");
+ break;
+ case "right":
+ ui.attributes.class.push("xfaRight");
+ break;
+ case "top":
+ ui.attributes.class.push("xfaTop");
+ break;
+ case "bottom":
+ ui.attributes.class.push("xfaBottom");
+ break;
+ case "inline":
+ ui.attributes.class.push("xfaLeft");
+ break;
+ }
+ this.w = savedW;
+ this.h = savedH;
+ return HTMLResult.success(createWrapper(this, html), bbox);
+ }
+}
+class Fill extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "fill", true);
+ this.id = attributes.id || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ this.linear = null;
+ this.pattern = null;
+ this.radial = null;
+ this.solid = null;
+ this.stipple = null;
+ }
+ [$toStyle]() {
+ const parent = this[$getParent]();
+ const grandpa = parent[$getParent]();
+ const ggrandpa = grandpa[$getParent]();
+ const style = Object.create(null);
+ let propName = "color";
+ let altPropName = propName;
+ if (parent instanceof Border) {
+ propName = "background-color";
+ altPropName = "background";
+ if (ggrandpa instanceof Ui) {
+ style.backgroundColor = "white";
+ }
+ }
+ if (parent instanceof Rectangle || parent instanceof Arc) {
+ propName = altPropName = "fill";
+ style.fill = "white";
+ }
+ for (const name of Object.getOwnPropertyNames(this)) {
+ if (name === "extras" || name === "color") {
+ continue;
+ }
+ const obj = this[name];
+ if (!(obj instanceof XFAObject)) {
+ continue;
+ }
+ const color = obj[$toStyle](this.color);
+ if (color) {
+ style[color.startsWith("#") ? propName : altPropName] = color;
+ }
+ return style;
+ }
+ if (this.color?.value) {
+ const color = this.color[$toStyle]();
+ style[color.startsWith("#") ? propName : altPropName] = color;
+ }
+ return style;
+ }
+}
+class Filter extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "filter", true);
+ this.addRevocationInfo = getStringOption(attributes.addRevocationInfo, ["", "required", "optional", "none"]);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.version = getInteger({
+ data: this.version,
+ defaultValue: 5,
+ validate: x => x >= 1 && x <= 5
+ });
+ this.appearanceFilter = null;
+ this.certificates = null;
+ this.digestMethods = null;
+ this.encodings = null;
+ this.encryptionMethods = null;
+ this.handler = null;
+ this.lockDocument = null;
+ this.mdp = null;
+ this.reasons = null;
+ this.timeStamp = null;
+ }
+}
+class Float extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "float");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ const number = parseFloat(this[$content].trim());
+ this[$content] = isNaN(number) ? null : number;
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] !== null ? this[$content].toString() : "");
+ }
+}
+class template_Font extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "font", true);
+ this.baselineShift = getMeasurement(attributes.baselineShift);
+ this.fontHorizontalScale = getFloat({
+ data: attributes.fontHorizontalScale,
+ defaultValue: 100,
+ validate: x => x >= 0
+ });
+ this.fontVerticalScale = getFloat({
+ data: attributes.fontVerticalScale,
+ defaultValue: 100,
+ validate: x => x >= 0
+ });
+ this.id = attributes.id || "";
+ this.kerningMode = getStringOption(attributes.kerningMode, ["none", "pair"]);
+ this.letterSpacing = getMeasurement(attributes.letterSpacing, "0");
+ this.lineThrough = getInteger({
+ data: attributes.lineThrough,
+ defaultValue: 0,
+ validate: x => x === 1 || x === 2
+ });
+ this.lineThroughPeriod = getStringOption(attributes.lineThroughPeriod, ["all", "word"]);
+ this.overline = getInteger({
+ data: attributes.overline,
+ defaultValue: 0,
+ validate: x => x === 1 || x === 2
+ });
+ this.overlinePeriod = getStringOption(attributes.overlinePeriod, ["all", "word"]);
+ this.posture = getStringOption(attributes.posture, ["normal", "italic"]);
+ this.size = getMeasurement(attributes.size, "10pt");
+ this.typeface = attributes.typeface || "Courier";
+ this.underline = getInteger({
+ data: attributes.underline,
+ defaultValue: 0,
+ validate: x => x === 1 || x === 2
+ });
+ this.underlinePeriod = getStringOption(attributes.underlinePeriod, ["all", "word"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.weight = getStringOption(attributes.weight, ["normal", "bold"]);
+ this.extras = null;
+ this.fill = null;
+ }
+ [$clean](builder) {
+ super[$clean](builder);
+ this[$globalData].usedTypefaces.add(this.typeface);
+ }
+ [$toStyle]() {
+ const style = toStyle(this, "fill");
+ const color = style.color;
+ if (color) {
+ if (color === "#000000") {
+ delete style.color;
+ } else if (!color.startsWith("#")) {
+ style.background = color;
+ style.backgroundClip = "text";
+ style.color = "transparent";
+ }
+ }
+ if (this.baselineShift) {
+ style.verticalAlign = measureToString(this.baselineShift);
+ }
+ style.fontKerning = this.kerningMode === "none" ? "none" : "normal";
+ style.letterSpacing = measureToString(this.letterSpacing);
+ if (this.lineThrough !== 0) {
+ style.textDecoration = "line-through";
+ if (this.lineThrough === 2) {
+ style.textDecorationStyle = "double";
+ }
+ }
+ if (this.overline !== 0) {
+ style.textDecoration = "overline";
+ if (this.overline === 2) {
+ style.textDecorationStyle = "double";
+ }
+ }
+ style.fontStyle = this.posture;
+ style.fontSize = measureToString(0.99 * this.size);
+ setFontFamily(this, this, this[$globalData].fontFinder, style);
+ if (this.underline !== 0) {
+ style.textDecoration = "underline";
+ if (this.underline === 2) {
+ style.textDecorationStyle = "double";
+ }
+ }
+ style.fontWeight = this.weight;
+ return style;
+ }
+}
+class Format extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "format", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.picture = null;
+ }
+}
+class Handler extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "handler");
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Hyphenation extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "hyphenation");
+ this.excludeAllCaps = getInteger({
+ data: attributes.excludeAllCaps,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.excludeInitialCap = getInteger({
+ data: attributes.excludeInitialCap,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.hyphenate = getInteger({
+ data: attributes.hyphenate,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.id = attributes.id || "";
+ this.pushCharacterCount = getInteger({
+ data: attributes.pushCharacterCount,
+ defaultValue: 3,
+ validate: x => x >= 0
+ });
+ this.remainCharacterCount = getInteger({
+ data: attributes.remainCharacterCount,
+ defaultValue: 3,
+ validate: x => x >= 0
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.wordCharacterCount = getInteger({
+ data: attributes.wordCharacterCount,
+ defaultValue: 7,
+ validate: x => x >= 0
+ });
+ }
+}
+class Image extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "image");
+ this.aspect = getStringOption(attributes.aspect, ["fit", "actual", "height", "none", "width"]);
+ this.contentType = attributes.contentType || "";
+ this.href = attributes.href || "";
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.transferEncoding = getStringOption(attributes.transferEncoding, ["base64", "none", "package"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$toHTML]() {
+ if (this.contentType && !MIMES.has(this.contentType.toLowerCase())) {
+ return HTMLResult.EMPTY;
+ }
+ let buffer = this[$globalData].images?.get(this.href);
+ if (!buffer && (this.href || !this[$content])) {
+ return HTMLResult.EMPTY;
+ }
+ if (!buffer && this.transferEncoding === "base64") {
+ buffer = Uint8Array.fromBase64(this[$content]);
+ }
+ if (!buffer) {
+ return HTMLResult.EMPTY;
+ }
+ if (!this.contentType) {
+ for (const [header, type] of IMAGES_HEADERS) {
+ if (buffer.length > header.length && header.every((x, i) => x === buffer[i])) {
+ this.contentType = type;
+ break;
+ }
+ }
+ if (!this.contentType) {
+ return HTMLResult.EMPTY;
+ }
+ }
+ const blob = new Blob([buffer], {
+ type: this.contentType
+ });
+ let style;
+ switch (this.aspect) {
+ case "fit":
+ case "actual":
+ break;
+ case "height":
+ style = {
+ height: "100%",
+ objectFit: "fill"
+ };
+ break;
+ case "none":
+ style = {
+ width: "100%",
+ height: "100%",
+ objectFit: "fill"
+ };
+ break;
+ case "width":
+ style = {
+ width: "100%",
+ objectFit: "fill"
+ };
+ break;
+ }
+ const parent = this[$getParent]();
+ return HTMLResult.success({
+ name: "img",
+ attributes: {
+ class: ["xfaImage"],
+ style,
+ src: URL.createObjectURL(blob),
+ alt: parent ? ariaLabel(parent[$getParent]()) : null
+ }
+ });
+ }
+}
+class ImageEdit extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "imageEdit", true);
+ this.data = getStringOption(attributes.data, ["link", "embed"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.extras = null;
+ this.margin = null;
+ }
+ [$toHTML](availableSpace) {
+ if (this.data === "embed") {
+ return HTMLResult.success({
+ name: "div",
+ children: [],
+ attributes: {}
+ });
+ }
+ return HTMLResult.EMPTY;
+ }
+}
+class Integer extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "integer");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ const number = parseInt(this[$content].trim(), 10);
+ this[$content] = isNaN(number) ? null : number;
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] !== null ? this[$content].toString() : "");
+ }
+}
+class Issuers extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "issuers", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.certificate = new XFAObjectArray();
+ }
+}
+class Items extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "items", true);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.ref = attributes.ref || "";
+ this.save = getInteger({
+ data: attributes.save,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.boolean = new XFAObjectArray();
+ this.date = new XFAObjectArray();
+ this.dateTime = new XFAObjectArray();
+ this.decimal = new XFAObjectArray();
+ this.exData = new XFAObjectArray();
+ this.float = new XFAObjectArray();
+ this.image = new XFAObjectArray();
+ this.integer = new XFAObjectArray();
+ this.text = new XFAObjectArray();
+ this.time = new XFAObjectArray();
+ }
+ [$toHTML]() {
+ const output = [];
+ for (const child of this[$getChildren]()) {
+ output.push(child[$text]());
+ }
+ return HTMLResult.success(output);
+ }
+}
+class Keep extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "keep", true);
+ this.id = attributes.id || "";
+ const options = ["none", "contentArea", "pageArea"];
+ this.intact = getStringOption(attributes.intact, options);
+ this.next = getStringOption(attributes.next, options);
+ this.previous = getStringOption(attributes.previous, options);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+}
+class KeyUsage extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "keyUsage");
+ const options = ["", "yes", "no"];
+ this.crlSign = getStringOption(attributes.crlSign, options);
+ this.dataEncipherment = getStringOption(attributes.dataEncipherment, options);
+ this.decipherOnly = getStringOption(attributes.decipherOnly, options);
+ this.digitalSignature = getStringOption(attributes.digitalSignature, options);
+ this.encipherOnly = getStringOption(attributes.encipherOnly, options);
+ this.id = attributes.id || "";
+ this.keyAgreement = getStringOption(attributes.keyAgreement, options);
+ this.keyCertSign = getStringOption(attributes.keyCertSign, options);
+ this.keyEncipherment = getStringOption(attributes.keyEncipherment, options);
+ this.nonRepudiation = getStringOption(attributes.nonRepudiation, options);
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Line extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "line", true);
+ this.hand = getStringOption(attributes.hand, ["even", "left", "right"]);
+ this.id = attributes.id || "";
+ this.slope = getStringOption(attributes.slope, ["\\", "/"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.edge = null;
+ }
+ [$toHTML]() {
+ const parent = this[$getParent]()[$getParent]();
+ const edge = this.edge || new Edge({});
+ const edgeStyle = edge[$toStyle]();
+ const style = Object.create(null);
+ const thickness = edge.presence === "visible" ? edge.thickness : 0;
+ style.strokeWidth = measureToString(thickness);
+ style.stroke = edgeStyle.color;
+ let x1, y1, x2, y2;
+ let width = "100%";
+ let height = "100%";
+ if (parent.w <= thickness) {
+ [x1, y1, x2, y2] = ["50%", 0, "50%", "100%"];
+ width = style.strokeWidth;
+ } else if (parent.h <= thickness) {
+ [x1, y1, x2, y2] = [0, "50%", "100%", "50%"];
+ height = style.strokeWidth;
+ } else if (this.slope === "\\") {
+ [x1, y1, x2, y2] = [0, 0, "100%", "100%"];
+ } else {
+ [x1, y1, x2, y2] = [0, "100%", "100%", 0];
+ }
+ const line = {
+ name: "line",
+ attributes: {
+ xmlns: SVG_NS,
+ x1,
+ y1,
+ x2,
+ y2,
+ style
+ }
+ };
+ const svg = {
+ name: "svg",
+ children: [line],
+ attributes: {
+ xmlns: SVG_NS,
+ width,
+ height,
+ style: {
+ overflow: "visible"
+ }
+ }
+ };
+ if (hasMargin(parent)) {
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ style: {
+ display: "inline",
+ width: "100%",
+ height: "100%"
+ }
+ },
+ children: [svg]
+ });
+ }
+ svg.attributes.style.position = "absolute";
+ return HTMLResult.success(svg);
+ }
+}
+class Linear extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "linear", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["toRight", "toBottom", "toLeft", "toTop"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ }
+ [$toStyle](startColor) {
+ startColor = startColor ? startColor[$toStyle]() : "#FFFFFF";
+ const transf = this.type.replace(/([RBLT])/, " $1").toLowerCase();
+ const endColor = this.color ? this.color[$toStyle]() : "#000000";
+ return `linear-gradient(${transf}, ${startColor}, ${endColor})`;
+ }
+}
+class LockDocument extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "lockDocument");
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ this[$content] = getStringOption(this[$content], ["auto", "0", "1"]);
+ }
+}
+class Manifest extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "manifest", true);
+ this.action = getStringOption(attributes.action, ["include", "all", "exclude"]);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.ref = new XFAObjectArray();
+ }
+}
+class Margin extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "margin", true);
+ this.bottomInset = getMeasurement(attributes.bottomInset, "0");
+ this.id = attributes.id || "";
+ this.leftInset = getMeasurement(attributes.leftInset, "0");
+ this.rightInset = getMeasurement(attributes.rightInset, "0");
+ this.topInset = getMeasurement(attributes.topInset, "0");
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+ [$toStyle]() {
+ return {
+ margin: measureToString(this.topInset) + " " + measureToString(this.rightInset) + " " + measureToString(this.bottomInset) + " " + measureToString(this.leftInset)
+ };
+ }
+}
+class Mdp extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "mdp");
+ this.id = attributes.id || "";
+ this.permissions = getInteger({
+ data: attributes.permissions,
+ defaultValue: 2,
+ validate: x => x === 1 || x === 3
+ });
+ this.signatureType = getStringOption(attributes.signatureType, ["filler", "author"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Medium extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "medium");
+ this.id = attributes.id || "";
+ this.imagingBBox = getBBox(attributes.imagingBBox);
+ this.long = getMeasurement(attributes.long);
+ this.orientation = getStringOption(attributes.orientation, ["portrait", "landscape"]);
+ this.short = getMeasurement(attributes.short);
+ this.stock = attributes.stock || "";
+ this.trayIn = getStringOption(attributes.trayIn, ["auto", "delegate", "pageFront"]);
+ this.trayOut = getStringOption(attributes.trayOut, ["auto", "delegate"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Message extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "message", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.text = new XFAObjectArray();
+ }
+}
+class NumericEdit extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "numericEdit", true);
+ this.hScrollPolicy = getStringOption(attributes.hScrollPolicy, ["auto", "off", "on"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.comb = null;
+ this.extras = null;
+ this.margin = null;
+ }
+ [$toHTML](availableSpace) {
+ const style = toStyle(this, "border", "font", "margin");
+ const field = this[$getParent]()[$getParent]();
+ const html = {
+ name: "input",
+ attributes: {
+ type: "text",
+ fieldId: field[$uid],
+ dataId: field[$data]?.[$uid] || field[$uid],
+ class: ["xfaTextfield"],
+ style,
+ "aria-label": ariaLabel(field),
+ "aria-required": false
+ }
+ };
+ if (isRequired(field)) {
+ html.attributes["aria-required"] = true;
+ html.attributes.required = true;
+ }
+ return HTMLResult.success({
+ name: "label",
+ attributes: {
+ class: ["xfaLabel"]
+ },
+ children: [html]
+ });
+ }
+}
+class Occur extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "occur", true);
+ this.id = attributes.id || "";
+ this.initial = attributes.initial !== "" ? getInteger({
+ data: attributes.initial,
+ defaultValue: "",
+ validate: x => true
+ }) : "";
+ this.max = attributes.max !== "" ? getInteger({
+ data: attributes.max,
+ defaultValue: -1,
+ validate: x => true
+ }) : "";
+ this.min = attributes.min !== "" ? getInteger({
+ data: attributes.min,
+ defaultValue: 1,
+ validate: x => true
+ }) : "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+ [$clean]() {
+ const parent = this[$getParent]();
+ const originalMin = this.min;
+ if (this.min === "") {
+ this.min = parent instanceof PageArea || parent instanceof PageSet ? 0 : 1;
+ }
+ if (this.max === "") {
+ if (originalMin === "") {
+ this.max = parent instanceof PageArea || parent instanceof PageSet ? -1 : 1;
+ } else {
+ this.max = this.min;
+ }
+ }
+ if (this.max !== -1 && this.max < this.min) {
+ this.max = this.min;
+ }
+ if (this.initial === "") {
+ this.initial = parent instanceof Template ? 1 : this.min;
+ }
+ }
+}
+class Oid extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "oid");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Oids extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "oids", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.oid = new XFAObjectArray();
+ }
+}
+class Overflow extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "overflow");
+ this.id = attributes.id || "";
+ this.leader = attributes.leader || "";
+ this.target = attributes.target || "";
+ this.trailer = attributes.trailer || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$getExtra]() {
+ if (!this[$extra]) {
+ const parent = this[$getParent]();
+ const root = this[$getTemplateRoot]();
+ const target = root[$searchNode](this.target, parent);
+ const leader = root[$searchNode](this.leader, parent);
+ const trailer = root[$searchNode](this.trailer, parent);
+ this[$extra] = {
+ target: target?.[0] || null,
+ leader: leader?.[0] || null,
+ trailer: trailer?.[0] || null,
+ addLeader: false,
+ addTrailer: false
+ };
+ }
+ return this[$extra];
+ }
+}
+class PageArea extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "pageArea", true);
+ this.blankOrNotBlank = getStringOption(attributes.blankOrNotBlank, ["any", "blank", "notBlank"]);
+ this.id = attributes.id || "";
+ this.initialNumber = getInteger({
+ data: attributes.initialNumber,
+ defaultValue: 1,
+ validate: x => true
+ });
+ this.name = attributes.name || "";
+ this.numbered = getInteger({
+ data: attributes.numbered,
+ defaultValue: 1,
+ validate: x => true
+ });
+ this.oddOrEven = getStringOption(attributes.oddOrEven, ["any", "even", "odd"]);
+ this.pagePosition = getStringOption(attributes.pagePosition, ["any", "first", "last", "only", "rest"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.desc = null;
+ this.extras = null;
+ this.medium = null;
+ this.occur = null;
+ this.area = new XFAObjectArray();
+ this.contentArea = new XFAObjectArray();
+ this.draw = new XFAObjectArray();
+ this.exclGroup = new XFAObjectArray();
+ this.field = new XFAObjectArray();
+ this.subform = new XFAObjectArray();
+ }
+ [$isUsable]() {
+ if (!this[$extra]) {
+ this[$extra] = {
+ numberOfUse: 0
+ };
+ return true;
+ }
+ return !this.occur || this.occur.max === -1 || this[$extra].numberOfUse < this.occur.max;
+ }
+ [$cleanPage]() {
+ delete this[$extra];
+ }
+ [$getNextPage]() {
+ this[$extra] ||= {
+ numberOfUse: 0
+ };
+ const parent = this[$getParent]();
+ if (parent.relation === "orderedOccurrence") {
+ if (this[$isUsable]()) {
+ this[$extra].numberOfUse += 1;
+ return this;
+ }
+ }
+ return parent[$getNextPage]();
+ }
+ [$getAvailableSpace]() {
+ return this[$extra].space || {
+ width: 0,
+ height: 0
+ };
+ }
+ [$toHTML]() {
+ this[$extra] ||= {
+ numberOfUse: 1
+ };
+ const children = [];
+ this[$extra].children = children;
+ const style = Object.create(null);
+ if (this.medium && this.medium.short && this.medium.long) {
+ style.width = measureToString(this.medium.short);
+ style.height = measureToString(this.medium.long);
+ this[$extra].space = {
+ width: this.medium.short,
+ height: this.medium.long
+ };
+ if (this.medium.orientation === "landscape") {
+ const x = style.width;
+ style.width = style.height;
+ style.height = x;
+ this[$extra].space = {
+ width: this.medium.long,
+ height: this.medium.short
+ };
+ }
+ } else {
+ warn("XFA - No medium specified in pageArea: please file a bug.");
+ }
+ this[$childrenToHTML]({
+ filter: new Set(["area", "draw", "field", "subform"]),
+ include: true
+ });
+ this[$childrenToHTML]({
+ filter: new Set(["contentArea"]),
+ include: true
+ });
+ return HTMLResult.success({
+ name: "div",
+ children,
+ attributes: {
+ class: ["xfaPage"],
+ id: this[$uid],
+ style,
+ xfaName: this.name
+ }
+ });
+ }
+}
+class PageSet extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "pageSet", true);
+ this.duplexImposition = getStringOption(attributes.duplexImposition, ["longEdge", "shortEdge"]);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.relation = getStringOption(attributes.relation, ["orderedOccurrence", "duplexPaginated", "simplexPaginated"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.occur = null;
+ this.pageArea = new XFAObjectArray();
+ this.pageSet = new XFAObjectArray();
+ }
+ [$cleanPage]() {
+ for (const page of this.pageArea.children) {
+ page[$cleanPage]();
+ }
+ for (const page of this.pageSet.children) {
+ page[$cleanPage]();
+ }
+ }
+ [$isUsable]() {
+ return !this.occur || this.occur.max === -1 || this[$extra].numberOfUse < this.occur.max;
+ }
+ [$getNextPage]() {
+ this[$extra] ||= {
+ numberOfUse: 1,
+ pageIndex: -1,
+ pageSetIndex: -1
+ };
+ if (this.relation === "orderedOccurrence") {
+ if (this[$extra].pageIndex + 1 < this.pageArea.children.length) {
+ this[$extra].pageIndex += 1;
+ const pageArea = this.pageArea.children[this[$extra].pageIndex];
+ return pageArea[$getNextPage]();
+ }
+ if (this[$extra].pageSetIndex + 1 < this.pageSet.children.length) {
+ this[$extra].pageSetIndex += 1;
+ return this.pageSet.children[this[$extra].pageSetIndex][$getNextPage]();
+ }
+ if (this[$isUsable]()) {
+ this[$extra].numberOfUse += 1;
+ this[$extra].pageIndex = -1;
+ this[$extra].pageSetIndex = -1;
+ return this[$getNextPage]();
+ }
+ const parent = this[$getParent]();
+ if (parent instanceof PageSet) {
+ return parent[$getNextPage]();
+ }
+ this[$cleanPage]();
+ return this[$getNextPage]();
+ }
+ const pageNumber = this[$getTemplateRoot]()[$extra].pageNumber;
+ const parity = pageNumber % 2 === 0 ? "even" : "odd";
+ const position = pageNumber === 0 ? "first" : "rest";
+ let page = this.pageArea.children.find(p => p.oddOrEven === parity && p.pagePosition === position);
+ if (page) {
+ return page;
+ }
+ page = this.pageArea.children.find(p => p.oddOrEven === "any" && p.pagePosition === position);
+ if (page) {
+ return page;
+ }
+ page = this.pageArea.children.find(p => p.oddOrEven === "any" && p.pagePosition === "any");
+ if (page) {
+ return page;
+ }
+ return this.pageArea.children[0];
+ }
+}
+class Para extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "para", true);
+ this.hAlign = getStringOption(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]);
+ this.id = attributes.id || "";
+ this.lineHeight = attributes.lineHeight ? getMeasurement(attributes.lineHeight, "0pt") : "";
+ this.marginLeft = attributes.marginLeft ? getMeasurement(attributes.marginLeft, "0pt") : "";
+ this.marginRight = attributes.marginRight ? getMeasurement(attributes.marginRight, "0pt") : "";
+ this.orphans = getInteger({
+ data: attributes.orphans,
+ defaultValue: 0,
+ validate: x => x >= 0
+ });
+ this.preserve = attributes.preserve || "";
+ this.radixOffset = attributes.radixOffset ? getMeasurement(attributes.radixOffset, "0pt") : "";
+ this.spaceAbove = attributes.spaceAbove ? getMeasurement(attributes.spaceAbove, "0pt") : "";
+ this.spaceBelow = attributes.spaceBelow ? getMeasurement(attributes.spaceBelow, "0pt") : "";
+ this.tabDefault = attributes.tabDefault ? getMeasurement(this.tabDefault) : "";
+ this.tabStops = (attributes.tabStops || "").trim().split(/\s+/).map((x, i) => i % 2 === 1 ? getMeasurement(x) : x);
+ this.textIndent = attributes.textIndent ? getMeasurement(attributes.textIndent, "0pt") : "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.vAlign = getStringOption(attributes.vAlign, ["top", "bottom", "middle"]);
+ this.widows = getInteger({
+ data: attributes.widows,
+ defaultValue: 0,
+ validate: x => x >= 0
+ });
+ this.hyphenation = null;
+ }
+ [$toStyle]() {
+ const style = toStyle(this, "hAlign");
+ if (this.marginLeft !== "") {
+ style.paddingLeft = measureToString(this.marginLeft);
+ }
+ if (this.marginRight !== "") {
+ style.paddingRight = measureToString(this.marginRight);
+ }
+ if (this.spaceAbove !== "") {
+ style.paddingTop = measureToString(this.spaceAbove);
+ }
+ if (this.spaceBelow !== "") {
+ style.paddingBottom = measureToString(this.spaceBelow);
+ }
+ if (this.textIndent !== "") {
+ style.textIndent = measureToString(this.textIndent);
+ fixTextIndent(style);
+ }
+ if (this.lineHeight > 0) {
+ style.lineHeight = measureToString(this.lineHeight);
+ }
+ if (this.tabDefault !== "") {
+ style.tabSize = measureToString(this.tabDefault);
+ }
+ if (this.tabStops.length > 0) {}
+ if (this.hyphenatation) {
+ Object.assign(style, this.hyphenatation[$toStyle]());
+ }
+ return style;
+ }
+}
+class PasswordEdit extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "passwordEdit", true);
+ this.hScrollPolicy = getStringOption(attributes.hScrollPolicy, ["auto", "off", "on"]);
+ this.id = attributes.id || "";
+ this.passwordChar = attributes.passwordChar || "*";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.extras = null;
+ this.margin = null;
+ }
+}
+class template_Pattern extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "pattern", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["crossHatch", "crossDiagonal", "diagonalLeft", "diagonalRight", "horizontal", "vertical"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ }
+ [$toStyle](startColor) {
+ startColor = startColor ? startColor[$toStyle]() : "#FFFFFF";
+ const endColor = this.color ? this.color[$toStyle]() : "#000000";
+ const width = 5;
+ const cmd = "repeating-linear-gradient";
+ const colors = `${startColor},${startColor} ${width}px,${endColor} ${width}px,${endColor} ${2 * width}px`;
+ switch (this.type) {
+ case "crossHatch":
+ return `${cmd}(to top,${colors}) ${cmd}(to right,${colors})`;
+ case "crossDiagonal":
+ return `${cmd}(45deg,${colors}) ${cmd}(-45deg,${colors})`;
+ case "diagonalLeft":
+ return `${cmd}(45deg,${colors})`;
+ case "diagonalRight":
+ return `${cmd}(-45deg,${colors})`;
+ case "horizontal":
+ return `${cmd}(to top,${colors})`;
+ case "vertical":
+ return `${cmd}(to right,${colors})`;
+ }
+ return "";
+ }
+}
+class Picture extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "picture");
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Proto extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "proto", true);
+ this.appearanceFilter = new XFAObjectArray();
+ this.arc = new XFAObjectArray();
+ this.area = new XFAObjectArray();
+ this.assist = new XFAObjectArray();
+ this.barcode = new XFAObjectArray();
+ this.bindItems = new XFAObjectArray();
+ this.bookend = new XFAObjectArray();
+ this.boolean = new XFAObjectArray();
+ this.border = new XFAObjectArray();
+ this.break = new XFAObjectArray();
+ this.breakAfter = new XFAObjectArray();
+ this.breakBefore = new XFAObjectArray();
+ this.button = new XFAObjectArray();
+ this.calculate = new XFAObjectArray();
+ this.caption = new XFAObjectArray();
+ this.certificate = new XFAObjectArray();
+ this.certificates = new XFAObjectArray();
+ this.checkButton = new XFAObjectArray();
+ this.choiceList = new XFAObjectArray();
+ this.color = new XFAObjectArray();
+ this.comb = new XFAObjectArray();
+ this.connect = new XFAObjectArray();
+ this.contentArea = new XFAObjectArray();
+ this.corner = new XFAObjectArray();
+ this.date = new XFAObjectArray();
+ this.dateTime = new XFAObjectArray();
+ this.dateTimeEdit = new XFAObjectArray();
+ this.decimal = new XFAObjectArray();
+ this.defaultUi = new XFAObjectArray();
+ this.desc = new XFAObjectArray();
+ this.digestMethod = new XFAObjectArray();
+ this.digestMethods = new XFAObjectArray();
+ this.draw = new XFAObjectArray();
+ this.edge = new XFAObjectArray();
+ this.encoding = new XFAObjectArray();
+ this.encodings = new XFAObjectArray();
+ this.encrypt = new XFAObjectArray();
+ this.encryptData = new XFAObjectArray();
+ this.encryption = new XFAObjectArray();
+ this.encryptionMethod = new XFAObjectArray();
+ this.encryptionMethods = new XFAObjectArray();
+ this.event = new XFAObjectArray();
+ this.exData = new XFAObjectArray();
+ this.exObject = new XFAObjectArray();
+ this.exclGroup = new XFAObjectArray();
+ this.execute = new XFAObjectArray();
+ this.extras = new XFAObjectArray();
+ this.field = new XFAObjectArray();
+ this.fill = new XFAObjectArray();
+ this.filter = new XFAObjectArray();
+ this.float = new XFAObjectArray();
+ this.font = new XFAObjectArray();
+ this.format = new XFAObjectArray();
+ this.handler = new XFAObjectArray();
+ this.hyphenation = new XFAObjectArray();
+ this.image = new XFAObjectArray();
+ this.imageEdit = new XFAObjectArray();
+ this.integer = new XFAObjectArray();
+ this.issuers = new XFAObjectArray();
+ this.items = new XFAObjectArray();
+ this.keep = new XFAObjectArray();
+ this.keyUsage = new XFAObjectArray();
+ this.line = new XFAObjectArray();
+ this.linear = new XFAObjectArray();
+ this.lockDocument = new XFAObjectArray();
+ this.manifest = new XFAObjectArray();
+ this.margin = new XFAObjectArray();
+ this.mdp = new XFAObjectArray();
+ this.medium = new XFAObjectArray();
+ this.message = new XFAObjectArray();
+ this.numericEdit = new XFAObjectArray();
+ this.occur = new XFAObjectArray();
+ this.oid = new XFAObjectArray();
+ this.oids = new XFAObjectArray();
+ this.overflow = new XFAObjectArray();
+ this.pageArea = new XFAObjectArray();
+ this.pageSet = new XFAObjectArray();
+ this.para = new XFAObjectArray();
+ this.passwordEdit = new XFAObjectArray();
+ this.pattern = new XFAObjectArray();
+ this.picture = new XFAObjectArray();
+ this.radial = new XFAObjectArray();
+ this.reason = new XFAObjectArray();
+ this.reasons = new XFAObjectArray();
+ this.rectangle = new XFAObjectArray();
+ this.ref = new XFAObjectArray();
+ this.script = new XFAObjectArray();
+ this.setProperty = new XFAObjectArray();
+ this.signData = new XFAObjectArray();
+ this.signature = new XFAObjectArray();
+ this.signing = new XFAObjectArray();
+ this.solid = new XFAObjectArray();
+ this.speak = new XFAObjectArray();
+ this.stipple = new XFAObjectArray();
+ this.subform = new XFAObjectArray();
+ this.subformSet = new XFAObjectArray();
+ this.subjectDN = new XFAObjectArray();
+ this.subjectDNs = new XFAObjectArray();
+ this.submit = new XFAObjectArray();
+ this.text = new XFAObjectArray();
+ this.textEdit = new XFAObjectArray();
+ this.time = new XFAObjectArray();
+ this.timeStamp = new XFAObjectArray();
+ this.toolTip = new XFAObjectArray();
+ this.traversal = new XFAObjectArray();
+ this.traverse = new XFAObjectArray();
+ this.ui = new XFAObjectArray();
+ this.validate = new XFAObjectArray();
+ this.value = new XFAObjectArray();
+ this.variables = new XFAObjectArray();
+ }
+}
+class Radial extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "radial", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["toEdge", "toCenter"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ }
+ [$toStyle](startColor) {
+ startColor = startColor ? startColor[$toStyle]() : "#FFFFFF";
+ const endColor = this.color ? this.color[$toStyle]() : "#000000";
+ const colors = this.type === "toEdge" ? `${startColor},${endColor}` : `${endColor},${startColor}`;
+ return `radial-gradient(circle at center, ${colors})`;
+ }
+}
+class Reason extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "reason");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Reasons extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "reasons", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.reason = new XFAObjectArray();
+ }
+}
+class Rectangle extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "rectangle", true);
+ this.hand = getStringOption(attributes.hand, ["even", "left", "right"]);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.corner = new XFAObjectArray(4);
+ this.edge = new XFAObjectArray(4);
+ this.fill = null;
+ }
+ [$toHTML]() {
+ const edge = this.edge.children.length ? this.edge.children[0] : new Edge({});
+ const edgeStyle = edge[$toStyle]();
+ const style = Object.create(null);
+ if (this.fill?.presence === "visible") {
+ Object.assign(style, this.fill[$toStyle]());
+ } else {
+ style.fill = "transparent";
+ }
+ style.strokeWidth = measureToString(edge.presence === "visible" ? edge.thickness : 0);
+ style.stroke = edgeStyle.color;
+ const corner = this.corner.children.length ? this.corner.children[0] : new Corner({});
+ const cornerStyle = corner[$toStyle]();
+ const rect = {
+ name: "rect",
+ attributes: {
+ xmlns: SVG_NS,
+ width: "100%",
+ height: "100%",
+ x: 0,
+ y: 0,
+ rx: cornerStyle.radius,
+ ry: cornerStyle.radius,
+ style
+ }
+ };
+ const svg = {
+ name: "svg",
+ children: [rect],
+ attributes: {
+ xmlns: SVG_NS,
+ style: {
+ overflow: "visible"
+ },
+ width: "100%",
+ height: "100%"
+ }
+ };
+ const parent = this[$getParent]()[$getParent]();
+ if (hasMargin(parent)) {
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ style: {
+ display: "inline",
+ width: "100%",
+ height: "100%"
+ }
+ },
+ children: [svg]
+ });
+ }
+ svg.attributes.style.position = "absolute";
+ return HTMLResult.success(svg);
+ }
+}
+class RefElement extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "ref");
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Script extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "script");
+ this.binding = attributes.binding || "";
+ this.contentType = attributes.contentType || "";
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.runAt = getStringOption(attributes.runAt, ["client", "both", "server"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class SetProperty extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "setProperty");
+ this.connection = attributes.connection || "";
+ this.ref = attributes.ref || "";
+ this.target = attributes.target || "";
+ }
+}
+class SignData extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "signData", true);
+ this.id = attributes.id || "";
+ this.operation = getStringOption(attributes.operation, ["sign", "clear", "verify"]);
+ this.ref = attributes.ref || "";
+ this.target = attributes.target || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.filter = null;
+ this.manifest = null;
+ }
+}
+class Signature extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "signature", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["PDF1.3", "PDF1.6"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.border = null;
+ this.extras = null;
+ this.filter = null;
+ this.manifest = null;
+ this.margin = null;
+ }
+}
+class Signing extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "signing", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.certificate = new XFAObjectArray();
+ }
+}
+class Solid extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "solid", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ }
+ [$toStyle](startColor) {
+ return startColor ? startColor[$toStyle]() : "#FFFFFF";
+ }
+}
+class Speak extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "speak");
+ this.disable = getInteger({
+ data: attributes.disable,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.id = attributes.id || "";
+ this.priority = getStringOption(attributes.priority, ["custom", "caption", "name", "toolTip"]);
+ this.rid = attributes.rid || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Stipple extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "stipple", true);
+ this.id = attributes.id || "";
+ this.rate = getInteger({
+ data: attributes.rate,
+ defaultValue: 50,
+ validate: x => x >= 0 && x <= 100
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.color = null;
+ this.extras = null;
+ }
+ [$toStyle](bgColor) {
+ const alpha = this.rate / 100;
+ return Util.makeHexColor(Math.round(bgColor.value.r * (1 - alpha) + this.value.r * alpha), Math.round(bgColor.value.g * (1 - alpha) + this.value.g * alpha), Math.round(bgColor.value.b * (1 - alpha) + this.value.b * alpha));
+ }
+}
+class Subform extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "subform", true);
+ this.access = getStringOption(attributes.access, ["open", "nonInteractive", "protected", "readOnly"]);
+ this.allowMacro = getInteger({
+ data: attributes.allowMacro,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.anchorType = getStringOption(attributes.anchorType, ["topLeft", "bottomCenter", "bottomLeft", "bottomRight", "middleCenter", "middleLeft", "middleRight", "topCenter", "topRight"]);
+ this.colSpan = getInteger({
+ data: attributes.colSpan,
+ defaultValue: 1,
+ validate: n => n >= 1 || n === -1
+ });
+ this.columnWidths = (attributes.columnWidths || "").trim().split(/\s+/).map(x => x === "-1" ? -1 : getMeasurement(x));
+ this.h = attributes.h ? getMeasurement(attributes.h) : "";
+ this.hAlign = getStringOption(attributes.hAlign, ["left", "center", "justify", "justifyAll", "radix", "right"]);
+ this.id = attributes.id || "";
+ this.layout = getStringOption(attributes.layout, ["position", "lr-tb", "rl-row", "rl-tb", "row", "table", "tb"]);
+ this.locale = attributes.locale || "";
+ this.maxH = getMeasurement(attributes.maxH, "0pt");
+ this.maxW = getMeasurement(attributes.maxW, "0pt");
+ this.mergeMode = getStringOption(attributes.mergeMode, ["consumeData", "matchTemplate"]);
+ this.minH = getMeasurement(attributes.minH, "0pt");
+ this.minW = getMeasurement(attributes.minW, "0pt");
+ this.name = attributes.name || "";
+ this.presence = getStringOption(attributes.presence, ["visible", "hidden", "inactive", "invisible"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.restoreState = getStringOption(attributes.restoreState, ["manual", "auto"]);
+ this.scope = getStringOption(attributes.scope, ["name", "none"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.w = attributes.w ? getMeasurement(attributes.w) : "";
+ this.x = getMeasurement(attributes.x, "0pt");
+ this.y = getMeasurement(attributes.y, "0pt");
+ this.assist = null;
+ this.bind = null;
+ this.bookend = null;
+ this.border = null;
+ this.break = null;
+ this.calculate = null;
+ this.desc = null;
+ this.extras = null;
+ this.keep = null;
+ this.margin = null;
+ this.occur = null;
+ this.overflow = null;
+ this.pageSet = null;
+ this.para = null;
+ this.traversal = null;
+ this.validate = null;
+ this.variables = null;
+ this.area = new XFAObjectArray();
+ this.breakAfter = new XFAObjectArray();
+ this.breakBefore = new XFAObjectArray();
+ this.connect = new XFAObjectArray();
+ this.draw = new XFAObjectArray();
+ this.event = new XFAObjectArray();
+ this.exObject = new XFAObjectArray();
+ this.exclGroup = new XFAObjectArray();
+ this.field = new XFAObjectArray();
+ this.proto = new XFAObjectArray();
+ this.setProperty = new XFAObjectArray();
+ this.subform = new XFAObjectArray();
+ this.subformSet = new XFAObjectArray();
+ }
+ [$getSubformParent]() {
+ const parent = this[$getParent]();
+ if (parent instanceof SubformSet) {
+ return parent[$getSubformParent]();
+ }
+ return parent;
+ }
+ [$isBindable]() {
+ return true;
+ }
+ [$isThereMoreWidth]() {
+ return this.layout.endsWith("-tb") && this[$extra].attempt === 0 && this[$extra].numberInLine > 0 || this[$getParent]()[$isThereMoreWidth]();
+ }
+ *[$getContainedChildren]() {
+ yield* getContainedChildren(this);
+ }
+ [$flushHTML]() {
+ return flushHTML(this);
+ }
+ [$addHTML](html, bbox) {
+ addHTML(this, html, bbox);
+ }
+ [$getAvailableSpace]() {
+ return getAvailableSpace(this);
+ }
+ [$isSplittable]() {
+ const parent = this[$getSubformParent]();
+ if (!parent[$isSplittable]()) {
+ return false;
+ }
+ if (this[$extra]._isSplittable !== undefined) {
+ return this[$extra]._isSplittable;
+ }
+ if (this.layout === "position" || this.layout.includes("row")) {
+ this[$extra]._isSplittable = false;
+ return false;
+ }
+ if (this.keep && this.keep.intact !== "none") {
+ this[$extra]._isSplittable = false;
+ return false;
+ }
+ if (parent.layout?.endsWith("-tb") && parent[$extra].numberInLine !== 0) {
+ return false;
+ }
+ this[$extra]._isSplittable = true;
+ return true;
+ }
+ [$toHTML](availableSpace) {
+ setTabIndex(this);
+ if (this.break) {
+ if (this.break.after !== "auto" || this.break.afterTarget !== "") {
+ const node = new BreakAfter({
+ targetType: this.break.after,
+ target: this.break.afterTarget,
+ startNew: this.break.startNew.toString()
+ });
+ node[$globalData] = this[$globalData];
+ this[$appendChild](node);
+ this.breakAfter.push(node);
+ }
+ if (this.break.before !== "auto" || this.break.beforeTarget !== "") {
+ const node = new BreakBefore({
+ targetType: this.break.before,
+ target: this.break.beforeTarget,
+ startNew: this.break.startNew.toString()
+ });
+ node[$globalData] = this[$globalData];
+ this[$appendChild](node);
+ this.breakBefore.push(node);
+ }
+ if (this.break.overflowTarget !== "") {
+ const node = new Overflow({
+ target: this.break.overflowTarget,
+ leader: this.break.overflowLeader,
+ trailer: this.break.overflowTrailer
+ });
+ node[$globalData] = this[$globalData];
+ this[$appendChild](node);
+ this.overflow.push(node);
+ }
+ this[$removeChild](this.break);
+ this.break = null;
+ }
+ if (this.presence === "hidden" || this.presence === "inactive") {
+ return HTMLResult.EMPTY;
+ }
+ if (this.breakBefore.children.length > 1 || this.breakAfter.children.length > 1) {
+ warn("XFA - Several breakBefore or breakAfter in subforms: please file a bug.");
+ }
+ if (this.breakBefore.children.length >= 1) {
+ const breakBefore = this.breakBefore.children[0];
+ if (handleBreak(breakBefore)) {
+ return HTMLResult.breakNode(breakBefore);
+ }
+ }
+ if (this[$extra]?.afterBreakAfter) {
+ return HTMLResult.EMPTY;
+ }
+ fixDimensions(this);
+ const children = [];
+ const attributes = {
+ id: this[$uid],
+ class: []
+ };
+ setAccess(this, attributes.class);
+ this[$extra] ||= Object.create(null);
+ Object.assign(this[$extra], {
+ children,
+ line: null,
+ attributes,
+ attempt: 0,
+ numberInLine: 0,
+ availableSpace: {
+ width: Math.min(this.w || Infinity, availableSpace.width),
+ height: Math.min(this.h || Infinity, availableSpace.height)
+ },
+ width: 0,
+ height: 0,
+ prevHeight: 0,
+ currentWidth: 0
+ });
+ const root = this[$getTemplateRoot]();
+ const savedNoLayoutFailure = root[$extra].noLayoutFailure;
+ const isSplittable = this[$isSplittable]();
+ if (!isSplittable) {
+ setFirstUnsplittable(this);
+ }
+ if (!checkDimensions(this, availableSpace)) {
+ return HTMLResult.FAILURE;
+ }
+ const filter = new Set(["area", "draw", "exclGroup", "field", "subform", "subformSet"]);
+ if (this.layout.includes("row")) {
+ const columnWidths = this[$getSubformParent]().columnWidths;
+ if (Array.isArray(columnWidths) && columnWidths.length > 0) {
+ this[$extra].columnWidths = columnWidths;
+ this[$extra].currentColumn = 0;
+ }
+ }
+ const style = toStyle(this, "anchorType", "dimensions", "position", "presence", "border", "margin", "hAlign");
+ const classNames = ["xfaSubform"];
+ const cl = layoutClass(this);
+ if (cl) {
+ classNames.push(cl);
+ }
+ attributes.style = style;
+ attributes.class = classNames;
+ if (this.name) {
+ attributes.xfaName = this.name;
+ }
+ if (this.overflow) {
+ const overflowExtra = this.overflow[$getExtra]();
+ if (overflowExtra.addLeader) {
+ overflowExtra.addLeader = false;
+ handleOverflow(this, overflowExtra.leader, availableSpace);
+ }
+ }
+ this[$pushPara]();
+ const isLrTb = this.layout === "lr-tb" || this.layout === "rl-tb";
+ const maxRun = isLrTb ? MAX_ATTEMPTS_FOR_LRTB_LAYOUT : 1;
+ for (; this[$extra].attempt < maxRun; this[$extra].attempt++) {
+ if (isLrTb && this[$extra].attempt === MAX_ATTEMPTS_FOR_LRTB_LAYOUT - 1) {
+ this[$extra].numberInLine = 0;
+ }
+ const result = this[$childrenToHTML]({
+ filter,
+ include: true
+ });
+ if (result.success) {
+ break;
+ }
+ if (result.isBreak()) {
+ this[$popPara]();
+ return result;
+ }
+ if (isLrTb && this[$extra].attempt === 0 && this[$extra].numberInLine === 0 && !root[$extra].noLayoutFailure) {
+ this[$extra].attempt = maxRun;
+ break;
+ }
+ }
+ this[$popPara]();
+ if (!isSplittable) {
+ unsetFirstUnsplittable(this);
+ }
+ root[$extra].noLayoutFailure = savedNoLayoutFailure;
+ if (this[$extra].attempt === maxRun) {
+ if (this.overflow) {
+ this[$getTemplateRoot]()[$extra].overflowNode = this.overflow;
+ }
+ if (!isSplittable) {
+ delete this[$extra];
+ }
+ return HTMLResult.FAILURE;
+ }
+ if (this.overflow) {
+ const overflowExtra = this.overflow[$getExtra]();
+ if (overflowExtra.addTrailer) {
+ overflowExtra.addTrailer = false;
+ handleOverflow(this, overflowExtra.trailer, availableSpace);
+ }
+ }
+ let marginH = 0;
+ let marginV = 0;
+ if (this.margin) {
+ marginH = this.margin.leftInset + this.margin.rightInset;
+ marginV = this.margin.topInset + this.margin.bottomInset;
+ }
+ const width = Math.max(this[$extra].width + marginH, this.w || 0);
+ const height = Math.max(this[$extra].height + marginV, this.h || 0);
+ const bbox = [this.x, this.y, width, height];
+ if (this.w === "") {
+ style.width = measureToString(width);
+ }
+ if (this.h === "") {
+ style.height = measureToString(height);
+ }
+ if ((style.width === "0px" || style.height === "0px") && children.length === 0) {
+ return HTMLResult.EMPTY;
+ }
+ const html = {
+ name: "div",
+ attributes,
+ children
+ };
+ applyAssist(this, attributes);
+ const result = HTMLResult.success(createWrapper(this, html), bbox);
+ if (this.breakAfter.children.length >= 1) {
+ const breakAfter = this.breakAfter.children[0];
+ if (handleBreak(breakAfter)) {
+ this[$extra].afterBreakAfter = result;
+ return HTMLResult.breakNode(breakAfter);
+ }
+ }
+ delete this[$extra];
+ return result;
+ }
+}
+class SubformSet extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "subformSet", true);
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.relation = getStringOption(attributes.relation, ["ordered", "choice", "unordered"]);
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.bookend = null;
+ this.break = null;
+ this.desc = null;
+ this.extras = null;
+ this.occur = null;
+ this.overflow = null;
+ this.breakAfter = new XFAObjectArray();
+ this.breakBefore = new XFAObjectArray();
+ this.subform = new XFAObjectArray();
+ this.subformSet = new XFAObjectArray();
+ }
+ *[$getContainedChildren]() {
+ yield* getContainedChildren(this);
+ }
+ [$getSubformParent]() {
+ let parent = this[$getParent]();
+ while (!(parent instanceof Subform)) {
+ parent = parent[$getParent]();
+ }
+ return parent;
+ }
+ [$isBindable]() {
+ return true;
+ }
+}
+class SubjectDN extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "subjectDN");
+ this.delimiter = attributes.delimiter || ",";
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ this[$content] = new Map(this[$content].split(this.delimiter).map(kv => {
+ kv = kv.split("=", 2);
+ kv[0] = kv[0].trim();
+ return kv;
+ }));
+ }
+}
+class SubjectDNs extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "subjectDNs", true);
+ this.id = attributes.id || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.subjectDN = new XFAObjectArray();
+ }
+}
+class Submit extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "submit", true);
+ this.embedPDF = getInteger({
+ data: attributes.embedPDF,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.format = getStringOption(attributes.format, ["xdp", "formdata", "pdf", "urlencoded", "xfd", "xml"]);
+ this.id = attributes.id || "";
+ this.target = attributes.target || "";
+ this.textEncoding = getKeyword({
+ data: attributes.textEncoding ? attributes.textEncoding.toLowerCase() : "",
+ defaultValue: "",
+ validate: k => ["utf-8", "big-five", "fontspecific", "gbk", "gb-18030", "gb-2312", "ksc-5601", "none", "shift-jis", "ucs-2", "utf-16"].includes(k) || k.match(/iso-8859-\d{2}/)
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.xdpContent = attributes.xdpContent || "";
+ this.encrypt = null;
+ this.encryptData = new XFAObjectArray();
+ this.signData = new XFAObjectArray();
+ }
+}
+class Template extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "template", true);
+ this.baseProfile = getStringOption(attributes.baseProfile, ["full", "interactiveForms"]);
+ this.extras = null;
+ this.subform = new XFAObjectArray();
+ }
+ [$finalize]() {
+ if (this.subform.children.length === 0) {
+ warn("XFA - No subforms in template node.");
+ }
+ if (this.subform.children.length >= 2) {
+ warn("XFA - Several subforms in template node: please file a bug.");
+ }
+ this[$tabIndex] = DEFAULT_TAB_INDEX;
+ }
+ [$isSplittable]() {
+ return true;
+ }
+ [$searchNode](expr, container) {
+ if (expr.startsWith("#")) {
+ return [this[$ids].get(expr.slice(1))];
+ }
+ return searchNode(this, container, expr, true, true);
+ }
+ *[$toPages]() {
+ if (!this.subform.children.length) {
+ return HTMLResult.success({
+ name: "div",
+ children: []
+ });
+ }
+ this[$extra] = {
+ overflowNode: null,
+ firstUnsplittable: null,
+ currentContentArea: null,
+ currentPageArea: null,
+ noLayoutFailure: false,
+ pageNumber: 1,
+ pagePosition: "first",
+ oddOrEven: "odd",
+ blankOrNotBlank: "nonBlank",
+ paraStack: []
+ };
+ const root = this.subform.children[0];
+ root.pageSet[$cleanPage]();
+ const pageAreas = root.pageSet.pageArea.children;
+ const mainHtml = {
+ name: "div",
+ children: []
+ };
+ let pageArea = null;
+ let breakBefore = null;
+ let breakBeforeTarget = null;
+ if (root.breakBefore.children.length >= 1) {
+ breakBefore = root.breakBefore.children[0];
+ breakBeforeTarget = breakBefore.target;
+ } else if (root.subform.children.length >= 1 && root.subform.children[0].breakBefore.children.length >= 1) {
+ breakBefore = root.subform.children[0].breakBefore.children[0];
+ breakBeforeTarget = breakBefore.target;
+ } else if (root.break?.beforeTarget) {
+ breakBefore = root.break;
+ breakBeforeTarget = breakBefore.beforeTarget;
+ } else if (root.subform.children.length >= 1 && root.subform.children[0].break?.beforeTarget) {
+ breakBefore = root.subform.children[0].break;
+ breakBeforeTarget = breakBefore.beforeTarget;
+ }
+ if (breakBefore) {
+ const target = this[$searchNode](breakBeforeTarget, breakBefore[$getParent]());
+ if (target instanceof PageArea) {
+ pageArea = target;
+ breakBefore[$extra] = {};
+ }
+ }
+ pageArea ||= pageAreas[0];
+ pageArea[$extra] = {
+ numberOfUse: 1
+ };
+ const pageAreaParent = pageArea[$getParent]();
+ pageAreaParent[$extra] = {
+ numberOfUse: 1,
+ pageIndex: pageAreaParent.pageArea.children.indexOf(pageArea),
+ pageSetIndex: 0
+ };
+ let targetPageArea;
+ let leader = null;
+ let trailer = null;
+ let hasSomething = true;
+ let hasSomethingCounter = 0;
+ let startIndex = 0;
+ while (true) {
+ if (!hasSomething) {
+ mainHtml.children.pop();
+ if (++hasSomethingCounter === MAX_EMPTY_PAGES) {
+ warn("XFA - Something goes wrong: please file a bug.");
+ return mainHtml;
+ }
+ } else {
+ hasSomethingCounter = 0;
+ }
+ targetPageArea = null;
+ this[$extra].currentPageArea = pageArea;
+ const page = pageArea[$toHTML]().html;
+ mainHtml.children.push(page);
+ if (leader) {
+ this[$extra].noLayoutFailure = true;
+ page.children.push(leader[$toHTML](pageArea[$extra].space).html);
+ leader = null;
+ }
+ if (trailer) {
+ this[$extra].noLayoutFailure = true;
+ page.children.push(trailer[$toHTML](pageArea[$extra].space).html);
+ trailer = null;
+ }
+ const contentAreas = pageArea.contentArea.children;
+ const htmlContentAreas = page.children.filter(node => node.attributes.class.includes("xfaContentarea"));
+ hasSomething = false;
+ this[$extra].firstUnsplittable = null;
+ this[$extra].noLayoutFailure = false;
+ const flush = index => {
+ const html = root[$flushHTML]();
+ if (html) {
+ hasSomething ||= html.children?.length > 0;
+ htmlContentAreas[index].children.push(html);
+ }
+ };
+ for (let i = startIndex, ii = contentAreas.length; i < ii; i++) {
+ const contentArea = this[$extra].currentContentArea = contentAreas[i];
+ const space = {
+ width: contentArea.w,
+ height: contentArea.h
+ };
+ startIndex = 0;
+ if (leader) {
+ htmlContentAreas[i].children.push(leader[$toHTML](space).html);
+ leader = null;
+ }
+ if (trailer) {
+ htmlContentAreas[i].children.push(trailer[$toHTML](space).html);
+ trailer = null;
+ }
+ const html = root[$toHTML](space);
+ if (html.success) {
+ if (html.html) {
+ hasSomething ||= html.html.children?.length > 0;
+ htmlContentAreas[i].children.push(html.html);
+ } else if (!hasSomething && mainHtml.children.length > 1) {
+ mainHtml.children.pop();
+ }
+ return mainHtml;
+ }
+ if (html.isBreak()) {
+ const node = html.breakNode;
+ flush(i);
+ if (node.targetType === "auto") {
+ continue;
+ }
+ if (node.leader) {
+ leader = this[$searchNode](node.leader, node[$getParent]());
+ leader = leader ? leader[0] : null;
+ }
+ if (node.trailer) {
+ trailer = this[$searchNode](node.trailer, node[$getParent]());
+ trailer = trailer ? trailer[0] : null;
+ }
+ if (node.targetType === "pageArea") {
+ targetPageArea = node[$extra].target;
+ i = Infinity;
+ } else if (!node[$extra].target) {
+ i = node[$extra].index;
+ } else {
+ targetPageArea = node[$extra].target;
+ startIndex = node[$extra].index + 1;
+ i = Infinity;
+ }
+ continue;
+ }
+ if (this[$extra].overflowNode) {
+ const node = this[$extra].overflowNode;
+ this[$extra].overflowNode = null;
+ const overflowExtra = node[$getExtra]();
+ const target = overflowExtra.target;
+ overflowExtra.addLeader = overflowExtra.leader !== null;
+ overflowExtra.addTrailer = overflowExtra.trailer !== null;
+ flush(i);
+ const currentIndex = i;
+ i = Infinity;
+ if (target instanceof PageArea) {
+ targetPageArea = target;
+ } else if (target instanceof ContentArea) {
+ const index = contentAreas.indexOf(target);
+ if (index !== -1) {
+ if (index > currentIndex) {
+ i = index - 1;
+ } else {
+ startIndex = index;
+ }
+ } else {
+ targetPageArea = target[$getParent]();
+ startIndex = targetPageArea.contentArea.children.indexOf(target);
+ }
+ }
+ continue;
+ }
+ flush(i);
+ }
+ this[$extra].pageNumber += 1;
+ if (targetPageArea) {
+ if (targetPageArea[$isUsable]()) {
+ targetPageArea[$extra].numberOfUse += 1;
+ } else {
+ targetPageArea = null;
+ }
+ }
+ pageArea = targetPageArea || pageArea[$getNextPage]();
+ yield null;
+ }
+ }
+}
+class Text extends ContentObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "text");
+ this.id = attributes.id || "";
+ this.maxChars = getInteger({
+ data: attributes.maxChars,
+ defaultValue: 0,
+ validate: x => x >= 0
+ });
+ this.name = attributes.name || "";
+ this.rid = attributes.rid || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$acceptWhitespace]() {
+ return true;
+ }
+ [$onChild](child) {
+ if (child[$namespaceId] === NamespaceIds.xhtml.id) {
+ this[$content] = child;
+ return true;
+ }
+ warn(`XFA - Invalid content in Text: ${child[$nodeName]}.`);
+ return false;
+ }
+ [$onText](str) {
+ if (this[$content] instanceof XFAObject) {
+ return;
+ }
+ super[$onText](str);
+ }
+ [$finalize]() {
+ if (typeof this[$content] === "string") {
+ this[$content] = this[$content].replaceAll("\r\n", "\n");
+ }
+ }
+ [$getExtra]() {
+ if (typeof this[$content] === "string") {
+ return this[$content].split(/[\u2029\u2028\n]/).filter(Boolean).join("\n");
+ }
+ return this[$content][$text]();
+ }
+ [$toHTML](availableSpace) {
+ if (typeof this[$content] === "string") {
+ const html = valueToHtml(this[$content]).html;
+ if (this[$content].includes("\u2029")) {
+ html.name = "div";
+ html.children = [];
+ this[$content].split("\u2029").map(para => para.split(/[\u2028\n]/).flatMap(line => [{
+ name: "span",
+ value: line
+ }, {
+ name: "br"
+ }])).forEach(lines => {
+ html.children.push({
+ name: "p",
+ children: lines
+ });
+ });
+ } else if (/[\u2028\n]/.test(this[$content])) {
+ html.name = "div";
+ html.children = [];
+ this[$content].split(/[\u2028\n]/).forEach(line => {
+ html.children.push({
+ name: "span",
+ value: line
+ }, {
+ name: "br"
+ });
+ });
+ }
+ return HTMLResult.success(html);
+ }
+ return this[$content][$toHTML](availableSpace);
+ }
+}
+class TextEdit extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "textEdit", true);
+ this.allowRichText = getInteger({
+ data: attributes.allowRichText,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.hScrollPolicy = getStringOption(attributes.hScrollPolicy, ["auto", "off", "on"]);
+ this.id = attributes.id || "";
+ this.multiLine = getInteger({
+ data: attributes.multiLine,
+ defaultValue: "",
+ validate: x => x === 0 || x === 1
+ });
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.vScrollPolicy = getStringOption(attributes.vScrollPolicy, ["auto", "off", "on"]);
+ this.border = null;
+ this.comb = null;
+ this.extras = null;
+ this.margin = null;
+ }
+ [$toHTML](availableSpace) {
+ const style = toStyle(this, "border", "font", "margin");
+ let html;
+ const field = this[$getParent]()[$getParent]();
+ if (this.multiLine === "") {
+ this.multiLine = field instanceof Draw ? 1 : 0;
+ }
+ if (this.multiLine === 1) {
+ html = {
+ name: "textarea",
+ attributes: {
+ dataId: field[$data]?.[$uid] || field[$uid],
+ fieldId: field[$uid],
+ class: ["xfaTextfield"],
+ style,
+ "aria-label": ariaLabel(field),
+ "aria-required": false
+ }
+ };
+ } else {
+ html = {
+ name: "input",
+ attributes: {
+ type: "text",
+ dataId: field[$data]?.[$uid] || field[$uid],
+ fieldId: field[$uid],
+ class: ["xfaTextfield"],
+ style,
+ "aria-label": ariaLabel(field),
+ "aria-required": false
+ }
+ };
+ }
+ if (isRequired(field)) {
+ html.attributes["aria-required"] = true;
+ html.attributes.required = true;
+ }
+ return HTMLResult.success({
+ name: "label",
+ attributes: {
+ class: ["xfaLabel"]
+ },
+ children: [html]
+ });
+ }
+}
+class Time extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "time");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+ [$finalize]() {
+ const date = this[$content].trim();
+ this[$content] = date ? new Date(date) : null;
+ }
+ [$toHTML](availableSpace) {
+ return valueToHtml(this[$content] ? this[$content].toString() : "");
+ }
+}
+class TimeStamp extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "timeStamp");
+ this.id = attributes.id || "";
+ this.server = attributes.server || "";
+ this.type = getStringOption(attributes.type, ["optional", "required"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class ToolTip extends StringObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "toolTip");
+ this.id = attributes.id || "";
+ this.rid = attributes.rid || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Traversal extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "traversal", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.traverse = new XFAObjectArray();
+ }
+}
+class Traverse extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "traverse", true);
+ this.id = attributes.id || "";
+ this.operation = getStringOption(attributes.operation, ["next", "back", "down", "first", "left", "right", "up"]);
+ this.ref = attributes.ref || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.script = null;
+ }
+ get name() {
+ return this.operation;
+ }
+ [$isTransparent]() {
+ return false;
+ }
+}
+class Ui extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "ui", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.picture = null;
+ this.barcode = null;
+ this.button = null;
+ this.checkButton = null;
+ this.choiceList = null;
+ this.dateTimeEdit = null;
+ this.defaultUi = null;
+ this.imageEdit = null;
+ this.numericEdit = null;
+ this.passwordEdit = null;
+ this.signature = null;
+ this.textEdit = null;
+ }
+ [$getExtra]() {
+ if (this[$extra] === undefined) {
+ for (const name of Object.getOwnPropertyNames(this)) {
+ if (name === "extras" || name === "picture") {
+ continue;
+ }
+ const obj = this[name];
+ if (!(obj instanceof XFAObject)) {
+ continue;
+ }
+ this[$extra] = obj;
+ return obj;
+ }
+ this[$extra] = null;
+ }
+ return this[$extra];
+ }
+ [$toHTML](availableSpace) {
+ const obj = this[$getExtra]();
+ if (obj) {
+ return obj[$toHTML](availableSpace);
+ }
+ return HTMLResult.EMPTY;
+ }
+}
+class Validate extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "validate", true);
+ this.formatTest = getStringOption(attributes.formatTest, ["warning", "disabled", "error"]);
+ this.id = attributes.id || "";
+ this.nullTest = getStringOption(attributes.nullTest, ["disabled", "error", "warning"]);
+ this.scriptTest = getStringOption(attributes.scriptTest, ["error", "disabled", "warning"]);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.extras = null;
+ this.message = null;
+ this.picture = null;
+ this.script = null;
+ }
+}
+class Value extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "value", true);
+ this.id = attributes.id || "";
+ this.override = getInteger({
+ data: attributes.override,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.relevant = getRelevant(attributes.relevant);
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.arc = null;
+ this.boolean = null;
+ this.date = null;
+ this.dateTime = null;
+ this.decimal = null;
+ this.exData = null;
+ this.float = null;
+ this.image = null;
+ this.integer = null;
+ this.line = null;
+ this.rectangle = null;
+ this.text = null;
+ this.time = null;
+ }
+ [$setValue](value) {
+ const parent = this[$getParent]();
+ if (parent instanceof Field) {
+ if (parent.ui?.imageEdit) {
+ if (!this.image) {
+ this.image = new Image({});
+ this[$appendChild](this.image);
+ }
+ this.image[$content] = value[$content];
+ return;
+ }
+ }
+ const valueName = value[$nodeName];
+ if (this[valueName] !== null) {
+ this[valueName][$content] = value[$content];
+ return;
+ }
+ for (const name of Object.getOwnPropertyNames(this)) {
+ const obj = this[name];
+ if (obj instanceof XFAObject) {
+ this[name] = null;
+ this[$removeChild](obj);
+ }
+ }
+ this[value[$nodeName]] = value;
+ this[$appendChild](value);
+ }
+ [$text]() {
+ if (this.exData) {
+ return typeof this.exData[$content] === "string" ? this.exData[$content].trim() : this.exData[$content][$text]().trim();
+ }
+ for (const name of Object.getOwnPropertyNames(this)) {
+ if (name === "image") {
+ continue;
+ }
+ const obj = this[name];
+ if (obj instanceof XFAObject) {
+ return (obj[$content] || "").toString().trim();
+ }
+ }
+ return null;
+ }
+ [$toHTML](availableSpace) {
+ for (const name of Object.getOwnPropertyNames(this)) {
+ const obj = this[name];
+ if (!(obj instanceof XFAObject)) {
+ continue;
+ }
+ return obj[$toHTML](availableSpace);
+ }
+ return HTMLResult.EMPTY;
+ }
+}
+class Variables extends XFAObject {
+ constructor(attributes) {
+ super(TEMPLATE_NS_ID, "variables", true);
+ this.id = attributes.id || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ this.boolean = new XFAObjectArray();
+ this.date = new XFAObjectArray();
+ this.dateTime = new XFAObjectArray();
+ this.decimal = new XFAObjectArray();
+ this.exData = new XFAObjectArray();
+ this.float = new XFAObjectArray();
+ this.image = new XFAObjectArray();
+ this.integer = new XFAObjectArray();
+ this.manifest = new XFAObjectArray();
+ this.script = new XFAObjectArray();
+ this.text = new XFAObjectArray();
+ this.time = new XFAObjectArray();
+ }
+ [$isTransparent]() {
+ return true;
+ }
+}
+class TemplateNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(TemplateNamespace, name)) {
+ const node = TemplateNamespace[name](attributes);
+ node[$setSetAttributes](attributes);
+ return node;
+ }
+ return undefined;
+ }
+ static appearanceFilter(attrs) {
+ return new AppearanceFilter(attrs);
+ }
+ static arc(attrs) {
+ return new Arc(attrs);
+ }
+ static area(attrs) {
+ return new Area(attrs);
+ }
+ static assist(attrs) {
+ return new Assist(attrs);
+ }
+ static barcode(attrs) {
+ return new Barcode(attrs);
+ }
+ static bind(attrs) {
+ return new Bind(attrs);
+ }
+ static bindItems(attrs) {
+ return new BindItems(attrs);
+ }
+ static bookend(attrs) {
+ return new Bookend(attrs);
+ }
+ static boolean(attrs) {
+ return new BooleanElement(attrs);
+ }
+ static border(attrs) {
+ return new Border(attrs);
+ }
+ static break(attrs) {
+ return new Break(attrs);
+ }
+ static breakAfter(attrs) {
+ return new BreakAfter(attrs);
+ }
+ static breakBefore(attrs) {
+ return new BreakBefore(attrs);
+ }
+ static button(attrs) {
+ return new Button(attrs);
+ }
+ static calculate(attrs) {
+ return new Calculate(attrs);
+ }
+ static caption(attrs) {
+ return new Caption(attrs);
+ }
+ static certificate(attrs) {
+ return new Certificate(attrs);
+ }
+ static certificates(attrs) {
+ return new Certificates(attrs);
+ }
+ static checkButton(attrs) {
+ return new CheckButton(attrs);
+ }
+ static choiceList(attrs) {
+ return new ChoiceList(attrs);
+ }
+ static color(attrs) {
+ return new Color(attrs);
+ }
+ static comb(attrs) {
+ return new Comb(attrs);
+ }
+ static connect(attrs) {
+ return new Connect(attrs);
+ }
+ static contentArea(attrs) {
+ return new ContentArea(attrs);
+ }
+ static corner(attrs) {
+ return new Corner(attrs);
+ }
+ static date(attrs) {
+ return new DateElement(attrs);
+ }
+ static dateTime(attrs) {
+ return new DateTime(attrs);
+ }
+ static dateTimeEdit(attrs) {
+ return new DateTimeEdit(attrs);
+ }
+ static decimal(attrs) {
+ return new Decimal(attrs);
+ }
+ static defaultUi(attrs) {
+ return new DefaultUi(attrs);
+ }
+ static desc(attrs) {
+ return new Desc(attrs);
+ }
+ static digestMethod(attrs) {
+ return new DigestMethod(attrs);
+ }
+ static digestMethods(attrs) {
+ return new DigestMethods(attrs);
+ }
+ static draw(attrs) {
+ return new Draw(attrs);
+ }
+ static edge(attrs) {
+ return new Edge(attrs);
+ }
+ static encoding(attrs) {
+ return new Encoding(attrs);
+ }
+ static encodings(attrs) {
+ return new Encodings(attrs);
+ }
+ static encrypt(attrs) {
+ return new Encrypt(attrs);
+ }
+ static encryptData(attrs) {
+ return new EncryptData(attrs);
+ }
+ static encryption(attrs) {
+ return new Encryption(attrs);
+ }
+ static encryptionMethod(attrs) {
+ return new EncryptionMethod(attrs);
+ }
+ static encryptionMethods(attrs) {
+ return new EncryptionMethods(attrs);
+ }
+ static event(attrs) {
+ return new Event(attrs);
+ }
+ static exData(attrs) {
+ return new ExData(attrs);
+ }
+ static exObject(attrs) {
+ return new ExObject(attrs);
+ }
+ static exclGroup(attrs) {
+ return new ExclGroup(attrs);
+ }
+ static execute(attrs) {
+ return new Execute(attrs);
+ }
+ static extras(attrs) {
+ return new Extras(attrs);
+ }
+ static field(attrs) {
+ return new Field(attrs);
+ }
+ static fill(attrs) {
+ return new Fill(attrs);
+ }
+ static filter(attrs) {
+ return new Filter(attrs);
+ }
+ static float(attrs) {
+ return new Float(attrs);
+ }
+ static font(attrs) {
+ return new template_Font(attrs);
+ }
+ static format(attrs) {
+ return new Format(attrs);
+ }
+ static handler(attrs) {
+ return new Handler(attrs);
+ }
+ static hyphenation(attrs) {
+ return new Hyphenation(attrs);
+ }
+ static image(attrs) {
+ return new Image(attrs);
+ }
+ static imageEdit(attrs) {
+ return new ImageEdit(attrs);
+ }
+ static integer(attrs) {
+ return new Integer(attrs);
+ }
+ static issuers(attrs) {
+ return new Issuers(attrs);
+ }
+ static items(attrs) {
+ return new Items(attrs);
+ }
+ static keep(attrs) {
+ return new Keep(attrs);
+ }
+ static keyUsage(attrs) {
+ return new KeyUsage(attrs);
+ }
+ static line(attrs) {
+ return new Line(attrs);
+ }
+ static linear(attrs) {
+ return new Linear(attrs);
+ }
+ static lockDocument(attrs) {
+ return new LockDocument(attrs);
+ }
+ static manifest(attrs) {
+ return new Manifest(attrs);
+ }
+ static margin(attrs) {
+ return new Margin(attrs);
+ }
+ static mdp(attrs) {
+ return new Mdp(attrs);
+ }
+ static medium(attrs) {
+ return new Medium(attrs);
+ }
+ static message(attrs) {
+ return new Message(attrs);
+ }
+ static numericEdit(attrs) {
+ return new NumericEdit(attrs);
+ }
+ static occur(attrs) {
+ return new Occur(attrs);
+ }
+ static oid(attrs) {
+ return new Oid(attrs);
+ }
+ static oids(attrs) {
+ return new Oids(attrs);
+ }
+ static overflow(attrs) {
+ return new Overflow(attrs);
+ }
+ static pageArea(attrs) {
+ return new PageArea(attrs);
+ }
+ static pageSet(attrs) {
+ return new PageSet(attrs);
+ }
+ static para(attrs) {
+ return new Para(attrs);
+ }
+ static passwordEdit(attrs) {
+ return new PasswordEdit(attrs);
+ }
+ static pattern(attrs) {
+ return new template_Pattern(attrs);
+ }
+ static picture(attrs) {
+ return new Picture(attrs);
+ }
+ static proto(attrs) {
+ return new Proto(attrs);
+ }
+ static radial(attrs) {
+ return new Radial(attrs);
+ }
+ static reason(attrs) {
+ return new Reason(attrs);
+ }
+ static reasons(attrs) {
+ return new Reasons(attrs);
+ }
+ static rectangle(attrs) {
+ return new Rectangle(attrs);
+ }
+ static ref(attrs) {
+ return new RefElement(attrs);
+ }
+ static script(attrs) {
+ return new Script(attrs);
+ }
+ static setProperty(attrs) {
+ return new SetProperty(attrs);
+ }
+ static signData(attrs) {
+ return new SignData(attrs);
+ }
+ static signature(attrs) {
+ return new Signature(attrs);
+ }
+ static signing(attrs) {
+ return new Signing(attrs);
+ }
+ static solid(attrs) {
+ return new Solid(attrs);
+ }
+ static speak(attrs) {
+ return new Speak(attrs);
+ }
+ static stipple(attrs) {
+ return new Stipple(attrs);
+ }
+ static subform(attrs) {
+ return new Subform(attrs);
+ }
+ static subformSet(attrs) {
+ return new SubformSet(attrs);
+ }
+ static subjectDN(attrs) {
+ return new SubjectDN(attrs);
+ }
+ static subjectDNs(attrs) {
+ return new SubjectDNs(attrs);
+ }
+ static submit(attrs) {
+ return new Submit(attrs);
+ }
+ static template(attrs) {
+ return new Template(attrs);
+ }
+ static text(attrs) {
+ return new Text(attrs);
+ }
+ static textEdit(attrs) {
+ return new TextEdit(attrs);
+ }
+ static time(attrs) {
+ return new Time(attrs);
+ }
+ static timeStamp(attrs) {
+ return new TimeStamp(attrs);
+ }
+ static toolTip(attrs) {
+ return new ToolTip(attrs);
+ }
+ static traversal(attrs) {
+ return new Traversal(attrs);
+ }
+ static traverse(attrs) {
+ return new Traverse(attrs);
+ }
+ static ui(attrs) {
+ return new Ui(attrs);
+ }
+ static validate(attrs) {
+ return new Validate(attrs);
+ }
+ static value(attrs) {
+ return new Value(attrs);
+ }
+ static variables(attrs) {
+ return new Variables(attrs);
+ }
+}
+
+;// ./src/core/xfa/bind.js
+
+
+
+
+
+
+
+
+
+
+
+const bind_NS_DATASETS = NamespaceIds.datasets.id;
+function createText(content) {
+ const node = new Text({});
+ node[$content] = content;
+ return node;
+}
+class Binder {
+ constructor(root) {
+ this.root = root;
+ this.datasets = root.datasets;
+ this.data = root.datasets?.data || new XmlObject(bind_NS_DATASETS, "data");
+ this.emptyMerge = this.data[$getChildren]().length === 0;
+ this.root.form = this.form = root.template[$clone]();
+ }
+ _isConsumeData() {
+ return !this.emptyMerge && this._mergeMode;
+ }
+ _isMatchTemplate() {
+ return !this._isConsumeData();
+ }
+ bind() {
+ this._bindElement(this.form, this.data);
+ return this.form;
+ }
+ getData() {
+ return this.data;
+ }
+ _bindValue(formNode, data, picture) {
+ formNode[$data] = data;
+ if (formNode[$hasSettableValue]()) {
+ if (data[$isDataValue]()) {
+ const value = data[$getDataValue]();
+ formNode[$setValue](createText(value));
+ } else if (formNode instanceof Field && formNode.ui?.choiceList?.open === "multiSelect") {
+ const value = data[$getChildren]().map(child => child[$content].trim()).join("\n");
+ formNode[$setValue](createText(value));
+ } else if (this._isConsumeData()) {
+ warn(`XFA - Nodes haven't the same type.`);
+ }
+ } else if (!data[$isDataValue]() || this._isMatchTemplate()) {
+ this._bindElement(formNode, data);
+ } else {
+ warn(`XFA - Nodes haven't the same type.`);
+ }
+ }
+ _findDataByNameToConsume(name, isValue, dataNode, global) {
+ if (!name) {
+ return null;
+ }
+ let generator, match;
+ for (let i = 0; i < 3; i++) {
+ generator = dataNode[$getRealChildrenByNameIt](name, false, true);
+ while (true) {
+ match = generator.next().value;
+ if (!match) {
+ break;
+ }
+ if (isValue === match[$isDataValue]()) {
+ return match;
+ }
+ }
+ if (dataNode[$namespaceId] === bind_NS_DATASETS && dataNode[$nodeName] === "data") {
+ break;
+ }
+ dataNode = dataNode[$getParent]();
+ }
+ if (!global) {
+ return null;
+ }
+ generator = this.data[$getRealChildrenByNameIt](name, true, false);
+ match = generator.next().value;
+ if (match) {
+ return match;
+ }
+ generator = this.data[$getAttributeIt](name, true);
+ match = generator.next().value;
+ if (match?.[$isDataValue]()) {
+ return match;
+ }
+ return null;
+ }
+ _setProperties(formNode, dataNode) {
+ if (!Object.hasOwn(formNode, "setProperty")) {
+ return;
+ }
+ for (const {
+ ref,
+ target,
+ connection
+ } of formNode.setProperty.children) {
+ if (connection) {
+ continue;
+ }
+ if (!ref) {
+ continue;
+ }
+ const nodes = searchNode(this.root, dataNode, ref, false, false);
+ if (!nodes) {
+ warn(`XFA - Invalid reference: ${ref}.`);
+ continue;
+ }
+ const [node] = nodes;
+ if (!node[$isDescendent](this.data)) {
+ warn(`XFA - Invalid node: must be a data node.`);
+ continue;
+ }
+ const targetNodes = searchNode(this.root, formNode, target, false, false);
+ if (!targetNodes) {
+ warn(`XFA - Invalid target: ${target}.`);
+ continue;
+ }
+ const [targetNode] = targetNodes;
+ if (!targetNode[$isDescendent](formNode)) {
+ warn(`XFA - Invalid target: must be a property or subproperty.`);
+ continue;
+ }
+ const targetParent = targetNode[$getParent]();
+ if (targetNode instanceof SetProperty || targetParent instanceof SetProperty) {
+ warn(`XFA - Invalid target: cannot be a setProperty or one of its properties.`);
+ continue;
+ }
+ if (targetNode instanceof BindItems || targetParent instanceof BindItems) {
+ warn(`XFA - Invalid target: cannot be a bindItems or one of its properties.`);
+ continue;
+ }
+ const content = node[$text]();
+ const name = targetNode[$nodeName];
+ if (targetNode instanceof XFAAttribute) {
+ const attrs = Object.create(null);
+ attrs[name] = content;
+ const obj = Reflect.construct(Object.getPrototypeOf(targetParent).constructor, [attrs]);
+ targetParent[name] = obj[name];
+ continue;
+ }
+ if (!Object.hasOwn(targetNode, $content)) {
+ warn(`XFA - Invalid node to use in setProperty`);
+ continue;
+ }
+ targetNode[$data] = node;
+ targetNode[$content] = content;
+ targetNode[$finalize]();
+ }
+ }
+ _bindItems(formNode, dataNode) {
+ if (!Object.hasOwn(formNode, "items") || !Object.hasOwn(formNode, "bindItems") || formNode.bindItems.isEmpty()) {
+ return;
+ }
+ for (const item of formNode.items.children) {
+ formNode[$removeChild](item);
+ }
+ formNode.items.clear();
+ const labels = new Items({});
+ const values = new Items({});
+ formNode[$appendChild](labels);
+ formNode.items.push(labels);
+ formNode[$appendChild](values);
+ formNode.items.push(values);
+ for (const {
+ ref,
+ labelRef,
+ valueRef,
+ connection
+ } of formNode.bindItems.children) {
+ if (connection) {
+ continue;
+ }
+ if (!ref) {
+ continue;
+ }
+ const nodes = searchNode(this.root, dataNode, ref, false, false);
+ if (!nodes) {
+ warn(`XFA - Invalid reference: ${ref}.`);
+ continue;
+ }
+ for (const node of nodes) {
+ if (!node[$isDescendent](this.datasets)) {
+ warn(`XFA - Invalid ref (${ref}): must be a datasets child.`);
+ continue;
+ }
+ const labelNodes = searchNode(this.root, node, labelRef, true, false);
+ if (!labelNodes) {
+ warn(`XFA - Invalid label: ${labelRef}.`);
+ continue;
+ }
+ const [labelNode] = labelNodes;
+ if (!labelNode[$isDescendent](this.datasets)) {
+ warn(`XFA - Invalid label: must be a datasets child.`);
+ continue;
+ }
+ const valueNodes = searchNode(this.root, node, valueRef, true, false);
+ if (!valueNodes) {
+ warn(`XFA - Invalid value: ${valueRef}.`);
+ continue;
+ }
+ const [valueNode] = valueNodes;
+ if (!valueNode[$isDescendent](this.datasets)) {
+ warn(`XFA - Invalid value: must be a datasets child.`);
+ continue;
+ }
+ const label = createText(labelNode[$text]());
+ const value = createText(valueNode[$text]());
+ labels[$appendChild](label);
+ labels.text.push(label);
+ values[$appendChild](value);
+ values.text.push(value);
+ }
+ }
+ }
+ _bindOccurrences(formNode, matches, picture) {
+ let baseClone;
+ if (matches.length > 1) {
+ baseClone = formNode[$clone]();
+ baseClone[$removeChild](baseClone.occur);
+ baseClone.occur = null;
+ }
+ this._bindValue(formNode, matches[0], picture);
+ this._setProperties(formNode, matches[0]);
+ this._bindItems(formNode, matches[0]);
+ if (matches.length === 1) {
+ return;
+ }
+ const parent = formNode[$getParent]();
+ const name = formNode[$nodeName];
+ const pos = parent[$indexOf](formNode);
+ for (let i = 1, ii = matches.length; i < ii; i++) {
+ const match = matches[i];
+ const clone = baseClone[$clone]();
+ parent[name].push(clone);
+ parent[$insertAt](pos + i, clone);
+ this._bindValue(clone, match, picture);
+ this._setProperties(clone, match);
+ this._bindItems(clone, match);
+ }
+ }
+ _createOccurrences(formNode) {
+ if (!this.emptyMerge) {
+ return;
+ }
+ const {
+ occur
+ } = formNode;
+ if (!occur || occur.initial <= 1) {
+ return;
+ }
+ const parent = formNode[$getParent]();
+ const name = formNode[$nodeName];
+ if (!(parent[name] instanceof XFAObjectArray)) {
+ return;
+ }
+ let currentNumber;
+ if (formNode.name) {
+ currentNumber = parent[name].children.filter(e => e.name === formNode.name).length;
+ } else {
+ currentNumber = parent[name].children.length;
+ }
+ const pos = parent[$indexOf](formNode) + 1;
+ const ii = occur.initial - currentNumber;
+ if (ii) {
+ const nodeClone = formNode[$clone]();
+ nodeClone[$removeChild](nodeClone.occur);
+ nodeClone.occur = null;
+ parent[name].push(nodeClone);
+ parent[$insertAt](pos, nodeClone);
+ for (let i = 1; i < ii; i++) {
+ const clone = nodeClone[$clone]();
+ parent[name].push(clone);
+ parent[$insertAt](pos + i, clone);
+ }
+ }
+ }
+ _getOccurInfo(formNode) {
+ const {
+ name,
+ occur
+ } = formNode;
+ if (!occur || !name) {
+ return [1, 1];
+ }
+ const max = occur.max === -1 ? Infinity : occur.max;
+ return [occur.min, max];
+ }
+ _setAndBind(formNode, dataNode) {
+ this._setProperties(formNode, dataNode);
+ this._bindItems(formNode, dataNode);
+ this._bindElement(formNode, dataNode);
+ }
+ _bindElement(formNode, dataNode) {
+ const uselessNodes = [];
+ this._createOccurrences(formNode);
+ for (const child of formNode[$getChildren]()) {
+ if (child[$data]) {
+ continue;
+ }
+ if (this._mergeMode === undefined && child[$nodeName] === "subform") {
+ this._mergeMode = child.mergeMode === "consumeData";
+ const dataChildren = dataNode[$getChildren]();
+ if (dataChildren.length > 0) {
+ this._bindOccurrences(child, [dataChildren[0]], null);
+ } else if (this.emptyMerge) {
+ const nsId = dataNode[$namespaceId] === bind_NS_DATASETS ? -1 : dataNode[$namespaceId];
+ const dataChild = child[$data] = new XmlObject(nsId, child.name || "root");
+ dataNode[$appendChild](dataChild);
+ this._bindElement(child, dataChild);
+ }
+ continue;
+ }
+ if (!child[$isBindable]()) {
+ continue;
+ }
+ let global = false;
+ let picture = null;
+ let ref = null;
+ let match = null;
+ if (child.bind) {
+ switch (child.bind.match) {
+ case "none":
+ this._setAndBind(child, dataNode);
+ continue;
+ case "global":
+ global = true;
+ break;
+ case "dataRef":
+ if (!child.bind.ref) {
+ warn(`XFA - ref is empty in node ${child[$nodeName]}.`);
+ this._setAndBind(child, dataNode);
+ continue;
+ }
+ ref = child.bind.ref;
+ break;
+ default:
+ break;
+ }
+ if (child.bind.picture) {
+ picture = child.bind.picture[$content];
+ }
+ }
+ const [min, max] = this._getOccurInfo(child);
+ if (ref) {
+ match = searchNode(this.root, dataNode, ref, true, false);
+ if (match === null) {
+ match = createDataNode(this.data, dataNode, ref);
+ if (!match) {
+ continue;
+ }
+ if (this._isConsumeData()) {
+ match[$consumed] = true;
+ }
+ this._setAndBind(child, match);
+ continue;
+ } else {
+ if (this._isConsumeData()) {
+ match = match.filter(node => !node[$consumed]);
+ }
+ if (match.length > max) {
+ match = match.slice(0, max);
+ } else if (match.length === 0) {
+ match = null;
+ }
+ if (match && this._isConsumeData()) {
+ match.forEach(node => {
+ node[$consumed] = true;
+ });
+ }
+ }
+ } else {
+ if (!child.name) {
+ this._setAndBind(child, dataNode);
+ continue;
+ }
+ if (this._isConsumeData()) {
+ const matches = [];
+ while (matches.length < max) {
+ const found = this._findDataByNameToConsume(child.name, child[$hasSettableValue](), dataNode, global);
+ if (!found) {
+ break;
+ }
+ found[$consumed] = true;
+ matches.push(found);
+ }
+ match = matches.length > 0 ? matches : null;
+ } else {
+ match = dataNode[$getRealChildrenByNameIt](child.name, false, this.emptyMerge).next().value;
+ if (!match) {
+ if (min === 0) {
+ uselessNodes.push(child);
+ continue;
+ }
+ const nsId = dataNode[$namespaceId] === bind_NS_DATASETS ? -1 : dataNode[$namespaceId];
+ match = child[$data] = new XmlObject(nsId, child.name);
+ if (this.emptyMerge) {
+ match[$consumed] = true;
+ }
+ dataNode[$appendChild](match);
+ this._setAndBind(child, match);
+ continue;
+ }
+ if (this.emptyMerge) {
+ match[$consumed] = true;
+ }
+ match = [match];
+ }
+ }
+ if (match) {
+ this._bindOccurrences(child, match, picture);
+ } else if (min > 0) {
+ this._setAndBind(child, dataNode);
+ } else {
+ uselessNodes.push(child);
+ }
+ }
+ uselessNodes.forEach(node => node[$getParent]()[$removeChild](node));
+ }
+}
+
+;// ./src/core/xfa/data.js
+
+
+class DataHandler {
+ constructor(root, data) {
+ this.data = data;
+ this.dataset = root.datasets || null;
+ }
+ serialize(storage) {
+ const stack = [[-1, this.data[$getChildren]()]];
+ while (stack.length > 0) {
+ const last = stack.at(-1);
+ const [i, children] = last;
+ if (i + 1 === children.length) {
+ stack.pop();
+ continue;
+ }
+ const child = children[++last[0]];
+ const storageEntry = storage.get(child[$uid]);
+ if (storageEntry) {
+ child[$setValue](storageEntry);
+ } else {
+ const attributes = child[$getAttributes]();
+ for (const value of attributes.values()) {
+ const entry = storage.get(value[$uid]);
+ if (entry) {
+ value[$setValue](entry);
+ break;
+ }
+ }
+ }
+ const nodes = child[$getChildren]();
+ if (nodes.length > 0) {
+ stack.push([-1, nodes]);
+ }
+ }
+ const buf = [``];
+ if (this.dataset) {
+ for (const child of this.dataset[$getChildren]()) {
+ if (child[$nodeName] !== "data") {
+ child[$toString](buf);
+ }
+ }
+ }
+ this.data[$toString](buf);
+ buf.push("");
+ return buf.join("");
+ }
+}
+
+;// ./src/core/xfa/config.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const CONFIG_NS_ID = NamespaceIds.config.id;
+class Acrobat extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "acrobat", true);
+ this.acrobat7 = null;
+ this.autoSave = null;
+ this.common = null;
+ this.validate = null;
+ this.validateApprovalSignatures = null;
+ this.submitUrl = new XFAObjectArray();
+ }
+}
+class Acrobat7 extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "acrobat7", true);
+ this.dynamicRender = null;
+ }
+}
+class ADBE_JSConsole extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "ADBE_JSConsole", ["delegate", "Enable", "Disable"]);
+ }
+}
+class ADBE_JSDebugger extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "ADBE_JSDebugger", ["delegate", "Enable", "Disable"]);
+ }
+}
+class AddSilentPrint extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "addSilentPrint");
+ }
+}
+class AddViewerPreferences extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "addViewerPreferences");
+ }
+}
+class AdjustData extends Option10 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "adjustData");
+ }
+}
+class AdobeExtensionLevel extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "adobeExtensionLevel", 0, n => n >= 1 && n <= 8);
+ }
+}
+class Agent extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "agent", true);
+ this.name = attributes.name ? attributes.name.trim() : "";
+ this.common = new XFAObjectArray();
+ }
+}
+class AlwaysEmbed extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "alwaysEmbed");
+ }
+}
+class Amd extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "amd");
+ }
+}
+class config_Area extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "area");
+ this.level = getInteger({
+ data: attributes.level,
+ defaultValue: 0,
+ validate: n => n >= 1 && n <= 3
+ });
+ this.name = getStringOption(attributes.name, ["", "barcode", "coreinit", "deviceDriver", "font", "general", "layout", "merge", "script", "signature", "sourceSet", "templateCache"]);
+ }
+}
+class Attributes extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "attributes", ["preserve", "delegate", "ignore"]);
+ }
+}
+class AutoSave extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "autoSave", ["disabled", "enabled"]);
+ }
+}
+class Base extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "base");
+ }
+}
+class BatchOutput extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "batchOutput");
+ this.format = getStringOption(attributes.format, ["none", "concat", "zip", "zipCompress"]);
+ }
+}
+class BehaviorOverride extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "behaviorOverride");
+ }
+ [$finalize]() {
+ this[$content] = new Map(this[$content].trim().split(/\s+/).filter(x => x.includes(":")).map(x => x.split(":", 2)));
+ }
+}
+class Cache extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "cache", true);
+ this.templateCache = null;
+ }
+}
+class Change extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "change");
+ }
+}
+class Common extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "common", true);
+ this.data = null;
+ this.locale = null;
+ this.localeSet = null;
+ this.messaging = null;
+ this.suppressBanner = null;
+ this.template = null;
+ this.validationMessaging = null;
+ this.versionControl = null;
+ this.log = new XFAObjectArray();
+ }
+}
+class Compress extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "compress");
+ this.scope = getStringOption(attributes.scope, ["imageOnly", "document"]);
+ }
+}
+class CompressLogicalStructure extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "compressLogicalStructure");
+ }
+}
+class CompressObjectStream extends Option10 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "compressObjectStream");
+ }
+}
+class Compression extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "compression", true);
+ this.compressLogicalStructure = null;
+ this.compressObjectStream = null;
+ this.level = null;
+ this.type = null;
+ }
+}
+class Config extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "config", true);
+ this.acrobat = null;
+ this.present = null;
+ this.trace = null;
+ this.agent = new XFAObjectArray();
+ }
+}
+class Conformance extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "conformance", ["A", "B"]);
+ }
+}
+class ContentCopy extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "contentCopy");
+ }
+}
+class Copies extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "copies", 1, n => n >= 1);
+ }
+}
+class Creator extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "creator");
+ }
+}
+class CurrentPage extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "currentPage", 0, n => n >= 0);
+ }
+}
+class Data extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "data", true);
+ this.adjustData = null;
+ this.attributes = null;
+ this.incrementalLoad = null;
+ this.outputXSL = null;
+ this.range = null;
+ this.record = null;
+ this.startNode = null;
+ this.uri = null;
+ this.window = null;
+ this.xsl = null;
+ this.excludeNS = new XFAObjectArray();
+ this.transform = new XFAObjectArray();
+ }
+}
+class Debug extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "debug", true);
+ this.uri = null;
+ }
+}
+class DefaultTypeface extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "defaultTypeface");
+ this.writingScript = getStringOption(attributes.writingScript, ["*", "Arabic", "Cyrillic", "EastEuropeanRoman", "Greek", "Hebrew", "Japanese", "Korean", "Roman", "SimplifiedChinese", "Thai", "TraditionalChinese", "Vietnamese"]);
+ }
+}
+class Destination extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "destination", ["pdf", "pcl", "ps", "webClient", "zpl"]);
+ }
+}
+class DocumentAssembly extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "documentAssembly");
+ }
+}
+class Driver extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "driver", true);
+ this.name = attributes.name ? attributes.name.trim() : "";
+ this.fontInfo = null;
+ this.xdc = null;
+ }
+}
+class DuplexOption extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "duplexOption", ["simplex", "duplexFlipLongEdge", "duplexFlipShortEdge"]);
+ }
+}
+class DynamicRender extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "dynamicRender", ["forbidden", "required"]);
+ }
+}
+class Embed extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "embed");
+ }
+}
+class config_Encrypt extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "encrypt");
+ }
+}
+class config_Encryption extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "encryption", true);
+ this.encrypt = null;
+ this.encryptionLevel = null;
+ this.permissions = null;
+ }
+}
+class EncryptionLevel extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "encryptionLevel", ["40bit", "128bit"]);
+ }
+}
+class Enforce extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "enforce");
+ }
+}
+class Equate extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "equate");
+ this.force = getInteger({
+ data: attributes.force,
+ defaultValue: 1,
+ validate: n => n === 0
+ });
+ this.from = attributes.from || "";
+ this.to = attributes.to || "";
+ }
+}
+class EquateRange extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "equateRange");
+ this.from = attributes.from || "";
+ this.to = attributes.to || "";
+ this._unicodeRange = attributes.unicodeRange || "";
+ }
+ get unicodeRange() {
+ const ranges = [];
+ const unicodeRegex = /U\+([0-9a-fA-F]+)/;
+ const unicodeRange = this._unicodeRange;
+ for (let range of unicodeRange.split(",").map(x => x.trim()).filter(Boolean)) {
+ range = range.split("-", 2).map(x => {
+ const found = x.match(unicodeRegex);
+ if (!found) {
+ return 0;
+ }
+ return parseInt(found[1], 16);
+ });
+ if (range.length === 1) {
+ range.push(range[0]);
+ }
+ ranges.push(range);
+ }
+ return shadow(this, "unicodeRange", ranges);
+ }
+}
+class Exclude extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "exclude");
+ }
+ [$finalize]() {
+ this[$content] = this[$content].trim().split(/\s+/).filter(x => x && ["calculate", "close", "enter", "exit", "initialize", "ready", "validate"].includes(x));
+ }
+}
+class ExcludeNS extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "excludeNS");
+ }
+}
+class FlipLabel extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "flipLabel", ["usePrinterSetting", "on", "off"]);
+ }
+}
+class config_FontInfo extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "fontInfo", true);
+ this.embed = null;
+ this.map = null;
+ this.subsetBelow = null;
+ this.alwaysEmbed = new XFAObjectArray();
+ this.defaultTypeface = new XFAObjectArray();
+ this.neverEmbed = new XFAObjectArray();
+ }
+}
+class FormFieldFilling extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "formFieldFilling");
+ }
+}
+class GroupParent extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "groupParent");
+ }
+}
+class IfEmpty extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "ifEmpty", ["dataValue", "dataGroup", "ignore", "remove"]);
+ }
+}
+class IncludeXDPContent extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "includeXDPContent");
+ }
+}
+class IncrementalLoad extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "incrementalLoad", ["none", "forwardOnly"]);
+ }
+}
+class IncrementalMerge extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "incrementalMerge");
+ }
+}
+class Interactive extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "interactive");
+ }
+}
+class Jog extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "jog", ["usePrinterSetting", "none", "pageSet"]);
+ }
+}
+class LabelPrinter extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "labelPrinter", true);
+ this.name = getStringOption(attributes.name, ["zpl", "dpl", "ipl", "tcpl"]);
+ this.batchOutput = null;
+ this.flipLabel = null;
+ this.fontInfo = null;
+ this.xdc = null;
+ }
+}
+class Layout extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "layout", ["paginate", "panel"]);
+ }
+}
+class Level extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "level", 0, n => n > 0);
+ }
+}
+class Linearized extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "linearized");
+ }
+}
+class Locale extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "locale");
+ }
+}
+class LocaleSet extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "localeSet");
+ }
+}
+class Log extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "log", true);
+ this.mode = null;
+ this.threshold = null;
+ this.to = null;
+ this.uri = null;
+ }
+}
+class MapElement extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "map", true);
+ this.equate = new XFAObjectArray();
+ this.equateRange = new XFAObjectArray();
+ }
+}
+class MediumInfo extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "mediumInfo", true);
+ this.map = null;
+ }
+}
+class config_Message extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "message", true);
+ this.msgId = null;
+ this.severity = null;
+ }
+}
+class Messaging extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "messaging", true);
+ this.message = new XFAObjectArray();
+ }
+}
+class Mode extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "mode", ["append", "overwrite"]);
+ }
+}
+class ModifyAnnots extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "modifyAnnots");
+ }
+}
+class MsgId extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "msgId", 1, n => n >= 1);
+ }
+}
+class NameAttr extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "nameAttr");
+ }
+}
+class NeverEmbed extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "neverEmbed");
+ }
+}
+class NumberOfCopies extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "numberOfCopies", null, n => n >= 2 && n <= 5);
+ }
+}
+class OpenAction extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "openAction", true);
+ this.destination = null;
+ }
+}
+class Output extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "output", true);
+ this.to = null;
+ this.type = null;
+ this.uri = null;
+ }
+}
+class OutputBin extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "outputBin");
+ }
+}
+class OutputXSL extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "outputXSL", true);
+ this.uri = null;
+ }
+}
+class Overprint extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "overprint", ["none", "both", "draw", "field"]);
+ }
+}
+class Packets extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "packets");
+ }
+ [$finalize]() {
+ if (this[$content] === "*") {
+ return;
+ }
+ this[$content] = this[$content].trim().split(/\s+/).filter(x => ["config", "datasets", "template", "xfdf", "xslt"].includes(x));
+ }
+}
+class PageOffset extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pageOffset");
+ this.x = getInteger({
+ data: attributes.x,
+ defaultValue: "useXDCSetting",
+ validate: n => true
+ });
+ this.y = getInteger({
+ data: attributes.y,
+ defaultValue: "useXDCSetting",
+ validate: n => true
+ });
+ }
+}
+class PageRange extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pageRange");
+ }
+ [$finalize]() {
+ const numbers = this[$content].trim().split(/\s+/).map(x => parseInt(x, 10));
+ const ranges = [];
+ for (let i = 0, ii = numbers.length; i < ii; i += 2) {
+ ranges.push(numbers.slice(i, i + 2));
+ }
+ this[$content] = ranges;
+ }
+}
+class Pagination extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pagination", ["simplex", "duplexShortEdge", "duplexLongEdge"]);
+ }
+}
+class PaginationOverride extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "paginationOverride", ["none", "forceDuplex", "forceDuplexLongEdge", "forceDuplexShortEdge", "forceSimplex"]);
+ }
+}
+class Part extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "part", 1, n => false);
+ }
+}
+class Pcl extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pcl", true);
+ this.name = attributes.name || "";
+ this.batchOutput = null;
+ this.fontInfo = null;
+ this.jog = null;
+ this.mediumInfo = null;
+ this.outputBin = null;
+ this.pageOffset = null;
+ this.staple = null;
+ this.xdc = null;
+ }
+}
+class Pdf extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pdf", true);
+ this.name = attributes.name || "";
+ this.adobeExtensionLevel = null;
+ this.batchOutput = null;
+ this.compression = null;
+ this.creator = null;
+ this.encryption = null;
+ this.fontInfo = null;
+ this.interactive = null;
+ this.linearized = null;
+ this.openAction = null;
+ this.pdfa = null;
+ this.producer = null;
+ this.renderPolicy = null;
+ this.scriptModel = null;
+ this.silentPrint = null;
+ this.submitFormat = null;
+ this.tagged = null;
+ this.version = null;
+ this.viewerPreferences = null;
+ this.xdc = null;
+ }
+}
+class Pdfa extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pdfa", true);
+ this.amd = null;
+ this.conformance = null;
+ this.includeXDPContent = null;
+ this.part = null;
+ }
+}
+class Permissions extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "permissions", true);
+ this.accessibleContent = null;
+ this.change = null;
+ this.contentCopy = null;
+ this.documentAssembly = null;
+ this.formFieldFilling = null;
+ this.modifyAnnots = null;
+ this.plaintextMetadata = null;
+ this.print = null;
+ this.printHighQuality = null;
+ }
+}
+class PickTrayByPDFSize extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "pickTrayByPDFSize");
+ }
+}
+class config_Picture extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "picture");
+ }
+}
+class PlaintextMetadata extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "plaintextMetadata");
+ }
+}
+class Presence extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "presence", ["preserve", "dissolve", "dissolveStructure", "ignore", "remove"]);
+ }
+}
+class Present extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "present", true);
+ this.behaviorOverride = null;
+ this.cache = null;
+ this.common = null;
+ this.copies = null;
+ this.destination = null;
+ this.incrementalMerge = null;
+ this.layout = null;
+ this.output = null;
+ this.overprint = null;
+ this.pagination = null;
+ this.paginationOverride = null;
+ this.script = null;
+ this.validate = null;
+ this.xdp = null;
+ this.driver = new XFAObjectArray();
+ this.labelPrinter = new XFAObjectArray();
+ this.pcl = new XFAObjectArray();
+ this.pdf = new XFAObjectArray();
+ this.ps = new XFAObjectArray();
+ this.submitUrl = new XFAObjectArray();
+ this.webClient = new XFAObjectArray();
+ this.zpl = new XFAObjectArray();
+ }
+}
+class Print extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "print");
+ }
+}
+class PrintHighQuality extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "printHighQuality");
+ }
+}
+class PrintScaling extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "printScaling", ["appdefault", "noScaling"]);
+ }
+}
+class PrinterName extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "printerName");
+ }
+}
+class Producer extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "producer");
+ }
+}
+class Ps extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "ps", true);
+ this.name = attributes.name || "";
+ this.batchOutput = null;
+ this.fontInfo = null;
+ this.jog = null;
+ this.mediumInfo = null;
+ this.outputBin = null;
+ this.staple = null;
+ this.xdc = null;
+ }
+}
+class Range extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "range");
+ }
+ [$finalize]() {
+ this[$content] = this[$content].split(",", 2).map(range => range.split("-").map(x => parseInt(x.trim(), 10))).filter(range => range.every(x => !isNaN(x))).map(range => {
+ if (range.length === 1) {
+ range.push(range[0]);
+ }
+ return range;
+ });
+ }
+}
+class Record extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "record");
+ }
+ [$finalize]() {
+ this[$content] = this[$content].trim();
+ const n = parseInt(this[$content], 10);
+ if (!isNaN(n) && n >= 0) {
+ this[$content] = n;
+ }
+ }
+}
+class Relevant extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "relevant");
+ }
+ [$finalize]() {
+ this[$content] = this[$content].trim().split(/\s+/);
+ }
+}
+class Rename extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "rename");
+ }
+ [$finalize]() {
+ this[$content] = this[$content].trim();
+ if (this[$content].toLowerCase().startsWith("xml") || /[\p{L}_][\p{L}\d._\p{M}-]*/u.test(this[$content])) {
+ warn("XFA - Rename: invalid XFA name");
+ }
+ }
+}
+class RenderPolicy extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "renderPolicy", ["server", "client"]);
+ }
+}
+class RunScripts extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "runScripts", ["both", "client", "none", "server"]);
+ }
+}
+class config_Script extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "script", true);
+ this.currentPage = null;
+ this.exclude = null;
+ this.runScripts = null;
+ }
+}
+class ScriptModel extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "scriptModel", ["XFA", "none"]);
+ }
+}
+class Severity extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "severity", ["ignore", "error", "information", "trace", "warning"]);
+ }
+}
+class SilentPrint extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "silentPrint", true);
+ this.addSilentPrint = null;
+ this.printerName = null;
+ }
+}
+class Staple extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "staple");
+ this.mode = getStringOption(attributes.mode, ["usePrinterSetting", "on", "off"]);
+ }
+}
+class StartNode extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "startNode");
+ }
+}
+class StartPage extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "startPage", 0, n => true);
+ }
+}
+class SubmitFormat extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "submitFormat", ["html", "delegate", "fdf", "xml", "pdf"]);
+ }
+}
+class SubmitUrl extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "submitUrl");
+ }
+}
+class SubsetBelow extends IntegerObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "subsetBelow", 100, n => n >= 0 && n <= 100);
+ }
+}
+class SuppressBanner extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "suppressBanner");
+ }
+}
+class Tagged extends Option01 {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "tagged");
+ }
+}
+class config_Template extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "template", true);
+ this.base = null;
+ this.relevant = null;
+ this.startPage = null;
+ this.uri = null;
+ this.xsl = null;
+ }
+}
+class Threshold extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "threshold", ["trace", "error", "information", "warning"]);
+ }
+}
+class To extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "to", ["null", "memory", "stderr", "stdout", "system", "uri"]);
+ }
+}
+class TemplateCache extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "templateCache");
+ this.maxEntries = getInteger({
+ data: attributes.maxEntries,
+ defaultValue: 5,
+ validate: n => n >= 0
+ });
+ }
+}
+class Trace extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "trace", true);
+ this.area = new XFAObjectArray();
+ }
+}
+class Transform extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "transform", true);
+ this.groupParent = null;
+ this.ifEmpty = null;
+ this.nameAttr = null;
+ this.picture = null;
+ this.presence = null;
+ this.rename = null;
+ this.whitespace = null;
+ }
+}
+class Type extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "type", ["none", "ascii85", "asciiHex", "ccittfax", "flate", "lzw", "runLength", "native", "xdp", "mergedXDP"]);
+ }
+}
+class Uri extends StringObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "uri");
+ }
+}
+class config_Validate extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "validate", ["preSubmit", "prePrint", "preExecute", "preSave"]);
+ }
+}
+class ValidateApprovalSignatures extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "validateApprovalSignatures");
+ }
+ [$finalize]() {
+ this[$content] = this[$content].trim().split(/\s+/).filter(x => ["docReady", "postSign"].includes(x));
+ }
+}
+class ValidationMessaging extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "validationMessaging", ["allMessagesIndividually", "allMessagesTogether", "firstMessageOnly", "noMessages"]);
+ }
+}
+class Version extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "version", ["1.7", "1.6", "1.5", "1.4", "1.3", "1.2"]);
+ }
+}
+class VersionControl extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "VersionControl");
+ this.outputBelow = getStringOption(attributes.outputBelow, ["warn", "error", "update"]);
+ this.sourceAbove = getStringOption(attributes.sourceAbove, ["warn", "error"]);
+ this.sourceBelow = getStringOption(attributes.sourceBelow, ["update", "maintain"]);
+ }
+}
+class ViewerPreferences extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "viewerPreferences", true);
+ this.ADBE_JSConsole = null;
+ this.ADBE_JSDebugger = null;
+ this.addViewerPreferences = null;
+ this.duplexOption = null;
+ this.enforce = null;
+ this.numberOfCopies = null;
+ this.pageRange = null;
+ this.pickTrayByPDFSize = null;
+ this.printScaling = null;
+ }
+}
+class WebClient extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "webClient", true);
+ this.name = attributes.name ? attributes.name.trim() : "";
+ this.fontInfo = null;
+ this.xdc = null;
+ }
+}
+class Whitespace extends OptionObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "whitespace", ["preserve", "ltrim", "normalize", "rtrim", "trim"]);
+ }
+}
+class Window extends ContentObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "window");
+ }
+ [$finalize]() {
+ const pair = this[$content].split(",", 2).map(x => parseInt(x.trim(), 10));
+ if (pair.some(x => isNaN(x))) {
+ this[$content] = [0, 0];
+ return;
+ }
+ if (pair.length === 1) {
+ pair.push(pair[0]);
+ }
+ this[$content] = pair;
+ }
+}
+class Xdc extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "xdc", true);
+ this.uri = new XFAObjectArray();
+ this.xsl = new XFAObjectArray();
+ }
+}
+class Xdp extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "xdp", true);
+ this.packets = null;
+ }
+}
+class Xsl extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "xsl", true);
+ this.debug = null;
+ this.uri = null;
+ }
+}
+class Zpl extends XFAObject {
+ constructor(attributes) {
+ super(CONFIG_NS_ID, "zpl", true);
+ this.name = attributes.name ? attributes.name.trim() : "";
+ this.batchOutput = null;
+ this.flipLabel = null;
+ this.fontInfo = null;
+ this.xdc = null;
+ }
+}
+class ConfigNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(ConfigNamespace, name)) {
+ return ConfigNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static acrobat(attrs) {
+ return new Acrobat(attrs);
+ }
+ static acrobat7(attrs) {
+ return new Acrobat7(attrs);
+ }
+ static ADBE_JSConsole(attrs) {
+ return new ADBE_JSConsole(attrs);
+ }
+ static ADBE_JSDebugger(attrs) {
+ return new ADBE_JSDebugger(attrs);
+ }
+ static addSilentPrint(attrs) {
+ return new AddSilentPrint(attrs);
+ }
+ static addViewerPreferences(attrs) {
+ return new AddViewerPreferences(attrs);
+ }
+ static adjustData(attrs) {
+ return new AdjustData(attrs);
+ }
+ static adobeExtensionLevel(attrs) {
+ return new AdobeExtensionLevel(attrs);
+ }
+ static agent(attrs) {
+ return new Agent(attrs);
+ }
+ static alwaysEmbed(attrs) {
+ return new AlwaysEmbed(attrs);
+ }
+ static amd(attrs) {
+ return new Amd(attrs);
+ }
+ static area(attrs) {
+ return new config_Area(attrs);
+ }
+ static attributes(attrs) {
+ return new Attributes(attrs);
+ }
+ static autoSave(attrs) {
+ return new AutoSave(attrs);
+ }
+ static base(attrs) {
+ return new Base(attrs);
+ }
+ static batchOutput(attrs) {
+ return new BatchOutput(attrs);
+ }
+ static behaviorOverride(attrs) {
+ return new BehaviorOverride(attrs);
+ }
+ static cache(attrs) {
+ return new Cache(attrs);
+ }
+ static change(attrs) {
+ return new Change(attrs);
+ }
+ static common(attrs) {
+ return new Common(attrs);
+ }
+ static compress(attrs) {
+ return new Compress(attrs);
+ }
+ static compressLogicalStructure(attrs) {
+ return new CompressLogicalStructure(attrs);
+ }
+ static compressObjectStream(attrs) {
+ return new CompressObjectStream(attrs);
+ }
+ static compression(attrs) {
+ return new Compression(attrs);
+ }
+ static config(attrs) {
+ return new Config(attrs);
+ }
+ static conformance(attrs) {
+ return new Conformance(attrs);
+ }
+ static contentCopy(attrs) {
+ return new ContentCopy(attrs);
+ }
+ static copies(attrs) {
+ return new Copies(attrs);
+ }
+ static creator(attrs) {
+ return new Creator(attrs);
+ }
+ static currentPage(attrs) {
+ return new CurrentPage(attrs);
+ }
+ static data(attrs) {
+ return new Data(attrs);
+ }
+ static debug(attrs) {
+ return new Debug(attrs);
+ }
+ static defaultTypeface(attrs) {
+ return new DefaultTypeface(attrs);
+ }
+ static destination(attrs) {
+ return new Destination(attrs);
+ }
+ static documentAssembly(attrs) {
+ return new DocumentAssembly(attrs);
+ }
+ static driver(attrs) {
+ return new Driver(attrs);
+ }
+ static duplexOption(attrs) {
+ return new DuplexOption(attrs);
+ }
+ static dynamicRender(attrs) {
+ return new DynamicRender(attrs);
+ }
+ static embed(attrs) {
+ return new Embed(attrs);
+ }
+ static encrypt(attrs) {
+ return new config_Encrypt(attrs);
+ }
+ static encryption(attrs) {
+ return new config_Encryption(attrs);
+ }
+ static encryptionLevel(attrs) {
+ return new EncryptionLevel(attrs);
+ }
+ static enforce(attrs) {
+ return new Enforce(attrs);
+ }
+ static equate(attrs) {
+ return new Equate(attrs);
+ }
+ static equateRange(attrs) {
+ return new EquateRange(attrs);
+ }
+ static exclude(attrs) {
+ return new Exclude(attrs);
+ }
+ static excludeNS(attrs) {
+ return new ExcludeNS(attrs);
+ }
+ static flipLabel(attrs) {
+ return new FlipLabel(attrs);
+ }
+ static fontInfo(attrs) {
+ return new config_FontInfo(attrs);
+ }
+ static formFieldFilling(attrs) {
+ return new FormFieldFilling(attrs);
+ }
+ static groupParent(attrs) {
+ return new GroupParent(attrs);
+ }
+ static ifEmpty(attrs) {
+ return new IfEmpty(attrs);
+ }
+ static includeXDPContent(attrs) {
+ return new IncludeXDPContent(attrs);
+ }
+ static incrementalLoad(attrs) {
+ return new IncrementalLoad(attrs);
+ }
+ static incrementalMerge(attrs) {
+ return new IncrementalMerge(attrs);
+ }
+ static interactive(attrs) {
+ return new Interactive(attrs);
+ }
+ static jog(attrs) {
+ return new Jog(attrs);
+ }
+ static labelPrinter(attrs) {
+ return new LabelPrinter(attrs);
+ }
+ static layout(attrs) {
+ return new Layout(attrs);
+ }
+ static level(attrs) {
+ return new Level(attrs);
+ }
+ static linearized(attrs) {
+ return new Linearized(attrs);
+ }
+ static locale(attrs) {
+ return new Locale(attrs);
+ }
+ static localeSet(attrs) {
+ return new LocaleSet(attrs);
+ }
+ static log(attrs) {
+ return new Log(attrs);
+ }
+ static map(attrs) {
+ return new MapElement(attrs);
+ }
+ static mediumInfo(attrs) {
+ return new MediumInfo(attrs);
+ }
+ static message(attrs) {
+ return new config_Message(attrs);
+ }
+ static messaging(attrs) {
+ return new Messaging(attrs);
+ }
+ static mode(attrs) {
+ return new Mode(attrs);
+ }
+ static modifyAnnots(attrs) {
+ return new ModifyAnnots(attrs);
+ }
+ static msgId(attrs) {
+ return new MsgId(attrs);
+ }
+ static nameAttr(attrs) {
+ return new NameAttr(attrs);
+ }
+ static neverEmbed(attrs) {
+ return new NeverEmbed(attrs);
+ }
+ static numberOfCopies(attrs) {
+ return new NumberOfCopies(attrs);
+ }
+ static openAction(attrs) {
+ return new OpenAction(attrs);
+ }
+ static output(attrs) {
+ return new Output(attrs);
+ }
+ static outputBin(attrs) {
+ return new OutputBin(attrs);
+ }
+ static outputXSL(attrs) {
+ return new OutputXSL(attrs);
+ }
+ static overprint(attrs) {
+ return new Overprint(attrs);
+ }
+ static packets(attrs) {
+ return new Packets(attrs);
+ }
+ static pageOffset(attrs) {
+ return new PageOffset(attrs);
+ }
+ static pageRange(attrs) {
+ return new PageRange(attrs);
+ }
+ static pagination(attrs) {
+ return new Pagination(attrs);
+ }
+ static paginationOverride(attrs) {
+ return new PaginationOverride(attrs);
+ }
+ static part(attrs) {
+ return new Part(attrs);
+ }
+ static pcl(attrs) {
+ return new Pcl(attrs);
+ }
+ static pdf(attrs) {
+ return new Pdf(attrs);
+ }
+ static pdfa(attrs) {
+ return new Pdfa(attrs);
+ }
+ static permissions(attrs) {
+ return new Permissions(attrs);
+ }
+ static pickTrayByPDFSize(attrs) {
+ return new PickTrayByPDFSize(attrs);
+ }
+ static picture(attrs) {
+ return new config_Picture(attrs);
+ }
+ static plaintextMetadata(attrs) {
+ return new PlaintextMetadata(attrs);
+ }
+ static presence(attrs) {
+ return new Presence(attrs);
+ }
+ static present(attrs) {
+ return new Present(attrs);
+ }
+ static print(attrs) {
+ return new Print(attrs);
+ }
+ static printHighQuality(attrs) {
+ return new PrintHighQuality(attrs);
+ }
+ static printScaling(attrs) {
+ return new PrintScaling(attrs);
+ }
+ static printerName(attrs) {
+ return new PrinterName(attrs);
+ }
+ static producer(attrs) {
+ return new Producer(attrs);
+ }
+ static ps(attrs) {
+ return new Ps(attrs);
+ }
+ static range(attrs) {
+ return new Range(attrs);
+ }
+ static record(attrs) {
+ return new Record(attrs);
+ }
+ static relevant(attrs) {
+ return new Relevant(attrs);
+ }
+ static rename(attrs) {
+ return new Rename(attrs);
+ }
+ static renderPolicy(attrs) {
+ return new RenderPolicy(attrs);
+ }
+ static runScripts(attrs) {
+ return new RunScripts(attrs);
+ }
+ static script(attrs) {
+ return new config_Script(attrs);
+ }
+ static scriptModel(attrs) {
+ return new ScriptModel(attrs);
+ }
+ static severity(attrs) {
+ return new Severity(attrs);
+ }
+ static silentPrint(attrs) {
+ return new SilentPrint(attrs);
+ }
+ static staple(attrs) {
+ return new Staple(attrs);
+ }
+ static startNode(attrs) {
+ return new StartNode(attrs);
+ }
+ static startPage(attrs) {
+ return new StartPage(attrs);
+ }
+ static submitFormat(attrs) {
+ return new SubmitFormat(attrs);
+ }
+ static submitUrl(attrs) {
+ return new SubmitUrl(attrs);
+ }
+ static subsetBelow(attrs) {
+ return new SubsetBelow(attrs);
+ }
+ static suppressBanner(attrs) {
+ return new SuppressBanner(attrs);
+ }
+ static tagged(attrs) {
+ return new Tagged(attrs);
+ }
+ static template(attrs) {
+ return new config_Template(attrs);
+ }
+ static templateCache(attrs) {
+ return new TemplateCache(attrs);
+ }
+ static threshold(attrs) {
+ return new Threshold(attrs);
+ }
+ static to(attrs) {
+ return new To(attrs);
+ }
+ static trace(attrs) {
+ return new Trace(attrs);
+ }
+ static transform(attrs) {
+ return new Transform(attrs);
+ }
+ static type(attrs) {
+ return new Type(attrs);
+ }
+ static uri(attrs) {
+ return new Uri(attrs);
+ }
+ static validate(attrs) {
+ return new config_Validate(attrs);
+ }
+ static validateApprovalSignatures(attrs) {
+ return new ValidateApprovalSignatures(attrs);
+ }
+ static validationMessaging(attrs) {
+ return new ValidationMessaging(attrs);
+ }
+ static version(attrs) {
+ return new Version(attrs);
+ }
+ static versionControl(attrs) {
+ return new VersionControl(attrs);
+ }
+ static viewerPreferences(attrs) {
+ return new ViewerPreferences(attrs);
+ }
+ static webClient(attrs) {
+ return new WebClient(attrs);
+ }
+ static whitespace(attrs) {
+ return new Whitespace(attrs);
+ }
+ static window(attrs) {
+ return new Window(attrs);
+ }
+ static xdc(attrs) {
+ return new Xdc(attrs);
+ }
+ static xdp(attrs) {
+ return new Xdp(attrs);
+ }
+ static xsl(attrs) {
+ return new Xsl(attrs);
+ }
+ static zpl(attrs) {
+ return new Zpl(attrs);
+ }
+}
+
+;// ./src/core/xfa/connection_set.js
+
+
+const CONNECTION_SET_NS_ID = NamespaceIds.connectionSet.id;
+class ConnectionSet extends XFAObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "connectionSet", true);
+ this.wsdlConnection = new XFAObjectArray();
+ this.xmlConnection = new XFAObjectArray();
+ this.xsdConnection = new XFAObjectArray();
+ }
+}
+class EffectiveInputPolicy extends XFAObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "effectiveInputPolicy");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class EffectiveOutputPolicy extends XFAObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "effectiveOutputPolicy");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class Operation extends StringObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "operation");
+ this.id = attributes.id || "";
+ this.input = attributes.input || "";
+ this.name = attributes.name || "";
+ this.output = attributes.output || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class RootElement extends StringObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "rootElement");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class SoapAction extends StringObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "soapAction");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class SoapAddress extends StringObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "soapAddress");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class connection_set_Uri extends StringObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "uri");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class WsdlAddress extends StringObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "wsdlAddress");
+ this.id = attributes.id || "";
+ this.name = attributes.name || "";
+ this.use = attributes.use || "";
+ this.usehref = attributes.usehref || "";
+ }
+}
+class WsdlConnection extends XFAObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "wsdlConnection", true);
+ this.dataDescription = attributes.dataDescription || "";
+ this.name = attributes.name || "";
+ this.effectiveInputPolicy = null;
+ this.effectiveOutputPolicy = null;
+ this.operation = null;
+ this.soapAction = null;
+ this.soapAddress = null;
+ this.wsdlAddress = null;
+ }
+}
+class XmlConnection extends XFAObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "xmlConnection", true);
+ this.dataDescription = attributes.dataDescription || "";
+ this.name = attributes.name || "";
+ this.uri = null;
+ }
+}
+class XsdConnection extends XFAObject {
+ constructor(attributes) {
+ super(CONNECTION_SET_NS_ID, "xsdConnection", true);
+ this.dataDescription = attributes.dataDescription || "";
+ this.name = attributes.name || "";
+ this.rootElement = null;
+ this.uri = null;
+ }
+}
+class ConnectionSetNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(ConnectionSetNamespace, name)) {
+ return ConnectionSetNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static connectionSet(attrs) {
+ return new ConnectionSet(attrs);
+ }
+ static effectiveInputPolicy(attrs) {
+ return new EffectiveInputPolicy(attrs);
+ }
+ static effectiveOutputPolicy(attrs) {
+ return new EffectiveOutputPolicy(attrs);
+ }
+ static operation(attrs) {
+ return new Operation(attrs);
+ }
+ static rootElement(attrs) {
+ return new RootElement(attrs);
+ }
+ static soapAction(attrs) {
+ return new SoapAction(attrs);
+ }
+ static soapAddress(attrs) {
+ return new SoapAddress(attrs);
+ }
+ static uri(attrs) {
+ return new connection_set_Uri(attrs);
+ }
+ static wsdlAddress(attrs) {
+ return new WsdlAddress(attrs);
+ }
+ static wsdlConnection(attrs) {
+ return new WsdlConnection(attrs);
+ }
+ static xmlConnection(attrs) {
+ return new XmlConnection(attrs);
+ }
+ static xsdConnection(attrs) {
+ return new XsdConnection(attrs);
+ }
+}
+
+;// ./src/core/xfa/datasets.js
+
+
+
+const DATASETS_NS_ID = NamespaceIds.datasets.id;
+class datasets_Data extends XmlObject {
+ constructor(attributes) {
+ super(DATASETS_NS_ID, "data", attributes);
+ }
+ [$isNsAgnostic]() {
+ return true;
+ }
+}
+class Datasets extends XFAObject {
+ constructor(attributes) {
+ super(DATASETS_NS_ID, "datasets", true);
+ this.data = null;
+ this.Signature = null;
+ }
+ [$onChild](child) {
+ const name = child[$nodeName];
+ if (name === "data" && child[$namespaceId] === DATASETS_NS_ID || name === "Signature" && child[$namespaceId] === NamespaceIds.signature.id) {
+ this[name] = child;
+ }
+ this[$appendChild](child);
+ }
+}
+class DatasetsNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(DatasetsNamespace, name)) {
+ return DatasetsNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static datasets(attributes) {
+ return new Datasets(attributes);
+ }
+ static data(attributes) {
+ return new datasets_Data(attributes);
+ }
+}
+
+;// ./src/core/xfa/locale_set.js
+
+
+
+const LOCALE_SET_NS_ID = NamespaceIds.localeSet.id;
+class CalendarSymbols extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "calendarSymbols", true);
+ this.name = "gregorian";
+ this.dayNames = new XFAObjectArray(2);
+ this.eraNames = null;
+ this.meridiemNames = null;
+ this.monthNames = new XFAObjectArray(2);
+ }
+}
+class CurrencySymbol extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "currencySymbol");
+ this.name = getStringOption(attributes.name, ["symbol", "isoname", "decimal"]);
+ }
+}
+class CurrencySymbols extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "currencySymbols", true);
+ this.currencySymbol = new XFAObjectArray(3);
+ }
+}
+class DatePattern extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "datePattern");
+ this.name = getStringOption(attributes.name, ["full", "long", "med", "short"]);
+ }
+}
+class DatePatterns extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "datePatterns", true);
+ this.datePattern = new XFAObjectArray(4);
+ }
+}
+class DateTimeSymbols extends ContentObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "dateTimeSymbols");
+ }
+}
+class Day extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "day");
+ }
+}
+class DayNames extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "dayNames", true);
+ this.abbr = getInteger({
+ data: attributes.abbr,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.day = new XFAObjectArray(7);
+ }
+}
+class Era extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "era");
+ }
+}
+class EraNames extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "eraNames", true);
+ this.era = new XFAObjectArray(2);
+ }
+}
+class locale_set_Locale extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "locale", true);
+ this.desc = attributes.desc || "";
+ this.name = "isoname";
+ this.calendarSymbols = null;
+ this.currencySymbols = null;
+ this.datePatterns = null;
+ this.dateTimeSymbols = null;
+ this.numberPatterns = null;
+ this.numberSymbols = null;
+ this.timePatterns = null;
+ this.typeFaces = null;
+ }
+}
+class locale_set_LocaleSet extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "localeSet", true);
+ this.locale = new XFAObjectArray();
+ }
+}
+class Meridiem extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "meridiem");
+ }
+}
+class MeridiemNames extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "meridiemNames", true);
+ this.meridiem = new XFAObjectArray(2);
+ }
+}
+class Month extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "month");
+ }
+}
+class MonthNames extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "monthNames", true);
+ this.abbr = getInteger({
+ data: attributes.abbr,
+ defaultValue: 0,
+ validate: x => x === 1
+ });
+ this.month = new XFAObjectArray(12);
+ }
+}
+class NumberPattern extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "numberPattern");
+ this.name = getStringOption(attributes.name, ["full", "long", "med", "short"]);
+ }
+}
+class NumberPatterns extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "numberPatterns", true);
+ this.numberPattern = new XFAObjectArray(4);
+ }
+}
+class NumberSymbol extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "numberSymbol");
+ this.name = getStringOption(attributes.name, ["decimal", "grouping", "percent", "minus", "zero"]);
+ }
+}
+class NumberSymbols extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "numberSymbols", true);
+ this.numberSymbol = new XFAObjectArray(5);
+ }
+}
+class TimePattern extends StringObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "timePattern");
+ this.name = getStringOption(attributes.name, ["full", "long", "med", "short"]);
+ }
+}
+class TimePatterns extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "timePatterns", true);
+ this.timePattern = new XFAObjectArray(4);
+ }
+}
+class TypeFace extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "typeFace", true);
+ this.name = attributes.name | "";
+ }
+}
+class TypeFaces extends XFAObject {
+ constructor(attributes) {
+ super(LOCALE_SET_NS_ID, "typeFaces", true);
+ this.typeFace = new XFAObjectArray();
+ }
+}
+class LocaleSetNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(LocaleSetNamespace, name)) {
+ return LocaleSetNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static calendarSymbols(attrs) {
+ return new CalendarSymbols(attrs);
+ }
+ static currencySymbol(attrs) {
+ return new CurrencySymbol(attrs);
+ }
+ static currencySymbols(attrs) {
+ return new CurrencySymbols(attrs);
+ }
+ static datePattern(attrs) {
+ return new DatePattern(attrs);
+ }
+ static datePatterns(attrs) {
+ return new DatePatterns(attrs);
+ }
+ static dateTimeSymbols(attrs) {
+ return new DateTimeSymbols(attrs);
+ }
+ static day(attrs) {
+ return new Day(attrs);
+ }
+ static dayNames(attrs) {
+ return new DayNames(attrs);
+ }
+ static era(attrs) {
+ return new Era(attrs);
+ }
+ static eraNames(attrs) {
+ return new EraNames(attrs);
+ }
+ static locale(attrs) {
+ return new locale_set_Locale(attrs);
+ }
+ static localeSet(attrs) {
+ return new locale_set_LocaleSet(attrs);
+ }
+ static meridiem(attrs) {
+ return new Meridiem(attrs);
+ }
+ static meridiemNames(attrs) {
+ return new MeridiemNames(attrs);
+ }
+ static month(attrs) {
+ return new Month(attrs);
+ }
+ static monthNames(attrs) {
+ return new MonthNames(attrs);
+ }
+ static numberPattern(attrs) {
+ return new NumberPattern(attrs);
+ }
+ static numberPatterns(attrs) {
+ return new NumberPatterns(attrs);
+ }
+ static numberSymbol(attrs) {
+ return new NumberSymbol(attrs);
+ }
+ static numberSymbols(attrs) {
+ return new NumberSymbols(attrs);
+ }
+ static timePattern(attrs) {
+ return new TimePattern(attrs);
+ }
+ static timePatterns(attrs) {
+ return new TimePatterns(attrs);
+ }
+ static typeFace(attrs) {
+ return new TypeFace(attrs);
+ }
+ static typeFaces(attrs) {
+ return new TypeFaces(attrs);
+ }
+}
+
+;// ./src/core/xfa/signature.js
+
+
+const SIGNATURE_NS_ID = NamespaceIds.signature.id;
+class signature_Signature extends XFAObject {
+ constructor(attributes) {
+ super(SIGNATURE_NS_ID, "signature", true);
+ }
+}
+class SignatureNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(SignatureNamespace, name)) {
+ return SignatureNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static signature(attributes) {
+ return new signature_Signature(attributes);
+ }
+}
+
+;// ./src/core/xfa/stylesheet.js
+
+
+const STYLESHEET_NS_ID = NamespaceIds.stylesheet.id;
+class Stylesheet extends XFAObject {
+ constructor(attributes) {
+ super(STYLESHEET_NS_ID, "stylesheet", true);
+ }
+}
+class StylesheetNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(StylesheetNamespace, name)) {
+ return StylesheetNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static stylesheet(attributes) {
+ return new Stylesheet(attributes);
+ }
+}
+
+;// ./src/core/xfa/xdp.js
+
+
+
+const XDP_NS_ID = NamespaceIds.xdp.id;
+class xdp_Xdp extends XFAObject {
+ constructor(attributes) {
+ super(XDP_NS_ID, "xdp", true);
+ this.uuid = attributes.uuid || "";
+ this.timeStamp = attributes.timeStamp || "";
+ this.config = null;
+ this.connectionSet = null;
+ this.datasets = null;
+ this.localeSet = null;
+ this.stylesheet = new XFAObjectArray();
+ this.template = null;
+ }
+ [$onChildCheck](child) {
+ const ns = NamespaceIds[child[$nodeName]];
+ return ns && child[$namespaceId] === ns.id;
+ }
+}
+class XdpNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(XdpNamespace, name)) {
+ return XdpNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static xdp(attributes) {
+ return new xdp_Xdp(attributes);
+ }
+}
+
+;// ./src/core/xfa/xhtml.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const XHTML_NS_ID = NamespaceIds.xhtml.id;
+const $richText = Symbol();
+const VALID_STYLES = new Set(["color", "font", "font-family", "font-size", "font-stretch", "font-style", "font-weight", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top", "letter-spacing", "line-height", "orphans", "page-break-after", "page-break-before", "page-break-inside", "tab-interval", "tab-stop", "text-align", "text-decoration", "text-indent", "vertical-align", "widows", "kerning-mode", "xfa-font-horizontal-scale", "xfa-font-vertical-scale", "xfa-spacerun", "xfa-tab-stops"]);
+const StyleMapping = new Map([["page-break-after", "breakAfter"], ["page-break-before", "breakBefore"], ["page-break-inside", "breakInside"], ["kerning-mode", value => value === "none" ? "none" : "normal"], ["xfa-font-horizontal-scale", value => `scaleX(${Math.max(0, parseInt(value, 10) / 100).toFixed(2)})`], ["xfa-font-vertical-scale", value => `scaleY(${Math.max(0, parseInt(value, 10) / 100).toFixed(2)})`], ["xfa-spacerun", ""], ["xfa-tab-stops", ""], ["font-size", (value, original) => {
+ value = original.fontSize = Math.abs(getMeasurement(value));
+ return measureToString(0.99 * value);
+}], ["letter-spacing", value => measureToString(getMeasurement(value))], ["line-height", value => measureToString(getMeasurement(value))], ["margin", value => measureToString(getMeasurement(value))], ["margin-bottom", value => measureToString(getMeasurement(value))], ["margin-left", value => measureToString(getMeasurement(value))], ["margin-right", value => measureToString(getMeasurement(value))], ["margin-top", value => measureToString(getMeasurement(value))], ["text-indent", value => measureToString(getMeasurement(value))], ["font-family", value => value], ["vertical-align", value => measureToString(getMeasurement(value))]]);
+const spacesRegExp = /\s+/g;
+const crlfRegExp = /[\r\n]+/g;
+const crlfForRichTextRegExp = /\r\n?/g;
+function mapStyle(styleStr, node, richText) {
+ const style = Object.create(null);
+ if (!styleStr) {
+ return style;
+ }
+ const original = Object.create(null);
+ for (const [key, value] of styleStr.split(";").map(s => s.split(":", 2))) {
+ const mapping = StyleMapping.get(key);
+ if (mapping === "") {
+ continue;
+ }
+ let newValue = value;
+ if (mapping) {
+ newValue = typeof mapping === "string" ? mapping : mapping(value, original);
+ }
+ if (key.endsWith("scale")) {
+ style.transform = style.transform ? `${style[key]} ${newValue}` : newValue;
+ } else {
+ style[key.replaceAll(/-([a-z])/gi, (_, x) => x.toUpperCase())] = newValue;
+ }
+ }
+ if (style.fontFamily) {
+ setFontFamily({
+ typeface: style.fontFamily,
+ weight: style.fontWeight || "normal",
+ posture: style.fontStyle || "normal",
+ size: original.fontSize || 0
+ }, node, node[$globalData].fontFinder, style);
+ }
+ if (richText && style.verticalAlign && style.verticalAlign !== "0px" && style.fontSize) {
+ const SUB_SUPER_SCRIPT_FACTOR = 0.583;
+ const VERTICAL_FACTOR = 0.333;
+ const fontSize = getMeasurement(style.fontSize);
+ style.fontSize = measureToString(fontSize * SUB_SUPER_SCRIPT_FACTOR);
+ style.verticalAlign = measureToString(Math.sign(getMeasurement(style.verticalAlign)) * fontSize * VERTICAL_FACTOR);
+ }
+ if (richText && style.fontSize) {
+ style.fontSize = `calc(${style.fontSize} * var(--total-scale-factor))`;
+ }
+ fixTextIndent(style);
+ return style;
+}
+function checkStyle(node) {
+ if (!node.style) {
+ return "";
+ }
+ return node.style.split(";").filter(s => !!s.trim()).map(s => s.split(":", 2).map(t => t.trim())).filter(([key, value]) => {
+ if (key === "font-family") {
+ node[$globalData].usedTypefaces.add(value);
+ }
+ return VALID_STYLES.has(key);
+ }).map(kv => kv.join(":")).join(";");
+}
+const NoWhites = new Set(["body", "html"]);
+class XhtmlObject extends XmlObject {
+ constructor(attributes, name) {
+ super(XHTML_NS_ID, name);
+ this[$richText] = false;
+ this.style = attributes.style || "";
+ }
+ [$clean](builder) {
+ super[$clean](builder);
+ this.style = checkStyle(this);
+ }
+ [$acceptWhitespace]() {
+ return !NoWhites.has(this[$nodeName]);
+ }
+ [$onText](str, richText = false) {
+ if (!richText) {
+ str = str.replaceAll(crlfRegExp, "");
+ if (!this.style.includes("xfa-spacerun:yes")) {
+ str = str.replaceAll(spacesRegExp, " ");
+ }
+ } else {
+ this[$richText] = true;
+ }
+ if (str) {
+ this[$content] += str;
+ }
+ }
+ [$pushGlyphs](measure, mustPop = true) {
+ const xfaFont = Object.create(null);
+ const margin = {
+ top: NaN,
+ bottom: NaN,
+ left: NaN,
+ right: NaN
+ };
+ let lineHeight = null;
+ for (const [key, value] of this.style.split(";").map(s => s.split(":", 2))) {
+ switch (key) {
+ case "font-family":
+ xfaFont.typeface = stripQuotes(value);
+ break;
+ case "font-size":
+ xfaFont.size = getMeasurement(value);
+ break;
+ case "font-weight":
+ xfaFont.weight = value;
+ break;
+ case "font-style":
+ xfaFont.posture = value;
+ break;
+ case "letter-spacing":
+ xfaFont.letterSpacing = getMeasurement(value);
+ break;
+ case "margin":
+ const values = value.split(/ \t/).map(getMeasurement);
+ switch (values.length) {
+ case 1:
+ margin.top = margin.bottom = margin.left = margin.right = values[0];
+ break;
+ case 2:
+ margin.top = margin.bottom = values[0];
+ margin.left = margin.right = values[1];
+ break;
+ case 3:
+ margin.top = values[0];
+ margin.bottom = values[2];
+ margin.left = margin.right = values[1];
+ break;
+ case 4:
+ margin.top = values[0];
+ margin.left = values[1];
+ margin.bottom = values[2];
+ margin.right = values[3];
+ break;
+ }
+ break;
+ case "margin-top":
+ margin.top = getMeasurement(value);
+ break;
+ case "margin-bottom":
+ margin.bottom = getMeasurement(value);
+ break;
+ case "margin-left":
+ margin.left = getMeasurement(value);
+ break;
+ case "margin-right":
+ margin.right = getMeasurement(value);
+ break;
+ case "line-height":
+ lineHeight = getMeasurement(value);
+ break;
+ }
+ }
+ measure.pushData(xfaFont, margin, lineHeight);
+ if (this[$content]) {
+ measure.addString(this[$content]);
+ } else {
+ for (const child of this[$getChildren]()) {
+ if (child[$nodeName] === "#text") {
+ measure.addString(child[$content]);
+ continue;
+ }
+ child[$pushGlyphs](measure);
+ }
+ }
+ if (mustPop) {
+ measure.popFont();
+ }
+ }
+ [$toHTML](availableSpace) {
+ const children = [];
+ this[$extra] = {
+ children
+ };
+ this[$childrenToHTML]({});
+ if (children.length === 0 && !this[$content]) {
+ return HTMLResult.EMPTY;
+ }
+ let value;
+ if (this[$richText]) {
+ value = this[$content] ? this[$content].replaceAll(crlfForRichTextRegExp, "\n") : undefined;
+ } else {
+ value = this[$content] || undefined;
+ }
+ return HTMLResult.success({
+ name: this[$nodeName],
+ attributes: {
+ href: this.href,
+ style: mapStyle(this.style, this, this[$richText])
+ },
+ children,
+ value
+ });
+ }
+}
+class A extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "a");
+ this.href = fixURL(attributes.href) || "";
+ }
+}
+class B extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "b");
+ }
+ [$pushGlyphs](measure) {
+ measure.pushFont({
+ weight: "bold"
+ });
+ super[$pushGlyphs](measure);
+ measure.popFont();
+ }
+}
+class Body extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "body");
+ }
+ [$toHTML](availableSpace) {
+ const res = super[$toHTML](availableSpace);
+ const {
+ html
+ } = res;
+ if (!html) {
+ return HTMLResult.EMPTY;
+ }
+ html.name = "div";
+ html.attributes.class = ["xfaRich"];
+ return res;
+ }
+}
+class Br extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "br");
+ }
+ [$text]() {
+ return "\n";
+ }
+ [$pushGlyphs](measure) {
+ measure.addString("\n");
+ }
+ [$toHTML](availableSpace) {
+ return HTMLResult.success({
+ name: "br"
+ });
+ }
+}
+class Html extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "html");
+ }
+ [$toHTML](availableSpace) {
+ const children = [];
+ this[$extra] = {
+ children
+ };
+ this[$childrenToHTML]({});
+ if (children.length === 0) {
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ class: ["xfaRich"],
+ style: {}
+ },
+ value: this[$content] || ""
+ });
+ }
+ if (children.length === 1) {
+ const child = children[0];
+ if (child.attributes?.class.includes("xfaRich")) {
+ return HTMLResult.success(child);
+ }
+ }
+ return HTMLResult.success({
+ name: "div",
+ attributes: {
+ class: ["xfaRich"],
+ style: {}
+ },
+ children
+ });
+ }
+}
+class I extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "i");
+ }
+ [$pushGlyphs](measure) {
+ measure.pushFont({
+ posture: "italic"
+ });
+ super[$pushGlyphs](measure);
+ measure.popFont();
+ }
+}
+class Li extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "li");
+ }
+}
+class Ol extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "ol");
+ }
+}
+class P extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "p");
+ }
+ [$pushGlyphs](measure) {
+ super[$pushGlyphs](measure, false);
+ measure.addString("\n");
+ measure.addPara();
+ measure.popFont();
+ }
+ [$text]() {
+ const siblings = this[$getParent]()[$getChildren]();
+ if (siblings.at(-1) === this) {
+ return super[$text]();
+ }
+ return super[$text]() + "\n";
+ }
+}
+class Span extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "span");
+ }
+}
+class Sub extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "sub");
+ }
+}
+class Sup extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "sup");
+ }
+}
+class Ul extends XhtmlObject {
+ constructor(attributes) {
+ super(attributes, "ul");
+ }
+}
+class XhtmlNamespace {
+ static [$buildXFAObject](name, attributes) {
+ if (Object.hasOwn(XhtmlNamespace, name)) {
+ return XhtmlNamespace[name](attributes);
+ }
+ return undefined;
+ }
+ static a(attributes) {
+ return new A(attributes);
+ }
+ static b(attributes) {
+ return new B(attributes);
+ }
+ static body(attributes) {
+ return new Body(attributes);
+ }
+ static br(attributes) {
+ return new Br(attributes);
+ }
+ static html(attributes) {
+ return new Html(attributes);
+ }
+ static i(attributes) {
+ return new I(attributes);
+ }
+ static li(attributes) {
+ return new Li(attributes);
+ }
+ static ol(attributes) {
+ return new Ol(attributes);
+ }
+ static p(attributes) {
+ return new P(attributes);
+ }
+ static span(attributes) {
+ return new Span(attributes);
+ }
+ static sub(attributes) {
+ return new Sub(attributes);
+ }
+ static sup(attributes) {
+ return new Sup(attributes);
+ }
+ static ul(attributes) {
+ return new Ul(attributes);
+ }
+}
+
+;// ./src/core/xfa/setup.js
+
+
+
+
+
+
+
+
+
+const NamespaceSetUp = {
+ config: ConfigNamespace,
+ connection: ConnectionSetNamespace,
+ datasets: DatasetsNamespace,
+ localeSet: LocaleSetNamespace,
+ signature: SignatureNamespace,
+ stylesheet: StylesheetNamespace,
+ template: TemplateNamespace,
+ xdp: XdpNamespace,
+ xhtml: XhtmlNamespace
+};
+
+;// ./src/core/xfa/unknown.js
+
+
+class UnknownNamespace {
+ constructor(nsId) {
+ this.namespaceId = nsId;
+ }
+ [$buildXFAObject](name, attributes) {
+ return new XmlObject(this.namespaceId, name, attributes);
+ }
+}
+
+;// ./src/core/xfa/builder.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+class Root extends XFAObject {
+ constructor(ids) {
+ super(-1, "root", Object.create(null));
+ this.element = null;
+ this[$ids] = ids;
+ }
+ [$onChild](child) {
+ this.element = child;
+ return true;
+ }
+ [$finalize]() {
+ super[$finalize]();
+ if (this.element.template instanceof Template) {
+ this[$ids].set($root, this.element);
+ this.element.template[$resolvePrototypes](this[$ids]);
+ this.element.template[$ids] = this[$ids];
+ }
+ }
+}
+class Empty extends XFAObject {
+ constructor() {
+ super(-1, "", Object.create(null));
+ }
+ [$onChild](_) {
+ return false;
+ }
+}
+class Builder {
+ constructor(rootNameSpace = null) {
+ this._namespaceStack = [];
+ this._nsAgnosticLevel = 0;
+ this._namespacePrefixes = new Map();
+ this._namespaces = new Map();
+ this._nextNsId = Math.max(...Object.values(NamespaceIds).map(({
+ id
+ }) => id));
+ this._currentNamespace = rootNameSpace || new UnknownNamespace(++this._nextNsId);
+ }
+ buildRoot(ids) {
+ return new Root(ids);
+ }
+ build({
+ nsPrefix,
+ name,
+ attributes,
+ namespace,
+ prefixes
+ }) {
+ const hasNamespaceDef = namespace !== null;
+ if (hasNamespaceDef) {
+ this._namespaceStack.push(this._currentNamespace);
+ this._currentNamespace = this._searchNamespace(namespace);
+ }
+ if (prefixes) {
+ this._addNamespacePrefix(prefixes);
+ }
+ if (Object.hasOwn(attributes, $nsAttributes)) {
+ const dataTemplate = NamespaceSetUp.datasets;
+ const nsAttrs = attributes[$nsAttributes];
+ let xfaAttrs = null;
+ for (const [ns, attrs] of Object.entries(nsAttrs)) {
+ const nsToUse = this._getNamespaceToUse(ns);
+ if (nsToUse === dataTemplate) {
+ xfaAttrs = {
+ xfa: attrs
+ };
+ break;
+ }
+ }
+ if (xfaAttrs) {
+ attributes[$nsAttributes] = xfaAttrs;
+ } else {
+ delete attributes[$nsAttributes];
+ }
+ }
+ const namespaceToUse = this._getNamespaceToUse(nsPrefix);
+ const node = namespaceToUse?.[$buildXFAObject](name, attributes) || new Empty();
+ if (node[$isNsAgnostic]()) {
+ this._nsAgnosticLevel++;
+ }
+ if (hasNamespaceDef || prefixes || node[$isNsAgnostic]()) {
+ node[$cleanup] = {
+ hasNamespace: hasNamespaceDef,
+ prefixes,
+ nsAgnostic: node[$isNsAgnostic]()
+ };
+ }
+ return node;
+ }
+ isNsAgnostic() {
+ return this._nsAgnosticLevel > 0;
+ }
+ _searchNamespace(nsName) {
+ let ns = this._namespaces.get(nsName);
+ if (ns) {
+ return ns;
+ }
+ for (const [name, {
+ check
+ }] of Object.entries(NamespaceIds)) {
+ if (check(nsName)) {
+ ns = NamespaceSetUp[name];
+ if (ns) {
+ this._namespaces.set(nsName, ns);
+ return ns;
+ }
+ break;
+ }
+ }
+ ns = new UnknownNamespace(++this._nextNsId);
+ this._namespaces.set(nsName, ns);
+ return ns;
+ }
+ _addNamespacePrefix(prefixes) {
+ for (const {
+ prefix,
+ value
+ } of prefixes) {
+ const namespace = this._searchNamespace(value);
+ this._namespacePrefixes.getOrInsertComputed(prefix, makeArr).push(namespace);
+ }
+ }
+ _getNamespaceToUse(prefix) {
+ if (!prefix) {
+ return this._currentNamespace;
+ }
+ const prefixStack = this._namespacePrefixes.get(prefix);
+ if (prefixStack?.length > 0) {
+ return prefixStack.at(-1);
+ }
+ warn(`Unknown namespace prefix: ${prefix}.`);
+ return null;
+ }
+ clean(data) {
+ const {
+ hasNamespace,
+ prefixes,
+ nsAgnostic
+ } = data;
+ if (hasNamespace) {
+ this._currentNamespace = this._namespaceStack.pop();
+ }
+ prefixes?.forEach(({
+ prefix
+ }) => {
+ this._namespacePrefixes.get(prefix).pop();
+ });
+ if (nsAgnostic) {
+ this._nsAgnosticLevel--;
+ }
+ }
+}
+
+;// ./src/core/xfa/parser.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class XFAParser extends XMLParserBase {
+ constructor(rootNameSpace = null, richText = false) {
+ super();
+ this._builder = new Builder(rootNameSpace);
+ this._stack = [];
+ this._globalData = {
+ usedTypefaces: new Set()
+ };
+ this._ids = new Map();
+ this._current = this._builder.buildRoot(this._ids);
+ this._errorCode = XMLParserErrorCode.NoError;
+ this._whiteRegex = /^\s+$/;
+ this._nbsps = /\xa0+/g;
+ this._richText = richText;
+ }
+ parse(data) {
+ this.parseXml(data);
+ if (this._errorCode !== XMLParserErrorCode.NoError) {
+ return undefined;
+ }
+ this._current[$finalize]();
+ return this._current.element;
+ }
+ onText(text) {
+ text = text.replace(this._nbsps, match => match.slice(1) + " ");
+ if (this._richText || this._current[$acceptWhitespace]()) {
+ this._current[$onText](text, this._richText);
+ return;
+ }
+ if (this._whiteRegex.test(text)) {
+ return;
+ }
+ this._current[$onText](text.trim());
+ }
+ onCdata(text) {
+ this._current[$onText](text);
+ }
+ _mkAttributes(attributes, tagName) {
+ let namespace = null;
+ let prefixes = null;
+ const attributeObj = Object.create({});
+ for (const {
+ name,
+ value
+ } of attributes) {
+ if (name === "xmlns") {
+ if (!namespace) {
+ namespace = value;
+ } else {
+ warn(`XFA - multiple namespace definition in <${tagName}>`);
+ }
+ } else if (name.startsWith("xmlns:")) {
+ const prefix = name.substring("xmlns:".length);
+ prefixes ??= [];
+ prefixes.push({
+ prefix,
+ value
+ });
+ } else {
+ const i = name.indexOf(":");
+ if (i === -1) {
+ attributeObj[name] = value;
+ } else {
+ const nsAttrs = attributeObj[$nsAttributes] ??= Object.create(null);
+ const [ns, attrName] = [name.slice(0, i), name.slice(i + 1)];
+ const attrs = nsAttrs[ns] ||= Object.create(null);
+ attrs[attrName] = value;
+ }
+ }
+ }
+ return [namespace, prefixes, attributeObj];
+ }
+ _getNameAndPrefix(name, nsAgnostic) {
+ const i = name.indexOf(":");
+ if (i === -1) {
+ return [name, null];
+ }
+ return [name.substring(i + 1), nsAgnostic ? "" : name.substring(0, i)];
+ }
+ onBeginElement(tagName, attributes, isEmpty) {
+ const [namespace, prefixes, attributesObj] = this._mkAttributes(attributes, tagName);
+ const [name, nsPrefix] = this._getNameAndPrefix(tagName, this._builder.isNsAgnostic());
+ const node = this._builder.build({
+ nsPrefix,
+ name,
+ attributes: attributesObj,
+ namespace,
+ prefixes
+ });
+ node[$globalData] = this._globalData;
+ if (isEmpty) {
+ node[$finalize]();
+ if (this._current[$onChild](node)) {
+ node[$setId](this._ids);
+ }
+ node[$clean](this._builder);
+ return;
+ }
+ this._stack.push(this._current);
+ this._current = node;
+ }
+ onEndElement(name) {
+ const node = this._current;
+ if (node[$isCDATAXml]() && typeof node[$content] === "string") {
+ const parser = new XFAParser();
+ parser._globalData = this._globalData;
+ const root = parser.parse(node[$content]);
+ node[$content] = null;
+ node[$onChild](root);
+ }
+ node[$finalize]();
+ this._current = this._stack.pop();
+ if (this._current[$onChild](node)) {
+ node[$setId](this._ids);
+ }
+ node[$clean](this._builder);
+ }
+ onError(code) {
+ this._errorCode = code;
+ }
+}
+
+;// ./src/core/xfa/factory.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class XFAFactory {
+ constructor(data) {
+ try {
+ this.root = new XFAParser().parse(XFAFactory._createDocument(data));
+ const binder = new Binder(this.root);
+ this.form = binder.bind();
+ this.dataHandler = new DataHandler(this.root, binder.getData());
+ this.form[$globalData].template = this.form;
+ } catch (e) {
+ warn(`XFA - an error occurred during parsing and binding: ${e}`);
+ }
+ }
+ isValid() {
+ return !!(this.root && this.form);
+ }
+ _createPagesHelper() {
+ const iterator = this.form[$toPages]();
+ return new Promise((resolve, reject) => {
+ const nextIteration = () => {
+ try {
+ const value = iterator.next();
+ if (value.done) {
+ resolve(value.value);
+ } else {
+ setTimeout(nextIteration, 0);
+ }
+ } catch (e) {
+ reject(e);
+ }
+ };
+ setTimeout(nextIteration, 0);
+ });
+ }
+ async _createPages() {
+ try {
+ this.pages = await this._createPagesHelper();
+ this.dims = this.pages.children.map(c => {
+ const {
+ width,
+ height
+ } = c.attributes.style;
+ return [0, 0, parseInt(width, 10), parseInt(height, 10)];
+ });
+ } catch (e) {
+ warn(`XFA - an error occurred during layout: ${e}`);
+ }
+ }
+ getBoundingBox(pageIndex) {
+ return this.dims[pageIndex];
+ }
+ async getNumPages() {
+ if (!this.pages) {
+ await this._createPages();
+ }
+ return this.dims.length;
+ }
+ setImages(images) {
+ this.form[$globalData].images = images;
+ }
+ setFonts(fonts) {
+ this.form[$globalData].fontFinder = new FontFinder(fonts);
+ const missingFonts = [];
+ for (let typeface of this.form[$globalData].usedTypefaces) {
+ typeface = stripQuotes(typeface);
+ const font = this.form[$globalData].fontFinder.find(typeface);
+ if (!font) {
+ missingFonts.push(typeface);
+ }
+ }
+ if (missingFonts.length > 0) {
+ return missingFonts;
+ }
+ return null;
+ }
+ appendFonts(fonts, reallyMissingFonts) {
+ this.form[$globalData].fontFinder.add(fonts, reallyMissingFonts);
+ }
+ async getPages() {
+ if (!this.pages) {
+ await this._createPages();
+ }
+ const pages = this.pages;
+ this.pages = null;
+ return pages;
+ }
+ serializeData(storage) {
+ return this.dataHandler.serialize(storage);
+ }
+ static _createDocument(data) {
+ return !data.get("/xdp:xdp") ? data.get("xdp:xdp") : data.values().join("");
+ }
+ static getRichTextAsHtml(rc) {
+ if (!rc || typeof rc !== "string") {
+ return null;
+ }
+ try {
+ let root = new XFAParser(XhtmlNamespace, true).parse(rc);
+ if (!["body", "xhtml"].includes(root[$nodeName])) {
+ const newRoot = XhtmlNamespace.body({});
+ newRoot[$appendChild](root);
+ root = newRoot;
+ }
+ const result = root[$toHTML]();
+ if (!result.success) {
+ return null;
+ }
+ const {
+ html
+ } = result;
+ const {
+ attributes
+ } = html;
+ if (attributes) {
+ attributes.class &&= attributes.class.filter(attr => !attr.startsWith("xfa"));
+ attributes.dir = "auto";
+ }
+ return {
+ html,
+ str: root[$text]()
+ };
+ } catch (e) {
+ warn(`XFA - an error occurred during parsing of rich text: ${e}`);
+ }
+ return null;
+ }
+}
+
+;// ./src/core/annotation.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class AnnotationFactory {
+ static createGlobals(pdfManager) {
+ return Promise.all([pdfManager.ensureCatalog("acroForm"), pdfManager.ensureDoc("xfaDatasets"), pdfManager.ensureCatalog("structTreeRoot"), pdfManager.ensureCatalog("baseUrl"), pdfManager.ensureCatalog("attachments"), pdfManager.ensureCatalog("globalColorSpaceCache")]).then(([acroForm, xfaDatasets, structTreeRoot, baseUrl, attachments, globalColorSpaceCache]) => ({
+ pdfManager,
+ catalog: pdfManager.pdfDocument.catalog,
+ acroForm: acroForm instanceof Dict ? acroForm : Dict.empty,
+ xfaDatasets,
+ structTreeRoot,
+ baseUrl,
+ attachments,
+ globalColorSpaceCache
+ }), reason => {
+ warn(`createGlobals: "${reason}".`);
+ return null;
+ });
+ }
+ static async create(xref, ref, annotationGlobals, idFactory, collectFields, orphanFields, collectByType, pageRef) {
+ const pageIndex = collectFields ? await this._getPageIndex(xref, ref, annotationGlobals.pdfManager) : null;
+ return annotationGlobals.pdfManager.ensure(this, "_create", [xref, ref, annotationGlobals, idFactory, collectFields, orphanFields, collectByType, pageIndex, pageRef]);
+ }
+ static _create(xref, ref, annotationGlobals, idFactory, collectFields = false, orphanFields = null, collectByType = null, pageIndex = null, pageRef = null) {
+ const dict = xref.fetchIfRef(ref);
+ if (!(dict instanceof Dict)) {
+ return undefined;
+ }
+ let subtype = dict.get("Subtype");
+ subtype = subtype instanceof Name ? subtype.name : null;
+ if (collectByType && !collectByType.has(AnnotationType[subtype?.toUpperCase()])) {
+ return null;
+ }
+ const {
+ acroForm,
+ pdfManager
+ } = annotationGlobals;
+ const id = ref instanceof Ref ? ref.toString() : `annot_${idFactory.createObjId()}`;
+ const parameters = {
+ xref,
+ ref,
+ dict,
+ subtype,
+ id,
+ annotationGlobals,
+ collectFields,
+ orphanFields,
+ needAppearances: !collectFields && acroForm.get("NeedAppearances") === true,
+ pageIndex,
+ evaluatorOptions: pdfManager.evaluatorOptions,
+ pageRef
+ };
+ switch (subtype) {
+ case "Link":
+ return new LinkAnnotation(parameters);
+ case "Text":
+ return new TextAnnotation(parameters);
+ case "Widget":
+ let fieldType = getInheritableProperty({
+ dict,
+ key: "FT"
+ });
+ fieldType = fieldType instanceof Name ? fieldType.name : null;
+ switch (fieldType) {
+ case "Tx":
+ return new TextWidgetAnnotation(parameters);
+ case "Btn":
+ return new ButtonWidgetAnnotation(parameters);
+ case "Ch":
+ return new ChoiceWidgetAnnotation(parameters);
+ case "Sig":
+ return new SignatureWidgetAnnotation(parameters);
+ }
+ warn(`Unimplemented widget field type "${fieldType}", ` + "falling back to base field type.");
+ return new WidgetAnnotation(parameters);
+ case "Popup":
+ return new PopupAnnotation(parameters);
+ case "FreeText":
+ return new FreeTextAnnotation(parameters);
+ case "Line":
+ return new LineAnnotation(parameters);
+ case "Square":
+ return new SquareAnnotation(parameters);
+ case "Circle":
+ return new CircleAnnotation(parameters);
+ case "PolyLine":
+ return new PolylineAnnotation(parameters);
+ case "Polygon":
+ return new PolygonAnnotation(parameters);
+ case "Caret":
+ return new CaretAnnotation(parameters);
+ case "Ink":
+ return new InkAnnotation(parameters);
+ case "Highlight":
+ return new HighlightAnnotation(parameters);
+ case "Underline":
+ return new UnderlineAnnotation(parameters);
+ case "Squiggly":
+ return new SquigglyAnnotation(parameters);
+ case "StrikeOut":
+ return new StrikeOutAnnotation(parameters);
+ case "Stamp":
+ return new StampAnnotation(parameters);
+ case "FileAttachment":
+ return new FileAttachmentAnnotation(parameters);
+ case "RichMedia":
+ return new RichMediaAnnotation(parameters);
+ case "Screen":
+ return new ScreenAnnotation(parameters);
+ case "Sound":
+ return new SoundAnnotation(parameters);
+ default:
+ if (!collectFields) {
+ if (!subtype) {
+ warn("Annotation is missing the required /Subtype.");
+ } else {
+ warn(`Unimplemented annotation type "${subtype}", ` + "falling back to base annotation.");
+ }
+ }
+ return new Annotation(parameters);
+ }
+ }
+ static async _getPageIndex(xref, ref, pdfManager) {
+ try {
+ const annotDict = await xref.fetchIfRefAsync(ref);
+ if (!(annotDict instanceof Dict)) {
+ return -1;
+ }
+ const pageRef = annotDict.getRaw("P");
+ if (pageRef instanceof Ref) {
+ try {
+ return await pdfManager.ensureCatalog("getPageIndex", [pageRef]);
+ } catch (ex) {
+ info(`_getPageIndex -- not a valid page reference: "${ex}".`);
+ }
+ }
+ if (annotDict.has("Kids")) {
+ return -1;
+ }
+ const numPages = await pdfManager.ensureDoc("numPages");
+ for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
+ const page = await pdfManager.getPage(pageIndex);
+ const annotations = await pdfManager.ensure(page, "annotations");
+ for (const annotRef of annotations) {
+ if (annotRef instanceof Ref && isRefsEqual(annotRef, ref)) {
+ return pageIndex;
+ }
+ }
+ }
+ } catch (ex) {
+ warn(`_getPageIndex: "${ex}".`);
+ }
+ return -1;
+ }
+ static generateImages(annotations, xref, isOffscreenCanvasSupported) {
+ if (!isOffscreenCanvasSupported) {
+ warn("generateImages: OffscreenCanvas is not supported, cannot save or print some annotations with images.");
+ return null;
+ }
+ let imagePromises;
+ for (const {
+ bitmapId,
+ bitmap
+ } of annotations) {
+ if (!bitmap) {
+ continue;
+ }
+ imagePromises ||= new Map();
+ imagePromises.set(bitmapId, createImage(bitmap, xref));
+ }
+ return imagePromises;
+ }
+ static async saveNewAnnotations(evaluator, xref, task, annotations, imagePromises, changes) {
+ let baseFontRef;
+ const promises = [];
+ const {
+ isOffscreenCanvasSupported
+ } = evaluator.options;
+ for (const annotation of annotations) {
+ if (annotation.deleted) {
+ continue;
+ }
+ switch (annotation.annotationType) {
+ case AnnotationEditorType.FREETEXT:
+ if (!baseFontRef) {
+ const baseFont = new Dict(xref);
+ baseFont.setIfName("BaseFont", "Helvetica");
+ baseFont.setIfName("Type", "Font");
+ baseFont.setIfName("Subtype", "Type1");
+ baseFont.setIfName("Encoding", "WinAnsiEncoding");
+ baseFontRef = xref.getNewTemporaryRef();
+ changes.put(baseFontRef, {
+ data: baseFont
+ });
+ }
+ promises.push(FreeTextAnnotation.createNewAnnotation(xref, annotation, changes, {
+ evaluator,
+ task,
+ baseFontRef
+ }));
+ break;
+ case AnnotationEditorType.HIGHLIGHT:
+ if (annotation.quadPoints) {
+ promises.push(HighlightAnnotation.createNewAnnotation(xref, annotation, changes));
+ } else {
+ promises.push(InkAnnotation.createNewAnnotation(xref, annotation, changes));
+ }
+ break;
+ case AnnotationEditorType.INK:
+ promises.push(InkAnnotation.createNewAnnotation(xref, annotation, changes));
+ break;
+ case AnnotationEditorType.STAMP:
+ const image = isOffscreenCanvasSupported ? await imagePromises?.get(annotation.bitmapId) : null;
+ if (image?.imageStream) {
+ const {
+ imageStream,
+ smaskStream
+ } = image;
+ if (smaskStream) {
+ const smaskRef = xref.getNewTemporaryRef();
+ changes.put(smaskRef, {
+ data: smaskStream
+ });
+ imageStream.dict.set("SMask", smaskRef);
+ }
+ const imageRef = image.imageRef = xref.getNewTemporaryRef();
+ changes.put(imageRef, {
+ data: imageStream
+ });
+ image.imageStream = null;
+ image.imageRenderStream = null;
+ image.smaskStream = null;
+ image.smaskRenderStream = null;
+ }
+ promises.push(StampAnnotation.createNewAnnotation(xref, annotation, changes, {
+ image
+ }));
+ break;
+ case AnnotationEditorType.SIGNATURE:
+ promises.push(StampAnnotation.createNewAnnotation(xref, annotation, changes, {}));
+ break;
+ }
+ }
+ return {
+ annotations: (await Promise.all(promises)).flat()
+ };
+ }
+ static async printNewAnnotations(annotationGlobals, evaluator, task, annotations, imagePromises) {
+ if (!annotations) {
+ return null;
+ }
+ const {
+ options,
+ xref
+ } = evaluator;
+ const promises = [];
+ for (const annotation of annotations) {
+ if (annotation.deleted) {
+ continue;
+ }
+ switch (annotation.annotationType) {
+ case AnnotationEditorType.FREETEXT:
+ promises.push(FreeTextAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
+ evaluator,
+ task,
+ evaluatorOptions: options
+ }));
+ break;
+ case AnnotationEditorType.HIGHLIGHT:
+ if (annotation.quadPoints) {
+ promises.push(HighlightAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
+ evaluatorOptions: options
+ }));
+ } else {
+ promises.push(InkAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
+ evaluatorOptions: options
+ }));
+ }
+ break;
+ case AnnotationEditorType.INK:
+ promises.push(InkAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
+ evaluatorOptions: options
+ }));
+ break;
+ case AnnotationEditorType.STAMP:
+ const image = options.isOffscreenCanvasSupported ? await imagePromises?.get(annotation.bitmapId) : null;
+ if (image?.imageStream) {
+ const {
+ imageStream,
+ imageRenderStream,
+ smaskStream,
+ smaskRenderStream
+ } = image;
+ const imageRef = imageRenderStream || new JpegStream(imageStream, imageStream.length);
+ if (smaskStream || smaskRenderStream) {
+ imageRef.dict.set("SMask", smaskRenderStream || smaskStream);
+ }
+ image.imageRef = imageRef;
+ image.imageStream = null;
+ image.imageRenderStream = null;
+ image.smaskStream = null;
+ image.smaskRenderStream = null;
+ }
+ promises.push(StampAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
+ image,
+ evaluatorOptions: options
+ }));
+ break;
+ case AnnotationEditorType.SIGNATURE:
+ promises.push(StampAnnotation.createNewPrintAnnotation(annotationGlobals, xref, annotation, {
+ evaluatorOptions: options
+ }));
+ break;
+ }
+ }
+ return Promise.all(promises);
+ }
+}
+function getRgbColor(color, defaultColor = new Uint8ClampedArray(3)) {
+ if (!Array.isArray(color)) {
+ return defaultColor;
+ }
+ const rgbColor = defaultColor || new Uint8ClampedArray(3);
+ switch (color.length) {
+ case 0:
+ return null;
+ case 1:
+ ColorSpaceUtils.gray.getRgbItem(color, 0, rgbColor, 0);
+ return rgbColor;
+ case 3:
+ ColorSpaceUtils.rgb.getRgbItem(color, 0, rgbColor, 0);
+ return rgbColor;
+ case 4:
+ ColorSpaceUtils.cmyk.getRgbItem(color, 0, rgbColor, 0);
+ return rgbColor;
+ default:
+ return defaultColor;
+ }
+}
+function getPdfColorArray(color, defaultValue = null) {
+ return color && Array.from(color, c => c / 255) || defaultValue;
+}
+function getQuadPoints(dict, rect) {
+ const quadPoints = dict.getArray("QuadPoints");
+ if (!isNumberArray(quadPoints, null) || quadPoints.length === 0 || quadPoints.length % 8 > 0) {
+ return null;
+ }
+ const newQuadPoints = new Float32Array(quadPoints.length);
+ for (let i = 0, ii = quadPoints.length; i < ii; i += 8) {
+ const [x1, y1, x2, y2, x3, y3, x4, y4] = quadPoints.slice(i, i + 8);
+ const minX = Math.min(x1, x2, x3, x4);
+ const maxX = Math.max(x1, x2, x3, x4);
+ const minY = Math.min(y1, y2, y3, y4);
+ const maxY = Math.max(y1, y2, y3, y4);
+ if (rect !== null && (minX < rect[0] || maxX > rect[2] || minY < rect[1] || maxY > rect[3])) {
+ return null;
+ }
+ newQuadPoints.set([minX, maxY, maxX, maxY, minX, minY, maxX, minY], i);
+ }
+ return newQuadPoints;
+}
+function getTransformMatrix(rect, bbox, matrix) {
+ const minMax = F32_BBOX_INIT.slice();
+ Util.axialAlignedBoundingBox(bbox, matrix, minMax);
+ const [minX, minY, maxX, maxY] = minMax;
+ if (minX === maxX || minY === maxY) {
+ return [1, 0, 0, 1, rect[0], rect[1]];
+ }
+ const xRatio = (rect[2] - rect[0]) / (maxX - minX);
+ const yRatio = (rect[3] - rect[1]) / (maxY - minY);
+ return [xRatio, 0, 0, yRatio, rect[0] - minX * xRatio, rect[1] - minY * yRatio];
+}
+function writeLineToCurveToAppearance(data, buffer, maybeClose = false) {
+ buffer.push(`${numberToString(data[4])} ${numberToString(data[5])} m`);
+ for (let i = 6, ii = data.length; i < ii; i += 6) {
+ if (isNaN(data[i])) {
+ buffer.push(`${numberToString(data[i + 4])} ${numberToString(data[i + 5])} l`);
+ } else {
+ const curve = data.slice(i, i + 6);
+ buffer.push(`${curve.map(numberToString).join(" ")} c`);
+ }
+ }
+ if (maybeClose && data.length === 6) {
+ buffer.push(`${numberToString(data[4])} ${numberToString(data[5])} l`);
+ }
+}
+class Annotation {
+ appearance = null;
+ _oc = undefined;
+ constructor(params) {
+ const {
+ annotationGlobals,
+ dict,
+ orphanFields,
+ ref,
+ subtype,
+ xref
+ } = params;
+ const parentRef = orphanFields?.get(ref);
+ if (parentRef) {
+ dict.set("Parent", parentRef);
+ }
+ this.setTitle(dict.get("T"));
+ this.setContents(dict.get("Contents"));
+ this.setModificationDate(dict.get("M"));
+ this.setFlags(dict.get("F"));
+ this.setRectangle(dict.getArray("Rect"));
+ this.setColor(dict.getArray("C"));
+ this.setBorderStyle(dict);
+ this.setAppearance(dict);
+ this.#setOptionalContent(xref, dict);
+ const MK = dict.get("MK");
+ this.setBorderAndBackgroundColors(MK);
+ this.setRotation(MK, dict);
+ this.ref = params.ref instanceof Ref ? params.ref : null;
+ this._streams = [];
+ if (this.appearance) {
+ this._streams.push(this.appearance);
+ }
+ const isLocked = !!(this.flags & AnnotationFlag.LOCKED);
+ const isContentLocked = !!(this.flags & AnnotationFlag.LOCKEDCONTENTS);
+ this.data = {
+ annotationType: AnnotationType[subtype?.toUpperCase()],
+ annotationFlags: this.flags,
+ borderStyle: this.borderStyle,
+ color: this.color,
+ backgroundColor: this.backgroundColor,
+ borderColor: this.borderColor,
+ rotation: this.rotation,
+ contentsObj: this._contents,
+ hasAppearance: !!this.appearance,
+ id: params.id,
+ modificationDate: this.modificationDate,
+ oc: this._oc,
+ rect: this.rectangle,
+ subtype,
+ hasOwnCanvas: false,
+ noRotate: !!(this.flags & AnnotationFlag.NOROTATE),
+ noHTML: isLocked && isContentLocked,
+ isEditable: false,
+ structParent: -1
+ };
+ if (annotationGlobals.structTreeRoot) {
+ let structParent = dict.get("StructParent");
+ this.data.structParent = structParent = Number.isInteger(structParent) && structParent >= 0 ? structParent : -1;
+ annotationGlobals.structTreeRoot.addAnnotationIdToPage(params.pageRef, structParent, this.ref);
+ }
+ if (params.collectFields) {
+ const kids = dict.get("Kids");
+ if (Array.isArray(kids)) {
+ const kidIds = [];
+ for (const kid of kids) {
+ if (kid instanceof Ref) {
+ kidIds.push(kid.toString());
+ }
+ }
+ if (kidIds.length !== 0) {
+ this.data.kidIds = kidIds;
+ }
+ }
+ this.data.actions = collectActions(xref, dict, AnnotationActionEventType);
+ this.data.fieldName = this._constructFieldName(dict);
+ this.data.pageIndex = params.pageIndex;
+ }
+ const it = dict.get("IT");
+ if (it instanceof Name) {
+ this.data.it = it.name;
+ }
+ this._isOffscreenCanvasSupported = params.evaluatorOptions.isOffscreenCanvasSupported;
+ this._fallbackFontDict = null;
+ this._needAppearances = false;
+ }
+ _getOperatorListNoAppearance() {
+ return {
+ opList: new OperatorList(),
+ separateForm: false,
+ separateCanvas: false
+ };
+ }
+ _hasFlag(flags, flag) {
+ return !!(flags & flag);
+ }
+ _buildFlags(noView, noPrint) {
+ let {
+ flags
+ } = this;
+ if (noView === undefined) {
+ if (noPrint === undefined) {
+ return undefined;
+ }
+ if (noPrint) {
+ return flags & ~AnnotationFlag.PRINT;
+ }
+ return flags & ~AnnotationFlag.HIDDEN | AnnotationFlag.PRINT;
+ }
+ if (noView) {
+ flags |= AnnotationFlag.PRINT;
+ if (noPrint) {
+ return flags & ~AnnotationFlag.NOVIEW | AnnotationFlag.HIDDEN;
+ }
+ return flags & ~AnnotationFlag.HIDDEN | AnnotationFlag.NOVIEW;
+ }
+ flags &= ~(AnnotationFlag.HIDDEN | AnnotationFlag.NOVIEW);
+ if (noPrint) {
+ return flags & ~AnnotationFlag.PRINT;
+ }
+ return flags | AnnotationFlag.PRINT;
+ }
+ _isViewable(flags) {
+ return !this._hasFlag(flags, AnnotationFlag.INVISIBLE) && !this._hasFlag(flags, AnnotationFlag.NOVIEW);
+ }
+ _isPrintable(flags) {
+ return this._hasFlag(flags, AnnotationFlag.PRINT) && !this._hasFlag(flags, AnnotationFlag.HIDDEN) && !this._hasFlag(flags, AnnotationFlag.INVISIBLE);
+ }
+ mustBeViewed(annotationStorage, _renderForms) {
+ const noView = annotationStorage?.get(this.data.id)?.noView;
+ if (noView !== undefined) {
+ return !noView;
+ }
+ return this.viewable && !this._hasFlag(this.flags, AnnotationFlag.HIDDEN);
+ }
+ mustBePrinted(annotationStorage) {
+ const noPrint = annotationStorage?.get(this.data.id)?.noPrint;
+ if (noPrint !== undefined) {
+ return !noPrint;
+ }
+ return this.printable;
+ }
+ mustBeViewedWhenEditing(isEditing, modifiedIds = null) {
+ return isEditing ? !this.data.isEditable : !modifiedIds?.has(this.data.id);
+ }
+ get viewable() {
+ if (this.data.quadPoints === null) {
+ return false;
+ }
+ if (this.flags === 0) {
+ return true;
+ }
+ return this._isViewable(this.flags);
+ }
+ get printable() {
+ if (this.data.quadPoints === null) {
+ return false;
+ }
+ if (this.flags === 0) {
+ return false;
+ }
+ return this._isPrintable(this.flags);
+ }
+ _parseStringHelper(data) {
+ const str = typeof data === "string" ? stringToPDFString(data) : "";
+ const dir = str && bidi(str).dir === "rtl" ? "rtl" : "ltr";
+ return {
+ str,
+ dir
+ };
+ }
+ setDefaultAppearance(params) {
+ const {
+ dict,
+ annotationGlobals
+ } = params;
+ const defaultAppearance = getInheritableProperty({
+ dict,
+ key: "DA"
+ }) || annotationGlobals.acroForm.get("DA");
+ this._defaultAppearance = typeof defaultAppearance === "string" ? defaultAppearance : "";
+ this.data.defaultAppearanceData = parseDefaultAppearance(this._defaultAppearance);
+ }
+ setTitle(title) {
+ this._title = this._parseStringHelper(title);
+ }
+ setContents(contents) {
+ this._contents = this._parseStringHelper(contents);
+ }
+ setModificationDate(modificationDate) {
+ this.modificationDate = typeof modificationDate === "string" ? modificationDate : null;
+ }
+ setFlags(flags) {
+ this.flags = Number.isInteger(flags) && flags > 0 ? flags : 0;
+ if (this.flags & AnnotationFlag.INVISIBLE && this.constructor.name !== "Annotation") {
+ this.flags ^= AnnotationFlag.INVISIBLE;
+ }
+ }
+ hasFlag(flag) {
+ return this._hasFlag(this.flags, flag);
+ }
+ setRectangle(rectangle) {
+ this.rectangle = lookupNormalRect(rectangle, [0, 0, 0, 0]);
+ }
+ setColor(color) {
+ this.color = getRgbColor(color);
+ }
+ setLineEndings(lineEndings) {
+ this.lineEndings = ["None", "None"];
+ if (Array.isArray(lineEndings) && lineEndings.length === 2) {
+ for (let i = 0; i < 2; i++) {
+ const obj = lineEndings[i];
+ if (obj instanceof Name) {
+ switch (obj.name) {
+ case "None":
+ continue;
+ case "Square":
+ case "Circle":
+ case "Diamond":
+ case "OpenArrow":
+ case "ClosedArrow":
+ case "Butt":
+ case "ROpenArrow":
+ case "RClosedArrow":
+ case "Slash":
+ this.lineEndings[i] = obj.name;
+ continue;
+ }
+ }
+ warn(`Ignoring invalid lineEnding: ${obj}`);
+ }
+ }
+ }
+ setRotation(mk, dict) {
+ this.rotation = 0;
+ let angle = mk instanceof Dict ? mk.get("R") || 0 : dict.get("Rotate") || 0;
+ if (Number.isInteger(angle) && angle !== 0) {
+ angle %= 360;
+ if (angle < 0) {
+ angle += 360;
+ }
+ if (angle % 90 === 0) {
+ this.rotation = angle;
+ }
+ }
+ }
+ setBorderAndBackgroundColors(mk) {
+ if (mk instanceof Dict) {
+ this.borderColor = getRgbColor(mk.getArray("BC"), null);
+ this.backgroundColor = getRgbColor(mk.getArray("BG"), null);
+ } else {
+ this.borderColor = this.backgroundColor = null;
+ }
+ }
+ setBorderStyle(borderStyle) {
+ this.borderStyle = new AnnotationBorderStyle();
+ if (!(borderStyle instanceof Dict)) {
+ return;
+ }
+ if (borderStyle.has("BS")) {
+ const dict = borderStyle.get("BS");
+ if (dict instanceof Dict) {
+ const dictType = dict.get("Type");
+ if (!dictType || isName(dictType, "Border")) {
+ this.borderStyle.setWidth(dict.get("W"), this.rectangle);
+ this.borderStyle.setStyle(dict.get("S"));
+ this.borderStyle.setDashArray(dict.getArray("D"));
+ }
+ }
+ } else if (borderStyle.has("Border")) {
+ const array = borderStyle.getArray("Border");
+ if (Array.isArray(array)) {
+ if (array.length >= 3) {
+ this.borderStyle.setHorizontalCornerRadius(array[0]);
+ this.borderStyle.setVerticalCornerRadius(array[1]);
+ this.borderStyle.setWidth(array[2], this.rectangle);
+ if (array.length === 4) {
+ this.borderStyle.setDashArray(array[3], true);
+ }
+ } else if (array.length === 0) {
+ this.borderStyle.setWidth(0);
+ }
+ }
+ } else {
+ this.borderStyle.setWidth(0);
+ }
+ }
+ setAppearance(dict) {
+ const appearanceStates = dict.get("AP");
+ if (!(appearanceStates instanceof Dict)) {
+ return;
+ }
+ const normalAppearanceState = appearanceStates.get("N");
+ if (normalAppearanceState instanceof BaseStream) {
+ this.appearance = normalAppearanceState;
+ return;
+ }
+ if (!(normalAppearanceState instanceof Dict)) {
+ return;
+ }
+ const as = dict.get("AS");
+ if (!(as instanceof Name)) {
+ return;
+ }
+ const appearance = normalAppearanceState.get(as.name);
+ if (appearance instanceof BaseStream) {
+ this.appearance = appearance;
+ }
+ }
+ #setOptionalContent(xref, dict) {
+ if (dict.has("OC")) {
+ try {
+ this._oc = parseMarkedContentProps(xref, dict.get("OC"), null);
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`#setOptionalContent: ${ex}`);
+ }
+ }
+ }
+ async loadResources(keys, appearance) {
+ const resources = await appearance.dict.getAsync("Resources");
+ if (resources) {
+ await ObjectLoader.load(resources, keys, resources.xref);
+ }
+ return resources;
+ }
+ get _ownCanvasRequiresForms() {
+ return false;
+ }
+ async getOperatorList(evaluator, task, intent, annotationStorage) {
+ const {
+ hasOwnCanvas,
+ id,
+ rect
+ } = this.data;
+ let appearance = this.appearance;
+ const isUsingOwnCanvas = !!(hasOwnCanvas && intent & RenderingIntentFlag.DISPLAY && (!this._ownCanvasRequiresForms || intent & RenderingIntentFlag.ANNOTATIONS_FORMS));
+ if (isUsingOwnCanvas && (this.width === 0 || this.height === 0)) {
+ this.data.hasOwnCanvas = false;
+ return this._getOperatorListNoAppearance();
+ }
+ if (!appearance) {
+ if (!isUsingOwnCanvas) {
+ return this._getOperatorListNoAppearance();
+ }
+ appearance = new StringStream("", new Dict());
+ }
+ const appearanceDict = appearance.dict;
+ const resources = await this.loadResources(RESOURCES_KEYS_OPERATOR_LIST, appearance);
+ const bbox = lookupRect(appearanceDict.getArray("BBox"), [0, 0, this.width, this.height]);
+ const matrix = lookupMatrix(appearanceDict.getArray("Matrix"), IDENTITY_MATRIX);
+ const transform = getTransformMatrix(rect, bbox, matrix);
+ const opList = new OperatorList();
+ const optionalContent = this._oc;
+ if (optionalContent !== undefined) {
+ opList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
+ }
+ opList.addOp(OPS.beginAnnotation, [id, rect, transform, matrix, isUsingOwnCanvas]);
+ await evaluator.getOperatorList({
+ stream: appearance,
+ task,
+ resources,
+ operatorList: opList,
+ fallbackFontDict: this._fallbackFontDict
+ });
+ opList.addOp(OPS.endAnnotation, []);
+ if (optionalContent !== undefined) {
+ opList.addOp(OPS.endMarkedContent, []);
+ }
+ this.reset();
+ return {
+ opList,
+ separateForm: false,
+ separateCanvas: isUsingOwnCanvas
+ };
+ }
+ async save(evaluator, task, annotationStorage, changes) {
+ return null;
+ }
+ get overlaysTextContent() {
+ return false;
+ }
+ get hasTextContent() {
+ return false;
+ }
+ async extractTextContent(evaluator, task, viewBox) {
+ if (!this.appearance) {
+ return;
+ }
+ const resources = await this.loadResources(RESOURCES_KEYS_TEXT_CONTENT, this.appearance);
+ const text = [];
+ const buffer = [];
+ let firstPositionX = Infinity;
+ let firstPositionY = Infinity;
+ let firstPosition = null;
+ const sink = {
+ desiredSize: Math.Infinity,
+ ready: true,
+ enqueue(chunk, size) {
+ for (const item of chunk.items) {
+ if (item.str === undefined) {
+ continue;
+ }
+ firstPositionX = Math.min(firstPositionX, item.transform[4]);
+ firstPositionY = Math.min(firstPositionY, item.transform[5]);
+ buffer.push(item.str);
+ if (item.hasEOL) {
+ text.push(buffer.join("").trimEnd());
+ buffer.length = 0;
+ }
+ }
+ }
+ };
+ await evaluator.getTextContent({
+ stream: this.appearance,
+ task,
+ resources,
+ includeMarkedContent: true,
+ keepWhiteSpace: true,
+ sink,
+ viewBox
+ });
+ this.reset();
+ if (firstPositionX !== Infinity) {
+ firstPosition = [firstPositionX, firstPositionY];
+ }
+ if (buffer.length) {
+ text.push(buffer.join("").trimEnd());
+ }
+ if (text.length > 1 || text[0]) {
+ const appearanceDict = this.appearance.dict;
+ const bbox = lookupRect(appearanceDict.getArray("BBox"), null);
+ const matrix = lookupMatrix(appearanceDict.getArray("Matrix"), null);
+ this.data.textPosition = this._transformPoint(firstPosition, bbox, matrix);
+ this.data.textContent = text;
+ }
+ }
+ _transformPoint(coords, bbox, matrix) {
+ const {
+ rect
+ } = this.data;
+ bbox ||= [0, 0, 1, 1];
+ matrix ||= [1, 0, 0, 1, 0, 0];
+ const transform = getTransformMatrix(rect, bbox, matrix);
+ transform[4] -= rect[0];
+ transform[5] -= rect[1];
+ const p = coords.slice();
+ Util.applyTransform(p, transform);
+ Util.applyTransform(p, matrix);
+ return p;
+ }
+ getFieldObject() {
+ if (this.data.kidIds) {
+ return {
+ id: this.data.id,
+ actions: this.data.actions,
+ name: this.data.fieldName,
+ strokeColor: this.data.borderColor,
+ fillColor: this.data.backgroundColor,
+ type: "",
+ kidIds: this.data.kidIds,
+ page: this.data.pageIndex,
+ rotation: this.rotation
+ };
+ }
+ return null;
+ }
+ reset() {
+ for (const stream of this._streams) {
+ stream.reset();
+ }
+ }
+ _constructFieldName(dict) {
+ if (!dict.has("T") && !dict.has("Parent")) {
+ warn("Unknown field name, falling back to empty field name.");
+ return "";
+ }
+ if (!dict.has("Parent")) {
+ return stringToPDFString(dict.get("T"));
+ }
+ const fieldName = [];
+ if (dict.has("T")) {
+ fieldName.unshift(stringToPDFString(dict.get("T")));
+ }
+ let loopDict = dict;
+ const visited = new RefSet();
+ if (dict.objId) {
+ visited.put(dict.objId);
+ }
+ while (loopDict.has("Parent")) {
+ loopDict = loopDict.get("Parent");
+ if (!(loopDict instanceof Dict) || loopDict.objId && visited.has(loopDict.objId)) {
+ break;
+ }
+ if (loopDict.objId) {
+ visited.put(loopDict.objId);
+ }
+ if (loopDict.has("T")) {
+ fieldName.unshift(stringToPDFString(loopDict.get("T")));
+ }
+ }
+ return fieldName.join(".");
+ }
+ _getAttachmentId(fsDict, fsRef, annotationGlobals, isSound = false) {
+ if (!(fsDict instanceof Dict)) {
+ return undefined;
+ }
+ if (!(fsRef instanceof Ref)) {
+ fsRef = FileSpec.pickPlatformItem(fsDict.get("EF"), true);
+ }
+ return fsRef instanceof Ref ? annotationGlobals.catalog.getAttachmentIdForAnnotation(fsRef, isSound) : undefined;
+ }
+ get width() {
+ return this.data.rect[2] - this.data.rect[0];
+ }
+ get height() {
+ return this.data.rect[3] - this.data.rect[1];
+ }
+}
+class AnnotationBorderStyle {
+ width = 1;
+ rawWidth = 1;
+ style = AnnotationBorderStyleType.SOLID;
+ dashArray = [3];
+ horizontalCornerRadius = 0;
+ verticalCornerRadius = 0;
+ setWidth(width, rect = [0, 0, 0, 0]) {
+ if (width instanceof Name) {
+ this.width = 0;
+ return;
+ }
+ if (typeof width === "number") {
+ if (width > 0) {
+ this.rawWidth = width;
+ const maxWidth = (rect[2] - rect[0]) / 2;
+ const maxHeight = (rect[3] - rect[1]) / 2;
+ if (maxWidth > 0 && maxHeight > 0 && (width > maxWidth || width > maxHeight)) {
+ warn(`AnnotationBorderStyle.setWidth - ignoring width: ${width}`);
+ width = 1;
+ }
+ }
+ this.width = width;
+ }
+ }
+ setStyle(style) {
+ if (!(style instanceof Name)) {
+ return;
+ }
+ switch (style.name) {
+ case "S":
+ this.style = AnnotationBorderStyleType.SOLID;
+ break;
+ case "D":
+ this.style = AnnotationBorderStyleType.DASHED;
+ break;
+ case "B":
+ this.style = AnnotationBorderStyleType.BEVELED;
+ break;
+ case "I":
+ this.style = AnnotationBorderStyleType.INSET;
+ break;
+ case "U":
+ this.style = AnnotationBorderStyleType.UNDERLINE;
+ break;
+ default:
+ break;
+ }
+ }
+ setDashArray(dashArray, forceStyle = false) {
+ if (Array.isArray(dashArray)) {
+ let isValid = true;
+ let allZeros = true;
+ for (const element of dashArray) {
+ const validNumber = +element >= 0;
+ if (!validNumber) {
+ isValid = false;
+ break;
+ } else if (element > 0) {
+ allZeros = false;
+ }
+ }
+ if (dashArray.length === 0 || isValid && !allZeros) {
+ this.dashArray = dashArray;
+ if (forceStyle) {
+ this.setStyle(Name.get("D"));
+ }
+ } else {
+ this.width = 0;
+ }
+ } else if (dashArray) {
+ this.width = 0;
+ }
+ }
+ setHorizontalCornerRadius(radius) {
+ if (Number.isInteger(radius)) {
+ this.horizontalCornerRadius = radius;
+ }
+ }
+ setVerticalCornerRadius(radius) {
+ if (Number.isInteger(radius)) {
+ this.verticalCornerRadius = radius;
+ }
+ }
+}
+class MarkupAnnotation extends Annotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict
+ } = params;
+ if (dict.has("IRT")) {
+ const rawIRT = dict.getRaw("IRT");
+ this.data.inReplyTo = rawIRT instanceof Ref ? rawIRT.toString() : null;
+ const rt = dict.get("RT");
+ this.data.replyType = rt instanceof Name ? rt.name : AnnotationReplyType.REPLY;
+ }
+ let popupRef = null;
+ if (this.data.replyType === AnnotationReplyType.GROUP) {
+ const parent = dict.get("IRT");
+ this.setTitle(parent.get("T"));
+ this.data.titleObj = this._title;
+ this.setContents(parent.get("Contents"));
+ this.data.contentsObj = this._contents;
+ if (!parent.has("CreationDate")) {
+ this.data.creationDate = null;
+ } else {
+ this.setCreationDate(parent.get("CreationDate"));
+ this.data.creationDate = this.creationDate;
+ }
+ if (!parent.has("M")) {
+ this.data.modificationDate = null;
+ } else {
+ this.setModificationDate(parent.get("M"));
+ this.data.modificationDate = this.modificationDate;
+ }
+ popupRef = parent.getRaw("Popup");
+ if (!parent.has("C")) {
+ this.data.color = null;
+ } else {
+ this.setColor(parent.getArray("C"));
+ this.data.color = this.color;
+ }
+ } else {
+ this.data.titleObj = this._title;
+ this.setCreationDate(dict.get("CreationDate"));
+ this.data.creationDate = this.creationDate;
+ popupRef = dict.getRaw("Popup");
+ if (!dict.has("C")) {
+ this.data.color = null;
+ }
+ }
+ this.data.popupRef = popupRef instanceof Ref ? popupRef.toString() : null;
+ if (dict.has("RC")) {
+ this.data.richText = XFAFactory.getRichTextAsHtml(dict.get("RC"));
+ }
+ }
+ setCreationDate(creationDate) {
+ this.creationDate = typeof creationDate === "string" ? creationDate : null;
+ }
+ _setDefaultAppearance({
+ xref,
+ extra,
+ strokeColor,
+ fillColor,
+ blendMode,
+ strokeAlpha,
+ fillAlpha,
+ pointsCallback
+ }) {
+ const bbox = this.data.rect = BBOX_INIT.slice();
+ const buffer = ["q"];
+ if (extra) {
+ buffer.push(extra);
+ }
+ if (strokeColor) {
+ buffer.push(`${strokeColor[0]} ${strokeColor[1]} ${strokeColor[2]} RG`);
+ }
+ if (fillColor) {
+ buffer.push(`${fillColor[0]} ${fillColor[1]} ${fillColor[2]} rg`);
+ }
+ const pointsArray = this.data.quadPoints || Float32Array.from([this.rectangle[0], this.rectangle[3], this.rectangle[2], this.rectangle[3], this.rectangle[0], this.rectangle[1], this.rectangle[2], this.rectangle[1]]);
+ for (let i = 0, ii = pointsArray.length; i < ii; i += 8) {
+ const points = pointsCallback(buffer, pointsArray.subarray(i, i + 8));
+ Util.rectBoundingBox(...points, bbox);
+ }
+ buffer.push("Q");
+ const formDict = new Dict(xref);
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ const appearanceStream = new StringStream(buffer.join(" "), appearanceStreamDict);
+ formDict.set("Fm0", appearanceStream);
+ const gsDict = new Dict(xref);
+ if (blendMode) {
+ gsDict.setIfName("BM", blendMode);
+ }
+ gsDict.setIfNumber("CA", strokeAlpha);
+ gsDict.setIfNumber("ca", fillAlpha);
+ const stateDict = new Dict(xref);
+ stateDict.set("GS0", gsDict);
+ const resources = new Dict(xref);
+ resources.set("ExtGState", stateDict);
+ resources.set("XObject", formDict);
+ const appearanceDict = new Dict(xref);
+ appearanceDict.set("Resources", resources);
+ appearanceDict.set("BBox", bbox);
+ this.appearance = new StringStream("/GS0 gs /Fm0 Do", appearanceDict);
+ this._streams.push(this.appearance, appearanceStream);
+ }
+ static async createNewAnnotation(xref, annotation, changes, params) {
+ const annotationRef = annotation.ref ||= xref.getNewTemporaryRef();
+ const ap = await this.createNewAppearanceStream(annotation, xref, params);
+ let annotationDict;
+ if (ap) {
+ const apRef = xref.getNewTemporaryRef();
+ annotationDict = this.createNewDict(annotation, xref, {
+ apRef
+ });
+ changes.put(apRef, {
+ data: ap
+ });
+ } else {
+ annotationDict = this.createNewDict(annotation, xref, {});
+ }
+ if (Number.isInteger(annotation.parentTreeId)) {
+ annotationDict.set("StructParent", annotation.parentTreeId);
+ }
+ changes.put(annotationRef, {
+ data: annotationDict
+ });
+ const retRef = {
+ ref: annotationRef
+ };
+ const {
+ popup
+ } = annotation;
+ if (popup) {
+ if (popup.deleted) {
+ annotationDict.delete("Popup");
+ annotationDict.delete("Contents");
+ annotationDict.delete("RC");
+ return retRef;
+ }
+ const popupRef = popup.ref ||= xref.getNewTemporaryRef();
+ popup.parent = annotationRef;
+ const popupDict = PopupAnnotation.createNewDict(popup, xref);
+ changes.put(popupRef, {
+ data: popupDict
+ });
+ annotationDict.setIfDefined("Contents", stringToAsciiOrUTF16BE(popup.contents));
+ annotationDict.set("Popup", popupRef);
+ return [retRef, {
+ ref: popupRef
+ }];
+ }
+ return retRef;
+ }
+ static async createNewPrintAnnotation(annotationGlobals, xref, annotation, params) {
+ const ap = await this.createNewAppearanceStream(annotation, xref, params);
+ const annotationDict = this.createNewDict(annotation, xref, ap ? {
+ ap
+ } : {});
+ const newAnnotation = new this.prototype.constructor({
+ dict: annotationDict,
+ xref,
+ annotationGlobals,
+ evaluatorOptions: params.evaluatorOptions
+ });
+ if (annotation.ref) {
+ newAnnotation.ref = newAnnotation.refToReplace = annotation.ref;
+ }
+ return newAnnotation;
+ }
+}
+class WidgetAnnotation extends Annotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref,
+ annotationGlobals
+ } = params;
+ const data = this.data;
+ this._needAppearances = params.needAppearances;
+ if (data.fieldName === undefined) {
+ data.fieldName = this._constructFieldName(dict);
+ }
+ if (data.actions === undefined) {
+ data.actions = collectActions(xref, dict, AnnotationActionEventType);
+ }
+ let fieldValue = getInheritableProperty({
+ dict,
+ key: "V",
+ getArray: true
+ });
+ data.fieldValue = this._decodeFormValue(fieldValue);
+ const defaultFieldValue = getInheritableProperty({
+ dict,
+ key: "DV",
+ getArray: true
+ });
+ data.defaultFieldValue = this._decodeFormValue(defaultFieldValue);
+ if (fieldValue === undefined && annotationGlobals.xfaDatasets) {
+ const path = this._title.str;
+ if (path) {
+ this._hasValueFromXFA = true;
+ data.fieldValue = fieldValue = annotationGlobals.xfaDatasets.getValue(path);
+ }
+ }
+ if (fieldValue === undefined && data.defaultFieldValue !== null) {
+ data.fieldValue = data.defaultFieldValue;
+ }
+ data.alternativeText = stringToPDFString(dict.get("TU") || "");
+ this.setDefaultAppearance(params);
+ data.hasAppearance ||= this._needAppearances && data.fieldValue !== undefined && data.fieldValue !== null;
+ const fieldType = getInheritableProperty({
+ dict,
+ key: "FT"
+ });
+ data.fieldType = fieldType instanceof Name ? fieldType.name : null;
+ const localResources = getInheritableProperty({
+ dict,
+ key: "DR"
+ });
+ const acroFormResources = annotationGlobals.acroForm.get("DR");
+ const appearanceResources = this.appearance?.dict.get("Resources");
+ this._fieldResources = {
+ localResources,
+ acroFormResources,
+ appearanceResources,
+ mergedResources: Dict.merge({
+ xref,
+ dictArray: [localResources, appearanceResources, acroFormResources],
+ mergeSubDicts: true
+ })
+ };
+ data.fieldFlags = getInheritableProperty({
+ dict,
+ key: "Ff"
+ });
+ if (!Number.isInteger(data.fieldFlags) || data.fieldFlags < 0) {
+ data.fieldFlags = 0;
+ }
+ data.password = this.hasFieldFlag(AnnotationFieldFlag.PASSWORD);
+ data.readOnly = this.hasFieldFlag(AnnotationFieldFlag.READONLY);
+ data.required = this.hasFieldFlag(AnnotationFieldFlag.REQUIRED);
+ data.hidden = this._hasFlag(data.annotationFlags, AnnotationFlag.HIDDEN) || this._hasFlag(data.annotationFlags, AnnotationFlag.NOVIEW);
+ }
+ _decodeFormValue(formValue) {
+ if (Array.isArray(formValue)) {
+ const arr = formValue.map(item => this._decodeFormValue(item)).filter(item => item !== null);
+ return arr.length > 0 ? arr : null;
+ } else if (formValue instanceof Name) {
+ return formValue.name;
+ } else if (typeof formValue === "string") {
+ return stringToPDFString(formValue);
+ }
+ return null;
+ }
+ hasFieldFlag(flag) {
+ return !!(this.data.fieldFlags & flag);
+ }
+ _isViewable(flags) {
+ return true;
+ }
+ mustBeViewed(annotationStorage, renderForms) {
+ if (renderForms) {
+ return this.viewable;
+ }
+ return super.mustBeViewed(annotationStorage, renderForms) && !this._hasFlag(this.flags, AnnotationFlag.NOVIEW);
+ }
+ getRotationMatrix(annotationStorage) {
+ let rotation = annotationStorage?.get(this.data.id)?.rotation;
+ if (rotation === undefined) {
+ rotation = this.rotation;
+ }
+ return rotation === 0 ? IDENTITY_MATRIX : getRotationMatrix(rotation, this.width, this.height);
+ }
+ getBorderAndBackgroundAppearances(annotationStorage) {
+ let rotation = annotationStorage?.get(this.data.id)?.rotation;
+ if (rotation === undefined) {
+ rotation = this.rotation;
+ }
+ if (!this.backgroundColor && !this.borderColor) {
+ return "";
+ }
+ const rect = rotation === 0 || rotation === 180 ? `0 0 ${this.width} ${this.height} re` : `0 0 ${this.height} ${this.width} re`;
+ let str = "";
+ if (this.backgroundColor) {
+ str = `${getPdfColor(this.backgroundColor, true)} ${rect} f `;
+ }
+ if (this.borderColor) {
+ const borderWidth = this.borderStyle.width || 1;
+ str += `${borderWidth} w ${getPdfColor(this.borderColor, false)} ${rect} S `;
+ }
+ return str;
+ }
+ async getOperatorList(evaluator, task, intent, annotationStorage) {
+ if (intent & RenderingIntentFlag.ANNOTATIONS_FORMS && !(this instanceof SignatureWidgetAnnotation) && !this.data.noHTML && !this.data.hasOwnCanvas) {
+ const list = this._getOperatorListNoAppearance();
+ list.separateForm = true;
+ return list;
+ }
+ if (!this._hasText) {
+ return super.getOperatorList(evaluator, task, intent, annotationStorage);
+ }
+ const content = await this._getAppearance(evaluator, task, intent, annotationStorage);
+ if (this.appearance && content === null) {
+ return super.getOperatorList(evaluator, task, intent, annotationStorage);
+ }
+ const opList = new OperatorList();
+ if (!this._defaultAppearance || content === null) {
+ return {
+ opList,
+ separateForm: false,
+ separateCanvas: false
+ };
+ }
+ const isUsingOwnCanvas = !!(this.data.hasOwnCanvas && intent & RenderingIntentFlag.DISPLAY);
+ const matrix = [1, 0, 0, 1, 0, 0];
+ const bbox = [0, 0, this.width, this.height];
+ const transform = getTransformMatrix(this.data.rect, bbox, matrix);
+ const optionalContent = this._oc;
+ if (optionalContent !== undefined) {
+ opList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
+ }
+ opList.addOp(OPS.beginAnnotation, [this.data.id, this.data.rect, transform, this.getRotationMatrix(annotationStorage), isUsingOwnCanvas]);
+ const stream = new StringStream(content);
+ await evaluator.getOperatorList({
+ stream,
+ task,
+ resources: this._fieldResources.mergedResources,
+ operatorList: opList
+ });
+ opList.addOp(OPS.endAnnotation, []);
+ if (optionalContent !== undefined) {
+ opList.addOp(OPS.endMarkedContent, []);
+ }
+ return {
+ opList,
+ separateForm: false,
+ separateCanvas: isUsingOwnCanvas
+ };
+ }
+ _getMKDict(rotation) {
+ const mk = new Dict(null);
+ if (rotation) {
+ mk.set("R", rotation);
+ }
+ mk.setIfArray("BC", getPdfColorArray(this.borderColor));
+ mk.setIfArray("BG", getPdfColorArray(this.backgroundColor));
+ return mk.size > 0 ? mk : null;
+ }
+ amendSavedDict(annotationStorage, dict) {}
+ setValue(dict, value, xref, changes) {
+ const {
+ dict: parentDict,
+ ref: parentRef
+ } = getParentToUpdate(dict, this.ref, xref);
+ if (!parentDict) {
+ dict.set("V", value);
+ } else if (!changes.has(parentRef)) {
+ const newParentDict = parentDict.clone();
+ newParentDict.set("V", value);
+ changes.put(parentRef, {
+ data: newParentDict
+ });
+ return newParentDict;
+ }
+ return null;
+ }
+ async save(evaluator, task, annotationStorage, changes) {
+ const storageEntry = annotationStorage?.get(this.data.id);
+ const flags = this._buildFlags(storageEntry?.noView, storageEntry?.noPrint);
+ let value = storageEntry?.value,
+ rotation = storageEntry?.rotation;
+ if (value === this.data.fieldValue || value === undefined) {
+ if (!this._hasValueFromXFA && rotation === undefined && flags === undefined) {
+ return;
+ }
+ value ||= this.data.fieldValue;
+ }
+ if (rotation === undefined && !this._hasValueFromXFA && Array.isArray(value) && Array.isArray(this.data.fieldValue) && isArrayEqual(value, this.data.fieldValue) && flags === undefined) {
+ return;
+ }
+ if (rotation === undefined) {
+ rotation = this.rotation;
+ }
+ let appearance = null;
+ if (!this._needAppearances) {
+ appearance = await this._getAppearance(evaluator, task, RenderingIntentFlag.SAVE, annotationStorage);
+ if (appearance === null && flags === undefined) {
+ return;
+ }
+ } else {}
+ let needAppearances = false;
+ if (appearance?.needAppearances) {
+ needAppearances = true;
+ appearance = null;
+ }
+ const {
+ xref
+ } = evaluator;
+ const originalDict = xref.fetchIfRef(this.ref);
+ if (!(originalDict instanceof Dict)) {
+ return;
+ }
+ const dict = new Dict(xref);
+ for (const [key, rawVal] of originalDict.getRawEntries()) {
+ if (key !== "AP") {
+ dict.set(key, rawVal);
+ }
+ }
+ if (flags !== undefined) {
+ dict.set("F", flags);
+ if (appearance === null && !needAppearances) {
+ const ap = originalDict.getRaw("AP");
+ if (ap) {
+ dict.set("AP", ap);
+ }
+ }
+ }
+ const xfa = {
+ path: this.data.fieldName,
+ value
+ };
+ const newParentDict = this.setValue(dict, Array.isArray(value) ? value.map(stringToAsciiOrUTF16BE) : stringToAsciiOrUTF16BE(value), xref, changes);
+ this.amendSavedDict(annotationStorage, newParentDict || dict);
+ const maybeMK = this._getMKDict(rotation);
+ if (maybeMK) {
+ dict.set("MK", maybeMK);
+ }
+ changes.put(this.ref, {
+ data: dict,
+ xfa,
+ needAppearances
+ });
+ if (appearance !== null) {
+ const newRef = xref.getNewTemporaryRef();
+ const AP = new Dict(xref);
+ dict.set("AP", AP);
+ AP.set("N", newRef);
+ const resources = this._getSaveFieldResources(xref),
+ appearanceDict = new Dict(xref);
+ appearanceDict.setIfName("Subtype", "Form");
+ appearanceDict.set("Resources", resources);
+ const bbox = rotation % 180 === 0 ? [0, 0, this.width, this.height] : [0, 0, this.height, this.width];
+ appearanceDict.set("BBox", bbox);
+ const appearanceStream = new StringStream(appearance, appearanceDict);
+ const rotationMatrix = this.getRotationMatrix(annotationStorage);
+ if (rotationMatrix !== IDENTITY_MATRIX) {
+ appearanceDict.set("Matrix", rotationMatrix);
+ }
+ changes.put(newRef, {
+ data: appearanceStream,
+ xfa: null,
+ needAppearances: false
+ });
+ }
+ dict.set("M", `D:${getModificationDate()}`);
+ }
+ async _getAppearance(evaluator, task, intent, annotationStorage) {
+ if (this.data.password) {
+ return null;
+ }
+ const storageEntry = annotationStorage?.get(this.data.id);
+ let value, rotation;
+ if (storageEntry) {
+ value = storageEntry.formattedValue || storageEntry.value;
+ rotation = storageEntry.rotation;
+ }
+ if (rotation === undefined && value === undefined && !this._needAppearances) {
+ if (!this._hasValueFromXFA || this.appearance) {
+ return null;
+ }
+ }
+ const colors = this.getBorderAndBackgroundAppearances(annotationStorage);
+ if (value === undefined) {
+ value = this.data.fieldValue;
+ if (!value) {
+ return `/Tx BMC q ${colors}Q EMC`;
+ }
+ }
+ if (Array.isArray(value) && value.length === 1) {
+ value = value[0];
+ }
+ assert(typeof value === "string", "Expected `value` to be a string.");
+ value = value.trimEnd();
+ if (this.data.combo) {
+ const option = this.data.options.find(({
+ exportValue
+ }) => value === exportValue);
+ value = option?.displayValue || value;
+ }
+ if (value === "") {
+ return `/Tx BMC q ${colors}Q EMC`;
+ }
+ if (rotation === undefined) {
+ rotation = this.rotation;
+ }
+ let lineCount = -1;
+ let lines;
+ if (this.data.multiLine) {
+ lines = value.split(/\r\n?|\n/).map(line => line.normalize("NFC"));
+ lineCount = lines.length;
+ } else {
+ lines = [value.replace(/\r\n?|\n/, "").normalize("NFC")];
+ }
+ const defaultPadding = 1;
+ const defaultHPadding = 2;
+ let {
+ width: totalWidth,
+ height: totalHeight
+ } = this;
+ if (rotation === 90 || rotation === 270) {
+ [totalWidth, totalHeight] = [totalHeight, totalWidth];
+ }
+ if (!this._defaultAppearance) {
+ this.data.defaultAppearanceData = parseDefaultAppearance(this._defaultAppearance = "/Helvetica 0 Tf 0 g");
+ }
+ let font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources);
+ let defaultAppearance, fontSize, lineHeight;
+ const encodedLines = [];
+ let encodingError = false;
+ for (const line of lines) {
+ const encodedString = font.encodeString(line);
+ if (encodedString.length > 1) {
+ encodingError = true;
+ }
+ encodedLines.push(encodedString.join(""));
+ }
+ if (encodingError && intent & RenderingIntentFlag.SAVE) {
+ return {
+ needAppearances: true
+ };
+ }
+ if (encodingError && this._isOffscreenCanvasSupported) {
+ const fontFamily = this.data.comb ? "monospace" : "sans-serif";
+ const fakeUnicodeFont = new FakeUnicodeFont(evaluator.xref, fontFamily);
+ const resources = fakeUnicodeFont.createFontResources(lines.join(""));
+ const newFont = resources.getRaw("Font");
+ if (this._fieldResources.mergedResources.has("Font")) {
+ const oldFont = this._fieldResources.mergedResources.get("Font");
+ for (const [key, rawVal] of newFont.getRawEntries()) {
+ oldFont.set(key, rawVal);
+ }
+ } else {
+ this._fieldResources.mergedResources.set("Font", newFont);
+ }
+ const fontName = fakeUnicodeFont.fontName.name;
+ font = await WidgetAnnotation._getFontData(evaluator, task, {
+ fontName,
+ fontSize: 0
+ }, resources);
+ for (let i = 0, ii = encodedLines.length; i < ii; i++) {
+ encodedLines[i] = stringToUTF16String(lines[i]);
+ }
+ const savedDefaultAppearance = Object.assign(Object.create(null), this.data.defaultAppearanceData);
+ this.data.defaultAppearanceData.fontSize = 0;
+ this.data.defaultAppearanceData.fontName = fontName;
+ [defaultAppearance, fontSize, lineHeight] = this._computeFontSize(totalHeight - 2 * defaultPadding, totalWidth - 2 * defaultHPadding, value, font, lineCount);
+ this.data.defaultAppearanceData = savedDefaultAppearance;
+ } else {
+ if (!this._isOffscreenCanvasSupported) {
+ warn("_getAppearance: OffscreenCanvas is not supported, annotation may not render correctly.");
+ }
+ [defaultAppearance, fontSize, lineHeight] = this._computeFontSize(totalHeight - 2 * defaultPadding, totalWidth - 2 * defaultHPadding, value, font, lineCount);
+ }
+ let descent = font.descent;
+ if (isNaN(descent)) {
+ descent = BASELINE_FACTOR * lineHeight;
+ } else {
+ descent = Math.max(BASELINE_FACTOR * lineHeight, Math.abs(descent) * fontSize);
+ }
+ const defaultVPadding = Math.min(Math.floor((totalHeight - fontSize) / 2), defaultPadding);
+ const alignment = this.data.textAlignment;
+ let {
+ ascent: fontAscent,
+ descent: fontDescent
+ } = font;
+ if (isNaN(fontAscent) || isNaN(fontDescent) || !fontAscent && !fontDescent) {
+ fontAscent = (/* inlined export .LINE_FACTOR */1.35) - (/* inlined export .LINE_DESCENT_FACTOR */0.35);
+ fontDescent = (/* inlined export .LINE_DESCENT_FACTOR */0.35);
+ } else {
+ fontDescent = Math.abs(fontDescent);
+ }
+ const vShift = (totalHeight - (fontAscent + fontDescent) * fontSize) / 2 + fontDescent * fontSize;
+ if (this.data.multiLine) {
+ return this._getMultilineAppearance(defaultAppearance, encodedLines, font, fontSize, totalWidth, totalHeight, alignment, defaultHPadding, defaultVPadding, descent, lineHeight, annotationStorage);
+ }
+ if (this.data.comb) {
+ return this._getCombAppearance(defaultAppearance, font, encodedLines[0], fontSize, totalWidth, vShift, alignment, bidi(lines[0]).dir === "rtl", annotationStorage);
+ }
+ const bottomPadding = vShift;
+ if (alignment === 0 || alignment > 2) {
+ return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 ${numberToString(defaultHPadding)} ${numberToString(bottomPadding)} Tm (${escapeString(encodedLines[0])}) Tj` + " ET Q EMC";
+ }
+ const prevInfo = {
+ shift: 0
+ };
+ const renderedText = this._renderText(encodedLines[0], font, fontSize, totalWidth, alignment, prevInfo, defaultHPadding, bottomPadding);
+ return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 0 0 Tm ${renderedText}` + " ET Q EMC";
+ }
+ static async _getFontData(evaluator, task, appearanceData, resources) {
+ const operatorList = new OperatorList();
+ const initialState = {
+ font: null,
+ clone() {
+ return this;
+ }
+ };
+ const {
+ fontName,
+ fontSize
+ } = appearanceData;
+ await evaluator.handleSetFont(resources, [fontName && Name.get(fontName), fontSize], null, operatorList, task, initialState, null);
+ return initialState.font;
+ }
+ _getTextWidth(text, font) {
+ return Math.sumPrecise(font.charsToGlyphs(text).map(g => g.width)) / 1000;
+ }
+ _computeFontSize(height, width, text, font, lineCount) {
+ let {
+ fontSize
+ } = this.data.defaultAppearanceData;
+ let lineHeight = (fontSize || 12) * (/* inlined export .LINE_FACTOR */1.35),
+ numberOfLines = Math.round(height / lineHeight);
+ if (!fontSize) {
+ const roundWithTwoDigits = x => Math.floor(x * 100) / 100;
+ if (lineCount === -1) {
+ const textWidth = this._getTextWidth(text, font);
+ fontSize = roundWithTwoDigits(Math.min(height / (/* inlined export .LINE_FACTOR */1.35), width / textWidth));
+ numberOfLines = 1;
+ } else {
+ const lines = text.split(/\r\n?|\n/);
+ const cachedLines = [];
+ for (const line of lines) {
+ const encoded = font.encodeString(line).join("");
+ const glyphs = font.charsToGlyphs(encoded);
+ const positions = font.getCharPositions(encoded);
+ cachedLines.push({
+ line: encoded,
+ glyphs,
+ positions
+ });
+ }
+ const isTooBig = fsize => {
+ let totalHeight = 0;
+ for (const cache of cachedLines) {
+ const chunks = this._splitLine(null, font, fsize, width, cache);
+ totalHeight += chunks.length * fsize;
+ if (totalHeight > height) {
+ return true;
+ }
+ }
+ return false;
+ };
+ numberOfLines = Math.max(numberOfLines, lineCount);
+ while (true) {
+ lineHeight = height / numberOfLines;
+ fontSize = roundWithTwoDigits(lineHeight / (/* inlined export .LINE_FACTOR */1.35));
+ if (isTooBig(fontSize)) {
+ numberOfLines++;
+ continue;
+ }
+ break;
+ }
+ }
+ const {
+ fontName,
+ fontColor
+ } = this.data.defaultAppearanceData;
+ this._defaultAppearance = createDefaultAppearance({
+ fontSize,
+ fontName,
+ fontColor
+ });
+ }
+ return [this._defaultAppearance, fontSize, height / numberOfLines];
+ }
+ _renderText(text, font, fontSize, totalWidth, alignment, prevInfo, hPadding, vPadding) {
+ let shift;
+ if (alignment === 1) {
+ const width = this._getTextWidth(text, font) * fontSize;
+ shift = (totalWidth - width) / 2;
+ } else if (alignment === 2) {
+ const width = this._getTextWidth(text, font) * fontSize;
+ shift = totalWidth - width - hPadding;
+ } else {
+ shift = hPadding;
+ }
+ const shiftStr = numberToString(shift - prevInfo.shift);
+ prevInfo.shift = shift;
+ vPadding = numberToString(vPadding);
+ return `${shiftStr} ${vPadding} Td (${escapeString(text)}) Tj`;
+ }
+ _getSaveFieldResources(xref) {
+ const {
+ localResources,
+ appearanceResources,
+ acroFormResources
+ } = this._fieldResources;
+ const fontName = this.data.defaultAppearanceData?.fontName;
+ if (!fontName) {
+ return localResources || Dict.empty;
+ }
+ for (const resources of [localResources, appearanceResources]) {
+ if (resources instanceof Dict) {
+ const localFont = resources.get("Font");
+ if (localFont instanceof Dict && localFont.has(fontName)) {
+ return resources;
+ }
+ }
+ }
+ if (acroFormResources instanceof Dict) {
+ const acroFormFont = acroFormResources.get("Font");
+ if (acroFormFont instanceof Dict && acroFormFont.has(fontName)) {
+ const subFontDict = new Dict(xref);
+ subFontDict.set(fontName, acroFormFont.getRaw(fontName));
+ const subResourcesDict = new Dict(xref);
+ subResourcesDict.set("Font", subFontDict);
+ return Dict.merge({
+ xref,
+ dictArray: [subResourcesDict, localResources],
+ mergeSubDicts: true
+ });
+ }
+ }
+ return localResources || Dict.empty;
+ }
+ getFieldObject() {
+ return null;
+ }
+}
+class TextWidgetAnnotation extends WidgetAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict
+ } = params;
+ if (dict.has("PMD")) {
+ this.flags |= AnnotationFlag.HIDDEN;
+ this.data.hidden = true;
+ warn("Barcodes are not supported");
+ }
+ this.data.hasOwnCanvas = this.data.readOnly && !this.data.noHTML;
+ this._hasText = true;
+ if (typeof this.data.fieldValue !== "string") {
+ this.data.fieldValue = "";
+ }
+ let alignment = getInheritableProperty({
+ dict,
+ key: "Q"
+ });
+ if (!Number.isInteger(alignment) || alignment < 0 || alignment > 2) {
+ alignment = null;
+ }
+ this.data.textAlignment = alignment;
+ let maximumLength = getInheritableProperty({
+ dict,
+ key: "MaxLen"
+ });
+ if (!Number.isInteger(maximumLength) || maximumLength < 0) {
+ maximumLength = 0;
+ }
+ this.data.maxLen = maximumLength;
+ this.data.multiLine = this.hasFieldFlag(AnnotationFieldFlag.MULTILINE);
+ this.data.comb = this.hasFieldFlag(AnnotationFieldFlag.COMB) && !this.data.multiLine && !this.data.password && !this.hasFieldFlag(AnnotationFieldFlag.FILESELECT) && this.data.maxLen !== 0;
+ this.data.doNotScroll = this.hasFieldFlag(AnnotationFieldFlag.DONOTSCROLL);
+ const {
+ actions
+ } = this.data;
+ if (!actions) {
+ return;
+ }
+ const AFDateTime = /^AF(Date|Time)_(?:Keystroke|Format)(?:Ex)?\(['"]?([^'"]+)['"]?\);$/;
+ let canUseHTMLDateTime = false;
+ const aFormat = actions.get("Format"),
+ aKeystroke = actions.get("Keystroke");
+ if (aFormat?.length === 1 && aKeystroke?.length === 1 && AFDateTime.test(aFormat[0]) && AFDateTime.test(aKeystroke[0]) || aFormat?.length === 0 && aKeystroke?.length === 1 && AFDateTime.test(aKeystroke[0]) || aKeystroke?.length === 0 && aFormat?.length === 1 && AFDateTime.test(aFormat[0])) {
+ canUseHTMLDateTime = true;
+ }
+ const actionsToVisit = [];
+ if (aFormat) {
+ actionsToVisit.push(...aFormat);
+ }
+ if (aKeystroke) {
+ actionsToVisit.push(...aKeystroke);
+ }
+ if (canUseHTMLDateTime) {
+ actions.delete("Keystroke");
+ actions.set("Format", actionsToVisit);
+ }
+ for (const formatAction of actionsToVisit) {
+ const m = formatAction.match(AFDateTime);
+ if (!m) {
+ continue;
+ }
+ const isDate = m[1] === "Date";
+ let format = m[2];
+ const num = parseInt(format, 10);
+ if (!isNaN(num) && Math.floor(Math.log10(num)) + 1 === m[2].length) {
+ format = (isDate ? DateFormats : TimeFormats)[num] ?? format;
+ }
+ this.data.datetimeFormat = format;
+ if (!canUseHTMLDateTime) {
+ break;
+ }
+ if (isDate) {
+ if (/HH|MM|ss|h/.test(format)) {
+ this.data.datetimeType = "datetime-local";
+ this.data.timeStep = /ss/.test(format) ? 1 : 60;
+ } else {
+ this.data.datetimeType = "date";
+ }
+ break;
+ }
+ this.data.datetimeType = "time";
+ this.data.timeStep = /ss/.test(format) ? 1 : 60;
+ break;
+ }
+ }
+ get hasTextContent() {
+ return !!this.appearance && !this._needAppearances;
+ }
+ _getCombAppearance(defaultAppearance, font, text, fontSize, width, vShift, alignment, isRTL, annotationStorage) {
+ const combWidth = width / this.data.maxLen;
+ const colors = this.getBorderAndBackgroundAppearances(annotationStorage);
+ const cells = font.getCharPositions(text).map(([start, end]) => {
+ const glyph = text.substring(start, end);
+ return {
+ glyph,
+ width: this._getTextWidth(glyph, font) * fontSize
+ };
+ });
+ if (isRTL) {
+ cells.reverse();
+ }
+ const textWidth = combWidth * cells.length;
+ let hShift = 0;
+ if (alignment === 1) {
+ hShift += Math.floor((width - textWidth) / (2 * combWidth)) * combWidth;
+ } else if (alignment === 2) {
+ hShift += width - textWidth;
+ }
+ const buf = [];
+ let previousWidth = 0;
+ for (let i = 0, ii = cells.length; i < ii; i++) {
+ const {
+ glyph,
+ width: glyphWidth
+ } = cells[i];
+ const shift = i === 0 ? (combWidth - glyphWidth) / 2 : combWidth + (previousWidth - glyphWidth) / 2;
+ buf.push(`${numberToString(shift)} 0 Td (${escapeString(glyph)}) Tj`);
+ previousWidth = glyphWidth;
+ }
+ const renderedComb = buf.join(" ");
+ return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 ${numberToString(hShift)} ${numberToString(vShift)} Tm ${renderedComb}` + " ET Q EMC";
+ }
+ _getMultilineAppearance(defaultAppearance, lines, font, fontSize, width, height, alignment, hPadding, vPadding, descent, lineHeight, annotationStorage) {
+ const buf = [];
+ const totalWidth = width - 2 * hPadding;
+ const prevInfo = {
+ shift: 0
+ };
+ for (let i = 0, ii = lines.length; i < ii; i++) {
+ const line = lines[i];
+ const chunks = this._splitLine(line, font, fontSize, totalWidth);
+ for (let j = 0, jj = chunks.length; j < jj; j++) {
+ const chunk = chunks[j];
+ const vShift = i === 0 && j === 0 ? -vPadding - (lineHeight - descent) : -lineHeight;
+ buf.push(this._renderText(chunk, font, fontSize, width, alignment, prevInfo, hPadding, vShift));
+ }
+ }
+ const colors = this.getBorderAndBackgroundAppearances(annotationStorage);
+ const renderedText = buf.join("\n");
+ return `/Tx BMC q ${colors}BT ` + defaultAppearance + ` 1 0 0 1 0 ${numberToString(height)} Tm ${renderedText}` + " ET Q EMC";
+ }
+ _splitLine(line, font, fontSize, width, cache = {}) {
+ line = cache.line || line;
+ const glyphs = cache.glyphs || font.charsToGlyphs(line);
+ if (glyphs.length <= 1) {
+ return [line];
+ }
+ const positions = cache.positions || font.getCharPositions(line);
+ const scale = fontSize / 1000;
+ const chunks = [];
+ let lastSpacePosInStringStart = -1,
+ lastSpacePosInStringEnd = -1,
+ lastSpacePos = -1,
+ startChunk = 0,
+ currentWidth = 0;
+ for (let i = 0, ii = glyphs.length; i < ii; i++) {
+ const [start, end] = positions[i];
+ const glyph = glyphs[i];
+ const glyphWidth = glyph.width * scale;
+ if (glyph.unicode === " ") {
+ if (currentWidth + glyphWidth > width) {
+ chunks.push(line.substring(startChunk, start));
+ startChunk = start;
+ currentWidth = glyphWidth;
+ lastSpacePosInStringStart = -1;
+ lastSpacePos = -1;
+ } else {
+ currentWidth += glyphWidth;
+ lastSpacePosInStringStart = start;
+ lastSpacePosInStringEnd = end;
+ lastSpacePos = i;
+ }
+ } else if (currentWidth + glyphWidth > width) {
+ if (lastSpacePosInStringStart !== -1) {
+ chunks.push(line.substring(startChunk, lastSpacePosInStringEnd));
+ startChunk = lastSpacePosInStringEnd;
+ i = lastSpacePos + 1;
+ lastSpacePosInStringStart = -1;
+ currentWidth = 0;
+ } else {
+ chunks.push(line.substring(startChunk, start));
+ startChunk = start;
+ currentWidth = glyphWidth;
+ }
+ } else {
+ currentWidth += glyphWidth;
+ }
+ }
+ if (startChunk < line.length) {
+ chunks.push(line.substring(startChunk));
+ }
+ return chunks;
+ }
+ async extractTextContent(evaluator, task, viewBox) {
+ await super.extractTextContent(evaluator, task, viewBox);
+ const text = this.data.textContent;
+ if (!text) {
+ return;
+ }
+ const allText = text.join("\n");
+ if (allText === this.data.fieldValue) {
+ return;
+ }
+ const regex = allText.replaceAll(/([.*+?^${}()|[\]\\])|(\s+)/g, (_m, p1) => p1 ? `\\${p1}` : "\\s+");
+ if (new RegExp(`^\\s*${regex}\\s*$`).test(this.data.fieldValue)) {
+ this.data.textContent = this.data.fieldValue.split("\n");
+ }
+ }
+ getFieldObject() {
+ return {
+ id: this.data.id,
+ value: this.data.fieldValue,
+ defaultValue: this.data.defaultFieldValue || "",
+ multiline: this.data.multiLine,
+ password: this.data.password,
+ charLimit: this.data.maxLen,
+ comb: this.data.comb,
+ editable: !this.data.readOnly,
+ hidden: this.data.hidden,
+ name: this.data.fieldName,
+ rect: this.data.rect,
+ actions: this.data.actions,
+ page: this.data.pageIndex,
+ strokeColor: this.data.borderColor,
+ fillColor: this.data.backgroundColor,
+ rotation: this.rotation,
+ datetimeFormat: this.data.datetimeFormat,
+ hasDatetimeHTML: !!this.data.datetimeType,
+ type: "text"
+ };
+ }
+}
+class ButtonWidgetAnnotation extends WidgetAnnotation {
+ constructor(params) {
+ super(params);
+ this.checkedAppearance = null;
+ this.uncheckedAppearance = null;
+ const isRadio = this.hasFieldFlag(AnnotationFieldFlag.RADIO),
+ isPushButton = this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
+ this.data.checkBox = !isRadio && !isPushButton;
+ this.data.radioButton = isRadio && !isPushButton;
+ this.data.pushButton = isPushButton;
+ this.data.isTooltipOnly = false;
+ this.data.hasOwnCanvas = true;
+ this.data.noHTML = false;
+ if (this.data.checkBox) {
+ this._processCheckBox(params);
+ } else if (this.data.radioButton) {
+ this._processRadioButton(params);
+ } else if (this.data.pushButton) {
+ this._processPushButton(params);
+ } else {
+ warn("Invalid field flags for button widget annotation");
+ }
+ }
+ get _ownCanvasRequiresForms() {
+ return this.data.checkBox || this.data.radioButton;
+ }
+ #getOperatorListForAppearance(evaluator, task, intent, annotationStorage, rotation, appearance) {
+ if (!appearance) {
+ return this._getOperatorListNoAppearance();
+ }
+ const savedAppearance = this.appearance;
+ const savedMatrix = lookupMatrix(appearance.dict.getArray("Matrix"), IDENTITY_MATRIX);
+ if (rotation) {
+ appearance.dict.set("Matrix", this.getRotationMatrix(annotationStorage));
+ }
+ this.appearance = appearance;
+ const operatorList = super.getOperatorList(evaluator, task, intent, annotationStorage);
+ this.appearance = savedAppearance;
+ appearance.dict.set("Matrix", savedMatrix);
+ return operatorList;
+ }
+ async getOperatorList(evaluator, task, intent, annotationStorage) {
+ if (this.data.pushButton) {
+ return super.getOperatorList(evaluator, task, intent, false, annotationStorage);
+ }
+ if (intent & RenderingIntentFlag.DISPLAY && intent & RenderingIntentFlag.ANNOTATIONS_FORMS && (this.data.checkBox || this.data.radioButton)) {
+ const setCanvasName = (operatorList, name) => {
+ const index = operatorList.fnArray.indexOf(OPS.beginAnnotation);
+ if (index !== -1) {
+ operatorList.argsArray[index].push(name);
+ }
+ };
+ const checked = await this.#getOperatorListForAppearance(evaluator, task, intent, annotationStorage, null, this.checkedAppearance);
+ setCanvasName(checked.opList, "checked");
+ const unchecked = await this.#getOperatorListForAppearance(evaluator, task, intent, annotationStorage, null, this.uncheckedAppearance);
+ setCanvasName(unchecked.opList, "unchecked");
+ checked.opList.addOpList(unchecked.opList);
+ checked.separateForm ||= unchecked.separateForm;
+ checked.separateCanvas ||= unchecked.separateCanvas;
+ return checked;
+ }
+ let value = null;
+ let rotation = null;
+ if (annotationStorage) {
+ const storageEntry = annotationStorage.get(this.data.id);
+ value = storageEntry ? storageEntry.value : null;
+ rotation = storageEntry ? storageEntry.rotation : null;
+ }
+ if (value === null && this.appearance) {
+ return super.getOperatorList(evaluator, task, intent, annotationStorage);
+ }
+ value ??= this.data.checkBox ? this.data.fieldValue === this.data.exportValue : this.data.fieldValue === this.data.buttonValue;
+ return this.#getOperatorListForAppearance(evaluator, task, intent, annotationStorage, rotation, value ? this.checkedAppearance : this.uncheckedAppearance);
+ }
+ async save(evaluator, task, annotationStorage, changes) {
+ if (this.data.checkBox) {
+ this._saveCheckbox(evaluator, task, annotationStorage, changes);
+ return;
+ }
+ if (this.data.radioButton) {
+ this._saveRadioButton(evaluator, task, annotationStorage, changes);
+ }
+ }
+ async _saveCheckbox(evaluator, task, annotationStorage, changes) {
+ if (!annotationStorage) {
+ return;
+ }
+ const storageEntry = annotationStorage.get(this.data.id);
+ const flags = this._buildFlags(storageEntry?.noView, storageEntry?.noPrint);
+ let rotation = storageEntry?.rotation,
+ value = storageEntry?.value;
+ if (rotation === undefined && flags === undefined) {
+ if (value === undefined) {
+ return;
+ }
+ const defaultValue = this.data.fieldValue === this.data.exportValue;
+ if (defaultValue === value) {
+ return;
+ }
+ }
+ let dict = evaluator.xref.fetchIfRef(this.ref);
+ if (!(dict instanceof Dict)) {
+ return;
+ }
+ dict = dict.clone();
+ if (rotation === undefined) {
+ rotation = this.rotation;
+ }
+ if (value === undefined) {
+ value = this.data.fieldValue === this.data.exportValue;
+ }
+ const xfa = {
+ path: this.data.fieldName,
+ value: value ? this.data.exportValue : ""
+ };
+ const name = Name.get(value ? this._onStateName : "Off");
+ this.setValue(dict, name, evaluator.xref, changes);
+ dict.set("AS", name);
+ dict.set("M", `D:${getModificationDate()}`);
+ if (flags !== undefined) {
+ dict.set("F", flags);
+ }
+ const maybeMK = this._getMKDict(rotation);
+ if (maybeMK) {
+ dict.set("MK", maybeMK);
+ }
+ changes.put(this.ref, {
+ data: dict,
+ xfa,
+ needAppearances: false
+ });
+ }
+ async _saveRadioButton(evaluator, task, annotationStorage, changes) {
+ if (!annotationStorage) {
+ return;
+ }
+ const storageEntry = annotationStorage.get(this.data.id);
+ const flags = this._buildFlags(storageEntry?.noView, storageEntry?.noPrint);
+ let rotation = storageEntry?.rotation,
+ value = storageEntry?.value;
+ if (rotation === undefined && flags === undefined) {
+ if (value === undefined) {
+ return;
+ }
+ const defaultValue = this.data.fieldValue === this.data.buttonValue;
+ if (defaultValue === value) {
+ return;
+ }
+ }
+ let dict = evaluator.xref.fetchIfRef(this.ref);
+ if (!(dict instanceof Dict)) {
+ return;
+ }
+ dict = dict.clone();
+ if (value === undefined) {
+ value = this.data.fieldValue === this.data.buttonValue;
+ }
+ if (rotation === undefined) {
+ rotation = this.rotation;
+ }
+ const xfa = {
+ path: this.data.fieldName,
+ value: value ? this.data.buttonValue : ""
+ };
+ const name = Name.get(value ? this._onStateName : "Off");
+ if (value) {
+ this.setValue(dict, name, evaluator.xref, changes);
+ }
+ dict.set("AS", name);
+ dict.set("M", `D:${getModificationDate()}`);
+ if (flags !== undefined) {
+ dict.set("F", flags);
+ }
+ const maybeMK = this._getMKDict(rotation);
+ if (maybeMK) {
+ dict.set("MK", maybeMK);
+ }
+ changes.put(this.ref, {
+ data: dict,
+ xfa,
+ needAppearances: false
+ });
+ }
+ _getDefaultCheckedAppearance(params, type) {
+ const {
+ width,
+ height
+ } = this;
+ const bbox = [0, 0, width, height];
+ const FONT_RATIO = 0.8;
+ const fontSize = Math.min(width, height) * FONT_RATIO;
+ let metrics, char;
+ if (type === "check") {
+ metrics = {
+ width: 0.755 * fontSize,
+ height: 0.705 * fontSize
+ };
+ char = "\x33";
+ } else if (type === "disc") {
+ metrics = {
+ width: 0.791 * fontSize,
+ height: 0.705 * fontSize
+ };
+ char = "\x6C";
+ } else {
+ unreachable(`_getDefaultCheckedAppearance - unsupported type: ${type}`);
+ }
+ const xShift = numberToString((width - metrics.width) / 2);
+ const yShift = numberToString((height - metrics.height) / 2);
+ const appearance = `q BT /PdfJsZaDb ${fontSize} Tf 0 g ${xShift} ${yShift} Td (${char}) Tj ET Q`;
+ const appearanceStreamDict = new Dict(params.xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", bbox);
+ appearanceStreamDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
+ appearanceStreamDict.set("Length", appearance.length);
+ const resources = new Dict(params.xref);
+ const font = new Dict(params.xref);
+ font.set("PdfJsZaDb", this.fallbackFontDict);
+ resources.set("Font", font);
+ appearanceStreamDict.set("Resources", resources);
+ this.checkedAppearance = new StringStream(appearance, appearanceStreamDict);
+ this._streams.push(this.checkedAppearance);
+ }
+ _getOnStateName(dict) {
+ const appearanceStates = dict.get("AP");
+ if (!(appearanceStates instanceof Dict)) {
+ return null;
+ }
+ const normalAppearance = appearanceStates.get("N");
+ if (!(normalAppearance instanceof Dict)) {
+ return null;
+ }
+ for (const key of normalAppearance.getKeys()) {
+ if (key !== "Off") {
+ return key;
+ }
+ }
+ return null;
+ }
+ _getExportValueForOptIndex(index, opt, xref) {
+ if (Number.isInteger(index) && index >= 0 && index < opt.length) {
+ const value = this._decodeFormValue(xref.fetchIfRef(opt[index]));
+ if (typeof value === "string") {
+ return value;
+ }
+ }
+ return null;
+ }
+ _getOptInfo(dict, onState, opt, xref) {
+ if (!Array.isArray(opt)) {
+ return null;
+ }
+ const stateToIndex = new Map();
+ let currentIndex = null;
+ const fieldParent = dict.get("Parent");
+ const kids = fieldParent instanceof Dict ? fieldParent.get("Kids") : null;
+ if (Array.isArray(kids)) {
+ for (let i = 0, ii = Math.min(kids.length, opt.length); i < ii; i++) {
+ const kid = kids[i];
+ if (kid instanceof Ref && isRefsEqual(kid, this.ref)) {
+ currentIndex = i;
+ }
+ const kidDict = xref.fetchIfRef(kid);
+ if (!(kidDict instanceof Dict)) {
+ continue;
+ }
+ if (kidDict === dict) {
+ currentIndex = i;
+ }
+ const kidOnState = this._getOnStateName(kidDict);
+ if (typeof kidOnState === "string" && !stateToIndex.has(kidOnState)) {
+ stateToIndex.set(kidOnState, i);
+ }
+ }
+ } else if (opt.length === 1 && typeof onState === "string") {
+ currentIndex = 0;
+ stateToIndex.set(onState, 0);
+ }
+ return {
+ currentIndex,
+ opt,
+ stateToIndex
+ };
+ }
+ _getExportValue(state, optInfo, xref) {
+ if (!optInfo || typeof state !== "string" || state === "Off") {
+ return state;
+ }
+ if (state === this._onStateName) {
+ const exportValue = this._getExportValueForOptIndex(optInfo.currentIndex, optInfo.opt, xref);
+ if (exportValue !== null) {
+ return exportValue;
+ }
+ }
+ if (optInfo.stateToIndex.has(state)) {
+ const exportValue = this._getExportValueForOptIndex(optInfo.stateToIndex.get(state), optInfo.opt, xref);
+ if (exportValue !== null) {
+ return exportValue;
+ }
+ }
+ const index = parseInt(state, 10);
+ if (Number.isInteger(index) && String(index) === state) {
+ return this._getExportValueForOptIndex(index, optInfo.opt, xref) || state;
+ }
+ return state;
+ }
+ _processCheckBox(params) {
+ const customAppearance = params.dict.get("AP");
+ let normalAppearance = customAppearance instanceof Dict ? customAppearance.get("N") : null;
+ if (!(normalAppearance instanceof Dict)) {
+ normalAppearance = null;
+ }
+ const asValue = this._decodeFormValue(params.dict.get("AS"));
+ if (typeof asValue === "string") {
+ this.data.fieldValue = asValue;
+ }
+ const yes = this.data.fieldValue !== null && this.data.fieldValue !== "Off" ? this.data.fieldValue : "Yes";
+ const exportValues = normalAppearance ? [...normalAppearance.getKeys()] : [];
+ if (exportValues.length === 0) {
+ exportValues.push("Off", yes);
+ } else if (exportValues.length === 1) {
+ if (exportValues[0] === "Off") {
+ exportValues.push(yes);
+ } else {
+ exportValues.unshift("Off");
+ }
+ } else if (exportValues.includes(yes)) {
+ exportValues.length = 0;
+ exportValues.push("Off", yes);
+ } else {
+ const otherYes = exportValues.find(v => v !== "Off");
+ exportValues.length = 0;
+ exportValues.push("Off", otherYes);
+ }
+ const onState = exportValues[1];
+ this._onStateName = onState;
+ const opt = getInheritableProperty({
+ dict: params.dict,
+ key: "Opt"
+ });
+ const optInfo = this._getOptInfo(params.dict, onState, opt, params.xref);
+ this.data.exportValue = this._getExportValue(onState, optInfo, params.xref);
+ if (!exportValues.includes(this.data.fieldValue) && this.data.fieldValue !== this.data.exportValue) {
+ this.data.fieldValue = "Off";
+ }
+ this.data.fieldValue = this._getExportValue(this.data.fieldValue, optInfo, params.xref);
+ this.data.defaultFieldValue = this._getExportValue(this.data.defaultFieldValue, optInfo, params.xref);
+ const checkedAppearance = normalAppearance?.get(onState);
+ this.checkedAppearance = checkedAppearance instanceof BaseStream ? checkedAppearance : null;
+ const uncheckedAppearance = normalAppearance?.get("Off");
+ this.uncheckedAppearance = uncheckedAppearance instanceof BaseStream ? uncheckedAppearance : null;
+ if (this.checkedAppearance) {
+ this._streams.push(this.checkedAppearance);
+ } else {
+ this._getDefaultCheckedAppearance(params, "check");
+ }
+ if (this.uncheckedAppearance) {
+ this._streams.push(this.uncheckedAppearance);
+ }
+ this._fallbackFontDict = this.fallbackFontDict;
+ if (this.data.defaultFieldValue === null) {
+ this.data.defaultFieldValue = "Off";
+ }
+ }
+ _processRadioButton(params) {
+ this.data.buttonValue = null;
+ const fieldParent = params.dict.get("Parent");
+ if (fieldParent instanceof Dict) {
+ this.parent = params.dict.getRaw("Parent");
+ const fieldParentValue = fieldParent.get("V");
+ if (fieldParentValue instanceof Name) {
+ this.data.fieldValue = this._decodeFormValue(fieldParentValue);
+ }
+ }
+ const appearanceStates = params.dict.get("AP");
+ if (!(appearanceStates instanceof Dict)) {
+ return;
+ }
+ const normalAppearance = appearanceStates.get("N");
+ if (!(normalAppearance instanceof Dict)) {
+ return;
+ }
+ let onState = null;
+ for (const key of normalAppearance.getKeys()) {
+ if (key !== "Off") {
+ onState = key;
+ break;
+ }
+ }
+ this._onStateName = onState;
+ const opt = getInheritableProperty({
+ dict: params.dict,
+ key: "Opt"
+ });
+ const optInfo = this._getOptInfo(params.dict, onState, opt, params.xref);
+ this.data.buttonValue = this._getExportValue(onState, optInfo, params.xref);
+ this.data.fieldValue = this._getExportValue(this.data.fieldValue, optInfo, params.xref);
+ this.data.defaultFieldValue = this._getExportValue(this.data.defaultFieldValue, optInfo, params.xref);
+ const checkedAppearance = normalAppearance.get(onState);
+ this.checkedAppearance = checkedAppearance instanceof BaseStream ? checkedAppearance : null;
+ const uncheckedAppearance = normalAppearance.get("Off");
+ this.uncheckedAppearance = uncheckedAppearance instanceof BaseStream ? uncheckedAppearance : null;
+ if (this.checkedAppearance) {
+ this._streams.push(this.checkedAppearance);
+ } else {
+ this._getDefaultCheckedAppearance(params, "disc");
+ }
+ if (this.uncheckedAppearance) {
+ this._streams.push(this.uncheckedAppearance);
+ }
+ this._fallbackFontDict = this.fallbackFontDict;
+ if (this.data.defaultFieldValue === null) {
+ this.data.defaultFieldValue = "Off";
+ }
+ }
+ _processPushButton(params) {
+ const {
+ dict,
+ annotationGlobals
+ } = params;
+ if (!dict.has("A") && !dict.has("AA") && !this.data.alternativeText) {
+ warn("Push buttons without action dictionaries are not supported");
+ return;
+ }
+ this.data.isTooltipOnly = !dict.has("A") && !dict.has("AA");
+ Catalog.parseDestDictionary({
+ destDict: dict,
+ resultObj: this.data,
+ docBaseUrl: annotationGlobals.baseUrl,
+ docAttachments: annotationGlobals.attachments
+ });
+ }
+ getFieldObject() {
+ let type = "button";
+ let exportValues;
+ if (this.data.checkBox) {
+ type = "checkbox";
+ exportValues = this.data.exportValue;
+ } else if (this.data.radioButton) {
+ type = "radiobutton";
+ exportValues = this.data.buttonValue;
+ }
+ return {
+ id: this.data.id,
+ value: this.data.fieldValue || "Off",
+ defaultValue: this.data.defaultFieldValue,
+ exportValues,
+ editable: !this.data.readOnly,
+ name: this.data.fieldName,
+ rect: this.data.rect,
+ hidden: this.data.hidden,
+ actions: this.data.actions,
+ page: this.data.pageIndex,
+ strokeColor: this.data.borderColor,
+ fillColor: this.data.backgroundColor,
+ rotation: this.rotation,
+ type
+ };
+ }
+ get fallbackFontDict() {
+ const dict = new Dict();
+ dict.setIfName("BaseFont", "ZapfDingbats");
+ dict.setIfName("Type", "FallbackType");
+ dict.setIfName("Subtype", "FallbackType");
+ dict.setIfName("Encoding", "ZapfDingbatsEncoding");
+ return shadow(this, "fallbackFontDict", dict);
+ }
+}
+class ChoiceWidgetAnnotation extends WidgetAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ this.indices = dict.getArray("I");
+ this.hasIndices = Array.isArray(this.indices) && this.indices.length > 0;
+ this.data.options = [];
+ const options = getInheritableProperty({
+ dict,
+ key: "Opt"
+ });
+ if (Array.isArray(options)) {
+ for (let i = 0, ii = options.length; i < ii; i++) {
+ const option = xref.fetchIfRef(options[i]);
+ const isOptionArray = Array.isArray(option);
+ this.data.options[i] = {
+ exportValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[0]) : option),
+ displayValue: this._decodeFormValue(isOptionArray ? xref.fetchIfRef(option[1]) : option)
+ };
+ }
+ }
+ if (!this.hasIndices) {
+ if (typeof this.data.fieldValue === "string") {
+ this.data.fieldValue = [this.data.fieldValue];
+ } else {
+ this.data.fieldValue ||= [];
+ }
+ } else {
+ this.data.fieldValue = [];
+ const ii = this.data.options.length;
+ for (const i of this.indices) {
+ if (Number.isInteger(i) && i >= 0 && i < ii) {
+ this.data.fieldValue.push(this.data.options[i].exportValue);
+ }
+ }
+ }
+ if (this.data.options.length === 0 && this.data.fieldValue.length > 0) {
+ this.data.options = this.data.fieldValue.map(value => ({
+ exportValue: value,
+ displayValue: value
+ }));
+ }
+ this.data.combo = this.hasFieldFlag(AnnotationFieldFlag.COMBO);
+ this.data.multiSelect = this.hasFieldFlag(AnnotationFieldFlag.MULTISELECT);
+ this._hasText = true;
+ }
+ getFieldObject() {
+ const type = this.data.combo ? "combobox" : "listbox";
+ const value = this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : null;
+ return {
+ id: this.data.id,
+ value,
+ defaultValue: this.data.defaultFieldValue,
+ editable: !this.data.readOnly,
+ name: this.data.fieldName,
+ rect: this.data.rect,
+ numItems: this.data.fieldValue.length,
+ multipleSelection: this.data.multiSelect,
+ hidden: this.data.hidden,
+ actions: this.data.actions,
+ items: this.data.options,
+ page: this.data.pageIndex,
+ strokeColor: this.data.borderColor,
+ fillColor: this.data.backgroundColor,
+ rotation: this.rotation,
+ type
+ };
+ }
+ amendSavedDict(annotationStorage, dict) {
+ if (!this.hasIndices) {
+ return;
+ }
+ let values = annotationStorage?.get(this.data.id)?.value;
+ if (!Array.isArray(values)) {
+ values = [values];
+ }
+ const indices = [];
+ const {
+ options
+ } = this.data;
+ for (let i = 0, j = 0, ii = options.length; i < ii; i++) {
+ if (options[i].exportValue === values[j]) {
+ indices.push(i);
+ j += 1;
+ }
+ }
+ dict.set("I", indices);
+ }
+ async _getAppearance(evaluator, task, intent, annotationStorage) {
+ if (this.data.combo) {
+ return super._getAppearance(evaluator, task, intent, annotationStorage);
+ }
+ let exportedValue, rotation;
+ const storageEntry = annotationStorage?.get(this.data.id);
+ if (storageEntry) {
+ rotation = storageEntry.rotation;
+ exportedValue = storageEntry.value;
+ }
+ if (rotation === undefined && exportedValue === undefined && !this._needAppearances) {
+ return null;
+ }
+ if (exportedValue === undefined) {
+ exportedValue = this.data.fieldValue;
+ } else if (!Array.isArray(exportedValue)) {
+ exportedValue = [exportedValue];
+ }
+ const defaultPadding = 1;
+ const defaultHPadding = 2;
+ let {
+ width: totalWidth,
+ height: totalHeight
+ } = this;
+ if (rotation === 90 || rotation === 270) {
+ [totalWidth, totalHeight] = [totalHeight, totalWidth];
+ }
+ const lineCount = this.data.options.length;
+ const valueIndices = [];
+ for (let i = 0; i < lineCount; i++) {
+ const {
+ exportValue
+ } = this.data.options[i];
+ if (exportedValue.includes(exportValue)) {
+ valueIndices.push(i);
+ }
+ }
+ if (!this._defaultAppearance) {
+ this.data.defaultAppearanceData = parseDefaultAppearance(this._defaultAppearance = "/Helvetica 0 Tf 0 g");
+ }
+ const font = await WidgetAnnotation._getFontData(evaluator, task, this.data.defaultAppearanceData, this._fieldResources.mergedResources);
+ let defaultAppearance;
+ let {
+ fontSize
+ } = this.data.defaultAppearanceData;
+ if (!fontSize) {
+ const lineHeight = (totalHeight - defaultPadding) / lineCount;
+ let lineWidth = -1;
+ let value;
+ for (const {
+ displayValue
+ } of this.data.options) {
+ const width = this._getTextWidth(displayValue, font);
+ if (width > lineWidth) {
+ lineWidth = width;
+ value = displayValue;
+ }
+ }
+ [defaultAppearance, fontSize] = this._computeFontSize(lineHeight, totalWidth - 2 * defaultHPadding, value, font, -1);
+ } else {
+ defaultAppearance = this._defaultAppearance;
+ }
+ const lineHeight = fontSize * (/* inlined export .LINE_FACTOR */1.35);
+ const vPadding = (lineHeight - fontSize) / 2;
+ const numberOfVisibleLines = Math.floor(totalHeight / lineHeight);
+ let firstIndex = 0;
+ if (valueIndices.length > 0) {
+ const minIndex = Math.min(...valueIndices);
+ const maxIndex = Math.max(...valueIndices);
+ firstIndex = MathClamp(maxIndex - numberOfVisibleLines + 1, 0, minIndex);
+ }
+ const end = Math.min(firstIndex + numberOfVisibleLines + 1, lineCount);
+ const buf = ["/Tx BMC q", `1 1 ${totalWidth} ${totalHeight} re W n`];
+ if (valueIndices.length) {
+ buf.push("0.600006 0.756866 0.854904 rg");
+ for (const index of valueIndices) {
+ if (firstIndex <= index && index < end) {
+ buf.push(`1 ${totalHeight - (index - firstIndex + 1) * lineHeight} ${totalWidth} ${lineHeight} re f`);
+ }
+ }
+ }
+ buf.push("BT", defaultAppearance, `1 0 0 1 0 ${totalHeight} Tm`);
+ const prevInfo = {
+ shift: 0
+ };
+ for (let i = firstIndex; i < end; i++) {
+ const {
+ displayValue
+ } = this.data.options[i];
+ const vpadding = i === firstIndex ? vPadding : 0;
+ buf.push(this._renderText(displayValue, font, fontSize, totalWidth, 0, prevInfo, defaultHPadding, -lineHeight + vpadding));
+ }
+ buf.push("ET Q EMC");
+ return buf.join("\n");
+ }
+}
+class SignatureWidgetAnnotation extends WidgetAnnotation {
+ _hasValueFromXFA = false;
+ constructor(params) {
+ super(params);
+ this.data.fieldValue = null;
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = !this.data.hasOwnCanvas;
+ }
+ getFieldObject() {
+ return {
+ id: this.data.id,
+ value: null,
+ page: this.data.pageIndex,
+ type: "signature"
+ };
+ }
+}
+class TextAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ const DEFAULT_ICON_SIZE = 22;
+ super(params);
+ this.data.noRotate = true;
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = false;
+ const {
+ dict
+ } = params;
+ if (this.data.hasAppearance) {
+ this.data.name = "NoIcon";
+ } else {
+ this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
+ this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
+ this.data.name = dict.has("Name") ? dict.get("Name").name : "Note";
+ }
+ if (dict.has("State")) {
+ this.data.state = dict.get("State") || null;
+ this.data.stateModel = dict.get("StateModel") || null;
+ } else {
+ this.data.state = null;
+ this.data.stateModel = null;
+ }
+ }
+}
+class LinkAnnotation extends Annotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ annotationGlobals
+ } = params;
+ this.data.noHTML = false;
+ const quadPoints = getQuadPoints(dict, this.rectangle);
+ if (quadPoints) {
+ this.data.quadPoints = quadPoints;
+ }
+ this.data.borderColor ||= this.data.color;
+ Catalog.parseDestDictionary({
+ destDict: dict,
+ resultObj: this.data,
+ docBaseUrl: annotationGlobals.baseUrl,
+ docAttachments: annotationGlobals.attachments
+ });
+ }
+ get overlaysTextContent() {
+ return true;
+ }
+}
+class PopupAnnotation extends Annotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict
+ } = params;
+ this.data.noHTML = false;
+ if (this.width === 0 || this.height === 0) {
+ this.data.rect = null;
+ }
+ let parentItem = dict.get("Parent");
+ if (!parentItem) {
+ warn("Popup annotation has a missing or invalid parent annotation.");
+ return;
+ }
+ this.data.parentRect = lookupNormalRect(parentItem.getArray("Rect"), null);
+ this.data.creationDate = parentItem.get("CreationDate") || "";
+ const rt = parentItem.get("RT");
+ if (isName(rt, AnnotationReplyType.GROUP)) {
+ parentItem = parentItem.get("IRT");
+ }
+ if (!parentItem.has("M")) {
+ this.data.modificationDate = null;
+ } else {
+ this.setModificationDate(parentItem.get("M"));
+ this.data.modificationDate = this.modificationDate;
+ }
+ if (!parentItem.has("C")) {
+ this.data.color = null;
+ } else {
+ this.setColor(parentItem.getArray("C"));
+ this.data.color = this.color;
+ }
+ if (!this.viewable) {
+ const parentFlags = parentItem.get("F");
+ if (this._isViewable(parentFlags)) {
+ this.setFlags(parentFlags);
+ }
+ }
+ this.setTitle(parentItem.get("T"));
+ this.data.titleObj = this._title;
+ this.setContents(parentItem.get("Contents"));
+ this.data.contentsObj = this._contents;
+ if (parentItem.has("RC")) {
+ this.data.richText = XFAFactory.getRichTextAsHtml(parentItem.get("RC"));
+ }
+ this.data.open = !!dict.get("Open");
+ }
+ static createNewDict(annotation, xref, _params) {
+ const {
+ oldAnnotation,
+ rect,
+ parent
+ } = annotation;
+ const popup = oldAnnotation || new Dict(xref);
+ popup.setIfNotExists("Type", Name.get("Annot"));
+ popup.setIfNotExists("Subtype", Name.get("Popup"));
+ popup.setIfNotExists("Open", false);
+ popup.setIfArray("Rect", rect);
+ popup.set("Parent", parent);
+ return popup;
+ }
+ static async createNewAppearanceStream(annotation, xref, params) {
+ return null;
+ }
+}
+class FreeTextAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.isEditable = !this.data.noHTML;
+ this.data.noHTML = false;
+ const {
+ annotationGlobals,
+ xref
+ } = params;
+ this.setDefaultAppearance(params);
+ this._hasAppearance = !!this.appearance;
+ if (this._hasAppearance) {
+ const {
+ fontColor,
+ fontSize
+ } = parseAppearanceStream(this.appearance, xref, annotationGlobals.globalColorSpaceCache);
+ this.data.defaultAppearanceData.fontColor = fontColor;
+ this.data.defaultAppearanceData.fontSize = fontSize || 10;
+ } else {
+ this.data.defaultAppearanceData.fontSize ||= 10;
+ const {
+ fontColor,
+ fontSize
+ } = this.data.defaultAppearanceData;
+ if (this._contents.str) {
+ this.data.textContent = this._contents.str.split(/\r\n?|\n/).map(line => line.trimEnd());
+ const {
+ coords,
+ bbox,
+ matrix
+ } = FakeUnicodeFont.getFirstPositionInfo(this.rectangle, this.rotation, fontSize);
+ this.data.textPosition = this._transformPoint(coords, bbox, matrix);
+ }
+ if (this._isOffscreenCanvasSupported) {
+ const strokeAlpha = params.dict.get("CA");
+ const fakeUnicodeFont = new FakeUnicodeFont(xref, "sans-serif");
+ this.appearance = fakeUnicodeFont.createAppearance(this._contents.str, this.rectangle, this.rotation, fontSize, fontColor, strokeAlpha);
+ this._streams.push(this.appearance);
+ } else {
+ warn("FreeTextAnnotation: OffscreenCanvas is not supported, annotation may not render correctly.");
+ }
+ }
+ }
+ get hasTextContent() {
+ return this._hasAppearance;
+ }
+ static createNewDict(annotation, xref, {
+ apRef,
+ ap
+ }) {
+ const {
+ color,
+ date,
+ fontSize,
+ oldAnnotation,
+ rect,
+ rotation,
+ user,
+ value
+ } = annotation;
+ const freetext = oldAnnotation || new Dict(xref);
+ freetext.setIfNotExists("Type", Name.get("Annot"));
+ freetext.setIfNotExists("Subtype", Name.get("FreeText"));
+ freetext.set(oldAnnotation ? "M" : "CreationDate", `D:${getModificationDate(date)}`);
+ if (oldAnnotation) {
+ freetext.delete("RC");
+ }
+ freetext.setIfArray("Rect", rect);
+ const da = `/Helv ${fontSize} Tf ${getPdfColor(color, true)}`;
+ freetext.set("DA", da);
+ freetext.setIfDefined("Contents", stringToAsciiOrUTF16BE(value));
+ freetext.setIfNotExists("F", 4);
+ freetext.setIfNotExists("Border", [0, 0, 0]);
+ freetext.setIfNumber("Rotate", rotation);
+ freetext.setIfDefined("T", stringToAsciiOrUTF16BE(user));
+ if (apRef || ap) {
+ const n = new Dict(xref);
+ freetext.set("AP", n);
+ n.set("N", apRef || ap);
+ }
+ return freetext;
+ }
+ static async createNewAppearanceStream(annotation, xref, params) {
+ const {
+ baseFontRef,
+ evaluator,
+ task
+ } = params;
+ const {
+ color,
+ fontSize,
+ rect,
+ rotation,
+ value
+ } = annotation;
+ if (!color) {
+ return null;
+ }
+ const resources = new Dict(xref);
+ const font = new Dict(xref);
+ if (baseFontRef) {
+ font.set("Helv", baseFontRef);
+ } else {
+ const baseFont = new Dict(xref);
+ baseFont.setIfName("BaseFont", "Helvetica");
+ baseFont.setIfName("Type", "Font");
+ baseFont.setIfName("Subtype", "Type1");
+ baseFont.setIfName("Encoding", "WinAnsiEncoding");
+ font.set("Helv", baseFont);
+ }
+ resources.set("Font", font);
+ const helv = await WidgetAnnotation._getFontData(evaluator, task, {
+ fontName: "Helv",
+ fontSize
+ }, resources);
+ const [x1, y1, x2, y2] = rect;
+ let w = x2 - x1;
+ let h = y2 - y1;
+ if (rotation % 180 !== 0) {
+ [w, h] = [h, w];
+ }
+ const lines = value.split("\n");
+ const scale = fontSize / 1000;
+ let totalWidth = -Infinity;
+ const encodedLines = [];
+ for (let line of lines) {
+ const encoded = helv.encodeString(line);
+ if (encoded.length > 1) {
+ return null;
+ }
+ line = encoded.join("");
+ encodedLines.push(line);
+ let lineWidth = 0;
+ const glyphs = helv.charsToGlyphs(line);
+ for (const glyph of glyphs) {
+ lineWidth += glyph.width * scale;
+ }
+ totalWidth = Math.max(totalWidth, lineWidth);
+ }
+ const hscale = totalWidth > w ? w / totalWidth : 1;
+ let vscale = 1;
+ const lineHeight = (/* inlined export .LINE_FACTOR */1.35) * fontSize;
+ const lineAscent = ((/* inlined export .LINE_FACTOR */1.35) - (/* inlined export .LINE_DESCENT_FACTOR */0.35)) * fontSize;
+ const totalHeight = lineHeight * lines.length;
+ if (totalHeight > h) {
+ vscale = h / totalHeight;
+ }
+ const fscale = Math.min(hscale, vscale);
+ const newFontSize = fontSize * fscale;
+ let firstPoint, clipBox, matrix;
+ switch (rotation) {
+ case 0:
+ matrix = [1, 0, 0, 1];
+ clipBox = [rect[0], rect[1], w, h];
+ firstPoint = [rect[0], rect[3] - lineAscent];
+ break;
+ case 90:
+ matrix = [0, 1, -1, 0];
+ clipBox = [rect[1], -rect[2], w, h];
+ firstPoint = [rect[1], -rect[0] - lineAscent];
+ break;
+ case 180:
+ matrix = [-1, 0, 0, -1];
+ clipBox = [-rect[2], -rect[3], w, h];
+ firstPoint = [-rect[2], -rect[1] - lineAscent];
+ break;
+ case 270:
+ matrix = [0, -1, 1, 0];
+ clipBox = [-rect[3], rect[0], w, h];
+ firstPoint = [-rect[3], rect[2] - lineAscent];
+ break;
+ }
+ const buffer = ["q", `${matrix.join(" ")} 0 0 cm`, `${clipBox.join(" ")} re W n`, `BT`, `${getPdfColor(color, true)}`, `0 Tc /Helv ${numberToString(newFontSize)} Tf`];
+ buffer.push(`${firstPoint.join(" ")} Td (${escapeString(encodedLines[0])}) Tj`);
+ const vShift = numberToString(lineHeight);
+ for (let i = 1, ii = encodedLines.length; i < ii; i++) {
+ const line = encodedLines[i];
+ buffer.push(`0 -${vShift} Td (${escapeString(line)}) Tj`);
+ }
+ buffer.push("ET", "Q");
+ const appearance = buffer.join("\n");
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", rect);
+ appearanceStreamDict.set("Resources", resources);
+ appearanceStreamDict.set("Matrix", [1, 0, 0, 1, -rect[0], -rect[1]]);
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+}
+class LineAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = false;
+ const lineCoordinates = lookupRect(dict.getArray("L"), [0, 0, 0, 0]);
+ this.data.lineCoordinates = Util.normalizeRect(lineCoordinates);
+ this.setLineEndings(dict.getArray("LE"));
+ this.data.lineEndings = this.lineEndings;
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ const interiorColor = getRgbColor(dict.getArray("IC"), null);
+ const fillColor = getPdfColorArray(interiorColor);
+ const fillAlpha = fillColor ? strokeAlpha : null;
+ const borderWidth = this.borderStyle.width || 1,
+ borderAdjust = 2 * borderWidth;
+ const bbox = [this.data.lineCoordinates[0] - borderAdjust, this.data.lineCoordinates[1] - borderAdjust, this.data.lineCoordinates[2] + borderAdjust, this.data.lineCoordinates[3] + borderAdjust];
+ if (!Util.intersect(this.rectangle, bbox)) {
+ this.rectangle = bbox;
+ }
+ this._setDefaultAppearance({
+ xref,
+ extra: `${borderWidth} w`,
+ strokeColor,
+ fillColor,
+ strokeAlpha,
+ fillAlpha,
+ pointsCallback: (buffer, points) => {
+ buffer.push(`${lineCoordinates[0]} ${lineCoordinates[1]} m`, `${lineCoordinates[2]} ${lineCoordinates[3]} l`, "S");
+ return [points[0] - borderWidth, points[7] - borderWidth, points[2] + borderWidth, points[3] + borderWidth];
+ }
+ });
+ }
+ }
+}
+class SquareAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = false;
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ const interiorColor = getRgbColor(dict.getArray("IC"), null);
+ const fillColor = getPdfColorArray(interiorColor);
+ const fillAlpha = fillColor ? strokeAlpha : null;
+ if (this.borderStyle.width === 0 && !fillColor) {
+ return;
+ }
+ this._setDefaultAppearance({
+ xref,
+ extra: `${this.borderStyle.width} w`,
+ strokeColor,
+ fillColor,
+ strokeAlpha,
+ fillAlpha,
+ pointsCallback: (buffer, points) => {
+ const x = points[4] + this.borderStyle.width / 2;
+ const y = points[5] + this.borderStyle.width / 2;
+ const width = points[6] - points[4] - this.borderStyle.width;
+ const height = points[3] - points[7] - this.borderStyle.width;
+ buffer.push(`${x} ${y} ${width} ${height} re`);
+ if (fillColor) {
+ buffer.push("B");
+ } else {
+ buffer.push("S");
+ }
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ }
+}
+class CircleAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ const interiorColor = getRgbColor(dict.getArray("IC"), null);
+ const fillColor = getPdfColorArray(interiorColor);
+ const fillAlpha = fillColor ? strokeAlpha : null;
+ if (this.borderStyle.width === 0 && !fillColor) {
+ return;
+ }
+ const controlPointsDistance = 4 / 3 * Math.tan(Math.PI / (2 * 4));
+ this._setDefaultAppearance({
+ xref,
+ extra: `${this.borderStyle.width} w`,
+ strokeColor,
+ fillColor,
+ strokeAlpha,
+ fillAlpha,
+ pointsCallback: (buffer, points) => {
+ const x0 = points[0] + this.borderStyle.width / 2;
+ const y0 = points[1] - this.borderStyle.width / 2;
+ const x1 = points[6] - this.borderStyle.width / 2;
+ const y1 = points[7] + this.borderStyle.width / 2;
+ const xMid = x0 + (x1 - x0) / 2;
+ const yMid = y0 + (y1 - y0) / 2;
+ const xOffset = (x1 - x0) / 2 * controlPointsDistance;
+ const yOffset = (y1 - y0) / 2 * controlPointsDistance;
+ buffer.push(`${xMid} ${y1} m`, `${xMid + xOffset} ${y1} ${x1} ${yMid + yOffset} ${x1} ${yMid} c`, `${x1} ${yMid - yOffset} ${xMid + xOffset} ${y0} ${xMid} ${y0} c`, `${xMid - xOffset} ${y0} ${x0} ${yMid - yOffset} ${x0} ${yMid} c`, `${x0} ${yMid + yOffset} ${xMid - xOffset} ${y1} ${xMid} ${y1} c`, "h");
+ if (fillColor) {
+ buffer.push("B");
+ } else {
+ buffer.push("S");
+ }
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ }
+}
+class PolylineAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = false;
+ this.data.vertices = null;
+ if (!(this instanceof PolygonAnnotation)) {
+ this.setLineEndings(dict.getArray("LE"));
+ this.data.lineEndings = this.lineEndings;
+ }
+ const rawVertices = dict.getArray("Vertices");
+ if (!isNumberArray(rawVertices, null)) {
+ return;
+ }
+ const vertices = this.data.vertices = Float32Array.from(rawVertices);
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ let fillColor = getRgbColor(dict.getArray("IC"), null);
+ fillColor &&= getPdfColorArray(fillColor);
+ let operator;
+ if (fillColor) {
+ if (this.color) {
+ operator = fillColor.every((c, i) => c === strokeColor[i]) ? "f" : "B";
+ } else {
+ operator = "f";
+ }
+ } else {
+ operator = "S";
+ }
+ const borderWidth = this.borderStyle.width || 1,
+ borderAdjust = 2 * borderWidth;
+ const bbox = BBOX_INIT.slice();
+ for (let i = 0, ii = vertices.length; i < ii; i += 2) {
+ Util.rectBoundingBox(vertices[i] - borderAdjust, vertices[i + 1] - borderAdjust, vertices[i] + borderAdjust, vertices[i + 1] + borderAdjust, bbox);
+ }
+ if (!Util.intersect(this.rectangle, bbox)) {
+ this.rectangle = bbox;
+ }
+ this._setDefaultAppearance({
+ xref,
+ extra: `${borderWidth} w`,
+ strokeColor,
+ strokeAlpha,
+ fillColor,
+ fillAlpha: fillColor ? strokeAlpha : null,
+ pointsCallback: (buffer, points) => {
+ for (let i = 0, ii = vertices.length; i < ii; i += 2) {
+ buffer.push(`${vertices[i]} ${vertices[i + 1]} ${i === 0 ? "m" : "l"}`);
+ }
+ buffer.push(operator);
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ }
+}
+class PolygonAnnotation extends PolylineAnnotation {}
+class CaretAnnotation extends MarkupAnnotation {}
+class InkAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = false;
+ const {
+ dict,
+ xref
+ } = params;
+ this.data.inkLists = [];
+ this.data.isEditable = !this.data.noHTML;
+ this.data.noHTML = false;
+ this.data.opacity = dict.get("CA") || 1;
+ const rawInkLists = dict.getArray("InkList");
+ if (!Array.isArray(rawInkLists)) {
+ return;
+ }
+ for (const rawInkList of rawInkLists) {
+ if (!Array.isArray(rawInkList)) {
+ continue;
+ }
+ const inkList = new Float32Array(rawInkList.length);
+ this.data.inkLists.push(inkList);
+ for (let j = 0, jj = rawInkList.length; j < jj; j += 2) {
+ const x = xref.fetchIfRef(rawInkList[j]),
+ y = xref.fetchIfRef(rawInkList[j + 1]);
+ if (typeof x === "number" && typeof y === "number") {
+ inkList[j] = x;
+ inkList[j + 1] = y;
+ }
+ }
+ }
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ const borderWidth = this.borderStyle.width || 1,
+ borderAdjust = 2 * borderWidth;
+ const bbox = BBOX_INIT.slice();
+ for (const inkList of this.data.inkLists) {
+ for (let i = 0, ii = inkList.length; i < ii; i += 2) {
+ Util.rectBoundingBox(inkList[i] - borderAdjust, inkList[i + 1] - borderAdjust, inkList[i] + borderAdjust, inkList[i + 1] + borderAdjust, bbox);
+ }
+ }
+ if (!Util.intersect(this.rectangle, bbox)) {
+ this.rectangle = bbox;
+ }
+ this._setDefaultAppearance({
+ xref,
+ extra: `${borderWidth} w`,
+ strokeColor,
+ strokeAlpha,
+ pointsCallback: (buffer, points) => {
+ for (const inkList of this.data.inkLists) {
+ for (let i = 0, ii = inkList.length; i < ii; i += 2) {
+ buffer.push(`${inkList[i]} ${inkList[i + 1]} ${i === 0 ? "m" : "l"}`);
+ }
+ buffer.push("S");
+ }
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ }
+ static createNewDict(annotation, xref, {
+ apRef,
+ ap
+ }) {
+ const {
+ oldAnnotation,
+ color,
+ date,
+ opacity,
+ paths,
+ outlines,
+ rect,
+ rotation,
+ thickness,
+ user
+ } = annotation;
+ const ink = oldAnnotation || new Dict(xref);
+ ink.setIfNotExists("Type", Name.get("Annot"));
+ ink.setIfNotExists("Subtype", Name.get("Ink"));
+ ink.set(oldAnnotation ? "M" : "CreationDate", `D:${getModificationDate(date)}`);
+ ink.setIfArray("Rect", rect);
+ ink.setIfArray("InkList", outlines?.points || paths?.points);
+ ink.setIfNotExists("F", 4);
+ ink.setIfNumber("Rotate", rotation);
+ ink.setIfDefined("T", stringToAsciiOrUTF16BE(user));
+ if (outlines) {
+ ink.setIfName("IT", "InkHighlight");
+ }
+ if (thickness > 0) {
+ const bs = new Dict(xref);
+ ink.set("BS", bs);
+ bs.set("W", thickness);
+ }
+ ink.setIfArray("C", getPdfColorArray(color));
+ ink.setIfNumber("CA", opacity);
+ if (ap || apRef) {
+ const n = new Dict(xref);
+ ink.set("AP", n);
+ n.set("N", apRef || ap);
+ }
+ return ink;
+ }
+ static async createNewAppearanceStream(annotation, xref, params) {
+ if (annotation.outlines) {
+ return this.createNewAppearanceStreamForHighlight(annotation, xref, params);
+ }
+ const {
+ color,
+ rect,
+ paths,
+ thickness,
+ opacity
+ } = annotation;
+ if (!color) {
+ return null;
+ }
+ const appearanceBuffer = [`${thickness} w 1 J 1 j`, `${getPdfColor(color, false)}`];
+ if (opacity !== 1) {
+ appearanceBuffer.push("/R0 gs");
+ }
+ for (const outline of paths.lines) {
+ writeLineToCurveToAppearance(outline, appearanceBuffer, true);
+ }
+ appearanceBuffer.push("S");
+ const appearance = appearanceBuffer.join("\n");
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", rect);
+ appearanceStreamDict.set("Length", appearance.length);
+ if (opacity !== 1) {
+ const resources = new Dict(xref);
+ const extGState = new Dict(xref);
+ const r0 = new Dict(xref);
+ r0.set("CA", opacity);
+ r0.setIfName("Type", "ExtGState");
+ extGState.set("R0", r0);
+ resources.set("ExtGState", extGState);
+ appearanceStreamDict.set("Resources", resources);
+ }
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+ static async createNewAppearanceStreamForHighlight(annotation, xref, params) {
+ const {
+ color,
+ rect,
+ outlines: {
+ outline
+ },
+ opacity
+ } = annotation;
+ if (!color) {
+ return null;
+ }
+ const appearanceBuffer = [`${getPdfColor(color, true)}`, "/R0 gs"];
+ writeLineToCurveToAppearance(outline, appearanceBuffer);
+ appearanceBuffer.push("h f");
+ const appearance = appearanceBuffer.join("\n");
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", rect);
+ appearanceStreamDict.set("Length", appearance.length);
+ const resources = new Dict(xref);
+ const extGState = new Dict(xref);
+ resources.set("ExtGState", extGState);
+ appearanceStreamDict.set("Resources", resources);
+ const r0 = new Dict(xref);
+ extGState.set("R0", r0);
+ r0.setIfName("BM", "Multiply");
+ if (opacity !== 1) {
+ r0.set("ca", opacity);
+ r0.setIfName("Type", "ExtGState");
+ }
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+}
+class HighlightAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ this.data.isEditable = !this.data.noHTML;
+ this.data.noHTML = false;
+ this.data.opacity = dict.get("CA") || 1;
+ const quadPoints = this.data.quadPoints = getQuadPoints(dict, null);
+ if (quadPoints) {
+ if (!this.appearance) {
+ const fillColor = getPdfColorArray(this.color, [1, 1, 0]);
+ const fillAlpha = dict.get("CA");
+ this._setDefaultAppearance({
+ xref,
+ fillColor,
+ blendMode: "Multiply",
+ fillAlpha,
+ pointsCallback: (buffer, points) => {
+ buffer.push(`${points[0]} ${points[1]} m`, `${points[2]} ${points[3]} l`, `${points[6]} ${points[7]} l`, `${points[4]} ${points[5]} l`, "f");
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ } else {
+ this.data.popupRef = null;
+ }
+ }
+ get overlaysTextContent() {
+ return true;
+ }
+ static createNewDict(annotation, xref, {
+ apRef,
+ ap
+ }) {
+ const {
+ color,
+ date,
+ oldAnnotation,
+ opacity,
+ rect,
+ rotation,
+ user,
+ quadPoints
+ } = annotation;
+ const highlight = oldAnnotation || new Dict(xref);
+ highlight.setIfNotExists("Type", Name.get("Annot"));
+ highlight.setIfNotExists("Subtype", Name.get("Highlight"));
+ highlight.set(oldAnnotation ? "M" : "CreationDate", `D:${getModificationDate(date)}`);
+ highlight.setIfArray("Rect", rect);
+ highlight.setIfNotExists("F", 4);
+ highlight.setIfNotExists("Border", [0, 0, 0]);
+ highlight.setIfNumber("Rotate", rotation);
+ highlight.setIfArray("QuadPoints", quadPoints);
+ highlight.setIfArray("C", getPdfColorArray(color));
+ highlight.setIfNumber("CA", opacity);
+ highlight.setIfDefined("T", stringToAsciiOrUTF16BE(user));
+ if (apRef || ap) {
+ const n = new Dict(xref);
+ highlight.set("AP", n);
+ n.set("N", apRef || ap);
+ }
+ return highlight;
+ }
+ static async createNewAppearanceStream(annotation, xref, params) {
+ const {
+ color,
+ rect,
+ outlines,
+ opacity
+ } = annotation;
+ if (!color) {
+ return null;
+ }
+ const appearanceBuffer = [`${getPdfColor(color, true)}`, "/R0 gs"];
+ const buffer = [];
+ for (const outline of outlines) {
+ buffer.length = 0;
+ buffer.push(`${numberToString(outline[0])} ${numberToString(outline[1])} m`);
+ for (let i = 2, ii = outline.length; i < ii; i += 2) {
+ buffer.push(`${numberToString(outline[i])} ${numberToString(outline[i + 1])} l`);
+ }
+ buffer.push("h");
+ appearanceBuffer.push(buffer.join("\n"));
+ }
+ appearanceBuffer.push("f*");
+ const appearance = appearanceBuffer.join("\n");
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", rect);
+ appearanceStreamDict.set("Length", appearance.length);
+ const resources = new Dict(xref);
+ const extGState = new Dict(xref);
+ resources.set("ExtGState", extGState);
+ appearanceStreamDict.set("Resources", resources);
+ const r0 = new Dict(xref);
+ extGState.set("R0", r0);
+ r0.setIfName("BM", "Multiply");
+ if (opacity !== 1) {
+ r0.set("ca", opacity);
+ r0.setIfName("Type", "ExtGState");
+ }
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+}
+class UnderlineAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ const quadPoints = this.data.quadPoints = getQuadPoints(dict, null);
+ if (quadPoints) {
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ this._setDefaultAppearance({
+ xref,
+ extra: "[] 0 d 0.571 w",
+ strokeColor,
+ strokeAlpha,
+ pointsCallback: (buffer, points) => {
+ buffer.push(`${points[4]} ${points[5] + 1.3} m`, `${points[6]} ${points[7] + 1.3} l`, "S");
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ } else {
+ this.data.popupRef = null;
+ }
+ }
+ get overlaysTextContent() {
+ return true;
+ }
+}
+class SquigglyAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ const quadPoints = this.data.quadPoints = getQuadPoints(dict, null);
+ if (quadPoints) {
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ this._setDefaultAppearance({
+ xref,
+ extra: "[] 0 d 1 w",
+ strokeColor,
+ strokeAlpha,
+ pointsCallback: (buffer, points) => {
+ const dy = (points[1] - points[5]) / 6;
+ let shift = dy;
+ let x = points[4];
+ const y = points[5];
+ const xEnd = points[6];
+ buffer.push(`${x} ${y + shift} m`);
+ do {
+ x += 2;
+ shift = shift === 0 ? dy : 0;
+ buffer.push(`${x} ${y + shift} l`);
+ } while (x < xEnd);
+ buffer.push("S");
+ return [points[4], y - 2 * dy, xEnd, y + 2 * dy];
+ }
+ });
+ }
+ } else {
+ this.data.popupRef = null;
+ }
+ }
+ get overlaysTextContent() {
+ return true;
+ }
+}
+class StrikeOutAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref
+ } = params;
+ const quadPoints = this.data.quadPoints = getQuadPoints(dict, null);
+ if (quadPoints) {
+ if (!this.appearance) {
+ const strokeColor = getPdfColorArray(this.color, [0, 0, 0]);
+ const strokeAlpha = dict.get("CA");
+ this._setDefaultAppearance({
+ xref,
+ extra: "[] 0 d 1 w",
+ strokeColor,
+ strokeAlpha,
+ pointsCallback: (buffer, points) => {
+ buffer.push(`${(points[0] + points[4]) / 2} ` + `${(points[1] + points[5]) / 2} m`, `${(points[2] + points[6]) / 2} ` + `${(points[3] + points[7]) / 2} l`, "S");
+ return [points[0], points[7], points[2], points[3]];
+ }
+ });
+ }
+ } else {
+ this.data.popupRef = null;
+ }
+ }
+ get overlaysTextContent() {
+ return true;
+ }
+}
+class StampAnnotation extends MarkupAnnotation {
+ #savedHasOwnCanvas = null;
+ constructor(params) {
+ super(params);
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.isEditable = !this.data.noHTML;
+ this.data.noHTML = false;
+ }
+ mustBeViewedWhenEditing(isEditing, modifiedIds = null) {
+ if (isEditing) {
+ if (!this.data.isEditable) {
+ return true;
+ }
+ this.#savedHasOwnCanvas ??= this.data.hasOwnCanvas;
+ this.data.hasOwnCanvas = true;
+ return true;
+ }
+ if (this.#savedHasOwnCanvas !== null) {
+ this.data.hasOwnCanvas = this.#savedHasOwnCanvas;
+ this.#savedHasOwnCanvas = null;
+ }
+ return !modifiedIds?.has(this.data.id);
+ }
+ static createNewDict(annotation, xref, {
+ apRef,
+ ap
+ }) {
+ const {
+ date,
+ oldAnnotation,
+ rect,
+ rotation,
+ user
+ } = annotation;
+ const stamp = oldAnnotation || new Dict(xref);
+ stamp.setIfNotExists("Type", Name.get("Annot"));
+ stamp.setIfNotExists("Subtype", Name.get("Stamp"));
+ stamp.set(oldAnnotation ? "M" : "CreationDate", `D:${getModificationDate(date)}`);
+ stamp.setIfArray("Rect", rect);
+ stamp.setIfNotExists("F", 4);
+ stamp.setIfNotExists("Border", [0, 0, 0]);
+ stamp.setIfNumber("Rotate", rotation);
+ stamp.setIfDefined("T", stringToAsciiOrUTF16BE(user));
+ if (apRef || ap) {
+ const n = new Dict(xref);
+ stamp.set("AP", n);
+ n.set("N", apRef || ap);
+ }
+ return stamp;
+ }
+ static async #createNewAppearanceStreamForDrawing(annotation, xref) {
+ const {
+ areContours,
+ color,
+ rect,
+ lines,
+ thickness
+ } = annotation;
+ if (!color) {
+ return null;
+ }
+ const appearanceBuffer = [`${thickness} w 1 J 1 j`, `${getPdfColor(color, areContours)}`];
+ for (const line of lines) {
+ writeLineToCurveToAppearance(line, appearanceBuffer, true);
+ }
+ appearanceBuffer.push(areContours ? "F" : "S");
+ const appearance = appearanceBuffer.join("\n");
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", rect);
+ appearanceStreamDict.set("Length", appearance.length);
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+ static async createNewAppearanceStream(annotation, xref, params) {
+ if (annotation.oldAnnotation) {
+ return null;
+ }
+ if (annotation.isSignature) {
+ return this.#createNewAppearanceStreamForDrawing(annotation, xref);
+ }
+ const {
+ rotation
+ } = annotation;
+ const {
+ imageRef,
+ width,
+ height
+ } = params.image;
+ const resources = new Dict(xref);
+ const xobject = new Dict(xref);
+ resources.set("XObject", xobject);
+ xobject.set("Im0", imageRef);
+ const appearance = `q ${width} 0 0 ${height} 0 0 cm /Im0 Do Q`;
+ const appearanceStreamDict = new Dict(xref);
+ appearanceStreamDict.set("FormType", 1);
+ appearanceStreamDict.setIfName("Subtype", "Form");
+ appearanceStreamDict.setIfName("Type", "XObject");
+ appearanceStreamDict.set("BBox", [0, 0, width, height]);
+ appearanceStreamDict.set("Resources", resources);
+ if (rotation) {
+ const matrix = getRotationMatrix(rotation, width, height);
+ appearanceStreamDict.set("Matrix", matrix);
+ }
+ return new StringStream(appearance, appearanceStreamDict);
+ }
+}
+class FileAttachmentAnnotation extends MarkupAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ annotationGlobals,
+ dict
+ } = params;
+ const fsDict = dict.get("FS");
+ this.data.hasOwnCanvas = this.data.noRotate;
+ this.data.noHTML = false;
+ this.data.fileId = this._getAttachmentId(fsDict, dict.getRaw("FS"), annotationGlobals);
+ this.data.file = new FileSpec(fsDict).serializable;
+ const name = dict.get("Name");
+ this.data.name = name instanceof Name ? stringToPDFString(name.name) : "PushPin";
+ const fillAlpha = dict.get("ca");
+ this.data.fillAlpha = typeof fillAlpha === "number" && fillAlpha >= 0 && fillAlpha <= 1 ? fillAlpha : null;
+ }
+}
+class MediaAnnotation extends Annotation {
+ static #MEDIA_MIME_TYPE_RE = /^(?:video|audio)\//;
+ constructor(params) {
+ super(params);
+ this.data.noHTML = true;
+ }
+ _setMediaData({
+ assetRef,
+ assetDict,
+ filename,
+ contentType,
+ wrapSound = false
+ }, annotationGlobals) {
+ this.data.noHTML = false;
+ this.data.richMedia = {
+ fileId: this._getAttachmentId(assetDict, assetRef, annotationGlobals, wrapSound),
+ filename,
+ contentType
+ };
+ }
+ static _getContentType(assetDict, filename, contentType = null) {
+ if (typeof contentType === "string" && MediaAnnotation.#MEDIA_MIME_TYPE_RE.test(contentType)) {
+ return contentType;
+ }
+ const stream = FileSpec.pickPlatformItem(assetDict.get("EF"));
+ const subtype = stream instanceof BaseStream ? stream.dict?.get("Subtype") : null;
+ if (subtype instanceof Name && MediaAnnotation.#MEDIA_MIME_TYPE_RE.test(subtype.name)) {
+ return subtype.name;
+ }
+ const ext = filename.split(".").at(-1)?.toLowerCase();
+ switch (ext) {
+ case "mp4":
+ case "m4v":
+ return "video/mp4";
+ case "webm":
+ return "video/webm";
+ case "ogv":
+ return "video/ogg";
+ case "mov":
+ return "video/quicktime";
+ case "mp3":
+ return "audio/mpeg";
+ case "m4a":
+ return "audio/mp4";
+ case "wav":
+ return "audio/wav";
+ case "oga":
+ case "ogg":
+ return "audio/ogg";
+ default:
+ return null;
+ }
+ }
+}
+class RichMediaAnnotation extends MediaAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref,
+ annotationGlobals
+ } = params;
+ const content = dict.get("RichMediaContent");
+ if (!(content instanceof Dict)) {
+ return;
+ }
+ const asset = RichMediaAnnotation.#findAsset(content, xref);
+ if (!asset) {
+ warn("RichMedia annotation has no playable asset.");
+ return;
+ }
+ this._setMediaData(asset, annotationGlobals);
+ }
+ static #findAsset(content, xref) {
+ const configurations = content.get("Configurations");
+ if (!Array.isArray(configurations)) {
+ return null;
+ }
+ for (const configRef of configurations) {
+ const config = xref.fetchIfRef(configRef);
+ if (!(config instanceof Dict)) {
+ continue;
+ }
+ const instances = config.get("Instances");
+ if (!Array.isArray(instances)) {
+ continue;
+ }
+ for (const instanceRef of instances) {
+ const instance = xref.fetchIfRef(instanceRef);
+ if (!(instance instanceof Dict)) {
+ continue;
+ }
+ if (isName(instance.get("Subtype"), "Flash")) {
+ continue;
+ }
+ const rawAsset = instance.getRaw("Asset");
+ const asset = xref.fetchIfRef(rawAsset);
+ if (!(asset instanceof Dict)) {
+ continue;
+ }
+ if (!FileSpec.hasEmbeddedFile(asset)) {
+ continue;
+ }
+ const {
+ filename
+ } = new FileSpec(asset).serializable;
+ const contentType = MediaAnnotation._getContentType(asset, filename);
+ if (!contentType) {
+ continue;
+ }
+ return {
+ assetRef: rawAsset instanceof Ref ? rawAsset : null,
+ assetDict: asset,
+ filename,
+ contentType
+ };
+ }
+ }
+ return null;
+ }
+}
+class ScreenAnnotation extends MediaAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref,
+ annotationGlobals
+ } = params;
+ const asset = ScreenAnnotation.#findAsset(dict, xref);
+ if (!asset) {
+ return;
+ }
+ this._setMediaData(asset, annotationGlobals);
+ }
+ static #findAsset(dict, xref) {
+ for (const action of this.#renditionActions(dict)) {
+ const asset = this.#findRenditionAsset(action.get("R"), xref, new RefSet());
+ if (asset) {
+ return asset;
+ }
+ }
+ return null;
+ }
+ static *#renditionActions(dict) {
+ const action = dict.get("A");
+ if (action instanceof Dict && isName(action.get("S"), "Rendition") && this.#isPlayAction(action)) {
+ yield action;
+ }
+ const additionalActions = dict.get("AA");
+ if (additionalActions instanceof Dict) {
+ for (const [, aa] of additionalActions) {
+ if (aa instanceof Dict && isName(aa.get("S"), "Rendition") && this.#isPlayAction(aa)) {
+ yield aa;
+ }
+ }
+ }
+ }
+ static #isPlayAction(action) {
+ const operation = action.get("OP");
+ return operation === undefined || operation === AnnotationRenditionOperation.PLAY_OR_RESUME || operation === AnnotationRenditionOperation.PLAY;
+ }
+ static #findRenditionAsset(rendition, xref, seen) {
+ if (!(rendition instanceof Dict)) {
+ return null;
+ }
+ const subtype = rendition.get("S");
+ if (isName(subtype, "MR")) {
+ return this.#findClipAsset(rendition.get("C"), xref);
+ }
+ if (isName(subtype, "SR")) {
+ const renditions = rendition.get("R");
+ if (Array.isArray(renditions)) {
+ for (const ref of renditions) {
+ if (ref instanceof Ref) {
+ if (seen.has(ref)) {
+ continue;
+ }
+ seen.put(ref);
+ }
+ const asset = this.#findRenditionAsset(xref.fetchIfRef(ref), xref, seen);
+ if (asset) {
+ return asset;
+ }
+ }
+ }
+ }
+ return null;
+ }
+ static #findClipAsset(clip, xref) {
+ if (!(clip instanceof Dict) || !isName(clip.get("S"), "MCD")) {
+ return null;
+ }
+ const rawData = clip.getRaw("D");
+ const data = xref.fetchIfRef(rawData);
+ const contentTypeHint = clip.get("CT");
+ let explicitType = typeof contentTypeHint === "string" ? contentTypeHint : null;
+ let assetDict, filename;
+ if (data instanceof BaseStream) {
+ assetDict = data.dict;
+ const name = clip.get("N");
+ filename = typeof name === "string" ? stringToPDFString(name) : "";
+ if (!explicitType) {
+ const subtype = data.dict.get("Subtype");
+ if (subtype instanceof Name) {
+ explicitType = subtype.name;
+ }
+ }
+ } else if (data instanceof Dict) {
+ if (!FileSpec.hasEmbeddedFile(data)) {
+ return null;
+ }
+ assetDict = data;
+ ({
+ filename
+ } = new FileSpec(data).serializable);
+ } else {
+ return null;
+ }
+ const contentType = MediaAnnotation._getContentType(assetDict, filename, explicitType);
+ if (!contentType) {
+ return null;
+ }
+ return {
+ assetRef: rawData instanceof Ref ? rawData : null,
+ assetDict,
+ filename,
+ contentType
+ };
+ }
+}
+class SoundAnnotation extends MediaAnnotation {
+ constructor(params) {
+ super(params);
+ const {
+ dict,
+ xref,
+ annotationGlobals
+ } = params;
+ const soundRef = dict.getRaw("Sound");
+ if (!(soundRef instanceof Ref)) {
+ return;
+ }
+ let sound;
+ try {
+ sound = xref.fetch(soundRef);
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`SoundAnnotation: "${ex}".`);
+ return;
+ }
+ if (!(sound instanceof BaseStream) || !getSoundFormat(sound.dict)) {
+ return;
+ }
+ this._setMediaData({
+ assetRef: soundRef,
+ assetDict: sound.dict,
+ filename: "sound.wav",
+ contentType: "audio/wav",
+ wrapSound: true
+ }, annotationGlobals);
+ }
+}
+
+;// ./src/core/calculate_md5.js
+
+
+
+
+
+
+const PARAMS = {
+ get r() {
+ return shadow(this, "r", new Uint8Array([7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]));
+ },
+ get k() {
+ return shadow(this, "k", new Int32Array([-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, 643717713, -373897302, -701558691, 38016083, -660478335, -405537848, 568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784, 1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556, -1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222, -722521979, 76029189, -640364487, -421815835, 530742520, -995338651, -198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606, -1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649, -145523070, -1120210379, 718787259, -343485551]));
+ }
+};
+function calculateMD5(data, offset, length) {
+ let h0 = 1732584193,
+ h1 = -271733879,
+ h2 = -1732584194,
+ h3 = 271733878;
+ const paddedLength = length + 72 & ~63;
+ const padded = new Uint8Array(paddedLength);
+ let i, j;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ const n = paddedLength - 8;
+ if (i < n) {
+ i = n;
+ }
+ padded[i++] = length << 3 & 0xff;
+ padded[i++] = length >> 5 & 0xff;
+ padded[i++] = length >> 13 & 0xff;
+ padded[i++] = length >> 21 & 0xff;
+ padded[i++] = length >>> 29 & 0xff;
+ i += 3;
+ const w = new Int32Array(16);
+ const {
+ k,
+ r
+ } = PARAMS;
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 16; ++j, i += 4) {
+ w[j] = padded[i] | padded[i + 1] << 8 | padded[i + 2] << 16 | padded[i + 3] << 24;
+ }
+ let a = h0,
+ b = h1,
+ c = h2,
+ d = h3,
+ f,
+ g;
+ for (j = 0; j < 64; ++j) {
+ if (j < 16) {
+ f = b & c | ~b & d;
+ g = j;
+ } else if (j < 32) {
+ f = d & b | ~d & c;
+ g = 5 * j + 1 & 15;
+ } else if (j < 48) {
+ f = b ^ c ^ d;
+ g = 3 * j + 5 & 15;
+ } else {
+ f = c ^ (b | ~d);
+ g = 7 * j & 15;
+ }
+ const tmp = d,
+ rotateArg = a + f + k[j] + w[g] | 0,
+ rotate = r[j];
+ d = c;
+ c = b;
+ b = b + (rotateArg << rotate | rotateArg >>> 32 - rotate) | 0;
+ a = tmp;
+ }
+ h0 = h0 + a | 0;
+ h1 = h1 + b | 0;
+ h2 = h2 + c | 0;
+ h3 = h3 + d | 0;
+ }
+ return new Uint8Array([h0 & 0xFF, h0 >> 8 & 0xFF, h0 >> 16 & 0xFF, h0 >>> 24 & 0xFF, h1 & 0xFF, h1 >> 8 & 0xFF, h1 >> 16 & 0xFF, h1 >>> 24 & 0xFF, h2 & 0xFF, h2 >> 8 & 0xFF, h2 >> 16 & 0xFF, h2 >>> 24 & 0xFF, h3 & 0xFF, h3 >> 8 & 0xFF, h3 >> 16 & 0xFF, h3 >>> 24 & 0xFF]);
+}
+
+;// ./src/core/dataset_reader.js
+
+
+
+
+
+function decodeString(str) {
+ try {
+ return stringToUTF8String(str);
+ } catch (ex) {
+ warn(`UTF-8 decoding failed: "${ex}".`);
+ return str;
+ }
+}
+class DatasetXMLParser extends SimpleXMLParser {
+ node = null;
+ onEndElement(name) {
+ const node = super.onEndElement(name);
+ if (node && name === "xfa:datasets") {
+ this.node = node;
+ throw new Error("Aborting DatasetXMLParser.");
+ }
+ }
+}
+class DatasetReader {
+ constructor(data) {
+ if (data.datasets) {
+ this.node = new SimpleXMLParser({
+ hasAttributes: true
+ }).parseFromString(data.datasets).documentElement;
+ } else {
+ const parser = new DatasetXMLParser({
+ hasAttributes: true
+ });
+ try {
+ parser.parseFromString(data["xdp:xdp"]);
+ } catch {}
+ this.node = parser.node;
+ }
+ }
+ getValue(path) {
+ if (!this.node || !path) {
+ return "";
+ }
+ const node = this.node.searchNode(parseXFAPath(path), 0);
+ if (!node) {
+ return "";
+ }
+ const first = node.firstChild;
+ if (first?.nodeName === "value") {
+ return node.children.map(child => decodeString(child.textContent));
+ }
+ return decodeString(node.textContent);
+ }
+}
+
+;// ./src/core/intersector.js
+
+class SingleIntersector {
+ #annotation;
+ minX = Infinity;
+ minY = Infinity;
+ maxX = -Infinity;
+ maxY = -Infinity;
+ #quadPoints = null;
+ #text = [];
+ #extraChars = [];
+ #lastIntersectingQuadIndex = -1;
+ #canTakeExtraChars = false;
+ constructor(annotation) {
+ this.#annotation = annotation;
+ const quadPoints = annotation.data.quadPoints;
+ if (!quadPoints) {
+ [this.minX, this.minY, this.maxX, this.maxY] = annotation.data.rect;
+ return;
+ }
+ for (let i = 0, ii = quadPoints.length; i < ii; i += 8) {
+ this.minX = Math.min(this.minX, quadPoints[i]);
+ this.maxX = Math.max(this.maxX, quadPoints[i + 2]);
+ this.minY = Math.min(this.minY, quadPoints[i + 5]);
+ this.maxY = Math.max(this.maxY, quadPoints[i + 1]);
+ }
+ if (quadPoints.length > 8) {
+ this.#quadPoints = quadPoints;
+ }
+ }
+ #intersects(x, y) {
+ if (this.minX >= x || this.maxX <= x || this.minY >= y || this.maxY <= y) {
+ return false;
+ }
+ const quadPoints = this.#quadPoints;
+ if (!quadPoints) {
+ return true;
+ }
+ if (this.#lastIntersectingQuadIndex >= 0) {
+ const i = this.#lastIntersectingQuadIndex;
+ if (!(quadPoints[i] >= x || quadPoints[i + 2] <= x || quadPoints[i + 5] >= y || quadPoints[i + 1] <= y)) {
+ return true;
+ }
+ this.#lastIntersectingQuadIndex = -1;
+ }
+ for (let i = 0, ii = quadPoints.length; i < ii; i += 8) {
+ if (!(quadPoints[i] >= x || quadPoints[i + 2] <= x || quadPoints[i + 5] >= y || quadPoints[i + 1] <= y)) {
+ this.#lastIntersectingQuadIndex = i;
+ return true;
+ }
+ }
+ return false;
+ }
+ addGlyph(x, y, glyph) {
+ if (!this.#intersects(x, y)) {
+ this.disableExtraChars();
+ return false;
+ }
+ if (this.#extraChars.length > 0) {
+ this.#text.push(this.#extraChars.join(""));
+ this.#extraChars.length = 0;
+ }
+ this.#text.push(glyph);
+ this.#canTakeExtraChars = true;
+ return true;
+ }
+ addExtraChar(char) {
+ if (this.#canTakeExtraChars) {
+ this.#extraChars.push(char);
+ }
+ }
+ disableExtraChars() {
+ if (!this.#canTakeExtraChars) {
+ return;
+ }
+ this.#canTakeExtraChars = false;
+ this.#extraChars.length = 0;
+ }
+ setText() {
+ this.#annotation.data.overlaidText = this.#text.join("");
+ }
+}
+const STEPS = 64;
+class Intersector {
+ #intersectors = [];
+ #grid = [];
+ #minX;
+ #maxX;
+ #minY;
+ #maxY;
+ #invXRatio;
+ #invYRatio;
+ constructor(annotations) {
+ let minX = Infinity;
+ let minY = Infinity;
+ let maxX = -Infinity;
+ let maxY = -Infinity;
+ const intersectors = this.#intersectors;
+ for (const annotation of annotations) {
+ if (!annotation.data.quadPoints && !annotation.data.rect) {
+ continue;
+ }
+ const intersector = new SingleIntersector(annotation);
+ intersectors.push(intersector);
+ minX = Math.min(minX, intersector.minX);
+ minY = Math.min(minY, intersector.minY);
+ maxX = Math.max(maxX, intersector.maxX);
+ maxY = Math.max(maxY, intersector.maxY);
+ }
+ this.#minX = minX;
+ this.#minY = minY;
+ this.#maxX = maxX;
+ this.#maxY = maxY;
+ this.#invXRatio = (STEPS - 1) / (maxX - minX);
+ this.#invYRatio = (STEPS - 1) / (maxY - minY);
+ for (const intersector of intersectors) {
+ const iMin = this.#getGridIndex(intersector.minX, intersector.minY);
+ const iMax = this.#getGridIndex(intersector.maxX, intersector.maxY);
+ const w = (iMax - iMin) % STEPS;
+ const h = Math.floor((iMax - iMin) / STEPS);
+ for (let i = iMin; i <= iMin + h * STEPS; i += STEPS) {
+ for (let j = 0; j <= w; j++) {
+ (this.#grid[i + j] ??= []).push(intersector);
+ }
+ }
+ }
+ }
+ #getGridIndex(x, y) {
+ const i = Math.floor((x - this.#minX) * this.#invXRatio);
+ const j = Math.floor((y - this.#minY) * this.#invYRatio);
+ return i + j * STEPS;
+ }
+ addGlyph(transform, width, height, glyph) {
+ const x = transform[4] + width / 2;
+ const y = transform[5] + height / 2;
+ if (x < this.#minX || y < this.#minY || x > this.#maxX || y > this.#maxY) {
+ return;
+ }
+ const intersectors = this.#grid[this.#getGridIndex(x, y)];
+ if (!intersectors) {
+ return;
+ }
+ for (const intersector of intersectors) {
+ intersector.addGlyph(x, y, glyph);
+ }
+ }
+ addExtraChar(char) {
+ for (const intersector of this.#intersectors) {
+ intersector.addExtraChar(char);
+ }
+ }
+ setText() {
+ for (const intersector of this.#intersectors) {
+ intersector.setText();
+ }
+ }
+}
+
+;// ./src/core/calculate_sha_other.js
+
+
+
+
+
+
+class Word64 {
+ constructor(highInteger, lowInteger) {
+ this.high = highInteger | 0;
+ this.low = lowInteger | 0;
+ }
+ and(word) {
+ this.high &= word.high;
+ this.low &= word.low;
+ }
+ xor(word) {
+ this.high ^= word.high;
+ this.low ^= word.low;
+ }
+ shiftRight(places) {
+ this.low = this.low >>> places | this.high << 32 - places;
+ this.high = this.high >>> places | 0;
+ }
+ rotateRight(places) {
+ let low, high;
+ if (places & 32) {
+ high = this.low;
+ low = this.high;
+ } else {
+ low = this.low;
+ high = this.high;
+ }
+ places &= 31;
+ this.low = low >>> places | high << 32 - places;
+ this.high = high >>> places | low << 32 - places;
+ }
+ not() {
+ this.high = ~this.high;
+ this.low = ~this.low;
+ }
+ add(word) {
+ const lowAdd = (this.low >>> 0) + (word.low >>> 0);
+ let highAdd = (this.high >>> 0) + (word.high >>> 0);
+ if (lowAdd > 0xffffffff) {
+ highAdd += 1;
+ }
+ this.low = lowAdd | 0;
+ this.high = highAdd | 0;
+ }
+ copyTo(bytes, offset) {
+ bytes[offset] = this.high >>> 24 & 0xff;
+ bytes[offset + 1] = this.high >> 16 & 0xff;
+ bytes[offset + 2] = this.high >> 8 & 0xff;
+ bytes[offset + 3] = this.high & 0xff;
+ bytes[offset + 4] = this.low >>> 24 & 0xff;
+ bytes[offset + 5] = this.low >> 16 & 0xff;
+ bytes[offset + 6] = this.low >> 8 & 0xff;
+ bytes[offset + 7] = this.low & 0xff;
+ }
+ assign(word) {
+ this.high = word.high;
+ this.low = word.low;
+ }
+}
+const calculate_sha_other_PARAMS = {
+ get k() {
+ return shadow(this, "k", [new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd), new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc), new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019), new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118), new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe), new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2), new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1), new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694), new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3), new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65), new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483), new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5), new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210), new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4), new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725), new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70), new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926), new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df), new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8), new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b), new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001), new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30), new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910), new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8), new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53), new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8), new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb), new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3), new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60), new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec), new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9), new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b), new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207), new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178), new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6), new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b), new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493), new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c), new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a), new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)]);
+ }
+};
+function ch(result, x, y, z, tmp) {
+ result.assign(x);
+ result.and(y);
+ tmp.assign(x);
+ tmp.not();
+ tmp.and(z);
+ result.xor(tmp);
+}
+function maj(result, x, y, z, tmp) {
+ result.assign(x);
+ result.and(y);
+ tmp.assign(x);
+ tmp.and(z);
+ result.xor(tmp);
+ tmp.assign(y);
+ tmp.and(z);
+ result.xor(tmp);
+}
+function sigma(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(28);
+ tmp.assign(x);
+ tmp.rotateRight(34);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.rotateRight(39);
+ result.xor(tmp);
+}
+function sigmaPrime(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(14);
+ tmp.assign(x);
+ tmp.rotateRight(18);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.rotateRight(41);
+ result.xor(tmp);
+}
+function littleSigma(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(1);
+ tmp.assign(x);
+ tmp.rotateRight(8);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.shiftRight(7);
+ result.xor(tmp);
+}
+function littleSigmaPrime(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(19);
+ tmp.assign(x);
+ tmp.rotateRight(61);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.shiftRight(6);
+ result.xor(tmp);
+}
+function calculateSHA512(data, offset, length, mode384 = false) {
+ let h0, h1, h2, h3, h4, h5, h6, h7;
+ if (!mode384) {
+ h0 = new Word64(0x6a09e667, 0xf3bcc908);
+ h1 = new Word64(0xbb67ae85, 0x84caa73b);
+ h2 = new Word64(0x3c6ef372, 0xfe94f82b);
+ h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
+ h4 = new Word64(0x510e527f, 0xade682d1);
+ h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
+ h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
+ h7 = new Word64(0x5be0cd19, 0x137e2179);
+ } else {
+ h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
+ h1 = new Word64(0x629a292a, 0x367cd507);
+ h2 = new Word64(0x9159015a, 0x3070dd17);
+ h3 = new Word64(0x152fecd8, 0xf70e5939);
+ h4 = new Word64(0x67332667, 0xffc00b31);
+ h5 = new Word64(0x8eb44a87, 0x68581511);
+ h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
+ h7 = new Word64(0x47b5481d, 0xbefa4fa4);
+ }
+ const paddedLength = Math.ceil((length + 17) / 128) * 128;
+ const padded = new Uint8Array(paddedLength);
+ let i, j;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ const n = paddedLength - 16;
+ if (i < n) {
+ i = n;
+ }
+ i += 11;
+ padded[i++] = length >>> 29 & 0xff;
+ padded[i++] = length >> 21 & 0xff;
+ padded[i++] = length >> 13 & 0xff;
+ padded[i++] = length >> 5 & 0xff;
+ padded[i++] = length << 3 & 0xff;
+ const w = new Array(80);
+ for (i = 0; i < 80; i++) {
+ w[i] = new Word64(0, 0);
+ }
+ const {
+ k
+ } = calculate_sha_other_PARAMS;
+ let a = new Word64(0, 0),
+ b = new Word64(0, 0),
+ c = new Word64(0, 0);
+ let d = new Word64(0, 0),
+ e = new Word64(0, 0),
+ f = new Word64(0, 0);
+ let g = new Word64(0, 0),
+ h = new Word64(0, 0);
+ const t1 = new Word64(0, 0),
+ t2 = new Word64(0, 0);
+ const tmp1 = new Word64(0, 0),
+ tmp2 = new Word64(0, 0);
+ let tmp3;
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 16; ++j) {
+ w[j].high = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3];
+ w[j].low = padded[i + 4] << 24 | padded[i + 5] << 16 | padded[i + 6] << 8 | padded[i + 7];
+ i += 8;
+ }
+ for (j = 16; j < 80; ++j) {
+ tmp3 = w[j];
+ littleSigmaPrime(tmp3, w[j - 2], tmp2);
+ tmp3.add(w[j - 7]);
+ littleSigma(tmp1, w[j - 15], tmp2);
+ tmp3.add(tmp1);
+ tmp3.add(w[j - 16]);
+ }
+ a.assign(h0);
+ b.assign(h1);
+ c.assign(h2);
+ d.assign(h3);
+ e.assign(h4);
+ f.assign(h5);
+ g.assign(h6);
+ h.assign(h7);
+ for (j = 0; j < 80; ++j) {
+ t1.assign(h);
+ sigmaPrime(tmp1, e, tmp2);
+ t1.add(tmp1);
+ ch(tmp1, e, f, g, tmp2);
+ t1.add(tmp1);
+ t1.add(k[j]);
+ t1.add(w[j]);
+ sigma(t2, a, tmp2);
+ maj(tmp1, a, b, c, tmp2);
+ t2.add(tmp1);
+ tmp3 = h;
+ h = g;
+ g = f;
+ f = e;
+ d.add(t1);
+ e = d;
+ d = c;
+ c = b;
+ b = a;
+ tmp3.assign(t1);
+ tmp3.add(t2);
+ a = tmp3;
+ }
+ h0.add(a);
+ h1.add(b);
+ h2.add(c);
+ h3.add(d);
+ h4.add(e);
+ h5.add(f);
+ h6.add(g);
+ h7.add(h);
+ }
+ let result;
+ if (!mode384) {
+ result = new Uint8Array(64);
+ h0.copyTo(result, 0);
+ h1.copyTo(result, 8);
+ h2.copyTo(result, 16);
+ h3.copyTo(result, 24);
+ h4.copyTo(result, 32);
+ h5.copyTo(result, 40);
+ h6.copyTo(result, 48);
+ h7.copyTo(result, 56);
+ } else {
+ result = new Uint8Array(48);
+ h0.copyTo(result, 0);
+ h1.copyTo(result, 8);
+ h2.copyTo(result, 16);
+ h3.copyTo(result, 24);
+ h4.copyTo(result, 32);
+ h5.copyTo(result, 40);
+ }
+ return result;
+}
+function calculateSHA384(data, offset, length) {
+ return calculateSHA512(data, offset, length, true);
+}
+
+;// ./src/core/calculate_sha256.js
+
+
+
+
+
+
+const calculate_sha256_PARAMS = {
+ get k() {
+ return shadow(this, "k", [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]);
+ }
+};
+function rotr(x, n) {
+ return x >>> n | x << 32 - n;
+}
+function calculate_sha256_ch(x, y, z) {
+ return x & y ^ ~x & z;
+}
+function calculate_sha256_maj(x, y, z) {
+ return x & y ^ x & z ^ y & z;
+}
+function calculate_sha256_sigma(x) {
+ return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
+}
+function calculate_sha256_sigmaPrime(x) {
+ return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
+}
+function calculate_sha256_littleSigma(x) {
+ return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;
+}
+function calculate_sha256_littleSigmaPrime(x) {
+ return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;
+}
+function calculateSHA256(data, offset, length) {
+ let h0 = 0x6a09e667,
+ h1 = 0xbb67ae85,
+ h2 = 0x3c6ef372,
+ h3 = 0xa54ff53a,
+ h4 = 0x510e527f,
+ h5 = 0x9b05688c,
+ h6 = 0x1f83d9ab,
+ h7 = 0x5be0cd19;
+ const paddedLength = Math.ceil((length + 9) / 64) * 64;
+ const padded = new Uint8Array(paddedLength);
+ let i, j;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ const n = paddedLength - 8;
+ if (i < n) {
+ i = n;
+ }
+ i += 3;
+ padded[i++] = length >>> 29 & 0xff;
+ padded[i++] = length >> 21 & 0xff;
+ padded[i++] = length >> 13 & 0xff;
+ padded[i++] = length >> 5 & 0xff;
+ padded[i++] = length << 3 & 0xff;
+ const w = new Uint32Array(64);
+ const {
+ k
+ } = calculate_sha256_PARAMS;
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 16; ++j) {
+ w[j] = padded[i] << 24 | padded[i + 1] << 16 | padded[i + 2] << 8 | padded[i + 3];
+ i += 4;
+ }
+ for (j = 16; j < 64; ++j) {
+ w[j] = calculate_sha256_littleSigmaPrime(w[j - 2]) + w[j - 7] + calculate_sha256_littleSigma(w[j - 15]) + w[j - 16] | 0;
+ }
+ let a = h0,
+ b = h1,
+ c = h2,
+ d = h3,
+ e = h4,
+ f = h5,
+ g = h6,
+ h = h7,
+ t1,
+ t2;
+ for (j = 0; j < 64; ++j) {
+ t1 = h + calculate_sha256_sigmaPrime(e) + calculate_sha256_ch(e, f, g) + k[j] + w[j];
+ t2 = calculate_sha256_sigma(a) + calculate_sha256_maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1 | 0;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2 | 0;
+ }
+ h0 = h0 + a | 0;
+ h1 = h1 + b | 0;
+ h2 = h2 + c | 0;
+ h3 = h3 + d | 0;
+ h4 = h4 + e | 0;
+ h5 = h5 + f | 0;
+ h6 = h6 + g | 0;
+ h7 = h7 + h | 0;
+ }
+ return new Uint8Array([h0 >> 24 & 0xFF, h0 >> 16 & 0xFF, h0 >> 8 & 0xFF, h0 & 0xFF, h1 >> 24 & 0xFF, h1 >> 16 & 0xFF, h1 >> 8 & 0xFF, h1 & 0xFF, h2 >> 24 & 0xFF, h2 >> 16 & 0xFF, h2 >> 8 & 0xFF, h2 & 0xFF, h3 >> 24 & 0xFF, h3 >> 16 & 0xFF, h3 >> 8 & 0xFF, h3 & 0xFF, h4 >> 24 & 0xFF, h4 >> 16 & 0xFF, h4 >> 8 & 0xFF, h4 & 0xFF, h5 >> 24 & 0xFF, h5 >> 16 & 0xFF, h5 >> 8 & 0xFF, h5 & 0xFF, h6 >> 24 & 0xFF, h6 >> 16 & 0xFF, h6 >> 8 & 0xFF, h6 & 0xFF, h7 >> 24 & 0xFF, h7 >> 16 & 0xFF, h7 >> 8 & 0xFF, h7 & 0xFF]);
+}
+
+;// ./src/core/decrypt_stream.js
+
+const chunkSize = 512;
+class DecryptStream extends DecodeStream {
+ #nextChunk = null;
+ constructor(str, maybeLength, decrypt) {
+ super(maybeLength);
+ this.stream = str;
+ this.dict = str.dict;
+ this.decrypt = decrypt;
+ }
+ readBlock() {
+ let chunk = this.#nextChunk ?? this.stream.getBytes(chunkSize);
+ if (!chunk.length) {
+ this.eof = true;
+ return;
+ }
+ this.#nextChunk = this.stream.getBytes(chunkSize);
+ const hasMoreData = this.#nextChunk.length > 0;
+ const decrypt = this.decrypt;
+ chunk = decrypt(chunk, !hasMoreData);
+ const bufferLength = this.bufferLength,
+ newLength = bufferLength + chunk.length,
+ buffer = this.ensureBuffer(newLength);
+ buffer.set(chunk, bufferLength);
+ this.bufferLength = newLength;
+ }
+ getOriginalStream() {
+ return this;
+ }
+}
+
+;// ./src/core/sasl_prep.js
+
+
+
+
+
+
+
+const NON_ASCII_SPACES = new Set([0x00a0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, 0x200b, 0x202f, 0x205f, 0x3000]);
+const COMMONLY_MAPPED_TO_NOTHING = new Set([0x00ad, 0x034f, 0x1806, 0x180b, 0x180c, 0x180d, 0x200b, 0x200c, 0x200d, 0x2060, 0xfe00, 0xfe01, 0xfe02, 0xfe03, 0xfe04, 0xfe05, 0xfe06, 0xfe07, 0xfe08, 0xfe09, 0xfe0a, 0xfe0b, 0xfe0c, 0xfe0d, 0xfe0e, 0xfe0f, 0xfeff]);
+function saslPrep(str) {
+ let mapped = "";
+ for (const char of str) {
+ const code = char.codePointAt(0);
+ if (NON_ASCII_SPACES.has(code)) {
+ mapped += " ";
+ } else if (!COMMONLY_MAPPED_TO_NOTHING.has(code)) {
+ mapped += char;
+ }
+ }
+ return mapped.normalize("NFKC");
+}
+
+;// ./src/core/crypto.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class ARCFourCipher {
+ a = 0;
+ b = 0;
+ constructor(key) {
+ const s = new Uint8Array(256);
+ const keyLength = key.length;
+ for (let i = 0; i < 256; ++i) {
+ s[i] = i;
+ }
+ for (let i = 0, j = 0; i < 256; ++i) {
+ const tmp = s[i];
+ j = j + tmp + key[i % keyLength] & 0xff;
+ s[i] = s[j];
+ s[j] = tmp;
+ }
+ this.s = s;
+ }
+ encryptBlock(data) {
+ let a = this.a,
+ b = this.b;
+ const s = this.s;
+ const n = data.length;
+ const output = new Uint8Array(n);
+ for (let i = 0; i < n; ++i) {
+ a = a + 1 & 0xff;
+ const tmp = s[a];
+ b = b + tmp & 0xff;
+ const tmp2 = s[b];
+ s[a] = tmp2;
+ s[b] = tmp;
+ output[i] = data[i] ^ s[tmp + tmp2 & 0xff];
+ }
+ this.a = a;
+ this.b = b;
+ return output;
+ }
+ decryptBlock(data) {
+ return this.encryptBlock(data);
+ }
+ encrypt(data) {
+ return this.encryptBlock(data);
+ }
+}
+class NullCipher {
+ decryptBlock(data) {
+ return data;
+ }
+ encrypt(data) {
+ return data;
+ }
+}
+class AESBaseCipher {
+ _s = new Uint8Array([0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]);
+ _inv_s = new Uint8Array([0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]);
+ _mix = new Uint32Array([0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
+ _mixCol = Uint8Array.from({
+ length: 256
+ }, (_, i) => i < 128 ? i << 1 : i << 1 ^ 0x1b);
+ constructor() {
+ this.buffer = new Uint8Array(16);
+ this.bufferPosition = 0;
+ }
+ _expandKey(cipherKey) {
+ unreachable("Cannot call `_expandKey` on the base class");
+ }
+ _decrypt(input, key) {
+ let t, u, v;
+ const state = new Uint8Array(16);
+ state.set(input);
+ for (let j = 0, k = this._keySize; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ for (let i = this._cyclesOfRepetition - 1; i >= 1; --i) {
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
+ for (let j = 0; j < 16; ++j) {
+ state[j] = this._inv_s[state[j]];
+ }
+ for (let j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ for (let j = 0; j < 16; j += 4) {
+ const s0 = this._mix[state[j]];
+ const s1 = this._mix[state[j + 1]];
+ const s2 = this._mix[state[j + 2]];
+ const s3 = this._mix[state[j + 3]];
+ t = s0 ^ s1 >>> 8 ^ s1 << 24 ^ s2 >>> 16 ^ s2 << 16 ^ s3 >>> 24 ^ s3 << 8;
+ state[j] = t >>> 24 & 0xff;
+ state[j + 1] = t >> 16 & 0xff;
+ state[j + 2] = t >> 8 & 0xff;
+ state[j + 3] = t & 0xff;
+ }
+ }
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
+ for (let j = 0; j < 16; ++j) {
+ state[j] = this._inv_s[state[j]];
+ state[j] ^= key[j];
+ }
+ return state;
+ }
+ _encrypt(input, key) {
+ const s = this._s;
+ let t, u, v;
+ const state = new Uint8Array(16);
+ state.set(input);
+ for (let j = 0; j < 16; ++j) {
+ state[j] ^= key[j];
+ }
+ for (let i = 1; i < this._cyclesOfRepetition; i++) {
+ for (let j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ for (let j = 0; j < 16; j += 4) {
+ const s0 = state[j];
+ const s1 = state[j + 1];
+ const s2 = state[j + 2];
+ const s3 = state[j + 3];
+ t = s0 ^ s1 ^ s2 ^ s3;
+ state[j] ^= t ^ this._mixCol[s0 ^ s1];
+ state[j + 1] ^= t ^ this._mixCol[s1 ^ s2];
+ state[j + 2] ^= t ^ this._mixCol[s2 ^ s3];
+ state[j + 3] ^= t ^ this._mixCol[s3 ^ s0];
+ }
+ for (let j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ }
+ for (let j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ for (let j = 0, k = this._keySize; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ return state;
+ }
+ _decryptBlock2(data, finalize) {
+ const sourceLength = data.length;
+ let buffer = this.buffer,
+ bufferLength = this.bufferPosition;
+ const result = [];
+ let iv = this.iv;
+ for (let i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ const plain = this._decrypt(buffer, this._key);
+ for (let j = 0; j < 16; ++j) {
+ plain[j] ^= iv[j];
+ }
+ iv = buffer;
+ result.push(plain);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array(0);
+ }
+ let outputLength = 16 * result.length;
+ if (finalize) {
+ const lastBlock = result.at(-1);
+ let psLen = lastBlock[15];
+ if (psLen <= 16) {
+ for (let i = 15, ii = 16 - psLen; i >= ii; --i) {
+ if (lastBlock[i] !== psLen) {
+ psLen = 0;
+ break;
+ }
+ }
+ outputLength -= psLen;
+ result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
+ }
+ }
+ const output = new Uint8Array(outputLength);
+ for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
+ }
+ decryptBlock(data, finalize, iv = null) {
+ const sourceLength = data.length;
+ const buffer = this.buffer;
+ let bufferLength = this.bufferPosition;
+ if (iv) {
+ this.iv = iv;
+ } else {
+ for (let i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
+ buffer[bufferLength] = data[i];
+ }
+ if (bufferLength < 16) {
+ this.bufferLength = bufferLength;
+ return new Uint8Array(0);
+ }
+ this.iv = buffer;
+ data = data.subarray(16);
+ }
+ this.buffer = new Uint8Array(16);
+ this.bufferLength = 0;
+ this.decryptBlock = this._decryptBlock2;
+ return this.decryptBlock(data, finalize);
+ }
+ encrypt(data, iv) {
+ const sourceLength = data.length;
+ let buffer = this.buffer,
+ bufferLength = this.bufferPosition;
+ const result = [];
+ iv ||= new Uint8Array(16);
+ for (let i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ for (let j = 0; j < 16; ++j) {
+ buffer[j] ^= iv[j];
+ }
+ const cipher = this._encrypt(buffer, this._key);
+ iv = cipher;
+ result.push(cipher);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array(0);
+ }
+ const outputLength = 16 * result.length;
+ const output = new Uint8Array(outputLength);
+ for (let i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
+ }
+}
+class AES128Cipher extends AESBaseCipher {
+ _rcon = new Uint8Array([0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d]);
+ constructor(key) {
+ super();
+ this._cyclesOfRepetition = 10;
+ this._keySize = 160;
+ this._key = this._expandKey(key);
+ }
+ _expandKey(cipherKey) {
+ const b = 176;
+ const s = this._s;
+ const rcon = this._rcon;
+ const result = new Uint8Array(b);
+ result.set(cipherKey);
+ for (let j = 16, i = 1; j < b; ++i) {
+ let t1 = result[j - 3];
+ let t2 = result[j - 2];
+ let t3 = result[j - 1];
+ let t4 = result[j - 4];
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ t1 ^= rcon[i];
+ for (let n = 0; n < 4; ++n) {
+ result[j] = t1 ^= result[j - 16];
+ j++;
+ result[j] = t2 ^= result[j - 16];
+ j++;
+ result[j] = t3 ^= result[j - 16];
+ j++;
+ result[j] = t4 ^= result[j - 16];
+ j++;
+ }
+ }
+ return result;
+ }
+}
+class AES256Cipher extends AESBaseCipher {
+ constructor(key) {
+ super();
+ this._cyclesOfRepetition = 14;
+ this._keySize = 224;
+ this._key = this._expandKey(key);
+ }
+ _expandKey(cipherKey) {
+ const b = 240;
+ const s = this._s;
+ const result = new Uint8Array(b);
+ result.set(cipherKey);
+ let r = 1;
+ let t1, t2, t3, t4;
+ for (let j = 32, i = 1; j < b; ++i) {
+ if (j % 32 === 16) {
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ } else if (j % 32 === 0) {
+ t1 = result[j - 3];
+ t2 = result[j - 2];
+ t3 = result[j - 1];
+ t4 = result[j - 4];
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ t1 ^= r;
+ if ((r <<= 1) >= 256) {
+ r = (r ^ 0x1b) & 0xff;
+ }
+ }
+ for (let n = 0; n < 4; ++n) {
+ result[j] = t1 ^= result[j - 32];
+ j++;
+ result[j] = t2 ^= result[j - 32];
+ j++;
+ result[j] = t3 ^= result[j - 32];
+ j++;
+ result[j] = t4 ^= result[j - 32];
+ j++;
+ }
+ }
+ return result;
+ }
+}
+class PDFBase {
+ _hash(password, input, userBytes) {
+ unreachable("Abstract method `_hash` called");
+ }
+ checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) {
+ const hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerValidationSalt, password.length);
+ hashData.set(userBytes, password.length + ownerValidationSalt.length);
+ const result = this._hash(password, hashData, userBytes);
+ return isArrayEqual(result, ownerPassword);
+ }
+ checkUserPassword(password, userValidationSalt, userPassword) {
+ const hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userValidationSalt, password.length);
+ const result = this._hash(password, hashData, []);
+ return isArrayEqual(result, userPassword);
+ }
+ getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) {
+ const hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerKeySalt, password.length);
+ hashData.set(userBytes, password.length + ownerKeySalt.length);
+ const key = this._hash(password, hashData, userBytes);
+ const cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
+ }
+ getUserKey(password, userKeySalt, userEncryption) {
+ const hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userKeySalt, password.length);
+ const key = this._hash(password, hashData, []);
+ const cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
+ }
+}
+class PDF17 extends PDFBase {
+ _hash(password, input, userBytes) {
+ return calculateSHA256(input, 0, input.length);
+ }
+}
+class PDF20 extends PDFBase {
+ _hash(password, input, userBytes) {
+ let k = calculateSHA256(input, 0, input.length).subarray(0, 32);
+ let e = [0];
+ let i = 0;
+ while (i < 64 || e.at(-1) > i - 32) {
+ const combinedLength = password.length + k.length + userBytes.length,
+ combinedArray = new Uint8Array(combinedLength);
+ let writeOffset = 0;
+ combinedArray.set(password, writeOffset);
+ writeOffset += password.length;
+ combinedArray.set(k, writeOffset);
+ writeOffset += k.length;
+ combinedArray.set(userBytes, writeOffset);
+ const k1 = new Uint8Array(combinedLength * 64);
+ for (let j = 0, pos = 0; j < 64; j++, pos += combinedLength) {
+ k1.set(combinedArray, pos);
+ }
+ const cipher = new AES128Cipher(k.subarray(0, 16));
+ e = cipher.encrypt(k1, k.subarray(16, 32));
+ const remainder = Math.sumPrecise(e.slice(0, 16)) % 3;
+ if (remainder === 0) {
+ k = calculateSHA256(e, 0, e.length);
+ } else if (remainder === 1) {
+ k = calculateSHA384(e, 0, e.length);
+ } else if (remainder === 2) {
+ k = calculateSHA512(e, 0, e.length);
+ }
+ i++;
+ }
+ return k.subarray(0, 32);
+ }
+}
+class CipherTransform {
+ #cipherCache = new Map();
+ embeddedFilterName = null;
+ constructor(resolveCipher, stringFilterName = null, streamFilterName = null) {
+ this.resolveCipher = resolveCipher;
+ this.streamFilterName = streamFilterName;
+ this.stringFilterName = stringFilterName;
+ }
+ #getCipher(filterName = null) {
+ const key = filterName instanceof Name ? filterName.name : "__default__";
+ return this.#cipherCache.getOrInsertComputed(key, () => this.resolveCipher(filterName));
+ }
+ createStream(stream, length, cryptFilterName = null) {
+ const defaultFilterName = this.embeddedFilterName && isDict(stream.dict, "EmbeddedFile") ? this.embeddedFilterName : this.streamFilterName;
+ const Cipher = this.#getCipher(cryptFilterName || defaultFilterName);
+ const cipher = new Cipher();
+ return new DecryptStream(stream, length, function cipherTransformDecryptStream(data, finalize) {
+ return cipher.decryptBlock(data, finalize);
+ });
+ }
+ decryptString(s) {
+ const Cipher = this.#getCipher(this.stringFilterName);
+ const cipher = new Cipher();
+ let data = stringToBytes(s);
+ data = cipher.decryptBlock(data, true);
+ return bytesToString(data);
+ }
+ encryptString(s) {
+ const Cipher = this.#getCipher(this.stringFilterName);
+ const cipher = new Cipher();
+ if (cipher instanceof AESBaseCipher) {
+ const strLen = s.length;
+ const pad = 16 - strLen % 16;
+ s += String.fromCharCode(pad).repeat(pad);
+ const iv = new Uint8Array(16);
+ crypto.getRandomValues(iv);
+ let data = stringToBytes(s);
+ data = cipher.encrypt(data, iv);
+ const buf = new Uint8Array(16 + data.length);
+ buf.set(iv);
+ buf.set(data, 16);
+ return bytesToString(buf);
+ }
+ let data = stringToBytes(s);
+ data = cipher.encrypt(data);
+ return bytesToString(data);
+ }
+}
+function utf8PasswordToBytes(password) {
+ try {
+ password = utf8StringToString(password);
+ } catch {
+ warn("CipherTransformFactory: Unable to convert UTF8 encoded password.");
+ }
+ return stringToBytes(password);
+}
+class CipherTransformFactory {
+ #fileId;
+ static get _defaultPasswordBytes() {
+ return shadow(this, "_defaultPasswordBytes", new Uint8Array([0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a]));
+ }
+ #createEncryptionKey20(revision, password, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms) {
+ if (password) {
+ const passwordLength = Math.min(127, password.length);
+ password = password.subarray(0, passwordLength);
+ } else {
+ password = [];
+ }
+ const pdfAlgorithm = revision === 6 ? new PDF20() : new PDF17();
+ if (pdfAlgorithm.checkUserPassword(password, userValidationSalt, userPassword)) {
+ return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
+ } else if (password.length && pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt, uBytes, ownerPassword)) {
+ return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes, ownerEncryption);
+ }
+ return null;
+ }
+ #prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata) {
+ const hashDataSize = 40 + ownerPassword.length + fileId.length;
+ const hashData = new Uint8Array(hashDataSize);
+ let i = 0,
+ j,
+ n;
+ if (password) {
+ n = Math.min(32, password.length);
+ for (; i < n; ++i) {
+ hashData[i] = password[i];
+ }
+ }
+ j = 0;
+ while (i < 32) {
+ hashData[i++] = CipherTransformFactory._defaultPasswordBytes[j++];
+ }
+ hashData.set(ownerPassword, i);
+ i += ownerPassword.length;
+ hashData[i++] = flags & 0xff;
+ hashData[i++] = flags >> 8 & 0xff;
+ hashData[i++] = flags >> 16 & 0xff;
+ hashData[i++] = flags >>> 24 & 0xff;
+ hashData.set(fileId, i);
+ i += fileId.length;
+ if (revision >= 4 && !encryptMetadata) {
+ hashData.fill(0xff, i, i + 4);
+ i += 4;
+ }
+ let hash = calculateMD5(hashData, 0, i);
+ const keyLengthInBytes = keyLength >> 3;
+ if (revision >= 3) {
+ for (j = 0; j < 50; ++j) {
+ hash = calculateMD5(hash, 0, keyLengthInBytes);
+ }
+ }
+ const encryptionKey = hash.subarray(0, keyLengthInBytes);
+ let cipher, checkData;
+ if (revision >= 3) {
+ i = 0;
+ hashData.set(CipherTransformFactory._defaultPasswordBytes, i);
+ i += 32;
+ hashData.set(fileId, i);
+ i += fileId.length;
+ cipher = new ARCFourCipher(encryptionKey);
+ checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
+ n = encryptionKey.length;
+ const derivedKey = new Uint8Array(n);
+ for (j = 1; j <= 19; ++j) {
+ for (let k = 0; k < n; ++k) {
+ derivedKey[k] = encryptionKey[k] ^ j;
+ }
+ cipher = new ARCFourCipher(derivedKey);
+ checkData = cipher.encryptBlock(checkData);
+ }
+ } else {
+ cipher = new ARCFourCipher(encryptionKey);
+ checkData = cipher.encryptBlock(CipherTransformFactory._defaultPasswordBytes);
+ }
+ return checkData.every((data, k) => userPassword[k] === data) ? encryptionKey : null;
+ }
+ #decodeUserPassword(password, ownerPassword, revision, keyLength) {
+ const hashData = new Uint8Array(32);
+ let i = 0;
+ const n = Math.min(32, password.length);
+ for (; i < n; ++i) {
+ hashData[i] = password[i];
+ }
+ let j = 0;
+ while (i < 32) {
+ hashData[i++] = CipherTransformFactory._defaultPasswordBytes[j++];
+ }
+ let hash = calculateMD5(hashData, 0, i);
+ const keyLengthInBytes = keyLength >> 3;
+ if (revision >= 3) {
+ for (j = 0; j < 50; ++j) {
+ hash = calculateMD5(hash, 0, hash.length);
+ }
+ }
+ let cipher, userPassword;
+ if (revision >= 3) {
+ userPassword = ownerPassword;
+ const derivedKey = new Uint8Array(keyLengthInBytes);
+ for (j = 19; j >= 0; j--) {
+ for (let k = 0; k < keyLengthInBytes; ++k) {
+ derivedKey[k] = hash[k] ^ j;
+ }
+ cipher = new ARCFourCipher(derivedKey);
+ userPassword = cipher.encryptBlock(userPassword);
+ }
+ } else {
+ cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
+ userPassword = cipher.encryptBlock(ownerPassword);
+ }
+ return userPassword;
+ }
+ #buildObjectKey(num, gen, encryptionKey, isAes = false) {
+ const n = encryptionKey.length;
+ const key = new Uint8Array(n + 9);
+ key.set(encryptionKey);
+ let i = n;
+ key[i++] = num & 0xff;
+ key[i++] = num >> 8 & 0xff;
+ key[i++] = num >> 16 & 0xff;
+ key[i++] = gen & 0xff;
+ key[i++] = gen >> 8 & 0xff;
+ if (isAes) {
+ key[i++] = 0x73;
+ key[i++] = 0x41;
+ key[i++] = 0x6c;
+ key[i++] = 0x54;
+ }
+ const hash = calculateMD5(key, 0, i);
+ return hash.subarray(0, Math.min(n + 5, 16));
+ }
+ constructor(dict, fileId, password) {
+ const filter = dict.get("Filter");
+ if (!isName(filter, "Standard")) {
+ throw new FormatError("unknown encryption method");
+ }
+ this.filterName = filter.name;
+ this.dict = dict;
+ this.#fileId = fileId;
+ const algorithm = dict.get("V");
+ if (!Number.isInteger(algorithm) || algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5) {
+ throw new FormatError("unsupported encryption algorithm");
+ }
+ this.algorithm = algorithm;
+ let keyLength = dict.get("Length");
+ if (!keyLength) {
+ if (algorithm <= 3) {
+ keyLength = 40;
+ } else {
+ const cfDict = dict.get("CF");
+ const streamCryptoName = dict.get("StmF");
+ if (cfDict instanceof Dict && streamCryptoName instanceof Name) {
+ cfDict.suppressEncryption = true;
+ const handlerDict = cfDict.get(streamCryptoName.name);
+ keyLength = handlerDict?.get("Length") || 128;
+ if (keyLength < 40) {
+ keyLength <<= 3;
+ }
+ }
+ }
+ }
+ if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) {
+ throw new FormatError("invalid key length");
+ }
+ let cf = null;
+ let stmf = Name.get("Identity");
+ let strf = Name.get("Identity");
+ let eff = stmf;
+ if (algorithm >= 4) {
+ cf = dict.get("CF");
+ if (cf instanceof Dict) {
+ cf.suppressEncryption = true;
+ }
+ stmf = dict.get("StmF") || Name.get("Identity");
+ strf = dict.get("StrF") || Name.get("Identity");
+ eff = dict.get("EFF") || stmf;
+ }
+ this.cf = cf;
+ this.stmf = stmf;
+ this.strf = strf;
+ this.eff = eff;
+ const ownerBytes = stringToBytes(dict.get("O")),
+ userBytes = stringToBytes(dict.get("U"));
+ const ownerPassword = ownerBytes.subarray(0, 32);
+ const userPassword = userBytes.subarray(0, 32);
+ const flags = dict.get("P");
+ const revision = dict.get("R");
+ const encryptMetadata = (algorithm === 4 || algorithm === 5) && dict.get("EncryptMetadata") !== false;
+ this.encryptMetadata = encryptMetadata;
+ const fileIdBytes = stringToBytes(fileId);
+ let passwordBytes, rawPasswordBytes;
+ if (password) {
+ if (revision === 6) {
+ const preppedPassword = saslPrep(password);
+ passwordBytes = utf8PasswordToBytes(preppedPassword);
+ if (preppedPassword !== password) {
+ rawPasswordBytes = utf8PasswordToBytes(password);
+ }
+ } else if (algorithm === 5) {
+ passwordBytes = utf8PasswordToBytes(password);
+ } else {
+ passwordBytes = stringToBytes(password);
+ }
+ }
+ let encryptionKey;
+ if (algorithm !== 5) {
+ encryptionKey = this.#prepareKeyData(fileIdBytes, passwordBytes, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata);
+ } else {
+ const ownerValidationSalt = ownerBytes.subarray(32, 40);
+ const ownerKeySalt = ownerBytes.subarray(40, 48);
+ const uBytes = userBytes.subarray(0, 48);
+ const userValidationSalt = userBytes.subarray(32, 40);
+ const userKeySalt = userBytes.subarray(40, 48);
+ const ownerEncryption = stringToBytes(dict.get("OE"));
+ const userEncryption = stringToBytes(dict.get("UE"));
+ const perms = stringToBytes(dict.get("Perms"));
+ for (const candidate of rawPasswordBytes ? [passwordBytes, rawPasswordBytes] : [passwordBytes]) {
+ encryptionKey = this.#createEncryptionKey20(revision, candidate, ownerPassword, ownerValidationSalt, ownerKeySalt, uBytes, userPassword, userValidationSalt, userKeySalt, ownerEncryption, userEncryption, perms);
+ if (encryptionKey) {
+ break;
+ }
+ }
+ }
+ if (!encryptionKey) {
+ if (!password) {
+ if (this.algorithm >= 4 && isName(this.stmf, "Identity") && isName(this.strf, "Identity")) {
+ const effCF = this.cf?.get(this.eff.name);
+ const authEvent = effCF?.get("AuthEvent");
+ if (isName(authEvent, "EFOpen")) {
+ this.encryptionKey = null;
+ return;
+ }
+ }
+ throw new PasswordException("No password given", PasswordResponses.NEED_PASSWORD);
+ }
+ const decodedPassword = this.#decodeUserPassword(passwordBytes, ownerPassword, revision, keyLength);
+ encryptionKey = this.#prepareKeyData(fileIdBytes, decodedPassword, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata);
+ }
+ if (!encryptionKey) {
+ throw new PasswordException("Incorrect Password", PasswordResponses.INCORRECT_PASSWORD);
+ }
+ if (algorithm === 4 && encryptionKey.length < 16) {
+ this.encryptionKey = new Uint8Array(16);
+ this.encryptionKey.set(encryptionKey);
+ } else {
+ this.encryptionKey = encryptionKey;
+ }
+ }
+ setPassword(password) {
+ const transform = new CipherTransformFactory(this.dict, this.#fileId, password);
+ this.encryptionKey = transform.encryptionKey;
+ }
+ createCipherTransform(num, gen) {
+ if (this.algorithm === 4 || this.algorithm === 5) {
+ const resolveCipher = filterName => {
+ if (!(filterName instanceof Name)) {
+ throw new FormatError("Invalid crypt filter name.");
+ }
+ const cryptFilter = this.cf.get(filterName.name);
+ const cfm = cryptFilter?.get("CFM");
+ if (!cfm || cfm.name === "None") {
+ return NullCipher;
+ }
+ if (!this.encryptionKey) {
+ throw new PasswordException("No password given", PasswordResponses.NEED_PASSWORD);
+ }
+ if (this.algorithm === 5 || cfm.name === "AESV3") {
+ return AES256Cipher.bind(null, this.encryptionKey);
+ }
+ if (cfm.name === "V2") {
+ return ARCFourCipher.bind(null, this.#buildObjectKey(num, gen, this.encryptionKey, false));
+ }
+ if (cfm.name === "AESV2") {
+ return AES128Cipher.bind(null, this.#buildObjectKey(num, gen, this.encryptionKey, true));
+ }
+ throw new FormatError("Unknown crypto method");
+ };
+ const transform = new CipherTransform(resolveCipher, this.strf, this.stmf);
+ transform.embeddedFilterName = this.eff;
+ return transform;
+ }
+ const resolveCipher = () => ARCFourCipher.bind(null, this.#buildObjectKey(num, gen, this.encryptionKey, false));
+ return new CipherTransform(resolveCipher);
+ }
+}
+
+;// ./src/core/xref.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class XRef {
+ #cacheMap = new Map();
+ #entries = [];
+ #newPersistentRefNum = null;
+ #newTemporaryRefNum = null;
+ #parsedWithRecovery = false;
+ #pendingRefs = new RefSet();
+ #persistentRefsCache = null;
+ #xrefSectionOffsets = new Set();
+ #xrefSectionsComplete = true;
+ #xrefStms = new Set();
+ constructor(stream, pdfManager) {
+ this.stream = stream;
+ this.pdfManager = pdfManager;
+ }
+ getNewPersistentRef(obj) {
+ if (this.#newPersistentRefNum === null) {
+ this.#newPersistentRefNum = this.#entries.length || 1;
+ }
+ const num = this.#newPersistentRefNum++;
+ this.#cacheMap.set(num, obj);
+ return Ref.get(num, 0);
+ }
+ getNewTemporaryRef() {
+ if (this.#newTemporaryRefNum === null) {
+ this.#newTemporaryRefNum = this.#entries.length || 1;
+ if (this.#newPersistentRefNum) {
+ this.#persistentRefsCache = new Map();
+ for (let i = this.#newTemporaryRefNum; i < this.#newPersistentRefNum; i++) {
+ this.#persistentRefsCache.set(i, this.#cacheMap.get(i));
+ this.#cacheMap.delete(i);
+ }
+ }
+ }
+ return Ref.get(this.#newTemporaryRefNum++, 0);
+ }
+ resetNewTemporaryRef() {
+ this.#newTemporaryRefNum = null;
+ if (this.#persistentRefsCache) {
+ for (const [num, obj] of this.#persistentRefsCache) {
+ this.#cacheMap.set(num, obj);
+ }
+ }
+ this.#persistentRefsCache = null;
+ }
+ setStartXRef(startXRef) {
+ this.startXRefQueue = [startXRef];
+ }
+ parse(recoveryMode = false) {
+ this.#parsedWithRecovery = recoveryMode;
+ let trailerDict;
+ if (!recoveryMode) {
+ trailerDict = this.readXRef();
+ } else {
+ warn("Indexing all PDF objects");
+ trailerDict = this.indexObjects();
+ }
+ trailerDict.assignXref(this);
+ this.trailer = trailerDict;
+ let encrypt;
+ try {
+ encrypt = trailerDict.get("Encrypt");
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`XRef.parse - Invalid "Encrypt" reference: "${ex}".`);
+ }
+ if (encrypt instanceof Dict) {
+ const ids = trailerDict.get("ID");
+ const fileId = ids?.length ? ids[0] : "";
+ encrypt.suppressEncryption = true;
+ this.encrypt = new CipherTransformFactory(encrypt, fileId, this.pdfManager.password);
+ }
+ let root;
+ try {
+ root = trailerDict.get("Root");
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`XRef.parse - Invalid "Root" reference: "${ex}".`);
+ }
+ if (root instanceof Dict) {
+ try {
+ const pages = root.get("Pages");
+ if (pages instanceof Dict) {
+ this.root = root;
+ return;
+ }
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`XRef.parse - Invalid "Pages" reference: "${ex}".`);
+ }
+ }
+ if (!recoveryMode) {
+ throw new XRefParseException();
+ }
+ throw new InvalidPDFException("Invalid Root reference.");
+ }
+ processXRefTable(parser) {
+ this._tableState ??= {
+ entryNum: 0,
+ streamPos: parser.lexer.stream.pos,
+ parserBuf1: parser.buf1,
+ parserBuf2: parser.buf2
+ };
+ const obj = this.readXRefTable(parser);
+ if (!isCmd(obj, "trailer")) {
+ throw new FormatError("Invalid XRef table: could not find trailer dictionary");
+ }
+ let dict = parser.getObj();
+ if (dict instanceof BaseStream) {
+ dict = dict.dict;
+ }
+ if (!(dict instanceof Dict)) {
+ throw new FormatError("Invalid XRef table: could not parse trailer dictionary");
+ }
+ delete this._tableState;
+ return dict;
+ }
+ readXRefTable(parser) {
+ const stream = parser.lexer.stream;
+ const tableState = this._tableState;
+ stream.pos = tableState.streamPos;
+ parser.buf1 = tableState.parserBuf1;
+ parser.buf2 = tableState.parserBuf2;
+ let obj;
+ while (true) {
+ if (!("firstEntryNum" in tableState) || !("entryCount" in tableState)) {
+ if (isCmd(obj = parser.getObj(), "trailer")) {
+ break;
+ }
+ tableState.firstEntryNum = obj;
+ tableState.entryCount = parser.getObj();
+ }
+ let first = tableState.firstEntryNum;
+ const count = tableState.entryCount;
+ if (!Number.isInteger(first) || !Number.isInteger(count)) {
+ throw new FormatError("Invalid XRef table: wrong types in subsection header");
+ }
+ for (let i = tableState.entryNum; i < count; i++) {
+ tableState.streamPos = stream.pos;
+ tableState.entryNum = i;
+ tableState.parserBuf1 = parser.buf1;
+ tableState.parserBuf2 = parser.buf2;
+ const entry = {
+ offset: parser.getObj(),
+ gen: parser.getObj(),
+ free: false,
+ uncompressed: false
+ };
+ const type = parser.getObj();
+ if (type instanceof Cmd) {
+ switch (type.cmd) {
+ case "f":
+ entry.free = true;
+ break;
+ case "n":
+ entry.uncompressed = true;
+ break;
+ }
+ }
+ if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.gen) || !(entry.free || entry.uncompressed)) {
+ throw new FormatError(`Invalid entry in XRef subsection: ${first}, ${count}`);
+ }
+ if (i === 0 && entry.free && first === 1) {
+ first = 0;
+ }
+ this.#entries[first + i] ??= entry;
+ }
+ tableState.entryNum = 0;
+ tableState.streamPos = stream.pos;
+ tableState.parserBuf1 = parser.buf1;
+ tableState.parserBuf2 = parser.buf2;
+ delete tableState.firstEntryNum;
+ delete tableState.entryCount;
+ }
+ if (this.#entries[0] && !this.#entries[0].free) {
+ throw new FormatError("Invalid XRef table: unexpected first object");
+ }
+ return obj;
+ }
+ processXRefStream(stream) {
+ if (!("streamState" in this)) {
+ const {
+ dict,
+ pos
+ } = stream;
+ const byteWidths = dict.get("W");
+ const range = dict.get("Index") || [0, dict.get("Size")];
+ this.streamState = {
+ entryRanges: range,
+ byteWidths,
+ entryNum: 0,
+ streamPos: pos
+ };
+ }
+ this.readXRefStream(stream);
+ delete this.streamState;
+ return stream.dict;
+ }
+ readXRefStream(stream) {
+ const streamState = this.streamState;
+ stream.pos = streamState.streamPos;
+ const [typeFieldWidth, offsetFieldWidth, generationFieldWidth] = streamState.byteWidths;
+ const entryRanges = streamState.entryRanges;
+ while (entryRanges.length > 0) {
+ const [first, n] = entryRanges;
+ if (!Number.isInteger(first) || !Number.isInteger(n)) {
+ throw new FormatError(`Invalid XRef range fields: ${first}, ${n}`);
+ }
+ if (!Number.isInteger(typeFieldWidth) || !Number.isInteger(offsetFieldWidth) || !Number.isInteger(generationFieldWidth)) {
+ throw new FormatError(`Invalid XRef entry fields length: ${first}, ${n}`);
+ }
+ for (let i = streamState.entryNum; i < n; ++i) {
+ streamState.entryNum = i;
+ streamState.streamPos = stream.pos;
+ let type = 0,
+ offset = 0,
+ generation = 0;
+ for (let j = 0; j < typeFieldWidth; ++j) {
+ const typeByte = stream.getByte();
+ if (typeByte === -1) {
+ throw new FormatError("Invalid XRef byteWidths 'type'.");
+ }
+ type = type << 8 | typeByte;
+ }
+ if (typeFieldWidth === 0) {
+ type = 1;
+ }
+ for (let j = 0; j < offsetFieldWidth; ++j) {
+ const offsetByte = stream.getByte();
+ if (offsetByte === -1) {
+ throw new FormatError("Invalid XRef byteWidths 'offset'.");
+ }
+ offset = offset << 8 | offsetByte;
+ }
+ for (let j = 0; j < generationFieldWidth; ++j) {
+ const generationByte = stream.getByte();
+ if (generationByte === -1) {
+ throw new FormatError("Invalid XRef byteWidths 'generation'.");
+ }
+ generation = generation << 8 | generationByte;
+ }
+ const entry = {
+ offset,
+ gen: generation,
+ free: false,
+ uncompressed: false
+ };
+ switch (type) {
+ case 0:
+ entry.free = true;
+ break;
+ case 1:
+ entry.uncompressed = true;
+ break;
+ case 2:
+ break;
+ default:
+ throw new FormatError(`Invalid XRef entry type: ${type}`);
+ }
+ this.#entries[first + i] ??= entry;
+ }
+ streamState.entryNum = 0;
+ streamState.streamPos = stream.pos;
+ entryRanges.splice(0, 2);
+ }
+ }
+ indexObjects() {
+ const TAB = 0x9,
+ LF = 0xa,
+ CR = 0xd,
+ SPACE = 0x20;
+ const PERCENT = 0x25,
+ LT = 0x3c;
+ function readToken(data, offset) {
+ let token = "",
+ ch = data[offset];
+ while (ch !== LF && ch !== CR && ch !== LT) {
+ if (++offset >= data.length) {
+ break;
+ }
+ token += String.fromCharCode(ch);
+ ch = data[offset];
+ }
+ return token;
+ }
+ function skipUntil(data, offset, what) {
+ const length = what.length,
+ dataLength = data.length;
+ let skipped = 0;
+ while (offset < dataLength) {
+ let i = 0;
+ while (i < length && data[offset + i] === what[i]) {
+ ++i;
+ }
+ if (i >= length) {
+ break;
+ }
+ offset++;
+ skipped++;
+ }
+ return skipped;
+ }
+ const gEndobjRegExp = /\b(endobj|\d+\s+\d+\s+obj|xref|trailer\s*<<)\b/g;
+ const gStartxrefRegExp = /\b(startxref|\d+\s+\d+\s+obj)\b/g;
+ const objRegExp = /^(\d+)\s+(\d+)\s+obj\b/;
+ const trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
+ const startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]);
+ const xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
+ this.#entries.length = 0;
+ this.#cacheMap.clear();
+ const stream = this.stream;
+ stream.pos = 0;
+ const buffer = stream.getBytes(),
+ bufferStr = bytesToString(buffer),
+ length = buffer.length;
+ let position = stream.start;
+ const trailers = [],
+ xrefStms = [];
+ while (position < length) {
+ let ch = buffer[position];
+ if (ch === TAB || ch === LF || ch === CR || ch === SPACE) {
+ ++position;
+ continue;
+ }
+ if (ch === PERCENT) {
+ do {
+ ++position;
+ if (position >= length) {
+ break;
+ }
+ ch = buffer[position];
+ } while (ch !== LF && ch !== CR);
+ continue;
+ }
+ const token = readToken(buffer, position);
+ let m;
+ if (token.startsWith("xref") && (token.length === 4 || /\s/.test(token[4]))) {
+ position += skipUntil(buffer, position, trailerBytes);
+ trailers.push(position);
+ position += skipUntil(buffer, position, startxrefBytes);
+ } else if (m = objRegExp.exec(token)) {
+ const num = m[1] | 0,
+ gen = m[2] | 0;
+ const startPos = position + token.length;
+ let contentLength,
+ updateEntries = false;
+ if (!this.#entries[num]) {
+ updateEntries = true;
+ } else if (this.#entries[num].gen === gen) {
+ try {
+ const parser = new Parser({
+ lexer: new Lexer(stream.makeSubStream(startPos))
+ });
+ parser.getObj();
+ updateEntries = true;
+ } catch (ex) {
+ if (ex instanceof ParserEOFException) {
+ warn(`indexObjects -- checking object (${token}): "${ex}".`);
+ } else {
+ updateEntries = true;
+ }
+ }
+ }
+ if (updateEntries) {
+ this.#entries[num] = {
+ offset: position - stream.start,
+ gen,
+ free: false,
+ uncompressed: true
+ };
+ }
+ gEndobjRegExp.lastIndex = startPos;
+ const match = gEndobjRegExp.exec(bufferStr);
+ if (match) {
+ const endPos = gEndobjRegExp.lastIndex + 1;
+ contentLength = endPos - position;
+ if (match[1] !== "endobj") {
+ warn(`indexObjects: Found "${match[1]}" inside of another "obj", ` + 'caused by missing "endobj" -- trying to recover.');
+ contentLength -= match[1].length + 1;
+ }
+ } else {
+ contentLength = length - position;
+ }
+ const content = buffer.subarray(position, position + contentLength);
+ const xrefTagOffset = skipUntil(content, 0, xrefBytes);
+ if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) {
+ xrefStms.push(position - stream.start);
+ this.#xrefStms.add(position - stream.start);
+ }
+ position += contentLength;
+ } else if (token.startsWith("trailer") && (token.length === 7 || /\s/.test(token[7]))) {
+ trailers.push(position);
+ const startPos = position + token.length;
+ let contentLength;
+ gStartxrefRegExp.lastIndex = startPos;
+ const match = gStartxrefRegExp.exec(bufferStr);
+ if (match) {
+ const endPos = gStartxrefRegExp.lastIndex + 1;
+ contentLength = endPos - position;
+ if (match[1] !== "startxref") {
+ warn(`indexObjects: Found "${match[1]}" after "trailer", ` + 'caused by missing "startxref" -- trying to recover.');
+ contentLength -= match[1].length + 1;
+ }
+ } else {
+ contentLength = length - position;
+ }
+ position += contentLength;
+ } else {
+ position += token.length + 1;
+ }
+ }
+ for (const xrefStm of xrefStms) {
+ this.startXRefQueue.push(xrefStm);
+ this.readXRef(true);
+ }
+ const trailerDicts = [];
+ let isEncrypted = false;
+ for (const trailer of trailers) {
+ stream.pos = trailer;
+ const parser = new Parser({
+ lexer: new Lexer(stream),
+ xref: this,
+ allowStreams: true,
+ recoveryMode: true
+ });
+ const obj = parser.getObj();
+ if (!isCmd(obj, "trailer")) {
+ continue;
+ }
+ const dict = parser.getObj();
+ if (!(dict instanceof Dict)) {
+ continue;
+ }
+ trailerDicts.push(dict);
+ if (dict.has("Encrypt")) {
+ isEncrypted = true;
+ }
+ }
+ let trailerDict, trailerError;
+ for (const dict of [...trailerDicts, "genFallback", ...trailerDicts]) {
+ if (dict === "genFallback") {
+ if (!trailerError) {
+ break;
+ }
+ this._generationFallback = true;
+ continue;
+ }
+ let validPagesDict = false;
+ try {
+ const rootDict = dict.get("Root");
+ if (!(rootDict instanceof Dict)) {
+ continue;
+ }
+ const pagesDict = rootDict.get("Pages");
+ if (!(pagesDict instanceof Dict)) {
+ continue;
+ }
+ const pagesCount = pagesDict.get("Count");
+ if (Number.isInteger(pagesCount)) {
+ validPagesDict = true;
+ }
+ } catch (ex) {
+ trailerError = ex;
+ continue;
+ }
+ if (validPagesDict && (!isEncrypted || dict.has("Encrypt")) && dict.has("ID")) {
+ return dict;
+ }
+ trailerDict = dict;
+ }
+ if (trailerDict) {
+ return trailerDict;
+ }
+ if (this.topDict) {
+ return this.topDict;
+ }
+ if (!trailerDicts.length) {
+ for (const num in this.#entries) {
+ const entry = this.#entries[num];
+ if (!entry) {
+ continue;
+ }
+ const ref = Ref.get(parseInt(num, 10), entry.gen);
+ let obj;
+ try {
+ obj = this.fetch(ref);
+ } catch {
+ continue;
+ }
+ if (obj instanceof BaseStream) {
+ obj = obj.dict;
+ }
+ if (obj instanceof Dict && obj.has("Root")) {
+ return obj;
+ }
+ }
+ }
+ throw new InvalidPDFException("Invalid PDF structure.");
+ }
+ readXRef(recoveryMode = false) {
+ const stream = this.stream;
+ const startXRefParsedCache = new Set();
+ while (this.startXRefQueue.length) {
+ try {
+ const startXRef = this.startXRefQueue[0];
+ if (startXRefParsedCache.has(startXRef)) {
+ warn("readXRef - skipping XRef table since it was already parsed.");
+ this.startXRefQueue.shift();
+ continue;
+ }
+ startXRefParsedCache.add(startXRef);
+ stream.pos = startXRef + stream.start;
+ const parser = new Parser({
+ lexer: new Lexer(stream),
+ xref: this,
+ allowStreams: true
+ });
+ let obj = parser.getObj();
+ let dict;
+ if (isCmd(obj, "xref")) {
+ dict = this.processXRefTable(parser);
+ this.topDict ||= dict;
+ obj = dict.get("XRefStm");
+ if (Number.isInteger(obj) && !this.#xrefStms.has(obj)) {
+ this.#xrefStms.add(obj);
+ this.startXRefQueue.push(obj);
+ }
+ } else if (Number.isInteger(obj)) {
+ if (!Number.isInteger(parser.getObj()) || !isCmd(parser.getObj(), "obj") || !((obj = parser.getObj()) instanceof BaseStream)) {
+ throw new FormatError("Invalid XRef stream");
+ }
+ dict = this.processXRefStream(obj);
+ this.topDict ||= dict;
+ if (!dict) {
+ throw new FormatError("Failed to read XRef stream");
+ }
+ } else {
+ throw new FormatError("Invalid XRef stream header");
+ }
+ this.#xrefSectionOffsets.add(startXRef);
+ obj = dict.get("Prev");
+ if (Number.isInteger(obj)) {
+ this.startXRefQueue.push(obj);
+ } else if (obj instanceof Ref) {
+ this.startXRefQueue.push(obj.num);
+ }
+ } catch (e) {
+ if (e instanceof MissingDataException) {
+ throw e;
+ }
+ this.#xrefSectionsComplete = false;
+ info("(while reading XRef): " + e);
+ }
+ this.startXRefQueue.shift();
+ }
+ if (this.topDict) {
+ return this.topDict;
+ }
+ if (recoveryMode) {
+ return undefined;
+ }
+ throw new XRefParseException();
+ }
+ countUpdatesAfter(offset) {
+ if (this.#parsedWithRecovery || !this.#xrefSectionsComplete) {
+ return null;
+ }
+ const relativeOffset = offset - this.stream.start;
+ let count = 0;
+ for (const sectionOffset of this.#xrefSectionOffsets) {
+ if (sectionOffset >= relativeOffset && !this.#xrefStms.has(sectionOffset)) {
+ count++;
+ }
+ }
+ return count;
+ }
+ getEntry(i) {
+ const entry = this.#entries[i];
+ return entry && !entry.free && entry.offset ? entry : null;
+ }
+ fetchIfRef(obj, suppressEncryption = false) {
+ return obj instanceof Ref ? this.fetch(obj, suppressEncryption) : obj;
+ }
+ fetch(ref, suppressEncryption = false) {
+ if (!(ref instanceof Ref)) {
+ throw new Error("ref object is not a reference");
+ }
+ const num = ref.num;
+ const cacheEntry = this.#cacheMap.get(num);
+ if (cacheEntry !== undefined) {
+ if (cacheEntry instanceof Dict && !cacheEntry.objId) {
+ cacheEntry.objId = ref.toString();
+ }
+ return cacheEntry;
+ }
+ let xrefEntry = this.getEntry(num);
+ if (xrefEntry === null) {
+ return xrefEntry;
+ }
+ if (this.#pendingRefs.has(ref)) {
+ this.#pendingRefs.remove(ref);
+ warn(`Ignoring circular reference: ${ref}.`);
+ return CIRCULAR_REF;
+ }
+ this.#pendingRefs.put(ref);
+ try {
+ xrefEntry = xrefEntry.uncompressed ? this.fetchUncompressed(ref, xrefEntry, suppressEncryption) : this.fetchCompressed(ref, xrefEntry, suppressEncryption);
+ this.#pendingRefs.remove(ref);
+ } catch (ex) {
+ this.#pendingRefs.remove(ref);
+ throw ex;
+ }
+ if (xrefEntry instanceof Dict) {
+ xrefEntry.objId = ref.toString();
+ } else if (xrefEntry instanceof BaseStream) {
+ xrefEntry.dict.objId = ref.toString();
+ }
+ return xrefEntry;
+ }
+ fetchUncompressed(ref, xrefEntry, suppressEncryption = false) {
+ const gen = ref.gen;
+ let num = ref.num;
+ if (xrefEntry.gen !== gen) {
+ const msg = `Inconsistent generation in XRef: ${ref}`;
+ if (this._generationFallback && xrefEntry.gen < gen) {
+ warn(msg);
+ return this.fetchUncompressed(Ref.get(num, xrefEntry.gen), xrefEntry, suppressEncryption);
+ }
+ throw new XRefEntryException(msg);
+ }
+ const stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start);
+ const parser = new Parser({
+ lexer: new Lexer(stream),
+ xref: this,
+ allowStreams: true
+ });
+ const obj1 = parser.getObj();
+ const obj2 = parser.getObj();
+ const obj3 = parser.getObj();
+ if (obj1 !== num || obj2 !== gen || !(obj3 instanceof Cmd)) {
+ throw new XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
+ }
+ if (obj3.cmd !== "obj") {
+ if (obj3.cmd.startsWith("obj")) {
+ num = parseInt(obj3.cmd.substring(3), 10);
+ if (!Number.isNaN(num)) {
+ return num;
+ }
+ }
+ throw new XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
+ }
+ xrefEntry = this.encrypt && !suppressEncryption ? parser.getObj(this.encrypt.createCipherTransform(num, gen)) : parser.getObj();
+ if (!(xrefEntry instanceof BaseStream)) {
+ this.#cacheMap.set(num, xrefEntry);
+ }
+ return xrefEntry;
+ }
+ fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
+ const tableOffset = xrefEntry.offset;
+ const stream = this.fetch(Ref.get(tableOffset, 0));
+ if (!(stream instanceof BaseStream)) {
+ throw new FormatError("bad ObjStm stream");
+ }
+ const first = stream.dict.get("First");
+ const n = stream.dict.get("N");
+ if (!Number.isInteger(first) || !Number.isInteger(n)) {
+ throw new FormatError("invalid first and n parameters for ObjStm stream");
+ }
+ let parser = new Parser({
+ lexer: new Lexer(stream),
+ xref: this,
+ allowStreams: true
+ });
+ const nums = new Array(n);
+ const offsets = new Array(n);
+ for (let i = 0; i < n; ++i) {
+ const num = parser.getObj();
+ if (!Number.isInteger(num)) {
+ throw new FormatError(`invalid object number in the ObjStm stream: ${num}`);
+ }
+ const offset = parser.getObj();
+ if (!Number.isInteger(offset)) {
+ throw new FormatError(`invalid object offset in the ObjStm stream: ${offset}`);
+ }
+ nums[i] = num;
+ const entry = this.getEntry(num);
+ if (entry?.offset === tableOffset && entry.gen !== i) {
+ entry.gen = i;
+ }
+ offsets[i] = offset;
+ }
+ const start = (stream.start || 0) + first;
+ const entries = new Array(n);
+ for (let i = 0; i < n; ++i) {
+ const length = i < n - 1 ? offsets[i + 1] - offsets[i] : undefined;
+ if (length < 0) {
+ throw new FormatError("Invalid offset in the ObjStm stream.");
+ }
+ parser = new Parser({
+ lexer: new Lexer(stream.makeSubStream(start + offsets[i], length, stream.dict)),
+ xref: this,
+ allowStreams: true
+ });
+ const obj = parser.getObj();
+ entries[i] = obj;
+ if (obj instanceof BaseStream) {
+ continue;
+ }
+ const num = nums[i],
+ entry = this.#entries[num];
+ if (entry && entry.offset === tableOffset && entry.gen === i) {
+ this.#cacheMap.set(num, obj);
+ }
+ }
+ xrefEntry = entries[xrefEntry.gen];
+ if (xrefEntry === undefined) {
+ throw new XRefEntryException(`Bad (compressed) XRef entry: ${ref}`);
+ }
+ return xrefEntry;
+ }
+ async fetchIfRefAsync(obj, suppressEncryption) {
+ return obj instanceof Ref ? this.fetchAsync(obj, suppressEncryption) : obj;
+ }
+ async fetchAsync(ref, suppressEncryption) {
+ try {
+ return this.fetch(ref, suppressEncryption);
+ } catch (ex) {
+ if (!(ex instanceof MissingDataException)) {
+ throw ex;
+ }
+ await this.pdfManager.requestRange(ex.begin, ex.end);
+ return this.fetchAsync(ref, suppressEncryption);
+ }
+ }
+ getCatalogObj() {
+ return this.root;
+ }
+}
+
+;// ./src/core/document.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
+const SIGNATURE_TAIL_CHUNK_SIZE = 65536;
+class Page {
+ #resourcesPromise = null;
+ constructor({
+ pdfManager,
+ xref,
+ pageIndex,
+ pageDict,
+ ref,
+ globalIdFactory,
+ fontCache,
+ builtInCMapCache,
+ standardFontDataCache,
+ globalColorSpaceCache,
+ globalImageCache,
+ systemFontCache,
+ nonBlendModesSet,
+ xfaFactory
+ }) {
+ this.pdfManager = pdfManager;
+ this.pageIndex = pageIndex;
+ this.pageDict = pageDict;
+ this.xref = xref;
+ this.ref = ref;
+ this.fontCache = fontCache;
+ this.builtInCMapCache = builtInCMapCache;
+ this.standardFontDataCache = standardFontDataCache;
+ this.globalColorSpaceCache = globalColorSpaceCache;
+ this.globalImageCache = globalImageCache;
+ this.systemFontCache = systemFontCache;
+ this.nonBlendModesSet = nonBlendModesSet;
+ this.evaluatorOptions = pdfManager.evaluatorOptions;
+ this.xfaFactory = xfaFactory;
+ const idCounters = {
+ obj: 0
+ };
+ this._localIdFactory = class extends globalIdFactory {
+ static createObjId() {
+ return `p${pageIndex}_${++idCounters.obj}`;
+ }
+ static getPageObjId() {
+ return `p${ref.toString()}`;
+ }
+ };
+ }
+ _createPartialEvaluator(handler, pageIndex = this.pageIndex) {
+ return new PartialEvaluator({
+ xref: this.xref,
+ handler,
+ pageIndex,
+ idFactory: this._localIdFactory,
+ fontCache: this.fontCache,
+ builtInCMapCache: this.builtInCMapCache,
+ standardFontDataCache: this.standardFontDataCache,
+ globalColorSpaceCache: this.globalColorSpaceCache,
+ globalImageCache: this.globalImageCache,
+ systemFontCache: this.systemFontCache,
+ options: this.evaluatorOptions
+ });
+ }
+ #getInheritableProperty(key, getArray = false) {
+ const value = getInheritableProperty({
+ dict: this.pageDict,
+ key,
+ getArray,
+ stopWhenFound: false
+ });
+ if (!Array.isArray(value)) {
+ return value;
+ }
+ if (value.length === 1 || !(value[0] instanceof Dict)) {
+ return value[0];
+ }
+ return Dict.merge({
+ xref: this.xref,
+ dictArray: value
+ });
+ }
+ get content() {
+ return this.pageDict.getArray("Contents");
+ }
+ get resources() {
+ const resources = this.#getInheritableProperty("Resources");
+ return shadow(this, "resources", resources instanceof Dict ? resources : Dict.empty);
+ }
+ getBoundingBox(name) {
+ if (this.xfaData) {
+ return this.xfaData.bbox;
+ }
+ const box = lookupNormalRect(this.#getInheritableProperty(name, true), null);
+ if (box) {
+ if (box[2] - box[0] > 0 && box[3] - box[1] > 0) {
+ return box;
+ }
+ warn(`Empty, or invalid, /${name} entry.`);
+ }
+ return null;
+ }
+ get mediaBox() {
+ return shadow(this, "mediaBox", this.getBoundingBox("MediaBox") || LETTER_SIZE_MEDIABOX);
+ }
+ get cropBox() {
+ return shadow(this, "cropBox", this.getBoundingBox("CropBox") || this.mediaBox);
+ }
+ get userUnit() {
+ const obj = this.pageDict.get("UserUnit");
+ return shadow(this, "userUnit", typeof obj === "number" && obj > 0 ? obj : 1.0);
+ }
+ get view() {
+ const {
+ cropBox,
+ mediaBox
+ } = this;
+ if (cropBox !== mediaBox && !isArrayEqual(cropBox, mediaBox)) {
+ const box = Util.intersect(cropBox, mediaBox);
+ if (box && box[2] - box[0] > 0 && box[3] - box[1] > 0) {
+ return shadow(this, "view", box);
+ }
+ warn("Empty /CropBox and /MediaBox intersection.");
+ }
+ return shadow(this, "view", mediaBox);
+ }
+ get rotate() {
+ let rotate = this.#getInheritableProperty("Rotate") || 0;
+ if (rotate % 90 !== 0) {
+ rotate = 0;
+ } else if (rotate >= 360) {
+ rotate %= 360;
+ } else if (rotate < 0) {
+ rotate = (rotate % 360 + 360) % 360;
+ }
+ return shadow(this, "rotate", rotate);
+ }
+ #onSubStreamError(reason, objId) {
+ if (this.evaluatorOptions.ignoreErrors) {
+ warn(`getContentStream - ignoring sub-stream (${objId}): "${reason}".`);
+ return;
+ }
+ throw reason;
+ }
+ async getContentStream() {
+ const content = await this.pdfManager.ensure(this, "content");
+ if (content instanceof BaseStream && !content.isImageStream) {
+ if (content.isAsync) {
+ const bytes = await content.asyncGetBytes();
+ if (bytes) {
+ return new Stream(bytes, 0, bytes.length, content.dict);
+ }
+ }
+ return content;
+ }
+ if (Array.isArray(content)) {
+ const promises = [];
+ for (let i = 0, ii = content.length; i < ii; i++) {
+ const item = content[i];
+ if (item instanceof BaseStream && item.isAsync) {
+ promises.push(item.asyncGetBytes().then(bytes => {
+ if (bytes) {
+ content[i] = new Stream(bytes, 0, bytes.length, item.dict);
+ }
+ }));
+ }
+ }
+ if (promises.length > 0) {
+ await Promise.all(promises);
+ }
+ return new StreamsSequenceStream(content, this.#onSubStreamError.bind(this));
+ }
+ return new NullStream();
+ }
+ get xfaData() {
+ return shadow(this, "xfaData", this.xfaFactory ? {
+ bbox: this.xfaFactory.getBoundingBox(this.pageIndex)
+ } : null);
+ }
+ async #replaceIdByRef(annotations, deletedAnnotations, existingAnnotations) {
+ const promises = [];
+ for (const annotation of annotations) {
+ if (!annotation.id) {
+ continue;
+ }
+ const ref = Ref.fromString(annotation.id);
+ if (!ref) {
+ warn(`A non-linked annotation cannot be modified: ${annotation.id}`);
+ continue;
+ }
+ if (annotation.deleted) {
+ deletedAnnotations.put(ref);
+ if (annotation.popupRef) {
+ const popupRef = Ref.fromString(annotation.popupRef);
+ if (popupRef) {
+ deletedAnnotations.put(popupRef);
+ }
+ }
+ continue;
+ }
+ if (annotation.popup?.deleted) {
+ const popupRef = Ref.fromString(annotation.popupRef);
+ if (popupRef) {
+ deletedAnnotations.put(popupRef);
+ }
+ }
+ existingAnnotations?.put(ref);
+ annotation.ref = ref;
+ promises.push(this.xref.fetchAsync(ref).then(obj => {
+ if (obj instanceof Dict) {
+ annotation.oldAnnotation = obj.clone();
+ }
+ }, () => {
+ warn(`Cannot fetch \`oldAnnotation\` for: ${ref}.`);
+ }));
+ delete annotation.id;
+ }
+ await Promise.all(promises);
+ }
+ async saveNewAnnotations(handler, task, annotations, imagePromises, changes) {
+ if (this.xfaFactory) {
+ throw new Error("XFA: Cannot save new annotations.");
+ }
+ const partialEvaluator = this._createPartialEvaluator(handler);
+ const deletedAnnotations = new RefSet();
+ const existingAnnotations = new RefSet();
+ await this.#replaceIdByRef(annotations, deletedAnnotations, existingAnnotations);
+ const pageDict = this.pageDict;
+ const annotationsArray = this.annotations.filter(a => !(a instanceof Ref && deletedAnnotations.has(a)));
+ const newData = await AnnotationFactory.saveNewAnnotations(partialEvaluator, this.xref, task, annotations, imagePromises, changes);
+ for (const {
+ ref
+ } of newData.annotations) {
+ if (ref instanceof Ref && !existingAnnotations.has(ref)) {
+ annotationsArray.push(ref);
+ }
+ }
+ const dict = pageDict.clone();
+ dict.set("Annots", annotationsArray);
+ changes.put(this.ref, {
+ data: dict
+ });
+ for (const deletedRef of deletedAnnotations) {
+ changes.put(deletedRef, {
+ data: null
+ });
+ }
+ }
+ async save(handler, task, annotationStorage, changes) {
+ const partialEvaluator = this._createPartialEvaluator(handler);
+ const annotations = await this._parsedAnnotations;
+ const promises = [];
+ for (const annotation of annotations) {
+ promises.push(annotation.save(partialEvaluator, task, annotationStorage, changes).catch(function (reason) {
+ warn("save - ignoring annotation data during " + `"${task.name}" task: "${reason}".`);
+ return null;
+ }));
+ }
+ return Promise.all(promises);
+ }
+ async loadResources(keys) {
+ await (this.#resourcesPromise ??= this.pdfManager.ensure(this, "resources"));
+ await ObjectLoader.load(this.resources, keys, this.xref);
+ }
+ async #getMergedResources(streamDict, keys) {
+ const localResources = streamDict?.get("Resources");
+ if (!(localResources instanceof Dict && localResources.size)) {
+ return this.resources;
+ }
+ await ObjectLoader.load(localResources, keys, this.xref);
+ return Dict.merge({
+ xref: this.xref,
+ dictArray: [localResources, this.resources],
+ mergeSubDicts: true
+ });
+ }
+ async getOperatorList({
+ handler,
+ sink,
+ task,
+ intent,
+ cacheKey,
+ pageIndex = this.pageIndex,
+ annotationStorage = null,
+ modifiedIds = null
+ }) {
+ const contentStreamPromise = this.getContentStream();
+ const resourcesPromise = this.loadResources(RESOURCES_KEYS_OPERATOR_LIST);
+ const partialEvaluator = this._createPartialEvaluator(handler, pageIndex);
+ const newAnnotsByPage = !this.xfaFactory ? getNewAnnotationsMap(annotationStorage) : null;
+ const newAnnots = newAnnotsByPage?.get(this.pageIndex);
+ let newAnnotationsPromise = Promise.resolve(null);
+ let deletedAnnotations = null;
+ if (newAnnots) {
+ const annotationGlobalsPromise = this.pdfManager.ensureDoc("annotationGlobals");
+ let imagePromises;
+ const missingBitmaps = new Set();
+ for (const {
+ bitmapId,
+ bitmap
+ } of newAnnots) {
+ if (bitmapId && !bitmap && !missingBitmaps.has(bitmapId)) {
+ missingBitmaps.add(bitmapId);
+ }
+ }
+ const {
+ isOffscreenCanvasSupported
+ } = this.evaluatorOptions;
+ if (missingBitmaps.size > 0) {
+ const annotationWithBitmaps = newAnnots.slice();
+ for (const [key, annotation] of annotationStorage) {
+ if (!key.startsWith(AnnotationEditorPrefix)) {
+ continue;
+ }
+ if (annotation.bitmap && missingBitmaps.has(annotation.bitmapId)) {
+ annotationWithBitmaps.push(annotation);
+ }
+ }
+ imagePromises = AnnotationFactory.generateImages(annotationWithBitmaps, this.xref, isOffscreenCanvasSupported);
+ } else {
+ imagePromises = AnnotationFactory.generateImages(newAnnots, this.xref, isOffscreenCanvasSupported);
+ }
+ deletedAnnotations = new RefSet();
+ newAnnotationsPromise = Promise.all([annotationGlobalsPromise, this.#replaceIdByRef(newAnnots, deletedAnnotations, null)]).then(([annotationGlobals]) => {
+ if (!annotationGlobals) {
+ return null;
+ }
+ return AnnotationFactory.printNewAnnotations(annotationGlobals, partialEvaluator, task, newAnnots, imagePromises);
+ });
+ }
+ const pageListPromise = Promise.all([contentStreamPromise, resourcesPromise]).then(async ([contentStream]) => {
+ const resources = await this.#getMergedResources(contentStream.dict, RESOURCES_KEYS_OPERATOR_LIST);
+ const opList = new OperatorList(intent, sink);
+ handler.send("StartRenderPage", {
+ transparency: partialEvaluator.hasBlendModes(resources, this.nonBlendModesSet),
+ pageIndex,
+ cacheKey
+ });
+ await partialEvaluator.getOperatorList({
+ stream: contentStream,
+ task,
+ resources,
+ operatorList: opList
+ });
+ return opList;
+ });
+ let [pageOpList, annotations, newAnnotations] = await Promise.all([pageListPromise, this._parsedAnnotations, newAnnotationsPromise]);
+ if (newAnnotations) {
+ annotations = annotations.filter(a => !(a.ref && deletedAnnotations.has(a.ref)));
+ for (let i = 0, ii = newAnnotations.length; i < ii; i++) {
+ const newAnnotation = newAnnotations[i];
+ if (newAnnotation.refToReplace) {
+ const j = annotations.findIndex(a => a.ref && isRefsEqual(a.ref, newAnnotation.refToReplace));
+ if (j >= 0) {
+ annotations.splice(j, 1, newAnnotation);
+ newAnnotations.splice(i--, 1);
+ ii--;
+ }
+ }
+ }
+ annotations = annotations.concat(newAnnotations);
+ }
+ if (annotations.length === 0 || intent & RenderingIntentFlag.ANNOTATIONS_DISABLE) {
+ pageOpList.flush(true);
+ return {
+ length: pageOpList.totalLength
+ };
+ }
+ const renderForms = !!(intent & RenderingIntentFlag.ANNOTATIONS_FORMS),
+ isEditing = !!(intent & RenderingIntentFlag.IS_EDITING),
+ intentAny = !!(intent & RenderingIntentFlag.ANY),
+ intentDisplay = !!(intent & RenderingIntentFlag.DISPLAY),
+ intentPrint = !!(intent & RenderingIntentFlag.PRINT);
+ const opListPromises = [];
+ for (const annotation of annotations) {
+ if (intentAny || intentDisplay && annotation.mustBeViewed(annotationStorage, renderForms) && annotation.mustBeViewedWhenEditing(isEditing, modifiedIds) || intentPrint && annotation.mustBePrinted(annotationStorage)) {
+ opListPromises.push(annotation.getOperatorList(partialEvaluator, task, intent, annotationStorage).catch(function (reason) {
+ warn("getOperatorList - ignoring annotation data during " + `"${task.name}" task: "${reason}".`);
+ return {
+ opList: null,
+ separateForm: false,
+ separateCanvas: false
+ };
+ }));
+ }
+ }
+ const opLists = await Promise.all(opListPromises);
+ let form = false,
+ canvas = false;
+ for (const {
+ opList,
+ separateForm,
+ separateCanvas
+ } of opLists) {
+ pageOpList.addOpList(opList);
+ form ||= separateForm;
+ canvas ||= separateCanvas;
+ }
+ pageOpList.flush(true, {
+ form,
+ canvas
+ });
+ return {
+ length: pageOpList.totalLength
+ };
+ }
+ async extractTextContent({
+ handler,
+ task,
+ includeMarkedContent,
+ disableNormalization,
+ sink,
+ intersector = null
+ }) {
+ const contentStreamPromise = this.getContentStream();
+ const resourcesPromise = this.loadResources(RESOURCES_KEYS_TEXT_CONTENT);
+ const langPromise = this.pdfManager.ensureCatalog("lang");
+ const [contentStream,, lang] = await Promise.all([contentStreamPromise, resourcesPromise, langPromise]);
+ const resources = await this.#getMergedResources(contentStream.dict, RESOURCES_KEYS_TEXT_CONTENT);
+ const partialEvaluator = this._createPartialEvaluator(handler);
+ return partialEvaluator.getTextContent({
+ stream: contentStream,
+ task,
+ resources,
+ includeMarkedContent,
+ disableNormalization,
+ sink,
+ viewBox: this.view,
+ lang,
+ intersector
+ });
+ }
+ async getStructTree() {
+ const structTreeRoot = await this.pdfManager.ensureCatalog("structTreeRoot");
+ if (!structTreeRoot) {
+ return null;
+ }
+ await this._parsedAnnotations;
+ try {
+ const structTree = await this.pdfManager.ensure(this, "_parseStructTree", [structTreeRoot]);
+ return await this.pdfManager.ensure(structTree, "serializable");
+ } catch (ex) {
+ warn(`getStructTree: "${ex}".`);
+ return null;
+ }
+ }
+ _parseStructTree(structTreeRoot) {
+ const tree = new StructTreePage(structTreeRoot, this.pageDict);
+ tree.parse(this.ref);
+ return tree;
+ }
+ async getAnnotationsData(handler, task, intent) {
+ const annotations = await this._parsedAnnotations;
+ if (annotations.length === 0) {
+ return annotations;
+ }
+ const annotationsData = [],
+ textContentPromises = [];
+ let partialEvaluator;
+ const intentAny = !!(intent & RenderingIntentFlag.ANY),
+ intentDisplay = !!(intent & RenderingIntentFlag.DISPLAY),
+ intentPrint = !!(intent & RenderingIntentFlag.PRINT);
+ const highlightedAnnotations = [];
+ for (const annotation of annotations) {
+ const isVisible = intentAny || intentDisplay && annotation.viewable;
+ if (isVisible || intentPrint && annotation.printable) {
+ annotationsData.push(annotation.data);
+ }
+ if (annotation.hasTextContent && isVisible) {
+ partialEvaluator ??= this._createPartialEvaluator(handler);
+ textContentPromises.push(annotation.extractTextContent(partialEvaluator, task, [-Infinity, -Infinity, Infinity, Infinity]).catch(function (reason) {
+ warn(`getAnnotationsData - ignoring textContent during "${task.name}" task: "${reason}".`);
+ }));
+ } else if (annotation.overlaysTextContent && isVisible) {
+ highlightedAnnotations.push(annotation);
+ }
+ }
+ if (highlightedAnnotations.length > 0) {
+ const intersector = new Intersector(highlightedAnnotations);
+ textContentPromises.push(this.extractTextContent({
+ handler,
+ task,
+ includeMarkedContent: false,
+ disableNormalization: false,
+ sink: null,
+ intersector
+ }).then(() => {
+ intersector.setText();
+ }));
+ }
+ await Promise.all(textContentPromises);
+ return annotationsData;
+ }
+ get annotations() {
+ const annots = this.#getInheritableProperty("Annots");
+ return shadow(this, "annotations", Array.isArray(annots) ? annots : []);
+ }
+ get _parsedAnnotations() {
+ const promise = this.pdfManager.ensure(this, "annotations").then(async annots => {
+ if (annots.length === 0) {
+ return annots;
+ }
+ const [annotationGlobals, fieldObjects] = await Promise.all([this.pdfManager.ensureDoc("annotationGlobals"), this.pdfManager.ensureDoc("fieldObjects")]);
+ if (!annotationGlobals) {
+ return [];
+ }
+ const orphanFields = fieldObjects?.orphanFields;
+ const annotationPromises = [];
+ for (const annotationRef of annots) {
+ annotationPromises.push(AnnotationFactory.create(this.xref, annotationRef, annotationGlobals, this._localIdFactory, false, orphanFields, null, this.ref).catch(function (reason) {
+ warn(`_parsedAnnotations: "${reason}".`);
+ return null;
+ }));
+ }
+ const sortedAnnotations = [];
+ let popupAnnotations, widgetAnnotations;
+ for (const annotation of await Promise.all(annotationPromises)) {
+ if (!annotation) {
+ continue;
+ }
+ if (annotation instanceof WidgetAnnotation) {
+ (widgetAnnotations ||= []).push(annotation);
+ continue;
+ }
+ if (annotation instanceof PopupAnnotation) {
+ (popupAnnotations ||= []).push(annotation);
+ continue;
+ }
+ sortedAnnotations.push(annotation);
+ }
+ if (widgetAnnotations) {
+ sortedAnnotations.push(...widgetAnnotations);
+ }
+ if (popupAnnotations) {
+ sortedAnnotations.push(...popupAnnotations);
+ }
+ return sortedAnnotations;
+ });
+ return shadow(this, "_parsedAnnotations", promise);
+ }
+ get jsActions() {
+ const actions = collectActions(this.xref, this.pageDict, PageActionEventType);
+ return shadow(this, "jsActions", actions);
+ }
+ async collectAnnotationsByType(handler, task, types, promises, annotationGlobals) {
+ const {
+ pageIndex
+ } = this;
+ if (Object.hasOwn(this, "_parsedAnnotations")) {
+ const cachedAnnotations = await this._parsedAnnotations;
+ for (const {
+ data
+ } of cachedAnnotations) {
+ if (!types || types.has(data.annotationType)) {
+ data.pageIndex = pageIndex;
+ promises.push(Promise.resolve(data));
+ }
+ }
+ return;
+ }
+ const annots = await this.pdfManager.ensure(this, "annotations");
+ let partialEvaluator;
+ for (const annotationRef of annots) {
+ promises.push(AnnotationFactory.create(this.xref, annotationRef, annotationGlobals, this._localIdFactory, false, null, types, this.ref).then(async annotation => {
+ if (!annotation) {
+ return null;
+ }
+ annotation.data.pageIndex = pageIndex;
+ if (annotation.hasTextContent && annotation.viewable) {
+ partialEvaluator ??= this._createPartialEvaluator(handler);
+ await annotation.extractTextContent(partialEvaluator, task, [-Infinity, -Infinity, Infinity, Infinity]);
+ }
+ return annotation.data;
+ }).catch(function (reason) {
+ warn(`collectAnnotationsByType: "${reason}".`);
+ return null;
+ }));
+ }
+ }
+}
+const PDF_HEADER_SIGNATURE = new Uint8Array([0x25, 0x50, 0x44, 0x46, 0x2d]);
+const STARTXREF_SIGNATURE = new Uint8Array([0x73, 0x74, 0x61, 0x72, 0x74, 0x78, 0x72, 0x65, 0x66]);
+const ENDOBJ_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x6f, 0x62, 0x6a]);
+function find(stream, signature, limit = 1024, backwards = false) {
+ const signatureLength = signature.length;
+ const scanBytes = stream.peekBytes(limit);
+ const scanLength = scanBytes.length - signatureLength;
+ if (scanLength <= 0) {
+ return false;
+ }
+ if (backwards) {
+ const signatureEnd = signatureLength - 1;
+ let pos = scanBytes.length - 1;
+ while (pos >= signatureEnd) {
+ let j = 0;
+ while (j < signatureLength && scanBytes[pos - j] === signature[signatureEnd - j]) {
+ j++;
+ }
+ if (j >= signatureLength) {
+ stream.pos += pos - signatureEnd;
+ return true;
+ }
+ pos--;
+ }
+ } else {
+ let pos = 0;
+ while (pos <= scanLength) {
+ let j = 0;
+ while (j < signatureLength && scanBytes[pos + j] === signature[j]) {
+ j++;
+ }
+ if (j >= signatureLength) {
+ stream.pos += pos;
+ return true;
+ }
+ pos++;
+ }
+ }
+ return false;
+}
+class PDFDocument {
+ #pagePromises = new Map();
+ #signatureData = null;
+ #version = null;
+ constructor(pdfManager, stream) {
+ if (stream.length <= 0) {
+ throw new InvalidPDFException("The PDF file is empty, i.e. its size is zero bytes.");
+ }
+ this.pdfManager = pdfManager;
+ this.stream = stream;
+ this.xref = new XRef(stream, pdfManager);
+ const idCounters = {
+ font: 0
+ };
+ this._globalIdFactory = class {
+ static getDocId() {
+ return `g_${pdfManager.docId}`;
+ }
+ static createFontId() {
+ return `f${++idCounters.font}`;
+ }
+ static createObjId() {
+ unreachable("Abstract method `createObjId` called.");
+ }
+ static getPageObjId() {
+ unreachable("Abstract method `getPageObjId` called.");
+ }
+ };
+ }
+ parse(recoveryMode) {
+ this.xref.parse(recoveryMode);
+ this.catalog = new Catalog(this.pdfManager, this.xref);
+ }
+ get linearization() {
+ let linearization = null;
+ try {
+ linearization = Linearization.create(this.stream);
+ } catch (err) {
+ if (err instanceof MissingDataException) {
+ throw err;
+ }
+ info(err);
+ }
+ return shadow(this, "linearization", linearization);
+ }
+ get startXRef() {
+ const stream = this.stream;
+ let startXRef = 0;
+ if (this.linearization) {
+ stream.reset();
+ if (find(stream, ENDOBJ_SIGNATURE)) {
+ stream.skip(6);
+ let ch = stream.peekByte();
+ while (isWhiteSpace(ch)) {
+ stream.pos++;
+ ch = stream.peekByte();
+ }
+ startXRef = stream.pos - stream.start;
+ }
+ } else {
+ const step = 1024;
+ const startXRefLength = STARTXREF_SIGNATURE.length;
+ let found = false,
+ pos = stream.end;
+ while (!found && pos > 0) {
+ pos -= step - startXRefLength;
+ if (pos < 0) {
+ pos = 0;
+ }
+ stream.pos = pos;
+ found = find(stream, STARTXREF_SIGNATURE, step, true);
+ }
+ if (found) {
+ stream.skip(9);
+ let ch;
+ do {
+ ch = stream.getByte();
+ } while (isWhiteSpace(ch));
+ let str = "";
+ while (ch >= 0x20 && ch <= 0x39) {
+ str += String.fromCharCode(ch);
+ ch = stream.getByte();
+ }
+ startXRef = parseInt(str, 10);
+ if (isNaN(startXRef)) {
+ startXRef = 0;
+ }
+ }
+ }
+ return shadow(this, "startXRef", startXRef);
+ }
+ checkHeader() {
+ const stream = this.stream;
+ stream.reset();
+ if (!find(stream, PDF_HEADER_SIGNATURE)) {
+ return;
+ }
+ stream.moveStart();
+ stream.skip(PDF_HEADER_SIGNATURE.length);
+ let version = "",
+ ch;
+ while ((ch = stream.getByte()) > 0x20 && version.length < 7) {
+ version += String.fromCharCode(ch);
+ }
+ if (PDF_VERSION_REGEXP.test(version)) {
+ this.#version = version;
+ } else {
+ warn(`Invalid PDF header version: ${version}`);
+ }
+ }
+ parseStartXRef() {
+ this.xref.setStartXRef(this.startXRef);
+ }
+ get numPages() {
+ let num = 0;
+ if (this.catalog.hasActualNumPages) {
+ num = this.catalog.numPages;
+ } else if (this.xfaFactory) {
+ num = this.xfaFactory.getNumPages();
+ } else if (this.linearization) {
+ num = this.linearization.numPages;
+ } else {
+ num = this.catalog.numPages;
+ }
+ return shadow(this, "numPages", num);
+ }
+ #hasOnlyDocumentSignatures(fields, recursionDepth = 0) {
+ const RECURSION_LIMIT = 10;
+ if (!Array.isArray(fields)) {
+ return false;
+ }
+ return fields.every(field => {
+ field = this.xref.fetchIfRef(field);
+ if (!(field instanceof Dict)) {
+ return false;
+ }
+ if (field.has("Kids")) {
+ if (++recursionDepth > RECURSION_LIMIT) {
+ warn("#hasOnlyDocumentSignatures: maximum recursion depth reached");
+ return false;
+ }
+ return this.#hasOnlyDocumentSignatures(field.get("Kids"), recursionDepth);
+ }
+ const isSignature = isName(getInheritableProperty({
+ dict: field,
+ key: "FT"
+ }), "Sig");
+ const rectangle = field.get("Rect");
+ const isInvisible = Array.isArray(rectangle) && rectangle.every(value => value === 0);
+ return isSignature && isInvisible;
+ });
+ }
+ get _xfaStreams() {
+ const {
+ acroForm
+ } = this.catalog;
+ if (!acroForm) {
+ return null;
+ }
+ const xfa = acroForm.get("XFA");
+ const entries = new Map(["xdp:xdp", "template", "datasets", "config", "connectionSet", "localeSet", "stylesheet", "/xdp:xdp"].map(e => [e, null]));
+ if (xfa instanceof BaseStream && !xfa.isEmpty) {
+ entries.set("xdp:xdp", xfa);
+ return entries;
+ }
+ if (!Array.isArray(xfa) || xfa.length === 0) {
+ return null;
+ }
+ for (let i = 0, ii = xfa.length; i < ii; i += 2) {
+ let name;
+ if (i === 0) {
+ name = "xdp:xdp";
+ } else if (i === ii - 2) {
+ name = "/xdp:xdp";
+ } else {
+ name = xfa[i];
+ }
+ if (!entries.has(name)) {
+ continue;
+ }
+ const data = this.xref.fetchIfRef(xfa[i + 1]);
+ if (!(data instanceof BaseStream) || data.isEmpty) {
+ continue;
+ }
+ entries.set(name, data);
+ }
+ return entries;
+ }
+ get xfaDatasets() {
+ const streams = this._xfaStreams;
+ if (!streams) {
+ return shadow(this, "xfaDatasets", null);
+ }
+ for (const key of ["datasets", "xdp:xdp"]) {
+ const stream = streams.get(key);
+ if (!stream) {
+ continue;
+ }
+ try {
+ const str = stringToUTF8String(stream.getString());
+ const data = {
+ [key]: str
+ };
+ return shadow(this, "xfaDatasets", new DatasetReader(data));
+ } catch {
+ warn("XFA - Invalid utf-8 string.");
+ break;
+ }
+ }
+ return shadow(this, "xfaDatasets", null);
+ }
+ get xfaData() {
+ const streams = this._xfaStreams;
+ if (!streams) {
+ return null;
+ }
+ const data = new Map();
+ for (const [key, stream] of streams) {
+ if (!stream) {
+ continue;
+ }
+ try {
+ data.set(key, stringToUTF8String(stream.getString()));
+ } catch {
+ warn("XFA - Invalid utf-8 string.");
+ return null;
+ }
+ }
+ return data;
+ }
+ get xfaFactory() {
+ let data;
+ if (this.pdfManager.enableXfa && this.catalog.needsRendering && this.formInfo.hasXfa && !this.formInfo.hasAcroForm) {
+ data = this.xfaData;
+ }
+ return shadow(this, "xfaFactory", data ? new XFAFactory(data) : null);
+ }
+ get isPureXfa() {
+ return this.xfaFactory ? this.xfaFactory.isValid() : false;
+ }
+ get htmlForXfa() {
+ return this.xfaFactory ? this.xfaFactory.getPages() : null;
+ }
+ async #loadXfaImages() {
+ const xfaImages = await this.pdfManager.ensureCatalog("xfaImages");
+ if (!xfaImages) {
+ return;
+ }
+ this.xfaFactory.setImages(xfaImages);
+ }
+ async #loadXfaFonts(handler, task) {
+ const acroForm = await this.pdfManager.ensureCatalog("acroForm");
+ if (!acroForm) {
+ return;
+ }
+ const resources = await acroForm.getAsync("DR");
+ if (!(resources instanceof Dict)) {
+ return;
+ }
+ await ObjectLoader.load(resources, ["Font"], this.xref);
+ const fontRes = resources.get("Font");
+ if (!(fontRes instanceof Dict)) {
+ return;
+ }
+ const options = Object.assign(Object.create(null), this.pdfManager.evaluatorOptions, {
+ useSystemFonts: false
+ });
+ const {
+ builtInCMapCache,
+ fontCache,
+ standardFontDataCache
+ } = this.catalog;
+ const partialEvaluator = new PartialEvaluator({
+ xref: this.xref,
+ handler,
+ pageIndex: -1,
+ idFactory: this._globalIdFactory,
+ fontCache,
+ builtInCMapCache,
+ standardFontDataCache,
+ options
+ });
+ const operatorList = new OperatorList();
+ const pdfFonts = [];
+ const initialState = {
+ get font() {
+ return pdfFonts.at(-1);
+ },
+ set font(font) {
+ pdfFonts.push(font);
+ },
+ clone() {
+ return this;
+ }
+ };
+ const parseFont = (fontName, fallbackFontDict, cssFontInfo) => partialEvaluator.handleSetFont(resources, [Name.get(fontName), 1], null, operatorList, task, initialState, fallbackFontDict, cssFontInfo).catch(reason => {
+ warn(`loadXfaFonts: "${reason}".`);
+ return null;
+ });
+ const promises = [];
+ for (const [fontName, font] of fontRes) {
+ const descriptor = font.get("FontDescriptor");
+ if (!(descriptor instanceof Dict)) {
+ continue;
+ }
+ const fontFamily = normalizeCSSFontFamily(descriptor.get("FontFamily"));
+ const fontWeight = descriptor.get("FontWeight");
+ const italicAngle = -descriptor.get("ItalicAngle");
+ const cssFontInfo = {
+ fontFamily,
+ fontWeight,
+ italicAngle
+ };
+ if (!validateCSSFont(cssFontInfo)) {
+ continue;
+ }
+ promises.push(parseFont(fontName, null, cssFontInfo));
+ }
+ await Promise.all(promises);
+ const missingFonts = this.xfaFactory.setFonts(pdfFonts);
+ if (!missingFonts) {
+ return;
+ }
+ options.ignoreErrors = true;
+ promises.length = 0;
+ pdfFonts.length = 0;
+ const reallyMissingFonts = new Set();
+ for (const missing of missingFonts) {
+ if (!getXfaFontName(`${missing}-Regular`)) {
+ reallyMissingFonts.add(missing);
+ }
+ }
+ if (reallyMissingFonts.size) {
+ missingFonts.push("PdfJS-Fallback");
+ }
+ for (const missing of missingFonts) {
+ if (reallyMissingFonts.has(missing)) {
+ continue;
+ }
+ for (const fontInfo of [{
+ name: "Regular",
+ fontWeight: 400,
+ italicAngle: 0
+ }, {
+ name: "Bold",
+ fontWeight: 700,
+ italicAngle: 0
+ }, {
+ name: "Italic",
+ fontWeight: 400,
+ italicAngle: 12
+ }, {
+ name: "BoldItalic",
+ fontWeight: 700,
+ italicAngle: 12
+ }]) {
+ const name = `${missing}-${fontInfo.name}`;
+ promises.push(parseFont(name, getXfaFontDict(name), {
+ fontFamily: missing,
+ fontWeight: fontInfo.fontWeight,
+ italicAngle: fontInfo.italicAngle
+ }));
+ }
+ }
+ await Promise.all(promises);
+ this.xfaFactory.appendFonts(pdfFonts, reallyMissingFonts);
+ }
+ loadXfaResources(handler, task) {
+ return Promise.all([this.#loadXfaFonts(handler, task).catch(() => {}), this.#loadXfaImages()]);
+ }
+ serializeXfaData(annotationStorage) {
+ return this.xfaFactory ? this.xfaFactory.serializeData(annotationStorage) : null;
+ }
+ get version() {
+ return this.catalog.version || this.#version;
+ }
+ get formInfo() {
+ const formInfo = {
+ hasFields: false,
+ hasAcroForm: false,
+ hasXfa: false,
+ hasSignatures: false
+ };
+ const {
+ acroForm
+ } = this.catalog;
+ if (!acroForm) {
+ return shadow(this, "formInfo", formInfo);
+ }
+ try {
+ const fields = acroForm.get("Fields");
+ const hasFields = Array.isArray(fields) && fields.length > 0;
+ formInfo.hasFields = hasFields;
+ const xfa = acroForm.get("XFA");
+ formInfo.hasXfa = Array.isArray(xfa) && xfa.length > 0 || xfa instanceof BaseStream && !xfa.isEmpty;
+ const sigFlags = acroForm.get("SigFlags");
+ const hasSignatures = !!(sigFlags & 0x1);
+ const hasOnlyDocumentSignatures = hasSignatures && this.#hasOnlyDocumentSignatures(fields);
+ formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures;
+ formInfo.hasSignatures = hasSignatures;
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn(`Cannot fetch form information: "${ex}".`);
+ }
+ return shadow(this, "formInfo", formInfo);
+ }
+ get documentInfo() {
+ const {
+ catalog,
+ formInfo,
+ xref
+ } = this;
+ const docInfo = {
+ PDFFormatVersion: this.version,
+ Language: catalog.lang,
+ EncryptFilterName: xref.encrypt?.filterName ?? null,
+ IsLinearized: !!this.linearization,
+ IsAcroFormPresent: formInfo.hasAcroForm,
+ IsXFAPresent: formInfo.hasXfa,
+ IsCollectionPresent: !!catalog.collection,
+ IsSignaturesPresent: formInfo.hasSignatures
+ };
+ let infoDict;
+ try {
+ infoDict = xref.trailer.get("Info");
+ } catch (err) {
+ if (err instanceof MissingDataException) {
+ throw err;
+ }
+ info("The document information dictionary is invalid.");
+ }
+ if (!(infoDict instanceof Dict)) {
+ return shadow(this, "documentInfo", docInfo);
+ }
+ for (const [key, value] of infoDict) {
+ switch (key) {
+ case "Title":
+ case "Author":
+ case "Subject":
+ case "Keywords":
+ case "Creator":
+ case "Producer":
+ case "CreationDate":
+ case "ModDate":
+ if (typeof value === "string") {
+ docInfo[key] = stringToPDFString(value);
+ continue;
+ }
+ break;
+ case "Trapped":
+ if (value instanceof Name) {
+ docInfo[key] = value;
+ continue;
+ }
+ break;
+ default:
+ let customValue;
+ switch (typeof value) {
+ case "string":
+ customValue = stringToPDFString(value);
+ break;
+ case "number":
+ case "boolean":
+ customValue = value;
+ break;
+ default:
+ if (value instanceof Name) {
+ customValue = value;
+ break;
+ }
+ warn(`Bad value, for custom key "${key}", in Info: ${value}.`);
+ continue;
+ }
+ (docInfo.Custom ??= new Map()).set(key, customValue);
+ continue;
+ }
+ warn(`Bad value, for key "${key}", in Info: ${value}.`);
+ }
+ return shadow(this, "documentInfo", docInfo);
+ }
+ get fingerprints() {
+ const FINGERPRINT_FIRST_BYTES = 1024;
+ const EMPTY_FINGERPRINT = "\x00".repeat(16);
+ function validate(data) {
+ return typeof data === "string" && data.length === 16 && data !== EMPTY_FINGERPRINT;
+ }
+ const id = this.xref.trailer.get("ID");
+ let hashOriginal, hashModified;
+ if (Array.isArray(id) && validate(id[0])) {
+ hashOriginal = stringToBytes(id[0]);
+ if (id[1] !== id[0] && validate(id[1])) {
+ hashModified = stringToBytes(id[1]);
+ }
+ } else {
+ hashOriginal = calculateMD5(this.stream.getByteRange(0, FINGERPRINT_FIRST_BYTES), 0, FINGERPRINT_FIRST_BYTES);
+ }
+ return shadow(this, "fingerprints", [hashOriginal.toHex(), hashModified?.toHex() ?? null]);
+ }
+ async #getLinearizationPage(pageIndex) {
+ const {
+ catalog,
+ linearization,
+ xref
+ } = this;
+ const ref = Ref.get(linearization.objectNumberFirst, 0);
+ try {
+ const obj = await xref.fetchAsync(ref);
+ if (obj instanceof Dict) {
+ let type = obj.getRaw("Type");
+ if (type instanceof Ref) {
+ type = await xref.fetchAsync(type);
+ }
+ if (isName(type, "Page") || !obj.has("Type") && !obj.has("Kids") && obj.has("Contents")) {
+ if (!catalog.pageKidsCountCache.has(ref)) {
+ catalog.pageKidsCountCache.put(ref, 1);
+ }
+ if (!catalog.pageIndexCache.has(ref)) {
+ catalog.pageIndexCache.put(ref, 0);
+ }
+ return [obj, ref];
+ }
+ }
+ throw new FormatError("The Linearization dictionary doesn't point to a valid Page dictionary.");
+ } catch (reason) {
+ warn(`_getLinearizationPage: "${reason.message}".`);
+ return catalog.getPageDict(pageIndex);
+ }
+ }
+ getPage(pageIndex) {
+ const cachedPromise = this.#pagePromises.get(pageIndex);
+ if (cachedPromise) {
+ return cachedPromise;
+ }
+ const {
+ catalog,
+ linearization,
+ xfaFactory
+ } = this;
+ let promise;
+ if (xfaFactory) {
+ promise = Promise.resolve([Dict.empty, null]);
+ } else if (linearization?.pageFirst === pageIndex) {
+ promise = this.#getLinearizationPage(pageIndex);
+ } else {
+ promise = catalog.getPageDict(pageIndex);
+ }
+ promise = promise.then(([pageDict, ref]) => new Page({
+ pdfManager: this.pdfManager,
+ xref: this.xref,
+ pageIndex,
+ pageDict,
+ ref,
+ globalIdFactory: this._globalIdFactory,
+ fontCache: catalog.fontCache,
+ builtInCMapCache: catalog.builtInCMapCache,
+ standardFontDataCache: catalog.standardFontDataCache,
+ globalColorSpaceCache: catalog.globalColorSpaceCache,
+ globalImageCache: catalog.globalImageCache,
+ systemFontCache: catalog.systemFontCache,
+ nonBlendModesSet: catalog.nonBlendModesSet,
+ xfaFactory
+ }));
+ this.#pagePromises.set(pageIndex, promise);
+ return promise;
+ }
+ async checkFirstPage(recoveryMode = false) {
+ if (recoveryMode) {
+ return;
+ }
+ try {
+ await this.getPage(0);
+ } catch (reason) {
+ if (reason instanceof XRefEntryException) {
+ this.#pagePromises.delete(0);
+ await this.cleanup();
+ throw new XRefParseException();
+ }
+ }
+ }
+ async checkLastPage(recoveryMode = false) {
+ const {
+ catalog,
+ pdfManager
+ } = this;
+ catalog.setActualNumPages();
+ let numPages;
+ try {
+ await Promise.all([pdfManager.ensureDoc("xfaFactory"), pdfManager.ensureDoc("linearization"), pdfManager.ensureCatalog("numPages")]);
+ if (this.xfaFactory) {
+ return;
+ } else if (this.linearization) {
+ numPages = this.linearization.numPages;
+ } else {
+ numPages = catalog.numPages;
+ }
+ if (!Number.isInteger(numPages)) {
+ throw new FormatError("Page count is not an integer.");
+ } else if (numPages <= 1) {
+ return;
+ }
+ await this.getPage(numPages - 1);
+ } catch (reason) {
+ this.#pagePromises.delete(numPages - 1);
+ await this.cleanup();
+ if (reason instanceof XRefEntryException && !recoveryMode) {
+ throw new XRefParseException();
+ }
+ warn(`checkLastPage - invalid /Pages tree /Count: ${numPages}.`);
+ let pagesTree;
+ try {
+ pagesTree = await catalog.getAllPageDicts(recoveryMode);
+ } catch (reasonAll) {
+ if (reasonAll instanceof XRefEntryException && !recoveryMode) {
+ throw new XRefParseException();
+ }
+ catalog.setActualNumPages(1);
+ return;
+ }
+ for (const [pageIndex, [pageDict, ref]] of pagesTree) {
+ let promise;
+ if (pageDict instanceof Error) {
+ promise = Promise.reject(pageDict);
+ promise.catch(() => {});
+ } else {
+ promise = Promise.resolve(new Page({
+ pdfManager,
+ xref: this.xref,
+ pageIndex,
+ pageDict,
+ ref,
+ globalIdFactory: this._globalIdFactory,
+ fontCache: catalog.fontCache,
+ builtInCMapCache: catalog.builtInCMapCache,
+ standardFontDataCache: catalog.standardFontDataCache,
+ globalColorSpaceCache: this.globalColorSpaceCache,
+ globalImageCache: catalog.globalImageCache,
+ systemFontCache: catalog.systemFontCache,
+ nonBlendModesSet: catalog.nonBlendModesSet,
+ xfaFactory: null
+ }));
+ }
+ this.#pagePromises.set(pageIndex, promise);
+ }
+ catalog.setActualNumPages(pagesTree.size);
+ }
+ }
+ async fontFallback(id, handler) {
+ const {
+ catalog,
+ pdfManager
+ } = this;
+ for (const translatedFont of await Promise.all(catalog.fontCache)) {
+ if (translatedFont.loadedName === id) {
+ translatedFont.fallback(handler, pdfManager.evaluatorOptions);
+ return;
+ }
+ }
+ }
+ async cleanup(manuallyTriggered = false) {
+ return this.catalog ? this.catalog.cleanup(manuallyTriggered) : clearGlobalCaches();
+ }
+ async #collectFieldObjects(name, parentRef, fieldRef, promises, annotationGlobals, visitedRefs, orphanFields) {
+ const {
+ xref
+ } = this;
+ if (!(fieldRef instanceof Ref) || visitedRefs.has(fieldRef)) {
+ return;
+ }
+ visitedRefs.put(fieldRef);
+ const field = await xref.fetchAsync(fieldRef);
+ if (!(field instanceof Dict)) {
+ return;
+ }
+ let subtype = await field.getAsync("Subtype");
+ subtype = subtype instanceof Name ? subtype.name : null;
+ switch (subtype) {
+ case "Link":
+ return;
+ }
+ if (field.has("T")) {
+ const partName = stringToPDFString(await field.getAsync("T"));
+ name = name === "" ? partName : `${name}.${partName}`;
+ } else {
+ let obj = field;
+ const walkedRefs = new RefSet();
+ while (true) {
+ obj = obj.getRaw("Parent") || parentRef;
+ if (obj instanceof Ref) {
+ if (visitedRefs.has(obj) || walkedRefs.has(obj)) {
+ break;
+ }
+ walkedRefs.put(obj);
+ obj = await xref.fetchAsync(obj);
+ }
+ if (!(obj instanceof Dict)) {
+ break;
+ }
+ if (obj.has("T")) {
+ const partName = stringToPDFString(await obj.getAsync("T"));
+ name = name === "" ? partName : `${name}.${partName}`;
+ break;
+ }
+ }
+ }
+ if (parentRef && !field.has("Parent") && isName(field.get("Subtype"), "Widget")) {
+ orphanFields.put(fieldRef, parentRef);
+ }
+ promises.getOrInsertComputed(name, makeArr).push(AnnotationFactory.create(xref, fieldRef, annotationGlobals, null, true, orphanFields, null, null).then(annotation => annotation?.getFieldObject()).catch(function (reason) {
+ warn(`#collectFieldObjects: "${reason}".`);
+ return null;
+ }));
+ if (!field.has("Kids")) {
+ return;
+ }
+ const kids = await field.getAsync("Kids");
+ if (Array.isArray(kids)) {
+ for (const kid of kids) {
+ await this.#collectFieldObjects(name, fieldRef, kid, promises, annotationGlobals, visitedRefs, orphanFields);
+ }
+ }
+ }
+ get fieldObjects() {
+ const promise = this.pdfManager.ensureDoc("formInfo").then(async formInfo => {
+ if (!formInfo.hasFields) {
+ return null;
+ }
+ const annotationGlobals = await this.annotationGlobals;
+ if (!annotationGlobals) {
+ return null;
+ }
+ const {
+ acroForm
+ } = annotationGlobals;
+ const visitedRefs = new RefSet();
+ const allFields = new Map();
+ const fieldPromises = new Map();
+ const orphanFields = new RefMap();
+ for (const fieldRef of acroForm.get("Fields")) {
+ await this.#collectFieldObjects("", null, fieldRef, fieldPromises, annotationGlobals, visitedRefs, orphanFields);
+ }
+ const allPromises = [];
+ for (const [name, promises] of fieldPromises) {
+ allPromises.push(Promise.all(promises).then(fields => {
+ fields = fields.filter(Boolean);
+ if (fields.length > 0) {
+ allFields.set(name, fields);
+ }
+ }));
+ }
+ await Promise.all(allPromises);
+ return {
+ allFields: allFields.size ? allFields : null,
+ orphanFields
+ };
+ });
+ return shadow(this, "fieldObjects", promise);
+ }
+ async #collectSignatureFields(fields, out, visitedRefs) {
+ if (!Array.isArray(fields)) {
+ return;
+ }
+ for (const fieldRef of fields) {
+ if (fieldRef instanceof Ref) {
+ if (visitedRefs.has(fieldRef)) {
+ continue;
+ }
+ visitedRefs.put(fieldRef);
+ }
+ const field = await this.xref.fetchIfRefAsync(fieldRef);
+ if (!(field instanceof Dict)) {
+ continue;
+ }
+ if (isName(await field.getAsync("FT"), "Sig")) {
+ const sigDict = await field.getAsync("V");
+ if (sigDict instanceof Dict) {
+ const parsed = await this.#parseSignatureDict(field, sigDict, fieldRef);
+ if (parsed) {
+ out.push(parsed);
+ }
+ }
+ }
+ if (field.has("Kids")) {
+ await this.#collectSignatureFields(await field.getAsync("Kids"), out, visitedRefs);
+ }
+ }
+ }
+ async #getByteRange(begin, end) {
+ try {
+ return this.stream.getByteRange(begin, end);
+ } catch (ex) {
+ if (!(ex instanceof MissingDataException)) {
+ throw ex;
+ }
+ await this.pdfManager.requestRange(begin, end);
+ return this.#getByteRange(begin, end);
+ }
+ }
+ async #coversWholeDocument(signedEnd, modificationsAfterSignature) {
+ if (modificationsAfterSignature > 0) {
+ return false;
+ }
+ const fileLength = this.stream.end;
+ for (let begin = signedEnd; begin < fileLength; begin += SIGNATURE_TAIL_CHUNK_SIZE) {
+ const end = Math.min(begin + SIGNATURE_TAIL_CHUNK_SIZE, fileLength);
+ const tail = await this.#getByteRange(begin, end);
+ for (const byte of tail) {
+ if (byte !== 0x00 && byte !== 0x09 && byte !== 0x0a && byte !== 0x0c && byte !== 0x0d && byte !== 0x20) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ async #parseSignatureDict(field, sigDict, fieldRef) {
+ const byteRange = await sigDict.getAsync("ByteRange");
+ if (!Array.isArray(byteRange) || byteRange.length !== 4 || byteRange.some(n => !Number.isInteger(n) || n < 0)) {
+ return null;
+ }
+ const [a, b, c, d] = byteRange;
+ const fileLength = this.stream.end || 0;
+ if (a !== 0 || b <= 0 || a + b > c || c + d > fileLength || fileLength === 0) {
+ return null;
+ }
+ const contents = await sigDict.getAsync("Contents");
+ if (typeof contents !== "string" || contents.length === 0) {
+ return null;
+ }
+ const [filterName, subFilterName, t, name, reason, location, contactInfo, m] = await Promise.all([sigDict.getAsync("Filter"), sigDict.getAsync("SubFilter"), field.getAsync("T"), sigDict.getAsync("Name"), sigDict.getAsync("Reason"), sigDict.getAsync("Location"), sigDict.getAsync("ContactInfo"), sigDict.getAsync("M")]);
+ const filter = filterName instanceof Name ? filterName.name : null,
+ subFilter = subFilterName instanceof Name ? subFilterName.name : null;
+ let signatureType = null;
+ if (subFilter === "adbe.pkcs7.detached") {
+ signatureType = 0;
+ } else if (subFilter === "adbe.pkcs7.sha1") {
+ signatureType = 1;
+ }
+ const refKey = fieldRef instanceof Ref ? fieldRef.toString() : "inline";
+ return {
+ id: `${refKey}:${a}-${b}-${c}-${d}`,
+ fieldName: typeof t === "string" ? stringToPDFString(t) : "",
+ signerName: typeof name === "string" ? stringToPDFString(name) : null,
+ reason: typeof reason === "string" ? stringToPDFString(reason) : null,
+ location: typeof location === "string" ? stringToPDFString(location) : null,
+ contactInfo: typeof contactInfo === "string" ? stringToPDFString(contactInfo) : null,
+ signingTime: typeof m === "string" ? m : null,
+ filter,
+ subFilter,
+ signatureType,
+ byteRange,
+ pkcs7: stringToBytes(contents),
+ revisionIndex: 0,
+ parentId: null
+ };
+ }
+ get signatures() {
+ const promise = this.pdfManager.ensureDoc("formInfo").then(async formInfo => {
+ if (!formInfo.hasSignatures || !formInfo.hasFields) {
+ return null;
+ }
+ const annotationGlobals = await this.annotationGlobals;
+ if (!annotationGlobals) {
+ return null;
+ }
+ const fields = annotationGlobals.acroForm.get("Fields");
+ const collected = [];
+ await this.#collectSignatureFields(fields, collected, new RefSet());
+ await Promise.all(collected.map(async signature => {
+ const signedEnd = signature.byteRange[2] + signature.byteRange[3];
+ signature.modificationsAfterSignature = this.xref.countUpdatesAfter(signedEnd);
+ signature.coversWholeDocument = await this.#coversWholeDocument(signedEnd, signature.modificationsAfterSignature);
+ }));
+ collected.sort((a, b) => b.byteRange[2] + b.byteRange[3] - (a.byteRange[2] + a.byteRange[3]));
+ for (let i = 0, ii = collected.length; i < ii; i++) {
+ const sig = collected[i];
+ sig.revisionIndex = i;
+ for (let j = i - 1; j >= 0; j--) {
+ const candidate = collected[j];
+ if (candidate.byteRange[2] + candidate.byteRange[3] > sig.byteRange[2] + sig.byteRange[3]) {
+ sig.parentId = candidate.id;
+ break;
+ }
+ }
+ }
+ const signatureData = new Map();
+ const metadata = collected.map(sig => {
+ const {
+ pkcs7,
+ ...rest
+ } = sig;
+ signatureData.set(sig.id, {
+ byteRange: sig.byteRange,
+ pkcs7
+ });
+ return rest;
+ });
+ this.#signatureData = signatureData;
+ return metadata.length ? metadata : null;
+ });
+ return shadow(this, "signatures", promise);
+ }
+ async getSignatureData(id) {
+ await this.signatures;
+ const signature = this.#signatureData?.get(id);
+ if (!signature) {
+ return null;
+ }
+ const {
+ byteRange,
+ pkcs7
+ } = signature;
+ const [a, b, c, d] = byteRange;
+ const data = await Promise.all([this.#getByteRange(a, a + b), this.#getByteRange(c, c + d)]);
+ return {
+ data,
+ pkcs7
+ };
+ }
+ get hasJSActions() {
+ const promise = Promise.all([this.pdfManager.ensureCatalog("jsActions"), this.pdfManager.ensureDoc("fieldObjects")]).then(([catalogJsActions, fieldObjects]) => {
+ if (catalogJsActions) {
+ return true;
+ }
+ if (fieldObjects?.allFields) {
+ return fieldObjects.allFields.values().some(fieldObj => fieldObj.some(obj => obj.actions !== null));
+ }
+ return false;
+ });
+ return shadow(this, "hasJSActions", promise);
+ }
+ get calculationOrderIds() {
+ const calculationOrder = this.catalog.acroForm?.get("CO");
+ if (!Array.isArray(calculationOrder) || calculationOrder.length === 0) {
+ return shadow(this, "calculationOrderIds", null);
+ }
+ const ids = [];
+ for (const id of calculationOrder) {
+ if (id instanceof Ref) {
+ ids.push(id.toString());
+ }
+ }
+ return shadow(this, "calculationOrderIds", ids.length ? ids : null);
+ }
+ get annotationGlobals() {
+ return shadow(this, "annotationGlobals", AnnotationFactory.createGlobals(this.pdfManager));
+ }
+ async toJSObject(value, firstCall = true) {
+ throw new Error("Not implemented: toJSObject");
+ }
+}
+
+;// ./src/core/pdf_manager.js
+
+
+
+
+
+
+
+
+
+
+
+
+function parseDocBaseUrl(url) {
+ if (url) {
+ const absoluteUrl = createValidAbsoluteUrl(url);
+ if (absoluteUrl) {
+ return absoluteUrl.href;
+ }
+ warn(`Invalid absolute docBaseUrl: "${url}".`);
+ }
+ return null;
+}
+class BasePdfManager {
+ constructor({
+ docBaseUrl,
+ docId,
+ enableXfa,
+ evaluatorOptions,
+ handler,
+ password
+ }) {
+ this._docBaseUrl = parseDocBaseUrl(docBaseUrl);
+ this._docId = docId;
+ this._password = password;
+ this.enableXfa = enableXfa;
+ evaluatorOptions.isOffscreenCanvasSupported &&= FeatureTest.isOffscreenCanvasSupported;
+ evaluatorOptions.isImageDecoderSupported &&= FeatureTest.isImageDecoderSupported;
+ this.evaluatorOptions = Object.freeze(evaluatorOptions);
+ ImageResizer.setOptions(evaluatorOptions);
+ JpegStream.setOptions(evaluatorOptions);
+ OperatorList.setOptions(evaluatorOptions);
+ const options = {
+ ...evaluatorOptions,
+ handler
+ };
+ IccColorSpace.setOptions(options);
+ CmykICCBasedCS.setOptions(options);
+ PDFFunctionFactory.setOptions(options);
+ Pattern.setOptions(options);
+ WasmImage.setOptions(options);
+ }
+ get docId() {
+ return this._docId;
+ }
+ get password() {
+ return this._password;
+ }
+ get docBaseUrl() {
+ return this._docBaseUrl;
+ }
+ ensureDoc(prop, args) {
+ return this.ensure(this.pdfDocument, prop, args);
+ }
+ ensureCatalog(prop, args) {
+ return this.ensure(this.pdfDocument.catalog, prop, args);
+ }
+ async initDocument(recoveryMode) {
+ await this.ensureDoc("checkHeader");
+ await this.ensureDoc("parseStartXRef");
+ await this.ensureDoc("parse", [recoveryMode]);
+ await this.ensureDoc("checkFirstPage", [recoveryMode]);
+ await this.ensureDoc("checkLastPage", [recoveryMode]);
+ }
+ getPage(pageIndex) {
+ return this.pdfDocument.getPage(pageIndex);
+ }
+ fontFallback(id, handler) {
+ return this.pdfDocument.fontFallback(id, handler);
+ }
+ cleanup(manuallyTriggered = false) {
+ return this.pdfDocument.cleanup(manuallyTriggered);
+ }
+ async ensure(obj, prop, args) {
+ unreachable("Abstract method `ensure` called");
+ }
+ requestRange(begin, end) {
+ unreachable("Abstract method `requestRange` called");
+ }
+ requestLoadedStream(noFetch = false) {
+ unreachable("Abstract method `requestLoadedStream` called");
+ }
+ sendProgressiveData(chunk) {
+ unreachable("Abstract method `sendProgressiveData` called");
+ }
+ updatePassword(password) {
+ this._password = password;
+ this.pdfDocument.xref.encrypt?.setPassword(password);
+ }
+ terminate(reason) {
+ unreachable("Abstract method `terminate` called");
+ }
+}
+class LocalPdfManager extends BasePdfManager {
+ constructor(args) {
+ super(args);
+ const stream = new Stream(args.source);
+ this.pdfDocument = new PDFDocument(this, stream);
+ this._loadedStreamPromise = Promise.resolve(stream);
+ }
+ async ensure(obj, prop, args) {
+ const value = obj[prop];
+ if (typeof value === "function") {
+ return value.apply(obj, args);
+ }
+ return value;
+ }
+ requestLoadedStream(noFetch = false) {
+ return this._loadedStreamPromise;
+ }
+ terminate(reason) {}
+}
+class NetworkPdfManager extends BasePdfManager {
+ constructor(args) {
+ super(args);
+ this.streamManager = new ChunkedStreamManager(args.source, {
+ msgHandler: args.handler,
+ length: args.length,
+ disableAutoFetch: args.disableAutoFetch,
+ rangeChunkSize: args.rangeChunkSize
+ });
+ this.pdfDocument = new PDFDocument(this, this.streamManager.getStream());
+ }
+ async ensure(obj, prop, args) {
+ try {
+ const value = obj[prop];
+ if (typeof value === "function") {
+ return await value.apply(obj, args);
+ }
+ return value;
+ } catch (ex) {
+ if (!(ex instanceof MissingDataException)) {
+ throw ex;
+ }
+ await this.requestRange(ex.begin, ex.end);
+ return this.ensure(obj, prop, args);
+ }
+ }
+ requestRange(begin, end) {
+ return this.streamManager.requestRange(begin, end);
+ }
+ requestLoadedStream(noFetch = false) {
+ return this.streamManager.requestAllChunks(noFetch);
+ }
+ sendProgressiveData(chunk) {
+ this.streamManager.onReceiveData({
+ chunk
+ });
+ }
+ terminate(reason) {
+ this.streamManager.abort(reason);
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.promise.try.js
+var es_promise_try = __webpack_require__(1689);
+;// ./src/shared/message_handler.js
+
+
+const CallbackKind = {
+ DATA: 1,
+ ERROR: 2
+};
+const StreamKind = {
+ CANCEL: 1,
+ CANCEL_COMPLETE: 2,
+ CLOSE: 3,
+ ENQUEUE: 4,
+ ERROR: 5,
+ PULL: 6,
+ PULL_COMPLETE: 7,
+ START_COMPLETE: 8
+};
+function onFn() {}
+function wrapReason(ex) {
+ if (ex instanceof AbortException || ex instanceof InvalidPDFException || ex instanceof PasswordException || ex instanceof ResponseException || ex instanceof UnknownErrorException) {
+ return ex;
+ }
+ if (!(ex instanceof Error || typeof ex === "object" && ex !== null)) {
+ unreachable('wrapReason: Expected "reason" to be a (possibly cloned) Error.');
+ }
+ switch (ex.name) {
+ case "AbortException":
+ return new AbortException(ex.message);
+ case "InvalidPDFException":
+ return new InvalidPDFException(ex.message);
+ case "PasswordException":
+ return new PasswordException(ex.message, ex.code);
+ case "ResponseException":
+ return new ResponseException(ex.message, ex.status, ex.missing);
+ case "UnknownErrorException":
+ return new UnknownErrorException(ex.message, ex.details);
+ }
+ return new UnknownErrorException(ex.message, ex.toString());
+}
+class MessageHandler {
+ #messageAC = new AbortController();
+ constructor(sourceName, targetName, comObj) {
+ this.sourceName = sourceName;
+ this.targetName = targetName;
+ this.comObj = comObj;
+ this.callbackId = 1;
+ this.streamId = 1;
+ this.streamSinks = Object.create(null);
+ this.streamControllers = Object.create(null);
+ this.callbackCapabilities = Object.create(null);
+ this.actionHandler = Object.create(null);
+ comObj.addEventListener("message", this.#onMessage.bind(this), {
+ signal: this.#messageAC.signal
+ });
+ }
+ #onMessage({
+ data
+ }) {
+ if (data.targetName !== this.sourceName) {
+ return;
+ }
+ if (data.stream) {
+ this.#processStreamMessage(data);
+ return;
+ }
+ if (data.callback) {
+ const callbackId = data.callbackId;
+ const capability = this.callbackCapabilities[callbackId];
+ if (!capability) {
+ throw new Error(`Cannot resolve callback ${callbackId}`);
+ }
+ delete this.callbackCapabilities[callbackId];
+ if (data.callback === CallbackKind.DATA) {
+ capability.resolve(data.data);
+ } else if (data.callback === CallbackKind.ERROR) {
+ capability.reject(wrapReason(data.reason));
+ } else {
+ throw new Error("Unexpected callback case");
+ }
+ return;
+ }
+ const action = this.actionHandler[data.action];
+ if (!action) {
+ throw new Error(`Unknown action from worker: ${data.action}`);
+ }
+ if (data.callbackId) {
+ const sourceName = this.sourceName,
+ targetName = data.sourceName,
+ comObj = this.comObj;
+ Promise.try(action, data.data).then(function (result) {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ callback: CallbackKind.DATA,
+ callbackId: data.callbackId,
+ data: result
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ callback: CallbackKind.ERROR,
+ callbackId: data.callbackId,
+ reason: wrapReason(reason)
+ });
+ });
+ return;
+ }
+ if (data.streamId) {
+ this.#createStreamSink(data);
+ return;
+ }
+ action(data.data);
+ }
+ on(actionName, handler) {
+ const ah = this.actionHandler;
+ if (ah[actionName]) {
+ throw new Error(`There is already an actionName called "${actionName}"`);
+ }
+ ah[actionName] = handler;
+ }
+ send(actionName, data, transfers) {
+ this.comObj.postMessage({
+ sourceName: this.sourceName,
+ targetName: this.targetName,
+ action: actionName,
+ data
+ }, transfers);
+ }
+ sendWithPromise(actionName, data, transfers) {
+ const callbackId = this.callbackId++;
+ const capability = Promise.withResolvers();
+ this.callbackCapabilities[callbackId] = capability;
+ try {
+ this.comObj.postMessage({
+ sourceName: this.sourceName,
+ targetName: this.targetName,
+ action: actionName,
+ callbackId,
+ data
+ }, transfers);
+ } catch (ex) {
+ capability.reject(ex);
+ }
+ return capability.promise;
+ }
+ sendWithStream(actionName, data, queueingStrategy, transfers) {
+ const streamId = this.streamId++,
+ sourceName = this.sourceName,
+ targetName = this.targetName,
+ comObj = this.comObj;
+ return new ReadableStream({
+ start: controller => {
+ const startCapability = Promise.withResolvers();
+ this.streamControllers[streamId] = {
+ controller,
+ startCall: startCapability,
+ pullCall: null,
+ cancelCall: null,
+ isClosed: false
+ };
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ action: actionName,
+ streamId,
+ data,
+ desiredSize: controller.desiredSize
+ }, transfers);
+ return startCapability.promise;
+ },
+ pull: controller => {
+ const pullCapability = Promise.withResolvers();
+ this.streamControllers[streamId].pullCall = pullCapability;
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.PULL,
+ streamId,
+ desiredSize: controller.desiredSize
+ });
+ return pullCapability.promise;
+ },
+ cancel: reason => {
+ assert(reason instanceof Error, "cancel must have a valid reason");
+ const cancelCapability = Promise.withResolvers();
+ this.streamControllers[streamId].cancelCall = cancelCapability;
+ this.streamControllers[streamId].isClosed = true;
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.CANCEL,
+ streamId,
+ reason: wrapReason(reason)
+ });
+ return cancelCapability.promise;
+ }
+ }, queueingStrategy);
+ }
+ #createStreamSink(data) {
+ const streamId = data.streamId,
+ sourceName = this.sourceName,
+ targetName = data.sourceName,
+ comObj = this.comObj;
+ const self = this,
+ action = this.actionHandler[data.action];
+ const streamSink = {
+ enqueue(chunk, size = 1, transfers) {
+ if (this.isCancelled) {
+ return;
+ }
+ const lastDesiredSize = this.desiredSize;
+ this.desiredSize -= size;
+ if (lastDesiredSize > 0 && this.desiredSize <= 0) {
+ this.sinkCapability = Promise.withResolvers();
+ this.ready = this.sinkCapability.promise;
+ }
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.ENQUEUE,
+ streamId,
+ chunk
+ }, transfers);
+ },
+ close() {
+ if (this.isCancelled) {
+ return;
+ }
+ this.isCancelled = true;
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.CLOSE,
+ streamId
+ });
+ delete self.streamSinks[streamId];
+ },
+ error(reason) {
+ assert(reason instanceof Error, "error must have a valid reason");
+ if (this.isCancelled) {
+ return;
+ }
+ this.isCancelled = true;
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.ERROR,
+ streamId,
+ reason: wrapReason(reason)
+ });
+ },
+ sinkCapability: Promise.withResolvers(),
+ onPull: null,
+ onCancel: null,
+ isCancelled: false,
+ desiredSize: data.desiredSize,
+ ready: null
+ };
+ streamSink.sinkCapability.resolve();
+ streamSink.ready = streamSink.sinkCapability.promise;
+ this.streamSinks[streamId] = streamSink;
+ Promise.try(action, data.data, streamSink).then(function () {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.START_COMPLETE,
+ streamId,
+ success: true
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.START_COMPLETE,
+ streamId,
+ reason: wrapReason(reason)
+ });
+ });
+ }
+ #processStreamMessage(data) {
+ const streamId = data.streamId,
+ sourceName = this.sourceName,
+ targetName = data.sourceName,
+ comObj = this.comObj;
+ const streamController = this.streamControllers[streamId],
+ streamSink = this.streamSinks[streamId];
+ switch (data.stream) {
+ case StreamKind.START_COMPLETE:
+ if (data.success) {
+ streamController.startCall.resolve();
+ } else {
+ streamController.startCall.reject(wrapReason(data.reason));
+ }
+ break;
+ case StreamKind.PULL_COMPLETE:
+ if (data.success) {
+ streamController.pullCall.resolve();
+ } else {
+ streamController.pullCall.reject(wrapReason(data.reason));
+ }
+ break;
+ case StreamKind.PULL:
+ if (!streamSink) {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.PULL_COMPLETE,
+ streamId,
+ success: true
+ });
+ break;
+ }
+ if (streamSink.desiredSize <= 0 && data.desiredSize > 0) {
+ streamSink.sinkCapability.resolve();
+ }
+ streamSink.desiredSize = data.desiredSize;
+ Promise.try(streamSink.onPull || onFn).then(function () {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.PULL_COMPLETE,
+ streamId,
+ success: true
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.PULL_COMPLETE,
+ streamId,
+ reason: wrapReason(reason)
+ });
+ });
+ break;
+ case StreamKind.ENQUEUE:
+ assert(streamController, "enqueue should have stream controller");
+ if (streamController.isClosed) {
+ break;
+ }
+ streamController.controller.enqueue(data.chunk);
+ break;
+ case StreamKind.CLOSE:
+ assert(streamController, "close should have stream controller");
+ if (streamController.isClosed) {
+ break;
+ }
+ streamController.isClosed = true;
+ streamController.controller.close();
+ this.#deleteStreamController(streamController, streamId);
+ break;
+ case StreamKind.ERROR:
+ assert(streamController, "error should have stream controller");
+ streamController.controller.error(wrapReason(data.reason));
+ this.#deleteStreamController(streamController, streamId);
+ break;
+ case StreamKind.CANCEL_COMPLETE:
+ if (data.success) {
+ streamController.cancelCall.resolve();
+ } else {
+ streamController.cancelCall.reject(wrapReason(data.reason));
+ }
+ this.#deleteStreamController(streamController, streamId);
+ break;
+ case StreamKind.CANCEL:
+ if (!streamSink) {
+ break;
+ }
+ const dataReason = wrapReason(data.reason);
+ Promise.try(streamSink.onCancel || onFn, dataReason).then(function () {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.CANCEL_COMPLETE,
+ streamId,
+ success: true
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ sourceName,
+ targetName,
+ stream: StreamKind.CANCEL_COMPLETE,
+ streamId,
+ reason: wrapReason(reason)
+ });
+ });
+ streamSink.sinkCapability.reject(dataReason);
+ streamSink.isCancelled = true;
+ delete this.streamSinks[streamId];
+ break;
+ default:
+ throw new Error("Unexpected stream case");
+ }
+ }
+ async #deleteStreamController(streamController, streamId) {
+ await Promise.allSettled([streamController.startCall?.promise, streamController.pullCall?.promise, streamController.cancelCall?.promise]);
+ delete this.streamControllers[streamId];
+ }
+ destroy() {
+ this.#messageAC?.abort();
+ this.#messageAC = null;
+ }
+}
+
+;// ./src/core/writer.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+async function writeObject(ref, obj, buffer, {
+ encrypt = null,
+ encryptRef = null
+}) {
+ const transform = encrypt && encryptRef !== ref ? encrypt.createCipherTransform(ref.num, ref.gen) : null;
+ buffer.push(`${ref.num} ${ref.gen} obj\n`);
+ await writeValue(obj, buffer, transform);
+ buffer.push("\nendobj\n");
+}
+async function writeDict(dict, buffer, transform) {
+ buffer.push("<<");
+ for (const [key, rawObj] of dict.getRawEntries()) {
+ buffer.push(` /${escapePDFName(key)} `);
+ await writeValue(rawObj, buffer, transform);
+ }
+ buffer.push(">>");
+}
+async function writeStream(stream, buffer, transform) {
+ stream = stream.getOriginalStream();
+ stream.reset();
+ let bytes = stream.getBytes();
+ const {
+ dict
+ } = stream;
+ const [filter, params] = await Promise.all([dict.getAsync("Filter"), dict.getAsync("DecodeParms")]);
+ const filterZero = Array.isArray(filter) ? await dict.xref.fetchIfRefAsync(filter[0]) : filter;
+ const isFilterZeroFlateDecode = isName(filterZero, "FlateDecode");
+ const isFilterZeroImageDecode = isName(filterZero, "DCTDecode") || isName(filterZero, "JPXDecode") || isName(filterZero, "JBIG2Decode") || isName(filterZero, "CCITTFaxDecode") || isName(filterZero, "LZWDecode");
+ const isFilterZeroCompressedObject = isFilterZeroFlateDecode || isFilterZeroImageDecode || isName(filterZero, "BrotliDecode");
+ const MIN_LENGTH_FOR_COMPRESSING = 256;
+ if (!isFilterZeroCompressedObject && bytes.length >= MIN_LENGTH_FOR_COMPRESSING) {
+ try {
+ const cs = new CompressionStream("deflate");
+ const writer = cs.writable.getWriter();
+ await writer.ready;
+ writer.write(bytes).then(async () => {
+ await writer.ready;
+ await writer.close();
+ }).catch(() => {});
+ bytes = await new Response(cs.readable).bytes();
+ let newFilter, newParams;
+ if (!filter) {
+ newFilter = Name.get("FlateDecode");
+ } else if (!isFilterZeroFlateDecode) {
+ newFilter = Array.isArray(filter) ? [Name.get("FlateDecode"), ...filter] : [Name.get("FlateDecode"), filter];
+ if (params) {
+ newParams = Array.isArray(params) ? [null, ...params] : [null, params];
+ }
+ }
+ if (newFilter) {
+ dict.set("Filter", newFilter);
+ }
+ if (newParams) {
+ dict.set("DecodeParms", newParams);
+ }
+ } catch (ex) {
+ info(`writeStream - cannot compress data: "${ex}".`);
+ }
+ }
+ let string = bytesToString(bytes);
+ if (transform) {
+ string = transform.encryptString(string);
+ }
+ dict.set("Length", string.length);
+ await writeDict(dict, buffer, transform);
+ buffer.push(" stream\n", string, "\nendstream");
+}
+async function writeArray(array, buffer, transform) {
+ buffer.push("[");
+ for (let i = 0, ii = array.length; i < ii; i++) {
+ await writeValue(array[i], buffer, transform);
+ if (i < ii - 1) {
+ buffer.push(" ");
+ }
+ }
+ buffer.push("]");
+}
+function numberToPDFString(value) {
+ if (Number.isInteger(value) && Math.abs(value) >= 1e21) {
+ return BigInt(value).toString();
+ }
+ const str = value.toFixed(10);
+ let end = str.length;
+ while (str[end - 1] === "0") {
+ end--;
+ }
+ if (str[end - 1] === ".") {
+ end--;
+ }
+ return str.slice(0, end);
+}
+async function writeValue(value, buffer, transform) {
+ if (value instanceof Name) {
+ buffer.push(`/${escapePDFName(value.name)}`);
+ } else if (value instanceof Ref) {
+ buffer.push(`${value.num} ${value.gen} R`);
+ } else if (Array.isArray(value) || ArrayBuffer.isView(value)) {
+ await writeArray(value, buffer, transform);
+ } else if (typeof value === "string") {
+ if (transform) {
+ value = transform.encryptString(value);
+ }
+ buffer.push(`(${escapeString(value)})`);
+ } else if (typeof value === "number") {
+ buffer.push(numberToPDFString(value));
+ } else if (typeof value === "boolean") {
+ buffer.push(value.toString());
+ } else if (value instanceof Dict) {
+ await writeDict(value, buffer, transform);
+ } else if (value instanceof BaseStream) {
+ await writeStream(value, buffer, transform);
+ } else if (value === null) {
+ buffer.push("null");
+ } else {
+ warn(`Unhandled value in writer: ${typeof value}, please file a bug.`);
+ }
+}
+function writeInt(number, size, offset, buffer) {
+ for (let i = size + offset - 1; i > offset - 1; i--) {
+ buffer[i] = number & 0xff;
+ number >>= 8;
+ }
+ return offset + size;
+}
+function writeString(string, offset, buffer) {
+ const ii = string.length;
+ for (let i = 0; i < ii; i++) {
+ buffer[offset + i] = string.charCodeAt(i) & 0xff;
+ }
+ return offset + ii;
+}
+function computeMD5(filesize, xrefInfo) {
+ const time = Math.floor(Date.now() / 1000);
+ const filename = xrefInfo.filename || "";
+ const md5Buffer = [time.toString(), filename, filesize.toString(), ...xrefInfo.infoMap.values()];
+ const md5BufferLen = Math.sumPrecise(md5Buffer.map(str => str.length));
+ const array = new Uint8Array(md5BufferLen);
+ let offset = 0;
+ for (const str of md5Buffer) {
+ offset = writeString(str, offset, array);
+ }
+ return bytesToString(calculateMD5(array, 0, array.length));
+}
+function writeXFADataForAcroform(str, changes) {
+ const xml = new SimpleXMLParser({
+ hasAttributes: true
+ }).parseFromString(str);
+ for (const {
+ xfa
+ } of changes) {
+ if (!xfa) {
+ continue;
+ }
+ const {
+ path,
+ value
+ } = xfa;
+ if (!path || value === null) {
+ continue;
+ }
+ const nodePath = parseXFAPath(path);
+ let node = xml.documentElement.searchNode(nodePath, 0);
+ if (!node && nodePath.length > 1) {
+ node = xml.documentElement.searchNode([nodePath.at(-1)], 0);
+ }
+ if (node) {
+ node.childNodes = Array.isArray(value) ? value.map(val => new SimpleDOMNode("value", val)) : [new SimpleDOMNode("#text", value)];
+ } else {
+ warn(`Node not found for path: ${path}`);
+ }
+ }
+ const buffer = [];
+ xml.documentElement.dump(buffer);
+ return buffer.join("");
+}
+async function updateAcroform({
+ xref,
+ acroForm,
+ acroFormRef,
+ hasXfa,
+ hasXfaDatasetsEntry,
+ xfaDatasetsRef,
+ needAppearances,
+ changes
+}) {
+ if (hasXfa && !hasXfaDatasetsEntry && !xfaDatasetsRef) {
+ warn("XFA - Cannot save it");
+ }
+ if (!needAppearances && (!hasXfa || !xfaDatasetsRef || hasXfaDatasetsEntry)) {
+ return;
+ }
+ const dict = acroForm.clone();
+ if (hasXfa && !hasXfaDatasetsEntry) {
+ const newXfa = acroForm.get("XFA").slice();
+ newXfa.splice(2, 0, "datasets");
+ newXfa.splice(3, 0, xfaDatasetsRef);
+ dict.set("XFA", newXfa);
+ }
+ if (needAppearances) {
+ dict.set("NeedAppearances", true);
+ }
+ changes.put(acroFormRef, {
+ data: dict
+ });
+}
+function updateXFA({
+ xfaData,
+ xfaDatasetsRef,
+ changes,
+ xref
+}) {
+ if (xfaData === null) {
+ const datasets = xref.fetchIfRef(xfaDatasetsRef);
+ xfaData = writeXFADataForAcroform(datasets.getString(), changes);
+ }
+ const xfaDataStream = new StringStream(xfaData, new Dict(xref));
+ xfaDataStream.dict.setIfName("Type", "EmbeddedFile");
+ changes.put(xfaDatasetsRef, {
+ data: xfaDataStream
+ });
+}
+async function getXRefTable(xrefInfo, baseOffset, newRefs, newXref, buffer) {
+ buffer.push("xref\n");
+ const indexes = getIndexes(newRefs);
+ let indexesPosition = 0;
+ for (const {
+ ref,
+ data
+ } of newRefs) {
+ if (ref.num === indexes[indexesPosition]) {
+ buffer.push(`${indexes[indexesPosition]} ${indexes[indexesPosition + 1]}\n`);
+ indexesPosition += 2;
+ }
+ if (data !== null) {
+ buffer.push(`${baseOffset.toString().padStart(10, "0")} ${Math.min(ref.gen, 0xffff).toString().padStart(5, "0")} n\r\n`);
+ baseOffset += data.length;
+ } else {
+ buffer.push(`0000000000 ${Math.min(ref.gen + 1, 0xffff).toString().padStart(5, "0")} f\r\n`);
+ }
+ }
+ computeIDs(baseOffset, xrefInfo, newXref);
+ buffer.push("trailer\n");
+ await writeDict(newXref, buffer, null);
+ buffer.push("\nstartxref\n", baseOffset.toString(), "\n%%EOF\n");
+}
+function getIndexes(newRefs) {
+ const indexes = [];
+ for (const {
+ ref
+ } of newRefs) {
+ if (ref.num === indexes.at(-2) + indexes.at(-1)) {
+ indexes[indexes.length - 1] += 1;
+ } else {
+ indexes.push(ref.num, 1);
+ }
+ }
+ return indexes;
+}
+async function getXRefStreamTable(xrefInfo, baseOffset, newRefs, newXref, buffer) {
+ const xrefTableData = [];
+ let maxOffset = 0;
+ let maxGen = 0;
+ for (const {
+ ref,
+ data,
+ objStreamRef,
+ index
+ } of newRefs) {
+ let gen;
+ maxOffset = Math.max(maxOffset, baseOffset);
+ if (objStreamRef) {
+ gen = index;
+ xrefTableData.push([2, objStreamRef.num, gen]);
+ } else if (data !== null) {
+ gen = Math.min(ref.gen, 0xffff);
+ xrefTableData.push([1, baseOffset, gen]);
+ baseOffset += data.length;
+ } else {
+ gen = Math.min(ref.gen + 1, 0xffff);
+ xrefTableData.push([0, 0, gen]);
+ }
+ maxGen = Math.max(maxGen, gen);
+ }
+ newXref.set("Index", getIndexes(newRefs));
+ const offsetSize = getSizeInBytes(maxOffset);
+ const maxGenSize = getSizeInBytes(maxGen);
+ const sizes = [1, offsetSize, maxGenSize];
+ newXref.set("W", sizes);
+ computeIDs(baseOffset, xrefInfo, newXref);
+ const structSize = Math.sumPrecise(sizes);
+ const data = new Uint8Array(structSize * xrefTableData.length);
+ const stream = new Stream(data);
+ stream.dict = newXref;
+ let offset = 0;
+ for (const [type, objOffset, gen] of xrefTableData) {
+ offset = writeInt(type, sizes[0], offset, data);
+ offset = writeInt(objOffset, sizes[1], offset, data);
+ offset = writeInt(gen, sizes[2], offset, data);
+ }
+ await writeObject(xrefInfo.newRef, stream, buffer, {});
+ buffer.push("startxref\n", baseOffset.toString(), "\n%%EOF\n");
+}
+function computeIDs(baseOffset, xrefInfo, newXref) {
+ if (Array.isArray(xrefInfo.fileIds) && xrefInfo.fileIds.length > 0) {
+ const md5 = computeMD5(baseOffset, xrefInfo);
+ newXref.set("ID", [xrefInfo.fileIds[0] || md5, md5]);
+ }
+}
+function getTrailerDict(xrefInfo, changes, useXrefStream) {
+ const newXref = new Dict(null);
+ newXref.setIfDefined("Prev", xrefInfo?.startXRef);
+ const refForXrefTable = xrefInfo.newRef;
+ if (useXrefStream) {
+ changes.put(refForXrefTable, {
+ data: ""
+ });
+ newXref.set("Size", refForXrefTable.num + 1);
+ newXref.setIfName("Type", "XRef");
+ } else {
+ newXref.set("Size", refForXrefTable.num);
+ }
+ newXref.setIfDefined("Root", xrefInfo?.rootRef);
+ newXref.setIfDefined("Info", xrefInfo?.infoRef);
+ newXref.setIfDefined("Encrypt", xrefInfo?.encryptRef);
+ return newXref;
+}
+async function writeChanges(changes, xref, buffer = []) {
+ const newRefs = [];
+ for (const [ref, {
+ data,
+ objStreamRef,
+ index
+ }] of changes.items()) {
+ if (objStreamRef) {
+ newRefs.push({
+ ref,
+ data,
+ objStreamRef,
+ index
+ });
+ continue;
+ }
+ if (data === null || typeof data === "string") {
+ newRefs.push({
+ ref,
+ data
+ });
+ continue;
+ }
+ await writeObject(ref, data, buffer, xref);
+ newRefs.push({
+ ref,
+ data: buffer.join("")
+ });
+ buffer.length = 0;
+ }
+ return newRefs.sort((a, b) => a.ref.num - b.ref.num);
+}
+async function incrementalUpdate({
+ originalData,
+ xrefInfo,
+ changes,
+ xref = null,
+ hasXfa = false,
+ xfaDatasetsRef = null,
+ hasXfaDatasetsEntry = false,
+ needAppearances,
+ acroFormRef = null,
+ acroForm = null,
+ xfaData = null,
+ useXrefStream = false
+}) {
+ await updateAcroform({
+ xref,
+ acroForm,
+ acroFormRef,
+ hasXfa,
+ hasXfaDatasetsEntry,
+ xfaDatasetsRef,
+ needAppearances,
+ changes
+ });
+ if (hasXfa) {
+ updateXFA({
+ xfaData,
+ xfaDatasetsRef,
+ changes,
+ xref
+ });
+ }
+ const newXref = getTrailerDict(xrefInfo, changes, useXrefStream);
+ const buffer = [];
+ const newRefs = await writeChanges(changes, xref, buffer);
+ let baseOffset = originalData.length;
+ const lastByte = originalData.at(-1);
+ if (lastByte !== 0x0a && lastByte !== 0x0d) {
+ buffer.push("\n");
+ baseOffset += 1;
+ }
+ for (const {
+ data
+ } of newRefs) {
+ if (data !== null) {
+ buffer.push(data);
+ }
+ }
+ await (useXrefStream ? getXRefStreamTable(xrefInfo, baseOffset, newRefs, newXref, buffer) : getXRefTable(xrefInfo, baseOffset, newRefs, newXref, buffer));
+ const totalLength = originalData.length + Math.sumPrecise(buffer.map(str => str.length));
+ const array = new Uint8Array(totalLength);
+ array.set(originalData);
+ let offset = originalData.length;
+ for (const str of buffer) {
+ offset = writeString(str, offset, array);
+ }
+ return array;
+}
+
+;// ./src/core/editor/pdf_editor.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const MAX_LEAVES_PER_PAGES_NODE = 16;
+const MAX_IN_NAME_TREE_NODE = 64;
+class PageData {
+ constructor(page, documentData) {
+ this.page = page;
+ this.documentData = documentData;
+ this.annotations = null;
+ this.pointingNamedDestinations = null;
+ this.copyLevel = 0;
+ documentData.pagesMap.put(page.ref, this);
+ }
+}
+class DocumentData {
+ constructor(document) {
+ this.document = document;
+ this.destinations = null;
+ this.pageLabels = null;
+ this.pagesMap = new RefMap();
+ this.oldRefMapping = new RefMap();
+ this.dedupNamedDestinations = new Map();
+ this.usedNamedDestinations = new Set();
+ this.postponedRefCopies = new RefMap();
+ this.resourceStreamPromises = new Map();
+ this.usedStructParents = new Set();
+ this.oldStructParentMapping = new Map();
+ this.structTreeRoot = null;
+ this.parentTree = null;
+ this.idTree = null;
+ this.roleMap = null;
+ this.classMap = null;
+ this.namespaces = null;
+ this.structTreeAF = null;
+ this.structTreePronunciationLexicon = [];
+ this.acroForm = null;
+ this.acroFormDefaultAppearance = "";
+ this.acroFormDefaultResources = null;
+ this.acroFormQ = 0;
+ this.hasSignatureAnnotations = false;
+ this.fieldToParent = new RefMap();
+ this.outline = null;
+ this.embeddedFiles = null;
+ }
+}
+class XRefWrapper {
+ constructor(entries, getNewRef) {
+ this.entries = entries;
+ this._getNewRef = getNewRef;
+ }
+ getNewTemporaryRef() {
+ return this._getNewRef();
+ }
+ countUpdatesAfter(offset) {
+ return null;
+ }
+ fetchIfRef(obj) {
+ return obj instanceof Ref ? this.fetch(obj) : obj;
+ }
+ fetch(ref) {
+ if (!(ref instanceof Ref)) {
+ throw new Error("ref object is not a reference");
+ }
+ return this.entries[ref.num];
+ }
+ async fetchIfRefAsync(obj) {
+ return obj instanceof Ref ? this.fetchAsync(obj) : obj;
+ }
+ async fetchAsync(ref) {
+ return this.fetch(ref);
+ }
+}
+class PDFEditor {
+ isSingleFile = false;
+ #newAnnotationsParams = null;
+ #primaryDocument = null;
+ #resourceStreamCache = new Map();
+ currentDocument = null;
+ oldPages = [];
+ newPages = [];
+ xref = [null];
+ xrefWrapper = new XRefWrapper(this.xref, () => this.newRef);
+ newRefCount = 1;
+ namesDict = null;
+ version = "1.7";
+ pageLabels = null;
+ namedDestinations = new Map();
+ parentTree = new Map();
+ structTreeKids = [];
+ idTree = new Map();
+ classMap = new Dict();
+ roleMap = new Dict();
+ namespaces = new Map();
+ structTreeAF = [];
+ structTreePronunciationLexicon = [];
+ fields = [];
+ acroFormDefaultAppearance = "";
+ acroFormDefaultResources = null;
+ acroFormNeedAppearances = false;
+ acroFormSigFlags = 0;
+ acroFormCalculationOrder = null;
+ acroFormQ = 0;
+ outlineItems = null;
+ embeddedFiles = new Map();
+ constructor({
+ useObjectStreams = true,
+ title = "",
+ author = ""
+ } = {}) {
+ [this.rootRef, this.rootDict] = this.newDict;
+ [this.infoRef, this.infoDict] = this.newDict;
+ [this.pagesRef, this.pagesDict] = this.newDict;
+ this.useObjectStreams = useObjectStreams;
+ this.objStreamRefs = useObjectStreams ? new Set() : null;
+ this.title = title;
+ this.author = author;
+ }
+ get newRef() {
+ return Ref.get(this.newRefCount++, 0);
+ }
+ get newDict() {
+ const ref = this.newRef;
+ const dict = this.xref[ref.num] = new Dict();
+ return [ref, dict];
+ }
+ async #cloneObject(obj, xref) {
+ const ref = this.newRef;
+ this.xref[ref.num] = await this.#collectDependencies(obj, true, xref);
+ return ref;
+ }
+ cloneDict(dict) {
+ const newDict = dict.clone();
+ newDict.xref = this.xrefWrapper;
+ return newDict;
+ }
+ async #collectDependencies(obj, mustClone, xref, resourceStreamPath = new RefSet()) {
+ if (obj instanceof Ref) {
+ const {
+ currentDocument: {
+ fieldToParent,
+ oldRefMapping
+ }
+ } = this;
+ const existingRef = oldRefMapping.get(obj);
+ if (existingRef) {
+ return existingRef;
+ }
+ const oldRef = obj;
+ obj = await xref.fetchAsync(oldRef);
+ const mappedRef = oldRefMapping.get(oldRef);
+ if (mappedRef) {
+ return mappedRef;
+ }
+ if (typeof obj === "number") {
+ return obj;
+ }
+ if (obj instanceof BaseStream && this.#isResourceStream(obj.dict)) {
+ return this.#collectResourceStream(oldRef, obj, xref, resourceStreamPath);
+ }
+ const newRef = this.newRef;
+ oldRefMapping.put(oldRef, newRef);
+ let cloneSource = true;
+ if (fieldToParent.has(oldRef) && obj instanceof Dict) {
+ obj = this.cloneDict(obj);
+ obj.delete("Parent");
+ cloneSource = false;
+ }
+ this.xref[newRef.num] = await this.#collectDependencies(obj, cloneSource, xref, resourceStreamPath);
+ return newRef;
+ }
+ const promises = [];
+ const {
+ currentDocument: {
+ postponedRefCopies
+ }
+ } = this;
+ if (Array.isArray(obj)) {
+ if (mustClone) {
+ obj = obj.slice();
+ }
+ for (let i = 0, ii = obj.length; i < ii; i++) {
+ const postponedActions = obj[i] instanceof Ref && postponedRefCopies.get(obj[i]);
+ if (postponedActions) {
+ postponedActions.push(ref => obj[i] = ref);
+ continue;
+ }
+ promises.push(this.#collectDependencies(obj[i], true, xref, resourceStreamPath).then(newObj => obj[i] = newObj));
+ }
+ await Promise.all(promises);
+ return obj;
+ }
+ let dict;
+ if (obj instanceof BaseStream) {
+ ({
+ dict
+ } = obj = obj.getOriginalStream().clone());
+ dict.xref = this.xrefWrapper;
+ } else if (obj instanceof Dict) {
+ if (mustClone) {
+ obj = obj.clone();
+ obj.xref = this.xrefWrapper;
+ }
+ dict = obj;
+ }
+ if (dict) {
+ for (const [key, rawObj] of dict.getRawEntries()) {
+ const postponedActions = rawObj instanceof Ref && postponedRefCopies.get(rawObj);
+ if (postponedActions) {
+ postponedActions.push(ref => dict.set(key, ref));
+ continue;
+ }
+ promises.push(this.#collectDependencies(rawObj, true, xref, resourceStreamPath).then(newObj => dict.set(key, newObj)));
+ }
+ await Promise.all(promises);
+ }
+ return obj;
+ }
+ #isResourceStream(dict) {
+ const subtype = dict.get("Subtype");
+ return isName(subtype, "Image") || dict.has("Length1") || isName(subtype, "Type1C") || isName(subtype, "CIDFontType0C") || isName(subtype, "OpenType");
+ }
+ #rawStreamBytes(stream) {
+ const original = stream.getOriginalStream();
+ original.reset();
+ return original.getBytes();
+ }
+ async #serializeDict(dict) {
+ const buffer = [];
+ await writeValue(dict, buffer, null);
+ return buffer.join("");
+ }
+ #resourceStreamKey(dictStr, bytes) {
+ const SAMPLE_SIZE = 256;
+ const SAMPLE_COUNT = 4;
+ const {
+ length
+ } = bytes;
+ const hash = new MurmurHash3_64();
+ hash.update(dictStr);
+ hash.update(`#${length}`);
+ if (length <= SAMPLE_SIZE * SAMPLE_COUNT) {
+ hash.update(bytes);
+ } else {
+ const step = Math.floor((length - SAMPLE_SIZE) / (SAMPLE_COUNT - 1));
+ for (let i = 0; i < SAMPLE_COUNT; i++) {
+ const start = Math.min(i * step, length - SAMPLE_SIZE);
+ hash.update(bytes.subarray(start, start + SAMPLE_SIZE));
+ }
+ }
+ return hash.hexdigest();
+ }
+ async #collectResourceStream(oldRef, stream, xref, resourceStreamPath) {
+ const {
+ currentDocument: {
+ oldRefMapping,
+ resourceStreamPromises
+ }
+ } = this;
+ if (resourceStreamPath.has(oldRef)) {
+ return oldRefMapping.getOrPutComputed(oldRef, () => this.newRef);
+ }
+ const key = oldRef.toString();
+ const pending = resourceStreamPromises.get(key);
+ if (pending) {
+ return pending;
+ }
+ const childPath = new RefSet(resourceStreamPath);
+ childPath.put(oldRef);
+ const promise = Promise.resolve().then(async () => {
+ const collected = await this.#collectDependencies(stream, true, xref, childPath);
+ const cycleRef = oldRefMapping.get(oldRef);
+ if (cycleRef) {
+ this.xref[cycleRef.num] = collected;
+ return cycleRef;
+ }
+ const ref = await this.#dedupResourceStream(collected);
+ oldRefMapping.put(oldRef, ref);
+ return ref;
+ });
+ resourceStreamPromises.set(key, promise);
+ try {
+ return await promise;
+ } finally {
+ if (resourceStreamPromises.get(key) === promise) {
+ resourceStreamPromises.delete(key);
+ }
+ }
+ }
+ async #dedupResourceStream(stream) {
+ const dictStr = await this.#serializeDict(stream.dict);
+ const bytes = this.#rawStreamBytes(stream);
+ const key = this.#resourceStreamKey(dictStr, bytes);
+ const bucket = this.#resourceStreamCache.getOrInsertComputed(key, makeArr);
+ for (const entry of bucket) {
+ if (entry.dictStr === dictStr && isArrayEqual(this.#rawStreamBytes(entry.stream), bytes)) {
+ return entry.ref;
+ }
+ }
+ const ref = this.newRef;
+ this.xref[ref.num] = stream;
+ bucket.push({
+ ref,
+ dictStr,
+ stream
+ });
+ return ref;
+ }
+ async #resolveStructKids(rawKids, xref) {
+ if (rawKids instanceof Ref) {
+ const fetched = await xref.fetchAsync(rawKids);
+ return Array.isArray(fetched) ? fetched : [rawKids];
+ }
+ return Array.isArray(rawKids) ? rawKids : [rawKids];
+ }
+ async #cloneStructTreeNode(parentStructRef, node, xref, removedStructElements, dedupIDs, dedupClasses, dedupRoles, visited = new RefSet()) {
+ const {
+ currentDocument: {
+ pagesMap,
+ oldRefMapping
+ }
+ } = this;
+ const pg = node.getRaw("Pg");
+ if (pg instanceof Ref && !pagesMap.has(pg)) {
+ return null;
+ }
+ const k = node.getRaw("K");
+ if (k instanceof Ref && visited.has(k)) {
+ return null;
+ }
+ const kids = await this.#resolveStructKids(k, xref);
+ const newKids = [];
+ const structElemIndices = [];
+ for (let kid of kids) {
+ const kidRef = kid instanceof Ref ? kid : null;
+ if (kidRef) {
+ if (visited.has(kidRef)) {
+ continue;
+ }
+ visited.put(kidRef);
+ kid = await xref.fetchAsync(kidRef);
+ }
+ if (typeof kid === "number") {
+ newKids.push(kid);
+ continue;
+ }
+ if (!(kid instanceof Dict)) {
+ continue;
+ }
+ const pgRef = kid.getRaw("Pg");
+ if (pgRef instanceof Ref && !pagesMap.has(pgRef)) {
+ continue;
+ }
+ const type = kid.get("Type");
+ if (!type || isName(type, "StructElem")) {
+ let setAsSpan = false;
+ if (kidRef && removedStructElements.has(kidRef)) {
+ if (!isName(kid.get("S"), "Link")) {
+ continue;
+ }
+ setAsSpan = true;
+ }
+ const newKidRef = await this.#cloneStructTreeNode(kidRef, kid, xref, removedStructElements, dedupIDs, dedupClasses, dedupRoles, visited);
+ if (newKidRef) {
+ structElemIndices.push(newKids.length);
+ newKids.push(newKidRef);
+ if (kidRef) {
+ oldRefMapping.put(kidRef, newKidRef);
+ }
+ if (setAsSpan) {
+ this.xref[newKidRef.num].setIfName("S", "Span");
+ }
+ }
+ continue;
+ }
+ if (isName(type, "OBJR")) {
+ if (!kidRef) {
+ continue;
+ }
+ const oldObjRef = kid.getRaw("Obj");
+ if (oldObjRef instanceof Ref && !oldRefMapping.get(oldObjRef)) {
+ continue;
+ }
+ const newKidRef = oldRefMapping.get(kidRef) || (await this.#collectDependencies(kidRef, true, xref));
+ const newKid = this.xref[newKidRef.num];
+ const objRef = newKid.getRaw("Obj");
+ if (objRef instanceof Ref) {
+ const obj = this.xref[objRef.num];
+ if (obj instanceof Dict && !obj.has("StructParent") && parentStructRef) {
+ const structParent = this.parentTree.size;
+ this.parentTree.set(structParent, [oldRefMapping, parentStructRef]);
+ obj.set("StructParent", structParent);
+ }
+ }
+ newKids.push(newKidRef);
+ continue;
+ }
+ if (isName(type, "MCR")) {
+ const newKid = await this.#collectDependencies(kidRef || kid, true, xref);
+ newKids.push(newKid);
+ continue;
+ }
+ if (kidRef) {
+ const newKidRef = await this.#collectDependencies(kidRef, true, xref);
+ newKids.push(newKidRef);
+ }
+ }
+ if (kids.length !== 0 && newKids.length === 0) {
+ return null;
+ }
+ const newNodeRef = this.newRef;
+ const newNode = this.xref[newNodeRef.num] = this.cloneDict(node);
+ newNode.delete("ID");
+ newNode.delete("C");
+ newNode.delete("K");
+ newNode.delete("P");
+ newNode.delete("S");
+ await this.#collectDependencies(newNode, false, xref);
+ const classNames = node.get("C");
+ if (classNames instanceof Name) {
+ const newClassName = dedupClasses.get(classNames.name);
+ newNode.set("C", newClassName ? Name.get(newClassName) : classNames);
+ } else if (Array.isArray(classNames)) {
+ const newClassNames = [];
+ for (const className of classNames) {
+ if (className instanceof Name) {
+ const newClassName = dedupClasses.get(className.name);
+ newClassNames.push(newClassName ? Name.get(newClassName) : className);
+ }
+ }
+ newNode.set("C", newClassNames);
+ }
+ const roleName = node.get("S");
+ if (roleName instanceof Name) {
+ const newRoleName = dedupRoles.get(roleName.name);
+ newNode.set("S", newRoleName ? Name.get(newRoleName) : roleName);
+ }
+ const id = node.get("ID");
+ if (typeof id === "string") {
+ const stringId = stringToPDFString(id, false);
+ const newId = dedupIDs.get(stringId);
+ newNode.set("ID", newId ? stringToAsciiOrUTF16BE(newId) : id);
+ }
+ let attributes = newNode.get("A");
+ if (attributes) {
+ if (!Array.isArray(attributes)) {
+ attributes = [attributes];
+ }
+ for (let attr of attributes) {
+ attr = this.xrefWrapper.fetchIfRef(attr);
+ if (!(attr instanceof Dict)) {
+ continue;
+ }
+ if (isName(attr.get("O"), "Table") && attr.has("Headers")) {
+ const headers = this.xrefWrapper.fetchIfRef(attr.getRaw("Headers"));
+ if (Array.isArray(headers)) {
+ for (let i = 0, ii = headers.length; i < ii; i++) {
+ const header = this.xrefWrapper.fetchIfRef(headers[i]);
+ if (typeof header !== "string") {
+ continue;
+ }
+ const newId = dedupIDs.get(stringToPDFString(header, false));
+ if (newId) {
+ headers[i] = newId;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (const index of structElemIndices) {
+ const structElemRef = newKids[index];
+ const structElem = this.xref[structElemRef.num];
+ structElem.set("P", newNodeRef);
+ }
+ if (newKids.length === 1) {
+ newNode.set("K", newKids[0]);
+ } else if (newKids.length > 1) {
+ newNode.set("K", newKids);
+ }
+ return newNodeRef;
+ }
+ #getFilteredPageIndices({
+ document,
+ includePages,
+ excludePages
+ }) {
+ if (!document) {
+ return [];
+ }
+ const compile = list => {
+ if (!list?.length) {
+ return null;
+ }
+ const indices = new Set();
+ const ranges = [];
+ for (const item of list) {
+ if (Array.isArray(item)) {
+ ranges.push(item);
+ } else {
+ indices.add(item);
+ }
+ }
+ return {
+ indices,
+ ranges
+ };
+ };
+ const matches = (index, {
+ indices,
+ ranges
+ }) => indices.has(index) || ranges.some(([start, end]) => index >= start && index <= end);
+ const inc = compile(includePages);
+ const exc = compile(excludePages);
+ const result = [];
+ for (let i = 0, ii = document.numPages; i < ii; i++) {
+ if (exc && matches(i, exc)) {
+ continue;
+ }
+ if (!inc || matches(i, inc)) {
+ result.push(i);
+ }
+ }
+ return result;
+ }
+ #resolveInsertAfterIndices(pageInfos) {
+ const counts = new Array(pageInfos.length);
+ const sequence = [];
+ const insertAfterList = [];
+ for (let i = 0; i < pageInfos.length; i++) {
+ const info = pageInfos[i];
+ let count;
+ if (info.image) {
+ count = counts[i] = 1;
+ } else if (!info.document) {
+ counts[i] = 0;
+ continue;
+ } else {
+ count = counts[i] = this.#getFilteredPageIndices(info).length;
+ }
+ if (info.pageIndices) {
+ continue;
+ }
+ if (info.insertAfter === undefined) {
+ for (let j = 0; j < count; j++) {
+ sequence.push(i);
+ }
+ } else {
+ insertAfterList.push({
+ i,
+ insertAfter: info.insertAfter,
+ count
+ });
+ }
+ }
+ if (insertAfterList.length === 0) {
+ return pageInfos;
+ }
+ const hasContent = info => !!(info.document || info.image);
+ for (let i = 0; i < pageInfos.length; i++) {
+ const info = pageInfos[i];
+ if (hasContent(info) && info.pageIndices && info.pageIndices.length < counts[i]) {
+ throw new Error("extractPages: partial pageIndices cannot be combined with insertAfter entries.");
+ }
+ }
+ insertAfterList.sort((a, b) => a.insertAfter - b.insertAfter || a.i - b.i);
+ if (sequence.length === 0 && pageInfos.some(info => hasContent(info) && info.pageIndices)) {
+ const updatedPageInfos = pageInfos.slice();
+ let maxExistingPos = -1;
+ for (const info of pageInfos) {
+ if (!hasContent(info) || !info.pageIndices) {
+ continue;
+ }
+ for (const idx of info.pageIndices) {
+ if (idx > maxExistingPos) {
+ maxExistingPos = idx;
+ }
+ }
+ }
+ let offset = 0;
+ for (const {
+ i,
+ insertAfter,
+ count
+ } of insertAfterList) {
+ const threshold = Math.min(Math.max(insertAfter, -1) + offset, maxExistingPos);
+ for (let j = 0; j < updatedPageInfos.length; j++) {
+ const existingInfo = updatedPageInfos[j];
+ if (!hasContent(existingInfo) || !existingInfo.pageIndices || existingInfo.pageIndices.every(idx => idx <= threshold)) {
+ continue;
+ }
+ updatedPageInfos[j] = {
+ ...existingInfo,
+ pageIndices: existingInfo.pageIndices.map(idx => idx > threshold ? idx + count : idx)
+ };
+ }
+ const pageIndices = [];
+ for (let k = 0; k < count; k++) {
+ pageIndices.push(threshold + 1 + k);
+ }
+ const result = {
+ ...updatedPageInfos[i],
+ pageIndices
+ };
+ delete result.insertAfter;
+ updatedPageInfos[i] = result;
+ offset += count;
+ maxExistingPos += count;
+ }
+ return updatedPageInfos;
+ }
+ let offset = 0;
+ for (const {
+ i,
+ insertAfter,
+ count
+ } of insertAfterList) {
+ const insertPos = Math.max(insertAfter, -1) + 1 + offset;
+ sequence.splice(insertPos, 0, ...new Array(count).fill(i));
+ offset += count;
+ }
+ const pageIndicesArr = new Array(pageInfos.length);
+ for (let pos = 0; pos < sequence.length; pos++) {
+ const infoIdx = sequence[pos];
+ (pageIndicesArr[infoIdx] ||= []).push(pos);
+ }
+ return pageInfos.map((info, i) => {
+ if (!hasContent(info) || info.pageIndices) {
+ return info;
+ }
+ const result = {
+ ...info,
+ pageIndices: pageIndicesArr[i] || []
+ };
+ delete result.insertAfter;
+ return result;
+ });
+ }
+ async extractPages(pageInfos, annotationStorage, primaryDocument, handler, task) {
+ this.#primaryDocument = primaryDocument;
+ pageInfos = this.#resolveInsertAfterIndices(pageInfos);
+ const promises = [];
+ let newIndex = 0;
+ const reservePageSlot = newPageIndex => {
+ if (!Number.isInteger(newPageIndex) || newPageIndex < 0) {
+ throw new Error("extractPages: invalid page index.");
+ }
+ if (this.oldPages[newPageIndex] !== undefined) {
+ throw new Error("extractPages: overlapping pageIndices.");
+ }
+ this.oldPages[newPageIndex] = null;
+ };
+ const allDocumentData = [];
+ if (annotationStorage) {
+ this.#newAnnotationsParams = {
+ handler,
+ task,
+ newAnnotationsByPage: getNewAnnotationsMap(annotationStorage),
+ imagesPromises: AnnotationFactory.generateImages(annotationStorage.values(), this.xrefWrapper, true)
+ };
+ }
+ const imageEntries = [];
+ for (const pageInfo of pageInfos) {
+ const {
+ document,
+ image,
+ includePages,
+ excludePages,
+ pageIndices
+ } = pageInfo;
+ if (image) {
+ if (pageIndices) {
+ newIndex = -1;
+ if (pageIndices.length > 1) {
+ throw new Error("extractPages: too many pageIndices.");
+ }
+ }
+ let newPageIndex;
+ if (pageIndices?.length) {
+ newPageIndex = pageIndices[0];
+ } else if (newIndex !== -1) {
+ newPageIndex = newIndex++;
+ } else {
+ for (newPageIndex = 0; this.oldPages[newPageIndex] !== undefined; newPageIndex++) {}
+ }
+ reservePageSlot(newPageIndex);
+ imageEntries.push({
+ image,
+ slot: newPageIndex
+ });
+ continue;
+ }
+ if (!document) {
+ continue;
+ }
+ if (pageIndices) {
+ newIndex = -1;
+ }
+ const filteredPageIndices = this.#getFilteredPageIndices({
+ document,
+ includePages,
+ excludePages
+ });
+ if (pageIndices && pageIndices.length > filteredPageIndices.length) {
+ throw new Error("extractPages: too many pageIndices.");
+ }
+ const documentData = new DocumentData(document);
+ allDocumentData.push(documentData);
+ promises.push(this.#collectDocumentData(documentData));
+ let pageIndex = 0;
+ for (const i of filteredPageIndices) {
+ let newPageIndex;
+ if (pageIndices) {
+ newPageIndex = pageIndices[pageIndex++];
+ }
+ if (newPageIndex === undefined) {
+ if (newIndex !== -1) {
+ newPageIndex = newIndex++;
+ } else {
+ for (newPageIndex = 0; this.oldPages[newPageIndex] !== undefined; newPageIndex++) {}
+ }
+ }
+ reservePageSlot(newPageIndex);
+ promises.push(document.getPage(i).then(page => {
+ this.oldPages[newPageIndex] = new PageData(page, documentData);
+ }));
+ }
+ }
+ await Promise.all(promises);
+ if (this.oldPages.length === 0) {
+ throw new Error("extractPages: nothing to extract.");
+ }
+ const copyCounts = new Map();
+ const documents = new Set();
+ for (let i = 0, ii = this.oldPages.length; i < ii; i++) {
+ const pageData = this.oldPages[i];
+ if (pageData === undefined) {
+ throw new Error("extractPages: sparse pageIndices.");
+ }
+ if (pageData) {
+ const {
+ page
+ } = pageData;
+ const copyLevel = copyCounts.get(page) ?? 0;
+ copyCounts.set(page, copyLevel + 1);
+ pageData.copyLevel = copyLevel;
+ documents.add(pageData.documentData.document);
+ }
+ }
+ this.isSingleFile = documents.size === 1;
+ promises.length = 0;
+ this.#collectValidDestinations(allDocumentData);
+ this.#collectOutlineDestinations(allDocumentData);
+ this.#collectPageLabels();
+ for (const page of this.oldPages) {
+ if (page) {
+ promises.push(this.#postCollectPageData(page));
+ }
+ }
+ await Promise.all(promises);
+ this.#findDuplicateNamedDestinations();
+ this.#setPostponedRefCopies(allDocumentData);
+ const imageSlots = new Map();
+ for (const entry of imageEntries) {
+ imageSlots.set(entry.slot, entry);
+ }
+ const modalPageSize = imageSlots.size > 0 ? this.#modalPageSize() : null;
+ for (let i = 0, ii = this.oldPages.length; i < ii; i++) {
+ const imageEntry = imageSlots.get(i);
+ if (imageEntry) {
+ this.newPages[i] = await this.#makeImagePage(imageEntry.image, modalPageSize);
+ } else {
+ this.newPages[i] = await this.#makePageCopy(i, null);
+ }
+ }
+ this.#fixPostponedRefCopies(allDocumentData);
+ await this.#mergeStructTrees(allDocumentData);
+ await this.#mergeAcroForms(allDocumentData);
+ this.#buildOutline(allDocumentData);
+ await this.#collectEmbeddedFiles(allDocumentData);
+ return this.writePDF();
+ }
+ async #collectDocumentData(documentData) {
+ const {
+ document: {
+ pdfManager,
+ xref
+ }
+ } = documentData;
+ await Promise.all([pdfManager.ensureCatalog("destinations").then(destinations => documentData.destinations = destinations), pdfManager.ensureCatalog("rawPageLabels").then(pageLabels => documentData.pageLabels = pageLabels), pdfManager.ensureCatalog("structTreeRoot").then(structTreeRoot => documentData.structTreeRoot = structTreeRoot), pdfManager.ensureCatalog("acroForm").then(acroForm => documentData.acroForm = acroForm), pdfManager.ensureCatalog("documentOutlineForEditor").then(outline => documentData.outline = outline), pdfManager.ensureCatalog("rawEmbeddedFiles").then(ef => documentData.embeddedFiles = ef)]);
+ const structTreeRoot = documentData.structTreeRoot;
+ if (structTreeRoot) {
+ const rootDict = structTreeRoot.dict;
+ const parentTree = rootDict.get("ParentTree");
+ if (parentTree) {
+ const numberTree = new NumberTree(parentTree, xref);
+ documentData.parentTree = numberTree.getAll(true);
+ }
+ const idTree = rootDict.get("IDTree");
+ if (idTree) {
+ const nameTree = new NameTree(idTree, xref);
+ documentData.idTree = nameTree.getAll(true);
+ }
+ documentData.roleMap = rootDict.get("RoleMap") || null;
+ documentData.classMap = rootDict.get("ClassMap") || null;
+ let namespaces = rootDict.get("Namespaces") || null;
+ if (namespaces && !Array.isArray(namespaces)) {
+ namespaces = [namespaces];
+ }
+ documentData.namespaces = namespaces;
+ documentData.structTreeAF = rootDict.get("AF") || null;
+ documentData.structTreePronunciationLexicon = rootDict.get("PronunciationLexicon") || null;
+ }
+ }
+ async #postCollectPageData(pageData) {
+ const {
+ page: {
+ xref,
+ annotations
+ },
+ documentData: {
+ pagesMap,
+ destinations,
+ usedNamedDestinations,
+ fieldToParent
+ }
+ } = pageData;
+ if (!annotations) {
+ return;
+ }
+ const promises = [];
+ let newAnnotations = [];
+ let newIndex = 0;
+ let {
+ hasSignatureAnnotations
+ } = pageData.documentData;
+ for (const annotationRef of annotations) {
+ const newAnnotationIndex = newIndex++;
+ promises.push(xref.fetchIfRefAsync(annotationRef).then(async annotationDict => {
+ if (!isName(annotationDict.get("Subtype"), "Link")) {
+ if (isName(annotationDict.get("Subtype"), "Widget")) {
+ hasSignatureAnnotations ||= isName(getInheritableProperty({
+ dict: annotationDict,
+ key: "FT"
+ }), "Sig");
+ const parentRef = annotationDict.getRaw("Parent") || null;
+ fieldToParent.put(annotationRef, parentRef);
+ }
+ newAnnotations[newAnnotationIndex] = annotationRef;
+ return;
+ }
+ const action = annotationDict.get("A");
+ if (action instanceof Dict && !isName(action.get("S"), "GoTo")) {
+ newAnnotations[newAnnotationIndex] = annotationRef;
+ return;
+ }
+ const dest = action instanceof Dict ? action.get("D") : annotationDict.get("Dest");
+ if (!dest || Array.isArray(dest) && (!(dest[0] instanceof Ref) || pagesMap.has(dest[0]))) {
+ newAnnotations[newAnnotationIndex] = annotationRef;
+ } else if (dest instanceof Name || typeof dest === "string") {
+ const destString = stringToPDFString(dest instanceof Name ? dest.name : dest, true);
+ if (destinations.has(destString)) {
+ newAnnotations[newAnnotationIndex] = annotationRef;
+ usedNamedDestinations.add(destString);
+ }
+ }
+ }));
+ }
+ await Promise.all(promises);
+ newAnnotations = newAnnotations.filter(Boolean);
+ pageData.annotations = newAnnotations.length > 0 ? newAnnotations : null;
+ pageData.documentData.hasSignatureAnnotations ||= hasSignatureAnnotations;
+ }
+ #setPostponedRefCopies(allDocumentData) {
+ for (const {
+ postponedRefCopies,
+ pagesMap
+ } of allDocumentData) {
+ for (const oldPageRef of pagesMap.keys()) {
+ postponedRefCopies.put(oldPageRef, []);
+ }
+ }
+ }
+ #fixPostponedRefCopies(allDocumentData) {
+ for (const {
+ postponedRefCopies,
+ oldRefMapping
+ } of allDocumentData) {
+ for (const [oldRef, actions] of postponedRefCopies.items()) {
+ const newRef = oldRefMapping.get(oldRef);
+ for (const action of actions) {
+ action(newRef);
+ }
+ }
+ postponedRefCopies.clear();
+ }
+ }
+ #visitObject(obj, callback, visited = new RefSet()) {
+ if (obj instanceof Ref) {
+ if (!visited.has(obj)) {
+ visited.put(obj);
+ this.#visitObject(this.xref[obj.num], callback, visited);
+ }
+ return;
+ }
+ if (Array.isArray(obj)) {
+ for (const item of obj) {
+ this.#visitObject(item, callback, visited);
+ }
+ return;
+ }
+ let dict;
+ if (obj instanceof BaseStream) {
+ ({
+ dict
+ } = obj);
+ } else if (obj instanceof Dict) {
+ dict = obj;
+ }
+ if (dict) {
+ callback(dict);
+ for (const value of dict.getRawValues()) {
+ this.#visitObject(value, callback, visited);
+ }
+ }
+ }
+ async #mergeStructTrees(allDocumentData) {
+ let newStructParentId = 0;
+ const {
+ parentTree: newParentTree
+ } = this;
+ for (let i = 0, ii = this.newPages.length; i < ii; i++) {
+ if (!this.oldPages[i]) {
+ continue;
+ }
+ const {
+ documentData: {
+ parentTree,
+ oldRefMapping,
+ oldStructParentMapping,
+ usedStructParents,
+ document: {
+ xref
+ }
+ }
+ } = this.oldPages[i];
+ if (!parentTree) {
+ continue;
+ }
+ const pageRef = this.newPages[i];
+ const pageDict = this.xref[pageRef.num];
+ const visited = new RefSet();
+ visited.put(pageRef);
+ this.#visitObject(pageDict, dict => {
+ const structParent = dict.get("StructParent") ?? dict.get("StructParents");
+ if (typeof structParent !== "number") {
+ return;
+ }
+ usedStructParents.add(structParent);
+ let parent = parentTree.get(structParent);
+ const parentRef = parent instanceof Ref ? parent : null;
+ if (parentRef) {
+ const array = xref.fetch(parentRef);
+ if (Array.isArray(array)) {
+ parent = array;
+ }
+ }
+ if (Array.isArray(parent) && parent.every(ref => ref === null)) {
+ parent = null;
+ }
+ if (!parent) {
+ if (dict.has("StructParent")) {
+ dict.delete("StructParent");
+ } else {
+ dict.delete("StructParents");
+ }
+ return;
+ }
+ let newStructParent = oldStructParentMapping.get(structParent);
+ if (newStructParent === undefined) {
+ newStructParent = newStructParentId++;
+ oldStructParentMapping.set(structParent, newStructParent);
+ newParentTree.set(newStructParent, [oldRefMapping, parent]);
+ }
+ if (dict.has("StructParent")) {
+ dict.set("StructParent", newStructParent);
+ } else {
+ dict.set("StructParents", newStructParent);
+ }
+ }, visited);
+ }
+ const {
+ structTreeKids,
+ idTree: newIdTree,
+ classMap: newClassMap,
+ roleMap: newRoleMap,
+ namespaces: newNamespaces,
+ structTreeAF: newStructTreeAF,
+ structTreePronunciationLexicon: newStructTreePronunciationLexicon
+ } = this;
+ for (const documentData of allDocumentData) {
+ const {
+ document: {
+ xref
+ },
+ oldRefMapping,
+ parentTree,
+ usedStructParents,
+ structTreeRoot,
+ idTree,
+ classMap,
+ roleMap,
+ namespaces,
+ structTreeAF,
+ structTreePronunciationLexicon
+ } = documentData;
+ if (!structTreeRoot) {
+ continue;
+ }
+ this.currentDocument = documentData;
+ const removedStructElements = new RefSet();
+ for (const [key, value] of parentTree || []) {
+ if (!usedStructParents.has(key) && value instanceof Ref) {
+ removedStructElements.put(value);
+ }
+ }
+ const dedupIDs = new Map();
+ for (const [id, nodeRef] of idTree || []) {
+ let _id = id;
+ if (newIdTree.has(id)) {
+ for (let i = 1;; i++) {
+ const newId = `${id}_${i}`;
+ if (!newIdTree.has(newId)) {
+ dedupIDs.set(id, newId);
+ _id = newId;
+ break;
+ }
+ }
+ }
+ newIdTree.set(_id, nodeRef);
+ }
+ const dedupClasses = new Map();
+ if (classMap?.size > 0) {
+ for (let [className, classDict] of classMap) {
+ classDict = await this.#collectDependencies(classDict, true, xref);
+ if (newClassMap.has(className)) {
+ for (let i = 1;; i++) {
+ const newClassName = `${className}_${i}`;
+ if (!newClassMap.has(newClassName)) {
+ dedupClasses.set(className, newClassName);
+ className = newClassName;
+ break;
+ }
+ }
+ }
+ newClassMap.set(className, classDict);
+ }
+ }
+ const dedupRoles = new Map();
+ if (roleMap?.size > 0) {
+ for (const [roleName, mappedName] of roleMap) {
+ const newMappedName = newRoleMap.get(roleName);
+ if (!newMappedName) {
+ newRoleMap.set(roleName, mappedName);
+ continue;
+ }
+ if (newMappedName === mappedName) {
+ continue;
+ }
+ for (let i = 1;; i++) {
+ const newRoleName = `${roleName}_${i}`;
+ if (!newRoleMap.has(newRoleName)) {
+ dedupRoles.set(roleName, newRoleName);
+ newRoleMap.set(newRoleName, mappedName);
+ break;
+ }
+ }
+ }
+ }
+ if (namespaces?.length > 0) {
+ for (const namespaceRef of namespaces) {
+ const namespace = await xref.fetchIfRefAsync(namespaceRef);
+ let ns = namespace.get("NS");
+ if (!ns || newNamespaces.has(ns)) {
+ continue;
+ }
+ ns = stringToPDFString(ns, false);
+ const newNamespace = await this.#collectDependencies(namespace, true, xref);
+ newNamespaces.set(ns, newNamespace);
+ }
+ }
+ if (structTreeAF) {
+ for (const afRef of structTreeAF) {
+ newStructTreeAF.push(await this.#collectDependencies(afRef, true, xref));
+ }
+ }
+ if (structTreePronunciationLexicon) {
+ for (const lexiconRef of structTreePronunciationLexicon) {
+ newStructTreePronunciationLexicon.push(await this.#collectDependencies(lexiconRef, true, xref));
+ }
+ }
+ const rawKids = structTreeRoot.dict.getRaw("K");
+ if (!rawKids) {
+ continue;
+ }
+ const kids = await this.#resolveStructKids(rawKids, xref);
+ for (let kid of kids) {
+ const kidRef = kid instanceof Ref ? kid : null;
+ kid = await xref.fetchIfRefAsync(kid);
+ if (!(kid instanceof Dict)) {
+ continue;
+ }
+ let setAsSpan = false;
+ if (kidRef && removedStructElements.has(kidRef)) {
+ if (!isName(kid.get("S"), "Link")) {
+ continue;
+ }
+ setAsSpan = true;
+ }
+ const newKidRef = await this.#cloneStructTreeNode(kidRef, kid, xref, removedStructElements, dedupIDs, dedupClasses, dedupRoles);
+ if (newKidRef) {
+ structTreeKids.push(newKidRef);
+ if (kidRef) {
+ oldRefMapping.put(kidRef, newKidRef);
+ }
+ if (setAsSpan) {
+ this.xref[newKidRef.num].setIfName("S", "Span");
+ }
+ }
+ }
+ for (const [id, nodeRef] of idTree || []) {
+ const newNodeRef = nodeRef instanceof Ref && oldRefMapping.get(nodeRef);
+ const newId = dedupIDs.get(id) || id;
+ if (newNodeRef) {
+ newIdTree.set(newId, newNodeRef);
+ } else {
+ newIdTree.delete(newId);
+ }
+ }
+ }
+ for (const [key, [oldRefMapping, parent]] of newParentTree) {
+ if (!parent) {
+ newParentTree.delete(key);
+ continue;
+ }
+ if (!Array.isArray(parent)) {
+ const newParent = oldRefMapping.get(parent);
+ if (newParent === undefined) {
+ newParentTree.delete(key);
+ } else {
+ newParentTree.set(key, newParent);
+ }
+ continue;
+ }
+ const newParents = parent.map(ref => ref instanceof Ref && oldRefMapping.get(ref) || null);
+ if (newParents.length === 0 || newParents.every(ref => ref === null)) {
+ newParentTree.delete(key);
+ continue;
+ }
+ newParentTree.set(key, newParents);
+ }
+ this.currentDocument = null;
+ }
+ #collectValidDestinations(allDocumentData) {
+ for (const documentData of allDocumentData) {
+ if (!documentData.destinations) {
+ continue;
+ }
+ const {
+ destinations,
+ pagesMap
+ } = documentData;
+ const newDestinations = documentData.destinations = new Map();
+ for (const [key, dest] of destinations) {
+ const pageRef = dest[0];
+ const pageData = pageRef instanceof Ref && pagesMap.get(pageRef);
+ if (!pageData) {
+ continue;
+ }
+ (pageData.pointingNamedDestinations ||= new Set()).add(key);
+ newDestinations.set(key, dest);
+ }
+ }
+ }
+ #findDuplicateNamedDestinations() {
+ const {
+ namedDestinations
+ } = this;
+ const getUniqueDestinationName = name => {
+ if (!namedDestinations.has(name)) {
+ return name;
+ }
+ for (let i = 1;; i++) {
+ const dedupedName = `${name}_${i}`;
+ if (!namedDestinations.has(dedupedName)) {
+ return dedupedName;
+ }
+ }
+ };
+ for (let i = 0, ii = this.oldPages.length; i < ii; i++) {
+ const page = this.oldPages[i];
+ if (!page) {
+ continue;
+ }
+ const {
+ documentData: {
+ destinations,
+ dedupNamedDestinations,
+ usedNamedDestinations
+ }
+ } = page;
+ let {
+ pointingNamedDestinations
+ } = page;
+ if (!pointingNamedDestinations) {
+ continue;
+ }
+ page.pointingNamedDestinations = pointingNamedDestinations = pointingNamedDestinations.intersection(usedNamedDestinations);
+ for (const pointingDest of pointingNamedDestinations) {
+ if (!usedNamedDestinations.has(pointingDest)) {
+ continue;
+ }
+ const dest = destinations.get(pointingDest).slice();
+ if (!namedDestinations.has(pointingDest)) {
+ namedDestinations.set(pointingDest, dest);
+ continue;
+ }
+ const newName = getUniqueDestinationName(`${pointingDest}_p${i + 1}`);
+ dedupNamedDestinations.set(pointingDest, newName);
+ namedDestinations.set(newName, dest);
+ }
+ }
+ }
+ #fixNamedDestinations(annotations, dedupNamedDestinations) {
+ if (dedupNamedDestinations.size === 0) {
+ return;
+ }
+ const fixDestination = (dict, key, dest) => {
+ if (typeof dest === "string") {
+ dict.set(key, dedupNamedDestinations.get(stringToPDFString(dest, true)) || dest);
+ }
+ };
+ for (const annotRef of annotations) {
+ const annotDict = this.xref[annotRef.num];
+ if (!isName(annotDict.get("Subtype"), "Link")) {
+ continue;
+ }
+ const action = annotDict.get("A");
+ if (action instanceof Dict && action.has("D")) {
+ const dest = action.get("D");
+ fixDestination(action, "D", dest);
+ continue;
+ }
+ const dest = annotDict.get("Dest");
+ fixDestination(annotDict, "Dest", dest);
+ }
+ }
+ #collectOutlineDestinations(allDocumentData) {
+ const collect = (items, destinations, usedNamedDestinations) => {
+ for (const item of items) {
+ if (typeof item.dest === "string" && destinations?.has(item.dest)) {
+ usedNamedDestinations.add(item.dest);
+ }
+ if (item.items.length > 0) {
+ collect(item.items, destinations, usedNamedDestinations);
+ }
+ }
+ };
+ for (const documentData of allDocumentData) {
+ const {
+ outline,
+ destinations,
+ usedNamedDestinations
+ } = documentData;
+ if (outline?.length) {
+ collect(outline, destinations, usedNamedDestinations);
+ }
+ }
+ }
+ #isValidOutlineDest(item, documentData) {
+ const {
+ dest,
+ action,
+ url,
+ unsafeUrl,
+ attachment,
+ setOCGState
+ } = item;
+ if (action || url || unsafeUrl || attachment || setOCGState) {
+ return true;
+ }
+ if (!dest) {
+ return false;
+ }
+ if (typeof dest === "string") {
+ const name = documentData.dedupNamedDestinations.get(dest) || dest;
+ return this.namedDestinations.has(name);
+ }
+ if (Array.isArray(dest) && dest[0] instanceof Ref) {
+ return !!documentData.oldRefMapping.get(dest[0]);
+ }
+ return false;
+ }
+ #filterOutlineItems(items, documentData) {
+ const result = [];
+ for (const item of items) {
+ const filteredChildren = this.#filterOutlineItems(item.items, documentData);
+ const hasValidOwnDest = this.#isValidOutlineDest(item, documentData);
+ if (hasValidOwnDest || filteredChildren.length > 0) {
+ result.push({
+ ...item,
+ dest: hasValidOwnDest ? item.dest : null,
+ rawDict: hasValidOwnDest ? item.rawDict : null,
+ items: filteredChildren,
+ _documentData: documentData
+ });
+ }
+ }
+ return result;
+ }
+ #buildOutline(allDocumentData) {
+ const outlineItems = [];
+ for (const documentData of allDocumentData) {
+ const {
+ outline
+ } = documentData;
+ if (!outline?.length) {
+ continue;
+ }
+ outlineItems.push(...this.#filterOutlineItems(outline, documentData));
+ }
+ this.outlineItems = outlineItems.length > 0 ? outlineItems : null;
+ }
+ async #setOutlineItemDest(itemDict, item) {
+ const {
+ dest,
+ rawDict
+ } = item;
+ const documentData = item._documentData;
+ if (dest) {
+ if (typeof dest === "string") {
+ const name = documentData.dedupNamedDestinations.get(dest) || dest;
+ itemDict.set("Dest", stringToAsciiOrUTF16BE(name));
+ } else if (Array.isArray(dest)) {
+ const newDest = dest.slice();
+ if (newDest[0] instanceof Ref) {
+ newDest[0] = documentData.oldRefMapping.get(newDest[0]) || newDest[0];
+ }
+ itemDict.set("Dest", newDest);
+ }
+ return;
+ }
+ const actionDict = rawDict?.get("A");
+ if (actionDict instanceof Dict) {
+ this.currentDocument = documentData;
+ const actionRef = await this.#cloneObject(actionDict, documentData.document.xref);
+ this.currentDocument = null;
+ itemDict.set("A", actionRef);
+ }
+ }
+ async #makeOutline() {
+ const {
+ outlineItems
+ } = this;
+ if (!outlineItems?.length) {
+ return;
+ }
+ const [outlineRootRef, outlineRootDict] = this.newDict;
+ outlineRootDict.setIfName("Type", "Outlines");
+ const assignRefs = items => {
+ for (const item of items) {
+ [item._ref] = this.newDict;
+ if (item.items.length > 0) {
+ assignRefs(item.items);
+ }
+ }
+ };
+ assignRefs(outlineItems);
+ const fillItems = async (items, parentRef) => {
+ let totalCount = 0;
+ for (let i = 0; i < items.length; i++) {
+ const item = items[i];
+ const dict = this.xref[item._ref.num];
+ dict.set("Title", stringToAsciiOrUTF16BE(item.title));
+ dict.set("Parent", parentRef);
+ if (i > 0) {
+ dict.set("Prev", items[i - 1]._ref);
+ }
+ if (i < items.length - 1) {
+ dict.set("Next", items[i + 1]._ref);
+ }
+ if (item.items.length > 0) {
+ dict.set("First", item.items[0]._ref);
+ dict.set("Last", item.items.at(-1)._ref);
+ const childCount = await fillItems(item.items, item._ref);
+ if (item.count !== undefined) {
+ dict.set("Count", item.count < 0 ? -childCount : childCount);
+ }
+ totalCount += item.count !== undefined && item.count < 0 ? 1 : childCount + 1;
+ } else {
+ totalCount += 1;
+ }
+ await this.#setOutlineItemDest(dict, item);
+ const flags = (item.bold ? 2 : 0) | (item.italic ? 1 : 0);
+ if (flags !== 0) {
+ dict.set("F", flags);
+ }
+ if (item.color && (item.color[0] !== 0 || item.color[1] !== 0 || item.color[2] !== 0)) {
+ dict.set("C", [item.color[0] / 255, item.color[1] / 255, item.color[2] / 255]);
+ }
+ }
+ return totalCount;
+ };
+ const totalCount = await fillItems(outlineItems, outlineRootRef);
+ outlineRootDict.set("First", outlineItems[0]._ref);
+ outlineRootDict.set("Last", outlineItems.at(-1)._ref);
+ outlineRootDict.set("Count", totalCount);
+ this.rootDict.set("Outlines", outlineRootRef);
+ }
+ async #mergeAcroForms(allDocumentData) {
+ this.#setAcroFormDefaultBasicValues(allDocumentData);
+ this.#setAcroFormDefaultAppearance(allDocumentData);
+ this.#setAcroFormQ(allDocumentData);
+ await this.#setAcroFormDefaultResources(allDocumentData);
+ const newFields = this.fields;
+ for (const documentData of allDocumentData) {
+ let fields = documentData.acroForm?.get("Fields") || null;
+ if (!fields && documentData.fieldToParent.size > 0) {
+ fields = this.#fixFields(documentData.fieldToParent, documentData.document.xref);
+ }
+ if (Array.isArray(fields) && fields.length > 0) {
+ this.currentDocument = documentData;
+ await this.#cloneFields(newFields, fields);
+ this.currentDocument = null;
+ }
+ }
+ this.#setAcroFormCalculationOrder(allDocumentData);
+ }
+ #setAcroFormQ(allDocumentData) {
+ let firstQ = 0;
+ let firstDocData = null;
+ for (const documentData of allDocumentData) {
+ const q = documentData.acroForm?.get("Q");
+ if (typeof q !== "number" || q === 0) {
+ continue;
+ }
+ if (firstDocData?.acroFormQ > 0) {
+ documentData.acroFormQ = q;
+ continue;
+ }
+ if (firstQ === 0) {
+ firstQ = q;
+ firstDocData = documentData;
+ continue;
+ }
+ if (q === firstQ) {
+ continue;
+ }
+ firstDocData.acroFormQ ||= firstQ;
+ documentData.acroFormQ = q;
+ firstQ = 0;
+ }
+ if (firstQ > 0) {
+ this.acroFormQ = firstQ;
+ }
+ }
+ #setAcroFormDefaultBasicValues(allDocumentData) {
+ let sigFlags = 0;
+ let needAppearances = false;
+ for (const documentData of allDocumentData) {
+ if (!documentData.acroForm) {
+ continue;
+ }
+ const sf = documentData.acroForm.get("SigFlags");
+ if (typeof sf === "number" && documentData.hasSignatureAnnotations) {
+ sigFlags |= sf;
+ }
+ if (documentData.acroForm.get("NeedAppearances") === true) {
+ needAppearances = true;
+ }
+ }
+ this.acroFormSigFlags = sigFlags;
+ this.acroFormNeedAppearances = needAppearances;
+ }
+ #setAcroFormCalculationOrder(allDocumentData) {
+ const calculationOrder = [];
+ for (const documentData of allDocumentData) {
+ const co = documentData.acroForm?.get("CO") || null;
+ if (!Array.isArray(co)) {
+ continue;
+ }
+ const {
+ oldRefMapping
+ } = documentData;
+ for (const coRef of co) {
+ const newCoRef = coRef instanceof Ref && oldRefMapping.get(coRef);
+ if (newCoRef) {
+ calculationOrder.push(newCoRef);
+ }
+ }
+ }
+ this.acroFormCalculationOrder = calculationOrder.length > 0 ? calculationOrder : null;
+ }
+ #setAcroFormDefaultAppearance(allDocumentData) {
+ let firstDA = null;
+ let firstDocData = null;
+ for (const documentData of allDocumentData) {
+ const da = documentData.acroForm?.get("DA") || null;
+ if (!da || typeof da !== "string") {
+ continue;
+ }
+ if (firstDocData?.acroFormDefaultAppearance) {
+ documentData.acroFormDefaultAppearance = da;
+ continue;
+ }
+ if (!firstDA) {
+ firstDA = da;
+ firstDocData = documentData;
+ continue;
+ }
+ if (da === firstDA) {
+ continue;
+ }
+ firstDocData.acroFormDefaultAppearance ||= firstDA;
+ documentData.acroFormDefaultAppearance = da;
+ firstDA = null;
+ }
+ if (firstDA) {
+ this.acroFormDefaultAppearance = firstDA;
+ }
+ }
+ async #setAcroFormDefaultResources(allDocumentData) {
+ let firstDR = null;
+ let firstDRRef = null;
+ let firstDocData = null;
+ for (const documentData of allDocumentData) {
+ const dr = documentData.acroForm?.get("DR") || null;
+ if (!dr || !(dr instanceof Dict)) {
+ continue;
+ }
+ if (firstDocData?.acroFormDefaultResources) {
+ documentData.acroFormDefaultResources = dr;
+ continue;
+ }
+ if (!firstDR) {
+ firstDR = dr;
+ firstDRRef = documentData.acroForm.getRaw("DR");
+ firstDocData = documentData;
+ continue;
+ }
+ if (deepCompare(firstDR, dr)) {
+ continue;
+ }
+ firstDocData.acroFormDefaultResources ||= firstDR;
+ documentData.acroFormDefaultResources = dr;
+ firstDR = null;
+ firstDRRef = null;
+ }
+ if (firstDR) {
+ this.currentDocument = firstDocData;
+ this.acroFormDefaultResources = await this.#collectDependencies(firstDRRef, true, firstDocData.document.xref);
+ this.currentDocument = null;
+ }
+ }
+ #fixFields(fieldToParent, xref) {
+ const newFields = [];
+ const processed = new RefSet();
+ for (const [fieldRef, parentRef] of fieldToParent.items()) {
+ if (!parentRef) {
+ newFields.push(fieldRef);
+ continue;
+ }
+ let parent = parentRef;
+ let lastNonNullParent = parentRef;
+ const visited = new RefSet();
+ while (true) {
+ if (parent instanceof Ref) {
+ if (visited.has(parent)) {
+ break;
+ }
+ visited.put(parent);
+ }
+ const parentDict = xref.fetchIfRef(parent);
+ if (!(parentDict instanceof Dict)) {
+ break;
+ }
+ parent = parentDict.getRaw("Parent") || null;
+ if (!parent) {
+ break;
+ }
+ lastNonNullParent = parent;
+ }
+ if (lastNonNullParent instanceof Ref && !processed.has(lastNonNullParent)) {
+ newFields.push(lastNonNullParent);
+ processed.put(lastNonNullParent);
+ }
+ }
+ return newFields;
+ }
+ async #cloneFields(newFields, fields) {
+ const processed = new RefSet();
+ const stack = [{
+ kids: fields,
+ newKids: newFields,
+ pos: 0,
+ oldParentRef: null,
+ parentRef: null,
+ parent: null
+ }];
+ const {
+ document: {
+ xref
+ },
+ oldRefMapping,
+ fieldToParent,
+ acroFormDefaultAppearance,
+ acroFormDefaultResources,
+ acroFormQ
+ } = this.currentDocument;
+ const daToFix = [];
+ const drToFix = [];
+ while (stack.length > 0) {
+ const data = stack.at(-1);
+ const {
+ kids,
+ newKids,
+ parent,
+ pos
+ } = data;
+ if (pos === kids.length) {
+ stack.pop();
+ if (newKids.length === 0 || !parent) {
+ continue;
+ }
+ const parentDict = this.xref[data.parentRef.num] = this.cloneDict(parent);
+ parentDict.delete("Parent");
+ parentDict.delete("Kids");
+ await this.#collectDependencies(parentDict, false, xref);
+ parentDict.set("Kids", newKids);
+ if (stack.length > 0) {
+ const lastData = stack.at(-1);
+ if (!lastData.parentRef && lastData.oldParentRef) {
+ const parentRef = lastData.parentRef = this.newRef;
+ parentDict.set("Parent", parentRef);
+ oldRefMapping.put(lastData.oldParentRef, parentRef);
+ }
+ lastData.newKids.push(data.parentRef);
+ }
+ continue;
+ }
+ const oldKidRef = kids[data.pos++];
+ if (!(oldKidRef instanceof Ref) || processed.has(oldKidRef)) {
+ continue;
+ }
+ processed.put(oldKidRef);
+ const kid = xref.fetchIfRef(oldKidRef);
+ if (!(kid instanceof Dict)) {
+ continue;
+ }
+ if (kid.has("Kids")) {
+ const kidsArray = kid.get("Kids");
+ if (!Array.isArray(kidsArray)) {
+ continue;
+ }
+ stack.push({
+ kids: kidsArray,
+ newKids: [],
+ pos: 0,
+ oldParentRef: oldKidRef,
+ parentRef: null,
+ parent: kid
+ });
+ continue;
+ }
+ if (!fieldToParent.has(oldKidRef)) {
+ continue;
+ }
+ const newRef = oldRefMapping.get(oldKidRef);
+ if (!newRef) {
+ continue;
+ }
+ newKids.push(newRef);
+ if (!data.parentRef && data.oldParentRef) {
+ data.parentRef = this.newRef;
+ oldRefMapping.put(data.oldParentRef, data.parentRef);
+ }
+ const newKid = this.xref[newRef.num];
+ if (data.parentRef) {
+ newKid.set("Parent", data.parentRef);
+ }
+ if (acroFormDefaultAppearance && !newKid.has("DA")) {
+ daToFix.push(newKid);
+ }
+ if (acroFormDefaultResources && !newKid.has("Kids") && newKid.get("AP") instanceof Dict) {
+ drToFix.push(newKid);
+ }
+ if (acroFormQ && !newKid.has("Q")) {
+ newKid.set("Q", acroFormQ);
+ }
+ }
+ for (const field of daToFix) {
+ const fieldType = getInheritableProperty({
+ dict: field,
+ key: "FT"
+ });
+ if (!isName(fieldType, "Tx")) {
+ continue;
+ }
+ const da = getInheritableProperty({
+ dict: field,
+ key: "DA"
+ });
+ if (!da) {
+ field.set("DA", acroFormDefaultAppearance);
+ }
+ }
+ const resourcesValuesCache = new Map();
+ const fixAppearanceResources = async stream => {
+ let resources = stream.dict.getRaw("Resources");
+ resources &&= this.xrefWrapper.fetchIfRef(resources);
+ if (!(resources instanceof Dict)) {
+ const newResourcesRef = await resourcesValuesCache.getOrInsertComputed(acroFormDefaultResources, () => this.#cloneObject(acroFormDefaultResources, xref));
+ stream.dict.set("Resources", newResourcesRef);
+ return;
+ }
+ for (const [resKey, resValue] of acroFormDefaultResources.getRawEntries()) {
+ if (resources.has(resKey)) {
+ continue;
+ }
+ let newResValue = resValue;
+ if (resValue instanceof Ref) {
+ newResValue = await this.#collectDependencies(resValue, true, xref);
+ } else if (resValue instanceof Dict || resValue instanceof BaseStream || Array.isArray(resValue)) {
+ newResValue = await resourcesValuesCache.getOrInsertComputed(resValue, () => this.#cloneObject(resValue, xref));
+ }
+ resources.set(resKey, newResValue);
+ }
+ };
+ for (const field of drToFix) {
+ const ap = field.get("AP");
+ for (const [, value] of ap) {
+ if (value instanceof BaseStream) {
+ await fixAppearanceResources(value);
+ } else if (value instanceof Dict) {
+ for (const [, stream] of value) {
+ if (stream instanceof BaseStream) {
+ await fixAppearanceResources(stream);
+ }
+ }
+ }
+ }
+ }
+ }
+ async #collectPageLabels() {
+ if (!this.isSingleFile) {
+ return;
+ }
+ const firstRealPage = this.oldPages.find(p => !!p);
+ if (!firstRealPage) {
+ return;
+ }
+ const {
+ documentData: {
+ document,
+ pageLabels
+ }
+ } = firstRealPage;
+ if (!pageLabels) {
+ return;
+ }
+ const numPages = document.numPages;
+ const labelsByPageIndex = new Map();
+ const oldPageIndices = new Set(this.oldPages.filter(Boolean).map(({
+ page: {
+ pageIndex
+ }
+ }) => pageIndex));
+ let currentLabel = null;
+ let stFirstIndex = -1;
+ for (let i = 0; i < numPages; i++) {
+ const newLabel = pageLabels.get(i);
+ if (newLabel) {
+ currentLabel = newLabel;
+ stFirstIndex = currentLabel.has("St") ? i : -1;
+ }
+ if (!oldPageIndices.has(i)) {
+ continue;
+ }
+ if (stFirstIndex !== -1) {
+ const st = currentLabel.get("St");
+ currentLabel = this.cloneDict(currentLabel);
+ currentLabel.set("St", st + (i - stFirstIndex));
+ stFirstIndex = -1;
+ }
+ labelsByPageIndex.set(i, currentLabel);
+ }
+ const defaultLabel = index => {
+ const label = new Dict();
+ label.setIfName("S", "D");
+ label.set("St", index + 1);
+ return label;
+ };
+ currentLabel = null;
+ const newPageLabels = this.pageLabels = [];
+ for (let i = 0, ii = this.oldPages.length; i < ii; i++) {
+ const pageData = this.oldPages[i];
+ const label = pageData ? labelsByPageIndex.get(pageData.page.pageIndex) || defaultLabel(i) : defaultLabel(i);
+ if (label === currentLabel) {
+ continue;
+ }
+ currentLabel = label;
+ newPageLabels.push([i, currentLabel]);
+ }
+ }
+ async #makePageCopy(pageIndex) {
+ const {
+ page,
+ documentData,
+ annotations,
+ pointingNamedDestinations,
+ copyLevel
+ } = this.oldPages[pageIndex];
+ this.currentDocument = documentData;
+ const {
+ dedupNamedDestinations,
+ oldRefMapping
+ } = documentData;
+ const {
+ xref,
+ rotate,
+ mediaBox,
+ resources,
+ ref: oldPageRef
+ } = page;
+ const pageRef = this.newRef;
+ const pageDict = this.xref[pageRef.num] = this.cloneDict(page.pageDict);
+ oldRefMapping.put(oldPageRef, pageRef);
+ if (pointingNamedDestinations) {
+ for (const pointingDest of pointingNamedDestinations) {
+ const name = dedupNamedDestinations.get(pointingDest) || pointingDest;
+ const dest = this.namedDestinations.get(name);
+ dest[0] = pageRef;
+ }
+ }
+ for (const key of ["Rotate", "MediaBox", "CropBox", "BleedBox", "TrimBox", "ArtBox", "Resources", "Annots", "Parent", "UserUnit"]) {
+ pageDict.delete(key);
+ }
+ const lastRef = this.newRefCount;
+ await this.#collectDependencies(pageDict, false, xref);
+ pageDict.set("Rotate", rotate);
+ pageDict.set("MediaBox", mediaBox);
+ for (const boxName of ["CropBox", "BleedBox", "TrimBox", "ArtBox"]) {
+ const box = page.getBoundingBox(boxName);
+ if (box?.some((value, index) => value !== mediaBox[index])) {
+ pageDict.set(boxName, box);
+ }
+ }
+ const userUnit = page.userUnit;
+ if (userUnit !== 1) {
+ pageDict.set("UserUnit", userUnit);
+ }
+ pageDict.setIfDict("Resources", await this.#collectDependencies(resources, true, xref));
+ let newAnnots = null;
+ if (annotations) {
+ const newAnnotations = await this.#collectDependencies(annotations, true, xref);
+ this.#fixNamedDestinations(newAnnotations, dedupNamedDestinations);
+ if (Array.isArray(newAnnotations) && newAnnotations.length > 0) {
+ newAnnots = newAnnotations;
+ }
+ }
+ const newAnnotations = documentData.document === this.#primaryDocument ? this.#newAnnotationsParams?.newAnnotationsByPage?.get(page.pageIndex)?.filter(({
+ copyLevel: level
+ }) => (level ?? 0) === copyLevel) : null;
+ if (newAnnotations?.length) {
+ const {
+ handler,
+ task,
+ imagesPromises
+ } = this.#newAnnotationsParams;
+ const changes = new RefMap();
+ const newData = await AnnotationFactory.saveNewAnnotations(page._createPartialEvaluator(handler), this.xrefWrapper, task, newAnnotations, imagesPromises, changes);
+ for (const [ref, {
+ data
+ }] of changes.items()) {
+ this.xref[ref.num] = data;
+ }
+ newAnnots ||= [];
+ for (const {
+ ref
+ } of newData.annotations) {
+ newAnnots.push(ref);
+ }
+ }
+ pageDict.setIfArray("Annots", newAnnots);
+ if (this.useObjectStreams) {
+ const newLastRef = this.newRefCount;
+ const pageObjectRefs = [];
+ for (let i = lastRef; i < newLastRef; i++) {
+ const obj = this.xref[i];
+ if (obj instanceof BaseStream) {
+ continue;
+ }
+ pageObjectRefs.push(Ref.get(i, 0));
+ }
+ for (let i = 0; i < pageObjectRefs.length; i += 0xffff) {
+ const objStreamRef = this.newRef;
+ this.objStreamRefs.add(objStreamRef.num);
+ this.xref[objStreamRef.num] = pageObjectRefs.slice(i, i + 0xffff);
+ }
+ }
+ this.currentDocument = null;
+ return pageRef;
+ }
+ #modalPageSize() {
+ const counts = new Map();
+ for (const pageData of this.oldPages) {
+ if (!pageData) {
+ continue;
+ }
+ const {
+ page
+ } = pageData;
+ const [x0, y0, x1, y1] = page.view;
+ let width = x1 - x0;
+ let height = y1 - y0;
+ if (width <= 0 || height <= 0) {
+ continue;
+ }
+ if (page.rotate % 180 !== 0) {
+ [width, height] = [height, width];
+ }
+ const key = `${width}x${height}`;
+ const entry = counts.get(key);
+ if (entry) {
+ entry.count++;
+ } else {
+ counts.set(key, {
+ width,
+ height,
+ count: 1
+ });
+ }
+ }
+ if (counts.size === 0) {
+ const [,, width, height] = LETTER_SIZE_MEDIABOX;
+ return {
+ width,
+ height
+ };
+ }
+ let best = null;
+ for (const entry of counts.values()) {
+ if (!best || entry.count > best.count || entry.count === best.count && entry.width * entry.height > best.width * best.height) {
+ best = entry;
+ }
+ }
+ return {
+ width: best.width,
+ height: best.height
+ };
+ }
+ async #makeImagePage(bitmap, pageSize) {
+ const {
+ width: pageW,
+ height: pageH
+ } = pageSize;
+ const DEFAULT_MARGIN_RATIO = 0.1;
+ const margin = pageW * DEFAULT_MARGIN_RATIO;
+ const availW = Math.max(1, pageW - 2 * margin);
+ const availH = Math.max(1, pageH - 2 * margin);
+ const lastRef = this.newRefCount;
+ const {
+ imageStream,
+ smaskStream,
+ width: imgW,
+ height: imgH
+ } = await createImage(bitmap, this.xrefWrapper, {
+ closeBitmap: true
+ });
+ const scale = Math.min(availW / imgW, availH / imgH);
+ const drawW = imgW * scale;
+ const drawH = imgH * scale;
+ const tx = (pageW - drawW) / 2;
+ const ty = (pageH - drawH) / 2;
+ if (smaskStream) {
+ const smaskRef = this.newRef;
+ this.xref[smaskRef.num] = smaskStream;
+ imageStream.dict.set("SMask", smaskRef);
+ }
+ const imageRef = this.newRef;
+ this.xref[imageRef.num] = imageStream;
+ const xobjectDict = new Dict(this.xrefWrapper);
+ xobjectDict.set("Im0", imageRef);
+ const resourcesDict = new Dict(this.xrefWrapper);
+ resourcesDict.set("XObject", xobjectDict);
+ resourcesDict.set("ProcSet", [Name.get("PDF"), Name.get("ImageC")]);
+ const content = `q ${numberToString(drawW)} 0 0 ${numberToString(drawH)} ` + `${numberToString(tx)} ${numberToString(ty)} cm /Im0 Do Q`;
+ const contentsStream = new StringStream(content, new Dict(this.xrefWrapper));
+ const contentsRef = this.newRef;
+ this.xref[contentsRef.num] = contentsStream;
+ const pageRef = this.newRef;
+ const pageDict = this.xref[pageRef.num] = new Dict(this.xrefWrapper);
+ pageDict.setIfName("Type", "Page");
+ pageDict.set("MediaBox", [0, 0, pageW, pageH]);
+ pageDict.set("Resources", resourcesDict);
+ pageDict.set("Contents", contentsRef);
+ if (this.useObjectStreams) {
+ const newLastRef = this.newRefCount;
+ const pageObjectRefs = [];
+ for (let i = lastRef; i < newLastRef; i++) {
+ const obj = this.xref[i];
+ if (obj instanceof BaseStream) {
+ continue;
+ }
+ pageObjectRefs.push(Ref.get(i, 0));
+ }
+ for (let i = 0; i < pageObjectRefs.length; i += 0xffff) {
+ const objStreamRef = this.newRef;
+ this.objStreamRefs.add(objStreamRef.num);
+ this.xref[objStreamRef.num] = pageObjectRefs.slice(i, i + 0xffff);
+ }
+ }
+ return pageRef;
+ }
+ #makePageTree() {
+ const {
+ newPages: pages,
+ rootDict,
+ pagesRef,
+ pagesDict
+ } = this;
+ rootDict.set("Pages", pagesRef);
+ pagesDict.setIfName("Type", "Pages");
+ pagesDict.set("Count", pages.length);
+ const maxLeaves = false ? 0 : MAX_LEAVES_PER_PAGES_NODE;
+ const stack = [{
+ dict: pagesDict,
+ kids: pages,
+ parentRef: pagesRef
+ }];
+ while (stack.length > 0) {
+ const {
+ dict,
+ kids,
+ parentRef
+ } = stack.pop();
+ if (kids.length <= maxLeaves) {
+ dict.set("Kids", kids);
+ for (const ref of kids) {
+ this.xref[ref.num].set("Parent", parentRef);
+ }
+ continue;
+ }
+ const chunkSize = Math.max(maxLeaves, Math.ceil(kids.length / maxLeaves));
+ const kidsChunks = [];
+ for (let i = 0; i < kids.length; i += chunkSize) {
+ kidsChunks.push(kids.slice(i, i + chunkSize));
+ }
+ const kidsRefs = [];
+ dict.set("Kids", kidsRefs);
+ for (const chunk of kidsChunks) {
+ const [kidRef, kidDict] = this.newDict;
+ kidsRefs.push(kidRef);
+ kidDict.setIfName("Type", "Pages");
+ kidDict.set("Parent", parentRef);
+ kidDict.set("Count", chunk.length);
+ stack.push({
+ dict: kidDict,
+ kids: chunk,
+ parentRef: kidRef
+ });
+ }
+ }
+ }
+ #makeNameNumTree(map, areNames) {
+ const allEntries = map.sort(areNames ? ([keyA], [keyB]) => {
+ if (keyA < keyB) {
+ return -1;
+ }
+ if (keyA > keyB) {
+ return 1;
+ }
+ return 0;
+ } : ([keyA], [keyB]) => keyA - keyB);
+ const maxLeaves = false ? 0 : MAX_IN_NAME_TREE_NODE;
+ const [treeRef, treeDict] = this.newDict;
+ const stack = [{
+ dict: treeDict,
+ entries: allEntries,
+ isRoot: true
+ }];
+ const valueType = areNames ? "Names" : "Nums";
+ while (stack.length > 0) {
+ const {
+ dict,
+ entries,
+ isRoot
+ } = stack.pop();
+ if (entries.length <= maxLeaves) {
+ if (!isRoot) {
+ dict.set("Limits", [entries[0][0], entries.at(-1)[0]]);
+ }
+ dict.set(valueType, entries.flat());
+ continue;
+ }
+ const entriesChunks = [];
+ const chunkSize = Math.max(maxLeaves, Math.ceil(entries.length / maxLeaves));
+ for (let i = 0; i < entries.length; i += chunkSize) {
+ entriesChunks.push(entries.slice(i, i + chunkSize));
+ }
+ const entriesRefs = [];
+ dict.set("Kids", entriesRefs);
+ for (const chunk of entriesChunks) {
+ const [entriesRef, entriesDict] = this.newDict;
+ entriesRefs.push(entriesRef);
+ entriesDict.set("Limits", [chunk[0][0], chunk.at(-1)[0]]);
+ stack.push({
+ dict: entriesDict,
+ entries: chunk
+ });
+ }
+ }
+ return treeRef;
+ }
+ #makePageLabelsTree() {
+ const {
+ pageLabels
+ } = this;
+ if (!pageLabels?.length) {
+ return;
+ }
+ const {
+ rootDict
+ } = this;
+ const pageLabelsRef = this.#makeNameNumTree(this.pageLabels, false);
+ rootDict.set("PageLabels", pageLabelsRef);
+ }
+ async #collectEmbeddedFiles(allDocumentData) {
+ const {
+ embeddedFiles
+ } = this;
+ for (const documentData of allDocumentData) {
+ const {
+ embeddedFiles: docEmbeddedFiles,
+ document: {
+ xref
+ }
+ } = documentData;
+ if (!docEmbeddedFiles?.size) {
+ continue;
+ }
+ this.currentDocument = documentData;
+ for (const [key, valueRef] of docEmbeddedFiles) {
+ let name = key;
+ if (embeddedFiles.has(name)) {
+ const displayName = stringToPDFString(key, true);
+ for (let i = 1;; i++) {
+ const deduped = stringToAsciiOrUTF16BE(`${displayName}_${i}`);
+ if (!embeddedFiles.has(deduped)) {
+ name = deduped;
+ break;
+ }
+ }
+ }
+ embeddedFiles.set(name, await this.#collectDependencies(valueRef, true, xref));
+ }
+ this.currentDocument = null;
+ }
+ }
+ #makeEmbeddedFilesTree() {
+ const {
+ embeddedFiles
+ } = this;
+ if (embeddedFiles.size === 0) {
+ return;
+ }
+ if (!this.namesDict) {
+ [this.namesRef, this.namesDict] = this.newDict;
+ this.rootDict.set("Names", this.namesRef);
+ }
+ this.namesDict.set("EmbeddedFiles", this.#makeNameNumTree(Array.from(embeddedFiles.entries()), true));
+ }
+ #makeDestinationsTree() {
+ const {
+ namedDestinations
+ } = this;
+ if (namedDestinations.size === 0) {
+ return;
+ }
+ if (!this.namesDict) {
+ [this.namesRef, this.namesDict] = this.newDict;
+ this.rootDict.set("Names", this.namesRef);
+ }
+ this.namesDict.set("Dests", this.#makeNameNumTree(Array.from(namedDestinations, ([name, dest]) => [stringToAsciiOrUTF16BE(name), dest]), true));
+ }
+ #makeStructTree() {
+ const {
+ structTreeKids
+ } = this;
+ if (!structTreeKids?.length) {
+ return;
+ }
+ const {
+ rootDict
+ } = this;
+ const structTreeRef = this.newRef;
+ const structTree = this.xref[structTreeRef.num] = new Dict();
+ structTree.setIfName("Type", "StructTreeRoot");
+ structTree.setIfArray("K", structTreeKids);
+ for (const kidRef of structTreeKids) {
+ const kid = this.xref[kidRef.num];
+ const type = kid.get("Type");
+ if (!type || isName(type, "StructElem")) {
+ kid.set("P", structTreeRef);
+ }
+ }
+ if (this.parentTree.size > 0) {
+ const parentTreeRef = this.#makeNameNumTree(Array.from(this.parentTree.entries()), false);
+ const parentTree = this.xref[parentTreeRef.num];
+ parentTree.setIfName("Type", "ParentTree");
+ structTree.set("ParentTree", parentTreeRef);
+ let nextKey = 0;
+ for (const key of this.parentTree.keys()) {
+ nextKey = Math.max(nextKey, key + 1);
+ }
+ structTree.set("ParentTreeNextKey", nextKey);
+ }
+ if (this.idTree.size > 0) {
+ const idTreeRef = this.#makeNameNumTree(Array.from(this.idTree.entries()), true);
+ const idTree = this.xref[idTreeRef.num];
+ idTree.setIfName("Type", "IDTree");
+ structTree.set("IDTree", idTreeRef);
+ }
+ if (this.classMap.size > 0) {
+ const classMapRef = this.newRef;
+ this.xref[classMapRef.num] = this.classMap;
+ structTree.set("ClassMap", classMapRef);
+ }
+ if (this.roleMap.size > 0) {
+ const roleMapRef = this.newRef;
+ this.xref[roleMapRef.num] = this.roleMap;
+ structTree.set("RoleMap", roleMapRef);
+ }
+ if (this.namespaces.size > 0) {
+ const namespacesRef = this.newRef;
+ this.xref[namespacesRef.num] = Array.from(this.namespaces.values());
+ structTree.set("Namespaces", namespacesRef);
+ }
+ if (this.structTreeAF.length > 0) {
+ const structTreeAFRef = this.newRef;
+ this.xref[structTreeAFRef.num] = this.structTreeAF;
+ structTree.set("AF", structTreeAFRef);
+ }
+ if (this.structTreePronunciationLexicon.length > 0) {
+ const structTreePronunciationLexiconRef = this.newRef;
+ this.xref[structTreePronunciationLexiconRef.num] = this.structTreePronunciationLexicon;
+ structTree.set("PronunciationLexicon", structTreePronunciationLexiconRef);
+ }
+ rootDict.set("StructTreeRoot", structTreeRef);
+ }
+ #makeAcroForm() {
+ if (this.fields.length === 0) {
+ return;
+ }
+ const {
+ rootDict
+ } = this;
+ const acroFormRef = this.newRef;
+ const acroForm = this.xref[acroFormRef.num] = new Dict();
+ rootDict.set("AcroForm", acroFormRef);
+ acroForm.set("Fields", this.fields);
+ if (this.acroFormNeedAppearances) {
+ acroForm.set("NeedAppearances", true);
+ }
+ if (this.acroFormSigFlags > 0) {
+ acroForm.set("SigFlags", this.acroFormSigFlags);
+ }
+ acroForm.setIfArray("CO", this.acroFormCalculationOrder);
+ acroForm.setIfDefined("DR", this.acroFormDefaultResources);
+ if (this.acroFormDefaultAppearance) {
+ acroForm.set("DA", this.acroFormDefaultAppearance);
+ }
+ if (this.acroFormQ > 0) {
+ acroForm.set("Q", this.acroFormQ);
+ }
+ }
+ async #makeRoot() {
+ const {
+ rootDict
+ } = this;
+ rootDict.setIfName("Type", "Catalog");
+ rootDict.setIfName("Version", this.version);
+ this.#makeAcroForm();
+ this.#makePageTree();
+ this.#makePageLabelsTree();
+ this.#makeEmbeddedFilesTree();
+ this.#makeDestinationsTree();
+ this.#makeStructTree();
+ await this.#makeOutline();
+ }
+ #makeInfo() {
+ const infoMap = new Map();
+ if (this.isSingleFile) {
+ const firstRealPage = this.oldPages.find(p => !!p);
+ const {
+ xref: {
+ trailer
+ }
+ } = firstRealPage.documentData.document;
+ const oldInfoDict = trailer.get("Info");
+ for (const [key, value] of oldInfoDict || []) {
+ if (typeof value === "string") {
+ infoMap.set(key, stringToPDFString(value));
+ }
+ }
+ }
+ infoMap.delete("ModDate");
+ infoMap.set("CreationDate", getModificationDate());
+ infoMap.set("Creator", "PDF.js");
+ infoMap.set("Producer", "Firefox");
+ if (this.author) {
+ infoMap.set("Author", this.author);
+ }
+ if (this.title) {
+ infoMap.set("Title", this.title);
+ }
+ for (const [key, value] of infoMap) {
+ this.infoDict.set(key, stringToAsciiOrUTF16BE(value));
+ }
+ return infoMap;
+ }
+ async #makeEncrypt() {
+ if (!this.isSingleFile) {
+ return [null, null, null];
+ }
+ const firstRealPage = this.oldPages.find(p => !!p);
+ const {
+ documentData
+ } = firstRealPage;
+ const {
+ document: {
+ xref: {
+ trailer,
+ encrypt
+ }
+ }
+ } = documentData;
+ if (!trailer.has("Encrypt")) {
+ return [null, null, null];
+ }
+ const encryptDict = trailer.get("Encrypt");
+ if (!(encryptDict instanceof Dict)) {
+ return [null, null, null];
+ }
+ this.currentDocument = documentData;
+ const result = [await this.#cloneObject(encryptDict, trailer.xref), encrypt, trailer.get("ID")];
+ this.currentDocument = null;
+ return result;
+ }
+ async #createChanges() {
+ const changes = new RefMap();
+ changes.put(Ref.get(0, 0xffff), {
+ data: null
+ });
+ for (let i = 1, ii = this.xref.length; i < ii; i++) {
+ if (this.objStreamRefs?.has(i)) {
+ await this.#createObjectStream(Ref.get(i, 0), this.xref[i], changes);
+ } else {
+ changes.put(Ref.get(i, 0), {
+ data: this.xref[i]
+ });
+ }
+ }
+ return [changes, this.newRef];
+ }
+ async #createObjectStream(objStreamRef, objRefs, changes) {
+ const streamBuffer = [""];
+ const objOffsets = [];
+ let offset = 0;
+ const buffer = [];
+ for (let i = 0, ii = objRefs.length; i < ii; i++) {
+ const objRef = objRefs[i];
+ changes.put(objRef, {
+ data: null,
+ objStreamRef,
+ index: i
+ });
+ objOffsets.push(`${objRef.num} ${offset}`);
+ const data = this.xref[objRef.num];
+ await writeValue(data, buffer, null);
+ const obj = buffer.join("");
+ buffer.length = 0;
+ streamBuffer.push(obj);
+ offset += obj.length + 1;
+ }
+ streamBuffer[0] = objOffsets.join("\n");
+ const dict = new Dict();
+ dict.setIfName("Type", "ObjStm");
+ dict.set("N", objRefs.length);
+ dict.set("First", streamBuffer[0].length + 1);
+ const objStream = new StringStream(streamBuffer.join("\n"), dict);
+ changes.put(objStreamRef, {
+ data: objStream
+ });
+ }
+ async writePDF() {
+ await this.#makeRoot();
+ const infoMap = this.#makeInfo();
+ const [encryptRef, encrypt, fileIds] = await this.#makeEncrypt();
+ const [changes, xrefTableRef] = await this.#createChanges();
+ const header = stringToBytes(`%PDF-${this.version}\n%\xfa\xde\xfa\xce`);
+ return incrementalUpdate({
+ originalData: header,
+ changes,
+ xrefInfo: {
+ startXRef: null,
+ rootRef: this.rootRef,
+ infoRef: this.infoRef,
+ encryptRef,
+ newRef: xrefTableRef,
+ fileIds: fileIds || [null, null],
+ infoMap
+ },
+ useXrefStream: this.useObjectStreams,
+ xref: {
+ encrypt,
+ encryptRef
+ }
+ });
+ }
+}
+
+;// ./src/shared/base_pdf_stream.js
+
+
+
+
+
+
+
+
+class BasePDFStream {
+ #PDFStreamReader = null;
+ #PDFStreamRangeReader = null;
+ _fullReader = null;
+ _rangeReaders = new Set();
+ _source = null;
+ constructor(source, PDFStreamReader, PDFStreamRangeReader) {
+ this._source = source;
+ this.#PDFStreamReader = PDFStreamReader;
+ this.#PDFStreamRangeReader = PDFStreamRangeReader;
+ }
+ get _progressiveDataLength() {
+ return this._fullReader?._loaded ?? 0;
+ }
+ getFullReader() {
+ assert(!this._fullReader, "BasePDFStream.getFullReader can only be called once.");
+ return this._fullReader = new this.#PDFStreamReader(this);
+ }
+ getRangeReader(begin, end) {
+ if (end <= this._progressiveDataLength) {
+ return null;
+ }
+ const reader = new this.#PDFStreamRangeReader(this, begin, end);
+ this._rangeReaders.add(reader);
+ return reader;
+ }
+ cancelAllRequests(reason) {
+ this._fullReader?.cancel(reason);
+ for (const reader of new Set(this._rangeReaders)) {
+ reader.cancel(reason);
+ }
+ }
+}
+class BasePDFStreamReader {
+ onProgress = null;
+ _contentLength = 0;
+ _filename = null;
+ _headersCapability = Promise.withResolvers();
+ _isRangeSupported = false;
+ _isStreamingSupported = false;
+ _loaded = 0;
+ _stream = null;
+ constructor(stream) {
+ this._stream = stream;
+ }
+ _callOnProgress() {
+ this.onProgress?.({
+ loaded: this._loaded,
+ total: this._contentLength
+ });
+ }
+ get headersReady() {
+ return this._headersCapability.promise;
+ }
+ get filename() {
+ return this._filename;
+ }
+ get contentLength() {
+ return this._contentLength;
+ }
+ get isRangeSupported() {
+ return this._isRangeSupported;
+ }
+ get isStreamingSupported() {
+ return this._isStreamingSupported;
+ }
+ async read() {
+ unreachable("Abstract method `read` called");
+ }
+ cancel(reason) {
+ unreachable("Abstract method `cancel` called");
+ }
+}
+class BasePDFStreamRangeReader {
+ _stream = null;
+ constructor(stream, begin, end) {
+ this._stream = stream;
+ }
+ async read() {
+ unreachable("Abstract method `read` called");
+ }
+ cancel(reason) {
+ unreachable("Abstract method `cancel` called");
+ }
+}
+
+;// ./src/core/worker_stream.js
+
+class PDFWorkerStream extends BasePDFStream {
+ constructor(source) {
+ super(source, PDFWorkerStreamReader, PDFWorkerStreamRangeReader);
+ }
+}
+class PDFWorkerStreamReader extends BasePDFStreamReader {
+ _reader = null;
+ constructor(stream) {
+ super(stream);
+ const {
+ msgHandler
+ } = stream._source;
+ const readableStream = msgHandler.sendWithStream("GetReader");
+ this._reader = readableStream.getReader();
+ msgHandler.sendWithPromise("ReaderHeadersReady").then(data => {
+ this._contentLength = data.contentLength;
+ this._isStreamingSupported = data.isStreamingSupported;
+ this._isRangeSupported = data.isRangeSupported;
+ this._headersCapability.resolve();
+ }, this._headersCapability.reject);
+ }
+ async read() {
+ const {
+ value,
+ done
+ } = await this._reader.read();
+ if (done) {
+ return {
+ value: undefined,
+ done: true
+ };
+ }
+ return {
+ value: value.buffer,
+ done: false
+ };
+ }
+ cancel(reason) {
+ this._reader.cancel(reason);
+ }
+}
+class PDFWorkerStreamRangeReader extends BasePDFStreamRangeReader {
+ _reader = null;
+ constructor(stream, begin, end) {
+ super(stream, begin, end);
+ const {
+ msgHandler
+ } = stream._source;
+ const readableStream = msgHandler.sendWithStream("GetRangeReader", {
+ begin,
+ end
+ });
+ this._reader = readableStream.getReader();
+ }
+ async read() {
+ const {
+ value,
+ done
+ } = await this._reader.read();
+ if (done) {
+ return {
+ value: undefined,
+ done: true
+ };
+ }
+ return {
+ value: value.buffer,
+ done: false
+ };
+ }
+ cancel(reason) {
+ this._reader.cancel(reason);
+ }
+}
+
+;// ./src/core/worker.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class WorkerTask {
+ #capability = Promise.withResolvers();
+ terminated = false;
+ constructor(name) {
+ this.name = name;
+ }
+ get finished() {
+ return this.#capability.promise;
+ }
+ finish() {
+ this.#capability.resolve();
+ }
+ terminate() {
+ this.terminated = true;
+ }
+ ensureNotTerminated() {
+ if (this.terminated) {
+ throw new Error("Worker task was terminated");
+ }
+ }
+}
+class WorkerMessageHandler {
+ static {
+ if (typeof window === "undefined" && !isNodeJS && typeof self !== "undefined" && typeof self.postMessage === "function" && "onmessage" in self) {
+ this.initializeFromPort(self);
+ }
+ }
+ static setup(handler, port) {
+ let testMessageProcessed = false;
+ handler.on("test", data => {
+ if (testMessageProcessed) {
+ return;
+ }
+ testMessageProcessed = true;
+ handler.send("test", data instanceof Uint8Array);
+ });
+ handler.on("configure", data => {
+ setVerbosityLevel(data.verbosity);
+ });
+ handler.on("GetDocRequest", data => this.createDocumentHandler(data, port));
+ }
+ static createDocumentHandler(docParams, port) {
+ let pdfManager;
+ let terminated = false;
+ let cancelXHRs = null;
+ const WorkerTasks = new Set();
+ const verbosity = getVerbosityLevel();
+ const {
+ docId,
+ apiVersion
+ } = docParams;
+ const workerVersion = "6.3.289";
+ if (apiVersion !== workerVersion) {
+ throw new Error(`The API version "${apiVersion}" does not match ` + `the Worker version "${workerVersion}".`);
+ }
+ const buildMsg = (type, prop) => `The \`${type}.prototype\` contains unexpected enumerable property ` + `"${prop}", thus breaking e.g. \`for...in\` iteration of ${type}s.`;
+ for (const prop in {}) {
+ throw new Error(buildMsg("Object", prop));
+ }
+ for (const prop in []) {
+ throw new Error(buildMsg("Array", prop));
+ }
+ const workerHandlerName = docId + "_worker";
+ let handler = new MessageHandler(workerHandlerName, docId, port);
+ function ensureNotTerminated() {
+ if (terminated) {
+ throw new Error("Worker was terminated");
+ }
+ }
+ function startWorkerTask(task) {
+ WorkerTasks.add(task);
+ }
+ function finishWorkerTask(task) {
+ task.finish();
+ WorkerTasks.delete(task);
+ }
+ async function loadDocument(recoveryMode) {
+ await pdfManager.initDocument(recoveryMode);
+ const isPureXfa = await pdfManager.ensureDoc("isPureXfa");
+ if (isPureXfa) {
+ const task = new WorkerTask("loadXfaResources");
+ startWorkerTask(task);
+ await pdfManager.ensureDoc("loadXfaResources", [handler, task]);
+ finishWorkerTask(task);
+ }
+ const [numPages, fingerprints] = await Promise.all([pdfManager.ensureDoc("numPages"), pdfManager.ensureDoc("fingerprints")]);
+ const htmlForXfa = isPureXfa ? await pdfManager.ensureDoc("htmlForXfa") : null;
+ return {
+ numPages,
+ fingerprints,
+ htmlForXfa
+ };
+ }
+ async function getPdfManager({
+ data,
+ password,
+ disableAutoFetch,
+ rangeChunkSize,
+ docBaseUrl,
+ enableXfa,
+ evaluatorOptions
+ }) {
+ const pdfManagerArgs = {
+ source: null,
+ disableAutoFetch,
+ docBaseUrl,
+ docId,
+ enableXfa,
+ evaluatorOptions,
+ handler,
+ length: 0,
+ password,
+ rangeChunkSize
+ };
+ if (data) {
+ pdfManagerArgs.source = data;
+ return new LocalPdfManager(pdfManagerArgs);
+ }
+ const pdfStream = new PDFWorkerStream({
+ msgHandler: handler
+ }),
+ fullReader = pdfStream.getFullReader();
+ const {
+ promise,
+ resolve,
+ reject
+ } = Promise.withResolvers();
+ let newPdfManager,
+ cachedChunks = [];
+ cancelXHRs = reason => pdfStream.cancelAllRequests(reason);
+ fullReader.headersReady.then(() => {
+ if (!fullReader.isRangeSupported) {
+ return;
+ }
+ pdfManagerArgs.source = pdfStream;
+ pdfManagerArgs.length = fullReader.contentLength;
+ pdfManagerArgs.disableAutoFetch ||= fullReader.isStreamingSupported;
+ newPdfManager = new NetworkPdfManager(pdfManagerArgs);
+ for (const chunk of cachedChunks) {
+ newPdfManager.sendProgressiveData(chunk);
+ }
+ cachedChunks = null;
+ resolve(newPdfManager);
+ cancelXHRs = null;
+ }).catch(reason => {
+ reject(reason);
+ cancelXHRs = null;
+ });
+ async function readData() {
+ let loaded = 0;
+ while (true) {
+ const {
+ value,
+ done
+ } = await fullReader.read();
+ ensureNotTerminated();
+ if (done) {
+ break;
+ }
+ loaded += value.byteLength;
+ if (!fullReader.isStreamingSupported) {
+ handler.send("DocProgress", {
+ loaded,
+ total: fullReader.contentLength
+ });
+ }
+ if (newPdfManager) {
+ newPdfManager.sendProgressiveData(value);
+ } else {
+ cachedChunks.push(value);
+ }
+ }
+ if (!newPdfManager) {
+ pdfManagerArgs.source = arrayBuffersToBytes(cachedChunks);
+ cachedChunks = null;
+ newPdfManager = new LocalPdfManager(pdfManagerArgs);
+ resolve(newPdfManager);
+ }
+ cancelXHRs = null;
+ }
+ readData().catch(reason => {
+ reject(reason);
+ cancelXHRs = null;
+ });
+ return promise;
+ }
+ async function getPassword(ex) {
+ const task = new WorkerTask(`PasswordException: response ${ex.code}`);
+ startWorkerTask(task);
+ try {
+ const res = await handler.sendWithPromise("PasswordRequest", ex);
+ return res.password;
+ } finally {
+ Promise.resolve().then(() => {
+ finishWorkerTask(task);
+ });
+ }
+ }
+ function setupDoc(data) {
+ function onSuccess(doc) {
+ ensureNotTerminated();
+ handler.send("GetDoc", {
+ pdfInfo: doc
+ });
+ }
+ function onFailure(ex) {
+ if (terminated) {
+ return;
+ }
+ if (ex instanceof PasswordException) {
+ getPassword(ex).then(password => {
+ pdfManager.updatePassword(password);
+ pdfManagerReady();
+ }).catch(() => {
+ handler.send("DocException", ex);
+ });
+ } else {
+ handler.send("DocException", wrapReason(ex));
+ }
+ }
+ function pdfManagerReady() {
+ ensureNotTerminated();
+ loadDocument(false).then(onSuccess, function (reason) {
+ ensureNotTerminated();
+ if (!(reason instanceof XRefParseException)) {
+ onFailure(reason);
+ return;
+ }
+ pdfManager.requestLoadedStream().then(function () {
+ ensureNotTerminated();
+ loadDocument(true).then(onSuccess, onFailure);
+ }, onFailure);
+ });
+ }
+ ensureNotTerminated();
+ getPdfManager(data).then(function (newPdfManager) {
+ if (terminated) {
+ newPdfManager.terminate(new AbortException("Worker was terminated."));
+ throw new Error("Worker was terminated");
+ }
+ pdfManager = newPdfManager;
+ pdfManager.requestLoadedStream(true).then(stream => {
+ handler.send("DataLoaded", {
+ length: stream.bytes.byteLength
+ });
+ }, () => {});
+ }).then(pdfManagerReady, onFailure);
+ }
+ handler.on("GetPage", async function ({
+ pageIndex
+ }) {
+ const page = await pdfManager.getPage(pageIndex);
+ const [rotate, ref, userUnit, view] = await Promise.all([pdfManager.ensure(page, "rotate"), pdfManager.ensure(page, "ref"), pdfManager.ensure(page, "userUnit"), pdfManager.ensure(page, "view")]);
+ return {
+ rotate,
+ ref,
+ refStr: ref?.toString() ?? null,
+ userUnit,
+ view
+ };
+ });
+ handler.on("GetPageIndex", function ({
+ num,
+ gen
+ }) {
+ return pdfManager.ensureCatalog("getPageIndex", [Ref.get(num, gen)]);
+ });
+ handler.on("GetDestinations", function () {
+ return pdfManager.ensureCatalog("destinations");
+ });
+ handler.on("GetDestination", function ({
+ id
+ }) {
+ return pdfManager.ensureCatalog("getDestination", [id]);
+ });
+ handler.on("GetPageLabels", function () {
+ return pdfManager.ensureCatalog("pageLabels");
+ });
+ handler.on("GetPageLayout", function () {
+ return pdfManager.ensureCatalog("pageLayout");
+ });
+ handler.on("GetPageMode", function () {
+ return pdfManager.ensureCatalog("pageMode");
+ });
+ handler.on("GetViewerPreferences", function () {
+ return pdfManager.ensureCatalog("viewerPreferences");
+ });
+ handler.on("GetOpenAction", function () {
+ return pdfManager.ensureCatalog("openAction");
+ });
+ handler.on("GetAttachments", function () {
+ return pdfManager.ensureCatalog("attachments");
+ });
+ handler.on("GetAttachmentContent", async function (id) {
+ let passwordEx;
+ while (true) {
+ const password = passwordEx ? await getPassword(passwordEx) : null;
+ try {
+ if (password) {
+ pdfManager.updatePassword(password);
+ }
+ return await pdfManager.ensureCatalog("attachmentContent", [id]);
+ } catch (ex) {
+ if (ex instanceof PasswordException) {
+ passwordEx = ex;
+ continue;
+ }
+ throw ex;
+ }
+ }
+ });
+ handler.on("GetDocJSActions", function () {
+ return pdfManager.ensureCatalog("jsActions");
+ });
+ handler.on("GetPageJSActions", async function ({
+ pageIndex
+ }) {
+ const page = await pdfManager.getPage(pageIndex);
+ return pdfManager.ensure(page, "jsActions");
+ });
+ handler.on("GetAnnotationsByType", async function ({
+ types,
+ pageIndexesToSkip
+ }) {
+ const [numPages, annotationGlobals] = await Promise.all([pdfManager.ensureDoc("numPages"), pdfManager.ensureDoc("annotationGlobals")]);
+ if (!annotationGlobals) {
+ return null;
+ }
+ const pagePromises = [];
+ const annotationPromises = [];
+ let task = null;
+ try {
+ for (let i = 0, ii = numPages; i < ii; i++) {
+ if (pageIndexesToSkip?.has(i)) {
+ continue;
+ }
+ if (!task) {
+ task = new WorkerTask("GetAnnotationsByType");
+ startWorkerTask(task);
+ }
+ pagePromises.push(pdfManager.getPage(i).then(page => page.collectAnnotationsByType(handler, task, types, annotationPromises, annotationGlobals)));
+ }
+ await Promise.all(pagePromises);
+ const annotations = await Promise.all(annotationPromises);
+ return annotations.filter(Boolean);
+ } finally {
+ if (task) {
+ finishWorkerTask(task);
+ }
+ }
+ });
+ handler.on("GetOutline", function () {
+ return pdfManager.ensureCatalog("documentOutline");
+ });
+ handler.on("GetOptionalContentConfig", function () {
+ return pdfManager.ensureCatalog("optionalContentConfig");
+ });
+ handler.on("GetPermissions", function () {
+ return pdfManager.ensureCatalog("permissions");
+ });
+ handler.on("GetMetadata", function () {
+ return Promise.all([pdfManager.ensureDoc("documentInfo"), pdfManager.ensureCatalog("metadata"), pdfManager.ensureCatalog("hasStructTree")]);
+ });
+ handler.on("GetMarkInfo", function () {
+ return pdfManager.ensureCatalog("markInfo");
+ });
+ handler.on("GetData", async function () {
+ const stream = await pdfManager.requestLoadedStream();
+ return stream.bytes;
+ });
+ handler.on("GetAnnotations", async function ({
+ pageIndex,
+ intent
+ }) {
+ const page = await pdfManager.getPage(pageIndex);
+ const task = new WorkerTask(`GetAnnotations: page ${pageIndex}`);
+ startWorkerTask(task);
+ try {
+ return await page.getAnnotationsData(handler, task, intent);
+ } finally {
+ finishWorkerTask(task);
+ }
+ });
+ handler.on("GetFieldObjects", async function () {
+ const fieldObjects = await pdfManager.ensureDoc("fieldObjects");
+ return fieldObjects?.allFields || null;
+ });
+ handler.on("GetSignatures", function () {
+ return pdfManager.ensureDoc("signatures");
+ });
+ handler.on("GetSignatureData", function (id) {
+ return pdfManager.ensureDoc("getSignatureData", [id]);
+ });
+ handler.on("HasJSActions", function () {
+ return pdfManager.ensureDoc("hasJSActions");
+ });
+ handler.on("GetCalculationOrderIds", function () {
+ return pdfManager.ensureDoc("calculationOrderIds");
+ });
+ handler.on("ExtractPages", async function ({
+ pageInfos,
+ annotationStorage
+ }) {
+ if (!pageInfos) {
+ warn("extractPages: nothing to extract.");
+ return null;
+ }
+ if (!Array.isArray(pageInfos)) {
+ pageInfos = [pageInfos];
+ }
+ let newDocumentId = 0;
+ for (const pageInfo of pageInfos) {
+ if (pageInfo.image) {
+ continue;
+ }
+ if (pageInfo.document === null) {
+ pageInfo.document = pdfManager.pdfDocument;
+ } else if (ArrayBuffer.isView(pageInfo.document)) {
+ const manager = new LocalPdfManager({
+ source: pageInfo.document,
+ docId: `${docId}_extractPages_${newDocumentId++}`,
+ handler,
+ password: pageInfo.password ?? null,
+ evaluatorOptions: Object.assign({}, pdfManager.evaluatorOptions)
+ });
+ let recoveryMode = false;
+ let isValid = true;
+ while (true) {
+ try {
+ await manager.requestLoadedStream();
+ await manager.initDocument(recoveryMode);
+ break;
+ } catch (e) {
+ if (e instanceof XRefParseException) {
+ if (recoveryMode === false) {
+ recoveryMode = true;
+ continue;
+ } else {
+ isValid = false;
+ warn("extractPages: XRefParseException.");
+ }
+ } else if (e instanceof PasswordException) {
+ try {
+ const password = await getPassword(e);
+ manager.updatePassword(password);
+ } catch {
+ isValid = false;
+ warn("extractPages: invalid password.");
+ }
+ } else {
+ isValid = false;
+ warn("extractPages: invalid document.");
+ }
+ if (!isValid) {
+ break;
+ }
+ }
+ }
+ if (!isValid) {
+ pageInfo.document = null;
+ }
+ const isPureXfa = await manager.ensureDoc("isPureXfa");
+ if (isPureXfa) {
+ pageInfo.document = null;
+ warn("extractPages does not support pure XFA documents.");
+ } else {
+ pageInfo.document = manager.pdfDocument;
+ }
+ } else {
+ warn("extractPages: invalid document.");
+ }
+ }
+ let task;
+ try {
+ const pdfEditor = new PDFEditor();
+ task = new WorkerTask(`ExtractPages: ${pageInfos.length} page(s)`);
+ startWorkerTask(task);
+ return await pdfEditor.extractPages(pageInfos, annotationStorage, pdfManager.pdfDocument, handler, task);
+ } catch (reason) {
+ warn(`extractPages: "${reason}".`);
+ return null;
+ } finally {
+ if (task) {
+ finishWorkerTask(task);
+ }
+ }
+ });
+ handler.on("SaveDocument", async function ({
+ isPureXfa,
+ numPages,
+ annotationStorage,
+ filename
+ }) {
+ const globalPromises = [pdfManager.requestLoadedStream(), pdfManager.ensureCatalog("acroForm"), pdfManager.ensureCatalog("acroFormRef"), pdfManager.ensureDoc("startXRef"), pdfManager.ensureDoc("xref"), pdfManager.ensureCatalog("structTreeRoot")];
+ const changes = new RefMap();
+ const promises = [];
+ const newAnnotationsByPage = !isPureXfa ? getNewAnnotationsMap(annotationStorage) : null;
+ const [stream, acroForm, acroFormRef, startXRef, xref, _structTreeRoot] = await Promise.all(globalPromises);
+ const catalogRef = xref.trailer.getRaw("Root") || null;
+ let structTreeRoot;
+ if (newAnnotationsByPage) {
+ if (!_structTreeRoot) {
+ if (await StructTreeRoot.canCreateStructureTree({
+ catalogRef,
+ pdfManager,
+ newAnnotationsByPage
+ })) {
+ structTreeRoot = null;
+ }
+ } else if (await _structTreeRoot.canUpdateStructTree({
+ pdfManager,
+ newAnnotationsByPage
+ })) {
+ structTreeRoot = _structTreeRoot;
+ }
+ const imagePromises = AnnotationFactory.generateImages(annotationStorage.values(), xref, pdfManager.evaluatorOptions.isOffscreenCanvasSupported);
+ const newAnnotationPromises = structTreeRoot === undefined ? promises : [];
+ for (const [pageIndex, annotations] of newAnnotationsByPage) {
+ newAnnotationPromises.push(pdfManager.getPage(pageIndex).then(page => {
+ const task = new WorkerTask(`Save (editor): page ${pageIndex}`);
+ startWorkerTask(task);
+ return page.saveNewAnnotations(handler, task, annotations, imagePromises, changes).finally(() => {
+ finishWorkerTask(task);
+ });
+ }));
+ }
+ if (structTreeRoot === null) {
+ promises.push(Promise.all(newAnnotationPromises).then(async () => {
+ await StructTreeRoot.createStructureTree({
+ newAnnotationsByPage,
+ xref,
+ catalogRef,
+ pdfManager,
+ changes
+ });
+ }));
+ } else if (structTreeRoot) {
+ promises.push(Promise.all(newAnnotationPromises).then(async () => {
+ await structTreeRoot.updateStructureTree({
+ newAnnotationsByPage,
+ pdfManager,
+ changes
+ });
+ }));
+ }
+ }
+ if (isPureXfa) {
+ promises.push(pdfManager.ensureDoc("serializeXfaData", [annotationStorage]));
+ } else {
+ for (let pageIndex = 0; pageIndex < numPages; pageIndex++) {
+ promises.push(pdfManager.getPage(pageIndex).then(function (page) {
+ const task = new WorkerTask(`Save: page ${pageIndex}`);
+ startWorkerTask(task);
+ return page.save(handler, task, annotationStorage, changes).finally(() => {
+ finishWorkerTask(task);
+ });
+ }));
+ }
+ }
+ const refs = await Promise.all(promises);
+ let xfaData = null;
+ if (isPureXfa) {
+ xfaData = refs[0];
+ if (!xfaData) {
+ return stream.bytes;
+ }
+ } else if (changes.size === 0) {
+ return stream.bytes;
+ }
+ const needAppearances = acroFormRef && acroForm instanceof Dict && changes.values().some(ref => ref.needAppearances);
+ const xfa = acroForm instanceof Dict && acroForm.get("XFA") || null;
+ let xfaDatasetsRef = null;
+ let hasXfaDatasetsEntry = false;
+ if (Array.isArray(xfa)) {
+ for (let i = 0, ii = xfa.length; i < ii; i += 2) {
+ if (xfa[i] === "datasets") {
+ xfaDatasetsRef = xfa[i + 1];
+ hasXfaDatasetsEntry = true;
+ }
+ }
+ if (xfaDatasetsRef === null) {
+ xfaDatasetsRef = xref.getNewTemporaryRef();
+ }
+ } else if (xfa) {
+ warn("Unsupported XFA type.");
+ }
+ let newXrefInfo = Object.create(null);
+ if (xref.trailer) {
+ const infoMap = new Map();
+ const xrefInfo = xref.trailer.get("Info") || null;
+ if (xrefInfo instanceof Dict) {
+ for (const [key, value] of xrefInfo) {
+ if (typeof value === "string") {
+ infoMap.set(key, stringToPDFString(value));
+ }
+ }
+ }
+ newXrefInfo = {
+ rootRef: catalogRef,
+ encryptRef: xref.trailer.getRaw("Encrypt") || null,
+ newRef: xref.getNewTemporaryRef(),
+ infoRef: xref.trailer.getRaw("Info") || null,
+ infoMap,
+ fileIds: xref.trailer.get("ID") || null,
+ startXRef,
+ filename
+ };
+ }
+ return incrementalUpdate({
+ originalData: stream.bytes,
+ xrefInfo: newXrefInfo,
+ changes,
+ xref,
+ hasXfa: !!xfa,
+ xfaDatasetsRef,
+ hasXfaDatasetsEntry,
+ needAppearances,
+ acroFormRef,
+ acroForm,
+ xfaData,
+ useXrefStream: isDict(xref.topDict, "XRef")
+ }).finally(() => {
+ xref.resetNewTemporaryRef();
+ });
+ });
+ handler.on("GetOperatorList", function ({
+ pageId,
+ pageIndex,
+ intent,
+ cacheKey,
+ annotationStorage,
+ modifiedIds
+ }, sink) {
+ pdfManager.getPage(pageId).then(function (page) {
+ const task = new WorkerTask(`GetOperatorList: page ${pageIndex}`);
+ startWorkerTask(task);
+ const start = verbosity >= VerbosityLevel.INFOS ? Date.now() : 0;
+ page.getOperatorList({
+ handler,
+ sink,
+ task,
+ intent,
+ cacheKey,
+ annotationStorage,
+ modifiedIds,
+ pageIndex
+ }).then(opListInfo => {
+ if (start) {
+ info(`${task.name}; time=${Date.now() - start}ms, len=${opListInfo.length}`);
+ }
+ sink.close();
+ }, reason => {
+ if (task.terminated) {
+ return;
+ }
+ sink.error(reason);
+ }).finally(() => {
+ finishWorkerTask(task);
+ });
+ });
+ });
+ handler.on("GetTextContent", function ({
+ pageId,
+ pageIndex,
+ includeMarkedContent,
+ disableNormalization
+ }, sink) {
+ pdfManager.getPage(pageId).then(function (page) {
+ const task = new WorkerTask("GetTextContent: page " + pageIndex);
+ startWorkerTask(task);
+ const start = verbosity >= VerbosityLevel.INFOS ? Date.now() : 0;
+ page.extractTextContent({
+ handler,
+ task,
+ sink,
+ includeMarkedContent,
+ disableNormalization
+ }).then(() => {
+ if (start) {
+ info(`${task.name}; time=${Date.now() - start}ms`);
+ }
+ sink.close();
+ }, reason => {
+ if (task.terminated) {
+ return;
+ }
+ sink.error(reason);
+ }).finally(() => {
+ finishWorkerTask(task);
+ });
+ });
+ });
+ handler.on("GetStructTree", async function ({
+ pageIndex
+ }) {
+ const page = await pdfManager.getPage(pageIndex);
+ return pdfManager.ensure(page, "getStructTree");
+ });
+ handler.on("FontFallback", function ({
+ id
+ }) {
+ return pdfManager.fontFallback(id, handler);
+ });
+ handler.on("Cleanup", function () {
+ return pdfManager.cleanup(true);
+ });
+ handler.on("Terminate", async function () {
+ terminated = true;
+ const waitOn = [];
+ if (pdfManager) {
+ pdfManager.terminate(new AbortException("Worker was terminated."));
+ const cleanupPromise = pdfManager.cleanup();
+ waitOn.push(cleanupPromise);
+ pdfManager = null;
+ } else {
+ clearGlobalCaches();
+ }
+ cancelXHRs?.(new AbortException("Worker was terminated."));
+ for (const task of WorkerTasks) {
+ waitOn.push(task.finished);
+ task.terminate();
+ }
+ await Promise.all(waitOn);
+ handler.destroy();
+ handler = null;
+ });
+ handler.on("Ready", function () {
+ setupDoc(docParams);
+ docParams = null;
+ });
+ return workerHandlerName;
+ }
+ static initializeFromPort(port) {
+ const handler = new MessageHandler("worker", "main", port);
+ this.setup(handler, port);
+ handler.send("ready", null);
+ }
+}
+
+;// ./src/pdf.worker.js
+
+globalThis.pdfjsWorker = {
+ WorkerMessageHandler: WorkerMessageHandler
+};
+
+export { WorkerMessageHandler };
+
+//# sourceMappingURL=pdf.worker.mjs.map
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-EUC-H.bcmap
new file mode 100644
index 0000000..2655fc7
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-EUC-V.bcmap
new file mode 100644
index 0000000..f1ed853
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-H.bcmap
new file mode 100644
index 0000000..39e89d3
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-RKSJ-H.bcmap
new file mode 100644
index 0000000..e4167cb
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-RKSJ-V.bcmap
new file mode 100644
index 0000000..50b1646
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-V.bcmap
new file mode 100644
index 0000000..d7af99b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78ms-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78ms-RKSJ-H.bcmap
new file mode 100644
index 0000000..37077d0
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78ms-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78ms-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78ms-RKSJ-V.bcmap
new file mode 100644
index 0000000..acf2323
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/78ms-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/83pv-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/83pv-RKSJ-H.bcmap
new file mode 100644
index 0000000..2359bc5
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/83pv-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90ms-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90ms-RKSJ-H.bcmap
new file mode 100644
index 0000000..af82938
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90ms-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90ms-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90ms-RKSJ-V.bcmap
new file mode 100644
index 0000000..780549d
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90ms-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90msp-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90msp-RKSJ-H.bcmap
new file mode 100644
index 0000000..bfd3119
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90msp-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90msp-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90msp-RKSJ-V.bcmap
new file mode 100644
index 0000000..25ef14a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90msp-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90pv-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90pv-RKSJ-H.bcmap
new file mode 100644
index 0000000..02f713b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90pv-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90pv-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90pv-RKSJ-V.bcmap
new file mode 100644
index 0000000..d08e0cc
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/90pv-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-H.bcmap
new file mode 100644
index 0000000..59442ac
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-RKSJ-H.bcmap
new file mode 100644
index 0000000..a3065e4
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-RKSJ-V.bcmap
new file mode 100644
index 0000000..040014c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-V.bcmap
new file mode 100644
index 0000000..2f816d3
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Add-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-0.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-0.bcmap
new file mode 100644
index 0000000..88ec04a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-0.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-1.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-1.bcmap
new file mode 100644
index 0000000..03a5014
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-1.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-2.bcmap
new file mode 100644
index 0000000..2aa9514
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-3.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-3.bcmap
new file mode 100644
index 0000000..86d8b8c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-3.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-4.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-4.bcmap
new file mode 100644
index 0000000..f50fc6c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-4.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-5.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-5.bcmap
new file mode 100644
index 0000000..6caf4a8
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-5.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-6.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-6.bcmap
new file mode 100644
index 0000000..b77fb07
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-6.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-UCS2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-UCS2.bcmap
new file mode 100644
index 0000000..69d79a2
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-CNS1-UCS2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-0.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-0.bcmap
new file mode 100644
index 0000000..3610108
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-0.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-1.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-1.bcmap
new file mode 100644
index 0000000..707bb10
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-1.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-2.bcmap
new file mode 100644
index 0000000..f7648cc
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-3.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-3.bcmap
new file mode 100644
index 0000000..8521458
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-3.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-4.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-4.bcmap
new file mode 100644
index 0000000..e40c63a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-4.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-5.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-5.bcmap
new file mode 100644
index 0000000..d7623b5
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-5.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-UCS2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-UCS2.bcmap
new file mode 100644
index 0000000..7586525
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-GB1-UCS2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-0.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-0.bcmap
new file mode 100644
index 0000000..f0e94ec
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-0.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-1.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-1.bcmap
new file mode 100644
index 0000000..dad42c5
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-1.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-2.bcmap
new file mode 100644
index 0000000..090819a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-3.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-3.bcmap
new file mode 100644
index 0000000..087dfc1
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-3.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-4.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-4.bcmap
new file mode 100644
index 0000000..46aa9bf
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-4.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-5.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-5.bcmap
new file mode 100644
index 0000000..5b4b65c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-5.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-6.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-6.bcmap
new file mode 100644
index 0000000..e77d699
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-6.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-UCS2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-UCS2.bcmap
new file mode 100644
index 0000000..128a141
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Japan1-UCS2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-0.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-0.bcmap
new file mode 100644
index 0000000..cef1a99
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-0.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-1.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-1.bcmap
new file mode 100644
index 0000000..11ffa36
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-1.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-2.bcmap
new file mode 100644
index 0000000..3172308
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-UCS2.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-UCS2.bcmap
new file mode 100644
index 0000000..f3371c0
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Adobe-Korea1-UCS2.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5-H.bcmap
new file mode 100644
index 0000000..beb4d22
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5-V.bcmap
new file mode 100644
index 0000000..2d4f87d
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5pc-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5pc-H.bcmap
new file mode 100644
index 0000000..ce00131
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5pc-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5pc-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5pc-V.bcmap
new file mode 100644
index 0000000..73b99ff
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/B5pc-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS-EUC-H.bcmap
new file mode 100644
index 0000000..61d1d0c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS-EUC-V.bcmap
new file mode 100644
index 0000000..1a393a5
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS1-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS1-H.bcmap
new file mode 100644
index 0000000..f738e21
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS1-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS1-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS1-V.bcmap
new file mode 100644
index 0000000..9c3169f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS1-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS2-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS2-H.bcmap
new file mode 100644
index 0000000..c89b352
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS2-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS2-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS2-V.bcmap
new file mode 100644
index 0000000..7588cec
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/CNS2-V.bcmap
@@ -0,0 +1,3 @@
+àRCopyright 1990-2009 Adobe Systems Incorporated.
+All rights reserved.
+See ./LICENSEáCNS2-H
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETHK-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETHK-B5-H.bcmap
new file mode 100644
index 0000000..cb29415
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETHK-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETHK-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETHK-B5-V.bcmap
new file mode 100644
index 0000000..f09aec6
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETHK-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETen-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETen-B5-H.bcmap
new file mode 100644
index 0000000..c2d7746
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETen-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETen-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETen-B5-V.bcmap
new file mode 100644
index 0000000..89bff15
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETen-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETenms-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETenms-B5-H.bcmap
new file mode 100644
index 0000000..a7d69db
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETenms-B5-H.bcmap
@@ -0,0 +1,3 @@
+àRCopyright 1990-2009 Adobe Systems Incorporated.
+All rights reserved.
+See ./LICENSEá ETen-B5-H` ^
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETenms-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETenms-B5-V.bcmap
new file mode 100644
index 0000000..adc5d61
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/ETenms-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/EUC-H.bcmap
new file mode 100644
index 0000000..e92ea5b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/EUC-V.bcmap
new file mode 100644
index 0000000..7a7c183
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-H.bcmap
new file mode 100644
index 0000000..3b5cde4
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-RKSJ-H.bcmap
new file mode 100644
index 0000000..ea4d2d9
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-RKSJ-V.bcmap
new file mode 100644
index 0000000..3457c27
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-V.bcmap
new file mode 100644
index 0000000..4999ca4
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Ext-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-EUC-H.bcmap
new file mode 100644
index 0000000..e39908b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-EUC-V.bcmap
new file mode 100644
index 0000000..d5be544
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-H.bcmap
new file mode 100644
index 0000000..39189c5
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-H.bcmap
@@ -0,0 +1,4 @@
+àRCopyright 1990-2009 Adobe Systems Incorporated.
+All rights reserved.
+See ./LICENSE!!�º]aX!!]`�21�> �p�z�$]‚�"R‚d�-Uƒ7�*„
4„%�+ „Z „{�/…%…<�9K…b�1]†.�"‡‰`]‡,�"]ˆ
+�"]ˆh�"]‰F�"]Š$�"]‹�"]‹`�"]Œ>�"]��"]�z�"]ŽX�"]�6�"]��"]�r�"]‘P�"]’.�"]“�"]“j�"]”H�"]•&�"]–�"]–b�"]—@�"]˜�"]˜|�"]™Z�"]š8�"]›�"]›t�"]œR�"]�0�"]ž�"]žl�"]ŸJ�"] (�"]¡�"]¡d�"]¢B�"]£ �"X£~�']¤W�"]¥5�"]¦�"]¦q�"]§O�"]¨-�"]©�"]©i�"]ªG�"]«%�"]¬�"]¬a�"]?�"]®�"]®{�"]¯Y�"]°7�"]±�"]±s�"]²Q�"]³/�"]´
�"]´k�"]µI�"]¶'�"]·�"]·c�"]¸A�"]¹�"]¹}�"]º[�"]»9
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-V.bcmap
new file mode 100644
index 0000000..3108345
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GB-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK-EUC-H.bcmap
new file mode 100644
index 0000000..05fff7e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK-EUC-V.bcmap
new file mode 100644
index 0000000..0cdf6be
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK2K-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK2K-H.bcmap
new file mode 100644
index 0000000..46f6ba5
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK2K-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK2K-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK2K-V.bcmap
new file mode 100644
index 0000000..d9a9479
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBK2K-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBKp-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBKp-EUC-H.bcmap
new file mode 100644
index 0000000..5cb0af6
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBKp-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBKp-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBKp-EUC-V.bcmap
new file mode 100644
index 0000000..bca93b8
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBKp-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-EUC-H.bcmap
new file mode 100644
index 0000000..4b4e2d3
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-EUC-V.bcmap
new file mode 100644
index 0000000..38f7066
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-H.bcmap
new file mode 100644
index 0000000..8437ac3
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-V.bcmap
new file mode 100644
index 0000000..697ab4a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBT-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBTpc-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBTpc-EUC-H.bcmap
new file mode 100644
index 0000000..f6e50e8
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBTpc-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBTpc-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBTpc-EUC-V.bcmap
new file mode 100644
index 0000000..6c0d71a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBTpc-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBpc-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBpc-EUC-H.bcmap
new file mode 100644
index 0000000..c9edf67
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBpc-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBpc-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBpc-EUC-V.bcmap
new file mode 100644
index 0000000..31450c9
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/GBpc-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/H.bcmap
new file mode 100644
index 0000000..7b24ea4
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdla-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdla-B5-H.bcmap
new file mode 100644
index 0000000..7d30c05
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdla-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdla-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdla-B5-V.bcmap
new file mode 100644
index 0000000..7894694
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdla-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdlb-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdlb-B5-H.bcmap
new file mode 100644
index 0000000..d829a23
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdlb-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdlb-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdlb-B5-V.bcmap
new file mode 100644
index 0000000..2b572b5
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKdlb-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKgccs-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKgccs-B5-H.bcmap
new file mode 100644
index 0000000..971a4f2
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKgccs-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKgccs-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKgccs-B5-V.bcmap
new file mode 100644
index 0000000..d353ca2
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKgccs-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm314-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm314-B5-H.bcmap
new file mode 100644
index 0000000..576dc01
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm314-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm314-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm314-B5-V.bcmap
new file mode 100644
index 0000000..0e96d0e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm314-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm471-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm471-B5-H.bcmap
new file mode 100644
index 0000000..11d170c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm471-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm471-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm471-B5-V.bcmap
new file mode 100644
index 0000000..54959bf
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKm471-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKscs-B5-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKscs-B5-H.bcmap
new file mode 100644
index 0000000..6ef7857
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKscs-B5-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKscs-B5-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKscs-B5-V.bcmap
new file mode 100644
index 0000000..1fb2fa2
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/HKscs-B5-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Hankaku.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Hankaku.bcmap
new file mode 100644
index 0000000..4b8ec7f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Hankaku.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Hiragana.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Hiragana.bcmap
new file mode 100644
index 0000000..17e983e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Hiragana.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-EUC-H.bcmap
new file mode 100644
index 0000000..a45c65f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-EUC-V.bcmap
new file mode 100644
index 0000000..0e7b21f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-H.bcmap
new file mode 100644
index 0000000..b9b22b6
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-Johab-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-Johab-H.bcmap
new file mode 100644
index 0000000..2531ffc
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-Johab-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-Johab-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-Johab-V.bcmap
new file mode 100644
index 0000000..367ceb2
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-Johab-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-V.bcmap
new file mode 100644
index 0000000..6ae2f0b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-H.bcmap
new file mode 100644
index 0000000..a8d4240
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-HW-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-HW-H.bcmap
new file mode 100644
index 0000000..8b4ae18
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-HW-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-HW-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-HW-V.bcmap
new file mode 100644
index 0000000..b655dbc
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-HW-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-V.bcmap
new file mode 100644
index 0000000..21f97f6
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCms-UHC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCpc-EUC-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCpc-EUC-H.bcmap
new file mode 100644
index 0000000..e06f361
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCpc-EUC-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCpc-EUC-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCpc-EUC-V.bcmap
new file mode 100644
index 0000000..f3c9113
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/KSCpc-EUC-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Katakana.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Katakana.bcmap
new file mode 100644
index 0000000..524303c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Katakana.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/LICENSE b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/LICENSE
new file mode 100644
index 0000000..b1ad168
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/LICENSE
@@ -0,0 +1,36 @@
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/NWP-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/NWP-H.bcmap
new file mode 100644
index 0000000..afc5e4b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/NWP-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/NWP-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/NWP-V.bcmap
new file mode 100644
index 0000000..bb5785e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/NWP-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/RKSJ-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/RKSJ-H.bcmap
new file mode 100644
index 0000000..fb8d298
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/RKSJ-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/RKSJ-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/RKSJ-V.bcmap
new file mode 100644
index 0000000..a2555a6
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/RKSJ-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Roman.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Roman.bcmap
new file mode 100644
index 0000000..f896dcf
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/Roman.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UCS2-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UCS2-H.bcmap
new file mode 100644
index 0000000..d5db27c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UCS2-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UCS2-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UCS2-V.bcmap
new file mode 100644
index 0000000..1dc9b7a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UCS2-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF16-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF16-H.bcmap
new file mode 100644
index 0000000..961afef
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF16-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF16-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF16-V.bcmap
new file mode 100644
index 0000000..df0cffe
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF16-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF32-H.bcmap
new file mode 100644
index 0000000..1ab18a1
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF32-V.bcmap
new file mode 100644
index 0000000..ad14662
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF8-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF8-H.bcmap
new file mode 100644
index 0000000..83c6bd7
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF8-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF8-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF8-V.bcmap
new file mode 100644
index 0000000..22a27e4
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniCNS-UTF8-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UCS2-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UCS2-H.bcmap
new file mode 100644
index 0000000..5bd6228
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UCS2-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UCS2-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UCS2-V.bcmap
new file mode 100644
index 0000000..53c534b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UCS2-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF16-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF16-H.bcmap
new file mode 100644
index 0000000..b95045b
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF16-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF16-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF16-V.bcmap
new file mode 100644
index 0000000..51f023e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF16-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF32-H.bcmap
new file mode 100644
index 0000000..f0dbd14
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF32-V.bcmap
new file mode 100644
index 0000000..ce9c30a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF8-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF8-H.bcmap
new file mode 100644
index 0000000..982ca46
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF8-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF8-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF8-V.bcmap
new file mode 100644
index 0000000..f78020d
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniGB-UTF8-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-H.bcmap
new file mode 100644
index 0000000..7daf56a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-HW-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-HW-H.bcmap
new file mode 100644
index 0000000..ac9975c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-HW-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-HW-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-HW-V.bcmap
new file mode 100644
index 0000000..3da0a1c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-HW-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-V.bcmap
new file mode 100644
index 0000000..c50b9dd
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UCS2-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF16-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF16-H.bcmap
new file mode 100644
index 0000000..6761344
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF16-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF16-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF16-V.bcmap
new file mode 100644
index 0000000..70bf90c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF16-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF32-H.bcmap
new file mode 100644
index 0000000..7a83d53
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF32-V.bcmap
new file mode 100644
index 0000000..7a87135
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF8-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF8-H.bcmap
new file mode 100644
index 0000000..9f0334c
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF8-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF8-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF8-V.bcmap
new file mode 100644
index 0000000..808a94f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS-UTF8-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF16-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF16-H.bcmap
new file mode 100644
index 0000000..d768bf8
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF16-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF16-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF16-V.bcmap
new file mode 100644
index 0000000..3d5bf6f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF16-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF32-H.bcmap
new file mode 100644
index 0000000..09eee10
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF32-V.bcmap
new file mode 100644
index 0000000..6c54600
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF8-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF8-H.bcmap
new file mode 100644
index 0000000..1b1a64f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF8-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF8-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF8-V.bcmap
new file mode 100644
index 0000000..994aa9e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJIS2004-UTF8-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UCS2-HW-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UCS2-HW-V.bcmap
new file mode 100644
index 0000000..643f921
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UCS2-HW-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UCS2-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UCS2-V.bcmap
new file mode 100644
index 0000000..c148f67
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UCS2-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UTF8-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UTF8-V.bcmap
new file mode 100644
index 0000000..1849d80
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISPro-UTF8-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX0213-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX0213-UTF32-H.bcmap
new file mode 100644
index 0000000..a83a677
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX0213-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX0213-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX0213-UTF32-V.bcmap
new file mode 100644
index 0000000..f527248
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX0213-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX02132004-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX02132004-UTF32-H.bcmap
new file mode 100644
index 0000000..e1a988d
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX02132004-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX02132004-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX02132004-UTF32-V.bcmap
new file mode 100644
index 0000000..47e054a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniJISX02132004-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UCS2-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UCS2-H.bcmap
new file mode 100644
index 0000000..b5b9485
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UCS2-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UCS2-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UCS2-V.bcmap
new file mode 100644
index 0000000..026adca
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UCS2-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF16-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF16-H.bcmap
new file mode 100644
index 0000000..fd4e66e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF16-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF16-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF16-V.bcmap
new file mode 100644
index 0000000..075efb7
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF16-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF32-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF32-H.bcmap
new file mode 100644
index 0000000..769d214
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF32-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF32-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF32-V.bcmap
new file mode 100644
index 0000000..bdab208
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF32-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF8-H.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF8-H.bcmap
new file mode 100644
index 0000000..6ff8674
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF8-H.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF8-V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF8-V.bcmap
new file mode 100644
index 0000000..8dfa76a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/UniKS-UTF8-V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/V.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/V.bcmap
new file mode 100644
index 0000000..fdec990
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/V.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/WP-Symbol.bcmap b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/WP-Symbol.bcmap
new file mode 100644
index 0000000..46729bb
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/cmaps/WP-Symbol.bcmap differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/debugger.css b/app/web/vendor/pdfjs/6.3.289-app1/web/debugger.css
new file mode 100644
index 0000000..7405844
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/debugger.css
@@ -0,0 +1,145 @@
+/* Copyright 2014 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+:root {
+ --panel-width: 300px;
+}
+
+#PDFBug,
+#PDFBug :is(input, button, select) {
+ font: message-box;
+}
+#PDFBug {
+ color-scheme: only light;
+
+ background-color: white;
+ color: black;
+ border: 1px solid rgb(102 102 102);
+ position: fixed;
+ top: 32px;
+ right: 0;
+ bottom: 0;
+ font-size: 10px;
+ padding: 0;
+ width: var(--panel-width);
+}
+#PDFBug .controls {
+ background: rgb(238 238 238);
+ border-bottom: 1px solid rgb(102 102 102);
+ padding: 3px;
+}
+#PDFBug .panels {
+ inset: 27px 0 0;
+ overflow: auto;
+ position: absolute;
+}
+#PDFBug .panels > div {
+ padding: 5px;
+}
+#PDFBug button.active {
+ font-weight: bold;
+}
+.debuggerShowText,
+.debuggerHideText:hover {
+ background-color: rgb(255 255 0 / 0.25);
+}
+#PDFBug .stats {
+ font-family: courier;
+ font-size: 10px;
+ white-space: pre;
+}
+#PDFBug .stats .title {
+ font-weight: bold;
+}
+#PDFBug table {
+ font-size: 10px;
+ white-space: pre;
+}
+#PDFBug table.showText {
+ border-collapse: collapse;
+ text-align: center;
+}
+#PDFBug table.showText,
+#PDFBug table.showText :is(tr, td) {
+ border: 1px solid black;
+ padding: 1px;
+}
+#PDFBug table.showText td.advance {
+ color: grey;
+}
+
+#viewer.textLayer-visible .textLayer {
+ opacity: 1;
+}
+
+#viewer.textLayer-visible .canvasWrapper {
+ background-color: rgb(128 255 128);
+}
+
+#viewer.textLayer-visible .canvasWrapper canvas {
+ mix-blend-mode: screen;
+}
+
+#viewer.textLayer-visible .textLayer span {
+ background-color: rgb(255 255 0 / 0.1);
+ color: rgb(0 0 0);
+ border: solid 1px rgb(255 0 0 / 0.5);
+ box-sizing: border-box;
+}
+
+#viewer.textLayer-visible .textLayer span[aria-owns] {
+ background-color: rgb(255 0 0 / 0.3);
+}
+
+#viewer.textLayer-hover .textLayer span:hover {
+ background-color: rgb(255 255 255);
+ color: rgb(0 0 0);
+}
+
+#viewer.textLayer-shadow .textLayer span {
+ background-color: rgb(255 255 255 / 0.6);
+ color: rgb(0 0 0);
+}
+
+.pdfBugGroupsLayer {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+
+ > * {
+ position: absolute;
+ outline-color: red;
+ outline-width: 2px;
+
+ --hover-outline-style: solid !important;
+ --hover-background-color: rgb(255 0 0 / 0.2);
+
+ &:hover {
+ outline-style: var(--hover-outline-style);
+ background-color: var(--hover-background-color);
+ cursor: pointer;
+ }
+
+ .showDebugBoxes & {
+ outline-style: dashed;
+ }
+ }
+}
+
+.showDebugBoxes {
+ .pdfBugGroupsLayer {
+ pointer-events: all;
+ }
+}
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/debugger.mjs b/app/web/vendor/pdfjs/6.3.289-app1/web/debugger.mjs
new file mode 100644
index 0000000..cbaaf79
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/debugger.mjs
@@ -0,0 +1,835 @@
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const { makeSet, OPS } = globalThis.pdfjsLib || (await import("pdfjs-lib"));
+
+const opMap = Object.create(null);
+for (const key in OPS) {
+ opMap[OPS[key]] = key;
+}
+
+const FontInspector = (function FontInspectorClosure() {
+ let fonts;
+ let active = false;
+ const fontAttribute = "data-font-name";
+ function removeSelection() {
+ const divs = document.querySelectorAll(`span[${fontAttribute}]`);
+ for (const div of divs) {
+ div.className = "";
+ }
+ }
+ function resetSelection() {
+ const divs = document.querySelectorAll(`span[${fontAttribute}]`);
+ for (const div of divs) {
+ div.className = "debuggerHideText";
+ }
+ }
+ function selectFont(fontName, show) {
+ const divs = document.querySelectorAll(
+ `span[${fontAttribute}=${fontName}]`
+ );
+ for (const div of divs) {
+ div.className = show ? "debuggerShowText" : "debuggerHideText";
+ }
+ }
+ function textLayerClick(e) {
+ if (
+ !e.target.dataset.fontName ||
+ e.target.tagName.toUpperCase() !== "SPAN"
+ ) {
+ return;
+ }
+ const fontName = e.target.dataset.fontName;
+ const selects = document.getElementsByTagName("input");
+ for (const select of selects) {
+ if (select.dataset.fontName !== fontName) {
+ continue;
+ }
+ select.checked = !select.checked;
+ selectFont(fontName, select.checked);
+ select.scrollIntoView();
+ }
+ }
+ return {
+ // Properties/functions needed by PDFBug.
+ id: "FontInspector",
+ name: "Font Inspector",
+ panel: null,
+ manager: null,
+ init() {
+ const panel = this.panel;
+ const tmp = document.createElement("button");
+ tmp.addEventListener("click", resetSelection);
+ tmp.textContent = "Refresh";
+ panel.append(tmp);
+
+ fonts = document.createElement("div");
+ panel.append(fonts);
+ },
+ cleanup() {
+ fonts.textContent = "";
+ },
+ enabled: false,
+ get active() {
+ return active;
+ },
+ set active(value) {
+ active = value;
+ if (active) {
+ document.body.addEventListener("click", textLayerClick, true);
+ resetSelection();
+ } else {
+ document.body.removeEventListener("click", textLayerClick, true);
+ removeSelection();
+ }
+ },
+ // FontInspector specific functions.
+ fontAdded(fontObj, url) {
+ function properties(obj, list) {
+ const moreInfo = document.createElement("table");
+ for (const entry of list) {
+ const tr = document.createElement("tr");
+ const td1 = document.createElement("td");
+ td1.textContent = entry;
+ tr.append(td1);
+ const td2 = document.createElement("td");
+ td2.textContent = obj[entry].toString();
+ tr.append(td2);
+ moreInfo.append(tr);
+ }
+ return moreInfo;
+ }
+
+ const moreInfo = fontObj.css
+ ? properties(fontObj, ["baseFontName"])
+ : properties(fontObj, ["name", "type"]);
+
+ const fontName = fontObj.loadedName;
+ const font = document.createElement("div");
+ const name = document.createElement("span");
+ name.textContent = fontName;
+ let download;
+ if (!fontObj.css) {
+ download = document.createElement("a");
+ if (url) {
+ url = /url\(['"]?([^)"']+)/.exec(url);
+ download.href = url[1];
+ } else if (fontObj.data) {
+ download.href = URL.createObjectURL(
+ new Blob([fontObj.data], { type: fontObj.mimetype })
+ );
+ }
+ download.textContent = "Download";
+ }
+
+ const logIt = document.createElement("a");
+ logIt.href = "";
+ logIt.textContent = "Log";
+ logIt.addEventListener("click", function (event) {
+ event.preventDefault();
+ console.log(fontObj);
+ });
+ const select = document.createElement("input");
+ select.setAttribute("type", "checkbox");
+ select.dataset.fontName = fontName;
+ select.addEventListener("click", function () {
+ selectFont(fontName, select.checked);
+ });
+ if (download) {
+ font.append(select, name, " ", download, " ", logIt, moreInfo);
+ } else {
+ font.append(select, name, " ", logIt, moreInfo);
+ }
+ fonts.append(font);
+ // Somewhat of a hack, should probably add a hook for when the text layer
+ // is done rendering.
+ setTimeout(() => {
+ if (this.active) {
+ resetSelection();
+ }
+ }, 2000);
+ },
+ };
+})();
+
+// Manages all the page steppers.
+const StepperManager = (function StepperManagerClosure() {
+ let steppers = [];
+ let stepperDiv = null;
+ let stepperControls = null;
+ let stepperChooser = null;
+ let breakPoints = Object.create(null);
+ return {
+ // Properties/functions needed by PDFBug.
+ id: "Stepper",
+ name: "Stepper",
+ panel: null,
+ manager: null,
+ init() {
+ const self = this;
+ stepperControls = document.createElement("div");
+ stepperChooser = document.createElement("select");
+ stepperChooser.addEventListener("change", function (event) {
+ self.selectStepper(this.value);
+ });
+ stepperControls.append(stepperChooser);
+ stepperDiv = document.createElement("div");
+ this.panel.append(stepperControls, stepperDiv);
+ if (sessionStorage.getItem("pdfjsBreakPoints")) {
+ breakPoints = JSON.parse(sessionStorage.getItem("pdfjsBreakPoints"));
+ }
+ },
+ cleanup() {
+ stepperChooser.textContent = "";
+ stepperDiv.textContent = "";
+ steppers = [];
+ },
+ enabled: false,
+ active: false,
+ // Stepper specific functions.
+ create(pageIndex) {
+ const pageContainer = document.querySelector(
+ `#viewer div[data-page-number="${pageIndex + 1}"]`
+ );
+
+ const debug = document.createElement("div");
+ debug.id = "stepper" + pageIndex;
+ debug.hidden = true;
+ debug.className = "stepper";
+ stepperDiv.append(debug);
+ const b = document.createElement("option");
+ b.textContent = "Page " + (pageIndex + 1);
+ b.value = pageIndex;
+ stepperChooser.append(b);
+ const initBreakPoints = breakPoints[pageIndex] || [];
+ const stepper = new Stepper(
+ debug,
+ pageIndex,
+ initBreakPoints,
+ pageContainer
+ );
+ steppers.push(stepper);
+ if (steppers.length === 1) {
+ this.selectStepper(pageIndex, false);
+ }
+ return stepper;
+ },
+ selectStepper(pageIndex, selectPanel) {
+ pageIndex |= 0;
+ if (selectPanel) {
+ this.manager.selectPanel(this);
+ }
+ for (const stepper of steppers) {
+ stepper.panel.hidden = stepper.pageIndex !== pageIndex;
+ }
+ for (const option of stepperChooser.options) {
+ option.selected = (option.value | 0) === pageIndex;
+ }
+ },
+ saveBreakPoints(pageIndex, bps) {
+ breakPoints[pageIndex] = bps;
+ sessionStorage.setItem("pdfjsBreakPoints", JSON.stringify(breakPoints));
+ },
+ };
+})();
+
+// The stepper for each page's operatorList.
+class Stepper {
+ // Shorter way to create element and optionally set textContent.
+ #c(tag, textContent) {
+ const d = document.createElement(tag);
+ if (textContent) {
+ d.textContent = textContent;
+ }
+ return d;
+ }
+
+ #simplifyArgs(args) {
+ if (typeof args === "string") {
+ const MAX_STRING_LENGTH = 75;
+ return args.length <= MAX_STRING_LENGTH
+ ? args
+ : args.substring(0, MAX_STRING_LENGTH) + "...";
+ }
+ if (typeof args !== "object" || args === null) {
+ return args;
+ }
+ if ("length" in args) {
+ // array
+ const MAX_ITEMS = 10,
+ simpleArgs = [];
+ let i, ii;
+ for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) {
+ simpleArgs.push(this.#simplifyArgs(args[i]));
+ }
+ if (i < args.length) {
+ simpleArgs.push("...");
+ }
+ return simpleArgs;
+ }
+ const simpleObj = {};
+ for (const key in args) {
+ simpleObj[key] = this.#simplifyArgs(args[key]);
+ }
+ return simpleObj;
+ }
+
+ constructor(panel, pageIndex, initialBreakPoints, pageContainer) {
+ this.panel = panel;
+ this.breakPoint = 0;
+ this.nextBreakPoint = null;
+ this.pageIndex = pageIndex;
+ this.breakPoints = initialBreakPoints;
+ this.currentIdx = -1;
+ this.operatorListIdx = 0;
+ this.indentLevel = 0;
+ this.operatorsGroups = null;
+ this.pageContainer = pageContainer;
+ }
+
+ init(operatorList) {
+ const panel = this.panel;
+ const content = this.#c("div", "c=continue, s=step");
+
+ const showBoxesToggle = this.#c("label", "Show bounding boxes");
+ const showBoxesCheckbox = this.#c("input");
+ showBoxesCheckbox.type = "checkbox";
+ showBoxesToggle.prepend(showBoxesCheckbox);
+ content.append(this.#c("br"), showBoxesToggle);
+
+ const table = this.#c("table");
+ content.append(table);
+ table.cellSpacing = 0;
+ const headerRow = this.#c("tr");
+ table.append(headerRow);
+ headerRow.append(
+ this.#c("th", "Break"),
+ this.#c("th", "Idx"),
+ this.#c("th", "fn"),
+ this.#c("th", "args")
+ );
+ panel.append(content);
+ this.table = table;
+ this.updateOperatorList(operatorList);
+
+ const hoverStyle = this.#c("style");
+ this.hoverStyle = hoverStyle;
+ content.prepend(hoverStyle);
+ table.addEventListener("mouseover", this.#handleStepHover.bind(this));
+ table.addEventListener("mouseleave", e => {
+ hoverStyle.innerText = "";
+ });
+
+ showBoxesCheckbox.addEventListener("change", () => {
+ this.pageContainer.classList.toggle(
+ "showDebugBoxes",
+ showBoxesCheckbox.checked
+ );
+ });
+ }
+
+ updateOperatorList(operatorList) {
+ const self = this;
+
+ function cboxOnClick() {
+ const x = +this.dataset.idx;
+ if (this.checked) {
+ self.breakPoints.push(x);
+ } else {
+ self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
+ }
+ StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
+ }
+
+ const MAX_OPERATORS_COUNT = 15000;
+ if (this.operatorListIdx > MAX_OPERATORS_COUNT) {
+ return;
+ }
+
+ const chunk = document.createDocumentFragment();
+ const operatorsToDisplay = Math.min(
+ MAX_OPERATORS_COUNT,
+ operatorList.fnArray.length
+ );
+ for (let i = this.operatorListIdx; i < operatorsToDisplay; i++) {
+ const line = this.#c("tr");
+ line.className = "line";
+ line.dataset.idx = i;
+ chunk.append(line);
+ const checked = this.breakPoints.includes(i);
+ const args = operatorList.argsArray[i] || [];
+
+ const breakCell = this.#c("td");
+ const cbox = this.#c("input");
+ cbox.type = "checkbox";
+ cbox.className = "points";
+ cbox.checked = checked;
+ cbox.dataset.idx = i;
+ cbox.onclick = cboxOnClick;
+
+ breakCell.append(cbox);
+ line.append(breakCell, this.#c("td", i.toString()));
+ const fn = opMap[operatorList.fnArray[i]];
+ let decArgs = args;
+ if (fn === "showText") {
+ const glyphs = args[0];
+ const charCodeRow = this.#c("tr");
+ const fontCharRow = this.#c("tr");
+ const unicodeRow = this.#c("tr");
+ for (const glyph of glyphs) {
+ if (typeof glyph === "object" && glyph !== null) {
+ charCodeRow.append(this.#c("td", glyph.originalCharCode));
+ fontCharRow.append(this.#c("td", glyph.fontChar));
+ unicodeRow.append(this.#c("td", glyph.unicode));
+ } else {
+ // null or number
+ const advanceEl = this.#c("td", glyph);
+ advanceEl.classList.add("advance");
+ charCodeRow.append(advanceEl);
+ fontCharRow.append(this.#c("td"));
+ unicodeRow.append(this.#c("td"));
+ }
+ }
+ decArgs = this.#c("td");
+ const table = this.#c("table");
+ table.classList.add("showText");
+ decArgs.append(table);
+ table.append(charCodeRow, fontCharRow, unicodeRow);
+ } else if (fn === "constructPath") {
+ const [op, [path], minMax] = args;
+ decArgs = this.#c("td");
+ decArgs.append(JSON.stringify(this.#simplifyArgs(path)));
+ decArgs.append(this.#c("br"));
+ decArgs.append(`minMax: ${JSON.stringify(this.#simplifyArgs(minMax))}`);
+ decArgs.append(this.#c("br"));
+ decArgs.append(`→ ${opMap[op]}`);
+ } else if (fn === "restore" && this.indentLevel > 0) {
+ this.indentLevel--;
+ }
+ line.append(this.#c("td", " ".repeat(this.indentLevel * 2) + fn));
+ if (fn === "save") {
+ this.indentLevel++;
+ }
+
+ if (decArgs instanceof HTMLElement) {
+ line.append(decArgs);
+ } else {
+ line.append(this.#c("td", JSON.stringify(this.#simplifyArgs(decArgs))));
+ }
+ }
+ if (operatorsToDisplay < operatorList.fnArray.length) {
+ const lastCell = this.#c("td", "...");
+ lastCell.colspan = 4;
+ chunk.append(lastCell);
+ }
+ this.operatorListIdx = operatorList.fnArray.length;
+ this.table.append(chunk);
+ }
+
+ setOperatorBBoxes(bboxes, metadata) {
+ let boxesContainer = this.pageContainer.querySelector(".pdfBugGroupsLayer");
+ if (!boxesContainer) {
+ boxesContainer = this.#c("div");
+ boxesContainer.classList.add("pdfBugGroupsLayer");
+ this.pageContainer.append(boxesContainer);
+
+ boxesContainer.addEventListener(
+ "click",
+ this.#handleDebugBoxClick.bind(this)
+ );
+ boxesContainer.addEventListener(
+ "mouseover",
+ this.#handleDebugBoxHover.bind(this)
+ );
+ }
+ boxesContainer.innerHTML = "";
+
+ const dependents = new Map();
+ for (const [dependentIdx, { dependencies: ownDependencies }] of metadata) {
+ for (const dependencyIdx of ownDependencies) {
+ dependents
+ .getOrInsertComputed(dependencyIdx, makeSet)
+ .add(dependentIdx);
+ }
+ }
+
+ const groups = Array.from({ length: bboxes.length }, (_, i) => {
+ let minX = null;
+ let minY = null;
+ let maxX = null;
+ let maxY = null;
+ if (!bboxes.isEmpty(i)) {
+ minX = bboxes.minX(i);
+ minY = bboxes.minY(i);
+ maxX = bboxes.maxX(i);
+ maxY = bboxes.maxY(i);
+ }
+
+ return {
+ minX,
+ minY,
+ maxX,
+ maxY,
+ dependencies: Array.from(metadata.get(i)?.dependencies ?? []).sort(),
+ dependents: Array.from(dependents.get(i) ?? []).sort(),
+ isRenderingOperation: metadata.get(i)?.isRenderingOperation ?? false,
+ idx: i,
+ };
+ });
+ this.operatorsGroups = groups;
+
+ const operatorsGroupsByZindex = groups.toSorted((a, b) => {
+ if (a.minX === null) {
+ return b.minX === null ? 0 : 1;
+ }
+ if (b.minX === null) {
+ return -1;
+ }
+
+ const diffs = [
+ a.minY - b.minY,
+ a.minX - b.minX,
+ b.maxY - a.maxY,
+ b.maxX - a.maxX,
+ ];
+ for (const diff of diffs) {
+ if (Math.abs(diff) > 0.01) {
+ return Math.sign(diff);
+ }
+ }
+ for (const diff of diffs) {
+ if (Math.abs(diff) > 0.0001) {
+ return Math.sign(diff);
+ }
+ }
+ return 0;
+ });
+
+ for (const group of operatorsGroupsByZindex) {
+ if (group.minX !== null) {
+ const el = this.#c("div");
+ el.style.left = `${group.minX * 100}%`;
+ el.style.top = `${group.minY * 100}%`;
+ el.style.width = `${(group.maxX - group.minX) * 100}%`;
+ el.style.height = `${(group.maxY - group.minY) * 100}%`;
+ el.dataset.idx = group.idx;
+ boxesContainer.append(el);
+ }
+ }
+ }
+
+ #handleStepHover(e) {
+ const tr = e.target.closest("tr");
+ if (!tr || tr.dataset.idx === undefined) {
+ return;
+ }
+
+ const index = +tr.dataset.idx;
+ this.#highlightStepsGroup(index);
+ }
+
+ #handleDebugBoxHover(e) {
+ if (e.target.dataset.idx === undefined) {
+ return;
+ }
+
+ const idx = Number(e.target.dataset.idx);
+ this.#highlightStepsGroup(idx);
+ }
+
+ #handleDebugBoxClick(e) {
+ if (e.target.dataset.idx === undefined) {
+ return;
+ }
+
+ const idx = Number(e.target.dataset.idx);
+
+ this.table.childNodes[idx].scrollIntoView();
+ }
+
+ #highlightStepsGroup(index) {
+ const group = this.operatorsGroups?.[index];
+ if (!group) {
+ return;
+ }
+
+ const renderingColor = `rgba(0, 0, 0, 0.1)`;
+ const dependencyColor = `rgba(0, 255, 255, 0.1)`;
+ const dependentColor = `rgba(255, 0, 0, 0.1)`;
+
+ const solid = color => `background-color: ${color}`;
+ // Used for operations that have an empty bounding box
+ const striped = color => `
+ background-image: repeating-linear-gradient(
+ -45deg,
+ white,
+ white 10px,
+ ${color} 10px,
+ ${color} 20px
+ )
+ `;
+
+ const select = idx => `#${this.panel.id} tr[data-idx="${idx}"]`;
+ const selectN = idxs =>
+ idxs.length === 0 ? "q:not(q)" : idxs.map(select).join(", ");
+
+ const isEmpty = idx =>
+ !this.operatorsGroups[idx] || this.operatorsGroups[idx].minX === null;
+
+ const selfColor = group.isRenderingOperation
+ ? renderingColor
+ : dependentColor;
+
+ this.hoverStyle.innerText = `${select(index)} {
+ ${group.minX === null ? striped(selfColor) : solid(selfColor)}
+ }`;
+ if (group.dependencies.length > 0) {
+ this.hoverStyle.innerText += `
+ ${selectN(group.dependencies.filter(idx => !isEmpty(idx)))} {
+ ${solid(dependencyColor)}
+ }
+ ${selectN(group.dependencies.filter(isEmpty))} {
+ ${striped(dependencyColor)}
+ }`;
+ }
+ if (group.dependents.length > 0) {
+ this.hoverStyle.innerText += `
+ ${selectN(group.dependents.filter(idx => !isEmpty(idx)))} {
+ ${solid(dependentColor)}
+ }
+ ${selectN(group.dependents.filter(isEmpty))} {
+ ${striped(dependentColor)}
+ }`;
+ }
+
+ this.hoverStyle.innerText += `
+ #viewer [data-page-number="${this.pageIndex + 1}"] .pdfBugGroupsLayer [data-idx="${index}"] {
+ background-color: var(--hover-background-color);
+ outline-style: var(--hover-outline-style);
+ }
+ `;
+ }
+
+ getNextBreakPoint() {
+ this.breakPoints.sort((a, b) => a - b);
+ return this.breakPoints.find(idx => idx > this.currentIdx) ?? null;
+ }
+
+ breakIt(idx, callback) {
+ StepperManager.selectStepper(this.pageIndex, true);
+ this.currentIdx = idx;
+
+ const listener = evt => {
+ switch (evt.keyCode) {
+ case 83: // step
+ document.removeEventListener("keydown", listener);
+ this.nextBreakPoint = this.currentIdx + 1;
+ this.goTo(-1);
+ callback();
+ break;
+ case 67: // continue
+ document.removeEventListener("keydown", listener);
+ this.nextBreakPoint = this.getNextBreakPoint();
+ this.goTo(-1);
+ callback();
+ break;
+ }
+ };
+ document.addEventListener("keydown", listener);
+ this.goTo(idx);
+ }
+
+ shouldSkip(idx) {
+ return false;
+ }
+
+ goTo(idx) {
+ const allRows = this.panel.getElementsByClassName("line");
+ for (const row of allRows) {
+ if ((row.dataset.idx | 0) === idx) {
+ row.style.backgroundColor = "rgb(251,250,207)";
+ row.scrollIntoView();
+ } else {
+ row.style.backgroundColor = null;
+ }
+ }
+ }
+}
+
+const Stats = (function () {
+ let stats = [];
+ function clear(node) {
+ node.textContent = ""; // Remove any `node` contents from the DOM.
+ }
+ return {
+ // Properties/functions needed by PDFBug.
+ id: "Stats",
+ name: "Stats",
+ panel: null,
+ manager: null,
+ init() {},
+ enabled: false,
+ active: false,
+ // Stats specific functions.
+ add(pageNumber, stat) {
+ if (!stat) {
+ return;
+ }
+ const statsIndex = stats.findIndex(s => s.pageNumber === pageNumber);
+ if (statsIndex !== -1) {
+ stats[statsIndex].div.remove();
+ stats.splice(statsIndex, 1);
+ }
+ const wrapper = document.createElement("div");
+ wrapper.className = "stats";
+ const title = document.createElement("div");
+ title.className = "title";
+ title.textContent = "Page: " + pageNumber;
+ const statsDiv = document.createElement("div");
+ statsDiv.textContent = stat.toString();
+ wrapper.append(title, statsDiv);
+ stats.push({ pageNumber, div: wrapper });
+ stats.sort((a, b) => a.pageNumber - b.pageNumber);
+ clear(this.panel);
+ for (const entry of stats) {
+ this.panel.append(entry.div);
+ }
+ },
+ cleanup() {
+ stats = [];
+ clear(this.panel);
+ },
+ };
+})();
+
+// Manages all the debugging tools.
+class PDFBug {
+ static #buttons = [];
+
+ static #activePanel = null;
+
+ static tools = [FontInspector, StepperManager, Stats];
+
+ static enable(ids) {
+ const all = ids.length === 1 && ids[0] === "all";
+ const tools = this.tools;
+ for (const tool of tools) {
+ if (all || ids.includes(tool.id)) {
+ tool.enabled = true;
+ }
+ }
+ if (!all) {
+ // Sort the tools by the order they are enabled.
+ tools.sort(function (a, b) {
+ let indexA = ids.indexOf(a.id);
+ indexA = indexA < 0 ? tools.length : indexA;
+ let indexB = ids.indexOf(b.id);
+ indexB = indexB < 0 ? tools.length : indexB;
+ return indexA - indexB;
+ });
+ }
+ }
+
+ static init(container, ids) {
+ this.loadCSS();
+ this.enable(ids);
+ /*
+ * Basic Layout:
+ * PDFBug
+ * Controls
+ * Panels
+ * Panel
+ * Panel
+ * ...
+ */
+ const ui = document.createElement("div");
+ ui.id = "PDFBug";
+
+ const controls = document.createElement("div");
+ controls.setAttribute("class", "controls");
+ ui.append(controls);
+
+ const panels = document.createElement("div");
+ panels.setAttribute("class", "panels");
+ ui.append(panels);
+
+ container.append(ui);
+ container.style.right = "var(--panel-width)";
+
+ // Initialize all the debugging tools.
+ for (const tool of this.tools) {
+ const panel = document.createElement("div");
+ const panelButton = document.createElement("button");
+ panelButton.textContent = tool.name;
+ panelButton.addEventListener("click", event => {
+ event.preventDefault();
+ this.selectPanel(tool);
+ });
+ controls.append(panelButton);
+ panels.append(panel);
+ tool.panel = panel;
+ tool.manager = this;
+ if (tool.enabled) {
+ tool.init();
+ } else {
+ panel.textContent =
+ `${tool.name} is disabled. To enable add "${tool.id}" to ` +
+ "the pdfBug parameter and refresh (separate multiple by commas).";
+ }
+ this.#buttons.push(panelButton);
+ }
+ this.selectPanel(0);
+ }
+
+ static loadCSS() {
+ const { url } = import.meta;
+
+ const link = document.createElement("link");
+ link.rel = "stylesheet";
+ link.href = url.replace(/\.mjs$/, ".css");
+
+ document.head.append(link);
+ }
+
+ static cleanup() {
+ for (const tool of this.tools) {
+ if (tool.enabled) {
+ tool.cleanup();
+ }
+ }
+ }
+
+ static selectPanel(index) {
+ if (typeof index !== "number") {
+ index = this.tools.indexOf(index);
+ }
+ if (index === this.#activePanel) {
+ return;
+ }
+ this.#activePanel = index;
+ for (const [j, tool] of this.tools.entries()) {
+ const isActive = j === index;
+ this.#buttons[j].classList.toggle("active", isActive);
+ tool.active = isActive;
+ tool.panel.hidden = !isActive;
+ }
+ }
+}
+
+globalThis.FontInspector = FontInspector;
+globalThis.StepperManager = StepperManager;
+globalThis.Stats = Stats;
+
+export { PDFBug };
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/iccs/CGATS001Compat-v2-micro.icc b/app/web/vendor/pdfjs/6.3.289-app1/web/iccs/CGATS001Compat-v2-micro.icc
new file mode 100644
index 0000000..b5a7349
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/iccs/CGATS001Compat-v2-micro.icc differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/iccs/LICENSE b/app/web/vendor/pdfjs/6.3.289-app1/web/iccs/LICENSE
new file mode 100644
index 0000000..4ee29e0
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/iccs/LICENSE
@@ -0,0 +1,116 @@
+CC0 1.0 Universal
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator and
+subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the
+purpose of contributing to a commons of creative, cultural and scientific
+works ("Commons") that the public can reliably and without fear of later
+claims of infringement build upon, modify, incorporate in other works, reuse
+and redistribute as freely as possible in any form whatsoever and for any
+purposes, including without limitation commercial purposes. These owners may
+contribute to the Commons to promote the ideal of a free culture and the
+further production of creative, cultural and scientific works, or to gain
+reputation or greater distribution for their Work in part through the use and
+efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation
+of additional consideration or compensation, the person associating CC0 with a
+Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
+and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
+and publicly distribute the Work under its terms, with knowledge of his or her
+Copyright and Related Rights in the Work and the meaning and intended legal
+effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not limited
+to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
+ and translate a Work;
+
+ ii. moral rights retained by the original author(s) and/or performer(s);
+
+ iii. publicity and privacy rights pertaining to a person's image or likeness
+ depicted in a Work;
+
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+
+ v. rights protecting the extraction, dissemination, use and reuse of data in
+ a Work;
+
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation thereof,
+ including any amended or successor version of such directive); and
+
+ vii. other similar, equivalent or corresponding rights throughout the world
+ based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of,
+applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
+unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
+and Related Rights and associated claims and causes of action, whether now
+known or unknown (including existing as well as future claims and causes of
+action), in the Work (i) in all territories worldwide, (ii) for the maximum
+duration provided by applicable law or treaty (including future time
+extensions), (iii) in any current or future medium and for any number of
+copies, and (iv) for any purpose whatsoever, including without limitation
+commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
+the Waiver for the benefit of each member of the public at large and to the
+detriment of Affirmer's heirs and successors, fully intending that such Waiver
+shall not be subject to revocation, rescission, cancellation, termination, or
+any other legal or equitable action to disrupt the quiet enjoyment of the Work
+by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be
+judged legally invalid or ineffective under applicable law, then the Waiver
+shall be preserved to the maximum extent permitted taking into account
+Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
+is so judged Affirmer hereby grants to each affected person a royalty-free,
+non transferable, non sublicensable, non exclusive, irrevocable and
+unconditional license to exercise Affirmer's Copyright and Related Rights in
+the Work (i) in all territories worldwide, (ii) for the maximum duration
+provided by applicable law or treaty (including future time extensions), (iii)
+in any current or future medium and for any number of copies, and (iv) for any
+purpose whatsoever, including without limitation commercial, advertising or
+promotional purposes (the "License"). The License shall be deemed effective as
+of the date CC0 was applied by Affirmer to the Work. Should any part of the
+License for any reason be judged legally invalid or ineffective under
+applicable law, such partial invalidity or ineffectiveness shall not
+invalidate the remainder of the License, and in such case Affirmer hereby
+affirms that he or she will not (i) exercise any of his or her remaining
+Copyright and Related Rights in the Work or (ii) assert any associated claims
+and causes of action with respect to the Work, in either case contrary to
+Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+
+ b. Affirmer offers the Work as-is and makes no representations or warranties
+ of any kind concerning the Work, express, implied, statutory or otherwise,
+ including without limitation warranties of title, merchantability, fitness
+ for a particular purpose, non infringement, or the absence of latent or
+ other defects, accuracy, or the present or absence of errors, whether or not
+ discoverable, all to the greatest extent permissible under applicable law.
+
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without limitation
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
+ disclaims responsibility for obtaining any necessary consents, permissions
+ or other rights required for any use of the Work.
+
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to this
+ CC0 or use of the Work.
+
+For more information, please see
+http://creativecommons.org/publicdomain/zero/1.0/
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_add.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_add.svg
new file mode 100644
index 0000000..3451b53
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_add.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_disclaimer.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_disclaimer.svg
new file mode 100644
index 0000000..6fe79e7
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_disclaimer.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_done.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_done.svg
new file mode 100644
index 0000000..f54924e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_done.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_spinner.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_spinner.svg
new file mode 100644
index 0000000..fedb472
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_spinner.svg
@@ -0,0 +1,30 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_warning.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_warning.svg
new file mode 100644
index 0000000..03014ce
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/altText_warning.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-check.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-check.svg
new file mode 100644
index 0000000..71cd16d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-check.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-comment.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-comment.svg
new file mode 100644
index 0000000..86f1f17
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-comment.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-help.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-help.svg
new file mode 100644
index 0000000..00938fe
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-help.svg
@@ -0,0 +1,26 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-insert.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-insert.svg
new file mode 100644
index 0000000..519ef68
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-insert.svg
@@ -0,0 +1,10 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-key.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-key.svg
new file mode 100644
index 0000000..8d09d53
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-key.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-newparagraph.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-newparagraph.svg
new file mode 100644
index 0000000..38d2497
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-newparagraph.svg
@@ -0,0 +1,11 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-noicon.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-noicon.svg
new file mode 100644
index 0000000..c07d108
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-noicon.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-note.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-note.svg
new file mode 100644
index 0000000..7017365
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-note.svg
@@ -0,0 +1,42 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-paperclip.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-paperclip.svg
new file mode 100644
index 0000000..2bed225
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-paperclip.svg
@@ -0,0 +1,6 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-paragraph.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-paragraph.svg
new file mode 100644
index 0000000..6ae5212
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-paragraph.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-pushpin.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-pushpin.svg
new file mode 100644
index 0000000..6e0896c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/annotation-pushpin.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/checkmark.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/checkmark.svg
new file mode 100644
index 0000000..20ba0d2
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/checkmark.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-actionsButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-actionsButton.svg
new file mode 100644
index 0000000..3161438
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-actionsButton.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-closeButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-closeButton.svg
new file mode 100644
index 0000000..6fb5f6a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-closeButton.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-editButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-editButton.svg
new file mode 100644
index 0000000..92b1316
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-editButton.svg
@@ -0,0 +1,8 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-popup-editButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-popup-editButton.svg
new file mode 100644
index 0000000..e497422
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/comment-popup-editButton.svg
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorFreeHighlight.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorFreeHighlight.svg
new file mode 100644
index 0000000..513f6bd
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorFreeHighlight.svg
@@ -0,0 +1,6 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorFreeText.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorFreeText.svg
new file mode 100644
index 0000000..de2838e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorFreeText.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorInk.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorInk.svg
new file mode 100644
index 0000000..1dadb5c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorInk.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorTextHighlight.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorTextHighlight.svg
new file mode 100644
index 0000000..800340c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/cursor-editorTextHighlight.svg
@@ -0,0 +1,8 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/editor-toolbar-delete.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/editor-toolbar-delete.svg
new file mode 100644
index 0000000..f84520d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/editor-toolbar-delete.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/editor-toolbar-edit.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/editor-toolbar-edit.svg
new file mode 100644
index 0000000..692de38
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/editor-toolbar-edit.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/findbarButton-next.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/findbarButton-next.svg
new file mode 100644
index 0000000..8cb39be
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/findbarButton-next.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/findbarButton-previous.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/findbarButton-previous.svg
new file mode 100644
index 0000000..b610879
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/findbarButton-previous.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/gv-toolbarButton-download.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/gv-toolbarButton-download.svg
new file mode 100644
index 0000000..d56cf3c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/gv-toolbarButton-download.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/loading-icon.gif b/app/web/vendor/pdfjs/6.3.289-app1/web/images/loading-icon.gif
new file mode 100644
index 0000000..1c72ebb
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/images/loading-icon.gif differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/loading.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/loading.svg
new file mode 100644
index 0000000..0a15ff6
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/loading.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_closingButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_closingButton.svg
new file mode 100644
index 0000000..8a40715
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_closingButton.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_info.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_info.svg
new file mode 100644
index 0000000..b12b6be
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_info.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_warning.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_warning.svg
new file mode 100644
index 0000000..011cfcf
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/messageBar_warning.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_closeButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_closeButton.svg
new file mode 100644
index 0000000..92fc5ec
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_closeButton.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_selected.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_selected.svg
new file mode 100644
index 0000000..32c4816
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_selected.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_viewArrow.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_viewArrow.svg
new file mode 100644
index 0000000..a4932d4
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_viewArrow.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_viewButton.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_viewButton.svg
new file mode 100644
index 0000000..24c518d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/pages_viewButton.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-documentProperties.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-documentProperties.svg
new file mode 100644
index 0000000..dd3917b
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-documentProperties.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-firstPage.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-firstPage.svg
new file mode 100644
index 0000000..f5c917f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-firstPage.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-handTool.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-handTool.svg
new file mode 100644
index 0000000..b7073b5
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-handTool.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-lastPage.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-lastPage.svg
new file mode 100644
index 0000000..c04f650
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-lastPage.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-rotateCcw.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-rotateCcw.svg
new file mode 100644
index 0000000..da73a1b
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-rotateCcw.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-rotateCw.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-rotateCw.svg
new file mode 100644
index 0000000..c41ce73
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-rotateCw.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollHorizontal.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollHorizontal.svg
new file mode 100644
index 0000000..fb440b9
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollHorizontal.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollPage.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollPage.svg
new file mode 100644
index 0000000..64a9f50
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollPage.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollVertical.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollVertical.svg
new file mode 100644
index 0000000..dc7e805
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollVertical.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollWrapped.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollWrapped.svg
new file mode 100644
index 0000000..75fe26b
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-scrollWrapped.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-selectTool.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-selectTool.svg
new file mode 100644
index 0000000..94d5141
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-selectTool.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadEven.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadEven.svg
new file mode 100644
index 0000000..ce201e3
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadEven.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadNone.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadNone.svg
new file mode 100644
index 0000000..e8d487f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadNone.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadOdd.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadOdd.svg
new file mode 100644
index 0000000..9211a42
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/secondaryToolbarButton-spreadOdd.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/signature-properties-row-check.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/signature-properties-row-check.svg
new file mode 100644
index 0000000..f40d830
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/signature-properties-row-check.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-bookmark.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-bookmark.svg
new file mode 100644
index 0000000..c4c37c9
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-bookmark.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-currentOutlineItem.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-currentOutlineItem.svg
new file mode 100644
index 0000000..01e6762
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-currentOutlineItem.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-download.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-download.svg
new file mode 100644
index 0000000..e2e850a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-download.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorFreeText.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorFreeText.svg
new file mode 100644
index 0000000..13a67bd
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorFreeText.svg
@@ -0,0 +1,5 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorHighlight.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorHighlight.svg
new file mode 100644
index 0000000..b3cd7fd
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorHighlight.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorInk.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorInk.svg
new file mode 100644
index 0000000..b579eec
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorInk.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorSignature.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorSignature.svg
new file mode 100644
index 0000000..0b4e904
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorSignature.svg
@@ -0,0 +1,6 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorStamp.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorStamp.svg
new file mode 100644
index 0000000..a1fef49
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-editorStamp.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-menuArrow.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-menuArrow.svg
new file mode 100644
index 0000000..82ffeaa
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-menuArrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-menuArrowNova.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-menuArrowNova.svg
new file mode 100644
index 0000000..f5c8020
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-menuArrowNova.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-openFile.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-openFile.svg
new file mode 100644
index 0000000..e773781
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-openFile.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-pageDown.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-pageDown.svg
new file mode 100644
index 0000000..1fc12e7
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-pageDown.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-pageUp.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-pageUp.svg
new file mode 100644
index 0000000..0936b9a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-pageUp.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-presentationMode.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-presentationMode.svg
new file mode 100644
index 0000000..901d567
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-presentationMode.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-print.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-print.svg
new file mode 100644
index 0000000..97a3904
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-print.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-search.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-search.svg
new file mode 100644
index 0000000..0cc7ae2
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-search.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-secondaryToolbarToggle.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-secondaryToolbarToggle.svg
new file mode 100644
index 0000000..cace863
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-secondaryToolbarToggle.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-signaturePropertiesError.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-signaturePropertiesError.svg
new file mode 100644
index 0000000..43a8b41
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-signaturePropertiesError.svg
@@ -0,0 +1,7 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-signaturePropertiesVerified.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-signaturePropertiesVerified.svg
new file mode 100644
index 0000000..e294c6c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-signaturePropertiesVerified.svg
@@ -0,0 +1,7 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewAttachments.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewAttachments.svg
new file mode 100644
index 0000000..ab73f6e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewAttachments.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewLayers.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewLayers.svg
new file mode 100644
index 0000000..1d72668
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewLayers.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewOutline.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewOutline.svg
new file mode 100644
index 0000000..7ed1bd9
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewOutline.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewThumbnail.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewThumbnail.svg
new file mode 100644
index 0000000..040d123
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewThumbnail.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewsManagerToggle.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewsManagerToggle.svg
new file mode 100644
index 0000000..1d8d0e4
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-viewsManagerToggle.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-zoomIn.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-zoomIn.svg
new file mode 100644
index 0000000..30ec51a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-zoomIn.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-zoomOut.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-zoomOut.svg
new file mode 100644
index 0000000..f273b59
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/toolbarButton-zoomOut.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/treeitem-collapsed.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/treeitem-collapsed.svg
new file mode 100644
index 0000000..831cddf
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/treeitem-collapsed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/images/treeitem-expanded.svg b/app/web/vendor/pdfjs/6.3.289-app1/web/images/treeitem-expanded.svg
new file mode 100644
index 0000000..2d45f0c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/images/treeitem-expanded.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ach/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ach/viewer.ftl
new file mode 100644
index 0000000..8f10145
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ach/viewer.ftl
@@ -0,0 +1,200 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pot buk mukato
+pdfjs-previous-button-label = Mukato
+pdfjs-next-button =
+ .title = Pot buk malubo
+pdfjs-next-button-label = Malubo
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pot buk
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = pi { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } me { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Jwik Matidi
+pdfjs-zoom-out-button-label = Jwik Matidi
+pdfjs-zoom-in-button =
+ .title = Kwot Madit
+pdfjs-zoom-in-button-label = Kwot Madit
+pdfjs-zoom-select =
+ .title = Kwoti
+pdfjs-presentation-mode-button =
+ .title = Lokke i kit me tyer
+pdfjs-presentation-mode-button-label = Kit me tyer
+pdfjs-open-file-button =
+ .title = Yab Pwail
+pdfjs-open-file-button-label = Yab
+pdfjs-print-button =
+ .title = Go
+pdfjs-print-button-label = Go
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Gintic
+pdfjs-tools-button-label = Gintic
+pdfjs-first-page-button =
+ .title = Cit i pot buk mukwongo
+pdfjs-first-page-button-label = Cit i pot buk mukwongo
+pdfjs-last-page-button =
+ .title = Cit i pot buk magiko
+pdfjs-last-page-button-label = Cit i pot buk magiko
+pdfjs-page-rotate-cw-button =
+ .title = Wire i tung lacuc
+pdfjs-page-rotate-cw-button-label = Wire i tung lacuc
+pdfjs-page-rotate-ccw-button =
+ .title = Wire i tung lacam
+pdfjs-page-rotate-ccw-button-label = Wire i tung lacam
+pdfjs-cursor-text-select-tool-button =
+ .title = Cak gitic me yero coc
+pdfjs-cursor-text-select-tool-button-label = Gitic me yero coc
+pdfjs-cursor-hand-tool-button =
+ .title = Cak gitic me cing
+pdfjs-cursor-hand-tool-button-label = Gitic cing
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Jami me gin acoya…
+pdfjs-document-properties-button-label = Jami me gin acoya…
+pdfjs-document-properties-file-name = Nying pwail:
+pdfjs-document-properties-file-size = Dit pa pwail:
+pdfjs-document-properties-title = Wiye:
+pdfjs-document-properties-author = Ngat mucoyo:
+pdfjs-document-properties-subject = Subjek:
+pdfjs-document-properties-keywords = Lok mapire tek:
+pdfjs-document-properties-creation-date = Nino dwe me cwec:
+pdfjs-document-properties-modification-date = Nino dwe me yub:
+pdfjs-document-properties-creator = Lacwec:
+pdfjs-document-properties-producer = Layub PDF:
+pdfjs-document-properties-version = Kit PDF:
+pdfjs-document-properties-page-count = Kwan me pot buk:
+pdfjs-document-properties-page-size = Dit pa potbuk:
+pdfjs-document-properties-page-size-unit-inches = i
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = atir
+pdfjs-document-properties-page-size-orientation-landscape = arii
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Waraga
+pdfjs-document-properties-page-size-name-legal = Cik
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-linearized-yes = Eyo
+pdfjs-document-properties-linearized-no = Pe
+pdfjs-document-properties-close-button = Lor
+
+## Print
+
+pdfjs-print-progress-message = Yubo coc me agoya…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Juki
+pdfjs-printing-not-supported = Ciko: Layeny ma pe teno goyo liweng.
+pdfjs-printing-not-ready = Ciko: PDF pe ocane weng me agoya.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Lok gintic ma inget
+pdfjs-toggle-sidebar-button-label = Lok gintic ma inget
+pdfjs-document-outline-button =
+ .title = Nyut Wiyewiye me Gin acoya (dii-kiryo me yaro/kano jami weng)
+pdfjs-document-outline-button-label = Pek pa gin acoya
+pdfjs-attachments-button =
+ .title = Nyut twec
+pdfjs-attachments-button-label = Twec
+pdfjs-thumbs-button =
+ .title = Nyut cal
+pdfjs-thumbs-button-label = Cal
+pdfjs-findbar-button =
+ .title = Nong iye gin acoya
+pdfjs-findbar-button-label = Nong
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pot buk { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Cal me pot buk { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Nong
+ .placeholder = Nong i dokumen…
+pdfjs-find-previous-button =
+ .title = Nong timme pa lok mukato
+pdfjs-find-previous-button-label = Mukato
+pdfjs-find-next-button =
+ .title = Nong timme pa lok malubo
+pdfjs-find-next-button-label = Malubo
+pdfjs-find-highlight-checkbox = Ket Lanyut I Weng
+pdfjs-find-match-case-checkbox-label = Lok marwate
+pdfjs-find-reached-top = Oo iwi gin acoya, omede ki i tere
+pdfjs-find-reached-bottom = Oo i agiki me gin acoya, omede ki iwiye
+pdfjs-find-not-found = Lok pe ononge
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lac me iye pot buk
+pdfjs-page-scale-fit = Porre me pot buk
+pdfjs-page-scale-auto = Kwot pire kene
+pdfjs-page-scale-actual = Dite kikome
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Bal otime kun cano PDF.
+pdfjs-invalid-file-error = Pwail me PDF ma pe atir onyo obale woko.
+pdfjs-missing-file-error = Pwail me PDF tye ka rem.
+pdfjs-unexpected-response-error = Lagam mape kigeno pa lapok tic.
+pdfjs-rendering-error = Bal otime i kare me nyuto pot buk.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Lok angea manok]
+
+## Password
+
+pdfjs-password-label = Ket mung me donyo me yabo pwail me PDF man.
+pdfjs-password-invalid = Mung me donyo pe atir. Tim ber i tem doki.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Juki
+pdfjs-web-fonts-disabled = Kijuko dit pa coc me kakube woko: pe romo tic ki dit pa coc me PDF ma kiketo i kine.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/af/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/af/viewer.ftl
new file mode 100644
index 0000000..577888c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/af/viewer.ftl
@@ -0,0 +1,179 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Vorige bladsy
+pdfjs-previous-button-label = Vorige
+pdfjs-next-button =
+ .title = Volgende bladsy
+pdfjs-next-button-label = Volgende
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Bladsy
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = van { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } van { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoem uit
+pdfjs-zoom-out-button-label = Zoem uit
+pdfjs-zoom-in-button =
+ .title = Zoem in
+pdfjs-zoom-in-button-label = Zoem in
+pdfjs-zoom-select =
+ .title = Zoem
+pdfjs-presentation-mode-button =
+ .title = Wissel na voorleggingsmodus
+pdfjs-presentation-mode-button-label = Voorleggingsmodus
+pdfjs-open-file-button =
+ .title = Open lêer
+pdfjs-open-file-button-label = Open
+pdfjs-print-button =
+ .title = Druk
+pdfjs-print-button-label = Druk
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Nutsgoed
+pdfjs-tools-button-label = Nutsgoed
+pdfjs-first-page-button =
+ .title = Gaan na eerste bladsy
+pdfjs-first-page-button-label = Gaan na eerste bladsy
+pdfjs-last-page-button =
+ .title = Gaan na laaste bladsy
+pdfjs-last-page-button-label = Gaan na laaste bladsy
+pdfjs-page-rotate-cw-button =
+ .title = Roteer kloksgewys
+pdfjs-page-rotate-cw-button-label = Roteer kloksgewys
+pdfjs-page-rotate-ccw-button =
+ .title = Roteer anti-kloksgewys
+pdfjs-page-rotate-ccw-button-label = Roteer anti-kloksgewys
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktiveer gereedskap om teks te merk
+pdfjs-cursor-text-select-tool-button-label = Teksmerkgereedskap
+pdfjs-cursor-hand-tool-button =
+ .title = Aktiveer handjie
+pdfjs-cursor-hand-tool-button-label = Handjie
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumenteienskappe…
+pdfjs-document-properties-button-label = Dokumenteienskappe…
+pdfjs-document-properties-file-name = Lêernaam:
+pdfjs-document-properties-file-size = Lêergrootte:
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Outeur:
+pdfjs-document-properties-subject = Onderwerp:
+pdfjs-document-properties-keywords = Sleutelwoorde:
+pdfjs-document-properties-creation-date = Skeppingsdatum:
+pdfjs-document-properties-modification-date = Wysigingsdatum:
+pdfjs-document-properties-creator = Skepper:
+pdfjs-document-properties-producer = PDF-vervaardiger:
+pdfjs-document-properties-version = PDF-weergawe:
+pdfjs-document-properties-page-count = Aantal bladsye:
+
+##
+
+pdfjs-document-properties-close-button = Sluit
+
+## Print
+
+pdfjs-print-progress-message = Berei tans dokument voor om te druk…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Kanselleer
+pdfjs-printing-not-supported = Waarskuwing: Dié blaaier ondersteun nie drukwerk ten volle nie.
+pdfjs-printing-not-ready = Waarskuwing: Die PDF is nog nie volledig gelaai vir drukwerk nie.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Sypaneel aan/af
+pdfjs-toggle-sidebar-button-label = Sypaneel aan/af
+pdfjs-document-outline-button =
+ .title = Wys dokumentskema (dubbelklik om alle items oop/toe te vou)
+pdfjs-document-outline-button-label = Dokumentoorsig
+pdfjs-attachments-button =
+ .title = Wys aanhegsels
+pdfjs-attachments-button-label = Aanhegsels
+pdfjs-thumbs-button =
+ .title = Wys duimnaels
+pdfjs-thumbs-button-label = Duimnaels
+pdfjs-findbar-button =
+ .title = Soek in dokument
+pdfjs-findbar-button-label = Vind
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Bladsy { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Duimnael van bladsy { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Vind
+ .placeholder = Soek in dokument…
+pdfjs-find-previous-button =
+ .title = Vind die vorige voorkoms van die frase
+pdfjs-find-previous-button-label = Vorige
+pdfjs-find-next-button =
+ .title = Vind die volgende voorkoms van die frase
+pdfjs-find-next-button-label = Volgende
+pdfjs-find-highlight-checkbox = Verlig almal
+pdfjs-find-match-case-checkbox-label = Kassensitief
+pdfjs-find-reached-top = Bokant van dokument is bereik; gaan voort van onder af
+pdfjs-find-reached-bottom = Einde van dokument is bereik; gaan voort van bo af
+pdfjs-find-not-found = Frase nie gevind nie
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Bladsywydte
+pdfjs-page-scale-fit = Pas bladsy
+pdfjs-page-scale-auto = Outomatiese zoem
+pdfjs-page-scale-actual = Werklike grootte
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = 'n Fout het voorgekom met die laai van die PDF.
+pdfjs-invalid-file-error = Ongeldige of korrupte PDF-lêer.
+pdfjs-missing-file-error = PDF-lêer is weg.
+pdfjs-unexpected-response-error = Onverwagse antwoord van bediener.
+pdfjs-rendering-error = 'n Fout het voorgekom toe die bladsy weergegee is.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }-annotasie]
+
+## Password
+
+pdfjs-password-label = Gee die wagwoord om dié PDF-lêer mee te open.
+pdfjs-password-invalid = Ongeldige wagwoord. Probeer gerus weer.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Kanselleer
+pdfjs-web-fonts-disabled = Webfonte is gedeaktiveer: kan nie PDF-fonte wat ingebed is, gebruik nie.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/an/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/an/viewer.ftl
new file mode 100644
index 0000000..ad5d2fe
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/an/viewer.ftl
@@ -0,0 +1,228 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pachina anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Pachina siguient
+pdfjs-next-button-label = Siguient
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pachina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Achiquir
+pdfjs-zoom-out-button-label = Achiquir
+pdfjs-zoom-in-button =
+ .title = Agrandir
+pdfjs-zoom-in-button-label = Agrandir
+pdfjs-zoom-select =
+ .title = Grandaria
+pdfjs-presentation-mode-button =
+ .title = Cambear t'o modo de presentación
+pdfjs-presentation-mode-button-label = Modo de presentación
+pdfjs-open-file-button =
+ .title = Ubrir o fichero
+pdfjs-open-file-button-label = Ubrir
+pdfjs-print-button =
+ .title = Imprentar
+pdfjs-print-button-label = Imprentar
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ferramientas
+pdfjs-tools-button-label = Ferramientas
+pdfjs-first-page-button =
+ .title = Ir ta la primer pachina
+pdfjs-first-page-button-label = Ir ta la primer pachina
+pdfjs-last-page-button =
+ .title = Ir ta la zaguer pachina
+pdfjs-last-page-button-label = Ir ta la zaguer pachina
+pdfjs-page-rotate-cw-button =
+ .title = Chirar enta la dreita
+pdfjs-page-rotate-cw-button-label = Chira enta la dreita
+pdfjs-page-rotate-ccw-button =
+ .title = Chirar enta la zurda
+pdfjs-page-rotate-ccw-button-label = Chirar enta la zurda
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar la ferramienta de selección de texto
+pdfjs-cursor-text-select-tool-button-label = Ferramienta de selección de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Activar la ferramienta man
+pdfjs-cursor-hand-tool-button-label = Ferramienta man
+pdfjs-scroll-vertical-button =
+ .title = Usar lo desplazamiento vertical
+pdfjs-scroll-vertical-button-label = Desplazamiento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar lo desplazamiento horizontal
+pdfjs-scroll-horizontal-button-label = Desplazamiento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Activaar lo desplazamiento contino
+pdfjs-scroll-wrapped-button-label = Desplazamiento contino
+pdfjs-spread-none-button =
+ .title = No unir vistas de pachinas
+pdfjs-spread-none-button-label = Una pachina nomás
+pdfjs-spread-odd-button =
+ .title = Mostrar vista de pachinas, con as impars a la zurda
+pdfjs-spread-odd-button-label = Doble pachina, impar a la zurda
+pdfjs-spread-even-button =
+ .title = Amostrar vista de pachinas, con as pars a la zurda
+pdfjs-spread-even-button-label = Doble pachina, para a la zurda
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedatz d'o documento...
+pdfjs-document-properties-button-label = Propiedatz d'o documento...
+pdfjs-document-properties-file-name = Nombre de fichero:
+pdfjs-document-properties-file-size = Grandaria d'o fichero:
+pdfjs-document-properties-title = Titol:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Afer:
+pdfjs-document-properties-keywords = Parolas clau:
+pdfjs-document-properties-creation-date = Calendata de creyación:
+pdfjs-document-properties-modification-date = Calendata de modificación:
+pdfjs-document-properties-creator = Creyador:
+pdfjs-document-properties-producer = Creyador de PDF:
+pdfjs-document-properties-version = Versión de PDF:
+pdfjs-document-properties-page-count = Numero de pachinas:
+pdfjs-document-properties-page-size = Mida de pachina:
+pdfjs-document-properties-page-size-unit-inches = pulgadas
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } x { $height } { $unit } { $orientation }
+pdfjs-document-properties-page-size-dimension-name-string = { $width } x { $height } { $unit } { $name }, { $orientation }
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista web rapida:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Zarrar
+
+## Print
+
+pdfjs-print-progress-message = Se ye preparando la documentación pa imprentar…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Pare cuenta: Iste navegador no maneya totalment as impresions.
+pdfjs-printing-not-ready = Aviso: Encara no se ha cargau completament o PDF ta imprentar-lo.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Amostrar u amagar a barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Cambiar barra lateral (lo documento contiene esquema/adchuntos/capas)
+pdfjs-toggle-sidebar-button-label = Amostrar a barra lateral
+pdfjs-document-outline-button =
+ .title = Amostrar esquema d'o documento (fer doble clic pa expandir/compactar totz los items)
+pdfjs-document-outline-button-label = Esquema d'o documento
+pdfjs-attachments-button =
+ .title = Amostrar os adchuntos
+pdfjs-attachments-button-label = Adchuntos
+pdfjs-layers-button =
+ .title = Amostrar capas (doble clic para reiniciar totas las capas a lo estau per defecto)
+pdfjs-layers-button-label = Capas
+pdfjs-thumbs-button =
+ .title = Amostrar as miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-findbar-button =
+ .title = Trobar en o documento
+pdfjs-findbar-button-label = Trobar
+pdfjs-additional-layers = Capas adicionals
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pachina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura d'a pachina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Trobar
+ .placeholder = Trobar en o documento…
+pdfjs-find-previous-button =
+ .title = Trobar l'anterior coincidencia d'a frase
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Trobar a siguient coincidencia d'a frase
+pdfjs-find-next-button-label = Siguient
+pdfjs-find-highlight-checkbox = Resaltar-lo tot
+pdfjs-find-match-case-checkbox-label = Coincidencia de mayusclas/minusclas
+pdfjs-find-entire-word-checkbox-label = Parolas completas
+pdfjs-find-reached-top = S'ha plegau a l'inicio d'o documento, se contina dende baixo
+pdfjs-find-reached-bottom = S'ha plegau a la fin d'o documento, se contina dende alto
+pdfjs-find-not-found = No s'ha trobau a frase
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Amplaria d'a pachina
+pdfjs-page-scale-fit = Achuste d'a pachina
+pdfjs-page-scale-auto = Grandaria automatica
+pdfjs-page-scale-actual = Grandaria actual
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = S'ha produciu una error en cargar o PDF.
+pdfjs-invalid-file-error = O PDF no ye valido u ye estorbau.
+pdfjs-missing-file-error = No i ha fichero PDF.
+pdfjs-unexpected-response-error = Respuesta a lo servicio inasperada.
+pdfjs-rendering-error = Ha ocurriu una error en renderizar a pachina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotación { $type }]
+
+## Password
+
+pdfjs-password-label = Introduzca a clau ta ubrir iste fichero PDF.
+pdfjs-password-invalid = Clau invalida. Torna a intentar-lo.
+pdfjs-password-ok-button = Acceptar
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = As fuents web son desactivadas: no se puet incrustar fichers PDF.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ar/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ar/viewer.ftl
new file mode 100644
index 0000000..9d60944
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ar/viewer.ftl
@@ -0,0 +1,835 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = الصفحة السابقة
+pdfjs-previous-button-label = السابقة
+pdfjs-next-button =
+ .title = الصفحة التالية
+pdfjs-next-button-label = التالية
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = صفحة
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = من { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } من { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = بعّد
+pdfjs-zoom-out-button-label = بعّد
+pdfjs-zoom-in-button =
+ .title = قرّب
+pdfjs-zoom-in-button-label = قرّب
+pdfjs-zoom-select =
+ .title = التقريب
+pdfjs-presentation-mode-button =
+ .title = انتقل لوضع العرض التقديمي
+pdfjs-presentation-mode-button-label = وضع العرض التقديمي
+pdfjs-open-file-button =
+ .title = افتح ملفًا
+pdfjs-open-file-button-label = افتح
+pdfjs-print-button =
+ .title = اطبع
+pdfjs-print-button-label = اطبع
+pdfjs-save-button =
+ .title = احفظ
+pdfjs-save-button-label = احفظ
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = نزّل
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = نزّل
+pdfjs-bookmark-button =
+ .title = الصفحة الحالية (عرض URL من الصفحة الحالية)
+pdfjs-bookmark-button-label = الصفحة الحالية
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = الأدوات
+pdfjs-tools-button-label = الأدوات
+pdfjs-first-page-button =
+ .title = انتقل إلى الصفحة الأولى
+pdfjs-first-page-button-label = انتقل إلى الصفحة الأولى
+pdfjs-last-page-button =
+ .title = انتقل إلى الصفحة الأخيرة
+pdfjs-last-page-button-label = انتقل إلى الصفحة الأخيرة
+pdfjs-page-rotate-cw-button =
+ .title = أدر باتجاه عقارب الساعة
+pdfjs-page-rotate-cw-button-label = أدر باتجاه عقارب الساعة
+pdfjs-page-rotate-ccw-button =
+ .title = أدر بعكس اتجاه عقارب الساعة
+pdfjs-page-rotate-ccw-button-label = أدر بعكس اتجاه عقارب الساعة
+pdfjs-cursor-text-select-tool-button =
+ .title = فعّل أداة اختيار النص
+pdfjs-cursor-text-select-tool-button-label = أداة اختيار النص
+pdfjs-cursor-hand-tool-button =
+ .title = فعّل أداة اليد
+pdfjs-cursor-hand-tool-button-label = أداة اليد
+pdfjs-scroll-page-button =
+ .title = استخدم تمرير الصفحة
+pdfjs-scroll-page-button-label = تمرير الصفحة
+pdfjs-scroll-vertical-button =
+ .title = استخدم التمرير الرأسي
+pdfjs-scroll-vertical-button-label = التمرير الرأسي
+pdfjs-scroll-horizontal-button =
+ .title = استخدم التمرير الأفقي
+pdfjs-scroll-horizontal-button-label = التمرير الأفقي
+pdfjs-scroll-wrapped-button =
+ .title = استخدم التمرير الملتف
+pdfjs-scroll-wrapped-button-label = التمرير الملتف
+pdfjs-spread-none-button =
+ .title = لا تدمج هوامش الصفحات مع بعضها البعض
+pdfjs-spread-none-button-label = بلا هوامش
+pdfjs-spread-odd-button =
+ .title = ادمج هوامش الصفحات الفردية
+pdfjs-spread-odd-button-label = هوامش الصفحات الفردية
+pdfjs-spread-even-button =
+ .title = ادمج هوامش الصفحات الزوجية
+pdfjs-spread-even-button-label = هوامش الصفحات الزوجية
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = خصائص المستند…
+pdfjs-document-properties-button-label = خصائص المستند…
+pdfjs-document-properties-file-name = اسم الملف:
+pdfjs-document-properties-file-size = حجم الملف:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } ك.بايت ({ $b } بايتات)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } م.بايت ({ $b } بايتات)
+pdfjs-document-properties-title = العنوان:
+pdfjs-document-properties-author = المؤلف:
+pdfjs-document-properties-subject = الموضوع:
+pdfjs-document-properties-keywords = الكلمات الأساسية:
+pdfjs-document-properties-creation-date = تاريخ الإنشاء:
+pdfjs-document-properties-modification-date = تاريخ التعديل:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = المُنشئ:
+pdfjs-document-properties-producer = منتج PDF:
+pdfjs-document-properties-version = إصدارة PDF:
+pdfjs-document-properties-page-count = عدد الصفحات:
+pdfjs-document-properties-page-size = مقاس الورقة:
+pdfjs-document-properties-page-size-unit-inches = بوصة
+pdfjs-document-properties-page-size-unit-millimeters = ملم
+pdfjs-document-properties-page-size-orientation-portrait = طوليّ
+pdfjs-document-properties-page-size-orientation-landscape = عرضيّ
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = خطاب
+pdfjs-document-properties-page-size-name-legal = قانونيّ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }، { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = العرض السريع عبر الوِب:
+pdfjs-document-properties-linearized-yes = نعم
+pdfjs-document-properties-linearized-no = لا
+pdfjs-document-properties-close-button = أغلق
+pdfjs-digital-signature-properties-view-certificate = اعرض الشهادة
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = السبب: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = الطابع الزمني: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Print
+
+pdfjs-print-progress-message = يُحضّر المستند للطباعة…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }٪
+pdfjs-print-progress-close-button = ألغِ
+pdfjs-printing-not-supported = تحذير: لا يدعم هذا المتصفح الطباعة بشكل كامل.
+pdfjs-printing-not-ready = تحذير: ملف PDF لم يُحمّل كاملًا للطباعة.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = بدّل ظهور الشريط الجانبي
+pdfjs-toggle-sidebar-notification-button =
+ .title = بدّل ظهور الشريط الجانبي (يحتوي المستند على مخطط أو مرفقات أو طبقات)
+pdfjs-toggle-sidebar-button-label = بدّل ظهور الشريط الجانبي
+pdfjs-document-outline-button =
+ .title = اعرض فهرس المستند (نقر مزدوج لتمديد أو تقليص كل العناصر)
+pdfjs-document-outline-button-label = مخطط المستند
+pdfjs-attachments-button =
+ .title = اعرض المرفقات
+pdfjs-attachments-button-label = المُرفقات
+pdfjs-layers-button =
+ .title = اعرض الطبقات (انقر مرتين لتصفير كل الطبقات إلى الحالة المبدئية)
+pdfjs-layers-button-label = الطبقات
+pdfjs-thumbs-button =
+ .title = اعرض مُصغرات
+pdfjs-thumbs-button-label = مُصغّرات
+pdfjs-current-outline-item-button =
+ .title = ابحث عن عنصر المخطّط التفصيلي الحالي
+pdfjs-current-outline-item-button-label = عنصر المخطّط التفصيلي الحالي
+pdfjs-findbar-button =
+ .title = ابحث في المستند
+pdfjs-findbar-button-label = ابحث
+pdfjs-additional-layers = الطبقات الإضافية
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = صفحة { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = مصغّرة صفحة { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = حدّد الصفحة { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = الصفحة { $page } من { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ابحث
+ .placeholder = ابحث في المستند…
+pdfjs-find-previous-button =
+ .title = ابحث عن التّواجد السّابق للعبارة
+pdfjs-find-previous-button-label = السابق
+pdfjs-find-next-button =
+ .title = ابحث عن التّواجد التّالي للعبارة
+pdfjs-find-next-button-label = التالي
+pdfjs-find-highlight-checkbox = أبرِز الكل
+pdfjs-find-match-case-checkbox-label = طابق حالة الأحرف
+pdfjs-find-match-diacritics-checkbox-label = طابِق التشكيل
+pdfjs-find-entire-word-checkbox-label = كلمات كاملة
+pdfjs-find-reached-top = تابعت من الأسفل بعدما وصلت إلى بداية المستند
+pdfjs-find-reached-bottom = تابعت من الأعلى بعدما وصلت إلى نهاية المستند
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [zero] لا مطابقة
+ [one] { $current } من أصل { $total } مطابقة
+ [two] { $current } من أصل { $total } مطابقة
+ [few] { $current } من أصل { $total } مطابقة
+ [many] { $current } من أصل { $total } مطابقة
+ *[other] { $current } من أصل { $total } مطابقة
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [zero] { $limit } مطابقة
+ [one] أكثر من { $limit } مطابقة
+ [two] أكثر من { $limit } مطابقة
+ [few] أكثر من { $limit } مطابقة
+ [many] أكثر من { $limit } مطابقة
+ *[other] أكثر من { $limit } مطابقات
+ }
+pdfjs-find-not-found = لا وجود للعبارة
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = عرض الصفحة
+pdfjs-page-scale-fit = ملائمة الصفحة
+pdfjs-page-scale-auto = تقريب تلقائي
+pdfjs-page-scale-actual = الحجم الفعلي
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }٪
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = صفحة { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = حدث عطل أثناء تحميل ملف PDF.
+pdfjs-invalid-file-error = ملف PDF تالف أو غير صحيح.
+pdfjs-missing-file-error = ملف PDF غير موجود.
+pdfjs-unexpected-response-error = استجابة خادوم غير متوقعة.
+pdfjs-rendering-error = حدث خطأ أثناء عرض الصفحة.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [تعليق { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = أدخل لكلمة السر لفتح هذا الملف.
+pdfjs-password-invalid = كلمة سر خطأ. من فضلك أعد المحاولة.
+pdfjs-password-ok-button = حسنًا
+pdfjs-password-cancel-button = ألغِ
+pdfjs-web-fonts-disabled = خطوط الوب مُعطّلة: تعذّر استخدام خطوط PDF المُضمّنة.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = نص
+pdfjs-editor-color-picker-free-text-input =
+ .title = غيِّر لون النص
+pdfjs-editor-free-text-button-label = نص
+pdfjs-editor-ink-button =
+ .title = ارسم
+pdfjs-editor-color-picker-ink-input =
+ .title = غيِّر لون الرسم
+pdfjs-editor-ink-button-label = ارسم
+pdfjs-editor-stamp-button =
+ .title = أضِف أو حرّر الصور
+pdfjs-editor-stamp-button-label = أضِف أو حرّر الصور
+pdfjs-editor-highlight-button =
+ .title = أبرِز
+pdfjs-editor-highlight-button-label = أبرِز
+pdfjs-highlight-floating-button1 =
+ .title = أبرِز
+ .aria-label = أبرِز
+pdfjs-highlight-floating-button-label = أبرِز
+pdfjs-comment-floating-button =
+ .title = علق
+ .aria-label = علق
+pdfjs-comment-floating-button-label = علق
+pdfjs-editor-comment-button =
+ .title = علق
+ .aria-label = علق
+pdfjs-editor-comment-button-label = التعليق
+pdfjs-editor-signature-button =
+ .title = أضِف توقيع
+pdfjs-editor-signature-button-label = أضِف توقيع
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = محرِّر الإبراز
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = محرِّر الرسم
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = محرِّر التوقيع: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = محرِّر الصور
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = أزِل الرسم
+pdfjs-editor-remove-freetext-button =
+ .title = أزِل النص
+pdfjs-editor-remove-stamp-button =
+ .title = أزِل الصورة
+pdfjs-editor-remove-highlight-button =
+ .title = أزِل الإبراز
+pdfjs-editor-remove-signature-button =
+ .title = أزِل التوقيع
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = اللون
+pdfjs-editor-free-text-size-input = الحجم
+pdfjs-editor-ink-color-input = اللون
+pdfjs-editor-ink-thickness-input = السماكة
+pdfjs-editor-ink-opacity-input = العتامة
+pdfjs-editor-stamp-add-image-button =
+ .title = أضِف صورة
+pdfjs-editor-stamp-add-image-button-label = أضِف صورة
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = السماكة
+pdfjs-editor-free-highlight-thickness-title =
+ .title = غيّر السُمك عند إبراز عناصر أُخرى غير النص
+pdfjs-editor-add-signature-container =
+ .aria-label = عناصر التحكم في التوقيع والتوقيعات المحفوظة
+pdfjs-editor-signature-add-signature-button =
+ .title = أضِف توقيع جديد
+pdfjs-editor-signature-add-signature-button-label = أضِف توقيع جديد
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = التوقيع المحفوظ: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = محرِّر النص
+ .default-content = ابدأ في كتابة…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [zero] تعليق
+ [one] تعليق
+ [two] تعليقات
+ [few] تعليقات
+ [many] تعليقات
+ *[other] تعليقات
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = أغلِق الشريط الجانبي
+ .aria-label = أغلِق الشريط الجانبي
+pdfjs-editor-comments-sidebar-close-button-label = أغلِق الشريط الجانبي
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = هل رأيت شيئاً جديرًا بالملاحظة؟ ابرزه واترك تعليقًا.
+pdfjs-editor-comments-sidebar-no-comments-link = اطّلع على المزيد
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = نص بديل
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = حرّر النص البديل
+pdfjs-editor-alt-text-dialog-label = اختر خيار
+pdfjs-editor-alt-text-dialog-description = يساعد النص البديل عندما لا يتمكن الأشخاص من رؤية الصورة أو عندما لا يتم تحميلها.
+pdfjs-editor-alt-text-add-description-label = أضِف وصف
+pdfjs-editor-alt-text-add-description-description = استهدف جملتين تصفان الموضوع أو الإعداد أو الإجراءات.
+pdfjs-editor-alt-text-mark-decorative-label = علّمها على أنها زخرفية
+pdfjs-editor-alt-text-mark-decorative-description = يُستخدم هذا في الصور المزخرفة، مثل الحدود أو العلامات المائية.
+pdfjs-editor-alt-text-cancel-button = ألغِ
+pdfjs-editor-alt-text-save-button = احفظ
+pdfjs-editor-alt-text-decorative-tooltip = عُلّمت على أنها زخرفية
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = على سبيل المثال، "يجلس شاب على الطاولة لتناول وجبة"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = نص بديل
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = الزاوية اليُسرى العُليا — غيّر الحجم
+pdfjs-editor-resizer-top-middle =
+ .aria-label = أعلى الوسط - غيّر الحجم
+pdfjs-editor-resizer-top-right =
+ .aria-label = الزاوية اليُمنى العُليا - غيّر الحجم
+pdfjs-editor-resizer-middle-right =
+ .aria-label = اليمين الأوسط - غيّر الحجم
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = الزاوية اليُمنى السُفلى - غيّر الحجم
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = أسفل الوسط - غيّر الحجم
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = الزاوية اليُسرى السُفلية - غيّر الحجم
+pdfjs-editor-resizer-middle-left =
+ .aria-label = مُنتصف اليسار - غيّر الحجم
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = أبرِز اللون
+pdfjs-editor-colorpicker-button =
+ .title = غيّر اللون
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = اختيارات الألوان
+pdfjs-editor-colorpicker-yellow =
+ .title = أصفر
+pdfjs-editor-colorpicker-green =
+ .title = أخضر
+pdfjs-editor-colorpicker-blue =
+ .title = أزرق
+pdfjs-editor-colorpicker-pink =
+ .title = وردي
+pdfjs-editor-colorpicker-red =
+ .title = أحمر
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = أظهِر الكل
+pdfjs-editor-highlight-show-all-button =
+ .title = أظهِر الكل
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = حرّر النص البديل (وصف الصورة)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = أضِف النص البديل (وصف الصورة)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = اكتب وصفك هنا…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = وصف مختصر للأشخاص الذين لا يستطيعون رؤية الصورة أو عندما لا يتم تحميل الصورة.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = أُنشئ هذا النص البديل تلقائيًا وقد يكون غير دقيق.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = اطّلع على المزيد
+pdfjs-editor-new-alt-text-create-automatically-button-label = أنشئ نص بديل تلقائيًا
+pdfjs-editor-new-alt-text-not-now-button = ليس الآن
+pdfjs-editor-new-alt-text-error-title = لم يتمكن من إنشاء نص بديل تلقائيًا
+pdfjs-editor-new-alt-text-error-description = يُرجى كتابة نص بديلك أو المحاولة مرة أخرى لاحقًا.
+pdfjs-editor-new-alt-text-error-close-button = أغلق
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = يُنزّل نموذج الذكاء الاصطناعي للنص البديل ({ $downloadedSize } من { $totalSize } م.بايت)
+ .aria-valuetext = يُنزّل نموذج الذكاء الاصطناعي للنص البديل ({ $downloadedSize } من { $totalSize } م.بايت)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = أُضِيف نص بديل
+pdfjs-editor-new-alt-text-added-button-label = أُضِيف نص بديل
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = نص بديل مفقود
+pdfjs-editor-new-alt-text-missing-button-label = نص بديل مفقود
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = راجع النص البديل
+pdfjs-editor-new-alt-text-to-review-button-label = راجع النص البديل
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = أُنشئ تلقائيًا: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = إعدادات النص البديل للصورة
+pdfjs-image-alt-text-settings-button-label = إعدادات النص البديل للصورة
+pdfjs-editor-alt-text-settings-dialog-label = إعدادات النص البديل للصورة
+pdfjs-editor-alt-text-settings-automatic-title = نص بديل تلقائي
+pdfjs-editor-alt-text-settings-create-model-button-label = أنشئ نص بديل تلقائيًا
+pdfjs-editor-alt-text-settings-create-model-description = يقترح أوصافًا لمساعدة الأشخاص الذين لا يستطيعون رؤية الصورة أو عندما لا يتم تحميل الصورة.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = نموذج الذكاء الاصطناعي للنص البديل ({ $totalSize } م.بايت)
+pdfjs-editor-alt-text-settings-ai-model-description = يتم تشغيله محليًا على جهازك حتى تظل بياناتك خاصة. مطلوب للنص البديل التلقائي.
+pdfjs-editor-alt-text-settings-delete-model-button = احذف
+pdfjs-editor-alt-text-settings-download-model-button = نزّل
+pdfjs-editor-alt-text-settings-downloading-model-button = يُنزل…
+pdfjs-editor-alt-text-settings-editor-title = مُحرِّر النص البديل
+pdfjs-editor-alt-text-settings-show-dialog-button-label = أظهِر مُحرِّر النص البديل على الفور عند إضافة صورة
+pdfjs-editor-alt-text-settings-show-dialog-description = يساعدك على التأكد من أن جميع صورك تحتوي على نص بديل.
+pdfjs-editor-alt-text-settings-close-button = أغلق
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = أُضيف إبراز
+pdfjs-editor-freetext-added-alert = أُضيف النص
+pdfjs-editor-ink-added-alert = أُضيف رسم
+pdfjs-editor-stamp-added-alert = أُضيف صورة
+pdfjs-editor-signature-added-alert = أُضيف توقيع
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = أُزِيل البرز
+pdfjs-editor-undo-bar-message-freetext = أُزيل النص
+pdfjs-editor-undo-bar-message-ink = أُزِيلت الرسمة
+pdfjs-editor-undo-bar-message-stamp = أُزيلت الصورة
+pdfjs-editor-undo-bar-message-signature = أُزيل التوقيع
+pdfjs-editor-undo-bar-message-comment = أُزيل التعليق
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [zero] أُزيل لا تعليق
+ [one] أُزيل تعليق
+ [two] أُزيل تعليقين
+ [few] أُزيلت { $count } تعليقات
+ [many] أُزيل { $count } تعليق
+ *[other] أُزيل { $count } تعليق
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = تراجع
+pdfjs-editor-undo-bar-undo-button-label = تراجع
+pdfjs-editor-undo-bar-close-button =
+ .title = أغلق
+pdfjs-editor-undo-bar-close-button-label = أغلق
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = يتيح هذا النموذج للمستخدم إنشاء توقيع لإضافته إلى مستند PDF. ويمكن للمستخدم تحرير الاسم (الذي يعمل أيضًا كنص بديل)، وحفظ التوقيع بشكل اختياري للاستخدام المتكرر.
+pdfjs-editor-add-signature-dialog-title = أضِف توقيعًا
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = اكتب
+ .title = اكتب
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = ارسم
+ .title = ارسم
+pdfjs-editor-add-signature-image-button = صورة
+ .title = صورة
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = اكتب توقيعك
+ .placeholder = اكتب توقيعك
+pdfjs-editor-add-signature-draw-placeholder = ارسم توقيعك
+pdfjs-editor-add-signature-draw-thickness-range-label = السماكة
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = سمك الرسم: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = اسحب الملف هنا لرفعه
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] أو اختر ملفات الصور
+ *[other] أو تصفح ملفات الصور
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = الوصف (نص بديل)
+pdfjs-editor-add-signature-description-input =
+ .title = الوصف (نص بديل)
+pdfjs-editor-add-signature-description-default-when-drawing = توقيع
+pdfjs-editor-add-signature-clear-button-label = امحُ التوقيع
+pdfjs-editor-add-signature-clear-button =
+ .title = امحُ التوقيع
+pdfjs-editor-add-signature-save-checkbox = احفظ التوقيع
+pdfjs-editor-add-signature-save-warning-message = لقد وصلت إلى الحد الأقصى وهو 5 توقيعات محفوظة. أزِل توقيع واحد لحفظ المزيد.
+pdfjs-editor-add-signature-image-upload-error-title = تعذر رفع الصورة.
+pdfjs-editor-add-signature-image-upload-error-description = تحقق من اتصال الشبكة لديك أو جرّب صورة أخرى.
+pdfjs-editor-add-signature-image-no-data-error-title = لا يمكن تحويل هذه الصورة إلى توقيع
+pdfjs-editor-add-signature-image-no-data-error-description = من فضلك حاول رفع صورة أخرى.
+pdfjs-editor-add-signature-error-close-button = أغلق
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = ألغِ
+pdfjs-editor-add-signature-add-button = أضِف
+pdfjs-editor-edit-signature-update-button = حدّث
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = حرّر التعليق
+pdfjs-editor-edit-comment-popup-button =
+ .title = حرّر التعليق
+pdfjs-editor-delete-comment-popup-button-label = أزِل التعليق
+pdfjs-editor-delete-comment-popup-button =
+ .title = أزِل التعليق
+pdfjs-show-comment-button =
+ .title = أظهر التعليق
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = حرّر التعليق
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = حدّث
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = أضِف تعليقًا
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = أضف
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = ابدأ الكتابة…
+pdfjs-editor-edit-comment-dialog-cancel-button = ألغِ
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = أضف التعليق
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = تبديل الشريط الجانبي (يحتوي المستند على صور مصغرة/مخطط تفصيلي/مرفقات/طبقات)
+pdfjs-toggle-views-manager-button1-label = أدِر الصفحات
+pdfjs-views-manager-sidebar =
+ .aria-label = الشريط الجانبي
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = أداة تغيير حجم الشريط الجانبي
+pdfjs-views-manager-view-selector-button =
+ .title = المناظير
+pdfjs-views-manager-view-selector-button-label = المناظير
+pdfjs-views-manager-pages-title = الصفحات
+pdfjs-views-manager-outlines-title1 = مخطط المستند
+ .title = مخطط المستند (انقر نقرًا مزدوجًا لتوسيع/طي كافة العناصر)
+pdfjs-views-manager-attachments-title = المرفقات
+pdfjs-views-manager-layers-title1 = طبقات
+ .title = الطبقات (انقر نقرًا مزدوجًا لإعادة تعيين كافة الطبقات إلى الحالة المبدئية)
+pdfjs-views-manager-pages-option-label = الصفحات
+pdfjs-views-manager-outlines-option-label = مخطط المستند
+pdfjs-views-manager-attachments-option-label = المرفقات
+pdfjs-views-manager-layers-option-label = الطبقات
+pdfjs-views-manager-add-file-button =
+ .title = أضف ملف
+pdfjs-views-manager-add-file-button-label = أضف ملف
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [zero] { $count } محدّد
+ [one] { $count } محدّد
+ [two] { $count } محدّدان
+ [few] { $count } محدّد
+ [many] { $count } محدّد
+ *[other] { $count } محدّد
+ }
+pdfjs-views-manager-pages-status-none-action-label = حدّد الصفحات
+pdfjs-views-manager-pages-status-action-button-label = أدِر
+pdfjs-views-manager-pages-status-copy-button-label = انسخ
+pdfjs-views-manager-pages-status-cut-button-label = قصّ
+pdfjs-views-manager-pages-status-delete-button-label = احذف
+pdfjs-views-manager-pages-status-export-selected-button-label = حُدِّد التصدير…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [zero] لا صفحات قُصت
+ [one] صفحة قُصت
+ [two] { $count } صفحتان قُصت
+ [few] { $count } صفحات قُصت
+ [many] { $count } صفحةً قُصت
+ *[other] { $count } صفحة قُصت
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [zero] لا صفحة منسوخة
+ [one] صفحة منسوخة
+ [two] صفحتان منسوختان
+ [few] { $count } صفحات منسوخة
+ [many] { $count } صفحةً منسوخةً
+ *[other] { $count } صفحة منسوخة
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [zero] لا صفحات محذوفة
+ [one] حُذف صفحة
+ [two] حُذف صفحتان
+ [few] حُذف { $count } صفحات
+ [many] حُذف { $count } صفحةً
+ *[other] حُذف { $count } صفحة
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = يجهز ملفك…
+pdfjs-views-manager-pages-status-waiting-uploading-label = يرفع ملف…
+pdfjs-views-manager-status-warning-cut-label = تعذّر القص. أنعش الصفحة وحاول مجددًا.
+pdfjs-views-manager-status-warning-copy-label = تعذّر النسخ. أنعش الصفحة وحاول مجددًا.
+pdfjs-views-manager-status-warning-delete-label = تعذّر الحذف. حدِّث الصفحة وحاول مجددًا.
+pdfjs-views-manager-status-warning-save-label = تعذّر الحفظ. أنعش الصفحة وحاول مجددًا.
+pdfjs-views-manager-status-undo-button-label = تراجع
+pdfjs-views-manager-status-done-button-label = تمّ
+pdfjs-views-manager-status-close-button =
+ .title = أغلق
+pdfjs-views-manager-status-close-button-label = أغلق
+pdfjs-views-manager-paste-button-label = ألصق
+pdfjs-views-manager-paste-button-before =
+ .title = ألصق قبل الصفحة الأولى
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = ألصق بعد الصفحة { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = جديد
+pdfjs-views-manager-waiting-for-file = يرفع ملف…
+pdfjs-toggle-views-manager-button1 =
+ .title = أدِر الصفحات
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = خصائص التوقيع الرقمي
+ .aria-label = خصائص التوقيع الرقمي
+pdfjs-digital-signature-properties-button-label = خصائص التوقيع الرقمي
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = وقِّع المستند بتوقيع رقمي صالح
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = الحالة: تحققَ من التوقيع
+pdfjs-digital-signature-properties-status-invalid = الحالة: التوقيع غير صالح
+pdfjs-digital-signature-properties-status-unknown = الحالة: تعذّر التحقق (غير مدعوم)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = الشهادة: موثوقة ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = الشهادة: غير متوفرة
+pdfjs-digital-signature-properties-certificate-untrusted = الشهادة: غير موثوقة
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = الشهادة: جهة إصدار مجهولة ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = الشهادة: موقعّة ذاتيًا ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = الشهادة: جهة إصدار مجهولة ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = الشهادة: منتهية الصلاحية
+pdfjs-digital-signature-properties-certificate-expired-with-date = الشهادة: منتهية الصلاحية ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = الشهادة: مُلغاة
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = أزِل التوقيع المحفوظ
+pdfjs-editor-delete-signature-button-label1 = أزِل التوقيع المحفوظ
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = عدّل الوصف
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = عدّل الوصف
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ast/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ast/viewer.ftl
new file mode 100644
index 0000000..2993916
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ast/viewer.ftl
@@ -0,0 +1,172 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Páxina anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Páxina siguiente
+pdfjs-next-button-label = Siguiente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Páxina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Alloñar
+pdfjs-zoom-out-button-label = Alloña
+pdfjs-zoom-in-button =
+ .title = Averar
+pdfjs-zoom-in-button-label = Avera
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Cambiar al mou de presentación
+pdfjs-presentation-mode-button-label = Mou de presentación
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprentar
+pdfjs-print-button-label = Imprentar
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ferramientes
+pdfjs-tools-button-label = Ferramientes
+pdfjs-first-page-button-label = Dir a la primer páxina
+pdfjs-last-page-button-label = Dir a la última páxina
+pdfjs-page-rotate-cw-button =
+ .title = Voltia a la derecha
+pdfjs-page-rotate-cw-button-label = Voltiar a la derecha
+pdfjs-page-rotate-ccw-button =
+ .title = Voltia a la esquierda
+pdfjs-page-rotate-ccw-button-label = Voltiar a la esquierda
+pdfjs-cursor-text-select-tool-button =
+ .title = Activa la ferramienta d'esbilla de testu
+pdfjs-cursor-text-select-tool-button-label = Ferramienta d'esbilla de testu
+pdfjs-cursor-hand-tool-button =
+ .title = Activa la ferramienta de mano
+pdfjs-cursor-hand-tool-button-label = Ferramienta de mano
+pdfjs-scroll-vertical-button =
+ .title = Usa'l desplazamientu vertical
+pdfjs-scroll-vertical-button-label = Desplazamientu vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usa'l desplazamientu horizontal
+pdfjs-scroll-horizontal-button-label = Desplazamientu horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usa'l desplazamientu continuu
+pdfjs-scroll-wrapped-button-label = Desplazamientu continuu
+pdfjs-spread-none-button-label = Fueyes individuales
+pdfjs-spread-odd-button-label = Fueyes pares
+pdfjs-spread-even-button-label = Fueyes impares
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedaes del documentu…
+pdfjs-document-properties-button-label = Propiedaes del documentu…
+pdfjs-document-properties-file-name = Nome del ficheru:
+pdfjs-document-properties-file-size = Tamañu del ficheru:
+pdfjs-document-properties-title = Títulu:
+pdfjs-document-properties-keywords = Pallabres clave:
+pdfjs-document-properties-creation-date = Data de creación:
+pdfjs-document-properties-modification-date = Data de modificación:
+pdfjs-document-properties-producer = Productor del PDF:
+pdfjs-document-properties-version = Versión del PDF:
+pdfjs-document-properties-page-count = Númberu de páxines:
+pdfjs-document-properties-page-size = Tamañu de páxina:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista web rápida:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = Non
+pdfjs-document-properties-close-button = Zarrar
+
+## Print
+
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Encaboxar
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Alternar la barra llateral
+pdfjs-attachments-button =
+ .title = Amosar los axuntos
+pdfjs-attachments-button-label = Axuntos
+pdfjs-layers-button-label = Capes
+pdfjs-thumbs-button =
+ .title = Amosar les miniatures
+pdfjs-thumbs-button-label = Miniatures
+pdfjs-findbar-button-label = Atopar
+pdfjs-additional-layers = Capes adicionales
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Páxina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button-label = Siguiente
+pdfjs-find-entire-word-checkbox-label = Pallabres completes
+pdfjs-find-reached-top = Algamóse'l comienzu de la páxina, síguese dende abaxo
+pdfjs-find-reached-bottom = Algamóse la fin del documentu, síguese dende arriba
+
+## Predefined zoom values
+
+pdfjs-page-scale-auto = Zoom automáticu
+pdfjs-page-scale-actual = Tamañu real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Páxina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Asocedió un fallu mentanto se cargaba'l PDF.
+
+## Password
+
+pdfjs-password-ok-button = Aceptar
+pdfjs-password-cancel-button = Encaboxar
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/az/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/az/viewer.ftl
new file mode 100644
index 0000000..a2d8c19
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/az/viewer.ftl
@@ -0,0 +1,228 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Əvvəlki səhifə
+pdfjs-previous-button-label = Əvvəlkini tap
+pdfjs-next-button =
+ .title = Növbəti səhifə
+pdfjs-next-button-label = İrəli
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Səhifə
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Uzaqlaş
+pdfjs-zoom-out-button-label = Uzaqlaş
+pdfjs-zoom-in-button =
+ .title = Yaxınlaş
+pdfjs-zoom-in-button-label = Yaxınlaş
+pdfjs-zoom-select =
+ .title = Yaxınlaşdırma
+pdfjs-presentation-mode-button =
+ .title = Təqdimat Rejiminə Keç
+pdfjs-presentation-mode-button-label = Təqdimat Rejimi
+pdfjs-open-file-button =
+ .title = Fayl Aç
+pdfjs-open-file-button-label = Aç
+pdfjs-print-button =
+ .title = Yazdır
+pdfjs-print-button-label = Yazdır
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Alətlər
+pdfjs-tools-button-label = Alətlər
+pdfjs-first-page-button =
+ .title = İlk Səhifəyə get
+pdfjs-first-page-button-label = İlk Səhifəyə get
+pdfjs-last-page-button =
+ .title = Son Səhifəyə get
+pdfjs-last-page-button-label = Son Səhifəyə get
+pdfjs-page-rotate-cw-button =
+ .title = Saat İstiqamətində Fırlat
+pdfjs-page-rotate-cw-button-label = Saat İstiqamətində Fırlat
+pdfjs-page-rotate-ccw-button =
+ .title = Saat İstiqamətinin Əksinə Fırlat
+pdfjs-page-rotate-ccw-button-label = Saat İstiqamətinin Əksinə Fırlat
+pdfjs-cursor-text-select-tool-button =
+ .title = Yazı seçmə alətini aktivləşdir
+pdfjs-cursor-text-select-tool-button-label = Yazı seçmə aləti
+pdfjs-cursor-hand-tool-button =
+ .title = Əl alətini aktivləşdir
+pdfjs-cursor-hand-tool-button-label = Əl aləti
+pdfjs-scroll-vertical-button =
+ .title = Şaquli sürüşdürmə işlət
+pdfjs-scroll-vertical-button-label = Şaquli sürüşdürmə
+pdfjs-scroll-horizontal-button =
+ .title = Üfüqi sürüşdürmə işlət
+pdfjs-scroll-horizontal-button-label = Üfüqi sürüşdürmə
+pdfjs-scroll-wrapped-button =
+ .title = Bükülü sürüşdürmə işlət
+pdfjs-scroll-wrapped-button-label = Bükülü sürüşdürmə
+pdfjs-spread-none-button =
+ .title = Yan-yana birləşdirilmiş səhifələri işlətmə
+pdfjs-spread-none-button-label = Birləşdirmə
+pdfjs-spread-odd-button =
+ .title = Yan-yana birləşdirilmiş səhifələri tək nömrəli səhifələrdən başlat
+pdfjs-spread-odd-button-label = Tək nömrəli
+pdfjs-spread-even-button =
+ .title = Yan-yana birləşdirilmiş səhifələri cüt nömrəli səhifələrdən başlat
+pdfjs-spread-even-button-label = Cüt nömrəli
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Sənəd xüsusiyyətləri…
+pdfjs-document-properties-button-label = Sənəd xüsusiyyətləri…
+pdfjs-document-properties-file-name = Fayl adı:
+pdfjs-document-properties-file-size = Fayl ölçüsü:
+pdfjs-document-properties-title = Başlık:
+pdfjs-document-properties-author = Müəllif:
+pdfjs-document-properties-subject = Mövzu:
+pdfjs-document-properties-keywords = Açar sözlər:
+pdfjs-document-properties-creation-date = Yaradılış Tarixi :
+pdfjs-document-properties-modification-date = Dəyişdirilmə Tarixi :
+pdfjs-document-properties-creator = Yaradan:
+pdfjs-document-properties-producer = PDF yaradıcısı:
+pdfjs-document-properties-version = PDF versiyası:
+pdfjs-document-properties-page-count = Səhifə sayı:
+pdfjs-document-properties-page-size = Səhifə Ölçüsü:
+pdfjs-document-properties-page-size-unit-inches = inç
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portret
+pdfjs-document-properties-page-size-orientation-landscape = albom
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Məktub
+pdfjs-document-properties-page-size-name-legal = Hüquqi
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Bəli
+pdfjs-document-properties-linearized-no = Xeyr
+pdfjs-document-properties-close-button = Qapat
+
+## Print
+
+pdfjs-print-progress-message = Sənəd çap üçün hazırlanır…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Ləğv et
+pdfjs-printing-not-supported = Xəbərdarlıq: Çap bu səyyah tərəfindən tam olaraq dəstəklənmir.
+pdfjs-printing-not-ready = Xəbərdarlıq: PDF çap üçün tam yüklənməyib.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Yan Paneli Aç/Bağla
+pdfjs-toggle-sidebar-notification-button =
+ .title = Yan paneli çevir (sənəddə icmal/bağlamalar/laylar mövcuddur)
+pdfjs-toggle-sidebar-button-label = Yan Paneli Aç/Bağla
+pdfjs-document-outline-button =
+ .title = Sənədin eskizini göstər (bütün bəndləri açmaq/yığmaq üçün iki dəfə klikləyin)
+pdfjs-document-outline-button-label = Sənəd strukturu
+pdfjs-attachments-button =
+ .title = Bağlamaları göstər
+pdfjs-attachments-button-label = Bağlamalar
+pdfjs-layers-button =
+ .title = Layları göstər (bütün layları ilkin halına sıfırlamaq üçün iki dəfə klikləyin)
+pdfjs-layers-button-label = Laylar
+pdfjs-thumbs-button =
+ .title = Kiçik şəkilləri göstər
+pdfjs-thumbs-button-label = Kiçik şəkillər
+pdfjs-findbar-button =
+ .title = Sənəddə Tap
+pdfjs-findbar-button-label = Tap
+pdfjs-additional-layers = Əlavə laylar
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Səhifə{ $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } səhifəsinin kiçik vəziyyəti
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Tap
+ .placeholder = Sənəddə tap…
+pdfjs-find-previous-button =
+ .title = Bir öncəki uyğun gələn sözü tapır
+pdfjs-find-previous-button-label = Geri
+pdfjs-find-next-button =
+ .title = Bir sonrakı uyğun gələn sözü tapır
+pdfjs-find-next-button-label = İrəli
+pdfjs-find-highlight-checkbox = İşarələ
+pdfjs-find-match-case-checkbox-label = Böyük/kiçik hərfə həssaslıq
+pdfjs-find-entire-word-checkbox-label = Tam sözlər
+pdfjs-find-reached-top = Sənədin yuxarısına çatdı, aşağıdan davam edir
+pdfjs-find-reached-bottom = Sənədin sonuna çatdı, yuxarıdan davam edir
+pdfjs-find-not-found = Uyğunlaşma tapılmadı
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Səhifə genişliyi
+pdfjs-page-scale-fit = Səhifəni sığdır
+pdfjs-page-scale-auto = Avtomatik yaxınlaşdır
+pdfjs-page-scale-actual = Hazırkı Həcm
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF yüklenərkən bir səhv yarandı.
+pdfjs-invalid-file-error = Səhv və ya zədələnmiş olmuş PDF fayl.
+pdfjs-missing-file-error = PDF fayl yoxdur.
+pdfjs-unexpected-response-error = Gözlənilməz server cavabı.
+pdfjs-rendering-error = Səhifə göstərilərkən səhv yarandı.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotasiyası]
+
+## Password
+
+pdfjs-password-label = Bu PDF faylı açmaq üçün parolu daxil edin.
+pdfjs-password-invalid = Parol səhvdir. Bir daha yoxlayın.
+pdfjs-password-ok-button = Tamam
+pdfjs-password-cancel-button = Ləğv et
+pdfjs-web-fonts-disabled = Web Şriftlər söndürülüb: yerləşdirilmiş PDF şriftlərini istifadə etmək mümkün deyil.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/be/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/be/viewer.ftl
new file mode 100644
index 0000000..a526254
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/be/viewer.ftl
@@ -0,0 +1,850 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Папярэдняя старонка
+pdfjs-previous-button-label = Папярэдняя
+pdfjs-next-button =
+ .title = Наступная старонка
+pdfjs-next-button-label = Наступная
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Старонка
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = з { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } з { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Паменшыць
+pdfjs-zoom-out-button-label = Паменшыць
+pdfjs-zoom-in-button =
+ .title = Павялічыць
+pdfjs-zoom-in-button-label = Павялічыць
+pdfjs-zoom-select =
+ .title = Павялічэнне тэксту
+pdfjs-presentation-mode-button =
+ .title = Пераключыцца ў рэжым паказу
+pdfjs-presentation-mode-button-label = Рэжым паказу
+pdfjs-open-file-button =
+ .title = Адкрыць файл
+pdfjs-open-file-button-label = Адкрыць
+pdfjs-print-button =
+ .title = Друкаваць
+pdfjs-print-button-label = Друкаваць
+pdfjs-save-button =
+ .title = Захаваць
+pdfjs-save-button-label = Захаваць
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Сцягнуць
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Сцягнуць
+pdfjs-bookmark-button =
+ .title = Дзейная старонка (паглядзець URL-адрас з дзейнай старонкі)
+pdfjs-bookmark-button-label = Цяперашняя старонка
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Прылады
+pdfjs-tools-button-label = Прылады
+pdfjs-first-page-button =
+ .title = Перайсці на першую старонку
+pdfjs-first-page-button-label = Перайсці на першую старонку
+pdfjs-last-page-button =
+ .title = Перайсці на апошнюю старонку
+pdfjs-last-page-button-label = Перайсці на апошнюю старонку
+pdfjs-page-rotate-cw-button =
+ .title = Павярнуць па сонцу
+pdfjs-page-rotate-cw-button-label = Павярнуць па сонцу
+pdfjs-page-rotate-ccw-button =
+ .title = Павярнуць супраць сонца
+pdfjs-page-rotate-ccw-button-label = Павярнуць супраць сонца
+pdfjs-cursor-text-select-tool-button =
+ .title = Уключыць прыладу выбару тэксту
+pdfjs-cursor-text-select-tool-button-label = Прылада выбару тэксту
+pdfjs-cursor-hand-tool-button =
+ .title = Уключыць ручную прыладу
+pdfjs-cursor-hand-tool-button-label = Ручная прылада
+pdfjs-scroll-page-button =
+ .title = Выкарыстоўваць пракрутку старонкi
+pdfjs-scroll-page-button-label = Пракрутка старонкi
+pdfjs-scroll-vertical-button =
+ .title = Ужываць вертыкальную пракрутку
+pdfjs-scroll-vertical-button-label = Вертыкальная пракрутка
+pdfjs-scroll-horizontal-button =
+ .title = Ужываць гарызантальную пракрутку
+pdfjs-scroll-horizontal-button-label = Гарызантальная пракрутка
+pdfjs-scroll-wrapped-button =
+ .title = Ужываць маштабавальную пракрутку
+pdfjs-scroll-wrapped-button-label = Маштабавальная пракрутка
+pdfjs-spread-none-button =
+ .title = Не выкарыстоўваць разгорнутыя старонкі
+pdfjs-spread-none-button-label = Без разгорнутых старонак
+pdfjs-spread-odd-button =
+ .title = Разгорнутыя старонкі пачынаючы з няцотных нумароў
+pdfjs-spread-odd-button-label = Няцотныя старонкі злева
+pdfjs-spread-even-button =
+ .title = Разгорнутыя старонкі пачынаючы з цотных нумароў
+pdfjs-spread-even-button-label = Цотныя старонкі злева
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Уласцівасці дакумента…
+pdfjs-document-properties-button-label = Уласцівасці дакумента…
+pdfjs-document-properties-file-name = Назва файла:
+pdfjs-document-properties-file-size = Памер файла:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } КБ ({ $b } байтаў)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } МБ ({ $b } байтаў)
+pdfjs-document-properties-title = Загаловак:
+pdfjs-document-properties-author = Аўтар:
+pdfjs-document-properties-subject = Тэма:
+pdfjs-document-properties-keywords = Ключавыя словы:
+pdfjs-document-properties-creation-date = Дата стварэння:
+pdfjs-document-properties-modification-date = Дата змянення:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Стваральнік:
+pdfjs-document-properties-producer = Вырабнік PDF:
+pdfjs-document-properties-version = Версія PDF:
+pdfjs-document-properties-page-count = Колькасць старонак:
+pdfjs-document-properties-page-size = Памер старонкі:
+pdfjs-document-properties-page-size-unit-inches = цаляў
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = кніжная
+pdfjs-document-properties-page-size-orientation-landscape = альбомная
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Хуткі прагляд у Інтэрнэце:
+pdfjs-document-properties-linearized-yes = Так
+pdfjs-document-properties-linearized-no = Не
+pdfjs-document-properties-close-button = Закрыць
+pdfjs-digital-signature-properties-view-certificate = Паказаць сертыфікат
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Прычына: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Адзнака часу: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Дадатковы подпіс ({ $count })
+ [few] Дадатковыя подпісы ({ $count })
+ *[many] Дадатковыя подпісы ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Падрыхтоўка дакумента да друку…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Скасаваць
+pdfjs-printing-not-supported = Папярэджанне: друк не падтрымліваецца цалкам гэтым браўзерам.
+pdfjs-printing-not-ready = Увага: PDF не сцягнуты цалкам для друкавання.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Паказаць/схаваць бакавую панэль
+pdfjs-toggle-sidebar-notification-button =
+ .title = Паказаць/схаваць бакавую панэль (дакумент мае змест/укладанні/пласты)
+pdfjs-toggle-sidebar-button-label = Паказаць/схаваць бакавую панэль
+pdfjs-document-outline-button =
+ .title = Паказаць структуру дакумента (двайная пстрычка, каб разгарнуць /згарнуць усе элементы)
+pdfjs-document-outline-button-label = Структура дакумента
+pdfjs-attachments-button =
+ .title = Паказаць далучэнні
+pdfjs-attachments-button-label = Далучэнні
+pdfjs-layers-button =
+ .title = Паказаць пласты (націсніце двойчы, каб скінуць усе пласты да прадвызначанага стану)
+pdfjs-layers-button-label = Пласты
+pdfjs-thumbs-button =
+ .title = Паказ мініяцюр
+pdfjs-thumbs-button-label = Мініяцюры
+pdfjs-current-outline-item-button =
+ .title = Знайсці бягучы элемент структуры
+pdfjs-current-outline-item-button-label = Бягучы элемент структуры
+pdfjs-findbar-button =
+ .title = Пошук у дакуменце
+pdfjs-findbar-button-label = Знайсці
+pdfjs-additional-layers = Дадатковыя пласты
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Старонка { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Мініяцюра старонкі { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Выбраць старонку { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Старонка { $page } з { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Шукаць
+ .placeholder = Шукаць у дакуменце…
+pdfjs-find-previous-button =
+ .title = Знайсці папярэдні выпадак выразу
+pdfjs-find-previous-button-label = Папярэдні
+pdfjs-find-next-button =
+ .title = Знайсці наступны выпадак выразу
+pdfjs-find-next-button-label = Наступны
+pdfjs-find-highlight-checkbox = Падфарбаваць усе
+pdfjs-find-match-case-checkbox-label = Адрозніваць вялікія/малыя літары
+pdfjs-find-match-diacritics-checkbox-label = З улікам дыякрытык
+pdfjs-find-entire-word-checkbox-label = Словы цалкам
+pdfjs-find-reached-top = Дасягнуты пачатак дакумента, працяг з канца
+pdfjs-find-reached-bottom = Дасягнуты канец дакумента, працяг з пачатку
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } з { $total } супадзенняў
+ [few] { $current } з { $total } супадзенняў
+ *[many] { $current } з { $total } супадзенняў
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Больш за { $limit } супадзенне
+ [few] Больш за { $limit } супадзенні
+ *[many] Больш за { $limit } супадзенняў
+ }
+pdfjs-find-not-found = Выраз не знойдзены
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Шырыня старонкі
+pdfjs-page-scale-fit = Уцісненне старонкі
+pdfjs-page-scale-auto = Аўтаматычнае павелічэнне
+pdfjs-page-scale-actual = Сапраўдны памер
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Старонка { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Здарылася памылка ў часе загрузкі PDF.
+pdfjs-invalid-file-error = Няспраўны або пашкоджаны файл PDF.
+pdfjs-missing-file-error = Адсутны файл PDF.
+pdfjs-unexpected-response-error = Нечаканы адказ сервера.
+pdfjs-rendering-error = Здарылася памылка падчас адлюстравання старонкі.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Увядзіце пароль, каб адкрыць гэты файл PDF.
+pdfjs-password-invalid = Нядзейсны пароль. Паспрабуйце зноў.
+pdfjs-password-ok-button = Добра
+pdfjs-password-cancel-button = Скасаваць
+pdfjs-web-fonts-disabled = Шрыфты Сеціва забаронены: немагчыма ўжываць укладзеныя шрыфты PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Тэкст
+pdfjs-editor-color-picker-free-text-input =
+ .title = Змяніць колер тэксту
+pdfjs-editor-free-text-button-label = Тэкст
+pdfjs-editor-ink-button =
+ .title = Маляваць
+pdfjs-editor-color-picker-ink-input =
+ .title = Змяніць колер малюнка
+pdfjs-editor-ink-button-label = Маляваць
+pdfjs-editor-stamp-button =
+ .title = Дадаць або змяніць выявы
+pdfjs-editor-stamp-button-label = Дадаць або змяніць выявы
+pdfjs-editor-highlight-button =
+ .title = Вылучэнне
+pdfjs-editor-highlight-button-label = Вылучэнне
+pdfjs-highlight-floating-button1 =
+ .title = Падфарбаваць
+ .aria-label = Падфарбаваць
+pdfjs-highlight-floating-button-label = Падфарбаваць
+pdfjs-comment-floating-button =
+ .title = Каментаваць
+ .aria-label = Каментаваць
+pdfjs-comment-floating-button-label = Каментаваць
+pdfjs-editor-comment-button =
+ .title = Каментарый
+ .aria-label = Каментарый
+pdfjs-editor-comment-button-label = Каментарый
+pdfjs-editor-signature-button =
+ .title = Дадаць подпіс
+pdfjs-editor-signature-button-label = Дадаць подпіс
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Рэдактар вылучэнняў
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Рэдактар малюнкаў
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Рэдактар подпісаў: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Рэдактар выяў
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Выдаліць малюнак
+pdfjs-editor-remove-freetext-button =
+ .title = Выдаліць тэкст
+pdfjs-editor-remove-stamp-button =
+ .title = Выдаліць выяву
+pdfjs-editor-remove-highlight-button =
+ .title = Выдаліць падфарбоўку
+pdfjs-editor-remove-signature-button =
+ .title = Выдаліць подпіс
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Колер
+pdfjs-editor-free-text-size-input = Памер
+pdfjs-editor-ink-color-input = Колер
+pdfjs-editor-ink-thickness-input = Таўшчыня
+pdfjs-editor-ink-opacity-input = Непразрыстасць
+pdfjs-editor-stamp-add-image-button =
+ .title = Дадаць выяву
+pdfjs-editor-stamp-add-image-button-label = Дадаць выяву
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Таўшчыня
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Змяняць таўшчыню пры вылучэнні іншых элементаў, акрамя тэксту
+pdfjs-editor-add-signature-container =
+ .aria-label = Элементы кіравання подпісамі і захаваныя подпісы
+pdfjs-editor-signature-add-signature-button =
+ .title = Дадаць новы подпіс
+pdfjs-editor-signature-add-signature-button-label = Дадаць новы подпіс
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Захаваны подпіс: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Тэкставы рэдактар
+ .default-content = Пачніце ўводзіць…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Каментарый
+ [few] Каментарыі
+ *[many] Каментарыі
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Закрыць бакавую панэль
+ .aria-label = Закрыць бакавую панэль
+pdfjs-editor-comments-sidebar-close-button-label = Закрыць бакавую панэль
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Бачыце штосьці вартае ўвагі? Вылучыце і пакіньце каментарый.
+pdfjs-editor-comments-sidebar-no-comments-link = Падрабязней
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Альтэрнатыўны тэкст
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Змяніць альтэрнатыўны тэкст
+pdfjs-editor-alt-text-dialog-label = Выберыце варыянт
+pdfjs-editor-alt-text-dialog-description = Альтэрнатыўны тэкст дапамагае, калі людзі не бачаць выяву або калі яна не загружаецца.
+pdfjs-editor-alt-text-add-description-label = Дадаць апісанне
+pdfjs-editor-alt-text-add-description-description = Старайцеся скласці 1-2 сказы, якія апісваюць прадмет, абстаноўку або дзеянні.
+pdfjs-editor-alt-text-mark-decorative-label = Пазначыць як дэкаратыўны
+pdfjs-editor-alt-text-mark-decorative-description = Выкарыстоўваецца для дэкаратыўных выяваў, такіх як рамкі або вадзяныя знакі.
+pdfjs-editor-alt-text-cancel-button = Скасаваць
+pdfjs-editor-alt-text-save-button = Захаваць
+pdfjs-editor-alt-text-decorative-tooltip = Пазначаны як дэкаратыўны
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Напрыклад, «Малады чалавек садзіцца за стол есці»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Альтэрнатыўны тэкст
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Верхні левы кут — змяніць памер
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Уверсе пасярэдзіне — змяніць памер
+pdfjs-editor-resizer-top-right =
+ .aria-label = Верхні правы кут — змяніць памер
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Пасярэдзіне справа — змяніць памер
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Правы ніжні кут — змяніць памер
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Пасярэдзіне ўнізе — змяніць памер
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Левы ніжні кут — змяніць памер
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Пасярэдзіне злева — змяніць памер
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Колер падфарбоўкі
+pdfjs-editor-colorpicker-button =
+ .title = Змяніць колер
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Выбар колеру
+pdfjs-editor-colorpicker-yellow =
+ .title = Жоўты
+pdfjs-editor-colorpicker-green =
+ .title = Зялёны
+pdfjs-editor-colorpicker-blue =
+ .title = Блакітны
+pdfjs-editor-colorpicker-pink =
+ .title = Ружовы
+pdfjs-editor-colorpicker-red =
+ .title = Чырвоны
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Паказаць усе
+pdfjs-editor-highlight-show-all-button =
+ .title = Паказаць усе
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Рэдагаваць тэкст для атрыбута alt (апісанне выявы)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Дадаць тэкст для атрыбута alt (апісанне выявы)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Напішыце сваё апісанне тут…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Кароткае апісанне для людзей, якія не бачаць выяву, ці калі выява не загружаецца.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Гэты тэкст для атрыбута alt быў створаны аўтаматычна і можа быць недакладным
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Даведацца больш
+pdfjs-editor-new-alt-text-create-automatically-button-label = Ствараць тэкст для атрыбута alt аўтаматычна
+pdfjs-editor-new-alt-text-not-now-button = Не зараз
+pdfjs-editor-new-alt-text-error-title = Не ўдалося аўтаматычна стварыць тэкст для атрыбута alt
+pdfjs-editor-new-alt-text-error-description = Калі ласка, напішыце ўласны тэкст для атрыбута alt або паўтарыце спробу пазней.
+pdfjs-editor-new-alt-text-error-close-button = Закрыць
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Сцягванне мадэлі ШІ для тэксту для атрыбута alt ({ $downloadedSize } з { $totalSize } МБ)
+ .aria-valuetext = Сцягванне мадэлі ШІ для тэксту для атрыбута alt ({ $downloadedSize } з { $totalSize } МБ)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Тэкст для атрыбута alt дададзены
+pdfjs-editor-new-alt-text-added-button-label = Тэкст для атрыбута alt дададзены
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Адсутнічае тэкст для атрыбута alt
+pdfjs-editor-new-alt-text-missing-button-label = Адсутнічае тэкст для атрыбута alt
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Водгук на тэкст для атрыбута alt
+pdfjs-editor-new-alt-text-to-review-button-label = Водгук на тэкст для атрыбута alt
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Створаны аўтаматычна: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Налады альтэрнатыўнага тэксту для выявы
+pdfjs-image-alt-text-settings-button-label = Налады альтэрнатыўнага тэксту для выявы
+pdfjs-editor-alt-text-settings-dialog-label = Налады альтэрнатыўнага тэксту для выявы
+pdfjs-editor-alt-text-settings-automatic-title = Аўтаматычны тэкст для атрыбута alt
+pdfjs-editor-alt-text-settings-create-model-button-label = Ствараць тэкст для атрыбута alt аўтаматычна
+pdfjs-editor-alt-text-settings-create-model-description = Прапануе апісанні, каб дапамагчы людзям, якія не бачаць выяву, ці калі выява не загружаецца.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Мадэль ШІ для тэксту для атрыбута alt ({ $totalSize } МБ)
+pdfjs-editor-alt-text-settings-ai-model-description = Працуе лакальна на вашай прыладзе, таму вашы звесткі застаюцца прыватнымі. Патрабуецца для аўтаматычнага альтэрнатыўнага тэксту.
+pdfjs-editor-alt-text-settings-delete-model-button = Выдаліць
+pdfjs-editor-alt-text-settings-download-model-button = Сцягнуць
+pdfjs-editor-alt-text-settings-downloading-model-button = Сцягванне…
+pdfjs-editor-alt-text-settings-editor-title = Рэдактар тэксту для атрыбута alt
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Адразу паказваць рэдактар тэксту для атрыбута alt пры даданні выявы
+pdfjs-editor-alt-text-settings-show-dialog-description = Дапамагае пераканацца, што ўсе вашы выявы маюць альтэрнатыўны тэкст.
+pdfjs-editor-alt-text-settings-close-button = Закрыць
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Вылучэнне дададзена
+pdfjs-editor-freetext-added-alert = Тэкст дададзены
+pdfjs-editor-ink-added-alert = Малюнак дададзены
+pdfjs-editor-stamp-added-alert = Выява дададзена
+pdfjs-editor-signature-added-alert = Подпіс дададзены
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Падсвятленне выдалена
+pdfjs-editor-undo-bar-message-freetext = Тэкст выдалены
+pdfjs-editor-undo-bar-message-ink = Малюнак выдалены
+pdfjs-editor-undo-bar-message-stamp = Відарыс выдалены
+pdfjs-editor-undo-bar-message-signature = Подпіс выдалены
+pdfjs-editor-undo-bar-message-comment = Каментарый выдалены
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } анатацыя выдалена
+ [few] { $count } анатацыі выдалена
+ *[many] { $count } анатацый выдалена
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Адмяніць
+pdfjs-editor-undo-bar-undo-button-label = Адмяніць
+pdfjs-editor-undo-bar-close-button =
+ .title = Закрыць
+pdfjs-editor-undo-bar-close-button-label = Закрыць
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Гэты рэжым дазваляе карыстальніку ствараць подпіс для дадання ў дакумент PDF. Карыстальнік можа рэдагаваць імя (якое таксама служыць альтэрнатыўным тэкстам) і пры жаданні захаваць подпіс для паўторнага выкарыстання.
+pdfjs-editor-add-signature-dialog-title = Дадаць подпіс
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Увод
+ .title = Увод
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Маляваць
+ .title = Маляваць
+pdfjs-editor-add-signature-image-button = Выява
+ .title = Выява
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Увядзіце свой подпіс
+ .placeholder = Увядзіце свой подпіс
+pdfjs-editor-add-signature-draw-placeholder = Намалюйце свой подпіс
+pdfjs-editor-add-signature-draw-thickness-range-label = Таўшчыня
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Таўшчыня малюнка: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Перацягнуць файл сюды, каб загрузіць
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Або праглядайце файлы малюнкаў
+ *[other] Або праглядайце файлы малюнкаў
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Апісанне (альтэрнатыўны тэкст)
+pdfjs-editor-add-signature-description-input =
+ .title = Апісанне (альтэрнатыўны тэкст)
+pdfjs-editor-add-signature-description-default-when-drawing = Подпіс
+pdfjs-editor-add-signature-clear-button-label = Выдаліць подпіс
+pdfjs-editor-add-signature-clear-button =
+ .title = Выдаліць подпіс
+pdfjs-editor-add-signature-save-checkbox = Захаваць подпіс
+pdfjs-editor-add-signature-save-warning-message = Вы дасягнулі ліміту ў 5 захаваных подпісаў. Выдаліце адзін, каб захаваць іншы.
+pdfjs-editor-add-signature-image-upload-error-title = Не ўдалося загрузіць выяву
+pdfjs-editor-add-signature-image-upload-error-description = Праверце падключэнне да сеткі ці паспрабуйце іншую выяву.
+pdfjs-editor-add-signature-image-no-data-error-title = Не ўдалося пераўтварыць гэту выяву ў подпіс
+pdfjs-editor-add-signature-image-no-data-error-description = Калі ласка, паспрабуйце зацягнуць іншую выяву.
+pdfjs-editor-add-signature-error-close-button = Закрыць
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Скасаваць
+pdfjs-editor-add-signature-add-button = Дадаць
+pdfjs-editor-edit-signature-update-button = Абнавіць
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Змяніць каментарый
+pdfjs-editor-edit-comment-popup-button =
+ .title = Змяніць каментарый
+pdfjs-editor-delete-comment-popup-button-label = Выдаліць каментарый
+pdfjs-editor-delete-comment-popup-button =
+ .title = Выдаліць каментарый
+pdfjs-show-comment-button =
+ .title = Паказаць каментарый
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Змяніць каментарый
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Абнавіць
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Дадаць каментарый
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Дадаць
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Пачніце набор тэксту…
+pdfjs-editor-edit-comment-dialog-cancel-button = Скасаваць
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Дадаць каментарый
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Паказаць/схаваць бакавую панэль (дакумент мае мініяцюры/змест/далучэнні/пласты)
+pdfjs-toggle-views-manager-button1-label = Кіраванне старонкамі
+pdfjs-views-manager-sidebar =
+ .aria-label = Бакавая панэль
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Змена памеру бакавой панэлі
+pdfjs-views-manager-view-selector-button =
+ .title = Выгляд
+pdfjs-views-manager-view-selector-button-label = Выгляд
+pdfjs-views-manager-pages-title = Старонкі
+pdfjs-views-manager-outlines-title1 = Структура дакумента
+ .title = Структура дакумента (націсніце двойчы, каб разгарнуць/згарнуць усе элементы)
+pdfjs-views-manager-attachments-title = Далучэнні
+pdfjs-views-manager-layers-title1 = Пласты
+ .title = Пласты (націсніце двойчы каб скінуць у прадвызначаны стан)
+pdfjs-views-manager-pages-option-label = Старонкі
+pdfjs-views-manager-outlines-option-label = Структура дакумента
+pdfjs-views-manager-attachments-option-label = Далучэнні
+pdfjs-views-manager-layers-option-label = Пласты
+pdfjs-views-manager-add-file-button =
+ .title = Дадаць файл
+pdfjs-views-manager-add-file-button-label = Дадаць файл
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] Вылучана { $count }
+ [few] Вылучаны { $count }
+ *[many] Вылучана { $count }
+ }
+pdfjs-views-manager-pages-status-none-action-label = Выбраць старонкі
+pdfjs-views-manager-pages-status-action-button-label = Кіраваць
+pdfjs-views-manager-pages-status-copy-button-label = Капіяваць
+pdfjs-views-manager-pages-status-cut-button-label = Выразаць
+pdfjs-views-manager-pages-status-delete-button-label = Выдаліць
+pdfjs-views-manager-pages-status-export-selected-button-label = Экспартаваць выбранае…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Выразана { $count } старонка
+ [few] Выразана { $count } старонкі
+ *[many] Выразана { $count } старонак
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Скапіравана { $count } старонка
+ [few] Скапіравана { $count } старонкі
+ *[many] Скапіравана { $count } старонак
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Выдалена { $count } старонка
+ [few] Выдалена { $count } старонкі
+ *[many] Выдалена { $count } старонак
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Рыхтуецца ваш файл…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Зацягваецца файл…
+pdfjs-views-manager-status-warning-cut-label = Не ўдалося выразаць. Абнавіце старонку і паспрабуйце зноў.
+pdfjs-views-manager-status-warning-copy-label = Не ўдалося скапіяваць. Абнавіце старонку і паспрабуйце зноў.
+pdfjs-views-manager-status-warning-delete-label = Не ўдалося выдаліць. Абнавіце старонку і паспрабуйце зноў.
+pdfjs-views-manager-status-warning-save-label = Не ўдалося захаваць. Абнавіце старонку і паспрабуйце зноў.
+pdfjs-views-manager-status-undo-button-label = Адмяніць
+pdfjs-views-manager-status-done-button-label = Гатова
+pdfjs-views-manager-status-close-button =
+ .title = Закрыць
+pdfjs-views-manager-status-close-button-label = Закрыць
+pdfjs-views-manager-paste-button-label = Уставіць
+pdfjs-views-manager-paste-button-before =
+ .title = Уставіць перад першай старонкай
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Уставіць пасля старонкі { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = НОВАЕ
+pdfjs-views-manager-waiting-for-file = Зацягваецца файл…
+pdfjs-toggle-views-manager-button1 =
+ .title = Кіраванне старонкамі
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Уласцівасці лічбавага подпісу
+ .aria-label = Уласцівасці лічбавага подпісу
+pdfjs-digital-signature-properties-button-label = Уласцівасці лічбавага подпісу
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Дакумент быў падпісаны сапраўдным лічбавым подпісам
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Дакумент падпісаны, але { $count } лічбавы подпіс не ўдалося праверыць
+ [few] Дакумент падпісаны, але { $count } лічбавыя подпісы не ўдалося праверыць
+ *[many] Дакумент падпісаны, але { $count } лічбавых подпісаў не ўдалося праверыць
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Дакумент падпісаны { $count } недавераным сертыфікатам
+ [few] Дакумент падпісаны { $count } недаверанымі сертыфікатамі
+ *[many] Дакумент падпісаны { $count } недаверанымі сертыфікатамі
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Дакумент падпісаны { $count } пратэрмінаваным сертыфікатам
+ [few] Дакумент падпісаны { $count } пратэрмінаванымі сертыфікатамі
+ *[many] Дакумент падпісаны { $count } пратэрмінаванымі сертыфікатамі
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Дакумент мае { $count } нядзейсны лічбавы подпіс
+ [few] Дакумент мае { $count } нядзейсныя лічбавыя подпісы
+ *[many] Дакумент мае { $count } нядзейсных лічбавых подпісаў
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Дакумент падпісаны { $count } адкліканым сертыфікатам
+ [few] Дакумент падпісаны { $count } адкліканымі сертыфікатамі
+ *[many] Дакумент падпісаны { $count } адкліканымі сертыфікатамі
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Статус: Подпіс правераны
+pdfjs-digital-signature-properties-status-invalid = Статус: Подпіс нядзейсны
+pdfjs-digital-signature-properties-status-unknown = Статус: Немагчыма праверыць (не падтрымліваецца)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Сертыфікат: Давераны ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Сертыфікат: Недаступны
+pdfjs-digital-signature-properties-certificate-untrusted = Сертыфікат: Недавераны
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Сертыфікат: Невядомы выдавец ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Сертыфікат: Самападпісаны ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Сертыфікат: Недавераны выдавец ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Сертыфікат: Пратэрмінаваны
+pdfjs-digital-signature-properties-certificate-expired-with-date = Сертыфікат: Пратэрмінаваны ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Сертыфікат: Адкліканы
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Выдаліць захаваны подпіс
+pdfjs-editor-delete-signature-button-label1 = Выдаліць захаваны подпіс
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Рэдагаваць апісанне
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Рэдагаваць апісанне
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bg/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bg/viewer.ftl
new file mode 100644
index 0000000..7240146
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bg/viewer.ftl
@@ -0,0 +1,414 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Предишна страница
+pdfjs-previous-button-label = Предишна
+pdfjs-next-button =
+ .title = Следваща страница
+pdfjs-next-button-label = Следваща
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Страница
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = от { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } от { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Намаляване
+pdfjs-zoom-out-button-label = Намаляване
+pdfjs-zoom-in-button =
+ .title = Увеличаване
+pdfjs-zoom-in-button-label = Увеличаване
+pdfjs-zoom-select =
+ .title = Мащабиране
+pdfjs-presentation-mode-button =
+ .title = Превключване към режим на представяне
+pdfjs-presentation-mode-button-label = Режим на представяне
+pdfjs-open-file-button =
+ .title = Отваряне на файл
+pdfjs-open-file-button-label = Отваряне
+pdfjs-print-button =
+ .title = Отпечатване
+pdfjs-print-button-label = Отпечатване
+pdfjs-save-button =
+ .title = Запазване
+pdfjs-save-button-label = Запазване
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Изтегляне
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Изтегляне
+pdfjs-bookmark-button =
+ .title = Текуща страница (преглед на адреса на страницата)
+pdfjs-bookmark-button-label = Текуща страница
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Инструменти
+pdfjs-tools-button-label = Инструменти
+pdfjs-first-page-button =
+ .title = Към първата страница
+pdfjs-first-page-button-label = Към първата страница
+pdfjs-last-page-button =
+ .title = Към последната страница
+pdfjs-last-page-button-label = Към последната страница
+pdfjs-page-rotate-cw-button =
+ .title = Завъртане по час. стрелка
+pdfjs-page-rotate-cw-button-label = Завъртане по часовниковата стрелка
+pdfjs-page-rotate-ccw-button =
+ .title = Завъртане обратно на час. стрелка
+pdfjs-page-rotate-ccw-button-label = Завъртане обратно на часовниковата стрелка
+pdfjs-cursor-text-select-tool-button =
+ .title = Включване на инструмента за избор на текст
+pdfjs-cursor-text-select-tool-button-label = Инструмент за избор на текст
+pdfjs-cursor-hand-tool-button =
+ .title = Включване на инструмента ръка
+pdfjs-cursor-hand-tool-button-label = Инструмент ръка
+pdfjs-scroll-page-button =
+ .title = Използване на плъзгане на страници
+pdfjs-scroll-page-button-label = Плъзгане на страници
+pdfjs-scroll-vertical-button =
+ .title = Използване на вертикално плъзгане
+pdfjs-scroll-vertical-button-label = Вертикално плъзгане
+pdfjs-scroll-horizontal-button =
+ .title = Използване на хоризонтално
+pdfjs-scroll-horizontal-button-label = Хоризонтално плъзгане
+pdfjs-scroll-wrapped-button =
+ .title = Използване на мащабируемо плъзгане
+pdfjs-scroll-wrapped-button-label = Мащабируемо плъзгане
+pdfjs-spread-none-button =
+ .title = Режимът на сдвояване е изключен
+pdfjs-spread-none-button-label = Без сдвояване
+pdfjs-spread-odd-button =
+ .title = Сдвояване, започвайки от нечетните страници
+pdfjs-spread-odd-button-label = Нечетните отляво
+pdfjs-spread-even-button =
+ .title = Сдвояване, започвайки от четните страници
+pdfjs-spread-even-button-label = Четните отляво
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Свойства на документа…
+pdfjs-document-properties-button-label = Свойства на документа…
+pdfjs-document-properties-file-name = Име на файл:
+pdfjs-document-properties-file-size = Големина на файл:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } КБ ({ $b } байта)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } МБ ({ $b } байта)
+pdfjs-document-properties-title = Заглавие:
+pdfjs-document-properties-author = Автор:
+pdfjs-document-properties-subject = Тема:
+pdfjs-document-properties-keywords = Ключови думи:
+pdfjs-document-properties-creation-date = Дата на създаване:
+pdfjs-document-properties-modification-date = Дата на промяна:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Създател:
+pdfjs-document-properties-producer = PDF произведен от:
+pdfjs-document-properties-version = Издание на PDF:
+pdfjs-document-properties-page-count = Брой страници:
+pdfjs-document-properties-page-size = Размер на страницата:
+pdfjs-document-properties-page-size-unit-inches = инч
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = портрет
+pdfjs-document-properties-page-size-orientation-landscape = пейзаж
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Правни въпроси
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Бърз преглед:
+pdfjs-document-properties-linearized-yes = Да
+pdfjs-document-properties-linearized-no = Не
+pdfjs-document-properties-close-button = Затваряне
+
+## Print
+
+pdfjs-print-progress-message = Подготвяне на документа за отпечатване…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Отказ
+pdfjs-printing-not-supported = Внимание: Този четец няма пълна поддръжка на отпечатване.
+pdfjs-printing-not-ready = Внимание: Този PDF файл не е напълно зареден за печат.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Превключване на страничната лента
+pdfjs-toggle-sidebar-notification-button =
+ .title = Превключване на страничната лента (документът има структура/прикачени файлове/слоеве)
+pdfjs-toggle-sidebar-button-label = Превключване на страничната лента
+pdfjs-document-outline-button =
+ .title = Показване на структурата на документа (двукратно щракване за свиване/разгъване на всичко)
+pdfjs-document-outline-button-label = Структура на документа
+pdfjs-attachments-button =
+ .title = Показване на притурките
+pdfjs-attachments-button-label = Притурки
+pdfjs-layers-button =
+ .title = Показване на слоевете (двукратно щракване за възстановяване на всички слоеве към състоянието по подразбиране)
+pdfjs-layers-button-label = Слоеве
+pdfjs-thumbs-button =
+ .title = Показване на миниатюрите
+pdfjs-thumbs-button-label = Миниатюри
+pdfjs-current-outline-item-button =
+ .title = Намиране на текущия елемент от структурата
+pdfjs-current-outline-item-button-label = Текущ елемент от структурата
+pdfjs-findbar-button =
+ .title = Намиране в документа
+pdfjs-findbar-button-label = Търсене
+pdfjs-additional-layers = Допълнителни слоеве
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Страница { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Миниатюра на страница { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Търсене
+ .placeholder = Търсене в документа…
+pdfjs-find-previous-button =
+ .title = Намиране на предишно съвпадение на фразата
+pdfjs-find-previous-button-label = Предишна
+pdfjs-find-next-button =
+ .title = Намиране на следващо съвпадение на фразата
+pdfjs-find-next-button-label = Следваща
+pdfjs-find-highlight-checkbox = Открояване на всички
+pdfjs-find-match-case-checkbox-label = Съвпадение на регистъра
+pdfjs-find-match-diacritics-checkbox-label = Без производни букви
+pdfjs-find-entire-word-checkbox-label = Цели думи
+pdfjs-find-reached-top = Достигнато е началото на документа, продължаване от края
+pdfjs-find-reached-bottom = Достигнат е краят на документа, продължаване от началото
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } от { $total } съвпадение
+ *[other] { $current } от { $total } съвпадения
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Повече от { $limit } съвпадение
+ *[other] Повече от { $limit } съвпадения
+ }
+pdfjs-find-not-found = Фразата не е намерена
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ширина на страницата
+pdfjs-page-scale-fit = Вместване в страницата
+pdfjs-page-scale-auto = Автоматично мащабиране
+pdfjs-page-scale-actual = Действителен размер
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Страница { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Получи се грешка при зареждане на PDF-а.
+pdfjs-invalid-file-error = Невалиден или повреден PDF файл.
+pdfjs-missing-file-error = Липсващ PDF файл.
+pdfjs-unexpected-response-error = Неочакван отговор от сървъра.
+pdfjs-rendering-error = Грешка при изчертаване на страницата.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Анотация { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Въведете парола за отваряне на този PDF файл.
+pdfjs-password-invalid = Невалидна парола. Моля, опитайте отново.
+pdfjs-password-ok-button = Добре
+pdfjs-password-cancel-button = Отказ
+pdfjs-web-fonts-disabled = Уеб-шрифтовете са забранени: разрешаване на използването на вградените PDF шрифтове.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Текст
+pdfjs-editor-free-text-button-label = Текст
+pdfjs-editor-ink-button =
+ .title = Рисуване
+pdfjs-editor-ink-button-label = Рисуване
+pdfjs-editor-stamp-button =
+ .title = Добавяне или променяне на изображения
+pdfjs-editor-stamp-button-label = Добавяне или променяне на изображения
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Премахване на рисунката
+pdfjs-editor-remove-freetext-button =
+ .title = Премахване на текста
+pdfjs-editor-remove-stamp-button =
+ .title = Пермахване на изображението
+pdfjs-editor-remove-highlight-button =
+ .title = Премахване на открояването
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Цвят
+pdfjs-editor-free-text-size-input = Размер
+pdfjs-editor-ink-color-input = Цвят
+pdfjs-editor-ink-thickness-input = Дебелина
+pdfjs-editor-ink-opacity-input = Прозрачност
+pdfjs-editor-stamp-add-image-button =
+ .title = Добавяне на изображение
+pdfjs-editor-stamp-add-image-button-label = Добавяне на изображение
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Текстов редактор
+ .default-content = Започнете да пишете…
+pdfjs-editor-comments-sidebar-close-button-label = Затваряне на страничната лента
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Алтернативен текст
+pdfjs-editor-alt-text-dialog-label = Изберете от възможностите
+pdfjs-editor-alt-text-dialog-description = Алтернативният текст помага на потребителите, когато не могат да видят изображението или то не се зарежда.
+pdfjs-editor-alt-text-add-description-label = Добавяне на описание
+pdfjs-editor-alt-text-add-description-description = Стремете се към 1-2 изречения, описващи предмета, настройката или действията.
+pdfjs-editor-alt-text-mark-decorative-label = Отбелязване като декоративно
+pdfjs-editor-alt-text-mark-decorative-description = Използва се за орнаменти или декоративни изображения, като контури и водни знаци.
+pdfjs-editor-alt-text-cancel-button = Отказ
+pdfjs-editor-alt-text-save-button = Запазване
+pdfjs-editor-alt-text-decorative-tooltip = Отбелязване като декоративно
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Например, „Млад мъж седи на маса и се храни“
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Горен ляв ъгъл — преоразмеряване
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Горе в средата — преоразмеряване
+pdfjs-editor-resizer-top-right =
+ .aria-label = Горен десен ъгъл — преоразмеряване
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Дясно в средата — преоразмеряване
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Долен десен ъгъл — преоразмеряване
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Долу в средата — преоразмеряване
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Долен ляв ъгъл — преоразмеряване
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Ляво в средата — преоразмеряване
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Цвят на открояване
+pdfjs-editor-colorpicker-button =
+ .title = Промяна на цвят
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Избор на цвят
+pdfjs-editor-colorpicker-yellow =
+ .title = Жълто
+pdfjs-editor-colorpicker-green =
+ .title = Зелено
+pdfjs-editor-colorpicker-blue =
+ .title = Синьо
+pdfjs-editor-colorpicker-pink =
+ .title = Розово
+pdfjs-editor-colorpicker-red =
+ .title = Червено
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Научете повече
+pdfjs-editor-new-alt-text-not-now-button = Не сега
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-delete-model-button = Изтриване
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Показване на заместващ текстов редактор веднага при добавяне на изображение
+
+## Controls
+
+pdfjs-editor-add-signature-image-upload-error-description = Проверете мрежовата си връзка или опитайте с друго изображение.
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-button1-label = Управление на страници
+pdfjs-views-manager-pages-status-action-button-label = Управление
+pdfjs-toggle-views-manager-button1 =
+ .title = Управление на страници
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-expired = Сертификат: с изтекъл срок на валидност
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bn/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bn/viewer.ftl
new file mode 100644
index 0000000..7ca2c1d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bn/viewer.ftl
@@ -0,0 +1,218 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = পূর্ববর্তী পাতা
+pdfjs-previous-button-label = পূর্ববর্তী
+pdfjs-next-button =
+ .title = পরবর্তী পাতা
+pdfjs-next-button-label = পরবর্তী
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = পাতা
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } এর
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } এর { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = ছোট আকারে প্রদর্শন
+pdfjs-zoom-out-button-label = ছোট আকারে প্রদর্শন
+pdfjs-zoom-in-button =
+ .title = বড় আকারে প্রদর্শন
+pdfjs-zoom-in-button-label = বড় আকারে প্রদর্শন
+pdfjs-zoom-select =
+ .title = বড় আকারে প্রদর্শন
+pdfjs-presentation-mode-button =
+ .title = উপস্থাপনা মোডে স্যুইচ করুন
+pdfjs-presentation-mode-button-label = উপস্থাপনা মোড
+pdfjs-open-file-button =
+ .title = ফাইল খুলুন
+pdfjs-open-file-button-label = খুলুন
+pdfjs-print-button =
+ .title = মুদ্রণ
+pdfjs-print-button-label = মুদ্রণ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = টুল
+pdfjs-tools-button-label = টুল
+pdfjs-first-page-button =
+ .title = প্রথম পাতায় যাও
+pdfjs-first-page-button-label = প্রথম পাতায় যাও
+pdfjs-last-page-button =
+ .title = শেষ পাতায় যাও
+pdfjs-last-page-button-label = শেষ পাতায় যাও
+pdfjs-page-rotate-cw-button =
+ .title = ঘড়ির কাঁটার দিকে ঘোরাও
+pdfjs-page-rotate-cw-button-label = ঘড়ির কাঁটার দিকে ঘোরাও
+pdfjs-page-rotate-ccw-button =
+ .title = ঘড়ির কাঁটার বিপরীতে ঘোরাও
+pdfjs-page-rotate-ccw-button-label = ঘড়ির কাঁটার বিপরীতে ঘোরাও
+pdfjs-cursor-text-select-tool-button =
+ .title = লেখা নির্বাচক টুল সক্রিয় করুন
+pdfjs-cursor-text-select-tool-button-label = লেখা নির্বাচক টুল
+pdfjs-cursor-hand-tool-button =
+ .title = হ্যান্ড টুল সক্রিয় করুন
+pdfjs-cursor-hand-tool-button-label = হ্যান্ড টুল
+pdfjs-scroll-vertical-button =
+ .title = উলম্ব স্ক্রলিং ব্যবহার করুন
+pdfjs-scroll-vertical-button-label = উলম্ব স্ক্রলিং
+pdfjs-scroll-horizontal-button =
+ .title = অনুভূমিক স্ক্রলিং ব্যবহার করুন
+pdfjs-scroll-horizontal-button-label = অনুভূমিক স্ক্রলিং
+pdfjs-scroll-wrapped-button =
+ .title = Wrapped স্ক্রোলিং ব্যবহার করুন
+pdfjs-scroll-wrapped-button-label = Wrapped স্ক্রোলিং
+pdfjs-spread-none-button =
+ .title = পেজ স্প্রেডগুলোতে যোগদান করবেন না
+pdfjs-spread-none-button-label = Spreads নেই
+pdfjs-spread-odd-button-label = বিজোড় Spreads
+pdfjs-spread-even-button-label = জোড় Spreads
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = নথি বৈশিষ্ট্য…
+pdfjs-document-properties-button-label = নথি বৈশিষ্ট্য…
+pdfjs-document-properties-file-name = ফাইলের নাম:
+pdfjs-document-properties-file-size = ফাইলের আকার:
+pdfjs-document-properties-title = শিরোনাম:
+pdfjs-document-properties-author = লেখক:
+pdfjs-document-properties-subject = বিষয়:
+pdfjs-document-properties-keywords = কীওয়ার্ড:
+pdfjs-document-properties-creation-date = তৈরির তারিখ:
+pdfjs-document-properties-modification-date = পরিবর্তনের তারিখ:
+pdfjs-document-properties-creator = প্রস্তুতকারক:
+pdfjs-document-properties-producer = পিডিএফ প্রস্তুতকারক:
+pdfjs-document-properties-version = পিডিএফ সংষ্করণ:
+pdfjs-document-properties-page-count = মোট পাতা:
+pdfjs-document-properties-page-size = পাতার সাইজ:
+pdfjs-document-properties-page-size-unit-inches = এর মধ্যে
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = উলম্ব
+pdfjs-document-properties-page-size-orientation-landscape = অনুভূমিক
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = লেটার
+pdfjs-document-properties-page-size-name-legal = লীগাল
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = হ্যাঁ
+pdfjs-document-properties-linearized-no = না
+pdfjs-document-properties-close-button = বন্ধ
+
+## Print
+
+pdfjs-print-progress-message = মুদ্রণের জন্য নথি প্রস্তুত করা হচ্ছে…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = বাতিল
+pdfjs-printing-not-supported = সতর্কতা: এই ব্রাউজারে মুদ্রণ সম্পূর্ণভাবে সমর্থিত নয়।
+pdfjs-printing-not-ready = সতর্কীকরণ: পিডিএফটি মুদ্রণের জন্য সম্পূর্ণ লোড হয়নি।
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = সাইডবার টগল করুন
+pdfjs-toggle-sidebar-button-label = সাইডবার টগল করুন
+pdfjs-document-outline-button =
+ .title = নথির আউটলাইন দেখাও (সব আইটেম প্রসারিত/সঙ্কুচিত করতে ডবল ক্লিক করুন)
+pdfjs-document-outline-button-label = নথির রূপরেখা
+pdfjs-attachments-button =
+ .title = সংযুক্তি দেখাও
+pdfjs-attachments-button-label = সংযুক্তি
+pdfjs-thumbs-button =
+ .title = থাম্বনেইল সমূহ প্রদর্শন করুন
+pdfjs-thumbs-button-label = থাম্বনেইল সমূহ
+pdfjs-findbar-button =
+ .title = নথির মধ্যে খুঁজুন
+pdfjs-findbar-button-label = খুঁজুন
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = পাতা { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } পাতার থাম্বনেইল
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = খুঁজুন
+ .placeholder = নথির মধ্যে খুঁজুন…
+pdfjs-find-previous-button =
+ .title = বাক্যাংশের পূর্ববর্তী উপস্থিতি অনুসন্ধান
+pdfjs-find-previous-button-label = পূর্ববর্তী
+pdfjs-find-next-button =
+ .title = বাক্যাংশের পরবর্তী উপস্থিতি অনুসন্ধান
+pdfjs-find-next-button-label = পরবর্তী
+pdfjs-find-highlight-checkbox = সব হাইলাইট করুন
+pdfjs-find-match-case-checkbox-label = অক্ষরের ছাঁদ মেলানো
+pdfjs-find-entire-word-checkbox-label = সম্পূর্ণ শব্দ
+pdfjs-find-reached-top = পাতার শুরুতে পৌছে গেছে, নীচ থেকে আরম্ভ করা হয়েছে
+pdfjs-find-reached-bottom = পাতার শেষে পৌছে গেছে, উপর থেকে আরম্ভ করা হয়েছে
+pdfjs-find-not-found = বাক্যাংশ পাওয়া যায়নি
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = পাতার প্রস্থ
+pdfjs-page-scale-fit = পাতা ফিট করুন
+pdfjs-page-scale-auto = স্বয়ংক্রিয় জুম
+pdfjs-page-scale-actual = প্রকৃত আকার
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = পিডিএফ লোড করার সময় ত্রুটি দেখা দিয়েছে।
+pdfjs-invalid-file-error = অকার্যকর অথবা ক্ষতিগ্রস্ত পিডিএফ ফাইল।
+pdfjs-missing-file-error = নিখোঁজ PDF ফাইল।
+pdfjs-unexpected-response-error = অপ্রত্যাশীত সার্ভার প্রতিক্রিয়া।
+pdfjs-rendering-error = পাতা উপস্থাপনার সময় ত্রুটি দেখা দিয়েছে।
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } টীকা]
+
+## Password
+
+pdfjs-password-label = পিডিএফ ফাইলটি ওপেন করতে পাসওয়ার্ড দিন।
+pdfjs-password-invalid = ভুল পাসওয়ার্ড। অনুগ্রহ করে আবার চেষ্টা করুন।
+pdfjs-password-ok-button = ঠিক আছে
+pdfjs-password-cancel-button = বাতিল
+pdfjs-web-fonts-disabled = ওয়েব ফন্ট নিষ্ক্রিয়: সংযুক্ত পিডিএফ ফন্ট ব্যবহার করা যাচ্ছে না।
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bo/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bo/viewer.ftl
new file mode 100644
index 0000000..4bea897
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bo/viewer.ftl
@@ -0,0 +1,222 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = དྲ་ངོས་སྔོན་མ
+pdfjs-previous-button-label = སྔོན་མ
+pdfjs-next-button =
+ .title = དྲ་ངོས་རྗེས་མ
+pdfjs-next-button-label = རྗེས་མ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ཤོག་ངོས
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = of { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom Out
+pdfjs-zoom-out-button-label = Zoom Out
+pdfjs-zoom-in-button =
+ .title = Zoom In
+pdfjs-zoom-in-button-label = Zoom In
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Switch to Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Open File
+pdfjs-open-file-button-label = Open
+pdfjs-print-button =
+ .title = Print
+pdfjs-print-button-label = Print
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tools
+pdfjs-tools-button-label = Tools
+pdfjs-first-page-button =
+ .title = Go to First Page
+pdfjs-first-page-button-label = Go to First Page
+pdfjs-last-page-button =
+ .title = Go to Last Page
+pdfjs-last-page-button-label = Go to Last Page
+pdfjs-page-rotate-cw-button =
+ .title = Rotate Clockwise
+pdfjs-page-rotate-cw-button-label = Rotate Clockwise
+pdfjs-page-rotate-ccw-button =
+ .title = Rotate Counterclockwise
+pdfjs-page-rotate-ccw-button-label = Rotate Counterclockwise
+pdfjs-cursor-text-select-tool-button =
+ .title = Enable Text Selection Tool
+pdfjs-cursor-text-select-tool-button-label = Text Selection Tool
+pdfjs-cursor-hand-tool-button =
+ .title = Enable Hand Tool
+pdfjs-cursor-hand-tool-button-label = Hand Tool
+pdfjs-scroll-vertical-button =
+ .title = Use Vertical Scrolling
+pdfjs-scroll-vertical-button-label = Vertical Scrolling
+pdfjs-scroll-horizontal-button =
+ .title = Use Horizontal Scrolling
+pdfjs-scroll-horizontal-button-label = Horizontal Scrolling
+pdfjs-scroll-wrapped-button =
+ .title = Use Wrapped Scrolling
+pdfjs-scroll-wrapped-button-label = Wrapped Scrolling
+pdfjs-spread-none-button =
+ .title = Do not join page spreads
+pdfjs-spread-none-button-label = No Spreads
+pdfjs-spread-odd-button =
+ .title = Join page spreads starting with odd-numbered pages
+pdfjs-spread-odd-button-label = Odd Spreads
+pdfjs-spread-even-button =
+ .title = Join page spreads starting with even-numbered pages
+pdfjs-spread-even-button-label = Even Spreads
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Document Properties…
+pdfjs-document-properties-button-label = Document Properties…
+pdfjs-document-properties-file-name = File name:
+pdfjs-document-properties-file-size = File size:
+pdfjs-document-properties-title = Title:
+pdfjs-document-properties-author = Author:
+pdfjs-document-properties-subject = Subject:
+pdfjs-document-properties-keywords = Keywords:
+pdfjs-document-properties-creation-date = Creation Date:
+pdfjs-document-properties-modification-date = Modification Date:
+pdfjs-document-properties-creator = Creator:
+pdfjs-document-properties-producer = PDF Producer:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Page Count:
+pdfjs-document-properties-page-size = Page Size:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = landscape
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Yes
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Close
+
+## Print
+
+pdfjs-print-progress-message = Preparing document for printing…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancel
+pdfjs-printing-not-supported = Warning: Printing is not fully supported by this browser.
+pdfjs-printing-not-ready = Warning: The PDF is not fully loaded for printing.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toggle Sidebar
+pdfjs-toggle-sidebar-button-label = Toggle Sidebar
+pdfjs-document-outline-button =
+ .title = Show Document Outline (double-click to expand/collapse all items)
+pdfjs-document-outline-button-label = Document Outline
+pdfjs-attachments-button =
+ .title = Show Attachments
+pdfjs-attachments-button-label = Attachments
+pdfjs-thumbs-button =
+ .title = Show Thumbnails
+pdfjs-thumbs-button-label = Thumbnails
+pdfjs-findbar-button =
+ .title = Find in Document
+pdfjs-findbar-button-label = Find
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail of Page { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Find
+ .placeholder = Find in document…
+pdfjs-find-previous-button =
+ .title = Find the previous occurrence of the phrase
+pdfjs-find-previous-button-label = Previous
+pdfjs-find-next-button =
+ .title = Find the next occurrence of the phrase
+pdfjs-find-next-button-label = Next
+pdfjs-find-highlight-checkbox = Highlight all
+pdfjs-find-match-case-checkbox-label = Match case
+pdfjs-find-entire-word-checkbox-label = Whole words
+pdfjs-find-reached-top = Reached top of document, continued from bottom
+pdfjs-find-reached-bottom = Reached end of document, continued from top
+pdfjs-find-not-found = Phrase not found
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Page Width
+pdfjs-page-scale-fit = Page Fit
+pdfjs-page-scale-auto = Automatic Zoom
+pdfjs-page-scale-actual = Actual Size
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = An error occurred while loading the PDF.
+pdfjs-invalid-file-error = Invalid or corrupted PDF file.
+pdfjs-missing-file-error = Missing PDF file.
+pdfjs-unexpected-response-error = Unexpected server response.
+pdfjs-rendering-error = An error occurred while rendering the page.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = Enter the password to open this PDF file.
+pdfjs-password-invalid = Invalid password. Please try again.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancel
+pdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bqi/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bqi/viewer.ftl
new file mode 100644
index 0000000..a08758e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bqi/viewer.ftl
@@ -0,0 +1,325 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = بلگه دیندایی
+pdfjs-previous-button-label = دیندایی
+pdfjs-next-button =
+ .title = بلگه نیایی
+pdfjs-next-button-label = بئڌی
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = بلگه
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = ز { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } ز { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = کۊچیر نمایی
+pdfjs-zoom-out-button-label = کۊچیر نمایی
+pdfjs-zoom-in-button =
+ .title = گپ نمایی
+pdfjs-zoom-in-button-label = گپ نمایی
+pdfjs-zoom-select =
+ .title = زۊم کردن
+pdfjs-open-file-button =
+ .title = گۊشیڌن فایل
+pdfjs-open-file-button-label = گۊشیڌن
+pdfjs-print-button =
+ .title = چاپ
+pdfjs-print-button-label = چاپ
+pdfjs-save-button =
+ .title = زفت
+pdfjs-save-button-label = زفت
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = دانلود
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = دانلود
+pdfjs-bookmark-button-label = بلگه هیم سکویی
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ٱوزارا
+pdfjs-tools-button-label = ٱوزارا
+pdfjs-first-page-button =
+ .title = رئڌن و بلگه نیایی
+pdfjs-first-page-button-label = رئڌن و بلگه نیایی
+pdfjs-last-page-button =
+ .title = رئڌن و بلگه دیندایی
+pdfjs-last-page-button-label = رئڌن و بلگه دیندایی
+pdfjs-page-rotate-cw-button =
+ .title = لر خردن ساعتگرد
+pdfjs-page-rotate-cw-button-label = لر خردن ساعتگرد
+pdfjs-page-rotate-ccw-button =
+ .title = لر خردن خلاف ساعتگرد
+pdfjs-page-rotate-ccw-button-label = لر خردن خلاف ساعتگرد
+pdfjs-cursor-text-select-tool-button =
+ .title = فعال کردن ٱوزار پسند هؽل
+pdfjs-cursor-text-select-tool-button-label = ٱوزار پسند هؽل
+pdfjs-cursor-hand-tool-button =
+ .title = فعال کردن ٱوزار دست
+pdfjs-cursor-hand-tool-button-label = ٱوزار دست
+pdfjs-scroll-page-button =
+ .title = و کار گرؽڌن اسکرۊل بلگه
+pdfjs-scroll-page-button-label = اسکرۊل بلگه
+pdfjs-scroll-vertical-button =
+ .title = و کار گرؽڌن اسکرۊل عمۊدی
+pdfjs-scroll-vertical-button-label = اسکرۊل عمۊدی
+pdfjs-scroll-horizontal-button =
+ .title = و کار گرؽڌن اسکرۊل اوفوقی
+pdfjs-scroll-horizontal-button-label = اسکرۊل اوفوقی
+pdfjs-scroll-wrapped-button =
+ .title = و کار گرؽڌن اسکرۊل پؽچسته
+pdfjs-scroll-wrapped-button-label = اسکرۊل پؽچسته
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = خۊسۊسیات سند…
+pdfjs-document-properties-button-label = خۊسۊسیات سند…
+pdfjs-document-properties-file-name = نوم فایل:
+pdfjs-document-properties-file-size = هندا فایل:
+pdfjs-document-properties-title = عونوان:
+pdfjs-document-properties-author = هؽل کوݩ:
+pdfjs-document-properties-subject = سرتال:
+pdfjs-document-properties-creation-date = تاریخ وورکل وابیڌن:
+pdfjs-document-properties-modification-date = تاریخ آلشتکاری:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = وورکل کون:
+pdfjs-document-properties-producer = وورکل کون PDF:
+pdfjs-document-properties-version = نوسخه PDF:
+pdfjs-document-properties-page-count = تئداد بلگه یل:
+pdfjs-document-properties-page-size = هندا بلگه:
+pdfjs-document-properties-page-size-unit-inches = اینچ
+pdfjs-document-properties-page-size-unit-millimeters = میلی متر
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = landscape
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = نامه
+pdfjs-document-properties-page-size-name-legal = هۊقۊقی
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = نیشتن زل وب:
+pdfjs-document-properties-linearized-yes = هری
+pdfjs-document-properties-linearized-no = ن
+pdfjs-document-properties-close-button = بستن
+
+## Print
+
+pdfjs-print-progress-message = ٱماڌه کردن سند سی چاپ کردن…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = لقو
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = آلشت هالت نوار کلی
+pdfjs-toggle-sidebar-button-label = آلشت هالت نوار کلی
+pdfjs-document-outline-button-label = تئر سند
+pdfjs-attachments-button =
+ .title = نشووݩ داڌن پیوستا
+pdfjs-attachments-button-label = پیوستا
+pdfjs-layers-button-label = لایه یل
+pdfjs-thumbs-button =
+ .title = نشووݩ داڌن شؽواتا کۊچیر
+pdfjs-thumbs-button-label = شؽواتا کۊچیر
+pdfjs-findbar-button =
+ .title = جوستن من سند
+pdfjs-findbar-button-label = جوستن
+pdfjs-additional-layers = لایه یل ازافه
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = بلگه { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-previous-button-label = دیندایی
+pdfjs-find-next-button-label = بئڌی
+pdfjs-find-highlight-checkbox = هایلایت کردن پوی
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = پئنا بلگه
+pdfjs-page-scale-fit = هندا کردن بلگه
+pdfjs-page-scale-auto = زۊم کردن خوتکار
+pdfjs-page-scale-actual = هندا واقعی
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = بلگه { $page }
+
+## Annotations
+
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-ok-button = خا
+pdfjs-password-cancel-button = لقو
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = هؽل
+pdfjs-editor-free-text-button-label = هؽل
+pdfjs-editor-ink-button =
+ .title = کشیڌن
+pdfjs-editor-ink-button-label = کشیڌن
+pdfjs-editor-stamp-button =
+ .title = ٱووردن یا آلشت شؽواتا
+pdfjs-editor-stamp-button-label = ٱووردن یا آلشت شؽواتا
+
+## Default editor aria labels
+
+pdfjs-editor-stamp-editor =
+ .aria-label = آلشتگر شؽوات
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = رنگ
+pdfjs-editor-free-text-size-input = هندا
+pdfjs-editor-ink-color-input = رنگ
+pdfjs-editor-ink-thickness-input = کۊلۊفتی
+pdfjs-editor-ink-opacity-input = کر بیڌن
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = کۊلۊفتی
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = آلشتگر هؽل
+ .default-content = ناهاڌن پا هؽل کردن...
+pdfjs-editor-comments-sidebar-no-comments-link = قلوه دووسته بۊین
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-cancel-button = لقو
+pdfjs-editor-alt-text-save-button = زفت
+
+## Color picker
+
+pdfjs-editor-colorpicker-yellow =
+ .title = هیل
+pdfjs-editor-colorpicker-green =
+ .title = ساوز
+pdfjs-editor-colorpicker-blue =
+ .title = کوۊ
+pdfjs-editor-colorpicker-pink =
+ .title = آل
+pdfjs-editor-colorpicker-red =
+ .title = سوئر
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = نشووݩ داڌن پوی
+pdfjs-editor-highlight-show-all-button =
+ .title = نشووݩ داڌن پوی
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = قلوه دووسته بۊین
+pdfjs-editor-new-alt-text-not-now-button = سکو ن
+pdfjs-editor-new-alt-text-error-close-button = بستن
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-undo-button-label = وورگندن
+pdfjs-editor-undo-bar-close-button =
+ .title = بستن
+pdfjs-editor-undo-bar-close-button-label = بستن
+
+## Tab panels
+
+pdfjs-editor-add-signature-draw-thickness-range-label = کۊلۊفتی
+
+## Controls
+
+pdfjs-editor-add-signature-error-close-button = بستن
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = لقو
+pdfjs-editor-add-signature-add-button = ٱووردن
+pdfjs-editor-edit-signature-update-button = ورۊ رسۊوی
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = آلشت منشڌ
+pdfjs-editor-edit-comment-popup-button =
+ .title = آلشت منشڌ
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = آلشت منشڌ
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = ورۊ رسۊوی
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = ٱووردن
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = ناهاڌن پا هؽل کردن…
+pdfjs-editor-edit-comment-dialog-cancel-button = لقو
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-views-manager-sidebar =
+ .aria-label = نوار کلی
+pdfjs-views-manager-layers-option-label = لایه یل
+pdfjs-views-manager-pages-status-action-button-label = دؽوۉداری
+pdfjs-views-manager-pages-status-copy-button-label = لف گیری
+pdfjs-views-manager-pages-status-cut-button-label = بۊریڌن
+pdfjs-views-manager-pages-status-delete-button-label = پاک کردن
+pdfjs-views-manager-status-undo-button-label = وورگندن
+pdfjs-views-manager-status-done-button-label = ٱنجوم وابی
+pdfjs-views-manager-status-close-button =
+ .title = بستن
+pdfjs-views-manager-status-close-button-label = بستن
+pdfjs-views-manager-paste-button-label = جا وندن
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = نۊ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/br/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/br/viewer.ftl
new file mode 100644
index 0000000..1f86d46
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/br/viewer.ftl
@@ -0,0 +1,323 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pajenn a-raok
+pdfjs-previous-button-label = A-raok
+pdfjs-next-button =
+ .title = Pajenn war-lerc'h
+pdfjs-next-button-label = War-lerc'h
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pajenn
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = eus { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } war { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoum bihanaat
+pdfjs-zoom-out-button-label = Zoum bihanaat
+pdfjs-zoom-in-button =
+ .title = Zoum brasaat
+pdfjs-zoom-in-button-label = Zoum brasaat
+pdfjs-zoom-select =
+ .title = Zoum
+pdfjs-presentation-mode-button =
+ .title = Trec'haoliñ etrezek ar mod kinnigadenn
+pdfjs-presentation-mode-button-label = Mod kinnigadenn
+pdfjs-open-file-button =
+ .title = Digeriñ ur restr
+pdfjs-open-file-button-label = Digeriñ ur restr
+pdfjs-print-button =
+ .title = Moullañ
+pdfjs-print-button-label = Moullañ
+pdfjs-save-button =
+ .title = Enrollañ
+pdfjs-save-button-label = Enrollañ
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Pellgargañ
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Pellgargañ
+pdfjs-bookmark-button-label = Pajenn a-vremañ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ostilhoù
+pdfjs-tools-button-label = Ostilhoù
+pdfjs-first-page-button =
+ .title = Mont d'ar bajenn gentañ
+pdfjs-first-page-button-label = Mont d'ar bajenn gentañ
+pdfjs-last-page-button =
+ .title = Mont d'ar bajenn diwezhañ
+pdfjs-last-page-button-label = Mont d'ar bajenn diwezhañ
+pdfjs-page-rotate-cw-button =
+ .title = C'hwelañ gant roud ar bizied
+pdfjs-page-rotate-cw-button-label = C'hwelañ gant roud ar bizied
+pdfjs-page-rotate-ccw-button =
+ .title = C'hwelañ gant roud gin ar bizied
+pdfjs-page-rotate-ccw-button-label = C'hwelañ gant roud gin ar bizied
+pdfjs-cursor-text-select-tool-button =
+ .title = Gweredekaat an ostilh diuzañ testenn
+pdfjs-cursor-text-select-tool-button-label = Ostilh diuzañ testenn
+pdfjs-cursor-hand-tool-button =
+ .title = Gweredekaat an ostilh dorn
+pdfjs-cursor-hand-tool-button-label = Ostilh dorn
+pdfjs-scroll-vertical-button =
+ .title = Arverañ an dibunañ a-blom
+pdfjs-scroll-vertical-button-label = Dibunañ a-serzh
+pdfjs-scroll-horizontal-button =
+ .title = Arverañ an dibunañ a-blaen
+pdfjs-scroll-horizontal-button-label = Dibunañ a-blaen
+pdfjs-scroll-wrapped-button =
+ .title = Arverañ an dibunañ paket
+pdfjs-scroll-wrapped-button-label = Dibunañ paket
+pdfjs-spread-none-button =
+ .title = Chom hep stagañ ar skignadurioù
+pdfjs-spread-none-button-label = Skignadenn ebet
+pdfjs-spread-odd-button =
+ .title = Lakaat ar pajennadoù en ur gregiñ gant ar pajennoù ampar
+pdfjs-spread-odd-button-label = Pajennoù ampar
+pdfjs-spread-even-button =
+ .title = Lakaat ar pajennadoù en ur gregiñ gant ar pajennoù par
+pdfjs-spread-even-button-label = Pajennoù par
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Perzhioù an teul…
+pdfjs-document-properties-button-label = Perzhioù an teul…
+pdfjs-document-properties-file-name = Anv restr:
+pdfjs-document-properties-file-size = Ment ar restr:
+pdfjs-document-properties-title = Titl:
+pdfjs-document-properties-author = Aozer:
+pdfjs-document-properties-subject = Danvez:
+pdfjs-document-properties-keywords = Gerioù-alc'hwez:
+pdfjs-document-properties-creation-date = Deiziad krouiñ:
+pdfjs-document-properties-modification-date = Deiziad kemmañ:
+pdfjs-document-properties-creator = Krouer:
+pdfjs-document-properties-producer = Kenderc'her PDF:
+pdfjs-document-properties-version = Handelv PDF:
+pdfjs-document-properties-page-count = Niver a bajennoù:
+pdfjs-document-properties-page-size = Ment ar bajenn:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = poltred
+pdfjs-document-properties-page-size-orientation-landscape = gweledva
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Lizher
+pdfjs-document-properties-page-size-name-legal = Lezennel
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Gwel Web Herrek:
+pdfjs-document-properties-linearized-yes = Ya
+pdfjs-document-properties-linearized-no = Ket
+pdfjs-document-properties-close-button = Serriñ
+
+## Print
+
+pdfjs-print-progress-message = O prientiñ an teul evit moullañ...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Nullañ
+pdfjs-printing-not-supported = Kemenn: N'eo ket skoret penn-da-benn ar moullañ gant ar merdeer-mañ.
+pdfjs-printing-not-ready = Kemenn: N'hall ket bezañ moullet ar restr PDF rak n'eo ket karget penn-da-benn.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Diskouez/kuzhat ar varrenn gostez
+pdfjs-toggle-sidebar-notification-button =
+ .title = Trec'haoliñ ar varrenn-gostez (ur steuñv pe stagadennoù a zo en teul)
+pdfjs-toggle-sidebar-button-label = Diskouez/kuzhat ar varrenn gostez
+pdfjs-document-outline-button =
+ .title = Diskouez steuñv an teul (daouglikit evit brasaat/bihanaat an holl elfennoù)
+pdfjs-document-outline-button-label = Sinedoù an teuliad
+pdfjs-attachments-button =
+ .title = Diskouez ar c'henstagadurioù
+pdfjs-attachments-button-label = Kenstagadurioù
+pdfjs-layers-button =
+ .title = Diskouez ar gwiskadoù (daou-glikañ evit adderaouekaat an holl gwiskadoù d'o stad dre ziouer)
+pdfjs-layers-button-label = Gwiskadoù
+pdfjs-thumbs-button =
+ .title = Diskouez ar melvennoù
+pdfjs-thumbs-button-label = Melvennoù
+pdfjs-findbar-button =
+ .title = Klask e-barzh an teuliad
+pdfjs-findbar-button-label = Klask
+pdfjs-additional-layers = Gwiskadoù ouzhpenn
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pajenn { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Melvenn ar bajenn { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Klask
+ .placeholder = Klask e-barzh an teuliad
+pdfjs-find-previous-button =
+ .title = Kavout an tamm frazenn kent o klotañ ganti
+pdfjs-find-previous-button-label = Kent
+pdfjs-find-next-button =
+ .title = Kavout an tamm frazenn war-lerc'h o klotañ ganti
+pdfjs-find-next-button-label = War-lerc'h
+pdfjs-find-highlight-checkbox = Sklêrijennañ pep tra
+pdfjs-find-match-case-checkbox-label = Teurel evezh ouzh ar pennlizherennoù
+pdfjs-find-match-diacritics-checkbox-label = Doujañ d’an tiredoù
+pdfjs-find-entire-word-checkbox-label = Gerioù a-bezh
+pdfjs-find-reached-top = Tizhet eo bet derou ar bajenn, kenderc'hel diouzh an diaz
+pdfjs-find-reached-bottom = Tizhet eo bet dibenn ar bajenn, kenderc'hel diouzh ar c'hrec'h
+pdfjs-find-not-found = N'haller ket kavout ar frazenn
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Led ar bajenn
+pdfjs-page-scale-fit = Pajenn a-bezh
+pdfjs-page-scale-auto = Zoum emgefreek
+pdfjs-page-scale-actual = Ment wir
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pajenn { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Degouezhet ez eus bet ur fazi e-pad kargañ ar PDF.
+pdfjs-invalid-file-error = Restr PDF didalvoudek pe kontronet.
+pdfjs-missing-file-error = Restr PDF o vankout.
+pdfjs-unexpected-response-error = Respont dic'hortoz a-berzh an dafariad
+pdfjs-rendering-error = Degouezhet ez eus bet ur fazi e-pad skrammañ ar bajennad.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Notennañ]
+
+## Password
+
+pdfjs-password-label = Enankit ar ger-tremen evit digeriñ ar restr PDF-mañ.
+pdfjs-password-invalid = Ger-tremen didalvoudek. Klaskit en-dro mar plij.
+pdfjs-password-ok-button = Mat eo
+pdfjs-password-cancel-button = Nullañ
+pdfjs-web-fonts-disabled = Diweredekaet eo an nodrezhoù web: n'haller ket arverañ an nodrezhoù PDF enframmet.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Testenn
+pdfjs-editor-free-text-button-label = Testenn
+pdfjs-editor-ink-button =
+ .title = Tresañ
+pdfjs-editor-ink-button-label = Tresañ
+pdfjs-editor-stamp-button =
+ .title = Ouzhpennañ pe aozañ skeudennoù
+pdfjs-editor-stamp-button-label = Ouzhpennañ pe aozañ skeudennoù
+pdfjs-editor-highlight-button =
+ .title = Sklerijennañ
+pdfjs-editor-highlight-button-label = Sklerijennañ
+pdfjs-highlight-floating-button1 =
+ .title = Sklerijennañ
+ .aria-label = Sklerijennañ
+pdfjs-highlight-floating-button-label = Sklerijennañ
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Liv
+pdfjs-editor-free-text-size-input = Ment
+pdfjs-editor-ink-color-input = Liv
+pdfjs-editor-ink-thickness-input = Tevder
+pdfjs-editor-ink-opacity-input = Boullder
+pdfjs-editor-stamp-add-image-button =
+ .title = Ouzhpennañ ur skeudenn
+pdfjs-editor-stamp-add-image-button-label = Ouzhpennañ ur skeudenn
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tevded
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-add-description-label = Ouzhpennañ un deskrivadur
+pdfjs-editor-alt-text-cancel-button = Nullañ
+pdfjs-editor-alt-text-save-button = Enrollañ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Da skouer, “Ur paotr yaouank ouzh taol o tebriñ boued”
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Liv sklêrijennañ
+pdfjs-editor-colorpicker-button =
+ .title = Cheñch liv
+pdfjs-editor-colorpicker-yellow =
+ .title = Melen
+pdfjs-editor-colorpicker-blue =
+ .title = Glas
+pdfjs-editor-colorpicker-pink =
+ .title = Roz
+pdfjs-editor-colorpicker-red =
+ .title = Ruz
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Diskouez pep tra
+pdfjs-editor-highlight-show-all-button =
+ .title = Diskouez pep tra
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Gouzout hiroc’h
+pdfjs-editor-new-alt-text-error-close-button = Serriñ
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-delete-model-button = Dilemel
+pdfjs-editor-alt-text-settings-download-model-button = Pellgargañ
+pdfjs-editor-alt-text-settings-downloading-model-button = O pellgargañ…
+pdfjs-editor-alt-text-settings-close-button = Serriñ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/brx/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/brx/viewer.ftl
new file mode 100644
index 0000000..bd44403
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/brx/viewer.ftl
@@ -0,0 +1,189 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = आगोलनि बिलाइ
+pdfjs-previous-button-label = आगोलनि
+pdfjs-next-button =
+ .title = उननि बिलाइ
+pdfjs-next-button-label = उननि
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = बिलाइ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } नि
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } नि { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = फिसायै जुम खालाम
+pdfjs-zoom-out-button-label = फिसायै जुम खालाम
+pdfjs-zoom-in-button =
+ .title = गेदेरै जुम खालाम
+pdfjs-zoom-in-button-label = गेदेरै जुम खालाम
+pdfjs-zoom-select =
+ .title = जुम खालाम
+pdfjs-presentation-mode-button =
+ .title = दिन्थिफुंनाय म'डआव थां
+pdfjs-presentation-mode-button-label = दिन्थिफुंनाय म'ड
+pdfjs-open-file-button =
+ .title = फाइलखौ खेव
+pdfjs-open-file-button-label = खेव
+pdfjs-print-button =
+ .title = साफाय
+pdfjs-print-button-label = साफाय
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = टुल
+pdfjs-tools-button-label = टुल
+pdfjs-first-page-button =
+ .title = गिबि बिलाइआव थां
+pdfjs-first-page-button-label = गिबि बिलाइआव थां
+pdfjs-last-page-button =
+ .title = जोबथा बिलाइआव थां
+pdfjs-last-page-button-label = जोबथा बिलाइआव थां
+pdfjs-page-rotate-cw-button =
+ .title = घरि गिदिंनाय फार्से फिदिं
+pdfjs-page-rotate-cw-button-label = घरि गिदिंनाय फार्से फिदिं
+pdfjs-page-rotate-ccw-button =
+ .title = घरि गिदिंनाय उल्था फार्से फिदिं
+pdfjs-page-rotate-ccw-button-label = घरि गिदिंनाय उल्था फार्से फिदिं
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = फोरमान बिलाइनि आखुथाय...
+pdfjs-document-properties-button-label = फोरमान बिलाइनि आखुथाय...
+pdfjs-document-properties-file-name = फाइलनि मुं:
+pdfjs-document-properties-file-size = फाइलनि महर:
+pdfjs-document-properties-title = बिमुं:
+pdfjs-document-properties-author = लिरगिरि:
+pdfjs-document-properties-subject = आयदा:
+pdfjs-document-properties-keywords = गाहाय सोदोब:
+pdfjs-document-properties-creation-date = सोरजिनाय अक्ट':
+pdfjs-document-properties-modification-date = सुद्रायनाय अक्ट':
+pdfjs-document-properties-creator = सोरजिग्रा:
+pdfjs-document-properties-producer = PDF दिहुनग्रा:
+pdfjs-document-properties-version = PDF बिसान:
+pdfjs-document-properties-page-count = बिलाइनि हिसाब:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = प'र्ट्रेट
+pdfjs-document-properties-page-size-orientation-landscape = लेण्डस्केप
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = लायजाम
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-linearized-yes = नंगौ
+pdfjs-document-properties-linearized-no = नङा
+pdfjs-document-properties-close-button = बन्द खालाम
+
+## Print
+
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = नेवसि
+pdfjs-printing-not-supported = सांग्रांथि: साफायनाया बे ब्राउजारजों आबुङै हेफाजाब होजाया।
+pdfjs-printing-not-ready = सांग्रांथि: PDF खौ साफायनायनि थाखाय फुरायै ल'ड खालामाखै।
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = टग्गल साइडबार
+pdfjs-toggle-sidebar-button-label = टग्गल साइडबार
+pdfjs-document-outline-button-label = फोरमान बिलाइ सिमा हांखो
+pdfjs-attachments-button =
+ .title = नांजाब होनायखौ दिन्थि
+pdfjs-attachments-button-label = नांजाब होनाय
+pdfjs-thumbs-button =
+ .title = थामनेइलखौ दिन्थि
+pdfjs-thumbs-button-label = थामनेइल
+pdfjs-findbar-button =
+ .title = फोरमान बिलाइआव नागिरना दिहुन
+pdfjs-findbar-button-label = नायगिरना दिहुन
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = बिलाइ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = बिलाइ { $page } नि थामनेइल
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = नायगिरना दिहुन
+ .placeholder = फोरमान बिलाइआव नागिरना दिहुन...
+pdfjs-find-previous-button =
+ .title = बाथ्रा खोन्दोबनि सिगांनि नुजाथिनायखौ नागिर
+pdfjs-find-previous-button-label = आगोलनि
+pdfjs-find-next-button =
+ .title = बाथ्रा खोन्दोबनि उननि नुजाथिनायखौ नागिर
+pdfjs-find-next-button-label = उननि
+pdfjs-find-highlight-checkbox = गासैखौबो हाइलाइट खालाम
+pdfjs-find-match-case-checkbox-label = गोरोबनाय केस
+pdfjs-find-reached-top = थालो निफ्राय जागायनानै फोरमान बिलाइनि बिजौआव सौहैबाय
+pdfjs-find-reached-bottom = बिजौ निफ्राय जागायनानै फोरमान बिलाइनि बिजौआव सौहैबाय
+pdfjs-find-not-found = बाथ्रा खोन्दोब मोनाखै
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = बिलाइनि गुवार
+pdfjs-page-scale-fit = बिलाइ गोरोबनाय
+pdfjs-page-scale-auto = गावनोगाव जुम
+pdfjs-page-scale-actual = थार महर
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF ल'ड खालामनाय समाव मोनसे गोरोन्थि जाबाय।
+pdfjs-invalid-file-error = बाहायजायै एबा गाज्रि जानाय PDF फाइल
+pdfjs-missing-file-error = गोमानाय PDF फाइल
+pdfjs-unexpected-response-error = मिजिंथियै सार्भार फिननाय।
+pdfjs-rendering-error = बिलाइखौ राव सोलायनाय समाव मोनसे गोरोन्थि जादों।
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } सोदोब बेखेवनाय]
+
+## Password
+
+pdfjs-password-label = बे PDF फाइलखौ खेवनो पासवार्ड हाबहो।
+pdfjs-password-invalid = बाहायजायै पासवार्ड। अननानै फिन नाजा।
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = नेवसि
+pdfjs-web-fonts-disabled = वेब फन्टखौ लोरबां खालामबाय: अरजाबहोनाय PDF फन्टखौ बाहायनो हायाखै।
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bs/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bs/viewer.ftl
new file mode 100644
index 0000000..f0a67ca
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/bs/viewer.ftl
@@ -0,0 +1,588 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Prethodna strana
+pdfjs-previous-button-label = Prethodna
+pdfjs-next-button =
+ .title = Sljedeća strna
+pdfjs-next-button-label = Sljedeća
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Strana
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = od { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } od { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Umanji
+pdfjs-zoom-out-button-label = Umanji
+pdfjs-zoom-in-button =
+ .title = Uvećaj
+pdfjs-zoom-in-button-label = Uvećaj
+pdfjs-zoom-select =
+ .title = Uvećanje
+pdfjs-presentation-mode-button =
+ .title = Prebaci se u prezentacijski režim
+pdfjs-presentation-mode-button-label = Prezentacijski režim
+pdfjs-open-file-button =
+ .title = Otvori fajl
+pdfjs-open-file-button-label = Otvori
+pdfjs-print-button =
+ .title = Štampaj
+pdfjs-print-button-label = Štampaj
+pdfjs-save-button =
+ .title = Sačuvaj
+pdfjs-save-button-label = Sačuvaj
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Preuzmi
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Preuzmi
+pdfjs-bookmark-button =
+ .title = Trenutna stranica (Prikaži URL sa trenutne stranice)
+pdfjs-bookmark-button-label = Trenutna stranica
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Alati
+pdfjs-tools-button-label = Alati
+pdfjs-first-page-button =
+ .title = Idi na prvu stranu
+pdfjs-first-page-button-label = Idi na prvu stranu
+pdfjs-last-page-button =
+ .title = Idi na zadnju stranu
+pdfjs-last-page-button-label = Idi na zadnju stranu
+pdfjs-page-rotate-cw-button =
+ .title = Rotiraj u smjeru kazaljke na satu
+pdfjs-page-rotate-cw-button-label = Rotiraj u smjeru kazaljke na satu
+pdfjs-page-rotate-ccw-button =
+ .title = Rotiraj suprotno smjeru kazaljke na satu
+pdfjs-page-rotate-ccw-button-label = Rotiraj suprotno smjeru kazaljke na satu
+pdfjs-cursor-text-select-tool-button =
+ .title = Omogući alat za označavanje teksta
+pdfjs-cursor-text-select-tool-button-label = Alat za označavanje teksta
+pdfjs-cursor-hand-tool-button =
+ .title = Omogući ručni alat
+pdfjs-cursor-hand-tool-button-label = Ručni alat
+pdfjs-scroll-page-button =
+ .title = Koristite pomicanje stranice
+pdfjs-scroll-page-button-label = Pomicanje stranice
+pdfjs-scroll-vertical-button =
+ .title = Koristite vertikalno pomicanje
+pdfjs-scroll-vertical-button-label = Vertikalno pomicanje
+pdfjs-scroll-horizontal-button =
+ .title = Koristite horizontalno pomicanje
+pdfjs-scroll-horizontal-button-label = Horizontalno pomicanje
+pdfjs-scroll-wrapped-button =
+ .title = Koristite omotno pomicanje
+pdfjs-scroll-wrapped-button-label = Omotno pomicanje
+pdfjs-spread-none-button =
+ .title = Ne izrađuj duplerice
+pdfjs-spread-none-button-label = Bez duplerica
+pdfjs-spread-odd-button =
+ .title = Izradi duplerice koje počinju s neparnim stranicama
+pdfjs-spread-odd-button-label = Neparne duplerice
+pdfjs-spread-even-button =
+ .title = Izradi duplerice koje počinju s parnim stranicama
+pdfjs-spread-even-button-label = Parne duplerice
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Svojstva dokumenta...
+pdfjs-document-properties-button-label = Svojstva dokumenta...
+pdfjs-document-properties-file-name = Naziv fajla:
+pdfjs-document-properties-file-size = Veličina fajla:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bajtova)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtova)
+pdfjs-document-properties-title = Naslov:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Predmet:
+pdfjs-document-properties-keywords = Ključne riječi:
+pdfjs-document-properties-creation-date = Datum kreiranja:
+pdfjs-document-properties-modification-date = Datum promjene:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Kreator:
+pdfjs-document-properties-producer = PDF stvaratelj:
+pdfjs-document-properties-version = PDF verzija:
+pdfjs-document-properties-page-count = Broj stranica:
+pdfjs-document-properties-page-size = Veličina stranice:
+pdfjs-document-properties-page-size-unit-inches = u
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = uspravno
+pdfjs-document-properties-page-size-orientation-landscape = vodoravno
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Pismo
+pdfjs-document-properties-page-size-name-legal = Pravni
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Brzi web pregled:
+pdfjs-document-properties-linearized-yes = Da
+pdfjs-document-properties-linearized-no = Ne
+pdfjs-document-properties-close-button = Zatvori
+
+## Print
+
+pdfjs-print-progress-message = Pripremam dokument za štampu…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Otkaži
+pdfjs-printing-not-supported = Upozorenje: Štampanje nije u potpunosti podržano u ovom browseru.
+pdfjs-printing-not-ready = Upozorenje: PDF nije u potpunosti učitan za štampanje.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Uključi/isključi bočnu traku
+pdfjs-toggle-sidebar-notification-button =
+ .title = Uključi/isključi bočnu traku (dokument sadrži obris/priloge/slojeve)
+pdfjs-toggle-sidebar-button-label = Uključi/isključi bočnu traku
+pdfjs-document-outline-button =
+ .title = Prikaži outline dokumenta (dvoklik za skupljanje/širenje svih stavki)
+pdfjs-document-outline-button-label = Konture dokumenta
+pdfjs-attachments-button =
+ .title = Prikaži priloge
+pdfjs-attachments-button-label = Prilozi
+pdfjs-layers-button =
+ .title = Prikaži slojeve (dvostruki klik da biste vratili sve slojeve na zadano stanje)
+pdfjs-layers-button-label = Slojevi
+pdfjs-thumbs-button =
+ .title = Prikaži thumbnailove
+pdfjs-thumbs-button-label = Thumbnailovi
+pdfjs-current-outline-item-button =
+ .title = Pronađi trenutnu stavku strukture
+pdfjs-current-outline-item-button-label = Trenutna stavka strukture
+pdfjs-findbar-button =
+ .title = Pronađi u dokumentu
+pdfjs-findbar-button-label = Pronađi
+pdfjs-additional-layers = Dodatni slojevi
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Strana { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail strane { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Pronađi
+ .placeholder = Pronađi u dokumentu…
+pdfjs-find-previous-button =
+ .title = Pronađi prethodno pojavljivanje fraze
+pdfjs-find-previous-button-label = Prethodno
+pdfjs-find-next-button =
+ .title = Pronađi sljedeće pojavljivanje fraze
+pdfjs-find-next-button-label = Sljedeće
+pdfjs-find-highlight-checkbox = Označi sve
+pdfjs-find-match-case-checkbox-label = Osjetljivost na karaktere
+pdfjs-find-match-diacritics-checkbox-label = Podudaranje dijakritika
+pdfjs-find-entire-word-checkbox-label = Cijele riječi
+pdfjs-find-reached-top = Dostigao sam vrh dokumenta, nastavljam sa dna
+pdfjs-find-reached-bottom = Dostigao sam kraj dokumenta, nastavljam sa vrha
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } od { $total } podudaranje
+ [few] { $current } od { $total } podudaranja
+ *[other] { $current } od { $total } podudaranja
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Više od { $limit } podudaranja
+ [few] Više od { $limit } podudaranja
+ *[other] Više od { $limit } podudaranja
+ }
+pdfjs-find-not-found = Fraza nije pronađena
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Širina strane
+pdfjs-page-scale-fit = Uklopi stranu
+pdfjs-page-scale-auto = Automatsko uvećanje
+pdfjs-page-scale-actual = Stvarna veličina
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Stranica { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Došlo je do greške prilikom učitavanja PDF-a.
+pdfjs-invalid-file-error = Neispravan ili oštećen PDF fajl.
+pdfjs-missing-file-error = Nedostaje PDF fajl.
+pdfjs-unexpected-response-error = Neočekivani odgovor servera.
+pdfjs-rendering-error = Došlo je do greške prilikom renderiranja strane.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } pribilješka]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Upišite lozinku da biste otvorili ovaj PDF fajl.
+pdfjs-password-invalid = Pogrešna lozinka. Pokušajte ponovo.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Otkaži
+pdfjs-web-fonts-disabled = Web fontovi su onemogućeni: nemoguće koristiti ubačene PDF fontove.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Crtanje
+pdfjs-editor-ink-button-label = Crtanje
+pdfjs-editor-stamp-button =
+ .title = Dodajte ili uredite slike
+pdfjs-editor-stamp-button-label = Dodajte ili uredite slike
+pdfjs-editor-highlight-button =
+ .title = Istaknite
+pdfjs-editor-highlight-button-label = Istaknite
+pdfjs-highlight-floating-button1 =
+ .title = Istaknite
+ .aria-label = Istaknite
+pdfjs-highlight-floating-button-label = Istaknite
+pdfjs-editor-signature-button =
+ .title = Dodaj potpis
+pdfjs-editor-signature-button-label = Dodaj potpis
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Uređivač istaknutih elemenata
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Uređivač crteža
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Uređivač potpisa: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Uređivač slika
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Ukloni crtež
+pdfjs-editor-remove-freetext-button =
+ .title = Ukloni tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Ukloni sliku
+pdfjs-editor-remove-highlight-button =
+ .title = Ukloni istaknuti dio
+pdfjs-editor-remove-signature-button =
+ .title = Ukloni potpis
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Boja
+pdfjs-editor-free-text-size-input = Veličina
+pdfjs-editor-ink-color-input = Boja
+pdfjs-editor-ink-thickness-input = Debljina
+pdfjs-editor-ink-opacity-input = Neprozirnost
+pdfjs-editor-stamp-add-image-button =
+ .title = Dodaj sliku
+pdfjs-editor-stamp-add-image-button-label = Dodaj sliku
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Debljina
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Promijenite debljinu prilikom označavanja stavki koje nisu tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Kontrole potpisa i sačuvani potpisi
+pdfjs-editor-signature-add-signature-button =
+ .title = Dodaj novi potpis
+pdfjs-editor-signature-add-signature-button-label = Dodaj novi potpis
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Sačuvani potpis: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Uređivač teksta
+ .default-content = Počnite kucati…
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativni tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Uredi alternativni tekst
+pdfjs-editor-alt-text-dialog-label = Odaberite opciju
+pdfjs-editor-alt-text-dialog-description = Alternativni tekst (Alt tekst) pomaže kada ljudi ne mogu vidjeti sliku ili kada se ona ne učitava.
+pdfjs-editor-alt-text-add-description-label = Dodajte opis
+pdfjs-editor-alt-text-add-description-description = Ciljajte na 1-2 rečenice koje opisuju temu, okruženje ili radnju.
+pdfjs-editor-alt-text-mark-decorative-label = Označi kao dekorativno
+pdfjs-editor-alt-text-mark-decorative-description = Ovo se koristi za ukrasne slike, poput okvira ili vodenih žigova.
+pdfjs-editor-alt-text-cancel-button = Otkaži
+pdfjs-editor-alt-text-save-button = Sačuvaj
+pdfjs-editor-alt-text-decorative-tooltip = Označeno kao dekorativno
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Na primjer, „Mladić sjeda za stol da jede obrok“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativni tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Gornji lijevi ugao — promjena veličine
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Gore u sredini — promijeni veličinu
+pdfjs-editor-resizer-top-right =
+ .aria-label = Gornji desni ugao — promijeni veličinu
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Sredina desno — promijeni veličinu
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Donji desni ugao — promijeni veličinu
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Donji srednji dio — promijeni veličinu
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Donji lijevi ugao — promijeni veličinu
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Sredina lijevo — promijeni veličinu
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Boja isticanja
+pdfjs-editor-colorpicker-button =
+ .title = Promijeni boju
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Izbor boja
+pdfjs-editor-colorpicker-yellow =
+ .title = Žuta
+pdfjs-editor-colorpicker-green =
+ .title = Zelena
+pdfjs-editor-colorpicker-blue =
+ .title = Plava
+pdfjs-editor-colorpicker-pink =
+ .title = Roza
+pdfjs-editor-colorpicker-red =
+ .title = Crvena
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Prikaži sve
+pdfjs-editor-highlight-show-all-button =
+ .title = Prikaži sve
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Uredi alternativni tekst (opis slike)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Dodaj alternativni tekst (opis slike)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Ovdje napišite svoj opis…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kratak opis za osobe koje ne mogu vidjeti sliku ili kada se slika ne učitava.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ovaj alternativni tekst je kreiran automatski i moguće je da je netačan.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Saznajte više
+pdfjs-editor-new-alt-text-create-automatically-button-label = Automatski kreiraj alternativni tekst
+pdfjs-editor-new-alt-text-not-now-button = Ne sada
+pdfjs-editor-new-alt-text-error-title = Nije moguće automatski kreirati alternativni tekst
+pdfjs-editor-new-alt-text-error-description = Molimo vas da napišete vlastiti alternativni tekst ili pokušate ponovo kasnije.
+pdfjs-editor-new-alt-text-error-close-button = Zatvori
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Preuzimanje alternativnog tekstualnog AI modela ({ $downloadedSize } od { $totalSize } MB)
+ .aria-valuetext = Preuzimanje alternativnog tekstualnog AI modela ({ $downloadedSize } od { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativni tekst je dodan
+pdfjs-editor-new-alt-text-added-button-label = Alternativni tekst je dodan
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Nedostaje alternativni tekst
+pdfjs-editor-new-alt-text-missing-button-label = Nedostaje alternativni tekst
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternativni tekst recenzije
+pdfjs-editor-new-alt-text-to-review-button-label = Alternativni tekst recenzije
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automatski kreirano: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Postavke alternativnog teksta slike
+pdfjs-image-alt-text-settings-button-label = Postavke alternativnog teksta slike
+pdfjs-editor-alt-text-settings-dialog-label = Postavke alternativnog teksta slike
+pdfjs-editor-alt-text-settings-automatic-title = Automatski alternativni tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Automatski kreiraj alternativni tekst
+pdfjs-editor-alt-text-settings-create-model-description = Predlaže opise kako bi pomogao ljudima koji ne vide sliku ili kada se slika ne učitava.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alternativni tekst AI model ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Radi lokalno na vašem uređaju tako da vaši podaci ostaju privatni. Potrebno za automatski alternativni tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Izbriši
+pdfjs-editor-alt-text-settings-download-model-button = Preuzmi
+pdfjs-editor-alt-text-settings-downloading-model-button = Preuzimam…
+pdfjs-editor-alt-text-settings-editor-title = Uređivač alternativnog teksta
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Odmah prikaži uređivač alternativnog teksta prilikom dodavanja slike
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomaže vam da osigurate da sve vaše slike imaju alternativni tekst.
+pdfjs-editor-alt-text-settings-close-button = Zatvori
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Istaknuto je uklonjeno
+pdfjs-editor-undo-bar-message-freetext = Tekst uklonjen
+pdfjs-editor-undo-bar-message-ink = Crtež uklonjen
+pdfjs-editor-undo-bar-message-stamp = Slika uklonjena
+pdfjs-editor-undo-bar-message-signature = Potpis uklonjen
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } bilješka uklonjena
+ [few] { $count } bilješke uklonjene
+ *[other] { $count } bilješki uklonjeno
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Poništi
+pdfjs-editor-undo-bar-undo-button-label = Poništi
+pdfjs-editor-undo-bar-close-button =
+ .title = Zatvori
+pdfjs-editor-undo-bar-close-button-label = Zatvori
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Ovaj modalni prozor omogućava korisniku da kreira potpis koji će dodati PDF dokumentu. Korisnik može urediti ime (koje služi i kao alternativni tekst) i opcionalno sačuvati potpis za ponovnu upotrebu.
+pdfjs-editor-add-signature-dialog-title = Dodaj potpis
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Ukucaj
+ .title = Ukucaj
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Napiši
+ .title = Napiši
+pdfjs-editor-add-signature-image-button = Slika
+ .title = Slika
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Ukucajte svoj potpis
+ .placeholder = Ukucajte svoj potpis
+pdfjs-editor-add-signature-draw-placeholder = Napišite svoj potpis
+pdfjs-editor-add-signature-draw-thickness-range-label = Debljina
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Debljina pisanja: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Prevucite datoteku ovdje da biste je učitali
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ili odaberite slikovne datoteke
+ *[other] Ili pregledajte slikovne datoteke
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Opis (alternativni tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Opis (alternativni tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Potpis
+pdfjs-editor-add-signature-clear-button-label = Očisti potpis
+pdfjs-editor-add-signature-clear-button =
+ .title = Očisti potpis
+pdfjs-editor-add-signature-save-checkbox = Sačuvaj potpis
+pdfjs-editor-add-signature-save-warning-message = Dostigli ste ograničenje od 5 sačuvanih potpisa. Uklonite jedan da biste sačuvali više.
+pdfjs-editor-add-signature-image-upload-error-title = Nije moguće učitati sliku
+pdfjs-editor-add-signature-image-upload-error-description = Provjerite mrežnu vezu ili pokušajte s drugom slikom.
+pdfjs-editor-add-signature-image-no-data-error-title = Nije moguće pretvoriti ovu sliku u potpis
+pdfjs-editor-add-signature-image-no-data-error-description = Molimo pokušajte učitati drugu sliku.
+pdfjs-editor-add-signature-error-close-button = Zatvori
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Otkaži
+pdfjs-editor-add-signature-add-button = Dodaj
+pdfjs-editor-edit-signature-update-button = Ažuriraj
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Ukloni sačuvani potpis
+pdfjs-editor-delete-signature-button-label1 = Ukloni sačuvani potpis
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Uredi opis
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Uredi opis
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ca/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ca/viewer.ftl
new file mode 100644
index 0000000..1c60c7b
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ca/viewer.ftl
@@ -0,0 +1,494 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pàgina anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Pàgina següent
+pdfjs-next-button-label = Següent
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pàgina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Redueix
+pdfjs-zoom-out-button-label = Redueix
+pdfjs-zoom-in-button =
+ .title = Amplia
+pdfjs-zoom-in-button-label = Amplia
+pdfjs-zoom-select =
+ .title = Escala
+pdfjs-presentation-mode-button =
+ .title = Canvia al mode de presentació
+pdfjs-presentation-mode-button-label = Mode de presentació
+pdfjs-open-file-button =
+ .title = Obre el fitxer
+pdfjs-open-file-button-label = Obre
+pdfjs-print-button =
+ .title = Imprimeix
+pdfjs-print-button-label = Imprimeix
+pdfjs-save-button =
+ .title = Desa
+pdfjs-save-button-label = Desa
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Baixa
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Baixa
+pdfjs-bookmark-button =
+ .title = Pàgina actual (mostra l'URL de la pàgina actual)
+pdfjs-bookmark-button-label = Pàgina actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Eines
+pdfjs-tools-button-label = Eines
+pdfjs-first-page-button =
+ .title = Vés a la primera pàgina
+pdfjs-first-page-button-label = Vés a la primera pàgina
+pdfjs-last-page-button =
+ .title = Vés a l'última pàgina
+pdfjs-last-page-button-label = Vés a l'última pàgina
+pdfjs-page-rotate-cw-button =
+ .title = Gira cap a la dreta
+pdfjs-page-rotate-cw-button-label = Gira cap a la dreta
+pdfjs-page-rotate-ccw-button =
+ .title = Gira cap a l'esquerra
+pdfjs-page-rotate-ccw-button-label = Gira cap a l'esquerra
+pdfjs-cursor-text-select-tool-button =
+ .title = Habilita l'eina de selecció de text
+pdfjs-cursor-text-select-tool-button-label = Eina de selecció de text
+pdfjs-cursor-hand-tool-button =
+ .title = Habilita l'eina de mà
+pdfjs-cursor-hand-tool-button-label = Eina de mà
+pdfjs-scroll-page-button =
+ .title = Usa el desplaçament de pàgina
+pdfjs-scroll-page-button-label = Desplaçament de pàgina
+pdfjs-scroll-vertical-button =
+ .title = Utilitza el desplaçament vertical
+pdfjs-scroll-vertical-button-label = Desplaçament vertical
+pdfjs-scroll-horizontal-button =
+ .title = Utilitza el desplaçament horitzontal
+pdfjs-scroll-horizontal-button-label = Desplaçament horitzontal
+pdfjs-scroll-wrapped-button =
+ .title = Activa el desplaçament continu
+pdfjs-scroll-wrapped-button-label = Desplaçament continu
+pdfjs-spread-none-button =
+ .title = No agrupis les pàgines de dues en dues
+pdfjs-spread-none-button-label = Una sola pàgina
+pdfjs-spread-odd-button =
+ .title = Mostra dues pàgines començant per les pàgines de numeració senar
+pdfjs-spread-odd-button-label = Doble pàgina (senar)
+pdfjs-spread-even-button =
+ .title = Mostra dues pàgines començant per les pàgines de numeració parell
+pdfjs-spread-even-button-label = Doble pàgina (parell)
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propietats del document…
+pdfjs-document-properties-button-label = Propietats del document…
+pdfjs-document-properties-file-name = Nom del fitxer:
+pdfjs-document-properties-file-size = Mida del fitxer:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Títol:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Assumpte:
+pdfjs-document-properties-keywords = Paraules clau:
+pdfjs-document-properties-creation-date = Data de creació:
+pdfjs-document-properties-modification-date = Data de modificació:
+pdfjs-document-properties-creator = Creador:
+pdfjs-document-properties-producer = Generador de PDF:
+pdfjs-document-properties-version = Versió de PDF:
+pdfjs-document-properties-page-count = Nombre de pàgines:
+pdfjs-document-properties-page-size = Mida de la pàgina:
+pdfjs-document-properties-page-size-unit-inches = polzades
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = apaïsat
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista web ràpida:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Tanca
+pdfjs-digital-signature-properties-view-certificate = Mostra el certificat
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Motiu: { $reason }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Una subsignatura
+ *[other] ({ $count }) subsignatures
+ }
+
+## Print
+
+pdfjs-print-progress-message = S'està preparant la impressió del document…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancel·la
+pdfjs-printing-not-supported = Avís: la impressió no és plenament funcional en aquest navegador.
+pdfjs-printing-not-ready = Atenció: el PDF no s'ha acabat de carregar per imprimir-lo.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Mostra/amaga la barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Mostra/amaga la barra lateral (el document conté un esquema, adjuncions o capes)
+pdfjs-toggle-sidebar-button-label = Mostra/amaga la barra lateral
+pdfjs-document-outline-button =
+ .title = Mostra l'esquema del document (doble clic per ampliar/reduir tots els elements)
+pdfjs-document-outline-button-label = Esquema del document
+pdfjs-attachments-button =
+ .title = Mostra les adjuncions
+pdfjs-attachments-button-label = Adjuncions
+pdfjs-layers-button =
+ .title = Mostra les capes (doble clic per restablir totes les capes al seu estat per defecte)
+pdfjs-layers-button-label = Capes
+pdfjs-thumbs-button =
+ .title = Mostra les miniatures
+pdfjs-thumbs-button-label = Miniatures
+pdfjs-current-outline-item-button =
+ .title = Cerca l'element d'esquema actual
+pdfjs-current-outline-item-button-label = Element d'esquema actual
+pdfjs-findbar-button =
+ .title = Cerca al document
+pdfjs-findbar-button-label = Cerca
+pdfjs-additional-layers = Capes addicionals
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pàgina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura de la pàgina { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Pàgina { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Cerca
+ .placeholder = Cerca al document…
+pdfjs-find-previous-button =
+ .title = Cerca l'anterior coincidència de l'expressió
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Cerca la següent coincidència de l'expressió
+pdfjs-find-next-button-label = Següent
+pdfjs-find-highlight-checkbox = Ressalta-ho tot
+pdfjs-find-match-case-checkbox-label = Distingeix entre majúscules i minúscules
+pdfjs-find-match-diacritics-checkbox-label = Respecta els diacrítics
+pdfjs-find-entire-word-checkbox-label = Paraules senceres
+pdfjs-find-reached-top = S'ha arribat al principi del document, es continua pel final
+pdfjs-find-reached-bottom = S'ha arribat al final del document, es continua pel principi
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } d'{ $total } coincidència
+ *[other] { $current } de { $total } coincidències
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Més d'{ $limit } coincidència
+ *[other] Més de { $limit } coincidències
+ }
+pdfjs-find-not-found = No s'ha trobat l'expressió
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Amplada de la pàgina
+pdfjs-page-scale-fit = Ajusta la pàgina
+pdfjs-page-scale-auto = Zoom automàtic
+pdfjs-page-scale-actual = Mida real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pàgina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = S'ha produït un error en carregar el PDF.
+pdfjs-invalid-file-error = El fitxer PDF no és vàlid o està malmès.
+pdfjs-missing-file-error = Falta el fitxer PDF.
+pdfjs-unexpected-response-error = Resposta inesperada del servidor.
+pdfjs-rendering-error = S'ha produït un error mentre es renderitzava la pàgina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotació { $type }]
+
+## Password
+
+pdfjs-password-label = Introduïu la contrasenya per obrir aquest fitxer PDF.
+pdfjs-password-invalid = La contrasenya no és vàlida. Torneu-ho a provar.
+pdfjs-password-ok-button = D'acord
+pdfjs-password-cancel-button = Cancel·la
+pdfjs-web-fonts-disabled = Els tipus de lletra web estan desactivats: no es poden utilitzar els tipus de lletra incrustats al PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Canvia el color del text
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Dibuixa
+pdfjs-editor-color-picker-ink-input =
+ .title = Canvia el color de dibuix
+pdfjs-editor-ink-button-label = Dibuixa
+pdfjs-editor-stamp-button =
+ .title = Afegeix o edita imatges
+pdfjs-editor-stamp-button-label = Afegeix o edita imatges
+pdfjs-editor-highlight-button =
+ .title = Ressalta
+pdfjs-editor-highlight-button-label = Ressalta
+pdfjs-highlight-floating-button1 =
+ .title = Ressalta
+ .aria-label = Ressalta
+pdfjs-highlight-floating-button-label = Ressalta
+pdfjs-editor-signature-button =
+ .title = Afegeix una signatura
+pdfjs-editor-signature-button-label = Afegeix una signatura
+
+## Default editor aria labels
+
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de dibuix
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de signatures: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor d'imatges
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Suprimeix el dibuix
+pdfjs-editor-remove-freetext-button =
+ .title = Suprimeix el text
+pdfjs-editor-remove-stamp-button =
+ .title = Suprimeix la imatge
+pdfjs-editor-remove-highlight-button =
+ .title = Suprimeix el ressaltat
+pdfjs-editor-remove-signature-button =
+ .title = Elimina la signatura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Mida
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Gruix
+pdfjs-editor-ink-opacity-input = Opacitat
+pdfjs-editor-stamp-add-image-button =
+ .title = Afegeix una imatge
+pdfjs-editor-stamp-add-image-button-label = Afegeix una imatge
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Gruix
+pdfjs-editor-add-signature-container =
+ .aria-label = Controls de signatura i signatures desades
+pdfjs-editor-signature-add-signature-button =
+ .title = Afegeix una nova signatura
+pdfjs-editor-signature-add-signature-button-label = Afegeix una nova signatura
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Signatura desada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de text
+ .default-content = Comença a escriute...
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentari
+ *[other] Comentaris
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Tanca la barra lateral
+ .aria-label = Tanca la barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Tanca la barra lateral
+pdfjs-editor-comments-sidebar-no-comments-link = Més informació
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Text alternatiu
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Edita el text alternatiu
+pdfjs-editor-alt-text-dialog-label = Trieu una opció
+pdfjs-editor-alt-text-dialog-description = El text alternatiu és d'ajuda quan no es pot veure la imatge o quan no es carrega.
+pdfjs-editor-alt-text-add-description-label = Afegeix una descripció
+pdfjs-editor-alt-text-add-description-description = Una o dues frases amb la intenció de descriure el subjecte, l'entorn o les accions.
+pdfjs-editor-alt-text-mark-decorative-label = Marca com a decoratiu
+pdfjs-editor-alt-text-mark-decorative-description = Això s'utilitza per a imatges ornamentals, com ara vores o marques d'aigua.
+pdfjs-editor-alt-text-cancel-button = Cancel·la
+pdfjs-editor-alt-text-save-button = Desa
+pdfjs-editor-alt-text-decorative-tooltip = S'ha marcat com a decoratiu
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Per exemple, “Un jove seu a taula per menjar un àpat”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Text alternatiu
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color de ressaltat
+pdfjs-editor-colorpicker-button =
+ .title = Canvia el color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opcions de color
+pdfjs-editor-colorpicker-yellow =
+ .title = Groc
+pdfjs-editor-colorpicker-green =
+ .title = Verd
+pdfjs-editor-colorpicker-blue =
+ .title = Blau
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Vermell
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostra-ho tot
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostra-ho tot
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Edita el text alternatiu (descripció de la imatge)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Afegeix text alternatiu (descripció de la imatge)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escriviu la vostra descripció aquí...
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Descripció breu per a les persones que no poden veure la imatge o quan la imatge no es carrega.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Aquest text alternatiu ha estat creat automàticament i pot ser inexacte.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Més informació
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crea el text alternatiu automàticament
+pdfjs-editor-new-alt-text-not-now-button = Ara no
+pdfjs-editor-new-alt-text-error-title = No s'ha pogut crear el text alternatiu automàticament
+pdfjs-editor-new-alt-text-error-description = Escriviu el vostre propi text alternatiu o proveu més tard.
+pdfjs-editor-new-alt-text-error-close-button = Tanca
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Text alternatiu afegit.
+pdfjs-editor-new-alt-text-added-button-label = Text alternatiu afegit.
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-delete-model-button = Suprimeix
+pdfjs-editor-alt-text-settings-download-model-button = Baixa
+pdfjs-editor-alt-text-settings-downloading-model-button = S'està descarregant…
+pdfjs-editor-alt-text-settings-close-button = Tanca
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-ink = S'ha eliminat el dibuix
+pdfjs-editor-undo-bar-message-stamp = S'ha eliminat la imatge
+pdfjs-editor-undo-bar-message-signature = S’ha eliminat la signatura
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] S'ha eliminat una anotació
+ *[other] S'han eliminat { $count } anotacions
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Desfés
+pdfjs-editor-undo-bar-undo-button-label = Desfés
+pdfjs-editor-undo-bar-close-button =
+ .title = Tanca
+pdfjs-editor-undo-bar-close-button-label = Tanca
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancel·la
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cak/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cak/viewer.ftl
new file mode 100644
index 0000000..3f9c6a2
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cak/viewer.ftl
@@ -0,0 +1,264 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Jun kan ruxaq
+pdfjs-previous-button-label = Jun kan
+pdfjs-next-button =
+ .title = Jun chik ruxaq
+pdfjs-next-button-label = Jun chik
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Ruxaq
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = richin { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } richin { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Tich'utinirisäx
+pdfjs-zoom-out-button-label = Tich'utinirisäx
+pdfjs-zoom-in-button =
+ .title = Tinimirisäx
+pdfjs-zoom-in-button-label = Tinimirisäx
+pdfjs-zoom-select =
+ .title = Sum
+pdfjs-presentation-mode-button =
+ .title = Tijal ri rub'anikil niwachin
+pdfjs-presentation-mode-button-label = Pa rub'eyal niwachin
+pdfjs-open-file-button =
+ .title = Tijaq Yakb'äl
+pdfjs-open-file-button-label = Tijaq
+pdfjs-print-button =
+ .title = Titz'ajb'äx
+pdfjs-print-button-label = Titz'ajb'äx
+pdfjs-save-button =
+ .title = Tiyak
+pdfjs-save-button-label = Tiyak
+pdfjs-bookmark-button-label = Ruxaq k'o wakami
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Samajib'äl
+pdfjs-tools-button-label = Samajib'äl
+pdfjs-first-page-button =
+ .title = Tib'e pa nab'ey ruxaq
+pdfjs-first-page-button-label = Tib'e pa nab'ey ruxaq
+pdfjs-last-page-button =
+ .title = Tib'e pa ruk'isib'äl ruxaq
+pdfjs-last-page-button-label = Tib'e pa ruk'isib'äl ruxaq
+pdfjs-page-rotate-cw-button =
+ .title = Tisutïx pan ajkiq'a'
+pdfjs-page-rotate-cw-button-label = Tisutïx pan ajkiq'a'
+pdfjs-page-rotate-ccw-button =
+ .title = Tisutïx pan ajxokon
+pdfjs-page-rotate-ccw-button-label = Tisutïx pan ajxokon
+pdfjs-cursor-text-select-tool-button =
+ .title = Titzij ri rusamajib'al Rucha'ik Rucholajem Tzij
+pdfjs-cursor-text-select-tool-button-label = Rusamajib'al Rucha'ik Rucholajem Tzij
+pdfjs-cursor-hand-tool-button =
+ .title = Titzij ri q'ab'aj samajib'äl
+pdfjs-cursor-hand-tool-button-label = Q'ab'aj Samajib'äl
+pdfjs-scroll-page-button =
+ .title = Tokisäx Ruxaq Q'axanem
+pdfjs-scroll-page-button-label = Ruxaq Q'axanem
+pdfjs-scroll-vertical-button =
+ .title = Tokisäx Pa'äl Q'axanem
+pdfjs-scroll-vertical-button-label = Pa'äl Q'axanem
+pdfjs-scroll-horizontal-button =
+ .title = Tokisäx Kotz'öl Q'axanem
+pdfjs-scroll-horizontal-button-label = Kotz'öl Q'axanem
+pdfjs-scroll-wrapped-button =
+ .title = Tokisäx Tzub'aj Q'axanem
+pdfjs-scroll-wrapped-button-label = Tzub'aj Q'axanem
+pdfjs-spread-none-button =
+ .title = Man ketun taq ruxaq pa rub'eyal wuj
+pdfjs-spread-none-button-label = Majun Rub'eyal
+pdfjs-spread-odd-button =
+ .title = Ke'atunu' ri taq ruxaq rik'in natikirisaj rik'in jun man k'ulaj ta rajilab'al
+pdfjs-spread-odd-button-label = Man K'ulaj Ta Rub'eyal
+pdfjs-spread-even-button =
+ .title = Ke'atunu' ri taq ruxaq rik'in natikirisaj rik'in jun k'ulaj rajilab'al
+pdfjs-spread-even-button-label = K'ulaj Rub'eyal
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Taq richinil wuj…
+pdfjs-document-properties-button-label = Taq richinil wuj…
+pdfjs-document-properties-file-name = Rub'i' yakb'äl:
+pdfjs-document-properties-file-size = Runimilem yakb'äl:
+pdfjs-document-properties-title = B'i'aj:
+pdfjs-document-properties-author = B'anel:
+pdfjs-document-properties-subject = Taqikil:
+pdfjs-document-properties-keywords = Kixe'el taq tzij:
+pdfjs-document-properties-creation-date = Ruq'ijul xtz'uk:
+pdfjs-document-properties-modification-date = Ruq'ijul xjalwachïx:
+pdfjs-document-properties-creator = Q'inonel:
+pdfjs-document-properties-producer = PDF b'anöy:
+pdfjs-document-properties-version = PDF ruwäch:
+pdfjs-document-properties-page-count = Jarupe' ruxaq:
+pdfjs-document-properties-page-size = Runimilem ri Ruxaq:
+pdfjs-document-properties-page-size-unit-inches = pa
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = rupalem
+pdfjs-document-properties-page-size-orientation-landscape = rukotz'olem
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Loman wuj
+pdfjs-document-properties-page-size-name-legal = Taqanel tzijol
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Anin Rutz'etik Ajk'amaya'l:
+pdfjs-document-properties-linearized-yes = Ja'
+pdfjs-document-properties-linearized-no = Mani
+pdfjs-document-properties-close-button = Titz'apïx
+
+## Print
+
+pdfjs-print-progress-message = Ruchojmirisaxik wuj richin nitz'ajb'äx…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Tiq'at
+pdfjs-printing-not-supported = Rutzijol k'ayewal: Ri rutz'ajb'axik man koch'el ta ronojel pa re okik'amaya'l re'.
+pdfjs-printing-not-ready = Rutzijol k'ayewal: Ri PDF man xusamajij ta ronojel richin nitz'ajb'äx.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Tijal ri ajxikin kajtz'ik
+pdfjs-toggle-sidebar-notification-button =
+ .title = Tik'ex ri ajxikin yuqkajtz'ik (ri wuj eruk'wan taq ruchi'/taqo/kuchuj)
+pdfjs-toggle-sidebar-button-label = Tijal ri ajxikin kajtz'ik
+pdfjs-document-outline-button =
+ .title = Tik'ut pe ruch'akulal wuj (kamul-pitz'oj richin nirik'/nich'utinirisäx ronojel ruch'akulal)
+pdfjs-document-outline-button-label = Ruch'akulal wuj
+pdfjs-attachments-button =
+ .title = Kek'ut pe ri taq taqoj
+pdfjs-attachments-button-label = Taq taqoj
+pdfjs-layers-button =
+ .title = Kek'ut taq Kuchuj (ka'i'-pitz' richin yetzolïx ronojel ri taq kuchuj e k'o wi)
+pdfjs-layers-button-label = Taq kuchuj
+pdfjs-thumbs-button =
+ .title = Kek'ut pe taq ch'utiq
+pdfjs-thumbs-button-label = Koköj
+pdfjs-current-outline-item-button =
+ .title = Kekanöx Taq Ch'akulal Kik'wan Chib'äl
+pdfjs-current-outline-item-button-label = Taq Ch'akulal Kik'wan Chib'äl
+pdfjs-findbar-button =
+ .title = Tikanöx chupam ri wuj
+pdfjs-findbar-button-label = Tikanöx
+pdfjs-additional-layers = Tz'aqat ta Kuchuj
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Ruxaq { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Ruch'utinirisaxik ruxaq { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Tikanöx
+ .placeholder = Tikanöx pa wuj…
+pdfjs-find-previous-button =
+ .title = Tib'an b'enam pa ri jun kan q'aptzij xilitäj
+pdfjs-find-previous-button-label = Jun kan
+pdfjs-find-next-button =
+ .title = Tib'e pa ri jun chik pajtzij xilitäj
+pdfjs-find-next-button-label = Jun chik
+pdfjs-find-highlight-checkbox = Tiya' retal ronojel
+pdfjs-find-match-case-checkbox-label = Tuk'äm ri' kik'in taq nimatz'ib' chuqa' taq ch'utitz'ib'
+pdfjs-find-match-diacritics-checkbox-label = Tiya' Kikojol Tz'aqat taq Tz'ib'
+pdfjs-find-entire-word-checkbox-label = Tz'aqät taq tzij
+pdfjs-find-reached-top = Xb'eq'i' ri rutikirib'al wuj, xtikanöx k'a pa ruk'isib'äl
+pdfjs-find-reached-bottom = Xb'eq'i' ri ruk'isib'äl wuj, xtikanöx pa rutikirib'al
+pdfjs-find-not-found = Man xilitäj ta ri pajtzij
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ruwa ruxaq
+pdfjs-page-scale-fit = Tinuk' ruxaq
+pdfjs-page-scale-auto = Yonil chi nimilem
+pdfjs-page-scale-actual = Runimilem Wakami
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Ruxaq { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Xk'ulwachitäj jun sach'oj toq xnuk'ux ri PDF .
+pdfjs-invalid-file-error = Man oke ta o yujtajinäq ri PDF yakb'äl.
+pdfjs-missing-file-error = Man xilitäj ta ri PDF yakb'äl.
+pdfjs-unexpected-response-error = Man oyob'en ta tz'olin rutzij ruk'u'x samaj.
+pdfjs-rendering-error = Xk'ulwachitäj jun sachoj toq ninuk'wachij ri ruxaq.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Tz'ib'anïk]
+
+## Password
+
+pdfjs-password-label = Tatz'ib'aj ri ewan tzij richin najäq re yakb'äl re' pa PDF.
+pdfjs-password-invalid = Man okel ta ri ewan tzij: Tatojtob'ej chik.
+pdfjs-password-ok-button = Ütz
+pdfjs-password-cancel-button = Tiq'at
+pdfjs-web-fonts-disabled = E chupül ri taq ajk'amaya'l tz'ib': man tikirel ta nokisäx ri taq tz'ib' PDF pa ch'ikenïk
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Rucholajem tz'ib'
+pdfjs-editor-free-text-button-label = Rucholajem tz'ib'
+pdfjs-editor-ink-button =
+ .title = Tiwachib'ëx
+pdfjs-editor-ink-button-label = Tiwachib'ëx
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = B'onil
+pdfjs-editor-free-text-size-input = Nimilem
+pdfjs-editor-ink-color-input = B'onil
+pdfjs-editor-ink-thickness-input = Rupimil
+pdfjs-editor-ink-opacity-input = Q'equmal
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ckb/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ckb/viewer.ftl
new file mode 100644
index 0000000..73f9e86
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ckb/viewer.ftl
@@ -0,0 +1,213 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = پەڕەی پێشوو
+pdfjs-previous-button-label = پێشوو
+pdfjs-next-button =
+ .title = پەڕەی دوواتر
+pdfjs-next-button-label = دوواتر
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = پەرە
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = لە { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } لە { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = ڕۆچوونی
+pdfjs-zoom-out-button-label = ڕۆچوونی
+pdfjs-zoom-in-button =
+ .title = هێنانەپێش
+pdfjs-zoom-in-button-label = هێنانەپێش
+pdfjs-zoom-select =
+ .title = زووم
+pdfjs-presentation-mode-button =
+ .title = گۆڕین بۆ دۆخی پێشکەشکردن
+pdfjs-presentation-mode-button-label = دۆخی پێشکەشکردن
+pdfjs-open-file-button =
+ .title = پەڕگە بکەرەوە
+pdfjs-open-file-button-label = کردنەوە
+pdfjs-print-button =
+ .title = چاپکردن
+pdfjs-print-button-label = چاپکردن
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ئامرازەکان
+pdfjs-tools-button-label = ئامرازەکان
+pdfjs-first-page-button =
+ .title = برۆ بۆ یەکەم پەڕە
+pdfjs-first-page-button-label = بڕۆ بۆ یەکەم پەڕە
+pdfjs-last-page-button =
+ .title = بڕۆ بۆ کۆتا پەڕە
+pdfjs-last-page-button-label = بڕۆ بۆ کۆتا پەڕە
+pdfjs-page-rotate-cw-button =
+ .title = ئاڕاستەی میلی کاتژمێر
+pdfjs-page-rotate-cw-button-label = ئاڕاستەی میلی کاتژمێر
+pdfjs-page-rotate-ccw-button =
+ .title = پێچەوانەی میلی کاتژمێر
+pdfjs-page-rotate-ccw-button-label = پێچەوانەی میلی کاتژمێر
+pdfjs-cursor-text-select-tool-button =
+ .title = توڵامرازی نیشانکەری دەق چالاک بکە
+pdfjs-cursor-text-select-tool-button-label = توڵامرازی نیشانکەری دەق
+pdfjs-cursor-hand-tool-button =
+ .title = توڵامرازی دەستی چالاک بکە
+pdfjs-cursor-hand-tool-button-label = توڵامرازی دەستی
+pdfjs-scroll-vertical-button =
+ .title = ناردنی ئەستوونی بەکاربێنە
+pdfjs-scroll-vertical-button-label = ناردنی ئەستوونی
+pdfjs-scroll-horizontal-button =
+ .title = ناردنی ئاسۆیی بەکاربێنە
+pdfjs-scroll-horizontal-button-label = ناردنی ئاسۆیی
+pdfjs-scroll-wrapped-button =
+ .title = ناردنی لوولکراو بەکاربێنە
+pdfjs-scroll-wrapped-button-label = ناردنی لوولکراو
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = تایبەتمەندییەکانی بەڵگەنامە...
+pdfjs-document-properties-button-label = تایبەتمەندییەکانی بەڵگەنامە...
+pdfjs-document-properties-file-name = ناوی پەڕگە:
+pdfjs-document-properties-file-size = قەبارەی پەڕگە:
+pdfjs-document-properties-title = سەردێڕ:
+pdfjs-document-properties-author = نووسەر
+pdfjs-document-properties-subject = بابەت:
+pdfjs-document-properties-keywords = کلیلەوشە:
+pdfjs-document-properties-creation-date = بەرواری درووستکردن:
+pdfjs-document-properties-modification-date = بەرواری دەستکاریکردن:
+pdfjs-document-properties-creator = درووستکەر:
+pdfjs-document-properties-producer = بەرهەمهێنەری PDF:
+pdfjs-document-properties-version = وەشانی PDF:
+pdfjs-document-properties-page-count = ژمارەی پەرەکان:
+pdfjs-document-properties-page-size = قەبارەی پەڕە:
+pdfjs-document-properties-page-size-unit-inches = ئینچ
+pdfjs-document-properties-page-size-unit-millimeters = ملم
+pdfjs-document-properties-page-size-orientation-portrait = پۆرترەیت(درێژ)
+pdfjs-document-properties-page-size-orientation-landscape = پانیی
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = نامە
+pdfjs-document-properties-page-size-name-legal = یاسایی
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = پیشاندانی وێبی خێرا:
+pdfjs-document-properties-linearized-yes = بەڵێ
+pdfjs-document-properties-linearized-no = نەخێر
+pdfjs-document-properties-close-button = داخستن
+
+## Print
+
+pdfjs-print-progress-message = بەڵگەنامە ئامادەدەکرێت بۆ چاپکردن...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = پاشگەزبوونەوە
+pdfjs-printing-not-supported = ئاگاداربە: چاپکردن بە تەواوی پشتگیر ناکرێت لەم وێبگەڕە.
+pdfjs-printing-not-ready = ئاگاداربە: PDF بە تەواوی بارنەبووە بۆ چاپکردن.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = لاتەنیشت پیشاندان/شاردنەوە
+pdfjs-toggle-sidebar-button-label = لاتەنیشت پیشاندان/شاردنەوە
+pdfjs-document-outline-button-label = سنووری چوارچێوە
+pdfjs-attachments-button =
+ .title = پاشکۆکان پیشان بدە
+pdfjs-attachments-button-label = پاشکۆکان
+pdfjs-layers-button-label = چینەکان
+pdfjs-thumbs-button =
+ .title = وێنۆچکە پیشان بدە
+pdfjs-thumbs-button-label = وێنۆچکە
+pdfjs-findbar-button =
+ .title = لە بەڵگەنامە بگەرێ
+pdfjs-findbar-button-label = دۆزینەوە
+pdfjs-additional-layers = چینی زیاتر
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = پەڕەی { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = وێنۆچکەی پەڕەی { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = دۆزینەوە
+ .placeholder = لە بەڵگەنامە بگەرێ...
+pdfjs-find-previous-button =
+ .title = هەبوونی پێشوو بدۆزرەوە لە ڕستەکەدا
+pdfjs-find-previous-button-label = پێشوو
+pdfjs-find-next-button =
+ .title = هەبوونی داهاتوو بدۆزەرەوە لە ڕستەکەدا
+pdfjs-find-next-button-label = دوواتر
+pdfjs-find-highlight-checkbox = هەمووی نیشانە بکە
+pdfjs-find-match-case-checkbox-label = دۆخی لەیەکچوون
+pdfjs-find-entire-word-checkbox-label = هەموو وشەکان
+pdfjs-find-reached-top = گەشتیتە سەرەوەی بەڵگەنامە، لە خوارەوە دەستت پێکرد
+pdfjs-find-reached-bottom = گەشتیتە کۆتایی بەڵگەنامە. لەسەرەوە دەستت پێکرد
+pdfjs-find-not-found = نووسین نەدۆزرایەوە
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = پانی پەڕە
+pdfjs-page-scale-fit = پڕبوونی پەڕە
+pdfjs-page-scale-auto = زوومی خۆکار
+pdfjs-page-scale-actual = قەبارەی ڕاستی
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = هەڵەیەک ڕوویدا لە کاتی بارکردنی PDF.
+pdfjs-invalid-file-error = پەڕگەی pdf تێکچووە یان نەگونجاوە.
+pdfjs-missing-file-error = پەڕگەی pdf بوونی نیە.
+pdfjs-unexpected-response-error = وەڵامی ڕاژەخوازی نەخوازراو.
+pdfjs-rendering-error = هەڵەیەک ڕوویدا لە کاتی پوختەکردنی (ڕێندەر) پەڕە.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } سەرنج]
+
+## Password
+
+pdfjs-password-label = وشەی تێپەڕ بنووسە بۆ کردنەوەی پەڕگەی pdf.
+pdfjs-password-invalid = وشەی تێپەڕ هەڵەیە. تکایە دووبارە هەوڵ بدەرەوە.
+pdfjs-password-ok-button = باشە
+pdfjs-password-cancel-button = پاشگەزبوونەوە
+pdfjs-web-fonts-disabled = جۆرەپیتی وێب ناچالاکە: نەتوانی جۆرەپیتی تێخراوی ناو pdfـەکە بەکاربێت.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cs/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cs/viewer.ftl
new file mode 100644
index 0000000..3534d0c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cs/viewer.ftl
@@ -0,0 +1,864 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Přejde na předchozí stránku
+pdfjs-previous-button-label = Předchozí
+pdfjs-next-button =
+ .title = Přejde na následující stránku
+pdfjs-next-button-label = Další
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Stránka
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = z { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } z { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zmenší velikost
+pdfjs-zoom-out-button-label = Zmenšit
+pdfjs-zoom-in-button =
+ .title = Zvětší velikost
+pdfjs-zoom-in-button-label = Zvětšit
+pdfjs-zoom-select =
+ .title = Nastaví velikost
+pdfjs-presentation-mode-button =
+ .title = Přepne do režimu prezentace
+pdfjs-presentation-mode-button-label = Režim prezentace
+pdfjs-open-file-button =
+ .title = Otevře soubor
+pdfjs-open-file-button-label = Otevřít
+pdfjs-print-button =
+ .title = Vytiskne dokument
+pdfjs-print-button-label = Vytisknout
+pdfjs-save-button =
+ .title = Uložit
+pdfjs-save-button-label = Uložit
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Stáhnout
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Stáhnout
+pdfjs-bookmark-button =
+ .title = Aktuální stránka (zobrazit URL od aktuální stránky)
+pdfjs-bookmark-button-label = Aktuální stránka
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Nástroje
+pdfjs-tools-button-label = Nástroje
+pdfjs-first-page-button =
+ .title = Přejde na první stránku
+pdfjs-first-page-button-label = Přejít na první stránku
+pdfjs-last-page-button =
+ .title = Přejde na poslední stránku
+pdfjs-last-page-button-label = Přejít na poslední stránku
+pdfjs-page-rotate-cw-button =
+ .title = Otočí po směru hodin
+pdfjs-page-rotate-cw-button-label = Otočit po směru hodin
+pdfjs-page-rotate-ccw-button =
+ .title = Otočí proti směru hodin
+pdfjs-page-rotate-ccw-button-label = Otočit proti směru hodin
+pdfjs-cursor-text-select-tool-button =
+ .title = Povolí výběr textu
+pdfjs-cursor-text-select-tool-button-label = Výběr textu
+pdfjs-cursor-hand-tool-button =
+ .title = Povolí nástroj ručička
+pdfjs-cursor-hand-tool-button-label = Nástroj ručička
+pdfjs-scroll-page-button =
+ .title = Posouvat po stránkách
+pdfjs-scroll-page-button-label = Posouvání po stránkách
+pdfjs-scroll-vertical-button =
+ .title = Použít svislé posouvání
+pdfjs-scroll-vertical-button-label = Svislé posouvání
+pdfjs-scroll-horizontal-button =
+ .title = Použít vodorovné posouvání
+pdfjs-scroll-horizontal-button-label = Vodorovné posouvání
+pdfjs-scroll-wrapped-button =
+ .title = Použít postupné posouvání
+pdfjs-scroll-wrapped-button-label = Postupné posouvání
+pdfjs-spread-none-button =
+ .title = Nesdružovat stránky
+pdfjs-spread-none-button-label = Žádné sdružení
+pdfjs-spread-odd-button =
+ .title = Sdruží stránky s umístěním lichých vlevo
+pdfjs-spread-odd-button-label = Sdružení stránek (liché vlevo)
+pdfjs-spread-even-button =
+ .title = Sdruží stránky s umístěním sudých vlevo
+pdfjs-spread-even-button-label = Sdružení stránek (sudé vlevo)
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Vlastnosti dokumentu…
+pdfjs-document-properties-button-label = Vlastnosti dokumentu…
+pdfjs-document-properties-file-name = Název souboru:
+pdfjs-document-properties-file-size = Velikost souboru:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } bajtů)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtů)
+pdfjs-document-properties-title = Název stránky:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Předmět:
+pdfjs-document-properties-keywords = Klíčová slova:
+pdfjs-document-properties-creation-date = Datum vytvoření:
+pdfjs-document-properties-modification-date = Datum úpravy:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Vytvořil:
+pdfjs-document-properties-producer = Tvůrce PDF:
+pdfjs-document-properties-version = Verze PDF:
+pdfjs-document-properties-page-count = Počet stránek:
+pdfjs-document-properties-page-size = Velikost stránky:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = na výšku
+pdfjs-document-properties-page-size-orientation-landscape = na šířku
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Dopis
+pdfjs-document-properties-page-size-name-legal = Právní dokument
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Rychlé zobrazování z webu:
+pdfjs-document-properties-linearized-yes = Ano
+pdfjs-document-properties-linearized-no = Ne
+pdfjs-document-properties-close-button = Zavřít
+pdfjs-digital-signature-properties-view-certificate = Zobrazit certifikát
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Důvod: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Časové razítko: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Podpis ({ $count })
+ [few] Podpisy ({ $count })
+ [many] Podpisy ({ $count })
+ *[other] Podpisy ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Příprava dokumentu pro tisk…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Zrušit
+pdfjs-printing-not-supported = Upozornění: Tisk není v tomto prohlížeči plně podporován.
+pdfjs-printing-not-ready = Upozornění: Dokument PDF není kompletně načten.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Postranní lišta
+pdfjs-toggle-sidebar-notification-button =
+ .title = Přepnout postranní lištu (dokument obsahuje osnovu/přílohy/vrstvy)
+pdfjs-toggle-sidebar-button-label = Postranní lišta
+pdfjs-document-outline-button =
+ .title = Zobrazí osnovu dokumentu (poklepání přepne zobrazení všech položek)
+pdfjs-document-outline-button-label = Osnova dokumentu
+pdfjs-attachments-button =
+ .title = Zobrazí přílohy
+pdfjs-attachments-button-label = Přílohy
+pdfjs-layers-button =
+ .title = Zobrazit vrstvy (poklepáním obnovíte všechny vrstvy do výchozího stavu)
+pdfjs-layers-button-label = Vrstvy
+pdfjs-thumbs-button =
+ .title = Zobrazí náhledy
+pdfjs-thumbs-button-label = Náhledy
+pdfjs-current-outline-item-button =
+ .title = Najít aktuální položku v osnově
+pdfjs-current-outline-item-button-label = Aktuální položka v osnově
+pdfjs-findbar-button =
+ .title = Najde v dokumentu
+pdfjs-findbar-button-label = Najít
+pdfjs-additional-layers = Další vrstvy
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Strana { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Náhled strany { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Vybrat stranu { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Strana { $page } z { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Najít
+ .placeholder = Najít v dokumentu…
+pdfjs-find-previous-button =
+ .title = Najde předchozí výskyt hledaného textu
+pdfjs-find-previous-button-label = Předchozí
+pdfjs-find-next-button =
+ .title = Najde další výskyt hledaného textu
+pdfjs-find-next-button-label = Další
+pdfjs-find-highlight-checkbox = Zvýraznit
+pdfjs-find-match-case-checkbox-label = Rozlišovat velikost
+pdfjs-find-match-diacritics-checkbox-label = Rozlišovat diakritiku
+pdfjs-find-entire-word-checkbox-label = Celá slova
+pdfjs-find-reached-top = Dosažen začátek dokumentu, pokračuje se od konce
+pdfjs-find-reached-bottom = Dosažen konec dokumentu, pokračuje se od začátku
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current }. z { $total } výskytu
+ [few] { $current }. z { $total } výskytů
+ [many] { $current }. z { $total } výskytů
+ *[other] { $current }. z { $total } výskytů
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Více než { $limit } výskyt
+ [few] Více než { $limit } výskyty
+ [many] Více než { $limit } výskytů
+ *[other] Více než { $limit } výskytů
+ }
+pdfjs-find-not-found = Hledaný text nenalezen
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Podle šířky
+pdfjs-page-scale-fit = Podle stránky
+pdfjs-page-scale-auto = Automatická velikost
+pdfjs-page-scale-actual = Skutečná velikost
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Strana { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Při nahrávání PDF nastala chyba.
+pdfjs-invalid-file-error = Neplatný nebo chybný soubor PDF.
+pdfjs-missing-file-error = Chybí soubor PDF.
+pdfjs-unexpected-response-error = Neočekávaná odpověď serveru.
+pdfjs-rendering-error = Při vykreslování stránky nastala chyba.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotace typu { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Pro otevření PDF souboru vložte heslo.
+pdfjs-password-invalid = Neplatné heslo. Zkuste to znovu.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Zrušit
+pdfjs-web-fonts-disabled = Webová písma jsou zakázána, proto není možné použít vložená písma PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Změna barvy textu
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Kreslení
+pdfjs-editor-color-picker-ink-input =
+ .title = Změna barvy kresby
+pdfjs-editor-ink-button-label = Kreslení
+pdfjs-editor-stamp-button =
+ .title = Přidání či úprava obrázků
+pdfjs-editor-stamp-button-label = Přidání či úprava obrázků
+pdfjs-editor-highlight-button =
+ .title = Zvýraznění
+pdfjs-editor-highlight-button-label = Zvýraznění
+pdfjs-highlight-floating-button1 =
+ .title = Zvýraznit
+ .aria-label = Zvýraznit
+pdfjs-highlight-floating-button-label = Zvýraznit
+pdfjs-comment-floating-button =
+ .title = Komentář
+ .aria-label = Komentář
+pdfjs-comment-floating-button-label = Komentář
+pdfjs-editor-comment-button =
+ .title = Komentář
+ .aria-label = Komentář
+pdfjs-editor-comment-button-label = Komentář
+pdfjs-editor-signature-button =
+ .title = Přidat podpis
+pdfjs-editor-signature-button-label = Přidat podpis
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor zvýraznění
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor kresby
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor podpisu: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor obrázků
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Odebrat kresbu
+pdfjs-editor-remove-freetext-button =
+ .title = Odebrat text
+pdfjs-editor-remove-stamp-button =
+ .title = Odebrat obrázek
+pdfjs-editor-remove-highlight-button =
+ .title = Odebrat zvýraznění
+pdfjs-editor-remove-signature-button =
+ .title = Odebrat podpis
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Barva
+pdfjs-editor-free-text-size-input = Velikost
+pdfjs-editor-ink-color-input = Barva
+pdfjs-editor-ink-thickness-input = Tloušťka
+pdfjs-editor-ink-opacity-input = Průhlednost
+pdfjs-editor-stamp-add-image-button =
+ .title = Přidat obrázek
+pdfjs-editor-stamp-add-image-button-label = Přidat obrázek
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tloušťka
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Změna tloušťky při zvýrazňování jiných položek než textu
+pdfjs-editor-add-signature-container =
+ .aria-label = Ovládací prvky pro podpisy a uložené podpisy
+pdfjs-editor-signature-add-signature-button =
+ .title = Přidat nový podpis
+pdfjs-editor-signature-add-signature-button-label = Přidat nový podpis
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Uložený podpis: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Textový editor
+ .default-content = Začněte psát...
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Komentář
+ [few] Komentáře
+ [many] Komentáře
+ *[other] Komentáře
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Zavřít postranní lištu
+ .aria-label = Zavřít postranní lištu
+pdfjs-editor-comments-sidebar-close-button-label = Zavřít postranní lištu
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vidíte něco pozoruhodného? Zvýrazněte to a zanechte komentář.
+pdfjs-editor-comments-sidebar-no-comments-link = Zjistit více
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Náhradní popis
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Upravit alternativní text
+pdfjs-editor-alt-text-dialog-label = Vyberte možnost
+pdfjs-editor-alt-text-dialog-description = Náhradní popis pomáhá, když lidé obrázek nevidí nebo když se nenačítá.
+pdfjs-editor-alt-text-add-description-label = Přidat popis
+pdfjs-editor-alt-text-add-description-description = Snažte se o 1-2 věty, které popisují předmět, prostředí nebo činnosti.
+pdfjs-editor-alt-text-mark-decorative-label = Označit jako dekorativní
+pdfjs-editor-alt-text-mark-decorative-description = Používá se pro okrasné obrázky, jako jsou rámečky nebo vodoznaky.
+pdfjs-editor-alt-text-cancel-button = Zrušit
+pdfjs-editor-alt-text-save-button = Uložit
+pdfjs-editor-alt-text-decorative-tooltip = Označen jako dekorativní
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Například: “Mladý muž si sedá ke stolu, aby se najedl.”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativní text
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Levý horní roh — změna velikosti
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Horní střed — změna velikosti
+pdfjs-editor-resizer-top-right =
+ .aria-label = Pravý horní roh — změna velikosti
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Vpravo uprostřed — změna velikosti
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Pravý dolní roh — změna velikosti
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Střed dole — změna velikosti
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Levý dolní roh — změna velikosti
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Vlevo uprostřed — změna velikosti
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Barva zvýraznění
+pdfjs-editor-colorpicker-button =
+ .title = Změna barvy
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Výběr barev
+pdfjs-editor-colorpicker-yellow =
+ .title = Žlutá
+pdfjs-editor-colorpicker-green =
+ .title = Zelená
+pdfjs-editor-colorpicker-blue =
+ .title = Modrá
+pdfjs-editor-colorpicker-pink =
+ .title = Růžová
+pdfjs-editor-colorpicker-red =
+ .title = Červená
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Zobrazit vše
+pdfjs-editor-highlight-show-all-button =
+ .title = Zobrazit vše
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Upravit alternativní text (popis obrázku)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Přidat alternativní text (popis obrázku)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Sem napište svůj popis…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Krátký popis pro lidi, kteří neuvidí obrázek nebo když se obrázek nenačítá.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Tento alternativní text byl vytvořen automaticky a může být nepřesný.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Více informací
+pdfjs-editor-new-alt-text-create-automatically-button-label = Vytvořit alternativní text automaticky
+pdfjs-editor-new-alt-text-not-now-button = Teď ne
+pdfjs-editor-new-alt-text-error-title = Nepodařilo se automaticky vytvořit alternativní text
+pdfjs-editor-new-alt-text-error-description = Napište prosím vlastní alternativní text nebo to zkuste znovu později.
+pdfjs-editor-new-alt-text-error-close-button = Zavřít
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Stahuje se model AI pro alternativní texty ({ $downloadedSize } z { $totalSize } MB)
+ .aria-valuetext = Stahuje se model AI pro alternativní texty ({ $downloadedSize } z { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativní text byl přidán
+pdfjs-editor-new-alt-text-added-button-label = Alternativní text byl přidán
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Chybí alternativní text
+pdfjs-editor-new-alt-text-missing-button-label = Chybí alternativní text
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Zkontrolovat alternativní text
+pdfjs-editor-new-alt-text-to-review-button-label = Zkontrolovat alternativní text
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Vytvořeno automaticky: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Nastavení alternativního textu obrázku
+pdfjs-image-alt-text-settings-button-label = Nastavení alternativního textu obrázku
+pdfjs-editor-alt-text-settings-dialog-label = Nastavení alternativního textu obrázku
+pdfjs-editor-alt-text-settings-automatic-title = Automatický alternativní text
+pdfjs-editor-alt-text-settings-create-model-button-label = Vytvořit alternativní text automaticky
+pdfjs-editor-alt-text-settings-create-model-description = Navrhuje popisy, které pomohou lidem, kteří nevidí obrázek nebo když se obrázek nenačte.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model AI pro alternativní text ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Běží lokálně na vašem zařízení, takže vaše data zůstávají v bezpečí. Vyžadováno pro automatický alternativní text.
+pdfjs-editor-alt-text-settings-delete-model-button = Smazat
+pdfjs-editor-alt-text-settings-download-model-button = Stáhnout
+pdfjs-editor-alt-text-settings-downloading-model-button = Probíhá stahování...
+pdfjs-editor-alt-text-settings-editor-title = Editor alternativního textu
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Při přidávání obrázku hned zobrazit editor alternativního textu
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomůže vám zajistit, aby všechny vaše obrázky obsahovaly alternativní text.
+pdfjs-editor-alt-text-settings-close-button = Zavřít
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Přidáno zvýraznění
+pdfjs-editor-freetext-added-alert = Text přidán
+pdfjs-editor-ink-added-alert = Kresba byla přidána
+pdfjs-editor-stamp-added-alert = Obrázek byl přidán
+pdfjs-editor-signature-added-alert = Byl přidán podpis
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Zvýraznění odebráno
+pdfjs-editor-undo-bar-message-freetext = Text odstraněn
+pdfjs-editor-undo-bar-message-ink = Kresba odstraněna
+pdfjs-editor-undo-bar-message-stamp = Obrázek odebrán
+pdfjs-editor-undo-bar-message-signature = Podpis odebrán
+pdfjs-editor-undo-bar-message-comment = Komentář odebrán
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotace odebrána
+ [few] { $count } anotace odebrány
+ [many] { $count } anotací odebráno
+ *[other] { $count } anotací odebráno
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Zpět
+pdfjs-editor-undo-bar-undo-button-label = Zpět
+pdfjs-editor-undo-bar-close-button =
+ .title = Zavřít
+pdfjs-editor-undo-bar-close-button-label = Zavřít
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Tento způsob umožňuje uživateli vytvořit podpis, který se přidá do dokumentu PDF. Uživatel může upravit jméno (které slouží zároveň jako alternativní text) a podpis uložit pro pozdější použití.
+pdfjs-editor-add-signature-dialog-title = Přidat podpis
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Psát
+ .title = Psát
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Kreslit
+ .title = Kreslit
+pdfjs-editor-add-signature-image-button = Obrázek
+ .title = Obrázek
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Zadejte svůj podpis
+ .placeholder = Zadejte svůj podpis
+pdfjs-editor-add-signature-draw-placeholder = Nakreslete svůj podpis
+pdfjs-editor-add-signature-draw-thickness-range-label = Tloušťka
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Tloušťka kresby: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Přetáhněte sem soubor, který chcete nahrát
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Nebo vyberte soubory obrazu
+ *[other] Nebo vyberte soubory obrazu
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Popis (alternativní text)
+pdfjs-editor-add-signature-description-input =
+ .title = Popis (alternativní text)
+pdfjs-editor-add-signature-description-default-when-drawing = Podpis
+pdfjs-editor-add-signature-clear-button-label = Vymazání podpisu
+pdfjs-editor-add-signature-clear-button =
+ .title = Vymazání podpisu
+pdfjs-editor-add-signature-save-checkbox = Uložit podpis
+pdfjs-editor-add-signature-save-warning-message = Dosáhli jste limitu 5 uložených podpisů. Chcete-li uložit další, jeden odstraňte.
+pdfjs-editor-add-signature-image-upload-error-title = Obrázek se nepodařilo nahrát
+pdfjs-editor-add-signature-image-upload-error-description = Zkontrolujte připojení k síti nebo zkuste jiný obrázek.
+pdfjs-editor-add-signature-image-no-data-error-title = Nelze převést tento obrázek na podpis
+pdfjs-editor-add-signature-image-no-data-error-description = Zkuste nahrát jiný obrázek.
+pdfjs-editor-add-signature-error-close-button = Zavřít
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Zrušit
+pdfjs-editor-add-signature-add-button = Přidat
+pdfjs-editor-edit-signature-update-button = Aktualizovat
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Upravit komentář
+pdfjs-editor-edit-comment-popup-button =
+ .title = Upravit komentář
+pdfjs-editor-delete-comment-popup-button-label = Odebrat komentář
+pdfjs-editor-delete-comment-popup-button =
+ .title = Odebrat komentář
+pdfjs-show-comment-button =
+ .title = Zobrazit komentář
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Upravit komentář
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualizovat
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Přidání komentáře
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Přidat
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Začněte psát…
+pdfjs-editor-edit-comment-dialog-cancel-button = Zrušit
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Přidání komentáře
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Přepnout postranní lištu (dokument obsahuje náhledy/osnovu/přílohy/vrstvy)
+pdfjs-toggle-views-manager-button1-label = Spravovat strany
+pdfjs-views-manager-sidebar =
+ .aria-label = Postranní lišta
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Změna velikosti v postranní liště
+pdfjs-views-manager-view-selector-button =
+ .title = Zobrazení
+pdfjs-views-manager-view-selector-button-label = Zobrazení
+pdfjs-views-manager-pages-title = Stránky
+pdfjs-views-manager-outlines-title1 = Osnova dokumentu
+ .title = Osnova dokumentu (dvojité klepnutí rozbalí/sbalí všechny položky)
+pdfjs-views-manager-attachments-title = Přílohy
+pdfjs-views-manager-layers-title1 = Vrstvy
+ .title = Vrstvy (dvojité klepnutí obnoví všechny vrstvy do výchozího stavu)
+pdfjs-views-manager-pages-option-label = Stránky
+pdfjs-views-manager-outlines-option-label = Osnova dokumentu
+pdfjs-views-manager-attachments-option-label = Přílohy
+pdfjs-views-manager-layers-option-label = Vrstvy
+pdfjs-views-manager-add-file-button =
+ .title = Přidat soubor
+pdfjs-views-manager-add-file-button-label = Přidat soubor
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } vybrána
+ [few] { $count } vybrány
+ [many] { $count } vybráno
+ *[other] { $count } vybráno
+ }
+pdfjs-views-manager-pages-status-none-action-label = Výběr stránek
+pdfjs-views-manager-pages-status-action-button-label = Správa
+pdfjs-views-manager-pages-status-copy-button-label = Kopírovat
+pdfjs-views-manager-pages-status-cut-button-label = Vyjmout
+pdfjs-views-manager-pages-status-delete-button-label = Smazat
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportovat vybrané…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 stránka vyjmuta
+ [few] { $count } stránky vyjmuty
+ [many] { $count } stránek vyjmuto
+ *[other] { $count } stránek vyjmuto
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 stránka zkopírována
+ [few] { $count } stránky zkopírovány
+ [many] { $count } stránek zkopírováno
+ *[other] { $count } stránek zkopírováno
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 stránka smazána
+ [few] { $count } stránky smazány
+ [many] { $count } stránek smazáno
+ *[other] { $count } stránek smazáno
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Příprava vašeho souboru…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Nahrávání souboru…
+pdfjs-views-manager-status-warning-cut-label = Nelze vyjmout. Obnovte stránku a zkuste to znovu.
+pdfjs-views-manager-status-warning-copy-label = Kopírování se nezdařilo. Obnovte stránku a zkuste to znovu.
+pdfjs-views-manager-status-warning-delete-label = Smazání se nezdařilo. Obnovte stránku a zkuste to znovu.
+pdfjs-views-manager-status-warning-save-label = Nepodařilo se uložit. Obnovte stránku a zkuste to znovu.
+pdfjs-views-manager-status-undo-button-label = Zpět
+pdfjs-views-manager-status-done-button-label = Hotovo
+pdfjs-views-manager-status-close-button =
+ .title = Zavřít
+pdfjs-views-manager-status-close-button-label = Zavřít
+pdfjs-views-manager-paste-button-label = Vložit
+pdfjs-views-manager-paste-button-before =
+ .title = Vloží před první stránku
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Vložit za stránku { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVÉ
+pdfjs-views-manager-waiting-for-file = Nahrávání souboru…
+pdfjs-toggle-views-manager-button1 =
+ .title = Spravovat strany
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Vlastnosti digitálního podpisu
+ .aria-label = Vlastnosti digitálního podpisu
+pdfjs-digital-signature-properties-button-label = Vlastnosti digitálního podpisu
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument byl podepsán platným digitálním podpisem
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument je podepsán, ale { $count } elektronický podpis se nepodařilo ověřit
+ [few] Dokument je podepsán, ale { $count } elektronické podpisy se nepodařilo ověřit
+ [many] Dokument je podepsán, ale { $count } elektronických podpisů se nepodařilo ověřit
+ *[other] Dokument je podepsán, ale { $count } elektronických podpisů se nepodařilo ověřit
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument podepsaný { $count } certifikátem, který není důvěryhodný
+ [few] Dokument podepsaný { $count } certifikáty, které nejsou důvěryhodné
+ [many] Dokument podepsaný { $count } certifikáty, které nejsou důvěryhodné
+ *[other] Dokument podepsaný { $count } certifikáty, které nejsou důvěryhodné
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument je podepsaný { $count } prošlým certifikátem
+ [few] Dokument je podepsaný { $count } prošlými certifikáty
+ [many] Dokument je podepsaný { $count } prošlými certifikáty
+ *[other] Dokument je podepsaný { $count } prošlými certifikáty
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument má { $count } neplatný elektronický podpis
+ [few] Dokument má { $count } neplatné elektronické podpisy
+ [many] Dokument má { $count } neplatných elektronických podpisů
+ *[other] Dokument má { $count } neplatných elektronických podpisů
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument je podepsaný { $count } zneplatněným certifikátem
+ [few] Dokument je podepsaný { $count } zneplatněnými certifikáty
+ [many] Dokument je podepsaný { $count } zneplatněnými certifikáty
+ *[other] Dokument je podepsaný { $count } zneplatněnými certifikáty
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stav: Podpis ověřen
+pdfjs-digital-signature-properties-status-invalid = Stav: Podpis je neplatný
+pdfjs-digital-signature-properties-status-unknown = Stav: Nelze ověřit (nepodporováno)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certifikát: Důvěryhodný ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certifikát: nedostupný
+pdfjs-digital-signature-properties-certificate-untrusted = Certifikát: nedůvěryhodný
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certifikát: Neznámý vydavatel ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certifikát: Self-signed ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certifikát: Nedůvěryhodný vydavatel ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certifikát: vypršel
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certifikát: Vypršel ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certifikát: zneplatněn
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Odebrat uložený podpis
+pdfjs-editor-delete-signature-button-label1 = Odebrat uložený podpis
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Upravit popis
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Upravit popis
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cy/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cy/viewer.ftl
new file mode 100644
index 0000000..66d3ff6
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/cy/viewer.ftl
@@ -0,0 +1,892 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Tudalen Flaenorol
+pdfjs-previous-button-label = Blaenorol
+pdfjs-next-button =
+ .title = Tudalen Nesaf
+pdfjs-next-button-label = Nesaf
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Tudalen
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = o { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } o { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Lleihau
+pdfjs-zoom-out-button-label = Lleihau
+pdfjs-zoom-in-button =
+ .title = Cynyddu
+pdfjs-zoom-in-button-label = Cynyddu
+pdfjs-zoom-select =
+ .title = Chwyddo
+pdfjs-presentation-mode-button =
+ .title = Newid i'r Modd Cyflwyno
+pdfjs-presentation-mode-button-label = Modd Cyflwyno
+pdfjs-open-file-button =
+ .title = Agor Ffeil
+pdfjs-open-file-button-label = Agor
+pdfjs-print-button =
+ .title = Argraffu
+pdfjs-print-button-label = Argraffu
+pdfjs-save-button =
+ .title = Cadw
+pdfjs-save-button-label = Cadw
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Llwytho i lawr
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Llwytho i lawr
+pdfjs-bookmark-button =
+ .title = Tudalen Gyfredol (Gweld URL o'r Dudalen Gyfredol)
+pdfjs-bookmark-button-label = Tudalen Gyfredol
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Offer
+pdfjs-tools-button-label = Offer
+pdfjs-first-page-button =
+ .title = Mynd i'r Dudalen Gyntaf
+pdfjs-first-page-button-label = Mynd i'r Dudalen Gyntaf
+pdfjs-last-page-button =
+ .title = Mynd i'r Dudalen Olaf
+pdfjs-last-page-button-label = Mynd i'r Dudalen Olaf
+pdfjs-page-rotate-cw-button =
+ .title = Cylchdroi Clocwedd
+pdfjs-page-rotate-cw-button-label = Cylchdroi Clocwedd
+pdfjs-page-rotate-ccw-button =
+ .title = Cylchdroi Gwrthglocwedd
+pdfjs-page-rotate-ccw-button-label = Cylchdroi Gwrthglocwedd
+pdfjs-cursor-text-select-tool-button =
+ .title = Galluogi Dewis Offeryn Testun
+pdfjs-cursor-text-select-tool-button-label = Offeryn Dewis Testun
+pdfjs-cursor-hand-tool-button =
+ .title = Galluogi Offeryn Llaw
+pdfjs-cursor-hand-tool-button-label = Offeryn Llaw
+pdfjs-scroll-page-button =
+ .title = Defnyddio Sgrolio Tudalen
+pdfjs-scroll-page-button-label = Sgrolio Tudalen
+pdfjs-scroll-vertical-button =
+ .title = Defnyddio Sgrolio Fertigol
+pdfjs-scroll-vertical-button-label = Sgrolio Fertigol
+pdfjs-scroll-horizontal-button =
+ .title = Defnyddio Sgrolio Llorweddol
+pdfjs-scroll-horizontal-button-label = Sgrolio Llorweddol
+pdfjs-scroll-wrapped-button =
+ .title = Defnyddio Sgrolio Amlapio
+pdfjs-scroll-wrapped-button-label = Sgrolio Amlapio
+pdfjs-spread-none-button =
+ .title = Peidio uno trawsdaleniadau
+pdfjs-spread-none-button-label = Dim Trawsdaleniadau
+pdfjs-spread-odd-button =
+ .title = Uno trawsdaleniadau gan gychwyn gyda thudalennau odrif
+pdfjs-spread-odd-button-label = Trawsdaleniadau Odrif
+pdfjs-spread-even-button =
+ .title = Uno trawsdaleniadau gan gychwyn gyda thudalennau eilrif
+pdfjs-spread-even-button-label = Trawsdaleniadau Eilrif
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Priodweddau Dogfen…
+pdfjs-document-properties-button-label = Priodweddau Dogfen…
+pdfjs-document-properties-file-name = Enw ffeil:
+pdfjs-document-properties-file-size = Maint ffeil:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } beit)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } beit)
+pdfjs-document-properties-title = Teitl:
+pdfjs-document-properties-author = Awdur:
+pdfjs-document-properties-subject = Pwnc:
+pdfjs-document-properties-keywords = Allweddair:
+pdfjs-document-properties-creation-date = Dyddiad Creu:
+pdfjs-document-properties-modification-date = Dyddiad Addasu:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Crewr:
+pdfjs-document-properties-producer = Cynhyrchydd PDF:
+pdfjs-document-properties-version = Fersiwn PDF:
+pdfjs-document-properties-page-count = Cyfrif Tudalen:
+pdfjs-document-properties-page-size = Maint Tudalen:
+pdfjs-document-properties-page-size-unit-inches = o fewn
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portread
+pdfjs-document-properties-page-size-orientation-landscape = tirlun
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Llythyr
+pdfjs-document-properties-page-size-name-legal = Cyfreithiol
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Golwg Gwe Cyflym:
+pdfjs-document-properties-linearized-yes = Iawn
+pdfjs-document-properties-linearized-no = Na
+pdfjs-document-properties-close-button = Cau
+pdfjs-digital-signature-properties-view-certificate = Gweld tystysgrif
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Rheswm: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Stamp amser: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [zero] Is-lofnodion ( { $count } )
+ [one] Is-lofnodion ( { $count } )
+ [two] Is-lofnodion ( { $count } )
+ [few] Is-lofnodion ( { $count } )
+ [many] Is-lofnodion ( { $count } )
+ *[other] Is-lofnodion ( { $count } )
+ }
+
+## Print
+
+pdfjs-print-progress-message = Paratoi dogfen ar gyfer ei hargraffu…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Diddymu
+pdfjs-printing-not-supported = Rhybudd: Nid yw argraffu yn cael ei gynnal yn llawn gan y porwr.
+pdfjs-printing-not-ready = Rhybudd: Nid yw'r PDF wedi ei lwytho'n llawn ar gyfer argraffu.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toglo'r Bar Ochr
+pdfjs-toggle-sidebar-notification-button =
+ .title = Toglo'r Bar Ochr (mae'r ddogfen yn cynnwys amlinelliadau/atodiadau/haenau)
+pdfjs-toggle-sidebar-button-label = Toglo'r Bar Ochr
+pdfjs-document-outline-button =
+ .title = Dangos Amlinell Dogfen (clic dwbl i ymestyn/cau pob eitem)
+pdfjs-document-outline-button-label = Amlinelliad Dogfen
+pdfjs-attachments-button =
+ .title = Dangos Atodiadau
+pdfjs-attachments-button-label = Atodiadau
+pdfjs-layers-button =
+ .title = Dangos Haenau (cliciwch ddwywaith i ailosod yr holl haenau i'r cyflwr rhagosodedig)
+pdfjs-layers-button-label = Haenau
+pdfjs-thumbs-button =
+ .title = Dangos Lluniau Bach
+pdfjs-thumbs-button-label = Lluniau Bach
+pdfjs-current-outline-item-button =
+ .title = Canfod yr Eitem Amlinellol Gyfredol
+pdfjs-current-outline-item-button-label = Yr Eitem Amlinellol Gyfredol
+pdfjs-findbar-button =
+ .title = Canfod yn y Ddogfen
+pdfjs-findbar-button-label = Canfod
+pdfjs-additional-layers = Haenau Ychwanegol
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Tudalen { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Llun Bach Tudalen { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Dewis tudalen { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Tudalen { $page } o { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Canfod
+ .placeholder = Canfod yn y ddogfen…
+pdfjs-find-previous-button =
+ .title = Canfod enghraifft flaenorol o'r ymadrodd
+pdfjs-find-previous-button-label = Blaenorol
+pdfjs-find-next-button =
+ .title = Canfod enghraifft nesaf yr ymadrodd
+pdfjs-find-next-button-label = Nesaf
+pdfjs-find-highlight-checkbox = Amlygu Popeth
+pdfjs-find-match-case-checkbox-label = Cydweddu Maint
+pdfjs-find-match-diacritics-checkbox-label = Diacritigau Cyfatebol
+pdfjs-find-entire-word-checkbox-label = Geiriau Cyfan
+pdfjs-find-reached-top = Wedi cyrraedd brig y dudalen, parhau o'r gwaelod
+pdfjs-find-reached-bottom = Wedi cyrraedd diwedd y dudalen, parhau o'r brig
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [zero] { $current } o { $total } cydweddiadau
+ [one] { $current } o { $total } cydweddiad
+ [two] { $current } o { $total } gydweddiad
+ [few] { $current } o { $total } cydweddiad
+ [many] { $current } o { $total } chydweddiad
+ *[other] { $current } o { $total } cydweddiad
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [zero] Mwy nag { $limit } cydweddiadau
+ [one] Mwy nag { $limit } cydweddiad
+ [two] Mwy nag { $limit } gydweddiad
+ [few] Mwy nag { $limit } cydweddiad
+ [many] Mwy nag { $limit } chydweddiad
+ *[other] Mwy nag { $limit } cydweddiad
+ }
+pdfjs-find-not-found = Heb ganfod ymadrodd
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lled Tudalen
+pdfjs-page-scale-fit = Ffit Tudalen
+pdfjs-page-scale-auto = Chwyddo Awtomatig
+pdfjs-page-scale-actual = Maint Gwirioneddol
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Tudalen { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Digwyddodd gwall wrth lwytho'r PDF.
+pdfjs-invalid-file-error = Ffeil PDF annilys neu llwgr.
+pdfjs-missing-file-error = Ffeil PDF coll.
+pdfjs-unexpected-response-error = Ymateb annisgwyl gan y gweinydd.
+pdfjs-rendering-error = Digwyddodd gwall wrth adeiladu'r dudalen.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anodiad { $type } ]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Rhowch gyfrinair i agor y PDF.
+pdfjs-password-invalid = Cyfrinair annilys. Ceisiwch eto.
+pdfjs-password-ok-button = Iawn
+pdfjs-password-cancel-button = Diddymu
+pdfjs-web-fonts-disabled = Ffontiau gwe wedi eu hanalluogi: methu defnyddio ffontiau PDF mewnblanedig.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Testun
+pdfjs-editor-color-picker-free-text-input =
+ .title = Newid lliw testun
+pdfjs-editor-free-text-button-label = Testun
+pdfjs-editor-ink-button =
+ .title = Lluniadu
+pdfjs-editor-color-picker-ink-input =
+ .title = Newid lliw lluniadu
+pdfjs-editor-ink-button-label = Lluniadu
+pdfjs-editor-stamp-button =
+ .title = Ychwanegu neu olygu delweddau
+pdfjs-editor-stamp-button-label = Ychwanegu neu olygu delweddau
+pdfjs-editor-highlight-button =
+ .title = Amlygu
+pdfjs-editor-highlight-button-label = Amlygu
+pdfjs-highlight-floating-button1 =
+ .title = Amlygu
+ .aria-label = Amlygu
+pdfjs-highlight-floating-button-label = Amlygu
+pdfjs-comment-floating-button =
+ .title = Sylw
+ .aria-label = Sylw
+pdfjs-comment-floating-button-label = Sylw
+pdfjs-editor-comment-button =
+ .title = Sylw
+ .aria-label = Sylw
+pdfjs-editor-comment-button-label = Sylw
+pdfjs-editor-signature-button =
+ .title = Ychwanegu llofnod
+pdfjs-editor-signature-button-label = Ychwanegu llofnod
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Golygydd amlygu
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Golygydd lluniadu
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Golygydd llofnod: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Golygydd delweddau
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Dileu lluniad
+pdfjs-editor-remove-freetext-button =
+ .title = Dileu testun
+pdfjs-editor-remove-stamp-button =
+ .title = Dileu delwedd
+pdfjs-editor-remove-highlight-button =
+ .title = Tynnu amlygiad
+pdfjs-editor-remove-signature-button =
+ .title = Dileu llofnod
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Lliw
+pdfjs-editor-free-text-size-input = Maint
+pdfjs-editor-ink-color-input = Lliw
+pdfjs-editor-ink-thickness-input = Trwch
+pdfjs-editor-ink-opacity-input = Didreiddedd
+pdfjs-editor-stamp-add-image-button =
+ .title = Ychwanegu delwedd
+pdfjs-editor-stamp-add-image-button-label = Ychwanegu delwedd
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Trwch
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Newid trwch wrth amlygu eitemau heblaw testun
+pdfjs-editor-add-signature-container =
+ .aria-label = Rheolyddion llofnodion a llofnodion wedi'u cadw
+pdfjs-editor-signature-add-signature-button =
+ .title = Ychwanegu llofnod newydd
+pdfjs-editor-signature-add-signature-button-label = Ychwanegu llofnod newydd
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Llofnod wedi'i gadw: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Golygydd Testun
+ .default-content = Cychwyn teipio…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [zero] Sylwadau
+ [one] Sylw
+ [two] Sylw
+ [few] Sylw
+ [many] Sylw
+ *[other] Sylw
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Cau'r bar ochr
+ .aria-label = Cau'r bar ochr
+pdfjs-editor-comments-sidebar-close-button-label = Cau'r bar ochr
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Gweld rhywbeth nodedig? Amlygwch ef a gadael sylw.
+pdfjs-editor-comments-sidebar-no-comments-link = Dysgu rhagor
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Testun amgen (alt)
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Golygu testun amgen
+pdfjs-editor-alt-text-dialog-label = Dewisiadau
+pdfjs-editor-alt-text-dialog-description = Mae testun amgen (testun alt) yn helpu pan na all pobl weld y ddelwedd neu pan nad yw'n llwytho.
+pdfjs-editor-alt-text-add-description-label = Ychwanegu disgrifiad
+pdfjs-editor-alt-text-add-description-description = Anelwch at 1-2 frawddeg sy'n disgrifio'r pwnc, y cefndir neu'r gweithredoedd.
+pdfjs-editor-alt-text-mark-decorative-label = Marcio fel addurniadol
+pdfjs-editor-alt-text-mark-decorative-description = Mae'n cael ei ddefnyddio ar gyfer delweddau addurniadol, fel borderi neu farciau dŵr.
+pdfjs-editor-alt-text-cancel-button = Diddymu
+pdfjs-editor-alt-text-save-button = Cadw
+pdfjs-editor-alt-text-decorative-tooltip = Marcio fel addurniadol
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Er enghraifft, “Mae dyn ifanc yn eistedd wrth fwrdd i fwyta pryd bwyd”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Testun amgen (alt)
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Y gornel chwith uchaf — newid maint
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Canol uchaf - newid maint
+pdfjs-editor-resizer-top-right =
+ .aria-label = Y gornel dde uchaf - newid maint
+pdfjs-editor-resizer-middle-right =
+ .aria-label = De canol - newid maint
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Y gornel dde isaf — newid maint
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Canol gwaelod — newid maint
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Y gornel chwith isaf — newid maint
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Chwith canol — newid maint
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Lliw amlygu
+pdfjs-editor-colorpicker-button =
+ .title = Newid lliw
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Dewisiadau lliw
+pdfjs-editor-colorpicker-yellow =
+ .title = Melyn
+pdfjs-editor-colorpicker-green =
+ .title = Gwyrdd
+pdfjs-editor-colorpicker-blue =
+ .title = Glas
+pdfjs-editor-colorpicker-pink =
+ .title = Pinc
+pdfjs-editor-colorpicker-red =
+ .title = Coch
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Dangos y cyfan
+pdfjs-editor-highlight-show-all-button =
+ .title = Dangos y cyfan
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Golygu testun amgen (disgrifiad o ddelwedd)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Ychwanegwch destun amgen (disgrifiad delwedd)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Ysgrifennwch eich disgrifiad yma…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Disgrifiad byr ar gyfer pobl sydd ddim yn gallu gweld y ddelwedd neu pan nad yw'r ddelwedd yn llwytho.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Cafodd y testun amgen hwn ei greu'n awtomatig a gall fod yn anghywir.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Rhagor
+pdfjs-editor-new-alt-text-create-automatically-button-label = Creu testun amgen yn awtomatig
+pdfjs-editor-new-alt-text-not-now-button = Nid nawr
+pdfjs-editor-new-alt-text-error-title = Methu â chreu testun amgen yn awtomatig
+pdfjs-editor-new-alt-text-error-description = Ysgrifennwch eich testun amgen eich hun neu ceisiwch eto yn nes ymlaen.
+pdfjs-editor-new-alt-text-error-close-button = Cau
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Wrthi'n llwytho i lawr model AI testun amgen ( { $downloadedSize } o { $totalSize } MB)
+ .aria-valuetext = Wrthi'n llwytho i lawr model AI testun amgen ( { $downloadedSize } o { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Ychwanegwyd testun amgen
+pdfjs-editor-new-alt-text-added-button-label = Ychwanegwyd testun amgen
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Testun amgen coll
+pdfjs-editor-new-alt-text-missing-button-label = Testun amgen coll
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Adolygu'r testun amgen
+pdfjs-editor-new-alt-text-to-review-button-label = Adolygu'r testun amgen
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Crëwyd yn awtomatig: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Gosodiadau testun amgen delwedd
+pdfjs-image-alt-text-settings-button-label = Gosodiadau testun amgen delwedd
+pdfjs-editor-alt-text-settings-dialog-label = Gosodiadau testun amgen delwedd
+pdfjs-editor-alt-text-settings-automatic-title = Testun amgen awtomatig
+pdfjs-editor-alt-text-settings-create-model-button-label = Creu testun amgen yn awtomatig
+pdfjs-editor-alt-text-settings-create-model-description = Yn awgrymu disgrifiadau i helpu pobl sydd ddim yn gallu gweld y ddelwedd neu pan nad yw'r ddelwedd yn llwytho.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model AI testun amgen ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Yn rhedeg yn lleol ar eich dyfais fel bod eich data'n aros yn breifat. Yn ofynnol ar gyfer testun amgen awtomatig.
+pdfjs-editor-alt-text-settings-delete-model-button = Dileu
+pdfjs-editor-alt-text-settings-download-model-button = Llwytho i Lawr
+pdfjs-editor-alt-text-settings-downloading-model-button = Wrthi'n llwytho i lawr…
+pdfjs-editor-alt-text-settings-editor-title = Golygydd testun amgen
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Dangoswch y golygydd testun amgen yn syth wrth ychwanegu delwedd
+pdfjs-editor-alt-text-settings-show-dialog-description = Yn eich helpu i wneud yn siŵr bod gan eich holl ddelweddau destun amgen.
+pdfjs-editor-alt-text-settings-close-button = Cau
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Amlygu wedi'i ychwanegu
+pdfjs-editor-freetext-added-alert = Testun wedi'i ychwanegu
+pdfjs-editor-ink-added-alert = Lluniadu wedi'i ychwanegu
+pdfjs-editor-stamp-added-alert = Delwedd wedi'i hychwanegu
+pdfjs-editor-signature-added-alert = Llofnod wedi'i ychwanegu
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Tynnwyd yr amlygu
+pdfjs-editor-undo-bar-message-freetext = Tynnwyd y testun
+pdfjs-editor-undo-bar-message-ink = Tynnwyd y lluniad
+pdfjs-editor-undo-bar-message-stamp = Tynnwyd y ddelwedd
+pdfjs-editor-undo-bar-message-signature = Llofnod wedi'i dynnu
+pdfjs-editor-undo-bar-message-comment = Sylw wedi'i dynnu
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [zero] { $count } anodiad wedi'u tynnu
+ [one] { $count } anodiad wedi'i dynnu
+ [two] { $count } anodiad wedi'u tynnu
+ [few] { $count } anodiad wedi'u tynnu
+ [many] { $count } anodiad wedi'u tynnu
+ *[other] { $count } anodiad wedi'u tynnu
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Dadwneud
+pdfjs-editor-undo-bar-undo-button-label = Dadwneud
+pdfjs-editor-undo-bar-close-button =
+ .title = Cau
+pdfjs-editor-undo-bar-close-button-label = Cau
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Mae'r modd hwn yn caniatáu i'r defnyddiwr greu llofnod i'w ychwanegu at ddogfen PDF. Gall y defnyddiwr olygu'r enw (sydd hefyd yn gweithredu fel y testun amgen), ac yn ddewisol cadw'r llofnod i'w ddefnyddio dro ar ôl tro.
+pdfjs-editor-add-signature-dialog-title = Ychwanegu llofnod
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Math
+ .title = Math
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Lluniadu
+ .title = Lluniadu
+pdfjs-editor-add-signature-image-button = Delwedd
+ .title = Delwedd
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Teipiwch eich llofnod
+ .placeholder = Teipiwch eich llofnod
+pdfjs-editor-add-signature-draw-placeholder = Lluniwch eich llofnod
+pdfjs-editor-add-signature-draw-thickness-range-label = Trwch
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Trwch y llinell: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Llusgwch ffeil yma i'w llwytho
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Neu ddewis ffeiliau delwedd
+ *[other] Neu bori ffeiliau delwedd
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Disgrifiad (testun amgen)
+pdfjs-editor-add-signature-description-input =
+ .title = Disgrifiad (testun amgen)
+pdfjs-editor-add-signature-description-default-when-drawing = Llofnod
+pdfjs-editor-add-signature-clear-button-label = Diddymu llofnod
+pdfjs-editor-add-signature-clear-button =
+ .title = Diddymu llofnod
+pdfjs-editor-add-signature-save-checkbox = Cadw llofnod
+pdfjs-editor-add-signature-save-warning-message = Rydych chi wedi cyrraedd y terfyn o 5 llofnod sydd wedi'u cadw. Tynnwch un i gadw rhagor
+pdfjs-editor-add-signature-image-upload-error-title = Methu llwytho'r ddelwedd.
+pdfjs-editor-add-signature-image-upload-error-description = Gwiriwch eich cysylltiad rhwydwaith neu rhowch gynnig ar ddelwedd arall.
+pdfjs-editor-add-signature-image-no-data-error-title = Methu trosi'r ddelwedd hon yn llofnod
+pdfjs-editor-add-signature-image-no-data-error-description = Ceisiwch lwytho delwedd wahanol.
+pdfjs-editor-add-signature-error-close-button = Cau
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Diddymu
+pdfjs-editor-add-signature-add-button = Ychwanegu
+pdfjs-editor-edit-signature-update-button = Diweddaru
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Golygu sylw
+pdfjs-editor-edit-comment-popup-button =
+ .title = Golygu sylw
+pdfjs-editor-delete-comment-popup-button-label = Tynnu sylw
+pdfjs-editor-delete-comment-popup-button =
+ .title = Tynnu sylw
+pdfjs-show-comment-button =
+ .title = Dangos sylw
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Golygu sylw
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Diweddaru
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Ychwanegu sylw
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Ychwanegu
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Cychwyn teipio…
+pdfjs-editor-edit-comment-dialog-cancel-button = Diddymu
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Ychwanegu sylw
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Togl y Bar Ochr (dogfen yn cynnwys lluniau bach/amlinelliad/atodiadau/haenau)
+pdfjs-toggle-views-manager-button1-label = Rheoli tudalennau
+pdfjs-views-manager-sidebar =
+ .aria-label = Bar Ochr
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Newid maint bar ochr
+pdfjs-views-manager-view-selector-button =
+ .title = Golygon
+pdfjs-views-manager-view-selector-button-label = Golygon
+pdfjs-views-manager-pages-title = Tudalennau
+pdfjs-views-manager-outlines-title1 = Amlinelliad Dogfen
+ .title = Amlinelliad dogfen (clic dwbl i ehangu/leihau pob eitem)
+pdfjs-views-manager-attachments-title = Atodiadau
+pdfjs-views-manager-layers-title1 = Haenau
+ .title = Haenau clic dwbl i ailosod pob haen i'r cyflwr ragosodedig)
+pdfjs-views-manager-pages-option-label = Tudalennau
+pdfjs-views-manager-outlines-option-label = Amlinelliad dogfen
+pdfjs-views-manager-attachments-option-label = Atodiadau
+pdfjs-views-manager-layers-option-label = Haenau
+pdfjs-views-manager-add-file-button =
+ .title = Ychwanegu ffeil
+pdfjs-views-manager-add-file-button-label = Ychwanegu ffeil
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [zero] { $count } wedi'u dewis
+ [one] { $count } wedi'i dewis
+ [two] { $count } wedi'u dewis
+ [few] { $count } wedi'u dewis
+ [many] { $count } wedi'u dewis
+ *[other] { $count } wedi'u dewis
+ }
+pdfjs-views-manager-pages-status-none-action-label = Dewiswch dudalennau
+pdfjs-views-manager-pages-status-action-button-label = Rheoli
+pdfjs-views-manager-pages-status-copy-button-label = Copïo
+pdfjs-views-manager-pages-status-cut-button-label = Torri
+pdfjs-views-manager-pages-status-delete-button-label = Dileu
+pdfjs-views-manager-pages-status-export-selected-button-label = Wedi dewis allforio…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [zero] { $count } tudalennau wedi'u torri
+ [one] { $count } dudalen wedi'i thorri
+ [two] { $count } dudalen wedi'u torri
+ [few] { $count } tudalen wedi'u torri
+ [many] { $count } tudalen wedi'u torri
+ *[other] { $count } tudalen wedi'u torri
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [zero] { $count } tudalennau wedi'u copïo
+ [one] { $count } tudalen wedi'i chopïo
+ [two] { $count } tudalen wedi'u copïo
+ [few] { $count } tudalen wedi'u copïo
+ [many] { $count } tudalen wedi'u copïo
+ *[other] { $count } tudalen wedi'u copïo
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [zero] { $count } tudalennau wedi'u dileu
+ [one] { $count } tudalen wedi'i dileu
+ [two] { $count } dudalen wedi'u dileu
+ [few] { $count } tudalen wedi'u dileu
+ [many] { $count } tudalen wedi'u dileu
+ *[other] { $count } tudalen wedi'u dileu
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Yn paratoi eich ffeil…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Yn llwytho ffeil i fyny…
+pdfjs-views-manager-status-warning-cut-label = Methu torri. Adnewyddwch y dudalen a cheisio eto.
+pdfjs-views-manager-status-warning-copy-label = Methu copïo. Adnewyddwch y dudalen a cheisio eto.
+pdfjs-views-manager-status-warning-delete-label = Methu dileu. Adnewyddwch y dudalen a cheisio eto.
+pdfjs-views-manager-status-warning-save-label = Methu cadw. Adnewyddwch y dudalen a cheisio eto.
+pdfjs-views-manager-status-undo-button-label = Dadwneud
+pdfjs-views-manager-status-done-button-label = Gorffen
+pdfjs-views-manager-status-close-button =
+ .title = Cau
+pdfjs-views-manager-status-close-button-label = Cau
+pdfjs-views-manager-paste-button-label = Gludo
+pdfjs-views-manager-paste-button-before =
+ .title = Gludo cyn y dudalen gyntaf
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Gludo ar ôl tudalen { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NEWYDD
+pdfjs-views-manager-waiting-for-file = Yn llwytho ffeil i fyny…
+pdfjs-toggle-views-manager-button1 =
+ .title = Rheoli tudalennau
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Priodweddau llofnod digidol
+ .aria-label = Priodweddau llofnod digidol
+pdfjs-digital-signature-properties-button-label = Priodweddau llofnod digidol
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Llofnodwyd y ddogfen gyda llofnod digidol dilys
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [zero] Llofnodwyd y ddogfen ond doedd dim modd dilysu { $count } llofnod digidol
+ [one] Llofnodwyd y ddogfen ond doedd dim modd dilysu { $count } llofnod digidol
+ [two] Llofnodwyd y ddogfen ond doedd dim modd dilysu { $count } llofnod digidol
+ [few] Llofnodwyd y ddogfen ond doedd dim modd dilysu { $count } llofnod digidol
+ [many] Llofnodwyd y ddogfen ond doedd dim modd dilysu { $count } llofnod digidol
+ *[other] Llofnodwyd y ddogfen ond doedd dim modd dilysu { $count } llofnod digidol
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [zero] Dogfen wedi'i llofnodi â { $count } thystysgrif does dim modd ymddiried ynddyn nhw
+ [one] Dogfen wedi'i llofnodi â { $count } thystysgrif does dim modd ymddiried ynddi
+ [two] Dogfen wedi'i llofnodi â { $count } thystysgrifau does dim modd ymddiried ynddyn nhw
+ [few] Dogfen wedi'i llofnodi â { $count } thystysgrifau does dim modd ymddiried ynddyn nhw
+ [many] Dogfen wedi'i llofnodi â { $count } thystysgrifau does dim modd ymddiried ynddyn nhw
+ *[other] Dogfen wedi'i llofnodi â { $count } thystysgrifau does dim modd ymddiried ynddyn nhw
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [zero] Dogfen wedi'i llofnodi gyda { $count } tystysgrifau sydd wedi dod i ben
+ [one] Dogfen wedi'i llofnodi gydag { $count } dystysgrif sydd wedi dod i ben
+ [two] Dogfen wedi'i llofnodi gyda { $count } dystysgrif sydd wedi dod i ben
+ [few] Dogfen wedi'i llofnodi gyda { $count } tystysgrif sydd wedi dod i ben
+ [many] Dogfen wedi'i llofnodi gyda { $count } thystysgrif sydd wedi dod i ben
+ *[other] Dogfen wedi'i llofnodi gyda { $count } tystysgrif sydd wedi dod i ben
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [zero] Mae gan y ddogfen { $count } llofnodion digidol annilys
+ [one] Mae gan y ddogfen { $count } llofnod digidol annilys
+ [two] Mae gan y ddogfen { $count } llofnod digidol annilys
+ [few] Mae gan y ddogfen { $count } llofnod digidol annilys
+ [many] Mae gan y ddogfen { $count } llofnod digidol annilys
+ *[other] Mae gan y ddogfen { $count } llofnod digidol annilys
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [zero] Dogfen wedi'i llofnodi gyda { $count } tystysgrifau wedi'u dirymu
+ [one] Dogfen wedi'i llofnodi gyda { $count } tystysgrif wedi'u dirymu
+ [two] Dogfen wedi'i llofnodi gyda { $count } tystysgrif wedi'u dirymu
+ [few] Dogfen wedi'i llofnodi gyda { $count } tystysgrif wedi'u dirymu
+ [many] Dogfen wedi'i llofnodi gyda { $count } thystysgrif wedi'u dirymu
+ *[other] Dogfen wedi'i llofnodi gyda { $count } tystysgrif wedi'u dirymu
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Statws: Llofnod wedi'i ddilysu
+pdfjs-digital-signature-properties-status-invalid = Statws: Llofnod annilys
+pdfjs-digital-signature-properties-status-unknown = Statws: Methu dilysu (heb ei gefnogi)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Tystysgrif: Wedi ymddiried ( { $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Tystysgrif: Ddim ar gael
+pdfjs-digital-signature-properties-certificate-untrusted = Tystysgrif: Dim ymddiriedaeth
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Tystysgrif: Cyhoeddwr anhysbys ( { $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Tystysgrif: Hunan-lofnod ( { $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Tystysgrif: Cyhoeddwr heb ymddiriedaeth ( { $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Tystysgrif: Wedi dod i ben
+pdfjs-digital-signature-properties-certificate-expired-with-date = Tystysgrif: Wedi dod i ben ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Tystysgrif: Wedi'i ddirymu
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Tynnu llofnod sydd wedi'i gadw
+pdfjs-editor-delete-signature-button-label1 = Tynnwch y llofnod sydd wedi'i gadw
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Golygu disgrifiad
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Golygu disgrifiad
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/da/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/da/viewer.ftl
new file mode 100644
index 0000000..ba5bd58
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/da/viewer.ftl
@@ -0,0 +1,739 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Forrige side
+pdfjs-previous-button-label = Forrige
+pdfjs-next-button =
+ .title = Næste side
+pdfjs-next-button-label = Næste
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Side
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = af { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } af { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom ud
+pdfjs-zoom-out-button-label = Zoom ud
+pdfjs-zoom-in-button =
+ .title = Zoom ind
+pdfjs-zoom-in-button-label = Zoom ind
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Skift til fuldskærmsvisning
+pdfjs-presentation-mode-button-label = Fuldskærmsvisning
+pdfjs-open-file-button =
+ .title = Åbn fil
+pdfjs-open-file-button-label = Åbn
+pdfjs-print-button =
+ .title = Udskriv
+pdfjs-print-button-label = Udskriv
+pdfjs-save-button =
+ .title = Gem
+pdfjs-save-button-label = Gem
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Hent
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Hent
+pdfjs-bookmark-button =
+ .title = Aktuel side (vis URL fra den aktuelle side)
+pdfjs-bookmark-button-label = Aktuel side
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Funktioner
+pdfjs-tools-button-label = Funktioner
+pdfjs-first-page-button =
+ .title = Gå til første side
+pdfjs-first-page-button-label = Gå til første side
+pdfjs-last-page-button =
+ .title = Gå til sidste side
+pdfjs-last-page-button-label = Gå til sidste side
+pdfjs-page-rotate-cw-button =
+ .title = Roter med uret
+pdfjs-page-rotate-cw-button-label = Roter med uret
+pdfjs-page-rotate-ccw-button =
+ .title = Roter mod uret
+pdfjs-page-rotate-ccw-button-label = Roter mod uret
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktiver markeringsværktøj
+pdfjs-cursor-text-select-tool-button-label = Markeringsværktøj
+pdfjs-cursor-hand-tool-button =
+ .title = Aktiver håndværktøj
+pdfjs-cursor-hand-tool-button-label = Håndværktøj
+pdfjs-scroll-page-button =
+ .title = Brug sidescrolling
+pdfjs-scroll-page-button-label = Sidescrolling
+pdfjs-scroll-vertical-button =
+ .title = Brug vertikal scrolling
+pdfjs-scroll-vertical-button-label = Vertikal scrolling
+pdfjs-scroll-horizontal-button =
+ .title = Brug horisontal scrolling
+pdfjs-scroll-horizontal-button-label = Horisontal scrolling
+pdfjs-scroll-wrapped-button =
+ .title = Brug ombrudt scrolling
+pdfjs-scroll-wrapped-button-label = Ombrudt scrolling
+pdfjs-spread-none-button =
+ .title = Vis enkeltsider
+pdfjs-spread-none-button-label = Enkeltsider
+pdfjs-spread-odd-button =
+ .title = Vis opslag med ulige sidenumre til venstre
+pdfjs-spread-odd-button-label = Opslag med forside
+pdfjs-spread-even-button =
+ .title = Vis opslag med lige sidenumre til venstre
+pdfjs-spread-even-button-label = Opslag uden forside
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentegenskaber…
+pdfjs-document-properties-button-label = Dokumentegenskaber…
+pdfjs-document-properties-file-name = Filnavn:
+pdfjs-document-properties-file-size = Filstørrelse:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Forfatter:
+pdfjs-document-properties-subject = Emne:
+pdfjs-document-properties-keywords = Nøgleord:
+pdfjs-document-properties-creation-date = Oprettet:
+pdfjs-document-properties-modification-date = Redigeret:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Program:
+pdfjs-document-properties-producer = PDF-producent:
+pdfjs-document-properties-version = PDF-version:
+pdfjs-document-properties-page-count = Antal sider:
+pdfjs-document-properties-page-size = Sidestørrelse:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = stående
+pdfjs-document-properties-page-size-orientation-landscape = liggende
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Hurtig web-visning:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nej
+pdfjs-document-properties-close-button = Luk
+
+## Print
+
+pdfjs-print-progress-message = Forbereder dokument til udskrivning…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Annuller
+pdfjs-printing-not-supported = Advarsel: Udskrivning er ikke fuldt understøttet af browseren.
+pdfjs-printing-not-ready = Advarsel: PDF-filen er ikke fuldt indlæst til udskrivning.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Slå sidepanel til eller fra
+pdfjs-toggle-sidebar-notification-button =
+ .title = Slå sidepanel til eller fra (dokumentet indeholder disposition/vedhæftede filer/lag)
+pdfjs-toggle-sidebar-button-label = Slå sidepanel til eller fra
+pdfjs-document-outline-button =
+ .title = Vis dokumentets disposition (dobbeltklik for at udvide/sammenfolde alle elementer)
+pdfjs-document-outline-button-label = Dokument-disposition
+pdfjs-attachments-button =
+ .title = Vis vedhæftede filer
+pdfjs-attachments-button-label = Vedhæftede filer
+pdfjs-layers-button =
+ .title = Vis lag (dobbeltklik for at nulstille alle lag til standard-tilstanden)
+pdfjs-layers-button-label = Lag
+pdfjs-thumbs-button =
+ .title = Vis miniaturer
+pdfjs-thumbs-button-label = Miniaturer
+pdfjs-current-outline-item-button =
+ .title = Find det aktuelle dispositions-element
+pdfjs-current-outline-item-button-label = Aktuelt dispositions-element
+pdfjs-findbar-button =
+ .title = Find i dokument
+pdfjs-findbar-button-label = Find
+pdfjs-additional-layers = Yderligere lag
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniature af side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Vælg side { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Side { $page } af { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Find
+ .placeholder = Find i dokument…
+pdfjs-find-previous-button =
+ .title = Find den forrige forekomst
+pdfjs-find-previous-button-label = Forrige
+pdfjs-find-next-button =
+ .title = Find den næste forekomst
+pdfjs-find-next-button-label = Næste
+pdfjs-find-highlight-checkbox = Fremhæv alle
+pdfjs-find-match-case-checkbox-label = Forskel på store og små bogstaver
+pdfjs-find-match-diacritics-checkbox-label = Diakritiske tegn
+pdfjs-find-entire-word-checkbox-label = Hele ord
+pdfjs-find-reached-top = Toppen af siden blev nået, fortsatte fra bunden
+pdfjs-find-reached-bottom = Bunden af siden blev nået, fortsatte fra toppen
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } af { $total } forekomst
+ *[other] { $current } af { $total } forekomster
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mere end { $limit } forekomst
+ *[other] Mere end { $limit } forekomster
+ }
+pdfjs-find-not-found = Der blev ikke fundet noget
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sidebredde
+pdfjs-page-scale-fit = Tilpas til side
+pdfjs-page-scale-auto = Automatisk zoom
+pdfjs-page-scale-actual = Faktisk størrelse
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Side { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Der opstod en fejl ved indlæsning af PDF-filen.
+pdfjs-invalid-file-error = PDF-filen er ugyldig eller ødelagt.
+pdfjs-missing-file-error = Manglende PDF-fil.
+pdfjs-unexpected-response-error = Uventet svar fra serveren.
+pdfjs-rendering-error = Der opstod en fejl ved generering af siden.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }kommentar]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Angiv adgangskode til at åbne denne PDF-fil.
+pdfjs-password-invalid = Ugyldig adgangskode. Prøv igen.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Fortryd
+pdfjs-web-fonts-disabled = Webskrifttyper er deaktiverede. De indlejrede skrifttyper i PDF-filen kan ikke anvendes.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Skift tekstfarve
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Tegn
+pdfjs-editor-color-picker-ink-input =
+ .title = Skift tegne-farve
+pdfjs-editor-ink-button-label = Tegn
+pdfjs-editor-stamp-button =
+ .title = Tilføj eller rediger billeder
+pdfjs-editor-stamp-button-label = Tilføj eller rediger billeder
+pdfjs-editor-highlight-button =
+ .title = Fremhæv
+pdfjs-editor-highlight-button-label = Fremhæv
+pdfjs-highlight-floating-button1 =
+ .title = Fremhæv
+ .aria-label = Fremhæv
+pdfjs-highlight-floating-button-label = Fremhæv
+pdfjs-comment-floating-button =
+ .title = Kommenter
+ .aria-label = Kommenter
+pdfjs-comment-floating-button-label = Kommenter
+pdfjs-editor-comment-button =
+ .title = Kommentar
+ .aria-label = Kommentar
+pdfjs-editor-comment-button-label = Kommentar
+pdfjs-editor-signature-button =
+ .title = Tilføj signatur
+pdfjs-editor-signature-button-label = Tilføj signatur
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Redigering af fremhævning
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Redigering af tegninger
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Redigering af signatur: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Redigering af billeder
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Fjern tegning
+pdfjs-editor-remove-freetext-button =
+ .title = Fjern tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Fjern billede
+pdfjs-editor-remove-highlight-button =
+ .title = Fjern fremhævning
+pdfjs-editor-remove-signature-button =
+ .title = Fjern signatur
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Farve
+pdfjs-editor-free-text-size-input = Størrelse
+pdfjs-editor-ink-color-input = Farve
+pdfjs-editor-ink-thickness-input = Tykkelse
+pdfjs-editor-ink-opacity-input = Uigennemsigtighed
+pdfjs-editor-stamp-add-image-button =
+ .title = Tilføj billede
+pdfjs-editor-stamp-add-image-button-label = Tilføj billede
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tykkelse
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Ændr tykkelse, når andre elementer end tekst fremhæves
+pdfjs-editor-add-signature-container =
+ .aria-label = Indstillinger for signaturer og gemte signaturer
+pdfjs-editor-signature-add-signature-button =
+ .title = Tilføj ny signatur
+pdfjs-editor-signature-add-signature-button-label = Tilføj ny signatur
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Gemt signatur: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Teksteditor
+ .default-content = Begynd at skrive…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Kommentar
+ *[other] Kommentarer
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Luk sidepanelet
+ .aria-label = Luk sidepanelet
+pdfjs-editor-comments-sidebar-close-button-label = Luk sidepanelet
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Har du fundet noget interessant? Fremhæv det og gem en kommentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Læs mere
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativ tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Rediger alternativ tekst
+pdfjs-editor-alt-text-dialog-label = Vælg en indstilling
+pdfjs-editor-alt-text-dialog-description = Alternativ tekst hjælper folk, som ikke kan se billedet eller når det ikke indlæses.
+pdfjs-editor-alt-text-add-description-label = Tilføj en beskrivelse
+pdfjs-editor-alt-text-add-description-description = Sigt efter en eller to sætninger, der beskriver emnet, omgivelserne eller handlinger.
+pdfjs-editor-alt-text-mark-decorative-label = Marker som dekorativ
+pdfjs-editor-alt-text-mark-decorative-description = Dette bruges for dekorative billeder som rammer eller vandmærker.
+pdfjs-editor-alt-text-cancel-button = Annuller
+pdfjs-editor-alt-text-save-button = Gem
+pdfjs-editor-alt-text-decorative-tooltip = Markeret som dekorativ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = For eksempel: "En ung mand sætter sig ved et bord for at spise et måltid mad"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativ tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Øverste venstre hjørne — tilpas størrelse
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Øverste i midten — tilpas størrelse
+pdfjs-editor-resizer-top-right =
+ .aria-label = Øverste højre hjørne — tilpas størrelse
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Midten til højre — tilpas størrelse
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Nederste højre hjørne - tilpas størrelse
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Nederst i midten - tilpas størrelse
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Nederste venstre hjørne - tilpas størrelse
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Midten til venstre — tilpas størrelse
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Fremhævningsfarve
+pdfjs-editor-colorpicker-button =
+ .title = Skift farve
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Farvevalg
+pdfjs-editor-colorpicker-yellow =
+ .title = Gul
+pdfjs-editor-colorpicker-green =
+ .title = Grøn
+pdfjs-editor-colorpicker-blue =
+ .title = Blå
+pdfjs-editor-colorpicker-pink =
+ .title = Lyserød
+pdfjs-editor-colorpicker-red =
+ .title = Rød
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Vis alle
+pdfjs-editor-highlight-show-all-button =
+ .title = Vis alle
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Rediger alternativ tekst (billedbeskrivelse)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Tilføj alternativ tekst (billedbeskrivelse)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skriv din beskrivelse her...
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kort beskrivelse til personer, der ikke kan se billedet, eller når billedet ikke indlæses.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Denne alternative tekst blev oprettet automatisk og kan være upræcis.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Læs mere
+pdfjs-editor-new-alt-text-create-automatically-button-label = Opret alternativ tekst automatisk
+pdfjs-editor-new-alt-text-not-now-button = Ikke nu
+pdfjs-editor-new-alt-text-error-title = Kunne ikke oprette alternativ tekst automatisk
+pdfjs-editor-new-alt-text-error-description = Skriv din egen alternative tekst, eller prøv igen senere.
+pdfjs-editor-new-alt-text-error-close-button = Luk
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Henter alternativ tekst AI-model ({ $downloadedSize } af { $totalSize } MB)
+ .aria-valuetext = Henter alternativ tekst AI-model ({ $downloadedSize } af { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativ tekst tilføjet
+pdfjs-editor-new-alt-text-added-button-label = Alternativ tekst tilføjet
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Mangler alternativ tekst
+pdfjs-editor-new-alt-text-missing-button-label = Mangler alternativ tekst
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Gennemgå alternativ tekst
+pdfjs-editor-new-alt-text-to-review-button-label = Gennemgå alternativ tekst
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Oprettet automatisk: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Indstillinger for alternativ tekst til billeder
+pdfjs-image-alt-text-settings-button-label = Indstillinger for alternativ tekst til billeder
+pdfjs-editor-alt-text-settings-dialog-label = Indstillinger for alternativ tekst til billeder
+pdfjs-editor-alt-text-settings-automatic-title = Automatisk alternativ tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Opret alternativ tekst automatisk
+pdfjs-editor-alt-text-settings-create-model-description = Foreslår beskrivelser for at hjælpe folk, der ikke kan se billedet, eller når billedet ikke indlæses.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = AI-model til at oprette alternative tekster ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Kører lokalt på din enhed, så dine data forbliver private. Påkrævet for at anvende automatisk alternativ tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Slet
+pdfjs-editor-alt-text-settings-download-model-button = Hent
+pdfjs-editor-alt-text-settings-downloading-model-button = Henter…
+pdfjs-editor-alt-text-settings-editor-title = Redigering af alternativ tekst
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Vis redigering af alternativ tekst med det samme, når et billede tilføjes
+pdfjs-editor-alt-text-settings-show-dialog-description = Hjælper dig med at sikre, at alle dine billeder har alternativ tekst.
+pdfjs-editor-alt-text-settings-close-button = Luk
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Fremhævning tilføjet
+pdfjs-editor-freetext-added-alert = Tekst tilføjet
+pdfjs-editor-ink-added-alert = Tegning tilføjet
+pdfjs-editor-stamp-added-alert = Billede tilføjet
+pdfjs-editor-signature-added-alert = Signatur tilføjet
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Fremhævning fjernet
+pdfjs-editor-undo-bar-message-freetext = Tekst fjernet
+pdfjs-editor-undo-bar-message-ink = Tegning fjernet
+pdfjs-editor-undo-bar-message-stamp = Billede fjernet
+pdfjs-editor-undo-bar-message-signature = Signatur fjernet
+pdfjs-editor-undo-bar-message-comment = Kommentar fjernet
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } kommentar fjernet
+ *[other] { $count } kommentarer fjernet
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Fortryd
+pdfjs-editor-undo-bar-undo-button-label = Fortryd
+pdfjs-editor-undo-bar-close-button =
+ .title = Luk
+pdfjs-editor-undo-bar-close-button-label = Luk
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Modal-vinduet gør det muligt for brugeren at oprette en signatur, som kan føjes til PDF-dokumenter. Brugeren kan redigere navnet (der også fungerer som alternativ tekst) og eventuelt gemme signaturen, så den kan bruges igen.
+pdfjs-editor-add-signature-dialog-title = Tilføj en signatur
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Indtast
+ .title = Indtast
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Tegn
+ .title = Tegn
+pdfjs-editor-add-signature-image-button = Billede
+ .title = Billede
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Indtast din signatur
+ .placeholder = Indtast din signatur
+pdfjs-editor-add-signature-draw-placeholder = Tegn din signatur
+pdfjs-editor-add-signature-draw-thickness-range-label = Tykkelse
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Linjetykkelse: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Træk en fil herhen for at uploade den
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Eller vælg billedfiler
+ *[other] Eller vælg billedfiler
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Beskrivelse (alternativ tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Beskrivelse (alternativ tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Underskrift
+pdfjs-editor-add-signature-clear-button-label = Ryd signatur
+pdfjs-editor-add-signature-clear-button =
+ .title = Ryd signatur
+pdfjs-editor-add-signature-save-checkbox = Gem signatur
+pdfjs-editor-add-signature-save-warning-message = Du har nået grænsen på 5 gemte signaturer. Fjern en for at tilføje en ny.
+pdfjs-editor-add-signature-image-upload-error-title = Kunne ikke uploade billede
+pdfjs-editor-add-signature-image-upload-error-description = Kontroller din netværksforbindelse eller prøv med et andet billede.
+pdfjs-editor-add-signature-image-no-data-error-title = Kan ikke konvertere dette billede til en signatur
+pdfjs-editor-add-signature-image-no-data-error-description = Prøv at uploade et andet billede.
+pdfjs-editor-add-signature-error-close-button = Luk
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Annuller
+pdfjs-editor-add-signature-add-button = Tilføj
+pdfjs-editor-edit-signature-update-button = Opdater
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Rediger kommentar
+pdfjs-editor-edit-comment-popup-button =
+ .title = Rediger kommentar
+pdfjs-editor-delete-comment-popup-button-label = Fjern kommentar
+pdfjs-editor-delete-comment-popup-button =
+ .title = Fjern kommentar
+pdfjs-show-comment-button =
+ .title = Vis kommentar
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Rediger kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Opdater
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Tilføj kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Tilføj
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Begynd at skrive…
+pdfjs-editor-edit-comment-dialog-cancel-button = Annuller
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Tilføj kommentar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Slå sidepanel til eller fra (dokumentet indeholder miniaturer/disposition/vedhæftede filer/lag)
+pdfjs-toggle-views-manager-button1-label = Håndter sider
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidepanel
+pdfjs-views-manager-view-selector-button =
+ .title = Visninger
+pdfjs-views-manager-view-selector-button-label = Visninger
+pdfjs-views-manager-pages-title = Sider
+pdfjs-views-manager-attachments-title = Vedhæftede filer
+pdfjs-views-manager-layers-title1 = Lag
+ .title = Lag (dobbeltklik for at nulstille alle lag til standard-tilstanden)
+pdfjs-views-manager-pages-option-label = Sider
+pdfjs-views-manager-outlines-option-label = Dokument-disposition
+pdfjs-views-manager-attachments-option-label = Vedhæftede filer
+pdfjs-views-manager-layers-option-label = Lag
+pdfjs-views-manager-add-file-button =
+ .title = Tilføj fil
+pdfjs-views-manager-add-file-button-label = Tilføj fil
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } valgt
+ *[other] { $count } valgt
+ }
+pdfjs-views-manager-pages-status-none-action-label = Vælg sider
+pdfjs-views-manager-pages-status-action-button-label = Håndter
+pdfjs-views-manager-pages-status-copy-button-label = Kopier
+pdfjs-views-manager-pages-status-cut-button-label = Klip
+pdfjs-views-manager-pages-status-delete-button-label = Slet
+pdfjs-views-manager-pages-status-export-selected-button-label = Eksporter valgte…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 side klippet
+ *[other] { $count } sider klippet
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 side kopieret
+ *[other] { $count } sider kopieret
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 side slettet
+ *[other] { $count } sider slettet
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Gør din fil klar…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Uploader fil…
+pdfjs-views-manager-status-undo-button-label = Fortryd
+pdfjs-views-manager-status-done-button-label = Færdig
+pdfjs-views-manager-status-close-button =
+ .title = Luk
+pdfjs-views-manager-status-close-button-label = Luk
+pdfjs-views-manager-paste-button-label = Indsæt
+pdfjs-views-manager-paste-button-before =
+ .title = Indsæt før første side
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Indsæt efter side { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NY
+pdfjs-views-manager-waiting-for-file = Uploader fil…
+pdfjs-toggle-views-manager-button1 =
+ .title = Håndter sider
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Fjern gemt signatur
+pdfjs-editor-delete-signature-button-label1 = Fjern gemt signatur
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Rediger beskrivelse
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Rediger beskrivelse
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/de/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/de/viewer.ftl
new file mode 100644
index 0000000..76f3112
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/de/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Eine Seite zurück
+pdfjs-previous-button-label = Zurück
+pdfjs-next-button =
+ .title = Eine Seite vor
+pdfjs-next-button-label = Vor
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Seite
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = von { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } von { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Verkleinern
+pdfjs-zoom-out-button-label = Verkleinern
+pdfjs-zoom-in-button =
+ .title = Vergrößern
+pdfjs-zoom-in-button-label = Vergrößern
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = In Präsentationsmodus wechseln
+pdfjs-presentation-mode-button-label = Präsentationsmodus
+pdfjs-open-file-button =
+ .title = Datei öffnen
+pdfjs-open-file-button-label = Öffnen
+pdfjs-print-button =
+ .title = Drucken
+pdfjs-print-button-label = Drucken
+pdfjs-save-button =
+ .title = Speichern
+pdfjs-save-button-label = Speichern
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Herunterladen
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Herunterladen
+pdfjs-bookmark-button =
+ .title = Aktuelle Seite (URL von aktueller Seite anzeigen)
+pdfjs-bookmark-button-label = Aktuelle Seite
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Werkzeuge
+pdfjs-tools-button-label = Werkzeuge
+pdfjs-first-page-button =
+ .title = Erste Seite anzeigen
+pdfjs-first-page-button-label = Erste Seite anzeigen
+pdfjs-last-page-button =
+ .title = Letzte Seite anzeigen
+pdfjs-last-page-button-label = Letzte Seite anzeigen
+pdfjs-page-rotate-cw-button =
+ .title = Im Uhrzeigersinn drehen
+pdfjs-page-rotate-cw-button-label = Im Uhrzeigersinn drehen
+pdfjs-page-rotate-ccw-button =
+ .title = Gegen den Uhrzeigersinn drehen
+pdfjs-page-rotate-ccw-button-label = Gegen den Uhrzeigersinn drehen
+pdfjs-cursor-text-select-tool-button =
+ .title = Textauswahl-Werkzeug aktivieren
+pdfjs-cursor-text-select-tool-button-label = Textauswahl-Werkzeug
+pdfjs-cursor-hand-tool-button =
+ .title = Hand-Werkzeug aktivieren
+pdfjs-cursor-hand-tool-button-label = Hand-Werkzeug
+pdfjs-scroll-page-button =
+ .title = Seiten einzeln anordnen
+pdfjs-scroll-page-button-label = Einzelseitenanordnung
+pdfjs-scroll-vertical-button =
+ .title = Seiten übereinander anordnen
+pdfjs-scroll-vertical-button-label = Vertikale Seitenanordnung
+pdfjs-scroll-horizontal-button =
+ .title = Seiten nebeneinander anordnen
+pdfjs-scroll-horizontal-button-label = Horizontale Seitenanordnung
+pdfjs-scroll-wrapped-button =
+ .title = Seiten neben- und übereinander anordnen, abhängig vom Platz
+pdfjs-scroll-wrapped-button-label = Kombinierte Seitenanordnung
+pdfjs-spread-none-button =
+ .title = Seiten nicht nebeneinander anzeigen
+pdfjs-spread-none-button-label = Einzelne Seiten
+pdfjs-spread-odd-button =
+ .title = Jeweils eine ungerade und eine gerade Seite nebeneinander anzeigen
+pdfjs-spread-odd-button-label = Ungerade + gerade Seite
+pdfjs-spread-even-button =
+ .title = Jeweils eine gerade und eine ungerade Seite nebeneinander anzeigen
+pdfjs-spread-even-button-label = Gerade + ungerade Seite
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumenteigenschaften
+pdfjs-document-properties-button-label = Dokumenteigenschaften…
+pdfjs-document-properties-file-name = Dateiname:
+pdfjs-document-properties-file-size = Dateigröße:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } Bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } Bytes)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Thema:
+pdfjs-document-properties-keywords = Stichwörter:
+pdfjs-document-properties-creation-date = Erstelldatum:
+pdfjs-document-properties-modification-date = Bearbeitungsdatum:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Anwendung:
+pdfjs-document-properties-producer = PDF erstellt mit:
+pdfjs-document-properties-version = PDF-Version:
+pdfjs-document-properties-page-count = Seitenzahl:
+pdfjs-document-properties-page-size = Seitengröße:
+pdfjs-document-properties-page-size-unit-inches = Zoll
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = Hochformat
+pdfjs-document-properties-page-size-orientation-landscape = Querformat
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Schnelle Webanzeige:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nein
+pdfjs-document-properties-close-button = Schließen
+pdfjs-digital-signature-properties-view-certificate = Zertifikat ansehen
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Grund: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Zeitstempel: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] ({ $count }) Untersignatur
+ *[other] ({ $count }) Untersignaturen
+ }
+
+## Print
+
+pdfjs-print-progress-message = Dokument wird für Drucken vorbereitet…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Abbrechen
+pdfjs-printing-not-supported = Warnung: Die Drucken-Funktion wird durch diesen Browser nicht vollständig unterstützt.
+pdfjs-printing-not-ready = Warnung: Die PDF-Datei ist nicht vollständig geladen, dies ist für das Drucken aber empfohlen.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Sidebar umschalten
+pdfjs-toggle-sidebar-notification-button =
+ .title = Sidebar umschalten (Dokument enthält Dokumentstruktur/Anhänge/Ebenen)
+pdfjs-toggle-sidebar-button-label = Sidebar umschalten
+pdfjs-document-outline-button =
+ .title = Dokumentstruktur anzeigen (Doppelklicken, um alle Einträge aus- bzw. einzuklappen)
+pdfjs-document-outline-button-label = Dokumentstruktur
+pdfjs-attachments-button =
+ .title = Anhänge anzeigen
+pdfjs-attachments-button-label = Anhänge
+pdfjs-layers-button =
+ .title = Ebenen anzeigen (Doppelklicken, um alle Ebenen auf den Standardzustand zurückzusetzen)
+pdfjs-layers-button-label = Ebenen
+pdfjs-thumbs-button =
+ .title = Miniaturansichten anzeigen
+pdfjs-thumbs-button-label = Miniaturansichten
+pdfjs-current-outline-item-button =
+ .title = Aktuelles Struktur-Element finden
+pdfjs-current-outline-item-button-label = Aktuelles Struktur-Element
+pdfjs-findbar-button =
+ .title = Dokument durchsuchen
+pdfjs-findbar-button-label = Suchen
+pdfjs-additional-layers = Zusätzliche Ebenen
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Seite { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniaturansicht von Seite { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seite { $page } auswählen
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Seite { $page } von { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Suchen
+ .placeholder = Dokument durchsuchen…
+pdfjs-find-previous-button =
+ .title = Vorheriges Vorkommen des Suchbegriffs finden
+pdfjs-find-previous-button-label = Zurück
+pdfjs-find-next-button =
+ .title = Nächstes Vorkommen des Suchbegriffs finden
+pdfjs-find-next-button-label = Weiter
+pdfjs-find-highlight-checkbox = Alle hervorheben
+pdfjs-find-match-case-checkbox-label = Groß-/Kleinschreibung beachten
+pdfjs-find-match-diacritics-checkbox-label = Akzente
+pdfjs-find-entire-word-checkbox-label = Ganze Wörter
+pdfjs-find-reached-top = Anfang des Dokuments erreicht, fahre am Ende fort
+pdfjs-find-reached-bottom = Ende des Dokuments erreicht, fahre am Anfang fort
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } von { $total } Übereinstimmung
+ *[other] { $current } von { $total } Übereinstimmungen
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mehr als { $limit } Übereinstimmung
+ *[other] Mehr als { $limit } Übereinstimmungen
+ }
+pdfjs-find-not-found = Suchbegriff nicht gefunden
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Seitenbreite
+pdfjs-page-scale-fit = Seitengröße
+pdfjs-page-scale-auto = Automatischer Zoom
+pdfjs-page-scale-actual = Originalgröße
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Seite { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Beim Laden der PDF-Datei trat ein Fehler auf.
+pdfjs-invalid-file-error = Ungültige oder beschädigte PDF-Datei
+pdfjs-missing-file-error = Fehlende PDF-Datei
+pdfjs-unexpected-response-error = Unerwartete Antwort des Servers
+pdfjs-rendering-error = Beim Darstellen der Seite trat ein Fehler auf.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Anmerkung]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Geben Sie zum Öffnen der PDF-Datei deren Passwort ein.
+pdfjs-password-invalid = Falsches Passwort. Bitte versuchen Sie es erneut.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Abbrechen
+pdfjs-web-fonts-disabled = Web-Schriftarten sind deaktiviert: Eingebettete PDF-Schriftarten konnten nicht geladen werden.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Textfarbe ändern
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Zeichnen
+pdfjs-editor-color-picker-ink-input =
+ .title = Zeichnungsfarbe ändern
+pdfjs-editor-ink-button-label = Zeichnen
+pdfjs-editor-stamp-button =
+ .title = Grafiken hinzufügen oder bearbeiten
+pdfjs-editor-stamp-button-label = Grafiken hinzufügen oder bearbeiten
+pdfjs-editor-highlight-button =
+ .title = Hervorheben
+pdfjs-editor-highlight-button-label = Hervorheben
+pdfjs-highlight-floating-button1 =
+ .title = Hervorheben
+ .aria-label = Hervorheben
+pdfjs-highlight-floating-button-label = Hervorheben
+pdfjs-comment-floating-button =
+ .title = Kommentieren
+ .aria-label = Kommentieren
+pdfjs-comment-floating-button-label = Kommentieren
+pdfjs-editor-comment-button =
+ .title = Kommentar
+ .aria-label = Kommentar
+pdfjs-editor-comment-button-label = Kommentar
+pdfjs-editor-signature-button =
+ .title = Unterschrift hinzufügen
+pdfjs-editor-signature-button-label = Unterschrift hinzufügen
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Hervorhebungs-Editor
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Zeichnungseditor
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Unterschrifts-Editor: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Grafik-Editor
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Zeichnung entfernen
+pdfjs-editor-remove-freetext-button =
+ .title = Text entfernen
+pdfjs-editor-remove-stamp-button =
+ .title = Grafik entfernen
+pdfjs-editor-remove-highlight-button =
+ .title = Hervorhebung entfernen
+pdfjs-editor-remove-signature-button =
+ .title = Unterschrift entfernen
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Farbe
+pdfjs-editor-free-text-size-input = Größe
+pdfjs-editor-ink-color-input = Farbe
+pdfjs-editor-ink-thickness-input = Linienstärke
+pdfjs-editor-ink-opacity-input = Deckkraft
+pdfjs-editor-stamp-add-image-button =
+ .title = Grafik hinzufügen
+pdfjs-editor-stamp-add-image-button-label = Grafik hinzufügen
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Linienstärke
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Linienstärke beim Hervorheben anderer Elemente als Text ändern
+pdfjs-editor-add-signature-container =
+ .aria-label = Signaturkontrollen und gespeicherte Signaturen
+pdfjs-editor-signature-add-signature-button =
+ .title = Neue Unterschrift hinzufügen
+pdfjs-editor-signature-add-signature-button-label = Neue Unterschrift hinzufügen
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Gespeicherte Signatur: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Texteditor
+ .default-content = Schreiben beginnen…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Kommentar
+ *[other] Kommentare
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Sidebar schließen
+ .aria-label = Sidebar schließen
+pdfjs-editor-comments-sidebar-close-button-label = Sidebar schließen
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Haben Sie etwas Bemerkenswertes entdeckt? Heben Sie es hervor und hinterlassen Sie einen Kommentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Weitere Informationen
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativ-Text
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternativ-Text bearbeiten
+pdfjs-editor-alt-text-dialog-label = Option wählen
+pdfjs-editor-alt-text-dialog-description = Alt-Text (Alternativtext) hilft, wenn Personen die Grafik nicht sehen können oder wenn sie nicht geladen wird.
+pdfjs-editor-alt-text-add-description-label = Beschreibung hinzufügen
+pdfjs-editor-alt-text-add-description-description = Ziel sind 1-2 Sätze, die das Thema, das Szenario oder Aktionen beschreiben.
+pdfjs-editor-alt-text-mark-decorative-label = Als dekorativ markieren
+pdfjs-editor-alt-text-mark-decorative-description = Dies wird für Ziergrafiken wie Ränder oder Wasserzeichen verwendet.
+pdfjs-editor-alt-text-cancel-button = Abbrechen
+pdfjs-editor-alt-text-save-button = Speichern
+pdfjs-editor-alt-text-decorative-tooltip = Als dekorativ markiert
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Zum Beispiel: "Ein junger Mann setzt sich an einen Tisch, um zu essen."
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativ-Text
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Linke obere Ecke - Größe ändern
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Oben mittig - Größe ändern
+pdfjs-editor-resizer-top-right =
+ .aria-label = Rechts oben - Größe ändern
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Mitte rechts - Größe ändern
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Rechte untere Ecke - Größe ändern
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Unten mittig - Größe ändern
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Linke untere Ecke - Größe ändern
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Mitte links - Größe ändern
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Hervorhebungsfarbe
+pdfjs-editor-colorpicker-button =
+ .title = Farbe ändern
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Farbauswahl
+pdfjs-editor-colorpicker-yellow =
+ .title = Gelb
+pdfjs-editor-colorpicker-green =
+ .title = Grün
+pdfjs-editor-colorpicker-blue =
+ .title = Blau
+pdfjs-editor-colorpicker-pink =
+ .title = Pink
+pdfjs-editor-colorpicker-red =
+ .title = Rot
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Alle anzeigen
+pdfjs-editor-highlight-show-all-button =
+ .title = Alle anzeigen
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alternativ-Text (Grafikbeschreibung) bearbeiten
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alternativ-Text (Grafikbeschreibung) hinzufügen
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Schreiben Sie Ihre Beschreibung hier…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kurze Beschreibung für Personen, die die Grafik nicht sehen können, oder wenn die Grafik nicht geladen wird.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Dieser Alternativ-Text wurde automatisch erstellt und könnte ungenau sein.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Weitere Informationen
+pdfjs-editor-new-alt-text-create-automatically-button-label = Alternativ-Text automatisch erstellen
+pdfjs-editor-new-alt-text-not-now-button = Nicht jetzt
+pdfjs-editor-new-alt-text-error-title = Alternativ-Text konnte nicht automatisch erstellt werden
+pdfjs-editor-new-alt-text-error-description = Bitte schreiben Sie Ihren eigenen Alternativ-Text oder versuchen Sie es später erneut.
+pdfjs-editor-new-alt-text-error-close-button = Schließen
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Alternativ-Text-KI-Modell wird heruntergeladen ({ $downloadedSize } von { $totalSize } MB)
+ .aria-valuetext = Alternativ-Text-KI-Modell wird heruntergeladen ({ $downloadedSize } von { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativ-Text hinzugefügt
+pdfjs-editor-new-alt-text-added-button-label = Alternativ-Text hinzugefügt
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Fehlender Alternativ-Text
+pdfjs-editor-new-alt-text-missing-button-label = Fehlender Alternativ-Text
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternativ-Text überprüfen
+pdfjs-editor-new-alt-text-to-review-button-label = Alternativ-Text überprüfen
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automatisch erstellt: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Alternativ-Text-Einstellungen für Grafiken
+pdfjs-image-alt-text-settings-button-label = Alternativ-Text-Einstellungen für Grafiken
+pdfjs-editor-alt-text-settings-dialog-label = Alternativ-Text-Einstellungen für Grafiken
+pdfjs-editor-alt-text-settings-automatic-title = Automatischer Alternativ-Text
+pdfjs-editor-alt-text-settings-create-model-button-label = Alternativ-Text automatisch erstellen
+pdfjs-editor-alt-text-settings-create-model-description = Schlägt Beschreibungen vor, um Personen zu helfen, die die Grafik nicht sehen können, oder wenn die Grafik nicht geladen wird.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alternativ-Text-KI-Modell ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Wird lokal auf Ihrem Gerät ausgeführt, sodass Ihre Daten privat bleiben. Erforderlich für automatischen Alternativ-Text.
+pdfjs-editor-alt-text-settings-delete-model-button = Löschen
+pdfjs-editor-alt-text-settings-download-model-button = Herunterladen
+pdfjs-editor-alt-text-settings-downloading-model-button = Wird heruntergeladen…
+pdfjs-editor-alt-text-settings-editor-title = Alternativ-Texteditor
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Alternativ-Texteditor beim Hinzufügen einer Grafik anzeigen
+pdfjs-editor-alt-text-settings-show-dialog-description = Hilft Ihnen, sicherzustellen, dass alle Ihre Grafiken Alternativ-Text haben.
+pdfjs-editor-alt-text-settings-close-button = Schließen
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Hervorhebung hinzugefügt
+pdfjs-editor-freetext-added-alert = Text hinzugefügt
+pdfjs-editor-ink-added-alert = Zeichnung hinzugefügt
+pdfjs-editor-stamp-added-alert = Bild hinzugefügt
+pdfjs-editor-signature-added-alert = Signatur hinzugefügt
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Hervorhebung entfernt
+pdfjs-editor-undo-bar-message-freetext = Text entfernt
+pdfjs-editor-undo-bar-message-ink = Zeichnung entfernt
+pdfjs-editor-undo-bar-message-stamp = Grafik entfernt
+pdfjs-editor-undo-bar-message-signature = Unterschrift entfernt
+pdfjs-editor-undo-bar-message-comment = Kommentar entfernt
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } Anmerkung entfernt
+ *[other] { $count } Anmerkungen entfernt
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Rückgängig
+pdfjs-editor-undo-bar-undo-button-label = Rückgängig
+pdfjs-editor-undo-bar-close-button =
+ .title = Schließen
+pdfjs-editor-undo-bar-close-button-label = Schließen
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Dieses Modal ermöglicht es dem Benutzer, eine Unterschrift zu erstellen, um sie zu einem PDF-Dokument hinzuzufügen. Der Benutzer kann den Namen bearbeiten (der auch als Alt-Text dient) und optional die Unterschrift zur wiederholten Verwendung speichern.
+pdfjs-editor-add-signature-dialog-title = Unterschrift hinzufügen
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Eintippen
+ .title = Eintippen
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Zeichnen
+ .title = Zeichnen
+pdfjs-editor-add-signature-image-button = Grafik
+ .title = Grafik
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Tippen Sie Ihre Unterschrift ein
+ .placeholder = Tippen Sie Ihre Unterschrift ein
+pdfjs-editor-add-signature-draw-placeholder = Ihre Unterschrift zeichnen
+pdfjs-editor-add-signature-draw-thickness-range-label = Linienstärke
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Zeichnungsstärke: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Datei zum Hochladen hierher ziehen
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Oder Grafikdateien wählen
+ *[other] Oder Bilddateien durchsuchen
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Beschreibung (alternativer Text)
+pdfjs-editor-add-signature-description-input =
+ .title = Beschreibung (alternativer Text)
+pdfjs-editor-add-signature-description-default-when-drawing = Unterschrift
+pdfjs-editor-add-signature-clear-button-label = Unterschrift löschen
+pdfjs-editor-add-signature-clear-button =
+ .title = Unterschrift löschen
+pdfjs-editor-add-signature-save-checkbox = Unterschrift speichern
+pdfjs-editor-add-signature-save-warning-message = Sie haben die Grenze von 5 gespeicherten Unterschriften erreicht. Entfernen Sie eine, um weitere zu speichern.
+pdfjs-editor-add-signature-image-upload-error-title = Grafik konnte nicht hochgeladen werden
+pdfjs-editor-add-signature-image-upload-error-description = Überprüfen Sie Ihre Netzwerkverbindung, oder versuchen Sie es mit einer anderen Grafik.
+pdfjs-editor-add-signature-image-no-data-error-title = Kann Grafik nicht in eine Unterschrift umwandeln
+pdfjs-editor-add-signature-image-no-data-error-description = Bitte versuchen Sie, eine andere Grafik hochzuladen.
+pdfjs-editor-add-signature-error-close-button = Schließen
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Abbrechen
+pdfjs-editor-add-signature-add-button = Hinzufügen
+pdfjs-editor-edit-signature-update-button = Aktualisieren
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Kommentar bearbeiten
+pdfjs-editor-edit-comment-popup-button =
+ .title = Kommentar bearbeiten
+pdfjs-editor-delete-comment-popup-button-label = Kommentar entfernen
+pdfjs-editor-delete-comment-popup-button =
+ .title = Kommentar entfernen
+pdfjs-show-comment-button =
+ .title = Kommentar anzeigen
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Kommentar bearbeiten
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualisieren
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Kommentar hinzufügen
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Hinzufügen
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Schreiben beginnen…
+pdfjs-editor-edit-comment-dialog-cancel-button = Abbrechen
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Kommentar hinzufügen
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Sidebar umschalten (Dokument enthält Miniaturansichten/Dokumentstruktur/Anhänge/Ebenen)
+pdfjs-toggle-views-manager-button1-label = Seiten verwalten
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidebar
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Größenanpassung der Sidebar
+pdfjs-views-manager-view-selector-button =
+ .title = Ansichten
+pdfjs-views-manager-view-selector-button-label = Ansichten
+pdfjs-views-manager-pages-title = Seiten
+pdfjs-views-manager-outlines-title1 = Dokumentstruktur
+ .title = Dokumentstruktur (Doppelklick zum Ein- bzw. Ausblenden aller Einträge)
+pdfjs-views-manager-attachments-title = Anhänge
+pdfjs-views-manager-layers-title1 = Ebenen
+ .title = Ebenen (Doppelklick, um alle Ebenen auf den Standard-Zustand zurückzusetzen)
+pdfjs-views-manager-pages-option-label = Seiten
+pdfjs-views-manager-outlines-option-label = Dokumentstruktur
+pdfjs-views-manager-attachments-option-label = Anhänge
+pdfjs-views-manager-layers-option-label = Ebenen
+pdfjs-views-manager-add-file-button =
+ .title = Datei hinzufügen
+pdfjs-views-manager-add-file-button-label = Datei hinzufügen
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } ausgewählt
+ *[other] { $count } ausgewählt
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seiten auswählen
+pdfjs-views-manager-pages-status-action-button-label = Verwalten
+pdfjs-views-manager-pages-status-copy-button-label = Kopieren
+pdfjs-views-manager-pages-status-cut-button-label = Ausschneiden
+pdfjs-views-manager-pages-status-delete-button-label = Löschen
+pdfjs-views-manager-pages-status-export-selected-button-label = Ausgewählte exportieren…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 Seite ausgeschnitten
+ *[other] { $count } Seiten ausgeschnitten
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 Seite kopiert
+ *[other] { $count } Seiten kopiert
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 Seite gelöscht
+ *[other] { $count } Seiten gelöscht
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Ihre Datei wird vorbereitet…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Datei wird hochgeladen…
+pdfjs-views-manager-status-warning-cut-label = Ausschneiden nicht möglich. Aktualisieren Sie die Seite und versuchen Sie es erneut.
+pdfjs-views-manager-status-warning-copy-label = Kopieren nicht möglich. Aktualisieren Sie die Seite und versuchen Sie es erneut.
+pdfjs-views-manager-status-warning-delete-label = Löschen nicht möglich. Aktualisieren Sie die Seite und versuchen Sie es erneut.
+pdfjs-views-manager-status-warning-save-label = Speichern nicht möglich. Aktualisieren Sie die Seite und versuchen Sie es erneut.
+pdfjs-views-manager-status-undo-button-label = Rückgängig
+pdfjs-views-manager-status-done-button-label = Fertig
+pdfjs-views-manager-status-close-button =
+ .title = Schließen
+pdfjs-views-manager-status-close-button-label = Schließen
+pdfjs-views-manager-paste-button-label = Einfügen
+pdfjs-views-manager-paste-button-before =
+ .title = Vor der ersten Seite einfügen
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Nach Seite { $page } einfügen
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NEU
+pdfjs-views-manager-waiting-for-file = Datei wird hochgeladen…
+pdfjs-toggle-views-manager-button1 =
+ .title = Seiten verwalten
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Eigenschaften digitaler Signatur
+ .aria-label = Eigenschaften digitaler Signatur
+pdfjs-digital-signature-properties-button-label = Eigenschaften digitaler Signatur
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument wurde mit einer gültigen digitalen Signatur signiert
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument signiert, aber { $count } digitale Signatur konnte nicht verifiziert werden
+ *[other] Dokument signiert, aber { $count } digitale Signaturen konnten nicht verifiziert werden
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument mit { $count } Zertifikat signiert, das nicht vertrauenswürdig ist
+ *[other] Dokument mit { $count } Zertifikaten signiert, die nicht vertrauenswürdig sind
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument mit { $count } abgelaufenen Zertifikat signiert
+ *[other] Dokument mit { $count } abgelaufenen Zertifikaten signiert
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument hat { $count } ungültige digitale Signatur
+ *[other] Dokument hat { $count } ungültige digitale Signaturen
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument mit { $count } gesperrten Zertifikat signiert
+ *[other] Dokument mit { $count } gesperrten Zertifikaten signiert
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signatur überprüft
+pdfjs-digital-signature-properties-status-invalid = Status: Signatur ungültig
+pdfjs-digital-signature-properties-status-unknown = Status: Verifizieren nicht möglich (nicht unterstützt)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Zertifikat: Vertrauenswürdig ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Zertifikat: Nicht verfügbar
+pdfjs-digital-signature-properties-certificate-untrusted = Zertifikat: Nicht vertrauenswürdig
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Zertifikat: Unbekannter Aussteller ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Zertifikat: Selbstsigniert ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Zertifikat: Nicht vertrauenswürdiger Aussteller ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Zertifikat: Abgelaufen
+pdfjs-digital-signature-properties-certificate-expired-with-date = Zertifikat: Abgelaufen ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Zertifikat: Widerrufen
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Gespeicherte Unterschrift entfernen
+pdfjs-editor-delete-signature-button-label1 = Gespeicherte Unterschrift entfernen
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Beschreibung bearbeiten
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Beschreibung bearbeiten
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/dsb/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/dsb/viewer.ftl
new file mode 100644
index 0000000..ec7a74f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/dsb/viewer.ftl
@@ -0,0 +1,864 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pjerwjejšny bok
+pdfjs-previous-button-label = Slědk
+pdfjs-next-button =
+ .title = Pśiducy bok
+pdfjs-next-button-label = Dalej
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Bok
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = z { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } z { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Pómjeńšyś
+pdfjs-zoom-out-button-label = Pómjeńšyś
+pdfjs-zoom-in-button =
+ .title = Pówětšyś
+pdfjs-zoom-in-button-label = Pówětšyś
+pdfjs-zoom-select =
+ .title = Skalěrowanje
+pdfjs-presentation-mode-button =
+ .title = Do prezentaciskego modusa pśejś
+pdfjs-presentation-mode-button-label = Prezentaciski modus
+pdfjs-open-file-button =
+ .title = Dataju wócyniś
+pdfjs-open-file-button-label = Wócyniś
+pdfjs-print-button =
+ .title = Śišćaś
+pdfjs-print-button-label = Śišćaś
+pdfjs-save-button =
+ .title = Składowaś
+pdfjs-save-button-label = Składowaś
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Ześěgnuś
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Ześěgnuś
+pdfjs-bookmark-button =
+ .title = Aktualny bok (URL z aktualnego boka pokazaś)
+pdfjs-bookmark-button-label = Aktualny bok
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Rědy
+pdfjs-tools-button-label = Rědy
+pdfjs-first-page-button =
+ .title = K prědnemu bokoju
+pdfjs-first-page-button-label = K prědnemu bokoju
+pdfjs-last-page-button =
+ .title = K slědnemu bokoju
+pdfjs-last-page-button-label = K slědnemu bokoju
+pdfjs-page-rotate-cw-button =
+ .title = Wobwjertnuś ako špěra źo
+pdfjs-page-rotate-cw-button-label = Wobwjertnuś ako špěra źo
+pdfjs-page-rotate-ccw-button =
+ .title = Wobwjertnuś nawopaki ako špěra źo
+pdfjs-page-rotate-ccw-button-label = Wobwjertnuś nawopaki ako špěra źo
+pdfjs-cursor-text-select-tool-button =
+ .title = Rěd za wuběranje teksta zmóžniś
+pdfjs-cursor-text-select-tool-button-label = Rěd za wuběranje teksta
+pdfjs-cursor-hand-tool-button =
+ .title = Rucny rěd zmóžniś
+pdfjs-cursor-hand-tool-button-label = Rucny rěd
+pdfjs-scroll-page-button =
+ .title = Kulanje boka wužywaś
+pdfjs-scroll-page-button-label = Kulanje boka
+pdfjs-scroll-vertical-button =
+ .title = Wertikalne suwanje wužywaś
+pdfjs-scroll-vertical-button-label = Wertikalne suwanje
+pdfjs-scroll-horizontal-button =
+ .title = Horicontalne suwanje wužywaś
+pdfjs-scroll-horizontal-button-label = Horicontalne suwanje
+pdfjs-scroll-wrapped-button =
+ .title = Pózlažke suwanje wužywaś
+pdfjs-scroll-wrapped-button-label = Pózlažke suwanje
+pdfjs-spread-none-button =
+ .title = Boki njezwězaś
+pdfjs-spread-none-button-label = Žeden dwójny bok
+pdfjs-spread-odd-button =
+ .title = Boki zachopinajucy z njerownymi bokami zwězaś
+pdfjs-spread-odd-button-label = Njerowne boki
+pdfjs-spread-even-button =
+ .title = Boki zachopinajucy z rownymi bokami zwězaś
+pdfjs-spread-even-button-label = Rowne boki
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentowe kakosći…
+pdfjs-document-properties-button-label = Dokumentowe kakosći…
+pdfjs-document-properties-file-name = Mě dataje:
+pdfjs-document-properties-file-size = Wjelikosć dataje:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bajtow)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtow)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Awtor:
+pdfjs-document-properties-subject = Tema:
+pdfjs-document-properties-keywords = Klucowe słowa:
+pdfjs-document-properties-creation-date = Datum napóranja:
+pdfjs-document-properties-modification-date = Datum změny:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Awtor:
+pdfjs-document-properties-producer = PDF-gótowaŕ:
+pdfjs-document-properties-version = PDF-wersija:
+pdfjs-document-properties-page-count = Licba bokow:
+pdfjs-document-properties-page-size = Wjelikosć boka:
+pdfjs-document-properties-page-size-unit-inches = col
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = wusoki format
+pdfjs-document-properties-page-size-orientation-landscape = prěcny format
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Jo
+pdfjs-document-properties-linearized-no = Ně
+pdfjs-document-properties-close-button = Zacyniś
+pdfjs-digital-signature-properties-view-certificate = Certifikat pokazaś
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Pśicyna: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Casowy kołk: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] { $count } pódsignatura
+ [two] { $count } pódsignaturje
+ [few] { $count } pódsignatury
+ *[other] { $count } pódsignaturow
+ }
+
+## Print
+
+pdfjs-print-progress-message = Dokument pśigótujo se za śišćanje…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Pśetergnuś
+pdfjs-printing-not-supported = Warnowanje: Śišćanje njepódpěra se połnje pśez toś ten wobglědowak.
+pdfjs-printing-not-ready = Warnowanje: PDF njejo se za śišćanje dopołnje zacytał.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Bocnicu pokazaś/schowaś
+pdfjs-toggle-sidebar-notification-button =
+ .title = Bocnicu pśešaltowaś (dokument rozrědowanje/pśipiski/warstwy wopśimujo)
+pdfjs-toggle-sidebar-button-label = Bocnicu pokazaś/schowaś
+pdfjs-document-outline-button =
+ .title = Dokumentowe naraźenje pokazaś (dwójne kliknjenje, aby se wšykne zapiski pokazali/schowali)
+pdfjs-document-outline-button-label = Dokumentowa struktura
+pdfjs-attachments-button =
+ .title = Pśidanki pokazaś
+pdfjs-attachments-button-label = Pśidanki
+pdfjs-layers-button =
+ .title = Warstwy pokazaś (klikniśo dwójcy, aby wšykne warstwy na standardny staw slědk stajił)
+pdfjs-layers-button-label = Warstwy
+pdfjs-thumbs-button =
+ .title = Miniatury pokazaś
+pdfjs-thumbs-button-label = Miniatury
+pdfjs-current-outline-item-button =
+ .title = Aktualny rozrědowański zapisk pytaś
+pdfjs-current-outline-item-button-label = Aktualny rozrědowański zapisk
+pdfjs-findbar-button =
+ .title = W dokumenśe pytaś
+pdfjs-findbar-button-label = Pytaś
+pdfjs-additional-layers = Dalšne warstwy
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Bok { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura boka { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Bok { $page } wubraś
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Bok { $page } z { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Pytaś
+ .placeholder = W dokumenśe pytaś…
+pdfjs-find-previous-button =
+ .title = Pjerwjejšne wustupowanje pytańskego wuraza pytaś
+pdfjs-find-previous-button-label = Slědk
+pdfjs-find-next-button =
+ .title = Pśidujuce wustupowanje pytańskego wuraza pytaś
+pdfjs-find-next-button-label = Dalej
+pdfjs-find-highlight-checkbox = Wšykne wuzwignuś
+pdfjs-find-match-case-checkbox-label = Na wjelikopisanje źiwaś
+pdfjs-find-match-diacritics-checkbox-label = Diakritiske znamuška wužywaś
+pdfjs-find-entire-word-checkbox-label = Cełe słowa
+pdfjs-find-reached-top = Zachopjeńk dokumenta dostany, pókšacujo se z kóńcom
+pdfjs-find-reached-bottom = Kóńc dokumenta dostany, pókšacujo se ze zachopjeńkom
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } z { $total } wótpowědnika
+ [two] { $current } z { $total } wótpowědnikowu
+ [few] { $current } z { $total } wótpowědnikow
+ *[other] { $current } z { $total } wótpowědnikow
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Wušej { $limit } wótpowědnik
+ [two] Wušej { $limit } wótpowědnika
+ [few] Wušej { $limit } wótpowědniki
+ *[other] Wušej { $limit } wótpowědniki
+ }
+pdfjs-find-not-found = Pytański wuraz njejo se namakał
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Šyrokosć boka
+pdfjs-page-scale-fit = Wjelikosć boka
+pdfjs-page-scale-auto = Awtomatiske skalěrowanje
+pdfjs-page-scale-actual = Aktualna wjelikosć
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Bok { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Pśi zacytowanju PDF jo zmólka nastała.
+pdfjs-invalid-file-error = Njepłaśiwa abo wobškóźona PDF-dataja.
+pdfjs-missing-file-error = Felujuca PDF-dataja.
+pdfjs-unexpected-response-error = Njewócakane serwerowe wótegrono.
+pdfjs-rendering-error = Pśi zwobraznjanju boka jo zmólka nastała.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Typ pśipiskow: { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Zapódajśo gronidło, aby PDF-dataju wócynił.
+pdfjs-password-invalid = Njepłaśiwe gronidło. Pšosym wopytajśo hyšći raz.
+pdfjs-password-ok-button = W pórěźe
+pdfjs-password-cancel-button = Pśetergnuś
+pdfjs-web-fonts-disabled = Webpisma su znjemóžnjone: njejo móžno, zasajźone PDF-pisma wužywaś.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Tekstowu barwu změniś
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Kresliś
+pdfjs-editor-color-picker-ink-input =
+ .title = Kresleńsku barwu změniś
+pdfjs-editor-ink-button-label = Kresliś
+pdfjs-editor-stamp-button =
+ .title = Wobraze pśidaś abo wobźěłaś
+pdfjs-editor-stamp-button-label = Wobraze pśidaś abo wobźěłaś
+pdfjs-editor-highlight-button =
+ .title = Wuzwignuś
+pdfjs-editor-highlight-button-label = Wuzwignuś
+pdfjs-highlight-floating-button1 =
+ .title = Wuzwignuś
+ .aria-label = Wuzwignuś
+pdfjs-highlight-floating-button-label = Wuzwignuś
+pdfjs-comment-floating-button =
+ .title = Komentěrowaś
+ .aria-label = Komentěrowaś
+pdfjs-comment-floating-button-label = Komentěrowaś
+pdfjs-editor-comment-button =
+ .title = Komentěrowaś
+ .aria-label = Komentěrowaś
+pdfjs-editor-comment-button-label = Komentar
+pdfjs-editor-signature-button =
+ .title = Signaturu pśidaś
+pdfjs-editor-signature-button-label = Signaturu pśidaś
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor wuzwignjenja
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Kresleński editor
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signaturowy editor: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Wobrazowy editor
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Kreslanku wótwónoźeś
+pdfjs-editor-remove-freetext-button =
+ .title = Tekst wótwónoźeś
+pdfjs-editor-remove-stamp-button =
+ .title = Wobraz wótwónoźeś
+pdfjs-editor-remove-highlight-button =
+ .title = Wuzwignjenje wótpóraś
+pdfjs-editor-remove-signature-button =
+ .title = Signaturu wótwónoźeś
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Barwa
+pdfjs-editor-free-text-size-input = Wjelikosć
+pdfjs-editor-ink-color-input = Barwa
+pdfjs-editor-ink-thickness-input = Tłustosć
+pdfjs-editor-ink-opacity-input = Opacita
+pdfjs-editor-stamp-add-image-button =
+ .title = Wobraz pśidaś
+pdfjs-editor-stamp-add-image-button-label = Wobraz pśidaś
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tłustosć
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Tłustosć změniś, gaž se zapiski wuzwiguju, kótarež tekst njejsu
+pdfjs-editor-add-signature-container =
+ .aria-label = Wóźeńske elementy signaturow a skłaźone signatury
+pdfjs-editor-signature-add-signature-button =
+ .title = Nowu signaturu pśidaś
+pdfjs-editor-signature-add-signature-button-label = Nowu signaturu pśidaś
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Skłaźona signatura: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstowy editor
+ .default-content = Zachopśo pisaś …
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] { $count } komentar
+ [two] { $count } komentara
+ [few] { $count } komentary
+ *[other] { $count } komentarow
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Bocnicu zacyniś
+ .aria-label = Bocnicu zacyniś
+pdfjs-editor-comments-sidebar-close-button-label = Bocnicu zacyniś
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Wiźiśo něco wobspomnjeśa gódnego? Wuzwigniśo to a zawóstajśo komentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Dalšne informacije
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternatiwny tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternatiwny tekst wobźěłaś
+pdfjs-editor-alt-text-dialog-label = Nastajenje wubraś
+pdfjs-editor-alt-text-dialog-description = Alternatiwny tekst pomaga, gaž luźe njamógu wobraz wiźeś abo gaž se wobraz njezacytajo.
+pdfjs-editor-alt-text-add-description-label = Wopisanje pśidaś
+pdfjs-editor-alt-text-add-description-description = Pišćo 1 sadu abo 2 saźe, kótarejž temu, nastajenje abo akcije wopisujotej.
+pdfjs-editor-alt-text-mark-decorative-label = Ako dekoratiwny markěrowaś
+pdfjs-editor-alt-text-mark-decorative-description = To se za pyšnjece wobraze wužywa, na pśikład ramiki abo wódowe znamjenja.
+pdfjs-editor-alt-text-cancel-button = Pśetergnuś
+pdfjs-editor-alt-text-save-button = Składowaś
+pdfjs-editor-alt-text-decorative-tooltip = Ako dekoratiwny markěrowany
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Na pśikład, „Młody muski za blidom sejźi, aby jěź jědł“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternatiwny tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Górjejce nalěwo – wjelikosć změniś
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Górjejce wesrjejź – wjelikosć změniś
+pdfjs-editor-resizer-top-right =
+ .aria-label = Górjejce napšawo – wjelikosć změniś
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Wesrjejź napšawo – wjelikosć změniś
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Dołojce napšawo – wjelikosć změniś
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Dołojce wesrjejź – wjelikosć změniś
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Dołojce nalěwo – wjelikosć změniś
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Wesrjejź nalěwo – wjelikosć změniś
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Barwa wuzwignjenja
+pdfjs-editor-colorpicker-button =
+ .title = Barwu změniś
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Wuběrk barwow
+pdfjs-editor-colorpicker-yellow =
+ .title = Žołty
+pdfjs-editor-colorpicker-green =
+ .title = Zeleny
+pdfjs-editor-colorpicker-blue =
+ .title = Módry
+pdfjs-editor-colorpicker-pink =
+ .title = Pink
+pdfjs-editor-colorpicker-red =
+ .title = Cerwjeny
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Wšykne pokazaś
+pdfjs-editor-highlight-show-all-button =
+ .title = Wšykne pokazaś
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alternatiwny tekst wobźěłaś (wobrazowe wopisanje)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alternatiwny tekst pśidaś (wobrazowe wopisanje)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Pišćo how swójo wopisanje…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Krotke wopisanje za luźe, kótarež njamóžośo wobraz wiźeś abo gaž se wobraz njezacytajo.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Toś ten alternatiwny tekst jo se awtomatiski napórał a jo snaź njedokradny.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Dalšne informacije
+pdfjs-editor-new-alt-text-create-automatically-button-label = Alternatiwny tekst awtomatiski napóraś
+pdfjs-editor-new-alt-text-not-now-button = Nic něnto
+pdfjs-editor-new-alt-text-error-title = Alternatiwny tekst njedajo se awtomatiski napóraś
+pdfjs-editor-new-alt-text-error-description = Pšosym pišćo swój alternatiwny tekst abo wopytajśo pózdźej hyšći raz.
+pdfjs-editor-new-alt-text-error-close-button = Zacyniś
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Model KI za alternatiwny tekst se ześěgujo ({ $downloadedSize } z { $totalSize } MB)
+ .aria-valuetext = Model KI za alternatiwny tekst se ześěgujo ({ $downloadedSize } z { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternatiwny tekst jo se pśidał
+pdfjs-editor-new-alt-text-added-button-label = Alternatiwny tekst jo se pśidał
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Alternatiwny tekst felujo
+pdfjs-editor-new-alt-text-missing-button-label = Alternatiwny tekst felujo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternatiwny tekst pśeglědowaś
+pdfjs-editor-new-alt-text-to-review-button-label = Alternatiwny tekst pśeglědowaś
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Awtomatiski napórany: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Nastajenja alternatiwnego wobrazowego teksta
+pdfjs-image-alt-text-settings-button-label = Nastajenja alternatiwnego wobrazowego teksta
+pdfjs-editor-alt-text-settings-dialog-label = Nastajenja alternatiwnego wobrazowego teksta
+pdfjs-editor-alt-text-settings-automatic-title = Awtomatiski alternatiwny tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Alternatiwny tekst awtomatiski napóraś
+pdfjs-editor-alt-text-settings-create-model-description = Naraźujo wopisanja, aby pomagał ludam, kótarež njamóžośo wobraz wiźeś abo gaž se wobraz njezacytajo.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model KI alternatiwnego teksta ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Běžy lokalnje na wašom rěźe, aby waše daty priwatne wóstali. Za awtomatiski alternatiwny tekst trjebny.
+pdfjs-editor-alt-text-settings-delete-model-button = Lašowaś
+pdfjs-editor-alt-text-settings-download-model-button = Ześěgnuś
+pdfjs-editor-alt-text-settings-downloading-model-button = Ześěgujo se…
+pdfjs-editor-alt-text-settings-editor-title = Editor za alternatiwny tekst
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Editor alternatiwnego teksta ned pokazaś, gaž se wobraz pśidawa
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomaga, wam wšym swójim wobrazam alternatiwny tekst pśidaś.
+pdfjs-editor-alt-text-settings-close-button = Zacyniś
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Wuzwignjenje pśidane
+pdfjs-editor-freetext-added-alert = Tekst pśidany
+pdfjs-editor-ink-added-alert = Kreslanka pśidana
+pdfjs-editor-stamp-added-alert = Wobraz pśidany
+pdfjs-editor-signature-added-alert = Signatura pśidana
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Wótwónoźone wuzwignuś
+pdfjs-editor-undo-bar-message-freetext = Tekst jo se wótwónoźeł
+pdfjs-editor-undo-bar-message-ink = Kreslanka jo se wótwónoźeła
+pdfjs-editor-undo-bar-message-stamp = Wobraz jo se wótwónoźeł
+pdfjs-editor-undo-bar-message-signature = Signatura jo se wótwónoźeła
+pdfjs-editor-undo-bar-message-comment = Komentar jo se wótwónoźeł
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } pśipisk jo se wótwónoźeł
+ [two] { $count } pśipiska stej se wótwónoźełej
+ [few] { $count } pśipiski su se wótwónoźeli
+ *[other] { $count } pśipiskow jo se wótwónoźeło
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Anulěrowaś
+pdfjs-editor-undo-bar-undo-button-label = Anulěrowaś
+pdfjs-editor-undo-bar-close-button =
+ .title = Zacyniś
+pdfjs-editor-undo-bar-close-button-label = Zacyniś
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Toś ten modalny dialog wužywarjeju zmóžnja, signaturu napóraś, aby PDF-dokument pśidał. Wužywaŕ móžo mě wobźěłaś (kótarež teke ako alternatiwny tekst słužy) a pó žycenju signaturu za wóspjetne wužywanje składowaś.
+pdfjs-editor-add-signature-dialog-title = Signaturu pśidaś
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Typ
+ .title = Typ
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Kresliś
+ .title = Kresliś
+pdfjs-editor-add-signature-image-button = Wobraz
+ .title = Wobraz
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Zapódajśo swóju signaturu
+ .placeholder = Zapódajśo swóju signaturu
+pdfjs-editor-add-signature-draw-placeholder = Kresliśo swóju signaturu
+pdfjs-editor-add-signature-draw-thickness-range-label = Tłustosć
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Tłustosć kreslanki: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Śěgniśo dataju sem, aby ju nagrał
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Abo wubjeŕśo wobrazowe dataje
+ *[other] Abo pśepytajśo wobrazowe dataje
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Wopisanje (alternatiwny tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Wopisanje (alternatiwny tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatura
+pdfjs-editor-add-signature-clear-button-label = Signaturu lašowaś
+pdfjs-editor-add-signature-clear-button =
+ .title = Signaturu lašowaś
+pdfjs-editor-add-signature-save-checkbox = Signaturu składowaś
+pdfjs-editor-add-signature-save-warning-message = Sćo dojśpił limit 5 skłaźonych signaturow. Wótwónoźćo jadnu, aby wěcej składował.
+pdfjs-editor-add-signature-image-upload-error-title = Wobraz njedajo se nagraś
+pdfjs-editor-add-signature-image-upload-error-description = Pśeglědajśo swój seśowy zwisk abo wopytajśo drugi wobraz.
+pdfjs-editor-add-signature-image-no-data-error-title = Toś ten wobraz njedajo se do signatury pśetwóriś
+pdfjs-editor-add-signature-image-no-data-error-description = Wopytajśo pšosym drugi wobraz nagraś.
+pdfjs-editor-add-signature-error-close-button = Zacyniś
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Pśetergnuś
+pdfjs-editor-add-signature-add-button = Pśidaś
+pdfjs-editor-edit-signature-update-button = Aktualizěrowaś
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Komentar wobźěłaś
+pdfjs-editor-edit-comment-popup-button =
+ .title = Komentar wobźěłaś
+pdfjs-editor-delete-comment-popup-button-label = Komentar wótwónoźeś
+pdfjs-editor-delete-comment-popup-button =
+ .title = Komentar wótwónoźeś
+pdfjs-show-comment-button =
+ .title = Komentar pokazaś
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Komentar wobźěłaś
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualizěrowaś
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Komentar pśidaś
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Pśidaś
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Zachopśo pisaś…
+pdfjs-editor-edit-comment-dialog-cancel-button = Pśetergnuś
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Komentar pśidaś
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Bocnicu pśešaltowaś (dokument miniatury/rozrědowanje/pśipiski/warstwy wopśimujo)
+pdfjs-toggle-views-manager-button1-label = Boki zastojaś
+pdfjs-views-manager-sidebar =
+ .aria-label = Bocnica
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Pśiměrjenje wjelikosći bocnice
+pdfjs-views-manager-view-selector-button =
+ .title = Naglědy
+pdfjs-views-manager-view-selector-button-label = Naglědy
+pdfjs-views-manager-pages-title = Boki
+pdfjs-views-manager-outlines-title1 = Dokumentowa struktura
+ .title = Dokumentowa struktura (klikniśo dwójcy, aby wšykne zapiski pokazał/schował)
+pdfjs-views-manager-attachments-title = Pśidanki
+pdfjs-views-manager-layers-title1 = Rowniny
+ .title = Rowniny (klikniśo dwójcy, aby wšykne rowniny na standardny status slědk stajił)
+pdfjs-views-manager-pages-option-label = Boki
+pdfjs-views-manager-outlines-option-label = Dokumentowa struktura
+pdfjs-views-manager-attachments-option-label = Pśidanki
+pdfjs-views-manager-layers-option-label = Rowniny
+pdfjs-views-manager-add-file-button =
+ .title = Dataju pśidaś
+pdfjs-views-manager-add-file-button-label = Dataju pśidaś
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } wubrany
+ [two] { $count } wubranej
+ [few] { $count } wubrane
+ *[other] { $count } wubrane
+ }
+pdfjs-views-manager-pages-status-none-action-label = Boki wubraś
+pdfjs-views-manager-pages-status-action-button-label = Zastojaś
+pdfjs-views-manager-pages-status-copy-button-label = Kopěrowaś
+pdfjs-views-manager-pages-status-cut-button-label = Wurězaś
+pdfjs-views-manager-pages-status-delete-button-label = Lašowaś
+pdfjs-views-manager-pages-status-export-selected-button-label = Wubrane eksportěrowaś…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] { $count } bok wurězany
+ [two] { $count } boka wurězanej
+ [few] { $count } boki wurězane
+ *[other] { $count } bokow wurězane
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] { $count } bok kopěrowany
+ [two] { $count } boka kopěrowanej
+ [few] { $count } boki kopěrowane
+ *[other] { $count } bokow kopěrowane
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] { $count } bok wulašowany
+ [two] { $count } boka wulašowanej
+ [few] { $count } boki wulašowane
+ *[other] { $count } bokow wulašowane
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Waša dataja se pśigótujo…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Dataja se nagrawa…
+pdfjs-views-manager-status-warning-cut-label = Njedajo se wurězaś. Aktualizěrujśo bok a wopytajśo hyšći raz.
+pdfjs-views-manager-status-warning-copy-label = Njedajo se kopěrowaś. Aktualizěrujśo bok a wopytajśo hyšći raz.
+pdfjs-views-manager-status-warning-delete-label = Njedajo se lašowaś. Aktualizěrujśo bok a wopytajśo hyšći raz.
+pdfjs-views-manager-status-warning-save-label = Njedajo se składowaś. Aktualizěrujśo bok a wopytajśo hyšći raz.
+pdfjs-views-manager-status-undo-button-label = Anulěrowaś
+pdfjs-views-manager-status-done-button-label = Dokóńcony
+pdfjs-views-manager-status-close-button =
+ .title = Zacyniś
+pdfjs-views-manager-status-close-button-label = Zacyniś
+pdfjs-views-manager-paste-button-label = Zasajźiś
+pdfjs-views-manager-paste-button-before =
+ .title = Pśed prědnym bokom zasajźiś
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Za bokom { $page } zasajźiś
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOWY
+pdfjs-views-manager-waiting-for-file = Dataja se nagrawa…
+pdfjs-toggle-views-manager-button1 =
+ .title = Boki zastojaś
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Kakosći digitalneje signatury
+ .aria-label = Kakosći digitalneje signatury
+pdfjs-digital-signature-properties-button-label = Kakosći digitalneje signatury
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument jo se signěrował z płaśiweju digitalneju signaturu
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument jo se signěrował, ale { $count } digitalna signatura njedajo se wobkšuśiś
+ [two] Dokument jo se signěrował, ale { $count } digitalnej signaturje njedajotej se wobkšuśiś
+ [few] Dokument jo se signěrował, ale { $count } digitalne signatury njedaju se wobkšuśiś
+ *[other] Dokument jo se signěrował, ale { $count } digitalnych signaturow njedajo se wobkšuśiś
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument jo z { $count } certifikatom signěrowany, kótaryž njejo dowěry gódny
+ [two] Dokument jo z { $count } certifikatoma signěrowany, kótarejž njejstej dowěry gódnej
+ [few] Dokument jo z { $count } certifikatami signěrowany, kótarež njejsu dowěry gódne
+ *[other] Dokument jo z { $count } certifikatami signěrowany, kótarež njejsu dowěry gódne
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument jo z { $count } spadnjonym certifikatom signěrowany
+ [two] Dokument jo z { $count } spadnjonyma certifikatoma signěrowany
+ [few] Dokument jo z { $count } spadnjonymi certifikatami signěrowany
+ *[other] Dokument jo z { $count } spadnjonymi certifikatami signěrowany
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument ma { $count } njepłaśiwu digitalnu signaturu
+ [two] Dokument ma { $count } njepłaśiwej digitalnej signaturje
+ [few] Dokument ma { $count } njepłaśiwe digitalne signatury
+ *[other] Dokument ma { $count } njepłaśiwych digitalnych signaturow
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument jo z { $count } wótwołanym certifikatom signěrowany
+ [two] Dokument jo z { $count } wótwołanyma certifikatoma signěrowany
+ [few] Dokument jo z { $count } wótwołanymi certifikatami signěrowany
+ *[other] Dokument jo z { $count } wótwołanymi certifikatami signěrowany
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signatura jo wobkšuśona
+pdfjs-digital-signature-properties-status-invalid = Status: Signatura jo njepłaśiwa
+pdfjs-digital-signature-properties-status-unknown = Status: Njedajo se wobkšuśiś (njepódpěra se)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certifikat: Dowěry gódny ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certifikat: Nic k dispoziciji
+pdfjs-digital-signature-properties-certificate-untrusted = Certifikat: Dowěry njegódny
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certifikat: Njeznaty wudawaŕ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certifikat: Samsigněrowany ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certifikat: Dowěry njegódny wudawaŕ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certifikat: Spadnjony
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certifikat: Spadnjony ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certifikat: Wótwołany
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Skłaźonu signaturu wótwónoźeś
+pdfjs-editor-delete-signature-button-label1 = Skłaźonu signaturu wótwónoźeś
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Wopisanje wobźěłaś
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Wopisanje wobźěłaś
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/el/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/el/viewer.ftl
new file mode 100644
index 0000000..fbd292d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/el/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Προηγούμενη σελίδα
+pdfjs-previous-button-label = Προηγούμενη
+pdfjs-next-button =
+ .title = Επόμενη σελίδα
+pdfjs-next-button-label = Επόμενη
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Σελίδα
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = από { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } από { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Σμίκρυνση
+pdfjs-zoom-out-button-label = Σμίκρυνση
+pdfjs-zoom-in-button =
+ .title = Μεγέθυνση
+pdfjs-zoom-in-button-label = Μεγέθυνση
+pdfjs-zoom-select =
+ .title = Ζουμ
+pdfjs-presentation-mode-button =
+ .title = Εναλλαγή σε λειτουργία παρουσίασης
+pdfjs-presentation-mode-button-label = Λειτουργία παρουσίασης
+pdfjs-open-file-button =
+ .title = Άνοιγμα αρχείου
+pdfjs-open-file-button-label = Άνοιγμα
+pdfjs-print-button =
+ .title = Εκτύπωση
+pdfjs-print-button-label = Εκτύπωση
+pdfjs-save-button =
+ .title = Αποθήκευση
+pdfjs-save-button-label = Αποθήκευση
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Λήψη
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Λήψη
+pdfjs-bookmark-button =
+ .title = Τρέχουσα σελίδα (Προβολή URL από τρέχουσα σελίδα)
+pdfjs-bookmark-button-label = Τρέχουσα σελίδα
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Εργαλεία
+pdfjs-tools-button-label = Εργαλεία
+pdfjs-first-page-button =
+ .title = Μετάβαση στην πρώτη σελίδα
+pdfjs-first-page-button-label = Μετάβαση στην πρώτη σελίδα
+pdfjs-last-page-button =
+ .title = Μετάβαση στην τελευταία σελίδα
+pdfjs-last-page-button-label = Μετάβαση στην τελευταία σελίδα
+pdfjs-page-rotate-cw-button =
+ .title = Δεξιόστροφη περιστροφή
+pdfjs-page-rotate-cw-button-label = Δεξιόστροφη περιστροφή
+pdfjs-page-rotate-ccw-button =
+ .title = Αριστερόστροφη περιστροφή
+pdfjs-page-rotate-ccw-button-label = Αριστερόστροφη περιστροφή
+pdfjs-cursor-text-select-tool-button =
+ .title = Ενεργοποίηση εργαλείου επιλογής κειμένου
+pdfjs-cursor-text-select-tool-button-label = Εργαλείο επιλογής κειμένου
+pdfjs-cursor-hand-tool-button =
+ .title = Ενεργοποίηση εργαλείου χεριού
+pdfjs-cursor-hand-tool-button-label = Εργαλείο χεριού
+pdfjs-scroll-page-button =
+ .title = Χρήση κύλισης σελίδας
+pdfjs-scroll-page-button-label = Κύλιση σελίδας
+pdfjs-scroll-vertical-button =
+ .title = Χρήση κάθετης κύλισης
+pdfjs-scroll-vertical-button-label = Κάθετη κύλιση
+pdfjs-scroll-horizontal-button =
+ .title = Χρήση οριζόντιας κύλισης
+pdfjs-scroll-horizontal-button-label = Οριζόντια κύλιση
+pdfjs-scroll-wrapped-button =
+ .title = Χρήση κυκλικής κύλισης
+pdfjs-scroll-wrapped-button-label = Κυκλική κύλιση
+pdfjs-spread-none-button =
+ .title = Να μην γίνει σύνδεση των επεκτάσεων σελίδων
+pdfjs-spread-none-button-label = Χωρίς επεκτάσεις
+pdfjs-spread-odd-button =
+ .title = Σύνδεση επεκτάσεων σελίδων ξεκινώντας από τις μονές σελίδες
+pdfjs-spread-odd-button-label = Μονές επεκτάσεις
+pdfjs-spread-even-button =
+ .title = Σύνδεση επεκτάσεων σελίδων ξεκινώντας από τις ζυγές σελίδες
+pdfjs-spread-even-button-label = Ζυγές επεκτάσεις
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Ιδιότητες εγγράφου…
+pdfjs-document-properties-button-label = Ιδιότητες εγγράφου…
+pdfjs-document-properties-file-name = Όνομα αρχείου:
+pdfjs-document-properties-file-size = Μέγεθος αρχείου:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Τίτλος:
+pdfjs-document-properties-author = Συγγραφέας:
+pdfjs-document-properties-subject = Θέμα:
+pdfjs-document-properties-keywords = Λέξεις-κλειδιά:
+pdfjs-document-properties-creation-date = Ημερομηνία δημιουργίας:
+pdfjs-document-properties-modification-date = Ημερομηνία τροποποίησης:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Δημιουργός:
+pdfjs-document-properties-producer = Παραγωγός PDF:
+pdfjs-document-properties-version = Έκδοση PDF:
+pdfjs-document-properties-page-count = Αριθμός σελίδων:
+pdfjs-document-properties-page-size = Μέγεθος σελίδας:
+pdfjs-document-properties-page-size-unit-inches = ίντσες
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = κατακόρυφα
+pdfjs-document-properties-page-size-orientation-landscape = οριζόντια
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Επιστολή
+pdfjs-document-properties-page-size-name-legal = Τύπου Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Ταχεία προβολή ιστού:
+pdfjs-document-properties-linearized-yes = Ναι
+pdfjs-document-properties-linearized-no = Όχι
+pdfjs-document-properties-close-button = Κλείσιμο
+pdfjs-digital-signature-properties-view-certificate = Προβολή πιστοποιητικού
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Αιτία: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Χρονοσήμανση: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Δευτερεύουσα υπογραφή ({ $count })
+ *[other] Δευτερεύουσες υπογραφές ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Προετοιμασία του εγγράφου για εκτύπωση…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Ακύρωση
+pdfjs-printing-not-supported = Προειδοποίηση: Η εκτύπωση δεν υποστηρίζεται πλήρως από το πρόγραμμα περιήγησης.
+pdfjs-printing-not-ready = Προειδοποίηση: Το PDF δεν φορτώθηκε πλήρως για εκτύπωση.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = (Απ)ενεργοποίηση πλαϊνής γραμμής
+pdfjs-toggle-sidebar-notification-button =
+ .title = (Απ)ενεργοποίηση πλαϊνής γραμμής (το έγγραφο περιέχει περίγραμμα/συνημμένα/επίπεδα)
+pdfjs-toggle-sidebar-button-label = (Απ)ενεργοποίηση πλαϊνής γραμμής
+pdfjs-document-outline-button =
+ .title = Εμφάνιση διάρθρωσης εγγράφου (διπλό κλικ για ανάπτυξη/σύμπτυξη όλων των στοιχείων)
+pdfjs-document-outline-button-label = Διάρθρωση εγγράφου
+pdfjs-attachments-button =
+ .title = Εμφάνιση συνημμένων
+pdfjs-attachments-button-label = Συνημμένα
+pdfjs-layers-button =
+ .title = Εμφάνιση επιπέδων (διπλό κλικ για επαναφορά όλων των επιπέδων στην προεπιλεγμένη κατάσταση)
+pdfjs-layers-button-label = Επίπεδα
+pdfjs-thumbs-button =
+ .title = Εμφάνιση μικρογραφιών
+pdfjs-thumbs-button-label = Μικρογραφίες
+pdfjs-current-outline-item-button =
+ .title = Εύρεση τρέχοντος στοιχείου διάρθρωσης
+pdfjs-current-outline-item-button-label = Τρέχον στοιχείο διάρθρωσης
+pdfjs-findbar-button =
+ .title = Εύρεση στο έγγραφο
+pdfjs-findbar-button-label = Εύρεση
+pdfjs-additional-layers = Επιπρόσθετα επίπεδα
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Σελίδα { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Μικρογραφία σελίδας { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Επιλογή σελίδας { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Σελίδα { $page } από { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Εύρεση
+ .placeholder = Εύρεση στο έγγραφο…
+pdfjs-find-previous-button =
+ .title = Εύρεση της προηγούμενης εμφάνισης της φράσης
+pdfjs-find-previous-button-label = Προηγούμενο
+pdfjs-find-next-button =
+ .title = Εύρεση της επόμενης εμφάνισης της φράσης
+pdfjs-find-next-button-label = Επόμενο
+pdfjs-find-highlight-checkbox = Επισήμανση όλων
+pdfjs-find-match-case-checkbox-label = Συμφωνία πεζών/κεφαλαίων
+pdfjs-find-match-diacritics-checkbox-label = Αντιστοίχιση διακριτικών
+pdfjs-find-entire-word-checkbox-label = Ολόκληρες λέξεις
+pdfjs-find-reached-top = Φτάσατε στην αρχή του εγγράφου, συνέχεια από το τέλος
+pdfjs-find-reached-bottom = Φτάσατε στο τέλος του εγγράφου, συνέχεια από την αρχή
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } από { $total } αντιστοιχία
+ *[other] { $current } από { $total } αντιστοιχίες
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Περισσότερες από { $limit } αντιστοιχία
+ *[other] Περισσότερες από { $limit } αντιστοιχίες
+ }
+pdfjs-find-not-found = Η φράση δεν βρέθηκε
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Πλάτος σελίδας
+pdfjs-page-scale-fit = Μέγεθος σελίδας
+pdfjs-page-scale-auto = Αυτόματο ζουμ
+pdfjs-page-scale-actual = Πραγματικό μέγεθος
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Σελίδα { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Προέκυψε σφάλμα κατά τη φόρτωση του PDF.
+pdfjs-invalid-file-error = Μη έγκυρο ή κατεστραμμένο αρχείο PDF.
+pdfjs-missing-file-error = Λείπει αρχείο PDF.
+pdfjs-unexpected-response-error = Απρόσμενη απάντηση διακομιστή.
+pdfjs-rendering-error = Προέκυψε σφάλμα κατά την εμφάνιση της σελίδας.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Σχόλιο «{ $type }»]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Εισαγάγετε τον κωδικό πρόσβασης για να ανοίξετε αυτό το αρχείο PDF.
+pdfjs-password-invalid = Μη έγκυρος κωδικός πρόσβασης. Δοκιμάστε ξανά.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Ακύρωση
+pdfjs-web-fonts-disabled = Οι γραμματοσειρές ιστού είναι ανενεργές: δεν είναι δυνατή η χρήση των ενσωματωμένων γραμματοσειρών PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Κείμενο
+pdfjs-editor-color-picker-free-text-input =
+ .title = Αλλαγή χρώματος κειμένου
+pdfjs-editor-free-text-button-label = Κείμενο
+pdfjs-editor-ink-button =
+ .title = Σχέδιο
+pdfjs-editor-color-picker-ink-input =
+ .title = Αλλαγή χρώματος σχεδίου
+pdfjs-editor-ink-button-label = Σχέδιο
+pdfjs-editor-stamp-button =
+ .title = Προσθήκη ή επεξεργασία εικόνων
+pdfjs-editor-stamp-button-label = Προσθήκη ή επεξεργασία εικόνων
+pdfjs-editor-highlight-button =
+ .title = Επισήμανση
+pdfjs-editor-highlight-button-label = Επισήμανση
+pdfjs-highlight-floating-button1 =
+ .title = Επισήμανση
+ .aria-label = Επισήμανση
+pdfjs-highlight-floating-button-label = Επισήμανση
+pdfjs-comment-floating-button =
+ .title = Σχόλιο
+ .aria-label = Σχόλιο
+pdfjs-comment-floating-button-label = Σχόλιο
+pdfjs-editor-comment-button =
+ .title = Σχόλιο
+ .aria-label = Σχόλιο
+pdfjs-editor-comment-button-label = Σχόλιο
+pdfjs-editor-signature-button =
+ .title = Προσθήκη υπογραφής
+pdfjs-editor-signature-button-label = Προσθήκη υπογραφής
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Επεξεργασία επισήμανσης
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Επεξεργασία σχεδίου
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Επεξεργασία υπογραφής: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Επεξεργασία εικόνας
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Αφαίρεση σχεδίου
+pdfjs-editor-remove-freetext-button =
+ .title = Αφαίρεση κειμένου
+pdfjs-editor-remove-stamp-button =
+ .title = Αφαίρεση εικόνας
+pdfjs-editor-remove-highlight-button =
+ .title = Αφαίρεση επισήμανσης
+pdfjs-editor-remove-signature-button =
+ .title = Αφαίρεση υπογραφής
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Χρώμα
+pdfjs-editor-free-text-size-input = Μέγεθος
+pdfjs-editor-ink-color-input = Χρώμα
+pdfjs-editor-ink-thickness-input = Πάχος
+pdfjs-editor-ink-opacity-input = Αδιαφάνεια
+pdfjs-editor-stamp-add-image-button =
+ .title = Προσθήκη εικόνας
+pdfjs-editor-stamp-add-image-button-label = Προσθήκη εικόνας
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Πάχος
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Αλλαγή πάχους κατά την επισήμανση στοιχείων εκτός κειμένου
+pdfjs-editor-add-signature-container =
+ .aria-label = Στοιχεία ελέγχου υπογραφής και αποθηκευμένες υπογραφές
+pdfjs-editor-signature-add-signature-button =
+ .title = Προσθήκη νέας υπογραφής
+pdfjs-editor-signature-add-signature-button-label = Προσθήκη νέας υπογραφής
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Αποθηκευμένη υπογραφή: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Επεξεργασία κειμένου
+ .default-content = Ξεκινήστε να πληκτρολογείτε…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Σχόλια
+ *[other] Σχόλια
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Κλείσιμο πλευρικής στήλης
+ .aria-label = Κλείσιμο πλευρικής στήλης
+pdfjs-editor-comments-sidebar-close-button-label = Κλείσιμο πλευρικής στήλης
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Βλέπετε κάτι αξιοσημείωτο; Επισημάνετε το και αφήστε ένα σχόλιο.
+pdfjs-editor-comments-sidebar-no-comments-link = Μάθετε περισσότερα
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Εναλλακτικό κείμενο
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Επεξεργασία εναλλακτικού κειμένου
+pdfjs-editor-alt-text-dialog-label = Διαλέξτε μια επιλογή
+pdfjs-editor-alt-text-dialog-description = Το εναλλακτικό κείμενο είναι χρήσιμο όταν οι άνθρωποι δεν μπορούν να δουν την εικόνα ή όταν αυτή δεν φορτώνεται.
+pdfjs-editor-alt-text-add-description-label = Προσθήκη περιγραφής
+pdfjs-editor-alt-text-add-description-description = Στοχεύστε σε μία ή δύο προτάσεις που περιγράφουν το θέμα, τη ρύθμιση ή τις ενέργειες.
+pdfjs-editor-alt-text-mark-decorative-label = Επισήμανση ως διακοσμητικό
+pdfjs-editor-alt-text-mark-decorative-description = Χρησιμοποιείται για διακοσμητικές εικόνες, όπως περιγράμματα ή υδατογραφήματα.
+pdfjs-editor-alt-text-cancel-button = Ακύρωση
+pdfjs-editor-alt-text-save-button = Αποθήκευση
+pdfjs-editor-alt-text-decorative-tooltip = Επισημασμένο ως διακοσμητικό
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Για παράδειγμα, «Ένας νεαρός άνδρας κάθεται σε ένα τραπέζι για να φάει ένα γεύμα»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Εναλλακτικό κείμενο
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Επάνω αριστερή γωνία — αλλαγή μεγέθους
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Μέσο επάνω πλευράς — αλλαγή μεγέθους
+pdfjs-editor-resizer-top-right =
+ .aria-label = Επάνω δεξιά γωνία — αλλαγή μεγέθους
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Μέσο δεξιάς πλευράς — αλλαγή μεγέθους
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Κάτω δεξιά γωνία — αλλαγή μεγέθους
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Μέσο κάτω πλευράς — αλλαγή μεγέθους
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Κάτω αριστερή γωνία — αλλαγή μεγέθους
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Μέσο αριστερής πλευράς — αλλαγή μεγέθους
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Χρώμα επισήμανσης
+pdfjs-editor-colorpicker-button =
+ .title = Αλλαγή χρώματος
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Επιλογές χρωμάτων
+pdfjs-editor-colorpicker-yellow =
+ .title = Κίτρινο
+pdfjs-editor-colorpicker-green =
+ .title = Πράσινο
+pdfjs-editor-colorpicker-blue =
+ .title = Μπλε
+pdfjs-editor-colorpicker-pink =
+ .title = Ροζ
+pdfjs-editor-colorpicker-red =
+ .title = Κόκκινο
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Εμφάνιση όλων
+pdfjs-editor-highlight-show-all-button =
+ .title = Εμφάνιση όλων
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Επεξεργασία εναλλακτικού κειμένου (περιγραφή εικόνας)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Προσθήκη εναλλακτικού κειμένου (περιγραφή εικόνας)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Γράψτε την περιγραφή σας εδώ…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Σύντομη περιγραφή για άτομα που δεν μπορούν να δουν την εικόνα ή όταν η εικόνα δεν φορτώνεται.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Αυτό το εναλλακτικό κείμενο δημιουργήθηκε αυτόματα και ενδέχεται να είναι ανακριβές.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Μάθετε περισσότερα
+pdfjs-editor-new-alt-text-create-automatically-button-label = Αυτόματη δημιουργία εναλλακτικού κειμένου
+pdfjs-editor-new-alt-text-not-now-button = Όχι τώρα
+pdfjs-editor-new-alt-text-error-title = Δεν ήταν δυνατή η αυτόματη δημιουργία εναλλακτικού κειμένου
+pdfjs-editor-new-alt-text-error-description = Γράψτε το δικό σας εναλλακτικό κείμενο ή δοκιμάστε ξανά αργότερα.
+pdfjs-editor-new-alt-text-error-close-button = Κλείσιμο
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Λήψη μοντέλου ΤΝ εναλλακτικού κειμένου ({ $downloadedSize } από { $totalSize } MB)
+ .aria-valuetext = Λήψη μοντέλου ΤΝ εναλλακτικού κειμένου ({ $downloadedSize } από { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Προστέθηκε εναλλακτικό κείμενο
+pdfjs-editor-new-alt-text-added-button-label = Προστέθηκε εναλλακτικό κείμενο
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Απουσία εναλλακτικού κειμένου
+pdfjs-editor-new-alt-text-missing-button-label = Απουσία εναλλακτικού κειμένου
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Έλεγχος εναλλακτικού κειμένου
+pdfjs-editor-new-alt-text-to-review-button-label = Έλεγχος εναλλακτικού κειμένου
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Αυτόματη δημιουργία: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ρυθμίσεις εναλλακτικού κειμένου εικόνας
+pdfjs-image-alt-text-settings-button-label = Ρυθμίσεις εναλλακτικού κειμένου εικόνας
+pdfjs-editor-alt-text-settings-dialog-label = Ρυθμίσεις εναλλακτικού κειμένου εικόνας
+pdfjs-editor-alt-text-settings-automatic-title = Αυτόματο εναλλακτικό κείμενο
+pdfjs-editor-alt-text-settings-create-model-button-label = Αυτόματη δημιουργία εναλλακτικού κειμένου
+pdfjs-editor-alt-text-settings-create-model-description = Προτείνει περιγραφές για άτομα που δεν μπορούν να δουν την εικόνα ή όταν η εικόνα δεν φορτώνεται.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Μοντέλο ΤΝ εναλλακτικού κειμένου ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Εκτελείται τοπικά στη συσκευή σας, ώστε τα δεδομένα σας να παραμένουν ιδιωτικά. Απαιτείται για τη δημιουργία του αυτόματου εναλλακτικού κειμένου.
+pdfjs-editor-alt-text-settings-delete-model-button = Διαγραφή
+pdfjs-editor-alt-text-settings-download-model-button = Λήψη
+pdfjs-editor-alt-text-settings-downloading-model-button = Λήψη…
+pdfjs-editor-alt-text-settings-editor-title = Επεξεργασία εναλλακτικού κειμένου
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Άμεση εμφάνιση της επεξεργασίας εναλλακτικού κειμένου κατά την προσθήκη εικόνας
+pdfjs-editor-alt-text-settings-show-dialog-description = Σας βοηθά να βεβαιωθείτε ότι όλες οι εικόνες σας έχουν εναλλακτικό κείμενο.
+pdfjs-editor-alt-text-settings-close-button = Κλείσιμο
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Προστέθηκε επισήμανση
+pdfjs-editor-freetext-added-alert = Προστέθηκε κείμενο
+pdfjs-editor-ink-added-alert = Προστέθηκε σχέδιο
+pdfjs-editor-stamp-added-alert = Προστέθηκε εικόνα
+pdfjs-editor-signature-added-alert = Προστέθηκε υπογραφή
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Η επισήμανση αφαιρέθηκε
+pdfjs-editor-undo-bar-message-freetext = Το κείμενο αφαιρέθηκε
+pdfjs-editor-undo-bar-message-ink = Το σχέδιο αφαιρέθηκε
+pdfjs-editor-undo-bar-message-stamp = Η εικόνα αφαιρέθηκε
+pdfjs-editor-undo-bar-message-signature = Η υπογραφή αφαιρέθηκε
+pdfjs-editor-undo-bar-message-comment = Το σχόλιο αφαιρέθηκε
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] Αφαιρέθηκε { $count } σχολιασμός
+ *[other] Αφαιρέθηκαν { $count } σχολιασμοί
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Αναίρεση
+pdfjs-editor-undo-bar-undo-button-label = Αναίρεση
+pdfjs-editor-undo-bar-close-button =
+ .title = Κλείσιμο
+pdfjs-editor-undo-bar-close-button-label = Κλείσιμο
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Αυτό το παράθυρο διαλόγου επιτρέπει στον χρήστη να δημιουργήσει μια υπογραφή για να την προσθέσει σε ένα έγγραφο PDF. Ο χρήστης μπορεί να επεξεργαστεί το όνομα (το οποίο χρησιμεύει και ως εναλλακτικό κείμενο) και, προαιρετικά, να αποθηκεύσει την υπογραφή για επαναλαμβανόμενη χρήση.
+pdfjs-editor-add-signature-dialog-title = Προσθήκη υπογραφής
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Πληκτρολόγηση
+ .title = Πληκτρολόγηση
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Σχέδιο
+ .title = Σχέδιο
+pdfjs-editor-add-signature-image-button = Εικόνα
+ .title = Εικόνα
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Πληκτρολογήστε την υπογραφή σας
+ .placeholder = Πληκτρολογήστε την υπογραφή σας
+pdfjs-editor-add-signature-draw-placeholder = Σχεδιάστε την υπογραφή σας
+pdfjs-editor-add-signature-draw-thickness-range-label = Πάχος
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Πάχος σχεδίου: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Σύρετε ένα αρχείο εδώ για μεταφόρτωση
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ή επιλέξτε αρχεία εικόνας
+ *[other] Ή περιηγηθείτε σε αρχεία εικόνας
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Περιγραφή (εναλλακτικό κείμενο)
+pdfjs-editor-add-signature-description-input =
+ .title = Περιγραφή (εναλλακτικό κείμενο)
+pdfjs-editor-add-signature-description-default-when-drawing = Υπογραφή
+pdfjs-editor-add-signature-clear-button-label = Απαλοιφή υπογραφής
+pdfjs-editor-add-signature-clear-button =
+ .title = Απαλοιφή υπογραφής
+pdfjs-editor-add-signature-save-checkbox = Αποθήκευση υπογραφής
+pdfjs-editor-add-signature-save-warning-message = Έχετε φτάσει το όριο των 5 αποθηκευμένων υπογραφών. Αφαιρέστε μία για να αποθηκεύσετε περισσότερες.
+pdfjs-editor-add-signature-image-upload-error-title = Δεν ήταν δυνατή η μεταφόρτωση της εικόνας
+pdfjs-editor-add-signature-image-upload-error-description = Ελέγξτε τη σύνδεση δικτύου σας ή δοκιμάστε μια άλλη εικόνα.
+pdfjs-editor-add-signature-image-no-data-error-title = Δεν είναι δυνατή η μετατροπή αυτής της εικόνας σε υπογραφή
+pdfjs-editor-add-signature-image-no-data-error-description = Δοκιμάστε να μεταφορτώσετε μια άλλη εικόνα.
+pdfjs-editor-add-signature-error-close-button = Κλείσιμο
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Ακύρωση
+pdfjs-editor-add-signature-add-button = Προσθήκη
+pdfjs-editor-edit-signature-update-button = Ενημέρωση
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Επεξεργασία σχολίου
+pdfjs-editor-edit-comment-popup-button =
+ .title = Επεξεργασία σχολίου
+pdfjs-editor-delete-comment-popup-button-label = Αφαίρεση σχολίου
+pdfjs-editor-delete-comment-popup-button =
+ .title = Αφαίρεση σχολίου
+pdfjs-show-comment-button =
+ .title = Εμφάνιση σχολίου
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Επεξεργασία σχολίου
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Ενημέρωση
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Προσθήκη σχολίου
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Προσθήκη
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Ξεκινήστε να πληκτρολογείτε…
+pdfjs-editor-edit-comment-dialog-cancel-button = Ακύρωση
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Προσθήκη σχολίου
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = (Απ)ενεργοποίηση πλαϊνής γραμμής (το έγγραφο περιέχει μικρογραφίες/περίγραμμα/συνημμένα/επίπεδα)
+pdfjs-toggle-views-manager-button1-label = Διαχείριση σελίδων
+pdfjs-views-manager-sidebar =
+ .aria-label = Πλαϊνή γραμμή
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Αλλαγή μεγέθους πλαϊνής γραμμής
+pdfjs-views-manager-view-selector-button =
+ .title = Προβολές
+pdfjs-views-manager-view-selector-button-label = Προβολές
+pdfjs-views-manager-pages-title = Σελίδες
+pdfjs-views-manager-outlines-title1 = Διάρθρωση εγγράφου
+ .title = Διάρθρωση εγγράφου (διπλό κλικ για ανάπτυξη/σύμπτυξη όλων των στοιχείων)
+pdfjs-views-manager-attachments-title = Συνημμένα
+pdfjs-views-manager-layers-title1 = Επίπεδα
+ .title = Επίπεδα (διπλό κλικ για επαναφορά όλων των επιπέδων στην προεπιλεγμένη κατάσταση)
+pdfjs-views-manager-pages-option-label = Σελίδες
+pdfjs-views-manager-outlines-option-label = Διάρθρωση εγγράφου
+pdfjs-views-manager-attachments-option-label = Συνημμένα
+pdfjs-views-manager-layers-option-label = Επίπεδα
+pdfjs-views-manager-add-file-button =
+ .title = Προσθήκη αρχείου
+pdfjs-views-manager-add-file-button-label = Προσθήκη αρχείου
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } επιλεγμένη
+ *[other] { $count } επιλεγμένες
+ }
+pdfjs-views-manager-pages-status-none-action-label = Επιλογή σελίδων
+pdfjs-views-manager-pages-status-action-button-label = Διαχείριση
+pdfjs-views-manager-pages-status-copy-button-label = Αντιγραφή
+pdfjs-views-manager-pages-status-cut-button-label = Αποκοπή
+pdfjs-views-manager-pages-status-delete-button-label = Διαγραφή
+pdfjs-views-manager-pages-status-export-selected-button-label = Εξαγωγή επιλεγμένων…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Αποκόπηκε 1 σελίδα
+ *[other] Αποκόπηκαν { $count } σελίδες
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Αντιγράφηκε 1 σελίδα
+ *[other] Αντιγράφηκαν { $count } σελίδες
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Διαγράφηκε 1 σελίδα
+ *[other] Διαγράφηκαν { $count } σελίδες
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Προετοιμασία αρχείου…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Μεταφόρτωση αρχείου…
+pdfjs-views-manager-status-warning-cut-label = Δεν ήταν δυνατή η αποκοπή. Ανανεώστε τη σελίδα και δοκιμάστε ξανά.
+pdfjs-views-manager-status-warning-copy-label = Δεν ήταν δυνατή η αντιγραφή. Ανανεώστε τη σελίδα και δοκιμάστε ξανά.
+pdfjs-views-manager-status-warning-delete-label = Δεν ήταν δυνατή η διαγραφή. Ανανεώστε τη σελίδα και δοκιμάστε ξανά.
+pdfjs-views-manager-status-warning-save-label = Δεν ήταν δυνατή η αποθήκευση. Ανανεώστε τη σελίδα και δοκιμάστε ξανά.
+pdfjs-views-manager-status-undo-button-label = Αναίρεση
+pdfjs-views-manager-status-done-button-label = Τέλος
+pdfjs-views-manager-status-close-button =
+ .title = Κλείσιμο
+pdfjs-views-manager-status-close-button-label = Κλείσιμο
+pdfjs-views-manager-paste-button-label = Επικόλληση
+pdfjs-views-manager-paste-button-before =
+ .title = Επικόλληση πριν από την πρώτη σελίδα
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Επικόλληση μετά τη σελίδα { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = ΝΕΟ
+pdfjs-views-manager-waiting-for-file = Μεταφόρτωση αρχείου…
+pdfjs-toggle-views-manager-button1 =
+ .title = Διαχείριση σελίδων
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Ιδιότητες ψηφιακής υπογραφής
+ .aria-label = Ιδιότητες ψηφιακής υπογραφής
+pdfjs-digital-signature-properties-button-label = Ιδιότητες ψηφιακής υπογραφής
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Το έγγραφο έχει υπογραφεί με έγκυρη ψηφιακή υπογραφή
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Το έγγραφο έχει υπογραφεί, αλλά δεν ήταν δυνατή η επαλήθευση { $count } ψηφιακής υπογραφής
+ *[other] Το έγγραφο έχει υπογραφεί, αλλά δεν ήταν δυνατή η επαλήθευση { $count } ψηφιακών υπογραφών
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Το έγγραφο έχει υπογραφεί με { $count } πιστοποιητικό που δεν είναι αξιόπιστο
+ *[other] Το έγγραφο έχει υπογραφεί με { $count } πιστοποιητικά που δεν είναι αξιόπιστα
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Το έγγραφο έχει υπογραφεί με { $count } ληγμένο πιστοποιητικό
+ *[other] Το έγγραφο έχει υπογραφεί με { $count } ληγμένα πιστοποιητικά
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Το έγγραφο διαθέτει { $count } μη έγκυρη ψηφιακή υπογραφή
+ *[other] Το έγγραφο διαθέτει { $count } μη έγκυρες ψηφιακές υπογραφές
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Το έγγραφο έχει υπογραφεί με { $count } ανακληθέν πιστοποιητικό
+ *[other] Το έγγραφο έχει υπογραφεί με { $count } ανακληθέντα πιστοποιητικά
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Κατάσταση: Επαληθευμένη υπογραφή
+pdfjs-digital-signature-properties-status-invalid = Κατάσταση: Μη έγκυρη υπογραφή
+pdfjs-digital-signature-properties-status-unknown = Κατάσταση: Αδυναμία επαλήθευσης (δεν υποστηρίζεται)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Πιστοποιητικό: Έμπιστο ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Πιστοποιητικό: Μη διαθέσιμο
+pdfjs-digital-signature-properties-certificate-untrusted = Πιστοποιητικό: Μη αξιόπιστο
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Πιστοποιητικό: Άγνωστος εκδότης ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Πιστοποιητικό: Αυτοϋπογεγραμμένο ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Πιστοποιητικό: Μη αξιόπιστος εκδότης ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Πιστοποιητικό: Έχει λήξει
+pdfjs-digital-signature-properties-certificate-expired-with-date = Πιστοποιητικό: Έχει λήξει ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Πιστοποιητικό: Έχει ανακληθεί
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Αφαίρεση αποθηκευμένης υπογραφής
+pdfjs-editor-delete-signature-button-label1 = Αφαίρεση αποθηκευμένης υπογραφής
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Επεξεργασία περιγραφής
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Επεξεργασία περιγραφής
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-CA/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-CA/viewer.ftl
new file mode 100644
index 0000000..4c2daaa
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-CA/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Previous Page
+pdfjs-previous-button-label = Previous
+pdfjs-next-button =
+ .title = Next Page
+pdfjs-next-button-label = Next
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Page
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = of { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom Out
+pdfjs-zoom-out-button-label = Zoom Out
+pdfjs-zoom-in-button =
+ .title = Zoom In
+pdfjs-zoom-in-button-label = Zoom In
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Switch to Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Open File
+pdfjs-open-file-button-label = Open
+pdfjs-print-button =
+ .title = Print
+pdfjs-print-button-label = Print
+pdfjs-save-button =
+ .title = Save
+pdfjs-save-button-label = Save
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Download
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Download
+pdfjs-bookmark-button =
+ .title = Current Page (View URL from Current Page)
+pdfjs-bookmark-button-label = Current Page
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tools
+pdfjs-tools-button-label = Tools
+pdfjs-first-page-button =
+ .title = Go to First Page
+pdfjs-first-page-button-label = Go to First Page
+pdfjs-last-page-button =
+ .title = Go to Last Page
+pdfjs-last-page-button-label = Go to Last Page
+pdfjs-page-rotate-cw-button =
+ .title = Rotate Clockwise
+pdfjs-page-rotate-cw-button-label = Rotate Clockwise
+pdfjs-page-rotate-ccw-button =
+ .title = Rotate Counterclockwise
+pdfjs-page-rotate-ccw-button-label = Rotate Counterclockwise
+pdfjs-cursor-text-select-tool-button =
+ .title = Enable Text Selection Tool
+pdfjs-cursor-text-select-tool-button-label = Text Selection Tool
+pdfjs-cursor-hand-tool-button =
+ .title = Enable Hand Tool
+pdfjs-cursor-hand-tool-button-label = Hand Tool
+pdfjs-scroll-page-button =
+ .title = Use Page Scrolling
+pdfjs-scroll-page-button-label = Page Scrolling
+pdfjs-scroll-vertical-button =
+ .title = Use Vertical Scrolling
+pdfjs-scroll-vertical-button-label = Vertical Scrolling
+pdfjs-scroll-horizontal-button =
+ .title = Use Horizontal Scrolling
+pdfjs-scroll-horizontal-button-label = Horizontal Scrolling
+pdfjs-scroll-wrapped-button =
+ .title = Use Wrapped Scrolling
+pdfjs-scroll-wrapped-button-label = Wrapped Scrolling
+pdfjs-spread-none-button =
+ .title = Do not join page spreads
+pdfjs-spread-none-button-label = No Spreads
+pdfjs-spread-odd-button =
+ .title = Join page spreads starting with odd-numbered pages
+pdfjs-spread-odd-button-label = Odd Spreads
+pdfjs-spread-even-button =
+ .title = Join page spreads starting with even-numbered pages
+pdfjs-spread-even-button-label = Even Spreads
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Document Properties…
+pdfjs-document-properties-button-label = Document Properties…
+pdfjs-document-properties-file-name = File name:
+pdfjs-document-properties-file-size = File size:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Title:
+pdfjs-document-properties-author = Author:
+pdfjs-document-properties-subject = Subject:
+pdfjs-document-properties-keywords = Keywords:
+pdfjs-document-properties-creation-date = Creation Date:
+pdfjs-document-properties-modification-date = Modification Date:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creator:
+pdfjs-document-properties-producer = PDF Producer:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Page Count:
+pdfjs-document-properties-page-size = Page Size:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = landscape
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Yes
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Close
+pdfjs-digital-signature-properties-view-certificate = View certificate
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Reason: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Timestamp: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Sub-signature ({ $count })
+ *[other] Sub-signatures ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparing document for printing…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancel
+pdfjs-printing-not-supported = Warning: Printing is not fully supported by this browser.
+pdfjs-printing-not-ready = Warning: The PDF is not fully loaded for printing.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toggle Sidebar
+pdfjs-toggle-sidebar-notification-button =
+ .title = Toggle Sidebar (document contains outline/attachments/layers)
+pdfjs-toggle-sidebar-button-label = Toggle Sidebar
+pdfjs-document-outline-button =
+ .title = Show Document Outline (double-click to expand/collapse all items)
+pdfjs-document-outline-button-label = Document Outline
+pdfjs-attachments-button =
+ .title = Show Attachments
+pdfjs-attachments-button-label = Attachments
+pdfjs-layers-button =
+ .title = Show Layers (double-click to reset all layers to the default state)
+pdfjs-layers-button-label = Layers
+pdfjs-thumbs-button =
+ .title = Show Thumbnails
+pdfjs-thumbs-button-label = Thumbnails
+pdfjs-current-outline-item-button =
+ .title = Find Current Outline Item
+pdfjs-current-outline-item-button-label = Current Outline Item
+pdfjs-findbar-button =
+ .title = Find in Document
+pdfjs-findbar-button-label = Find
+pdfjs-additional-layers = Additional Layers
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail of Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Select page { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Page { $page } of { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Find
+ .placeholder = Find in document…
+pdfjs-find-previous-button =
+ .title = Find the previous occurrence of the phrase
+pdfjs-find-previous-button-label = Previous
+pdfjs-find-next-button =
+ .title = Find the next occurrence of the phrase
+pdfjs-find-next-button-label = Next
+pdfjs-find-highlight-checkbox = Highlight All
+pdfjs-find-match-case-checkbox-label = Match Case
+pdfjs-find-match-diacritics-checkbox-label = Match Diacritics
+pdfjs-find-entire-word-checkbox-label = Whole Words
+pdfjs-find-reached-top = Reached top of document, continued from bottom
+pdfjs-find-reached-bottom = Reached end of document, continued from top
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } of { $total } match
+ *[other] { $current } of { $total } matches
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] More than { $limit } match
+ *[other] More than { $limit } matches
+ }
+pdfjs-find-not-found = Phrase not found
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Page Width
+pdfjs-page-scale-fit = Page Fit
+pdfjs-page-scale-auto = Automatic Zoom
+pdfjs-page-scale-actual = Actual Size
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Page { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = An error occurred while loading the PDF.
+pdfjs-invalid-file-error = Invalid or corrupted PDF file.
+pdfjs-missing-file-error = Missing PDF file.
+pdfjs-unexpected-response-error = Unexpected server response.
+pdfjs-rendering-error = An error occurred while rendering the page.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Enter the password to open this PDF file.
+pdfjs-password-invalid = Invalid password. Please try again.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancel
+pdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Change text colour
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Draw
+pdfjs-editor-color-picker-ink-input =
+ .title = Change drawing colour
+pdfjs-editor-ink-button-label = Draw
+pdfjs-editor-stamp-button =
+ .title = Add or edit images
+pdfjs-editor-stamp-button-label = Add or edit images
+pdfjs-editor-highlight-button =
+ .title = Highlight
+pdfjs-editor-highlight-button-label = Highlight
+pdfjs-highlight-floating-button1 =
+ .title = Highlight
+ .aria-label = Highlight
+pdfjs-highlight-floating-button-label = Highlight
+pdfjs-comment-floating-button =
+ .title = Comment
+ .aria-label = Comment
+pdfjs-comment-floating-button-label = Comment
+pdfjs-editor-comment-button =
+ .title = Comment
+ .aria-label = Comment
+pdfjs-editor-comment-button-label = Comment
+pdfjs-editor-signature-button =
+ .title = Add signature
+pdfjs-editor-signature-button-label = Add signature
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Highlight editor
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Drawing editor
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signature editor: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Image editor
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Remove drawing
+pdfjs-editor-remove-freetext-button =
+ .title = Remove text
+pdfjs-editor-remove-stamp-button =
+ .title = Remove image
+pdfjs-editor-remove-highlight-button =
+ .title = Remove highlight
+pdfjs-editor-remove-signature-button =
+ .title = Remove signature
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Colour
+pdfjs-editor-free-text-size-input = Size
+pdfjs-editor-ink-color-input = Colour
+pdfjs-editor-ink-thickness-input = Thickness
+pdfjs-editor-ink-opacity-input = Opacity
+pdfjs-editor-stamp-add-image-button =
+ .title = Add image
+pdfjs-editor-stamp-add-image-button-label = Add image
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Thickness
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Change thickness when highlighting items other than text
+pdfjs-editor-add-signature-container =
+ .aria-label = Signature controls and saved signatures
+pdfjs-editor-signature-add-signature-button =
+ .title = Add new signature
+pdfjs-editor-signature-add-signature-button-label = Add new signature
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Saved signature: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Text Editor
+ .default-content = Start typing…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comment
+ *[other] Comments
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Close the sidebar
+ .aria-label = Close the sidebar
+pdfjs-editor-comments-sidebar-close-button-label = Close the sidebar
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = See something noteworthy? Highlight it and leave a comment.
+pdfjs-editor-comments-sidebar-no-comments-link = Learn more
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alt text
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Edit alt text
+pdfjs-editor-alt-text-dialog-label = Choose an option
+pdfjs-editor-alt-text-dialog-description = Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.
+pdfjs-editor-alt-text-add-description-label = Add a description
+pdfjs-editor-alt-text-add-description-description = Aim for 1-2 sentences that describe the subject, setting, or actions.
+pdfjs-editor-alt-text-mark-decorative-label = Mark as decorative
+pdfjs-editor-alt-text-mark-decorative-description = This is used for ornamental images, like borders or watermarks.
+pdfjs-editor-alt-text-cancel-button = Cancel
+pdfjs-editor-alt-text-save-button = Save
+pdfjs-editor-alt-text-decorative-tooltip = Marked as decorative
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = For example, “A young man sits down at a table to eat a meal”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alt text
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Top left corner — resize
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Top middle — resize
+pdfjs-editor-resizer-top-right =
+ .aria-label = Top right corner — resize
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Middle right — resize
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Bottom right corner — resize
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Bottom middle — resize
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Bottom left corner — resize
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Middle left — resize
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Highlight colour
+pdfjs-editor-colorpicker-button =
+ .title = Change colour
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Colour choices
+pdfjs-editor-colorpicker-yellow =
+ .title = Yellow
+pdfjs-editor-colorpicker-green =
+ .title = Green
+pdfjs-editor-colorpicker-blue =
+ .title = Blue
+pdfjs-editor-colorpicker-pink =
+ .title = Pink
+pdfjs-editor-colorpicker-red =
+ .title = Red
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Show all
+pdfjs-editor-highlight-show-all-button =
+ .title = Show all
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Edit alt text (image description)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Add alt text (image description)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Write your description here…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Short description for people who can’t see the image or when the image doesn’t load.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = This alt text was created automatically and may be inaccurate.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Learn more
+pdfjs-editor-new-alt-text-create-automatically-button-label = Create alt text automatically
+pdfjs-editor-new-alt-text-not-now-button = Not now
+pdfjs-editor-new-alt-text-error-title = Couldn’t create alt text automatically
+pdfjs-editor-new-alt-text-error-description = Please write your own alt text or try again later.
+pdfjs-editor-new-alt-text-error-close-button = Close
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
+ .aria-valuetext = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alt text added
+pdfjs-editor-new-alt-text-added-button-label = Alt text added
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Missing alt text
+pdfjs-editor-new-alt-text-missing-button-label = Missing alt text
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Review alt text
+pdfjs-editor-new-alt-text-to-review-button-label = Review alt text
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Created automatically: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Image alt text settings
+pdfjs-image-alt-text-settings-button-label = Image alt text settings
+pdfjs-editor-alt-text-settings-dialog-label = Image alt text settings
+pdfjs-editor-alt-text-settings-automatic-title = Automatic alt text
+pdfjs-editor-alt-text-settings-create-model-button-label = Create alt text automatically
+pdfjs-editor-alt-text-settings-create-model-description = Suggests descriptions to help people who can’t see the image or when the image doesn’t load.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alt text AI model ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Runs locally on your device so your data stays private. Required for automatic alt text.
+pdfjs-editor-alt-text-settings-delete-model-button = Delete
+pdfjs-editor-alt-text-settings-download-model-button = Download
+pdfjs-editor-alt-text-settings-downloading-model-button = Downloading…
+pdfjs-editor-alt-text-settings-editor-title = Alt text editor
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image
+pdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.
+pdfjs-editor-alt-text-settings-close-button = Close
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Highlight added
+pdfjs-editor-freetext-added-alert = Text added
+pdfjs-editor-ink-added-alert = Drawing added
+pdfjs-editor-stamp-added-alert = Image added
+pdfjs-editor-signature-added-alert = Signature added
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Highlight removed
+pdfjs-editor-undo-bar-message-freetext = Text removed
+pdfjs-editor-undo-bar-message-ink = Drawing removed
+pdfjs-editor-undo-bar-message-stamp = Image removed
+pdfjs-editor-undo-bar-message-signature = Signature removed
+pdfjs-editor-undo-bar-message-comment = Comment removed
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotation removed
+ *[other] { $count } annotations removed
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Undo
+pdfjs-editor-undo-bar-undo-button-label = Undo
+pdfjs-editor-undo-bar-close-button =
+ .title = Close
+pdfjs-editor-undo-bar-close-button-label = Close
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use.
+pdfjs-editor-add-signature-dialog-title = Add a signature
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Type
+ .title = Type
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Draw
+ .title = Draw
+pdfjs-editor-add-signature-image-button = Image
+ .title = Image
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Type your signature
+ .placeholder = Type your signature
+pdfjs-editor-add-signature-draw-placeholder = Draw your signature
+pdfjs-editor-add-signature-draw-thickness-range-label = Thickness
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Drawing thickness: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Drag a file here to upload
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Or choose image files
+ *[other] Or browse image files
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Description (alt text)
+pdfjs-editor-add-signature-description-input =
+ .title = Description (alt text)
+pdfjs-editor-add-signature-description-default-when-drawing = Signature
+pdfjs-editor-add-signature-clear-button-label = Clear signature
+pdfjs-editor-add-signature-clear-button =
+ .title = Clear signature
+pdfjs-editor-add-signature-save-checkbox = Save signature
+pdfjs-editor-add-signature-save-warning-message = You’ve reached the limit of 5 saved signatures. Remove one to save more.
+pdfjs-editor-add-signature-image-upload-error-title = Couldn’t upload image
+pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.
+pdfjs-editor-add-signature-image-no-data-error-title = Can’t convert this image into a signature
+pdfjs-editor-add-signature-image-no-data-error-description = Please try uploading a different image.
+pdfjs-editor-add-signature-error-close-button = Close
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancel
+pdfjs-editor-add-signature-add-button = Add
+pdfjs-editor-edit-signature-update-button = Update
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Edit comment
+pdfjs-editor-edit-comment-popup-button =
+ .title = Edit comment
+pdfjs-editor-delete-comment-popup-button-label = Remove comment
+pdfjs-editor-delete-comment-popup-button =
+ .title = Remove comment
+pdfjs-show-comment-button =
+ .title = Show comment
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Edit comment
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Update
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Add comment
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Add
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Start typing…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancel
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Add comment
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Toggle Sidebar (document contains thumbnails/outline/attachments/layers)
+pdfjs-toggle-views-manager-button1-label = Manage pages
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidebar
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Sidebar resizer
+pdfjs-views-manager-view-selector-button =
+ .title = Views
+pdfjs-views-manager-view-selector-button-label = Views
+pdfjs-views-manager-pages-title = Pages
+pdfjs-views-manager-outlines-title1 = Document outline
+ .title = Document outline (double-click to expand/collapse all items)
+pdfjs-views-manager-attachments-title = Attachments
+pdfjs-views-manager-layers-title1 = Layers
+ .title = Layers (double-click to reset all layers to the default state)
+pdfjs-views-manager-pages-option-label = Pages
+pdfjs-views-manager-outlines-option-label = Document outline
+pdfjs-views-manager-attachments-option-label = Attachments
+pdfjs-views-manager-layers-option-label = Layers
+pdfjs-views-manager-add-file-button =
+ .title = Add file
+pdfjs-views-manager-add-file-button-label = Add file
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selected
+ *[other] { $count } selected
+ }
+pdfjs-views-manager-pages-status-none-action-label = Select pages
+pdfjs-views-manager-pages-status-action-button-label = Manage
+pdfjs-views-manager-pages-status-copy-button-label = Copy
+pdfjs-views-manager-pages-status-cut-button-label = Cut
+pdfjs-views-manager-pages-status-delete-button-label = Delete
+pdfjs-views-manager-pages-status-export-selected-button-label = Export selected…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 page cut
+ *[other] { $count } pages cut
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 page copied
+ *[other] { $count } pages copied
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 page deleted
+ *[other] { $count } pages deleted
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Getting your file ready…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Uploading file…
+pdfjs-views-manager-status-warning-cut-label = Couldn’t cut. Refresh page and try again.
+pdfjs-views-manager-status-warning-copy-label = Couldn’t copy. Refresh page and try again.
+pdfjs-views-manager-status-warning-delete-label = Couldn’t delete. Refresh page and try again.
+pdfjs-views-manager-status-warning-save-label = Couldn’t save. Refresh page and try again.
+pdfjs-views-manager-status-undo-button-label = Undo
+pdfjs-views-manager-status-done-button-label = Done
+pdfjs-views-manager-status-close-button =
+ .title = Close
+pdfjs-views-manager-status-close-button-label = Close
+pdfjs-views-manager-paste-button-label = Paste
+pdfjs-views-manager-paste-button-before =
+ .title = Paste before the first page
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Paste after page { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NEW
+pdfjs-views-manager-waiting-for-file = Uploading file…
+pdfjs-toggle-views-manager-button1 =
+ .title = Manage pages
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Digital signature properties
+ .aria-label = Digital signature properties
+pdfjs-digital-signature-properties-button-label = Digital signature properties
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Document was signed with a valid digital signature
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Document signed but { $count } digital signature could not be verified
+ *[other] Document signed but { $count } digital signatures could not be verified
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Document signed with { $count } certificate that is not trusted
+ *[other] Document signed with { $count } certificates that are not trusted
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Document signed with { $count } expired certificate
+ *[other] Document signed with { $count } expired certificates
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Document has { $count } invalid digital signature
+ *[other] Document has { $count } invalid digital signatures
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Document signed with { $count } revoked certificate
+ *[other] Document signed with { $count } revoked certificates
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signature verified
+pdfjs-digital-signature-properties-status-invalid = Status: Signature invalid
+pdfjs-digital-signature-properties-status-unknown = Status: Unable to verify (unsupported)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificate: Trusted ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificate: Unavailable
+pdfjs-digital-signature-properties-certificate-untrusted = Certificate: Untrusted
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificate: Unknown issuer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificate: Self-signed ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificate: Untrusted issuer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificate: Expired
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificate: Expired ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificate: Revoked
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Remove saved signature
+pdfjs-editor-delete-signature-button-label1 = Remove saved signature
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Edit description
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Edit description
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-GB/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-GB/viewer.ftl
new file mode 100644
index 0000000..c5287a1
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-GB/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Previous Page
+pdfjs-previous-button-label = Previous
+pdfjs-next-button =
+ .title = Next Page
+pdfjs-next-button-label = Next
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Page
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = of { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom Out
+pdfjs-zoom-out-button-label = Zoom Out
+pdfjs-zoom-in-button =
+ .title = Zoom In
+pdfjs-zoom-in-button-label = Zoom In
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Switch to Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Open File
+pdfjs-open-file-button-label = Open
+pdfjs-print-button =
+ .title = Print
+pdfjs-print-button-label = Print
+pdfjs-save-button =
+ .title = Save
+pdfjs-save-button-label = Save
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Download
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Download
+pdfjs-bookmark-button =
+ .title = Current Page (View URL from Current Page)
+pdfjs-bookmark-button-label = Current Page
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tools
+pdfjs-tools-button-label = Tools
+pdfjs-first-page-button =
+ .title = Go to First Page
+pdfjs-first-page-button-label = Go to First Page
+pdfjs-last-page-button =
+ .title = Go to Last Page
+pdfjs-last-page-button-label = Go to Last Page
+pdfjs-page-rotate-cw-button =
+ .title = Rotate Clockwise
+pdfjs-page-rotate-cw-button-label = Rotate Clockwise
+pdfjs-page-rotate-ccw-button =
+ .title = Rotate Anti-Clockwise
+pdfjs-page-rotate-ccw-button-label = Rotate Anti-Clockwise
+pdfjs-cursor-text-select-tool-button =
+ .title = Enable Text Selection Tool
+pdfjs-cursor-text-select-tool-button-label = Text Selection Tool
+pdfjs-cursor-hand-tool-button =
+ .title = Enable Hand Tool
+pdfjs-cursor-hand-tool-button-label = Hand Tool
+pdfjs-scroll-page-button =
+ .title = Use Page Scrolling
+pdfjs-scroll-page-button-label = Page Scrolling
+pdfjs-scroll-vertical-button =
+ .title = Use Vertical Scrolling
+pdfjs-scroll-vertical-button-label = Vertical Scrolling
+pdfjs-scroll-horizontal-button =
+ .title = Use Horizontal Scrolling
+pdfjs-scroll-horizontal-button-label = Horizontal Scrolling
+pdfjs-scroll-wrapped-button =
+ .title = Use Wrapped Scrolling
+pdfjs-scroll-wrapped-button-label = Wrapped Scrolling
+pdfjs-spread-none-button =
+ .title = Do not join page spreads
+pdfjs-spread-none-button-label = No Spreads
+pdfjs-spread-odd-button =
+ .title = Join page spreads starting with odd-numbered pages
+pdfjs-spread-odd-button-label = Odd Spreads
+pdfjs-spread-even-button =
+ .title = Join page spreads starting with even-numbered pages
+pdfjs-spread-even-button-label = Even Spreads
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Document Properties…
+pdfjs-document-properties-button-label = Document Properties…
+pdfjs-document-properties-file-name = File name:
+pdfjs-document-properties-file-size = File size:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Title:
+pdfjs-document-properties-author = Author:
+pdfjs-document-properties-subject = Subject:
+pdfjs-document-properties-keywords = Keywords:
+pdfjs-document-properties-creation-date = Creation Date:
+pdfjs-document-properties-modification-date = Modification Date:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creator:
+pdfjs-document-properties-producer = PDF Producer:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Page Count:
+pdfjs-document-properties-page-size = Page Size:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = landscape
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Yes
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Close
+pdfjs-digital-signature-properties-view-certificate = View certificate
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Reason: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Timestamp: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Sub-signature ({ $count })
+ *[other] Sub-signatures ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparing document for printing…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancel
+pdfjs-printing-not-supported = Warning: Printing is not fully supported by this browser.
+pdfjs-printing-not-ready = Warning: The PDF is not fully loaded for printing.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toggle Sidebar
+pdfjs-toggle-sidebar-notification-button =
+ .title = Toggle Sidebar (document contains outline/attachments/layers)
+pdfjs-toggle-sidebar-button-label = Toggle Sidebar
+pdfjs-document-outline-button =
+ .title = Show Document Outline (double-click to expand/collapse all items)
+pdfjs-document-outline-button-label = Document Outline
+pdfjs-attachments-button =
+ .title = Show Attachments
+pdfjs-attachments-button-label = Attachments
+pdfjs-layers-button =
+ .title = Show Layers (double-click to reset all layers to the default state)
+pdfjs-layers-button-label = Layers
+pdfjs-thumbs-button =
+ .title = Show Thumbnails
+pdfjs-thumbs-button-label = Thumbnails
+pdfjs-current-outline-item-button =
+ .title = Find Current Outline Item
+pdfjs-current-outline-item-button-label = Current Outline Item
+pdfjs-findbar-button =
+ .title = Find in Document
+pdfjs-findbar-button-label = Find
+pdfjs-additional-layers = Additional Layers
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail of Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Select page { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Page { $page } of { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Find
+ .placeholder = Find in document…
+pdfjs-find-previous-button =
+ .title = Find the previous occurrence of the phrase
+pdfjs-find-previous-button-label = Previous
+pdfjs-find-next-button =
+ .title = Find the next occurrence of the phrase
+pdfjs-find-next-button-label = Next
+pdfjs-find-highlight-checkbox = Highlight All
+pdfjs-find-match-case-checkbox-label = Match Case
+pdfjs-find-match-diacritics-checkbox-label = Match Diacritics
+pdfjs-find-entire-word-checkbox-label = Whole Words
+pdfjs-find-reached-top = Reached top of document, continued from bottom
+pdfjs-find-reached-bottom = Reached end of document, continued from top
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } of { $total } match
+ *[other] { $current } of { $total } matches
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] More than { $limit } match
+ *[other] More than { $limit } matches
+ }
+pdfjs-find-not-found = Phrase not found
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Page Width
+pdfjs-page-scale-fit = Page Fit
+pdfjs-page-scale-auto = Automatic Zoom
+pdfjs-page-scale-actual = Actual Size
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Page { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = An error occurred while loading the PDF.
+pdfjs-invalid-file-error = Invalid or corrupted PDF file.
+pdfjs-missing-file-error = Missing PDF file.
+pdfjs-unexpected-response-error = Unexpected server response.
+pdfjs-rendering-error = An error occurred while rendering the page.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Enter the password to open this PDF file.
+pdfjs-password-invalid = Invalid password. Please try again.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancel
+pdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Change text colour
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Draw
+pdfjs-editor-color-picker-ink-input =
+ .title = Change drawing colour
+pdfjs-editor-ink-button-label = Draw
+pdfjs-editor-stamp-button =
+ .title = Add or edit images
+pdfjs-editor-stamp-button-label = Add or edit images
+pdfjs-editor-highlight-button =
+ .title = Highlight
+pdfjs-editor-highlight-button-label = Highlight
+pdfjs-highlight-floating-button1 =
+ .title = Highlight
+ .aria-label = Highlight
+pdfjs-highlight-floating-button-label = Highlight
+pdfjs-comment-floating-button =
+ .title = Comment
+ .aria-label = Comment
+pdfjs-comment-floating-button-label = Comment
+pdfjs-editor-comment-button =
+ .title = Comment
+ .aria-label = Comment
+pdfjs-editor-comment-button-label = Comment
+pdfjs-editor-signature-button =
+ .title = Add signature
+pdfjs-editor-signature-button-label = Add signature
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Highlight editor
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Drawing editor
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signature editor: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Image editor
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Remove drawing
+pdfjs-editor-remove-freetext-button =
+ .title = Remove text
+pdfjs-editor-remove-stamp-button =
+ .title = Remove image
+pdfjs-editor-remove-highlight-button =
+ .title = Remove highlight
+pdfjs-editor-remove-signature-button =
+ .title = Remove signature
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Colour
+pdfjs-editor-free-text-size-input = Size
+pdfjs-editor-ink-color-input = Colour
+pdfjs-editor-ink-thickness-input = Thickness
+pdfjs-editor-ink-opacity-input = Opacity
+pdfjs-editor-stamp-add-image-button =
+ .title = Add image
+pdfjs-editor-stamp-add-image-button-label = Add image
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Thickness
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Change thickness when highlighting items other than text
+pdfjs-editor-add-signature-container =
+ .aria-label = Signature controls and saved signatures
+pdfjs-editor-signature-add-signature-button =
+ .title = Add new signature
+pdfjs-editor-signature-add-signature-button-label = Add new signature
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Saved signature: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Text Editor
+ .default-content = Start typing…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comment
+ *[other] Comments
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Close the sidebar
+ .aria-label = Close the sidebar
+pdfjs-editor-comments-sidebar-close-button-label = Close the sidebar
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = See something noteworthy? Highlight it and leave a comment.
+pdfjs-editor-comments-sidebar-no-comments-link = Learn more
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alt text
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Edit alt text
+pdfjs-editor-alt-text-dialog-label = Choose an option
+pdfjs-editor-alt-text-dialog-description = Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.
+pdfjs-editor-alt-text-add-description-label = Add a description
+pdfjs-editor-alt-text-add-description-description = Aim for 1-2 sentences that describe the subject, setting, or actions.
+pdfjs-editor-alt-text-mark-decorative-label = Mark as decorative
+pdfjs-editor-alt-text-mark-decorative-description = This is used for ornamental images, like borders or watermarks.
+pdfjs-editor-alt-text-cancel-button = Cancel
+pdfjs-editor-alt-text-save-button = Save
+pdfjs-editor-alt-text-decorative-tooltip = Marked as decorative
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = For example, “A young man sits down at a table to eat a meal”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alt text
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Top left corner — resize
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Top middle — resize
+pdfjs-editor-resizer-top-right =
+ .aria-label = Top right corner — resize
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Middle right — resize
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Bottom right corner — resize
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Bottom middle — resize
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Bottom left corner — resize
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Middle left — resize
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Highlight colour
+pdfjs-editor-colorpicker-button =
+ .title = Change colour
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Colour choices
+pdfjs-editor-colorpicker-yellow =
+ .title = Yellow
+pdfjs-editor-colorpicker-green =
+ .title = Green
+pdfjs-editor-colorpicker-blue =
+ .title = Blue
+pdfjs-editor-colorpicker-pink =
+ .title = Pink
+pdfjs-editor-colorpicker-red =
+ .title = Red
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Show all
+pdfjs-editor-highlight-show-all-button =
+ .title = Show all
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Edit alt text (image description)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Add alt text (image description)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Write your description here…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Short description for people who can’t see the image or when the image doesn’t load.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = This alt text was created automatically and may be inaccurate.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Learn more
+pdfjs-editor-new-alt-text-create-automatically-button-label = Create alt text automatically
+pdfjs-editor-new-alt-text-not-now-button = Not now
+pdfjs-editor-new-alt-text-error-title = Couldn’t create alt text automatically
+pdfjs-editor-new-alt-text-error-description = Please write your own alt text or try again later.
+pdfjs-editor-new-alt-text-error-close-button = Close
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
+ .aria-valuetext = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alt text added
+pdfjs-editor-new-alt-text-added-button-label = Alt text added
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Missing alt text
+pdfjs-editor-new-alt-text-missing-button-label = Missing alt text
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Review alt text
+pdfjs-editor-new-alt-text-to-review-button-label = Review alt text
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Created automatically: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Image alt text settings
+pdfjs-image-alt-text-settings-button-label = Image alt text settings
+pdfjs-editor-alt-text-settings-dialog-label = Image alt text settings
+pdfjs-editor-alt-text-settings-automatic-title = Automatic alt text
+pdfjs-editor-alt-text-settings-create-model-button-label = Create alt text automatically
+pdfjs-editor-alt-text-settings-create-model-description = Suggests descriptions to help people who can’t see the image or when the image doesn’t load.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alt text AI model ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Runs locally on your device so your data stays private. Required for automatic alt text.
+pdfjs-editor-alt-text-settings-delete-model-button = Delete
+pdfjs-editor-alt-text-settings-download-model-button = Download
+pdfjs-editor-alt-text-settings-downloading-model-button = Downloading…
+pdfjs-editor-alt-text-settings-editor-title = Alt text editor
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image
+pdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.
+pdfjs-editor-alt-text-settings-close-button = Close
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Highlight added
+pdfjs-editor-freetext-added-alert = Text added
+pdfjs-editor-ink-added-alert = Drawing added
+pdfjs-editor-stamp-added-alert = Image added
+pdfjs-editor-signature-added-alert = Signature added
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Highlight removed
+pdfjs-editor-undo-bar-message-freetext = Text removed
+pdfjs-editor-undo-bar-message-ink = Drawing removed
+pdfjs-editor-undo-bar-message-stamp = Image removed
+pdfjs-editor-undo-bar-message-signature = Signature removed
+pdfjs-editor-undo-bar-message-comment = Comment removed
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotation removed
+ *[other] { $count } annotations removed
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Undo
+pdfjs-editor-undo-bar-undo-button-label = Undo
+pdfjs-editor-undo-bar-close-button =
+ .title = Close
+pdfjs-editor-undo-bar-close-button-label = Close
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use.
+pdfjs-editor-add-signature-dialog-title = Add a signature
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Type
+ .title = Type
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Draw
+ .title = Draw
+pdfjs-editor-add-signature-image-button = Image
+ .title = Image
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Type your signature
+ .placeholder = Type your signature
+pdfjs-editor-add-signature-draw-placeholder = Draw your signature
+pdfjs-editor-add-signature-draw-thickness-range-label = Thickness
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Drawing thickness: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Drag a file here to upload
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Or choose image files
+ *[other] Or browse image files
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Description (alt text)
+pdfjs-editor-add-signature-description-input =
+ .title = Description (alt text)
+pdfjs-editor-add-signature-description-default-when-drawing = Signature
+pdfjs-editor-add-signature-clear-button-label = Clear signature
+pdfjs-editor-add-signature-clear-button =
+ .title = Clear signature
+pdfjs-editor-add-signature-save-checkbox = Save signature
+pdfjs-editor-add-signature-save-warning-message = You’ve reached the limit of 5 saved signatures. Remove one to save more.
+pdfjs-editor-add-signature-image-upload-error-title = Couldn’t upload image
+pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.
+pdfjs-editor-add-signature-image-no-data-error-title = Can’t convert this image into a signature
+pdfjs-editor-add-signature-image-no-data-error-description = Please try uploading a different image.
+pdfjs-editor-add-signature-error-close-button = Close
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancel
+pdfjs-editor-add-signature-add-button = Add
+pdfjs-editor-edit-signature-update-button = Update
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Edit comment
+pdfjs-editor-edit-comment-popup-button =
+ .title = Edit comment
+pdfjs-editor-delete-comment-popup-button-label = Remove comment
+pdfjs-editor-delete-comment-popup-button =
+ .title = Remove comment
+pdfjs-show-comment-button =
+ .title = Show comment
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Edit comment
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Update
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Add comment
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Add
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Start typing…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancel
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Add comment
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Toggle Sidebar (document contains thumbnails/outline/attachments/layers)
+pdfjs-toggle-views-manager-button1-label = Manage pages
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidebar
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Sidebar resizer
+pdfjs-views-manager-view-selector-button =
+ .title = Views
+pdfjs-views-manager-view-selector-button-label = Views
+pdfjs-views-manager-pages-title = Pages
+pdfjs-views-manager-outlines-title1 = Document outline
+ .title = Document outline (double-click to expand/collapse all items)
+pdfjs-views-manager-attachments-title = Attachments
+pdfjs-views-manager-layers-title1 = Layers
+ .title = Layers (double-click to reset all layers to the default state)
+pdfjs-views-manager-pages-option-label = Pages
+pdfjs-views-manager-outlines-option-label = Document outline
+pdfjs-views-manager-attachments-option-label = Attachments
+pdfjs-views-manager-layers-option-label = Layers
+pdfjs-views-manager-add-file-button =
+ .title = Add file
+pdfjs-views-manager-add-file-button-label = Add file
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selected
+ *[other] { $count } selected
+ }
+pdfjs-views-manager-pages-status-none-action-label = Select pages
+pdfjs-views-manager-pages-status-action-button-label = Manage
+pdfjs-views-manager-pages-status-copy-button-label = Copy
+pdfjs-views-manager-pages-status-cut-button-label = Cut
+pdfjs-views-manager-pages-status-delete-button-label = Delete
+pdfjs-views-manager-pages-status-export-selected-button-label = Export selected…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 page cut
+ *[other] { $count } pages cut
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 page copied
+ *[other] { $count } pages copied
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 page deleted
+ *[other] { $count } pages deleted
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Getting your file ready…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Uploading file…
+pdfjs-views-manager-status-warning-cut-label = Couldn’t cut. Refresh page and try again.
+pdfjs-views-manager-status-warning-copy-label = Couldn’t copy. Refresh page and try again.
+pdfjs-views-manager-status-warning-delete-label = Couldn’t delete. Refresh page and try again.
+pdfjs-views-manager-status-warning-save-label = Couldn’t save. Refresh page and try again.
+pdfjs-views-manager-status-undo-button-label = Undo
+pdfjs-views-manager-status-done-button-label = Done
+pdfjs-views-manager-status-close-button =
+ .title = Close
+pdfjs-views-manager-status-close-button-label = Close
+pdfjs-views-manager-paste-button-label = Paste
+pdfjs-views-manager-paste-button-before =
+ .title = Paste before the first page
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Paste after page { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NEW
+pdfjs-views-manager-waiting-for-file = Uploading file…
+pdfjs-toggle-views-manager-button1 =
+ .title = Manage pages
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Digital signature properties
+ .aria-label = Digital signature properties
+pdfjs-digital-signature-properties-button-label = Digital signature properties
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Document was signed with a valid digital signature
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Document signed but { $count } digital signature could not be verified
+ *[other] Document signed but { $count } digital signatures could not be verified
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Document signed with { $count } certificate that is not trusted
+ *[other] Document signed with { $count } certificates that are not trusted
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Document signed with { $count } expired certificate
+ *[other] Document signed with { $count } expired certificates
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Document has { $count } invalid digital signature
+ *[other] Document has { $count } invalid digital signatures
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Document signed with { $count } revoked certificate
+ *[other] Document signed with { $count } revoked certificates
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signature verified
+pdfjs-digital-signature-properties-status-invalid = Status: Signature invalid
+pdfjs-digital-signature-properties-status-unknown = Status: Unable to verify (unsupported)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificate: Trusted ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificate: Unavailable
+pdfjs-digital-signature-properties-certificate-untrusted = Certificate: Untrusted
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificate: Unknown issuer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificate: Self-signed ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificate: Untrusted issuer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificate: Expired
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificate: Expired ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificate: Revoked
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Remove saved signature
+pdfjs-editor-delete-signature-button-label1 = Remove saved signature
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Edit description
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Edit description
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-US/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-US/viewer.ftl
new file mode 100644
index 0000000..1d0e9ed
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/en-US/viewer.ftl
@@ -0,0 +1,873 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Previous Page
+pdfjs-previous-button-label = Previous
+pdfjs-next-button =
+ .title = Next Page
+pdfjs-next-button-label = Next
+
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Page
+
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = of { $pagesCount }
+
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+
+pdfjs-zoom-out-button =
+ .title = Zoom Out
+pdfjs-zoom-out-button-label = Zoom Out
+pdfjs-zoom-in-button =
+ .title = Zoom In
+pdfjs-zoom-in-button-label = Zoom In
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Switch to Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Open File
+pdfjs-open-file-button-label = Open
+pdfjs-print-button =
+ .title = Print
+pdfjs-print-button-label = Print
+pdfjs-save-button =
+ .title = Save
+pdfjs-save-button-label = Save
+
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Download
+
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Download
+
+pdfjs-bookmark-button =
+ .title = Current Page (View URL from Current Page)
+pdfjs-bookmark-button-label = Current Page
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tools
+
+pdfjs-tools-button-label = Tools
+pdfjs-first-page-button =
+ .title = Go to First Page
+pdfjs-first-page-button-label = Go to First Page
+pdfjs-last-page-button =
+ .title = Go to Last Page
+pdfjs-last-page-button-label = Go to Last Page
+pdfjs-page-rotate-cw-button =
+ .title = Rotate Clockwise
+pdfjs-page-rotate-cw-button-label = Rotate Clockwise
+pdfjs-page-rotate-ccw-button =
+ .title = Rotate Counterclockwise
+pdfjs-page-rotate-ccw-button-label = Rotate Counterclockwise
+pdfjs-cursor-text-select-tool-button =
+ .title = Enable Text Selection Tool
+pdfjs-cursor-text-select-tool-button-label = Text Selection Tool
+pdfjs-cursor-hand-tool-button =
+ .title = Enable Hand Tool
+pdfjs-cursor-hand-tool-button-label = Hand Tool
+pdfjs-scroll-page-button =
+ .title = Use Page Scrolling
+pdfjs-scroll-page-button-label = Page Scrolling
+pdfjs-scroll-vertical-button =
+ .title = Use Vertical Scrolling
+pdfjs-scroll-vertical-button-label = Vertical Scrolling
+pdfjs-scroll-horizontal-button =
+ .title = Use Horizontal Scrolling
+pdfjs-scroll-horizontal-button-label = Horizontal Scrolling
+pdfjs-scroll-wrapped-button =
+ .title = Use Wrapped Scrolling
+pdfjs-scroll-wrapped-button-label = Wrapped Scrolling
+pdfjs-spread-none-button =
+ .title = Do not join page spreads
+pdfjs-spread-none-button-label = No Spreads
+pdfjs-spread-odd-button =
+ .title = Join page spreads starting with odd-numbered pages
+pdfjs-spread-odd-button-label = Odd Spreads
+pdfjs-spread-even-button =
+ .title = Join page spreads starting with even-numbered pages
+pdfjs-spread-even-button-label = Even Spreads
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Document Properties…
+pdfjs-document-properties-button-label = Document Properties…
+pdfjs-document-properties-file-name = File name:
+pdfjs-document-properties-file-size = File size:
+
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+
+pdfjs-document-properties-title = Title:
+pdfjs-document-properties-author = Author:
+pdfjs-document-properties-subject = Subject:
+pdfjs-document-properties-keywords = Keywords:
+pdfjs-document-properties-creation-date = Creation Date:
+pdfjs-document-properties-modification-date = Modification Date:
+
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+pdfjs-document-properties-creator = Creator:
+pdfjs-document-properties-producer = PDF Producer:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Page Count:
+pdfjs-document-properties-page-size = Page Size:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = landscape
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Yes
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Close
+
+## Print
+
+pdfjs-print-progress-message = Preparing document for printing…
+
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+
+pdfjs-print-progress-close-button = Cancel
+pdfjs-printing-not-supported = Warning: Printing is not fully supported by this browser.
+pdfjs-printing-not-ready = Warning: The PDF is not fully loaded for printing.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-current-outline-item-button =
+ .title = Find Current Outline Item
+pdfjs-current-outline-item-button-label = Current Outline Item
+pdfjs-findbar-button =
+ .title = Find in Document
+pdfjs-findbar-button-label = Find
+pdfjs-additional-layers = Additional Layers
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Page { $page } of { $total }
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail of Page { $page }
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Select page { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Find
+ .placeholder = Find in document…
+pdfjs-find-previous-button =
+ .title = Find the previous occurrence of the phrase
+pdfjs-find-previous-button-label = Previous
+pdfjs-find-next-button =
+ .title = Find the next occurrence of the phrase
+pdfjs-find-next-button-label = Next
+pdfjs-find-highlight-checkbox = Highlight All
+pdfjs-find-match-case-checkbox-label = Match Case
+pdfjs-find-match-diacritics-checkbox-label = Match Diacritics
+pdfjs-find-entire-word-checkbox-label = Whole Words
+pdfjs-find-reached-top = Reached top of document, continued from bottom
+pdfjs-find-reached-bottom = Reached end of document, continued from top
+
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } of { $total } match
+ *[other] { $current } of { $total } matches
+ }
+
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] More than { $limit } match
+ *[other] More than { $limit } matches
+ }
+
+pdfjs-find-not-found = Phrase not found
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Page Width
+pdfjs-page-scale-fit = Page Fit
+pdfjs-page-scale-auto = Automatic Zoom
+pdfjs-page-scale-actual = Actual Size
+
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Page { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = An error occurred while loading the PDF.
+pdfjs-invalid-file-error = Invalid or corrupted PDF file.
+pdfjs-missing-file-error = Missing PDF file.
+pdfjs-unexpected-response-error = Unexpected server response.
+pdfjs-rendering-error = An error occurred while rendering the page.
+
+## Annotations
+
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = Enter the password to open this PDF file.
+pdfjs-password-invalid = Invalid password. Please try again.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancel
+pdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Change text color
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Draw
+pdfjs-editor-color-picker-ink-input =
+ .title = Change drawing color
+pdfjs-editor-ink-button-label = Draw
+pdfjs-editor-stamp-button =
+ .title = Add or edit images
+pdfjs-editor-stamp-button-label = Add or edit images
+pdfjs-editor-highlight-button =
+ .title = Highlight
+pdfjs-editor-highlight-button-label = Highlight
+pdfjs-highlight-floating-button1 =
+ .title = Highlight
+ .aria-label = Highlight
+pdfjs-highlight-floating-button-label = Highlight
+pdfjs-comment-floating-button =
+ .title = Comment
+ .aria-label = Comment
+pdfjs-comment-floating-button-label = Comment
+pdfjs-editor-comment-button =
+ .title = Comment
+ .aria-label = Comment
+pdfjs-editor-comment-button-label = Comment
+pdfjs-editor-signature-button =
+ .title = Add signature
+pdfjs-editor-signature-button-label = Add signature
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Highlight editor
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Drawing editor
+
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signature editor: { $description }
+
+pdfjs-editor-stamp-editor =
+ .aria-label = Image editor
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Remove drawing
+pdfjs-editor-remove-freetext-button =
+ .title = Remove text
+pdfjs-editor-remove-stamp-button =
+ .title = Remove image
+pdfjs-editor-remove-highlight-button =
+ .title = Remove highlight
+pdfjs-editor-remove-signature-button =
+ .title = Remove signature
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Size
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Thickness
+pdfjs-editor-ink-opacity-input = Opacity
+pdfjs-editor-stamp-add-image-button =
+ .title = Add image
+pdfjs-editor-stamp-add-image-button-label = Add image
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Thickness
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Change thickness when highlighting items other than text
+pdfjs-editor-add-signature-container =
+ .aria-label = Signature controls and saved signatures
+pdfjs-editor-signature-add-signature-button =
+ .title = Add new signature
+pdfjs-editor-signature-add-signature-button-label = Add new signature
+
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Saved signature: { $description }
+
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Text Editor
+ .default-content = Start typing…
+
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comment
+ *[other] Comments
+ }
+
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Close the sidebar
+ .aria-label = Close the sidebar
+pdfjs-editor-comments-sidebar-close-button-label = Close the sidebar
+
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = See something noteworthy? Highlight it and leave a comment.
+pdfjs-editor-comments-sidebar-no-comments-link = Learn more
+
+## Alt-text dialog
+
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alt text
+pdfjs-editor-alt-text-button-label = Alt text
+
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Edit alt text
+pdfjs-editor-alt-text-dialog-label = Choose an option
+pdfjs-editor-alt-text-dialog-description = Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.
+pdfjs-editor-alt-text-add-description-label = Add a description
+pdfjs-editor-alt-text-add-description-description = Aim for 1-2 sentences that describe the subject, setting, or actions.
+pdfjs-editor-alt-text-mark-decorative-label = Mark as decorative
+pdfjs-editor-alt-text-mark-decorative-description = This is used for ornamental images, like borders or watermarks.
+pdfjs-editor-alt-text-cancel-button = Cancel
+pdfjs-editor-alt-text-save-button = Save
+pdfjs-editor-alt-text-decorative-tooltip = Marked as decorative
+
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = For example, “A young man sits down at a table to eat a meal”
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Top left corner — resize
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Top middle — resize
+pdfjs-editor-resizer-top-right =
+ .aria-label = Top right corner — resize
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Middle right — resize
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Bottom right corner — resize
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Bottom middle — resize
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Bottom left corner — resize
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Middle left — resize
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Highlight color
+
+pdfjs-editor-colorpicker-button =
+ .title = Change color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Color choices
+pdfjs-editor-colorpicker-yellow =
+ .title = Yellow
+pdfjs-editor-colorpicker-green =
+ .title = Green
+pdfjs-editor-colorpicker-blue =
+ .title = Blue
+pdfjs-editor-colorpicker-pink =
+ .title = Pink
+pdfjs-editor-colorpicker-red =
+ .title = Red
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Show all
+pdfjs-editor-highlight-show-all-button =
+ .title = Show all
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Edit alt text (image description)
+
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Add alt text (image description)
+
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Write your description here…
+
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Short description for people who can’t see the image or when the image doesn’t load.
+
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = This alt text was created automatically and may be inaccurate.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Learn more
+
+pdfjs-editor-new-alt-text-create-automatically-button-label = Create alt text automatically
+pdfjs-editor-new-alt-text-not-now-button = Not now
+pdfjs-editor-new-alt-text-error-title = Couldn’t create alt text automatically
+pdfjs-editor-new-alt-text-error-description = Please write your own alt text or try again later.
+pdfjs-editor-new-alt-text-error-close-button = Close
+
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
+ .aria-valuetext = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)
+
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alt text added
+pdfjs-editor-new-alt-text-added-button-label = Alt text added
+
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Missing alt text
+pdfjs-editor-new-alt-text-missing-button-label = Missing alt text
+
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Review alt text
+pdfjs-editor-new-alt-text-to-review-button-label = Review alt text
+
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Created automatically: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Image alt text settings
+pdfjs-image-alt-text-settings-button-label = Image alt text settings
+
+pdfjs-editor-alt-text-settings-dialog-label = Image alt text settings
+pdfjs-editor-alt-text-settings-automatic-title = Automatic alt text
+pdfjs-editor-alt-text-settings-create-model-button-label = Create alt text automatically
+pdfjs-editor-alt-text-settings-create-model-description = Suggests descriptions to help people who can’t see the image or when the image doesn’t load.
+
+pdfjs-editor-alt-text-settings-editor-title = Alt text editor
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image
+pdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.
+pdfjs-editor-alt-text-settings-close-button = Close
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Highlight added
+pdfjs-editor-freetext-added-alert = Text added
+pdfjs-editor-ink-added-alert = Drawing added
+pdfjs-editor-stamp-added-alert = Image added
+pdfjs-editor-signature-added-alert = Signature added
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Highlight removed
+pdfjs-editor-undo-bar-message-freetext = Text removed
+pdfjs-editor-undo-bar-message-ink = Drawing removed
+pdfjs-editor-undo-bar-message-stamp = Image removed
+pdfjs-editor-undo-bar-message-signature = Signature removed
+pdfjs-editor-undo-bar-message-comment = Comment removed
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotation removed
+ *[other] { $count } annotations removed
+ }
+
+pdfjs-editor-undo-bar-undo-button =
+ .title = Undo
+pdfjs-editor-undo-bar-undo-button-label = Undo
+pdfjs-editor-undo-bar-close-button =
+ .title = Close
+pdfjs-editor-undo-bar-close-button-label = Close
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use.
+pdfjs-editor-add-signature-dialog-title = Add a signature
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Type
+ .title = Type
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Draw
+ .title = Draw
+pdfjs-editor-add-signature-image-button = Image
+ .title = Image
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Type your signature
+ .placeholder = Type your signature
+pdfjs-editor-add-signature-draw-placeholder = Draw your signature
+pdfjs-editor-add-signature-draw-thickness-range-label = Thickness
+
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Drawing thickness: { $thickness }
+
+pdfjs-editor-add-signature-image-placeholder = Drag a file here to upload
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Or choose image files
+ *[other] Or browse image files
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Description (alt text)
+pdfjs-editor-add-signature-description-input =
+ .title = Description (alt text)
+pdfjs-editor-add-signature-description-default-when-drawing = Signature
+
+
+pdfjs-editor-add-signature-clear-button-label = Clear signature
+pdfjs-editor-add-signature-clear-button =
+ .title = Clear signature
+pdfjs-editor-add-signature-save-checkbox = Save signature
+pdfjs-editor-add-signature-save-warning-message = You’ve reached the limit of 5 saved signatures. Remove one to save more.
+pdfjs-editor-add-signature-image-upload-error-title = Couldn’t upload image
+pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.
+pdfjs-editor-add-signature-image-no-data-error-title = Can’t convert this image into a signature
+pdfjs-editor-add-signature-image-no-data-error-description = Please try uploading a different image.
+pdfjs-editor-add-signature-error-close-button = Close
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancel
+pdfjs-editor-add-signature-add-button = Add
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Remove saved signature
+pdfjs-editor-delete-signature-button-label1 = Remove saved signature
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Edit description
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Edit description
+
+## Dialog buttons
+
+pdfjs-editor-edit-signature-update-button = Update
+
+## Comment popup
+
+pdfjs-show-comment-button =
+ .title = Show comment
+
+pdfjs-editor-edit-comment-popup-button-label = Edit comment
+pdfjs-editor-edit-comment-popup-button =
+ .title = Edit comment
+pdfjs-editor-delete-comment-popup-button-label = Remove comment
+pdfjs-editor-delete-comment-popup-button =
+ .title = Remove comment
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Edit comment
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Update
+
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Add comment
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Add
+
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Start typing…
+
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancel
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Add comment
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-button1 =
+ .title = Manage pages
+pdfjs-toggle-views-manager-notification-button =
+ .title = Toggle Sidebar (document contains thumbnails/outline/attachments/layers)
+pdfjs-toggle-views-manager-button1-label = Manage pages
+
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidebar
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Sidebar resizer
+pdfjs-views-manager-view-selector-button =
+ .title = Views
+pdfjs-views-manager-view-selector-button-label = Views
+pdfjs-views-manager-pages-title = Pages
+pdfjs-views-manager-outlines-title1 = Document outline
+ .title = Document outline (double-click to expand/collapse all items)
+pdfjs-views-manager-attachments-title = Attachments
+pdfjs-views-manager-layers-title1 = Layers
+ .title = Layers (double-click to reset all layers to the default state)
+
+pdfjs-views-manager-pages-option-label = Pages
+pdfjs-views-manager-outlines-option-label = Document outline
+pdfjs-views-manager-attachments-option-label = Attachments
+pdfjs-views-manager-layers-option-label = Layers
+
+pdfjs-views-manager-add-file-button =
+ .title = Add file
+pdfjs-views-manager-add-file-button-label = Add file
+
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selected
+ *[other] { $count } selected
+ }
+pdfjs-views-manager-pages-status-none-action-label = Select pages
+pdfjs-views-manager-pages-status-action-button-label = Manage
+pdfjs-views-manager-pages-status-copy-button-label = Copy
+pdfjs-views-manager-pages-status-cut-button-label = Cut
+pdfjs-views-manager-pages-status-delete-button-label = Delete
+pdfjs-views-manager-pages-status-export-selected-button-label = Export selected…
+
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 page cut
+ *[other] { $count } pages cut
+ }
+
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 page copied
+ *[other] { $count } pages copied
+ }
+
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 page deleted
+ *[other] { $count } pages deleted
+ }
+
+pdfjs-views-manager-status-undo-button-label = Undo
+pdfjs-views-manager-status-done-button-label = Done
+pdfjs-views-manager-status-close-button =
+ .title = Close
+pdfjs-views-manager-status-close-button-label = Close
+
+pdfjs-views-manager-paste-button-label = Paste
+pdfjs-views-manager-paste-button-before =
+ .title = Paste before the first page
+
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Paste after page { $page }
+
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NEW
+
+pdfjs-views-manager-waiting-for-file = Uploading file…
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Digital signature properties
+ .aria-label = Digital signature properties
+pdfjs-digital-signature-properties-button-label = Digital signature properties
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Document was signed with a valid digital signature
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Document signed but { $count } digital signature could not be verified
+ *[other] Document signed but { $count } digital signatures could not be verified
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Document signed with { $count } certificate that is not trusted
+ *[other] Document signed with { $count } certificates that are not trusted
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Document signed with { $count } expired certificate
+ *[other] Document signed with { $count } expired certificates
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Document has { $count } invalid digital signature
+ *[other] Document has { $count } invalid digital signatures
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Document signed with { $count } revoked certificate
+ *[other] Document signed with { $count } revoked certificates
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signature verified
+pdfjs-digital-signature-properties-status-invalid = Status: Signature invalid
+pdfjs-digital-signature-properties-status-unknown = Status: Unable to verify (unsupported)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificate: Trusted ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificate: Unavailable
+pdfjs-digital-signature-properties-certificate-untrusted = Certificate: Untrusted
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificate: Unknown issuer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificate: Self-signed ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificate: Untrusted issuer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificate: Expired
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificate: Expired ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificate: Revoked
+
+##
+
+pdfjs-digital-signature-properties-view-certificate = View certificate
+
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Reason: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Timestamp: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Sub-signature ({ $count })
+ *[other] Sub-signatures ({ $count })
+ }
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/eo/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/eo/viewer.ftl
new file mode 100644
index 0000000..4a6ac90
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/eo/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Antaŭa paĝo
+pdfjs-previous-button-label = Malantaŭen
+pdfjs-next-button =
+ .title = Venonta paĝo
+pdfjs-next-button-label = Antaŭen
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Paĝo
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = el { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } el { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Malpligrandigi
+pdfjs-zoom-out-button-label = Malpligrandigi
+pdfjs-zoom-in-button =
+ .title = Pligrandigi
+pdfjs-zoom-in-button-label = Pligrandigi
+pdfjs-zoom-select =
+ .title = Pligrandigilo
+pdfjs-presentation-mode-button =
+ .title = Iri al prezenta reĝimo
+pdfjs-presentation-mode-button-label = Prezenta reĝimo
+pdfjs-open-file-button =
+ .title = Malfermi dosieron
+pdfjs-open-file-button-label = Malfermi
+pdfjs-print-button =
+ .title = Presi
+pdfjs-print-button-label = Presi
+pdfjs-save-button =
+ .title = Konservi
+pdfjs-save-button-label = Konservi
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Elŝuti
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Elŝuti
+pdfjs-bookmark-button =
+ .title = Nuna paĝo (Montri adreson de la nuna paĝo)
+pdfjs-bookmark-button-label = Nuna paĝo
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Iloj
+pdfjs-tools-button-label = Iloj
+pdfjs-first-page-button =
+ .title = Iri al la unua paĝo
+pdfjs-first-page-button-label = Iri al la unua paĝo
+pdfjs-last-page-button =
+ .title = Iri al la lasta paĝo
+pdfjs-last-page-button-label = Iri al la lasta paĝo
+pdfjs-page-rotate-cw-button =
+ .title = Rotaciigi dekstrume
+pdfjs-page-rotate-cw-button-label = Rotaciigi dekstrume
+pdfjs-page-rotate-ccw-button =
+ .title = Rotaciigi maldekstrume
+pdfjs-page-rotate-ccw-button-label = Rotaciigi maldekstrume
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktivigi tekstan elektilon
+pdfjs-cursor-text-select-tool-button-label = Teksta elektilo
+pdfjs-cursor-hand-tool-button =
+ .title = Aktivigi ilon de mano
+pdfjs-cursor-hand-tool-button-label = Ilo de mano
+pdfjs-scroll-page-button =
+ .title = Uzi rulumon de paĝo
+pdfjs-scroll-page-button-label = Rulumo de paĝo
+pdfjs-scroll-vertical-button =
+ .title = Uzi vertikalan rulumon
+pdfjs-scroll-vertical-button-label = Vertikala rulumo
+pdfjs-scroll-horizontal-button =
+ .title = Uzi horizontalan rulumon
+pdfjs-scroll-horizontal-button-label = Horizontala rulumo
+pdfjs-scroll-wrapped-button =
+ .title = Uzi ambaŭdirektan rulumon
+pdfjs-scroll-wrapped-button-label = Ambaŭdirekta rulumo
+pdfjs-spread-none-button =
+ .title = Ne montri paĝojn po du
+pdfjs-spread-none-button-label = Unupaĝa vido
+pdfjs-spread-odd-button =
+ .title = Kunigi paĝojn komencante per nepara paĝo
+pdfjs-spread-odd-button-label = Po du paĝoj, neparaj maldekstre
+pdfjs-spread-even-button =
+ .title = Kunigi paĝojn komencante per para paĝo
+pdfjs-spread-even-button-label = Po du paĝoj, paraj maldekstre
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Atributoj de dokumento…
+pdfjs-document-properties-button-label = Atributoj de dokumento…
+pdfjs-document-properties-file-name = Nomo de dosiero:
+pdfjs-document-properties-file-size = Grando de dosiero:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KO ({ $b } oktetoj)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } Mo ({ $b } oktetoj)
+pdfjs-document-properties-title = Titolo:
+pdfjs-document-properties-author = Aŭtoro:
+pdfjs-document-properties-subject = Temo:
+pdfjs-document-properties-keywords = Ŝlosilvorto:
+pdfjs-document-properties-creation-date = Dato de kreado:
+pdfjs-document-properties-modification-date = Dato de modifo:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Kreinto:
+pdfjs-document-properties-producer = Produktinto de PDF:
+pdfjs-document-properties-version = Versio de PDF:
+pdfjs-document-properties-page-count = Nombro de paĝoj:
+pdfjs-document-properties-page-size = Grando de paĝo:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertikala
+pdfjs-document-properties-page-size-orientation-landscape = horizontala
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letera
+pdfjs-document-properties-page-size-name-legal = Jura
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Rapida tekstaĵa vido:
+pdfjs-document-properties-linearized-yes = Jes
+pdfjs-document-properties-linearized-no = Ne
+pdfjs-document-properties-close-button = Fermi
+pdfjs-digital-signature-properties-view-certificate = Vidi atestilon
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Kialo: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Tempindiko: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Duaranga subskribo ({ $count })
+ *[other] Duarangaj subskriboj ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparo de dokumento por presi ĝin …
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Nuligi
+pdfjs-printing-not-supported = Averto: tiu ĉi retumilo ne plene subtenas presadon.
+pdfjs-printing-not-ready = Averto: la PDF dosiero ne estas plene ŝargita por presado.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Montri/kaŝi flankan strion
+pdfjs-toggle-sidebar-notification-button =
+ .title = Montri/kaŝi flankan strion (la dokumento enhavas konturon/kunsendaĵojn/tavolojn)
+pdfjs-toggle-sidebar-button-label = Montri/kaŝi flankan strion
+pdfjs-document-outline-button =
+ .title = Montri la konturon de dokumento (alklaku duoble por faldi/malfaldi ĉiujn elementojn)
+pdfjs-document-outline-button-label = Konturo de dokumento
+pdfjs-attachments-button =
+ .title = Montri kunsendaĵojn
+pdfjs-attachments-button-label = Kunsendaĵojn
+pdfjs-layers-button =
+ .title = Montri tavolojn (duoble alklaku por remeti ĉiujn tavolojn en la norman staton)
+pdfjs-layers-button-label = Tavoloj
+pdfjs-thumbs-button =
+ .title = Montri miniaturojn
+pdfjs-thumbs-button-label = Miniaturoj
+pdfjs-current-outline-item-button =
+ .title = Trovi nunan konturan elementon
+pdfjs-current-outline-item-button-label = Nuna kontura elemento
+pdfjs-findbar-button =
+ .title = Serĉi en dokumento
+pdfjs-findbar-button-label = Serĉi
+pdfjs-additional-layers = Aldonaj tavoloj
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Paĝo { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniaturo de paĝo { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Elekti paĝon { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Paĝo { $page } el { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Serĉi
+ .placeholder = Serĉi en dokumento…
+pdfjs-find-previous-button =
+ .title = Serĉi la antaŭan aperon de la frazo
+pdfjs-find-previous-button-label = Malantaŭen
+pdfjs-find-next-button =
+ .title = Serĉi la venontan aperon de la frazo
+pdfjs-find-next-button-label = Antaŭen
+pdfjs-find-highlight-checkbox = Elstarigi ĉiujn
+pdfjs-find-match-case-checkbox-label = Distingi usklecon
+pdfjs-find-match-diacritics-checkbox-label = Respekti supersignojn
+pdfjs-find-entire-word-checkbox-label = Tutaj vortoj
+pdfjs-find-reached-top = Komenco de la dokumento atingita, daŭrigado ekde la fino
+pdfjs-find-reached-bottom = Fino de la dokumento atingita, daŭrigado ekde la komenco
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } el { $total } kongruo
+ *[other] { $current } el { $total } kongruoj
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Pli ol { $limit } kongruo
+ *[other] Pli ol { $limit } kongruoj
+ }
+pdfjs-find-not-found = Frazo ne trovita
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Larĝo de paĝo
+pdfjs-page-scale-fit = Adapti paĝon
+pdfjs-page-scale-auto = Aŭtomata skalo
+pdfjs-page-scale-actual = Reala grando
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Paĝo { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Okazis eraro dum la ŝargado de la PDF dosiero.
+pdfjs-invalid-file-error = Nevalida aŭ difektita PDF dosiero.
+pdfjs-missing-file-error = Mankas dosiero PDF.
+pdfjs-unexpected-response-error = Neatendita respondo de servilo.
+pdfjs-rendering-error = Okazis eraro dum la montro de la paĝo.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Prinoto: { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Tajpu pasvorton por malfermi tiun ĉi dosieron PDF.
+pdfjs-password-invalid = Nevalida pasvorto. Bonvolu provi denove.
+pdfjs-password-ok-button = Akcepti
+pdfjs-password-cancel-button = Nuligi
+pdfjs-web-fonts-disabled = Neaktivaj teksaĵaj tiparoj: ne elbas uzi enmetitajn tiparojn de PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Teksto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Ŝanĝi koloron de teksto
+pdfjs-editor-free-text-button-label = Teksto
+pdfjs-editor-ink-button =
+ .title = Desegni
+pdfjs-editor-color-picker-ink-input =
+ .title = Ŝanĝi desegnan koloron
+pdfjs-editor-ink-button-label = Desegni
+pdfjs-editor-stamp-button =
+ .title = Aldoni aŭ modifi bildojn
+pdfjs-editor-stamp-button-label = Aldoni aŭ modifi bildojn
+pdfjs-editor-highlight-button =
+ .title = Elstarigi
+pdfjs-editor-highlight-button-label = Elstarigi
+pdfjs-highlight-floating-button1 =
+ .title = Elstarigi
+ .aria-label = Elstarigi
+pdfjs-highlight-floating-button-label = Elstarigi
+pdfjs-comment-floating-button =
+ .title = Komenti
+ .aria-label = Komenti
+pdfjs-comment-floating-button-label = Komenti
+pdfjs-editor-comment-button =
+ .title = Komenti
+ .aria-label = Komenti
+pdfjs-editor-comment-button-label = Komenti
+pdfjs-editor-signature-button =
+ .title = Aldoni subskribon
+pdfjs-editor-signature-button-label = Aldoni subskribon
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Redaktilo de elstaraĵo
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Redaktilo de desegno
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Redaktilo de subskribo: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Redaktilo de bildo
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Forigi desegnon
+pdfjs-editor-remove-freetext-button =
+ .title = Forigi tekston
+pdfjs-editor-remove-stamp-button =
+ .title = Forigi bildon
+pdfjs-editor-remove-highlight-button =
+ .title = Forigi elstaraĵon
+pdfjs-editor-remove-signature-button =
+ .title = Forigi subskribon
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Koloro
+pdfjs-editor-free-text-size-input = Grando
+pdfjs-editor-ink-color-input = Koloro
+pdfjs-editor-ink-thickness-input = Dikeco
+pdfjs-editor-ink-opacity-input = Maldiafaneco
+pdfjs-editor-stamp-add-image-button =
+ .title = Aldoni bildon
+pdfjs-editor-stamp-add-image-button-label = Aldoni bildon
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Dikeco
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Ŝanĝi dikecon dum elstarigo de netekstaj elementoj
+pdfjs-editor-add-signature-container =
+ .aria-label = Kontrolado de subskriboj kaj konservitaj subskriboj
+pdfjs-editor-signature-add-signature-button =
+ .title = Aldoni novan subskribon
+pdfjs-editor-signature-add-signature-button-label = Aldoni novan subskribon
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Konservita subskribo: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Teksta redaktilo
+ .default-content = Komencu tajpi…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Komenti
+ *[other] Komentoj
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Fermi la flankan strion
+ .aria-label = Fermi la flankan strion
+pdfjs-editor-comments-sidebar-close-button-label = Fermi la flankan strion
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Ĉu vi rimarkas ion interesan? Elstarigu tion kaj aldonu komenton.
+pdfjs-editor-comments-sidebar-no-comments-link = Pli da informo
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativa teksto
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Redakti alternativan tekston
+pdfjs-editor-alt-text-dialog-label = Elektu eblon
+pdfjs-editor-alt-text-dialog-description = Alternativa teksto helpas personojn, en la okazoj kiam ili ne povas vidi aŭ ŝargi la bildon.
+pdfjs-editor-alt-text-add-description-label = Aldoni priskribon
+pdfjs-editor-alt-text-add-description-description = La celo estas unu aŭ du frazoj, kiuj priskribas la temon, etoson aŭ agojn.
+pdfjs-editor-alt-text-mark-decorative-label = Marki kiel ornaman
+pdfjs-editor-alt-text-mark-decorative-description = Tio ĉi estas uzita por ornamaj bildoj, kiel randoj aŭ fonaj bildoj.
+pdfjs-editor-alt-text-cancel-button = Nuligi
+pdfjs-editor-alt-text-save-button = Konservi
+pdfjs-editor-alt-text-decorative-tooltip = Markita kiel ornama
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Ekzemple: “Juna persono sidiĝas ĉetable por ekmanĝi”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativa teksto
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Supra maldekstra angulo — ŝangi grandon
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Supra mezo — ŝanĝi grandon
+pdfjs-editor-resizer-top-right =
+ .aria-label = Supran dekstran angulon — ŝanĝi grandon
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Dekstra mezo — ŝanĝi grandon
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Malsupra deksta angulo — ŝanĝi grandon
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Malsupra mezo — ŝanĝi grandon
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Malsupra maldekstra angulo — ŝanĝi grandon
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Maldekstra mezo — ŝanĝi grandon
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Elstarigi koloron
+pdfjs-editor-colorpicker-button =
+ .title = Ŝanĝi koloron
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Elekto de koloroj
+pdfjs-editor-colorpicker-yellow =
+ .title = Flava
+pdfjs-editor-colorpicker-green =
+ .title = Verda
+pdfjs-editor-colorpicker-blue =
+ .title = Blua
+pdfjs-editor-colorpicker-pink =
+ .title = Roza
+pdfjs-editor-colorpicker-red =
+ .title = Ruĝa
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Montri ĉiujn
+pdfjs-editor-highlight-show-all-button =
+ .title = Montri ĉiujn
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Modifi alternativan tekston (priskribo de bildo)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Aldoni alternativan tekston (priskribo de bildo)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skribu vian priskribon ĉi tie…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Mallonga priskribo por personoj kiuj ne povas vidi la bildon kaj por montri kiam la bildo ne ŝargeblas.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Tiu ĉi alternativa teksto estis aŭtomate kreita kaj povus esti malĝusta.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Pli da informo
+pdfjs-editor-new-alt-text-create-automatically-button-label = Aŭtomate krei alternativan tekston
+pdfjs-editor-new-alt-text-not-now-button = Ne nun
+pdfjs-editor-new-alt-text-error-title = Ne eblis aŭtomate krei alternativan tekston
+pdfjs-editor-new-alt-text-error-description = Bonvolu skribi vian propran alternativan tekston aŭ provi denove poste.
+pdfjs-editor-new-alt-text-error-close-button = Fermi
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Elŝuto de modelo de artefarita intelekto por alternativa teksto ({ $downloadedSize } el { $totalSize } MO)
+ .aria-valuetext = Elŝuto de modelo de artefarita intelekto por alternativa teksto ({ $downloadedSize } el { $totalSize } MO)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativa teksto aldonita
+pdfjs-editor-new-alt-text-added-button-label = Alternativa teksto aldonita
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Mankas alternativa teksto
+pdfjs-editor-new-alt-text-missing-button-label = Mankas alternativa teksto
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Kontroli alternativan tekston
+pdfjs-editor-new-alt-text-to-review-button-label = Kontroli alternativan tekston
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Aŭtomate kreita: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Agordoj por alternativa teksto de bildoj
+pdfjs-image-alt-text-settings-button-label = Agordoj por alternativa teksto de bildoj
+pdfjs-editor-alt-text-settings-dialog-label = Agordoj por alternativa teksto de bildoj
+pdfjs-editor-alt-text-settings-automatic-title = Aŭtomata alternativa teksto
+pdfjs-editor-alt-text-settings-create-model-button-label = Aŭtomate krei alternativan tekston
+pdfjs-editor-alt-text-settings-create-model-description = Tio ĉi sugestas priskribojn por helpi personojn kiuj ne povas vidi aŭ ŝargi la bildon.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de artefarita intelekto por alternativa teksto ({ $totalSize } MO)
+pdfjs-editor-alt-text-settings-ai-model-description = Ĝi funkcias en via aparato, do viaj datumoj restas privataj. Ĝi estas postulata por aŭtomata kreado de alternativa teksto.
+pdfjs-editor-alt-text-settings-delete-model-button = Forigi
+pdfjs-editor-alt-text-settings-download-model-button = Elŝuti
+pdfjs-editor-alt-text-settings-downloading-model-button = Elŝuto…
+pdfjs-editor-alt-text-settings-editor-title = Redaktilo de alternativa teksto
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Montri redaktilon de alternativa teksto tuj post aldono de bildo
+pdfjs-editor-alt-text-settings-show-dialog-description = Tio ĉi helpas vin kontroli ĉu ĉiuj bildoj havas alternativan tekston.
+pdfjs-editor-alt-text-settings-close-button = Fermi
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Elstarigo aldonita
+pdfjs-editor-freetext-added-alert = Teksto aldonita
+pdfjs-editor-ink-added-alert = Desegno aldonita
+pdfjs-editor-stamp-added-alert = Bildo aldonita
+pdfjs-editor-signature-added-alert = Subskribo aldonita
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Elstaraĵo forigita
+pdfjs-editor-undo-bar-message-freetext = Teksto forigita
+pdfjs-editor-undo-bar-message-ink = Desegno forigita
+pdfjs-editor-undo-bar-message-stamp = Bildo forigita
+pdfjs-editor-undo-bar-message-signature = Subskribo forigita
+pdfjs-editor-undo-bar-message-comment = Komento forigita
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] unu prinoto forigita
+ *[other] { $count } prinotoj forigitaj
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Malfari
+pdfjs-editor-undo-bar-undo-button-label = Malfari
+pdfjs-editor-undo-bar-close-button =
+ .title = Fermi
+pdfjs-editor-undo-bar-close-button-label = Fermi
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Tiu ĉi fenestro permesas al la uzanto krei subskribon por aldoni al dokumento PDF. La uzanto povas modifi la nomon (kiu estas cetere la alternativa teksto) kaj havas la eblon konservi la subskribon por posta uzo.
+pdfjs-editor-add-signature-dialog-title = Aldoni subskribon
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tajpi
+ .title = Tajpi
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Desegni
+ .title = Desegni
+pdfjs-editor-add-signature-image-button = Bildo
+ .title = Bildo
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Tajpu vian subskribon
+ .placeholder = Tajpu vian subskribon
+pdfjs-editor-add-signature-draw-placeholder = Desegni vian subskribon
+pdfjs-editor-add-signature-draw-thickness-range-label = Dikeco
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Dikeco de desegno: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Trenu dosieron ĉi tien por alŝuti ĝin
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Aŭ elektu bildan dosieron
+ *[other] Aŭ elektu bildan dosieron
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Priskribo (alternativa teksto)
+pdfjs-editor-add-signature-description-input =
+ .title = Priskribo (alternativa teksto)
+pdfjs-editor-add-signature-description-default-when-drawing = Subskribo
+pdfjs-editor-add-signature-clear-button-label = Viŝi subskribon
+pdfjs-editor-add-signature-clear-button =
+ .title = Viŝi subskribon
+pdfjs-editor-add-signature-save-checkbox = Konservi subskribon
+pdfjs-editor-add-signature-save-warning-message = Vi atingis la limon de kvin konservitaj subskriboj. Forigi unu por povi konservi pli da.
+pdfjs-editor-add-signature-image-upload-error-title = Ne eblis alŝuti bildon
+pdfjs-editor-add-signature-image-upload-error-description = Kontrolu vian retaliron aŭ provu alŝuti alian bildon.
+pdfjs-editor-add-signature-image-no-data-error-title = Ne eblas konverti tiun ĉi bildon al subskribo
+pdfjs-editor-add-signature-image-no-data-error-description = Bonvolu provi alŝuti novan bildon.
+pdfjs-editor-add-signature-error-close-button = Fermi
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Nuligi
+pdfjs-editor-add-signature-add-button = Aldoni
+pdfjs-editor-edit-signature-update-button = Ĝisdatigi
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Modifi komenton
+pdfjs-editor-edit-comment-popup-button =
+ .title = Modifi komenton
+pdfjs-editor-delete-comment-popup-button-label = Forigi komenton
+pdfjs-editor-delete-comment-popup-button =
+ .title = Forigi komenton
+pdfjs-show-comment-button =
+ .title = Montri komenton
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Modifi komenton
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Ĝisdatigi
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Aldoni komenton
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Aldoni
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Ektajpi…
+pdfjs-editor-edit-comment-dialog-cancel-button = Nuligi
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Aldoni komenton
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Montri/kaŝi flankan strion (la dokumento enhavas miniaturojn/konturon/kunsendaĵojn/tavolojn)
+pdfjs-toggle-views-manager-button1-label = Administri paĝojn
+pdfjs-views-manager-sidebar =
+ .aria-label = Flanka strio
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Dimensiigilo por la flanka strio
+pdfjs-views-manager-view-selector-button =
+ .title = Vidoj
+pdfjs-views-manager-view-selector-button-label = Vidoj
+pdfjs-views-manager-pages-title = Paĝoj
+pdfjs-views-manager-outlines-title1 = Konturo de dokumento
+ .title = Konturo de dokumento (alklaku duoble por faldi/malfaldi ĉiujn elementojn)
+pdfjs-views-manager-attachments-title = Kunsendaĵoj
+pdfjs-views-manager-layers-title1 = Tavoloj
+ .title = Tavoloj (alklaku duoble por ke ĉiuj tavoloj reiru al la norma stato)
+pdfjs-views-manager-pages-option-label = Paĝoj
+pdfjs-views-manager-outlines-option-label = Konturo de dokumento
+pdfjs-views-manager-attachments-option-label = Kunsendaĵoj
+pdfjs-views-manager-layers-option-label = Tavoloj
+pdfjs-views-manager-add-file-button =
+ .title = Aldoni dosieron
+pdfjs-views-manager-add-file-button-label = Aldoni dosieron
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } elektita
+ *[other] { $count } elektitaj
+ }
+pdfjs-views-manager-pages-status-none-action-label = Elekti paĝojn
+pdfjs-views-manager-pages-status-action-button-label = Administri
+pdfjs-views-manager-pages-status-copy-button-label = Kopii
+pdfjs-views-manager-pages-status-cut-button-label = Eltondi
+pdfjs-views-manager-pages-status-delete-button-label = Forigi
+pdfjs-views-manager-pages-status-export-selected-button-label = Eksporti elektitajn…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 paĝo eltondita
+ *[other] { $count } paĝoj eltonditaj
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 paĝo kopiita
+ *[other] { $count } paĝoj kopiitaj
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 paĝo forigita
+ *[other] { $count } paĝoj forigitaj
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Pretigo de via dosiero…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Dosiero alŝutata…
+pdfjs-views-manager-status-warning-cut-label = Ne eblis eltondi. Refreŝigu la paĝon kaj provu denove.
+pdfjs-views-manager-status-warning-copy-label = Ne eblis kopii. Refreŝigu la paĝon kaj provu denove.
+pdfjs-views-manager-status-warning-delete-label = Ne eblis forigi. Refreŝigu la paĝon kaj provu denove.
+pdfjs-views-manager-status-warning-save-label = Ne eblis konservi. Refreŝigu la paĝon kaj provu denove.
+pdfjs-views-manager-status-undo-button-label = Malfari
+pdfjs-views-manager-status-done-button-label = Farita
+pdfjs-views-manager-status-close-button =
+ .title = Fermi
+pdfjs-views-manager-status-close-button-label = Fermi
+pdfjs-views-manager-paste-button-label = Alglui
+pdfjs-views-manager-paste-button-before =
+ .title = Alglui antaŭ la unua paĝo
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Alglui post la paĝo { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVA
+pdfjs-views-manager-waiting-for-file = Dosiero alŝutata…
+pdfjs-toggle-views-manager-button1 =
+ .title = Administri paĝojn
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Atributoj de cifereca subskribo
+ .aria-label = Atributoj de cifereca subskribo
+pdfjs-digital-signature-properties-button-label = Atributoj de cifereca subskribo
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = La dokumento estis subskribita de valida cifereca subskribo
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokumento subskribita, tamen { $count } cifereca subskribo ne povis esti kontrolita
+ *[other] Dokumento subskribita, tamen { $count } ciferecaj subskriboj ne povis esti kontrolita
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokumento subskribita de { $count } nefidata atestilo
+ *[other] Dokumento subskribita de { $count } nefidataj atestiloj
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokumento subskribita de { $count } senvalidiĝinta atestilo
+ *[other] Dokumento subskribita de { $count } senvalidiĝintaj atestiloj
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] La dokumento havas { $count } nevalidan ciferecan subskribon
+ *[other] La dokumento havas { $count } nevalidajn ciferecajn subskribojn
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokumento subskribita de { $count } senvalidigita atestilo
+ *[other] Dokumento subskribita de { $count } senvalidigitaj atestiloj
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stato: Subskribo kontrolita
+pdfjs-digital-signature-properties-status-invalid = Stato: Subskribo nevalida
+pdfjs-digital-signature-properties-status-unknown = Stato: Ne eblas kontroli (nesubtenata)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Atestilo: Fidata ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Atestilo: Nedisponebla
+pdfjs-digital-signature-properties-certificate-untrusted = Atestilo: Ne fidata
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Atestilo: Nekonata eldoninto ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Atestilo: Memsubskribita ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Atestilo: Nefidata eldoninto ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Atestilo: Senvalidiĝinta
+pdfjs-digital-signature-properties-certificate-expired-with-date = Atestilo: Senvalidiĝinta ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Atestilo: Senvalidigita
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Forigi konservitan subskribon
+pdfjs-editor-delete-signature-button-label1 = Forigi konservitan subskribon
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Modifi priskribon
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Modifi priskribon
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-AR/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-AR/viewer.ftl
new file mode 100644
index 0000000..bd64e9d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-AR/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Página siguiente
+pdfjs-next-button-label = Siguiente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Página
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ( { $pageNumber } de { $pagesCount } )
+pdfjs-zoom-out-button =
+ .title = Alejar
+pdfjs-zoom-out-button-label = Alejar
+pdfjs-zoom-in-button =
+ .title = Acercar
+pdfjs-zoom-in-button-label = Acercar
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Cambiar a modo presentación
+pdfjs-presentation-mode-button-label = Modo presentación
+pdfjs-open-file-button =
+ .title = Abrir archivo
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Guardar
+pdfjs-save-button-label = Guardar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Descargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Descargar
+pdfjs-bookmark-button =
+ .title = Página actual (Ver URL de la página actual)
+pdfjs-bookmark-button-label = Página actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Herramientas
+pdfjs-tools-button-label = Herramientas
+pdfjs-first-page-button =
+ .title = Ir a primera página
+pdfjs-first-page-button-label = Ir a primera página
+pdfjs-last-page-button =
+ .title = Ir a última página
+pdfjs-last-page-button-label = Ir a última página
+pdfjs-page-rotate-cw-button =
+ .title = Rotar horario
+pdfjs-page-rotate-cw-button-label = Rotar horario
+pdfjs-page-rotate-ccw-button =
+ .title = Rotar antihorario
+pdfjs-page-rotate-ccw-button-label = Rotar antihorario
+pdfjs-cursor-text-select-tool-button =
+ .title = Habilitar herramienta de selección de texto
+pdfjs-cursor-text-select-tool-button-label = Herramienta de selección de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Habilitar herramienta mano
+pdfjs-cursor-hand-tool-button-label = Herramienta mano
+pdfjs-scroll-page-button =
+ .title = Usar desplazamiento de página
+pdfjs-scroll-page-button-label = Desplazamiento de página
+pdfjs-scroll-vertical-button =
+ .title = Usar desplazamiento vertical
+pdfjs-scroll-vertical-button-label = Desplazamiento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar desplazamiento vertical
+pdfjs-scroll-horizontal-button-label = Desplazamiento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar desplazamiento encapsulado
+pdfjs-scroll-wrapped-button-label = Desplazamiento encapsulado
+pdfjs-spread-none-button =
+ .title = No unir páginas dobles
+pdfjs-spread-none-button-label = Sin dobles
+pdfjs-spread-odd-button =
+ .title = Unir páginas dobles comenzando con las impares
+pdfjs-spread-odd-button-label = Dobles impares
+pdfjs-spread-even-button =
+ .title = Unir páginas dobles comenzando con las pares
+pdfjs-spread-even-button-label = Dobles pares
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedades del documento…
+pdfjs-document-properties-button-label = Propiedades del documento…
+pdfjs-document-properties-file-name = Nombre de archivo:
+pdfjs-document-properties-file-size = Tamaño de archivo:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Asunto:
+pdfjs-document-properties-keywords = Palabras clave:
+pdfjs-document-properties-creation-date = Fecha de creación:
+pdfjs-document-properties-modification-date = Fecha de modificación:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creador:
+pdfjs-document-properties-producer = Productor PDF:
+pdfjs-document-properties-version = Versión de PDF:
+pdfjs-document-properties-page-count = Cantidad de páginas:
+pdfjs-document-properties-page-size = Tamaño de página:
+pdfjs-document-properties-page-size-unit-inches = en
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = normal
+pdfjs-document-properties-page-size-orientation-landscape = apaisado
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista rápida de la Web:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Cerrar
+pdfjs-digital-signature-properties-view-certificate = Ver certificado
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Razón: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Fecha: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Subfirma ({ $count })
+ *[other] Subfirmas ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparando documento para imprimir…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Advertencia: La impresión no está totalmente soportada por este navegador.
+pdfjs-printing-not-ready = Advertencia: El PDF no está completamente cargado para impresión.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Alternar barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Alternar barra lateral (el documento contiene esquemas/adjuntos/capas)
+pdfjs-toggle-sidebar-button-label = Alternar barra lateral
+pdfjs-document-outline-button =
+ .title = Mostrar esquema del documento (doble clic para expandir/colapsar todos los ítems)
+pdfjs-document-outline-button-label = Esquema del documento
+pdfjs-attachments-button =
+ .title = Mostrar adjuntos
+pdfjs-attachments-button-label = Adjuntos
+pdfjs-layers-button =
+ .title = Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado)
+pdfjs-layers-button-label = Capas
+pdfjs-thumbs-button =
+ .title = Mostrar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Buscar elemento de esquema actual
+pdfjs-current-outline-item-button-label = Elemento de esquema actual
+pdfjs-findbar-button =
+ .title = Buscar en documento
+pdfjs-findbar-button-label = Buscar
+pdfjs-additional-layers = Capas adicionales
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura de página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seleccionar página { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Página { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Buscar
+ .placeholder = Buscar en documento…
+pdfjs-find-previous-button =
+ .title = Buscar la aparición anterior de la frase
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Buscar la siguiente aparición de la frase
+pdfjs-find-next-button-label = Siguiente
+pdfjs-find-highlight-checkbox = Resaltar todo
+pdfjs-find-match-case-checkbox-label = Coincidir mayúsculas
+pdfjs-find-match-diacritics-checkbox-label = Coincidir diacríticos
+pdfjs-find-entire-word-checkbox-label = Palabras completas
+pdfjs-find-reached-top = Inicio de documento alcanzado, continuando desde abajo
+pdfjs-find-reached-bottom = Fin de documento alcanzado, continuando desde arriba
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } de { $total } coincidencia
+ *[other] { $current } de { $total } coincidencias
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Más de { $limit } coincidencia
+ *[other] Más de { $limit } coincidencias
+ }
+pdfjs-find-not-found = Frase no encontrada
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ancho de página
+pdfjs-page-scale-fit = Ajustar página
+pdfjs-page-scale-auto = Zoom automático
+pdfjs-page-scale-actual = Tamaño real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Página { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ocurrió un error al cargar el PDF.
+pdfjs-invalid-file-error = Archivo PDF no válido o corrupto.
+pdfjs-missing-file-error = Archivo PDF faltante.
+pdfjs-unexpected-response-error = Respuesta del servidor inesperada.
+pdfjs-rendering-error = Ocurrió un error al dibujar la página.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Anotación]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Ingrese la contraseña para abrir este archivo PDF
+pdfjs-password-invalid = Contraseña inválida. Intente nuevamente.
+pdfjs-password-ok-button = Aceptar
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = Tipografía web deshabilitada: no se pueden usar tipos incrustados en PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambiar color del texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Dibujar
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambiar color del dibujo
+pdfjs-editor-ink-button-label = Dibujar
+pdfjs-editor-stamp-button =
+ .title = Agregar o editar imágenes
+pdfjs-editor-stamp-button-label = Agregar o editar imágenes
+pdfjs-editor-highlight-button =
+ .title = Resaltar
+pdfjs-editor-highlight-button-label = Resaltar
+pdfjs-highlight-floating-button1 =
+ .title = Resaltar
+ .aria-label = Resaltar
+pdfjs-highlight-floating-button-label = Resaltar
+pdfjs-comment-floating-button =
+ .title = Comentar
+ .aria-label = Comentar
+pdfjs-comment-floating-button-label = Comentar
+pdfjs-editor-comment-button =
+ .title = Comentar
+ .aria-label = Comentar
+pdfjs-editor-comment-button-label = Comentar
+pdfjs-editor-signature-button =
+ .title = Agregar firma
+pdfjs-editor-signature-button-label = Agregar firma
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de resaltado
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de dibujos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de firmas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imágenes
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Eliminar dibujo
+pdfjs-editor-remove-freetext-button =
+ .title = Eliminar texto
+pdfjs-editor-remove-stamp-button =
+ .title = Eliminar imagen
+pdfjs-editor-remove-highlight-button =
+ .title = Eliminar resaltado
+pdfjs-editor-remove-signature-button =
+ .title = Eliminar firma
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Tamaño
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Espesor
+pdfjs-editor-ink-opacity-input = Opacidad
+pdfjs-editor-stamp-add-image-button =
+ .title = Agregar una imagen
+pdfjs-editor-stamp-add-image-button-label = Agregar una imagen
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grosor
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Cambiar el grosor al resaltar elementos que no sean texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controles de firma y firmas guardadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Agregar nueva firma
+pdfjs-editor-signature-add-signature-button-label = Agregar nueva firma
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firma guardada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Comenzar a tipear…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentario
+ *[other] Comentarios
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Cerrar la barra lateral
+ .aria-label = Cerrar la barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Cerrar la barra lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ¿Ve algo digno de mención? Resáltelo y deje un comentario.
+pdfjs-editor-comments-sidebar-no-comments-link = Conocer más
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar texto alternativo
+pdfjs-editor-alt-text-dialog-label = Elegir una opción
+pdfjs-editor-alt-text-dialog-description = El texto alternativo (texto alternativo) ayuda cuando las personas no pueden ver la imagen o cuando no se carga.
+pdfjs-editor-alt-text-add-description-label = Agregar una descripción
+pdfjs-editor-alt-text-add-description-description = Intente escribir 1 o 2 oraciones que describan el tema, el entorno o las acciones.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativo
+pdfjs-editor-alt-text-mark-decorative-description = Esto se usa para imágenes ornamentales, como bordes o marcas de agua.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Guardar
+pdfjs-editor-alt-text-decorative-tooltip = Marcado como decorativo
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por ejemplo: “Un joven se sienta a la mesa a comer”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Esquina superior izquierda — cambiar el tamaño
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Arriba en el medio — cambiar el tamaño
+pdfjs-editor-resizer-top-right =
+ .aria-label = Esquina superior derecha — cambiar el tamaño
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Al centro a la derecha — cambiar el tamaño
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Esquina inferior derecha — cambiar el tamaño
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Abajo en el medio — cambiar el tamaño
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Esquina inferior izquierda — cambiar el tamaño
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Al centro a la izquierda — cambiar el tamaño
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color de resaltado
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar el color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opciones de color
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarillo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosado
+pdfjs-editor-colorpicker-red =
+ .title = Rojo
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostrar todo
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostrar todo
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descripción de la imagen)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Agregar texto alternativo (descripción de la imagen)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escribir la descripción aquí…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Descripción corta para las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo fue creado automáticamente y puede ser incorrecto.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Conocer más
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-new-alt-text-not-now-button = No ahora
+pdfjs-editor-new-alt-text-error-title = No se pudo crear el texto alternativo automáticamente
+pdfjs-editor-new-alt-text-error-description = Escriba su propio texto alternativo o pruebe nuevamente más tarde.
+pdfjs-editor-new-alt-text-error-close-button = Cerrar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Descargando modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Descargando modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Texto alternativo agregado
+pdfjs-editor-new-alt-text-added-button-label = Texto alternativo agregado
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Falta el texto alternativo
+pdfjs-editor-new-alt-text-missing-button-label = Falta el texto alternativo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Calificar el texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Revisar el texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creado automáticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Configuración de texto alternativo de la imagen
+pdfjs-image-alt-text-settings-button-label = Configuración de texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-dialog-label = Configuración de texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-alt-text-settings-create-model-description = Sugiere descripciones para ayudar a las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de IA de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Se ejecuta localmente en el dispositivo para que los datos se mantengan privados. Requerido para texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Borrar
+pdfjs-editor-alt-text-settings-download-model-button = Descargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Descargando…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar el editor de texto alternativo inmediatamente al agregar una imagen
+pdfjs-editor-alt-text-settings-show-dialog-description = Te ayuda a asegurarse de que todas las imágenes tengan texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Cerrar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Resaltado agregado
+pdfjs-editor-freetext-added-alert = Texto agregado
+pdfjs-editor-ink-added-alert = Dibujo agregado
+pdfjs-editor-stamp-added-alert = Imagen agregada
+pdfjs-editor-signature-added-alert = Firma agregada
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Resaltado eliminado
+pdfjs-editor-undo-bar-message-freetext = Texto eliminado
+pdfjs-editor-undo-bar-message-ink = Dibujo eliminado
+pdfjs-editor-undo-bar-message-stamp = Imagen eliminada
+pdfjs-editor-undo-bar-message-signature = Firma eliminada
+pdfjs-editor-undo-bar-message-comment = Comentario eliminado
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotación eliminada
+ *[other] { $count } anotaciones eliminadas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Deshacer
+pdfjs-editor-undo-bar-undo-button-label = Deshacer
+pdfjs-editor-undo-bar-close-button =
+ .title = Cerrar
+pdfjs-editor-undo-bar-close-button-label = Cerrar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Este modal permite al usuario crear una firma para agregar a un documento PDF. El usuario puede editar el nombre (que también sirve como texto alternativo) y opcionalmente guardar la firma para un uso repetido.
+pdfjs-editor-add-signature-dialog-title = Agregar una firma
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tipear
+ .title = Tipear
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dibujar
+ .title = Dibujar
+pdfjs-editor-add-signature-image-button = Imagen
+ .title = Imagen
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Escribir la firma
+ .placeholder = Escribir la firma
+pdfjs-editor-add-signature-draw-placeholder = Dibujar la firma
+pdfjs-editor-add-signature-draw-thickness-range-label = Grosor
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grosor del dibujo: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arrastrar un archivo acá para subirlo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] O seleccionar archivos de imágenes
+ *[other] O seleccionar archivos de imágenes
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Firma
+pdfjs-editor-add-signature-clear-button-label = Borrar firma
+pdfjs-editor-add-signature-clear-button =
+ .title = Borrar firma
+pdfjs-editor-add-signature-save-checkbox = Guardar firma
+pdfjs-editor-add-signature-save-warning-message = Se alcanzó el límite de 5 firmas guardadas. Elimine una para guardar más.
+pdfjs-editor-add-signature-image-upload-error-title = No se pudo subir la imagen
+pdfjs-editor-add-signature-image-upload-error-description = Verifique la conexión de red o pruebe con otra imagen.
+pdfjs-editor-add-signature-image-no-data-error-title = No se puede convertir esta imagen en una firma
+pdfjs-editor-add-signature-image-no-data-error-description = Intente subir una imagen diferente.
+pdfjs-editor-add-signature-error-close-button = Cerrar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Agregar
+pdfjs-editor-edit-signature-update-button = Actualizar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editar comentario
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editar comentario
+pdfjs-editor-delete-comment-popup-button-label = Eliminar comentario
+pdfjs-editor-delete-comment-popup-button =
+ .title = Eliminar comentario
+pdfjs-show-comment-button =
+ .title = Mostrar comentario
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editar comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Actualizar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Agregar comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Agregar
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Empezar a tipear…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancelar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Agregar comentario
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Alternar barra lateral (el documento contiene miniaturas/esquemas/adjuntos/capas)
+pdfjs-toggle-views-manager-button1-label = Administrar páginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionador de barra lateral
+pdfjs-views-manager-view-selector-button =
+ .title = Vistas
+pdfjs-views-manager-view-selector-button-label = Vistas
+pdfjs-views-manager-pages-title = Páginas
+pdfjs-views-manager-outlines-title1 = Esquema del documento
+ .title = Esquema del documento (doble clic para expandir/colapsar todos los ítems)
+pdfjs-views-manager-attachments-title = Adjuntos
+pdfjs-views-manager-layers-title1 = Capas
+ .title = Capas (doble clic para restablecer todas las capas al estado predeterminado)
+pdfjs-views-manager-pages-option-label = Páginas
+pdfjs-views-manager-outlines-option-label = Esquema del documento
+pdfjs-views-manager-attachments-option-label = Adjuntos
+pdfjs-views-manager-layers-option-label = Capas
+pdfjs-views-manager-add-file-button =
+ .title = Agregar archivo
+pdfjs-views-manager-add-file-button-label = Agregar archivo
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } seleccionada
+ *[other] { $count } seleccionadas
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seleccionar páginas
+pdfjs-views-manager-pages-status-action-button-label = Administrar
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Cortar
+pdfjs-views-manager-pages-status-delete-button-label = Borrar
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar seleccionado…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 página cortada
+ *[other] { $count } páginas cortadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 página copiada
+ *[other] { $count } páginas copiadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 página borrada
+ *[other] { $count } páginas borradas
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparando el archivo…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Subiendo el archivo…
+pdfjs-views-manager-status-warning-cut-label = No se pudo cortar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-warning-copy-label = No se pudo copiar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-warning-delete-label = No se pudo borrar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-warning-save-label = No se pudo guardar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-undo-button-label = Deshacer
+pdfjs-views-manager-status-done-button-label = Listo
+pdfjs-views-manager-status-close-button =
+ .title = Cerrar
+pdfjs-views-manager-status-close-button-label = Cerrar
+pdfjs-views-manager-paste-button-label = Pegar
+pdfjs-views-manager-paste-button-before =
+ .title = Pegar antes de la primera página
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Pegar después de la página { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NUEVO
+pdfjs-views-manager-waiting-for-file = Subiendo archivo…
+pdfjs-toggle-views-manager-button1 =
+ .title = Administrar páginas
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Propiedades de firma digital
+ .aria-label = Propiedades de firma digital
+pdfjs-digital-signature-properties-button-label = Propiedades de firma digital
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = El documento fue firmado con una firma digital válida
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Documento firmado pero { $count } firma digital no pudo ser verificada
+ *[other] Documento firmado pero { $count } firmas digitales no pudieron ser verificadas
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Documento firmado con { $count } certificado que no es confiable
+ *[other] Documento firmado con { $count } certificados que no son confiables
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Documento firmado con { $count } certificado expirado
+ *[other] Documento firmado con { $count } certificado expirado
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] El documento tiene { $count } firma digital inválida
+ *[other] El documento tiene { $count } firmas digitales inválidas
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Documento firmado con { $count } certificado revocado
+ *[other] Documento firmado con { $count } certificados revocados
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Estado: Firma verificada
+pdfjs-digital-signature-properties-status-invalid = Estado: Firma inválida
+pdfjs-digital-signature-properties-status-unknown = Estado: No se puede verificar (no soportada)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificado: Confiable ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificado: No disponible
+pdfjs-digital-signature-properties-certificate-untrusted = Certificado: No confiable
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificado: Emisor desconocido ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificado: Autofirmado ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificado: Emisor no confiable ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificado: Vencido
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificado: Vencido ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificado: Revocado
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Eliminar firma guardada
+pdfjs-editor-delete-signature-button-label1 = Eliminar firma guardada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editar descripción
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editar descripción
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-CL/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-CL/viewer.ftl
new file mode 100644
index 0000000..3806a5b
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-CL/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Página siguiente
+pdfjs-next-button-label = Siguiente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Página
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Alejar
+pdfjs-zoom-out-button-label = Alejar
+pdfjs-zoom-in-button =
+ .title = Acercar
+pdfjs-zoom-in-button-label = Acercar
+pdfjs-zoom-select =
+ .title = Ampliación
+pdfjs-presentation-mode-button =
+ .title = Cambiar al modo de presentación
+pdfjs-presentation-mode-button-label = Modo de presentación
+pdfjs-open-file-button =
+ .title = Abrir archivo
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Guardar
+pdfjs-save-button-label = Guardar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Descargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Descargar
+pdfjs-bookmark-button =
+ .title = Página actual (Ver URL de la página actual)
+pdfjs-bookmark-button-label = Página actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Herramientas
+pdfjs-tools-button-label = Herramientas
+pdfjs-first-page-button =
+ .title = Ir a la primera página
+pdfjs-first-page-button-label = Ir a la primera página
+pdfjs-last-page-button =
+ .title = Ir a la última página
+pdfjs-last-page-button-label = Ir a la última página
+pdfjs-page-rotate-cw-button =
+ .title = Girar a la derecha
+pdfjs-page-rotate-cw-button-label = Girar a la derecha
+pdfjs-page-rotate-ccw-button =
+ .title = Girar a la izquierda
+pdfjs-page-rotate-ccw-button-label = Girar a la izquierda
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar la herramienta de selección de texto
+pdfjs-cursor-text-select-tool-button-label = Herramienta de selección de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Activar la herramienta de mano
+pdfjs-cursor-hand-tool-button-label = Herramienta de mano
+pdfjs-scroll-page-button =
+ .title = Usar desplazamiento de página
+pdfjs-scroll-page-button-label = Desplazamiento de página
+pdfjs-scroll-vertical-button =
+ .title = Usar desplazamiento vertical
+pdfjs-scroll-vertical-button-label = Desplazamiento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar desplazamiento horizontal
+pdfjs-scroll-horizontal-button-label = Desplazamiento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar desplazamiento en bloque
+pdfjs-scroll-wrapped-button-label = Desplazamiento en bloque
+pdfjs-spread-none-button =
+ .title = No juntar páginas a modo de libro
+pdfjs-spread-none-button-label = Vista de una página
+pdfjs-spread-odd-button =
+ .title = Junta las páginas partiendo con una de número impar
+pdfjs-spread-odd-button-label = Vista de libro impar
+pdfjs-spread-even-button =
+ .title = Junta las páginas partiendo con una de número par
+pdfjs-spread-even-button-label = Vista de libro par
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedades del documento…
+pdfjs-document-properties-button-label = Propiedades del documento…
+pdfjs-document-properties-file-name = Nombre de archivo:
+pdfjs-document-properties-file-size = Tamaño del archivo:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Asunto:
+pdfjs-document-properties-keywords = Palabras clave:
+pdfjs-document-properties-creation-date = Fecha de creación:
+pdfjs-document-properties-modification-date = Fecha de modificación:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creador:
+pdfjs-document-properties-producer = Productor del PDF:
+pdfjs-document-properties-version = Versión de PDF:
+pdfjs-document-properties-page-count = Cantidad de páginas:
+pdfjs-document-properties-page-size = Tamaño de la página:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Oficio
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista rápida en Web:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Cerrar
+pdfjs-digital-signature-properties-view-certificate = Ver certificado
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Motivo: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Marca de tiempo: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Subfirma ({ $count })
+ *[other] Subfirmas ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparando documento para impresión…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Advertencia: Imprimir no está soportado completamente por este navegador.
+pdfjs-printing-not-ready = Advertencia: El PDF no está completamente cargado para ser impreso.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Cambiar barra lateral (índice de contenidos del documento/adjuntos/capas)
+pdfjs-toggle-sidebar-button-label = Mostrar u ocultar la barra lateral
+pdfjs-document-outline-button =
+ .title = Mostrar esquema del documento (doble clic para expandir/contraer todos los elementos)
+pdfjs-document-outline-button-label = Esquema del documento
+pdfjs-attachments-button =
+ .title = Mostrar adjuntos
+pdfjs-attachments-button-label = Adjuntos
+pdfjs-layers-button =
+ .title = Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado)
+pdfjs-layers-button-label = Capas
+pdfjs-thumbs-button =
+ .title = Mostrar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Buscar elemento de esquema actual
+pdfjs-current-outline-item-button-label = Elemento de esquema actual
+pdfjs-findbar-button =
+ .title = Buscar en el documento
+pdfjs-findbar-button-label = Buscar
+pdfjs-additional-layers = Capas adicionales
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura de la página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Selecciona la página { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Página { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Encontrar
+ .placeholder = Encontrar en el documento…
+pdfjs-find-previous-button =
+ .title = Buscar la aparición anterior de la frase
+pdfjs-find-previous-button-label = Previo
+pdfjs-find-next-button =
+ .title = Buscar la siguiente aparición de la frase
+pdfjs-find-next-button-label = Siguiente
+pdfjs-find-highlight-checkbox = Destacar todos
+pdfjs-find-match-case-checkbox-label = Coincidir mayús./minús.
+pdfjs-find-match-diacritics-checkbox-label = Coincidir diacríticos
+pdfjs-find-entire-word-checkbox-label = Palabras completas
+pdfjs-find-reached-top = Se alcanzó el inicio del documento, continuando desde el final
+pdfjs-find-reached-bottom = Se alcanzó el final del documento, continuando desde el inicio
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] Coincidencia { $current } de { $total }
+ *[other] Coincidencia { $current } de { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Más de { $limit } coincidencia
+ *[other] Más de { $limit } coincidencias
+ }
+pdfjs-find-not-found = Frase no encontrada
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ancho de página
+pdfjs-page-scale-fit = Ajuste de página
+pdfjs-page-scale-auto = Aumento automático
+pdfjs-page-scale-actual = Tamaño actual
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Página { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ocurrió un error al cargar el PDF.
+pdfjs-invalid-file-error = Archivo PDF inválido o corrupto.
+pdfjs-missing-file-error = Falta el archivo PDF.
+pdfjs-unexpected-response-error = Respuesta del servidor inesperada.
+pdfjs-rendering-error = Ocurrió un error al renderizar la página.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Anotación]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Ingresa la contraseña para abrir este archivo PDF.
+pdfjs-password-invalid = Contraseña inválida. Por favor, vuelve a intentarlo.
+pdfjs-password-ok-button = Aceptar
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = Las tipografías web están desactivadas: imposible usar las fuentes PDF embebidas.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambiar color del texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Dibujar
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambiar color del dibujo
+pdfjs-editor-ink-button-label = Dibujar
+pdfjs-editor-stamp-button =
+ .title = Añadir o editar imágenes
+pdfjs-editor-stamp-button-label = Añadir o editar imágenes
+pdfjs-editor-highlight-button =
+ .title = Destacar
+pdfjs-editor-highlight-button-label = Destacar
+pdfjs-highlight-floating-button1 =
+ .title = Destacar
+ .aria-label = Destacar
+pdfjs-highlight-floating-button-label = Destacar
+pdfjs-comment-floating-button =
+ .title = Comentario
+ .aria-label = Comentario
+pdfjs-comment-floating-button-label = Comentario
+pdfjs-editor-comment-button =
+ .title = Comentar
+ .aria-label = Comentar
+pdfjs-editor-comment-button-label = Comentar
+pdfjs-editor-signature-button =
+ .title = Añadir firma
+pdfjs-editor-signature-button-label = Añadir firma
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de destacados
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de dibujos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de firmas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imágenes
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Eliminar dibujo
+pdfjs-editor-remove-freetext-button =
+ .title = Eliminar texto
+pdfjs-editor-remove-stamp-button =
+ .title = Eliminar imagen
+pdfjs-editor-remove-highlight-button =
+ .title = Quitar resaltado
+pdfjs-editor-remove-signature-button =
+ .title = Eliminar firma
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Tamaño
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Grosor
+pdfjs-editor-ink-opacity-input = Opacidad
+pdfjs-editor-stamp-add-image-button =
+ .title = Añadir imagen
+pdfjs-editor-stamp-add-image-button-label = Añadir imagen
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grosor
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Cambia el grosor al resaltar elementos que no sean texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controles de firma y firmas guardadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Añadir nueva firma
+pdfjs-editor-signature-add-signature-button-label = Añadir nueva firma
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firma guardada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Empieza a escribir…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentario
+ *[other] Comentarios
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Cerrar la barra lateral
+ .aria-label = Cerrar la barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Cerrar la barra lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ¿Ves algo interesante? Resáltalo y deja un comentario.
+pdfjs-editor-comments-sidebar-no-comments-link = Más información
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar texto alternativo
+pdfjs-editor-alt-text-dialog-label = Elige una opción
+pdfjs-editor-alt-text-dialog-description = El texto alternativo (alt text) ayuda cuando las personas no pueden ver la imagen o cuando no se carga.
+pdfjs-editor-alt-text-add-description-label = Añade una descripción
+pdfjs-editor-alt-text-add-description-description = Intenta escribir 1 o 2 oraciones que describan el tema, el ambiente o las acciones.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativa
+pdfjs-editor-alt-text-mark-decorative-description = Se utiliza para imágenes ornamentales, como bordes o marcas de agua.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Guardar
+pdfjs-editor-alt-text-decorative-tooltip = Marcada como decorativa
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por ejemplo: “Un joven se sienta a la mesa a comer”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Esquina superior izquierda — cambiar el tamaño
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Borde superior en el medio — cambiar el tamaño
+pdfjs-editor-resizer-top-right =
+ .aria-label = Esquina superior derecha — cambiar el tamaño
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Borde derecho en el medio — cambiar el tamaño
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Esquina inferior derecha — cambiar el tamaño
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Borde inferior en el medio — cambiar el tamaño
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Esquina inferior izquierda — cambiar el tamaño
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Borde izquierdo en el medio — cambiar el tamaño
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color de resaltado
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opciones de color
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarillo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Rojo
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostrar todo
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostrar todo
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descripción de la imagen)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Añadir texto alternativo (descripción de la imagen)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escribe tu descripción aquí…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Breve descripción para las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo fue creado automáticamente y puede ser incorrecto.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Aprender más
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-new-alt-text-not-now-button = Ahora no
+pdfjs-editor-new-alt-text-error-title = No se pudo crear el texto alternativo automáticamente
+pdfjs-editor-new-alt-text-error-description = Escribe tu propio texto alternativo o vuelve a intentarlo más tarde.
+pdfjs-editor-new-alt-text-error-close-button = Cerrar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Descargando el modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Descargando el modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Se añadió el texto alternativo
+pdfjs-editor-new-alt-text-added-button-label = Se añadió el texto alternativo
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Falta el texto alternativo
+pdfjs-editor-new-alt-text-missing-button-label = Falta el texto alternativo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revisar el texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Revisar el texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creado automáticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ajustes del texto alternativo de la imagen
+pdfjs-image-alt-text-settings-button-label = Ajustes del texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-dialog-label = Ajustes del texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-alt-text-settings-create-model-description = Sugiere descripciones para ayudar a las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de IA de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Se ejecuta localmente en tu dispositivo para que tus datos permanezcan privados. Necesario para el texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Eliminar
+pdfjs-editor-alt-text-settings-download-model-button = Descargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Bajando…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar el editor de texto alternativo inmediatamente al añadir una imagen
+pdfjs-editor-alt-text-settings-show-dialog-description = Te ayuda a asegurarte de que todas tus imágenes tengan texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Cerrar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Destacado añadido
+pdfjs-editor-freetext-added-alert = Texto añadido
+pdfjs-editor-ink-added-alert = Dibujo añadido
+pdfjs-editor-stamp-added-alert = Imagen añadida
+pdfjs-editor-signature-added-alert = Firma añadida
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Resaltado eliminado
+pdfjs-editor-undo-bar-message-freetext = Texto eliminado
+pdfjs-editor-undo-bar-message-ink = Dibujo eliminado
+pdfjs-editor-undo-bar-message-stamp = Imagen eliminada
+pdfjs-editor-undo-bar-message-signature = Firma eliminada
+pdfjs-editor-undo-bar-message-comment = Comentario eliminado
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotación eliminada
+ *[other] { $count } anotaciones eliminadas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Deshacer
+pdfjs-editor-undo-bar-undo-button-label = Deshacer
+pdfjs-editor-undo-bar-close-button =
+ .title = Cerrar
+pdfjs-editor-undo-bar-close-button-label = Cerrar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Este modal permite al usuario crear una firma para agregarla a un documento PDF. El usuario puede editar el nombre (que también sirve como texto alternativo) y, opcionalmente, guardar la firma para usarla nuevamente.
+pdfjs-editor-add-signature-dialog-title = Añadir una firma
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Escribir
+ .title = Escribir
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dibujar
+ .title = Dibujar
+pdfjs-editor-add-signature-image-button = Imagen
+ .title = Imagen
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Escribe tu firma
+ .placeholder = Escribe tu firma
+pdfjs-editor-add-signature-draw-placeholder = Dibuja tu firma
+pdfjs-editor-add-signature-draw-thickness-range-label = Grosor
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grosor del dibujo: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arrastre un archivo aquí para cargarlo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] O elige archivos de imagen
+ *[other] O busca archivos de imagen
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Firma
+pdfjs-editor-add-signature-clear-button-label = Limpiar firma
+pdfjs-editor-add-signature-clear-button =
+ .title = Limpiar firma
+pdfjs-editor-add-signature-save-checkbox = Guardar firma
+pdfjs-editor-add-signature-save-warning-message = Has alcanzado el límite de 5 firmas guardadas. Elimina una para guardar más.
+pdfjs-editor-add-signature-image-upload-error-title = No se pudo subir la imagen
+pdfjs-editor-add-signature-image-upload-error-description = Verifica tu conexión de red o prueba con otra imagen.
+pdfjs-editor-add-signature-image-no-data-error-title = No se puede convertir esta imagen en una firma
+pdfjs-editor-add-signature-image-no-data-error-description = Por favor, intenta cargar una imagen diferente.
+pdfjs-editor-add-signature-error-close-button = Cerrar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Añadir
+pdfjs-editor-edit-signature-update-button = Actualizar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editar comentario
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editar comentario
+pdfjs-editor-delete-comment-popup-button-label = Eliminar comentario
+pdfjs-editor-delete-comment-popup-button =
+ .title = Eliminar comentario
+pdfjs-show-comment-button =
+ .title = Mostrar comentario
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editar comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Actualizar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Añadir comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Añadir
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Empieza a escribir…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancelar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Añadir comentario
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Cambiar barra lateral (índice de contenidos del documento/miniaturas/adjuntos/capas)
+pdfjs-toggle-views-manager-button1-label = Gestionar páginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionador de la barra lateral
+pdfjs-views-manager-view-selector-button =
+ .title = Vistas
+pdfjs-views-manager-view-selector-button-label = Vistas
+pdfjs-views-manager-pages-title = Páginas
+pdfjs-views-manager-outlines-title1 = Esquema del documento
+ .title = Esquema del documento (doble clic para expandir/contraer todos los elementos)
+pdfjs-views-manager-attachments-title = Adjuntos
+pdfjs-views-manager-layers-title1 = Capas
+ .title = Capas (doble clic para restablecer todas las capas a su estado predeterminado)
+pdfjs-views-manager-pages-option-label = Páginas
+pdfjs-views-manager-outlines-option-label = Esquema del documento
+pdfjs-views-manager-attachments-option-label = Adjuntos
+pdfjs-views-manager-layers-option-label = Capas
+pdfjs-views-manager-add-file-button =
+ .title = Añadir archivo
+pdfjs-views-manager-add-file-button-label = Añadir archivo
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } seleccionado
+ *[other] { $count } seleccionados
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seleccionar páginas
+pdfjs-views-manager-pages-status-action-button-label = Administrar
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Cortar
+pdfjs-views-manager-pages-status-delete-button-label = Eliminar
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar selección…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 página cortada
+ *[other] { $count } páginas cortadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 página copiada
+ *[other] { $count } páginas copiadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 página eliminada
+ *[other] { $count } páginas eliminadas
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparando tu archivo…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Subiendo archivo…
+pdfjs-views-manager-status-warning-cut-label = No se pudo cortar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-warning-copy-label = No se pudo copiar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-warning-delete-label = No se pudo eliminar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-warning-save-label = No se pudo guardar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-undo-button-label = Deshacer
+pdfjs-views-manager-status-done-button-label = Hecho
+pdfjs-views-manager-status-close-button =
+ .title = Cerrar
+pdfjs-views-manager-status-close-button-label = Cerrar
+pdfjs-views-manager-paste-button-label = Pegar
+pdfjs-views-manager-paste-button-before =
+ .title = Pegar antes de la primera página
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Pegar después de la página { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NUEVO
+pdfjs-views-manager-waiting-for-file = Subiendo archivo…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gestionar páginas
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Propiedades de firma digital
+ .aria-label = Propiedades de firma digital
+pdfjs-digital-signature-properties-button-label = Propiedades de firma digital
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = El documento fue firmado con una firma digital válida
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Documento firmado, pero no se pudo verificar la firma digital
+ *[other] Documento firmado, pero no se pudieron verificar las { $count } firmas digitales
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Documento firmado con { $count } certificado que no es de confianza
+ *[other] Documento firmado con { $count } certificados que no son de confianza
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Documento firmado con { $count } certificado expirado
+ *[other] Documento firmado con { $count } certificados expirados
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] El documento tiene { $count } firma digital no válida
+ *[other] El documento tiene { $count } firmas digitales no válidas
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Documento firmado con { $count } certificado revocado
+ *[other] Documento firmado con { $count } certificados revocados
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Estado: Firma verificada
+pdfjs-digital-signature-properties-status-invalid = Estado: Firma inválida
+pdfjs-digital-signature-properties-status-unknown = Estado: No se puede verificar (no compatible)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificado: Confiable ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificado: No disponible
+pdfjs-digital-signature-properties-certificate-untrusted = Certificado: No confiable
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificado: Emisor desconocido ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificado: Autofirmado ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificado: Emisor no confiable ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificado: Expirado
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificado: Expirado ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificado: Revocado
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Eliminar firma guardada
+pdfjs-editor-delete-signature-button-label1 = Eliminar firma guardada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editar descripción
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editar descripción
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-ES/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-ES/viewer.ftl
new file mode 100644
index 0000000..d69a4ab
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-ES/viewer.ftl
@@ -0,0 +1,747 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Página siguiente
+pdfjs-next-button-label = Siguiente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Página
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Reducir
+pdfjs-zoom-out-button-label = Reducir
+pdfjs-zoom-in-button =
+ .title = Aumentar
+pdfjs-zoom-in-button-label = Aumentar
+pdfjs-zoom-select =
+ .title = Tamaño
+pdfjs-presentation-mode-button =
+ .title = Cambiar al modo presentación
+pdfjs-presentation-mode-button-label = Modo presentación
+pdfjs-open-file-button =
+ .title = Abrir archivo
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Guardar
+pdfjs-save-button-label = Guardar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Descargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Descargar
+pdfjs-bookmark-button =
+ .title = Página actual (Ver URL de la página actual)
+pdfjs-bookmark-button-label = Página actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Herramientas
+pdfjs-tools-button-label = Herramientas
+pdfjs-first-page-button =
+ .title = Ir a la primera página
+pdfjs-first-page-button-label = Ir a la primera página
+pdfjs-last-page-button =
+ .title = Ir a la última página
+pdfjs-last-page-button-label = Ir a la última página
+pdfjs-page-rotate-cw-button =
+ .title = Rotar en sentido horario
+pdfjs-page-rotate-cw-button-label = Rotar en sentido horario
+pdfjs-page-rotate-ccw-button =
+ .title = Rotar en sentido antihorario
+pdfjs-page-rotate-ccw-button-label = Rotar en sentido antihorario
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar herramienta de selección de texto
+pdfjs-cursor-text-select-tool-button-label = Herramienta de selección de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Activar herramienta de mano
+pdfjs-cursor-hand-tool-button-label = Herramienta de mano
+pdfjs-scroll-page-button =
+ .title = Usar desplazamiento de página
+pdfjs-scroll-page-button-label = Desplazamiento de página
+pdfjs-scroll-vertical-button =
+ .title = Usar desplazamiento vertical
+pdfjs-scroll-vertical-button-label = Desplazamiento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar desplazamiento horizontal
+pdfjs-scroll-horizontal-button-label = Desplazamiento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar desplazamiento en bloque
+pdfjs-scroll-wrapped-button-label = Desplazamiento en bloque
+pdfjs-spread-none-button =
+ .title = No juntar páginas en vista de libro
+pdfjs-spread-none-button-label = Vista de libro
+pdfjs-spread-odd-button =
+ .title = Juntar las páginas partiendo de una con número impar
+pdfjs-spread-odd-button-label = Vista de libro impar
+pdfjs-spread-even-button =
+ .title = Juntar las páginas partiendo de una con número par
+pdfjs-spread-even-button-label = Vista de libro par
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedades del documento…
+pdfjs-document-properties-button-label = Propiedades del documento…
+pdfjs-document-properties-file-name = Nombre de archivo:
+pdfjs-document-properties-file-size = Tamaño de archivo:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Asunto:
+pdfjs-document-properties-keywords = Palabras clave:
+pdfjs-document-properties-creation-date = Fecha de creación:
+pdfjs-document-properties-modification-date = Fecha de modificación:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creador:
+pdfjs-document-properties-producer = Productor PDF:
+pdfjs-document-properties-version = Versión PDF:
+pdfjs-document-properties-page-count = Número de páginas:
+pdfjs-document-properties-page-size = Tamaño de la página:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista rápida de la web:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Cerrar
+
+## Print
+
+pdfjs-print-progress-message = Preparando documento para impresión…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Advertencia: Imprimir no está totalmente soportado por este navegador.
+pdfjs-printing-not-ready = Advertencia: Este PDF no se ha cargado completamente para poder imprimirse.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Cambiar barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Alternar barra lateral (el documento contiene esquemas/adjuntos/capas)
+pdfjs-toggle-sidebar-button-label = Cambiar barra lateral
+pdfjs-document-outline-button =
+ .title = Mostrar resumen del documento (doble clic para expandir/contraer todos los elementos)
+pdfjs-document-outline-button-label = Resumen de documento
+pdfjs-attachments-button =
+ .title = Mostrar adjuntos
+pdfjs-attachments-button-label = Adjuntos
+pdfjs-layers-button =
+ .title = Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado)
+pdfjs-layers-button-label = Capas
+pdfjs-thumbs-button =
+ .title = Mostrar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Encontrar elemento de esquema actual
+pdfjs-current-outline-item-button-label = Elemento de esquema actual
+pdfjs-findbar-button =
+ .title = Buscar en el documento
+pdfjs-findbar-button-label = Buscar
+pdfjs-additional-layers = Capas adicionales
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura de la página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seleccionar página { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Página { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Buscar
+ .placeholder = Buscar en el documento…
+pdfjs-find-previous-button =
+ .title = Encontrar la anterior aparición de la frase
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Encontrar la siguiente aparición de esta frase
+pdfjs-find-next-button-label = Siguiente
+pdfjs-find-highlight-checkbox = Resaltar todos
+pdfjs-find-match-case-checkbox-label = Coincidencia de mayús./minús.
+pdfjs-find-match-diacritics-checkbox-label = Coincidir diacríticos
+pdfjs-find-entire-word-checkbox-label = Palabras completas
+pdfjs-find-reached-top = Se alcanzó el inicio del documento, se continúa desde el final
+pdfjs-find-reached-bottom = Se alcanzó el final del documento, se continúa desde el inicio
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } de { $total } coincidencia
+ *[other] { $current } de { $total } coincidencias
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Más de { $limit } coincidencia
+ *[other] Más de { $limit } coincidencias
+ }
+pdfjs-find-not-found = Frase no encontrada
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Anchura de la página
+pdfjs-page-scale-fit = Ajuste de la página
+pdfjs-page-scale-auto = Tamaño automático
+pdfjs-page-scale-actual = Tamaño real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Página { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ocurrió un error al cargar el PDF.
+pdfjs-invalid-file-error = Fichero PDF no válido o corrupto.
+pdfjs-missing-file-error = No hay fichero PDF.
+pdfjs-unexpected-response-error = Respuesta inesperada del servidor.
+pdfjs-rendering-error = Ocurrió un error al renderizar la página.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotación { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Introduzca la contraseña para abrir este archivo PDF.
+pdfjs-password-invalid = Contraseña no válida. Vuelva a intentarlo.
+pdfjs-password-ok-button = Aceptar
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = Las tipografías web están desactivadas: es imposible usar las tipografías PDF embebidas.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambiar el color del texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Dibujar
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambiar el color del dibujo
+pdfjs-editor-ink-button-label = Dibujar
+pdfjs-editor-stamp-button =
+ .title = Añadir o editar imágenes
+pdfjs-editor-stamp-button-label = Añadir o editar imágenes
+pdfjs-editor-highlight-button =
+ .title = Resaltar
+pdfjs-editor-highlight-button-label = Resaltar
+pdfjs-highlight-floating-button1 =
+ .title = Resaltar
+ .aria-label = Resaltar
+pdfjs-highlight-floating-button-label = Resaltar
+pdfjs-comment-floating-button =
+ .title = Comentario
+ .aria-label = Comentario
+pdfjs-comment-floating-button-label = Comentario
+pdfjs-editor-comment-button =
+ .title = Comentario
+ .aria-label = Comentario
+pdfjs-editor-comment-button-label = Comentario
+pdfjs-editor-signature-button =
+ .title = Añadir firma
+pdfjs-editor-signature-button-label = Añadir firma
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de resaltado
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de dibujos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de firmas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imágenes
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Eliminar dibujo
+pdfjs-editor-remove-freetext-button =
+ .title = Eliminar texto
+pdfjs-editor-remove-stamp-button =
+ .title = Eliminar imagen
+pdfjs-editor-remove-highlight-button =
+ .title = Quitar resaltado
+pdfjs-editor-remove-signature-button =
+ .title = Eliminar firma
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Tamaño
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Grosor
+pdfjs-editor-ink-opacity-input = Opacidad
+pdfjs-editor-stamp-add-image-button =
+ .title = Añadir imagen
+pdfjs-editor-stamp-add-image-button-label = Añadir imagen
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grosor
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Cambiar el grosor al resaltar elementos que no sean texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controles de firma y firmas guardadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Añadir nueva firma
+pdfjs-editor-signature-add-signature-button-label = Añadir nueva firma
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firma guardada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Empiece a escribir…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentario
+ *[other] Comentarios
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Cerrar la barra lateral
+ .aria-label = Cerrar la barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Cerrar la barra lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ¿Ve algo interesante? Resáltelo y deje un comentario.
+pdfjs-editor-comments-sidebar-no-comments-link = Saber más
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar el texto alternativo
+pdfjs-editor-alt-text-dialog-label = Elegir una opción
+pdfjs-editor-alt-text-dialog-description = El texto alternativo ayuda cuando las personas no pueden ver la imagen o cuando no se carga.
+pdfjs-editor-alt-text-add-description-label = Añadir una descripción
+pdfjs-editor-alt-text-add-description-description = Intente escribir 1 o 2 frases que describan el tema, el entorno o las acciones.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativa
+pdfjs-editor-alt-text-mark-decorative-description = Se utiliza para imágenes ornamentales, como bordes o marcas de agua.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Guardar
+pdfjs-editor-alt-text-decorative-tooltip = Marcada como decorativa
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por ejemplo: “Un joven se sienta a la mesa a comer”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Esquina superior izquierda — redimensionar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Borde superior en el medio — redimensionar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Esquina superior derecha — redimensionar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Borde derecho en el medio — redimensionar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Esquina inferior derecha — redimensionar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Borde inferior en el medio — redimensionar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Esquina inferior izquierda — redimensionar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Borde izquierdo en el medio — redimensionar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color de resaltado
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opciones de color
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarillo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Rojo
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostrar todo
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostrar todo
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descripción de la imagen)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Añadir texto alternativo (descripción de la imagen)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escribir la descripción aquí…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Breve descripción para las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo fue creado automáticamente y puede ser inexacto.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Saber más
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-new-alt-text-not-now-button = Ahora no
+pdfjs-editor-new-alt-text-error-title = No se ha podido crear el texto alternativo automáticamente
+pdfjs-editor-new-alt-text-error-description = Escriba su propio texto alternativo o inténtelo de nuevo más tarde.
+pdfjs-editor-new-alt-text-error-close-button = Cerrar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Descargando el modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Descargando el modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Se añadió el texto alternativo
+pdfjs-editor-new-alt-text-added-button-label = Se añadió el texto alternativo
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Falta el texto alternativo
+pdfjs-editor-new-alt-text-missing-button-label = Falta el texto alternativo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revisar el texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Revisar el texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creado automáticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ajustes del texto alternativo de la imagen
+pdfjs-image-alt-text-settings-button-label = Ajustes del texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-dialog-label = Ajustes del texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-alt-text-settings-create-model-description = Sugiere descripciones para ayudar a las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de IA de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Se ejecuta localmente en el dispositivo para que los datos se mantengan privados. Requerido para texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Eliminar
+pdfjs-editor-alt-text-settings-download-model-button = Descargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Descargando…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar el editor de texto alternativo inmediatamente al añadir una imagen
+pdfjs-editor-alt-text-settings-show-dialog-description = Le ayuda a asegurarse de que todas sus imágenes tengan texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Cerrar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Resaltado añadido
+pdfjs-editor-freetext-added-alert = Texto añadido
+pdfjs-editor-ink-added-alert = Dibujo añadido
+pdfjs-editor-stamp-added-alert = Imagen añadida
+pdfjs-editor-signature-added-alert = Firma añadida
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Resaltado eliminado
+pdfjs-editor-undo-bar-message-freetext = Texto eliminado
+pdfjs-editor-undo-bar-message-ink = Dibujo eliminado
+pdfjs-editor-undo-bar-message-stamp = Imagen eliminada
+pdfjs-editor-undo-bar-message-signature = Firma eliminada
+pdfjs-editor-undo-bar-message-comment = Comentario eliminado
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotación eliminada
+ *[other] { $count } anotaciones eliminadas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Deshacer
+pdfjs-editor-undo-bar-undo-button-label = Deshacer
+pdfjs-editor-undo-bar-close-button =
+ .title = Cerrar
+pdfjs-editor-undo-bar-close-button-label = Cerrar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Este modal permite al usuario crear una firma para añadirla a un documento PDF. El usuario puede editar el nombre (que también sirve como texto alternativo) y, opcionalmente, guardar la firma para usarla nuevamente.
+pdfjs-editor-add-signature-dialog-title = Añadir una firma
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Escribir
+ .title = Escribir
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dibujar
+ .title = Dibujar
+pdfjs-editor-add-signature-image-button = Imagen
+ .title = Imagen
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Escriba su firma
+ .placeholder = Escriba su firma
+pdfjs-editor-add-signature-draw-placeholder = Dibuje su firma
+pdfjs-editor-add-signature-draw-thickness-range-label = Grosor
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grosor del dibujo: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arrastre un archivo aquí para cargarlo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] O seleccione archivos de imágenes
+ *[other] O seleccione archivos de imágenes
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Firma
+pdfjs-editor-add-signature-clear-button-label = Borrar firma
+pdfjs-editor-add-signature-clear-button =
+ .title = Borrar firma
+pdfjs-editor-add-signature-save-checkbox = Guardar firma
+pdfjs-editor-add-signature-save-warning-message = Ha alcanzado el límite de 5 firmas guardadas. Elimine una para guardar más.
+pdfjs-editor-add-signature-image-upload-error-title = No se ha podido subir la imagen
+pdfjs-editor-add-signature-image-upload-error-description = Compruebe su conexión de red o pruebe con otra imagen.
+pdfjs-editor-add-signature-image-no-data-error-title = No se puede convertir esta imagen en una firma
+pdfjs-editor-add-signature-image-no-data-error-description = Por favor, intente cargar una imagen diferente.
+pdfjs-editor-add-signature-error-close-button = Cerrar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Añadir
+pdfjs-editor-edit-signature-update-button = Actualizar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editar comentario
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editar comentario
+pdfjs-editor-delete-comment-popup-button-label = Eliminar comentario
+pdfjs-editor-delete-comment-popup-button =
+ .title = Eliminar comentario
+pdfjs-show-comment-button =
+ .title = Mostrar comentario
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editar comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Actualizar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Añadir comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Añadir
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Empezar a escribir…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancelar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Añadir comentario
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Alternar barra lateral (el documento contiene miniaturas/esquemas/adjuntos/capas)
+pdfjs-toggle-views-manager-button1-label = Administrar páginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionador de la barra lateral
+pdfjs-views-manager-view-selector-button =
+ .title = Vistas
+pdfjs-views-manager-view-selector-button-label = Vistas
+pdfjs-views-manager-pages-title = Páginas
+pdfjs-views-manager-outlines-title1 = Esquema del documento
+ .title = Esquema del documento (doble-clic para expandir/contraer todos los elementos)
+pdfjs-views-manager-attachments-title = Adjuntos
+pdfjs-views-manager-layers-title1 = Capas
+ .title = Capas (doble clic para restablecer todas las capas a su estado predeterminado)
+pdfjs-views-manager-pages-option-label = Páginas
+pdfjs-views-manager-outlines-option-label = Esquema del documento
+pdfjs-views-manager-attachments-option-label = Adjuntos
+pdfjs-views-manager-layers-option-label = Capas
+pdfjs-views-manager-add-file-button =
+ .title = Añadir archivo
+pdfjs-views-manager-add-file-button-label = Añadir archivo
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } seleccionado
+ *[other] { $count } seleccionados
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seleccionar páginas
+pdfjs-views-manager-pages-status-action-button-label = Administrar
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Cortar
+pdfjs-views-manager-pages-status-delete-button-label = Eliminar
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar selección…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 página cortada
+ *[other] { $count } páginas cortadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 página copiada
+ *[other] { $count } páginas copiadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 página eliminada
+ *[other] { $count } páginas eliminadas
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparando su archivo…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Subiendo el archivo…
+pdfjs-views-manager-status-warning-cut-label = No se pudo cortar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-warning-copy-label = No se pudo copiar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-warning-delete-label = No se pudo eliminar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-warning-save-label = No se pudo guardar. Refresque la página y pruebe de nuevo.
+pdfjs-views-manager-status-undo-button-label = Deshacer
+pdfjs-views-manager-status-done-button-label = Hecho
+pdfjs-views-manager-status-close-button =
+ .title = Cerrar
+pdfjs-views-manager-status-close-button-label = Cerrar
+pdfjs-views-manager-paste-button-label = Pegar
+pdfjs-views-manager-paste-button-before =
+ .title = Pegar antes de la primera página
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Pegar después de la página { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NUEVO
+pdfjs-views-manager-waiting-for-file = Subiendo el archivo…
+pdfjs-toggle-views-manager-button1 =
+ .title = Administrar páginas
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Eliminar firma guardada
+pdfjs-editor-delete-signature-button-label1 = Eliminar firma guardada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editar descripción
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editar descripción
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-MX/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-MX/viewer.ftl
new file mode 100644
index 0000000..987dd98
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/es-MX/viewer.ftl
@@ -0,0 +1,748 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Página siguiente
+pdfjs-next-button-label = Siguiente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Página
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Reducir
+pdfjs-zoom-out-button-label = Reducir
+pdfjs-zoom-in-button =
+ .title = Aumentar
+pdfjs-zoom-in-button-label = Aumentar
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Cambiar al modo presentación
+pdfjs-presentation-mode-button-label = Modo presentación
+pdfjs-open-file-button =
+ .title = Abrir archivo
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Guardar
+pdfjs-save-button-label = Guardar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Descargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Descargar
+pdfjs-bookmark-button =
+ .title = Página actual (Ver URL de la página actual)
+pdfjs-bookmark-button-label = Página actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Herramientas
+pdfjs-tools-button-label = Herramientas
+pdfjs-first-page-button =
+ .title = Ir a la primera página
+pdfjs-first-page-button-label = Ir a la primera página
+pdfjs-last-page-button =
+ .title = Ir a la última página
+pdfjs-last-page-button-label = Ir a la última página
+pdfjs-page-rotate-cw-button =
+ .title = Girar a la derecha
+pdfjs-page-rotate-cw-button-label = Girar a la derecha
+pdfjs-page-rotate-ccw-button =
+ .title = Girar a la izquierda
+pdfjs-page-rotate-ccw-button-label = Girar a la izquierda
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar la herramienta de selección de texto
+pdfjs-cursor-text-select-tool-button-label = Herramienta de selección de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Activar la herramienta de mano
+pdfjs-cursor-hand-tool-button-label = Herramienta de mano
+pdfjs-scroll-page-button =
+ .title = Usar desplazamiento de página
+pdfjs-scroll-page-button-label = Desplazamiento de página
+pdfjs-scroll-vertical-button =
+ .title = Usar desplazamiento vertical
+pdfjs-scroll-vertical-button-label = Desplazamiento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar desplazamiento horizontal
+pdfjs-scroll-horizontal-button-label = Desplazamiento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar desplazamiento encapsulado
+pdfjs-scroll-wrapped-button-label = Desplazamiento encapsulado
+pdfjs-spread-none-button =
+ .title = No unir páginas separadas
+pdfjs-spread-none-button-label = Vista de una página
+pdfjs-spread-odd-button =
+ .title = Unir las páginas partiendo con una de número impar
+pdfjs-spread-odd-button-label = Vista de libro impar
+pdfjs-spread-even-button =
+ .title = Juntar las páginas partiendo con una de número par
+pdfjs-spread-even-button-label = Vista de libro par
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedades del documento…
+pdfjs-document-properties-button-label = Propiedades del documento…
+pdfjs-document-properties-file-name = Nombre del archivo:
+pdfjs-document-properties-file-size = Tamaño del archivo:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Asunto:
+pdfjs-document-properties-keywords = Palabras claves:
+pdfjs-document-properties-creation-date = Fecha de creación:
+pdfjs-document-properties-modification-date = Fecha de modificación:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creador:
+pdfjs-document-properties-producer = Productor PDF:
+pdfjs-document-properties-version = Versión PDF:
+pdfjs-document-properties-page-count = Número de páginas:
+pdfjs-document-properties-page-size = Tamaño de la página:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Oficio
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista rápida de la web:
+pdfjs-document-properties-linearized-yes = Sí
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Cerrar
+pdfjs-digital-signature-properties-view-certificate = Ver certificado
+
+## Print
+
+pdfjs-print-progress-message = Preparando documento para impresión…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Advertencia: La impresión no está completamente soportada por este navegador.
+pdfjs-printing-not-ready = Advertencia: El PDF no cargó completamente para impresión.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Cambiar barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Alternar barra lateral (el documento contiene esquemas/adjuntos/capas)
+pdfjs-toggle-sidebar-button-label = Cambiar barra lateral
+pdfjs-document-outline-button =
+ .title = Mostrar esquema del documento (doble clic para expandir/contraer todos los elementos)
+pdfjs-document-outline-button-label = Esquema del documento
+pdfjs-attachments-button =
+ .title = Mostrar adjuntos
+pdfjs-attachments-button-label = Adjuntos
+pdfjs-layers-button =
+ .title = Mostrar capas (doble clic para restablecer todas las capas al estado predeterminado)
+pdfjs-layers-button-label = Capas
+pdfjs-thumbs-button =
+ .title = Mostrar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Buscar elemento de esquema actual
+pdfjs-current-outline-item-button-label = Elemento de esquema actual
+pdfjs-findbar-button =
+ .title = Buscar en el documento
+pdfjs-findbar-button-label = Buscar
+pdfjs-additional-layers = Capas adicionales
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura de la página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seleccionar página { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Página { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Buscar
+ .placeholder = Buscar en el documento…
+pdfjs-find-previous-button =
+ .title = Ir a la anterior frase encontrada
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Ir a la siguiente frase encontrada
+pdfjs-find-next-button-label = Siguiente
+pdfjs-find-highlight-checkbox = Resaltar todo
+pdfjs-find-match-case-checkbox-label = Coincidir con mayúsculas y minúsculas
+pdfjs-find-match-diacritics-checkbox-label = Coincidir diacríticos
+pdfjs-find-entire-word-checkbox-label = Palabras completas
+pdfjs-find-reached-top = Se alcanzó el inicio del documento, se buscará al final
+pdfjs-find-reached-bottom = Se alcanzó el final del documento, se buscará al inicio
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } de { $total } coincidencia
+ *[other] { $current } de { $total } coincidencias
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Más de { $limit } coincidencia
+ *[other] Más de { $limit } coincidencias
+ }
+pdfjs-find-not-found = No se encontró la frase
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ancho de página
+pdfjs-page-scale-fit = Ajustar página
+pdfjs-page-scale-auto = Zoom automático
+pdfjs-page-scale-actual = Tamaño real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Página { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Un error ocurrió al cargar el PDF.
+pdfjs-invalid-file-error = Archivo PDF inválido o dañado.
+pdfjs-missing-file-error = Archivo PDF no encontrado.
+pdfjs-unexpected-response-error = Respuesta inesperada del servidor.
+pdfjs-rendering-error = Un error ocurrió al renderizar la página.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } anotación]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Ingresa la contraseña para abrir este archivo PDF.
+pdfjs-password-invalid = Contraseña inválida. Por favor intenta de nuevo.
+pdfjs-password-ok-button = Aceptar
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = Las fuentes web están desactivadas: es imposible usar las fuentes PDF embebidas.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambiar el color del texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Dibujar
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambiar el color del dibujo
+pdfjs-editor-ink-button-label = Dibujar
+pdfjs-editor-stamp-button =
+ .title = Agregar o editar imágenes
+pdfjs-editor-stamp-button-label = Agregar o editar imágenes
+pdfjs-editor-highlight-button =
+ .title = Destacar
+pdfjs-editor-highlight-button-label = Destacar
+pdfjs-highlight-floating-button1 =
+ .title = Destacados
+ .aria-label = Destacados
+pdfjs-highlight-floating-button-label = Destacados
+pdfjs-comment-floating-button =
+ .title = Comentario
+ .aria-label = Comentario
+pdfjs-comment-floating-button-label = Comentario
+pdfjs-editor-comment-button =
+ .title = Comentario
+ .aria-label = Comentario
+pdfjs-editor-comment-button-label = Comentario
+pdfjs-editor-signature-button =
+ .title = Agregar firma
+pdfjs-editor-signature-button-label = Añadir firma
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de destacados
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de dibujos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de firmas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imágenes
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Eliminar dibujo
+pdfjs-editor-remove-freetext-button =
+ .title = Eliminar texto
+pdfjs-editor-remove-stamp-button =
+ .title = Eliminar imagen
+pdfjs-editor-remove-highlight-button =
+ .title = Eliminar destacado
+pdfjs-editor-remove-signature-button =
+ .title = Eliminar firma
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Tamaño
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Grosor
+pdfjs-editor-ink-opacity-input = Opacidad
+pdfjs-editor-stamp-add-image-button =
+ .title = Agregar imagen
+pdfjs-editor-stamp-add-image-button-label = Agregar imagen
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Espesor
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Cambiar el grosor al resaltar elementos que no sean texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controles de firma y firmas guardadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Agregar nueva firma
+pdfjs-editor-signature-add-signature-button-label = Agregar nueva firma
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firma guardada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Comenzar a escribir…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentario
+ *[other] Comentarios
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Cerrar la barra lateral
+ .aria-label = Cerrar la barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Cerrar la barra lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ¿Ves algo interesante? Resáltalo y deja un comentario.
+pdfjs-editor-comments-sidebar-no-comments-link = Saber más
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar texto alternativo
+pdfjs-editor-alt-text-dialog-label = Elige una opción
+pdfjs-editor-alt-text-dialog-description = El texto alternativo (texto alternativo) ayuda cuando las personas no pueden ver la imagen o cuando no se carga.
+pdfjs-editor-alt-text-add-description-label = Añadir una descripción
+pdfjs-editor-alt-text-add-description-description = Intente escribir 1 o 2 oraciones que describan el tema, el entorno o las acciones.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativo
+pdfjs-editor-alt-text-mark-decorative-description = Se utiliza para imágenes ornamentales, como bordes o marcas de agua.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Guardar
+pdfjs-editor-alt-text-decorative-tooltip = Marcado como decorativo
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por ejemplo: “Un joven se sienta a la mesa a comer”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Esquina superior izquierda — redimensionar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Borde superior en el medio — redimensionar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Esquina superior derecha — redimensionar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Borde derecho en el medio — redimensionar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Esquina inferior derecha — redimensionar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Borde inferior en el medio — redimensionar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Esquina inferior izquierda — redimensionar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Borde izquierdo en el medio — redimensionar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color de resaltado
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opciones de color
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarillo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Rojo
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostrar todo
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostrar todo
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descripción de la imagen)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Agregar texto alternativo (descripción de la imagen)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escribe tu descripción aquí…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Breve descripción para las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo fue creado automáticamente y puede ser inexacto.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Saber más
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-new-alt-text-not-now-button = Ahora no
+pdfjs-editor-new-alt-text-error-title = No se pudo crear el texto alternativo automáticamente
+pdfjs-editor-new-alt-text-error-description = Escribe tu propio texto alternativo o inténtalo de nuevo más tarde.
+pdfjs-editor-new-alt-text-error-close-button = Cerrar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Descargando el modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Descargando el modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Se agregó el texto alternativo
+pdfjs-editor-new-alt-text-added-button-label = Se agregó el texto alternativo
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Falta el texto alternativo
+pdfjs-editor-new-alt-text-missing-button-label = Falta texto alternativo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revisar el texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Revisar el texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creado automáticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ajustes del texto alternativo de la imagen
+pdfjs-image-alt-text-settings-button-label = Ajustes del texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-dialog-label = Ajustes del texto alternativo de la imagen
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear texto alternativo automáticamente
+pdfjs-editor-alt-text-settings-create-model-description = Sugiere descripciones para ayudar a las personas que no pueden ver la imagen o cuando la imagen no se carga.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de IA de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Se ejecuta localmente en el dispositivo para que los datos se mantengan privados. Requerido para texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Eliminar
+pdfjs-editor-alt-text-settings-download-model-button = Descargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Descargando…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar el editor de texto alternativo inmediatamente al añadir una imagen
+pdfjs-editor-alt-text-settings-show-dialog-description = Te ayuda a asegurarte de que todas tus imágenes tengan texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Cerrar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Destacado añadido
+pdfjs-editor-freetext-added-alert = Texto agregado
+pdfjs-editor-ink-added-alert = Dibujo agregado
+pdfjs-editor-stamp-added-alert = Imagen agregada
+pdfjs-editor-signature-added-alert = Firma agregada
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Resaltado eliminado
+pdfjs-editor-undo-bar-message-freetext = Texto eliminado
+pdfjs-editor-undo-bar-message-ink = Dibujo eliminado
+pdfjs-editor-undo-bar-message-stamp = Imagen eliminada
+pdfjs-editor-undo-bar-message-signature = Firma eliminada
+pdfjs-editor-undo-bar-message-comment = Comentario eliminado
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotación eliminada
+ *[other] { $count } anotaciones eliminadas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Deshacer
+pdfjs-editor-undo-bar-undo-button-label = Deshacer
+pdfjs-editor-undo-bar-close-button =
+ .title = Cerrar
+pdfjs-editor-undo-bar-close-button-label = Cerrar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Este modal permite al usuario crear una firma para añadirla a un documento PDF. El usuario puede editar el nombre (que también sirve como texto alternativo) y, opcionalmente, guardar la firma para utilizarla en otras ocasiones.
+pdfjs-editor-add-signature-dialog-title = Agregar una firma
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tipo
+ .title = Tipo
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dibujar
+ .title = Dibujar
+pdfjs-editor-add-signature-image-button = Imagen
+ .title = Imagen
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Escribe tu firma
+ .placeholder = Escribe tu firma
+pdfjs-editor-add-signature-draw-placeholder = Dibuja tu firma
+pdfjs-editor-add-signature-draw-thickness-range-label = Grosor
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grosor del dibujo: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arrastra un archivo aquí para cargarlo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] O elegir archivos de imagen
+ *[other] O buscar archivos de imagen
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descripción (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Firma
+pdfjs-editor-add-signature-clear-button-label = Limpiar firma
+pdfjs-editor-add-signature-clear-button =
+ .title = Limpiar firma
+pdfjs-editor-add-signature-save-checkbox = Guardar firma
+pdfjs-editor-add-signature-save-warning-message = Has alcanzado el límite de 5 firmas guardadas. Elimina una para guardar más.
+pdfjs-editor-add-signature-image-upload-error-title = No se pudo cargar la imagen
+pdfjs-editor-add-signature-image-upload-error-description = Verifica tu conexión de red o prueba con otra imagen.
+pdfjs-editor-add-signature-image-no-data-error-title = No se puede convertir esta imagen en una firma
+pdfjs-editor-add-signature-image-no-data-error-description = Intenta cargar una imagen diferente.
+pdfjs-editor-add-signature-error-close-button = Cerrar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Agregar
+pdfjs-editor-edit-signature-update-button = Actualizar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editar comentario
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editar comentario
+pdfjs-editor-delete-comment-popup-button-label = Eliminar comentario
+pdfjs-editor-delete-comment-popup-button =
+ .title = Eliminar comentario
+pdfjs-show-comment-button =
+ .title = Mostrar comentario
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editar comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Actualizar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Agregar comentario
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Agregar
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Empieza a escribir…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancelar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Añadir comentario
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Cambiar barra lateral (índice de contenidos del documento/miniaturas/adjuntos/capas)
+pdfjs-toggle-views-manager-button1-label = Administrar páginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Cambiar tamaño de la barra lateral
+pdfjs-views-manager-view-selector-button =
+ .title = Vistas
+pdfjs-views-manager-view-selector-button-label = Vistas
+pdfjs-views-manager-pages-title = Páginas
+pdfjs-views-manager-outlines-title1 = Esquema del documento
+ .title = Esquema del documento (haz doble clic para expandir/contraer todos los elementos)
+pdfjs-views-manager-attachments-title = Adjuntos
+pdfjs-views-manager-layers-title1 = Capas
+ .title = Capas (haz doble clic para restablecer todas las capas a su estado predeterminado)
+pdfjs-views-manager-pages-option-label = Páginas
+pdfjs-views-manager-outlines-option-label = Esquema del documento
+pdfjs-views-manager-attachments-option-label = Adjuntos
+pdfjs-views-manager-layers-option-label = Capas
+pdfjs-views-manager-add-file-button =
+ .title = Agregar archivo
+pdfjs-views-manager-add-file-button-label = Agregar archivo
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } seleccionado
+ *[other] { $count } seleccionados
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seleccionar páginas
+pdfjs-views-manager-pages-status-action-button-label = Administrar
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Cortar
+pdfjs-views-manager-pages-status-delete-button-label = Eliminar
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar seleccionado…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 página cortada
+ *[other] { $count } páginas cortadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 página copiada
+ *[other] { $count } páginas copiadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 página eliminada
+ *[other] { $count } páginas eliminadas
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparando tu archivo…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Subiendo archivo…
+pdfjs-views-manager-status-warning-cut-label = No se pudo cortar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-warning-copy-label = No se pudo pegar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-warning-delete-label = No se pudo eliminar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-warning-save-label = No se pudo guardar. Actualiza la página y vuelve a intentarlo.
+pdfjs-views-manager-status-undo-button-label = Deshacer
+pdfjs-views-manager-status-done-button-label = Hecho
+pdfjs-views-manager-status-close-button =
+ .title = Cerrar
+pdfjs-views-manager-status-close-button-label = Cerrar
+pdfjs-views-manager-paste-button-label = Pegar
+pdfjs-views-manager-paste-button-before =
+ .title = Pegar antes de la primera página
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Pegar después de la página { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NUEVO
+pdfjs-views-manager-waiting-for-file = Subiendo archivo…
+pdfjs-toggle-views-manager-button1 =
+ .title = Administrar páginas
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Eliminar la firma guardada
+pdfjs-editor-delete-signature-button-label1 = Eliminar la firma guardada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editar descripción
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editar descripción
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/et/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/et/viewer.ftl
new file mode 100644
index 0000000..e0212b7
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/et/viewer.ftl
@@ -0,0 +1,246 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Eelmine lehekülg
+pdfjs-previous-button-label = Eelmine
+pdfjs-next-button =
+ .title = Järgmine lehekülg
+pdfjs-next-button-label = Järgmine
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Leht
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber }/{ $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Vähenda
+pdfjs-zoom-out-button-label = Vähenda
+pdfjs-zoom-in-button =
+ .title = Suurenda
+pdfjs-zoom-in-button-label = Suurenda
+pdfjs-zoom-select =
+ .title = Suurendamine
+pdfjs-presentation-mode-button =
+ .title = Lülitu esitlusrežiimi
+pdfjs-presentation-mode-button-label = Esitlusrežiim
+pdfjs-open-file-button =
+ .title = Ava fail
+pdfjs-open-file-button-label = Ava
+pdfjs-print-button =
+ .title = Prindi
+pdfjs-print-button-label = Prindi
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tööriistad
+pdfjs-tools-button-label = Tööriistad
+pdfjs-first-page-button =
+ .title = Mine esimesele leheküljele
+pdfjs-first-page-button-label = Mine esimesele leheküljele
+pdfjs-last-page-button =
+ .title = Mine viimasele leheküljele
+pdfjs-last-page-button-label = Mine viimasele leheküljele
+pdfjs-page-rotate-cw-button =
+ .title = Pööra päripäeva
+pdfjs-page-rotate-cw-button-label = Pööra päripäeva
+pdfjs-page-rotate-ccw-button =
+ .title = Pööra vastupäeva
+pdfjs-page-rotate-ccw-button-label = Pööra vastupäeva
+pdfjs-cursor-text-select-tool-button =
+ .title = Luba teksti valimise tööriist
+pdfjs-cursor-text-select-tool-button-label = Teksti valimise tööriist
+pdfjs-cursor-hand-tool-button =
+ .title = Luba sirvimistööriist
+pdfjs-cursor-hand-tool-button-label = Sirvimistööriist
+pdfjs-scroll-page-button =
+ .title = Kasutatakse lehe kaupa kerimist
+pdfjs-scroll-page-button-label = Lehe kaupa kerimine
+pdfjs-scroll-vertical-button =
+ .title = Kasuta vertikaalset kerimist
+pdfjs-scroll-vertical-button-label = Vertikaalne kerimine
+pdfjs-scroll-horizontal-button =
+ .title = Kasuta horisontaalset kerimist
+pdfjs-scroll-horizontal-button-label = Horisontaalne kerimine
+pdfjs-scroll-wrapped-button =
+ .title = Kasuta rohkem mahutavat kerimist
+pdfjs-scroll-wrapped-button-label = Rohkem mahutav kerimine
+pdfjs-spread-none-button =
+ .title = Ära kõrvuta lehekülgi
+pdfjs-spread-none-button-label = Lehtede kõrvutamine puudub
+pdfjs-spread-odd-button =
+ .title = Kõrvuta leheküljed, alustades paaritute numbritega lehekülgedega
+pdfjs-spread-odd-button-label = Kõrvutamine paaritute numbritega alustades
+pdfjs-spread-even-button =
+ .title = Kõrvuta leheküljed, alustades paarisnumbritega lehekülgedega
+pdfjs-spread-even-button-label = Kõrvutamine paarisnumbritega alustades
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumendi omadused…
+pdfjs-document-properties-button-label = Dokumendi omadused…
+pdfjs-document-properties-file-name = Faili nimi:
+pdfjs-document-properties-file-size = Faili suurus:
+pdfjs-document-properties-title = Pealkiri:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Teema:
+pdfjs-document-properties-keywords = Märksõnad:
+pdfjs-document-properties-creation-date = Loodud:
+pdfjs-document-properties-modification-date = Muudetud:
+pdfjs-document-properties-creator = Looja:
+pdfjs-document-properties-producer = Generaator:
+pdfjs-document-properties-version = Generaatori versioon:
+pdfjs-document-properties-page-count = Lehekülgi:
+pdfjs-document-properties-page-size = Lehe suurus:
+pdfjs-document-properties-page-size-unit-inches = tolli
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertikaalpaigutus
+pdfjs-document-properties-page-size-orientation-landscape = rõhtpaigutus
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = "Fast Web View" tugi:
+pdfjs-document-properties-linearized-yes = Jah
+pdfjs-document-properties-linearized-no = Ei
+pdfjs-document-properties-close-button = Sulge
+
+## Print
+
+pdfjs-print-progress-message = Dokumendi ettevalmistamine printimiseks…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Loobu
+pdfjs-printing-not-supported = Hoiatus: printimine pole selle brauseri poolt täielikult toetatud.
+pdfjs-printing-not-ready = Hoiatus: PDF pole printimiseks täielikult laaditud.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Näita külgriba
+pdfjs-toggle-sidebar-notification-button =
+ .title = Näita külgriba (dokument sisaldab sisukorda/manuseid/kihte)
+pdfjs-toggle-sidebar-button-label = Näita külgriba
+pdfjs-document-outline-button =
+ .title = Näita sisukorda (kõigi punktide laiendamiseks/ahendamiseks topeltklõpsa)
+pdfjs-document-outline-button-label = Näita sisukorda
+pdfjs-attachments-button =
+ .title = Näita manuseid
+pdfjs-attachments-button-label = Manused
+pdfjs-layers-button =
+ .title = Näita kihte (kõikide kihtide vaikeolekusse lähtestamiseks topeltklõpsa)
+pdfjs-layers-button-label = Kihid
+pdfjs-thumbs-button =
+ .title = Näita pisipilte
+pdfjs-thumbs-button-label = Pisipildid
+pdfjs-current-outline-item-button =
+ .title = Otsi üles praegune kontuuriüksus
+pdfjs-current-outline-item-button-label = Praegune kontuuriüksus
+pdfjs-findbar-button =
+ .title = Otsi dokumendist
+pdfjs-findbar-button-label = Otsi
+pdfjs-additional-layers = Täiendavad kihid
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page }. lehekülg
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page }. lehekülje pisipilt
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Otsi
+ .placeholder = Otsi dokumendist…
+pdfjs-find-previous-button =
+ .title = Otsi fraasi eelmine esinemiskoht
+pdfjs-find-previous-button-label = Eelmine
+pdfjs-find-next-button =
+ .title = Otsi fraasi järgmine esinemiskoht
+pdfjs-find-next-button-label = Järgmine
+pdfjs-find-highlight-checkbox = Too kõik esile
+pdfjs-find-match-case-checkbox-label = Tõstutundlik
+pdfjs-find-match-diacritics-checkbox-label = Otsitakse diakriitiliselt
+pdfjs-find-entire-word-checkbox-label = Täissõnad
+pdfjs-find-reached-top = Jõuti dokumendi algusesse, jätkati lõpust
+pdfjs-find-reached-bottom = Jõuti dokumendi lõppu, jätkati algusest
+pdfjs-find-not-found = Fraasi ei leitud
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Mahuta laiusele
+pdfjs-page-scale-fit = Mahuta leheküljele
+pdfjs-page-scale-auto = Automaatne suurendamine
+pdfjs-page-scale-actual = Tegelik suurus
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Lehekülg { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDFi laadimisel esines viga.
+pdfjs-invalid-file-error = Vigane või rikutud PDF-fail.
+pdfjs-missing-file-error = PDF-fail puudub.
+pdfjs-unexpected-response-error = Ootamatu vastus serverilt.
+pdfjs-rendering-error = Lehe renderdamisel esines viga.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = PDF-faili avamiseks sisesta parool.
+pdfjs-password-invalid = Vigane parool. Palun proovi uuesti.
+pdfjs-password-ok-button = Sobib
+pdfjs-password-cancel-button = Loobu
+pdfjs-web-fonts-disabled = Veebifondid on keelatud: PDFiga kaasatud fonte pole võimalik kasutada.
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-delete-model-button = Kustuta
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/eu/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/eu/viewer.ftl
new file mode 100644
index 0000000..6a5996a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/eu/viewer.ftl
@@ -0,0 +1,840 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Aurreko orria
+pdfjs-previous-button-label = Aurrekoa
+pdfjs-next-button =
+ .title = Hurrengo orria
+pdfjs-next-button-label = Hurrengoa
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Orria
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Urrundu zooma
+pdfjs-zoom-out-button-label = Urrundu zooma
+pdfjs-zoom-in-button =
+ .title = Gerturatu zooma
+pdfjs-zoom-in-button-label = Gerturatu zooma
+pdfjs-zoom-select =
+ .title = Zooma
+pdfjs-presentation-mode-button =
+ .title = Aldatu aurkezpen modura
+pdfjs-presentation-mode-button-label = Arkezpen modua
+pdfjs-open-file-button =
+ .title = Ireki fitxategia
+pdfjs-open-file-button-label = Ireki
+pdfjs-print-button =
+ .title = Inprimatu
+pdfjs-print-button-label = Inprimatu
+pdfjs-save-button =
+ .title = Gorde
+pdfjs-save-button-label = Gorde
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Deskargatu
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Deskargatu
+pdfjs-bookmark-button =
+ .title = Uneko orria (ikusi uneko orriaren URLa)
+pdfjs-bookmark-button-label = Uneko orria
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tresnak
+pdfjs-tools-button-label = Tresnak
+pdfjs-first-page-button =
+ .title = Joan lehen orrira
+pdfjs-first-page-button-label = Joan lehen orrira
+pdfjs-last-page-button =
+ .title = Joan azken orrira
+pdfjs-last-page-button-label = Joan azken orrira
+pdfjs-page-rotate-cw-button =
+ .title = Biratu erlojuaren norantzan
+pdfjs-page-rotate-cw-button-label = Biratu erlojuaren norantzan
+pdfjs-page-rotate-ccw-button =
+ .title = Biratu erlojuaren aurkako norantzan
+pdfjs-page-rotate-ccw-button-label = Biratu erlojuaren aurkako norantzan
+pdfjs-cursor-text-select-tool-button =
+ .title = Gaitu testuaren hautapen tresna
+pdfjs-cursor-text-select-tool-button-label = Testuaren hautapen tresna
+pdfjs-cursor-hand-tool-button =
+ .title = Gaitu eskuaren tresna
+pdfjs-cursor-hand-tool-button-label = Eskuaren tresna
+pdfjs-scroll-page-button =
+ .title = Erabili orriaren korritzea
+pdfjs-scroll-page-button-label = Orriaren korritzea
+pdfjs-scroll-vertical-button =
+ .title = Erabili korritze bertikala
+pdfjs-scroll-vertical-button-label = Korritze bertikala
+pdfjs-scroll-horizontal-button =
+ .title = Erabili korritze horizontala
+pdfjs-scroll-horizontal-button-label = Korritze horizontala
+pdfjs-scroll-wrapped-button =
+ .title = Erabili korritze egokitua
+pdfjs-scroll-wrapped-button-label = Korritze egokitua
+pdfjs-spread-none-button =
+ .title = Ez elkartu barreiatutako orriak
+pdfjs-spread-none-button-label = Barreiatzerik ez
+pdfjs-spread-odd-button =
+ .title = Elkartu barreiatutako orriak bakoiti zenbakidunekin hasita
+pdfjs-spread-odd-button-label = Barreiatze bakoitia
+pdfjs-spread-even-button =
+ .title = Elkartu barreiatutako orriak bikoiti zenbakidunekin hasita
+pdfjs-spread-even-button-label = Barreiatze bikoitia
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentuaren propietateak…
+pdfjs-document-properties-button-label = Dokumentuaren propietateak…
+pdfjs-document-properties-file-name = Fitxategi-izena:
+pdfjs-document-properties-file-size = Fitxategiaren tamaina:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } byte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } byte)
+pdfjs-document-properties-title = Izenburua:
+pdfjs-document-properties-author = Egilea:
+pdfjs-document-properties-subject = Gaia:
+pdfjs-document-properties-keywords = Gako-hitzak:
+pdfjs-document-properties-creation-date = Sortze-data:
+pdfjs-document-properties-modification-date = Aldatze-data:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Sortzailea:
+pdfjs-document-properties-producer = PDFaren ekoizlea:
+pdfjs-document-properties-version = PDF bertsioa:
+pdfjs-document-properties-page-count = Orrialde kopurua:
+pdfjs-document-properties-page-size = Orriaren tamaina:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = bertikala
+pdfjs-document-properties-page-size-orientation-landscape = horizontala
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Gutuna
+pdfjs-document-properties-page-size-name-legal = Legala
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Webeko ikuspegi bizkorra:
+pdfjs-document-properties-linearized-yes = Bai
+pdfjs-document-properties-linearized-no = Ez
+pdfjs-document-properties-close-button = Itxi
+pdfjs-digital-signature-properties-view-certificate = Ikusi ziurtagiria
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Arrazoia: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Denbora-marka: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Azpi-sinadura ({ $count })
+ *[other] Azpi-sinadurak ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Dokumentua inprimatzeko prestatzen…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = %{ $progress }
+pdfjs-print-progress-close-button = Utzi
+pdfjs-printing-not-supported = Abisua: inprimatzeko euskarria ez da erabatekoa nabigatzaile honetan.
+pdfjs-printing-not-ready = Abisua: PDFa ez dago erabat kargatuta inprimatzeko.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Txandakatu alboko barra
+pdfjs-toggle-sidebar-notification-button =
+ .title = Txandakatu alboko barra (dokumentuak eskema/eranskinak/geruzak ditu)
+pdfjs-toggle-sidebar-button-label = Txandakatu alboko barra
+pdfjs-document-outline-button =
+ .title = Erakutsi dokumentuaren eskema (klik bikoitza elementu guztiak zabaltzeko/tolesteko)
+pdfjs-document-outline-button-label = Dokumentuaren eskema
+pdfjs-attachments-button =
+ .title = Erakutsi eranskinak
+pdfjs-attachments-button-label = Eranskinak
+pdfjs-layers-button =
+ .title = Erakutsi geruzak (klik bikoitza geruza guztiak egoera lehenetsira berrezartzeko)
+pdfjs-layers-button-label = Geruzak
+pdfjs-thumbs-button =
+ .title = Erakutsi koadro txikiak
+pdfjs-thumbs-button-label = Koadro txikiak
+pdfjs-current-outline-item-button =
+ .title = Bilatu uneko eskemaren elementua
+pdfjs-current-outline-item-button-label = Uneko eskemaren elementua
+pdfjs-findbar-button =
+ .title = Bilatu dokumentuan
+pdfjs-findbar-button-label = Bilatu
+pdfjs-additional-layers = Geruza gehigarriak
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page }. orria
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page }. orriaren koadro txikia
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Hautatu { $page } orria
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = { $page } / { $total } orria
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Bilatu
+ .placeholder = Bilatu dokumentuan…
+pdfjs-find-previous-button =
+ .title = Bilatu esaldiaren aurreko parekatzea
+pdfjs-find-previous-button-label = Aurrekoa
+pdfjs-find-next-button =
+ .title = Bilatu esaldiaren hurrengo parekatzea
+pdfjs-find-next-button-label = Hurrengoa
+pdfjs-find-highlight-checkbox = Nabarmendu guztia
+pdfjs-find-match-case-checkbox-label = Bat etorri maiuskulekin/minuskulekin
+pdfjs-find-match-diacritics-checkbox-label = Bereizi diakritikoak
+pdfjs-find-entire-word-checkbox-label = Hitz osoak
+pdfjs-find-reached-top = Dokumentuaren hasierara heldu da, bukaeratik jarraitzen
+pdfjs-find-reached-bottom = Dokumentuaren bukaerara heldu da, hasieratik jarraitzen
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current }/{ $total } bat-etortzea
+ *[other] { $current }/{ $total } bat-etortzea
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Bat datorren { $limit } baino gehiago
+ *[other] Bat datozen { $limit } baino gehiago
+ }
+pdfjs-find-not-found = Esaldia ez da aurkitu
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Orriaren zabalera
+pdfjs-page-scale-fit = Doitu orrira
+pdfjs-page-scale-auto = Zoom automatikoa
+pdfjs-page-scale-actual = Benetako tamaina
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = %{ $scale }
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page }. orria
+
+## Loading indicator messages
+
+pdfjs-loading-error = Errorea gertatu da PDFa kargatzean.
+pdfjs-invalid-file-error = PDF fitxategi baliogabe edo hondatua.
+pdfjs-missing-file-error = PDF fitxategia falta da.
+pdfjs-unexpected-response-error = Espero gabeko zerbitzariaren erantzuna.
+pdfjs-rendering-error = Errorea gertatu da orria errendatzean.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } ohartarazpena]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Idatzi PDF fitxategi hau irekitzeko pasahitza.
+pdfjs-password-invalid = Pasahitz baliogabea. Saiatu berriro mesedez.
+pdfjs-password-ok-button = Ados
+pdfjs-password-cancel-button = Utzi
+pdfjs-web-fonts-disabled = Webeko letra-tipoak desgaituta daude: ezin dira kapsulatutako PDF letra-tipoak erabili.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Testua
+pdfjs-editor-color-picker-free-text-input =
+ .title = Aldatu testuaren kolorea
+pdfjs-editor-free-text-button-label = Testua
+pdfjs-editor-ink-button =
+ .title = Marrazkia
+pdfjs-editor-color-picker-ink-input =
+ .title = Aldatu marrazteko kolorea
+pdfjs-editor-ink-button-label = Marrazkia
+pdfjs-editor-stamp-button =
+ .title = Gehitu edo editatu irudiak
+pdfjs-editor-stamp-button-label = Gehitu edo editatu irudiak
+pdfjs-editor-highlight-button =
+ .title = Nabarmendu
+pdfjs-editor-highlight-button-label = Nabarmendu
+pdfjs-highlight-floating-button1 =
+ .title = Nabarmendu
+ .aria-label = Nabarmendu
+pdfjs-highlight-floating-button-label = Nabarmendu
+pdfjs-comment-floating-button =
+ .title = Iruzkina
+ .aria-label = Iruzkina
+pdfjs-comment-floating-button-label = Iruzkina
+pdfjs-editor-comment-button =
+ .title = Iruzkina
+ .aria-label = Iruzkina
+pdfjs-editor-comment-button-label = Iruzkina
+pdfjs-editor-signature-button =
+ .title = Gehitu sinadura
+pdfjs-editor-signature-button-label = Gehitu sinadura
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Nabarmendutakoen editorea
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Marrazkien editorea
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Sinaduren editorea: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Irudien editorea
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Kendu marrazkia
+pdfjs-editor-remove-freetext-button =
+ .title = Kendu testua
+pdfjs-editor-remove-stamp-button =
+ .title = Kendu irudia
+pdfjs-editor-remove-highlight-button =
+ .title = Kendu nabarmentzea
+pdfjs-editor-remove-signature-button =
+ .title = Kendu sinadura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Kolorea
+pdfjs-editor-free-text-size-input = Tamaina
+pdfjs-editor-ink-color-input = Kolorea
+pdfjs-editor-ink-thickness-input = Loditasuna
+pdfjs-editor-ink-opacity-input = Opakutasuna
+pdfjs-editor-stamp-add-image-button =
+ .title = Gehitu irudia
+pdfjs-editor-stamp-add-image-button-label = Gehitu irudia
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Loditasuna
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Aldatu loditasuna testua ez beste elementuak nabarmentzean
+pdfjs-editor-add-signature-container =
+ .aria-label = Sinaduren kontrolak eta gordetako sinadurak
+pdfjs-editor-signature-add-signature-button =
+ .title = Gehitu sinadura berria
+pdfjs-editor-signature-add-signature-button-label = Gehitu sinadura berria
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Gordetako sinadura: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Testu-editorea
+ .default-content = Hasi idazten…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Iruzkina
+ *[other] Iruzkinak
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Itxi alboko barra
+ .aria-label = Itxi alboko barra
+pdfjs-editor-comments-sidebar-close-button-label = Itxi alboko barra
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Azpimarratzeko zerbait ikusi duzu? Nabarmen ezazu eta utzi iruzkina.
+pdfjs-editor-comments-sidebar-no-comments-link = Argibide gehiago
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Ordezko testua
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editatu ordezko testua
+pdfjs-editor-alt-text-dialog-label = Aukeratu aukera
+pdfjs-editor-alt-text-dialog-description = Ordezko testuak laguntzen du jendeak ezin duenean irudia ikusi edo ez denean kargatzen.
+pdfjs-editor-alt-text-add-description-label = Gehitu azalpena
+pdfjs-editor-alt-text-add-description-description = Saiatu idazten gaia, ezarpena edo ekintzak deskribatzen dituen esaldi 1 edo 2.
+pdfjs-editor-alt-text-mark-decorative-label = Markatu apaingarri gisa
+pdfjs-editor-alt-text-mark-decorative-description = Irudiak apaingarrientzat erabiltzen da, adibidez ertz edo ur-marketarako.
+pdfjs-editor-alt-text-cancel-button = Utzi
+pdfjs-editor-alt-text-save-button = Gorde
+pdfjs-editor-alt-text-decorative-tooltip = Apaingarri gisa markatuta
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Adibidez, "gizon gaztea mahaian eserita dago bazkaltzeko"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Ordezko testua
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Goiko ezkerreko izkina — aldatu tamaina
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Goian erdian — aldatu tamaina
+pdfjs-editor-resizer-top-right =
+ .aria-label = Goiko eskuineko izkina — aldatu tamaina
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Erdian eskuinean — aldatu tamaina
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Beheko eskuineko izkina — aldatu tamaina
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Behean erdian — aldatu tamaina
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Beheko ezkerreko izkina — aldatu tamaina
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Erdian ezkerrean — aldatu tamaina
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Nabarmentze kolorea
+pdfjs-editor-colorpicker-button =
+ .title = Aldatu kolorea
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Kolore-aukerak
+pdfjs-editor-colorpicker-yellow =
+ .title = Horia
+pdfjs-editor-colorpicker-green =
+ .title = Berdea
+pdfjs-editor-colorpicker-blue =
+ .title = Urdina
+pdfjs-editor-colorpicker-pink =
+ .title = Arrosa
+pdfjs-editor-colorpicker-red =
+ .title = Gorria
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Erakutsi denak
+pdfjs-editor-highlight-show-all-button =
+ .title = Erakutsi denak
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editatu ordezko testua (irudiaren azalpena)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Gehitu ordezko testua (irudiaren azalpena)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Idatzi zure azalpena hemen…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Azalpen laburra irudia ikusi ezin duen jendearentzat edo irudia kargatu ezin denerako.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ordezko testu hau automatikoki sortu da eta okerra izan liteke.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Argibide gehiago
+pdfjs-editor-new-alt-text-create-automatically-button-label = Sortu ordezko testua automatikoki
+pdfjs-editor-new-alt-text-not-now-button = Une honetan ez
+pdfjs-editor-new-alt-text-error-title = Ezin da ordezko testua automatikoki sortu
+pdfjs-editor-new-alt-text-error-description = Idatzi zure ordezko testu propioa edo saiatu berriro geroago.
+pdfjs-editor-new-alt-text-error-close-button = Itxi
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Ordezko testuaren AA modeloa deskargatzen ({ $downloadedSize }/{ $totalSize } MB)
+ .aria-valuetext = Ordezko testuaren AA modeloa deskargatzen ({ $downloadedSize }/{ $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Ordezko testua gehituta
+pdfjs-editor-new-alt-text-added-button-label = Ordezko testua gehituta
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Ordezko testua falta da
+pdfjs-editor-new-alt-text-missing-button-label = Ordezko testua falta da
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Berrikusi ordezko testua
+pdfjs-editor-new-alt-text-to-review-button-label = Berrikusi ordezko testua
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automatikoki sortua: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Irudien ordezko testuaren ezarpenak
+pdfjs-image-alt-text-settings-button-label = Irudien ordezko testuaren ezarpenak
+pdfjs-editor-alt-text-settings-dialog-label = Irudien ordezko testuaren ezarpenak
+pdfjs-editor-alt-text-settings-automatic-title = Ordezko testu automatikoa
+pdfjs-editor-alt-text-settings-create-model-button-label = Sortu ordezko testua automatikoki
+pdfjs-editor-alt-text-settings-create-model-description = Azalpenak iradokitzen ditu irudia ikusi ezin duen jendearentzat edo irudia kargatu ezin denerako.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Ordezko testuaren AA modeloa ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Zure gailuan modu lokalean exekutatzen da eta zure datuak pribatu mantentzen dira. Ordezko testu automatikorako beharrezkoa.
+pdfjs-editor-alt-text-settings-delete-model-button = Ezabatu
+pdfjs-editor-alt-text-settings-download-model-button = Deskargatu
+pdfjs-editor-alt-text-settings-downloading-model-button = Deskargatzen…
+pdfjs-editor-alt-text-settings-editor-title = Ordezko testuaren editorea
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Erakutsi ordezko testua irudi bat gehitzean berehala
+pdfjs-editor-alt-text-settings-show-dialog-description = Zure irudi guztiek ordezko testua dutela ziurtatzen laguntzen dizu.
+pdfjs-editor-alt-text-settings-close-button = Itxi
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Nabarmentzea gehituta
+pdfjs-editor-freetext-added-alert = Testua gehituta
+pdfjs-editor-ink-added-alert = Marrazkia gehituta
+pdfjs-editor-stamp-added-alert = Irudia gehituta
+pdfjs-editor-signature-added-alert = Sinadura gehituta
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Nabarmentzea kenduta
+pdfjs-editor-undo-bar-message-freetext = Testua kenduta
+pdfjs-editor-undo-bar-message-ink = Marrazkia kenduta
+pdfjs-editor-undo-bar-message-stamp = Irudia kenduta
+pdfjs-editor-undo-bar-message-signature = Sinadura kenduta
+pdfjs-editor-undo-bar-message-comment = Iruzkina kenduta
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] Esku-ohar bat kenduta
+ *[other] { $count } esku-ohar kenduta
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Desegin
+pdfjs-editor-undo-bar-undo-button-label = Desegin
+pdfjs-editor-undo-bar-close-button =
+ .title = Itxi
+pdfjs-editor-undo-bar-close-button-label = Itxi
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label =
+ Leiho modal honek PDF dokumentu batera gehitzeko sinadurak
+ sortzea ahalbidetzen dio erabiltzaileari. Erabiltzaileak izena edita
+ dezake (ordezko testu modura ere erabiltzen dena) eta sinadura
+ gordetzeko aukera du gehiagotan erabili ahal izateko.
+pdfjs-editor-add-signature-dialog-title = Gehitu sinadura
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Idatzi
+ .title = Idatzi
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Marraztu
+ .title = Marraztu
+pdfjs-editor-add-signature-image-button = Irudia
+ .title = Irudia
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Idatzi zure sinadura
+ .placeholder = Idatzi zure sinadura
+pdfjs-editor-add-signature-draw-placeholder = Marraztu zure sinadura
+pdfjs-editor-add-signature-draw-thickness-range-label = Loditasuna
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Marrazteko loditasuna: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Igotzeko, jaregin fitxategia hemen
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Edo aukeratu irudi-fitxategiak
+ *[other] Edo arakatu irudi-fitxategiak
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Azalpena (ordezko testua)
+pdfjs-editor-add-signature-description-input =
+ .title = Azalpena (ordezko testua)
+pdfjs-editor-add-signature-description-default-when-drawing = Sinadura
+pdfjs-editor-add-signature-clear-button-label = Garbitu sinadura
+pdfjs-editor-add-signature-clear-button =
+ .title = Garbitu sinadura
+pdfjs-editor-add-signature-save-checkbox = Gorde sinadura
+pdfjs-editor-add-signature-save-warning-message = Gordetako sinadura kopuruaren mugara heldu zara (5). Gehiago gorde ahal izateko, ken ezazu bat.
+pdfjs-editor-add-signature-image-upload-error-title = Ezin da irudia igo
+pdfjs-editor-add-signature-image-upload-error-description = Egiaztatu zure sareko konexioa edo saiatu beste irudi batekin.
+pdfjs-editor-add-signature-image-no-data-error-title = Ezin da irudia sinaduran bihurtu
+pdfjs-editor-add-signature-image-no-data-error-description = Saiatu beste irudi bat igotzen.
+pdfjs-editor-add-signature-error-close-button = Itxi
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Utzi
+pdfjs-editor-add-signature-add-button = Gehitu
+pdfjs-editor-edit-signature-update-button = Eguneratu
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editatu iruzkina
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editatu iruzkina
+pdfjs-editor-delete-comment-popup-button-label = Kendu iruzkina
+pdfjs-editor-delete-comment-popup-button =
+ .title = Kendu iruzkina
+pdfjs-show-comment-button =
+ .title = Erakutsi iruzkina
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editatu iruzkina
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Eguneratu
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Gehitu iruzkina
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Gehitu
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Hasi idazten…
+pdfjs-editor-edit-comment-dialog-cancel-button = Utzi
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Gehitu iruzkina
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Txandakatu alboko barra (dokumentuak koadro txikiak/eskema/eranskinak/geruzak ditu)
+pdfjs-toggle-views-manager-button1-label = Kudeatu orriak
+pdfjs-views-manager-sidebar =
+ .aria-label = Alboko barra
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Alboko barra neurriz aldatzekoa
+pdfjs-views-manager-view-selector-button =
+ .title = Ikuspegiak
+pdfjs-views-manager-view-selector-button-label = Ikuspegiak
+pdfjs-views-manager-pages-title = Orriak
+pdfjs-views-manager-outlines-title1 = Dokumentuaren eskema
+ .title = Dokumentuaren eskema (klik bikoitza elementu guztiak zabaltzeko/tolesteko)
+pdfjs-views-manager-attachments-title = Eranskinak
+pdfjs-views-manager-layers-title1 = Geruzak
+ .title = Geruzak (klik bikoitza geruza guztiak egoera lehenetsira berrezartzeko)
+pdfjs-views-manager-pages-option-label = Orriak
+pdfjs-views-manager-outlines-option-label = Dokumentuaren eskema
+pdfjs-views-manager-attachments-option-label = Eranskinak
+pdfjs-views-manager-layers-option-label = Geruzak
+pdfjs-views-manager-add-file-button =
+ .title = Gehitu fitxategia
+pdfjs-views-manager-add-file-button-label = Gehitu fitxategia
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } hautatuta
+ *[other] { $count } hautatuta
+ }
+pdfjs-views-manager-pages-status-none-action-label = Hautatu orriak
+pdfjs-views-manager-pages-status-action-button-label = Kudeatu
+pdfjs-views-manager-pages-status-copy-button-label = Kopiatu
+pdfjs-views-manager-pages-status-cut-button-label = Ebaki
+pdfjs-views-manager-pages-status-delete-button-label = Ezabatu
+pdfjs-views-manager-pages-status-export-selected-button-label = Esportatu hautatutakoa…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Orri bat moztuta
+ *[other] { $count } orri moztuta
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Orri bat kopiatuta
+ *[other] { $count } orri kopiatuta
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Orri bat ezabatuta
+ *[other] { $count } orri ezabatuta
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Zuee fitxategia prestatzen…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Fitxategia igotzen…
+pdfjs-views-manager-status-warning-cut-label = Ezin da moztu. Berritu orria eta saiatu berriro.
+pdfjs-views-manager-status-warning-copy-label = Ezin da kopiatu. Berritu orria eta saiatu berriro.
+pdfjs-views-manager-status-warning-delete-label = Ezin da ezabatu. Berritu orria eta saiatu berriro.
+pdfjs-views-manager-status-warning-save-label = Ezin da gorde. Berritu orria eta saiatu berriro.
+pdfjs-views-manager-status-undo-button-label = Desegin
+pdfjs-views-manager-status-done-button-label = Eginda
+pdfjs-views-manager-status-close-button =
+ .title = Itxi
+pdfjs-views-manager-status-close-button-label = Itxi
+pdfjs-views-manager-paste-button-label = Itsatsi
+pdfjs-views-manager-paste-button-before =
+ .title = Itsatsi lehen orriaren aurretik
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Itsatsi { $page }. orriaren aurretik
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = BERRIA
+pdfjs-views-manager-waiting-for-file = Fitxategia igotzen…
+pdfjs-toggle-views-manager-button1 =
+ .title = Kudeatu orriak
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Sinadura digitalaren propietateak
+ .aria-label = Sinadura digitalaren propietateak
+pdfjs-digital-signature-properties-button-label = Sinadura digitalaren propietateak
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokumentua baliozko sinadura digitalarekin sinatuta dago
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokumentua sinatuta dago baina sinadura digital bat ezin izan da egiaztatu
+ *[other] Dokumentua sinatuta dago baina { $count } sinadura digital ezin izan dira egiaztatu
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Document ziurtagiri fidagaitz batekin sinatuta dago
+ *[other] Document { $count } ziurtagiri fidagaitzekin sinatuta dago
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokumentua iraungitako ziurtagiri batekin sinatuta dago
+ *[other] Dokumentua iraungitako { $count } ziurtagirirekin sinatuta dago
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokumentuak sinadura digital baliogabe bat du
+ *[other] Dokumentuak { $count } sinadura digital baliogabe ditu
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokumentua baliogabetutako ziurtagiri batekin sinatuta dago
+ *[other] Dokumentua baliogabetutako { $count } ziurtagirirekin sinatuta dago
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Egoera: sinadura egiaztatuta
+pdfjs-digital-signature-properties-status-invalid = Egoera: sinadura baliogabea
+pdfjs-digital-signature-properties-status-unknown = Egoera: ezin da egiaztatu (euskarririk ez)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Ziurtagiria: fidagarria ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Ziurtagiria: ez dago erabilgarri
+pdfjs-digital-signature-properties-certificate-untrusted = Ziurtagiria: fidagaitza
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Ziurtagiria: jaulkitzaile ezezaguna ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Ziurtagiria: bere buruak sinatutakoa ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Ziurtagiria: jaulkitzaile fidagaitza ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Ziurtagiria: iraungita
+pdfjs-digital-signature-properties-certificate-expired-with-date = Ziurtagiria: iraungita ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Ziurtagiria: baliogabetuta
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Kendu gordetako sinadura
+pdfjs-editor-delete-signature-button-label1 = Kendu gordetako sinadura
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editatu azalpena
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editatu azalpena
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fa/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fa/viewer.ftl
new file mode 100644
index 0000000..edff37c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fa/viewer.ftl
@@ -0,0 +1,322 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = صفحهٔ قبلی
+pdfjs-previous-button-label = قبلی
+pdfjs-next-button =
+ .title = صفحهٔ بعدی
+pdfjs-next-button-label = بعدی
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = صفحه
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = از { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber }از { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = کوچکنمایی
+pdfjs-zoom-out-button-label = کوچکنمایی
+pdfjs-zoom-in-button =
+ .title = بزرگنمایی
+pdfjs-zoom-in-button-label = بزرگنمایی
+pdfjs-zoom-select =
+ .title = زوم
+pdfjs-presentation-mode-button =
+ .title = تغییر به حالت ارائه
+pdfjs-presentation-mode-button-label = حالت ارائه
+pdfjs-open-file-button =
+ .title = باز کردن پرونده
+pdfjs-open-file-button-label = باز کردن
+pdfjs-print-button =
+ .title = چاپ
+pdfjs-print-button-label = چاپ
+pdfjs-save-button =
+ .title = ذخیره
+pdfjs-save-button-label = ذخیره
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = دریافت
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = دریافت
+pdfjs-bookmark-button =
+ .title = صفحه فعلی (مشاهده نشانی اینترنتی از صفحه فعلی)
+pdfjs-bookmark-button-label = صفحه فعلی
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ابزارها
+pdfjs-tools-button-label = ابزارها
+pdfjs-first-page-button =
+ .title = برو به اولین صفحه
+pdfjs-first-page-button-label = برو به اولین صفحه
+pdfjs-last-page-button =
+ .title = برو به آخرین صفحه
+pdfjs-last-page-button-label = برو به آخرین صفحه
+pdfjs-page-rotate-cw-button =
+ .title = چرخش ساعتگرد
+pdfjs-page-rotate-cw-button-label = چرخش ساعتگرد
+pdfjs-page-rotate-ccw-button =
+ .title = چرخش پاد ساعتگرد
+pdfjs-page-rotate-ccw-button-label = چرخش پاد ساعتگرد
+pdfjs-cursor-text-select-tool-button =
+ .title = فعال کردن ابزارِ انتخابِ متن
+pdfjs-cursor-text-select-tool-button-label = ابزارِ انتخابِ متن
+pdfjs-cursor-hand-tool-button =
+ .title = فعال کردن ابزارِ دست
+pdfjs-cursor-hand-tool-button-label = ابزار دست
+pdfjs-scroll-page-button =
+ .title = استفاده از پیمایش صفحه
+pdfjs-scroll-page-button-label = پیمایش صفحه
+pdfjs-scroll-vertical-button =
+ .title = استفاده از پیمایش عمودی
+pdfjs-scroll-vertical-button-label = پیمایش عمودی
+pdfjs-scroll-horizontal-button =
+ .title = استفاده از پیمایش افقی
+pdfjs-scroll-horizontal-button-label = پیمایش افقی
+pdfjs-spread-none-button =
+ .title = صفحات پیوسته را یکی نکنید
+pdfjs-spread-none-button-label = بدون صفحات پیوسته
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = خصوصیات سند...
+pdfjs-document-properties-button-label = خصوصیات سند...
+pdfjs-document-properties-file-name = نام پرونده:
+pdfjs-document-properties-file-size = حجم پرونده:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } کیلوبایت ({ $b } بایت)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } مگابایت ({ $b } بایت)
+pdfjs-document-properties-title = عنوان:
+pdfjs-document-properties-author = نویسنده:
+pdfjs-document-properties-subject = موضوع:
+pdfjs-document-properties-keywords = کلیدواژهها:
+pdfjs-document-properties-creation-date = تاریخ ایجاد:
+pdfjs-document-properties-modification-date = تاریخ ویرایش:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = ایجاد کننده:
+pdfjs-document-properties-producer = ایجاد کننده PDF:
+pdfjs-document-properties-version = نسخه PDF:
+pdfjs-document-properties-page-count = تعداد صفحات:
+pdfjs-document-properties-page-size = اندازه صفحه:
+pdfjs-document-properties-page-size-unit-inches = اینچ
+pdfjs-document-properties-page-size-unit-millimeters = میلیمتر
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = نامه
+pdfjs-document-properties-page-size-name-legal = حقوقی
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-linearized-yes = بله
+pdfjs-document-properties-linearized-no = خیر
+pdfjs-document-properties-close-button = بستن
+
+## Print
+
+pdfjs-print-progress-message = آماده سازی مدارک برای چاپ کردن…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = لغو
+pdfjs-printing-not-supported = هشدار: قابلیت چاپ بهطور کامل در این مرورگر پشتیبانی نمیشود.
+pdfjs-printing-not-ready = اخطار: پرونده PDF بطور کامل بارگیری نشده و امکان چاپ وجود ندارد.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = باز و بسته کردن نوار کناری
+pdfjs-toggle-sidebar-button-label = تغییرحالت نوارکناری
+pdfjs-document-outline-button =
+ .title = نمایش رئوس مطالب مدارک(برای بازشدن/جمع شدن همه موارد دوبار کلیک کنید)
+pdfjs-document-outline-button-label = طرح نوشتار
+pdfjs-attachments-button =
+ .title = نمایش پیوستها
+pdfjs-attachments-button-label = پیوستها
+pdfjs-layers-button-label = لایهها
+pdfjs-thumbs-button =
+ .title = نمایش تصاویر بندانگشتی
+pdfjs-thumbs-button-label = تصاویر بندانگشتی
+pdfjs-findbar-button =
+ .title = جستجو در سند
+pdfjs-findbar-button-label = پیدا کردن
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = صفحه { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = تصویر بند انگشتی صفحه { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = پیدا کردن
+ .placeholder = پیدا کردن در سند…
+pdfjs-find-previous-button =
+ .title = پیدا کردن رخداد قبلی عبارت
+pdfjs-find-previous-button-label = قبلی
+pdfjs-find-next-button =
+ .title = پیدا کردن رخداد بعدی عبارت
+pdfjs-find-next-button-label = بعدی
+pdfjs-find-highlight-checkbox = برجسته و هایلایت کردن همه موارد
+pdfjs-find-match-case-checkbox-label = تطبیق کوچکی و بزرگی حروف
+pdfjs-find-entire-word-checkbox-label = تمام کلمهها
+pdfjs-find-reached-top = به بالای صفحه رسیدیم، از پایین ادامه میدهیم
+pdfjs-find-reached-bottom = به آخر صفحه رسیدیم، از بالا ادامه میدهیم
+pdfjs-find-not-found = عبارت پیدا نشد
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = عرض صفحه
+pdfjs-page-scale-fit = اندازه کردن صفحه
+pdfjs-page-scale-auto = بزرگنمایی خودکار
+pdfjs-page-scale-actual = اندازه واقعی
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = صفحهٔ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = هنگام بارگیری پرونده PDF خطایی رخ داد.
+pdfjs-invalid-file-error = پرونده PDF نامعتبر یامعیوب میباشد.
+pdfjs-missing-file-error = پرونده PDF یافت نشد.
+pdfjs-unexpected-response-error = پاسخ پیش بینی نشده سرور
+pdfjs-rendering-error = هنگام بارگیری صفحه خطایی رخ داد.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = جهت باز کردن پرونده PDF گذرواژه را وارد نمائید.
+pdfjs-password-invalid = گذرواژه نامعتبر. لطفا مجددا تلاش کنید.
+pdfjs-password-ok-button = تأیید
+pdfjs-password-cancel-button = لغو
+pdfjs-web-fonts-disabled = فونت های تحت وب غیر فعال شده اند: امکان استفاده از نمایش دهنده داخلی PDF وجود ندارد.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = متن
+pdfjs-editor-free-text-button-label = متن
+pdfjs-editor-ink-button =
+ .title = کشیدن
+pdfjs-editor-ink-button-label = کشیدن
+pdfjs-editor-stamp-button =
+ .title = افزودن یا ویرایش تصاویر
+pdfjs-editor-stamp-button-label = افزودن یا ویرایش تصاویر
+pdfjs-editor-highlight-button =
+ .title = برجسته کردن
+pdfjs-editor-highlight-button-label = برجسته کردن
+pdfjs-highlight-floating-button1 =
+ .title = برجسته کردن
+ .aria-label = برجسته کردن
+pdfjs-highlight-floating-button-label = برجسته کردن
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = رنگ
+pdfjs-editor-free-text-size-input = اندازه
+pdfjs-editor-ink-color-input = رنگ
+pdfjs-editor-stamp-add-image-button =
+ .title = افزودن تصویر
+pdfjs-editor-stamp-add-image-button-label = افزودن تصویر
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = ویرایشگر متن
+ .default-content = شروع به نوشتن کنید…
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-add-description-label = افزودن توضیحات
+pdfjs-editor-alt-text-cancel-button = انصراف
+pdfjs-editor-alt-text-save-button = ذخیره
+
+## Color picker
+
+pdfjs-editor-colorpicker-button =
+ .title = تغییر رنگ
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = انتخاب رنگ
+pdfjs-editor-colorpicker-yellow =
+ .title = زرد
+pdfjs-editor-colorpicker-green =
+ .title = سبز
+pdfjs-editor-colorpicker-blue =
+ .title = آبی
+pdfjs-editor-colorpicker-pink =
+ .title = صورتی
+pdfjs-editor-colorpicker-red =
+ .title = قرمز
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = نمایش همه
+pdfjs-editor-highlight-show-all-button =
+ .title = نمایش همه
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = بیشتر بدانید
+pdfjs-editor-new-alt-text-not-now-button = اکنون نه
+pdfjs-editor-new-alt-text-error-close-button = بستن
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-delete-model-button = حذف
+pdfjs-editor-alt-text-settings-download-model-button = دریافت
+pdfjs-editor-alt-text-settings-downloading-model-button = در حال دریافت…
+pdfjs-editor-alt-text-settings-close-button = بستن
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ff/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ff/viewer.ftl
new file mode 100644
index 0000000..e7cc1d7
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ff/viewer.ftl
@@ -0,0 +1,222 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Hello Ɓennungo
+pdfjs-previous-button-label = Ɓennuɗo
+pdfjs-next-button =
+ .title = Hello faango
+pdfjs-next-button-label = Yeeso
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Hello
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = e nder { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Lonngo Woɗɗa
+pdfjs-zoom-out-button-label = Lonngo Woɗɗa
+pdfjs-zoom-in-button =
+ .title = Lonngo Ara
+pdfjs-zoom-in-button-label = Lonngo Ara
+pdfjs-zoom-select =
+ .title = Lonngo
+pdfjs-presentation-mode-button =
+ .title = Faytu to Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Uddit Fiilde
+pdfjs-open-file-button-label = Uddit
+pdfjs-print-button =
+ .title = Winndito
+pdfjs-print-button-label = Winndito
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Kuutorɗe
+pdfjs-tools-button-label = Kuutorɗe
+pdfjs-first-page-button =
+ .title = Yah to hello adanngo
+pdfjs-first-page-button-label = Yah to hello adanngo
+pdfjs-last-page-button =
+ .title = Yah to hello wattindiingo
+pdfjs-last-page-button-label = Yah to hello wattindiingo
+pdfjs-page-rotate-cw-button =
+ .title = Yiiltu Faya Ñaamo
+pdfjs-page-rotate-cw-button-label = Yiiltu Faya Ñaamo
+pdfjs-page-rotate-ccw-button =
+ .title = Yiiltu Faya Nano
+pdfjs-page-rotate-ccw-button-label = Yiiltu Faya Nano
+pdfjs-cursor-text-select-tool-button =
+ .title = Gollin kaɓirgel cuɓirgel binndi
+pdfjs-cursor-text-select-tool-button-label = Kaɓirgel cuɓirgel binndi
+pdfjs-cursor-hand-tool-button =
+ .title = Hurmin kuutorgal junngo
+pdfjs-cursor-hand-tool-button-label = Kaɓirgel junngo
+pdfjs-scroll-vertical-button =
+ .title = Huutoro gorwitol daringol
+pdfjs-scroll-vertical-button-label = Gorwitol daringol
+pdfjs-scroll-horizontal-button =
+ .title = Huutoro gorwitol lelingol
+pdfjs-scroll-horizontal-button-label = Gorwitol daringol
+pdfjs-scroll-wrapped-button =
+ .title = Huutoro gorwitol coomingol
+pdfjs-scroll-wrapped-button-label = Gorwitol coomingol
+pdfjs-spread-none-button =
+ .title = Hoto tawtu kelle kelle
+pdfjs-spread-none-button-label = Alaa Spreads
+pdfjs-spread-odd-button =
+ .title = Tawtu kelle puɗɗortooɗe kelle teelɗe
+pdfjs-spread-odd-button-label = Kelle teelɗe
+pdfjs-spread-even-button =
+ .title = Tawtu ɗereeji kelle puɗɗoriiɗi kelle teeltuɗe
+pdfjs-spread-even-button-label = Kelle teeltuɗe
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Keeroraaɗi Winndannde…
+pdfjs-document-properties-button-label = Keeroraaɗi Winndannde…
+pdfjs-document-properties-file-name = Innde fiilde:
+pdfjs-document-properties-file-size = Ɓetol fiilde:
+pdfjs-document-properties-title = Tiitoonde:
+pdfjs-document-properties-author = Binnduɗo:
+pdfjs-document-properties-subject = Toɓɓere:
+pdfjs-document-properties-keywords = Kelmekele jiytirɗe:
+pdfjs-document-properties-creation-date = Ñalnde Sosaa:
+pdfjs-document-properties-modification-date = Ñalnde Waylaa:
+pdfjs-document-properties-creator = Cosɗo:
+pdfjs-document-properties-producer = Paggiiɗo PDF:
+pdfjs-document-properties-version = Yamre PDF:
+pdfjs-document-properties-page-count = Limoore Kelle:
+pdfjs-document-properties-page-size = Ɓeto Hello:
+pdfjs-document-properties-page-size-unit-inches = nder
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = dariingo
+pdfjs-document-properties-page-size-orientation-landscape = wertiingo
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Ɓataake
+pdfjs-document-properties-page-size-name-legal = Laawol
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Ɗisngo geese yaawngo:
+pdfjs-document-properties-linearized-yes = Eey
+pdfjs-document-properties-linearized-no = Alaa
+pdfjs-document-properties-close-button = Uddu
+
+## Print
+
+pdfjs-print-progress-message = Nana heboo winnditaade fiilannde…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Haaytu
+pdfjs-printing-not-supported = Reentino: Winnditagol tammbitaaka no feewi e ndee wanngorde.
+pdfjs-printing-not-ready = Reentino: PDF oo loowaaki haa timmi ngam winnditagol.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toggilo Palal Sawndo
+pdfjs-toggle-sidebar-button-label = Toggilo Palal Sawndo
+pdfjs-document-outline-button =
+ .title = Hollu Ƴiyal Fiilannde (dobdobo ngam wertude/taggude teme fof)
+pdfjs-document-outline-button-label = Toɓɓe Fiilannde
+pdfjs-attachments-button =
+ .title = Hollu Ɗisanɗe
+pdfjs-attachments-button-label = Ɗisanɗe
+pdfjs-thumbs-button =
+ .title = Hollu Dooɓe
+pdfjs-thumbs-button-label = Dooɓe
+pdfjs-findbar-button =
+ .title = Yiylo e fiilannde
+pdfjs-findbar-button-label = Yiytu
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Hello { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Dooɓre Hello { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Yiytu
+ .placeholder = Yiylo nder dokimaa
+pdfjs-find-previous-button =
+ .title = Yiylo cilol ɓennugol konngol ngol
+pdfjs-find-previous-button-label = Ɓennuɗo
+pdfjs-find-next-button =
+ .title = Yiylo cilol garowol konngol ngol
+pdfjs-find-next-button-label = Yeeso
+pdfjs-find-highlight-checkbox = Jalbin fof
+pdfjs-find-match-case-checkbox-label = Jaaɓnu darnde
+pdfjs-find-entire-word-checkbox-label = Kelme timmuɗe tan
+pdfjs-find-reached-top = Heɓii fuɗɗorde fiilannde, jokku faya les
+pdfjs-find-reached-bottom = Heɓii hoore fiilannde, jokku faya les
+pdfjs-find-not-found = Konngi njiyataa
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Njaajeendi Hello
+pdfjs-page-scale-fit = Keƴeendi Hello
+pdfjs-page-scale-auto = Loongorde Jaajol
+pdfjs-page-scale-actual = Ɓetol Jaati
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Juumre waɗii tuma nde loowata PDF oo.
+pdfjs-invalid-file-error = Fiilde PDF moƴƴaani walla jiibii.
+pdfjs-missing-file-error = Fiilde PDF ena ŋakki.
+pdfjs-unexpected-response-error = Jaabtol sarworde tijjinooka.
+pdfjs-rendering-error = Juumre waɗii tuma nde yoŋkittoo hello.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Siiftannde]
+
+## Password
+
+pdfjs-password-label = Naatu finnde ngam uddite ndee fiilde PDF.
+pdfjs-password-invalid = Finnde moƴƴaani. Tiiɗno eto kadi.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Haaytu
+pdfjs-web-fonts-disabled = Ponte geese ko daaƴaaɗe: horiima huutoraade ponte PDF coomtoraaɗe.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fi/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fi/viewer.ftl
new file mode 100644
index 0000000..73c120e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fi/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Edellinen sivu
+pdfjs-previous-button-label = Edellinen
+pdfjs-next-button =
+ .title = Seuraava sivu
+pdfjs-next-button-label = Seuraava
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Sivu
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Loitonna
+pdfjs-zoom-out-button-label = Loitonna
+pdfjs-zoom-in-button =
+ .title = Lähennä
+pdfjs-zoom-in-button-label = Lähennä
+pdfjs-zoom-select =
+ .title = Suurennus
+pdfjs-presentation-mode-button =
+ .title = Siirry esitystilaan
+pdfjs-presentation-mode-button-label = Esitystila
+pdfjs-open-file-button =
+ .title = Avaa tiedosto
+pdfjs-open-file-button-label = Avaa
+pdfjs-print-button =
+ .title = Tulosta
+pdfjs-print-button-label = Tulosta
+pdfjs-save-button =
+ .title = Tallenna
+pdfjs-save-button-label = Tallenna
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Lataa
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Lataa
+pdfjs-bookmark-button =
+ .title = Nykyinen sivu (Näytä URL-osoite nykyiseltä sivulta)
+pdfjs-bookmark-button-label = Nykyinen sivu
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tools
+pdfjs-tools-button-label = Tools
+pdfjs-first-page-button =
+ .title = Siirry ensimmäiselle sivulle
+pdfjs-first-page-button-label = Siirry ensimmäiselle sivulle
+pdfjs-last-page-button =
+ .title = Siirry viimeiselle sivulle
+pdfjs-last-page-button-label = Siirry viimeiselle sivulle
+pdfjs-page-rotate-cw-button =
+ .title = Kierrä oikealle
+pdfjs-page-rotate-cw-button-label = Kierrä oikealle
+pdfjs-page-rotate-ccw-button =
+ .title = Kierrä vasemmalle
+pdfjs-page-rotate-ccw-button-label = Kierrä vasemmalle
+pdfjs-cursor-text-select-tool-button =
+ .title = Käytä tekstinvalintatyökalua
+pdfjs-cursor-text-select-tool-button-label = Tekstinvalintatyökalu
+pdfjs-cursor-hand-tool-button =
+ .title = Käytä käsityökalua
+pdfjs-cursor-hand-tool-button-label = Käsityökalu
+pdfjs-scroll-page-button =
+ .title = Käytä sivun vieritystä
+pdfjs-scroll-page-button-label = Sivun vieritys
+pdfjs-scroll-vertical-button =
+ .title = Käytä pystysuuntaista vieritystä
+pdfjs-scroll-vertical-button-label = Pystysuuntainen vieritys
+pdfjs-scroll-horizontal-button =
+ .title = Käytä vaakasuuntaista vieritystä
+pdfjs-scroll-horizontal-button-label = Vaakasuuntainen vieritys
+pdfjs-scroll-wrapped-button =
+ .title = Käytä rivittyvää vieritystä
+pdfjs-scroll-wrapped-button-label = Rivittyvä vieritys
+pdfjs-spread-none-button =
+ .title = Älä yhdistä sivuja aukeamiksi
+pdfjs-spread-none-button-label = Ei aukeamia
+pdfjs-spread-odd-button =
+ .title = Yhdistä sivut aukeamiksi alkaen parittomalta sivulta
+pdfjs-spread-odd-button-label = Parittomalta alkavat aukeamat
+pdfjs-spread-even-button =
+ .title = Yhdistä sivut aukeamiksi alkaen parilliselta sivulta
+pdfjs-spread-even-button-label = Parilliselta alkavat aukeamat
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentin ominaisuudet…
+pdfjs-document-properties-button-label = Dokumentin ominaisuudet…
+pdfjs-document-properties-file-name = Tiedoston nimi:
+pdfjs-document-properties-file-size = Tiedoston koko:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kt ({ $b } tavua)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } Mt ({ $b } tavua)
+pdfjs-document-properties-title = Otsikko:
+pdfjs-document-properties-author = Tekijä:
+pdfjs-document-properties-subject = Aihe:
+pdfjs-document-properties-keywords = Avainsanat:
+pdfjs-document-properties-creation-date = Luomispäivämäärä:
+pdfjs-document-properties-modification-date = Muokkauspäivämäärä:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Luoja:
+pdfjs-document-properties-producer = PDF-tuottaja:
+pdfjs-document-properties-version = PDF-versio:
+pdfjs-document-properties-page-count = Sivujen määrä:
+pdfjs-document-properties-page-size = Sivun koko:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = pysty
+pdfjs-document-properties-page-size-orientation-landscape = vaaka
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Nopea web-katselu:
+pdfjs-document-properties-linearized-yes = Kyllä
+pdfjs-document-properties-linearized-no = Ei
+pdfjs-document-properties-close-button = Sulje
+pdfjs-digital-signature-properties-view-certificate = Näytä varmenne
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Syy: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Aikaleima: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Aliallekirjoitus ({ $count })
+ *[other] Aliallekirjoitukset ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Valmistellaan dokumenttia tulostamista varten…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Peruuta
+pdfjs-printing-not-supported = Varoitus: Selain ei tue kaikkia tulostustapoja.
+pdfjs-printing-not-ready = Varoitus: PDF-tiedosto ei ole vielä latautunut kokonaan, eikä sitä voi vielä tulostaa.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Näytä/piilota sivupaneeli
+pdfjs-toggle-sidebar-notification-button =
+ .title = Näytä/piilota sivupaneeli (dokumentissa on sisällys/liitteitä/tasoja)
+pdfjs-toggle-sidebar-button-label = Näytä/piilota sivupaneeli
+pdfjs-document-outline-button =
+ .title = Näytä dokumentin sisällys (laajenna tai kutista kohdat kaksoisnapsauttamalla)
+pdfjs-document-outline-button-label = Dokumentin sisällys
+pdfjs-attachments-button =
+ .title = Näytä liitteet
+pdfjs-attachments-button-label = Liitteet
+pdfjs-layers-button =
+ .title = Näytä tasot (kaksoisnapsauta palauttaaksesi kaikki tasot oletustilaan)
+pdfjs-layers-button-label = Tasot
+pdfjs-thumbs-button =
+ .title = Näytä pienoiskuvat
+pdfjs-thumbs-button-label = Pienoiskuvat
+pdfjs-current-outline-item-button =
+ .title = Etsi nykyinen sisällyksen kohta
+pdfjs-current-outline-item-button-label = Nykyinen sisällyksen kohta
+pdfjs-findbar-button =
+ .title = Etsi dokumentista
+pdfjs-findbar-button-label = Etsi
+pdfjs-additional-layers = Lisätasot
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Sivu { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Pienoiskuva sivusta { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Valitse sivu { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Sivu { $page }/{ $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Etsi
+ .placeholder = Etsi dokumentista…
+pdfjs-find-previous-button =
+ .title = Etsi hakusanan edellinen osuma
+pdfjs-find-previous-button-label = Edellinen
+pdfjs-find-next-button =
+ .title = Etsi hakusanan seuraava osuma
+pdfjs-find-next-button-label = Seuraava
+pdfjs-find-highlight-checkbox = Korosta kaikki
+pdfjs-find-match-case-checkbox-label = Huomioi kirjainkoko
+pdfjs-find-match-diacritics-checkbox-label = Erota tarkkeet
+pdfjs-find-entire-word-checkbox-label = Kokonaiset sanat
+pdfjs-find-reached-top = Päästiin dokumentin alkuun, jatketaan lopusta
+pdfjs-find-reached-bottom = Päästiin dokumentin loppuun, jatketaan alusta
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } / { $total } osuma
+ *[other] { $current } / { $total } osumaa
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Yli { $limit } osuma
+ *[other] Yli { $limit } osumaa
+ }
+pdfjs-find-not-found = Hakusanaa ei löytynyt
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sivun leveys
+pdfjs-page-scale-fit = Koko sivu
+pdfjs-page-scale-auto = Automaattinen suurennus
+pdfjs-page-scale-actual = Todellinen koko
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Sivu { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Tapahtui virhe ladattaessa PDF-tiedostoa.
+pdfjs-invalid-file-error = Virheellinen tai vioittunut PDF-tiedosto.
+pdfjs-missing-file-error = Puuttuva PDF-tiedosto.
+pdfjs-unexpected-response-error = Odottamaton vastaus palvelimelta.
+pdfjs-rendering-error = Tapahtui virhe piirrettäessä sivua.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }-merkintä]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Kirjoita PDF-tiedoston salasana.
+pdfjs-password-invalid = Virheellinen salasana. Yritä uudestaan.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Peruuta
+pdfjs-web-fonts-disabled = Verkkosivujen omat kirjasinlajit on estetty: ei voida käyttää upotettuja PDF-kirjasinlajeja.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Teksti
+pdfjs-editor-color-picker-free-text-input =
+ .title = Muuta tekstin väriä
+pdfjs-editor-free-text-button-label = Teksti
+pdfjs-editor-ink-button =
+ .title = Piirros
+pdfjs-editor-color-picker-ink-input =
+ .title = Vaihda piirustuksen väriä
+pdfjs-editor-ink-button-label = Piirros
+pdfjs-editor-stamp-button =
+ .title = Lisää tai muokkaa kuvia
+pdfjs-editor-stamp-button-label = Lisää tai muokkaa kuvia
+pdfjs-editor-highlight-button =
+ .title = Korostus
+pdfjs-editor-highlight-button-label = Korostus
+pdfjs-highlight-floating-button1 =
+ .title = Korostus
+ .aria-label = Korostus
+pdfjs-highlight-floating-button-label = Korostus
+pdfjs-comment-floating-button =
+ .title = Kommentti
+ .aria-label = Kommentti
+pdfjs-comment-floating-button-label = Kommentti
+pdfjs-editor-comment-button =
+ .title = Kommentti
+ .aria-label = Kommentti
+pdfjs-editor-comment-button-label = Kommentti
+pdfjs-editor-signature-button =
+ .title = Lisää allekirjoitus
+pdfjs-editor-signature-button-label = Lisää allekirjoitus
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Korostusmuokkain
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Piirustusmuokkain
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Allekirjoituksen muokkain: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Kuvamuokkain
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Poista piirros
+pdfjs-editor-remove-freetext-button =
+ .title = Poista teksti
+pdfjs-editor-remove-stamp-button =
+ .title = Poista kuva
+pdfjs-editor-remove-highlight-button =
+ .title = Poista korostus
+pdfjs-editor-remove-signature-button =
+ .title = Poista allekirjoitus
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Väri
+pdfjs-editor-free-text-size-input = Koko
+pdfjs-editor-ink-color-input = Väri
+pdfjs-editor-ink-thickness-input = Paksuus
+pdfjs-editor-ink-opacity-input = Peittävyys
+pdfjs-editor-stamp-add-image-button =
+ .title = Lisää kuva
+pdfjs-editor-stamp-add-image-button-label = Lisää kuva
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Paksuus
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Muuta paksuutta korostaessasi muita kohteita kuin tekstiä
+pdfjs-editor-add-signature-container =
+ .aria-label = Allekirjoitussäätimet ja tallennetut allekirjoitukset
+pdfjs-editor-signature-add-signature-button =
+ .title = Lisää uusi allekirjoitus
+pdfjs-editor-signature-add-signature-button-label = Lisää uusi allekirjoitus
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Tallennettu allekirjoitus: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstimuokkain
+ .default-content = Aloita kirjoittaminen…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Kommentti
+ *[other] Kommenttia
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Sulje sivupaneeli
+ .aria-label = Sulje sivupaneeli
+pdfjs-editor-comments-sidebar-close-button-label = Sulje sivupaneeli
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Näetkö jotain huomionarvoista? Korosta se ja jätä kommentti.
+pdfjs-editor-comments-sidebar-no-comments-link = Lue lisää
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Vaihtoehtoinen teksti
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Muokkaa vaihtoehtoista tekstiä
+pdfjs-editor-alt-text-dialog-label = Valitse vaihtoehto
+pdfjs-editor-alt-text-dialog-description = Vaihtoehtoinen teksti ("alt-teksti") auttaa ihmisiä, jotka eivät näe kuvaa tai kun kuva ei lataudu.
+pdfjs-editor-alt-text-add-description-label = Lisää kuvaus
+pdfjs-editor-alt-text-add-description-description = Pyri 1-2 lauseeseen, jotka kuvaavat aihetta, ympäristöä tai toimintaa.
+pdfjs-editor-alt-text-mark-decorative-label = Merkitse koristeelliseksi
+pdfjs-editor-alt-text-mark-decorative-description = Tätä käytetään koristekuville, kuten reunuksille tai vesileimoille.
+pdfjs-editor-alt-text-cancel-button = Peruuta
+pdfjs-editor-alt-text-save-button = Tallenna
+pdfjs-editor-alt-text-decorative-tooltip = Merkitty koristeelliseksi
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Esimerkiksi "Nuori mies istuu pöytään syömään aterian"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Vaihtoehtoinen teksti
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Vasen yläkulma - muuta kokoa
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Ylhäällä keskellä - muuta kokoa
+pdfjs-editor-resizer-top-right =
+ .aria-label = Oikea yläkulma - muuta kokoa
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Keskellä oikealla - muuta kokoa
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Oikea alakulma - muuta kokoa
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Alhaalla keskellä - muuta kokoa
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Vasen alakulma - muuta kokoa
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Keskellä vasemmalla - muuta kokoa
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Korostusväri
+pdfjs-editor-colorpicker-button =
+ .title = Vaihda väri
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Värivalinnat
+pdfjs-editor-colorpicker-yellow =
+ .title = Keltainen
+pdfjs-editor-colorpicker-green =
+ .title = Vihreä
+pdfjs-editor-colorpicker-blue =
+ .title = Sininen
+pdfjs-editor-colorpicker-pink =
+ .title = Pinkki
+pdfjs-editor-colorpicker-red =
+ .title = Punainen
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Näytä kaikki
+pdfjs-editor-highlight-show-all-button =
+ .title = Näytä kaikki
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Muokkaa vaihtoehtoista tekstiä (kuvan kuvaus)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Lisää vaihtoehtoinen teksti (kuvan kuvaus)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Kirjoita kuvaus tähän…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Lyhyt kuvaus ihmisille, jotka eivät näe kuvaa tai kun kuva ei lataudu.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Tämä vaihtoehtoinen teksti luotiin automaattisesti, ja se voi olla epätarkka.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Lue lisää
+pdfjs-editor-new-alt-text-create-automatically-button-label = Luo vaihtoehtoinen teksti automaattisesti
+pdfjs-editor-new-alt-text-not-now-button = Ei nyt
+pdfjs-editor-new-alt-text-error-title = Vaihtoehtotekstiä ei voitu luoda automaattisesti
+pdfjs-editor-new-alt-text-error-description = Kirjoita oma vaihtoehtoinen teksti tai yritä myöhemmin uudelleen.
+pdfjs-editor-new-alt-text-error-close-button = Sulje
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Ladataan vaihtoehtoisen tekstin tekoälymallia ({ $downloadedSize } / { $totalSize } Mt)
+ .aria-valuetext = Ladataan vaihtoehtoisen tekstin tekoälymallia ({ $downloadedSize } / { $totalSize } Mt)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Vaihtoehtoinen teksti lisätty
+pdfjs-editor-new-alt-text-added-button-label = Vaihtoehtoinen teksti lisätty
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Vaihtoehtoinen teksti puuttuu
+pdfjs-editor-new-alt-text-missing-button-label = Vaihtoehtoinen teksti puuttuu
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Tarkista vaihtoehtoinen teksti
+pdfjs-editor-new-alt-text-to-review-button-label = Tarkista vaihtoehtoinen teksti
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Luotu automaattisesti: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Kuvan vaihtoehtoisen tekstin asetukset
+pdfjs-image-alt-text-settings-button-label = Kuvan vaihtoehtoisen tekstin asetukset
+pdfjs-editor-alt-text-settings-dialog-label = Kuvan vaihtoehtoisen tekstin asetukset
+pdfjs-editor-alt-text-settings-automatic-title = Automaattinen vaihtoehtoinen teksti
+pdfjs-editor-alt-text-settings-create-model-button-label = Luo vaihtoehtoinen teksti automaattisesti
+pdfjs-editor-alt-text-settings-create-model-description = Ehdottaa kuvauksia, jotka auttavat ihmisiä, jotka eivät näe kuvaa tai kun kuva ei lataudu.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Vaihtoehtoisen tekstin tekoälymalli ({ $totalSize } Mt)
+pdfjs-editor-alt-text-settings-ai-model-description = Toimii paikallisesti laitteellasi, joten tietosi pysyvät yksityisinä. Vaadittu automaattiselle vaihtoehtoiselle tekstille.
+pdfjs-editor-alt-text-settings-delete-model-button = Poista
+pdfjs-editor-alt-text-settings-download-model-button = Lataa
+pdfjs-editor-alt-text-settings-downloading-model-button = Ladataan…
+pdfjs-editor-alt-text-settings-editor-title = Vaihtoehtoisen tekstin muokkain
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Näytä vaihtoehtoisen tekstin muokkain heti, kun lisäät kuvan
+pdfjs-editor-alt-text-settings-show-dialog-description = Auttaa varmistamaan, että kaikissa kuvissasi on vaihtoehtoinen teksti.
+pdfjs-editor-alt-text-settings-close-button = Sulje
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Korostus lisätty
+pdfjs-editor-freetext-added-alert = Teksti lisätty
+pdfjs-editor-ink-added-alert = Piirustus lisätty
+pdfjs-editor-stamp-added-alert = Kuva lisätty
+pdfjs-editor-signature-added-alert = Allekirjoitus lisätty
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Korostus poistettu
+pdfjs-editor-undo-bar-message-freetext = Teksti poistettu
+pdfjs-editor-undo-bar-message-ink = Piirustus poistettu
+pdfjs-editor-undo-bar-message-stamp = Kuva poistettu
+pdfjs-editor-undo-bar-message-signature = Allekirjoitus poistettu
+pdfjs-editor-undo-bar-message-comment = Kommentti poistettu
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } merkintä poistettu
+ *[other] { $count } merkintää poistettu
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Kumoa
+pdfjs-editor-undo-bar-undo-button-label = Kumoa
+pdfjs-editor-undo-bar-close-button =
+ .title = Sulje
+pdfjs-editor-undo-bar-close-button-label = Sulje
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Tämän ikkunan avulla käyttäjä voi luoda allekirjoituksen PDF-asiakirjaan lisättäväksi. Käyttäjä voi muokata nimeä (joka toimii myös vaihtoehtoisena tekstinä) ja valinnaisesti tallentaa allekirjoituksen toistuvaa käyttöä varten.
+pdfjs-editor-add-signature-dialog-title = Lisää allekirjoitus
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Kirjoita
+ .title = Kirjoita
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Piirrä
+ .title = Piirrä
+pdfjs-editor-add-signature-image-button = Kuva
+ .title = Kuva
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Kirjoita allekirjoituksesi
+ .placeholder = Kirjoita allekirjoituksesi
+pdfjs-editor-add-signature-draw-placeholder = Piirrä allekirjoituksesi
+pdfjs-editor-add-signature-draw-thickness-range-label = Paksuus
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Piirustuksen paksuus: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Lähetä tiedosto vetämällä se tähän
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Tai selaa kuvatiedostoja
+ *[other] Tai selaa kuvatiedostoja
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Kuvaus (vaihtoehtoinen teksti)
+pdfjs-editor-add-signature-description-input =
+ .title = Kuvaus (vaihtoehtoinen teksti)
+pdfjs-editor-add-signature-description-default-when-drawing = Allekirjoitus
+pdfjs-editor-add-signature-clear-button-label = Tyhjennä allekirjoitus
+pdfjs-editor-add-signature-clear-button =
+ .title = Tyhjennä allekirjoitus
+pdfjs-editor-add-signature-save-checkbox = Tallenna allekirjoitus
+pdfjs-editor-add-signature-save-warning-message = Olet saavuttanut viiden tallennetun allekirjoituksen rajan. Poista yksi säästääksesi lisää.
+pdfjs-editor-add-signature-image-upload-error-title = Kuvaa ei voitu lähettää
+pdfjs-editor-add-signature-image-upload-error-description = Tarkista verkkoyhteyden tila tai kokeile toista kuvaa.
+pdfjs-editor-add-signature-image-no-data-error-title = Tätä kuvaa ei voida muuntaa allekirjoitukseksi
+pdfjs-editor-add-signature-image-no-data-error-description = Yritä lähettää eri kuva.
+pdfjs-editor-add-signature-error-close-button = Sulje
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Peruuta
+pdfjs-editor-add-signature-add-button = Lisää
+pdfjs-editor-edit-signature-update-button = Päivitä
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Muokkaa kommenttia
+pdfjs-editor-edit-comment-popup-button =
+ .title = Muokkaa kommenttia
+pdfjs-editor-delete-comment-popup-button-label = Poista kommentti
+pdfjs-editor-delete-comment-popup-button =
+ .title = Poista kommentti
+pdfjs-show-comment-button =
+ .title = Näytä kommentti
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Muokkaa kommenttia
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Päivitä
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Lisää kommentti
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Lisää
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Aloita kirjoittaminen…
+pdfjs-editor-edit-comment-dialog-cancel-button = Peruuta
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Lisää kommentti
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Näytä/piilota sivupaneeli (dokumentissa on pienoiskuvat/sisällys/liitteitä/tasoja)
+pdfjs-toggle-views-manager-button1-label = Hallitse sivuja
+pdfjs-views-manager-sidebar =
+ .aria-label = Sivupaneeli
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Sivupaneelin koon muuttaja
+pdfjs-views-manager-view-selector-button =
+ .title = Näkymät
+pdfjs-views-manager-view-selector-button-label = Näkymät
+pdfjs-views-manager-pages-title = Sivut
+pdfjs-views-manager-outlines-title1 = Dokumentin sisällys
+ .title = Dokumentin sisällys (napsauta kahdesti laajentaaksesi/supistaaksesi kohteet)
+pdfjs-views-manager-attachments-title = Liitteet
+pdfjs-views-manager-layers-title1 = Tasot
+ .title = Tasot (napsauta kahdesti nollataksesi tasot niiden oletustilaan)
+pdfjs-views-manager-pages-option-label = Sivut
+pdfjs-views-manager-outlines-option-label = Dokumentin sisällys
+pdfjs-views-manager-attachments-option-label = Liitteet
+pdfjs-views-manager-layers-option-label = Tasot
+pdfjs-views-manager-add-file-button =
+ .title = Lisää tiedosto
+pdfjs-views-manager-add-file-button-label = Lisää tiedosto
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } valittu
+ *[other] { $count } valittu
+ }
+pdfjs-views-manager-pages-status-none-action-label = Valitse sivut
+pdfjs-views-manager-pages-status-action-button-label = Hallitse
+pdfjs-views-manager-pages-status-copy-button-label = Kopioi
+pdfjs-views-manager-pages-status-cut-button-label = Leikkaa
+pdfjs-views-manager-pages-status-delete-button-label = Poista
+pdfjs-views-manager-pages-status-export-selected-button-label = Vie valitut…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 sivu leikattu
+ *[other] { $count } sivua leikattu
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 sivu kopioitu
+ *[other] { $count } sivua kopioitu
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 sivu poistettu
+ *[other] { $count } sivua poistettu
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Tiedostoa valmistellaan…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Lähetetään tiedostoa…
+pdfjs-views-manager-status-warning-cut-label = Leikkaaminen epäonnistui. Päivitä sivu ja yritä uudelleen.
+pdfjs-views-manager-status-warning-copy-label = Kopiointi epäonnistui. Päivitä sivu ja yritä uudelleen.
+pdfjs-views-manager-status-warning-delete-label = Poisto epäonnistui. Päivitä sivu ja yritä uudelleen.
+pdfjs-views-manager-status-warning-save-label = Tallentaminen epäonnistui. Päivitä sivu ja yritä uudelleen.
+pdfjs-views-manager-status-undo-button-label = Kumoa
+pdfjs-views-manager-status-done-button-label = Valmis
+pdfjs-views-manager-status-close-button =
+ .title = Sulje
+pdfjs-views-manager-status-close-button-label = Sulje
+pdfjs-views-manager-paste-button-label = Liitä
+pdfjs-views-manager-paste-button-before =
+ .title = Liitä ennen ensimmäistä sivua
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Liitä sivun { $page } jälkeen
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = UUTTA
+pdfjs-views-manager-waiting-for-file = Lähetetään tiedostoa…
+pdfjs-toggle-views-manager-button1 =
+ .title = Hallitse sivuja
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Digitaalisen allekirjoituksen ominaisuudet
+ .aria-label = Digitaalisen allekirjoituksen ominaisuudet
+pdfjs-digital-signature-properties-button-label = Digitaalisen allekirjoituksen ominaisuudet
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Asiakirja allekirjoitettiin kelvollisella digitaalisella allekirjoituksella
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Asiakirja allekirjoitettu, mutta { $count } digitaalista allekirjoitusta ei voitu vahvistaa
+ *[other] Asiakirja allekirjoitettu, mutta { $count } digitaalista allekirjoitusta ei voitu vahvistaa
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Asiakirja on allekirjoitettu { $count } varmenteella, johon ei luoteta
+ *[other] Asiakirja on allekirjoitettu { $count } varmenteella, joihin ei luoteta
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Asiakirja allekirjoitettu { $count } vanhentuneella varmenteella
+ *[other] Asiakirja allekirjoitettu { $count } vanhentuneella varmenteella
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Asiakirjassa on { $count } virheellinen digitaalinen allekirjoitus
+ *[other] Asiakirjassa on { $count } virheellistä digitaalista allekirjoitusta
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Asiakirja allekirjoitettu { $count } kumotulla varmenteella
+ *[other] Asiakirja allekirjoitettu { $count } kumotulla varmenteella
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Tila: Allekirjoitus vahvistettu
+pdfjs-digital-signature-properties-status-invalid = Tila: Allekirjoitus virheellinen
+pdfjs-digital-signature-properties-status-unknown = Tila: Vahvistus epäonnistui (ei tuettu)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Varmenne: Luotettu ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Varmenne: Ei saatavilla
+pdfjs-digital-signature-properties-certificate-untrusted = Varmenne: Ei-luotettu
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Varmenne: Tuntematon myöntäjä ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Varmenne: Itse allekirjoitettu ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Varmenne: Ei-luotettu myöntäjä ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Varmenne: Vanhentunut
+pdfjs-digital-signature-properties-certificate-expired-with-date = Varmenne: Vanhentunut ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Varmenne: Kumottu
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Poista tallennettu allekirjoitus
+pdfjs-editor-delete-signature-button-label1 = Poista tallennettu allekirjoitus
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Muokkaa kuvausta
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Muokkaa kuvausta
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fr/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fr/viewer.ftl
new file mode 100644
index 0000000..1895f27
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fr/viewer.ftl
@@ -0,0 +1,832 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Page précédente
+pdfjs-previous-button-label = Précédent
+pdfjs-next-button =
+ .title = Page suivante
+pdfjs-next-button-label = Suivant
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Page
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = sur { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } sur { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom arrière
+pdfjs-zoom-out-button-label = Zoom arrière
+pdfjs-zoom-in-button =
+ .title = Zoom avant
+pdfjs-zoom-in-button-label = Zoom avant
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Basculer en mode présentation
+pdfjs-presentation-mode-button-label = Mode présentation
+pdfjs-open-file-button =
+ .title = Ouvrir le fichier
+pdfjs-open-file-button-label = Ouvrir le fichier
+pdfjs-print-button =
+ .title = Imprimer
+pdfjs-print-button-label = Imprimer
+pdfjs-save-button =
+ .title = Enregistrer
+pdfjs-save-button-label = Enregistrer
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Télécharger
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Télécharger
+pdfjs-bookmark-button =
+ .title = Page courante (montrer l’adresse de la page courante)
+pdfjs-bookmark-button-label = Page courante
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Outils
+pdfjs-tools-button-label = Outils
+pdfjs-first-page-button =
+ .title = Aller à la première page
+pdfjs-first-page-button-label = Aller à la première page
+pdfjs-last-page-button =
+ .title = Aller à la dernière page
+pdfjs-last-page-button-label = Aller à la dernière page
+pdfjs-page-rotate-cw-button =
+ .title = Rotation horaire
+pdfjs-page-rotate-cw-button-label = Rotation horaire
+pdfjs-page-rotate-ccw-button =
+ .title = Rotation antihoraire
+pdfjs-page-rotate-ccw-button-label = Rotation antihoraire
+pdfjs-cursor-text-select-tool-button =
+ .title = Activer l’outil de sélection de texte
+pdfjs-cursor-text-select-tool-button-label = Outil de sélection de texte
+pdfjs-cursor-hand-tool-button =
+ .title = Activer l’outil main
+pdfjs-cursor-hand-tool-button-label = Outil main
+pdfjs-scroll-page-button =
+ .title = Utiliser le défilement par page
+pdfjs-scroll-page-button-label = Défilement par page
+pdfjs-scroll-vertical-button =
+ .title = Utiliser le défilement vertical
+pdfjs-scroll-vertical-button-label = Défilement vertical
+pdfjs-scroll-horizontal-button =
+ .title = Utiliser le défilement horizontal
+pdfjs-scroll-horizontal-button-label = Défilement horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Utiliser le défilement par bloc
+pdfjs-scroll-wrapped-button-label = Défilement par bloc
+pdfjs-spread-none-button =
+ .title = Ne pas afficher les pages deux à deux
+pdfjs-spread-none-button-label = Pas de double affichage
+pdfjs-spread-odd-button =
+ .title = Afficher les pages par deux, impaires à gauche
+pdfjs-spread-odd-button-label = Doubles pages, impaires à gauche
+pdfjs-spread-even-button =
+ .title = Afficher les pages par deux, paires à gauche
+pdfjs-spread-even-button-label = Doubles pages, paires à gauche
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propriétés du document…
+pdfjs-document-properties-button-label = Propriétés du document…
+pdfjs-document-properties-file-name = Nom du fichier :
+pdfjs-document-properties-file-size = Taille du fichier :
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } Ko ({ $b } octets)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } Mo ({ $b } octets)
+pdfjs-document-properties-title = Titre :
+pdfjs-document-properties-author = Auteur :
+pdfjs-document-properties-subject = Sujet :
+pdfjs-document-properties-keywords = Mots-clés :
+pdfjs-document-properties-creation-date = Date de création :
+pdfjs-document-properties-modification-date = Modifié le :
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Créé par :
+pdfjs-document-properties-producer = Outil de conversion PDF :
+pdfjs-document-properties-version = Version PDF :
+pdfjs-document-properties-page-count = Nombre de pages :
+pdfjs-document-properties-page-size = Taille de la page :
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = paysage
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = lettre
+pdfjs-document-properties-page-size-name-legal = document juridique
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Affichage rapide des pages web :
+pdfjs-document-properties-linearized-yes = Oui
+pdfjs-document-properties-linearized-no = Non
+pdfjs-document-properties-close-button = Fermer
+pdfjs-digital-signature-properties-view-certificate = Afficher le certificat
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Raison : { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Horodatage : { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Sous-signature ({ $count })
+ *[other] Sous-signatures ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Préparation du document pour l’impression…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Annuler
+pdfjs-printing-not-supported = Attention : l’impression n’est pas totalement prise en charge par ce navigateur.
+pdfjs-printing-not-ready = Attention : le PDF n’est pas entièrement chargé pour pouvoir l’imprimer.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Afficher/Masquer le panneau latéral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Afficher/Masquer le panneau latéral (le document contient des signets/pièces jointes/calques)
+pdfjs-toggle-sidebar-button-label = Afficher/Masquer le panneau latéral
+pdfjs-document-outline-button =
+ .title = Afficher les signets du document (double-cliquer pour développer/réduire tous les éléments)
+pdfjs-document-outline-button-label = Signets du document
+pdfjs-attachments-button =
+ .title = Afficher les pièces jointes
+pdfjs-attachments-button-label = Pièces jointes
+pdfjs-layers-button =
+ .title = Afficher les calques (double-cliquer pour réinitialiser tous les calques à l’état par défaut)
+pdfjs-layers-button-label = Calques
+pdfjs-thumbs-button =
+ .title = Afficher les vignettes
+pdfjs-thumbs-button-label = Vignettes
+pdfjs-current-outline-item-button =
+ .title = Trouver l’élément de plan actuel
+pdfjs-current-outline-item-button-label = Élément de plan actuel
+pdfjs-findbar-button =
+ .title = Rechercher dans le document
+pdfjs-findbar-button-label = Rechercher
+pdfjs-additional-layers = Calques additionnels
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Vignette de la page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Sélectionner la page { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Page { $page } sur { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Rechercher
+ .placeholder = Rechercher dans le document…
+pdfjs-find-previous-button =
+ .title = Trouver l’occurrence précédente de l’expression
+pdfjs-find-previous-button-label = Précédent
+pdfjs-find-next-button =
+ .title = Trouver la prochaine occurrence de l’expression
+pdfjs-find-next-button-label = Suivant
+pdfjs-find-highlight-checkbox = Tout surligner
+pdfjs-find-match-case-checkbox-label = Respecter la casse
+pdfjs-find-match-diacritics-checkbox-label = Respecter les accents et diacritiques
+pdfjs-find-entire-word-checkbox-label = Mots entiers
+pdfjs-find-reached-top = Haut de la page atteint, poursuite depuis la fin
+pdfjs-find-reached-bottom = Bas de la page atteint, poursuite au début
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = Occurrence { $current } sur { $total }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [1] Plus d’une occurrence
+ *[other] Plus de { $limit } occurrences
+ }
+pdfjs-find-not-found = Expression non trouvée
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Pleine largeur
+pdfjs-page-scale-fit = Page entière
+pdfjs-page-scale-auto = Zoom automatique
+pdfjs-page-scale-actual = Taille réelle
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Page { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Une erreur s’est produite lors du chargement du fichier PDF.
+pdfjs-invalid-file-error = Fichier PDF invalide ou corrompu.
+pdfjs-missing-file-error = Fichier PDF manquant.
+pdfjs-unexpected-response-error = Réponse inattendue du serveur.
+pdfjs-rendering-error = Une erreur s’est produite lors de l’affichage de la page.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Annotation { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Veuillez saisir le mot de passe pour ouvrir ce fichier PDF.
+pdfjs-password-invalid = Mot de passe incorrect. Veuillez réessayer.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Annuler
+pdfjs-web-fonts-disabled = Les polices web sont désactivées : impossible d’utiliser les polices intégrées au PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texte
+pdfjs-editor-color-picker-free-text-input =
+ .title = Changer la couleur du texte
+pdfjs-editor-free-text-button-label = Texte
+pdfjs-editor-ink-button =
+ .title = Dessiner
+pdfjs-editor-color-picker-ink-input =
+ .title = Changer la couleur pour dessiner
+pdfjs-editor-ink-button-label = Dessiner
+pdfjs-editor-stamp-button =
+ .title = Ajouter ou modifier des images
+pdfjs-editor-stamp-button-label = Ajouter ou modifier des images
+pdfjs-editor-highlight-button =
+ .title = Surligner
+pdfjs-editor-highlight-button-label = Surligner
+pdfjs-highlight-floating-button1 =
+ .title = Surligner
+ .aria-label = Surligner
+pdfjs-highlight-floating-button-label = Surligner
+pdfjs-comment-floating-button =
+ .title = Commenter
+ .aria-label = Commenter
+pdfjs-comment-floating-button-label = Commenter
+pdfjs-editor-comment-button =
+ .title = Commenter
+ .aria-label = Commenter
+pdfjs-editor-comment-button-label = Commenter
+pdfjs-editor-signature-button =
+ .title = Ajouter une signature
+pdfjs-editor-signature-button-label = Ajouter une signature
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Éditeur de surlignage
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Éditeur de dessins
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Éditeur de signature : { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Éditeur d’images
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Supprimer le dessin
+pdfjs-editor-remove-freetext-button =
+ .title = Supprimer le texte
+pdfjs-editor-remove-stamp-button =
+ .title = Supprimer l’image
+pdfjs-editor-remove-highlight-button =
+ .title = Supprimer le surlignage
+pdfjs-editor-remove-signature-button =
+ .title = Retirer la signature
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Couleur
+pdfjs-editor-free-text-size-input = Taille
+pdfjs-editor-ink-color-input = Couleur
+pdfjs-editor-ink-thickness-input = Épaisseur
+pdfjs-editor-ink-opacity-input = Opacité
+pdfjs-editor-stamp-add-image-button =
+ .title = Ajouter une image
+pdfjs-editor-stamp-add-image-button-label = Ajouter une image
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Épaisseur
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Modifier l’épaisseur pour le surlignage d’éléments non textuels
+pdfjs-editor-add-signature-container =
+ .aria-label = Contrôles de signature et signatures enregistrées
+pdfjs-editor-signature-add-signature-button =
+ .title = Ajouter une nouvelle signature
+pdfjs-editor-signature-add-signature-button-label = Ajouter une nouvelle signature
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Signature enregistrée : { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Éditeur de texte
+ .default-content = Commencez à écrire…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Commentaire
+ *[other] Commentaires
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Fermer le panneau latéral
+ .aria-label = Fermer le panneau latéral
+pdfjs-editor-comments-sidebar-close-button-label = Fermer le panneau latéral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vous remarquez quelque chose d’intéressant ? Mettez-le en surbrillance et ajoutez un commentaire.
+pdfjs-editor-comments-sidebar-no-comments-link = En savoir plus
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texte alternatif
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Modifier le texte alternatif
+pdfjs-editor-alt-text-dialog-label = Sélectionnez une option
+pdfjs-editor-alt-text-dialog-description = Le texte alternatif est utile lorsque des personnes ne peuvent pas voir l’image ou que l’image ne se charge pas.
+pdfjs-editor-alt-text-add-description-label = Ajouter une description
+pdfjs-editor-alt-text-add-description-description = Il est conseillé de rédiger une ou deux phrases décrivant le sujet, le cadre ou les actions.
+pdfjs-editor-alt-text-mark-decorative-label = Marquer comme décorative
+pdfjs-editor-alt-text-mark-decorative-description = Cette option est utilisée pour les images décoratives, comme les bordures ou les filigranes.
+pdfjs-editor-alt-text-cancel-button = Annuler
+pdfjs-editor-alt-text-save-button = Enregistrer
+pdfjs-editor-alt-text-decorative-tooltip = Marquée comme décorative
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Par exemple, « Un jeune homme est assis à une table pour prendre un repas »
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texte alternatif
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Coin supérieur gauche — redimensionner
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Milieu haut — redimensionner
+pdfjs-editor-resizer-top-right =
+ .aria-label = Coin supérieur droit — redimensionner
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Milieu droit — redimensionner
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Coin inférieur droit — redimensionner
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Centre bas — redimensionner
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Coin inférieur gauche — redimensionner
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Milieu gauche — redimensionner
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Couleur de surlignage
+pdfjs-editor-colorpicker-button =
+ .title = Changer de couleur
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Choix de couleurs
+pdfjs-editor-colorpicker-yellow =
+ .title = Jaune
+pdfjs-editor-colorpicker-green =
+ .title = Vert
+pdfjs-editor-colorpicker-blue =
+ .title = Bleu
+pdfjs-editor-colorpicker-pink =
+ .title = Rose
+pdfjs-editor-colorpicker-red =
+ .title = Rouge
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Tout afficher
+pdfjs-editor-highlight-show-all-button =
+ .title = Tout afficher
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Modifier le texte alternatif (description de l’image)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Ajouter du texte alternatif (description de l’image)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Rédigez votre description ici…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Courte description pour les personnes qui ne peuvent pas voir l’image ou lorsque l’image ne se charge pas.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ce texte alternatif a été créé automatiquement et peut être inexact.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = En savoir plus
+pdfjs-editor-new-alt-text-create-automatically-button-label = Créer automatiquement le texte alternatif
+pdfjs-editor-new-alt-text-not-now-button = Pas maintenant
+pdfjs-editor-new-alt-text-error-title = Impossible de créer automatiquement le texte alternatif
+pdfjs-editor-new-alt-text-error-description = Veuillez rédiger votre propre texte alternatif ou réessayer plus tard.
+pdfjs-editor-new-alt-text-error-close-button = Fermer
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Téléchargement du modèle d’IA de texte alternatif ({ $downloadedSize } sur { $totalSize } Mo)
+ .aria-valuetext = Téléchargement du modèle d’IA de texte alternatif ({ $downloadedSize } sur { $totalSize } Mo)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Texte alternatif ajouté
+pdfjs-editor-new-alt-text-added-button-label = Texte alternatif ajouté
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Texte alternatif manquant
+pdfjs-editor-new-alt-text-missing-button-label = Texte alternatif manquant
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Réviser le texte alternatif
+pdfjs-editor-new-alt-text-to-review-button-label = Réviser le texte alternatif
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Créé automatiquement : { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Paramètres du texte alternatif des images
+pdfjs-image-alt-text-settings-button-label = Paramètres du texte alternatif des images
+pdfjs-editor-alt-text-settings-dialog-label = Paramètres du texte alternatif des images
+pdfjs-editor-alt-text-settings-automatic-title = Texte alternatif automatique
+pdfjs-editor-alt-text-settings-create-model-button-label = Créer automatiquement le texte alternatif
+pdfjs-editor-alt-text-settings-create-model-description = Suggère des descriptions pour aider les personnes qui ne peuvent pas voir l’image ou lorsque l’image ne se charge pas.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modèle d’IA de texte alternatif ({ $totalSize } Mo)
+pdfjs-editor-alt-text-settings-ai-model-description = Fonctionne localement sur votre appareil, vos données restent privées. Obligatoire pour la génération automatique de texte alternatif.
+pdfjs-editor-alt-text-settings-delete-model-button = Supprimer
+pdfjs-editor-alt-text-settings-download-model-button = Télécharger
+pdfjs-editor-alt-text-settings-downloading-model-button = Téléchargement…
+pdfjs-editor-alt-text-settings-editor-title = Éditeur de texte alternatif
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Afficher l’éditeur de texte alternatif immédiatement lors de l’ajout d’une image
+pdfjs-editor-alt-text-settings-show-dialog-description = Vous aide à vous assurer que toutes vos images ont du texte alternatif.
+pdfjs-editor-alt-text-settings-close-button = Fermer
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Surlignage ajouté
+pdfjs-editor-freetext-added-alert = Texte ajouté
+pdfjs-editor-ink-added-alert = Dessin ajouté
+pdfjs-editor-stamp-added-alert = Image ajoutée
+pdfjs-editor-signature-added-alert = Signature ajoutée
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Surlignage supprimé
+pdfjs-editor-undo-bar-message-freetext = Texte supprimé
+pdfjs-editor-undo-bar-message-ink = Dessin supprimé
+pdfjs-editor-undo-bar-message-stamp = Image supprimée
+pdfjs-editor-undo-bar-message-signature = Signature retirée
+pdfjs-editor-undo-bar-message-comment = Commentaire supprimé
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotation supprimée
+ *[other] { $count } annotations supprimées
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Annuler
+pdfjs-editor-undo-bar-undo-button-label = Annuler
+pdfjs-editor-undo-bar-close-button =
+ .title = Fermer
+pdfjs-editor-undo-bar-close-button-label = Fermer
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Cette fenêtre permet de créer une signature à ajouter à un document au format PDF. Il est possible d’en modifier le nom (qui sert également de texte alternatif) et, éventuellement, de l’enregistrer pour une utilisation répétée.
+pdfjs-editor-add-signature-dialog-title = Ajout d’une signature
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Saisir
+ .title = Saisir au clavier
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dessiner
+ .title = Dessiner
+pdfjs-editor-add-signature-image-button = Image
+ .title = Image
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Saisissez votre signature
+ .placeholder = Saisissez votre signature
+pdfjs-editor-add-signature-draw-placeholder = Tracez votre signature
+pdfjs-editor-add-signature-draw-thickness-range-label = Épaisseur
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Épaisseur du trait : { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Déposez un fichier ici pour l’envoyer
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ou choisissez parmi les fichiers image
+ *[other] Ou parcourez les fichiers image
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Description (texte alternatif)
+pdfjs-editor-add-signature-description-input =
+ .title = Description (texte alternatif)
+pdfjs-editor-add-signature-description-default-when-drawing = Signature
+pdfjs-editor-add-signature-clear-button-label = Effacer la signature
+pdfjs-editor-add-signature-clear-button =
+ .title = Effacer la signature
+pdfjs-editor-add-signature-save-checkbox = Enregistrer la signature
+pdfjs-editor-add-signature-save-warning-message = Vous avez atteint la limite de 5 signatures enregistrées. Supprimez-en une pour en enregistrer une autre.
+pdfjs-editor-add-signature-image-upload-error-title = Impossible d’envoyer l’image
+pdfjs-editor-add-signature-image-upload-error-description = Vérifiez votre connexion réseau ou essayez avec une autre image.
+pdfjs-editor-add-signature-image-no-data-error-title = Impossible de convertir cette image en signature
+pdfjs-editor-add-signature-image-no-data-error-description = Veuillez essayer d’envoyer une autre image.
+pdfjs-editor-add-signature-error-close-button = Fermer
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Annuler
+pdfjs-editor-add-signature-add-button = Ajouter
+pdfjs-editor-edit-signature-update-button = Mettre à jour
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Modifier le commentaire
+pdfjs-editor-edit-comment-popup-button =
+ .title = Modifier le commentaire
+pdfjs-editor-delete-comment-popup-button-label = Supprimer le commentaire
+pdfjs-editor-delete-comment-popup-button =
+ .title = Supprimer le commentaire
+pdfjs-show-comment-button =
+ .title = Voir les commentaires
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Modifier le commentaire
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Mettre à jour
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Ajouter un commentaire
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Ajouter
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Commencer à écrire…
+pdfjs-editor-edit-comment-dialog-cancel-button = Annuler
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Ajouter un commentaire
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Afficher/Masquer le panneau latéral (le document contient des vignettes/plan/pièces jointes/calques)
+pdfjs-toggle-views-manager-button1-label = Gérer les pages
+pdfjs-views-manager-sidebar =
+ .aria-label = Panneau latéral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionner le panneau latéral
+pdfjs-views-manager-view-selector-button =
+ .title = Vues
+pdfjs-views-manager-view-selector-button-label = Vues
+pdfjs-views-manager-pages-title = Pages
+pdfjs-views-manager-outlines-title1 = Structure du document
+ .title = Structure du document (double-cliquer pour développer/réduire tous les éléments)
+pdfjs-views-manager-attachments-title = Pièces jointes
+pdfjs-views-manager-layers-title1 = Calques
+ .title = Calques (double-cliquer pour réinitialiser tous les calques à leur état par défaut)
+pdfjs-views-manager-pages-option-label = Pages
+pdfjs-views-manager-outlines-option-label = Signets du document
+pdfjs-views-manager-attachments-option-label = Pièces jointes
+pdfjs-views-manager-layers-option-label = Calques
+pdfjs-views-manager-add-file-button =
+ .title = Ajouter un fichier
+pdfjs-views-manager-add-file-button-label = Ajouter un fichier
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } page sélectionnée
+ *[other] { $count } pages sélectionnées
+ }
+pdfjs-views-manager-pages-status-none-action-label = Sélectionner des pages
+pdfjs-views-manager-pages-status-action-button-label = Gérer
+pdfjs-views-manager-pages-status-copy-button-label = Copier
+pdfjs-views-manager-pages-status-cut-button-label = Couper
+pdfjs-views-manager-pages-status-delete-button-label = Supprimer
+pdfjs-views-manager-pages-status-export-selected-button-label = Exporter la sélection…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 page coupée
+ *[other] { $count } pages coupées
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 page copiée
+ *[other] { $count } pages copiées
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 page supprimée
+ *[other] { $count } pages supprimées
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Préparation de votre fichier…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Envoi du fichier…
+pdfjs-views-manager-status-warning-cut-label = Impossible de couper. Actualisez la page et essayez à nouveau.
+pdfjs-views-manager-status-warning-copy-label = Copie impossible. Actualisez la page et essayez à nouveau.
+pdfjs-views-manager-status-warning-delete-label = Suppression impossible. Actualisez la page et essayez à nouveau.
+pdfjs-views-manager-status-warning-save-label = Enregistrement impossible. Actualisez la page et essayez à nouveau.
+pdfjs-views-manager-status-undo-button-label = Annuler
+pdfjs-views-manager-status-done-button-label = Terminer
+pdfjs-views-manager-status-close-button =
+ .title = Fermer
+pdfjs-views-manager-status-close-button-label = Fermer
+pdfjs-views-manager-paste-button-label = Coller
+pdfjs-views-manager-paste-button-before =
+ .title = Coller avant la première page
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Coller après la page { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOUVEAU
+pdfjs-views-manager-waiting-for-file = Envoi du fichier…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gérer les pages
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Propriétés de la signature numérique
+ .aria-label = Propriétés de la signature numérique
+pdfjs-digital-signature-properties-button-label = Propriétés de la signature numérique
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Le document a été signé avec une signature numérique valide
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Document signé mais { $count } signature numérique n’a pas pu être vérifiée
+ *[other] Document signé mais { $count } signatures numériques n’ont pas pu être vérifiées
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [1] Document signé avec un certificat non digne de confiance
+ *[other] Document signé avec { $count } certificats non dignes de confiance
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [1] Document signé avec un certificat expiré
+ *[other] Document signé avec { $count } certificats expirés
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [1] Le document contient une signature numérique non valide
+ *[other] Le document contient { $count } signatures numériques non valides
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [1] Document signé avec un certificat révoqué
+ *[other] Document signé avec { $count } certificats révoqués
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = État : signature vérifiée
+pdfjs-digital-signature-properties-status-invalid = État : signature invalide
+pdfjs-digital-signature-properties-status-unknown = État : impossible à vérifier (non pris en charge)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificat : fiable ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificat : indisponible
+pdfjs-digital-signature-properties-certificate-untrusted = Certificat : non fiable
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificat : émetteur inconnu ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificat : auto-signé ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificat : émetteur non fiable ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificat : expiré
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificat : expiré ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificat : révoqué
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Supprimer la signature enregistrée
+pdfjs-editor-delete-signature-button-label1 = Supprimer la signature enregistrée
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Modifier la description
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Modifier la description
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fur/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fur/viewer.ftl
new file mode 100644
index 0000000..ed94224
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fur/viewer.ftl
@@ -0,0 +1,648 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagjine di prime
+pdfjs-previous-button-label = Indaûr
+pdfjs-next-button =
+ .title = Prossime pagjine
+pdfjs-next-button-label = Indevant
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagjine
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = di { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } di { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Impiçulìs
+pdfjs-zoom-out-button-label = Impiçulìs
+pdfjs-zoom-in-button =
+ .title = Ingrandìs
+pdfjs-zoom-in-button-label = Ingrandìs
+pdfjs-zoom-select =
+ .title = Ingrandiment
+pdfjs-presentation-mode-button =
+ .title = Passe ae modalitât presentazion
+pdfjs-presentation-mode-button-label = Modalitât presentazion
+pdfjs-open-file-button =
+ .title = Vierç un file
+pdfjs-open-file-button-label = Vierç
+pdfjs-print-button =
+ .title = Stampe
+pdfjs-print-button-label = Stampe
+pdfjs-save-button =
+ .title = Salve
+pdfjs-save-button-label = Salve
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Discjame
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Discjame
+pdfjs-bookmark-button =
+ .title = Pagjine corinte (mostre URL de pagjine atuâl)
+pdfjs-bookmark-button-label = Pagjine corinte
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Struments
+pdfjs-tools-button-label = Struments
+pdfjs-first-page-button =
+ .title = Va ae prime pagjine
+pdfjs-first-page-button-label = Va ae prime pagjine
+pdfjs-last-page-button =
+ .title = Va ae ultime pagjine
+pdfjs-last-page-button-label = Va ae ultime pagjine
+pdfjs-page-rotate-cw-button =
+ .title = Zire in sens orari
+pdfjs-page-rotate-cw-button-label = Zire in sens orari
+pdfjs-page-rotate-ccw-button =
+ .title = Zire in sens antiorari
+pdfjs-page-rotate-ccw-button-label = Zire in sens antiorari
+pdfjs-cursor-text-select-tool-button =
+ .title = Ative il strument di selezion dal test
+pdfjs-cursor-text-select-tool-button-label = Strument di selezion dal test
+pdfjs-cursor-hand-tool-button =
+ .title = Ative il strument manute
+pdfjs-cursor-hand-tool-button-label = Strument manute
+pdfjs-scroll-page-button =
+ .title = Dopre il scoriment des pagjinis
+pdfjs-scroll-page-button-label = Scoriment pagjinis
+pdfjs-scroll-vertical-button =
+ .title = Dopre scoriment verticâl
+pdfjs-scroll-vertical-button-label = Scoriment verticâl
+pdfjs-scroll-horizontal-button =
+ .title = Dopre scoriment orizontâl
+pdfjs-scroll-horizontal-button-label = Scoriment orizontâl
+pdfjs-scroll-wrapped-button =
+ .title = Dopre scoriment par blocs
+pdfjs-scroll-wrapped-button-label = Scoriment par blocs
+pdfjs-spread-none-button =
+ .title = No sta meti dongje pagjinis in cubie
+pdfjs-spread-none-button-label = No cubiis di pagjinis
+pdfjs-spread-odd-button =
+ .title = Met dongje cubiis di pagjinis scomençant des pagjinis dispar
+pdfjs-spread-odd-button-label = Cubiis di pagjinis, dispar a çampe
+pdfjs-spread-even-button =
+ .title = Met dongje cubiis di pagjinis scomençant des pagjinis pâr
+pdfjs-spread-even-button-label = Cubiis di pagjinis, pâr a çampe
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Proprietâts dal document…
+pdfjs-document-properties-button-label = Proprietâts dal document…
+pdfjs-document-properties-file-name = Non dal file:
+pdfjs-document-properties-file-size = Dimension dal file:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Titul:
+pdfjs-document-properties-author = Autôr:
+pdfjs-document-properties-subject = Ogjet:
+pdfjs-document-properties-keywords = Peraulis clâf:
+pdfjs-document-properties-creation-date = Date di creazion:
+pdfjs-document-properties-modification-date = Date di modifiche:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creatôr
+pdfjs-document-properties-producer = Gjeneradôr PDF:
+pdfjs-document-properties-version = Version PDF:
+pdfjs-document-properties-page-count = Numar di pagjinis:
+pdfjs-document-properties-page-size = Dimension de pagjine:
+pdfjs-document-properties-page-size-unit-inches = oncis
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = verticâl
+pdfjs-document-properties-page-size-orientation-landscape = orizontâl
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letare
+pdfjs-document-properties-page-size-name-legal = Legâl
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Visualizazion web svelte:
+pdfjs-document-properties-linearized-yes = Sì
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Siere
+
+## Print
+
+pdfjs-print-progress-message = Daûr a prontâ il document pe stampe…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Anule
+pdfjs-printing-not-supported = Atenzion: la stampe no je supuartade ad implen di chest navigadôr.
+pdfjs-printing-not-ready = Atenzion: il PDF nol è stât cjamât dal dut pe stampe.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Ative/Disative sbare laterâl
+pdfjs-toggle-sidebar-notification-button =
+ .title = Ative/Disative sbare laterâl (il document al conten struture/zontis/strâts)
+pdfjs-toggle-sidebar-button-label = Ative/Disative sbare laterâl
+pdfjs-document-outline-button =
+ .title = Mostre la struture dal document (dopli clic par slargjâ/strenzi ducj i elements)
+pdfjs-document-outline-button-label = Struture dal document
+pdfjs-attachments-button =
+ .title = Mostre lis zontis
+pdfjs-attachments-button-label = Zontis
+pdfjs-layers-button =
+ .title = Mostre i strâts (dopli clic par ristabilî ducj i strâts al stât predefinît)
+pdfjs-layers-button-label = Strâts
+pdfjs-thumbs-button =
+ .title = Mostre miniaturis
+pdfjs-thumbs-button-label = Miniaturis
+pdfjs-current-outline-item-button =
+ .title = Cjate l'element de struture atuâl
+pdfjs-current-outline-item-button-label = Element de struture atuâl
+pdfjs-findbar-button =
+ .title = Cjate tal document
+pdfjs-findbar-button-label = Cjate
+pdfjs-additional-layers = Strâts adizionâi
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagjine { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniature de pagjine { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Cjate
+ .placeholder = Cjate tal document…
+pdfjs-find-previous-button =
+ .title = Cjate il câs precedent dal test
+pdfjs-find-previous-button-label = Precedent
+pdfjs-find-next-button =
+ .title = Cjate il câs sucessîf dal test
+pdfjs-find-next-button-label = Sucessîf
+pdfjs-find-highlight-checkbox = Evidenzie dut
+pdfjs-find-match-case-checkbox-label = Fâs distinzion tra maiusculis e minusculis
+pdfjs-find-match-diacritics-checkbox-label = Corispondence diacritiche
+pdfjs-find-entire-word-checkbox-label = Peraulis interiis
+pdfjs-find-reached-top = Si è rivâts al inizi dal document e si à continuât de fin
+pdfjs-find-reached-bottom = Si è rivât ae fin dal document e si à continuât dal inizi
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } di { $total } corispondence
+ *[other] { $current } di { $total } corispondencis
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Plui di { $limit } corispondence
+ *[other] Plui di { $limit } corispondencis
+ }
+pdfjs-find-not-found = Test no cjatât
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Largjece de pagjine
+pdfjs-page-scale-fit = Pagjine interie
+pdfjs-page-scale-auto = Ingrandiment automatic
+pdfjs-page-scale-actual = Dimension reâl
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagjine { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Al è vignût fûr un erôr intant che si cjariave il PDF.
+pdfjs-invalid-file-error = File PDF no valit o ruvinât.
+pdfjs-missing-file-error = Al mancje il file PDF.
+pdfjs-unexpected-response-error = Rispueste dal servidôr inspietade.
+pdfjs-rendering-error = Al è vignût fûr un erôr tal realizâ la visualizazion de pagjine.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotazion { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Inserìs la password par vierzi chest file PDF.
+pdfjs-password-invalid = Password no valide. Par plasê torne prove.
+pdfjs-password-ok-button = Va ben
+pdfjs-password-cancel-button = Anule
+pdfjs-web-fonts-disabled = I caratars dal Web a son disativâts: Impussibil doprâ i caratars PDF incorporâts.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Test
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambie colôr dal test
+pdfjs-editor-free-text-button-label = Test
+pdfjs-editor-ink-button =
+ .title = Dissen
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambie colôr dal dissen
+pdfjs-editor-ink-button-label = Dissen
+pdfjs-editor-stamp-button =
+ .title = Zonte o modifiche imagjins
+pdfjs-editor-stamp-button-label = Zonte o modifiche imagjins
+pdfjs-editor-highlight-button =
+ .title = Evidenzie
+pdfjs-editor-highlight-button-label = Evidenzie
+pdfjs-highlight-floating-button1 =
+ .title = Evidenzie
+ .aria-label = Evidenzie
+pdfjs-highlight-floating-button-label = Evidenzie
+pdfjs-comment-floating-button =
+ .title = Comente
+ .aria-label = Comente
+pdfjs-comment-floating-button-label = Comente
+pdfjs-editor-comment-button =
+ .title = Comente
+ .aria-label = Comente
+pdfjs-editor-comment-button-label = Comente
+pdfjs-editor-signature-button =
+ .title = Zonte firme
+pdfjs-editor-signature-button-label = Zonte firme
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Modifiche evidenziazions
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Modifiche dissens
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editôr firmis: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Modifiche imagjins
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Gjave dissen
+pdfjs-editor-remove-freetext-button =
+ .title = Gjave test
+pdfjs-editor-remove-stamp-button =
+ .title = Gjave imagjin
+pdfjs-editor-remove-highlight-button =
+ .title = Gjave evidenziazion
+pdfjs-editor-remove-signature-button =
+ .title = Gjave firme
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Colôr
+pdfjs-editor-free-text-size-input = Dimension
+pdfjs-editor-ink-color-input = Colôr
+pdfjs-editor-ink-thickness-input = Spessôr
+pdfjs-editor-ink-opacity-input = Opacitât
+pdfjs-editor-stamp-add-image-button =
+ .title = Zonte imagjin
+pdfjs-editor-stamp-add-image-button-label = Zonte imagjin
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Spessôr
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Modifiche il spessôr de selezion pai elements che no son testuâi
+pdfjs-editor-add-signature-container =
+ .aria-label = Controi firme e firmis salvadis
+pdfjs-editor-signature-add-signature-button =
+ .title = Zonte gnove firme
+pdfjs-editor-signature-add-signature-button-label = Zonte gnove firme
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firme salvade: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editôr di test
+ .default-content = Scomence a scrivi…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Coment
+ *[other] Coments
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Siere la sbare laterâl
+ .aria-label = Siere la sbare laterâl
+pdfjs-editor-comments-sidebar-close-button-label = Siere la sbare laterâl
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Âstu cjatât alc di interessant? Evidenzilu e lasse un coment.
+pdfjs-editor-comments-sidebar-no-comments-link = Plui informazions
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Test alternatîf
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Modifiche test alternatîf
+pdfjs-editor-alt-text-dialog-label = Sielç une opzion
+pdfjs-editor-alt-text-dialog-description = Il test alternatîf (“alt text”) al jude cuant che lis personis no puedin viodi la imagjin o cuant che la imagjine no ven cjariade.
+pdfjs-editor-alt-text-add-description-label = Zonte une descrizion
+pdfjs-editor-alt-text-add-description-description = Ponte a une o dôs frasis che a descrivin l’argoment, la ambientazion o lis azions.
+pdfjs-editor-alt-text-mark-decorative-label = Segne come decorative
+pdfjs-editor-alt-text-mark-decorative-description = Chest al ven doprât pes imagjins ornamentâls, come i ôrs o lis filigranis.
+pdfjs-editor-alt-text-cancel-button = Anule
+pdfjs-editor-alt-text-save-button = Salve
+pdfjs-editor-alt-text-decorative-tooltip = Segnade come decorative
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Par esempli, “Un zovin si sente a taule par mangjâ”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Test alternatîf
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Cjanton in alt a çampe — ridimensione
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Bande superiôr tal mieç — ridimensione
+pdfjs-editor-resizer-top-right =
+ .aria-label = Cjanton in alt a diestre — ridimensione
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Bande diestre tal mieç — ridimensione
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Cjanton in bas a diestre — ridimensione
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Bande inferiôr tal mieç — ridimensione
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Cjanton in bas a çampe — ridimensione
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Bande di çampe tal mieç — ridimensione
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Colôr par evidenziâ
+pdfjs-editor-colorpicker-button =
+ .title = Cambie colôr
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Sieltis di colôr
+pdfjs-editor-colorpicker-yellow =
+ .title = Zâl
+pdfjs-editor-colorpicker-green =
+ .title = Vert
+pdfjs-editor-colorpicker-blue =
+ .title = Blu
+pdfjs-editor-colorpicker-pink =
+ .title = Rose
+pdfjs-editor-colorpicker-red =
+ .title = Ros
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostre dut
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostre dut
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Modifiche test alternatîf (descrizion de imagjin)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Zonte test alternatîf (descrizion de imagjin)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Scrîf achì la tô descrizion…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Curte descrizion par personis che no rivin a viodi la imagjin, o che e ven mostrade cuant che no si rive a cjariâle.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Chest test alternatîf al è stât creât in automatic e al è pussibil che nol sedi cret.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Plui informazions
+pdfjs-editor-new-alt-text-create-automatically-button-label = Cree test alternatîf in automatic
+pdfjs-editor-new-alt-text-not-now-button = No cumò
+pdfjs-editor-new-alt-text-error-title = Impussibil creâ test alternatîf in automatic
+pdfjs-editor-new-alt-text-error-description = Scrîf il to test alternatîf o prove plui tart.
+pdfjs-editor-new-alt-text-error-close-button = Siere
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Daûr a discjariâil model IA pal test alternatîf ({ $downloadedSize } di { $totalSize } MB)
+ .aria-valuetext = Daûr a discjariâ il model IA pal test alternatîf ({ $downloadedSize } di { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Test alternatîf zontât
+pdfjs-editor-new-alt-text-added-button-label = Test alternatîf zontât
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Al mancje il test alternatîf
+pdfjs-editor-new-alt-text-missing-button-label = Al mancje il test alternatîf
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Verifiche test alternatîf
+pdfjs-editor-new-alt-text-to-review-button-label = Verifiche test alternatîf
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creât in automatic: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Impostazions test alternatîf pes imagjins
+pdfjs-image-alt-text-settings-button-label = Impostazions test alternatîf pes imagjins
+pdfjs-editor-alt-text-settings-dialog-label = Impostazions test alternatîf pes imagjins
+pdfjs-editor-alt-text-settings-automatic-title = Test alternatîf automatic
+pdfjs-editor-alt-text-settings-create-model-button-label = Cree test alternatîf in automatic
+pdfjs-editor-alt-text-settings-create-model-description = Al sugjerìs descrizions par judâ lis personis che no rivin a viodi la imagjin o cuant che la imagjin no ven cjariade.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model IA pal test alternatîf ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Al ven eseguît in locâl sul to dispositîf, cussì che i tiei dâts a restin riservâts. Al è necessari pe gjenerazion automatiche dal test alternatîf.
+pdfjs-editor-alt-text-settings-delete-model-button = Elimine
+pdfjs-editor-alt-text-settings-download-model-button = Discjame
+pdfjs-editor-alt-text-settings-downloading-model-button = Daûr a discjariâ…
+pdfjs-editor-alt-text-settings-editor-title = Modifiche test alternatîf
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostre l'editôr dal test alternatîf a pene che e ven zontade une imagjin
+pdfjs-editor-alt-text-settings-show-dialog-description = Ti jude a sigurâti che dutis lis tôs imagjins a vedin il test alternatîf.
+pdfjs-editor-alt-text-settings-close-button = Siere
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Evidenziazion zontade
+pdfjs-editor-freetext-added-alert = Test zontât
+pdfjs-editor-ink-added-alert = Dissen zontât
+pdfjs-editor-stamp-added-alert = Imagjin zontade
+pdfjs-editor-signature-added-alert = Firme zontade
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Evidenziazion gjavade
+pdfjs-editor-undo-bar-message-freetext = Test gjavât
+pdfjs-editor-undo-bar-message-ink = Dissen gjavât
+pdfjs-editor-undo-bar-message-stamp = Imagjin gjavade
+pdfjs-editor-undo-bar-message-signature = Firme gjavade
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } note gjavade
+ *[other] { $count } notis gjavadis
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Anule
+pdfjs-editor-undo-bar-undo-button-label = Anule
+pdfjs-editor-undo-bar-close-button =
+ .title = Siere
+pdfjs-editor-undo-bar-close-button-label = Siere
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Chest barcon al permet al utent di creâ une firme di zontâ a un document PDF. L’utent al pues modificâ il non (che al vignarà doprât ancje come test alternatîf) e, se lu desidere, salvâ la firme par tornâ a doprâle un doman.
+pdfjs-editor-add-signature-dialog-title = Zonte une firme
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Scrîf
+ .title = Scrîf
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dissegne
+ .title = Dissegne
+pdfjs-editor-add-signature-image-button = Imagjin
+ .title = Imagjin
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Scrîf la tô firme
+ .placeholder = Scrîf la tô firme
+pdfjs-editor-add-signature-draw-placeholder = Dissegne la tô firme
+pdfjs-editor-add-signature-draw-thickness-range-label = Spessôr
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Spessôr de tresse: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Strissine un file achì par cjariâlu
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Opûr sielç i files imagjin
+ *[other] Opûr sgarfe pai files imagjin
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descrizion (test alternatîf)
+pdfjs-editor-add-signature-description-input =
+ .title = Descrizion (test alternatîf)
+pdfjs-editor-add-signature-description-default-when-drawing = Firme
+pdfjs-editor-add-signature-clear-button-label = Nete firme
+pdfjs-editor-add-signature-clear-button =
+ .title = Nete firme
+pdfjs-editor-add-signature-save-checkbox = Salve firme
+pdfjs-editor-add-signature-save-warning-message = Tu sês rivât/rivade al limit di 5 firmis salvadis. Gjave une par salvânt une altre.
+pdfjs-editor-add-signature-image-upload-error-title = Impussibil cjariâ la imagjin
+pdfjs-editor-add-signature-image-upload-error-description = Controle la conession di rêt o prove cuntune altre imagjin.
+pdfjs-editor-add-signature-image-no-data-error-title = Impussibil convertî cheste imagjin intune firme
+pdfjs-editor-add-signature-image-no-data-error-description = Prove a cjariâ une altre imagjin.
+pdfjs-editor-add-signature-error-close-button = Siere
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Anule
+pdfjs-editor-add-signature-add-button = Zonte
+pdfjs-editor-edit-signature-update-button = Inzorne
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Modifiche coment
+pdfjs-editor-edit-comment-popup-button =
+ .title = Modifiche coment
+pdfjs-editor-delete-comment-popup-button-label = Gjave coment
+pdfjs-editor-delete-comment-popup-button =
+ .title = Gjave coment
+pdfjs-show-comment-button =
+ .title = Mostre coment
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Modifiche coment
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Inzorne
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Zonte coment
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Zonte
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Scomence a scrivi…
+pdfjs-editor-edit-comment-dialog-cancel-button = Anule
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Zonte coment
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Gjave firme salvade
+pdfjs-editor-delete-signature-button-label1 = Gjave firme salvade
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Modifiche descrizion
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Modifiche descrizion
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fy-NL/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fy-NL/viewer.ftl
new file mode 100644
index 0000000..828cd85
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/fy-NL/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Foarige side
+pdfjs-previous-button-label = Foarige
+pdfjs-next-button =
+ .title = Folgjende side
+pdfjs-next-button-label = Folgjende
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Side
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = fan { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } fan { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Utzoome
+pdfjs-zoom-out-button-label = Utzoome
+pdfjs-zoom-in-button =
+ .title = Ynzoome
+pdfjs-zoom-in-button-label = Ynzoome
+pdfjs-zoom-select =
+ .title = Zoome
+pdfjs-presentation-mode-button =
+ .title = Wikselje nei presintaasjemodus
+pdfjs-presentation-mode-button-label = Presintaasjemodus
+pdfjs-open-file-button =
+ .title = Bestân iepenje
+pdfjs-open-file-button-label = Iepenje
+pdfjs-print-button =
+ .title = Ofdrukke
+pdfjs-print-button-label = Ofdrukke
+pdfjs-save-button =
+ .title = Bewarje
+pdfjs-save-button-label = Bewarje
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Downloade
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Downloade
+pdfjs-bookmark-button =
+ .title = Aktuele side (URL fan aktuele side besjen)
+pdfjs-bookmark-button-label = Aktuele side
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ark
+pdfjs-tools-button-label = Ark
+pdfjs-first-page-button =
+ .title = Gean nei earste side
+pdfjs-first-page-button-label = Gean nei earste side
+pdfjs-last-page-button =
+ .title = Gean nei lêste side
+pdfjs-last-page-button-label = Gean nei lêste side
+pdfjs-page-rotate-cw-button =
+ .title = Rjochtsom draaie
+pdfjs-page-rotate-cw-button-label = Rjochtsom draaie
+pdfjs-page-rotate-ccw-button =
+ .title = Linksom draaie
+pdfjs-page-rotate-ccw-button-label = Linksom draaie
+pdfjs-cursor-text-select-tool-button =
+ .title = Tekstseleksjehelpmiddel ynskeakelje
+pdfjs-cursor-text-select-tool-button-label = Tekstseleksjehelpmiddel
+pdfjs-cursor-hand-tool-button =
+ .title = Hânhelpmiddel ynskeakelje
+pdfjs-cursor-hand-tool-button-label = Hânhelpmiddel
+pdfjs-scroll-page-button =
+ .title = Sideskowen brûke
+pdfjs-scroll-page-button-label = Sideskowen
+pdfjs-scroll-vertical-button =
+ .title = Fertikaal skowe brûke
+pdfjs-scroll-vertical-button-label = Fertikaal skowe
+pdfjs-scroll-horizontal-button =
+ .title = Horizontaal skowe brûke
+pdfjs-scroll-horizontal-button-label = Horizontaal skowe
+pdfjs-scroll-wrapped-button =
+ .title = Skowe mei oersjoch brûke
+pdfjs-scroll-wrapped-button-label = Skowe mei oersjoch
+pdfjs-spread-none-button =
+ .title = Sidesprieding net gearfetsje
+pdfjs-spread-none-button-label = Gjin sprieding
+pdfjs-spread-odd-button =
+ .title = Sidesprieding gearfetsje te starten mei ûneven nûmers
+pdfjs-spread-odd-button-label = Uneven sprieding
+pdfjs-spread-even-button =
+ .title = Sidesprieding gearfetsje te starten mei even nûmers
+pdfjs-spread-even-button-label = Even sprieding
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokuminteigenskippen…
+pdfjs-document-properties-button-label = Dokuminteigenskippen…
+pdfjs-document-properties-file-name = Bestânsnamme:
+pdfjs-document-properties-file-size = Bestânsgrutte:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Auteur:
+pdfjs-document-properties-subject = Underwerp:
+pdfjs-document-properties-keywords = Kaaiwurden:
+pdfjs-document-properties-creation-date = Oanmaakdatum:
+pdfjs-document-properties-modification-date = Bewurkingsdatum:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Makker:
+pdfjs-document-properties-producer = PDF-makker:
+pdfjs-document-properties-version = PDF-ferzje:
+pdfjs-document-properties-page-count = Siden:
+pdfjs-document-properties-page-size = Sideformaat:
+pdfjs-document-properties-page-size-unit-inches = yn
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = steand
+pdfjs-document-properties-page-size-orientation-landscape = lizzend
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Juridysk
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Flugge webwerjefte:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nee
+pdfjs-document-properties-close-button = Slute
+pdfjs-digital-signature-properties-view-certificate = Sertifikaat besjen
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Reden: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Tiidstimpel: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Undertekening ({ $count })
+ *[other] Undertekeningen ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Dokumint tariede oar ôfdrukken…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Annulearje
+pdfjs-printing-not-supported = Warskôging: ôfdrukken wurdt net folslein stipe troch dizze browser.
+pdfjs-printing-not-ready = Warskôging: PDF is net folslein laden om ôf te drukken.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Sidebalke yn-/útskeakelje
+pdfjs-toggle-sidebar-notification-button =
+ .title = Sidebalke yn-/útskeakelje (dokumint befettet oersjoch/bylagen/lagen)
+pdfjs-toggle-sidebar-button-label = Sidebalke yn-/útskeakelje
+pdfjs-document-outline-button =
+ .title = Dokumintoersjoch toane (dûbelklik om alle items út/yn te klappen)
+pdfjs-document-outline-button-label = Dokumintoersjoch
+pdfjs-attachments-button =
+ .title = Bylagen toane
+pdfjs-attachments-button-label = Bylagen
+pdfjs-layers-button =
+ .title = Lagen toane (dûbelklik om alle lagen nei de standertsteat werom te setten)
+pdfjs-layers-button-label = Lagen
+pdfjs-thumbs-button =
+ .title = Miniatueren toane
+pdfjs-thumbs-button-label = Miniatueren
+pdfjs-current-outline-item-button =
+ .title = Aktueel item yn ynhâldsopjefte sykje
+pdfjs-current-outline-item-button-label = Aktueel item yn ynhâldsopjefte
+pdfjs-findbar-button =
+ .title = Sykje yn dokumint
+pdfjs-findbar-button-label = Sykje
+pdfjs-additional-layers = Oanfoljende lagen
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatuer fan side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Side { $page } selektearje
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Side { $page } fan { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Sykje
+ .placeholder = Sykje yn dokumint…
+pdfjs-find-previous-button =
+ .title = It foarige foarkommen fan de tekst sykje
+pdfjs-find-previous-button-label = Foarige
+pdfjs-find-next-button =
+ .title = It folgjende foarkommen fan de tekst sykje
+pdfjs-find-next-button-label = Folgjende
+pdfjs-find-highlight-checkbox = Alles markearje
+pdfjs-find-match-case-checkbox-label = Haadlettergefoelich
+pdfjs-find-match-diacritics-checkbox-label = Diakrityske tekens brûke
+pdfjs-find-entire-word-checkbox-label = Hiele wurden
+pdfjs-find-reached-top = Boppekant fan dokumint berikt, trochgien fan ûnder ôf
+pdfjs-find-reached-bottom = Ein fan dokumint berikt, trochgien fan boppe ôf
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } fan { $total } oerienkomst
+ *[other] { $current } fan { $total } oerienkomsten
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mear as { $limit } oerienkomst
+ *[other] Mear as { $limit } oerienkomsten
+ }
+pdfjs-find-not-found = Tekst net fûn
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sidebreedte
+pdfjs-page-scale-fit = Hiele side
+pdfjs-page-scale-auto = Automatysk zoome
+pdfjs-page-scale-actual = Werklike grutte
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Side { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Der is in flater bard by it laden fan de PDF.
+pdfjs-invalid-file-error = Ynfalide of korruptearre PDF-bestân.
+pdfjs-missing-file-error = PDF-bestân ûntbrekt.
+pdfjs-unexpected-response-error = Unferwacht serverantwurd.
+pdfjs-rendering-error = Der is in flater bard by it renderjen fan de side.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }-annotaasje]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Jou it wachtwurd om dit PDF-bestân te iepenjen.
+pdfjs-password-invalid = Ferkeard wachtwurd. Probearje opnij.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Annulearje
+pdfjs-web-fonts-disabled = Weblettertypen binne útskeakele: gebrûk fan ynsluten PDF-lettertypen is net mooglik.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Tekstleur wizigje
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Tekenje
+pdfjs-editor-color-picker-ink-input =
+ .title = Tekenkleur wizigje
+pdfjs-editor-ink-button-label = Tekenje
+pdfjs-editor-stamp-button =
+ .title = Ofbyldingen tafoegje of bewurkje
+pdfjs-editor-stamp-button-label = Ofbyldingen tafoegje of bewurkje
+pdfjs-editor-highlight-button =
+ .title = Markearje
+pdfjs-editor-highlight-button-label = Markearje
+pdfjs-highlight-floating-button1 =
+ .title = Markearje
+ .aria-label = Markearje
+pdfjs-highlight-floating-button-label = Markearje
+pdfjs-comment-floating-button =
+ .title = Opmerking
+ .aria-label = Opmerking
+pdfjs-comment-floating-button-label = Opmerking
+pdfjs-editor-comment-button =
+ .title = Opmerking
+ .aria-label = Opmerking
+pdfjs-editor-comment-button-label = Opmerking
+pdfjs-editor-signature-button =
+ .title = Hantekening tafoegje
+pdfjs-editor-signature-button-label = Hantekening tafoegje
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Markearingsbewurker
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Tekeningbewurker
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Undertekeningsbewurker: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Ofbyldingsbewurker
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Tekening fuortsmite
+pdfjs-editor-remove-freetext-button =
+ .title = Tekst fuortsmite
+pdfjs-editor-remove-stamp-button =
+ .title = Ofbylding fuortsmite
+pdfjs-editor-remove-highlight-button =
+ .title = Markearring fuortsmite
+pdfjs-editor-remove-signature-button =
+ .title = Hantekening fuortsmite
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Kleur
+pdfjs-editor-free-text-size-input = Grutte
+pdfjs-editor-ink-color-input = Kleur
+pdfjs-editor-ink-thickness-input = Tsjokte
+pdfjs-editor-ink-opacity-input = Transparânsje
+pdfjs-editor-stamp-add-image-button =
+ .title = Ofbylding tafoegje
+pdfjs-editor-stamp-add-image-button-label = Ofbylding tafoegje
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tsjokte
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Tsjokte wizigje by aksintuearring fan oare items as tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Undertekeningsynstellingen en bewarre ûndertekeningen
+pdfjs-editor-signature-add-signature-button =
+ .title = Nije hantekening tafoegje
+pdfjs-editor-signature-add-signature-button-label = Nije hantekening tafoegje
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Bewarre ûndertekening: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstbewurker
+ .default-content = Start mei typen…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Opmerking
+ *[other] Opmerkingen
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = De sydbalke slute
+ .aria-label = De sydbalke slute
+pdfjs-editor-comments-sidebar-close-button-label = De sydbalke slute
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Sjogge jo wat it neamen wurdich? Markearje it en lit in opmerking efter.
+pdfjs-editor-comments-sidebar-no-comments-link = Mear ynfo
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternative tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternative tekst bewurkje
+pdfjs-editor-alt-text-dialog-label = Kies in opsje
+pdfjs-editor-alt-text-dialog-description = Alternative tekst helpt wannear’t minsken de ôfbylding net sjen kinne of wannear’t dizze net laden wurdt.
+pdfjs-editor-alt-text-add-description-label = Foegje in beskriuwing ta
+pdfjs-editor-alt-text-add-description-description = Stribje nei 1-2 sinnen dy’t it ûnderwerp, de omjouwing of de aksjes beskriuwe.
+pdfjs-editor-alt-text-mark-decorative-label = As dekoratyf markearje
+pdfjs-editor-alt-text-mark-decorative-description = Dit wurdt brûkt foar sierlike ôfbyldingen, lykas rânen of wettermerken.
+pdfjs-editor-alt-text-cancel-button = Annulearje
+pdfjs-editor-alt-text-save-button = Bewarje
+pdfjs-editor-alt-text-decorative-tooltip = As dekoratyf markearre
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Bygelyks, ‘In jonge man sit oan in tafel om te iten’
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternative tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Linkerboppehoek – formaat wizigje
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Midden boppe – formaat wizigje
+pdfjs-editor-resizer-top-right =
+ .aria-label = Rjochterboppehoek – formaat wizigje
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Midden rjochts – formaat wizigje
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Rjochterûnderhoek – formaat wizigje
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Midden ûnder – formaat wizigje
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Linkerûnderhoek – formaat wizigje
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Links midden – formaat wizigje
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Markearringskleur
+pdfjs-editor-colorpicker-button =
+ .title = Kleur wizigje
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Kleurkarren
+pdfjs-editor-colorpicker-yellow =
+ .title = Giel
+pdfjs-editor-colorpicker-green =
+ .title = Grien
+pdfjs-editor-colorpicker-blue =
+ .title = Blau
+pdfjs-editor-colorpicker-pink =
+ .title = Rôs
+pdfjs-editor-colorpicker-red =
+ .title = Read
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Alles toane
+pdfjs-editor-highlight-show-all-button =
+ .title = Alles toane
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alternative tekst (ôfbyldingsbeskriuwing) bewurkje
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alternative tekst (ôfbyldingsbeskriuwing) tafoegje
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skriuw hjir jo beskriuwing…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Koarte beskriuwing foar minsken dy’t de ôfbylding net sjen kinne of wannear’t de ôfbylding net laden wurdt.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Dizze alternative tekst is automatysk makke en is mooglik net korrekt.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Mear ynfo
+pdfjs-editor-new-alt-text-create-automatically-button-label = Alternative tekst automatysk oanmeitsje
+pdfjs-editor-new-alt-text-not-now-button = No net
+pdfjs-editor-new-alt-text-error-title = Kin alternative tekst net automatysk oanmeitsje
+pdfjs-editor-new-alt-text-error-description = Skriuw jo eigen alternative tekst of probearje it letter nochris.
+pdfjs-editor-new-alt-text-error-close-button = Slute
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = AI-model foar alternative tekst downloade ({ $downloadedSize } fan { $totalSize } MB)
+ .aria-valuetext = AI-model foar alternative tekst downloade ({ $downloadedSize } fan { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternative tekst tafoege
+pdfjs-editor-new-alt-text-added-button-label = Alternative tekst tafoege
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Alternative tekst ûntbrekt
+pdfjs-editor-new-alt-text-missing-button-label = Alternative tekst ûntbrekt
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternative tekst beoardiele
+pdfjs-editor-new-alt-text-to-review-button-label = Alternative tekst beoardiele
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automatysk oanmakke: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ynstellingen foar alternative tekst fan ôfbyldingen
+pdfjs-image-alt-text-settings-button-label = Ynstellingen foar alternative tekst fan ôfbyldingen
+pdfjs-editor-alt-text-settings-dialog-label = Ynstellingen foar alternative tekst fan ôfbyldingen
+pdfjs-editor-alt-text-settings-automatic-title = Automatyske alternative tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Alternative tekst automatysk oanmeitsje
+pdfjs-editor-alt-text-settings-create-model-description = Stelt beskriuwingen foar om minsken te helpen dy’t de ôfbylding net sjen kinne of foar wa’t de ôfbylding net laden wurdt.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = AI-model foar alternative tekst ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Wurdt lokaal op jo apparaat útfierd, sadat jo gegevens privee bliuwe. Fereaske foar automatyske alternative tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Fuortsmite
+pdfjs-editor-alt-text-settings-download-model-button = Downloade
+pdfjs-editor-alt-text-settings-downloading-model-button = Downloade…
+pdfjs-editor-alt-text-settings-editor-title = Alternative-tekstbewurker
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Alternative-tekstbewurker daliks toane by tafoegjen fan in ôfbylding
+pdfjs-editor-alt-text-settings-show-dialog-description = Helpt jo derfoar te soargjen dat al jo ôfbyldingen alternative tekst hawwe.
+pdfjs-editor-alt-text-settings-close-button = Slute
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Markearring tafoege
+pdfjs-editor-freetext-added-alert = Tekst tafoege
+pdfjs-editor-ink-added-alert = Tekening tafoege
+pdfjs-editor-stamp-added-alert = Ofbylding tafoege
+pdfjs-editor-signature-added-alert = Hantekening tafoege
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Markearring fuortsmiten
+pdfjs-editor-undo-bar-message-freetext = Tekst fuortsmiten
+pdfjs-editor-undo-bar-message-ink = Tekening fuortsmiten
+pdfjs-editor-undo-bar-message-stamp = Ofbylding fuortsmiten
+pdfjs-editor-undo-bar-message-signature = Hantekening fuortsmiten
+pdfjs-editor-undo-bar-message-comment = Opmerking fuortsmiten
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotaasje fuortsmiten
+ *[other] { $count } annotaasjes fuortsmiten
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Ungedien meitsje
+pdfjs-editor-undo-bar-undo-button-label = Ungedien meitsje
+pdfjs-editor-undo-bar-close-button =
+ .title = Slute
+pdfjs-editor-undo-bar-close-button-label = Slute
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Mei dizze modal kin de brûker in hantekening meitsje om oan in PDF-dokumint ta te foegjen. De brûker kin de namme bewurkje (dy’t ek tsjinnet as alternative tekst), en opsjoneel de ûndertekening bewarje foar werhelle gebrûk.
+pdfjs-editor-add-signature-dialog-title = In hantekening tafoegje
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Type
+ .title = Type
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Tekenje
+ .title = Tekenje
+pdfjs-editor-add-signature-image-button = Ofbylding
+ .title = Ofbylding
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Jo hantekening type
+ .placeholder = Jo hantekening type
+pdfjs-editor-add-signature-draw-placeholder = Jo hantekening tekenje
+pdfjs-editor-add-signature-draw-thickness-range-label = Tsjokte
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Tekentsjokte: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Sleep bestân hjirhinne om op te laden
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Of kies ôfbyldingsbestannen
+ *[other] Of kies ôfbyldingsbestannen
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Beskriuwing (alternative tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Beskriuwing (alternative tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Hantekening
+pdfjs-editor-add-signature-clear-button-label = Hantekening wiskje
+pdfjs-editor-add-signature-clear-button =
+ .title = Hantekening wiskje
+pdfjs-editor-add-signature-save-checkbox = Hantekening bewarje
+pdfjs-editor-add-signature-save-warning-message = Jo hawwe de limyt fan 5 bewarre hantekeningen berikt. Smyt ien fuort om in oar te bewarjen.
+pdfjs-editor-add-signature-image-upload-error-title = Kin de ôfbylding net oplade
+pdfjs-editor-add-signature-image-upload-error-description = Kontrolearje jo netwurkferbining of probearje in oare ôfbylding.
+pdfjs-editor-add-signature-image-no-data-error-title = Kin dizze ôfbylding net nei in hantekening konvertearje
+pdfjs-editor-add-signature-image-no-data-error-description = Probearje in oare ôfbylding op te laden.
+pdfjs-editor-add-signature-error-close-button = Slute
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Annulearje
+pdfjs-editor-add-signature-add-button = Tafoegje
+pdfjs-editor-edit-signature-update-button = Bywurkje
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Opmerking bewurkje
+pdfjs-editor-edit-comment-popup-button =
+ .title = Opmerking bewurkje
+pdfjs-editor-delete-comment-popup-button-label = Opmerking fuortsmite
+pdfjs-editor-delete-comment-popup-button =
+ .title = Opmerking fuortsmite
+pdfjs-show-comment-button =
+ .title = Opmerking toane
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Opmerking bewurkje
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Bywurkje
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Opmerking tafoegje
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Tafoegje
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Begjin mei typen…
+pdfjs-editor-edit-comment-dialog-cancel-button = Annulearje
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Opmerking tafoegje
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Sidebalke yn-/útskeakelje (dokumint befettet miniatueren/oersjoch/bylagen/lagen)
+pdfjs-toggle-views-manager-button1-label = Siden beheare
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidebalke
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Gruttewiziging sydbalke
+pdfjs-views-manager-view-selector-button =
+ .title = Werjeften
+pdfjs-views-manager-view-selector-button-label = Werjeften
+pdfjs-views-manager-pages-title = Siden
+pdfjs-views-manager-outlines-title1 = Dokumintoersjoch
+ .title = Dokumintoersjoch (dûbelklik om alle items út/yn te klappen)
+pdfjs-views-manager-attachments-title = Bylagen
+pdfjs-views-manager-layers-title1 = Lagen
+ .title = Lagen (dûbelklik om alle lagen nei de standertstatus werom te setten)
+pdfjs-views-manager-pages-option-label = Siden
+pdfjs-views-manager-outlines-option-label = Dokumintoersjoch
+pdfjs-views-manager-attachments-option-label = Bylagen
+pdfjs-views-manager-layers-option-label = Lagen
+pdfjs-views-manager-add-file-button =
+ .title = Bestân tafoegje
+pdfjs-views-manager-add-file-button-label = Bestân tafoegje
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selektearre
+ *[other] { $count } selektearre
+ }
+pdfjs-views-manager-pages-status-none-action-label = Siden selektearje
+pdfjs-views-manager-pages-status-action-button-label = Beheare
+pdfjs-views-manager-pages-status-copy-button-label = Kopiearje
+pdfjs-views-manager-pages-status-cut-button-label = Knippe
+pdfjs-views-manager-pages-status-delete-button-label = Fuortsmite
+pdfjs-views-manager-pages-status-export-selected-button-label = Selektearre eksportearje…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 side knipt
+ *[other] { $count } siden knipt
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 side kopiearre
+ *[other] { $count } siden kopiearre
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 side fuortsmiten
+ *[other] { $count } siden fuortsmiten
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Jo bestân tariede…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Bestân oplade…
+pdfjs-views-manager-status-warning-cut-label = Kin net knippe. Ferfarskje de side en probearje it opnij.
+pdfjs-views-manager-status-warning-copy-label = Kin net kopiearje. Ferfarskje de side en probearje it opnij.
+pdfjs-views-manager-status-warning-delete-label = Kin net fuortsmite. Ferfarskje de side en probearje it opnij.
+pdfjs-views-manager-status-warning-save-label = Kin net bewarje. Ferfarskje de side en probearje it opnij.
+pdfjs-views-manager-status-undo-button-label = Ungedien meitsje
+pdfjs-views-manager-status-done-button-label = Dien
+pdfjs-views-manager-status-close-button =
+ .title = Slute
+pdfjs-views-manager-status-close-button-label = Slute
+pdfjs-views-manager-paste-button-label = Plakke
+pdfjs-views-manager-paste-button-before =
+ .title = Plakke foar de earste side
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Plakke nei side { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NIJ
+pdfjs-views-manager-waiting-for-file = Bestân oplade…
+pdfjs-toggle-views-manager-button1 =
+ .title = Siden beheare
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Eigenskippen fan digitale hantekening
+ .aria-label = Eigenskippen fan digitale hantekening
+pdfjs-digital-signature-properties-button-label = Eigenskippen fan digitale hantekening
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokumint is ûndertekene mei in jildige digitale hantekening
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokumint ûndertekene, mar { $count } digitale hantekening koe net ferifiearre wurde
+ *[other] Dokumint ûndertekene, mar { $count } digitale hantekeningen koene net ferifiearre wurde
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokumint ûndertekene mei { $count } sertifikaat dat net fertroud wurdt
+ *[other] Dokumint ûndertekene mei { $count } sertifikaten dy’t net fertroud wurde
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokumint ûndertekene mei { $count } ferrûne sertifikaat
+ *[other] Dokumint ûndertekene mei { $count } ferrûne sertifikaten
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokumint hat { $count } ûnjildige digitale hantekening
+ *[other] Dokumint hat { $count } ûnjildige digitale hantekeningen
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokumint ûndertekene mei { $count } ynlutsen sertifikaat
+ *[other] Dokumint ûndertekene mei { $count } ynlutsen sertifikaten
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: hantekening ferifiearre
+pdfjs-digital-signature-properties-status-invalid = Status: hantekening ûnjildich
+pdfjs-digital-signature-properties-status-unknown = Status: kin net ferifiearje wurde (net stipe)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Sertifikaat: fertroud ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Sertifikaat: net beskikber
+pdfjs-digital-signature-properties-certificate-untrusted = Sertifikaat: net fertroud
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Sertifikaat: Unbekende útjouwer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Sertifikaat: selsûndertekene ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Sertifikaat: net-fertroude útjouwer ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Sertifikaat: ferrûn
+pdfjs-digital-signature-properties-certificate-expired-with-date = Sertifikaat: ferrûn ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Sertifikaat: ynlutsen
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Bewarre ûndertekening fuortsmite
+pdfjs-editor-delete-signature-button-label1 = Bewarre ûndertekening fuortsmite
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Beskriuwing bewurkje
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Beskriuwing bewurkje
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ga-IE/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ga-IE/viewer.ftl
new file mode 100644
index 0000000..680d5bf
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ga-IE/viewer.ftl
@@ -0,0 +1,180 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = An Leathanach Roimhe Seo
+pdfjs-previous-button-label = Roimhe Seo
+pdfjs-next-button =
+ .title = An Chéad Leathanach Eile
+pdfjs-next-button-label = Ar Aghaidh
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Leathanach
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = as { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } as { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Súmáil Amach
+pdfjs-zoom-out-button-label = Súmáil Amach
+pdfjs-zoom-in-button =
+ .title = Súmáil Isteach
+pdfjs-zoom-in-button-label = Súmáil Isteach
+pdfjs-zoom-select =
+ .title = Súmáil
+pdfjs-presentation-mode-button =
+ .title = Úsáid an Mód Láithreoireachta
+pdfjs-presentation-mode-button-label = Mód Láithreoireachta
+pdfjs-open-file-button =
+ .title = Oscail Comhad
+pdfjs-open-file-button-label = Oscail
+pdfjs-print-button =
+ .title = Priontáil
+pdfjs-print-button-label = Priontáil
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Uirlisí
+pdfjs-tools-button-label = Uirlisí
+pdfjs-first-page-button =
+ .title = Go dtí an chéad leathanach
+pdfjs-first-page-button-label = Go dtí an chéad leathanach
+pdfjs-last-page-button =
+ .title = Go dtí an leathanach deiridh
+pdfjs-last-page-button-label = Go dtí an leathanach deiridh
+pdfjs-page-rotate-cw-button =
+ .title = Rothlaigh ar deiseal
+pdfjs-page-rotate-cw-button-label = Rothlaigh ar deiseal
+pdfjs-page-rotate-ccw-button =
+ .title = Rothlaigh ar tuathal
+pdfjs-page-rotate-ccw-button-label = Rothlaigh ar tuathal
+pdfjs-cursor-text-select-tool-button =
+ .title = Cumasaigh an Uirlis Roghnaithe Téacs
+pdfjs-cursor-text-select-tool-button-label = Uirlis Roghnaithe Téacs
+pdfjs-cursor-hand-tool-button =
+ .title = Cumasaigh an Uirlis Láimhe
+pdfjs-cursor-hand-tool-button-label = Uirlis Láimhe
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Airíonna na Cáipéise…
+pdfjs-document-properties-button-label = Airíonna na Cáipéise…
+pdfjs-document-properties-file-name = Ainm an chomhaid:
+pdfjs-document-properties-file-size = Méid an chomhaid:
+pdfjs-document-properties-title = Teideal:
+pdfjs-document-properties-author = Údar:
+pdfjs-document-properties-subject = Ábhar:
+pdfjs-document-properties-keywords = Eochairfhocail:
+pdfjs-document-properties-creation-date = Dáta Cruthaithe:
+pdfjs-document-properties-modification-date = Dáta Athraithe:
+pdfjs-document-properties-creator = Cruthaitheoir:
+pdfjs-document-properties-producer = Cruthaitheoir an PDF:
+pdfjs-document-properties-version = Leagan PDF:
+pdfjs-document-properties-page-count = Líon Leathanach:
+
+##
+
+pdfjs-document-properties-close-button = Dún
+
+## Print
+
+pdfjs-print-progress-message = Cáipéis á hullmhú le priontáil…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cealaigh
+pdfjs-printing-not-supported = Rabhadh: Ní thacaíonn an brabhsálaí le priontáil go hiomlán.
+pdfjs-printing-not-ready = Rabhadh: Ní féidir an PDF a phriontáil go dtí go mbeidh an cháipéis iomlán lódáilte.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Scoránaigh an Barra Taoibh
+pdfjs-toggle-sidebar-button-label = Scoránaigh an Barra Taoibh
+pdfjs-document-outline-button =
+ .title = Taispeáin Imlíne na Cáipéise (déchliceáil chun chuile rud a leathnú nó a laghdú)
+pdfjs-document-outline-button-label = Creatlach na Cáipéise
+pdfjs-attachments-button =
+ .title = Taispeáin Iatáin
+pdfjs-attachments-button-label = Iatáin
+pdfjs-thumbs-button =
+ .title = Taispeáin Mionsamhlacha
+pdfjs-thumbs-button-label = Mionsamhlacha
+pdfjs-findbar-button =
+ .title = Aimsigh sa Cháipéis
+pdfjs-findbar-button-label = Aimsigh
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Leathanach { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Mionsamhail Leathanaigh { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Aimsigh
+ .placeholder = Aimsigh sa cháipéis…
+pdfjs-find-previous-button =
+ .title = Aimsigh an sampla roimhe seo den nath seo
+pdfjs-find-previous-button-label = Roimhe seo
+pdfjs-find-next-button =
+ .title = Aimsigh an chéad sampla eile den nath sin
+pdfjs-find-next-button-label = Ar aghaidh
+pdfjs-find-highlight-checkbox = Aibhsigh uile
+pdfjs-find-match-case-checkbox-label = Cásíogair
+pdfjs-find-entire-word-checkbox-label = Focail iomlána
+pdfjs-find-reached-top = Ag barr na cáipéise, ag leanúint ón mbun
+pdfjs-find-reached-bottom = Ag bun na cáipéise, ag leanúint ón mbarr
+pdfjs-find-not-found = Frása gan aimsiú
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Leithead Leathanaigh
+pdfjs-page-scale-fit = Laghdaigh go dtí an Leathanach
+pdfjs-page-scale-auto = Súmáil Uathoibríoch
+pdfjs-page-scale-actual = Fíormhéid
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Tharla earráid agus an cháipéis PDF á lódáil.
+pdfjs-invalid-file-error = Comhad neamhbhailí nó truaillithe PDF.
+pdfjs-missing-file-error = Comhad PDF ar iarraidh.
+pdfjs-unexpected-response-error = Freagra ón bhfreastalaí nach rabhthas ag súil leis.
+pdfjs-rendering-error = Tharla earráid agus an leathanach á leagan amach.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anótáil { $type }]
+
+## Password
+
+pdfjs-password-label = Cuir an focal faire isteach chun an comhad PDF seo a oscailt.
+pdfjs-password-invalid = Focal faire mícheart. Déan iarracht eile.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cealaigh
+pdfjs-web-fonts-disabled = Tá clófhoirne Gréasáin díchumasaithe: ní féidir clófhoirne leabaithe PDF a úsáid.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gd/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gd/viewer.ftl
new file mode 100644
index 0000000..a15bc9e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gd/viewer.ftl
@@ -0,0 +1,266 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = An duilleag roimhe
+pdfjs-previous-button-label = Air ais
+pdfjs-next-button =
+ .title = An ath-dhuilleag
+pdfjs-next-button-label = Air adhart
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Duilleag
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = à { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } à { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Sùm a-mach
+pdfjs-zoom-out-button-label = Sùm a-mach
+pdfjs-zoom-in-button =
+ .title = Sùm a-steach
+pdfjs-zoom-in-button-label = Sùm a-steach
+pdfjs-zoom-select =
+ .title = Sùm
+pdfjs-presentation-mode-button =
+ .title = Gearr leum dhan mhodh taisbeanaidh
+pdfjs-presentation-mode-button-label = Am modh taisbeanaidh
+pdfjs-open-file-button =
+ .title = Fosgail faidhle
+pdfjs-open-file-button-label = Fosgail
+pdfjs-print-button =
+ .title = Clò-bhuail
+pdfjs-print-button-label = Clò-bhuail
+pdfjs-save-button =
+ .title = Sàbhail
+pdfjs-save-button-label = Sàbhail
+pdfjs-bookmark-button =
+ .title = An duilleag làithreach (Seall an URL on duilleag làithreach)
+pdfjs-bookmark-button-label = An duilleag làithreach
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Innealan
+pdfjs-tools-button-label = Innealan
+pdfjs-first-page-button =
+ .title = Rach gun chiad duilleag
+pdfjs-first-page-button-label = Rach gun chiad duilleag
+pdfjs-last-page-button =
+ .title = Rach gun duilleag mu dheireadh
+pdfjs-last-page-button-label = Rach gun duilleag mu dheireadh
+pdfjs-page-rotate-cw-button =
+ .title = Cuairtich gu deiseil
+pdfjs-page-rotate-cw-button-label = Cuairtich gu deiseil
+pdfjs-page-rotate-ccw-button =
+ .title = Cuairtich gu tuathail
+pdfjs-page-rotate-ccw-button-label = Cuairtich gu tuathail
+pdfjs-cursor-text-select-tool-button =
+ .title = Cuir an comas inneal taghadh an teacsa
+pdfjs-cursor-text-select-tool-button-label = Inneal taghadh an teacsa
+pdfjs-cursor-hand-tool-button =
+ .title = Cuir inneal na làimhe an comas
+pdfjs-cursor-hand-tool-button-label = Inneal na làimhe
+pdfjs-scroll-page-button =
+ .title = Cleachd sgroladh duilleige
+pdfjs-scroll-page-button-label = Sgroladh duilleige
+pdfjs-scroll-vertical-button =
+ .title = Cleachd sgroladh inghearach
+pdfjs-scroll-vertical-button-label = Sgroladh inghearach
+pdfjs-scroll-horizontal-button =
+ .title = Cleachd sgroladh còmhnard
+pdfjs-scroll-horizontal-button-label = Sgroladh còmhnard
+pdfjs-scroll-wrapped-button =
+ .title = Cleachd sgroladh paisgte
+pdfjs-scroll-wrapped-button-label = Sgroladh paisgte
+pdfjs-spread-none-button =
+ .title = Na cuir còmhla sgoileadh dhuilleagan
+pdfjs-spread-none-button-label = Gun sgaoileadh dhuilleagan
+pdfjs-spread-odd-button =
+ .title = Cuir còmhla duilleagan sgaoilte a thòisicheas le duilleagan aig a bheil àireamh chorr
+pdfjs-spread-odd-button-label = Sgaoileadh dhuilleagan corra
+pdfjs-spread-even-button =
+ .title = Cuir còmhla duilleagan sgaoilte a thòisicheas le duilleagan aig a bheil àireamh chothrom
+pdfjs-spread-even-button-label = Sgaoileadh dhuilleagan cothrom
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Roghainnean na sgrìobhainne…
+pdfjs-document-properties-button-label = Roghainnean na sgrìobhainne…
+pdfjs-document-properties-file-name = Ainm an fhaidhle:
+pdfjs-document-properties-file-size = Meud an fhaidhle:
+pdfjs-document-properties-title = Tiotal:
+pdfjs-document-properties-author = Ùghdar:
+pdfjs-document-properties-subject = Cuspair:
+pdfjs-document-properties-keywords = Faclan-luirg:
+pdfjs-document-properties-creation-date = Latha a chruthachaidh:
+pdfjs-document-properties-modification-date = Latha atharrachaidh:
+pdfjs-document-properties-creator = Cruthadair:
+pdfjs-document-properties-producer = Saothraiche a' PDF:
+pdfjs-document-properties-version = Tionndadh a' PDF:
+pdfjs-document-properties-page-count = Àireamh de dhuilleagan:
+pdfjs-document-properties-page-size = Meud na duilleige:
+pdfjs-document-properties-page-size-unit-inches = ann an
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portraid
+pdfjs-document-properties-page-size-orientation-landscape = dreach-tìre
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Litir
+pdfjs-document-properties-page-size-name-legal = Laghail
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Grad shealladh-lìn:
+pdfjs-document-properties-linearized-yes = Tha
+pdfjs-document-properties-linearized-no = Chan eil
+pdfjs-document-properties-close-button = Dùin
+
+## Print
+
+pdfjs-print-progress-message = Ag ullachadh na sgrìobhainn airson clò-bhualadh…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Sguir dheth
+pdfjs-printing-not-supported = Rabhadh: Chan eil am brabhsair seo a' cur làn-taic ri clò-bhualadh.
+pdfjs-printing-not-ready = Rabhadh: Cha deach am PDF a luchdadh gu tur airson clò-bhualadh.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toglaich am bàr-taoibh
+pdfjs-toggle-sidebar-notification-button =
+ .title = Toglaich am bàr-taoibh (tha oir-loidhne/ceanglachain/breathan aig an sgrìobhainn)
+pdfjs-toggle-sidebar-button-label = Toglaich am bàr-taoibh
+pdfjs-document-outline-button =
+ .title = Seall oir-loidhne na sgrìobhainn (dèan briogadh dùbailte airson a h-uile nì a leudachadh/a cho-theannadh)
+pdfjs-document-outline-button-label = Oir-loidhne na sgrìobhainne
+pdfjs-attachments-button =
+ .title = Seall na ceanglachain
+pdfjs-attachments-button-label = Ceanglachain
+pdfjs-layers-button =
+ .title = Seall na breathan (dèan briogadh dùbailte airson a h-uile breath ath-shuidheachadh dhan staid bhunaiteach)
+pdfjs-layers-button-label = Breathan
+pdfjs-thumbs-button =
+ .title = Seall na dealbhagan
+pdfjs-thumbs-button-label = Dealbhagan
+pdfjs-current-outline-item-button =
+ .title = Lorg nì làithreach na h-oir-loidhne
+pdfjs-current-outline-item-button-label = Nì làithreach na h-oir-loidhne
+pdfjs-findbar-button =
+ .title = Lorg san sgrìobhainn
+pdfjs-findbar-button-label = Lorg
+pdfjs-additional-layers = Barrachd breathan
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Duilleag a { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Dealbhag duilleag a { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Lorg
+ .placeholder = Lorg san sgrìobhainn...
+pdfjs-find-previous-button =
+ .title = Lorg làthair roimhe na h-abairt seo
+pdfjs-find-previous-button-label = Air ais
+pdfjs-find-next-button =
+ .title = Lorg ath-làthair na h-abairt seo
+pdfjs-find-next-button-label = Air adhart
+pdfjs-find-highlight-checkbox = Soillsich a h-uile
+pdfjs-find-match-case-checkbox-label = Aire do litrichean mòra is beaga
+pdfjs-find-match-diacritics-checkbox-label = Aire do stràcan
+pdfjs-find-entire-word-checkbox-label = Faclan-slàna
+pdfjs-find-reached-top = Ràinig sinn barr na duilleige, a' leantainn air adhart o bhonn na duilleige
+pdfjs-find-reached-bottom = Ràinig sinn bonn na duilleige, a' leantainn air adhart o bharr na duilleige
+pdfjs-find-not-found = Cha deach an abairt a lorg
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Leud na duilleige
+pdfjs-page-scale-fit = Freagair ri meud na duilleige
+pdfjs-page-scale-auto = Sùm fèin-obrachail
+pdfjs-page-scale-actual = Am fìor-mheud
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Duilleag { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Thachair mearachd rè luchdadh a' PDF.
+pdfjs-invalid-file-error = Faidhle PDF a tha mì-dhligheach no coirbte.
+pdfjs-missing-file-error = Faidhle PDF a tha a dhìth.
+pdfjs-unexpected-response-error = Freagairt on fhrithealaiche ris nach robh dùil.
+pdfjs-rendering-error = Thachair mearachd rè reandaradh na duilleige.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Nòtachadh { $type }]
+
+## Password
+
+pdfjs-password-label = Cuir a-steach am facal-faire gus am faidhle PDF seo fhosgladh.
+pdfjs-password-invalid = Tha am facal-faire cearr. Nach fheuch thu ris a-rithist?
+pdfjs-password-ok-button = Ceart ma-thà
+pdfjs-password-cancel-button = Sguir dheth
+pdfjs-web-fonts-disabled = Tha cruthan-clò lìn à comas: Chan urrainn dhuinn cruthan-clò PDF leabaichte a chleachdadh.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Teacsa
+pdfjs-editor-free-text-button-label = Teacsa
+pdfjs-editor-ink-button =
+ .title = Tarraing
+pdfjs-editor-ink-button-label = Tarraing
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Dath
+pdfjs-editor-free-text-size-input = Meud
+pdfjs-editor-ink-color-input = Dath
+pdfjs-editor-ink-thickness-input = Tighead
+pdfjs-editor-ink-opacity-input = Trìd-dhoilleireachd
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gl/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gl/viewer.ftl
new file mode 100644
index 0000000..b77dda3
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gl/viewer.ftl
@@ -0,0 +1,591 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Páxina anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Seguinte páxina
+pdfjs-next-button-label = Seguinte
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Páxina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Reducir
+pdfjs-zoom-out-button-label = Reducir
+pdfjs-zoom-in-button =
+ .title = Ampliar
+pdfjs-zoom-in-button-label = Ampliar
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Cambiar ao modo presentación
+pdfjs-presentation-mode-button-label = Modo presentación
+pdfjs-open-file-button =
+ .title = Abrir ficheiro
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Gardar
+pdfjs-save-button-label = Gardar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Descargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Descargar
+pdfjs-bookmark-button =
+ .title = Páxina actual (ver o URL da páxina actual)
+pdfjs-bookmark-button-label = Páxina actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ferramentas
+pdfjs-tools-button-label = Ferramentas
+pdfjs-first-page-button =
+ .title = Ir á primeira páxina
+pdfjs-first-page-button-label = Ir á primeira páxina
+pdfjs-last-page-button =
+ .title = Ir á última páxina
+pdfjs-last-page-button-label = Ir á última páxina
+pdfjs-page-rotate-cw-button =
+ .title = Rotar no sentido das agullas do reloxo
+pdfjs-page-rotate-cw-button-label = Rotar no sentido das agullas do reloxo
+pdfjs-page-rotate-ccw-button =
+ .title = Rotar no sentido contrario ás agullas do reloxo
+pdfjs-page-rotate-ccw-button-label = Rotar no sentido contrario ás agullas do reloxo
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar a ferramenta de selección de texto
+pdfjs-cursor-text-select-tool-button-label = Ferramenta de selección de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Activar a ferramenta de man
+pdfjs-cursor-hand-tool-button-label = Ferramenta de man
+pdfjs-scroll-page-button =
+ .title = Usar o desprazamento da páxina
+pdfjs-scroll-page-button-label = Desprazamento da páxina
+pdfjs-scroll-vertical-button =
+ .title = Usar o desprazamento vertical
+pdfjs-scroll-vertical-button-label = Desprazamento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar o desprazamento horizontal
+pdfjs-scroll-horizontal-button-label = Desprazamento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar o desprazamento en bloque
+pdfjs-scroll-wrapped-button-label = Desprazamento por bloque
+pdfjs-spread-none-button =
+ .title = Non agrupar páxinas
+pdfjs-spread-none-button-label = Ningún agrupamento
+pdfjs-spread-odd-button =
+ .title = Crea grupo de páxinas que comezan con números de páxina impares
+pdfjs-spread-odd-button-label = Agrupamento impar
+pdfjs-spread-even-button =
+ .title = Crea grupo de páxinas que comezan con números de páxina pares
+pdfjs-spread-even-button-label = Agrupamento par
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedades do documento…
+pdfjs-document-properties-button-label = Propiedades do documento…
+pdfjs-document-properties-file-name = Nome do ficheiro:
+pdfjs-document-properties-file-size = Tamaño do ficheiro:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Asunto:
+pdfjs-document-properties-keywords = Palabras clave:
+pdfjs-document-properties-creation-date = Data de creación:
+pdfjs-document-properties-modification-date = Data de modificación:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creado por:
+pdfjs-document-properties-producer = Xenerador do PDF:
+pdfjs-document-properties-version = Versión de PDF:
+pdfjs-document-properties-page-count = Número de páxinas:
+pdfjs-document-properties-page-size = Tamaño da páxina:
+pdfjs-document-properties-page-size-unit-inches = pol
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Visualización rápida das páxinas web:
+pdfjs-document-properties-linearized-yes = Si
+pdfjs-document-properties-linearized-no = Non
+pdfjs-document-properties-close-button = Pechar
+
+## Print
+
+pdfjs-print-progress-message = Preparando o documento para imprimir…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Aviso: A impresión non é compatíbel de todo con este navegador.
+pdfjs-printing-not-ready = Aviso: O PDF non se cargou completamente para imprimirse.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Amosar/agochar a barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Alternar barra lateral (o documento contén esquema/anexos/capas)
+pdfjs-toggle-sidebar-button-label = Amosar/agochar a barra lateral
+pdfjs-document-outline-button =
+ .title = Amosar a estrutura do documento (dobre clic para expandir/contraer todos os elementos)
+pdfjs-document-outline-button-label = Estrutura do documento
+pdfjs-attachments-button =
+ .title = Amosar anexos
+pdfjs-attachments-button-label = Anexos
+pdfjs-layers-button =
+ .title = Mostrar capas (prema dúas veces para restaurar todas as capas o estado predeterminado)
+pdfjs-layers-button-label = Capas
+pdfjs-thumbs-button =
+ .title = Amosar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Atopar o elemento delimitado actualmente
+pdfjs-current-outline-item-button-label = Elemento delimitado actualmente
+pdfjs-findbar-button =
+ .title = Atopar no documento
+pdfjs-findbar-button-label = Atopar
+pdfjs-additional-layers = Capas adicionais
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Páxina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura da páxina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Atopar
+ .placeholder = Atopar no documento…
+pdfjs-find-previous-button =
+ .title = Atopar a anterior aparición da frase
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Atopar a seguinte aparición da frase
+pdfjs-find-next-button-label = Seguinte
+pdfjs-find-highlight-checkbox = Realzar todo
+pdfjs-find-match-case-checkbox-label = Diferenciar maiúsculas de minúsculas
+pdfjs-find-match-diacritics-checkbox-label = Distinguir os diacríticos
+pdfjs-find-entire-word-checkbox-label = Palabras completas
+pdfjs-find-reached-top = Chegouse ao inicio do documento, continuar desde o final
+pdfjs-find-reached-bottom = Chegouse ao final do documento, continuar desde o inicio
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] Coincidencia { $current } de { $total }
+ *[other] Coincidencia { $current } de { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Máis de { $limit } coincidencia
+ *[other] Máis de { $limit } coincidencias
+ }
+pdfjs-find-not-found = Non se atopou a frase
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Largura da páxina
+pdfjs-page-scale-fit = Axuste de páxina
+pdfjs-page-scale-auto = Zoom automático
+pdfjs-page-scale-actual = Tamaño actual
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Páxina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Produciuse un erro ao cargar o PDF.
+pdfjs-invalid-file-error = Ficheiro PDF danado ou non válido.
+pdfjs-missing-file-error = Falta o ficheiro PDF.
+pdfjs-unexpected-response-error = Resposta inesperada do servidor.
+pdfjs-rendering-error = Produciuse un erro ao representar a páxina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotación { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Escriba o contrasinal para abrir este ficheiro PDF.
+pdfjs-password-invalid = Contrasinal incorrecto. Tente de novo.
+pdfjs-password-ok-button = Aceptar
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = Desactiváronse as fontes web: foi imposíbel usar as fontes incrustadas no PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Debuxo
+pdfjs-editor-ink-button-label = Debuxo
+pdfjs-editor-stamp-button =
+ .title = Engadir ou editar imaxes
+pdfjs-editor-stamp-button-label = Engadir ou editar imaxes
+pdfjs-editor-highlight-button =
+ .title = Destacar
+pdfjs-editor-highlight-button-label = Destacar
+pdfjs-highlight-floating-button1 =
+ .title = Destacar
+ .aria-label = Destacar
+pdfjs-highlight-floating-button-label = Destacar
+pdfjs-editor-signature-button =
+ .title = Engadir sinatura
+pdfjs-editor-signature-button-label = Engadir sinatura
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de destacados
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de debuxos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de sinaturas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imaxes
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Eliminar debuxo
+pdfjs-editor-remove-freetext-button =
+ .title = Eliminar o texto
+pdfjs-editor-remove-stamp-button =
+ .title = Eliminar a imaxe
+pdfjs-editor-remove-highlight-button =
+ .title = Eliminar o resaltado
+pdfjs-editor-remove-signature-button =
+ .title = Eliminar sinatura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Cor
+pdfjs-editor-free-text-size-input = Tamaño
+pdfjs-editor-ink-color-input = Cor
+pdfjs-editor-ink-thickness-input = Grosor
+pdfjs-editor-ink-opacity-input = Opacidade
+pdfjs-editor-stamp-add-image-button =
+ .title = Engadir imaxe
+pdfjs-editor-stamp-add-image-button-label = Engadir imaxe
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grosor
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Cambiar o grosor ao resaltar elementos que non sexan texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controis de sinaturas e sinaturas gardadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Engadir nova sinatura
+pdfjs-editor-signature-add-signature-button-label = Engadir nova sinatura
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Sinatura gardada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Empeza a escribir...
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar o texto alternativo
+pdfjs-editor-alt-text-dialog-label = Escoller unha opción
+pdfjs-editor-alt-text-dialog-description = O texto alternativo (texto alt) axuda cando as persoas non poden ver a imaxe ou cando non se carga.
+pdfjs-editor-alt-text-add-description-label = Engadir unha descrición
+pdfjs-editor-alt-text-add-description-description = Tenta escribir 1-2 frases que describan o tema, o escenario ou as accións.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativo
+pdfjs-editor-alt-text-mark-decorative-description = Utilízase para imaxes ornamentais, como bordos ou marcas de auga.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Gardar
+pdfjs-editor-alt-text-decorative-tooltip = Marcado como decorativo
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por exemplo, «Un mozo séntase á mesa para comer»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Esquina superior esquerda: cambia o tamaño
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Medio superior: cambia o tamaño
+pdfjs-editor-resizer-top-right =
+ .aria-label = Esquina superior dereita: cambia o tamaño
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Medio dereito: cambia o tamaño
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Esquina inferior dereita: cambia o tamaño
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Abaixo medio: cambia o tamaño
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Esquina inferior esquerda: cambia o tamaño
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Medio esquerdo: cambia o tamaño
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Cor de resaltado
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar de cor
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opcións de cor
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarelo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Vermello
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Amosar todo
+pdfjs-editor-highlight-show-all-button =
+ .title = Amosar todo
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descrición da imaxe)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Engadir texto alternativo (descrición da imaxe)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escribe a túa descrición aquí...
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Breve descrición para as persoas que non poden ver a imaxe ou cando a imaxe non carga.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo creouse automaticamente e pode ser inexacto.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Máis información
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crea texto alternativo automaticamente
+pdfjs-editor-new-alt-text-not-now-button = Agora non
+pdfjs-editor-new-alt-text-error-title = Non se puido crear o texto alternativo automaticamente
+pdfjs-editor-new-alt-text-error-description = Escribe o teu propio texto alternativo ou téntao de novo máis tarde.
+pdfjs-editor-new-alt-text-error-close-button = Pechar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Descargando o modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Descargando o modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Texto alternativo engadido
+pdfjs-editor-new-alt-text-added-button-label = Texto alternativo engadido
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Falta o texto alternativo
+pdfjs-editor-new-alt-text-missing-button-label = Falta o texto alternativo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revisar o texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Revisar o texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creado automaticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Configuración do texto alternativo da imaxe
+pdfjs-image-alt-text-settings-button-label = Configuración do texto alternativo da imaxe
+pdfjs-editor-alt-text-settings-dialog-label = Configuración do texto alternativo da imaxe
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear texto alternativo automaticamente
+pdfjs-editor-alt-text-settings-create-model-description = Suxire descricións para axudar ás persoas que non poden ver a imaxe ou cando a imaxe non se carga.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de IA de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Funciona localmente no teu dispositivo para que os teus datos se manteñan privados. Necesario para o texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Eliminar
+pdfjs-editor-alt-text-settings-download-model-button = Descargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Descargando…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar o editor de texto alternativo inmediatamente ao engadir unha imaxe
+pdfjs-editor-alt-text-settings-show-dialog-description = Axúdache a asegurarte de que todas as túas imaxes teñan texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Pechar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Resaltado engadido
+pdfjs-editor-freetext-added-alert = Texto engadido
+pdfjs-editor-ink-added-alert = Debuxo engadido
+pdfjs-editor-stamp-added-alert = Imaxe engadida
+pdfjs-editor-signature-added-alert = Sinatura engadida
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Resaltado eliminado
+pdfjs-editor-undo-bar-message-freetext = Texto eliminado
+pdfjs-editor-undo-bar-message-ink = Debuxo eliminado
+pdfjs-editor-undo-bar-message-stamp = Imaxe eliminada
+pdfjs-editor-undo-bar-message-signature = Sinatura eliminada
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] Eliminouse { $count } anotación
+ *[other] Elimináronse { $count } anotacións
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Desfacer
+pdfjs-editor-undo-bar-undo-button-label = Desfacer
+pdfjs-editor-undo-bar-close-button =
+ .title = Pechar
+pdfjs-editor-undo-bar-close-button-label = Pechar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Este modal permite ao usuario crear unha sinatura para engadila a un documento PDF. O usuario pode editar o nome (que tamén serve como texto alternativo) e, opcionalmente, gardar a sinatura para usala novamente.
+pdfjs-editor-add-signature-dialog-title = Engadir unha sinatura
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tipo
+ .title = Tipo
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Debuxar
+ .title = Debuxar
+pdfjs-editor-add-signature-image-button = Imaxe
+ .title = Imaxe
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Escribe a túa sinatura
+ .placeholder = Escribe a túa sinatura
+pdfjs-editor-add-signature-draw-placeholder = Debuxa a túa sinatura
+pdfjs-editor-add-signature-draw-thickness-range-label = Grosor
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grosor do debuxo: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arrastra un ficheiro aquí para cargalo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ou selecciona ficheiros de imaxes
+ *[other] Ou navega ficheiros de imaxes
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descrición (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descrición (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Sinatura
+pdfjs-editor-add-signature-clear-button-label = Borrar a sinatura
+pdfjs-editor-add-signature-clear-button =
+ .title = Borrar a sinatura
+pdfjs-editor-add-signature-save-checkbox = Gardar a sinatura
+pdfjs-editor-add-signature-save-warning-message = Acadaches o límite de 5 sinaturas gardadas. Elimina unha para gardar máis.
+pdfjs-editor-add-signature-image-upload-error-title = Non se puido cargar a imaxe
+pdfjs-editor-add-signature-image-upload-error-description = Comproba a túa conexión de rede ou proba con outra imaxe.
+pdfjs-editor-add-signature-error-close-button = Pechar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Engadir
+pdfjs-editor-edit-signature-update-button = Actualizar
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Eliminar a sinatura gardada
+pdfjs-editor-delete-signature-button-label1 = Eliminar a sinatura gardada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editar descrición
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editar descrición
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gn/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gn/viewer.ftl
new file mode 100644
index 0000000..aff1523
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gn/viewer.ftl
@@ -0,0 +1,816 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Kuatiarogue mboyvegua
+pdfjs-previous-button-label = Mboyvegua
+pdfjs-next-button =
+ .title = Kuatiarogue upeigua
+pdfjs-next-button-label = Upeigua
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Kuatiarogue
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } gui
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Momichĩ
+pdfjs-zoom-out-button-label = Momichĩ
+pdfjs-zoom-in-button =
+ .title = Mbotuicha
+pdfjs-zoom-in-button-label = Mbotuicha
+pdfjs-zoom-select =
+ .title = Tuichakue
+pdfjs-presentation-mode-button =
+ .title = Jehechauka reko moambue
+pdfjs-presentation-mode-button-label = Jehechauka reko
+pdfjs-open-file-button =
+ .title = Marandurendápe jeike
+pdfjs-open-file-button-label = Jeike
+pdfjs-print-button =
+ .title = Monguatia
+pdfjs-print-button-label = Monguatia
+pdfjs-save-button =
+ .title = Ñongatu
+pdfjs-save-button-label = Ñongatu
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Mboguejy
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Mboguejy
+pdfjs-bookmark-button =
+ .title = Kuatiarogue ag̃agua (Ehecha URL kuatiarogue ag̃agua)
+pdfjs-bookmark-button-label = Kuatiarogue Ag̃agua
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tembiporu
+pdfjs-tools-button-label = Tembiporu
+pdfjs-first-page-button =
+ .title = Kuatiarogue ñepyrũme jeho
+pdfjs-first-page-button-label = Kuatiarogue ñepyrũme jeho
+pdfjs-last-page-button =
+ .title = Kuatiarogue pahápe jeho
+pdfjs-last-page-button-label = Kuatiarogue pahápe jeho
+pdfjs-page-rotate-cw-button =
+ .title = Aravóicha mbojere
+pdfjs-page-rotate-cw-button-label = Aravóicha mbojere
+pdfjs-page-rotate-ccw-button =
+ .title = Aravo rapykue gotyo mbojere
+pdfjs-page-rotate-ccw-button-label = Aravo rapykue gotyo mbojere
+pdfjs-cursor-text-select-tool-button =
+ .title = Emyandy moñe’ẽrã jeporavo rembiporu
+pdfjs-cursor-text-select-tool-button-label = Moñe’ẽrã jeporavo rembiporu
+pdfjs-cursor-hand-tool-button =
+ .title = Tembiporu po pegua myandy
+pdfjs-cursor-hand-tool-button-label = Tembiporu po pegua
+pdfjs-scroll-page-button =
+ .title = Eiporu kuatiarogue jeku’e
+pdfjs-scroll-page-button-label = Kuatiarogue jeku’e
+pdfjs-scroll-vertical-button =
+ .title = Eiporu jeku’e ykeguáva
+pdfjs-scroll-vertical-button-label = Jeku’e ykeguáva
+pdfjs-scroll-horizontal-button =
+ .title = Eiporu jeku’e yvate gotyo
+pdfjs-scroll-horizontal-button-label = Jeku’e yvate gotyo
+pdfjs-scroll-wrapped-button =
+ .title = Eiporu jeku’e mbohyrupyre
+pdfjs-scroll-wrapped-button-label = Jeku’e mbohyrupyre
+pdfjs-spread-none-button =
+ .title = Ani ejuaju spreads kuatiarogue ndive
+pdfjs-spread-none-button-label = Spreads ỹre
+pdfjs-spread-odd-button =
+ .title = Embojuaju kuatiarogue jepysokue eñepyrũvo kuatiarogue impar-vagui
+pdfjs-spread-odd-button-label = Spreads impar
+pdfjs-spread-even-button =
+ .title = Embojuaju kuatiarogue jepysokue eñepyrũvo kuatiarogue par-vagui
+pdfjs-spread-even-button-label = Ipukuve uvei
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Kuatia mba’etee…
+pdfjs-document-properties-button-label = Kuatia mba’etee…
+pdfjs-document-properties-file-name = Marandurenda réra:
+pdfjs-document-properties-file-size = Marandurenda tuichakue:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Teratee:
+pdfjs-document-properties-author = Apohára:
+pdfjs-document-properties-subject = Mba’egua:
+pdfjs-document-properties-keywords = Jehero:
+pdfjs-document-properties-creation-date = Teñoihague arange:
+pdfjs-document-properties-modification-date = Iñambue hague arange:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Apo’ypyha:
+pdfjs-document-properties-producer = PDF mbosako’iha:
+pdfjs-document-properties-version = PDF mbojuehegua:
+pdfjs-document-properties-page-count = Kuatiarogue papapy:
+pdfjs-document-properties-page-size = Kuatiarogue tuichakue:
+pdfjs-document-properties-page-size-unit-inches = Amo
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = Oĩháicha
+pdfjs-document-properties-page-size-orientation-landscape = apaisado
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Kuatiañe’ẽ
+pdfjs-document-properties-page-size-name-legal = Tee
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Ñanduti jahecha pya’e:
+pdfjs-document-properties-linearized-yes = Añete
+pdfjs-document-properties-linearized-no = Ahániri
+pdfjs-document-properties-close-button = Mboty
+pdfjs-digital-signature-properties-view-certificate = Mboajapyre jehecha
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Mba’ére: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Ára: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Mboheraguapy’i ({ $count })
+ *[other] Mboheraguapy’ieta ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Embosako’i kuatia emonguatia hag̃ua…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Heja
+pdfjs-printing-not-supported = Kyhyjerã: Ñembokuatia ndojokupytypái ko kundahára ndive.
+pdfjs-printing-not-ready = Kyhyjerã: Ko PDF nahenyhẽmbái oñembokuatia hag̃uáicha.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Tenda yke moambue
+pdfjs-toggle-sidebar-notification-button =
+ .title = Embojopyru tenda ykegua (kuatia oguereko kuaakaha/moirũha/ñuãha)
+pdfjs-toggle-sidebar-button-label = Tenda yke moambue
+pdfjs-document-outline-button =
+ .title = Ehechauka kuatia rape (eikutu mokõi jey embotuicha/emomichĩ hag̃ua opavavete mba’eporu)
+pdfjs-document-outline-button-label = Kuatia apopyre
+pdfjs-attachments-button =
+ .title = Moirũha jehechauka
+pdfjs-attachments-button-label = Moirũha
+pdfjs-layers-button =
+ .title = Ehechauka ñuãha (eikutu jo’a emomba’apo hag̃ua opaite ñuãha tekoypýpe)
+pdfjs-layers-button-label = Ñuãha
+pdfjs-thumbs-button =
+ .title = Mba’emirĩ jehechauka
+pdfjs-thumbs-button-label = Mba’emirĩ
+pdfjs-current-outline-item-button =
+ .title = Eheka mba’eporu ag̃aguaitéva
+pdfjs-current-outline-item-button-label = Mba’eporu ag̃aguaitéva
+pdfjs-findbar-button =
+ .title = Kuatiápe jeheka
+pdfjs-findbar-button-label = Juhu
+pdfjs-additional-layers = Ñuãha moirũguáva
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Kuatiarogue { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Kuatiarogue mba’emirĩ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Eiporavo kuatiarogue { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Kuatiarogue { $page } { $total } mba’e
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Juhu
+ .placeholder = Kuatiápe jejuhu…
+pdfjs-find-previous-button =
+ .title = Ejuhu ñe’ẽrysýi osẽ’ypy hague
+pdfjs-find-previous-button-label = Mboyvegua
+pdfjs-find-next-button =
+ .title = Eho ñe’ẽ juhupyre upeiguávape
+pdfjs-find-next-button-label = Upeigua
+pdfjs-find-highlight-checkbox = Embojekuaavepa
+pdfjs-find-match-case-checkbox-label = Ejesareko taiguasu/taimichĩre
+pdfjs-find-match-diacritics-checkbox-label = Diacrítico moñondive
+pdfjs-find-entire-word-checkbox-label = Ñe’ẽ oĩmbáva
+pdfjs-find-reached-top = Ojehupyty kuatia ñepyrũ, oku’ejeýta kuatia paha guive
+pdfjs-find-reached-bottom = Ojehupyty kuatia paha, oku’ejeýta kuatia ñepyrũ guive
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } ha { $total } ojueheguáva
+ *[other] { $current } ha { $total } ojueheguáva
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Hetave { $limit } ojueheguáva
+ *[other] Hetave { $limit } ojueheguáva
+ }
+pdfjs-find-not-found = Ñe’ẽrysýi ojejuhu’ỹva
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Kuatiarogue pekue
+pdfjs-page-scale-fit = Kuatiarogue ñemoĩporã
+pdfjs-page-scale-auto = Tuichakue ijeheguíva
+pdfjs-page-scale-actual = Tuichakue ag̃agua
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Kuatiarogue { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Oiko jejavy PDF oñemyeñyhẽnguévo.
+pdfjs-invalid-file-error = PDF marandurenda ndoikóiva térã ivaipyréva.
+pdfjs-missing-file-error = Ndaipóri PDF marandurenda
+pdfjs-unexpected-response-error = Mohendahavusu mbohovái eha’ãrõ’ỹva.
+pdfjs-rendering-error = Oiko jejavy ehechaukasévo kuatiarogue.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Jehaipy { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Emoinge ñe’ẽñemi eipe’a hag̃ua ko marandurenda PDF.
+pdfjs-password-invalid = Ñe’ẽñemi ndoikóiva. Eha’ã jey.
+pdfjs-password-ok-button = MONEĨ
+pdfjs-password-cancel-button = Heja
+pdfjs-web-fonts-disabled = Ñanduti taity oñemongéma: ndaikatumo’ãi eiporu PDF jehai’íva taity.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Moñe’ẽrã
+pdfjs-editor-color-picker-free-text-input =
+ .title = Emoambue moñe’ẽrã sa’y
+pdfjs-editor-free-text-button-label = Moñe’ẽrã
+pdfjs-editor-ink-button =
+ .title = Moha’ãnga
+pdfjs-editor-color-picker-ink-input =
+ .title = Emoambue ta’ãnga sa’y
+pdfjs-editor-ink-button-label = Moha’ãnga
+pdfjs-editor-stamp-button =
+ .title = Embojuaju térã embosako’i ta’ãnga
+pdfjs-editor-stamp-button-label = Embojuaju térã embosako’i ta’ãnga
+pdfjs-editor-highlight-button =
+ .title = Mbosa’y
+pdfjs-editor-highlight-button-label = Mbosa’y
+pdfjs-highlight-floating-button1 =
+ .title = Mbosa’y
+ .aria-label = Mbosa’y
+pdfjs-highlight-floating-button-label = Mbosa’y
+pdfjs-comment-floating-button =
+ .title = Je’erei
+ .aria-label = Je’erei
+pdfjs-comment-floating-button-label = Je’erei
+pdfjs-editor-comment-button =
+ .title = Je’erei
+ .aria-label = Je’erei
+pdfjs-editor-comment-button-label = Je’erei
+pdfjs-editor-signature-button =
+ .title = Embojuaju teraguapy
+pdfjs-editor-signature-button-label = Embojuaju teraguapy
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Jehechaukarã mbosako’iha
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Ta’ãnga’apo moheñoiha
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Teraguapy mbosako’iha: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Ta’ãnga mbosako’iha
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Emboguete ta’ãnga
+pdfjs-editor-remove-freetext-button =
+ .title = Emboguete moñe’ẽrã
+pdfjs-editor-remove-stamp-button =
+ .title = Emboguete ta’ãnga
+pdfjs-editor-remove-highlight-button =
+ .title = Eipe’a jehechaveha
+pdfjs-editor-remove-signature-button =
+ .title = Embogue teraguapy
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Sa’y
+pdfjs-editor-free-text-size-input = Tuichakue
+pdfjs-editor-ink-color-input = Sa’y
+pdfjs-editor-ink-thickness-input = Anambusu
+pdfjs-editor-ink-opacity-input = Pytũngy
+pdfjs-editor-stamp-add-image-button =
+ .title = Embojuaju ta’ãnga
+pdfjs-editor-stamp-add-image-button-label = Embojuaju ta’ãnga
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Anambusu
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Emoambue anambusukue embosa’ývo mba’eporu ha’e’ỹva moñe’ẽrã
+pdfjs-editor-add-signature-container =
+ .aria-label = Teraguapy ñemaña ha teraguapy ñongatupyre
+pdfjs-editor-signature-add-signature-button =
+ .title = Embojuaju teraguapy pyahu
+pdfjs-editor-signature-add-signature-button-label = Embojuaju teraguapy pyahu
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Teraguapy ñongatupyre: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Moñe’ẽrã moheñoiha
+ .default-content = Eñepyrũ ehai…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Je’erei
+ *[other] Je’ereieta
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Emboty ta'ãngarupa yke
+ .aria-label = Emboty ta'ãngarupa yke
+pdfjs-editor-comments-sidebar-close-button-label = Emboty ta'ãngarupa yke
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ¿Ehechápa peteĩ mbaʼe iporãva? Emomba’e ha eheja jehaipy.
+pdfjs-editor-comments-sidebar-no-comments-link = Kuaave
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Moñe’ẽrã mokõiháva
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Embojuruja moñe’ẽrã mokõiháva
+pdfjs-editor-alt-text-dialog-label = Eiporavo poravorã
+pdfjs-editor-alt-text-dialog-description = Moñe’ẽrã ykepegua (moñe’ẽrã ykepegua) nepytyvõ nderehecháiramo ta’ãnga térã nahenyhẽiramo.
+pdfjs-editor-alt-text-add-description-label = Embojuaju ñemoha’ãnga
+pdfjs-editor-alt-text-add-description-description = Ehaimi 1 térã 2 ñe’ẽjuaju oñe’ẽva pe téma rehe, ijere térã mba’eapóre.
+pdfjs-editor-alt-text-mark-decorative-label = Emongurusu jeguakárõ
+pdfjs-editor-alt-text-mark-decorative-description = Ojeporu ta’ãnga jeguakarã, tembe’y térã ta’ãnga ruguarãramo.
+pdfjs-editor-alt-text-cancel-button = Heja
+pdfjs-editor-alt-text-save-button = Ñongatu
+pdfjs-editor-alt-text-decorative-tooltip = Jeguakárõ mongurusupyre
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Techapyrã: “Peteĩ mitãrusu oguapy mesápe okaru hag̃ua”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Moñe’ẽrã mokõiháva
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Yvate asu gotyo — emoambue tuichakue
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Yvate mbytépe — emoambue tuichakue
+pdfjs-editor-resizer-top-right =
+ .aria-label = Yvate akatúape — emoambue tuichakue
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Mbyte akatúape — emoambue tuichakue
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Yvy gotyo akatúape — emoambue tuichakue
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Yvy gotyo mbytépe — emoambue tuichakue
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Iguýpe asu gotyo — emoambue tuichakue
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Mbyte asu gotyo — emoambue tuichakue
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Jehechaveha sa’y
+pdfjs-editor-colorpicker-button =
+ .title = Emoambue sa’y
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Sa’y poravopyrã
+pdfjs-editor-colorpicker-yellow =
+ .title = Sa’yju
+pdfjs-editor-colorpicker-green =
+ .title = Hovyũ
+pdfjs-editor-colorpicker-blue =
+ .title = Hovy
+pdfjs-editor-colorpicker-pink =
+ .title = Pytãngy
+pdfjs-editor-colorpicker-red =
+ .title = Pyha
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Techaukapa
+pdfjs-editor-highlight-show-all-button =
+ .title = Techaukapa
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Embosako’i moñe’ẽrã mokõiha (ta’ãngáre ñeñe’ẽ)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Embojuaju moñe’ẽrã mokõiha (ta’ãngáre ñeñe’ẽ)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Edescribi ko’ápe…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Ñemyesakã mbykymi opavave ohecha’ỹva upe ta’ãnga térã pe ta’ãnga nahenyhẽiramo.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ko moñe’ẽrã mokõiha oñemoheñói ijehegui ha ikatu ndoikoporãi.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Eikuaave
+pdfjs-editor-new-alt-text-create-automatically-button-label = Emoheñói moñe’ẽrã mokõiha ijeheguíva
+pdfjs-editor-new-alt-text-not-now-button = Ani ko’ág̃a
+pdfjs-editor-new-alt-text-error-title = Noñemoheñói moñe’ẽrã mokõiha ijeheguíva
+pdfjs-editor-new-alt-text-error-description = Ehai ne moñe’ẽrã mokõiha térã eha’ã jey ag̃amieve.
+pdfjs-editor-new-alt-text-error-close-button = Mboty
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Emboguejyhína IA moñe’ẽrã mokõiháva ({ $downloadedSize } { $totalSize } MB) mba’e
+ .aria-valuetext = Emboguejyhína IA moñe’ẽrã mokõiháva ({ $downloadedSize } { $totalSize } MB) mba’e
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Moñe’ẽrã mokõiha mbojuajupyre
+pdfjs-editor-new-alt-text-added-button-label = Oñembojuaju moñe’ẽrã mokõiha
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Ndaipóri moñe’ẽrã mokõiha
+pdfjs-editor-new-alt-text-missing-button-label = Ndaipóri moñe’ẽrã mokõiha
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Ehechajey moñe’ẽrã mokõiha
+pdfjs-editor-new-alt-text-to-review-button-label = Ehechajey moñe’ẽrã mokõiha
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Heñóiva ijeheguiete: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ta’ãnga moñe’ẽrã mokõiha ñemboheko
+pdfjs-image-alt-text-settings-button-label = Ta’ãnga moñe’ẽrã mokõiha ñemboheko
+pdfjs-editor-alt-text-settings-dialog-label = Ta’ãnga moñe’ẽrã mokõiha ñemboheko
+pdfjs-editor-alt-text-settings-automatic-title = Moñe’ẽrã mokõiha ijeheguíva
+pdfjs-editor-alt-text-settings-create-model-button-label = Emoheñói moñe’ẽrã mokõiha ijeheguíva
+pdfjs-editor-alt-text-settings-create-model-description = Ñemyesakã mbykymi opavave tapicha ohecha’ỹva upe ta’ãnga térã pe ta’ãnga nahenyhẽiramo.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Peteĩva IA moñe’ẽrã mokõiha ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Oku’e mba’e’okaitépe umi mba’ekuaarã hekoñemi hag̃ua. Tekotevẽva moñe’ẽrã ykegua ijeheguívape.
+pdfjs-editor-alt-text-settings-delete-model-button = Mboguete
+pdfjs-editor-alt-text-settings-download-model-button = Mboguejy
+pdfjs-editor-alt-text-settings-downloading-model-button = Emboguejyhína…
+pdfjs-editor-alt-text-settings-editor-title = Moñe’ẽrã mokõiha mbosako’iha
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Ehechauka moñe’ẽrã mokõiha mbosako’iha embojuajúvo ta’ãnga
+pdfjs-editor-alt-text-settings-show-dialog-description = Nepytyvõta ta’ãngakuéra orekotaha moñe’ẽrã mokõiha.
+pdfjs-editor-alt-text-settings-close-button = Mboty
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Techaukarã juajupyre
+pdfjs-editor-freetext-added-alert = Moñe’ẽrã juajupyre
+pdfjs-editor-ink-added-alert = Ta’ãnga juajupyre
+pdfjs-editor-stamp-added-alert = Ta’ãnga juajupyre
+pdfjs-editor-signature-added-alert = Teraguapy juajupyre
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Mbosa’ýva mboguete
+pdfjs-editor-undo-bar-message-freetext = Moñe’ẽrã mboguepyre
+pdfjs-editor-undo-bar-message-ink = Ta’ãnga mboguepyre
+pdfjs-editor-undo-bar-message-stamp = Ta’ãnga mboguepyre
+pdfjs-editor-undo-bar-message-signature = Teraguapy mboguepyre
+pdfjs-editor-undo-bar-message-comment = Je’epy mboguepyre
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } jehaikue mboguepyre
+ *[other] { $count } jehaikue mboguepyre
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Mboguevi
+pdfjs-editor-undo-bar-undo-button-label = Mboguevi
+pdfjs-editor-undo-bar-close-button =
+ .title = Mboty
+pdfjs-editor-undo-bar-close-button-label = Mboty
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Ko modal omoneĩ poruhárape omoheñóivo mboheraguapy ombojuaju hag̃ua PDF rehe. Upe poruhára ombosako’ikuaa téra (oikóva avei moñe’ẽrã mokõihávarõ) ha, ejaposérõ, eñongatu mboheraguapy eiporujey hag̃ua.
+pdfjs-editor-add-signature-dialog-title = Embojuaju teraguapy
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Jehai
+ .title = Jehai
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Moha’ãnga
+ .title = Moha’ãnga
+pdfjs-editor-add-signature-image-button = Ta’ãnga
+ .title = Ta’ãnga
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Ehai nde reraguapy
+ .placeholder = Ehai nde reraguapy
+pdfjs-editor-add-signature-draw-placeholder = Emoha’ãnga nde reraguapy
+pdfjs-editor-add-signature-draw-thickness-range-label = Anambusu
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Ta’ãnga anambusukue: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Egueru marandurenda ápe ehupi hag̃ua
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Eiporavo ta’ãnga marandurenda
+ *[other] Eiporavo ta’ãnga marandurenda
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Moha’ãnga (moñe’ẽrã ykepegua)
+pdfjs-editor-add-signature-description-input =
+ .title = Moha’ãnga (moñe’ẽrã ykepegua)
+pdfjs-editor-add-signature-description-default-when-drawing = Teraguapy
+pdfjs-editor-add-signature-clear-button-label = Emboguete teraguapy
+pdfjs-editor-add-signature-clear-button =
+ .title = Emboguete teraguapy
+pdfjs-editor-add-signature-save-checkbox = Eñongatu teraguapy
+pdfjs-editor-add-signature-save-warning-message = Ehupytýma 5 mboheraguapy ñongatupyre. Embogue peteĩ eñongatukuaa jey hag̃ua.
+pdfjs-editor-add-signature-image-upload-error-title = Ndaikatúi ojehupi pe ta’ãnga
+pdfjs-editor-add-signature-image-upload-error-description = Ehechajey ne ñanduti oikópa térã aha’ã ambue ta’ãnga ndive.
+pdfjs-editor-add-signature-image-no-data-error-title = Ndaikatúi ejapo ko ta’ãngágui teraguapy
+pdfjs-editor-add-signature-image-no-data-error-description = Eñeha’ãkena ehupi ambuéva ta’ãnga.
+pdfjs-editor-add-signature-error-close-button = Mboty
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Heja
+pdfjs-editor-add-signature-add-button = Mbojuaju
+pdfjs-editor-edit-signature-update-button = Mbohekopyahu
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Je’erei mbosako’i
+pdfjs-editor-edit-comment-popup-button =
+ .title = Je’erei mbosako’i
+pdfjs-editor-delete-comment-popup-button-label = Je’erei mboguete
+pdfjs-editor-delete-comment-popup-button =
+ .title = Je’erei mboguete
+pdfjs-show-comment-button =
+ .title = Ehechauka je’epy
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Je’erei mbosako’i
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Mbohekopyahu
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Je’erei mbojuaju
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Mbojuaju
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Ehai ñepyrũ…
+pdfjs-editor-edit-comment-dialog-cancel-button = Eheja
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Je’erei mbojuaju
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Embojopyru tenda ykegua (kuatia oguereko mba’e’i, kuaakaha/moirũha/ñuãha)
+pdfjs-toggle-views-manager-button1-label = Eñangareko kuotiarogue
+pdfjs-views-manager-sidebar =
+ .aria-label = Ta’ãngarupa yke
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Tuichakue mongu’eha tenda yképe
+pdfjs-views-manager-view-selector-button =
+ .title = Hechaha
+pdfjs-views-manager-view-selector-button-label = Hechaha
+pdfjs-views-manager-pages-title = Kuatiarogue
+pdfjs-views-manager-outlines-title1 = Kuatiaite jejapopy
+ .title = Kuatiaite jejapopy (eikutu jo’a emyasãi hag̃ua/emomichĩmbaite mba’eporuita)
+pdfjs-views-manager-attachments-title = Moirũha
+pdfjs-views-manager-layers-title1 = Ñuãhaita
+ .title = Ñuãhaita (eikutu jo’a erupaite jey hag̃ua ñuãhaita oĩ haguepevoi)
+pdfjs-views-manager-pages-option-label = Kuatiarogueita
+pdfjs-views-manager-outlines-option-label = Kuatiaite jejapopy
+pdfjs-views-manager-attachments-option-label = Moirũhaita
+pdfjs-views-manager-layers-option-label = Ñuãhaita
+pdfjs-views-manager-add-file-button =
+ .title = Embojuaju marandurenda
+pdfjs-views-manager-add-file-button-label = Embojuaju marandurenda
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } poravopyre
+ *[other] { $count } poravopyre
+ }
+pdfjs-views-manager-pages-status-none-action-label = Eiporavo kuatiarogue
+pdfjs-views-manager-pages-status-action-button-label = Ñangareko
+pdfjs-views-manager-pages-status-copy-button-label = Monguatia
+pdfjs-views-manager-pages-status-cut-button-label = Kytĩ
+pdfjs-views-manager-pages-status-delete-button-label = Mboguete
+pdfjs-views-manager-pages-status-export-selected-button-label = Eguerahauka poravopyre…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 kuatiarogue kytĩmbyre
+ *[other] { $count } kuatiarogue kytĩmbyre
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 kuatiarogue monguatiapyre
+ *[other] { $count } kuatiarogue monguatiapyre
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 kuatiarogue mboguepyre
+ *[other] { $count } kuatiarogue mboguepyre
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Embosako’ihína ne marandurenda…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Ehupihína marandurenda…
+pdfjs-views-manager-status-warning-cut-label = Ndaikatúi oñekytĩ. Embopyahu kuatiarogue ha eha’ã jey.
+pdfjs-views-manager-status-warning-copy-label = Ndaikatúi oñembokuatia. Embopyahu kuatiarogue ha eha’ã jey.
+pdfjs-views-manager-status-warning-delete-label = Ndaikatúi embogue. Embopyahu kuatiarogue ha eha’ã jey.
+pdfjs-views-manager-status-warning-save-label = Ndaikatúi eñongatu. Embopyahu kuatiarogue ha eha’ã jey.
+pdfjs-views-manager-status-undo-button-label = Mboguevi
+pdfjs-views-manager-status-done-button-label = Oĩma
+pdfjs-views-manager-status-close-button =
+ .title = Mboty
+pdfjs-views-manager-status-close-button-label = Mboty
+pdfjs-views-manager-paste-button-label = Mboja
+pdfjs-views-manager-paste-button-before =
+ .title = Emboja togue peteĩha mboyve
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Emboja kuatiarogue { $page } rire
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = PYAHU
+pdfjs-views-manager-waiting-for-file = Ehupihína marandurenda…
+pdfjs-toggle-views-manager-button1 =
+ .title = Eñangareko kuotiarogue
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Firma digital oguerekóva
+ .aria-label = Firma digital oguerekóva
+pdfjs-digital-signature-properties-button-label = Firma digital oguerekóva
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Pe kuatia oñemboheraguapy firma digital oikóvape
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Kuatia mboheraguapypyre { $count } mboajepyre oikove’ỹva ndive
+ *[other] Kuatia mboheraguapypyre { $count } mboajepyreita oikove’ỹva ndive
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Heko: Mboheraguapy hechajeypyre
+pdfjs-digital-signature-properties-status-invalid = Heko: Mboheraguapy oiko’ỹva
+pdfjs-digital-signature-properties-status-unknown = Heko: Ndojehechajeykuaái (ndojokupytýi)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Mboajapyre: Jeroviaha ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Mboajapyre: Oĩ’ỹva
+pdfjs-digital-signature-properties-certificate-untrusted = Mboajapyre: Jerovia’ỹha
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Mboajapyre: Guenohẽha jekuaa’ỹva ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Mboajapyre: Heraguapejeheguíva { $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Mboajapyre: Guenohẽha jerovia’ỹha ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Mboajapyre: Oikove’ỹmava
+pdfjs-digital-signature-properties-certificate-expired-with-date = Mboajapyre: Oikove’ỹmava ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Mboajapyre: Mbojevypyre
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Embogue teraguapy ñongatupyre
+pdfjs-editor-delete-signature-button-label1 = Embogue teraguapy ñongatupyre
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Embosako’i moha’ãnga
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Embosako’i moha’ãnga
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gu-IN/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gu-IN/viewer.ftl
new file mode 100644
index 0000000..5ad3db1
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/gu-IN/viewer.ftl
@@ -0,0 +1,222 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = પહેલાનુ પાનું
+pdfjs-previous-button-label = પહેલાનુ
+pdfjs-next-button =
+ .title = આગળનુ પાનું
+pdfjs-next-button-label = આગળનું
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = પાનું
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = નો { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } નો { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = મોટુ કરો
+pdfjs-zoom-out-button-label = મોટુ કરો
+pdfjs-zoom-in-button =
+ .title = નાનું કરો
+pdfjs-zoom-in-button-label = નાનું કરો
+pdfjs-zoom-select =
+ .title = નાનું મોટુ કરો
+pdfjs-presentation-mode-button =
+ .title = રજૂઆત સ્થિતિમાં જાવ
+pdfjs-presentation-mode-button-label = રજૂઆત સ્થિતિ
+pdfjs-open-file-button =
+ .title = ફાઇલ ખોલો
+pdfjs-open-file-button-label = ખોલો
+pdfjs-print-button =
+ .title = છાપો
+pdfjs-print-button-label = છારો
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = સાધનો
+pdfjs-tools-button-label = સાધનો
+pdfjs-first-page-button =
+ .title = પહેલાં પાનામાં જાવ
+pdfjs-first-page-button-label = પ્રથમ પાનાં પર જાવ
+pdfjs-last-page-button =
+ .title = છેલ્લા પાનાં પર જાવ
+pdfjs-last-page-button-label = છેલ્લા પાનાં પર જાવ
+pdfjs-page-rotate-cw-button =
+ .title = ઘડિયાળનાં કાંટા તરફ ફેરવો
+pdfjs-page-rotate-cw-button-label = ઘડિયાળનાં કાંટા તરફ ફેરવો
+pdfjs-page-rotate-ccw-button =
+ .title = ઘડિયાળનાં કાંટાની ઉલટી દિશામાં ફેરવો
+pdfjs-page-rotate-ccw-button-label = ઘડિયાળનાં કાંટાની વિરુદ્દ ફેરવો
+pdfjs-cursor-text-select-tool-button =
+ .title = ટેક્સ્ટ પસંદગી ટૂલ સક્ષમ કરો
+pdfjs-cursor-text-select-tool-button-label = ટેક્સ્ટ પસંદગી ટૂલ
+pdfjs-cursor-hand-tool-button =
+ .title = હાથનાં સાધનને સક્રિય કરો
+pdfjs-cursor-hand-tool-button-label = હેન્ડ ટૂલ
+pdfjs-scroll-vertical-button =
+ .title = ઊભી સ્ક્રોલિંગનો ઉપયોગ કરો
+pdfjs-scroll-vertical-button-label = ઊભી સ્ક્રોલિંગ
+pdfjs-scroll-horizontal-button =
+ .title = આડી સ્ક્રોલિંગનો ઉપયોગ કરો
+pdfjs-scroll-horizontal-button-label = આડી સ્ક્રોલિંગ
+pdfjs-scroll-wrapped-button =
+ .title = આવરિત સ્ક્રોલિંગનો ઉપયોગ કરો
+pdfjs-scroll-wrapped-button-label = આવરિત સ્ક્રોલિંગ
+pdfjs-spread-none-button =
+ .title = પૃષ્ઠ સ્પ્રેડમાં જોડાવશો નહીં
+pdfjs-spread-none-button-label = કોઈ સ્પ્રેડ નથી
+pdfjs-spread-odd-button =
+ .title = એકી-ક્રમાંકિત પૃષ્ઠો સાથે પ્રારંભ થતાં પૃષ્ઠ સ્પ્રેડમાં જોડાઓ
+pdfjs-spread-odd-button-label = એકી સ્પ્રેડ્સ
+pdfjs-spread-even-button =
+ .title = નંબર-ક્રમાંકિત પૃષ્ઠોથી શરૂ થતાં પૃષ્ઠ સ્પ્રેડમાં જોડાઓ
+pdfjs-spread-even-button-label = સરખું ફેલાવવું
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = દસ્તાવેજ ગુણધર્મો…
+pdfjs-document-properties-button-label = દસ્તાવેજ ગુણધર્મો…
+pdfjs-document-properties-file-name = ફાઇલ નામ:
+pdfjs-document-properties-file-size = ફાઇલ માપ:
+pdfjs-document-properties-title = શીર્ષક:
+pdfjs-document-properties-author = લેખક:
+pdfjs-document-properties-subject = વિષય:
+pdfjs-document-properties-keywords = કિવર્ડ:
+pdfjs-document-properties-creation-date = નિર્માણ તારીખ:
+pdfjs-document-properties-modification-date = ફેરફાર તારીખ:
+pdfjs-document-properties-creator = નિર્માતા:
+pdfjs-document-properties-producer = PDF નિર્માતા:
+pdfjs-document-properties-version = PDF આવૃત્તિ:
+pdfjs-document-properties-page-count = પાનાં ગણતરી:
+pdfjs-document-properties-page-size = પૃષ્ઠનું કદ:
+pdfjs-document-properties-page-size-unit-inches = ઇંચ
+pdfjs-document-properties-page-size-unit-millimeters = મીમી
+pdfjs-document-properties-page-size-orientation-portrait = ઉભું
+pdfjs-document-properties-page-size-orientation-landscape = આડુ
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = પત્ર
+pdfjs-document-properties-page-size-name-legal = કાયદાકીય
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = ઝડપી વૅબ દૃશ્ય:
+pdfjs-document-properties-linearized-yes = હા
+pdfjs-document-properties-linearized-no = ના
+pdfjs-document-properties-close-button = બંધ કરો
+
+## Print
+
+pdfjs-print-progress-message = છાપકામ માટે દસ્તાવેજ તૈયાર કરી રહ્યા છે…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = રદ કરો
+pdfjs-printing-not-supported = ચેતવણી: છાપવાનું આ બ્રાઉઝર દ્દારા સંપૂર્ણપણે આધારભૂત નથી.
+pdfjs-printing-not-ready = Warning: PDF એ છાપવા માટે સંપૂર્ણપણે લાવેલ છે.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = ટૉગલ બાજુપટ્ટી
+pdfjs-toggle-sidebar-button-label = ટૉગલ બાજુપટ્ટી
+pdfjs-document-outline-button =
+ .title = દસ્તાવેજની રૂપરેખા બતાવો(બધી આઇટમ્સને વિસ્તૃત/સંકુચિત કરવા માટે ડબલ-ક્લિક કરો)
+pdfjs-document-outline-button-label = દસ્તાવેજ રૂપરેખા
+pdfjs-attachments-button =
+ .title = જોડાણોને બતાવો
+pdfjs-attachments-button-label = જોડાણો
+pdfjs-thumbs-button =
+ .title = થંબનેલ્સ બતાવો
+pdfjs-thumbs-button-label = થંબનેલ્સ
+pdfjs-findbar-button =
+ .title = દસ્તાવેજમાં શોધો
+pdfjs-findbar-button-label = શોધો
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = પાનું { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = પાનાં { $page } નું થંબનેલ્સ
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = શોધો
+ .placeholder = દસ્તાવેજમાં શોધો…
+pdfjs-find-previous-button =
+ .title = શબ્દસમૂહની પાછલી ઘટનાને શોધો
+pdfjs-find-previous-button-label = પહેલાંનુ
+pdfjs-find-next-button =
+ .title = શબ્દસમૂહની આગળની ઘટનાને શોધો
+pdfjs-find-next-button-label = આગળનું
+pdfjs-find-highlight-checkbox = બધુ પ્રકાશિત કરો
+pdfjs-find-match-case-checkbox-label = કેસ બંધબેસાડો
+pdfjs-find-entire-word-checkbox-label = સંપૂર્ણ શબ્દો
+pdfjs-find-reached-top = દસ્તાવેજનાં ટોચે પહોંચી ગયા, તળિયેથી ચાલુ કરેલ હતુ
+pdfjs-find-reached-bottom = દસ્તાવેજનાં અંતે પહોંચી ગયા, ઉપરથી ચાલુ કરેલ હતુ
+pdfjs-find-not-found = શબ્દસમૂહ મળ્યુ નથી
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = પાનાની પહોળાઇ
+pdfjs-page-scale-fit = પાનું બંધબેસતુ
+pdfjs-page-scale-auto = આપમેળે નાનુંમોટુ કરો
+pdfjs-page-scale-actual = ચોક્કસ માપ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = ભૂલ ઉદ્ભવી જ્યારે PDF ને લાવી રહ્યા હોય.
+pdfjs-invalid-file-error = અયોગ્ય અથવા ભાંગેલ PDF ફાઇલ.
+pdfjs-missing-file-error = ગુમ થયેલ PDF ફાઇલ.
+pdfjs-unexpected-response-error = અનપેક્ષિત સર્વર પ્રતિસાદ.
+pdfjs-rendering-error = ભૂલ ઉદ્ભવી જ્યારે પાનાંનુ રેન્ડ કરી રહ્યા હોય.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = આ PDF ફાઇલને ખોલવા પાસવર્ડને દાખલ કરો.
+pdfjs-password-invalid = અયોગ્ય પાસવર્ડ. મહેરબાની કરીને ફરી પ્રયત્ન કરો.
+pdfjs-password-ok-button = બરાબર
+pdfjs-password-cancel-button = રદ કરો
+pdfjs-web-fonts-disabled = વેબ ફોન્ટ નિષ્ક્રિય થયેલ છે: ઍમ્બેડ થયેલ PDF ફોન્ટને વાપરવાનું અસમર્થ.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/he/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/he/viewer.ftl
new file mode 100644
index 0000000..49c3f82
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/he/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = דף קודם
+pdfjs-previous-button-label = קודם
+pdfjs-next-button =
+ .title = דף הבא
+pdfjs-next-button-label = הבא
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = דף
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = מתוך { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } מתוך { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = התרחקות
+pdfjs-zoom-out-button-label = התרחקות
+pdfjs-zoom-in-button =
+ .title = התקרבות
+pdfjs-zoom-in-button-label = התקרבות
+pdfjs-zoom-select =
+ .title = מרחק מתצוגה
+pdfjs-presentation-mode-button =
+ .title = מעבר למצב מצגת
+pdfjs-presentation-mode-button-label = מצב מצגת
+pdfjs-open-file-button =
+ .title = פתיחת קובץ
+pdfjs-open-file-button-label = פתיחה
+pdfjs-print-button =
+ .title = הדפסה
+pdfjs-print-button-label = הדפסה
+pdfjs-save-button =
+ .title = שמירה
+pdfjs-save-button-label = שמירה
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = הורדה
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = הורדה
+pdfjs-bookmark-button =
+ .title = עמוד נוכחי (הצגת כתובת האתר מהעמוד הנוכחי)
+pdfjs-bookmark-button-label = עמוד נוכחי
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = כלים
+pdfjs-tools-button-label = כלים
+pdfjs-first-page-button =
+ .title = מעבר לעמוד הראשון
+pdfjs-first-page-button-label = מעבר לעמוד הראשון
+pdfjs-last-page-button =
+ .title = מעבר לעמוד האחרון
+pdfjs-last-page-button-label = מעבר לעמוד האחרון
+pdfjs-page-rotate-cw-button =
+ .title = הטיה עם כיוון השעון
+pdfjs-page-rotate-cw-button-label = הטיה עם כיוון השעון
+pdfjs-page-rotate-ccw-button =
+ .title = הטיה כנגד כיוון השעון
+pdfjs-page-rotate-ccw-button-label = הטיה כנגד כיוון השעון
+pdfjs-cursor-text-select-tool-button =
+ .title = הפעלת כלי בחירת טקסט
+pdfjs-cursor-text-select-tool-button-label = כלי בחירת טקסט
+pdfjs-cursor-hand-tool-button =
+ .title = הפעלת כלי היד
+pdfjs-cursor-hand-tool-button-label = כלי יד
+pdfjs-scroll-page-button =
+ .title = שימוש בגלילת עמוד
+pdfjs-scroll-page-button-label = גלילת עמוד
+pdfjs-scroll-vertical-button =
+ .title = שימוש בגלילה אנכית
+pdfjs-scroll-vertical-button-label = גלילה אנכית
+pdfjs-scroll-horizontal-button =
+ .title = שימוש בגלילה אופקית
+pdfjs-scroll-horizontal-button-label = גלילה אופקית
+pdfjs-scroll-wrapped-button =
+ .title = שימוש בגלילה רציפה
+pdfjs-scroll-wrapped-button-label = גלילה רציפה
+pdfjs-spread-none-button =
+ .title = לא לצרף מפתחי עמודים
+pdfjs-spread-none-button-label = ללא מפתחים
+pdfjs-spread-odd-button =
+ .title = צירוף מפתחי עמודים שמתחילים בדפים עם מספרים אי־זוגיים
+pdfjs-spread-odd-button-label = מפתחים אי־זוגיים
+pdfjs-spread-even-button =
+ .title = צירוף מפתחי עמודים שמתחילים בדפים עם מספרים זוגיים
+pdfjs-spread-even-button-label = מפתחים זוגיים
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = מאפייני מסמך…
+pdfjs-document-properties-button-label = מאפייני מסמך…
+pdfjs-document-properties-file-name = שם קובץ:
+pdfjs-document-properties-file-size = גודל הקובץ:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } ק״ב ({ $b } בתים)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } מ״ב ({ $b } בתים)
+pdfjs-document-properties-title = כותרת:
+pdfjs-document-properties-author = מחבר:
+pdfjs-document-properties-subject = נושא:
+pdfjs-document-properties-keywords = מילות מפתח:
+pdfjs-document-properties-creation-date = תאריך יצירה:
+pdfjs-document-properties-modification-date = תאריך שינוי:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = יוצר:
+pdfjs-document-properties-producer = יצרן PDF:
+pdfjs-document-properties-version = גרסת PDF:
+pdfjs-document-properties-page-count = מספר דפים:
+pdfjs-document-properties-page-size = גודל העמוד:
+pdfjs-document-properties-page-size-unit-inches = אינ׳
+pdfjs-document-properties-page-size-unit-millimeters = מ״מ
+pdfjs-document-properties-page-size-orientation-portrait = לאורך
+pdfjs-document-properties-page-size-orientation-landscape = לרוחב
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = מכתב
+pdfjs-document-properties-page-size-name-legal = דף משפטי
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = תצוגת דף מהירה:
+pdfjs-document-properties-linearized-yes = כן
+pdfjs-document-properties-linearized-no = לא
+pdfjs-document-properties-close-button = סגירה
+pdfjs-digital-signature-properties-view-certificate = הצגת אישור
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = סיבה: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = חותמת זמן: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] חתימת משנה ({ $count })
+ *[other] חתימות משנה ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = מסמך בהכנה להדפסה…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ביטול
+pdfjs-printing-not-supported = אזהרה: הדפסה אינה נתמכת במלואה בדפדפן זה.
+pdfjs-printing-not-ready = אזהרה: מסמך ה־PDF לא נטען לחלוטין עד מצב שמאפשר הדפסה.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = הצגה/הסתרה של סרגל הצד
+pdfjs-toggle-sidebar-notification-button =
+ .title = החלפת תצוגת סרגל צד (מסמך שמכיל תוכן עניינים/קבצים מצורפים/שכבות)
+pdfjs-toggle-sidebar-button-label = הצגה/הסתרה של סרגל הצד
+pdfjs-document-outline-button =
+ .title = הצגת תוכן העניינים של המסמך (לחיצה כפולה כדי להרחיב או לצמצם את כל הפריטים)
+pdfjs-document-outline-button-label = תוכן העניינים של המסמך
+pdfjs-attachments-button =
+ .title = הצגת צרופות
+pdfjs-attachments-button-label = צרופות
+pdfjs-layers-button =
+ .title = הצגת שכבות (יש ללחוץ לחיצה כפולה כדי לאפס את כל השכבות למצב ברירת המחדל)
+pdfjs-layers-button-label = שכבות
+pdfjs-thumbs-button =
+ .title = הצגת תצוגה מקדימה
+pdfjs-thumbs-button-label = תצוגה מקדימה
+pdfjs-current-outline-item-button =
+ .title = מציאת פריט תוכן העניינים הנוכחי
+pdfjs-current-outline-item-button-label = פריט תוכן העניינים הנוכחי
+pdfjs-findbar-button =
+ .title = חיפוש במסמך
+pdfjs-findbar-button-label = חיפוש
+pdfjs-additional-layers = שכבות נוספות
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = עמוד { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = תצוגה מקדימה של עמוד { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = בחירת עמוד { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = עמוד { $page } מתוך { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = חיפוש
+ .placeholder = חיפוש במסמך…
+pdfjs-find-previous-button =
+ .title = מציאת המופע הקודם של הביטוי
+pdfjs-find-previous-button-label = קודם
+pdfjs-find-next-button =
+ .title = מציאת המופע הבא של הביטוי
+pdfjs-find-next-button-label = הבא
+pdfjs-find-highlight-checkbox = הדגשת הכול
+pdfjs-find-match-case-checkbox-label = התאמת אותיות
+pdfjs-find-match-diacritics-checkbox-label = התאמה דיאקריטית
+pdfjs-find-entire-word-checkbox-label = מילים שלמות
+pdfjs-find-reached-top = הגיע לראש הדף, ממשיך מלמטה
+pdfjs-find-reached-bottom = הגיע לסוף הדף, ממשיך מלמעלה
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } מתוך { $total } תוצאות
+ *[other] { $current } מתוך { $total } תוצאות
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] יותר מתוצאה אחת
+ *[other] יותר מ־{ $limit } תוצאות
+ }
+pdfjs-find-not-found = הביטוי לא נמצא
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = רוחב העמוד
+pdfjs-page-scale-fit = התאמה לעמוד
+pdfjs-page-scale-auto = מרחק מתצוגה אוטומטי
+pdfjs-page-scale-actual = גודל אמיתי
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = עמוד { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = אירעה שגיאה בעת טעינת ה־PDF.
+pdfjs-invalid-file-error = קובץ PDF פגום או לא תקין.
+pdfjs-missing-file-error = קובץ PDF חסר.
+pdfjs-unexpected-response-error = תגובת שרת לא צפויה.
+pdfjs-rendering-error = אירעה שגיאה בעת עיבוד הדף.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [הערת { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = נא להכניס את הססמה לפתיחת קובץ PDF זה.
+pdfjs-password-invalid = ססמה שגויה. נא לנסות שוב.
+pdfjs-password-ok-button = אישור
+pdfjs-password-cancel-button = ביטול
+pdfjs-web-fonts-disabled = גופני רשת מנוטרלים: לא ניתן להשתמש בגופני PDF מוטבעים.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = טקסט
+pdfjs-editor-color-picker-free-text-input =
+ .title = שינוי צבע הטקסט
+pdfjs-editor-free-text-button-label = טקסט
+pdfjs-editor-ink-button =
+ .title = ציור
+pdfjs-editor-color-picker-ink-input =
+ .title = שינוי צבע הציור
+pdfjs-editor-ink-button-label = ציור
+pdfjs-editor-stamp-button =
+ .title = הוספה או עריכת תמונות
+pdfjs-editor-stamp-button-label = הוספה או עריכת תמונות
+pdfjs-editor-highlight-button =
+ .title = סימון
+pdfjs-editor-highlight-button-label = סימון
+pdfjs-highlight-floating-button1 =
+ .title = סימון
+ .aria-label = סימון
+pdfjs-highlight-floating-button-label = סימון
+pdfjs-comment-floating-button =
+ .title = הערה
+ .aria-label = הערה
+pdfjs-comment-floating-button-label = הערה
+pdfjs-editor-comment-button =
+ .title = הערה
+ .aria-label = הערה
+pdfjs-editor-comment-button-label = הערה
+pdfjs-editor-signature-button =
+ .title = הוספת חתימה
+pdfjs-editor-signature-button-label = הוספת חתימה
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = עורך סימונים
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = עורך ציורים
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = עורך החתימות: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = עורך תמונות
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = הסרת ציור
+pdfjs-editor-remove-freetext-button =
+ .title = הסרת טקסט
+pdfjs-editor-remove-stamp-button =
+ .title = הסרת תמונה
+pdfjs-editor-remove-highlight-button =
+ .title = הסרת סימון
+pdfjs-editor-remove-signature-button =
+ .title = הסרת חתימה
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = צבע
+pdfjs-editor-free-text-size-input = גודל
+pdfjs-editor-ink-color-input = צבע
+pdfjs-editor-ink-thickness-input = עובי
+pdfjs-editor-ink-opacity-input = אטימות
+pdfjs-editor-stamp-add-image-button =
+ .title = הוספת תמונה
+pdfjs-editor-stamp-add-image-button-label = הוספת תמונה
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = עובי
+pdfjs-editor-free-highlight-thickness-title =
+ .title = שינוי עובי בעת סימון פריטים שאינם טקסט
+pdfjs-editor-add-signature-container =
+ .aria-label = פקדי חתימה וחתימות שמורות
+pdfjs-editor-signature-add-signature-button =
+ .title = הוספת חתימה חדשה
+pdfjs-editor-signature-add-signature-button-label = הוספת חתימה חדשה
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = חתימה שמורה: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = עורך טקסט
+ .default-content = נא להתחיל להקליד…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] הערה
+ *[other] הערות
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = סגירת סרגל הצד
+ .aria-label = סגירת סרגל הצד
+pdfjs-editor-comments-sidebar-close-button-label = סגירת סרגל הצד
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ראית משהו ראוי לציון? ניתן לסמן אותו ולהשאיר הערה.
+pdfjs-editor-comments-sidebar-no-comments-link = מידע נוסף
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = טקסט חלופי
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = עריכת טקסט חלופי
+pdfjs-editor-alt-text-dialog-label = בחירת אפשרות
+pdfjs-editor-alt-text-dialog-description = טקסט חלופי עוזר כשאנשים לא יכולים לראות את התמונה או כשהיא לא נטענת.
+pdfjs-editor-alt-text-add-description-label = הוספת תיאור
+pdfjs-editor-alt-text-add-description-description = כדאי לתאר במשפט אחד או שניים את הנושא, התפאורה או הפעולות.
+pdfjs-editor-alt-text-mark-decorative-label = סימון כדקורטיבי
+pdfjs-editor-alt-text-mark-decorative-description = זה משמש לתמונות נוי, כמו גבולות או סימני מים.
+pdfjs-editor-alt-text-cancel-button = ביטול
+pdfjs-editor-alt-text-save-button = שמירה
+pdfjs-editor-alt-text-decorative-tooltip = מסומן כדקורטיבי
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = לדוגמה, ״גבר צעיר מתיישב ליד שולחן לאכול ארוחה״
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = טקסט חלופי
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = פינה שמאלית עליונה - שינוי גודל
+pdfjs-editor-resizer-top-middle =
+ .aria-label = למעלה באמצע - שינוי גודל
+pdfjs-editor-resizer-top-right =
+ .aria-label = פינה ימנית עליונה - שינוי גודל
+pdfjs-editor-resizer-middle-right =
+ .aria-label = ימינה באמצע - שינוי גודל
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = פינה ימנית תחתונה - שינוי גודל
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = למטה באמצע - שינוי גודל
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = פינה שמאלית תחתונה - שינוי גודל
+pdfjs-editor-resizer-middle-left =
+ .aria-label = שמאלה באמצע - שינוי גודל
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = צבע סימון
+pdfjs-editor-colorpicker-button =
+ .title = שינוי צבע
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = בחירת צבע
+pdfjs-editor-colorpicker-yellow =
+ .title = צהוב
+pdfjs-editor-colorpicker-green =
+ .title = ירוק
+pdfjs-editor-colorpicker-blue =
+ .title = כחול
+pdfjs-editor-colorpicker-pink =
+ .title = ורוד
+pdfjs-editor-colorpicker-red =
+ .title = אדום
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = הצגת הכול
+pdfjs-editor-highlight-show-all-button =
+ .title = הצגת הכול
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = עריכת טקסט חלופי (תיאור תמונה)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = הוספת טקסט חלופי (תיאור תמונה)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = נא לכתוב את התיאור שלך כאן…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = תיאור קצר לאנשים שאינם יכולים לראות את התמונה או כאשר התמונה אינה נטענת.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = טקסט חלופי זה נוצר באופן אוטומטי ועשוי להיות לא מדויק.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = מידע נוסף
+pdfjs-editor-new-alt-text-create-automatically-button-label = יצירת טקסט חלופי באופן אוטומטי
+pdfjs-editor-new-alt-text-not-now-button = לא כעת
+pdfjs-editor-new-alt-text-error-title = לא ניתן היה ליצור טקסט חלופי באופן אוטומטי
+pdfjs-editor-new-alt-text-error-description = נא לכתוב טקסט חלופי משלך או לנסות שוב מאוחר יותר.
+pdfjs-editor-new-alt-text-error-close-button = סגירה
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = בתהליך הורדת מודל AI של טקסט חלופי ({ $downloadedSize } מתוך { $totalSize } מ״ב)
+ .aria-valuetext = בתהליך הורדת מודל AI של טקסט חלופי ({ $downloadedSize } מתוך { $totalSize } מ״ב)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = נוסף טקסט חלופי
+pdfjs-editor-new-alt-text-added-button-label = נוסף טקסט חלופי
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = חסר טקסט חלופי
+pdfjs-editor-new-alt-text-missing-button-label = חסר טקסט חלופי
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = סקירת טקסט חלופי
+pdfjs-editor-new-alt-text-to-review-button-label = סקירת טקסט חלופי
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = נוצר באופן אוטומטי: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = הגדרות טקסט חלופי של תמונה
+pdfjs-image-alt-text-settings-button-label = הגדרות טקסט חלופי של תמונה
+pdfjs-editor-alt-text-settings-dialog-label = הגדרות טקסט חלופי של תמונה
+pdfjs-editor-alt-text-settings-automatic-title = טקסט חלופי אוטומטי
+pdfjs-editor-alt-text-settings-create-model-button-label = יצירת טקסט חלופי באופן אוטומטי
+pdfjs-editor-alt-text-settings-create-model-description = הצעת תיאורים כדי לסייע לאנשים שאינם יכולים לראות את התמונה או כאשר התמונה אינה נטענת.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = מודל AI לטקסט חלופי ({ $totalSize } מ״ב)
+pdfjs-editor-alt-text-settings-ai-model-description = פועל באופן מקומי במכשיר שלך כך שהנתונים שלך נשארים פרטיים. נדרש עבור טקסט חלופי אוטומטי.
+pdfjs-editor-alt-text-settings-delete-model-button = מחיקה
+pdfjs-editor-alt-text-settings-download-model-button = הורדה
+pdfjs-editor-alt-text-settings-downloading-model-button = בהורדה…
+pdfjs-editor-alt-text-settings-editor-title = עורך טקסט חלופי
+pdfjs-editor-alt-text-settings-show-dialog-button-label = הצגת עורך טקסט חלופי מיד בעת הוספת תמונה
+pdfjs-editor-alt-text-settings-show-dialog-description = מסייע לך לוודא שלכל התמונות שלך יש טקסט חלופי.
+pdfjs-editor-alt-text-settings-close-button = סגירה
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = הסימון נוסף
+pdfjs-editor-freetext-added-alert = הטקסט נוסף
+pdfjs-editor-ink-added-alert = הציור נוסף
+pdfjs-editor-stamp-added-alert = התמונה נוספה
+pdfjs-editor-signature-added-alert = החתימה נוספה
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = הסימון הוסר
+pdfjs-editor-undo-bar-message-freetext = הטקסט הוסר
+pdfjs-editor-undo-bar-message-ink = הציור הוסר
+pdfjs-editor-undo-bar-message-stamp = התמונה הוסרה
+pdfjs-editor-undo-bar-message-signature = החתימה הוסרה
+pdfjs-editor-undo-bar-message-comment = ההערה הוסרה
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] הערה אחת הוסרה
+ *[other] { $count } הערות הוסרו
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = ביטול פעולה
+pdfjs-editor-undo-bar-undo-button-label = ביטול פעלה
+pdfjs-editor-undo-bar-close-button =
+ .title = סגירה
+pdfjs-editor-undo-bar-close-button-label = סגירה
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = מודל זה מאפשר למשתמש ליצור חתימה להוספה למסמך PDF. המשתמש יכול לערוך את השם (שמשמש גם כטקסט האלטרנטיבי), ובאופן אופציונלי לשמור את החתימה לשימוש חוזר.
+pdfjs-editor-add-signature-dialog-title = הוספת חתימה
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = הקלדה
+ .title = הקלדה
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = ציור
+ .title = ציור
+pdfjs-editor-add-signature-image-button = תמונה
+ .title = תמונה
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = נא להקליד את החתימה שלך
+ .placeholder = נא להקליד את החתימה שלך
+pdfjs-editor-add-signature-draw-placeholder = נא לצייר את החתימה שלך
+pdfjs-editor-add-signature-draw-thickness-range-label = עובי
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = עובי הציור: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = יש לגרור לכאן קובץ להעלאה
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] או לבחור בקובצי תמונה
+ *[other] או לעיין בקובצי תמונה
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = תיאור (טקסט חלופי)
+pdfjs-editor-add-signature-description-input =
+ .title = תיאור (טקסט חלופי)
+pdfjs-editor-add-signature-description-default-when-drawing = חתימה
+pdfjs-editor-add-signature-clear-button-label = ניקוי חתימה
+pdfjs-editor-add-signature-clear-button =
+ .title = ניקוי חתימה
+pdfjs-editor-add-signature-save-checkbox = שמירת החתימה
+pdfjs-editor-add-signature-save-warning-message = הגעת למגבלה של 5 חתימות שמורות. יש להסיר אחד כדי לשמור עוד.
+pdfjs-editor-add-signature-image-upload-error-title = לא ניתן להעלות את התמונה
+pdfjs-editor-add-signature-image-upload-error-description = נא לבדוק את החיבור שלך לרשת או לנסות תמונה אחרת.
+pdfjs-editor-add-signature-image-no-data-error-title = לא ניתן להמיר את התמונה הזו לחתימה
+pdfjs-editor-add-signature-image-no-data-error-description = נא לנסות להעלות תמונה אחרת.
+pdfjs-editor-add-signature-error-close-button = סגירה
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = ביטול
+pdfjs-editor-add-signature-add-button = הוספה
+pdfjs-editor-edit-signature-update-button = עדכון
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = עריכת הערה
+pdfjs-editor-edit-comment-popup-button =
+ .title = עריכת הערה
+pdfjs-editor-delete-comment-popup-button-label = הסרת הערה
+pdfjs-editor-delete-comment-popup-button =
+ .title = הסרת הערה
+pdfjs-show-comment-button =
+ .title = הצגת הערה
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = עריכת הערה
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = עדכון
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = הוספת הערה
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = הוספה
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = להתחיל להקליד…
+pdfjs-editor-edit-comment-dialog-cancel-button = ביטול
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = הוספת הערה
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = החלפת תצוגת סרגל צד (מסמך שמכיל תמונות ממוזערות/תוכן עניינים/קבצים מצורפים/שכבות)
+pdfjs-toggle-views-manager-button1-label = ניהול עמודים
+pdfjs-views-manager-sidebar =
+ .aria-label = סרגל צד
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = שינוי גודל סרגל הצד
+pdfjs-views-manager-view-selector-button =
+ .title = תצוגות
+pdfjs-views-manager-view-selector-button-label = תצוגות
+pdfjs-views-manager-pages-title = עמודים
+pdfjs-views-manager-outlines-title1 = תוכן העניינים של המסמך
+ .title = הצגת תוכן העניינים של המסמך (יש ללחוץ לחיצה כפולה כדי להרחיב או לצמצם את כל הפריטים)
+pdfjs-views-manager-attachments-title = קבצים מצורפים
+pdfjs-views-manager-layers-title1 = שכבות
+ .title = הצגת שכבות (יש ללחוץ לחיצה כפולה כדי לאפס את כל השכבות למצב ברירת המחדל)
+pdfjs-views-manager-pages-option-label = עמודים
+pdfjs-views-manager-outlines-option-label = תוכן העניינים של המסמך
+pdfjs-views-manager-attachments-option-label = קבצים מצורפים
+pdfjs-views-manager-layers-option-label = שכבות
+pdfjs-views-manager-add-file-button =
+ .title = הוספת קובץ
+pdfjs-views-manager-add-file-button-label = הוספת קובץ
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] אחד נבחר
+ *[other] { $count } נבחרו
+ }
+pdfjs-views-manager-pages-status-none-action-label = בחירת עמודים
+pdfjs-views-manager-pages-status-action-button-label = ניהול
+pdfjs-views-manager-pages-status-copy-button-label = העתקה
+pdfjs-views-manager-pages-status-cut-button-label = גזירה
+pdfjs-views-manager-pages-status-delete-button-label = מחיקה
+pdfjs-views-manager-pages-status-export-selected-button-label = ייצוא הפריטים שנבחרו…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] עמוד אחד נגזר
+ *[other] { $count } עמודים נגזרו
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] עמוד אחד הועתק
+ *[other] { $count } עמודים הועתקו
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] עמוד אחד נמחק
+ *[other] { $count } עמודים נמחקו
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = בתהליך הכנת הקובץ שלך…
+pdfjs-views-manager-pages-status-waiting-uploading-label = בתהליך העלאת הקובץ…
+pdfjs-views-manager-status-warning-cut-label = לא ניתן היה לגזור. נא לרענן את הדף ולנסות שוב.
+pdfjs-views-manager-status-warning-copy-label = לא ניתן היה להעתיק. נא לרענן את הדף ולנסות שוב.
+pdfjs-views-manager-status-warning-delete-label = לא ניתן היה למחוק. נא לרענן את הדף ולנסות שוב.
+pdfjs-views-manager-status-warning-save-label = לא ניתן היה לשמור. נא לרענן את הדף ולנסות שוב.
+pdfjs-views-manager-status-undo-button-label = ביטול פעולה
+pdfjs-views-manager-status-done-button-label = סיום
+pdfjs-views-manager-status-close-button =
+ .title = סגירה
+pdfjs-views-manager-status-close-button-label = סגירה
+pdfjs-views-manager-paste-button-label = הדבקה
+pdfjs-views-manager-paste-button-before =
+ .title = להדביק לפני העמוד הראשון
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = להדביק אחרי עמוד { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = חדש
+pdfjs-views-manager-waiting-for-file = בתהליך העלאת הקובץ…
+pdfjs-toggle-views-manager-button1 =
+ .title = ניהול עמודים
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = מאפייני חתימה דיגיטלית
+ .aria-label = מאפייני חתימה דיגיטלית
+pdfjs-digital-signature-properties-button-label = מאפייני חתימה דיגיטלית
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = המסמך נחתם בחתימה דיגיטלית תקפה
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] המסמך חתום אך לא ניתן היה לאמת חתימה דיגיטלית אחת
+ *[other] המסמך חתום אך לא ניתן היה לאמת { $count } חתימות דיגיטליות
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] המסמך חתום עם אישור אחד שאינו מהימן
+ *[other] המסמך חתום עם { $count } אישורים שאינם מהימנים
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] המסמך חתום עם אישור אחד שפג תוקפו
+ *[other] המסמך חתום עם { $count } אישורים שפג תוקפם
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] למסמך יש חתימה דיגיטלית אחת שאינה תקינה
+ *[other] למסמך יש { $count } חתימות דיגיטליות שאינן תקינות
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] המסמך חתום עם אישור אחד שנשלל
+ *[other] המסמך חתום עם { $count } אישורים שנשללו
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = מצב: החתימה מאומתת
+pdfjs-digital-signature-properties-status-invalid = מצב: החתימה לא תקינה
+pdfjs-digital-signature-properties-status-unknown = מצב: לא ניתן לאמת (לא נתמך)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = אישור אבטחה: מהימן ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = אישור אבטחה: לא זמין
+pdfjs-digital-signature-properties-certificate-untrusted = אישור אבטחה: לא מהימן
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = אישור אבטחה: מנפיק לא ידוע ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = אישור אבטחה: נחתם עצמית ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = אישור אבטחה: מנפיק לא מהימן ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = אישור אבטחה: פג תוקפו
+pdfjs-digital-signature-properties-certificate-expired-with-date = אישור אבטחה: פג תוקפו ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = אישור אבטחה: נשלל
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = הסרת חתימה שמורה
+pdfjs-editor-delete-signature-button-label1 = הסרת חתימה שמורה
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = עריכת תיאור
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = עריכת תיאור
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hi-IN/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hi-IN/viewer.ftl
new file mode 100644
index 0000000..91459eb
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hi-IN/viewer.ftl
@@ -0,0 +1,221 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = पिछला पृष्ठ
+pdfjs-previous-button-label = पिछला
+pdfjs-next-button =
+ .title = अगला पृष्ठ
+pdfjs-next-button-label = आगे
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = पृष्ठ:
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } का
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = छोटा करें
+pdfjs-zoom-out-button-label = छोटा करें
+pdfjs-zoom-in-button =
+ .title = बड़ा करें
+pdfjs-zoom-in-button-label = बड़ा करें
+pdfjs-zoom-select =
+ .title = बड़ा-छोटा करें
+pdfjs-presentation-mode-button =
+ .title = प्रस्तुति अवस्था में जाएँ
+pdfjs-presentation-mode-button-label = प्रस्तुति अवस्था
+pdfjs-open-file-button =
+ .title = फ़ाइल खोलें
+pdfjs-open-file-button-label = खोलें
+pdfjs-print-button =
+ .title = छापें
+pdfjs-print-button-label = छापें
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = औज़ार
+pdfjs-tools-button-label = औज़ार
+pdfjs-first-page-button =
+ .title = प्रथम पृष्ठ पर जाएँ
+pdfjs-first-page-button-label = प्रथम पृष्ठ पर जाएँ
+pdfjs-last-page-button =
+ .title = अंतिम पृष्ठ पर जाएँ
+pdfjs-last-page-button-label = अंतिम पृष्ठ पर जाएँ
+pdfjs-page-rotate-cw-button =
+ .title = घड़ी की दिशा में घुमाएँ
+pdfjs-page-rotate-cw-button-label = घड़ी की दिशा में घुमाएँ
+pdfjs-page-rotate-ccw-button =
+ .title = घड़ी की दिशा से उल्टा घुमाएँ
+pdfjs-page-rotate-ccw-button-label = घड़ी की दिशा से उल्टा घुमाएँ
+pdfjs-cursor-text-select-tool-button =
+ .title = पाठ चयन उपकरण सक्षम करें
+pdfjs-cursor-text-select-tool-button-label = पाठ चयन उपकरण
+pdfjs-cursor-hand-tool-button =
+ .title = हस्त उपकरण सक्षम करें
+pdfjs-cursor-hand-tool-button-label = हस्त उपकरण
+pdfjs-scroll-vertical-button =
+ .title = लंबवत स्क्रॉलिंग का उपयोग करें
+pdfjs-scroll-vertical-button-label = लंबवत स्क्रॉलिंग
+pdfjs-scroll-horizontal-button =
+ .title = क्षितिजिय स्क्रॉलिंग का उपयोग करें
+pdfjs-scroll-horizontal-button-label = क्षितिजिय स्क्रॉलिंग
+pdfjs-scroll-wrapped-button =
+ .title = व्राप्पेड स्क्रॉलिंग का उपयोग करें
+pdfjs-spread-none-button-label = कोई स्प्रेड उपलब्ध नहीं
+pdfjs-spread-odd-button =
+ .title = विषम-क्रमांकित पृष्ठों से प्रारंभ होने वाले पृष्ठ स्प्रेड में शामिल हों
+pdfjs-spread-odd-button-label = विषम फैलाव
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = दस्तावेज़ विशेषता...
+pdfjs-document-properties-button-label = दस्तावेज़ विशेषता...
+pdfjs-document-properties-file-name = फ़ाइल नाम:
+pdfjs-document-properties-file-size = फाइल आकारः
+pdfjs-document-properties-title = शीर्षक:
+pdfjs-document-properties-author = लेखकः
+pdfjs-document-properties-subject = विषय:
+pdfjs-document-properties-keywords = कुंजी-शब्द:
+pdfjs-document-properties-creation-date = निर्माण दिनांक:
+pdfjs-document-properties-modification-date = संशोधन दिनांक:
+pdfjs-document-properties-creator = निर्माता:
+pdfjs-document-properties-producer = PDF उत्पादक:
+pdfjs-document-properties-version = PDF संस्करण:
+pdfjs-document-properties-page-count = पृष्ठ गिनती:
+pdfjs-document-properties-page-size = पृष्ठ आकार:
+pdfjs-document-properties-page-size-unit-inches = इंच
+pdfjs-document-properties-page-size-unit-millimeters = मिमी
+pdfjs-document-properties-page-size-orientation-portrait = पोर्ट्रेट
+pdfjs-document-properties-page-size-orientation-landscape = लैंडस्केप
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = पत्र
+pdfjs-document-properties-page-size-name-legal = क़ानूनी
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = तीव्र वेब व्यू:
+pdfjs-document-properties-linearized-yes = हाँ
+pdfjs-document-properties-linearized-no = नहीं
+pdfjs-document-properties-close-button = बंद करें
+
+## Print
+
+pdfjs-print-progress-message = छपाई के लिए दस्तावेज़ को तैयार किया जा रहा है...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = रद्द करें
+pdfjs-printing-not-supported = चेतावनी: इस ब्राउज़र पर छपाई पूरी तरह से समर्थित नहीं है.
+pdfjs-printing-not-ready = चेतावनी: PDF छपाई के लिए पूरी तरह से लोड नहीं है.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = स्लाइडर टॉगल करें
+pdfjs-toggle-sidebar-button-label = स्लाइडर टॉगल करें
+pdfjs-document-outline-button =
+ .title = दस्तावेज़ की रूपरेखा दिखाइए (सारी वस्तुओं को फलने अथवा समेटने के लिए दो बार क्लिक करें)
+pdfjs-document-outline-button-label = दस्तावेज़ आउटलाइन
+pdfjs-attachments-button =
+ .title = संलग्नक दिखायें
+pdfjs-attachments-button-label = संलग्नक
+pdfjs-thumbs-button =
+ .title = लघुछवियाँ दिखाएँ
+pdfjs-thumbs-button-label = लघु छवि
+pdfjs-findbar-button =
+ .title = दस्तावेज़ में ढूँढ़ें
+pdfjs-findbar-button-label = ढूँढें
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = पृष्ठ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = पृष्ठ { $page } की लघु-छवि
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ढूँढें
+ .placeholder = दस्तावेज़ में खोजें...
+pdfjs-find-previous-button =
+ .title = वाक्यांश की पिछली उपस्थिति ढूँढ़ें
+pdfjs-find-previous-button-label = पिछला
+pdfjs-find-next-button =
+ .title = वाक्यांश की अगली उपस्थिति ढूँढ़ें
+pdfjs-find-next-button-label = अगला
+pdfjs-find-highlight-checkbox = सभी आलोकित करें
+pdfjs-find-match-case-checkbox-label = मिलान स्थिति
+pdfjs-find-entire-word-checkbox-label = संपूर्ण शब्द
+pdfjs-find-reached-top = पृष्ठ के ऊपर पहुंच गया, नीचे से जारी रखें
+pdfjs-find-reached-bottom = पृष्ठ के नीचे में जा पहुँचा, ऊपर से जारी
+pdfjs-find-not-found = वाक्यांश नहीं मिला
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = पृष्ठ चौड़ाई
+pdfjs-page-scale-fit = पृष्ठ फिट
+pdfjs-page-scale-auto = स्वचालित जूम
+pdfjs-page-scale-actual = वास्तविक आकार
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF लोड करते समय एक त्रुटि हुई.
+pdfjs-invalid-file-error = अमान्य या भ्रष्ट PDF फ़ाइल.
+pdfjs-missing-file-error = अनुपस्थित PDF फ़ाइल.
+pdfjs-unexpected-response-error = अप्रत्याशित सर्वर प्रतिक्रिया.
+pdfjs-rendering-error = पृष्ठ रेंडरिंग के दौरान त्रुटि आई.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = इस PDF फ़ाइल को खोलने के लिए कृपया कूटशब्द भरें.
+pdfjs-password-invalid = अवैध कूटशब्द, कृपया फिर कोशिश करें.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = रद्द करें
+pdfjs-web-fonts-disabled = वेब फॉन्ट्स निष्क्रिय हैं: अंतःस्थापित PDF फॉन्टस के उपयोग में असमर्थ.
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = रंग
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hr/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hr/viewer.ftl
new file mode 100644
index 0000000..bd8fcf9
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hr/viewer.ftl
@@ -0,0 +1,723 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Prethodna stranica
+pdfjs-previous-button-label = Prethodna
+pdfjs-next-button =
+ .title = Sljedeća stranica
+pdfjs-next-button-label = Sljedeća
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Stranica
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = od { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } od { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Umanji
+pdfjs-zoom-out-button-label = Umanji
+pdfjs-zoom-in-button =
+ .title = Uvećaj
+pdfjs-zoom-in-button-label = Uvećaj
+pdfjs-zoom-select =
+ .title = Zumiranje
+pdfjs-presentation-mode-button =
+ .title = Prebaci u modus prezentacija
+pdfjs-presentation-mode-button-label = Modus prezentacija
+pdfjs-open-file-button =
+ .title = Otvori datoteku
+pdfjs-open-file-button-label = Otvori
+pdfjs-print-button =
+ .title = Ispiši
+pdfjs-print-button-label = Ispiši
+pdfjs-save-button =
+ .title = Spremi
+pdfjs-save-button-label = Spremi
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Preuzimanja
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Preuzimanja
+pdfjs-bookmark-button =
+ .title = Trenutačna stranica (pogledaj URL s trenutačne stranice)
+pdfjs-bookmark-button-label = Trenutačna stranica
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Alati
+pdfjs-tools-button-label = Alati
+pdfjs-first-page-button =
+ .title = Idi na prvu stranicu
+pdfjs-first-page-button-label = Idi na prvu stranicu
+pdfjs-last-page-button =
+ .title = Idi na zadnju stranicu
+pdfjs-last-page-button-label = Idi na zadnju stranicu
+pdfjs-page-rotate-cw-button =
+ .title = Okreni nadesno
+pdfjs-page-rotate-cw-button-label = Okreni nadesno
+pdfjs-page-rotate-ccw-button =
+ .title = Okreni nalijevo
+pdfjs-page-rotate-ccw-button-label = Okreni nalijevo
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktiviraj alat za biranje teksta
+pdfjs-cursor-text-select-tool-button-label = Alat za označavanje teksta
+pdfjs-cursor-hand-tool-button =
+ .title = Aktiviraj ručni alat
+pdfjs-cursor-hand-tool-button-label = Ručni alat
+pdfjs-scroll-page-button =
+ .title = Koristi klizanje stranice
+pdfjs-scroll-page-button-label = Klizanje stranice
+pdfjs-scroll-vertical-button =
+ .title = Koristi okomito pomicanje
+pdfjs-scroll-vertical-button-label = Okomito pomicanje
+pdfjs-scroll-horizontal-button =
+ .title = Koristi vodoravno pomicanje
+pdfjs-scroll-horizontal-button-label = Vodoravno pomicanje
+pdfjs-scroll-wrapped-button =
+ .title = Koristi kontinuirani raspored stranica
+pdfjs-scroll-wrapped-button-label = Kontinuirani raspored stranica
+pdfjs-spread-none-button =
+ .title = Ne izrađuj duplerice
+pdfjs-spread-none-button-label = Pojedinačne stranice
+pdfjs-spread-odd-button =
+ .title = Izradi duplerice koje počinju s neparnim stranicama
+pdfjs-spread-odd-button-label = Neparne duplerice
+pdfjs-spread-even-button =
+ .title = Izradi duplerice koje počinju s parnim stranicama
+pdfjs-spread-even-button-label = Parne duplerice
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Svojstva dokumenta …
+pdfjs-document-properties-button-label = Svojstva dokumenta …
+pdfjs-document-properties-file-name = Ime datoteke:
+pdfjs-document-properties-file-size = Veličina datoteke:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bajtova)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtova)
+pdfjs-document-properties-title = Naslov:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Predmet:
+pdfjs-document-properties-keywords = Ključne riječi:
+pdfjs-document-properties-creation-date = Datum stvaranja:
+pdfjs-document-properties-modification-date = Datum promjene:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Stvaratelj:
+pdfjs-document-properties-producer = PDF stvaratelj:
+pdfjs-document-properties-version = PDF verzija:
+pdfjs-document-properties-page-count = Broj stranica:
+pdfjs-document-properties-page-size = Dimenzije stranice:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = uspravno
+pdfjs-document-properties-page-size-orientation-landscape = položeno
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Brzi web pregled:
+pdfjs-document-properties-linearized-yes = Da
+pdfjs-document-properties-linearized-no = Ne
+pdfjs-document-properties-close-button = Zatvori
+
+## Print
+
+pdfjs-print-progress-message = Pripremanje dokumenta za ispis…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Odustani
+pdfjs-printing-not-supported = Upozorenje: Ovaj preglednik ne podržava u potpunosti ispisivanje.
+pdfjs-printing-not-ready = Upozorenje: PDF nije u potpunosti učitan za ispis.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Prikaži/sakrij bočnu traku
+pdfjs-toggle-sidebar-notification-button =
+ .title = Prikazivanje i sklanjanje bočne trake (dokument sadrži strukturu/privitke/slojeve)
+pdfjs-toggle-sidebar-button-label = Prikaži/sakrij bočnu traku
+pdfjs-document-outline-button =
+ .title = Prikaži strukturu dokumenta (dvoklik za rasklapanje/sklapanje svih stavki)
+pdfjs-document-outline-button-label = Struktura dokumenta
+pdfjs-attachments-button =
+ .title = Prikaži privitke
+pdfjs-attachments-button-label = Privitci
+pdfjs-layers-button =
+ .title = Prikaži slojeve (dvoklik za vraćanje svih slojeva u standardno stanje)
+pdfjs-layers-button-label = Slojevi
+pdfjs-thumbs-button =
+ .title = Prikaži minijature
+pdfjs-thumbs-button-label = Minijature
+pdfjs-current-outline-item-button =
+ .title = Pronađi trenutačni element strukture
+pdfjs-current-outline-item-button-label = Trenutačni element strukture
+pdfjs-findbar-button =
+ .title = Pronađi u dokumentu
+pdfjs-findbar-button-label = Pronađi
+pdfjs-additional-layers = Dodatni slojevi
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Stranica { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Minijatura stranice { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Odaberi stranicu { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Stranica { $page } od { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Pronađi
+ .placeholder = Pronađi u dokumentu …
+pdfjs-find-previous-button =
+ .title = Pronađi prethodno pojavljivanje ovog izraza
+pdfjs-find-previous-button-label = Prethodno
+pdfjs-find-next-button =
+ .title = Pronađi sljedeće pojavljivanje ovog izraza
+pdfjs-find-next-button-label = Dalje
+pdfjs-find-highlight-checkbox = Istankni sve
+pdfjs-find-match-case-checkbox-label = Razlikovanje velikih i malih slova
+pdfjs-find-match-diacritics-checkbox-label = Razlikuj dijakritičke znakove
+pdfjs-find-entire-word-checkbox-label = Cijele riječi
+pdfjs-find-reached-top = Dosegnut početak dokumenta, nastavak s kraja
+pdfjs-find-reached-bottom = Dosegnut kraj dokumenta, nastavak s početka
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } od { $total } rezultata
+ [few] { $current } od { $total } rezultata
+ *[other] { $current } od { $total } rezultata
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Više od { $limit } rezultat
+ [few] Više od { $limit } rezultata
+ *[other] Više od { $limit } rezultata
+ }
+pdfjs-find-not-found = Izraz nije pronađen
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Prilagodi širini prozora
+pdfjs-page-scale-fit = Prilagodi veličini prozora
+pdfjs-page-scale-auto = Automatsko zumiranje
+pdfjs-page-scale-actual = Stvarna veličina
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Stranica { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Došlo je do greške pri učitavanju PDF-a.
+pdfjs-invalid-file-error = Neispravna ili oštećena PDF datoteka.
+pdfjs-missing-file-error = Nedostaje PDF datoteka.
+pdfjs-unexpected-response-error = Neočekivani odgovor servera.
+pdfjs-rendering-error = Došlo je do greške prilikom iscrtavanja stranice.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Bilješka]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Za otvoranje ove PDF datoteku upiši lozinku.
+pdfjs-password-invalid = Neispravna lozinka. Pokušaj ponovo.
+pdfjs-password-ok-button = U redu
+pdfjs-password-cancel-button = Odustani
+pdfjs-web-fonts-disabled = Web fontovi su deaktivirani: nije moguće koristiti ugrađene PDF fontove.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Promijeni boju teksta
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Crtanje
+pdfjs-editor-color-picker-ink-input =
+ .title = Promijeni boju crteža
+pdfjs-editor-ink-button-label = Crtanje
+pdfjs-editor-stamp-button =
+ .title = Dodaj ili uredi slike
+pdfjs-editor-stamp-button-label = Dodaj ili uredi slike
+pdfjs-editor-highlight-button =
+ .title = Istakni
+pdfjs-editor-highlight-button-label = Istakni
+pdfjs-highlight-floating-button1 =
+ .title = Istakni
+ .aria-label = Istakni
+pdfjs-highlight-floating-button-label = Istakni
+pdfjs-comment-floating-button =
+ .title = Komentiraj
+ .aria-label = Komentiraj
+pdfjs-comment-floating-button-label = Komentiraj
+pdfjs-editor-comment-button =
+ .title = Komentar
+ .aria-label = Komentar
+pdfjs-editor-comment-button-label = Komentar
+pdfjs-editor-signature-button =
+ .title = Dodaj potpis
+pdfjs-editor-signature-button-label = Dodaj potpis
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Uređivač za isticanje teksta
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Uređivač crteža
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Uređivač potpisa: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Uređivač slika
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Ukloni crtež
+pdfjs-editor-remove-freetext-button =
+ .title = Ukloni tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Ukloni sliku
+pdfjs-editor-remove-highlight-button =
+ .title = Ukloni isticanje
+pdfjs-editor-remove-signature-button =
+ .title = Ukloni potpis
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Boja
+pdfjs-editor-free-text-size-input = Veličina
+pdfjs-editor-ink-color-input = Boja
+pdfjs-editor-ink-thickness-input = Debljina
+pdfjs-editor-ink-opacity-input = Neprozirnost
+pdfjs-editor-stamp-add-image-button =
+ .title = Dodaj sliku
+pdfjs-editor-stamp-add-image-button-label = Dodaj sliku
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Debljina
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Promjeni debljinu pri isticanju drugih stavki osim teksta
+pdfjs-editor-add-signature-container =
+ .aria-label = Kontrole potpisa i spremljeni potpisi
+pdfjs-editor-signature-add-signature-button =
+ .title = Dodaj novi potpis
+pdfjs-editor-signature-add-signature-button-label = Dodaj novi potpis
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Spremljeni potpis: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Uređivač teksta
+ .default-content = Počni tipkati …
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Komentar
+ [few] Komentara
+ *[other] Komentara
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Zatvori bočnu traku
+ .aria-label = Zatvori bočnu traku
+pdfjs-editor-comments-sidebar-close-button-label = Zatvori bočnu traku
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vidiš nešto vrijedno pažnje? Istakni to i ostavi komentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Saznaj više
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativni tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Uredi alternativni tekst
+pdfjs-editor-alt-text-dialog-label = Odaberi jednu opciju
+pdfjs-editor-alt-text-dialog-description = Alternativni tekst pomaže slijepim osobama ili kada se slika ne učita.
+pdfjs-editor-alt-text-add-description-label = Dodaj opis
+pdfjs-editor-alt-text-add-description-description = Sažmi sadržaj predmeta, okruženje ili radnje u jednoj ili dvije rečenice.
+pdfjs-editor-alt-text-mark-decorative-label = Označi kao ukrasno
+pdfjs-editor-alt-text-mark-decorative-description = Ovo se koristi za ukrasne slike, poput rubova ili vodenih žigova.
+pdfjs-editor-alt-text-cancel-button = Odustani
+pdfjs-editor-alt-text-save-button = Spremi
+pdfjs-editor-alt-text-decorative-tooltip = Označeno kao ukrasno
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Na primjer, „Mladić sjeda za stol kako bi jeo”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativni tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Gornji lijevi kut – promijeni veličinu
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Sredina gore – promijeni veličinu
+pdfjs-editor-resizer-top-right =
+ .aria-label = Gornji desni kut – promijeni veličinu
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Sredina desno – promijeni veličinu
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Donji desni kut – promijeni veličinu
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Sredina dolje – promjeni veličinu
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Donji lijevi kut – promijeni veličinu
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Sredina lijevo – promijeni veličinu
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Boja isticanja
+pdfjs-editor-colorpicker-button =
+ .title = Promjeni boju
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Izbor boja
+pdfjs-editor-colorpicker-yellow =
+ .title = Žuta
+pdfjs-editor-colorpicker-green =
+ .title = Zelena
+pdfjs-editor-colorpicker-blue =
+ .title = Plava
+pdfjs-editor-colorpicker-pink =
+ .title = Ružičasta
+pdfjs-editor-colorpicker-red =
+ .title = Crvena
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Prikaži sve
+pdfjs-editor-highlight-show-all-button =
+ .title = Prikaži sve
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Uredi alternativni tekst (opis slike)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Dodaj alternativni tekst (opis slike)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Ovdje upiši tvoj opis …
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kratki opis koji pomažu osobama koji ne mogu vidjeti sliku ili kada se slika ne učita.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ovaj je alternativni tekst stvoren automatski i može biti netočan.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Saznaj više
+pdfjs-editor-new-alt-text-create-automatically-button-label = Automatski stvori alternativni tekst
+pdfjs-editor-new-alt-text-not-now-button = Ne sada
+pdfjs-editor-new-alt-text-error-title = Nije bilo moguće automatski izraditi alternativni tekst
+pdfjs-editor-new-alt-text-error-description = Napiši vlastiti alternativni tekst ili pokušaj kasnije ponovo.
+pdfjs-editor-new-alt-text-error-close-button = Zatvori
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Preuzimanje alternativnog teksta UI modela ({ $downloadedSize } od { $totalSize } MB)
+ .aria-valuetext = Preuzimanje alternativnog teksta UI modela ({ $downloadedSize } od { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativni tekst je dodan
+pdfjs-editor-new-alt-text-added-button-label = Alternativni tekst je dodan
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Nedostaje alternativni tekst
+pdfjs-editor-new-alt-text-missing-button-label = Nedostaje alternativni tekst
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Pregledaj alternativni tekst
+pdfjs-editor-new-alt-text-to-review-button-label = Pregledaj alternativni tekst
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Stvoreno automatski: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Postavke alternativnog teksta slike
+pdfjs-image-alt-text-settings-button-label = Postavke alternativnog teksta slike
+pdfjs-editor-alt-text-settings-dialog-label = Postavke alternativnog teksta slike
+pdfjs-editor-alt-text-settings-automatic-title = Automatski alternativni tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Stvori alternativni tekst automatski
+pdfjs-editor-alt-text-settings-create-model-description = Predlaže opise koji pomažu osobama koji ne mogu vidjeti sliku ili kada se slika ne učita.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alternativni tekst UI modela ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Radi lokalno na tvom uređaju kako bi tvoji podaci ostali privatni. Potrebno za automatski alternativni tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Izbriši
+pdfjs-editor-alt-text-settings-download-model-button = Preuzmi
+pdfjs-editor-alt-text-settings-downloading-model-button = Preuzimanje …
+pdfjs-editor-alt-text-settings-editor-title = Uređivač alternativnog teksta
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Prikaži uređivač alternativnog teksta odmah pri dodavanju slike
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomaže osigurati da sve tvoje slike imaju alternativni tekst.
+pdfjs-editor-alt-text-settings-close-button = Zatvori
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Isticanje je dodano
+pdfjs-editor-freetext-added-alert = Tekst je dodan
+pdfjs-editor-ink-added-alert = Crtež je dodan
+pdfjs-editor-stamp-added-alert = Slika je dodana
+pdfjs-editor-signature-added-alert = Potpis je dodan
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Isticanje uklonjeno
+pdfjs-editor-undo-bar-message-freetext = Tekst uklonjen
+pdfjs-editor-undo-bar-message-ink = Crtež uklonjen
+pdfjs-editor-undo-bar-message-stamp = Slika uklonjena
+pdfjs-editor-undo-bar-message-signature = Potpis uklonjen
+pdfjs-editor-undo-bar-message-comment = Komentar je uklonjen
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } pribilješka uklonjena
+ [few] { $count } pribilješke uklonjene
+ *[other] { $count } pribilješki uklonjeno
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Poništi
+pdfjs-editor-undo-bar-undo-button-label = Poništi
+pdfjs-editor-undo-bar-close-button =
+ .title = Zatvori
+pdfjs-editor-undo-bar-close-button-label = Zatvori
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Ovaj prozor omogućuje korisniku stvoriti potpis i dodati ga u PDF dokument. Korisnik može urediti ime (koje služi i kao alternativni tekst) i opcionalno spremiti potpis za ponovnu upotrebu.
+pdfjs-editor-add-signature-dialog-title = Dodaj potpis
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Utipkaj
+ .title = Utipkaj
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Crtaj
+ .title = Crtaj
+pdfjs-editor-add-signature-image-button = Slika
+ .title = Slika
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Utipkaj svoj potpis
+ .placeholder = Utipkaj svoj potpis
+pdfjs-editor-add-signature-draw-placeholder = Nacrtaj svoj potpis
+pdfjs-editor-add-signature-draw-thickness-range-label = Debljina
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Debljina crtanja: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Povuci datoteku za prijenos ovamo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ili odaberi slikovne datoteke
+ *[other] Ili odaberi slikovne datoteke
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Opis (alternativni tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Opis (alternativni tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Potpis
+pdfjs-editor-add-signature-clear-button-label = Izbriši potpis
+pdfjs-editor-add-signature-clear-button =
+ .title = Izbriši potpis
+pdfjs-editor-add-signature-save-checkbox = Spremi potpis
+pdfjs-editor-add-signature-save-warning-message = Dosegnuto je ograničenje od 5 spremljenih potpisa. Za spremanje novih ukloni jedan potpis.
+pdfjs-editor-add-signature-image-upload-error-title = Nije moguće prenijeti sliku
+pdfjs-editor-add-signature-image-upload-error-description = Provjeri mrežnu vezu ili pokušaj s jednom drugom slikom.
+pdfjs-editor-add-signature-image-no-data-error-title = Ova se slika ne može pretvoriti u potpis
+pdfjs-editor-add-signature-image-no-data-error-description = Probaj prenijeti jednu drugu sliku.
+pdfjs-editor-add-signature-error-close-button = Zatvori
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Odustani
+pdfjs-editor-add-signature-add-button = Dodaj
+pdfjs-editor-edit-signature-update-button = Aktualiziraj
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Uredi komentar
+pdfjs-editor-edit-comment-popup-button =
+ .title = Uredi komentar
+pdfjs-editor-delete-comment-popup-button-label = Ukloni komentar
+pdfjs-editor-delete-comment-popup-button =
+ .title = Ukloni komentar
+pdfjs-show-comment-button =
+ .title = Prikaži komentar
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Uredi komentar
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualiziraj
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Dodaj komentar
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Dodaj
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Počni tipkati …
+pdfjs-editor-edit-comment-dialog-cancel-button = Odustani
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Dodaj komentar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-button1-label = Upravljaj stranicama
+pdfjs-views-manager-sidebar =
+ .aria-label = Bočna traka
+pdfjs-views-manager-view-selector-button =
+ .title = Prikazi
+pdfjs-views-manager-view-selector-button-label = Prikazi
+pdfjs-views-manager-pages-title = Stranice
+pdfjs-views-manager-outlines-title1 = Struktura dokumenta
+ .title = Struktura dokumenta (sažmi/proširi sve stavke dvostrukim klikom)
+pdfjs-views-manager-attachments-title = Privici
+pdfjs-views-manager-layers-title1 = Slojevi
+ .title = Slojevi (ponovo postavi sve slojeve na zadano stanje dvostrukim klikom)
+pdfjs-views-manager-pages-option-label = Stranice
+pdfjs-views-manager-outlines-option-label = Struktura dokumenta
+pdfjs-views-manager-attachments-option-label = Privici
+pdfjs-views-manager-layers-option-label = Slojevi
+pdfjs-views-manager-add-file-button =
+ .title = Dodaj datoteku
+pdfjs-views-manager-add-file-button-label = Dodaj datoteku
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } odabrana
+ [few] { $count } odabrane
+ *[other] { $count } odabranih
+ }
+pdfjs-views-manager-pages-status-none-action-label = Odaberi stranice
+pdfjs-views-manager-pages-status-action-button-label = Upravljaj
+pdfjs-views-manager-pages-status-copy-button-label = Kopiraj
+pdfjs-views-manager-pages-status-cut-button-label = Izreži
+pdfjs-views-manager-pages-status-delete-button-label = Izbriši
+pdfjs-views-manager-status-warning-cut-label = Nije moguće izrezati. Osvježi stranicu i pokušaj ponovo.
+pdfjs-views-manager-status-warning-copy-label = Nije moguće kopirati. Osvježi stranicu i pokušaj ponovo.
+pdfjs-views-manager-status-warning-delete-label = Nije moguće izbrisati. Osvježi stranicu i pokušaj ponovo.
+pdfjs-views-manager-status-warning-save-label = Nije moguće spremiti. Osvježi stranicu i pokušaj ponovo.
+pdfjs-views-manager-status-undo-button-label = Poništi
+pdfjs-views-manager-status-done-button-label = Gotovo
+pdfjs-views-manager-status-close-button =
+ .title = Zatvori
+pdfjs-views-manager-status-close-button-label = Zatvori
+pdfjs-views-manager-paste-button-label = Umetni
+pdfjs-views-manager-paste-button-before =
+ .title = Umetni prije prve stranice
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Umetni nakon stranice { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVO
+pdfjs-toggle-views-manager-button1 =
+ .title = Upravljaj stranicama
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Ukloni spremljeni potpis
+pdfjs-editor-delete-signature-button-label1 = Ukloni spremljeni potpis
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Uredi opis
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Uredi opis
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hsb/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hsb/viewer.ftl
new file mode 100644
index 0000000..3a52b0a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hsb/viewer.ftl
@@ -0,0 +1,864 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Předchadna strona
+pdfjs-previous-button-label = Wróćo
+pdfjs-next-button =
+ .title = Přichodna strona
+pdfjs-next-button-label = Dale
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Strona
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = z { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } z { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Pomjeńšić
+pdfjs-zoom-out-button-label = Pomjeńšić
+pdfjs-zoom-in-button =
+ .title = Powjetšić
+pdfjs-zoom-in-button-label = Powjetšić
+pdfjs-zoom-select =
+ .title = Skalowanje
+pdfjs-presentation-mode-button =
+ .title = Do prezentaciskeho modusa přeńć
+pdfjs-presentation-mode-button-label = Prezentaciski modus
+pdfjs-open-file-button =
+ .title = Dataju wočinić
+pdfjs-open-file-button-label = Wočinić
+pdfjs-print-button =
+ .title = Ćišćeć
+pdfjs-print-button-label = Ćišćeć
+pdfjs-save-button =
+ .title = Składować
+pdfjs-save-button-label = Składować
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Sćahnyć
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Sćahnyć
+pdfjs-bookmark-button =
+ .title = Aktualna strona (URL z aktualneje strony pokazać)
+pdfjs-bookmark-button-label = Aktualna strona
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Nastroje
+pdfjs-tools-button-label = Nastroje
+pdfjs-first-page-button =
+ .title = K prěnjej stronje
+pdfjs-first-page-button-label = K prěnjej stronje
+pdfjs-last-page-button =
+ .title = K poslednjej stronje
+pdfjs-last-page-button-label = K poslednjej stronje
+pdfjs-page-rotate-cw-button =
+ .title = K směrej časnika wjerćeć
+pdfjs-page-rotate-cw-button-label = K směrej časnika wjerćeć
+pdfjs-page-rotate-ccw-button =
+ .title = Přećiwo směrej časnika wjerćeć
+pdfjs-page-rotate-ccw-button-label = Přećiwo směrej časnika wjerćeć
+pdfjs-cursor-text-select-tool-button =
+ .title = Nastroj za wuběranje teksta zmóžnić
+pdfjs-cursor-text-select-tool-button-label = Nastroj za wuběranje teksta
+pdfjs-cursor-hand-tool-button =
+ .title = Ručny nastroj zmóžnić
+pdfjs-cursor-hand-tool-button-label = Ručny nastroj
+pdfjs-scroll-page-button =
+ .title = Kulenje strony wužiwać
+pdfjs-scroll-page-button-label = Kulenje strony
+pdfjs-scroll-vertical-button =
+ .title = Wertikalne suwanje wužiwać
+pdfjs-scroll-vertical-button-label = Wertikalne suwanje
+pdfjs-scroll-horizontal-button =
+ .title = Horicontalne suwanje wužiwać
+pdfjs-scroll-horizontal-button-label = Horicontalne suwanje
+pdfjs-scroll-wrapped-button =
+ .title = Postupne suwanje wužiwać
+pdfjs-scroll-wrapped-button-label = Postupne suwanje
+pdfjs-spread-none-button =
+ .title = Strony njezwjazać
+pdfjs-spread-none-button-label = Žana dwójna strona
+pdfjs-spread-odd-button =
+ .title = Strony započinajo z njerunymi stronami zwjazać
+pdfjs-spread-odd-button-label = Njerune strony
+pdfjs-spread-even-button =
+ .title = Strony započinajo z runymi stronami zwjazać
+pdfjs-spread-even-button-label = Rune strony
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentowe kajkosće…
+pdfjs-document-properties-button-label = Dokumentowe kajkosće…
+pdfjs-document-properties-file-name = Mjeno dataje:
+pdfjs-document-properties-file-size = Wulkosć dataje:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bajtow)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtow)
+pdfjs-document-properties-title = Titul:
+pdfjs-document-properties-author = Awtor:
+pdfjs-document-properties-subject = Předmjet:
+pdfjs-document-properties-keywords = Klučowe słowa:
+pdfjs-document-properties-creation-date = Datum wutworjenja:
+pdfjs-document-properties-modification-date = Datum změny:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Awtor:
+pdfjs-document-properties-producer = PDF-zhotowjer:
+pdfjs-document-properties-version = PDF-wersija:
+pdfjs-document-properties-page-count = Ličba stronow:
+pdfjs-document-properties-page-size = Wulkosć strony:
+pdfjs-document-properties-page-size-unit-inches = cól
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = wysoki format
+pdfjs-document-properties-page-size-orientation-landscape = prěčny format
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Haj
+pdfjs-document-properties-linearized-no = Ně
+pdfjs-document-properties-close-button = Začinić
+pdfjs-digital-signature-properties-view-certificate = Certifikat pokazać
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Přičina: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Časowy kołk: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] { $count } podsignatura
+ [two] { $count } podsignaturje
+ [few] { $count } podsignatury
+ *[other] { $count } podsignaturow
+ }
+
+## Print
+
+pdfjs-print-progress-message = Dokument so za ćišćenje přihotuje…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Přetorhnyć
+pdfjs-printing-not-supported = Warnowanje: Ćišćenje so přez tutón wobhladowak połnje njepodpěruje.
+pdfjs-printing-not-ready = Warnowanje: PDF njeje so za ćišćenje dospołnje začitał.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Bóčnicu pokazać/schować
+pdfjs-toggle-sidebar-notification-button =
+ .title = Bóčnicu přepinać (dokument rozrjad/přiwěški/woršty wobsahuje)
+pdfjs-toggle-sidebar-button-label = Bóčnicu pokazać/schować
+pdfjs-document-outline-button =
+ .title = Dokumentowy naćisk pokazać (dwójne kliknjenje, zo bychu so wšě zapiski pokazali/schowali)
+pdfjs-document-outline-button-label = Dokumentowa struktura
+pdfjs-attachments-button =
+ .title = Přiwěški pokazać
+pdfjs-attachments-button-label = Přiwěški
+pdfjs-layers-button =
+ .title = Woršty pokazać (klikńće dwójce, zo byšće wšě woršty na standardny staw wróćo stajił)
+pdfjs-layers-button-label = Woršty
+pdfjs-thumbs-button =
+ .title = Miniatury pokazać
+pdfjs-thumbs-button-label = Miniatury
+pdfjs-current-outline-item-button =
+ .title = Aktualny rozrjadowy zapisk pytać
+pdfjs-current-outline-item-button-label = Aktualny rozrjadowy zapisk
+pdfjs-findbar-button =
+ .title = W dokumenće pytać
+pdfjs-findbar-button-label = Pytać
+pdfjs-additional-layers = Dalše woršty
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Strona { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura strony { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Stronu { $page } wubrać
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Strona { $page } z { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Pytać
+ .placeholder = W dokumenće pytać…
+pdfjs-find-previous-button =
+ .title = Předchadne wustupowanje pytanskeho wuraza pytać
+pdfjs-find-previous-button-label = Wróćo
+pdfjs-find-next-button =
+ .title = Přichodne wustupowanje pytanskeho wuraza pytać
+pdfjs-find-next-button-label = Dale
+pdfjs-find-highlight-checkbox = Wšě wuzběhnyć
+pdfjs-find-match-case-checkbox-label = Wulkopisanje wobkedźbować
+pdfjs-find-match-diacritics-checkbox-label = Diakritiske znamješka wužiwać
+pdfjs-find-entire-word-checkbox-label = Cyłe słowa
+pdfjs-find-reached-top = Spočatk dokumenta docpěty, pokročuje so z kóncom
+pdfjs-find-reached-bottom = Kónc dokument docpěty, pokročuje so ze spočatkom
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } z { $total } wotpowědnika
+ [two] { $current } z { $total } wotpowědnikow
+ [few] { $current } z { $total } wotpowědnikow
+ *[other] { $current } z { $total } wotpowědnikow
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Wyše { $limit } wotpowědnik
+ [two] Wyše { $limit } wotpowědnikaj
+ [few] Wyše { $limit } wotpowědniki
+ *[other] Wyše { $limit } wotpowědnikow
+ }
+pdfjs-find-not-found = Pytanski wuraz njeje so namakał
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Šěrokosć strony
+pdfjs-page-scale-fit = Wulkosć strony
+pdfjs-page-scale-auto = Awtomatiske skalowanje
+pdfjs-page-scale-actual = Aktualna wulkosć
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Strona { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Při začitowanju PDF je zmylk wustupił.
+pdfjs-invalid-file-error = Njepłaćiwa abo wobškodźena PDF-dataja.
+pdfjs-missing-file-error = Falowaca PDF-dataja.
+pdfjs-unexpected-response-error = Njewočakowana serwerowa wotmołwa.
+pdfjs-rendering-error = Při zwobraznjenju strony je zmylk wustupił.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Typ přispomnjenki: { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Zapodajće hesło, zo byšće PDF-dataju wočinił.
+pdfjs-password-invalid = Njepłaćiwe hesło. Prošu spytajće hišće raz.
+pdfjs-password-ok-button = W porjadku
+pdfjs-password-cancel-button = Přetorhnyć
+pdfjs-web-fonts-disabled = Webpisma su znjemóžnjene: njeje móžno, zasadźene PDF-pisma wužiwać.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Tekstowu barbu změnić
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Rysować
+pdfjs-editor-color-picker-ink-input =
+ .title = Rysowansku barbu změnić
+pdfjs-editor-ink-button-label = Rysować
+pdfjs-editor-stamp-button =
+ .title = Wobrazy přidać abo wobdźěłać
+pdfjs-editor-stamp-button-label = Wobrazy přidać abo wobdźěłać
+pdfjs-editor-highlight-button =
+ .title = Wuzběhnyć
+pdfjs-editor-highlight-button-label = Wuzběhnyć
+pdfjs-highlight-floating-button1 =
+ .title = Wuzběhnjenje
+ .aria-label = Wuzběhnjenje
+pdfjs-highlight-floating-button-label = Wuzběhnjenje
+pdfjs-comment-floating-button =
+ .title = Komentować
+ .aria-label = Komentować
+pdfjs-comment-floating-button-label = Komentować
+pdfjs-editor-comment-button =
+ .title = Komentować
+ .aria-label = Komentować
+pdfjs-editor-comment-button-label = Komentować
+pdfjs-editor-signature-button =
+ .title = Signaturu přidać
+pdfjs-editor-signature-button-label = Signaturu přidać
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Wuzběhowanski editor
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Rysowanski editor
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signaturowy editor: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Wobrazowy editor
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Rysowanku wotstronić
+pdfjs-editor-remove-freetext-button =
+ .title = Tekst wotstronić
+pdfjs-editor-remove-stamp-button =
+ .title = Wobraz wotstronić
+pdfjs-editor-remove-highlight-button =
+ .title = Wuzběhnjenje wotstronić
+pdfjs-editor-remove-signature-button =
+ .title = Signaturu wotstronić
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Barba
+pdfjs-editor-free-text-size-input = Wulkosć
+pdfjs-editor-ink-color-input = Barba
+pdfjs-editor-ink-thickness-input = Tołstosć
+pdfjs-editor-ink-opacity-input = Opacita
+pdfjs-editor-stamp-add-image-button =
+ .title = Wobraz přidać
+pdfjs-editor-stamp-add-image-button-label = Wobraz přidać
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tołstosć
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Tołstosć změnić, hdyž so zapiski wuzběhuja, kotrež tekst njejsu
+pdfjs-editor-add-signature-container =
+ .aria-label = Wodźenske elementy signaturow a składowane signatury
+pdfjs-editor-signature-add-signature-button =
+ .title = Nowu signaturu přidać
+pdfjs-editor-signature-add-signature-button-label = Nowu signaturu přidać
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Składowana signatura: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstowy editor
+ .default-content = Započńće pisać …
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] { $count } komentar
+ [two] { $count } komentaraj
+ [few] { $count } komentary
+ *[other] { $count } komentarow
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Bóčnicu začinić
+ .aria-label = Bóčnicu začinić
+pdfjs-editor-comments-sidebar-close-button-label = Bóčnicu začinić
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Widźiće něšto přispomnjenja hódneho? Wuzběhńće to a zawostajće komentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Dalše informacije
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternatiwny tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternatiwny tekst wobdźěłać
+pdfjs-editor-alt-text-dialog-label = Nastajenje wubrać
+pdfjs-editor-alt-text-dialog-description = Alternatiwny tekst pomha, hdyž ludźo njemóža wobraz widźeć abo hdyž so wobraz njezačita.
+pdfjs-editor-alt-text-add-description-label = Wopisanje přidać
+pdfjs-editor-alt-text-add-description-description = Pisajće 1 sadu abo 2 sadźe, kotrejž temu, nastajenje abo akcije wopisujetej.
+pdfjs-editor-alt-text-mark-decorative-label = Jako dekoratiwny markěrować
+pdfjs-editor-alt-text-mark-decorative-description = To so za pyšace wobrazy wužiwa, na přikład ramiki abo wodowe znamjenja.
+pdfjs-editor-alt-text-cancel-button = Přetorhnyć
+pdfjs-editor-alt-text-save-button = Składować
+pdfjs-editor-alt-text-decorative-tooltip = Jako dekoratiwny markěrowany
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Na přikład, „Młody muž za blidom sedźi, zo by jědź jědł“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternatiwny tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Horjeka nalěwo – wulkosć změnić
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Horjeka wosrjedź – wulkosć změnić
+pdfjs-editor-resizer-top-right =
+ .aria-label = Horjeka naprawo – wulkosć změnić
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Wosrjedź naprawo – wulkosć změnić
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Deleka naprawo – wulkosć změnić
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Deleka wosrjedź – wulkosć změnić
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Deleka nalěwo – wulkosć změnić
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Wosrjedź nalěwo – wulkosć změnić
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Barba wuzběhnjenja
+pdfjs-editor-colorpicker-button =
+ .title = Barbu změnić
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Wuběr barbow
+pdfjs-editor-colorpicker-yellow =
+ .title = Žołty
+pdfjs-editor-colorpicker-green =
+ .title = Zeleny
+pdfjs-editor-colorpicker-blue =
+ .title = Módry
+pdfjs-editor-colorpicker-pink =
+ .title = Pink
+pdfjs-editor-colorpicker-red =
+ .title = Čerwjeny
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Wšě pokazać
+pdfjs-editor-highlight-show-all-button =
+ .title = Wšě pokazać
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alternatiwny tekst wobdźěłać (wobrazowe wopisanje)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alternatiwny tekst přidać (wobrazowe wopisanje)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Pisajće tu swoje wopisanje…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Krótke wopisanje za ludźi, kotřiž njemóžeće wobraz widźeć abo hdyž so wobraz njezačita.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Tutón alternatiwny tekst je so awtomatisce wutworił a je snano njedokładny.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Dalše informacije
+pdfjs-editor-new-alt-text-create-automatically-button-label = Alternatiwny tekst awtomatisce wutworić
+pdfjs-editor-new-alt-text-not-now-button = Nic nětko
+pdfjs-editor-new-alt-text-error-title = Alternatiwny tekst njeda so awtomatisce wutworić
+pdfjs-editor-new-alt-text-error-description = Prošu pisajće swój alternatiwny tekst abo spytajće pozdźišo hišće raz.
+pdfjs-editor-new-alt-text-error-close-button = Začinić
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Model KI za alternatiwny tekst so sćahuje ({ $downloadedSize } z { $totalSize } MB)
+ .aria-valuetext = Model KI za alternatiwny tekst so sćahuje ({ $downloadedSize } z { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternatiwny tekst je so přidał
+pdfjs-editor-new-alt-text-added-button-label = Alternatiwny tekst je so přidał
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Alternatiwny tekst faluje
+pdfjs-editor-new-alt-text-missing-button-label = Alternatiwny tekst faluje
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternatiwny tekst přepruwować
+pdfjs-editor-new-alt-text-to-review-button-label = Alternatiwny tekst přepruwować
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Awtomatisce wutworjeny: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Nastajenja alternatiwneho wobrazoweho teksta
+pdfjs-image-alt-text-settings-button-label = Nastajenja alternatiwneho wobrazoweho teksta
+pdfjs-editor-alt-text-settings-dialog-label = Nastajenja alternatiwneho wobrazoweho teksta
+pdfjs-editor-alt-text-settings-automatic-title = Awtomatiski alternatiwny tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Alternatiwny tekst awtomatisce wutworić
+pdfjs-editor-alt-text-settings-create-model-description = Namjetuje wopisanja, zo by ludźom pomhał, kotřiž njemóžeće wobraz widźeć abo hdyž so wobraz njezačita.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model KI alternatiwneho teksta ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Běži lokalnje na wašim graće, zo bychu waše daty priwatne wostali. Za awtomatiski alternatiwny tekst trěbny.
+pdfjs-editor-alt-text-settings-delete-model-button = Zhašeć
+pdfjs-editor-alt-text-settings-download-model-button = Sćahnyć
+pdfjs-editor-alt-text-settings-downloading-model-button = Sćahuje so…
+pdfjs-editor-alt-text-settings-editor-title = Editor za alternatiwny tekst
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Editor alternatiwneho teksta hnydom pokazać, hdyž so wobraz přidawa
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomha, wam wšěm swojim wobrazam alternatiwny tekst přidać.
+pdfjs-editor-alt-text-settings-close-button = Začinić
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Wuzběhnjenje přidate
+pdfjs-editor-freetext-added-alert = Tekst přidaty
+pdfjs-editor-ink-added-alert = Rysowanka přidata
+pdfjs-editor-stamp-added-alert = Wobraz přidaty
+pdfjs-editor-signature-added-alert = Signatura přidata
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Wotstronjene wuzběhnyć
+pdfjs-editor-undo-bar-message-freetext = Tekst je so wotstronił
+pdfjs-editor-undo-bar-message-ink = Rysowanka je so wotstroniła
+pdfjs-editor-undo-bar-message-stamp = Wobraz je so wotstronił
+pdfjs-editor-undo-bar-message-signature = Signatura je so wotstroniła
+pdfjs-editor-undo-bar-message-comment = Komentar je so wotstronił
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } přispomnjenka je so wotstroniła
+ [two] { $count } přispomnjence stej so wotstroniłoj
+ [few] { $count } přispomnjenki su so wotstronili
+ *[other] { $count } přispomnjenkow je so wotstroniło
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Cofnyć
+pdfjs-editor-undo-bar-undo-button-label = Cofnyć
+pdfjs-editor-undo-bar-close-button =
+ .title = Začinić
+pdfjs-editor-undo-bar-close-button-label = Začinić
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Tutón modalny dialog wužiwarjej zmóžnja, signaturu wutworić, zo by PDF-dokument přidał. Wužiwar móže mjeno wobdźěłać (kotrež tež jako alternatiwny tekst słuži) a po přeću signaturu za wospjetne wužiwanje składować.
+pdfjs-editor-add-signature-dialog-title = Signaturu přidać
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Typ
+ .title = Typ
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Rysować
+ .title = Rysować
+pdfjs-editor-add-signature-image-button = Wobraz
+ .title = Wobraz
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Zapodajće swoju signaturu
+ .placeholder = Zapodajće swoju signaturu
+pdfjs-editor-add-signature-draw-placeholder = Rysujće swoju signaturu
+pdfjs-editor-add-signature-draw-thickness-range-label = Tołstosć
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Tołstosć rysowanki: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Ćehńće dataju sem, zo byšće ju nahrał
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Abo přepytajće wobrazowe dataje
+ *[other] Abo přepytajće wobrazowe dataje
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Wopisanje (alternatiwny tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Wopisanje (alternatiwny tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatura
+pdfjs-editor-add-signature-clear-button-label = Signaturu zhašeć
+pdfjs-editor-add-signature-clear-button =
+ .title = Signaturu zhašeć
+pdfjs-editor-add-signature-save-checkbox = Signaturu składować
+pdfjs-editor-add-signature-save-warning-message = Sće limit 5 składowanych signaturow docpěł. Wotstrońće jednu, zo byšće wjace składował.
+pdfjs-editor-add-signature-image-upload-error-title = Wobraz njeda so nahrać
+pdfjs-editor-add-signature-image-upload-error-description = Přepruwujće swój syćowy zwisk abo spytajće druhi wobraz.
+pdfjs-editor-add-signature-image-no-data-error-title = Tutón wobraz njeda so do signatury přetworić
+pdfjs-editor-add-signature-image-no-data-error-description = Spytajće prošu druhi wobraz nahrać.
+pdfjs-editor-add-signature-error-close-button = Začinić
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Přetorhnyć
+pdfjs-editor-add-signature-add-button = Přidać
+pdfjs-editor-edit-signature-update-button = Aktualizować
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Komentar wobdźěłać
+pdfjs-editor-edit-comment-popup-button =
+ .title = Komentar wobdźěłać
+pdfjs-editor-delete-comment-popup-button-label = Komentar wotstronić
+pdfjs-editor-delete-comment-popup-button =
+ .title = Komentar wotstronić
+pdfjs-show-comment-button =
+ .title = Komentar pokazać
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Komentar wobdźěłać
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualizować
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Komentar přidać
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Přidać
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Započńće pisać…
+pdfjs-editor-edit-comment-dialog-cancel-button = Přetorhnyć
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Komentar přidać
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Bóčnicu přepinać (dokument miniatury/rozrjad/přiwěški/woršty wobsahuje)
+pdfjs-toggle-views-manager-button1-label = Strony rjadować
+pdfjs-views-manager-sidebar =
+ .aria-label = Bóčnica
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Přiměrjenje wulkosće bóčnicy
+pdfjs-views-manager-view-selector-button =
+ .title = Napohlady
+pdfjs-views-manager-view-selector-button-label = Napohlady
+pdfjs-views-manager-pages-title = Strony
+pdfjs-views-manager-outlines-title1 = Dokumentowa struktura
+ .title = Dokumentowa struktura (klikńće dwójce, zo byšće wšě zapiski pokazał/schował)
+pdfjs-views-manager-attachments-title = Přiwěški
+pdfjs-views-manager-layers-title1 = Runiny
+ .title = Runiny (klikńće dwójce, zo byšće wšě runiny na standardny status wróćo stajił)
+pdfjs-views-manager-pages-option-label = Strony
+pdfjs-views-manager-outlines-option-label = Dokumentowa struktura
+pdfjs-views-manager-attachments-option-label = Přiwěški
+pdfjs-views-manager-layers-option-label = Runiny
+pdfjs-views-manager-add-file-button =
+ .title = Dataju přidać
+pdfjs-views-manager-add-file-button-label = Dataju přidać
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } wubrany
+ [two] { $count } wubranej
+ [few] { $count } wubrane
+ *[other] { $count } wubranych
+ }
+pdfjs-views-manager-pages-status-none-action-label = Strony wubrać
+pdfjs-views-manager-pages-status-action-button-label = Rjadować
+pdfjs-views-manager-pages-status-copy-button-label = Kopěrować
+pdfjs-views-manager-pages-status-cut-button-label = Wutřihać
+pdfjs-views-manager-pages-status-delete-button-label = Zhašeć
+pdfjs-views-manager-pages-status-export-selected-button-label = Wubrane eksportować…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] { $count } strona wutřihana
+ [two] { $count } stronje wutřihanej
+ [few] { $count } strony wutřihane
+ *[other] { $count } stronow wutřihane
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] { $count } strona kopěrowana
+ [two] { $count } strona kopěrowanej
+ [few] { $count } strona kopěrowane
+ *[other] { $count } strona kopěrowane
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] { $count } strona zhašana
+ [two] { $count } strona zhašanej
+ [few] { $count } strona zhašane
+ *[other] { $count } strona zhašane
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Waša dataja so přihotuje…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Dataja so nahrawa…
+pdfjs-views-manager-status-warning-cut-label = Njeda so wutřihać. Aktualizujće stronu a spytajće hišće raz.
+pdfjs-views-manager-status-warning-copy-label = Njeda so kopěrować. Aktualizujće stronu a spytajće hišće raz.
+pdfjs-views-manager-status-warning-delete-label = Njeda so zhašeć. Aktualizujće stronu a spytajće hišće raz.
+pdfjs-views-manager-status-warning-save-label = Njeda so składować. Aktualizujće stronu a spytajće hišće raz.
+pdfjs-views-manager-status-undo-button-label = Cofnyć
+pdfjs-views-manager-status-done-button-label = Dokónčeny
+pdfjs-views-manager-status-close-button =
+ .title = Začinić
+pdfjs-views-manager-status-close-button-label = Začinić
+pdfjs-views-manager-paste-button-label = Zasadźić
+pdfjs-views-manager-paste-button-before =
+ .title = Před prěnjej stronu zasadźić
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Za stronu { $page } zasadźić
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOWY
+pdfjs-views-manager-waiting-for-file = Dataja so nahrawa…
+pdfjs-toggle-views-manager-button1 =
+ .title = Strony rjadować
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Kajkosće digitalneje signatury
+ .aria-label = Kajkosće digitalneje signatury
+pdfjs-digital-signature-properties-button-label = Kajkosće digitalneje signatury
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument je so z płaćiwej digitalnej signaturu signował
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument je so signował, ale { $count } digitalna signatura njeda so wobkrućić
+ [two] Dokument je so signował, ale { $count } digitalnej signaturje njedatej so wobkrućić
+ [few] Dokument je so signował, ale { $count } digitalne signatury njedachu so wobkrućić
+ *[other] Dokument je so signował, ale { $count } digitalnych signaturow njeda so wobkrućić
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument je z { $count } certifikatom signowany, kotryž dowěry hódny njeje
+ [two] Dokument je z { $count } certifikatomaj signowany, kotrejž dowěry hódnej njejstej
+ [few] Dokument je z { $count } certifikatami signowany, kotrež dowěry hódne njejsu
+ *[other] Dokument je z { $count } certifikatami signowany, kotrež dowěry hódne njejsu
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument je z { $count } spadnjenym certifikatom signowany
+ [two] Dokument je z { $count } spadnjenymaj certifikatomaj signowany
+ [few] Dokument je z { $count } spadnjenymi certifikatami signowany
+ *[other] Dokument je z { $count } spadnjenymi certifikatami signowany
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument ma { $count } njepłaćiwu digitalnu signaturu
+ [two] Dokument ma { $count } njepłaćiwej digitalnej signaturje
+ [few] Dokument ma { $count } njepłaćiwe digitalne signatury
+ *[other] Dokument ma { $count } njepłaćiwych digitalnych signaturow
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument je z { $count } wotwołanym certifikatom signowany
+ [two] Dokument je z { $count } wotwołanymaj certifikatomaj signowany
+ [few] Dokument je z { $count } wotwołanymi certifikatami signowany
+ *[other] Dokument je z { $count } wotwołanymi certifikatami signowany
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signatura je wobkrućena
+pdfjs-digital-signature-properties-status-invalid = Status: Signatura je njepłaćiwa
+pdfjs-digital-signature-properties-status-unknown = Status: Njeda so wobkrućić (njepodpěruje so)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certifikat: Dowěry hódny ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certifikat: Nic k dispoziciji
+pdfjs-digital-signature-properties-certificate-untrusted = Certifikat: Dowěry njehódny
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certifikat: Njeznaty wudawar ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certifikat: Samsignowany ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certifikat: Dowěry njehódny wudawar ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certifikat: Spadnjeny
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certifikat: Spadnjeny ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certifikat: Wotwołany
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Składowanu signaturu wotstronić
+pdfjs-editor-delete-signature-button-label1 = Składowanu signaturu wotstronić
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Wopisanje wobdźěłać
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Wopisanje wobdźěłać
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hu/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hu/viewer.ftl
new file mode 100644
index 0000000..e63349f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hu/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Előző oldal
+pdfjs-previous-button-label = Előző
+pdfjs-next-button =
+ .title = Következő oldal
+pdfjs-next-button-label = Tovább
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Oldal
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = összesen: { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Kicsinyítés
+pdfjs-zoom-out-button-label = Kicsinyítés
+pdfjs-zoom-in-button =
+ .title = Nagyítás
+pdfjs-zoom-in-button-label = Nagyítás
+pdfjs-zoom-select =
+ .title = Nagyítás
+pdfjs-presentation-mode-button =
+ .title = Váltás bemutató módba
+pdfjs-presentation-mode-button-label = Bemutató mód
+pdfjs-open-file-button =
+ .title = Fájl megnyitása
+pdfjs-open-file-button-label = Megnyitás
+pdfjs-print-button =
+ .title = Nyomtatás
+pdfjs-print-button-label = Nyomtatás
+pdfjs-save-button =
+ .title = Mentés
+pdfjs-save-button-label = Mentés
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Letöltés
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Letöltés
+pdfjs-bookmark-button =
+ .title = Jelenlegi oldal (webcím megtekintése a jelenlegi oldalról)
+pdfjs-bookmark-button-label = Jelenlegi oldal
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Eszközök
+pdfjs-tools-button-label = Eszközök
+pdfjs-first-page-button =
+ .title = Ugrás az első oldalra
+pdfjs-first-page-button-label = Ugrás az első oldalra
+pdfjs-last-page-button =
+ .title = Ugrás az utolsó oldalra
+pdfjs-last-page-button-label = Ugrás az utolsó oldalra
+pdfjs-page-rotate-cw-button =
+ .title = Forgatás az óramutató járásával egyezően
+pdfjs-page-rotate-cw-button-label = Forgatás az óramutató járásával egyezően
+pdfjs-page-rotate-ccw-button =
+ .title = Forgatás az óramutató járásával ellentétesen
+pdfjs-page-rotate-ccw-button-label = Forgatás az óramutató járásával ellentétesen
+pdfjs-cursor-text-select-tool-button =
+ .title = Szövegkijelölő eszköz bekapcsolása
+pdfjs-cursor-text-select-tool-button-label = Szövegkijelölő eszköz
+pdfjs-cursor-hand-tool-button =
+ .title = Kéz eszköz bekapcsolása
+pdfjs-cursor-hand-tool-button-label = Kéz eszköz
+pdfjs-scroll-page-button =
+ .title = Oldalgörgetés használata
+pdfjs-scroll-page-button-label = Oldalgörgetés
+pdfjs-scroll-vertical-button =
+ .title = Függőleges görgetés használata
+pdfjs-scroll-vertical-button-label = Függőleges görgetés
+pdfjs-scroll-horizontal-button =
+ .title = Vízszintes görgetés használata
+pdfjs-scroll-horizontal-button-label = Vízszintes görgetés
+pdfjs-scroll-wrapped-button =
+ .title = Rácsos elrendezés használata
+pdfjs-scroll-wrapped-button-label = Rácsos elrendezés
+pdfjs-spread-none-button =
+ .title = Ne tapassza össze az oldalakat
+pdfjs-spread-none-button-label = Nincs összetapasztás
+pdfjs-spread-odd-button =
+ .title = Lapok összetapasztása, a páratlan számú oldalakkal kezdve
+pdfjs-spread-odd-button-label = Összetapasztás: páratlan
+pdfjs-spread-even-button =
+ .title = Lapok összetapasztása, a páros számú oldalakkal kezdve
+pdfjs-spread-even-button-label = Összetapasztás: páros
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentum tulajdonságai…
+pdfjs-document-properties-button-label = Dokumentum tulajdonságai…
+pdfjs-document-properties-file-name = Fájlnév:
+pdfjs-document-properties-file-size = Fájlméret:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } bájt)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bájt)
+pdfjs-document-properties-title = Cím:
+pdfjs-document-properties-author = Szerző:
+pdfjs-document-properties-subject = Tárgy:
+pdfjs-document-properties-keywords = Kulcsszavak:
+pdfjs-document-properties-creation-date = Létrehozás dátuma:
+pdfjs-document-properties-modification-date = Módosítás dátuma:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Létrehozta:
+pdfjs-document-properties-producer = PDF előállító:
+pdfjs-document-properties-version = PDF verzió:
+pdfjs-document-properties-page-count = Oldalszám:
+pdfjs-document-properties-page-size = Lapméret:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = álló
+pdfjs-document-properties-page-size-orientation-landscape = fekvő
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Jogi információk
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Gyors webes nézet:
+pdfjs-document-properties-linearized-yes = Igen
+pdfjs-document-properties-linearized-no = Nem
+pdfjs-document-properties-close-button = Bezárás
+pdfjs-digital-signature-properties-view-certificate = Tanúsítvány megtekintése
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Ok: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Időbélyeg: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Részaláírás ({ $count })
+ *[other] Részaláírások ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Dokumentum előkészítése nyomtatáshoz…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Mégse
+pdfjs-printing-not-supported = Figyelmeztetés: Ez a böngésző nem teljesen támogatja a nyomtatást.
+pdfjs-printing-not-ready = Figyelmeztetés: A PDF nincs teljesen betöltve a nyomtatáshoz.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Oldalsáv be/ki
+pdfjs-toggle-sidebar-notification-button =
+ .title = Oldalsáv be/ki (a dokumentum vázlatot/mellékleteket/rétegeket tartalmaz)
+pdfjs-toggle-sidebar-button-label = Oldalsáv be/ki
+pdfjs-document-outline-button =
+ .title = Dokumentum megjelenítése online (dupla kattintás minden elem kinyitásához/összecsukásához)
+pdfjs-document-outline-button-label = Dokumentumvázlat
+pdfjs-attachments-button =
+ .title = Mellékletek megjelenítése
+pdfjs-attachments-button-label = Van melléklet
+pdfjs-layers-button =
+ .title = Rétegek megjelenítése (dupla kattintás az összes réteg alapértelmezett állapotra visszaállításához)
+pdfjs-layers-button-label = Rétegek
+pdfjs-thumbs-button =
+ .title = Bélyegképek megjelenítése
+pdfjs-thumbs-button-label = Bélyegképek
+pdfjs-current-outline-item-button =
+ .title = Jelenlegi vázlatelem megkeresése
+pdfjs-current-outline-item-button-label = Jelenlegi vázlatelem
+pdfjs-findbar-button =
+ .title = Keresés a dokumentumban
+pdfjs-findbar-button-label = Keresés
+pdfjs-additional-layers = További rétegek
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page }. oldal
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page }. oldal bélyegképe
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = { $page }. oldal kiválasztása
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = { $page }. / { $total } oldal
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Keresés
+ .placeholder = Keresés a dokumentumban…
+pdfjs-find-previous-button =
+ .title = A kifejezés előző előfordulásának keresése
+pdfjs-find-previous-button-label = Előző
+pdfjs-find-next-button =
+ .title = A kifejezés következő előfordulásának keresése
+pdfjs-find-next-button-label = Tovább
+pdfjs-find-highlight-checkbox = Összes kiemelése
+pdfjs-find-match-case-checkbox-label = Kis- és nagybetűk megkülönböztetése
+pdfjs-find-match-diacritics-checkbox-label = Diakritikus jelek
+pdfjs-find-entire-word-checkbox-label = Teljes szavak
+pdfjs-find-reached-top = A dokumentum eleje elérve, folytatás a végétől
+pdfjs-find-reached-bottom = A dokumentum vége elérve, folytatás az elejétől
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } / { $total } találat
+ *[other] { $current } / { $total } találat
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Több mint { $limit } találat
+ *[other] Több mint { $limit } találat
+ }
+pdfjs-find-not-found = A kifejezés nem található
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Oldalszélesség
+pdfjs-page-scale-fit = Teljes oldal
+pdfjs-page-scale-auto = Automatikus nagyítás
+pdfjs-page-scale-actual = Valódi méret
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page }. oldal
+
+## Loading indicator messages
+
+pdfjs-loading-error = Hiba történt a PDF betöltésekor.
+pdfjs-invalid-file-error = Érvénytelen vagy sérült PDF fájl.
+pdfjs-missing-file-error = Hiányzó PDF fájl.
+pdfjs-unexpected-response-error = Váratlan kiszolgálóválasz.
+pdfjs-rendering-error = Hiba történt az oldal feldolgozása közben.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } megjegyzés]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Adja meg a jelszót a PDF fájl megnyitásához.
+pdfjs-password-invalid = Helytelen jelszó. Próbálja újra.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Mégse
+pdfjs-web-fonts-disabled = Webes betűkészletek letiltva: nem használhatók a beágyazott PDF betűkészletek.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Szöveg
+pdfjs-editor-color-picker-free-text-input =
+ .title = Szövegszín módosítása
+pdfjs-editor-free-text-button-label = Szöveg
+pdfjs-editor-ink-button =
+ .title = Rajzolás
+pdfjs-editor-color-picker-ink-input =
+ .title = Rajzolási szín módosítása
+pdfjs-editor-ink-button-label = Rajzolás
+pdfjs-editor-stamp-button =
+ .title = Képek hozzáadása vagy szerkesztése
+pdfjs-editor-stamp-button-label = Képek hozzáadása vagy szerkesztése
+pdfjs-editor-highlight-button =
+ .title = Kiemelés
+pdfjs-editor-highlight-button-label = Kiemelés
+pdfjs-highlight-floating-button1 =
+ .title = Kiemelés
+ .aria-label = Kiemelés
+pdfjs-highlight-floating-button-label = Kiemelés
+pdfjs-comment-floating-button =
+ .title = Megjegyzés
+ .aria-label = Megjegyzés
+pdfjs-comment-floating-button-label = Megjegyzés
+pdfjs-editor-comment-button =
+ .title = Megjegyzés
+ .aria-label = Megjegyzés
+pdfjs-editor-comment-button-label = Megjegyzés
+pdfjs-editor-signature-button =
+ .title = Aláírás hozzáadása
+pdfjs-editor-signature-button-label = Aláírás hozzáadása
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Kiemelésszerkesztő
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Rajzszerkesztő
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Aláírás-szerkesztő: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Képszerkesztő
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Rajz eltávolítása
+pdfjs-editor-remove-freetext-button =
+ .title = Szöveg eltávolítása
+pdfjs-editor-remove-stamp-button =
+ .title = Kép eltávolítása
+pdfjs-editor-remove-highlight-button =
+ .title = Kiemelés eltávolítása
+pdfjs-editor-remove-signature-button =
+ .title = Aláírás eltávolítása
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Szín
+pdfjs-editor-free-text-size-input = Méret
+pdfjs-editor-ink-color-input = Szín
+pdfjs-editor-ink-thickness-input = Vastagság
+pdfjs-editor-ink-opacity-input = Átlátszatlanság
+pdfjs-editor-stamp-add-image-button =
+ .title = Kép hozzáadása
+pdfjs-editor-stamp-add-image-button-label = Kép hozzáadása
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Vastagság
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Vastagság módosítása, ha nem szöveges elemeket emel ki
+pdfjs-editor-add-signature-container =
+ .aria-label = Aláírás-vezérlők és mentett aláírások
+pdfjs-editor-signature-add-signature-button =
+ .title = Új aláírás hozzáadása
+pdfjs-editor-signature-add-signature-button-label = Új aláírás hozzáadása
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Mentett aláírás: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Szövegszerkesztő
+ .default-content = Kezdjen gépelni…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Megjegyzés
+ *[other] Megjegyzések
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Oldalsáv bezárása
+ .aria-label = Oldalsáv bezárása
+pdfjs-editor-comments-sidebar-close-button-label = Oldalsáv bezárása
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Lát valami figyelemre méltót? Jelölje ki és írjon megjegyzést.
+pdfjs-editor-comments-sidebar-no-comments-link = További tudnivalók
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternatív szöveg
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternatív szöveg szerkesztése
+pdfjs-editor-alt-text-dialog-label = Válasszon egy lehetőséget
+pdfjs-editor-alt-text-dialog-description = Az alternatív szöveg segít, ha az emberek nem látják a képet, vagy ha az nem töltődik be.
+pdfjs-editor-alt-text-add-description-label = Leírás hozzáadása
+pdfjs-editor-alt-text-add-description-description = Törekedjen 1-2 mondatra, amely jellemzi a témát, környezetet vagy cselekvést.
+pdfjs-editor-alt-text-mark-decorative-label = Megjelölés dekoratívként
+pdfjs-editor-alt-text-mark-decorative-description = Ez a díszítőképeknél használatos, mint a szegélyek vagy a vízjelek.
+pdfjs-editor-alt-text-cancel-button = Mégse
+pdfjs-editor-alt-text-save-button = Mentés
+pdfjs-editor-alt-text-decorative-tooltip = Megjelölve dekoratívként
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Például: „Egy fiatal férfi leül enni egy asztalhoz”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternatív szöveg
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Bal felső sarok – átméretezés
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Felül középen – átméretezés
+pdfjs-editor-resizer-top-right =
+ .aria-label = Jobb felső sarok – átméretezés
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Jobbra középen – átméretezés
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Jobb alsó sarok – átméretezés
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Alul középen – átméretezés
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Bal alsó sarok – átméretezés
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Balra középen – átméretezés
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Kiemelés színe
+pdfjs-editor-colorpicker-button =
+ .title = Szín módosítása
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Színválasztások
+pdfjs-editor-colorpicker-yellow =
+ .title = Sárga
+pdfjs-editor-colorpicker-green =
+ .title = Zöld
+pdfjs-editor-colorpicker-blue =
+ .title = Kék
+pdfjs-editor-colorpicker-pink =
+ .title = Rózsaszín
+pdfjs-editor-colorpicker-red =
+ .title = Vörös
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Összes megjelenítése
+pdfjs-editor-highlight-show-all-button =
+ .title = Összes megjelenítése
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alternatív szöveg szerkesztése (képleírás)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alternatív szöveg hozzáadása (képleírás)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Írja ide a leírását…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Rövid leírás azoknak, akik nem látják a képet, vagy arra az esetre, ha a kép nem tölt be.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ez az alternatív szöveg automatikusan lett létrehozva, és pontatlan lehet.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = További tudnivalók
+pdfjs-editor-new-alt-text-create-automatically-button-label = Alternatív szöveg automatikus létrehozása
+pdfjs-editor-new-alt-text-not-now-button = Most nem
+pdfjs-editor-new-alt-text-error-title = Az alternatív szöveg automatikus létrehozása nem sikerült
+pdfjs-editor-new-alt-text-error-description = Írja meg a saját alternatív szövegét, vagy próbálja újra később.
+pdfjs-editor-new-alt-text-error-close-button = Bezárás
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Alternatív szöveg MI modell letöltése ({ $downloadedSize } / { $totalSize } MB)
+ .aria-valuetext = Alternatív szöveg MI modell letöltése ({ $downloadedSize } / { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternatív szöveg hozzáadva
+pdfjs-editor-new-alt-text-added-button-label = Alternatív szöveg hozzáadva
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Hiányzó alternatív szöveg
+pdfjs-editor-new-alt-text-missing-button-label = Hiányzó alternatív szöveg
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternatív szöveg áttekintése
+pdfjs-editor-new-alt-text-to-review-button-label = Alternatív szöveg szerkesztése
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automatikusan létrehozva: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Kép alternatív szövegének beállításai
+pdfjs-image-alt-text-settings-button-label = Kép alternatív szövegének beállításai
+pdfjs-editor-alt-text-settings-dialog-label = Kép alternatív szövegének beállításai
+pdfjs-editor-alt-text-settings-automatic-title = Automatikus alternatív szöveg
+pdfjs-editor-alt-text-settings-create-model-button-label = Alternatív szöveg automatikus létrehozása
+pdfjs-editor-alt-text-settings-create-model-description = Leírásokat javasol, hogy segítsen azoknak, akik nem látják a képet, vagy arra az esetre, ha a kép nem tölt be.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alternatív szöveg MI modellje ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Helyben fut az eszközén, így az adatai privátok maradnak. Az automatikus alternatív szövegekhez szükséges.
+pdfjs-editor-alt-text-settings-delete-model-button = Törlés
+pdfjs-editor-alt-text-settings-download-model-button = Letöltés
+pdfjs-editor-alt-text-settings-downloading-model-button = Letöltés…
+pdfjs-editor-alt-text-settings-editor-title = Alternatív szöveg szerkesztője
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Az alternatív szöveg szerkesztőjének azonnali megjelenítése egy kép hozzáadásakor
+pdfjs-editor-alt-text-settings-show-dialog-description = Segít elérni, hogy az összes képén legyen alternatív szöveg.
+pdfjs-editor-alt-text-settings-close-button = Bezárás
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Kiemelés hozzáadva
+pdfjs-editor-freetext-added-alert = Szöveg hozzáadva
+pdfjs-editor-ink-added-alert = Rajz hozzáadva
+pdfjs-editor-stamp-added-alert = Kép hozzáadva
+pdfjs-editor-signature-added-alert = Aláírás hozzáadva
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Kiemelés eltávolítva
+pdfjs-editor-undo-bar-message-freetext = Szöveg eltávolítva
+pdfjs-editor-undo-bar-message-ink = Rajz eltávolítva
+pdfjs-editor-undo-bar-message-stamp = Kép eltávolítva
+pdfjs-editor-undo-bar-message-signature = Aláírás eltávolítva
+pdfjs-editor-undo-bar-message-comment = Megjegyzés eltávolítva
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } kommentár eltávolítva
+ *[other] { $count } kommentár eltávolítva
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Visszavonás
+pdfjs-editor-undo-bar-undo-button-label = Visszavonás
+pdfjs-editor-undo-bar-close-button =
+ .title = Bezárás
+pdfjs-editor-undo-bar-close-button-label = Bezárás
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Ez a mód lehetővé teszi a felhasználónak, hogy aláírást hozzon létre, és ezt egy PDF dokumentumhoz adja. A felhasználó szerkesztheti a nevet (ez egyben alternatív szövegként is szolgál), és ismételt felhasználás céljából tetszés szerint mentheti az aláírást.
+pdfjs-editor-add-signature-dialog-title = Aláírás hozzáadása
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Beírás
+ .title = Beírás
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Rajzolás
+ .title = Rajzolás
+pdfjs-editor-add-signature-image-button = Kép
+ .title = Kép
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Írja be az aláírását
+ .placeholder = Írja be az aláírását
+pdfjs-editor-add-signature-draw-placeholder = Rajzolja le az aláírását
+pdfjs-editor-add-signature-draw-thickness-range-label = Vastagság
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Rajzolási vastagság: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Húzzon ide egy fájlt a feltöltéshez
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Vagy tallózzon a képfájlok között
+ *[other] Vagy tallózzon a képfájlok között
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Leírás (alternatív szöveg)
+pdfjs-editor-add-signature-description-input =
+ .title = Leírás (alternatív szöveg)
+pdfjs-editor-add-signature-description-default-when-drawing = Aláírás
+pdfjs-editor-add-signature-clear-button-label = Aláírás törlése
+pdfjs-editor-add-signature-clear-button =
+ .title = Aláírás törlése
+pdfjs-editor-add-signature-save-checkbox = Aláírás mentése
+pdfjs-editor-add-signature-save-warning-message = Elérte a mentett aláírások 5 darabos korlátját. A mentéshez távolítson el egyet.
+pdfjs-editor-add-signature-image-upload-error-title = A kép nem tölthető fel
+pdfjs-editor-add-signature-image-upload-error-description = Ellenőrizze a hálózati kapcsolatot, vagy próbálkozzon egy másik képpel.
+pdfjs-editor-add-signature-image-no-data-error-title = Ez a kép nem alakítható át aláírássá
+pdfjs-editor-add-signature-image-no-data-error-description = Próbáljon meg másik képet feltölteni.
+pdfjs-editor-add-signature-error-close-button = Bezárás
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Mégse
+pdfjs-editor-add-signature-add-button = Hozzáadás
+pdfjs-editor-edit-signature-update-button = Frissítés
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Megjegyzés szerkesztése
+pdfjs-editor-edit-comment-popup-button =
+ .title = Megjegyzés szerkesztése
+pdfjs-editor-delete-comment-popup-button-label = Megjegyzés eltávolítása
+pdfjs-editor-delete-comment-popup-button =
+ .title = Megjegyzés eltávolítása
+pdfjs-show-comment-button =
+ .title = Megjegyzés megjelenítése
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Megjegyzés szerkesztése
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Frissítés
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Megjegyzés hozzáadása
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Hozzáadás
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Kezdjen el gépelni…
+pdfjs-editor-edit-comment-dialog-cancel-button = Mégse
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Megjegyzés hozzáadása
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Oldalsáv be/ki (a dokumentum bélyegképeket/vázlatot/mellékleteket/rétegeket tartalmaz)
+pdfjs-toggle-views-manager-button1-label = Oldalak kezelése
+pdfjs-views-manager-sidebar =
+ .aria-label = Oldalsáv
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Oldalsáv-átméretező
+pdfjs-views-manager-view-selector-button =
+ .title = Nézetek
+pdfjs-views-manager-view-selector-button-label = Nézetek
+pdfjs-views-manager-pages-title = Oldalak
+pdfjs-views-manager-outlines-title1 = Dokumentumvázlat
+ .title = Dokumentumvázlat (dupla kattintás az összes elem kinyitásához/becsukásához)
+pdfjs-views-manager-attachments-title = Mellékletek
+pdfjs-views-manager-layers-title1 = Rétegek
+ .title = Rétegek (dupla kattintás az összes réteg eredeti állapotba való visszaállításához)
+pdfjs-views-manager-pages-option-label = Oldalak
+pdfjs-views-manager-outlines-option-label = Dokumentumvázlat
+pdfjs-views-manager-attachments-option-label = Mellékletek
+pdfjs-views-manager-layers-option-label = Rétegek
+pdfjs-views-manager-add-file-button =
+ .title = Fájl hozzáadása
+pdfjs-views-manager-add-file-button-label = Fájl hozzáadása
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } kiválasztva
+ *[other] { $count } kiválasztva
+ }
+pdfjs-views-manager-pages-status-none-action-label = Oldalak kiválasztása
+pdfjs-views-manager-pages-status-action-button-label = Kezelés
+pdfjs-views-manager-pages-status-copy-button-label = Másolás
+pdfjs-views-manager-pages-status-cut-button-label = Kivágás
+pdfjs-views-manager-pages-status-delete-button-label = Törlés
+pdfjs-views-manager-pages-status-export-selected-button-label = Kiválasztottak exportálása…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 oldal kivágva
+ *[other] { $count } oldal kivágva
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 oldal másolva
+ *[other] { $count } oldal másolva
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 oldal törölve
+ *[other] { $count } oldal törölve
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = A fájl előkészítése…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Fájl feltöltése…
+pdfjs-views-manager-status-warning-cut-label = Nem sikerült kivágni. Frissítse az oldalt, és próbálja újra.
+pdfjs-views-manager-status-warning-copy-label = Nem sikerült másolni. Frissítse az oldalt, és próbálja újra.
+pdfjs-views-manager-status-warning-delete-label = Nem sikerült törölni. Frissítse az oldalt, és próbálja újra.
+pdfjs-views-manager-status-warning-save-label = Nem sikerült menteni. Frissítse az oldalt, és próbálja újra.
+pdfjs-views-manager-status-undo-button-label = Visszavonás
+pdfjs-views-manager-status-done-button-label = Kész
+pdfjs-views-manager-status-close-button =
+ .title = Bezárás
+pdfjs-views-manager-status-close-button-label = Bezárás
+pdfjs-views-manager-paste-button-label = Beillesztés
+pdfjs-views-manager-paste-button-before =
+ .title = Beillesztés az első oldal elé
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Beillesztés a(z) { $page }. oldal után
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = ÚJ
+pdfjs-views-manager-waiting-for-file = Fájl feltöltése…
+pdfjs-toggle-views-manager-button1 =
+ .title = Oldalak kezelése
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Digitális aláírás tulajdonságai
+ .aria-label = Digitális aláírás tulajdonságai
+pdfjs-digital-signature-properties-button-label = Digitális aláírás tulajdonságai
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = A dokumentum érvényes digitális aláírással lett aláírva
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] A dokumentum alá van írva, de { $count } digitális aláírás nem ellenőrizhető
+ *[other] A dokumentum alá van írva, de { $count } digitális aláírás nem ellenőrizhető
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] A dokumentum { $count } nem megbízható tanúsítvánnyal van aláírva
+ *[other] A dokumentum { $count } nem megbízható tanúsítvánnyal van aláírva
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] A dokumentum { $count } lejárt tanúsítvánnyal van aláírva
+ *[other] A dokumentum { $count } lejárt tanúsítvánnyal van aláírva
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] A dokumentum { $count } érvénytelen aláírással rendelkezik
+ *[other] A dokumentum { $count } érvénytelen aláírással rendelkezik
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] A dokumentum { $count } visszavont tanúsítvánnyal van aláírva
+ *[other] A dokumentum { $count } visszavont tanúsítvánnyal van aláírva
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Állapot: az aláírás ellenőrizve
+pdfjs-digital-signature-properties-status-invalid = Állapot: az aláírás érvénytelen
+pdfjs-digital-signature-properties-status-unknown = Állapot: nem ellenőrizhető (nem támogatott)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Tanúsítvány: megbízható ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Tanúsítvány: nem érhető el
+pdfjs-digital-signature-properties-certificate-untrusted = Tanúsítvány: nem megbízható
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Tanúsítvány: ismeretlen kibocsátó ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Tanúsítvány: önaláírt ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Tanúsítvány: nem megbízható kibocsátó ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Tanúsítvány: lejárt
+pdfjs-digital-signature-properties-certificate-expired-with-date = Tanúsítvány: lejárt ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Tanúsítvány: visszavonva
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Mentett aláírás eltávolítása
+pdfjs-editor-delete-signature-button-label1 = Mentett aláírás eltávolítása
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Leírás szerkesztése
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Leírás szerkesztése
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hy-AM/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hy-AM/viewer.ftl
new file mode 100644
index 0000000..349374c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hy-AM/viewer.ftl
@@ -0,0 +1,646 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Նախորդ էջը
+pdfjs-previous-button-label = Նախորդը
+pdfjs-next-button =
+ .title = Հաջորդ էջը
+pdfjs-next-button-label = Հաջորդը
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Էջ.
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = -ը՝ { $pagesCount }-ից
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber }-ը { $pagesCount })-ից
+pdfjs-zoom-out-button =
+ .title = Փոքրացնել
+pdfjs-zoom-out-button-label = Փոքրացնել
+pdfjs-zoom-in-button =
+ .title = Խոշորացնել
+pdfjs-zoom-in-button-label = Խոշորացնել
+pdfjs-zoom-select =
+ .title = Դիտափոխում
+pdfjs-presentation-mode-button =
+ .title = Անցնել Ներկայացման եղանակին
+pdfjs-presentation-mode-button-label = Ներկայացման եղանակ
+pdfjs-open-file-button =
+ .title = Բացել ֆայլ
+pdfjs-open-file-button-label = Բացել
+pdfjs-print-button =
+ .title = Տպել
+pdfjs-print-button-label = Տպել
+pdfjs-save-button =
+ .title = Պահել
+pdfjs-save-button-label = Պահել
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Ներբեռնել
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Ներբեռնել
+pdfjs-bookmark-button =
+ .title = Ընթացիկ էջ (Դիտել URL-ը ընթացիկ էջից)
+pdfjs-bookmark-button-label = Ընթացիկ էջ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Գործիքներ
+pdfjs-tools-button-label = Գործիքներ
+pdfjs-first-page-button =
+ .title = Անցնել առաջին էջին
+pdfjs-first-page-button-label = Անցնել առաջին էջին
+pdfjs-last-page-button =
+ .title = Անցնել վերջին էջին
+pdfjs-last-page-button-label = Անցնել վերջին էջին
+pdfjs-page-rotate-cw-button =
+ .title = Պտտել ըստ ժամացույցի սլաքի
+pdfjs-page-rotate-cw-button-label = Պտտել ըստ ժամացույցի սլաքի
+pdfjs-page-rotate-ccw-button =
+ .title = Պտտել հակառակ ժամացույցի սլաքի
+pdfjs-page-rotate-ccw-button-label = Պտտել հակառակ ժամացույցի սլաքի
+pdfjs-cursor-text-select-tool-button =
+ .title = Միացնել գրույթ ընտրելու գործիքը
+pdfjs-cursor-text-select-tool-button-label = Գրույթը ընտրելու գործիք
+pdfjs-cursor-hand-tool-button =
+ .title = Միացնել Ձեռքի գործիքը
+pdfjs-cursor-hand-tool-button-label = Ձեռքի գործիք
+pdfjs-scroll-page-button =
+ .title = Օգտագործեք էջի գլորումը
+pdfjs-scroll-page-button-label = Էջի գլորում
+pdfjs-scroll-vertical-button =
+ .title = Օգտագործել ուղղահայաց ոլորում
+pdfjs-scroll-vertical-button-label = Ուղղահայաց ոլորում
+pdfjs-scroll-horizontal-button =
+ .title = Օգտագործել հորիզոնական ոլորում
+pdfjs-scroll-horizontal-button-label = Հորիզոնական ոլորում
+pdfjs-scroll-wrapped-button =
+ .title = Օգտագործել փաթաթված ոլորում
+pdfjs-scroll-wrapped-button-label = Փաթաթված ոլորում
+pdfjs-spread-none-button =
+ .title = Մի միացեք էջի վերածածկերին
+pdfjs-spread-none-button-label = Չկա վերածածկեր
+pdfjs-spread-odd-button =
+ .title = Միացեք էջի վերածածկերին սկսելով՝ կենտ համարակալված էջերով
+pdfjs-spread-odd-button-label = Կենտ վերածածկեր
+pdfjs-spread-even-button =
+ .title = Միացեք էջի վերածածկերին սկսելով՝ զույգ համարակալված էջերով
+pdfjs-spread-even-button-label = Զույգ վերածածկեր
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Փաստաթղթի հատկությունները…
+pdfjs-document-properties-button-label = Փաստաթղթի հատկությունները…
+pdfjs-document-properties-file-name = Ֆայլի անունը.
+pdfjs-document-properties-file-size = Ֆայլի չափը.
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } ԿԲ ({ $b } բայթ)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } ՄԲ ({ $b } բայթ)
+pdfjs-document-properties-title = Վերնագիր.
+pdfjs-document-properties-author = Հեղինակ․
+pdfjs-document-properties-subject = Վերնագիր.
+pdfjs-document-properties-keywords = Հիմնաբառ.
+pdfjs-document-properties-creation-date = Ստեղծելու ամսաթիվը.
+pdfjs-document-properties-modification-date = Փոփոխելու ամսաթիվը.
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Ստեղծող.
+pdfjs-document-properties-producer = PDF-ի հեղինակը.
+pdfjs-document-properties-version = PDF-ի տարբերակը.
+pdfjs-document-properties-page-count = Էջերի քանակը.
+pdfjs-document-properties-page-size = Էջի չափը.
+pdfjs-document-properties-page-size-unit-inches = ում
+pdfjs-document-properties-page-size-unit-millimeters = մմ
+pdfjs-document-properties-page-size-orientation-portrait = ուղղաձիգ
+pdfjs-document-properties-page-size-orientation-landscape = հորիզոնական
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Նամակ
+pdfjs-document-properties-page-size-name-legal = Օրինական
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Արագ վեբ դիտում․
+pdfjs-document-properties-linearized-yes = Այո
+pdfjs-document-properties-linearized-no = Ոչ
+pdfjs-document-properties-close-button = Փակել
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Պատճառը՝ { $reason }
+
+## Print
+
+pdfjs-print-progress-message = Նախապատրաստում է փաստաթուղթը տպելուն...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Չեղարկել
+pdfjs-printing-not-supported = Զգուշացում. Տպելը ամբողջությամբ չի աջակցվում դիտարկիչի կողմից։
+pdfjs-printing-not-ready = Զգուշացում. PDF-ը ամբողջությամբ չի բեռնավորվել տպելու համար:
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Բացել/Փակել կողագոտին
+pdfjs-toggle-sidebar-notification-button =
+ .title = Փոխարկել Կողագոտին (փաստաթուղթը պարունակում է ուրվագիծ/կցորդներ)
+pdfjs-toggle-sidebar-button-label = Բացել/Փակել կողագոտին
+pdfjs-document-outline-button =
+ .title = Ցուցադրել փաստաթղթի ուրվագիծը (կրկնակի սեղմեք՝ միավորները ընդարձակելու/կոծկելու համար)
+pdfjs-document-outline-button-label = Փաստաթղթի բովանդակությունը
+pdfjs-attachments-button =
+ .title = Ցուցադրել կցորդները
+pdfjs-attachments-button-label = Կցորդներ
+pdfjs-layers-button =
+ .title = Ցուցադրել շերտերը (կրկնակի սեղմեք բոլոր շերտերը սկզբնական վիճակին վերականգնելու համար)
+pdfjs-layers-button-label = Շերտեր
+pdfjs-thumbs-button =
+ .title = Ցուցադրել մանրապատկերը
+pdfjs-thumbs-button-label = Մանրապատկերը
+pdfjs-current-outline-item-button =
+ .title = Գտեք ընթացիկ ուրվագծային տարրը
+pdfjs-current-outline-item-button-label = Ընթացիկ ուրվագծային տարր
+pdfjs-findbar-button =
+ .title = Գտնել փաստաթղթում
+pdfjs-findbar-button-label = Որոնում
+pdfjs-additional-layers = Լրացուցիչ շերտեր
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Էջը { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Էջի մանրապատկերը { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Որոնում
+ .placeholder = Գտնել փաստաթղթում...
+pdfjs-find-previous-button =
+ .title = Գտնել անրահայտության նախորդ հանդիպումը
+pdfjs-find-previous-button-label = Նախորդը
+pdfjs-find-next-button =
+ .title = Գտիր արտահայտության հաջորդ հանդիպումը
+pdfjs-find-next-button-label = Հաջորդը
+pdfjs-find-highlight-checkbox = Գունանշել բոլորը
+pdfjs-find-match-case-checkbox-label = Հաշվի առնել մեծ/փոքրատառը
+pdfjs-find-match-diacritics-checkbox-label = Համընկել հնչյունատարբերիչ նշանները
+pdfjs-find-entire-word-checkbox-label = Ամբողջ բառերը
+pdfjs-find-reached-top = Հասել եք փաստաթղթի վերևին, կշարունակվի ներքևից
+pdfjs-find-reached-bottom = Հասել եք փաստաթղթի վերջին, կշարունակվի վերևից
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current }՝ { $total } համընկնումից
+ *[other] { $current } of { $total } համընկնումներից
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Ավելի քան { $limit } համընկնում
+ *[other] Ավելի քան { $limit } համընկնումներ
+ }
+pdfjs-find-not-found = Արտահայտությունը չգտնվեց
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Էջի լայնքը
+pdfjs-page-scale-fit = Ձգել էջը
+pdfjs-page-scale-auto = Ինքնաշխատ
+pdfjs-page-scale-actual = Իրական չափը
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Էջ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Սխալ՝ PDF ֆայլը բացելիս։
+pdfjs-invalid-file-error = Սխալ կամ վնասված PDF ֆայլ:
+pdfjs-missing-file-error = PDF ֆայլը բացակայում է:
+pdfjs-unexpected-response-error = Սպասարկիչի անսպասելի պատասխան:
+pdfjs-rendering-error = Սխալ՝ էջը ստեղծելիս:
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Ծանոթություն]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Մուտքագրեք PDF-ի գաղտնաբառը:
+pdfjs-password-invalid = Գաղտնաբառը սխալ է: Կրկին փորձեք:
+pdfjs-password-ok-button = Լավ
+pdfjs-password-cancel-button = Չեղարկել
+pdfjs-web-fonts-disabled = Վեբ-տառատեսակները անջատված են. հնարավոր չէ օգտագործել ներկառուցված PDF տառատեսակները:
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Գրվածք
+pdfjs-editor-color-picker-free-text-input =
+ .title = Փոխել տեքստի գույնը
+pdfjs-editor-free-text-button-label = Գրվածք
+pdfjs-editor-ink-button =
+ .title = Նկարել
+pdfjs-editor-color-picker-ink-input =
+ .title = Փոխել նկարելու գույնը
+pdfjs-editor-ink-button-label = Նկարել
+pdfjs-editor-stamp-button =
+ .title = Հավելել կամ խմբագրել պատկերներ
+pdfjs-editor-stamp-button-label = Հավելել կամ խմբագրել պատկերներ
+pdfjs-editor-highlight-button =
+ .title = Գունանշում
+pdfjs-editor-highlight-button-label = Գունանշում
+pdfjs-highlight-floating-button1 =
+ .title = Գունանշում
+ .aria-label = Գունանշում
+pdfjs-highlight-floating-button-label = Գունանշում
+pdfjs-comment-floating-button =
+ .title = Մեկնաբանություն
+ .aria-label = Մեկնաբանություն
+pdfjs-comment-floating-button-label = Մեկնաբանություն
+pdfjs-editor-signature-button =
+ .title = Ավելացնել ստորագրություն
+pdfjs-editor-signature-button-label = Ավելացնել ստորագրություն
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Գունանշել խմբագիրը
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Նկարելու խմբագիր
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Ստորագրության խմբագիր՝ { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Պատկերի խմբագիր
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Հեռացնել նկարումը
+pdfjs-editor-remove-freetext-button =
+ .title = Հեռացնել գրվածքը
+pdfjs-editor-remove-stamp-button =
+ .title = Հեռացնել պատկերը
+pdfjs-editor-remove-highlight-button =
+ .title = Հեռացնել գունանշումը
+pdfjs-editor-remove-signature-button =
+ .title = Հեռացնել ստորագրությունը
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Գույն
+pdfjs-editor-free-text-size-input = Չափ
+pdfjs-editor-ink-color-input = Գույն
+pdfjs-editor-ink-thickness-input = Հաստություն
+pdfjs-editor-ink-opacity-input = Մգություն
+pdfjs-editor-stamp-add-image-button =
+ .title = Հավելել պատկեր
+pdfjs-editor-stamp-add-image-button-label = Հավելել պատկեր
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Հաստություն
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Փոխել հաստությունը՝ տեքստից բացի այլ տարրեր գունանշելիս
+pdfjs-editor-add-signature-container =
+ .aria-label = Ստորագրության կառավարման տարրեր և պահված ստորագրություններ
+pdfjs-editor-signature-add-signature-button =
+ .title = Ավելացնել նոր ստորագրություն
+pdfjs-editor-signature-add-signature-button-label = Ավելացնել նոր ստորագրություն
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Պահված ստորագրություն՝ { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Գրվածքի խմբագիր
+ .default-content = Սկսեք մուտքագրել...
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Մեկնաբանություն
+ *[other] Մեկնաբանություններ
+ }
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Տեսնո՞ւմ եք ինչ-որ ուշագրավ բան։ Գունանշեք այն և թողեք մեկնաբանություն։
+pdfjs-editor-comments-sidebar-no-comments-link = Իմանալ ավելին
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Այլընտրանքային գրվածք
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Խմբագրել այլընտրանքային գրվածքը
+pdfjs-editor-alt-text-dialog-label = Ընտրեք տառատեսակը
+pdfjs-editor-alt-text-dialog-description = Այլընտրանքային տեքստը (alternative text) օգնում է, երբ մարդիկ չեն կարողանում տեսնել պատկերը կամ երբ այն չի բեռնվում։
+pdfjs-editor-alt-text-add-description-label = Հավելել նկարագրություն
+pdfjs-editor-alt-text-add-description-description = Ձգտեք գրել 1-2 նախադասություն, որոնք նկարագրում են թեման, միջավայրը կամ գործողությունները։
+pdfjs-editor-alt-text-mark-decorative-label = Նշել որպես դեկորատիվ
+pdfjs-editor-alt-text-mark-decorative-description = Սա օգտագործվում է դեկորատիվ պատկերների համար, ինչպիսիք են եզրագծերը կամ ջրանիշերը։
+pdfjs-editor-alt-text-cancel-button = Չեղարկել
+pdfjs-editor-alt-text-save-button = Պահել
+pdfjs-editor-alt-text-decorative-tooltip = Նշել որպես դեկորատիվ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Օրինակ՝ «Մի երիտասարդ նստում է սեղանի շուրջ՝ ուտելու»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Այլընտրանքային գրվածք
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Վերին ձախ անկյուն՝ չափափոխել
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Վերևի մեջտեղում՝ չափափոխել
+pdfjs-editor-resizer-top-right =
+ .aria-label = Վերին ձախ անկյուն՝ չափափոխել
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Մեջտեղի աջ կողմում՝ չափափոխել
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Վերին ձախ անկյուն՝ չափափոխել
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Վերևի մեջտեղում՝ չափափոխել
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Վերին ձախ անկյուն՝ չափափոխել
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Մեջտեղի ձախ կողմում՝ չափափոխել
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Գունանշման գույն
+pdfjs-editor-colorpicker-button =
+ .title = Փոխել գույնը
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Գույների ընտրություն
+pdfjs-editor-colorpicker-yellow =
+ .title = Դեղին
+pdfjs-editor-colorpicker-green =
+ .title = Կանաչ
+pdfjs-editor-colorpicker-blue =
+ .title = Կապույտ
+pdfjs-editor-colorpicker-pink =
+ .title = Վարդագույն
+pdfjs-editor-colorpicker-red =
+ .title = Կարմիր
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Ցուցադրել բոլորը
+pdfjs-editor-highlight-show-all-button =
+ .title = Ցուցադրել բոլորը
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Խմբագրել այլընտրանքային տեքստը (պատկերի նկարագրությունը)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Ավելացնել այլընտրանքային գրվածք (պատկերի նկարագրություն)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Գրեք ձեր նկարագրությունն այստեղ…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Կարճ նկարագրություն նրանց համար, ովքեր չեն կարող տեսնել պատկերը կամ երբ պատկերը չի բեռնվում։
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Այս այլընտրանքային տեքստը ստեղծվել է ինքնաշխատ և կարող է սխալ լինել։
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Իմանալ ավելին
+pdfjs-editor-new-alt-text-create-automatically-button-label = Ինքնաշխատ ստեղծել այլընտրանքային գրվածք
+pdfjs-editor-new-alt-text-not-now-button = Ոչ հիմա
+pdfjs-editor-new-alt-text-error-title = Հնարավոր չէ ինքնաշխատ ստեղծել այլընտրանքային գրվածք
+pdfjs-editor-new-alt-text-error-description = Խնդրում ենք գրել ձեր սեփական այլընտրանքային տեքստը կամ փորձել կրկին ավելի ուշ։
+pdfjs-editor-new-alt-text-error-close-button = Փակել
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Ներբեռնվում է այլընտրանքային գրվածքի ահեստական բանականության մոդելը ({ $downloadedSize }՝ { $totalSize } ՄԲ-ից)
+ .aria-valuetext = Ներբեռնվում է այլընտրանքային գրվածքի ահեստական բանականության մոդելը ({ $downloadedSize }՝ { $totalSize } ՄԲ-ից)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Այլընտրանքային գրվածքն ավելացված է
+pdfjs-editor-new-alt-text-added-button-label = Այլընտրանքային գրվածքն ավելացված է
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Այլընտրանքային գրվածքը բացակայում է
+pdfjs-editor-new-alt-text-missing-button-label = Այլընտրանքային գրվածքը բացակայում է
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Վերանայել այլընտրանքային գրվածքը
+pdfjs-editor-new-alt-text-to-review-button-label = Վերանայել այլընտրանքային գրվածքը
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Ստեղծվել է ինքնաշխատվ՝ { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Պատկերի այլընտրանքային գրվածքի կարգավորումներ
+pdfjs-image-alt-text-settings-button-label = Պատկերի այլընտրանքային գրվածքի կարգավորումներ
+pdfjs-editor-alt-text-settings-dialog-label = Պատկերի այլընտրանքային գրվածքի կարգավորումներ
+pdfjs-editor-alt-text-settings-automatic-title = Ինքնաշխատ այլընտրանքային գրվածք
+pdfjs-editor-alt-text-settings-create-model-button-label = Ինքնաշխատ ստեղծել այլընտրանքային գրվածք
+pdfjs-editor-alt-text-settings-create-model-description = Կարճ նկարագրություն նրանց համար, ովքեր չեն կարող տեսնել պատկերը կամ երբ պատկերը չի բեռնվում։
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Այլընտրանքային գրվածքի արհեստական բանականության մոդել ({ $totalSize } ՄԲ)
+pdfjs-editor-alt-text-settings-ai-model-description = Աշխատում է տեղայնորեն ձեր սարքի վրա, որպեսզի ձեր տվյալները մնան գաղտնի: Պահանջվում է ինքնաշխատ այլընտրանքային գրվածքի համար:
+pdfjs-editor-alt-text-settings-delete-model-button = Ջնջել
+pdfjs-editor-alt-text-settings-download-model-button = Ներբեռնել
+pdfjs-editor-alt-text-settings-downloading-model-button = Ներբեռնվում է…
+pdfjs-editor-alt-text-settings-editor-title = Այլընտրանքային գրվածքի խմբագիր
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Պատկեր ավելացնելիս անմիջապես ցուցադրել այլընտրանքային գրվածքի խմբագիրը
+pdfjs-editor-alt-text-settings-show-dialog-description = Օգնում է համոզվել, որ ձեր բոլոր պատկերներն ունեն այլընտրանքային գրվածք։
+pdfjs-editor-alt-text-settings-close-button = Փակել
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Գունանշումը ավելացվել է
+pdfjs-editor-freetext-added-alert = Գրվածքը ավելացվել է
+pdfjs-editor-ink-added-alert = Նկարումը ավելացվել է
+pdfjs-editor-stamp-added-alert = Պատկերն ավելացված է
+pdfjs-editor-signature-added-alert = Ստորագրությունն ավելացված է
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Գունանշումը հեռացված է
+pdfjs-editor-undo-bar-message-freetext = Գրվածքը հեռացվել է
+pdfjs-editor-undo-bar-message-ink = Նկարվածը հեռացվել է
+pdfjs-editor-undo-bar-message-stamp = Պատկերը հեռացվել է
+pdfjs-editor-undo-bar-message-signature = Ստորագրությունը հեռացված է
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } մեկնաբանությունը հեռացվել է
+ *[other] { $count } մեկնաբանությունները հեռացվել են
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Հետարկել
+pdfjs-editor-undo-bar-undo-button-label = Հետարկել
+pdfjs-editor-undo-bar-close-button =
+ .title = Փակել
+pdfjs-editor-undo-bar-close-button-label = Փակել
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Այս յուրահատկությունը հնարավորություն է տալիս օգտվողին ստեղծել ստորագրություն՝ PDF փաստաթղթում ավելացնելու համար: Օգտվողը կարող է խմբագրել անունը (որը նաև ծառայում է որպես alt տեքստ) և լրացուցիչ պահել այն՝ հետագա օգտագործման համար:
+pdfjs-editor-add-signature-dialog-title = Ավելացնել ստորագրություն
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Տեսակ
+ .title = Տեսակ
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Նկարել
+ .title = Նկարել
+pdfjs-editor-add-signature-image-button = Պատկեր
+ .title = Պատկեր
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Մուտքագրել ստորագրություն
+ .placeholder = Մուտքագրել ստորագրություն
+pdfjs-editor-add-signature-draw-placeholder = Նկարեք ձեր ստորագրությունը
+pdfjs-editor-add-signature-draw-thickness-range-label = Հաստություն
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Նկարելու հաստությունը՝ { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Քաշեք ֆայլը այստեղ՝ վերբեռնելու համար
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Կամ ընտրեք պատկերի ֆայլը
+ *[other] Կամ ընտրեք պատկերի ֆայլերը
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Նկարագրություն (այլընտրանքային գրվածք)
+pdfjs-editor-add-signature-description-input =
+ .title = Նկարագրություն (այլընտրանքային գրվածք)
+pdfjs-editor-add-signature-description-default-when-drawing = Ստորագրություն
+pdfjs-editor-add-signature-clear-button-label = Մաքրել ստորագրությունը
+pdfjs-editor-add-signature-clear-button =
+ .title = Մաքրել ստորագրությունը
+pdfjs-editor-add-signature-save-checkbox = Պահել ստորագրությունը
+pdfjs-editor-add-signature-save-warning-message = Դուք հասել եք պահպանված ստորագրությունների 5 սահմանաչափին։ Հեռացրեք մեկը՝ ավելին պահելու համար։
+pdfjs-editor-add-signature-image-upload-error-title = Չհաջողվեց վերբեռնել պատկերը
+pdfjs-editor-add-signature-image-upload-error-description = Ստուգեք ձեր ցանցային կապակցումը կամ փորձեք մեկ այլ պատկեր։
+pdfjs-editor-add-signature-image-no-data-error-title = Այս պատկերը հնարավոր չէ վերածել ստորագրության
+pdfjs-editor-add-signature-image-no-data-error-description = Խնդրում եմ փորձեք վերբեռնել այլ պատկեր։
+pdfjs-editor-add-signature-error-close-button = Փակել
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Չեղարկել
+pdfjs-editor-add-signature-add-button = Ավելացնել
+pdfjs-editor-edit-signature-update-button = Թարմացնել
+
+## Edit a comment dialog
+
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Ավելացնել մեկնաբանություն
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Ավելացնել
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Մուտքագրեք այստեղ…
+pdfjs-editor-edit-comment-dialog-cancel-button = Չեղարկել
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Ավելացնել մեկնաբանություն
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-views-manager-add-file-button =
+ .title = Ավելացնել ֆայլ
+pdfjs-views-manager-add-file-button-label = Ավելացնել ֆայլ
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Հեռացնել պահված ստորագրությունը
+pdfjs-editor-delete-signature-button-label1 = Հեռացնել պահված ստորագրությունը
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Խմբագրել նկարագրությունը
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Խմբագրել նկարագրությունը
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hye/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hye/viewer.ftl
new file mode 100644
index 0000000..4625bfe
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/hye/viewer.ftl
@@ -0,0 +1,242 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Նախորդ էջ
+pdfjs-previous-button-label = Նախորդը
+pdfjs-next-button =
+ .title = Յաջորդ էջ
+pdfjs-next-button-label = Յաջորդը
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = էջ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount }-ից
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber }-ը { $pagesCount })-ից
+pdfjs-zoom-out-button =
+ .title = Փոքրացնել
+pdfjs-zoom-out-button-label = Փոքրացնել
+pdfjs-zoom-in-button =
+ .title = Խոշորացնել
+pdfjs-zoom-in-button-label = Խոշորացնել
+pdfjs-zoom-select =
+ .title = Խոշորացում
+pdfjs-presentation-mode-button =
+ .title = Անցնել ներկայացման եղանակին
+pdfjs-presentation-mode-button-label = Ներկայացման եղանակ
+pdfjs-open-file-button =
+ .title = Բացել նիշքը
+pdfjs-open-file-button-label = Բացել
+pdfjs-print-button =
+ .title = Տպել
+pdfjs-print-button-label = Տպել
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Գործիքներ
+pdfjs-tools-button-label = Գործիքներ
+pdfjs-first-page-button =
+ .title = Գնալ դէպի առաջին էջ
+pdfjs-first-page-button-label = Գնալ դէպի առաջին էջ
+pdfjs-last-page-button =
+ .title = Գնալ դէպի վերջին էջ
+pdfjs-last-page-button-label = Գնալ դէպի վերջին էջ
+pdfjs-page-rotate-cw-button =
+ .title = Պտտել ժամացոյցի սլաքի ուղղութեամբ
+pdfjs-page-rotate-cw-button-label = Պտտել ժամացոյցի սլաքի ուղղութեամբ
+pdfjs-page-rotate-ccw-button =
+ .title = Պտտել ժամացոյցի սլաքի հակառակ ուղղութեամբ
+pdfjs-page-rotate-ccw-button-label = Պտտել ժամացոյցի սլաքի հակառակ ուղղութեամբ
+pdfjs-cursor-text-select-tool-button =
+ .title = Միացնել գրոյթ ընտրելու գործիքը
+pdfjs-cursor-text-select-tool-button-label = Գրուածք ընտրելու գործիք
+pdfjs-cursor-hand-tool-button =
+ .title = Միացնել ձեռքի գործիքը
+pdfjs-cursor-hand-tool-button-label = Ձեռքի գործիք
+pdfjs-scroll-page-button =
+ .title = Աւգտագործել էջի ոլորում
+pdfjs-scroll-page-button-label = Էջի ոլորում
+pdfjs-scroll-vertical-button =
+ .title = Աւգտագործել ուղղահայեաց ոլորում
+pdfjs-scroll-vertical-button-label = Ուղղահայեաց ոլորում
+pdfjs-scroll-horizontal-button =
+ .title = Աւգտագործել հորիզոնական ոլորում
+pdfjs-scroll-horizontal-button-label = Հորիզոնական ոլորում
+pdfjs-scroll-wrapped-button =
+ .title = Աւգտագործել փաթաթուած ոլորում
+pdfjs-scroll-wrapped-button-label = Փաթաթուած ոլորում
+pdfjs-spread-none-button =
+ .title = Մի միացէք էջի կոնտեքստում
+pdfjs-spread-none-button-label = Չկայ կոնտեքստ
+pdfjs-spread-odd-button =
+ .title = Միացէք էջի կոնտեքստին սկսելով՝ կենտ համարակալուած էջերով
+pdfjs-spread-odd-button-label = Տարաւրինակ կոնտեքստ
+pdfjs-spread-even-button =
+ .title = Միացէք էջի կոնտեքստին սկսելով՝ զոյգ համարակալուած էջերով
+pdfjs-spread-even-button-label = Հաւասար վերածածկեր
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Փաստաթղթի հատկութիւնները…
+pdfjs-document-properties-button-label = Փաստաթղթի յատկութիւնները…
+pdfjs-document-properties-file-name = Նիշքի անունը․
+pdfjs-document-properties-file-size = Նիշք չափը.
+pdfjs-document-properties-title = Վերնագիր
+pdfjs-document-properties-author = Հեղինակ․
+pdfjs-document-properties-subject = առարկայ
+pdfjs-document-properties-keywords = Հիմնաբառեր
+pdfjs-document-properties-creation-date = Ստեղծման ամսաթիւ
+pdfjs-document-properties-modification-date = Փոփոխութեան ամսաթիւ.
+pdfjs-document-properties-creator = Ստեղծող
+pdfjs-document-properties-producer = PDF-ի Արտադրողը.
+pdfjs-document-properties-version = PDF-ի տարբերակը.
+pdfjs-document-properties-page-count = Էջերի քանակը.
+pdfjs-document-properties-page-size = Էջի չափը.
+pdfjs-document-properties-page-size-unit-inches = ում
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = ուղղաձիգ
+pdfjs-document-properties-page-size-orientation-landscape = հորիզոնական
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Նամակ
+pdfjs-document-properties-page-size-name-legal = Աւրինական
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Արագ վեբ դիտում․
+pdfjs-document-properties-linearized-yes = Այո
+pdfjs-document-properties-linearized-no = Ոչ
+pdfjs-document-properties-close-button = Փակել
+
+## Print
+
+pdfjs-print-progress-message = Նախապատրաստում է փաստաթուղթը տպելուն…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Չեղարկել
+pdfjs-printing-not-supported = Զգուշացում. Տպելը ամբողջութեամբ չի աջակցուում զննարկիչի կողմից։
+pdfjs-printing-not-ready = Զգուշացում. PDF֊ը ամբողջութեամբ չի բեռնաւորուել տպելու համար։
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Փոխարկել կողային վահանակը
+pdfjs-toggle-sidebar-notification-button =
+ .title = Փոխանջատել կողմնասիւնը (փաստաթուղթը պարունակում է ուրուագիծ/կցորդներ/շերտեր)
+pdfjs-toggle-sidebar-button-label = Փոխարկել կողային վահանակը
+pdfjs-document-outline-button =
+ .title = Ցուցադրել փաստաթղթի ուրուագիծը (կրկնակի սեղմէք՝ միաւորները ընդարձակելու/կոծկելու համար)
+pdfjs-document-outline-button-label = Փաստաթղթի ուրուագիծ
+pdfjs-attachments-button =
+ .title = Ցուցադրել կցորդները
+pdfjs-attachments-button-label = Կցորդներ
+pdfjs-layers-button =
+ .title = Ցուցադրել շերտերը (կրկնահպել վերակայելու բոլոր շերտերը սկզբնադիր վիճակի)
+pdfjs-layers-button-label = Շերտեր
+pdfjs-thumbs-button =
+ .title = Ցուցադրել մանրապատկերը
+pdfjs-thumbs-button-label = Մանրապատկեր
+pdfjs-current-outline-item-button =
+ .title = Գտէք ընթացիկ գծագրման տարրը
+pdfjs-current-outline-item-button-label = Ընթացիկ գծագրման տարր
+pdfjs-findbar-button =
+ .title = Գտնել փաստաթղթում
+pdfjs-findbar-button-label = Որոնում
+pdfjs-additional-layers = Լրացուցիչ շերտեր
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Էջը { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Էջի մանրապատկերը { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Որոնում
+ .placeholder = Գտնել փաստաթղթում…
+pdfjs-find-previous-button =
+ .title = Գտնել արտայայտութեան նախորդ արտայայտութիւնը
+pdfjs-find-previous-button-label = Նախորդը
+pdfjs-find-next-button =
+ .title = Գտիր արտայայտութեան յաջորդ արտայայտութիւնը
+pdfjs-find-next-button-label = Հաջորդը
+pdfjs-find-highlight-checkbox = Գունանշել բոլորը
+pdfjs-find-match-case-checkbox-label = Հաշուի առնել հանգամանքը
+pdfjs-find-match-diacritics-checkbox-label = Հնչիւնատարբերիչ նշանների համապատասխանեցում
+pdfjs-find-entire-word-checkbox-label = Ամբողջ բառերը
+pdfjs-find-reached-top = Հասել եք փաստաթղթի վերեւին,շարունակել ներքեւից
+pdfjs-find-reached-bottom = Հասել էք փաստաթղթի վերջին, շարունակել վերեւից
+pdfjs-find-not-found = Արտայայտութիւնը չգտնուեց
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Էջի լայնութիւն
+pdfjs-page-scale-fit = Հարմարեցնել էջը
+pdfjs-page-scale-auto = Ինքնաշխատ խոշորացում
+pdfjs-page-scale-actual = Իրական չափը
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Էջ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF նիշքը բացելիս սխալ է տեղի ունեցել։
+pdfjs-invalid-file-error = Սխալ կամ վնասուած PDF նիշք։
+pdfjs-missing-file-error = PDF նիշքը բացակաիւմ է։
+pdfjs-unexpected-response-error = Սպասարկիչի անսպասելի պատասխան։
+pdfjs-rendering-error = Սխալ է տեղի ունեցել էջի մեկնաբանման ժամանակ
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Ծանոթութիւն]
+
+## Password
+
+pdfjs-password-label = Մուտքագրէք գաղտնաբառը այս PDF նիշքը բացելու համար
+pdfjs-password-invalid = Գաղտնաբառը սխալ է: Կրկին փորձէք:
+pdfjs-password-ok-button = Լաւ
+pdfjs-password-cancel-button = Չեղարկել
+pdfjs-web-fonts-disabled = Վեբ-տառատեսակները անջատուած են. հնարաւոր չէ աւգտագործել ներկառուցուած PDF տառատեսակները։
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ia/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ia/viewer.ftl
new file mode 100644
index 0000000..e53f4b0
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ia/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagina previe
+pdfjs-previous-button-label = Previe
+pdfjs-next-button =
+ .title = Pagina sequente
+pdfjs-next-button-label = Sequente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Distantiar
+pdfjs-zoom-out-button-label = Distantiar
+pdfjs-zoom-in-button =
+ .title = Approximar
+pdfjs-zoom-in-button-label = Approximar
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Excambiar a modo presentation
+pdfjs-presentation-mode-button-label = Modo presentation
+pdfjs-open-file-button =
+ .title = Aperir le file
+pdfjs-open-file-button-label = Aperir
+pdfjs-print-button =
+ .title = Imprimer
+pdfjs-print-button-label = Imprimer
+pdfjs-save-button =
+ .title = Salvar
+pdfjs-save-button-label = Salvar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Discargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Discargar
+pdfjs-bookmark-button =
+ .title = Pagina actual (vide le URL del pagina actual)
+pdfjs-bookmark-button-label = Pagina actual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Instrumentos
+pdfjs-tools-button-label = Instrumentos
+pdfjs-first-page-button =
+ .title = Ir al prime pagina
+pdfjs-first-page-button-label = Ir al prime pagina
+pdfjs-last-page-button =
+ .title = Ir al ultime pagina
+pdfjs-last-page-button-label = Ir al ultime pagina
+pdfjs-page-rotate-cw-button =
+ .title = Rotar in senso horari
+pdfjs-page-rotate-cw-button-label = Rotar in senso horari
+pdfjs-page-rotate-ccw-button =
+ .title = Rotar in senso antihorari
+pdfjs-page-rotate-ccw-button-label = Rotar in senso antihorari
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar le instrumento de selection de texto
+pdfjs-cursor-text-select-tool-button-label = Instrumento de selection de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Activar le instrumento mano
+pdfjs-cursor-hand-tool-button-label = Instrumento mano
+pdfjs-scroll-page-button =
+ .title = Usar rolamento de pagina
+pdfjs-scroll-page-button-label = Rolamento de pagina
+pdfjs-scroll-vertical-button =
+ .title = Usar rolamento vertical
+pdfjs-scroll-vertical-button-label = Rolamento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar rolamento horizontal
+pdfjs-scroll-horizontal-button-label = Rolamento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar rolamento incapsulate
+pdfjs-scroll-wrapped-button-label = Rolamento incapsulate
+pdfjs-spread-none-button =
+ .title = Non junger paginas dual
+pdfjs-spread-none-button-label = Sin paginas dual
+pdfjs-spread-odd-button =
+ .title = Junger paginas dual a partir de paginas con numeros impar
+pdfjs-spread-odd-button-label = Paginas dual impar
+pdfjs-spread-even-button =
+ .title = Junger paginas dual a partir de paginas con numeros par
+pdfjs-spread-even-button-label = Paginas dual par
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Proprietates del documento…
+pdfjs-document-properties-button-label = Proprietates del documento…
+pdfjs-document-properties-file-name = Nomine del file:
+pdfjs-document-properties-file-size = Dimension de file:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Titulo:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Subjecto:
+pdfjs-document-properties-keywords = Parolas clave:
+pdfjs-document-properties-creation-date = Data de creation:
+pdfjs-document-properties-modification-date = Data de modification:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creator:
+pdfjs-document-properties-producer = Productor PDF:
+pdfjs-document-properties-version = Version PDF:
+pdfjs-document-properties-page-count = Numero de paginas:
+pdfjs-document-properties-page-size = Dimension del pagina:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = horizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Littera
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista web rapide:
+pdfjs-document-properties-linearized-yes = Si
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Clauder
+pdfjs-digital-signature-properties-view-certificate = Vider le certificato
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Ration: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Data e hora: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Firma secundari ({ $count })
+ *[other] Firmas secundari ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparation del documento pro le impression…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancellar
+pdfjs-printing-not-supported = Attention : le impression non es totalmente supportate per ce navigator.
+pdfjs-printing-not-ready = Attention: le file PDF non es integremente cargate pro lo poter imprimer.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Monstrar/celar le barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Monstrar/celar le barra lateral (le documento contine structura/attachamentos/stratos)
+pdfjs-toggle-sidebar-button-label = Monstrar/celar le barra lateral
+pdfjs-document-outline-button =
+ .title = Monstrar le schema del documento (clic duple pro expander/contraher tote le elementos)
+pdfjs-document-outline-button-label = Schema del documento
+pdfjs-attachments-button =
+ .title = Monstrar le annexos
+pdfjs-attachments-button-label = Annexos
+pdfjs-layers-button =
+ .title = Monstrar stratos (clicca duple pro remontar tote le stratos al stato predefinite)
+pdfjs-layers-button-label = Stratos
+pdfjs-thumbs-button =
+ .title = Monstrar le vignettes
+pdfjs-thumbs-button-label = Vignettes
+pdfjs-current-outline-item-button =
+ .title = Trovar le elemento de structura actual
+pdfjs-current-outline-item-button-label = Elemento de structura actual
+pdfjs-findbar-button =
+ .title = Cercar in le documento
+pdfjs-findbar-button-label = Cercar
+pdfjs-additional-layers = Altere stratos
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Vignette del pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seliger pagina { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Pagina { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Cercar
+ .placeholder = Cercar in le documento…
+pdfjs-find-previous-button =
+ .title = Trovar le previe occurrentia del phrase
+pdfjs-find-previous-button-label = Previe
+pdfjs-find-next-button =
+ .title = Trovar le successive occurrentia del phrase
+pdfjs-find-next-button-label = Sequente
+pdfjs-find-highlight-checkbox = Evidentiar toto
+pdfjs-find-match-case-checkbox-label = Distinguer majusculas/minusculas
+pdfjs-find-match-diacritics-checkbox-label = Differentiar diacriticos
+pdfjs-find-entire-word-checkbox-label = Parolas integre
+pdfjs-find-reached-top = Initio del documento attingite, continuation ab fin
+pdfjs-find-reached-bottom = Fin del documento attingite, continuation ab initio
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } de { $total } correspondentia
+ *[other] { $current } de { $total } correspondentias
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Plus de { $limit } correspondentia
+ *[other] Plus de { $limit } correspondentias
+ }
+pdfjs-find-not-found = Phrase non trovate
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Plen largor del pagina
+pdfjs-page-scale-fit = Pagina integre
+pdfjs-page-scale-auto = Zoom automatic
+pdfjs-page-scale-actual = Dimension real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Un error occurreva durante que on cargava le file PDF.
+pdfjs-invalid-file-error = File PDF corrumpite o non valide.
+pdfjs-missing-file-error = File PDF mancante.
+pdfjs-unexpected-response-error = Responsa del servitor inexpectate.
+pdfjs-rendering-error = Un error occurreva durante que on processava le pagina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Insere le contrasigno pro aperir iste file PDF.
+pdfjs-password-invalid = Contrasigno invalide. Per favor retenta.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancellar
+pdfjs-web-fonts-disabled = Le typos de litteras web es disactivate: impossibile usar le typos de litteras PDF incorporate.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambiar color de texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Designar
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambiar color de designo
+pdfjs-editor-ink-button-label = Designar
+pdfjs-editor-stamp-button =
+ .title = Adder o rediger imagines
+pdfjs-editor-stamp-button-label = Adder o rediger imagines
+pdfjs-editor-highlight-button =
+ .title = Evidentia
+pdfjs-editor-highlight-button-label = Evidentia
+pdfjs-highlight-floating-button1 =
+ .title = Evidentiar
+ .aria-label = Evidentiar
+pdfjs-highlight-floating-button-label = Evidentiar
+pdfjs-comment-floating-button =
+ .title = Commento
+ .aria-label = Commento
+pdfjs-comment-floating-button-label = Commento
+pdfjs-editor-comment-button =
+ .title = Commento
+ .aria-label = Commento
+pdfjs-editor-comment-button-label = Commento
+pdfjs-editor-signature-button =
+ .title = Adder signatura
+pdfjs-editor-signature-button-label = Adder signatura
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de evidentiation
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de designos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de signaturas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imagines
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Remover le designo
+pdfjs-editor-remove-freetext-button =
+ .title = Remover texto
+pdfjs-editor-remove-stamp-button =
+ .title = Remover imagine
+pdfjs-editor-remove-highlight-button =
+ .title = Remover evidentia
+pdfjs-editor-remove-signature-button =
+ .title = Remover signatura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Dimension
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Spissor
+pdfjs-editor-ink-opacity-input = Opacitate
+pdfjs-editor-stamp-add-image-button =
+ .title = Adder imagine
+pdfjs-editor-stamp-add-image-button-label = Adder imagine
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Spissor
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Cambiar spissor evidentiante elementos differente de texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controlos de signatura e signaturas salvate
+pdfjs-editor-signature-add-signature-button =
+ .title = Adder nove signatura
+pdfjs-editor-signature-add-signature-button-label = Adder nove signatura
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Signatura salvate: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Initiar a inserer…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Commento
+ *[other] Commentos
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Clauder le barra lateral
+ .aria-label = Clauder le barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Clauder le barra lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vide tu alco notabile? Evidentia lo e lassa un commentario.
+pdfjs-editor-comments-sidebar-no-comments-link = Pro saper plus
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternative
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Rediger texto alternative
+pdfjs-editor-alt-text-dialog-label = Elige un option
+pdfjs-editor-alt-text-dialog-description = Le texto alternative (alt text) adjuta quando le personas non pote vider le imagine o quando illo non carga.
+pdfjs-editor-alt-text-add-description-label = Adder un description
+pdfjs-editor-alt-text-add-description-description = Mira a 1-2 phrases que describe le subjecto, parametro, o actiones.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorative
+pdfjs-editor-alt-text-mark-decorative-description = Isto es usate pro imagines ornamental, como bordaturas o filigranas.
+pdfjs-editor-alt-text-cancel-button = Cancellar
+pdfjs-editor-alt-text-save-button = Salvar
+pdfjs-editor-alt-text-decorative-tooltip = Marcate como decorative
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Per exemplo, “Un juvene sede a un tabula pro mangiar un repasto”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternative
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Angulo superior sinistre — redimensionar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Medio superior — redimensionar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Angulo superior dextre — redimensionar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Medio dextre — redimensionar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Angulo inferior dextre — redimensionar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Medio inferior — redimensionar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Angulo inferior sinistre — redimensionar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Medio sinistre — redimensionar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color pro evidentiar
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Electiones del color
+pdfjs-editor-colorpicker-yellow =
+ .title = Jalne
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Blau
+pdfjs-editor-colorpicker-pink =
+ .title = Rosate
+pdfjs-editor-colorpicker-red =
+ .title = Rubie
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Monstrar toto
+pdfjs-editor-highlight-show-all-button =
+ .title = Monstrar toto
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Rediger texto alternative (description del imagine)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Adder texto alternative (description del imagine)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Scribe tu description ci…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Breve description pro personas qui non pote vider le imagine o quando le imagine non se carga.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Iste texto alternative ha essite create automaticamente e pote esser inexacte.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Pro saper plus
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crear texto alternative automaticamente
+pdfjs-editor-new-alt-text-not-now-button = Non ora
+pdfjs-editor-new-alt-text-error-title = Impossibile crear texto alternative automaticamente
+pdfjs-editor-new-alt-text-error-description = Scribe tu proprie texto alternative o retenta plus tarde.
+pdfjs-editor-new-alt-text-error-close-button = Clauder
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Discargante modello de intelligentia artificial del texto alternative ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Discargante modello de intelligentia artificial del texto alternative ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Texto alternative addite
+pdfjs-editor-new-alt-text-added-button-label = Texto alternative addite
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Texto alternative mancante
+pdfjs-editor-new-alt-text-missing-button-label = Texto alternative mancante
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revider texto alternative
+pdfjs-editor-new-alt-text-to-review-button-label = Revider texto alternative
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automaticamente create: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Parametros del texto alternative del imagine
+pdfjs-image-alt-text-settings-button-label = Parametros del texto alternative del imagine
+pdfjs-editor-alt-text-settings-dialog-label = Parametros del texto alternative del imagine
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternative automatic
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear texto alternative automaticamente
+pdfjs-editor-alt-text-settings-create-model-description = Suggere descriptiones pro adjutar le personas qui non pote vider le imagine o quando le imagine non carga.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modello de intelligentia artificial del texto alternative ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Flue localmente sur tu apparato assi tu datos remane private. Necessari pro texto alternative automatic.
+pdfjs-editor-alt-text-settings-delete-model-button = Deler
+pdfjs-editor-alt-text-settings-download-model-button = Discargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Discargante…
+pdfjs-editor-alt-text-settings-editor-title = Rediger texto alternative
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Monstrar le redactor de texto alternative a pena on adde un imagine
+pdfjs-editor-alt-text-settings-show-dialog-description = Te adjuta a verifica que tote tu imagines ha un texto alternative.
+pdfjs-editor-alt-text-settings-close-button = Clauder
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Evidentia addite
+pdfjs-editor-freetext-added-alert = Texto addite
+pdfjs-editor-ink-added-alert = Designo addite
+pdfjs-editor-stamp-added-alert = Imagine addite
+pdfjs-editor-signature-added-alert = Firma addite
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Evidentiation removite
+pdfjs-editor-undo-bar-message-freetext = Texto removite
+pdfjs-editor-undo-bar-message-ink = Designo removite
+pdfjs-editor-undo-bar-message-stamp = Imagine removite
+pdfjs-editor-undo-bar-message-signature = Signatura removite
+pdfjs-editor-undo-bar-message-comment = Commento removite
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotation removite
+ *[other] { $count } annotationes removite
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Disfacer
+pdfjs-editor-undo-bar-undo-button-label = Disfacer
+pdfjs-editor-undo-bar-close-button =
+ .title = Clauder
+pdfjs-editor-undo-bar-close-button-label = Clauder
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Iste formulario permitte al usator crear un firma a adder a un documento PDF. Le usator pote modificar le nomine (le qual tamben servi de texto alternative) e, si desirate, salvar le firma pro uso repetite.
+pdfjs-editor-add-signature-dialog-title = Adder un signatura
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Typar
+ .title = Typar
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Designar
+ .title = Designar
+pdfjs-editor-add-signature-image-button = Imagine
+ .title = Imagine
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Insere tu firma
+ .placeholder = Insere tu firma
+pdfjs-editor-add-signature-draw-placeholder = Designa tu firma
+pdfjs-editor-add-signature-draw-thickness-range-label = Spissor
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Spissor de designo: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Trahe un file hic pro incargar lo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] O elige files de imagine
+ *[other] O folietta files de imagine
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Description (texto alternative)
+pdfjs-editor-add-signature-description-input =
+ .title = Description (texto alternative)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatura
+pdfjs-editor-add-signature-clear-button-label = Rader signatura
+pdfjs-editor-add-signature-clear-button =
+ .title = Rader signatura
+pdfjs-editor-add-signature-save-checkbox = Salvar signatura
+pdfjs-editor-add-signature-save-warning-message = Tu ha attingite le limite de 5 firmas salvate. Remove un pro salvar un altere.
+pdfjs-editor-add-signature-image-upload-error-title = Non poteva incargar le imagine
+pdfjs-editor-add-signature-image-upload-error-description = Verifica tu connexion al rete o tenta un altere imagine.
+pdfjs-editor-add-signature-image-no-data-error-title = Impossibile converter iste imagine in un firma
+pdfjs-editor-add-signature-image-no-data-error-description = Essaya cargar un imagine differente.
+pdfjs-editor-add-signature-error-close-button = Clauder
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancellar
+pdfjs-editor-add-signature-add-button = Adder
+pdfjs-editor-edit-signature-update-button = Actualisar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Rediger commento
+pdfjs-editor-edit-comment-popup-button =
+ .title = Rediger commento
+pdfjs-editor-delete-comment-popup-button-label = Remover commento
+pdfjs-editor-delete-comment-popup-button =
+ .title = Remover commento
+pdfjs-show-comment-button =
+ .title = Monstrar commento
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Rediger commento
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Actualisar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Adder commento
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Adder
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Comenciar a scriber…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancellar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Adder commento
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Monstrar/celar le barra lateral (le documento contine miniaturas/structura/attachamentos/stratos)
+pdfjs-toggle-views-manager-button1-label = Gerer paginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Saltar al declaration
+pdfjs-views-manager-view-selector-button =
+ .title = Vistas
+pdfjs-views-manager-view-selector-button-label = Vistas
+pdfjs-views-manager-pages-title = Paginas
+pdfjs-views-manager-outlines-title1 = Structura de documento
+ .title = Structura de documento (clicca-duplemente pro expander/collaber tote elementos)
+pdfjs-views-manager-attachments-title = Annexos
+pdfjs-views-manager-layers-title1 = Stratos
+ .title = Stratos (clicca-duplemente pro reinitialisar tote le stratos al stato predefinite)
+pdfjs-views-manager-pages-option-label = Paginas
+pdfjs-views-manager-outlines-option-label = Schema del documento
+pdfjs-views-manager-attachments-option-label = Annexos
+pdfjs-views-manager-layers-option-label = Stratos
+pdfjs-views-manager-add-file-button =
+ .title = Adder file
+pdfjs-views-manager-add-file-button-label = Adder file
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } seligite
+ *[other] { $count } seligite
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seliger paginas
+pdfjs-views-manager-pages-status-action-button-label = Gerer
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Secar
+pdfjs-views-manager-pages-status-delete-button-label = Deler
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar seligite…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 pagina secate
+ *[other] { $count } paginas secate
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 pagina copiate
+ *[other] { $count } paginas copiate
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 pagina delite
+ *[other] { $count } paginas delite
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparante file…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Cargante file…
+pdfjs-views-manager-status-warning-cut-label = Impossibile secar. Refresca le pagina e retenta.
+pdfjs-views-manager-status-warning-copy-label = Impossibile copiar. Refresca le pagina e retenta.
+pdfjs-views-manager-status-warning-delete-label = Impossibile deler. Refresca le pagina e retenta.
+pdfjs-views-manager-status-warning-save-label = Impossibile salvar. Refresca le pagina e retenta.
+pdfjs-views-manager-status-undo-button-label = Disfacer
+pdfjs-views-manager-status-done-button-label = Facite
+pdfjs-views-manager-status-close-button =
+ .title = Clauder
+pdfjs-views-manager-status-close-button-label = Clauder
+pdfjs-views-manager-paste-button-label = Collar
+pdfjs-views-manager-paste-button-before =
+ .title = Collar ante le prime pagina
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Colla post pagina { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVA
+pdfjs-views-manager-waiting-for-file = Cargante file…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gerer paginas
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Proprietates del firma digital
+ .aria-label = Proprietates del firma digital
+pdfjs-digital-signature-properties-button-label = Proprietates del firma digital
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Le documento era firmate con un firma digital valide
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Documento firmate ma { $count } firma digital non poteva esser verificate
+ *[other] Documento firmate ma { $count } firmas digital non poteva esser verificate
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Documento firmate con { $count } certificato que non es de fiducia
+ *[other] Documento firmate con { $count } certificatos que non es de fiducia
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Documento firmate con { $count } certificato expirate
+ *[other] Documento firmate con { $count } certificatos expirate
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Le documento ha { $count } firma digital non valide
+ *[other] Le documento ha { $count } firmas digital non valide
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Documento firmate con { $count } certificato revocate
+ *[other] Documento firmate con { $count } certificatos revocate
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stato: firma verificate
+pdfjs-digital-signature-properties-status-invalid = Stato: firma non valide
+pdfjs-digital-signature-properties-status-unknown = Stato: impossibile verificar (non supportate)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificato: de fiducia ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificato: indisponibile
+pdfjs-digital-signature-properties-certificate-untrusted = Certificato: non de confidentia
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificato: emissor incognite ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificato: auto-firmate ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificato: emissor non de confidentia ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificato: expirate
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificato: expirate ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificato: revocate
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Remover signatura salvate
+pdfjs-editor-delete-signature-button-label1 = Remover signatura salvate
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Rediger description
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Rediger description
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/id/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/id/viewer.ftl
new file mode 100644
index 0000000..f5b84af
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/id/viewer.ftl
@@ -0,0 +1,589 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Laman Sebelumnya
+pdfjs-previous-button-label = Sebelumnya
+pdfjs-next-button =
+ .title = Laman Selanjutnya
+pdfjs-next-button-label = Selanjutnya
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Halaman
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = dari { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } dari { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Perkecil
+pdfjs-zoom-out-button-label = Perkecil
+pdfjs-zoom-in-button =
+ .title = Perbesar
+pdfjs-zoom-in-button-label = Perbesar
+pdfjs-zoom-select =
+ .title = Perbesaran
+pdfjs-presentation-mode-button =
+ .title = Ganti ke Mode Presentasi
+pdfjs-presentation-mode-button-label = Mode Presentasi
+pdfjs-open-file-button =
+ .title = Buka Berkas
+pdfjs-open-file-button-label = Buka
+pdfjs-print-button =
+ .title = Cetak
+pdfjs-print-button-label = Cetak
+pdfjs-save-button =
+ .title = Simpan
+pdfjs-save-button-label = Simpan
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Unduh
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Unduh
+pdfjs-bookmark-button =
+ .title = Laman Saat Ini (Lihat URL dari Laman Sekarang)
+pdfjs-bookmark-button-label = Laman Saat Ini
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Alat
+pdfjs-tools-button-label = Alat
+pdfjs-first-page-button =
+ .title = Buka Halaman Pertama
+pdfjs-first-page-button-label = Buka Halaman Pertama
+pdfjs-last-page-button =
+ .title = Buka Halaman Terakhir
+pdfjs-last-page-button-label = Buka Halaman Terakhir
+pdfjs-page-rotate-cw-button =
+ .title = Putar Searah Jarum Jam
+pdfjs-page-rotate-cw-button-label = Putar Searah Jarum Jam
+pdfjs-page-rotate-ccw-button =
+ .title = Putar Berlawanan Arah Jarum Jam
+pdfjs-page-rotate-ccw-button-label = Putar Berlawanan Arah Jarum Jam
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktifkan Alat Seleksi Teks
+pdfjs-cursor-text-select-tool-button-label = Alat Seleksi Teks
+pdfjs-cursor-hand-tool-button =
+ .title = Aktifkan Alat Tangan
+pdfjs-cursor-hand-tool-button-label = Alat Tangan
+pdfjs-scroll-page-button =
+ .title = Gunakan Pengguliran Laman
+pdfjs-scroll-page-button-label = Pengguliran Laman
+pdfjs-scroll-vertical-button =
+ .title = Gunakan Penggeseran Vertikal
+pdfjs-scroll-vertical-button-label = Penggeseran Vertikal
+pdfjs-scroll-horizontal-button =
+ .title = Gunakan Penggeseran Horizontal
+pdfjs-scroll-horizontal-button-label = Penggeseran Horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Gunakan Penggeseran Terapit
+pdfjs-scroll-wrapped-button-label = Penggeseran Terapit
+pdfjs-spread-none-button =
+ .title = Jangan gabungkan lembar halaman
+pdfjs-spread-none-button-label = Tidak Ada Lembaran
+pdfjs-spread-odd-button =
+ .title = Gabungkan lembar lamanan mulai dengan halaman ganjil
+pdfjs-spread-odd-button-label = Lembaran Ganjil
+pdfjs-spread-even-button =
+ .title = Gabungkan lembar halaman dimulai dengan halaman genap
+pdfjs-spread-even-button-label = Lembaran Genap
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Properti Dokumen…
+pdfjs-document-properties-button-label = Properti Dokumen…
+pdfjs-document-properties-file-name = Nama berkas:
+pdfjs-document-properties-file-size = Ukuran berkas:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } byte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } byte)
+pdfjs-document-properties-title = Judul:
+pdfjs-document-properties-author = Penyusun:
+pdfjs-document-properties-subject = Subjek:
+pdfjs-document-properties-keywords = Kata Kunci:
+pdfjs-document-properties-creation-date = Tanggal Dibuat:
+pdfjs-document-properties-modification-date = Tanggal Dimodifikasi:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Pembuat:
+pdfjs-document-properties-producer = Pemroduksi PDF:
+pdfjs-document-properties-version = Versi PDF:
+pdfjs-document-properties-page-count = Jumlah Halaman:
+pdfjs-document-properties-page-size = Ukuran Laman:
+pdfjs-document-properties-page-size-unit-inches = inci
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = tegak
+pdfjs-document-properties-page-size-orientation-landscape = mendatar
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Tampilan Web Kilat:
+pdfjs-document-properties-linearized-yes = Ya
+pdfjs-document-properties-linearized-no = Tidak
+pdfjs-document-properties-close-button = Tutup
+
+## Print
+
+pdfjs-print-progress-message = Menyiapkan dokumen untuk pencetakan…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Batalkan
+pdfjs-printing-not-supported = Peringatan: Pencetakan tidak didukung secara lengkap pada peramban ini.
+pdfjs-printing-not-ready = Peringatan: Berkas PDF masih belum dimuat secara lengkap untuk dapat dicetak.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Aktif/Nonaktifkan Bilah Samping
+pdfjs-toggle-sidebar-notification-button =
+ .title = Aktif/Nonaktifkan Bilah Samping (dokumen berisi kerangka/lampiran/lapisan)
+pdfjs-toggle-sidebar-button-label = Aktif/Nonaktifkan Bilah Samping
+pdfjs-document-outline-button =
+ .title = Tampilkan Kerangka Dokumen (klik ganda untuk membentangkan/menciutkan semua item)
+pdfjs-document-outline-button-label = Kerangka Dokumen
+pdfjs-attachments-button =
+ .title = Tampilkan Lampiran
+pdfjs-attachments-button-label = Lampiran
+pdfjs-layers-button =
+ .title = Tampilkan Lapisan (klik ganda untuk mengatur ulang semua lapisan ke keadaan baku)
+pdfjs-layers-button-label = Lapisan
+pdfjs-thumbs-button =
+ .title = Tampilkan Miniatur
+pdfjs-thumbs-button-label = Miniatur
+pdfjs-current-outline-item-button =
+ .title = Cari Butir Ikhtisar Saat Ini
+pdfjs-current-outline-item-button-label = Butir Ikhtisar Saat Ini
+pdfjs-findbar-button =
+ .title = Temukan di Dokumen
+pdfjs-findbar-button-label = Temukan
+pdfjs-additional-layers = Lapisan Tambahan
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Laman { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatur Laman { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Temukan
+ .placeholder = Temukan di dokumen…
+pdfjs-find-previous-button =
+ .title = Temukan kata sebelumnya
+pdfjs-find-previous-button-label = Sebelumnya
+pdfjs-find-next-button =
+ .title = Temukan lebih lanjut
+pdfjs-find-next-button-label = Selanjutnya
+pdfjs-find-highlight-checkbox = Sorot semuanya
+pdfjs-find-match-case-checkbox-label = Cocokkan BESAR/kecil
+pdfjs-find-match-diacritics-checkbox-label = Pencocokan Diakritik
+pdfjs-find-entire-word-checkbox-label = Seluruh teks
+pdfjs-find-reached-top = Sampai di awal dokumen, dilanjutkan dari bawah
+pdfjs-find-reached-bottom = Sampai di akhir dokumen, dilanjutkan dari atas
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = { $current } dari { $total } yang cocok
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = Lebih dari { $limit } kecocokan
+pdfjs-find-not-found = Frasa tidak ditemukan
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lebar Laman
+pdfjs-page-scale-fit = Muat Laman
+pdfjs-page-scale-auto = Perbesaran Otomatis
+pdfjs-page-scale-actual = Ukuran Asli
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Halaman { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Galat terjadi saat memuat PDF.
+pdfjs-invalid-file-error = Berkas PDF tidak valid atau rusak.
+pdfjs-missing-file-error = Berkas PDF tidak ada.
+pdfjs-unexpected-response-error = Balasan server yang tidak diharapkan.
+pdfjs-rendering-error = Galat terjadi saat merender laman.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotasi { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Masukkan sandi untuk membuka berkas PDF ini.
+pdfjs-password-invalid = Sandi tidak valid. Silakan coba lagi.
+pdfjs-password-ok-button = Oke
+pdfjs-password-cancel-button = Batal
+pdfjs-web-fonts-disabled = Font web dinonaktifkan: tidak dapat menggunakan font PDF yang tersemat.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Teks
+pdfjs-editor-color-picker-free-text-input =
+ .title = Ubah warna teks
+pdfjs-editor-free-text-button-label = Teks
+pdfjs-editor-ink-button =
+ .title = Gambar
+pdfjs-editor-color-picker-ink-input =
+ .title = Ubah warna gambar
+pdfjs-editor-ink-button-label = Gambar
+pdfjs-editor-stamp-button =
+ .title = Tambah atau edit gambar
+pdfjs-editor-stamp-button-label = Tambah atau edit gambar
+pdfjs-editor-highlight-button =
+ .title = Sorot
+pdfjs-editor-highlight-button-label = Sorot
+pdfjs-highlight-floating-button1 =
+ .title = Sorot
+ .aria-label = Sorot
+pdfjs-highlight-floating-button-label = Sorot
+pdfjs-comment-floating-button =
+ .title = Komentar
+ .aria-label = Komentar
+pdfjs-comment-floating-button-label = Komentar
+pdfjs-editor-signature-button =
+ .title = Tambahkan tanda tangan
+pdfjs-editor-signature-button-label = Tambahkan tanda tangan
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor sorot
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor gambar
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor tanda tangan: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor gambar
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Hapus gambar
+pdfjs-editor-remove-freetext-button =
+ .title = Hapus teks
+pdfjs-editor-remove-stamp-button =
+ .title = Hapus gambar
+pdfjs-editor-remove-highlight-button =
+ .title = Hapus sorotan
+pdfjs-editor-remove-signature-button =
+ .title = Hapus tanda tangan
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Warna
+pdfjs-editor-free-text-size-input = Ukuran
+pdfjs-editor-ink-color-input = Warna
+pdfjs-editor-ink-thickness-input = Ketebalan
+pdfjs-editor-ink-opacity-input = Opasitas
+pdfjs-editor-stamp-add-image-button =
+ .title = Tambahkan gambar
+pdfjs-editor-stamp-add-image-button-label = Tambahkan gambar
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Ketebalan
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Ubah ketebalan saat menyorot item selain teks
+pdfjs-editor-add-signature-container =
+ .aria-label = Kontrol tanda tangan dan tanda tangan tersimpan
+pdfjs-editor-signature-add-signature-button =
+ .title = Tambahkan tanda tangan baru
+pdfjs-editor-signature-add-signature-button-label = Tambahkan tanda tangan baru
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Tanda tangan tersimpan: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor Teks
+ .default-content = Mulai mengetik…
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Teks alternatif
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Edit teks alternatif
+pdfjs-editor-alt-text-dialog-label = Pilih opsi
+pdfjs-editor-alt-text-dialog-description = Teks alternatif membantu ketika orang tidak dapat melihat gambar atau ketika tidak termuat.
+pdfjs-editor-alt-text-add-description-label = Tambahkan deskripsi
+pdfjs-editor-alt-text-add-description-description = Upayakan 1-2 kalimat yang menggambarkan subjek, latar, atau tindakan.
+pdfjs-editor-alt-text-mark-decorative-label = Tandai sebagai dekoratif
+pdfjs-editor-alt-text-mark-decorative-description = Ini digunakan untuk gambar hias, seperti batas atau tanda air.
+pdfjs-editor-alt-text-cancel-button = Batal
+pdfjs-editor-alt-text-save-button = Simpan
+pdfjs-editor-alt-text-decorative-tooltip = Ditandai sebagai dekoratif
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Misalnya, “Seorang pemuda duduk di meja untuk makan”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Teks alternatif
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Pojok kiri atas — ubah ukuran
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Tengah atas — ubah ukuran
+pdfjs-editor-resizer-top-right =
+ .aria-label = Pojok kanan atas — ubah ukuran
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Kanan tengah — ubah ukuran
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Pojok kanan bawah — ubah ukuran
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Tengah bawah — ubah ukuran
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Pojok kiri bawah — ubah ukuran
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Kiri tengah — ubah ukuran
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Warna sorot
+pdfjs-editor-colorpicker-button =
+ .title = Ubah warna
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Pilihan warna
+pdfjs-editor-colorpicker-yellow =
+ .title = Kuning
+pdfjs-editor-colorpicker-green =
+ .title = Hijau
+pdfjs-editor-colorpicker-blue =
+ .title = Biru
+pdfjs-editor-colorpicker-pink =
+ .title = Merah Jambu
+pdfjs-editor-colorpicker-red =
+ .title = Merah
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Tampilkan semua
+pdfjs-editor-highlight-show-all-button =
+ .title = Tampilkan semua
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Edit teks alternatif (deskripsi gambar)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Tambahkan teks alternatif (deskripsi gambar)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Tulis deskripsi Anda di sini…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Deskripsi singkat untuk orang yang tidak dapat melihat gambar atau saat gambar tidak termuat.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Teks alternatif ini dibuat secara otomatis dan mungkin tidak akurat.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Pelajari lebih lanjut
+pdfjs-editor-new-alt-text-create-automatically-button-label = Buat teks alternatif secara otomatis
+pdfjs-editor-new-alt-text-not-now-button = Jangan sekarang
+pdfjs-editor-new-alt-text-error-title = Tidak bisa membuat teks alternatif secara otomatis
+pdfjs-editor-new-alt-text-error-description = Silakan tulis teks alternatif Anda sendiri atau coba lagi nanti.
+pdfjs-editor-new-alt-text-error-close-button = Tutup
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Mengunduh model AI teks alternatif ({ $downloadedSize } dari { $totalSize } MB)
+ .aria-valuetext = Mengunduh model AI teks alternatif ({ $downloadedSize } dari { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Teks alternatif ditambahkan
+pdfjs-editor-new-alt-text-added-button-label = Teks alternatif ditambahkan
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Teks alternatif hilang
+pdfjs-editor-new-alt-text-missing-button-label = Teks alternatif hilang
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Tinjau teks alternatif
+pdfjs-editor-new-alt-text-to-review-button-label = Tinjau teks alternatif
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Dibuat secara otomatis: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Pengaturan teks alternatif gambar
+pdfjs-image-alt-text-settings-button-label = Pengaturan teks alternatif gambar
+pdfjs-editor-alt-text-settings-dialog-label = Pengaturan teks alternatif gambar
+pdfjs-editor-alt-text-settings-automatic-title = Teks alternatif otomatis
+pdfjs-editor-alt-text-settings-create-model-button-label = Buat teks alternatif secara otomatis
+pdfjs-editor-alt-text-settings-create-model-description = Menyarankan deskripsi untuk membantu orang yang tidak dapat melihat gambar atau ketika gambar tidak termuat.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model AI teks alternatif ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Berjalan secara lokal di perangkat Anda sehingga data Anda tetap pribadi. Diperlukan untuk teks alternatif otomatis.
+pdfjs-editor-alt-text-settings-delete-model-button = Hapus
+pdfjs-editor-alt-text-settings-download-model-button = Unduh
+pdfjs-editor-alt-text-settings-downloading-model-button = Mengunduh…
+pdfjs-editor-alt-text-settings-editor-title = Editor teks alternatif
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Tampilkan editor teks alternatif segera saat menambahkan gambar
+pdfjs-editor-alt-text-settings-show-dialog-description = Membantu Anda memastikan semua gambar Anda memiliki teks alternatif.
+pdfjs-editor-alt-text-settings-close-button = Tutup
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Sorotan ditambahkan
+pdfjs-editor-freetext-added-alert = Teks ditambahkan
+pdfjs-editor-ink-added-alert = Gambar ditambahkan
+pdfjs-editor-stamp-added-alert = Citra ditambahkan
+pdfjs-editor-signature-added-alert = Tanda tangan ditambahkan
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Sorotan dihapus
+pdfjs-editor-undo-bar-message-freetext = Teks dihapus
+pdfjs-editor-undo-bar-message-ink = Gambar dihapus
+pdfjs-editor-undo-bar-message-stamp = Gambar dihapus
+pdfjs-editor-undo-bar-message-signature = Tanda tangan dihapus
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = { $count } anotasi dihapus
+pdfjs-editor-undo-bar-undo-button =
+ .title = Urungkan
+pdfjs-editor-undo-bar-undo-button-label = Urungkan
+pdfjs-editor-undo-bar-close-button =
+ .title = Tutup
+pdfjs-editor-undo-bar-close-button-label = Tutup
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Modal ini memungkinkan pengguna untuk membuat tanda tangan yang dapat ditambahkan ke dokumen PDF. Pengguna dapat mengedit nama (yang juga berfungsi sebagai teks alternatif), dan jika diinginkan, menyimpan tanda tangan untuk digunakan kembali.
+pdfjs-editor-add-signature-dialog-title = Tambahkan tanda tangan
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tipe
+ .title = Tipe
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Gambarkan
+ .title = Gambarkan
+pdfjs-editor-add-signature-image-button = Gambar
+ .title = Gambar
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Ketik tanda tangan Anda
+ .placeholder = Ketik tanda tangan Anda
+pdfjs-editor-add-signature-draw-placeholder = Buat tanda tangan Anda
+pdfjs-editor-add-signature-draw-thickness-range-label = Ketebalan
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Ketebalan gambar: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Seret berkas ke sini untuk mengunggah
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Atau pilih berkas gambar
+ *[other] Atau cari berkas gambar
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Deskripsi (teks alternatif)
+pdfjs-editor-add-signature-description-input =
+ .title = Deskripsi (teks alternatif)
+pdfjs-editor-add-signature-description-default-when-drawing = Tanda tangan
+pdfjs-editor-add-signature-clear-button-label = Hapus tanda tangan
+pdfjs-editor-add-signature-clear-button =
+ .title = Hapus tanda tangan
+pdfjs-editor-add-signature-save-checkbox = Simpan tanda tangan
+pdfjs-editor-add-signature-save-warning-message = Anda telah mencapai batas 5 tanda tangan tersimpan. Hapus untuk menyimpan lebih banyak.
+pdfjs-editor-add-signature-image-upload-error-title = Tidak dapat mengunggah gambar
+pdfjs-editor-add-signature-image-upload-error-description = Periksa sambungan jaringan Anda atau coba gambar lain.
+pdfjs-editor-add-signature-image-no-data-error-title = Tak bisa mengonversi citra ini menjadi tanda tangan
+pdfjs-editor-add-signature-image-no-data-error-description = Coba unggah gambar lain.
+pdfjs-editor-add-signature-error-close-button = Tutup
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Batal
+pdfjs-editor-add-signature-add-button = Tambah
+pdfjs-editor-edit-signature-update-button = Perbarui
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Hapus tanda tangan tersimpan
+pdfjs-editor-delete-signature-button-label1 = Hapus tanda tangan tersimpan
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Edit deskripsi
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Edit deskripsi
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/is/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/is/viewer.ftl
new file mode 100644
index 0000000..2f27e67
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/is/viewer.ftl
@@ -0,0 +1,572 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Fyrri síða
+pdfjs-previous-button-label = Fyrri
+pdfjs-next-button =
+ .title = Næsta síða
+pdfjs-next-button-label = Næsti
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Síða
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = af { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } af { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Minnka aðdrátt
+pdfjs-zoom-out-button-label = Minnka aðdrátt
+pdfjs-zoom-in-button =
+ .title = Auka aðdrátt
+pdfjs-zoom-in-button-label = Auka aðdrátt
+pdfjs-zoom-select =
+ .title = Aðdráttur
+pdfjs-presentation-mode-button =
+ .title = Skipta yfir á kynningarham
+pdfjs-presentation-mode-button-label = Kynningarhamur
+pdfjs-open-file-button =
+ .title = Opna skrá
+pdfjs-open-file-button-label = Opna
+pdfjs-print-button =
+ .title = Prenta
+pdfjs-print-button-label = Prenta
+pdfjs-save-button =
+ .title = Vista
+pdfjs-save-button-label = Vista
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Sækja
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Sækja
+pdfjs-bookmark-button =
+ .title = Núverandi síða (Skoða vefslóð frá núverandi síðu)
+pdfjs-bookmark-button-label = Núverandi síða
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Verkfæri
+pdfjs-tools-button-label = Verkfæri
+pdfjs-first-page-button =
+ .title = Fara á fyrstu síðu
+pdfjs-first-page-button-label = Fara á fyrstu síðu
+pdfjs-last-page-button =
+ .title = Fara á síðustu síðu
+pdfjs-last-page-button-label = Fara á síðustu síðu
+pdfjs-page-rotate-cw-button =
+ .title = Snúa réttsælis
+pdfjs-page-rotate-cw-button-label = Snúa réttsælis
+pdfjs-page-rotate-ccw-button =
+ .title = Snúa rangsælis
+pdfjs-page-rotate-ccw-button-label = Snúa rangsælis
+pdfjs-cursor-text-select-tool-button =
+ .title = Virkja textavalsáhald
+pdfjs-cursor-text-select-tool-button-label = Textavalsáhald
+pdfjs-cursor-hand-tool-button =
+ .title = Virkja handarverkfæri
+pdfjs-cursor-hand-tool-button-label = Handarverkfæri
+pdfjs-scroll-page-button =
+ .title = Nota síðuskrun
+pdfjs-scroll-page-button-label = Síðuskrun
+pdfjs-scroll-vertical-button =
+ .title = Nota lóðrétt skrun
+pdfjs-scroll-vertical-button-label = Lóðrétt skrun
+pdfjs-scroll-horizontal-button =
+ .title = Nota lárétt skrun
+pdfjs-scroll-horizontal-button-label = Lárétt skrun
+pdfjs-scroll-wrapped-button =
+ .title = Nota línuskipt síðuskrun
+pdfjs-scroll-wrapped-button-label = Línuskipt síðuskrun
+pdfjs-spread-none-button =
+ .title = Ekki taka þátt í dreifingu síðna
+pdfjs-spread-none-button-label = Engin dreifing
+pdfjs-spread-odd-button =
+ .title = Taka þátt í dreifingu síðna með oddatölum
+pdfjs-spread-odd-button-label = Oddatöludreifing
+pdfjs-spread-even-button =
+ .title = Taktu þátt í dreifingu síðna með jöfnuntölum
+pdfjs-spread-even-button-label = Jafnatöludreifing
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Eiginleikar skjals…
+pdfjs-document-properties-button-label = Eiginleikar skjals…
+pdfjs-document-properties-file-name = Skráarheiti:
+pdfjs-document-properties-file-size = Skrárstærð:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bæti)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bæti)
+pdfjs-document-properties-title = Titill:
+pdfjs-document-properties-author = Hönnuður:
+pdfjs-document-properties-subject = Efni:
+pdfjs-document-properties-keywords = Stikkorð:
+pdfjs-document-properties-creation-date = Búið til:
+pdfjs-document-properties-modification-date = Dags breytingar:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Höfundur:
+pdfjs-document-properties-producer = PDF framleiðandi:
+pdfjs-document-properties-version = PDF útgáfa:
+pdfjs-document-properties-page-count = Blaðsíðufjöldi:
+pdfjs-document-properties-page-size = Stærð síðu:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = skammsnið
+pdfjs-document-properties-page-size-orientation-landscape = langsnið
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fljótleg vefskoðun:
+pdfjs-document-properties-linearized-yes = Já
+pdfjs-document-properties-linearized-no = Nei
+pdfjs-document-properties-close-button = Loka
+
+## Print
+
+pdfjs-print-progress-message = Undirbý skjal fyrir prentun…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Hætta við
+pdfjs-printing-not-supported = Aðvörun: Prentun er ekki með fyllilegan stuðning á þessum vafra.
+pdfjs-printing-not-ready = Aðvörun: Ekki er búið að hlaða inn allri PDF skránni fyrir prentun.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Víxla hliðarstiku af/á
+pdfjs-toggle-sidebar-notification-button =
+ .title = Víxla hliðarstiku af/á (skjal inniheldur yfirlit/viðhengi/lög)
+pdfjs-toggle-sidebar-button-label = Víxla hliðarstiku af/á
+pdfjs-document-outline-button =
+ .title = Sýna yfirlit skjals (tvísmelltu til að opna/loka öllum hlutum)
+pdfjs-document-outline-button-label = Efnisskipan skjals
+pdfjs-attachments-button =
+ .title = Sýna viðhengi
+pdfjs-attachments-button-label = Viðhengi
+pdfjs-layers-button =
+ .title = Birta lög (tvísmelltu til að endurstilla öll lög í sjálfgefna stöðu)
+pdfjs-layers-button-label = Lög
+pdfjs-thumbs-button =
+ .title = Sýna smámyndir
+pdfjs-thumbs-button-label = Smámyndir
+pdfjs-current-outline-item-button =
+ .title = Finna núverandi atriði efnisskipunar
+pdfjs-current-outline-item-button-label = Núverandi atriði efnisskipunar
+pdfjs-findbar-button =
+ .title = Leita í skjali
+pdfjs-findbar-button-label = Leita
+pdfjs-additional-layers = Viðbótarlög
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Síða { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Smámynd af síðu { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Leita
+ .placeholder = Leita í skjali…
+pdfjs-find-previous-button =
+ .title = Leita að fyrra tilfelli þessara orða
+pdfjs-find-previous-button-label = Fyrri
+pdfjs-find-next-button =
+ .title = Leita að næsta tilfelli þessara orða
+pdfjs-find-next-button-label = Næsti
+pdfjs-find-highlight-checkbox = Lita allt
+pdfjs-find-match-case-checkbox-label = Passa við stafstöðu
+pdfjs-find-match-diacritics-checkbox-label = Passa við broddstafi
+pdfjs-find-entire-word-checkbox-label = Heil orð
+pdfjs-find-reached-top = Náði efst í skjal, held áfram neðst
+pdfjs-find-reached-bottom = Náði enda skjals, held áfram efst
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } af { $total } passar við
+ *[other] { $current } af { $total } passa við
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Fleiri en { $limit } passar við
+ *[other] Fleiri en { $limit } passa við
+ }
+pdfjs-find-not-found = Fann ekki orðið
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Síðubreidd
+pdfjs-page-scale-fit = Passa á síðu
+pdfjs-page-scale-auto = Sjálfvirkur aðdráttur
+pdfjs-page-scale-actual = Raunstærð
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Síða { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Villa kom upp við að hlaða inn PDF.
+pdfjs-invalid-file-error = Ógild eða skemmd PDF skrá.
+pdfjs-missing-file-error = Vantar PDF skrá.
+pdfjs-unexpected-response-error = Óvænt svar frá netþjóni.
+pdfjs-rendering-error = Upp kom villa við að birta síðuna.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Skýring]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Settu inn lykilorð til að opna þessa PDF-skrá.
+pdfjs-password-invalid = Ógilt lykilorð. Reyndu aftur.
+pdfjs-password-ok-button = Í lagi
+pdfjs-password-cancel-button = Hætta við
+pdfjs-web-fonts-disabled = Vef leturgerðir eru óvirkar: get ekki notað innbyggðar PDF leturgerðir.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texti
+pdfjs-editor-free-text-button-label = Texti
+pdfjs-editor-ink-button =
+ .title = Teikna
+pdfjs-editor-ink-button-label = Teikna
+pdfjs-editor-stamp-button =
+ .title = Bæta við eða breyta myndum
+pdfjs-editor-stamp-button-label = Bæta við eða breyta myndum
+pdfjs-editor-highlight-button =
+ .title = Áherslulita
+pdfjs-editor-highlight-button-label = Áherslulita
+pdfjs-highlight-floating-button1 =
+ .title = Áherslulita
+ .aria-label = Áherslulita
+pdfjs-highlight-floating-button-label = Áherslulita
+pdfjs-editor-signature-button =
+ .title = Bæta við undirritun
+pdfjs-editor-signature-button-label = Bæta við undirritun
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Fjarlægja teikningu
+pdfjs-editor-remove-freetext-button =
+ .title = Fjarlægja texta
+pdfjs-editor-remove-stamp-button =
+ .title = Fjarlægja mynd
+pdfjs-editor-remove-highlight-button =
+ .title = Fjarlægja áherslulit
+pdfjs-editor-remove-signature-button =
+ .title = Fjarlægja undirskrift
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Litur
+pdfjs-editor-free-text-size-input = Stærð
+pdfjs-editor-ink-color-input = Litur
+pdfjs-editor-ink-thickness-input = Þykkt
+pdfjs-editor-ink-opacity-input = Ógegnsæi
+pdfjs-editor-stamp-add-image-button =
+ .title = Bæta við mynd
+pdfjs-editor-stamp-add-image-button-label = Bæta við mynd
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Þykkt
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Breyta þykkt við áherslulitun annarra atriða en texta
+pdfjs-editor-signature-add-signature-button =
+ .title = Bæta við nýrri undirritun
+pdfjs-editor-signature-add-signature-button-label = Bæta við nýrri undirritun
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Vistuð undirskrift: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Textaritill
+ .default-content = Byrjaðu að skrifa…
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alt-varatexti
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Breyta alt-myndatexta
+pdfjs-editor-alt-text-dialog-label = Veldu valkost
+pdfjs-editor-alt-text-dialog-description = Alt-varatexti (auka-myndatexti) hjálpar þegar fólk getur ekki séð myndina eða þegar hún hleðst ekki inn.
+pdfjs-editor-alt-text-add-description-label = Bættu við lýsingu
+pdfjs-editor-alt-text-add-description-description = Reyndu að takmarka þetta við 1-2 setningar sem lýsa efninu, umhverfi eða aðgerðum.
+pdfjs-editor-alt-text-mark-decorative-label = Merkja sem skraut
+pdfjs-editor-alt-text-mark-decorative-description = Þetta er notað fyrir skrautmyndir, eins og borða eða vatnsmerki.
+pdfjs-editor-alt-text-cancel-button = Hætta við
+pdfjs-editor-alt-text-save-button = Vista
+pdfjs-editor-alt-text-decorative-tooltip = Merkt sem skraut
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Til dæmis: „Ungur maður sest við borð til að snæða máltíð“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alt-myndatexti
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Efst í vinstra horni - breyta stærð
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Efst á miðju - breyta stærð
+pdfjs-editor-resizer-top-right =
+ .aria-label = Efst í hægra horni - breyta stærð
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Miðja til hægri - breyta stærð
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Neðst í hægra horni - breyta stærð
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Neðst á miðju - breyta stærð
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Neðst í vinstra horni - breyta stærð
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Miðja til vinstri - breyta stærð
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Áherslulitur
+pdfjs-editor-colorpicker-button =
+ .title = Skipta um lit
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Val lita
+pdfjs-editor-colorpicker-yellow =
+ .title = Gult
+pdfjs-editor-colorpicker-green =
+ .title = Grænt
+pdfjs-editor-colorpicker-blue =
+ .title = Blátt
+pdfjs-editor-colorpicker-pink =
+ .title = Bleikt
+pdfjs-editor-colorpicker-red =
+ .title = Rautt
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Birta allt
+pdfjs-editor-highlight-show-all-button =
+ .title = Birta allt
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Breyta alt-myndatexta (lýsingu á mynd)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Bæta við alt-myndatexta (lýsingu á mynd)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skrifaðu lýsinguna þína hér…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Stutt lýsing fyrir fólk sem getur ekki séð myndina eða þegar myndin hleðst ekki inn.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Þessi alt-myndatexti var búinn til sjálfvirkt og gæti verið ónákvæmur.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Kanna nánar
+pdfjs-editor-new-alt-text-create-automatically-button-label = Útbúa alt-myndatexta sjálfvirkt
+pdfjs-editor-new-alt-text-not-now-button = Ekki núna
+pdfjs-editor-new-alt-text-error-title = Gat ekki búið til alt-myndatexta sjálfkrafa
+pdfjs-editor-new-alt-text-error-description = Skrifaðu þinn eiginn alt-myndatexta eða reyndu aftur síðar.
+pdfjs-editor-new-alt-text-error-close-button = Loka
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Sækir gervigreindarlíkan með alt-myndatextum ({ $downloadedSize } af { $totalSize } MB)
+ .aria-valuetext = Sækir gervigreindarlíkan með alt-myndatextum ({ $downloadedSize } af { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alt-myndatexta bætt við
+pdfjs-editor-new-alt-text-added-button-label = Alt-myndatexta bætt við
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Vantar alt-myndatexta
+pdfjs-editor-new-alt-text-missing-button-label = Vantar alt-myndatexta
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Yfirfara alt-myndatexta
+pdfjs-editor-new-alt-text-to-review-button-label = Yfirfara myndatexta
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Útbúið sjálfvirkt: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Stillingar fyrir alt-texta myndar
+pdfjs-image-alt-text-settings-button-label = Stillingar fyrir alt-texta myndar
+pdfjs-editor-alt-text-settings-dialog-label = Stillingar fyrir alt-texta myndar
+pdfjs-editor-alt-text-settings-automatic-title = Sjálfvirkur alt-myndatexti
+pdfjs-editor-alt-text-settings-create-model-button-label = Útbúa alt-myndatexta sjálfvirkt
+pdfjs-editor-alt-text-settings-create-model-description = Stingur upp á lýsingum til að hjálpa fólki sem getur ekki séð myndina eða þegar myndin hleðst ekki inn.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Gervigreindarlíkan alt-myndatexta ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Keyrir staðbundið á tækinu þínu svo gögnin þín haldast undir þinni stjórn. Nauðsynlegt fyrir sjálfvirka alt-myndatexta.
+pdfjs-editor-alt-text-settings-delete-model-button = Eyða
+pdfjs-editor-alt-text-settings-download-model-button = Sækja
+pdfjs-editor-alt-text-settings-downloading-model-button = Sæki…
+pdfjs-editor-alt-text-settings-editor-title = Ritill fyrir alt-myndatexta
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Sýna alt-myndatextaritil strax þegar mynd er bætt við
+pdfjs-editor-alt-text-settings-show-dialog-description = Hjálpar þér að tryggja að allar myndirnar þínar séu með alt-myndatexta.
+pdfjs-editor-alt-text-settings-close-button = Loka
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-stamp-added-alert = Mynd bætt við
+pdfjs-editor-signature-added-alert = Undirritun bætt við
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Áherslulitun fjarlægð
+pdfjs-editor-undo-bar-message-freetext = Texti fjarlægður
+pdfjs-editor-undo-bar-message-ink = Teikning fjarlægð
+pdfjs-editor-undo-bar-message-stamp = Mynd fjarlægð
+pdfjs-editor-undo-bar-message-signature = Undirskrift fjarlægð
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } glósa fjarlægð
+ *[other] { $count } glósur fjarlægðar
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Afturkalla
+pdfjs-editor-undo-bar-undo-button-label = Afturkalla
+pdfjs-editor-undo-bar-close-button =
+ .title = Loka
+pdfjs-editor-undo-bar-close-button-label = Loka
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Þessi gluggi gerir notandanum kleift að búa til undirskrift til að bæta við PDF-skjal. Notandinn getur breytt nafninu (sem einnig þjónar sem alt-texti), og valið að vista undirskriftina til endurtekinnar notkunar.
+pdfjs-editor-add-signature-dialog-title = Bæta við undirskrift
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tegund
+ .title = Tegund
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Teikna
+ .title = Teikna
+pdfjs-editor-add-signature-image-button = Mynd
+ .title = Mynd
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Skrifaðu inn undirskriftina þína
+ .placeholder = Skrifaðu inn undirskriftina þína
+pdfjs-editor-add-signature-draw-placeholder = Teiknaðu undirskriftina þína
+pdfjs-editor-add-signature-draw-thickness-range-label = Þykkt
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Sverleiki teikningar: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Dragðu skrá hingað til að senda inn
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Eða skoðaðu myndskrár
+ *[other] Eða skoðaðu myndskrár
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Lýsing (alt-hjálpartexti)
+pdfjs-editor-add-signature-description-input =
+ .title = Lýsing (alt-hjálpartexti)
+pdfjs-editor-add-signature-description-default-when-drawing = Undirskrift
+pdfjs-editor-add-signature-clear-button-label = Hreinsa undirskrift
+pdfjs-editor-add-signature-clear-button =
+ .title = Hreinsa undirskrift
+pdfjs-editor-add-signature-save-checkbox = Vista undirskrift
+pdfjs-editor-add-signature-save-warning-message = Þú hefur náð hámarki 5 vistaðra undirskrifta. Fjarlægðu eina til að geta vistað fleiri.
+pdfjs-editor-add-signature-image-upload-error-title = Ekki tókst að senda inn mynd
+pdfjs-editor-add-signature-image-upload-error-description = Athugaðu nettenginguna þína eða prófaðu aðra mynd.
+pdfjs-editor-add-signature-image-no-data-error-title = Get ekki breytt þessari mynd í undirskrift
+pdfjs-editor-add-signature-image-no-data-error-description = Reyndu að senda inn aðra mynd.
+pdfjs-editor-add-signature-error-close-button = Loka
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Hætta við
+pdfjs-editor-add-signature-add-button = Bæta við
+pdfjs-editor-edit-signature-update-button = Uppfæra
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Fjarlægja vistaða undirskrift
+pdfjs-editor-delete-signature-button-label1 = Fjarlægja vistaða undirskrift
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Breyta lýsingu
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Breyta lýsingu
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/it/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/it/viewer.ftl
new file mode 100644
index 0000000..1ee05d1
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/it/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagina precedente
+pdfjs-previous-button-label = Precedente
+pdfjs-next-button =
+ .title = Pagina successiva
+pdfjs-next-button-label = Successiva
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = di { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } di { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Riduci zoom
+pdfjs-zoom-out-button-label = Riduci zoom
+pdfjs-zoom-in-button =
+ .title = Aumenta zoom
+pdfjs-zoom-in-button-label = Aumenta zoom
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Passa alla modalità presentazione
+pdfjs-presentation-mode-button-label = Modalità presentazione
+pdfjs-open-file-button =
+ .title = Apri file
+pdfjs-open-file-button-label = Apri
+pdfjs-print-button =
+ .title = Stampa
+pdfjs-print-button-label = Stampa
+pdfjs-save-button =
+ .title = Salva
+pdfjs-save-button-label = Salva
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Scarica
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Scarica
+pdfjs-bookmark-button =
+ .title = Pagina corrente (mostra URL della pagina corrente)
+pdfjs-bookmark-button-label = Pagina corrente
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Strumenti
+pdfjs-tools-button-label = Strumenti
+pdfjs-first-page-button =
+ .title = Vai alla prima pagina
+pdfjs-first-page-button-label = Vai alla prima pagina
+pdfjs-last-page-button =
+ .title = Vai all’ultima pagina
+pdfjs-last-page-button-label = Vai all’ultima pagina
+pdfjs-page-rotate-cw-button =
+ .title = Ruota in senso orario
+pdfjs-page-rotate-cw-button-label = Ruota in senso orario
+pdfjs-page-rotate-ccw-button =
+ .title = Ruota in senso antiorario
+pdfjs-page-rotate-ccw-button-label = Ruota in senso antiorario
+pdfjs-cursor-text-select-tool-button =
+ .title = Attiva strumento di selezione testo
+pdfjs-cursor-text-select-tool-button-label = Strumento di selezione testo
+pdfjs-cursor-hand-tool-button =
+ .title = Attiva strumento mano
+pdfjs-cursor-hand-tool-button-label = Strumento mano
+pdfjs-scroll-page-button =
+ .title = Utilizza scorrimento pagine
+pdfjs-scroll-page-button-label = Scorrimento pagine
+pdfjs-scroll-vertical-button =
+ .title = Scorri le pagine in verticale
+pdfjs-scroll-vertical-button-label = Scorrimento verticale
+pdfjs-scroll-horizontal-button =
+ .title = Scorri le pagine in orizzontale
+pdfjs-scroll-horizontal-button-label = Scorrimento orizzontale
+pdfjs-scroll-wrapped-button =
+ .title = Scorri le pagine in verticale, disponendole da sinistra a destra e andando a capo automaticamente
+pdfjs-scroll-wrapped-button-label = Scorrimento con a capo automatico
+pdfjs-spread-none-button =
+ .title = Non raggruppare pagine
+pdfjs-spread-none-button-label = Nessun raggruppamento
+pdfjs-spread-odd-button =
+ .title = Crea gruppi di pagine che iniziano con numeri di pagina dispari
+pdfjs-spread-odd-button-label = Raggruppamento dispari
+pdfjs-spread-even-button =
+ .title = Crea gruppi di pagine che iniziano con numeri di pagina pari
+pdfjs-spread-even-button-label = Raggruppamento pari
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Proprietà del documento…
+pdfjs-document-properties-button-label = Proprietà del documento…
+pdfjs-document-properties-file-name = Nome file:
+pdfjs-document-properties-file-size = Dimensione file:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } byte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } byte)
+pdfjs-document-properties-title = Titolo:
+pdfjs-document-properties-author = Autore:
+pdfjs-document-properties-subject = Oggetto:
+pdfjs-document-properties-keywords = Parole chiave:
+pdfjs-document-properties-creation-date = Data creazione:
+pdfjs-document-properties-modification-date = Data modifica:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Autore originale:
+pdfjs-document-properties-producer = Produttore PDF:
+pdfjs-document-properties-version = Versione PDF:
+pdfjs-document-properties-page-count = Conteggio pagine:
+pdfjs-document-properties-page-size = Dimensioni pagina:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = verticale
+pdfjs-document-properties-page-size-orientation-landscape = orizzontale
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Lettera
+pdfjs-document-properties-page-size-name-legal = Legale
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Visualizzazione web veloce:
+pdfjs-document-properties-linearized-yes = Sì
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Chiudi
+pdfjs-digital-signature-properties-view-certificate = Visualizza certificato
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Motivo: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Data e ora: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Firma secondaria ({ $count })
+ *[other] Firme secondarie ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparazione documento per la stampa…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Annulla
+pdfjs-printing-not-supported = Attenzione: la stampa non è completamente supportata da questo browser.
+pdfjs-printing-not-ready = Attenzione: il PDF non è ancora stato caricato completamente per la stampa.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Attiva/disattiva barra laterale
+pdfjs-toggle-sidebar-notification-button =
+ .title = Attiva/disattiva barra laterale (il documento contiene struttura/allegati/livelli)
+pdfjs-toggle-sidebar-button-label = Attiva/disattiva barra laterale
+pdfjs-document-outline-button =
+ .title = Visualizza la struttura del documento (doppio clic per visualizzare/comprimere tutti gli elementi)
+pdfjs-document-outline-button-label = Struttura documento
+pdfjs-attachments-button =
+ .title = Visualizza allegati
+pdfjs-attachments-button-label = Allegati
+pdfjs-layers-button =
+ .title = Visualizza livelli (doppio clic per ripristinare tutti i livelli allo stato predefinito)
+pdfjs-layers-button-label = Livelli
+pdfjs-thumbs-button =
+ .title = Mostra le miniature
+pdfjs-thumbs-button-label = Miniature
+pdfjs-current-outline-item-button =
+ .title = Trova elemento struttura corrente
+pdfjs-current-outline-item-button-label = Elemento struttura corrente
+pdfjs-findbar-button =
+ .title = Trova nel documento
+pdfjs-findbar-button-label = Trova
+pdfjs-additional-layers = Livelli aggiuntivi
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura della pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seleziona pagina { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Pagina { $page } di { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .placeholder = Trova nel documento…
+ .title = Trova
+pdfjs-find-previous-button =
+ .title = Trova l’occorrenza precedente del testo da cercare
+pdfjs-find-previous-button-label = Precedente
+pdfjs-find-next-button =
+ .title = Trova l’occorrenza successiva del testo da cercare
+pdfjs-find-next-button-label = Successivo
+pdfjs-find-highlight-checkbox = Evidenzia
+pdfjs-find-match-case-checkbox-label = Maiuscole/minuscole
+pdfjs-find-match-diacritics-checkbox-label = Segni diacritici
+pdfjs-find-entire-word-checkbox-label = Parole intere
+pdfjs-find-reached-top = Raggiunto l’inizio della pagina, continua dalla fine
+pdfjs-find-reached-bottom = Raggiunta la fine della pagina, continua dall’inizio
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } di { $total } corrispondenza
+ *[other] { $current } di { $total } corrispondenze
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Più di { $limit } corrispondenza
+ *[other] Più di { $limit } corrispondenze
+ }
+pdfjs-find-not-found = Testo non trovato
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Larghezza pagina
+pdfjs-page-scale-fit = Adatta a una pagina
+pdfjs-page-scale-auto = Zoom automatico
+pdfjs-page-scale-actual = Dimensioni effettive
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Si è verificato un errore durante il caricamento del PDF.
+pdfjs-invalid-file-error = File PDF non valido o danneggiato.
+pdfjs-missing-file-error = File PDF non disponibile.
+pdfjs-unexpected-response-error = Risposta imprevista del server
+pdfjs-rendering-error = Si è verificato un errore durante il rendering della pagina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Annotazione: { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Inserire la password per aprire questo file PDF.
+pdfjs-password-invalid = Password non corretta. Riprova.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Annulla
+pdfjs-web-fonts-disabled = I web font risultano disattivati: impossibile utilizzare i caratteri incorporati nel PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Testo
+pdfjs-editor-color-picker-free-text-input =
+ .title = Cambia colore del testo
+pdfjs-editor-free-text-button-label = Testo
+pdfjs-editor-ink-button =
+ .title = Disegna
+pdfjs-editor-color-picker-ink-input =
+ .title = Cambia colore del disegno
+pdfjs-editor-ink-button-label = Disegna
+pdfjs-editor-stamp-button =
+ .title = Aggiungi o rimuovi immagine
+pdfjs-editor-stamp-button-label = Aggiungi o rimuovi immagine
+pdfjs-editor-highlight-button =
+ .title = Evidenzia
+pdfjs-editor-highlight-button-label = Evidenzia
+pdfjs-highlight-floating-button1 =
+ .aria-label = Evidenzia
+ .title = Evidenzia
+pdfjs-highlight-floating-button-label = Evidenzia
+pdfjs-comment-floating-button =
+ .aria-label = Commenta
+ .title = Commenta
+pdfjs-comment-floating-button-label = Commenta
+pdfjs-editor-comment-button =
+ .aria-label = Commenta
+ .title = Commenta
+pdfjs-editor-comment-button-label = Commenta
+pdfjs-editor-signature-button =
+ .title = Aggiungi firma
+pdfjs-editor-signature-button-label = Aggiungi firma
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Modifica evidenziazioni
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Modifica disegni
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor firme: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Modifica immagini
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Rimuovi disegno
+pdfjs-editor-remove-freetext-button =
+ .title = Rimuovi testo
+pdfjs-editor-remove-stamp-button =
+ .title = Rimuovi immagine
+pdfjs-editor-remove-highlight-button =
+ .title = Rimuovi evidenziazione
+pdfjs-editor-remove-signature-button =
+ .title = Rimuovi firma
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Colore
+pdfjs-editor-free-text-size-input = Dimensione
+pdfjs-editor-ink-color-input = Colore
+pdfjs-editor-ink-thickness-input = Spessore
+pdfjs-editor-ink-opacity-input = Opacità
+pdfjs-editor-stamp-add-image-button =
+ .title = Aggiungi immagine
+pdfjs-editor-stamp-add-image-button-label = Aggiungi immagine
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Spessore
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Modifica lo spessore della selezione per elementi non testuali
+pdfjs-editor-add-signature-container =
+ .aria-label = Controlli firma e firme salvate
+pdfjs-editor-signature-add-signature-button =
+ .title = Aggiungi nuova firma
+pdfjs-editor-signature-add-signature-button-label = Aggiungi nuova firma
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firma salvata: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor di testo
+ .default-content = Inizia a digitare…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Commento
+ *[other] Commenti
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .aria-label = Chiudi la barra laterale
+ .title = Chiudi la barra laterale
+pdfjs-editor-comments-sidebar-close-button-label = Chiudi la barra laterale
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Hai notato qualcosa di interessante? Evidenzialo e aggiungi un commento.
+pdfjs-editor-comments-sidebar-no-comments-link = Ulteriori informazioni
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Testo alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Modifica testo alternativo
+pdfjs-editor-alt-text-dialog-label = Scegli un’opzione
+pdfjs-editor-alt-text-dialog-description = Il testo alternativo (“alt text”) aiuta quando le persone non possono vedere l’immagine o quando l’immagine non viene caricata.
+pdfjs-editor-alt-text-add-description-label = Aggiungi una descrizione
+pdfjs-editor-alt-text-add-description-description = Punta a una o due frasi che descrivono l’argomento, l’ambientazione o le azioni.
+pdfjs-editor-alt-text-mark-decorative-label = Contrassegna come decorativa
+pdfjs-editor-alt-text-mark-decorative-description = Viene utilizzato per immagini ornamentali, come bordi o filigrane.
+pdfjs-editor-alt-text-cancel-button = Annulla
+pdfjs-editor-alt-text-save-button = Salva
+pdfjs-editor-alt-text-decorative-tooltip = Contrassegnata come decorativa
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Ad esempio, “Un giovane si siede a tavola per mangiare”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Testo alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Angolo in alto a sinistra — ridimensiona
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Lato superiore nel mezzo — ridimensiona
+pdfjs-editor-resizer-top-right =
+ .aria-label = Angolo in alto a destra — ridimensiona
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Lato destro nel mezzo — ridimensiona
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Angolo in basso a destra — ridimensiona
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Lato inferiore nel mezzo — ridimensiona
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Angolo in basso a sinistra — ridimensiona
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Lato sinistro nel mezzo — ridimensiona
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Colore evidenziatore
+pdfjs-editor-colorpicker-button =
+ .title = Cambia colore
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Colori disponibili
+pdfjs-editor-colorpicker-yellow =
+ .title = Giallo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Blu
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Rosso
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostra tutto
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostra tutto
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Modifica testo alternativo (descrizione dell’immagine)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Aggiungi testo alternativo (descrizione dell’immagine)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Scrivi qui la tua descrizione…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Breve descrizione per le persone che non possono vedere l’immagine, o mostrata quando l’immagine non si carica.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Questo testo alternativo è stato creato automaticamente e potrebbe non essere accurato.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Ulteriori informazioni
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crea automaticamente testo alternativo
+pdfjs-editor-new-alt-text-not-now-button = Non adesso
+pdfjs-editor-new-alt-text-error-title = Impossibile creare automaticamente il testo alternativo
+pdfjs-editor-new-alt-text-error-description = Scrivi il testo alternativo o riprova più tardi.
+pdfjs-editor-new-alt-text-error-close-button = Chiudi
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Download in corso del modello IA per il testo alternativo ({ $downloadedSize } di { $totalSize } MB)
+ .aria-valuetext = Download in corso del modello IA per il testo alternativo ({ $downloadedSize } di { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Aggiunto testo alternativo
+pdfjs-editor-new-alt-text-added-button-label = Aggiunto testo alternativo
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Testo alternativo mancante
+pdfjs-editor-new-alt-text-missing-button-label = Testo alternativo mancante
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Verifica testo alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Verifica testo alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creato automaticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Impostazioni testo alternativo per le immagini
+pdfjs-image-alt-text-settings-button-label = Impostazioni testo alternativo per le immagini
+pdfjs-editor-alt-text-settings-dialog-label = Impostazioni testo alternativo per le immagini
+pdfjs-editor-alt-text-settings-automatic-title = Testo alternativo automatico
+pdfjs-editor-alt-text-settings-create-model-button-label = Crea testo alternativo automaticamente
+pdfjs-editor-alt-text-settings-create-model-description = Suggerisce una descrizione per le persone che non possono vedere l’immagine, o mostrata quando l’immagine non si carica.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modello IA per il testo alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Viene eseguito localmente sul tuo dispositivo in modo che i tuoi dati rimangano riservati. È richiesto per la generazione automatica del testo alternativo.
+pdfjs-editor-alt-text-settings-delete-model-button = Elimina
+pdfjs-editor-alt-text-settings-download-model-button = Scarica
+pdfjs-editor-alt-text-settings-downloading-model-button = Download…
+pdfjs-editor-alt-text-settings-editor-title = Modifica testo alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostra l’editor del testo alternativo non appena si aggiunge un’immagine
+pdfjs-editor-alt-text-settings-show-dialog-description = Ti aiuta ad assicurarti che tutte le tue immagini abbiano il testo alternativo.
+pdfjs-editor-alt-text-settings-close-button = Chiudi
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Aggiunta evidenziazione
+pdfjs-editor-freetext-added-alert = Aggiunto testo
+pdfjs-editor-ink-added-alert = Aggiunto disegno
+pdfjs-editor-stamp-added-alert = Aggiunta immagine
+pdfjs-editor-signature-added-alert = Aggiunta firma
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Evidenziazione rimossa
+pdfjs-editor-undo-bar-message-freetext = Testo rimosso
+pdfjs-editor-undo-bar-message-ink = Disegno rimosso
+pdfjs-editor-undo-bar-message-stamp = Immagine rimossa
+pdfjs-editor-undo-bar-message-signature = Firma rimossa
+pdfjs-editor-undo-bar-message-comment = Commento rimosso
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotazione rimossa
+ *[other] { $count } annotazioni rimosse
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Annulla
+pdfjs-editor-undo-bar-undo-button-label = Annulla
+pdfjs-editor-undo-bar-close-button =
+ .title = Chiudi
+pdfjs-editor-undo-bar-close-button-label = Chiudi
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Questa finestra consente all’utente di creare una firma da aggiungere a un documento PDF. L’utente può modificare il nome (che verrà utilizzato anche come testo alternativo) e, se lo desidera, salvare la firma per riutilizzarla in futuro.
+pdfjs-editor-add-signature-dialog-title = Aggiungi una firma
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Scrivi
+ .title = Scrivi
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Disegna
+ .title = Disegna
+pdfjs-editor-add-signature-image-button = Immagine
+ .title = Immagine
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Digita la tua firma
+ .placeholder = Digita la tua firma
+pdfjs-editor-add-signature-draw-placeholder = Disegna la tua firma
+pdfjs-editor-add-signature-draw-thickness-range-label = Spessore
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Spessore del tratto: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Trascina un file qui per caricarlo
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Oppure scegli un file immagine
+ *[other] Oppure sfoglia i file immagine
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descrizione (testo alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descrizione (testo alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Firma
+pdfjs-editor-add-signature-clear-button-label = Cancella firma
+pdfjs-editor-add-signature-clear-button =
+ .title = Cancella firma
+pdfjs-editor-add-signature-save-checkbox = Salva firma
+pdfjs-editor-add-signature-save-warning-message = Hai raggiunto il limite di 5 firme salvate. Rimuovine una per salvarne altre.
+pdfjs-editor-add-signature-image-upload-error-title = Impossibile caricare l’immagine
+pdfjs-editor-add-signature-image-upload-error-description = Controlla la connessione di rete o prova con un’altra immagine.
+pdfjs-editor-add-signature-image-no-data-error-title = Impossibile convertire questa immagine in una firma
+pdfjs-editor-add-signature-image-no-data-error-description = Prova a caricare un’altra immagine.
+pdfjs-editor-add-signature-error-close-button = Chiudi
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Annulla
+pdfjs-editor-add-signature-add-button = Aggiungi
+pdfjs-editor-edit-signature-update-button = Aggiorna
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Modifica commento
+pdfjs-editor-edit-comment-popup-button =
+ .title = Modifica commento
+pdfjs-editor-delete-comment-popup-button-label = Elimina commento
+pdfjs-editor-delete-comment-popup-button =
+ .title = Elimina commento
+pdfjs-show-comment-button =
+ .title = Mostra commento
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Modifica commento
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aggiorna
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Aggiungi commento
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Aggiungi
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Inizia a digitare…
+pdfjs-editor-edit-comment-dialog-cancel-button = Annulla
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Aggiungi commento
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Attiva/disattiva barra laterale (il documento contiene miniature, struttura, allegati, livelli)
+pdfjs-toggle-views-manager-button1-label = Gestisci pagine
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra laterale
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Regolatore della larghezza della barra laterale
+pdfjs-views-manager-view-selector-button =
+ .title = Viste
+pdfjs-views-manager-view-selector-button-label = Viste
+pdfjs-views-manager-pages-title = Pagine
+pdfjs-views-manager-outlines-title1 = Struttura del documento
+ .title = Struttura del documento (doppio clic per espandere/comprimere tutti gli elementi)
+pdfjs-views-manager-attachments-title = Allegati
+pdfjs-views-manager-layers-title1 = Livelli
+ .title = Livelli (doppio clic per ripristinare tutti i livelli allo stato predefinito)
+pdfjs-views-manager-pages-option-label = Pagine
+pdfjs-views-manager-outlines-option-label = Struttura del documento
+pdfjs-views-manager-attachments-option-label = Allegati
+pdfjs-views-manager-layers-option-label = Livelli
+pdfjs-views-manager-add-file-button =
+ .title = Aggiungi file
+pdfjs-views-manager-add-file-button-label = Aggiungi file
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selezionata
+ *[other] { $count } selezionate
+ }
+pdfjs-views-manager-pages-status-none-action-label = Seleziona pagine
+pdfjs-views-manager-pages-status-action-button-label = Gestisci
+pdfjs-views-manager-pages-status-copy-button-label = Copia
+pdfjs-views-manager-pages-status-cut-button-label = Taglia
+pdfjs-views-manager-pages-status-delete-button-label = Elimina
+pdfjs-views-manager-pages-status-export-selected-button-label = Esporta selezionate…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] { $count } pagina tagliata
+ *[other] { $count } pagine tagliate
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] { $count } pagina copiata
+ *[other] { $count } pagine copiate
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] { $count } pagina eliminata
+ *[other] { $count } pagine eliminate
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparazione file…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Caricamento file…
+pdfjs-views-manager-status-warning-cut-label = Taglio non riuscito. Ricarica la pagina e riprova.
+pdfjs-views-manager-status-warning-copy-label = Copia non riuscita. Ricarica la pagina e riprova.
+pdfjs-views-manager-status-warning-delete-label = Eliminazione non riuscita. Ricarica la pagina e riprova.
+pdfjs-views-manager-status-warning-save-label = Salvataggio non riuscito. Ricarica la pagina e prova di nuovo.
+pdfjs-views-manager-status-undo-button-label = Annulla
+pdfjs-views-manager-status-done-button-label = Fatto
+pdfjs-views-manager-status-close-button =
+ .title = Chiudi
+pdfjs-views-manager-status-close-button-label = Chiudi
+pdfjs-views-manager-paste-button-label = Incolla
+pdfjs-views-manager-paste-button-before =
+ .title = Incolla dopo la prima pagina
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Incolla dopo pagina { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVITÀ
+pdfjs-views-manager-waiting-for-file = Caricamento file…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gestisci pagine
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .aria-label = Proprietà firma digitale
+ .title = Proprietà firma digitale
+pdfjs-digital-signature-properties-button-label = Proprietà firma digitale
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Il documento è stato firmato con una firma digitale valida
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Il documento è stato firmato ma non è stato possibile verificare { $count } firma digitale
+ *[other] Il documento è stato firmato ma non è stato possibile verificare { $count } firme digitali
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Documento firmato con { $count } certificato non attendibile
+ *[other] Documento firmato con { $count } certificati non attendibili
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Documento firmato con { $count } certificato scaduto
+ *[other] Documento firmato con { $count } certificati scaduti
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Il documento contiene { $count } firma digitale non valida
+ *[other] Il documento contiene { $count } firme digitali non valide
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Documento firmato con { $count } certificato revocato
+ *[other] Documento firmato con { $count } certificati revocati
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stato: firma verificata
+pdfjs-digital-signature-properties-status-invalid = Stato: firma non valida
+pdfjs-digital-signature-properties-status-unknown = Stato: impossibile verificare (non supportato)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificato: affidabile ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificato: non disponibile
+pdfjs-digital-signature-properties-certificate-untrusted = Certificato: non attendibile
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificato: emittente sconosciuto ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificato: autofirmato ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificato: emittente non attendibile ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificato: scaduto
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificato: scaduto ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificato: revocato
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Rimuovi firma salvata
+pdfjs-editor-delete-signature-button-label1 = Rimuovi firma salvata
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Modifica descrizione
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Modifica descrizione
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ja/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ja/viewer.ftl
new file mode 100644
index 0000000..23139d1
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ja/viewer.ftl
@@ -0,0 +1,780 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = 前のページへ戻ります
+pdfjs-previous-button-label = 前へ
+pdfjs-next-button =
+ .title = 次のページへ進みます
+pdfjs-next-button-label = 次へ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ページ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = 表示を縮小します
+pdfjs-zoom-out-button-label = 縮小
+pdfjs-zoom-in-button =
+ .title = 表示を拡大します
+pdfjs-zoom-in-button-label = 拡大
+pdfjs-zoom-select =
+ .title = 拡大/縮小
+pdfjs-presentation-mode-button =
+ .title = プレゼンテーションモードに切り替えます
+pdfjs-presentation-mode-button-label = プレゼンテーションモード
+pdfjs-open-file-button =
+ .title = ファイルを開きます
+pdfjs-open-file-button-label = 開く
+pdfjs-print-button =
+ .title = 印刷します
+pdfjs-print-button-label = 印刷
+pdfjs-save-button =
+ .title = 保存します
+pdfjs-save-button-label = 保存
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ダウンロードします
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ダウンロード
+pdfjs-bookmark-button =
+ .title = 現在のページの URL です (現在のページを表示する URL)
+pdfjs-bookmark-button-label = 現在のページ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ツール
+pdfjs-tools-button-label = ツール
+pdfjs-first-page-button =
+ .title = 最初のページへ移動します
+pdfjs-first-page-button-label = 最初のページへ移動
+pdfjs-last-page-button =
+ .title = 最後のページへ移動します
+pdfjs-last-page-button-label = 最後のページへ移動
+pdfjs-page-rotate-cw-button =
+ .title = ページを右へ回転します
+pdfjs-page-rotate-cw-button-label = 右回転
+pdfjs-page-rotate-ccw-button =
+ .title = ページを左へ回転します
+pdfjs-page-rotate-ccw-button-label = 左回転
+pdfjs-cursor-text-select-tool-button =
+ .title = テキスト選択ツールを有効にします
+pdfjs-cursor-text-select-tool-button-label = テキスト選択ツール
+pdfjs-cursor-hand-tool-button =
+ .title = 手のひらツールを有効にします
+pdfjs-cursor-hand-tool-button-label = 手のひらツール
+pdfjs-scroll-page-button =
+ .title = ページ単位でスクロールします
+pdfjs-scroll-page-button-label = ページ単位でスクロール
+pdfjs-scroll-vertical-button =
+ .title = 縦スクロールにします
+pdfjs-scroll-vertical-button-label = 縦スクロール
+pdfjs-scroll-horizontal-button =
+ .title = 横スクロールにします
+pdfjs-scroll-horizontal-button-label = 横スクロール
+pdfjs-scroll-wrapped-button =
+ .title = 折り返しスクロールにします
+pdfjs-scroll-wrapped-button-label = 折り返しスクロール
+pdfjs-spread-none-button =
+ .title = 見開きにしません
+pdfjs-spread-none-button-label = 見開きにしない
+pdfjs-spread-odd-button =
+ .title = 奇数ページ開始で見開きにします
+pdfjs-spread-odd-button-label = 奇数ページ見開き
+pdfjs-spread-even-button =
+ .title = 偶数ページ開始で見開きにします
+pdfjs-spread-even-button-label = 偶数ページ見開き
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = 文書のプロパティ...
+pdfjs-document-properties-button-label = 文書のプロパティ...
+pdfjs-document-properties-file-name = ファイル名:
+pdfjs-document-properties-file-size = ファイルサイズ:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } バイト)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } バイト)
+pdfjs-document-properties-title = タイトル:
+pdfjs-document-properties-author = 作成者:
+pdfjs-document-properties-subject = 件名:
+pdfjs-document-properties-keywords = キーワード:
+pdfjs-document-properties-creation-date = 作成日:
+pdfjs-document-properties-modification-date = 更新日:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = アプリケーション:
+pdfjs-document-properties-producer = PDF 作成:
+pdfjs-document-properties-version = PDF のバージョン:
+pdfjs-document-properties-page-count = ページ数:
+pdfjs-document-properties-page-size = ページサイズ:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = 縦
+pdfjs-document-properties-page-size-orientation-landscape = 横
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = レター
+pdfjs-document-properties-page-size-name-legal = リーガル
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = ウェブ表示用に最適化:
+pdfjs-document-properties-linearized-yes = はい
+pdfjs-document-properties-linearized-no = いいえ
+pdfjs-document-properties-close-button = 閉じる
+pdfjs-digital-signature-properties-view-certificate = 証明書を表示
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = 理由: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = タイムスタンプ: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures = サブ署名 ({ $count } 筆)
+
+## Print
+
+pdfjs-print-progress-message = 文書の印刷を準備しています...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = キャンセル
+pdfjs-printing-not-supported = 警告: このブラウザーでは印刷が完全にサポートされていません。
+pdfjs-printing-not-ready = 警告: PDF を印刷するための読み込みが終了していません。
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = サイドバー表示を切り替えます
+pdfjs-toggle-sidebar-notification-button =
+ .title = サイドバー表示を切り替えます (文書に含まれるアウトライン / 添付 / レイヤー)
+pdfjs-toggle-sidebar-button-label = サイドバーの切り替え
+pdfjs-document-outline-button =
+ .title = 文書の目次を表示します (ダブルクリックで項目を開閉します)
+pdfjs-document-outline-button-label = 文書の目次
+pdfjs-attachments-button =
+ .title = 添付ファイルを表示します
+pdfjs-attachments-button-label = 添付ファイル
+pdfjs-layers-button =
+ .title = レイヤーを表示します (ダブルクリックですべてのレイヤーが初期状態に戻ります)
+pdfjs-layers-button-label = レイヤー
+pdfjs-thumbs-button =
+ .title = 縮小版を表示します
+pdfjs-thumbs-button-label = 縮小版
+pdfjs-current-outline-item-button =
+ .title = 現在のアウトライン項目を検索
+pdfjs-current-outline-item-button-label = 現在のアウトライン項目
+pdfjs-findbar-button =
+ .title = 文書内を検索します
+pdfjs-findbar-button-label = 検索
+pdfjs-additional-layers = 追加レイヤー
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } ページ
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } ページの縮小版
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = { $page } ページを選択します
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = { $page } / { $total } ページ
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = 検索
+ .placeholder = 文書内を検索...
+pdfjs-find-previous-button =
+ .title = 現在より前の位置で指定文字列が現れる部分を検索します
+pdfjs-find-previous-button-label = 前へ
+pdfjs-find-next-button =
+ .title = 現在より後の位置で指定文字列が現れる部分を検索します
+pdfjs-find-next-button-label = 次へ
+pdfjs-find-highlight-checkbox = すべて強調表示
+pdfjs-find-match-case-checkbox-label = 大文字/小文字を区別
+pdfjs-find-match-diacritics-checkbox-label = 発音区別符号を区別
+pdfjs-find-entire-word-checkbox-label = 単語一致
+pdfjs-find-reached-top = 文書先頭に到達したので末尾から続けて検索します
+pdfjs-find-reached-bottom = 文書末尾に到達したので先頭から続けて検索します
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = { $total } 件中 { $current } 件目
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = { $limit } 件以上一致
+pdfjs-find-not-found = 見つかりませんでした
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = 幅に合わせる
+pdfjs-page-scale-fit = ページのサイズに合わせる
+pdfjs-page-scale-auto = 自動ズーム
+pdfjs-page-scale-actual = 実際のサイズ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page } ページ
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF の読み込み中にエラーが発生しました。
+pdfjs-invalid-file-error = 無効または破損した PDF ファイル。
+pdfjs-missing-file-error = PDF ファイルが見つかりません。
+pdfjs-unexpected-response-error = サーバーから予期せぬ応答がありました。
+pdfjs-rendering-error = ページのレンダリング中にエラーが発生しました。
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } 注釈]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = この PDF ファイルを開くためのパスワードを入力してください。
+pdfjs-password-invalid = パスワードが正しくありません。もう一度試してください。
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = キャンセル
+pdfjs-web-fonts-disabled = ウェブフォントが無効になっています: 埋め込まれた PDF のフォントを使用できません。
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = フリーテキスト注釈を追加します
+pdfjs-editor-color-picker-free-text-input =
+ .title = テキスト色を変更します
+pdfjs-editor-free-text-button-label = フリーテキスト注釈
+pdfjs-editor-ink-button =
+ .title = インク注釈を追加します
+pdfjs-editor-color-picker-ink-input =
+ .title = インク色を変更します
+pdfjs-editor-ink-button-label = インク注釈
+pdfjs-editor-stamp-button =
+ .title = 画像を追加または編集します
+pdfjs-editor-stamp-button-label = 画像を追加または編集
+pdfjs-editor-highlight-button =
+ .title = 強調します
+pdfjs-editor-highlight-button-label = 強調
+pdfjs-highlight-floating-button1 =
+ .title = 強調します
+ .aria-label = 強調します
+pdfjs-highlight-floating-button-label = 強調
+pdfjs-comment-floating-button =
+ .title = コメントを追加します
+ .aria-label = コメントを追加します
+pdfjs-comment-floating-button-label = コメント
+pdfjs-editor-comment-button =
+ .title = コメントを編集します
+ .aria-label = コメントを編集します
+pdfjs-editor-comment-button-label = コメント
+pdfjs-editor-signature-button =
+ .title = 署名を追加します
+pdfjs-editor-signature-button-label = 署名を追加
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = 強調エディター
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = 描画エディター
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = 署名エディター: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = 画像エディター
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = インク注釈を削除します
+pdfjs-editor-remove-freetext-button =
+ .title = テキストを削除します
+pdfjs-editor-remove-stamp-button =
+ .title = 画像を削除します
+pdfjs-editor-remove-highlight-button =
+ .title = 強調を削除します
+pdfjs-editor-remove-signature-button =
+ .title = 署名を削除します
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = 色
+pdfjs-editor-free-text-size-input = サイズ
+pdfjs-editor-ink-color-input = 色
+pdfjs-editor-ink-thickness-input = 太さ
+pdfjs-editor-ink-opacity-input = 不透明度
+pdfjs-editor-stamp-add-image-button =
+ .title = 画像を追加します
+pdfjs-editor-stamp-add-image-button-label = 画像を追加
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = 太さ
+pdfjs-editor-free-highlight-thickness-title =
+ .title = テキスト以外のアイテムを強調する時の太さを変更します
+pdfjs-editor-add-signature-container =
+ .aria-label = 署名コントロールと保存された署名
+pdfjs-editor-signature-add-signature-button =
+ .title = 新しい署名を追加します
+pdfjs-editor-signature-add-signature-button-label = 新しい署名を追加
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = 保存された署名: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = フリーテキスト注釈エディター
+ .default-content = テキストを入力してください...
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title = コメント
+pdfjs-editor-comments-sidebar-close-button =
+ .title = サイドバーを閉じます
+ .aria-label = サイドバーを閉じる
+pdfjs-editor-comments-sidebar-close-button-label = サイドバーを閉じる
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = 気になることがあれば、選択してコメントを残してください。
+pdfjs-editor-comments-sidebar-no-comments-link = 詳細情報
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = 代替テキスト
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = 代替テキストを編集
+pdfjs-editor-alt-text-dialog-label = オプションの選択
+pdfjs-editor-alt-text-dialog-description = 代替テキストは画像が表示されない場合や読み込まれない場合にユーザーの助けになります。
+pdfjs-editor-alt-text-add-description-label = 説明を追加
+pdfjs-editor-alt-text-add-description-description = 対象や設定、動作を説明する短い文章を記入してください。
+pdfjs-editor-alt-text-mark-decorative-label = 装飾マークを付ける
+pdfjs-editor-alt-text-mark-decorative-description = これは区切り線やウォーターマークなどの装飾画像に使用されます。
+pdfjs-editor-alt-text-cancel-button = キャンセル
+pdfjs-editor-alt-text-save-button = 保存
+pdfjs-editor-alt-text-decorative-tooltip = 装飾マークが付いています
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = 例:「若い人がテーブルの席について食事をしています」
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = 代替テキスト
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = 左上隅 — サイズ変更
+pdfjs-editor-resizer-top-middle =
+ .aria-label = 上中央 — サイズ変更
+pdfjs-editor-resizer-top-right =
+ .aria-label = 右上隅 — サイズ変更
+pdfjs-editor-resizer-middle-right =
+ .aria-label = 右中央 — サイズ変更
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = 右下隅 — サイズ変更
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = 下中央 — サイズ変更
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = 左下隅 — サイズ変更
+pdfjs-editor-resizer-middle-left =
+ .aria-label = 左中央 — サイズ変更
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = 強調色
+pdfjs-editor-colorpicker-button =
+ .title = 色を変更します
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = 色の選択
+pdfjs-editor-colorpicker-yellow =
+ .title = 黄色
+pdfjs-editor-colorpicker-green =
+ .title = 緑色
+pdfjs-editor-colorpicker-blue =
+ .title = 青色
+pdfjs-editor-colorpicker-pink =
+ .title = ピンク色
+pdfjs-editor-colorpicker-red =
+ .title = 赤色
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = すべて表示
+# (^m^) en-US: .title = Show all
+pdfjs-editor-highlight-show-all-button =
+ .title = 強調の表示を切り替えます
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = 代替テキストを編集 (画像の説明)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = 代替テキストを追加 (画像の説明)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = ここに説明を記入してください...
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = 画像が読み込まれない場合や見えない人のための短い説明です。
+pdfjs-editor-new-alt-text-disclaimer1 = この代替テキストは自動的に生成されたため正確でない可能性があります。
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = 詳細情報
+pdfjs-editor-new-alt-text-create-automatically-button-label = 代替テキストを自動生成
+pdfjs-editor-new-alt-text-not-now-button = 後で
+pdfjs-editor-new-alt-text-error-title = 代替テキストを自動生成できませんでした
+pdfjs-editor-new-alt-text-error-description = ご自分で代替テキストを書くか後でもう一度試してください。
+pdfjs-editor-new-alt-text-error-close-button = 閉じる
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = 代替テキスト AI モデルをダウンロードしています ({ $downloadedSize } / { $totalSize } MB)
+ .aria-valuetext = 代替テキスト AI モデルをダウンロードしています ({ $downloadedSize } / { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = 代替テキストを追加しました
+pdfjs-editor-new-alt-text-added-button-label = 代替テキストを追加しました
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = 代替テキストがありません
+pdfjs-editor-new-alt-text-missing-button-label = 代替テキストがありません
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = 代替テキストをレビュー
+pdfjs-editor-new-alt-text-to-review-button-label = 代替テキストをレビュー
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = 自動生成されました: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = 画像の代替テキスト設定
+pdfjs-image-alt-text-settings-button-label = 画像の代替テキスト設定
+pdfjs-editor-alt-text-settings-dialog-label = 画像の代替テキスト設定
+pdfjs-editor-alt-text-settings-automatic-title = 自動代替テキスト
+pdfjs-editor-alt-text-settings-create-model-button-label = 代替テキストを自動生成
+pdfjs-editor-alt-text-settings-create-model-description = 画像が読み込まれない場合や見えない人のために説明を提案します。
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = 代替テキスト AI モデル ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = ローカルの端末上で実行されるためデータは非公開になります。代替テキストの自動生成に必要です。
+pdfjs-editor-alt-text-settings-delete-model-button = 削除
+pdfjs-editor-alt-text-settings-download-model-button = ダウンロード
+pdfjs-editor-alt-text-settings-downloading-model-button = ダウンロード中...
+pdfjs-editor-alt-text-settings-editor-title = 代替テキストエディター
+pdfjs-editor-alt-text-settings-show-dialog-button-label = 画像の追加時に代替テキストエディターを表示する
+pdfjs-editor-alt-text-settings-show-dialog-description = すべての画像に代替テキストを追加する助けになります。
+pdfjs-editor-alt-text-settings-close-button = 閉じる
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = 強調表示を追加しました
+pdfjs-editor-freetext-added-alert = フリーテキスト注釈を追加しました
+pdfjs-editor-ink-added-alert = インク注釈を追加しました
+pdfjs-editor-stamp-added-alert = 画像を追加しました
+pdfjs-editor-signature-added-alert = 署名を追加しました
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = 強調表示が削除されました
+pdfjs-editor-undo-bar-message-freetext = フリーテキスト注釈が削除されました
+pdfjs-editor-undo-bar-message-ink = インク注釈が削除されました
+pdfjs-editor-undo-bar-message-stamp = 画像が削除されました
+pdfjs-editor-undo-bar-message-signature = 署名が削除されました
+pdfjs-editor-undo-bar-message-comment = コメントが削除されました
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = { $count } 個の注釈が削除されました
+pdfjs-editor-undo-bar-undo-button =
+ .title = 元に戻す
+pdfjs-editor-undo-bar-undo-button-label = 元に戻す
+pdfjs-editor-undo-bar-close-button =
+ .title = 閉じる
+pdfjs-editor-undo-bar-close-button-label = 閉じる
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = このダイアログではユーザーが署名を作成して PDF 文書に追加できます。
+pdfjs-editor-add-signature-dialog-title = 署名を追加
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = タイプ
+ .title = キーボード入力します
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = 手書き
+ .title = 手書き入力します
+pdfjs-editor-add-signature-image-button = 画像
+ .title = 画像を指定します
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = 署名をキーボード入力
+ .placeholder = 署名をキーボード入力
+pdfjs-editor-add-signature-draw-placeholder = 署名を手書き入力
+pdfjs-editor-add-signature-draw-thickness-range-label = 線の太さ
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = 線の太さ: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = ファイルをここにドラッグしてアップロード
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] または画像ファイルを選択
+ *[other] または画像ファイルを参照
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = 説明 (代替テキスト)
+pdfjs-editor-add-signature-description-input =
+ .title = 説明 (代替テキスト) を追加します
+pdfjs-editor-add-signature-description-default-when-drawing = 署名
+pdfjs-editor-add-signature-clear-button-label = 署名を消去
+pdfjs-editor-add-signature-clear-button =
+ .title = 署名を消去します
+pdfjs-editor-add-signature-save-checkbox = 署名を保存
+pdfjs-editor-add-signature-save-warning-message = 保存された署名が上限の 5 個に達しました。さらに保存するにはいずれかを削除してください。
+pdfjs-editor-add-signature-image-upload-error-title = 画像をアップロードできません
+pdfjs-editor-add-signature-image-upload-error-description = ネットワーク接続を確認するか別の画像を試してください。
+pdfjs-editor-add-signature-image-no-data-error-title = この画像は署名に変換できません
+pdfjs-editor-add-signature-image-no-data-error-description = 別の画像をアップロードしてください。
+pdfjs-editor-add-signature-error-close-button = 閉じる
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = キャンセル
+pdfjs-editor-add-signature-add-button = 追加
+pdfjs-editor-edit-signature-update-button = 更新
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = コメントを編集
+pdfjs-editor-edit-comment-popup-button =
+ .title = コメントを編集します
+pdfjs-editor-delete-comment-popup-button-label = コメントを削除
+pdfjs-editor-delete-comment-popup-button =
+ .title = コメントを削除します
+pdfjs-show-comment-button =
+ .title = コメントを表示します
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = コメントを編集
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = 更新
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = コメントを追加
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = 追加
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = コメントを入力してください...
+pdfjs-editor-edit-comment-dialog-cancel-button = キャンセル
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = コメントを追加します
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = サイドバーを切り替えます (文書に含まれるサムネイル、アウトライン、添付データ、レイヤー)
+pdfjs-toggle-views-manager-button1-label = ページを管理
+pdfjs-views-manager-sidebar =
+ .aria-label = サイドバー
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = サイドバーの幅変更
+pdfjs-views-manager-view-selector-button =
+ .title = ビュー
+pdfjs-views-manager-view-selector-button-label = ビュー
+pdfjs-views-manager-pages-title = ページ
+pdfjs-views-manager-outlines-title1 = 文書のアウトライン
+ .title = 文書のアウトライン (ダブルクリックですべての項目を展開/折りたたみ)
+pdfjs-views-manager-attachments-title = 添付データ
+pdfjs-views-manager-layers-title1 = レイヤー
+ .title = レイヤー (ダブルクリックですべてのレイヤーを既定状態にリセット)
+pdfjs-views-manager-pages-option-label = ページ
+pdfjs-views-manager-outlines-option-label = 文書のアウトライン
+pdfjs-views-manager-attachments-option-label = 添付データ
+pdfjs-views-manager-layers-option-label = レイヤー
+pdfjs-views-manager-add-file-button =
+ .title = ファイルを追加します
+pdfjs-views-manager-add-file-button-label = ファイルを追加
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label = { $count } ページ選択中
+pdfjs-views-manager-pages-status-none-action-label = ページを選択
+pdfjs-views-manager-pages-status-action-button-label = 管理
+pdfjs-views-manager-pages-status-copy-button-label = コピー
+pdfjs-views-manager-pages-status-cut-button-label = 切り取り
+pdfjs-views-manager-pages-status-delete-button-label = 削除
+pdfjs-views-manager-pages-status-export-selected-button-label = 選択したページをエクスポート...
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label = { $count } ページを切り取りました
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label = { $count } ページをコピーしました
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label = { $count } ページを削除しました
+pdfjs-views-manager-pages-status-waiting-ready-label = ファイルを準備しています...
+pdfjs-views-manager-pages-status-waiting-uploading-label = ファイルをアップロードしています...
+pdfjs-views-manager-status-warning-cut-label = 切り取りできませんでした。ページを更新してもう一度試してください。
+pdfjs-views-manager-status-warning-copy-label = コピーできませんでした。ページを更新してもう一度試してください。
+pdfjs-views-manager-status-warning-delete-label = 削除できませんでした。ページを更新してもう一度試してください。
+pdfjs-views-manager-status-warning-save-label = 保存できませんでした。ページを更新してもう一度試してください。
+pdfjs-views-manager-status-undo-button-label = 元に戻す
+pdfjs-views-manager-status-done-button-label = 完了
+pdfjs-views-manager-status-close-button =
+ .title = 閉じる
+pdfjs-views-manager-status-close-button-label = 閉じる
+pdfjs-views-manager-paste-button-label = 貼り付け
+pdfjs-views-manager-paste-button-before =
+ .title = 最初のページの前に貼り付けます
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = { $page } ページの後に貼り付けます
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = 新機能
+pdfjs-views-manager-waiting-for-file = ファイルをアップロードしています...
+pdfjs-toggle-views-manager-button1 =
+ .title = ページを管理
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = デジタル署名のプロパティ
+ .aria-label = デジタル署名のプロパティ
+pdfjs-digital-signature-properties-button-label = デジタル署名のプロパティ
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = 文書は検証されたデジタル署名で署名されています
+pdfjs-digital-signature-properties-banner-unknown = 文書は署名されていますが、{ $count } 筆のデジタル署名が検証できません
+pdfjs-digital-signature-properties-banner-untrusted = 文書は { $count } 筆の信頼できないデジタル署名で署名されています
+pdfjs-digital-signature-properties-banner-expired = 文書は { $count } 枚の有効期限が切れた証明書で署名されています
+pdfjs-digital-signature-properties-banner-invalid = 文書には { $count } 筆の不正なデジタル署名があります
+pdfjs-digital-signature-properties-banner-revoked = 文書は { $count } 枚の破棄された証明書で署名されています
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = 状態: 検証された証明書
+pdfjs-digital-signature-properties-status-invalid = 状態: 不正な証明書
+pdfjs-digital-signature-properties-status-unknown = 状態: 検証不可 (未サポート)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = 証明書: 信頼されている ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = 証明書: 利用不可
+pdfjs-digital-signature-properties-certificate-untrusted = 証明書: 信頼できない
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = 証明書: 発行者不明 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = 証明書: 自己署名 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = 証明書: 信頼できない発行者 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = 証明書: 有効期限切れ
+pdfjs-digital-signature-properties-certificate-expired-with-date = 証明書: 有効期限切れ ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = 証明書: 破棄
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = 保存された署名を削除します
+pdfjs-editor-delete-signature-button-label1 = 保存された署名を削除
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = 説明を編集
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = 説明の編集
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ka/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ka/viewer.ftl
new file mode 100644
index 0000000..43a4cff
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ka/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = წინა გვერდი
+pdfjs-previous-button-label = წინა
+pdfjs-next-button =
+ .title = შემდეგი გვერდი
+pdfjs-next-button-label = შემდეგი
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = გვერდი
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount }-დან
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } { $pagesCount }-დან)
+pdfjs-zoom-out-button =
+ .title = ზომის შემცირება
+pdfjs-zoom-out-button-label = დაშორება
+pdfjs-zoom-in-button =
+ .title = ზომის გაზრდა
+pdfjs-zoom-in-button-label = მოახლოება
+pdfjs-zoom-select =
+ .title = ზომა
+pdfjs-presentation-mode-button =
+ .title = წარდგენის რეჟიმზე გადართვა
+pdfjs-presentation-mode-button-label = წარდგენის რეჟიმი
+pdfjs-open-file-button =
+ .title = ფაილის გახსნა
+pdfjs-open-file-button-label = გახსნა
+pdfjs-print-button =
+ .title = ამობეჭდვა
+pdfjs-print-button-label = ამობეჭდვა
+pdfjs-save-button =
+ .title = შენახვა
+pdfjs-save-button-label = შენახვა
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ჩამოტვირთვა
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ჩამოტვირთვა
+pdfjs-bookmark-button =
+ .title = მიმდინარე გვერდი (ბმული ამ გვერდისთვის)
+pdfjs-bookmark-button-label = მიმდინარე გვერდი
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ხელსაწყოები
+pdfjs-tools-button-label = ხელსაწყოები
+pdfjs-first-page-button =
+ .title = პირველ გვერდზე გადასვლა
+pdfjs-first-page-button-label = პირველ გვერდზე გადასვლა
+pdfjs-last-page-button =
+ .title = ბოლო გვერდზე გადასვლა
+pdfjs-last-page-button-label = ბოლო გვერდზე გადასვლა
+pdfjs-page-rotate-cw-button =
+ .title = საათის ისრის მიმართულებით შებრუნება
+pdfjs-page-rotate-cw-button-label = მარჯვნივ გადაბრუნება
+pdfjs-page-rotate-ccw-button =
+ .title = საათის ისრის საპირისპიროდ შებრუნება
+pdfjs-page-rotate-ccw-button-label = მარცხნივ გადაბრუნება
+pdfjs-cursor-text-select-tool-button =
+ .title = მოსანიშნი მაჩვენებლის გამოყენება
+pdfjs-cursor-text-select-tool-button-label = მოსანიშნი მაჩვენებელი
+pdfjs-cursor-hand-tool-button =
+ .title = გადასაადგილებელი მაჩვენებლის გამოყენება
+pdfjs-cursor-hand-tool-button-label = გადასაადგილებელი
+pdfjs-scroll-page-button =
+ .title = გვერდზე გადაადგილების გამოყენება
+pdfjs-scroll-page-button-label = გვერდშივე გადაადგილება
+pdfjs-scroll-vertical-button =
+ .title = გვერდების შვეულად ჩვენება
+pdfjs-scroll-vertical-button-label = შვეული გადაადგილება
+pdfjs-scroll-horizontal-button =
+ .title = გვერდების თარაზულად ჩვენება
+pdfjs-scroll-horizontal-button-label = განივი გადაადგილება
+pdfjs-scroll-wrapped-button =
+ .title = გვერდების ცხრილურად ჩვენება
+pdfjs-scroll-wrapped-button-label = ცხრილური გადაადგილება
+pdfjs-spread-none-button =
+ .title = ორ გვერდზე გაშლის გარეშე
+pdfjs-spread-none-button-label = ცალგვერდიანი ჩვენება
+pdfjs-spread-odd-button =
+ .title = ორ გვერდზე გაშლა კენტი გვერდიდან
+pdfjs-spread-odd-button-label = ორ გვერდზე კენტიდან
+pdfjs-spread-even-button =
+ .title = ორ გვერდზე გაშლა ლუწი გვერდიდან
+pdfjs-spread-even-button-label = ორ გვერდზე ლუწიდან
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = დოკუმენტის შესახებ…
+pdfjs-document-properties-button-label = დოკუმენტის შესახებ…
+pdfjs-document-properties-file-name = ფაილის სახელი:
+pdfjs-document-properties-file-size = ფაილის მოცულობა:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } კბაიტი ({ $b } ბაიტი)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } მბაიტი ({ $b } ბაიტი)
+pdfjs-document-properties-title = სათაური:
+pdfjs-document-properties-author = შემქმნელი:
+pdfjs-document-properties-subject = თემა:
+pdfjs-document-properties-keywords = საკვანძო სიტყვები:
+pdfjs-document-properties-creation-date = შექმნის დრო:
+pdfjs-document-properties-modification-date = ჩასწორების დრო:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = შემდგენელი:
+pdfjs-document-properties-producer = PDF-შემდგენელი:
+pdfjs-document-properties-version = PDF-ვერსია:
+pdfjs-document-properties-page-count = გვერდები:
+pdfjs-document-properties-page-size = გვერდის ზომა:
+pdfjs-document-properties-page-size-unit-inches = დუიმი
+pdfjs-document-properties-page-size-unit-millimeters = მმ
+pdfjs-document-properties-page-size-orientation-portrait = შვეულად
+pdfjs-document-properties-page-size-orientation-landscape = თარაზულად
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = მსუბუქი ვებჩვენება:
+pdfjs-document-properties-linearized-yes = დიახ
+pdfjs-document-properties-linearized-no = არა
+pdfjs-document-properties-close-button = დახურვა
+pdfjs-digital-signature-properties-view-certificate = სერტიფიკატის ნახვა
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = მიზეზი: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = დროის ნიშნული: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] ქვეხელმოწერები ({ $count })
+ *[other] ქვეხელმოწერები ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = დოკუმენტი მზადდება ამოსაბეჭდად…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = გაუქმება
+pdfjs-printing-not-supported = გაფრთხილება: ამობეჭდვა ამ ბრაუზერში არაა სრულად მხარდაჭერილი.
+pdfjs-printing-not-ready = გაფრთხილება: PDF სრულად ჩატვირთული არაა, ამობეჭდვის დასაწყებად.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = გვერდითა ზოლის გამოჩენა/დამალვა
+pdfjs-toggle-sidebar-notification-button =
+ .title = გვერდითი ზოლის გამოჩენა (შეიცავს სარჩევს/დანართს/შრეებს)
+pdfjs-toggle-sidebar-button-label = გვერდითა ზოლის გამოჩენა/დამალვა
+pdfjs-document-outline-button =
+ .title = დოკუმენტის სარჩევის ჩვენება (ორმაგი წკაპით თითოეულის ჩამოშლა/აკეცვა)
+pdfjs-document-outline-button-label = დოკუმენტის სარჩევი
+pdfjs-attachments-button =
+ .title = დანართების ჩვენება
+pdfjs-attachments-button-label = დანართები
+pdfjs-layers-button =
+ .title = შრეების გამოჩენა (ორმაგი წკაპით ყველა შრის ნაგულისხმევზე დაბრუნება)
+pdfjs-layers-button-label = შრეები
+pdfjs-thumbs-button =
+ .title = შეთვალიერება
+pdfjs-thumbs-button-label = ესკიზები
+pdfjs-current-outline-item-button =
+ .title = მიმდინარე გვერდის მონახვა სარჩევში
+pdfjs-current-outline-item-button-label = მიმდინარე გვერდი სარჩევში
+pdfjs-findbar-button =
+ .title = პოვნა დოკუმენტში
+pdfjs-findbar-button-label = ძიება
+pdfjs-additional-layers = დამატებითი შრეები
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = გვერდი { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = გვერდის შეთვალიერება { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = მონიშნეთ { $page } გვერდი
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = გვერდი { $page }, სულ { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ძიება
+ .placeholder = პოვნა დოკუმენტში…
+pdfjs-find-previous-button =
+ .title = წინა დამთხვევის პოვნა
+pdfjs-find-previous-button-label = წინა
+pdfjs-find-next-button =
+ .title = მომდევნო დამთხვევის პოვნა
+pdfjs-find-next-button-label = შემდეგი
+pdfjs-find-highlight-checkbox = ყველაფრის მონიშვნა
+pdfjs-find-match-case-checkbox-label = მთავრულით
+pdfjs-find-match-diacritics-checkbox-label = ნიშნებით
+pdfjs-find-entire-word-checkbox-label = მთლიანი სიტყვები
+pdfjs-find-reached-top = მიღწეულია დოკუმენტის დასაწყისი, გრძელდება ბოლოდან
+pdfjs-find-reached-bottom = მიღწეულია დოკუმენტის ბოლო, გრძელდება დასაწყისიდან
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] თანხვედრა { $current }, სულ { $total }
+ *[other] თანხვედრა { $current }, სულ { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] არანაკლებ { $limit } თანხვედრა
+ *[other] არანაკლებ { $limit } თანხვედრა
+ }
+pdfjs-find-not-found = ფრაზა ვერ მოიძებნა
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = გვერდის სიგანეზე
+pdfjs-page-scale-fit = მთლიანი გვერდი
+pdfjs-page-scale-auto = ავტომატური
+pdfjs-page-scale-actual = საწყისი ზომა
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = გვერდი { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = შეცდომა, PDF-ფაილის ჩატვირთვისას.
+pdfjs-invalid-file-error = არამართებული ან დაზიანებული PDF-ფაილი.
+pdfjs-missing-file-error = ნაკლული PDF-ფაილი.
+pdfjs-unexpected-response-error = სერვერის მოულოდნელი პასუხი.
+pdfjs-rendering-error = შეცდომა, გვერდის ჩვენებისას.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } შენიშვნა]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = შეიყვანეთ პაროლი PDF-ფაილის გასახსნელად.
+pdfjs-password-invalid = არასწორი პაროლი. გთხოვთ, სცადოთ ხელახლა.
+pdfjs-password-ok-button = კარგი
+pdfjs-password-cancel-button = გაუქმება
+pdfjs-web-fonts-disabled = ვებშრიფტები გამორთულია: ჩაშენებული PDF-შრიფტების გამოყენება ვერ ხერხდება.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = წარწერა
+pdfjs-editor-color-picker-free-text-input =
+ .title = წარწერის ფერის შეცვლა
+pdfjs-editor-free-text-button-label = წარწერა
+pdfjs-editor-ink-button =
+ .title = მოხაზვა
+pdfjs-editor-color-picker-ink-input =
+ .title = მოხაზულის ფერის შეცვლა
+pdfjs-editor-ink-button-label = მოხაზვა
+pdfjs-editor-stamp-button =
+ .title = სურათების დართვა ან ჩასწორება
+pdfjs-editor-stamp-button-label = სურათების დართვა ან ჩასწორება
+pdfjs-editor-highlight-button =
+ .title = მონიშვნა
+pdfjs-editor-highlight-button-label = მონიშვნა
+pdfjs-highlight-floating-button1 =
+ .title = მონიშვნა
+ .aria-label = მონიშვნა
+pdfjs-highlight-floating-button-label = მონიშვნა
+pdfjs-comment-floating-button =
+ .title = შენიშვნა
+ .aria-label = შენიშვნა
+pdfjs-comment-floating-button-label = შენიშვნა
+pdfjs-editor-comment-button =
+ .title = შენიშვნა
+ .aria-label = შენიშვნა
+pdfjs-editor-comment-button-label = შენიშვნა
+pdfjs-editor-signature-button =
+ .title = ხელმოწერის დამატება
+pdfjs-editor-signature-button-label = ხელმოწერის დამატება
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = მონიშვნის ჩასწორება
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = მოხაზულის ჩასწორება
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = ხელმოწერის ჩასწორება: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = სურათის ჩასწორება
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = მოხაზულის მოცილება
+pdfjs-editor-remove-freetext-button =
+ .title = წარწერის მოცილება
+pdfjs-editor-remove-stamp-button =
+ .title = სურათის მოცილება
+pdfjs-editor-remove-highlight-button =
+ .title = მონიშვნის მოცილება
+pdfjs-editor-remove-signature-button =
+ .title = ხელმოწერის მოცილება
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = ფერი
+pdfjs-editor-free-text-size-input = ზომა
+pdfjs-editor-ink-color-input = ფერი
+pdfjs-editor-ink-thickness-input = სისქე
+pdfjs-editor-ink-opacity-input = გაუმჭვირვალობა
+pdfjs-editor-stamp-add-image-button =
+ .title = სურათის დამატება
+pdfjs-editor-stamp-add-image-button-label = სურათის დამატება
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = სისქე
+pdfjs-editor-free-highlight-thickness-title =
+ .title = სისქის შეცვლა წარწერის გარდა სხვა ნაწილების მონიშვნისას
+pdfjs-editor-add-signature-container =
+ .aria-label = ხელმოწერის მართვა და შენახული ხელმოწერები
+pdfjs-editor-signature-add-signature-button =
+ .title = ახალი ხელმოწერის დამატება
+pdfjs-editor-signature-add-signature-button-label = ახალი ხელმოწერის დამატება
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = შენახული ხელმოწერა: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = წარწერის ჩასწორება
+ .default-content = დაიწყეთ აკრეფა…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] შენიშვნა
+ *[other] შენიშვნა
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = გვერდითი ზოლის დახურვა
+ .aria-label = გვერდითი ზოლის დახურვა
+pdfjs-editor-comments-sidebar-close-button-label = გვერდითი ზოლის დახურვა
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = რამე საყურადღებოს წააწყდით? გააფერადეთ და დაურთეთ შენიშვნა.
+pdfjs-editor-comments-sidebar-no-comments-link = ვრცლად
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = თანდართული წარწერა
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = დართული წარწერის ჩასწორება
+pdfjs-editor-alt-text-dialog-label = არჩევა
+pdfjs-editor-alt-text-dialog-description = თანდართული (შემნაცვლებელი) წარწერა გამოსადეგია მათთვის, ვინც ვერ ხედავს სურათებს ან გამოისახება მაშინ, როცა სურათი ვერ ჩაიტვირთება.
+pdfjs-editor-alt-text-add-description-label = აღწერილობის მითითება
+pdfjs-editor-alt-text-add-description-description = განკუთვნილია 1-2 წინადადებით საგნის, მახასიათებლის ან მოქმედების აღსაწერად.
+pdfjs-editor-alt-text-mark-decorative-label = მოინიშნოს მორთულობად
+pdfjs-editor-alt-text-mark-decorative-description = განკუთვნილია შესამკობი სურათებისთვის, გარსშემოსავლები ჩარჩოებისა და ჭვირნიშნებისთვის.
+pdfjs-editor-alt-text-cancel-button = გაუქმება
+pdfjs-editor-alt-text-save-button = შენახვა
+pdfjs-editor-alt-text-decorative-tooltip = მოინიშნოს მორთულობად
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = მაგალითად, „ახალგაზრდა მამაკაცი მაგიდასთან ზის და სადილობს“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = დართული წარწერა
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = ზევით მარცხნივ — ზომაცვლა
+pdfjs-editor-resizer-top-middle =
+ .aria-label = ზევით შუაში — ზომაცვლა
+pdfjs-editor-resizer-top-right =
+ .aria-label = ზევით მარჯვნივ — ზომაცვლა
+pdfjs-editor-resizer-middle-right =
+ .aria-label = შუაში მარჯვნივ — ზომაცვლა
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = ქვევით მარჯვნივ — ზომაცვლა
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = ქვევით შუაში — ზომაცვლა
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = ზვევით მარცხნივ — ზომაცვლა
+pdfjs-editor-resizer-middle-left =
+ .aria-label = შუაში მარცხნივ — ზომაცვლა
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = მოსანიშნი ფერი
+pdfjs-editor-colorpicker-button =
+ .title = ფერის შეცვლა
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = ფერის არჩევა
+pdfjs-editor-colorpicker-yellow =
+ .title = ყვითელი
+pdfjs-editor-colorpicker-green =
+ .title = მწვანე
+pdfjs-editor-colorpicker-blue =
+ .title = ლურჯი
+pdfjs-editor-colorpicker-pink =
+ .title = ვარდისფერი
+pdfjs-editor-colorpicker-red =
+ .title = წითელი
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = ყველას ჩვენება
+pdfjs-editor-highlight-show-all-button =
+ .title = ყველას ჩვენება
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = დართული წარწერის ჩასწორება (სურათის აღწერის)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = დართული წარწერის დამატება (სურათის აღწერის)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = დაწერეთ თქვენი აღწერილობა აქ…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = მოკლე აღწერა მათთვის, ვინც ვერ ხედავს სურათს ან ვისთანაც ვერ ჩაიტვირთება სურათი.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = ეს დართული წარწერა ავტომატურადაა შედგენილი და შესაძლოა, უმართებულო იყოს.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = ვრცლად
+pdfjs-editor-new-alt-text-create-automatically-button-label = დართული წარწერის თვითშედგენა
+pdfjs-editor-new-alt-text-not-now-button = ახლა არა
+pdfjs-editor-new-alt-text-error-title = დართული წარწერის შედგენა ვერ მოხერხდა
+pdfjs-editor-new-alt-text-error-description = გთხოვთ დაწეროთ საკუთარი დანართი და კვლავ სცადოთ მოგვიანებით.
+pdfjs-editor-new-alt-text-error-close-button = დახურვა
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = ჩამოიტვირთება დართული წარწერის შესადეგი AI-მოდელი ({ $downloadedSize } ზომით { $totalSize } მბაიტი)
+ .aria-valuetext = ჩამოიტვირთება დართული წარწერის შესადეგი AI-მოდელი ({ $downloadedSize } ზომით { $totalSize } მბაიტი)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = დართული წარწერა დამატებულია
+pdfjs-editor-new-alt-text-added-button-label = დართული წარწერა დამატებულია
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = აკლია დართული წარწერა
+pdfjs-editor-new-alt-text-missing-button-label = აკლია დართული წარწერა
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = დართული წარწერის გადახედვა
+pdfjs-editor-new-alt-text-to-review-button-label = დართული წარწერის გადახედვა
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = შედგენილია ავტომატურად: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = სურათის დართული წარწერის პარამეტრები
+pdfjs-image-alt-text-settings-button-label = სურათის დართული წარწერის პარამეტრები
+pdfjs-editor-alt-text-settings-dialog-label = სურათის დართული წარწერის პარამეტრები
+pdfjs-editor-alt-text-settings-automatic-title = ავტომატურად დართული წარწერა
+pdfjs-editor-alt-text-settings-create-model-button-label = დართული წარწერის თვითშედგენა
+pdfjs-editor-alt-text-settings-create-model-description = აღწერს სურათს მათთვის, ვინც ვერ ხედავს ან ვისთანაც ვერ ჩაიტვირთება.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = დართული წარწერის შესადგენი AI-მოდელი ({ $totalSize } მბაიტი)
+pdfjs-editor-alt-text-settings-ai-model-description = ეშვება ადგილობრივად თქვენს მოწყობილობაზე, ასე რომ მონაცემები დარჩება პირადი. საჭიროა დართული წარწერების თვითშედგენისთვის.
+pdfjs-editor-alt-text-settings-delete-model-button = წაშლა
+pdfjs-editor-alt-text-settings-download-model-button = ჩამოტვირთვა
+pdfjs-editor-alt-text-settings-downloading-model-button = ჩამოიტვრითება...
+pdfjs-editor-alt-text-settings-editor-title = დართული წარწერის ჩამსწორებელი
+pdfjs-editor-alt-text-settings-show-dialog-button-label = გამოჩნდეს დართული წარწერის ჩამსწორებელი სურათის დამატებისთანავე
+pdfjs-editor-alt-text-settings-show-dialog-description = უზრუნველყოფს, რომ თქვენს ყველა სურათს ახლდეს დართული წარწერა.
+pdfjs-editor-alt-text-settings-close-button = დახურვა
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = მონიშვნა დამატებულია
+pdfjs-editor-freetext-added-alert = წარწერა დამატებულია
+pdfjs-editor-ink-added-alert = მოხაზვა დამატებული
+pdfjs-editor-stamp-added-alert = სურათი დამატებულია
+pdfjs-editor-signature-added-alert = ხელმოწერა დამატებულია
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = მონიშვნა მოცილებულია
+pdfjs-editor-undo-bar-message-freetext = წარწერა მოცილებულია
+pdfjs-editor-undo-bar-message-ink = მოხაზულის მოცილებულია
+pdfjs-editor-undo-bar-message-stamp = სურათი მოცილებულია
+pdfjs-editor-undo-bar-message-signature = ხელმოწერა მოცილებულია
+pdfjs-editor-undo-bar-message-comment = შენიშვნა მოცილებულია
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } შენიშვნა მოცილებულია
+ *[other] { $count } შენიშვნა მოცილებულია
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = დაბრუნება
+pdfjs-editor-undo-bar-undo-button-label = დაბრუნება
+pdfjs-editor-undo-bar-close-button =
+ .title = დახურვა
+pdfjs-editor-undo-bar-close-button-label = დახურვა
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = ეს არე საშუალებას აძლევს მომხმარებელს, შექმნას საკუთარი ხელმოწერა PDF-დოკუმენტისთვის. მომხმარებელს შეეძლება ჩაასწოროს სახელი (რომელიც დართული ტექსტის მოვალეობასაც ასრულებს) და სურვილისამებრ შეინახოს ხელმოწერა განმეორებით გამოსაყენებლად.
+pdfjs-editor-add-signature-dialog-title = ხელმოწერის დამატება
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = აკრეფა
+ .title = აკრეფა
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = მოხაზვა
+ .title = მოხაზვა
+pdfjs-editor-add-signature-image-button = სურათი
+ .title = სურათი
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = აკრიფეთ ხელმოწერა
+ .placeholder = აკრიფეთ ხელმოწერა
+pdfjs-editor-add-signature-draw-placeholder = მოხაზეთ ხელმოწერა
+pdfjs-editor-add-signature-draw-thickness-range-label = სისქე
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = მოხაზულის სისქე: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = ჩავლებით გადმოიტანეთ ასატვირთად
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] ან ამოარჩიეთ სურათებიდან
+ *[other] ან ამოარჩიეთ სურათებიდან
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = აღწერილობა (დართული წარწერა)
+pdfjs-editor-add-signature-description-input =
+ .title = აღწერილობა (დართული წარწერა)
+pdfjs-editor-add-signature-description-default-when-drawing = ხელმოწერა
+pdfjs-editor-add-signature-clear-button-label = ხელმოწერის წაშლა
+pdfjs-editor-add-signature-clear-button =
+ .title = ხელმოწერის წაშლა
+pdfjs-editor-add-signature-save-checkbox = ხელმოწერის შენახვა
+pdfjs-editor-add-signature-save-warning-message = მიღწეულია 5 ხელმოწერის შენახვის ზღვარი. მოაცილეთ რომელიმე ახლის შესანახად.
+pdfjs-editor-add-signature-image-upload-error-title = ვერ აიტვირთა სურათი
+pdfjs-editor-add-signature-image-upload-error-description = შეამოწმეთ ქსელთან კავშირი ან მოსინჯეთ სხვა სურათი.
+pdfjs-editor-add-signature-image-no-data-error-title = ვერ გარდაიქმნება ეს სურათი ხელმოწერად
+pdfjs-editor-add-signature-image-no-data-error-description = გთხოვთ, სცადოთ სხვა სურათის ატვირთვა.
+pdfjs-editor-add-signature-error-close-button = დახურვა
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = გაუქმება
+pdfjs-editor-add-signature-add-button = დამატება
+pdfjs-editor-edit-signature-update-button = განახლება
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = შენიშვნის ჩასწორება
+pdfjs-editor-edit-comment-popup-button =
+ .title = შენიშვნის ჩასწორება
+pdfjs-editor-delete-comment-popup-button-label = შენიშვნის მოცილება
+pdfjs-editor-delete-comment-popup-button =
+ .title = შენიშვნის მოცილება
+pdfjs-show-comment-button =
+ .title = შენიშვნის გამოჩენა
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = შენიშვნის ჩასწორება
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = განახლება
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = შენიშვნის დამატება
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = დამატება
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = აკრიფეთ…
+pdfjs-editor-edit-comment-dialog-cancel-button = გაუქმება
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = შენიშვნის დამატება
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = გვერდითი ზოლის გამოჩენა (შეიცავს შესათვალიერებელს/სარჩევს/დანართს)
+pdfjs-toggle-views-manager-button1-label = გვერდების მართვა
+pdfjs-views-manager-sidebar =
+ .aria-label = გვერდითი ზოლი
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = გვერდითი ზოლის ზომაცვლა
+pdfjs-views-manager-view-selector-button =
+ .title = ხედები
+pdfjs-views-manager-view-selector-button-label = ხედები
+pdfjs-views-manager-pages-title = გვერდები
+pdfjs-views-manager-outlines-title1 = დოკუმენტის სარჩევი
+ .title = დოკუმენტის სარჩევი (ორმაგი წკაპით ყველა ჩანაწერის ჩამოშლა/აკეცვა)
+pdfjs-views-manager-attachments-title = დანართები
+pdfjs-views-manager-layers-title1 = შრეები
+ .title = შრეები (ორმაგი წკაპით ყველა შრის ნაგულისხმევზე დაბრუნება)
+pdfjs-views-manager-pages-option-label = გვერდები
+pdfjs-views-manager-outlines-option-label = დოკუმენტის სარჩევი
+pdfjs-views-manager-attachments-option-label = დანართები
+pdfjs-views-manager-layers-option-label = შრეები
+pdfjs-views-manager-add-file-button =
+ .title = ფაილის დამატება
+pdfjs-views-manager-add-file-button-label = ფაილის დამატება
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } შერჩეული
+ *[other] { $count } შერჩეული
+ }
+pdfjs-views-manager-pages-status-none-action-label = გვერდების შერჩევა
+pdfjs-views-manager-pages-status-action-button-label = მართვა
+pdfjs-views-manager-pages-status-copy-button-label = ასლი
+pdfjs-views-manager-pages-status-cut-button-label = ამოჭრა
+pdfjs-views-manager-pages-status-delete-button-label = წაშლა
+pdfjs-views-manager-pages-status-export-selected-button-label = შერჩეულის გატანა…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 გვერდი ამოიჭრა
+ *[other] { $count } გვერდი ამოიჭრა
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 გვერდის ასლი აღებულია
+ *[other] { $count } გვერდის ასლი აღებულია
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 გვერდი წაიშალა
+ *[other] { $count } გვერდი წაიშალა
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = მზადდება თქვენი ფაილი…
+pdfjs-views-manager-pages-status-waiting-uploading-label = ფაილი აიტვირთება…
+pdfjs-views-manager-status-warning-cut-label = ვერ ამოიჭრა. განაახლეთ გვერდი და კვლავ სცადეთ.
+pdfjs-views-manager-status-warning-copy-label = ასლი ვერ აიღო. განაახლეთ გვერდი და კვლავ სცადეთ.
+pdfjs-views-manager-status-warning-delete-label = ვერ წაიშალა. განაახლეთ გვერდი და კვლავ სცადეთ.
+pdfjs-views-manager-status-warning-save-label = ვერ შეინახა. განაახლეთ გვერდი და კვლავ სცადეთ.
+pdfjs-views-manager-status-undo-button-label = დაბრუნება
+pdfjs-views-manager-status-done-button-label = მზადაა
+pdfjs-views-manager-status-close-button =
+ .title = დახურვა
+pdfjs-views-manager-status-close-button-label = დახურვა
+pdfjs-views-manager-paste-button-label = ჩასმა
+pdfjs-views-manager-paste-button-before =
+ .title = ჩასმა პირველი გვერდის წინ
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = ჩასმა { $page } გვერდის შემდეგ
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = ᲡᲘᲐᲮᲚᲔ
+pdfjs-views-manager-waiting-for-file = ფაილი აიტვირთება…
+pdfjs-toggle-views-manager-button1 =
+ .title = გვერდების მართვა
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = ციფრული ხელმოწერის პარამეტრები
+ .aria-label = ციფრული ხელმოწერის პარამეტრები
+pdfjs-digital-signature-properties-button-label = ციფრული ხელმოწერის პარამეტრები
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = დოკუმენტი ხელმოწერილია მართებული ციფრული ხელმოწერით
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] დოკუმენტი ხელმოწერილია, მაგრამ { $count } ციფრული ხელმოწერა ვერ დამოწმდა
+ *[other] დოკუმენტი ხელმოწერილია, მაგრამ { $count } ციფრული ხელმოწერა ვერ დამოწმდა
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] დოკუმენტი ხელმოწერილია { $count } არასანდო სერტიფიკატით
+ *[other] დოკუმენტი ხელმოწერილია { $count } არასანდო სერტიფიკატით
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] დოკუმენტი ხელმოწერილია { $count } ვადაგასული სერტიფიკატით
+ *[other] დოკუმენტი ხელმოწერილია { $count } ვადაგასული სერტიფიკატით
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] დოკუმენტი ხელმოწერილია { $count } უმართებულო ციფრული სერტიფიკატით
+ *[other] დოკუმენტი ხელმოწერილია { $count } უმართებულო ციფრული სერტიფიკატით
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] დოკუმენტი ხელმოწერილია { $count } ძალადაკარგული სერტიფიკატით
+ *[other] დოკუმენტი ხელმოწერილია { $count } ძალადაკარგული სერტიფიკატით
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = მდგომარეობა: ხელმოწერა დამოწმებულია
+pdfjs-digital-signature-properties-status-invalid = მდგომარეობა: ხელმოწერა უმართებულოა
+pdfjs-digital-signature-properties-status-unknown = მდგომარეობა: ვერ მოწმდება (მხარდაუჭერელია)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = სერტიფიკატი: სანდოა ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = სერტიფიკატი: მიუწვდომელია
+pdfjs-digital-signature-properties-certificate-untrusted = სერტიფიკატი: არასანდოა
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = სერტიფიკატი: უცნობი გამცემი ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = სერტიფიკატი: თვითხელმოწერით ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = სერტიფიკატი: არასანდო გამცემი ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = სერტიფიკატი: ვადაგასული
+pdfjs-digital-signature-properties-certificate-expired-with-date = სერტიფიკატი: ვადაგასული ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = სერტიფიკატი: ძალადაკარგულია
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = შენახული ხელმოწერის მოცილება
+pdfjs-editor-delete-signature-button-label1 = შენახული ხელმოწერის მოცილება
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = აღწერილობის ჩასწორება
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = აღწერილობის ჩასწორება
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kab/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kab/viewer.ftl
new file mode 100644
index 0000000..8cd604c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kab/viewer.ftl
@@ -0,0 +1,626 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Asebter azewwar
+pdfjs-previous-button-label = Azewwar
+pdfjs-next-button =
+ .title = Asebter d-iteddun
+pdfjs-next-button-label = Ddu ɣer zdat
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Asebter
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = ɣef { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } n { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Semẓi
+pdfjs-zoom-out-button-label = Semẓi
+pdfjs-zoom-in-button =
+ .title = Semɣeṛ
+pdfjs-zoom-in-button-label = Semɣeṛ
+pdfjs-zoom-select =
+ .title = Semɣeṛ/Semẓi
+pdfjs-presentation-mode-button =
+ .title = Uɣal ɣer Uskar Tihawt
+pdfjs-presentation-mode-button-label = Askar Tihawt
+pdfjs-open-file-button =
+ .title = Ldi Afaylu
+pdfjs-open-file-button-label = Ldi
+pdfjs-print-button =
+ .title = Siggez
+pdfjs-print-button-label = Siggez
+pdfjs-save-button =
+ .title = Sekles
+pdfjs-save-button-label = Sekles
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Sader
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Sader
+pdfjs-bookmark-button =
+ .title = Asebter amiran (Sken-d tansa URL seg usebter amiran)
+pdfjs-bookmark-button-label = Asebter amiran
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ifecka
+pdfjs-tools-button-label = Ifecka
+pdfjs-first-page-button =
+ .title = Ddu ɣer usebter amezwaru
+pdfjs-first-page-button-label = Ddu ɣer usebter amezwaru
+pdfjs-last-page-button =
+ .title = Ddu ɣer usebter aneggaru
+pdfjs-last-page-button-label = Ddu ɣer usebter aneggaru
+pdfjs-page-rotate-cw-button =
+ .title = Tuzzya tusrigt
+pdfjs-page-rotate-cw-button-label = Tuzzya tusrigt
+pdfjs-page-rotate-ccw-button =
+ .title = Tuzzya amgal-usrig
+pdfjs-page-rotate-ccw-button-label = Tuzzya amgal-usrig
+pdfjs-cursor-text-select-tool-button =
+ .title = Rmed afecku n tefrant n uḍris
+pdfjs-cursor-text-select-tool-button-label = Afecku n tefrant n uḍris
+pdfjs-cursor-hand-tool-button =
+ .title = Rmed afecku afus
+pdfjs-cursor-hand-tool-button-label = Afecku afus
+pdfjs-scroll-page-button =
+ .title = Seqdec adrurem n usebter
+pdfjs-scroll-page-button-label = Adrurem n usebter
+pdfjs-scroll-vertical-button =
+ .title = Seqdec adrurem ubdid
+pdfjs-scroll-vertical-button-label = Adrurem ubdid
+pdfjs-scroll-horizontal-button =
+ .title = Seqdec adrurem aglawan
+pdfjs-scroll-horizontal-button-label = Adrurem aglawan
+pdfjs-scroll-wrapped-button =
+ .title = Seqdec adrurem yuẓen
+pdfjs-scroll-wrapped-button-label = Adrurem yuẓen
+pdfjs-spread-none-button =
+ .title = Ur sedday ara isiɣzaf n usebter
+pdfjs-spread-none-button-label = Ulac isiɣzaf
+pdfjs-spread-odd-button =
+ .title = Seddu isiɣzaf n usebter ibeddun s yisebtar irayuganen
+pdfjs-spread-odd-button-label = Isiɣzaf irayuganen
+pdfjs-spread-even-button =
+ .title = Seddu isiɣzaf n usebter ibeddun s yisebtar iyuganen
+pdfjs-spread-even-button-label = Isiɣzaf iyuganen
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Taɣaṛa n isemli…
+pdfjs-document-properties-button-label = Taɣaṛa n isemli…
+pdfjs-document-properties-file-name = Isem n ufaylu:
+pdfjs-document-properties-file-size = Teɣzi n ufaylu:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } yibiten)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } yibiten)
+pdfjs-document-properties-title = Azwel:
+pdfjs-document-properties-author = Ameskar:
+pdfjs-document-properties-subject = Amgay:
+pdfjs-document-properties-keywords = Awalen n tsaruţ
+pdfjs-document-properties-creation-date = Azemz n tmerna:
+pdfjs-document-properties-modification-date = Azemz n usnifel:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Yerna-t:
+pdfjs-document-properties-producer = Afecku n uselket PDF:
+pdfjs-document-properties-version = Lqem PDF:
+pdfjs-document-properties-page-count = Amḍan n yisebtar:
+pdfjs-document-properties-page-size = Teɣzi n usebter:
+pdfjs-document-properties-page-size-unit-inches = deg
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = s teɣzi
+pdfjs-document-properties-page-size-orientation-landscape = s tehri
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Asekkil
+pdfjs-document-properties-page-size-name-legal = Usḍif
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Taskant Web taruradt:
+pdfjs-document-properties-linearized-yes = Ih
+pdfjs-document-properties-linearized-no = Ala
+pdfjs-document-properties-close-button = Mdel
+
+## Print
+
+pdfjs-print-progress-message = Aheggi i usiggez n isemli…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Sefsex
+pdfjs-printing-not-supported = Ɣuṛ-k: Asiggez ur ittusefrak ara yakan imaṛṛa deg iminig-a.
+pdfjs-printing-not-ready = Ɣuṛ-k: Afaylu PDF ur d-yuli ara imeṛṛa akken ad ittusiggez.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Sken/Fer agalis adisan
+pdfjs-toggle-sidebar-notification-button =
+ .title = Ffer/Sekn agalis adisan (isemli yegber aɣawas/ticeqqufin yeddan/tissiwin)
+pdfjs-toggle-sidebar-button-label = Sken/Fer agalis adisan
+pdfjs-document-outline-button =
+ .title = Sken isemli (Senned snat tikal i wesemɣer/Afneẓ n iferdisen meṛṛa)
+pdfjs-document-outline-button-label = Isɣalen n isebtar
+pdfjs-attachments-button =
+ .title = Sken ticeqqufin yeddan
+pdfjs-attachments-button-label = Ticeqqufin yeddan
+pdfjs-layers-button =
+ .title = Skeen tissiwin (sit sin yiberdan i uwennez n meṛṛa tissiwin ɣer waddad amezwer)
+pdfjs-layers-button-label = Tissiwin
+pdfjs-thumbs-button =
+ .title = Sken tanfult.
+pdfjs-thumbs-button-label = Tinfulin
+pdfjs-current-outline-item-button =
+ .title = Af-d aferdis n uɣawas amiran
+pdfjs-current-outline-item-button-label = Aferdis n uɣawas amiran
+pdfjs-findbar-button =
+ .title = Nadi deg isemli
+pdfjs-findbar-button-label = Nadi
+pdfjs-additional-layers = Tissiwin-nniḍen
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Asebter { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Tanfult n usebter { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Nadi
+ .placeholder = Nadi deg isemli…
+pdfjs-find-previous-button =
+ .title = Aff-d tamseḍriwt n twinest n deffir
+pdfjs-find-previous-button-label = Azewwar
+pdfjs-find-next-button =
+ .title = Aff-d timseḍriwt n twinest d-iteddun
+pdfjs-find-next-button-label = Ddu ɣer zdat
+pdfjs-find-highlight-checkbox = Err izirig imaṛṛa
+pdfjs-find-match-case-checkbox-label = Qadeṛ amasal n isekkilen
+pdfjs-find-match-diacritics-checkbox-label = Qadeṛ ifeskilen
+pdfjs-find-entire-word-checkbox-label = Awalen iččuranen
+pdfjs-find-reached-top = Yabbeḍ s afella n usebter, tuɣalin s wadda
+pdfjs-find-reached-bottom = Tebḍeḍ s adda n usebter, tuɣalin s afella
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] Timeḍriwt { $current } ɣef { $total }
+ *[other] Timeḍriwin { $current } ɣef { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Ugar n { $limit } umṣada
+ *[other] Ugar n { $limit } yimṣadayen
+ }
+pdfjs-find-not-found = Ulac tawinest
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Tehri n usebter
+pdfjs-page-scale-fit = Asebter imaṛṛa
+pdfjs-page-scale-auto = Asemɣeṛ/Asemẓi awurman
+pdfjs-page-scale-actual = Teɣzi tilawt
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Asebter { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Teḍra-d tuccḍa deg alluy n PDF:
+pdfjs-invalid-file-error = Afaylu PDF arameɣtu neɣ yexṣeṛ.
+pdfjs-missing-file-error = Ulac afaylu PDF.
+pdfjs-unexpected-response-error = Aqeddac yerra-d yir tiririt ur nettwaṛǧi ara.
+pdfjs-rendering-error = Teḍra-d tuccḍa deg uskan n usebter.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Tabzimt { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Sekcem awal uffir akken ad ldiḍ afaylu-yagi PDF
+pdfjs-password-invalid = Awal uffir mačči d ameɣtu, Ɛreḍ tikelt-nniḍen.
+pdfjs-password-ok-button = IH
+pdfjs-password-cancel-button = Sefsex
+pdfjs-web-fonts-disabled = Tisefsiyin web ttwassensent; D awezɣi useqdec n tsefsiyin yettwarnan ɣer PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Aḍris
+pdfjs-editor-color-picker-free-text-input =
+ .title = Senfel ini n uḍris
+pdfjs-editor-free-text-button-label = Aḍris
+pdfjs-editor-ink-button =
+ .title = Suneɣ
+pdfjs-editor-color-picker-ink-input =
+ .title = Senfel ini n usuneɣ
+pdfjs-editor-ink-button-label = Suneɣ
+pdfjs-editor-stamp-button =
+ .title = Rnu neɣ ẓreg tugniwin
+pdfjs-editor-stamp-button-label = Rnu neɣ ẓreg tugniwin
+pdfjs-editor-highlight-button =
+ .title = Derrer
+pdfjs-editor-highlight-button-label = Derrer
+pdfjs-highlight-floating-button1 =
+ .title = Derrer
+ .aria-label = Derrer
+pdfjs-highlight-floating-button-label = Derrer
+pdfjs-comment-floating-button =
+ .title = Wennet
+ .aria-label = Wennet
+pdfjs-comment-floating-button-label = Awennit
+pdfjs-editor-comment-button =
+ .title = Wennet
+ .aria-label = Wennet
+pdfjs-editor-comment-button-label = Awennit
+pdfjs-editor-signature-button =
+ .title = Rnu azmul
+pdfjs-editor-signature-button-label = Rnu azmul
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Amaẓrag usebrureq
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Amaẓrag n usuneɣ
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = usuneɣ n uzmul: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Amaẓrag n tugna
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Kkes asuneɣ
+pdfjs-editor-remove-freetext-button =
+ .title = Kkes aḍris
+pdfjs-editor-remove-stamp-button =
+ .title = Kkes tugna
+pdfjs-editor-remove-highlight-button =
+ .title = Kkes aderrer
+pdfjs-editor-remove-signature-button =
+ .title = Kkes azmul
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Initen
+pdfjs-editor-free-text-size-input = Teɣzi
+pdfjs-editor-ink-color-input = Ini
+pdfjs-editor-ink-thickness-input = Tuzert
+pdfjs-editor-ink-opacity-input = Tebrek
+pdfjs-editor-stamp-add-image-button =
+ .title = Rnu tawlaft
+pdfjs-editor-stamp-add-image-button-label = Rnu tawlaft
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tuzert
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Beddel tuzert mi ara d-tesbeggneḍ iferdisen niḍen ur nelli d aḍris
+pdfjs-editor-add-signature-container =
+ .aria-label = Isenqaden n uzmul d yizmulen yettwaskelsen
+pdfjs-editor-signature-add-signature-button =
+ .title = Rnu azmul amaynut
+pdfjs-editor-signature-add-signature-button-label = Rnu azmul amaynut
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Yettwasekles uzmul: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Amaẓrag n uḍris
+ .default-content = Bdu tira…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Awennit
+ *[other] Iwenniten
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Mdel agalis adisan
+ .aria-label = Mdel agalis adisan
+pdfjs-editor-comments-sidebar-close-button-label = Mdel agalis adisan
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Twalaḍ ayen i ak⋅akem-iɛeǧben? Sebrureq-it, ternuḍ eǧǧ awennit.
+pdfjs-editor-comments-sidebar-no-comments-link = Issin ugar
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Aḍris amaskal
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Ẓreg aḍris amaskal
+pdfjs-editor-alt-text-dialog-label = Fren taxtirt
+pdfjs-editor-alt-text-dialog-description = Aḍris amaskal yettallel mi ara yili imdanen ur ttwalin ara tugna neɣ mi ara yili ur d-tuli ara.
+pdfjs-editor-alt-text-add-description-label = Rnu aglam
+pdfjs-editor-alt-text-add-description-description = Yettuwelleh tira n tefyirt neɣ n snat ideg ara d-yettwaglem asentel, akatar neɣ tigawin.
+pdfjs-editor-alt-text-mark-decorative-label = Creḍ d adlag
+pdfjs-editor-alt-text-mark-decorative-description = Taxtiṛt-a tettwaseqdacay i tugniwin n ucebbaḥ, am tamiwin neɣ i tecraḍ tifrawanin.
+pdfjs-editor-alt-text-cancel-button = Sefsex
+pdfjs-editor-alt-text-save-button = Sekles
+pdfjs-editor-alt-text-decorative-tooltip = Yettwacreḍ d adlag
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = D amedya, “Yiwen yilemẓi iqqim ɣer ṭṭabla,ad yečč imekli”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Aḍris amaskal
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Tiɣmert n ufella n zelmeḍ — semsawi teɣzi
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Talemmat n ufella — semsawi teɣzi
+pdfjs-editor-resizer-top-right =
+ .aria-label = Tiɣmert n ufella n yeffus — semsawi teɣzi
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Talemmast tayeffust — semsawi teɣzi
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Tiɣmert n wadda n yeffus — semsawi teɣzi
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Talemmat n wadda — semsawi teɣzi
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Tiɣmert n wadda n zelmeḍ — semsawi teɣzi
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Talemmast tazelmdaḍt — semsawi teɣzi
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Ini n uderrer
+pdfjs-editor-colorpicker-button =
+ .title = Senfel ini
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Afran n yiniten
+pdfjs-editor-colorpicker-yellow =
+ .title = Awraɣ
+pdfjs-editor-colorpicker-green =
+ .title = Azegzaw
+pdfjs-editor-colorpicker-blue =
+ .title = Amidadi
+pdfjs-editor-colorpicker-pink =
+ .title = Axuxi
+pdfjs-editor-colorpicker-red =
+ .title = Azggaɣ
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Sken akk
+pdfjs-editor-highlight-show-all-button =
+ .title = Sken akk
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Ẓreg aḍris niḍen (aglam n tugna)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Rnu aḍris niḍen (aglam n tugna)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Aru aglam-ik dagi…
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Issin ugar
+pdfjs-editor-new-alt-text-create-automatically-button-label = Rnu aḍris niḍen s wudem awurman
+pdfjs-editor-new-alt-text-not-now-button = Mačči tura
+pdfjs-editor-new-alt-text-error-title = D awezɣi timerna n uḍris niḍen s wudem awurman
+pdfjs-editor-new-alt-text-error-description = Ttxil-k⋅m aru aḍris-ik⋅im niḍen neɣ ɛreḍ tikkelt niḍen.
+pdfjs-editor-new-alt-text-error-close-button = Mdel
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Asader n tmudemt n IA n uḍris amlellay ({ $downloadedSize } n { $totalSize } MB)
+ .aria-valuetext = Asader n tmudemt n IA n uḍris amlellay ({ $downloadedSize } n { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Yettwarna weḍris amlellay
+pdfjs-editor-new-alt-text-added-button-label = Yettwarna weḍris amlellay
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Ixuṣ uḍris amlellay
+pdfjs-editor-new-alt-text-missing-button-label = Ixuṣ uḍris amlellay
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Senqed aḍris amlellay
+pdfjs-editor-new-alt-text-to-review-button-label = Senqed aḍris amlellay
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Yettwarna s wudem awurman: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Iɣewwaṛen n weḍris amlellay n tugna
+pdfjs-image-alt-text-settings-button-label = Iɣewwaṛen n weḍris amlellay n tugna
+pdfjs-editor-alt-text-settings-dialog-label = Iɣewwaṛen n weḍris amlellay n tugna
+pdfjs-editor-alt-text-settings-automatic-title = Aḍris amlellay awurman
+pdfjs-editor-alt-text-settings-create-model-button-label = Rnu aḍris niḍen s wudem awurman
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Tamudemt n IA n uḍris amlellay ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-delete-model-button = Kkes
+pdfjs-editor-alt-text-settings-download-model-button = Sader
+pdfjs-editor-alt-text-settings-downloading-model-button = Asader…
+pdfjs-editor-alt-text-settings-editor-title = Amaẓrag n weḍris amlellay
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Sken amaẓrag n uḍris amlellay akken kan ara ternuḍ tugna
+pdfjs-editor-alt-text-settings-show-dialog-description = Yettall ad tḍemneḍ tugniwin sɛant aḍris amlellay.
+pdfjs-editor-alt-text-settings-close-button = Mdel
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Yettwarna usebrureq
+pdfjs-editor-freetext-added-alert = Yettwarna uḍris
+pdfjs-editor-ink-added-alert = Yettwarna usuneɣ
+pdfjs-editor-stamp-added-alert = Tugna tettwarna
+pdfjs-editor-signature-added-alert = Azmul yettwarna
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Yettwakkes usebrureq
+pdfjs-editor-undo-bar-message-freetext = Aḍris yettwakkes
+pdfjs-editor-undo-bar-message-ink = Asuneɣ yettwakkes
+pdfjs-editor-undo-bar-message-stamp = Tugna tettwakkes
+pdfjs-editor-undo-bar-message-signature = Azmul yettwakkes
+pdfjs-editor-undo-bar-undo-button =
+ .title = Sefsex
+pdfjs-editor-undo-bar-undo-button-label = Sefsex
+pdfjs-editor-undo-bar-close-button =
+ .title = Mdel
+pdfjs-editor-undo-bar-close-button-label = Mdel
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-title = Rnu azmul
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Anaw
+ .title = Anaw
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Suneɣ
+ .title = Suneɣ
+pdfjs-editor-add-signature-image-button = Tugna
+ .title = Tugna
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Zru azmul-ik
+ .placeholder = Zru azmul-ik
+pdfjs-editor-add-signature-draw-placeholder = Suneɣ azmul-ik
+pdfjs-editor-add-signature-draw-thickness-range-label = Tuzert
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Tuzert n usuneɣ: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Seḥnucceḍ afaylu da akken ad t-saliṭ
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] neɣ fren ifuyla n tugna
+ *[other] neɣ inig ifuyla n tugna
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Aglam (aḍris amlellay)
+pdfjs-editor-add-signature-description-input =
+ .title = Aglam (aḍris amlellay)
+pdfjs-editor-add-signature-description-default-when-drawing = Azmul
+pdfjs-editor-add-signature-clear-button-label = Sfeḍ azmul
+pdfjs-editor-add-signature-clear-button =
+ .title = Sfeḍ azmul
+pdfjs-editor-add-signature-save-checkbox = Sekles azmul
+pdfjs-editor-add-signature-image-upload-error-title = Ur izmir ara ad yessali tugna
+pdfjs-editor-add-signature-image-upload-error-description = Ssefqed tuqqna-inek⋅inem n uẓeṭṭa neɣ ɛreḍ tugna-nniḍen.
+pdfjs-editor-add-signature-image-no-data-error-title = D awezɣi aselket n tugna-a ɣer uzmul
+pdfjs-editor-add-signature-image-no-data-error-description = Ttxil-k⋅m ɛreḍ ad tzedmeḍ tugna niḍen
+pdfjs-editor-add-signature-error-close-button = Mdel
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Semmet
+pdfjs-editor-add-signature-add-button = Rnu
+pdfjs-editor-edit-signature-update-button = Leqqem
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Ẓreg awennit
+pdfjs-editor-edit-comment-popup-button =
+ .title = Ẓreg awennit
+pdfjs-editor-delete-comment-popup-button-label = Kkes awennit
+pdfjs-editor-delete-comment-popup-button =
+ .title = Kkes awennit
+pdfjs-show-comment-button =
+ .title = Sken awennit
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Ẓreg awennit
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Rnu awennit
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Bdu tira...
+pdfjs-editor-edit-comment-dialog-cancel-button = Sefsex
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Kkes azmul yettwakelsen
+pdfjs-editor-delete-signature-button-label1 = Kkes azmul yettwakelsen
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Ẓreg aglam
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Ẓreg aglam
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kk/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kk/viewer.ftl
new file mode 100644
index 0000000..f6a9be8
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kk/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Алдыңғы парақ
+pdfjs-previous-button-label = Алдыңғысы
+pdfjs-next-button =
+ .title = Келесі парақ
+pdfjs-next-button-label = Келесі
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Парақ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } ішінен
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = (парақ { $pageNumber }, { $pagesCount } ішінен)
+pdfjs-zoom-out-button =
+ .title = Кішірейту
+pdfjs-zoom-out-button-label = Кішірейту
+pdfjs-zoom-in-button =
+ .title = Үлкейту
+pdfjs-zoom-in-button-label = Үлкейту
+pdfjs-zoom-select =
+ .title = Масштаб
+pdfjs-presentation-mode-button =
+ .title = Презентация режиміне ауысу
+pdfjs-presentation-mode-button-label = Презентация режимі
+pdfjs-open-file-button =
+ .title = Файлды ашу
+pdfjs-open-file-button-label = Ашу
+pdfjs-print-button =
+ .title = Баспаға шығару
+pdfjs-print-button-label = Баспаға шығару
+pdfjs-save-button =
+ .title = Сақтау
+pdfjs-save-button-label = Сақтау
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Жүктеп алу
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Жүктеп алу
+pdfjs-bookmark-button =
+ .title = Ағымдағы бет (Ағымдағы беттен URL адресін көру)
+pdfjs-bookmark-button-label = Ағымдағы бет
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Құралдар
+pdfjs-tools-button-label = Құралдар
+pdfjs-first-page-button =
+ .title = Алғашқы параққа өту
+pdfjs-first-page-button-label = Алғашқы параққа өту
+pdfjs-last-page-button =
+ .title = Соңғы параққа өту
+pdfjs-last-page-button-label = Соңғы параққа өту
+pdfjs-page-rotate-cw-button =
+ .title = Сағат тілі бағытымен айналдыру
+pdfjs-page-rotate-cw-button-label = Сағат тілі бағытымен бұру
+pdfjs-page-rotate-ccw-button =
+ .title = Сағат тілі бағытына қарсы бұру
+pdfjs-page-rotate-ccw-button-label = Сағат тілі бағытына қарсы бұру
+pdfjs-cursor-text-select-tool-button =
+ .title = Мәтінді таңдау құралын іске қосу
+pdfjs-cursor-text-select-tool-button-label = Мәтінді таңдау құралы
+pdfjs-cursor-hand-tool-button =
+ .title = Қол құралын іске қосу
+pdfjs-cursor-hand-tool-button-label = Қол құралы
+pdfjs-scroll-page-button =
+ .title = Беттерді айналдыруды пайдалану
+pdfjs-scroll-page-button-label = Беттерді айналдыру
+pdfjs-scroll-vertical-button =
+ .title = Вертикалды айналдыруды қолдану
+pdfjs-scroll-vertical-button-label = Вертикалды айналдыру
+pdfjs-scroll-horizontal-button =
+ .title = Горизонталды айналдыруды қолдану
+pdfjs-scroll-horizontal-button-label = Горизонталды айналдыру
+pdfjs-scroll-wrapped-button =
+ .title = Масштабталатын айналдыруды қолдану
+pdfjs-scroll-wrapped-button-label = Масштабталатын айналдыру
+pdfjs-spread-none-button =
+ .title = Жазық беттер режимін қолданбау
+pdfjs-spread-none-button-label = Жазық беттер режимсіз
+pdfjs-spread-odd-button =
+ .title = Жазық беттер тақ нөмірлі беттерден басталады
+pdfjs-spread-odd-button-label = Тақ нөмірлі беттер сол жақтан
+pdfjs-spread-even-button =
+ .title = Жазық беттер жұп нөмірлі беттерден басталады
+pdfjs-spread-even-button-label = Жұп нөмірлі беттер сол жақтан
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Құжат қасиеттері…
+pdfjs-document-properties-button-label = Құжат қасиеттері…
+pdfjs-document-properties-file-name = Файл аты:
+pdfjs-document-properties-file-size = Файл өлшемі:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } КБ ({ $b } байт)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } МБ ({ $b } байт)
+pdfjs-document-properties-title = Тақырыбы:
+pdfjs-document-properties-author = Авторы:
+pdfjs-document-properties-subject = Тақырыбы:
+pdfjs-document-properties-keywords = Кілт сөздер:
+pdfjs-document-properties-creation-date = Жасалған күні:
+pdfjs-document-properties-modification-date = Түзету күні:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Жасаған:
+pdfjs-document-properties-producer = PDF өндірген:
+pdfjs-document-properties-version = PDF нұсқасы:
+pdfjs-document-properties-page-count = Беттер саны:
+pdfjs-document-properties-page-size = Бет өлшемі:
+pdfjs-document-properties-page-size-unit-inches = дюйм
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = тік
+pdfjs-document-properties-page-size-orientation-landscape = жатық
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Жылдам Web көрінісі:
+pdfjs-document-properties-linearized-yes = Иә
+pdfjs-document-properties-linearized-no = Жоқ
+pdfjs-document-properties-close-button = Жабу
+pdfjs-digital-signature-properties-view-certificate = Сертификатты қарау
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Себебі: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Күн мен уақыт белгісі: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Ішкі қолтаңба ({ $count })
+ *[other] Ішкі қолтаңбалар ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Құжатты баспаға шығару үшін дайындау…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Бас тарту
+pdfjs-printing-not-supported = Ескерту: Баспаға шығаруды бұл браузер толығымен қолдамайды.
+pdfjs-printing-not-ready = Ескерту: Баспаға шығару үшін, бұл PDF толығымен жүктеліп алынбады.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Бүйір панелін көрсету/жасыру
+pdfjs-toggle-sidebar-notification-button =
+ .title = Бүйір панелін көрсету/жасыру (құжатта құрылымы/салынымдар/қабаттар бар)
+pdfjs-toggle-sidebar-button-label = Бүйір панелін көрсету/жасыру
+pdfjs-document-outline-button =
+ .title = Құжат құрылымын көрсету (барлық нәрселерді жазық қылу/жинау үшін қос шерту керек)
+pdfjs-document-outline-button-label = Құжат құрамасы
+pdfjs-attachments-button =
+ .title = Салынымдарды көрсету
+pdfjs-attachments-button-label = Салынымдар
+pdfjs-layers-button =
+ .title = Қабаттарды көрсету (барлық қабаттарды бастапқы күйге келтіру үшін екі рет шертіңіз)
+pdfjs-layers-button-label = Қабаттар
+pdfjs-thumbs-button =
+ .title = Кіші көріністерді көрсету
+pdfjs-thumbs-button-label = Кіші көріністер
+pdfjs-current-outline-item-button =
+ .title = Құрылымның ағымдағы элементін табу
+pdfjs-current-outline-item-button-label = Құрылымның ағымдағы элементі
+pdfjs-findbar-button =
+ .title = Құжаттан табу
+pdfjs-findbar-button-label = Табу
+pdfjs-additional-layers = Қосымша қабаттар
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } парағы
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } парағы үшін кіші көрінісі
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = { $page } бетін таңдау
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Бет { $page }/{ $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Табу
+ .placeholder = Құжаттан табу…
+pdfjs-find-previous-button =
+ .title = Осы сөздердің мәтіннен алдыңғы кездесуін табу
+pdfjs-find-previous-button-label = Алдыңғысы
+pdfjs-find-next-button =
+ .title = Осы сөздердің мәтіннен келесі кездесуін табу
+pdfjs-find-next-button-label = Келесі
+pdfjs-find-highlight-checkbox = Барлығын түспен ерекшелеу
+pdfjs-find-match-case-checkbox-label = Регистрді ескеру
+pdfjs-find-match-diacritics-checkbox-label = Диакритиканы ескеру
+pdfjs-find-entire-word-checkbox-label = Сөздер толығымен
+pdfjs-find-reached-top = Құжаттың басына жеттік, соңынан бастап жалғастырамыз
+pdfjs-find-reached-bottom = Құжаттың соңына жеттік, басынан бастап жалғастырамыз
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } сәйкестік, барлығы { $total }
+ *[other] { $current } сәйкестік, барлығы { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] { $limit } сәйкестіктен көп
+ *[other] { $limit } сәйкестіктен көп
+ }
+pdfjs-find-not-found = Сөз(дер) табылмады
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Парақ ені
+pdfjs-page-scale-fit = Парақты сыйдыру
+pdfjs-page-scale-auto = Автомасштабтау
+pdfjs-page-scale-actual = Нақты өлшемі
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Бет { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF жүктеу кезінде қате кетті.
+pdfjs-invalid-file-error = Зақымдалған немесе қате PDF файл.
+pdfjs-missing-file-error = PDF файлы жоқ.
+pdfjs-unexpected-response-error = Сервердің күтпеген жауабы.
+pdfjs-rendering-error = Парақты өңдеу кезінде қате кетті.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } аңдатпасы]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Бұл PDF файлын ашу үшін парольді енгізіңіз.
+pdfjs-password-invalid = Пароль дұрыс емес. Қайталап көріңіз.
+pdfjs-password-ok-button = ОК
+pdfjs-password-cancel-button = Бас тарту
+pdfjs-web-fonts-disabled = Веб қаріптері сөндірілген: құрамына енгізілген PDF қаріптерін қолдану мүмкін емес.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Мәтін
+pdfjs-editor-color-picker-free-text-input =
+ .title = Мәтін түсін өзгерту
+pdfjs-editor-free-text-button-label = Мәтін
+pdfjs-editor-ink-button =
+ .title = Сурет салу
+pdfjs-editor-color-picker-ink-input =
+ .title = Сызба түсін өзгерту
+pdfjs-editor-ink-button-label = Сурет салу
+pdfjs-editor-stamp-button =
+ .title = Суреттерді қосу немесе түзету
+pdfjs-editor-stamp-button-label = Суреттерді қосу немесе түзету
+pdfjs-editor-highlight-button =
+ .title = Ерекшелеу
+pdfjs-editor-highlight-button-label = Ерекшелеу
+pdfjs-highlight-floating-button1 =
+ .title = Ерекшелеу
+ .aria-label = Ерекшелеу
+pdfjs-highlight-floating-button-label = Ерекшелеу
+pdfjs-comment-floating-button =
+ .title = Түсіндірме
+ .aria-label = Түсіндірме
+pdfjs-comment-floating-button-label = Түсіндірме
+pdfjs-editor-comment-button =
+ .title = Түсіндірме
+ .aria-label = Түсіндірме
+pdfjs-editor-comment-button-label = Түсіндірме
+pdfjs-editor-signature-button =
+ .title = Қолтаңбаны қосу
+pdfjs-editor-signature-button-label = Қолтаңбаны қосу
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Ерекшелеу түзеткіші
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Сурет салу түзеткіші
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Қолтаңба түзеткіші: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Сурет редакторы
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Сызбаны өшіру
+pdfjs-editor-remove-freetext-button =
+ .title = Мәтінді өшіру
+pdfjs-editor-remove-stamp-button =
+ .title = Суретті өшіру
+pdfjs-editor-remove-highlight-button =
+ .title = Түспен ерекшелеуді өшіру
+pdfjs-editor-remove-signature-button =
+ .title = Қолтаңбаны өшіру
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Түс
+pdfjs-editor-free-text-size-input = Өлшемі
+pdfjs-editor-ink-color-input = Түс
+pdfjs-editor-ink-thickness-input = Қалыңдығы
+pdfjs-editor-ink-opacity-input = Мөлдірсіздігі
+pdfjs-editor-stamp-add-image-button =
+ .title = Суретті қосу
+pdfjs-editor-stamp-add-image-button-label = Суретті қосу
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Қалыңдығы
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Мәтіннен басқа элементтерді ерекшелеу кезінде қалыңдықты өзгерту
+pdfjs-editor-add-signature-container =
+ .aria-label = Қолтаңбаларды басқару және сақталған қолтаңбалар
+pdfjs-editor-signature-add-signature-button =
+ .title = Жаңа қолтаңбаны қосу
+pdfjs-editor-signature-add-signature-button-label = Жаңа қолтаңбаны қосу
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Сақталған қолтаңба: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Мәтін түзеткіші
+ .default-content = Теріп бастаңыз…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Түсіндірмелер
+ *[other] Түсіндірмелер
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Бүйір панелін жабу
+ .aria-label = Бүйір панелін жабу
+pdfjs-editor-comments-sidebar-close-button-label = Бүйір панелін жабу
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Назар аударарлық бірдеңе көрдіңіз бе? Оны ерекшелеп, түсіндірме қалдырыңыз.
+pdfjs-editor-comments-sidebar-no-comments-link = Көбірек білу
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Балама мәтін
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Балама мәтінді өңдеу
+pdfjs-editor-alt-text-dialog-label = Опцияны таңдау
+pdfjs-editor-alt-text-dialog-description = Балама мәтін адамдар суретті көре алмағанда немесе ол жүктелмегенде көмектеседі.
+pdfjs-editor-alt-text-add-description-label = Сипаттаманы қосу
+pdfjs-editor-alt-text-add-description-description = Тақырыпты, баптауды немесе әрекетті сипаттайтын 1-2 сөйлемді қолдануға тырысыңыз.
+pdfjs-editor-alt-text-mark-decorative-label = Декоративті деп белгілеу
+pdfjs-editor-alt-text-mark-decorative-description = Бұл жиектер немесе су белгілері сияқты оюлық суреттер үшін пайдаланылады.
+pdfjs-editor-alt-text-cancel-button = Бас тарту
+pdfjs-editor-alt-text-save-button = Сақтау
+pdfjs-editor-alt-text-decorative-tooltip = Декоративті деп белгіленген
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Мысалы, "Жас жігіт тамақ ішу үшін үстел басына отырады"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Балама мәтін
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Жоғарғы сол жақ бұрыш — өлшемін өзгерту
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Жоғарғы ортасы — өлшемін өзгерту
+pdfjs-editor-resizer-top-right =
+ .aria-label = Жоғарғы оң жақ бұрыш — өлшемін өзгерту
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Ортаңғы оң жақ — өлшемін өзгерту
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Төменгі оң жақ бұрыш — өлшемін өзгерту
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Төменгі ортасы — өлшемін өзгерту
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Төменгі сол жақ бұрыш — өлшемін өзгерту
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Ортаңғы сол жақ — өлшемін өзгерту
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Ерекшелеу түсі
+pdfjs-editor-colorpicker-button =
+ .title = Түсті өзгерту
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Түс таңдаулары
+pdfjs-editor-colorpicker-yellow =
+ .title = Сары
+pdfjs-editor-colorpicker-green =
+ .title = Жасыл
+pdfjs-editor-colorpicker-blue =
+ .title = Көк
+pdfjs-editor-colorpicker-pink =
+ .title = Қызғылт
+pdfjs-editor-colorpicker-red =
+ .title = Қызыл
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Барлығын көрсету
+pdfjs-editor-highlight-show-all-button =
+ .title = Барлығын көрсету
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Балама мәтінді өңдеу (сурет сипаттамасы)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Балама мәтінді қосу (сурет сипаттамасы)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Сипаттамаңызды осында жазыңыз…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Суретті көре алмайтын адамдар үшін немесе сурет жүктелмеген кезіне арналған қысқаша сипаттама.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Бұл балама мәтін автоматты түрде жасалды және дәлсіз болуы мүмкін.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Көбірек білу
+pdfjs-editor-new-alt-text-create-automatically-button-label = Балама мәтінді автоматты түрде жасау
+pdfjs-editor-new-alt-text-not-now-button = Қазір емес
+pdfjs-editor-new-alt-text-error-title = Балама мәтінді автоматты түрде жасау мүмкін болмады
+pdfjs-editor-new-alt-text-error-description = Өзіңіздің балама мәтініңізді жазыңыз немесе кейінірек қайталап көріңіз.
+pdfjs-editor-new-alt-text-error-close-button = Жабу
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Балама мәтін үшін ЖИ моделі жүктеп алынуда ({ $downloadedSize }/{ $totalSize } МБ)
+ .aria-valuetext = Балама мәтін үшін ЖИ моделі жүктеп алынуда ({ $downloadedSize }/{ $totalSize } МБ)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Балама мәтін қосылды
+pdfjs-editor-new-alt-text-added-button-label = Балама мәтін қосылды
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Балама мәтін жоқ
+pdfjs-editor-new-alt-text-missing-button-label = Балама мәтін жоқ
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Балама мәтінге пікір қалдыру
+pdfjs-editor-new-alt-text-to-review-button-label = Балама мәтінге пікір қалдыру
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Автоматты түрде жасалды: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Суреттің балама мәтінінің баптаулары
+pdfjs-image-alt-text-settings-button-label = Суреттің балама мәтінінің баптаулары
+pdfjs-editor-alt-text-settings-dialog-label = Суреттің балама мәтінінің баптаулары
+pdfjs-editor-alt-text-settings-automatic-title = Автоматты балама мәтін
+pdfjs-editor-alt-text-settings-create-model-button-label = Балама мәтінді автоматты түрде жасау
+pdfjs-editor-alt-text-settings-create-model-description = Суретті көре алмайтын адамдар үшін немесе сурет жүктелмеген кезіне арналған сипаттамаларды ұсынады.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Баламалы мәтіннің ЖИ моделі ({ $totalSize } МБ)
+pdfjs-editor-alt-text-settings-ai-model-description = Деректеріңіз жеке болып қалуы үшін құрылғыңызда жергілікті түрде жұмыс істейді. Автоматты балама мәтін үшін қажет.
+pdfjs-editor-alt-text-settings-delete-model-button = Өшіру
+pdfjs-editor-alt-text-settings-download-model-button = Жүктеп алу
+pdfjs-editor-alt-text-settings-downloading-model-button = Жүктеліп алынуда…
+pdfjs-editor-alt-text-settings-editor-title = Баламалы мәтін редакторы
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Суретті қосқанда балама мәтін редакторын бірден көрсету
+pdfjs-editor-alt-text-settings-show-dialog-description = Барлық суреттерде балама мәтін бар екеніне көз жеткізуге көмектеседі.
+pdfjs-editor-alt-text-settings-close-button = Жабу
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Ерекшелеу қосылды
+pdfjs-editor-freetext-added-alert = Мәтін қосылды
+pdfjs-editor-ink-added-alert = Сызба қосылды
+pdfjs-editor-stamp-added-alert = Сурет қосылды
+pdfjs-editor-signature-added-alert = Қолтаңба қосылды
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Ерекшелеу өшірілді
+pdfjs-editor-undo-bar-message-freetext = Мәтін өшірілді
+pdfjs-editor-undo-bar-message-ink = Сызба өшірілді
+pdfjs-editor-undo-bar-message-stamp = Сурет өшірілді
+pdfjs-editor-undo-bar-message-signature = Қолтаңба өшірілді
+pdfjs-editor-undo-bar-message-comment = Түсіндірме өшірілді
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } анимация өшірілді
+ *[other] { $count } анимация өшірілді
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Болдырмау
+pdfjs-editor-undo-bar-undo-button-label = Болдырмау
+pdfjs-editor-undo-bar-close-button =
+ .title = Жабу
+pdfjs-editor-undo-bar-close-button-label = Жабу
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Бұл модальді терезе пайдаланушыға PDF құжатына қосу үшін қолтаңба жасауға мүмкіндік береді. Пайдаланушы өз атын (ол балама мәтін ретінде де қолданылады) өңдей алады және қолтаңбаны кейін қайта пайдалану үшін сақтай алады.
+pdfjs-editor-add-signature-dialog-title = Қолтаңба қосу
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Енгізу
+ .title = Енгізу
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Сурет салу
+ .title = Сурет салу
+pdfjs-editor-add-signature-image-button = Сурет
+ .title = Сурет
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Қолтаңбаңызды теріңіз
+ .placeholder = Қолтаңбаңызды теріңіз
+pdfjs-editor-add-signature-draw-placeholder = Қолтаңбаңызды сызыңыз
+pdfjs-editor-add-signature-draw-thickness-range-label = Қалыңдығы
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Сызба қалыңздығы: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Жүктеп жіберу үшін файлды осы жерге сүйреңіз
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Немесе сурет файлдарын таңдаңыз
+ *[other] Немесе сурет файлдарын шолыңыз
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Сипаттама (балама мәтін)
+pdfjs-editor-add-signature-description-input =
+ .title = Сипаттама (балама мәтін)
+pdfjs-editor-add-signature-description-default-when-drawing = Қолтаңба
+pdfjs-editor-add-signature-clear-button-label = Қолтаңбаны өшіру
+pdfjs-editor-add-signature-clear-button =
+ .title = Қолтаңбаны өшіру
+pdfjs-editor-add-signature-save-checkbox = Қолтаңбаны сақтау
+pdfjs-editor-add-signature-save-warning-message = Сақталған 5 қолтаңбаның шегіне жеттіңіз. Көбірек сақтау үшін біреуін алып тастаңыз.
+pdfjs-editor-add-signature-image-upload-error-title = Суретті жүктеп жіберу мүмкін емес.
+pdfjs-editor-add-signature-image-upload-error-description = Желі байланысын тексеріңіз немесе басқа бейнені қолданып көріңіз.
+pdfjs-editor-add-signature-image-no-data-error-title = Бұл суретті қолтаңбаға түрлендіру мүмкін емес
+pdfjs-editor-add-signature-image-no-data-error-description = Басқа суретті жүктеп салып көріңіз.
+pdfjs-editor-add-signature-error-close-button = Жабу
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Бас тарту
+pdfjs-editor-add-signature-add-button = Қосу
+pdfjs-editor-edit-signature-update-button = Жаңарту
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Түсіндірмені түзету
+pdfjs-editor-edit-comment-popup-button =
+ .title = Түсіндірмені түзету
+pdfjs-editor-delete-comment-popup-button-label = Түсіндірмені өшіру
+pdfjs-editor-delete-comment-popup-button =
+ .title = Түсіндірмені өшіру
+pdfjs-show-comment-button =
+ .title = Түсіндірмені көрсету
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Түсіндірмені түзету
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Жаңарту
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Түсіндірмені қосу
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Қосу
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Теріп бастаңыз…
+pdfjs-editor-edit-comment-dialog-cancel-button = Бас тарту
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Пікір қосу
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Бүйір панелін көрсету/жасыру (құжатта кіші көріністер/құрылымы/салынымдар/қабаттар бар)
+pdfjs-toggle-views-manager-button1-label = Беттерді басқару
+pdfjs-views-manager-sidebar =
+ .aria-label = Бүйір панелі
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Бүйір панелінің өлшемін өзгертуші
+pdfjs-views-manager-view-selector-button =
+ .title = Көріністер
+pdfjs-views-manager-view-selector-button-label = Көріністер
+pdfjs-views-manager-pages-title = Беттер
+pdfjs-views-manager-outlines-title1 = Құжат құрылымы
+ .title = Құжат құрылымы (барлық нәрселерді жаю/жию үшін қос шерту)
+pdfjs-views-manager-attachments-title = Салынымдар
+pdfjs-views-manager-layers-title1 = Қабаттар
+ .title = Қабаттар (барлық нәрселерді жаю/жию үшін қос шерту)
+pdfjs-views-manager-pages-option-label = Беттер
+pdfjs-views-manager-outlines-option-label = Құжаттың құрылымы
+pdfjs-views-manager-attachments-option-label = Салынымдар
+pdfjs-views-manager-layers-option-label = Қабаттар
+pdfjs-views-manager-add-file-button =
+ .title = Файлды қосу
+pdfjs-views-manager-add-file-button-label = Файлды қосу
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } таңдалды
+ *[other] { $count } таңдалды
+ }
+pdfjs-views-manager-pages-status-none-action-label = Беттерді таңдау
+pdfjs-views-manager-pages-status-action-button-label = Басқару
+pdfjs-views-manager-pages-status-copy-button-label = Көшіріп алу
+pdfjs-views-manager-pages-status-cut-button-label = Қиып алу
+pdfjs-views-manager-pages-status-delete-button-label = Өшіру
+pdfjs-views-manager-pages-status-export-selected-button-label = Таңдалғанды экспорттау…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 бет қиып алынды
+ *[other] { $count } қиып алынды
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 бет көшірілді
+ *[other] { $count } бет көшірілді
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 бет өшірілді
+ *[other] { $count } бет өшірілді
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Файлыңыз дайындалуда…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Файл жүктеп салынуда…
+pdfjs-views-manager-status-warning-cut-label = Қиып алу мүмкін болмады. Бетті жаңартып, қайталап көріңіз.
+pdfjs-views-manager-status-warning-copy-label = Көшіру мүмкін болмады. Бетті жаңартып, қайталап көріңіз.
+pdfjs-views-manager-status-warning-delete-label = Өшіру мүмкін болмады. Бетті жаңартып, қайталап көріңіз.
+pdfjs-views-manager-status-warning-save-label = Сақтау мүмкін болмады. Бетті жаңартып, қайталап көріңіз.
+pdfjs-views-manager-status-undo-button-label = Болдырмау
+pdfjs-views-manager-status-done-button-label = Дайын
+pdfjs-views-manager-status-close-button =
+ .title = Жабу
+pdfjs-views-manager-status-close-button-label = Жабу
+pdfjs-views-manager-paste-button-label = Кірістіру
+pdfjs-views-manager-paste-button-before =
+ .title = Бірінші беттің алдына кірістіру
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = { $page } бетінен кейін кірістіру
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = ЖАҢА
+pdfjs-views-manager-waiting-for-file = Файл жүктеп салынуда…
+pdfjs-toggle-views-manager-button1 =
+ .title = Беттерді басқару
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Цифрлық қолтаңба қасиеттері
+ .aria-label = Цифрлық қолтаңба қасиеттері
+pdfjs-digital-signature-properties-button-label = Цифрлық қолтаңба қасиеттері
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Құжатқа жарамды цифрлық қолтаңбамен қол қойылған
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Құжатқа қол қойылған, бірақ { $count } цифрлық қолтаңбаны тексеру мүмкін болмады
+ *[other] Құжатқа қол қойылған, бірақ { $count } цифрлық қолтаңбаны тексеру мүмкін болмады
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Құжатқа сенімсіз { $count } сертификатпен қол қойылған
+ *[other] Құжатқа сенімсіз { $count } сертификатпен қол қойылған
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Құжатқа мерзімі өткен { $count } сертификатпен қол қойылған
+ *[other] Құжатқа мерзімі өткен { $count } сертификатпен қол қойылған
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Құжатта { $count } жарамсыз цифрлық қолтаңба бар
+ *[other] Құжатта { $count } жарамсыз цифрлық қолтаңба бар
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Құжатқа қайтарылған { $count } сертификатпен қол қойылған
+ *[other] Құжатқа қайтарылған { $count } сертификатпен қол қойылған
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Қалып-күй: Қолтаңба тексерілді
+pdfjs-digital-signature-properties-status-invalid = Қалып-күй: Қолтаңба жарамсыз
+pdfjs-digital-signature-properties-status-unknown = Қалып-күй: Тексеру мүмкін емес (қолдау көрсетілмейді)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Сертификат: Сенімді ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Сертификат: Қолжетімсіз
+pdfjs-digital-signature-properties-certificate-untrusted = Сертификат: Сенімсіз
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Сертификат: Белгісіз шығарушы ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Сертификат: Өздігінен қол қойылған ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Сертификат: Сенімсіз шығарушы ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Сертификат: Мерзімі өткен
+pdfjs-digital-signature-properties-certificate-expired-with-date = Сертификат: Мерзімі өткен ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Сертификат: Қайтарылған
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Сақталған қолтаңбаны өшіру
+pdfjs-editor-delete-signature-button-label1 = Сақталған қолтаңбаны өшіру
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Сипаттаманы түзету
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Сипаттаманы түзету
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/km/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/km/viewer.ftl
new file mode 100644
index 0000000..cf899f4
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/km/viewer.ftl
@@ -0,0 +1,242 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = ទំព័រមុន
+pdfjs-previous-button-label = មុន
+pdfjs-next-button =
+ .title = ទំព័របន្ទាប់
+pdfjs-next-button-label = បន្ទាប់
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ទំព័រ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = នៃ { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } នៃ { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = បង្រួម
+pdfjs-zoom-out-button-label = បង្រួម
+pdfjs-zoom-in-button =
+ .title = ពង្រីក
+pdfjs-zoom-in-button-label = ពង្រីក
+pdfjs-zoom-select =
+ .title = ពង្រីក
+pdfjs-presentation-mode-button =
+ .title = ប្ដូរទៅរបៀបបទបង្ហាញ
+pdfjs-presentation-mode-button-label = របៀបបទបង្ហាញ
+pdfjs-open-file-button =
+ .title = បើកឯកសារ
+pdfjs-open-file-button-label = បើក
+pdfjs-print-button =
+ .title = បោះពុម្ព
+pdfjs-print-button-label = បោះពុម្ព
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ឧបករណ៍
+pdfjs-tools-button-label = ឧបករណ៍
+pdfjs-first-page-button =
+ .title = ទៅកាន់ទំព័រដំបូង
+pdfjs-first-page-button-label = ទៅកាន់ទំព័រដំបូង
+pdfjs-last-page-button =
+ .title = ទៅកាន់ទំព័រចុងក្រោយ
+pdfjs-last-page-button-label = ទៅកាន់ទំព័រចុងក្រោយ
+pdfjs-page-rotate-cw-button =
+ .title = បង្វិលស្របទ្រនិចនាឡិកា
+pdfjs-page-rotate-cw-button-label = បង្វិលស្របទ្រនិចនាឡិកា
+pdfjs-page-rotate-ccw-button =
+ .title = បង្វិលច្រាសទ្រនិចនាឡិកា
+pdfjs-page-rotate-ccw-button-label = បង្វិលច្រាសទ្រនិចនាឡិកា
+pdfjs-cursor-text-select-tool-button =
+ .title = បើកឧបករណ៍ជ្រើសអត្ថបទ
+pdfjs-cursor-text-select-tool-button-label = ឧបករណ៍ជ្រើសអត្ថបទ
+pdfjs-cursor-hand-tool-button =
+ .title = បើកឧបករណ៍ដៃ
+pdfjs-cursor-hand-tool-button-label = ឧបករណ៍ដៃ
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = លក្ខណសម្បត្តិឯកសារ…
+pdfjs-document-properties-button-label = លក្ខណសម្បត្តិឯកសារ…
+pdfjs-document-properties-file-name = ឈ្មោះឯកសារ៖
+pdfjs-document-properties-file-size = ទំហំឯកសារ៖
+pdfjs-document-properties-title = ចំណងជើង៖
+pdfjs-document-properties-author = អ្នកនិពន្ធ៖
+pdfjs-document-properties-subject = ប្រធានបទ៖
+pdfjs-document-properties-keywords = ពាក្យគន្លឹះ៖
+pdfjs-document-properties-creation-date = កាលបរិច្ឆេទបង្កើត៖
+pdfjs-document-properties-modification-date = កាលបរិច្ឆេទកែប្រែ៖
+pdfjs-document-properties-creator = អ្នកបង្កើត៖
+pdfjs-document-properties-producer = កម្មវិធីបង្កើត PDF ៖
+pdfjs-document-properties-version = កំណែ PDF ៖
+pdfjs-document-properties-page-count = ចំនួនទំព័រ៖
+pdfjs-document-properties-page-size-unit-inches = អ៊ីញ
+pdfjs-document-properties-page-size-unit-millimeters = មម
+pdfjs-document-properties-page-size-orientation-portrait = បញ្ឈរ
+pdfjs-document-properties-page-size-orientation-landscape = ផ្តេក
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = សំបុត្រ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-linearized-yes = បាទ/ចាស
+pdfjs-document-properties-linearized-no = ទេ
+pdfjs-document-properties-close-button = បិទ
+
+## Print
+
+pdfjs-print-progress-message = កំពុងរៀបចំឯកសារសម្រាប់បោះពុម្ព…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = បោះបង់
+pdfjs-printing-not-supported = ការព្រមាន ៖ ការបោះពុម្ពមិនត្រូវបានគាំទ្រពេញលេញដោយកម្មវិធីរុករកនេះទេ ។
+pdfjs-printing-not-ready = ព្រមាន៖ PDF មិនត្រូវបានផ្ទុកទាំងស្រុងដើម្បីបោះពុម្ពទេ។
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = បិទ/បើកគ្រាប់រំកិល
+pdfjs-toggle-sidebar-button-label = បិទ/បើកគ្រាប់រំកិល
+pdfjs-document-outline-button =
+ .title = បង្ហាញគ្រោងឯកសារ (ចុចទ្វេដងដើម្បីពង្រីក/បង្រួមធាតុទាំងអស់)
+pdfjs-document-outline-button-label = គ្រោងឯកសារ
+pdfjs-attachments-button =
+ .title = បង្ហាញឯកសារភ្ជាប់
+pdfjs-attachments-button-label = ឯកសារភ្ជាប់
+pdfjs-thumbs-button =
+ .title = បង្ហាញរូបភាពតូចៗ
+pdfjs-thumbs-button-label = រួបភាពតូចៗ
+pdfjs-findbar-button =
+ .title = រកនៅក្នុងឯកសារ
+pdfjs-findbar-button-label = រក
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = ទំព័រ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = រូបភាពតូចរបស់ទំព័រ { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = រក
+ .placeholder = រកនៅក្នុងឯកសារ...
+pdfjs-find-previous-button =
+ .title = រកពាក្យ ឬឃ្លាដែលបានជួបមុន
+pdfjs-find-previous-button-label = មុន
+pdfjs-find-next-button =
+ .title = រកពាក្យ ឬឃ្លាដែលបានជួបបន្ទាប់
+pdfjs-find-next-button-label = បន្ទាប់
+pdfjs-find-highlight-checkbox = បន្លិចទាំងអស់
+pdfjs-find-match-case-checkbox-label = ករណីដំណូច
+pdfjs-find-reached-top = បានបន្តពីខាងក្រោម ទៅដល់ខាងលើនៃឯកសារ
+pdfjs-find-reached-bottom = បានបន្តពីខាងលើ ទៅដល់ចុងនៃឯកសារ
+pdfjs-find-not-found = រកមិនឃើញពាក្យ ឬឃ្លា
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ទទឹងទំព័រ
+pdfjs-page-scale-fit = សមទំព័រ
+pdfjs-page-scale-auto = ពង្រីកស្វ័យប្រវត្តិ
+pdfjs-page-scale-actual = ទំហំជាក់ស្ដែង
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = មានកំហុសបានកើតឡើងពេលកំពុងផ្ទុក PDF ។
+pdfjs-invalid-file-error = ឯកសារ PDF ខូច ឬមិនត្រឹមត្រូវ ។
+pdfjs-missing-file-error = បាត់ឯកសារ PDF
+pdfjs-unexpected-response-error = ការឆ្លើយតមម៉ាស៊ីនមេដែលមិនបានរំពឹង។
+pdfjs-rendering-error = មានកំហុសបានកើតឡើងពេលបង្ហាញទំព័រ ។
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } ចំណារពន្យល់]
+
+## Password
+
+pdfjs-password-label = បញ្ចូលពាក្យសម្ងាត់ដើម្បីបើកឯកសារ PDF នេះ។
+pdfjs-password-invalid = ពាក្យសម្ងាត់មិនត្រឹមត្រូវ។ សូមព្យាយាមម្ដងទៀត។
+pdfjs-password-ok-button = យល់ព្រម
+pdfjs-password-cancel-button = បោះបង់
+pdfjs-web-fonts-disabled = បានបិទពុម្ពអក្សរបណ្ដាញ ៖ មិនអាចប្រើពុម្ពអក្សរ PDF ដែលបានបង្កប់បានទេ ។
+
+## Editing
+
+pdfjs-editor-highlight-button =
+ .title = រំលេច
+pdfjs-editor-highlight-button-label = រំលេច
+pdfjs-highlight-floating-button-label = រំលេច
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-cancel-button = បោះបង់
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = បង្ហាញទាំងអស់
+pdfjs-editor-highlight-show-all-button =
+ .title = បង្ហាញទាំងអស់
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+pdfjs-editor-new-alt-text-not-now-button = មិនមែនឥឡូវ
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-delete-model-button = លុប
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = បោះបង់
+
+## Edit a comment dialog
+
+pdfjs-editor-edit-comment-dialog-cancel-button = បោះបង់
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-views-manager-pages-status-delete-button-label = លុប
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kn/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kn/viewer.ftl
new file mode 100644
index 0000000..0da25c5
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/kn/viewer.ftl
@@ -0,0 +1,180 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = ಹಿಂದಿನ ಪುಟ
+pdfjs-previous-button-label = ಹಿಂದಿನ
+pdfjs-next-button =
+ .title = ಮುಂದಿನ ಪುಟ
+pdfjs-next-button-label = ಮುಂದಿನ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ಪುಟ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } ರಲ್ಲಿ
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } ರಲ್ಲಿ { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = ಕಿರಿದಾಗಿಸು
+pdfjs-zoom-out-button-label = ಕಿರಿದಾಗಿಸಿ
+pdfjs-zoom-in-button =
+ .title = ಹಿರಿದಾಗಿಸು
+pdfjs-zoom-in-button-label = ಹಿರಿದಾಗಿಸಿ
+pdfjs-zoom-select =
+ .title = ಗಾತ್ರಬದಲಿಸು
+pdfjs-presentation-mode-button =
+ .title = ಪ್ರಸ್ತುತಿ (ಪ್ರಸೆಂಟೇಶನ್) ಕ್ರಮಕ್ಕೆ ಬದಲಾಯಿಸು
+pdfjs-presentation-mode-button-label = ಪ್ರಸ್ತುತಿ (ಪ್ರಸೆಂಟೇಶನ್) ಕ್ರಮ
+pdfjs-open-file-button =
+ .title = ಕಡತವನ್ನು ತೆರೆ
+pdfjs-open-file-button-label = ತೆರೆಯಿರಿ
+pdfjs-print-button =
+ .title = ಮುದ್ರಿಸು
+pdfjs-print-button-label = ಮುದ್ರಿಸಿ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ಉಪಕರಣಗಳು
+pdfjs-tools-button-label = ಉಪಕರಣಗಳು
+pdfjs-first-page-button =
+ .title = ಮೊದಲ ಪುಟಕ್ಕೆ ತೆರಳು
+pdfjs-first-page-button-label = ಮೊದಲ ಪುಟಕ್ಕೆ ತೆರಳು
+pdfjs-last-page-button =
+ .title = ಕೊನೆಯ ಪುಟಕ್ಕೆ ತೆರಳು
+pdfjs-last-page-button-label = ಕೊನೆಯ ಪುಟಕ್ಕೆ ತೆರಳು
+pdfjs-page-rotate-cw-button =
+ .title = ಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು
+pdfjs-page-rotate-cw-button-label = ಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು
+pdfjs-page-rotate-ccw-button =
+ .title = ಅಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು
+pdfjs-page-rotate-ccw-button-label = ಅಪ್ರದಕ್ಷಿಣೆಯಲ್ಲಿ ತಿರುಗಿಸು
+pdfjs-cursor-text-select-tool-button =
+ .title = ಪಠ್ಯ ಆಯ್ಕೆ ಉಪಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ
+pdfjs-cursor-text-select-tool-button-label = ಪಠ್ಯ ಆಯ್ಕೆಯ ಉಪಕರಣ
+pdfjs-cursor-hand-tool-button =
+ .title = ಕೈ ಉಪಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ
+pdfjs-cursor-hand-tool-button-label = ಕೈ ಉಪಕರಣ
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = ಡಾಕ್ಯುಮೆಂಟ್ ಗುಣಗಳು...
+pdfjs-document-properties-button-label = ಡಾಕ್ಯುಮೆಂಟ್ ಗುಣಗಳು...
+pdfjs-document-properties-file-name = ಕಡತದ ಹೆಸರು:
+pdfjs-document-properties-file-size = ಕಡತದ ಗಾತ್ರ:
+pdfjs-document-properties-title = ಶೀರ್ಷಿಕೆ:
+pdfjs-document-properties-author = ಕರ್ತೃ:
+pdfjs-document-properties-subject = ವಿಷಯ:
+pdfjs-document-properties-keywords = ಮುಖ್ಯಪದಗಳು:
+pdfjs-document-properties-creation-date = ರಚಿಸಿದ ದಿನಾಂಕ:
+pdfjs-document-properties-modification-date = ಮಾರ್ಪಡಿಸಲಾದ ದಿನಾಂಕ:
+pdfjs-document-properties-creator = ರಚಿಸಿದವರು:
+pdfjs-document-properties-producer = PDF ಉತ್ಪಾದಕ:
+pdfjs-document-properties-version = PDF ಆವೃತ್ತಿ:
+pdfjs-document-properties-page-count = ಪುಟದ ಎಣಿಕೆ:
+pdfjs-document-properties-page-size-unit-inches = ಇದರಲ್ಲಿ
+pdfjs-document-properties-page-size-orientation-portrait = ಭಾವಚಿತ್ರ
+pdfjs-document-properties-page-size-orientation-landscape = ಪ್ರಕೃತಿ ಚಿತ್ರ
+
+##
+
+pdfjs-document-properties-close-button = ಮುಚ್ಚು
+
+## Print
+
+pdfjs-print-progress-message = ಮುದ್ರಿಸುವುದಕ್ಕಾಗಿ ದಸ್ತಾವೇಜನ್ನು ಸಿದ್ಧಗೊಳಿಸಲಾಗುತ್ತಿದೆ…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ರದ್ದು ಮಾಡು
+pdfjs-printing-not-supported = ಎಚ್ಚರಿಕೆ: ಈ ಜಾಲವೀಕ್ಷಕದಲ್ಲಿ ಮುದ್ರಣಕ್ಕೆ ಸಂಪೂರ್ಣ ಬೆಂಬಲವಿಲ್ಲ.
+pdfjs-printing-not-ready = ಎಚ್ಚರಿಕೆ: PDF ಕಡತವು ಮುದ್ರಿಸಲು ಸಂಪೂರ್ಣವಾಗಿ ಲೋಡ್ ಆಗಿಲ್ಲ.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = ಬದಿಪಟ್ಟಿಯನ್ನು ಹೊರಳಿಸು
+pdfjs-toggle-sidebar-button-label = ಬದಿಪಟ್ಟಿಯನ್ನು ಹೊರಳಿಸು
+pdfjs-document-outline-button-label = ದಸ್ತಾವೇಜಿನ ಹೊರರೇಖೆ
+pdfjs-attachments-button =
+ .title = ಲಗತ್ತುಗಳನ್ನು ತೋರಿಸು
+pdfjs-attachments-button-label = ಲಗತ್ತುಗಳು
+pdfjs-thumbs-button =
+ .title = ಚಿಕ್ಕಚಿತ್ರದಂತೆ ತೋರಿಸು
+pdfjs-thumbs-button-label = ಚಿಕ್ಕಚಿತ್ರಗಳು
+pdfjs-findbar-button =
+ .title = ದಸ್ತಾವೇಜಿನಲ್ಲಿ ಹುಡುಕು
+pdfjs-findbar-button-label = ಹುಡುಕು
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = ಪುಟ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = ಪುಟವನ್ನು ಚಿಕ್ಕಚಿತ್ರದಂತೆ ತೋರಿಸು { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ಹುಡುಕು
+ .placeholder = ದಸ್ತಾವೇಜಿನಲ್ಲಿ ಹುಡುಕು…
+pdfjs-find-previous-button =
+ .title = ವಾಕ್ಯದ ಹಿಂದಿನ ಇರುವಿಕೆಯನ್ನು ಹುಡುಕು
+pdfjs-find-previous-button-label = ಹಿಂದಿನ
+pdfjs-find-next-button =
+ .title = ವಾಕ್ಯದ ಮುಂದಿನ ಇರುವಿಕೆಯನ್ನು ಹುಡುಕು
+pdfjs-find-next-button-label = ಮುಂದಿನ
+pdfjs-find-highlight-checkbox = ಎಲ್ಲವನ್ನು ಹೈಲೈಟ್ ಮಾಡು
+pdfjs-find-match-case-checkbox-label = ಕೇಸನ್ನು ಹೊಂದಿಸು
+pdfjs-find-reached-top = ದಸ್ತಾವೇಜಿನ ಮೇಲ್ಭಾಗವನ್ನು ತಲುಪಿದೆ, ಕೆಳಗಿನಿಂದ ಆರಂಭಿಸು
+pdfjs-find-reached-bottom = ದಸ್ತಾವೇಜಿನ ಕೊನೆಯನ್ನು ತಲುಪಿದೆ, ಮೇಲಿನಿಂದ ಆರಂಭಿಸು
+pdfjs-find-not-found = ವಾಕ್ಯವು ಕಂಡು ಬಂದಿಲ್ಲ
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ಪುಟದ ಅಗಲ
+pdfjs-page-scale-fit = ಪುಟದ ಸರಿಹೊಂದಿಕೆ
+pdfjs-page-scale-auto = ಸ್ವಯಂಚಾಲಿತ ಗಾತ್ರಬದಲಾವಣೆ
+pdfjs-page-scale-actual = ನಿಜವಾದ ಗಾತ್ರ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF ಅನ್ನು ಲೋಡ್ ಮಾಡುವಾಗ ಒಂದು ದೋಷ ಎದುರಾಗಿದೆ.
+pdfjs-invalid-file-error = ಅಮಾನ್ಯವಾದ ಅಥವ ಹಾಳಾದ PDF ಕಡತ.
+pdfjs-missing-file-error = PDF ಕಡತ ಇಲ್ಲ.
+pdfjs-unexpected-response-error = ಅನಿರೀಕ್ಷಿತವಾದ ಪೂರೈಕೆಗಣಕದ ಪ್ರತಿಕ್ರಿಯೆ.
+pdfjs-rendering-error = ಪುಟವನ್ನು ನಿರೂಪಿಸುವಾಗ ಒಂದು ದೋಷ ಎದುರಾಗಿದೆ.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } ಟಿಪ್ಪಣಿ]
+
+## Password
+
+pdfjs-password-label = PDF ಅನ್ನು ತೆರೆಯಲು ಗುಪ್ತಪದವನ್ನು ನಮೂದಿಸಿ.
+pdfjs-password-invalid = ಅಮಾನ್ಯವಾದ ಗುಪ್ತಪದ, ದಯವಿಟ್ಟು ಇನ್ನೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಿ.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = ರದ್ದು ಮಾಡು
+pdfjs-web-fonts-disabled = ಜಾಲ ಅಕ್ಷರಶೈಲಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ: ಅಡಕಗೊಳಿಸಿದ PDF ಅಕ್ಷರಶೈಲಿಗಳನ್ನು ಬಳಸಲು ಸಾಧ್ಯವಾಗಿಲ್ಲ.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ko/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ko/viewer.ftl
new file mode 100644
index 0000000..26346cf
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ko/viewer.ftl
@@ -0,0 +1,780 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = 이전 페이지
+pdfjs-previous-button-label = 이전
+pdfjs-next-button =
+ .title = 다음 페이지
+pdfjs-next-button-label = 다음
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = 페이지
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = 축소
+pdfjs-zoom-out-button-label = 축소
+pdfjs-zoom-in-button =
+ .title = 확대
+pdfjs-zoom-in-button-label = 확대
+pdfjs-zoom-select =
+ .title = 확대/축소
+pdfjs-presentation-mode-button =
+ .title = 프레젠테이션 모드로 전환
+pdfjs-presentation-mode-button-label = 프레젠테이션 모드
+pdfjs-open-file-button =
+ .title = 파일 열기
+pdfjs-open-file-button-label = 열기
+pdfjs-print-button =
+ .title = 인쇄
+pdfjs-print-button-label = 인쇄
+pdfjs-save-button =
+ .title = 저장
+pdfjs-save-button-label = 저장
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = 다운로드
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = 다운로드
+pdfjs-bookmark-button =
+ .title = 현재 페이지 (URL 보기)
+pdfjs-bookmark-button-label = 현재 페이지
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = 도구
+pdfjs-tools-button-label = 도구
+pdfjs-first-page-button =
+ .title = 첫 페이지로 이동
+pdfjs-first-page-button-label = 첫 페이지로 이동
+pdfjs-last-page-button =
+ .title = 마지막 페이지로 이동
+pdfjs-last-page-button-label = 마지막 페이지로 이동
+pdfjs-page-rotate-cw-button =
+ .title = 시계방향으로 회전
+pdfjs-page-rotate-cw-button-label = 시계방향으로 회전
+pdfjs-page-rotate-ccw-button =
+ .title = 시계 반대방향으로 회전
+pdfjs-page-rotate-ccw-button-label = 시계 반대방향으로 회전
+pdfjs-cursor-text-select-tool-button =
+ .title = 텍스트 선택 도구 활성화
+pdfjs-cursor-text-select-tool-button-label = 텍스트 선택 도구
+pdfjs-cursor-hand-tool-button =
+ .title = 손 도구 활성화
+pdfjs-cursor-hand-tool-button-label = 손 도구
+pdfjs-scroll-page-button =
+ .title = 페이지 스크롤 사용
+pdfjs-scroll-page-button-label = 페이지 스크롤
+pdfjs-scroll-vertical-button =
+ .title = 세로 스크롤 사용
+pdfjs-scroll-vertical-button-label = 세로 스크롤
+pdfjs-scroll-horizontal-button =
+ .title = 가로 스크롤 사용
+pdfjs-scroll-horizontal-button-label = 가로 스크롤
+pdfjs-scroll-wrapped-button =
+ .title = 자동 줄바꿈 스크롤 사용
+pdfjs-scroll-wrapped-button-label = 자동 줄바꿈 스크롤
+pdfjs-spread-none-button =
+ .title = 한 페이지 보기
+pdfjs-spread-none-button-label = 펼침 없음
+pdfjs-spread-odd-button =
+ .title = 홀수 페이지로 시작하는 두 페이지 보기
+pdfjs-spread-odd-button-label = 홀수 펼침
+pdfjs-spread-even-button =
+ .title = 짝수 페이지로 시작하는 두 페이지 보기
+pdfjs-spread-even-button-label = 짝수 펼침
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = 문서 속성…
+pdfjs-document-properties-button-label = 문서 속성…
+pdfjs-document-properties-file-name = 파일 이름:
+pdfjs-document-properties-file-size = 파일 크기:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } 바이트)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } 바이트)
+pdfjs-document-properties-title = 제목:
+pdfjs-document-properties-author = 작성자:
+pdfjs-document-properties-subject = 주제:
+pdfjs-document-properties-keywords = 키워드:
+pdfjs-document-properties-creation-date = 작성 날짜:
+pdfjs-document-properties-modification-date = 수정 날짜:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = 작성 프로그램:
+pdfjs-document-properties-producer = PDF 변환 소프트웨어:
+pdfjs-document-properties-version = PDF 버전:
+pdfjs-document-properties-page-count = 페이지 수:
+pdfjs-document-properties-page-size = 페이지 크기:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = 세로 방향
+pdfjs-document-properties-page-size-orientation-landscape = 가로 방향
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = 레터
+pdfjs-document-properties-page-size-name-legal = 리걸
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = 빠른 웹 보기:
+pdfjs-document-properties-linearized-yes = 예
+pdfjs-document-properties-linearized-no = 아니요
+pdfjs-document-properties-close-button = 닫기
+pdfjs-digital-signature-properties-view-certificate = 인증서 보기
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = 이유: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = 타임스탬프: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures = 하위 서명 ({ $count }개)
+
+## Print
+
+pdfjs-print-progress-message = 인쇄 문서 준비 중…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = 취소
+pdfjs-printing-not-supported = 경고: 이 브라우저는 인쇄를 완전히 지원하지 않습니다.
+pdfjs-printing-not-ready = 경고: 이 PDF를 인쇄를 할 수 있을 정도로 읽어들이지 못했습니다.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = 사이드바 표시/숨기기
+pdfjs-toggle-sidebar-notification-button =
+ .title = 사이드바 표시/숨기기 (문서에 아웃라인/첨부파일/레이어 포함됨)
+pdfjs-toggle-sidebar-button-label = 사이드바 표시/숨기기
+pdfjs-document-outline-button =
+ .title = 문서 아웃라인 보기 (더블 클릭해서 모든 항목 펼치기/접기)
+pdfjs-document-outline-button-label = 문서 아웃라인
+pdfjs-attachments-button =
+ .title = 첨부파일 보기
+pdfjs-attachments-button-label = 첨부파일
+pdfjs-layers-button =
+ .title = 레이어 보기 (더블 클릭해서 모든 레이어를 기본 상태로 재설정)
+pdfjs-layers-button-label = 레이어
+pdfjs-thumbs-button =
+ .title = 미리보기
+pdfjs-thumbs-button-label = 미리보기
+pdfjs-current-outline-item-button =
+ .title = 현재 아웃라인 항목 찾기
+pdfjs-current-outline-item-button-label = 현재 아웃라인 항목
+pdfjs-findbar-button =
+ .title = 검색
+pdfjs-findbar-button-label = 검색
+pdfjs-additional-layers = 추가 레이어
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } 페이지
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } 페이지 미리보기
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = { $page } 페이지 선택
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = { $page } / { $total } 페이지
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = 찾기
+ .placeholder = 문서에서 찾기…
+pdfjs-find-previous-button =
+ .title = 지정 문자열에 일치하는 1개 부분을 검색
+pdfjs-find-previous-button-label = 이전
+pdfjs-find-next-button =
+ .title = 지정 문자열에 일치하는 다음 부분을 검색
+pdfjs-find-next-button-label = 다음
+pdfjs-find-highlight-checkbox = 모두 강조 표시
+pdfjs-find-match-case-checkbox-label = 대/소문자 구분
+pdfjs-find-match-diacritics-checkbox-label = 분음 부호 일치
+pdfjs-find-entire-word-checkbox-label = 단어 단위로
+pdfjs-find-reached-top = 문서 처음까지 검색하고 끝으로 돌아와 검색했습니다.
+pdfjs-find-reached-bottom = 문서 끝까지 검색하고 앞으로 돌아와 검색했습니다.
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = { $current } / { $total } 일치
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = { $limit }개 이상 일치
+pdfjs-find-not-found = 검색 결과 없음
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = 페이지 너비에 맞추기
+pdfjs-page-scale-fit = 페이지에 맞추기
+pdfjs-page-scale-auto = 자동
+pdfjs-page-scale-actual = 실제 크기
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page } 페이지
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF를 로드하는 동안 오류가 발생했습니다.
+pdfjs-invalid-file-error = 잘못되었거나 손상된 PDF 파일.
+pdfjs-missing-file-error = PDF 파일 없음.
+pdfjs-unexpected-response-error = 예기치 않은 서버 응답입니다.
+pdfjs-rendering-error = 페이지를 렌더링하는 동안 오류가 발생했습니다.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } 주석]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = 이 PDF 파일을 열 수 있는 비밀번호를 입력하세요.
+pdfjs-password-invalid = 잘못된 비밀번호입니다. 다시 시도하세요.
+pdfjs-password-ok-button = 확인
+pdfjs-password-cancel-button = 취소
+pdfjs-web-fonts-disabled = 웹 폰트가 비활성화됨: 내장된 PDF 글꼴을 사용할 수 없습니다.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = 텍스트
+pdfjs-editor-color-picker-free-text-input =
+ .title = 텍스트 색상 변경
+pdfjs-editor-free-text-button-label = 텍스트
+pdfjs-editor-ink-button =
+ .title = 그리기
+pdfjs-editor-color-picker-ink-input =
+ .title = 그리기 색상 변경
+pdfjs-editor-ink-button-label = 그리기
+pdfjs-editor-stamp-button =
+ .title = 이미지 추가 또는 편집
+pdfjs-editor-stamp-button-label = 이미지 추가 또는 편집
+pdfjs-editor-highlight-button =
+ .title = 강조 표시
+pdfjs-editor-highlight-button-label = 강조 표시
+pdfjs-highlight-floating-button1 =
+ .title = 강조 표시
+ .aria-label = 강조 표시
+pdfjs-highlight-floating-button-label = 강조 표시
+pdfjs-comment-floating-button =
+ .title = 주석
+ .aria-label = 주석
+pdfjs-comment-floating-button-label = 주석
+pdfjs-editor-comment-button =
+ .title = 주석
+ .aria-label = 주석
+pdfjs-editor-comment-button-label = 주석
+pdfjs-editor-signature-button =
+ .title = 서명 추가
+pdfjs-editor-signature-button-label = 서명 추가
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = 강조 표시 편집기
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = 그리기 편집기
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = 서명 편집기: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = 이미지 편집기
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = 그리기 제거
+pdfjs-editor-remove-freetext-button =
+ .title = 텍스트 제거
+pdfjs-editor-remove-stamp-button =
+ .title = 이미지 제거
+pdfjs-editor-remove-highlight-button =
+ .title = 강조 표시 제거
+pdfjs-editor-remove-signature-button =
+ .title = 서명 제거
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = 색상
+pdfjs-editor-free-text-size-input = 크기
+pdfjs-editor-ink-color-input = 색상
+pdfjs-editor-ink-thickness-input = 두께
+pdfjs-editor-ink-opacity-input = 불투명도
+pdfjs-editor-stamp-add-image-button =
+ .title = 이미지 추가
+pdfjs-editor-stamp-add-image-button-label = 이미지 추가
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = 두께
+pdfjs-editor-free-highlight-thickness-title =
+ .title = 텍스트 이외의 항목을 강조 표시할 때 두께 변경
+pdfjs-editor-add-signature-container =
+ .aria-label = 서명 제어 및 저장된 서명
+pdfjs-editor-signature-add-signature-button =
+ .title = 새 서명 추가
+pdfjs-editor-signature-add-signature-button-label = 새 서명 추가
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = 저장된 서명: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = 텍스트 편집기
+ .default-content = 입력하세요…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title = 주석
+pdfjs-editor-comments-sidebar-close-button =
+ .title = 사이드바 닫기
+ .aria-label = 사이드바 닫기
+pdfjs-editor-comments-sidebar-close-button-label = 사이드바 닫기
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = 눈에 띄는 내용이 있나요? 해당 부분을 강조 표시하고 주석을 남겨주세요.
+pdfjs-editor-comments-sidebar-no-comments-link = 더 알아보기
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = 대체 텍스트
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = 대체 텍스트 편집
+pdfjs-editor-alt-text-dialog-label = 옵션을 선택하세요
+pdfjs-editor-alt-text-dialog-description = 대체 텍스트는 사람들이 이미지를 볼 수 없거나 이미지가 로드되지 않을 때 도움이 됩니다.
+pdfjs-editor-alt-text-add-description-label = 설명 추가
+pdfjs-editor-alt-text-add-description-description = 주제, 설정, 동작을 설명하는 1~2개의 문장을 목표로 하세요.
+pdfjs-editor-alt-text-mark-decorative-label = 장식용으로 표시
+pdfjs-editor-alt-text-mark-decorative-description = 테두리나 워터마크와 같은 장식적인 이미지에 사용됩니다.
+pdfjs-editor-alt-text-cancel-button = 취소
+pdfjs-editor-alt-text-save-button = 저장
+pdfjs-editor-alt-text-decorative-tooltip = 장식용으로 표시됨
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = 예를 들어, “한 청년이 식탁에 앉아 식사를 하고 있습니다.”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = 대체 텍스트
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = 왼쪽 위 — 크기 조정
+pdfjs-editor-resizer-top-middle =
+ .aria-label = 가운데 위 - 크기 조정
+pdfjs-editor-resizer-top-right =
+ .aria-label = 오른쪽 위 — 크기 조정
+pdfjs-editor-resizer-middle-right =
+ .aria-label = 오른쪽 가운데 — 크기 조정
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = 오른쪽 아래 - 크기 조정
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = 가운데 아래 — 크기 조정
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = 왼쪽 아래 - 크기 조정
+pdfjs-editor-resizer-middle-left =
+ .aria-label = 왼쪽 가운데 — 크기 조정
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = 색상
+pdfjs-editor-colorpicker-button =
+ .title = 색상 변경
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = 색상 선택
+pdfjs-editor-colorpicker-yellow =
+ .title = 노란색
+pdfjs-editor-colorpicker-green =
+ .title = 녹색
+pdfjs-editor-colorpicker-blue =
+ .title = 파란색
+pdfjs-editor-colorpicker-pink =
+ .title = 분홍색
+pdfjs-editor-colorpicker-red =
+ .title = 빨간색
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = 모두 보기
+pdfjs-editor-highlight-show-all-button =
+ .title = 모두 보기
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = 대체 텍스트 (이미지 설명) 편집
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = 대체 텍스트 (이미지 설명) 추가
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = 여기에 설명을 작성하세요…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = 이미지가 보이지 않거나 이미지가 로딩되지 않는 경우를 위한 간단한 설명입니다.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = 이 대체 텍스트는 자동으로 생성되었으므로 정확하지 않을 수 있습니다.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = 더 알아보기
+pdfjs-editor-new-alt-text-create-automatically-button-label = 자동으로 대체 텍스트 생성
+pdfjs-editor-new-alt-text-not-now-button = 나중에
+pdfjs-editor-new-alt-text-error-title = 대체 텍스트를 자동으로 생성할 수 없습니다.
+pdfjs-editor-new-alt-text-error-description = 대체 텍스트를 직접 작성하거나 나중에 다시 시도하세요.
+pdfjs-editor-new-alt-text-error-close-button = 닫기
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = 대체 텍스트 AI 모델 다운로드 중 ({ $downloadedSize } / { $totalSize } MB)
+ .aria-valuetext = 대체 텍스트 AI 모델 다운로드 중 ({ $downloadedSize } / { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = 대체 텍스트 추가됨
+pdfjs-editor-new-alt-text-added-button-label = 대체 텍스트 추가됨
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = 대체 텍스트 누락
+pdfjs-editor-new-alt-text-missing-button-label = 대체 텍스트 누락
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = 대체 텍스트 검토
+pdfjs-editor-new-alt-text-to-review-button-label = 대체 텍스트 검토
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = 자동으로 생성됨: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = 이미지 대체 텍스트 설정
+pdfjs-image-alt-text-settings-button-label = 이미지 대체 텍스트 설정
+pdfjs-editor-alt-text-settings-dialog-label = 이미지 대체 텍스트 설정
+pdfjs-editor-alt-text-settings-automatic-title = 자동 대체 텍스트
+pdfjs-editor-alt-text-settings-create-model-button-label = 자동으로 대체 텍스트 생성
+pdfjs-editor-alt-text-settings-create-model-description = 이미지가 보이지 않거나 이미지가 로딩되지 않을 때 도움이 되는 설명을 제안합니다.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = 대체 텍스트 AI 모델 ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = 사용자의 장치에서 로컬로 실행되므로 데이터가 비공개로 유지됩니다. 자동 대체 텍스트에 필요합니다.
+pdfjs-editor-alt-text-settings-delete-model-button = 삭제
+pdfjs-editor-alt-text-settings-download-model-button = 다운로드
+pdfjs-editor-alt-text-settings-downloading-model-button = 다운로드 중…
+pdfjs-editor-alt-text-settings-editor-title = 대체 텍스트 편집기
+pdfjs-editor-alt-text-settings-show-dialog-button-label = 이미지 추가 시 바로 대체 텍스트 편집기 표시
+pdfjs-editor-alt-text-settings-show-dialog-description = 모든 이미지에 대체 텍스트가 있는지 확인하는 데 도움이 됩니다.
+pdfjs-editor-alt-text-settings-close-button = 닫기
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = 강조 표시 추가됨
+pdfjs-editor-freetext-added-alert = 텍스트 추가됨
+pdfjs-editor-ink-added-alert = 그리기 추가됨
+pdfjs-editor-stamp-added-alert = 이미지 추가됨
+pdfjs-editor-signature-added-alert = 서명 추가됨
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = 강조 표시 제거됨
+pdfjs-editor-undo-bar-message-freetext = 텍스트 제거됨
+pdfjs-editor-undo-bar-message-ink = 그리기 제거됨
+pdfjs-editor-undo-bar-message-stamp = 이미지 제거됨
+pdfjs-editor-undo-bar-message-signature = 서명 제거됨
+pdfjs-editor-undo-bar-message-comment = 주석 제거됨
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = 주석 { $count }개 제거됨
+pdfjs-editor-undo-bar-undo-button =
+ .title = 실행 취소
+pdfjs-editor-undo-bar-undo-button-label = 실행 취소
+pdfjs-editor-undo-bar-close-button =
+ .title = 닫기
+pdfjs-editor-undo-bar-close-button-label = 닫기
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = 이 모달로 PDF 문서에 추가 할 서명을 만들 수 있습니다. 사용자는 이름(대체 텍스트 역할도 함)을 편집하고, 반복해 사용할 수 있도록 서명을 저장할 수도 있습니다.
+pdfjs-editor-add-signature-dialog-title = 서명 추가
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = 입력
+ .title = 입력
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = 그리기
+ .title = 그리기
+pdfjs-editor-add-signature-image-button = 이미지
+ .title = 이미지
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = 서명 입력
+ .placeholder = 서명 입력
+pdfjs-editor-add-signature-draw-placeholder = 서명 그리기
+pdfjs-editor-add-signature-draw-thickness-range-label = 두께
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = 그리기 두께: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = 이미지 파일을 여기에 끌어다 놓으세요
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] 또는 이미지 파일 찾아보기
+ *[other] 또는 이미지 파일 찾아보기
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = 설명 (대체 텍스트)
+pdfjs-editor-add-signature-description-input =
+ .title = 설명 (대체 텍스트)
+pdfjs-editor-add-signature-description-default-when-drawing = 서명
+pdfjs-editor-add-signature-clear-button-label = 서명 지우기
+pdfjs-editor-add-signature-clear-button =
+ .title = 서명 지우기
+pdfjs-editor-add-signature-save-checkbox = 서명 저장
+pdfjs-editor-add-signature-save-warning-message = 저장된 서명의 한계에 도달했습니다. 더 저장하려면 하나를 제거하세요.
+pdfjs-editor-add-signature-image-upload-error-title = 이미지를 업로드할 수 없음
+pdfjs-editor-add-signature-image-upload-error-description = 네트워크 연결을 확인하거나 다른 이미지로 시도하세요.
+pdfjs-editor-add-signature-image-no-data-error-title = 이 이미지를 서명으로 변환할 수 없음
+pdfjs-editor-add-signature-image-no-data-error-description = 다른 이미지를 업로드 해 주세요.
+pdfjs-editor-add-signature-error-close-button = 닫기
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = 취소
+pdfjs-editor-add-signature-add-button = 추가
+pdfjs-editor-edit-signature-update-button = 업데이트
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = 주석 편집
+pdfjs-editor-edit-comment-popup-button =
+ .title = 주석 편집
+pdfjs-editor-delete-comment-popup-button-label = 주석 제거
+pdfjs-editor-delete-comment-popup-button =
+ .title = 주석 제거
+pdfjs-show-comment-button =
+ .title = 주석 보기
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = 주석 편집
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = 업데이트
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = 주석 추가
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = 추가
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = 입력하세요…
+pdfjs-editor-edit-comment-dialog-cancel-button = 취소
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = 주석 추가
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = 사이드바 표시/숨기기 (문서에 미리보기/아웃라인/첨부파일/레이어 포함됨)
+pdfjs-toggle-views-manager-button1-label = 페이지 관리
+pdfjs-views-manager-sidebar =
+ .aria-label = 사이드바
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = 사이드바 크기 조정
+pdfjs-views-manager-view-selector-button =
+ .title = 보기
+pdfjs-views-manager-view-selector-button-label = 보기
+pdfjs-views-manager-pages-title = 페이지
+pdfjs-views-manager-outlines-title1 = 문서 아웃라인
+ .title = 문서 아웃라인 (더블 클릭해서 모든 항목 펼치기/접기)
+pdfjs-views-manager-attachments-title = 첨부파일
+pdfjs-views-manager-layers-title1 = 레이어
+ .title = 레이어 (더블 클릭해서 모든 레이어를 기본 상태로 재설정)
+pdfjs-views-manager-pages-option-label = 페이지
+pdfjs-views-manager-outlines-option-label = 문서 아웃라인
+pdfjs-views-manager-attachments-option-label = 첨부파일
+pdfjs-views-manager-layers-option-label = 레이어
+pdfjs-views-manager-add-file-button =
+ .title = 파일 추가
+pdfjs-views-manager-add-file-button-label = 파일 추가
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label = { $count }개 선택됨
+pdfjs-views-manager-pages-status-none-action-label = 페이지 선택
+pdfjs-views-manager-pages-status-action-button-label = 관리
+pdfjs-views-manager-pages-status-copy-button-label = 복사
+pdfjs-views-manager-pages-status-cut-button-label = 잘라내기
+pdfjs-views-manager-pages-status-delete-button-label = 삭제
+pdfjs-views-manager-pages-status-export-selected-button-label = 선택한 페이지 내보내기…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label = { $count }개 페이지 잘림
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label = { $count }개 페이지 복사됨
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label = { $count }개 페이지 삭제됨
+pdfjs-views-manager-pages-status-waiting-ready-label = 파일 준비 중…
+pdfjs-views-manager-pages-status-waiting-uploading-label = 파일 업로드 중…
+pdfjs-views-manager-status-warning-cut-label = 잘라낼 수 없습니다. 페이지를 새로 고침하고 다시 시도하세요.
+pdfjs-views-manager-status-warning-copy-label = 복사할 수 없습니다. 페이지를 새로 고침하고 다시 시도하세요.
+pdfjs-views-manager-status-warning-delete-label = 삭제할 수 없습니다. 페이지를 새로 고침하고 다시 시도하세요.
+pdfjs-views-manager-status-warning-save-label = 저장할 수 없습니다. 페이지를 새로 고침하고 다시 시도하세요.
+pdfjs-views-manager-status-undo-button-label = 실행 취소
+pdfjs-views-manager-status-done-button-label = 완료
+pdfjs-views-manager-status-close-button =
+ .title = 닫기
+pdfjs-views-manager-status-close-button-label = 닫기
+pdfjs-views-manager-paste-button-label = 붙여넣기
+pdfjs-views-manager-paste-button-before =
+ .title = 첫 페이지 앞에 붙여넣기
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = { $page } 페이지 뒤에 붙여넣기
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = 신규
+pdfjs-views-manager-waiting-for-file = 파일 업로드 중…
+pdfjs-toggle-views-manager-button1 =
+ .title = 페이지 관리
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = 디지털 서명 속성
+ .aria-label = 디지털 서명 속성
+pdfjs-digital-signature-properties-button-label = 디지털 서명 속성
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = 유효한 디지털 서명으로 문서에 서명되었습니다
+pdfjs-digital-signature-properties-banner-unknown = 문서에 서명되었지만 { $count }개의 디지털 서명을 확인할 수 없음
+pdfjs-digital-signature-properties-banner-untrusted = 신뢰할 수 없는 { $count }개의 인증서로 서명된 문서
+pdfjs-digital-signature-properties-banner-expired = { $count }개의 만료된 인증서로 서명된 문서
+pdfjs-digital-signature-properties-banner-invalid = 문서에 잘못된 { $count }개의 디지털 서명이 있음
+pdfjs-digital-signature-properties-banner-revoked = 폐기된 인증서 { $count }개로 서명된 문서
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = 상태: 서명 확인됨
+pdfjs-digital-signature-properties-status-invalid = 상태: 유효하지 않은 서명
+pdfjs-digital-signature-properties-status-unknown = 상태: 확인할 수 없음 (지원되지 않음)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = 인증서: 신뢰할 수 있음 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = 인증서: 사용할 수 없음
+pdfjs-digital-signature-properties-certificate-untrusted = 인증서: 신뢰할 수 없음
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = 인증서: 알 수 없는 발급자 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = 인증서: 자체 서명 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = 인증서: 신뢰할 수 없는 발급자 ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = 인증서: 만료됨
+pdfjs-digital-signature-properties-certificate-expired-with-date = 인증서: 만료됨 ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = 인증서: 폐기됨
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = 저장된 서명 제거
+pdfjs-editor-delete-signature-button-label1 = 저장된 서명 제거
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = 설명 편집
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = 설명 편집
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lij/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lij/viewer.ftl
new file mode 100644
index 0000000..8847b25
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lij/viewer.ftl
@@ -0,0 +1,222 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagina primma
+pdfjs-previous-button-label = Precedente
+pdfjs-next-button =
+ .title = Pagina dòppo
+pdfjs-next-button-label = Pròscima
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Diminoisci zoom
+pdfjs-zoom-out-button-label = Diminoisci zoom
+pdfjs-zoom-in-button =
+ .title = Aomenta zoom
+pdfjs-zoom-in-button-label = Aomenta zoom
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Vanni into mòddo de prezentaçion
+pdfjs-presentation-mode-button-label = Mòddo de prezentaçion
+pdfjs-open-file-button =
+ .title = Arvi file
+pdfjs-open-file-button-label = Arvi
+pdfjs-print-button =
+ .title = Stanpa
+pdfjs-print-button-label = Stanpa
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Atressi
+pdfjs-tools-button-label = Atressi
+pdfjs-first-page-button =
+ .title = Vanni a-a primma pagina
+pdfjs-first-page-button-label = Vanni a-a primma pagina
+pdfjs-last-page-button =
+ .title = Vanni a l'urtima pagina
+pdfjs-last-page-button-label = Vanni a l'urtima pagina
+pdfjs-page-rotate-cw-button =
+ .title = Gia into verso oraio
+pdfjs-page-rotate-cw-button-label = Gia into verso oraio
+pdfjs-page-rotate-ccw-button =
+ .title = Gia into verso antioraio
+pdfjs-page-rotate-ccw-button-label = Gia into verso antioraio
+pdfjs-cursor-text-select-tool-button =
+ .title = Abilita strumento de seleçion do testo
+pdfjs-cursor-text-select-tool-button-label = Strumento de seleçion do testo
+pdfjs-cursor-hand-tool-button =
+ .title = Abilita strumento man
+pdfjs-cursor-hand-tool-button-label = Strumento man
+pdfjs-scroll-vertical-button =
+ .title = Deuvia rebelamento verticale
+pdfjs-scroll-vertical-button-label = Rebelamento verticale
+pdfjs-scroll-horizontal-button =
+ .title = Deuvia rebelamento orizontâ
+pdfjs-scroll-horizontal-button-label = Rebelamento orizontâ
+pdfjs-scroll-wrapped-button =
+ .title = Deuvia rebelamento incapsolou
+pdfjs-scroll-wrapped-button-label = Rebelamento incapsolou
+pdfjs-spread-none-button =
+ .title = No unite a-a difuxon de pagina
+pdfjs-spread-none-button-label = No difuxon
+pdfjs-spread-odd-button =
+ .title = Uniscite a-a difuxon de pagina co-o numero dèspa
+pdfjs-spread-odd-button-label = Difuxon dèspa
+pdfjs-spread-even-button =
+ .title = Uniscite a-a difuxon de pagina co-o numero pari
+pdfjs-spread-even-button-label = Difuxon pari
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propietæ do documento…
+pdfjs-document-properties-button-label = Propietæ do documento…
+pdfjs-document-properties-file-name = Nomme schedaio:
+pdfjs-document-properties-file-size = Dimenscion schedaio:
+pdfjs-document-properties-title = Titolo:
+pdfjs-document-properties-author = Aoto:
+pdfjs-document-properties-subject = Ogetto:
+pdfjs-document-properties-keywords = Paròlle ciave:
+pdfjs-document-properties-creation-date = Dæta creaçion:
+pdfjs-document-properties-modification-date = Dæta cangiamento:
+pdfjs-document-properties-creator = Aotô originale:
+pdfjs-document-properties-producer = Produtô PDF:
+pdfjs-document-properties-version = Verscion PDF:
+pdfjs-document-properties-page-count = Contezzo pagine:
+pdfjs-document-properties-page-size = Dimenscion da pagina:
+pdfjs-document-properties-page-size-unit-inches = dii gròsci
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = drito
+pdfjs-document-properties-page-size-orientation-landscape = desteizo
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letia
+pdfjs-document-properties-page-size-name-legal = Lezze
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista veloce do Web:
+pdfjs-document-properties-linearized-yes = Sci
+pdfjs-document-properties-linearized-no = No
+pdfjs-document-properties-close-button = Særa
+
+## Print
+
+pdfjs-print-progress-message = Praparo o documento pe-a stanpa…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Anulla
+pdfjs-printing-not-supported = Atençion: a stanpa a no l'é conpletamente soportâ da sto navegatô.
+pdfjs-printing-not-ready = Atençion: o PDF o no l'é ancon caregou conpletamente pe-a stanpa.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Ativa/dizativa bara de scianco
+pdfjs-toggle-sidebar-button-label = Ativa/dizativa bara de scianco
+pdfjs-document-outline-button =
+ .title = Fanni vedde o contorno do documento (scicca doggio pe espande/ridue tutti i elementi)
+pdfjs-document-outline-button-label = Contorno do documento
+pdfjs-attachments-button =
+ .title = Fanni vedde alegæ
+pdfjs-attachments-button-label = Alegæ
+pdfjs-thumbs-button =
+ .title = Mostra miniatue
+pdfjs-thumbs-button-label = Miniatue
+pdfjs-findbar-button =
+ .title = Treuva into documento
+pdfjs-findbar-button-label = Treuva
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatua da pagina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Treuva
+ .placeholder = Treuva into documento…
+pdfjs-find-previous-button =
+ .title = Treuva a ripetiçion precedente do testo da çercâ
+pdfjs-find-previous-button-label = Precedente
+pdfjs-find-next-button =
+ .title = Treuva a ripetiçion dòppo do testo da çercâ
+pdfjs-find-next-button-label = Segoente
+pdfjs-find-highlight-checkbox = Evidençia
+pdfjs-find-match-case-checkbox-label = Maioscole/minoscole
+pdfjs-find-entire-word-checkbox-label = Poula intrega
+pdfjs-find-reached-top = Razonto a fin da pagina, continoa da l'iniçio
+pdfjs-find-reached-bottom = Razonto l'iniçio da pagina, continoa da-a fin
+pdfjs-find-not-found = Testo no trovou
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Larghessa pagina
+pdfjs-page-scale-fit = Adatta a una pagina
+pdfjs-page-scale-auto = Zoom aotomatico
+pdfjs-page-scale-actual = Dimenscioin efetive
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = S'é verificou 'n'erô itno caregamento do PDF.
+pdfjs-invalid-file-error = O schedaio PDF o l'é no valido ò aroinou.
+pdfjs-missing-file-error = O schedaio PDF o no gh'é.
+pdfjs-unexpected-response-error = Risposta inprevista do-u server
+pdfjs-rendering-error = Gh'é stæto 'n'erô itno rendering da pagina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotaçion: { $type }]
+
+## Password
+
+pdfjs-password-label = Dimme a paròlla segreta pe arvî sto schedaio PDF.
+pdfjs-password-invalid = Paròlla segreta sbalia. Preuva torna.
+pdfjs-password-ok-button = Va ben
+pdfjs-password-cancel-button = Anulla
+pdfjs-web-fonts-disabled = I font do web en dizativæ: inposcibile adeuviâ i carateri do PDF.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lo/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lo/viewer.ftl
new file mode 100644
index 0000000..492c8cf
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lo/viewer.ftl
@@ -0,0 +1,266 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = ຫນ້າກ່ອນຫນ້າ
+pdfjs-previous-button-label = ກ່ອນຫນ້າ
+pdfjs-next-button =
+ .title = ຫນ້າຖັດໄປ
+pdfjs-next-button-label = ຖັດໄປ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ຫນ້າ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = ຈາກ { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } ຈາກ { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = ຂະຫຍາຍອອກ
+pdfjs-zoom-out-button-label = ຂະຫຍາຍອອກ
+pdfjs-zoom-in-button =
+ .title = ຂະຫຍາຍເຂົ້າ
+pdfjs-zoom-in-button-label = ຂະຫຍາຍເຂົ້າ
+pdfjs-zoom-select =
+ .title = ຂະຫຍາຍ
+pdfjs-presentation-mode-button =
+ .title = ສັບປ່ຽນເປັນໂຫມດການນຳສະເຫນີ
+pdfjs-presentation-mode-button-label = ໂຫມດການນຳສະເຫນີ
+pdfjs-open-file-button =
+ .title = ເປີດໄຟລ໌
+pdfjs-open-file-button-label = ເປີດ
+pdfjs-print-button =
+ .title = ພິມ
+pdfjs-print-button-label = ພິມ
+pdfjs-save-button =
+ .title = ບັນທຶກ
+pdfjs-save-button-label = ບັນທຶກ
+pdfjs-bookmark-button =
+ .title = ໜ້າປັດຈຸບັນ (ເບິ່ງ URL ຈາກໜ້າປັດຈຸບັນ)
+pdfjs-bookmark-button-label = ຫນ້າປັດຈຸບັນ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ເຄື່ອງມື
+pdfjs-tools-button-label = ເຄື່ອງມື
+pdfjs-first-page-button =
+ .title = ໄປທີ່ຫນ້າທຳອິດ
+pdfjs-first-page-button-label = ໄປທີ່ຫນ້າທຳອິດ
+pdfjs-last-page-button =
+ .title = ໄປທີ່ຫນ້າສຸດທ້າຍ
+pdfjs-last-page-button-label = ໄປທີ່ຫນ້າສຸດທ້າຍ
+pdfjs-page-rotate-cw-button =
+ .title = ຫມູນຕາມເຂັມໂມງ
+pdfjs-page-rotate-cw-button-label = ຫມູນຕາມເຂັມໂມງ
+pdfjs-page-rotate-ccw-button =
+ .title = ຫມູນທວນເຂັມໂມງ
+pdfjs-page-rotate-ccw-button-label = ຫມູນທວນເຂັມໂມງ
+pdfjs-cursor-text-select-tool-button =
+ .title = ເປີດໃຊ້ເຄື່ອງມືການເລືອກຂໍ້ຄວາມ
+pdfjs-cursor-text-select-tool-button-label = ເຄື່ອງມືເລືອກຂໍ້ຄວາມ
+pdfjs-cursor-hand-tool-button =
+ .title = ເປີດໃຊ້ເຄື່ອງມືມື
+pdfjs-cursor-hand-tool-button-label = ເຄື່ອງມືມື
+pdfjs-scroll-page-button =
+ .title = ໃຊ້ການເລື່ອນໜ້າ
+pdfjs-scroll-page-button-label = ເລື່ອນໜ້າ
+pdfjs-scroll-vertical-button =
+ .title = ໃຊ້ການເລື່ອນແນວຕັ້ງ
+pdfjs-scroll-vertical-button-label = ເລື່ອນແນວຕັ້ງ
+pdfjs-scroll-horizontal-button =
+ .title = ໃຊ້ການເລື່ອນແນວນອນ
+pdfjs-scroll-horizontal-button-label = ເລື່ອນແນວນອນ
+pdfjs-scroll-wrapped-button =
+ .title = ໃຊ້ Wrapped Scrolling
+pdfjs-scroll-wrapped-button-label = Wrapped Scrolling
+pdfjs-spread-none-button =
+ .title = ບໍ່ຕ້ອງຮ່ວມການແຜ່ກະຈາຍຫນ້າ
+pdfjs-spread-none-button-label = ບໍ່ມີການແຜ່ກະຈາຍ
+pdfjs-spread-odd-button =
+ .title = ເຂົ້າຮ່ວມການແຜ່ກະຈາຍຫນ້າເລີ່ມຕົ້ນດ້ວຍຫນ້າເລກຄີກ
+pdfjs-spread-odd-button-label = ການແຜ່ກະຈາຍຄີກ
+pdfjs-spread-even-button =
+ .title = ເຂົ້າຮ່ວມການແຜ່ກະຈາຍຂອງຫນ້າເລີ່ມຕົ້ນດ້ວຍຫນ້າເລກຄູ່
+pdfjs-spread-even-button-label = ການແຜ່ກະຈາຍຄູ່
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = ຄຸນສົມບັດເອກະສານ...
+pdfjs-document-properties-button-label = ຄຸນສົມບັດເອກະສານ...
+pdfjs-document-properties-file-name = ຊື່ໄຟລ໌:
+pdfjs-document-properties-file-size = ຂະຫນາດໄຟລ໌:
+pdfjs-document-properties-title = ຫົວຂໍ້:
+pdfjs-document-properties-author = ຜູ້ຂຽນ:
+pdfjs-document-properties-subject = ຫົວຂໍ້:
+pdfjs-document-properties-keywords = ຄໍາທີ່ຕ້ອງການຄົ້ນຫາ:
+pdfjs-document-properties-creation-date = ວັນທີສ້າງ:
+pdfjs-document-properties-modification-date = ວັນທີແກ້ໄຂ:
+pdfjs-document-properties-creator = ຜູ້ສ້າງ:
+pdfjs-document-properties-producer = ຜູ້ຜະລິດ PDF:
+pdfjs-document-properties-version = ເວີຊັ່ນ PDF:
+pdfjs-document-properties-page-count = ຈຳນວນໜ້າ:
+pdfjs-document-properties-page-size = ຂະໜາດໜ້າ:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = ລວງຕັ້ງ
+pdfjs-document-properties-page-size-orientation-landscape = ລວງນອນ
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = ຈົດໝາຍ
+pdfjs-document-properties-page-size-name-legal = ຂໍ້ກົດຫມາຍ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = ມຸມມອງເວັບທີ່ໄວ:
+pdfjs-document-properties-linearized-yes = ແມ່ນ
+pdfjs-document-properties-linearized-no = ບໍ່
+pdfjs-document-properties-close-button = ປິດ
+
+## Print
+
+pdfjs-print-progress-message = ກຳລັງກະກຽມເອກະສານສຳລັບການພິມ...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ຍົກເລີກ
+pdfjs-printing-not-supported = ຄຳເຕືອນ: ບຼາວເຊີນີ້ບໍ່ຮອງຮັບການພິມຢ່າງເຕັມທີ່.
+pdfjs-printing-not-ready = ຄໍາເຕືອນ: PDF ບໍ່ໄດ້ຖືກໂຫຼດຢ່າງເຕັມທີ່ສໍາລັບການພິມ.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = ເປີດ/ປິດແຖບຂ້າງ
+pdfjs-toggle-sidebar-notification-button =
+ .title = ສະຫຼັບແຖບດ້ານຂ້າງ (ເອກະສານປະກອບມີໂຄງຮ່າງ/ໄຟລ໌ແນບ/ຊັ້ນຂໍ້ມູນ)
+pdfjs-toggle-sidebar-button-label = ເປີດ/ປິດແຖບຂ້າງ
+pdfjs-document-outline-button =
+ .title = ສະແດງໂຄງຮ່າງເອກະສານ (ກົດສອງຄັ້ງເພື່ອຂະຫຍາຍ / ຫຍໍ້ລາຍການທັງຫມົດ)
+pdfjs-document-outline-button-label = ເຄົ້າຮ່າງເອກະສານ
+pdfjs-attachments-button =
+ .title = ສະແດງໄຟລ໌ແນບ
+pdfjs-attachments-button-label = ໄຟລ໌ແນບ
+pdfjs-layers-button =
+ .title = ສະແດງຊັ້ນຂໍ້ມູນ (ຄລິກສອງເທື່ອເພື່ອຣີເຊັດຊັ້ນຂໍ້ມູນທັງໝົດໃຫ້ເປັນສະຖານະເລີ່ມຕົ້ນ)
+pdfjs-layers-button-label = ຊັ້ນ
+pdfjs-thumbs-button =
+ .title = ສະແດງຮູບຫຍໍ້
+pdfjs-thumbs-button-label = ຮູບຕົວຢ່າງ
+pdfjs-current-outline-item-button =
+ .title = ຊອກຫາລາຍການໂຄງຮ່າງປະຈຸບັນ
+pdfjs-current-outline-item-button-label = ລາຍການໂຄງຮ່າງປະຈຸບັນ
+pdfjs-findbar-button =
+ .title = ຊອກຫາໃນເອກະສານ
+pdfjs-findbar-button-label = ຄົ້ນຫາ
+pdfjs-additional-layers = ຊັ້ນຂໍ້ມູນເພີ່ມເຕີມ
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = ໜ້າ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = ຮູບຕົວຢ່າງຂອງໜ້າ { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ຄົ້ນຫາ
+ .placeholder = ຊອກຫາໃນເອກະສານ...
+pdfjs-find-previous-button =
+ .title = ຊອກຫາການປະກົດຕົວທີ່ຜ່ານມາຂອງປະໂຫຍກ
+pdfjs-find-previous-button-label = ກ່ອນຫນ້ານີ້
+pdfjs-find-next-button =
+ .title = ຊອກຫາຕຳແຫນ່ງຖັດໄປຂອງວະລີ
+pdfjs-find-next-button-label = ຕໍ່ໄປ
+pdfjs-find-highlight-checkbox = ໄຮໄລທ໌ທັງຫມົດ
+pdfjs-find-match-case-checkbox-label = ກໍລະນີທີ່ກົງກັນ
+pdfjs-find-match-diacritics-checkbox-label = ເຄື່ອງໝາຍກຳກັບການອອກສຽງກົງກັນ
+pdfjs-find-entire-word-checkbox-label = ກົງກັນທຸກຄຳ
+pdfjs-find-reached-top = ມາຮອດເທິງຂອງເອກະສານ, ສືບຕໍ່ຈາກລຸ່ມ
+pdfjs-find-reached-bottom = ຮອດຕອນທ້າຍຂອງເອກະສານ, ສືບຕໍ່ຈາກເທິງ
+pdfjs-find-not-found = ບໍ່ພົບວະລີທີ່ຕ້ອງການ
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ຄວາມກວ້າງໜ້າ
+pdfjs-page-scale-fit = ໜ້າພໍດີ
+pdfjs-page-scale-auto = ຊູມອັດຕະໂນມັດ
+pdfjs-page-scale-actual = ຂະໜາດຕົວຈິງ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = ໜ້າ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = ມີຂໍ້ຜິດພາດເກີດຂື້ນຂະນະທີ່ກຳລັງໂຫລດ PDF.
+pdfjs-invalid-file-error = ໄຟລ໌ PDF ບໍ່ຖືກຕ້ອງຫລືເສຍຫາຍ.
+pdfjs-missing-file-error = ບໍ່ມີໄຟລ໌ PDF.
+pdfjs-unexpected-response-error = ການຕອບສະໜອງຂອງເຊີບເວີທີ່ບໍ່ຄາດຄິດ.
+pdfjs-rendering-error = ມີຂໍ້ຜິດພາດເກີດຂື້ນຂະນະທີ່ກຳລັງເຣັນເດີຫນ້າ.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } ຄຳບັນຍາຍ]
+
+## Password
+
+pdfjs-password-label = ໃສ່ລະຫັດຜ່ານເພື່ອເປີດໄຟລ໌ PDF ນີ້.
+pdfjs-password-invalid = ລະຫັດຜ່ານບໍ່ຖືກຕ້ອງ. ກະລຸນາລອງອີກຄັ້ງ.
+pdfjs-password-ok-button = ຕົກລົງ
+pdfjs-password-cancel-button = ຍົກເລີກ
+pdfjs-web-fonts-disabled = ຟອນເວັບຖືກປິດໃຊ້ງານ: ບໍ່ສາມາດໃຊ້ຟອນ PDF ທີ່ຝັງໄວ້ໄດ້.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = ຂໍ້ຄວາມ
+pdfjs-editor-free-text-button-label = ຂໍ້ຄວາມ
+pdfjs-editor-ink-button =
+ .title = ແຕ້ມ
+pdfjs-editor-ink-button-label = ແຕ້ມ
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = ສີ
+pdfjs-editor-free-text-size-input = ຂະຫນາດ
+pdfjs-editor-ink-color-input = ສີ
+pdfjs-editor-ink-thickness-input = ຄວາມຫນາ
+pdfjs-editor-ink-opacity-input = ຄວາມໂປ່ງໃສ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/locale.json b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/locale.json
new file mode 100644
index 0000000..16ae62e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/locale.json
@@ -0,0 +1 @@
+{"ach":"ach/viewer.ftl","af":"af/viewer.ftl","an":"an/viewer.ftl","ar":"ar/viewer.ftl","ast":"ast/viewer.ftl","az":"az/viewer.ftl","be":"be/viewer.ftl","bg":"bg/viewer.ftl","bn":"bn/viewer.ftl","bo":"bo/viewer.ftl","bqi":"bqi/viewer.ftl","br":"br/viewer.ftl","brx":"brx/viewer.ftl","bs":"bs/viewer.ftl","ca":"ca/viewer.ftl","cak":"cak/viewer.ftl","ckb":"ckb/viewer.ftl","cs":"cs/viewer.ftl","cy":"cy/viewer.ftl","da":"da/viewer.ftl","de":"de/viewer.ftl","dsb":"dsb/viewer.ftl","el":"el/viewer.ftl","en-ca":"en-CA/viewer.ftl","en-gb":"en-GB/viewer.ftl","en-us":"en-US/viewer.ftl","eo":"eo/viewer.ftl","es-ar":"es-AR/viewer.ftl","es-cl":"es-CL/viewer.ftl","es-es":"es-ES/viewer.ftl","es-mx":"es-MX/viewer.ftl","et":"et/viewer.ftl","eu":"eu/viewer.ftl","fa":"fa/viewer.ftl","ff":"ff/viewer.ftl","fi":"fi/viewer.ftl","fr":"fr/viewer.ftl","fur":"fur/viewer.ftl","fy-nl":"fy-NL/viewer.ftl","ga-ie":"ga-IE/viewer.ftl","gd":"gd/viewer.ftl","gl":"gl/viewer.ftl","gn":"gn/viewer.ftl","gu-in":"gu-IN/viewer.ftl","he":"he/viewer.ftl","hi-in":"hi-IN/viewer.ftl","hr":"hr/viewer.ftl","hsb":"hsb/viewer.ftl","hu":"hu/viewer.ftl","hy-am":"hy-AM/viewer.ftl","hye":"hye/viewer.ftl","ia":"ia/viewer.ftl","id":"id/viewer.ftl","is":"is/viewer.ftl","it":"it/viewer.ftl","ja":"ja/viewer.ftl","ka":"ka/viewer.ftl","kab":"kab/viewer.ftl","kk":"kk/viewer.ftl","km":"km/viewer.ftl","kn":"kn/viewer.ftl","ko":"ko/viewer.ftl","lij":"lij/viewer.ftl","lo":"lo/viewer.ftl","lt":"lt/viewer.ftl","ltg":"ltg/viewer.ftl","lv":"lv/viewer.ftl","meh":"meh/viewer.ftl","mk":"mk/viewer.ftl","ml":"ml/viewer.ftl","mr":"mr/viewer.ftl","ms":"ms/viewer.ftl","my":"my/viewer.ftl","nb-no":"nb-NO/viewer.ftl","ne-np":"ne-NP/viewer.ftl","nl":"nl/viewer.ftl","nn-no":"nn-NO/viewer.ftl","oc":"oc/viewer.ftl","pa-in":"pa-IN/viewer.ftl","pl":"pl/viewer.ftl","pt-br":"pt-BR/viewer.ftl","pt-pt":"pt-PT/viewer.ftl","rm":"rm/viewer.ftl","ro":"ro/viewer.ftl","ru":"ru/viewer.ftl","sat":"sat/viewer.ftl","sc":"sc/viewer.ftl","scn":"scn/viewer.ftl","sco":"sco/viewer.ftl","si":"si/viewer.ftl","sk":"sk/viewer.ftl","skr":"skr/viewer.ftl","sl":"sl/viewer.ftl","son":"son/viewer.ftl","sq":"sq/viewer.ftl","sr":"sr/viewer.ftl","sv-se":"sv-SE/viewer.ftl","szl":"szl/viewer.ftl","ta":"ta/viewer.ftl","te":"te/viewer.ftl","tg":"tg/viewer.ftl","th":"th/viewer.ftl","tl":"tl/viewer.ftl","tr":"tr/viewer.ftl","trs":"trs/viewer.ftl","uk":"uk/viewer.ftl","ur":"ur/viewer.ftl","uz":"uz/viewer.ftl","vi":"vi/viewer.ftl","wo":"wo/viewer.ftl","xh":"xh/viewer.ftl","zh-cn":"zh-CN/viewer.ftl","zh-tw":"zh-TW/viewer.ftl"}
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lt/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lt/viewer.ftl
new file mode 100644
index 0000000..f15d1f9
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lt/viewer.ftl
@@ -0,0 +1,242 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Ankstesnis puslapis
+pdfjs-previous-button-label = Ankstesnis
+pdfjs-next-button =
+ .title = Kitas puslapis
+pdfjs-next-button-label = Kitas
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Puslapis
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = iš { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } iš { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Sumažinti
+pdfjs-zoom-out-button-label = Sumažinti
+pdfjs-zoom-in-button =
+ .title = Padidinti
+pdfjs-zoom-in-button-label = Padidinti
+pdfjs-zoom-select =
+ .title = Mastelis
+pdfjs-presentation-mode-button =
+ .title = Pereiti į pateikties veikseną
+pdfjs-presentation-mode-button-label = Pateikties veiksena
+pdfjs-open-file-button =
+ .title = Atverti failą
+pdfjs-open-file-button-label = Atverti
+pdfjs-print-button =
+ .title = Spausdinti
+pdfjs-print-button-label = Spausdinti
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Priemonės
+pdfjs-tools-button-label = Priemonės
+pdfjs-first-page-button =
+ .title = Eiti į pirmą puslapį
+pdfjs-first-page-button-label = Eiti į pirmą puslapį
+pdfjs-last-page-button =
+ .title = Eiti į paskutinį puslapį
+pdfjs-last-page-button-label = Eiti į paskutinį puslapį
+pdfjs-page-rotate-cw-button =
+ .title = Pasukti pagal laikrodžio rodyklę
+pdfjs-page-rotate-cw-button-label = Pasukti pagal laikrodžio rodyklę
+pdfjs-page-rotate-ccw-button =
+ .title = Pasukti prieš laikrodžio rodyklę
+pdfjs-page-rotate-ccw-button-label = Pasukti prieš laikrodžio rodyklę
+pdfjs-cursor-text-select-tool-button =
+ .title = Įjungti teksto žymėjimo įrankį
+pdfjs-cursor-text-select-tool-button-label = Teksto žymėjimo įrankis
+pdfjs-cursor-hand-tool-button =
+ .title = Įjungti vilkimo įrankį
+pdfjs-cursor-hand-tool-button-label = Vilkimo įrankis
+pdfjs-scroll-page-button =
+ .title = Naudoti puslapio slinkimą
+pdfjs-scroll-page-button-label = Puslapio slinkimas
+pdfjs-scroll-vertical-button =
+ .title = Naudoti vertikalų slinkimą
+pdfjs-scroll-vertical-button-label = Vertikalus slinkimas
+pdfjs-scroll-horizontal-button =
+ .title = Naudoti horizontalų slinkimą
+pdfjs-scroll-horizontal-button-label = Horizontalus slinkimas
+pdfjs-scroll-wrapped-button =
+ .title = Naudoti išklotą slinkimą
+pdfjs-scroll-wrapped-button-label = Išklotas slinkimas
+pdfjs-spread-none-button =
+ .title = Nejungti puslapių į dvilapius
+pdfjs-spread-none-button-label = Be dvilapių
+pdfjs-spread-odd-button =
+ .title = Sujungti į dvilapius pradedant nelyginiais puslapiais
+pdfjs-spread-odd-button-label = Nelyginiai dvilapiai
+pdfjs-spread-even-button =
+ .title = Sujungti į dvilapius pradedant lyginiais puslapiais
+pdfjs-spread-even-button-label = Lyginiai dvilapiai
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumento savybės…
+pdfjs-document-properties-button-label = Dokumento savybės…
+pdfjs-document-properties-file-name = Failo vardas:
+pdfjs-document-properties-file-size = Failo dydis:
+pdfjs-document-properties-title = Antraštė:
+pdfjs-document-properties-author = Autorius:
+pdfjs-document-properties-subject = Tema:
+pdfjs-document-properties-keywords = Reikšminiai žodžiai:
+pdfjs-document-properties-creation-date = Sukūrimo data:
+pdfjs-document-properties-modification-date = Modifikavimo data:
+pdfjs-document-properties-creator = Kūrėjas:
+pdfjs-document-properties-producer = PDF generatorius:
+pdfjs-document-properties-version = PDF versija:
+pdfjs-document-properties-page-count = Puslapių skaičius:
+pdfjs-document-properties-page-size = Puslapio dydis:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = stačias
+pdfjs-document-properties-page-size-orientation-landscape = gulsčias
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Laiškas
+pdfjs-document-properties-page-size-name-legal = Dokumentas
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Spartus žiniatinklio rodinys:
+pdfjs-document-properties-linearized-yes = Taip
+pdfjs-document-properties-linearized-no = Ne
+pdfjs-document-properties-close-button = Užverti
+
+## Print
+
+pdfjs-print-progress-message = Dokumentas ruošiamas spausdinimui…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Atsisakyti
+pdfjs-printing-not-supported = Dėmesio! Spausdinimas šioje naršyklėje nėra pilnai realizuotas.
+pdfjs-printing-not-ready = Dėmesio! PDF failas dar nėra pilnai įkeltas spausdinimui.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Rodyti / slėpti šoninį polangį
+pdfjs-toggle-sidebar-notification-button =
+ .title = Parankinė (dokumentas turi struktūrą / priedų / sluoksnių)
+pdfjs-toggle-sidebar-button-label = Šoninis polangis
+pdfjs-document-outline-button =
+ .title = Rodyti dokumento struktūrą (spustelėkite dukart norėdami išplėsti/suskleisti visus elementus)
+pdfjs-document-outline-button-label = Dokumento struktūra
+pdfjs-attachments-button =
+ .title = Rodyti priedus
+pdfjs-attachments-button-label = Priedai
+pdfjs-layers-button =
+ .title = Rodyti sluoksnius (spustelėkite dukart, norėdami atstatyti visus sluoksnius į numatytąją būseną)
+pdfjs-layers-button-label = Sluoksniai
+pdfjs-thumbs-button =
+ .title = Rodyti puslapių miniatiūras
+pdfjs-thumbs-button-label = Miniatiūros
+pdfjs-current-outline-item-button =
+ .title = Rasti dabartinį struktūros elementą
+pdfjs-current-outline-item-button-label = Dabartinis struktūros elementas
+pdfjs-findbar-button =
+ .title = Ieškoti dokumente
+pdfjs-findbar-button-label = Rasti
+pdfjs-additional-layers = Papildomi sluoksniai
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } puslapis
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } puslapio miniatiūra
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Rasti
+ .placeholder = Rasti dokumente…
+pdfjs-find-previous-button =
+ .title = Ieškoti ankstesnio frazės egzemplioriaus
+pdfjs-find-previous-button-label = Ankstesnis
+pdfjs-find-next-button =
+ .title = Ieškoti tolesnio frazės egzemplioriaus
+pdfjs-find-next-button-label = Tolesnis
+pdfjs-find-highlight-checkbox = Viską paryškinti
+pdfjs-find-match-case-checkbox-label = Skirti didžiąsias ir mažąsias raides
+pdfjs-find-match-diacritics-checkbox-label = Skirti diakritinius ženklus
+pdfjs-find-entire-word-checkbox-label = Ištisi žodžiai
+pdfjs-find-reached-top = Pasiekus dokumento pradžią, paieška pratęsta nuo pabaigos
+pdfjs-find-reached-bottom = Pasiekus dokumento pabaigą, paieška pratęsta nuo pradžios
+pdfjs-find-not-found = Ieškoma frazė nerasta
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Priderinti prie lapo pločio
+pdfjs-page-scale-fit = Pritaikyti prie lapo dydžio
+pdfjs-page-scale-auto = Automatinis mastelis
+pdfjs-page-scale-actual = Tikras dydis
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page } puslapis
+
+## Loading indicator messages
+
+pdfjs-loading-error = Įkeliant PDF failą įvyko klaida.
+pdfjs-invalid-file-error = Tai nėra PDF failas arba jis yra sugadintas.
+pdfjs-missing-file-error = PDF failas nerastas.
+pdfjs-unexpected-response-error = Netikėtas serverio atsakas.
+pdfjs-rendering-error = Atvaizduojant puslapį įvyko klaida.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [„{ $type }“ tipo anotacija]
+
+## Password
+
+pdfjs-password-label = Įveskite slaptažodį šiam PDF failui atverti.
+pdfjs-password-invalid = Slaptažodis neteisingas. Bandykite dar kartą.
+pdfjs-password-ok-button = Gerai
+pdfjs-password-cancel-button = Atsisakyti
+pdfjs-web-fonts-disabled = Saityno šriftai išjungti – PDF faile esančių šriftų naudoti negalima.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ltg/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ltg/viewer.ftl
new file mode 100644
index 0000000..d837f92
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ltg/viewer.ftl
@@ -0,0 +1,221 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Īprīkšejā lopa
+pdfjs-previous-button-label = Īprīkšejā
+pdfjs-next-button =
+ .title = Nuokomuo lopa
+pdfjs-next-button-label = Nuokomuo
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Lopa
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = nu { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } nu { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Attuolynuot
+pdfjs-zoom-out-button-label = Attuolynuot
+pdfjs-zoom-in-button =
+ .title = Pītuvynuot
+pdfjs-zoom-in-button-label = Pītuvynuot
+pdfjs-zoom-select =
+ .title = Palelynuojums
+pdfjs-presentation-mode-button =
+ .title = Puorslēgtīs iz Prezentacejis režymu
+pdfjs-presentation-mode-button-label = Prezentacejis režyms
+pdfjs-open-file-button =
+ .title = Attaiseit failu
+pdfjs-open-file-button-label = Attaiseit
+pdfjs-print-button =
+ .title = Drukuošona
+pdfjs-print-button-label = Drukōt
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Reiki
+pdfjs-tools-button-label = Reiki
+pdfjs-first-page-button =
+ .title = Īt iz pyrmū lopu
+pdfjs-first-page-button-label = Īt iz pyrmū lopu
+pdfjs-last-page-button =
+ .title = Īt iz piedejū lopu
+pdfjs-last-page-button-label = Īt iz piedejū lopu
+pdfjs-page-rotate-cw-button =
+ .title = Pagrīzt pa pulksteni
+pdfjs-page-rotate-cw-button-label = Pagrīzt pa pulksteni
+pdfjs-page-rotate-ccw-button =
+ .title = Pagrīzt pret pulksteni
+pdfjs-page-rotate-ccw-button-label = Pagrīzt pret pulksteni
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktivizēt teksta izvieles reiku
+pdfjs-cursor-text-select-tool-button-label = Teksta izvieles reiks
+pdfjs-cursor-hand-tool-button =
+ .title = Aktivēt rūkys reiku
+pdfjs-cursor-hand-tool-button-label = Rūkys reiks
+pdfjs-scroll-vertical-button =
+ .title = Izmontōt vertikalū ritinōšonu
+pdfjs-scroll-vertical-button-label = Vertikalō ritinōšona
+pdfjs-scroll-horizontal-button =
+ .title = Izmontōt horizontalū ritinōšonu
+pdfjs-scroll-horizontal-button-label = Horizontalō ritinōšona
+pdfjs-scroll-wrapped-button =
+ .title = Izmontōt mārūgojamū ritinōšonu
+pdfjs-scroll-wrapped-button-label = Mārūgojamō ritinōšona
+pdfjs-spread-none-button =
+ .title = Naizmontōt lopu atvāruma režimu
+pdfjs-spread-none-button-label = Bez atvārumim
+pdfjs-spread-odd-button =
+ .title = Izmontōt lopu atvārumus sōkut nu napōra numeru lopom
+pdfjs-spread-odd-button-label = Napōra lopys pa kreisi
+pdfjs-spread-even-button =
+ .title = Izmontōt lopu atvārumus sōkut nu pōra numeru lopom
+pdfjs-spread-even-button-label = Pōra lopys pa kreisi
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumenta īstatiejumi…
+pdfjs-document-properties-button-label = Dokumenta īstatiejumi…
+pdfjs-document-properties-file-name = Faila nūsaukums:
+pdfjs-document-properties-file-size = Faila izmārs:
+pdfjs-document-properties-title = Nūsaukums:
+pdfjs-document-properties-author = Autors:
+pdfjs-document-properties-subject = Tema:
+pdfjs-document-properties-keywords = Atslāgi vuordi:
+pdfjs-document-properties-creation-date = Izveides datums:
+pdfjs-document-properties-modification-date = lobuošonys datums:
+pdfjs-document-properties-creator = Radeituojs:
+pdfjs-document-properties-producer = PDF producents:
+pdfjs-document-properties-version = PDF verseja:
+pdfjs-document-properties-page-count = Lopu skaits:
+pdfjs-document-properties-page-size = Lopas izmārs:
+pdfjs-document-properties-page-size-unit-inches = collas
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portreta orientaceja
+pdfjs-document-properties-page-size-orientation-landscape = ainovys orientaceja
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Jā
+pdfjs-document-properties-linearized-no = Nā
+pdfjs-document-properties-close-button = Aiztaiseit
+
+## Print
+
+pdfjs-print-progress-message = Preparing document for printing…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Atceļt
+pdfjs-printing-not-supported = Uzmaneibu: Drukuošona nu itei puorlūka dorbojās tikai daleji.
+pdfjs-printing-not-ready = Uzmaneibu: PDF nav pilneibā īluodeits drukuošonai.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Puorslēgt suonu jūslu
+pdfjs-toggle-sidebar-button-label = Puorslēgt suonu jūslu
+pdfjs-document-outline-button =
+ .title = Show Document Outline (double-click to expand/collapse all items)
+pdfjs-document-outline-button-label = Dokumenta saturs
+pdfjs-attachments-button =
+ .title = Show Attachments
+pdfjs-attachments-button-label = Attachments
+pdfjs-thumbs-button =
+ .title = Paruodeit seiktālus
+pdfjs-thumbs-button-label = Seiktāli
+pdfjs-findbar-button =
+ .title = Mekleit dokumentā
+pdfjs-findbar-button-label = Mekleit
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Lopa { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Lopys { $page } seiktāls
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Mekleit
+ .placeholder = Mekleit dokumentā…
+pdfjs-find-previous-button =
+ .title = Atrast īprīkšejū
+pdfjs-find-previous-button-label = Īprīkšejā
+pdfjs-find-next-button =
+ .title = Atrast nuokamū
+pdfjs-find-next-button-label = Nuokomuo
+pdfjs-find-highlight-checkbox = Īkruosuot vysys
+pdfjs-find-match-case-checkbox-label = Lelū, mozū burtu jiuteigs
+pdfjs-find-reached-top = Sasnīgts dokumenta suokums, turpynojom nu beigom
+pdfjs-find-reached-bottom = Sasnīgtys dokumenta beigys, turpynojom nu suokuma
+pdfjs-find-not-found = Frāze nav atrosta
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lopys plotumā
+pdfjs-page-scale-fit = Ītylpynūt lopu
+pdfjs-page-scale-auto = Automatiskais izmārs
+pdfjs-page-scale-actual = Patīsais izmārs
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Īluodejūt PDF nūtyka klaida.
+pdfjs-invalid-file-error = Nadereigs voi būjuots PDF fails.
+pdfjs-missing-file-error = PDF fails nav atrosts.
+pdfjs-unexpected-response-error = Unexpected server response.
+pdfjs-rendering-error = Attālojūt lopu rodās klaida
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = Īvodit paroli, kab attaiseitu PDF failu.
+pdfjs-password-invalid = Napareiza parole, raugit vēļreiz.
+pdfjs-password-ok-button = Labi
+pdfjs-password-cancel-button = Atceļt
+pdfjs-web-fonts-disabled = Šķārsteikla fonti nav aktivizāti: Navar īgult PDF fontus.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lv/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lv/viewer.ftl
new file mode 100644
index 0000000..8420b21
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/lv/viewer.ftl
@@ -0,0 +1,275 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Iepriekšējā lapa
+pdfjs-previous-button-label = Iepriekšējā
+pdfjs-next-button =
+ .title = Nākamā lapa
+pdfjs-next-button-label = Nākamā
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Lapa
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = no { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } no { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Attālināt
+pdfjs-zoom-out-button-label = Attālināt
+pdfjs-zoom-in-button =
+ .title = Pietuvināt
+pdfjs-zoom-in-button-label = Pietuvināt
+pdfjs-zoom-select =
+ .title = Palielinājums
+pdfjs-presentation-mode-button =
+ .title = Pārslēgties uz Prezentācijas režīmu
+pdfjs-presentation-mode-button-label = Prezentācijas režīms
+pdfjs-open-file-button =
+ .title = Atvērt failu
+pdfjs-open-file-button-label = Atvērt
+pdfjs-print-button =
+ .title = Drukāšana
+pdfjs-print-button-label = Drukāt
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Rīki
+pdfjs-tools-button-label = Rīki
+pdfjs-first-page-button =
+ .title = Iet uz pirmo lapu
+pdfjs-first-page-button-label = Iet uz pirmo lapu
+pdfjs-last-page-button =
+ .title = Iet uz pēdējo lapu
+pdfjs-last-page-button-label = Iet uz pēdējo lapu
+pdfjs-page-rotate-cw-button =
+ .title = Pagriezt pa pulksteni
+pdfjs-page-rotate-cw-button-label = Pagriezt pa pulksteni
+pdfjs-page-rotate-ccw-button =
+ .title = Pagriezt pret pulksteni
+pdfjs-page-rotate-ccw-button-label = Pagriezt pret pulksteni
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktivizēt teksta izvēles rīku
+pdfjs-cursor-text-select-tool-button-label = Teksta izvēles rīks
+pdfjs-cursor-hand-tool-button =
+ .title = Aktivēt rokas rīku
+pdfjs-cursor-hand-tool-button-label = Rokas rīks
+pdfjs-scroll-vertical-button =
+ .title = Izmantot vertikālo ritināšanu
+pdfjs-scroll-vertical-button-label = Vertikālā ritināšana
+pdfjs-scroll-horizontal-button =
+ .title = Izmantot horizontālo ritināšanu
+pdfjs-scroll-horizontal-button-label = Horizontālā ritināšana
+pdfjs-scroll-wrapped-button =
+ .title = Izmantot apkļauto ritināšanu
+pdfjs-scroll-wrapped-button-label = Apkļautā ritināšana
+pdfjs-spread-none-button =
+ .title = Nepievienoties lapu izpletumiem
+pdfjs-spread-none-button-label = Neizmantot izpletumus
+pdfjs-spread-odd-button =
+ .title = Izmantot lapu izpletumus sākot ar nepāra numuru lapām
+pdfjs-spread-odd-button-label = Nepāra izpletumi
+pdfjs-spread-even-button =
+ .title = Izmantot lapu izpletumus sākot ar pāra numuru lapām
+pdfjs-spread-even-button-label = Pāra izpletumi
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumenta iestatījumi…
+pdfjs-document-properties-button-label = Dokumenta iestatījumi…
+pdfjs-document-properties-file-name = Faila nosaukums:
+pdfjs-document-properties-file-size = Faila izmērs:
+pdfjs-document-properties-title = Nosaukums:
+pdfjs-document-properties-author = Autors:
+pdfjs-document-properties-subject = Tēma:
+pdfjs-document-properties-keywords = Atslēgas vārdi:
+pdfjs-document-properties-creation-date = Izveides datums:
+pdfjs-document-properties-modification-date = LAbošanas datums:
+pdfjs-document-properties-creator = Radītājs:
+pdfjs-document-properties-producer = PDF producents:
+pdfjs-document-properties-version = PDF versija:
+pdfjs-document-properties-page-count = Lapu skaits:
+pdfjs-document-properties-page-size = Papīra izmērs:
+pdfjs-document-properties-page-size-unit-inches = collas
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portretorientācija
+pdfjs-document-properties-page-size-orientation-landscape = ainavorientācija
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Vēstule
+pdfjs-document-properties-page-size-name-legal = Juridiskie teksti
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Ātrā tīmekļa skats:
+pdfjs-document-properties-linearized-yes = Jā
+pdfjs-document-properties-linearized-no = Nē
+pdfjs-document-properties-close-button = Aizvērt
+
+## Print
+
+pdfjs-print-progress-message = Gatavo dokumentu drukāšanai...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Atcelt
+pdfjs-printing-not-supported = Uzmanību: Drukāšana no šī pārlūka darbojas tikai daļēji.
+pdfjs-printing-not-ready = Uzmanību: PDF nav pilnībā ielādēts drukāšanai.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Pārslēgt sānu joslu
+pdfjs-toggle-sidebar-button-label = Pārslēgt sānu joslu
+pdfjs-document-outline-button =
+ .title = Rādīt dokumenta struktūru (veiciet dubultklikšķi lai izvērstu/sakļautu visus vienumus)
+pdfjs-document-outline-button-label = Dokumenta saturs
+pdfjs-attachments-button =
+ .title = Rādīt pielikumus
+pdfjs-attachments-button-label = Pielikumi
+pdfjs-thumbs-button =
+ .title = Parādīt sīktēlus
+pdfjs-thumbs-button-label = Sīktēli
+pdfjs-findbar-button =
+ .title = Meklēt dokumentā
+pdfjs-findbar-button-label = Meklēt
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Lapa { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Lapas { $page } sīktēls
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Meklēt
+ .placeholder = Meklēt dokumentā…
+pdfjs-find-previous-button =
+ .title = Atrast iepriekšējo
+pdfjs-find-previous-button-label = Iepriekšējā
+pdfjs-find-next-button =
+ .title = Atrast nākamo
+pdfjs-find-next-button-label = Nākamā
+pdfjs-find-highlight-checkbox = Izcelt visus
+pdfjs-find-match-case-checkbox-label = Lielo un mazo burtu atbilstība
+pdfjs-find-match-diacritics-checkbox-label = Diakritisko zīmju atbilstība
+pdfjs-find-entire-word-checkbox-label = Veselus vārdus
+pdfjs-find-reached-top = Sasniegts dokumenta sākums, turpinām no beigām
+pdfjs-find-reached-bottom = Sasniegtas dokumenta beigas, turpinām no sākuma
+pdfjs-find-not-found = Vārdkopa nav atrasta
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lapas platumā
+pdfjs-page-scale-fit = Ietilpinot lapu
+pdfjs-page-scale-auto = Automātiskais izmērs
+pdfjs-page-scale-actual = Patiesais izmērs
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ielādējot PDF notika kļūda.
+pdfjs-invalid-file-error = Nederīga vai bojāt PDF datne.
+pdfjs-missing-file-error = PDF datne nav atrasta.
+pdfjs-unexpected-response-error = Negaidīa servera atbilde.
+pdfjs-rendering-error = Attēlojot lapu radās kļūda
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } anotācija]
+
+## Password
+
+pdfjs-password-label = Ievadiet paroli, lai atvērtu PDF failu.
+pdfjs-password-invalid = Nepareiza parole, mēģiniet vēlreiz.
+pdfjs-password-ok-button = Labi
+pdfjs-password-cancel-button = Atcelt
+pdfjs-web-fonts-disabled = Tīmekļa fonti nav aktivizēti: Nevar iegult PDF fontus.
+
+## Editing
+
+pdfjs-editor-stamp-button =
+ .title = Pievienot vai labot attēlus
+pdfjs-editor-stamp-button-label = Pievienot vai labot attēlus
+pdfjs-editor-signature-button =
+ .title = Pievienot parakstu
+pdfjs-editor-signature-button-label = Pievienot parakstu
+
+##
+
+pdfjs-editor-stamp-add-image-button =
+ .title = Pievienot attēlu
+pdfjs-editor-stamp-add-image-button-label = Pievienot attēlu
+pdfjs-editor-signature-add-signature-button =
+ .title = Pievienot jaunu parakstu
+pdfjs-editor-signature-add-signature-button-label = Pievienot jaunu parakstu
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-add-description-label = Pievienot aprakstu
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-title = Pievienot parakstu
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-add-button = Pievienot
+
+## Edit a comment dialog
+
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Pievienot piebildi
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Pievienot
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Pievienot piebildi
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-views-manager-add-file-button =
+ .title = Pievienot datni
+pdfjs-views-manager-add-file-button-label = Pievienot datni
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/meh/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/meh/viewer.ftl
new file mode 100644
index 0000000..43f1fef
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/meh/viewer.ftl
@@ -0,0 +1,48 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página yata
+pdfjs-zoom-select =
+ .title = Nasa´a ka´nu/Nasa´a luli
+pdfjs-open-file-button-label = Síne
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-linearized-yes = Kuvi
+pdfjs-document-properties-close-button = Nakasɨ
+
+## Print
+
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Nkuvi-ka
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-findbar-button-label = Nánuku
+
+## Predefined zoom values
+
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Password
+
+pdfjs-password-cancel-button = Nkuvi-ka
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/mk/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/mk/viewer.ftl
new file mode 100644
index 0000000..ad0ba31
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/mk/viewer.ftl
@@ -0,0 +1,747 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Претходна страница
+pdfjs-previous-button-label = Претходна
+pdfjs-next-button =
+ .title = Следна страница
+pdfjs-next-button-label = Следна
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Страница
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = од { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } од { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Намалување
+pdfjs-zoom-out-button-label = Намали
+pdfjs-zoom-in-button =
+ .title = Зголемување
+pdfjs-zoom-in-button-label = Зголеми
+pdfjs-zoom-select =
+ .title = Променување на големина
+pdfjs-presentation-mode-button =
+ .title = Премини во презентациски режим
+pdfjs-presentation-mode-button-label = Презентациски режим
+pdfjs-open-file-button =
+ .title = Отворање датотека
+pdfjs-open-file-button-label = Отвори
+pdfjs-print-button =
+ .title = Печатење
+pdfjs-print-button-label = Печати
+pdfjs-save-button =
+ .title = Снимање
+pdfjs-save-button-label = Сними
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Преземање
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Преземи
+pdfjs-bookmark-button =
+ .title = Тековна страница (Преглед на URL од тековна страница)
+pdfjs-bookmark-button-label = Тековна страница
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Алатки
+pdfjs-tools-button-label = Алатки
+pdfjs-first-page-button =
+ .title = Оди до првата страница
+pdfjs-first-page-button-label = Оди до првата страница
+pdfjs-last-page-button =
+ .title = Оди до последната страница
+pdfjs-last-page-button-label = Оди до последната страница
+pdfjs-page-rotate-cw-button =
+ .title = Ротирај по стрелките на часовникот
+pdfjs-page-rotate-cw-button-label = Ротирај по стрелките на часовникот
+pdfjs-page-rotate-ccw-button =
+ .title = Ротирај спротивно од стрелките на часовникот
+pdfjs-page-rotate-ccw-button-label = Ротирај спротивно од стрелките на часовникот
+pdfjs-cursor-text-select-tool-button =
+ .title = Овозможи алатка за избор на текст
+pdfjs-cursor-text-select-tool-button-label = Алатка за избор на текст
+pdfjs-cursor-hand-tool-button =
+ .title = Овозможување на рачна алатка
+pdfjs-cursor-hand-tool-button-label = Рачна алатка
+pdfjs-scroll-page-button =
+ .title = Употреба на поместување на страница
+pdfjs-scroll-page-button-label = Поместување на страница
+pdfjs-scroll-vertical-button =
+ .title = Употреба на вертикално поместување
+pdfjs-scroll-vertical-button-label = Вертикално поместување
+pdfjs-scroll-horizontal-button =
+ .title = Употреба на хоризонтално поместување
+pdfjs-scroll-horizontal-button-label = Хоризонтално поместување
+pdfjs-scroll-wrapped-button =
+ .title = Употреба на последователно поместување
+pdfjs-scroll-wrapped-button-label = Последователно поместување
+pdfjs-spread-none-button =
+ .title = Не спојувај спротивни страници
+pdfjs-spread-none-button-label = Без спојување
+pdfjs-spread-odd-button =
+ .title = Спој страници почнувајќи со непарен број
+pdfjs-spread-odd-button-label = Непарнo спојување
+pdfjs-spread-even-button =
+ .title = Спој страници почнувајќи со парен број
+pdfjs-spread-even-button-label = Парно спојување
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Својства на документот…
+pdfjs-document-properties-button-label = Својства на документот…
+pdfjs-document-properties-file-name = Име на датотека:
+pdfjs-document-properties-file-size = Големина на датотеката:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } бајти)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } бајти)
+pdfjs-document-properties-title = Наслов:
+pdfjs-document-properties-author = Автор:
+pdfjs-document-properties-subject = Тема:
+pdfjs-document-properties-keywords = Клучни зборови:
+pdfjs-document-properties-creation-date = Датум на создавање:
+pdfjs-document-properties-modification-date = Датум на промена:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Автор:
+pdfjs-document-properties-producer = Составувач на PDF:
+pdfjs-document-properties-version = Верзија на PDF:
+pdfjs-document-properties-page-count = Број на страници:
+pdfjs-document-properties-page-size = Големина на страница:
+pdfjs-document-properties-page-size-unit-inches = инч
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = портрет
+pdfjs-document-properties-page-size-orientation-landscape = пејзаж
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Писмо
+pdfjs-document-properties-page-size-name-legal = Правно
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Брз мрежен преглед:
+pdfjs-document-properties-linearized-yes = Да
+pdfjs-document-properties-linearized-no = Не
+pdfjs-document-properties-close-button = Затвори
+
+## Print
+
+pdfjs-print-progress-message = Документ се подготвува за печатење…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Откажи
+pdfjs-printing-not-supported = Предупредување: Печатењето не е целосно поддржано во овој прелистувач.
+pdfjs-printing-not-ready = Предупредување: PDF документот не е целосно вчитан за печатење.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Вклучи странична лента
+pdfjs-toggle-sidebar-notification-button =
+ .title = Вклучи странична лента (документот содржи преглед, прилози, или слоеви)
+pdfjs-toggle-sidebar-button-label = Вклучи странична лента
+pdfjs-document-outline-button =
+ .title = Прикажи го прегедот на документот (дво клик за да се прикажат/скријат сите елементи)
+pdfjs-document-outline-button-label = Преглед на документот
+pdfjs-attachments-button =
+ .title = Прикажување на прилози
+pdfjs-attachments-button-label = Прилози
+pdfjs-layers-button =
+ .title = Прикажи слоеви (двоклик за ресетирање на сите слоеви)
+pdfjs-layers-button-label = Слоеви
+pdfjs-thumbs-button =
+ .title = Прикажување на иконки
+pdfjs-thumbs-button-label = Иконки
+pdfjs-current-outline-item-button =
+ .title = Барање на тековниот елемент од прегледот
+pdfjs-current-outline-item-button-label = Тековен елемент од прегледот
+pdfjs-findbar-button =
+ .title = Најди во документот
+pdfjs-findbar-button-label = Најди
+pdfjs-additional-layers = Дополнителни слоеви
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Страница { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Иконка од страница { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Изберете страница { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Страница { $page } од { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Пребарување
+ .placeholder = Пронајди во документот…
+pdfjs-find-previous-button =
+ .title = Најди ја предходната појава на фразата
+pdfjs-find-previous-button-label = Претходно
+pdfjs-find-next-button =
+ .title = Најди ја следната појава на фразата
+pdfjs-find-next-button-label = Следно
+pdfjs-find-highlight-checkbox = Означи сѐ
+pdfjs-find-match-case-checkbox-label = Токму така
+pdfjs-find-match-diacritics-checkbox-label = Вклучи дијакритички знаци
+pdfjs-find-entire-word-checkbox-label = Цели зборови
+pdfjs-find-reached-top = Барањето стигна до почетокот на документот и почнува од крајот
+pdfjs-find-reached-bottom = Барањето стигна до крајот на документот и почнува од почеток
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } од { $total } совпаѓање
+ *[other] { $current } од { $total } совпаѓања
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Повеќе од { $limit } совпаѓање
+ *[other] Повеќе од { $limit } совпаѓања
+ }
+pdfjs-find-not-found = Фразата не е пронајдена
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ширина на страница
+pdfjs-page-scale-fit = Цела страница
+pdfjs-page-scale-auto = Автоматска големина
+pdfjs-page-scale-actual = Вистинска големина
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Страница { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Настана грешка при вчитувањето на PDF-от.
+pdfjs-invalid-file-error = Невалидна или корумпирана PDF датотека.
+pdfjs-missing-file-error = Недостасува PDF документ.
+pdfjs-unexpected-response-error = Неочекуван одговор од серверот.
+pdfjs-rendering-error = Настана грешка при прикажувањето на страницата.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } напомена]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Внесете ја лозинката за да ја отворите оваа PDF датотека.
+pdfjs-password-invalid = Невалидна лозинка. Обидете се повторно.
+pdfjs-password-ok-button = Во ред
+pdfjs-password-cancel-button = Откажи
+pdfjs-web-fonts-disabled = Интернет фонтовите се оневозможени: не може да се користат вградените PDF фонтови.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Текст
+pdfjs-editor-color-picker-free-text-input =
+ .title = Промена на боја на текст
+pdfjs-editor-free-text-button-label = Текст
+pdfjs-editor-ink-button =
+ .title = Цртање
+pdfjs-editor-color-picker-ink-input =
+ .title = Промена на боја за цртање
+pdfjs-editor-ink-button-label = Цртај
+pdfjs-editor-stamp-button =
+ .title = Додавање или уредување на слики
+pdfjs-editor-stamp-button-label = Додај или уреди слики
+pdfjs-editor-highlight-button =
+ .title = Нагласување
+pdfjs-editor-highlight-button-label = Нагласи
+pdfjs-highlight-floating-button1 =
+ .title = Нагласување
+ .aria-label = Нагласување
+pdfjs-highlight-floating-button-label = Нагласи
+pdfjs-comment-floating-button =
+ .title = Коментар
+ .aria-label = Коментар
+pdfjs-comment-floating-button-label = Коментар
+pdfjs-editor-comment-button =
+ .title = Коментар
+ .aria-label = Коментар
+pdfjs-editor-comment-button-label = Коментар
+pdfjs-editor-signature-button =
+ .title = Додавање на потпис
+pdfjs-editor-signature-button-label = Додај потпис
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Уредувач на нагласувања
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Уредувач за цртање
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Уредувач на потпис: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Уредувач на слика
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Отстранување на цртеж
+pdfjs-editor-remove-freetext-button =
+ .title = Отстранување на текст
+pdfjs-editor-remove-stamp-button =
+ .title = Отстранување на слика
+pdfjs-editor-remove-highlight-button =
+ .title = Отстранување на нагласувања
+pdfjs-editor-remove-signature-button =
+ .title = Отстранување на потпис
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Боја
+pdfjs-editor-free-text-size-input = Големина
+pdfjs-editor-ink-color-input = Боја
+pdfjs-editor-ink-thickness-input = Дебелина
+pdfjs-editor-ink-opacity-input = Прозрачност
+pdfjs-editor-stamp-add-image-button =
+ .title = Додавање на слика
+pdfjs-editor-stamp-add-image-button-label = Додај слика
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Дебелина
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Промени ја дебелината при нагласување на елементи што не се текст
+pdfjs-editor-add-signature-container =
+ .aria-label = Контрола на потписи и снимени потписи
+pdfjs-editor-signature-add-signature-button =
+ .title = Додавање на нов потпис
+pdfjs-editor-signature-add-signature-button-label = Додај нов потпис
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Снимен потпис: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Уредувач на текст
+ .default-content = Почнуи со пишување…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Коментар
+ *[other] Коментари
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Затвори ја страничната лента
+ .aria-label = Затвори ја страничната лента
+pdfjs-editor-comments-sidebar-close-button-label = Затвори ја страничната лента
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Гледате нешто вредно за внимание? Истакнете го и напишете коментар.
+pdfjs-editor-comments-sidebar-no-comments-link = Дознајте повеќе
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Дополнителен текст
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Уреди го дополнителниот текст
+pdfjs-editor-alt-text-dialog-label = Изберете опција
+pdfjs-editor-alt-text-dialog-description = Алтернативниот текст помага кога луѓе не можат да видат сликата или кога сликата не се вчитува
+pdfjs-editor-alt-text-add-description-label = Додај опис
+pdfjs-editor-alt-text-add-description-description = Додајте 1-2 реченици што го објаснуваат предметот, околината, или дејствата.
+pdfjs-editor-alt-text-mark-decorative-label = Означи како декоративно
+pdfjs-editor-alt-text-mark-decorative-description = Ова се користи за орнаментални слики, како граници или водени жигови.
+pdfjs-editor-alt-text-cancel-button = Откажи
+pdfjs-editor-alt-text-save-button = Сними
+pdfjs-editor-alt-text-decorative-tooltip = Означено како декоративно
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = На пример: „Момче седнува на маса за да јаде“.
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Дополнителен текст
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Горен лев ќош — промени големина
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Горе на средина — промени големина
+pdfjs-editor-resizer-top-right =
+ .aria-label = Горен десен ќош — промени големина
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Средина десно — промени големина
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Долен десен ќош — промени големина
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Долу на средина — промени големина
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Долен лев ќош — промени големина
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Средина лево — промени големина
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Боја за нагласување
+pdfjs-editor-colorpicker-button =
+ .title = Менување на боја
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Избор на бои
+pdfjs-editor-colorpicker-yellow =
+ .title = Жолта
+pdfjs-editor-colorpicker-green =
+ .title = Зелена
+pdfjs-editor-colorpicker-blue =
+ .title = Сина
+pdfjs-editor-colorpicker-pink =
+ .title = Розова
+pdfjs-editor-colorpicker-red =
+ .title = Црвена
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Прикажи сѐ
+pdfjs-editor-highlight-show-all-button =
+ .title = Прикажи сѐ
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Уреди го алтернативниот текст (опис на слика)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Додај алтернативен текст (опис на слика)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Напиши опис…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Краток опис за луѓе кои не можат да ја видат сликата или кога сликата не се вчитува.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Овој алтернативен текст е креиран автоматски и може да биде неточен.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Дознајте повеќе
+pdfjs-editor-new-alt-text-create-automatically-button-label = Креирај го алтернативниот текст автоматски
+pdfjs-editor-new-alt-text-not-now-button = Не сега
+pdfjs-editor-new-alt-text-error-title = Алтернатиовниот текст не може да се креира автоматски
+pdfjs-editor-new-alt-text-error-description = Напишете Ваш алтернативен текст или обидете се повторно подоцна.
+pdfjs-editor-new-alt-text-error-close-button = Затвори
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Преземање на алтернативен текст модел на ВИ ({ $downloadedSize } од { $totalSize } MB)
+ .aria-valuetext = Преземање на алтернативен текст модел на ВИ ({ $downloadedSize } од { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Алтернативниот текст е додаден
+pdfjs-editor-new-alt-text-added-button-label = Алтернативниот текст е додаден
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Недостасува алтернативен текст
+pdfjs-editor-new-alt-text-missing-button-label = Недостасува алтернативен текст
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Прегледај го алтернативниот текст
+pdfjs-editor-new-alt-text-to-review-button-label = Прегледај го алтернативниот текст
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Креирано автоматски: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Поставки за алтернативен текст на слика
+pdfjs-image-alt-text-settings-button-label = Поставки за алтернативен текст на слика
+pdfjs-editor-alt-text-settings-dialog-label = Поставки за алтернативен текст на слика
+pdfjs-editor-alt-text-settings-automatic-title = Автоматски алтернативен текст
+pdfjs-editor-alt-text-settings-create-model-button-label = Креирај го алтернативниот текст автоматски
+pdfjs-editor-alt-text-settings-create-model-description = Предлага описи за да им помогне на луѓето кои не можат да ја видат сликата или кога сликата не се вчитува.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Модел на вештачка интелигенција со алтернативен текст ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Работи локално на вашиот уред, така што вашите податоци остануваат приватни. Задолжително за автоматски алтернативен текст.
+pdfjs-editor-alt-text-settings-delete-model-button = Избриши
+pdfjs-editor-alt-text-settings-download-model-button = Преземи
+pdfjs-editor-alt-text-settings-downloading-model-button = Се презема…
+pdfjs-editor-alt-text-settings-editor-title = Уредувач на алтернативен текст
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Прикажи го уредувачот на алтернативен текст веднаш при додавање на слика
+pdfjs-editor-alt-text-settings-show-dialog-description = Ви помага да се осигурате дека сите ваши слики имаат алтернативен текст.
+pdfjs-editor-alt-text-settings-close-button = Затвори
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Нагласувањето е додадено
+pdfjs-editor-freetext-added-alert = Текстот е додаден
+pdfjs-editor-ink-added-alert = Цртежот е додаден
+pdfjs-editor-stamp-added-alert = Сликата е додадена
+pdfjs-editor-signature-added-alert = Потписот е додаден
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Нагласувањето е отстрането
+pdfjs-editor-undo-bar-message-freetext = Текстот е отстранет
+pdfjs-editor-undo-bar-message-ink = Цртежот е отстранет
+pdfjs-editor-undo-bar-message-stamp = Сликата е отстранета
+pdfjs-editor-undo-bar-message-signature = Потписот е отстранет
+pdfjs-editor-undo-bar-message-comment = Коментарот е отстранет
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } напомена е отстранета
+ *[other] { $count } напомени е отстранета
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Врати
+pdfjs-editor-undo-bar-undo-button-label = Врати
+pdfjs-editor-undo-bar-close-button =
+ .title = Затвори
+pdfjs-editor-undo-bar-close-button-label = Затвори
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Овој прозорец му овозможува на корисникот да креира потпис за да го додаде во PDF документ. Корисникот може да го уреди името (кое исто така служи како алтернативен текст) и опционално да го зачува потписот за повторна употреба.
+pdfjs-editor-add-signature-dialog-title = Додавање на потпис
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Типкај
+ .title = Типкај
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Цртај
+ .title = Цртај
+pdfjs-editor-add-signature-image-button = Слика
+ .title = Слика
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Типкајте го Вашиот потпис
+ .placeholder = Типкајте го Вашиот потпис
+pdfjs-editor-add-signature-draw-placeholder = Нацртајте го Вашиот потпис
+pdfjs-editor-add-signature-draw-thickness-range-label = Дебелина
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Дебелина на цртежот: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Повлечете датотека тука за да ја прикачите
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Или прелистајте датотеки со слики
+ *[other] Или прелистајте датотеки со слики
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Опис (алтернативен текст)
+pdfjs-editor-add-signature-description-input =
+ .title = Опис (алтернативен текст)
+pdfjs-editor-add-signature-description-default-when-drawing = Потпис
+pdfjs-editor-add-signature-clear-button-label = Избриши го потписот
+pdfjs-editor-add-signature-clear-button =
+ .title = Бришење на потписот
+pdfjs-editor-add-signature-save-checkbox = Сними го потписот
+pdfjs-editor-add-signature-save-warning-message = Можете да снимите најмногу 5 потписи. Отстранете еден за да снимите нов.
+pdfjs-editor-add-signature-image-upload-error-title = Сликата не може да се прикачи
+pdfjs-editor-add-signature-image-upload-error-description = Проверете ја мрежната врска или обидете се со друга слика.
+pdfjs-editor-add-signature-image-no-data-error-title = Оваа слика не може да се конвертира во потпис
+pdfjs-editor-add-signature-image-no-data-error-description = Обидете се да прикачите друга слика.
+pdfjs-editor-add-signature-error-close-button = Затвори
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Откажи
+pdfjs-editor-add-signature-add-button = Додај
+pdfjs-editor-edit-signature-update-button = Ажурирај
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Уреди коментар
+pdfjs-editor-edit-comment-popup-button =
+ .title = Уреди коментар
+pdfjs-editor-delete-comment-popup-button-label = Отстрани го коментарот
+pdfjs-editor-delete-comment-popup-button =
+ .title = Отстрани го коментарот
+pdfjs-show-comment-button =
+ .title = Прикажи го коментарот
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Уреди коментар
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Ажурирај
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Додај коментар
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Додај
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Започнете со пишување…
+pdfjs-editor-edit-comment-dialog-cancel-button = Откажи
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Додај коментар
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Вклучи странична лента (документот содржи преглед, прилози, или слоеви)
+pdfjs-toggle-views-manager-button1-label = Управувај со страниците
+pdfjs-views-manager-sidebar =
+ .aria-label = Странична лента
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Променувач на големината на страничната лента
+pdfjs-views-manager-view-selector-button =
+ .title = Погледи
+pdfjs-views-manager-view-selector-button-label = Погледи
+pdfjs-views-manager-pages-title = Страници
+pdfjs-views-manager-outlines-title1 = Преглед на документот
+ .title = Преглед на документот (двоклик за прикажување/криење на сите ставки)
+pdfjs-views-manager-attachments-title = Прилози
+pdfjs-views-manager-layers-title1 = Слоеви
+ .title = Слоеви (двоклик за ресетирање на сите слоеви)
+pdfjs-views-manager-pages-option-label = Страници
+pdfjs-views-manager-outlines-option-label = Преглед на документот
+pdfjs-views-manager-attachments-option-label = Прилози
+pdfjs-views-manager-layers-option-label = Слоеви
+pdfjs-views-manager-add-file-button =
+ .title = Додај датотека
+pdfjs-views-manager-add-file-button-label = Додај датотека
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } избран
+ *[other] { $count } избрани
+ }
+pdfjs-views-manager-pages-status-none-action-label = Избери страници
+pdfjs-views-manager-pages-status-action-button-label = Управувај
+pdfjs-views-manager-pages-status-copy-button-label = Копирај
+pdfjs-views-manager-pages-status-cut-button-label = Исечи
+pdfjs-views-manager-pages-status-delete-button-label = Избриши
+pdfjs-views-manager-pages-status-export-selected-button-label = Извези ги избраните…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 исечена страница
+ *[other] { $count } исечени страници
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 копирана страница
+ *[other] { $count } копирани страници
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 избришана страница
+ *[other] { $count } избришани страници
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Вашата датотека се подготвува…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Датотеката се прикачува…
+pdfjs-views-manager-status-warning-cut-label = Сечењето на успеа. Освежете ја страницата и обидете се повторно.
+pdfjs-views-manager-status-warning-copy-label = Копирањето на успеа. Освежете ја страницата и обидете се повторно.
+pdfjs-views-manager-status-warning-delete-label = Бришењето на успеа. Освежете ја страницата и обидете се повторно.
+pdfjs-views-manager-status-warning-save-label = Снимањето на успеа. Освежете ја страницата и обидете се повторно.
+pdfjs-views-manager-status-undo-button-label = Врати
+pdfjs-views-manager-status-done-button-label = Готово
+pdfjs-views-manager-status-close-button =
+ .title = Затвори
+pdfjs-views-manager-status-close-button-label = Затвори
+pdfjs-views-manager-paste-button-label = Залепи
+pdfjs-views-manager-paste-button-before =
+ .title = Залепи пред првата страница
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Залепи по страница { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = НОВО
+pdfjs-views-manager-waiting-for-file = Датотеката се прикачува…
+pdfjs-toggle-views-manager-button1 =
+ .title = Управување со страниците
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Отстрани го зачуваниот потпис
+pdfjs-editor-delete-signature-button-label1 = Отстрани го зачуваниот потпис
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Уреди опис
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Уреди опис
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ml/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ml/viewer.ftl
new file mode 100644
index 0000000..6c33b8f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ml/viewer.ftl
@@ -0,0 +1,509 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = മുമ്പുള്ള താള്
+pdfjs-previous-button-label = മുമ്പു്
+pdfjs-next-button =
+ .title = അടുത്ത താള്
+pdfjs-next-button-label = അടുത്തതു്
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = താള്
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } ലെ
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } ലെ { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = ചെറുതാക്കുക
+pdfjs-zoom-out-button-label = ചെറുതാക്കുക
+pdfjs-zoom-in-button =
+ .title = വലുതാക്കുക
+pdfjs-zoom-in-button-label = വലുതാക്കുക
+pdfjs-zoom-select =
+ .title = വ്യാപ്തി മാറ്റുക
+pdfjs-presentation-mode-button =
+ .title = പ്രസന്റേഷന് രീതിയിലേക്കു് മാറ്റുക
+pdfjs-presentation-mode-button-label = പ്രസന്റേഷന് രീതി
+pdfjs-open-file-button =
+ .title = ഫയല് തുറക്കുക
+pdfjs-open-file-button-label = തുറക്കുക
+pdfjs-print-button =
+ .title = അച്ചടിക്കുക
+pdfjs-print-button-label = അച്ചടിക്കുക
+pdfjs-save-button =
+ .title = കരുതിവയ്ക്കുക
+pdfjs-save-button-label = കരുതിവയ്ക്കുക
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ഇറക്കിവയ്ക്കുക
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ഇറക്കിവയ്ക്കുക
+pdfjs-bookmark-button =
+ .title = നിലവിലെ താൾ (നിലവിലെ താളിൽ നിന്നു് യൂ.ആർ.എൽ കാണുക)
+pdfjs-bookmark-button-label = നിലവിലുള്ള താൾ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ഉപകരണങ്ങള്
+pdfjs-tools-button-label = ഉപകരണങ്ങള്
+pdfjs-first-page-button =
+ .title = ആദ്യത്തെ താളിലേയ്ക്കു് പോകുക
+pdfjs-first-page-button-label = ആദ്യത്തെ താളിലേയ്ക്കു് പോകുക
+pdfjs-last-page-button =
+ .title = അവസാന താളിലേയ്ക്കു് പോകുക
+pdfjs-last-page-button-label = അവസാന താളിലേയ്ക്കു് പോകുക
+pdfjs-page-rotate-cw-button =
+ .title = ഘടികാരദിശയില് കറക്കുക
+pdfjs-page-rotate-cw-button-label = ഘടികാരദിശയില് കറക്കുക
+pdfjs-page-rotate-ccw-button =
+ .title = ഘടികാര ദിശയ്ക്കു് വിപരീതമായി കറക്കുക
+pdfjs-page-rotate-ccw-button-label = ഘടികാര ദിശയ്ക്കു് വിപരീതമായി കറക്കുക
+pdfjs-cursor-text-select-tool-button =
+ .title = ടെക്സ്റ്റ് തിരഞ്ഞെടുക്കൽ ടൂള് പ്രാപ്തമാക്കുക
+pdfjs-cursor-text-select-tool-button-label = എഴുത്തു് തിരഞ്ഞെടുക്കൽ കരു
+pdfjs-cursor-hand-tool-button =
+ .title = കൈക്കരു പ്രാപ്തമാക്കുക
+pdfjs-cursor-hand-tool-button-label = കൈക്കരു
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = രേഖയുടെ വിശേഷതകള്...
+pdfjs-document-properties-button-label = രേഖയുടെ വിശേഷതകള്...
+pdfjs-document-properties-file-name = ഫയലിന്റെ പേര്:
+pdfjs-document-properties-file-size = ഫയലിന്റെ വലിപ്പം:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } ബൈറ്റുകൾ)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } ബൈറ്റുകൾ)
+pdfjs-document-properties-title = തലക്കെട്ട്
+pdfjs-document-properties-author = രചയിതാവ്:
+pdfjs-document-properties-subject = വിഷയം:
+pdfjs-document-properties-keywords = പെരുമുരികൾ:
+pdfjs-document-properties-creation-date = പൂര്ത്തിയാകുന്ന തീയതി:
+pdfjs-document-properties-modification-date = മാറ്റം വരുത്തിയ തീയതി:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = സൃഷ്ടികര്ത്താവ്:
+pdfjs-document-properties-producer = പിഡിഎഫ് പ്രൊഡ്യൂസര്:
+pdfjs-document-properties-version = പിഡിഎഫ് പതിപ്പ്:
+pdfjs-document-properties-page-count = താളിന്റെ എണ്ണം:
+pdfjs-document-properties-page-size = താൾ വലുപ്പം
+pdfjs-document-properties-page-size-unit-inches = ഇഞ്ചു്
+pdfjs-document-properties-page-size-unit-millimeters = മില്ലീമീറ്റർ
+pdfjs-document-properties-page-size-orientation-portrait = ഛായപടം രീതിയില്
+pdfjs-document-properties-page-size-orientation-landscape = ഭൂദൃശ്യത്തിന്റെ ആകൃതിയില്
+pdfjs-document-properties-page-size-name-a-three = ആ 3
+pdfjs-document-properties-page-size-name-a-four = ആ 4
+pdfjs-document-properties-page-size-name-letter = കത്തു്
+pdfjs-document-properties-page-size-name-legal = നിയമപരം
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name },{ $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = വിരവോള ഗോളാന്തരക്കാഴ്ച :
+pdfjs-document-properties-linearized-yes = അതെ
+pdfjs-document-properties-linearized-no = ഇല്ല
+pdfjs-document-properties-close-button = അടയ്ക്കുക
+
+## Print
+
+pdfjs-print-progress-message = അച്ചടിപ്പിനു് പ്രമാണം ഒരുക്കുന്നു...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = റദ്ദാക്കുക
+pdfjs-printing-not-supported = മുന്നറിയിപ്പു്: ഈ അന്വേഷിയന്ത്രമിൽ അച്ചടിപ്പു് മുഴുവനായി പിന്തുണയ്ക്കാരില്ല.
+pdfjs-printing-not-ready = മുന്നറിയിപ്പു്: അച്ചടിക്കാനായി ഈ പിഡിഎഫ മൊത്തം ലഭ്യമാക്കിയിട്ടില്ല
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = അണിവക്കം ടോഗിൾ ചെയ്യുക
+pdfjs-toggle-sidebar-button-label = അണിവക്കം ടോഗിൾ ചെയ്യുക
+pdfjs-document-outline-button =
+ .title = ഡോക്യുമെന്റിന്റെ ബാഹ്യരേഖ കാണിക്കുക (എല്ലാ ഇനങ്ങളും വിപുലീകരിക്കാനും ചുരുക്കാനും ഇരട്ട ക്ലിക്കുചെയ്യുക)
+pdfjs-document-outline-button-label = രേഖയുടെ ഔട്ട്ലൈന്
+pdfjs-attachments-button =
+ .title = അറ്റാച്മെന്റുകള് കാണിയ്ക്കുക
+pdfjs-attachments-button-label = അറ്റാച്മെന്റുകള്
+pdfjs-layers-button-label = പാളികൾ
+pdfjs-thumbs-button =
+ .title = തംബ്നെയിലുകള് കാണിയ്ക്കുക
+pdfjs-thumbs-button-label = തംബ്നെയിലുകള്
+pdfjs-findbar-button =
+ .title = രേഖയില് കണ്ടുപിടിയ്ക്കുക
+pdfjs-findbar-button-label = കണ്ടെത്തുക
+pdfjs-additional-layers = കൂടാത്ത പാളികൾ
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = താള് { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } താളിനുള്ള തംബ്നെയില്
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = കണ്ടെത്തുക
+ .placeholder = ഡോക്യുമെന്റില് കണ്ടെത്തുക…
+pdfjs-find-previous-button =
+ .title = വാചകം ഇതിനു മുന്പ് ആവര്ത്തിച്ചത് കണ്ടെത്തുക
+pdfjs-find-previous-button-label = മുമ്പു്
+pdfjs-find-next-button =
+ .title = വാചകം വീണ്ടും ആവര്ത്തിക്കുന്നത് കണ്ടെത്തുക
+pdfjs-find-next-button-label = അടുത്തതു്
+pdfjs-find-highlight-checkbox = എല്ലാം എടുത്തുകാണിയ്ക്കുക
+pdfjs-find-match-case-checkbox-label = അക്ഷരങ്ങള് ഒത്തുനോക്കുക
+pdfjs-find-entire-word-checkbox-label = മുഴുവൻ വാക്കുകൾ
+pdfjs-find-reached-top = രേഖയുടെ മുകളില് എത്തിയിരിക്കുന്നു, താഴെ നിന്നും തുടരുന്നു
+pdfjs-find-reached-bottom = രേഖയുടെ അവസാനം വരെ എത്തിയിരിക്കുന്നു, മുകളില് നിന്നും തുടരുന്നു
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } / { $total } പൊരുത്തങ്ങള്
+ *[other] { $current } / { $total } പൊരുത്തങ്ങള്
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] { $limit } പൊരുത്തങ്ങളില് കൂടുതല്
+ *[other] { $limit } പൊരുത്തങ്ങളില് കൂടുതല്
+ }
+pdfjs-find-not-found = വാചകം കണ്ടെത്താനായില്ല
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = താളിന്റെ വീതി
+pdfjs-page-scale-fit = താള് പാകത്തിനാക്കുക
+pdfjs-page-scale-auto = സ്വയമായി വലുതാക്കുക
+pdfjs-page-scale-actual = യഥാര്ത്ഥ വ്യാപ്തി
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = താള് { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = പിഡിഎഫ് ലഭ്യമാക്കുമ്പോള് പിശക് ഉണ്ടായിരിയ്ക്കുന്നു.
+pdfjs-invalid-file-error = തെറ്റായ അല്ലെങ്കില് തകരാറുള്ള പിഡിഎഫ് ഫയല്.
+pdfjs-missing-file-error = പിഡിഎഫ് ഫയല് ലഭ്യമല്ല.
+pdfjs-unexpected-response-error = പ്രതീക്ഷിക്കാത്ത സെര്വര് മറുപടി.
+pdfjs-rendering-error = താള് റെണ്ടര് ചെയ്യുമ്പോള് പിശകുണ്ടായിരിയ്ക്കുന്നു.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = ഈ പിഡിഎഫ് ഫയല് തുറക്കുന്നതിനു് ഒളിവാക്ക് നല്കുക.
+pdfjs-password-invalid = തെറ്റായ ഒളിവാക്ക്, ദയവായി വീണ്ടും ശ്രമിയ്ക്കുക.
+pdfjs-password-ok-button = ശരി
+pdfjs-password-cancel-button = റദ്ദാക്കുക
+pdfjs-web-fonts-disabled = വെബിനുള്ള അക്ഷരസഞ്ചയങ്ങള് പ്രവര്ത്തന രഹിതം: എംബഡ്ഡ് ചെയ്ത പിഡിഎഫ് അക്ഷരസഞ്ചയങ്ങള് ഉപയോഗിയ്ക്കുവാന് സാധ്യമല്ല.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = എഴുത്തു്
+pdfjs-editor-free-text-button-label = എഴുത്തു്
+pdfjs-editor-ink-button =
+ .title = വരയ്ക്കുക
+pdfjs-editor-ink-button-label = വരയ്ക്കുക
+pdfjs-editor-stamp-button =
+ .title = ചിത്രങ്ങളെ ചേർക്കുക അല്ലെങ്കിൽ തിരുത്തുക
+pdfjs-editor-stamp-button-label = ചിത്രങ്ങളെ ചേർക്കുക അല്ലെങ്കിൽ തിരുത്തുക
+pdfjs-editor-highlight-button =
+ .title = അടയാളപ്പെടുക
+pdfjs-editor-highlight-button-label = അടയാളപ്പെടുക
+pdfjs-highlight-floating-button1 =
+ .title = അടയാളപ്പെടുക
+ .aria-label = അടയാളപ്പെടുക
+pdfjs-highlight-floating-button-label = അടയാളപ്പെടുക
+pdfjs-editor-signature-button =
+ .title = പുതിയ ഒപ്പു് ചേൎക്കുക
+pdfjs-editor-signature-button-label = പുതിയ ഒപ്പു് ചേൎക്കുക
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = ആലേഖ്യം മാറ്റുക
+pdfjs-editor-remove-freetext-button =
+ .title = എഴുത്തു് മാറ്റുക
+pdfjs-editor-remove-stamp-button =
+ .title = ചിത്രം മാറ്റുക
+pdfjs-editor-remove-highlight-button =
+ .title = അടയാളപ്പെട്ടുതു് മാറ്റുക
+pdfjs-editor-remove-signature-button =
+ .title = ഒപ്പു് മാറ്റുക
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = നിറം
+pdfjs-editor-free-text-size-input = വലുപ്പം
+pdfjs-editor-ink-color-input = നിറം
+pdfjs-editor-ink-thickness-input = കനം
+pdfjs-editor-ink-opacity-input = അതാര്യത
+pdfjs-editor-stamp-add-image-button =
+ .title = ചിത്രം ചേർക്കുക
+pdfjs-editor-stamp-add-image-button-label = ചിത്രം ചേർക്കുക
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = കനം
+pdfjs-editor-signature-add-signature-button =
+ .title = പുതിയ ഒപ്പു് ചേൎക്കുക
+pdfjs-editor-signature-add-signature-button-label = പുതിയ ഒപ്പു് ചേൎക്കുക
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = കരുതിവച്ച ഒപ്പു് : { $description }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = അണിവക്കം അടയ്ക്കുക
+ .aria-label = അണിവക്കം അടയ്ക്കുക
+pdfjs-editor-comments-sidebar-close-button-label = അണിവക്കം അടയ്ക്കുക
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = മറുയെഴുത്തു്
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = മറുയെഴുത്തു് തിരുത്തുക
+pdfjs-editor-alt-text-dialog-label = സാധ്യത തിരഞ്ഞെടുക്കൂ
+pdfjs-editor-alt-text-add-description-label = ഒരു വിവരണം ചേർക്കുക
+pdfjs-editor-alt-text-cancel-button = റദ്ദാക്കുക
+pdfjs-editor-alt-text-save-button = കരുതിവയ്ക്കുക
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = ഉദാഹരണം, “ഒരു ചെറുപ്പക്കാരൻ ഭക്ഷണം കഴിക്കാൻ മേശയിലിരുന്നു”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = മറുയെഴുത്തു്
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = അടയാളന്നിറം
+pdfjs-editor-colorpicker-button =
+ .title = നിറം മാറ്റുക
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = നിറസാധ്യതകൾ
+pdfjs-editor-colorpicker-yellow =
+ .title = മഞ്ഞ
+pdfjs-editor-colorpicker-green =
+ .title = പച്ച
+pdfjs-editor-colorpicker-blue =
+ .title = നീല
+pdfjs-editor-colorpicker-pink =
+ .title = പാടല
+pdfjs-editor-colorpicker-red =
+ .title = ചുമന്ന
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = എല്ലാം കാണിക്കുക
+pdfjs-editor-highlight-show-all-button =
+ .title = എല്ലാം കാണിക്കുക
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = മറുയെഴുത്തു് തിരുത്തുക (ചിത്ര വിവരണം)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = മറുയെഴുത്തു് ചേൎക്കുക (ചിത്ര വിവരണം)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = താങ്ങളുടെ വിവരണം ഇവിടെ എഴുതുക...
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = ഈ മറുയെഴുത്തു് തന്നെതാനെയുണ്ടാക്കിയതുകൊണ്ടു് തെറ്റായതാവാം.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = കൂടുതല് അറിയുക
+pdfjs-editor-new-alt-text-create-automatically-button-label = തന്നെതാനെ മറുയെഴുത്തു് ഉണ്ടാക്കുക
+pdfjs-editor-new-alt-text-not-now-button = ഇപ്പോഴല്ല
+pdfjs-editor-new-alt-text-error-title = തന്നെതാനെ മറുയെഴുത്തു് ഉണ്ടാക്കാൻ പറ്റിയില്ല
+pdfjs-editor-new-alt-text-error-description = തനതായ മറുയെഴുത്തു് ഇടുക അല്ലെങ്കിൽ പിന്നീടു് ശ്രമിയ്ക്കുക.
+pdfjs-editor-new-alt-text-error-close-button = അടയ്ക്കുക
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = മറുയെഴുത്തു് ചേൎത്തു
+pdfjs-editor-new-alt-text-added-button-label = മറുയെഴുത്തു് ചേൎത്തു
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = മറുയെഴുത്തു് കാണാന്നില്ല
+pdfjs-editor-new-alt-text-missing-button-label = മറുയെഴുത്തു് കാണാന്നില്ല
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = മറുയെഴുത്തു് അവലോകിക്കുക
+pdfjs-editor-new-alt-text-to-review-button-label = മറുയെഴുത്തു് അവലോകിക്കുക
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = തന്നെതാനെ ഉണ്ടാക്കി : { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = ചിത്ര മറുയെഴുത്തു് ക്രമീകരണങ്ങൾ
+pdfjs-image-alt-text-settings-button-label = ചിത്ര മറുയെഴുത്തു് ക്രമീകരണങ്ങൾ
+pdfjs-editor-alt-text-settings-dialog-label = ചിത്ര മറുയെഴുത്തു് ക്രമീകരണങ്ങൾ
+pdfjs-editor-alt-text-settings-automatic-title = യാന്ത്രിക മറുയെഴുത്തു്
+pdfjs-editor-alt-text-settings-create-model-button-label = തന്നെതാനെ മറുയെഴുത്തു് ഉണ്ടാക്കുക
+pdfjs-editor-alt-text-settings-delete-model-button = മായ്ക്കുക
+pdfjs-editor-alt-text-settings-download-model-button = ഇറക്കിവയ്ക്കുക
+pdfjs-editor-alt-text-settings-downloading-model-button = ഇറക്കിവയ്ക്കുന്നു
+pdfjs-editor-alt-text-settings-show-dialog-description = താങ്ങളുടെ എല്ലാ പടങ്ങളിലും മറുയെഴുത്തുണ്ടെന്നു് തീൎച്ചപ്പെടുത്താൻ തുണയ്ക്കുന്നു.
+pdfjs-editor-alt-text-settings-close-button = അടയ്ക്കുക
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = അടയാളം മാറ്റി
+pdfjs-editor-undo-bar-message-freetext = എഴുത്തു് മാറ്റി
+pdfjs-editor-undo-bar-message-ink = ആലേഖ്യം മാറ്റി
+pdfjs-editor-undo-bar-message-stamp = ചിത്രം മാറ്റി
+pdfjs-editor-undo-bar-message-signature = ഒപ്പു് മാറ്റി
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } കുറിപ്പെഴുതലുകൾ മാറ്റി
+ *[other] { $count } കുറിപ്പെഴുതലുകൾ മാറ്റി
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = പഴയപോലെയാക്കുക
+pdfjs-editor-undo-bar-undo-button-label = പഴയപോലെയാക്കുക
+pdfjs-editor-undo-bar-close-button =
+ .title = അടയ്ക്കുക
+pdfjs-editor-undo-bar-close-button-label = അടയ്ക്കുക
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-title = ഒപ്പു് ചേൎക്കുക
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = തരം
+ .title = തരം
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = വരയ്ക്കുക
+ .title = വരയ്ക്കുക
+pdfjs-editor-add-signature-image-button = ചിത്രം
+ .title = ചിത്രം
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = താങ്ങളുടെ ഒപ്പു് ഇവിടെ എഴുതുക
+ .placeholder = താങ്ങളുടെ ഒപ്പു് ഇവിടെ എഴുതുക
+pdfjs-editor-add-signature-draw-placeholder = താങ്ങളുടെ ഒപ്പു് വരയ്ക്കുക
+pdfjs-editor-add-signature-draw-thickness-range-label = കനം
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = വരപ്പുകനം: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = കയറ്റുവയ്ക്കാൻ വേണ്ടി ഫയലിനു് ഇവിടോട്ടു് വലിച്ചിടുക
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] അല്ലെങ്കിൽ ചിത്രം ഫയലുകൾ തപ്പുക
+ *[other] അല്ലെങ്കിൽ ചിത്രം ഫയലുകൾ തപ്പുക
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = വിവരണം (ഇതരയെഴുതു്)
+pdfjs-editor-add-signature-description-input =
+ .title = വിവരണം (ഇതരയെഴുതു്)
+pdfjs-editor-add-signature-description-default-when-drawing = ഒപ്പു്
+pdfjs-editor-add-signature-clear-button-label = ഒപ്പു് മായ്ക്കുക
+pdfjs-editor-add-signature-clear-button =
+ .title = ഒപ്പു് മായ്ക്കുക
+pdfjs-editor-add-signature-save-checkbox = ഒപ്പു് കരുതിവയ്ക്കുക
+pdfjs-editor-add-signature-save-warning-message = താങ്ങളുടെ ഒപ്പുകളുടെ എണ്ണം 5 ആയി. കൂടുതൽ കരുതിവയ്ക്കാൻ വേണ്ടി ഒരെണ്ണം മാറ്റണ്ടിവരും.
+pdfjs-editor-add-signature-image-upload-error-title = ചിത്രം കയറ്റുവയ്ക്കാൻ പറ്റിയില്ല
+pdfjs-editor-add-signature-image-upload-error-description = താങ്ങളുടെ ശൃംഖല സമ്പൎക്കം പരിശോധിക്കുക അല്ലെങ്കിൽ വേറെയൊരു ചിത്രം ഇട്ടുനോക്കുക
+pdfjs-editor-add-signature-error-close-button = അടയ്ക്കുക
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = റദ്ദാക്കുക
+pdfjs-editor-add-signature-add-button = ചേൎക്കുക
+pdfjs-editor-edit-signature-update-button = പുതുക്കുക
+
+## Edit a comment dialog
+
+pdfjs-editor-edit-comment-dialog-cancel-button = റദ്ദാക്കുക
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-views-manager-status-close-button =
+ .title = അടയ്ക്കുക
+pdfjs-views-manager-status-close-button-label = അടയ്ക്കുക
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = കരുതിവച്ച ഒപ്പു് മാറ്റുക
+pdfjs-editor-delete-signature-button-label1 = കരുതിവച്ച ഒപ്പു് മാറ്റുക
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = വിവരണം തിരുത്തുക
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = വിവരണം തിരുത്തുക
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/mr/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/mr/viewer.ftl
new file mode 100644
index 0000000..fbb9698
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/mr/viewer.ftl
@@ -0,0 +1,210 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = मागील पृष्ठ
+pdfjs-previous-button-label = मागील
+pdfjs-next-button =
+ .title = पुढील पृष्ठ
+pdfjs-next-button-label = पुढील
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = पृष्ठ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount }पैकी
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } पैकी { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = छोटे करा
+pdfjs-zoom-out-button-label = छोटे करा
+pdfjs-zoom-in-button =
+ .title = मोठे करा
+pdfjs-zoom-in-button-label = मोठे करा
+pdfjs-zoom-select =
+ .title = लहान किंवा मोठे करा
+pdfjs-presentation-mode-button =
+ .title = प्रस्तुतिकरण मोडचा वापर करा
+pdfjs-presentation-mode-button-label = प्रस्तुतिकरण मोड
+pdfjs-open-file-button =
+ .title = फाइल उघडा
+pdfjs-open-file-button-label = उघडा
+pdfjs-print-button =
+ .title = छपाई करा
+pdfjs-print-button-label = छपाई करा
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = साधने
+pdfjs-tools-button-label = साधने
+pdfjs-first-page-button =
+ .title = पहिल्या पृष्ठावर जा
+pdfjs-first-page-button-label = पहिल्या पृष्ठावर जा
+pdfjs-last-page-button =
+ .title = शेवटच्या पृष्ठावर जा
+pdfjs-last-page-button-label = शेवटच्या पृष्ठावर जा
+pdfjs-page-rotate-cw-button =
+ .title = घड्याळाच्या काट्याच्या दिशेने फिरवा
+pdfjs-page-rotate-cw-button-label = घड्याळाच्या काट्याच्या दिशेने फिरवा
+pdfjs-page-rotate-ccw-button =
+ .title = घड्याळाच्या काट्याच्या उलट दिशेने फिरवा
+pdfjs-page-rotate-ccw-button-label = घड्याळाच्या काट्याच्या उलट दिशेने फिरवा
+pdfjs-cursor-text-select-tool-button =
+ .title = मजकूर निवड साधन कार्यान्वयीत करा
+pdfjs-cursor-text-select-tool-button-label = मजकूर निवड साधन
+pdfjs-cursor-hand-tool-button =
+ .title = हात साधन कार्यान्वित करा
+pdfjs-cursor-hand-tool-button-label = हस्त साधन
+pdfjs-scroll-vertical-button =
+ .title = अनुलंब स्क्रोलिंग वापरा
+pdfjs-scroll-vertical-button-label = अनुलंब स्क्रोलिंग
+pdfjs-scroll-horizontal-button =
+ .title = क्षैतिज स्क्रोलिंग वापरा
+pdfjs-scroll-horizontal-button-label = क्षैतिज स्क्रोलिंग
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = दस्तऐवज गुणधर्म…
+pdfjs-document-properties-button-label = दस्तऐवज गुणधर्म…
+pdfjs-document-properties-file-name = फाइलचे नाव:
+pdfjs-document-properties-file-size = फाइल आकार:
+pdfjs-document-properties-title = शिर्षक:
+pdfjs-document-properties-author = लेखक:
+pdfjs-document-properties-subject = विषय:
+pdfjs-document-properties-keywords = मुख्यशब्द:
+pdfjs-document-properties-creation-date = निर्माण दिनांक:
+pdfjs-document-properties-modification-date = दुरूस्ती दिनांक:
+pdfjs-document-properties-creator = निर्माता:
+pdfjs-document-properties-producer = PDF निर्माता:
+pdfjs-document-properties-version = PDF आवृत्ती:
+pdfjs-document-properties-page-count = पृष्ठ संख्या:
+pdfjs-document-properties-page-size = पृष्ठ आकार:
+pdfjs-document-properties-page-size-unit-inches = इंच
+pdfjs-document-properties-page-size-unit-millimeters = मीमी
+pdfjs-document-properties-page-size-orientation-portrait = उभी मांडणी
+pdfjs-document-properties-page-size-orientation-landscape = आडवे
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = जलद वेब दृष्य:
+pdfjs-document-properties-linearized-yes = हो
+pdfjs-document-properties-linearized-no = नाही
+pdfjs-document-properties-close-button = बंद करा
+
+## Print
+
+pdfjs-print-progress-message = छपाई करीता पृष्ठ तयार करीत आहे…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = रद्द करा
+pdfjs-printing-not-supported = सावधानता: या ब्राउझरतर्फे छपाइ पूर्णपणे समर्थीत नाही.
+pdfjs-printing-not-ready = सावधानता: छपाईकरिता PDF पूर्णतया लोड झाले नाही.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = बाजूचीपट्टी टॉगल करा
+pdfjs-toggle-sidebar-button-label = बाजूचीपट्टी टॉगल करा
+pdfjs-document-outline-button =
+ .title = दस्तऐवज बाह्यरेखा दर्शवा (विस्तृत करण्यासाठी दोनवेळा क्लिक करा /सर्व घटक दाखवा)
+pdfjs-document-outline-button-label = दस्तऐवज रूपरेषा
+pdfjs-attachments-button =
+ .title = जोडपत्र दाखवा
+pdfjs-attachments-button-label = जोडपत्र
+pdfjs-thumbs-button =
+ .title = थंबनेल्स् दाखवा
+pdfjs-thumbs-button-label = थंबनेल्स्
+pdfjs-findbar-button =
+ .title = दस्तऐवजात शोधा
+pdfjs-findbar-button-label = शोधा
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = पृष्ठ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = पृष्ठाचे थंबनेल { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = शोधा
+ .placeholder = दस्तऐवजात शोधा…
+pdfjs-find-previous-button =
+ .title = वाकप्रयोगची मागील घटना शोधा
+pdfjs-find-previous-button-label = मागील
+pdfjs-find-next-button =
+ .title = वाकप्रयोगची पुढील घटना शोधा
+pdfjs-find-next-button-label = पुढील
+pdfjs-find-highlight-checkbox = सर्व ठळक करा
+pdfjs-find-match-case-checkbox-label = आकार जुळवा
+pdfjs-find-entire-word-checkbox-label = संपूर्ण शब्द
+pdfjs-find-reached-top = दस्तऐवजाच्या शीर्षकास पोहचले, तळपासून पुढे
+pdfjs-find-reached-bottom = दस्तऐवजाच्या तळाला पोहचले, शीर्षकापासून पुढे
+pdfjs-find-not-found = वाकप्रयोग आढळले नाही
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = पृष्ठाची रूंदी
+pdfjs-page-scale-fit = पृष्ठ बसवा
+pdfjs-page-scale-auto = स्वयं लाहन किंवा मोठे करणे
+pdfjs-page-scale-actual = प्रत्यक्ष आकार
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF लोड करतेवेळी त्रुटी आढळली.
+pdfjs-invalid-file-error = अवैध किंवा दोषीत PDF फाइल.
+pdfjs-missing-file-error = न आढळणारी PDF फाइल.
+pdfjs-unexpected-response-error = अनपेक्षित सर्व्हर प्रतिसाद.
+pdfjs-rendering-error = पृष्ठ दाखवतेवेळी त्रुटी आढळली.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } टिपण्णी]
+
+## Password
+
+pdfjs-password-label = ही PDF फाइल उघडण्याकरिता पासवर्ड द्या.
+pdfjs-password-invalid = अवैध पासवर्ड. कृपया पुन्हा प्रयत्न करा.
+pdfjs-password-ok-button = ठीक आहे
+pdfjs-password-cancel-button = रद्द करा
+pdfjs-web-fonts-disabled = वेब टंक असमर्थीत आहेत: एम्बेडेड PDF टंक वापर अशक्य.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ms/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ms/viewer.ftl
new file mode 100644
index 0000000..e5e8b1e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ms/viewer.ftl
@@ -0,0 +1,222 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Halaman Dahulu
+pdfjs-previous-button-label = Dahulu
+pdfjs-next-button =
+ .title = Halaman Berikut
+pdfjs-next-button-label = Berikut
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Halaman
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = daripada { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } daripada { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zum Keluar
+pdfjs-zoom-out-button-label = Zum Keluar
+pdfjs-zoom-in-button =
+ .title = Zum Masuk
+pdfjs-zoom-in-button-label = Zum Masuk
+pdfjs-zoom-select =
+ .title = Zum
+pdfjs-presentation-mode-button =
+ .title = Tukar ke Mod Persembahan
+pdfjs-presentation-mode-button-label = Mod Persembahan
+pdfjs-open-file-button =
+ .title = Buka Fail
+pdfjs-open-file-button-label = Buka
+pdfjs-print-button =
+ .title = Cetak
+pdfjs-print-button-label = Cetak
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Alatan
+pdfjs-tools-button-label = Alatan
+pdfjs-first-page-button =
+ .title = Pergi ke Halaman Pertama
+pdfjs-first-page-button-label = Pergi ke Halaman Pertama
+pdfjs-last-page-button =
+ .title = Pergi ke Halaman Terakhir
+pdfjs-last-page-button-label = Pergi ke Halaman Terakhir
+pdfjs-page-rotate-cw-button =
+ .title = Berputar ikut arah Jam
+pdfjs-page-rotate-cw-button-label = Berputar ikut arah Jam
+pdfjs-page-rotate-ccw-button =
+ .title = Pusing berlawan arah jam
+pdfjs-page-rotate-ccw-button-label = Pusing berlawan arah jam
+pdfjs-cursor-text-select-tool-button =
+ .title = Dayakan Alatan Pilihan Teks
+pdfjs-cursor-text-select-tool-button-label = Alatan Pilihan Teks
+pdfjs-cursor-hand-tool-button =
+ .title = Dayakan Alatan Tangan
+pdfjs-cursor-hand-tool-button-label = Alatan Tangan
+pdfjs-scroll-vertical-button =
+ .title = Guna Skrol Menegak
+pdfjs-scroll-vertical-button-label = Skrol Menegak
+pdfjs-scroll-horizontal-button =
+ .title = Guna Skrol Mengufuk
+pdfjs-scroll-horizontal-button-label = Skrol Mengufuk
+pdfjs-scroll-wrapped-button =
+ .title = Guna Skrol Berbalut
+pdfjs-scroll-wrapped-button-label = Skrol Berbalut
+pdfjs-spread-none-button =
+ .title = Jangan hubungkan hamparan halaman
+pdfjs-spread-none-button-label = Tanpa Hamparan
+pdfjs-spread-odd-button =
+ .title = Hubungkan hamparan halaman dengan halaman nombor ganjil
+pdfjs-spread-odd-button-label = Hamparan Ganjil
+pdfjs-spread-even-button =
+ .title = Hubungkan hamparan halaman dengan halaman nombor genap
+pdfjs-spread-even-button-label = Hamparan Seimbang
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Sifat Dokumen…
+pdfjs-document-properties-button-label = Sifat Dokumen…
+pdfjs-document-properties-file-name = Nama fail:
+pdfjs-document-properties-file-size = Saiz fail:
+pdfjs-document-properties-title = Tajuk:
+pdfjs-document-properties-author = Pengarang:
+pdfjs-document-properties-subject = Subjek:
+pdfjs-document-properties-keywords = Kata kunci:
+pdfjs-document-properties-creation-date = Masa Dicipta:
+pdfjs-document-properties-modification-date = Tarikh Ubahsuai:
+pdfjs-document-properties-creator = Pencipta:
+pdfjs-document-properties-producer = Pengeluar PDF:
+pdfjs-document-properties-version = Versi PDF:
+pdfjs-document-properties-page-count = Kiraan Laman:
+pdfjs-document-properties-page-size = Saiz Halaman:
+pdfjs-document-properties-page-size-unit-inches = dalam
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = potret
+pdfjs-document-properties-page-size-orientation-landscape = landskap
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Paparan Web Pantas:
+pdfjs-document-properties-linearized-yes = Ya
+pdfjs-document-properties-linearized-no = Tidak
+pdfjs-document-properties-close-button = Tutup
+
+## Print
+
+pdfjs-print-progress-message = Menyediakan dokumen untuk dicetak…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Batal
+pdfjs-printing-not-supported = Amaran: Cetakan ini tidak sepenuhnya disokong oleh pelayar ini.
+pdfjs-printing-not-ready = Amaran: PDF tidak sepenuhnya dimuatkan untuk dicetak.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Togol Bar Sisi
+pdfjs-toggle-sidebar-button-label = Togol Bar Sisi
+pdfjs-document-outline-button =
+ .title = Papar Rangka Dokumen (klik-dua-kali untuk kembangkan/kolaps semua item)
+pdfjs-document-outline-button-label = Rangka Dokumen
+pdfjs-attachments-button =
+ .title = Papar Lampiran
+pdfjs-attachments-button-label = Lampiran
+pdfjs-thumbs-button =
+ .title = Papar Thumbnails
+pdfjs-thumbs-button-label = Imej kecil
+pdfjs-findbar-button =
+ .title = Cari didalam Dokumen
+pdfjs-findbar-button-label = Cari
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Halaman { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Halaman Imej kecil { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Cari
+ .placeholder = Cari dalam dokumen…
+pdfjs-find-previous-button =
+ .title = Cari teks frasa berkenaan yang terdahulu
+pdfjs-find-previous-button-label = Dahulu
+pdfjs-find-next-button =
+ .title = Cari teks frasa berkenaan yang berikut
+pdfjs-find-next-button-label = Berikut
+pdfjs-find-highlight-checkbox = Serlahkan semua
+pdfjs-find-match-case-checkbox-label = Huruf sepadan
+pdfjs-find-entire-word-checkbox-label = Seluruh perkataan
+pdfjs-find-reached-top = Mencapai teratas daripada dokumen, sambungan daripada bawah
+pdfjs-find-reached-bottom = Mencapai terakhir daripada dokumen, sambungan daripada atas
+pdfjs-find-not-found = Frasa tidak ditemui
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lebar Halaman
+pdfjs-page-scale-fit = Muat Halaman
+pdfjs-page-scale-auto = Zoom Automatik
+pdfjs-page-scale-actual = Saiz Sebenar
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Masalah berlaku semasa menuatkan sebuah PDF.
+pdfjs-invalid-file-error = Tidak sah atau fail PDF rosak.
+pdfjs-missing-file-error = Fail PDF Hilang.
+pdfjs-unexpected-response-error = Respon pelayan yang tidak dijangka.
+pdfjs-rendering-error = Ralat berlaku ketika memberikan halaman.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Anotasi]
+
+## Password
+
+pdfjs-password-label = Masukan kata kunci untuk membuka fail PDF ini.
+pdfjs-password-invalid = Kata laluan salah. Cuba lagi.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Batal
+pdfjs-web-fonts-disabled = Fon web dinyahdayakan: tidak dapat menggunakan fon terbenam PDF.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/my/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/my/viewer.ftl
new file mode 100644
index 0000000..e6c6c35
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/my/viewer.ftl
@@ -0,0 +1,173 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = အရင် စာမျက်နှာ
+pdfjs-previous-button-label = အရင်နေရာ
+pdfjs-next-button =
+ .title = ရှေ့ စာမျက်နှာ
+pdfjs-next-button-label = နောက်တခု
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = စာမျက်နှာ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } ၏
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } ၏ { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = ချုံ့ပါ
+pdfjs-zoom-out-button-label = ချုံ့ပါ
+pdfjs-zoom-in-button =
+ .title = ချဲ့ပါ
+pdfjs-zoom-in-button-label = ချဲ့ပါ
+pdfjs-zoom-select =
+ .title = ချုံ့/ချဲ့ပါ
+pdfjs-presentation-mode-button =
+ .title = ဆွေးနွေးတင်ပြစနစ်သို့ ကူးပြောင်းပါ
+pdfjs-presentation-mode-button-label = ဆွေးနွေးတင်ပြစနစ်
+pdfjs-open-file-button =
+ .title = ဖိုင်အားဖွင့်ပါ။
+pdfjs-open-file-button-label = ဖွင့်ပါ
+pdfjs-print-button =
+ .title = ပုံနှိုပ်ပါ
+pdfjs-print-button-label = ပုံနှိုပ်ပါ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ကိရိယာများ
+pdfjs-tools-button-label = ကိရိယာများ
+pdfjs-first-page-button =
+ .title = ပထမ စာမျက်နှာသို့
+pdfjs-first-page-button-label = ပထမ စာမျက်နှာသို့
+pdfjs-last-page-button =
+ .title = နောက်ဆုံး စာမျက်နှာသို့
+pdfjs-last-page-button-label = နောက်ဆုံး စာမျက်နှာသို့
+pdfjs-page-rotate-cw-button =
+ .title = နာရီလက်တံ အတိုင်း
+pdfjs-page-rotate-cw-button-label = နာရီလက်တံ အတိုင်း
+pdfjs-page-rotate-ccw-button =
+ .title = နာရီလက်တံ ပြောင်းပြန်
+pdfjs-page-rotate-ccw-button-label = နာရီလက်တံ ပြောင်းပြန်
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = မှတ်တမ်းမှတ်ရာ ဂုဏ်သတ္တိများ
+pdfjs-document-properties-button-label = မှတ်တမ်းမှတ်ရာ ဂုဏ်သတ္တိများ
+pdfjs-document-properties-file-name = ဖိုင် :
+pdfjs-document-properties-file-size = ဖိုင်ဆိုဒ် :
+pdfjs-document-properties-title = ခေါင်းစဉ် -
+pdfjs-document-properties-author = ရေးသားသူ:
+pdfjs-document-properties-subject = အကြောင်းအရာ:
+pdfjs-document-properties-keywords = သော့ချက် စာလုံး:
+pdfjs-document-properties-creation-date = ထုတ်လုပ်ရက်စွဲ:
+pdfjs-document-properties-modification-date = ပြင်ဆင်ရက်စွဲ:
+pdfjs-document-properties-creator = ဖန်တီးသူ:
+pdfjs-document-properties-producer = PDF ထုတ်လုပ်သူ:
+pdfjs-document-properties-version = PDF ဗားရှင်း:
+pdfjs-document-properties-page-count = စာမျက်နှာအရေအတွက်:
+
+##
+
+pdfjs-document-properties-close-button = ပိတ်
+
+## Print
+
+pdfjs-print-progress-message = Preparing document for printing…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ပယ်ဖျက်ပါ
+pdfjs-printing-not-supported = သတိပေးချက်၊ပရင့်ထုတ်ခြင်းကိုဤဘယောက်ဆာသည် ပြည့်ဝစွာထောက်ပံ့မထားပါ ။
+pdfjs-printing-not-ready = သတိပေးချက်: ယခု PDF ဖိုင်သည် ပုံနှိပ်ရန် မပြည့်စုံပါ
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = ဘေးတန်းဖွင့်ပိတ်
+pdfjs-toggle-sidebar-button-label = ဖွင့်ပိတ် ဆလိုက်ဒါ
+pdfjs-document-outline-button =
+ .title = စာတမ်းအကျဉ်းချုပ်ကို ပြပါ (စာရင်းအားလုံးကို ချုံ့/ချဲ့ရန် ကလစ်နှစ်ချက်နှိပ်ပါ)
+pdfjs-document-outline-button-label = စာတမ်းအကျဉ်းချုပ်
+pdfjs-attachments-button =
+ .title = တွဲချက်များ ပြပါ
+pdfjs-attachments-button-label = တွဲထားချက်များ
+pdfjs-thumbs-button =
+ .title = ပုံရိပ်ငယ်များကို ပြပါ
+pdfjs-thumbs-button-label = ပုံရိပ်ငယ်များ
+pdfjs-findbar-button =
+ .title = Find in Document
+pdfjs-findbar-button-label = ရှာဖွေပါ
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = စာမျက်နှာ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = စာမျက်နှာရဲ့ ပုံရိပ်ငယ် { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ရှာဖွေပါ
+ .placeholder = စာတမ်းထဲတွင် ရှာဖွေရန်…
+pdfjs-find-previous-button =
+ .title = စကားစုရဲ့ အရင် ဖြစ်ပွားမှုကို ရှာဖွေပါ
+pdfjs-find-previous-button-label = နောက်သို့
+pdfjs-find-next-button =
+ .title = စကားစုရဲ့ နောက်ထပ် ဖြစ်ပွားမှုကို ရှာဖွေပါ
+pdfjs-find-next-button-label = ရှေ့သို့
+pdfjs-find-highlight-checkbox = အားလုံးကို မျဉ်းသားပါ
+pdfjs-find-match-case-checkbox-label = စာလုံး တိုက်ဆိုင်ပါ
+pdfjs-find-reached-top = စာမျက်နှာထိပ် ရောက်နေပြီ၊ အဆုံးကနေ ပြန်စပါ
+pdfjs-find-reached-bottom = စာမျက်နှာအဆုံး ရောက်နေပြီ၊ ထိပ်ကနေ ပြန်စပါ
+pdfjs-find-not-found = စကားစု မတွေ့ရဘူး
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = စာမျက်နှာ အကျယ်
+pdfjs-page-scale-fit = စာမျက်နှာ ကွက်တိ
+pdfjs-page-scale-auto = အလိုအလျောက် ချုံ့ချဲ့
+pdfjs-page-scale-actual = အမှန်တကယ်ရှိတဲ့ အရွယ်
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF ဖိုင် ကိုဆွဲတင်နေချိန်မှာ အမှားတစ်ခုတွေ့ရပါတယ်။
+pdfjs-invalid-file-error = မရသော သို့ ပျက်နေသော PDF ဖိုင်
+pdfjs-missing-file-error = PDF ပျောက်ဆုံး
+pdfjs-unexpected-response-error = မမျှော်လင့်ထားသော ဆာဗာမှ ပြန်ကြားချက်
+pdfjs-rendering-error = စာမျက်နှာကို ပုံဖော်နေချိန်မှာ အမှားတစ်ခုတွေ့ရပါတယ်။
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } အဓိပ္ပာယ်ဖွင့်ဆိုချက်]
+
+## Password
+
+pdfjs-password-label = ယခု PDF ကို ဖွင့်ရန် စကားဝှက်ကို ရိုက်ပါ။
+pdfjs-password-invalid = စာဝှက် မှားသည်။ ထပ်ကြိုးစားကြည့်ပါ။
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = ပယ်ဖျက်ပါ
+pdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nb-NO/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nb-NO/viewer.ftl
new file mode 100644
index 0000000..2413dc9
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nb-NO/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Forrige side
+pdfjs-previous-button-label = Forrige
+pdfjs-next-button =
+ .title = Neste side
+pdfjs-next-button-label = Neste
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Side
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = av { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } av { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom ut
+pdfjs-zoom-out-button-label = Zoom ut
+pdfjs-zoom-in-button =
+ .title = Zoom inn
+pdfjs-zoom-in-button-label = Zoom inn
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Bytt til presentasjonsmodus
+pdfjs-presentation-mode-button-label = Presentasjonsmodus
+pdfjs-open-file-button =
+ .title = Åpne fil
+pdfjs-open-file-button-label = Åpne
+pdfjs-print-button =
+ .title = Skriv ut
+pdfjs-print-button-label = Skriv ut
+pdfjs-save-button =
+ .title = Lagre
+pdfjs-save-button-label = Lagre
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Last ned
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Last ned
+pdfjs-bookmark-button =
+ .title = Gjeldende side (se URL fra gjeldende side)
+pdfjs-bookmark-button-label = Gjeldende side
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Verktøy
+pdfjs-tools-button-label = Verktøy
+pdfjs-first-page-button =
+ .title = Gå til første side
+pdfjs-first-page-button-label = Gå til første side
+pdfjs-last-page-button =
+ .title = Gå til siste side
+pdfjs-last-page-button-label = Gå til siste side
+pdfjs-page-rotate-cw-button =
+ .title = Roter med klokken
+pdfjs-page-rotate-cw-button-label = Roter med klokken
+pdfjs-page-rotate-ccw-button =
+ .title = Roter mot klokken
+pdfjs-page-rotate-ccw-button-label = Roter mot klokken
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktiver tekstmarkeringsverktøy
+pdfjs-cursor-text-select-tool-button-label = Tekstmarkeringsverktøy
+pdfjs-cursor-hand-tool-button =
+ .title = Aktiver handverktøy
+pdfjs-cursor-hand-tool-button-label = Handverktøy
+pdfjs-scroll-page-button =
+ .title = Bruk siderulling
+pdfjs-scroll-page-button-label = Siderulling
+pdfjs-scroll-vertical-button =
+ .title = Bruk vertikal rulling
+pdfjs-scroll-vertical-button-label = Vertikal rulling
+pdfjs-scroll-horizontal-button =
+ .title = Bruk horisontal rulling
+pdfjs-scroll-horizontal-button-label = Horisontal rulling
+pdfjs-scroll-wrapped-button =
+ .title = Bruk flersiderulling
+pdfjs-scroll-wrapped-button-label = Flersiderulling
+pdfjs-spread-none-button =
+ .title = Vis enkeltsider
+pdfjs-spread-none-button-label = Enkeltsider
+pdfjs-spread-odd-button =
+ .title = Vis oppslag med ulike sidenumre til venstre
+pdfjs-spread-odd-button-label = Oppslag med forside
+pdfjs-spread-even-button =
+ .title = Vis oppslag med like sidenumre til venstre
+pdfjs-spread-even-button-label = Oppslag uten forside
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentegenskaper …
+pdfjs-document-properties-button-label = Dokumentegenskaper …
+pdfjs-document-properties-file-name = Filnavn:
+pdfjs-document-properties-file-size = Filstørrelse:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } byte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } byte)
+pdfjs-document-properties-title = Dokumentegenskaper …
+pdfjs-document-properties-author = Forfatter:
+pdfjs-document-properties-subject = Emne:
+pdfjs-document-properties-keywords = Nøkkelord:
+pdfjs-document-properties-creation-date = Opprettet dato:
+pdfjs-document-properties-modification-date = Endret dato:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Opprettet av:
+pdfjs-document-properties-producer = PDF-verktøy:
+pdfjs-document-properties-version = PDF-versjon:
+pdfjs-document-properties-page-count = Sideantall:
+pdfjs-document-properties-page-size = Sidestørrelse:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = stående
+pdfjs-document-properties-page-size-orientation-landscape = liggende
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Hurtig nettvisning:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nei
+pdfjs-document-properties-close-button = Lukk
+pdfjs-digital-signature-properties-view-certificate = Vis sertifikat
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Grunn: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Tidsstempel: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Undersignatur ({ $count })
+ *[other] Undersignaturer ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Forbereder dokument for utskrift …
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Avbryt
+pdfjs-printing-not-supported = Advarsel: Utskrift er ikke fullstendig støttet av denne nettleseren.
+pdfjs-printing-not-ready = Advarsel: PDF er ikke fullstendig innlastet for utskrift.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Slå av/på sidestolpe
+pdfjs-toggle-sidebar-notification-button =
+ .title = Vis/gjem sidestolpe (dokumentet inneholder oversikt/vedlegg/lag)
+pdfjs-toggle-sidebar-button-label = Slå av/på sidestolpe
+pdfjs-document-outline-button =
+ .title = Vis dokumentdisposisjonen (dobbeltklikk for å utvide/skjule alle elementer)
+pdfjs-document-outline-button-label = Dokumentdisposisjon
+pdfjs-attachments-button =
+ .title = Vis vedlegg
+pdfjs-attachments-button-label = Vedlegg
+pdfjs-layers-button =
+ .title = Vis lag (dobbeltklikk for å tilbakestille alle lag til standardtilstand)
+pdfjs-layers-button-label = Lag
+pdfjs-thumbs-button =
+ .title = Vis miniatyrbilde
+pdfjs-thumbs-button-label = Miniatyrbilde
+pdfjs-current-outline-item-button =
+ .title = Finn gjeldende disposisjonselement
+pdfjs-current-outline-item-button-label = Gjeldende disposisjonselement
+pdfjs-findbar-button =
+ .title = Finn i dokumentet
+pdfjs-findbar-button-label = Finn
+pdfjs-additional-layers = Ytterligere lag
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatyrbilde av side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Velg side { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Side { $page } av { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Søk
+ .placeholder = Søk i dokument…
+pdfjs-find-previous-button =
+ .title = Finn forrige forekomst av frasen
+pdfjs-find-previous-button-label = Forrige
+pdfjs-find-next-button =
+ .title = Finn neste forekomst av frasen
+pdfjs-find-next-button-label = Neste
+pdfjs-find-highlight-checkbox = Uthev alle
+pdfjs-find-match-case-checkbox-label = Skill store/små bokstaver
+pdfjs-find-match-diacritics-checkbox-label = Samsvar diakritiske tegn
+pdfjs-find-entire-word-checkbox-label = Hele ord
+pdfjs-find-reached-top = Nådde toppen av dokumentet, fortsetter fra bunnen
+pdfjs-find-reached-bottom = Nådde bunnen av dokumentet, fortsetter fra toppen
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } av { $total } treff
+ *[other] { $current } av { $total } treff
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mer enn { $limit } treff
+ *[other] Mer enn { $limit } treff
+ }
+pdfjs-find-not-found = Fant ikke teksten
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sidebredde
+pdfjs-page-scale-fit = Tilpass til siden
+pdfjs-page-scale-auto = Automatisk zoom
+pdfjs-page-scale-actual = Virkelig størrelse
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Side { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = En feil oppstod ved lasting av PDF.
+pdfjs-invalid-file-error = Ugyldig eller skadet PDF-fil.
+pdfjs-missing-file-error = Manglende PDF-fil.
+pdfjs-unexpected-response-error = Uventet serverrespons.
+pdfjs-rendering-error = En feil oppstod ved opptegning av siden.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } annotasjon]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Skriv inn passordet for å åpne denne PDF-filen.
+pdfjs-password-invalid = Ugyldig passord. Prøv igjen.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Avbryt
+pdfjs-web-fonts-disabled = Web-fonter er avslått: Kan ikke bruke innbundne PDF-fonter.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Endre tekstfarge
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Tegn
+pdfjs-editor-color-picker-ink-input =
+ .title = Endre tegnefarge
+pdfjs-editor-ink-button-label = Tegn
+pdfjs-editor-stamp-button =
+ .title = Legg til eller rediger bilder
+pdfjs-editor-stamp-button-label = Legg til eller rediger bilder
+pdfjs-editor-highlight-button =
+ .title = Markere
+pdfjs-editor-highlight-button-label = Markere
+pdfjs-highlight-floating-button1 =
+ .title = Markere
+ .aria-label = Markere
+pdfjs-highlight-floating-button-label = Markere
+pdfjs-comment-floating-button =
+ .title = Kommenter
+ .aria-label = Kommenter
+pdfjs-comment-floating-button-label = Kommenter
+pdfjs-editor-comment-button =
+ .title = Kommentar
+ .aria-label = Kommentar
+pdfjs-editor-comment-button-label = Kommentar
+pdfjs-editor-signature-button =
+ .title = Legg til signatur
+pdfjs-editor-signature-button-label = Legg til signatur
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Redigering av markering
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Redigering av tegninger
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signatur-redigerer: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Bilderedigerer
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Fjern tegningen
+pdfjs-editor-remove-freetext-button =
+ .title = Fjern tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Fjern bildet
+pdfjs-editor-remove-highlight-button =
+ .title = Fjern utheving
+pdfjs-editor-remove-signature-button =
+ .title = Fjern signatur
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Farge
+pdfjs-editor-free-text-size-input = Størrelse
+pdfjs-editor-ink-color-input = Farge
+pdfjs-editor-ink-thickness-input = Tykkelse
+pdfjs-editor-ink-opacity-input = Opasitet
+pdfjs-editor-stamp-add-image-button =
+ .title = Legg til bilde
+pdfjs-editor-stamp-add-image-button-label = Legg til bilde
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tykkelse
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Endre tykkelse når du markerer andre elementer enn tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Signaturkontroller og lagrede signaturer
+pdfjs-editor-signature-add-signature-button =
+ .title = Legg til ny signatur
+pdfjs-editor-signature-add-signature-button-label = Legg til ny signatur
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Lagret signatur: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstredigering
+ .default-content = Begynn å skrive…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Kommentar
+ *[other] Kommentarer
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Lukk sidestolpen
+ .aria-label = Lukk sidestolpen
+pdfjs-editor-comments-sidebar-close-button-label = Lukk sidestolpen
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Ser du noe verdt å merke seg? Marker det og legg igjen en kommentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Les mer
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativ tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Rediger alternativ tekst
+pdfjs-editor-alt-text-dialog-label = Velg et alternativ
+pdfjs-editor-alt-text-dialog-description = Alt-tekst (alternativ tekst) hjelper når folk ikke kan se bildet eller når det ikke lastes inn.
+pdfjs-editor-alt-text-add-description-label = Legg til en beskrivelse
+pdfjs-editor-alt-text-add-description-description = Gå etter 1-2 setninger som beskriver emnet, settingen eller handlingene.
+pdfjs-editor-alt-text-mark-decorative-label = Merk som dekorativt
+pdfjs-editor-alt-text-mark-decorative-description = Dette brukes til dekorative bilder, som kantlinjer eller vannmerker.
+pdfjs-editor-alt-text-cancel-button = Avbryt
+pdfjs-editor-alt-text-save-button = Lagre
+pdfjs-editor-alt-text-decorative-tooltip = Merket som dekorativ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = For eksempel, «En ung mann setter seg ved et bord for å spise et måltid»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativ tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Øverste venstre hjørne – endre størrelse
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Øverst i midten — endre størrelse
+pdfjs-editor-resizer-top-right =
+ .aria-label = Øverste høyre hjørne – endre størrelse
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Midt til høyre – endre størrelse
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Nederste høyre hjørne – endre størrelse
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Nederst i midten — endre størrelse
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Nederste venstre hjørne – endre størrelse
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Midt til venstre — endre størrelse
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Uthevingsfarge
+pdfjs-editor-colorpicker-button =
+ .title = Endre farge
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Fargevalg
+pdfjs-editor-colorpicker-yellow =
+ .title = Gul
+pdfjs-editor-colorpicker-green =
+ .title = Grønn
+pdfjs-editor-colorpicker-blue =
+ .title = Blå
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Rød
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Vis alle
+pdfjs-editor-highlight-show-all-button =
+ .title = Vis alle
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Rediger alternativ tekst (bildebeskrivelse)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Legg til alternativ tekst (bildebeskrivelse)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skriv din beskrivelse her…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kort beskrivelse for folk som ikke kan se bildet eller når bildet ikke lastes inn.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Denne alternative teksten ble opprettet automatisk og kan være unøyaktig.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Les mer
+pdfjs-editor-new-alt-text-create-automatically-button-label = Lag alternativ tekst automatisk
+pdfjs-editor-new-alt-text-not-now-button = Ikke nå
+pdfjs-editor-new-alt-text-error-title = Kunne ikke opprette alternativ tekst automatisk
+pdfjs-editor-new-alt-text-error-description = Skriv din egen alternativ tekst eller prøv igjen senere.
+pdfjs-editor-new-alt-text-error-close-button = Lukk
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Laster ned alternativ tekst AI-modell ({ $downloadedSize } av { $totalSize } MB)
+ .aria-valuetext = Laster ned alternativ tekst AI-modell ({ $downloadedSize } av { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativ tekst lagt til
+pdfjs-editor-new-alt-text-added-button-label = Alternativ tekst lagt til
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Mangler alternativ tekst
+pdfjs-editor-new-alt-text-missing-button-label = Mangler alternativ tekst
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Gjennomgå alt-tekst
+pdfjs-editor-new-alt-text-to-review-button-label = Gjennomgå alternativ tekst
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Opprettet automatisk: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Innstillinger for alternativ tekst for bilde
+pdfjs-image-alt-text-settings-button-label = Innstillinger for alternativ tekst for bilde
+pdfjs-editor-alt-text-settings-dialog-label = Innstillinger for alternativ tekst for bilde
+pdfjs-editor-alt-text-settings-automatic-title = Automatisk alternativ tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Opprett alternativ tekst automatisk
+pdfjs-editor-alt-text-settings-create-model-description = Foreslår beskrivelser for å hjelpe folk som ikke kan se bildet eller når bildet ikke lastes inn.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alternativ tekst AI-modell ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Kjører lokalt på enheten din slik at dataene dine forblir private. Nødvendig for automatisk alternativ tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Slett
+pdfjs-editor-alt-text-settings-download-model-button = Last ned
+pdfjs-editor-alt-text-settings-downloading-model-button = Laster ned…
+pdfjs-editor-alt-text-settings-editor-title = Alternativ tekst-redigerer
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Vis alternativ tekst-redigerer direkte når du legger til et bilde
+pdfjs-editor-alt-text-settings-show-dialog-description = Hjelper deg å sørge for at alle bildene dine har alternativ tekst.
+pdfjs-editor-alt-text-settings-close-button = Lukk
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Utheving lagt til
+pdfjs-editor-freetext-added-alert = Tekst lagt til
+pdfjs-editor-ink-added-alert = Tegning lagt til
+pdfjs-editor-stamp-added-alert = Bilde lagt til
+pdfjs-editor-signature-added-alert = Signatur lagt til
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Markering fjernet
+pdfjs-editor-undo-bar-message-freetext = Tekst fjernet
+pdfjs-editor-undo-bar-message-ink = Tegning fjernet
+pdfjs-editor-undo-bar-message-stamp = Bilde fjernet
+pdfjs-editor-undo-bar-message-signature = Signatur fjernet
+pdfjs-editor-undo-bar-message-comment = Kommentar fjernet
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } kommentar fjernet
+ *[other] { $count } kommentarer fjernet
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Angre
+pdfjs-editor-undo-bar-undo-button-label = Angre
+pdfjs-editor-undo-bar-close-button =
+ .title = Lukk
+pdfjs-editor-undo-bar-close-button-label = Lukk
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Denne modalen lar brukeren lage en signatur for å legge til et PDF-dokument. Brukeren kan redigere navnet (som også fungerer som alt-teksten), og eventuelt lagre signaturen for gjentatt bruk.
+pdfjs-editor-add-signature-dialog-title = Legg til en signatur
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Type
+ .title = Type
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Tegn
+ .title = Tegn
+pdfjs-editor-add-signature-image-button = Bilde
+ .title = Bilde
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Skriv inn signaturen din
+ .placeholder = Skriv inn signaturen din
+pdfjs-editor-add-signature-draw-placeholder = Tegn signaturen din
+pdfjs-editor-add-signature-draw-thickness-range-label = Tykkelse
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Linjetykkelse: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Dra en fil her for å laste opp
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Eller velg bildefiler
+ *[other] Eller velg bildefiler
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Beskrivelse (alternativ tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Beskrivelse (alternativ tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatur
+pdfjs-editor-add-signature-clear-button-label = Fjern signatur
+pdfjs-editor-add-signature-clear-button =
+ .title = Fjern signatur
+pdfjs-editor-add-signature-save-checkbox = Lagre signatur
+pdfjs-editor-add-signature-save-warning-message = Du har nådd grensen på 5 lagrede signaturer. Fjern en for å lagre en ny.
+pdfjs-editor-add-signature-image-upload-error-title = Kunne ikke laste opp bildet
+pdfjs-editor-add-signature-image-upload-error-description = Sjekk nettverkstilkoblingen eller prøv et annet bilde.
+pdfjs-editor-add-signature-image-no-data-error-title = Kan ikke konvertere dette bildet til en signatur
+pdfjs-editor-add-signature-image-no-data-error-description = Prøv å laste opp et annet bilde.
+pdfjs-editor-add-signature-error-close-button = Lukk
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Avbryt
+pdfjs-editor-add-signature-add-button = Legg til
+pdfjs-editor-edit-signature-update-button = Oppdater
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Rediger kommentar
+pdfjs-editor-edit-comment-popup-button =
+ .title = Rediger kommentar
+pdfjs-editor-delete-comment-popup-button-label = Fjern kommentar
+pdfjs-editor-delete-comment-popup-button =
+ .title = Fjern kommentar
+pdfjs-show-comment-button =
+ .title = Vis kommentar
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Rediger kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Oppdater
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Legg til kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Legg til
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Begynn å skrive…
+pdfjs-editor-edit-comment-dialog-cancel-button = Avbryt
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Legg til kommentar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Vis/skjul sidestolpe (dokumentet inneholder miniatyrbilder/disposisjon/vedlegg/lag)
+pdfjs-toggle-views-manager-button1-label = Behandle sider
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidestolpe
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Endre størrelse på sidestolpen
+pdfjs-views-manager-view-selector-button =
+ .title = Visninger
+pdfjs-views-manager-view-selector-button-label = Visninger
+pdfjs-views-manager-pages-title = Sider
+pdfjs-views-manager-outlines-title1 = Dokumentoversikt
+ .title = Dokumentoversikt (dobbeltklikk for å utvide/skjule alle elementer)
+pdfjs-views-manager-attachments-title = Vedlegg
+pdfjs-views-manager-layers-title1 = Lag
+ .title = Lag (dobbeltklikk for å tilbakestille alle lag til standardtilstand)
+pdfjs-views-manager-pages-option-label = Sider
+pdfjs-views-manager-outlines-option-label = Dokumentdisposisjon
+pdfjs-views-manager-attachments-option-label = Vedlegg
+pdfjs-views-manager-layers-option-label = Lag
+pdfjs-views-manager-add-file-button =
+ .title = Legg til fil
+pdfjs-views-manager-add-file-button-label = Legg til fil
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } valgt
+ *[other] { $count } valgt
+ }
+pdfjs-views-manager-pages-status-none-action-label = Velg sider
+pdfjs-views-manager-pages-status-action-button-label = Behandle
+pdfjs-views-manager-pages-status-copy-button-label = Kopier
+pdfjs-views-manager-pages-status-cut-button-label = Klipp ut
+pdfjs-views-manager-pages-status-delete-button-label = Slett
+pdfjs-views-manager-pages-status-export-selected-button-label = Eksporter valgte…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 side klippet ut
+ *[other] { $count } sider klippet ut
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 side kopiert
+ *[other] { $count } sider kopiert
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 side slettet
+ *[other] { $count } sider slettet
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Klargjør filen din …
+pdfjs-views-manager-pages-status-waiting-uploading-label = Laster opp filen …
+pdfjs-views-manager-status-warning-cut-label = Kunne ikke klippe ut. Oppdater siden og prøv på nytt.
+pdfjs-views-manager-status-warning-copy-label = Kunne ikke kopiere. Oppdater siden og prøv på nytt.
+pdfjs-views-manager-status-warning-delete-label = Kunne ikke slette. Oppdater siden og prøv på nytt.
+pdfjs-views-manager-status-warning-save-label = Kunne ikke lagre. Oppdater siden og prøv på nytt.
+pdfjs-views-manager-status-undo-button-label = Angre
+pdfjs-views-manager-status-done-button-label = Ferdig
+pdfjs-views-manager-status-close-button =
+ .title = Lukk
+pdfjs-views-manager-status-close-button-label = Lukk
+pdfjs-views-manager-paste-button-label = Lim inn
+pdfjs-views-manager-paste-button-before =
+ .title = Lim inn før første side
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Lim inn etter side { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NY
+pdfjs-views-manager-waiting-for-file = Laster opp filen …
+pdfjs-toggle-views-manager-button1 =
+ .title = Behandle sider
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Egenskaper for digital signatur
+ .aria-label = Egenskaper for digital signatur
+pdfjs-digital-signature-properties-button-label = Egenskaper for digital signatur
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokumentet ble signert med en gyldig digital signatur
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokumentet er signert, men { $count } digital signatur kunne ikke verifiseres
+ *[other] Dokumentet er signert, men { $count } digitale signaturer kunne ikke verifiseres
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokumentet er signert med { $count } sertifikat som ikke er klarert
+ *[other] Dokumentet er signert med { $count } sertifikater som ikke er klarert
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokumentet er signert med { $count } utløpt sertifikat
+ *[other] Dokumentet er signert med { $count } utløpte sertifikater
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokumentet har { $count } ugyldig digital signatur
+ *[other] Dokumentet har { $count } ugyldige digitale signaturer
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokumentet er signert med { $count } tilbakekalt sertifikat
+ *[other] Dokumentet er signert med { $count } tilbakekalte sertifikater
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signatur bekreftet
+pdfjs-digital-signature-properties-status-invalid = Status: Signatur ugyldig
+pdfjs-digital-signature-properties-status-unknown = Status: Kan ikke bekrefte (støttes ikke)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Sertifikat: Klarert ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Sertifikat: Utilgjengelig
+pdfjs-digital-signature-properties-certificate-untrusted = Sertifikat: Ikke klarert
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Sertifikat: Ukjent utsteder ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Sertifikat: Selvsignert ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Sertifikat: Ikke klarert utsteder ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Sertifikat: Utløpt
+pdfjs-digital-signature-properties-certificate-expired-with-date = Sertifikat: Utløpt ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Sertifikat: Tilbakekalt
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Fjern lagret signatur
+pdfjs-editor-delete-signature-button-label1 = Fjern lagret signatur
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Rediger beskrivelse
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Rediger beskrivelse
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ne-NP/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ne-NP/viewer.ftl
new file mode 100644
index 0000000..38dac7a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ne-NP/viewer.ftl
@@ -0,0 +1,201 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = अघिल्लो पृष्ठ
+pdfjs-previous-button-label = अघिल्लो
+pdfjs-next-button =
+ .title = पछिल्लो पृष्ठ
+pdfjs-next-button-label = पछिल्लो
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = पृष्ठ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } मध्ये
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pagesCount } को { $pageNumber })
+pdfjs-zoom-out-button =
+ .title = जुम घटाउनुहोस्
+pdfjs-zoom-out-button-label = जुम घटाउनुहोस्
+pdfjs-zoom-in-button =
+ .title = जुम बढाउनुहोस्
+pdfjs-zoom-in-button-label = जुम बढाउनुहोस्
+pdfjs-zoom-select =
+ .title = जुम गर्नुहोस्
+pdfjs-presentation-mode-button =
+ .title = प्रस्तुति मोडमा जानुहोस्
+pdfjs-presentation-mode-button-label = प्रस्तुति मोड
+pdfjs-open-file-button =
+ .title = फाइल खोल्नुहोस्
+pdfjs-open-file-button-label = खोल्नुहोस्
+pdfjs-print-button =
+ .title = मुद्रण गर्नुहोस्
+pdfjs-print-button-label = मुद्रण गर्नुहोस्
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = औजारहरू
+pdfjs-tools-button-label = औजारहरू
+pdfjs-first-page-button =
+ .title = पहिलो पृष्ठमा जानुहोस्
+pdfjs-first-page-button-label = पहिलो पृष्ठमा जानुहोस्
+pdfjs-last-page-button =
+ .title = पछिल्लो पृष्ठमा जानुहोस्
+pdfjs-last-page-button-label = पछिल्लो पृष्ठमा जानुहोस्
+pdfjs-page-rotate-cw-button =
+ .title = घडीको दिशामा घुमाउनुहोस्
+pdfjs-page-rotate-cw-button-label = घडीको दिशामा घुमाउनुहोस्
+pdfjs-page-rotate-ccw-button =
+ .title = घडीको विपरित दिशामा घुमाउनुहोस्
+pdfjs-page-rotate-ccw-button-label = घडीको विपरित दिशामा घुमाउनुहोस्
+pdfjs-cursor-text-select-tool-button =
+ .title = पाठ चयन उपकरण सक्षम गर्नुहोस्
+pdfjs-cursor-text-select-tool-button-label = पाठ चयन उपकरण
+pdfjs-cursor-hand-tool-button =
+ .title = हाते उपकरण सक्षम गर्नुहोस्
+pdfjs-cursor-hand-tool-button-label = हाते उपकरण
+pdfjs-scroll-vertical-button =
+ .title = ठाडो स्क्रोलिङ्ग प्रयोग गर्नुहोस्
+pdfjs-scroll-vertical-button-label = ठाडो स्क्र्रोलिङ्ग
+pdfjs-scroll-horizontal-button =
+ .title = तेर्सो स्क्रोलिङ्ग प्रयोग गर्नुहोस्
+pdfjs-scroll-horizontal-button-label = तेर्सो स्क्रोलिङ्ग
+pdfjs-scroll-wrapped-button =
+ .title = लिपि स्क्रोलिङ्ग प्रयोग गर्नुहोस्
+pdfjs-scroll-wrapped-button-label = लिपि स्क्रोलिङ्ग
+pdfjs-spread-none-button =
+ .title = पृष्ठ स्प्रेडमा सामेल हुनुहुन्न
+pdfjs-spread-none-button-label = स्प्रेड छैन
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = कागजात विशेषताहरू...
+pdfjs-document-properties-button-label = कागजात विशेषताहरू...
+pdfjs-document-properties-file-name = फाइल नाम:
+pdfjs-document-properties-file-size = फाइल आकार:
+pdfjs-document-properties-title = शीर्षक:
+pdfjs-document-properties-author = लेखक:
+pdfjs-document-properties-subject = विषयः
+pdfjs-document-properties-keywords = शब्दकुञ्जीः
+pdfjs-document-properties-creation-date = सिर्जना गरिएको मिति:
+pdfjs-document-properties-modification-date = परिमार्जित मिति:
+pdfjs-document-properties-creator = सर्जक:
+pdfjs-document-properties-producer = PDF निर्माता:
+pdfjs-document-properties-version = PDF संस्करण
+pdfjs-document-properties-page-count = पृष्ठ गणना:
+pdfjs-document-properties-page-size = पृष्ठ आकार:
+pdfjs-document-properties-page-size-unit-inches = इन्च
+pdfjs-document-properties-page-size-unit-millimeters = मि.मि.
+pdfjs-document-properties-page-size-orientation-portrait = पोट्रेट
+pdfjs-document-properties-page-size-orientation-landscape = परिदृश्य
+pdfjs-document-properties-page-size-name-letter = अक्षर
+pdfjs-document-properties-page-size-name-legal = कानूनी
+
+##
+
+pdfjs-document-properties-linearized-yes = हो
+pdfjs-document-properties-linearized-no = होइन
+pdfjs-document-properties-close-button = बन्द गर्नुहोस्
+
+## Print
+
+pdfjs-print-progress-message = मुद्रणका लागि कागजात तयारी गरिदै…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = रद्द गर्नुहोस्
+pdfjs-printing-not-supported = चेतावनी: यो ब्राउजरमा मुद्रण पूर्णतया समर्थित छैन।
+pdfjs-printing-not-ready = चेतावनी: PDF मुद्रणका लागि पूर्णतया लोड भएको छैन।
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = टगल साइडबार
+pdfjs-toggle-sidebar-button-label = टगल साइडबार
+pdfjs-document-outline-button =
+ .title = कागजातको रूपरेखा देखाउनुहोस् (सबै वस्तुहरू विस्तार/पतन गर्न डबल-क्लिक गर्नुहोस्)
+pdfjs-document-outline-button-label = दस्तावेजको रूपरेखा
+pdfjs-attachments-button =
+ .title = संलग्नहरू देखाउनुहोस्
+pdfjs-attachments-button-label = संलग्नकहरू
+pdfjs-thumbs-button =
+ .title = थम्बनेलहरू देखाउनुहोस्
+pdfjs-thumbs-button-label = थम्बनेलहरू
+pdfjs-findbar-button =
+ .title = कागजातमा फेला पार्नुहोस्
+pdfjs-findbar-button-label = फेला पार्नुहोस्
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = पृष्ठ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } पृष्ठको थम्बनेल
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = फेला पार्नुहोस्
+ .placeholder = कागजातमा फेला पार्नुहोस्…
+pdfjs-find-previous-button =
+ .title = यस वाक्यांशको अघिल्लो घटना फेला पार्नुहोस्
+pdfjs-find-previous-button-label = अघिल्लो
+pdfjs-find-next-button =
+ .title = यस वाक्यांशको पछिल्लो घटना फेला पार्नुहोस्
+pdfjs-find-next-button-label = अर्को
+pdfjs-find-highlight-checkbox = सबै हाइलाइट गर्ने
+pdfjs-find-match-case-checkbox-label = केस जोडा मिलाउनुहोस्
+pdfjs-find-entire-word-checkbox-label = पुरा शब्दहरु
+pdfjs-find-reached-top = पृष्ठको शिर्षमा पुगीयो, तलबाट जारी गरिएको थियो
+pdfjs-find-reached-bottom = पृष्ठको अन्त्यमा पुगीयो, शिर्षबाट जारी गरिएको थियो
+pdfjs-find-not-found = वाक्यांश फेला परेन
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = पृष्ठ चौडाइ
+pdfjs-page-scale-fit = पृष्ठ ठिक्क मिल्ने
+pdfjs-page-scale-auto = स्वचालित जुम
+pdfjs-page-scale-actual = वास्तविक आकार
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = यो PDF लोड गर्दा एउटा त्रुटि देखापर्यो।
+pdfjs-invalid-file-error = अवैध वा दुषित PDF फाइल।
+pdfjs-missing-file-error = हराईरहेको PDF फाइल।
+pdfjs-unexpected-response-error = अप्रत्याशित सर्भर प्रतिक्रिया।
+pdfjs-rendering-error = पृष्ठ प्रतिपादन गर्दा एउटा त्रुटि देखापर्यो।
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = यस PDF फाइललाई खोल्न गोप्यशब्द प्रविष्ट गर्नुहोस्।
+pdfjs-password-invalid = अवैध गोप्यशब्द। पुनः प्रयास गर्नुहोस्।
+pdfjs-password-ok-button = ठिक छ
+pdfjs-password-cancel-button = रद्द गर्नुहोस्
+pdfjs-web-fonts-disabled = वेब फन्ट असक्षम छन्: एम्बेडेड PDF फन्ट प्रयोग गर्न असमर्थ।
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nl/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nl/viewer.ftl
new file mode 100644
index 0000000..fa04654
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nl/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Vorige pagina
+pdfjs-previous-button-label = Vorige
+pdfjs-next-button =
+ .title = Volgende pagina
+pdfjs-next-button-label = Volgende
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = van { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } van { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Uitzoomen
+pdfjs-zoom-out-button-label = Uitzoomen
+pdfjs-zoom-in-button =
+ .title = Inzoomen
+pdfjs-zoom-in-button-label = Inzoomen
+pdfjs-zoom-select =
+ .title = Zoomen
+pdfjs-presentation-mode-button =
+ .title = Wisselen naar presentatiemodus
+pdfjs-presentation-mode-button-label = Presentatiemodus
+pdfjs-open-file-button =
+ .title = Bestand openen
+pdfjs-open-file-button-label = Openen
+pdfjs-print-button =
+ .title = Afdrukken
+pdfjs-print-button-label = Afdrukken
+pdfjs-save-button =
+ .title = Opslaan
+pdfjs-save-button-label = Opslaan
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Downloaden
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Downloaden
+pdfjs-bookmark-button =
+ .title = Huidige pagina (URL van huidige pagina bekijken)
+pdfjs-bookmark-button-label = Huidige pagina
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Hulpmiddelen
+pdfjs-tools-button-label = Hulpmiddelen
+pdfjs-first-page-button =
+ .title = Naar eerste pagina gaan
+pdfjs-first-page-button-label = Naar eerste pagina gaan
+pdfjs-last-page-button =
+ .title = Naar laatste pagina gaan
+pdfjs-last-page-button-label = Naar laatste pagina gaan
+pdfjs-page-rotate-cw-button =
+ .title = Rechtsom draaien
+pdfjs-page-rotate-cw-button-label = Rechtsom draaien
+pdfjs-page-rotate-ccw-button =
+ .title = Linksom draaien
+pdfjs-page-rotate-ccw-button-label = Linksom draaien
+pdfjs-cursor-text-select-tool-button =
+ .title = Tekstselectiehulpmiddel inschakelen
+pdfjs-cursor-text-select-tool-button-label = Tekstselectiehulpmiddel
+pdfjs-cursor-hand-tool-button =
+ .title = Handhulpmiddel inschakelen
+pdfjs-cursor-hand-tool-button-label = Handhulpmiddel
+pdfjs-scroll-page-button =
+ .title = Paginascrollen gebruiken
+pdfjs-scroll-page-button-label = Paginascrollen
+pdfjs-scroll-vertical-button =
+ .title = Verticaal scrollen gebruiken
+pdfjs-scroll-vertical-button-label = Verticaal scrollen
+pdfjs-scroll-horizontal-button =
+ .title = Horizontaal scrollen gebruiken
+pdfjs-scroll-horizontal-button-label = Horizontaal scrollen
+pdfjs-scroll-wrapped-button =
+ .title = Scrollen met terugloop gebruiken
+pdfjs-scroll-wrapped-button-label = Scrollen met terugloop
+pdfjs-spread-none-button =
+ .title = Dubbele pagina’s niet samenvoegen
+pdfjs-spread-none-button-label = Geen dubbele pagina’s
+pdfjs-spread-odd-button =
+ .title = Dubbele pagina’s samenvoegen vanaf oneven pagina’s
+pdfjs-spread-odd-button-label = Oneven dubbele pagina’s
+pdfjs-spread-even-button =
+ .title = Dubbele pagina’s samenvoegen vanaf even pagina’s
+pdfjs-spread-even-button-label = Even dubbele pagina’s
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Documenteigenschappen…
+pdfjs-document-properties-button-label = Documenteigenschappen…
+pdfjs-document-properties-file-name = Bestandsnaam:
+pdfjs-document-properties-file-size = Bestandsgrootte:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Auteur:
+pdfjs-document-properties-subject = Onderwerp:
+pdfjs-document-properties-keywords = Sleutelwoorden:
+pdfjs-document-properties-creation-date = Aanmaakdatum:
+pdfjs-document-properties-modification-date = Wijzigingsdatum:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Maker:
+pdfjs-document-properties-producer = PDF-producent:
+pdfjs-document-properties-version = PDF-versie:
+pdfjs-document-properties-page-count = Aantal pagina’s:
+pdfjs-document-properties-page-size = Paginagrootte:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = staand
+pdfjs-document-properties-page-size-orientation-landscape = liggend
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Snelle webweergave:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nee
+pdfjs-document-properties-close-button = Sluiten
+pdfjs-digital-signature-properties-view-certificate = Certificaat bekijken
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Reden: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Tijdstempel: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Ondertekening ({ $count })
+ *[other] Ondertekeningen ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Document voorbereiden voor afdrukken…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Annuleren
+pdfjs-printing-not-supported = Waarschuwing: afdrukken wordt niet volledig ondersteund door deze browser.
+pdfjs-printing-not-ready = Waarschuwing: de PDF is niet volledig geladen voor afdrukken.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Zijbalk in-/uitschakelen
+pdfjs-toggle-sidebar-notification-button =
+ .title = Zijbalk in-/uitschakelen (document bevat overzicht/bijlagen/lagen)
+pdfjs-toggle-sidebar-button-label = Zijbalk in-/uitschakelen
+pdfjs-document-outline-button =
+ .title = Documentoverzicht tonen (dubbelklik om alle items uit/samen te vouwen)
+pdfjs-document-outline-button-label = Documentoverzicht
+pdfjs-attachments-button =
+ .title = Bijlagen tonen
+pdfjs-attachments-button-label = Bijlagen
+pdfjs-layers-button =
+ .title = Lagen tonen (dubbelklik om alle lagen naar de standaardstatus terug te zetten)
+pdfjs-layers-button-label = Lagen
+pdfjs-thumbs-button =
+ .title = Miniaturen tonen
+pdfjs-thumbs-button-label = Miniaturen
+pdfjs-current-outline-item-button =
+ .title = Huidig item in inhoudsopgave zoeken
+pdfjs-current-outline-item-button-label = Huidig item in inhoudsopgave
+pdfjs-findbar-button =
+ .title = Zoeken in document
+pdfjs-findbar-button-label = Zoeken
+pdfjs-additional-layers = Aanvullende lagen
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatuur van pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Pagina { $page } selecteren
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Pagina { $page } van { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Zoeken
+ .placeholder = Zoeken in document…
+pdfjs-find-previous-button =
+ .title = De vorige overeenkomst van de tekst zoeken
+pdfjs-find-previous-button-label = Vorige
+pdfjs-find-next-button =
+ .title = De volgende overeenkomst van de tekst zoeken
+pdfjs-find-next-button-label = Volgende
+pdfjs-find-highlight-checkbox = Alles markeren
+pdfjs-find-match-case-checkbox-label = Hoofdlettergevoelig
+pdfjs-find-match-diacritics-checkbox-label = Diakritische tekens gebruiken
+pdfjs-find-entire-word-checkbox-label = Hele woorden
+pdfjs-find-reached-top = Bovenkant van document bereikt, doorgegaan vanaf onderkant
+pdfjs-find-reached-bottom = Onderkant van document bereikt, doorgegaan vanaf bovenkant
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } van { $total } overeenkomst
+ *[other] { $current } van { $total } overeenkomsten
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Meer dan { $limit } overeenkomst
+ *[other] Meer dan { $limit } overeenkomsten
+ }
+pdfjs-find-not-found = Tekst niet gevonden
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Paginabreedte
+pdfjs-page-scale-fit = Hele pagina
+pdfjs-page-scale-auto = Automatisch zoomen
+pdfjs-page-scale-actual = Werkelijke grootte
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Er is een fout opgetreden bij het laden van de PDF.
+pdfjs-invalid-file-error = Ongeldig of beschadigd PDF-bestand.
+pdfjs-missing-file-error = PDF-bestand ontbreekt.
+pdfjs-unexpected-response-error = Onverwacht serverantwoord.
+pdfjs-rendering-error = Er is een fout opgetreden bij het weergeven van de pagina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }-aantekening]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Voer het wachtwoord in om dit PDF-bestand te openen.
+pdfjs-password-invalid = Ongeldig wachtwoord. Probeer het opnieuw.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Annuleren
+pdfjs-web-fonts-disabled = Weblettertypen zijn uitgeschakeld: gebruik van ingebedde PDF-lettertypen is niet mogelijk.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Tekstkleur wijzigen
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Tekenen
+pdfjs-editor-color-picker-ink-input =
+ .title = Tekenkleur wijzigen
+pdfjs-editor-ink-button-label = Tekenen
+pdfjs-editor-stamp-button =
+ .title = Afbeeldingen toevoegen of bewerken
+pdfjs-editor-stamp-button-label = Afbeeldingen toevoegen of bewerken
+pdfjs-editor-highlight-button =
+ .title = Markeren
+pdfjs-editor-highlight-button-label = Markeren
+pdfjs-highlight-floating-button1 =
+ .title = Markeren
+ .aria-label = Markeren
+pdfjs-highlight-floating-button-label = Markeren
+pdfjs-comment-floating-button =
+ .title = Opmerking
+ .aria-label = Opmerking
+pdfjs-comment-floating-button-label = Opmerking
+pdfjs-editor-comment-button =
+ .title = Opmerking
+ .aria-label = Opmerking
+pdfjs-editor-comment-button-label = Opmerking
+pdfjs-editor-signature-button =
+ .title = Handtekening toevoegen
+pdfjs-editor-signature-button-label = Handtekening toevoegen
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Markeringsbewerker
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Tekeningbewerker
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Ondertekening-editor: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Afbeeldingsbewerker
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Tekening verwijderen
+pdfjs-editor-remove-freetext-button =
+ .title = Tekst verwijderen
+pdfjs-editor-remove-stamp-button =
+ .title = Afbeelding verwijderen
+pdfjs-editor-remove-highlight-button =
+ .title = Markering verwijderen
+pdfjs-editor-remove-signature-button =
+ .title = Handtekening verwijderen
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Kleur
+pdfjs-editor-free-text-size-input = Grootte
+pdfjs-editor-ink-color-input = Kleur
+pdfjs-editor-ink-thickness-input = Dikte
+pdfjs-editor-ink-opacity-input = Opaciteit
+pdfjs-editor-stamp-add-image-button =
+ .title = Afbeelding toevoegen
+pdfjs-editor-stamp-add-image-button-label = Afbeelding toevoegen
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Dikte
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Dikte wijzigen bij accentuering van andere items dan tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Ondertekeningsinstellingen en opgeslagen ondertekeningen
+pdfjs-editor-signature-add-signature-button =
+ .title = Nieuwe handtekening toevoegen
+pdfjs-editor-signature-add-signature-button-label = Nieuwe handtekening toevoegen
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Opgeslagen ondertekening: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstbewerker
+ .default-content = Start met typen…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Opmerking
+ *[other] Opmerkingen
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = De zijbalk sluiten
+ .aria-label = De zijbalk sluiten
+pdfjs-editor-comments-sidebar-close-button-label = De zijbalk sluiten
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Ziet u iets noemenswaardigs? Markeer het en laat een opmerking achter.
+pdfjs-editor-comments-sidebar-no-comments-link = Meer info
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternatieve tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternatieve tekst bewerken
+pdfjs-editor-alt-text-dialog-label = Kies een optie
+pdfjs-editor-alt-text-dialog-description = Alternatieve tekst helpt wanneer mensen de afbeelding niet kunnen zien of wanneer deze niet wordt geladen.
+pdfjs-editor-alt-text-add-description-label = Voeg een beschrijving toe
+pdfjs-editor-alt-text-add-description-description = Streef naar 1-2 zinnen die het onderwerp, de omgeving of de acties beschrijven.
+pdfjs-editor-alt-text-mark-decorative-label = Als decoratief markeren
+pdfjs-editor-alt-text-mark-decorative-description = Dit wordt gebruikt voor sierafbeeldingen, zoals randen of watermerken.
+pdfjs-editor-alt-text-cancel-button = Annuleren
+pdfjs-editor-alt-text-save-button = Opslaan
+pdfjs-editor-alt-text-decorative-tooltip = Als decoratief gemarkeerd
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Bijvoorbeeld: ‘Een jonge man gaat aan een tafel zitten om te eten’
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternatieve tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Linkerbovenhoek – formaat wijzigen
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Midden boven – formaat wijzigen
+pdfjs-editor-resizer-top-right =
+ .aria-label = Rechterbovenhoek – formaat wijzigen
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Midden rechts – formaat wijzigen
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Rechterbenedenhoek – formaat wijzigen
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Midden onder – formaat wijzigen
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Linkerbenedenhoek – formaat wijzigen
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Links midden – formaat wijzigen
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Markeringskleur
+pdfjs-editor-colorpicker-button =
+ .title = Kleur wijzigen
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Kleurkeuzes
+pdfjs-editor-colorpicker-yellow =
+ .title = Geel
+pdfjs-editor-colorpicker-green =
+ .title = Groen
+pdfjs-editor-colorpicker-blue =
+ .title = Blauw
+pdfjs-editor-colorpicker-pink =
+ .title = Roze
+pdfjs-editor-colorpicker-red =
+ .title = Rood
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Alles tonen
+pdfjs-editor-highlight-show-all-button =
+ .title = Alles tonen
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alternatieve tekst (afbeeldingsbeschrijving) bewerken
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alternatieve tekst (afbeeldingsbeschrijving) toevoegen
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Schrijf hier uw beschrijving…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Korte beschrijving voor mensen die de afbeelding niet kunnen zien of wanneer de afbeelding niet wordt geladen.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Deze alternatieve tekst is automatisch gemaakt en is mogelijk onjuist.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Meer info
+pdfjs-editor-new-alt-text-create-automatically-button-label = Alternatieve tekst automatisch aanmaken
+pdfjs-editor-new-alt-text-not-now-button = Niet nu
+pdfjs-editor-new-alt-text-error-title = Kan alternatieve tekst niet automatisch aanmaken
+pdfjs-editor-new-alt-text-error-description = Schrijf uw eigen alternatieve tekst of probeer het later nog eens.
+pdfjs-editor-new-alt-text-error-close-button = Sluiten
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = AI-model voor alternatieve tekst downloaden ({ $downloadedSize } van { $totalSize } MB)
+ .aria-valuetext = AI-model voor alternatieve tekst downloaden ({ $downloadedSize } van { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternatieve tekst toegevoegd
+pdfjs-editor-new-alt-text-added-button-label = Alternatieve tekst toegevoegd
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Alternatieve tekst ontbreekt
+pdfjs-editor-new-alt-text-missing-button-label = Alternatieve tekst ontbreekt
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alternatieve tekst beoordelen
+pdfjs-editor-new-alt-text-to-review-button-label = Alternatieve tekst beoordelen
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Automatisch aangemaakt: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Instellingen voor alternatieve tekst van afbeeldingen
+pdfjs-image-alt-text-settings-button-label = Instellingen voor alternatieve tekst van afbeeldingen
+pdfjs-editor-alt-text-settings-dialog-label = Instellingen voor alternatieve tekst van afbeeldingen
+pdfjs-editor-alt-text-settings-automatic-title = Automatische alternatieve tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Alternatieve tekst automatisch aanmaken
+pdfjs-editor-alt-text-settings-create-model-description = Stelt beschrijvingen voor om mensen te helpen die de afbeelding niet kunnen zien of voor wie de afbeelding niet wordt geladen.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = AI-model voor alternatieve tekst ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Wordt lokaal op uw apparaat uitgevoerd, zodat uw gegevens privé blijven. Vereist voor automatische alternatieve tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Verwijderen
+pdfjs-editor-alt-text-settings-download-model-button = Downloaden
+pdfjs-editor-alt-text-settings-downloading-model-button = Downloaden…
+pdfjs-editor-alt-text-settings-editor-title = Alternatieve-tekstbewerker
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Alternatieve-tekstbewerker meteen tonen bij toevoegen van een afbeelding
+pdfjs-editor-alt-text-settings-show-dialog-description = Helpt u ervoor te zorgen dat al uw afbeeldingen alternatieve tekst hebben.
+pdfjs-editor-alt-text-settings-close-button = Sluiten
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Markering toegevoegd
+pdfjs-editor-freetext-added-alert = Tekst toegevoegd
+pdfjs-editor-ink-added-alert = Tekening toegevoegd
+pdfjs-editor-stamp-added-alert = Afbeelding toegevoegd
+pdfjs-editor-signature-added-alert = Handtekening toegevoegd
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Markering verwijderd
+pdfjs-editor-undo-bar-message-freetext = Tekst verwijderd
+pdfjs-editor-undo-bar-message-ink = Tekening verwijderd
+pdfjs-editor-undo-bar-message-stamp = Afbeelding verwijderd
+pdfjs-editor-undo-bar-message-signature = Handtekening verwijderd
+pdfjs-editor-undo-bar-message-comment = Opmerking verwijderd
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotatie verwijderd
+ *[other] { $count } annotaties verwijderd
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Ongedaan maken
+pdfjs-editor-undo-bar-undo-button-label = Ongedaan maken
+pdfjs-editor-undo-bar-close-button =
+ .title = Sluiten
+pdfjs-editor-undo-bar-close-button-label = Sluiten
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Met deze modal kan de gebruiker een handtekening maken om aan een PDF-document toe te voegen. De gebruiker kan de naam (die ook als alternatieve tekst dient) bewerken en optioneel de ondertekening opslaan voor herhaald gebruik.
+pdfjs-editor-add-signature-dialog-title = Een handtekening toevoegen
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Typen
+ .title = Typen
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Tekenen
+ .title = Tekenen
+pdfjs-editor-add-signature-image-button = Afbeelding
+ .title = Afbeelding
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Uw handtekening typen
+ .placeholder = Uw handtekening typen
+pdfjs-editor-add-signature-draw-placeholder = Uw handtekening tekenen
+pdfjs-editor-add-signature-draw-thickness-range-label = Dikte
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Tekendikte: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Sleep bestand hierheen om te uploaden
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Of kies afbeeldingsbestanden
+ *[other] Of kies afbeeldingsbestanden
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Beschrijving (alternatieve tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Beschrijving (alternatieve tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Handtekening
+pdfjs-editor-add-signature-clear-button-label = Handtekening wissen
+pdfjs-editor-add-signature-clear-button =
+ .title = Handtekening wissen
+pdfjs-editor-add-signature-save-checkbox = Handtekening opslaan
+pdfjs-editor-add-signature-save-warning-message = U hebt de limiet van 5 opgeslagen handtekeningen bereikt. Verwijder er een om een andere op te slaan.
+pdfjs-editor-add-signature-image-upload-error-title = Kan afbeelding niet uploaden
+pdfjs-editor-add-signature-image-upload-error-description = Controleer uw netwerkverbinding of probeer een andere afbeelding.
+pdfjs-editor-add-signature-image-no-data-error-title = Kan deze afbeelding niet naar een handtekening converteren
+pdfjs-editor-add-signature-image-no-data-error-description = Probeer een andere afbeelding te uploaden.
+pdfjs-editor-add-signature-error-close-button = Sluiten
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Annuleren
+pdfjs-editor-add-signature-add-button = Toevoegen
+pdfjs-editor-edit-signature-update-button = Bijwerken
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Opmerking bewerken
+pdfjs-editor-edit-comment-popup-button =
+ .title = Opmerking bewerken
+pdfjs-editor-delete-comment-popup-button-label = Opmerking verwijderen
+pdfjs-editor-delete-comment-popup-button =
+ .title = Opmerking verwijderen
+pdfjs-show-comment-button =
+ .title = Opmerking tonen
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Opmerking bewerken
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Bijwerken
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Opmerking toevoegen
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Toevoegen
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Begin met typen…
+pdfjs-editor-edit-comment-dialog-cancel-button = Annuleren
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Opmerking toevoegen
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Zijbalk in-/uitschakelen (document bevat miniaturen/overzicht/bijlagen/lagen)
+pdfjs-toggle-views-manager-button1-label = Pagina’s beheren
+pdfjs-views-manager-sidebar =
+ .aria-label = Zijbalk
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Groottewijziging zijbalk
+pdfjs-views-manager-view-selector-button =
+ .title = Weergaven
+pdfjs-views-manager-view-selector-button-label = Weergaven
+pdfjs-views-manager-pages-title = Pagina’s
+pdfjs-views-manager-outlines-title1 = Documentoverzicht
+ .title = Documentoverzicht (dubbelklik om alle items uit te vouwen/samen te vouwen)
+pdfjs-views-manager-attachments-title = Bijlagen
+pdfjs-views-manager-layers-title1 = Lagen
+ .title = Lagen (dubbelklik om alle lagen naar de standaardstatus terug te zetten)
+pdfjs-views-manager-pages-option-label = Pagina’s
+pdfjs-views-manager-outlines-option-label = Documentoverzicht
+pdfjs-views-manager-attachments-option-label = Bijlagen
+pdfjs-views-manager-layers-option-label = Lagen
+pdfjs-views-manager-add-file-button =
+ .title = Bestand toevoegen
+pdfjs-views-manager-add-file-button-label = Bestand toevoegen
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } geselecteerd
+ *[other] { $count } geselecteerd
+ }
+pdfjs-views-manager-pages-status-none-action-label = Pagina’s selecteren
+pdfjs-views-manager-pages-status-action-button-label = Beheren
+pdfjs-views-manager-pages-status-copy-button-label = Kopiëren
+pdfjs-views-manager-pages-status-cut-button-label = Knippen
+pdfjs-views-manager-pages-status-delete-button-label = Verwijderen
+pdfjs-views-manager-pages-status-export-selected-button-label = Geselecteerde exporteren…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 pagina geknipt
+ *[other] { $count } pagina’s geknipt
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 pagina gekopieerd
+ *[other] { $count } pagina’s gekopieerd
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 pagina verwijderd
+ *[other] { $count } pagina’s verwijderd
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Uw bestand voorbereiden…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Bestand uploaden…
+pdfjs-views-manager-status-warning-cut-label = Kan niet knippen. Vernieuw de pagina en probeer het opnieuw.
+pdfjs-views-manager-status-warning-copy-label = Kan niet kopiëren. Vernieuw de pagina en probeer het opnieuw.
+pdfjs-views-manager-status-warning-delete-label = Kan niet verwijderen. Vernieuw de pagina en probeer het opnieuw.
+pdfjs-views-manager-status-warning-save-label = Kan niet opslaan. Vernieuw de pagina en probeer het opnieuw.
+pdfjs-views-manager-status-undo-button-label = Ongedaan maken
+pdfjs-views-manager-status-done-button-label = Gereed
+pdfjs-views-manager-status-close-button =
+ .title = Sluiten
+pdfjs-views-manager-status-close-button-label = Sluiten
+pdfjs-views-manager-paste-button-label = Plakken
+pdfjs-views-manager-paste-button-before =
+ .title = Plakken voor de eerste pagina
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Plakken na pagina { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NIEUW
+pdfjs-views-manager-waiting-for-file = Bestand uploaden…
+pdfjs-toggle-views-manager-button1 =
+ .title = Pagina’s beheren
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Eigenschappen digitale handtekening
+ .aria-label = Eigenschappen digitale handtekening
+pdfjs-digital-signature-properties-button-label = Eigenschappen digitale handtekening
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Document is ondertekend met een geldige digitale handtekening
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Document ondertekend, maar { $count } digitale handtekening kon niet worden geverifieerd
+ *[other] Document ondertekend, maar { $count } digitale handtekeningen konden niet worden geverifieerd
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Document ondertekend met { $count } certificaat dat niet wordt vertrouwd
+ *[other] Document ondertekend met { $count } certificaten die niet worden vertrouwd
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Document ondertekend met { $count } verlopen certificaat
+ *[other] Document ondertekend met { $count } verlopen certificaten
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Document heeft { $count } ongeldige digitale handtekening
+ *[other] Document heeft { $count } ongeldige digitale handtekeningen
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Document ondertekend met { $count } ingetrokken certificaat
+ *[other] Document ondertekend met { $count } ingetrokken certificaten
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: handtekening geverifieerd
+pdfjs-digital-signature-properties-status-invalid = Status: handtekening ongeldig
+pdfjs-digital-signature-properties-status-unknown = Status: kan niet worden geverifieerd (niet ondersteund)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificaat: vertrouwd ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificaat: niet beschikbaar
+pdfjs-digital-signature-properties-certificate-untrusted = Certificaat: niet vertrouwd
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificaat: onbekende uitgever ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificaat: zelfondertekend ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificaat: niet-vertrouwde uitgever ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificaat: verlopen
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificaat: verlopen ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificaat: ingetrokken
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Opgeslagen ondertekening verwijderen
+pdfjs-editor-delete-signature-button-label1 = Opgeslagen ondertekening verwijderen
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Beschrijving bewerken
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Beschrijving bewerken
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nn-NO/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nn-NO/viewer.ftl
new file mode 100644
index 0000000..9e7358a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/nn-NO/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Føregåande side
+pdfjs-previous-button-label = Føregåande
+pdfjs-next-button =
+ .title = Neste side
+pdfjs-next-button-label = Neste
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Side
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = av { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } av { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom ut
+pdfjs-zoom-out-button-label = Zoom ut
+pdfjs-zoom-in-button =
+ .title = Zoom inn
+pdfjs-zoom-in-button-label = Zoom inn
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Byt til presentasjonsmodus
+pdfjs-presentation-mode-button-label = Presentasjonsmodus
+pdfjs-open-file-button =
+ .title = Opne fil
+pdfjs-open-file-button-label = Opne
+pdfjs-print-button =
+ .title = Skriv ut
+pdfjs-print-button-label = Skriv ut
+pdfjs-save-button =
+ .title = Lagre
+pdfjs-save-button-label = Lagre
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Last ned
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Last ned
+pdfjs-bookmark-button =
+ .title = Gjeldande side (sjå URL frå gjeldande side)
+pdfjs-bookmark-button-label = Gjeldande side
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Verktøy
+pdfjs-tools-button-label = Verktøy
+pdfjs-first-page-button =
+ .title = Gå til første side
+pdfjs-first-page-button-label = Gå til første side
+pdfjs-last-page-button =
+ .title = Gå til siste side
+pdfjs-last-page-button-label = Gå til siste side
+pdfjs-page-rotate-cw-button =
+ .title = Roter med klokka
+pdfjs-page-rotate-cw-button-label = Roter med klokka
+pdfjs-page-rotate-ccw-button =
+ .title = Roter mot klokka
+pdfjs-page-rotate-ccw-button-label = Roter mot klokka
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktiver tekstmarkeringsverktøy
+pdfjs-cursor-text-select-tool-button-label = Tekstmarkeringsverktøy
+pdfjs-cursor-hand-tool-button =
+ .title = Aktiver handverktøy
+pdfjs-cursor-hand-tool-button-label = Handverktøy
+pdfjs-scroll-page-button =
+ .title = Bruk siderulling
+pdfjs-scroll-page-button-label = Siderulling
+pdfjs-scroll-vertical-button =
+ .title = Bruk vertikal rulling
+pdfjs-scroll-vertical-button-label = Vertikal rulling
+pdfjs-scroll-horizontal-button =
+ .title = Bruk horisontal rulling
+pdfjs-scroll-horizontal-button-label = Horisontal rulling
+pdfjs-scroll-wrapped-button =
+ .title = Bruk fleirsiderulling
+pdfjs-scroll-wrapped-button-label = Fleirsiderulling
+pdfjs-spread-none-button =
+ .title = Vis enkeltsider
+pdfjs-spread-none-button-label = Enkeltside
+pdfjs-spread-odd-button =
+ .title = Vis oppslag med ulike sidenummer til venstre
+pdfjs-spread-odd-button-label = Oppslag med framside
+pdfjs-spread-even-button =
+ .title = Vis oppslag med like sidenummmer til venstre
+pdfjs-spread-even-button-label = Oppslag utan framside
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumenteigenskapar…
+pdfjs-document-properties-button-label = Dokumenteigenskapar…
+pdfjs-document-properties-file-name = Filnamn:
+pdfjs-document-properties-file-size = Filstorleik:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } byte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } byte)
+pdfjs-document-properties-title = Tittel:
+pdfjs-document-properties-author = Forfattar:
+pdfjs-document-properties-subject = Emne:
+pdfjs-document-properties-keywords = Stikkord:
+pdfjs-document-properties-creation-date = Dato oppretta:
+pdfjs-document-properties-modification-date = Dato endra:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Oppretta av:
+pdfjs-document-properties-producer = PDF-verktøy:
+pdfjs-document-properties-version = PDF-versjon:
+pdfjs-document-properties-page-count = Sidetal:
+pdfjs-document-properties-page-size = Sidestørrelse:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = ståande (portrait)
+pdfjs-document-properties-page-size-orientation-landscape = liggande (landscape)
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Brev
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Rask nettvising:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nei
+pdfjs-document-properties-close-button = Lat att
+pdfjs-digital-signature-properties-view-certificate = Vis sertifikat
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Grunn: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Tidsstempel: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Undersignatur ({ $count })
+ *[other] Undersignaturar ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Førebur dokumentet for utskrift…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Avbryt
+pdfjs-printing-not-supported = Åtvaring: Utskrift er ikkje fullstendig støtta av denne nettlesaren.
+pdfjs-printing-not-ready = Åtvaring: PDF ikkje fullstendig innlasta for utskrift.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Slå av/på sidestolpe
+pdfjs-toggle-sidebar-notification-button =
+ .title = Vis/gøym sidestolpe (dokumentet inneheld oversikt/vedlegg/lag)
+pdfjs-toggle-sidebar-button-label = Slå av/på sidestolpe
+pdfjs-document-outline-button =
+ .title = Vis dokumentdisposisjonen (dobbelklikk for å utvide/gøyme alle elementa)
+pdfjs-document-outline-button-label = Dokumentdisposisjon
+pdfjs-attachments-button =
+ .title = Vis vedlegg
+pdfjs-attachments-button-label = Vedlegg
+pdfjs-layers-button =
+ .title = Vis lag (dobbeltklikk for å tilbakestille alle lag til standardtilstand)
+pdfjs-layers-button-label = Lag
+pdfjs-thumbs-button =
+ .title = Vis miniatyrbilde
+pdfjs-thumbs-button-label = Miniatyrbilde
+pdfjs-current-outline-item-button =
+ .title = Finn gjeldande disposisjonselement
+pdfjs-current-outline-item-button-label = Gjeldande disposisjonselement
+pdfjs-findbar-button =
+ .title = Finn i dokumentet
+pdfjs-findbar-button-label = Finn
+pdfjs-additional-layers = Ytterlegare lag
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatyrbilde av side { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Vel side { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Side { $page } av { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Søk
+ .placeholder = Søk i dokument…
+pdfjs-find-previous-button =
+ .title = Finn førre førekomst av frasen
+pdfjs-find-previous-button-label = Førre
+pdfjs-find-next-button =
+ .title = Finn neste førekomst av frasen
+pdfjs-find-next-button-label = Neste
+pdfjs-find-highlight-checkbox = Uthev alle
+pdfjs-find-match-case-checkbox-label = Skil store/små bokstavar
+pdfjs-find-match-diacritics-checkbox-label = Samsvar diakritiske teikn
+pdfjs-find-entire-word-checkbox-label = Heile ord
+pdfjs-find-reached-top = Nådde toppen av dokumentet, fortset frå botnen
+pdfjs-find-reached-bottom = Nådde botnen av dokumentet, fortset frå toppen
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } av { $total } treff
+ *[other] { $current } av { $total } treff
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Meir enn { $limit } treff
+ *[other] Meir enn { $limit } treff
+ }
+pdfjs-find-not-found = Fann ikkje teksten
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sidebreidde
+pdfjs-page-scale-fit = Tilpass til sida
+pdfjs-page-scale-auto = Automatisk skalering
+pdfjs-page-scale-actual = Verkeleg storleik
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Side { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ein feil oppstod ved lasting av PDF.
+pdfjs-invalid-file-error = Ugyldig eller korrupt PDF-fil.
+pdfjs-missing-file-error = Manglande PDF-fil.
+pdfjs-unexpected-response-error = Uventa tenarrespons.
+pdfjs-rendering-error = Ein feil oppstod under vising av sida.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } annotasjon]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Skriv inn passordet for å opne denne PDF-fila.
+pdfjs-password-invalid = Ugyldig passord. Prøv på nytt.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Avbryt
+pdfjs-web-fonts-disabled = Web-skrifter er slått av: Kan ikkje bruke innbundne PDF-skrifter.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Endre tekstfarge
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Teikne
+pdfjs-editor-color-picker-ink-input =
+ .title = Endre teiknefarge
+pdfjs-editor-ink-button-label = Teikne
+pdfjs-editor-stamp-button =
+ .title = Legg til eller rediger bilde
+pdfjs-editor-stamp-button-label = Legg til eller rediger bilde
+pdfjs-editor-highlight-button =
+ .title = Markere
+pdfjs-editor-highlight-button-label = Markere
+pdfjs-highlight-floating-button1 =
+ .title = Markere
+ .aria-label = Markere
+pdfjs-highlight-floating-button-label = Markere
+pdfjs-comment-floating-button =
+ .title = Kommenter
+ .aria-label = Kommenter
+pdfjs-comment-floating-button-label = Kommenter
+pdfjs-editor-comment-button =
+ .title = Kommentar
+ .aria-label = Kommentar
+pdfjs-editor-comment-button-label = Kommentar
+pdfjs-editor-signature-button =
+ .title = Legg til signatur
+pdfjs-editor-signature-button-label = Legg til signatur
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Markeringsredigerar
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Redigering av teikningar
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signatur-redigerar: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Bildredigerar
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Fjern teikninga
+pdfjs-editor-remove-freetext-button =
+ .title = Fjern tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Fjern bildet
+pdfjs-editor-remove-highlight-button =
+ .title = Fjern utheving
+pdfjs-editor-remove-signature-button =
+ .title = Fjern signatur
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Farge
+pdfjs-editor-free-text-size-input = Storleik
+pdfjs-editor-ink-color-input = Farge
+pdfjs-editor-ink-thickness-input = Tjukn
+pdfjs-editor-ink-opacity-input = Ugjennomskinleg
+pdfjs-editor-stamp-add-image-button =
+ .title = Legg til bilde
+pdfjs-editor-stamp-add-image-button-label = Legg til bilde
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tjukn
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Endre tjukn når du markerer andre element enn tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Signaturkontroll og lagra signaturar
+pdfjs-editor-signature-add-signature-button =
+ .title = Legg til ny signatur
+pdfjs-editor-signature-add-signature-button-label = Legg til ny signatur
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Lagra signatur: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Tekstredigering
+ .default-content = Begynn å skrive…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Kommentarar
+ *[other] Kommentararar
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Lat att sidestolpen
+ .aria-label = Lat att sidestolpen
+pdfjs-editor-comments-sidebar-close-button-label = Lat att sidestolpen
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Ser du noko som er verdt å merke seg? Marker det og legg igjen ein kommentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Les meir
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alt-tekst
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Rediger alt-tekst tekst
+pdfjs-editor-alt-text-dialog-label = Vel eit alternativ
+pdfjs-editor-alt-text-dialog-description = Alt-tekst (alternativ tekst) hjelper når folk ikkje kan sjå bildet eller når det ikkje vert lasta inn.
+pdfjs-editor-alt-text-add-description-label = Legg til ei skildring
+pdfjs-editor-alt-text-add-description-description = Gå etter 1-2 setninger som skildrar emnet, settinga eller handlingane.
+pdfjs-editor-alt-text-mark-decorative-label = Merk som dekorativt
+pdfjs-editor-alt-text-mark-decorative-description = Dette vert brukt til dekorative bilde, som kantlinjer eller vassmerke.
+pdfjs-editor-alt-text-cancel-button = Avbryt
+pdfjs-editor-alt-text-save-button = Lagre
+pdfjs-editor-alt-text-decorative-tooltip = Merkt som dekorativ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Til dømes, «Ein ung mann set seg ved eit bord for å ete eit måltid»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alt-tekst
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Øvste venstre hjørne – endre størrelse
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Øvst i midten — endre størrelse
+pdfjs-editor-resizer-top-right =
+ .aria-label = Øvste høgre hjørne – endre størrelse
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Midt til høgre – endre størrelse
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Nedste høgre hjørne – endre størrelse
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Nedst i midten — endre størrelse
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Nedste venstre hjørne – endre størrelse
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Midt til venstre — endre størrelse
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Uthevingsfarge
+pdfjs-editor-colorpicker-button =
+ .title = Endre farge
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Fargeval
+pdfjs-editor-colorpicker-yellow =
+ .title = Gul
+pdfjs-editor-colorpicker-green =
+ .title = Grøn
+pdfjs-editor-colorpicker-blue =
+ .title = Blå
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Raud
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Vis alle
+pdfjs-editor-highlight-show-all-button =
+ .title = Vis alle
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Rediger alternativ tekst (bildeskildring)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Legg til alternativ tekst (bildeskildring)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skriv skildringa di her…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kort skildring for personar som ikkje kan sjå bildet, eller når bildet ikkje lastar inn.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Denne alternative teksten vart oppretta automatisk, og kan vere unøyaktig.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Les meir
+pdfjs-editor-new-alt-text-create-automatically-button-label = Opprett alternativ tekt automatisk
+pdfjs-editor-new-alt-text-not-now-button = Ikkje no
+pdfjs-editor-new-alt-text-error-title = Klarte ikkje å opprette alternativ tekst automatisk
+pdfjs-editor-new-alt-text-error-description = Skriv din eigen alternative tekst eller prøv igjen seinare.
+pdfjs-editor-new-alt-text-error-close-button = Lat att
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Lastar ned KI-modell med alternativ tekst ({ $downloadedSize } av { $totalSize } MB)
+ .aria-valuetext = Lastar ned KI-modell med alternativ tekst ({ $downloadedSize } av { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativ tekst lagt til
+pdfjs-editor-new-alt-text-added-button-label = Alternativ tekst lagt til
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Manglande alternativ tekst
+pdfjs-editor-new-alt-text-missing-button-label = Manglande alternativ tekst
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Vurder alternativ tekst
+pdfjs-editor-new-alt-text-to-review-button-label = Vurder alternativ tekst
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Oppretta automatisk: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Alternative tekst-innstillingar for bilde
+pdfjs-image-alt-text-settings-button-label = Alternative tekst-innstillingar for bilde
+pdfjs-editor-alt-text-settings-dialog-label = Alternative tekst-innstillingar for bilde
+pdfjs-editor-alt-text-settings-automatic-title = Automatisk alternativ tekst
+pdfjs-editor-alt-text-settings-create-model-button-label = Opprett alternativ tekt automatisk
+pdfjs-editor-alt-text-settings-create-model-description = Føreslår skildringar for å hjelpe folk som ikkje kan sjå bildet eller når bildet ikkje blir lasta inn.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = KI-modell for alternativ tekst ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Køyrer lokalt på eininga di slik at dataa dine blir verande private. Påkravd for automatisk alternativ tekst.
+pdfjs-editor-alt-text-settings-delete-model-button = Slett
+pdfjs-editor-alt-text-settings-download-model-button = Last ned
+pdfjs-editor-alt-text-settings-downloading-model-button = Lastar ned…
+pdfjs-editor-alt-text-settings-editor-title = Alternativ tekst-redigerar
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Vis alternativ tekst-redigerar direkte når du legg til eit bilde
+pdfjs-editor-alt-text-settings-show-dialog-description = Hjelper deg med å sørgje for at alle bilda dine har alternativ tekst.
+pdfjs-editor-alt-text-settings-close-button = Lat att
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Utheving lagt til
+pdfjs-editor-freetext-added-alert = Tekst lagt til
+pdfjs-editor-ink-added-alert = Teikning lagt til
+pdfjs-editor-stamp-added-alert = Bilde lagt til
+pdfjs-editor-signature-added-alert = Signatur lagt til
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Markering fjerna
+pdfjs-editor-undo-bar-message-freetext = Tekst fjerna
+pdfjs-editor-undo-bar-message-ink = Teikning fjerna
+pdfjs-editor-undo-bar-message-stamp = Bilde fjerna
+pdfjs-editor-undo-bar-message-signature = Signatur fjerna
+pdfjs-editor-undo-bar-message-comment = Kommentar fjerna
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } kommentar fjerna
+ *[other] { $count } kommentarar fjerna
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Angre
+pdfjs-editor-undo-bar-undo-button-label = Angre
+pdfjs-editor-undo-bar-close-button =
+ .title = Lat att
+pdfjs-editor-undo-bar-close-button-label = Lat att
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Denne modalen lèt brukaren lage ein signatur for å leggje til eit PDF-dokument. Brukaren kan redigere namnet (som også fungerer som alt-teksten), og eventuelt lagre signaturen for gjenteken bruk.
+pdfjs-editor-add-signature-dialog-title = Legg til ein signatur
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Type
+ .title = Type
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Teikne
+ .title = Teikne
+pdfjs-editor-add-signature-image-button = Bilde
+ .title = Bilde
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Skriv inn signaturen din
+ .placeholder = Skriv inn signaturen din
+pdfjs-editor-add-signature-draw-placeholder = Teikn signaturen din
+pdfjs-editor-add-signature-draw-thickness-range-label = Tjukn
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Linjetjukn: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Drag ei fil hit for å laste opp
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Eller vel bildefiler
+ *[other] Eller vel bildefiler
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Skildring (alternativ tekst)
+pdfjs-editor-add-signature-description-input =
+ .title = Skildring (alternativ tekst)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatur
+pdfjs-editor-add-signature-clear-button-label = Fjern signatur
+pdfjs-editor-add-signature-clear-button =
+ .title = Fjern signatur
+pdfjs-editor-add-signature-save-checkbox = Lagre signatur
+pdfjs-editor-add-signature-save-warning-message = Du har nådd grensa på 5 lagra signaturar. Fjern ein for å lagre ein ny.
+pdfjs-editor-add-signature-image-upload-error-title = Klarte ikkje å oppdatere bilde
+pdfjs-editor-add-signature-image-upload-error-description = Sjekk nettverkstilkoplinga eller prøv eit annet bilde.
+pdfjs-editor-add-signature-image-no-data-error-title = Kan ikkje konvertere dette bildet til ein signatur
+pdfjs-editor-add-signature-image-no-data-error-description = Prøv å laste opp eit anna bilde.
+pdfjs-editor-add-signature-error-close-button = Lat att
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Avbryt
+pdfjs-editor-add-signature-add-button = Legg til
+pdfjs-editor-edit-signature-update-button = Oppdater
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Rediger kommentar
+pdfjs-editor-edit-comment-popup-button =
+ .title = Rediger kommentar
+pdfjs-editor-delete-comment-popup-button-label = Fjern kommentar
+pdfjs-editor-delete-comment-popup-button =
+ .title = Fjern kommentar
+pdfjs-show-comment-button =
+ .title = Vis kommentar
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Rediger kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Oppdater
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Legg til kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Legg til
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Byrje å skrive…
+pdfjs-editor-edit-comment-dialog-cancel-button = Avbryt
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Legg til kommentar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Vis/skjul sidestolpe (dokumentet inneheld miniatyrbilde/disposisjon/vedlegg/lag)
+pdfjs-toggle-views-manager-button1-label = Handsam sider
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidestolpe
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Endre storleiken på sidestolpen
+pdfjs-views-manager-view-selector-button =
+ .title = Vis
+pdfjs-views-manager-view-selector-button-label = Visningar
+pdfjs-views-manager-pages-title = Sider
+pdfjs-views-manager-outlines-title1 = Dokumentoversikt
+ .title = Dokumentoversikt (dobbelklikk for å utvide/skjule alle element)
+pdfjs-views-manager-attachments-title = Vedlegg
+pdfjs-views-manager-layers-title1 = Lag
+ .title = Lag (dobbelklikk for å tilbakestille alle lag til standardtilstand)
+pdfjs-views-manager-pages-option-label = Sider
+pdfjs-views-manager-outlines-option-label = Dokumentdisposisjon
+pdfjs-views-manager-attachments-option-label = Vedlegg
+pdfjs-views-manager-layers-option-label = Lag
+pdfjs-views-manager-add-file-button =
+ .title = Legg til fil
+pdfjs-views-manager-add-file-button-label = Legg til fil
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } vald
+ *[other] { $count } valde
+ }
+pdfjs-views-manager-pages-status-none-action-label = Vel sider
+pdfjs-views-manager-pages-status-action-button-label = Handsam
+pdfjs-views-manager-pages-status-copy-button-label = Kopier
+pdfjs-views-manager-pages-status-cut-button-label = Klipp ut
+pdfjs-views-manager-pages-status-delete-button-label = Slett
+pdfjs-views-manager-pages-status-export-selected-button-label = Eksporter valde…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 side klipt ut
+ *[other] { $count } sider klipte ut
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 side kopiert
+ *[other] { $count } sider kopierte
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 side sletta
+ *[other] { $count } sider sletta
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Klargjer fila di…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Lastar opp fila…
+pdfjs-views-manager-status-warning-cut-label = Klarte ikkje å klippe ut. Oppdater sida og prøv på nytt.
+pdfjs-views-manager-status-warning-copy-label = Klarte ikkje å kopiere. Oppdater sida og prøv på nytt.
+pdfjs-views-manager-status-warning-delete-label = Klarte ikkje å slette. Oppdater sida og prøv på nytt.
+pdfjs-views-manager-status-warning-save-label = Klarte ikkje å lagre. Oppdater sida og prøv på nytt.
+pdfjs-views-manager-status-undo-button-label = Angre
+pdfjs-views-manager-status-done-button-label = Ferdig
+pdfjs-views-manager-status-close-button =
+ .title = Lat att
+pdfjs-views-manager-status-close-button-label = Lat att
+pdfjs-views-manager-paste-button-label = Lim inn
+pdfjs-views-manager-paste-button-before =
+ .title = Lim inn før første side
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Lim inn etter side { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NY
+pdfjs-views-manager-waiting-for-file = Lastar opp fila…
+pdfjs-toggle-views-manager-button1 =
+ .title = Handsam sider
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Eigenskapar for digital signatur
+ .aria-label = Eigenskapar for digital signatur
+pdfjs-digital-signature-properties-button-label = Eigenskapar for digital signatur
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokumentet vart signert med ei gyldig digital signatur
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokumentet er signert, men { $count } digital signatur kunne ikkje verifiserast
+ *[other] Dokumentet er signert, men { $count } digitale signaturar kunne ikkje verifiserast
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokumentet er signert med { $count } sertifikat som ikkje er klarert
+ *[other] Dokumentet er signert med { $count } sertifikat som ikkje er klarerte
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokumentet er signert med { $count } utgåttt sertifikat
+ *[other] Dokumentet er signert med { $count } utgåtte sertifikat
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokumentet har { $count } ugyldig digital signatur
+ *[other] Dokumentet har { $count } ugyldige digitale signaturar
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokumentet er signert med { $count } tilbakekalt sertifikat
+ *[other] Dokumentet er signert med { $count } tilbakekalte sertifikat
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signatur stadfesta
+pdfjs-digital-signature-properties-status-invalid = Status: Signatur ugyldig
+pdfjs-digital-signature-properties-status-unknown = Status: Kan ikkje stadfeste (blir ikkje støtta)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Sertifikat: Klarert ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Sertifikat: Utilgjengeleg
+pdfjs-digital-signature-properties-certificate-untrusted = Sertifikat: Ikkje klarert
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Sertifikat: Ukjent utferdar ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Sertifikat: Sjølvsignert ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Sertifikat: Ikkje klarert utferdar ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Sertifikat: Utgått
+pdfjs-digital-signature-properties-certificate-expired-with-date = Sertifikat: Utgått ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Sertifikat: Tilbakekalla
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Fjern lagra signatur
+pdfjs-editor-delete-signature-button-label1 = Fjern lagra signatur
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Rediger skildring
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Rediger skildring
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/oc/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/oc/viewer.ftl
new file mode 100644
index 0000000..a10a398
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/oc/viewer.ftl
@@ -0,0 +1,396 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagina precedenta
+pdfjs-previous-button-label = Precedent
+pdfjs-next-button =
+ .title = Pagina seguenta
+pdfjs-next-button-label = Seguent
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = sus { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom arrièr
+pdfjs-zoom-out-button-label = Zoom arrièr
+pdfjs-zoom-in-button =
+ .title = Zoom avant
+pdfjs-zoom-in-button-label = Zoom avant
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Bascular en mòde presentacion
+pdfjs-presentation-mode-button-label = Mòde Presentacion
+pdfjs-open-file-button =
+ .title = Dobrir lo fichièr
+pdfjs-open-file-button-label = Dobrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Enregistrar
+pdfjs-save-button-label = Enregistrar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Telecargar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Telecargar
+pdfjs-bookmark-button =
+ .title = Pagina actuala (mostrar l’adreça de la pagina actuala)
+pdfjs-bookmark-button-label = Pagina actuala
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Aisinas
+pdfjs-tools-button-label = Aisinas
+pdfjs-first-page-button =
+ .title = Anar a la primièra pagina
+pdfjs-first-page-button-label = Anar a la primièra pagina
+pdfjs-last-page-button =
+ .title = Anar a la darrièra pagina
+pdfjs-last-page-button-label = Anar a la darrièra pagina
+pdfjs-page-rotate-cw-button =
+ .title = Rotacion orària
+pdfjs-page-rotate-cw-button-label = Rotacion orària
+pdfjs-page-rotate-ccw-button =
+ .title = Rotacion antiorària
+pdfjs-page-rotate-ccw-button-label = Rotacion antiorària
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar l'aisina de seleccion de tèxte
+pdfjs-cursor-text-select-tool-button-label = Aisina de seleccion de tèxte
+pdfjs-cursor-hand-tool-button =
+ .title = Activar l’aisina man
+pdfjs-cursor-hand-tool-button-label = Aisina man
+pdfjs-scroll-page-button =
+ .title = Activar lo defilament per pagina
+pdfjs-scroll-page-button-label = Defilament per pagina
+pdfjs-scroll-vertical-button =
+ .title = Utilizar lo defilament vertical
+pdfjs-scroll-vertical-button-label = Defilament vertical
+pdfjs-scroll-horizontal-button =
+ .title = Utilizar lo defilament orizontal
+pdfjs-scroll-horizontal-button-label = Defilament orizontal
+pdfjs-scroll-wrapped-button =
+ .title = Activar lo defilament continú
+pdfjs-scroll-wrapped-button-label = Defilament continú
+pdfjs-spread-none-button =
+ .title = Agropar pas las paginas doas a doas
+pdfjs-spread-none-button-label = Una sola pagina
+pdfjs-spread-odd-button =
+ .title = Mostrar doas paginas en començant per las paginas imparas a esquèrra
+pdfjs-spread-odd-button-label = Dobla pagina, impara a drecha
+pdfjs-spread-even-button =
+ .title = Mostrar doas paginas en començant per las paginas paras a esquèrra
+pdfjs-spread-even-button-label = Dobla pagina, para a drecha
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Proprietats del document…
+pdfjs-document-properties-button-label = Proprietats del document…
+pdfjs-document-properties-file-name = Nom del fichièr :
+pdfjs-document-properties-file-size = Talha del fichièr :
+pdfjs-document-properties-title = Títol :
+pdfjs-document-properties-author = Autor :
+pdfjs-document-properties-subject = Subjècte :
+pdfjs-document-properties-keywords = Mots claus :
+pdfjs-document-properties-creation-date = Data de creacion :
+pdfjs-document-properties-modification-date = Data de modificacion :
+pdfjs-document-properties-creator = Creator :
+pdfjs-document-properties-producer = Aisina de conversion PDF :
+pdfjs-document-properties-version = Version PDF :
+pdfjs-document-properties-page-count = Nombre de paginas :
+pdfjs-document-properties-page-size = Talha de la pagina :
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = retrach
+pdfjs-document-properties-page-size-orientation-landscape = païsatge
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letra
+pdfjs-document-properties-page-size-name-legal = Document juridic
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista web rapida :
+pdfjs-document-properties-linearized-yes = Òc
+pdfjs-document-properties-linearized-no = Non
+pdfjs-document-properties-close-button = Tampar
+
+## Print
+
+pdfjs-print-progress-message = Preparacion del document per l’impression…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Anullar
+pdfjs-printing-not-supported = Atencion : l'impression es pas complètament gerida per aqueste navegador.
+pdfjs-printing-not-ready = Atencion : lo PDF es pas entièrament cargat per lo poder imprimir.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Afichar/amagar lo panèl lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Afichar/amagar lo panèl lateral (lo document conten esquèmas/pèças juntas/calques)
+pdfjs-toggle-sidebar-button-label = Afichar/amagar lo panèl lateral
+pdfjs-document-outline-button =
+ .title = Mostrar los esquèmas del document (dobleclicar per espandre/reduire totes los elements)
+pdfjs-document-outline-button-label = Marcapaginas del document
+pdfjs-attachments-button =
+ .title = Visualizar las pèças juntas
+pdfjs-attachments-button-label = Pèças juntas
+pdfjs-layers-button =
+ .title = Afichar los calques (doble-clicar per reïnicializar totes los calques a l’estat per defaut)
+pdfjs-layers-button-label = Calques
+pdfjs-thumbs-button =
+ .title = Afichar las vinhetas
+pdfjs-thumbs-button-label = Vinhetas
+pdfjs-current-outline-item-button =
+ .title = Trobar l’element de plan actual
+pdfjs-current-outline-item-button-label = Element de plan actual
+pdfjs-findbar-button =
+ .title = Cercar dins lo document
+pdfjs-findbar-button-label = Recercar
+pdfjs-additional-layers = Calques suplementaris
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Vinheta de la pagina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Recercar
+ .placeholder = Cercar dins lo document…
+pdfjs-find-previous-button =
+ .title = Tròba l'ocurréncia precedenta de la frasa
+pdfjs-find-previous-button-label = Precedent
+pdfjs-find-next-button =
+ .title = Tròba l'ocurréncia venenta de la frasa
+pdfjs-find-next-button-label = Seguent
+pdfjs-find-highlight-checkbox = Suslinhar tot
+pdfjs-find-match-case-checkbox-label = Respectar la cassa
+pdfjs-find-match-diacritics-checkbox-label = Respectar los diacritics
+pdfjs-find-entire-word-checkbox-label = Mots entièrs
+pdfjs-find-reached-top = Naut de la pagina atenh, perseguida del bas
+pdfjs-find-reached-bottom = Bas de la pagina atench, perseguida al començament
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] Ocurréncia { $current } de { $total }
+ *[other] Ocurréncia { $current } de { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mai de { $limit } ocurréncia
+ *[other] Mai de { $limit } ocurréncias
+ }
+pdfjs-find-not-found = Frasa pas trobada
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Largor plena
+pdfjs-page-scale-fit = Pagina entièra
+pdfjs-page-scale-auto = Zoom automatic
+pdfjs-page-scale-actual = Talha vertadièra
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Una error s'es producha pendent lo cargament del fichièr PDF.
+pdfjs-invalid-file-error = Fichièr PDF invalid o corromput.
+pdfjs-missing-file-error = Fichièr PDF mancant.
+pdfjs-unexpected-response-error = Responsa de servidor imprevista.
+pdfjs-rendering-error = Una error s'es producha pendent l'afichatge de la pagina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotacion { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Picatz lo senhal per dobrir aqueste fichièr PDF.
+pdfjs-password-invalid = Senhal incorrècte. Tornatz ensajar.
+pdfjs-password-ok-button = D'acòrdi
+pdfjs-password-cancel-button = Anullar
+pdfjs-web-fonts-disabled = Las polissas web son desactivadas : impossible d'utilizar las polissas integradas al PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tèxte
+pdfjs-editor-free-text-button-label = Tèxte
+pdfjs-editor-ink-button =
+ .title = Dessenhar
+pdfjs-editor-ink-button-label = Dessenhar
+pdfjs-editor-stamp-button =
+ .title = Apondre o modificar d’imatges
+pdfjs-editor-stamp-button-label = Apondre o modificar d’imatges
+pdfjs-editor-highlight-button =
+ .title = Subrelinhar
+pdfjs-editor-highlight-button-label = Subrelinhar
+pdfjs-highlight-floating-button1 =
+ .title = Subrelinhar
+ .aria-label = Subrelinhar
+pdfjs-highlight-floating-button-label = Subrelinhar
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Levar lo dessenh
+pdfjs-editor-remove-freetext-button =
+ .title = Suprimir lo tèxte
+pdfjs-editor-remove-stamp-button =
+ .title = Suprimir l’imatge
+pdfjs-editor-remove-highlight-button =
+ .title = Levar lo suslinhatge
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Color
+pdfjs-editor-free-text-size-input = Talha
+pdfjs-editor-ink-color-input = Color
+pdfjs-editor-ink-thickness-input = Espessor
+pdfjs-editor-ink-opacity-input = Opacitat
+pdfjs-editor-stamp-add-image-button =
+ .title = Apondre imatge
+pdfjs-editor-stamp-add-image-button-label = Apondre imatge
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Espessor
+pdfjs-editor-signature-add-signature-button =
+ .title = Apondre una signatura novèla
+pdfjs-editor-signature-add-signature-button-label = Apondre una signatura novèla
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de tèxte
+ .default-content = Començatz de picar…
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Tèxt alternatiu
+pdfjs-editor-alt-text-dialog-label = Causir una opcion
+pdfjs-editor-alt-text-add-description-label = Apondre una descripcion
+pdfjs-editor-alt-text-cancel-button = Anullar
+pdfjs-editor-alt-text-save-button = Enregistrar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Color de suslinhatge
+pdfjs-editor-colorpicker-button =
+ .title = Cambiar de color
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Causida de colors
+pdfjs-editor-colorpicker-yellow =
+ .title = Jaune
+pdfjs-editor-colorpicker-green =
+ .title = Verd
+pdfjs-editor-colorpicker-blue =
+ .title = Blau
+pdfjs-editor-colorpicker-pink =
+ .title = Ròse
+pdfjs-editor-colorpicker-red =
+ .title = Roge
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = O afichar tot
+pdfjs-editor-highlight-show-all-button =
+ .title = O afichar tot
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+pdfjs-editor-new-alt-text-not-now-button = Pas ara
+pdfjs-editor-new-alt-text-error-close-button = Tampar
+
+## Image alt-text settings
+
+pdfjs-editor-alt-text-settings-automatic-title = Tèxte alternatiu automatic
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear un tèxte alternatiu automaticament
+pdfjs-editor-alt-text-settings-delete-model-button = Suprimir
+pdfjs-editor-alt-text-settings-download-model-button = Telecargar
+pdfjs-editor-alt-text-settings-downloading-model-button = Telecargament…
+pdfjs-editor-alt-text-settings-editor-title = Editor de tèxte alternatiu
+pdfjs-editor-alt-text-settings-close-button = Tampar
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-freetext = Tèxte suprimit
+pdfjs-editor-undo-bar-message-ink = Dessenh suprimit
+pdfjs-editor-undo-bar-message-stamp = Imatge suprimit
+pdfjs-editor-undo-bar-undo-button =
+ .title = Anullar
+pdfjs-editor-undo-bar-undo-button-label = Anullar
+pdfjs-editor-undo-bar-close-button =
+ .title = Tampar
+pdfjs-editor-undo-bar-close-button-label = Tampar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NÒU
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pa-IN/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pa-IN/viewer.ftl
new file mode 100644
index 0000000..beb4a4e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pa-IN/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = ਪਿਛਲਾ ਸਫ਼ਾ
+pdfjs-previous-button-label = ਪਿੱਛੇ
+pdfjs-next-button =
+ .title = ਅਗਲਾ ਸਫ਼ਾ
+pdfjs-next-button-label = ਅੱਗੇ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ਸਫ਼ਾ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } ਵਿੱਚੋਂ
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = { $pagesCount }) ਵਿੱਚੋਂ ({ $pageNumber }
+pdfjs-zoom-out-button =
+ .title = ਜ਼ੂਮ ਆਉਟ
+pdfjs-zoom-out-button-label = ਜ਼ੂਮ ਆਉਟ
+pdfjs-zoom-in-button =
+ .title = ਜ਼ੂਮ ਇਨ
+pdfjs-zoom-in-button-label = ਜ਼ੂਮ ਇਨ
+pdfjs-zoom-select =
+ .title = ਜ਼ੂਨ
+pdfjs-presentation-mode-button =
+ .title = ਪਰਿਜੈਂਟੇਸ਼ਨ ਮੋਡ ਵਿੱਚ ਜਾਓ
+pdfjs-presentation-mode-button-label = ਪਰਿਜੈਂਟੇਸ਼ਨ ਮੋਡ
+pdfjs-open-file-button =
+ .title = ਫਾਈਲ ਨੂੰ ਖੋਲ੍ਹੋ
+pdfjs-open-file-button-label = ਖੋਲ੍ਹੋ
+pdfjs-print-button =
+ .title = ਪਰਿੰਟ
+pdfjs-print-button-label = ਪਰਿੰਟ
+pdfjs-save-button =
+ .title = ਸੰਭਾਲੋ
+pdfjs-save-button-label = ਸੰਭਾਲੋ
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ਡਾਊਨਲੋਡ
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ਡਾਊਨਲੋਡ
+pdfjs-bookmark-button =
+ .title = ਮੌਜੂਦਾ ਸਫ਼਼ਾ (ਮੌਜੂਦਾ ਸਫ਼ੇ ਤੋਂ URL ਵੇਖੋ)
+pdfjs-bookmark-button-label = ਮੌਜੂਦਾ ਸਫ਼਼ਾ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ਟੂਲ
+pdfjs-tools-button-label = ਟੂਲ
+pdfjs-first-page-button =
+ .title = ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+pdfjs-first-page-button-label = ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+pdfjs-last-page-button =
+ .title = ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+pdfjs-last-page-button-label = ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+pdfjs-page-rotate-cw-button =
+ .title = ਸੱਜੇ ਦਾਅ ਘੁੰਮਾਓ
+pdfjs-page-rotate-cw-button-label = ਸੱਜੇ ਦਾਅ ਘੁੰਮਾਓ
+pdfjs-page-rotate-ccw-button =
+ .title = ਖੱਬੇ ਦਾਅ ਘੁੰਮਾਓ
+pdfjs-page-rotate-ccw-button-label = ਖੱਬੇ ਦਾਅ ਘੁੰਮਾਓ
+pdfjs-cursor-text-select-tool-button =
+ .title = ਲਿਖਤ ਚੋਣ ਟੂਲ ਸਮਰੱਥ ਕਰੋ
+pdfjs-cursor-text-select-tool-button-label = ਲਿਖਤ ਚੋਣ ਟੂਲ
+pdfjs-cursor-hand-tool-button =
+ .title = ਹੱਥ ਟੂਲ ਸਮਰੱਥ ਕਰੋ
+pdfjs-cursor-hand-tool-button-label = ਹੱਥ ਟੂਲ
+pdfjs-scroll-page-button =
+ .title = ਸਫ਼ਾ ਖਿਸਕਾਉਣ ਨੂੰ ਵਰਤੋਂ
+pdfjs-scroll-page-button-label = ਸਫ਼ਾ ਖਿਸਕਾਉਣਾ
+pdfjs-scroll-vertical-button =
+ .title = ਖੜ੍ਹਵੇਂ ਸਕਰਾਉਣ ਨੂੰ ਵਰਤੋਂ
+pdfjs-scroll-vertical-button-label = ਖੜ੍ਹਵਾਂ ਸਰਕਾਉਣਾ
+pdfjs-scroll-horizontal-button =
+ .title = ਲੇਟਵੇਂ ਸਰਕਾਉਣ ਨੂੰ ਵਰਤੋਂ
+pdfjs-scroll-horizontal-button-label = ਲੇਟਵਾਂ ਸਰਕਾਉਣਾ
+pdfjs-scroll-wrapped-button =
+ .title = ਸਮੇਟੇ ਸਰਕਾਉਣ ਨੂੰ ਵਰਤੋਂ
+pdfjs-scroll-wrapped-button-label = ਸਮੇਟਿਆ ਸਰਕਾਉਣਾ
+pdfjs-spread-none-button =
+ .title = ਸਫ਼ਾ ਫੈਲਾਅ ਵਿੱਚ ਸ਼ਾਮਲ ਨਾ ਹੋਵੋ
+pdfjs-spread-none-button-label = ਕੋਈ ਫੈਲਾਅ ਨਹੀਂ
+pdfjs-spread-odd-button =
+ .title = ਟਾਂਕ ਅੰਕ ਵਾਲੇ ਸਫ਼ਿਆਂ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਸਫਿਆਂ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ
+pdfjs-spread-odd-button-label = ਟਾਂਕ ਫੈਲਾਅ
+pdfjs-spread-even-button =
+ .title = ਜਿਸਤ ਅੰਕ ਵਾਲੇ ਸਫ਼ਿਆਂ ਨਾਲ ਸ਼ੁਰੂ ਹੋਣ ਵਾਲੇ ਸਫਿਆਂ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ
+pdfjs-spread-even-button-label = ਜਿਸਤ ਫੈਲਾਅ
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = …ਦਸਤਾਵੇਜ਼ ਦੀ ਵਿਸ਼ੇਸ਼ਤਾ
+pdfjs-document-properties-button-label = …ਦਸਤਾਵੇਜ਼ ਦੀ ਵਿਸ਼ੇਸ਼ਤਾ
+pdfjs-document-properties-file-name = ਫਾਈਲ ਦਾ ਨਾਂ:
+pdfjs-document-properties-file-size = ਫਾਈਲ ਦਾ ਆਕਾਰ:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } ਬਾਈਟ)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } ਬਾਈਟ)
+pdfjs-document-properties-title = ਟਾਈਟਲ:
+pdfjs-document-properties-author = ਲੇਖਕ:
+pdfjs-document-properties-subject = ਵਿਸ਼ਾ:
+pdfjs-document-properties-keywords = ਸ਼ਬਦ:
+pdfjs-document-properties-creation-date = ਬਣਾਉਣ ਦੀ ਮਿਤੀ:
+pdfjs-document-properties-modification-date = ਸੋਧ ਦੀ ਮਿਤੀ:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = ਨਿਰਮਾਤਾ:
+pdfjs-document-properties-producer = PDF ਪ੍ਰੋਡਿਊਸਰ:
+pdfjs-document-properties-version = PDF ਵਰਜਨ:
+pdfjs-document-properties-page-count = ਸਫ਼ੇ ਦੀ ਗਿਣਤੀ:
+pdfjs-document-properties-page-size = ਸਫ਼ਾ ਆਕਾਰ:
+pdfjs-document-properties-page-size-unit-inches = ਇੰਚ
+pdfjs-document-properties-page-size-unit-millimeters = ਮਿਮੀ
+pdfjs-document-properties-page-size-orientation-portrait = ਪੋਰਟਰੇਟ
+pdfjs-document-properties-page-size-orientation-landscape = ਲੈਂਡਸਕੇਪ
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = ਲੈਟਰ
+pdfjs-document-properties-page-size-name-legal = ਕਨੂੰਨੀ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = ਤੇਜ਼ ਵੈੱਬ ਝਲਕ:
+pdfjs-document-properties-linearized-yes = ਹਾਂ
+pdfjs-document-properties-linearized-no = ਨਹੀਂ
+pdfjs-document-properties-close-button = ਬੰਦ ਕਰੋ
+pdfjs-digital-signature-properties-view-certificate = ਸਰਟੀਫਿਕੇਟ ਨੂੰ ਵੇਖੋ
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = ਕਾਰਨ: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = ਸਮਾਂ: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] ਅਧੀਨ-ਦਸਤਖ਼ਤ ({ $count })
+ *[other] ਅਧੀਨ-ਦਸਤਖ਼ਤ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = …ਪਰਿੰਟ ਕਰਨ ਲਈ ਦਸਤਾਵੇਜ਼ ਨੂੰ ਤਿਆਰ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ਰੱਦ ਕਰੋ
+pdfjs-printing-not-supported = ਸਾਵਧਾਨ: ਇਹ ਬਰਾਊਜ਼ਰ ਪਰਿੰਟ ਕਰਨ ਲਈ ਪੂਰੀ ਤਰ੍ਹਾਂ ਸਹਾਇਕ ਨਹੀਂ ਹੈ।
+pdfjs-printing-not-ready = ਸਾਵਧਾਨ: PDF ਨੂੰ ਪਰਿੰਟ ਕਰਨ ਲਈ ਪੂਰੀ ਤਰ੍ਹਾਂ ਲੋਡ ਨਹੀਂ ਹੈ।
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = ਬਾਹੀ ਬਦਲੋ
+pdfjs-toggle-sidebar-notification-button =
+ .title = ਬਾਹੀ ਨੂੰ ਬਦਲੋ (ਦਸਤਾਵੇਜ਼ ਖਾਕਾ/ਅਟੈਚਮੈਂਟ/ਪਰਤਾਂ ਰੱਖਦਾ ਹੈ)
+pdfjs-toggle-sidebar-button-label = ਬਾਹੀ ਬਦਲੋ
+pdfjs-document-outline-button =
+ .title = ਦਸਤਾਵੇਜ਼ ਖਾਕਾ ਦਿਖਾਓ (ਸਾਰੀਆਂ ਆਈਟਮਾਂ ਨੂੰ ਫੈਲਾਉਣ/ਸਮੇਟਣ ਲਈ ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰੋ)
+pdfjs-document-outline-button-label = ਦਸਤਾਵੇਜ਼ ਖਾਕਾ
+pdfjs-attachments-button =
+ .title = ਅਟੈਚਮੈਂਟ ਵੇਖਾਓ
+pdfjs-attachments-button-label = ਅਟੈਚਮੈਂਟਾਂ
+pdfjs-layers-button =
+ .title = ਪਰਤਾਂ ਵੇਖਾਓ (ਸਾਰੀਆਂ ਪਰਤਾਂ ਨੂੰ ਮੂਲ ਹਾਲਤ ਉੱਤੇ ਮੁੜ-ਸੈੱਟ ਕਰਨ ਲਈ ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰੋ)
+pdfjs-layers-button-label = ਪਰਤਾਂ
+pdfjs-thumbs-button =
+ .title = ਥੰਮਨੇਲ ਨੂੰ ਵੇਖਾਓ
+pdfjs-thumbs-button-label = ਥੰਮਨੇਲ
+pdfjs-current-outline-item-button =
+ .title = ਮੌੌਜੂਦਾ ਖਾਕਾ ਚੀਜ਼ ਲੱਭੋ
+pdfjs-current-outline-item-button-label = ਮੌਜੂਦਾ ਖਾਕਾ ਚੀਜ਼
+pdfjs-findbar-button =
+ .title = ਦਸਤਾਵੇਜ਼ ਵਿੱਚ ਲੱਭੋ
+pdfjs-findbar-button-label = ਲੱਭੋ
+pdfjs-additional-layers = ਵਾਧੂ ਪਰਤਾਂ
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = ਸਫ਼ਾ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } ਸਫ਼ੇ ਦਾ ਥੰਮਨੇਲ
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = { $page } ਸਫ਼ੇ ਨੂੰ ਚੁਣੋ
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = { $total } ਵਿੱਚੋਂ { $page } ਸਫ਼ਾ
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ਲੱਭੋ
+ .placeholder = …ਦਸਤਾਵੇਜ਼ 'ਚ ਲੱਭੋ
+pdfjs-find-previous-button =
+ .title = ਵਾਕ ਦੀ ਪਿਛਲੀ ਮੌਜੂਦਗੀ ਲੱਭੋ
+pdfjs-find-previous-button-label = ਪਿੱਛੇ
+pdfjs-find-next-button =
+ .title = ਵਾਕ ਦੀ ਅਗਲੀ ਮੌਜੂਦਗੀ ਲੱਭੋ
+pdfjs-find-next-button-label = ਅੱਗੇ
+pdfjs-find-highlight-checkbox = ਸਭ ਉਭਾਰੋ
+pdfjs-find-match-case-checkbox-label = ਅੱਖਰ ਆਕਾਰ ਨੂੰ ਮਿਲਾਉ
+pdfjs-find-match-diacritics-checkbox-label = ਭੇਦਸੂਚਕ ਮੇਲ
+pdfjs-find-entire-word-checkbox-label = ਪੂਰੇ ਸ਼ਬਦ
+pdfjs-find-reached-top = ਦਸਤਾਵੇਜ਼ ਦੇ ਉੱਤੇ ਆ ਗਏ ਹਾਂ, ਥੱਲੇ ਤੋਂ ਜਾਰੀ ਰੱਖਿਆ ਹੈ
+pdfjs-find-reached-bottom = ਦਸਤਾਵੇਜ਼ ਦੇ ਅੰਤ ਉੱਤੇ ਆ ਗਏ ਹਾਂ, ਉੱਤੇ ਤੋਂ ਜਾਰੀ ਰੱਖਿਆ ਹੈ
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $total } ਵਿੱਚੋਂ { $current } ਮੇਲ
+ *[other] { $total } ਵਿੱਚੋਂ { $current } ਮੇਲ
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] { $limit } ਤੋਂ ਵੱਧ ਮੇਲ
+ *[other] { $limit } ਤੋਂ ਵੱਧ ਮੇਲ
+ }
+pdfjs-find-not-found = ਵਾਕ ਨਹੀਂ ਲੱਭਿਆ
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ਸਫ਼ੇ ਦੀ ਚੌੜਾਈ
+pdfjs-page-scale-fit = ਸਫ਼ਾ ਫਿੱਟ
+pdfjs-page-scale-auto = ਆਟੋਮੈਟਿਕ ਜ਼ੂਮ ਕਰੋ
+pdfjs-page-scale-actual = ਆਟੋਮੈਟਿਕ ਆਕਾਰ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = ਸਫ਼ਾ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF ਲੋਡ ਕਰਨ ਦੇ ਦੌਰਾਨ ਗਲਤੀ ਆਈ ਹੈ।
+pdfjs-invalid-file-error = ਗਲਤ ਜਾਂ ਨਿਕਾਰਾ PDF ਫਾਈਲ ਹੈ।
+pdfjs-missing-file-error = ਨਾ-ਮੌਜੂਦ PDF ਫਾਈਲ।
+pdfjs-unexpected-response-error = ਅਣਜਾਣ ਸਰਵਰ ਜਵਾਬ।
+pdfjs-rendering-error = ਸਫ਼ਾ ਰੈਡਰ ਕਰਨ ਦੇ ਦੌਰਾਨ ਗਲਤੀ ਆਈ ਹੈ।
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } ਵਿਆਖਿਆ]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = ਇਹ PDF ਫਾਈਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਪਾਸਵਰਡ ਦਿਉ।
+pdfjs-password-invalid = ਗਲਤ ਪਾਸਵਰਡ। ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।
+pdfjs-password-ok-button = ਠੀਕ ਹੈ
+pdfjs-password-cancel-button = ਰੱਦ ਕਰੋ
+pdfjs-web-fonts-disabled = ਵੈਬ ਫੋਂਟ ਬੰਦ ਹਨ: ਇੰਬੈਡ PDF ਫੋਂਟ ਨੂੰ ਵਰਤਣ ਲਈ ਅਸਮਰੱਥ ਹੈ।
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = ਲਿਖਤ
+pdfjs-editor-color-picker-free-text-input =
+ .title = ਲਿਖਤ ਦੇ ਰੰਗ ਨੂੰ ਬਦਲੋ
+pdfjs-editor-free-text-button-label = ਲਿਖਤ
+pdfjs-editor-ink-button =
+ .title = ਵਾਹੋ
+pdfjs-editor-color-picker-ink-input =
+ .title = ਡਰਾਇੰਗ ਰੰਗ ਨੂੰ ਬਦਲੋ
+pdfjs-editor-ink-button-label = ਵਾਹੋ
+pdfjs-editor-stamp-button =
+ .title = ਚਿੱਤਰ ਜੋੜੋ ਜਾਂ ਸੋਧੋ
+pdfjs-editor-stamp-button-label = ਚਿੱਤਰ ਜੋੜੋ ਜਾਂ ਸੋਧੋ
+pdfjs-editor-highlight-button =
+ .title = ਹਾਈਲਾਈਟ
+pdfjs-editor-highlight-button-label = ਹਾਈਲਾਈਟ
+pdfjs-highlight-floating-button1 =
+ .title = ਹਾਈਲਾਈਟ
+ .aria-label = ਹਾਈਲਾਈਟ
+pdfjs-highlight-floating-button-label = ਹਾਈਲਾਈਟ
+pdfjs-comment-floating-button =
+ .title = ਟਿੱਪਣੀ
+ .aria-label = ਟਿੱਪਣੀ
+pdfjs-comment-floating-button-label = ਟਿੱਪਣੀ
+pdfjs-editor-comment-button =
+ .title = ਟਿੱਪਣੀ
+ .aria-label = ਟਿੱਪਣੀ
+pdfjs-editor-comment-button-label = ਟਿੱਪਣੀ
+pdfjs-editor-signature-button =
+ .title = ਦਸਤਖ਼ਤ ਜੋੜੋ
+pdfjs-editor-signature-button-label = ਦਸਤਖ਼ਤ ਜੋੜੋ
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = ਹਾਈਲਾਈਟ ਸੰਪਾਦਕ
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = ਡਰਾਇੰਗ ਸੰਪਾਦਕ
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = ਦਸਤਖ਼ਤ ਐਡੀਟਰ: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = ਚਿੱਤਰ ਸੰਪਾਦਕ
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = ਡਰਾਇੰਗ ਨੂੰ ਹਟਾਓ
+pdfjs-editor-remove-freetext-button =
+ .title = ਲਿਖਤ ਨੂੰ ਹਟਾਓ
+pdfjs-editor-remove-stamp-button =
+ .title = ਚਿੱਤਰ ਨੂੰ ਹਟਾਓ
+pdfjs-editor-remove-highlight-button =
+ .title = ਹਾਈਲਾਈਟ ਨੂੰ ਹਟਾਓ
+pdfjs-editor-remove-signature-button =
+ .title = ਦਸਤਖ਼ਤ ਨੂੰ ਹਟਾਓ
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = ਰੰਗ
+pdfjs-editor-free-text-size-input = ਆਕਾਰ
+pdfjs-editor-ink-color-input = ਰੰਗ
+pdfjs-editor-ink-thickness-input = ਮੋਟਾਈ
+pdfjs-editor-ink-opacity-input = ਧੁੰਦਲਾਪਨ
+pdfjs-editor-stamp-add-image-button =
+ .title = ਚਿੱਤਰ ਜੋੜੋ
+pdfjs-editor-stamp-add-image-button-label = ਚਿੱਤਰ ਜੋੜੋ
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = ਮੋਟਾਈ
+pdfjs-editor-free-highlight-thickness-title =
+ .title = ਚੀਜ਼ਾਂ ਨੂੰ ਹੋਰ ਲਿਖਤਾਂ ਤੋਂ ਉਘਾੜਨ ਸਮੇਂ ਮੋਟਾਈ ਨੂੰ ਬਦਲੋ
+pdfjs-editor-add-signature-container =
+ .aria-label = ਦਸਤਖ਼ਤ ਕੰਟਰੋਲ ਅਤੇ ਸੰਭਾਲੇ ਹੋਏ ਦਸਤਖ਼ਤ
+pdfjs-editor-signature-add-signature-button =
+ .title = ਨਵੇਂ ਦਸਤਖ਼ਤ ਨੂੰ ਜੋੜੋ
+pdfjs-editor-signature-add-signature-button-label = ਨਵੇਂ ਦਸਤਖ਼ਤ ਨੂੰ ਜੋੜੋ
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = ਸੰਭਾਲੇ ਦਸਤਖ਼ਤ: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = ਲਿਖਤ ਐਡੀਟਰ
+ .default-content = …ਲਿਖਣਾ ਸ਼ੁਰੂ ਕਰੋ
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] ਟਿੱਪਣੀ
+ *[other] ਟਿੱਪਣੀਆਂ
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = ਬਾਹੀ ਨੂੰ ਬੰਦ ਕਰੋ
+ .aria-label = ਬਾਹੀ ਨੂੰ ਬੰਦ ਕਰੋ
+pdfjs-editor-comments-sidebar-close-button-label = ਬਾਹੀ ਨੂੰ ਬੰਦ ਕਰੋ
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = ਕੀ ਕੁਝ ਧਿਆਨ ਦੇਣ ਯੋਗ ਵੇਖਿਆ ਹੈ? ਇਸ ਨੂੰ ਉਘਾੜੋ ਅਤੇ ਟਿੱਪਣੀ ਦਿਓ।
+pdfjs-editor-comments-sidebar-no-comments-link = ਹੋਰ ਜਾਣੋ
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = ਬਦਲਵੀਂ ਲਿਖਤ
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = ਬਦਲਵੀ ਲਿਖਤ ਨੂੰ ਸੋਧੋ
+pdfjs-editor-alt-text-dialog-label = ਚੋਣ ਕਰੋ
+pdfjs-editor-alt-text-dialog-description = ਚਿੱਤਰ ਨਾ ਦਿੱਸਣ ਜਾਂ ਲੋਡ ਨਾ ਹੋਣ ਦੀ ਹਾਲਤ ਵਿੱਚ Alt ਲਿਖਤ (ਬਦਲਵੀਂ ਲਿਖਤ) ਲੋਕਾਂ ਲਈ ਮਦਦਗਾਰ ਹੁੰਦੀ ਹੈ।
+pdfjs-editor-alt-text-add-description-label = ਵਰਣਨ ਜੋੜੋ
+pdfjs-editor-alt-text-add-description-description = 1-2 ਵਾਕ ਰੱਖੋ, ਜੋ ਕਿ ਵਿਸ਼ੇ, ਸੈਟਿੰਗ ਜਾਂ ਕਾਰਵਾਈਆਂ ਬਾਰੇ ਦਰਸਾਉਂਦੇ ਹੋਣ।
+pdfjs-editor-alt-text-mark-decorative-label = ਸਜਾਵਟ ਵਜੋਂ ਨਿਸ਼ਾਨ ਲਾਇਆ
+pdfjs-editor-alt-text-mark-decorative-description = ਇਸ ਨੂੰ ਸਜਾਵਟੀ ਚਿੱਤਰਾਂ ਲਈ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ ਜਿਵੇਂ ਕਿ ਹਾਸ਼ੀਆ ਜਾਂ ਵਾਟਰਮਾਰਕ ਆਦਿ।
+pdfjs-editor-alt-text-cancel-button = ਰੱਦ ਕਰੋ
+pdfjs-editor-alt-text-save-button = ਸੰਭਾਲੋ
+pdfjs-editor-alt-text-decorative-tooltip = ਸਜਾਵਟ ਵਜੋਂ ਨਿਸ਼ਾਨ ਲਾਓ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = ਮਿਸਾਲ ਵਜੋਂ, “ਗੱਭਰੂ ਭੋਜਨ ਲੈ ਕੇ ਮੇਜ਼ ਉੱਤੇ ਬੈਠਾ ਹੈ”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = ਬਦਲਵੀਂ ਲਿਖਤ
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = ਉੱਤੇ ਖੱਬਾ ਕੋਨਾ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-top-middle =
+ .aria-label = ਉੱਤੇ ਮੱਧ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-top-right =
+ .aria-label = ਉੱਤੇ ਸੱਜਾ ਕੋਨਾ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-middle-right =
+ .aria-label = ਮੱਧ ਸੱਜਾ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = ਹੇਠਾਂ ਸੱਜਾ ਕੋਨਾ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = ਹੇਠਾਂ ਮੱਧ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = ਹੇਠਾਂ ਖੱਬਾ ਕੋਨਾ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+pdfjs-editor-resizer-middle-left =
+ .aria-label = ਮੱਧ ਖੱਬਾ — ਮੁੜ-ਆਕਾਰ ਕਰੋ
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = ਹਾਈਟਲਾਈਟ ਦਾ ਰੰਗ
+pdfjs-editor-colorpicker-button =
+ .title = ਰੰਗ ਨੂੰ ਬਦਲੋ
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = ਰੰਗ ਚੋਣਾਂ
+pdfjs-editor-colorpicker-yellow =
+ .title = ਪੀਲਾ
+pdfjs-editor-colorpicker-green =
+ .title = ਹਰਾ
+pdfjs-editor-colorpicker-blue =
+ .title = ਨੀਲਾ
+pdfjs-editor-colorpicker-pink =
+ .title = ਗੁਲਾਬੀ
+pdfjs-editor-colorpicker-red =
+ .title = ਲਾਲ
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = ਸਭ ਵੇਖੋ
+pdfjs-editor-highlight-show-all-button =
+ .title = ਸਭ ਵੇਖੋ
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = ਬਦਲਵੀਂ ਲਿਖਤ (ਚਿੱਤਰ ਦਾ ਵਰਣਨ) ਨੂੰ ਸੋਧੋ
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = ਬਦਲਵੀਂ ਲਿਖਤ (ਚਿੱਤਰ ਦਾ ਵਰਣਨ) ਨੂੰ ਜੋੜੋ
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = …ਆਪਣਾ ਵਰਣਨਾ ਇੱਥੇ ਲਿਖੋ
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = ਲੋਕ, ਜੋ ਕਿ ਚਿੱਤਰ ਨਹੀਂ ਵੇਖ ਸਕਦੇ ਜਾਂ ਜਦ ਵੀ ਚਿੱਤਰਾਂ ਨੂੰ ਲੋਡ ਨਹੀਂ ਜਾ ਸਕਦਾ, ਉਸ ਲਈ ਛੋਟਾ ਵੇਰਵਾ ਦਿਓ।
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = ਇਹ ਬਦਲਵੀਂ ਲਿਖਤ ਆਪਣੇ-ਆਪ ਤਿਆਰ ਕੀਤੀ ਗਈ ਸੀ ਅਤੇ ਗਲਤ ਵੀ ਹੋ ਸਕਦੀ ਹੈ।
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = ਹੋਰ ਜਾਣੋ
+pdfjs-editor-new-alt-text-create-automatically-button-label = ਬਲਦਵੀਂ ਲਿਖਤ ਆਪਣੇ-ਆਪ ਬਣਾਓ
+pdfjs-editor-new-alt-text-not-now-button = ਹੁਣੇ ਨਹੀਂ
+pdfjs-editor-new-alt-text-error-title = ਬਦਲਵੀਂ ਲਿਖਤ ਆਪਣੇ-ਆਪ ਬਣਾਈ ਨਹੀਂ ਜਾ ਸਕੀ
+pdfjs-editor-new-alt-text-error-description = ਆਪਣਾ ਖੁਦ ਦੀ ਬਦਲਵੀਂ ਲਿਖਤ ਲਿਖੋ ਜਾਂ ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ।
+pdfjs-editor-new-alt-text-error-close-button = ਬੰਦ ਕਰੋ
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = ਬਦਲਵਾਂ ਲਿਖਤ AI ਮਾਡਲ ਡਾਊਨਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ ({ $totalSize } MB ਵਿੱਚੋਂ { $downloadedSize })
+ .aria-valuetext = ਬਦਲਵਾਂ ਲਿਖਤ AI ਮਾਡਲ ਡਾਊਨਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ ({ $totalSize } MB ਵਿੱਚੋਂ { $downloadedSize })
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = ਬਦਲਵੀਂ ਲਿਖਤ ਜੋੜੀ
+pdfjs-editor-new-alt-text-added-button-label = ਬਦਲਵੀਂ ਲਿਖਤ ਜੋੜੀ
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = ਬਦਲਵਾਂ ਲਿਖਤ ਗੁੰਮ ਹੈ
+pdfjs-editor-new-alt-text-missing-button-label = ਬਦਲਵਾਂ ਲਿਖਤ ਗੁੰਮ ਹੈ
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = ਬਦਲਵੀਂ ਲਿਖਤ ਦਾ ਰੀਵਿਊ ਕਰੋ
+pdfjs-editor-new-alt-text-to-review-button-label = ਬਦਲਵੀਂ ਲਿਖਤ ਦਾ ਰੀਵਿਊ ਕਰੋ
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = ਆਪਣੇ-ਆਪ ਬਣਾਇਆ: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = ਚਿੱਤਰ ਬਦਲਵੀਂ ਲਿਖਤ ਦੀਆਂ ਸੈਟਿੰਗਾਂ
+pdfjs-image-alt-text-settings-button-label = ਚਿੱਤਰ ਬਦਲਵੀਂ ਲਿਖਤ ਦੀਆਂ ਸੈਟਿੰਗਾਂ
+pdfjs-editor-alt-text-settings-dialog-label = ਚਿੱਤਰ ਬਦਲਵੀਂ ਲਿਖਤ ਦੀਆਂ ਸੈਟਿੰਗਾਂ
+pdfjs-editor-alt-text-settings-automatic-title = ਆਟੋਮਮੈਟਿਕ ਬਦਲਵੀਂ ਲਿਖਤ
+pdfjs-editor-alt-text-settings-create-model-button-label = ਬਲਦਵੀਂ ਲਿਖਤ ਆਪਣੇ-ਆਪ ਬਣਾਓ
+pdfjs-editor-alt-text-settings-create-model-description = ਚਿੱਤਰ ਨਾ ਵੇਖ ਸਕਣ ਵਾਲੇ ਲੋਕਾਂ ਦੀ ਮਦਦ ਜਾਂ ਜਦ ਵੀ ਚਿੱਤਰਾਂ ਨੂੰ ਲੋਡ ਨਹੀਂ ਜਾ ਸਕਦਾ, ਉਸ ਲਈ ਛੋਟਾ ਵੇਰਵਾ ਦਿਓ।
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = ਬਦਲਵੀ ਲਿਖਤ ਲਈ AI ਮਾਡਲ ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = ਤੁਹਾਡੇ ਡਿਵਾਈਸ ਉੱਤੇ ਲੋਕਲ ਹੀ ਚੱਲਦਾ ਹੋਣ ਕਰਕੇ ਤੁਹਾਡਾ ਡਾਟਾ ਪ੍ਰਾਈਵੇਟ ਹੀ ਰਹਿੰਦਾ ਹੈ। ਆਟੋਮੈਟਿਕ ਬਦਲਵੀਂ ਲਿਖਤ ਲਈ ਚਾਹੀਦਾ ਹੈ।
+pdfjs-editor-alt-text-settings-delete-model-button = ਹਟਾਓ
+pdfjs-editor-alt-text-settings-download-model-button = ਡਾਊਨਲੋਡ
+pdfjs-editor-alt-text-settings-downloading-model-button = …ਨੂੰ ਡਾਊਨਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
+pdfjs-editor-alt-text-settings-editor-title = ਬਦਲਵੀਂ ਲਿਖਤ ਐਡੀਟਰ
+pdfjs-editor-alt-text-settings-show-dialog-button-label = ਜਦੋਂ ਵਿੱਚ ਚਿੱਤਰ ਜੋੜਿਆ ਜਾਵੇ ਤਾਂ ਫ਼ੌਰਨ ਬਦਲਵੀ ਲਿਖਤ ਸੰਪਾਦਕ ਵੇਖਾਓ
+pdfjs-editor-alt-text-settings-show-dialog-description = ਤੁਹਾਡੀ ਮਦਦ ਕਰਦਾ ਹੈ ਕਿ ਤੁਹਾਡੇ ਸਾਰੇ ਚਿੱਤਰਾਂ ਲਈ ਬਦਲਵੀਂ ਲਿਖਤ ਮੌਜੂਦ ਹੋਵੇ।
+pdfjs-editor-alt-text-settings-close-button = ਬੰਦ ਕਰੋ
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = ਹਾਈਲਾਈਟ ਨੂੰ ਜੋੜਿਆ
+pdfjs-editor-freetext-added-alert = ਲਿਖਤ ਨੂੰ ਜੋੜਿਆ ਗਿਆ
+pdfjs-editor-ink-added-alert = ਡਰਾਇੰਗ ਨੂੰ ਜੋੜਿਆ
+pdfjs-editor-stamp-added-alert = ਚਿੱਤਰ ਨੂੰ ਜੋੜਿਆ
+pdfjs-editor-signature-added-alert = ਦਸਤਖ਼ਤਾਂ ਨੂੰ ਜੋੜਿਆ
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = ਹਾਈਲਾਈਟ ਨੂੰ ਹਟਾਇਆ ਗਿਆ
+pdfjs-editor-undo-bar-message-freetext = ਲਿਖਤ ਨੂੰ ਹਟਾਇਆ ਗਿਆ
+pdfjs-editor-undo-bar-message-ink = ਡਰਾਇੰਗ ਨੂੰ ਹਟਾਇਆ ਗਿਆ
+pdfjs-editor-undo-bar-message-stamp = ਚਿੱਤਰ ਨੂੰ ਹਟਾਇਆ ਗਿਆ
+pdfjs-editor-undo-bar-message-signature = ਦਸਤਖ਼ਤ ਨੂੰ ਹਟਾਇਆ
+pdfjs-editor-undo-bar-message-comment = ਟਿੱਪਣੀ ਨੂੰ ਹਟਾਇਆ ਗਿਆ
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } ਵਿਆਖਿਆ ਨੂੰ ਹਟਾਇਆ
+ *[other] { $count } ਵਿਆਖਿਆਵਾਂ ਨੂੰ ਹਟਾਇਆ
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = ਵਾਪਸ
+pdfjs-editor-undo-bar-undo-button-label = ਵਾਪਸ
+pdfjs-editor-undo-bar-close-button =
+ .title = ਬੰਦ ਕਰੋ
+pdfjs-editor-undo-bar-close-button-label = ਬੰਦ ਕਰੋ
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = ਇਹ ਮਾਡਲ ਵਰਤੋਂਕਾਰ ਨੂੰ PDF ਦਸਤਾਵੇਜ਼ ਵਿੱਚ ਜੋੜਨ ਲਈ ਦਸਤਖ਼ਤ ਬਣਾਉਣ ਦਿੰਦਾ ਹੈ। ਵਰਤੋਂਕਾਰ ਨਾਂ ਨੂੰ ਸੋਧ ਸਕਦਾ ਹੈ (ਜੋ ਕਿ ਬਦਲਵੀਂ ਲਿਖਤ ਵਜੋਂ ਕੰਮ ਕਰੇਗਾ) ਅਤੇ ਦੁਬਾਰਾ ਵਰਤੋਂ ਕਰਨ ਲਈ ਦਸਤਖ਼ਤਾਂ ਨੂੰ ਸੰਭਾਲ ਵੀ ਸਕਦਾ ਹੈ।
+pdfjs-editor-add-signature-dialog-title = ਦਸਤਖ਼ਤ ਨੂੰ ਜੋੜੋ
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = ਕਿਸਮ
+ .title = ਕਿਸਮ
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = ਵਾਹੋ
+ .title = ਵਾਹੋ
+pdfjs-editor-add-signature-image-button = ਚਿੱਤਰ
+ .title = ਚਿੱਤਰ
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = ਆਪਣੇ ਦਸਤਖ਼ਤ ਨੂੰ ਟਾਈਪ ਕਰੋ
+ .placeholder = ਆਪਣੇ ਦਸਤਖ਼ਤ ਨੂੰ ਟਾਈਪ ਕਰੋ
+pdfjs-editor-add-signature-draw-placeholder = ਆਪਣੇ ਦਸਤਖ਼ਤ ਨੂੰ ਵਾਹੋ
+pdfjs-editor-add-signature-draw-thickness-range-label = ਮੋਟਾਈ
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = ਵਹਾਉਣ ਲਈ ਚੌੜਾਈ: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = ਅੱਪਲੋਡ ਕਰਨ ਲਈ ਫ਼ਾਇਲ ਨੂੰ ਇੱਥੇ ਖਿੱਚੋ
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] ਜਾਂ ਚਿੱਤਰ ਫ਼ਾਇਲਾਂ ਨੂੰ ਚੁਣੋ
+ *[other] ਜਾਂ ਚਿੱਤਰ ਫ਼ਾਇਲਾਂ ਦੀ ਝਲਕ ਵੇਖੋ
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = ਵਰਣਨ (ਬਦਲਵੀਂ ਲਿਖਤ)
+pdfjs-editor-add-signature-description-input =
+ .title = ਵਰਣਨ (ਬਦਲਵੀਂ ਲਿਖਤ)
+pdfjs-editor-add-signature-description-default-when-drawing = ਦਸਤਖ਼ਤ
+pdfjs-editor-add-signature-clear-button-label = ਦਸਤਖ਼ਤ ਨੂੰ ਮਿਟਾਓ
+pdfjs-editor-add-signature-clear-button =
+ .title = ਦਸਤਖ਼ਤ ਨੂੰ ਮਿਟਾਓ
+pdfjs-editor-add-signature-save-checkbox = ਦਸਤਖ਼ਤ ਨੂੰ ਸੰਭਾਲੋ
+pdfjs-editor-add-signature-save-warning-message = ਤੁਸੀਂ ਵੱਧ ਤੋਂ ਵੱਧ 5 ਸੰਭਾਲੇ ਦਸਤਖ਼ਤਾਂ ਦੀ ਹੱਦ ਤੱਕ ਅੱਪੜੇ। ਹੋਰ ਸੰਭਾਲਣ ਲਈ ਇੱਕ ਨੂੰ ਹਟਾਓ।
+pdfjs-editor-add-signature-image-upload-error-title = ਚਿੱਤਰ ਨੂੰ ਅੱਪਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ
+pdfjs-editor-add-signature-image-upload-error-description = ਆਪਣੇ ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰੋ ਜਾਂ ਹੋਰ ਚਿੱਤਰ ਨੂੰ ਅਜ਼ਮਾਓ।
+pdfjs-editor-add-signature-image-no-data-error-title = ਇਸ ਚਿੱਤਰ ਨੂੰ ਦਸਤਖ਼ਤ ਵਿੱਚ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ ਹੈ
+pdfjs-editor-add-signature-image-no-data-error-description = ਵੱਖਰੇ ਚਿੱਤਰ ਨੂੰ ਅੱਪਲੋਡ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।
+pdfjs-editor-add-signature-error-close-button = ਬੰਦ ਕਰੋ
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = ਰੱਦ ਕਰੋ
+pdfjs-editor-add-signature-add-button = ਜੋੜੋ
+pdfjs-editor-edit-signature-update-button = ਅੱਪਡੇਟ
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = ਟਿੱਪਣੀ ਨੂੰ ਸੋਧੋ
+pdfjs-editor-edit-comment-popup-button =
+ .title = ਟਿੱਪਣੀ ਨੂੰ ਸੋਧੋ
+pdfjs-editor-delete-comment-popup-button-label = ਟਿੱਪਣੀ ਨੂੰ ਹਟਾਓ
+pdfjs-editor-delete-comment-popup-button =
+ .title = ਟਿੱਪਣੀ ਨੂੰ ਹਟਾਓ
+pdfjs-show-comment-button =
+ .title = ਟਿੱਪਣੀ ਨੂੰ ਵੇਖਾਓ
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = ਟਿੱਪਣੀ ਨੂੰ ਸੋਧੋ
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = ਅੱਪਡੇਟ ਕਰੋ
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = ਟਿੱਪਣੀ ਜੋੜੋ
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = ਜੋੜੋ
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = …ਲਿਖਣਾ ਸ਼ੁਰੂ ਕਰੋ
+pdfjs-editor-edit-comment-dialog-cancel-button = ਰੱਦ ਕਰੋ
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = ਟਿੱਪਣੀ ਜੋੜੋ
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = ਬਾਹੀ ਨੂੰ ਬਦਲੋ (ਦਸਤਾਵੇਜ਼ ਥੰਮਨੇਲ/ਆਨਲਾਈਨਅਟੈਚਮੈਂਟ/ਪਰਤਾਂ ਰੱਖਦਾ ਹੈ)
+pdfjs-toggle-views-manager-button1-label = ਸਫ਼ਿਆਂ ਦਾ ਇੰਤਜ਼ਾਮ
+pdfjs-views-manager-sidebar =
+ .aria-label = ਬਾਹੀ
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = ਬਾਹੀ ਦਾ ਆਕਾਰ-ਬਦਲ
+pdfjs-views-manager-view-selector-button =
+ .title = ਵੇਖੋ
+pdfjs-views-manager-view-selector-button-label = ਵੇਖੋ
+pdfjs-views-manager-pages-title = ਸਫ਼ੇ
+pdfjs-views-manager-outlines-title1 = ਦਸਤਾਵੇਜ਼ ਖਾਕਾ
+ .title = ਦਸਤਾਵੇਜ਼ ਖਾਕਾ (ਸਾਰੀਆਂ ਚੀਜ਼ਾਂ ਨੂੰ ਫੈਲਾਉਣ/ਸਮੇਟਣ ਲਈ ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰੋ)
+pdfjs-views-manager-attachments-title = ਅਟੈਚਮੈਂਟਾਂ
+pdfjs-views-manager-layers-title1 = ਲੇਅਰ
+ .title = ਲੇਅਰ (ਸਾਰੀਆਂ ਲੇਅਰਾਂ ਨੂੰ ਮੂਲ ਹਾਲਤ ਵਿੱਚ ਲੈ ਜਾਣ ਲਈ ਦੋ ਵਾਰ ਕਲਿੱਕ ਕਰੋ)
+pdfjs-views-manager-pages-option-label = ਸਫ਼ੇ
+pdfjs-views-manager-outlines-option-label = ਦਸਤਾਵੇਜ਼ ਆਉਟਲਾਈਨ
+pdfjs-views-manager-attachments-option-label = ਅਟੈਚਮੈਂਟਾਂ
+pdfjs-views-manager-layers-option-label = ਪਰਤਾਂ
+pdfjs-views-manager-add-file-button =
+ .title = ਫ਼ਾਇਲ ਨੂੰ ਜੋੜੋ
+pdfjs-views-manager-add-file-button-label = ਫ਼ਾਇਲ ਨੂੰ ਜੋੜੋ
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } ਚੁਣਿਆ
+ *[other] { $count } ਚੁਣੇ
+ }
+pdfjs-views-manager-pages-status-none-action-label = ਸਫ਼ੇ ਚੁਣੋ
+pdfjs-views-manager-pages-status-action-button-label = ਬੰਦੋਬਸਤ
+pdfjs-views-manager-pages-status-copy-button-label = ਕਾਪੀ ਕਰੋ
+pdfjs-views-manager-pages-status-cut-button-label = ਕੱਟੋ
+pdfjs-views-manager-pages-status-delete-button-label = ਹਟਾਓ
+pdfjs-views-manager-pages-status-export-selected-button-label = …ਚੁਣੇ ਨੂੰ ਐਕਸਪੋਰਟ ਕਰੋ
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 ਸਫ਼ੇ ਨੂੰ ਕੱਟਿਆਂ
+ *[other] { $count } ਸਫ਼ਿਆਂ ਨੂੰ ਕੱਟਿਆਂ
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 ਸਫ਼ੇ ਨੂੰ ਕਾਪੀ ਕੀਤਾ
+ *[other] { $count } ਸਫ਼ਿਆਂ ਨੂੰ ਕਾਪੀ ਕੀਤਾ
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 ਸਫ਼ੇ ਨੂੰ ਹਟਾਇਆ
+ *[other] { $count } ਸਫ਼ਿਆਂ ਨੂੰ ਹਟਾਇਆ
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = …ਤੁਹਾਡੀ ਫ਼ਾਇਲ ਨੂੰ ਤਿਆਰ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
+pdfjs-views-manager-pages-status-waiting-uploading-label = …ਫ਼ਾਇਲ ਨੂੰ ਅੱਪਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
+pdfjs-views-manager-status-warning-cut-label = ਕੱਟਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਸਫ਼ੇ ਨੂੰ ਤਾਜ਼ਾ ਕਰਕੇ ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ।
+pdfjs-views-manager-status-warning-copy-label = ਕਾਪੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਸਫ਼ੇ ਨੂੰ ਤਾਜ਼ਾ ਕਰਕੇ ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ।
+pdfjs-views-manager-status-warning-delete-label = ਹਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਸਫ਼ੇ ਨੂੰ ਤਾਜ਼ਾ ਕਰਕੇ ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ।
+pdfjs-views-manager-status-warning-save-label = ਸੰਭਾਲਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ। ਸਫ਼ੇ ਨੂੰ ਤਾਜ਼ਾ ਕਰਕੇ ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ।
+pdfjs-views-manager-status-undo-button-label = ਵਾਪਸ
+pdfjs-views-manager-status-done-button-label = ਮੁਕੰਮਲ
+pdfjs-views-manager-status-close-button =
+ .title = ਬੰਦ ਕਰੋ
+pdfjs-views-manager-status-close-button-label = ਬੰਦ ਕਰੋ
+pdfjs-views-manager-paste-button-label = ਚੇਪੋ
+pdfjs-views-manager-paste-button-before =
+ .title = ਪਹਿਲੇ ਸਫ਼ੇ ਦੇ ਬਾਅਦ ਚੇਪੋ
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = { $page } ਸਫ਼ੇ ਦੇ ਬਾਅਦ ਚੇਪੋ
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = ਨਵਾਂ
+pdfjs-views-manager-waiting-for-file = …ਫ਼ਾਇਲ ਨੂੰ ਅੱਪਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
+pdfjs-toggle-views-manager-button1 =
+ .title = ਸਫ਼ਿਆਂ ਦਾ ਇੰਤਜ਼ਾਮ
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = ਡਿਜੀਟਲ ਦਸਤਖਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ
+ .aria-label = ਡਿਜੀਟਲ ਦਸਤਖਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ
+pdfjs-digital-signature-properties-button-label = ਡਿਜੀਟਲ ਦਸਤਖਤ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = ਦਸਤਾਵੇਜ਼ ਨੂੰ ਵਾਜਬ ਡਿਜੀਟਲ ਦਸਤਖ਼ਤਾਂ ਨਾਲ ਸਾਈਨ ਕੀਤਾ ਗਿਆ ਸੀ
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] ਦਸਤਾਵੇਜ਼ ਨੂੰ ਸਾਈਨ ਤਾਂ ਕੀਤਾ ਗਿਆ ਸੀ ਪਰ { $count } ਡਿਜੀਟਲ ਦਸਤਖ਼ਤ ਨੂੰ ਤਸਦੀਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ
+ *[other] ਦਸਤਾਵੇਜ਼ ਨੂੰ ਸਾਈਨ ਤਾਂ ਕੀਤਾ ਗਿਆ ਸੀ ਪਰ { $count } ਡਿਜੀਟਲ ਦਸਤਖ਼ਤਾਂ ਨੂੰ ਤਸਦੀਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] ਦਸਤਾਵੇਜ਼ ਨੂੰ { $count } ਸਰਟੀਫਿਕੇਟ ਨਾਲ ਸਾਈਨ ਕੀਤਾ ਗਿਆ ਸੀ, ਜੋ ਭਰੋਸੇਯੋਗ ਨਹੀਂ ਹੈ
+ *[other] ਦਸਤਾਵੇਜ਼ ਨੂੰ { $count } ਸਰਟੀਫਿਕੇਟਾਂ ਨਾਲ ਸਾਈਨ ਕੀਤਾ ਗਿਆ ਸੀ, ਜੋ ਭਰੋਸੇਯੋਗ ਨਹੀਂ ਹਨ
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] ਦਸਤਾਵੇਜ਼ ਨੂੰ { $count } ਮਿਆਦ ਪੁੱਗੇ ਸਰਟੀਫਿਕੇਟ ਨਾਲ ਸਾਈਨ ਕੀਤਾ ਗਿਆ ਸੀ
+ *[other] ਦਸਤਾਵੇਜ਼ ਨੂੰ { $count } ਮਿਆਦ ਪੁੱਗੇ ਸਰਟੀਫਿਕੇਟਾਂ ਨਾਲ ਸਾਈਨ ਕੀਤਾ ਗਿਆ ਸੀ
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] ਦਸਤਾਵੇਜ਼ ਵਿੱਚ { $count } ਅਵੈਧ ਡਿਜੀਟਲ ਦਸਤਖਤ ਹਨ
+ *[other] ਦਸਤਾਵੇਜ਼ ਵਿੱਚ { $count } ਅਵੈਧ ਡਿਜੀਟਲ ਦਸਤਖਤ ਹਨ
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] ਦਸਤਾਵੇਜ਼ 'ਤੇ { $count } ਰੱਦ ਕੀਤੇ ਸਰਟੀਫਿਕੇਟ ਨਾਲ ਦਸਤਖਤ ਕੀਤੇ ਗਏ ਹਨ
+ *[other] ਦਸਤਾਵੇਜ਼ { $count } ਰੱਦ ਕੀਤੇ ਸਰਟੀਫਿਕੇਟਾਂ ਨਾਲ ਦਸਤਖਤ ਕੀਤਾ ਗਿਆ ਹੈ
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = ਸਥਿਤੀ: ਦਸਤਖਤਾਂ ਦੀ ਜਾਂਚ ਕੀਤੀ ਗਈ
+pdfjs-digital-signature-properties-status-invalid = ਸਥਿਤੀ: ਦਸਤਖਤ ਸਹੀ ਨਹੀਂ ਹਨ
+pdfjs-digital-signature-properties-status-unknown = ਸਥਿਤੀ: ਜਾਂਚ ਕਰਨ ਲਈ ਅਸਮਰੱਥ (ਗ਼ੈਰ-ਸਹਾਇਕ)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = ਸਰਟੀਫਿਕੇਟ: ਭਰੋਸਾਕਰਤਾ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = ਸਰਟੀਫਿਕੇਟ: ਗ਼ੈਰ-ਮੌਜੂਦ
+pdfjs-digital-signature-properties-certificate-untrusted = ਸਰਟੀਫਿਕੇਟ: ਬੇਭਰੋਸੇਯੋਗ
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = ਸਰਟੀਫਿਕੇਟ: ਅਣਪਛਾਤਾ ਜਾਰੀਕਰਤਾ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = ਸਰਟੀਫਿਕੇਟ: ਸਵੈ-ਦਸਤਖ਼ਤੀ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = ਸਰਟੀਫਿਕੇਟ: ਬੇਭਰੋਸੇਯੋਗ ਜਾਰੀ ਕਰਤਾ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = ਸਰਟੀਫਿਕੇਟ: ਮਿਆਦ ਪੁੱਗੀ
+pdfjs-digital-signature-properties-certificate-expired-with-date = ਸਰਟੀਫਿਕੇਟ: ਮਿਆਦ ਪੁੱਗੀ ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = ਸਰਟੀਫਿਕੇਟ: ਰੱਦ ਕੀਤਾ
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = ਸੰਭਾਲੇ ਹੋਏ ਦਸਤਖ਼ਤ ਨੂੰ ਹਟਾਓ
+pdfjs-editor-delete-signature-button-label1 = ਸੰਭਾਲੇ ਹੋਏ ਦਸਤਖ਼ਤ ਨੂੰ ਹਟਾਓ
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = ਵਰਣਨ ਨੂੰ ਸੋਧੋ
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = ਵਰਣਨ ਨੂੰ ਸੋਧੋ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pl/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pl/viewer.ftl
new file mode 100644
index 0000000..c800ff7
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pl/viewer.ftl
@@ -0,0 +1,849 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Poprzednia strona
+pdfjs-previous-button-label = Poprzednia
+pdfjs-next-button =
+ .title = Następna strona
+pdfjs-next-button-label = Następna
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Strona
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = z { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } z { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Pomniejsz
+pdfjs-zoom-out-button-label = Pomniejsz
+pdfjs-zoom-in-button =
+ .title = Powiększ
+pdfjs-zoom-in-button-label = Powiększ
+pdfjs-zoom-select =
+ .title = Skala
+pdfjs-presentation-mode-button =
+ .title = Przełącz na tryb prezentacji
+pdfjs-presentation-mode-button-label = Tryb prezentacji
+pdfjs-open-file-button =
+ .title = Otwórz plik
+pdfjs-open-file-button-label = Otwórz
+pdfjs-print-button =
+ .title = Drukuj
+pdfjs-print-button-label = Drukuj
+pdfjs-save-button =
+ .title = Zapisz
+pdfjs-save-button-label = Zapisz
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Pobierz
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Pobierz
+pdfjs-bookmark-button =
+ .title = Bieżąca strona (adres do otwarcia na bieżącej stronie)
+pdfjs-bookmark-button-label = Bieżąca strona
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Narzędzia
+pdfjs-tools-button-label = Narzędzia
+pdfjs-first-page-button =
+ .title = Przejdź do pierwszej strony
+pdfjs-first-page-button-label = Przejdź do pierwszej strony
+pdfjs-last-page-button =
+ .title = Przejdź do ostatniej strony
+pdfjs-last-page-button-label = Przejdź do ostatniej strony
+pdfjs-page-rotate-cw-button =
+ .title = Obróć zgodnie z ruchem wskazówek zegara
+pdfjs-page-rotate-cw-button-label = Obróć zgodnie z ruchem wskazówek zegara
+pdfjs-page-rotate-ccw-button =
+ .title = Obróć przeciwnie do ruchu wskazówek zegara
+pdfjs-page-rotate-ccw-button-label = Obróć przeciwnie do ruchu wskazówek zegara
+pdfjs-cursor-text-select-tool-button =
+ .title = Włącz narzędzie zaznaczania tekstu
+pdfjs-cursor-text-select-tool-button-label = Narzędzie zaznaczania tekstu
+pdfjs-cursor-hand-tool-button =
+ .title = Włącz narzędzie rączka
+pdfjs-cursor-hand-tool-button-label = Narzędzie rączka
+pdfjs-scroll-page-button =
+ .title = Przewijaj strony
+pdfjs-scroll-page-button-label = Przewijanie stron
+pdfjs-scroll-vertical-button =
+ .title = Przewijaj dokument w pionie
+pdfjs-scroll-vertical-button-label = Przewijanie pionowe
+pdfjs-scroll-horizontal-button =
+ .title = Przewijaj dokument w poziomie
+pdfjs-scroll-horizontal-button-label = Przewijanie poziome
+pdfjs-scroll-wrapped-button =
+ .title = Strony dokumentu wyświetlaj i przewijaj w kolumnach
+pdfjs-scroll-wrapped-button-label = Widok dwóch stron
+pdfjs-spread-none-button =
+ .title = Nie ustawiaj stron obok siebie
+pdfjs-spread-none-button-label = Brak kolumn
+pdfjs-spread-odd-button =
+ .title = Strony nieparzyste ustawiaj na lewo od parzystych
+pdfjs-spread-odd-button-label = Nieparzyste po lewej
+pdfjs-spread-even-button =
+ .title = Strony parzyste ustawiaj na lewo od nieparzystych
+pdfjs-spread-even-button-label = Parzyste po lewej
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Właściwości dokumentu…
+pdfjs-document-properties-button-label = Właściwości dokumentu…
+pdfjs-document-properties-file-name = Nazwa pliku:
+pdfjs-document-properties-file-size = Rozmiar pliku:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } B)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } B)
+pdfjs-document-properties-title = Tytuł:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Temat:
+pdfjs-document-properties-keywords = Słowa kluczowe:
+pdfjs-document-properties-creation-date = Data utworzenia:
+pdfjs-document-properties-modification-date = Data modyfikacji:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Utworzony przez:
+pdfjs-document-properties-producer = PDF wyprodukowany przez:
+pdfjs-document-properties-version = Wersja PDF:
+pdfjs-document-properties-page-count = Liczba stron:
+pdfjs-document-properties-page-size = Wymiary strony:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = pionowa
+pdfjs-document-properties-page-size-orientation-landscape = pozioma
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = US Letter
+pdfjs-document-properties-page-size-name-legal = US Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width }×{ $height } { $unit } (orientacja { $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width }×{ $height } { $unit } ({ $name }, orientacja { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Szybki podgląd w Internecie:
+pdfjs-document-properties-linearized-yes = tak
+pdfjs-document-properties-linearized-no = nie
+pdfjs-document-properties-close-button = Zamknij
+pdfjs-digital-signature-properties-view-certificate = Wyświetl certyfikat
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Powód: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Data: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] { $count } podpis podrzędny
+ [few] { $count } podpisy podrzędne
+ *[many] { $count } podpisów podrzędnych
+ }
+
+## Print
+
+pdfjs-print-progress-message = Przygotowywanie dokumentu do druku…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Anuluj
+pdfjs-printing-not-supported = Ostrzeżenie: drukowanie nie jest w pełni obsługiwane przez tę przeglądarkę.
+pdfjs-printing-not-ready = Ostrzeżenie: dokument PDF nie jest całkowicie wczytany, więc nie można go wydrukować.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Przełącz panel boczny
+pdfjs-toggle-sidebar-notification-button =
+ .title = Przełącz panel boczny (dokument zawiera konspekt/załączniki/warstwy)
+pdfjs-toggle-sidebar-button-label = Przełącz panel boczny
+pdfjs-document-outline-button =
+ .title = Konspekt dokumentu (podwójne kliknięcie rozwija lub zwija wszystkie pozycje)
+pdfjs-document-outline-button-label = Konspekt dokumentu
+pdfjs-attachments-button =
+ .title = Załączniki
+pdfjs-attachments-button-label = Załączniki
+pdfjs-layers-button =
+ .title = Warstwy (podwójne kliknięcie przywraca wszystkie warstwy do stanu domyślnego)
+pdfjs-layers-button-label = Warstwy
+pdfjs-thumbs-button =
+ .title = Miniatury
+pdfjs-thumbs-button-label = Miniatury
+pdfjs-current-outline-item-button =
+ .title = Znajdź bieżący element konspektu
+pdfjs-current-outline-item-button-label = Bieżący element konspektu
+pdfjs-findbar-button =
+ .title = Znajdź w dokumencie
+pdfjs-findbar-button-label = Znajdź
+pdfjs-additional-layers = Dodatkowe warstwy
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page }. strona
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura { $page }. strony
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Zaznacz { $page }. stronę
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = { $page }. strona z { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Znajdź
+ .placeholder = Znajdź w dokumencie…
+pdfjs-find-previous-button =
+ .title = Znajdź poprzednie wystąpienie tekstu
+pdfjs-find-previous-button-label = Poprzednie
+pdfjs-find-next-button =
+ .title = Znajdź następne wystąpienie tekstu
+pdfjs-find-next-button-label = Następne
+pdfjs-find-highlight-checkbox = Wyróżnianie wszystkich
+pdfjs-find-match-case-checkbox-label = Rozróżnianie wielkości liter
+pdfjs-find-match-diacritics-checkbox-label = Rozróżnianie liter diakrytyzowanych
+pdfjs-find-entire-word-checkbox-label = Całe słowa
+pdfjs-find-reached-top = Początek dokumentu. Wyszukiwanie od końca.
+pdfjs-find-reached-bottom = Koniec dokumentu. Wyszukiwanie od początku.
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current }. z { $total } trafienia
+ [few] { $current }. z { $total } trafień
+ *[many] { $current }. z { $total } trafień
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Więcej niż { $limit } trafienie
+ [few] Więcej niż { $limit } trafienia
+ *[many] Więcej niż { $limit } trafień
+ }
+pdfjs-find-not-found = Nie znaleziono tekstu
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Szerokość strony
+pdfjs-page-scale-fit = Dopasowanie strony
+pdfjs-page-scale-auto = Skala automatyczna
+pdfjs-page-scale-actual = Rozmiar oryginalny
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page }. strona
+
+## Loading indicator messages
+
+pdfjs-loading-error = Podczas wczytywania dokumentu PDF wystąpił błąd.
+pdfjs-invalid-file-error = Nieprawidłowy lub uszkodzony plik PDF.
+pdfjs-missing-file-error = Brak pliku PDF.
+pdfjs-unexpected-response-error = Nieoczekiwana odpowiedź serwera.
+pdfjs-rendering-error = Podczas renderowania strony wystąpił błąd.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Przypis: { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Wpisz hasło, aby otworzyć ten dokument PDF.
+pdfjs-password-invalid = Nieprawidłowe hasło. Proszę spróbować ponownie.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Anuluj
+pdfjs-web-fonts-disabled = Czcionki sieciowe są wyłączone: nie można użyć osadzonych czcionek PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Zmień kolor tekstu
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Rysunek
+pdfjs-editor-color-picker-ink-input =
+ .title = Zmień kolor rysunku
+pdfjs-editor-ink-button-label = Rysunek
+pdfjs-editor-stamp-button =
+ .title = Dodaj lub edytuj obrazy
+pdfjs-editor-stamp-button-label = Dodaj lub edytuj obrazy
+pdfjs-editor-highlight-button =
+ .title = Wyróżnij
+pdfjs-editor-highlight-button-label = Wyróżnij
+pdfjs-highlight-floating-button1 =
+ .title = Wyróżnij
+ .aria-label = Wyróżnij
+pdfjs-highlight-floating-button-label = Wyróżnij
+pdfjs-comment-floating-button =
+ .title = Dodaj komentarz
+ .aria-label = Dodaj komentarz
+pdfjs-comment-floating-button-label = Dodaj komentarz
+pdfjs-editor-comment-button =
+ .title = Dodaj komentarz
+ .aria-label = Dodaj komentarz
+pdfjs-editor-comment-button-label = Dodaj komentarz
+pdfjs-editor-signature-button =
+ .title = Dodaj podpis
+pdfjs-editor-signature-button-label = Dodaj podpis
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Edytor wyróżnienia
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Edytor rysunku
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Edytor podpisu: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Edytor obrazu
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Usuń rysunek
+pdfjs-editor-remove-freetext-button =
+ .title = Usuń tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Usuń obraz
+pdfjs-editor-remove-highlight-button =
+ .title = Usuń wyróżnienie
+pdfjs-editor-remove-signature-button =
+ .title = Usuń podpis
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Kolor
+pdfjs-editor-free-text-size-input = Rozmiar
+pdfjs-editor-ink-color-input = Kolor
+pdfjs-editor-ink-thickness-input = Grubość
+pdfjs-editor-ink-opacity-input = Nieprzezroczystość
+pdfjs-editor-stamp-add-image-button =
+ .title = Dodaj obraz
+pdfjs-editor-stamp-add-image-button-label = Dodaj obraz
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grubość
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Zmień grubość podczas wyróżniania elementów innych niż tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Sterowanie podpisami i zachowane podpisy
+pdfjs-editor-signature-add-signature-button =
+ .title = Dodaj nowy podpis
+pdfjs-editor-signature-add-signature-button-label = Dodaj nowy podpis
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Zachowany podpis: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Edytor tekstu
+ .default-content = Zacznij pisać…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Komentarz
+ *[other] Komentarze
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Zamknij panel boczny
+ .aria-label = Zamknij panel boczny
+pdfjs-editor-comments-sidebar-close-button-label = Zamknij panel boczny
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Widzisz coś godnego uwagi? Wyróżnij to i zostaw komentarz.
+pdfjs-editor-comments-sidebar-no-comments-link = Więcej informacji
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Tekst alternatywny
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Edytuj tekst alternatywny
+pdfjs-editor-alt-text-dialog-label = Wybierz opcję
+pdfjs-editor-alt-text-dialog-description = Tekst alternatywny pomaga, kiedy ktoś nie może zobaczyć obrazu lub gdy się nie wczytuje.
+pdfjs-editor-alt-text-add-description-label = Dodaj opis
+pdfjs-editor-alt-text-add-description-description = Staraj się napisać 1-2 zdania opisujące temat, miejsce lub działania.
+pdfjs-editor-alt-text-mark-decorative-label = Oznacz jako dekoracyjne
+pdfjs-editor-alt-text-mark-decorative-description = Używane w przypadku obrazów ozdobnych, takich jak obramowania lub znaki wodne.
+pdfjs-editor-alt-text-cancel-button = Anuluj
+pdfjs-editor-alt-text-save-button = Zapisz
+pdfjs-editor-alt-text-decorative-tooltip = Oznaczone jako dekoracyjne
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Na przykład: „Młody człowiek siada przy stole, aby zjeść posiłek”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Tekst alternatywny
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Lewy górny róg — zmień rozmiar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Górny środkowy — zmień rozmiar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Prawy górny róg — zmień rozmiar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Prawy środkowy — zmień rozmiar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Prawy dolny róg — zmień rozmiar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Dolny środkowy — zmień rozmiar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Lewy dolny róg — zmień rozmiar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Lewy środkowy — zmień rozmiar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Kolor wyróżnienia
+pdfjs-editor-colorpicker-button =
+ .title = Zmień kolor
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Wybór kolorów
+pdfjs-editor-colorpicker-yellow =
+ .title = Żółty
+pdfjs-editor-colorpicker-green =
+ .title = Zielony
+pdfjs-editor-colorpicker-blue =
+ .title = Niebieski
+pdfjs-editor-colorpicker-pink =
+ .title = Różowy
+pdfjs-editor-colorpicker-red =
+ .title = Czerwony
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Pokaż wszystkie
+pdfjs-editor-highlight-show-all-button =
+ .title = Pokaż wszystkie
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Edytuj tekst alternatywny (opis obrazu)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Dodaj tekst alternatywny (opis obrazu)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Napisz tutaj opis…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Krótki opis dla osób, które nie widzą obrazu lub kiedy obraz się nie wczytuje.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ten tekst alternatywny został utworzony automatycznie i może być niepoprawny.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Więcej informacji
+pdfjs-editor-new-alt-text-create-automatically-button-label = Automatycznie utwórz tekst alternatywny
+pdfjs-editor-new-alt-text-not-now-button = Nie teraz
+pdfjs-editor-new-alt-text-error-title = Nie można automatycznie utworzyć tekstu alternatywnego
+pdfjs-editor-new-alt-text-error-description = Proszę napisać własny tekst alternatywny lub spróbować ponownie później.
+pdfjs-editor-new-alt-text-error-close-button = Zamknij
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Pobieranie modelu SI tekstu alternatywnego ({ $downloadedSize } z { $totalSize } MB)
+ .aria-valuetext = Pobieranie modelu SI tekstu alternatywnego ({ $downloadedSize } z { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Dodano tekst alternatywny
+pdfjs-editor-new-alt-text-added-button-label = Dodano tekst alternatywny
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Brak tekstu alternatywnego
+pdfjs-editor-new-alt-text-missing-button-label = Brak tekstu alternatywnego
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Przejrzyj tekst alternatywny
+pdfjs-editor-new-alt-text-to-review-button-label = Przejrzyj tekst alternatywny
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Utworzono automatycznie: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Ustawienia tekstu alternatywnego obrazów
+pdfjs-image-alt-text-settings-button-label = Ustawienia tekstu alternatywnego obrazów
+pdfjs-editor-alt-text-settings-dialog-label = Ustawienia tekstu alternatywnego obrazów
+pdfjs-editor-alt-text-settings-automatic-title = Automatyczny tekst alternatywny
+pdfjs-editor-alt-text-settings-create-model-button-label = Automatyczne tworzenie tekstu alternatywnego
+pdfjs-editor-alt-text-settings-create-model-description = Podpowiada opisy, które mogą pomóc osobom, które nie widzą obrazu lub kiedy obraz się nie wczytuje.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model SI tekstu alternatywnego ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Działa lokalnie na urządzeniu użytkownika, więc Twoje dane pozostają prywatne. Wymagane do funkcji automatycznego tekstu alternatywnego.
+pdfjs-editor-alt-text-settings-delete-model-button = Usuń
+pdfjs-editor-alt-text-settings-download-model-button = Pobierz
+pdfjs-editor-alt-text-settings-downloading-model-button = Pobieranie…
+pdfjs-editor-alt-text-settings-editor-title = Edytor tekstu alternatywnego
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Wyświetlanie edytora tekstu alternatywnego od razu po dodaniu obrazu
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomaga upewnić się, że wszystkie obrazy mają tekst alternatywny.
+pdfjs-editor-alt-text-settings-close-button = Zamknij
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Dodano wyróżnione
+pdfjs-editor-freetext-added-alert = Dodano tekst
+pdfjs-editor-ink-added-alert = Dodano rysunek
+pdfjs-editor-stamp-added-alert = Dodano obraz
+pdfjs-editor-signature-added-alert = Dodano podpis
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Usunięto wyróżnienie
+pdfjs-editor-undo-bar-message-freetext = Usunięto tekst
+pdfjs-editor-undo-bar-message-ink = Usunięto rysunek
+pdfjs-editor-undo-bar-message-stamp = Usunięto obraz
+pdfjs-editor-undo-bar-message-signature = Usunięto podpis
+pdfjs-editor-undo-bar-message-comment = Usunięto komentarz
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] Usunięto przypis
+ [few] Usunięto { $count } przypisy
+ *[many] Usunięto { $count } przypisów
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Cofnij
+pdfjs-editor-undo-bar-undo-button-label = Cofnij
+pdfjs-editor-undo-bar-close-button =
+ .title = Zamknij
+pdfjs-editor-undo-bar-close-button-label = Zamknij
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = To okno umożliwia utworzenie podpisu, który można dodać do dokumentu PDF. Można zmienić nazwę (która służy także jako tekst alternatywny) i opcjonalnie zachować podpis do ponownego użycia.
+pdfjs-editor-add-signature-dialog-title = Dodanie podpisu
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Wpisz
+ .title = Wpisz
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Narysuj
+ .title = Narysuj
+pdfjs-editor-add-signature-image-button = Obraz
+ .title = Obraz
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Wpisz swój podpis
+ .placeholder = Wpisz swój podpis
+pdfjs-editor-add-signature-draw-placeholder = Narysuj swój podpis
+pdfjs-editor-add-signature-draw-thickness-range-label = Grubość
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grubość kreski: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Przeciągnij tutaj plik, aby go przesłać
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Lub wybierz plik obrazu
+ *[other] Lub przeglądaj pliki obrazów
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Opis (tekst alternatywny)
+pdfjs-editor-add-signature-description-input =
+ .title = Opis (tekst alternatywny)
+pdfjs-editor-add-signature-description-default-when-drawing = Podpis
+pdfjs-editor-add-signature-clear-button-label = Usuń podpis
+pdfjs-editor-add-signature-clear-button =
+ .title = Usuń podpis
+pdfjs-editor-add-signature-save-checkbox = Zachowaj podpis
+pdfjs-editor-add-signature-save-warning-message = Osiągnięto ograniczenie wynoszące pięć zachowanych podpisów. Usuń jeden, aby zachować więcej.
+pdfjs-editor-add-signature-image-upload-error-title = Nie można przesłać obrazu
+pdfjs-editor-add-signature-image-upload-error-description = Sprawdź połączenie sieciowe lub spróbuj przesłać inny obraz.
+pdfjs-editor-add-signature-image-no-data-error-title = Nie można przekonwertować tego obrazu na podpis
+pdfjs-editor-add-signature-image-no-data-error-description = Spróbuj przesłać inny obraz.
+pdfjs-editor-add-signature-error-close-button = Zamknij
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Anuluj
+pdfjs-editor-add-signature-add-button = Dodaj
+pdfjs-editor-edit-signature-update-button = Aktualizuj
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Edytuj komentarz
+pdfjs-editor-edit-comment-popup-button =
+ .title = Edytuj komentarz
+pdfjs-editor-delete-comment-popup-button-label = Usuń komentarz
+pdfjs-editor-delete-comment-popup-button =
+ .title = Usuń komentarz
+pdfjs-show-comment-button =
+ .title = Wyświetl komentarz
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Edytuj komentarz
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualizuj
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Dodaj komentarz
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Dodaj
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Zacznij pisać…
+pdfjs-editor-edit-comment-dialog-cancel-button = Anuluj
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Dodaj komentarz
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Przełącz panel boczny (dokument zawiera miniatury/konspekt/załączniki/warstwy)
+pdfjs-toggle-views-manager-button1-label = Zarządzaj stronami
+pdfjs-views-manager-sidebar =
+ .aria-label = Panel boczny
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Zmiana rozmiaru panelu bocznego
+pdfjs-views-manager-view-selector-button =
+ .title = Widoki
+pdfjs-views-manager-view-selector-button-label = Widoki
+pdfjs-views-manager-pages-title = Strony
+pdfjs-views-manager-outlines-title1 = Konspekt dokumentu
+ .title = Konspekt dokumentu (podwójne kliknięcie rozwija lub zwija wszystkie pozycje)
+pdfjs-views-manager-attachments-title = Załączniki
+pdfjs-views-manager-layers-title1 = Warstwy
+ .title = Warstwy (podwójne kliknięcie przywraca wszystkie warstwy do stanu domyślnego)
+pdfjs-views-manager-pages-option-label = Strony
+pdfjs-views-manager-outlines-option-label = Konspekt dokumentu
+pdfjs-views-manager-attachments-option-label = Załączniki
+pdfjs-views-manager-layers-option-label = Warstwy
+pdfjs-views-manager-add-file-button =
+ .title = Dodaj plik
+pdfjs-views-manager-add-file-button-label = Dodaj plik
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } zaznaczona
+ [few] { $count } zaznaczone
+ *[many] { $count } zaznaczonych
+ }
+pdfjs-views-manager-pages-status-none-action-label = Zaznacz strony
+pdfjs-views-manager-pages-status-action-button-label = Zarządzaj
+pdfjs-views-manager-pages-status-copy-button-label = Kopiuj
+pdfjs-views-manager-pages-status-cut-button-label = Wytnij
+pdfjs-views-manager-pages-status-delete-button-label = Usuń
+pdfjs-views-manager-pages-status-export-selected-button-label = Eksportuj zaznaczone…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Wycięto 1 stronę
+ [few] Wycięto { $count } strony
+ *[many] Wycięto { $count } stron
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Skopiowano 1 stronę
+ [few] Skopiowano { $count } strony
+ *[many] Skopiowano { $count } stron
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Usunięto 1 stronę
+ [few] Usunięto { $count } strony
+ *[many] Usunięto { $count } stron
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Przygotowywanie pliku…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Przesyłanie pliku…
+pdfjs-views-manager-status-warning-cut-label = Nie udało się wyciąć. Odśwież stronę i spróbuj ponownie.
+pdfjs-views-manager-status-warning-copy-label = Nie udało się skopiować. Odśwież stronę i spróbuj ponownie.
+pdfjs-views-manager-status-warning-delete-label = Nie udało się usunąć. Odśwież stronę i spróbuj ponownie.
+pdfjs-views-manager-status-warning-save-label = Nie udało się zachować. Odśwież stronę i spróbuj ponownie.
+pdfjs-views-manager-status-undo-button-label = Cofnij
+pdfjs-views-manager-status-done-button-label = Gotowe
+pdfjs-views-manager-status-close-button =
+ .title = Zamknij
+pdfjs-views-manager-status-close-button-label = Zamknij
+pdfjs-views-manager-paste-button-label = Wklej
+pdfjs-views-manager-paste-button-before =
+ .title = Wklej przed pierwszą stroną
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Wklej po { $page }. stronie
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = Nowe
+pdfjs-views-manager-waiting-for-file = Przesyłanie pliku…
+pdfjs-toggle-views-manager-button1 =
+ .title = Zarządzaj stronami
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Właściwości podpisu cyfrowego
+ .aria-label = Właściwości podpisu cyfrowego
+pdfjs-digital-signature-properties-button-label = Właściwości podpisu cyfrowego
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument został podpisany ważnym podpisem cyfrowym
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument jest popisany, ale nie można zweryfikować { $count } podpisu cyfrowego
+ [few] Dokument jest popisany, ale nie można zweryfikować { $count } podpisów cyfrowych
+ *[many] Dokument jest popisany, ale nie można zweryfikować { $count } podpisów cyfrowych
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument jest podpisany za pomocą { $count } certyfikatu, który nie jest zaufany
+ [few] Dokument jest podpisany za pomocą { $count } certyfikatów, które nie są zaufane
+ *[many] Dokument jest podpisany za pomocą { $count } certyfikatów, które nie są zaufane
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument jest podpisany za pomocą { $count } wygasłego certyfikatu
+ [few] Dokument jest podpisany za pomocą { $count } wygasłych certyfikatów
+ *[many] Dokument jest podpisany za pomocą { $count } wygasłych certyfikatów
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument ma { $count } nieważny podpis cyfrowy
+ [few] Dokument ma { $count } nieważne podpisy cyfrowe
+ *[many] Dokument ma { $count } nieważnych podpisów cyfrowych
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument jest podpisany za pomocą { $count } odwołanego certyfikatu
+ [few] Dokument jest podpisany za pomocą { $count } odwołanych certyfikatów
+ *[many] Dokument jest podpisany za pomocą { $count } odwołanych certyfikatów
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stan: podpis jest zweryfikowany
+pdfjs-digital-signature-properties-status-invalid = Stan: podpis jest nieważny
+pdfjs-digital-signature-properties-status-unknown = Stan: nie można zweryfikować (nieobsługiwane)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certyfikat: zaufany ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certyfikat: niedostępny
+pdfjs-digital-signature-properties-certificate-untrusted = Certyfikat: niezaufany
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certyfikat: nieznany wystawca ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certyfikat: samopodpisany ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certyfikat: niezaufany wystawca ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certyfikat: wygasły
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certyfikat: wygasły ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certyfikat: odwołany
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Usuń zachowany podpis
+pdfjs-editor-delete-signature-button-label1 = Usuń zachowany podpis
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Edytuj opis
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Edycja opisu
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pt-BR/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pt-BR/viewer.ftl
new file mode 100644
index 0000000..839c886
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pt-BR/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Próxima página
+pdfjs-next-button-label = Próxima
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Página
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Reduzir
+pdfjs-zoom-out-button-label = Reduzir
+pdfjs-zoom-in-button =
+ .title = Ampliar
+pdfjs-zoom-in-button-label = Ampliar
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Mudar para o modo de apresentação
+pdfjs-presentation-mode-button-label = Modo de apresentação
+pdfjs-open-file-button =
+ .title = Abrir arquivo
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Salvar
+pdfjs-save-button-label = Salvar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Baixar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Baixar
+pdfjs-bookmark-button =
+ .title = Página atual (ver URL da página atual)
+pdfjs-bookmark-button-label = Pagina atual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ferramentas
+pdfjs-tools-button-label = Ferramentas
+pdfjs-first-page-button =
+ .title = Ir para a primeira página
+pdfjs-first-page-button-label = Ir para a primeira página
+pdfjs-last-page-button =
+ .title = Ir para a última página
+pdfjs-last-page-button-label = Ir para a última página
+pdfjs-page-rotate-cw-button =
+ .title = Girar no sentido horário
+pdfjs-page-rotate-cw-button-label = Girar no sentido horário
+pdfjs-page-rotate-ccw-button =
+ .title = Girar no sentido anti-horário
+pdfjs-page-rotate-ccw-button-label = Girar no sentido anti-horário
+pdfjs-cursor-text-select-tool-button =
+ .title = Ativar a ferramenta de seleção de texto
+pdfjs-cursor-text-select-tool-button-label = Ferramenta de seleção de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Ativar ferramenta de deslocamento
+pdfjs-cursor-hand-tool-button-label = Ferramenta de deslocamento
+pdfjs-scroll-page-button =
+ .title = Usar rolagem de página
+pdfjs-scroll-page-button-label = Rolagem de página
+pdfjs-scroll-vertical-button =
+ .title = Usar deslocamento vertical
+pdfjs-scroll-vertical-button-label = Deslocamento vertical
+pdfjs-scroll-horizontal-button =
+ .title = Usar deslocamento horizontal
+pdfjs-scroll-horizontal-button-label = Deslocamento horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Usar deslocamento contido
+pdfjs-scroll-wrapped-button-label = Deslocamento contido
+pdfjs-spread-none-button =
+ .title = Não reagrupar páginas
+pdfjs-spread-none-button-label = Não estender
+pdfjs-spread-odd-button =
+ .title = Agrupar páginas começando em páginas com números ímpares
+pdfjs-spread-odd-button-label = Estender ímpares
+pdfjs-spread-even-button =
+ .title = Agrupar páginas começando em páginas com números pares
+pdfjs-spread-even-button-label = Estender pares
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propriedades do documento…
+pdfjs-document-properties-button-label = Propriedades do documento…
+pdfjs-document-properties-file-name = Nome do arquivo:
+pdfjs-document-properties-file-size = Tamanho do arquivo:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Assunto:
+pdfjs-document-properties-keywords = Palavras-chave:
+pdfjs-document-properties-creation-date = Data da criação:
+pdfjs-document-properties-modification-date = Data da modificação:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Criação:
+pdfjs-document-properties-producer = Criador do PDF:
+pdfjs-document-properties-version = Versão do PDF:
+pdfjs-document-properties-page-count = Número de páginas:
+pdfjs-document-properties-page-size = Tamanho da página:
+pdfjs-document-properties-page-size-unit-inches = pol.
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = retrato
+pdfjs-document-properties-page-size-orientation-landscape = paisagem
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Jurídico
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Exibição web rápida:
+pdfjs-document-properties-linearized-yes = Sim
+pdfjs-document-properties-linearized-no = Não
+pdfjs-document-properties-close-button = Fechar
+pdfjs-digital-signature-properties-view-certificate = Ver certificado
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Motivo: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Data e hora: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Assinatura secundária ({ $count })
+ *[other] Assinaturas secundárias ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Preparando documento para impressão…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Aviso: a impressão não é totalmente suportada neste navegador.
+pdfjs-printing-not-ready = Aviso: o PDF não está totalmente carregado para impressão.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Exibir/ocultar painel lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Exibir/ocultar painel lateral (documento contém estrutura/anexos/camadas)
+pdfjs-toggle-sidebar-button-label = Exibir/ocultar painel lateral
+pdfjs-document-outline-button =
+ .title = Mostrar estrutura do documento (duplo-clique expande/recolhe todos os itens)
+pdfjs-document-outline-button-label = Estrutura do documento
+pdfjs-attachments-button =
+ .title = Mostrar anexos
+pdfjs-attachments-button-label = Anexos
+pdfjs-layers-button =
+ .title = Mostrar camadas (duplo-clique redefine todas as camadas ao estado predefinido)
+pdfjs-layers-button-label = Camadas
+pdfjs-thumbs-button =
+ .title = Mostrar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Encontrar item atual da estrutura
+pdfjs-current-outline-item-button-label = Item atual da estrutura
+pdfjs-findbar-button =
+ .title = Procurar no documento
+pdfjs-findbar-button-label = Procurar
+pdfjs-additional-layers = Camadas adicionais
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura da página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Selecionar página { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Página { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Procurar
+ .placeholder = Procurar no documento…
+pdfjs-find-previous-button =
+ .title = Procurar a ocorrência anterior da frase
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Procurar a próxima ocorrência da frase
+pdfjs-find-next-button-label = Próxima
+pdfjs-find-highlight-checkbox = Destacar tudo
+pdfjs-find-match-case-checkbox-label = Diferenciar maiúsculas/minúsculas
+pdfjs-find-match-diacritics-checkbox-label = Considerar acentuação
+pdfjs-find-entire-word-checkbox-label = Palavras completas
+pdfjs-find-reached-top = Início do documento alcançado, continuando do fim
+pdfjs-find-reached-bottom = Fim do documento alcançado, continuando do início
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } de { $total } ocorrência
+ *[other] { $current } de { $total } ocorrências
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mais de { $limit } ocorrência
+ *[other] Mais de { $limit } ocorrências
+ }
+pdfjs-find-not-found = Não encontrado
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Largura da página
+pdfjs-page-scale-fit = Ajustar à janela
+pdfjs-page-scale-auto = Zoom automático
+pdfjs-page-scale-actual = Tamanho real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Página { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ocorreu um erro ao carregar o PDF.
+pdfjs-invalid-file-error = Arquivo PDF corrompido ou inválido.
+pdfjs-missing-file-error = Arquivo PDF ausente.
+pdfjs-unexpected-response-error = Resposta inesperada do servidor.
+pdfjs-rendering-error = Ocorreu um erro ao renderizar a página.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotação { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Forneça a senha para abrir este arquivo PDF.
+pdfjs-password-invalid = Senha inválida. Tente novamente.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = As fontes web estão desativadas: não foi possível usar fontes incorporadas do PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Mudar cor do texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Desenho
+pdfjs-editor-color-picker-ink-input =
+ .title = Mudar cor do desenho
+pdfjs-editor-ink-button-label = Desenho
+pdfjs-editor-stamp-button =
+ .title = Adicionar ou editar imagens
+pdfjs-editor-stamp-button-label = Adicionar ou editar imagens
+pdfjs-editor-highlight-button =
+ .title = Destaque
+pdfjs-editor-highlight-button-label = Destaque
+pdfjs-highlight-floating-button1 =
+ .title = Destaque
+ .aria-label = Destaque
+pdfjs-highlight-floating-button-label = Destaque
+pdfjs-comment-floating-button =
+ .title = Comentário
+ .aria-label = Comentário
+pdfjs-comment-floating-button-label = Comentário
+pdfjs-editor-comment-button =
+ .title = Comentar
+ .aria-label = Comentar
+pdfjs-editor-comment-button-label = Comentar
+pdfjs-editor-signature-button =
+ .title = Adicionar assinatura
+pdfjs-editor-signature-button-label = Adicionar assinatura
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de destaque
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de desenho
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de assinatura: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imagem
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Remover desenho
+pdfjs-editor-remove-freetext-button =
+ .title = Remover texto
+pdfjs-editor-remove-stamp-button =
+ .title = Remover imagem
+pdfjs-editor-remove-highlight-button =
+ .title = Remover destaque
+pdfjs-editor-remove-signature-button =
+ .title = Remover assinatura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Cor
+pdfjs-editor-free-text-size-input = Tamanho
+pdfjs-editor-ink-color-input = Cor
+pdfjs-editor-ink-thickness-input = Espessura
+pdfjs-editor-ink-opacity-input = Opacidade
+pdfjs-editor-stamp-add-image-button =
+ .title = Adicionar imagem
+pdfjs-editor-stamp-add-image-button-label = Adicionar imagem
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Espessura
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Mudar espessura ao destacar itens que não são texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controles de assinatura e assinaturas salvas
+pdfjs-editor-signature-add-signature-button =
+ .title = Adicionar nova assinatura
+pdfjs-editor-signature-add-signature-button-label = Adicionar nova assinatura
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Assinatura salva: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Comece a digitar…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentário
+ *[other] Comentários
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Fechar painel lateral
+ .aria-label = Fechar painel lateral
+pdfjs-editor-comments-sidebar-close-button-label = Fechar painel lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Viu algo digno de atenção? Destaque e deixe um comentário.
+pdfjs-editor-comments-sidebar-no-comments-link = Saiba mais
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar texto alternativo
+pdfjs-editor-alt-text-dialog-label = Escolha uma opção
+pdfjs-editor-alt-text-dialog-description = O texto alternativo ajuda quando uma imagem não aparece ou não é carregada.
+pdfjs-editor-alt-text-add-description-label = Adicionar uma descrição
+pdfjs-editor-alt-text-add-description-description = Procure usar uma ou duas frases que descrevam o assunto, cenário ou ação.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativa
+pdfjs-editor-alt-text-mark-decorative-description = Isto é usado em imagens ornamentais, como bordas ou marcas d'água.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Salvar
+pdfjs-editor-alt-text-decorative-tooltip = Marcado como decorativa
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por exemplo, “Um jovem senta-se à mesa para comer uma refeição”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Canto superior esquerdo — redimensionar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = No centro do topo — redimensionar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Canto superior direito — redimensionar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = No meio à direita — redimensionar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Canto inferior direito — redimensionar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = No centro da base — redimensionar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Canto inferior esquerdo — redimensionar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = No meio à esquerda — redimensionar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Cor de destaque
+pdfjs-editor-colorpicker-button =
+ .title = Mudar cor
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opções de cores
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarelo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Vermelho
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostrar todos
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostrar todos
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descrição da imagem)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Adicionar texto alternativo (descrição da imagem)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Você pode escrever uma descrição aqui…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Descrição curta para pessoas que não conseguem ver a imagem ou quando a imagem não é carregada.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo foi criado automaticamente, pode não estar correto.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Saiba mais
+pdfjs-editor-new-alt-text-create-automatically-button-label = Criar texto alternativo automaticamente
+pdfjs-editor-new-alt-text-not-now-button = Agora não
+pdfjs-editor-new-alt-text-error-title = Não foi possível criar texto alternativo automaticamente
+pdfjs-editor-new-alt-text-error-description = Escreva seu próprio texto alternativo ou tente novamente mais tarde.
+pdfjs-editor-new-alt-text-error-close-button = Fechar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Baixando modelo de inteligência artificial de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Baixando modelo de inteligência artificial de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Texto alternativo adicionado
+pdfjs-editor-new-alt-text-added-button-label = Texto alternativo adicionado
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Sem texto alternativo
+pdfjs-editor-new-alt-text-missing-button-label = Sem texto alternativo
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revisar texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Revisar texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Criado automaticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Configurações de texto alternativo de imagens
+pdfjs-image-alt-text-settings-button-label = Configurações de texto alternativo de imagens
+pdfjs-editor-alt-text-settings-dialog-label = Configurações de texto alternativo de imagens
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Criar texto alternativo automaticamente
+pdfjs-editor-alt-text-settings-create-model-description = Sugere uma descrição para ajudar pessoas que não conseguem ver a imagem ou quando a imagem não é carregada.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de inteligência artificial de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Funciona localmente no seu dispositivo para que seus dados permaneçam privativos. Necessário para texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Excluir
+pdfjs-editor-alt-text-settings-download-model-button = Baixar
+pdfjs-editor-alt-text-settings-downloading-model-button = Baixando…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar o editor de texto alternativo imediatamente ao adicionar uma imagem
+pdfjs-editor-alt-text-settings-show-dialog-description = Ajuda a assegurar que todas as suas imagens tenham texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Fechar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Destaque adicionado
+pdfjs-editor-freetext-added-alert = Texto adicionado
+pdfjs-editor-ink-added-alert = Desenho adicionado
+pdfjs-editor-stamp-added-alert = Imagem adicionada
+pdfjs-editor-signature-added-alert = Assinatura adicionada
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Destaque removido
+pdfjs-editor-undo-bar-message-freetext = Texto removido
+pdfjs-editor-undo-bar-message-ink = Desenho removido
+pdfjs-editor-undo-bar-message-stamp = Imagem removida
+pdfjs-editor-undo-bar-message-signature = Assinatura removida
+pdfjs-editor-undo-bar-message-comment = Comentário removido
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotação removida
+ *[other] { $count } anotações removidas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Desfazer
+pdfjs-editor-undo-bar-undo-button-label = Desfazer
+pdfjs-editor-undo-bar-close-button =
+ .title = Fechar
+pdfjs-editor-undo-bar-close-button-label = Fechar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Esta janela permite ao usuário criar uma assinatura para adicionar a um documento PDF. O usuário pode editar o nome (que também serve como texto alternativo) e, opcionalmente, salvar a assinatura usar novamente.
+pdfjs-editor-add-signature-dialog-title = Adicionar uma assinatura
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Digitar
+ .title = Digitar
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Desenhar
+ .title = Desenhar
+pdfjs-editor-add-signature-image-button = Imagem
+ .title = Imagem
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Digite sua assinatura
+ .placeholder = Digite sua assinatura
+pdfjs-editor-add-signature-draw-placeholder = Desenhe sua assinatura
+pdfjs-editor-add-signature-draw-thickness-range-label = Espessura
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Espessura do desenho: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arraste um arquivo aqui para enviar
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ou escolha arquivos de imagem
+ *[other] Ou escolha arquivos de imagem
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descrição (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descrição (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Assinatura
+pdfjs-editor-add-signature-clear-button-label = Limpar assinatura
+pdfjs-editor-add-signature-clear-button =
+ .title = Limpar assinatura
+pdfjs-editor-add-signature-save-checkbox = Salvar assinatura
+pdfjs-editor-add-signature-save-warning-message = Você atingiu o limite de 5 assinaturas salvas. Remova uma para salvar mais.
+pdfjs-editor-add-signature-image-upload-error-title = Não foi possível enviar a imagem
+pdfjs-editor-add-signature-image-upload-error-description = Verifique sua conexão de rede ou tente outra imagem.
+pdfjs-editor-add-signature-image-no-data-error-title = Não é possível converter esta imagem em uma assinatura
+pdfjs-editor-add-signature-image-no-data-error-description = Experimente enviar outra imagem.
+pdfjs-editor-add-signature-error-close-button = Fechar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Adicionar
+pdfjs-editor-edit-signature-update-button = Atualizar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editar comentário
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editar comentário
+pdfjs-editor-delete-comment-popup-button-label = Remover comentário
+pdfjs-editor-delete-comment-popup-button =
+ .title = Remover comentário
+pdfjs-show-comment-button =
+ .title = Mostrar comentário
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editar comentário
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Atualizar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Adicionar comentário
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Adicionar
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Começar a digitar…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancelar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Adicionar comentário
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Exibir/ocultar painel lateral (documento contém miniaturas/estrutura/anexos/camadas)
+pdfjs-toggle-views-manager-button1-label = Gerenciar páginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Painel lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionador do painel lateral
+pdfjs-views-manager-view-selector-button =
+ .title = Exibição
+pdfjs-views-manager-view-selector-button-label = Exibição
+pdfjs-views-manager-pages-title = Páginas
+pdfjs-views-manager-outlines-title1 = Estrutura do documento
+ .title = Estrutura do documento (duplo clique para expandir/recolher todos os itens)
+pdfjs-views-manager-attachments-title = Anexos
+pdfjs-views-manager-layers-title1 = Camadas
+ .title = Camadas (duplo clique para redefinir todas as camadas ao estado padrão)
+pdfjs-views-manager-pages-option-label = Páginas
+pdfjs-views-manager-outlines-option-label = Estrutura do documento
+pdfjs-views-manager-attachments-option-label = Anexos
+pdfjs-views-manager-layers-option-label = Camadas
+pdfjs-views-manager-add-file-button =
+ .title = Adicionar arquivo
+pdfjs-views-manager-add-file-button-label = Adicionar arquivo
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selecionada
+ *[other] { $count } selecionadas
+ }
+pdfjs-views-manager-pages-status-none-action-label = Selecionar páginas
+pdfjs-views-manager-pages-status-action-button-label = Gerenciar
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Cortar
+pdfjs-views-manager-pages-status-delete-button-label = Excluir
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar selecionados…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 página cortada
+ *[other] { $count } páginas cortadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 página copiada
+ *[other] { $count } páginas copiadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 página excluída
+ *[other] { $count } páginas excluídas
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Preparando seu arquivo…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Enviando arquivo…
+pdfjs-views-manager-status-warning-cut-label = Não foi possível cortar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-warning-copy-label = Não foi possível copiar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-warning-delete-label = Não foi possível excluir. Atualize a página e tente novamente.
+pdfjs-views-manager-status-warning-save-label = Não foi possível salvar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-undo-button-label = Desfazer
+pdfjs-views-manager-status-done-button-label = Pronto
+pdfjs-views-manager-status-close-button =
+ .title = Fechar
+pdfjs-views-manager-status-close-button-label = Fechar
+pdfjs-views-manager-paste-button-label = Colar
+pdfjs-views-manager-paste-button-before =
+ .title = Colar antes da primeira página
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Colar após a página { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVIDADE
+pdfjs-views-manager-waiting-for-file = Enviando arquivo…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gerenciar páginas
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Propriedades da assinatura digital
+ .aria-label = Propriedades da assinatura digital
+pdfjs-digital-signature-properties-button-label = Propriedades da assinatura digital
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = O documento foi assinado com uma assinatura digital válida
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Documento assinado, mas { $count } assinatura digital não pôde ser verificada
+ *[other] Documento assinado, mas { $count } assinaturas digitais não puderam ser verificadas
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Documento assinado com { $count } certificado que não é confiável
+ *[other] Documento assinado com { $count } certificados que não são confiáveis
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Documento assinado com { $count } certificado expirado
+ *[other] Documento assinado com { $count } certificados expirados
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] O documento tem { $count } assinatura digital inválida
+ *[other] O documento tem { $count } assinaturas digitais inválidas
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Documento assinado com { $count } certificado revogado
+ *[other] Documento assinado com { $count } certificados revogados
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Assinatura verificada
+pdfjs-digital-signature-properties-status-invalid = Status: Assinatura inválida
+pdfjs-digital-signature-properties-status-unknown = Status: Não foi possível verificar (não há suporte)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificado: Confiável ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificado: Não disponível
+pdfjs-digital-signature-properties-certificate-untrusted = Certificado: Não confiável
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificado: Emissor desconhecido ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificado: Autoassinado ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificado: Emissor não confiável ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificado: Expirado
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificado: Expirado ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificado: Revogado
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Remover assinatura salva
+pdfjs-editor-delete-signature-button-label1 = Remover assinatura salva
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Mudar descrição
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Mudar descrição
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pt-PT/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pt-PT/viewer.ftl
new file mode 100644
index 0000000..136a45c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/pt-PT/viewer.ftl
@@ -0,0 +1,747 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Página anterior
+pdfjs-previous-button-label = Anterior
+pdfjs-next-button =
+ .title = Página seguinte
+pdfjs-next-button-label = Seguinte
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Página
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Reduzir
+pdfjs-zoom-out-button-label = Reduzir
+pdfjs-zoom-in-button =
+ .title = Ampliar
+pdfjs-zoom-in-button-label = Ampliar
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Trocar para o modo de apresentação
+pdfjs-presentation-mode-button-label = Modo de apresentação
+pdfjs-open-file-button =
+ .title = Abrir ficheiro
+pdfjs-open-file-button-label = Abrir
+pdfjs-print-button =
+ .title = Imprimir
+pdfjs-print-button-label = Imprimir
+pdfjs-save-button =
+ .title = Guardar
+pdfjs-save-button-label = Guardar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Transferir
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Transferir
+pdfjs-bookmark-button =
+ .title = Página atual (ver URL da página atual)
+pdfjs-bookmark-button-label = Pagina atual
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Ferramentas
+pdfjs-tools-button-label = Ferramentas
+pdfjs-first-page-button =
+ .title = Ir para a primeira página
+pdfjs-first-page-button-label = Ir para a primeira página
+pdfjs-last-page-button =
+ .title = Ir para a última página
+pdfjs-last-page-button-label = Ir para a última página
+pdfjs-page-rotate-cw-button =
+ .title = Rodar à direita
+pdfjs-page-rotate-cw-button-label = Rodar à direita
+pdfjs-page-rotate-ccw-button =
+ .title = Rodar à esquerda
+pdfjs-page-rotate-ccw-button-label = Rodar à esquerda
+pdfjs-cursor-text-select-tool-button =
+ .title = Ativar ferramenta de seleção de texto
+pdfjs-cursor-text-select-tool-button-label = Ferramenta de seleção de texto
+pdfjs-cursor-hand-tool-button =
+ .title = Ativar ferramenta de mão
+pdfjs-cursor-hand-tool-button-label = Ferramenta de mão
+pdfjs-scroll-page-button =
+ .title = Utilizar deslocamento da página
+pdfjs-scroll-page-button-label = Deslocamento da página
+pdfjs-scroll-vertical-button =
+ .title = Utilizar deslocação vertical
+pdfjs-scroll-vertical-button-label = Deslocação vertical
+pdfjs-scroll-horizontal-button =
+ .title = Utilizar deslocação horizontal
+pdfjs-scroll-horizontal-button-label = Deslocação horizontal
+pdfjs-scroll-wrapped-button =
+ .title = Utilizar deslocação encapsulada
+pdfjs-scroll-wrapped-button-label = Deslocação encapsulada
+pdfjs-spread-none-button =
+ .title = Não juntar páginas dispersas
+pdfjs-spread-none-button-label = Sem spreads
+pdfjs-spread-odd-button =
+ .title = Juntar páginas dispersas a partir de páginas com números ímpares
+pdfjs-spread-odd-button-label = Spreads ímpares
+pdfjs-spread-even-button =
+ .title = Juntar páginas dispersas a partir de páginas com números pares
+pdfjs-spread-even-button-label = Spreads pares
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propriedades do documento…
+pdfjs-document-properties-button-label = Propriedades do documento…
+pdfjs-document-properties-file-name = Nome do ficheiro:
+pdfjs-document-properties-file-size = Tamanho do ficheiro:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Título:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Assunto:
+pdfjs-document-properties-keywords = Palavras-chave:
+pdfjs-document-properties-creation-date = Data de criação:
+pdfjs-document-properties-modification-date = Data de modificação:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Criador:
+pdfjs-document-properties-producer = Produtor de PDF:
+pdfjs-document-properties-version = Versão do PDF:
+pdfjs-document-properties-page-count = N.º de páginas:
+pdfjs-document-properties-page-size = Tamanho da página:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = retrato
+pdfjs-document-properties-page-size-orientation-landscape = paisagem
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Carta
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista rápida web:
+pdfjs-document-properties-linearized-yes = Sim
+pdfjs-document-properties-linearized-no = Não
+pdfjs-document-properties-close-button = Fechar
+
+## Print
+
+pdfjs-print-progress-message = A preparar o documento para impressão…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Cancelar
+pdfjs-printing-not-supported = Aviso: a impressão não é totalmente suportada por este navegador.
+pdfjs-printing-not-ready = Aviso: o PDF ainda não está totalmente carregado.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Alternar barra lateral
+pdfjs-toggle-sidebar-notification-button =
+ .title = Alternar barra lateral (o documento contém contornos/anexos/camadas)
+pdfjs-toggle-sidebar-button-label = Alternar barra lateral
+pdfjs-document-outline-button =
+ .title = Mostrar esquema do documento (duplo clique para expandir/colapsar todos os itens)
+pdfjs-document-outline-button-label = Esquema do documento
+pdfjs-attachments-button =
+ .title = Mostrar anexos
+pdfjs-attachments-button-label = Anexos
+pdfjs-layers-button =
+ .title = Mostrar camadas (clique duas vezes para repor todas as camadas para o estado predefinido)
+pdfjs-layers-button-label = Camadas
+pdfjs-thumbs-button =
+ .title = Mostrar miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Encontrar o item atualmente destacado
+pdfjs-current-outline-item-button-label = Item atualmente destacado
+pdfjs-findbar-button =
+ .title = Localizar em documento
+pdfjs-findbar-button-label = Localizar
+pdfjs-additional-layers = Camadas adicionais
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura da página { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Selecionar a página { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Página { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Localizar
+ .placeholder = Localizar em documento…
+pdfjs-find-previous-button =
+ .title = Localizar ocorrência anterior da frase
+pdfjs-find-previous-button-label = Anterior
+pdfjs-find-next-button =
+ .title = Localizar ocorrência seguinte da frase
+pdfjs-find-next-button-label = Seguinte
+pdfjs-find-highlight-checkbox = Destacar tudo
+pdfjs-find-match-case-checkbox-label = Correspondência
+pdfjs-find-match-diacritics-checkbox-label = Corresponder diacríticos
+pdfjs-find-entire-word-checkbox-label = Palavras completas
+pdfjs-find-reached-top = Topo do documento atingido, a continuar a partir do fundo
+pdfjs-find-reached-bottom = Fim do documento atingido, a continuar a partir do topo
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } de { $total } correspondência
+ *[other] { $current } de { $total } correspondências
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mais de { $limit } correspondência
+ *[other] Mais de { $limit } correspondências
+ }
+pdfjs-find-not-found = Frase não encontrada
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ajustar à largura
+pdfjs-page-scale-fit = Ajustar à página
+pdfjs-page-scale-auto = Zoom automático
+pdfjs-page-scale-actual = Tamanho real
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Página { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ocorreu um erro ao carregar o PDF.
+pdfjs-invalid-file-error = Ficheiro PDF inválido ou danificado.
+pdfjs-missing-file-error = Ficheiro PDF inexistente.
+pdfjs-unexpected-response-error = Resposta inesperada do servidor.
+pdfjs-rendering-error = Ocorreu um erro ao processar a página.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotação { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Introduza a palavra-passe para abrir este ficheiro PDF.
+pdfjs-password-invalid = Palavra-passe inválida. Por favor, tente novamente.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Cancelar
+pdfjs-web-fonts-disabled = Os tipos de letra web estão desativados: não é possível utilizar os tipos de letra PDF embutidos.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Texto
+pdfjs-editor-color-picker-free-text-input =
+ .title = Alterar cor do texto
+pdfjs-editor-free-text-button-label = Texto
+pdfjs-editor-ink-button =
+ .title = Desenhar
+pdfjs-editor-color-picker-ink-input =
+ .title = Alterar a cor de desenho
+pdfjs-editor-ink-button-label = Desenhar
+pdfjs-editor-stamp-button =
+ .title = Adicionar ou editar imagens
+pdfjs-editor-stamp-button-label = Adicionar ou editar imagens
+pdfjs-editor-highlight-button =
+ .title = Destaque
+pdfjs-editor-highlight-button-label = Destaque
+pdfjs-highlight-floating-button1 =
+ .title = Realçar
+ .aria-label = Realçar
+pdfjs-highlight-floating-button-label = Realçar
+pdfjs-comment-floating-button =
+ .title = Comentário
+ .aria-label = Comentário
+pdfjs-comment-floating-button-label = Comentário
+pdfjs-editor-comment-button =
+ .title = Comentário
+ .aria-label = Comentário
+pdfjs-editor-comment-button-label = Comentário
+pdfjs-editor-signature-button =
+ .title = Adicionar assinatura
+pdfjs-editor-signature-button-label = Adicionar assinatura
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de realce
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de desenho
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de assinatura: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imagem
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Remover desenho
+pdfjs-editor-remove-freetext-button =
+ .title = Remover texto
+pdfjs-editor-remove-stamp-button =
+ .title = Remover imagem
+pdfjs-editor-remove-highlight-button =
+ .title = Remover destaque
+pdfjs-editor-remove-signature-button =
+ .title = Remover assinatura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Cor
+pdfjs-editor-free-text-size-input = Tamanho
+pdfjs-editor-ink-color-input = Cor
+pdfjs-editor-ink-thickness-input = Espessura
+pdfjs-editor-ink-opacity-input = Opacidade
+pdfjs-editor-stamp-add-image-button =
+ .title = Adicionar imagem
+pdfjs-editor-stamp-add-image-button-label = Adicionar imagem
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Espessura
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Alterar espessura quando destacar itens que não sejam texto
+pdfjs-editor-add-signature-container =
+ .aria-label = Controlos de assinatura e assinaturas guardadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Adicionar nova assinatura
+pdfjs-editor-signature-add-signature-button-label = Adicionar nova assinatura
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Assinatura guardada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de texto
+ .default-content = Comece a escrever…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Comentário
+ *[other] Comentários
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Fechar barra lateral
+ .aria-label = Fechar barra lateral
+pdfjs-editor-comments-sidebar-close-button-label = Fechar barra lateral
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Viu algo interessante? Realce e adicione um comentário.
+pdfjs-editor-comments-sidebar-no-comments-link = Saber mais
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Texto alternativo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editar texto alternativo
+pdfjs-editor-alt-text-dialog-label = Escolher uma opção
+pdfjs-editor-alt-text-dialog-description = O texto alternativo (texto alternativo) ajuda quando as pessoas não conseguem ver a imagem ou quando a mesma não é carregada.
+pdfjs-editor-alt-text-add-description-label = Adicionar uma descrição
+pdfjs-editor-alt-text-add-description-description = Aponte para 1-2 frases que descrevam o assunto, definição ou ações.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar como decorativa
+pdfjs-editor-alt-text-mark-decorative-description = Isto é utilizado para imagens decorativas, tais como limites ou marcas d'água.
+pdfjs-editor-alt-text-cancel-button = Cancelar
+pdfjs-editor-alt-text-save-button = Guardar
+pdfjs-editor-alt-text-decorative-tooltip = Marcada como decorativa
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Por exemplo, “Um jovem senta-se à mesa para comer uma refeição”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Texto alternativo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Canto superior esquerdo — redimensionar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Superior ao centro — redimensionar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Canto superior direito — redimensionar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Centro à direita — redimensionar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Canto inferior direito — redimensionar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Inferior ao centro — redimensionar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Canto inferior esquerdo — redimensionar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Centro à esquerda — redimensionar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Cor de destaque
+pdfjs-editor-colorpicker-button =
+ .title = Alterar cor
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Escolhas de cor
+pdfjs-editor-colorpicker-yellow =
+ .title = Amarelo
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Azul
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Vermelho
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mostrar tudo
+pdfjs-editor-highlight-show-all-button =
+ .title = Mostrar tudo
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editar texto alternativo (descrição da imagem)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Adicionar texto alternativo (descrição da imagem)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Escreva a sua descrição aqui…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Descrição curta para as pessoas que não podem visualizar a imagem ou quando a imagem não carrega.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Este texto alternativo foi criado automaticamente e pode ser impreciso.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Saber mais
+pdfjs-editor-new-alt-text-create-automatically-button-label = Criar texto alternativo automaticamente
+pdfjs-editor-new-alt-text-not-now-button = Agora não
+pdfjs-editor-new-alt-text-error-title = Não foi possível criar o texto alternativo automaticamente
+pdfjs-editor-new-alt-text-error-description = Escreva o seu próprio texto alternativo ou tente novamente mais tarde.
+pdfjs-editor-new-alt-text-error-close-button = Fechar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = A transferir o modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = A transferir o modelo de IA de texto alternativo ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Texto alternativo adicionado
+pdfjs-editor-new-alt-text-added-button-label = Texto alternativo adicionado
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Texto alternativo em falta
+pdfjs-editor-new-alt-text-missing-button-label = Texto alternativo em falta
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Rever texto alternativo
+pdfjs-editor-new-alt-text-to-review-button-label = Rever texto alternativo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Criado automaticamente: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Definições de texto alternativo da imagem
+pdfjs-image-alt-text-settings-button-label = Definições de texto alternativo da imagem
+pdfjs-editor-alt-text-settings-dialog-label = Definições de texto alternativo das imagens
+pdfjs-editor-alt-text-settings-automatic-title = Texto alternativo automático
+pdfjs-editor-alt-text-settings-create-model-button-label = Criar texto alternativo automaticamente
+pdfjs-editor-alt-text-settings-create-model-description = Sugere descrições para ajudar as pessoas que não podem visualizar a imagem ou quando a imagem não carrega.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modelo de IA de texto alternativo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = É executado localmente no seu dispositivo para que os seus dados se mantenham privados. É necessário para o texto alternativo automático.
+pdfjs-editor-alt-text-settings-delete-model-button = Eliminar
+pdfjs-editor-alt-text-settings-download-model-button = Transferir
+pdfjs-editor-alt-text-settings-downloading-model-button = A transferir…
+pdfjs-editor-alt-text-settings-editor-title = Editor de texto alternativo
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mostrar editor de texto alternativo imediatamente ao adicionar uma imagem
+pdfjs-editor-alt-text-settings-show-dialog-description = Ajuda a garantir que todas as suas imagens tenham um texto alternativo.
+pdfjs-editor-alt-text-settings-close-button = Fechar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Destaque adicionado
+pdfjs-editor-freetext-added-alert = Texto adicionado
+pdfjs-editor-ink-added-alert = Desenho adicionado
+pdfjs-editor-stamp-added-alert = Imagem adicionada
+pdfjs-editor-signature-added-alert = Assinatura adicionada
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Destaque removido
+pdfjs-editor-undo-bar-message-freetext = Texto removido
+pdfjs-editor-undo-bar-message-ink = Desenho removido
+pdfjs-editor-undo-bar-message-stamp = Imagem removida
+pdfjs-editor-undo-bar-message-signature = Assinatura removida
+pdfjs-editor-undo-bar-message-comment = Comentário removido
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotação removida
+ *[other] { $count } anotações removidas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Anular
+pdfjs-editor-undo-bar-undo-button-label = Anular
+pdfjs-editor-undo-bar-close-button =
+ .title = Fechar
+pdfjs-editor-undo-bar-close-button-label = Fechar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Este modo permite ao utilizador criar uma assinatura para adicionar a um documento PDF. O utilizador pode editar o nome (que também funciona como texto alternativo) e, opcionalmente, guardar a assinatura para utilizações frequentes.
+pdfjs-editor-add-signature-dialog-title = Adicionar uma assinatura
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Digitar
+ .title = Digitar
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Desenhar
+ .title = Desenhar
+pdfjs-editor-add-signature-image-button = Imagem
+ .title = Imagem
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Digite a sua assinatura
+ .placeholder = Digite a sua assinatura
+pdfjs-editor-add-signature-draw-placeholder = Desenhe a sua assinatura
+pdfjs-editor-add-signature-draw-thickness-range-label = Espessura
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Espessura do desenho: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Arraste um ficheiro aqui para carregar
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ou escolha ficheiros de imagem
+ *[other] Ou explore ficheiros de imagem
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descrição (texto alternativo)
+pdfjs-editor-add-signature-description-input =
+ .title = Descrição (texto alternativo)
+pdfjs-editor-add-signature-description-default-when-drawing = Assinatura
+pdfjs-editor-add-signature-clear-button-label = Limpar assinatura
+pdfjs-editor-add-signature-clear-button =
+ .title = Limpar assinatura
+pdfjs-editor-add-signature-save-checkbox = Guardar assinatura
+pdfjs-editor-add-signature-save-warning-message = Atingiu o limite de 5 assinaturas guardadas. Remova uma para guardar mais.
+pdfjs-editor-add-signature-image-upload-error-title = Não foi possível carregar a imagem
+pdfjs-editor-add-signature-image-upload-error-description = Verifique a sua ligação à rede ou tente outra imagem.
+pdfjs-editor-add-signature-image-no-data-error-title = Não é possível converter esta imagem para uma assinatura
+pdfjs-editor-add-signature-image-no-data-error-description = Tente enviar uma imagem diferente.
+pdfjs-editor-add-signature-error-close-button = Fechar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Cancelar
+pdfjs-editor-add-signature-add-button = Adicionar
+pdfjs-editor-edit-signature-update-button = Atualizar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editar comentário
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editar comentário
+pdfjs-editor-delete-comment-popup-button-label = Remover comentário
+pdfjs-editor-delete-comment-popup-button =
+ .title = Remover comentário
+pdfjs-show-comment-button =
+ .title = Mostrar comentário
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editar comentário
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Atualizar
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Adicionar comentário
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Adicionar
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Comece a digitar…
+pdfjs-editor-edit-comment-dialog-cancel-button = Cancelar
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Adicionar comentário
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Alternar barra lateral (o documento inclui miniaturas/esquema/anexos/camadas)
+pdfjs-toggle-views-manager-button1-label = Gerir páginas
+pdfjs-views-manager-sidebar =
+ .aria-label = Barra lateral
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionador da barra lateral
+pdfjs-views-manager-view-selector-button =
+ .title = Vistas
+pdfjs-views-manager-view-selector-button-label = Vistas
+pdfjs-views-manager-pages-title = Páginas
+pdfjs-views-manager-outlines-title1 = Esquema do documento
+ .title = Esquema do documento (duplo clique para expandir/colapsar todos os itens)
+pdfjs-views-manager-attachments-title = Anexos
+pdfjs-views-manager-layers-title1 = Camadas
+ .title = Camadas (duplo clique para repor todas as camadas para o estado predefinido)
+pdfjs-views-manager-pages-option-label = Páginas
+pdfjs-views-manager-outlines-option-label = Esquema do documento
+pdfjs-views-manager-attachments-option-label = Anexos
+pdfjs-views-manager-layers-option-label = Camadas
+pdfjs-views-manager-add-file-button =
+ .title = Adicionar ficheiro
+pdfjs-views-manager-add-file-button-label = Adicionar ficheiro
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selecionada
+ *[other] { $count } selecionadas
+ }
+pdfjs-views-manager-pages-status-none-action-label = Selecionar páginas
+pdfjs-views-manager-pages-status-action-button-label = Gerir
+pdfjs-views-manager-pages-status-copy-button-label = Copiar
+pdfjs-views-manager-pages-status-cut-button-label = Cortar
+pdfjs-views-manager-pages-status-delete-button-label = Eliminar
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportar selecionado…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 página cortada
+ *[other] { $count } páginas cortadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 página copiada
+ *[other] { $count } páginas copiadas
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 página eliminada
+ *[other] { $count } páginas eliminadas
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = A preparar o seu ficheiro…
+pdfjs-views-manager-pages-status-waiting-uploading-label = A carregar ficheiro…
+pdfjs-views-manager-status-warning-cut-label = Não foi possível cortar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-warning-copy-label = Não foi possível copiar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-warning-delete-label = Não foi possível eliminar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-warning-save-label = Não foi possível guardar. Atualize a página e tente novamente.
+pdfjs-views-manager-status-undo-button-label = Desfazer
+pdfjs-views-manager-status-done-button-label = Feito
+pdfjs-views-manager-status-close-button =
+ .title = Fechar
+pdfjs-views-manager-status-close-button-label = Fechar
+pdfjs-views-manager-paste-button-label = Colar
+pdfjs-views-manager-paste-button-before =
+ .title = Colar antes da primeira página
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Colar depois da página { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVO
+pdfjs-views-manager-waiting-for-file = A carregar ficheiro…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gerir páginas
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Remover assinatura guardada
+pdfjs-editor-delete-signature-button-label1 = Remover assinatura guardada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editar descrição
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editar descrição
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/rm/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/rm/viewer.ftl
new file mode 100644
index 0000000..e632848
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/rm/viewer.ftl
@@ -0,0 +1,639 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagina precedenta
+pdfjs-previous-button-label = Enavos
+pdfjs-next-button =
+ .title = Proxima pagina
+pdfjs-next-button-label = Enavant
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = da { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } da { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Empitschnir
+pdfjs-zoom-out-button-label = Empitschnir
+pdfjs-zoom-in-button =
+ .title = Engrondir
+pdfjs-zoom-in-button-label = Engrondir
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Midar en il modus da preschentaziun
+pdfjs-presentation-mode-button-label = Modus da preschentaziun
+pdfjs-open-file-button =
+ .title = Avrir datoteca
+pdfjs-open-file-button-label = Avrir
+pdfjs-print-button =
+ .title = Stampar
+pdfjs-print-button-label = Stampar
+pdfjs-save-button =
+ .title = Memorisar
+pdfjs-save-button-label = Memorisar
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Telechargiar
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Telechargiar
+pdfjs-bookmark-button =
+ .title = Pagina actuala (mussar l'URL da la pagina actuala)
+pdfjs-bookmark-button-label = Pagina actuala
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Utensils
+pdfjs-tools-button-label = Utensils
+pdfjs-first-page-button =
+ .title = Siglir a l'emprima pagina
+pdfjs-first-page-button-label = Siglir a l'emprima pagina
+pdfjs-last-page-button =
+ .title = Siglir a la davosa pagina
+pdfjs-last-page-button-label = Siglir a la davosa pagina
+pdfjs-page-rotate-cw-button =
+ .title = Rotar en direcziun da l'ura
+pdfjs-page-rotate-cw-button-label = Rotar en direcziun da l'ura
+pdfjs-page-rotate-ccw-button =
+ .title = Rotar en direcziun cuntraria a l'ura
+pdfjs-page-rotate-ccw-button-label = Rotar en direcziun cuntraria a l'ura
+pdfjs-cursor-text-select-tool-button =
+ .title = Activar l'utensil per selecziunar text
+pdfjs-cursor-text-select-tool-button-label = Utensil per selecziunar text
+pdfjs-cursor-hand-tool-button =
+ .title = Activar l'utensil da maun
+pdfjs-cursor-hand-tool-button-label = Utensil da maun
+pdfjs-scroll-page-button =
+ .title = Utilisar la defilada per pagina
+pdfjs-scroll-page-button-label = Defilada per pagina
+pdfjs-scroll-vertical-button =
+ .title = Utilisar il defilar vertical
+pdfjs-scroll-vertical-button-label = Defilar vertical
+pdfjs-scroll-horizontal-button =
+ .title = Utilisar il defilar orizontal
+pdfjs-scroll-horizontal-button-label = Defilar orizontal
+pdfjs-scroll-wrapped-button =
+ .title = Utilisar il defilar en colonnas
+pdfjs-scroll-wrapped-button-label = Defilar en colonnas
+pdfjs-spread-none-button =
+ .title = Betg parallelisar las paginas
+pdfjs-spread-none-button-label = Betg parallel
+pdfjs-spread-odd-button =
+ .title = Parallelisar las paginas cun cumenzar cun paginas spèras
+pdfjs-spread-odd-button-label = Parallel spèr
+pdfjs-spread-even-button =
+ .title = Parallelisar las paginas cun cumenzar cun paginas pèras
+pdfjs-spread-even-button-label = Parallel pèr
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Caracteristicas dal document…
+pdfjs-document-properties-button-label = Caracteristicas dal document…
+pdfjs-document-properties-file-name = Num da la datoteca:
+pdfjs-document-properties-file-size = Grondezza da la datoteca:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Autur:
+pdfjs-document-properties-subject = Tema:
+pdfjs-document-properties-keywords = Chavazzins:
+pdfjs-document-properties-creation-date = Data da creaziun:
+pdfjs-document-properties-modification-date = Data da modificaziun:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Creà da:
+pdfjs-document-properties-producer = Creà il PDF cun:
+pdfjs-document-properties-version = Versiun da PDF:
+pdfjs-document-properties-page-count = Dumber da paginas:
+pdfjs-document-properties-page-size = Grondezza da la pagina:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = vertical
+pdfjs-document-properties-page-size-orientation-landscape = orizontal
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Gea
+pdfjs-document-properties-linearized-no = Na
+pdfjs-document-properties-close-button = Serrar
+
+## Print
+
+pdfjs-print-progress-message = Preparar il document per stampar…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Interrumper
+pdfjs-printing-not-supported = Attenziun: Il stampar na funcziunescha anc betg dal tut en quest navigatur.
+pdfjs-printing-not-ready = Attenziun: Il PDF n'è betg chargià cumplettamain per stampar.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Activar/deactivar la trav laterala
+pdfjs-toggle-sidebar-notification-button =
+ .title = Activar/deactivar la trav laterala (il document cuntegna structura dal document/agiuntas/nivels)
+pdfjs-toggle-sidebar-button-label = Activar/deactivar la trav laterala
+pdfjs-document-outline-button =
+ .title = Mussar la structura dal document (cliccar duas giadas per extender/cumprimer tut ils elements)
+pdfjs-document-outline-button-label = Structura dal document
+pdfjs-attachments-button =
+ .title = Mussar agiuntas
+pdfjs-attachments-button-label = Agiuntas
+pdfjs-layers-button =
+ .title = Mussar ils nivels (cliccar dubel per restaurar il stadi da standard da tut ils nivels)
+pdfjs-layers-button-label = Nivels
+pdfjs-thumbs-button =
+ .title = Mussar las miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Tschertgar l'element da structura actual
+pdfjs-current-outline-item-button-label = Element da structura actual
+pdfjs-findbar-button =
+ .title = Tschertgar en il document
+pdfjs-findbar-button-label = Tschertgar
+pdfjs-additional-layers = Nivels supplementars
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura da la pagina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Tschertgar
+ .placeholder = Tschertgar en il document…
+pdfjs-find-previous-button =
+ .title = Tschertgar la posiziun precedenta da l'expressiun
+pdfjs-find-previous-button-label = Enavos
+pdfjs-find-next-button =
+ .title = Tschertgar la proxima posiziun da l'expressiun
+pdfjs-find-next-button-label = Enavant
+pdfjs-find-highlight-checkbox = Relevar tuts
+pdfjs-find-match-case-checkbox-label = Resguardar maiusclas/minusclas
+pdfjs-find-match-diacritics-checkbox-label = Resguardar ils segns diacritics
+pdfjs-find-entire-word-checkbox-label = Pleds entirs
+pdfjs-find-reached-top = Il cumenzament dal document è cuntanschì, la tschertga cuntinuescha a la fin dal document
+pdfjs-find-reached-bottom = La fin dal document è cuntanschì, la tschertga cuntinuescha al cumenzament dal document
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } dad { $total } correspundenza
+ *[other] { $current } da { $total } correspundenzas
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Dapli che { $limit } correspundenza
+ *[other] Dapli che { $limit } correspundenzas
+ }
+pdfjs-find-not-found = Impussibel da chattar l'expressiun
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ladezza da la pagina
+pdfjs-page-scale-fit = Entira pagina
+pdfjs-page-scale-auto = Zoom automatic
+pdfjs-page-scale-actual = Grondezza actuala
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ina errur è cumparida cun chargiar il PDF.
+pdfjs-invalid-file-error = Datoteca PDF nunvalida u donnegiada.
+pdfjs-missing-file-error = Datoteca PDF manconta.
+pdfjs-unexpected-response-error = Resposta nunspetgada dal server.
+pdfjs-rendering-error = Ina errur è cumparida cun visualisar questa pagina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Annotaziun da { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Endatescha il pled-clav per avrir questa datoteca da PDF.
+pdfjs-password-invalid = Pled-clav nunvalid. Emprova anc ina giada.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Interrumper
+pdfjs-web-fonts-disabled = Scrittiras dal web èn deactivadas: impussibel dad utilisar las scrittiras integradas en il PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Midar la colur dal text
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Dissegnar
+pdfjs-editor-color-picker-ink-input =
+ .title = Midar la colur per dissegnar
+pdfjs-editor-ink-button-label = Dissegnar
+pdfjs-editor-stamp-button =
+ .title = Agiuntar u modifitgar maletgs
+pdfjs-editor-stamp-button-label = Agiuntar u modifitgar maletgs
+pdfjs-editor-highlight-button =
+ .title = Marcar
+pdfjs-editor-highlight-button-label = Marcar
+pdfjs-highlight-floating-button1 =
+ .title = Marcar
+ .aria-label = Marcar
+pdfjs-highlight-floating-button-label = Marcar
+pdfjs-comment-floating-button =
+ .title = Commentar
+ .aria-label = Commentar
+pdfjs-comment-floating-button-label = Commentar
+pdfjs-editor-comment-button =
+ .title = Commentari
+ .aria-label = Commentari
+pdfjs-editor-comment-button-label = Commentari
+pdfjs-editor-signature-button =
+ .title = Agiuntar ina signatura
+pdfjs-editor-signature-button-label = Agiuntar ina signatura
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editur per relevar
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editur per dissegnar
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editur da signatura: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editur per maletgs
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Allontanar il dissegn
+pdfjs-editor-remove-freetext-button =
+ .title = Allontanar il text
+pdfjs-editor-remove-stamp-button =
+ .title = Allontanar la grafica
+pdfjs-editor-remove-highlight-button =
+ .title = Allontanar l'emfasa
+pdfjs-editor-remove-signature-button =
+ .title = Allontanar la signatura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Colur
+pdfjs-editor-free-text-size-input = Grondezza
+pdfjs-editor-ink-color-input = Colur
+pdfjs-editor-ink-thickness-input = Grossezza
+pdfjs-editor-ink-opacity-input = Opacitad
+pdfjs-editor-stamp-add-image-button =
+ .title = Agiuntar in maletg
+pdfjs-editor-stamp-add-image-button-label = Agiuntar in maletg
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grossezza
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Midar la grossezza cun relevar elements betg textuals
+pdfjs-editor-add-signature-container =
+ .aria-label = Controllas da signatura e signaturas memorisadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Agiuntar ina nova signatura
+pdfjs-editor-signature-add-signature-button-label = Agiuntar ina nova signatura
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Signatura memorisada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editur da text
+ .default-content = Cumenza a tippar…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Commentari
+ *[other] Commentaris
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Serrar la trav laterala
+ .aria-label = Serrar la trav laterala
+pdfjs-editor-comments-sidebar-close-button-label = Serrar la trav laterala
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vesas insatge interessant? Marchescha la passascha ed agiuntescha in commentari.
+pdfjs-editor-comments-sidebar-no-comments-link = Ulteriuras infurmaziuns
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Text alternativ
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Modifitgar il text alternativ
+pdfjs-editor-alt-text-dialog-label = Tscherner ina opziun
+pdfjs-editor-alt-text-dialog-description = Il text alternativ (alt text) gida en cas che persunas na vesan betg il maletg u sch'i na reussescha betg d'al chargiar.
+pdfjs-editor-alt-text-add-description-label = Agiuntar ina descripziun
+pdfjs-editor-alt-text-add-description-description = Scriva idealmain 1-2 frasas che descrivan l'object, la situaziun u las acziuns.
+pdfjs-editor-alt-text-mark-decorative-label = Marcar sco decorativ
+pdfjs-editor-alt-text-mark-decorative-description = Quai vegn duvrà per maletgs ornamentals, sco urs u filigranas.
+pdfjs-editor-alt-text-cancel-button = Interrumper
+pdfjs-editor-alt-text-save-button = Memorisar
+pdfjs-editor-alt-text-decorative-tooltip = Marcà sco decorativ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Per exempel: «In um giuven sesa a maisa per mangiar in past»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Text alternativ
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Chantun sura a sanestra — redimensiunar
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Sura amez — redimensiunar
+pdfjs-editor-resizer-top-right =
+ .aria-label = Chantun sura a dretga — redimensiunar
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Da vart dretga amez — redimensiunar
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Chantun sut a dretga — redimensiunar
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Sutvart amez — redimensiunar
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Chantun sut a sanestra — redimensiunar
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Vart sanestra amez — redimensiunar
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Colur per l'emfasa
+pdfjs-editor-colorpicker-button =
+ .title = Midar la colur
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Colurs disponiblas
+pdfjs-editor-colorpicker-yellow =
+ .title = Mellen
+pdfjs-editor-colorpicker-green =
+ .title = Verd
+pdfjs-editor-colorpicker-blue =
+ .title = Blau
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Cotschen
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Mussar tut
+pdfjs-editor-highlight-show-all-button =
+ .title = Mussar tut
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Modifitgar il text alternativ (descripziun dal maletg)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Agiuntar in text alternativ (descripziun dal maletg)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Scriva qua tia descripziun…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Curta descripziun per persunas che na vesan betg il maletg u per cass en ils quals il maletg na vegn betg chargià.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Quest text alternativ è vegnì creà automaticamain ed è eventualmain nunprecis.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Ulteriuras infurmaziuns
+pdfjs-editor-new-alt-text-create-automatically-button-label = Crear automaticamain il text alternativ
+pdfjs-editor-new-alt-text-not-now-button = Betg ussa
+pdfjs-editor-new-alt-text-error-title = I n’è betg reussì da crear automaticamain il text alternativ
+pdfjs-editor-new-alt-text-error-description = Scriva per plaschair tes agen text alternativ u emprova pli tard anc ina giada.
+pdfjs-editor-new-alt-text-error-close-button = Serrar
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Telechargiar il model IA da text alternativ ({ $downloadedSize } da { $totalSize } MB)
+ .aria-valuetext = Telechargiar il model IA da text alternativ ({ $downloadedSize } da { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Agiuntà text alternativ
+pdfjs-editor-new-alt-text-added-button-label = Text alternativ agiuntà
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Text alternativ manca
+pdfjs-editor-new-alt-text-missing-button-label = Text alternativ manca
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Repassar il text alternativ
+pdfjs-editor-new-alt-text-to-review-button-label = Repassar il text alternativ
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creà automaticamain: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Parameters dal text alternativ da maletgs
+pdfjs-image-alt-text-settings-button-label = Parameters dal text alternativ da maletgs
+pdfjs-editor-alt-text-settings-dialog-label = Parameters dal text alternativ da maletgs
+pdfjs-editor-alt-text-settings-automatic-title = Text alternativ automatic
+pdfjs-editor-alt-text-settings-create-model-button-label = Crear automaticamain text alternativ
+pdfjs-editor-alt-text-settings-create-model-description = Propona descripziuns per gidar a persunas che na vesan betg il maletg u per cass en ils quals il maletg na vegn betg chargià.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model IA da text alternativ ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Vegn exequì localmain sin tes apparat per che tias datas restian privatas. Necessari per text alternativ automatic.
+pdfjs-editor-alt-text-settings-delete-model-button = Stizzar
+pdfjs-editor-alt-text-settings-download-model-button = Telechargiar
+pdfjs-editor-alt-text-settings-downloading-model-button = Telechargiar…
+pdfjs-editor-alt-text-settings-editor-title = Editur per text alternativ
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mussar l’editur per text alternativ directamain cun agiuntar in maletg
+pdfjs-editor-alt-text-settings-show-dialog-description = Ta gida a garantir che tut tes maletgs hajan in text alternativ.
+pdfjs-editor-alt-text-settings-close-button = Serrar
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Agiuntà ina emfasa
+pdfjs-editor-freetext-added-alert = Agiuntà in text
+pdfjs-editor-ink-added-alert = Agiuntà in dissegn
+pdfjs-editor-stamp-added-alert = Agiuntà in maletg
+pdfjs-editor-signature-added-alert = Agiuntà ina signatura
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Allontanà la marcaziun
+pdfjs-editor-undo-bar-message-freetext = Allontanà il text
+pdfjs-editor-undo-bar-message-ink = Allontanà il dissegn
+pdfjs-editor-undo-bar-message-stamp = Allontanà il maletg
+pdfjs-editor-undo-bar-message-signature = Allontanà la signatura
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } annotaziun allontanada
+ *[other] { $count } annotaziuns allontanadas
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Revocar
+pdfjs-editor-undo-bar-undo-button-label = Revocar
+pdfjs-editor-undo-bar-close-button =
+ .title = Serrar
+pdfjs-editor-undo-bar-close-button-label = Serrar
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Questa fanestra permetta a l’utilisader da crear ina signatura per l’agiuntar ad in document PDF. L’utilisader po modifitgar il num (che serva era sco text alternativ) e memorisar opziunalmain la signatura per l’utilisar anc ina giada en l’avegnir.
+pdfjs-editor-add-signature-dialog-title = Agiuntar ina signatura
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tippar
+ .title = Tippar
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Dissegnar
+ .title = Dissegnar
+pdfjs-editor-add-signature-image-button = Maletg
+ .title = Maletg
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Tippa tia signatura
+ .placeholder = Tippa tia signatura
+pdfjs-editor-add-signature-draw-placeholder = Dissegna tia signatura
+pdfjs-editor-add-signature-draw-thickness-range-label = Grossezza
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grossezza dal stritg: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Trair na qua ina datoteca per la transferir
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] U tscherner datotecas da maletg
+ *[other] U tscherner datotecas da maletg
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descripziun (text alternativ)
+pdfjs-editor-add-signature-description-input =
+ .title = Descripziun (text alternativ)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatura
+pdfjs-editor-add-signature-clear-button-label = Stizzar la signatura
+pdfjs-editor-add-signature-clear-button =
+ .title = Stizzar la signatura
+pdfjs-editor-add-signature-save-checkbox = Memorisar la signatura
+pdfjs-editor-add-signature-save-warning-message = Ti has cuntanschì il dumber maximal da 5 signaturas memorisadas. Allontanar ina per memorisar in’autra.
+pdfjs-editor-add-signature-image-upload-error-title = Impussibel da transferir il maletg
+pdfjs-editor-add-signature-image-upload-error-description = Controllescha tia connexiun cun la rait u emprova cun in’auter maletg.
+pdfjs-editor-add-signature-image-no-data-error-title = Impussibel da convertir quest maletg en ina signatura
+pdfjs-editor-add-signature-image-no-data-error-description = Emprova per plaschair da transferir in auter maletg.
+pdfjs-editor-add-signature-error-close-button = Serrar
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Interrumper
+pdfjs-editor-add-signature-add-button = Agiuntar
+pdfjs-editor-edit-signature-update-button = Actualisar
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Modifitgar il commentari
+pdfjs-editor-edit-comment-popup-button =
+ .title = Modifitgar il commentari
+pdfjs-editor-delete-comment-popup-button-label = Allontanar il commentari
+pdfjs-editor-delete-comment-popup-button =
+ .title = Allontanar il commentari
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Modifitgar il commentari
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Agiuntar in commentari
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Cumenzar a tippar…
+pdfjs-editor-edit-comment-dialog-cancel-button = Interrumper
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Allontanar la signatura memorisada
+pdfjs-editor-delete-signature-button-label1 = Allontanar la signatura memorisada
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Modifitgar la descripziun
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Modifitgar la descripziun
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ro/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ro/viewer.ftl
new file mode 100644
index 0000000..44d389e
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ro/viewer.ftl
@@ -0,0 +1,850 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pagina precedentă
+pdfjs-previous-button-label = Înapoi
+pdfjs-next-button =
+ .title = Pagina următoare
+pdfjs-next-button-label = Înainte
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pagina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = din { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } din { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Micșorează
+pdfjs-zoom-out-button-label = Micșorează
+pdfjs-zoom-in-button =
+ .title = Mărește
+pdfjs-zoom-in-button-label = Mărește
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Comută la modul de prezentare
+pdfjs-presentation-mode-button-label = Mod de prezentare
+pdfjs-open-file-button =
+ .title = Deschide un fișier
+pdfjs-open-file-button-label = Deschide
+pdfjs-print-button =
+ .title = Printează
+pdfjs-print-button-label = Printează
+pdfjs-save-button =
+ .title = Salvează
+pdfjs-save-button-label = Salvează
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Descarcă
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Descarcă
+pdfjs-bookmark-button =
+ .title = Pagina curentă (Vezi URL din pagina curentă)
+pdfjs-bookmark-button-label = Pagină curentă
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Instrumente
+pdfjs-tools-button-label = Instrumente
+pdfjs-first-page-button =
+ .title = Mergi la prima pagină
+pdfjs-first-page-button-label = Mergi la prima pagină
+pdfjs-last-page-button =
+ .title = Mergi la ultima pagină
+pdfjs-last-page-button-label = Mergi la ultima pagină
+pdfjs-page-rotate-cw-button =
+ .title = Rotește în sensul acelor de ceas
+pdfjs-page-rotate-cw-button-label = Rotește în sensul acelor de ceas
+pdfjs-page-rotate-ccw-button =
+ .title = Rotește în sens invers al acelor de ceas
+pdfjs-page-rotate-ccw-button-label = Rotește în sens invers al acelor de ceas
+pdfjs-cursor-text-select-tool-button =
+ .title = Activează instrumentul de selecție a textului
+pdfjs-cursor-text-select-tool-button-label = Instrumentul de selecție a textului
+pdfjs-cursor-hand-tool-button =
+ .title = Activează instrumentul mână
+pdfjs-cursor-hand-tool-button-label = Unealta mână
+pdfjs-scroll-page-button =
+ .title = Folosește derularea paginilor
+pdfjs-scroll-page-button-label = Derulare pagini
+pdfjs-scroll-vertical-button =
+ .title = Folosește derularea verticală
+pdfjs-scroll-vertical-button-label = Derulare verticală
+pdfjs-scroll-horizontal-button =
+ .title = Folosește derularea orizontală
+pdfjs-scroll-horizontal-button-label = Derulare orizontală
+pdfjs-scroll-wrapped-button =
+ .title = Folosește derularea încadrată
+pdfjs-scroll-wrapped-button-label = Derulare încadrată
+pdfjs-spread-none-button =
+ .title = Nu uni paginile broșate
+pdfjs-spread-none-button-label = Fără pagini broșate
+pdfjs-spread-odd-button =
+ .title = Unește paginile broșate începând cu cele impare
+pdfjs-spread-odd-button-label = Broșare pagini impare
+pdfjs-spread-even-button =
+ .title = Unește paginile broșate începând cu cele pare
+pdfjs-spread-even-button-label = Broșare pagini pare
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Proprietățile documentului…
+pdfjs-document-properties-button-label = Proprietățile documentului…
+pdfjs-document-properties-file-name = Numele fișierului:
+pdfjs-document-properties-file-size = Mărimea fișierului:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } octeți)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } octeți)
+pdfjs-document-properties-title = Titlu:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Subiect:
+pdfjs-document-properties-keywords = Cuvinte cheie:
+pdfjs-document-properties-creation-date = Data creării:
+pdfjs-document-properties-modification-date = Data modificării:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Autor:
+pdfjs-document-properties-producer = Producător PDF:
+pdfjs-document-properties-version = Versiune PDF:
+pdfjs-document-properties-page-count = Număr de pagini:
+pdfjs-document-properties-page-size = Mărimea paginii:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = verticală
+pdfjs-document-properties-page-size-orientation-landscape = orizontală
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Literă
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vizualizare web rapidă:
+pdfjs-document-properties-linearized-yes = Da
+pdfjs-document-properties-linearized-no = Nu
+pdfjs-document-properties-close-button = Închide
+pdfjs-digital-signature-properties-view-certificate = Vezi certificatul
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Motiv: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Marcaj temporal: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] ({ $count }) sub semnătură
+ [few] ({ $count }) sub semnături
+ *[other] ({ $count }) de sub semnături
+ }
+
+## Print
+
+pdfjs-print-progress-message = Se pregătește documentul pentru printare…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Anulează
+pdfjs-printing-not-supported = Avertisment: Printarea nu este suportată complet de acest browser.
+pdfjs-printing-not-ready = Avertisment: PDF-ul nu este încărcat complet pentru printare.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Comută bara laterală
+pdfjs-toggle-sidebar-notification-button =
+ .title = Comută bara laterală (documentul conține schițe/atașamente/straturi)
+pdfjs-toggle-sidebar-button-label = Comută bara laterală
+pdfjs-document-outline-button =
+ .title = Afișează schița documentului (dă dublu clic pentru a extinde/restrânge toate elementele)
+pdfjs-document-outline-button-label = Schiță a documentului
+pdfjs-attachments-button =
+ .title = Afișează atașamentele
+pdfjs-attachments-button-label = Atașamente
+pdfjs-layers-button =
+ .title = Afișează straturile (dă dublu clic pentru resetarea tuturor straturilor la starea implicită)
+pdfjs-layers-button-label = Straturi
+pdfjs-thumbs-button =
+ .title = Afișează miniaturi
+pdfjs-thumbs-button-label = Miniaturi
+pdfjs-current-outline-item-button =
+ .title = Găsește elementul pe schița actuală
+pdfjs-current-outline-item-button-label = Element al schiței actuale
+pdfjs-findbar-button =
+ .title = Caută în document
+pdfjs-findbar-button-label = Caută
+pdfjs-additional-layers = Straturi suplimentare
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pagina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura paginii { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Selectează pagina { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Pagina { $page } din { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Caută
+ .placeholder = Caută în document…
+pdfjs-find-previous-button =
+ .title = Mergi la apariția anterioară a textului
+pdfjs-find-previous-button-label = Înapoi
+pdfjs-find-next-button =
+ .title = Mergi la apariția următoare a textului
+pdfjs-find-next-button-label = Înainte
+pdfjs-find-highlight-checkbox = Evidențiază toate aparițiile
+pdfjs-find-match-case-checkbox-label = Ține cont de majuscule și minuscule
+pdfjs-find-match-diacritics-checkbox-label = Respectă diacriticele
+pdfjs-find-entire-word-checkbox-label = Cuvinte întregi
+pdfjs-find-reached-top = Am ajuns la începutul documentului, continuă de la sfârșit
+pdfjs-find-reached-bottom = Am ajuns la sfârșitul documentului, continuă de la început
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } din { $total } rezultat
+ [few] { $current } din { $total } rezultate
+ *[other] { $current } din { $total } de rezultate
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mai mult de { $limit } rezultat
+ [few] Mai mult de { $limit } rezultate
+ *[other] Mai mult de { $limit } de rezultate
+ }
+pdfjs-find-not-found = Nu s-a găsit textul
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lățime pagină
+pdfjs-page-scale-fit = Potrivire la pagină
+pdfjs-page-scale-auto = Zoom automat
+pdfjs-page-scale-actual = Mărime reală
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pagina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = A intervenit o eroare la încărcarea PDF-ului.
+pdfjs-invalid-file-error = Fișier PDF nevalid sau corupt.
+pdfjs-missing-file-error = Fișier PDF lipsă.
+pdfjs-unexpected-response-error = Răspuns neașteptat de la server.
+pdfjs-rendering-error = A intervenit o eroare la randarea paginii.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Adnotare { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Introdu parola pentru a deschide acest fișier PDF.
+pdfjs-password-invalid = Parolă nevalidă. Te rugăm să încerci din nou.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Anulează
+pdfjs-web-fonts-disabled = Fonturile web sunt dezactivate: nu se pot folosi fonturile PDF încorporate.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Schimbă culoarea textului
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Desenează
+pdfjs-editor-color-picker-ink-input =
+ .title = Schimbă culoarea de desen
+pdfjs-editor-ink-button-label = Desenează
+pdfjs-editor-stamp-button =
+ .title = Adaugă sau editează imagini
+pdfjs-editor-stamp-button-label = Adaugă sau editează imagini
+pdfjs-editor-highlight-button =
+ .title = Evidențiere
+pdfjs-editor-highlight-button-label = Evidențiere
+pdfjs-highlight-floating-button1 =
+ .title = Evidențiază
+ .aria-label = Evidențiere
+pdfjs-highlight-floating-button-label = Evidențiază
+pdfjs-comment-floating-button =
+ .title = Comentează
+ .aria-label = Comentariu
+pdfjs-comment-floating-button-label = Comentează
+pdfjs-editor-comment-button =
+ .title = Comentariu
+ .aria-label = Comentează
+pdfjs-editor-comment-button-label = Comentariu
+pdfjs-editor-signature-button =
+ .title = Adaugă semnătură
+pdfjs-editor-signature-button-label = Adaugă semnătură
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor de evidențiere
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor de desen
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor de semnătură: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor de imagini
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Elimină desenul
+pdfjs-editor-remove-freetext-button =
+ .title = Elimină textul
+pdfjs-editor-remove-stamp-button =
+ .title = Elimină imaginea
+pdfjs-editor-remove-highlight-button =
+ .title = Elimină evidențierea
+pdfjs-editor-remove-signature-button =
+ .title = Elimină semnătura
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Culoare
+pdfjs-editor-free-text-size-input = Mărime
+pdfjs-editor-ink-color-input = Culoare
+pdfjs-editor-ink-thickness-input = Grosime
+pdfjs-editor-ink-opacity-input = Opacitate
+pdfjs-editor-stamp-add-image-button =
+ .title = Adaugă imagine
+pdfjs-editor-stamp-add-image-button-label = Adaugă imagine
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grosime
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Schimbă grosimea când evidențiezi alte elemente decât text
+pdfjs-editor-add-signature-container =
+ .aria-label = Controale de semnături și semnături salvate
+pdfjs-editor-signature-add-signature-button =
+ .title = Adaugă o semnătură nouă
+pdfjs-editor-signature-add-signature-button-label = Adaugă o semnătură nouă
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Semnătură salvată: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editor de text
+ .default-content = Începe să tastezi...
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] comentariu
+ [few] comentarii
+ *[other] de comentarii
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Închide bara laterală
+ .aria-label = Închide bara laterală
+pdfjs-editor-comments-sidebar-close-button-label = Închide bara laterală
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vezi ceva care merită comentat? Evidențiază-l și lasă un comentariu.
+pdfjs-editor-comments-sidebar-no-comments-link = Află mai multe
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Text alternativ
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Editează textul alternativ
+pdfjs-editor-alt-text-dialog-label = Alege o opțiune
+pdfjs-editor-alt-text-dialog-description = Textul alternativ (alt text) ajută când oamenii nu pot vedea imaginea sau când nu se încarcă.
+pdfjs-editor-alt-text-add-description-label = Adaugă o descriere
+pdfjs-editor-alt-text-add-description-description = Încearcă să scrii 1-2 propoziții care să descrie subiectul, cadrul sau acțiunile.
+pdfjs-editor-alt-text-mark-decorative-label = Marchează ca decorativ
+pdfjs-editor-alt-text-mark-decorative-description = Este pentru imagini ornamentale, cum ar fi chenare sau filigrane.
+pdfjs-editor-alt-text-cancel-button = Anulează
+pdfjs-editor-alt-text-save-button = Salvează
+pdfjs-editor-alt-text-decorative-tooltip = Marcat ca decorativ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = De exemplu, „Un tânăr se așează la o masă să mănânce”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Text alternativ
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Colțul din stânga sus — redimensionează
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Mijloc de sus — redimensionează
+pdfjs-editor-resizer-top-right =
+ .aria-label = Colțul din dreapta sus — redimensionează
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Mijloc dreapta — redimensionează
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Colțul din dreapta jos — redimensionează
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Mijloc de jos - redimensionează
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Colțul din stânga jos — redimensionează
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Mijloc stânga — redimensionează
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Culoare de evidențiere
+pdfjs-editor-colorpicker-button =
+ .title = Schimbă culoarea
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Opțiuni de culoare
+pdfjs-editor-colorpicker-yellow =
+ .title = Galben
+pdfjs-editor-colorpicker-green =
+ .title = Verde
+pdfjs-editor-colorpicker-blue =
+ .title = Albastru
+pdfjs-editor-colorpicker-pink =
+ .title = Roz
+pdfjs-editor-colorpicker-red =
+ .title = Roșu
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Afișează tot
+pdfjs-editor-highlight-show-all-button =
+ .title = Afișează tot
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Editează textul alternativ (descrierea imaginii)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Adaugă text alternativ (descrierea imaginii)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Scrie descrierea aici...
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Scurtă descriere pentru cei care nu pot vedea imaginea sau pentru când nu se încarcă imaginea.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Acest text alternativ a fost creat automat și este posibil să nu fie exact.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Află mai multe
+pdfjs-editor-new-alt-text-create-automatically-button-label = Creează automat texte alternative
+pdfjs-editor-new-alt-text-not-now-button = Nu acum
+pdfjs-editor-new-alt-text-error-title = Nu s-a putut crea automat textul alternativ
+pdfjs-editor-new-alt-text-error-description = Te rugăm să scrii propriul text alternativ sau să încerci din nou mai târziu.
+pdfjs-editor-new-alt-text-error-close-button = Închide
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Se descarcă modelul AI de text alternativ ({ $downloadedSize } de { $totalSize } MB)
+ .aria-valuetext = Se descarcă modelul AI de text alternativ ({ $downloadedSize } de { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Text alternativ adăugat
+pdfjs-editor-new-alt-text-added-button-label = Text alternativ adăugat
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Text alternativ lipsă
+pdfjs-editor-new-alt-text-missing-button-label = Text alternativ lipsă
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revizuiește textul alternativ
+pdfjs-editor-new-alt-text-to-review-button-label = Revizuiește textul alternativ
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creat automat: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Setări text alternativ imagini
+pdfjs-image-alt-text-settings-button-label = Setări text alternativ imagini
+pdfjs-editor-alt-text-settings-dialog-label = Setări text alternativ imagini
+pdfjs-editor-alt-text-settings-automatic-title = Text alternativ automat
+pdfjs-editor-alt-text-settings-create-model-button-label = Creează automat texte alternative
+pdfjs-editor-alt-text-settings-create-model-description = Sugerează descrieri ca să îi ajuți pe cei care nu pot vedea imaginea sau pentru când nu se încarcă imaginea.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model AI de text alternativ ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Rulează local pe dispozitiv, deci datele tale rămân private. Necesar pentru text alternativ automat.
+pdfjs-editor-alt-text-settings-delete-model-button = Șterge
+pdfjs-editor-alt-text-settings-download-model-button = Descarcă
+pdfjs-editor-alt-text-settings-downloading-model-button = Se descarcă…
+pdfjs-editor-alt-text-settings-editor-title = Editor de text alternativ
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Afișează editorul de text alternativ imediat când adaugi o imagine
+pdfjs-editor-alt-text-settings-show-dialog-description = Te ajută să te asiguri că toate imaginile au text alternativ.
+pdfjs-editor-alt-text-settings-close-button = Închide
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Evidențiere adăugată
+pdfjs-editor-freetext-added-alert = Text adăugat
+pdfjs-editor-ink-added-alert = Desen adăugat
+pdfjs-editor-stamp-added-alert = Imagine adăugată
+pdfjs-editor-signature-added-alert = Semnătură adăugată
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Evidențiere eliminată
+pdfjs-editor-undo-bar-message-freetext = Text eliminat
+pdfjs-editor-undo-bar-message-ink = Desen eliminat
+pdfjs-editor-undo-bar-message-stamp = Imagine eliminată
+pdfjs-editor-undo-bar-message-signature = Semnătură eliminată
+pdfjs-editor-undo-bar-message-comment = Comentariu eliminat
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } adnotare eliminată
+ [few] { $count } adnotări eliminate
+ *[other] { $count } de adnotări eliminate
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Anulează
+pdfjs-editor-undo-bar-undo-button-label = Anulează
+pdfjs-editor-undo-bar-close-button =
+ .title = Închide
+pdfjs-editor-undo-bar-close-button-label = Închide
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Această fereastră permite utilizatorului să creeze o semnătură de adăugat la un document PDF. Utilizatorul poate edita numele (care servește și ca text alternativ) și, opțional, poate salva semnătura pentru utilizare repetată.
+pdfjs-editor-add-signature-dialog-title = Adaugă o semnătură
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Tip
+ .title = Tip
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Desenează
+ .title = Desenează
+pdfjs-editor-add-signature-image-button = Imagine
+ .title = Imagine
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Tastează semnătura
+ .placeholder = Tastează semnătura
+pdfjs-editor-add-signature-draw-placeholder = Desenează semnătura
+pdfjs-editor-add-signature-draw-thickness-range-label = Grosime
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Grosimea desenului: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Trage aici un fișier pentru încărcare
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Sau alege fișiere de imagini
+ *[other] Sau răsfoiește prin fișiere de imagini
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Descriere (text alternativ)
+pdfjs-editor-add-signature-description-input =
+ .title = Descriere (text alternativ)
+pdfjs-editor-add-signature-description-default-when-drawing = Semnătură
+pdfjs-editor-add-signature-clear-button-label = Șterge semnătura
+pdfjs-editor-add-signature-clear-button =
+ .title = Șterge semnătura
+pdfjs-editor-add-signature-save-checkbox = Salvează semnătura
+pdfjs-editor-add-signature-save-warning-message = Ai atins limita de 5 semnături salvate. Elimină una dacă vrei să salvezi alta.
+pdfjs-editor-add-signature-image-upload-error-title = Imaginea nu a putut fi încărcată
+pdfjs-editor-add-signature-image-upload-error-description = Verifică-ți conexiunea la rețea sau încearcă cu o altă imagine.
+pdfjs-editor-add-signature-image-no-data-error-title = Imaginea nu poate fi convertită în semnătură
+pdfjs-editor-add-signature-image-no-data-error-description = Încearcă să încarci altă imagine.
+pdfjs-editor-add-signature-error-close-button = Închide
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Anulează
+pdfjs-editor-add-signature-add-button = Adaugă
+pdfjs-editor-edit-signature-update-button = Actualizează
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Editează comentariul
+pdfjs-editor-edit-comment-popup-button =
+ .title = Editează comentariul
+pdfjs-editor-delete-comment-popup-button-label = Șterge comentariul
+pdfjs-editor-delete-comment-popup-button =
+ .title = Șterge comentariul
+pdfjs-show-comment-button =
+ .title = Afișează comentariul
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Editează comentariul
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Actualizează
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Adaugă un comentariu
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Adaugă
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Începe să tastezi…
+pdfjs-editor-edit-comment-dialog-cancel-button = Anulează
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Adaugă un comentariu
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Comută bara laterală (documentul conține miniaturi/schițe/atașamente/straturi)
+pdfjs-toggle-views-manager-button1-label = Gestionează paginile
+pdfjs-views-manager-sidebar =
+ .aria-label = Bară laterală
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Redimensionare bară laterală
+pdfjs-views-manager-view-selector-button =
+ .title = Vizualizări
+pdfjs-views-manager-view-selector-button-label = Vizualizări
+pdfjs-views-manager-pages-title = Pagini
+pdfjs-views-manager-outlines-title1 = Structura documentului
+ .title = Structura documentului (dă dublu clic pentru extinderea/restrângerea elementelor)
+pdfjs-views-manager-attachments-title = Atașamente
+pdfjs-views-manager-layers-title1 = Straturi
+ .title = Straturi (dă dublu clic ca să resetezi toate straturile la starea implicită)
+pdfjs-views-manager-pages-option-label = Pagini
+pdfjs-views-manager-outlines-option-label = Schiță document
+pdfjs-views-manager-attachments-option-label = Atașamente
+pdfjs-views-manager-layers-option-label = Straturi
+pdfjs-views-manager-add-file-button =
+ .title = Adaugă un fișier
+pdfjs-views-manager-add-file-button-label = Adaugă un fișier
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } selectată
+ [few] { $count } selectate
+ *[other] { $count } selectate
+ }
+pdfjs-views-manager-pages-status-none-action-label = Selectează pagini
+pdfjs-views-manager-pages-status-action-button-label = Gestionează
+pdfjs-views-manager-pages-status-copy-button-label = Copiază
+pdfjs-views-manager-pages-status-cut-button-label = Taie
+pdfjs-views-manager-pages-status-delete-button-label = Șterge
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportă selecția…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 pagină tăiată
+ [few] { $count } pagini tăiate
+ *[other] { $count } de pagini tăiate
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 pagină copiată
+ [few] { $count } pagini copiate
+ *[other] { $count } de pagini copiate
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 pagină ștearsă
+ [few] { $count } pagini șterse
+ *[other] { $count } de pagini șterse
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Se pregătește fișierul…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Se încarcă fișierul…
+pdfjs-views-manager-status-warning-cut-label = Nu s-a putut tăia. Reîmprospătează pagina și încearcă din nou.
+pdfjs-views-manager-status-warning-copy-label = Nu s-a putut copia. Reîmprospătează pagina și încearcă din nou.
+pdfjs-views-manager-status-warning-delete-label = Nu s-a putut șterge. Reîmprospătează pagina și încearcă din nou.
+pdfjs-views-manager-status-warning-save-label = Nu s-a putut salva. Reîmprospătează pagina și încearcă din nou.
+pdfjs-views-manager-status-undo-button-label = Anulează
+pdfjs-views-manager-status-done-button-label = Terminat
+pdfjs-views-manager-status-close-button =
+ .title = Închide
+pdfjs-views-manager-status-close-button-label = Închide
+pdfjs-views-manager-paste-button-label = Lipește
+pdfjs-views-manager-paste-button-before =
+ .title = Inserează înainte de prima pagină
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Inserează după pagina { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOU
+pdfjs-views-manager-waiting-for-file = Se încarcă fișierul…
+pdfjs-toggle-views-manager-button1 =
+ .title = Gestionează paginile
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Proprietățile semnăturii digitale
+ .aria-label = Proprietățile semnăturii digitale
+pdfjs-digital-signature-properties-button-label = Proprietățile semnăturii digitale
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Documentul a fost semnat cu o semnătură digitală validă
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Document semnat, dar { $count } semnătură digitală nu au putut fi verificată
+ [few] Document semnat, dar { $count } semnături digitale nu au putut fi verificate
+ *[other] Document semnat, dar { $count } de semnături digitale nu au putut fi verificate
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Document semnat cu { $count } certificat care nu este de încredere
+ [few] Document semnat cu { $count } certificate care nu sunt de încredere
+ *[other] Document semnat cu { $count } de certificate care nu sunt de încredere
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Document semnat cu { $count } certificat expirat
+ [few] Document semnat cu { $count } certificate expirate
+ *[other] Document semnat cu { $count } de certificate expirate
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Documentul are { $count } semnătură digitală nevalidă
+ [few] Documentul are { $count } semnături digitale nevalide
+ *[other] Documentul are { $count } de semnături digitale nevalide
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Document semnat cu { $count } certificat revocat
+ [few] Document semnat cu { $count } certificate revocate
+ *[other] Document semnat cu { $count } de certificate revocate
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stare: Semnătură verificată
+pdfjs-digital-signature-properties-status-invalid = Stare: Semnătură nevalidă
+pdfjs-digital-signature-properties-status-unknown = Stare: Nu se poate verifica (neacceptat)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certificat: De încredere ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certificat: Indisponibil
+pdfjs-digital-signature-properties-certificate-untrusted = Certificat: De neîncredere
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificat: Emitent necunoscut ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificat: Autosemnat ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificat: Emitent de neîncredere ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certificat: Expirat
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certificat: Expirat ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certificat: Revocat
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Elimină semnătura salvată
+pdfjs-editor-delete-signature-button-label1 = Elimină semnătura salvată
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Editează descrierea
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Editează descrierea
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ru/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ru/viewer.ftl
new file mode 100644
index 0000000..bac2800
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ru/viewer.ftl
@@ -0,0 +1,850 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Предыдущая страница
+pdfjs-previous-button-label = Предыдущая
+pdfjs-next-button =
+ .title = Следующая страница
+pdfjs-next-button-label = Следующая
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Страница
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = из { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } из { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Уменьшить
+pdfjs-zoom-out-button-label = Уменьшить
+pdfjs-zoom-in-button =
+ .title = Увеличить
+pdfjs-zoom-in-button-label = Увеличить
+pdfjs-zoom-select =
+ .title = Масштаб
+pdfjs-presentation-mode-button =
+ .title = Перейти в режим презентации
+pdfjs-presentation-mode-button-label = Режим презентации
+pdfjs-open-file-button =
+ .title = Открыть файл
+pdfjs-open-file-button-label = Открыть
+pdfjs-print-button =
+ .title = Печать
+pdfjs-print-button-label = Печать
+pdfjs-save-button =
+ .title = Сохранить
+pdfjs-save-button-label = Сохранить
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Скачать
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Скачать
+pdfjs-bookmark-button =
+ .title = Текущая страница (просмотр URL-адреса с текущей страницы)
+pdfjs-bookmark-button-label = Текущая страница
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Инструменты
+pdfjs-tools-button-label = Инструменты
+pdfjs-first-page-button =
+ .title = Перейти на первую страницу
+pdfjs-first-page-button-label = Перейти на первую страницу
+pdfjs-last-page-button =
+ .title = Перейти на последнюю страницу
+pdfjs-last-page-button-label = Перейти на последнюю страницу
+pdfjs-page-rotate-cw-button =
+ .title = Повернуть по часовой стрелке
+pdfjs-page-rotate-cw-button-label = Повернуть по часовой стрелке
+pdfjs-page-rotate-ccw-button =
+ .title = Повернуть против часовой стрелки
+pdfjs-page-rotate-ccw-button-label = Повернуть против часовой стрелки
+pdfjs-cursor-text-select-tool-button =
+ .title = Включить инструмент «Выделение текста»
+pdfjs-cursor-text-select-tool-button-label = Инструмент «Выделение текста»
+pdfjs-cursor-hand-tool-button =
+ .title = Включить инструмент «Рука»
+pdfjs-cursor-hand-tool-button-label = Инструмент «Рука»
+pdfjs-scroll-page-button =
+ .title = Использовать прокрутку страниц
+pdfjs-scroll-page-button-label = Прокрутка страниц
+pdfjs-scroll-vertical-button =
+ .title = Использовать вертикальную прокрутку
+pdfjs-scroll-vertical-button-label = Вертикальная прокрутка
+pdfjs-scroll-horizontal-button =
+ .title = Использовать горизонтальную прокрутку
+pdfjs-scroll-horizontal-button-label = Горизонтальная прокрутка
+pdfjs-scroll-wrapped-button =
+ .title = Использовать масштабируемую прокрутку
+pdfjs-scroll-wrapped-button-label = Масштабируемая прокрутка
+pdfjs-spread-none-button =
+ .title = Не использовать режим разворотов страниц
+pdfjs-spread-none-button-label = Без разворотов страниц
+pdfjs-spread-odd-button =
+ .title = Развороты начинаются с нечётных номеров страниц
+pdfjs-spread-odd-button-label = Нечётные страницы слева
+pdfjs-spread-even-button =
+ .title = Развороты начинаются с чётных номеров страниц
+pdfjs-spread-even-button-label = Чётные страницы слева
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Свойства документа…
+pdfjs-document-properties-button-label = Свойства документа…
+pdfjs-document-properties-file-name = Имя файла:
+pdfjs-document-properties-file-size = Размер файла:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } КБ ({ $b } байт)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } МБ ({ $b } байт)
+pdfjs-document-properties-title = Заголовок:
+pdfjs-document-properties-author = Автор:
+pdfjs-document-properties-subject = Тема:
+pdfjs-document-properties-keywords = Ключевые слова:
+pdfjs-document-properties-creation-date = Дата создания:
+pdfjs-document-properties-modification-date = Дата изменения:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Приложение:
+pdfjs-document-properties-producer = Производитель PDF:
+pdfjs-document-properties-version = Версия PDF:
+pdfjs-document-properties-page-count = Число страниц:
+pdfjs-document-properties-page-size = Размер страницы:
+pdfjs-document-properties-page-size-unit-inches = дюймов
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = книжная
+pdfjs-document-properties-page-size-orientation-landscape = альбомная
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Быстрый просмотр в Web:
+pdfjs-document-properties-linearized-yes = Да
+pdfjs-document-properties-linearized-no = Нет
+pdfjs-document-properties-close-button = Закрыть
+pdfjs-digital-signature-properties-view-certificate = Просмотреть сертификат
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Причина: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Метка времени: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Дополнительная подпись ({ $count })
+ [few] Дополнительные подписи ({ $count })
+ *[many] Дополнительные подписи ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Подготовка документа к печати…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Отмена
+pdfjs-printing-not-supported = Предупреждение: В этом браузере не полностью поддерживается печать.
+pdfjs-printing-not-ready = Предупреждение: PDF не полностью загружен для печати.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Показать/скрыть боковую панель
+pdfjs-toggle-sidebar-notification-button =
+ .title = Показать/скрыть боковую панель (документ имеет содержание/вложения/слои)
+pdfjs-toggle-sidebar-button-label = Показать/скрыть боковую панель
+pdfjs-document-outline-button =
+ .title = Показать содержание документа (двойной щелчок, чтобы развернуть/свернуть все элементы)
+pdfjs-document-outline-button-label = Содержание документа
+pdfjs-attachments-button =
+ .title = Показать вложения
+pdfjs-attachments-button-label = Вложения
+pdfjs-layers-button =
+ .title = Показать слои (дважды щёлкните, чтобы сбросить все слои к состоянию по умолчанию)
+pdfjs-layers-button-label = Слои
+pdfjs-thumbs-button =
+ .title = Показать миниатюры
+pdfjs-thumbs-button-label = Миниатюры
+pdfjs-current-outline-item-button =
+ .title = Найти текущий элемент структуры
+pdfjs-current-outline-item-button-label = Текущий элемент структуры
+pdfjs-findbar-button =
+ .title = Найти в документе
+pdfjs-findbar-button-label = Найти
+pdfjs-additional-layers = Дополнительные слои
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Страница { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Миниатюра страницы { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Выбрать страницу { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Страница { $page } из { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Найти
+ .placeholder = Найти в документе…
+pdfjs-find-previous-button =
+ .title = Найти предыдущее вхождение фразы в текст
+pdfjs-find-previous-button-label = Назад
+pdfjs-find-next-button =
+ .title = Найти следующее вхождение фразы в текст
+pdfjs-find-next-button-label = Далее
+pdfjs-find-highlight-checkbox = Подсветить все
+pdfjs-find-match-case-checkbox-label = С учётом регистра
+pdfjs-find-match-diacritics-checkbox-label = С учётом диакритических знаков
+pdfjs-find-entire-word-checkbox-label = Слова целиком
+pdfjs-find-reached-top = Достигнут верх документа, продолжено снизу
+pdfjs-find-reached-bottom = Достигнут конец документа, продолжено сверху
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } из { $total } совпадения
+ [few] { $current } из { $total } совпадений
+ *[many] { $current } из { $total } совпадений
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Более { $limit } совпадения
+ [few] Более { $limit } совпадений
+ *[many] Более { $limit } совпадений
+ }
+pdfjs-find-not-found = Фраза не найдена
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = По ширине страницы
+pdfjs-page-scale-fit = По размеру страницы
+pdfjs-page-scale-auto = Автоматически
+pdfjs-page-scale-actual = Реальный размер
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Страница { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = При загрузке PDF произошла ошибка.
+pdfjs-invalid-file-error = Некорректный или повреждённый PDF-файл.
+pdfjs-missing-file-error = PDF-файл отсутствует.
+pdfjs-unexpected-response-error = Неожиданный ответ сервера.
+pdfjs-rendering-error = При создании страницы произошла ошибка.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Аннотация { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Введите пароль, чтобы открыть этот PDF-файл.
+pdfjs-password-invalid = Неверный пароль. Пожалуйста, попробуйте снова.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Отмена
+pdfjs-web-fonts-disabled = Веб-шрифты отключены: не удалось задействовать встроенные PDF-шрифты.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Текст
+pdfjs-editor-color-picker-free-text-input =
+ .title = Изменить цвет текста
+pdfjs-editor-free-text-button-label = Текст
+pdfjs-editor-ink-button =
+ .title = Рисовать
+pdfjs-editor-color-picker-ink-input =
+ .title = Изменить цвет прорисовки
+pdfjs-editor-ink-button-label = Рисовать
+pdfjs-editor-stamp-button =
+ .title = Добавить или изменить изображения
+pdfjs-editor-stamp-button-label = Добавить или изменить изображения
+pdfjs-editor-highlight-button =
+ .title = Выделение
+pdfjs-editor-highlight-button-label = Выделение
+pdfjs-highlight-floating-button1 =
+ .title = Выделение
+ .aria-label = Выделение
+pdfjs-highlight-floating-button-label = Выделение
+pdfjs-comment-floating-button =
+ .title = Комментировать
+ .aria-label = Комментировать
+pdfjs-comment-floating-button-label = Комментировать
+pdfjs-editor-comment-button =
+ .title = Комментарий
+ .aria-label = Комментарий
+pdfjs-editor-comment-button-label = Комментарий
+pdfjs-editor-signature-button =
+ .title = Добавить подпись
+pdfjs-editor-signature-button-label = Добавить подпись
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Редактор выделения
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Редактор изображений
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Редактор подписи: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Редактор изображений
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Удалить рисунок
+pdfjs-editor-remove-freetext-button =
+ .title = Удалить текст
+pdfjs-editor-remove-stamp-button =
+ .title = Удалить изображение
+pdfjs-editor-remove-highlight-button =
+ .title = Удалить выделение
+pdfjs-editor-remove-signature-button =
+ .title = Удалить подпись
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Цвет
+pdfjs-editor-free-text-size-input = Размер
+pdfjs-editor-ink-color-input = Цвет
+pdfjs-editor-ink-thickness-input = Толщина
+pdfjs-editor-ink-opacity-input = Прозрачность
+pdfjs-editor-stamp-add-image-button =
+ .title = Добавить изображение
+pdfjs-editor-stamp-add-image-button-label = Добавить изображение
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Толщина
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Изменить толщину при выделении элементов, кроме текста
+pdfjs-editor-add-signature-container =
+ .aria-label = Управление подписями и сохранённые подписи
+pdfjs-editor-signature-add-signature-button =
+ .title = Добавить новую подпись
+pdfjs-editor-signature-add-signature-button-label = Добавить новую подпись
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Сохранённая подпись: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Текстовый редактор
+ .default-content = Начните ввод...
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Комментарий
+ [few] Комментарии
+ *[many] Комментарии
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Закрыть боковую панель
+ .aria-label = Закрыть боковую панель
+pdfjs-editor-comments-sidebar-close-button-label = Закрыть боковую панель
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Увидели что-то интересное? Выделите и оставьте комментарий.
+pdfjs-editor-comments-sidebar-no-comments-link = Подробнее
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Альтернативный текст
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Изменить альтернативный текст
+pdfjs-editor-alt-text-dialog-label = Выберите вариант
+pdfjs-editor-alt-text-dialog-description = Альтернативный текст помогает, когда люди не видят изображение или оно не загружается.
+pdfjs-editor-alt-text-add-description-label = Добавить описание
+pdfjs-editor-alt-text-add-description-description = Старайтесь составлять 1–2 предложения, описывающих предмет, обстановку или действия.
+pdfjs-editor-alt-text-mark-decorative-label = Отметить как декоративное
+pdfjs-editor-alt-text-mark-decorative-description = Используется для декоративных изображений, таких как рамки или водяные знаки.
+pdfjs-editor-alt-text-cancel-button = Отменить
+pdfjs-editor-alt-text-save-button = Сохранить
+pdfjs-editor-alt-text-decorative-tooltip = Помечен как декоративный
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Например: «Молодой человек садится за стол, чтобы поесть»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Альтернативный текст
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Левый верхний угол — изменить размер
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Вверху посередине — изменить размер
+pdfjs-editor-resizer-top-right =
+ .aria-label = Верхний правый угол — изменить размер
+pdfjs-editor-resizer-middle-right =
+ .aria-label = В центре справа — изменить размер
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Нижний правый угол — изменить размер
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Внизу посередине — изменить размер
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Нижний левый угол — изменить размер
+pdfjs-editor-resizer-middle-left =
+ .aria-label = В центре слева — изменить размер
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Цвет выделения
+pdfjs-editor-colorpicker-button =
+ .title = Изменить цвет
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Выбор цвета
+pdfjs-editor-colorpicker-yellow =
+ .title = Жёлтый
+pdfjs-editor-colorpicker-green =
+ .title = Зелёный
+pdfjs-editor-colorpicker-blue =
+ .title = Синий
+pdfjs-editor-colorpicker-pink =
+ .title = Розовый
+pdfjs-editor-colorpicker-red =
+ .title = Красный
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Показать все
+pdfjs-editor-highlight-show-all-button =
+ .title = Показать все
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Изменить альтернативный текст (описание изображения)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Добавить альтернативный текст (описание изображения)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Напишите здесь своё описание…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Короткое описание для людей, которые не видят изображение, или если изображение не загружается.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Этот альтернативный текст был создан автоматически и может быть неточным.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Подробнее
+pdfjs-editor-new-alt-text-create-automatically-button-label = Автоматически создавать альтернативный текст
+pdfjs-editor-new-alt-text-not-now-button = Не сейчас
+pdfjs-editor-new-alt-text-error-title = Не удалось автоматически создать альтернативный текст
+pdfjs-editor-new-alt-text-error-description = Пожалуйста, напишите свой альтернативный текст или попробуйте ещё раз позже.
+pdfjs-editor-new-alt-text-error-close-button = Закрыть
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Загрузка модели ИИ для альтернативного текста ({ $downloadedSize } из { $totalSize } МБ)
+ .aria-valuetext = Загрузка модели ИИ для альтернативного текста ({ $downloadedSize } из { $totalSize } МБ)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Альтернативный текст добавлен
+pdfjs-editor-new-alt-text-added-button-label = Альтернативный текст добавлен
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Отсутствует альтернативный текст
+pdfjs-editor-new-alt-text-missing-button-label = Отсутствует альтернативный текст
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Оценить альтернативный текст
+pdfjs-editor-new-alt-text-to-review-button-label = Оценить альтернативный текст
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Создано автоматически: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Настройки альтернативного текста для изображения
+pdfjs-image-alt-text-settings-button-label = Настройки альтернативного текста для изображения
+pdfjs-editor-alt-text-settings-dialog-label = Настройки альтернативного текста для изображения
+pdfjs-editor-alt-text-settings-automatic-title = Автоматический альтернативный текст
+pdfjs-editor-alt-text-settings-create-model-button-label = Автоматически создавать альтернативный текст
+pdfjs-editor-alt-text-settings-create-model-description = Предлагает описания, чтобы помочь людям, которые не видят изображение, или если изображение не загружается.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = ИИ-модель альтернативного текста ({ $totalSize } МБ)
+pdfjs-editor-alt-text-settings-ai-model-description = Запускается локально на вашем устройстве, поэтому ваши данные остаются конфиденциальными. Требуется для автоматического альтернативного текста.
+pdfjs-editor-alt-text-settings-delete-model-button = Удалить
+pdfjs-editor-alt-text-settings-download-model-button = Скачать
+pdfjs-editor-alt-text-settings-downloading-model-button = Загрузка…
+pdfjs-editor-alt-text-settings-editor-title = Редактор альтернативного текста
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Сразу показывать редактор альтернативного текста при добавлении изображения
+pdfjs-editor-alt-text-settings-show-dialog-description = Помогает вам убедиться, что все ваши изображения имеют альтернативный текст.
+pdfjs-editor-alt-text-settings-close-button = Закрыть
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Выделение добавлено
+pdfjs-editor-freetext-added-alert = Текст добавлен
+pdfjs-editor-ink-added-alert = Изображение добавлено
+pdfjs-editor-stamp-added-alert = Изображение добавлено
+pdfjs-editor-signature-added-alert = Подпись добавлена
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Выделение удалено
+pdfjs-editor-undo-bar-message-freetext = Текст удалён
+pdfjs-editor-undo-bar-message-ink = Рисунок удалён
+pdfjs-editor-undo-bar-message-stamp = Изображение удалено
+pdfjs-editor-undo-bar-message-signature = Подпись удалена
+pdfjs-editor-undo-bar-message-comment = Комментарий удалён
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } аннотация удалена
+ [few] { $count } аннотации удалены
+ *[many] { $count } аннотаций удалены
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Отменить
+pdfjs-editor-undo-bar-undo-button-label = Отменить
+pdfjs-editor-undo-bar-close-button =
+ .title = Закрыть
+pdfjs-editor-undo-bar-close-button-label = Закрыть
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Это окно позволяет пользователю создать подпись для добавления в PDF-документ. Пользователь может отредактировать имя (которое также используется в качестве альтернативного текста) и, по желанию, сохранить подпись для повторного использования.
+pdfjs-editor-add-signature-dialog-title = Добавить подпись
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Ввод
+ .title = Ввод
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Рисовать
+ .title = Рисовать
+pdfjs-editor-add-signature-image-button = Изображение
+ .title = Изображение
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Введите свою подпись
+ .placeholder = Введите свою подпись
+pdfjs-editor-add-signature-draw-placeholder = Нарисуйте свою подпись
+pdfjs-editor-add-signature-draw-thickness-range-label = Толщина
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Толщина рисунка: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Перетащите сюда файл для загрузки
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Или просмотрите файлы изображений
+ *[other] Или просмотрите файлы изображений
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Описание (альтернативный текст)
+pdfjs-editor-add-signature-description-input =
+ .title = Описание (альтернативный текст)
+pdfjs-editor-add-signature-description-default-when-drawing = Подпись
+pdfjs-editor-add-signature-clear-button-label = Удалить подпись
+pdfjs-editor-add-signature-clear-button =
+ .title = Удалить подпись
+pdfjs-editor-add-signature-save-checkbox = Сохранить подпись
+pdfjs-editor-add-signature-save-warning-message = Вы достигли лимита в 5 сохранённых подписей. Удалите одну, чтобы сохранить другие.
+pdfjs-editor-add-signature-image-upload-error-title = Не удалось загрузить изображение
+pdfjs-editor-add-signature-image-upload-error-description = Проверьте подключение к сети или попробуйте другое изображение.
+pdfjs-editor-add-signature-image-no-data-error-title = Не удалось преобразовать это изображение в подпись
+pdfjs-editor-add-signature-image-no-data-error-description = Пожалуйста, попробуйте загрузить другое изображение.
+pdfjs-editor-add-signature-error-close-button = Закрыть
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Отмена
+pdfjs-editor-add-signature-add-button = Добавить
+pdfjs-editor-edit-signature-update-button = Обновить
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Редактировать комментарий
+pdfjs-editor-edit-comment-popup-button =
+ .title = Редактировать комментарий
+pdfjs-editor-delete-comment-popup-button-label = Удалить комментарий
+pdfjs-editor-delete-comment-popup-button =
+ .title = Удалить комментарий
+pdfjs-show-comment-button =
+ .title = Показать комментарий
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Редактировать комментарий
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Обновить
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Добавить комментарий
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Добавить
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Начните ввод…
+pdfjs-editor-edit-comment-dialog-cancel-button = Отмена
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Добавить комментарий
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Показать/скрыть боковую панель (документ содержит миниатюры/структуру/вложения/слои)
+pdfjs-toggle-views-manager-button1-label = Управление страницами
+pdfjs-views-manager-sidebar =
+ .aria-label = Боковая панель
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Изменение размера боковой панели
+pdfjs-views-manager-view-selector-button =
+ .title = Вид
+pdfjs-views-manager-view-selector-button-label = Вид
+pdfjs-views-manager-pages-title = Страницы
+pdfjs-views-manager-outlines-title1 = Структура документа
+ .title = Структура документа (щёлкните дважды, чтобы раскрыть/свернуть все элементы)
+pdfjs-views-manager-attachments-title = Вложения
+pdfjs-views-manager-layers-title1 = Слои
+ .title = Слои (щёлкните дважды, чтобы сбросить все слои в положение по умолчанию)
+pdfjs-views-manager-pages-option-label = Страницы
+pdfjs-views-manager-outlines-option-label = Структура документа
+pdfjs-views-manager-attachments-option-label = Вложения
+pdfjs-views-manager-layers-option-label = Слои
+pdfjs-views-manager-add-file-button =
+ .title = Добавить файл
+pdfjs-views-manager-add-file-button-label = Добавить файл
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] Выбрана { $count }
+ [few] Выбраны { $count }
+ *[many] Выбрано { $count }
+ }
+pdfjs-views-manager-pages-status-none-action-label = Выбрать страницы
+pdfjs-views-manager-pages-status-action-button-label = Управление
+pdfjs-views-manager-pages-status-copy-button-label = Копировать
+pdfjs-views-manager-pages-status-cut-button-label = Вырезать
+pdfjs-views-manager-pages-status-delete-button-label = Удалить
+pdfjs-views-manager-pages-status-export-selected-button-label = Экспортировать выбранное…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Вырезана 1 страница
+ [few] Вырезаны { $count } страницы
+ *[many] Вырезано { $count } страниц
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Скопирована 1 страница
+ [few] Скопированы { $count } страницы
+ *[many] Скопировано { $count } страниц
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Удалена 1 страница
+ [few] Удалены { $count } страницы
+ *[many] Удалено { $count } страниц
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Идёт подготовка файла…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Выгрузка файла…
+pdfjs-views-manager-status-warning-cut-label = Не удалось вырезать. Обновить страницу и попробовать ещё раз.
+pdfjs-views-manager-status-warning-copy-label = Не удалось скопировать. Обновить страницу и попробовать ещё раз.
+pdfjs-views-manager-status-warning-delete-label = Не удалось удалить. Обновить страницу и попробовать ещё раз.
+pdfjs-views-manager-status-warning-save-label = Не удалось сохранить. Обновить страницу и попробовать ещё раз.
+pdfjs-views-manager-status-undo-button-label = Отменить
+pdfjs-views-manager-status-done-button-label = Готово
+pdfjs-views-manager-status-close-button =
+ .title = Закрыть
+pdfjs-views-manager-status-close-button-label = Закрыть
+pdfjs-views-manager-paste-button-label = Вставить
+pdfjs-views-manager-paste-button-before =
+ .title = Вставить перед первой страницей
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Вставить после страницы { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = НОВОЕ
+pdfjs-views-manager-waiting-for-file = Загрузка файла…
+pdfjs-toggle-views-manager-button1 =
+ .title = Управление страницами
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Свойства цифровой подписи
+ .aria-label = Свойства цифровой подписи
+pdfjs-digital-signature-properties-button-label = Свойства цифровой подписи
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Документ был подписан действительной цифровой подписью
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Документ подписан, но { $count } цифровая подпись не может быть проверены
+ [few] Документ подписан, но { $count } цифровых подписи не могут быть проверены
+ *[many] Документ подписан, но { $count } цифровых подписей не могут быть проверены
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Документ, подписанный { $count } недоверенным сертификатом
+ [few] Документ, подписанный { $count } недоверенными сертификатами
+ *[many] Документ, подписанный { $count } недоверенных сертификатов
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Документ, подписанный { $count } истёкшим сертификатом
+ [few] Документ, подписанный { $count } истёкшими сертификатами
+ *[many] Документ, подписанный { $count } истёкших сертификатов
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Документ имеет { $count } неверную цифровую подпись
+ [few] Документ имеет { $count } неверных цифровых подписей
+ *[many] Документ имеет { $count } неверных цифровых подписей
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Документ, подписанный { $count } отозванным сертификатом
+ [few] Документ, подписанный { $count } отозванными сертификатами
+ *[many] Документ, подписанный { $count } отозванных сертификатов
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Статус: Подпись проверена
+pdfjs-digital-signature-properties-status-invalid = Статус: Подпись недействительна
+pdfjs-digital-signature-properties-status-unknown = Статус: Не удалось проверить (не поддерживается)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Сертификат: Доверенный ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Сертификат: Недоступен
+pdfjs-digital-signature-properties-certificate-untrusted = Сертификат: Недоверенный
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Сертификат: Неизвестный издатель ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Сертификат: Самоподписанный ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Сертификат: Недоверенный издатель ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Сертификат: Истёк срок действия
+pdfjs-digital-signature-properties-certificate-expired-with-date = Сертификат: Истёк срок действия ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Сертификат: Отозван
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Удалить сохранённую подпись
+pdfjs-editor-delete-signature-button-label1 = Удалить сохранённую подпись
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Изменить описание
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Изменить описание
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sat/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sat/viewer.ftl
new file mode 100644
index 0000000..e2e3140
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sat/viewer.ftl
@@ -0,0 +1,278 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = ᱢᱟᱲᱟᱝ ᱥᱟᱦᱴᱟ
+pdfjs-previous-button-label = ᱢᱟᱲᱟᱝᱟᱜ
+pdfjs-next-button =
+ .title = ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ ᱥᱟᱦᱴᱟ
+pdfjs-next-button-label = ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ᱥᱟᱦᱴᱟ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = ᱨᱮᱭᱟᱜ { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } ᱠᱷᱚᱱ { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = ᱦᱤᱲᱤᱧ ᱛᱮᱭᱟᱨ
+pdfjs-zoom-out-button-label = ᱦᱤᱲᱤᱧ ᱛᱮᱭᱟᱨ
+pdfjs-zoom-in-button =
+ .title = ᱢᱟᱨᱟᱝ ᱛᱮᱭᱟᱨ
+pdfjs-zoom-in-button-label = ᱢᱟᱨᱟᱝ ᱛᱮᱭᱟᱨ
+pdfjs-zoom-select =
+ .title = ᱡᱩᱢ
+pdfjs-presentation-mode-button =
+ .title = ᱩᱫᱩᱜ ᱥᱚᱫᱚᱨ ᱚᱵᱚᱥᱛᱟ ᱨᱮ ᱚᱛᱟᱭ ᱢᱮ
+pdfjs-presentation-mode-button-label = ᱩᱫᱩᱜ ᱥᱚᱫᱚᱨ ᱚᱵᱚᱥᱛᱟ ᱨᱮ
+pdfjs-open-file-button =
+ .title = ᱨᱮᱫ ᱡᱷᱤᱡᱽ ᱢᱮ
+pdfjs-open-file-button-label = ᱡᱷᱤᱡᱽ ᱢᱮ
+pdfjs-print-button =
+ .title = ᱪᱷᱟᱯᱟ
+pdfjs-print-button-label = ᱪᱷᱟᱯᱟ
+pdfjs-save-button =
+ .title = ᱥᱟᱺᱪᱟᱣ ᱢᱮ
+pdfjs-save-button-label = ᱥᱟᱺᱪᱟᱣ ᱢᱮ
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ᱰᱟᱣᱩᱱᱞᱚᱰ
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ᱰᱟᱣᱩᱱᱞᱚᱰ
+pdfjs-bookmark-button =
+ .title = ᱱᱤᱛᱚᱜᱟᱜ ᱥᱟᱦᱴᱟ (ᱱᱤᱛᱚᱜᱟᱜ ᱥᱟᱦᱴᱟ ᱠᱷᱚᱱ URL ᱫᱮᱠᱷᱟᱣ ᱢᱮ)
+pdfjs-bookmark-button-label = ᱱᱤᱛᱚᱜᱟᱜ ᱥᱟᱦᱴᱟ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = ᱦᱟᱹᱛᱤᱭᱟᱹᱨ ᱠᱚ
+pdfjs-tools-button-label = ᱦᱟᱹᱛᱤᱭᱟᱹᱨ ᱠᱚ
+pdfjs-first-page-button =
+ .title = ᱯᱩᱭᱞᱩ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ
+pdfjs-first-page-button-label = ᱯᱩᱭᱞᱩ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ
+pdfjs-last-page-button =
+ .title = ᱢᱩᱪᱟᱹᱫ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ
+pdfjs-last-page-button-label = ᱢᱩᱪᱟᱹᱫ ᱥᱟᱦᱴᱟ ᱥᱮᱫ ᱪᱟᱞᱟᱜ ᱢᱮ
+pdfjs-page-rotate-cw-button =
+ .title = ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱟᱹᱪᱩᱨ
+pdfjs-page-rotate-cw-button-label = ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱟᱹᱪᱩᱨ
+pdfjs-page-rotate-ccw-button =
+ .title = ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱩᱞᱴᱟᱹ ᱟᱹᱪᱩᱨ
+pdfjs-page-rotate-ccw-button-label = ᱜᱷᱚᱰᱤ ᱦᱤᱥᱟᱹᱵ ᱛᱮ ᱩᱞᱴᱟᱹ ᱟᱹᱪᱩᱨ
+pdfjs-cursor-text-select-tool-button =
+ .title = ᱚᱞ ᱵᱟᱪᱷᱟᱣ ᱦᱟᱹᱛᱤᱭᱟᱨ ᱮᱢ ᱪᱷᱚᱭ ᱢᱮ
+pdfjs-cursor-text-select-tool-button-label = ᱚᱞ ᱵᱟᱪᱷᱟᱣ ᱦᱟᱹᱛᱤᱭᱟᱨ
+pdfjs-cursor-hand-tool-button =
+ .title = ᱛᱤ ᱦᱟᱹᱛᱤᱭᱟᱨ ᱮᱢ ᱪᱷᱚᱭ ᱢᱮ
+pdfjs-cursor-hand-tool-button-label = ᱛᱤ ᱦᱟᱹᱛᱤᱭᱟᱨ
+pdfjs-scroll-page-button =
+ .title = ᱥᱟᱦᱴᱟ ᱜᱩᱲᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ
+pdfjs-scroll-page-button-label = ᱥᱟᱦᱴᱟ ᱜᱩᱲᱟᱹᱣ
+pdfjs-scroll-vertical-button =
+ .title = ᱥᱤᱫᱽ ᱜᱩᱲᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ
+pdfjs-scroll-vertical-button-label = ᱥᱤᱫᱽ ᱜᱩᱲᱟᱹᱣ
+pdfjs-scroll-horizontal-button =
+ .title = ᱜᱤᱛᱤᱡ ᱛᱮ ᱜᱩᱲᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ
+pdfjs-scroll-horizontal-button-label = ᱜᱤᱛᱤᱡ ᱛᱮ ᱜᱩᱲᱟᱹᱣ
+pdfjs-scroll-wrapped-button =
+ .title = ᱞᱤᱯᱴᱟᱹᱣ ᱜᱩᱰᱨᱟᱹᱣ ᱵᱮᱵᱷᱟᱨ ᱢᱮ
+pdfjs-scroll-wrapped-button-label = ᱞᱤᱯᱴᱟᱣ ᱜᱩᱰᱨᱟᱹᱣ
+pdfjs-spread-none-button =
+ .title = ᱟᱞᱚᱢ ᱡᱚᱲᱟᱣ ᱟ ᱥᱟᱦᱴᱟ ᱫᱚ ᱯᱟᱥᱱᱟᱣᱜᱼᱟ
+pdfjs-spread-none-button-label = ᱯᱟᱥᱱᱟᱣ ᱵᱟᱹᱱᱩᱜᱼᱟ
+pdfjs-spread-odd-button =
+ .title = ᱥᱟᱦᱴᱟ ᱯᱟᱥᱱᱟᱣ ᱡᱚᱲᱟᱣ ᱢᱮ ᱡᱟᱦᱟᱸ ᱫᱚ ᱚᱰᱼᱮᱞ ᱥᱟᱦᱴᱟᱠᱚ ᱥᱟᱞᱟᱜ ᱮᱛᱦᱚᱵᱚᱜ ᱠᱟᱱᱟ
+pdfjs-spread-odd-button-label = ᱚᱰ ᱯᱟᱥᱱᱟᱣ
+pdfjs-spread-even-button =
+ .title = ᱥᱟᱦᱴᱟ ᱯᱟᱥᱱᱟᱣ ᱡᱚᱲᱟᱣ ᱢᱮ ᱡᱟᱦᱟᱸ ᱫᱚ ᱤᱣᱮᱱᱼᱮᱞ ᱥᱟᱦᱴᱟᱠᱚ ᱥᱟᱞᱟᱜ ᱮᱛᱦᱚᱵᱚᱜ ᱠᱟᱱᱟ
+pdfjs-spread-even-button-label = ᱯᱟᱥᱱᱟᱣ ᱤᱣᱮᱱ
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = ᱫᱚᱞᱤᱞ ᱜᱩᱱᱠᱚ …
+pdfjs-document-properties-button-label = ᱫᱚᱞᱤᱞ ᱜᱩᱱᱠᱚ …
+pdfjs-document-properties-file-name = ᱨᱮᱫᱽ ᱧᱩᱛᱩᱢ :
+pdfjs-document-properties-file-size = ᱨᱮᱫᱽ ᱢᱟᱯ :
+pdfjs-document-properties-title = ᱧᱩᱛᱩᱢ :
+pdfjs-document-properties-author = ᱚᱱᱚᱞᱤᱭᱟᱹ :
+pdfjs-document-properties-subject = ᱵᱤᱥᱚᱭ :
+pdfjs-document-properties-keywords = ᱠᱟᱹᱴᱷᱤ ᱥᱟᱵᱟᱫᱽ :
+pdfjs-document-properties-creation-date = ᱛᱮᱭᱟᱨ ᱢᱟᱸᱦᱤᱛ :
+pdfjs-document-properties-modification-date = ᱵᱚᱫᱚᱞ ᱦᱚᱪᱚ ᱢᱟᱹᱦᱤᱛ :
+pdfjs-document-properties-creator = ᱵᱮᱱᱟᱣᱤᱡ :
+pdfjs-document-properties-producer = PDF ᱛᱮᱭᱟᱨ ᱚᱰᱚᱠᱤᱡ :
+pdfjs-document-properties-version = PDF ᱵᱷᱟᱹᱨᱥᱚᱱ :
+pdfjs-document-properties-page-count = ᱥᱟᱦᱴᱟ ᱞᱮᱠᱷᱟ :
+pdfjs-document-properties-page-size = ᱥᱟᱦᱴᱟ ᱢᱟᱯ :
+pdfjs-document-properties-page-size-unit-inches = ᱤᱧᱪ
+pdfjs-document-properties-page-size-unit-millimeters = ᱢᱤᱢᱤ
+pdfjs-document-properties-page-size-orientation-portrait = ᱯᱚᱴᱨᱮᱴ
+pdfjs-document-properties-page-size-orientation-landscape = ᱞᱮᱱᱰᱥᱠᱮᱯ
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = ᱪᱤᱴᱷᱤ
+pdfjs-document-properties-page-size-name-legal = ᱠᱟᱹᱱᱩᱱᱤ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = ᱞᱚᱜᱚᱱ ᱣᱮᱵᱽ ᱧᱮᱞ :
+pdfjs-document-properties-linearized-yes = ᱦᱚᱭ
+pdfjs-document-properties-linearized-no = ᱵᱟᱝ
+pdfjs-document-properties-close-button = ᱵᱚᱸᱫᱚᱭ ᱢᱮ
+
+## Print
+
+pdfjs-print-progress-message = ᱪᱷᱟᱯᱟ ᱞᱟᱹᱜᱤᱫ ᱫᱚᱞᱤᱞ ᱛᱮᱭᱟᱨᱚᱜ ᱠᱟᱱᱟ …
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ᱵᱟᱹᱰᱨᱟᱹ
+pdfjs-printing-not-supported = ᱦᱚᱥᱤᱭᱟᱨ : ᱪᱷᱟᱯᱟ ᱱᱚᱣᱟ ᱯᱟᱱᱛᱮᱭᱟᱜ ᱫᱟᱨᱟᱭ ᱛᱮ ᱯᱩᱨᱟᱹᱣ ᱵᱟᱭ ᱜᱚᱲᱚᱣᱟᱠᱟᱱᱟ ᱾
+pdfjs-printing-not-ready = ᱦᱩᱥᱤᱭᱟᱹᱨ : ᱪᱷᱟᱯᱟ ᱞᱟᱹᱜᱤᱫ PDF ᱯᱩᱨᱟᱹ ᱵᱟᱭ ᱞᱟᱫᱮ ᱟᱠᱟᱱᱟ ᱾
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = ᱫᱷᱟᱨᱮᱵᱟᱨ ᱥᱮᱫ ᱩᱪᱟᱹᱲᱚᱜ ᱢᱮ
+pdfjs-toggle-sidebar-notification-button =
+ .title = ᱫᱷᱟᱨᱮᱵᱟᱨ ᱥᱮᱫ ᱩᱪᱟᱹᱲᱚᱜ ᱢᱮ (ᱫᱚᱞᱤᱞ ᱨᱮ ᱟᱣᱴᱞᱟᱭᱤᱢ ᱢᱮᱱᱟᱜᱼᱟ/ᱞᱟᱪᱷᱟᱠᱚ/ᱯᱚᱨᱚᱛᱠᱚ)
+pdfjs-toggle-sidebar-button-label = ᱫᱷᱟᱨᱮᱵᱟᱨ ᱥᱮᱫ ᱩᱪᱟᱹᱲᱚᱜ ᱢᱮ
+pdfjs-document-outline-button =
+ .title = ᱫᱚᱞᱚᱞ ᱟᱣᱴᱞᱟᱭᱤᱱ ᱫᱮᱠᱷᱟᱣ ᱢᱮ (ᱡᱷᱚᱛᱚ ᱡᱤᱱᱤᱥᱠᱚ ᱵᱟᱨ ᱡᱮᱠᱷᱟ ᱚᱛᱟ ᱠᱮᱛᱮ ᱡᱷᱟᱹᱞ/ᱦᱩᱰᱤᱧ ᱪᱷᱚᱭ ᱢᱮ)
+pdfjs-document-outline-button-label = ᱫᱚᱞᱤᱞ ᱛᱮᱭᱟᱨ ᱛᱮᱫ
+pdfjs-attachments-button =
+ .title = ᱞᱟᱴᱷᱟ ᱥᱮᱞᱮᱫ ᱠᱚ ᱩᱫᱩᱜᱽ ᱢᱮ
+pdfjs-attachments-button-label = ᱞᱟᱴᱷᱟ ᱥᱮᱞᱮᱫ ᱠᱚ
+pdfjs-layers-button =
+ .title = ᱯᱚᱨᱚᱛ ᱫᱮᱠᱷᱟᱣ ᱢᱮ (ᱢᱩᱞ ᱡᱟᱭᱜᱟ ᱛᱮ ᱡᱷᱚᱛᱚ ᱯᱚᱨᱚᱛᱠᱚ ᱨᱤᱥᱮᱴ ᱞᱟᱹᱜᱤᱫ ᱵᱟᱨ ᱡᱮᱠᱷᱟ ᱚᱛᱚᱭ ᱢᱮ)
+pdfjs-layers-button-label = ᱯᱚᱨᱚᱛᱠᱚ
+pdfjs-thumbs-button =
+ .title = ᱪᱤᱛᱟᱹᱨ ᱟᱦᱞᱟ ᱠᱚ ᱩᱫᱩᱜᱽ ᱢᱮ
+pdfjs-thumbs-button-label = ᱪᱤᱛᱟᱹᱨ ᱟᱦᱞᱟ ᱠᱚ
+pdfjs-current-outline-item-button =
+ .title = ᱱᱤᱛᱚᱜᱟᱜ ᱟᱣᱴᱞᱟᱭᱤᱱ ᱡᱟᱱᱤᱥ ᱯᱟᱱᱛᱮ ᱢᱮ
+pdfjs-current-outline-item-button-label = ᱱᱤᱛᱚᱜᱟᱜ ᱟᱣᱴᱞᱟᱭᱤᱱ ᱡᱟᱱᱤᱥ
+pdfjs-findbar-button =
+ .title = ᱫᱚᱞᱤᱞ ᱨᱮ ᱯᱟᱱᱛᱮ
+pdfjs-findbar-button-label = ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ
+pdfjs-additional-layers = ᱵᱟᱹᱲᱛᱤ ᱯᱚᱨᱚᱛᱠᱚ
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } ᱥᱟᱦᱴᱟ
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } ᱥᱟᱦᱴᱟ ᱨᱮᱭᱟᱜ ᱪᱤᱛᱟᱹᱨ ᱟᱦᱞᱟ
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ
+ .placeholder = ᱫᱚᱞᱤᱞ ᱨᱮ ᱯᱟᱱᱛᱮ ᱢᱮ …
+pdfjs-find-previous-button =
+ .title = ᱟᱭᱟᱛ ᱦᱤᱸᱥ ᱨᱮᱭᱟᱜ ᱯᱟᱹᱦᱤᱞ ᱥᱮᱫᱟᱜ ᱚᱰᱚᱠ ᱧᱟᱢ ᱢᱮ
+pdfjs-find-previous-button-label = ᱢᱟᱲᱟᱝᱟᱜ
+pdfjs-find-next-button =
+ .title = ᱟᱭᱟᱛ ᱦᱤᱸᱥ ᱨᱮᱭᱟᱜ ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ ᱚᱰᱚᱠ ᱧᱟᱢ ᱢᱮ
+pdfjs-find-next-button-label = ᱤᱱᱟᱹ ᱛᱟᱭᱚᱢ
+pdfjs-find-highlight-checkbox = ᱡᱷᱚᱛᱚ ᱩᱫᱩᱜ ᱨᱟᱠᱟᱵ
+pdfjs-find-match-case-checkbox-label = ᱡᱚᱲ ᱠᱟᱛᱷᱟ
+pdfjs-find-match-diacritics-checkbox-label = ᱵᱤᱥᱮᱥᱚᱠ ᱠᱚ ᱢᱮᱲᱟᱣ ᱢᱮ
+pdfjs-find-entire-word-checkbox-label = ᱡᱷᱚᱛᱚ ᱟᱹᱲᱟᱹᱠᱚ
+pdfjs-find-reached-top = ᱫᱚᱞᱤᱞ ᱨᱮᱭᱟᱜ ᱪᱤᱴ ᱨᱮ ᱥᱮᱴᱮᱨ, ᱞᱟᱛᱟᱨ ᱠᱷᱚᱱ ᱞᱮᱛᱟᱲ
+pdfjs-find-reached-bottom = ᱫᱚᱞᱤᱞ ᱨᱮᱭᱟᱜ ᱢᱩᱪᱟᱹᱫ ᱨᱮ ᱥᱮᱴᱮᱨ, ᱪᱚᱴ ᱠᱷᱚᱱ ᱞᱮᱛᱟᱲ
+pdfjs-find-not-found = ᱛᱚᱯᱚᱞ ᱫᱚᱱᱚᱲ ᱵᱟᱝ ᱧᱟᱢ ᱞᱮᱱᱟ
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ᱥᱟᱦᱴᱟ ᱚᱥᱟᱨ
+pdfjs-page-scale-fit = ᱥᱟᱦᱴᱟ ᱠᱷᱟᱯ
+pdfjs-page-scale-auto = ᱟᱡᱼᱟᱡ ᱛᱮ ᱦᱩᱰᱤᱧ ᱞᱟᱹᱴᱩ ᱛᱮᱭᱟᱨ
+pdfjs-page-scale-actual = ᱴᱷᱤᱠ ᱢᱟᱨᱟᱝ ᱛᱮᱫ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = { $page } ᱥᱟᱦᱴᱟ
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF ᱞᱟᱫᱮ ᱡᱚᱦᱚᱜ ᱢᱤᱫ ᱵᱷᱩᱞ ᱦᱩᱭ ᱮᱱᱟ ᱾
+pdfjs-invalid-file-error = ᱵᱟᱝ ᱵᱟᱛᱟᱣ ᱟᱨᱵᱟᱝᱠᱷᱟᱱ ᱰᱤᱜᱟᱹᱣ PDF ᱨᱮᱫᱽ ᱾
+pdfjs-missing-file-error = ᱟᱫᱟᱜ PDF ᱨᱮᱫᱽ ᱾
+pdfjs-unexpected-response-error = ᱵᱟᱝᱵᱩᱡᱷ ᱥᱚᱨᱵᱷᱚᱨ ᱛᱮᱞᱟ ᱾
+pdfjs-rendering-error = ᱥᱟᱦᱴᱟ ᱮᱢ ᱡᱚᱦᱚᱠ ᱢᱤᱫ ᱵᱷᱩᱞ ᱦᱩᱭ ᱮᱱᱟ ᱾
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } ᱢᱚᱱᱛᱚ ᱮᱢ]
+
+## Password
+
+pdfjs-password-label = ᱱᱚᱶᱟ PDF ᱨᱮᱫᱽ ᱡᱷᱤᱡᱽ ᱞᱟᱹᱜᱤᱫ ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫᱽ ᱟᱫᱮᱨ ᱢᱮ ᱾
+pdfjs-password-invalid = ᱵᱷᱩᱞ ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫᱽ ᱾ ᱫᱟᱭᱟᱠᱟᱛᱮ ᱫᱩᱦᱲᱟᱹ ᱪᱮᱥᱴᱟᱭ ᱢᱮ ᱾
+pdfjs-password-ok-button = ᱴᱷᱤᱠ
+pdfjs-password-cancel-button = ᱵᱟᱹᱰᱨᱟᱹ
+pdfjs-web-fonts-disabled = ᱣᱮᱵᱽ ᱪᱤᱠᱤ ᱵᱟᱝ ᱦᱩᱭ ᱦᱚᱪᱚ ᱠᱟᱱᱟ : ᱵᱷᱤᱛᱤᱨ ᱛᱷᱟᱯᱚᱱ PDF ᱪᱤᱠᱤ ᱵᱮᱵᱷᱟᱨ ᱵᱟᱝ ᱦᱩᱭ ᱠᱮᱭᱟ ᱾
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = ᱚᱞ
+pdfjs-editor-free-text-button-label = ᱚᱞ
+pdfjs-editor-ink-button =
+ .title = ᱛᱮᱭᱟᱨ
+pdfjs-editor-ink-button-label = ᱛᱮᱭᱟᱨ
+pdfjs-editor-stamp-button =
+ .title = ᱪᱤᱛᱟᱹᱨᱠᱚ ᱥᱮᱞᱮᱫ ᱥᱮ ᱥᱟᱯᱲᱟᱣ ᱢᱮ
+pdfjs-editor-stamp-button-label = ᱪᱤᱛᱟᱹᱨᱠᱚ ᱥᱮᱞᱮᱫ ᱥᱮ ᱥᱟᱯᱲᱟᱣ ᱢᱮ
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = ᱨᱚᱝ
+pdfjs-editor-free-text-size-input = ᱢᱟᱯ
+pdfjs-editor-ink-color-input = ᱨᱚᱝ
+pdfjs-editor-ink-thickness-input = ᱢᱚᱴᱟ
+pdfjs-editor-ink-opacity-input = ᱟᱨᱯᱟᱨ
+pdfjs-editor-stamp-add-image-button =
+ .title = ᱪᱤᱛᱟᱹᱨ ᱥᱮᱞᱮᱫ ᱢᱮ
+pdfjs-editor-stamp-add-image-button-label = ᱪᱤᱛᱟᱹᱨ ᱥᱮᱞᱮᱫ ᱢᱮ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sc/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sc/viewer.ftl
new file mode 100644
index 0000000..7f334e4
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sc/viewer.ftl
@@ -0,0 +1,468 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pàgina anteriore
+pdfjs-previous-button-label = S'ischeda chi b'est primu
+pdfjs-next-button =
+ .title = Pàgina imbeniente
+pdfjs-next-button-label = Imbeniente
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pàgina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = de { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } de { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Impitica
+pdfjs-zoom-out-button-label = Impitica
+pdfjs-zoom-in-button =
+ .title = Ismànnia
+pdfjs-zoom-in-button-label = Ismànnia
+pdfjs-zoom-select =
+ .title = Ismànnia
+pdfjs-presentation-mode-button =
+ .title = Cola a sa modalidade de presentatzione
+pdfjs-presentation-mode-button-label = Modalidade de presentatzione
+pdfjs-open-file-button =
+ .title = Aberi s'archìviu
+pdfjs-open-file-button-label = Abertu
+pdfjs-print-button =
+ .title = Imprenta
+pdfjs-print-button-label = Imprenta
+pdfjs-save-button =
+ .title = Sarva
+pdfjs-save-button-label = Sarva
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Iscàrriga
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Iscàrriga
+pdfjs-bookmark-button =
+ .title = Pàgina atuale (ammustra s’URL de sa pàgina atuale)
+pdfjs-bookmark-button-label = Pàgina atuale
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Istrumentos
+pdfjs-tools-button-label = Istrumentos
+pdfjs-first-page-button =
+ .title = Bae a sa prima pàgina
+pdfjs-first-page-button-label = Bae a sa prima pàgina
+pdfjs-last-page-button =
+ .title = Bae a s'ùrtima pàgina
+pdfjs-last-page-button-label = Bae a s'ùrtima pàgina
+pdfjs-page-rotate-cw-button =
+ .title = Gira in sensu oràriu
+pdfjs-page-rotate-cw-button-label = Gira in sensu oràriu
+pdfjs-page-rotate-ccw-button =
+ .title = Gira in sensu anti-oràriu
+pdfjs-page-rotate-ccw-button-label = Gira in sensu anti-oràriu
+pdfjs-cursor-text-select-tool-button =
+ .title = Ativa s'aina de seletzione de testu
+pdfjs-cursor-text-select-tool-button-label = Aina de seletzione de testu
+pdfjs-cursor-hand-tool-button =
+ .title = Ativa s'aina de manu
+pdfjs-cursor-hand-tool-button-label = Aina de manu
+pdfjs-scroll-page-button =
+ .title = Imprea s'iscurrimentu de pàgina
+pdfjs-scroll-page-button-label = Iscurrimentu de pàgina
+pdfjs-scroll-vertical-button =
+ .title = Imprea s'iscurrimentu verticale
+pdfjs-scroll-vertical-button-label = Iscurrimentu verticale
+pdfjs-scroll-horizontal-button =
+ .title = Imprea s'iscurrimentu orizontale
+pdfjs-scroll-horizontal-button-label = Iscurrimentu orizontale
+pdfjs-scroll-wrapped-button =
+ .title = Imprea s'iscurrimentu continu
+pdfjs-scroll-wrapped-button-label = Iscurrimentu continu
+pdfjs-spread-none-button-label = Pàginas individuales
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Propiedades de su documentu…
+pdfjs-document-properties-button-label = Propiedades de su documentu…
+pdfjs-document-properties-file-name = Nòmine de s'archìviu:
+pdfjs-document-properties-file-size = Mannària de s'archìviu:
+pdfjs-document-properties-title = Tìtulu:
+pdfjs-document-properties-author = Autoria:
+pdfjs-document-properties-subject = Ogetu:
+pdfjs-document-properties-keywords = Faeddos crae:
+pdfjs-document-properties-creation-date = Data de creatzione:
+pdfjs-document-properties-modification-date = Data de modìfica:
+pdfjs-document-properties-creator = Creatzione:
+pdfjs-document-properties-producer = Produtore de PDF:
+pdfjs-document-properties-version = Versione de PDF:
+pdfjs-document-properties-page-count = Contu de pàginas:
+pdfjs-document-properties-page-size = Mannària de sa pàgina:
+pdfjs-document-properties-page-size-unit-inches = pòddighes
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = verticale
+pdfjs-document-properties-page-size-orientation-landscape = orizontale
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Lìtera
+pdfjs-document-properties-page-size-name-legal = Legale
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Visualizatzione web lestra:
+pdfjs-document-properties-linearized-yes = Eja
+pdfjs-document-properties-linearized-no = Nono
+pdfjs-document-properties-close-button = Serra
+pdfjs-digital-signature-properties-view-certificate = Ammustra su tzertificadu
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Resone: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Data e ora: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Print
+
+pdfjs-print-progress-message = Aparitzende s'imprenta de su documentu…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Annulla
+pdfjs-printing-not-supported = Atentzione: s'imprenta no est funtzionende de su totu in custu navigadore.
+pdfjs-printing-not-ready = Atentzione: su PDF no est istadu carrigadu de su totu pro s'imprenta.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Ativa/disativa sa barra laterale
+pdfjs-toggle-sidebar-notification-button =
+ .title = Ativa/disativa sa barra laterale (su documentu cuntenet un'ischema, alligongiados o livellos)
+pdfjs-toggle-sidebar-button-label = Ativa/disativa sa barra laterale
+pdfjs-document-outline-button-label = Ischema de su documentu
+pdfjs-attachments-button =
+ .title = Ammustra alligongiados
+pdfjs-attachments-button-label = Alliongiados
+pdfjs-layers-button =
+ .title = Ammustra livellos (clic dòpiu pro ripristinare totu is livellos a s'istadu predefinidu)
+pdfjs-layers-button-label = Livellos
+pdfjs-thumbs-button =
+ .title = Ammustra miniaturas
+pdfjs-thumbs-button-label = Miniaturas
+pdfjs-current-outline-item-button =
+ .title = Agata s'elementu atuale de s'ischema
+pdfjs-current-outline-item-button-label = Elementu atuale de s'ischema
+pdfjs-findbar-button =
+ .title = Agata in su documentu
+pdfjs-findbar-button-label = Agata
+pdfjs-additional-layers = Livellos additzionales
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pàgina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura de sa pàgina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Seletziona sa pàgina { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Pàgina { $page } de { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Agata
+ .placeholder = Agata in su documentu…
+pdfjs-find-previous-button =
+ .title = Agata s'ocurrèntzia pretzedente de sa fràsia
+pdfjs-find-previous-button-label = S'ischeda chi b'est primu
+pdfjs-find-next-button =
+ .title = Agata s'ocurrèntzia imbeniente de sa fràsia
+pdfjs-find-next-button-label = Imbeniente
+pdfjs-find-highlight-checkbox = Evidèntzia totu
+pdfjs-find-match-case-checkbox-label = Distinghe intre majùsculas e minùsculas
+pdfjs-find-match-diacritics-checkbox-label = Respeta is diacrìticos
+pdfjs-find-entire-word-checkbox-label = Faeddos intreos
+pdfjs-find-reached-top = S'est lòmpidu a su cumintzu de su documentu, si sighit dae su bàsciu
+pdfjs-find-reached-bottom = Acabbu de su documentu, si sighit dae s'artu
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } currispondèntzia de { $total }
+ *[other] { $current } currispondèntzias de { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Prus de { $limit } currispondèntzia
+ *[other] Prus de { $limit } currispondèntzias
+ }
+pdfjs-find-not-found = Testu no agatadu
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Larghesa de sa pàgina
+pdfjs-page-scale-fit = Pàgina intrea
+pdfjs-page-scale-auto = Ingrandimentu automàticu
+pdfjs-page-scale-actual = Mannària reale
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Pàgina { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Faddina in sa càrriga de su PDF.
+pdfjs-invalid-file-error = Archìviu PDF non vàlidu o corrùmpidu.
+pdfjs-missing-file-error = Ammancat s'archìviu PDF.
+pdfjs-unexpected-response-error = Risposta imprevista de su serbidore.
+pdfjs-rendering-error = Faddina in sa visualizatzione de sa pàgina.
+
+## Annotations
+
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Inserta sa crae pro abèrrere custu archìviu PDF.
+pdfjs-password-invalid = Sa crae no est curreta. Torra a nche proare.
+pdfjs-password-ok-button = Andat bene
+pdfjs-password-cancel-button = Annulla
+pdfjs-web-fonts-disabled = Is tipografias web sunt disativadas: is tipografias incrustadas a su PDF non podent èssere impreadas.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Testu
+pdfjs-editor-color-picker-free-text-input =
+ .title = Muda su colore de su testu
+pdfjs-editor-free-text-button-label = Testu
+pdfjs-editor-ink-button =
+ .title = Disinnu
+pdfjs-editor-color-picker-ink-input =
+ .title = Muda su colore pro su disinnu
+pdfjs-editor-ink-button-label = Disinnu
+pdfjs-editor-stamp-button =
+ .title = Agiunghe o modìfica immàgines
+pdfjs-editor-stamp-button-label = Agiunghe o modìfica immàgines
+pdfjs-editor-highlight-button =
+ .title = Evidèntzia
+pdfjs-editor-highlight-button-label = Evidèntzia
+pdfjs-highlight-floating-button1 =
+ .title = Evidèntzia
+ .aria-label = Evidèntzia
+pdfjs-highlight-floating-button-label = Evidèntzia
+pdfjs-comment-floating-button =
+ .title = Cummenta
+ .aria-label = Cummenta
+pdfjs-comment-floating-button-label = Cummenta
+pdfjs-editor-comment-button =
+ .title = Cummenta
+ .aria-label = Cummenta
+pdfjs-editor-comment-button-label = Cummenta
+pdfjs-editor-signature-button =
+ .title = Agiunghe una firma
+pdfjs-editor-signature-button-label = Agiunghe una firma
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editore de sutaliniadura
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editore de disinnos
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editore de firmas: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editore de immàgines
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Boga su disinnu
+pdfjs-editor-remove-freetext-button =
+ .title = Boga su testu
+pdfjs-editor-remove-stamp-button =
+ .title = Boga s’immàgine
+pdfjs-editor-remove-highlight-button =
+ .title = Boga s’evidèntzia
+pdfjs-editor-remove-signature-button =
+ .title = Boga·nche sa firma
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Colore
+pdfjs-editor-free-text-size-input = Mannària
+pdfjs-editor-ink-color-input = Colore
+pdfjs-editor-ink-thickness-input = Grussària
+pdfjs-editor-stamp-add-image-button =
+ .title = Agiunghe un’immàgine
+pdfjs-editor-stamp-add-image-button-label = Agiunghe un’immàgine
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Grussària
+pdfjs-editor-add-signature-container =
+ .aria-label = Controllos de firma e firmas sarvadas
+pdfjs-editor-signature-add-signature-button =
+ .title = Agiunghe una firma noa
+pdfjs-editor-signature-add-signature-button-label = Agiunghe una firma noa
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Firma sarvada: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Editore de testu
+ .default-content = Cumintza a iscrìere…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Cummentu
+ *[other] Cummentos
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Serra sa barra laterale
+ .aria-label = Serra sa barra laterale
+pdfjs-editor-comments-sidebar-close-button-label = Serra sa barra laterale
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = As rilevadu una cosa de interessu? Sinnala·dda e agiunghe unu cummentu.
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Testu alternativu
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Modifica su testu alternativu
+pdfjs-editor-alt-text-dialog-label = Sèbera un’optzione
+pdfjs-editor-alt-text-dialog-description = Su testu alternativu (“alt text”) est ùtile pro persones chi non podent bìdere s’immàgine o cando non benit carrigada.
+pdfjs-editor-alt-text-add-description-label = Agiunghe una descritzione
+pdfjs-editor-alt-text-mark-decorative-label = Sinnala comente decorativa
+pdfjs-editor-alt-text-cancel-button = Annulla
+pdfjs-editor-alt-text-save-button = Sarva
+pdfjs-editor-alt-text-decorative-tooltip = Sinnalada comente decorativu
+
+## Color picker
+
+pdfjs-editor-colorpicker-button =
+ .title = Modifica su colore
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Colores a disponimentu
+pdfjs-editor-colorpicker-yellow =
+ .title = Grogu
+pdfjs-editor-colorpicker-green =
+ .title = Birde
+pdfjs-editor-colorpicker-blue =
+ .title = Biaitu
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Mancat su testu alternativu
+pdfjs-editor-new-alt-text-missing-button-label = Mancat su testu alternativu
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Revisiona su testu alternativu
+pdfjs-editor-new-alt-text-to-review-button-label = Revisiona su testu alternativu
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Creadu in automàticu: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Cunfiguratzione de su testu alternativu de is immàgines
+pdfjs-image-alt-text-settings-button-label = Cunfiguratzione de su testu alternativu de is immàgines
+pdfjs-editor-alt-text-settings-dialog-label = Cunfiguratzione de su testu alternativu de is immàgines
+pdfjs-editor-alt-text-settings-automatic-title = Testu alternativu automàticu
+pdfjs-editor-alt-text-settings-create-model-button-label = Crea testu alternativu in automàticu
+pdfjs-editor-alt-text-settings-create-model-description = Cussìgiat descritziones pro agiudare a gente chi non podet bìdere s’immàgine o cando non benit carrigada.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Modellu de IA pro su testu alternativu ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Est esecutadu in locale in manera chi is datos tuos abarrent in privadu. Rechestu pro sa generatzione automàtica de testu alternativu.
+pdfjs-editor-alt-text-settings-delete-model-button = Cantzella
+pdfjs-editor-alt-text-settings-download-model-button = Iscàrriga
+pdfjs-editor-alt-text-settings-downloading-model-button = Iscarrighende…
+pdfjs-editor-alt-text-settings-editor-title = Editore de testu alternativu
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Mustra deretu s’editore de testu alternativu cando siat agiunta un’immàgine
+pdfjs-editor-alt-text-settings-show-dialog-description = T’agiudat a assegurare chi totu is immàgines tuas tèngiant unu testu alternativu.
+pdfjs-editor-alt-text-settings-close-button = Serra
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-freetext = Testu cantzelladu
+pdfjs-editor-undo-bar-message-ink = Disinnu cantzelladu
+pdfjs-editor-undo-bar-message-stamp = Immàgine cantzellada
+pdfjs-editor-undo-bar-message-signature = Firma cantzellada
+pdfjs-editor-undo-bar-undo-button =
+ .title = Iscontza
+pdfjs-editor-undo-bar-undo-button-label = Iscontza
+pdfjs-editor-undo-bar-close-button =
+ .title = Serra
+pdfjs-editor-undo-bar-close-button-label = Serra
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Annulla
+
+## Edit a comment dialog
+
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Cumintza a iscrìere…
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/scn/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/scn/viewer.ftl
new file mode 100644
index 0000000..287201a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/scn/viewer.ftl
@@ -0,0 +1,32 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-zoom-out-button =
+ .title = Cchiù nicu
+pdfjs-zoom-out-button-label = Cchiù nicu
+pdfjs-zoom-in-button =
+ .title = Cchiù granni
+pdfjs-zoom-in-button-label = Cchiù granni
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Vista web lesta:
+pdfjs-document-properties-linearized-yes = Se
+
+## Print
+
+pdfjs-print-progress-close-button = Sfai
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Larghizza dâ pàggina
+
+## Password
+
+pdfjs-password-cancel-button = Sfai
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sco/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sco/viewer.ftl
new file mode 100644
index 0000000..ed4c3bb
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sco/viewer.ftl
@@ -0,0 +1,238 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Page Afore
+pdfjs-previous-button-label = Previous
+pdfjs-next-button =
+ .title = Page Efter
+pdfjs-next-button-label = Neist
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Page
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = o { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } o { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zoom Oot
+pdfjs-zoom-out-button-label = Zoom Oot
+pdfjs-zoom-in-button =
+ .title = Zoom In
+pdfjs-zoom-in-button-label = Zoom In
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Flit tae Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Open File
+pdfjs-open-file-button-label = Open
+pdfjs-print-button =
+ .title = Prent
+pdfjs-print-button-label = Prent
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Tools
+pdfjs-tools-button-label = Tools
+pdfjs-first-page-button =
+ .title = Gang tae First Page
+pdfjs-first-page-button-label = Gang tae First Page
+pdfjs-last-page-button =
+ .title = Gang tae Lest Page
+pdfjs-last-page-button-label = Gang tae Lest Page
+pdfjs-page-rotate-cw-button =
+ .title = Rotate Clockwise
+pdfjs-page-rotate-cw-button-label = Rotate Clockwise
+pdfjs-page-rotate-ccw-button =
+ .title = Rotate Coonterclockwise
+pdfjs-page-rotate-ccw-button-label = Rotate Coonterclockwise
+pdfjs-cursor-text-select-tool-button =
+ .title = Enable Text Walin Tool
+pdfjs-cursor-text-select-tool-button-label = Text Walin Tool
+pdfjs-cursor-hand-tool-button =
+ .title = Enable Haun Tool
+pdfjs-cursor-hand-tool-button-label = Haun Tool
+pdfjs-scroll-vertical-button =
+ .title = Yaise Vertical Scrollin
+pdfjs-scroll-vertical-button-label = Vertical Scrollin
+pdfjs-scroll-horizontal-button =
+ .title = Yaise Horizontal Scrollin
+pdfjs-scroll-horizontal-button-label = Horizontal Scrollin
+pdfjs-scroll-wrapped-button =
+ .title = Yaise Wrapped Scrollin
+pdfjs-scroll-wrapped-button-label = Wrapped Scrollin
+pdfjs-spread-none-button =
+ .title = Dinnae jyn page spreids
+pdfjs-spread-none-button-label = Nae Spreids
+pdfjs-spread-odd-button =
+ .title = Jyn page spreids stertin wi odd-numbered pages
+pdfjs-spread-odd-button-label = Odd Spreids
+pdfjs-spread-even-button =
+ .title = Jyn page spreids stertin wi even-numbered pages
+pdfjs-spread-even-button-label = Even Spreids
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Document Properties…
+pdfjs-document-properties-button-label = Document Properties…
+pdfjs-document-properties-file-name = File nemme:
+pdfjs-document-properties-file-size = File size:
+pdfjs-document-properties-title = Title:
+pdfjs-document-properties-author = Author:
+pdfjs-document-properties-subject = Subjeck:
+pdfjs-document-properties-keywords = Keywirds:
+pdfjs-document-properties-creation-date = Date o Makkin:
+pdfjs-document-properties-modification-date = Date o Chynges:
+pdfjs-document-properties-creator = Makker:
+pdfjs-document-properties-producer = PDF Producer:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Page Coont:
+pdfjs-document-properties-page-size = Page Size:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portrait
+pdfjs-document-properties-page-size-orientation-landscape = landscape
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Wab View:
+pdfjs-document-properties-linearized-yes = Aye
+pdfjs-document-properties-linearized-no = Naw
+pdfjs-document-properties-close-button = Sneck
+
+## Print
+
+pdfjs-print-progress-message = Reddin document fur prentin…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Stap
+pdfjs-printing-not-supported = Tak tent: Prentin isnae richt supportit by this stravaiger.
+pdfjs-printing-not-ready = Tak tent: The PDF isnae richt loadit fur prentin.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Toggle Sidebaur
+pdfjs-toggle-sidebar-notification-button =
+ .title = Toggle Sidebaur (document conteens ootline/attachments/layers)
+pdfjs-toggle-sidebar-button-label = Toggle Sidebaur
+pdfjs-document-outline-button =
+ .title = Kythe Document Ootline (double-click fur tae oot-fauld/in-fauld aw items)
+pdfjs-document-outline-button-label = Document Ootline
+pdfjs-attachments-button =
+ .title = Kythe Attachments
+pdfjs-attachments-button-label = Attachments
+pdfjs-layers-button =
+ .title = Kythe Layers (double-click fur tae reset aw layers tae the staunart state)
+pdfjs-layers-button-label = Layers
+pdfjs-thumbs-button =
+ .title = Kythe Thumbnails
+pdfjs-thumbs-button-label = Thumbnails
+pdfjs-current-outline-item-button =
+ .title = Find Current Ootline Item
+pdfjs-current-outline-item-button-label = Current Ootline Item
+pdfjs-findbar-button =
+ .title = Find in Document
+pdfjs-findbar-button-label = Find
+pdfjs-additional-layers = Mair Layers
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Page { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail o Page { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Find
+ .placeholder = Find in document…
+pdfjs-find-previous-button =
+ .title = Airt oot the last time this phrase occurred
+pdfjs-find-previous-button-label = Previous
+pdfjs-find-next-button =
+ .title = Airt oot the neist time this phrase occurs
+pdfjs-find-next-button-label = Neist
+pdfjs-find-highlight-checkbox = Highlicht aw
+pdfjs-find-match-case-checkbox-label = Match case
+pdfjs-find-entire-word-checkbox-label = Hale Wirds
+pdfjs-find-reached-top = Raxed tap o document, went on fae the dowp end
+pdfjs-find-reached-bottom = Raxed end o document, went on fae the tap
+pdfjs-find-not-found = Phrase no fund
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Page Width
+pdfjs-page-scale-fit = Page Fit
+pdfjs-page-scale-auto = Automatic Zoom
+pdfjs-page-scale-actual = Actual Size
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Page { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = An mishanter tuik place while loadin the PDF.
+pdfjs-invalid-file-error = No suithfest or camshauchlet PDF file.
+pdfjs-missing-file-error = PDF file tint.
+pdfjs-unexpected-response-error = Unexpectit server repone.
+pdfjs-rendering-error = A mishanter tuik place while renderin the page.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = Inpit the passwird fur tae open this PDF file.
+pdfjs-password-invalid = Passwird no suithfest. Gonnae gie it anither shot.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Stap
+pdfjs-web-fonts-disabled = Wab fonts are disabled: cannae yaise embeddit PDF fonts.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/si/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/si/viewer.ftl
new file mode 100644
index 0000000..28d53f3
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/si/viewer.ftl
@@ -0,0 +1,228 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = කලින් පිටුව
+pdfjs-previous-button-label = කලින්
+pdfjs-next-button =
+ .title = ඊළඟ පිටුව
+pdfjs-next-button-label = ඊළඟ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = පිටුව
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = කුඩාලනය
+pdfjs-zoom-out-button-label = කුඩාලනය
+pdfjs-zoom-in-button =
+ .title = විශාලනය
+pdfjs-zoom-in-button-label = විශාලනය
+pdfjs-zoom-select =
+ .title = විශාල කරන්න
+pdfjs-presentation-mode-button =
+ .title = සමර්පණ ප්රකාරය වෙත මාරුවන්න
+pdfjs-presentation-mode-button-label = සමර්පණ ප්රකාරය
+pdfjs-open-file-button =
+ .title = ගොනුව අරින්න
+pdfjs-open-file-button-label = අරින්න
+pdfjs-print-button =
+ .title = මුද්රණය
+pdfjs-print-button-label = මුද්රණය
+pdfjs-save-button =
+ .title = සුරකින්න
+pdfjs-save-button-label = සුරකින්න
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = බාගන්න
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = බාගන්න
+pdfjs-bookmark-button-label = පවතින පිටුව
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = මෙවලම්
+pdfjs-tools-button-label = මෙවලම්
+pdfjs-first-page-button =
+ .title = මුල් පිටුවට යන්න
+pdfjs-first-page-button-label = මුල් පිටුවට යන්න
+pdfjs-last-page-button =
+ .title = අවසන් පිටුවට යන්න
+pdfjs-last-page-button-label = අවසන් පිටුවට යන්න
+pdfjs-cursor-text-select-tool-button =
+ .title = පෙළ තේරීමේ මෙවලම සබල කරන්න
+pdfjs-cursor-text-select-tool-button-label = පෙළ තේරීමේ මෙවලම
+pdfjs-cursor-hand-tool-button =
+ .title = අත් මෙවලම සබල කරන්න
+pdfjs-cursor-hand-tool-button-label = අත් මෙවලම
+pdfjs-scroll-page-button =
+ .title = පිටුව අනුචලනය භාවිතය
+pdfjs-scroll-page-button-label = පිටුව අනුචලනය
+pdfjs-scroll-vertical-button =
+ .title = සිරස් අනුචලනය භාවිතය
+pdfjs-scroll-vertical-button-label = සිරස් අනුචලනය
+pdfjs-scroll-horizontal-button =
+ .title = තිරස් අනුචලනය භාවිතය
+pdfjs-scroll-horizontal-button-label = තිරස් අනුචලනය
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = ලේඛනයේ ගුණාංග…
+pdfjs-document-properties-button-label = ලේඛනයේ ගුණාංග…
+pdfjs-document-properties-file-name = ගොනුවේ නම:
+pdfjs-document-properties-file-size = ගොනුවේ ප්රමාණය:
+pdfjs-document-properties-title = සිරැසිය:
+pdfjs-document-properties-author = කතෘ:
+pdfjs-document-properties-subject = මාතෘකාව:
+pdfjs-document-properties-keywords = මූල පද:
+pdfjs-document-properties-creation-date = සෑදූ දිනය:
+pdfjs-document-properties-modification-date = සංශෝධිත දිනය:
+pdfjs-document-properties-creator = නිර්මාතෘ:
+pdfjs-document-properties-producer = පීඩීඑෆ් සම්පාදක:
+pdfjs-document-properties-version = පීඩීඑෆ් අනුවාදය:
+pdfjs-document-properties-page-count = පිටු ගණන:
+pdfjs-document-properties-page-size = පිටුවේ තරම:
+pdfjs-document-properties-page-size-unit-inches = අඟල්
+pdfjs-document-properties-page-size-unit-millimeters = මි.මී.
+pdfjs-document-properties-page-size-orientation-portrait = සිරස්
+pdfjs-document-properties-page-size-orientation-landscape = තිරස්
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width }×{ $height }{ $unit }{ $name }{ $orientation }
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = වේගවත් වියමන දැක්ම:
+pdfjs-document-properties-linearized-yes = ඔව්
+pdfjs-document-properties-linearized-no = නැහැ
+pdfjs-document-properties-close-button = වසන්න
+
+## Print
+
+pdfjs-print-progress-message = මුද්රණය සඳහා ලේඛනය සූදානම් වෙමින්…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = අවලංගු කරන්න
+pdfjs-printing-not-supported = අවවාදයයි: මෙම අතිරික්සුව මුද්රණය සඳහා හොඳින් සහාය නොදක්වයි.
+pdfjs-printing-not-ready = අවවාදයයි: මුද්රණයට පීඩීඑෆ් ගොනුව සම්පූර්ණයෙන් පූරණය වී නැත.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-document-outline-button-label = ලේඛනයේ වටසන
+pdfjs-attachments-button =
+ .title = ඇමුණුම් පෙන්වන්න
+pdfjs-attachments-button-label = ඇමුණුම්
+pdfjs-layers-button =
+ .title = ස්තර පෙන්වන්න (සියළු ස්තර පෙරනිමි තත්වයට යළි සැකසීමට දෙවරක් ඔබන්න)
+pdfjs-layers-button-label = ස්තර
+pdfjs-thumbs-button =
+ .title = සිඟිති රූ පෙන්වන්න
+pdfjs-thumbs-button-label = සිඟිති රූ
+pdfjs-findbar-button =
+ .title = ලේඛනයෙහි සොයන්න
+pdfjs-findbar-button-label = සොයන්න
+pdfjs-additional-layers = අතිරේක ස්තර
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = පිටුව { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = පිටුවේ සිඟිත රූව { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = සොයන්න
+ .placeholder = ලේඛනයේ සොයන්න…
+pdfjs-find-previous-button =
+ .title = මෙම වැකිකඩ කලින් යෙදුණු ස්ථානය සොයන්න
+pdfjs-find-previous-button-label = කලින්
+pdfjs-find-next-button =
+ .title = මෙම වැකිකඩ ඊළඟට යෙදෙන ස්ථානය සොයන්න
+pdfjs-find-next-button-label = ඊළඟ
+pdfjs-find-highlight-checkbox = සියල්ල උද්දීපනය
+pdfjs-find-entire-word-checkbox-label = සමස්ත වචන
+pdfjs-find-reached-top = ලේඛනයේ මුදුනට ළඟා විය, පහළ සිට ඉහළට
+pdfjs-find-reached-bottom = ලේඛනයේ අවසානයට ළඟා විය, ඉහළ සිට පහළට
+pdfjs-find-not-found = වැකිකඩ හමු නොවුණි
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = පිටුවේ පළල
+pdfjs-page-scale-auto = ස්වයංක්රීය විශාලනය
+pdfjs-page-scale-actual = සැබෑ ප්රමාණය
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = පිටුව { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = පීඩීඑෆ් පූරණය කිරීමේදී දෝෂයක් සිදු විය.
+pdfjs-invalid-file-error = වලංගු නොවන හෝ හානිවූ පීඩීඑෆ් ගොනුවකි.
+pdfjs-missing-file-error = මඟහැරුණු පීඩීඑෆ් ගොනුවකි.
+pdfjs-unexpected-response-error = අනපේක්ෂිත සේවාදායක ප්රතිචාරයකි.
+
+## Password
+
+pdfjs-password-label = මෙම පීඩීඑෆ් ගොනුව විවෘත කිරීමට මුරපදය යොදන්න.
+pdfjs-password-invalid = වැරදි මුරපදයකි. නැවත උත්සාහ කරන්න.
+pdfjs-password-ok-button = හරි
+pdfjs-password-cancel-button = අවලංගු
+pdfjs-web-fonts-disabled = වියමන අකුරු අබලයි: පීඩීඑෆ් වෙත කාවැද්දූ රුවකුරු භාවිතා කළ නොහැකිය.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = පෙළ
+pdfjs-editor-free-text-button-label = පෙළ
+pdfjs-editor-ink-button =
+ .title = අඳින්න
+pdfjs-editor-ink-button-label = අඳින්න
+pdfjs-editor-stamp-button =
+ .title = රූප සංස්කරණය හෝ එක් කරන්න
+pdfjs-editor-stamp-button-label = රූප සංස්කරණය හෝ එක් කරන්න
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = වර්ණය
+pdfjs-editor-free-text-size-input = තරම
+pdfjs-editor-ink-color-input = වර්ණය
+pdfjs-editor-ink-thickness-input = ඝණකම
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-mark-decorative-description = මෙය දාර හෝ දිය සලකුණු වැනි අලංකාර රූප සඳහා භාවිතා වේ.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sk/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sk/viewer.ftl
new file mode 100644
index 0000000..0feefc1
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sk/viewer.ftl
@@ -0,0 +1,864 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Predchádzajúca strana
+pdfjs-previous-button-label = Predchádzajúca
+pdfjs-next-button =
+ .title = Nasledujúca strana
+pdfjs-next-button-label = Nasledujúca
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Strana
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = z { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } z { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zmenšiť veľkosť
+pdfjs-zoom-out-button-label = Zmenšiť veľkosť
+pdfjs-zoom-in-button =
+ .title = Zväčšiť veľkosť
+pdfjs-zoom-in-button-label = Zväčšiť veľkosť
+pdfjs-zoom-select =
+ .title = Nastavenie veľkosti
+pdfjs-presentation-mode-button =
+ .title = Prepnúť na režim prezentácie
+pdfjs-presentation-mode-button-label = Režim prezentácie
+pdfjs-open-file-button =
+ .title = Otvoriť súbor
+pdfjs-open-file-button-label = Otvoriť
+pdfjs-print-button =
+ .title = Tlačiť
+pdfjs-print-button-label = Tlačiť
+pdfjs-save-button =
+ .title = Uložiť
+pdfjs-save-button-label = Uložiť
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Stiahnuť
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Stiahnuť
+pdfjs-bookmark-button =
+ .title = Aktuálna stránka (zobraziť adresu URL z aktuálnej stránky)
+pdfjs-bookmark-button-label = Aktuálna stránka
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Nástroje
+pdfjs-tools-button-label = Nástroje
+pdfjs-first-page-button =
+ .title = Prejsť na prvú stranu
+pdfjs-first-page-button-label = Prejsť na prvú stranu
+pdfjs-last-page-button =
+ .title = Prejsť na poslednú stranu
+pdfjs-last-page-button-label = Prejsť na poslednú stranu
+pdfjs-page-rotate-cw-button =
+ .title = Otočiť v smere hodinových ručičiek
+pdfjs-page-rotate-cw-button-label = Otočiť v smere hodinových ručičiek
+pdfjs-page-rotate-ccw-button =
+ .title = Otočiť proti smeru hodinových ručičiek
+pdfjs-page-rotate-ccw-button-label = Otočiť proti smeru hodinových ručičiek
+pdfjs-cursor-text-select-tool-button =
+ .title = Povoliť výber textu
+pdfjs-cursor-text-select-tool-button-label = Výber textu
+pdfjs-cursor-hand-tool-button =
+ .title = Povoliť nástroj ruka
+pdfjs-cursor-hand-tool-button-label = Nástroj ruka
+pdfjs-scroll-page-button =
+ .title = Použiť rolovanie po stránkach
+pdfjs-scroll-page-button-label = Rolovanie po stránkach
+pdfjs-scroll-vertical-button =
+ .title = Používať zvislé posúvanie
+pdfjs-scroll-vertical-button-label = Zvislé posúvanie
+pdfjs-scroll-horizontal-button =
+ .title = Používať vodorovné posúvanie
+pdfjs-scroll-horizontal-button-label = Vodorovné posúvanie
+pdfjs-scroll-wrapped-button =
+ .title = Použiť postupné posúvanie
+pdfjs-scroll-wrapped-button-label = Postupné posúvanie
+pdfjs-spread-none-button =
+ .title = Nezdružovať stránky
+pdfjs-spread-none-button-label = Žiadne združovanie
+pdfjs-spread-odd-button =
+ .title = Združí stránky a umiestni nepárne stránky vľavo
+pdfjs-spread-odd-button-label = Združiť stránky (nepárne vľavo)
+pdfjs-spread-even-button =
+ .title = Združí stránky a umiestni párne stránky vľavo
+pdfjs-spread-even-button-label = Združiť stránky (párne vľavo)
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Vlastnosti dokumentu…
+pdfjs-document-properties-button-label = Vlastnosti dokumentu…
+pdfjs-document-properties-file-name = Názov súboru:
+pdfjs-document-properties-file-size = Veľkosť súboru:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } bajtov)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtov)
+pdfjs-document-properties-title = Názov:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Predmet:
+pdfjs-document-properties-keywords = Kľúčové slová:
+pdfjs-document-properties-creation-date = Dátum vytvorenia:
+pdfjs-document-properties-modification-date = Dátum úpravy:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Aplikácia:
+pdfjs-document-properties-producer = Tvorca PDF:
+pdfjs-document-properties-version = Verzia PDF:
+pdfjs-document-properties-page-count = Počet strán:
+pdfjs-document-properties-page-size = Veľkosť stránky:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = na výšku
+pdfjs-document-properties-page-size-orientation-landscape = na šírku
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = List
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Rýchle zobrazovanie z webu:
+pdfjs-document-properties-linearized-yes = Áno
+pdfjs-document-properties-linearized-no = Nie
+pdfjs-document-properties-close-button = Zavrieť
+pdfjs-digital-signature-properties-view-certificate = Zobraziť certifikát
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Dôvod: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Časová pečiatka: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Podpodpis ({ $count })
+ [few] Podpodpisy ({ $count })
+ [many] Podpodpisy ({ $count })
+ *[other] Podpodpisy ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Príprava dokumentu na tlač…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Zrušiť
+pdfjs-printing-not-supported = Upozornenie: tlač nie je v tomto prehliadači plne podporovaná.
+pdfjs-printing-not-ready = Upozornenie: súbor PDF nie je plne načítaný pre tlač.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Prepnúť bočný panel
+pdfjs-toggle-sidebar-notification-button =
+ .title = Prepnúť bočný panel (dokument obsahuje osnovu/prílohy/vrstvy)
+pdfjs-toggle-sidebar-button-label = Prepnúť bočný panel
+pdfjs-document-outline-button =
+ .title = Zobraziť osnovu dokumentu (dvojitým kliknutím rozbalíte/zbalíte všetky položky)
+pdfjs-document-outline-button-label = Osnova dokumentu
+pdfjs-attachments-button =
+ .title = Zobraziť prílohy
+pdfjs-attachments-button-label = Prílohy
+pdfjs-layers-button =
+ .title = Zobraziť vrstvy (dvojitým kliknutím uvediete všetky vrstvy do pôvodného stavu)
+pdfjs-layers-button-label = Vrstvy
+pdfjs-thumbs-button =
+ .title = Zobraziť miniatúry
+pdfjs-thumbs-button-label = Miniatúry
+pdfjs-current-outline-item-button =
+ .title = Nájsť aktuálnu položku v osnove
+pdfjs-current-outline-item-button-label = Aktuálna položka v osnove
+pdfjs-findbar-button =
+ .title = Hľadať v dokumente
+pdfjs-findbar-button-label = Hľadať
+pdfjs-additional-layers = Ďalšie vrstvy
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Strana { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatúra strany { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Vybrať stranu { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Strana { $page } z { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Hľadať
+ .placeholder = Hľadať v dokumente…
+pdfjs-find-previous-button =
+ .title = Vyhľadať predchádzajúci výskyt reťazca
+pdfjs-find-previous-button-label = Predchádzajúce
+pdfjs-find-next-button =
+ .title = Vyhľadať ďalší výskyt reťazca
+pdfjs-find-next-button-label = Ďalšie
+pdfjs-find-highlight-checkbox = Zvýrazniť všetky
+pdfjs-find-match-case-checkbox-label = Rozlišovať veľkosť písmen
+pdfjs-find-match-diacritics-checkbox-label = Rozlišovať diakritiku
+pdfjs-find-entire-word-checkbox-label = Celé slová
+pdfjs-find-reached-top = Bol dosiahnutý začiatok stránky, pokračuje sa od konca
+pdfjs-find-reached-bottom = Bol dosiahnutý koniec stránky, pokračuje sa od začiatku
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] Výskyt { $current } z { $total }
+ [few] Výskyt { $current } z { $total }
+ [many] Výskyt { $current } z { $total }
+ *[other] Výskyt { $current } z { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Viac ako { $limit } výskyt
+ [few] Viac ako { $limit } výskyty
+ [many] Viac ako { $limit } výskytov
+ *[other] Viac ako { $limit } výskytov
+ }
+pdfjs-find-not-found = Výraz nebol nájdený
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Na šírku strany
+pdfjs-page-scale-fit = Na veľkosť strany
+pdfjs-page-scale-auto = Automatická veľkosť
+pdfjs-page-scale-actual = Skutočná veľkosť
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Strana { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Počas načítavania dokumentu PDF sa vyskytla chyba.
+pdfjs-invalid-file-error = Neplatný alebo poškodený súbor PDF.
+pdfjs-missing-file-error = Chýbajúci súbor PDF.
+pdfjs-unexpected-response-error = Neočakávaná odpoveď zo servera.
+pdfjs-rendering-error = Pri vykresľovaní stránky sa vyskytla chyba.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotácia typu { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Ak chcete otvoriť tento súbor PDF, zadajte jeho heslo.
+pdfjs-password-invalid = Heslo nie je platné. Skúste to znova.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Zrušiť
+pdfjs-web-fonts-disabled = Webové písma sú vypnuté: nie je možné použiť písma vložené do súboru PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Zmeniť farbu textu
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Kresliť
+pdfjs-editor-color-picker-ink-input =
+ .title = Zmeniť farbu kresby
+pdfjs-editor-ink-button-label = Kresliť
+pdfjs-editor-stamp-button =
+ .title = Pridať alebo upraviť obrázky
+pdfjs-editor-stamp-button-label = Pridať alebo upraviť obrázky
+pdfjs-editor-highlight-button =
+ .title = Zvýrazniť
+pdfjs-editor-highlight-button-label = Zvýrazniť
+pdfjs-highlight-floating-button1 =
+ .title = Zvýrazniť
+ .aria-label = Zvýrazniť
+pdfjs-highlight-floating-button-label = Zvýrazniť
+pdfjs-comment-floating-button =
+ .title = Pridať komentár
+ .aria-label = Pridať komentár
+pdfjs-comment-floating-button-label = Pridať komentár
+pdfjs-editor-comment-button =
+ .title = Pridať komentár
+ .aria-label = Pridať komentár
+pdfjs-editor-comment-button-label = Pridať komentár
+pdfjs-editor-signature-button =
+ .title = Pridať podpis
+pdfjs-editor-signature-button-label = Pridať podpis
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Editor zvýraznenia
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Editor kreslenia
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Editor podpisu: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Editor obrázkov
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Odstrániť kresbu
+pdfjs-editor-remove-freetext-button =
+ .title = Odstrániť text
+pdfjs-editor-remove-stamp-button =
+ .title = Odstrániť obrázok
+pdfjs-editor-remove-highlight-button =
+ .title = Odstrániť zvýraznenie
+pdfjs-editor-remove-signature-button =
+ .title = Odstrániť podpis
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Farba
+pdfjs-editor-free-text-size-input = Veľkosť
+pdfjs-editor-ink-color-input = Farba
+pdfjs-editor-ink-thickness-input = Hrúbka
+pdfjs-editor-ink-opacity-input = Priehľadnosť
+pdfjs-editor-stamp-add-image-button =
+ .title = Pridať obrázok
+pdfjs-editor-stamp-add-image-button-label = Pridať obrázok
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Hrúbka
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Zmeňte hrúbku pre zvýrazňovanie iných položiek ako textu
+pdfjs-editor-add-signature-container =
+ .aria-label = Ovládacie prvky pre podpisy a uložené podpisy
+pdfjs-editor-signature-add-signature-button =
+ .title = Pridať nový podpis
+pdfjs-editor-signature-add-signature-button-label = Pridať nový podpis
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Uložený podpis: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Textový editor
+ .default-content = Začnite písať…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Komentár
+ [few] Komentáre
+ [many] Komentárov
+ *[other] Komentárov
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Zavrieť bočný panel
+ .aria-label = Zavrieť bočný panel
+pdfjs-editor-comments-sidebar-close-button-label = Zavrieť bočný panel
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Vidíte niečo pozoruhodné? Zvýraznite to a zanechajte komentár.
+pdfjs-editor-comments-sidebar-no-comments-link = Ďalšie informácie
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternatívny text
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Upraviť alternatívny text
+pdfjs-editor-alt-text-dialog-label = Vyberte možnosť
+pdfjs-editor-alt-text-dialog-description = Alternatívny text (alt text) pomáha, keď ľudia obrázok nevidia alebo sa nenačítava.
+pdfjs-editor-alt-text-add-description-label = Pridať popis
+pdfjs-editor-alt-text-add-description-description = Zamerajte sa na 1-2 vety, ktoré popisujú predmet, prostredie alebo akcie.
+pdfjs-editor-alt-text-mark-decorative-label = Označiť ako dekoratívny
+pdfjs-editor-alt-text-mark-decorative-description = Používa sa na ozdobné obrázky, ako sú okraje alebo vodoznaky.
+pdfjs-editor-alt-text-cancel-button = Zrušiť
+pdfjs-editor-alt-text-save-button = Uložiť
+pdfjs-editor-alt-text-decorative-tooltip = Označený ako dekoratívny
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Napríklad: „Mladý muž si sadá za stôl, aby sa najedol“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternatívny text
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Ľavý horný roh – zmena veľkosti
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Horný stred – zmena veľkosti
+pdfjs-editor-resizer-top-right =
+ .aria-label = Pravý horný roh – zmena veľkosti
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Vpravo uprostred – zmena veľkosti
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Pravý dolný roh – zmena veľkosti
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Stred dole – zmena veľkosti
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Ľavý dolný roh – zmena veľkosti
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Vľavo uprostred – zmena veľkosti
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Farba zvýraznenia
+pdfjs-editor-colorpicker-button =
+ .title = Zmeniť farbu
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Výber farieb
+pdfjs-editor-colorpicker-yellow =
+ .title = Žltá
+pdfjs-editor-colorpicker-green =
+ .title = Zelená
+pdfjs-editor-colorpicker-blue =
+ .title = Modrá
+pdfjs-editor-colorpicker-pink =
+ .title = Ružová
+pdfjs-editor-colorpicker-red =
+ .title = Červená
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Zobraziť všetko
+pdfjs-editor-highlight-show-all-button =
+ .title = Zobraziť všetko
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Upraviť alternatívny text (popis obrázka)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Pridať alternatívny text (popis obrázka)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Sem napíšte svoj popis…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Krátky popis pre ľudí, ktorí nevidia obrázok alebo ak sa obrázok nenačíta.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Tento alternatívny text bol vytvorený automaticky a môže byť nepresný.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Ďalšie informácie
+pdfjs-editor-new-alt-text-create-automatically-button-label = Automaticky vytvoriť alternatívny text
+pdfjs-editor-new-alt-text-not-now-button = Teraz nie
+pdfjs-editor-new-alt-text-error-title = Alternatívny text sa nepodarilo vytvoriť automaticky
+pdfjs-editor-new-alt-text-error-description = Napíšte svoj vlastný alternatívny text alebo to skúste znova neskôr.
+pdfjs-editor-new-alt-text-error-close-button = Zavrieť
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Sťahuje sa model AI pre alternatívne texty ({ $downloadedSize } z { $totalSize } MB)
+ .aria-valuetext = Sťahuje sa model AI pre alternatívne texty ({ $downloadedSize } z { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternatívny text bol pridaný
+pdfjs-editor-new-alt-text-added-button-label = Alternatívny text bol pridaný
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Chýbajúci alternatívny text
+pdfjs-editor-new-alt-text-missing-button-label = Chýbajúci alternatívny text
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Skontrolovať alternatívny text
+pdfjs-editor-new-alt-text-to-review-button-label = Skontrolovať alternatívny text
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Vytvorené automaticky: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Nastavenia alternatívneho textu obrázka
+pdfjs-image-alt-text-settings-button-label = Nastavenia alternatívneho textu obrázka
+pdfjs-editor-alt-text-settings-dialog-label = Nastavenia alternatívneho textu obrázka
+pdfjs-editor-alt-text-settings-automatic-title = Automatický alternatívny text
+pdfjs-editor-alt-text-settings-create-model-button-label = Automaticky vytvoriť alternatívny text
+pdfjs-editor-alt-text-settings-create-model-description = Navrhuje popisy, ktoré pomôžu ľuďom, ktorým sa obrázok nezobrazuje alebo ak sa obrázok nenačíta.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model AI pre alternatívne texty ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Beží lokálne na vašom zariadení, takže vaše dáta zostanú súkromné. Vyžaduje sa pre automatický alternatívny text.
+pdfjs-editor-alt-text-settings-delete-model-button = Odstrániť
+pdfjs-editor-alt-text-settings-download-model-button = Stiahnuť
+pdfjs-editor-alt-text-settings-downloading-model-button = Sťahuje sa…
+pdfjs-editor-alt-text-settings-editor-title = Editor alternatívneho textu
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Pri pridávaní obrázka ihneď zobraziť editor alternatívneho textu
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomáha vám zabezpečiť, aby všetky vaše obrázky mali alternatívny text.
+pdfjs-editor-alt-text-settings-close-button = Zavrieť
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Zvýraznenie bolo pridané
+pdfjs-editor-freetext-added-alert = Text bol pridaný
+pdfjs-editor-ink-added-alert = Kresba bola pridaná
+pdfjs-editor-stamp-added-alert = Obrázok bol pridaný
+pdfjs-editor-signature-added-alert = Podpis bol pridaný
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Zvýraznenie bolo odstránené
+pdfjs-editor-undo-bar-message-freetext = Text bol odstránený
+pdfjs-editor-undo-bar-message-ink = Kreslenie bolo odstránené
+pdfjs-editor-undo-bar-message-stamp = Obrázok bol odstránený
+pdfjs-editor-undo-bar-message-signature = Podpis bol odstránený
+pdfjs-editor-undo-bar-message-comment = Komentár odstránený
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anotácia odstránená
+ [few] { $count } anotácie odstránené
+ [many] { $count } anotácií odstránených
+ *[other] { $count } anotácií odstránených
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Späť
+pdfjs-editor-undo-bar-undo-button-label = Späť
+pdfjs-editor-undo-bar-close-button =
+ .title = Zavrieť
+pdfjs-editor-undo-bar-close-button-label = Zavrieť
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Toto okno umožňuje používateľovi vytvoriť podpis, ktorý sa pridá do dokumentu PDF. Používateľ môže upraviť meno (ktoré zároveň slúži ako alternatívny text) a voliteľne uložiť podpis, ak ho plánuje v budúcnosti znova použiť.
+pdfjs-editor-add-signature-dialog-title = Pridať podpis
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Typ
+ .title = Typ
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Kresliť
+ .title = Kresliť
+pdfjs-editor-add-signature-image-button = Obrázok
+ .title = Obrázok
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Zadajte svoj podpis
+ .placeholder = Zadajte svoj podpis
+pdfjs-editor-add-signature-draw-placeholder = Nakreslite svoj podpis
+pdfjs-editor-add-signature-draw-thickness-range-label = Hrúbka
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Hrúbka ceruzky: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Sem presuňte súbor, ktorý chcete nahrať
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Alebo vyberte súbor s obrázkom
+ *[other] Alebo vyberte súbor s obrázkom
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Popis (alternatívny text)
+pdfjs-editor-add-signature-description-input =
+ .title = Popis (alternatívny text)
+pdfjs-editor-add-signature-description-default-when-drawing = Podpis
+pdfjs-editor-add-signature-clear-button-label = Vymazať podpis
+pdfjs-editor-add-signature-clear-button =
+ .title = Vymazať podpis
+pdfjs-editor-add-signature-save-checkbox = Uložiť podpis
+pdfjs-editor-add-signature-save-warning-message = Dosiahli ste limit 5 uložených podpisov. Ak chcete uložiť ďalší, jeden odstráňte.
+pdfjs-editor-add-signature-image-upload-error-title = Obrázok sa nepodarilo nahrať
+pdfjs-editor-add-signature-image-upload-error-description = Skontrolujte sieťové pripojenie alebo skúste iný obrázok.
+pdfjs-editor-add-signature-image-no-data-error-title = Tento obrázok sa nedá previesť na podpis
+pdfjs-editor-add-signature-image-no-data-error-description = Skúste nahrať iný obrázok.
+pdfjs-editor-add-signature-error-close-button = Zavrieť
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Zrušiť
+pdfjs-editor-add-signature-add-button = Pridať
+pdfjs-editor-edit-signature-update-button = Aktualizovať
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Upraviť komentár
+pdfjs-editor-edit-comment-popup-button =
+ .title = Upraviť komentár
+pdfjs-editor-delete-comment-popup-button-label = Odstrániť komentár
+pdfjs-editor-delete-comment-popup-button =
+ .title = Odstrániť komentár
+pdfjs-show-comment-button =
+ .title = Zobraziť komentár
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Upraviť komentár
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Aktualizovať
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Pridať komentár
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Pridať
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Začnite písať…
+pdfjs-editor-edit-comment-dialog-cancel-button = Zrušiť
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Pridať komentár
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Prepnúť bočný panel (dokument obsahuje miniatúry/prehľad/prílohy/vrstvy)
+pdfjs-toggle-views-manager-button1-label = Spravovať strany
+pdfjs-views-manager-sidebar =
+ .aria-label = Bočný panel
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Zmeniť veľkosť bočného panela
+pdfjs-views-manager-view-selector-button =
+ .title = Zobrazenia
+pdfjs-views-manager-view-selector-button-label = Zobrazenia
+pdfjs-views-manager-pages-title = Strany
+pdfjs-views-manager-outlines-title1 = Prehľad dokumentu
+ .title = Prehľad dokumentu (dvojitým kliknutím rozbalíte/zbalíte všetky položky)
+pdfjs-views-manager-attachments-title = Prílohy
+pdfjs-views-manager-layers-title1 = Vrstvy
+ .title = Vrstvy (dvojitým kliknutím obnovíte všetky vrstvy do predvoleného stavu)
+pdfjs-views-manager-pages-option-label = Strany
+pdfjs-views-manager-outlines-option-label = Prehľad dokumentu
+pdfjs-views-manager-attachments-option-label = Prílohy
+pdfjs-views-manager-layers-option-label = Vrstvy
+pdfjs-views-manager-add-file-button =
+ .title = Pridať súbor
+pdfjs-views-manager-add-file-button-label = Pridať súbor
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } označená
+ [few] { $count } označené
+ [many] { $count } označených
+ *[other] { $count } označených
+ }
+pdfjs-views-manager-pages-status-none-action-label = Vybrať strany
+pdfjs-views-manager-pages-status-action-button-label = Spravovať
+pdfjs-views-manager-pages-status-copy-button-label = Kopírovať
+pdfjs-views-manager-pages-status-cut-button-label = Vystrihnúť
+pdfjs-views-manager-pages-status-delete-button-label = Odstrániť
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportovať vybrané…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Vystrihnutá 1 strana
+ [few] Vystrihnuté { $count } strany
+ [many] Vystrihnutých { $count } strán
+ *[other] Vystrihnutých { $count } strán
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Skopírovaná 1 strana
+ [few] Skopírované { $count } strany
+ [many] Skopírovaných { $count } strán
+ *[other] Skopírovaných { $count } strán
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Odstránená 1 strana
+ [few] Odstránené { $count } strany
+ [many] Odstránených { $count } strán
+ *[other] Odstránených { $count } strán
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Váš súbor sa pripravuje…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Nahráva sa súbor…
+pdfjs-views-manager-status-warning-cut-label = Vystrihnutie sa nepodarilo. Obnovte stránku a skúste to znova.
+pdfjs-views-manager-status-warning-copy-label = Skopírovanie sa nepodarilo. Obnovte stránku a skúste to znova.
+pdfjs-views-manager-status-warning-delete-label = Odstránenie sa nepodarilo. Obnovte stránku a skúste to znova.
+pdfjs-views-manager-status-warning-save-label = Uloženie sa nepodarilo. Obnovte stránku a skúste to znova.
+pdfjs-views-manager-status-undo-button-label = Späť
+pdfjs-views-manager-status-done-button-label = Hotovo
+pdfjs-views-manager-status-close-button =
+ .title = Zavrieť
+pdfjs-views-manager-status-close-button-label = Zavrieť
+pdfjs-views-manager-paste-button-label = Prilepiť
+pdfjs-views-manager-paste-button-before =
+ .title = Vložiť pred prvú stranu
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Vložiť za stranu { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVÉ
+pdfjs-views-manager-waiting-for-file = Nahráva sa súbor…
+pdfjs-toggle-views-manager-button1 =
+ .title = Spravovať strany
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Vlastnosti digitálneho podpisu
+ .aria-label = Vlastnosti digitálneho podpisu
+pdfjs-digital-signature-properties-button-label = Vlastnosti digitálneho podpisu
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument bol podpísaný platným digitálnym podpisom
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument bol podpísaný, ale { $count } digitálny podpis sa nepodarilo overiť
+ [few] Dokument bol podpísaný, ale { $count } digitálne podpisy sa nepodarilo overiť
+ [many] Dokument bol podpísaný, ale { $count } digitálnych podpisov sa nepodarilo overiť
+ *[other] Dokument bol podpísaný, ale { $count } digitálnych podpisov sa nepodarilo overiť
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument bol podpísaný { $count } certifikátom, ktorý nie je dôveryhodný
+ [few] Dokument bol podpísaný { $count } certifikátmi, ktoré nie sú dôveryhodné
+ [many] Dokument bol podpísaný { $count } certifikátmi, ktoré nie sú dôveryhodné
+ *[other] Dokument bol podpísaný { $count } certifikátmi, ktoré nie sú dôveryhodné
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument bol podpísaný { $count } certifikátom, ktorému vypršala platnosť
+ [few] Dokument bol podpísaný { $count } certifikátmi, ktorých platnosť vypršala
+ [many] Dokument bol podpísaný { $count } certifikátmi, ktorých platnosť vypršala
+ *[other] Dokument bol podpísaný { $count } certifikátmi, ktorých platnosť vypršala
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument má { $count } neplatný digitálny podpis
+ [few] Dokument má { $count } neplatné digitálne podpisy
+ [many] Dokument má { $count } neplatných digitálnych podpisov
+ *[other] Dokument má { $count } neplatných digitálnych podpisov
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument bol podpísaný { $count } zrušeným certifikátom
+ [few] Dokument bol podpísaný { $count } zrušenými certifikátmi
+ [many] Dokument bol podpísaný { $count } zrušenými certifikátmi
+ *[other] Dokument bol podpísaný { $count } zrušenými certifikátmi
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stav: Podpis overený
+pdfjs-digital-signature-properties-status-invalid = Stav: Podpis neplatný
+pdfjs-digital-signature-properties-status-unknown = Stav: Nedá sa overiť (nepodporovaný)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certifikát: Dôveryhodný ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certifikát: Nie je k dispozícii
+pdfjs-digital-signature-properties-certificate-untrusted = Certifikát: Nedôveryhodný
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certifikát: Neznámy vydavateľ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certifikát: Samopodpísaný ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certifikát: Nedôveryhodný vydavateľ ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certifikát: Platnosť vypršala
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certifikát: Platnosť vypršala ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certifikát: Zrušený
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Odstrániť uložený podpis
+pdfjs-editor-delete-signature-button-label1 = Odstrániť uložený podpis
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Upraviť popis
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Upraviť popis
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/skr/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/skr/viewer.ftl
new file mode 100644
index 0000000..6136dfc
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/skr/viewer.ftl
@@ -0,0 +1,465 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = پچھلا ورقہ
+pdfjs-previous-button-label = پچھلا
+pdfjs-next-button =
+ .title = اڳلا ورقہ
+pdfjs-next-button-label = اڳلا
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = ورقہ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } دا
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } دا { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = زوم آؤٹ
+pdfjs-zoom-out-button-label = زوم آؤٹ
+pdfjs-zoom-in-button =
+ .title = زوم اِن
+pdfjs-zoom-in-button-label = زوم اِن
+pdfjs-zoom-select =
+ .title = زوم
+pdfjs-presentation-mode-button =
+ .title = پریزنٹیشن موڈ تے سوئچ کرو
+pdfjs-presentation-mode-button-label = پریزنٹیشن موڈ
+pdfjs-open-file-button =
+ .title = فائل کھولو
+pdfjs-open-file-button-label = کھولو
+pdfjs-print-button =
+ .title = چھاپو
+pdfjs-print-button-label = چھاپو
+pdfjs-save-button =
+ .title = ہتھیکڑا کرو
+pdfjs-save-button-label = ہتھیکڑا کرو
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ڈاؤن لوڈ
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ڈاؤن لوڈ
+pdfjs-bookmark-button =
+ .title = موجودہ ورقہ (موجودہ ورقے کنوں یوآرایل ݙیکھو)
+pdfjs-bookmark-button-label = موجودہ ورقہ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = اوزار
+pdfjs-tools-button-label = اوزار
+pdfjs-first-page-button =
+ .title = پہلے ورقے تے ونڄو
+pdfjs-first-page-button-label = پہلے ورقے تے ونڄو
+pdfjs-last-page-button =
+ .title = چھیکڑی ورقے تے ونڄو
+pdfjs-last-page-button-label = چھیکڑی ورقے تے ونڄو
+pdfjs-page-rotate-cw-button =
+ .title = گھڑی وانگوں گھماؤ
+pdfjs-page-rotate-cw-button-label = گھڑی وانگوں گھماؤ
+pdfjs-page-rotate-ccw-button =
+ .title = گھڑی تے اُپٹھ گھماؤ
+pdfjs-page-rotate-ccw-button-label = گھڑی تے اُپٹھ گھماؤ
+pdfjs-cursor-text-select-tool-button =
+ .title = متن منتخب کݨ والا آلہ فعال بݨاؤ
+pdfjs-cursor-text-select-tool-button-label = متن منتخب کرݨ والا آلہ
+pdfjs-cursor-hand-tool-button =
+ .title = ہینڈ ٹول فعال بݨاؤ
+pdfjs-cursor-hand-tool-button-label = ہینڈ ٹول
+pdfjs-scroll-page-button =
+ .title = پیج سکرولنگ استعمال کرو
+pdfjs-scroll-page-button-label = پیج سکرولنگ
+pdfjs-scroll-vertical-button =
+ .title = عمودی سکرولنگ استعمال کرو
+pdfjs-scroll-vertical-button-label = عمودی سکرولنگ
+pdfjs-scroll-horizontal-button =
+ .title = افقی سکرولنگ استعمال کرو
+pdfjs-scroll-horizontal-button-label = افقی سکرولنگ
+pdfjs-scroll-wrapped-button =
+ .title = ویڑھی ہوئی سکرولنگ استعمال کرو
+pdfjs-scroll-wrapped-button-label = وہڑھی ہوئی سکرولنگ
+pdfjs-spread-none-button =
+ .title = پیج سپریڈز وِچ شامل نہ تھیوو۔
+pdfjs-spread-none-button-label = کوئی پولھ کائنی
+pdfjs-spread-odd-button =
+ .title = طاق نمبر والے ورقیاں دے نال شروع تھیوݨ والے پیج سپریڈز وِچ شامل تھیوو۔
+pdfjs-spread-odd-button-label = تاک پھیلاؤ
+pdfjs-spread-even-button =
+ .title = جفت نمر والے ورقیاں نال شروع تھیوݨ والے پیج سپریڈز وِ شامل تھیوو۔
+pdfjs-spread-even-button-label = جفت پھیلاؤ
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = دستاویز خواص…
+pdfjs-document-properties-button-label = دستاویز خواص …
+pdfjs-document-properties-file-name = فائل دا ناں:
+pdfjs-document-properties-file-size = فائل دا سائز:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } بائٹاں)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } بائٹاں)
+pdfjs-document-properties-title = عنوان:
+pdfjs-document-properties-author = تخلیق کار:
+pdfjs-document-properties-subject = موضوع:
+pdfjs-document-properties-keywords = کلیدی الفاظ:
+pdfjs-document-properties-creation-date = تخلیق دی تاریخ:
+pdfjs-document-properties-modification-date = ترمیم دی تاریخ:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = تخلیق کار:
+pdfjs-document-properties-producer = PDF پیدا کار:
+pdfjs-document-properties-version = PDF ورژن:
+pdfjs-document-properties-page-count = ورقہ شماری:
+pdfjs-document-properties-page-size = ورقہ دی سائز:
+pdfjs-document-properties-page-size-unit-inches = وِچ
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = عمودی انداز
+pdfjs-document-properties-page-size-orientation-landscape = افقى انداز
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = لیٹر
+pdfjs-document-properties-page-size-name-legal = قنونی
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = تکھا ویب نظارہ:
+pdfjs-document-properties-linearized-yes = جیا
+pdfjs-document-properties-linearized-no = کو
+pdfjs-document-properties-close-button = بند کرو
+
+## Print
+
+pdfjs-print-progress-message = چھاپݨ کیتے دستاویز تیار تھیندے پئے ہن …
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = منسوخ کرو
+pdfjs-printing-not-supported = چتاوݨی: چھپائی ایں براؤزر تے پوری طراں معاونت شدہ کائنی۔
+pdfjs-printing-not-ready = چتاوݨی: PDF چھپائی کیتے پوری طراں لوڈ نئیں تھئی۔
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = سائیڈ بار ٹوگل کرو
+pdfjs-toggle-sidebar-notification-button =
+ .title = سائیڈ بار ٹوگل کرو (دستاویز وِچ آؤٹ لائن/ منسلکات/ پرتاں شامل ہن)
+pdfjs-toggle-sidebar-button-label = سائیڈ بار ٹوگل کرو
+pdfjs-document-outline-button =
+ .title = دستاویز دا خاکہ ݙکھاؤ (تمام آئٹمز کوں پھیلاوݨ/سنگوڑݨ کیتے ڈبل کلک کرو)
+pdfjs-document-outline-button-label = دستاویز آؤٹ لائن
+pdfjs-attachments-button =
+ .title = نتھیاں ݙکھاؤ
+pdfjs-attachments-button-label = منسلکات
+pdfjs-layers-button =
+ .title = پرتاں ݙکھاؤ (تمام پرتاں کوں ڈیفالٹ حالت وِچ دوبارہ ترتیب ݙیوݨ کیتے ڈبل کلک کرو)
+pdfjs-layers-button-label = پرتاں
+pdfjs-thumbs-button =
+ .title = تھمبنیل ݙکھاؤ
+pdfjs-thumbs-button-label = تھمبنیلز
+pdfjs-current-outline-item-button =
+ .title = موجودہ آؤٹ لائن آئٹم لبھو
+pdfjs-current-outline-item-button-label = موجودہ آؤٹ لائن آئٹم
+pdfjs-findbar-button =
+ .title = دستاویز وِچ لبھو
+pdfjs-findbar-button-label = لبھو
+pdfjs-additional-layers = اضافی پرتاں
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = ورقہ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = ورقے دا تھمبنیل { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = لبھو
+ .placeholder = دستاویز وِچ لبھو …
+pdfjs-find-previous-button =
+ .title = فقرے دا پچھلا واقعہ لبھو
+pdfjs-find-previous-button-label = پچھلا
+pdfjs-find-next-button =
+ .title = فقرے دا اڳلا واقعہ لبھو
+pdfjs-find-next-button-label = اڳلا
+pdfjs-find-highlight-checkbox = تمام نشابر کرو
+pdfjs-find-match-case-checkbox-label = حروف مشابہ کرو
+pdfjs-find-match-diacritics-checkbox-label = ڈائیکرٹکس مشابہ کرو
+pdfjs-find-entire-word-checkbox-label = تمام الفاظ
+pdfjs-find-reached-top = ورقے دے شروع تے پُج ڳیا، تلوں جاری کیتا ڳیا
+pdfjs-find-reached-bottom = ورقے دے پاند تے پُڄ ڳیا، اُتوں شروع کیتا ڳیا
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $total } وِچوں { $current } مشابہ
+ *[other] { $total } وِچوں { $current } مشابے
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] { $limit } توں ودھ مماثلت۔
+ *[other] { $limit } توں ودھ مماثلتاں۔
+ }
+pdfjs-find-not-found = فقرہ نئیں ملیا
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ورقے دی چوڑائی
+pdfjs-page-scale-fit = ورقہ فٹنگ
+pdfjs-page-scale-auto = آپوں آپ زوم
+pdfjs-page-scale-actual = اصل میچا
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = ورقہ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF لوڈ کریندے ویلھے نقص آ ڳیا۔
+pdfjs-invalid-file-error = غلط یا خراب شدہ PDF فائل۔
+pdfjs-missing-file-error = PDF فائل غائب ہے۔
+pdfjs-unexpected-response-error = سرور دا غیر متوقع جواب۔
+pdfjs-rendering-error = ورقہ رینڈر کریندے ویلھے ہک خرابی پیش آڳئی۔
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } تشریح]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = ایہ PDF فائل کھولݨ کیتے پاس ورڈ درج کرو۔
+pdfjs-password-invalid = غلط پاس ورڈ: براہ مہربانی ولدا کوشش کرو۔
+pdfjs-password-ok-button = ٹھیک ہے
+pdfjs-password-cancel-button = منسوخ کرو
+pdfjs-web-fonts-disabled = ویب فونٹس غیر فعال ہن: ایمبیڈڈ PDF فونٹس استعمال کرݨ کنوں قاصر ہن
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = متن
+pdfjs-editor-free-text-button-label = متن
+pdfjs-editor-ink-button =
+ .title = چھکو
+pdfjs-editor-ink-button-label = چھکو
+pdfjs-editor-stamp-button =
+ .title = تصویراں کوں شامل کرو یا ترمیم کرو
+pdfjs-editor-stamp-button-label = تصویراں کوں شامل کرو یا ترمیم کرو
+pdfjs-editor-highlight-button =
+ .title = نمایاں کرو
+pdfjs-editor-highlight-button-label = نمایاں کرو
+pdfjs-highlight-floating-button1 =
+ .title = نمایاں کرو
+ .aria-label = نمایاں کرو
+pdfjs-highlight-floating-button-label = نمایاں کرو
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = ڈرائینگ ہٹاؤ
+pdfjs-editor-remove-freetext-button =
+ .title = متن ہٹاؤ
+pdfjs-editor-remove-stamp-button =
+ .title = تصویر ہٹاؤ
+pdfjs-editor-remove-highlight-button =
+ .title = نمایاں ہٹاؤ
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = رنگ
+pdfjs-editor-free-text-size-input = سائز
+pdfjs-editor-ink-color-input = رنگ
+pdfjs-editor-ink-thickness-input = ٹھولھ
+pdfjs-editor-ink-opacity-input = دھندلاپن
+pdfjs-editor-stamp-add-image-button =
+ .title = تصویر شامل کرو
+pdfjs-editor-stamp-add-image-button-label = تصویر شامل کرو
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = مُٹاݨ
+pdfjs-editor-free-highlight-thickness-title =
+ .title = متن توں ان٘ج ٻئے شئیں کوں نمایاں کرݨ ویلے مُٹاݨ کوں بدلو
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alt متن
+pdfjs-editor-alt-text-dialog-label = ہِک اختیار چُݨو
+pdfjs-editor-alt-text-dialog-description = Alt متن (متبادل متن) اِیں ویلے مَدَت کرین٘دا ہِے جہڑیلے لوک تصویر کوں نِھیں ݙیکھ سڳدے یا جہڑیلے اِیہ لوڈ کائنی تِھین٘دا۔
+pdfjs-editor-alt-text-add-description-label = تفصیل شامل کرو
+pdfjs-editor-alt-text-add-description-description = 1-2 جملیاں دا مقصد جہڑے موضوع، ترتیب، یا اعمال کوں بیان کرین٘دے ہِن۔
+pdfjs-editor-alt-text-mark-decorative-label = آرائشی طور تے نشان زد کرو
+pdfjs-editor-alt-text-mark-decorative-description = اِیہ آرائشی تصویراں کِیتے استعمال تِھین٘دا ہِے، جیویں بارڈر یا واٹر مارکس۔
+pdfjs-editor-alt-text-cancel-button = منسوخ
+pdfjs-editor-alt-text-save-button = محفوظ
+pdfjs-editor-alt-text-decorative-tooltip = آرائشی دے طور تے نشان زد تِھی ڳِیا
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = مثال دے طور تے، "ہِک جؤان کھاݨاں کھاوݨ کِیتے میز اُتّے ٻیٹھا ہِے"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alt متن
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = اُتلی کَھٻّی نُکّڑ — سائز بدلو
+pdfjs-editor-resizer-top-middle =
+ .aria-label = اُتلا وِچلا — سائز بدلو
+pdfjs-editor-resizer-top-right =
+ .aria-label = اُتلی سَڄّی نُکَّڑ — سائز بدلو
+pdfjs-editor-resizer-middle-right =
+ .aria-label = وِچلا سڄّا — سائز بدلو
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = تلوِیں سَڄّی نُکَّڑ — سائز بدلو
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = تلواں وِچلا — سائز بدلو
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = تلوِیں کَھٻّی نُکّڑ — سائز بدلو
+pdfjs-editor-resizer-middle-left =
+ .aria-label = وِچلا کَھٻّا — سائز بدلو
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = نشابر رنگ
+pdfjs-editor-colorpicker-button =
+ .title = رنگ بدلو
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = رنگ اختیارات
+pdfjs-editor-colorpicker-yellow =
+ .title = پیلا
+pdfjs-editor-colorpicker-green =
+ .title = ساوا
+pdfjs-editor-colorpicker-blue =
+ .title = نیلا
+pdfjs-editor-colorpicker-pink =
+ .title = گلابی
+pdfjs-editor-colorpicker-red =
+ .title = لال
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = سارے ݙکھاؤ
+pdfjs-editor-highlight-show-all-button =
+ .title = سارے ݙکھاؤ
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = آلٹ عبارت وچ تبدیلی کرو (تصویر تفصیل)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = آلٹ عبارت شامل کرو (تصویر تفصیل)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = اتھ آپݨی وضاحت لکھو۔۔۔
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = اُنہاں لوکاں کیتے مختصر تفصیل جہڑے تصویر کائنی ݙیکھ سڳدے یا ڄݙݨ تصویر لوڈ کائبی تھیندی۔
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = آلٹ عبارت خودکار تخلیق تھئی ہے تے غلط تھی سڳدی ہے۔
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = ٻیا سِکھو
+pdfjs-editor-new-alt-text-create-automatically-button-label = آلٹ عبارت خودکار بݨاؤ
+pdfjs-editor-new-alt-text-not-now-button = ہݨ کائناں
+pdfjs-editor-new-alt-text-error-title = آلٹ عبارت خودکار نہ بݨاؤ
+pdfjs-editor-new-alt-text-error-description = سوہݨا، آپݨی آلٹ عبارت لکھو یا ولدا بعد وچ کوشش کرو۔
+pdfjs-editor-new-alt-text-error-close-button = بند کرو
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = آلٹ عبارت اے آئی ماڈل({ $totalSize }ایم بی دے { $downloadedSize }) ڈاؤن لوڈ تھیندا پئے
+ .aria-valuetext = آلٹ عبارت اے آئی ماڈل({ $totalSize }ایم بی دے { $downloadedSize }) ڈاؤن لوڈ تھیندا پئے
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = آلٹ عبارت شامل تھی ڳئی
+pdfjs-editor-new-alt-text-added-button-label = آلٹ عبارت شامل تھی ڳئی
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = متبادل عبارت غائب ہے
+pdfjs-editor-new-alt-text-missing-button-label = متبادل عبارت غائب ہے
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = alt متن تے نظرثانی کرو
+pdfjs-editor-new-alt-text-to-review-button-label = alt متن تے نظرثانی کرو
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = خودکار تخلیق تھئی: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = تصویر آلٹ عبارت ترتیباں
+pdfjs-image-alt-text-settings-button-label = تصویر آلٹ عبارت ترتیباں
+pdfjs-editor-alt-text-settings-dialog-label = تصویر آلٹ عبارت ترتیباں
+pdfjs-editor-alt-text-settings-automatic-title = خودکار آلٹ عبارت
+pdfjs-editor-alt-text-settings-create-model-button-label = آلٹ عبارت خودکار بݨاؤ
+pdfjs-editor-alt-text-settings-create-model-description = اُنہاں لوکاں دی مدد کیتے تفصیل تجویز کرو جہڑے تصویر کائنی ݙیکھ سڳدے یا ڄݙݨ تصویر لوڈ کائبی تھیندی۔
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = آلٹ عبارت اے آئی ماڈل ({ $totalSize } ایم بی)
+pdfjs-editor-alt-text-settings-ai-model-description = تہاݙی ڈیوائس تے مقامی طور تے چلدا ہے تاں جو تہاݙا ڈیٹا نجی رہوے۔ خودکار آلٹ عبارت کیتے ضروری ہے۔
+pdfjs-editor-alt-text-settings-delete-model-button = مٹاؤ
+pdfjs-editor-alt-text-settings-download-model-button = ڈاؤن لوڈ
+pdfjs-editor-alt-text-settings-downloading-model-button = ڈاؤن لوڈ تھیندا پئے …
+pdfjs-editor-alt-text-settings-editor-title = متبادل ٹیکسٹ ایڈیٹر
+pdfjs-editor-alt-text-settings-show-dialog-button-label = تصویر شامل کرݨ ویلے فوری طور تے آلٹ ٹیکسٹ ایڈیٹر ݙکھاؤ
+pdfjs-editor-alt-text-settings-show-dialog-description = ایہ تہاکوں یقینی بݨاوݨ وچ مدد کریندے جو تہاݙیاں ساریاں تصویراں وچ آلٹ عبارت ہے۔
+pdfjs-editor-alt-text-settings-close-button = بند کرو
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-undo-button =
+ .title = کیتا اݨ کیتا
+pdfjs-editor-undo-bar-undo-button-label = کیتا اݨ کیتا
+pdfjs-editor-undo-bar-close-button =
+ .title = بند کرو
+pdfjs-editor-undo-bar-close-button-label = بند کرو
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sl/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sl/viewer.ftl
new file mode 100644
index 0000000..82e1e6a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sl/viewer.ftl
@@ -0,0 +1,864 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Prejšnja stran
+pdfjs-previous-button-label = Nazaj
+pdfjs-next-button =
+ .title = Naslednja stran
+pdfjs-next-button-label = Naprej
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Stran
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = od { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } od { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Pomanjšaj
+pdfjs-zoom-out-button-label = Pomanjšaj
+pdfjs-zoom-in-button =
+ .title = Povečaj
+pdfjs-zoom-in-button-label = Povečaj
+pdfjs-zoom-select =
+ .title = Povečava
+pdfjs-presentation-mode-button =
+ .title = Preklopi v način predstavitve
+pdfjs-presentation-mode-button-label = Način predstavitve
+pdfjs-open-file-button =
+ .title = Odpri datoteko
+pdfjs-open-file-button-label = Odpri
+pdfjs-print-button =
+ .title = Natisni
+pdfjs-print-button-label = Natisni
+pdfjs-save-button =
+ .title = Shrani
+pdfjs-save-button-label = Shrani
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Prenesi
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Prenesi
+pdfjs-bookmark-button =
+ .title = Trenutna stran (prikaži URL, ki vodi do trenutne strani)
+pdfjs-bookmark-button-label = Na trenutno stran
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Orodja
+pdfjs-tools-button-label = Orodja
+pdfjs-first-page-button =
+ .title = Pojdi na prvo stran
+pdfjs-first-page-button-label = Pojdi na prvo stran
+pdfjs-last-page-button =
+ .title = Pojdi na zadnjo stran
+pdfjs-last-page-button-label = Pojdi na zadnjo stran
+pdfjs-page-rotate-cw-button =
+ .title = Zavrti v smeri urnega kazalca
+pdfjs-page-rotate-cw-button-label = Zavrti v smeri urnega kazalca
+pdfjs-page-rotate-ccw-button =
+ .title = Zavrti v nasprotni smeri urnega kazalca
+pdfjs-page-rotate-ccw-button-label = Zavrti v nasprotni smeri urnega kazalca
+pdfjs-cursor-text-select-tool-button =
+ .title = Omogoči orodje za izbor besedila
+pdfjs-cursor-text-select-tool-button-label = Orodje za izbor besedila
+pdfjs-cursor-hand-tool-button =
+ .title = Omogoči roko
+pdfjs-cursor-hand-tool-button-label = Roka
+pdfjs-scroll-page-button =
+ .title = Uporabi drsenje po strani
+pdfjs-scroll-page-button-label = Drsenje po strani
+pdfjs-scroll-vertical-button =
+ .title = Uporabi navpično drsenje
+pdfjs-scroll-vertical-button-label = Navpično drsenje
+pdfjs-scroll-horizontal-button =
+ .title = Uporabi vodoravno drsenje
+pdfjs-scroll-horizontal-button-label = Vodoravno drsenje
+pdfjs-scroll-wrapped-button =
+ .title = Uporabi ovito drsenje
+pdfjs-scroll-wrapped-button-label = Ovito drsenje
+pdfjs-spread-none-button =
+ .title = Ne združuj razponov strani
+pdfjs-spread-none-button-label = Brez razponov
+pdfjs-spread-odd-button =
+ .title = Združuj razpone strani z začetkom pri lihih straneh
+pdfjs-spread-odd-button-label = Lihi razponi
+pdfjs-spread-even-button =
+ .title = Združuj razpone strani z začetkom pri sodih straneh
+pdfjs-spread-even-button-label = Sodi razponi
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Lastnosti dokumenta …
+pdfjs-document-properties-button-label = Lastnosti dokumenta …
+pdfjs-document-properties-file-name = Ime datoteke:
+pdfjs-document-properties-file-size = Velikost datoteke:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bajtov)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajtov)
+pdfjs-document-properties-title = Ime:
+pdfjs-document-properties-author = Avtor:
+pdfjs-document-properties-subject = Tema:
+pdfjs-document-properties-keywords = Ključne besede:
+pdfjs-document-properties-creation-date = Datum nastanka:
+pdfjs-document-properties-modification-date = Datum spremembe:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Ustvaril:
+pdfjs-document-properties-producer = Izdelovalec PDF:
+pdfjs-document-properties-version = Različica PDF:
+pdfjs-document-properties-page-count = Število strani:
+pdfjs-document-properties-page-size = Velikost strani:
+pdfjs-document-properties-page-size-unit-inches = palcev
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = pokončno
+pdfjs-document-properties-page-size-orientation-landscape = ležeče
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Hitri spletni ogled:
+pdfjs-document-properties-linearized-yes = Da
+pdfjs-document-properties-linearized-no = Ne
+pdfjs-document-properties-close-button = Zapri
+pdfjs-digital-signature-properties-view-certificate = Ogled digitalnega potrdila
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Razlog: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Časovni žig: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Podpodpis ({ $count })
+ [two] Podpodpisi ({ $count })
+ [few] Podpodpisi ({ $count })
+ *[other] Podpodpisi ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Priprava dokumenta na tiskanje …
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress } %
+pdfjs-print-progress-close-button = Prekliči
+pdfjs-printing-not-supported = Opozorilo: ta brskalnik ne podpira vseh možnosti tiskanja.
+pdfjs-printing-not-ready = Opozorilo: PDF ni v celoti naložen za tiskanje.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Preklopi stransko vrstico
+pdfjs-toggle-sidebar-notification-button =
+ .title = Preklopi stransko vrstico (dokument vsebuje oris/priponke/plasti)
+pdfjs-toggle-sidebar-button-label = Preklopi stransko vrstico
+pdfjs-document-outline-button =
+ .title = Prikaži oris dokumenta (dvokliknite za razširitev/strnitev vseh predmetov)
+pdfjs-document-outline-button-label = Oris dokumenta
+pdfjs-attachments-button =
+ .title = Prikaži priponke
+pdfjs-attachments-button-label = Priponke
+pdfjs-layers-button =
+ .title = Prikaži plasti (dvokliknite za ponastavitev vseh plasti na privzeto stanje)
+pdfjs-layers-button-label = Plasti
+pdfjs-thumbs-button =
+ .title = Prikaži sličice
+pdfjs-thumbs-button-label = Sličice
+pdfjs-current-outline-item-button =
+ .title = Najdi trenutni predmet orisa
+pdfjs-current-outline-item-button-label = Trenutni predmet orisa
+pdfjs-findbar-button =
+ .title = Iskanje po dokumentu
+pdfjs-findbar-button-label = Najdi
+pdfjs-additional-layers = Dodatne plasti
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Stran { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Sličica strani { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Izberi stran { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Stran { $page } od { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Najdi
+ .placeholder = Najdi v dokumentu …
+pdfjs-find-previous-button =
+ .title = Najdi prejšnjo ponovitev iskanega
+pdfjs-find-previous-button-label = Najdi nazaj
+pdfjs-find-next-button =
+ .title = Najdi naslednjo ponovitev iskanega
+pdfjs-find-next-button-label = Najdi naprej
+pdfjs-find-highlight-checkbox = Označi vse
+pdfjs-find-match-case-checkbox-label = Razlikuj velike/male črke
+pdfjs-find-match-diacritics-checkbox-label = Razlikuj diakritične znake
+pdfjs-find-entire-word-checkbox-label = Cele besede
+pdfjs-find-reached-top = Dosežen začetek dokumenta iz smeri konca
+pdfjs-find-reached-bottom = Dosežen konec dokumenta, nadaljevanje od začetka
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] Zadetek { $current } od { $total }
+ [two] Zadetek { $current } od { $total }
+ [few] Zadetek { $current } od { $total }
+ *[other] Zadetek { $current } od { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Več kot { $limit } zadetek
+ [two] Več kot { $limit } zadetka
+ [few] Več kot { $limit } zadetki
+ *[other] Več kot { $limit } zadetkov
+ }
+pdfjs-find-not-found = Iskanega ni mogoče najti
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Širina strani
+pdfjs-page-scale-fit = Prilagodi stran
+pdfjs-page-scale-auto = Samodejno
+pdfjs-page-scale-actual = Dejanska velikost
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale } %
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Stran { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Med nalaganjem datoteke PDF je prišlo do napake.
+pdfjs-invalid-file-error = Neveljavna ali pokvarjena datoteka PDF.
+pdfjs-missing-file-error = Ni datoteke PDF.
+pdfjs-unexpected-response-error = Nepričakovan odgovor strežnika.
+pdfjs-rendering-error = Med pripravljanjem strani je prišlo do napake!
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Opomba vrste { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Vnesite geslo za odpiranje te datoteke PDF.
+pdfjs-password-invalid = Neveljavno geslo. Poskusite znova.
+pdfjs-password-ok-button = V redu
+pdfjs-password-cancel-button = Prekliči
+pdfjs-web-fonts-disabled = Spletne pisave so onemogočene: vgradnih pisav za PDF ni mogoče uporabiti.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Besedilo
+pdfjs-editor-color-picker-free-text-input =
+ .title = Spremeni barvo besedila
+pdfjs-editor-free-text-button-label = Besedilo
+pdfjs-editor-ink-button =
+ .title = Riši
+pdfjs-editor-color-picker-ink-input =
+ .title = Spremeni barvo risbe
+pdfjs-editor-ink-button-label = Riši
+pdfjs-editor-stamp-button =
+ .title = Dodajanje ali urejanje slik
+pdfjs-editor-stamp-button-label = Dodajanje ali urejanje slik
+pdfjs-editor-highlight-button =
+ .title = Označevalnik
+pdfjs-editor-highlight-button-label = Označevalnik
+pdfjs-highlight-floating-button1 =
+ .title = Označi
+ .aria-label = Označi
+pdfjs-highlight-floating-button-label = Označi
+pdfjs-comment-floating-button =
+ .title = Komentiraj
+ .aria-label = Komentiraj
+pdfjs-comment-floating-button-label = Komentiraj
+pdfjs-editor-comment-button =
+ .title = Komentiraj
+ .aria-label = Komentiraj
+pdfjs-editor-comment-button-label = Komentiraj
+pdfjs-editor-signature-button =
+ .title = Dodaj podpis
+pdfjs-editor-signature-button-label = Dodaj podpis
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Urejevalnik označb
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Urejevalnik risb
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Urejevalnik podpisov: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Urejevalnik slik
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Odstrani risbo
+pdfjs-editor-remove-freetext-button =
+ .title = Odstrani besedilo
+pdfjs-editor-remove-stamp-button =
+ .title = Odstrani sliko
+pdfjs-editor-remove-highlight-button =
+ .title = Odstrani označbo
+pdfjs-editor-remove-signature-button =
+ .title = Odstrani podpis
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Barva
+pdfjs-editor-free-text-size-input = Velikost
+pdfjs-editor-ink-color-input = Barva
+pdfjs-editor-ink-thickness-input = Debelina
+pdfjs-editor-ink-opacity-input = Neprosojnost
+pdfjs-editor-stamp-add-image-button =
+ .title = Dodaj sliko
+pdfjs-editor-stamp-add-image-button-label = Dodaj sliko
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Debelina
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Spremeni debelino pri označevanju nebesedilnih elementov
+pdfjs-editor-add-signature-container =
+ .aria-label = Kontrolniki za podpise in shranjeni podpisi
+pdfjs-editor-signature-add-signature-button =
+ .title = Dodaj nov podpis
+pdfjs-editor-signature-add-signature-button-label = Dodaj nov podpis
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Shranjen podpis: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Urejevalnik besedila
+ .default-content = Začnite tipkati …
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Komentar
+ [two] Komentarja
+ [few] Komentarji
+ *[other] Komentarji
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Zapri stransko vrstico
+ .aria-label = Zapri stransko vrstico
+pdfjs-editor-comments-sidebar-close-button-label = Zapri stransko vrstico
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Ste zasledili kaj omembe vrednega? Narišite oznako in dopišite komentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Več o tem
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Nadomestno besedilo
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Uredi nadomestno besedilo
+pdfjs-editor-alt-text-dialog-label = Izberite možnost
+pdfjs-editor-alt-text-dialog-description = Nadomestno besedilo se prikaže tistim, ki ne vidijo slike, ali če se ta ne naloži.
+pdfjs-editor-alt-text-add-description-label = Dodaj opis
+pdfjs-editor-alt-text-add-description-description = Poskušajte v enem ali dveh stavkih opisati motiv, okolje ali dejanja.
+pdfjs-editor-alt-text-mark-decorative-label = Označi kot okrasno
+pdfjs-editor-alt-text-mark-decorative-description = Uporablja se za slike, ki služijo samo okrasu, na primer obrobe ali vodne žige.
+pdfjs-editor-alt-text-cancel-button = Prekliči
+pdfjs-editor-alt-text-save-button = Shrani
+pdfjs-editor-alt-text-decorative-tooltip = Označeno kot okrasno
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Na primer: "Mladenič sedi za mizo pri jedi"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Nadomestno besedilo
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Zgornji levi kot – spremeni velikost
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Zgoraj na sredini – spremeni velikost
+pdfjs-editor-resizer-top-right =
+ .aria-label = Zgornji desni kot – spremeni velikost
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Desno na sredini – spremeni velikost
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Spodnji desni kot – spremeni velikost
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Spodaj na sredini – spremeni velikost
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Spodnji levi kot – spremeni velikost
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Levo na sredini – spremeni velikost
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Barva označbe
+pdfjs-editor-colorpicker-button =
+ .title = Spremeni barvo
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Izbira barve
+pdfjs-editor-colorpicker-yellow =
+ .title = Rumena
+pdfjs-editor-colorpicker-green =
+ .title = Zelena
+pdfjs-editor-colorpicker-blue =
+ .title = Modra
+pdfjs-editor-colorpicker-pink =
+ .title = Roza
+pdfjs-editor-colorpicker-red =
+ .title = Rdeča
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Prikaži vse
+pdfjs-editor-highlight-show-all-button =
+ .title = Prikaži vse
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Uredi nadomestno besedilo (opis slike)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Dodaj nadomestno besedilo (opis slike)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Tukaj napišite svoj opis …
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kratek opis za ljudi, ki ne morejo videti slike, ali za primer, ko se slika ne naloži.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = To nadomestno besedilo je bilo ustvarjeno samodejno in je lahko netočno.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Več o tem
+pdfjs-editor-new-alt-text-create-automatically-button-label = Samodejno ustvari nadomestno besedilo
+pdfjs-editor-new-alt-text-not-now-button = Ne zdaj
+pdfjs-editor-new-alt-text-error-title = Nadomestnega besedila ni bilo mogoče samodejno ustvariti
+pdfjs-editor-new-alt-text-error-description = Sestavite svoje nadomestno besedilo ali poskusite znova pozneje.
+pdfjs-editor-new-alt-text-error-close-button = Zapri
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Prenašanje modela UI za nadomestno besedilo ({ $downloadedSize } od { $totalSize } MB)
+ .aria-valuetext = Prenašanje modela UI za nadomestno besedilo ({ $downloadedSize } od { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Nadomestno besedilo dodano
+pdfjs-editor-new-alt-text-added-button-label = Nadomestno besedilo dodano
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Nadomestno besedilo manjka
+pdfjs-editor-new-alt-text-missing-button-label = Nadomestno besedilo manjka
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Oceni nadomestno besedilo
+pdfjs-editor-new-alt-text-to-review-button-label = Oceni nadomestno besedilo
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Samodejno ustvarjeno: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Nastavitve nadomestnega besedila slike
+pdfjs-image-alt-text-settings-button-label = Nastavitve nadomestnega besedila slike
+pdfjs-editor-alt-text-settings-dialog-label = Nastavitve nadomestnega besedila slike
+pdfjs-editor-alt-text-settings-automatic-title = Samodejno nadomestno besedilo
+pdfjs-editor-alt-text-settings-create-model-button-label = Samodejno ustvari nadomestno besedilo
+pdfjs-editor-alt-text-settings-create-model-description = Predlaga opise za pomoč ljudem, ki ne morejo videti slike, ali za primer, ko se slika ne naloži.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model UI za nadomestno besedilo ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Izvaja se lokalno na vaši napravi, tako da vaši podatki ostajajo zasebni. Zahtevano za samodejno nadomestno besedilo.
+pdfjs-editor-alt-text-settings-delete-model-button = Izbriši
+pdfjs-editor-alt-text-settings-download-model-button = Prenesi
+pdfjs-editor-alt-text-settings-downloading-model-button = Prenašanje ...
+pdfjs-editor-alt-text-settings-editor-title = Urejevalnik nadomestnega besedila
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Ob dodajanju slike takoj prikaži urejevalnik nadomestnega besedila
+pdfjs-editor-alt-text-settings-show-dialog-description = Pomaga vam zagotoviti, da imajo vse vaše slike nadomestno besedilo.
+pdfjs-editor-alt-text-settings-close-button = Zapri
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Označba dodana
+pdfjs-editor-freetext-added-alert = Besedilo dodano
+pdfjs-editor-ink-added-alert = Risba dodana
+pdfjs-editor-stamp-added-alert = Slika dodana
+pdfjs-editor-signature-added-alert = Podpis dodan
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Označba odstranjena
+pdfjs-editor-undo-bar-message-freetext = Besedilo odstranjeno
+pdfjs-editor-undo-bar-message-ink = Risba odstranjena
+pdfjs-editor-undo-bar-message-stamp = Slika odstranjena
+pdfjs-editor-undo-bar-message-signature = Podpis odstranjen
+pdfjs-editor-undo-bar-message-comment = Komentar odstranjen
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } označba odstranjena
+ [two] { $count } označbi odstranjeni
+ [few] { $count } označbe odstranjene
+ *[other] { $count } označb odstranjenih
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Razveljavi
+pdfjs-editor-undo-bar-undo-button-label = Razveljavi
+pdfjs-editor-undo-bar-close-button =
+ .title = Zapri
+pdfjs-editor-undo-bar-close-button-label = Zapri
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Ta način omogoča uporabniku ustvariti podpis, ki ga želi dodati dokumentu PDF. Uporabnik lahko uredi ime (ki se uporablja tudi kot nadomestno besedilo) in podpis po želji shrani za ponovno uporabo.
+pdfjs-editor-add-signature-dialog-title = Dodaj podpis
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Natipkaj
+ .title = Natipkaj
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Nariši
+ .title = Nariši
+pdfjs-editor-add-signature-image-button = Slika
+ .title = Slika
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Natipkajte svoj podpis
+ .placeholder = Natipkajte svoj podpis
+pdfjs-editor-add-signature-draw-placeholder = Narišite svoj podpis
+pdfjs-editor-add-signature-draw-thickness-range-label = Debelina
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Debelina peresa: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Povlecite datoteko sem za nalaganje
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ali prebrskajte slikovne datoteke
+ *[other] Ali prebrskajte slikovne datoteke
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Opis (nadomestno besedilo)
+pdfjs-editor-add-signature-description-input =
+ .title = Opis (nadomestno besedilo)
+pdfjs-editor-add-signature-description-default-when-drawing = Podpis
+pdfjs-editor-add-signature-clear-button-label = Pobriši podpis
+pdfjs-editor-add-signature-clear-button =
+ .title = Pobriši podpis
+pdfjs-editor-add-signature-save-checkbox = Shrani podpis
+pdfjs-editor-add-signature-save-warning-message = Dosegli ste omejitev 5 shranjenih podpisov. Če želite shraniti novega, enega odstranite.
+pdfjs-editor-add-signature-image-upload-error-title = Slike ni bilo mogoče naložiti
+pdfjs-editor-add-signature-image-upload-error-description = Preverite svojo povezavo z omrežjem ali poskusite z drugo sliko.
+pdfjs-editor-add-signature-image-no-data-error-title = Te slike ni mogoče pretvoriti v podpis
+pdfjs-editor-add-signature-image-no-data-error-description = Poskusite naložiti drugo sliko.
+pdfjs-editor-add-signature-error-close-button = Zapri
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Prekliči
+pdfjs-editor-add-signature-add-button = Dodaj
+pdfjs-editor-edit-signature-update-button = Spremeni
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Uredi komentar
+pdfjs-editor-edit-comment-popup-button =
+ .title = Uredi komentar
+pdfjs-editor-delete-comment-popup-button-label = Odstrani komentar
+pdfjs-editor-delete-comment-popup-button =
+ .title = Odstrani komentar
+pdfjs-show-comment-button =
+ .title = Pokaži komentar
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Uredi komentar
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Spremeni
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Dodaj komentar
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Dodaj
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Začnite tipkati …
+pdfjs-editor-edit-comment-dialog-cancel-button = Prekliči
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Dodaj komentar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Preklopi stransko vrstico (dokument vsebuje sličice/oris/priponke/plasti)
+pdfjs-toggle-views-manager-button1-label = Upravljanje strani
+pdfjs-views-manager-sidebar =
+ .aria-label = Stranska vrstica
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Sprememba velikosti stranske vrstice
+pdfjs-views-manager-view-selector-button =
+ .title = Pogledi
+pdfjs-views-manager-view-selector-button-label = Pogledi
+pdfjs-views-manager-pages-title = Strani
+pdfjs-views-manager-outlines-title1 = Oris dokumenta
+ .title = Oris dokumenta (dvokliknite za razširitev ali strnitev vseh elementov)
+pdfjs-views-manager-attachments-title = Priponke
+pdfjs-views-manager-layers-title1 = Plasti
+ .title = Plasti (dvokliknite za ponastavitev vseh plasti na privzeto stanje)
+pdfjs-views-manager-pages-option-label = Strani
+pdfjs-views-manager-outlines-option-label = Oris dokumenta
+pdfjs-views-manager-attachments-option-label = Priponke
+pdfjs-views-manager-layers-option-label = Plasti
+pdfjs-views-manager-add-file-button =
+ .title = Dodaj datoteko
+pdfjs-views-manager-add-file-button-label = Dodaj datoteko
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } izbrana
+ [two] { $count } izbrani
+ [few] { $count } izbrane
+ *[other] { $count } izbranih
+ }
+pdfjs-views-manager-pages-status-none-action-label = Izberite strani
+pdfjs-views-manager-pages-status-action-button-label = Upravljaj
+pdfjs-views-manager-pages-status-copy-button-label = Kopiraj
+pdfjs-views-manager-pages-status-cut-button-label = Izreži
+pdfjs-views-manager-pages-status-delete-button-label = Izbriši
+pdfjs-views-manager-pages-status-export-selected-button-label = Izvozi izbor …
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] { $count } stran izrezana
+ [two] { $count } strani izrezani
+ [few] { $count } strani izrezane
+ *[other] { $count } strani izrezanih
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] { $count } stran kopirana
+ [two] { $count } strani kopirani
+ [few] { $count } strani kopirane
+ *[other] { $count } strani kopiranih
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] { $count } stran izbrisana
+ [two] { $count } strani izbrisani
+ [few] { $count } strani izbrisane
+ *[other] { $count } strani izbrisanih
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Pripravljanje datoteke za vas …
+pdfjs-views-manager-pages-status-waiting-uploading-label = Nalaganje datoteke …
+pdfjs-views-manager-status-warning-cut-label = Izrezovanje ni bilo mogoče. Osvežite stran in poskusite znova.
+pdfjs-views-manager-status-warning-copy-label = Kopiranje ni bilo mogoče. Osvežite stran in poskusite znova.
+pdfjs-views-manager-status-warning-delete-label = Brisanje ni bilo mogoče. Osvežite stran in poskusite znova.
+pdfjs-views-manager-status-warning-save-label = Shranjevanje ni bilo mogoče. Osvežite stran in poskusite znova.
+pdfjs-views-manager-status-undo-button-label = Razveljavi
+pdfjs-views-manager-status-done-button-label = Končano
+pdfjs-views-manager-status-close-button =
+ .title = Zapri
+pdfjs-views-manager-status-close-button-label = Zapri
+pdfjs-views-manager-paste-button-label = Prilepi
+pdfjs-views-manager-paste-button-before =
+ .title = Prilepi pred prvo stran
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Prilepi za stranjo { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NOVO
+pdfjs-views-manager-waiting-for-file = Nalaganje datoteke …
+pdfjs-toggle-views-manager-button1 =
+ .title = Upravljanje strani
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Lastnosti digitalnega podpisa
+ .aria-label = Lastnosti digitalnega podpisa
+pdfjs-digital-signature-properties-button-label = Lastnosti digitalnega podpisa
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokument je bil podpisan z veljavnim digitalnim podpisom
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument je podpisan, vendar { $count } digitalnega podpisa ni bilo mogoče preveriti
+ [two] Dokument je podpisan, vendar { $count } digitalnih podpisov ni bilo mogoče preveriti
+ [few] Dokument je podpisan, vendar { $count } digitalnih podpisov ni bilo mogoče preveriti
+ *[other] Dokument je podpisan, vendar { $count } digitalnih podpisov ni bilo mogoče preveriti
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument je podpisan z { $count } digitalnim potrdilom, ki ni zaupanja vredno
+ [two] Dokument je podpisan z { $count } digitalnima potrdiloma, ki nista zaupanja vredni
+ [few] Dokument je podpisan s { $count } digitalnimi potrdili, ki niso zaupanja vredna
+ *[other] Dokument je podpisan s { $count } digitalnimi potrdili, ki niso zaupanja vredna
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument je podpisan z { $count } pretečenim digitalnim potrdilom
+ [two] Dokument je podpisan z { $count } pretečenima digitalnima potrdiloma
+ [few] Dokument je podpisan s { $count } pretečenimi digitalnimi potrdili
+ *[other] Dokument je podpisan s { $count } pretečenimi digitalnimi potrdili
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokument vsebuje { $count } neveljaven digitalni podpis
+ [two] Dokument vsebuje { $count } neveljavna digitalna podpisa
+ [few] Dokument vsebuje { $count } neveljavne digitalne podpise
+ *[other] Dokument vsebuje { $count } neveljavnih digitalnih podpisov
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument je podpisan z { $count } preklicanim digitalnim potrdilom
+ [two] Dokument je podpisan z { $count } preklicanima digitalnima potrdiloma
+ [few] Dokument je podpisan s { $count } preklicanimi digitalnimi potrdili
+ *[other] Dokument je podpisan s { $count } preklicanimi digitalnimi potrdili
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Stanje: podpis preverjen
+pdfjs-digital-signature-properties-status-invalid = Stanje: podpis neveljaven
+pdfjs-digital-signature-properties-status-unknown = Stanje: podpisa ni mogoče preveriti (nepodprt)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Digitalno potrdilo: zaupanja vredno ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Digitalno potrdilo: ni na voljo
+pdfjs-digital-signature-properties-certificate-untrusted = Digitalno potrdilo: ni zaupanja vredno
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Digitalno potrdilo: neznan izdajatelj ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Digitalno potrdilo: samopodpisano ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Digitalno potrdilo: izdajatelj ni zaupanja vreden ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Digitalno potrdilo: pretečeno
+pdfjs-digital-signature-properties-certificate-expired-with-date = Digitalno potrdilo: pretečeno ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Digitalno potrdilo: preklicano
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Odstrani shranjen podpis
+pdfjs-editor-delete-signature-button-label1 = Odstrani shranjen podpis
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Uredi opis
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Uredi opis
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/son/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/son/viewer.ftl
new file mode 100644
index 0000000..ecbe86d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/son/viewer.ftl
@@ -0,0 +1,173 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Moo bisante
+pdfjs-previous-button-label = Bisante
+pdfjs-next-button =
+ .title = Jinehere moo
+pdfjs-next-button-label = Jine
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Moo
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } ra
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } ka hun { $pagesCount }) ra
+pdfjs-zoom-out-button =
+ .title = Nakasandi
+pdfjs-zoom-out-button-label = Nakasandi
+pdfjs-zoom-in-button =
+ .title = Bebbeerandi
+pdfjs-zoom-in-button-label = Bebbeerandi
+pdfjs-zoom-select =
+ .title = Bebbeerandi
+pdfjs-presentation-mode-button =
+ .title = Bere cebeyan alhaali
+pdfjs-presentation-mode-button-label = Cebeyan alhaali
+pdfjs-open-file-button =
+ .title = Tuku feeri
+pdfjs-open-file-button-label = Feeri
+pdfjs-print-button =
+ .title = Kar
+pdfjs-print-button-label = Kar
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Goyjinawey
+pdfjs-tools-button-label = Goyjinawey
+pdfjs-first-page-button =
+ .title = Koy moo jinaa ga
+pdfjs-first-page-button-label = Koy moo jinaa ga
+pdfjs-last-page-button =
+ .title = Koy moo koraa ga
+pdfjs-last-page-button-label = Koy moo koraa ga
+pdfjs-page-rotate-cw-button =
+ .title = Kuubi kanbe guma here
+pdfjs-page-rotate-cw-button-label = Kuubi kanbe guma here
+pdfjs-page-rotate-ccw-button =
+ .title = Kuubi kanbe wowa here
+pdfjs-page-rotate-ccw-button-label = Kuubi kanbe wowa here
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Takadda mayrawey…
+pdfjs-document-properties-button-label = Takadda mayrawey…
+pdfjs-document-properties-file-name = Tuku maa:
+pdfjs-document-properties-file-size = Tuku adadu:
+pdfjs-document-properties-title = Tiiramaa:
+pdfjs-document-properties-author = Hantumkaw:
+pdfjs-document-properties-subject = Dalil:
+pdfjs-document-properties-keywords = Kufalkalimawey:
+pdfjs-document-properties-creation-date = Teeyan han:
+pdfjs-document-properties-modification-date = Barmayan han:
+pdfjs-document-properties-creator = Teekaw:
+pdfjs-document-properties-producer = PDF berandikaw:
+pdfjs-document-properties-version = PDF dumi:
+pdfjs-document-properties-page-count = Moo hinna:
+
+##
+
+pdfjs-document-properties-close-button = Daabu
+
+## Print
+
+pdfjs-print-progress-message = Goo ma takaddaa soolu k'a kar se…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Naŋ
+pdfjs-printing-not-supported = Yaamar: Karyan ši tee ka timme nda ceecikaa woo.
+pdfjs-printing-not-ready = Yaamar: PDF ši zunbu ka timme karyan še.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Kanjari ceraw zuu
+pdfjs-toggle-sidebar-button-label = Kanjari ceraw zuu
+pdfjs-document-outline-button =
+ .title = Takaddaa korfur alhaaloo cebe (naagu cee hinka ka haya-izey kul hayandi/kankamandi)
+pdfjs-document-outline-button-label = Takadda filla-boŋ
+pdfjs-attachments-button =
+ .title = Hangarey cebe
+pdfjs-attachments-button-label = Hangarey
+pdfjs-thumbs-button =
+ .title = Kabeboy biyey cebe
+pdfjs-thumbs-button-label = Kabeboy biyey
+pdfjs-findbar-button =
+ .title = Ceeci takaddaa ra
+pdfjs-findbar-button-label = Ceeci
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } moo
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Kabeboy bii { $page } moo še
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Ceeci
+ .placeholder = Ceeci takaddaa ra…
+pdfjs-find-previous-button =
+ .title = Kalimaɲaŋoo bangayri bisantaa ceeci
+pdfjs-find-previous-button-label = Bisante
+pdfjs-find-next-button =
+ .title = Kalimaɲaŋoo hiino bangayroo ceeci
+pdfjs-find-next-button-label = Jine
+pdfjs-find-highlight-checkbox = Ikul šilbay
+pdfjs-find-match-case-checkbox-label = Harfu-beeriyan hawgay
+pdfjs-find-reached-top = A too moŋoo boŋoo, koy jine ka šinitin nda cewoo
+pdfjs-find-reached-bottom = A too moɲoo cewoo, koy jine šintioo ga
+pdfjs-find-not-found = Kalimaɲaa mana duwandi
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Mooo hayyan
+pdfjs-page-scale-fit = Moo sawayan
+pdfjs-page-scale-auto = Boŋše azzaati barmayyan
+pdfjs-page-scale-actual = Adadu cimi
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Firka bangay kaŋ PDF goo ma zumandi.
+pdfjs-invalid-file-error = PDF tuku laala wala laybante.
+pdfjs-missing-file-error = PDF tuku kumante.
+pdfjs-unexpected-response-error = Manti feršikaw tuuruyan maatante.
+pdfjs-rendering-error = Firka bangay kaŋ moɲoo goo ma willandi.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = { $type } maasa-caw]
+
+## Password
+
+pdfjs-password-label = Šennikufal dam ka PDF tukoo woo feeri.
+pdfjs-password-invalid = Šennikufal laalo. Ceeci koyne taare.
+pdfjs-password-ok-button = Ayyo
+pdfjs-password-cancel-button = Naŋ
+pdfjs-web-fonts-disabled = Interneti šigirawey kay: ši hin ka goy nda PDF šigira hurantey.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sq/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sq/viewer.ftl
new file mode 100644
index 0000000..cbf3d55
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sq/viewer.ftl
@@ -0,0 +1,735 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Faqja e Mëparshme
+pdfjs-previous-button-label = E mëparshmja
+pdfjs-next-button =
+ .title = Faqja Pasuese
+pdfjs-next-button-label = Pasuesja
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Faqe
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = nga { $pagesCount } gjithsej
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } nga { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zvogëlojeni
+pdfjs-zoom-out-button-label = Zvogëlojeni
+pdfjs-zoom-in-button =
+ .title = Zmadhojeni
+pdfjs-zoom-in-button-label = Zmadhojini
+pdfjs-zoom-select =
+ .title = Zmadhim/Zvogëlim
+pdfjs-presentation-mode-button =
+ .title = Kalo te Mënyra Paraqitje
+pdfjs-presentation-mode-button-label = Mënyra Paraqitje
+pdfjs-open-file-button =
+ .title = Hapni Kartelë
+pdfjs-open-file-button-label = Hape
+pdfjs-print-button =
+ .title = Shtypje
+pdfjs-print-button-label = Shtype
+pdfjs-save-button =
+ .title = Ruaje
+pdfjs-save-button-label = Ruaje
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Shkarkojeni
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Shkarkoje
+pdfjs-bookmark-button =
+ .title = Faqja e Tanishme (Shihni URL nga Faqja e Tanishme)
+pdfjs-bookmark-button-label = Faqja e Tanishme
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Mjete
+pdfjs-tools-button-label = Mjete
+pdfjs-first-page-button =
+ .title = Kaloni te Faqja e Parë
+pdfjs-first-page-button-label = Kaloni te Faqja e Parë
+pdfjs-last-page-button =
+ .title = Kaloni te Faqja e Fundit
+pdfjs-last-page-button-label = Kaloni te Faqja e Fundit
+pdfjs-page-rotate-cw-button =
+ .title = Rrotullojeni Në Kahun Orar
+pdfjs-page-rotate-cw-button-label = Rrotulloje Në Kahun Orar
+pdfjs-page-rotate-ccw-button =
+ .title = Rrotullojeni Në Kahun Kundërorar
+pdfjs-page-rotate-ccw-button-label = Rrotulloje Në Kahun Kundërorar
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktivizo Mjet Përzgjedhjeje Teksti
+pdfjs-cursor-text-select-tool-button-label = Mjet Përzgjedhjeje Teksti
+pdfjs-cursor-hand-tool-button =
+ .title = Aktivizo Mjetin Dorë
+pdfjs-cursor-hand-tool-button-label = Mjeti Dorë
+pdfjs-scroll-page-button =
+ .title = Përdor Rrëshqitje Në Faqe
+pdfjs-scroll-page-button-label = Rrëshqitje Në Faqe
+pdfjs-scroll-vertical-button =
+ .title = Përdor Rrëshqitje Vertikale
+pdfjs-scroll-vertical-button-label = Rrëshqitje Vertikale
+pdfjs-scroll-horizontal-button =
+ .title = Përdor Rrëshqitje Horizontale
+pdfjs-scroll-horizontal-button-label = Rrëshqitje Horizontale
+pdfjs-scroll-wrapped-button =
+ .title = Përdor Rrëshqitje Me Mbështjellje
+pdfjs-scroll-wrapped-button-label = Rrëshqitje Me Mbështjellje
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Veti Dokumenti…
+pdfjs-document-properties-button-label = Veti Dokumenti…
+pdfjs-document-properties-file-name = Emër kartele:
+pdfjs-document-properties-file-size = Madhësi kartele:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bajte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bajte)
+pdfjs-document-properties-title = Titull:
+pdfjs-document-properties-author = Autor:
+pdfjs-document-properties-subject = Subjekt:
+pdfjs-document-properties-keywords = Fjalëkyçe:
+pdfjs-document-properties-creation-date = Datë Krijimi:
+pdfjs-document-properties-modification-date = Datë Ndryshimi:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Krijues:
+pdfjs-document-properties-producer = Prodhues PDF-je:
+pdfjs-document-properties-version = Version PDF-je:
+pdfjs-document-properties-page-count = Numër Faqesh:
+pdfjs-document-properties-page-size = Madhësi Faqeje:
+pdfjs-document-properties-page-size-unit-inches = inç
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = portret
+pdfjs-document-properties-page-size-orientation-landscape = së gjeri
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Parje e Shpjetë në Web:
+pdfjs-document-properties-linearized-yes = Po
+pdfjs-document-properties-linearized-no = Jo
+pdfjs-document-properties-close-button = Mbylleni
+
+## Print
+
+pdfjs-print-progress-message = Po përgatitet dokumenti për shtypje…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Anuloje
+pdfjs-printing-not-supported = Kujdes: Shtypja s’mbulohet plotësisht nga ky shfletues.
+pdfjs-printing-not-ready = Kujdes: PDF-ja s’është ngarkuar plotësisht që ta shtypni.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Shfaqni/Fshihni Anështyllën
+pdfjs-toggle-sidebar-notification-button =
+ .title = Hap/Mbyll Anështylë (dokumenti përmban përvijim/nashkëngjitje/shtresa)
+pdfjs-toggle-sidebar-button-label = Shfaq/Fshih Anështyllën
+pdfjs-document-outline-button =
+ .title = Shfaqni Përvijim Dokumenti (dyklikoni që të shfaqen/fshihen krejt elementët)
+pdfjs-document-outline-button-label = Përvijim Dokumenti
+pdfjs-attachments-button =
+ .title = Shfaqni Bashkëngjitje
+pdfjs-attachments-button-label = Bashkëngjitje
+pdfjs-layers-button =
+ .title = Shfaq Shtresa (dyklikoni që të rikthehen krejt shtresat në gjendjen e tyre parazgjedhje)
+pdfjs-layers-button-label = Shtresa
+pdfjs-thumbs-button =
+ .title = Shfaqni Miniatura
+pdfjs-thumbs-button-label = Miniatura
+pdfjs-current-outline-item-button =
+ .title = Gjej Objektin e Tanishëm të Përvijuar
+pdfjs-current-outline-item-button-label = Objekt i Tanishëm i Përvijuar
+pdfjs-findbar-button =
+ .title = Gjeni në Dokument
+pdfjs-findbar-button-label = Gjej
+pdfjs-additional-layers = Shtresa Shtesë
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Faqja { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniaturë e Faqes { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Përzgjidhni faqen { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Faqja { $page } nga { $total } gjithsej
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Gjej
+ .placeholder = Gjeni në dokument…
+pdfjs-find-previous-button =
+ .title = Gjeni hasjen e mëparshme të togfjalëshit
+pdfjs-find-previous-button-label = E mëparshmja
+pdfjs-find-next-button =
+ .title = Gjeni hasjen pasuese të togfjalëshit
+pdfjs-find-next-button-label = Pasuesja
+pdfjs-find-highlight-checkbox = Theksoji të tëra
+pdfjs-find-match-case-checkbox-label = Siç Është Shkruar
+pdfjs-find-match-diacritics-checkbox-label = Me Përputhje Me Shenjat Diakritike
+pdfjs-find-entire-word-checkbox-label = Fjalë të Plota
+pdfjs-find-reached-top = U mbërrit në krye të dokumentit, vazhduar prej fundit
+pdfjs-find-reached-bottom = U mbërrit në fund të dokumentit, vazhduar prej kreut
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } nga { $total } përputhje
+ *[other] { $current } nga { $total } përputhje
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Më tepër se { $limit } përputhje
+ *[other] Më tepër se { $limit } përputhje
+ }
+pdfjs-find-not-found = Togfjalësh që s’gjendet
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Gjerësi Faqeje
+pdfjs-page-scale-fit = Sa Nxë Faqja
+pdfjs-page-scale-auto = Zoom i Vetvetishëm
+pdfjs-page-scale-actual = Madhësia Faktike
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Faqja { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ndodhi një gabim gjatë ngarkimit të PDF-së.
+pdfjs-invalid-file-error = Kartelë PDF e pavlefshme ose e dëmtuar.
+pdfjs-missing-file-error = Kartelë PDF që mungon.
+pdfjs-unexpected-response-error = Përgjigje shërbyesi e papritur.
+pdfjs-rendering-error = Ndodhi një gabim gjatë riprodhimit të faqes.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Nënvizim { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Jepni fjalëkalimin që të hapet kjo kartelë PDF.
+pdfjs-password-invalid = Fjalëkalim i pavlefshëm. Ju lutemi, riprovoni.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Anuloje
+pdfjs-web-fonts-disabled = Shkronjat Web janë të çaktivizuara: s’arrihet të përdoren shkronja të trupëzuara në PDF.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Tekst
+pdfjs-editor-color-picker-free-text-input =
+ .title = Ndryshoni ngjyrë teksti
+pdfjs-editor-free-text-button-label = Tekst
+pdfjs-editor-ink-button =
+ .title = Vizatoni
+pdfjs-editor-color-picker-ink-input =
+ .title = Ndryshoni ngjyrë vizatimi
+pdfjs-editor-ink-button-label = Vizatoni
+pdfjs-editor-stamp-button =
+ .title = Shtoni ose përpunoni figura
+pdfjs-editor-stamp-button-label = Shtoni ose përpunoni figura
+pdfjs-editor-highlight-button =
+ .title = Theksim
+pdfjs-editor-highlight-button-label = Theksoje
+pdfjs-highlight-floating-button1 =
+ .title = Theksim
+ .aria-label = Theksim
+pdfjs-highlight-floating-button-label = Theksim
+pdfjs-comment-floating-button =
+ .title = Komentoni
+ .aria-label = Komentoni
+pdfjs-comment-floating-button-label = Komentoni
+pdfjs-editor-comment-button =
+ .title = Koment
+ .aria-label = Koment
+pdfjs-editor-comment-button-label = Komentoni
+pdfjs-editor-signature-button =
+ .title = Shtoni nënshkrim
+pdfjs-editor-signature-button-label = Shtoni nënshkrim
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Përpunues theksimesh
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Përpunues vizatimesh
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Përpunues nënshkrimesh: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Përpunues figurash
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Hiq vizatim
+pdfjs-editor-remove-freetext-button =
+ .title = Hiq tekst
+pdfjs-editor-remove-stamp-button =
+ .title = Hiq figurë
+pdfjs-editor-remove-highlight-button =
+ .title = Hiqe theksimin
+pdfjs-editor-remove-signature-button =
+ .title = Hiqe nënshkrimin
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Ngjyrë
+pdfjs-editor-free-text-size-input = Madhësi
+pdfjs-editor-ink-color-input = Ngjyrë
+pdfjs-editor-ink-thickness-input = Trashësi
+pdfjs-editor-ink-opacity-input = Patejdukshmëri
+pdfjs-editor-stamp-add-image-button =
+ .title = Shtoni figurë
+pdfjs-editor-stamp-add-image-button-label = Shtoni figurë
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Trashësi
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Ndryshoni trashësinë kur theksoni objekte tjetër nga tekst
+pdfjs-editor-add-signature-container =
+ .aria-label = Kontrolle nënshkrimesh dhe nënshkrime të ruajtur
+pdfjs-editor-signature-add-signature-button =
+ .title = Shtoni nënshkrim të ri
+pdfjs-editor-signature-add-signature-button-label = Shtoni nënshkrim të ri
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Nënshkrim i ruajtur: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Përpunues Tekstesh
+ .default-content = Filloni të shtypni…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Koment
+ *[other] Komente
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Mbylleni anështyllën
+ .aria-label = Mbylleni anështyllën
+pdfjs-editor-comments-sidebar-close-button-label = Mbylleni anështyllën
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Shihni diçka që ia vlen. Theksojeni dhe lini një koment.
+pdfjs-editor-comments-sidebar-no-comments-link = Mësoni më tepër
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Tekst alternativ
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Përpunoni tekst alternativ
+pdfjs-editor-alt-text-dialog-label = Zgjidhni një mundësi
+pdfjs-editor-alt-text-dialog-description = Teksti alt (tekst alternativ) vjen në ndihmë kur njerëzit s’mund të shohin figurën, ose kur ajo nuk ngarkohet.
+pdfjs-editor-alt-text-add-description-label = Shtoni një përshkrim
+pdfjs-editor-alt-text-add-description-description = Synoni për 1-2 togfjalësha që përshkruajnë subjektin, rrethanat apo veprimet.
+pdfjs-editor-alt-text-mark-decorative-label = Vëri shenjë si dekorative
+pdfjs-editor-alt-text-mark-decorative-description = Kjo përdoret për figura zbukuruese, fjala vjen, anë, ose watermark-e.
+pdfjs-editor-alt-text-cancel-button = Anuloje
+pdfjs-editor-alt-text-save-button = Ruaje
+pdfjs-editor-alt-text-decorative-tooltip = Iu vu shenjë si dekorative
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Për shembull, “Një djalosh ulet në një tryezë të hajë”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Tekst alternativ
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Cepi i sipërm majtas — ripërmasojeni
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Mesi i pjesës sipër — ripërmasojeni
+pdfjs-editor-resizer-top-right =
+ .aria-label = Cepi i sipërm djathtas — ripërmasojeni
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Djathtas në mes — ripërmasojeni
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Cepi i poshtëm djathtas — ripërmasojeni
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Mesi i pjesës poshtë — ripërmasojeni
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Cepi i poshtëm — ripërmasojeni
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Majtas në mes — ripërmasojeni
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Ngjyrë theksimi
+pdfjs-editor-colorpicker-button =
+ .title = Ndryshoni ngjyrë
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Zgjedhje ngjyre
+pdfjs-editor-colorpicker-yellow =
+ .title = E verdhë
+pdfjs-editor-colorpicker-green =
+ .title = E gjelbër
+pdfjs-editor-colorpicker-blue =
+ .title = Blu
+pdfjs-editor-colorpicker-pink =
+ .title = Rozë
+pdfjs-editor-colorpicker-red =
+ .title = E kuqe
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Shfaqi krejt
+pdfjs-editor-highlight-show-all-button =
+ .title = Shfaqi krejt
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Përpunoni tekst alternativ (përshkrim figure)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Shtoni tekst alternativ (përshkrim figure)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Shkruani këtu përshkrimin tuaj…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Përshkrim i shkurtër për persona që s’munden të shohin figurën, ose për kur figura nuk ngarkohet dot.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ky tekst alternativ qe krijuar automatikisht dhe mund të jetë i pasaktë.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Mësoni më tepër
+pdfjs-editor-new-alt-text-create-automatically-button-label = Krijo automatikisht tekst alternativ
+pdfjs-editor-new-alt-text-not-now-button = Jo tani
+pdfjs-editor-new-alt-text-error-title = S’u krijua dot automatikisht tekst alternativ
+pdfjs-editor-new-alt-text-error-description = Ju lutemi, shkruani tekstin tuaj alternativ, ose riprovoni më vonë.
+pdfjs-editor-new-alt-text-error-close-button = Mbylle
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Po shkarkohet model IA teksti alternativ ({ $downloadedSize } nga { $totalSize } MB)
+ .aria-valuetext = Po shkarkohet model IA teksti alternativ ({ $downloadedSize } nga { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = U shtua tekst alternativ
+pdfjs-editor-new-alt-text-added-button-label = U shtua tekst alternativ
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Mungon tekst alternativ
+pdfjs-editor-new-alt-text-missing-button-label = Mungon tekst alternativ
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Shqyrtoni tekst alternativ
+pdfjs-editor-new-alt-text-to-review-button-label = Shqyrtoni tekst alternativ
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Krijuar automatikisht: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Rregullime teksti alternativ figure
+pdfjs-image-alt-text-settings-button-label = Rregullime teksti alternativ figure
+pdfjs-editor-alt-text-settings-dialog-label = Rregullime teksti alternativ figure
+pdfjs-editor-alt-text-settings-automatic-title = Tekst alternativ i automatizuar
+pdfjs-editor-alt-text-settings-create-model-button-label = Krijo automatikisht tekst alternativ
+pdfjs-editor-alt-text-settings-create-model-description = Sugjeron përshkrime, për të ndihmuar persona që s’munden të shohin figurën, ose për kur figura nuk ngarkohet dot.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Model IA teksti alternativ ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Xhiron lokalisht në pajisjen tuaj, pra të dhënat tuaja mbeten private. E domosdoshme për tekst të automatizuar alternativ.
+pdfjs-editor-alt-text-settings-delete-model-button = Fshije
+pdfjs-editor-alt-text-settings-download-model-button = Shkarkoje
+pdfjs-editor-alt-text-settings-downloading-model-button = Po shkarkohet…
+pdfjs-editor-alt-text-settings-editor-title = Përpunues teksti alternativ
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Shfaq menjëherë përpunues teksti alternativ, kur shtohet një figurë
+pdfjs-editor-alt-text-settings-show-dialog-description = Ju ndihmon të siguroheni se krejt figurat tuaja kanë tekst alternativ.
+pdfjs-editor-alt-text-settings-close-button = Mbylle
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = U shtua theksim
+pdfjs-editor-freetext-added-alert = U shtua tekst
+pdfjs-editor-ink-added-alert = U shtua vizatim
+pdfjs-editor-stamp-added-alert = U shtua figurë
+pdfjs-editor-signature-added-alert = U shtua nënshkrim
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = U hoq theksimi
+pdfjs-editor-undo-bar-message-freetext = U hoq tekst
+pdfjs-editor-undo-bar-message-ink = U hoq vizatim
+pdfjs-editor-undo-bar-message-stamp = U hoq figurë
+pdfjs-editor-undo-bar-message-signature = Nënshkrimi u hoq
+pdfjs-editor-undo-bar-message-comment = Komenti u hoq
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] U hoq { $count } shënim
+ *[other] U hoqën { $count } shënime
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Zhbëje
+pdfjs-editor-undo-bar-undo-button-label = Zhbëje
+pdfjs-editor-undo-bar-close-button =
+ .title = Mbylle
+pdfjs-editor-undo-bar-close-button-label = Mbylle
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Kjo dritare modale i lejon përdoruesit të krijojë një nënshkrim për ta shtuar te një dokument PDF. Përdoruesi mund të përpunojë emrin (i cili shërben edhe si tekst alternativ) dhe, nëse do, ta ruajë nënshkrimin, për ta përdorur prapë.
+pdfjs-editor-add-signature-dialog-title = Shtoni një nënshkrim
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Lloj
+ .title = Lloj
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Vizatoni
+ .title = Vizatoni
+pdfjs-editor-add-signature-image-button = Figurë
+ .title = Figurë
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Shtypni nënshkrimin tuaj
+ .placeholder = Shtypni nënshkrimin tuaj
+pdfjs-editor-add-signature-draw-placeholder = Vizatoni nënshkrimin tuaj
+pdfjs-editor-add-signature-draw-thickness-range-label = Trashësi
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Trashësi vizatimi: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Tërhiqni këtu një kartelë për ngarkim
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ose zgjidhni kartelë figure
+ *[other] Ose zgjidhni kartelë figure
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Përshkrim (tekst alternativ)
+pdfjs-editor-add-signature-description-input =
+ .title = Përshkrim (tekst alternativ)
+pdfjs-editor-add-signature-description-default-when-drawing = Nënshkrim
+pdfjs-editor-add-signature-clear-button-label = Spastroje nënshkrimin
+pdfjs-editor-add-signature-clear-button =
+ .title = Spastroje nënshkrimin
+pdfjs-editor-add-signature-save-checkbox = Ruaje nënshkrimin
+pdfjs-editor-add-signature-save-warning-message = Keni mbërritur në kufirin e 5 nënshkrimeve të ruajtura. Që të ruani tjetër, hiqni një.
+pdfjs-editor-add-signature-image-upload-error-title = S’u ngarkua dot figurë
+pdfjs-editor-add-signature-image-upload-error-description = Kontrolloni lidhjen tuaj në rrjet, ose provoni figurë tjetër.
+pdfjs-editor-add-signature-image-no-data-error-title = S’shndërrohet dot kjo figurë në një nënshkrim
+pdfjs-editor-add-signature-image-no-data-error-description = Ju lutemi, provoni të ngarkoni një figurë tjetër.
+pdfjs-editor-add-signature-error-close-button = Mbylle
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Anuloje
+pdfjs-editor-add-signature-add-button = Shtoje
+pdfjs-editor-edit-signature-update-button = Përditësoje
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Përpunoni koment
+pdfjs-editor-edit-comment-popup-button =
+ .title = Përpunoni koment
+pdfjs-editor-delete-comment-popup-button-label = Hiqe komentin
+pdfjs-editor-delete-comment-popup-button =
+ .title = Hiqe komentin
+pdfjs-show-comment-button =
+ .title = Shfaqe komentin
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Përpunoni koment
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Përditësojeni
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Shtoni koment
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Shtoje
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Filloni të shtypni…
+pdfjs-editor-edit-comment-dialog-cancel-button = Anuloje
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Shtoni koment
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Shfaqni/Fshihni Anështyllër (dokumenti përmban miniatura/përvijim/bashkëngjitje/shtresa)
+pdfjs-toggle-views-manager-button1-label = Administroni faqe
+pdfjs-views-manager-sidebar =
+ .aria-label = Anështyllë
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Ripërmasues anështylle
+pdfjs-views-manager-view-selector-button =
+ .title = Pamje
+pdfjs-views-manager-view-selector-button-label = Pamje
+pdfjs-views-manager-pages-title = Faqe
+pdfjs-views-manager-attachments-title = Bashkëngjitje
+pdfjs-views-manager-layers-title1 = Shtresa
+ .title = Shtresa (dyklikoni që të rikthehen krejt shtresat te gjendja parazgjedhje)
+pdfjs-views-manager-pages-option-label = Faqe
+pdfjs-views-manager-outlines-option-label = Përvijim dokumenti
+pdfjs-views-manager-attachments-option-label = Bashkëngjitje
+pdfjs-views-manager-layers-option-label = Shtresa
+pdfjs-views-manager-add-file-button =
+ .title = Shtoni kartelë
+pdfjs-views-manager-add-file-button-label = Shtoni kartelë
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } e përzgjedhur
+ *[other] { $count } të përzgjedhura
+ }
+pdfjs-views-manager-pages-status-none-action-label = Përzgjidhni faqe
+pdfjs-views-manager-pages-status-action-button-label = Administrojini
+pdfjs-views-manager-pages-status-copy-button-label = Kopjoje
+pdfjs-views-manager-pages-status-cut-button-label = Prije
+pdfjs-views-manager-pages-status-delete-button-label = Fshije
+pdfjs-views-manager-pages-status-export-selected-button-label = Eksportoni të përzgjedhurit…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Prerje e 1 faqeje
+ *[other] Prerje e { $count } faqesh
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 faqe e kopjuar
+ *[other] { $count } faqe të kopjuara
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 faqe e fshirë
+ *[other] { $count } faqe të fshira
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Po bëhet gati kartela juaj…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Po ngarkohet kartelë…
+pdfjs-views-manager-status-warning-cut-label = S’u bë dot prerja. Rifreskoni faqen dhe riprovoni.
+pdfjs-views-manager-status-warning-copy-label = S’u kopjua dot. Rifreskoni faqen dhe riprovoni.
+pdfjs-views-manager-status-warning-delete-label = S’u fshi dot. Rifreskoni faqen dhe riprovoni.
+pdfjs-views-manager-status-warning-save-label = S’u ruajt dot. Rifreskoni faqen dhe riprovoni.
+pdfjs-views-manager-status-undo-button-label = Zhbëje
+pdfjs-views-manager-status-done-button-label = U bë
+pdfjs-views-manager-status-close-button =
+ .title = Mbylle
+pdfjs-views-manager-status-close-button-label = Mbylle
+pdfjs-views-manager-paste-button-label = Ngjite
+pdfjs-views-manager-paste-button-before =
+ .title = Ngjite para faqes së parë
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Ngjite pas faqes { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = E RE
+pdfjs-toggle-views-manager-button1 =
+ .title = Administroni faqe
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Hiqe nënshkrimin e ruajtur
+pdfjs-editor-delete-signature-button-label1 = Hiqe nënshkrimin e ruajtur
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Përpunoni përshkrimin
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Përpunoni përshkrimin
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sr/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sr/viewer.ftl
new file mode 100644
index 0000000..3da82e0
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sr/viewer.ftl
@@ -0,0 +1,850 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Претходна страница
+pdfjs-previous-button-label = Претходна
+pdfjs-next-button =
+ .title = Следећа страница
+pdfjs-next-button-label = Следећа
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Страница
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = од { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } од { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Умањи
+pdfjs-zoom-out-button-label = Умањи
+pdfjs-zoom-in-button =
+ .title = Увеличај
+pdfjs-zoom-in-button-label = Увеличај
+pdfjs-zoom-select =
+ .title = Увеличавање
+pdfjs-presentation-mode-button =
+ .title = Промени на приказ у режиму презентације
+pdfjs-presentation-mode-button-label = Режим презентације
+pdfjs-open-file-button =
+ .title = Отвори датотеку
+pdfjs-open-file-button-label = Отвори
+pdfjs-print-button =
+ .title = Штампај
+pdfjs-print-button-label = Штампај
+pdfjs-save-button =
+ .title = Сачувај
+pdfjs-save-button-label = Сачувај
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Преузми
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Преузми
+pdfjs-bookmark-button =
+ .title = Тренутна страница (погледајте URL са тренутне странице)
+pdfjs-bookmark-button-label = Тренутна страница
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Алатке
+pdfjs-tools-button-label = Алатке
+pdfjs-first-page-button =
+ .title = Иди на прву страницу
+pdfjs-first-page-button-label = Иди на прву страницу
+pdfjs-last-page-button =
+ .title = Иди на последњу страницу
+pdfjs-last-page-button-label = Иди на последњу страницу
+pdfjs-page-rotate-cw-button =
+ .title = Ротирај у смеру казаљке на сату
+pdfjs-page-rotate-cw-button-label = Ротирај у смеру казаљке на сату
+pdfjs-page-rotate-ccw-button =
+ .title = Ротирај у смеру супротном од казаљке на сату
+pdfjs-page-rotate-ccw-button-label = Ротирај у смеру супротном од казаљке на сату
+pdfjs-cursor-text-select-tool-button =
+ .title = Омогући алат за селектовање текста
+pdfjs-cursor-text-select-tool-button-label = Алат за селектовање текста
+pdfjs-cursor-hand-tool-button =
+ .title = Омогући алат за померање
+pdfjs-cursor-hand-tool-button-label = Алат за померање
+pdfjs-scroll-page-button =
+ .title = Користи скроловање по омоту
+pdfjs-scroll-page-button-label = Скроловање странице
+pdfjs-scroll-vertical-button =
+ .title = Користи вертикално скроловање
+pdfjs-scroll-vertical-button-label = Вертикално скроловање
+pdfjs-scroll-horizontal-button =
+ .title = Користи хоризонтално скроловање
+pdfjs-scroll-horizontal-button-label = Хоризонтално скроловање
+pdfjs-scroll-wrapped-button =
+ .title = Користи скроловање по омоту
+pdfjs-scroll-wrapped-button-label = Скроловање по омоту
+pdfjs-spread-none-button =
+ .title = Немој спајати ширења страница
+pdfjs-spread-none-button-label = Без распростирања
+pdfjs-spread-odd-button =
+ .title = Споји ширења страница које почињу непарним бројем
+pdfjs-spread-odd-button-label = Непарна распростирања
+pdfjs-spread-even-button =
+ .title = Споји ширења страница које почињу парним бројем
+pdfjs-spread-even-button-label = Парна распростирања
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Параметри документа…
+pdfjs-document-properties-button-label = Параметри документа…
+pdfjs-document-properties-file-name = Име датотеке:
+pdfjs-document-properties-file-size = Величина датотеке:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } бајтова)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } бајтова)
+pdfjs-document-properties-title = Наслов:
+pdfjs-document-properties-author = Аутор:
+pdfjs-document-properties-subject = Тема:
+pdfjs-document-properties-keywords = Кључне речи:
+pdfjs-document-properties-creation-date = Датум креирања:
+pdfjs-document-properties-modification-date = Датум модификације:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Стваралац:
+pdfjs-document-properties-producer = PDF произвођач:
+pdfjs-document-properties-version = PDF верзија:
+pdfjs-document-properties-page-count = Број страница:
+pdfjs-document-properties-page-size = Величина странице:
+pdfjs-document-properties-page-size-unit-inches = ин
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = усправно
+pdfjs-document-properties-page-size-orientation-landscape = водоравно
+pdfjs-document-properties-page-size-name-a-three = А3
+pdfjs-document-properties-page-size-name-a-four = А4
+pdfjs-document-properties-page-size-name-letter = Слово
+pdfjs-document-properties-page-size-name-legal = Права
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Брз веб приказ:
+pdfjs-document-properties-linearized-yes = Да
+pdfjs-document-properties-linearized-no = Не
+pdfjs-document-properties-close-button = Затвори
+pdfjs-digital-signature-properties-view-certificate = Прикажи сертификат
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Разлог: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Временски жиг: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Подпотпис ({ $count })
+ [few] Подпотписа ({ $count })
+ *[other] Подпотписа ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Припремам документ за штампање…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Откажи
+pdfjs-printing-not-supported = Упозорење: Штампање није у потпуности подржано у овом прегледачу.
+pdfjs-printing-not-ready = Упозорење: PDF није у потпуности учитан за штампу.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Прикажи/сакриј бочни панел
+pdfjs-toggle-sidebar-notification-button =
+ .title = Прикажи/сакриј бочни панел (документ садржи контуру/прилоге/слојеве)
+pdfjs-toggle-sidebar-button-label = Прикажи/сакриј бочни панел
+pdfjs-document-outline-button =
+ .title = Прикажи структуру документа (двоструким кликом проширујете/скупљате све ставке)
+pdfjs-document-outline-button-label = Контура документа
+pdfjs-attachments-button =
+ .title = Прикажи прилоге
+pdfjs-attachments-button-label = Прилози
+pdfjs-layers-button =
+ .title = Прикажи слојеве (дупли клик за враћање свих слојева у подразумевано стање)
+pdfjs-layers-button-label = Слојеви
+pdfjs-thumbs-button =
+ .title = Прикажи сличице
+pdfjs-thumbs-button-label = Сличице
+pdfjs-current-outline-item-button =
+ .title = Пронађите тренутни елемент структуре
+pdfjs-current-outline-item-button-label = Тренутна контура
+pdfjs-findbar-button =
+ .title = Пронађи у документу
+pdfjs-findbar-button-label = Пронађи
+pdfjs-additional-layers = Додатни слојеви
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Страница { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Сличица од странице { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Изабери страницу { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Страница { $page } од { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Пронађи
+ .placeholder = Пронађи у документу…
+pdfjs-find-previous-button =
+ .title = Пронађи претходно појављивање фразе
+pdfjs-find-previous-button-label = Претходна
+pdfjs-find-next-button =
+ .title = Пронађи следеће појављивање фразе
+pdfjs-find-next-button-label = Следећа
+pdfjs-find-highlight-checkbox = Истакнути све
+pdfjs-find-match-case-checkbox-label = Подударања
+pdfjs-find-match-diacritics-checkbox-label = Дијакритика
+pdfjs-find-entire-word-checkbox-label = Целе речи
+pdfjs-find-reached-top = Достигнут врх документа, наставио са дна
+pdfjs-find-reached-bottom = Достигнуто дно документа, наставио са врха
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } од { $total } поклапања
+ [few] { $current } од { $total } поклапања
+ *[other] { $current } од { $total } поклапања
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Више од { $limit } поклапања
+ [few] Више од { $limit } поклапања
+ *[other] Више од { $limit } поклапања
+ }
+pdfjs-find-not-found = Фраза није пронађена
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ширина странице
+pdfjs-page-scale-fit = Прилагоди страницу
+pdfjs-page-scale-auto = Аутоматско увеличавање
+pdfjs-page-scale-actual = Стварна величина
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Страница { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Дошло је до грешке приликом учитавања PDF-а.
+pdfjs-invalid-file-error = PDF датотека је неважећа или је оштећена.
+pdfjs-missing-file-error = Недостаје PDF датотека.
+pdfjs-unexpected-response-error = Неочекиван одговор од сервера.
+pdfjs-rendering-error = Дошло је до грешке приликом рендеровања ове странице.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } коментар]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Унесите лозинку да бисте отворили овај PDF докуменат.
+pdfjs-password-invalid = Неисправна лозинка. Покушајте поново.
+pdfjs-password-ok-button = У реду
+pdfjs-password-cancel-button = Откажи
+pdfjs-web-fonts-disabled = Веб фонтови су онемогућени: не могу користити уграђене PDF фонтове.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Текст
+pdfjs-editor-color-picker-free-text-input =
+ .title = Промени боју текста
+pdfjs-editor-free-text-button-label = Текст
+pdfjs-editor-ink-button =
+ .title = Цртај
+pdfjs-editor-color-picker-ink-input =
+ .title = Промени боју цртежа
+pdfjs-editor-ink-button-label = Цртај
+pdfjs-editor-stamp-button =
+ .title = Додај или уреди слике
+pdfjs-editor-stamp-button-label = Додај или уреди слике
+pdfjs-editor-highlight-button =
+ .title = Означи
+pdfjs-editor-highlight-button-label = Означи
+pdfjs-highlight-floating-button1 =
+ .title = Означи
+ .aria-label = Означи
+pdfjs-highlight-floating-button-label = Означи
+pdfjs-comment-floating-button =
+ .title = Коментар
+ .aria-label = Коментар
+pdfjs-comment-floating-button-label = Напомена
+pdfjs-editor-comment-button =
+ .title = Коментар
+ .aria-label = Коментар
+pdfjs-editor-comment-button-label = Коментар
+pdfjs-editor-signature-button =
+ .title = Додај потпис
+pdfjs-editor-signature-button-label = Додај потпис
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Уређивач истицања
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Уређивач цртања
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Уређивач потписа: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Уређивач слика
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Уклони цртеж
+pdfjs-editor-remove-freetext-button =
+ .title = Уклони текст
+pdfjs-editor-remove-stamp-button =
+ .title = Уклони слику
+pdfjs-editor-remove-highlight-button =
+ .title = Уклони ознаку
+pdfjs-editor-remove-signature-button =
+ .title = Уклони потпис
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Боја
+pdfjs-editor-free-text-size-input = Величина
+pdfjs-editor-ink-color-input = Боја
+pdfjs-editor-ink-thickness-input = Дебљина
+pdfjs-editor-ink-opacity-input = Опацитет
+pdfjs-editor-stamp-add-image-button =
+ .title = Додај слику
+pdfjs-editor-stamp-add-image-button-label = Додај слику
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Дебљина
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Промени дебљину при означавању других ставки сем текста
+pdfjs-editor-add-signature-container =
+ .aria-label = Контроле потписа и сачувани потписи
+pdfjs-editor-signature-add-signature-button =
+ .title = Додај нови потпис
+pdfjs-editor-signature-add-signature-button-label = Додај нови потпис
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Сачувани потпис: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Уређивач текста
+ .default-content = Почни куцати…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Напомена
+ [few] Напомене
+ *[other] Напомене
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Затвори бочну површ
+ .aria-label = Затвори бочну површ
+pdfjs-editor-comments-sidebar-close-button-label = Затвори бочну површ
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Видите нешто вредно пажње? Истакните то и оставите напомену.
+pdfjs-editor-comments-sidebar-no-comments-link = Сазнајте више
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Алтернативни текст
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Уреди алтернативни текст
+pdfjs-editor-alt-text-dialog-label = Одабери опцију
+pdfjs-editor-alt-text-dialog-description = Алтернативни текст помаже слепим и слабовидим особама или када се слика не учита.
+pdfjs-editor-alt-text-add-description-label = Додај опис
+pdfjs-editor-alt-text-add-description-description = Сажмите у 1-2 реченице које описују предмет, окружење или радње.
+pdfjs-editor-alt-text-mark-decorative-label = Означи као украсно
+pdfjs-editor-alt-text-mark-decorative-description = Ово је за украсне слике, као што су ивице или водени печати.
+pdfjs-editor-alt-text-cancel-button = Откажи
+pdfjs-editor-alt-text-save-button = Сачувај
+pdfjs-editor-alt-text-decorative-tooltip = Означено као украсно
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = На пример: „Младић седа за сто да једе“
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Алтернативни текст
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Горњи леви угао — промени величину
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Средина горе — промени величину
+pdfjs-editor-resizer-top-right =
+ .aria-label = Горњи десни угао — промени величину
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Средина десно — промени величину
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Доњи десни угао — промени величину
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Средина доле — промени величину
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Доњи леви угао — промени величину
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Средина лево — промени величину
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Боја означавања
+pdfjs-editor-colorpicker-button =
+ .title = Промени боју
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Избор боја
+pdfjs-editor-colorpicker-yellow =
+ .title = Жута
+pdfjs-editor-colorpicker-green =
+ .title = Зелена
+pdfjs-editor-colorpicker-blue =
+ .title = Плава
+pdfjs-editor-colorpicker-pink =
+ .title = Розе
+pdfjs-editor-colorpicker-red =
+ .title = Црвена
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Прикажи све
+pdfjs-editor-highlight-show-all-button =
+ .title = Прикажи све
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Уреди алтернативни текст (опис слике)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Додај алтернативни текст (опис слике)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Напиши опис овде…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Кратак опис за слепе и слабовиде људе или када се слика не успе учитати.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Овај алтернативни текст је направљен аутоматски и може бити нетачан.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Сазнајте више
+pdfjs-editor-new-alt-text-create-automatically-button-label = Прави алтернативни текст аутоматски
+pdfjs-editor-new-alt-text-not-now-button = Не сада
+pdfjs-editor-new-alt-text-error-title = Није могуће самостално направити алтернативни текст
+pdfjs-editor-new-alt-text-error-description = Напишите сопствени алтернативни текст или покушајте поново касније.
+pdfjs-editor-new-alt-text-error-close-button = Затвори
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Преузимање ВИ модела за алтернативни текст ({ $downloadedSize } од { $totalSize } MB)
+ .aria-valuetext = Преузимање ВИ модела за алтернативни текст ({ $downloadedSize } од { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Алтернативни текст је додат
+pdfjs-editor-new-alt-text-added-button-label = Алтернативни текст је додат
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Недостаје алтернативни текст
+pdfjs-editor-new-alt-text-missing-button-label = Недостаје алтернативни текст
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Прегледај алтернативни текст
+pdfjs-editor-new-alt-text-to-review-button-label = Прегледај алтернативни текст
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Аутоматски направљено: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Подешавања алтернативног текста слике
+pdfjs-image-alt-text-settings-button-label = Подешавања алтернативног текста слике
+pdfjs-editor-alt-text-settings-dialog-label = Подешавања алтернативног текста слике
+pdfjs-editor-alt-text-settings-automatic-title = Аутоматски алтернативни текст
+pdfjs-editor-alt-text-settings-create-model-button-label = Аутоматски прави алтернативни текст
+pdfjs-editor-alt-text-settings-create-model-description = Предлаже описе како би се помогло људима који не виде слику или када се слика не учита.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = ВИ модел за алтернативни текст ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Ради локално на вашем уређају тако да ваши подаци остају приватни. Потребно за аутоматски алтернативни текст.
+pdfjs-editor-alt-text-settings-delete-model-button = Обриши
+pdfjs-editor-alt-text-settings-download-model-button = Преузми
+pdfjs-editor-alt-text-settings-downloading-model-button = Преузимање…
+pdfjs-editor-alt-text-settings-editor-title = Уређивач алтернативног текста
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Прикажи уређивач алтернативног текста одмах при додавању слике
+pdfjs-editor-alt-text-settings-show-dialog-description = Помаже вам да све ваше слике имају алтернативни текст.
+pdfjs-editor-alt-text-settings-close-button = Затвори
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Истицање је додато
+pdfjs-editor-freetext-added-alert = Текст је додат
+pdfjs-editor-ink-added-alert = Цртеж је додат
+pdfjs-editor-stamp-added-alert = Слика је додата
+pdfjs-editor-signature-added-alert = Потпис је додат
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Истицање је уклоњено
+pdfjs-editor-undo-bar-message-freetext = Текст је уклоњен
+pdfjs-editor-undo-bar-message-ink = Цртеж је уклоњен
+pdfjs-editor-undo-bar-message-stamp = Слика је уклоњена
+pdfjs-editor-undo-bar-message-signature = Потпис је уклоњен
+pdfjs-editor-undo-bar-message-comment = Коментар је уклоњен
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] Уклоњена је { $count } забелешка
+ [few] Уклоњене су { $count } забелешке
+ *[other] Уклоњено је { $count } забелешки
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Опозови
+pdfjs-editor-undo-bar-undo-button-label = Опозови
+pdfjs-editor-undo-bar-close-button =
+ .title = Затвори
+pdfjs-editor-undo-bar-close-button-label = Затвори
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Овај прозор омогућава кориснику да направи потпис који ће додати у ПДФ документ. Корисник може да уреди име (које такође служи као алтернативни текст) и опционо сачува потпис за поновну употребу.
+pdfjs-editor-add-signature-dialog-title = Додај потпис
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Куцај
+ .title = Куцај
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Цртај
+ .title = Цртај
+pdfjs-editor-add-signature-image-button = Слика
+ .title = Слика
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Укуцајте свој потпис
+ .placeholder = Укуцајте свој потпис
+pdfjs-editor-add-signature-draw-placeholder = Нацртајте свој потпис
+pdfjs-editor-add-signature-draw-thickness-range-label = Дебљина
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Дебљина цртања: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Превуците датотеку овде за отпремање
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Или изаберите датотеке слика
+ *[other] Или потражите датотеке слика
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Опис (алтернативни текст)
+pdfjs-editor-add-signature-description-input =
+ .title = Опис (алтернативни текст)
+pdfjs-editor-add-signature-description-default-when-drawing = Потпис
+pdfjs-editor-add-signature-clear-button-label = Обриши потпис
+pdfjs-editor-add-signature-clear-button =
+ .title = Обриши потпис
+pdfjs-editor-add-signature-save-checkbox = Сачувај потпис
+pdfjs-editor-add-signature-save-warning-message = Достигли сте ограничење од 5 сачуваних потписа. Уклоните један да бисте сачували више.
+pdfjs-editor-add-signature-image-upload-error-title = Није могуће отпремити слику
+pdfjs-editor-add-signature-image-upload-error-description = Проверите своју мрежну везу или покушајте са другом сликом.
+pdfjs-editor-add-signature-image-no-data-error-title = Ова слика се не може претворити у потпис
+pdfjs-editor-add-signature-image-no-data-error-description = Покушајте да отпремите другу слику.
+pdfjs-editor-add-signature-error-close-button = Затвори
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Откажи
+pdfjs-editor-add-signature-add-button = Додај
+pdfjs-editor-edit-signature-update-button = Ажурирај
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Уреди коментар
+pdfjs-editor-edit-comment-popup-button =
+ .title = Уреди коментар
+pdfjs-editor-delete-comment-popup-button-label = Уклони коментар
+pdfjs-editor-delete-comment-popup-button =
+ .title = Уклони коментар
+pdfjs-show-comment-button =
+ .title = Прикажи напомену
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Уреди напомену
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Ажурирај
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Додај напомену
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Додај
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Почните да куцате…
+pdfjs-editor-edit-comment-dialog-cancel-button = Откажи
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Додај напомену
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Прикажи/сакриј бочну површ (документ садржи умањене сличице/оквир/прилоге/слојеве)
+pdfjs-toggle-views-manager-button1-label = Управљај страницама
+pdfjs-views-manager-sidebar =
+ .aria-label = Бочна површ
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Промена величине бочне површи
+pdfjs-views-manager-view-selector-button =
+ .title = Прегледи
+pdfjs-views-manager-view-selector-button-label = Прегледи
+pdfjs-views-manager-pages-title = Странице
+pdfjs-views-manager-outlines-title1 = Контура документа
+ .title = Контура документа (двоклик за ширење/скупљање свих ставки)
+pdfjs-views-manager-attachments-title = Прилози
+pdfjs-views-manager-layers-title1 = Слојеви
+ .title = Слојеви (двоклик за враћање свих слојева у подразумевано стање)
+pdfjs-views-manager-pages-option-label = Странице
+pdfjs-views-manager-outlines-option-label = Контура документа
+pdfjs-views-manager-attachments-option-label = Прилози
+pdfjs-views-manager-layers-option-label = Слојеви
+pdfjs-views-manager-add-file-button =
+ .title = Додај датотеку
+pdfjs-views-manager-add-file-button-label = Додај датотеку
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] Изабрана је { $count } страница
+ [few] Изабране су { $count } странице
+ *[other] Изабрано је { $count } страница
+ }
+pdfjs-views-manager-pages-status-none-action-label = Изаберите странице
+pdfjs-views-manager-pages-status-action-button-label = Управљај
+pdfjs-views-manager-pages-status-copy-button-label = Умножи
+pdfjs-views-manager-pages-status-cut-button-label = Исеци
+pdfjs-views-manager-pages-status-delete-button-label = Обриши
+pdfjs-views-manager-pages-status-export-selected-button-label = Извези изабрано…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] Исечена је 1 страница
+ [few] Исечене су { $count } странице
+ *[other] Исечено је { $count } страница
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] Умножена је 1 страница
+ [few] Умножене су { $count } странице
+ *[other] Умножено је { $count } страница
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] Обрисана је 1 страница
+ [few] Обрисане су { $count } странице
+ *[other] Обрисано је { $count } страница
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Припремам датотеку…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Отпремам датотеку…
+pdfjs-views-manager-status-warning-cut-label = Не могу да исечем. Освежите страницу и покушајте поново.
+pdfjs-views-manager-status-warning-copy-label = Не могу да умножим. Освежите страницу и покушајте поново.
+pdfjs-views-manager-status-warning-delete-label = Не могу да обришем. Освежите страницу и покушајте поново.
+pdfjs-views-manager-status-warning-save-label = Не могу да сачувам. Освежите страницу и покушајте поново.
+pdfjs-views-manager-status-undo-button-label = Опозови
+pdfjs-views-manager-status-done-button-label = Готово
+pdfjs-views-manager-status-close-button =
+ .title = Затвори
+pdfjs-views-manager-status-close-button-label = Затвори
+pdfjs-views-manager-paste-button-label = Убаци
+pdfjs-views-manager-paste-button-before =
+ .title = Убаци пре прве странице
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Убаци после странице { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = НОВО
+pdfjs-views-manager-waiting-for-file = Отпремам датотеку…
+pdfjs-toggle-views-manager-button1 =
+ .title = Управљај страницама
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Својства дигиталног потписа
+ .aria-label = Својства дигиталног потписа
+pdfjs-digital-signature-properties-button-label = Својства дигиталног потписа
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Документ је потписан исправним дигиталним потписом
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Документ је потписан, али { $count } дигитални потпис није могао да се потврди
+ [few] Документ је потписан, али { $count } дигитална потписа нису могли да се потврде
+ *[other] Документ је потписан, али { $count } дигиталних потписа није могло да се потврде
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Документ је потписан са { $count } сертификатом који није поуздан
+ [few] Документ је потписан са { $count } сертификата који нису поуздани
+ *[other] Документ је потписан са { $count } сертификата који нису поуздани
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Документ је потписан са { $count } истеклим сертификатом
+ [few] Документ је потписан са { $count } истекла сертификата
+ *[other] Документ је потписан са { $count } истеклих сертификата
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Документ има { $count } неважећи дигитални потпис
+ [few] Документ има { $count } неважећа дигитална потписа
+ *[other] Документ има { $count } неважећих дигиталних потписа
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Документ је потписан са { $count } опозваним сертификатом
+ [few] Документ је потписан са { $count } опозвана сертификата
+ *[other] Документ је потписан са { $count } опозваних сертификата
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Статус: потврђен потпис
+pdfjs-digital-signature-properties-status-invalid = Статус: неважећи потпис
+pdfjs-digital-signature-properties-status-unknown = Статус: није могуће потврдити (неподржано)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Сертификат: поуздан ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Сертификат: недоступан
+pdfjs-digital-signature-properties-certificate-untrusted = Сертификат: неповерљив
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Сертификат: непознат издавач ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Сертификат: самопотписан ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Сертификат: неповерљив издавач ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Сертификат: истекао
+pdfjs-digital-signature-properties-certificate-expired-with-date = Сертификат: истекао ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Сертификат: опозван
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Уклони сачувани потпис
+pdfjs-editor-delete-signature-button-label1 = Уклони сачувани потпис
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Уреди опис
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Уреди опис
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sv-SE/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sv-SE/viewer.ftl
new file mode 100644
index 0000000..b9cc32d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/sv-SE/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Föregående sida
+pdfjs-previous-button-label = Föregående
+pdfjs-next-button =
+ .title = Nästa sida
+pdfjs-next-button-label = Nästa
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Sida
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = av { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } av { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zooma ut
+pdfjs-zoom-out-button-label = Zooma ut
+pdfjs-zoom-in-button =
+ .title = Zooma in
+pdfjs-zoom-in-button-label = Zooma in
+pdfjs-zoom-select =
+ .title = Zoom
+pdfjs-presentation-mode-button =
+ .title = Byt till presentationsläge
+pdfjs-presentation-mode-button-label = Presentationsläge
+pdfjs-open-file-button =
+ .title = Öppna fil
+pdfjs-open-file-button-label = Öppna
+pdfjs-print-button =
+ .title = Skriv ut
+pdfjs-print-button-label = Skriv ut
+pdfjs-save-button =
+ .title = Spara
+pdfjs-save-button-label = Spara
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Hämta
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Hämta
+pdfjs-bookmark-button =
+ .title = Aktuell sida (Visa URL från aktuell sida)
+pdfjs-bookmark-button-label = Aktuell sida
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Verktyg
+pdfjs-tools-button-label = Verktyg
+pdfjs-first-page-button =
+ .title = Gå till första sidan
+pdfjs-first-page-button-label = Gå till första sidan
+pdfjs-last-page-button =
+ .title = Gå till sista sidan
+pdfjs-last-page-button-label = Gå till sista sidan
+pdfjs-page-rotate-cw-button =
+ .title = Rotera medurs
+pdfjs-page-rotate-cw-button-label = Rotera medurs
+pdfjs-page-rotate-ccw-button =
+ .title = Rotera moturs
+pdfjs-page-rotate-ccw-button-label = Rotera moturs
+pdfjs-cursor-text-select-tool-button =
+ .title = Aktivera textmarkeringsverktyg
+pdfjs-cursor-text-select-tool-button-label = Textmarkeringsverktyg
+pdfjs-cursor-hand-tool-button =
+ .title = Aktivera handverktyg
+pdfjs-cursor-hand-tool-button-label = Handverktyg
+pdfjs-scroll-page-button =
+ .title = Använd sidrullning
+pdfjs-scroll-page-button-label = Sidrullning
+pdfjs-scroll-vertical-button =
+ .title = Använd vertikal rullning
+pdfjs-scroll-vertical-button-label = Vertikal rullning
+pdfjs-scroll-horizontal-button =
+ .title = Använd horisontell rullning
+pdfjs-scroll-horizontal-button-label = Horisontell rullning
+pdfjs-scroll-wrapped-button =
+ .title = Använd överlappande rullning
+pdfjs-scroll-wrapped-button-label = Överlappande rullning
+pdfjs-spread-none-button =
+ .title = Visa enkelsidor
+pdfjs-spread-none-button-label = Enkelsidor
+pdfjs-spread-odd-button =
+ .title = Visa uppslag med olika sidnummer till vänster
+pdfjs-spread-odd-button-label = Uppslag med framsida
+pdfjs-spread-even-button =
+ .title = Visa uppslag med lika sidnummer till vänster
+pdfjs-spread-even-button-label = Uppslag utan framsida
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Dokumentegenskaper…
+pdfjs-document-properties-button-label = Dokumentegenskaper…
+pdfjs-document-properties-file-name = Filnamn:
+pdfjs-document-properties-file-size = Filstorlek:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } kB ({ $b } byte)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } byte)
+pdfjs-document-properties-title = Titel:
+pdfjs-document-properties-author = Författare:
+pdfjs-document-properties-subject = Ämne:
+pdfjs-document-properties-keywords = Nyckelord:
+pdfjs-document-properties-creation-date = Skapades:
+pdfjs-document-properties-modification-date = Ändrades:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Skapare:
+pdfjs-document-properties-producer = PDF-producent:
+pdfjs-document-properties-version = PDF-version:
+pdfjs-document-properties-page-count = Sidantal:
+pdfjs-document-properties-page-size = Pappersstorlek:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = porträtt
+pdfjs-document-properties-page-size-orientation-landscape = landskap
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Snabb webbvisning:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Nej
+pdfjs-document-properties-close-button = Stäng
+pdfjs-digital-signature-properties-view-certificate = Visa certifikat
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Orsak: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Tidsstämpel: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Undersignatur ({ $count })
+ *[other] Undersignaturer ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Förbereder sidor för utskrift…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Avbryt
+pdfjs-printing-not-supported = Varning: Utskrifter stöds inte helt av den här webbläsaren.
+pdfjs-printing-not-ready = Varning: PDF:en är inte klar för utskrift.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Visa/dölj sidofält
+pdfjs-toggle-sidebar-notification-button =
+ .title = Växla sidofält (dokumentet innehåller dokumentstruktur/bilagor/lager)
+pdfjs-toggle-sidebar-button-label = Visa/dölj sidofält
+pdfjs-document-outline-button =
+ .title = Visa dokumentdisposition (dubbelklicka för att expandera/komprimera alla objekt)
+pdfjs-document-outline-button-label = Dokumentöversikt
+pdfjs-attachments-button =
+ .title = Visa Bilagor
+pdfjs-attachments-button-label = Bilagor
+pdfjs-layers-button =
+ .title = Visa lager (dubbelklicka för att återställa alla lager till standardläge)
+pdfjs-layers-button-label = Lager
+pdfjs-thumbs-button =
+ .title = Visa miniatyrer
+pdfjs-thumbs-button-label = Miniatyrer
+pdfjs-current-outline-item-button =
+ .title = Hitta aktuellt dispositionsobjekt
+pdfjs-current-outline-item-button-label = Aktuellt dispositionsobjekt
+pdfjs-findbar-button =
+ .title = Sök i dokument
+pdfjs-findbar-button-label = Sök
+pdfjs-additional-layers = Ytterligare lager
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Sida { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatyr av sida { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Välj sida { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Sida { $page } av { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Sök
+ .placeholder = Sök i dokument…
+pdfjs-find-previous-button =
+ .title = Hitta föregående förekomst av frasen
+pdfjs-find-previous-button-label = Föregående
+pdfjs-find-next-button =
+ .title = Hitta nästa förekomst av frasen
+pdfjs-find-next-button-label = Nästa
+pdfjs-find-highlight-checkbox = Markera alla
+pdfjs-find-match-case-checkbox-label = Matcha versal/gemen
+pdfjs-find-match-diacritics-checkbox-label = Matcha diakritiska tecken
+pdfjs-find-entire-word-checkbox-label = Hela ord
+pdfjs-find-reached-top = Nådde början av dokumentet, började från slutet
+pdfjs-find-reached-bottom = Nådde slutet på dokumentet, började från början
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } av { $total } match
+ *[other] { $current } av { $total } matchningar
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Mer än { $limit } matchning
+ *[other] Fler än { $limit } matchningar
+ }
+pdfjs-find-not-found = Frasen hittades inte
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sidbredd
+pdfjs-page-scale-fit = Anpassa sida
+pdfjs-page-scale-auto = Automatisk zoom
+pdfjs-page-scale-actual = Verklig storlek
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Sida { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ett fel uppstod vid laddning av PDF-filen.
+pdfjs-invalid-file-error = Ogiltig eller korrupt PDF-fil.
+pdfjs-missing-file-error = Saknad PDF-fil.
+pdfjs-unexpected-response-error = Oväntat svar från servern.
+pdfjs-rendering-error = Ett fel uppstod vid visning av sidan.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }-annotering]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Skriv in lösenordet för att öppna PDF-filen.
+pdfjs-password-invalid = Ogiltigt lösenord. Försök igen.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Avbryt
+pdfjs-web-fonts-disabled = Webbtypsnitt är inaktiverade: kan inte använda inbäddade PDF-typsnitt.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Text
+pdfjs-editor-color-picker-free-text-input =
+ .title = Ändra textfärg
+pdfjs-editor-free-text-button-label = Text
+pdfjs-editor-ink-button =
+ .title = Rita
+pdfjs-editor-color-picker-ink-input =
+ .title = Ändra ritningsfärg
+pdfjs-editor-ink-button-label = Rita
+pdfjs-editor-stamp-button =
+ .title = Lägg till eller redigera bilder
+pdfjs-editor-stamp-button-label = Lägg till eller redigera bilder
+pdfjs-editor-highlight-button =
+ .title = Markera
+pdfjs-editor-highlight-button-label = Markera
+pdfjs-highlight-floating-button1 =
+ .title = Markera
+ .aria-label = Markera
+pdfjs-highlight-floating-button-label = Markera
+pdfjs-comment-floating-button =
+ .title = Kommentar
+ .aria-label = Kommentar
+pdfjs-comment-floating-button-label = Kommentar
+pdfjs-editor-comment-button =
+ .title = Kommentar
+ .aria-label = Kommentar
+pdfjs-editor-comment-button-label = Kommentar
+pdfjs-editor-signature-button =
+ .title = Lägg till signatur
+pdfjs-editor-signature-button-label = Lägg till signatur
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Markeringsredigerare
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Ritredigerare
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Signaturredigerare: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Bildredigerare
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Ta bort ritning
+pdfjs-editor-remove-freetext-button =
+ .title = Ta bort text
+pdfjs-editor-remove-stamp-button =
+ .title = Ta bort bild
+pdfjs-editor-remove-highlight-button =
+ .title = Ta bort markering
+pdfjs-editor-remove-signature-button =
+ .title = Ta bort signatur
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Färg
+pdfjs-editor-free-text-size-input = Storlek
+pdfjs-editor-ink-color-input = Färg
+pdfjs-editor-ink-thickness-input = Tjocklek
+pdfjs-editor-ink-opacity-input = Opacitet
+pdfjs-editor-stamp-add-image-button =
+ .title = Lägg till bild
+pdfjs-editor-stamp-add-image-button-label = Lägg till bild
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Tjocklek
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Ändra tjocklek när du markerar andra objekt än text
+pdfjs-editor-add-signature-container =
+ .aria-label = Signaturkontroller och sparade signaturer
+pdfjs-editor-signature-add-signature-button =
+ .title = Lägg till ny signatur
+pdfjs-editor-signature-add-signature-button-label = Lägg till ny signatur
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Sparad signatur: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Textredigerare
+ .default-content = Börja skriva…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Kommentar
+ *[other] Kommentarer
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Stäng sidofältet
+ .aria-label = Stäng sidofältet
+pdfjs-editor-comments-sidebar-close-button-label = Stäng sidofältet
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Ser du något anmärkningsvärt? Markera det och lämna en kommentar.
+pdfjs-editor-comments-sidebar-no-comments-link = Läs mer
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternativ text
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Redigera alternativ text
+pdfjs-editor-alt-text-dialog-label = Välj ett alternativ
+pdfjs-editor-alt-text-dialog-description = Alt text (alternativ text) hjälper till när människor inte kan se bilden eller när den inte laddas.
+pdfjs-editor-alt-text-add-description-label = Lägg till en beskrivning
+pdfjs-editor-alt-text-add-description-description = Sikta på 1-2 meningar som beskriver ämnet, miljön eller handlingen.
+pdfjs-editor-alt-text-mark-decorative-label = Markera som dekorativ
+pdfjs-editor-alt-text-mark-decorative-description = Detta används för dekorativa bilder, som kanter eller vattenstämplar.
+pdfjs-editor-alt-text-cancel-button = Avbryt
+pdfjs-editor-alt-text-save-button = Spara
+pdfjs-editor-alt-text-decorative-tooltip = Märkt som dekorativ
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Till exempel, "En ung man sätter sig vid ett bord för att äta en måltid"
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternativ text
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Det övre vänstra hörnet — ändra storlek
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Överst i mitten — ändra storlek
+pdfjs-editor-resizer-top-right =
+ .aria-label = Det övre högra hörnet — ändra storlek
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Mitten höger — ändra storlek
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Nedre högra hörnet — ändra storlek
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Nedre mitten — ändra storlek
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Nedre vänstra hörnet — ändra storlek
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Mitten till vänster — ändra storlek
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Markeringsfärg
+pdfjs-editor-colorpicker-button =
+ .title = Ändra färg
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Färgval
+pdfjs-editor-colorpicker-yellow =
+ .title = Gul
+pdfjs-editor-colorpicker-green =
+ .title = Grön
+pdfjs-editor-colorpicker-blue =
+ .title = Blå
+pdfjs-editor-colorpicker-pink =
+ .title = Rosa
+pdfjs-editor-colorpicker-red =
+ .title = Röd
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Visa alla
+pdfjs-editor-highlight-show-all-button =
+ .title = Visa alla
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Redigera alternativ text (bildbeskrivning)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Lägg till alternativ text (bildbeskrivning)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Skriv din beskrivning här…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Kort beskrivning för personer som inte kan se bilden eller när bilden inte laddas.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Denna alternativa text skapades automatiskt och kan vara felaktig.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Läs mer
+pdfjs-editor-new-alt-text-create-automatically-button-label = Skapa alternativ text automatiskt
+pdfjs-editor-new-alt-text-not-now-button = Inte nu
+pdfjs-editor-new-alt-text-error-title = Det gick inte att skapa alternativ text automatiskt
+pdfjs-editor-new-alt-text-error-description = Skriv din egna alternativa text eller försök igen senare.
+pdfjs-editor-new-alt-text-error-close-button = Stäng
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Hämtar AI-modell med alternativ text ({ $downloadedSize } av { $totalSize } MB)
+ .aria-valuetext = Hämtar AI-modell med alternativ text ({ $downloadedSize } av { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternativ text tillagd
+pdfjs-editor-new-alt-text-added-button-label = Alternativ text tillagd
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Saknar alternativ text
+pdfjs-editor-new-alt-text-missing-button-label = Saknar alternativ text
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Granska alternativ text
+pdfjs-editor-new-alt-text-to-review-button-label = Granska alternativ text
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Skapas automatiskt: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Alternativ textinställningar för bild
+pdfjs-image-alt-text-settings-button-label = Alternativ textinställningar för bild
+pdfjs-editor-alt-text-settings-dialog-label = Alternativ textinställningar för bild
+pdfjs-editor-alt-text-settings-automatic-title = Automatisk alternativ text
+pdfjs-editor-alt-text-settings-create-model-button-label = Skapa alternativ text automatiskt
+pdfjs-editor-alt-text-settings-create-model-description = Föreslår beskrivningar för att hjälpa personer som inte kan se bilden eller när bilden inte laddas.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = AI-modell för alternativ text ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Körs lokalt på din enhet så att din data förblir privat. Krävs för automatisk alternativ text.
+pdfjs-editor-alt-text-settings-delete-model-button = Ta bort
+pdfjs-editor-alt-text-settings-download-model-button = Hämta
+pdfjs-editor-alt-text-settings-downloading-model-button = Hämtar…
+pdfjs-editor-alt-text-settings-editor-title = Alternativ textredigerare
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Visa alternativ textredigerare direkt när du lägger till en bild
+pdfjs-editor-alt-text-settings-show-dialog-description = Hjälper dig att se till att alla dina bilder har alternativ text.
+pdfjs-editor-alt-text-settings-close-button = Stäng
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Markering tillagd
+pdfjs-editor-freetext-added-alert = Text tillagd
+pdfjs-editor-ink-added-alert = Ritning tillagd
+pdfjs-editor-stamp-added-alert = Bild tillagd
+pdfjs-editor-signature-added-alert = Signatur tillagd
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Markering borttagen
+pdfjs-editor-undo-bar-message-freetext = Text borttagen
+pdfjs-editor-undo-bar-message-ink = Ritning borttagen
+pdfjs-editor-undo-bar-message-stamp = Bild borttagen
+pdfjs-editor-undo-bar-message-signature = Signatur borttagen
+pdfjs-editor-undo-bar-message-comment = Kommentar borttagen
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } anteckning har tagits bort
+ *[other] { $count } anteckningar har tagits bort
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Ångra
+pdfjs-editor-undo-bar-undo-button-label = Ångra
+pdfjs-editor-undo-bar-close-button =
+ .title = Stäng
+pdfjs-editor-undo-bar-close-button-label = Stäng
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Denna modal tillåter användaren att skapa en signatur för att lägga till i ett PDF-dokument. Användaren kan redigera namnet (som också fungerar som alternativ text) och eventuellt spara signaturen för upprepad användning.
+pdfjs-editor-add-signature-dialog-title = Lägg till en signatur
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Typ
+ .title = Typ
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Rita
+ .title = Rita
+pdfjs-editor-add-signature-image-button = Bild
+ .title = Bild
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Skriv din signatur
+ .placeholder = Skriv din signatur
+pdfjs-editor-add-signature-draw-placeholder = Rita din signatur
+pdfjs-editor-add-signature-draw-thickness-range-label = Tjocklek
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Ritningstjocklek: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Dra en fil hit för att ladda upp
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Eller välj bildfiler
+ *[other] Eller bläddra bland bildfiler
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Beskrivning (alternativ text)
+pdfjs-editor-add-signature-description-input =
+ .title = Beskrivning (alternativ text)
+pdfjs-editor-add-signature-description-default-when-drawing = Signatur
+pdfjs-editor-add-signature-clear-button-label = Rensa signatur
+pdfjs-editor-add-signature-clear-button =
+ .title = Rensa signatur
+pdfjs-editor-add-signature-save-checkbox = Spara signatur
+pdfjs-editor-add-signature-save-warning-message = Du har nått gränsen på 5 sparade signaturer. Ta bort en för att spara fler.
+pdfjs-editor-add-signature-image-upload-error-title = Det gick inte att ladda upp bilden
+pdfjs-editor-add-signature-image-upload-error-description = Kontrollera din nätverksanslutning eller försök med en annan bild.
+pdfjs-editor-add-signature-image-no-data-error-title = Det går inte att konvertera den här bilden till en signatur
+pdfjs-editor-add-signature-image-no-data-error-description = Prova att ladda upp en annan bild.
+pdfjs-editor-add-signature-error-close-button = Stäng
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Avbryt
+pdfjs-editor-add-signature-add-button = Lägg till
+pdfjs-editor-edit-signature-update-button = Uppdatera
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Redigera kommentar
+pdfjs-editor-edit-comment-popup-button =
+ .title = Redigera kommentar
+pdfjs-editor-delete-comment-popup-button-label = Ta bort kommentar
+pdfjs-editor-delete-comment-popup-button =
+ .title = Ta bort kommentar
+pdfjs-show-comment-button =
+ .title = Visa kommentar
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Redigera kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Uppdatera
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Lägg till kommentar
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Lägg till
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Börja skriva…
+pdfjs-editor-edit-comment-dialog-cancel-button = Avbryt
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Lägg till kommentar
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Visa/dölj sidofält (dokument innehåller miniatyrer/översikt/bilagor/lager)
+pdfjs-toggle-views-manager-button1-label = Hantera sidor
+pdfjs-views-manager-sidebar =
+ .aria-label = Sidofält
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Storleksändring av sidofält
+pdfjs-views-manager-view-selector-button =
+ .title = Vyer
+pdfjs-views-manager-view-selector-button-label = Vyer
+pdfjs-views-manager-pages-title = Sidor
+pdfjs-views-manager-outlines-title1 = Dokumentöversikt
+ .title = Dokumentöversikt (dubbelklicka för att expandera/komprimera alla objekt)
+pdfjs-views-manager-attachments-title = Bilagor
+pdfjs-views-manager-layers-title1 = Lager
+ .title = Lager (dubbelklicka för att återställa alla lager till standardläge)
+pdfjs-views-manager-pages-option-label = Sidor
+pdfjs-views-manager-outlines-option-label = Dokumentöversikt
+pdfjs-views-manager-attachments-option-label = Bilagor
+pdfjs-views-manager-layers-option-label = Lager
+pdfjs-views-manager-add-file-button =
+ .title = Lägg till fil
+pdfjs-views-manager-add-file-button-label = Lägg till fil
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } vald
+ *[other] { $count } valda
+ }
+pdfjs-views-manager-pages-status-none-action-label = Välj sidor
+pdfjs-views-manager-pages-status-action-button-label = Hantera
+pdfjs-views-manager-pages-status-copy-button-label = Kopiera
+pdfjs-views-manager-pages-status-cut-button-label = Klipp ut
+pdfjs-views-manager-pages-status-delete-button-label = Ta bort
+pdfjs-views-manager-pages-status-export-selected-button-label = Exportera markerad…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 sida klippt
+ *[other] { $count } sidor klippta
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 sida kopierad
+ *[other] { $count } sidor kopierade
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 sida borttagen
+ *[other] { $count } sidor borttagna
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Förbereder din fil…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Överför fil…
+pdfjs-views-manager-status-warning-cut-label = Det gick inte att klippa. Uppdatera sidan och försök igen.
+pdfjs-views-manager-status-warning-copy-label = Det gick inte att kopiera. Uppdatera sidan och försök igen.
+pdfjs-views-manager-status-warning-delete-label = Det gick inte att ta bort. Uppdatera sidan och försök igen.
+pdfjs-views-manager-status-warning-save-label = Det gick inte att spara. Uppdatera sidan och försök igen.
+pdfjs-views-manager-status-undo-button-label = Ångra
+pdfjs-views-manager-status-done-button-label = Klar
+pdfjs-views-manager-status-close-button =
+ .title = Stäng
+pdfjs-views-manager-status-close-button-label = Stäng
+pdfjs-views-manager-paste-button-label = Klistra in
+pdfjs-views-manager-paste-button-before =
+ .title = Klistra in före den första sidan
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Klistra in efter sida { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = NYTT
+pdfjs-views-manager-waiting-for-file = Överför fil…
+pdfjs-toggle-views-manager-button1 =
+ .title = Hantera sidor
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Egenskaper för digital signatur
+ .aria-label = Egenskaper för digital signatur
+pdfjs-digital-signature-properties-button-label = Egenskaper för digital signatur
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Dokumentet signerades med en giltig digital signatur
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Dokument signerat men { $count } digital signatur kunde inte verifieras
+ *[other] Dokument signerat men { $count } digitala signaturer kunde inte verifieras
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Dokument signerat med { $count } certifikat som inte är tillförlitligt
+ *[other] Dokument signerat med { $count } certifikat som inte är tillförlitliga
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Dokument signerat med { $count } utgånget certifikat
+ *[other] Dokument signerat med { $count } utgångna certifikat
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Dokumentet har { $count } ogiltig digital signatur
+ *[other] Dokumentet har { $count } ogiltiga digitala signaturer
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Dokument signerat med { $count } återkallat certifikat
+ *[other] Dokument signerat med { $count } återkallade certifikat
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Status: Signatur verifierad
+pdfjs-digital-signature-properties-status-invalid = Status: Ogiltig signatur
+pdfjs-digital-signature-properties-status-unknown = Status: Kan inte verifiera (stöds inte)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Certifikat: Tillförlitligt ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Certifikat: Ej tillgänglig
+pdfjs-digital-signature-properties-certificate-untrusted = Certifikat: Otillförlitligt
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certifikat: Okänd utfärdare ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certifikat: Självsignerat ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certifikat: Otillförlitlig utfärdare ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Certifikat: Utgånget
+pdfjs-digital-signature-properties-certificate-expired-with-date = Certifikat: Utgånget ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Certifikat: Återkallat
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Ta bort sparad signatur
+pdfjs-editor-delete-signature-button-label1 = Ta bort sparad signatur
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Redigera beskrivning
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Redigera beskrivning
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/szl/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/szl/viewer.ftl
new file mode 100644
index 0000000..4ab6c8f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/szl/viewer.ftl
@@ -0,0 +1,228 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Piyrwyjszo strōna
+pdfjs-previous-button-label = Piyrwyjszo
+pdfjs-next-button =
+ .title = Nastympno strōna
+pdfjs-next-button-label = Dalij
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Strōna
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = ze { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } ze { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Zmyńsz
+pdfjs-zoom-out-button-label = Zmyńsz
+pdfjs-zoom-in-button =
+ .title = Zwiynksz
+pdfjs-zoom-in-button-label = Zwiynksz
+pdfjs-zoom-select =
+ .title = Srogość
+pdfjs-presentation-mode-button =
+ .title = Przełōncz na tryb prezyntacyje
+pdfjs-presentation-mode-button-label = Tryb prezyntacyje
+pdfjs-open-file-button =
+ .title = Ôdewrzij zbiōr
+pdfjs-open-file-button-label = Ôdewrzij
+pdfjs-print-button =
+ .title = Durkuj
+pdfjs-print-button-label = Durkuj
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Noczynia
+pdfjs-tools-button-label = Noczynia
+pdfjs-first-page-button =
+ .title = Idź ku piyrszyj strōnie
+pdfjs-first-page-button-label = Idź ku piyrszyj strōnie
+pdfjs-last-page-button =
+ .title = Idź ku ôstatnij strōnie
+pdfjs-last-page-button-label = Idź ku ôstatnij strōnie
+pdfjs-page-rotate-cw-button =
+ .title = Zwyrtnij w prawo
+pdfjs-page-rotate-cw-button-label = Zwyrtnij w prawo
+pdfjs-page-rotate-ccw-button =
+ .title = Zwyrtnij w lewo
+pdfjs-page-rotate-ccw-button-label = Zwyrtnij w lewo
+pdfjs-cursor-text-select-tool-button =
+ .title = Załōncz noczynie ôbiyranio tekstu
+pdfjs-cursor-text-select-tool-button-label = Noczynie ôbiyranio tekstu
+pdfjs-cursor-hand-tool-button =
+ .title = Załōncz noczynie rōnczka
+pdfjs-cursor-hand-tool-button-label = Noczynie rōnczka
+pdfjs-scroll-vertical-button =
+ .title = Używej piōnowego przewijanio
+pdfjs-scroll-vertical-button-label = Piōnowe przewijanie
+pdfjs-scroll-horizontal-button =
+ .title = Używej poziōmego przewijanio
+pdfjs-scroll-horizontal-button-label = Poziōme przewijanie
+pdfjs-scroll-wrapped-button =
+ .title = Używej szichtowego przewijanio
+pdfjs-scroll-wrapped-button-label = Szichtowe przewijanie
+pdfjs-spread-none-button =
+ .title = Niy dowej strōn w widoku po dwie
+pdfjs-spread-none-button-label = Po jednyj strōnie
+pdfjs-spread-odd-button =
+ .title = Pokoż strōny po dwie; niyporziste po lewyj
+pdfjs-spread-odd-button-label = Niyporziste po lewyj
+pdfjs-spread-even-button =
+ .title = Pokoż strōny po dwie; porziste po lewyj
+pdfjs-spread-even-button-label = Porziste po lewyj
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Włosności dokumyntu…
+pdfjs-document-properties-button-label = Włosności dokumyntu…
+pdfjs-document-properties-file-name = Miano zbioru:
+pdfjs-document-properties-file-size = Srogość zbioru:
+pdfjs-document-properties-title = Tytuł:
+pdfjs-document-properties-author = Autōr:
+pdfjs-document-properties-subject = Tymat:
+pdfjs-document-properties-keywords = Kluczowe słowa:
+pdfjs-document-properties-creation-date = Data zrychtowanio:
+pdfjs-document-properties-modification-date = Data zmiany:
+pdfjs-document-properties-creator = Zrychtowane ôd:
+pdfjs-document-properties-producer = PDF ôd:
+pdfjs-document-properties-version = Wersyjo PDF:
+pdfjs-document-properties-page-count = Wielość strōn:
+pdfjs-document-properties-page-size = Srogość strōny:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = piōnowo
+pdfjs-document-properties-page-size-orientation-landscape = poziōmo
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Gibki necowy podglōnd:
+pdfjs-document-properties-linearized-yes = Ja
+pdfjs-document-properties-linearized-no = Niy
+pdfjs-document-properties-close-button = Zawrzij
+
+## Print
+
+pdfjs-print-progress-message = Rychtowanie dokumyntu do durku…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Pociep
+pdfjs-printing-not-supported = Pozōr: Ta przeglōndarka niy cołkiym ôbsuguje durk.
+pdfjs-printing-not-ready = Pozōr: Tyn PDF niy ma za tela zaladowany do durku.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Przełōncz posek na rancie
+pdfjs-toggle-sidebar-notification-button =
+ .title = Przełōncz posek na rancie (dokumynt mo struktura/przidowki/warstwy)
+pdfjs-toggle-sidebar-button-label = Przełōncz posek na rancie
+pdfjs-document-outline-button =
+ .title = Pokoż struktura dokumyntu (tuplowane klikniyncie rozszyrzo/swijo wszyskie elymynta)
+pdfjs-document-outline-button-label = Struktura dokumyntu
+pdfjs-attachments-button =
+ .title = Pokoż przidowki
+pdfjs-attachments-button-label = Przidowki
+pdfjs-layers-button =
+ .title = Pokoż warstwy (tuplowane klikniyncie resetuje wszyskie warstwy do bazowego stanu)
+pdfjs-layers-button-label = Warstwy
+pdfjs-thumbs-button =
+ .title = Pokoż miniatury
+pdfjs-thumbs-button-label = Miniatury
+pdfjs-findbar-button =
+ .title = Znojdź w dokumyncie
+pdfjs-findbar-button-label = Znojdź
+pdfjs-additional-layers = Nadbytnie warstwy
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Strōna { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Miniatura strōny { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Znojdź
+ .placeholder = Znojdź w dokumyncie…
+pdfjs-find-previous-button =
+ .title = Znojdź piyrwyjsze pokozanie sie tyj frazy
+pdfjs-find-previous-button-label = Piyrwyjszo
+pdfjs-find-next-button =
+ .title = Znojdź nastympne pokozanie sie tyj frazy
+pdfjs-find-next-button-label = Dalij
+pdfjs-find-highlight-checkbox = Zaznacz wszysko
+pdfjs-find-match-case-checkbox-label = Poznowej srogość liter
+pdfjs-find-entire-word-checkbox-label = Cołke słowa
+pdfjs-find-reached-top = Doszło do samego wiyrchu strōny, dalij ôd spodku
+pdfjs-find-reached-bottom = Doszło do samego spodku strōny, dalij ôd wiyrchu
+pdfjs-find-not-found = Fraza niy znaleziōno
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Szyrzka strōny
+pdfjs-page-scale-fit = Napasowanie strōny
+pdfjs-page-scale-auto = Autōmatyczno srogość
+pdfjs-page-scale-actual = Aktualno srogość
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Przi ladowaniu PDFa pokozoł sie feler.
+pdfjs-invalid-file-error = Zły abo felerny zbiōr PDF.
+pdfjs-missing-file-error = Chybio zbioru PDF.
+pdfjs-unexpected-response-error = Niyôczekowano ôdpowiydź serwera.
+pdfjs-rendering-error = Przi renderowaniu strōny pokozoł sie feler.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Anotacyjo typu { $type }]
+
+## Password
+
+pdfjs-password-label = Wkludź hasło, coby ôdewrzić tyn zbiōr PDF.
+pdfjs-password-invalid = Hasło je złe. Sprōbuj jeszcze roz.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Pociep
+pdfjs-web-fonts-disabled = Necowe fōnty sōm zastawiōne: niy idzie użyć wkludzōnych fōntōw PDF.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ta/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ta/viewer.ftl
new file mode 100644
index 0000000..fe1c347
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ta/viewer.ftl
@@ -0,0 +1,198 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = முந்தைய பக்கம்
+pdfjs-previous-button-label = முந்தையது
+pdfjs-next-button =
+ .title = அடுத்த பக்கம்
+pdfjs-next-button-label = அடுத்து
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = பக்கம்
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } இல்
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = { $pagesCount }) இல் ({ $pageNumber }
+pdfjs-zoom-out-button =
+ .title = சிறிதாக்கு
+pdfjs-zoom-out-button-label = சிறிதாக்கு
+pdfjs-zoom-in-button =
+ .title = பெரிதாக்கு
+pdfjs-zoom-in-button-label = பெரிதாக்கு
+pdfjs-zoom-select =
+ .title = பெரிதாக்கு
+pdfjs-presentation-mode-button =
+ .title = விளக்ககாட்சி பயன்முறைக்கு மாறு
+pdfjs-presentation-mode-button-label = விளக்ககாட்சி பயன்முறை
+pdfjs-open-file-button =
+ .title = கோப்பினை திற
+pdfjs-open-file-button-label = திற
+pdfjs-print-button =
+ .title = அச்சிடு
+pdfjs-print-button-label = அச்சிடு
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = கருவிகள்
+pdfjs-tools-button-label = கருவிகள்
+pdfjs-first-page-button =
+ .title = முதல் பக்கத்திற்கு செல்லவும்
+pdfjs-first-page-button-label = முதல் பக்கத்திற்கு செல்லவும்
+pdfjs-last-page-button =
+ .title = கடைசி பக்கத்திற்கு செல்லவும்
+pdfjs-last-page-button-label = கடைசி பக்கத்திற்கு செல்லவும்
+pdfjs-page-rotate-cw-button =
+ .title = வலஞ்சுழியாக சுழற்று
+pdfjs-page-rotate-cw-button-label = வலஞ்சுழியாக சுழற்று
+pdfjs-page-rotate-ccw-button =
+ .title = இடஞ்சுழியாக சுழற்று
+pdfjs-page-rotate-ccw-button-label = இடஞ்சுழியாக சுழற்று
+pdfjs-cursor-text-select-tool-button =
+ .title = உரைத் தெரிவு கருவியைச் செயல்படுத்து
+pdfjs-cursor-text-select-tool-button-label = உரைத் தெரிவு கருவி
+pdfjs-cursor-hand-tool-button =
+ .title = கைக் கருவிக்ச் செயற்படுத்து
+pdfjs-cursor-hand-tool-button-label = கைக்குருவி
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = ஆவண பண்புகள்...
+pdfjs-document-properties-button-label = ஆவண பண்புகள்...
+pdfjs-document-properties-file-name = கோப்பு பெயர்:
+pdfjs-document-properties-file-size = கோப்பின் அளவு:
+pdfjs-document-properties-title = தலைப்பு:
+pdfjs-document-properties-author = எழுதியவர்
+pdfjs-document-properties-subject = பொருள்:
+pdfjs-document-properties-keywords = முக்கிய வார்த்தைகள்:
+pdfjs-document-properties-creation-date = படைத்த தேதி :
+pdfjs-document-properties-modification-date = திருத்திய தேதி:
+pdfjs-document-properties-creator = உருவாக்குபவர்:
+pdfjs-document-properties-producer = பிடிஎஃப் தயாரிப்பாளர்:
+pdfjs-document-properties-version = PDF பதிப்பு:
+pdfjs-document-properties-page-count = பக்க எண்ணிக்கை:
+pdfjs-document-properties-page-size = பக்க அளவு:
+pdfjs-document-properties-page-size-unit-inches = இதில்
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = நிலைபதிப்பு
+pdfjs-document-properties-page-size-orientation-landscape = நிலைபரப்பு
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = கடிதம்
+pdfjs-document-properties-page-size-name-legal = சட்டபூர்வ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-close-button = மூடுக
+
+## Print
+
+pdfjs-print-progress-message = அச்சிடுவதற்கான ஆவணம் தயாராகிறது...
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ரத்து
+pdfjs-printing-not-supported = எச்சரிக்கை: இந்த உலாவி அச்சிடுதலை முழுமையாக ஆதரிக்கவில்லை.
+pdfjs-printing-not-ready = எச்சரிக்கை: PDF அச்சிட முழுவதுமாக ஏற்றப்படவில்லை.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = பக்கப் பட்டியை நிலைமாற்று
+pdfjs-toggle-sidebar-button-label = பக்கப் பட்டியை நிலைமாற்று
+pdfjs-document-outline-button =
+ .title = ஆவண அடக்கத்தைக் காட்டு (இருமுறைச் சொடுக்கி அனைத்து உறுப்பிடிகளையும் விரி/சேர்)
+pdfjs-document-outline-button-label = ஆவண வெளிவரை
+pdfjs-attachments-button =
+ .title = இணைப்புகளை காண்பி
+pdfjs-attachments-button-label = இணைப்புகள்
+pdfjs-thumbs-button =
+ .title = சிறுபடங்களைக் காண்பி
+pdfjs-thumbs-button-label = சிறுபடங்கள்
+pdfjs-findbar-button =
+ .title = ஆவணத்தில் கண்டறி
+pdfjs-findbar-button-label = தேடு
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = பக்கம் { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = பக்கத்தின் சிறுபடம் { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = கண்டுபிடி
+ .placeholder = ஆவணத்தில் கண்டறி…
+pdfjs-find-previous-button =
+ .title = இந்த சொற்றொடரின் முந்தைய நிகழ்வை தேடு
+pdfjs-find-previous-button-label = முந்தையது
+pdfjs-find-next-button =
+ .title = இந்த சொற்றொடரின் அடுத்த நிகழ்வை தேடு
+pdfjs-find-next-button-label = அடுத்து
+pdfjs-find-highlight-checkbox = அனைத்தையும் தனிப்படுத்து
+pdfjs-find-match-case-checkbox-label = பேரெழுத்தாக்கத்தை உணர்
+pdfjs-find-reached-top = ஆவணத்தின் மேல் பகுதியை அடைந்தது, அடிப்பக்கத்திலிருந்து தொடர்ந்தது
+pdfjs-find-reached-bottom = ஆவணத்தின் முடிவை அடைந்தது, மேலிருந்து தொடர்ந்தது
+pdfjs-find-not-found = சொற்றொடர் காணவில்லை
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = பக்க அகலம்
+pdfjs-page-scale-fit = பக்கப் பொருத்தம்
+pdfjs-page-scale-auto = தானியக்க பெரிதாக்கல்
+pdfjs-page-scale-actual = உண்மையான அளவு
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF ஐ ஏற்றும் போது ஒரு பிழை ஏற்பட்டது.
+pdfjs-invalid-file-error = செல்லுபடியாகாத அல்லது சிதைந்த PDF கோப்பு.
+pdfjs-missing-file-error = PDF கோப்பு காணவில்லை.
+pdfjs-unexpected-response-error = சேவகன் பதில் எதிர்பாரதது.
+pdfjs-rendering-error = இந்தப் பக்கத்தை காட்சிப்படுத்தும் போது ஒரு பிழை ஏற்பட்டது.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } விளக்கம்]
+
+## Password
+
+pdfjs-password-label = இந்த PDF கோப்பை திறக்க கடவுச்சொல்லை உள்ளிடவும்.
+pdfjs-password-invalid = செல்லுபடியாகாத கடவுச்சொல், தயை செய்து மீண்டும் முயற்சி செய்க.
+pdfjs-password-ok-button = சரி
+pdfjs-password-cancel-button = ரத்து
+pdfjs-web-fonts-disabled = வலை எழுத்துருக்கள் முடக்கப்பட்டுள்ளன: உட்பொதிக்கப்பட்ட PDF எழுத்துருக்களைப் பயன்படுத்த முடியவில்லை.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/te/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/te/viewer.ftl
new file mode 100644
index 0000000..24838bc
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/te/viewer.ftl
@@ -0,0 +1,213 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = మునుపటి పేజీ
+pdfjs-previous-button-label = క్రితం
+pdfjs-next-button =
+ .title = తరువాత పేజీ
+pdfjs-next-button-label = తరువాత
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = పేజీ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = మొత్తం { $pagesCount } లో
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = (మొత్తం { $pagesCount } లో { $pageNumber }వది)
+pdfjs-zoom-out-button =
+ .title = జూమ్ తగ్గించు
+pdfjs-zoom-out-button-label = జూమ్ తగ్గించు
+pdfjs-zoom-in-button =
+ .title = జూమ్ చేయి
+pdfjs-zoom-in-button-label = జూమ్ చేయి
+pdfjs-zoom-select =
+ .title = జూమ్
+pdfjs-presentation-mode-button =
+ .title = ప్రదర్శనా రీతికి మారు
+pdfjs-presentation-mode-button-label = ప్రదర్శనా రీతి
+pdfjs-open-file-button =
+ .title = ఫైల్ తెరువు
+pdfjs-open-file-button-label = తెరువు
+pdfjs-print-button =
+ .title = ముద్రించు
+pdfjs-print-button-label = ముద్రించు
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = పనిముట్లు
+pdfjs-tools-button-label = పనిముట్లు
+pdfjs-first-page-button =
+ .title = మొదటి పేజీకి వెళ్ళు
+pdfjs-first-page-button-label = మొదటి పేజీకి వెళ్ళు
+pdfjs-last-page-button =
+ .title = చివరి పేజీకి వెళ్ళు
+pdfjs-last-page-button-label = చివరి పేజీకి వెళ్ళు
+pdfjs-page-rotate-cw-button =
+ .title = సవ్యదిశలో తిప్పు
+pdfjs-page-rotate-cw-button-label = సవ్యదిశలో తిప్పు
+pdfjs-page-rotate-ccw-button =
+ .title = అపసవ్యదిశలో తిప్పు
+pdfjs-page-rotate-ccw-button-label = అపసవ్యదిశలో తిప్పు
+pdfjs-cursor-text-select-tool-button =
+ .title = టెక్స్ట్ ఎంపిక సాధనాన్ని ప్రారంభించండి
+pdfjs-cursor-text-select-tool-button-label = టెక్స్ట్ ఎంపిక సాధనం
+pdfjs-cursor-hand-tool-button =
+ .title = చేతి సాధనం చేతనించు
+pdfjs-cursor-hand-tool-button-label = చేతి సాధనం
+pdfjs-scroll-vertical-button-label = నిలువు స్క్రోలింగు
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = పత్రము లక్షణాలు...
+pdfjs-document-properties-button-label = పత్రము లక్షణాలు...
+pdfjs-document-properties-file-name = దస్త్రం పేరు:
+pdfjs-document-properties-file-size = దస్త్రం పరిమాణం:
+pdfjs-document-properties-title = శీర్షిక:
+pdfjs-document-properties-author = మూలకర్త:
+pdfjs-document-properties-subject = విషయం:
+pdfjs-document-properties-keywords = కీ పదాలు:
+pdfjs-document-properties-creation-date = సృష్టించిన తేదీ:
+pdfjs-document-properties-modification-date = సవరించిన తేదీ:
+pdfjs-document-properties-creator = సృష్టికర్త:
+pdfjs-document-properties-producer = PDF ఉత్పాదకి:
+pdfjs-document-properties-version = PDF వర్షన్:
+pdfjs-document-properties-page-count = పేజీల సంఖ్య:
+pdfjs-document-properties-page-size = కాగితం పరిమాణం:
+pdfjs-document-properties-page-size-unit-inches = లో
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = నిలువుచిత్రం
+pdfjs-document-properties-page-size-orientation-landscape = అడ్డచిత్రం
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = లేఖ
+pdfjs-document-properties-page-size-name-legal = చట్టపరమైన
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+pdfjs-document-properties-linearized-yes = అవును
+pdfjs-document-properties-linearized-no = కాదు
+pdfjs-document-properties-close-button = మూసివేయి
+
+## Print
+
+pdfjs-print-progress-message = ముద్రించడానికి పత్రము సిద్ధమవుతున్నది…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = రద్దుచేయి
+pdfjs-printing-not-supported = హెచ్చరిక: ఈ విహారిణి చేత ముద్రణ పూర్తిగా తోడ్పాటు లేదు.
+pdfjs-printing-not-ready = హెచ్చరిక: ముద్రణ కొరకు ఈ PDF పూర్తిగా లోడవలేదు.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = పక్కపట్టీ మార్చు
+pdfjs-toggle-sidebar-button-label = పక్కపట్టీ మార్చు
+pdfjs-document-outline-button =
+ .title = పత్రము రూపము చూపించు (డబుల్ క్లిక్ చేసి అన్ని అంశాలను విస్తరించు/కూల్చు)
+pdfjs-document-outline-button-label = పత్రము అవుట్లైన్
+pdfjs-attachments-button =
+ .title = అనుబంధాలు చూపు
+pdfjs-attachments-button-label = అనుబంధాలు
+pdfjs-layers-button-label = పొరలు
+pdfjs-thumbs-button =
+ .title = థంబ్నైల్స్ చూపు
+pdfjs-thumbs-button-label = థంబ్నైల్స్
+pdfjs-findbar-button =
+ .title = పత్రములో కనుగొనుము
+pdfjs-findbar-button-label = కనుగొను
+pdfjs-additional-layers = అదనపు పొరలు
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = పేజీ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } పేజీ నఖచిత్రం
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = కనుగొను
+ .placeholder = పత్రములో కనుగొను…
+pdfjs-find-previous-button =
+ .title = పదం యొక్క ముందు సంభవాన్ని కనుగొను
+pdfjs-find-previous-button-label = మునుపటి
+pdfjs-find-next-button =
+ .title = పదం యొక్క తర్వాతి సంభవాన్ని కనుగొను
+pdfjs-find-next-button-label = తరువాత
+pdfjs-find-highlight-checkbox = అన్నిటిని ఉద్దీపనం చేయుము
+pdfjs-find-match-case-checkbox-label = అక్షరముల తేడాతో పోల్చు
+pdfjs-find-entire-word-checkbox-label = పూర్తి పదాలు
+pdfjs-find-reached-top = పేజీ పైకి చేరుకున్నది, క్రింది నుండి కొనసాగించండి
+pdfjs-find-reached-bottom = పేజీ చివరకు చేరుకున్నది, పైనుండి కొనసాగించండి
+pdfjs-find-not-found = పదబంధం కనబడలేదు
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = పేజీ వెడల్పు
+pdfjs-page-scale-fit = పేజీ అమర్పు
+pdfjs-page-scale-auto = స్వయంచాలక జూమ్
+pdfjs-page-scale-actual = యథార్ధ పరిమాణం
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF లోడవుచున్నప్పుడు ఒక దోషం ఎదురైంది.
+pdfjs-invalid-file-error = చెల్లని లేదా పాడైన PDF ఫైలు.
+pdfjs-missing-file-error = దొరకని PDF ఫైలు.
+pdfjs-unexpected-response-error = అనుకోని సర్వర్ స్పందన.
+pdfjs-rendering-error = పేజీను రెండర్ చేయుటలో ఒక దోషం ఎదురైంది.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } టీకా]
+
+## Password
+
+pdfjs-password-label = ఈ PDF ఫైల్ తెరుచుటకు సంకేతపదం ప్రవేశపెట్టుము.
+pdfjs-password-invalid = సంకేతపదం చెల్లదు. దయచేసి మళ్ళీ ప్రయత్నించండి.
+pdfjs-password-ok-button = సరే
+pdfjs-password-cancel-button = రద్దుచేయి
+pdfjs-web-fonts-disabled = వెబ్ ఫాంట్లు అచేతనించబడెను: ఎంబెడెడ్ PDF ఫాంట్లు ఉపయోగించలేక పోయింది.
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = రంగు
+pdfjs-editor-free-text-size-input = పరిమాణం
+pdfjs-editor-ink-color-input = రంగు
+pdfjs-editor-ink-thickness-input = మందం
+pdfjs-editor-ink-opacity-input = అకిరణ్యత
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tg/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tg/viewer.ftl
new file mode 100644
index 0000000..ad09f51
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tg/viewer.ftl
@@ -0,0 +1,741 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Саҳифаи қаблӣ
+pdfjs-previous-button-label = Қаблӣ
+pdfjs-next-button =
+ .title = Саҳифаи навбатӣ
+pdfjs-next-button-label = Навбатӣ
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Саҳифа
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = аз { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } аз { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Хурд кардан
+pdfjs-zoom-out-button-label = Хурд кардан
+pdfjs-zoom-in-button =
+ .title = Калон кардан
+pdfjs-zoom-in-button-label = Калон кардан
+pdfjs-zoom-select =
+ .title = Танзими андоза
+pdfjs-presentation-mode-button =
+ .title = Гузариш ба реҷаи тақдим
+pdfjs-presentation-mode-button-label = Реҷаи тақдим
+pdfjs-open-file-button =
+ .title = Кушодани файл
+pdfjs-open-file-button-label = Кушодан
+pdfjs-print-button =
+ .title = Чоп кардан
+pdfjs-print-button-label = Чоп кардан
+pdfjs-save-button =
+ .title = Нигоҳ доштан
+pdfjs-save-button-label = Нигоҳ доштан
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Боргирӣ кардан
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Боргирӣ кардан
+pdfjs-bookmark-button =
+ .title = Саҳифаи ҷорӣ (Дидани нишонии URL аз саҳифаи ҷорӣ)
+pdfjs-bookmark-button-label = Саҳифаи ҷорӣ
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Абзорҳо
+pdfjs-tools-button-label = Абзорҳо
+pdfjs-first-page-button =
+ .title = Ба саҳифаи аввал гузаред
+pdfjs-first-page-button-label = Ба саҳифаи аввал гузаред
+pdfjs-last-page-button =
+ .title = Ба саҳифаи охирин гузаред
+pdfjs-last-page-button-label = Ба саҳифаи охирин гузаред
+pdfjs-page-rotate-cw-button =
+ .title = Ба самти ҳаракати ақрабаки соат давр задан
+pdfjs-page-rotate-cw-button-label = Ба самти ҳаракати ақрабаки соат давр задан
+pdfjs-page-rotate-ccw-button =
+ .title = Ба муқобили самти ҳаракати ақрабаки соат давр задан
+pdfjs-page-rotate-ccw-button-label = Ба муқобили самти ҳаракати ақрабаки соат давр задан
+pdfjs-cursor-text-select-tool-button =
+ .title = Фаъол кардани «Абзори интихоби матн»
+pdfjs-cursor-text-select-tool-button-label = Абзори интихоби матн
+pdfjs-cursor-hand-tool-button =
+ .title = Фаъол кардани «Абзори даст»
+pdfjs-cursor-hand-tool-button-label = Абзори даст
+pdfjs-scroll-page-button =
+ .title = Истифодаи варақзанӣ
+pdfjs-scroll-page-button-label = Варақзанӣ
+pdfjs-scroll-vertical-button =
+ .title = Истифодаи варақзании амудӣ
+pdfjs-scroll-vertical-button-label = Варақзании амудӣ
+pdfjs-scroll-horizontal-button =
+ .title = Истифодаи варақзании уфуқӣ
+pdfjs-scroll-horizontal-button-label = Варақзании уфуқӣ
+pdfjs-scroll-wrapped-button =
+ .title = Истифодаи варақзании миқёсбандӣ
+pdfjs-scroll-wrapped-button-label = Варақзании миқёсбандӣ
+pdfjs-spread-none-button =
+ .title = Густариши саҳифаҳо истифода бурда нашавад
+pdfjs-spread-none-button-label = Бе густурдани саҳифаҳо
+pdfjs-spread-odd-button =
+ .title = Густариши саҳифаҳо аз саҳифаҳо бо рақамҳои тоқ оғоз карда мешавад
+pdfjs-spread-odd-button-label = Саҳифаҳои тоқ аз тарафи чап
+pdfjs-spread-even-button =
+ .title = Густариши саҳифаҳо аз саҳифаҳо бо рақамҳои ҷуфт оғоз карда мешавад
+pdfjs-spread-even-button-label = Саҳифаҳои ҷуфт аз тарафи чап
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Хусусиятҳои ҳуҷҷат…
+pdfjs-document-properties-button-label = Хусусиятҳои ҳуҷҷат…
+pdfjs-document-properties-file-name = Номи файл:
+pdfjs-document-properties-file-size = Андозаи файл:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } КБ ({ $b } байт)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } МБ ({ $b } байт)
+pdfjs-document-properties-title = Сарлавҳа:
+pdfjs-document-properties-author = Муаллиф:
+pdfjs-document-properties-subject = Мавзуъ:
+pdfjs-document-properties-keywords = Калимаҳои калидӣ:
+pdfjs-document-properties-creation-date = Санаи эҷод:
+pdfjs-document-properties-modification-date = Санаи тағйирот:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Эҷодкунанда:
+pdfjs-document-properties-producer = Таҳиякунандаи «PDF»:
+pdfjs-document-properties-version = Версияи «PDF»:
+pdfjs-document-properties-page-count = Шумораи саҳифаҳо:
+pdfjs-document-properties-page-size = Андозаи саҳифа:
+pdfjs-document-properties-page-size-unit-inches = дюйм
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = амудӣ
+pdfjs-document-properties-page-size-orientation-landscape = уфуқӣ
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Мактуб
+pdfjs-document-properties-page-size-name-legal = Ҳуқуқӣ
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Намоиши тез дар Интернет:
+pdfjs-document-properties-linearized-yes = Ҳа
+pdfjs-document-properties-linearized-no = Не
+pdfjs-document-properties-close-button = Пӯшидан
+
+## Print
+
+pdfjs-print-progress-message = Омодасозии ҳуҷҷат барои чоп…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Бекор кардан
+pdfjs-printing-not-supported = Диққат: Чопкунӣ аз тарафи ин браузер ба таври пурра дастгирӣ намешавад.
+pdfjs-printing-not-ready = Диққат: Файли «PDF» барои чопкунӣ пурра бор карда нашуд.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Фаъол кардани навори ҷонибӣ
+pdfjs-toggle-sidebar-notification-button =
+ .title = Фаъол кардани навори ҷонибӣ (ҳуҷҷат дорои сохтор/замимаҳо/қабатҳо мебошад)
+pdfjs-toggle-sidebar-button-label = Фаъол кардани навори ҷонибӣ
+pdfjs-document-outline-button =
+ .title = Намоиш додани сохтори ҳуҷҷат (барои баркушодан/пеҷондани ҳамаи унсурҳо дубора зер кунед)
+pdfjs-document-outline-button-label = Сохтори ҳуҷҷат
+pdfjs-attachments-button =
+ .title = Намоиш додани замимаҳо
+pdfjs-attachments-button-label = Замимаҳо
+pdfjs-layers-button =
+ .title = Намоиш додани қабатҳо (барои барқарор кардани ҳамаи қабатҳо ба вазъияти пешфарз дубора зер кунед)
+pdfjs-layers-button-label = Қабатҳо
+pdfjs-thumbs-button =
+ .title = Намоиш додани тасвирчаҳо
+pdfjs-thumbs-button-label = Тасвирчаҳо
+pdfjs-current-outline-item-button =
+ .title = Ёфтани унсури сохтори ҷорӣ
+pdfjs-current-outline-item-button-label = Унсури сохтори ҷорӣ
+pdfjs-findbar-button =
+ .title = Ёфтан дар ҳуҷҷат
+pdfjs-findbar-button-label = Ёфтан
+pdfjs-additional-layers = Қабатҳои иловагӣ
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Саҳифаи { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Тасвирчаи саҳифаи { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Интихоби саҳифаи { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Саҳифаи { $page } аз { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Ёфтан
+ .placeholder = Ёфтан дар ҳуҷҷат…
+pdfjs-find-previous-button =
+ .title = Ҷустуҷӯи мавриди қаблии ибораи пешниҳодшуда
+pdfjs-find-previous-button-label = Қаблӣ
+pdfjs-find-next-button =
+ .title = Ҷустуҷӯи мавриди навбатии ибораи пешниҳодшуда
+pdfjs-find-next-button-label = Навбатӣ
+pdfjs-find-highlight-checkbox = Ҳамаашро бо ранг ҷудо кардан
+pdfjs-find-match-case-checkbox-label = Бо дарназардошти ҳарфҳои хурду калон
+pdfjs-find-match-diacritics-checkbox-label = Бо дарназардошти аломатҳои диакритикӣ
+pdfjs-find-entire-word-checkbox-label = Калимаҳои пурра
+pdfjs-find-reached-top = Ба болои ҳуҷҷат расид, аз поён идома ёфт
+pdfjs-find-reached-bottom = Ба поёни ҳуҷҷат расид, аз боло идома ёфт
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } аз { $total } мувофиқат
+ *[other] { $current } аз { $total } мувофиқат
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Зиёда аз { $limit } мувофиқат
+ *[other] Зиёда аз { $limit } мувофиқат
+ }
+pdfjs-find-not-found = Ибора ёфт нашуд
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Аз рӯи паҳнои саҳифа
+pdfjs-page-scale-fit = Аз рӯи андозаи саҳифа
+pdfjs-page-scale-auto = Андозаи худкор
+pdfjs-page-scale-actual = Андозаи воқеӣ
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Саҳифаи { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Ҳангоми боркунии «PDF» хато ба миён омад.
+pdfjs-invalid-file-error = Файли «PDF» нодуруст ё вайроншуда мебошад.
+pdfjs-missing-file-error = Файли «PDF» ғоиб аст.
+pdfjs-unexpected-response-error = Ҷавоби ногаҳон аз сервер.
+pdfjs-rendering-error = Ҳангоми шаклсозии саҳифа хато ба миён омад.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Ҳошиянависӣ - { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Барои кушодани ин файли «PDF» ниҳонвожаро ворид кунед.
+pdfjs-password-invalid = Ниҳонвожаи нодуруст. Лутфан, аз нав кӯшиш кунед.
+pdfjs-password-ok-button = ХУБ
+pdfjs-password-cancel-button = Бекор кардан
+pdfjs-web-fonts-disabled = Шрифтҳои интернетӣ ғайрифаъоланд: истифодаи шрифтҳои дарунсохти «PDF» ғайриимкон аст.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Матн
+pdfjs-editor-color-picker-free-text-input =
+ .title = Иваз кардани ранги матн
+pdfjs-editor-free-text-button-label = Матн
+pdfjs-editor-ink-button =
+ .title = Расмкашӣ
+pdfjs-editor-color-picker-ink-input =
+ .title = Иваз кардани ранги расмкашӣ
+pdfjs-editor-ink-button-label = Расмкашӣ
+pdfjs-editor-stamp-button =
+ .title = Илова ё таҳрир кардани тасвирҳо
+pdfjs-editor-stamp-button-label = Илова ё таҳрир кардани тасвирҳо
+pdfjs-editor-highlight-button =
+ .title = Ҷудокунӣ
+pdfjs-editor-highlight-button-label = Ҷудокунӣ
+pdfjs-highlight-floating-button1 =
+ .title = Ҷудокунӣ
+ .aria-label = Ҷудокунӣ
+pdfjs-highlight-floating-button-label = Ҷудокунӣ
+pdfjs-comment-floating-button =
+ .title = Шарҳ
+ .aria-label = Шарҳ
+pdfjs-comment-floating-button-label = Шарҳ
+pdfjs-editor-comment-button =
+ .title = Шарҳ
+ .aria-label = Шарҳ
+pdfjs-editor-comment-button-label = Шарҳ
+pdfjs-editor-signature-button =
+ .title = Илова кардани имзо
+pdfjs-editor-signature-button-label = Илова кардани имзо
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Муҳаррири ҷудокунӣ
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Муҳаррири расмкашӣ
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Муҳаррири имзо: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Муҳаррири тасвир
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Тоза кардани нақша
+pdfjs-editor-remove-freetext-button =
+ .title = Тоза кардани матн
+pdfjs-editor-remove-stamp-button =
+ .title = Тоза кардани тасвир
+pdfjs-editor-remove-highlight-button =
+ .title = Тоза кардани ҷудокунӣ
+pdfjs-editor-remove-signature-button =
+ .title = Тоза кардани имзо
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Ранг
+pdfjs-editor-free-text-size-input = Андоза
+pdfjs-editor-ink-color-input = Ранг
+pdfjs-editor-ink-thickness-input = Ғафсӣ
+pdfjs-editor-ink-opacity-input = Шаффофӣ
+pdfjs-editor-stamp-add-image-button =
+ .title = Илова кардани тасвир
+pdfjs-editor-stamp-add-image-button-label = Илова кардани тасвир
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Ғафсӣ
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Иваз кардани ғафсӣ ҳангоми ҷудокунии унсурҳо ба ғайр аз матн
+pdfjs-editor-add-signature-container =
+ .aria-label = Идоракунии имзоҳо ва имзоҳои гузошташуда
+pdfjs-editor-signature-add-signature-button =
+ .title = Илова кардани имзои нав
+pdfjs-editor-signature-add-signature-button-label = Илова кардани имзои нав
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Имзои гузошташуда: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Муҳаррири матн
+ .default-content = Матнро ворид кунед…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Шарҳ
+ *[other] Шарҳҳо
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Пӯшидани навори ҷонибӣ
+ .aria-label = Пӯшидани навори ҷонибӣ
+pdfjs-editor-comments-sidebar-close-button-label = Пӯшидани навори ҷонибӣ
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Чизи диққатангезро мушоҳида кардед? Онро қайд кунед ва ба он шарҳ гузоред.
+pdfjs-editor-comments-sidebar-no-comments-link = Маълумоти бештар
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Матни иловагӣ
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Таҳрир кардани матни ивазкунанда
+pdfjs-editor-alt-text-dialog-label = Имконеро интихоб намоед
+pdfjs-editor-alt-text-dialog-description = Вақте ки одамон тасвирро дида наметавонанд ё вақте ки тасвир бор карда намешавад, матни иловагӣ (Alt text) кумак мерасонад.
+pdfjs-editor-alt-text-add-description-label = Илова кардани тавсиф
+pdfjs-editor-alt-text-add-description-description = Кӯшиш кунед, ки 1-2 ҷумлаеро нависед, ки ба мавзӯъ, танзим ё амалҳо тавзеҳ медиҳад.
+pdfjs-editor-alt-text-mark-decorative-label = Гузоштан ҳамчун матни ороишӣ
+pdfjs-editor-alt-text-mark-decorative-description = Ин барои тасвирҳои ороишӣ, ба монанди марзҳо ё аломатҳои обӣ, истифода мешавад.
+pdfjs-editor-alt-text-cancel-button = Бекор кардан
+pdfjs-editor-alt-text-save-button = Нигоҳ доштан
+pdfjs-editor-alt-text-decorative-tooltip = Ҳамчун матни ороишӣ гузошта шуд
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Барои мисол, «Ман забони тоҷикиро дӯст медорам»
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Матни ивазкунанда
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Кунҷи чапи боло — тағйир додани андоза
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Канори миёнаи боло — тағйир додани андоза
+pdfjs-editor-resizer-top-right =
+ .aria-label = Кунҷи рости боло — тағйир додани андоза
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Канори миёнаи рост — тағйир додани андоза
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Кунҷи рости поён — тағйир додани андоза
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Канори миёнаи поён — тағйир додани андоза
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Кунҷи чапи поён — тағйир додани андоза
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Канори миёнаи чап — тағйир додани андоза
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Ранги ҷудокунӣ
+pdfjs-editor-colorpicker-button =
+ .title = Иваз кардани ранг
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Интихоби ранг
+pdfjs-editor-colorpicker-yellow =
+ .title = Зард
+pdfjs-editor-colorpicker-green =
+ .title = Сабз
+pdfjs-editor-colorpicker-blue =
+ .title = Кабуд
+pdfjs-editor-colorpicker-pink =
+ .title = Гулобӣ
+pdfjs-editor-colorpicker-red =
+ .title = Сурх
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Ҳамаро намоиш додан
+pdfjs-editor-highlight-show-all-button =
+ .title = Ҳамаро намоиш додан
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Таҳрир кардани матни иловагӣ (тафсири тасвир)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Илова кардани матни иловагӣ (тафсири тасвир)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Тафсири худро дар ин ҷо нависед…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Тавсифи мухтасар барои одамоне, ки аксҳоро дида наметавонанд ё вақте ки аксҳо кушода намешаванд.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Ин матни ивазкунанда ба таври худкор сохта шудааст ва шояд нодуруст бошад.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Маълумоти бештар
+pdfjs-editor-new-alt-text-create-automatically-button-label = Ба таври худкор эҷод кардани матни иловагӣ
+pdfjs-editor-new-alt-text-not-now-button = Ҳоло не
+pdfjs-editor-new-alt-text-error-title = Матни иловагӣ ба таври худкор эҷод карда нашуд
+pdfjs-editor-new-alt-text-error-description = Лутфан, матни иловагии худро ворид кунед ё баъдтар аз нав кӯшиш кунед.
+pdfjs-editor-new-alt-text-error-close-button = Пӯшидан
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Боргирии модели зеҳни сунъӣ (AI) барои матни ивазкунанда ({ $downloadedSize } аз { $totalSize } МБ)
+ .aria-valuetext = Боргирии модели зеҳни сунъӣ (AI) барои матни ивазкунанда ({ $downloadedSize } аз { $totalSize } МБ)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Матни иловагӣ илова карда шуд
+pdfjs-editor-new-alt-text-added-button-label = Матни иловагӣ илова карда шуд
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Матни иловагӣ вуҷуд надорад
+pdfjs-editor-new-alt-text-missing-button-label = Матни иловагӣ вуҷуд надорад
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Бознигарӣ кардани матни иловагӣ
+pdfjs-editor-new-alt-text-to-review-button-label = Бознигарӣ кардани матни иловагӣ
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Ба таври худкор сохта шудааст: «{ $generatedAltText }»
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Танзимоти матни иловагии тасвир
+pdfjs-image-alt-text-settings-button-label = Танзимоти матни иловагии тасвир
+pdfjs-editor-alt-text-settings-dialog-label = Танзимоти матни иловагии тасвир
+pdfjs-editor-alt-text-settings-automatic-title = Матни иловагии худкор
+pdfjs-editor-alt-text-settings-create-model-button-label = Ба таври худкор эҷод кардани матни иловагӣ
+pdfjs-editor-alt-text-settings-create-model-description = Ин имкон барои расонидани кумак ба одамоне, ки аксҳоро дида наметавонанд ё вақте ки аксҳо кушода намешаванд, тавсифи аксҳоро пешниҳод мекунад.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Модели зеҳни сунъӣ «AI» барои матни ивазкунанда ({ $totalSize } МБ)
+pdfjs-editor-alt-text-settings-ai-model-description = Дар дастгоҳи шумо ба таври маҳаллӣ кор мекунад, бинобар ин махфияти маълумоти шахсии шумо нигоҳ дошта мешавад. Барои матни ивазкунандаи худкор лозим аст.
+pdfjs-editor-alt-text-settings-delete-model-button = Нест кардан
+pdfjs-editor-alt-text-settings-download-model-button = Боргирӣ кардан
+pdfjs-editor-alt-text-settings-downloading-model-button = Дар ҳоли боргирӣ…
+pdfjs-editor-alt-text-settings-editor-title = Муҳаррири матни иловагӣ
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Дарҳол нишон додани муҳаррири матни ивазкунанда ҳангоми иловакунии тасвир
+pdfjs-editor-alt-text-settings-show-dialog-description = Ба шумо кумак мекунад, ки боварӣ ҳосил кунед, ки ҳамаи тасвирҳои шумо дорои матни ивазкунанда мебошанд.
+pdfjs-editor-alt-text-settings-close-button = Пӯшидан
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Ҷудокунӣ илова карда шуд
+pdfjs-editor-freetext-added-alert = Матн илова карда шуд
+pdfjs-editor-ink-added-alert = Расм илова карда шуд
+pdfjs-editor-stamp-added-alert = Тасвир илова карда шуд
+pdfjs-editor-signature-added-alert = Имзо илова карда шуд
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Ҷудосозӣ тоза карда шуд
+pdfjs-editor-undo-bar-message-freetext = Матн тоза карда шуд
+pdfjs-editor-undo-bar-message-ink = Расм тоза карда шуд
+pdfjs-editor-undo-bar-message-stamp = Тасвир тоза карда шуд
+pdfjs-editor-undo-bar-message-signature = Имзо тоза карда шуд
+pdfjs-editor-undo-bar-message-comment = Шарҳ тоза карда шуд
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } ҳошиянависӣ тоза карда шуд
+ *[other] { $count } ҳошиянависӣ тоза карда шуданд
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Бекор кардан
+pdfjs-editor-undo-bar-undo-button-label = Бекор кардан
+pdfjs-editor-undo-bar-close-button =
+ .title = Пӯшидан
+pdfjs-editor-undo-bar-close-button-label = Пӯшидан
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Ин равзанаи зоҳирӣ ба корбар имкон медиҳад, ки тавонад имзоеро эҷод карда, ба ҳуҷҷати «PDF» илова намояд. Корбар метавонад номро таҳрир кунад (ном, инчунин, ҳамчун матни иловагӣ хизмат мекунад), ва ихтиёран имзоро барои истифодаи такрорӣ нигоҳ медорад.
+pdfjs-editor-add-signature-dialog-title = Илова кардани имзо
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Нависед
+ .title = Нависед
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Имзо гузоред
+ .title = Имзо гузоред
+pdfjs-editor-add-signature-image-button = Тасвир
+ .title = Тасвир
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Имзои худро бо ном нависед
+ .placeholder = Имзои худро бо ном нависед
+pdfjs-editor-add-signature-draw-placeholder = Имзои худро кашида, гузоред
+pdfjs-editor-add-signature-draw-thickness-range-label = Ғафсӣ
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Ғафсии имзо: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Барои бор кардани файл, онро дар ин ҷой кашида, гузоред
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Ё файлҳои тасвириро интихоб кунед
+ *[other] Ё файлҳои тасвириро интихоб кунед
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Тавсиф (матни иловагӣ)
+pdfjs-editor-add-signature-description-input =
+ .title = Тавсиф (матни иловагӣ)
+pdfjs-editor-add-signature-description-default-when-drawing = Имзо
+pdfjs-editor-add-signature-clear-button-label = Пок кардани имзо
+pdfjs-editor-add-signature-clear-button =
+ .title = Пок кардани имзо
+pdfjs-editor-add-signature-save-checkbox = Нигоҳ доштани имзо
+pdfjs-editor-add-signature-save-warning-message = Шумо ба ҳадди 5 имзои нигоҳдошташуда расидед. Барои нигоҳ доштани имзои нав, яке аз имзоҳои нигоҳдошташударо тоза намоед.
+pdfjs-editor-add-signature-image-upload-error-title = Тасвир бор карда нашуд
+pdfjs-editor-add-signature-image-upload-error-description = Пайвастшавии шабакаи худро санҷед ё тасвири дигареро кӯшиш кунед.
+pdfjs-editor-add-signature-image-no-data-error-title = Ин тасвир ба имзо табдил дода нашуд
+pdfjs-editor-add-signature-image-no-data-error-description = Лутфан, кӯшиш кунед, ки тасвири дигареро бор намоед.
+pdfjs-editor-add-signature-error-close-button = Пӯшидан
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Бекор кардан
+pdfjs-editor-add-signature-add-button = Илова кардан
+pdfjs-editor-edit-signature-update-button = Навсозӣ кардан
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Таҳрир кардани шарҳ
+pdfjs-editor-edit-comment-popup-button =
+ .title = Таҳрир кардани шарҳ
+pdfjs-editor-delete-comment-popup-button-label = Тоза кардани шарҳ
+pdfjs-editor-delete-comment-popup-button =
+ .title = Тоза кардани шарҳ
+pdfjs-show-comment-button =
+ .title = Нишон додани шарҳ
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Таҳрир кардани шарҳ
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Навсозӣ кардан
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Илова кардани шарҳ
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Илова кардан
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Нависед…
+pdfjs-editor-edit-comment-dialog-cancel-button = Бекор кардан
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Илова кардани шарҳ
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Фаъол кардани навори ҷонибӣ (ҳуҷҷат дорои тасвирчаҳо/сохтор/замимаҳо/қабатҳо мебошад)
+pdfjs-toggle-views-manager-button1-label = Идоракунии саҳифаҳо
+pdfjs-views-manager-sidebar =
+ .aria-label = Навори ҷонибӣ
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Тағйири андозаи навори ҷонибӣ
+pdfjs-views-manager-view-selector-button =
+ .title = Намудҳо
+pdfjs-views-manager-view-selector-button-label = Намудҳо
+pdfjs-views-manager-pages-title = Саҳифаҳо
+pdfjs-views-manager-attachments-title = Замимаҳо
+pdfjs-views-manager-pages-option-label = Саҳифаҳо
+pdfjs-views-manager-outlines-option-label = Сохтори ҳуҷҷат
+pdfjs-views-manager-attachments-option-label = Замимаҳо
+pdfjs-views-manager-layers-option-label = Қабатҳо
+pdfjs-views-manager-add-file-button =
+ .title = Илова кардани файл
+pdfjs-views-manager-add-file-button-label = Илова кардани файл
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } интихоб шуд
+ *[other] { $count } интихоб шуданд
+ }
+pdfjs-views-manager-pages-status-none-action-label = Саҳифаҳоро интихоб намоед
+pdfjs-views-manager-pages-status-action-button-label = Идора кардан
+pdfjs-views-manager-pages-status-copy-button-label = Нусха бардоштан
+pdfjs-views-manager-pages-status-cut-button-label = Буридан
+pdfjs-views-manager-pages-status-delete-button-label = Нест кардан
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 саҳифа бурида шуд
+ *[other] { $count } саҳифа бурида шуданд
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 саҳифа нусха бардошта шуд
+ *[other] { $count } саҳифа нусха бардошта шуданд
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 саҳифа нест карда шуд
+ *[other] { $count } саҳифа нест карда шуданд
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Файли шумо омода мешавад…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Дар ҳоли боркунии файл…
+pdfjs-views-manager-status-warning-cut-label = Бурида нашуд. Саҳифаро навсозӣ кунед ва аз нав кӯшиш намоед.
+pdfjs-views-manager-status-warning-copy-label = Нусха бардошта нашуд. Саҳифаро навсозӣ кунед ва аз нав кӯшиш намоед.
+pdfjs-views-manager-status-warning-delete-label = Нест карда нашуд. Саҳифаро навсозӣ кунед ва аз нав кӯшиш намоед.
+pdfjs-views-manager-status-warning-save-label = Нигоҳ дошта нашуд. Саҳифаро навсозӣ кунед ва аз нав кӯшиш намоед.
+pdfjs-views-manager-status-undo-button-label = Бекор кардан
+pdfjs-views-manager-status-done-button-label = Тайёр
+pdfjs-views-manager-status-close-button =
+ .title = Пӯшидан
+pdfjs-views-manager-status-close-button-label = Пӯшидан
+pdfjs-views-manager-paste-button-label = Гузоштан
+pdfjs-views-manager-paste-button-before =
+ .title = Гузоштан пеш аз саҳифаи аввалин
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Гузоштан пас аз саҳифаи { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = НАВ
+pdfjs-toggle-views-manager-button1 =
+ .title = Идоракунии саҳифаҳо
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Тоза кардани имзои гузошташуда
+pdfjs-editor-delete-signature-button-label1 = Тоза кардани имзои гузошташуда
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Таҳрир кардани тавсиф
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Таҳрир кардани тавсиф
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/th/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/th/viewer.ftl
new file mode 100644
index 0000000..ccc0034
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/th/viewer.ftl
@@ -0,0 +1,715 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = หน้าก่อนหน้า
+pdfjs-previous-button-label = ก่อนหน้า
+pdfjs-next-button =
+ .title = หน้าถัดไป
+pdfjs-next-button-label = ถัดไป
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = หน้า
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = จาก { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } จาก { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = ซูมออก
+pdfjs-zoom-out-button-label = ซูมออก
+pdfjs-zoom-in-button =
+ .title = ซูมเข้า
+pdfjs-zoom-in-button-label = ซูมเข้า
+pdfjs-zoom-select =
+ .title = ซูม
+pdfjs-presentation-mode-button =
+ .title = สลับเป็นโหมดการนำเสนอ
+pdfjs-presentation-mode-button-label = โหมดการนำเสนอ
+pdfjs-open-file-button =
+ .title = เปิดไฟล์
+pdfjs-open-file-button-label = เปิด
+pdfjs-print-button =
+ .title = พิมพ์
+pdfjs-print-button-label = พิมพ์
+pdfjs-save-button =
+ .title = บันทึก
+pdfjs-save-button-label = บันทึก
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = ดาวน์โหลด
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = ดาวน์โหลด
+pdfjs-bookmark-button =
+ .title = หน้าปัจจุบัน (ดู URL จากหน้าปัจจุบัน)
+pdfjs-bookmark-button-label = หน้าปัจจุบัน
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = เครื่องมือ
+pdfjs-tools-button-label = เครื่องมือ
+pdfjs-first-page-button =
+ .title = ไปยังหน้าแรก
+pdfjs-first-page-button-label = ไปยังหน้าแรก
+pdfjs-last-page-button =
+ .title = ไปยังหน้าสุดท้าย
+pdfjs-last-page-button-label = ไปยังหน้าสุดท้าย
+pdfjs-page-rotate-cw-button =
+ .title = หมุนตามเข็มนาฬิกา
+pdfjs-page-rotate-cw-button-label = หมุนตามเข็มนาฬิกา
+pdfjs-page-rotate-ccw-button =
+ .title = หมุนทวนเข็มนาฬิกา
+pdfjs-page-rotate-ccw-button-label = หมุนทวนเข็มนาฬิกา
+pdfjs-cursor-text-select-tool-button =
+ .title = เปิดใช้งานเครื่องมือการเลือกข้อความ
+pdfjs-cursor-text-select-tool-button-label = เครื่องมือการเลือกข้อความ
+pdfjs-cursor-hand-tool-button =
+ .title = เปิดใช้งานเครื่องมือมือ
+pdfjs-cursor-hand-tool-button-label = เครื่องมือมือ
+pdfjs-scroll-page-button =
+ .title = ใช้การเลื่อนหน้า
+pdfjs-scroll-page-button-label = การเลื่อนหน้า
+pdfjs-scroll-vertical-button =
+ .title = ใช้การเลื่อนแนวตั้ง
+pdfjs-scroll-vertical-button-label = การเลื่อนแนวตั้ง
+pdfjs-scroll-horizontal-button =
+ .title = ใช้การเลื่อนแนวนอน
+pdfjs-scroll-horizontal-button-label = การเลื่อนแนวนอน
+pdfjs-scroll-wrapped-button =
+ .title = ใช้การเลื่อนแบบคลุม
+pdfjs-scroll-wrapped-button-label = เลื่อนแบบคลุม
+pdfjs-spread-none-button =
+ .title = ไม่ต้องรวมการกระจายหน้า
+pdfjs-spread-none-button-label = ไม่กระจาย
+pdfjs-spread-odd-button =
+ .title = รวมการกระจายหน้าเริ่มจากหน้าคี่
+pdfjs-spread-odd-button-label = กระจายอย่างเหลือเศษ
+pdfjs-spread-even-button =
+ .title = รวมการกระจายหน้าเริ่มจากหน้าคู่
+pdfjs-spread-even-button-label = กระจายอย่างเท่าเทียม
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = คุณสมบัติเอกสาร…
+pdfjs-document-properties-button-label = คุณสมบัติเอกสาร…
+pdfjs-document-properties-file-name = ชื่อไฟล์:
+pdfjs-document-properties-file-size = ขนาดไฟล์:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } ไบต์)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } ไบต์)
+pdfjs-document-properties-title = ชื่อเรื่อง:
+pdfjs-document-properties-author = ผู้สร้าง:
+pdfjs-document-properties-subject = ชื่อเรื่อง:
+pdfjs-document-properties-keywords = คำสำคัญ:
+pdfjs-document-properties-creation-date = วันที่สร้าง:
+pdfjs-document-properties-modification-date = วันที่แก้ไข:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = ผู้สร้าง:
+pdfjs-document-properties-producer = ผู้ผลิต PDF:
+pdfjs-document-properties-version = รุ่น PDF:
+pdfjs-document-properties-page-count = จำนวนหน้า:
+pdfjs-document-properties-page-size = ขนาดหน้า:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = แนวตั้ง
+pdfjs-document-properties-page-size-orientation-landscape = แนวนอน
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = จดหมาย
+pdfjs-document-properties-page-size-name-legal = ข้อกฎหมาย
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = มุมมองเว็บแบบรวดเร็ว:
+pdfjs-document-properties-linearized-yes = ใช่
+pdfjs-document-properties-linearized-no = ไม่
+pdfjs-document-properties-close-button = ปิด
+
+## Print
+
+pdfjs-print-progress-message = กำลังเตรียมเอกสารสำหรับการพิมพ์…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = ยกเลิก
+pdfjs-printing-not-supported = คำเตือน: เบราว์เซอร์นี้ไม่ได้สนับสนุนการพิมพ์อย่างเต็มที่
+pdfjs-printing-not-ready = คำเตือน: PDF ไม่ได้รับการโหลดอย่างเต็มที่สำหรับการพิมพ์
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = เปิด/ปิดแถบข้าง
+pdfjs-toggle-sidebar-notification-button =
+ .title = เปิด/ปิดแถบข้าง (เอกสารมีเค้าร่าง/ไฟล์แนบ/เลเยอร์)
+pdfjs-toggle-sidebar-button-label = เปิด/ปิดแถบข้าง
+pdfjs-document-outline-button =
+ .title = แสดงเค้าร่างเอกสาร (คลิกสองครั้งเพื่อขยาย/ยุบรายการทั้งหมด)
+pdfjs-document-outline-button-label = เค้าร่างเอกสาร
+pdfjs-attachments-button =
+ .title = แสดงไฟล์แนบ
+pdfjs-attachments-button-label = ไฟล์แนบ
+pdfjs-layers-button =
+ .title = แสดงเลเยอร์ (คลิกสองครั้งเพื่อรีเซ็ตเลเยอร์ทั้งหมดเป็นสถานะเริ่มต้น)
+pdfjs-layers-button-label = เลเยอร์
+pdfjs-thumbs-button =
+ .title = แสดงภาพขนาดย่อ
+pdfjs-thumbs-button-label = ภาพขนาดย่อ
+pdfjs-current-outline-item-button =
+ .title = ค้นหารายการเค้าร่างปัจจุบัน
+pdfjs-current-outline-item-button-label = รายการเค้าร่างปัจจุบัน
+pdfjs-findbar-button =
+ .title = ค้นหาในเอกสาร
+pdfjs-findbar-button-label = ค้นหา
+pdfjs-additional-layers = เลเยอร์เพิ่มเติม
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = หน้า { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = ภาพขนาดย่อของหน้า { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = เลือกหน้า { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = หน้า { $page } จาก { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ค้นหา
+ .placeholder = ค้นหาในเอกสาร…
+pdfjs-find-previous-button =
+ .title = หาตำแหน่งก่อนหน้าของวลี
+pdfjs-find-previous-button-label = ก่อนหน้า
+pdfjs-find-next-button =
+ .title = หาตำแหน่งถัดไปของวลี
+pdfjs-find-next-button-label = ถัดไป
+pdfjs-find-highlight-checkbox = เน้นสีทั้งหมด
+pdfjs-find-match-case-checkbox-label = ตัวพิมพ์ใหญ่เล็กตรงกัน
+pdfjs-find-match-diacritics-checkbox-label = เครื่องหมายกำกับการออกเสียงตรงกัน
+pdfjs-find-entire-word-checkbox-label = ทั้งคำ
+pdfjs-find-reached-top = ค้นหาถึงจุดเริ่มต้นของหน้า เริ่มค้นต่อจากด้านล่าง
+pdfjs-find-reached-bottom = ค้นหาถึงจุดสิ้นสุดหน้า เริ่มค้นต่อจากด้านบน
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = { $current } จาก { $total } รายการที่ตรงกัน
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = มากกว่า { $limit } รายการที่ตรงกัน
+pdfjs-find-not-found = ไม่พบวลี
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = ความกว้างหน้า
+pdfjs-page-scale-fit = พอดีหน้า
+pdfjs-page-scale-auto = ซูมอัตโนมัติ
+pdfjs-page-scale-actual = ขนาดจริง
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = หน้า { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = เกิดข้อผิดพลาดขณะโหลด PDF
+pdfjs-invalid-file-error = ไฟล์ PDF ไม่ถูกต้องหรือเสียหาย
+pdfjs-missing-file-error = ไฟล์ PDF หายไป
+pdfjs-unexpected-response-error = การตอบสนองของเซิร์ฟเวอร์ที่ไม่คาดคิด
+pdfjs-rendering-error = เกิดข้อผิดพลาดขณะเรนเดอร์หน้า
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [คำอธิบายประกอบ { $type }]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = ป้อนรหัสผ่านเพื่อเปิดไฟล์ PDF นี้
+pdfjs-password-invalid = รหัสผ่านไม่ถูกต้อง โปรดลองอีกครั้ง
+pdfjs-password-ok-button = ตกลง
+pdfjs-password-cancel-button = ยกเลิก
+pdfjs-web-fonts-disabled = แบบอักษรเว็บถูกปิดใช้งาน: ไม่สามารถใช้แบบอักษร PDF ฝังตัว
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = ข้อความ
+pdfjs-editor-color-picker-free-text-input =
+ .title = เปลี่ยนสีข้อความ
+pdfjs-editor-free-text-button-label = ข้อความ
+pdfjs-editor-ink-button =
+ .title = รูปวาด
+pdfjs-editor-color-picker-ink-input =
+ .title = เปลี่ยนสีรูปวาด
+pdfjs-editor-ink-button-label = รูปวาด
+pdfjs-editor-stamp-button =
+ .title = เพิ่มหรือแก้ไขภาพ
+pdfjs-editor-stamp-button-label = เพิ่มหรือแก้ไขภาพ
+pdfjs-editor-highlight-button =
+ .title = เน้น
+pdfjs-editor-highlight-button-label = เน้น
+pdfjs-highlight-floating-button1 =
+ .title = เน้นสี
+ .aria-label = เน้นสี
+pdfjs-highlight-floating-button-label = เน้นสี
+pdfjs-comment-floating-button =
+ .title = แสดงความคิดเห็น
+ .aria-label = แสดงความคิดเห็น
+pdfjs-comment-floating-button-label = แสดงความคิดเห็น
+pdfjs-editor-comment-button =
+ .title = แสดงความคิดเห็น
+ .aria-label = แสดงความคิดเห็น
+pdfjs-editor-comment-button-label = ความคิดเห็น
+pdfjs-editor-signature-button =
+ .title = เพิ่มลายเซ็น
+pdfjs-editor-signature-button-label = เพิ่มลายเซ็น
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = ตัวแก้ไขสีเน้น
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = ตัวแก้ไขรูปวาด
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = ตัวแก้ไขลายเซ็น: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = ตัวแก้ไขภาพ
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = เอาภาพวาดออก
+pdfjs-editor-remove-freetext-button =
+ .title = เอาข้อความออก
+pdfjs-editor-remove-stamp-button =
+ .title = เอาภาพออก
+pdfjs-editor-remove-highlight-button =
+ .title = เอาการเน้นสีออก
+pdfjs-editor-remove-signature-button =
+ .title = ลบลายเซ็น
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = สี
+pdfjs-editor-free-text-size-input = ขนาด
+pdfjs-editor-ink-color-input = สี
+pdfjs-editor-ink-thickness-input = ความหนา
+pdfjs-editor-ink-opacity-input = ความทึบ
+pdfjs-editor-stamp-add-image-button =
+ .title = เพิ่มภาพ
+pdfjs-editor-stamp-add-image-button-label = เพิ่มภาพ
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = ความหนา
+pdfjs-editor-free-highlight-thickness-title =
+ .title = เปลี่ยนความหนาเมื่อเน้นรายการอื่นๆ ที่ไม่ใช่ข้อความ
+pdfjs-editor-add-signature-container =
+ .aria-label = ส่วนควบคุมลายเซ็นและลายเซ็นที่บันทึกไว้
+pdfjs-editor-signature-add-signature-button =
+ .title = เพิ่มลายเซ็นใหม่
+pdfjs-editor-signature-add-signature-button-label = เพิ่มลายเซ็นใหม่
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = ลายเซ็นที่บันทึกไว้: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = ตัวแก้ไขข้อความ
+ .default-content = เริ่มพิมพ์ได้เลย…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title = ความคิดเห็น
+pdfjs-editor-comments-sidebar-close-button =
+ .title = ปิดแถบข้าง
+ .aria-label = ปิดแถบข้าง
+pdfjs-editor-comments-sidebar-close-button-label = ปิดแถบข้าง
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = เห็นอะไรที่น่าสนใจใช่ไหม? เน้นสีไว้และแสดงความคิดเห็นได้เลย
+pdfjs-editor-comments-sidebar-no-comments-link = เรียนรู้เพิ่มเติม
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = ข้อความทดแทน
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = แก้ไขข้อความทดแทน
+pdfjs-editor-alt-text-dialog-label = เลือกตัวเลือก
+pdfjs-editor-alt-text-dialog-description = ข้อความทดแทนสามารถช่วยเหลือได้เมื่อผู้ใช้มองไม่เห็นภาพ หรือภาพไม่โหลด
+pdfjs-editor-alt-text-add-description-label = เพิ่มคำอธิบาย
+pdfjs-editor-alt-text-add-description-description = แนะนำให้ใช้ 1-2 ประโยคซึ่งอธิบายหัวเรื่อง ฉาก หรือการกระทำ
+pdfjs-editor-alt-text-mark-decorative-label = ทำเครื่องหมายเป็นสิ่งตกแต่ง
+pdfjs-editor-alt-text-mark-decorative-description = สิ่งนี้ใช้สำหรับภาพที่เป็นสิ่งประดับ เช่น ขอบ หรือลายน้ำ
+pdfjs-editor-alt-text-cancel-button = ยกเลิก
+pdfjs-editor-alt-text-save-button = บันทึก
+pdfjs-editor-alt-text-decorative-tooltip = ทำเครื่องหมายเป็นสิ่งตกแต่งแล้ว
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = ตัวอย่างเช่น “ชายหนุ่มคนหนึ่งนั่งลงที่โต๊ะเพื่อรับประทานอาหารมื้อหนึ่ง”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = ข้อความทดแทน
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = มุมซ้ายบน — ปรับขนาด
+pdfjs-editor-resizer-top-middle =
+ .aria-label = ตรงกลางด้านบน — ปรับขนาด
+pdfjs-editor-resizer-top-right =
+ .aria-label = มุมขวาบน — ปรับขนาด
+pdfjs-editor-resizer-middle-right =
+ .aria-label = ตรงกลางด้านขวา — ปรับขนาด
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = มุมขวาล่าง — ปรับขนาด
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = ตรงกลางด้านล่าง — ปรับขนาด
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = มุมซ้ายล่าง — ปรับขนาด
+pdfjs-editor-resizer-middle-left =
+ .aria-label = ตรงกลางด้านซ้าย — ปรับขนาด
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = สีเน้น
+pdfjs-editor-colorpicker-button =
+ .title = เปลี่ยนสี
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = ทางเลือกสี
+pdfjs-editor-colorpicker-yellow =
+ .title = เหลือง
+pdfjs-editor-colorpicker-green =
+ .title = เขียว
+pdfjs-editor-colorpicker-blue =
+ .title = น้ำเงิน
+pdfjs-editor-colorpicker-pink =
+ .title = ชมพู
+pdfjs-editor-colorpicker-red =
+ .title = แดง
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = แสดงทั้งหมด
+pdfjs-editor-highlight-show-all-button =
+ .title = แสดงทั้งหมด
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = แก้ไขข้อความทดแทน (คำอธิบายภาพ)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = เพิ่มข้อความทดแทน (คำอธิบายภาพ)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = เขียนคำอธิบายของคุณที่นี่…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = คำอธิบายสั้นๆ สำหรับผู้ที่ไม่สามารถมองเห็นภาพหรือเมื่อภาพไม่โหลด
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = ข้อความทดแทนนี้ถูกสร้างขึ้นโดยอัตโนมัติและอาจไม่ถูกต้อง
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = เรียนรู้เพิ่มเติม
+pdfjs-editor-new-alt-text-create-automatically-button-label = สร้างข้อความทดแทนโดยอัตโนมัติ
+pdfjs-editor-new-alt-text-not-now-button = ไม่ใช่ตอนนี้
+pdfjs-editor-new-alt-text-error-title = ไม่สามารถสร้างข้อความทดแทนโดยอัตโนมัติได้
+pdfjs-editor-new-alt-text-error-description = กรุณาเขียนข้อความทดแทนด้วยตัวเองหรือลองใหม่อีกครั้งในภายหลัง
+pdfjs-editor-new-alt-text-error-close-button = ปิด
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = กำลังดาวน์โหลดโมเดล AI สำหรับข้อความทดแทน ({ $downloadedSize } จาก { $totalSize } MB)
+ .aria-valuetext = กำลังดาวน์โหลดโมเดล AI สำหรับข้อความทดแทน ({ $downloadedSize } จาก { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = เพิ่มข้อความทดแทนแล้ว
+pdfjs-editor-new-alt-text-added-button-label = เพิ่มข้อความทดแทนแล้ว
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = ขาดข้อความทดแทน
+pdfjs-editor-new-alt-text-missing-button-label = ขาดข้อความทดแทน
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = ตรวจสอบข้อความทดแทน
+pdfjs-editor-new-alt-text-to-review-button-label = ตรวจสอบข้อความทดแทน
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = สร้างขึ้นโดยอัตโนมัติ: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = ตั้งค่าข้อความทดแทนภาพ
+pdfjs-image-alt-text-settings-button-label = ตั้งค่าข้อความทดแทนภาพ
+pdfjs-editor-alt-text-settings-dialog-label = ตั้งค่าข้อความทดแทนภาพ
+pdfjs-editor-alt-text-settings-automatic-title = การทดแทนด้วยข้อความอัตโนมัติ
+pdfjs-editor-alt-text-settings-create-model-button-label = สร้างข้อความทดแทนอัตโนมัติ
+pdfjs-editor-alt-text-settings-create-model-description = แนะนำคำอธิบายเพื่อช่วยเหลือผู้ที่ไม่สามารถมองเห็นภาพหรือเมื่อภาพไม่โหลด
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = โมเดล AI สำหรับข้อความทดแทน ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = ทำงานในเครื่องของคุณเพื่อให้ข้อมูลของคุณเป็นส่วนตัว จำเป็นสำหรับข้อความทดแทนอัตโนมัติ
+pdfjs-editor-alt-text-settings-delete-model-button = ลบ
+pdfjs-editor-alt-text-settings-download-model-button = ดาวน์โหลด
+pdfjs-editor-alt-text-settings-downloading-model-button = กำลังดาวน์โหลด…
+pdfjs-editor-alt-text-settings-editor-title = ตัวแก้ไขข้อความทดแทน
+pdfjs-editor-alt-text-settings-show-dialog-button-label = แสดงตัวแก้ไขข้อความทดแทนทันทีเมื่อเพิ่มภาพ
+pdfjs-editor-alt-text-settings-show-dialog-description = ช่วยให้คุณแน่ใจว่าภาพทั้งหมดของคุณมีข้อความทดแทน
+pdfjs-editor-alt-text-settings-close-button = ปิด
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = เพิ่มการเน้นสีแล้ว
+pdfjs-editor-freetext-added-alert = เพิ่มข้อความแล้ว
+pdfjs-editor-ink-added-alert = เพิ่มรูปวาดแล้ว
+pdfjs-editor-stamp-added-alert = เพิ่มภาพแล้ว
+pdfjs-editor-signature-added-alert = เพิ่มลายเซ็นแล้ว
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = เอาการเน้นสีออกแล้ว
+pdfjs-editor-undo-bar-message-freetext = เอาข้อความออกแล้ว
+pdfjs-editor-undo-bar-message-ink = เอาภาพวาดออกแล้ว
+pdfjs-editor-undo-bar-message-stamp = เอาภาพออกแล้ว
+pdfjs-editor-undo-bar-message-signature = ลบลายเซ็นแล้ว
+pdfjs-editor-undo-bar-message-comment = เอาความคิดเห็นออกแล้ว
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = เอาคำอธิบายประกอบ { $count } รายการออกแล้ว
+pdfjs-editor-undo-bar-undo-button =
+ .title = เลิกทำ
+pdfjs-editor-undo-bar-undo-button-label = เลิกทำ
+pdfjs-editor-undo-bar-close-button =
+ .title = ปิด
+pdfjs-editor-undo-bar-close-button-label = ปิด
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = โมดัลนี้ช่วยให้ผู้ใช้สามารถสร้างลายเซ็นเพื่อใช้เพิ่มลงในเอกสาร PDF ได้ ผู้ใช้สามารถแก้ไขชื่อ (ซึ่งใช้เป็นข้อความทดแทนได้ด้วย) และสามารถเลือกบันทึกลายเซ็นเพื่อใช้งานซ้ำได้
+pdfjs-editor-add-signature-dialog-title = เพิ่มลายเซ็น
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = พิมพ์
+ .title = พิมพ์
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = วาด
+ .title = วาด
+pdfjs-editor-add-signature-image-button = ภาพ
+ .title = ภาพ
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = พิมพ์ลายเซ็นของคุณ
+ .placeholder = พิมพ์ลายเซ็นของคุณ
+pdfjs-editor-add-signature-draw-placeholder = วาดลายเซ็นของคุณ
+pdfjs-editor-add-signature-draw-thickness-range-label = ความหนา
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = ความหนาของการวาด: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = ลากไฟล์มาที่นี่เพื่ออัปโหลด
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] หรือเลือกไฟล์ภาพ
+ *[other] หรือเรียกดูไฟล์ภาพ
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = คำอธิบาย (ข้อความทดแทน)
+pdfjs-editor-add-signature-description-input =
+ .title = คำอธิบาย (ข้อความทดแทน)
+pdfjs-editor-add-signature-description-default-when-drawing = ลายเซ็น
+pdfjs-editor-add-signature-clear-button-label = ล้างลายเซ็น
+pdfjs-editor-add-signature-clear-button =
+ .title = ล้างลายเซ็น
+pdfjs-editor-add-signature-save-checkbox = บันทึกลายเซ็น
+pdfjs-editor-add-signature-save-warning-message = คุณมีลายเซ็นที่บันทึกถึงจำนวนสูงสุด 5 รายการแล้ว โปรดลบรายการหนึ่งออกเมื่อจะบันทึกเพิ่ม
+pdfjs-editor-add-signature-image-upload-error-title = ไม่สามารถอัปโหลดภาพได้
+pdfjs-editor-add-signature-image-upload-error-description = ตรวจสอบการเชื่อมต่อเครือข่ายของคุณหรือลองใช้ภาพอื่น
+pdfjs-editor-add-signature-image-no-data-error-title = ไม่สามารถแปลงภาพนี้ให้เป็นลายเซ็นได้
+pdfjs-editor-add-signature-image-no-data-error-description = โปรดลองอัปโหลดภาพอื่น
+pdfjs-editor-add-signature-error-close-button = ปิด
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = ยกเลิก
+pdfjs-editor-add-signature-add-button = เพิ่ม
+pdfjs-editor-edit-signature-update-button = อัปเดต
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = แก้ไขความคิดเห็น
+pdfjs-editor-edit-comment-popup-button =
+ .title = แก้ไขความคิดเห็น
+pdfjs-editor-delete-comment-popup-button-label = เอาความคิดเห็นออก
+pdfjs-editor-delete-comment-popup-button =
+ .title = เอาความคิดเห็นออก
+pdfjs-show-comment-button =
+ .title = แสดงความคิดเห็น
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = แก้ไขความคิดเห็น
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = อัปเดต
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = เพิ่มความคิดเห็น
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = เพิ่ม
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = เริ่มพิมพ์…
+pdfjs-editor-edit-comment-dialog-cancel-button = ยกเลิก
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = เพิ่มความคิดเห็น
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = เปิด/ปิดแถบข้าง (เอกสารมีภาพย่อ/เค้าร่าง/ไฟล์แนบ/เลเยอร์)
+pdfjs-toggle-views-manager-button1-label = จัดการหน้า
+pdfjs-views-manager-sidebar =
+ .aria-label = แถบข้าง
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = ตัวปรับขนาดแถบข้าง
+pdfjs-views-manager-view-selector-button =
+ .title = มุมมอง
+pdfjs-views-manager-view-selector-button-label = มุมมอง
+pdfjs-views-manager-pages-title = หน้า
+pdfjs-views-manager-outlines-title1 = โครงร่างเอกสาร
+ .title = โครงร่างเอกสาร (คลิกสองครั้งเพื่อขยาย/ยุบรายการทั้งหมด)
+pdfjs-views-manager-attachments-title = ไฟล์แนบ
+pdfjs-views-manager-layers-title1 = เลเยอร์
+ .title = เลเยอร์ (คลิกสองครั้งเพื่อล้างค่าเลเยอร์ทั้งหมดกลับสู่สถานะเริ่มต้น)
+pdfjs-views-manager-pages-option-label = หน้า
+pdfjs-views-manager-outlines-option-label = เค้าร่างเอกสาร
+pdfjs-views-manager-attachments-option-label = ไฟล์แนบ
+pdfjs-views-manager-layers-option-label = เลเยอร์
+pdfjs-views-manager-add-file-button =
+ .title = เพิ่มไฟล์
+pdfjs-views-manager-add-file-button-label = เพิ่มไฟล์
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label = เลือกอยู่ { $count }
+pdfjs-views-manager-pages-status-none-action-label = เลือกหน้า
+pdfjs-views-manager-pages-status-action-button-label = จัดการ
+pdfjs-views-manager-pages-status-copy-button-label = คัดลอก
+pdfjs-views-manager-pages-status-cut-button-label = ตัด
+pdfjs-views-manager-pages-status-delete-button-label = ลบ
+pdfjs-views-manager-pages-status-export-selected-button-label = ส่งออกรายการที่เลือก…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label = ตัด { $count } หน้าแล้ว
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label = คัดลอก { $count } หน้าแล้ว
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label = ลบ { $count } หน้าแล้ว
+pdfjs-views-manager-pages-status-waiting-ready-label = กำลังเตรียมไฟล์ของคุณให้พร้อม…
+pdfjs-views-manager-pages-status-waiting-uploading-label = กำลังอัปโหลดไฟล์…
+pdfjs-views-manager-status-warning-cut-label = ไม่สามารถตัดได้ โปรดรีเฟรชหน้าแล้วลองอีกครั้ง
+pdfjs-views-manager-status-warning-copy-label = ไม่สามารถคัดลอกได้ โปรดรีเฟรชหน้าแล้วลองอีกครั้ง
+pdfjs-views-manager-status-warning-delete-label = ไม่สามารถลบได้ โปรดรีเฟรชหน้าแล้วลองอีกครั้ง
+pdfjs-views-manager-status-warning-save-label = ไม่สามารถบันทึกได้ โปรดรีเฟรชหน้าแล้วลองอีกครั้ง
+pdfjs-views-manager-status-undo-button-label = เลิกทำ
+pdfjs-views-manager-status-done-button-label = เสร็จสิ้น
+pdfjs-views-manager-status-close-button =
+ .title = ปิด
+pdfjs-views-manager-status-close-button-label = ปิด
+pdfjs-views-manager-paste-button-label = วาง
+pdfjs-views-manager-paste-button-before =
+ .title = วางก่อนหน้าแรก
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = วางหลังหน้า { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = ใหม่
+pdfjs-views-manager-waiting-for-file = กำลังอัปโหลดไฟล์…
+pdfjs-toggle-views-manager-button1 =
+ .title = จัดการหน้า
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = ลบลายเซ็นที่บันทึกไว้
+pdfjs-editor-delete-signature-button-label1 = ลบลายเซ็นที่บันทึกไว้
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = แก้ไขคำอธิบาย
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = แก้ไขคำอธิบาย
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tl/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tl/viewer.ftl
new file mode 100644
index 0000000..628ef97
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tl/viewer.ftl
@@ -0,0 +1,228 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Naunang Pahina
+pdfjs-previous-button-label = Nakaraan
+pdfjs-next-button =
+ .title = Sunod na Pahina
+pdfjs-next-button-label = Sunod
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Pahina
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = ng { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } ng { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Paliitin
+pdfjs-zoom-out-button-label = Paliitin
+pdfjs-zoom-in-button =
+ .title = Palakihin
+pdfjs-zoom-in-button-label = Palakihin
+pdfjs-zoom-select =
+ .title = Mag-zoom
+pdfjs-presentation-mode-button =
+ .title = Lumipat sa Presentation Mode
+pdfjs-presentation-mode-button-label = Presentation Mode
+pdfjs-open-file-button =
+ .title = Magbukas ng file
+pdfjs-open-file-button-label = Buksan
+pdfjs-print-button =
+ .title = i-Print
+pdfjs-print-button-label = i-Print
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Mga Kagamitan
+pdfjs-tools-button-label = Mga Kagamitan
+pdfjs-first-page-button =
+ .title = Pumunta sa Unang Pahina
+pdfjs-first-page-button-label = Pumunta sa Unang Pahina
+pdfjs-last-page-button =
+ .title = Pumunta sa Huling Pahina
+pdfjs-last-page-button-label = Pumunta sa Huling Pahina
+pdfjs-page-rotate-cw-button =
+ .title = Paikutin Pakanan
+pdfjs-page-rotate-cw-button-label = Paikutin Pakanan
+pdfjs-page-rotate-ccw-button =
+ .title = Paikutin Pakaliwa
+pdfjs-page-rotate-ccw-button-label = Paikutin Pakaliwa
+pdfjs-cursor-text-select-tool-button =
+ .title = I-enable ang Text Selection Tool
+pdfjs-cursor-text-select-tool-button-label = Text Selection Tool
+pdfjs-cursor-hand-tool-button =
+ .title = I-enable ang Hand Tool
+pdfjs-cursor-hand-tool-button-label = Hand Tool
+pdfjs-scroll-vertical-button =
+ .title = Gumamit ng Vertical Scrolling
+pdfjs-scroll-vertical-button-label = Vertical Scrolling
+pdfjs-scroll-horizontal-button =
+ .title = Gumamit ng Horizontal Scrolling
+pdfjs-scroll-horizontal-button-label = Horizontal Scrolling
+pdfjs-scroll-wrapped-button =
+ .title = Gumamit ng Wrapped Scrolling
+pdfjs-scroll-wrapped-button-label = Wrapped Scrolling
+pdfjs-spread-none-button =
+ .title = Huwag pagsamahin ang mga page spread
+pdfjs-spread-none-button-label = No Spreads
+pdfjs-spread-odd-button =
+ .title = Join page spreads starting with odd-numbered pages
+pdfjs-spread-odd-button-label = Mga Odd Spread
+pdfjs-spread-even-button =
+ .title = Pagsamahin ang mga page spread na nagsisimula sa mga even-numbered na pahina
+pdfjs-spread-even-button-label = Mga Even Spread
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Mga Katangian ng Dokumento…
+pdfjs-document-properties-button-label = Mga Katangian ng Dokumento…
+pdfjs-document-properties-file-name = File name:
+pdfjs-document-properties-file-size = File size:
+pdfjs-document-properties-title = Pamagat:
+pdfjs-document-properties-author = May-akda:
+pdfjs-document-properties-subject = Paksa:
+pdfjs-document-properties-keywords = Mga keyword:
+pdfjs-document-properties-creation-date = Petsa ng Pagkakagawa:
+pdfjs-document-properties-modification-date = Petsa ng Pagkakabago:
+pdfjs-document-properties-creator = Tagalikha:
+pdfjs-document-properties-producer = PDF Producer:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Bilang ng Pahina:
+pdfjs-document-properties-page-size = Laki ng Pahina:
+pdfjs-document-properties-page-size-unit-inches = pulgada
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = patayo
+pdfjs-document-properties-page-size-orientation-landscape = pahiga
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Fast Web View:
+pdfjs-document-properties-linearized-yes = Oo
+pdfjs-document-properties-linearized-no = Hindi
+pdfjs-document-properties-close-button = Isara
+
+## Print
+
+pdfjs-print-progress-message = Inihahanda ang dokumento para sa pag-print…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Kanselahin
+pdfjs-printing-not-supported = Babala: Hindi pa ganap na suportado ang pag-print sa browser na ito.
+pdfjs-printing-not-ready = Babala: Hindi ganap na nabuksan ang PDF para sa pag-print.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Ipakita/Itago ang Sidebar
+pdfjs-toggle-sidebar-notification-button =
+ .title = Ipakita/Itago ang Sidebar (nagtataglay ang dokumento ng balangkas/mga attachment/mga layer)
+pdfjs-toggle-sidebar-button-label = Ipakita/Itago ang Sidebar
+pdfjs-document-outline-button =
+ .title = Ipakita ang Document Outline (mag-double-click para i-expand/collapse ang laman)
+pdfjs-document-outline-button-label = Balangkas ng Dokumento
+pdfjs-attachments-button =
+ .title = Ipakita ang mga Attachment
+pdfjs-attachments-button-label = Mga attachment
+pdfjs-layers-button =
+ .title = Ipakita ang mga Layer (mag-double click para mareset ang lahat ng layer sa orihinal na estado)
+pdfjs-layers-button-label = Mga layer
+pdfjs-thumbs-button =
+ .title = Ipakita ang mga Thumbnail
+pdfjs-thumbs-button-label = Mga thumbnail
+pdfjs-findbar-button =
+ .title = Hanapin sa Dokumento
+pdfjs-findbar-button-label = Hanapin
+pdfjs-additional-layers = Mga Karagdagang Layer
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Pahina { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Thumbnail ng Pahina { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Hanapin
+ .placeholder = Hanapin sa dokumento…
+pdfjs-find-previous-button =
+ .title = Hanapin ang nakaraang pangyayari ng parirala
+pdfjs-find-previous-button-label = Nakaraan
+pdfjs-find-next-button =
+ .title = Hanapin ang susunod na pangyayari ng parirala
+pdfjs-find-next-button-label = Susunod
+pdfjs-find-highlight-checkbox = I-highlight lahat
+pdfjs-find-match-case-checkbox-label = Itugma ang case
+pdfjs-find-entire-word-checkbox-label = Buong salita
+pdfjs-find-reached-top = Naabot na ang tuktok ng dokumento, ipinagpatuloy mula sa ilalim
+pdfjs-find-reached-bottom = Naabot na ang dulo ng dokumento, ipinagpatuloy mula sa tuktok
+pdfjs-find-not-found = Hindi natagpuan ang parirala
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Lapad ng Pahina
+pdfjs-page-scale-fit = Pagkasyahin ang Pahina
+pdfjs-page-scale-auto = Automatic Zoom
+pdfjs-page-scale-actual = Totoong sukat
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Nagkaproblema habang niloload ang PDF.
+pdfjs-invalid-file-error = Di-wasto o sira ang PDF file.
+pdfjs-missing-file-error = Nawawalang PDF file.
+pdfjs-unexpected-response-error = Hindi inaasahang tugon ng server.
+pdfjs-rendering-error = Nagkaproblema habang nirerender ang pahina.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = Ipasok ang password upang buksan ang PDF file na ito.
+pdfjs-password-invalid = Maling password. Subukan uli.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Kanselahin
+pdfjs-web-fonts-disabled = Naka-disable ang mga Web font: hindi kayang gamitin ang mga naka-embed na PDF font.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tr/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tr/viewer.ftl
new file mode 100644
index 0000000..a735e08
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/tr/viewer.ftl
@@ -0,0 +1,836 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Önceki sayfa
+pdfjs-previous-button-label = Önceki
+pdfjs-next-button =
+ .title = Sonraki sayfa
+pdfjs-next-button-label = Sonraki
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Sayfa
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Uzaklaştır
+pdfjs-zoom-out-button-label = Uzaklaştır
+pdfjs-zoom-in-button =
+ .title = Yakınlaştır
+pdfjs-zoom-in-button-label = Yakınlaştır
+pdfjs-zoom-select =
+ .title = Yakınlaştırma
+pdfjs-presentation-mode-button =
+ .title = Sunum moduna geç
+pdfjs-presentation-mode-button-label = Sunum modu
+pdfjs-open-file-button =
+ .title = Dosya aç
+pdfjs-open-file-button-label = Aç
+pdfjs-print-button =
+ .title = Yazdır
+pdfjs-print-button-label = Yazdır
+pdfjs-save-button =
+ .title = Kaydet
+pdfjs-save-button-label = Kaydet
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = İndir
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = İndir
+pdfjs-bookmark-button =
+ .title = Geçerli sayfa (geçerli sayfanın adresini görüntüle)
+pdfjs-bookmark-button-label = Geçerli sayfa
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Araçlar
+pdfjs-tools-button-label = Araçlar
+pdfjs-first-page-button =
+ .title = İlk sayfaya git
+pdfjs-first-page-button-label = İlk sayfaya git
+pdfjs-last-page-button =
+ .title = Son sayfaya git
+pdfjs-last-page-button-label = Son sayfaya git
+pdfjs-page-rotate-cw-button =
+ .title = Saat yönünde döndür
+pdfjs-page-rotate-cw-button-label = Saat yönünde döndür
+pdfjs-page-rotate-ccw-button =
+ .title = Saat yönünün tersine döndür
+pdfjs-page-rotate-ccw-button-label = Saat yönünün tersine döndür
+pdfjs-cursor-text-select-tool-button =
+ .title = Metin seçme aracını etkinleştir
+pdfjs-cursor-text-select-tool-button-label = Metin seçme aracı
+pdfjs-cursor-hand-tool-button =
+ .title = El aracını etkinleştir
+pdfjs-cursor-hand-tool-button-label = El aracı
+pdfjs-scroll-page-button =
+ .title = Sayfa kaydırmayı kullan
+pdfjs-scroll-page-button-label = Sayfa kaydırma
+pdfjs-scroll-vertical-button =
+ .title = Dikey kaydırmayı kullan
+pdfjs-scroll-vertical-button-label = Dikey kaydırma
+pdfjs-scroll-horizontal-button =
+ .title = Yatay kaydırmayı kullan
+pdfjs-scroll-horizontal-button-label = Yatay kaydırma
+pdfjs-scroll-wrapped-button =
+ .title = Yan yana kaydırmayı kullan
+pdfjs-scroll-wrapped-button-label = Yan yana kaydırma
+pdfjs-spread-none-button =
+ .title = Yan yana sayfaları birleştirme
+pdfjs-spread-none-button-label = Birleştirme
+pdfjs-spread-odd-button =
+ .title = Yan yana sayfaları tek numaralı sayfalardan başlayarak birleştir
+pdfjs-spread-odd-button-label = Tek numaralı
+pdfjs-spread-even-button =
+ .title = Yan yana sayfaları çift numaralı sayfalardan başlayarak birleştir
+pdfjs-spread-even-button-label = Çift numaralı
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Belge özellikleri…
+pdfjs-document-properties-button-label = Belge özellikleri…
+pdfjs-document-properties-file-name = Dosya adı:
+pdfjs-document-properties-file-size = Dosya boyutu:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bayt)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bayt)
+pdfjs-document-properties-title = Başlık:
+pdfjs-document-properties-author = Yazar:
+pdfjs-document-properties-subject = Konu:
+pdfjs-document-properties-keywords = Anahtar kelimeler:
+pdfjs-document-properties-creation-date = Oluşturma tarihi:
+pdfjs-document-properties-modification-date = Değiştirme tarihi:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Oluşturan:
+pdfjs-document-properties-producer = PDF üreticisi:
+pdfjs-document-properties-version = PDF sürümü:
+pdfjs-document-properties-page-count = Sayfa sayısı:
+pdfjs-document-properties-page-size = Sayfa boyutu:
+pdfjs-document-properties-page-size-unit-inches = inç
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = dikey
+pdfjs-document-properties-page-size-orientation-landscape = yatay
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Hızlı web görünümü:
+pdfjs-document-properties-linearized-yes = Evet
+pdfjs-document-properties-linearized-no = Hayır
+pdfjs-document-properties-close-button = Kapat
+pdfjs-digital-signature-properties-view-certificate = Sertifikayı göster
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Neden: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Zaman damgası: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures =
+ { $count ->
+ [one] Alt imza ({ $count })
+ *[other] Alt imzalar ({ $count })
+ }
+
+## Print
+
+pdfjs-print-progress-message = Belge yazdırılmaya hazırlanıyor…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = %{ $progress }
+pdfjs-print-progress-close-button = Vazgeç
+pdfjs-printing-not-supported = Uyarı: Yazdırma bu tarayıcı tarafından tam olarak desteklenmemektedir.
+pdfjs-printing-not-ready = Uyarı: PDF tamamen yüklenmedi ve yazdırmaya hazır değil.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Kenar çubuğunu aç/kapat
+pdfjs-toggle-sidebar-notification-button =
+ .title = Kenar çubuğunu aç/kapat (Belge ana hat/ekler/katmanlar içeriyor)
+pdfjs-toggle-sidebar-button-label = Kenar çubuğunu aç/kapat
+pdfjs-document-outline-button =
+ .title = Belge ana hatlarını göster (Tüm öğeleri genişletmek/daraltmak için çift tıklayın)
+pdfjs-document-outline-button-label = Belge ana hatları
+pdfjs-attachments-button =
+ .title = Ekleri göster
+pdfjs-attachments-button-label = Ekler
+pdfjs-layers-button =
+ .title = Katmanları göster (tüm katmanları varsayılan duruma sıfırlamak için çift tıklayın)
+pdfjs-layers-button-label = Katmanlar
+pdfjs-thumbs-button =
+ .title = Küçük resimleri göster
+pdfjs-thumbs-button-label = Küçük resimler
+pdfjs-current-outline-item-button =
+ .title = Mevcut ana hat öğesini bul
+pdfjs-current-outline-item-button-label = Mevcut ana hat öğesi
+pdfjs-findbar-button =
+ .title = Belgede bul
+pdfjs-findbar-button-label = Bul
+pdfjs-additional-layers = Ek katmanlar
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Sayfa { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page }. sayfanın küçük hâli
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = { $page }. sayfayı seç
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Sayfa { $page }/{ $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Bul
+ .placeholder = Belgede bul…
+pdfjs-find-previous-button =
+ .title = Önceki eşleşmeyi bul
+pdfjs-find-previous-button-label = Önceki
+pdfjs-find-next-button =
+ .title = Sonraki eşleşmeyi bul
+pdfjs-find-next-button-label = Sonraki
+pdfjs-find-highlight-checkbox = Tümünü vurgula
+pdfjs-find-match-case-checkbox-label = Büyük-küçük harfe duyarlı
+pdfjs-find-match-diacritics-checkbox-label = Fonetik işaretleri bul
+pdfjs-find-entire-word-checkbox-label = Tam sözcükler
+pdfjs-find-reached-top = Belgenin başına ulaşıldı, sonundan devam edildi
+pdfjs-find-reached-bottom = Belgenin sonuna ulaşıldı, başından devam edildi
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $total } eşleşmeden { $current }. eşleşme
+ *[other] { $total } eşleşmeden { $current }. eşleşme
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] { $limit } eşleşmeden fazla
+ *[other] { $limit } eşleşmeden fazla
+ }
+pdfjs-find-not-found = Eşleşme bulunamadı
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sayfa genişliği
+pdfjs-page-scale-fit = Sayfayı sığdır
+pdfjs-page-scale-auto = Otomatik yakınlaştır
+pdfjs-page-scale-actual = Gerçek boyut
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = %{ $scale }
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Sayfa { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF yüklenirken bir hata oluştu.
+pdfjs-invalid-file-error = Geçersiz veya bozulmuş PDF dosyası.
+pdfjs-missing-file-error = PDF dosyası eksik.
+pdfjs-unexpected-response-error = Beklenmeyen sunucu yanıtı.
+pdfjs-rendering-error = Sayfa yorumlanırken bir hata oluştu.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } işareti]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Bu PDF dosyasını açmak için parolasını yazın.
+pdfjs-password-invalid = Geçersiz parola. Lütfen yeniden deneyin.
+pdfjs-password-ok-button = Tamam
+pdfjs-password-cancel-button = Vazgeç
+pdfjs-web-fonts-disabled = Web fontları devre dışı: Gömülü PDF fontları kullanılamıyor.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Metin
+pdfjs-editor-color-picker-free-text-input =
+ .title = Metin rengini değiştir
+pdfjs-editor-free-text-button-label = Metin
+pdfjs-editor-ink-button =
+ .title = Çiz
+pdfjs-editor-color-picker-ink-input =
+ .title = Çizim rengini değiştir
+pdfjs-editor-ink-button-label = Çiz
+pdfjs-editor-stamp-button =
+ .title = Resim ekle veya düzenle
+pdfjs-editor-stamp-button-label = Resim ekle veya düzenle
+pdfjs-editor-highlight-button =
+ .title = Vurgula
+pdfjs-editor-highlight-button-label = Vurgula
+pdfjs-highlight-floating-button1 =
+ .title = Vurgula
+ .aria-label = Vurgula
+pdfjs-highlight-floating-button-label = Vurgula
+pdfjs-comment-floating-button =
+ .title = Yorum ekle
+ .aria-label = Yorum ekle
+pdfjs-comment-floating-button-label = Yorum ekle
+pdfjs-editor-comment-button =
+ .title = Yorum ekle
+ .aria-label = Yorum ekle
+pdfjs-editor-comment-button-label = Yorum ekle
+pdfjs-editor-signature-button =
+ .title = İmza ekle
+pdfjs-editor-signature-button-label = İmza ekle
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Vurgu düzenleyici
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Çizim düzenleyici
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = İmza düzenleyici: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Resim düzenleyici
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Çizimi kaldır
+pdfjs-editor-remove-freetext-button =
+ .title = Metni kaldır
+pdfjs-editor-remove-stamp-button =
+ .title = Resmi kaldır
+pdfjs-editor-remove-highlight-button =
+ .title = Vurgulamayı kaldır
+pdfjs-editor-remove-signature-button =
+ .title = İmzayı kaldır
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Renk
+pdfjs-editor-free-text-size-input = Boyut
+pdfjs-editor-ink-color-input = Renk
+pdfjs-editor-ink-thickness-input = Kalınlık
+pdfjs-editor-ink-opacity-input = Saydamlık
+pdfjs-editor-stamp-add-image-button =
+ .title = Resim ekle
+pdfjs-editor-stamp-add-image-button-label = Resim ekle
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Kalınlık
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Metin dışındaki öğeleri vurgularken kalınlığı değiştir
+pdfjs-editor-add-signature-container =
+ .aria-label = İmza yönetimi ve kayıtlı imzalar
+pdfjs-editor-signature-add-signature-button =
+ .title = Yeni imza ekle
+pdfjs-editor-signature-add-signature-button-label = Yeni imza ekle
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Kayıtlı imza: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Metin düzenleyicisi
+ .default-content = Yazmaya başlayın…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Yorum
+ *[other] Yorumlar
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Kenar çubuğunu kapat
+ .aria-label = Kenar çubuğunu kapat
+pdfjs-editor-comments-sidebar-close-button-label = Kenar çubuğunu kapat
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Not almaya değer bir şey mi gördünüz? Onu işaretleyip yorum yazabilirsiniz.
+pdfjs-editor-comments-sidebar-no-comments-link = Daha fazla bilgi alın
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Alternatif metin
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Alternatif metni düzenle
+pdfjs-editor-alt-text-dialog-label = Bir seçenek seçin
+pdfjs-editor-alt-text-dialog-description = Alternatif metin, insanlar resmi göremediğinde veya resim yüklenmediğinde işe yarar.
+pdfjs-editor-alt-text-add-description-label = Açıklama ekle
+pdfjs-editor-alt-text-add-description-description = Konuyu, ortamı veya eylemleri tanımlayan bir iki cümle yazmaya çalışın.
+pdfjs-editor-alt-text-mark-decorative-label = Dekoratif olarak işaretle
+pdfjs-editor-alt-text-mark-decorative-description = Kenarlıklar veya filigranlar gibi dekoratif resimler için kullanılır.
+pdfjs-editor-alt-text-cancel-button = Vazgeç
+pdfjs-editor-alt-text-save-button = Kaydet
+pdfjs-editor-alt-text-decorative-tooltip = Dekoratif olarak işaretlendi
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Örneğin, “Genç bir adam yemek yemek için masaya oturuyor”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Alternatif metin
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Sol üst köşe — yeniden boyutlandır
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Üst orta — yeniden boyutlandır
+pdfjs-editor-resizer-top-right =
+ .aria-label = Sağ üst köşe — yeniden boyutlandır
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Orta sağ — yeniden boyutlandır
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Sağ alt köşe — yeniden boyutlandır
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Alt orta — yeniden boyutlandır
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Sol alt köşe — yeniden boyutlandır
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Orta sol — yeniden boyutlandır
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Vurgu rengi
+pdfjs-editor-colorpicker-button =
+ .title = Rengi değiştir
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Renk seçenekleri
+pdfjs-editor-colorpicker-yellow =
+ .title = Sarı
+pdfjs-editor-colorpicker-green =
+ .title = Yeşil
+pdfjs-editor-colorpicker-blue =
+ .title = Mavi
+pdfjs-editor-colorpicker-pink =
+ .title = Pembe
+pdfjs-editor-colorpicker-red =
+ .title = Kırmızı
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Tümünü göster
+pdfjs-editor-highlight-show-all-button =
+ .title = Tümünü göster
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Alt metni düzenle (resim açıklaması)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Alt metin ekle (resim açıklaması)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Açıklamanızı buraya yazın…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Görme engelli kişilere gösterilecek veya resmin yüklenemediği durumlarda gösterilecek kısa açıklama.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Bu alt metin otomatik olarak oluşturulmuştur ve hatalı olabilir.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Daha fazla bilgi alın
+pdfjs-editor-new-alt-text-create-automatically-button-label = Otomatik olarak alt metin oluştur
+pdfjs-editor-new-alt-text-not-now-button = Şimdi değil
+pdfjs-editor-new-alt-text-error-title = Alt metin otomatik olarak oluşturulamadı
+pdfjs-editor-new-alt-text-error-description = Lütfen kendi alt metninizi yazın veya daha sonra yeniden deneyin.
+pdfjs-editor-new-alt-text-error-close-button = Kapat
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Alt metin yapay zekâ modeli indiriliyor ({ $downloadedSize } / { $totalSize } MB)
+ .aria-valuetext = Alt metin yapay zekâ modeli indiriliyor ({ $downloadedSize } / { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Alternatif metin eklendi
+pdfjs-editor-new-alt-text-added-button-label = Alt metin eklendi
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Alt metin eksik
+pdfjs-editor-new-alt-text-missing-button-label = Alt metin eksik
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Alt metni incele
+pdfjs-editor-new-alt-text-to-review-button-label = Alt metni incele
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Otomatik olarak oluşturuldu: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Resim alt metni ayarları
+pdfjs-image-alt-text-settings-button-label = Resim alt metni ayarları
+pdfjs-editor-alt-text-settings-dialog-label = Resim alt metni ayarları
+pdfjs-editor-alt-text-settings-automatic-title = Otomatik alt metin
+pdfjs-editor-alt-text-settings-create-model-button-label = Otomatik olarak alt metin oluştur
+pdfjs-editor-alt-text-settings-create-model-description = Görme engelli kişilere gösterilecek veya resmin yüklenemediği durumlarda gösterilecek açıklamalar önerir.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Alt metin yapay zekâ modeli ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Verilerinizin gizli kalması için cihazınızda yerel olarak çalışır. Otomatik alt metin için gereklidir.
+pdfjs-editor-alt-text-settings-delete-model-button = Sil
+pdfjs-editor-alt-text-settings-download-model-button = İndir
+pdfjs-editor-alt-text-settings-downloading-model-button = İndiriliyor…
+pdfjs-editor-alt-text-settings-editor-title = Alt metin düzenleyicisi
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Resim eklerken alt metin düzenleyicisini hemen göster
+pdfjs-editor-alt-text-settings-show-dialog-description = Tüm resimlerinizin alt metne sahip olduğundan emin olmanızı sağlar.
+pdfjs-editor-alt-text-settings-close-button = Kapat
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Vurgu eklendi
+pdfjs-editor-freetext-added-alert = Metin eklendi
+pdfjs-editor-ink-added-alert = Çizim eklendi
+pdfjs-editor-stamp-added-alert = Resim eklendi
+pdfjs-editor-signature-added-alert = İmza eklendi
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Vurgulama silindi
+pdfjs-editor-undo-bar-message-freetext = Metin silindi
+pdfjs-editor-undo-bar-message-ink = Çizim silindi
+pdfjs-editor-undo-bar-message-stamp = Görsel silindi
+pdfjs-editor-undo-bar-message-signature = İmza kaldırıldı
+pdfjs-editor-undo-bar-message-comment = Yorum silindi
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } ek açıklama silindi
+ *[other] { $count } ek açıklama silindi
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Geri al
+pdfjs-editor-undo-bar-undo-button-label = Geri al
+pdfjs-editor-undo-bar-close-button =
+ .title = Kapat
+pdfjs-editor-undo-bar-close-button-label = Kapat
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Bu pencereden PDF belgesine eklemek üzere imza oluşturabilirsiniz. Adınızı düzenleyebilir (adınız alt metin olarak da kullanılır) ve isterseniz ileride tekrar kullanmak üzere imzayı kaydedebilirsiniz.
+pdfjs-editor-add-signature-dialog-title = İmza ekle
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Yaz
+ .title = Yaz
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Çiz
+ .title = Çiz
+pdfjs-editor-add-signature-image-button = Resim
+ .title = Resim
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = İmzanızı yazın
+ .placeholder = İmzanızı yazın
+pdfjs-editor-add-signature-draw-placeholder = İmzanızı çizin
+pdfjs-editor-add-signature-draw-thickness-range-label = Kalınlık
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Çizgi kalınlığı: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Yüklenecek dosyayı buraya sürükleyin
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Veya resim dosyalarına göz atın
+ *[other] Veya resim dosyalarına göz atın
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Açıklama (alt metin)
+pdfjs-editor-add-signature-description-input =
+ .title = Açıklama (alt metin)
+pdfjs-editor-add-signature-description-default-when-drawing = İmza
+pdfjs-editor-add-signature-clear-button-label = İmzayı temizle
+pdfjs-editor-add-signature-clear-button =
+ .title = İmzayı temizle
+pdfjs-editor-add-signature-save-checkbox = İmzayı kaydet
+pdfjs-editor-add-signature-save-warning-message = Kayıtlı 5 imza sınırına ulaştınız. Daha fazla imza kaydetmek için imzalardan birini kaldırın.
+pdfjs-editor-add-signature-image-upload-error-title = Resim yüklenemedi
+pdfjs-editor-add-signature-image-upload-error-description = Ağ bağlantınızı kontrol edin veya başka bir resim deneyin.
+pdfjs-editor-add-signature-image-no-data-error-title = Bu resim imzaya dönüştürülemez
+pdfjs-editor-add-signature-image-no-data-error-description = Lütfen farklı bir resim yüklemeyi deneyin.
+pdfjs-editor-add-signature-error-close-button = Kapat
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Vazgeç
+pdfjs-editor-add-signature-add-button = Ekle
+pdfjs-editor-edit-signature-update-button = Güncelle
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Yorumu düzenle
+pdfjs-editor-edit-comment-popup-button =
+ .title = Yorumu düzenle
+pdfjs-editor-delete-comment-popup-button-label = Yorumu sil
+pdfjs-editor-delete-comment-popup-button =
+ .title = Yorumu sil
+pdfjs-show-comment-button =
+ .title = Yorumu göster
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Yorumu düzenle
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Güncelle
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Yorum ekle
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Ekle
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Yazmaya başlayın…
+pdfjs-editor-edit-comment-dialog-cancel-button = Vazgeç
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Yorum ekle
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Kenar çubuğunu aç/kapat (Belge, küçük resimler/ana hat/ekler/katmanlar içeriyor)
+pdfjs-toggle-views-manager-button1-label = Sayfaları yönet
+pdfjs-views-manager-sidebar =
+ .aria-label = Kenar çubuğu
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Kenar çubuğu boyutlandırıcı
+pdfjs-views-manager-view-selector-button =
+ .title = Görünümler
+pdfjs-views-manager-view-selector-button-label = Görünümler
+pdfjs-views-manager-pages-title = Sayfalar
+pdfjs-views-manager-outlines-title1 = Belge ana hatları
+ .title = Belge ana hatları (Tüm öğeleri genişletmek/daraltmak için çift tıklayın)
+pdfjs-views-manager-attachments-title = Ekler
+pdfjs-views-manager-layers-title1 = Katmanlar
+ .title = Katmanlar (Tüm katmanları varsayılan duruma sıfırlamak için çift tıklayın)
+pdfjs-views-manager-pages-option-label = Sayfalar
+pdfjs-views-manager-outlines-option-label = Belge ana hatları
+pdfjs-views-manager-attachments-option-label = Ekler
+pdfjs-views-manager-layers-option-label = Katmanlar
+pdfjs-views-manager-add-file-button =
+ .title = Dosya ekle
+pdfjs-views-manager-add-file-button-label = Dosya ekle
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] { $count } seçili
+ *[other] { $count } seçili
+ }
+pdfjs-views-manager-pages-status-none-action-label = Sayfaları seç
+pdfjs-views-manager-pages-status-action-button-label = Yönet
+pdfjs-views-manager-pages-status-copy-button-label = Kopyala
+pdfjs-views-manager-pages-status-cut-button-label = Kes
+pdfjs-views-manager-pages-status-delete-button-label = Sil
+pdfjs-views-manager-pages-status-export-selected-button-label = Seçilenleri dışa aktar…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 sayfa kesildi
+ *[other] { $count } sayfa kesildi
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 sayfa kopyalandı
+ *[other] { $count } sayfa kopyalandı
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 sayfa silindi
+ *[other] { $count } sayfa silindi
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Dosyanız hazırlanıyor…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Dosya yükleniyor…
+pdfjs-views-manager-status-warning-cut-label = Kesilemedi. Sayfayı tazeleyip yeniden deneyin.
+pdfjs-views-manager-status-warning-copy-label = Kopyalanamadı. Sayfayı tazeleyip yeniden deneyin.
+pdfjs-views-manager-status-warning-delete-label = Silinemedi. Sayfayı tazeleyip yeniden deneyin.
+pdfjs-views-manager-status-warning-save-label = Kaydedilemedi. Sayfayı tazeleyip yeniden deneyin.
+pdfjs-views-manager-status-undo-button-label = Geri al
+pdfjs-views-manager-status-done-button-label = Tamam
+pdfjs-views-manager-status-close-button =
+ .title = Kapat
+pdfjs-views-manager-status-close-button-label = Kapat
+pdfjs-views-manager-paste-button-label = Yapıştır
+pdfjs-views-manager-paste-button-before =
+ .title = İlk sayfadan önce yapıştır
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = { $page }. sayfadan sonra yapıştır
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = YENİ
+pdfjs-views-manager-waiting-for-file = Dosya yükleniyor…
+pdfjs-toggle-views-manager-button1 =
+ .title = Sayfaları yönet
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Dijital imza özellikleri
+ .aria-label = Dijital imza özellikleri
+pdfjs-digital-signature-properties-button-label = Dijital imza özellikleri
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Belge geçerli bir dijital imza ile imzalanmıştır
+pdfjs-digital-signature-properties-banner-unknown =
+ { $count ->
+ [one] Belge imzalanmış ancak { $count } dijital imza doğrulanamadı
+ *[other] Belge imzalanmış ancak { $count } dijital imza doğrulanamadı
+ }
+pdfjs-digital-signature-properties-banner-untrusted =
+ { $count ->
+ [one] Belge, güvenilmeyen { $count } sertifikayla imzalanmış
+ *[other] Belge, güvenilmeyen { $count } sertifikayla imzalanmış
+ }
+pdfjs-digital-signature-properties-banner-expired =
+ { $count ->
+ [one] Belge, süresi dolmuş { $count } sertifika ile imzalanmış
+ *[other] Belge, süresi dolmuş { $count } sertifika ile imzalanmış
+ }
+pdfjs-digital-signature-properties-banner-invalid =
+ { $count ->
+ [one] Belge { $count } geçersiz dijital imza içeriyor
+ *[other] Belge { $count } geçersiz dijital imza içeriyor
+ }
+pdfjs-digital-signature-properties-banner-revoked =
+ { $count ->
+ [one] Belge, iptal edilmiş { $count } sertifika ile imzalanmış
+ *[other] Belge, iptal edilmiş { $count } sertifika ile imzalanmış
+ }
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Durum: İmza doğrulandı
+pdfjs-digital-signature-properties-status-invalid = Durum: İmza geçersiz
+pdfjs-digital-signature-properties-status-unknown = Durum: Doğrulanamadı (desteklenmiyor)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Sertifika: Güvenilir ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Sertifika: Kullanılamıyor
+pdfjs-digital-signature-properties-certificate-untrusted = Sertifika: Güvensiz
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Sertifika: Bilinmeyen yayıncı ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Sertifika: Kendi kendine imzalanmış ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Sertifika: Güvenilmeyen yayıncı ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Sertifika: Süresi dolmuş
+pdfjs-digital-signature-properties-certificate-expired-with-date = Sertifika: Süresi dolmuş ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Sertifika: İptal edilmiş
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Kayıtlı imzayı kaldır
+pdfjs-editor-delete-signature-button-label1 = Kayıtlı imzayı kaldır
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Açıklamayı düzenle
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Açıklamayı düzenle
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/trs/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/trs/viewer.ftl
new file mode 100644
index 0000000..de1e8cb
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/trs/viewer.ftl
@@ -0,0 +1,163 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Pajinâ gunâj rukùu
+pdfjs-previous-button-label = Sa gachin
+pdfjs-next-button =
+ .title = Pajinâ 'na' ñaan
+pdfjs-next-button-label = Ne' ñaan
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Ñanj
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = si'iaj { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Nagi'iaj li'
+pdfjs-zoom-out-button-label = Nagi'iaj li'
+pdfjs-zoom-in-button =
+ .title = Nagi'iaj niko'
+pdfjs-zoom-in-button-label = Nagi'iaj niko'
+pdfjs-zoom-select =
+ .title = dàj nìko ma'an
+pdfjs-presentation-mode-button =
+ .title = Naduno' daj ga ma
+pdfjs-presentation-mode-button-label = Daj gà ma
+pdfjs-open-file-button =
+ .title = Na'nïn' chrû ñanj
+pdfjs-open-file-button-label = Na'nïn
+pdfjs-print-button =
+ .title = Nari' ña du'ua
+pdfjs-print-button-label = Nari' ñadu'ua
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Rasun
+pdfjs-tools-button-label = Nej rasùun
+pdfjs-first-page-button =
+ .title = gun' riña pajina asiniin
+pdfjs-first-page-button-label = Gun' riña pajina asiniin
+pdfjs-last-page-button =
+ .title = Gun' riña pajina rukù ni'in
+pdfjs-last-page-button-label = Gun' riña pajina rukù ni'inj
+pdfjs-page-rotate-cw-button =
+ .title = Tanikaj ne' huat
+pdfjs-page-rotate-cw-button-label = Tanikaj ne' huat
+pdfjs-page-rotate-ccw-button =
+ .title = Tanikaj ne' chînt'
+pdfjs-page-rotate-ccw-button-label = Tanikaj ne' chint
+pdfjs-cursor-text-select-tool-button =
+ .title = Dugi'iaj sun' sa ganahui texto
+pdfjs-cursor-text-select-tool-button-label = Nej rasun arajsun' da' nahui' texto
+pdfjs-cursor-hand-tool-button =
+ .title = Nachrun' nej rasun
+pdfjs-cursor-hand-tool-button-label = Sa rajsun ro'o'
+pdfjs-scroll-vertical-button =
+ .title = Garasun' dukuán runūu
+pdfjs-scroll-vertical-button-label = Dukuán runūu
+pdfjs-scroll-horizontal-button =
+ .title = Garasun' dukuán nikin' nahui
+pdfjs-scroll-horizontal-button-label = Dukuán nikin' nahui
+pdfjs-scroll-wrapped-button =
+ .title = Garasun' sa nachree
+pdfjs-scroll-wrapped-button-label = Sa nachree
+pdfjs-spread-none-button =
+ .title = Si nagi'iaj nugun'un' nej pagina hua ninin
+pdfjs-spread-none-button-label = Ni'io daj hua pagina
+pdfjs-spread-odd-button =
+ .title = Nagi'iaj nugua'ant nej pajina
+pdfjs-spread-odd-button-label = Ni'io' daj hua libro gurin
+pdfjs-spread-even-button =
+ .title = Nakāj dugui' ngà nej pajinâ ayi'ì ngà da' hùi hùi
+pdfjs-spread-even-button-label = Nahuin nìko nej
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Nej sa nikāj ñanj…
+pdfjs-document-properties-button-label = Nej sa nikāj ñanj…
+pdfjs-document-properties-file-name = Si yugui archîbo:
+pdfjs-document-properties-file-size = Dàj yachìj archîbo:
+pdfjs-document-properties-title = Si yugui:
+pdfjs-document-properties-author = Sí girirà:
+pdfjs-document-properties-subject = Dugui':
+pdfjs-document-properties-keywords = Nej nuguan' huìi:
+pdfjs-document-properties-creation-date = Gui gurugui' man:
+pdfjs-document-properties-modification-date = Nuguan' nahuin nakà:
+pdfjs-document-properties-creator = Guiri ro'
+pdfjs-document-properties-producer = Sa ri PDF:
+pdfjs-document-properties-version = PDF Version:
+pdfjs-document-properties-page-count = Si Guendâ Pâjina:
+pdfjs-document-properties-page-size = Dàj yachìj pâjina:
+pdfjs-document-properties-page-size-unit-inches = riña
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = nadu'ua
+pdfjs-document-properties-page-size-orientation-landscape = dàj huaj
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Da'ngà'a
+pdfjs-document-properties-page-size-name-legal = Nuguan' a'nï'ïn
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Nanèt chre ni'iajt riña Web:
+pdfjs-document-properties-linearized-yes = Ga'ue
+pdfjs-document-properties-linearized-no = Si ga'ue
+pdfjs-document-properties-close-button = Narán
+
+## Print
+
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Duyichin'
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Nadunā barrâ nù yi'nïn
+pdfjs-toggle-sidebar-button-label = Nadunā barrâ nù yi'nïn
+pdfjs-findbar-button-label = Narì'
+
+## Find panel button title and messages
+
+pdfjs-find-previous-button-label = Sa gachîn
+pdfjs-find-next-button-label = Ne' ñaan
+pdfjs-find-highlight-checkbox = Daran' sa ña'an
+pdfjs-find-match-case-checkbox-label = Match case
+pdfjs-find-not-found = Nu narì'ij nugua'anj
+
+## Predefined zoom values
+
+pdfjs-page-scale-actual = Dàj yàchi akuan' nín
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Password
+
+pdfjs-password-ok-button = Ga'ue
+pdfjs-password-cancel-button = Duyichin'
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/uk/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/uk/viewer.ftl
new file mode 100644
index 0000000..3b293e2
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/uk/viewer.ftl
@@ -0,0 +1,727 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Попередня сторінка
+pdfjs-previous-button-label = Попередня
+pdfjs-next-button =
+ .title = Наступна сторінка
+pdfjs-next-button-label = Наступна
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Сторінка
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = із { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } із { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Зменшити
+pdfjs-zoom-out-button-label = Зменшити
+pdfjs-zoom-in-button =
+ .title = Збільшити
+pdfjs-zoom-in-button-label = Збільшити
+pdfjs-zoom-select =
+ .title = Масштаб
+pdfjs-presentation-mode-button =
+ .title = Перейти в режим презентації
+pdfjs-presentation-mode-button-label = Режим презентації
+pdfjs-open-file-button =
+ .title = Відкрити файл
+pdfjs-open-file-button-label = Відкрити
+pdfjs-print-button =
+ .title = Друк
+pdfjs-print-button-label = Друк
+pdfjs-save-button =
+ .title = Зберегти
+pdfjs-save-button-label = Зберегти
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Завантажити
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Завантажити
+pdfjs-bookmark-button =
+ .title = Поточна сторінка (перегляд URL-адреси з поточної сторінки)
+pdfjs-bookmark-button-label = Поточна сторінка
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Інструменти
+pdfjs-tools-button-label = Інструменти
+pdfjs-first-page-button =
+ .title = На першу сторінку
+pdfjs-first-page-button-label = На першу сторінку
+pdfjs-last-page-button =
+ .title = На останню сторінку
+pdfjs-last-page-button-label = На останню сторінку
+pdfjs-page-rotate-cw-button =
+ .title = Повернути за годинниковою стрілкою
+pdfjs-page-rotate-cw-button-label = Повернути за годинниковою стрілкою
+pdfjs-page-rotate-ccw-button =
+ .title = Повернути проти годинникової стрілки
+pdfjs-page-rotate-ccw-button-label = Повернути проти годинникової стрілки
+pdfjs-cursor-text-select-tool-button =
+ .title = Увімкнути інструмент вибору тексту
+pdfjs-cursor-text-select-tool-button-label = Інструмент вибору тексту
+pdfjs-cursor-hand-tool-button =
+ .title = Увімкнути інструмент "Рука"
+pdfjs-cursor-hand-tool-button-label = Інструмент "Рука"
+pdfjs-scroll-page-button =
+ .title = Використовувати прокручування сторінки
+pdfjs-scroll-page-button-label = Прокручування сторінки
+pdfjs-scroll-vertical-button =
+ .title = Використовувати вертикальне прокручування
+pdfjs-scroll-vertical-button-label = Вертикальне прокручування
+pdfjs-scroll-horizontal-button =
+ .title = Використовувати горизонтальне прокручування
+pdfjs-scroll-horizontal-button-label = Горизонтальне прокручування
+pdfjs-scroll-wrapped-button =
+ .title = Використовувати масштабоване прокручування
+pdfjs-scroll-wrapped-button-label = Масштабоване прокручування
+pdfjs-spread-none-button =
+ .title = Не використовувати розгорнуті сторінки
+pdfjs-spread-none-button-label = Без розгорнутих сторінок
+pdfjs-spread-odd-button =
+ .title = Розгорнуті сторінки починаються з непарних номерів
+pdfjs-spread-odd-button-label = Непарні сторінки зліва
+pdfjs-spread-even-button =
+ .title = Розгорнуті сторінки починаються з парних номерів
+pdfjs-spread-even-button-label = Парні сторінки зліва
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Властивості документа…
+pdfjs-document-properties-button-label = Властивості документа…
+pdfjs-document-properties-file-name = Назва файлу:
+pdfjs-document-properties-file-size = Розмір файлу:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } кБ ({ $b } байтів)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } МБ ({ $b } байтів)
+pdfjs-document-properties-title = Заголовок:
+pdfjs-document-properties-author = Автор:
+pdfjs-document-properties-subject = Тема:
+pdfjs-document-properties-keywords = Ключові слова:
+pdfjs-document-properties-creation-date = Дата створення:
+pdfjs-document-properties-modification-date = Дата зміни:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Створено:
+pdfjs-document-properties-producer = Виробник PDF:
+pdfjs-document-properties-version = Версія PDF:
+pdfjs-document-properties-page-count = Кількість сторінок:
+pdfjs-document-properties-page-size = Розмір сторінки:
+pdfjs-document-properties-page-size-unit-inches = дюймів
+pdfjs-document-properties-page-size-unit-millimeters = мм
+pdfjs-document-properties-page-size-orientation-portrait = книжкова
+pdfjs-document-properties-page-size-orientation-landscape = альбомна
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Швидкий перегляд в Інтернеті:
+pdfjs-document-properties-linearized-yes = Так
+pdfjs-document-properties-linearized-no = Ні
+pdfjs-document-properties-close-button = Закрити
+
+## Print
+
+pdfjs-print-progress-message = Підготовка документу до друку…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Скасувати
+pdfjs-printing-not-supported = Попередження: Цей браузер не повністю підтримує друк.
+pdfjs-printing-not-ready = Попередження: PDF не повністю завантажений для друку.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Бічна панель
+pdfjs-toggle-sidebar-notification-button =
+ .title = Перемкнути бічну панель (документ містить ескіз/вкладення/шари)
+pdfjs-toggle-sidebar-button-label = Перемкнути бічну панель
+pdfjs-document-outline-button =
+ .title = Показати схему документу (подвійний клік для розгортання/згортання елементів)
+pdfjs-document-outline-button-label = Схема документа
+pdfjs-attachments-button =
+ .title = Показати вкладення
+pdfjs-attachments-button-label = Вкладення
+pdfjs-layers-button =
+ .title = Показати шари (двічі клацніть, щоб скинути всі шари до типового стану)
+pdfjs-layers-button-label = Шари
+pdfjs-thumbs-button =
+ .title = Показати мініатюри
+pdfjs-thumbs-button-label = Мініатюри
+pdfjs-current-outline-item-button =
+ .title = Знайти поточний елемент змісту
+pdfjs-current-outline-item-button-label = Поточний елемент змісту
+pdfjs-findbar-button =
+ .title = Знайти в документі
+pdfjs-findbar-button-label = Знайти
+pdfjs-additional-layers = Додаткові шари
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Сторінка { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Ескіз сторінки { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Знайти
+ .placeholder = Знайти в документі…
+pdfjs-find-previous-button =
+ .title = Знайти попереднє входження фрази
+pdfjs-find-previous-button-label = Попереднє
+pdfjs-find-next-button =
+ .title = Знайти наступне входження фрази
+pdfjs-find-next-button-label = Наступне
+pdfjs-find-highlight-checkbox = Підсвітити все
+pdfjs-find-match-case-checkbox-label = З урахуванням регістру
+pdfjs-find-match-diacritics-checkbox-label = Відповідність діакритичних знаків
+pdfjs-find-entire-word-checkbox-label = Цілі слова
+pdfjs-find-reached-top = Досягнуто початку документу, продовжено з кінця
+pdfjs-find-reached-bottom = Досягнуто кінця документу, продовжено з початку
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count =
+ { $total ->
+ [one] { $current } збіг з { $total }
+ [few] { $current } збіги з { $total }
+ *[many] { $current } збігів з { $total }
+ }
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit =
+ { $limit ->
+ [one] Понад { $limit } збіг
+ [few] Понад { $limit } збіги
+ *[many] Понад { $limit } збігів
+ }
+pdfjs-find-not-found = Фразу не знайдено
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = За шириною
+pdfjs-page-scale-fit = Вмістити
+pdfjs-page-scale-auto = Автомасштаб
+pdfjs-page-scale-actual = Дійсний розмір
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Сторінка { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Під час завантаження PDF сталася помилка.
+pdfjs-invalid-file-error = Недійсний або пошкоджений PDF-файл.
+pdfjs-missing-file-error = Відсутній PDF-файл.
+pdfjs-unexpected-response-error = Неочікувана відповідь сервера.
+pdfjs-rendering-error = Під час виведення сторінки сталася помилка.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type }-анотація]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Введіть пароль для відкриття цього PDF-файлу.
+pdfjs-password-invalid = Неправильний пароль. Спробуйте ще раз.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Скасувати
+pdfjs-web-fonts-disabled = Вебшрифти вимкнено: неможливо використати вбудовані у PDF шрифти.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Текст
+pdfjs-editor-color-picker-free-text-input =
+ .title = Змінити колір тексту
+pdfjs-editor-free-text-button-label = Текст
+pdfjs-editor-ink-button =
+ .title = Малювати
+pdfjs-editor-color-picker-ink-input =
+ .title = Змінити колір малюнка
+pdfjs-editor-ink-button-label = Малювати
+pdfjs-editor-stamp-button =
+ .title = Додати чи редагувати зображення
+pdfjs-editor-stamp-button-label = Додати чи редагувати зображення
+pdfjs-editor-highlight-button =
+ .title = Підсвітити
+pdfjs-editor-highlight-button-label = Підсвітити
+pdfjs-highlight-floating-button1 =
+ .title = Підсвітити
+ .aria-label = Підсвітити
+pdfjs-highlight-floating-button-label = Підсвітити
+pdfjs-comment-floating-button =
+ .title = Коментувати
+ .aria-label = Коментувати
+pdfjs-comment-floating-button-label = Коментувати
+pdfjs-editor-comment-button =
+ .title = Коментар
+ .aria-label = Коментар
+pdfjs-editor-comment-button-label = Коментар
+pdfjs-editor-signature-button =
+ .title = Додати підпис
+pdfjs-editor-signature-button-label = Додати підпис
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Редактор підсвічень
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Редактор малюнків
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Редактор підпису: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Редактор зображень
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Вилучити малюнок
+pdfjs-editor-remove-freetext-button =
+ .title = Вилучити текст
+pdfjs-editor-remove-stamp-button =
+ .title = Вилучити зображення
+pdfjs-editor-remove-highlight-button =
+ .title = Вилучити підсвічення
+pdfjs-editor-remove-signature-button =
+ .title = Вилучити підпис
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Колір
+pdfjs-editor-free-text-size-input = Розмір
+pdfjs-editor-ink-color-input = Колір
+pdfjs-editor-ink-thickness-input = Товщина
+pdfjs-editor-ink-opacity-input = Прозорість
+pdfjs-editor-stamp-add-image-button =
+ .title = Додати зображення
+pdfjs-editor-stamp-add-image-button-label = Додати зображення
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Товщина
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Змінюйте товщину під час підсвічення елементів, крім тексту
+pdfjs-editor-add-signature-container =
+ .aria-label = Елементи керування підписами та збережені підписи
+pdfjs-editor-signature-add-signature-button =
+ .title = Додати новий підпис
+pdfjs-editor-signature-add-signature-button-label = Додати новий підпис
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Збережений підпис: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Текстовий редактор
+ .default-content = Напишіть щось…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title =
+ { $count ->
+ [one] Коментар
+ [few] Коментарі
+ *[many] Коментарі
+ }
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Закрити бічну панель
+ .aria-label = Закрити бічну панель
+pdfjs-editor-comments-sidebar-close-button-label = Закрити бічну панель
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Бачите щось варте уваги? Підсвітіть і додайте коментар.
+pdfjs-editor-comments-sidebar-no-comments-link = Докладніше
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Альтернативний текст
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Редагувати альтернативний текст
+pdfjs-editor-alt-text-dialog-label = Вибрати варіант
+pdfjs-editor-alt-text-dialog-description = Альтернативний текст допомагає, коли зображення не видно або коли воно не завантажується.
+pdfjs-editor-alt-text-add-description-label = Додати опис
+pdfjs-editor-alt-text-add-description-description = Намагайтеся створити 1-2 речення, які описують тему, обставини або дії.
+pdfjs-editor-alt-text-mark-decorative-label = Позначити декоративним
+pdfjs-editor-alt-text-mark-decorative-description = Використовується для декоративних зображень, наприклад рамок або водяних знаків.
+pdfjs-editor-alt-text-cancel-button = Скасувати
+pdfjs-editor-alt-text-save-button = Зберегти
+pdfjs-editor-alt-text-decorative-tooltip = Позначено декоративним
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Наприклад, “Молодий чоловік сідає за стіл їсти”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Альтернативний текст
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Верхній лівий кут – зміна розміру
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Вгорі посередині – зміна розміру
+pdfjs-editor-resizer-top-right =
+ .aria-label = Верхній правий кут – зміна розміру
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Праворуч посередині – зміна розміру
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Нижній правий кут – зміна розміру
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Внизу посередині – зміна розміру
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Нижній лівий кут – зміна розміру
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Ліворуч посередині – зміна розміру
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Колір підсвічення
+pdfjs-editor-colorpicker-button =
+ .title = Змінити колір
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Вибір кольору
+pdfjs-editor-colorpicker-yellow =
+ .title = Жовтий
+pdfjs-editor-colorpicker-green =
+ .title = Зелений
+pdfjs-editor-colorpicker-blue =
+ .title = Блакитний
+pdfjs-editor-colorpicker-pink =
+ .title = Рожевий
+pdfjs-editor-colorpicker-red =
+ .title = Червоний
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Показати все
+pdfjs-editor-highlight-show-all-button =
+ .title = Показати все
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Редагувати альтернативний текст (опис зображення)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Додати альтернативний текст (опис зображення)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Напишіть свій опис тут…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Короткий опис для людей, які не бачать зображення, або якщо зображення не завантажується.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Цей альтернативний текст створено автоматично, тому він може бути неточним.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Докладніше
+pdfjs-editor-new-alt-text-create-automatically-button-label = Автоматично створювати альтернативний текст
+pdfjs-editor-new-alt-text-not-now-button = Не зараз
+pdfjs-editor-new-alt-text-error-title = Не вдалося автоматично створити альтернативний текст
+pdfjs-editor-new-alt-text-error-description = Напишіть власний альтернативний текст або повторіть спробу пізніше.
+pdfjs-editor-new-alt-text-error-close-button = Закрити
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Завантаження моделі ШІ для альтернативного тексту ({ $downloadedSize } з { $totalSize } МБ)
+ .aria-valuetext = Завантаження моделі ШІ для альтернативного тексту ({ $downloadedSize } з { $totalSize } МБ)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Альтернативний текст додано
+pdfjs-editor-new-alt-text-added-button-label = Альтернативний текст додано
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Відсутній альтернативний текст
+pdfjs-editor-new-alt-text-missing-button-label = Відсутній альтернативний текст
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Переглянути альтернативний текст
+pdfjs-editor-new-alt-text-to-review-button-label = Переглянути альтернативний текст
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Створено автоматично: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Налаштування альтернативного тексту зображення
+pdfjs-image-alt-text-settings-button-label = Налаштування альтернативного тексту зображення
+pdfjs-editor-alt-text-settings-dialog-label = Налаштування альтернативного тексту зображення
+pdfjs-editor-alt-text-settings-automatic-title = Автоматичний альтернативний текст
+pdfjs-editor-alt-text-settings-create-model-button-label = Автоматично створювати альтернативний текст
+pdfjs-editor-alt-text-settings-create-model-description = Пропонує описи, щоб допомогти людям, які не бачать зображення, або якщо зображення не завантажується.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Модель ШІ для альтернативного тексту ({ $totalSize } МБ)
+pdfjs-editor-alt-text-settings-ai-model-description = Працює локально на вашому пристрої, тому приватність ваших даних захищена. Призначена для автоматичного створення альтернативного тексту.
+pdfjs-editor-alt-text-settings-delete-model-button = Видалити
+pdfjs-editor-alt-text-settings-download-model-button = Завантажити
+pdfjs-editor-alt-text-settings-downloading-model-button = Завантаження…
+pdfjs-editor-alt-text-settings-editor-title = Редактор альтернативного тексту
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Показувати редактор альтернативного тексту під час додавання зображення
+pdfjs-editor-alt-text-settings-show-dialog-description = Допомагає переконатися, що всі ваші зображення мають альтернативний текст.
+pdfjs-editor-alt-text-settings-close-button = Закрити
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Підсвічення додано
+pdfjs-editor-freetext-added-alert = Текст додано
+pdfjs-editor-ink-added-alert = Малюнок додано
+pdfjs-editor-stamp-added-alert = Зображення додано
+pdfjs-editor-signature-added-alert = Підпис додано
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Підсвічення вилучено
+pdfjs-editor-undo-bar-message-freetext = Текст вилучено
+pdfjs-editor-undo-bar-message-ink = Малюнок вилучено
+pdfjs-editor-undo-bar-message-stamp = Зображення вилучено
+pdfjs-editor-undo-bar-message-signature = Підпис вилучено
+pdfjs-editor-undo-bar-message-comment = Коментар вилучено
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple =
+ { $count ->
+ [one] { $count } анотацію вилучено
+ [few] { $count } анотації вилучено
+ *[many] { $count } анотацій вилучено
+ }
+pdfjs-editor-undo-bar-undo-button =
+ .title = Повернути
+pdfjs-editor-undo-bar-undo-button-label = Повернути
+pdfjs-editor-undo-bar-close-button =
+ .title = Закрити
+pdfjs-editor-undo-bar-close-button-label = Закрити
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = У цьому вікні користувач може створити підпис для додавання до PDF-документа. Користувач може відредагувати назву (яка також слугує альтернативним текстом) і, за бажання, зберегти підпис для повторного використання.
+pdfjs-editor-add-signature-dialog-title = Додати підпис
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Ввести
+ .title = Ввести
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Малювати
+ .title = Малювати
+pdfjs-editor-add-signature-image-button = Зображення
+ .title = Зображення
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Введіть свій підпис
+ .placeholder = Введіть свій підпис
+pdfjs-editor-add-signature-draw-placeholder = Намалюйте свій підпис
+pdfjs-editor-add-signature-draw-thickness-range-label = Товщина
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Товщина лінії: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Перетягніть файл сюди, щоб вивантажити
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Або виберіть файли зображень
+ *[other] Або перегляньте файли зображень
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Опис (альтернативний текст)
+pdfjs-editor-add-signature-description-input =
+ .title = Опис (альтернативний текст)
+pdfjs-editor-add-signature-description-default-when-drawing = Підпис
+pdfjs-editor-add-signature-clear-button-label = Очистити підпис
+pdfjs-editor-add-signature-clear-button =
+ .title = Очистити підпис
+pdfjs-editor-add-signature-save-checkbox = Зберегти підпис
+pdfjs-editor-add-signature-save-warning-message = Ви досягли ліміту в 5 збережених підписів. Вилучіть один, щоб зберегти інший.
+pdfjs-editor-add-signature-image-upload-error-title = Не вдалося вивантажити зображення
+pdfjs-editor-add-signature-image-upload-error-description = Перевірте мережеве з'єднання або спробуйте інше зображення.
+pdfjs-editor-add-signature-image-no-data-error-title = Не вдається конвертувати це зображення в підпис
+pdfjs-editor-add-signature-image-no-data-error-description = Спробуйте вивантажити інше зображення.
+pdfjs-editor-add-signature-error-close-button = Закрити
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Скасувати
+pdfjs-editor-add-signature-add-button = Додати
+pdfjs-editor-edit-signature-update-button = Оновити
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Редагувати коментар
+pdfjs-editor-edit-comment-popup-button =
+ .title = Редагувати коментар
+pdfjs-editor-delete-comment-popup-button-label = Вилучити коментар
+pdfjs-editor-delete-comment-popup-button =
+ .title = Вилучити коментар
+pdfjs-show-comment-button =
+ .title = Показати коментар
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Редагувати коментар
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Оновити
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Додати коментар
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Додати
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Почніть вводити…
+pdfjs-editor-edit-comment-dialog-cancel-button = Скасувати
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Додати коментар
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Перемкнути бічну панель (документ містить мініатюри/ескіз/вкладення/шари)
+pdfjs-views-manager-sidebar =
+ .aria-label = Бічна панель
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Зміна розміру бічної панелі
+pdfjs-views-manager-view-selector-button =
+ .title = Вигляд
+pdfjs-views-manager-view-selector-button-label = Вигляд
+pdfjs-views-manager-pages-title = Сторінки
+pdfjs-views-manager-attachments-title = Вкладення
+pdfjs-views-manager-pages-option-label = Сторінки
+pdfjs-views-manager-outlines-option-label = Схема документа
+pdfjs-views-manager-attachments-option-label = Вкладення
+pdfjs-views-manager-layers-option-label = Шари
+pdfjs-views-manager-add-file-button =
+ .title = Додати файл
+pdfjs-views-manager-add-file-button-label = Додати файл
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label =
+ { $count ->
+ [one] Вибрано { $count }
+ [few] Вибрано { $count }
+ *[many] Вибрано { $count }
+ }
+pdfjs-views-manager-pages-status-none-action-label = Вибрати сторінки
+pdfjs-views-manager-pages-status-action-button-label = Керувати
+pdfjs-views-manager-pages-status-copy-button-label = Копіювати
+pdfjs-views-manager-pages-status-cut-button-label = Вирізати
+pdfjs-views-manager-pages-status-delete-button-label = Видалити
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label =
+ { $count ->
+ [one] 1 сторінку вирізано
+ [few] { $count } сторінки вирізано
+ *[many] { $count } сторінок вирізано
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label =
+ { $count ->
+ [one] 1 сторінку скопійовано
+ [few] { $count } сторінки скопійовано
+ *[many] { $count } сторінок скопійовано
+ }
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label =
+ { $count ->
+ [one] 1 сторінку видалено
+ [few] { $count } сторінки видалено
+ *[many] { $count } сторінок видалено
+ }
+pdfjs-views-manager-pages-status-waiting-ready-label = Підготовка файлу…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Вивантаження файлу…
+pdfjs-views-manager-status-warning-cut-label = Не вдалося вирізати. Оновіть сторінку та спробуйте ще раз.
+pdfjs-views-manager-status-warning-copy-label = Не вдалося скопіювати. Оновіть сторінку та спробуйте ще раз.
+pdfjs-views-manager-status-warning-delete-label = Не вдалося видалити. Оновіть сторінку та спробуйте ще раз.
+pdfjs-views-manager-status-warning-save-label = Не вдалося зберегти. Оновіть сторінку та спробуйте ще раз.
+pdfjs-views-manager-status-undo-button-label = Повернути
+pdfjs-views-manager-status-close-button =
+ .title = Закрити
+pdfjs-views-manager-status-close-button-label = Закрити
+pdfjs-views-manager-paste-button-label = Вставити
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Видалити збережений підпис
+pdfjs-editor-delete-signature-button-label1 = Видалити збережений підпис
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Редагувати опис
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Редагувати опис
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ur/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ur/viewer.ftl
new file mode 100644
index 0000000..1d2e92d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/ur/viewer.ftl
@@ -0,0 +1,222 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = پچھلا صفحہ
+pdfjs-previous-button-label = پچھلا
+pdfjs-next-button =
+ .title = اگلا صفحہ
+pdfjs-next-button-label = آگے
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = صفحہ
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = { $pagesCount } کا
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } کا { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = باہر زوم کریں
+pdfjs-zoom-out-button-label = باہر زوم کریں
+pdfjs-zoom-in-button =
+ .title = اندر زوم کریں
+pdfjs-zoom-in-button-label = اندر زوم کریں
+pdfjs-zoom-select =
+ .title = زوم
+pdfjs-presentation-mode-button =
+ .title = پیشکش موڈ میں چلے جائیں
+pdfjs-presentation-mode-button-label = پیشکش موڈ
+pdfjs-open-file-button =
+ .title = مسل کھولیں
+pdfjs-open-file-button-label = کھولیں
+pdfjs-print-button =
+ .title = چھاپیں
+pdfjs-print-button-label = چھاپیں
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = آلات
+pdfjs-tools-button-label = آلات
+pdfjs-first-page-button =
+ .title = پہلے صفحہ پر جائیں
+pdfjs-first-page-button-label = پہلے صفحہ پر جائیں
+pdfjs-last-page-button =
+ .title = آخری صفحہ پر جائیں
+pdfjs-last-page-button-label = آخری صفحہ پر جائیں
+pdfjs-page-rotate-cw-button =
+ .title = گھڑی وار گھمائیں
+pdfjs-page-rotate-cw-button-label = گھڑی وار گھمائیں
+pdfjs-page-rotate-ccw-button =
+ .title = ضد گھڑی وار گھمائیں
+pdfjs-page-rotate-ccw-button-label = ضد گھڑی وار گھمائیں
+pdfjs-cursor-text-select-tool-button =
+ .title = متن کے انتخاب کے ٹول کو فعال بناے
+pdfjs-cursor-text-select-tool-button-label = متن کے انتخاب کا آلہ
+pdfjs-cursor-hand-tool-button =
+ .title = ہینڈ ٹول کو فعال بناییں
+pdfjs-cursor-hand-tool-button-label = ہاتھ کا آلہ
+pdfjs-scroll-vertical-button =
+ .title = عمودی اسکرولنگ کا استعمال کریں
+pdfjs-scroll-vertical-button-label = عمودی اسکرولنگ
+pdfjs-scroll-horizontal-button =
+ .title = افقی سکرولنگ کا استعمال کریں
+pdfjs-scroll-horizontal-button-label = افقی سکرولنگ
+pdfjs-spread-none-button =
+ .title = صفحہ پھیلانے میں شامل نہ ہوں
+pdfjs-spread-none-button-label = کوئی پھیلاؤ نہیں
+pdfjs-spread-odd-button-label = تاک پھیلاؤ
+pdfjs-spread-even-button-label = جفت پھیلاؤ
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = دستاویز خواص…
+pdfjs-document-properties-button-label = دستاویز خواص…
+pdfjs-document-properties-file-name = نام مسل:
+pdfjs-document-properties-file-size = مسل سائز:
+pdfjs-document-properties-title = عنوان:
+pdfjs-document-properties-author = تخلیق کار:
+pdfjs-document-properties-subject = موضوع:
+pdfjs-document-properties-keywords = کلیدی الفاظ:
+pdfjs-document-properties-creation-date = تخلیق کی تاریخ:
+pdfjs-document-properties-modification-date = ترمیم کی تاریخ:
+pdfjs-document-properties-creator = تخلیق کار:
+pdfjs-document-properties-producer = PDF پیدا کار:
+pdfjs-document-properties-version = PDF ورژن:
+pdfjs-document-properties-page-count = صفحہ شمار:
+pdfjs-document-properties-page-size = صفہ کی لمبائ:
+pdfjs-document-properties-page-size-unit-inches = میں
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = عمودی انداز
+pdfjs-document-properties-page-size-orientation-landscape = افقى انداز
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = خط
+pdfjs-document-properties-page-size-name-legal = قانونی
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } { $name } { $orientation }
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = تیز ویب دیکھیں:
+pdfjs-document-properties-linearized-yes = ہاں
+pdfjs-document-properties-linearized-no = نہیں
+pdfjs-document-properties-close-button = بند کریں
+
+## Print
+
+pdfjs-print-progress-message = چھاپنے کرنے کے لیے دستاویز تیار کیے جا رھے ھیں
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = *{ $progress }%*
+pdfjs-print-progress-close-button = منسوخ کریں
+pdfjs-printing-not-supported = تنبیہ:چھاپنا اس براؤزر پر پوری طرح معاونت شدہ نہیں ہے۔
+pdfjs-printing-not-ready = تنبیہ: PDF چھپائی کے لیے پوری طرح لوڈ نہیں ہوئی۔
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = سلائیڈ ٹوگل کریں
+pdfjs-toggle-sidebar-button-label = سلائیڈ ٹوگل کریں
+pdfjs-document-outline-button =
+ .title = دستاویز کی سرخیاں دکھایں (تمام اشیاء وسیع / غائب کرنے کے لیے ڈبل کلک کریں)
+pdfjs-document-outline-button-label = دستاویز آؤٹ لائن
+pdfjs-attachments-button =
+ .title = منسلکات دکھائیں
+pdfjs-attachments-button-label = منسلکات
+pdfjs-thumbs-button =
+ .title = تھمبنیل دکھائیں
+pdfjs-thumbs-button-label = مجمل
+pdfjs-findbar-button =
+ .title = دستاویز میں ڈھونڈیں
+pdfjs-findbar-button-label = ڈھونڈیں
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = صفحہ { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = صفحے کا مجمل { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = ڈھونڈیں
+ .placeholder = دستاویز… میں ڈھونڈیں
+pdfjs-find-previous-button =
+ .title = فقرے کا پچھلا وقوع ڈھونڈیں
+pdfjs-find-previous-button-label = پچھلا
+pdfjs-find-next-button =
+ .title = فقرے کا اگلہ وقوع ڈھونڈیں
+pdfjs-find-next-button-label = آگے
+pdfjs-find-highlight-checkbox = تمام نمایاں کریں
+pdfjs-find-match-case-checkbox-label = حروف مشابہ کریں
+pdfjs-find-entire-word-checkbox-label = تمام الفاظ
+pdfjs-find-reached-top = صفحہ کے شروع پر پہنچ گیا، نیچے سے جاری کیا
+pdfjs-find-reached-bottom = صفحہ کے اختتام پر پہنچ گیا، اوپر سے جاری کیا
+pdfjs-find-not-found = فقرا نہیں ملا
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = صفحہ چوڑائی
+pdfjs-page-scale-fit = صفحہ فٹنگ
+pdfjs-page-scale-auto = خودکار زوم
+pdfjs-page-scale-actual = اصل سائز
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = صفحہ { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF لوڈ کرتے وقت نقص آ گیا۔
+pdfjs-invalid-file-error = ناجائز یا خراب PDF مسل
+pdfjs-missing-file-error = PDF مسل غائب ہے۔
+pdfjs-unexpected-response-error = غیرمتوقع پیش کار جواب
+pdfjs-rendering-error = صفحہ بناتے ہوئے نقص آ گیا۔
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } نوٹ]
+
+## Password
+
+pdfjs-password-label = PDF مسل کھولنے کے لیے پاس ورڈ داخل کریں.
+pdfjs-password-invalid = ناجائز پاس ورڈ. براےؑ کرم دوبارہ کوشش کریں.
+pdfjs-password-ok-button = ٹھیک ہے
+pdfjs-password-cancel-button = منسوخ کریں
+pdfjs-web-fonts-disabled = ویب فانٹ نا اہل ہیں: شامل PDF فانٹ استعمال کرنے میں ناکام۔
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/uz/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/uz/viewer.ftl
new file mode 100644
index 0000000..8bc38e6
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/uz/viewer.ftl
@@ -0,0 +1,154 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Oldingi sahifa
+pdfjs-previous-button-label = Oldingi
+pdfjs-next-button =
+ .title = Keyingi sahifa
+pdfjs-next-button-label = Keyingi
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = /{ $pagesCount }
+pdfjs-zoom-out-button =
+ .title = Kichiklashtirish
+pdfjs-zoom-out-button-label = Kichiklashtirish
+pdfjs-zoom-in-button =
+ .title = Kattalashtirish
+pdfjs-zoom-in-button-label = Kattalashtirish
+pdfjs-zoom-select =
+ .title = Masshtab
+pdfjs-presentation-mode-button =
+ .title = Namoyish usuliga oʻtish
+pdfjs-presentation-mode-button-label = Namoyish usuli
+pdfjs-open-file-button =
+ .title = Faylni ochish
+pdfjs-open-file-button-label = Ochish
+pdfjs-print-button =
+ .title = Chop qilish
+pdfjs-print-button-label = Chop qilish
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Vositalar
+pdfjs-tools-button-label = Vositalar
+pdfjs-first-page-button =
+ .title = Birinchi sahifaga oʻtish
+pdfjs-first-page-button-label = Birinchi sahifaga oʻtish
+pdfjs-last-page-button =
+ .title = Soʻnggi sahifaga oʻtish
+pdfjs-last-page-button-label = Soʻnggi sahifaga oʻtish
+pdfjs-page-rotate-cw-button =
+ .title = Soat yoʻnalishi boʻyicha burish
+pdfjs-page-rotate-cw-button-label = Soat yoʻnalishi boʻyicha burish
+pdfjs-page-rotate-ccw-button =
+ .title = Soat yoʻnalishiga qarshi burish
+pdfjs-page-rotate-ccw-button-label = Soat yoʻnalishiga qarshi burish
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Hujjat xossalari
+pdfjs-document-properties-button-label = Hujjat xossalari
+pdfjs-document-properties-file-name = Fayl nomi:
+pdfjs-document-properties-file-size = Fayl hajmi:
+pdfjs-document-properties-title = Nomi:
+pdfjs-document-properties-author = Muallifi:
+pdfjs-document-properties-subject = Mavzusi:
+pdfjs-document-properties-keywords = Kalit so‘zlar
+pdfjs-document-properties-creation-date = Yaratilgan sanasi:
+pdfjs-document-properties-modification-date = O‘zgartirilgan sanasi
+pdfjs-document-properties-creator = Yaratuvchi:
+pdfjs-document-properties-producer = PDF ishlab chiqaruvchi:
+pdfjs-document-properties-version = PDF versiyasi:
+pdfjs-document-properties-page-count = Sahifa soni:
+
+##
+
+pdfjs-document-properties-close-button = Yopish
+
+## Print
+
+pdfjs-printing-not-supported = Diqqat: chop qilish bruzer tomonidan toʻliq qoʻllab-quvvatlanmaydi.
+pdfjs-printing-not-ready = Diqqat: PDF fayl chop qilish uchun toʻliq yuklanmadi.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Yon panelni yoqib/oʻchirib qoʻyish
+pdfjs-toggle-sidebar-button-label = Yon panelni yoqib/oʻchirib qoʻyish
+pdfjs-document-outline-button-label = Hujjat tuzilishi
+pdfjs-attachments-button =
+ .title = Ilovalarni ko‘rsatish
+pdfjs-attachments-button-label = Ilovalar
+pdfjs-thumbs-button =
+ .title = Nishonchalarni koʻrsatish
+pdfjs-thumbs-button-label = Nishoncha
+pdfjs-findbar-button =
+ .title = Hujjat ichidan topish
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = { $page } sahifa
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = { $page } sahifa nishonchasi
+
+## Find panel button title and messages
+
+pdfjs-find-previous-button =
+ .title = Soʻzlardagi oldingi hodisani topish
+pdfjs-find-previous-button-label = Oldingi
+pdfjs-find-next-button =
+ .title = Iboradagi keyingi hodisani topish
+pdfjs-find-next-button-label = Keyingi
+pdfjs-find-highlight-checkbox = Barchasini ajratib koʻrsatish
+pdfjs-find-match-case-checkbox-label = Katta-kichik harflarni farqlash
+pdfjs-find-reached-top = Hujjatning boshigacha yetib keldik, pastdan davom ettiriladi
+pdfjs-find-reached-bottom = Hujjatning oxiriga yetib kelindi, yuqoridan davom ettirladi
+pdfjs-find-not-found = Soʻzlar topilmadi
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Sahifa eni
+pdfjs-page-scale-fit = Sahifani moslashtirish
+pdfjs-page-scale-auto = Avtomatik masshtab
+pdfjs-page-scale-actual = Haqiqiy hajmi
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = PDF yuklanayotganda xato yuz berdi.
+pdfjs-invalid-file-error = Xato yoki buzuq PDF fayli.
+pdfjs-missing-file-error = PDF fayl kerak.
+pdfjs-unexpected-response-error = Kutilmagan server javobi.
+pdfjs-rendering-error = Sahifa renderlanayotganda xato yuz berdi.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Annotation]
+
+## Password
+
+pdfjs-password-label = PDF faylni ochish uchun parolni kiriting.
+pdfjs-password-invalid = Parol - notoʻgʻri. Qaytadan urinib koʻring.
+pdfjs-password-ok-button = OK
+pdfjs-web-fonts-disabled = Veb shriftlar oʻchirilgan: ichki PDF shriftlardan foydalanib boʻlmmaydi.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/vi/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/vi/viewer.ftl
new file mode 100644
index 0000000..ff3094d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/vi/viewer.ftl
@@ -0,0 +1,780 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Trang trước
+pdfjs-previous-button-label = Trước
+pdfjs-next-button =
+ .title = Trang Sau
+pdfjs-next-button-label = Tiếp
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Trang
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = trên { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } trên { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Thu nhỏ
+pdfjs-zoom-out-button-label = Thu nhỏ
+pdfjs-zoom-in-button =
+ .title = Phóng to
+pdfjs-zoom-in-button-label = Phóng to
+pdfjs-zoom-select =
+ .title = Thu phóng
+pdfjs-presentation-mode-button =
+ .title = Chuyển sang chế độ trình chiếu
+pdfjs-presentation-mode-button-label = Chế độ trình chiếu
+pdfjs-open-file-button =
+ .title = Mở tập tin
+pdfjs-open-file-button-label = Mở tập tin
+pdfjs-print-button =
+ .title = In
+pdfjs-print-button-label = In
+pdfjs-save-button =
+ .title = Lưu
+pdfjs-save-button-label = Lưu
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = Tải xuống
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = Tải xuống
+pdfjs-bookmark-button =
+ .title = Trang hiện tại (xem URL từ trang hiện tại)
+pdfjs-bookmark-button-label = Trang hiện tại
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Công cụ
+pdfjs-tools-button-label = Công cụ
+pdfjs-first-page-button =
+ .title = Về trang đầu
+pdfjs-first-page-button-label = Về trang đầu
+pdfjs-last-page-button =
+ .title = Đến trang cuối
+pdfjs-last-page-button-label = Đến trang cuối
+pdfjs-page-rotate-cw-button =
+ .title = Xoay theo chiều kim đồng hồ
+pdfjs-page-rotate-cw-button-label = Xoay theo chiều kim đồng hồ
+pdfjs-page-rotate-ccw-button =
+ .title = Xoay ngược chiều kim đồng hồ
+pdfjs-page-rotate-ccw-button-label = Xoay ngược chiều kim đồng hồ
+pdfjs-cursor-text-select-tool-button =
+ .title = Kích hoạt công cụ chọn vùng văn bản
+pdfjs-cursor-text-select-tool-button-label = Công cụ chọn vùng văn bản
+pdfjs-cursor-hand-tool-button =
+ .title = Kích hoạt công cụ con trỏ
+pdfjs-cursor-hand-tool-button-label = Công cụ con trỏ
+pdfjs-scroll-page-button =
+ .title = Sử dụng cuộn trang hiện tại
+pdfjs-scroll-page-button-label = Cuộn trang hiện tại
+pdfjs-scroll-vertical-button =
+ .title = Sử dụng cuộn dọc
+pdfjs-scroll-vertical-button-label = Cuộn dọc
+pdfjs-scroll-horizontal-button =
+ .title = Sử dụng cuộn ngang
+pdfjs-scroll-horizontal-button-label = Cuộn ngang
+pdfjs-scroll-wrapped-button =
+ .title = Sử dụng cuộn ngắt dòng
+pdfjs-scroll-wrapped-button-label = Cuộn ngắt dòng
+pdfjs-spread-none-button =
+ .title = Không nối rộng trang
+pdfjs-spread-none-button-label = Không có phân cách
+pdfjs-spread-odd-button =
+ .title = Nối trang bài bắt đầu với các trang được đánh số lẻ
+pdfjs-spread-odd-button-label = Phân cách theo số lẻ
+pdfjs-spread-even-button =
+ .title = Nối trang bài bắt đầu với các trang được đánh số chẵn
+pdfjs-spread-even-button-label = Phân cách theo số chẵn
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Thuộc tính của tài liệu…
+pdfjs-document-properties-button-label = Thuộc tính của tài liệu…
+pdfjs-document-properties-file-name = Tên tập tin:
+pdfjs-document-properties-file-size = Kích thước:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)
+pdfjs-document-properties-title = Tiêu đề:
+pdfjs-document-properties-author = Tác giả:
+pdfjs-document-properties-subject = Chủ đề:
+pdfjs-document-properties-keywords = Từ khóa:
+pdfjs-document-properties-creation-date = Ngày tạo:
+pdfjs-document-properties-modification-date = Ngày sửa đổi:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = Người tạo:
+pdfjs-document-properties-producer = Phần mềm tạo PDF:
+pdfjs-document-properties-version = Phiên bản PDF:
+pdfjs-document-properties-page-count = Tổng số trang:
+pdfjs-document-properties-page-size = Kích thước trang:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = khổ dọc
+pdfjs-document-properties-page-size-orientation-landscape = khổ ngang
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Thư
+pdfjs-document-properties-page-size-name-legal = Pháp lý
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = Xem nhanh trên web:
+pdfjs-document-properties-linearized-yes = Có
+pdfjs-document-properties-linearized-no = Không
+pdfjs-document-properties-close-button = Ðóng
+pdfjs-digital-signature-properties-view-certificate = Xem chứng chỉ
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = Nguyên nhân: { $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = Timestamp: { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures = Chữ ký thành phần ({ $count })
+
+## Print
+
+pdfjs-print-progress-message = Chuẩn bị trang để in…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Hủy bỏ
+pdfjs-printing-not-supported = Cảnh báo: In ấn không được hỗ trợ đầy đủ ở trình duyệt này.
+pdfjs-printing-not-ready = Cảnh báo: PDF chưa được tải hết để in.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Bật/Tắt thanh lề
+pdfjs-toggle-sidebar-notification-button =
+ .title = Bật tắt thanh lề (tài liệu bao gồm bản phác thảo/tập tin đính kèm/lớp)
+pdfjs-toggle-sidebar-button-label = Bật/Tắt thanh lề
+pdfjs-document-outline-button =
+ .title = Hiển thị tài liệu phác thảo (nhấp đúp vào để mở rộng/thu gọn tất cả các mục)
+pdfjs-document-outline-button-label = Bản phác tài liệu
+pdfjs-attachments-button =
+ .title = Hiện nội dung đính kèm
+pdfjs-attachments-button-label = Nội dung đính kèm
+pdfjs-layers-button =
+ .title = Hiển thị các lớp (nhấp đúp để đặt lại tất cả các lớp về trạng thái mặc định)
+pdfjs-layers-button-label = Lớp
+pdfjs-thumbs-button =
+ .title = Hiển thị ảnh thu nhỏ
+pdfjs-thumbs-button-label = Ảnh thu nhỏ
+pdfjs-current-outline-item-button =
+ .title = Tìm mục phác thảo hiện tại
+pdfjs-current-outline-item-button-label = Mục phác thảo hiện tại
+pdfjs-findbar-button =
+ .title = Tìm trong tài liệu
+pdfjs-findbar-button-label = Tìm
+pdfjs-additional-layers = Các lớp bổ sung
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Trang { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Ảnh thu nhỏ của trang { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = Chọn trang { $page }
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = Trang { $page } / { $total }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Tìm
+ .placeholder = Tìm trong tài liệu…
+pdfjs-find-previous-button =
+ .title = Tìm cụm từ ở phần trước
+pdfjs-find-previous-button-label = Trước
+pdfjs-find-next-button =
+ .title = Tìm cụm từ ở phần sau
+pdfjs-find-next-button-label = Tiếp
+pdfjs-find-highlight-checkbox = Đánh dấu tất cả
+pdfjs-find-match-case-checkbox-label = Phân biệt hoa, thường
+pdfjs-find-match-diacritics-checkbox-label = Khớp dấu phụ
+pdfjs-find-entire-word-checkbox-label = Toàn bộ từ
+pdfjs-find-reached-top = Đã đến phần đầu tài liệu, quay trở lại từ cuối
+pdfjs-find-reached-bottom = Đã đến phần cuối của tài liệu, quay trở lại từ đầu
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = { $current } trên { $total } kết quả
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = Tìm thấy hơn { $limit } kết quả
+pdfjs-find-not-found = Không tìm thấy cụm từ này
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Vừa chiều rộng
+pdfjs-page-scale-fit = Vừa chiều cao
+pdfjs-page-scale-auto = Tự động chọn kích thước
+pdfjs-page-scale-actual = Kích thước thực
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = Trang { $page }
+
+## Loading indicator messages
+
+pdfjs-loading-error = Lỗi khi tải tài liệu PDF.
+pdfjs-invalid-file-error = Tập tin PDF hỏng hoặc không hợp lệ.
+pdfjs-missing-file-error = Thiếu tập tin PDF.
+pdfjs-unexpected-response-error = Máy chủ có phản hồi lạ.
+pdfjs-rendering-error = Lỗi khi hiển thị trang.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Chú thích]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = Nhập mật khẩu để mở tập tin PDF này.
+pdfjs-password-invalid = Mật khẩu không đúng. Vui lòng thử lại.
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Hủy bỏ
+pdfjs-web-fonts-disabled = Phông chữ Web bị vô hiệu hóa: không thể sử dụng các phông chữ PDF được nhúng.
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = Văn bản
+pdfjs-editor-color-picker-free-text-input =
+ .title = Thay đổi màu chữ
+pdfjs-editor-free-text-button-label = Văn bản
+pdfjs-editor-ink-button =
+ .title = Vẽ
+pdfjs-editor-color-picker-ink-input =
+ .title = Thay đổi màu vẽ
+pdfjs-editor-ink-button-label = Vẽ
+pdfjs-editor-stamp-button =
+ .title = Thêm hoặc chỉnh sửa hình ảnh
+pdfjs-editor-stamp-button-label = Thêm hoặc chỉnh sửa hình ảnh
+pdfjs-editor-highlight-button =
+ .title = Đánh dấu
+pdfjs-editor-highlight-button-label = Đánh dấu
+pdfjs-highlight-floating-button1 =
+ .title = Đánh dấu
+ .aria-label = Đánh dấu
+pdfjs-highlight-floating-button-label = Đánh dấu
+pdfjs-comment-floating-button =
+ .title = Chú thích
+ .aria-label = Chú thích
+pdfjs-comment-floating-button-label = Chú thích
+pdfjs-editor-comment-button =
+ .title = Chú thích
+ .aria-label = Chú thích
+pdfjs-editor-comment-button-label = Chú thích
+pdfjs-editor-signature-button =
+ .title = Thêm chữ ký
+pdfjs-editor-signature-button-label = Thêm chữ ký
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = Trình chỉnh sửa đánh dấu
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = Trình chỉnh sửa bản vẽ
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = Trình chỉnh sửa chữ ký: { $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = Trình chỉnh sửa hình ảnh
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = Xóa bản vẽ
+pdfjs-editor-remove-freetext-button =
+ .title = Xóa văn bản
+pdfjs-editor-remove-stamp-button =
+ .title = Xóa ảnh
+pdfjs-editor-remove-highlight-button =
+ .title = Xóa phần đánh dấu
+pdfjs-editor-remove-signature-button =
+ .title = Xoá chữ ký
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = Màu
+pdfjs-editor-free-text-size-input = Kích cỡ
+pdfjs-editor-ink-color-input = Màu
+pdfjs-editor-ink-thickness-input = Độ dày
+pdfjs-editor-ink-opacity-input = Độ mờ
+pdfjs-editor-stamp-add-image-button =
+ .title = Thêm hình ảnh
+pdfjs-editor-stamp-add-image-button-label = Thêm hình ảnh
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = Độ dày
+pdfjs-editor-free-highlight-thickness-title =
+ .title = Thay đổi độ dày khi đánh dấu các mục không phải là văn bản
+pdfjs-editor-add-signature-container =
+ .aria-label = Kiểm soát chữ ký và chữ ký đã lưu
+pdfjs-editor-signature-add-signature-button =
+ .title = Thêm chữ ký mới
+pdfjs-editor-signature-add-signature-button-label = Thêm chữ ký mới
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = Đã lưu chữ ký: { $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = Trình chỉnh sửa văn bản
+ .default-content = Bắt đầu nhập…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title = Chú thích
+pdfjs-editor-comments-sidebar-close-button =
+ .title = Đóng thanh lề
+ .aria-label = Đóng thanh lề
+pdfjs-editor-comments-sidebar-close-button-label = Đóng thanh lề
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = Bạn thấy điều gì đáng chú ý? Hãy đánh dấu và để lại chú thích.
+pdfjs-editor-comments-sidebar-no-comments-link = Tìm hiểu thêm
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = Văn bản thay thế
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = Chỉnh sửa văn bản thay thế
+pdfjs-editor-alt-text-dialog-label = Chọn một lựa chọn
+pdfjs-editor-alt-text-dialog-description = Văn bản thay thế sẽ hữu ích khi mọi người không thể thấy hình ảnh hoặc khi hình ảnh không tải.
+pdfjs-editor-alt-text-add-description-label = Thêm một mô tả
+pdfjs-editor-alt-text-add-description-description = Hãy nhắm tới 1-2 câu mô tả chủ đề, bối cảnh hoặc hành động.
+pdfjs-editor-alt-text-mark-decorative-label = Đánh dấu là trang trí
+pdfjs-editor-alt-text-mark-decorative-description = Điều này được sử dụng cho các hình ảnh trang trí, như đường viền hoặc watermark.
+pdfjs-editor-alt-text-cancel-button = Hủy bỏ
+pdfjs-editor-alt-text-save-button = Lưu
+pdfjs-editor-alt-text-decorative-tooltip = Đã đánh dấu là trang trí
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = Ví dụ: “Một thanh niên ngồi xuống bàn để thưởng thức một bữa ăn”
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = Văn bản thay thế
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = Trên cùng bên trái — thay đổi kích thước
+pdfjs-editor-resizer-top-middle =
+ .aria-label = Trên cùng ở giữa — thay đổi kích thước
+pdfjs-editor-resizer-top-right =
+ .aria-label = Trên cùng bên phải — thay đổi kích thước
+pdfjs-editor-resizer-middle-right =
+ .aria-label = Ở giữa bên phải — thay đổi kích thước
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = Dưới cùng bên phải — thay đổi kích thước
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = Ở giữa dưới cùng — thay đổi kích thước
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = Góc dưới bên trái — thay đổi kích thước
+pdfjs-editor-resizer-middle-left =
+ .aria-label = Ở giữa bên trái — thay đổi kích thước
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = Màu đánh dấu
+pdfjs-editor-colorpicker-button =
+ .title = Thay đổi màu
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = Lựa chọn màu sắc
+pdfjs-editor-colorpicker-yellow =
+ .title = Vàng
+pdfjs-editor-colorpicker-green =
+ .title = Xanh lục
+pdfjs-editor-colorpicker-blue =
+ .title = Xanh dương
+pdfjs-editor-colorpicker-pink =
+ .title = Hồng
+pdfjs-editor-colorpicker-red =
+ .title = Đỏ
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = Hiện tất cả
+pdfjs-editor-highlight-show-all-button =
+ .title = Hiện tất cả
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = Chỉnh sửa văn bản thay thế (mô tả hình ảnh)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = Thêm văn bản thay thế (mô tả hình ảnh)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = Viết mô tả của bạn ở đây…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = Mô tả ngắn gọn dành cho người không xem được ảnh hoặc khi không thể tải ảnh.
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = Văn bản thay thế này được tạo tự động và có thể không chính xác.
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = Tìm hiểu thêm
+pdfjs-editor-new-alt-text-create-automatically-button-label = Tạo văn bản thay thế tự động
+pdfjs-editor-new-alt-text-not-now-button = Để sau
+pdfjs-editor-new-alt-text-error-title = Không thể tạo tự động văn bản thay thế
+pdfjs-editor-new-alt-text-error-description = Vui lòng viết văn bản thay thế của riêng bạn hoặc thử lại sau.
+pdfjs-editor-new-alt-text-error-close-button = Đóng
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = Đang tải xuống mô hình AI văn bản thay thế ({ $downloadedSize } / { $totalSize } MB)
+ .aria-valuetext = Đang tải xuống mô hình AI văn bản thay thế ({ $downloadedSize } / { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = Đã thêm văn bản thay thế
+pdfjs-editor-new-alt-text-added-button-label = Đã thêm văn bản thay thế
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = Thiếu văn bản thay thế
+pdfjs-editor-new-alt-text-missing-button-label = Thiếu văn bản thay thế
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = Xem lại văn bản thay thế
+pdfjs-editor-new-alt-text-to-review-button-label = Xem lại văn bản thay thế
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Được tạo tự động: { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = Cài đặt văn bản thay thế của hình ảnh
+pdfjs-image-alt-text-settings-button-label = Cài đặt văn bản thay thế của hình ảnh
+pdfjs-editor-alt-text-settings-dialog-label = Cài đặt văn bản thay thế của hình ảnh
+pdfjs-editor-alt-text-settings-automatic-title = Văn bản thay thế tự động
+pdfjs-editor-alt-text-settings-create-model-button-label = Tạo văn bản thay thế tự động
+pdfjs-editor-alt-text-settings-create-model-description = Đề xuất mô tả giúp ích cho những người không xem được ảnh hoặc khi không thể tải ảnh.
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = Mô hình AI văn bản khác ({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = Chạy cục bộ trên thiết bị của bạn để dữ liệu của bạn luôn ở chế độ riêng tư. Bắt buộc đối với văn bản thay thế tự động.
+pdfjs-editor-alt-text-settings-delete-model-button = Xóa
+pdfjs-editor-alt-text-settings-download-model-button = Tải xuống
+pdfjs-editor-alt-text-settings-downloading-model-button = Đang tải xuống…
+pdfjs-editor-alt-text-settings-editor-title = Trình soạn thảo văn bản thay thế
+pdfjs-editor-alt-text-settings-show-dialog-button-label = Hiển thị ngay trình soạn thảo văn bản thay thế khi thêm hình ảnh
+pdfjs-editor-alt-text-settings-show-dialog-description = Giúp bạn đảm bảo tất cả hình ảnh của bạn đều có văn bản thay thế.
+pdfjs-editor-alt-text-settings-close-button = Đóng
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = Đã thêm tô sáng
+pdfjs-editor-freetext-added-alert = Đã thêm chữ
+pdfjs-editor-ink-added-alert = Đã thêm bản vẽ
+pdfjs-editor-stamp-added-alert = Đã thêm ảnh
+pdfjs-editor-signature-added-alert = Đã thêm chữ ký
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = Đã xóa đánh dấu
+pdfjs-editor-undo-bar-message-freetext = Đã xóa văn bản
+pdfjs-editor-undo-bar-message-ink = Đã xóa bản vẽ
+pdfjs-editor-undo-bar-message-stamp = Đã xóa hình ảnh
+pdfjs-editor-undo-bar-message-signature = Chữ ký đã bị xoá
+pdfjs-editor-undo-bar-message-comment = Đã xoá chú thích
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = { $count } chú thích đã bị xóa
+pdfjs-editor-undo-bar-undo-button =
+ .title = Hoàn tác
+pdfjs-editor-undo-bar-undo-button-label = Hoàn tác
+pdfjs-editor-undo-bar-close-button =
+ .title = Đóng
+pdfjs-editor-undo-bar-close-button-label = Đóng
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = Phương thức này cho phép người dùng tạo một chữ ký để thêm vào tài liệu PDF. Người dùng có thể chỉnh sửa tên (cũng đóng vai trò là văn bản thay thế) và tùy chọn lưu chữ ký để sử dụng nhiều lần.
+pdfjs-editor-add-signature-dialog-title = Thêm chữ ký
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = Đánh văn bản
+ .title = Đánh văn bản
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = Vẽ
+ .title = Vẽ
+pdfjs-editor-add-signature-image-button = Hình ảnh
+ .title = Hình ảnh
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = Nhập chữ ký của bạn
+ .placeholder = Nhập chữ ký của bạn
+pdfjs-editor-add-signature-draw-placeholder = Vẽ chữ ký của bạn
+pdfjs-editor-add-signature-draw-thickness-range-label = Độ dày
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = Độ dày bút vẽ: { $thickness }
+pdfjs-editor-add-signature-image-placeholder = Kéo một tập tin tại đây để tải lên
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] Hoặc chọn hình ảnh
+ *[other] Hoặc chọn hình ảnh
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = Mô tả (văn bản thay thế)
+pdfjs-editor-add-signature-description-input =
+ .title = Mô tả (văn bản thay thế)
+pdfjs-editor-add-signature-description-default-when-drawing = Chữ ký
+pdfjs-editor-add-signature-clear-button-label = Xoá chữ ký
+pdfjs-editor-add-signature-clear-button =
+ .title = Xoá chữ ký
+pdfjs-editor-add-signature-save-checkbox = Lưu chữ ký
+pdfjs-editor-add-signature-save-warning-message = Bạn đã đạt đến giới hạn 5 chữ ký đã lưu. Hãy xóa một cái để lưu thêm.
+pdfjs-editor-add-signature-image-upload-error-title = Không thể tải lên hình ảnh
+pdfjs-editor-add-signature-image-upload-error-description = Kiểm tra kết nối mạng của bạn hoặc thử hình ảnh khác.
+pdfjs-editor-add-signature-image-no-data-error-title = Không thể chuyển đổi hình ảnh này thành chữ ký
+pdfjs-editor-add-signature-image-no-data-error-description = Vui lòng thử tải lên một hình ảnh khác.
+pdfjs-editor-add-signature-error-close-button = Đóng
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = Hủy bỏ
+pdfjs-editor-add-signature-add-button = Thêm
+pdfjs-editor-edit-signature-update-button = Cập nhật
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = Chỉnh sửa chú thích
+pdfjs-editor-edit-comment-popup-button =
+ .title = Chỉnh sửa chú thích
+pdfjs-editor-delete-comment-popup-button-label = Xoá chú thích
+pdfjs-editor-delete-comment-popup-button =
+ .title = Xoá chú thích
+pdfjs-show-comment-button =
+ .title = Hiển thị chú thích
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = Chỉnh sửa chú thích
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = Cập nhật
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = Thêm chú thích
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = Thêm
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = Bắt đầu nhập…
+pdfjs-editor-edit-comment-dialog-cancel-button = Hủy bỏ
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = Thêm chú thích
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = Bật tắt thanh lề (tài liệu bao gồm hình thu nhỏ/phác thảo/tập tin đính kèm/lớp)
+pdfjs-toggle-views-manager-button1-label = Quản lý trang
+pdfjs-views-manager-sidebar =
+ .aria-label = Thanh lề
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = Công cụ điều chỉnh kích thước thanh lề
+pdfjs-views-manager-view-selector-button =
+ .title = Chế độ hiển thị
+pdfjs-views-manager-view-selector-button-label = Chế độ hiển thị
+pdfjs-views-manager-pages-title = Trang
+pdfjs-views-manager-outlines-title1 = Bản phác thảo tài liệu
+ .title = Bản phác thảo tài liệu (nhấp đúp chuột để mở rộng/thu gọn tất cả các mục)
+pdfjs-views-manager-attachments-title = Đính kèm
+pdfjs-views-manager-layers-title1 = Lớp
+ .title = Lớp (nhấp đúp chuột để đặt lại tất cả các lớp về trạng thái mặc định.)
+pdfjs-views-manager-pages-option-label = Trang
+pdfjs-views-manager-outlines-option-label = Bản phác thảo tài liệu
+pdfjs-views-manager-attachments-option-label = Đính kèm
+pdfjs-views-manager-layers-option-label = Lớp
+pdfjs-views-manager-add-file-button =
+ .title = Thêm tập tin
+pdfjs-views-manager-add-file-button-label = Thêm tập tin
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label = { $count } đã chọn
+pdfjs-views-manager-pages-status-none-action-label = Chọn trang
+pdfjs-views-manager-pages-status-action-button-label = Quản lý
+pdfjs-views-manager-pages-status-copy-button-label = Sao chép
+pdfjs-views-manager-pages-status-cut-button-label = Cắt
+pdfjs-views-manager-pages-status-delete-button-label = Dán
+pdfjs-views-manager-pages-status-export-selected-button-label = Xuất các mục đã chọn…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label = Đã cắt { $count } trang
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label = Đã sao chép { $count } trang
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label = Đã xoá { $count } trang
+pdfjs-views-manager-pages-status-waiting-ready-label = Đang chuẩn bị tập tin của bạn…
+pdfjs-views-manager-pages-status-waiting-uploading-label = Đang tải lên tập tin…
+pdfjs-views-manager-status-warning-cut-label = Không thể cắt. Vui lòng làm mới trang và thử lại.
+pdfjs-views-manager-status-warning-copy-label = Không thể sao chép. Vui lòng làm mới trang và thử lại.
+pdfjs-views-manager-status-warning-delete-label = Không thể xoá. Vui lòng làm mới trang và thử lại.
+pdfjs-views-manager-status-warning-save-label = Không thể lưu. Vui lòng làm mới trang và thử lại.
+pdfjs-views-manager-status-undo-button-label = Hoàn tác
+pdfjs-views-manager-status-done-button-label = Xong
+pdfjs-views-manager-status-close-button =
+ .title = Đóng
+pdfjs-views-manager-status-close-button-label = Đóng
+pdfjs-views-manager-paste-button-label = Dán
+pdfjs-views-manager-paste-button-before =
+ .title = Dán trước trang đầu
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = Dán sau trang { $page }
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = MỚI
+pdfjs-views-manager-waiting-for-file = Đang tải lên tập tin…
+pdfjs-toggle-views-manager-button1 =
+ .title = Quản lý trang
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = Thuộc tính chữ ký điện tử
+ .aria-label = Thuộc tính chữ ký điện tử
+pdfjs-digital-signature-properties-button-label = Thuộc tính chữ ký điện tử
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = Tài liệu đã được ký bằng chữ ký điện tử hợp lệ
+pdfjs-digital-signature-properties-banner-unknown = Tài liệu đã được ký nhưng không thể xác minh { $count } chữ ký điện tử
+pdfjs-digital-signature-properties-banner-untrusted = Tài liệu được ký bằng { $count } chứng chỉ không đáng tin cậy
+pdfjs-digital-signature-properties-banner-expired = Tài liệu được ký bằng { $count } chứng chỉ đã hết hạn
+pdfjs-digital-signature-properties-banner-invalid = Tài liệu có { $count } chữ ký điện tử không hợp lệ
+pdfjs-digital-signature-properties-banner-revoked = Tài liệu được ký bằng { $count } chứng chỉ đã bị thu hồi
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = Trạng thái: Chữ ký đã được xác minh
+pdfjs-digital-signature-properties-status-invalid = Trạng thái: Chữ ký không hợp lệ
+pdfjs-digital-signature-properties-status-unknown = Trạng thái: Không thể xác minh (không được hỗ trợ)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = Chứng chỉ: Đáng tin cậy ({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = Chứng chỉ: Không khả dụng
+pdfjs-digital-signature-properties-certificate-untrusted = Chứng chỉ: Không đáng tin cậy
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Chứng chỉ: Người cấp không xác định ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = Chứng chỉ: Tự ký ({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Chứng chỉ: Người cấp không đáng tin cậy ({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = Chứng chỉ: Đã hết hạn
+pdfjs-digital-signature-properties-certificate-expired-with-date = Chứng chỉ: Đã hết hạn ({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = Chứng chỉ: Đã bị thu hồi
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = Xoá chữ ký đã lưu
+pdfjs-editor-delete-signature-button-label1 = Xoá chữ ký đã lưu
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = Chỉnh sửa mô tả
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = Chỉnh sửa mô tả
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/wo/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/wo/viewer.ftl
new file mode 100644
index 0000000..22c6a3f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/wo/viewer.ftl
@@ -0,0 +1,100 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Xët wi jiitu
+pdfjs-previous-button-label = Bi jiitu
+pdfjs-next-button =
+ .title = Xët wi ci topp
+pdfjs-next-button-label = Bi ci topp
+pdfjs-zoom-out-button =
+ .title = Wàññi
+pdfjs-zoom-out-button-label = Wàññi
+pdfjs-zoom-in-button =
+ .title = Yaatal
+pdfjs-zoom-in-button-label = Yaatal
+pdfjs-zoom-select =
+ .title = Yambalaŋ
+pdfjs-presentation-mode-button =
+ .title = Wañarñil ci anamu wone
+pdfjs-presentation-mode-button-label = Anamu Wone
+pdfjs-open-file-button =
+ .title = Ubbi benn dencukaay
+pdfjs-open-file-button-label = Ubbi
+pdfjs-print-button =
+ .title = Móol
+pdfjs-print-button-label = Móol
+
+## Document properties dialog
+
+pdfjs-document-properties-title = Bopp:
+
+## Print
+
+pdfjs-printing-not-supported = Artu: Joowkat bii nanguwul lool mool.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-thumbs-button =
+ .title = Wone nataal yu ndaw yi
+pdfjs-thumbs-button-label = Nataal yu ndaw yi
+pdfjs-findbar-button =
+ .title = Gis ci biir jukki bi
+pdfjs-findbar-button-label = Wut
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Xët { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Wiñet bu xët { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-previous-button =
+ .title = Seet beneen kaddu bu ni mel te jiitu
+pdfjs-find-previous-button-label = Bi jiitu
+pdfjs-find-next-button =
+ .title = Seet beneen kaddu bu ni mel
+pdfjs-find-next-button-label = Bi ci topp
+pdfjs-find-highlight-checkbox = Melaxal lépp
+pdfjs-find-match-case-checkbox-label = Sàmm jëmmalin wi
+pdfjs-find-reached-top = Jot nañu ndorteel xët wi, kontine dale ko ci suuf
+pdfjs-find-reached-bottom = Jot nañu jeexitalu xët wi, kontine ci ndorte
+pdfjs-find-not-found = Gisiñu kaddu gi
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Yaatuwaay bu mët
+pdfjs-page-scale-fit = Xët lëmm
+pdfjs-page-scale-auto = Yambalaŋ ci saa si
+pdfjs-page-scale-actual = Dayo bi am
+
+## Loading indicator messages
+
+pdfjs-loading-error = Am na njumte ci yebum dencukaay PDF bi.
+pdfjs-invalid-file-error = Dencukaay PDF bi baaxul walla mu sankar.
+pdfjs-rendering-error = Am njumte bu am bi xët bi di wonewu.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [Karmat { $type }]
+
+## Password
+
+pdfjs-password-ok-button = OK
+pdfjs-password-cancel-button = Neenal
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/xh/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/xh/viewer.ftl
new file mode 100644
index 0000000..a55157a
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/xh/viewer.ftl
@@ -0,0 +1,179 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = Iphepha langaphambili
+pdfjs-previous-button-label = Okwangaphambili
+pdfjs-next-button =
+ .title = Iphepha elilandelayo
+pdfjs-next-button-label = Okulandelayo
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = Iphepha
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = kwali- { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } kwali { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = Bhekelisela Kudana
+pdfjs-zoom-out-button-label = Bhekelisela Kudana
+pdfjs-zoom-in-button =
+ .title = Sondeza Kufuphi
+pdfjs-zoom-in-button-label = Sondeza Kufuphi
+pdfjs-zoom-select =
+ .title = Yandisa / Nciphisa
+pdfjs-presentation-mode-button =
+ .title = Tshintshela kwimo yonikezelo
+pdfjs-presentation-mode-button-label = Imo yonikezelo
+pdfjs-open-file-button =
+ .title = Vula Ifayile
+pdfjs-open-file-button-label = Vula
+pdfjs-print-button =
+ .title = Printa
+pdfjs-print-button-label = Printa
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = Izixhobo zemiyalelo
+pdfjs-tools-button-label = Izixhobo zemiyalelo
+pdfjs-first-page-button =
+ .title = Yiya kwiphepha lokuqala
+pdfjs-first-page-button-label = Yiya kwiphepha lokuqala
+pdfjs-last-page-button =
+ .title = Yiya kwiphepha lokugqibela
+pdfjs-last-page-button-label = Yiya kwiphepha lokugqibela
+pdfjs-page-rotate-cw-button =
+ .title = Jikelisa ngasekunene
+pdfjs-page-rotate-cw-button-label = Jikelisa ngasekunene
+pdfjs-page-rotate-ccw-button =
+ .title = Jikelisa ngasekhohlo
+pdfjs-page-rotate-ccw-button-label = Jikelisa ngasekhohlo
+pdfjs-cursor-text-select-tool-button =
+ .title = Vumela iSixhobo sokuKhetha iTeksti
+pdfjs-cursor-text-select-tool-button-label = ISixhobo sokuKhetha iTeksti
+pdfjs-cursor-hand-tool-button =
+ .title = Yenza iSixhobo seSandla siSebenze
+pdfjs-cursor-hand-tool-button-label = ISixhobo seSandla
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = Iipropati zoxwebhu…
+pdfjs-document-properties-button-label = Iipropati zoxwebhu…
+pdfjs-document-properties-file-name = Igama lefayile:
+pdfjs-document-properties-file-size = Isayizi yefayile:
+pdfjs-document-properties-title = Umxholo:
+pdfjs-document-properties-author = Umbhali:
+pdfjs-document-properties-subject = Umbandela:
+pdfjs-document-properties-keywords = Amagama aphambili:
+pdfjs-document-properties-creation-date = Umhla wokwenziwa kwayo:
+pdfjs-document-properties-modification-date = Umhla wokulungiswa kwayo:
+pdfjs-document-properties-creator = Umntu oyenzileyo:
+pdfjs-document-properties-producer = Umvelisi we-PDF:
+pdfjs-document-properties-version = Uhlelo lwe-PDF:
+pdfjs-document-properties-page-count = Inani lamaphepha:
+
+##
+
+pdfjs-document-properties-close-button = Vala
+
+## Print
+
+pdfjs-print-progress-message = Ilungisa uxwebhu ukuze iprinte…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = Rhoxisa
+pdfjs-printing-not-supported = Isilumkiso: Ukuprinta akuxhaswa ngokupheleleyo yile bhrawuza.
+pdfjs-printing-not-ready = Isilumkiso: IPDF ayihlohlwanga ngokupheleleyo ukwenzela ukuprinta.
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = Togola ngebha eseCaleni
+pdfjs-toggle-sidebar-button-label = Togola ngebha eseCaleni
+pdfjs-document-outline-button =
+ .title = Bonisa uLwandlalo loXwebhu (cofa kabini ukuze wandise/diliza zonke izinto)
+pdfjs-document-outline-button-label = Isishwankathelo soxwebhu
+pdfjs-attachments-button =
+ .title = Bonisa iziqhotyoshelwa
+pdfjs-attachments-button-label = Iziqhoboshelo
+pdfjs-thumbs-button =
+ .title = Bonisa ukrobiso kumfanekiso
+pdfjs-thumbs-button-label = Ukrobiso kumfanekiso
+pdfjs-findbar-button =
+ .title = Fumana kuXwebhu
+pdfjs-findbar-button-label = Fumana
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = Iphepha { $page }
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = Ukrobiso kumfanekiso wephepha { $page }
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = Fumana
+ .placeholder = Fumana kuXwebhu…
+pdfjs-find-previous-button =
+ .title = Fumanisa isenzeko sangaphambili sebinzana lamagama
+pdfjs-find-previous-button-label = Okwangaphambili
+pdfjs-find-next-button =
+ .title = Fumanisa isenzeko esilandelayo sebinzana lamagama
+pdfjs-find-next-button-label = Okulandelayo
+pdfjs-find-highlight-checkbox = Qaqambisa konke
+pdfjs-find-match-case-checkbox-label = Tshatisa ngobukhulu bukanobumba
+pdfjs-find-reached-top = Ufike ngaphezulu ephepheni, kusukwa ngezantsi
+pdfjs-find-reached-bottom = Ufike ekupheleni kwephepha, kusukwa ngaphezulu
+pdfjs-find-not-found = Ibinzana alifunyenwanga
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = Ububanzi bephepha
+pdfjs-page-scale-fit = Ukulinganiswa kwephepha
+pdfjs-page-scale-auto = Ukwandisa/Ukunciphisa Ngokwayo
+pdfjs-page-scale-actual = Ubungakanani bokwenene
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## Loading indicator messages
+
+pdfjs-loading-error = Imposiso yenzekile xa kulayishwa i-PDF.
+pdfjs-invalid-file-error = Ifayile ye-PDF engeyiyo okanye eyonakalisiweyo.
+pdfjs-missing-file-error = Ifayile ye-PDF edukileyo.
+pdfjs-unexpected-response-error = Impendulo yeseva engalindelekanga.
+pdfjs-rendering-error = Imposiso yenzekile xa bekunikezelwa iphepha.
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } Ubhalo-nqaku]
+
+## Password
+
+pdfjs-password-label = Faka ipasiwedi ukuze uvule le fayile yePDF.
+pdfjs-password-invalid = Ipasiwedi ayisebenzi. Nceda uzame kwakhona.
+pdfjs-password-ok-button = KULUNGILE
+pdfjs-password-cancel-button = Rhoxisa
+pdfjs-web-fonts-disabled = Iifonti zewebhu ziqhwalelisiwe: ayikwazi ukusebenzisa iifonti ze-PDF ezincanyathelisiweyo.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/zh-CN/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/zh-CN/viewer.ftl
new file mode 100644
index 0000000..29f4364
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/zh-CN/viewer.ftl
@@ -0,0 +1,761 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = 上一页
+pdfjs-previous-button-label = 上一页
+pdfjs-next-button =
+ .title = 下一页
+pdfjs-next-button-label = 下一页
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = 页面
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = / { $pagesCount }
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = ({ $pageNumber } / { $pagesCount })
+pdfjs-zoom-out-button =
+ .title = 缩小
+pdfjs-zoom-out-button-label = 缩小
+pdfjs-zoom-in-button =
+ .title = 放大
+pdfjs-zoom-in-button-label = 放大
+pdfjs-zoom-select =
+ .title = 缩放
+pdfjs-presentation-mode-button =
+ .title = 切换到演示模式
+pdfjs-presentation-mode-button-label = 演示模式
+pdfjs-open-file-button =
+ .title = 打开文件
+pdfjs-open-file-button-label = 打开
+pdfjs-print-button =
+ .title = 打印
+pdfjs-print-button-label = 打印
+pdfjs-save-button =
+ .title = 保存
+pdfjs-save-button-label = 保存
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = 下载
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = 下载
+pdfjs-bookmark-button =
+ .title = 当前页面(在当前页面查看 URL)
+pdfjs-bookmark-button-label = 当前页面
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = 工具
+pdfjs-tools-button-label = 工具
+pdfjs-first-page-button =
+ .title = 转到第一页
+pdfjs-first-page-button-label = 转到第一页
+pdfjs-last-page-button =
+ .title = 转到最后一页
+pdfjs-last-page-button-label = 转到最后一页
+pdfjs-page-rotate-cw-button =
+ .title = 顺时针旋转
+pdfjs-page-rotate-cw-button-label = 顺时针旋转
+pdfjs-page-rotate-ccw-button =
+ .title = 逆时针旋转
+pdfjs-page-rotate-ccw-button-label = 逆时针旋转
+pdfjs-cursor-text-select-tool-button =
+ .title = 启用文本选择工具
+pdfjs-cursor-text-select-tool-button-label = 文本选择工具
+pdfjs-cursor-hand-tool-button =
+ .title = 启用手形工具
+pdfjs-cursor-hand-tool-button-label = 手形工具
+pdfjs-scroll-page-button =
+ .title = 使用页面滚动
+pdfjs-scroll-page-button-label = 页面滚动
+pdfjs-scroll-vertical-button =
+ .title = 使用垂直滚动
+pdfjs-scroll-vertical-button-label = 垂直滚动
+pdfjs-scroll-horizontal-button =
+ .title = 使用水平滚动
+pdfjs-scroll-horizontal-button-label = 水平滚动
+pdfjs-scroll-wrapped-button =
+ .title = 使用平铺滚动
+pdfjs-scroll-wrapped-button-label = 平铺滚动
+pdfjs-spread-none-button =
+ .title = 不加入衔接页
+pdfjs-spread-none-button-label = 单页视图
+pdfjs-spread-odd-button =
+ .title = 加入衔接页使奇数页作为起始页
+pdfjs-spread-odd-button-label = 双页视图
+pdfjs-spread-even-button =
+ .title = 加入衔接页使偶数页作为起始页
+pdfjs-spread-even-button-label = 书籍视图
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = 文档属性…
+pdfjs-document-properties-button-label = 文档属性…
+pdfjs-document-properties-file-name = 文件名:
+pdfjs-document-properties-file-size = 文件大小:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB({ $b } 字节)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB({ $b } 字节)
+pdfjs-document-properties-title = 标题:
+pdfjs-document-properties-author = 作者:
+pdfjs-document-properties-subject = 主题:
+pdfjs-document-properties-keywords = 关键词:
+pdfjs-document-properties-creation-date = 创建日期:
+pdfjs-document-properties-modification-date = 修改日期:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = 创建者:
+pdfjs-document-properties-producer = PDF 生成器:
+pdfjs-document-properties-version = PDF 版本:
+pdfjs-document-properties-page-count = 页数:
+pdfjs-document-properties-page-size = 页面大小:
+pdfjs-document-properties-page-size-unit-inches = 英寸
+pdfjs-document-properties-page-size-unit-millimeters = 毫米
+pdfjs-document-properties-page-size-orientation-portrait = 纵向
+pdfjs-document-properties-page-size-orientation-landscape = 横向
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit }({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit }({ $name },{ $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = 快速 Web 视图:
+pdfjs-document-properties-linearized-yes = 是
+pdfjs-document-properties-linearized-no = 否
+pdfjs-document-properties-close-button = 关闭
+pdfjs-digital-signature-properties-view-certificate = 查看证书
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = 原因:{ $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = 时间戳:{ DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Print
+
+pdfjs-print-progress-message = 正在准备打印文档…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = 取消
+pdfjs-printing-not-supported = 警告:此浏览器尚未完整支持打印功能。
+pdfjs-printing-not-ready = 警告:此 PDF 未完成加载,无法打印。
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = 打开/关闭侧栏
+pdfjs-toggle-sidebar-notification-button =
+ .title = 打开/关闭侧栏(文档所含的大纲/附件/图层)
+pdfjs-toggle-sidebar-button-label = 打开/关闭侧栏
+pdfjs-document-outline-button =
+ .title = 显示文档大纲(双击展开/折叠所有项)
+pdfjs-document-outline-button-label = 文档大纲
+pdfjs-attachments-button =
+ .title = 显示附件
+pdfjs-attachments-button-label = 附件
+pdfjs-layers-button =
+ .title = 显示图层(双击即可将所有图层重置为默认状态)
+pdfjs-layers-button-label = 图层
+pdfjs-thumbs-button =
+ .title = 显示缩略图
+pdfjs-thumbs-button-label = 缩略图
+pdfjs-current-outline-item-button =
+ .title = 查找当前大纲项目
+pdfjs-current-outline-item-button-label = 当前大纲项目
+pdfjs-findbar-button =
+ .title = 在文档中查找
+pdfjs-findbar-button-label = 查找
+pdfjs-additional-layers = 其他图层
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = 第 { $page } 页
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = 页面 { $page } 的缩略图
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = 选择第 { $page } 页
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = 第 { $page } / { $total } 页
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = 查找
+ .placeholder = 在文档中查找…
+pdfjs-find-previous-button =
+ .title = 查找词语上一次出现的位置
+pdfjs-find-previous-button-label = 上一页
+pdfjs-find-next-button =
+ .title = 查找词语后一次出现的位置
+pdfjs-find-next-button-label = 下一页
+pdfjs-find-highlight-checkbox = 全部高亮显示
+pdfjs-find-match-case-checkbox-label = 区分大小写
+pdfjs-find-match-diacritics-checkbox-label = 匹配变音符号
+pdfjs-find-entire-word-checkbox-label = 全词匹配
+pdfjs-find-reached-top = 到达文档开头,从末尾继续
+pdfjs-find-reached-bottom = 到达文档末尾,从开头继续
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = 第 { $current } 项,共找到 { $total } 个匹配项
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = 匹配超过 { $limit } 项
+pdfjs-find-not-found = 找不到指定词语
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = 适合页宽
+pdfjs-page-scale-fit = 适合页面
+pdfjs-page-scale-auto = 自动缩放
+pdfjs-page-scale-actual = 实际大小
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = 第 { $page } 页
+
+## Loading indicator messages
+
+pdfjs-loading-error = 加载 PDF 时发生错误。
+pdfjs-invalid-file-error = 无效或损坏的 PDF 文件。
+pdfjs-missing-file-error = 缺少 PDF 文件。
+pdfjs-unexpected-response-error = 意外的服务器响应。
+pdfjs-rendering-error = 渲染页面时发生错误。
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } 注释]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = 输入密码以打开此 PDF 文件。
+pdfjs-password-invalid = 密码无效。请重试。
+pdfjs-password-ok-button = 确定
+pdfjs-password-cancel-button = 取消
+pdfjs-web-fonts-disabled = Web 字体已被禁用:无法使用嵌入的 PDF 字体。
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = 文本
+pdfjs-editor-color-picker-free-text-input =
+ .title = 更改文本颜色
+pdfjs-editor-free-text-button-label = 文本
+pdfjs-editor-ink-button =
+ .title = 绘图
+pdfjs-editor-color-picker-ink-input =
+ .title = 更改绘图颜色
+pdfjs-editor-ink-button-label = 绘图
+pdfjs-editor-stamp-button =
+ .title = 添加或编辑图像
+pdfjs-editor-stamp-button-label = 添加或编辑图像
+pdfjs-editor-highlight-button =
+ .title = 高亮
+pdfjs-editor-highlight-button-label = 高亮
+pdfjs-highlight-floating-button1 =
+ .title = 高亮
+ .aria-label = 高亮
+pdfjs-highlight-floating-button-label = 高亮
+pdfjs-comment-floating-button =
+ .title = 批注
+ .aria-label = 批注
+pdfjs-comment-floating-button-label = 批注
+pdfjs-editor-comment-button =
+ .title = 批注
+ .aria-label = 批注
+pdfjs-editor-comment-button-label = 批注
+pdfjs-editor-signature-button =
+ .title = 添加签名
+pdfjs-editor-signature-button-label = 添加签名
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = 高亮编辑器
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = 绘图编辑器
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = 签名编辑器:{ $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = 图像编辑器
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = 移除绘图
+pdfjs-editor-remove-freetext-button =
+ .title = 移除文本
+pdfjs-editor-remove-stamp-button =
+ .title = 移除图像
+pdfjs-editor-remove-highlight-button =
+ .title = 移除高亮
+pdfjs-editor-remove-signature-button =
+ .title = 移除签名
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = 颜色
+pdfjs-editor-free-text-size-input = 字号
+pdfjs-editor-ink-color-input = 颜色
+pdfjs-editor-ink-thickness-input = 粗细
+pdfjs-editor-ink-opacity-input = 不透明度
+pdfjs-editor-stamp-add-image-button =
+ .title = 添加图像
+pdfjs-editor-stamp-add-image-button-label = 添加图像
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = 粗细
+pdfjs-editor-free-highlight-thickness-title =
+ .title = 更改高亮粗细(用于文本以外项目)
+pdfjs-editor-add-signature-container =
+ .aria-label = 签名管理和保存的签名
+pdfjs-editor-signature-add-signature-button =
+ .title = 添加新签名
+pdfjs-editor-signature-add-signature-button-label = 添加新签名
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = 保存的签名:{ $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = 文本编辑器
+ .default-content = 在此键入…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title = 批注
+pdfjs-editor-comments-sidebar-close-button =
+ .title = 关闭侧栏
+ .aria-label = 关闭侧栏
+pdfjs-editor-comments-sidebar-close-button-label = 关闭侧栏
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = 发现值得注意的地方?可为其添加高亮并批注。
+pdfjs-editor-comments-sidebar-no-comments-link = 详细了解
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = 替换文字
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = 编辑替换文字
+pdfjs-editor-alt-text-dialog-label = 选择一项
+pdfjs-editor-alt-text-dialog-description = 替换文字可在用户无法看到或加载图像时,描述其内容。
+pdfjs-editor-alt-text-add-description-label = 添加描述
+pdfjs-editor-alt-text-add-description-description = 用一两个句子,描述主题、背景或动作。
+pdfjs-editor-alt-text-mark-decorative-label = 标记为装饰
+pdfjs-editor-alt-text-mark-decorative-description = 用于装饰的图像,例如边框和水印。
+pdfjs-editor-alt-text-cancel-button = 取消
+pdfjs-editor-alt-text-save-button = 保存
+pdfjs-editor-alt-text-decorative-tooltip = 已标记为装饰
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = 例如:一个少年坐到桌前,准备吃饭
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = 替换文字
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = 调整尺寸 - 左上角
+pdfjs-editor-resizer-top-middle =
+ .aria-label = 调整尺寸 - 顶部中间
+pdfjs-editor-resizer-top-right =
+ .aria-label = 调整尺寸 - 右上角
+pdfjs-editor-resizer-middle-right =
+ .aria-label = 调整尺寸 - 右侧中间
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = 调整尺寸 - 右下角
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = 调整大小 - 底部中间
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = 调整尺寸 - 左下角
+pdfjs-editor-resizer-middle-left =
+ .aria-label = 调整尺寸 - 左侧中间
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = 高亮色
+pdfjs-editor-colorpicker-button =
+ .title = 更改颜色
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = 颜色选择
+pdfjs-editor-colorpicker-yellow =
+ .title = 黄色
+pdfjs-editor-colorpicker-green =
+ .title = 绿色
+pdfjs-editor-colorpicker-blue =
+ .title = 蓝色
+pdfjs-editor-colorpicker-pink =
+ .title = 粉色
+pdfjs-editor-colorpicker-red =
+ .title = 红色
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = 显示全部
+pdfjs-editor-highlight-show-all-button =
+ .title = 显示全部
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = 编辑替换文字(图像描述)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = 添加替换文字(图像描述)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = 请在此处撰写描述…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = 向无法看到或加载图像的用户提供的简短描述。
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = 此段替换文字为自动创建,有可能不准确。
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = 详细了解
+pdfjs-editor-new-alt-text-create-automatically-button-label = 自动创建替换文字
+pdfjs-editor-new-alt-text-not-now-button = 暂时不要
+pdfjs-editor-new-alt-text-error-title = 无法自动创建替换文字
+pdfjs-editor-new-alt-text-error-description = 请自行撰写替换文字,或稍后再试。
+pdfjs-editor-new-alt-text-error-close-button = 关闭
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = 正在下载提供替换文字的 AI 模型({ $downloadedSize }/{ $totalSize } MB)
+ .aria-valuetext = 正在下载提供替换文字的 AI 模型({ $downloadedSize }/{ $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = 已添加替换文字
+pdfjs-editor-new-alt-text-added-button-label = 已添加替换文字
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = 缺少替换文字
+pdfjs-editor-new-alt-text-missing-button-label = 缺少替换文字
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = 检查替换文字
+pdfjs-editor-new-alt-text-to-review-button-label = 检查替换文字
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = [自动创建] { $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = 图像替换文字设置
+pdfjs-image-alt-text-settings-button-label = 图像替换文字设置
+pdfjs-editor-alt-text-settings-dialog-label = 图像替换文字设置
+pdfjs-editor-alt-text-settings-automatic-title = 自动创建替换文字
+pdfjs-editor-alt-text-settings-create-model-button-label = 自动创建替换文字
+pdfjs-editor-alt-text-settings-create-model-description = 向无法看到或加载图像的用户提供描述。
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = 提供替换文字的 AI 模型({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = 在您的设备本地运行,可使数据保持私密。自动创建替换文字需要使用此模型。
+pdfjs-editor-alt-text-settings-delete-model-button = 删除
+pdfjs-editor-alt-text-settings-download-model-button = 下载
+pdfjs-editor-alt-text-settings-downloading-model-button = 正在下载…
+pdfjs-editor-alt-text-settings-editor-title = 替换文字编辑器
+pdfjs-editor-alt-text-settings-show-dialog-button-label = 添加图像后立即显示替换文字编辑器
+pdfjs-editor-alt-text-settings-show-dialog-description = 帮助确保所有图像均拥有替换文字。
+pdfjs-editor-alt-text-settings-close-button = 关闭
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = 已添加高亮
+pdfjs-editor-freetext-added-alert = 已添加文本
+pdfjs-editor-ink-added-alert = 已添加绘图
+pdfjs-editor-stamp-added-alert = 已添加图像
+pdfjs-editor-signature-added-alert = 已添加签名
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = 已移除高亮
+pdfjs-editor-undo-bar-message-freetext = 已移除文本
+pdfjs-editor-undo-bar-message-ink = 已移除绘图
+pdfjs-editor-undo-bar-message-stamp = 已移除图像
+pdfjs-editor-undo-bar-message-signature = 签名已移除
+pdfjs-editor-undo-bar-message-comment = 已移除批注
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = 已移除 { $count } 条注释
+pdfjs-editor-undo-bar-undo-button =
+ .title = 撤销
+pdfjs-editor-undo-bar-undo-button-label = 撤销
+pdfjs-editor-undo-bar-close-button =
+ .title = 关闭
+pdfjs-editor-undo-bar-close-button-label = 关闭
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = 用户可通过此模态对话框创建要添加到 PDF 文档中的签名、编辑其名称(同时用作替换文字),并可保存签名以便重复使用。
+pdfjs-editor-add-signature-dialog-title = 添加签名
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = 键入
+ .title = 键入
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = 绘制
+ .title = 绘制
+pdfjs-editor-add-signature-image-button = 图像
+ .title = 图像
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = 键入签名
+ .placeholder = 键入签名
+pdfjs-editor-add-signature-draw-placeholder = 绘制签名
+pdfjs-editor-add-signature-draw-thickness-range-label = 粗细
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = 笔画粗细:{ $thickness }
+pdfjs-editor-add-signature-image-placeholder = 拖放文件到此处以上传
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] 或选取图像文件
+ *[other] 或浏览图像文件
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = 描述(替换文字)
+pdfjs-editor-add-signature-description-input =
+ .title = 描述(替换文字)
+pdfjs-editor-add-signature-description-default-when-drawing = 签名
+pdfjs-editor-add-signature-clear-button-label = 清除签名
+pdfjs-editor-add-signature-clear-button =
+ .title = 清除签名
+pdfjs-editor-add-signature-save-checkbox = 保存签名
+pdfjs-editor-add-signature-save-warning-message = 最多可保存 5 个签名,请移除一个以继续保存。
+pdfjs-editor-add-signature-image-upload-error-title = 无法上传图像
+pdfjs-editor-add-signature-image-upload-error-description = 请检查网络连接,或尝试上传其他图像。
+pdfjs-editor-add-signature-image-no-data-error-title = 无法将此图像转换为签名
+pdfjs-editor-add-signature-image-no-data-error-description = 请尝试上传其他图像。
+pdfjs-editor-add-signature-error-close-button = 关闭
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = 取消
+pdfjs-editor-add-signature-add-button = 添加
+pdfjs-editor-edit-signature-update-button = 更新
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = 编辑批注
+pdfjs-editor-edit-comment-popup-button =
+ .title = 编辑批注
+pdfjs-editor-delete-comment-popup-button-label = 移除批注
+pdfjs-editor-delete-comment-popup-button =
+ .title = 移除批注
+pdfjs-show-comment-button =
+ .title = 显示批注
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = 编辑批注
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = 更新
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = 添加批注
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = 添加
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = 开始键入…
+pdfjs-editor-edit-comment-dialog-cancel-button = 取消
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = 添加批注
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = 打开/关闭侧栏(文档所含的缩略图/大纲/附件/图层)
+pdfjs-toggle-views-manager-button1-label = 管理页面
+pdfjs-views-manager-sidebar =
+ .aria-label = 侧栏
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = 调整侧栏大小
+pdfjs-views-manager-view-selector-button =
+ .title = 视图
+pdfjs-views-manager-view-selector-button-label = 视图
+pdfjs-views-manager-pages-title = 页面
+pdfjs-views-manager-outlines-title1 = 文档大纲
+ .title = 文档大纲(双击可展开/折叠所有项目)
+pdfjs-views-manager-attachments-title = 附件
+pdfjs-views-manager-layers-title1 = 图层
+ .title = 图层(双击可将所有图层重置为默认状态)
+pdfjs-views-manager-pages-option-label = 页面
+pdfjs-views-manager-outlines-option-label = 文档大纲
+pdfjs-views-manager-attachments-option-label = 附件
+pdfjs-views-manager-layers-option-label = 图层
+pdfjs-views-manager-add-file-button =
+ .title = 添加文件
+pdfjs-views-manager-add-file-button-label = 添加文件
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label = 已选择 { $count } 页
+pdfjs-views-manager-pages-status-none-action-label = 选择页面
+pdfjs-views-manager-pages-status-action-button-label = 管理
+pdfjs-views-manager-pages-status-copy-button-label = 复制
+pdfjs-views-manager-pages-status-cut-button-label = 剪切
+pdfjs-views-manager-pages-status-delete-button-label = 删除
+pdfjs-views-manager-pages-status-export-selected-button-label = 导出选中的页面…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label = 已剪切 { $count } 页
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label = 已复制 { $count } 页
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label = 已删除 { $count } 页
+pdfjs-views-manager-pages-status-waiting-ready-label = 正在准备文件…
+pdfjs-views-manager-pages-status-waiting-uploading-label = 正在上传文件…
+pdfjs-views-manager-status-warning-cut-label = 无法剪切,请刷新页面并重试。
+pdfjs-views-manager-status-warning-copy-label = 无法复制,请刷新页面并重试。
+pdfjs-views-manager-status-warning-delete-label = 无法删除,请刷新页面并重试。
+pdfjs-views-manager-status-warning-save-label = 无法保存,请刷新页面并重试。
+pdfjs-views-manager-status-undo-button-label = 撤销
+pdfjs-views-manager-status-done-button-label = 完成
+pdfjs-views-manager-status-close-button =
+ .title = 关闭
+pdfjs-views-manager-status-close-button-label = 关闭
+pdfjs-views-manager-paste-button-label = 粘贴
+pdfjs-views-manager-paste-button-before =
+ .title = 粘贴在第一页之前
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = 粘贴在第 { $page } 页之后
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = 新
+pdfjs-views-manager-waiting-for-file = 正在上传文件…
+pdfjs-toggle-views-manager-button1 =
+ .title = 管理页面
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = 数字签名属性
+ .aria-label = 数字签名属性
+pdfjs-digital-signature-properties-button-label = 数字签名属性
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = 状态:签名已验证
+pdfjs-digital-signature-properties-status-invalid = 状态:签名无效
+pdfjs-digital-signature-properties-status-unknown = 状态:无法验证(不支持)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = 证书:受信任({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = 证书:不可用
+pdfjs-digital-signature-properties-certificate-untrusted = 证书:不可信
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = 证书:颁发者未知({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = 证书:自签名({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = 证书: 颁发者不可信({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = 证书: 已过期
+pdfjs-digital-signature-properties-certificate-expired-with-date = 证书:已过期({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = 证书:已吊销
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = 移除已保存的签名
+pdfjs-editor-delete-signature-button-label1 = 移除已保存的签名
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = 编辑描述
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = 编辑描述
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/locale/zh-TW/viewer.ftl b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/zh-TW/viewer.ftl
new file mode 100644
index 0000000..bf58047
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/locale/zh-TW/viewer.ftl
@@ -0,0 +1,780 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+## Main toolbar buttons (tooltips and alt text for images)
+
+pdfjs-previous-button =
+ .title = 上一頁
+pdfjs-previous-button-label = 上一頁
+pdfjs-next-button =
+ .title = 下一頁
+pdfjs-next-button-label = 下一頁
+# .title: Tooltip for the pageNumber input.
+pdfjs-page-input =
+ .title = 第
+# Variables:
+# $pagesCount (Number) - the total number of pages in the document
+# This string follows an input field with the number of the page currently displayed.
+pdfjs-of-pages = 頁,共 { $pagesCount } 頁
+# Variables:
+# $pageNumber (Number) - the currently visible page
+# $pagesCount (Number) - the total number of pages in the document
+pdfjs-page-of-pages = (第 { $pageNumber } 頁,共 { $pagesCount } 頁)
+pdfjs-zoom-out-button =
+ .title = 縮小
+pdfjs-zoom-out-button-label = 縮小
+pdfjs-zoom-in-button =
+ .title = 放大
+pdfjs-zoom-in-button-label = 放大
+pdfjs-zoom-select =
+ .title = 縮放
+pdfjs-presentation-mode-button =
+ .title = 切換至簡報模式
+pdfjs-presentation-mode-button-label = 簡報模式
+pdfjs-open-file-button =
+ .title = 開啟檔案
+pdfjs-open-file-button-label = 開啟
+pdfjs-print-button =
+ .title = 列印
+pdfjs-print-button-label = 列印
+pdfjs-save-button =
+ .title = 儲存
+pdfjs-save-button-label = 儲存
+# Used in Firefox for Android as a tooltip for the download button (“download” is a verb).
+pdfjs-download-button =
+ .title = 下載
+# Used in Firefox for Android as a label for the download button (“download” is a verb).
+# Length of the translation matters since we are in a mobile context, with limited screen estate.
+pdfjs-download-button-label = 下載
+pdfjs-bookmark-button =
+ .title = 目前頁面(含目前檢視頁面的網址)
+pdfjs-bookmark-button-label = 目前頁面
+
+## Secondary toolbar and context menu
+
+pdfjs-tools-button =
+ .title = 工具
+pdfjs-tools-button-label = 工具
+pdfjs-first-page-button =
+ .title = 跳到第一頁
+pdfjs-first-page-button-label = 跳到第一頁
+pdfjs-last-page-button =
+ .title = 跳到最後一頁
+pdfjs-last-page-button-label = 跳到最後一頁
+pdfjs-page-rotate-cw-button =
+ .title = 順時針旋轉
+pdfjs-page-rotate-cw-button-label = 順時針旋轉
+pdfjs-page-rotate-ccw-button =
+ .title = 逆時針旋轉
+pdfjs-page-rotate-ccw-button-label = 逆時針旋轉
+pdfjs-cursor-text-select-tool-button =
+ .title = 開啟文字選擇工具
+pdfjs-cursor-text-select-tool-button-label = 文字選擇工具
+pdfjs-cursor-hand-tool-button =
+ .title = 開啟頁面移動工具
+pdfjs-cursor-hand-tool-button-label = 頁面移動工具
+pdfjs-scroll-page-button =
+ .title = 使用單頁捲動版面
+pdfjs-scroll-page-button-label = 單頁捲動
+pdfjs-scroll-vertical-button =
+ .title = 使用垂直捲動版面
+pdfjs-scroll-vertical-button-label = 垂直捲動
+pdfjs-scroll-horizontal-button =
+ .title = 使用水平捲動版面
+pdfjs-scroll-horizontal-button-label = 水平捲動
+pdfjs-scroll-wrapped-button =
+ .title = 使用多頁捲動版面
+pdfjs-scroll-wrapped-button-label = 多頁捲動
+pdfjs-spread-none-button =
+ .title = 不要進行跨頁顯示
+pdfjs-spread-none-button-label = 不跨頁
+pdfjs-spread-odd-button =
+ .title = 從奇數頁開始跨頁
+pdfjs-spread-odd-button-label = 奇數跨頁
+pdfjs-spread-even-button =
+ .title = 從偶數頁開始跨頁
+pdfjs-spread-even-button-label = 偶數跨頁
+
+## Document properties dialog
+
+pdfjs-document-properties-button =
+ .title = 文件內容…
+pdfjs-document-properties-button-label = 文件內容…
+pdfjs-document-properties-file-name = 檔案名稱:
+pdfjs-document-properties-file-size = 檔案大小:
+# Variables:
+# $kb (Number) - the PDF file size in kilobytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB({ $b } 位元組)
+# Variables:
+# $mb (Number) - the PDF file size in megabytes
+# $b (Number) - the PDF file size in bytes
+pdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB({ $b } 位元組)
+pdfjs-document-properties-title = 標題:
+pdfjs-document-properties-author = 作者:
+pdfjs-document-properties-subject = 主旨:
+pdfjs-document-properties-keywords = 關鍵字:
+pdfjs-document-properties-creation-date = 建立日期:
+pdfjs-document-properties-modification-date = 修改日期:
+# Variables:
+# $dateObj (Date) - the creation/modification date and time of the PDF file
+pdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+pdfjs-document-properties-creator = 建立者:
+pdfjs-document-properties-producer = PDF 產生器:
+pdfjs-document-properties-version = PDF 版本:
+pdfjs-document-properties-page-count = 頁數:
+pdfjs-document-properties-page-size = 頁面大小:
+pdfjs-document-properties-page-size-unit-inches = in
+pdfjs-document-properties-page-size-unit-millimeters = mm
+pdfjs-document-properties-page-size-orientation-portrait = 垂直
+pdfjs-document-properties-page-size-orientation-landscape = 水平
+pdfjs-document-properties-page-size-name-a-three = A3
+pdfjs-document-properties-page-size-name-a-four = A4
+pdfjs-document-properties-page-size-name-letter = Letter
+pdfjs-document-properties-page-size-name-legal = Legal
+
+## Variables:
+## $width (Number) - the width of the (current) page
+## $height (Number) - the height of the (current) page
+## $unit (String) - the unit of measurement of the (current) page
+## $name (String) - the name of the (current) page
+## $orientation (String) - the orientation of the (current) page
+
+pdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit }({ $orientation })
+pdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit }({ $name },{ $orientation })
+
+##
+
+# The linearization status of the document; usually called "Fast Web View" in
+# English locales of Adobe software.
+pdfjs-document-properties-linearized = 快速 Web 檢視:
+pdfjs-document-properties-linearized-yes = 是
+pdfjs-document-properties-linearized-no = 否
+pdfjs-document-properties-close-button = 關閉
+pdfjs-digital-signature-properties-view-certificate = 檢視憑證
+# Shown beneath an invalid signature card to explain why verification
+# failed. The text comes from NSS (e.g. "Signature integrity has been
+# compromised", "PKCS#7 signature could not be parsed") and is not
+# itself localized — it is the underlying error message produced by
+# the verification backend.
+# Variables:
+# $reason (String) - error message describing why the signature
+# could not be verified.
+pdfjs-digital-signature-properties-reason = 原因:{ $reason }
+# Variables:
+# $dateObj (Date) - the signing time from the /Sig dict's /M entry.
+pdfjs-digital-signature-properties-timestamp = 時間戳記:{ DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+# Variables:
+# $count (Number) - number of nested sub-signatures (one per earlier
+# incremental revision of the document).
+pdfjs-digital-signature-properties-sub-signatures = 子簽章({ $count })
+
+## Print
+
+pdfjs-print-progress-message = 正在準備列印文件…
+# Variables:
+# $progress (Number) - percent value
+pdfjs-print-progress-percent = { $progress }%
+pdfjs-print-progress-close-button = 取消
+pdfjs-printing-not-supported = 警告:此瀏覽器未完整支援列印功能。
+pdfjs-printing-not-ready = 警告:此 PDF 未完成下載以供列印。
+
+## Tooltips and alt text for side panel toolbar buttons
+
+pdfjs-toggle-sidebar-button =
+ .title = 切換側邊欄
+pdfjs-toggle-sidebar-notification-button =
+ .title = 切換側邊欄(包含大綱、附件、圖層的文件)
+pdfjs-toggle-sidebar-button-label = 切換側邊欄
+pdfjs-document-outline-button =
+ .title = 顯示文件大綱(雙擊展開/摺疊所有項目)
+pdfjs-document-outline-button-label = 文件大綱
+pdfjs-attachments-button =
+ .title = 顯示附件
+pdfjs-attachments-button-label = 附件
+pdfjs-layers-button =
+ .title = 顯示圖層(滑鼠雙擊即可將所有圖層重設為預設狀態)
+pdfjs-layers-button-label = 圖層
+pdfjs-thumbs-button =
+ .title = 顯示縮圖
+pdfjs-thumbs-button-label = 縮圖
+pdfjs-current-outline-item-button =
+ .title = 尋找目前的大綱項目
+pdfjs-current-outline-item-button-label = 目前的大綱項目
+pdfjs-findbar-button =
+ .title = 在文件中尋找
+pdfjs-findbar-button-label = 尋找
+pdfjs-additional-layers = 其他圖層
+
+## Thumbnails panel item (tooltip and alt text for images)
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-title =
+ .title = 第 { $page } 頁
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-canvas =
+ .aria-label = 第 { $page } 頁的縮圖
+# Variables:
+# $page (Number) - the page number
+pdfjs-thumb-page-checkbox1 =
+ .title = 選擇第 { $page } 頁
+# Variables:
+# $page (Number) - the page number
+# $total (Number) - the number of pages
+pdfjs-thumb-page-title1 =
+ .title = 第 { $page } 頁,共 { $total } 頁
+
+## Find panel button title and messages
+
+pdfjs-find-input =
+ .title = 尋找
+ .placeholder = 在文件中搜尋…
+pdfjs-find-previous-button =
+ .title = 尋找文字前次出現的位置
+pdfjs-find-previous-button-label = 上一個
+pdfjs-find-next-button =
+ .title = 尋找文字下次出現的位置
+pdfjs-find-next-button-label = 下一個
+pdfjs-find-highlight-checkbox = 強調全部
+pdfjs-find-match-case-checkbox-label = 區分大小寫
+pdfjs-find-match-diacritics-checkbox-label = 符合變音符號
+pdfjs-find-entire-word-checkbox-label = 符合整個字
+pdfjs-find-reached-top = 已搜尋至文件頂端,自底端繼續搜尋
+pdfjs-find-reached-bottom = 已搜尋至文件底端,自頂端繼續搜尋
+# Variables:
+# $current (Number) - the index of the currently active find result
+# $total (Number) - the total number of matches in the document
+pdfjs-find-match-count = 第 { $current } 筆符合,共符合 { $total } 筆
+# Variables:
+# $limit (Number) - the maximum number of matches
+pdfjs-find-match-count-limit = 符合超過 { $limit } 項
+pdfjs-find-not-found = 找不到指定文字
+
+## Predefined zoom values
+
+pdfjs-page-scale-width = 頁面寬度
+pdfjs-page-scale-fit = 縮放至頁面大小
+pdfjs-page-scale-auto = 自動縮放
+pdfjs-page-scale-actual = 實際大小
+# Variables:
+# $scale (Number) - percent value for page scale
+pdfjs-page-scale-percent = { $scale }%
+
+## PDF page
+
+# Variables:
+# $page (Number) - the page number
+pdfjs-page-landmark =
+ .aria-label = 第 { $page } 頁
+
+## Loading indicator messages
+
+pdfjs-loading-error = 載入 PDF 時發生錯誤。
+pdfjs-invalid-file-error = 無效或毀損的 PDF 檔案。
+pdfjs-missing-file-error = 找不到 PDF 檔案。
+pdfjs-unexpected-response-error = 伺服器回應未預期的內容。
+pdfjs-rendering-error = 描繪頁面時發生錯誤。
+
+## Annotations
+
+# .alt: This is used as a tooltip.
+# Variables:
+# $type (String) - an annotation type from a list defined in the PDF spec
+# (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+pdfjs-text-annotation-type =
+ .alt = [{ $type } 註解]
+# Variables:
+# $dateObj (Date) - the modification date and time of the annotation
+pdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: "short", timeStyle: "medium") }
+
+## Password
+
+pdfjs-password-label = 請輸入用來開啟此 PDF 檔案的密碼。
+pdfjs-password-invalid = 密碼不正確,請再試一次。
+pdfjs-password-ok-button = 確定
+pdfjs-password-cancel-button = 取消
+pdfjs-web-fonts-disabled = 已停用網路字型 (Web fonts): 無法使用 PDF 內嵌字型。
+
+## Editing
+
+pdfjs-editor-free-text-button =
+ .title = 文字
+pdfjs-editor-color-picker-free-text-input =
+ .title = 更改文字色彩
+pdfjs-editor-free-text-button-label = 文字
+pdfjs-editor-ink-button =
+ .title = 繪圖
+pdfjs-editor-color-picker-ink-input =
+ .title = 更改繪圖色彩
+pdfjs-editor-ink-button-label = 繪圖
+pdfjs-editor-stamp-button =
+ .title = 新增或編輯圖片
+pdfjs-editor-stamp-button-label = 新增或編輯圖片
+pdfjs-editor-highlight-button =
+ .title = 強調
+pdfjs-editor-highlight-button-label = 強調
+pdfjs-highlight-floating-button1 =
+ .title = 強調
+ .aria-label = 強調
+pdfjs-highlight-floating-button-label = 強調
+pdfjs-comment-floating-button =
+ .title = 註解
+ .aria-label = 註解
+pdfjs-comment-floating-button-label = 註解
+pdfjs-editor-comment-button =
+ .title = 註解
+ .aria-label = 註解
+pdfjs-editor-comment-button-label = 註解
+pdfjs-editor-signature-button =
+ .title = 加入簽章
+pdfjs-editor-signature-button-label = 加入簽章
+
+## Default editor aria labels
+
+# “Highlight” is a noun, the string is used on the editor for highlights.
+pdfjs-editor-highlight-editor =
+ .aria-label = 強調樣式編輯器
+# “Drawing” is a noun, the string is used on the editor for drawings.
+pdfjs-editor-ink-editor =
+ .aria-label = 繪圖編輯器
+# Used when a signature editor is selected/hovered.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-signature-editor1 =
+ .aria-description = 簽章編輯器:{ $description }
+pdfjs-editor-stamp-editor =
+ .aria-label = 圖片編輯器
+
+## Remove button for the various kind of editor.
+
+pdfjs-editor-remove-ink-button =
+ .title = 移除繪圖
+pdfjs-editor-remove-freetext-button =
+ .title = 移除文字
+pdfjs-editor-remove-stamp-button =
+ .title = 移除圖片
+pdfjs-editor-remove-highlight-button =
+ .title = 移除選擇範圍的強調效果
+pdfjs-editor-remove-signature-button =
+ .title = 移除簽章
+
+##
+
+# Editor Parameters
+pdfjs-editor-free-text-color-input = 色彩
+pdfjs-editor-free-text-size-input = 大小
+pdfjs-editor-ink-color-input = 色彩
+pdfjs-editor-ink-thickness-input = 線條粗細
+pdfjs-editor-ink-opacity-input = 透明度
+pdfjs-editor-stamp-add-image-button =
+ .title = 新增圖片
+pdfjs-editor-stamp-add-image-button-label = 新增圖片
+# This refers to the thickness of the line used for free highlighting (not bound to text)
+pdfjs-editor-free-highlight-thickness-input = 線條粗細
+pdfjs-editor-free-highlight-thickness-title =
+ .title = 更改強調文字以外的項目時的線條粗細
+pdfjs-editor-add-signature-container =
+ .aria-label = 簽章控制元件與儲存的簽章
+pdfjs-editor-signature-add-signature-button =
+ .title = 新增簽章
+pdfjs-editor-signature-add-signature-button-label = 新增簽章
+# Used on the button to use an already saved signature.
+# Variables:
+# $description (String) - a string describing/labeling the signature.
+pdfjs-editor-add-saved-signature-button =
+ .title = 已儲存簽章:{ $description }
+# .default-content is used as a placeholder in an empty text editor.
+pdfjs-free-text2 =
+ .aria-label = 文字編輯器
+ .default-content = 請打字…
+# Used to show how many comments are present in the pdf file.
+# Variables:
+# $count (Number) - the number of comments.
+pdfjs-editor-comments-sidebar-title = 註解
+pdfjs-editor-comments-sidebar-close-button =
+ .title = 關閉側邊欄
+ .aria-label = 關閉側邊欄
+pdfjs-editor-comments-sidebar-close-button-label = 關閉側邊欄
+# Instructional copy to add a comment by selecting text or an annotations.
+pdfjs-editor-comments-sidebar-no-comments1 = 想把哪個部分記下來?可以畫螢光強調,並且留下註解。
+pdfjs-editor-comments-sidebar-no-comments-link = 更多資訊
+
+## Alt-text dialog
+
+pdfjs-editor-alt-text-button-label = 替代文字
+pdfjs-editor-alt-text-edit-button =
+ .aria-label = 編輯替代文字
+pdfjs-editor-alt-text-dialog-label = 挑選一種
+pdfjs-editor-alt-text-dialog-description = 替代文字可協助盲人,或於圖片無法載入時提供說明。
+pdfjs-editor-alt-text-add-description-label = 新增描述
+pdfjs-editor-alt-text-add-description-description = 用 1-2 句文字描述主題、背景或動作。
+pdfjs-editor-alt-text-mark-decorative-label = 標示為裝飾性內容
+pdfjs-editor-alt-text-mark-decorative-description = 這是裝飾性圖片,例如邊框或浮水印。
+pdfjs-editor-alt-text-cancel-button = 取消
+pdfjs-editor-alt-text-save-button = 儲存
+pdfjs-editor-alt-text-decorative-tooltip = 已標示為裝飾性內容
+# .placeholder: This is a placeholder for the alt text input area
+pdfjs-editor-alt-text-textarea =
+ .placeholder = 例如:「有一位年輕男人坐在桌子前面吃飯」
+# Alternative text (alt text) helps when people can't see the image.
+pdfjs-editor-alt-text-button =
+ .aria-label = 替代文字
+
+## Editor resizers
+## This is used in an aria label to help to understand the role of the resizer.
+
+pdfjs-editor-resizer-top-left =
+ .aria-label = 左上角 — 調整大小
+pdfjs-editor-resizer-top-middle =
+ .aria-label = 頂部中間 — 調整大小
+pdfjs-editor-resizer-top-right =
+ .aria-label = 右上角 — 調整大小
+pdfjs-editor-resizer-middle-right =
+ .aria-label = 中間右方 — 調整大小
+pdfjs-editor-resizer-bottom-right =
+ .aria-label = 右下角 — 調整大小
+pdfjs-editor-resizer-bottom-middle =
+ .aria-label = 底部中間 — 調整大小
+pdfjs-editor-resizer-bottom-left =
+ .aria-label = 左下角 — 調整大小
+pdfjs-editor-resizer-middle-left =
+ .aria-label = 中間左方 — 調整大小
+
+## Color picker
+
+# This means "Color used to highlight text"
+pdfjs-editor-highlight-colorpicker-label = 強調色彩
+pdfjs-editor-colorpicker-button =
+ .title = 更改色彩
+pdfjs-editor-colorpicker-dropdown =
+ .aria-label = 色彩選項
+pdfjs-editor-colorpicker-yellow =
+ .title = 黃色
+pdfjs-editor-colorpicker-green =
+ .title = 綠色
+pdfjs-editor-colorpicker-blue =
+ .title = 藍色
+pdfjs-editor-colorpicker-pink =
+ .title = 粉紅色
+pdfjs-editor-colorpicker-red =
+ .title = 紅色
+
+## Show all highlights
+## This is a toggle button to show/hide all the highlights.
+
+pdfjs-editor-highlight-show-all-button-label = 顯示全部
+pdfjs-editor-highlight-show-all-button =
+ .title = 顯示全部
+
+## New alt-text dialog
+## Group note for entire feature: Alternative text (alt text) helps when people can't see the image. This feature includes a tool to create alt text automatically using an AI model that works locally on the user's device to preserve privacy.
+
+# Modal header positioned above a text box where users can edit the alt text.
+pdfjs-editor-new-alt-text-dialog-edit-label = 編輯替代文字(圖片描述)
+# Modal header positioned above a text box where users can add the alt text.
+pdfjs-editor-new-alt-text-dialog-add-label = 新增替代文字(圖片描述)
+pdfjs-editor-new-alt-text-textarea =
+ .placeholder = 在此寫下您的描述文字…
+# This text refers to the alt text box above this description. It offers a definition of alt text.
+pdfjs-editor-new-alt-text-description = 為看不到圖片的讀者,或圖片無法載入時顯示的簡短描述。
+# This is a required legal disclaimer that refers to the automatically created text inside the alt text box above this text. It disappears if the text is edited by a human.
+pdfjs-editor-new-alt-text-disclaimer1 = 此替代文字是自動產生的,可能不夠精確。
+pdfjs-editor-new-alt-text-disclaimer-learn-more-url = 更多資訊
+pdfjs-editor-new-alt-text-create-automatically-button-label = 自動產生替代文字
+pdfjs-editor-new-alt-text-not-now-button = 暫時不要
+pdfjs-editor-new-alt-text-error-title = 無法自動產生替代文字
+pdfjs-editor-new-alt-text-error-description = 請自行填寫替代文字,或稍後再試一次。
+pdfjs-editor-new-alt-text-error-close-button = 關閉
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+# $downloadedSize (Number) - the downloaded size (in MB) of the AI model.
+pdfjs-editor-new-alt-text-ai-model-downloading-progress = 正在下載替代文字 AI 模型({ $downloadedSize } / { $totalSize } MB)
+ .aria-valuetext = 正在下載替代文字 AI 模型({ $downloadedSize } / { $totalSize } MB)
+# This is a button that users can click to edit the alt text they have already added.
+pdfjs-editor-new-alt-text-added-button =
+ .aria-label = 已新增替代文字
+pdfjs-editor-new-alt-text-added-button-label = 已新增替代文字
+# This is a button that users can click to open the alt text editor and add alt text when it is not present.
+pdfjs-editor-new-alt-text-missing-button =
+ .aria-label = 缺少替代文字
+pdfjs-editor-new-alt-text-missing-button-label = 缺少替代文字
+# This is a button that opens up the alt text modal where users should review the alt text that was automatically generated.
+pdfjs-editor-new-alt-text-to-review-button =
+ .aria-label = 確認替代文字
+pdfjs-editor-new-alt-text-to-review-button-label = 確認替代文字
+# "Created automatically" is a prefix that will be added to the beginning of any alt text that has been automatically generated. After the colon, the user will see/hear the actual alt text description. If the alt text has been edited by a human, this prefix will not appear.
+# Variables:
+# $generatedAltText (String) - the generated alt-text.
+pdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = 自動產生:{ $generatedAltText }
+
+## Image alt-text settings
+
+pdfjs-image-alt-text-settings-button =
+ .title = 圖片替代文字設定
+pdfjs-image-alt-text-settings-button-label = 圖片替代文字設定
+pdfjs-editor-alt-text-settings-dialog-label = 圖片替代文字設定
+pdfjs-editor-alt-text-settings-automatic-title = 自動化替代文字
+pdfjs-editor-alt-text-settings-create-model-button-label = 自動產生替代文字
+pdfjs-editor-alt-text-settings-create-model-description = 為您建議圖片描述,幫助看不到圖片的讀者,或於圖片無法載入時顯示。
+# Variables:
+# $totalSize (Number) - the total size (in MB) of the AI model.
+pdfjs-editor-alt-text-settings-download-model-label = 替代文字 AI 模型({ $totalSize } MB)
+pdfjs-editor-alt-text-settings-ai-model-description = 在您的本機裝置上運作,以確保您的資料隱私。必須下載此模型才可以自動產生替代文字。
+pdfjs-editor-alt-text-settings-delete-model-button = 刪除
+pdfjs-editor-alt-text-settings-download-model-button = 下載
+pdfjs-editor-alt-text-settings-downloading-model-button = 下載中…
+pdfjs-editor-alt-text-settings-editor-title = 替代文字編輯器
+pdfjs-editor-alt-text-settings-show-dialog-button-label = 新增圖片後立即顯示替代文字編輯器
+pdfjs-editor-alt-text-settings-show-dialog-description = 幫助您確保所有圖片都有替代文字。
+pdfjs-editor-alt-text-settings-close-button = 關閉
+
+## Accessibility labels (announced by screen readers) for objects added to the editor.
+
+pdfjs-editor-highlight-added-alert = 已加入強調範圍
+pdfjs-editor-freetext-added-alert = 已加入文字
+pdfjs-editor-ink-added-alert = 已新增繪圖
+pdfjs-editor-stamp-added-alert = 已新增圖片
+pdfjs-editor-signature-added-alert = 已新增簽章
+
+## "Annotations removed" bar
+
+pdfjs-editor-undo-bar-message-highlight = 已移除強調
+pdfjs-editor-undo-bar-message-freetext = 已移除文字
+pdfjs-editor-undo-bar-message-ink = 已移除繪圖
+pdfjs-editor-undo-bar-message-stamp = 已移除圖片
+pdfjs-editor-undo-bar-message-signature = 已移除簽章
+pdfjs-editor-undo-bar-message-comment = 已移除註解
+# Variables:
+# $count (Number) - the number of removed annotations.
+pdfjs-editor-undo-bar-message-multiple = 已移除 { $count } 筆註解
+pdfjs-editor-undo-bar-undo-button =
+ .title = 還原
+pdfjs-editor-undo-bar-undo-button-label = 還原
+pdfjs-editor-undo-bar-close-button =
+ .title = 關閉
+pdfjs-editor-undo-bar-close-button-label = 關閉
+
+## Add a signature dialog
+
+pdfjs-editor-add-signature-dialog-label = 此對話框讓使用者能夠建立簽章以加入 PDF 文件。使用者可以編輯他們的姓名(同時也是替代文字),並選擇性儲存簽章,以供未來重複使用。
+pdfjs-editor-add-signature-dialog-title = 加入簽章
+
+## Tab names
+
+# Type is a verb (you can type your name as signature)
+pdfjs-editor-add-signature-type-button = 打字
+ .title = 打字
+# Draw is a verb (you can draw your signature)
+pdfjs-editor-add-signature-draw-button = 手繪
+ .title = 手繪
+pdfjs-editor-add-signature-image-button = 圖片
+ .title = 圖片
+
+## Tab panels
+
+pdfjs-editor-add-signature-type-input =
+ .aria-label = 輸入簽章
+ .placeholder = 輸入簽章
+pdfjs-editor-add-signature-draw-placeholder = 手繪簽章
+pdfjs-editor-add-signature-draw-thickness-range-label = 線條粗細
+# Variables:
+# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
+pdfjs-editor-add-signature-draw-thickness-range =
+ .title = 繪製時的線條粗細:{ $thickness }
+pdfjs-editor-add-signature-image-placeholder = 將檔案拖曳到此處即可上傳
+pdfjs-editor-add-signature-image-browse-link =
+ { PLATFORM() ->
+ [macos] 或選擇圖片檔案
+ *[other] 或瀏覽圖片檔案
+ }
+
+## Controls
+
+pdfjs-editor-add-signature-description-label = 描述(替代文字)
+pdfjs-editor-add-signature-description-input =
+ .title = 描述(替代文字)
+pdfjs-editor-add-signature-description-default-when-drawing = 簽章
+pdfjs-editor-add-signature-clear-button-label = 清除簽章
+pdfjs-editor-add-signature-clear-button =
+ .title = 清除簽章
+pdfjs-editor-add-signature-save-checkbox = 儲存簽章
+pdfjs-editor-add-signature-save-warning-message = 您已經儲存 5 式簽章,請移除任一式才能再新增。
+pdfjs-editor-add-signature-image-upload-error-title = 無法上傳圖片
+pdfjs-editor-add-signature-image-upload-error-description = 請檢查您的網路連線,或改用其他圖片。
+pdfjs-editor-add-signature-image-no-data-error-title = 無法將此圖片轉換成簽章
+pdfjs-editor-add-signature-image-no-data-error-description = 請試著上傳另一張圖片。
+pdfjs-editor-add-signature-error-close-button = 關閉
+
+## Dialog buttons
+
+pdfjs-editor-add-signature-cancel-button = 取消
+pdfjs-editor-add-signature-add-button = 新增
+pdfjs-editor-edit-signature-update-button = 更新
+
+## Comment popup
+
+pdfjs-editor-edit-comment-popup-button-label = 編輯註解
+pdfjs-editor-edit-comment-popup-button =
+ .title = 編輯註解
+pdfjs-editor-delete-comment-popup-button-label = 移除註解
+pdfjs-editor-delete-comment-popup-button =
+ .title = 移除註解
+pdfjs-show-comment-button =
+ .title = 顯示註解
+
+## Edit a comment dialog
+
+# An existing comment is edited
+pdfjs-editor-edit-comment-dialog-title-when-editing = 編輯註解
+pdfjs-editor-edit-comment-dialog-save-button-when-editing = 更新
+# No existing comment
+pdfjs-editor-edit-comment-dialog-title-when-adding = 新增註解
+pdfjs-editor-edit-comment-dialog-save-button-when-adding = 新增
+pdfjs-editor-edit-comment-dialog-text-input =
+ .placeholder = 在此打字…
+pdfjs-editor-edit-comment-dialog-cancel-button = 取消
+
+## Edit a comment button in the editor toolbar
+
+pdfjs-editor-add-comment-button =
+ .title = 新增註解
+
+## The view manager is a sidebar displaying different views:
+## - thumbnails;
+## - outline;
+## - attachments;
+## - layers.
+## The thumbnails view is used to edit the pdf: remove/insert pages, ...
+
+pdfjs-toggle-views-manager-notification-button =
+ .title = 切換側邊欄(包含縮圖、大綱、附件、圖層的文件)
+pdfjs-toggle-views-manager-button1-label = 管理頁面
+pdfjs-views-manager-sidebar =
+ .aria-label = 側邊欄
+pdfjs-views-manager-sidebar-resizer =
+ .aria-label = 調整側邊欄大小
+pdfjs-views-manager-view-selector-button =
+ .title = 畫面
+pdfjs-views-manager-view-selector-button-label = 畫面
+pdfjs-views-manager-pages-title = 頁面
+pdfjs-views-manager-outlines-title1 = 文件大綱
+ .title = 文件大綱(點兩下即可展開/摺疊所有項目)
+pdfjs-views-manager-attachments-title = 附件
+pdfjs-views-manager-layers-title1 = 圖層
+ .title = 圖層(點兩下即可將所有圖層重設回預設狀態)
+pdfjs-views-manager-pages-option-label = 頁面
+pdfjs-views-manager-outlines-option-label = 文件大綱
+pdfjs-views-manager-attachments-option-label = 附件
+pdfjs-views-manager-layers-option-label = 圖層
+pdfjs-views-manager-add-file-button =
+ .title = 新增檔案
+pdfjs-views-manager-add-file-button-label = 新增檔案
+# Variables:
+# $count (Number) - the number of selected pages.
+pdfjs-views-manager-pages-status-action-label = 已選擇 { $count } 頁
+pdfjs-views-manager-pages-status-none-action-label = 選擇頁面
+pdfjs-views-manager-pages-status-action-button-label = 管理
+pdfjs-views-manager-pages-status-copy-button-label = 複製
+pdfjs-views-manager-pages-status-cut-button-label = 剪下
+pdfjs-views-manager-pages-status-delete-button-label = 刪除
+pdfjs-views-manager-pages-status-export-selected-button-label = 匯出選擇項目…
+# Variables:
+# $count (Number) - the number of selected pages to be cut.
+pdfjs-views-manager-status-undo-cut-label = 已剪下 { $count } 頁
+# Variables:
+# $count (Number) - the number of selected pages to be copied.
+pdfjs-views-manager-pages-status-undo-copy-label = 已複製 { $count } 頁
+# Variables:
+# $count (Number) - the number of selected pages to be deleted.
+pdfjs-views-manager-pages-status-undo-delete-label = 已刪除 { $count } 頁
+pdfjs-views-manager-pages-status-waiting-ready-label = 正在準備您的檔案…
+pdfjs-views-manager-pages-status-waiting-uploading-label = 正在上傳檔案…
+pdfjs-views-manager-status-warning-cut-label = 無法剪下頁面,請重新整理頁面後再試一次。
+pdfjs-views-manager-status-warning-copy-label = 無法複製頁面,請重新整理頁面後再試一次。
+pdfjs-views-manager-status-warning-delete-label = 無法刪除頁面,請重新整理頁面後再試一次。
+pdfjs-views-manager-status-warning-save-label = 無法儲存頁面,請重新整理頁面後再試一次。
+pdfjs-views-manager-status-undo-button-label = 還原
+pdfjs-views-manager-status-done-button-label = 完成
+pdfjs-views-manager-status-close-button =
+ .title = 關閉
+pdfjs-views-manager-status-close-button-label = 關閉
+pdfjs-views-manager-paste-button-label = 貼上
+pdfjs-views-manager-paste-button-before =
+ .title = 貼到第一頁前
+# Variables:
+# $page (Number) - the page number after which the paste button is.
+pdfjs-views-manager-paste-button-after =
+ .title = 貼到第 { $page } 頁後
+# Badge used to promote a new feature in the UI, keep it as short as possible.
+# It's spelled uppercase for English, but it can be translated as usual.
+pdfjs-new-badge-content = 新功能
+pdfjs-views-manager-waiting-for-file = 正在上傳檔案…
+pdfjs-toggle-views-manager-button1 =
+ .title = 管理頁面
+
+## Digital signature properties (signature verification panel)
+
+pdfjs-digital-signature-properties-button =
+ .title = 數位簽章屬性
+ .aria-label = 數位簽章屬性
+pdfjs-digital-signature-properties-button-label = 數位簽章屬性
+
+## Banner shown above the signature list summarising the overall
+## verification state of the document. Each variant is selected by the
+## viewer based on the worst per-signature status; one signature is
+## enough to lower the banner.
+##
+## Variables:
+## $count (Number) - number of signatures at the worst level.
+
+pdfjs-digital-signature-properties-banner-verified = 文件使用有效的數位簽章進行簽署
+pdfjs-digital-signature-properties-banner-unknown = 文件已進行簽署,但無法驗證當中的 { $count } 筆數位簽章
+pdfjs-digital-signature-properties-banner-untrusted = 文件已進行簽署,但當中的 { $count } 筆數位簽章不受信任
+pdfjs-digital-signature-properties-banner-expired = 文件已進行簽署,但當中的 { $count } 筆數位簽章已過期
+pdfjs-digital-signature-properties-banner-invalid = 文件中有 { $count } 筆無效的數位簽章
+pdfjs-digital-signature-properties-banner-revoked = 文件已進行簽署,但當中的 { $count } 筆數位簽章已廢止
+
+## Per-signature status row. Only three distinct strings are needed:
+## the signature crypto either verified (the cert chain may still be
+## untrusted/expired/revoked, but that's surfaced on the cert row
+## below), or it failed, or its sub-format isn't supported.
+
+pdfjs-digital-signature-properties-status-verified = 狀態:已驗證簽章
+pdfjs-digital-signature-properties-status-invalid = 狀態:簽章無效
+pdfjs-digital-signature-properties-status-unknown = 狀態:無法驗證(不支援)
+
+## Per-signature certificate row. The variants with an issuer / date in
+## parentheses embed fully-localized context — no English fall-through.
+##
+## Variables:
+## $issuer (String) - issuer or subject common name from the cert.
+## $dateObj (Date) - notAfter date for the expired-with-date form.
+
+pdfjs-digital-signature-properties-certificate-trusted = 憑證:受信任({ $issuer })
+pdfjs-digital-signature-properties-certificate-unknown = 憑證:無法使用
+pdfjs-digital-signature-properties-certificate-untrusted = 憑證:未受信任
+pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = 憑證:未知的簽發者({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-self-signed = 憑證:自行簽署({ $issuer })
+pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = 憑證:未受信任的簽發者({ $issuer })
+pdfjs-digital-signature-properties-certificate-expired = 憑證:已過期
+pdfjs-digital-signature-properties-certificate-expired-with-date = 憑證:已過期({ DATETIME($dateObj, dateStyle: "medium") })
+pdfjs-digital-signature-properties-certificate-revoked = 憑證:已廢止
+
+## Main menu for adding/removing signatures
+
+pdfjs-editor-delete-signature-button1 =
+ .title = 移除儲存的簽章
+pdfjs-editor-delete-signature-button-label1 = 移除儲存的簽章
+
+## Editor toolbar
+
+pdfjs-editor-add-signature-edit-button-label = 編輯描述
+
+## Edit signature description dialog
+
+pdfjs-editor-edit-signature-dialog-title = 編輯描述
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitDingbats.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitDingbats.pfb
new file mode 100644
index 0000000..30d5296
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitDingbats.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixed.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixed.pfb
new file mode 100644
index 0000000..f12dcbc
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixed.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedBold.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedBold.pfb
new file mode 100644
index 0000000..cf8e24a
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedBold.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedBoldItalic.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedBoldItalic.pfb
new file mode 100644
index 0000000..d288001
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedBoldItalic.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedItalic.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedItalic.pfb
new file mode 100644
index 0000000..d71697d
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitFixedItalic.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerif.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerif.pfb
new file mode 100644
index 0000000..3fa682e
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerif.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifBold.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifBold.pfb
new file mode 100644
index 0000000..ff7c6dd
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifBold.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifBoldItalic.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifBoldItalic.pfb
new file mode 100644
index 0000000..460231f
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifBoldItalic.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifItalic.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifItalic.pfb
new file mode 100644
index 0000000..d03a7c7
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSerifItalic.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSymbol.pfb b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSymbol.pfb
new file mode 100644
index 0000000..c8f9bca
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/FoxitSymbol.pfb differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LICENSE_FOXIT b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LICENSE_FOXIT
new file mode 100644
index 0000000..8b4ed6d
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LICENSE_FOXIT
@@ -0,0 +1,27 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LICENSE_LIBERATION b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LICENSE_LIBERATION
new file mode 100644
index 0000000..213c182
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LICENSE_LIBERATION
@@ -0,0 +1,363 @@
+LICENSE AGREEMENT AND LIMITED PRODUCT WARRANTY
+LIBERATION FONT SOFTWARE
+
+This agreement governs the use of the Software and any updates to the Software, regardless of the delivery mechanism. Subject to the following terms, Red Hat, Inc. ("Red Hat") grants to the user ("Client") a license to this work pursuant to the GNU General Public License v.2 with the exceptions set forth below and such other terms as are set forth in this End User License Agreement.
+
+ 1. The Software and License Exception. LIBERATION font software (the "Software") consists of TrueType-OpenType formatted font software for rendering LIBERATION typefaces in sans-serif, serif, and monospaced character styles. You are licensed to use, modify, copy, and distribute the Software pursuant to the GNU General Public License v.2 with the following exceptions:
+
+ (a) As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.
+
+ (b) As a further exception, any distribution of the object code of the Software in a physical product must provide you the right to access and modify the source code for the Software and to reinstall that modified version of the Software in object code form on the same physical product on which you received it.
+
+ 2. Intellectual Property Rights. The Software and each of its components, including the source code, documentation, appearance, structure and organization are owned by Red Hat and others and are protected under copyright and other laws. Title to the Software and any component, or to any copy, modification, or merged portion shall remain with the aforementioned, subject to the applicable license. The "LIBERATION" trademark is a trademark of Red Hat, Inc. in the U.S. and other countries. This agreement does not permit Client to distribute modified versions of the Software using Red Hat's trademarks. If Client makes a redistribution of a modified version of the Software, then Client must modify the files names to remove any reference to the Red Hat trademarks and must not use the Red Hat trademarks in any way to reference or promote the modified Software.
+
+ 3. Limited Warranty. To the maximum extent permitted under applicable law, the Software is provided and licensed "as is" without warranty of any kind, expressed or implied, including the implied warranties of merchantability, non-infringement or fitness for a particular purpose. Red Hat does not warrant that the functions contained in the Software will meet Client's requirements or that the operation of the Software will be entirely error free or appear precisely as described in the accompanying documentation.
+
+ 4. Limitation of Remedies and Liability. To the maximum extent permitted by applicable law, Red Hat or any Red Hat authorized dealer will not be liable to Client for any incidental or consequential damages, including lost profits or lost savings arising out of the use or inability to use the Software, even if Red Hat or such dealer has been advised of the possibility of such damages.
+
+ 5. General. If any provision of this agreement is held to be unenforceable, that shall not affect the enforceability of the remaining provisions. This agreement shall be governed by the laws of the State of North Carolina and of the United States, without regard to any conflict of laws provisions, except that the United Nations Convention on the International Sale of Goods shall not apply.
+Copyright © 2007-2011 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.
+
+------------------------------------------------------------------------------
+
+The text of the GNU General Public License, version 2, referenced above:
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Bold.ttf b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Bold.ttf
new file mode 100644
index 0000000..ee23715
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Bold.ttf differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-BoldItalic.ttf b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-BoldItalic.ttf
new file mode 100644
index 0000000..42b5717
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-BoldItalic.ttf differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Italic.ttf b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Italic.ttf
new file mode 100644
index 0000000..0cf6126
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Italic.ttf differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Regular.ttf b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Regular.ttf
new file mode 100644
index 0000000..366d148
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/standard_fonts/LiberationSans-Regular.ttf differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.css b/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.css
new file mode 100644
index 0000000..3fed284
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.css
@@ -0,0 +1,8206 @@
+/* Copyright 2014 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+:root{
+ --button-primary-bg-color:var(
+ --button-background-color-primary,
+ light-dark(#0060df, #0df)
+ );
+ --button-primary-fg-color:var(
+ --button-text-color-primary,
+ light-dark(#fbfbfe, #15141a)
+ );
+ --button-primary-border-color:var(--button-primary-bg-color);
+ --button-primary-active-bg-color:var(
+ --button-background-color-primary-active,
+ light-dark(#054096, #aaf2ff)
+ );
+ --button-primary-active-fg-color:var(--button-primary-fg-color);
+ --button-primary-active-border-color:var(--button-primary-active-bg-color);
+ --button-primary-hover-bg-color:var(
+ --button-background-color-primary-hover,
+ light-dark(#0250bb, #80ebff)
+ );
+ --button-primary-hover-fg-color:var(--button-primary-fg-color);
+ --button-primary-hover-border-color:var(--button-primary-hover-bg-color);
+ --button-primary-disabled-bg-color:var(--button-primary-bg-color);
+ --button-primary-disabled-border-color:var(--button-primary-border-color);
+ --button-primary-disabled-fg-color:var(--button-primary-fg-color);
+
+ --button-secondary-bg-color:var(
+ --button-background-color,
+ light-dark(rgb(21 20 26 / 0.07), rgb(251 251 254 / 0.07))
+ );
+ --button-secondary-fg-color:var(--text-color, light-dark(#15141a, #fbfbfe));
+ --button-secondary-border-color:var(
+ --button-border-color,
+ var(--button-secondary-bg-color)
+ );
+ --button-secondary-active-bg-color:var(
+ --button-background-color-active,
+ light-dark(rgb(21 20 26 / 0.21), rgb(251 251 254 / 0.21))
+ );
+ --button-secondary-active-fg-color:var(--button-secondary-fg-color);
+ --button-secondary-active-border-color:var(--button-secondary-bg-color);
+ --button-secondary-hover-bg-color:var(
+ --button-background-color-hover,
+ light-dark(rgb(21 20 26 / 0.14), rgb(251 251 254 / 0.14))
+ );
+ --button-secondary-hover-fg-color:var(--button-secondary-fg-color);
+ --button-secondary-hover-border-color:var(--button-secondary-hover-bg-color);
+ --button-secondary-disabled-bg-color:var(--button-secondary-bg-color);
+ --button-secondary-disabled-border-color:var(
+ --button-secondary-border-color
+ );
+ --button-secondary-disabled-fg-color:var(--button-secondary-fg-color);
+ --button-disabled-opacity:0.4;
+ --hover-filter:brightness(0.9);
+
+ @media (prefers-color-scheme: dark){
+ --button-disabled-opacity:0.6;
+ --hover-filter:brightness(1.4);
+ }
+
+ @media screen and (forced-colors: active){
+ --button-primary-bg-color:var(
+ --button-background-color-primary,
+ ButtonText
+ );
+ --button-primary-fg-color:var(--button-text-color-primary, ButtonFace);
+ --button-primary-border-color:var(
+ --button-border-color-primary,
+ ButtonText
+ );
+ --button-primary-active-bg-color:var(
+ --button-background-color-primary-active,
+ SelectedItem
+ );
+ --button-primary-active-fg-color:var(
+ --button-text-color-primary-active,
+ HighlightText
+ );
+ --button-primary-active-border-color:var(
+ --button-border-color-primary-active,
+ ButtonText
+ );
+ --button-primary-hover-bg-color:var(
+ --button-background-color-primary-hover,
+ SelectedItem
+ );
+ --button-primary-hover-fg-color:var(
+ --button-text-color-primary-hover,
+ HighlightText
+ );
+ --button-primary-hover-border-color:var(
+ --button-border-color-primary-hover,
+ SelectedItem
+ );
+ --button-primary-disabled-bg-color:var(
+ --button-background-color-primary-disabled,
+ GrayText
+ );
+ --button-primary-disabled-fg-color:var(
+ --button-text-color-primary-disabled,
+ ButtonFace
+ );
+ --button-primary-disabled-border-color:var(
+ --button-border-color-primary-disabled,
+ GrayText
+ );
+
+ --button-secondary-bg-color:var(--button-background-color, ButtonFace);
+ --button-secondary-fg-color:var(--button-text-color, ButtonText);
+ --button-secondary-border-color:var(--button-border-color, ButtonText);
+ --button-secondary-active-bg-color:var(
+ --button-background-color-active,
+ HighlightText
+ );
+ --button-secondary-active-fg-color:var(
+ --button-text-color-active,
+ SelectedItem
+ );
+ --button-secondary-active-border-color:var(
+ --button-border-color-active,
+ ButtonText
+ );
+ --button-secondary-hover-bg-color:var(
+ --button-background-color-hover,
+ HighlightText
+ );
+ --button-secondary-hover-fg-color:var(
+ --button-text-color-hover,
+ SelectedItem
+ );
+ --button-secondary-hover-border-color:var(
+ --button-border-color-hover,
+ SelectedItem
+ );
+ --button-secondary-disabled-fg-color:var(
+ --button-text-color-disabled,
+ GrayText
+ );
+ --button-secondary-disabled-border-color:var(
+ --button-border-color-disabled,
+ GrayText
+ );
+ --button-disabled-opacity:1;
+ --hover-filter:none;
+ }
+}
+
+.primaryButton,
+.secondaryButton{
+ border-radius:var(--button-border-radius, 4px);
+ border:1px solid;
+ font:menu;
+ font-weight:var(--button-font-weight, 590);
+ font-size:var(--button-font-size, 13px);
+ padding:var(--button-padding, 4px 16px);
+ width:auto;
+ min-height:var(--button-min-height, 32px);
+
+ &:hover{
+ cursor:pointer;
+ filter:var(--hover-filter);
+ }
+
+ > span{
+ color:inherit;
+ font:inherit;
+ }
+
+ &:disabled{
+ pointer-events:none;
+ }
+}
+
+.primaryButton{
+ color:var(--button-primary-fg-color);
+ background-color:var(--button-primary-bg-color);
+ border-color:var(--button-primary-border-color);
+ opacity:1;
+
+ &:hover{
+ color:var(--button-primary-hover-fg-color);
+ background-color:var(--button-primary-hover-bg-color);
+ border-color:var(--button-primary-hover-border-color);
+ }
+
+ &:active{
+ color:var(--button-primary-active-fg-color);
+ background-color:var(--button-primary-active-bg-color);
+ border-color:var(--button-primary-active-border-color);
+ }
+
+ &:disabled{
+ background-color:var(--button-primary-disabled-bg-color);
+ border-color:var(--button-primary-disabled-border-color);
+ color:var(--button-primary-disabled-fg-color);
+ opacity:var(--button-disabled-opacity);
+ }
+}
+
+.secondaryButton{
+ color:var(--button-secondary-fg-color);
+ background-color:var(--button-secondary-bg-color);
+ border-color:var(--button-secondary-border-color);
+
+ &:hover{
+ color:var(--button-secondary-hover-fg-color);
+ background-color:var(--button-secondary-hover-bg-color);
+ border-color:var(--button-secondary-hover-border-color);
+ }
+
+ &:active{
+ color:var(--button-secondary-active-fg-color);
+ background-color:var(--button-secondary-active-bg-color);
+ border-color:var(--button-secondary-active-border-color);
+ }
+
+ &:disabled{
+ background-color:var(--button-secondary-disabled-bg-color);
+ border-color:var(--button-secondary-disabled-border-color);
+ color:var(--button-secondary-disabled-fg-color);
+ opacity:var(--button-disabled-opacity);
+ }
+}
+
+.messageBar{
+ --closing-button-icon:url(images/messageBar_closingButton.svg);
+ --message-bar-close-button-color:var(--text-primary-color);
+ --message-bar-close-button-color-hover:var(--text-primary-color);
+ --message-bar-close-button-border-radius:var(--border-radius-small, 4px);
+ --message-bar-close-button-border:none;
+ --message-bar-close-button-hover-bg-color:var(
+ --button-background-color-hover,
+ light-dark(rgb(21 20 26 / 0.14), rgb(251 251 254 / 0.14))
+ );
+ --message-bar-close-button-active-bg-color:var(
+ --button-background-color-active,
+ light-dark(rgb(21 20 26 / 0.21), rgb(251 251 254 / 0.21))
+ );
+ --message-bar-close-button-focus-bg-color:var(
+ --button-background-color,
+ light-dark(rgb(21 20 26 / 0.07), rgb(251 251 254 / 0.07))
+ );
+
+ @media screen and (forced-colors: active){
+ --message-bar-close-button-color:var(--button-text-color, ButtonText);
+ --message-bar-close-button-border:1px solid var(--button-border-color, ButtonText);
+ --message-bar-close-button-hover-bg-color:var(
+ --button-background-color-hover,
+ SelectedItemText
+ );
+ --message-bar-close-button-active-bg-color:var(
+ --button-background-color-hover,
+ SelectedItemText
+ );
+ --message-bar-close-button-focus-bg-color:var(
+ --button-background-color-hover,
+ SelectedItemText
+ );
+ --message-bar-close-button-color-hover:var(
+ --button-text-color-hover,
+ SelectedItem
+ );
+ }
+
+ display:flex;
+ position:relative;
+ padding:8px 8px 8px 16px;
+ flex-direction:column;
+ justify-content:center;
+ align-items:center;
+ gap:8px;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ border-radius:var(--border-radius-small, 4px);
+
+ border:1px solid var(--message-bar-border-color);
+ background:var(--message-bar-bg-color);
+ color:var(--message-bar-fg-color);
+
+ > div{
+ display:flex;
+ align-items:flex-start;
+ gap:8px;
+ align-self:stretch;
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--message-bar-icon);
+ mask-image:var(--message-bar-icon);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:var(--message-bar-icon-color);
+ flex-shrink:0;
+ }
+ }
+
+ button{
+ cursor:pointer;
+
+ &:focus-visible{
+ outline:var(--focus-ring-outline);
+ outline-offset:2px;
+ }
+ }
+
+ .closeButton{
+ width:32px;
+ height:32px;
+ background:none;
+ border-radius:var(--message-bar-close-button-border-radius);
+ border:var(--message-bar-close-button-border);
+
+ display:flex;
+ align-items:center;
+ justify-content:center;
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--closing-button-icon);
+ mask-image:var(--closing-button-icon);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:var(--message-bar-close-button-color);
+ }
+
+ &:is(:hover, :active, :focus)::before{
+ background-color:var(--message-bar-close-button-color-hover);
+ }
+
+ &:hover{
+ background-color:var(--message-bar-close-button-hover-bg-color);
+ }
+
+ &:active{
+ background-color:var(--message-bar-close-button-active-bg-color);
+ }
+
+ &:focus{
+ background-color:var(--message-bar-close-button-focus-bg-color);
+ }
+
+ > span{
+ display:inline-block;
+ width:0;
+ height:0;
+ overflow:hidden;
+ }
+ }
+}
+
+#editorUndoBar{
+ --message-bar-icon:url(images/messageBar_info.svg);
+ --message-bar-icon-color:light-dark(#0060df, #73a7f3);
+ --message-bar-bg-color:light-dark(#deeafc, #003070);
+ --message-bar-fg-color:var(--text-primary-color);
+ --message-bar-border-color:light-dark(
+ rgb(0 0 0 / 0.08),
+ rgb(255 255 255 / 0.08)
+ );
+
+ @media screen and (forced-colors: active){
+ --message-bar-icon-color:CanvasText;
+ --message-bar-bg-color:Canvas;
+ --message-bar-border-color:CanvasText;
+ }
+
+ position:fixed;
+ top:50px;
+ left:50%;
+ transform:translateX(-50%);
+ z-index:10;
+
+ padding-block:8px;
+ padding-inline:16px 8px;
+
+ font:menu;
+ font-size:15px;
+
+ cursor:default;
+
+ button{
+ cursor:pointer;
+ }
+
+ #editorUndoBarUndoButton{
+ margin-inline-start:8px;
+ border-color:var(--color-accent-primary, light-dark(#0060df, #0df));
+ }
+
+ > div{
+ align-items:center;
+ }
+}
+
+.dialog{
+ --dialog-bg-color:var(--background-color-canvas, light-dark(white, #1c1b22));
+ --dialog-border-color:var(
+ --background-color-canvas,
+ light-dark(white, #1c1b22)
+ );
+ --dialog-shadow:0 2px 14px 0 light-dark(rgb(58 57 68 / 0.2), #15141a);
+ --text-secondary-color:light-dark(#5b5b66, #cfcfd8);
+ --separator-color:light-dark(#f0f0f4, #52525e);
+ --textarea-border-color:var(--border-color-interactive, #8f8f9d);
+ --textarea-bg-color:light-dark(white, #42414d);
+ --textarea-fg-color:var(--text-secondary-color);
+
+ --input-text-bg-color:light-dark(white, #42414d);
+ --input-text-fg-color:var(--text-primary-color);
+
+ @media screen and (forced-colors: active){
+ --dialog-bg-color:var(--background-color-canvas, Canvas);
+ --dialog-border-color:var(--border-color, CanvasText);
+ --dialog-shadow:none;
+ --text-secondary-color:CanvasText;
+ --separator-color:CanvasText;
+
+ --textarea-border-color:ButtonBorder;
+ --textarea-bg-color:Field;
+ --textarea-fg-color:ButtonText;
+
+ --input-text-bg-color:Field;
+ --input-text-fg-color:FieldText;
+ }
+
+ font:message-box;
+ font-size:13px;
+ font-weight:400;
+ line-height:150%;
+ border-radius:var(--border-radius-medium, 4px);
+ padding:12px 16px;
+ border:1px solid var(--dialog-border-color);
+ background:var(--dialog-bg-color);
+ color:var(--text-primary-color);
+ box-shadow:var(--dialog-shadow);
+
+ .mainContainer{
+ *:focus-visible{
+ outline:var(--focus-ring-outline);
+ outline-offset:2px;
+ }
+
+ .title{
+ display:flex;
+ width:auto;
+ flex-direction:column;
+ justify-content:flex-end;
+ align-items:flex-start;
+ gap:12px;
+
+ > span{
+ font-size:13px;
+ font-style:normal;
+ font-weight:590;
+ line-height:150%;
+ }
+ }
+
+ .dialogSeparator{
+ width:100%;
+ height:0;
+ margin-block:4px;
+ border-top:1px solid var(--separator-color);
+ border-bottom:none;
+ }
+
+ .dialogButtonsGroup{
+ display:flex;
+ gap:12px;
+ align-self:flex-end;
+ }
+ input:is([type="checkbox"], [type="radio"]){
+ accent-color:var(--color-accent-primary, light-dark(#0060df, #0df));
+ width:var(--checkbox-size, 16px);
+ height:var(--checkbox-size, 16px);
+ }
+
+ .radio{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:4px;
+
+ > .radioButton{
+ display:flex;
+ gap:8px;
+ align-self:stretch;
+ align-items:center;
+ }
+
+ > .radioLabel{
+ display:flex;
+ padding-inline-start:24px;
+ align-items:flex-start;
+ gap:10px;
+ align-self:stretch;
+
+ > span{
+ flex:1 0 0;
+ font-size:11px;
+ color:var(--text-secondary-color);
+ }
+ }
+ }
+
+ button:not(:is(.toggle-button, .closeButton, .clearInputButton)){
+ border-radius:var(--button-border-radius, 4px);
+ border-width:1px;
+ border-style:solid;
+ font:menu;
+ font-weight:var(--button-font-weight, 590);
+ font-size:var(--button-font-size, 13px);
+ padding:var(--button-padding, 4px 16px);
+ width:auto;
+ min-height:var(--button-min-height, 32px);
+
+ &:hover{
+ cursor:pointer;
+ filter:var(--hover-filter);
+ }
+
+ > span{
+ color:inherit;
+ font:inherit;
+ }
+ &:disabled{
+ pointer-events:none;
+ }
+ }
+
+ a{
+ color:var(--link-fg-color);
+
+ &:hover{
+ color:var(--link-hover-fg-color);
+ }
+ }
+
+ textarea{
+ font:inherit;
+ padding:8px;
+ resize:none;
+ margin:0;
+ box-sizing:border-box;
+ border-radius:var(--border-radius-small, 4px);
+ border:1px solid var(--textarea-border-color);
+ background:var(--textarea-bg-color);
+ color:var(--textarea-fg-color);
+
+ &:focus{
+ outline-offset:0;
+ border-color:transparent;
+ }
+
+ &:disabled{
+ pointer-events:none;
+ opacity:0.4;
+ }
+ }
+
+ input[type="text"]{
+ background-color:var(--input-text-bg-color);
+ color:var(--input-text-fg-color);
+ }
+
+ .messageBar{
+ --message-bar-bg-color:light-dark(#ffebcd, #5a3100);
+ --message-bar-fg-color:light-dark(#15141a, #fbfbfe);
+ --message-bar-border-color:light-dark(
+ rgb(0 0 0 / 0.08),
+ rgb(255 255 255 / 0.08)
+ );
+ --message-bar-icon:url(images/messageBar_warning.svg);
+ --message-bar-icon-color:light-dark(#cd411e, #e49c49);
+
+ @media screen and (forced-colors: active){
+ --message-bar-bg-color:HighlightText;
+ --message-bar-fg-color:CanvasText;
+ --message-bar-border-color:CanvasText;
+ --message-bar-icon-color:CanvasText;
+ }
+
+ align-self:stretch;
+
+ > div{
+ &::before,
+ > div{
+ margin-block:4px;
+ }
+
+ > div{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:8px;
+ flex:1 0 0;
+
+ .title{
+ font-size:13px;
+ font-weight:590;
+ }
+
+ .description{
+ font-size:13px;
+ }
+ }
+ }
+ }
+
+ .toggler{
+ display:flex;
+ align-items:center;
+ gap:8px;
+ align-self:stretch;
+
+ > .togglerLabel{
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ }
+ }
+ }
+}
+
+.textLayer{
+ color-scheme:only light;
+
+ position:absolute;
+ text-align:initial;
+ inset:0;
+ overflow:clip;
+ opacity:1;
+ line-height:1;
+ letter-spacing:normal;
+ word-spacing:normal;
+ -webkit-text-size-adjust:none;
+ -moz-text-size-adjust:none;
+ text-size-adjust:none;
+ forced-color-adjust:none;
+ transform-origin:0 0;
+ caret-color:CanvasText;
+ z-index:0;
+
+ &.highlighting{
+ touch-action:none;
+ }
+
+ :is(span, br){
+ color:transparent;
+ position:absolute;
+ white-space:pre;
+ cursor:text;
+ transform-origin:0% 0%;
+ -webkit-user-select:text;
+ -moz-user-select:text;
+ user-select:text;
+ }
+ --min-font-size:1;
+ --text-scale-factor:calc(var(--total-scale-factor) * var(--min-font-size));
+ --min-font-size-inv:calc(1 / var(--min-font-size));
+
+ > :not(.markedContent),
+ .markedContent span:not(.markedContent){
+ z-index:1;
+
+ --font-height:0;
+ font-size:calc(var(--text-scale-factor) * var(--font-height));
+
+ --scale-x:1;
+ --rotate:0deg;
+ transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
+ }
+
+ .markedContent{
+ display:contents;
+ }
+
+ span[role="img"]{
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ cursor:default;
+ }
+
+ .highlight{
+ --highlight-bg-color:rgb(180 0 170 / 0.25);
+ --highlight-selected-bg-color:rgb(0 100 0 / 0.25);
+ --highlight-backdrop-filter:none;
+ --highlight-selected-backdrop-filter:none;
+
+ @media screen and (forced-colors: active){
+ --highlight-bg-color:transparent;
+ --highlight-selected-bg-color:transparent;
+ --highlight-backdrop-filter:var(--hcm-highlight-filter);
+ --highlight-selected-backdrop-filter:var(
+ --hcm-highlight-selected-filter
+ );
+ }
+
+ margin:-1px;
+ padding:1px;
+ background-color:var(--highlight-bg-color);
+ backdrop-filter:var(--highlight-backdrop-filter);
+ border-radius:4px;
+
+ &.appended{
+ position:initial;
+ }
+
+ &.begin{
+ border-radius:4px 0 0 4px;
+ }
+
+ &.end{
+ border-radius:0 4px 4px 0;
+ }
+
+ &.middle{
+ border-radius:0;
+ }
+
+ &.selected{
+ background-color:var(--highlight-selected-bg-color);
+ backdrop-filter:var(--highlight-selected-backdrop-filter);
+ scroll-margin-top:50px;
+ }
+ }
+
+ ::-moz-selection{
+ background:rgba(0 0 255 / 0.25);
+ background:color-mix(in srgb, AccentColor, transparent 50%);
+ color:transparent;
+ }
+
+ ::selection{
+ background:rgba(0 0 255 / 0.25);
+ background:color-mix(in srgb, AccentColor, transparent 50%);
+ color:transparent;
+ }
+
+ &.selectionRendering{
+ ::-moz-selection{
+ background:transparent;
+ color:transparent;
+ }
+ ::selection{
+ background:transparent;
+ color:transparent;
+ }
+ }
+ br::-moz-selection{
+ background:transparent;
+ }
+ br::selection{
+ background:transparent;
+ }
+
+ .endOfContent{
+ display:block;
+ position:absolute;
+ inset:100% 0 0;
+ z-index:0;
+ cursor:default;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ }
+
+ &.selecting .endOfContent{
+ top:0;
+ }
+}
+
+.textLayerImages{
+ position:absolute;
+ inset:0;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ canvas{
+ position:absolute;
+ transform-origin:0% 0%;
+ }
+}
+
+.annotationLayer{
+ color-scheme:only light;
+
+ --annotation-unfocused-field-background:url("data:image/svg+xml;charset=UTF-8,");
+ --annotation-unfocused-field-filter:url("data:image/svg+xml;charset=UTF-8,#pdfjsFillableField");
+ --input-focus-border-color:Highlight;
+ --input-focus-outline:1px solid Canvas;
+ --input-unfocused-border-color:transparent;
+ --input-disabled-border-color:transparent;
+ --input-hover-border-color:black;
+ --link-outline:none;
+
+ @media screen and (forced-colors: active){
+ --input-focus-border-color:CanvasText;
+ --input-unfocused-border-color:ActiveText;
+ --input-disabled-border-color:GrayText;
+ --input-hover-border-color:Highlight;
+ --link-outline:1.5px solid LinkText;
+
+ .textWidgetAnnotation :is(input, textarea):required,
+ .choiceWidgetAnnotation select:required,
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required{
+ outline:1.5px solid selectedItem;
+ }
+
+ .linkAnnotation{
+ outline:var(--link-outline);
+
+ &:hover{
+ backdrop-filter:var(--hcm-highlight-filter);
+ }
+
+ & > a:hover{
+ opacity:0 !important;
+ background:none !important;
+ box-shadow:none;
+ }
+ }
+
+ .popupAnnotation .popup{
+ outline:calc(1.5px * var(--total-scale-factor)) solid CanvasText !important;
+ background-color:ButtonFace !important;
+ color:ButtonText !important;
+ }
+
+ .highlightArea:hover::after{
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ backdrop-filter:var(--hcm-highlight-filter);
+ content:"";
+ pointer-events:none;
+ }
+
+ .popupAnnotation.focused .popup{
+ outline:calc(3px * var(--total-scale-factor)) solid Highlight !important;
+ }
+ }
+
+ position:absolute;
+ top:0;
+ left:0;
+ pointer-events:none;
+ transform-origin:0 0;
+
+ &[data-main-rotation="90"] .norotate{
+ transform:rotate(270deg) translateX(-100%);
+ }
+ &[data-main-rotation="180"] .norotate{
+ transform:rotate(180deg) translate(-100%, -100%);
+ }
+ &[data-main-rotation="270"] .norotate{
+ transform:rotate(90deg) translateY(-100%);
+ }
+
+ &.disabled{
+ section,
+ .popup{
+ pointer-events:none;
+ }
+ }
+
+ .annotationContent{
+ position:absolute;
+ width:100%;
+ height:100%;
+ pointer-events:none;
+
+ &.freetext{
+ background:transparent;
+ border:none;
+ inset:0;
+ overflow:visible;
+ white-space:nowrap;
+ font:10px sans-serif;
+ line-height:1.35;
+ }
+ }
+
+ section{
+ position:absolute;
+ text-align:initial;
+ pointer-events:auto;
+ box-sizing:border-box;
+ transform-origin:0 0;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ &:has(div.annotationContent){
+ canvas.annotationContent{
+ display:none;
+ }
+ }
+
+ .overlaidText{
+ position:absolute;
+ top:0;
+ left:0;
+ width:0;
+ height:0;
+ display:inline-block;
+ overflow:hidden;
+ }
+ }
+ .hasOwnCanvas:not(.sandboxModified) :is(input, textarea){
+ display:none;
+ }
+
+ .hasOwnCanvas.sandboxModified canvas.annotationContent{
+ display:none;
+ }
+
+ .textLayer.selecting ~ & section{
+ pointer-events:none;
+ }
+
+ :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton) > a{
+ position:absolute;
+ font-size:1em;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ }
+
+ :is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder)
+ > a:hover{
+ opacity:0.2;
+ background-color:rgb(255 255 0);
+ }
+
+ .linkAnnotation.hasBorder:hover{
+ background-color:rgb(255 255 0 / 0.2);
+ }
+
+ .hasBorder{
+ background-size:100% 100%;
+ }
+
+ .textAnnotation img{
+ position:absolute;
+ cursor:pointer;
+ width:100%;
+ height:100%;
+ top:0;
+ left:0;
+ }
+
+ .textWidgetAnnotation :is(input, textarea),
+ .choiceWidgetAnnotation select,
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) input{
+ background-image:var(--annotation-unfocused-field-background);
+ border:2px solid var(--input-unfocused-border-color);
+ box-sizing:border-box;
+ font:calc(9px * var(--total-scale-factor)) sans-serif;
+ height:100%;
+ margin:0;
+ vertical-align:top;
+ width:100%;
+ }
+
+ .textWidgetAnnotation :is(input, textarea):required,
+ .choiceWidgetAnnotation select:required,
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required{
+ outline:1.5px solid red;
+ }
+
+ .choiceWidgetAnnotation select option{
+ padding:0;
+ }
+
+ .textWidgetAnnotation textarea{
+ resize:none;
+ }
+
+ .textWidgetAnnotation :is(input, textarea)[disabled],
+ .choiceWidgetAnnotation select[disabled],
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) input[disabled]{
+ background:none;
+ border:2px solid var(--input-disabled-border-color);
+ cursor:not-allowed;
+ }
+
+ .textWidgetAnnotation :is(input, textarea):hover,
+ .choiceWidgetAnnotation select:hover,
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) input:hover{
+ border:2px solid var(--input-hover-border-color);
+ }
+ .textWidgetAnnotation :is(input, textarea):hover,
+ .choiceWidgetAnnotation select:hover,
+ .buttonWidgetAnnotation.checkBox input:hover{
+ border-radius:2px;
+ }
+
+ .textWidgetAnnotation :is(input, textarea):focus,
+ .choiceWidgetAnnotation select:focus{
+ background:none;
+ border:2px solid var(--input-focus-border-color);
+ border-radius:2px;
+ outline:var(--input-focus-outline);
+ }
+
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) :focus{
+ background-image:none;
+ background-color:transparent;
+ }
+
+ .buttonWidgetAnnotation.checkBox :focus{
+ border:2px solid var(--input-focus-border-color);
+ border-radius:2px;
+ outline:var(--input-focus-outline);
+ }
+
+ .buttonWidgetAnnotation.radioButton :focus{
+ border:2px solid var(--input-focus-border-color);
+ outline:var(--input-focus-outline);
+ }
+
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton){
+ [data-canvas-name]{
+ filter:var(--annotation-unfocused-field-filter);
+ }
+
+ &:focus-within [data-canvas-name]{
+ filter:none;
+ }
+
+ [data-canvas-name="checked"]{
+ &:has(~ input:checked){
+ display:block;
+ }
+
+ &:has(~ input:not(:checked)){
+ display:none;
+ }
+ }
+
+ [data-canvas-name="unchecked"]{
+ &:has(~ input:checked){
+ display:none;
+ }
+
+ &:has(~ input:not(:checked)){
+ display:block;
+ }
+ }
+ }
+
+ .textWidgetAnnotation input.comb{
+ --comb-width:0px;
+ --comb-letter-spacing:calc(var(--comb-width) - 1ch);
+
+ font-family:monospace;
+ letter-spacing:var(--comb-letter-spacing);
+ overflow-x:hidden;
+ padding:0;
+ text-indent:calc(
+ var(--comb-offset, 0) * var(--comb-width) + var(--comb-letter-spacing) / 2
+ );
+ }
+
+ .textWidgetAnnotation input.comb:focus{
+ background-image:repeating-linear-gradient(
+ to right,
+ transparent 0 calc(var(--comb-width) - 1px),
+ var(--input-focus-border-color) calc(var(--comb-width) - 1px)
+ var(--comb-width)
+ );
+ }
+
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton) input{
+ -webkit-appearance:none;
+ -moz-appearance:none;
+ appearance:none;
+ }
+
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton):has(
+ [data-canvas-name="checked"]
+ )
+ input:checked,
+ .buttonWidgetAnnotation:is(.checkBox, .radioButton):has(
+ [data-canvas-name="unchecked"]
+ )
+ input:not(:checked){
+ background-image:none;
+ }
+
+ .fileAttachmentAnnotation .popupTriggerArea{
+ height:100%;
+ width:100%;
+ }
+
+ .mediaAnnotation{
+ pointer-events:auto;
+
+ .mediaContent{
+ width:100%;
+ }
+
+ video.mediaContent{
+ height:100%;
+ -o-object-fit:contain;
+ object-fit:contain;
+ }
+
+ audio.mediaContent{
+ position:absolute;
+ bottom:0;
+ }
+
+ .mediaPlayButton{
+ height:100%;
+ width:100%;
+ margin:0;
+ padding:0;
+ border:none;
+ cursor:pointer;
+ background-color:transparent;
+ background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='40' fill='rgba(0,0,0,0.55)'/%3E%3Cpath d='M40 32 L70 50 L40 68 Z' fill='white'/%3E%3C/svg%3E");
+ background-position:center;
+ background-repeat:no-repeat;
+ background-size:calc(48px * var(--total-scale-factor));
+
+ &:hover{
+ background-color:rgba(255 255 255 / 0.1);
+ }
+ }
+ }
+
+ .popupAnnotation{
+ position:absolute;
+ font-size:calc(9px * var(--total-scale-factor));
+ pointer-events:none;
+ width:-moz-max-content;
+ width:max-content;
+ max-width:45%;
+ height:auto;
+ }
+
+ .popup{
+ background-color:rgb(255 255 153);
+ color:black;
+ box-shadow:0 calc(2px * var(--total-scale-factor)) calc(5px * var(--total-scale-factor)) rgb(136 136 136);
+ border-radius:calc(2px * var(--total-scale-factor));
+ outline:1.5px solid rgb(255 255 74);
+ padding:calc(6px * var(--total-scale-factor));
+ cursor:pointer;
+ font:message-box;
+ white-space:normal;
+ word-wrap:break-word;
+ pointer-events:auto;
+ -webkit-user-select:text;
+ -moz-user-select:text;
+ user-select:text;
+ }
+
+ .popupAnnotation.focused .popup{
+ outline-width:3px;
+ }
+
+ .popup *{
+ font-size:calc(9px * var(--total-scale-factor));
+ }
+
+ .popup > .header{
+ display:inline-block;
+ }
+
+ .popup > .header > .title{
+ display:inline;
+ font-weight:bold;
+ }
+
+ .popup > .header .popupDate{
+ display:inline-block;
+ margin-left:calc(5px * var(--total-scale-factor));
+ width:-moz-fit-content;
+ width:fit-content;
+ }
+
+ .popupContent{
+ border-top:1px solid rgb(51 51 51);
+ margin-top:calc(2px * var(--total-scale-factor));
+ padding-top:calc(2px * var(--total-scale-factor));
+ }
+
+ .richText > *{
+ white-space:pre-wrap;
+ font-size:calc(9px * var(--total-scale-factor));
+ }
+
+ .popupTriggerArea{
+ cursor:pointer;
+
+ &:hover{
+ backdrop-filter:var(--hcm-highlight-filter);
+ }
+ }
+
+ section svg{
+ position:absolute;
+ width:100%;
+ height:100%;
+ top:0;
+ left:0;
+ }
+
+ .annotationTextContent{
+ position:absolute;
+ width:100%;
+ height:100%;
+ opacity:0;
+ color:transparent;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ pointer-events:none;
+
+ span{
+ width:100%;
+ display:inline-block;
+ }
+ }
+
+ svg.quadrilateralsContainer{
+ contain:strict;
+ width:0;
+ height:0;
+ position:absolute;
+ top:0;
+ left:0;
+ z-index:-1;
+ }
+}
+
+:root{
+ --xfa-unfocused-field-background:url("data:image/svg+xml;charset=UTF-8,");
+ --xfa-focus-outline:auto;
+}
+
+@media screen and (forced-colors: active){
+ :root{
+ --xfa-focus-outline:2px solid CanvasText;
+ }
+ .xfaLayer *:required{
+ outline:1.5px solid selectedItem;
+ }
+}
+
+.xfaLayer{
+ color-scheme:only light;
+
+ background-color:transparent;
+}
+
+.xfaLayer .highlight{
+ margin:-1px;
+ padding:1px;
+ background-color:rgb(239 203 237);
+ border-radius:4px;
+}
+
+.xfaLayer .highlight.appended{
+ position:initial;
+}
+
+.xfaLayer .highlight.begin{
+ border-radius:4px 0 0 4px;
+}
+
+.xfaLayer .highlight.end{
+ border-radius:0 4px 4px 0;
+}
+
+.xfaLayer .highlight.middle{
+ border-radius:0;
+}
+
+.xfaLayer .highlight.selected{
+ background-color:rgb(203 223 203);
+}
+
+.xfaPage{
+ overflow:hidden;
+ position:relative;
+}
+
+.xfaContentarea{
+ position:absolute;
+}
+
+.xfaPrintOnly{
+ display:none;
+}
+
+.xfaLayer{
+ position:absolute;
+ text-align:initial;
+ top:0;
+ left:0;
+ transform-origin:0 0;
+ line-height:1.2;
+}
+
+.xfaLayer *{
+ color:inherit;
+ font:inherit;
+ font-style:inherit;
+ font-weight:inherit;
+ font-kerning:inherit;
+ letter-spacing:-0.01px;
+ text-align:inherit;
+ text-decoration:inherit;
+ box-sizing:border-box;
+ background-color:transparent;
+ padding:0;
+ margin:0;
+ pointer-events:auto;
+ line-height:inherit;
+}
+
+.xfaLayer *:required{
+ outline:1.5px solid red;
+}
+
+.xfaLayer div,
+.xfaLayer svg,
+.xfaLayer svg *{
+ pointer-events:none;
+}
+
+.xfaLayer a{
+ color:blue;
+}
+
+.xfaRich li{
+ margin-left:3em;
+}
+
+.xfaFont{
+ color:black;
+ font-weight:normal;
+ font-kerning:none;
+ font-size:10px;
+ font-style:normal;
+ letter-spacing:0;
+ text-decoration:none;
+ vertical-align:0;
+}
+
+.xfaCaption{
+ overflow:hidden;
+ flex:0 0 auto;
+}
+
+.xfaCaptionForCheckButton{
+ overflow:hidden;
+ flex:1 1 auto;
+}
+
+.xfaLabel{
+ height:100%;
+ width:100%;
+}
+
+.xfaLeft{
+ display:flex;
+ flex-direction:row;
+ align-items:center;
+}
+
+.xfaRight{
+ display:flex;
+ flex-direction:row-reverse;
+ align-items:center;
+}
+
+:is(.xfaLeft, .xfaRight) > :is(.xfaCaption, .xfaCaptionForCheckButton){
+ max-height:100%;
+}
+
+.xfaTop{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+}
+
+.xfaBottom{
+ display:flex;
+ flex-direction:column-reverse;
+ align-items:flex-start;
+}
+
+:is(.xfaTop, .xfaBottom) > :is(.xfaCaption, .xfaCaptionForCheckButton){
+ width:100%;
+}
+
+.xfaBorder{
+ background-color:transparent;
+ position:absolute;
+ pointer-events:none;
+}
+
+.xfaWrapped{
+ width:100%;
+ height:100%;
+}
+
+:is(.xfaTextfield, .xfaSelect):focus{
+ background-image:none;
+ background-color:transparent;
+ outline:var(--xfa-focus-outline);
+ outline-offset:-1px;
+}
+
+:is(.xfaCheckbox, .xfaRadio):focus{
+ outline:var(--xfa-focus-outline);
+}
+
+.xfaTextfield,
+.xfaSelect{
+ height:100%;
+ width:100%;
+ flex:1 1 auto;
+ border:none;
+ resize:none;
+ background-image:var(--xfa-unfocused-field-background);
+}
+
+.xfaSelect{
+ padding-inline:2px;
+}
+
+:is(.xfaTop, .xfaBottom) > :is(.xfaTextfield, .xfaSelect){
+ flex:0 1 auto;
+}
+
+.xfaButton{
+ cursor:pointer;
+ width:100%;
+ height:100%;
+ border:none;
+ text-align:center;
+}
+
+.xfaLink{
+ width:100%;
+ height:100%;
+ position:absolute;
+ top:0;
+ left:0;
+}
+
+.xfaCheckbox,
+.xfaRadio{
+ width:100%;
+ height:100%;
+ flex:0 0 auto;
+ border:none;
+}
+
+.xfaRich{
+ white-space:pre-wrap;
+ width:100%;
+ height:100%;
+}
+
+.xfaImage{
+ -o-object-position:left top;
+ object-position:left top;
+ -o-object-fit:contain;
+ object-fit:contain;
+ width:100%;
+ height:100%;
+}
+
+.xfaLrTb,
+.xfaRlTb,
+.xfaTb{
+ display:flex;
+ flex-direction:column;
+ align-items:stretch;
+}
+
+.xfaLr{
+ display:flex;
+ flex-direction:row;
+ align-items:stretch;
+}
+
+.xfaRl{
+ display:flex;
+ flex-direction:row-reverse;
+ align-items:stretch;
+}
+
+.xfaTb > div{
+ justify-content:left;
+}
+
+.xfaPosition{
+ position:relative;
+}
+
+.xfaArea{
+ position:relative;
+}
+
+.xfaValignMiddle{
+ display:flex;
+ align-items:center;
+}
+
+.xfaTable{
+ display:flex;
+ flex-direction:column;
+ align-items:stretch;
+}
+
+.xfaTable .xfaRow{
+ display:flex;
+ flex-direction:row;
+ align-items:stretch;
+}
+
+.xfaTable .xfaRlRow{
+ display:flex;
+ flex-direction:row-reverse;
+ align-items:stretch;
+ flex:1;
+}
+
+.xfaTable .xfaRlRow > div{
+ flex:1;
+}
+
+:is(.xfaNonInteractive, .xfaDisabled, .xfaReadOnly) :is(input, textarea){
+ background:initial;
+}
+
+@media print{
+ .xfaTextfield,
+ .xfaSelect{
+ background:transparent;
+ }
+
+ .xfaSelect{
+ -webkit-appearance:none;
+ -moz-appearance:none;
+ appearance:none;
+ text-indent:1px;
+ text-overflow:"";
+ }
+}
+
+.canvasWrapper{
+ svg{
+ transform:none;
+
+ &.moving{
+ z-index:100000;
+ }
+
+ &.highlight,
+ &.highlightOutline{
+ &[data-main-rotation="90"]{
+ mask,
+ use:not(.clip, .mask){
+ transform:matrix(0, 1, -1, 0, 1, 0);
+ }
+ }
+
+ &[data-main-rotation="180"]{
+ mask,
+ use:not(.clip, .mask){
+ transform:matrix(-1, 0, 0, -1, 1, 1);
+ }
+ }
+
+ &[data-main-rotation="270"]{
+ mask,
+ use:not(.clip, .mask){
+ transform:matrix(0, -1, 1, 0, 0, 1);
+ }
+ }
+ }
+
+ &.draw{
+ position:absolute;
+ mix-blend-mode:normal;
+
+ &[data-draw-rotation="90"]{
+ transform:rotate(90deg);
+ }
+
+ &[data-draw-rotation="180"]{
+ transform:rotate(180deg);
+ }
+
+ &[data-draw-rotation="270"]{
+ transform:rotate(270deg);
+ }
+ }
+
+ &.highlight{
+ --blend-mode:multiply;
+
+ @media screen and (forced-colors: active){
+ --blend-mode:difference;
+ }
+
+ position:absolute;
+ mix-blend-mode:var(--blend-mode);
+
+ &:not(.free){
+ fill-rule:evenodd;
+ }
+ }
+
+ &.highlightOutline{
+ position:absolute;
+ mix-blend-mode:normal;
+ fill-rule:evenodd;
+ fill:none;
+
+ &:not(.free){
+ &.hovered:not(.selected){
+ stroke:var(--hover-outline-color);
+ stroke-width:var(--outline-width);
+ }
+
+ &.selected{
+ .mainOutline{
+ stroke:var(--outline-around-color);
+ stroke-width:calc(
+ var(--outline-width) + 2 * var(--outline-around-width)
+ );
+ }
+
+ .secondaryOutline{
+ stroke:var(--outline-color);
+ stroke-width:var(--outline-width);
+ }
+ }
+ }
+
+ &.free{
+ &.hovered:not(.selected){
+ stroke:var(--hover-outline-color);
+ stroke-width:calc(2 * var(--outline-width));
+ }
+
+ &.selected{
+ .mainOutline{
+ stroke:var(--outline-around-color);
+ stroke-width:calc(
+ 2 * (var(--outline-width) + var(--outline-around-width))
+ );
+ }
+
+ .secondaryOutline{
+ stroke:var(--outline-color);
+ stroke-width:calc(2 * var(--outline-width));
+ }
+ }
+ }
+ }
+ }
+}
+
+.toggle-button{
+ --toggle-background-color:var(
+ --button-background-color,
+ color-mix(in srgb, currentColor 7%, transparent)
+ );
+ --toggle-background-color-hover:var(
+ --button-background-color-hover,
+ color-mix(in srgb, currentColor 14%, transparent)
+ );
+ --toggle-background-color-active:var(
+ --button-background-color-active,
+ color-mix(in srgb, currentColor 21%, transparent)
+ );
+ --toggle-background-color-pressed:var(
+ --color-accent-primary,
+ light-dark(#0060df, #0df)
+ );
+ --toggle-background-color-pressed-hover:var(
+ --color-accent-primary-hover,
+ light-dark(#0250bb, #80ebff)
+ );
+ --toggle-background-color-pressed-active:var(
+ --color-accent-primary-active,
+ light-dark(#054096, #aaf2ff)
+ );
+ --toggle-border-color:var(
+ --border-color-interactive,
+ light-dark(#8f8f9d, #f9f9fa)
+ );
+ --toggle-border-color-hover:var(--toggle-border-color);
+ --toggle-border-color-active:var(--toggle-border-color);
+ --toggle-border-radius:var(--border-radius-circle, 9999px);
+ --toggle-border-width:var(--border-width, 1px);
+ --toggle-height:var(--size-item-small, 16px);
+ --toggle-width:var(--size-item-large, 32px);
+ --toggle-dot-background-color:var(--toggle-border-color);
+ --toggle-dot-background-color-hover:var(--toggle-dot-background-color);
+ --toggle-dot-background-color-active:var(--toggle-dot-background-color);
+ --toggle-dot-background-color-on-pressed:var(
+ --background-color-canvas,
+ light-dark(white, #1c1b22)
+ );
+ --toggle-dot-margin:1px;
+ --toggle-dot-height:calc(
+ var(--toggle-height) - 2 * var(--toggle-dot-margin) - 2 *
+ var(--toggle-border-width)
+ );
+ --toggle-dot-width:var(--toggle-dot-height);
+ --toggle-dot-transform-x:calc(
+ var(--toggle-width) - 4 * var(--toggle-dot-margin) - var(--toggle-dot-width)
+ );
+ --input-width:var(--toggle-width);
+
+ -webkit-appearance:none;
+
+ -moz-appearance:none;
+
+ appearance:none;
+ padding:0;
+ border:var(--toggle-border-width) solid var(--toggle-border-color);
+ height:var(--toggle-height);
+ width:var(--toggle-width);
+ border-radius:var(--toggle-border-radius);
+ background-color:var(--toggle-background-color);
+ box-sizing:border-box;
+
+ &:focus-visible{
+ outline:var(--focus-ring-outline);
+ outline-offset:var(--focus-outline-offset, 2px);
+ }
+
+ &:enabled:hover{
+ background-color:var(--toggle-background-color-hover);
+ border-color:var(--toggle-border-color);
+ }
+
+ &:enabled:hover:active{
+ background-color:var(--toggle-background-color-active);
+ border-color:var(--toggle-border-color);
+ }
+
+ &::before{
+ display:block;
+ content:"";
+ background-color:var(--toggle-dot-background-color);
+ height:var(--toggle-dot-height);
+ width:var(--toggle-dot-width);
+ margin:var(--toggle-dot-margin);
+ border-radius:var(--toggle-border-radius);
+ translate:0;
+ }
+}
+
+.toggle-button[aria-pressed="true"]{
+ background-color:var(--toggle-background-color-pressed);
+ border-color:transparent;
+
+ &:enabled:hover{
+ background-color:var(--toggle-background-color-pressed-hover);
+ border-color:transparent;
+ }
+
+ &:enabled:hover:active{
+ background-color:var(--toggle-background-color-pressed-active);
+ border-color:transparent;
+ }
+
+ &::before{
+ translate:var(--toggle-dot-transform-x);
+ background-color:var(--toggle-dot-background-color-on-pressed);
+ }
+
+ &:enabled:hover::before,
+ &:enabled:hover:active::before{
+ background-color:var(--toggle-dot-background-color-on-pressed);
+ }
+
+ &:-moz-locale-dir(rtl)::before,
+ &:dir(rtl)::before{
+ translate:calc(-1 * var(--toggle-dot-transform-x));
+ }
+}
+
+@media (prefers-reduced-motion: no-preference){
+ .toggle-button::before{
+ transition:translate 100ms;
+ }
+}
+
+@media (prefers-contrast){
+ .toggle-button:enabled:hover{
+ border-color:var(--toggle-border-color-hover);
+ }
+
+ .toggle-button:enabled:hover:active{
+ border-color:var(--toggle-border-color-active);
+ }
+
+ .toggle-button[aria-pressed="true"]:enabled{
+ border-color:var(--toggle-border-color);
+ position:relative;
+
+ &:hover{
+ border-color:var(--toggle-border-color-hover);
+
+ &:active{
+ background-color:var(--toggle-dot-background-color-active);
+ border-color:var(--toggle-dot-background-color-hover);
+ }
+ }
+ }
+
+ .toggle-button:enabled:hover::before,
+ .toggle-button:enabled:hover:active::before{
+ background-color:var(--toggle-dot-background-color-hover);
+ }
+}
+
+@media (forced-colors){
+ .toggle-button{
+ --toggle-background-color:var(--button-background-color, ButtonFace);
+ --toggle-background-color-pressed:var(--color-accent-primary, ButtonText);
+ --toggle-background-color-pressed-hover:var(
+ --color-accent-primary-hover,
+ SelectedItem
+ );
+ --toggle-background-color-pressed-active:var(
+ --color-accent-primary-active,
+ SelectedItem
+ );
+ --toggle-border-color:var(--border-color-interactive, ButtonText);
+ --toggle-dot-background-color:var(--color-accent-primary, ButtonText);
+ --toggle-dot-background-color-hover:var(
+ --color-accent-primary-hover,
+ SelectedItem
+ );
+ --toggle-dot-background-color-active:var(
+ --color-accent-primary-active,
+ SelectedItem
+ );
+ --toggle-dot-background-color-on-pressed:var(
+ --button-background-color,
+ ButtonFace
+ );
+ --toggle-border-color-hover:var(
+ --border-color-interactive-hover,
+ SelectedItem
+ );
+ --toggle-border-color-active:var(
+ --border-color-interactive-active,
+ ButtonText
+ );
+ }
+
+ .toggle-button[aria-pressed="true"]:enabled::after{
+ border:1px solid var(--button-background-color, ButtonFace);
+ content:"";
+ position:absolute;
+ height:var(--toggle-height);
+ width:var(--toggle-width);
+ display:block;
+ border-radius:var(--toggle-border-radius);
+ inset:-2px;
+ }
+
+ .toggle-button[aria-pressed="true"]:enabled:hover:active::after{
+ border-color:var(--toggle-border-color-active);
+ }
+}
+
+:root{
+ --clear-signature-button-icon:url(images/editor-toolbar-delete.svg);
+ --signature-bg:var(
+ --background-color-box-info,
+ light-dark(#f9f9fb, #2b2a33)
+ );
+ --signature-hover-bg:var(
+ --button-background-color-hover,
+ light-dark(#f0f0f4, var(--signature-bg))
+ );
+ --button-signature-bg:transparent;
+ --button-signature-color:var(--main-color);
+ --button-signature-active-bg:light-dark(#cfcfd8, #5b5b66);
+ --button-signature-active-border:none;
+ --button-signature-active-color:var(--button-signature-color);
+ --button-signature-border:none;
+ --button-signature-hover-bg:light-dark(#e0e0e6, #52525e);
+ --button-signature-hover-color:var(--button-signature-color);
+
+ @media screen and (forced-colors: active){
+ --signature-bg:HighlightText;
+ --signature-hover-bg:var(--signature-bg);
+ --button-signature-bg:HighlightText;
+ --button-signature-color:ButtonText;
+ --button-signature-active-bg:ButtonText;
+ --button-signature-active-color:HighlightText;
+ --button-signature-border:1px solid ButtonText;
+ --button-signature-hover-bg:Highlight;
+ --button-signature-hover-color:HighlightText;
+ }
+}
+
+.signatureDialog{
+ --primary-color:var(--text-primary-color);
+ --signature-border-color:var(--border-color-interactive, #8f8f9d);
+ --open-link-fg:var(--link-fg-color);
+ --open-link-hover-fg:var(--link-hover-fg-color);
+
+ @media screen and (forced-colors: active){
+ --primary-color:ButtonText;
+ --signature-border-color:var(--border-color-interactive, ButtonText);
+ --open-link-fg:ButtonText;
+ --open-link-hover-fg:ButtonText;
+ }
+
+ width:570px;
+ max-width:100%;
+ min-width:300px;
+ padding:16px 0;
+
+ .mainContainer{
+ width:100%;
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:12px;
+
+ span:not([role="sectionhead"]){
+ font-size:13px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ }
+
+ .title{
+ margin-inline-start:16px;
+ }
+ }
+
+ .inputWithClearButton{
+ --button-dimension:24px;
+ --clear-button-icon:url(images/messageBar_closingButton.svg);
+
+ width:100%;
+ position:relative;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+
+ > input{
+ width:100%;
+ height:var(--size-item-large, 32px);
+ padding-inline:8px calc(4px + var(--button-dimension));
+ box-sizing:border-box;
+ border-radius:var(--border-radius-small, 4px);
+ border:1px solid var(--signature-border-color);
+ }
+
+ .clearInputButton{
+ position:absolute;
+ inset-block-start:4px;
+ inset-inline-end:4px;
+ display:inline-block;
+ width:var(--button-dimension);
+ height:var(--button-dimension);
+ background-color:var(--input-text-fg-color);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ -webkit-mask-image:var(--clear-button-icon);
+ mask-image:var(--clear-button-icon);
+ padding:0;
+ border:0;
+ }
+ }
+}
+
+#addSignatureDialog{
+ --secondary-color:var(--text-secondary-color);
+ --bg-hover:var(
+ --button-background-color-hover,
+ light-dark(#e0e0e6, #52525e)
+ );
+ --tab-top-line-active-color:var(
+ --color-accent-primary,
+ light-dark(#0060df, #0df)
+ );
+ --tab-top-line-active-hover-color:var(--tab-text-hover-color);
+ --tab-top-line-hover-color:var(--border-color-interactive, #8f8f9d);
+ --tab-top-line-inactive-color:light-dark(#cfcfd8, #8f8f9d);
+ --tab-bottom-line-active-color:var(--tab-top-line-inactive-color);
+ --tab-bottom-line-hover-color:var(--tab-top-line-inactive-color);
+ --tab-bottom-line-inactive-color:var(--tab-top-line-inactive-color);
+ --tab-bg:var(--dialog-bg-color);
+ --tab-bg-active-color:var(--tab-bg);
+ --tab-bg-active-hover-color:var(--bg-hover);
+ --tab-bg-hover:var(--bg-hover);
+ --tab-panel-border:none;
+ --tab-panel-border-radius:var(--border-radius-small, 4px);
+ --tab-text-color:var(--primary-color);
+ --tab-text-active-color:var(--tab-top-line-active-color);
+ --tab-text-active-hover-color:var(--tab-text-hover-color);
+ --tab-text-hover-color:var(--tab-text-color);
+ --signature-placeholder-color:var(--secondary-color);
+ --signature-draw-placeholder-color:var(--primary-color);
+ --signature-color:var(--primary-color);
+ --save-warning-color:var(--secondary-color);
+ --thickness-bg:var(--dialog-bg-color);
+ --thickness-label-color:var(--primary-color);
+ --thickness-slider-color:var(--primary-color);
+ --thickness-border:none;
+ --draw-cursor:url(images/cursor-editorInk.svg) 0 16, pointer;
+
+ @media screen and (forced-colors: active){
+ --secondary-color:ButtonText;
+ --bg:HighlightText;
+ --bg-hover:var(--bg);
+ --tab-top-line-active-color:var(--color-accent-primary, ButtonText);
+ --tab-top-line-active-hover-color:HighlightText;
+ --tab-top-line-hover-color:var(--border-color-interactive, SelectedItem);
+ --tab-top-line-inactive-color:ButtonText;
+ --tab-bottom-line-active-color:var(--tab-top-line-active-color);
+ --tab-bottom-line-hover-color:var(--tab-top-line-hover-color);
+ --tab-bg:var(--bg);
+ --tab-bg-active-color:SelectedItem;
+ --tab-bg-active-hover-color:SelectedItem;
+ --tab-panel-border:1px solid ButtonText;
+ --tab-panel-border-radius:8px;
+ --tab-text-color:ButtonText;
+ --tab-text-active-color:HighlightText;
+ --tab-text-active-hover-color:HighlightText;
+ --tab-text-hover-color:SelectedItem;
+ --signature-color:ButtonText;
+ --thickness-bg:Canvas;
+ --thickness-label-color:CanvasText;
+ --thickness-slider-color:ButtonText;
+ --thickness-border:1px solid var(--signature-border-color);
+ }
+
+ #addSignatureDialogLabel{
+ overflow:hidden;
+ position:absolute;
+ inset:0;
+ width:0;
+ height:0;
+ }
+
+ &.waiting::after{
+ content:"";
+ cursor:wait;
+ position:absolute;
+ inset:0;
+ width:100%;
+ height:100%;
+ }
+
+ .mainContainer{
+ [role="tablist"]{
+ width:100%;
+ display:flex;
+ align-items:flex-start;
+ gap:0;
+
+ > [role="tab"]{
+ flex:1 0 0;
+ align-self:stretch;
+ background-color:var(--tab-bg);
+ padding-inline:0;
+ cursor:default;
+
+ border-inline:0;
+ border-block-width:1px;
+ border-block-style:solid;
+ border-block-start-color:var(--tab-top-line-inactive-color);
+ border-block-end-color:var(--tab-bottom-line-inactive-color);
+ border-radius:0;
+
+ font:menu;
+ font-size:13px;
+ font-style:normal;
+ line-height:normal;
+ font-weight:400;
+ color:var(--tab-text-color);
+
+ &:hover{
+ border-block-start-width:2px;
+ border-block-start-color:var(--tab-top-line-hover-color);
+ border-block-end-color:var(--tab-bottom-line-hover-color);
+ background-color:var(--tab-bg-hover);
+ color:var(--tab-text-hover-color);
+ }
+
+ &:focus-visible{
+ outline:2px solid var(--tab-top-line-active-color);
+ outline-offset:-2px;
+ }
+
+ &[aria-selected="true"]{
+ border-block-start-width:2px;
+ border-block-start-color:var(--tab-top-line-active-color);
+ border-block-end-color:var(--tab-bottom-line-active-color);
+ background-color:var(--tab-bg-active-color);
+ font-weight:590;
+ color:var(--tab-text-active-color);
+
+ &:hover{
+ border-block-start-color:var(--tab-top-line-active-hover-color);
+ background-color:var(--tab-bg-active-hover-color);
+ color:var(--tab-text-active-hover-color);
+ }
+ }
+ }
+ }
+
+ #addSignatureActionContainer{
+ width:100%;
+ height:auto;
+ display:flex;
+ flex-direction:column;
+ align-items:flex-end;
+ align-self:stretch;
+ gap:12px;
+ padding-inline:16px;
+ box-sizing:border-box;
+
+ > [role="tabpanel"]{
+ position:relative;
+ width:100%;
+ height:220px;
+ background-color:var(--signature-bg);
+ border:var(--tab-panel-border);
+ border-radius:var(--tab-panel-border-radius);
+
+ > svg{
+ position:absolute;
+ inset:0;
+ width:100%;
+ height:100%;
+ background-color:transparent;
+ }
+
+ addSignatureTypeContainer{
+ display:none;
+
+ #addSignatureTypeInput{
+ position:absolute;
+ inset:0;
+ width:100%;
+ height:100%;
+ border:0;
+ padding:0;
+ text-align:center;
+ color:var(--signature-color);
+ background-color:transparent;
+ border-radius:var(--tab-panel-border-radius);
+
+ font-family:"Brush script", "Apple Chancery", "Segoe script", "Freestyle Script", "Palace Script MT", "Brush Script MT", TK, cursive, serif;
+ font-size:44px;
+ font-style:italic;
+ font-weight:400;
+
+ &::-moz-placeholder{
+ color:var(--signature-placeholder-color);
+ text-align:center;
+
+ font:menu;
+ font-style:normal;
+ font-weight:274;
+ font-size:44px;
+ line-height:normal;
+ }
+
+ &::placeholder{
+ color:var(--signature-placeholder-color);
+ text-align:center;
+
+ font:menu;
+ font-style:normal;
+ font-weight:274;
+ font-size:44px;
+ line-height:normal;
+ }
+ }
+ }
+
+ addSignatureDrawContainer{
+ display:none;
+
+ > span{
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ display:grid;
+ align-items:center;
+ justify-content:center;
+
+ background-color:transparent;
+ color:var(--signature-placeholder-color);
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ }
+
+ > svg{
+ stroke:var(--signature-color);
+ fill:none;
+ stroke-opacity:1;
+ stroke-linecap:round;
+ stroke-linejoin:round;
+ stroke-miterlimit:10;
+
+ &:hover{
+ cursor:var(--draw-cursor);
+ }
+ }
+
+ #thickness{
+ position:absolute;
+ width:100%;
+ inset-block-end:0;
+ display:grid;
+ align-items:center;
+ justify-content:center;
+ pointer-events:none;
+
+ > span{
+ color:var(--signature-draw-placeholder-color);
+ }
+
+ > div{
+ width:auto;
+ height:auto;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ gap:8px;
+ padding:6px 8px 7px;
+ margin:0;
+ background-color:var(--thickness-bg);
+ border-radius:4px 4px 0 0;
+ border-inline:var(--thickness-border);
+ border-top:var(--thickness-border);
+ pointer-events:auto;
+ position:relative;
+ top:1px;
+
+ > label{
+ color:var(--thickness-label-color);
+ }
+
+ > input{
+ width:100px;
+ height:14px;
+ background-color:transparent;
+
+ &::-webkit-slider-runnable-track,
+ &::-moz-range-track,
+ &::-moz-range-progress{
+ background-color:var(--thickness-slider-color);
+ }
+
+ &::-webkit-slider-thumb,
+ &::-moz-range-thumb{
+ background-color:var(--thickness-bg);
+ }
+
+ border-radius:4.5px;
+ border:0;
+ color:var(--signature-color);
+ }
+ }
+ }
+ }
+
+ addSignatureImageContainer{
+ display:none;
+
+ > svg{
+ stroke:none;
+ stroke-width:0;
+ fill:var(--signature-color);
+ fill-opacity:1;
+ }
+
+ #addSignatureImagePlaceholder{
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ background-color:transparent;
+ display:flex;
+ flex-direction:column;
+ align-items:center;
+ justify-content:center;
+
+ span{
+ color:var(--signature-placeholder-color);
+ }
+
+ a{
+ color:var(--open-link-fg);
+ text-decoration:underline;
+ cursor:pointer;
+
+ &:hover{
+ color:var(--open-link-hover-fg);
+ }
+ }
+ }
+
+ #addSignatureFilePicker{
+ visibility:hidden;
+ position:relative;
+ width:0;
+ height:0;
+ }
+ }
+ }
+
+ &[data-selected="type"] > #addSignatureTypeContainer,
+ &[data-selected="draw"] > #addSignatureDrawContainer,
+ &[data-selected="image"] > #addSignatureImageContainer{
+ display:block;
+ }
+
+ #addSignatureControls{
+ display:flex;
+ flex-direction:column;
+ justify-content:center;
+ align-items:flex-start;
+ gap:12px;
+ align-self:stretch;
+
+ #horizontalContainer{
+ display:flex;
+ align-items:flex-end;
+ gap:16px;
+ align-self:stretch;
+
+ #addSignatureDescriptionContainer{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:4px;
+ flex:1 0 0;
+
+ &:has(input:disabled) > label{
+ opacity:0.4;
+ }
+
+ > label{
+ width:auto;
+ }
+ }
+
+ #clearSignatureButton{
+ display:flex;
+ align-items:center;
+
+ > span{
+ display:flex;
+ height:24px;
+ align-items:center;
+ gap:4px;
+ flex-shrink:0;
+
+ &::after{
+ content:"";
+ display:inline-block;
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--clear-signature-button-icon);
+ mask-image:var(--clear-signature-button-icon);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:currentColor;
+ flex-shrink:0;
+ }
+ }
+ }
+ }
+
+ #addSignatureSaveContainer{
+ display:grid;
+ grid-template-columns:max-content auto;
+ gap:4px;
+ width:100%;
+
+ > input{
+ margin:0;
+
+ &:disabled + label{
+ opacity:0.4;
+ }
+ }
+
+ > label{
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ }
+
+ &:not(.fullStorage) #addSignatureSaveWarning{
+ display:none;
+ }
+
+ &.fullStorage #addSignatureSaveWarning{
+ display:block;
+ opacity:1;
+ color:var(--save-warning-color);
+ font-size:11px;
+ }
+ }
+ }
+ }
+ }
+}
+
+#editSignatureDescriptionDialog{
+ .mainContainer{
+ padding-inline:16px;
+ box-sizing:border-box;
+
+ .title{
+ margin-inline-start:0;
+ }
+
+ #editSignatureDescriptionAndView{
+ width:auto;
+ display:flex;
+ justify-content:flex-end;
+ align-items:flex-start;
+ gap:12px;
+ align-self:stretch;
+
+ #editSignatureDescriptionContainer{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:4px;
+ flex:1 1 auto;
+ }
+
+ > svg{
+ width:210px;
+ height:180px;
+ padding:8px;
+ background-color:var(--signature-bg);
+
+ > path{
+ stroke:var(--button-signature-color);
+ stroke-width:1px;
+ stroke-linecap:round;
+ stroke-linejoin:round;
+ stroke-miterlimit:10;
+ vector-effect:non-scaling-stroke;
+ fill:none;
+
+ &.contours{
+ fill:var(--button-signature-color);
+ stroke-width:0.5px;
+ }
+ }
+ }
+ }
+ }
+}
+
+#editorSignatureParamsToolbar{
+ padding:8px;
+
+ #addSignatureDoorHanger{
+ gap:8px;
+ padding:2px;
+
+ .toolbarAddSignatureButtonContainer{
+ height:32px;
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ align-self:stretch;
+ gap:8px;
+
+ button{
+ border:var(--button-signature-border);
+ border-radius:4px;
+ background-color:var(--button-signature-bg);
+ color:var(--button-signature-color);
+
+ &:hover{
+ background-color:var(--button-signature-hover-bg);
+ }
+
+ &:active{
+ border:var(--button-signature-active-border);
+ background-color:var(--button-signature-active-bg);
+ color:var(--button-signature-active-color);
+
+ &::before{
+ background-color:var(--button-signature-active-color);
+ }
+ }
+
+ &:focus-visible{
+ outline:var(--focus-ring-outline);
+
+ &::before{
+ background-color:var(--button-signature-color);
+ }
+ }
+ }
+
+ .deleteButton{
+ &::before{
+ -webkit-mask-image:var(--clear-signature-button-icon);
+ mask-image:var(--clear-signature-button-icon);
+ }
+ }
+
+ .toolbarAddSignatureButton{
+ width:calc(0.8 * var(--editor-toolbar-min-width));
+ height:100%;
+ min-height:var(--menuitem-height);
+ aspect-ratio:unset;
+ display:flex;
+ align-items:center;
+ justify-content:flex-start;
+ outline:none;
+ border-radius:4px;
+ box-sizing:border-box;
+ font:message-box;
+ position:relative;
+ flex:1 1 auto;
+ padding:0;
+ gap:8px;
+ text-align:start;
+ white-space:normal;
+ cursor:default;
+ overflow:hidden;
+
+ > svg{
+ display:inline-block;
+ height:100%;
+ aspect-ratio:1;
+ background-color:var(--signature-bg);
+ flex:none;
+ padding:4px;
+ box-sizing:border-box;
+ border:none;
+ border-radius:4px;
+
+ > path{
+ stroke:var(--button-signature-color);
+ stroke-width:1px;
+ stroke-linecap:round;
+ stroke-linejoin:round;
+ stroke-miterlimit:10;
+ vector-effect:non-scaling-stroke;
+ fill:none;
+
+ &.contours{
+ fill:var(--button-signature-color);
+ stroke-width:0.5px;
+ }
+ }
+ }
+
+ &:is(:hover, :active) > svg{
+ border-radius:4px 0 0 4px;
+ background-color:var(--signature-hover-bg);
+ }
+
+ &:hover{
+ > span{
+ color:var(--button-signature-hover-color);
+ }
+ }
+
+ &:active{
+ background-color:var(--button-signature-active-bg);
+ }
+
+ &:is([disabled="disabled"], [disabled]){
+ opacity:0.5;
+ pointer-events:none;
+ }
+
+ > span{
+ height:auto;
+ text-overflow:ellipsis;
+ white-space:nowrap;
+ flex:1 1 auto;
+ font:menu;
+ font-size:13px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ overflow:hidden;
+ }
+ }
+ }
+ }
+}
+
+.editDescription.altText{
+ --alt-text-add-image:url(images/editor-toolbar-edit.svg) !important;
+
+ &::before{
+ width:16px !important;
+ height:16px !important;
+ }
+}
+
+.commentPopup,
+#commentManagerDialog{
+ width:360px;
+ max-width:100%;
+ min-width:200px;
+ position:absolute;
+ padding:8px 16px 16px;
+ margin-left:0;
+ margin-top:0;
+ box-sizing:border-box;
+
+ border-radius:8px;
+}
+
+#commentManagerDialog{
+ --comment-close-button-icon:url(images/comment-closeButton.svg);
+
+ .mainContainer{
+ width:100%;
+ height:auto;
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:4px;
+
+ #commentManagerToolbar{
+ width:100%;
+ height:32px;
+ display:flex;
+ justify-content:flex-start;
+ align-items:flex-start;
+ gap:8px;
+ align-self:stretch;
+
+ cursor:move;
+ }
+
+ #commentManagerTextInput{
+ width:100%;
+ min-height:132px;
+ margin-bottom:12px;
+ }
+ }
+}
+
+.annotationLayer.disabled :is(.annotationCommentButton){
+ display:none;
+}
+
+:is(.annotationLayer, .annotationEditorLayer){
+ .annotationCommentButton{
+ color-scheme:light dark;
+ --comment-button-bg:var(
+ --background-color-canvas,
+ light-dark(white, #1c1b22)
+ );
+ --comment-button-fg:light-dark(#5b5b66, #fbfbfe);
+ --comment-button-active-bg:light-dark(#0041a4, #a6ecf4);
+ --comment-button-active-fg:var(
+ --button-text-color-primary,
+ light-dark(white, #15141a)
+ );
+ --comment-button-hover-bg:var(
+ --color-accent-primary-hover,
+ light-dark(#0053cb, #61dce9)
+ );
+ --comment-button-hover-fg:var(
+ --button-text-color-primary,
+ light-dark(white, #15141a)
+ );
+ --comment-button-selected-bg:var(
+ --color-accent-primary,
+ light-dark(#0062fa, #00cadb)
+ );
+ --comment-button-border-color:var(
+ --border-color-interactive,
+ light-dark(#8f8f9d, #bfbfc9)
+ );
+ --comment-button-active-border-color:var(--comment-button-active-bg);
+ --comment-button-focus-border-color:light-dark(#cfcfd8, #3a3944);
+ --comment-button-hover-border-color:var(--comment-button-hover-bg);
+ --comment-button-selected-border-color:var(--comment-button-selected-bg);
+ --comment-button-selected-fg:var(
+ --button-text-color-primary,
+ light-dark(white, #15141a)
+ );
+ --comment-button-dim:24px;
+ --comment-button-box-shadow:0 0.25px 0.75px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 2px 6px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --comment-button-focus-outline-color:var(
+ --focus-outline-color,
+ light-dark(#0062fa, #00cadb)
+ );
+ @media screen and (forced-colors: active){
+ --comment-button-bg:var(--button-background-color, ButtonFace);
+ --comment-button-fg:var(--button-text-color, ButtonText);
+ --comment-button-hover-bg:var(
+ --button-background-color-hover,
+ SelectedItemText
+ );
+ --comment-button-hover-fg:var(--button-text-color-hover, SelectedItem);
+ --comment-button-active-bg:var(
+ --button-background-color-active,
+ SelectedItemText
+ );
+ --comment-button-active-fg:var(--button-text-color-active, SelectedItem);
+ --comment-button-border-color:var(--button-border-color, ButtonBorder);
+ --comment-button-active-border-color:var(
+ --button-border-color-active,
+ ButtonBorder
+ );
+ --comment-button-hover-border-color:var(
+ --button-border-color-hover,
+ SelectedItem
+ );
+ --comment-button-box-shadow:none;
+ --comment-button-focus-outline-color:var(
+ --focus-outline-color,
+ CanvasText
+ );
+ --comment-button-selected-bg:var(
+ --button-background-color-primary,
+ ButtonBorder
+ );
+ --comment-button-selected-fg:var(
+ --button-text-color-primary,
+ ButtonFace
+ );
+ }
+
+ position:absolute;
+ width:var(--comment-button-dim);
+ height:var(--comment-button-dim);
+ background-color:var(--comment-button-bg);
+ border-radius:6px 6px 6px 0;
+ border:1px solid var(--comment-button-border-color);
+ box-shadow:var(--comment-button-box-shadow);
+ cursor:auto;
+ z-index:1;
+ padding:4px;
+ margin:0;
+ box-sizing:border-box;
+ pointer-events:auto;
+
+ &:dir(rtl){
+ border-radius:6px 6px 0;
+ }
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:100%;
+ height:100%;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ -webkit-mask-image:var(--comment-edit-button-icon);
+ mask-image:var(--comment-edit-button-icon);
+ background-color:var(--comment-button-fg);
+ margin:0;
+ padding:0;
+ transform:scaleX(var(--dir-factor));
+ }
+
+ &:focus-visible{
+ outline:2px solid var(--comment-button-focus-outline-color);
+ outline-offset:1px;
+ border-color:var(--comment-button-focus-border-color);
+ }
+
+ &:hover{
+ background-color:var(--comment-button-hover-bg) !important;
+ border-color:var(--comment-button-hover-border-color);
+
+ &::before{
+ background-color:var(--comment-button-hover-fg);
+ }
+ }
+
+ &:active{
+ background-color:var(--comment-button-active-bg) !important;
+ border-color:var(--comment-button-active-border-color);
+
+ &::before{
+ background-color:var(--comment-button-active-fg);
+ }
+ }
+
+ &.selected{
+ background-color:var(--comment-button-selected-bg) !important;
+ border-color:var(--comment-button-selected-border-color);
+
+ &::before{
+ background-color:var(--comment-button-selected-fg);
+ }
+ }
+ }
+}
+
+#editorCommentsSidebar,
+.commentPopup{
+ --comment-close-button-icon:url(images/comment-closeButton.svg);
+ --comment-popup-edit-button-icon:url(images/comment-popup-editButton.svg);
+ --comment-popup-delete-button-icon:url(images/editor-toolbar-delete.svg);
+
+ --comment-date-fg-color:light-dark(
+ rgb(21 20 26 / 0.69),
+ rgb(251 251 254 / 0.69)
+ );
+ --comment-bg-color:light-dark(#f9f9fb, #1c1b22);
+ --comment-hover-bg-color:light-dark(#e0e0e6, #2c2b33);
+ --comment-active-bg-color:light-dark(#d1d1d9, #3a3944);
+ --comment-hover-brightness:0.89;
+ --comment-hover-filter:brightness(var(--comment-hover-brightness));
+ --comment-active-brightness:0.825;
+ --comment-active-filter:brightness(var(--comment-active-brightness));
+ --comment-border-color:light-dark(#f0f0f4, #52525e);
+ --comment-focus-outline-color:var(
+ --focus-outline-color,
+ light-dark(#0062fa, #00cadb)
+ );
+ --comment-fg-color:var(--text-color, light-dark(#15141a, #fbfbfe));
+ --comment-count-bg-color:light-dark(#e2f7ff, #00317e);
+ --comment-indicator-active-fg-color:light-dark(#0041a4, #a6ecf4);
+ --comment-indicator-active-filter:brightness(
+ calc(1 / var(--comment-active-brightness))
+ );
+ --comment-indicator-focus-fg-color:light-dark(#5b5b66, #fbfbfe);
+ --comment-indicator-hover-fg-color:var(
+ --color-accent-primary-hover,
+ light-dark(#0053cb, #61dce9)
+ );
+ --comment-indicator-hover-filter:brightness(
+ calc(1 / var(--comment-hover-brightness))
+ );
+ --comment-indicator-selected-fg-color:var(
+ --color-accent-primary,
+ light-dark(#0062fa, #00cadb)
+ );
+
+ --button-comment-bg:transparent;
+ --button-comment-color:var(--main-color);
+ --button-comment-active-bg:light-dark(#cfcfd8, #5b5b66);
+ --button-comment-active-border:none;
+ --button-comment-active-color:var(--button-comment-color);
+ --button-comment-border:none;
+ --button-comment-hover-bg:light-dark(#e0e0e6, #52525e);
+ --button-comment-hover-color:var(--button-comment-color);
+
+ @media screen and (forced-colors: active){
+ --comment-date-fg-color:CanvasText;
+ --comment-bg-color:Canvas;
+ --comment-hover-bg-color:Canvas;
+ --comment-hover-filter:none;
+ --comment-active-bg-color:Canvas;
+ --comment-active-filter:none;
+ --comment-border-color:CanvasText;
+ --comment-fg-color:var(--text-color, CanvasText);
+ --comment-count-bg-color:Canvas;
+ --comment-indicator-active-fg-color:SelectedItem;
+ --comment-indicator-focus-fg-color:var(--text-color, CanvasText);
+ --comment-indicator-hover-fg-color:var(--text-color, CanvasText);
+ --comment-indicator-selected-fg-color:SelectedItem;
+ --button-comment-bg:ButtonFace;
+ --button-comment-color:ButtonText;
+ --button-comment-active-bg:Highlight;
+ --button-comment-active-color:HighlightText;
+ --button-comment-border:1px solid ButtonText;
+ --button-comment-hover-bg:Highlight;
+ --button-comment-hover-color:HighlightText;
+ }
+}
+
+#editorCommentsSidebar{
+ display:flex;
+ height:auto;
+ padding-bottom:16px;
+ flex-direction:column;
+ align-items:flex-start;
+ overflow-y:visible;
+
+ #editorCommentsSidebarHeader{
+ width:100%;
+ box-sizing:border-box;
+ padding:16px;
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+
+ .commentCount{
+ display:flex;
+ align-items:baseline;
+ gap:6px;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ #editorCommentsSidebarTitle{
+ font:menu;
+ font-style:normal;
+ font-weight:590;
+ line-height:normal;
+ font-size:17px;
+ color:var(--comment-fg-color);
+ }
+
+ #editorCommentsSidebarCount{
+ padding:0 4px;
+ border-radius:4px;
+ background-color:var(--comment-count-bg-color);
+
+ color:var(--comment-fg-color);
+ text-align:center;
+
+ font:menu;
+ font-size:13px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ }
+ }
+
+ #editorCommentsSidebarCloseButton{
+ width:32px;
+ height:32px;
+ padding:8px;
+ border-radius:4px;
+ border:var(--button-comment-border);
+ background-color:var(--button-comment-bg);
+ cursor:pointer;
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:100%;
+ height:100%;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-image:var(--comment-close-button-icon);
+ mask-image:var(--comment-close-button-icon);
+ background-color:var(--button-comment-color);
+ }
+
+ &:hover{
+ background-color:var(--button-comment-hover-bg);
+
+ &::before{
+ background-color:var(--button-comment-hover-color);
+ }
+ }
+
+ &:active{
+ border:var(--button-comment-active-border);
+ background-color:var(--button-comment-active-bg);
+
+ &::before{
+ background-color:var(--button-comment-active-color);
+ }
+ }
+
+ &:focus-visible{
+ outline:var(--focus-ring-outline);
+ }
+
+ > span{
+ display:inline-block;
+ width:0;
+ height:0;
+ overflow:hidden;
+ }
+ }
+ }
+
+ #editorCommentsSidebarListContainer{
+ overflow:auto;
+ width:100%;
+
+ #editorCommentsSidebarList{
+ display:flex;
+ width:auto;
+ padding:4px 16px;
+ gap:10px;
+ align-items:flex-start;
+ flex-direction:column;
+ list-style-type:none;
+
+ .sidebarComment{
+ display:flex;
+ width:auto;
+ padding:8px 16px 16px;
+ flex-direction:column;
+ align-items:flex-start;
+ align-self:stretch;
+ gap:4px;
+
+ border-radius:8px;
+ border:0.5px solid var(--comment-border-color);
+ background-color:var(--comment-bg-color);
+
+ &:not(.noComments){
+ &:hover{
+ @media screen and (forced-colors: active){
+ background-color:var(--comment-hover-bg-color);
+ }
+ filter:var(--comment-hover-filter);
+
+ time::after{
+ display:inline-block;
+ background-color:var(--comment-indicator-hover-fg-color);
+ filter:var(--comment-indicator-hover-filter);
+ }
+ }
+
+ &:active{
+ @media screen and (forced-colors: active){
+ background-color:var(--comment-active-bg-color);
+ }
+ filter:var(--comment-active-filter);
+
+ time::after{
+ display:inline-block;
+ background-color:var(--comment-indicator-active-fg-color);
+ filter:var(--comment-indicator-active-filter);
+ }
+ }
+
+ &:is(:focus, :focus-visible) time::after{
+ display:inline-block;
+ background-color:var(--comment-indicator-focus-fg-color);
+ }
+
+ &:focus-visible{
+ outline:2px solid var(--comment-focus-outline-color);
+ outline-offset:2px;
+ }
+
+ &.selected{
+ .sidebarCommentText{
+ max-height:-moz-fit-content;
+ max-height:fit-content;
+ -webkit-line-clamp:unset;
+ }
+
+ time::after{
+ display:inline-block;
+ background-color:var(--comment-indicator-selected-fg-color);
+ }
+ }
+ }
+
+ .sidebarCommentText{
+ font:menu;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ font-size:15px;
+ width:100%;
+ height:-moz-fit-content;
+ height:fit-content;
+ max-height:80px;
+ display:-webkit-box;
+ -webkit-box-orient:vertical;
+ -webkit-line-clamp:2;
+ overflow:hidden;
+ overflow-wrap:break-word;
+
+ .richText{
+ --total-scale-factor:1.5;
+ }
+ }
+
+ &.noComments{
+ .sidebarCommentText{
+ max-height:-moz-fit-content;
+ max-height:fit-content;
+ -webkit-line-clamp:unset;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ }
+
+ a{
+ font:menu;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ font-size:15px;
+ width:100%;
+ height:auto;
+ overflow-wrap:break-word;
+ margin-block-start:15px;
+ color:var(--link-fg-color);
+
+ &:focus-visible{
+ outline:var(--focus-ring-outline);
+ }
+
+ &:hover{
+ color:var(--link-hover-fg-color);
+ }
+ }
+ }
+
+ time{
+ width:100%;
+ display:inline-flex;
+ align-items:center;
+ justify-content:space-between;
+
+ font:menu;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ font-size:13px;
+
+ &::after{
+ content:"";
+ display:none;
+ width:16px;
+ height:16px;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-image:var(--comment-edit-button-icon);
+ mask-image:var(--comment-edit-button-icon);
+ transform:scaleX(var(--dir-factor));
+ }
+ }
+ }
+ }
+ }
+}
+
+.commentPopup{
+ color-scheme:light dark;
+
+ --divider-color:light-dark(#cfcfd8, #3a3944);
+ --comment-shadow:0 0.5px 2px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 4px 16px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+
+ @media screen and (forced-colors: active){
+ --divider-color:CanvasText;
+ --comment-shadow:none;
+ }
+
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:12px;
+ z-index:100001;
+ pointer-events:auto;
+ margin-top:2px;
+
+ border:0.5px solid var(--comment-border-color);
+ background:var(--comment-bg-color);
+ box-shadow:var(--comment-shadow);
+
+ &:focus-visible{
+ outline:none;
+ }
+
+ &.dragging{
+ cursor:move !important;
+
+ *{
+ cursor:move !important;
+ }
+
+ button{
+ pointer-events:none !important;
+ }
+ }
+
+ &:not(.selected) .commentPopupButtons{
+ visibility:hidden !important;
+ }
+
+ hr{
+ width:100%;
+ height:1px;
+ border:none;
+ border-top:1px solid var(--divider-color);
+ margin:0;
+ padding:0;
+ }
+
+ .commentPopupTop{
+ display:flex;
+ width:100%;
+ height:auto;
+ padding-bottom:4px;
+ justify-content:space-between;
+ align-items:center;
+ align-self:stretch;
+ cursor:move;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ .commentPopupTime{
+ font:menu;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ font-size:13px;
+ color:var(--comment-date-fg-color);
+ }
+
+ .commentPopupButtons{
+ display:flex;
+ align-items:center;
+ gap:2px;
+ cursor:default;
+
+ > button{
+ width:32px;
+ height:32px;
+ padding:8px;
+ border:var(--button-comment-border);
+ border-radius:4px;
+ background-color:var(--button-comment-bg);
+ color:var(--button-comment-color);
+
+ &:hover{
+ background-color:var(--button-comment-hover-bg);
+
+ &::before{
+ background-color:var(--button-comment-hover-color);
+ }
+ }
+
+ &:active{
+ border:var(--button-comment-active-border);
+ background-color:var(--button-comment-active-bg);
+ color:var(--button-comment-active-color);
+
+ &::before{
+ background-color:var(--button-comment-active-color);
+ }
+ }
+
+ &:focus-visible{
+ background-color:var(--button-comment-hover-bg);
+ outline:2px solid var(--comment-focus-outline-color);
+ outline-offset:0;
+ }
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:100%;
+ height:100%;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ }
+
+ &.commentPopupEdit::before{
+ -webkit-mask-image:var(--comment-popup-edit-button-icon);
+ mask-image:var(--comment-popup-edit-button-icon);
+ }
+
+ &.commentPopupDelete::before{
+ -webkit-mask-image:var(--comment-popup-delete-button-icon);
+ mask-image:var(--comment-popup-delete-button-icon);
+ }
+ }
+ }
+ }
+
+ .commentPopupText{
+ width:100%;
+ height:auto;
+
+ font:menu;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ font-size:15px;
+ color:var(--comment-fg-color);
+ }
+}
+
+.commentPopupText,
+.sidebarCommentText .richText{
+ margin-block:0;
+
+ p:first-of-type{
+ margin-block:0;
+ }
+
+ > *{
+ white-space:pre-wrap;
+ font-size:max(15px, calc(10px * var(--total-scale-factor)));
+ overflow-wrap:break-word;
+ }
+
+ span{
+ color:var(--comment-fg-color) !important;
+ }
+}
+
+:root{
+ --editor-toolbar-vert-offset:6px;
+ --outline-width:2px;
+ --outline-color:var(--color-blue-60, #0060df);
+ --outline-around-width:1px;
+ --outline-around-color:var(--color-gray-20, #f0f0f4);
+ --hover-outline-around-color:var(--outline-around-color);
+ --editor-selection-outline:solid var(--outline-width) var(--outline-color);
+ --unfocus-outline:solid var(--outline-width) transparent;
+ --focus-outline-around:solid var(--outline-around-width) var(--outline-around-color);
+ --hover-outline-color:var(--color-gray-60, #8f8f9d);
+ --hover-outline:solid var(--outline-width) var(--hover-outline-color);
+ --hover-outline-around:solid var(--outline-around-width) var(--hover-outline-around-color);
+ --freetext-line-height:1.35;
+ --freetext-padding:2px;
+ --resizer-bg-color:var(--outline-color);
+ --resizer-size:6px;
+ --resizer-shift:calc(
+ 0px - (var(--outline-width) + var(--resizer-size)) / 2 -
+ var(--outline-around-width)
+ );
+ --editorFreeText-editing-cursor:text;
+ --editorInk-editing-cursor:url(images/cursor-editorInk.svg) 0 16, pointer;
+ --editorHighlight-editing-cursor:url(images/cursor-editorTextHighlight.svg) 24 24, text;
+ --editorFreeHighlight-editing-cursor:url(images/cursor-editorFreeHighlight.svg) 1 18, pointer;
+
+ --new-alt-text-warning-image:url(images/altText_warning.svg);
+}
+
+.textLayer{
+ &.highlighting{
+ cursor:var(--editorFreeHighlight-editing-cursor);
+
+ &:not(.free) span{
+ cursor:var(--editorHighlight-editing-cursor);
+
+ &[role="img"]{
+ cursor:var(--editorFreeHighlight-editing-cursor);
+ }
+ }
+
+ &.free span{
+ cursor:var(--editorFreeHighlight-editing-cursor);
+ }
+ }
+}
+
+.page:has(.annotationEditorLayer.nonEditing)
+ .annotationLayer
+ .editorAnnotation{
+ position:absolute;
+ pointer-events:none;
+}
+
+#viewerContainer.pdfPresentationMode:fullscreen,
+.annotationEditorLayer.disabled{
+ .noAltTextBadge{
+ display:none !important;
+ }
+}
+
+@media (min-resolution: 1.1dppx){
+ :root{
+ --editorFreeText-editing-cursor:url(images/cursor-editorFreeText.svg) 0 16, text;
+ }
+}
+
+@media screen and (forced-colors: active){
+ :root{
+ --outline-color:CanvasText;
+ --outline-around-color:ButtonFace;
+ --resizer-bg-color:ButtonText;
+ --hover-outline-color:var(--color-accent-primary-hover, Highlight);
+ --hover-outline-around-color:SelectedItemText;
+ }
+}
+
+[data-editor-rotation="90"]{
+ transform:rotate(90deg);
+}
+
+[data-editor-rotation="180"]{
+ transform:rotate(180deg);
+}
+
+[data-editor-rotation="270"]{
+ transform:rotate(270deg);
+}
+
+.annotationEditorLayer{
+ background:transparent;
+ position:absolute;
+ inset:0;
+ font-size:calc(100px * var(--total-scale-factor));
+ transform-origin:0 0;
+ cursor:auto;
+
+ .selectedEditor{
+ z-index:100000 !important;
+ }
+
+ &.drawing *{
+ pointer-events:none !important;
+ }
+
+ &.getElements{
+ pointer-events:auto !important;
+ > div{
+ pointer-events:auto !important;
+ }
+ }
+}
+
+.annotationEditorLayer.waiting{
+ content:"";
+ cursor:wait;
+ position:absolute;
+ inset:0;
+ width:100%;
+ height:100%;
+}
+
+.annotationEditorLayer.disabled{
+ pointer-events:none;
+
+ &.highlightEditing
+ :is(
+ .freeTextEditor,
+ .inkEditor,
+ .stampEditor,
+ .signatureEditor,
+ .commentPopup
+ ){
+ pointer-events:auto;
+ }
+}
+
+.annotationEditorLayer.freetextEditing{
+ cursor:var(--editorFreeText-editing-cursor);
+}
+
+.annotationEditorLayer.inkEditing{
+ cursor:var(--editorInk-editing-cursor);
+}
+
+.annotationEditorLayer .draw{
+ box-sizing:border-box;
+}
+
+.annotationEditorLayer
+ :is(.freeTextEditor, .inkEditor, .stampEditor, .signatureEditor){
+ position:absolute;
+ background:transparent;
+ z-index:1;
+ transform-origin:0 0;
+ cursor:auto;
+ max-width:100%;
+ max-height:100%;
+ border:var(--unfocus-outline);
+
+ &.draggable.selectedEditor{
+ cursor:move;
+ }
+
+ &.selectedEditor{
+ border:var(--editor-selection-outline);
+ outline:var(--focus-outline-around);
+
+ &::before{
+ content:"";
+ position:absolute;
+ inset:0;
+ border:var(--focus-outline-around);
+ pointer-events:none;
+ }
+ }
+
+ &:hover:not(.selectedEditor){
+ border:var(--hover-outline);
+ outline:var(--hover-outline-around);
+
+ &::before{
+ content:"";
+ position:absolute;
+ inset:0;
+ border:var(--focus-outline-around);
+ }
+ }
+}
+
+.annotationEditorLayer
+ :is(
+ .freeTextEditor,
+ .inkEditor,
+ .stampEditor,
+ .highlightEditor,
+ .signatureEditor
+ ),
+.textLayer{
+ .editToolbar{
+ --editor-toolbar-delete-image:url(images/editor-toolbar-delete.svg);
+ --editor-toolbar-bg-color:light-dark(#f0f0f4, #2b2a33);
+ --editor-toolbar-highlight-image:url(images/toolbarButton-editorHighlight.svg);
+ --editor-toolbar-fg-color:light-dark(#2e2e56, #fbfbfe);
+ --editor-toolbar-border-color:var(--border-color-interactive, #8f8f9d);
+ --editor-toolbar-hover-border-color:var(--editor-toolbar-border-color);
+ --editor-toolbar-hover-bg-color:light-dark(#e0e0e6, #52525e);
+ --editor-toolbar-hover-fg-color:var(--editor-toolbar-fg-color);
+ --editor-toolbar-hover-outline:none;
+ --editor-toolbar-focus-outline-color:var(
+ --focus-outline-color,
+ light-dark(#0060df, #0df)
+ );
+ --editor-toolbar-shadow:0 2px 6px 0 rgb(58 57 68 / 0.2);
+ --editor-toolbar-height:28px;
+ --editor-toolbar-padding:2px;
+ --alt-text-done-color:var(
+ --color-accent-attention,
+ light-dark(#2ac3a2, #54ffbd)
+ );
+ --alt-text-warning-color:light-dark(#0090ed, #80ebff);
+ --alt-text-hover-done-color:var(--alt-text-done-color);
+ --alt-text-hover-warning-color:var(--alt-text-warning-color);
+
+ @media screen and (forced-colors: active){
+ --editor-toolbar-bg-color:var(--button-background-color, ButtonFace);
+ --editor-toolbar-fg-color:var(--button-text-color, ButtonText);
+ --editor-toolbar-border-color:var(--button-border-color, ButtonText);
+ --editor-toolbar-hover-border-color:var(
+ --button-border-color-hover,
+ AccentColor
+ );
+ --editor-toolbar-hover-bg-color:var(
+ --button-background-color-hover,
+ ButtonFace
+ );
+ --editor-toolbar-hover-fg-color:var(
+ --button-text-color-hover,
+ AccentColor
+ );
+ --editor-toolbar-hover-outline:2px solid var(--editor-toolbar-hover-border-color);
+ --editor-toolbar-focus-outline-color:var(
+ --button-border-color,
+ ButtonBorder
+ );
+ --editor-toolbar-shadow:none;
+ --alt-text-done-color:var(--editor-toolbar-fg-color);
+ --alt-text-warning-color:var(--editor-toolbar-fg-color);
+ --alt-text-hover-done-color:var(--editor-toolbar-hover-fg-color);
+ --alt-text-hover-warning-color:var(--editor-toolbar-hover-fg-color);
+ }
+
+ display:flex;
+ width:-moz-fit-content;
+ width:fit-content;
+ height:var(--editor-toolbar-height);
+ flex-direction:column;
+ justify-content:center;
+ align-items:center;
+ cursor:default;
+ pointer-events:auto;
+ box-sizing:content-box;
+ padding:var(--editor-toolbar-padding);
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ position:absolute;
+ inset-inline-end:0;
+ inset-block-start:calc(100% + var(--editor-toolbar-vert-offset));
+
+ border-radius:6px;
+ background-color:var(--editor-toolbar-bg-color);
+ border:1px solid var(--editor-toolbar-border-color);
+ box-shadow:var(--editor-toolbar-shadow);
+
+ &.hidden{
+ display:none;
+ }
+
+ &:has(:focus-visible){
+ border-color:transparent;
+ }
+
+ &:dir(ltr){
+ transform-origin:100% 0;
+ }
+
+ &:dir(rtl){
+ transform-origin:0 0;
+ }
+
+ .buttons{
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ gap:0;
+ height:100%;
+
+ button{
+ padding:0;
+ }
+
+ .divider{
+ width:0;
+ height:calc(
+ 2 * var(--editor-toolbar-padding) + var(--editor-toolbar-height)
+ );
+ border-left:1px solid var(--editor-toolbar-border-color);
+ border-right:none;
+ display:inline-block;
+ margin-inline:2px;
+ }
+
+ .basic{
+ width:var(--editor-toolbar-height);
+
+ &::before{
+ content:"";
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ display:inline-block;
+ background-color:var(--editor-toolbar-fg-color);
+ width:100%;
+ height:100%;
+ }
+
+ &:hover::before{
+ background-color:var(--editor-toolbar-hover-fg-color);
+ }
+
+ &.highlightButton::before{
+ -webkit-mask-image:var(--editor-toolbar-highlight-image);
+ mask-image:var(--editor-toolbar-highlight-image);
+ }
+
+ &.commentButton::before{
+ -webkit-mask-image:var(--comment-edit-button-icon);
+ mask-image:var(--comment-edit-button-icon);
+ }
+
+ &.deleteButton::before{
+ -webkit-mask-image:var(--editor-toolbar-delete-image);
+ mask-image:var(--editor-toolbar-delete-image);
+ }
+ }
+
+ > *{
+ height:var(--editor-toolbar-height);
+ }
+
+ > :not(.divider){
+ border:none;
+ background-color:transparent;
+ cursor:pointer;
+
+ &:hover{
+ border-radius:2px;
+ background-color:var(--editor-toolbar-hover-bg-color);
+ color:var(--editor-toolbar-hover-fg-color);
+ outline:var(--editor-toolbar-hover-outline);
+ outline-offset:1px;
+
+ &:active{
+ outline:none;
+ }
+ }
+
+ &:focus-visible{
+ border-radius:2px;
+ outline:2px solid var(--editor-toolbar-focus-outline-color);
+ }
+ }
+
+ .altText{
+ --alt-text-add-image:url(images/altText_add.svg);
+ --alt-text-done-image:url(images/altText_done.svg);
+
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ width:-moz-max-content;
+ width:max-content;
+ padding-inline:8px;
+ pointer-events:all;
+ font:menu;
+ font-weight:590;
+ font-size:12px;
+ color:var(--editor-toolbar-fg-color);
+
+ &:disabled{
+ pointer-events:none;
+ }
+
+ &::before{
+ content:"";
+ -webkit-mask-image:var(--alt-text-add-image);
+ mask-image:var(--alt-text-add-image);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ display:inline-block;
+ width:12px;
+ height:13px;
+ background-color:var(--editor-toolbar-fg-color);
+ margin-inline-end:4px;
+ }
+
+ &:hover::before{
+ background-color:var(--editor-toolbar-hover-fg-color);
+ }
+
+ &.done::before{
+ -webkit-mask-image:var(--alt-text-done-image);
+ mask-image:var(--alt-text-done-image);
+ }
+
+ &.new{
+ &::before{
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--new-alt-text-warning-image);
+ mask-image:var(--new-alt-text-warning-image);
+ background-color:var(--alt-text-warning-color);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ }
+
+ &:hover::before{
+ background-color:var(--alt-text-hover-warning-color);
+ }
+
+ &.done{
+ &::before{
+ -webkit-mask-image:var(--alt-text-done-image);
+ mask-image:var(--alt-text-done-image);
+ background-color:var(--alt-text-done-color);
+ }
+
+ &:hover::before{
+ background-color:var(--alt-text-hover-done-color);
+ }
+ }
+ }
+
+ .tooltip{
+ display:none;
+ word-wrap:anywhere;
+
+ &.show{
+ --alt-text-tooltip-bg:light-dark(#f0f0f4, #1c1b22);
+ --alt-text-tooltip-fg:var(
+ --text-color,
+ light-dark(#15141a, #fbfbfe)
+ );
+ --alt-text-tooltip-border:var(--border-color-interactive, #8f8f9d);
+ --alt-text-tooltip-shadow:0 2px 6px 0 light-dark(rgb(58 57 68 / 0.2), #15141a);
+
+ @media screen and (forced-colors: active){
+ --alt-text-tooltip-bg:Canvas;
+ --alt-text-tooltip-fg:var(--text-color, CanvasText);
+ --alt-text-tooltip-border:var(--border-color, CanvasText);
+ --alt-text-tooltip-shadow:none;
+ }
+
+ display:inline-flex;
+ flex-direction:column;
+ align-items:center;
+ justify-content:center;
+ position:absolute;
+ top:calc(100% + 2px);
+ inset-inline-start:0;
+ padding-block:2px 3px;
+ padding-inline:3px;
+ max-width:300px;
+ width:-moz-max-content;
+ width:max-content;
+ height:auto;
+ font-size:12px;
+
+ border:0.5px solid var(--alt-text-tooltip-border);
+ background:var(--alt-text-tooltip-bg);
+ box-shadow:var(--alt-text-tooltip-shadow);
+ color:var(--alt-text-tooltip-fg);
+
+ pointer-events:none;
+ }
+ }
+ }
+
+ .comment{
+ width:var(--editor-toolbar-height);
+
+ &::before{
+ content:"";
+ -webkit-mask-image:var(--comment-edit-button-icon);
+ mask-image:var(--comment-edit-button-icon);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ display:inline-block;
+ background-color:var(--editor-toolbar-fg-color);
+ width:100%;
+ height:100%;
+ }
+ }
+ }
+ }
+}
+
+.annotationEditorLayer .freeTextEditor{
+ padding:calc(var(--freetext-padding) * var(--total-scale-factor));
+ width:auto;
+ height:auto;
+ touch-action:none;
+}
+
+.annotationEditorLayer .freeTextEditor .internal{
+ background:transparent;
+ border:none;
+ inset:0;
+ overflow:visible;
+ white-space:nowrap;
+ font:10px sans-serif;
+ line-height:var(--freetext-line-height);
+ text-align:start;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+}
+
+.annotationEditorLayer .freeTextEditor .overlay{
+ position:absolute;
+ display:none;
+ background:transparent;
+ inset:0;
+ width:100%;
+ height:100%;
+}
+
+.annotationEditorLayer freeTextEditor .overlay.enabled{
+ display:block;
+}
+
+.annotationEditorLayer .freeTextEditor .internal:empty::before{
+ content:attr(default-content);
+ color:gray;
+}
+
+.annotationEditorLayer .freeTextEditor .internal:focus{
+ outline:none;
+ -webkit-user-select:auto;
+ -moz-user-select:auto;
+ user-select:auto;
+}
+
+.annotationEditorLayer .inkEditor{
+ width:100%;
+ height:100%;
+}
+
+.annotationEditorLayer .inkEditor.editing{
+ cursor:inherit;
+}
+
+.annotationEditorLayer .inkEditor .inkEditorCanvas{
+ position:absolute;
+ inset:0;
+ width:100%;
+ height:100%;
+ touch-action:none;
+}
+
+.annotationEditorLayer .stampEditor{
+ width:auto;
+ height:auto;
+
+ canvas{
+ position:absolute;
+ width:100%;
+ height:100%;
+ margin:0;
+ top:0;
+ left:0;
+ }
+
+ .noAltTextBadge{
+ --no-alt-text-badge-border-color:light-dark(#f0f0f4, #52525e);
+ --no-alt-text-badge-bg-color:light-dark(#cfcfd8, #fbfbfe);
+ --no-alt-text-badge-fg-color:light-dark(#5b5b66, #15141a);
+
+ @media screen and (forced-colors: active){
+ --no-alt-text-badge-border-color:ButtonText;
+ --no-alt-text-badge-bg-color:ButtonFace;
+ --no-alt-text-badge-fg-color:ButtonText;
+ }
+
+ position:absolute;
+ inset-inline-end:5px;
+ inset-block-end:5px;
+ display:inline-flex;
+ width:32px;
+ height:32px;
+ padding:3px;
+ justify-content:center;
+ align-items:center;
+ pointer-events:none;
+ z-index:1;
+
+ border-radius:2px;
+ border:1px solid var(--no-alt-text-badge-border-color);
+ background:var(--no-alt-text-badge-bg-color);
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--new-alt-text-warning-image);
+ mask-image:var(--new-alt-text-warning-image);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:var(--no-alt-text-badge-fg-color);
+ }
+ }
+}
+
+.annotationEditorLayer{
+ :is(.freeTextEditor, .inkEditor, .stampEditor, .signatureEditor){
+ & > .resizers{
+ position:absolute;
+ inset:0;
+ z-index:1;
+
+ &.hidden{
+ display:none;
+ }
+
+ & > .resizer{
+ width:var(--resizer-size);
+ height:var(--resizer-size);
+ background:content-box var(--resizer-bg-color);
+ border:var(--focus-outline-around);
+ border-radius:2px;
+ position:absolute;
+
+ &.topLeft{
+ top:var(--resizer-shift);
+ left:var(--resizer-shift);
+ }
+
+ &.topMiddle{
+ top:var(--resizer-shift);
+ left:calc(50% + var(--resizer-shift));
+ }
+
+ &.topRight{
+ top:var(--resizer-shift);
+ right:var(--resizer-shift);
+ }
+
+ &.middleRight{
+ top:calc(50% + var(--resizer-shift));
+ right:var(--resizer-shift);
+ }
+
+ &.bottomRight{
+ bottom:var(--resizer-shift);
+ right:var(--resizer-shift);
+ }
+
+ &.bottomMiddle{
+ bottom:var(--resizer-shift);
+ left:calc(50% + var(--resizer-shift));
+ }
+
+ &.bottomLeft{
+ bottom:var(--resizer-shift);
+ left:var(--resizer-shift);
+ }
+
+ &.middleLeft{
+ top:calc(50% + var(--resizer-shift));
+ left:var(--resizer-shift);
+ }
+ }
+ }
+ }
+
+ &[data-main-rotation="0"]
+ :is([data-editor-rotation="0"], [data-editor-rotation="180"]),
+ &[data-main-rotation="90"]
+ :is([data-editor-rotation="270"], [data-editor-rotation="90"]),
+ &[data-main-rotation="180"]
+ :is([data-editor-rotation="180"], [data-editor-rotation="0"]),
+ &[data-main-rotation="270"]
+ :is([data-editor-rotation="90"], [data-editor-rotation="270"]){
+ & > .resizers > .resizer{
+ &.topLeft,
+ &.bottomRight{
+ cursor:nwse-resize;
+ }
+
+ &.topMiddle,
+ &.bottomMiddle{
+ cursor:ns-resize;
+ }
+
+ &.topRight,
+ &.bottomLeft{
+ cursor:nesw-resize;
+ }
+
+ &.middleRight,
+ &.middleLeft{
+ cursor:ew-resize;
+ }
+ }
+ }
+
+ &[data-main-rotation="0"]
+ :is([data-editor-rotation="90"], [data-editor-rotation="270"]),
+ &[data-main-rotation="90"]
+ :is([data-editor-rotation="0"], [data-editor-rotation="180"]),
+ &[data-main-rotation="180"]
+ :is([data-editor-rotation="270"], [data-editor-rotation="90"]),
+ &[data-main-rotation="270"]
+ :is([data-editor-rotation="180"], [data-editor-rotation="0"]){
+ & > .resizers > .resizer{
+ &.topLeft,
+ &.bottomRight{
+ cursor:nesw-resize;
+ }
+
+ &.topMiddle,
+ &.bottomMiddle{
+ cursor:ew-resize;
+ }
+
+ &.topRight,
+ &.bottomLeft{
+ cursor:nwse-resize;
+ }
+
+ &.middleRight,
+ &.middleLeft{
+ cursor:ns-resize;
+ }
+ }
+ }
+
+ &
+ :is(
+ [data-main-rotation="0"] [data-editor-rotation="90"],
+ [data-main-rotation="90"] [data-editor-rotation="0"],
+ [data-main-rotation="180"] [data-editor-rotation="270"],
+ [data-main-rotation="270"] [data-editor-rotation="180"]
+ ){
+ .editToolbar{
+ rotate:270deg;
+
+ &:dir(ltr){
+ inset-inline-end:calc(0px - var(--editor-toolbar-vert-offset));
+ inset-block-start:0;
+ }
+
+ &:dir(rtl){
+ inset-inline-end:calc(100% + var(--editor-toolbar-vert-offset));
+ inset-block-start:0;
+ }
+ }
+ }
+
+ &
+ :is(
+ [data-main-rotation="0"] [data-editor-rotation="180"],
+ [data-main-rotation="90"] [data-editor-rotation="90"],
+ [data-main-rotation="180"] [data-editor-rotation="0"],
+ [data-main-rotation="270"] [data-editor-rotation="270"]
+ ){
+ .editToolbar{
+ rotate:180deg;
+ inset-inline-end:100%;
+ inset-block-start:calc(0px - var(--editor-toolbar-vert-offset));
+ }
+ }
+
+ &
+ :is(
+ [data-main-rotation="0"] [data-editor-rotation="270"],
+ [data-main-rotation="90"] [data-editor-rotation="180"],
+ [data-main-rotation="180"] [data-editor-rotation="90"],
+ [data-main-rotation="270"] [data-editor-rotation="0"]
+ ){
+ .editToolbar{
+ rotate:90deg;
+
+ &:dir(ltr){
+ inset-inline-end:calc(100% + var(--editor-toolbar-vert-offset));
+ inset-block-start:100%;
+ }
+
+ &:dir(rtl){
+ inset-inline-start:calc(0px - var(--editor-toolbar-vert-offset));
+ inset-block-start:0;
+ }
+ }
+ }
+}
+
+.dialog.altText{
+ &::backdrop{
+ -webkit-mask:url(#alttext-manager-mask);
+ mask:url(#alttext-manager-mask);
+ }
+ &.positioned{
+ margin:0;
+ }
+
+ & #altTextContainer{
+ width:300px;
+ height:-moz-fit-content;
+ height:fit-content;
+ display:inline-flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:16px;
+
+ & #overallDescription{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:4px;
+ align-self:stretch;
+
+ & span{
+ align-self:stretch;
+ }
+
+ & .title{
+ font-size:13px;
+ font-style:normal;
+ font-weight:590;
+ }
+ }
+
+ & #addDescription{
+ display:flex;
+ flex-direction:column;
+ align-items:stretch;
+ gap:8px;
+
+ & .descriptionArea{
+ flex:1;
+ padding-inline:24px 10px;
+
+ textarea{
+ width:100%;
+ min-height:75px;
+ }
+ }
+ }
+
+ & #buttons{
+ display:flex;
+ justify-content:flex-end;
+ align-items:flex-start;
+ gap:8px;
+ align-self:stretch;
+ }
+ }
+}
+
+.dialog.newAltText{
+ --new-alt-text-ai-disclaimer-icon:url(images/altText_disclaimer.svg);
+ --new-alt-text-spinner-icon:url(images/altText_spinner.svg);
+ --preview-image-bg-color:light-dark(#f0f0f4, #2b2a33);
+ --preview-image-border:none;
+
+ @media screen and (forced-colors: active){
+ --preview-image-bg-color:ButtonFace;
+ --preview-image-border:1px solid ButtonText;
+ }
+
+ width:80%;
+ max-width:570px;
+ min-width:300px;
+ padding:0;
+
+ &.noAi{
+ #newAltTextDisclaimer,
+ #newAltTextCreateAutomatically{
+ display:none !important;
+ }
+ }
+
+ &.aiInstalling{
+ #newAltTextCreateAutomatically{
+ display:none !important;
+ }
+ #newAltTextDownloadModel{
+ display:flex !important;
+ }
+ }
+
+ &.error{
+ #newAltTextNotNow{
+ display:none !important;
+ }
+
+ #newAltTextCancel{
+ display:inline-block !important;
+ }
+ }
+
+ &:not(.error) #newAltTextError{
+ display:none !important;
+ }
+
+ #newAltTextContainer{
+ display:flex;
+ width:auto;
+ padding:16px;
+ flex-direction:column;
+ justify-content:flex-end;
+ align-items:flex-start;
+ gap:12px;
+ flex:0 1 auto;
+ line-height:normal;
+
+ #mainContent{
+ display:flex;
+ justify-content:flex-end;
+ align-items:flex-start;
+ gap:12px;
+ align-self:stretch;
+ flex:1 1 auto;
+
+ #descriptionAndSettings{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:16px;
+ flex:1 0 0;
+ align-self:stretch;
+ }
+
+ #descriptionInstruction{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:8px;
+ align-self:stretch;
+ flex:1 1 auto;
+
+ #newAltTextDescriptionContainer{
+ width:100%;
+ height:70px;
+ position:relative;
+
+ textarea{
+ width:100%;
+ height:100%;
+ padding:8px;
+
+ &::-moz-placeholder{
+ color:var(--text-secondary-color);
+ }
+
+ &::placeholder{
+ color:var(--text-secondary-color);
+ }
+ }
+
+ .altTextSpinner{
+ display:none;
+ position:absolute;
+ width:16px;
+ height:16px;
+ inset-inline-start:8px;
+ inset-block-start:8px;
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:var(--text-secondary-color);
+ pointer-events:none;
+ }
+
+ &.loading{
+ textarea::-moz-placeholder{
+ color:transparent;
+ }
+ textarea::placeholder{
+ color:transparent;
+ }
+
+ .altTextSpinner{
+ display:inline-block;
+ -webkit-mask-image:var(--new-alt-text-spinner-icon);
+ mask-image:var(--new-alt-text-spinner-icon);
+ }
+ }
+ }
+
+ #newAltTextDescription{
+ font-size:11px;
+ }
+
+ #newAltTextDisclaimer{
+ display:flex;
+ flex-direction:row;
+ align-items:flex-start;
+ gap:4px;
+ font-size:11px;
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:17px;
+ height:16px;
+ -webkit-mask-image:var(--new-alt-text-ai-disclaimer-icon);
+ mask-image:var(--new-alt-text-ai-disclaimer-icon);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:var(--text-secondary-color);
+ flex:1 0 auto;
+ }
+ }
+ }
+
+ #newAltTextDownloadModel{
+ display:flex;
+ align-items:center;
+ gap:4px;
+ align-self:stretch;
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--new-alt-text-spinner-icon);
+ mask-image:var(--new-alt-text-spinner-icon);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ background-color:var(--text-secondary-color);
+ }
+ }
+
+ #newAltTextImagePreview{
+ width:180px;
+ aspect-ratio:1;
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ flex:0 0 auto;
+ background-color:var(--preview-image-bg-color);
+ border:var(--preview-image-border);
+
+ > canvas{
+ max-width:100%;
+ max-height:100%;
+ }
+ }
+ }
+ }
+}
+
+.colorPicker{
+ --hover-outline-color:var(
+ --color-accent-primary-hover,
+ light-dark(#0250bb, #80ebff)
+ );
+ --selected-outline-color:light-dark(#0060df, #aaf2ff);
+ --swatch-border-color:light-dark(#cfcfd8, #52525e);
+
+ @media screen and (forced-colors: active){
+ --hover-outline-color:Highlight;
+ --selected-outline-color:var(--hover-outline-color);
+ --swatch-border-color:ButtonText;
+ }
+
+ .swatch{
+ width:16px;
+ height:16px;
+ border:1px solid var(--swatch-border-color);
+ border-radius:100%;
+ outline-offset:2px;
+ box-sizing:border-box;
+ forced-color-adjust:none;
+ }
+
+ button:is(:hover, .selected) > .swatch{
+ border:none;
+ }
+}
+
+.basicColorPicker{
+ width:28px;
+
+ &::-moz-color-swatch{
+ border-radius:100%;
+ margin:0;
+ }
+
+ &::-webkit-color-swatch{
+ border-radius:100%;
+ margin:0;
+ }
+}
+
+.annotationEditorLayer{
+ &[data-main-rotation="0"]{
+ .highlightEditor:not(.free) > .editToolbar{
+ rotate:0deg;
+ }
+ }
+
+ &[data-main-rotation="90"]{
+ .highlightEditor:not(.free) > .editToolbar{
+ rotate:270deg;
+ }
+ }
+
+ &[data-main-rotation="180"]{
+ .highlightEditor:not(.free) > .editToolbar{
+ rotate:180deg;
+ }
+ }
+
+ &[data-main-rotation="270"]{
+ .highlightEditor:not(.free) > .editToolbar{
+ rotate:90deg;
+ }
+ }
+
+ .highlightEditor{
+ position:absolute;
+ background:transparent;
+ z-index:1;
+ cursor:auto;
+ max-width:100%;
+ max-height:100%;
+ border:none;
+ outline:none;
+ pointer-events:none;
+ transform-origin:0 0;
+
+ &:not(.free){
+ transform:none;
+ }
+
+ .internal{
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ pointer-events:auto;
+ }
+
+ &.disabled .internal{
+ pointer-events:none;
+ }
+
+ &.selectedEditor{
+ .internal{
+ cursor:pointer;
+ }
+ }
+
+ .editToolbar{
+ --editor-toolbar-colorpicker-arrow-image:url(images/toolbarButton-menuArrow.svg);
+
+ transform-origin:center !important;
+
+ .buttons{
+ .colorPicker{
+ position:relative;
+ width:auto;
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ gap:4px;
+ padding:4px;
+
+ &::after{
+ content:"";
+ -webkit-mask-image:var(--editor-toolbar-colorpicker-arrow-image);
+ mask-image:var(--editor-toolbar-colorpicker-arrow-image);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ display:inline-block;
+ background-color:var(--editor-toolbar-fg-color);
+ width:12px;
+ height:12px;
+ }
+
+ &:hover::after{
+ background-color:var(--editor-toolbar-hover-fg-color);
+ }
+
+ &:has(.dropdown:not(.hidden)){
+ background-color:var(--editor-toolbar-hover-bg-color);
+
+ &::after{
+ scale:-1;
+ }
+ }
+
+ .dropdown{
+ position:absolute;
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ flex-direction:column;
+ gap:11px;
+ padding-block:8px;
+ border-radius:6px;
+ background-color:var(--editor-toolbar-bg-color);
+ border:1px solid var(--editor-toolbar-border-color);
+ box-shadow:var(--editor-toolbar-shadow);
+ inset-block-start:calc(100% + 4px);
+ width:calc(100% + 2 * var(--editor-toolbar-padding));
+
+ button{
+ width:100%;
+ height:auto;
+ border:none;
+ cursor:pointer;
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ background:none;
+
+ &:is(:active, :focus-visible){
+ outline:none;
+ }
+
+ > .swatch{
+ outline-offset:2px;
+ }
+
+ &[aria-selected="true"] > .swatch{
+ outline:2px solid var(--selected-outline-color);
+ }
+
+ &:is(:hover, :active, :focus-visible) > .swatch{
+ outline:2px solid var(--hover-outline-color);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+.editorParamsToolbar:has(#highlightParamsToolbarContainer){
+ padding:unset;
+}
+
+#highlightParamsToolbarContainer{
+ gap:16px;
+ padding-inline:10px;
+ padding-block-end:12px;
+
+ .colorPicker{
+ display:flex;
+ flex-direction:column;
+ gap:8px;
+
+ .dropdown{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ flex-direction:row;
+ height:auto;
+
+ button{
+ width:auto;
+ height:auto;
+ border:none;
+ cursor:pointer;
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ background:none;
+ flex:0 0 auto;
+ padding:0;
+
+ .swatch{
+ width:24px;
+ height:24px;
+ }
+
+ &:is(:active, :focus-visible){
+ outline:none;
+ }
+
+ &[aria-selected="true"] > .swatch{
+ outline:2px solid var(--selected-outline-color);
+ }
+
+ &:is(:hover, :active, :focus-visible) > .swatch{
+ outline:2px solid var(--hover-outline-color);
+ }
+ }
+ }
+ }
+
+ #editorHighlightThickness{
+ display:flex;
+ flex-direction:column;
+ align-items:center;
+ gap:4px;
+ align-self:stretch;
+
+ .editorParamsLabel{
+ height:auto;
+ align-self:stretch;
+ }
+
+ .thicknessPicker{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ align-self:stretch;
+
+ --example-color:light-dark(#bfbfc9, #80808e);
+
+ @media screen and (forced-colors: active){
+ --example-color:CanvasText;
+ }
+
+ :is(& > .editorParamsSlider[disabled]){
+ opacity:0.4;
+ }
+
+ &::before,
+ &::after{
+ content:"";
+ width:8px;
+ aspect-ratio:1;
+ display:block;
+ border-radius:100%;
+ background-color:var(--example-color);
+ }
+ &::after{
+ width:24px;
+ }
+
+ .editorParamsSlider{
+ width:unset;
+ height:14px;
+ }
+ }
+ }
+
+ #editorHighlightVisibility{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ gap:8px;
+ align-self:stretch;
+
+ .divider{
+ --divider-color:light-dark(#d7d7db, #8f8f9d);
+
+ @media screen and (forced-colors: active){
+ --divider-color:CanvasText;
+ }
+
+ margin-block:4px;
+ width:100%;
+ height:1px;
+ background-color:var(--divider-color);
+ }
+
+ .toggler{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ align-self:stretch;
+ }
+ }
+}
+
+#altTextSettingsDialog{
+ padding:16px;
+
+ #altTextSettingsContainer{
+ display:flex;
+ width:573px;
+ flex-direction:column;
+ gap:16px;
+
+ .mainContainer{
+ gap:16px;
+ }
+
+ .description{
+ color:var(--text-secondary-color);
+ }
+
+ #aiModelSettings{
+ display:flex;
+ flex-direction:column;
+ gap:12px;
+ }
+
+ #automaticAltText,
+ #altTextEditor{
+ display:flex;
+ flex-direction:column;
+ gap:8px;
+ }
+
+ #createModelDescription,
+ #aiModelSettings,
+ #showAltTextDialogDescription{
+ padding-inline-start:40px;
+ }
+
+ #automaticSettings{
+ display:flex;
+ flex-direction:column;
+ gap:16px;
+ }
+ }
+}
+
+button.hasPopupMenu{
+ &[aria-expanded="true"] + menu{
+ visibility:visible;
+ }
+
+ &[aria-expanded="false"] + menu{
+ visibility:hidden;
+ }
+}
+
+.popupMenu{
+ --menuitem-checkmark-icon:url(images/checkmark.svg);
+ --menu-mark-icon-size:0;
+ --menu-icon-size:16px;
+ --menuitem-gap:5px;
+ --menuitem-border-color:transparent;
+ --menuitem-active-bg:color-mix(
+ in srgb,
+ var(--menu-text-color),
+ transparent 79%
+ );
+ --menuitem-text-active-fg:var(--menu-text-color);
+ --menuitem-active-border-color:var(--menuitem-border-color);
+ --menuitem-focus-bg:color-mix(
+ in srgb,
+ var(--menu-text-color),
+ transparent 93%
+ );
+ --menuitem-focus-outline-color:var(
+ --focus-outline-color,
+ light-dark(#0062fa, #00cadb)
+ );
+ --menuitem-focus-border-color:light-dark(white, black);
+
+ --menu-bg:var(--background-color-box, light-dark(white, #23222b));
+ --menu-background-blend-mode:normal;
+ --menu-box-shadow:0 0.375px 1.5px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 3px 12px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --menu-border-color:light-dark(rgb(21 20 26 / 0.1), rgb(251 251 254 / 0.1));
+ --menuitem-border-radius:8px;
+ --menu-backdrop-filter:none;
+ --menu-text-color:var(--text-color, light-dark(#15141a, #fbfbfe));
+ --menu-text-disabled-color:var(--menu-text-color);
+ --menuitem-text-hover-fg:var(--menu-text-color);
+ --menuitem-hover-bg:color-mix(
+ in srgb,
+ var(--menu-text-color),
+ transparent 86%
+ );
+ --menuitem-hover-background-blend-mode:normal;
+ --disabled-opacity:0.62;
+
+ @media screen and (forced-colors: active){
+ --menu-bg:var(--background-color-box, Canvas);
+ --menu-background-blend-mode:normal;
+ --menu-box-shadow:none;
+ --menu-backdrop-filter:none;
+ --menu-text-color:var(--text-color, ButtonText);
+ --menu-text-disabled-color:GrayText;
+ --menu-border-color:CanvasText;
+ --menuitem-border-color:none;
+ --menuitem-hover-bg:SelectedItemText;
+ --menuitem-text-hover-fg:SelectedItem;
+ --menuitem-active-bg:SelectedItemText;
+ --menuitem-active-border-color:ButtonText;
+ --menuitem-text-active-fg:SelectedItem;
+ --menuitem-focus-bg:ButtonFace;
+ --menuitem-focus-outline-color:var(--focus-outline-color, CanvasText);
+ --menuitem-focus-border-color:none;
+ --disabled-opacity:1;
+ }
+
+ display:flex;
+ flex-direction:column;
+ width:-moz-max-content;
+ width:max-content;
+ height:auto;
+ position:relative;
+ left:0;
+ top:1px;
+ margin:0;
+ padding:5px;
+ box-sizing:border-box;
+
+ background:var(--menu-bg);
+ background-blend-mode:var(--menu-background-blend-mode);
+ box-shadow:var(--menu-box-shadow);
+ border-radius:6px;
+ border:1px solid var(--menu-border-color);
+ backdrop-filter:var(--menu-backdrop-filter);
+
+ &.withMark{
+ --menu-mark-icon-size:16px;
+ }
+
+ > button{
+ display:flex;
+ align-items:center;
+ position:relative;
+ width:100%;
+ height:26px;
+ padding-inline:calc(var(--menu-mark-icon-size) + var(--menuitem-gap)) var(--menuitem-gap);
+ gap:var(--menuitem-gap);
+ box-sizing:border-box;
+ border-radius:var(--menuitem-border-radius);
+ border:1px solid var(--menuitem-border-color);
+ background:transparent;
+
+ &.selected::after{
+ content:"";
+ display:inline-block;
+ width:11px;
+ height:11px;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-image:var(--menuitem-checkmark-icon);
+ mask-image:var(--menuitem-checkmark-icon);
+ background-color:var(--menu-text-color);
+ position:absolute;
+ inset-inline-start:var(--menuitem-gap);
+ top:50%;
+ transform:translateY(-50%) scaleX(var(--dir-factor));
+ }
+
+ &:disabled{
+ opacity:var(--disabled-opacity);
+
+ &.selected::after{
+ background-color:var(--menu-text-disabled-color);
+ }
+
+ &:not(.noIcon)::before{
+ background-color:var(--menu-text-disabled-color);
+ }
+
+ > span{
+ color:var(--menu-text-disabled-color);
+ }
+ }
+
+ &:not(:disabled){
+ &:hover{
+ background:var(--menuitem-hover-bg);
+ background-blend-mode:var(--menuitem-hover-background-blend-mode);
+
+ &:not(.noIcon)::before{
+ background-color:var(--menuitem-text-hover-fg);
+ }
+
+ > span{
+ color:var(--menuitem-text-hover-fg);
+ }
+
+ &.selected::after{
+ background-color:var(--menuitem-text-hover-fg);
+ }
+ }
+
+ &:active{
+ background-color:var(--menuitem-active-bg);
+ border-color:var(--menuitem-active-border-color);
+
+ > span{
+ color:var(--menuitem-text-active-fg);
+ }
+ }
+
+ &:focus-visible{
+ border-color:var(--menuitem-focus-border-color);
+ background-color:var(--menuitem-focus-bg);
+ outline:2px solid var(--menuitem-focus-outline-color);
+ outline-offset:2px;
+ }
+ }
+
+ &:not(.noIcon)::before{
+ display:inline-block;
+ width:var(--menu-icon-size);
+ height:var(--menu-icon-size);
+ content:"";
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ -webkit-mask-position:center;
+ mask-position:center;
+ background-color:var(--menu-text-color);
+ }
+
+ > span{
+ display:flex;
+ align-items:center;
+ align-self:stretch;
+ width:100%;
+ min-width:-moz-max-content;
+ min-width:max-content;
+ text-align:start;
+ color:var(--menu-text-color);
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ padding-inline-start:6px;
+
+ font:menu;
+ font-size:13px;
+ font-style:normal;
+ font-weight:510;
+ line-height:normal;
+ }
+ }
+
+}
+
+.treeView{
+ --treeitem-color:light-dark(rgb(0 0 0 / 0.8), rgb(255 255 255 / 0.8));
+ --treeitem-bg-color:light-dark(rgb(0 0 0 / 0.15), rgb(255 255 255 / 0.15));
+ --treeitem-hover-color:light-dark(rgb(0 0 0 / 0.9), rgb(255 255 255 / 0.9));
+ --treeitem-selected-color:light-dark(
+ rgb(0 0 0 / 0.9),
+ rgb(255 255 255 / 0.9)
+ );
+ --treeitem-selected-bg-color:light-dark(
+ rgb(0 0 0 / 0.25),
+ rgb(255 255 255 / 0.25)
+ );
+ --treeitem-expanded-icon:url(images/treeitem-expanded.svg);
+ --treeitem-collapsed-icon:url(images/treeitem-collapsed.svg);
+
+ &.withNesting{
+ .treeItemToggler{
+ &::before{
+ position:absolute;
+ display:inline-block;
+ width:16px;
+ height:16px;
+ inset-inline-end:4px;
+
+ content:"";
+ background-color:var(--toolbar-icon-bg-color);
+ -webkit-mask-image:var(--treeitem-expanded-icon);
+ mask-image:var(--treeitem-expanded-icon);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ }
+
+ position:relative;
+ float:inline-start;
+ height:0;
+ width:0;
+ color:rgb(255 255 255 / 0.5);
+
+ &.treeItemsHidden{
+ &::before{
+ -webkit-mask-image:var(--treeitem-collapsed-icon);
+ mask-image:var(--treeitem-collapsed-icon);
+ transform:scaleX(var(--dir-factor));
+ }
+
+ ~ .treeItems{
+ display:none;
+ }
+ }
+
+ &:hover + a,
+ &:hover ~ .treeItems{
+ background-color:var(--treeitem-bg-color);
+ background-clip:padding-box;
+ border-radius:2px;
+ color:var(--treeitem-hover-color);
+ }
+ }
+
+ > .treeItem,
+ .treeItem > .treeItems{
+ margin-inline-start:20px;
+ }
+ }
+
+ layersView .treeItem > a{
+ *{
+ cursor:pointer;
+ }
+
+ > label{
+ display:flex;
+ align-items:center;
+ padding-inline-start:4px;
+ > input{
+ margin-top:1px;
+ }
+ }
+ }
+
+ .treeItem{
+ > a{
+ text-decoration:none;
+ display:inline-block;
+ min-width:calc(100% - 4px);
+ height:auto;
+ margin-bottom:1px;
+ padding:2px 0 5px;
+ padding-inline-start:4px;
+ border-radius:2px;
+ color:var(--treeitem-color);
+ font-size:13px;
+ line-height:15px;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ white-space:normal;
+ cursor:default;
+
+ &:hover{
+ background-color:var(--treeitem-bg-color);
+ background-clip:padding-box;
+ border-radius:2px;
+ color:var(--treeitem-hover-color);
+
+ }
+ }
+
+ &.selected > a{
+ background-color:var(--treeitem-selected-bg-color);
+ color:var(--treeitem-selected-color);
+ }
+ }
+}
+
+#outerContainer{
+ &.viewsManagerMoving{
+ #viewsManager{
+ visibility:visible;
+ }
+ }
+
+ &.viewsManagerOpen{
+ #viewsManager{
+ visibility:visible;
+ inset-inline-start:8px;
+ }
+
+ #viewerContainer:not(.pdfPresentationMode){
+ inset-inline-start:var(--viewsManager-width, 0);
+ transition-property:inset-inline-start;
+ }
+ }
+
+ &.viewsManagerResizing :is(#sidebarContainer, #viewerContainer, #loadingBar){
+ transition-duration:0s;
+ }
+}
+
+#viewsManager{
+ --views-manager-button-icon:url(images/pages_viewButton.svg);
+ --views-manager-button-arrow-icon:url(images/pages_viewArrow.svg);
+ --views-manager-add-file-button-icon:url(images/toolbarButton-zoomIn.svg);
+ --current-outline-button-icon:url(images/toolbarButton-currentOutlineItem.svg);
+ --menuitem-thumbnailsView-icon:url(images/pages_viewButton.svg);
+ --menuitem-outlinesView-icon:url(images/toolbarButton-viewOutline.svg);
+ --menuitem-attachmentsView-icon:url(images/toolbarButton-viewAttachments.svg);
+ --menuitem-layersView-icon:url(images/toolbarButton-viewLayers.svg);
+ --manage-button-icon:url(images/toolbarButton-pageDown.svg);
+ --close-button-icon:url(images/pages_closeButton.svg);
+ --undo-label-icon:url(images/altText_done.svg);
+ --pages-selected-icon:url(images/pages_selected.svg);
+ --spinner-icon:url(images/altText_spinner.svg);
+
+ --sidebar-bg-color:light-dark(rgb(255 255 255 / 0.92), rgb(66 65 77 / 0.92));
+ --sidebar-backdrop-filter:blur(7px);
+ --sidebar-width:230px;
+ --sidebar-min-width:min-content;
+ --sidebar-max-width:50vw;
+ --sidebar-block-padding:8px;
+
+ --views-text-color:var(--text-color, light-dark(#15141a, #fbfbfe));
+ --button-fg:var(--views-text-color);
+ --button-no-bg:var(--button-background-color-toolbar, transparent);
+ --button-bg:var(
+ --button-background-color,
+ light-dark(rgb(21 20 26 / 0.07), rgb(251 251 254 / 0.07))
+ );
+ --views-button-border-color:var(--button-border-color, transparent);
+ --button-hover-bg:var(
+ --button-background-color-hover,
+ light-dark(rgb(21 20 26 / 0.14), rgb(251 251 254 / 0.14))
+ );
+ --button-hover-fg:var(--views-text-color);
+ --button-hover-border-color:var(--views-button-border-color);
+ --button-active-bg:var(
+ --button-background-color-active,
+ light-dark(rgb(21 20 26 / 0.21), rgb(251 251 254 / 0.21))
+ );
+ --button-active-fg:var(--views-text-color);
+ --button-active-border-color:var(--views-button-border-color);
+ --button-focus-no-bg:color-mix(
+ in srgb,
+ var(--views-text-color),
+ transparent 93%
+ );
+ --button-focus-outline-color:var(
+ --focus-outline-color,
+ light-dark(#0062fa, #00cadb)
+ );
+ --button-focus-border-color:light-dark(white, black);
+ --status-border-color:transparent;
+ --status-actions-bg:light-dark(
+ rgb(21 20 26 / 0.03),
+ rgb(251 251 254 / 0.03)
+ );
+ --status-undo-bg:light-dark(rgb(0 98 250 / 0.08), rgb(0 202 219 / 0.08));
+ --status-waiting-bg:var(--status-undo-bg);
+ --indicator-color:var(--color-accent-primary, light-dark(#0062fa, #00cadb));
+ --status-warning-bg:light-dark(#ffe8ea, #6e001f);
+ --indicator-warning-color:light-dark(#b20037, #ffa0aa);
+ --header-shadow:0 0.25px 0.75px -0.75px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 2px 6px -6px light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --header-bg:light-dark(rgb(255 255 255 / 0.92), #42414e);
+ --image-outline:none;
+ --image-border-width:6px;
+ --image-border-color:light-dark(#cfcfd8, #3a3944);
+ --image-hover-border-color:#bfbfc9;
+ --image-current-border-color:var(--button-focus-outline-color);
+ --image-current-focused-outline-color:var(--image-hover-border-color);
+ --image-page-number-bg:light-dark(#f0f0f4, #42414d);
+ --image-page-number-fg:var(--views-text-color);
+ --image-page-number-border-color:transparent;
+ --image-hover-page-number-bg:var(--image-page-number-bg);
+ --image-hover-page-number-fg:var(--image-page-number-fg);
+ --image-current-page-number-bg:var(--image-current-border-color);
+ --image-current-page-number-fg:light-dark(#fff, #15141a);
+ --image-current-hover-page-number-bg:var(--image-current-page-number-bg);
+ --image-current-hover-page-number-fg:var(--image-current-page-number-fg);
+ --image-shadow:0 0.375px 1.5px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 0 0 1px var(--image-border-color), 0 3px 12px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --image-hover-shadow:0 0.375px 1.5px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 0 0 1px light-dark(rgb(21 20 26 / 0.1), rgb(251 251 254 / 0.1)), 0 0 0 var(--image-border-width) var(--image-hover-border-color), 0 3px 12px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --image-current-shadow:0 0.375px 1.5px 0 light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 0 0 var(--image-border-width) var(--image-current-border-color), 0 3px 12px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --image-dragging-placeholder-bg:light-dark(
+ rgb(0 98 250 / 0.08),
+ rgb(0 202 219 / 0.08)
+ );
+ --image-dragging-placeholder-border:var(--image-outline);
+ --multiple-dragging-bg:white;
+ --image-multiple-dragging-shadow:0 0 0 var(--image-border-width) var(--image-current-border-color), var(--image-border-width) var(--image-border-width) 0 calc(var(--image-border-width) / 2) var(--multiple-dragging-bg), var(--image-border-width) var(--image-border-width) 0 calc(3 * var(--image-border-width) / 2) var(--image-current-border-color);
+ --image-dragging-shadow:0 0 0 var(--image-border-width) var(--image-current-border-color);
+ --multiple-dragging-indicator-bg:var(--indicator-color);
+ --multiple-dragging-text-color:light-dark(#fbfbfe, #15141a);
+
+ @media screen and (forced-colors: active){
+ --views-text-color:var(--text-color, CanvasText);
+ --button-fg:var(--button-text-color, ButtonText);
+ --button-bg:var(--button-background-color, ButtonFace);
+ --button-no-bg:var(--button-background-color, ButtonFace);
+ --views-button-border-color:var(--button-border-color, ButtonText);
+ --button-hover-bg:var(--button-background-color-hover, SelectedItemText);
+ --button-hover-fg:var(--button-text-color-hover, SelectedItem);
+ --button-hover-border-color:var(--button-border-color-hover, SelectedItem);
+ --button-active-bg:var(--button-background-color-active, SelectedItemText);
+ --button-active-fg:var(--button-text-color-active, SelectedItem);
+ --button-active-border-color:var(--button-border-color-active, ButtonText);
+ --button-focus-no-bg:var(--button-background-color, ButtonFace);
+ --button-focus-outline-color:var(--focus-outline-color, CanvasText);
+ --button-focus-border-color:none;
+ --status-border-color:CanvasText;
+ --status-undo-bg:none;
+ --indicator-color:var(--text-color, CanvasText);
+ --status-warning-bg:none;
+ --indicator-warning-color:CanvasText;
+ --header-shadow:none;
+ --image-shadow:none;
+ --image-outline:1px solid ButtonText;
+ --image-focus-outline-color:CanvasText;
+ --image-hover-border-color:SelectedItem;
+ --image-hover-page-number-bg:SelectedItemText;
+ --image-hover-page-number-fg:SelectedItem;
+ --image-current-page-number-bg:ButtonText;
+ --image-current-page-number-fg:ButtonFace;
+ --image-current-border-color:var(--border-color, ButtonText);
+ --image-current-focused-outline-color:var(--image-hover-border-color);
+ --image-current-hover-page-number-bg:SelectedItem;
+ --image-current-hover-page-number-fg:SelectedItemText;
+ --image-page-number-bg:ButtonFace;
+ --image-page-number-fg:ButtonText;
+ --image-page-number-border-color:var(--image-page-number-fg);
+ --multiple-dragging-bg:Canvas;
+ --multiple-dragging-indicator-bg:var(--text-color, ButtonBorder);
+ --multiple-dragging-text-color:Canvas;
+ --image-dragging-placeholder-bg:Canvas;
+ --image-dragging-placeholder-border:1px GrayText solid;
+ }
+
+ display:flex;
+ padding-bottom:16px;
+ flex-direction:column;
+ align-items:flex-start;
+ inset-block-start:calc(100% + var(--sidebar-block-padding));
+ height:calc(
+ var(--viewer-container-height) - 2 * var(--sidebar-block-padding)
+ );
+ position:absolute;
+
+ inset-inline-start:calc(
+ -1 * var(--viewsManager-width, --sidebar-width) - 1px
+ );
+ transition-property:inset-inline-start;
+ transition-duration:var(--sidebar-transition-duration);
+ transition-timing-function:var(--sidebar-transition-timing-function);
+
+ .sidebarResizer{
+ inset-inline-start:calc(100% + 4px);
+ }
+
+ .viewsManagerButton{
+ width:auto;
+ color:var(--button-fg);
+ border-radius:var(--button-border-radius, 8px);
+ border:1px solid var(--views-button-border-color);
+ background:var(--button-bg);
+
+ &:hover{
+ background-color:var(--button-hover-bg) !important;
+ color:var(--button-hover-fg) !important;
+ border-color:var(--button-hover-border-color) !important;
+
+ &::before{
+ background-color:var(--button-hover-fg) !important;
+ }
+ }
+ &:active{
+ background:var(--button-active-bg) !important;
+ color:var(--button-active-fg) !important;
+ border-color:var(--button-active-border-color) !important;
+
+ &::before{
+ background-color:var(--button-active-fg) !important;
+ }
+ }
+ &:focus-visible{
+ outline:2px solid var(--button-focus-outline-color);
+ outline-offset:2px;
+ border-color:var(--button-focus-border-color);
+ }
+
+ &.viewsCloseButton{
+ width:var(--size-item-large, 26px);
+ height:var(--size-item-large, 26px);
+ border-radius:var(--button-border-radius, 8px);
+ background:none;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+
+ &::before{
+ width:16px;
+ height:16px;
+ -webkit-mask-image:var(--close-button-icon);
+ mask-image:var(--close-button-icon);
+ }
+ }
+ }
+
+ #viewsManagerHeader{
+ display:flex;
+ flex-direction:column;
+ align-items:flex-start;
+ align-self:stretch;
+ width:100%;
+ box-shadow:var(--header-shadow);
+ flex:0 0 auto;
+ background-color:var(--header-bg);
+
+ .viewsManagerLabel{
+ flex:1 1 auto;
+ color:var(--views-text-color);
+ text-align:center;
+ height:-moz-fit-content;
+ height:fit-content;
+ width:-moz-fit-content;
+ width:fit-content;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ font:menu;
+ font-size:15px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ }
+
+ #viewsManagerTitle{
+ display:flex;
+ flex-direction:row;
+ align-items:center;
+ align-self:stretch;
+ justify-content:space-between;
+ width:auto;
+ padding-block:12px;
+ padding-inline:8px 16px;
+
+ &:not(:has(#viewsManagerHeaderLabel ~ button:not([hidden])))::after{
+
+ content:"";
+ flex:0 0 auto;
+ width:32px;
+ height:32px;
+ pointer-events:none;
+ }
+
+ #viewsManagerSelector{
+ width:48px;
+ height:32px;
+ display:block;
+
+ > button{
+ background:var(--button-no-bg);
+ width:100%;
+ height:100%;
+
+ &:focus-visible{
+ background-color:var(--button-focus-no-bg);
+ }
+
+ &::before{
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-image:var(--views-manager-button-icon);
+ mask-image:var(--views-manager-button-icon);
+ background-color:var(--button-fg);
+ }
+
+ &::after{
+ content:"";
+ display:inline-block;
+ width:12px;
+ height:12px;
+ margin-inline-start:8px;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-image:var(--views-manager-button-arrow-icon);
+ mask-image:var(--views-manager-button-arrow-icon);
+ background-color:var(--button-fg);
+ }
+
+ &:hover{
+ &::before,
+ &::after{
+ background-color:var(--button-hover-fg) !important;
+ }
+ }
+
+ &:active{
+ &::before,
+ &::after{
+ background-color:var(--button-active-fg) !important;
+ }
+ }
+ }
+
+ > .popupMenu{
+ min-width:182px;
+ z-index:1;
+
+ > button{
+ thumbnailsViewMenu::before{
+ -webkit-mask-image:var(--menuitem-thumbnailsView-icon);
+ mask-image:var(--menuitem-thumbnailsView-icon);
+ }
+ outlinesViewMenu::before{
+ -webkit-mask-image:var(--menuitem-outlinesView-icon);
+ mask-image:var(--menuitem-outlinesView-icon);
+ }
+ attachmentsViewMenu::before{
+ -webkit-mask-image:var(--menuitem-attachmentsView-icon);
+ mask-image:var(--menuitem-attachmentsView-icon);
+ }
+ layersViewMenu::before{
+ -webkit-mask-image:var(--menuitem-layersView-icon);
+ mask-image:var(--menuitem-layersView-icon);
+ }
+ }
+ }
+ }
+
+ #viewsManagerAddFileButton{
+ background:var(--button-no-bg);
+ width:32px;
+ height:32px;
+
+ &:focus-visible{
+ background-color:var(--button-focus-no-bg);
+ }
+
+ &::before{
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-image:var(--views-manager-add-file-button-icon);
+ mask-image:var(--views-manager-add-file-button-icon);
+ background-color:var(--button-fg);
+ }
+
+ > input{
+ display:none;
+ }
+ }
+
+ #viewsManagerCurrentOutlineButton{
+ background:var(--button-no-bg);
+ width:32px;
+ height:32px;
+
+ &:focus-visible{
+ background-color:var(--button-focus-no-bg);
+ }
+
+ &::before{
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-image:var(--current-outline-button-icon);
+ mask-image:var(--current-outline-button-icon);
+ background-color:var(--button-fg);
+ }
+ }
+ }
+
+ #viewsManagerStatus{
+ display:grid;
+ width:100%;
+ border:1px solid var(--status-border-color);
+
+ > div{
+ min-height:64px;
+ width:100%;
+ padding-inline:16px;
+ grid-area:1 / 1;
+ box-sizing:border-box;
+
+ &.hidden{
+ visibility:hidden;
+ display:unset !important;
+ }
+ }
+
+ .viewsManagerStatusLabel{
+ display:flex;
+ align-items:center;
+ gap:8px;
+
+ font:menu;
+ font-size:13px;
+ }
+
+ #viewsManagerStatusAction{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ align-self:stretch;
+ background-color:var(--status-actions-bg);
+
+ #viewsManagerStatusActionLabelContainer > button{
+ position:relative;
+ width:var(--icon-size);
+ height:var(--icon-size);
+ border:none;
+ padding:0;
+ flex:0 0 auto;
+
+ &::before{
+ content:"";
+ position:absolute;
+ inset:0;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ background-color:var(--indicator-color);
+ -webkit-mask-image:var(--pages-selected-icon);
+ mask-image:var(--pages-selected-icon);
+ }
+
+ @media screen and (forced-colors: active){
+ border-radius:2px;
+ background-color:var(--button-bg);
+
+ &::before{
+ background-color:var(--button-fg);
+ }
+ &:hover{
+ background-color:var(--button-hover-bg);
+
+ &::before{
+ background-color:var(--button-hover-fg);
+ }
+ }
+ &:active{
+ background-color:var(--button-active-bg);
+
+ &::before{
+ background-color:var(--button-active-fg);
+ }
+ }
+ }
+
+ viewsManagerStatusActionDeselectButton:focus-visible{
+ outline:2px solid var(--button-focus-outline-color);
+ border:1px solid var(--button-focus-border-color);
+ border-radius:2px;
+ outline-offset:1px;
+ }
+ }
+
+ #actionSelector{
+ height:32px;
+ min-width:115px;
+ width:auto;
+ display:block;
+
+ #viewsManagerStatusActionButton{
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+ gap:8px;
+ width:100%;
+ height:100%;
+ padding:4px 16px;
+
+ &::after{
+ content:"";
+ display:inline-block;
+ width:var(--icon-size);
+ height:var(--icon-size);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-image:var(--manage-button-icon);
+ mask-image:var(--manage-button-icon);
+ background-color:var(--button-fg);
+ }
+
+ &:hover::after{
+ background-color:var(--button-hover-fg) !important;
+ }
+
+ &:active::after{
+ background-color:var(--button-active-fg) !important;
+ }
+ }
+
+ > .popupMenu{
+ width:100%;
+ min-width:-moz-fit-content;
+ min-width:fit-content;
+ z-index:1;
+ }
+ }
+ }
+
+ #viewsManagerStatusUndo{
+ display:flex;
+ justify-content:space-between;
+ align-items:center;
+ align-self:stretch;
+ background-color:var(--status-undo-bg);
+
+ > span::before{
+ content:"";
+ display:inline-block;
+ width:var(--icon-size);
+ height:var(--icon-size);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-image:var(--undo-label-icon);
+ mask-image:var(--undo-label-icon);
+ background-color:var(--indicator-color);
+ }
+
+ > div{
+ display:flex;
+ align-items:center;
+ gap:8px;
+ width:auto;
+
+ #viewsManagerStatusUndoButton{
+ width:auto;
+ min-height:24px;
+ padding:4px 8px;
+ }
+ }
+ }
+
+ #viewsManagerStatusWarning{
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+ background-color:var(--status-warning-bg);
+
+ > span{
+ align-items:flex-start;
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:var(--icon-size);
+ height:var(--icon-size);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ background-color:var(--indicator-warning-color);
+ -webkit-mask-image:var(--undo-label-icon);
+ mask-image:var(--undo-label-icon);
+ flex:0 0 auto;
+ }
+ }
+ }
+
+ #viewsManagerStatusWaiting{
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+ background-color:var(--status-waiting-bg);
+
+ > span::before{
+ content:"";
+ display:inline-block;
+ width:var(--icon-size);
+ height:var(--icon-size);
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-position:center;
+ mask-position:center;
+ background-color:var(--indicator-color);
+ -webkit-mask-image:var(--spinner-icon);
+ mask-image:var(--spinner-icon);
+ flex:0 0 auto;
+ }
+ }
+ }
+ }
+
+ #viewsManagerContent{
+ width:100%;
+ flex:1 1 0%;
+ overflow:auto;
+
+ &:has(#thumbnailsView.isDragging){
+ overflow-x:hidden;
+ }
+
+ #thumbnailsView{
+ --thumbnail-width:126px;
+ --gap-between-input-and-thumbnail:16px;
+
+ display:flex;
+ flex-flow:row wrap;
+ align-items:center;
+ justify-content:space-evenly;
+ padding:20px 32px;
+ gap:44px;
+ width:100%;
+ box-sizing:border-box;
+ position:relative;
+
+ &.isDragging{
+ cursor:grabbing;
+
+ > .thumbnail{
+ > .thumbnailImageContainer:hover{
+ cursor:grabbing;
+
+ &:not([aria-current="page"]){
+ box-shadow:var(--image-shadow);
+ }
+ }
+
+ > input{
+ pointer-events:none;
+ }
+ }
+ }
+
+ &.isDragging > .dragMarker,
+ &.isDraggingFile > .dragMarker{
+ position:absolute;
+ top:0;
+ left:0;
+ border:2px solid var(--indicator-color);
+ contain:strict;
+ }
+
+ &.pasteMode{
+ gap:var(--gap-between-input-and-thumbnail);
+
+ > .thumbnail{
+ flex-direction:column;
+
+ > input{
+ display:none;
+ }
+
+ > .thumbnailPasteButton{
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ border-radius:16px;
+ min-height:24px;
+ padding:4px 16px;
+
+ font:menu;
+ font-size:13px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ }
+ }
+ }
+
+ &:not(.pasteMode) > .thumbnail > .thumbnailPasteButton{
+ display:none;
+ }
+
+ > .thumbnail{
+ --input-dim:16px;
+
+ &:not(&:has(input)){
+ --input-dim:0px;
+ --gap-between-input-and-thumbnail:0px;
+ }
+
+ display:inline-flex;
+ justify-content:flex-end;
+ align-items:center;
+ flex-direction:row-reverse;
+ gap:var(--gap-between-input-and-thumbnail);
+ width:calc(
+ var(--thumbnail-width) + 2 *
+ (var(--input-dim) + var(--gap-between-input-and-thumbnail))
+ );
+ height:auto;
+ position:relative;
+ scroll-margin-top:20px;
+
+ .thumbnailPasteButton{
+ padding:8px 0;
+ text-align:center;
+ }
+
+ &:not(.isDragging) > .thumbnailImageContainer::after{
+ content:attr(page-number);
+ border-radius:8px;
+ border:1px solid var(--image-page-number-border-color);
+ background-color:var(--image-page-number-bg);
+ color:var(--image-page-number-fg);
+ position:absolute;
+ bottom:5px;
+ inset-inline-end:50%;
+ min-width:32px;
+ height:16px;
+ text-align:center;
+ box-sizing:content-box;
+ translate:calc(var(--dir-factor) * 50%);
+
+ font:menu;
+ font-size:12px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+
+ pointer-events:none;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ }
+
+ &:has([aria-current="page"]):not(.isDragging)
+ > .thumbnailImageContainer::after{
+ background-color:var(--image-current-page-number-bg);
+ color:var(--image-current-page-number-fg);
+ outline:1px solid var(--image-current-border-color);
+ }
+
+ &.isDragging > input{
+ visibility:hidden;
+ }
+
+ > input{
+ margin:0;
+ width:var(--input-dim);
+ height:var(--input-dim);
+ accent-color:var(--indicator-color);
+ }
+
+ > .thumbnailImageContainer{
+ --thumbnail-dragging-scale:1.4;
+
+ width:var(--thumbnail-width);
+ border:none;
+ border-radius:8px;
+ box-shadow:var(--image-shadow);
+ box-sizing:content-box;
+ outline:var(--image-outline);
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ position:relative;
+
+ img{
+ width:100%;
+ height:100%;
+ border:none;
+ border-radius:8px;
+ outline:none;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ pointer-events:none;
+
+ }
+
+ &.missingThumbnailImage{
+ content-visibility:hidden;
+ }
+
+ &:hover{
+ cursor:pointer;
+ box-shadow:var(--image-hover-shadow);
+
+ &::after{
+ background-color:var(--image-hover-page-number-bg);
+ color:var(--image-hover-page-number-fg);
+ }
+
+ @media screen and (forced-colors: active){
+ box-shadow:none;
+ outline:var(--image-border-width) var(--image-hover-border-color) solid;
+ }
+ }
+
+ &:focus-visible{
+ &:not([aria-current="page"]){
+ box-shadow:var(--image-hover-shadow);
+ outline:none;
+
+ @media screen and (forced-colors: active){
+ box-shadow:none;
+ outline:var(--image-border-width) var(--image-focus-outline-color) solid;
+ }
+ }
+
+ &[aria-current="page"]{
+ outline:var(--image-border-width) solid var(--image-current-focused-outline-color);
+ outline-offset:var(--image-border-width);
+
+ @media screen and (forced-colors: active){
+ box-shadow:none;
+ outline:var(--image-border-width) var(--image-current-border-color) solid;
+ outline-offset:0;
+
+ > img{
+ outline:var(--image-border-width) var(--image-focus-outline-color) solid;
+ outline-offset:var(--image-border-width);
+ }
+ }
+ }
+
+ @media screen and (forced-colors: active){
+ box-shadow:none;
+ outline:var(--image-border-width) var(--image-current-border-color) solid;
+
+ &:hover > img{
+ outline:var(--image-border-width) var(--image-hover-border-color) solid;
+ outline-offset:var(--image-border-width);
+ }
+ }
+ }
+
+ &[aria-current="page"]{
+ box-shadow:var(--image-current-shadow);
+
+ &:hover::after{
+ background-color:var(--image-current-hover-page-number-bg);
+ color:var(--image-current-hover-page-number-fg);
+ }
+
+ @media screen and (forced-colors: active){
+ box-shadow:none;
+ outline:var(--image-border-width) var(--image-current-border-color) solid;
+
+ &:hover > img{
+ outline:var(--image-border-width) var(--image-hover-border-color) solid;
+ outline-offset:var(--image-border-width);
+ }
+ }
+ }
+
+ &.placeholder{
+ background-color:var(--image-dragging-placeholder-bg);
+ box-shadow:none !important;
+ outline:var(--image-dragging-placeholder-border);
+ }
+
+ &.draggingThumbnail{
+ position:absolute;
+ left:0;
+ top:0;
+ z-index:1;
+ transform-origin:0 0 0;
+ scale:calc(1 / var(--thumbnail-dragging-scale));
+ pointer-events:none;
+ box-shadow:var(--image-dragging-shadow);
+
+ &.multiple{
+ box-shadow:var(--image-multiple-dragging-shadow);
+
+ @media screen and (forced-colors: active){
+ forced-color-adjust:none;
+ box-shadow:var(--image-multiple-dragging-shadow);
+ }
+
+ > .thumbnailImageContainer{
+ position:absolute;
+ top:0;
+ left:0;
+
+ width:var(--thumbnail-width);
+ border:none;
+ border-radius:8px;
+ box-sizing:content-box;
+ outline:none;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ }
+
+ &::after{
+ content:attr(data-multiple-count);
+ border-radius:calc(8px * var(--thumbnail-dragging-scale));
+
+ background-color:var(--multiple-dragging-indicator-bg);
+ color:var(--multiple-dragging-text-color);
+ position:absolute;
+ inset-block-end:calc(4px * var(--thumbnail-dragging-scale));
+ inset-inline-start:calc(4px * var(--thumbnail-dragging-scale));
+ min-width:calc(32px * var(--thumbnail-dragging-scale));
+ height:calc(16px * var(--thumbnail-dragging-scale));
+ text-align:center;
+ font:menu;
+ font-size:calc(13px * var(--thumbnail-dragging-scale));
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ contain:strict;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ #attachmentsView{
+ --attachment-color:light-dark(rgb(0 0 0 / 0.8), rgb(255 255 255 / 0.8));
+ --attachment-bg-color:light-dark(
+ rgb(0 0 0 / 0.15),
+ rgb(255 255 255 / 0.15)
+ );
+ --attachment-hover-color:light-dark(
+ rgb(0 0 0 / 0.9),
+ rgb(255 255 255 / 0.9)
+ );
+
+ > ul{
+ list-style-type:none;
+ padding:0;
+
+ > li > a{
+ text-decoration:none;
+ display:inline-block;
+ min-width:calc(100% - 4px);
+ height:auto;
+ margin-bottom:1px;
+ padding:2px 0 5px;
+ padding-inline-start:4px;
+ border-radius:2px;
+ color:var(--attachment-color);
+ font-size:13px;
+ line-height:15px;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ white-space:normal;
+ cursor:pointer;
+
+ &:hover{
+ background-color:var(--attachment-bg-color);
+ background-clip:padding-box;
+ border-radius:2px;
+ color:var(--attachment-hover-color);
+ }
+ }
+ }
+ }
+ }
+}
+
+.sidebar{
+ --sidebar-bg-color:var(--background-color-box, light-dark(#fff, #23222b));
+ --sidebar-border-color:light-dark(
+ rgb(21 20 26 / 0.1),
+ rgb(251 251 254 / 0.1)
+ );
+ --sidebar-box-shadow:0 0.25px 0.75px light-dark(rgb(0 0 0 / 0.05), rgb(0 0 0 / 0.2)), 0 2px 6px 0 light-dark(rgb(0 0 0 / 0.1), rgb(0 0 0 / 0.4));
+ --sidebar-backdrop-filter:none;
+ --sidebar-border-radius:8px;
+ --sidebar-padding:5px;
+ --sidebar-min-width:180px;
+ --sidebar-max-width:632px;
+ --sidebar-width:239px;
+ --resizer-width:4px;
+ --resizer-shift:calc(0px - var(--resizer-width) - 2px);
+ --resizer-hover-bg-color:var(
+ --color-accent-primary,
+ light-dark(#0062fa, #00cadb)
+ );
+
+ @media screen and (forced-colors: active){
+ --sidebar-bg-color:var(--background-color-box, Canvas);
+ --sidebar-border-color:CanvasText;
+ --sidebar-box-shadow:none;
+ --resizer-hover-bg-color:var(--text-color, CanvasText);
+ }
+
+ border-radius:var(--sidebar-border-radius);
+ box-shadow:var(--sidebar-box-shadow);
+ border:1px solid var(--sidebar-border-color);
+ background-color:var(--sidebar-bg-color);
+ inset-block-start:calc(100% + var(--doorhanger-height) - 2px);
+ padding-block:var(--sidebar-padding);
+ width:var(--sidebar-width);
+ min-width:var(--sidebar-min-width);
+ max-width:var(--sidebar-max-width);
+ backdrop-filter:var(--sidebar-backdrop-filter);
+ box-sizing:border-box;
+ position:relative;
+
+ .sidebarResizer{
+ width:var(--resizer-width);
+ background-color:transparent;
+ forced-color-adjust:none;
+ cursor:ew-resize;
+ position:absolute;
+ inset-block:0;
+ inset-inline-start:var(--resizer-shift);
+ transition:background-color 0.5s ease-in-out, border-color 0.5s ease-in-out;
+ box-sizing:border-box;
+ border:1px solid transparent;
+ border-block-width:0;
+ background-clip:content-box;
+
+ &:hover{
+ background-color:var(--resizer-hover-bg-color);
+ border-color:white;
+ }
+ &:focus-visible{
+ background-color:var(--resizer-hover-bg-color);
+ outline:none;
+ }
+ }
+
+ &.resizing{
+ cursor:ew-resize;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+
+ :not(.sidebarResizer){
+ pointer-events:none;
+ }
+
+ .sidebarResizer{
+ background-color:var(--resizer-hover-bg-color);
+ }
+ }
+}
+
+:root{
+ color-scheme:light dark;
+
+ --viewer-container-height:0;
+ --pdfViewer-padding-bottom:0;
+ --page-margin:1px auto -8px;
+ --page-border:9px solid transparent;
+ --spreadHorizontalWrapped-margin-LR:-3.5px;
+ --loading-icon-delay:400ms;
+ --focus-ring-color:var(--focus-outline-color, light-dark(#0060df, #0df));
+ --focus-ring-outline:var(--focus-outline-width, 2px) solid var(--focus-ring-color);
+ --text-primary-color:var(--text-color, light-dark(#15141a, #fbfbfe));
+ --link-fg-color:var(--link-color, light-dark(#0060df, #0df));
+ --link-hover-fg-color:var(--link-color-hover, light-dark(#0250bb, #80ebff));
+ --new-badge-bg:light-dark(#070, #37b847);
+ --new-badge-color:light-dark(#fff, #15141a);
+ --new-badge-border-color:light-dark(#fbfbfe / 40%, #15141a / 40%);
+
+ @media screen and (forced-colors: active){
+ --pdfViewer-padding-bottom:9px;
+ --page-margin:8px auto -1px;
+ --page-border:1px solid CanvasText;
+ --spreadHorizontalWrapped-margin-LR:3.5px;
+ --focus-ring-color:var(--focus-outline-color, CanvasText);
+ --text-primary-color:var(--text-color, CanvasText);
+ --link-fg-color:var(--link-color, LinkText);
+ --link-hover-fg-color:var(--link-color-hover, LinkText);
+ --new-badge-bg:AccentColor;
+ --new-badge-color:ButtonFace;
+ --new-badge-border-color:CanvasText;
+ }
+}
+
+.newBadge{
+ background-color:var(--new-badge-bg);
+ color:var(--new-badge-color);
+ border-radius:4px;
+ border:1px solid var(--new-badge-border-color);
+ padding-inline:4px;
+
+ margin-inline:4px;
+ font:menu;
+ font-size:12px;
+ font-style:normal;
+ font-weight:400;
+ line-height:normal;
+ flex:0 0 fit-content;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+}
+
+[data-main-rotation="90"]{
+ transform:rotate(90deg) translateY(-100%);
+}
+[data-main-rotation="180"]{
+ transform:rotate(180deg) translate(-100%, -100%);
+}
+[data-main-rotation="270"]{
+ transform:rotate(270deg) translateX(-100%);
+}
+
+.pdfViewer{
+ --scale-factor:1;
+ --page-bg-color:unset;
+
+ padding-bottom:var(--pdfViewer-padding-bottom);
+
+ --hcm-highlight-filter:none;
+ --hcm-highlight-selected-filter:none;
+
+ @media screen and (forced-colors: active){
+ --hcm-highlight-filter:invert(100%);
+ }
+
+ &.copyAll{
+ cursor:wait;
+ }
+
+ .canvasWrapper{
+ overflow:hidden;
+ width:100%;
+ height:100%;
+
+ canvas{
+ position:absolute;
+ top:0;
+ left:0;
+ margin:0;
+ display:block;
+ width:100%;
+ height:100%;
+ contain:content;
+
+ .structTree{
+ contain:strict;
+ }
+
+ &.detailView{
+ image-rendering:pixelated;
+ }
+ }
+ .selection{
+ position:absolute;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ pointer-events:none;
+ background:rgb(0 90 255 / 0.22);
+ }
+ }
+}
+
+.pdfViewer .page{
+ --user-unit:1;
+ --total-scale-factor:calc(var(--scale-factor) * var(--user-unit));
+ --scale-round-x:1px;
+ --scale-round-y:1px;
+
+ direction:ltr;
+ width:816px;
+ height:1056px;
+ margin:var(--page-margin);
+ position:relative;
+ overflow:visible;
+ border:var(--page-border);
+ background-clip:content-box;
+ background-color:var(--page-bg-color, rgb(255 255 255));
+}
+
+.pdfViewer .dummyPage{
+ position:relative;
+ width:0;
+ height:var(--viewer-container-height);
+}
+
+.pdfViewer.noUserSelect{
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+}
+
+.pdfViewer.removePageBorders .page{
+ margin:0 auto 10px;
+ border:none;
+}
+
+.pdfViewer:is(.scrollHorizontal, .scrollWrapped),
+.spread{
+ margin-inline:3.5px;
+ text-align:center;
+}
+
+.pdfViewer.scrollHorizontal,
+.spread{
+ white-space:nowrap;
+}
+
+.pdfViewer.removePageBorders,
+.pdfViewer:is(.scrollHorizontal, .scrollWrapped) .spread{
+ margin-inline:0;
+}
+
+.spread :is(.page, .dummyPage),
+.pdfViewer:is(.scrollHorizontal, .scrollWrapped) :is(.page, .spread){
+ display:inline-block;
+ vertical-align:middle;
+}
+
+.spread .page,
+.pdfViewer:is(.scrollHorizontal, .scrollWrapped) .page{
+ margin-inline:var(--spreadHorizontalWrapped-margin-LR);
+}
+
+.pdfViewer.removePageBorders .spread .page,
+.pdfViewer.removePageBorders:is(.scrollHorizontal, .scrollWrapped) .page{
+ margin-inline:5px;
+}
+
+.pdfViewer .page.loadingIcon::after{
+ position:absolute;
+ top:0;
+ left:0;
+ content:"";
+ width:100%;
+ height:100%;
+ background:url("images/loading-icon.gif") center no-repeat;
+ display:none;
+ transition-property:display;
+ transition-delay:var(--loading-icon-delay);
+ z-index:5;
+ contain:strict;
+}
+
+.pdfViewer .page.loading::after{
+ display:block;
+}
+
+.pdfViewer .page:not(.loading)::after{
+ transition-property:none;
+ display:none;
+}
+
+.pdfPresentationMode .pdfViewer{
+ padding-bottom:0;
+}
+
+.pdfPresentationMode .spread{
+ margin:0;
+}
+
+.pdfPresentationMode .pdfViewer .page{
+ margin:0 auto;
+ border:2px solid transparent;
+}
+
+:root{
+ --sig-card-border:light-dark(rgb(228 228 232), rgb(82 82 86));
+ --sig-card-bg:var(--field-bg-color, light-dark(white, rgb(64 64 68)));
+ --sig-card-nested-bg:light-dark(rgb(252 252 253), rgb(72 72 76));
+ --sig-row-color:light-dark(rgb(58 58 60), rgb(228 228 232));
+ --sig-detail-color:light-dark(rgb(96 96 96), rgb(180 180 184));
+ --sig-divider-color:light-dark(rgb(228 228 232), rgb(82 82 86));
+ --sig-summary-hover-color:light-dark(rgb(28 67 138), rgb(126 169 255));
+ --sig-link-color:var(
+ --link-color,
+ light-dark(rgb(28 113 216), rgb(126 169 255))
+ );
+ --sig-link-hover-bg:light-dark(
+ rgb(28 113 216 / 0.1),
+ rgb(126 169 255 / 0.15)
+ );
+ --sig-banner-verified-bg:var(
+ --background-color-success,
+ light-dark(rgb(228 247 235), rgb(28 84 49))
+ );
+ --sig-banner-verified-color:light-dark(rgb(16 92 47), rgb(176 232 196));
+ --sig-banner-warn-bg:var(
+ --background-color-warning,
+ light-dark(rgb(255 247 217), rgb(95 67 9))
+ );
+ --sig-banner-warn-color:light-dark(rgb(124 84 9), rgb(255 222 153));
+ --sig-banner-error-bg:var(
+ --background-color-critical,
+ light-dark(rgb(254 226 235), rgb(122 21 51))
+ );
+ --sig-banner-error-color:light-dark(rgb(167 26 70), rgb(255 188 207));
+ --sig-icon-default:light-dark(rgb(150 150 150), rgb(180 180 184));
+ --sig-icon-warn:var(
+ --icon-color-warning,
+ light-dark(rgb(217 142 27), rgb(255 178 77))
+ );
+ --sig-icon-error:var(
+ --icon-color-critical,
+ light-dark(rgb(196 31 71), rgb(255 117 145))
+ );
+ --sig-icon-verified:var(
+ --icon-color-success,
+ light-dark(rgb(29 142 61), rgb(106 210 126))
+ );
+
+ @media screen and (forced-colors: active){
+ --sig-card-border:ButtonBorder;
+ --sig-card-bg:Canvas;
+ --sig-card-nested-bg:ButtonFace;
+ --sig-row-color:ButtonText;
+ --sig-detail-color:GrayText;
+ --sig-divider-color:GrayText;
+ --sig-summary-hover-color:AccentColor;
+ --sig-link-color:var(--link-color, LinkText);
+ --sig-link-hover-bg:transparent;
+ --sig-banner-verified-bg:var(--background-color-success, ButtonFace);
+ --sig-banner-verified-color:var(--text-color, ButtonText);
+ --sig-banner-warn-bg:var(--background-color-warning, ButtonFace);
+ --sig-banner-warn-color:var(--text-color, ButtonText);
+ --sig-banner-error-bg:var(--background-color-critical, ButtonFace);
+ --sig-banner-error-color:var(--text-color, ButtonText);
+ --sig-icon-default:GrayText;
+ --sig-icon-warn:var(--icon-color-warning, AccentColor);
+ --sig-icon-error:var(--icon-color-critical, AccentColor);
+ --sig-icon-verified:var(--icon-color-success, AccentColor);
+ }
+}
+
+#signaturePropertiesButton{
+ &::before{
+ -webkit-mask-image:var(--toolbarButton-editorSignature-icon);
+ mask-image:var(--toolbarButton-editorSignature-icon);
+ transform:scaleX(var(--dir-factor));
+ }
+ &.state-verified::before,
+ &.state-warn::before,
+ &.state-error::before{
+ opacity:1;
+ }
+ &.state-verified::before{
+ -webkit-mask-image:var(--toolbarButton-signaturePropertiesVerified-icon);
+ mask-image:var(--toolbarButton-signaturePropertiesVerified-icon);
+ background-color:var(--sig-icon-verified);
+ }
+ &.state-warn::before{
+ -webkit-mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ background-color:var(--sig-icon-warn);
+ }
+ &.state-error::before{
+ -webkit-mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ background-color:var(--sig-icon-error);
+ }
+ &.state-loading{
+ &::before{
+ display:none;
+ }
+ .loadingDot{
+ display:inline-block;
+ width:4px;
+ height:4px;
+ margin:0 1px;
+ border-radius:50%;
+ background:var(--toolbar-icon-bg-color);
+ animation:signaturePropertiesDot 1.2s ease-in-out infinite both;
+
+ &:nth-child(2){
+ animation-delay:0.2s;
+ }
+ &:nth-child(3){
+ animation-delay:0.4s;
+ }
+ }
+ }
+}
+
+@keyframes signaturePropertiesDot{
+ 0%,
+ 80%,
+ 100%{
+ opacity:0.3;
+ transform:scale(0.85);
+ }
+ 40%{
+ opacity:1;
+ transform:scale(1);
+ }
+}
+
+#signaturePropertiesPanel{
+ width:320px;
+ padding:0;
+}
+
+.signaturePropertiesContainer{
+ display:flex;
+ flex-direction:column;
+ max-height:70vh;
+ overflow:hidden;
+}
+
+.sigBanner{
+ margin:12px 12px 8px;
+ padding:10px 12px;
+ border-radius:6px;
+ display:flex;
+ align-items:center;
+ gap:10px;
+ font-size:12.5px;
+ line-height:1.35;
+ border-inline-start:3px solid currentcolor;
+
+ &.verified{
+ background:var(--sig-banner-verified-bg);
+ color:var(--sig-banner-verified-color);
+ border-inline-start-color:var(--sig-icon-verified);
+ }
+ &.warn{
+ background:var(--sig-banner-warn-bg);
+ color:var(--sig-banner-warn-color);
+ border-inline-start-color:var(--sig-icon-warn);
+ }
+ &.error{
+ background:var(--sig-banner-error-bg);
+ color:var(--sig-banner-error-color);
+ border-inline-start-color:var(--sig-icon-error);
+ }
+}
+
+.signaturePropertiesList{
+ list-style:none;
+ margin:0;
+ padding:0 12px 12px;
+ overflow-y:auto;
+ display:flex;
+ flex-direction:column;
+ gap:6px;
+}
+
+.sigCard{
+ border:1px solid var(--sig-card-border);
+ border-radius:6px;
+ padding:8px 10px;
+ display:flex;
+ flex-direction:column;
+ gap:3px;
+ background:var(--sig-card-bg);
+
+ .signer{
+ font-weight:600;
+ font-size:13px;
+ letter-spacing:0.1px;
+ margin-bottom:1px;
+ }
+
+ .row{
+ display:flex;
+ flex-wrap:nowrap;
+ gap:2px 6px;
+ align-items:flex-start;
+ font-size:12px;
+ color:var(--sig-row-color);
+ min-height:18px;
+
+ > span{
+ flex:1 1 auto;
+ min-width:0;
+ overflow-wrap:break-word;
+ }
+
+ &::before{
+ content:"";
+ display:inline-block;
+ width:14px;
+ height:14px;
+ flex-shrink:0;
+ margin-top:1px;
+ -webkit-mask-position:center;
+ mask-position:center;
+ -webkit-mask-repeat:no-repeat;
+ mask-repeat:no-repeat;
+ -webkit-mask-size:contain;
+ mask-size:contain;
+ -webkit-mask-image:var(--signatureProperties-rowCheck-icon);
+ mask-image:var(--signatureProperties-rowCheck-icon);
+ background-color:var(--sig-icon-default);
+ transform:scaleX(var(--dir-factor));
+ }
+ &.status--verified::before,
+ &.status--untrusted::before,
+ &.status--expired::before,
+ &.status--revoked::before,
+ &.cert--trusted::before{
+ -webkit-mask-image:var(--signatureProperties-rowCheck-icon);
+ mask-image:var(--signatureProperties-rowCheck-icon);
+ background-color:var(--sig-icon-default);
+ }
+ &.cert--untrusted::before,
+ &.cert--expired::before{
+ -webkit-mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ background-color:var(--sig-icon-warn);
+ }
+ &.cert--revoked::before,
+ &.status--invalid::before,
+ &.status--unknown::before,
+ &.cert--unknown::before{
+ -webkit-mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ mask-image:var(--toolbarButton-signaturePropertiesError-icon);
+ background-color:var(--sig-icon-error);
+ }
+ }
+ &.sigCard--top-allfine > .row.status--verified::before,
+ &.sigCard--top-allfine > .row.cert--trusted::before{
+ -webkit-mask-image:var(--toolbarButton-signaturePropertiesVerified-icon);
+ mask-image:var(--toolbarButton-signaturePropertiesVerified-icon);
+ background-color:var(--sig-icon-verified);
+ }
+
+ .detail{
+ font-size:11.5px;
+ color:var(--sig-detail-color);
+ margin-inline-start:20px;
+ line-height:1.35;
+ }
+
+ .viewCert{
+ align-self:center;
+ margin-top:4px;
+ color:var(--sig-link-color);
+ background:none;
+ border:none;
+ cursor:pointer;
+ font-size:12px;
+ padding:2px 4px;
+ border-radius:4px;
+ white-space:nowrap;
+
+ &:hover{
+ background:var(--sig-link-hover-bg);
+ text-decoration:underline;
+ }
+ &:focus-visible{
+ outline:2px solid var(--sig-link-color);
+ outline-offset:1px;
+
+ }
+ }
+
+ .subSignatures{
+ margin-top:4px;
+ border-top:1px dashed var(--sig-divider-color);
+ padding-top:4px;
+ font-size:12px;
+
+ > summary{
+ cursor:pointer;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ list-style:none;
+ color:var(--sig-detail-color);
+ display:flex;
+ align-items:center;
+ gap:4px;
+ padding:2px 0;
+
+ &:hover{
+ color:var(--sig-summary-hover-color);
+ }
+ &::-webkit-details-marker{
+ display:none;
+ }
+ &::before{
+ content:"";
+ display:inline-block;
+ width:0;
+ height:0;
+ border-top:4px solid transparent;
+ border-bottom:4px solid transparent;
+ border-inline-start:5px solid currentcolor;
+ transition:transform 0.15s;
+ }
+ }
+ &[open] > summary::before{
+ transform:rotate(90deg);
+ }
+ }
+
+ .nested,
+ .subSignatures > .signaturePropertiesList{
+ padding:4px 0 2px;
+ margin-inline-start:0;
+ gap:4px;
+ }
+
+ .nested{
+ margin-top:4px;
+ }
+ .subSignatures .sigCard,
+ .nested .sigCard{
+ padding:6px 8px;
+ background:var(--sig-card-nested-bg);
+ gap:2px;
+ }
+
+ .subSignatures .signer,
+ .nested .signer{
+ font-size:12px;
+ font-weight:500;
+ }
+}
+
+:root{
+ --dir-factor:1;
+
+ --sidebar-width:200px;
+ --sidebar-transition-duration:200ms;
+ --sidebar-transition-timing-function:ease;
+
+ --toolbar-height:32px;
+ --toolbar-horizontal-padding:1px;
+ --toolbar-vertical-padding:2px;
+ --icon-size:16px;
+
+ --toolbar-icon-opacity:0.7;
+ --doorhanger-icon-opacity:0.9;
+ --doorhanger-height:8px;
+
+ --main-color:light-dark(rgb(12 12 13), rgb(249 249 250));
+ --body-bg-color:light-dark(rgb(212 212 215), rgb(42 42 46));
+ --progressBar-color:light-dark(rgb(10 132 255), rgb(0 96 223));
+ --progressBar-bg-color:light-dark(rgb(221 221 222), rgb(40 40 43));
+ --progressBar-blend-color:light-dark(rgb(116 177 239), rgb(20 68 133));
+ --scrollbar-color:light-dark(auto, rgb(121 121 123));
+ --scrollbar-bg-color:light-dark(auto, rgb(35 35 39));
+ --toolbar-icon-bg-color:light-dark(rgb(0 0 0), rgb(255 255 255));
+ --toolbar-icon-hover-bg-color:light-dark(rgb(0 0 0), rgb(255 255 255));
+
+ --sidebar-narrow-bg-color:light-dark(
+ rgb(212 212 215 / 0.9),
+ rgb(42 42 46 / 0.9)
+ );
+ --sidebar-toolbar-bg-color:light-dark(rgb(245 246 247), rgb(50 50 52));
+ --toolbar-bg-color:light-dark(rgb(249 249 250), rgb(56 56 61));
+ --toolbar-border-color:light-dark(rgb(184 184 184), rgb(12 12 13));
+ --toolbar-box-shadow:0 1px 0 var(--toolbar-border-color);
+ --toolbar-border-bottom:none;
+ --toolbarSidebar-box-shadow:inset calc(-1px * var(--dir-factor)) 0 0 rgb(0 0 0 / 0.25), 0 1px 0 rgb(0 0 0 / 0.15), 0 0 1px rgb(0 0 0 / 0.1);
+ --toolbarSidebar-border-bottom:none;
+ --button-hover-color:var(
+ --button-background-color-toolbar-hover,
+ color-mix(in srgb, currentColor 17%, transparent)
+ );
+ --toggled-btn-color:light-dark(rgb(0 0 0), rgb(255 255 255));
+ --toggled-btn-bg-color:rgb(0 0 0 / 0.3);
+ --toggled-hover-active-btn-color:rgb(0 0 0 / 0.4);
+ --toggled-hover-btn-outline:none;
+ --dropdown-btn-bg-color:light-dark(rgb(215 215 219), rgb(74 74 79));
+ --dropdown-btn-border:none;
+ --separator-color:rgb(0 0 0 / 0.3);
+ --field-color:light-dark(rgb(6 6 6), rgb(250 250 250));
+ --field-bg-color:light-dark(rgb(255 255 255), rgb(64 64 68));
+ --field-border-color:light-dark(rgb(187 187 188), rgb(115 115 115));
+ --doorhanger-bg-color:light-dark(rgb(255 255 255), #42414d);
+ --doorhanger-border-color:light-dark(rgb(12 12 13 / 0.2), rgb(39 39 43));
+ --doorhanger-hover-color:light-dark(rgb(12 12 13), rgb(249 249 250));
+ --doorhanger-separator-color:light-dark(rgb(222 222 222), rgb(92 92 97));
+
+ --loading-icon:url(images/loading.svg);
+ --toolbarButton-editorComment-icon:url(images/comment-editButton.svg);
+ --toolbarButton-editorFreeText-icon:url(images/toolbarButton-editorFreeText.svg);
+ --toolbarButton-editorHighlight-icon:url(images/toolbarButton-editorHighlight.svg);
+ --toolbarButton-editorInk-icon:url(images/toolbarButton-editorInk.svg);
+ --toolbarButton-editorStamp-icon:url(images/toolbarButton-editorStamp.svg);
+ --toolbarButton-editorSignature-icon:url(images/toolbarButton-editorSignature.svg);
+ --toolbarButton-signaturePropertiesVerified-icon:url(images/toolbarButton-signaturePropertiesVerified.svg);
+ --toolbarButton-signaturePropertiesError-icon:url(images/toolbarButton-signaturePropertiesError.svg);
+ --signatureProperties-rowCheck-icon:url(images/signature-properties-row-check.svg);
+ --toolbarButton-menuArrow-icon:url(images/toolbarButton-menuArrow.svg);
+ --toolbarButton-viewsManagerToggle-icon:url(images/toolbarButton-viewsManagerToggle.svg);
+ --toolbarButton-secondaryToolbarToggle-icon:url(images/toolbarButton-secondaryToolbarToggle.svg);
+ --toolbarButton-pageUp-icon:url(images/toolbarButton-pageUp.svg);
+ --toolbarButton-pageDown-icon:url(images/toolbarButton-pageDown.svg);
+ --toolbarButton-zoomOut-icon:url(images/toolbarButton-zoomOut.svg);
+ --toolbarButton-zoomIn-icon:url(images/toolbarButton-zoomIn.svg);
+ --toolbarButton-presentationMode-icon:url(images/toolbarButton-presentationMode.svg);
+ --toolbarButton-print-icon:url(images/toolbarButton-print.svg);
+ --toolbarButton-openFile-icon:url(images/toolbarButton-openFile.svg);
+ --toolbarButton-download-icon:url(images/toolbarButton-download.svg);
+ --toolbarButton-bookmark-icon:url(images/toolbarButton-bookmark.svg);
+ --toolbarButton-viewThumbnail-icon:url(images/toolbarButton-viewThumbnail.svg);
+ --toolbarButton-viewOutline-icon:url(images/toolbarButton-viewOutline.svg);
+ --toolbarButton-viewAttachments-icon:url(images/toolbarButton-viewAttachments.svg);
+ --toolbarButton-viewLayers-icon:url(images/toolbarButton-viewLayers.svg);
+ --toolbarButton-currentOutlineItem-icon:url(images/toolbarButton-currentOutlineItem.svg);
+ --toolbarButton-search-icon:url(images/toolbarButton-search.svg);
+ --findbarButton-previous-icon:url(images/findbarButton-previous.svg);
+ --findbarButton-next-icon:url(images/findbarButton-next.svg);
+ --secondaryToolbarButton-firstPage-icon:url(images/secondaryToolbarButton-firstPage.svg);
+ --secondaryToolbarButton-lastPage-icon:url(images/secondaryToolbarButton-lastPage.svg);
+ --secondaryToolbarButton-rotateCcw-icon:url(images/secondaryToolbarButton-rotateCcw.svg);
+ --secondaryToolbarButton-rotateCw-icon:url(images/secondaryToolbarButton-rotateCw.svg);
+ --secondaryToolbarButton-selectTool-icon:url(images/secondaryToolbarButton-selectTool.svg);
+ --secondaryToolbarButton-handTool-icon:url(images/secondaryToolbarButton-handTool.svg);
+ --secondaryToolbarButton-scrollPage-icon:url(images/secondaryToolbarButton-scrollPage.svg);
+ --secondaryToolbarButton-scrollVertical-icon:url(images/secondaryToolbarButton-scrollVertical.svg);
+ --secondaryToolbarButton-scrollHorizontal-icon:url(images/secondaryToolbarButton-scrollHorizontal.svg);
+ --secondaryToolbarButton-scrollWrapped-icon:url(images/secondaryToolbarButton-scrollWrapped.svg);
+ --secondaryToolbarButton-spreadNone-icon:url(images/secondaryToolbarButton-spreadNone.svg);
+ --secondaryToolbarButton-spreadOdd-icon:url(images/secondaryToolbarButton-spreadOdd.svg);
+ --secondaryToolbarButton-spreadEven-icon:url(images/secondaryToolbarButton-spreadEven.svg);
+ --secondaryToolbarButton-imageAltTextSettings-icon:var(
+ --toolbarButton-editorStamp-icon
+ );
+ --secondaryToolbarButton-documentProperties-icon:url(images/secondaryToolbarButton-documentProperties.svg);
+ --editorParams-stampAddImage-icon:url(images/toolbarButton-zoomIn.svg);
+ --comment-edit-button-icon:url(images/comment-editButton.svg);
+}
+
+:root:dir(rtl){
+ --dir-factor:-1;
+}
+
+@media screen and (forced-colors: active){
+ :root{
+ --button-hover-color:Highlight;
+ --toolbar-icon-opacity:1;
+ --toolbar-icon-bg-color:ButtonText;
+ --toolbar-icon-hover-bg-color:ButtonFace;
+ --toggled-hover-active-btn-color:ButtonText;
+ --toggled-hover-btn-outline:2px solid ButtonBorder;
+ --toolbar-border-color:CanvasText;
+ --toolbar-border-bottom:1px solid var(--toolbar-border-color);
+ --toolbar-box-shadow:none;
+ --toggled-btn-color:HighlightText;
+ --toggled-btn-bg-color:LinkText;
+ --doorhanger-hover-color:ButtonFace;
+ --doorhanger-border-color-whcm:1px solid ButtonText;
+ --doorhanger-triangle-opacity-whcm:0;
+ --dropdown-btn-border:1px solid ButtonText;
+ --field-border-color:ButtonText;
+ --main-color:CanvasText;
+ --separator-color:GrayText;
+ --doorhanger-separator-color:GrayText;
+ --toolbarSidebar-box-shadow:none;
+ --toolbarSidebar-border-bottom:1px solid var(--toolbar-border-color);
+ }
+}
+
+@media screen and (prefers-reduced-motion: reduce){
+ :root{
+ --sidebar-transition-duration:0;
+ }
+}
+
+@keyframes progressIndeterminate{
+ 0%{
+ transform:translateX(calc(-142px * var(--dir-factor)));
+ }
+
+ 100%{
+ transform:translateX(0);
+ }
+}
+
+html{
+ &[data-toolbar-density="compact"]{
+ --toolbar-height:30px;
+ }
+ &[data-toolbar-density="touch"]{
+ --toolbar-height:44px;
+ }
+}
+
+html,
+body{
+ height:100%;
+ width:100%;
+}
+
+body{
+ margin:0;
+ background-color:var(--body-bg-color);
+ scrollbar-color:var(--scrollbar-color) var(--scrollbar-bg-color);
+
+ &.wait::before{
+ content:"";
+ position:fixed;
+ width:100%;
+ height:100%;
+ z-index:100000;
+ cursor:wait;
+ }
+}
+.visuallyHidden{
+ position:absolute;
+ top:0;
+ left:0;
+ border:0;
+ margin:0;
+ padding:0;
+ width:0;
+ height:0;
+ overflow:hidden;
+ white-space:nowrap;
+ font-size:0;
+}
+
+.hidden,
+[hidden]{
+ display:none !important;
+}
+
+#viewerContainer.pdfPresentationMode:fullscreen{
+ top:0;
+ background-color:rgb(0 0 0);
+ width:100%;
+ height:100%;
+ overflow:hidden;
+ cursor:none;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+}
+
+.pdfPresentationMode:fullscreen
+ section:not([data-internal-link], .mediaAnnotation){
+ pointer-events:none;
+}
+
+.pdfPresentationMode:fullscreen .textLayer span{
+ cursor:none;
+}
+
+.pdfPresentationMode.pdfPresentationModeControls > *,
+.pdfPresentationMode.pdfPresentationModeControls .textLayer span{
+ cursor:default;
+}
+
+#outerContainer{
+ width:100%;
+ height:100%;
+ position:relative;
+ margin:0;
+}
+
+#mainContainer{
+ position:absolute;
+ inset:0;
+ min-width:350px;
+ margin:0;
+ display:flex;
+ flex-direction:column;
+}
+
+#sidebarContent{
+ inset-block:var(--toolbar-height) 0;
+ inset-inline-start:0;
+ overflow:auto;
+ position:absolute;
+ width:100%;
+ box-shadow:inset calc(-1px * var(--dir-factor)) 0 0 rgb(0 0 0 / 0.25);
+}
+
+#viewerContainer{
+ overflow:auto;
+ position:absolute;
+ inset:var(--toolbar-height) 0 0;
+ outline:none;
+ z-index:0;
+}
+
+#viewerContainer:not(.pdfPresentationMode){
+ transition-duration:var(--sidebar-transition-duration);
+ transition-timing-function:var(--sidebar-transition-timing-function);
+}
+
+#sidebarContainer :is(input, button, select){
+ font:message-box;
+}
+
+.toolbar{
+ z-index:2;
+}
+
+#toolbarSidebar{
+ width:100%;
+ height:var(--toolbar-height);
+ background-color:var(--sidebar-toolbar-bg-color);
+ box-shadow:var(--toolbarSidebar-box-shadow);
+ border-bottom:var(--toolbarSidebar-border-bottom);
+ padding:var(--toolbar-vertical-padding) var(--toolbar-horizontal-padding);
+ justify-content:space-between;
+
+ #toolbarSidebarLeft{
+ width:auto;
+ height:100%;
+
+ #viewThumbnail::before{
+ -webkit-mask-image:var(--toolbarButton-viewThumbnail-icon);
+ mask-image:var(--toolbarButton-viewThumbnail-icon);
+ }
+
+ #viewOutline::before{
+ -webkit-mask-image:var(--toolbarButton-viewOutline-icon);
+ mask-image:var(--toolbarButton-viewOutline-icon);
+ transform:scaleX(var(--dir-factor));
+ }
+
+ #viewAttachments::before{
+ -webkit-mask-image:var(--toolbarButton-viewAttachments-icon);
+ mask-image:var(--toolbarButton-viewAttachments-icon);
+ }
+
+ #viewLayers::before{
+ -webkit-mask-image:var(--toolbarButton-viewLayers-icon);
+ mask-image:var(--toolbarButton-viewLayers-icon);
+ }
+ }
+
+ #toolbarSidebarRight{
+ width:auto;
+ height:100%;
+ padding-inline-end:2px;
+ }
+}
+
+.doorHanger,
+.doorHangerRight{
+ border-radius:2px;
+ box-shadow:0 1px 5px var(--doorhanger-border-color), 0 0 0 1px var(--doorhanger-border-color);
+ border:var(--doorhanger-border-color-whcm);
+ background-color:var(--doorhanger-bg-color);
+ inset-block-start:calc(100% + var(--doorhanger-height) - 2px);
+
+ &::after,
+ &::before{
+ bottom:100%;
+ border-style:solid;
+ border-color:transparent;
+ content:"";
+ height:0;
+ width:0;
+ position:absolute;
+ pointer-events:none;
+ opacity:var(--doorhanger-triangle-opacity-whcm);
+ }
+
+ &::before{
+ border-width:calc(var(--doorhanger-height) + 2px);
+ border-bottom-color:var(--doorhanger-border-color);
+ }
+
+ &::after{
+ border-width:var(--doorhanger-height);
+ }
+}
+
+.doorHangerRight{
+ inset-inline-end:calc(50% - var(--doorhanger-height) - 1px);
+
+ &::before{
+ inset-inline-end:-1px;
+ }
+
+ &::after{
+ border-bottom-color:var(--doorhanger-bg-color);
+ inset-inline-end:1px;
+ }
+}
+
+.doorHanger{
+ inset-inline-start:calc(50% - var(--doorhanger-height) - 1px);
+
+ &::before{
+ inset-inline-start:-1px;
+ }
+
+ &::after{
+ border-bottom-color:var(--toolbar-bg-color);
+ inset-inline-start:1px;
+ }
+
+}
+
+.splitToolbarButtonSeparator{
+ float:inline-start;
+ width:0;
+ height:62%;
+ border-left:1px solid var(--separator-color);
+ border-right:none;
+}
+
+#viewsManagerToggleButton::before{
+ -webkit-mask-image:var(--toolbarButton-viewsManagerToggle-icon);
+ mask-image:var(--toolbarButton-viewsManagerToggle-icon);
+ transform:scaleX(var(--dir-factor));
+}
+
+#secondaryToolbarToggleButton::before{
+ -webkit-mask-image:var(--toolbarButton-secondaryToolbarToggle-icon);
+ mask-image:var(--toolbarButton-secondaryToolbarToggle-icon);
+ transform:scaleX(var(--dir-factor));
+}
+
+#previous::before{
+ -webkit-mask-image:var(--toolbarButton-pageUp-icon);
+ mask-image:var(--toolbarButton-pageUp-icon);
+}
+
+#next::before{
+ -webkit-mask-image:var(--toolbarButton-pageDown-icon);
+ mask-image:var(--toolbarButton-pageDown-icon);
+}
+
+#zoomOutButton::before{
+ -webkit-mask-image:var(--toolbarButton-zoomOut-icon);
+ mask-image:var(--toolbarButton-zoomOut-icon);
+}
+
+#zoomInButton::before{
+ -webkit-mask-image:var(--toolbarButton-zoomIn-icon);
+ mask-image:var(--toolbarButton-zoomIn-icon);
+}
+
+#editorCommentButton::before{
+ -webkit-mask-image:var(--toolbarButton-editorComment-icon);
+ mask-image:var(--toolbarButton-editorComment-icon);
+ transform:scaleX(var(--dir-factor));
+}
+
+#editorFreeTextButton::before{
+ -webkit-mask-image:var(--toolbarButton-editorFreeText-icon);
+ mask-image:var(--toolbarButton-editorFreeText-icon);
+}
+
+#editorHighlightButton::before{
+ -webkit-mask-image:var(--toolbarButton-editorHighlight-icon);
+ mask-image:var(--toolbarButton-editorHighlight-icon);
+}
+
+#editorInkButton::before{
+ -webkit-mask-image:var(--toolbarButton-editorInk-icon);
+ mask-image:var(--toolbarButton-editorInk-icon);
+}
+
+#editorStampButton::before{
+ -webkit-mask-image:var(--toolbarButton-editorStamp-icon);
+ mask-image:var(--toolbarButton-editorStamp-icon);
+}
+
+#editorSignatureButton::before{
+ -webkit-mask-image:var(--toolbarButton-editorSignature-icon);
+ mask-image:var(--toolbarButton-editorSignature-icon);
+}
+
+#printButton::before{
+ -webkit-mask-image:var(--toolbarButton-print-icon);
+ mask-image:var(--toolbarButton-print-icon);
+}
+
+#downloadButton::before{
+ -webkit-mask-image:var(--toolbarButton-download-icon);
+ mask-image:var(--toolbarButton-download-icon);
+}
+
+#currentOutlineItem::before{
+ -webkit-mask-image:var(--toolbarButton-currentOutlineItem-icon);
+ mask-image:var(--toolbarButton-currentOutlineItem-icon);
+ transform:scaleX(var(--dir-factor));
+}
+
+#viewFindButton::before{
+ -webkit-mask-image:var(--toolbarButton-search-icon);
+ mask-image:var(--toolbarButton-search-icon);
+}
+
+.pdfSidebarNotification::after{
+ position:absolute;
+ display:inline-block;
+ top:2px;
+ inset-inline-end:2px;
+ content:"";
+ background-color:rgb(112 219 85);
+ height:9px;
+ width:9px;
+ border-radius:50%;
+
+}
+
+.verticalToolbarSeparator{
+ display:block;
+ margin-inline:2px;
+ width:0;
+ height:80%;
+ border-left:1px solid var(--separator-color);
+ border-right:none;
+ box-sizing:border-box;
+}
+
+.horizontalToolbarSeparator{
+ display:block;
+ margin:6px 0;
+ border-top:1px solid var(--doorhanger-separator-color);
+ border-bottom:none;
+ height:0;
+ width:100%;
+}
+
+.toggleButton{
+ display:inline;
+
+ &:has(> input:checked){
+ color:var(--toggled-btn-color);
+ background-color:var(--toggled-btn-bg-color);
+ }
+
+ &:is(:hover, :has(> input:focus-visible)){
+ color:var(--toggled-btn-color);
+ background-color:var(--button-hover-color);
+ }
+
+ & > input{
+ position:absolute;
+ top:50%;
+ left:50%;
+ opacity:0;
+ width:0;
+ height:0;
+ }
+}
+
+.toolbarField{
+ padding:4px 7px;
+ margin:3px 0;
+ border-radius:2px;
+ background-color:var(--field-bg-color);
+ background-clip:padding-box;
+ border:1px solid var(--field-border-color);
+ box-shadow:none;
+ color:var(--field-color);
+ font-size:12px;
+ line-height:16px;
+ outline:none;
+
+ &:focus{
+ border-color:#0a84ff;
+ }
+}
+
+#pageNumber{
+ -moz-appearance:textfield;
+ text-align:end;
+ width:40px;
+ background-size:0 0;
+ transition-property:none;
+
+ &::-webkit-inner-spin-button{
+ -webkit-appearance:none;
+ }
+
+ .loadingInput:has(> &.loading)::after{
+ display:inline;
+ visibility:visible;
+
+ transition-property:visibility;
+ transition-delay:var(--loading-icon-delay);
+ }
+}
+
+.loadingInput{
+ position:relative;
+
+ &::after{
+ position:absolute;
+ visibility:hidden;
+ display:none;
+ width:var(--icon-size);
+ height:var(--icon-size);
+
+ content:"";
+ background-color:var(--toolbar-icon-bg-color);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ -webkit-mask-image:var(--loading-icon);
+ mask-image:var(--loading-icon);
+ }
+
+ &.start::after{
+ inset-inline-start:4px;
+ }
+
+ &.end::after{
+ inset-inline-end:4px;
+ }
+}
+#outlineOptionsContainer{
+ display:none;
+
+ #sidebarContainer:has(#outlineView:not(.hidden)) &{
+ display:inline flex;
+ }
+}
+
+dialog{
+ margin:auto;
+ padding:15px;
+ border-spacing:4px;
+ color:var(--main-color);
+ font:message-box;
+ font-size:12px;
+ line-height:14px;
+ background-color:var(--doorhanger-bg-color);
+ border:1px solid rgb(0 0 0 / 0.5);
+ border-radius:var(--border-radius-medium, 4px);
+ box-shadow:0 1px 4px rgb(0 0 0 / 0.3);
+}
+
+dialog::backdrop{
+ background-color:rgb(0 0 0 / 0.2);
+}
+
+dialog > .row{
+ display:table-row;
+}
+
+dialog > .row > *{
+ display:table-cell;
+}
+
+dialog .toolbarField{
+ margin:5px 0;
+}
+
+dialog .separator{
+ display:block;
+ margin:4px 0;
+ height:0;
+ width:100%;
+ border-top:1px solid var(--separator-color);
+ border-bottom:none;
+}
+
+dialog .buttonRow{
+ display:flex;
+ justify-content:center;
+ align-items:center;
+ gap:8px;
+}
+
+dialog :link{
+ color:rgb(255 255 255);
+}
+
+#passwordDialog{
+ text-align:center;
+}
+
+#passwordDialog .toolbarField{
+ width:200px;
+}
+
+#documentPropertiesDialog{
+ text-align:left;
+}
+
+#documentPropertiesDialog .row > *{
+ min-width:100px;
+ text-align:start;
+}
+
+#documentPropertiesDialog .row > span{
+ width:125px;
+ word-wrap:break-word;
+}
+
+#documentPropertiesDialog .row > p{
+ max-width:225px;
+ word-wrap:break-word;
+}
+
+#documentPropertiesDialog .buttonRow{
+ margin-top:10px;
+}
+
+#printServiceDialog{
+ min-width:200px;
+}
+
+.grab-to-pan-grab{
+ cursor:grab !important;
+}
+
+.grab-to-pan-grab
+ *:not(input):not(textarea):not(button):not(select):not(:link){
+ cursor:inherit !important;
+}
+
+.grab-to-pan-grab:active,
+.grab-to-pan-grabbing{
+ cursor:grabbing !important;
+}
+
+.grab-to-pan-grabbing{
+ position:fixed;
+ background:rgb(0 0 0 / 0);
+ display:block;
+ inset:0;
+ overflow:hidden;
+ z-index:50000;
+}
+
+.toolbarButton{
+ height:100%;
+ aspect-ratio:1;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ background:none;
+ border:none;
+ color:var(--main-color);
+ outline:none;
+ border-radius:2px;
+ box-sizing:border-box;
+ font:message-box;
+ flex:none;
+ position:relative;
+ padding:0;
+
+ > span{
+ display:inline-block;
+ width:0;
+ height:0;
+ overflow:hidden;
+ }
+
+ &::before{
+ opacity:var(--toolbar-icon-opacity);
+ display:inline-block;
+ width:var(--icon-size);
+ height:var(--icon-size);
+ content:"";
+ background-color:var(--toolbar-icon-bg-color);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+ -webkit-mask-position:center;
+ mask-position:center;
+ }
+
+ &.toggled{
+ background-color:var(--toggled-btn-bg-color);
+ color:var(--toggled-btn-color);
+
+ &::before{
+ background-color:var(--toggled-btn-color);
+ }
+
+ &:hover{
+ outline:var(--toggled-hover-btn-outline) !important;
+
+ &:active{
+ background-color:var(--toggled-hover-active-btn-color);
+ }
+ }
+ }
+
+ &:is(:hover, :focus-visible){
+ background-color:var(--button-hover-color);
+
+ &::before{
+ background-color:var(--toolbar-icon-hover-bg-color);
+ }
+ }
+
+ &:is([disabled="disabled"], [disabled]){
+ opacity:0.5;
+ pointer-events:none;
+ }
+
+ &.labeled{
+ width:100%;
+ min-height:var(--menuitem-height);
+ justify-content:flex-start;
+ gap:8px;
+ padding-inline-start:12px;
+ aspect-ratio:unset;
+ text-align:start;
+ white-space:normal;
+ cursor:default;
+
+ &:is(a){
+ text-decoration:none;
+
+ &[href="#"]{
+ opacity:0.5;
+ pointer-events:none;
+ }
+ }
+
+ &::before{
+ opacity:var(--doorhanger-icon-opacity);
+ }
+
+ &:is(:hover, :focus-visible){
+ color:var(--doorhanger-hover-color);
+ }
+
+ > span{
+ display:inline-block;
+ width:-moz-max-content;
+ width:max-content;
+ height:auto;
+ }
+ }
+}
+
+.toolbarButtonWithContainer{
+ height:100%;
+ aspect-ratio:1;
+ display:inline-block;
+ position:relative;
+ flex:none;
+
+ > .toolbarButton{
+ width:100%;
+ height:100%;
+ }
+
+ .menu{
+ padding-block:5px;
+ }
+
+ .menuContainer{
+ height:auto;
+ max-height:calc(
+ var(--viewer-container-height) - var(--toolbar-height) -
+ var(--doorhanger-height)
+ );
+ display:flex;
+ flex-direction:column;
+ box-sizing:border-box;
+ overflow-y:auto;
+ }
+
+ .editorParamsToolbar{
+ --editor-toolbar-min-width:220px;
+
+ height:auto;
+ min-width:var(--editor-toolbar-min-width);
+ width:-moz-max-content;
+ width:max-content;
+ position:absolute;
+ z-index:30000;
+ cursor:default;
+
+ :is(#editorStampAddImage, #editorSignatureAddSignature)::before{
+ -webkit-mask-image:var(--editorParams-stampAddImage-icon);
+ mask-image:var(--editorParams-stampAddImage-icon);
+ }
+
+ .editorParamsLabel{
+ flex:none;
+ font:menu;
+ font-size:13px;
+ font-style:normal;
+ font-weight:400;
+ line-height:150%;
+ width:-moz-fit-content;
+ width:fit-content;
+ inset-inline-start:0;
+ color:var(--main-color);
+ }
+
+ button:is(:hover, :focus-visible) .editorParamsLabel{
+ color:var(--doorhanger-hover-color);
+ }
+
+ .editorParamsToolbarContainer{
+ width:100%;
+ height:auto;
+ display:flex;
+ flex-direction:column;
+ box-sizing:border-box;
+ padding-inline:10px;
+ padding-block:10px;
+
+ > .editorParamsSetter{
+ min-height:26px;
+ display:flex;
+ align-items:center;
+ justify-content:space-between;
+ }
+
+ .editorParamsColor{
+ width:32px;
+ height:32px;
+ flex:none;
+ padding:0;
+ }
+
+ .editorParamsSlider{
+ background-color:transparent;
+ width:90px;
+ flex:0 1 0;
+ font:message-box;
+
+ &::-moz-range-progress{
+ background-color:black;
+ }
+
+ &::-webkit-slider-runnable-track,
+ &::-moz-range-track{
+ background-color:black;
+ }
+
+ &::-webkit-slider-thumb,
+ &::-moz-range-thumb{
+ background-color:white;
+ }
+ }
+ }
+ }
+}
+
+#secondaryToolbar{
+ height:auto;
+ width:220px;
+ position:absolute;
+ z-index:30000;
+ cursor:default;
+ min-height:26px;
+ max-height:calc(var(--viewer-container-height) - 40px);
+
+ #secondaryToolbarButtonContainer{
+ #secondaryOpenFile::before{
+ -webkit-mask-image:var(--toolbarButton-openFile-icon);
+ mask-image:var(--toolbarButton-openFile-icon);
+ }
+
+ #secondaryPrint::before{
+ -webkit-mask-image:var(--toolbarButton-print-icon);
+ mask-image:var(--toolbarButton-print-icon);
+ }
+
+ #secondaryDownload::before{
+ -webkit-mask-image:var(--toolbarButton-download-icon);
+ mask-image:var(--toolbarButton-download-icon);
+ }
+
+ #presentationMode::before{
+ -webkit-mask-image:var(--toolbarButton-presentationMode-icon);
+ mask-image:var(--toolbarButton-presentationMode-icon);
+ }
+
+ #viewBookmark::before{
+ -webkit-mask-image:var(--toolbarButton-bookmark-icon);
+ mask-image:var(--toolbarButton-bookmark-icon);
+ }
+
+ #firstPage::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-firstPage-icon);
+ mask-image:var(--secondaryToolbarButton-firstPage-icon);
+ }
+
+ #lastPage::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-lastPage-icon);
+ mask-image:var(--secondaryToolbarButton-lastPage-icon);
+ }
+
+ #pageRotateCcw::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-rotateCcw-icon);
+ mask-image:var(--secondaryToolbarButton-rotateCcw-icon);
+ }
+
+ #pageRotateCw::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-rotateCw-icon);
+ mask-image:var(--secondaryToolbarButton-rotateCw-icon);
+ }
+
+ #cursorSelectTool::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-selectTool-icon);
+ mask-image:var(--secondaryToolbarButton-selectTool-icon);
+ }
+
+ #cursorHandTool::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-handTool-icon);
+ mask-image:var(--secondaryToolbarButton-handTool-icon);
+ }
+
+ #scrollPage::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-scrollPage-icon);
+ mask-image:var(--secondaryToolbarButton-scrollPage-icon);
+ }
+
+ #scrollVertical::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-scrollVertical-icon);
+ mask-image:var(--secondaryToolbarButton-scrollVertical-icon);
+ }
+
+ #scrollHorizontal::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-scrollHorizontal-icon);
+ mask-image:var(--secondaryToolbarButton-scrollHorizontal-icon);
+ }
+
+ #scrollWrapped::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-scrollWrapped-icon);
+ mask-image:var(--secondaryToolbarButton-scrollWrapped-icon);
+ }
+
+ #spreadNone::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-spreadNone-icon);
+ mask-image:var(--secondaryToolbarButton-spreadNone-icon);
+ }
+
+ #spreadOdd::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-spreadOdd-icon);
+ mask-image:var(--secondaryToolbarButton-spreadOdd-icon);
+ }
+
+ #spreadEven::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-spreadEven-icon);
+ mask-image:var(--secondaryToolbarButton-spreadEven-icon);
+ }
+
+ #imageAltTextSettings::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-imageAltTextSettings-icon);
+ mask-image:var(--secondaryToolbarButton-imageAltTextSettings-icon);
+ }
+
+ #documentProperties::before{
+ -webkit-mask-image:var(--secondaryToolbarButton-documentProperties-icon);
+ mask-image:var(--secondaryToolbarButton-documentProperties-icon);
+ }
+ }
+}
+
+#findbar{
+ --input-horizontal-padding:4px;
+ --findbar-padding:2px;
+
+ width:-moz-max-content;
+
+ width:max-content;
+ max-width:90vw;
+ min-height:var(--toolbar-height);
+ height:auto;
+ position:absolute;
+ z-index:30000;
+ cursor:default;
+ padding:0;
+ min-width:300px;
+ background-color:var(--toolbar-bg-color);
+ box-sizing:border-box;
+ flex-wrap:wrap;
+ justify-content:flex-start;
+
+ > *{
+ height:var(--toolbar-height);
+ padding:var(--findbar-padding);
+ }
+
+ #findInputContainer{
+ margin-inline-start:2px;
+
+ #findPreviousButton::before{
+ -webkit-mask-image:var(--findbarButton-previous-icon);
+ mask-image:var(--findbarButton-previous-icon);
+ }
+
+ #findNextButton::before{
+ -webkit-mask-image:var(--findbarButton-next-icon);
+ mask-image:var(--findbarButton-next-icon);
+ }
+
+ #findInput{
+ width:200px;
+ padding:5px var(--input-horizontal-padding);
+ &::-moz-placeholder{
+ font-style:normal;
+ }
+ &::placeholder{
+ font-style:normal;
+ }
+
+ .loadingInput:has(> &[data-status="pending"])::after{
+ display:inline;
+ visibility:visible;
+ inset-inline-end:calc(var(--input-horizontal-padding) + 1px);
+ }
+
+ &[data-status="notFound"]{
+ background-color:rgb(255 102 102);
+
+ }
+ }
+ }
+
+ #findbarMessageContainer{
+ display:none;
+ gap:4px;
+
+ &:has(> :is(#findResultsCount, #findMsg):not(:empty)){
+ display:inline flex;
+ }
+
+ #findResultsCount{
+ background-color:rgb(217 217 217);
+ color:rgb(82 82 82);
+ padding-block:4px;
+
+ &:empty{
+ display:none;
+ }
+ }
+
+ #findMsg{
+ &[data-status="notFound"]{
+ font-weight:bold;
+ }
+
+ &:empty{
+ display:none;
+ }
+ }
+ }
+
+ &.wrapContainers{
+ flex-direction:column;
+ align-items:flex-start;
+ height:-moz-max-content;
+ height:max-content;
+
+ .toolbarLabel{
+ margin:0 4px;
+ }
+
+ #findbarMessageContainer{
+ flex-wrap:wrap;
+ flex-flow:column nowrap;
+ align-items:flex-start;
+ height:-moz-max-content;
+ height:max-content;
+
+ #findResultsCount{
+ height:calc(var(--toolbar-height) - 2 * var(--findbar-padding));
+ }
+
+ #findMsg{
+ min-height:var(--toolbar-height);
+ }
+ }
+ }
+}
+
+@page{
+ margin:0;
+}
+
+#printContainer{
+ display:none;
+}
+
+@media print{
+ body{
+ background:rgb(0 0 0 / 0) none;
+ }
+
+ body[data-pdfjsprinting] #outerContainer{
+ display:none;
+ }
+
+ body[data-pdfjsprinting] #printContainer{
+ display:block;
+ }
+
+ #printContainer{
+ height:100%;
+ }
+ #printContainer > .printedPage{
+ page-break-after:always;
+ page-break-inside:avoid;
+ height:100%;
+ width:100%;
+
+ display:flex;
+ flex-direction:column;
+ justify-content:center;
+ align-items:center;
+ }
+
+ #printContainer > .xfaPrintedPage .xfaPage{
+ position:absolute;
+ }
+
+ #printContainer > .xfaPrintedPage{
+ page-break-after:always;
+ page-break-inside:avoid;
+ width:100%;
+ height:100%;
+ position:relative;
+ }
+
+ #printContainer > .printedPage :is(canvas, img){
+ max-width:100%;
+ max-height:100%;
+
+ direction:ltr;
+ display:block;
+ }
+}
+
+.visibleMediumView{
+ display:none !important;
+}
+
+.toolbarLabel{
+ width:-moz-max-content;
+ width:max-content;
+ min-width:16px;
+ height:100%;
+ padding-inline:4px;
+ margin:2px;
+ border-radius:2px;
+
+ color:var(--main-color);
+ font-size:12px;
+ line-height:14px;
+ text-align:left;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ cursor:default;
+ box-sizing:border-box;
+
+ display:inline flex;
+ flex-direction:column;
+ align-items:center;
+ justify-content:center;
+
+ > label{
+ width:100%;
+ }
+}
+
+.toolbarHorizontalGroup{
+ height:100%;
+ display:inline flex;
+ flex-direction:row;
+ align-items:center;
+ justify-content:space-between;
+ gap:1px;
+ box-sizing:border-box;
+
+}
+
+.dropdownToolbarButton{
+ display:inline flex;
+ flex-direction:row;
+ align-items:center;
+ justify-content:center;
+ position:relative;
+
+ width:-moz-fit-content;
+
+ width:fit-content;
+ min-width:140px;
+ padding:0;
+ background-color:var(--dropdown-btn-bg-color);
+ border:var(--dropdown-btn-border);
+ border-radius:2px;
+ color:var(--main-color);
+ font-size:12px;
+ line-height:14px;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ user-select:none;
+ cursor:default;
+ box-sizing:border-box;
+ outline:none;
+
+ &:hover{
+ background-color:var(--button-hover-color);
+ }
+
+ > select{
+ -webkit-appearance:none;
+ -moz-appearance:none;
+ appearance:none;
+ width:inherit;
+ min-width:inherit;
+ height:28px;
+ font:message-box;
+ font-size:12px;
+ color:var(--main-color);
+ margin:0;
+ padding-block:1px 2px;
+ padding-inline:6px 38px;
+ border:none;
+ outline:none;
+ background-color:var(--dropdown-btn-bg-color);
+
+ > option{
+ background:var(--doorhanger-bg-color);
+ color:var(--main-color);
+ }
+
+ &:is(:hover, :focus-visible){
+ background-color:var(--button-hover-color);
+ color:var(--toggled-btn-color);
+ }
+ }
+
+ &::after{
+ position:absolute;
+ display:inline;
+ width:var(--icon-size);
+ height:var(--icon-size);
+
+ content:"";
+ background-color:var(--toolbar-icon-bg-color);
+ -webkit-mask-size:cover;
+ mask-size:cover;
+
+ inset-inline-end:4px;
+ pointer-events:none;
+ -webkit-mask-image:var(--toolbarButton-menuArrow-icon);
+ mask-image:var(--toolbarButton-menuArrow-icon);
+ }
+
+ &:is(:hover, :focus-visible, :active)::after{
+ background-color:var(--toolbar-icon-hover-bg-color);
+ }
+}
+
+#toolbarContainer{
+ --menuitem-height:calc(var(--toolbar-height) - 6px);
+
+ width:100%;
+ height:var(--toolbar-height);
+ padding:var(--toolbar-vertical-padding) var(--toolbar-horizontal-padding);
+ position:relative;
+ box-sizing:border-box;
+ font:message-box;
+ background-color:var(--toolbar-bg-color);
+ box-shadow:var(--toolbar-box-shadow);
+ border-bottom:var(--toolbar-border-bottom);
+
+ #toolbarViewer{
+ width:100%;
+ height:100%;
+ justify-content:space-between;
+
+ > *{
+ flex:none;
+ }
+
+ input{
+ font:message-box;
+ }
+
+ .toolbarButtonSpacer{
+ width:30px;
+ display:block;
+ height:1px;
+ }
+
+ #toolbarViewerLeft{
+ margin-inline-start:8px;
+
+ #numPages.toolbarLabel{
+ padding-inline-start:3px;
+ flex:none;
+ }
+ }
+ }
+
+ #loadingBar{
+ --progressBar-percent:0%;
+ --progressBar-end-offset:0;
+
+ position:absolute;
+ top:var(--toolbar-height);
+ inset-inline:0 var(--progressBar-end-offset);
+ height:4px;
+ background-color:var(--progressBar-bg-color);
+ border-bottom:1px solid var(--toolbar-border-color);
+ transition-property:inset-inline-start;
+ transition-duration:var(--sidebar-transition-duration);
+ transition-timing-function:var(--sidebar-transition-timing-function);
+
+ .progress{
+ position:absolute;
+ top:0;
+ inset-inline-start:0;
+ width:100%;
+ transform:scaleX(var(--progressBar-percent));
+ transform-origin:calc(50% - 50% * var(--dir-factor)) 0;
+ height:100%;
+ background-color:var(--progressBar-color);
+ overflow:hidden;
+ transition:transform 200ms;
+ }
+
+ &.indeterminate .progress{
+ transform:none;
+ background-color:var(--progressBar-bg-color);
+ transition:none;
+
+ .glimmer{
+ position:absolute;
+ top:0;
+ inset-inline-start:0;
+ height:100%;
+ width:calc(100% + 150px);
+ background:repeating-linear-gradient(
+ 135deg,
+ var(--progressBar-blend-color) 0,
+ var(--progressBar-bg-color) 5px,
+ var(--progressBar-bg-color) 45px,
+ var(--progressBar-color) 55px,
+ var(--progressBar-color) 95px,
+ var(--progressBar-blend-color) 100px
+ );
+ animation:progressIndeterminate 1s linear infinite;
+ }
+ }
+ }
+}
+
+@media all and (max-width: 840px){
+ #sidebarContainer{
+ background-color:var(--sidebar-narrow-bg-color);
+ }
+ #outerContainer.viewsManagerOpen #viewerContainer{
+ inset-inline-start:0 !important;
+ }
+}
+
+@media all and (max-width: 750px){
+ #outerContainer .hiddenMediumView{
+ display:none !important;
+ }
+ #outerContainer .visibleMediumView:not(.hidden, [hidden]){
+ display:inline-block !important;
+ }
+}
+
+@media all and (max-width: 690px){
+ .hiddenSmallView,
+ .hiddenSmallView *{
+ display:none !important;
+ }
+
+ #toolbarContainer #toolbarViewer .toolbarButtonSpacer{
+ width:0;
+ }
+}
+
+@media all and (max-width: 560px){
+ #scaleSelectContainer{
+ display:none;
+ }
+}
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.html b/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.html
new file mode 100644
index 0000000..034c5f2
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.html
@@ -0,0 +1,1238 @@
+
+
+
+
+
+
+
+ PDF.js viewer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.mjs b/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.mjs
new file mode 100644
index 0000000..048ec80
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/viewer.mjs
@@ -0,0 +1,26654 @@
+/**
+ * @licstart The following is the entire license notice for the
+ * JavaScript code in this page
+ *
+ * Copyright 2024 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @licend The above is the entire license notice for the
+ * JavaScript code in this page
+ */
+
+/**
+ * pdfjsVersion = 6.3.289
+ * pdfjsBuild = 1c8020a7d
+ */
+/******/ var __webpack_modules__ = ({
+
+/***/ 9306
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isCallable = __webpack_require__(4901);
+var tryToString = __webpack_require__(6823);
+
+var $TypeError = TypeError;
+
+// `Assert: IsCallable(argument) is true`
+module.exports = function (argument) {
+ if (isCallable(argument)) return argument;
+ throw new $TypeError(tryToString(argument) + ' is not a function');
+};
+
+
+/***/ },
+
+/***/ 3506
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isPossiblePrototype = __webpack_require__(3925);
+
+var $String = String;
+var $TypeError = TypeError;
+
+module.exports = function (argument) {
+ if (isPossiblePrototype(argument)) return argument;
+ throw new $TypeError("Can't set " + $String(argument) + ' as a prototype');
+};
+
+
+/***/ },
+
+/***/ 7080
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var has = (__webpack_require__(4402).has);
+
+// Perform ? RequireInternalSlot(M, [[SetData]])
+module.exports = function (it) {
+ has(it);
+ return it;
+};
+
+
+/***/ },
+
+/***/ 3463
+(module) {
+
+
+var $TypeError = TypeError;
+
+module.exports = function (argument) {
+ if (typeof argument == 'string') return argument;
+ throw new $TypeError('Argument is not a string');
+};
+
+
+/***/ },
+
+/***/ 4328
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var WeakMapHelpers = __webpack_require__(4995);
+
+var weakmap = new WeakMapHelpers.WeakMap();
+var set = WeakMapHelpers.set;
+var remove = WeakMapHelpers.remove;
+
+module.exports = function (key) {
+ set(weakmap, key, 1);
+ remove(weakmap, key);
+ return key;
+};
+
+
+/***/ },
+
+/***/ 6557
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var has = (__webpack_require__(4995).has);
+
+// Perform ? RequireInternalSlot(M, [[WeakMapData]])
+module.exports = function (it) {
+ has(it);
+ return it;
+};
+
+
+/***/ },
+
+/***/ 6469
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var wellKnownSymbol = __webpack_require__(8227);
+var create = __webpack_require__(2360);
+var defineProperty = (__webpack_require__(4913).f);
+
+var UNSCOPABLES = wellKnownSymbol('unscopables');
+var ArrayPrototype = Array.prototype;
+
+// Array.prototype[@@unscopables]
+// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
+if (ArrayPrototype[UNSCOPABLES] === undefined) {
+ defineProperty(ArrayPrototype, UNSCOPABLES, {
+ configurable: true,
+ value: create(null)
+ });
+}
+
+// add a key to Array.prototype[@@unscopables]
+module.exports = function (key) {
+ ArrayPrototype[UNSCOPABLES][key] = true;
+};
+
+
+/***/ },
+
+/***/ 679
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isPrototypeOf = __webpack_require__(1625);
+
+var $TypeError = TypeError;
+
+module.exports = function (it, Prototype) {
+ if (isPrototypeOf(Prototype, it)) return it;
+ throw new $TypeError('Incorrect invocation');
+};
+
+
+/***/ },
+
+/***/ 8551
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isObject = __webpack_require__(34);
+
+var $String = String;
+var $TypeError = TypeError;
+
+// `Assert: Type(argument) is Object`
+module.exports = function (argument) {
+ if (isObject(argument)) return argument;
+ throw new $TypeError($String(argument) + ' is not an object');
+};
+
+
+/***/ },
+
+/***/ 7811
+(module) {
+
+
+// eslint-disable-next-line es/no-typed-arrays -- safe
+module.exports = typeof ArrayBuffer != 'undefined' && typeof DataView != 'undefined';
+
+
+/***/ },
+
+/***/ 4644
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var NATIVE_ARRAY_BUFFER = __webpack_require__(7811);
+var DESCRIPTORS = __webpack_require__(3724);
+var globalThis = __webpack_require__(4576);
+var isCallable = __webpack_require__(4901);
+var isObject = __webpack_require__(34);
+var hasOwn = __webpack_require__(9297);
+var classof = __webpack_require__(6955);
+var tryToString = __webpack_require__(6823);
+var createNonEnumerableProperty = __webpack_require__(6699);
+var defineBuiltIn = __webpack_require__(6840);
+var defineBuiltInAccessor = __webpack_require__(2106);
+var isPrototypeOf = __webpack_require__(1625);
+var getPrototypeOf = __webpack_require__(2787);
+var setPrototypeOf = __webpack_require__(2967);
+var wellKnownSymbol = __webpack_require__(8227);
+var uid = __webpack_require__(3392);
+var InternalStateModule = __webpack_require__(1181);
+
+var enforceInternalState = InternalStateModule.enforce;
+var getInternalState = InternalStateModule.get;
+var Int8Array = globalThis.Int8Array;
+var Int8ArrayPrototype = Int8Array && Int8Array.prototype;
+var Uint8ClampedArray = globalThis.Uint8ClampedArray;
+var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
+var TypedArray = Int8Array && getPrototypeOf(Int8Array);
+var TypedArrayPrototype = Int8ArrayPrototype && getPrototypeOf(Int8ArrayPrototype);
+var ObjectPrototype = Object.prototype;
+var TypeError = globalThis.TypeError;
+
+var TO_STRING_TAG = wellKnownSymbol('toStringTag');
+var TYPED_ARRAY_TAG = uid('TYPED_ARRAY_TAG');
+var TYPED_ARRAY_CONSTRUCTOR = 'TypedArrayConstructor';
+// Fixing native typed arrays in Opera Presto crashes the browser, see #595
+var NATIVE_ARRAY_BUFFER_VIEWS = NATIVE_ARRAY_BUFFER && !!setPrototypeOf && classof(globalThis.opera) !== 'Opera';
+var TYPED_ARRAY_TAG_REQUIRED = false;
+var NAME, Constructor, Prototype;
+
+var TypedArrayConstructorsList = {
+ Int8Array: 1,
+ Uint8Array: 1,
+ Uint8ClampedArray: 1,
+ Int16Array: 2,
+ Uint16Array: 2,
+ Int32Array: 4,
+ Uint32Array: 4,
+ Float32Array: 4,
+ Float64Array: 8
+};
+
+var BigIntArrayConstructorsList = {
+ BigInt64Array: 8,
+ BigUint64Array: 8
+};
+
+var isView = function isView(it) {
+ if (!isObject(it)) return false;
+ var klass = classof(it);
+ return klass === 'DataView'
+ || hasOwn(TypedArrayConstructorsList, klass)
+ || hasOwn(BigIntArrayConstructorsList, klass);
+};
+
+var getTypedArrayConstructor = function (it) {
+ var proto = getPrototypeOf(it);
+ if (!isObject(proto)) return;
+ var state = getInternalState(proto);
+ return (state && hasOwn(state, TYPED_ARRAY_CONSTRUCTOR)) ? state[TYPED_ARRAY_CONSTRUCTOR] : getTypedArrayConstructor(proto);
+};
+
+var isTypedArray = function (it) {
+ if (!isObject(it)) return false;
+ var klass = classof(it);
+ return hasOwn(TypedArrayConstructorsList, klass)
+ || hasOwn(BigIntArrayConstructorsList, klass);
+};
+
+var aTypedArray = function (it) {
+ if (isTypedArray(it)) return it;
+ throw new TypeError('Target is not a typed array');
+};
+
+var aTypedArrayConstructor = function (C) {
+ if (isCallable(C) && (!setPrototypeOf || isPrototypeOf(TypedArray, C))) return C;
+ throw new TypeError(tryToString(C) + ' is not a typed array constructor');
+};
+
+var exportTypedArrayMethod = function (KEY, property, forced, options) {
+ if (!DESCRIPTORS) return;
+ if (forced) for (var ARRAY in TypedArrayConstructorsList) {
+ var TypedArrayConstructor = globalThis[ARRAY];
+ if (TypedArrayConstructor && hasOwn(TypedArrayConstructor.prototype, KEY)) try {
+ delete TypedArrayConstructor.prototype[KEY];
+ } catch (error) {
+ // old WebKit bug - some methods are non-configurable
+ try {
+ TypedArrayConstructor.prototype[KEY] = property;
+ } catch (error2) { /* empty */ }
+ }
+ }
+ if (!TypedArrayPrototype[KEY] || forced) {
+ defineBuiltIn(TypedArrayPrototype, KEY, forced ? property
+ : NATIVE_ARRAY_BUFFER_VIEWS && Int8ArrayPrototype[KEY] || property, options);
+ }
+};
+
+var exportTypedArrayStaticMethod = function (KEY, property, forced) {
+ var ARRAY, TypedArrayConstructor;
+ if (!DESCRIPTORS) return;
+ if (setPrototypeOf) {
+ if (forced) for (ARRAY in TypedArrayConstructorsList) {
+ TypedArrayConstructor = globalThis[ARRAY];
+ if (TypedArrayConstructor && hasOwn(TypedArrayConstructor, KEY)) try {
+ delete TypedArrayConstructor[KEY];
+ } catch (error) { /* empty */ }
+ }
+ if (!TypedArray[KEY] || forced) {
+ // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
+ try {
+ return defineBuiltIn(TypedArray, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS && TypedArray[KEY] || property);
+ } catch (error) { /* empty */ }
+ } else return;
+ }
+ for (ARRAY in TypedArrayConstructorsList) {
+ TypedArrayConstructor = globalThis[ARRAY];
+ if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
+ defineBuiltIn(TypedArrayConstructor, KEY, property);
+ }
+ }
+};
+
+for (NAME in TypedArrayConstructorsList) {
+ Constructor = globalThis[NAME];
+ Prototype = Constructor && Constructor.prototype;
+ if (Prototype) enforceInternalState(Prototype)[TYPED_ARRAY_CONSTRUCTOR] = Constructor;
+ else NATIVE_ARRAY_BUFFER_VIEWS = false;
+}
+
+for (NAME in BigIntArrayConstructorsList) {
+ Constructor = globalThis[NAME];
+ Prototype = Constructor && Constructor.prototype;
+ if (Prototype) enforceInternalState(Prototype)[TYPED_ARRAY_CONSTRUCTOR] = Constructor;
+}
+
+// WebKit bug - typed arrays constructors prototype is Object.prototype
+if (!NATIVE_ARRAY_BUFFER_VIEWS || !isCallable(TypedArray) || TypedArray === Function.prototype) {
+ // eslint-disable-next-line no-shadow -- safe
+ TypedArray = function TypedArray() {
+ throw new TypeError('Incorrect invocation');
+ };
+ if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
+ if (globalThis[NAME]) setPrototypeOf(globalThis[NAME], TypedArray);
+ }
+}
+
+if (!NATIVE_ARRAY_BUFFER_VIEWS || !TypedArrayPrototype || TypedArrayPrototype === ObjectPrototype) {
+ TypedArrayPrototype = TypedArray.prototype;
+ if (NATIVE_ARRAY_BUFFER_VIEWS) for (NAME in TypedArrayConstructorsList) {
+ if (globalThis[NAME]) setPrototypeOf(globalThis[NAME].prototype, TypedArrayPrototype);
+ }
+}
+
+// WebKit bug - one more object in Uint8ClampedArray prototype chain
+if (NATIVE_ARRAY_BUFFER_VIEWS && getPrototypeOf(Uint8ClampedArrayPrototype) !== TypedArrayPrototype) {
+ setPrototypeOf(Uint8ClampedArrayPrototype, TypedArrayPrototype);
+}
+
+if (DESCRIPTORS && !hasOwn(TypedArrayPrototype, TO_STRING_TAG)) {
+ TYPED_ARRAY_TAG_REQUIRED = true;
+ defineBuiltInAccessor(TypedArrayPrototype, TO_STRING_TAG, {
+ configurable: true,
+ get: function () {
+ return isObject(this) ? this[TYPED_ARRAY_TAG] : undefined;
+ }
+ });
+ for (NAME in TypedArrayConstructorsList) if (globalThis[NAME]) {
+ createNonEnumerableProperty(globalThis[NAME].prototype, TYPED_ARRAY_TAG, NAME);
+ }
+}
+
+module.exports = {
+ NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS,
+ TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQUIRED && TYPED_ARRAY_TAG,
+ aTypedArray: aTypedArray,
+ aTypedArrayConstructor: aTypedArrayConstructor,
+ exportTypedArrayMethod: exportTypedArrayMethod,
+ exportTypedArrayStaticMethod: exportTypedArrayStaticMethod,
+ getTypedArrayConstructor: getTypedArrayConstructor,
+ isView: isView,
+ isTypedArray: isTypedArray,
+ TypedArray: TypedArray,
+ TypedArrayPrototype: TypedArrayPrototype
+};
+
+
+/***/ },
+
+/***/ 9617
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toIndexedObject = __webpack_require__(5397);
+var toAbsoluteIndex = __webpack_require__(5610);
+var lengthOfArrayLike = __webpack_require__(6198);
+
+// `Array.prototype.{ indexOf, includes }` methods implementation
+var createMethod = function (IS_INCLUDES) {
+ return function ($this, el, fromIndex) {
+ var O = toIndexedObject($this);
+ var length = lengthOfArrayLike(O);
+ if (length === 0) return !IS_INCLUDES && -1;
+ var index = toAbsoluteIndex(fromIndex, length);
+ var value;
+ // Array#includes uses SameValueZero equality algorithm
+ // eslint-disable-next-line no-self-compare -- NaN check
+ if (IS_INCLUDES && el !== el) while (length > index) {
+ value = O[index++];
+ // eslint-disable-next-line no-self-compare -- NaN check
+ if (value !== value) return true;
+ // Array#indexOf ignores holes, Array#includes - not
+ } else for (;length > index; index++) {
+ if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
+ } return !IS_INCLUDES && -1;
+ };
+};
+
+module.exports = {
+ // `Array.prototype.includes` method
+ // https://tc39.es/ecma262/#sec-array.prototype.includes
+ includes: createMethod(true),
+ // `Array.prototype.indexOf` method
+ // https://tc39.es/ecma262/#sec-array.prototype.indexof
+ indexOf: createMethod(false)
+};
+
+
+/***/ },
+
+/***/ 4527
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var isArray = __webpack_require__(4376);
+
+var $TypeError = TypeError;
+// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+
+// Safari < 13 does not throw an error in this case
+var SILENT_ON_NON_WRITABLE_LENGTH_SET = DESCRIPTORS && !function () {
+ // makes no sense without proper strict mode support
+ if (this !== undefined) return true;
+ try {
+ // eslint-disable-next-line es/no-object-defineproperty -- safe
+ Object.defineProperty([], 'length', { writable: false }).length = 1;
+ } catch (error) {
+ return error instanceof TypeError;
+ }
+}();
+
+module.exports = SILENT_ON_NON_WRITABLE_LENGTH_SET ? function (O, length) {
+ if (isArray(O) && !getOwnPropertyDescriptor(O, 'length').writable) {
+ throw new $TypeError('Cannot set read only .length');
+ } return O.length = length;
+} : function (O, length) {
+ return O.length = length;
+};
+
+
+/***/ },
+
+/***/ 6319
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var anObject = __webpack_require__(8551);
+var iteratorClose = __webpack_require__(9539);
+
+// call something on iterator step with safe closing on error
+module.exports = function (iterator, fn, value, ENTRIES) {
+ try {
+ return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
+ } catch (error) {
+ iteratorClose(iterator, 'throw', error);
+ }
+};
+
+
+/***/ },
+
+/***/ 2195
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+var toString = uncurryThis({}.toString);
+var stringSlice = uncurryThis(''.slice);
+
+module.exports = function (it) {
+ return stringSlice(toString(it), 8, -1);
+};
+
+
+/***/ },
+
+/***/ 6955
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var TO_STRING_TAG_SUPPORT = __webpack_require__(2140);
+var isCallable = __webpack_require__(4901);
+var classofRaw = __webpack_require__(2195);
+var wellKnownSymbol = __webpack_require__(8227);
+
+var TO_STRING_TAG = wellKnownSymbol('toStringTag');
+var $Object = Object;
+
+// ES3 wrong here
+var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) === 'Arguments';
+
+// fallback for IE11 Script Access Denied error
+var tryGet = function (it, key) {
+ try {
+ return it[key];
+ } catch (error) { /* empty */ }
+};
+
+// getting tag from ES6+ `Object.prototype.toString`
+module.exports = TO_STRING_TAG_SUPPORT ? classofRaw : function (it) {
+ var O, tag, result;
+ return it === undefined ? 'Undefined' : it === null ? 'Null'
+ // @@toStringTag case
+ : typeof (tag = tryGet(O = $Object(it), TO_STRING_TAG)) == 'string' ? tag
+ // builtinTag case
+ : CORRECT_ARGUMENTS ? classofRaw(O)
+ // ES3 arguments fallback
+ : (result = classofRaw(O)) === 'Object' && isCallable(O.callee) ? 'Arguments' : result;
+};
+
+
+/***/ },
+
+/***/ 7740
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var hasOwn = __webpack_require__(9297);
+var ownKeys = __webpack_require__(5031);
+var getOwnPropertyDescriptorModule = __webpack_require__(7347);
+var definePropertyModule = __webpack_require__(4913);
+
+module.exports = function (target, source, exceptions) {
+ var keys = ownKeys(source);
+ var defineProperty = definePropertyModule.f;
+ var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule.f;
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+ if (!hasOwn(target, key) && !(exceptions && hasOwn(exceptions, key))) {
+ defineProperty(target, key, getOwnPropertyDescriptor(source, key));
+ }
+ }
+};
+
+
+/***/ },
+
+/***/ 2211
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var fails = __webpack_require__(9039);
+
+module.exports = !fails(function () {
+ function F() { /* empty */ }
+ F.prototype.constructor = null;
+ // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
+ return Object.getPrototypeOf(new F()) !== F.prototype;
+});
+
+
+/***/ },
+
+/***/ 2529
+(module) {
+
+
+// `CreateIterResultObject` abstract operation
+// https://tc39.es/ecma262/#sec-createiterresultobject
+module.exports = function (value, done) {
+ return { value: value, done: done };
+};
+
+
+/***/ },
+
+/***/ 6699
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var definePropertyModule = __webpack_require__(4913);
+var createPropertyDescriptor = __webpack_require__(6980);
+
+module.exports = DESCRIPTORS ? function (object, key, value) {
+ return definePropertyModule.f(object, key, createPropertyDescriptor(1, value));
+} : function (object, key, value) {
+ object[key] = value;
+ return object;
+};
+
+
+/***/ },
+
+/***/ 6980
+(module) {
+
+
+module.exports = function (bitmap, value) {
+ return {
+ enumerable: !(bitmap & 1),
+ configurable: !(bitmap & 2),
+ writable: !(bitmap & 4),
+ value: value
+ };
+};
+
+
+/***/ },
+
+/***/ 4659
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var definePropertyModule = __webpack_require__(4913);
+var createPropertyDescriptor = __webpack_require__(6980);
+
+module.exports = function (object, key, value) {
+ if (DESCRIPTORS) definePropertyModule.f(object, key, createPropertyDescriptor(0, value));
+ else object[key] = value;
+};
+
+
+/***/ },
+
+/***/ 2106
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var makeBuiltIn = __webpack_require__(283);
+var defineProperty = __webpack_require__(4913);
+
+module.exports = function (target, name, descriptor) {
+ if (descriptor.get) makeBuiltIn(descriptor.get, name, { getter: true });
+ if (descriptor.set) makeBuiltIn(descriptor.set, name, { setter: true });
+ return defineProperty.f(target, name, descriptor);
+};
+
+
+/***/ },
+
+/***/ 6840
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isCallable = __webpack_require__(4901);
+var definePropertyModule = __webpack_require__(4913);
+var makeBuiltIn = __webpack_require__(283);
+var defineGlobalProperty = __webpack_require__(9433);
+
+module.exports = function (O, key, value, options) {
+ if (!options) options = {};
+ var simple = options.enumerable;
+ var name = options.name !== undefined ? options.name : key;
+ if (isCallable(value)) makeBuiltIn(value, name, options);
+ if (options.global) {
+ if (simple) O[key] = value;
+ else defineGlobalProperty(key, value);
+ } else {
+ try {
+ if (!options.unsafe) delete O[key];
+ else if (O[key]) simple = true;
+ } catch (error) { /* empty */ }
+ if (simple) O[key] = value;
+ else definePropertyModule.f(O, key, {
+ value: value,
+ enumerable: false,
+ configurable: !options.nonConfigurable,
+ writable: !options.nonWritable
+ });
+ } return O;
+};
+
+
+/***/ },
+
+/***/ 6279
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var defineBuiltIn = __webpack_require__(6840);
+
+module.exports = function (target, src, options) {
+ for (var key in src) defineBuiltIn(target, key, src[key], options);
+ return target;
+};
+
+
+/***/ },
+
+/***/ 9433
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+
+// eslint-disable-next-line es/no-object-defineproperty -- safe
+var defineProperty = Object.defineProperty;
+
+module.exports = function (key, value) {
+ try {
+ defineProperty(globalThis, key, { value: value, configurable: true, writable: true });
+ } catch (error) {
+ globalThis[key] = value;
+ } return value;
+};
+
+
+/***/ },
+
+/***/ 3724
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var fails = __webpack_require__(9039);
+
+// Detect IE8's incomplete defineProperty implementation
+module.exports = !fails(function () {
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
+ return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] !== 7;
+});
+
+
+/***/ },
+
+/***/ 4055
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+var isObject = __webpack_require__(34);
+
+var document = globalThis.document;
+// typeof document.createElement is 'object' in old IE
+var EXISTS = isObject(document) && isObject(document.createElement);
+
+module.exports = function (it) {
+ return EXISTS ? document.createElement(it) : {};
+};
+
+
+/***/ },
+
+/***/ 6837
+(module) {
+
+
+var $TypeError = TypeError;
+var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF; // 2 ** 53 - 1 == 9007199254740991
+
+module.exports = function (it) {
+ if (it > MAX_SAFE_INTEGER) throw new $TypeError('Maximum allowed index exceeded');
+ return it;
+};
+
+
+/***/ },
+
+/***/ 8727
+(module) {
+
+
+// IE8- don't enum bug keys
+module.exports = [
+ 'constructor',
+ 'hasOwnProperty',
+ 'isPrototypeOf',
+ 'propertyIsEnumerable',
+ 'toLocaleString',
+ 'toString',
+ 'valueOf'
+];
+
+
+/***/ },
+
+/***/ 2839
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+
+var navigator = globalThis.navigator;
+var userAgent = navigator && navigator.userAgent;
+
+module.exports = userAgent ? String(userAgent) : '';
+
+
+/***/ },
+
+/***/ 9519
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+var userAgent = __webpack_require__(2839);
+
+var process = globalThis.process;
+var Deno = globalThis.Deno;
+var versions = process && process.versions || Deno && Deno.version;
+var v8 = versions && versions.v8;
+var match, version;
+
+if (v8) {
+ match = v8.split('.');
+ // in old Chrome, versions of V8 isn't V8 = Chrome / 10
+ // but their correct versions are not interesting for us
+ version = match[0] > 0 && match[0] < 4 ? 1 : +(match[0] + match[1]);
+}
+
+// BrowserFS NodeJS `process` polyfill incorrectly set `.v8` to `0.0`
+// so check `userAgent` even if `.v8` exists, but 0
+if (!version && userAgent) {
+ match = userAgent.match(/Edge\/(\d+)/);
+ if (!match || match[1] >= 74) {
+ match = userAgent.match(/Chrome\/(\d+)/);
+ if (match) version = +match[1];
+ }
+}
+
+module.exports = version;
+
+
+/***/ },
+
+/***/ 6518
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+var getOwnPropertyDescriptor = (__webpack_require__(7347).f);
+var createNonEnumerableProperty = __webpack_require__(6699);
+var defineBuiltIn = __webpack_require__(6840);
+var defineGlobalProperty = __webpack_require__(9433);
+var copyConstructorProperties = __webpack_require__(7740);
+var isForced = __webpack_require__(2796);
+
+/*
+ options.target - name of the target object
+ options.global - target is the global object
+ options.stat - export as static methods of target
+ options.proto - export as prototype methods of target
+ options.real - real prototype method for the `pure` version
+ options.forced - export even if the native feature is available
+ options.bind - bind methods to the target, required for the `pure` version
+ options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
+ options.unsafe - use the simple assignment of property instead of delete + defineProperty
+ options.sham - add a flag to not completely full polyfills
+ options.enumerable - export as enumerable property
+ options.dontCallGetSet - prevent calling a getter on target
+ options.name - the .name of the function if it does not match the key
+*/
+module.exports = function (options, source) {
+ var TARGET = options.target;
+ var GLOBAL = options.global;
+ var STATIC = options.stat;
+ var FORCED, target, key, targetProperty, sourceProperty, descriptor;
+ if (GLOBAL) {
+ target = globalThis;
+ } else if (STATIC) {
+ target = globalThis[TARGET] || defineGlobalProperty(TARGET, {});
+ } else {
+ target = globalThis[TARGET] && globalThis[TARGET].prototype;
+ }
+ if (target) for (key in source) {
+ sourceProperty = source[key];
+ if (options.dontCallGetSet) {
+ descriptor = getOwnPropertyDescriptor(target, key);
+ targetProperty = descriptor && descriptor.value;
+ } else targetProperty = target[key];
+ FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
+ // contained in target
+ if (!FORCED && targetProperty !== undefined) {
+ if (typeof sourceProperty == typeof targetProperty) continue;
+ copyConstructorProperties(sourceProperty, targetProperty);
+ }
+ // add a flag to not completely full polyfills
+ if (options.sham || (targetProperty && targetProperty.sham)) {
+ createNonEnumerableProperty(sourceProperty, 'sham', true);
+ }
+ defineBuiltIn(target, key, sourceProperty, options);
+ }
+};
+
+
+/***/ },
+
+/***/ 9039
+(module) {
+
+
+module.exports = function (exec) {
+ try {
+ return !!exec();
+ } catch (error) {
+ return true;
+ }
+};
+
+
+/***/ },
+
+/***/ 6080
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(7476);
+var aCallable = __webpack_require__(9306);
+var NATIVE_BIND = __webpack_require__(616);
+
+var bind = uncurryThis(uncurryThis.bind);
+
+// optional / simple context binding
+module.exports = function (fn, that) {
+ aCallable(fn);
+ return that === undefined ? fn : NATIVE_BIND ? bind(fn, that) : function (/* ...args */) {
+ return fn.apply(that, arguments);
+ };
+};
+
+
+/***/ },
+
+/***/ 616
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var fails = __webpack_require__(9039);
+
+module.exports = !fails(function () {
+ // eslint-disable-next-line es/no-function-prototype-bind -- safe
+ var test = function () { /* empty */ }.bind();
+ // eslint-disable-next-line no-prototype-builtins -- safe
+ return typeof test != 'function' || test.hasOwnProperty('prototype');
+});
+
+
+/***/ },
+
+/***/ 9565
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var NATIVE_BIND = __webpack_require__(616);
+
+var call = Function.prototype.call;
+// eslint-disable-next-line es/no-function-prototype-bind -- safe
+module.exports = NATIVE_BIND ? call.bind(call) : function () {
+ return call.apply(call, arguments);
+};
+
+
+/***/ },
+
+/***/ 350
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var hasOwn = __webpack_require__(9297);
+
+var FunctionPrototype = Function.prototype;
+// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+var getDescriptor = DESCRIPTORS && Object.getOwnPropertyDescriptor;
+
+var EXISTS = hasOwn(FunctionPrototype, 'name');
+// additional protection from minified / mangled / dropped function names
+var PROPER = EXISTS && function something() { /* empty */ }.name === 'something';
+var CONFIGURABLE = EXISTS && (!DESCRIPTORS || (DESCRIPTORS && getDescriptor(FunctionPrototype, 'name').configurable));
+
+module.exports = {
+ EXISTS: EXISTS,
+ PROPER: PROPER,
+ CONFIGURABLE: CONFIGURABLE
+};
+
+
+/***/ },
+
+/***/ 6706
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var aCallable = __webpack_require__(9306);
+
+module.exports = function (object, key, method) {
+ try {
+ // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+ return uncurryThis(aCallable(Object.getOwnPropertyDescriptor(object, key)[method]));
+ } catch (error) { /* empty */ }
+};
+
+
+/***/ },
+
+/***/ 7476
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var classofRaw = __webpack_require__(2195);
+var uncurryThis = __webpack_require__(9504);
+
+module.exports = function (fn) {
+ // Nashorn bug:
+ // https://github.com/zloirock/core-js/issues/1128
+ // https://github.com/zloirock/core-js/issues/1130
+ if (classofRaw(fn) === 'Function') return uncurryThis(fn);
+};
+
+
+/***/ },
+
+/***/ 9504
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var NATIVE_BIND = __webpack_require__(616);
+
+var FunctionPrototype = Function.prototype;
+var call = FunctionPrototype.call;
+// eslint-disable-next-line es/no-function-prototype-bind -- safe
+var uncurryThisWithBind = NATIVE_BIND && FunctionPrototype.bind.bind(call, call);
+
+module.exports = NATIVE_BIND ? uncurryThisWithBind : function (fn) {
+ return function () {
+ return call.apply(fn, arguments);
+ };
+};
+
+
+/***/ },
+
+/***/ 7751
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+var isCallable = __webpack_require__(4901);
+
+var aFunction = function (argument) {
+ return isCallable(argument) ? argument : undefined;
+};
+
+module.exports = function (namespace, method) {
+ return arguments.length < 2 ? aFunction(globalThis[namespace]) : globalThis[namespace] && globalThis[namespace][method];
+};
+
+
+/***/ },
+
+/***/ 1767
+(module) {
+
+
+// `GetIteratorDirect(obj)` abstract operation
+// https://tc39.es/ecma262/#sec-getiteratordirect
+module.exports = function (obj) {
+ return {
+ iterator: obj,
+ next: obj.next,
+ done: false
+ };
+};
+
+
+/***/ },
+
+/***/ 8563
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var call = __webpack_require__(9565);
+var isCallable = __webpack_require__(4901);
+var anObject = __webpack_require__(8551);
+var tryToString = __webpack_require__(6823);
+var getIteratorMethod = __webpack_require__(3085);
+
+var $TypeError = TypeError;
+
+module.exports = function (argument, usingIterator) {
+ var iteratorMethod = arguments.length < 2 ? getIteratorMethod(argument) : usingIterator;
+ if (isCallable(iteratorMethod)) return anObject(call(iteratorMethod, argument));
+ throw new $TypeError(tryToString(argument) + ' is not iterable');
+};
+
+
+/***/ },
+
+/***/ 3085
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var classof = __webpack_require__(2195);
+var isNullOrUndefined = __webpack_require__(4117);
+var getMethod = __webpack_require__(5966);
+var wellKnownSymbol = __webpack_require__(8227);
+
+var ITERATOR = wellKnownSymbol('iterator');
+var ArrayPrototype = Array.prototype;
+
+module.exports = function (it) {
+ if (!isNullOrUndefined(it)) return getMethod(it, ITERATOR)
+ || getMethod(it, '@@iterator')
+ || (classof(it) === 'Arguments' ? ArrayPrototype[ITERATOR] : undefined);
+};
+
+
+/***/ },
+
+/***/ 5966
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aCallable = __webpack_require__(9306);
+var isNullOrUndefined = __webpack_require__(4117);
+
+// `GetMethod` abstract operation
+// https://tc39.es/ecma262/#sec-getmethod
+module.exports = function (V, P) {
+ var func = V[P];
+ return isNullOrUndefined(func) ? undefined : aCallable(func);
+};
+
+
+/***/ },
+
+/***/ 3789
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var call = __webpack_require__(9565);
+var toIntegerOrInfinity = __webpack_require__(1291);
+var getIteratorDirect = __webpack_require__(1767);
+
+var INVALID_SIZE = 'Invalid size';
+var $RangeError = RangeError;
+var $TypeError = TypeError;
+var max = Math.max;
+
+var SetRecord = function (set, intSize) {
+ this.set = set;
+ this.size = max(intSize, 0);
+ this.has = aCallable(set.has);
+ this.keys = aCallable(set.keys);
+};
+
+SetRecord.prototype = {
+ getIterator: function () {
+ return getIteratorDirect(anObject(call(this.keys, this.set)));
+ },
+ includes: function (it) {
+ return call(this.has, this.set, it);
+ }
+};
+
+// `GetSetRecord` abstract operation
+// https://tc39.es/proposal-set-methods/#sec-getsetrecord
+module.exports = function (obj) {
+ anObject(obj);
+ var numSize = +obj.size;
+ // NOTE: If size is undefined, then numSize will be NaN
+ // eslint-disable-next-line no-self-compare -- NaN check
+ if (numSize !== numSize) throw new $TypeError(INVALID_SIZE);
+ var intSize = toIntegerOrInfinity(numSize);
+ if (intSize < 0) throw new $RangeError(INVALID_SIZE);
+ return new SetRecord(obj, intSize);
+};
+
+
+/***/ },
+
+/***/ 4576
+(module) {
+
+
+var check = function (it) {
+ return it && it.Math === Math && it;
+};
+
+// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
+module.exports =
+ // eslint-disable-next-line es/no-global-this -- safe
+ check(typeof globalThis == 'object' && globalThis) ||
+ check(typeof window == 'object' && window) ||
+ // eslint-disable-next-line no-restricted-globals -- safe
+ check(typeof self == 'object' && self) ||
+ check(typeof global == 'object' && global) ||
+ check(typeof this == 'object' && this) ||
+ // eslint-disable-next-line no-new-func -- fallback
+ (function () { return this; })() || Function('return this')();
+
+
+/***/ },
+
+/***/ 9297
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var toObject = __webpack_require__(8981);
+
+var hasOwnProperty = uncurryThis({}.hasOwnProperty);
+
+// `HasOwnProperty` abstract operation
+// https://tc39.es/ecma262/#sec-hasownproperty
+// eslint-disable-next-line es/no-object-hasown -- safe
+module.exports = Object.hasOwn || function hasOwn(it, key) {
+ return hasOwnProperty(toObject(it), key);
+};
+
+
+/***/ },
+
+/***/ 421
+(module) {
+
+
+module.exports = {};
+
+
+/***/ },
+
+/***/ 397
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var getBuiltIn = __webpack_require__(7751);
+
+module.exports = getBuiltIn('document', 'documentElement');
+
+
+/***/ },
+
+/***/ 5917
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var fails = __webpack_require__(9039);
+var createElement = __webpack_require__(4055);
+
+// Thanks to IE8 for its funny defineProperty
+module.exports = !DESCRIPTORS && !fails(function () {
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
+ return Object.defineProperty(createElement('div'), 'a', {
+ get: function () { return 7; }
+ }).a !== 7;
+});
+
+
+/***/ },
+
+/***/ 7055
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var fails = __webpack_require__(9039);
+var classof = __webpack_require__(2195);
+
+var $Object = Object;
+var split = uncurryThis(''.split);
+
+// fallback for non-array-like ES3 and non-enumerable old V8 strings
+module.exports = fails(function () {
+ // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
+ // eslint-disable-next-line no-prototype-builtins -- safe
+ return !$Object('z').propertyIsEnumerable(0);
+}) ? function (it) {
+ return classof(it) === 'String' ? split(it, '') : $Object(it);
+} : $Object;
+
+
+/***/ },
+
+/***/ 3706
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var isCallable = __webpack_require__(4901);
+var store = __webpack_require__(7629);
+
+var functionToString = uncurryThis(Function.toString);
+
+// this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
+if (!isCallable(store.inspectSource)) {
+ store.inspectSource = function (it) {
+ return functionToString(it);
+ };
+}
+
+module.exports = store.inspectSource;
+
+
+/***/ },
+
+/***/ 1181
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var NATIVE_WEAK_MAP = __webpack_require__(8622);
+var globalThis = __webpack_require__(4576);
+var isObject = __webpack_require__(34);
+var createNonEnumerableProperty = __webpack_require__(6699);
+var hasOwn = __webpack_require__(9297);
+var shared = __webpack_require__(7629);
+var sharedKey = __webpack_require__(6119);
+var hiddenKeys = __webpack_require__(421);
+
+var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
+var TypeError = globalThis.TypeError;
+var WeakMap = globalThis.WeakMap;
+var set, get, has;
+
+var enforce = function (it) {
+ return has(it) ? get(it) : set(it, {});
+};
+
+var getterFor = function (TYPE) {
+ return function (it) {
+ var state;
+ if (!isObject(it) || (state = get(it)).type !== TYPE) {
+ throw new TypeError('Incompatible receiver, ' + TYPE + ' required');
+ } return state;
+ };
+};
+
+if (NATIVE_WEAK_MAP || shared.state) {
+ var store = shared.state || (shared.state = new WeakMap());
+ /* eslint-disable no-self-assign -- prototype methods protection */
+ store.get = store.get;
+ store.has = store.has;
+ store.set = store.set;
+ /* eslint-enable no-self-assign -- prototype methods protection */
+ set = function (it, metadata) {
+ if (store.has(it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
+ metadata.facade = it;
+ store.set(it, metadata);
+ return metadata;
+ };
+ get = function (it) {
+ return store.get(it) || {};
+ };
+ has = function (it) {
+ return store.has(it);
+ };
+} else {
+ var STATE = sharedKey('state');
+ hiddenKeys[STATE] = true;
+ set = function (it, metadata) {
+ if (hasOwn(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
+ metadata.facade = it;
+ createNonEnumerableProperty(it, STATE, metadata);
+ return metadata;
+ };
+ get = function (it) {
+ return hasOwn(it, STATE) ? it[STATE] : {};
+ };
+ has = function (it) {
+ return hasOwn(it, STATE);
+ };
+}
+
+module.exports = {
+ set: set,
+ get: get,
+ has: has,
+ enforce: enforce,
+ getterFor: getterFor
+};
+
+
+/***/ },
+
+/***/ 4209
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var wellKnownSymbol = __webpack_require__(8227);
+var Iterators = __webpack_require__(6269);
+
+var ITERATOR = wellKnownSymbol('iterator');
+var ArrayPrototype = Array.prototype;
+
+// check on default Array iterator
+module.exports = function (it) {
+ return it !== undefined && (Iterators.Array === it || ArrayPrototype[ITERATOR] === it);
+};
+
+
+/***/ },
+
+/***/ 4376
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var classof = __webpack_require__(2195);
+
+// `IsArray` abstract operation
+// https://tc39.es/ecma262/#sec-isarray
+// eslint-disable-next-line es/no-array-isarray -- safe
+module.exports = Array.isArray || function isArray(argument) {
+ return classof(argument) === 'Array';
+};
+
+
+/***/ },
+
+/***/ 1108
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var classof = __webpack_require__(6955);
+
+module.exports = function (it) {
+ var klass = classof(it);
+ return klass === 'BigInt64Array' || klass === 'BigUint64Array';
+};
+
+
+/***/ },
+
+/***/ 4901
+(module) {
+
+
+// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot
+var documentAll = typeof document == 'object' && document.all;
+
+// `IsCallable` abstract operation
+// https://tc39.es/ecma262/#sec-iscallable
+// eslint-disable-next-line unicorn/no-typeof-undefined -- required for testing
+module.exports = typeof documentAll == 'undefined' && documentAll !== undefined ? function (argument) {
+ return typeof argument == 'function' || argument === documentAll;
+} : function (argument) {
+ return typeof argument == 'function';
+};
+
+
+/***/ },
+
+/***/ 2796
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var fails = __webpack_require__(9039);
+var isCallable = __webpack_require__(4901);
+
+var replacement = /#|\.prototype\./;
+
+var isForced = function (feature, detection) {
+ var value = data[normalize(feature)];
+ return value === POLYFILL ? true
+ : value === NATIVE ? false
+ : isCallable(detection) ? fails(detection)
+ : !!detection;
+};
+
+var normalize = isForced.normalize = function (string) {
+ return String(string).replace(replacement, '.').toLowerCase();
+};
+
+var data = isForced.data = {};
+var NATIVE = isForced.NATIVE = 'N';
+var POLYFILL = isForced.POLYFILL = 'P';
+
+module.exports = isForced;
+
+
+/***/ },
+
+/***/ 4117
+(module) {
+
+
+// we can't use just `it == null` since of `document.all` special case
+// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-aec
+module.exports = function (it) {
+ return it === null || it === undefined;
+};
+
+
+/***/ },
+
+/***/ 34
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isCallable = __webpack_require__(4901);
+
+module.exports = function (it) {
+ return typeof it == 'object' ? it !== null : isCallable(it);
+};
+
+
+/***/ },
+
+/***/ 3925
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isObject = __webpack_require__(34);
+
+module.exports = function (argument) {
+ return isObject(argument) || argument === null;
+};
+
+
+/***/ },
+
+/***/ 6395
+(module) {
+
+
+module.exports = false;
+
+
+/***/ },
+
+/***/ 5810
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isObject = __webpack_require__(34);
+var getInternalState = (__webpack_require__(1181).get);
+
+module.exports = function isRawJSON(O) {
+ if (!isObject(O)) return false;
+ var state = getInternalState(O);
+ return !!state && state.type === 'RawJSON';
+};
+
+
+/***/ },
+
+/***/ 757
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var getBuiltIn = __webpack_require__(7751);
+var isCallable = __webpack_require__(4901);
+var isPrototypeOf = __webpack_require__(1625);
+var USE_SYMBOL_AS_UID = __webpack_require__(7040);
+
+var $Object = Object;
+
+module.exports = USE_SYMBOL_AS_UID ? function (it) {
+ return typeof it == 'symbol';
+} : function (it) {
+ var $Symbol = getBuiltIn('Symbol');
+ return isCallable($Symbol) && isPrototypeOf($Symbol.prototype, $Object(it));
+};
+
+
+/***/ },
+
+/***/ 507
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var call = __webpack_require__(9565);
+
+module.exports = function (record, fn, ITERATOR_INSTEAD_OF_RECORD) {
+ var iterator = ITERATOR_INSTEAD_OF_RECORD ? record : record.iterator;
+ var next = record.next;
+ var step, result;
+ while (!(step = call(next, iterator)).done) {
+ result = fn(step.value);
+ if (result !== undefined) return result;
+ }
+};
+
+
+/***/ },
+
+/***/ 2652
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var bind = __webpack_require__(6080);
+var call = __webpack_require__(9565);
+var anObject = __webpack_require__(8551);
+var tryToString = __webpack_require__(6823);
+var isArrayIteratorMethod = __webpack_require__(4209);
+var lengthOfArrayLike = __webpack_require__(6198);
+var isPrototypeOf = __webpack_require__(1625);
+var getIterator = __webpack_require__(8563);
+var getIteratorMethod = __webpack_require__(3085);
+var iteratorClose = __webpack_require__(9539);
+
+var $TypeError = TypeError;
+
+var Result = function (stopped, result) {
+ this.stopped = stopped;
+ this.result = result;
+};
+
+var ResultPrototype = Result.prototype;
+
+module.exports = function (iterable, unboundFunction, options) {
+ var that = options && options.that;
+ var AS_ENTRIES = !!(options && options.AS_ENTRIES);
+ var IS_RECORD = !!(options && options.IS_RECORD);
+ var IS_ITERATOR = !!(options && options.IS_ITERATOR);
+ var INTERRUPTED = !!(options && options.INTERRUPTED);
+ var fn = bind(unboundFunction, that);
+ var iterator, iterFn, index, length, result, next, step;
+
+ var stop = function (condition) {
+ var $iterator = iterator;
+ iterator = undefined;
+ if ($iterator) iteratorClose($iterator, 'normal');
+ return new Result(true, condition);
+ };
+
+ var callFn = function (value) {
+ if (AS_ENTRIES) {
+ anObject(value);
+ return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
+ } return INTERRUPTED ? fn(value, stop) : fn(value);
+ };
+
+ if (IS_RECORD) {
+ iterator = iterable.iterator;
+ } else if (IS_ITERATOR) {
+ iterator = iterable;
+ } else {
+ iterFn = getIteratorMethod(iterable);
+ if (!iterFn) throw new $TypeError(tryToString(iterable) + ' is not iterable');
+ // optimisation for array iterators
+ if (isArrayIteratorMethod(iterFn)) {
+ for (index = 0, length = lengthOfArrayLike(iterable); length > index; index++) {
+ result = callFn(iterable[index]);
+ if (result && isPrototypeOf(ResultPrototype, result)) return result;
+ } return new Result(false);
+ }
+ iterator = getIterator(iterable, iterFn);
+ }
+
+ next = IS_RECORD ? iterable.next : iterator.next;
+ while (!(step = call(next, iterator)).done) {
+ // `IteratorValue` errors should propagate without closing the iterator
+ var value = step.value;
+ try {
+ result = callFn(value);
+ } catch (error) {
+ if (iterator) iteratorClose(iterator, 'throw', error);
+ else throw error;
+ }
+ if (typeof result == 'object' && result && isPrototypeOf(ResultPrototype, result)) return result;
+ } return new Result(false);
+};
+
+
+/***/ },
+
+/***/ 6859
+(module) {
+
+
+// release references held by exhausted / closed iterator helpers to allow GC of the source chain
+module.exports = function (state) {
+ state.iterator = state.next = state.nextHandler = state.mapper = state.predicate = state.inner =
+ state.iterables = state.iters = state.openIters = state.padding = state.finishResults = state.buffer = null;
+};
+
+
+/***/ },
+
+/***/ 1385
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var iteratorClose = __webpack_require__(9539);
+
+module.exports = function (iters, kind, value) {
+ for (var i = iters.length - 1; i >= 0; i--) {
+ if (iters[i] === undefined) continue;
+ try {
+ value = iteratorClose(iters[i].iterator, kind, value);
+ } catch (error) {
+ kind = 'throw';
+ value = error;
+ }
+ }
+ if (kind === 'throw') throw value;
+ return value;
+};
+
+
+/***/ },
+
+/***/ 9539
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var call = __webpack_require__(9565);
+var anObject = __webpack_require__(8551);
+var getMethod = __webpack_require__(5966);
+
+module.exports = function (iterator, kind, value) {
+ var innerResult, innerError;
+ anObject(iterator);
+ try {
+ innerResult = getMethod(iterator, 'return');
+ if (!innerResult) {
+ if (kind === 'throw') throw value;
+ return value;
+ }
+ innerResult = call(innerResult, iterator);
+ } catch (error) {
+ innerError = true;
+ innerResult = error;
+ }
+ if (kind === 'throw') throw value;
+ if (innerError) throw innerResult;
+ anObject(innerResult);
+ return value;
+};
+
+
+/***/ },
+
+/***/ 9462
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var call = __webpack_require__(9565);
+var create = __webpack_require__(2360);
+var createNonEnumerableProperty = __webpack_require__(6699);
+var defineBuiltIns = __webpack_require__(6279);
+var wellKnownSymbol = __webpack_require__(8227);
+var InternalStateModule = __webpack_require__(1181);
+var getMethod = __webpack_require__(5966);
+var IteratorPrototype = (__webpack_require__(7657).IteratorPrototype);
+var createIterResultObject = __webpack_require__(2529);
+var iteratorClose = __webpack_require__(9539);
+var iteratorCloseAll = __webpack_require__(1385);
+var cleanupState = __webpack_require__(6859);
+
+var TO_STRING_TAG = wellKnownSymbol('toStringTag');
+var ITERATOR_HELPER = 'IteratorHelper';
+var WRAP_FOR_VALID_ITERATOR = 'WrapForValidIterator';
+var NORMAL = 'normal';
+var THROW = 'throw';
+var setInternalState = InternalStateModule.set;
+
+var createIteratorProxyPrototype = function (IS_ITERATOR) {
+ var getInternalState = InternalStateModule.getterFor(IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER);
+
+ return defineBuiltIns(create(IteratorPrototype), {
+ next: function next() {
+ var state = getInternalState(this);
+ // for simplification:
+ // for `%WrapForValidIteratorPrototype%.next` or with `state.returnHandlerResult` our `nextHandler` returns `IterResultObject`
+ // for `%IteratorHelperPrototype%.next` - just a value
+ if (IS_ITERATOR) return state.nextHandler();
+ if (state.done) return createIterResultObject(undefined, true);
+ try {
+ var result = state.nextHandler();
+ if (state.done) cleanupState(state);
+ return state.returnHandlerResult ? result : createIterResultObject(result, state.done);
+ } catch (error) {
+ state.done = true;
+ cleanupState(state);
+ throw error;
+ }
+ },
+ 'return': function () {
+ var state = getInternalState(this);
+ var iterator = state.iterator;
+ var inner = state.inner;
+ var openIters = state.openIters;
+ var done = state.done;
+ state.done = true;
+ if (IS_ITERATOR) {
+ var returnMethod = getMethod(iterator, 'return');
+ return returnMethod ? call(returnMethod, iterator) : createIterResultObject(undefined, true);
+ }
+ cleanupState(state);
+ if (done) return createIterResultObject(undefined, true);
+ if (inner) try {
+ iteratorClose(inner.iterator, NORMAL);
+ } catch (error) {
+ return iteratorClose(iterator, THROW, error);
+ }
+ if (openIters) try {
+ iteratorCloseAll(openIters, NORMAL);
+ } catch (error) {
+ if (iterator) return iteratorClose(iterator, THROW, error);
+ throw error;
+ }
+ if (iterator) iteratorClose(iterator, NORMAL);
+ return createIterResultObject(undefined, true);
+ }
+ });
+};
+
+var WrapForValidIteratorPrototype = createIteratorProxyPrototype(true);
+var IteratorHelperPrototype = createIteratorProxyPrototype(false);
+
+createNonEnumerableProperty(IteratorHelperPrototype, TO_STRING_TAG, 'Iterator Helper');
+
+module.exports = function (nextHandler, IS_ITERATOR, RETURN_HANDLER_RESULT) {
+ var IteratorProxy = function Iterator(record, state) {
+ if (state) {
+ state.iterator = record.iterator;
+ state.next = record.next;
+ } else state = record;
+ state.type = IS_ITERATOR ? WRAP_FOR_VALID_ITERATOR : ITERATOR_HELPER;
+ state.returnHandlerResult = !!RETURN_HANDLER_RESULT;
+ state.nextHandler = nextHandler;
+ state.counter = 0;
+ state.done = false;
+ setInternalState(this, state);
+ };
+
+ IteratorProxy.prototype = IS_ITERATOR ? WrapForValidIteratorPrototype : IteratorHelperPrototype;
+
+ return IteratorProxy;
+};
+
+
+/***/ },
+
+/***/ 684
+(module) {
+
+
+// Should throw an error on invalid iterator
+// https://issues.chromium.org/issues/336839115
+module.exports = function (methodName, argument) {
+ // eslint-disable-next-line es/no-iterator -- required for testing
+ var method = typeof Iterator == 'function' && Iterator.prototype[methodName];
+ if (method) try {
+ method.call({ next: null }, argument).next();
+ } catch (error) {
+ return true;
+ }
+};
+
+
+/***/ },
+
+/***/ 4549
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+
+// https://github.com/tc39/ecma262/pull/3467
+module.exports = function (METHOD_NAME, ExpectedError) {
+ var Iterator = globalThis.Iterator;
+ var IteratorPrototype = Iterator && Iterator.prototype;
+ var method = IteratorPrototype && IteratorPrototype[METHOD_NAME];
+
+ var CLOSED = false;
+
+ if (method) try {
+ method.call({
+ next: function () { return { done: true }; },
+ 'return': function () { CLOSED = true; }
+ }, -1);
+ } catch (error) {
+ // https://bugs.webkit.org/show_bug.cgi?id=291195
+ if (!(error instanceof ExpectedError)) CLOSED = false;
+ }
+
+ if (!CLOSED) return method;
+};
+
+
+/***/ },
+
+/***/ 7657
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var fails = __webpack_require__(9039);
+var isCallable = __webpack_require__(4901);
+var isObject = __webpack_require__(34);
+var create = __webpack_require__(2360);
+var getPrototypeOf = __webpack_require__(2787);
+var defineBuiltIn = __webpack_require__(6840);
+var wellKnownSymbol = __webpack_require__(8227);
+var IS_PURE = __webpack_require__(6395);
+
+var ITERATOR = wellKnownSymbol('iterator');
+var BUGGY_SAFARI_ITERATORS = false;
+
+// `%IteratorPrototype%` object
+// https://tc39.es/ecma262/#sec-%iteratorprototype%-object
+var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;
+
+/* eslint-disable es/no-array-prototype-keys -- safe */
+if ([].keys) {
+ arrayIterator = [].keys();
+ // Safari 8 has buggy iterators w/o `next`
+ if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;
+ else {
+ PrototypeOfArrayIteratorPrototype = getPrototypeOf(getPrototypeOf(arrayIterator));
+ if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
+ }
+}
+
+var NEW_ITERATOR_PROTOTYPE = !isObject(IteratorPrototype) || fails(function () {
+ var test = {};
+ // FF44- legacy iterators case
+ return IteratorPrototype[ITERATOR].call(test) !== test;
+});
+
+if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype = {};
+else if (IS_PURE) IteratorPrototype = create(IteratorPrototype);
+
+// `%IteratorPrototype%[@@iterator]()` method
+// https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
+if (!isCallable(IteratorPrototype[ITERATOR])) {
+ defineBuiltIn(IteratorPrototype, ITERATOR, function () {
+ return this;
+ });
+}
+
+module.exports = {
+ IteratorPrototype: IteratorPrototype,
+ BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
+};
+
+
+/***/ },
+
+/***/ 6269
+(module) {
+
+
+module.exports = Object.create ? Object.create(null) : {};
+
+
+/***/ },
+
+/***/ 6198
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toLength = __webpack_require__(8014);
+
+// `LengthOfArrayLike` abstract operation
+// https://tc39.es/ecma262/#sec-lengthofarraylike
+module.exports = function (obj) {
+ return toLength(obj.length);
+};
+
+
+/***/ },
+
+/***/ 283
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var fails = __webpack_require__(9039);
+var isCallable = __webpack_require__(4901);
+var hasOwn = __webpack_require__(9297);
+var DESCRIPTORS = __webpack_require__(3724);
+var CONFIGURABLE_FUNCTION_NAME = (__webpack_require__(350).CONFIGURABLE);
+var inspectSource = __webpack_require__(3706);
+var InternalStateModule = __webpack_require__(1181);
+
+var enforceInternalState = InternalStateModule.enforce;
+var getInternalState = InternalStateModule.get;
+var $String = String;
+// eslint-disable-next-line es/no-object-defineproperty -- safe
+var defineProperty = Object.defineProperty;
+var stringSlice = uncurryThis(''.slice);
+var replace = uncurryThis(''.replace);
+var join = uncurryThis([].join);
+
+var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function () {
+ return defineProperty(function () { /* empty */ }, 'length', { value: 8 }).length !== 8;
+});
+
+var TEMPLATE = String(String).split('String');
+
+var makeBuiltIn = module.exports = function (value, name, options) {
+ if (stringSlice($String(name), 0, 7) === 'Symbol(') {
+ name = '[' + replace($String(name), /^Symbol\(([^)]*)\).*$/, '$1') + ']';
+ }
+ if (options && options.getter) name = 'get ' + name;
+ if (options && options.setter) name = 'set ' + name;
+ if (!hasOwn(value, 'name') || (CONFIGURABLE_FUNCTION_NAME && value.name !== name)) {
+ if (DESCRIPTORS) defineProperty(value, 'name', { value: name, configurable: true });
+ else value.name = name;
+ }
+ if (CONFIGURABLE_LENGTH && options && hasOwn(options, 'arity') && value.length !== options.arity) {
+ defineProperty(value, 'length', { value: options.arity });
+ }
+ try {
+ if (options && hasOwn(options, 'constructor') && options.constructor) {
+ if (DESCRIPTORS) defineProperty(value, 'prototype', { writable: false });
+ // in V8 ~ Chrome 53, prototypes of some methods, like `Array.prototype.values`, are non-writable
+ } else if (value.prototype) value.prototype = undefined;
+ } catch (error) { /* empty */ }
+ var state = enforceInternalState(value);
+ if (!hasOwn(state, 'source')) {
+ state.source = join(TEMPLATE, typeof name == 'string' ? name : '');
+ } return value;
+};
+
+// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
+// eslint-disable-next-line no-extend-native -- required
+Function.prototype.toString = makeBuiltIn(function toString() {
+ return isCallable(this) && getInternalState(this).source || inspectSource(this);
+}, 'toString');
+
+
+/***/ },
+
+/***/ 2248
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+// eslint-disable-next-line es/no-map -- safe
+var MapPrototype = Map.prototype;
+
+module.exports = {
+ // eslint-disable-next-line es/no-map -- safe
+ Map: Map,
+ set: uncurryThis(MapPrototype.set),
+ get: uncurryThis(MapPrototype.get),
+ has: uncurryThis(MapPrototype.has),
+ remove: uncurryThis(MapPrototype['delete']),
+ proto: MapPrototype
+};
+
+
+/***/ },
+
+/***/ 741
+(module) {
+
+
+var ceil = Math.ceil;
+var floor = Math.floor;
+
+// `Math.trunc` method
+// https://tc39.es/ecma262/#sec-math.trunc
+// eslint-disable-next-line es/no-math-trunc -- safe
+module.exports = Math.trunc || function trunc(x) {
+ var n = +x;
+ return (n > 0 ? floor : ceil)(n);
+};
+
+
+/***/ },
+
+/***/ 7819
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+/* eslint-disable es/no-json -- safe */
+var fails = __webpack_require__(9039);
+
+module.exports = !fails(function () {
+ var unsafeInt = '9007199254740993';
+ // eslint-disable-next-line es/no-json-rawjson -- feature detection
+ var raw = JSON.rawJSON(unsafeInt);
+ // eslint-disable-next-line es/no-json-israwjson -- feature detection
+ return !JSON.isRawJSON(raw) || JSON.stringify(raw) !== unsafeInt;
+});
+
+
+/***/ },
+
+/***/ 2360
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+/* global ActiveXObject -- old IE, WSH */
+var anObject = __webpack_require__(8551);
+var definePropertiesModule = __webpack_require__(6801);
+var enumBugKeys = __webpack_require__(8727);
+var hiddenKeys = __webpack_require__(421);
+var html = __webpack_require__(397);
+var documentCreateElement = __webpack_require__(4055);
+var sharedKey = __webpack_require__(6119);
+
+var GT = '>';
+var LT = '<';
+var PROTOTYPE = 'prototype';
+var SCRIPT = 'script';
+var IE_PROTO = sharedKey('IE_PROTO');
+
+var EmptyConstructor = function () { /* empty */ };
+
+var scriptTag = function (content) {
+ return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
+};
+
+// Create object with fake `null` prototype: use ActiveX Object with cleared prototype
+var NullProtoObjectViaActiveX = function (activeXDocument) {
+ activeXDocument.write(scriptTag(''));
+ activeXDocument.close();
+ var temp = activeXDocument.parentWindow.Object;
+ // eslint-disable-next-line no-useless-assignment -- avoid memory leak
+ activeXDocument = null;
+ return temp;
+};
+
+// Create object with fake `null` prototype: use iframe Object with cleared prototype
+var NullProtoObjectViaIFrame = function () {
+ // Thrash, waste and sodomy: IE GC bug
+ var iframe = documentCreateElement('iframe');
+ var JS = 'java' + SCRIPT + ':';
+ var iframeDocument;
+ iframe.style.display = 'none';
+ html.appendChild(iframe);
+ // https://github.com/zloirock/core-js/issues/475
+ iframe.src = String(JS);
+ iframeDocument = iframe.contentWindow.document;
+ iframeDocument.open();
+ iframeDocument.write(scriptTag('document.F=Object'));
+ iframeDocument.close();
+ return iframeDocument.F;
+};
+
+// Check for document.domain and active x support
+// No need to use active x approach when document.domain is not set
+// see https://github.com/es-shims/es5-shim/issues/150
+// variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
+// avoid IE GC bug
+var activeXDocument;
+var NullProtoObject = function () {
+ try {
+ activeXDocument = new ActiveXObject('htmlfile');
+ } catch (error) { /* ignore */ }
+ NullProtoObject = typeof document != 'undefined'
+ ? document.domain && activeXDocument
+ ? NullProtoObjectViaActiveX(activeXDocument) // old IE
+ : NullProtoObjectViaIFrame()
+ : NullProtoObjectViaActiveX(activeXDocument); // WSH
+ var length = enumBugKeys.length;
+ while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]];
+ return NullProtoObject();
+};
+
+hiddenKeys[IE_PROTO] = true;
+
+// `Object.create` method
+// https://tc39.es/ecma262/#sec-object.create
+// eslint-disable-next-line es/no-object-create -- safe
+module.exports = Object.create || function create(O, Properties) {
+ var result;
+ if (O !== null) {
+ EmptyConstructor[PROTOTYPE] = anObject(O);
+ result = new EmptyConstructor();
+ EmptyConstructor[PROTOTYPE] = null;
+ // add "__proto__" for Object.getPrototypeOf polyfill
+ result[IE_PROTO] = O;
+ } else result = NullProtoObject();
+ return Properties === undefined ? result : definePropertiesModule.f(result, Properties);
+};
+
+
+/***/ },
+
+/***/ 6801
+(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var V8_PROTOTYPE_DEFINE_BUG = __webpack_require__(8686);
+var definePropertyModule = __webpack_require__(4913);
+var anObject = __webpack_require__(8551);
+var toIndexedObject = __webpack_require__(5397);
+var objectKeys = __webpack_require__(1072);
+
+// `Object.defineProperties` method
+// https://tc39.es/ecma262/#sec-object.defineproperties
+// eslint-disable-next-line es/no-object-defineproperties -- safe
+exports.f = DESCRIPTORS && !V8_PROTOTYPE_DEFINE_BUG ? Object.defineProperties : function defineProperties(O, Properties) {
+ anObject(O);
+ var props = toIndexedObject(Properties);
+ var keys = objectKeys(Properties);
+ var length = keys.length;
+ var index = 0;
+ var key;
+ while (length > index) definePropertyModule.f(O, key = keys[index++], props[key]);
+ return O;
+};
+
+
+/***/ },
+
+/***/ 4913
+(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var IE8_DOM_DEFINE = __webpack_require__(5917);
+var V8_PROTOTYPE_DEFINE_BUG = __webpack_require__(8686);
+var anObject = __webpack_require__(8551);
+var toPropertyKey = __webpack_require__(6969);
+
+var $TypeError = TypeError;
+// eslint-disable-next-line es/no-object-defineproperty -- safe
+var $defineProperty = Object.defineProperty;
+// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+var ENUMERABLE = 'enumerable';
+var CONFIGURABLE = 'configurable';
+var WRITABLE = 'writable';
+
+// `Object.defineProperty` method
+// https://tc39.es/ecma262/#sec-object.defineproperty
+exports.f = DESCRIPTORS ? V8_PROTOTYPE_DEFINE_BUG ? function defineProperty(O, P, Attributes) {
+ anObject(O);
+ P = toPropertyKey(P);
+ anObject(Attributes);
+ if (typeof O === 'function' && P === 'prototype' && 'value' in Attributes && WRITABLE in Attributes && !Attributes[WRITABLE]) {
+ var current = $getOwnPropertyDescriptor(O, P);
+ if (current && current[WRITABLE]) {
+ O[P] = Attributes.value;
+ Attributes = {
+ configurable: CONFIGURABLE in Attributes ? Attributes[CONFIGURABLE] : current[CONFIGURABLE],
+ enumerable: ENUMERABLE in Attributes ? Attributes[ENUMERABLE] : current[ENUMERABLE],
+ writable: false
+ };
+ }
+ } return $defineProperty(O, P, Attributes);
+} : $defineProperty : function defineProperty(O, P, Attributes) {
+ anObject(O);
+ P = toPropertyKey(P);
+ anObject(Attributes);
+ if (IE8_DOM_DEFINE) try {
+ return $defineProperty(O, P, Attributes);
+ } catch (error) { /* empty */ }
+ if ('get' in Attributes || 'set' in Attributes) throw new $TypeError('Accessors not supported');
+ if ('value' in Attributes) O[P] = Attributes.value;
+ return O;
+};
+
+
+/***/ },
+
+/***/ 7347
+(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var call = __webpack_require__(9565);
+var propertyIsEnumerableModule = __webpack_require__(8773);
+var createPropertyDescriptor = __webpack_require__(6980);
+var toIndexedObject = __webpack_require__(5397);
+var toPropertyKey = __webpack_require__(6969);
+var hasOwn = __webpack_require__(9297);
+var IE8_DOM_DEFINE = __webpack_require__(5917);
+
+// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+var $getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+
+// `Object.getOwnPropertyDescriptor` method
+// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
+exports.f = DESCRIPTORS ? $getOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) {
+ O = toIndexedObject(O);
+ P = toPropertyKey(P);
+ if (IE8_DOM_DEFINE) try {
+ return $getOwnPropertyDescriptor(O, P);
+ } catch (error) { /* empty */ }
+ if (hasOwn(O, P)) return createPropertyDescriptor(!call(propertyIsEnumerableModule.f, O, P), O[P]);
+};
+
+
+/***/ },
+
+/***/ 8480
+(__unused_webpack_module, exports, __webpack_require__) {
+
+
+var internalObjectKeys = __webpack_require__(1828);
+var enumBugKeys = __webpack_require__(8727);
+
+var hiddenKeys = enumBugKeys.concat('length', 'prototype');
+
+// `Object.getOwnPropertyNames` method
+// https://tc39.es/ecma262/#sec-object.getownpropertynames
+// eslint-disable-next-line es/no-object-getownpropertynames -- safe
+exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
+ return internalObjectKeys(O, hiddenKeys);
+};
+
+
+/***/ },
+
+/***/ 3717
+(__unused_webpack_module, exports) {
+
+
+// eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
+exports.f = Object.getOwnPropertySymbols;
+
+
+/***/ },
+
+/***/ 2787
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var hasOwn = __webpack_require__(9297);
+var isCallable = __webpack_require__(4901);
+var toObject = __webpack_require__(8981);
+var sharedKey = __webpack_require__(6119);
+var CORRECT_PROTOTYPE_GETTER = __webpack_require__(2211);
+
+var IE_PROTO = sharedKey('IE_PROTO');
+var $Object = Object;
+var ObjectPrototype = $Object.prototype;
+
+// `Object.getPrototypeOf` method
+// https://tc39.es/ecma262/#sec-object.getprototypeof
+// eslint-disable-next-line es/no-object-getprototypeof -- safe
+module.exports = CORRECT_PROTOTYPE_GETTER ? $Object.getPrototypeOf : function (O) {
+ var object = toObject(O);
+ if (hasOwn(object, IE_PROTO)) return object[IE_PROTO];
+ var constructor = object.constructor;
+ if (isCallable(constructor) && object instanceof constructor) {
+ return constructor.prototype;
+ } return object instanceof $Object ? ObjectPrototype : null;
+};
+
+
+/***/ },
+
+/***/ 1625
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+module.exports = uncurryThis({}.isPrototypeOf);
+
+
+/***/ },
+
+/***/ 1828
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var hasOwn = __webpack_require__(9297);
+var toIndexedObject = __webpack_require__(5397);
+var indexOf = (__webpack_require__(9617).indexOf);
+var hiddenKeys = __webpack_require__(421);
+
+var push = uncurryThis([].push);
+
+module.exports = function (object, names) {
+ var O = toIndexedObject(object);
+ var i = 0;
+ var result = [];
+ var key;
+ for (key in O) !hasOwn(hiddenKeys, key) && hasOwn(O, key) && push(result, key);
+ // Don't enum bug & hidden keys
+ while (names.length > i) if (hasOwn(O, key = names[i++])) {
+ ~indexOf(result, key) || push(result, key);
+ }
+ return result;
+};
+
+
+/***/ },
+
+/***/ 1072
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var internalObjectKeys = __webpack_require__(1828);
+var enumBugKeys = __webpack_require__(8727);
+
+// `Object.keys` method
+// https://tc39.es/ecma262/#sec-object.keys
+// eslint-disable-next-line es/no-object-keys -- safe
+module.exports = Object.keys || function keys(O) {
+ return internalObjectKeys(O, enumBugKeys);
+};
+
+
+/***/ },
+
+/***/ 8773
+(__unused_webpack_module, exports) {
+
+
+var $propertyIsEnumerable = {}.propertyIsEnumerable;
+// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+
+// Nashorn ~ JDK8 bug
+var NASHORN_BUG = getOwnPropertyDescriptor && !$propertyIsEnumerable.call({ 1: 2 }, 1);
+
+// `Object.prototype.propertyIsEnumerable` method implementation
+// https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
+exports.f = NASHORN_BUG ? function propertyIsEnumerable(V) {
+ var descriptor = getOwnPropertyDescriptor(this, V);
+ return !!descriptor && descriptor.enumerable;
+} : $propertyIsEnumerable;
+
+
+/***/ },
+
+/***/ 2967
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+/* eslint-disable no-proto -- safe */
+var uncurryThisAccessor = __webpack_require__(6706);
+var isObject = __webpack_require__(34);
+var requireObjectCoercible = __webpack_require__(7750);
+var aPossiblePrototype = __webpack_require__(3506);
+
+// `Object.setPrototypeOf` method
+// https://tc39.es/ecma262/#sec-object.setprototypeof
+// Works with __proto__ only. Old v8 can't work with null proto objects.
+// eslint-disable-next-line es/no-object-setprototypeof -- safe
+module.exports = Object.setPrototypeOf || ('__proto__' in {} ? function () {
+ var CORRECT_SETTER = false;
+ var test = {};
+ var setter;
+ try {
+ setter = uncurryThisAccessor(Object.prototype, '__proto__', 'set');
+ setter(test, []);
+ CORRECT_SETTER = test instanceof Array;
+ } catch (error) { /* empty */ }
+ return function setPrototypeOf(O, proto) {
+ requireObjectCoercible(O);
+ aPossiblePrototype(proto);
+ if (!isObject(O)) return O;
+ if (CORRECT_SETTER) setter(O, proto);
+ else O.__proto__ = proto;
+ return O;
+ };
+}() : undefined);
+
+
+/***/ },
+
+/***/ 4270
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var call = __webpack_require__(9565);
+var isCallable = __webpack_require__(4901);
+var isObject = __webpack_require__(34);
+
+var $TypeError = TypeError;
+
+// `OrdinaryToPrimitive` abstract operation
+// https://tc39.es/ecma262/#sec-ordinarytoprimitive
+module.exports = function (input, pref) {
+ var fn, val;
+ if (pref === 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;
+ if (isCallable(fn = input.valueOf) && !isObject(val = call(fn, input))) return val;
+ if (pref !== 'string' && isCallable(fn = input.toString) && !isObject(val = call(fn, input))) return val;
+ throw new $TypeError("Can't convert object to primitive value");
+};
+
+
+/***/ },
+
+/***/ 5031
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var getBuiltIn = __webpack_require__(7751);
+var uncurryThis = __webpack_require__(9504);
+var getOwnPropertyNamesModule = __webpack_require__(8480);
+var getOwnPropertySymbolsModule = __webpack_require__(3717);
+var anObject = __webpack_require__(8551);
+
+var concat = uncurryThis([].concat);
+
+// all object keys, includes non-enumerable and symbols
+module.exports = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) {
+ var keys = getOwnPropertyNamesModule.f(anObject(it));
+ var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;
+ return getOwnPropertySymbols ? concat(keys, getOwnPropertySymbols(it)) : keys;
+};
+
+
+/***/ },
+
+/***/ 8235
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var hasOwn = __webpack_require__(9297);
+
+var $SyntaxError = SyntaxError;
+var $parseInt = parseInt;
+var fromCharCode = String.fromCharCode;
+var at = uncurryThis(''.charAt);
+var slice = uncurryThis(''.slice);
+var exec = uncurryThis(/./.exec);
+
+var codePoints = {
+ '\\"': '"',
+ '\\\\': '\\',
+ '\\/': '/',
+ '\\b': '\b',
+ '\\f': '\f',
+ '\\n': '\n',
+ '\\r': '\r',
+ '\\t': '\t'
+};
+
+var IS_4_HEX_DIGITS = /^[\da-f]{4}$/i;
+// eslint-disable-next-line regexp/no-control-character -- safe
+var IS_C0_CONTROL_CODE = /^[\u0000-\u001F]$/;
+
+module.exports = function (source, i) {
+ var unterminated = true;
+ var value = '';
+ while (i < source.length) {
+ var chr = at(source, i);
+ if (chr === '\\') {
+ var twoChars = slice(source, i, i + 2);
+ if (hasOwn(codePoints, twoChars)) {
+ value += codePoints[twoChars];
+ i += 2;
+ } else if (twoChars === '\\u') {
+ i += 2;
+ var fourHexDigits = slice(source, i, i + 4);
+ if (!exec(IS_4_HEX_DIGITS, fourHexDigits)) throw new $SyntaxError('Bad Unicode escape at: ' + i);
+ value += fromCharCode($parseInt(fourHexDigits, 16));
+ i += 4;
+ } else throw new $SyntaxError('Unknown escape sequence: "' + twoChars + '"');
+ } else if (chr === '"') {
+ unterminated = false;
+ i++;
+ break;
+ } else {
+ if (exec(IS_C0_CONTROL_CODE, chr)) throw new $SyntaxError('Bad control character in string literal at: ' + i);
+ value += chr;
+ i++;
+ }
+ }
+ if (unterminated) throw new $SyntaxError('Unterminated string at: ' + i);
+ return { value: value, end: i };
+};
+
+
+/***/ },
+
+/***/ 7750
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var isNullOrUndefined = __webpack_require__(4117);
+
+var $TypeError = TypeError;
+
+// `RequireObjectCoercible` abstract operation
+// https://tc39.es/ecma262/#sec-requireobjectcoercible
+module.exports = function (it) {
+ if (isNullOrUndefined(it)) throw new $TypeError("Can't call method on " + it);
+ return it;
+};
+
+
+/***/ },
+
+/***/ 9286
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var SetHelpers = __webpack_require__(4402);
+var iterate = __webpack_require__(8469);
+
+var Set = SetHelpers.Set;
+var add = SetHelpers.add;
+
+module.exports = function (set) {
+ var result = new Set();
+ iterate(set, function (it) {
+ add(result, it);
+ });
+ return result;
+};
+
+
+/***/ },
+
+/***/ 3440
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var SetHelpers = __webpack_require__(4402);
+var clone = __webpack_require__(9286);
+var size = __webpack_require__(5170);
+var getSetRecord = __webpack_require__(3789);
+var iterateSet = __webpack_require__(8469);
+var iterateSimple = __webpack_require__(507);
+
+var has = SetHelpers.has;
+var remove = SetHelpers.remove;
+
+// `Set.prototype.difference` method
+// https://tc39.es/ecma262/#sec-set.prototype.difference
+module.exports = function difference(other) {
+ var O = aSet(this);
+ var otherRec = getSetRecord(other);
+ var result = clone(O);
+ if (size(result) <= otherRec.size) iterateSet(result, function (e) {
+ if (otherRec.includes(e)) remove(result, e);
+ });
+ else iterateSimple(otherRec.getIterator(), function (e) {
+ if (has(result, e)) remove(result, e);
+ });
+ return result;
+};
+
+
+/***/ },
+
+/***/ 4402
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+// eslint-disable-next-line es/no-set -- safe
+var SetPrototype = Set.prototype;
+
+module.exports = {
+ // eslint-disable-next-line es/no-set -- safe
+ Set: Set,
+ add: uncurryThis(SetPrototype.add),
+ has: uncurryThis(SetPrototype.has),
+ remove: uncurryThis(SetPrototype['delete']),
+ proto: SetPrototype
+};
+
+
+/***/ },
+
+/***/ 8750
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var SetHelpers = __webpack_require__(4402);
+var size = __webpack_require__(5170);
+var getSetRecord = __webpack_require__(3789);
+var iterateSet = __webpack_require__(8469);
+var iterateSimple = __webpack_require__(507);
+
+var Set = SetHelpers.Set;
+var add = SetHelpers.add;
+var has = SetHelpers.has;
+
+// `Set.prototype.intersection` method
+// https://tc39.es/ecma262/#sec-set.prototype.intersection
+module.exports = function intersection(other) {
+ var O = aSet(this);
+ var otherRec = getSetRecord(other);
+ var result = new Set();
+
+ if (size(O) > otherRec.size) {
+ iterateSimple(otherRec.getIterator(), function (e) {
+ if (has(O, e)) add(result, e);
+ });
+ } else {
+ iterateSet(O, function (e) {
+ if (otherRec.includes(e)) add(result, e);
+ });
+ }
+
+ return result;
+};
+
+
+/***/ },
+
+/***/ 4449
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var has = (__webpack_require__(4402).has);
+var size = __webpack_require__(5170);
+var getSetRecord = __webpack_require__(3789);
+var iterateSet = __webpack_require__(8469);
+var iterateSimple = __webpack_require__(507);
+var iteratorClose = __webpack_require__(9539);
+
+// `Set.prototype.isDisjointFrom` method
+// https://tc39.es/ecma262/#sec-set.prototype.isdisjointfrom
+module.exports = function isDisjointFrom(other) {
+ var O = aSet(this);
+ var otherRec = getSetRecord(other);
+ if (size(O) <= otherRec.size) return iterateSet(O, function (e) {
+ if (otherRec.includes(e)) return false;
+ }, true) !== false;
+ var iterator = otherRec.getIterator();
+ return iterateSimple(iterator, function (e) {
+ if (has(O, e)) return iteratorClose(iterator.iterator, 'normal', false);
+ }) !== false;
+};
+
+
+/***/ },
+
+/***/ 3838
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var size = __webpack_require__(5170);
+var iterate = __webpack_require__(8469);
+var getSetRecord = __webpack_require__(3789);
+
+// `Set.prototype.isSubsetOf` method
+// https://tc39.es/ecma262/#sec-set.prototype.issubsetof
+module.exports = function isSubsetOf(other) {
+ var O = aSet(this);
+ var otherRec = getSetRecord(other);
+ if (size(O) > otherRec.size) return false;
+ return iterate(O, function (e) {
+ if (!otherRec.includes(e)) return false;
+ }, true) !== false;
+};
+
+
+/***/ },
+
+/***/ 8527
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var has = (__webpack_require__(4402).has);
+var size = __webpack_require__(5170);
+var getSetRecord = __webpack_require__(3789);
+var iterateSimple = __webpack_require__(507);
+var iteratorClose = __webpack_require__(9539);
+
+// `Set.prototype.isSupersetOf` method
+// https://tc39.es/ecma262/#sec-set.prototype.issupersetof
+module.exports = function isSupersetOf(other) {
+ var O = aSet(this);
+ var otherRec = getSetRecord(other);
+ if (size(O) < otherRec.size) return false;
+ var iterator = otherRec.getIterator();
+ return iterateSimple(iterator, function (e) {
+ if (!has(O, e)) return iteratorClose(iterator.iterator, 'normal', false);
+ }) !== false;
+};
+
+
+/***/ },
+
+/***/ 8469
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var iterateSimple = __webpack_require__(507);
+var SetHelpers = __webpack_require__(4402);
+
+var Set = SetHelpers.Set;
+var SetPrototype = SetHelpers.proto;
+var forEach = uncurryThis(SetPrototype.forEach);
+var keys = uncurryThis(SetPrototype.keys);
+var next = keys(new Set()).next;
+
+module.exports = function (set, fn, interruptible) {
+ return interruptible ? iterateSimple({ iterator: keys(set), next: next }, fn) : forEach(set, fn);
+};
+
+
+/***/ },
+
+/***/ 4916
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var getBuiltIn = __webpack_require__(7751);
+
+var createSetLike = function (size) {
+ return {
+ size: size,
+ has: function () {
+ return false;
+ },
+ keys: function () {
+ return {
+ next: function () {
+ return { done: true };
+ }
+ };
+ }
+ };
+};
+
+var createSetLikeWithInfinitySize = function (size) {
+ return {
+ size: size,
+ has: function () {
+ return true;
+ },
+ keys: function () {
+ throw new Error('e');
+ }
+ };
+};
+
+module.exports = function (name, callback) {
+ var Set = getBuiltIn('Set');
+ try {
+ new Set()[name](createSetLike(0));
+ try {
+ // late spec change, early WebKit ~ Safari 17 implementation does not pass it
+ // https://github.com/tc39/proposal-set-methods/pull/88
+ // also covered engines with
+ // https://bugs.webkit.org/show_bug.cgi?id=272679
+ new Set()[name](createSetLike(-1));
+ return false;
+ } catch (error2) {
+ if (!callback) return true;
+ // early V8 implementation bug
+ // https://issues.chromium.org/issues/351332634
+ try {
+ new Set()[name](createSetLikeWithInfinitySize(-Infinity));
+ return false;
+ } catch (error) {
+ var set = new Set([1, 2]);
+ return callback(set[name](createSetLikeWithInfinitySize(Infinity)));
+ }
+ }
+ } catch (error) {
+ return false;
+ }
+};
+
+
+/***/ },
+
+/***/ 9835
+(module) {
+
+
+// Should get iterator record of a set-like object before cloning this
+// https://bugs.webkit.org/show_bug.cgi?id=289430
+module.exports = function (METHOD_NAME) {
+ try {
+ // eslint-disable-next-line es/no-set -- needed for test
+ var baseSet = new Set();
+ var setLike = {
+ size: 0,
+ has: function () { return true; },
+ keys: function () {
+ // eslint-disable-next-line es/no-object-defineproperty -- needed for test
+ return Object.defineProperty({}, 'next', {
+ get: function () {
+ baseSet.clear();
+ baseSet.add(4);
+ return function () {
+ return { done: true };
+ };
+ }
+ });
+ }
+ };
+ var result = baseSet[METHOD_NAME](setLike);
+
+ return result.size === 1 && result.values().next().value === 4;
+ } catch (error) {
+ return false;
+ }
+};
+
+
+/***/ },
+
+/***/ 5170
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThisAccessor = __webpack_require__(6706);
+var SetHelpers = __webpack_require__(4402);
+
+module.exports = uncurryThisAccessor(SetHelpers.proto, 'size', 'get') || function (set) {
+ return set.size;
+};
+
+
+/***/ },
+
+/***/ 3650
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var SetHelpers = __webpack_require__(4402);
+var clone = __webpack_require__(9286);
+var getSetRecord = __webpack_require__(3789);
+var iterateSimple = __webpack_require__(507);
+
+var add = SetHelpers.add;
+var has = SetHelpers.has;
+var remove = SetHelpers.remove;
+
+// `Set.prototype.symmetricDifference` method
+// https://tc39.es/ecma262/#sec-set.prototype.symmetricdifference
+module.exports = function symmetricDifference(other) {
+ var O = aSet(this);
+ var keysIter = getSetRecord(other).getIterator();
+ var result = clone(O);
+ iterateSimple(keysIter, function (e) {
+ if (has(O, e)) remove(result, e);
+ else add(result, e);
+ });
+ return result;
+};
+
+
+/***/ },
+
+/***/ 4204
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var aSet = __webpack_require__(7080);
+var add = (__webpack_require__(4402).add);
+var clone = __webpack_require__(9286);
+var getSetRecord = __webpack_require__(3789);
+var iterateSimple = __webpack_require__(507);
+
+// `Set.prototype.union` method
+// https://tc39.es/ecma262/#sec-set.prototype.union
+module.exports = function union(other) {
+ var O = aSet(this);
+ var keysIter = getSetRecord(other).getIterator();
+ var result = clone(O);
+ iterateSimple(keysIter, function (it) {
+ add(result, it);
+ });
+ return result;
+};
+
+
+/***/ },
+
+/***/ 6119
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var shared = __webpack_require__(5745);
+var uid = __webpack_require__(3392);
+
+var keys = shared('keys');
+
+module.exports = function (key) {
+ return keys[key] || (keys[key] = uid(key));
+};
+
+
+/***/ },
+
+/***/ 7629
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var IS_PURE = __webpack_require__(6395);
+var globalThis = __webpack_require__(4576);
+var defineGlobalProperty = __webpack_require__(9433);
+
+var SHARED = '__core-js_shared__';
+var store = module.exports = globalThis[SHARED] || defineGlobalProperty(SHARED, {});
+
+(store.versions || (store.versions = [])).push({
+ version: '3.50.0',
+ mode: IS_PURE ? 'pure' : 'global',
+ copyright: '© 2013–2025 Denis Pushkarev (zloirock.ru), 2025–2026 CoreJS Company (core-js.io). All rights reserved.',
+ license: 'https://github.com/zloirock/core-js/blob/v3.50.0/LICENSE',
+ source: 'https://github.com/zloirock/core-js'
+});
+
+
+/***/ },
+
+/***/ 5745
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var store = __webpack_require__(7629);
+// eslint-disable-next-line es/no-object-create -- safe
+var create = Object.create || Object;
+
+module.exports = function (key, value) {
+ return store[key] || (store[key] = value || create(null));
+};
+
+
+/***/ },
+
+/***/ 533
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+var toLength = __webpack_require__(8014);
+var toString = __webpack_require__(655);
+var $repeat = __webpack_require__(2333);
+var requireObjectCoercible = __webpack_require__(7750);
+
+var repeat = uncurryThis($repeat);
+var stringSlice = uncurryThis(''.slice);
+var ceil = Math.ceil;
+
+// `String.prototype.{ padStart, padEnd }` methods implementation
+var createMethod = function (IS_END) {
+ return function ($this, maxLength, fillString) {
+ var S = toString(requireObjectCoercible($this));
+ var intMaxLength = toLength(maxLength);
+ var stringLength = S.length;
+ if (intMaxLength <= stringLength) return S;
+ var fillStr = fillString === undefined ? ' ' : toString(fillString);
+ var fillLen, stringFiller;
+ if (fillStr === '') return S;
+ fillLen = intMaxLength - stringLength;
+ stringFiller = repeat(fillStr, ceil(fillLen / fillStr.length));
+ if (stringFiller.length > fillLen) stringFiller = stringSlice(stringFiller, 0, fillLen);
+ return IS_END ? S + stringFiller : stringFiller + S;
+ };
+};
+
+module.exports = {
+ // `String.prototype.padStart` method
+ // https://tc39.es/ecma262/#sec-string.prototype.padstart
+ start: createMethod(false),
+ // `String.prototype.padEnd` method
+ // https://tc39.es/ecma262/#sec-string.prototype.padend
+ end: createMethod(true)
+};
+
+
+/***/ },
+
+/***/ 2333
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toIntegerOrInfinity = __webpack_require__(1291);
+var toString = __webpack_require__(655);
+var requireObjectCoercible = __webpack_require__(7750);
+
+var $RangeError = RangeError;
+var floor = Math.floor;
+
+// `String.prototype.repeat` method implementation
+// https://tc39.es/ecma262/#sec-string.prototype.repeat
+module.exports = function repeat(count) {
+ var str = toString(requireObjectCoercible(this));
+ var result = '';
+ var n = toIntegerOrInfinity(count);
+ if (n < 0 || n === Infinity) throw new $RangeError('Wrong number of repetitions');
+ for (;n > 0; (n = floor(n / 2)) && (str += str)) if (n % 2) result += str;
+ return result;
+};
+
+
+/***/ },
+
+/***/ 4495
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+/* eslint-disable es/no-symbol -- required for testing */
+var V8_VERSION = __webpack_require__(9519);
+var fails = __webpack_require__(9039);
+var globalThis = __webpack_require__(4576);
+
+var $String = globalThis.String;
+
+// eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
+module.exports = !!Object.getOwnPropertySymbols && !fails(function () {
+ var symbol = Symbol('symbol detection');
+ // Chrome 38 Symbol has incorrect toString conversion
+ // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
+ // nb: Do not call `String` directly to avoid this being optimized out to `symbol+''` which will,
+ // of course, fail.
+ return !$String(symbol) || !(Object(symbol) instanceof Symbol) ||
+ // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
+ !Symbol.sham && V8_VERSION && V8_VERSION < 41;
+});
+
+
+/***/ },
+
+/***/ 1240
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+// `thisNumberValue` abstract operation
+// https://tc39.es/ecma262/#sec-thisnumbervalue
+module.exports = uncurryThis(1.1.valueOf);
+
+
+/***/ },
+
+/***/ 5610
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toIntegerOrInfinity = __webpack_require__(1291);
+
+var max = Math.max;
+var min = Math.min;
+
+// Helper for a popular repeating case of the spec:
+// Let integer be ? ToInteger(index).
+// If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
+module.exports = function (index, length) {
+ var integer = toIntegerOrInfinity(index);
+ return integer < 0 ? max(integer + length, 0) : min(integer, length);
+};
+
+
+/***/ },
+
+/***/ 5854
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toPrimitive = __webpack_require__(2777);
+
+var $TypeError = TypeError;
+
+// `ToBigInt` abstract operation
+// https://tc39.es/ecma262/#sec-tobigint
+module.exports = function (argument) {
+ var prim = toPrimitive(argument, 'number');
+ if (typeof prim == 'number') throw new $TypeError("Can't convert number to bigint");
+ // eslint-disable-next-line es/no-bigint -- safe
+ return BigInt(prim);
+};
+
+
+/***/ },
+
+/***/ 5397
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+// toObject with fallback for non-array-like ES3 strings
+var IndexedObject = __webpack_require__(7055);
+var requireObjectCoercible = __webpack_require__(7750);
+
+module.exports = function (it) {
+ return IndexedObject(requireObjectCoercible(it));
+};
+
+
+/***/ },
+
+/***/ 1291
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var trunc = __webpack_require__(741);
+
+// `ToIntegerOrInfinity` abstract operation
+// https://tc39.es/ecma262/#sec-tointegerorinfinity
+module.exports = function (argument) {
+ var number = +argument;
+ // eslint-disable-next-line no-self-compare -- NaN check
+ return number !== number || number === 0 ? 0 : trunc(number);
+};
+
+
+/***/ },
+
+/***/ 8014
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toIntegerOrInfinity = __webpack_require__(1291);
+
+var min = Math.min;
+
+// `ToLength` abstract operation
+// https://tc39.es/ecma262/#sec-tolength
+module.exports = function (argument) {
+ var len = toIntegerOrInfinity(argument);
+ return len > 0 ? min(len, 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
+};
+
+
+/***/ },
+
+/***/ 8981
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var requireObjectCoercible = __webpack_require__(7750);
+
+var $Object = Object;
+
+// `ToObject` abstract operation
+// https://tc39.es/ecma262/#sec-toobject
+module.exports = function (argument) {
+ return $Object(requireObjectCoercible(argument));
+};
+
+
+/***/ },
+
+/***/ 2777
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var call = __webpack_require__(9565);
+var isObject = __webpack_require__(34);
+var isSymbol = __webpack_require__(757);
+var getMethod = __webpack_require__(5966);
+var ordinaryToPrimitive = __webpack_require__(4270);
+var wellKnownSymbol = __webpack_require__(8227);
+
+var $TypeError = TypeError;
+var TO_PRIMITIVE = wellKnownSymbol('toPrimitive');
+
+// `ToPrimitive` abstract operation
+// https://tc39.es/ecma262/#sec-toprimitive
+module.exports = function (input, pref) {
+ if (!isObject(input) || isSymbol(input)) return input;
+ var exoticToPrim = getMethod(input, TO_PRIMITIVE);
+ var result;
+ if (exoticToPrim) {
+ if (pref === undefined) pref = 'default';
+ result = call(exoticToPrim, input, pref);
+ if (!isObject(result) || isSymbol(result)) return result;
+ throw new $TypeError("Can't convert object to primitive value");
+ }
+ if (pref === undefined) pref = 'number';
+ return ordinaryToPrimitive(input, pref);
+};
+
+
+/***/ },
+
+/***/ 6969
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var toPrimitive = __webpack_require__(2777);
+var isSymbol = __webpack_require__(757);
+
+// `ToPropertyKey` abstract operation
+// https://tc39.es/ecma262/#sec-topropertykey
+module.exports = function (argument) {
+ var key = toPrimitive(argument, 'string');
+ return isSymbol(key) ? key : key + '';
+};
+
+
+/***/ },
+
+/***/ 2140
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var wellKnownSymbol = __webpack_require__(8227);
+
+var TO_STRING_TAG = wellKnownSymbol('toStringTag');
+var test = {};
+// eslint-disable-next-line unicorn/no-immediate-mutation -- ES3 syntax limitation
+test[TO_STRING_TAG] = 'z';
+
+module.exports = String(test) === '[object z]';
+
+
+/***/ },
+
+/***/ 655
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var classof = __webpack_require__(6955);
+
+var $String = String;
+
+module.exports = function (argument) {
+ if (classof(argument) === 'Symbol') throw new TypeError('Cannot convert a Symbol value to a string');
+ return $String(argument);
+};
+
+
+/***/ },
+
+/***/ 6823
+(module) {
+
+
+var $String = String;
+
+module.exports = function (argument) {
+ try {
+ return $String(argument);
+ } catch (error) {
+ return 'Object';
+ }
+};
+
+
+/***/ },
+
+/***/ 3392
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+var id = 0;
+var postfix = Math.random();
+var toString = uncurryThis(1.1.toString);
+
+module.exports = function (key) {
+ return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36);
+};
+
+
+/***/ },
+
+/***/ 7416
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var fails = __webpack_require__(9039);
+var wellKnownSymbol = __webpack_require__(8227);
+var DESCRIPTORS = __webpack_require__(3724);
+var IS_PURE = __webpack_require__(6395);
+
+var ITERATOR = wellKnownSymbol('iterator');
+
+module.exports = !fails(function () {
+ // eslint-disable-next-line unicorn/relative-url-style -- required for testing
+ var url = new URL('b?a=1&b=2&c=3', 'https://a');
+ var params = url.searchParams;
+ var params2 = new URLSearchParams('a=1&a=2&b=3');
+ var result = '';
+ url.pathname = 'c%20d';
+ params.forEach(function (value, key) {
+ params['delete']('b');
+ result += key + value;
+ });
+ params2['delete']('a', 2);
+ // `undefined` case is a Chromium 117 bug
+ // https://bugs.chromium.org/p/v8/issues/detail?id=14222
+ params2['delete']('b', undefined);
+ return (IS_PURE && (!url.toJSON || !params2.has('a', 1) || params2.has('a', 2) || !params2.has('a', undefined) || params2.has('b')))
+ || (!params.size && (IS_PURE || !DESCRIPTORS))
+ || !params.sort
+ || url.href !== 'https://a/c%20d?a=1&c=3'
+ || params.get('c') !== '3'
+ || String(new URLSearchParams('?a=1')) !== 'a=1'
+ || !params[ITERATOR]
+ // throws in Edge
+ || new URL('https://a@b').username !== 'a'
+ || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
+ // not punycoded in Edge
+ || new URL('https://тест').host !== 'xn--e1aybc'
+ // not escaped in Chrome 62-
+ || new URL('https://a#б').hash !== '#%D0%B1'
+ // fails in Chrome 66-
+ || result !== 'a1c3'
+ // throws in Safari
+ || new URL('https://x', undefined).host !== 'x';
+});
+
+
+/***/ },
+
+/***/ 7040
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+/* eslint-disable es/no-symbol -- required for testing */
+var NATIVE_SYMBOL = __webpack_require__(4495);
+
+module.exports = NATIVE_SYMBOL &&
+ !Symbol.sham &&
+ typeof Symbol.iterator == 'symbol';
+
+
+/***/ },
+
+/***/ 8686
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var DESCRIPTORS = __webpack_require__(3724);
+var fails = __webpack_require__(9039);
+
+// V8 ~ Chrome 36-
+// https://bugs.chromium.org/p/v8/issues/detail?id=3334
+module.exports = DESCRIPTORS && fails(function () {
+ // eslint-disable-next-line es/no-object-defineproperty -- required for testing
+ return Object.defineProperty(function () { /* empty */ }, 'prototype', {
+ value: 42,
+ writable: false
+ }).prototype !== 42;
+});
+
+
+/***/ },
+
+/***/ 2812
+(module) {
+
+
+var $TypeError = TypeError;
+
+module.exports = function (passed, required) {
+ if (passed < required) throw new $TypeError('Not enough arguments');
+ return passed;
+};
+
+
+/***/ },
+
+/***/ 8622
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+var isCallable = __webpack_require__(4901);
+
+var WeakMap = globalThis.WeakMap;
+
+module.exports = isCallable(WeakMap) && /native code/.test(String(WeakMap));
+
+
+/***/ },
+
+/***/ 4995
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var uncurryThis = __webpack_require__(9504);
+
+// eslint-disable-next-line es/no-weak-map -- safe
+var WeakMapPrototype = WeakMap.prototype;
+
+module.exports = {
+ // eslint-disable-next-line es/no-weak-map -- safe
+ WeakMap: WeakMap,
+ set: uncurryThis(WeakMapPrototype.set),
+ get: uncurryThis(WeakMapPrototype.get),
+ has: uncurryThis(WeakMapPrototype.has),
+ remove: uncurryThis(WeakMapPrototype['delete'])
+};
+
+
+/***/ },
+
+/***/ 8227
+(module, __unused_webpack_exports, __webpack_require__) {
+
+
+var globalThis = __webpack_require__(4576);
+var shared = __webpack_require__(5745);
+var hasOwn = __webpack_require__(9297);
+var uid = __webpack_require__(3392);
+var NATIVE_SYMBOL = __webpack_require__(4495);
+var USE_SYMBOL_AS_UID = __webpack_require__(7040);
+
+var Symbol = globalThis.Symbol;
+var WellKnownSymbolsStore = shared('wks');
+var createWellKnownSymbol = USE_SYMBOL_AS_UID ? Symbol['for'] || Symbol : Symbol && Symbol.withoutSetter || uid;
+
+module.exports = function (name) {
+ if (!hasOwn(WellKnownSymbolsStore, name)) {
+ WellKnownSymbolsStore[name] = NATIVE_SYMBOL && hasOwn(Symbol, name)
+ ? Symbol[name]
+ : createWellKnownSymbol('Symbol.' + name);
+ } return WellKnownSymbolsStore[name];
+};
+
+
+/***/ },
+
+/***/ 7452
+(module) {
+
+
+// a string of all valid unicode whitespaces
+module.exports = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' +
+ '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
+
+
+/***/ },
+
+/***/ 4423
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var $includes = (__webpack_require__(9617).includes);
+var fails = __webpack_require__(9039);
+var addToUnscopables = __webpack_require__(6469);
+
+// FF99+ bug
+var BROKEN_ON_SPARSE = fails(function () {
+ // eslint-disable-next-line es/no-array-prototype-includes -- detection
+ return !Array(1).includes();
+});
+
+// Safari 26.4- bug
+var BROKEN_ON_SPARSE_WITH_FROM_INDEX = fails(function () {
+ // eslint-disable-next-line no-sparse-arrays, es/no-array-prototype-includes -- detection
+ return [, 1].includes(undefined, 1);
+});
+
+// `Array.prototype.includes` method
+// https://tc39.es/ecma262/#sec-array.prototype.includes
+$({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE || BROKEN_ON_SPARSE_WITH_FROM_INDEX }, {
+ includes: function includes(el /* , fromIndex = 0 */) {
+ return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
+ }
+});
+
+// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
+addToUnscopables('includes');
+
+
+/***/ },
+
+/***/ 4114
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var toObject = __webpack_require__(8981);
+var lengthOfArrayLike = __webpack_require__(6198);
+var setArrayLength = __webpack_require__(4527);
+var doesNotExceedSafeInteger = __webpack_require__(6837);
+var fails = __webpack_require__(9039);
+
+var INCORRECT_TO_LENGTH = fails(function () {
+ return [].push.call({ length: 0x100000000 }, 1) !== 4294967297;
+});
+
+// V8 <= 121 and Safari <= 15.4; FF < 23 throws InternalError
+// https://bugs.chromium.org/p/v8/issues/detail?id=12681
+var properErrorOnNonWritableLength = function () {
+ try {
+ // eslint-disable-next-line es/no-object-defineproperty -- safe
+ Object.defineProperty([], 'length', { writable: false }).push();
+ } catch (error) {
+ return error instanceof TypeError;
+ }
+};
+
+var FORCED = INCORRECT_TO_LENGTH || !properErrorOnNonWritableLength();
+
+// `Array.prototype.push` method
+// https://tc39.es/ecma262/#sec-array.prototype.push
+$({ target: 'Array', proto: true, arity: 1, forced: FORCED }, {
+ // eslint-disable-next-line no-unused-vars -- required for `.length`
+ push: function push(item) {
+ var O = toObject(this);
+ var len = lengthOfArrayLike(O);
+ var argCount = arguments.length;
+ doesNotExceedSafeInteger(len + argCount);
+ for (var i = 0; i < argCount; i++) {
+ O[len] = arguments[i];
+ len++;
+ }
+ setArrayLength(O, len);
+ return len;
+ }
+});
+
+
+/***/ },
+
+/***/ 8111
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var globalThis = __webpack_require__(4576);
+var anInstance = __webpack_require__(679);
+var anObject = __webpack_require__(8551);
+var isCallable = __webpack_require__(4901);
+var getPrototypeOf = __webpack_require__(2787);
+var defineBuiltInAccessor = __webpack_require__(2106);
+var createProperty = __webpack_require__(4659);
+var fails = __webpack_require__(9039);
+var hasOwn = __webpack_require__(9297);
+var wellKnownSymbol = __webpack_require__(8227);
+var IteratorPrototype = (__webpack_require__(7657).IteratorPrototype);
+var DESCRIPTORS = __webpack_require__(3724);
+var IS_PURE = __webpack_require__(6395);
+
+var CONSTRUCTOR = 'constructor';
+var ITERATOR = 'Iterator';
+var TO_STRING_TAG = wellKnownSymbol('toStringTag');
+
+var $TypeError = TypeError;
+var NativeIterator = globalThis[ITERATOR];
+
+// FF56- have non-standard global helper `Iterator`
+var FORCED = IS_PURE
+ || !isCallable(NativeIterator)
+ || NativeIterator.prototype !== IteratorPrototype
+ // FF44- non-standard `Iterator` passes previous tests
+ || !fails(function () { NativeIterator({}); });
+
+var IteratorConstructor = function Iterator() {
+ anInstance(this, IteratorPrototype);
+ if (getPrototypeOf(this) === IteratorPrototype) throw new $TypeError('Abstract class Iterator not directly constructable');
+};
+
+var defineIteratorPrototypeAccessor = function (key, value) {
+ if (DESCRIPTORS) {
+ defineBuiltInAccessor(IteratorPrototype, key, {
+ configurable: true,
+ get: function () {
+ return value;
+ },
+ set: function (replacement) {
+ anObject(this);
+ if (this === IteratorPrototype) throw new $TypeError("You can't redefine this property");
+ if (hasOwn(this, key)) this[key] = replacement;
+ else createProperty(this, key, replacement);
+ }
+ });
+ } else IteratorPrototype[key] = value;
+};
+
+if (!hasOwn(IteratorPrototype, TO_STRING_TAG)) defineIteratorPrototypeAccessor(TO_STRING_TAG, ITERATOR);
+
+if (FORCED || !hasOwn(IteratorPrototype, CONSTRUCTOR) || IteratorPrototype[CONSTRUCTOR] === Object) {
+ defineIteratorPrototypeAccessor(CONSTRUCTOR, IteratorConstructor);
+}
+
+IteratorConstructor.prototype = IteratorPrototype;
+
+// `Iterator` constructor
+// https://tc39.es/ecma262/#sec-iterator
+$({ global: true, constructor: true, forced: FORCED }, {
+ Iterator: IteratorConstructor
+});
+
+
+/***/ },
+
+/***/ 1148
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var call = __webpack_require__(9565);
+var iterate = __webpack_require__(2652);
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var getIteratorDirect = __webpack_require__(1767);
+var iteratorClose = __webpack_require__(9539);
+var iteratorHelperWithoutClosingOnEarlyError = __webpack_require__(4549);
+
+var everyWithoutClosingOnEarlyError = iteratorHelperWithoutClosingOnEarlyError('every', TypeError);
+
+// `Iterator.prototype.every` method
+// https://tc39.es/ecma262/#sec-iterator.prototype.every
+$({ target: 'Iterator', proto: true, real: true, forced: everyWithoutClosingOnEarlyError }, {
+ every: function every(predicate) {
+ anObject(this);
+ try {
+ aCallable(predicate);
+ } catch (error) {
+ iteratorClose(this, 'throw', error);
+ }
+
+ if (everyWithoutClosingOnEarlyError) return call(everyWithoutClosingOnEarlyError, this, predicate);
+
+ var record = getIteratorDirect(this);
+ var counter = 0;
+ return !iterate(record, function (value, stop) {
+ if (!predicate(value, counter++)) return stop();
+ }, { IS_RECORD: true, INTERRUPTED: true }).stopped;
+ }
+});
+
+
+/***/ },
+
+/***/ 2489
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var call = __webpack_require__(9565);
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var getIteratorDirect = __webpack_require__(1767);
+var createIteratorProxy = __webpack_require__(9462);
+var callWithSafeIterationClosing = __webpack_require__(6319);
+var IS_PURE = __webpack_require__(6395);
+var iteratorClose = __webpack_require__(9539);
+var iteratorHelperThrowsOnInvalidIterator = __webpack_require__(684);
+var iteratorHelperWithoutClosingOnEarlyError = __webpack_require__(4549);
+
+var FILTER_WITHOUT_THROWING_ON_INVALID_ITERATOR = !IS_PURE && !iteratorHelperThrowsOnInvalidIterator('filter', function () { /* empty */ });
+var filterWithoutClosingOnEarlyError = !IS_PURE && !FILTER_WITHOUT_THROWING_ON_INVALID_ITERATOR
+ && iteratorHelperWithoutClosingOnEarlyError('filter', TypeError);
+
+var FORCED = IS_PURE || FILTER_WITHOUT_THROWING_ON_INVALID_ITERATOR || filterWithoutClosingOnEarlyError;
+
+var IteratorProxy = createIteratorProxy(function () {
+ var iterator = this.iterator;
+ var predicate = this.predicate;
+ var next = this.next;
+ var result, done, value;
+ while (true) {
+ result = anObject(call(next, iterator));
+ done = this.done = !!result.done;
+ if (done) return;
+ value = result.value;
+ if (callWithSafeIterationClosing(iterator, predicate, [value, this.counter++], true)) return value;
+ }
+});
+
+// `Iterator.prototype.filter` method
+// https://tc39.es/ecma262/#sec-iterator.prototype.filter
+$({ target: 'Iterator', proto: true, real: true, forced: FORCED }, {
+ filter: function filter(predicate) {
+ anObject(this);
+ try {
+ aCallable(predicate);
+ } catch (error) {
+ iteratorClose(this, 'throw', error);
+ }
+
+ if (filterWithoutClosingOnEarlyError) return call(filterWithoutClosingOnEarlyError, this, predicate);
+
+ return new IteratorProxy(getIteratorDirect(this), {
+ predicate: predicate
+ });
+ }
+});
+
+
+/***/ },
+
+/***/ 116
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var call = __webpack_require__(9565);
+var iterate = __webpack_require__(2652);
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var getIteratorDirect = __webpack_require__(1767);
+var iteratorClose = __webpack_require__(9539);
+var iteratorHelperWithoutClosingOnEarlyError = __webpack_require__(4549);
+
+var findWithoutClosingOnEarlyError = iteratorHelperWithoutClosingOnEarlyError('find', TypeError);
+
+// `Iterator.prototype.find` method
+// https://tc39.es/ecma262/#sec-iterator.prototype.find
+$({ target: 'Iterator', proto: true, real: true, forced: findWithoutClosingOnEarlyError }, {
+ find: function find(predicate) {
+ anObject(this);
+ try {
+ aCallable(predicate);
+ } catch (error) {
+ iteratorClose(this, 'throw', error);
+ }
+
+ if (findWithoutClosingOnEarlyError) return call(findWithoutClosingOnEarlyError, this, predicate);
+
+ var record = getIteratorDirect(this);
+ var counter = 0;
+ return iterate(record, function (value, stop) {
+ if (predicate(value, counter++)) return stop(value);
+ }, { IS_RECORD: true, INTERRUPTED: true }).result;
+ }
+});
+
+
+/***/ },
+
+/***/ 7588
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var call = __webpack_require__(9565);
+var iterate = __webpack_require__(2652);
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var getIteratorDirect = __webpack_require__(1767);
+var iteratorClose = __webpack_require__(9539);
+var iteratorHelperWithoutClosingOnEarlyError = __webpack_require__(4549);
+
+var forEachWithoutClosingOnEarlyError = iteratorHelperWithoutClosingOnEarlyError('forEach', TypeError);
+
+// `Iterator.prototype.forEach` method
+// https://tc39.es/ecma262/#sec-iterator.prototype.foreach
+$({ target: 'Iterator', proto: true, real: true, forced: forEachWithoutClosingOnEarlyError }, {
+ forEach: function forEach(fn) {
+ anObject(this);
+ try {
+ aCallable(fn);
+ } catch (error) {
+ iteratorClose(this, 'throw', error);
+ }
+
+ if (forEachWithoutClosingOnEarlyError) return call(forEachWithoutClosingOnEarlyError, this, fn);
+
+ var record = getIteratorDirect(this);
+ var counter = 0;
+ iterate(record, function (value) {
+ fn(value, counter++);
+ }, { IS_RECORD: true });
+ }
+});
+
+
+/***/ },
+
+/***/ 1701
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var call = __webpack_require__(9565);
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var getIteratorDirect = __webpack_require__(1767);
+var createIteratorProxy = __webpack_require__(9462);
+var callWithSafeIterationClosing = __webpack_require__(6319);
+var iteratorClose = __webpack_require__(9539);
+var iteratorHelperThrowsOnInvalidIterator = __webpack_require__(684);
+var iteratorHelperWithoutClosingOnEarlyError = __webpack_require__(4549);
+var IS_PURE = __webpack_require__(6395);
+
+var MAP_WITHOUT_THROWING_ON_INVALID_ITERATOR = !IS_PURE && !iteratorHelperThrowsOnInvalidIterator('map', function () { /* empty */ });
+var mapWithoutClosingOnEarlyError = !IS_PURE && !MAP_WITHOUT_THROWING_ON_INVALID_ITERATOR
+ && iteratorHelperWithoutClosingOnEarlyError('map', TypeError);
+
+var FORCED = IS_PURE || MAP_WITHOUT_THROWING_ON_INVALID_ITERATOR || mapWithoutClosingOnEarlyError;
+
+var IteratorProxy = createIteratorProxy(function () {
+ var iterator = this.iterator;
+ var result = anObject(call(this.next, iterator));
+ var done = this.done = !!result.done;
+ if (!done) return callWithSafeIterationClosing(iterator, this.mapper, [result.value, this.counter++], true);
+});
+
+// `Iterator.prototype.map` method
+// https://tc39.es/ecma262/#sec-iterator.prototype.map
+$({ target: 'Iterator', proto: true, real: true, forced: FORCED }, {
+ map: function map(mapper) {
+ anObject(this);
+ try {
+ aCallable(mapper);
+ } catch (error) {
+ iteratorClose(this, 'throw', error);
+ }
+
+ if (mapWithoutClosingOnEarlyError) return call(mapWithoutClosingOnEarlyError, this, mapper);
+
+ return new IteratorProxy(getIteratorDirect(this), {
+ mapper: mapper
+ });
+ }
+});
+
+
+/***/ },
+
+/***/ 3579
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var call = __webpack_require__(9565);
+var iterate = __webpack_require__(2652);
+var aCallable = __webpack_require__(9306);
+var anObject = __webpack_require__(8551);
+var getIteratorDirect = __webpack_require__(1767);
+var iteratorClose = __webpack_require__(9539);
+var iteratorHelperWithoutClosingOnEarlyError = __webpack_require__(4549);
+
+var someWithoutClosingOnEarlyError = iteratorHelperWithoutClosingOnEarlyError('some', TypeError);
+
+// `Iterator.prototype.some` method
+// https://tc39.es/ecma262/#sec-iterator.prototype.some
+$({ target: 'Iterator', proto: true, real: true, forced: someWithoutClosingOnEarlyError }, {
+ some: function some(predicate) {
+ anObject(this);
+ try {
+ aCallable(predicate);
+ } catch (error) {
+ iteratorClose(this, 'throw', error);
+ }
+
+ if (someWithoutClosingOnEarlyError) return call(someWithoutClosingOnEarlyError, this, predicate);
+
+ var record = getIteratorDirect(this);
+ var counter = 0;
+ return iterate(record, function (value, stop) {
+ if (predicate(value, counter++)) return stop();
+ }, { IS_RECORD: true, INTERRUPTED: true }).stopped;
+ }
+});
+
+
+/***/ },
+
+/***/ 9112
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var DESCRIPTORS = __webpack_require__(3724);
+var globalThis = __webpack_require__(4576);
+var getBuiltIn = __webpack_require__(7751);
+var uncurryThis = __webpack_require__(9504);
+var call = __webpack_require__(9565);
+var isCallable = __webpack_require__(4901);
+var isObject = __webpack_require__(34);
+var isArray = __webpack_require__(4376);
+var hasOwn = __webpack_require__(9297);
+var toString = __webpack_require__(655);
+var lengthOfArrayLike = __webpack_require__(6198);
+var createProperty = __webpack_require__(4659);
+var fails = __webpack_require__(9039);
+var parseJSONString = __webpack_require__(8235);
+var NATIVE_SYMBOL = __webpack_require__(4495);
+
+var JSON = globalThis.JSON;
+var Number = globalThis.Number;
+var SyntaxError = globalThis.SyntaxError;
+var nativeParse = JSON && JSON.parse;
+var enumerableOwnProperties = getBuiltIn('Object', 'keys');
+// eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
+var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+var at = uncurryThis(''.charAt);
+var slice = uncurryThis(''.slice);
+var exec = uncurryThis(/./.exec);
+var push = uncurryThis([].push);
+
+var IS_DIGIT = /^\d$/;
+var IS_NON_ZERO_DIGIT = /^[1-9]$/;
+var IS_NUMBER_START = /^[\d-]$/;
+var IS_WHITESPACE = /^[\t\n\r ]$/;
+
+var PRIMITIVE = 0;
+var OBJECT = 1;
+
+var $parse = function (source, reviver) {
+ source = toString(source);
+ var context = new Context(source, 0);
+ var root = context.parse();
+ var value = root.value;
+ var endIndex = context.skip(IS_WHITESPACE, root.end);
+ if (endIndex < source.length) {
+ throw new SyntaxError('Unexpected extra character: "' + at(source, endIndex) + '" after the parsed data at: ' + endIndex);
+ }
+ return isCallable(reviver) ? internalize({ '': value }, '', reviver, root) : value;
+};
+
+var internalize = function (holder, name, reviver, node) {
+ var val = holder[name];
+ var unmodified = node && val === node.value;
+ var context = unmodified && typeof node.source == 'string' ? { source: node.source } : {};
+ var elementRecordsLen, keys, len, i, P;
+ if (isObject(val)) {
+ var nodeIsArray = isArray(val);
+ var nodes = unmodified ? node.nodes : nodeIsArray ? [] : {};
+ if (nodeIsArray) {
+ elementRecordsLen = nodes.length;
+ len = lengthOfArrayLike(val);
+ for (i = 0; i < len; i++) {
+ internalizeProperty(val, i, internalize(val, '' + i, reviver, i < elementRecordsLen ? nodes[i] : undefined));
+ }
+ } else {
+ keys = enumerableOwnProperties(val);
+ len = lengthOfArrayLike(keys);
+ for (i = 0; i < len; i++) {
+ P = keys[i];
+ internalizeProperty(val, P, internalize(val, P, reviver, hasOwn(nodes, P) ? nodes[P] : undefined));
+ }
+ }
+ }
+ return call(reviver, holder, name, val, context);
+};
+
+var internalizeProperty = function (object, key, value) {
+ if (DESCRIPTORS) {
+ var descriptor = getOwnPropertyDescriptor(object, key);
+ if (descriptor && !descriptor.configurable) return;
+ }
+ if (value === undefined) delete object[key];
+ else createProperty(object, key, value);
+};
+
+var Node = function (value, end, source, nodes) {
+ this.value = value;
+ this.end = end;
+ this.source = source;
+ this.nodes = nodes;
+};
+
+var Context = function (source, index) {
+ this.source = source;
+ this.index = index;
+};
+
+// https://www.json.org/json-en.html
+Context.prototype = {
+ fork: function (nextIndex) {
+ return new Context(this.source, nextIndex);
+ },
+ parse: function () {
+ var source = this.source;
+ var i = this.skip(IS_WHITESPACE, this.index);
+ var fork = this.fork(i);
+ var chr = at(source, i);
+ if (exec(IS_NUMBER_START, chr)) return fork.number();
+ switch (chr) {
+ case '{':
+ return fork.object();
+ case '[':
+ return fork.array();
+ case '"':
+ return fork.string();
+ case 't':
+ return fork.keyword(true);
+ case 'f':
+ return fork.keyword(false);
+ case 'n':
+ return fork.keyword(null);
+ } throw new SyntaxError('Unexpected character: "' + chr + '" at: ' + i);
+ },
+ node: function (type, value, start, end, nodes) {
+ return new Node(value, end, type ? null : slice(this.source, start, end), nodes);
+ },
+ object: function () {
+ var source = this.source;
+ var i = this.index + 1;
+ var expectKeypair = false;
+ var object = {};
+ var nodes = {};
+ var closed = false;
+ while (i < source.length) {
+ i = this.until(['"', '}'], i);
+ if (at(source, i) === '}' && !expectKeypair) {
+ i++;
+ closed = true;
+ break;
+ }
+ // Parsing the key
+ var result = this.fork(i).string();
+ var key = result.value;
+ i = result.end;
+ i = this.until([':'], i) + 1;
+ // Parsing value
+ i = this.skip(IS_WHITESPACE, i);
+ result = this.fork(i).parse();
+ createProperty(nodes, key, result);
+ createProperty(object, key, result.value);
+ i = this.until([',', '}'], result.end);
+ var chr = at(source, i);
+ if (chr === ',') {
+ expectKeypair = true;
+ i++;
+ } else if (chr === '}') {
+ i++;
+ closed = true;
+ break;
+ }
+ }
+ if (!closed) throw new SyntaxError('Unterminated object at: ' + i);
+ return this.node(OBJECT, object, this.index, i, nodes);
+ },
+ array: function () {
+ var source = this.source;
+ var i = this.index + 1;
+ var expectElement = false;
+ var array = [];
+ var nodes = [];
+ var closed = false;
+ while (i < source.length) {
+ i = this.skip(IS_WHITESPACE, i);
+ if (at(source, i) === ']' && !expectElement) {
+ i++;
+ closed = true;
+ break;
+ }
+ var result = this.fork(i).parse();
+ push(nodes, result);
+ push(array, result.value);
+ i = this.until([',', ']'], result.end);
+ if (at(source, i) === ',') {
+ expectElement = true;
+ i++;
+ } else if (at(source, i) === ']') {
+ i++;
+ closed = true;
+ break;
+ }
+ }
+ if (!closed) throw new SyntaxError('Unterminated array at: ' + i);
+ return this.node(OBJECT, array, this.index, i, nodes);
+ },
+ string: function () {
+ var index = this.index;
+ var parsed = parseJSONString(this.source, this.index + 1);
+ return this.node(PRIMITIVE, parsed.value, index, parsed.end);
+ },
+ number: function () {
+ var source = this.source;
+ var startIndex = this.index;
+ var i = startIndex;
+ if (at(source, i) === '-') i++;
+ if (at(source, i) === '0') i++;
+ else if (exec(IS_NON_ZERO_DIGIT, at(source, i))) i = this.skip(IS_DIGIT, i + 1);
+ else throw new SyntaxError('Failed to parse number at: ' + i);
+ if (at(source, i) === '.') {
+ var fractionStartIndex = i + 1;
+ i = this.skip(IS_DIGIT, fractionStartIndex);
+ if (fractionStartIndex === i) throw new SyntaxError("Failed to parse number's fraction at: " + i);
+ }
+ if (at(source, i) === 'e' || at(source, i) === 'E') {
+ i++;
+ if (at(source, i) === '+' || at(source, i) === '-') i++;
+ var exponentStartIndex = i;
+ i = this.skip(IS_DIGIT, i);
+ if (exponentStartIndex === i) throw new SyntaxError("Failed to parse number's exponent value at: " + i);
+ }
+ return this.node(PRIMITIVE, Number(slice(source, startIndex, i)), startIndex, i);
+ },
+ keyword: function (value) {
+ var keyword = '' + value;
+ var index = this.index;
+ var endIndex = index + keyword.length;
+ if (slice(this.source, index, endIndex) !== keyword) throw new SyntaxError('Failed to parse value at: ' + index);
+ return this.node(PRIMITIVE, value, index, endIndex);
+ },
+ skip: function (regex, i) {
+ var source = this.source;
+ for (; i < source.length; i++) if (!exec(regex, at(source, i))) break;
+ return i;
+ },
+ until: function (array, i) {
+ i = this.skip(IS_WHITESPACE, i);
+ var chr = at(this.source, i);
+ for (var j = 0; j < array.length; j++) if (array[j] === chr) return i;
+ throw new SyntaxError('Unexpected character: "' + chr + '" at: ' + i);
+ }
+};
+
+var NO_SOURCE_SUPPORT = fails(function () {
+ var unsafeInt = '9007199254740993';
+ var source;
+ nativeParse(unsafeInt, function (key, value, context) {
+ source = context.source;
+ });
+ return source !== unsafeInt;
+});
+
+var PROPER_BASE_PARSE = NATIVE_SYMBOL && !fails(function () {
+ // Safari 9 bug
+ return 1 / nativeParse('-0 \t') !== -Infinity;
+});
+
+// `JSON.parse` method
+// https://tc39.es/ecma262/#sec-json.parse
+// https://github.com/tc39/proposal-json-parse-with-source
+$({ target: 'JSON', stat: true, forced: NO_SOURCE_SUPPORT }, {
+ parse: function parse(text, reviver) {
+ return PROPER_BASE_PARSE && !isCallable(reviver) ? nativeParse(text) : $parse(text, reviver);
+ }
+});
+
+
+/***/ },
+
+/***/ 3110
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var getBuiltIn = __webpack_require__(7751);
+var call = __webpack_require__(9565);
+var uncurryThis = __webpack_require__(9504);
+var fails = __webpack_require__(9039);
+var isArray = __webpack_require__(4376);
+var isCallable = __webpack_require__(4901);
+var isObject = __webpack_require__(34);
+var create = __webpack_require__(2360);
+var isRawJSON = __webpack_require__(5810);
+var isSymbol = __webpack_require__(757);
+var classof = __webpack_require__(2195);
+var thisNumberValue = __webpack_require__(1240);
+var includes = (__webpack_require__(9617).includes);
+var hasOwn = __webpack_require__(9297);
+var toString = __webpack_require__(655);
+var parseJSONString = __webpack_require__(8235);
+var uid = __webpack_require__(3392);
+var NATIVE_SYMBOL = __webpack_require__(4495);
+var NATIVE_RAW_JSON = __webpack_require__(7819);
+
+var $String = String;
+var $TypeError = TypeError;
+var $stringify = getBuiltIn('JSON', 'stringify');
+var $BigInt = getBuiltIn('BigInt');
+var stringValueOf = uncurryThis(''.valueOf);
+var booleanValueOf = uncurryThis(true.valueOf);
+var bigIntValueOf = $BigInt && uncurryThis($BigInt.prototype.valueOf);
+var exec = uncurryThis(/./.exec);
+var charAt = uncurryThis(''.charAt);
+var charCodeAt = uncurryThis(''.charCodeAt);
+var replace = uncurryThis(''.replace);
+var slice = uncurryThis(''.slice);
+var push = uncurryThis([].push);
+var pop = uncurryThis([].pop);
+var numberToString = uncurryThis(1.1.toString);
+
+var surrogates = /[\uD800-\uDFFF]/g;
+var leadingSurrogates = /^[\uD800-\uDBFF]$/;
+var trailingSurrogates = /^[\uDC00-\uDFFF]$/;
+var digits = /^\d+$/;
+
+// a placeholder of a raw JSON value
+var RAW_MARK = uid();
+// a prefix of keys of a reordered object, see `createOrderedObject`
+var KEY_MARK = uid();
+// the last key of a reordered object, marks the end of its serialization
+var END_MARK = uid();
+var RAW_MARK_LENGTH = RAW_MARK.length;
+var KEY_MARK_LENGTH = KEY_MARK.length;
+
+var WRONG_SYMBOLS_CONVERSION = !NATIVE_SYMBOL || fails(function () {
+ var symbol = getBuiltIn('Symbol')('stringify detection');
+ // MS Edge converts symbol values to JSON as {}
+ return $stringify([symbol]) !== '[null]'
+ // WebKit converts symbol values to JSON as null
+ || $stringify({ a: symbol }) !== '{}'
+ // V8 throws on boxed symbols
+ || $stringify(Object(symbol)) !== '{}';
+});
+
+// https://github.com/tc39/proposal-well-formed-stringify
+var ILL_FORMED_UNICODE = fails(function () {
+ return $stringify('\uDF06\uD834') !== '"\\udf06\\ud834"'
+ || $stringify('\uDEAD') !== '"\\udead"';
+});
+
+var isRawJSONValue = NATIVE_RAW_JSON ? getBuiltIn('JSON', 'isRawJSON') : isRawJSON;
+
+var stringifyWithProperSymbolsConversion = WRONG_SYMBOLS_CONVERSION ? function (it, replacer, space) {
+ return $stringify(it, function (key, value) {
+ var replaced = call(replacer, this, key, value);
+ if (!isSymbol(replaced)) return replaced;
+ }, space);
+} : $stringify;
+
+var fixIllFormedJSON = function (match, offset, string) {
+ var prev = charAt(string, offset - 1);
+ var next = charAt(string, offset + 1);
+ if (
+ (exec(leadingSurrogates, match) && !exec(trailingSurrogates, next)) ||
+ (exec(trailingSurrogates, match) && !exec(leadingSurrogates, prev))
+ ) {
+ return '\\u' + numberToString(charCodeAt(match, 0), 16);
+ } return match;
+};
+
+// `PropertyList` of `JSON.stringify`
+// https://tc39.es/ecma262/#sec-json.stringify
+var getPropertyList = function (replacer) {
+ if (!isArray(replacer)) return;
+ var rawLength = replacer.length;
+ var propertyList = [];
+ // a null prototype object is used as a set of already added keys to keep the deduplication linear
+ var addedKeys = create(null);
+ for (var i = 0; i < rawLength; i++) {
+ var element = replacer[i];
+ var key;
+ if (typeof element == 'string') key = element;
+ else if (typeof element == 'number' || classof(element) === 'Number' || classof(element) === 'String') key = toString(element);
+ else continue;
+ if (!hasOwn(addedKeys, key)) {
+ addedKeys[key] = true;
+ push(propertyList, key);
+ }
+ }
+ return propertyList;
+};
+
+// values with such an internal slot are unwrapped by `SerializeJSONProperty` instead of being serialized as objects
+var hasInternalSlot = function (valueOf, it) {
+ try {
+ valueOf(it);
+ return true;
+ } catch (error) {
+ return false;
+ }
+};
+
+// the slot check is expensive, so it's performed only for the kind reported by the value itself -
+// a value lying about its kind via `Symbol.toStringTag` is serialized as an ordinary object
+var isBoxedPrimitive = function (it) {
+ var kind = classof(it);
+ return (kind === 'Number' && hasInternalSlot(thisNumberValue, it))
+ || (kind === 'String' && hasInternalSlot(stringValueOf, it))
+ || (kind === 'Boolean' && hasInternalSlot(booleanValueOf, it))
+ || (!!bigIntValueOf && kind === 'BigInt' && hasInternalSlot(bigIntValueOf, it));
+};
+
+// only objects serialized by `SerializeJSONObject` are affected by the property list
+var isSerializedAsObject = function (it) {
+ if (!isObject(it) || isCallable(it) || isArray(it)) return false;
+ try {
+ return !isBoxedPrimitive(it);
+ // `classof` reads `Symbol.toStringTag`, so a proxy could throw - it has no internal slots anyway
+ } catch (error) {
+ return true;
+ }
+};
+
+// the engine unwraps it in the same order as it would read the original property,
+// so the property is read lazily and `toJSON` is called once and with the original key
+var createElementHolder = function (holder, key) {
+ return {
+ toJSON: function () {
+ var element = holder[key];
+ if (isObject(element) || typeof element == 'bigint') {
+ var elementToJSON = element.toJSON;
+ if (isCallable(elementToJSON)) element = call(elementToJSON, element, key);
+ } return element;
+ }
+ };
+};
+
+// own keys of objects are sorted - integer-like keys are moved to the beginning,
+// so such keys should be marked and restored in the serialized string
+var getKeyPrefix = function (propertyList) {
+ for (var i = 0, length = propertyList.length; i < length; i++) {
+ if (exec(digits, propertyList[i])) return KEY_MARK;
+ } return '';
+};
+
+// `SerializeJSONObject` iterates the property list, so the value is replaced with an object with keys in this order
+var createOrderedObject = function (value, propertyList, keyPrefix) {
+ // keys are not marked if the property list has no integer-like keys, so `Object.prototype`
+ // with a setter, a non-writable property or `__proto__` should not intercept the assignment
+ var ordered = create(null);
+ for (var i = 0, length = propertyList.length; i < length; i++) {
+ var key = propertyList[i];
+ ordered[keyPrefix + key] = createElementHolder(value, key);
+ }
+ ordered[END_MARK] = null;
+ return ordered;
+};
+
+// `JSON.stringify` method
+// https://tc39.es/ecma262/#sec-json.stringify
+// https://github.com/tc39/proposal-json-parse-with-source
+if ($stringify) $({ target: 'JSON', stat: true, arity: 3, forced: WRONG_SYMBOLS_CONVERSION || ILL_FORMED_UNICODE || !NATIVE_RAW_JSON }, {
+ stringify: function stringify(text, replacer, space) {
+ var replacerFunction = isCallable(replacer) ? replacer : undefined;
+ var propertyList = replacerFunction ? undefined : getPropertyList(replacer);
+ var keyPrefix = propertyList && getKeyPrefix(propertyList);
+ var rawStrings = [];
+ var openObjects = [];
+ var parentOrdered = [];
+ var currentOrdered;
+ var marked = false;
+ var root = true;
+
+ var json = stringifyWithProperSymbolsConversion(text, function (key, value) {
+ // some old implementations (like WebKit) could pass numbers as keys
+ key = $String(key);
+
+ if (propertyList) {
+ if (key === END_MARK) {
+ pop(openObjects);
+ currentOrdered = pop(parentOrdered);
+ return;
+ }
+ if (root) root = false;
+ // the innermost reordered object already contains only keys of the property list and arrays are not
+ // affected by it, the rest of objects (like objects with a fake `Symbol.toStringTag`) are filtered here
+ else if (this !== currentOrdered && !isArray(this) && !includes(propertyList, key)) return;
+ } else if (replacerFunction) value = call(replacerFunction, this, key, value);
+
+ if (isRawJSONValue(value)) {
+ if (NATIVE_RAW_JSON) return value;
+ marked = true;
+ return RAW_MARK + (push(rawStrings, value.rawJSON) - 1);
+ }
+
+ if (propertyList && isSerializedAsObject(value)) {
+ // reordered objects are new each time, so cycles should be detected before the engine does it
+ if (includes(openObjects, value)) throw new $TypeError('Converting circular structure to JSON');
+ var ordered = createOrderedObject(value, propertyList, keyPrefix);
+ push(openObjects, value);
+ push(parentOrdered, currentOrdered);
+ currentOrdered = ordered;
+ if (keyPrefix) marked = true;
+ return ordered;
+ }
+
+ return value;
+ }, space);
+
+ if (typeof json != 'string') return json;
+
+ if (ILL_FORMED_UNICODE) json = replace(json, surrogates, fixIllFormedJSON);
+
+ if (!marked) return json;
+
+ var result = '';
+ var length = json.length;
+
+ for (var i = 0; i < length; i++) {
+ var chr = charAt(json, i);
+ if (chr === '"') {
+ var end = parseJSONString(json, ++i).end - 1;
+ var string = slice(json, i, end);
+ if (slice(string, 0, RAW_MARK_LENGTH) === RAW_MARK) result += rawStrings[slice(string, RAW_MARK_LENGTH)];
+ else if (slice(string, 0, KEY_MARK_LENGTH) === KEY_MARK) result += '"' + slice(string, KEY_MARK_LENGTH) + '"';
+ else result += '"' + string + '"';
+ i = end;
+ } else result += chr;
+ }
+
+ return result;
+ }
+});
+
+
+/***/ },
+
+/***/ 2731
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var aCallable = __webpack_require__(9306);
+var MapHelpers = __webpack_require__(2248);
+var IS_PURE = __webpack_require__(6395);
+
+var get = MapHelpers.get;
+var has = MapHelpers.has;
+var set = MapHelpers.set;
+
+// `Map.prototype.getOrInsertComputed` method
+// https://tc39.es/ecma262/#sec-map.prototype.getorinsertcomputed
+$({ target: 'Map', proto: true, real: true, forced: IS_PURE }, {
+ getOrInsertComputed: function getOrInsertComputed(key, callbackfn) {
+ var hasKey = has(this, key);
+ aCallable(callbackfn);
+ if (hasKey) return get(this, key);
+ // CanonicalizeKeyedCollectionKey
+ if (key === 0 && 1 / key === -Infinity) key = 0;
+ var value = callbackfn(key);
+ set(this, key, value);
+ return value;
+ }
+});
+
+
+/***/ },
+
+/***/ 5367
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var MapHelpers = __webpack_require__(2248);
+var IS_PURE = __webpack_require__(6395);
+
+var get = MapHelpers.get;
+var has = MapHelpers.has;
+var set = MapHelpers.set;
+
+// `Map.prototype.getOrInsert` method
+// https://tc39.es/ecma262/#sec-map.prototype.getorinsert
+$({ target: 'Map', proto: true, real: true, forced: IS_PURE }, {
+ getOrInsert: function getOrInsert(key, value) {
+ if (has(this, key)) return get(this, key);
+ set(this, key, value);
+ return value;
+ }
+});
+
+
+/***/ },
+
+/***/ 6069
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var uncurryThis = __webpack_require__(9504);
+var aString = __webpack_require__(3463);
+var hasOwn = __webpack_require__(9297);
+var padStart = (__webpack_require__(533).start);
+var WHITESPACES = __webpack_require__(7452);
+
+var $Array = Array;
+var $escape = RegExp.escape;
+var charAt = uncurryThis(''.charAt);
+var charCodeAt = uncurryThis(''.charCodeAt);
+var numberToString = uncurryThis(1.1.toString);
+var join = uncurryThis([].join);
+var FIRST_DIGIT_OR_ASCII = /^[0-9a-z]/i;
+var SYNTAX_SOLIDUS = /^[$()*+./?[\\\]^{|}]/;
+var OTHER_PUNCTUATORS_AND_WHITESPACES = RegExp('^[!"#%&\',\\-:;<=>@`~' + WHITESPACES + ']');
+var exec = uncurryThis(FIRST_DIGIT_OR_ASCII.exec);
+
+var ControlEscape = {
+ '\u0009': 't',
+ '\u000A': 'n',
+ '\u000B': 'v',
+ '\u000C': 'f',
+ '\u000D': 'r'
+};
+
+var escapeChar = function (chr) {
+ var hex = numberToString(charCodeAt(chr, 0), 16);
+ return hex.length < 3 ? '\\x' + padStart(hex, 2, '0') : '\\u' + padStart(hex, 4, '0');
+};
+
+// Avoiding the use of polyfills of the previous iteration of this proposal
+var FORCED = !$escape || $escape('ab') !== '\\x61b';
+
+// `RegExp.escape` method
+// https://tc39.es/ecma262/#sec-regexp.escape
+$({ target: 'RegExp', stat: true, forced: FORCED }, {
+ escape: function escape(S) {
+ aString(S);
+ var length = S.length;
+ var result = $Array(length);
+
+ for (var i = 0; i < length; i++) {
+ var chr = charAt(S, i);
+ if (i === 0 && exec(FIRST_DIGIT_OR_ASCII, chr)) {
+ result[i] = escapeChar(chr);
+ } else if (hasOwn(ControlEscape, chr)) {
+ result[i] = '\\' + ControlEscape[chr];
+ } else if (exec(SYNTAX_SOLIDUS, chr)) {
+ result[i] = '\\' + chr;
+ } else if (exec(OTHER_PUNCTUATORS_AND_WHITESPACES, chr)) {
+ result[i] = escapeChar(chr);
+ } else {
+ var charCode = charCodeAt(chr, 0);
+ // single UTF-16 code unit
+ if ((charCode & 0xF800) !== 0xD800) result[i] = chr;
+ // unpaired surrogate
+ else if (charCode >= 0xDC00 || i + 1 >= length || (charCodeAt(S, i + 1) & 0xFC00) !== 0xDC00) result[i] = escapeChar(chr);
+ // surrogate pair
+ else {
+ result[i] = chr;
+ result[++i] = charAt(S, i);
+ }
+ }
+ }
+
+ return join(result, '');
+ }
+});
+
+
+/***/ },
+
+/***/ 7642
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var difference = __webpack_require__(3440);
+var fails = __webpack_require__(9039);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var SET_LIKE_INCORRECT_BEHAVIOR = !setMethodAcceptSetLike('difference', function (result) {
+ return result.size === 0;
+});
+
+var FORCED = SET_LIKE_INCORRECT_BEHAVIOR || fails(function () {
+ // https://bugs.webkit.org/show_bug.cgi?id=288595
+ var setLike = {
+ size: 1,
+ has: function () { return true; },
+ keys: function () {
+ var index = 0;
+ return {
+ next: function () {
+ var done = index++ > 1;
+ if (baseSet.has(1)) baseSet.clear();
+ return { done: done, value: 2 };
+ }
+ };
+ }
+ };
+ // eslint-disable-next-line es/no-set -- testing
+ var baseSet = new Set([1, 2, 3, 4]);
+ // eslint-disable-next-line es/no-set-prototype-difference -- testing
+ return baseSet.difference(setLike).size !== 3;
+});
+
+// `Set.prototype.difference` method
+// https://tc39.es/ecma262/#sec-set.prototype.difference
+$({ target: 'Set', proto: true, real: true, forced: FORCED }, {
+ difference: difference
+});
+
+
+/***/ },
+
+/***/ 8004
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var fails = __webpack_require__(9039);
+var intersection = __webpack_require__(8750);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var INCORRECT = !setMethodAcceptSetLike('intersection', function (result) {
+ return result.size === 2 && result.has(1) && result.has(2);
+}) || fails(function () {
+ // eslint-disable-next-line es/no-array-from, es/no-set, es/no-set-prototype-intersection -- testing
+ return String(Array.from(new Set([1, 2, 3]).intersection(new Set([3, 2])))) !== '3,2';
+});
+
+// `Set.prototype.intersection` method
+// https://tc39.es/ecma262/#sec-set.prototype.intersection
+$({ target: 'Set', proto: true, real: true, forced: INCORRECT }, {
+ intersection: intersection
+});
+
+
+/***/ },
+
+/***/ 3853
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var isDisjointFrom = __webpack_require__(4449);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var INCORRECT = !setMethodAcceptSetLike('isDisjointFrom', function (result) {
+ return !result;
+});
+
+// `Set.prototype.isDisjointFrom` method
+// https://tc39.es/ecma262/#sec-set.prototype.isdisjointfrom
+$({ target: 'Set', proto: true, real: true, forced: INCORRECT }, {
+ isDisjointFrom: isDisjointFrom
+});
+
+
+/***/ },
+
+/***/ 5876
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var isSubsetOf = __webpack_require__(3838);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var INCORRECT = !setMethodAcceptSetLike('isSubsetOf', function (result) {
+ return result;
+});
+
+// `Set.prototype.isSubsetOf` method
+// https://tc39.es/ecma262/#sec-set.prototype.issubsetof
+$({ target: 'Set', proto: true, real: true, forced: INCORRECT }, {
+ isSubsetOf: isSubsetOf
+});
+
+
+/***/ },
+
+/***/ 2475
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var isSupersetOf = __webpack_require__(8527);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var INCORRECT = !setMethodAcceptSetLike('isSupersetOf', function (result) {
+ return !result;
+});
+
+// `Set.prototype.isSupersetOf` method
+// https://tc39.es/ecma262/#sec-set.prototype.issupersetof
+$({ target: 'Set', proto: true, real: true, forced: INCORRECT }, {
+ isSupersetOf: isSupersetOf
+});
+
+
+/***/ },
+
+/***/ 5024
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var symmetricDifference = __webpack_require__(3650);
+var setMethodGetKeysBeforeCloning = __webpack_require__(9835);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var FORCED = !setMethodAcceptSetLike('symmetricDifference') || !setMethodGetKeysBeforeCloning('symmetricDifference');
+
+// `Set.prototype.symmetricDifference` method
+// https://tc39.es/ecma262/#sec-set.prototype.symmetricdifference
+$({ target: 'Set', proto: true, real: true, forced: FORCED }, {
+ symmetricDifference: symmetricDifference
+});
+
+
+/***/ },
+
+/***/ 1698
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var union = __webpack_require__(4204);
+var setMethodGetKeysBeforeCloning = __webpack_require__(9835);
+var setMethodAcceptSetLike = __webpack_require__(4916);
+
+var FORCED = !setMethodAcceptSetLike('union') || !setMethodGetKeysBeforeCloning('union');
+
+// `Set.prototype.union` method
+// https://tc39.es/ecma262/#sec-set.prototype.union
+$({ target: 'Set', proto: true, real: true, forced: FORCED }, {
+ union: union
+});
+
+
+/***/ },
+
+/***/ 9577
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var ArrayBufferViewCore = __webpack_require__(4644);
+var isBigIntArray = __webpack_require__(1108);
+var lengthOfArrayLike = __webpack_require__(6198);
+var toIntegerOrInfinity = __webpack_require__(1291);
+var toBigInt = __webpack_require__(5854);
+
+var aTypedArray = ArrayBufferViewCore.aTypedArray;
+var getTypedArrayConstructor = ArrayBufferViewCore.getTypedArrayConstructor;
+var exportTypedArrayMethod = ArrayBufferViewCore.exportTypedArrayMethod;
+
+var $RangeError = RangeError;
+
+var PROPER_ORDER = function () {
+ try {
+ // eslint-disable-next-line no-throw-literal, es/no-typed-arrays, es/no-array-prototype-with -- required for testing
+ new Int8Array(1)['with'](2, { valueOf: function () { throw 8; } });
+ } catch (error) {
+ // some early implementations, like WebKit, does not follow the final semantic
+ // https://github.com/tc39/proposal-change-array-by-copy/pull/86
+ return error === 8;
+ }
+}();
+
+// Bug in WebKit. It should truncate a negative fractional index to zero, but instead throws an error
+var THROW_ON_NEGATIVE_FRACTIONAL_INDEX = PROPER_ORDER && function () {
+ try {
+ // eslint-disable-next-line es/no-typed-arrays, es/no-array-prototype-with -- required for testing
+ new Int8Array(1)['with'](-0.5, 1);
+ } catch (error) {
+ return true;
+ }
+}();
+
+// `%TypedArray%.prototype.with` method
+// https://tc39.es/ecma262/#sec-%typedarray%.prototype.with
+exportTypedArrayMethod('with', { 'with': function (index, value) {
+ var O = aTypedArray(this);
+ var len = lengthOfArrayLike(O);
+ var relativeIndex = toIntegerOrInfinity(index);
+ var actualIndex = relativeIndex < 0 ? len + relativeIndex : relativeIndex;
+ var numericValue = isBigIntArray(O) ? toBigInt(value) : +value;
+ if (actualIndex >= len || actualIndex < 0) throw new $RangeError('Incorrect index');
+ var A = new (getTypedArrayConstructor(O))(len);
+ var k = 0;
+ for (; k < len; k++) A[k] = k === actualIndex ? numericValue : O[k];
+ return A;
+} }['with'], !PROPER_ORDER || THROW_ON_NEGATIVE_FRACTIONAL_INDEX);
+
+
+/***/ },
+
+/***/ 9452
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var aCallable = __webpack_require__(9306);
+var aWeakMap = __webpack_require__(6557);
+var aWeakKey = __webpack_require__(4328);
+var WeakMapHelpers = __webpack_require__(4995);
+var IS_PURE = __webpack_require__(6395);
+
+var get = WeakMapHelpers.get;
+var has = WeakMapHelpers.has;
+var set = WeakMapHelpers.set;
+
+var FORCED = IS_PURE || !function () {
+ try {
+ // eslint-disable-next-line es/no-weak-map, no-throw-literal -- testing
+ if (WeakMap.prototype.getOrInsertComputed) new WeakMap().getOrInsertComputed(1, function () { throw 1; });
+ } catch (error) {
+ // FF144 Nightly - Beta 3 bug
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1988369
+ return error instanceof TypeError;
+ }
+}();
+
+// `WeakMap.prototype.getOrInsertComputed` method
+// https://tc39.es/ecma262/#sec-weakmap.prototype.getorinsertcomputed
+$({ target: 'WeakMap', proto: true, real: true, forced: FORCED }, {
+ getOrInsertComputed: function getOrInsertComputed(key, callbackfn) {
+ if (!IS_PURE) aWeakMap(this);
+ aWeakKey(key);
+ aCallable(callbackfn);
+ if (has(this, key)) return get(this, key);
+ var value = callbackfn(key);
+ set(this, key, value);
+ return value;
+ }
+});
+
+
+/***/ },
+
+/***/ 8454
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var WeakMapHelpers = __webpack_require__(4995);
+var IS_PURE = __webpack_require__(6395);
+
+var get = WeakMapHelpers.get;
+var has = WeakMapHelpers.has;
+var set = WeakMapHelpers.set;
+
+// `WeakMap.prototype.getOrInsert` method
+// https://tc39.es/ecma262/#sec-weakmap.prototype.getorinsert
+$({ target: 'WeakMap', proto: true, real: true, forced: IS_PURE }, {
+ getOrInsert: function getOrInsert(key, value) {
+ if (has(this, key)) return get(this, key);
+ set(this, key, value);
+ return value;
+ }
+});
+
+
+/***/ },
+
+/***/ 5781
+(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) {
+
+
+var $ = __webpack_require__(6518);
+var getBuiltIn = __webpack_require__(7751);
+var validateArgumentsLength = __webpack_require__(2812);
+var toString = __webpack_require__(655);
+var USE_NATIVE_URL = __webpack_require__(7416);
+
+var URL = getBuiltIn('URL');
+
+// `URL.parse` method
+// https://url.spec.whatwg.org/#dom-url-parse
+$({ target: 'URL', stat: true, forced: !USE_NATIVE_URL }, {
+ parse: function parse(url) {
+ var length = validateArgumentsLength(arguments.length, 1);
+ var urlString = toString(url);
+ var base = length < 2 || arguments[1] === undefined ? undefined : toString(arguments[1]);
+ try {
+ return new URL(urlString, base);
+ } catch (error) {
+ return null;
+ }
+ }
+});
+
+
+/***/ }
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ const __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ const cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ const module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter/value functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ if(Array.isArray(definition)) {
+/******/ var i = 0;
+/******/ while(i < definition.length) {
+/******/ var key = definition[i++];
+/******/ var binding = definition[i++];
+/******/ if(!__webpack_require__.o(exports, key)) {
+/******/ if(binding === 0) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, value: definition[i++] });
+/******/ } else {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: binding });
+/******/ }
+/******/ } else if(binding === 0) { i++; }
+/******/ }
+/******/ } else {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/************************************************************************/
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.includes.js
+var es_array_includes = __webpack_require__(4423);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.array.push.js
+var es_array_push = __webpack_require__(4114);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.map.get-or-insert.js
+var es_map_get_or_insert = __webpack_require__(5367);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.map.get-or-insert-computed.js
+var es_map_get_or_insert_computed = __webpack_require__(2731);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.difference.v2.js
+var es_set_difference_v2 = __webpack_require__(7642);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.intersection.v2.js
+var es_set_intersection_v2 = __webpack_require__(8004);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.is-disjoint-from.v2.js
+var es_set_is_disjoint_from_v2 = __webpack_require__(3853);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.is-subset-of.v2.js
+var es_set_is_subset_of_v2 = __webpack_require__(5876);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.is-superset-of.v2.js
+var es_set_is_superset_of_v2 = __webpack_require__(2475);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.symmetric-difference.v2.js
+var es_set_symmetric_difference_v2 = __webpack_require__(5024);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.set.union.v2.js
+var es_set_union_v2 = __webpack_require__(1698);
+;// ./web/ui_utils.js
+
+
+
+
+
+
+
+
+
+
+
+const DEFAULT_SCALE_VALUE = "auto";
+const DEFAULT_SCALE = 1.0;
+const DEFAULT_SCALE_DELTA = 1.1;
+const MIN_SCALE = 0.1;
+const MAX_SCALE = 25.0;
+const UNKNOWN_SCALE = 0;
+const MAX_AUTO_SCALE = 1.25;
+const SCROLLBAR_PADDING = 40;
+const VERTICAL_PADDING = 5;
+const PresentationModeState = {
+ UNKNOWN: 0,
+ NORMAL: 1,
+ CHANGING: 2,
+ FULLSCREEN: 3
+};
+const SidebarView = {
+ UNKNOWN: -1,
+ NONE: 0,
+ THUMBS: 1,
+ OUTLINE: 2,
+ ATTACHMENTS: 3,
+ LAYERS: 4
+};
+const TextLayerMode = {
+ DISABLE: 0,
+ ENABLE: 1,
+ ENABLE_PERMISSIONS: 2
+};
+const ScrollMode = {
+ UNKNOWN: -1,
+ VERTICAL: 0,
+ HORIZONTAL: 1,
+ WRAPPED: 2,
+ PAGE: 3
+};
+const SpreadMode = {
+ UNKNOWN: -1,
+ NONE: 0,
+ ODD: 1,
+ EVEN: 2
+};
+const CursorTool = {
+ SELECT: 0,
+ HAND: 1,
+ ZOOM: 2
+};
+const AutoPrintRegExp = /\bprint\s*\(/;
+function scrollIntoView(element, spot) {
+ let parent = element.offsetParent;
+ if (!parent) {
+ console.error("offsetParent is not set -- cannot scroll");
+ return;
+ }
+ let offsetY = element.offsetTop + element.clientTop;
+ let offsetX = element.offsetLeft + element.clientLeft;
+ while (parent.clientHeight === parent.scrollHeight && parent.clientWidth === parent.scrollWidth) {
+ offsetY += parent.offsetTop;
+ offsetX += parent.offsetLeft;
+ parent = parent.offsetParent;
+ if (!parent) {
+ return;
+ }
+ }
+ if (spot) {
+ if (spot.top !== undefined) {
+ offsetY += spot.top;
+ }
+ if (spot.left !== undefined) {
+ offsetX += spot.left;
+ parent.scrollLeft = offsetX;
+ }
+ }
+ parent.scrollTop = offsetY;
+}
+function watchScroll(viewAreaElement, callback, abortSignal = undefined) {
+ function onRAF() {
+ rAF = null;
+ const currentX = viewAreaElement.scrollLeft;
+ const lastX = state.lastX;
+ if (currentX !== lastX) {
+ state.right = currentX > lastX;
+ }
+ state.lastX = currentX;
+ const currentY = viewAreaElement.scrollTop;
+ const lastY = state.lastY;
+ if (currentY !== lastY) {
+ state.down = currentY > lastY;
+ }
+ state.lastY = currentY;
+ callback(state);
+ }
+ const state = {
+ right: true,
+ down: true,
+ lastX: viewAreaElement.scrollLeft,
+ lastY: viewAreaElement.scrollTop
+ };
+ let rAF = null;
+ viewAreaElement.addEventListener("scroll", () => {
+ rAF ??= window.requestAnimationFrame(onRAF);
+ }, {
+ useCapture: true,
+ signal: abortSignal
+ });
+ abortSignal?.addEventListener("abort", () => window.cancelAnimationFrame(rAF), {
+ once: true
+ });
+ return state;
+}
+function parseQueryString(query) {
+ const params = new Map();
+ for (const [key, value] of new URLSearchParams(query)) {
+ params.set(key.toLowerCase(), value);
+ }
+ return params;
+}
+const InvisibleCharsRegExp = /[\x00-\x1F]/g;
+function removeNullCharacters(str, replaceInvisible = false) {
+ if (!InvisibleCharsRegExp.test(str)) {
+ return str;
+ }
+ if (replaceInvisible) {
+ return str.replaceAll(InvisibleCharsRegExp, m => m === "\x00" ? "" : " ");
+ }
+ return str.replaceAll("\x00", "");
+}
+function binarySearchFirstItem(items, condition, start = 0) {
+ let minIndex = start;
+ let maxIndex = items.length - 1;
+ if (maxIndex < 0 || !condition(items[maxIndex])) {
+ return items.length;
+ }
+ if (condition(items[minIndex])) {
+ return minIndex;
+ }
+ while (minIndex < maxIndex) {
+ const currentIndex = minIndex + maxIndex >> 1;
+ const currentItem = items[currentIndex];
+ if (condition(currentItem)) {
+ maxIndex = currentIndex;
+ } else {
+ minIndex = currentIndex + 1;
+ }
+ }
+ return minIndex;
+}
+function approximateFraction(x) {
+ if (Math.floor(x) === x) {
+ return [x, 1];
+ }
+ const xinv = 1 / x;
+ const limit = 8;
+ if (xinv > limit) {
+ return [1, limit];
+ } else if (Math.floor(xinv) === xinv) {
+ return [1, xinv];
+ }
+ const x_ = x > 1 ? xinv : x;
+ let a = 0,
+ b = 1,
+ c = 1,
+ d = 1;
+ while (true) {
+ const p = a + c,
+ q = b + d;
+ if (q > limit) {
+ break;
+ }
+ if (x_ <= p / q) {
+ c = p;
+ d = q;
+ } else {
+ a = p;
+ b = q;
+ }
+ }
+ if (x_ - a / b < c / d - x_) {
+ return x_ === x ? [a, b] : [b, a];
+ }
+ return x_ === x ? [c, d] : [d, c];
+}
+function floorToDivide(x, div) {
+ return x - x % div;
+}
+function getPageSizeInches({
+ view,
+ userUnit,
+ rotate
+}) {
+ const [x1, y1, x2, y2] = view;
+ const changeOrientation = rotate % 180 !== 0;
+ const width = (x2 - x1) / 72 * userUnit;
+ const height = (y2 - y1) / 72 * userUnit;
+ return {
+ width: changeOrientation ? height : width,
+ height: changeOrientation ? width : height
+ };
+}
+function backtrackBeforeAllVisibleElements(index, views, top) {
+ if (index < 2) {
+ return index;
+ }
+ let elt = views[index].div;
+ let pageTop = elt.offsetTop + elt.clientTop;
+ if (pageTop >= top) {
+ elt = views[index - 1].div;
+ pageTop = elt.offsetTop + elt.clientTop;
+ }
+ for (let i = index - 2; i >= 0; --i) {
+ elt = views[i].div;
+ if (elt.offsetTop + elt.clientTop + elt.clientHeight <= pageTop) {
+ break;
+ }
+ index = i;
+ }
+ return index;
+}
+function visibleSort(a, b) {
+ const pc = a.percent - b.percent;
+ return Math.abs(pc) > 0.001 ? -pc : a.id - b.id;
+}
+function getVisibleElements({
+ scrollEl,
+ views,
+ sortByVisibility = false,
+ horizontal = false,
+ rtl = false
+}) {
+ const top = scrollEl.scrollTop,
+ bottom = top + scrollEl.clientHeight;
+ const left = scrollEl.scrollLeft,
+ right = left + scrollEl.clientWidth;
+ function isElementBottomAfterViewTop(view) {
+ const element = view.div;
+ const elementBottom = element.offsetTop + element.clientTop + element.clientHeight;
+ return elementBottom > top;
+ }
+ function isElementNextAfterViewHorizontally(view) {
+ const element = view.div;
+ const elementLeft = element.offsetLeft + element.clientLeft;
+ const elementRight = elementLeft + element.clientWidth;
+ return rtl ? elementLeft < right : elementRight > left;
+ }
+ const visible = [],
+ ids = new Set(),
+ numViews = views.length;
+ let firstVisibleElementInd = binarySearchFirstItem(views, horizontal ? isElementNextAfterViewHorizontally : isElementBottomAfterViewTop);
+ if (firstVisibleElementInd > 0 && firstVisibleElementInd < numViews && !horizontal) {
+ firstVisibleElementInd = backtrackBeforeAllVisibleElements(firstVisibleElementInd, views, top);
+ }
+ let lastEdge = horizontal ? right : -1;
+ for (let i = firstVisibleElementInd; i < numViews; i++) {
+ const view = views[i],
+ element = view.div;
+ const currentWidth = element.offsetLeft + element.clientLeft;
+ const currentHeight = element.offsetTop + element.clientTop;
+ const viewWidth = element.clientWidth,
+ viewHeight = element.clientHeight;
+ const viewRight = currentWidth + viewWidth;
+ const viewBottom = currentHeight + viewHeight;
+ if (lastEdge === -1) {
+ if (viewBottom >= bottom) {
+ lastEdge = viewBottom;
+ }
+ } else if ((horizontal ? currentWidth : currentHeight) > lastEdge) {
+ break;
+ }
+ if (viewBottom <= top || currentHeight >= bottom || viewRight <= left || currentWidth >= right) {
+ continue;
+ }
+ const minY = Math.max(0, top - currentHeight);
+ const minX = Math.max(0, left - currentWidth);
+ const hiddenHeight = minY + Math.max(0, viewBottom - bottom);
+ const hiddenWidth = minX + Math.max(0, viewRight - right);
+ const fractionHeight = (viewHeight - hiddenHeight) / viewHeight,
+ fractionWidth = (viewWidth - hiddenWidth) / viewWidth;
+ const percent = fractionHeight * fractionWidth * 100 | 0;
+ visible.push({
+ id: view.id,
+ x: currentWidth,
+ y: currentHeight,
+ visibleArea: percent === 100 ? null : {
+ minX,
+ minY,
+ maxX: Math.min(viewRight, right) - currentWidth,
+ maxY: Math.min(viewBottom, bottom) - currentHeight
+ },
+ view,
+ percent,
+ widthPercent: fractionWidth * 100 | 0
+ });
+ ids.add(view.id);
+ }
+ const first = visible[0],
+ last = visible.at(-1);
+ if (sortByVisibility) {
+ visible.sort(visibleSort);
+ }
+ return {
+ first,
+ last,
+ views: visible,
+ ids
+ };
+}
+function normalizeWheelEventDirection(evt) {
+ let delta = Math.hypot(evt.deltaX, evt.deltaY);
+ const angle = Math.atan2(evt.deltaY, evt.deltaX);
+ if (-0.25 * Math.PI < angle && angle < 0.75 * Math.PI) {
+ delta = -delta;
+ }
+ return delta;
+}
+function normalizeWheelEventDelta(evt) {
+ const deltaMode = evt.deltaMode;
+ let delta = normalizeWheelEventDirection(evt);
+ const MOUSE_PIXELS_PER_LINE = 30;
+ const MOUSE_LINES_PER_PAGE = 30;
+ if (deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
+ delta /= MOUSE_PIXELS_PER_LINE * MOUSE_LINES_PER_PAGE;
+ } else if (deltaMode === WheelEvent.DOM_DELTA_LINE) {
+ delta /= MOUSE_LINES_PER_PAGE;
+ }
+ return delta;
+}
+function isValidRotation(angle) {
+ return Number.isInteger(angle) && angle % 90 === 0;
+}
+function isValidScrollMode(mode) {
+ return Number.isInteger(mode) && Object.values(ScrollMode).includes(mode) && mode !== ScrollMode.UNKNOWN;
+}
+function isValidSpreadMode(mode) {
+ return Number.isInteger(mode) && Object.values(SpreadMode).includes(mode) && mode !== SpreadMode.UNKNOWN;
+}
+function isPortraitOrientation(size) {
+ return size.width <= size.height;
+}
+const animationStarted = new Promise(function (resolve) {
+ window.requestAnimationFrame(resolve);
+});
+const docStyle = document.documentElement.style;
+class ProgressBar {
+ #classList = null;
+ #disableAutoFetchTimeout = null;
+ #percent = 0;
+ #style = null;
+ #visible = true;
+ constructor(bar) {
+ this.#classList = bar.classList;
+ this.#style = bar.style;
+ }
+ get percent() {
+ return this.#percent;
+ }
+ set percent(val) {
+ this.#percent = val;
+ if (isNaN(val)) {
+ this.#classList.add("indeterminate");
+ return;
+ }
+ this.#classList.remove("indeterminate");
+ this.#style.setProperty("--progressBar-percent", `${this.#percent}%`);
+ }
+ setWidth(viewer) {
+ if (!viewer) {
+ return;
+ }
+ const container = viewer.parentNode;
+ const scrollbarWidth = container.offsetWidth - viewer.offsetWidth;
+ if (scrollbarWidth > 0) {
+ this.#style.setProperty("--progressBar-end-offset", `${scrollbarWidth}px`);
+ }
+ }
+ setDisableAutoFetch(delay = 5000) {
+ if (this.#percent === 100 || isNaN(this.#percent)) {
+ return;
+ }
+ if (this.#disableAutoFetchTimeout) {
+ clearTimeout(this.#disableAutoFetchTimeout);
+ }
+ this.show();
+ this.#disableAutoFetchTimeout = setTimeout(() => {
+ this.#disableAutoFetchTimeout = null;
+ this.hide();
+ }, delay);
+ }
+ hide() {
+ if (!this.#visible) {
+ return;
+ }
+ this.#visible = false;
+ this.#classList.add("hidden");
+ }
+ show() {
+ if (this.#visible) {
+ return;
+ }
+ this.#visible = true;
+ this.#classList.remove("hidden");
+ }
+}
+function getActiveOrFocusedElement() {
+ let curRoot = document;
+ let curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus");
+ while (curActiveOrFocused?.shadowRoot) {
+ curRoot = curActiveOrFocused.shadowRoot;
+ curActiveOrFocused = curRoot.activeElement || curRoot.querySelector(":focus");
+ }
+ return curActiveOrFocused;
+}
+function apiPageLayoutToViewerModes(layout) {
+ let scrollMode = ScrollMode.VERTICAL,
+ spreadMode = SpreadMode.NONE;
+ switch (layout) {
+ case "SinglePage":
+ scrollMode = ScrollMode.PAGE;
+ break;
+ case "OneColumn":
+ break;
+ case "TwoPageLeft":
+ scrollMode = ScrollMode.PAGE;
+ case "TwoColumnLeft":
+ spreadMode = SpreadMode.ODD;
+ break;
+ case "TwoPageRight":
+ scrollMode = ScrollMode.PAGE;
+ case "TwoColumnRight":
+ spreadMode = SpreadMode.EVEN;
+ break;
+ }
+ return {
+ scrollMode,
+ spreadMode
+ };
+}
+function apiPageModeToSidebarView(mode) {
+ switch (mode) {
+ case "UseNone":
+ return SidebarView.NONE;
+ case "UseThumbs":
+ return SidebarView.THUMBS;
+ case "UseOutlines":
+ return SidebarView.OUTLINE;
+ case "UseAttachments":
+ return SidebarView.ATTACHMENTS;
+ case "UseOC":
+ return SidebarView.LAYERS;
+ }
+ return SidebarView.NONE;
+}
+function toggleCheckedBtn(button, toggle, view = null) {
+ button.classList.toggle("toggled", toggle);
+ button.setAttribute("aria-checked", toggle);
+ view?.classList.toggle("hidden", !toggle);
+}
+function toggleSelectedBtn(button, toggle, view = null) {
+ button.classList.toggle("selected", toggle);
+ button.setAttribute("aria-selected", toggle);
+ view?.classList.toggle("hidden", !toggle);
+}
+function toggleExpandedBtn(button, toggle, view = null) {
+ button.classList.toggle("toggled", toggle);
+ button.setAttribute("aria-expanded", toggle);
+ view?.classList.toggle("hidden", !toggle);
+}
+const calcRound = function () {
+ const e = document.createElement("div");
+ e.style.width = "round(down, calc(1.6666666666666665 * 792px), 1px)";
+ return e.style.width === "calc(1320px)" ? Math.fround : x => x;
+}();
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.constructor.js
+var es_iterator_constructor = __webpack_require__(8111);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.for-each.js
+var es_iterator_for_each = __webpack_require__(7588);
+;// ./web/app_options.js
+
+
+
+
+{
+ var compatParams = new Map();
+ const {
+ maxTouchPoints,
+ platform,
+ userAgent
+ } = navigator;
+ const isAndroid = /Android/.test(userAgent);
+ const isIOS = /\b(?:iPad|iPhone|iPod)(?=;)/.test(userAgent) || platform === "MacIntel" && maxTouchPoints > 1;
+ if (isIOS || isAndroid) {
+ compatParams.set("maxCanvasPixels", 5242880);
+ }
+ if (isAndroid) {
+ compatParams.set("useSystemFonts", false);
+ }
+}
+const OptionKind = {
+ BROWSER: 0x01,
+ VIEWER: 0x02,
+ API: 0x04,
+ WORKER: 0x08,
+ EVENT_DISPATCH: 0x10,
+ PREFERENCE: 0x80
+};
+const Type = {
+ BOOLEAN: 0x01,
+ NUMBER: 0x02,
+ OBJECT: 0x04,
+ STRING: 0x08,
+ UNDEFINED: 0x10
+};
+const defaultOptions = new Map([["allowedGlobalEvents", {
+ value: null,
+ kind: OptionKind.BROWSER
+}], ["canvasMaxAreaInBytes", {
+ value: -1,
+ kind: OptionKind.BROWSER + OptionKind.API
+}], ["isInAutomation", {
+ value: false,
+ kind: OptionKind.BROWSER
+}], ["localeProperties", {
+ value: {
+ lang: navigator.language || "en-US"
+ },
+ kind: OptionKind.BROWSER
+}], ["maxCanvasDim", {
+ value: 32767,
+ kind: OptionKind.BROWSER + OptionKind.VIEWER
+}], ["nimbusDataStr", {
+ value: "",
+ kind: OptionKind.BROWSER
+}], ["supportsCaretBrowsingMode", {
+ value: false,
+ kind: OptionKind.BROWSER
+}], ["supportsDocumentFonts", {
+ value: true,
+ kind: OptionKind.BROWSER
+}], ["supportsDownloading", {
+ value: true,
+ kind: OptionKind.BROWSER
+}], ["supportsIntegratedFind", {
+ value: false,
+ kind: OptionKind.BROWSER
+}], ["supportsMouseWheelZoomCtrlKey", {
+ value: true,
+ kind: OptionKind.BROWSER
+}], ["supportsMouseWheelZoomMetaKey", {
+ value: true,
+ kind: OptionKind.BROWSER
+}], ["supportsPinchToZoom", {
+ value: true,
+ kind: OptionKind.BROWSER
+}], ["supportsPrinting", {
+ value: true,
+ kind: OptionKind.BROWSER
+}], ["toolbarDensity", {
+ value: 0,
+ kind: OptionKind.BROWSER + OptionKind.EVENT_DISPATCH
+}], ["altTextLearnMoreUrl", {
+ value: "",
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["annotationEditorMode", {
+ value: 0,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["annotationMode", {
+ value: 2,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["capCanvasAreaFactor", {
+ value: 200,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["commentLearnMoreUrl", {
+ value: "",
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["cursorToolOnLoad", {
+ value: 0,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["debuggerSrc", {
+ value: "./debugger.mjs",
+ kind: OptionKind.VIEWER
+}], ...[["defaultUrl", {
+ value: "compressed.tracemonkey-pldi-09.pdf",
+ kind: OptionKind.VIEWER
+}]], ["defaultZoomDelay", {
+ value: 400,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["defaultZoomValue", {
+ value: "",
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["disableHistory", {
+ value: false,
+ kind: OptionKind.VIEWER
+}], ["disablePageLabels", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ...[["disablePreferences", {
+ value: false,
+ kind: OptionKind.VIEWER
+}]], ...[], ["enableAltText", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableAltTextModelDownload", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH
+}], ["enableAutoLinking", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableComment", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableDetailCanvas", {
+ value: true,
+ kind: OptionKind.VIEWER
+}], ...[], ["enableGuessAltText", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE + OptionKind.EVENT_DISPATCH
+}], ["enableHighlightFloatingButton", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableMerge", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableNewAltTextWhenAddingImage", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableNewBadge", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableNova", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableOptimizedPartialRendering", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enablePermissions", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enablePrintAutoRotate", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableScripting", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableSelectionRendering", {
+ value: true,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableSignatureEditor", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableSignatureVerification", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableSplitMerge", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["enableUpdatedAddImage", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["externalLinkRel", {
+ value: "noopener noreferrer nofollow",
+ kind: OptionKind.VIEWER
+}], ["externalLinkTarget", {
+ value: 0,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ...[], ["highlightEditorColors", {
+ value: "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F," + "yellow_HCM=#FFFFCC,green_HCM=#53FFBC,blue_HCM=#80EBFF,pink_HCM=#F6B8FF,red_HCM=#C50043",
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["historyUpdateUrl", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["ignoreDestinationZoom", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["imageResourcesPath", {
+ value: "./images/",
+ kind: OptionKind.VIEWER
+}], ["imagesRightClickMinSize", {
+ value: -1,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["maxCanvasPixels", {
+ value: 2 ** 25,
+ kind: OptionKind.VIEWER
+}], ["minDurationToUpdateCanvas", {
+ value: 500,
+ kind: OptionKind.VIEWER
+}], ["forcePageColors", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["pageColorsBackground", {
+ value: "Canvas",
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["pageColorsForeground", {
+ value: "CanvasText",
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["pdfBugEnabled", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["postMessageAfterPrintCallback", {
+ value: false,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["printResolution", {
+ value: 150,
+ kind: OptionKind.VIEWER
+}], ...[["sandboxBundleSrc", {
+ value: "../build/pdf.sandbox.mjs",
+ kind: OptionKind.VIEWER
+}]], ["sidebarViewOnLoad", {
+ value: -1,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["scrollModeOnLoad", {
+ value: -1,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["spreadModeOnLoad", {
+ value: -1,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["textLayerMode", {
+ value: 1,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["viewerCssTheme", {
+ value: 0,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["viewOnLoad", {
+ value: 0,
+ kind: OptionKind.VIEWER + OptionKind.PREFERENCE
+}], ["cMapPacked", {
+ value: true,
+ kind: OptionKind.API
+}], ["cMapUrl", {
+ value: "../web/cmaps/",
+ kind: OptionKind.API
+}], ["disableAutoFetch", {
+ value: false,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["disableFontFace", {
+ value: false,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["disableRange", {
+ value: false,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["disableStream", {
+ value: false,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["docBaseUrl", {
+ value: "",
+ kind: OptionKind.API
+}], ["enableHWA", {
+ value: true,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["enableWebGPU", {
+ value: true,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["enableXfa", {
+ value: true,
+ kind: OptionKind.API + OptionKind.PREFERENCE
+}], ["fontExtraProperties", {
+ value: false,
+ kind: OptionKind.API
+}], ["iccUrl", {
+ value: "../web/iccs/",
+ kind: OptionKind.API
+}], ["isOffscreenCanvasSupported", {
+ value: true,
+ kind: OptionKind.API
+}], ["maxImageSize", {
+ value: -1,
+ kind: OptionKind.API
+}], ["pdfBug", {
+ value: false,
+ kind: OptionKind.API
+}], ["standardFontDataUrl", {
+ value: "../web/standard_fonts/",
+ kind: OptionKind.API
+}], ["useSystemFonts", {
+ value: undefined,
+ kind: OptionKind.API,
+ type: Type.BOOLEAN + Type.UNDEFINED
+}], ["verbosity", {
+ value: 1,
+ kind: OptionKind.API
+}], ["wasmUrl", {
+ value: "../web/wasm/",
+ kind: OptionKind.API
+}], ["workerPort", {
+ value: null,
+ kind: OptionKind.WORKER
+}], ["workerSrc", {
+ value: "../build/pdf.worker.mjs",
+ kind: OptionKind.WORKER
+}]]);
+class AppOptions {
+ static eventBus;
+ static #opts = new Map();
+ static {
+ for (const [name, defaultOpt] of defaultOptions) {
+ this.#opts.set(name, defaultOpt.value);
+ }
+ for (const [name, value] of compatParams) {
+ this.#opts.set(name, value);
+ }
+ this._hasInvokedSet = false;
+ this._checkDisablePreferences = () => {
+ if (this.get("disablePreferences")) {
+ return true;
+ }
+ if (this._hasInvokedSet) {
+ console.warn("The Preferences may override manually set AppOptions; " + 'please use the "disablePreferences"-option to prevent that.');
+ }
+ return false;
+ };
+ }
+ static get(name) {
+ return this.#opts.get(name);
+ }
+ static getAll(kind = null, defaultOnly = false) {
+ const options = Object.create(null);
+ for (const [name, defaultOpt] of defaultOptions) {
+ if (kind && !(kind & defaultOpt.kind)) {
+ continue;
+ }
+ options[name] = !defaultOnly ? this.#opts.get(name) : defaultOpt.value;
+ }
+ return options;
+ }
+ static set(name, value) {
+ this.setAll({
+ [name]: value
+ });
+ }
+ static setAll(options, prefs = false) {
+ this._hasInvokedSet ||= true;
+ let events;
+ for (const name in options) {
+ const defaultOpt = defaultOptions.get(name),
+ userOpt = options[name];
+ if (!defaultOpt || !(typeof userOpt === typeof defaultOpt.value || Type[(typeof userOpt).toUpperCase()] & defaultOpt.type)) {
+ continue;
+ }
+ const {
+ kind
+ } = defaultOpt;
+ if (prefs && !(kind & OptionKind.BROWSER || kind & OptionKind.PREFERENCE)) {
+ continue;
+ }
+ if (this.eventBus && kind & OptionKind.EVENT_DISPATCH) {
+ (events ??= new Map()).set(name, userOpt);
+ }
+ this.#opts.set(name, userOpt);
+ }
+ events?.forEach((value, name) => {
+ this.eventBus.dispatch(name.toLowerCase(), {
+ source: this,
+ value
+ });
+ });
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.json.parse.js
+var es_json_parse = __webpack_require__(9112);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.json.stringify.js
+var es_json_stringify = __webpack_require__(3110);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/web.url.parse.js
+var web_url_parse = __webpack_require__(5781);
+;// ./web/pdfjs.js
+const {
+ AbortException,
+ AnnotationEditorLayer,
+ AnnotationEditorParamsType,
+ AnnotationEditorType,
+ AnnotationEditorUIManager,
+ AnnotationLayer,
+ AnnotationMode,
+ AnnotationType,
+ applyOpacity,
+ build,
+ ColorPicker,
+ createValidAbsoluteUrl,
+ CSSConstants,
+ DOMSVGFactory,
+ DrawLayer,
+ FeatureTest,
+ fetchData,
+ findContrastColor,
+ getDocument,
+ getFilenameFromUrl,
+ getPdfFilenameFromUrl,
+ getRGB,
+ getRGBA,
+ getUuid,
+ GlobalWorkerOptions,
+ ImageKind,
+ InvalidPDFException,
+ isDataScheme,
+ isPdfFile,
+ isValidExplicitDest,
+ makeArr,
+ makeMap,
+ makeObj,
+ makeSet,
+ MathClamp,
+ noContextMenu,
+ normalizeUnicode,
+ OPS,
+ OutputScale,
+ PasswordException,
+ PasswordResponses,
+ PDFDataRangeTransport,
+ PDFDateString,
+ PDFWorker,
+ PermissionFlag,
+ PixelsPerInch,
+ RenderingCancelledException,
+ renderRichText,
+ ResponseException,
+ setLayerDimensions,
+ shadow,
+ SignatureExtractor,
+ stopEvent,
+ SupportedImageMimeTypes,
+ TextLayer,
+ TextLayerImages,
+ TouchManager,
+ updateUrlHash,
+ Util,
+ VerbosityLevel,
+ version,
+ XfaLayer
+} = globalThis.pdfjsLib;
+
+;// ./web/internal_evt.js
+const INTERNAL_EVT = "e4c8307e-183e-4bf3-b76e-4ccdfc3f885a";
+const internalOpt = Object.freeze({
+ internal: INTERNAL_EVT
+});
+
+;// ./web/pdf_link_service.js
+
+
+
+
+
+
+
+
+const DEFAULT_LINK_REL = "noopener noreferrer nofollow";
+const LinkTarget = {
+ NONE: 0,
+ SELF: 1,
+ BLANK: 2,
+ PARENT: 3,
+ TOP: 4
+};
+class PDFLinkService {
+ externalLinkEnabled = true;
+ constructor({
+ eventBus,
+ externalLinkTarget = null,
+ externalLinkRel = null,
+ ignoreDestinationZoom = false
+ } = {}) {
+ this.eventBus = eventBus;
+ this.externalLinkTarget = externalLinkTarget;
+ this.externalLinkRel = externalLinkRel;
+ this._ignoreDestinationZoom = ignoreDestinationZoom;
+ this.baseUrl = null;
+ this.pdfDocument = null;
+ this.pdfViewer = null;
+ this.pdfHistory = null;
+ }
+ setDocument(pdfDocument, baseUrl = null) {
+ this.baseUrl = baseUrl;
+ this.pdfDocument = pdfDocument;
+ }
+ setViewer(pdfViewer) {
+ this.pdfViewer = pdfViewer;
+ }
+ setHistory(pdfHistory) {
+ this.pdfHistory = pdfHistory;
+ }
+ get pagesCount() {
+ return this.pdfDocument?.pagesMapper.pagesNumber || 0;
+ }
+ get page() {
+ return this.pdfDocument ? this.pdfViewer.currentPageNumber : 1;
+ }
+ set page(value) {
+ if (this.pdfDocument) {
+ this.pdfViewer.currentPageNumber = value;
+ }
+ }
+ get rotation() {
+ return this.pdfDocument ? this.pdfViewer.pagesRotation : 0;
+ }
+ set rotation(value) {
+ if (this.pdfDocument) {
+ this.pdfViewer.pagesRotation = value;
+ }
+ }
+ get isInPresentationMode() {
+ return this.pdfDocument ? this.pdfViewer.isInPresentationMode : false;
+ }
+ async goToDestination(dest) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ let namedDest, explicitDest, pageNumber;
+ if (typeof dest === "string") {
+ namedDest = dest;
+ explicitDest = await this.pdfDocument.getDestination(dest);
+ } else {
+ namedDest = null;
+ explicitDest = await dest;
+ }
+ if (!Array.isArray(explicitDest)) {
+ console.error(`goToDestination: "${explicitDest}" is not a valid destination array, for dest="${dest}".`);
+ return;
+ }
+ const [destRef] = explicitDest;
+ if (destRef && typeof destRef === "object") {
+ pageNumber = this.pdfDocument.cachedPageNumber(destRef);
+ if (!pageNumber) {
+ try {
+ pageNumber = (await this.pdfDocument.getPageIndex(destRef)) + 1;
+ } catch {
+ console.error(`goToDestination: "${destRef}" is not a valid page reference, for dest="${dest}".`);
+ return;
+ }
+ }
+ } else if (Number.isInteger(destRef)) {
+ pageNumber = destRef + 1;
+ }
+ if (!pageNumber || pageNumber < 1 || pageNumber > this.pagesCount) {
+ console.error(`goToDestination: "${pageNumber}" is not a valid page number, for dest="${dest}".`);
+ return;
+ }
+ if (this.pdfHistory) {
+ this.pdfHistory.pushCurrentPosition();
+ this.pdfHistory.push({
+ namedDest,
+ explicitDest,
+ pageNumber
+ });
+ }
+ this.pdfViewer.scrollPageIntoView({
+ pageNumber,
+ destArray: explicitDest,
+ ignoreDestinationZoom: this._ignoreDestinationZoom
+ });
+ const ac = new AbortController();
+ this.eventBus.on("textlayerrendered", evt => {
+ if (evt.pageNumber === pageNumber) {
+ evt.source.textLayer.div.focus();
+ ac.abort();
+ }
+ }, {
+ signal: ac.signal,
+ ...internalOpt
+ });
+ }
+ goToPage(val) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const pageNumber = typeof val === "string" && this.pdfViewer.pageLabelToPageNumber(val) || val | 0;
+ if (!(Number.isInteger(pageNumber) && pageNumber > 0 && pageNumber <= this.pagesCount)) {
+ console.error(`PDFLinkService.goToPage: "${val}" is not a valid page.`);
+ return;
+ }
+ if (this.pdfHistory) {
+ this.pdfHistory.pushCurrentPosition();
+ this.pdfHistory.pushPage(pageNumber);
+ }
+ this.pdfViewer.scrollPageIntoView({
+ pageNumber
+ });
+ }
+ goToXY(pageNumber, x, y, options = {}) {
+ this.pdfViewer.scrollPageIntoView({
+ pageNumber,
+ destArray: [null, {
+ name: "XYZ"
+ }, x, y],
+ ignoreDestinationZoom: true,
+ ...options
+ });
+ }
+ async getAttachmentContent(id) {
+ try {
+ return await this.pdfDocument?.getAttachmentContent(id);
+ } catch (error) {
+ if (!(error instanceof PasswordException)) {
+ console.warn(`Unable to load attachment content: ${error}`);
+ }
+ }
+ return null;
+ }
+ addLinkAttributes(link, url, newWindow = false) {
+ if (!url || typeof url !== "string") {
+ throw new Error('A valid "url" parameter must provided.');
+ }
+ const target = newWindow ? LinkTarget.BLANK : this.externalLinkTarget,
+ rel = this.externalLinkRel;
+ let displayUrl = url;
+ const parsedUrl = URL.parse(url);
+ if (parsedUrl?.username || parsedUrl?.password) {
+ parsedUrl.username = parsedUrl.password = "";
+ displayUrl = parsedUrl.href;
+ }
+ if (this.externalLinkEnabled) {
+ link.href = url;
+ link.title = displayUrl;
+ } else {
+ link.href = "";
+ link.title = `Disabled: ${displayUrl}`;
+ link.onclick = () => false;
+ }
+ let targetStr = "";
+ switch (target) {
+ case LinkTarget.NONE:
+ break;
+ case LinkTarget.SELF:
+ targetStr = "_self";
+ break;
+ case LinkTarget.BLANK:
+ targetStr = "_blank";
+ break;
+ case LinkTarget.PARENT:
+ targetStr = "_parent";
+ break;
+ case LinkTarget.TOP:
+ targetStr = "_top";
+ break;
+ }
+ link.target = targetStr;
+ link.rel = typeof rel === "string" ? rel : DEFAULT_LINK_REL;
+ }
+ getDestinationHash(dest) {
+ if (typeof dest === "string") {
+ if (dest.length > 0) {
+ return this.getAnchorUrl("#" + escape(dest));
+ }
+ } else if (Array.isArray(dest)) {
+ const str = JSON.stringify(dest);
+ if (str.length > 0) {
+ return this.getAnchorUrl("#" + escape(str));
+ }
+ }
+ return this.getAnchorUrl("");
+ }
+ getAnchorUrl(anchor) {
+ return this.baseUrl ? this.baseUrl + anchor : anchor;
+ }
+ setHash(hash) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ let pageNumber, dest;
+ if (hash.includes("=")) {
+ const params = parseQueryString(hash);
+ if (params.has("search")) {
+ const query = params.get("search").replaceAll('"', ""),
+ phrase = params.get("phrase") === "true";
+ this.eventBus.dispatch("findfromurlhash", {
+ source: this,
+ query: phrase ? query : query.match(/\S+/g)
+ });
+ }
+ if (params.has("page")) {
+ pageNumber = params.get("page") | 0 || 1;
+ }
+ if (params.has("zoom")) {
+ const zoomArgs = params.get("zoom").split(",");
+ const zoomArg = zoomArgs[0];
+ const zoomArgNumber = parseFloat(zoomArg);
+ if (!zoomArg.includes("Fit")) {
+ dest = [null, {
+ name: "XYZ"
+ }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null, zoomArgs.length > 2 ? zoomArgs[2] | 0 : null, zoomArgNumber ? zoomArgNumber / 100 : zoomArg];
+ } else if (zoomArg === "Fit" || zoomArg === "FitB") {
+ dest = [null, {
+ name: zoomArg
+ }];
+ } else if (zoomArg === "FitH" || zoomArg === "FitBH" || zoomArg === "FitV" || zoomArg === "FitBV") {
+ dest = [null, {
+ name: zoomArg
+ }, zoomArgs.length > 1 ? zoomArgs[1] | 0 : null];
+ } else if (zoomArg === "FitR") {
+ if (zoomArgs.length !== 5) {
+ console.error('PDFLinkService.setHash: Not enough parameters for "FitR".');
+ } else {
+ dest = [null, {
+ name: zoomArg
+ }, zoomArgs[1] | 0, zoomArgs[2] | 0, zoomArgs[3] | 0, zoomArgs[4] | 0];
+ }
+ } else {
+ console.error(`PDFLinkService.setHash: "${zoomArg}" is not a valid zoom value.`);
+ }
+ }
+ if (dest) {
+ this.pdfViewer.scrollPageIntoView({
+ pageNumber: pageNumber || this.page,
+ destArray: dest,
+ allowNegativeOffset: true
+ });
+ } else if (pageNumber) {
+ this.page = pageNumber;
+ }
+ if (params.has("pagemode")) {
+ this.eventBus.dispatch("pagemode", {
+ source: this,
+ mode: params.get("pagemode")
+ });
+ }
+ if (params.has("nameddest")) {
+ this.goToDestination(params.get("nameddest"));
+ }
+ return;
+ }
+ dest = unescape(hash);
+ try {
+ dest = JSON.parse(dest);
+ if (!Array.isArray(dest)) {
+ dest = dest.toString();
+ }
+ } catch {}
+ if (typeof dest === "string" || isValidExplicitDest(dest)) {
+ this.goToDestination(dest);
+ return;
+ }
+ console.error(`PDFLinkService.setHash: "${unescape(hash)}" is not a valid destination.`);
+ }
+ executeNamedAction(action) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ switch (action) {
+ case "GoBack":
+ this.pdfHistory?.back();
+ break;
+ case "GoForward":
+ this.pdfHistory?.forward();
+ break;
+ case "NextPage":
+ this.pdfViewer.nextPage();
+ break;
+ case "PrevPage":
+ this.pdfViewer.previousPage();
+ break;
+ case "LastPage":
+ this.page = this.pagesCount;
+ break;
+ case "FirstPage":
+ this.page = 1;
+ break;
+ default:
+ break;
+ }
+ this.eventBus.dispatch("namedaction", {
+ source: this,
+ action
+ });
+ }
+ async executeSetOCGState(action) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const pdfDocument = this.pdfDocument,
+ optionalContentConfig = await this.pdfViewer.optionalContentConfigPromise;
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ optionalContentConfig.setOCGState(action);
+ this.pdfViewer.optionalContentConfigPromise = Promise.resolve(optionalContentConfig);
+ }
+}
+class SimpleLinkService extends PDFLinkService {
+ setDocument(pdfDocument, baseUrl = null) {}
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.some.js
+var es_iterator_some = __webpack_require__(3579);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.find.js
+var es_iterator_find = __webpack_require__(116);
+;// ./web/event_utils.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const WaitOnType = {
+ EVENT: "event",
+ TIMEOUT: "timeout"
+};
+async function waitOnEventOrTimeout({
+ target,
+ name,
+ delay = 0
+}) {
+ if (typeof target !== "object" || !(name && typeof name === "string") || !(Number.isInteger(delay) && delay >= 0)) {
+ throw new Error("waitOnEventOrTimeout - invalid parameters.");
+ }
+ const {
+ promise,
+ resolve
+ } = Promise.withResolvers();
+ const ac = new AbortController();
+ function handler(type) {
+ ac.abort();
+ clearTimeout(timeout);
+ resolve(type);
+ }
+ const evtMethod = target instanceof EventBus ? "on" : "addEventListener";
+ const evtOpts = target instanceof EventBus ? {
+ signal: ac.signal,
+ ...internalOpt
+ } : {
+ signal: ac.signal
+ };
+ target[evtMethod](name, handler.bind(null, WaitOnType.EVENT), evtOpts);
+ const timeout = setTimeout(handler.bind(null, WaitOnType.TIMEOUT), delay);
+ return promise;
+}
+class EventBus {
+ #listeners = new Map();
+ constructor() {
+ Object.seal(this);
+ }
+ on(eventName, listener, options = null) {
+ let rmAbort = null;
+ if (options?.signal instanceof AbortSignal) {
+ const {
+ signal
+ } = options;
+ if (signal.aborted) {
+ console.error("Cannot use an `aborted` signal.");
+ return;
+ }
+ const onAbort = () => this.off(eventName, listener);
+ rmAbort = () => signal.removeEventListener("abort", onAbort);
+ signal.addEventListener("abort", onAbort);
+ }
+ this.#listeners.getOrInsertComputed(eventName, makeSet).add({
+ listener,
+ internal: options?.internal === INTERNAL_EVT,
+ once: options?.once === true,
+ rmAbort
+ });
+ }
+ off(eventName, listener, options = null) {
+ const eventListeners = this.#listeners.get(eventName);
+ const evt = eventListeners?.keys().find(e => e.listener === listener);
+ if (evt) {
+ evt.rmAbort?.();
+ eventListeners.delete(evt);
+ }
+ }
+ dispatch(eventName, data) {
+ const eventListeners = this.#listeners.get(eventName);
+ if (!eventListeners?.size) {
+ return;
+ }
+ let extListeners;
+ for (const {
+ listener,
+ internal,
+ once
+ } of new Set(eventListeners)) {
+ if (once) {
+ this.off(eventName, listener);
+ }
+ if (!internal) {
+ (extListeners ??= []).push(listener);
+ continue;
+ }
+ listener(data);
+ }
+ if (extListeners) {
+ for (const listener of extListeners) {
+ listener(data);
+ }
+ }
+ }
+}
+class FirefoxEventBus extends EventBus {
+ #externalServices;
+ #globalEventNames;
+ #isInAutomation;
+ constructor(globalEventNames, externalServices, isInAutomation) {
+ super();
+ this.#globalEventNames = globalEventNames;
+ this.#externalServices = externalServices;
+ this.#isInAutomation = isInAutomation;
+ }
+ dispatch(eventName, data) {
+ throw new Error("Not implemented: FirefoxEventBus.dispatch");
+ }
+}
+
+;// ./web/external_services.js
+class BaseExternalServices {
+ updateFindControlState(data) {}
+ updateFindMatchesCount(data) {}
+ initPassiveLoading() {}
+ reportTelemetry(data) {}
+ reportText(data) {}
+ async createL10n() {
+ throw new Error("Not implemented: createL10n");
+ }
+ createScripting() {
+ throw new Error("Not implemented: createScripting");
+ }
+ createSignatureStorage() {
+ throw new Error("Not implemented: createSignatureStorage");
+ }
+ createSignatureVerifier() {
+ return null;
+ }
+ updateEditorStates(data) {
+ throw new Error("Not implemented: updateEditorStates");
+ }
+ dispatchGlobalEvent(_event) {}
+}
+
+;// ./web/preferences.js
+
+class BasePreferences {
+ #defaults = Object.freeze(AppOptions.getAll(OptionKind.PREFERENCE, true));
+ #initializedPromise = null;
+ constructor() {
+ this.#initializedPromise = this._readFromStorage(this.#defaults).then(({
+ browserPrefs,
+ prefs
+ }) => {
+ if (AppOptions._checkDisablePreferences()) {
+ return;
+ }
+ AppOptions.setAll({
+ ...browserPrefs,
+ ...prefs
+ }, true);
+ });
+ }
+ async _writeToStorage(prefObj) {
+ throw new Error("Not implemented: _writeToStorage");
+ }
+ async _readFromStorage(prefObj) {
+ throw new Error("Not implemented: _readFromStorage");
+ }
+ async reset() {
+ await this.#initializedPromise;
+ AppOptions.setAll(this.#defaults, true);
+ await this._writeToStorage(this.#defaults);
+ }
+ async set(name, value) {
+ await this.#initializedPromise;
+ AppOptions.setAll({
+ [name]: value
+ }, true);
+ await this._writeToStorage(AppOptions.getAll(OptionKind.PREFERENCE));
+ }
+ async get(name) {
+ await this.#initializedPromise;
+ return AppOptions.get(name);
+ }
+ get defaults() {
+ return this.#defaults;
+ }
+ get initializedPromise() {
+ return this.#initializedPromise;
+ }
+}
+
+;// ./node_modules/@fluent/bundle/esm/types.js
+class FluentType {
+ constructor(value) {
+ this.value = value;
+ }
+ valueOf() {
+ return this.value;
+ }
+}
+class FluentNone extends FluentType {
+ constructor(value = "???") {
+ super(value);
+ }
+ toString(scope) {
+ return `{${this.value}}`;
+ }
+}
+class FluentNumber extends FluentType {
+ constructor(value, opts = {}) {
+ super(value);
+ this.opts = opts;
+ }
+ toString(scope) {
+ if (scope) {
+ try {
+ const nf = scope.memoizeIntlObject(Intl.NumberFormat, this.opts);
+ return nf.format(this.value);
+ } catch (err) {
+ scope.reportError(err);
+ }
+ }
+ return this.value.toString(10);
+ }
+}
+class FluentDateTime extends FluentType {
+ static supportsValue(value) {
+ if (typeof value === "number") return true;
+ if (value instanceof Date) return true;
+ if (value instanceof FluentType) return FluentDateTime.supportsValue(value.valueOf());
+ if ("Temporal" in globalThis) {
+ const _Temporal = globalThis.Temporal;
+ if (value instanceof _Temporal.Instant || value instanceof _Temporal.PlainDateTime || value instanceof _Temporal.PlainDate || value instanceof _Temporal.PlainMonthDay || value instanceof _Temporal.PlainTime || value instanceof _Temporal.PlainYearMonth) {
+ return true;
+ }
+ }
+ return false;
+ }
+ constructor(value, opts = {}) {
+ if (value instanceof FluentDateTime) {
+ opts = {
+ ...value.opts,
+ ...opts
+ };
+ value = value.value;
+ } else if (value instanceof FluentType) {
+ value = value.valueOf();
+ }
+ if (typeof value === "object" && "calendarId" in value && opts.calendar === undefined) {
+ opts = {
+ ...opts,
+ calendar: value.calendarId
+ };
+ }
+ super(value);
+ this.opts = opts;
+ }
+ [Symbol.toPrimitive](hint) {
+ return hint === "string" ? this.toString() : this.toNumber();
+ }
+ toNumber() {
+ const value = this.value;
+ if (typeof value === "number") return value;
+ if (value instanceof Date) return value.getTime();
+ if ("epochMilliseconds" in value) {
+ return value.epochMilliseconds;
+ }
+ if ("toZonedDateTime" in value) {
+ return value.toZonedDateTime("UTC").epochMilliseconds;
+ }
+ throw new TypeError("Unwrapping a non-number value as a number");
+ }
+ toString(scope) {
+ if (scope) {
+ try {
+ const dtf = scope.memoizeIntlObject(Intl.DateTimeFormat, this.opts);
+ return dtf.format(this.value);
+ } catch (err) {
+ scope.reportError(err);
+ }
+ }
+ if (typeof this.value === "number" || this.value instanceof Date) {
+ return new Date(this.value).toISOString();
+ }
+ return this.value.toString();
+ }
+}
+;// ./node_modules/@fluent/bundle/esm/resolver.js
+
+
+const MAX_PLACEABLES = 100;
+const FSI = "\u2068";
+const PDI = "\u2069";
+function match(scope, selector, key) {
+ if (key === selector) {
+ return true;
+ }
+ if (key instanceof FluentNumber && selector instanceof FluentNumber && key.value === selector.value) {
+ return true;
+ }
+ if (selector instanceof FluentNumber && typeof key === "string") {
+ let category = scope.memoizeIntlObject(Intl.PluralRules, selector.opts).select(selector.value);
+ if (key === category) {
+ return true;
+ }
+ }
+ return false;
+}
+function getDefault(scope, variants, star) {
+ if (variants[star]) {
+ return resolvePattern(scope, variants[star].value);
+ }
+ scope.reportError(new RangeError("No default"));
+ return new FluentNone();
+}
+function getArguments(scope, args) {
+ const positional = [];
+ const named = Object.create(null);
+ for (const arg of args) {
+ if (arg.type === "narg") {
+ named[arg.name] = resolveExpression(scope, arg.value);
+ } else {
+ positional.push(resolveExpression(scope, arg));
+ }
+ }
+ return {
+ positional,
+ named
+ };
+}
+function resolveExpression(scope, expr) {
+ switch (expr.type) {
+ case "str":
+ return expr.value;
+ case "num":
+ return new FluentNumber(expr.value, {
+ minimumFractionDigits: expr.precision
+ });
+ case "var":
+ return resolveVariableReference(scope, expr);
+ case "mesg":
+ return resolveMessageReference(scope, expr);
+ case "term":
+ return resolveTermReference(scope, expr);
+ case "func":
+ return resolveFunctionReference(scope, expr);
+ case "select":
+ return resolveSelectExpression(scope, expr);
+ default:
+ return new FluentNone();
+ }
+}
+function resolveVariableReference(scope, {
+ name
+}) {
+ let arg;
+ if (scope.params) {
+ if (Object.prototype.hasOwnProperty.call(scope.params, name)) {
+ arg = scope.params[name];
+ } else {
+ return new FluentNone(`$${name}`);
+ }
+ } else if (scope.args && Object.prototype.hasOwnProperty.call(scope.args, name)) {
+ arg = scope.args[name];
+ } else {
+ scope.reportError(new ReferenceError(`Unknown variable: $${name}`));
+ return new FluentNone(`$${name}`);
+ }
+ if (arg instanceof FluentType) {
+ return arg;
+ }
+ switch (typeof arg) {
+ case "string":
+ return arg;
+ case "number":
+ return new FluentNumber(arg);
+ case "object":
+ if (FluentDateTime.supportsValue(arg)) {
+ return new FluentDateTime(arg);
+ }
+ default:
+ scope.reportError(new TypeError(`Variable type not supported: $${name}, ${typeof arg}`));
+ return new FluentNone(`$${name}`);
+ }
+}
+function resolveMessageReference(scope, {
+ name,
+ attr
+}) {
+ const message = scope.bundle._messages.get(name);
+ if (!message) {
+ scope.reportError(new ReferenceError(`Unknown message: ${name}`));
+ return new FluentNone(name);
+ }
+ if (attr) {
+ const attribute = message.attributes[attr];
+ if (attribute) {
+ return resolvePattern(scope, attribute);
+ }
+ scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
+ return new FluentNone(`${name}.${attr}`);
+ }
+ if (message.value) {
+ return resolvePattern(scope, message.value);
+ }
+ scope.reportError(new ReferenceError(`No value: ${name}`));
+ return new FluentNone(name);
+}
+function resolveTermReference(scope, {
+ name,
+ attr,
+ args
+}) {
+ const id = `-${name}`;
+ const term = scope.bundle._terms.get(id);
+ if (!term) {
+ scope.reportError(new ReferenceError(`Unknown term: ${id}`));
+ return new FluentNone(id);
+ }
+ if (attr) {
+ const attribute = term.attributes[attr];
+ if (attribute) {
+ scope.params = getArguments(scope, args).named;
+ const resolved = resolvePattern(scope, attribute);
+ scope.params = null;
+ return resolved;
+ }
+ scope.reportError(new ReferenceError(`Unknown attribute: ${attr}`));
+ return new FluentNone(`${id}.${attr}`);
+ }
+ scope.params = getArguments(scope, args).named;
+ const resolved = resolvePattern(scope, term.value);
+ scope.params = null;
+ return resolved;
+}
+function resolveFunctionReference(scope, {
+ name,
+ args
+}) {
+ let func = scope.bundle._functions[name];
+ if (!func) {
+ scope.reportError(new ReferenceError(`Unknown function: ${name}()`));
+ return new FluentNone(`${name}()`);
+ }
+ if (typeof func !== "function") {
+ scope.reportError(new TypeError(`Function ${name}() is not callable`));
+ return new FluentNone(`${name}()`);
+ }
+ try {
+ let resolved = getArguments(scope, args);
+ return func(resolved.positional, resolved.named);
+ } catch (err) {
+ scope.reportError(err);
+ return new FluentNone(`${name}()`);
+ }
+}
+function resolveSelectExpression(scope, {
+ selector,
+ variants,
+ star
+}) {
+ let sel = resolveExpression(scope, selector);
+ if (sel instanceof FluentNone) {
+ return getDefault(scope, variants, star);
+ }
+ for (const variant of variants) {
+ const key = resolveExpression(scope, variant.key);
+ if (match(scope, sel, key)) {
+ return resolvePattern(scope, variant.value);
+ }
+ }
+ return getDefault(scope, variants, star);
+}
+function resolveComplexPattern(scope, ptn) {
+ if (scope.dirty.has(ptn)) {
+ scope.reportError(new RangeError("Cyclic reference"));
+ return new FluentNone();
+ }
+ scope.dirty.add(ptn);
+ const result = [];
+ const useIsolating = scope.bundle._useIsolating && ptn.length > 1;
+ for (const elem of ptn) {
+ if (typeof elem === "string") {
+ result.push(scope.bundle._transform(elem));
+ continue;
+ }
+ scope.placeables++;
+ if (scope.placeables > MAX_PLACEABLES) {
+ scope.dirty.delete(ptn);
+ throw new RangeError(`Too many placeables expanded: ${scope.placeables}, ` + `max allowed is ${MAX_PLACEABLES}`);
+ }
+ if (useIsolating) {
+ result.push(FSI);
+ }
+ result.push(resolveExpression(scope, elem).toString(scope));
+ if (useIsolating) {
+ result.push(PDI);
+ }
+ }
+ scope.dirty.delete(ptn);
+ return result.join("");
+}
+function resolvePattern(scope, value) {
+ if (typeof value === "string") {
+ return scope.bundle._transform(value);
+ }
+ return resolveComplexPattern(scope, value);
+}
+;// ./node_modules/@fluent/bundle/esm/scope.js
+
+
+class Scope {
+ constructor(bundle, errors, args) {
+ this.dirty = new WeakSet();
+ this.params = null;
+ this.placeables = 0;
+ this.bundle = bundle;
+ this.errors = errors;
+ this.args = args;
+ }
+ reportError(error) {
+ if (!this.errors || !(error instanceof Error)) {
+ throw error;
+ }
+ this.errors.push(error);
+ }
+ memoizeIntlObject(ctor, opts) {
+ let cache = this.bundle._intls.get(ctor);
+ if (!cache) {
+ cache = {};
+ this.bundle._intls.set(ctor, cache);
+ }
+ let id = JSON.stringify(opts);
+ if (!cache[id]) {
+ cache[id] = new ctor(this.bundle.locales, opts);
+ }
+ return cache[id];
+ }
+}
+;// ./node_modules/@fluent/bundle/esm/builtins.js
+
+
+function values(opts, allowed) {
+ const unwrapped = Object.create(null);
+ for (const [name, opt] of Object.entries(opts)) {
+ if (allowed.includes(name)) {
+ unwrapped[name] = opt.valueOf();
+ }
+ }
+ return unwrapped;
+}
+const NUMBER_ALLOWED = ["unitDisplay", "currencyDisplay", "useGrouping", "minimumIntegerDigits", "minimumFractionDigits", "maximumFractionDigits", "minimumSignificantDigits", "maximumSignificantDigits"];
+function NUMBER(args, opts) {
+ let arg = args[0];
+ if (arg instanceof FluentNone) {
+ return new FluentNone(`NUMBER(${arg.valueOf()})`);
+ }
+ if (arg instanceof FluentNumber) {
+ return new FluentNumber(arg.valueOf(), {
+ ...arg.opts,
+ ...values(opts, NUMBER_ALLOWED)
+ });
+ }
+ if (arg instanceof FluentDateTime) {
+ return new FluentNumber(arg.toNumber(), {
+ ...values(opts, NUMBER_ALLOWED)
+ });
+ }
+ throw new TypeError("Invalid argument to NUMBER");
+}
+const DATETIME_ALLOWED = ["dateStyle", "timeStyle", "fractionalSecondDigits", "dayPeriod", "hour12", "weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName"];
+function DATETIME(args, opts) {
+ let arg = args[0];
+ if (arg instanceof FluentNone) {
+ return new FluentNone(`DATETIME(${arg.valueOf()})`);
+ }
+ if (arg instanceof FluentDateTime || arg instanceof FluentNumber) {
+ return new FluentDateTime(arg, values(opts, DATETIME_ALLOWED));
+ }
+ throw new TypeError("Invalid argument to DATETIME");
+}
+;// ./node_modules/@fluent/bundle/esm/memoizer.js
+
+
+const cache = new Map();
+function getMemoizerForLocale(locales) {
+ const stringLocale = Array.isArray(locales) ? locales.join(" ") : locales;
+ let memoizer = cache.get(stringLocale);
+ if (memoizer === undefined) {
+ memoizer = new Map();
+ cache.set(stringLocale, memoizer);
+ }
+ return memoizer;
+}
+;// ./node_modules/@fluent/bundle/esm/bundle.js
+
+
+
+
+
+
+
+
+class FluentBundle {
+ constructor(locales, {
+ functions,
+ useIsolating = true,
+ transform = v => v
+ } = {}) {
+ this._terms = new Map();
+ this._messages = new Map();
+ this.locales = Array.isArray(locales) ? locales : [locales];
+ this._functions = {
+ NUMBER: NUMBER,
+ DATETIME: DATETIME,
+ ...functions
+ };
+ this._useIsolating = useIsolating;
+ this._transform = transform;
+ this._intls = getMemoizerForLocale(locales);
+ }
+ hasMessage(id) {
+ return this._messages.has(id);
+ }
+ getMessage(id) {
+ return this._messages.get(id);
+ }
+ addResource(res, {
+ allowOverrides = false
+ } = {}) {
+ const errors = [];
+ for (let i = 0; i < res.body.length; i++) {
+ let entry = res.body[i];
+ if (entry.id.startsWith("-")) {
+ if (allowOverrides === false && this._terms.has(entry.id)) {
+ errors.push(new Error(`Attempt to override an existing term: "${entry.id}"`));
+ continue;
+ }
+ this._terms.set(entry.id, entry);
+ } else {
+ if (allowOverrides === false && this._messages.has(entry.id)) {
+ errors.push(new Error(`Attempt to override an existing message: "${entry.id}"`));
+ continue;
+ }
+ this._messages.set(entry.id, entry);
+ }
+ }
+ return errors;
+ }
+ formatPattern(pattern, args = null, errors = null) {
+ if (typeof pattern === "string") {
+ return this._transform(pattern);
+ }
+ let scope = new Scope(this, errors, args);
+ try {
+ let value = resolveComplexPattern(scope, pattern);
+ return value.toString(scope);
+ } catch (err) {
+ if (scope.errors && err instanceof Error) {
+ scope.errors.push(err);
+ return new FluentNone().toString(scope);
+ }
+ throw err;
+ }
+ }
+}
+;// ./node_modules/@fluent/bundle/esm/resource.js
+
+const RE_MESSAGE_START = /^(-?[a-zA-Z][\w-]*) *= */gm;
+const RE_ATTRIBUTE_START = /\.([a-zA-Z][\w-]*) *= */y;
+const RE_VARIANT_START = /\*?\[/y;
+const RE_NUMBER_LITERAL = /(-?[0-9]+(?:\.([0-9]+))?)/y;
+const RE_IDENTIFIER = /([a-zA-Z][\w-]*)/y;
+const RE_REFERENCE = /([$-])?([a-zA-Z][\w-]*)(?:\.([a-zA-Z][\w-]*))?/y;
+const RE_FUNCTION_NAME = /^[A-Z][A-Z0-9_-]*$/;
+const RE_TEXT_RUN = /([^{}\n\r]+)/y;
+const RE_STRING_RUN = /([^\\"\n\r]*)/y;
+const RE_STRING_ESCAPE = /\\([\\"])/y;
+const RE_UNICODE_ESCAPE = /\\u([a-fA-F0-9]{4})|\\U([a-fA-F0-9]{6})/y;
+const RE_LEADING_NEWLINES = /^\n+/;
+const RE_TRAILING_SPACES = / +$/;
+const RE_BLANK_LINES = / *\r?\n/g;
+const RE_INDENT = /( *)$/;
+const TOKEN_BRACE_OPEN = /{\s*/y;
+const TOKEN_BRACE_CLOSE = /\s*}/y;
+const TOKEN_BRACKET_OPEN = /\[\s*/y;
+const TOKEN_BRACKET_CLOSE = /\s*] */y;
+const TOKEN_PAREN_OPEN = /\s*\(\s*/y;
+const TOKEN_ARROW = /\s*->\s*/y;
+const TOKEN_COLON = /\s*:\s*/y;
+const TOKEN_COMMA = /\s*,?\s*/y;
+const TOKEN_BLANK = /\s+/y;
+class FluentResource {
+ constructor(source) {
+ this.body = [];
+ RE_MESSAGE_START.lastIndex = 0;
+ let cursor = 0;
+ while (true) {
+ let next = RE_MESSAGE_START.exec(source);
+ if (next === null) {
+ break;
+ }
+ cursor = RE_MESSAGE_START.lastIndex;
+ try {
+ this.body.push(parseMessage(next[1]));
+ } catch (err) {
+ if (err instanceof SyntaxError) {
+ continue;
+ }
+ throw err;
+ }
+ }
+ function test(re) {
+ re.lastIndex = cursor;
+ return re.test(source);
+ }
+ function consumeChar(char, errorClass) {
+ if (source[cursor] === char) {
+ cursor++;
+ return true;
+ }
+ if (errorClass) {
+ throw new errorClass(`Expected ${char}`);
+ }
+ return false;
+ }
+ function consumeToken(re, errorClass) {
+ if (test(re)) {
+ cursor = re.lastIndex;
+ return true;
+ }
+ if (errorClass) {
+ throw new errorClass(`Expected ${re.toString()}`);
+ }
+ return false;
+ }
+ function match(re) {
+ re.lastIndex = cursor;
+ let result = re.exec(source);
+ if (result === null) {
+ throw new SyntaxError(`Expected ${re.toString()}`);
+ }
+ cursor = re.lastIndex;
+ return result;
+ }
+ function match1(re) {
+ return match(re)[1];
+ }
+ function parseMessage(id) {
+ let value = parsePattern();
+ let attributes = parseAttributes();
+ if (value === null && Object.keys(attributes).length === 0) {
+ throw new SyntaxError("Expected message value or attributes");
+ }
+ return {
+ id,
+ value,
+ attributes
+ };
+ }
+ function parseAttributes() {
+ let attrs = Object.create(null);
+ while (test(RE_ATTRIBUTE_START)) {
+ let name = match1(RE_ATTRIBUTE_START);
+ let value = parsePattern();
+ if (value === null) {
+ throw new SyntaxError("Expected attribute value");
+ }
+ attrs[name] = value;
+ }
+ return attrs;
+ }
+ function parsePattern() {
+ let first;
+ if (test(RE_TEXT_RUN)) {
+ first = match1(RE_TEXT_RUN);
+ }
+ if (source[cursor] === "{" || source[cursor] === "}") {
+ return parsePatternElements(first ? [first] : [], Infinity);
+ }
+ let indent = parseIndent();
+ if (indent) {
+ if (first) {
+ return parsePatternElements([first, indent], indent.length);
+ }
+ indent.value = trim(indent.value, RE_LEADING_NEWLINES);
+ return parsePatternElements([indent], indent.length);
+ }
+ if (first) {
+ return trim(first, RE_TRAILING_SPACES);
+ }
+ return null;
+ }
+ function parsePatternElements(elements = [], commonIndent) {
+ while (true) {
+ if (test(RE_TEXT_RUN)) {
+ elements.push(match1(RE_TEXT_RUN));
+ continue;
+ }
+ if (source[cursor] === "{") {
+ elements.push(parsePlaceable());
+ continue;
+ }
+ if (source[cursor] === "}") {
+ throw new SyntaxError("Unbalanced closing brace");
+ }
+ let indent = parseIndent();
+ if (indent) {
+ elements.push(indent);
+ commonIndent = Math.min(commonIndent, indent.length);
+ continue;
+ }
+ break;
+ }
+ let lastIndex = elements.length - 1;
+ let lastElement = elements[lastIndex];
+ if (typeof lastElement === "string") {
+ elements[lastIndex] = trim(lastElement, RE_TRAILING_SPACES);
+ }
+ let baked = [];
+ for (let element of elements) {
+ if (element instanceof Indent) {
+ element = element.value.slice(0, element.value.length - commonIndent);
+ }
+ if (element) {
+ baked.push(element);
+ }
+ }
+ return baked;
+ }
+ function parsePlaceable() {
+ consumeToken(TOKEN_BRACE_OPEN, SyntaxError);
+ let selector = parseInlineExpression();
+ if (consumeToken(TOKEN_BRACE_CLOSE)) {
+ return selector;
+ }
+ if (consumeToken(TOKEN_ARROW)) {
+ let variants = parseVariants();
+ consumeToken(TOKEN_BRACE_CLOSE, SyntaxError);
+ return {
+ type: "select",
+ selector,
+ ...variants
+ };
+ }
+ throw new SyntaxError("Unclosed placeable");
+ }
+ function parseInlineExpression() {
+ if (source[cursor] === "{") {
+ return parsePlaceable();
+ }
+ if (test(RE_REFERENCE)) {
+ let [, sigil, name, attr = null] = match(RE_REFERENCE);
+ if (sigil === "$") {
+ return {
+ type: "var",
+ name
+ };
+ }
+ if (consumeToken(TOKEN_PAREN_OPEN)) {
+ let args = parseArguments();
+ if (sigil === "-") {
+ return {
+ type: "term",
+ name,
+ attr,
+ args
+ };
+ }
+ if (RE_FUNCTION_NAME.test(name)) {
+ return {
+ type: "func",
+ name,
+ args
+ };
+ }
+ throw new SyntaxError("Function names must be all upper-case");
+ }
+ if (sigil === "-") {
+ return {
+ type: "term",
+ name,
+ attr,
+ args: []
+ };
+ }
+ return {
+ type: "mesg",
+ name,
+ attr
+ };
+ }
+ return parseLiteral();
+ }
+ function parseArguments() {
+ let args = [];
+ while (true) {
+ switch (source[cursor]) {
+ case ")":
+ cursor++;
+ return args;
+ case undefined:
+ throw new SyntaxError("Unclosed argument list");
+ }
+ args.push(parseArgument());
+ consumeToken(TOKEN_COMMA);
+ }
+ }
+ function parseArgument() {
+ let expr = parseInlineExpression();
+ if (expr.type !== "mesg") {
+ return expr;
+ }
+ if (consumeToken(TOKEN_COLON)) {
+ return {
+ type: "narg",
+ name: expr.name,
+ value: parseLiteral()
+ };
+ }
+ return expr;
+ }
+ function parseVariants() {
+ let variants = [];
+ let count = 0;
+ let star;
+ while (test(RE_VARIANT_START)) {
+ if (consumeChar("*")) {
+ star = count;
+ }
+ let key = parseVariantKey();
+ let value = parsePattern();
+ if (value === null) {
+ throw new SyntaxError("Expected variant value");
+ }
+ variants[count++] = {
+ key,
+ value
+ };
+ }
+ if (count === 0) {
+ return null;
+ }
+ if (star === undefined) {
+ throw new SyntaxError("Expected default variant");
+ }
+ return {
+ variants,
+ star
+ };
+ }
+ function parseVariantKey() {
+ consumeToken(TOKEN_BRACKET_OPEN, SyntaxError);
+ let key;
+ if (test(RE_NUMBER_LITERAL)) {
+ key = parseNumberLiteral();
+ } else {
+ key = {
+ type: "str",
+ value: match1(RE_IDENTIFIER)
+ };
+ }
+ consumeToken(TOKEN_BRACKET_CLOSE, SyntaxError);
+ return key;
+ }
+ function parseLiteral() {
+ if (test(RE_NUMBER_LITERAL)) {
+ return parseNumberLiteral();
+ }
+ if (source[cursor] === '"') {
+ return parseStringLiteral();
+ }
+ throw new SyntaxError("Invalid expression");
+ }
+ function parseNumberLiteral() {
+ let [, value, fraction = ""] = match(RE_NUMBER_LITERAL);
+ let precision = fraction.length;
+ return {
+ type: "num",
+ value: parseFloat(value),
+ precision
+ };
+ }
+ function parseStringLiteral() {
+ consumeChar('"', SyntaxError);
+ let value = "";
+ while (true) {
+ value += match1(RE_STRING_RUN);
+ if (source[cursor] === "\\") {
+ value += parseEscapeSequence();
+ continue;
+ }
+ if (consumeChar('"')) {
+ return {
+ type: "str",
+ value
+ };
+ }
+ throw new SyntaxError("Unclosed string literal");
+ }
+ }
+ function parseEscapeSequence() {
+ if (test(RE_STRING_ESCAPE)) {
+ return match1(RE_STRING_ESCAPE);
+ }
+ if (test(RE_UNICODE_ESCAPE)) {
+ let [, codepoint4, codepoint6] = match(RE_UNICODE_ESCAPE);
+ let codepoint = parseInt(codepoint4 || codepoint6, 16);
+ return codepoint <= 0xd7ff || 0xe000 <= codepoint ? String.fromCodePoint(codepoint) : "�";
+ }
+ throw new SyntaxError("Unknown escape sequence");
+ }
+ function parseIndent() {
+ let start = cursor;
+ consumeToken(TOKEN_BLANK);
+ switch (source[cursor]) {
+ case ".":
+ case "[":
+ case "*":
+ case "}":
+ case undefined:
+ return false;
+ case "{":
+ return makeIndent(source.slice(start, cursor));
+ }
+ if (source[cursor - 1] === " ") {
+ return makeIndent(source.slice(start, cursor));
+ }
+ return false;
+ }
+ function trim(text, re) {
+ return text.replace(re, "");
+ }
+ function makeIndent(blank) {
+ let value = blank.replace(RE_BLANK_LINES, "\n");
+ let length = RE_INDENT.exec(blank)[1].length;
+ return new Indent(value, length);
+ }
+ }
+}
+class Indent {
+ constructor(value, length) {
+ this.value = value;
+ this.length = length;
+ }
+}
+;// ./node_modules/@fluent/bundle/esm/index.js
+
+
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.map.js
+var es_iterator_map = __webpack_require__(1701);
+;// ./node_modules/@fluent/dom/esm/overlay.js
+
+
+
+const reOverlay = /<|?\w+;/;
+const TEXT_LEVEL_ELEMENTS = {
+ "http://www.w3.org/1999/xhtml": ["em", "strong", "small", "s", "cite", "q", "dfn", "abbr", "data", "time", "code", "var", "samp", "kbd", "sub", "sup", "i", "b", "u", "mark", "bdi", "bdo", "span", "br", "wbr"]
+};
+const LOCALIZABLE_ATTRIBUTES = {
+ "http://www.w3.org/1999/xhtml": {
+ global: ["title", "aria-description", "aria-label", "aria-valuetext"],
+ a: ["download"],
+ area: ["download", "alt"],
+ input: ["alt", "placeholder"],
+ menuitem: ["label"],
+ menu: ["label"],
+ optgroup: ["label"],
+ option: ["label"],
+ track: ["label"],
+ img: ["alt"],
+ textarea: ["placeholder"],
+ th: ["abbr"]
+ },
+ "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": {
+ global: ["accesskey", "aria-label", "aria-valuetext", "label", "title", "tooltiptext"],
+ description: ["value"],
+ key: ["key", "keycode"],
+ label: ["value"],
+ textbox: ["placeholder", "value"]
+ }
+};
+function translateElement(element, translation) {
+ const {
+ value
+ } = translation;
+ if (typeof value === "string") {
+ if (element.localName === "title" && element.namespaceURI === "http://www.w3.org/1999/xhtml") {
+ element.textContent = value;
+ } else if (!reOverlay.test(value)) {
+ element.textContent = value;
+ } else {
+ const templateElement = element.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml", "template");
+ templateElement.innerHTML = value;
+ overlayChildNodes(templateElement.content, element);
+ }
+ }
+ overlayAttributes(translation, element);
+}
+function overlayChildNodes(fromFragment, toElement) {
+ for (const childNode of fromFragment.childNodes) {
+ if (childNode.nodeType === childNode.TEXT_NODE) {
+ continue;
+ }
+ if (childNode.hasAttribute("data-l10n-name")) {
+ const sanitized = getNodeForNamedElement(toElement, childNode);
+ fromFragment.replaceChild(sanitized, childNode);
+ continue;
+ }
+ if (isElementAllowed(childNode)) {
+ const sanitized = createSanitizedElement(childNode);
+ fromFragment.replaceChild(sanitized, childNode);
+ continue;
+ }
+ console.warn(`An element of forbidden type "${childNode.localName}" was found in ` + "the translation. Only safe text-level elements and elements with " + "data-l10n-name are allowed.");
+ fromFragment.replaceChild(createTextNodeFromTextContent(childNode), childNode);
+ }
+ toElement.textContent = "";
+ toElement.appendChild(fromFragment);
+}
+function hasAttribute(attributes, name) {
+ if (!attributes) {
+ return false;
+ }
+ for (let attr of attributes) {
+ if (attr.name === name) {
+ return true;
+ }
+ }
+ return false;
+}
+function overlayAttributes(fromElement, toElement) {
+ const explicitlyAllowed = toElement.hasAttribute("data-l10n-attrs") ? toElement.getAttribute("data-l10n-attrs").split(",").map(i => i.trim()) : null;
+ for (const attr of Array.from(toElement.attributes)) {
+ if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed) && !hasAttribute(fromElement.attributes, attr.name)) {
+ toElement.removeAttribute(attr.name);
+ }
+ }
+ if (!fromElement.attributes) {
+ return;
+ }
+ for (const attr of Array.from(fromElement.attributes)) {
+ if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed) && toElement.getAttribute(attr.name) !== attr.value) {
+ toElement.setAttribute(attr.name, attr.value);
+ }
+ }
+}
+function getNodeForNamedElement(sourceElement, translatedChild) {
+ const childName = translatedChild.getAttribute("data-l10n-name");
+ const sourceChild = sourceElement.querySelector(`[data-l10n-name="${childName}"]`);
+ if (!sourceChild) {
+ console.warn(`An element named "${childName}" wasn't found in the source.`);
+ return createTextNodeFromTextContent(translatedChild);
+ }
+ if (sourceChild.localName !== translatedChild.localName) {
+ console.warn(`An element named "${childName}" was found in the translation ` + `but its type ${translatedChild.localName} didn't match the ` + `element found in the source (${sourceChild.localName}).`);
+ return createTextNodeFromTextContent(translatedChild);
+ }
+ sourceElement.removeChild(sourceChild);
+ const clone = sourceChild.cloneNode(false);
+ return shallowPopulateUsing(translatedChild, clone);
+}
+function createSanitizedElement(element) {
+ const clone = element.ownerDocument.createElement(element.localName);
+ return shallowPopulateUsing(element, clone);
+}
+function createTextNodeFromTextContent(element) {
+ return element.ownerDocument.createTextNode(element.textContent);
+}
+function isElementAllowed(element) {
+ const allowed = TEXT_LEVEL_ELEMENTS[element.namespaceURI];
+ return allowed && allowed.includes(element.localName);
+}
+function isAttrNameLocalizable(name, element, explicitlyAllowed = null) {
+ if (explicitlyAllowed && explicitlyAllowed.includes(name)) {
+ return true;
+ }
+ const allowed = LOCALIZABLE_ATTRIBUTES[element.namespaceURI];
+ if (!allowed) {
+ return false;
+ }
+ const attrName = name.toLowerCase();
+ const elemName = element.localName;
+ if (allowed.global.includes(attrName)) {
+ return true;
+ }
+ if (!allowed[elemName]) {
+ return false;
+ }
+ if (allowed[elemName].includes(attrName)) {
+ return true;
+ }
+ if (element.namespaceURI === "http://www.w3.org/1999/xhtml" && elemName === "input" && attrName === "value") {
+ const type = element.type.toLowerCase();
+ if (type === "submit" || type === "button" || type === "reset") {
+ return true;
+ }
+ }
+ return false;
+}
+function shallowPopulateUsing(fromElement, toElement) {
+ toElement.textContent = fromElement.textContent;
+ overlayAttributes(fromElement, toElement);
+ return toElement;
+}
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.filter.js
+var es_iterator_filter = __webpack_require__(2489);
+;// ./node_modules/cached-iterable/src/cached_iterable.mjs
+class CachedIterable extends Array {
+ static from(iterable) {
+ if (iterable instanceof this) {
+ return iterable;
+ }
+ return new this(iterable);
+ }
+}
+;// ./node_modules/cached-iterable/src/cached_sync_iterable.mjs
+
+
+class CachedSyncIterable extends CachedIterable {
+ constructor(iterable) {
+ super();
+ if (Symbol.iterator in Object(iterable)) {
+ this.iterator = iterable[Symbol.iterator]();
+ } else {
+ throw new TypeError("Argument must implement the iteration protocol.");
+ }
+ }
+ [Symbol.iterator]() {
+ const cached = this;
+ let cur = 0;
+ return {
+ next() {
+ if (cached.length <= cur) {
+ cached.push(cached.iterator.next());
+ }
+ return cached[cur++];
+ }
+ };
+ }
+ touchNext(count = 1) {
+ let idx = 0;
+ while (idx++ < count) {
+ const last = this[this.length - 1];
+ if (last && last.done) {
+ break;
+ }
+ this.push(this.iterator.next());
+ }
+ return this[this.length - 1];
+ }
+}
+;// ./node_modules/cached-iterable/src/cached_async_iterable.mjs
+
+
+class CachedAsyncIterable extends CachedIterable {
+ constructor(iterable) {
+ super();
+ if (Symbol.asyncIterator in Object(iterable)) {
+ this.iterator = iterable[Symbol.asyncIterator]();
+ } else if (Symbol.iterator in Object(iterable)) {
+ this.iterator = iterable[Symbol.iterator]();
+ } else {
+ throw new TypeError("Argument must implement the iteration protocol.");
+ }
+ }
+ [Symbol.asyncIterator]() {
+ const cached = this;
+ let cur = 0;
+ return {
+ async next() {
+ if (cached.length <= cur) {
+ cached.push(cached.iterator.next());
+ }
+ return cached[cur++];
+ }
+ };
+ }
+ async touchNext(count = 1) {
+ let idx = 0;
+ while (idx++ < count) {
+ const last = this[this.length - 1];
+ if (last && (await last).done) {
+ break;
+ }
+ this.push(this.iterator.next());
+ }
+ return this[this.length - 1];
+ }
+}
+;// ./node_modules/cached-iterable/src/index.mjs
+
+
+;// ./node_modules/@fluent/dom/esm/localization.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class Localization {
+ constructor(resourceIds = [], generateBundles) {
+ this.resourceIds = resourceIds;
+ this.generateBundles = generateBundles;
+ this.onChange(true);
+ }
+ addResourceIds(resourceIds, eager = false) {
+ this.resourceIds.push(...resourceIds);
+ this.onChange(eager);
+ return this.resourceIds.length;
+ }
+ removeResourceIds(resourceIds) {
+ this.resourceIds = this.resourceIds.filter(r => !resourceIds.includes(r));
+ this.onChange();
+ return this.resourceIds.length;
+ }
+ async formatWithFallback(keys, method) {
+ const translations = [];
+ let hasAtLeastOneBundle = false;
+ for await (const bundle of this.bundles) {
+ hasAtLeastOneBundle = true;
+ const missingIds = keysFromBundle(method, bundle, keys, translations);
+ if (missingIds.size === 0) {
+ break;
+ }
+ if (typeof console !== "undefined") {
+ const locale = bundle.locales[0];
+ const ids = Array.from(missingIds).join(", ");
+ console.warn(`[fluent] Missing translations in ${locale}: ${ids}`);
+ }
+ }
+ if (!hasAtLeastOneBundle && typeof console !== "undefined") {
+ console.warn(`[fluent] Request for keys failed because no resource bundles got generated.
+ keys: ${JSON.stringify(keys)}.
+ resourceIds: ${JSON.stringify(this.resourceIds)}.`);
+ }
+ return translations;
+ }
+ formatMessages(keys) {
+ return this.formatWithFallback(keys, messageFromBundle);
+ }
+ formatValues(keys) {
+ return this.formatWithFallback(keys, valueFromBundle);
+ }
+ async formatValue(id, args) {
+ const [val] = await this.formatValues([{
+ id,
+ args
+ }]);
+ return val;
+ }
+ handleEvent() {
+ this.onChange();
+ }
+ onChange(eager = false) {
+ this.bundles = CachedAsyncIterable.from(this.generateBundles(this.resourceIds));
+ if (eager) {
+ this.bundles.touchNext(2);
+ }
+ }
+}
+function valueFromBundle(bundle, errors, message, args) {
+ if (message.value) {
+ return bundle.formatPattern(message.value, args, errors);
+ }
+ return null;
+}
+function messageFromBundle(bundle, errors, message, args) {
+ const formatted = {
+ value: null,
+ attributes: null
+ };
+ if (message.value) {
+ formatted.value = bundle.formatPattern(message.value, args, errors);
+ }
+ let attrNames = Object.keys(message.attributes);
+ if (attrNames.length > 0) {
+ formatted.attributes = new Array(attrNames.length);
+ for (let [i, name] of attrNames.entries()) {
+ let value = bundle.formatPattern(message.attributes[name], args, errors);
+ formatted.attributes[i] = {
+ name,
+ value
+ };
+ }
+ }
+ return formatted;
+}
+function keysFromBundle(method, bundle, keys, translations) {
+ const messageErrors = [];
+ const missingIds = new Set();
+ keys.forEach(({
+ id,
+ args
+ }, i) => {
+ if (translations[i] !== undefined) {
+ return;
+ }
+ let message = bundle.getMessage(id);
+ if (message) {
+ messageErrors.length = 0;
+ translations[i] = method(bundle, messageErrors, message, args);
+ if (messageErrors.length > 0 && typeof console !== "undefined") {
+ const locale = bundle.locales[0];
+ const errors = messageErrors.join(", ");
+ console.warn(`[fluent][resolver] errors in ${locale}/${id}: ${errors}.`);
+ }
+ } else {
+ missingIds.add(id);
+ }
+ });
+ return missingIds;
+}
+;// ./node_modules/@fluent/dom/esm/dom_localization.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const L10NID_ATTR_NAME = "data-l10n-id";
+const L10NARGS_ATTR_NAME = "data-l10n-args";
+const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
+class DOMLocalization extends Localization {
+ constructor(resourceIds, generateBundles) {
+ super(resourceIds, generateBundles);
+ this.roots = new Set();
+ this.pendingrAF = null;
+ this.pendingElements = new Set();
+ this.windowElement = null;
+ this.mutationObserver = null;
+ this.observerConfig = {
+ attributes: true,
+ characterData: false,
+ childList: true,
+ subtree: true,
+ attributeFilter: [L10NID_ATTR_NAME, L10NARGS_ATTR_NAME]
+ };
+ }
+ onChange(eager = false) {
+ super.onChange(eager);
+ if (this.roots) {
+ this.translateRoots();
+ }
+ }
+ setAttributes(element, id, args) {
+ element.setAttribute(L10NID_ATTR_NAME, id);
+ if (args) {
+ element.setAttribute(L10NARGS_ATTR_NAME, JSON.stringify(args));
+ } else {
+ element.removeAttribute(L10NARGS_ATTR_NAME);
+ }
+ return element;
+ }
+ getAttributes(element) {
+ return {
+ id: element.getAttribute(L10NID_ATTR_NAME),
+ args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null)
+ };
+ }
+ connectRoot(newRoot) {
+ for (const root of this.roots) {
+ if (root === newRoot || root.contains(newRoot) || newRoot.contains(root)) {
+ throw new Error("Cannot add a root that overlaps with existing root.");
+ }
+ }
+ if (this.windowElement) {
+ if (this.windowElement !== newRoot.ownerDocument.defaultView) {
+ throw new Error(`Cannot connect a root:
+ DOMLocalization already has a root from a different window.`);
+ }
+ } else {
+ this.windowElement = newRoot.ownerDocument.defaultView;
+ this.mutationObserver = new this.windowElement.MutationObserver(mutations => this.translateMutations(mutations));
+ }
+ this.roots.add(newRoot);
+ this.mutationObserver.observe(newRoot, this.observerConfig);
+ }
+ disconnectRoot(root) {
+ this.roots.delete(root);
+ this.pauseObserving();
+ if (this.roots.size === 0) {
+ this.mutationObserver = null;
+ if (this.windowElement && this.pendingrAF) {
+ this.windowElement.cancelAnimationFrame(this.pendingrAF);
+ }
+ this.windowElement = null;
+ this.pendingrAF = null;
+ this.pendingElements.clear();
+ return true;
+ }
+ this.resumeObserving();
+ return false;
+ }
+ translateRoots() {
+ const roots = Array.from(this.roots);
+ return Promise.all(roots.map(root => this.translateFragment(root)));
+ }
+ pauseObserving() {
+ if (!this.mutationObserver) {
+ return;
+ }
+ this.translateMutations(this.mutationObserver.takeRecords());
+ this.mutationObserver.disconnect();
+ }
+ resumeObserving() {
+ if (!this.mutationObserver) {
+ return;
+ }
+ for (const root of this.roots) {
+ this.mutationObserver.observe(root, this.observerConfig);
+ }
+ }
+ translateMutations(mutations) {
+ for (const mutation of mutations) {
+ switch (mutation.type) {
+ case "attributes":
+ if (mutation.target.hasAttribute("data-l10n-id")) {
+ this.pendingElements.add(mutation.target);
+ }
+ break;
+ case "childList":
+ for (const addedNode of mutation.addedNodes) {
+ if (addedNode.nodeType === addedNode.ELEMENT_NODE) {
+ if (addedNode.childElementCount) {
+ for (const element of this.getTranslatables(addedNode)) {
+ this.pendingElements.add(element);
+ }
+ } else if (addedNode.hasAttribute(L10NID_ATTR_NAME)) {
+ this.pendingElements.add(addedNode);
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (this.pendingElements.size > 0) {
+ if (this.pendingrAF === null) {
+ this.pendingrAF = this.windowElement.requestAnimationFrame(() => {
+ this.translateElements(Array.from(this.pendingElements));
+ this.pendingElements.clear();
+ this.pendingrAF = null;
+ });
+ }
+ }
+ }
+ translateFragment(frag) {
+ return this.translateElements(this.getTranslatables(frag));
+ }
+ async translateElements(elements) {
+ if (!elements.length) {
+ return undefined;
+ }
+ const keys = elements.map(this.getKeysForElement);
+ const translations = await this.formatMessages(keys);
+ return this.applyTranslations(elements, translations);
+ }
+ applyTranslations(elements, translations) {
+ this.pauseObserving();
+ for (let i = 0; i < elements.length; i++) {
+ if (translations[i] !== undefined) {
+ translateElement(elements[i], translations[i]);
+ }
+ }
+ this.resumeObserving();
+ }
+ getTranslatables(element) {
+ const nodes = Array.from(element.querySelectorAll(L10N_ELEMENT_QUERY));
+ if (typeof element.hasAttribute === "function" && element.hasAttribute(L10NID_ATTR_NAME)) {
+ nodes.push(element);
+ }
+ return nodes;
+ }
+ getKeysForElement(element) {
+ return {
+ id: element.getAttribute(L10NID_ATTR_NAME),
+ args: JSON.parse(element.getAttribute(L10NARGS_ATTR_NAME) || null)
+ };
+ }
+}
+;// ./node_modules/@fluent/dom/esm/index.js
+
+
+;// ./web/l10n.js
+
+
+
+
+
+
+
+
+
+
+class L10n {
+ #dir;
+ #elements;
+ #lang;
+ #l10n;
+ constructor({
+ lang,
+ isRTL
+ }, l10n = null) {
+ this.#lang = L10n.#fixupLangCode(lang);
+ this.#l10n = l10n;
+ this.#dir = isRTL ?? L10n.#isRTL(this.#lang) ? "rtl" : "ltr";
+ }
+ _setL10n(l10n) {
+ this.#l10n = l10n;
+ }
+ getLanguage() {
+ return this.#lang;
+ }
+ getDirection() {
+ return this.#dir;
+ }
+ async get(ids, args = null, fallback) {
+ if (Array.isArray(ids)) {
+ ids = ids.map(id => ({
+ id
+ }));
+ const messages = await this.#l10n.formatMessages(ids);
+ return messages.map(message => message.value);
+ }
+ const messages = await this.#l10n.formatMessages([{
+ id: ids,
+ args
+ }]);
+ return messages[0]?.value || fallback;
+ }
+ async translate(element) {
+ (this.#elements ||= new Set()).add(element);
+ try {
+ this.#l10n.connectRoot(element);
+ await this.#l10n.translateRoots();
+ } catch {}
+ }
+ async translateOnce(element) {
+ try {
+ await this.#l10n.translateElements([element]);
+ } catch (ex) {
+ console.error("translateOnce:", ex);
+ }
+ }
+ async destroy() {
+ if (this.#elements) {
+ for (const element of this.#elements) {
+ this.#l10n.disconnectRoot(element);
+ }
+ this.#elements.clear();
+ this.#elements = null;
+ }
+ this.#l10n.pauseObserving();
+ }
+ pause() {
+ this.#l10n.pauseObserving();
+ }
+ resume() {
+ this.#l10n.resumeObserving();
+ }
+ static #fixupLangCode(langCode) {
+ langCode = langCode?.toLowerCase() || "en-us";
+ const PARTIAL_LANG_CODES = {
+ en: "en-us",
+ es: "es-es",
+ fy: "fy-nl",
+ ga: "ga-ie",
+ gu: "gu-in",
+ hi: "hi-in",
+ hy: "hy-am",
+ nb: "nb-no",
+ ne: "ne-np",
+ nn: "nn-no",
+ pa: "pa-in",
+ pt: "pt-pt",
+ sv: "sv-se",
+ zh: "zh-cn"
+ };
+ return PARTIAL_LANG_CODES[langCode] || langCode;
+ }
+ static #isRTL(lang) {
+ const shortCode = lang.split("-", 1)[0];
+ return ["ar", "he", "fa", "ps", "ur"].includes(shortCode);
+ }
+}
+const GenericL10n = null;
+
+;// ./web/genericl10n.js
+
+
+
+
+
+function PLATFORM() {
+ const {
+ isAndroid,
+ isLinux,
+ isMac,
+ isWindows
+ } = FeatureTest.platform;
+ if (isLinux) {
+ return "linux";
+ }
+ if (isWindows) {
+ return "windows";
+ }
+ if (isMac) {
+ return "macos";
+ }
+ if (isAndroid) {
+ return "android";
+ }
+ return "other";
+}
+function createBundle(lang, text) {
+ const resource = new FluentResource(text);
+ const bundle = new FluentBundle(lang, {
+ functions: {
+ PLATFORM
+ }
+ });
+ const errors = bundle.addResource(resource);
+ if (errors.length) {
+ console.error("L10n errors", errors);
+ }
+ return bundle;
+}
+class genericl10n_GenericL10n extends L10n {
+ constructor(lang) {
+ super({
+ lang
+ });
+ const generateBundles = !lang ? genericl10n_GenericL10n.#generateBundlesFallback.bind(genericl10n_GenericL10n, this.getLanguage()) : genericl10n_GenericL10n.#generateBundles.bind(genericl10n_GenericL10n, "en-us", this.getLanguage());
+ this._setL10n(new DOMLocalization([], generateBundles));
+ }
+ static async *#generateBundles(defaultLang, baseLang) {
+ const {
+ baseURL,
+ paths
+ } = await this.#getPaths();
+ const langs = [baseLang];
+ if (defaultLang !== baseLang) {
+ const shortLang = baseLang.split("-", 1)[0];
+ if (shortLang !== baseLang) {
+ langs.push(shortLang);
+ }
+ langs.push(defaultLang);
+ }
+ const bundles = langs.map(lang => [lang, this.#createBundle(lang, baseURL, paths)]);
+ for (const [lang, bundlePromise] of bundles) {
+ const bundle = await bundlePromise;
+ if (bundle) {
+ yield bundle;
+ } else if (lang === "en-us") {
+ yield this.#createBundleFallback(lang);
+ }
+ }
+ }
+ static async #createBundle(lang, baseURL, paths) {
+ const path = paths[lang];
+ if (!path) {
+ return null;
+ }
+ const url = new URL(path, baseURL);
+ const text = await fetchData(url, "text");
+ return createBundle(lang, text);
+ }
+ static async #getPaths() {
+ try {
+ const {
+ href
+ } = document.querySelector(`link[type="application/l10n"]`);
+ const paths = await fetchData(href, "json");
+ return {
+ baseURL: href.substring(0, href.lastIndexOf("/") + 1) || "./",
+ paths
+ };
+ } catch {}
+ return {
+ baseURL: "./",
+ paths: Object.create(null)
+ };
+ }
+ static async *#generateBundlesFallback(lang) {
+ yield this.#createBundleFallback(lang);
+ }
+ static async #createBundleFallback(lang) {
+ const text = "pdfjs-previous-button =\n .title = Previous Page\npdfjs-previous-button-label = Previous\npdfjs-next-button =\n .title = Next Page\npdfjs-next-button-label = Next\npdfjs-page-input =\n .title = Page\npdfjs-of-pages = of { $pagesCount }\npdfjs-page-of-pages = ({ $pageNumber } of { $pagesCount })\npdfjs-zoom-out-button =\n .title = Zoom Out\npdfjs-zoom-out-button-label = Zoom Out\npdfjs-zoom-in-button =\n .title = Zoom In\npdfjs-zoom-in-button-label = Zoom In\npdfjs-zoom-select =\n .title = Zoom\npdfjs-presentation-mode-button =\n .title = Switch to Presentation Mode\npdfjs-presentation-mode-button-label = Presentation Mode\npdfjs-open-file-button =\n .title = Open File\npdfjs-open-file-button-label = Open\npdfjs-print-button =\n .title = Print\npdfjs-print-button-label = Print\npdfjs-save-button =\n .title = Save\npdfjs-save-button-label = Save\npdfjs-download-button =\n .title = Download\npdfjs-download-button-label = Download\npdfjs-bookmark-button =\n .title = Current Page (View URL from Current Page)\npdfjs-bookmark-button-label = Current Page\npdfjs-tools-button =\n .title = Tools\npdfjs-tools-button-label = Tools\npdfjs-first-page-button =\n .title = Go to First Page\npdfjs-first-page-button-label = Go to First Page\npdfjs-last-page-button =\n .title = Go to Last Page\npdfjs-last-page-button-label = Go to Last Page\npdfjs-page-rotate-cw-button =\n .title = Rotate Clockwise\npdfjs-page-rotate-cw-button-label = Rotate Clockwise\npdfjs-page-rotate-ccw-button =\n .title = Rotate Counterclockwise\npdfjs-page-rotate-ccw-button-label = Rotate Counterclockwise\npdfjs-cursor-text-select-tool-button =\n .title = Enable Text Selection Tool\npdfjs-cursor-text-select-tool-button-label = Text Selection Tool\npdfjs-cursor-hand-tool-button =\n .title = Enable Hand Tool\npdfjs-cursor-hand-tool-button-label = Hand Tool\npdfjs-scroll-page-button =\n .title = Use Page Scrolling\npdfjs-scroll-page-button-label = Page Scrolling\npdfjs-scroll-vertical-button =\n .title = Use Vertical Scrolling\npdfjs-scroll-vertical-button-label = Vertical Scrolling\npdfjs-scroll-horizontal-button =\n .title = Use Horizontal Scrolling\npdfjs-scroll-horizontal-button-label = Horizontal Scrolling\npdfjs-scroll-wrapped-button =\n .title = Use Wrapped Scrolling\npdfjs-scroll-wrapped-button-label = Wrapped Scrolling\npdfjs-spread-none-button =\n .title = Do not join page spreads\npdfjs-spread-none-button-label = No Spreads\npdfjs-spread-odd-button =\n .title = Join page spreads starting with odd-numbered pages\npdfjs-spread-odd-button-label = Odd Spreads\npdfjs-spread-even-button =\n .title = Join page spreads starting with even-numbered pages\npdfjs-spread-even-button-label = Even Spreads\npdfjs-document-properties-button =\n .title = Document Properties…\npdfjs-document-properties-button-label = Document Properties…\npdfjs-document-properties-file-name = File name:\npdfjs-document-properties-file-size = File size:\npdfjs-document-properties-size-kb = { NUMBER($kb, maximumSignificantDigits: 3) } KB ({ $b } bytes)\npdfjs-document-properties-size-mb = { NUMBER($mb, maximumSignificantDigits: 3) } MB ({ $b } bytes)\npdfjs-document-properties-title = Title:\npdfjs-document-properties-author = Author:\npdfjs-document-properties-subject = Subject:\npdfjs-document-properties-keywords = Keywords:\npdfjs-document-properties-creation-date = Creation Date:\npdfjs-document-properties-modification-date = Modification Date:\npdfjs-document-properties-date-time-string = { DATETIME($dateObj, dateStyle: \"short\", timeStyle: \"medium\") }\npdfjs-document-properties-creator = Creator:\npdfjs-document-properties-producer = PDF Producer:\npdfjs-document-properties-version = PDF Version:\npdfjs-document-properties-page-count = Page Count:\npdfjs-document-properties-page-size = Page Size:\npdfjs-document-properties-page-size-unit-inches = in\npdfjs-document-properties-page-size-unit-millimeters = mm\npdfjs-document-properties-page-size-orientation-portrait = portrait\npdfjs-document-properties-page-size-orientation-landscape = landscape\npdfjs-document-properties-page-size-name-a-three = A3\npdfjs-document-properties-page-size-name-a-four = A4\npdfjs-document-properties-page-size-name-letter = Letter\npdfjs-document-properties-page-size-name-legal = Legal\npdfjs-document-properties-page-size-dimension-string = { $width } × { $height } { $unit } ({ $orientation })\npdfjs-document-properties-page-size-dimension-name-string = { $width } × { $height } { $unit } ({ $name }, { $orientation })\npdfjs-document-properties-linearized = Fast Web View:\npdfjs-document-properties-linearized-yes = Yes\npdfjs-document-properties-linearized-no = No\npdfjs-document-properties-close-button = Close\npdfjs-print-progress-message = Preparing document for printing…\npdfjs-print-progress-percent = { $progress }%\npdfjs-print-progress-close-button = Cancel\npdfjs-printing-not-supported = Warning: Printing is not fully supported by this browser.\npdfjs-printing-not-ready = Warning: The PDF is not fully loaded for printing.\npdfjs-current-outline-item-button =\n .title = Find Current Outline Item\npdfjs-current-outline-item-button-label = Current Outline Item\npdfjs-findbar-button =\n .title = Find in Document\npdfjs-findbar-button-label = Find\npdfjs-additional-layers = Additional Layers\npdfjs-thumb-page-title1 =\n .title = Page { $page } of { $total }\npdfjs-thumb-page-canvas =\n .aria-label = Thumbnail of Page { $page }\npdfjs-thumb-page-checkbox1 =\n .title = Select page { $page }\npdfjs-find-input =\n .title = Find\n .placeholder = Find in document…\npdfjs-find-previous-button =\n .title = Find the previous occurrence of the phrase\npdfjs-find-previous-button-label = Previous\npdfjs-find-next-button =\n .title = Find the next occurrence of the phrase\npdfjs-find-next-button-label = Next\npdfjs-find-highlight-checkbox = Highlight All\npdfjs-find-match-case-checkbox-label = Match Case\npdfjs-find-match-diacritics-checkbox-label = Match Diacritics\npdfjs-find-entire-word-checkbox-label = Whole Words\npdfjs-find-reached-top = Reached top of document, continued from bottom\npdfjs-find-reached-bottom = Reached end of document, continued from top\npdfjs-find-match-count =\n { $total ->\n [one] { $current } of { $total } match\n *[other] { $current } of { $total } matches\n }\npdfjs-find-match-count-limit =\n { $limit ->\n [one] More than { $limit } match\n *[other] More than { $limit } matches\n }\npdfjs-find-not-found = Phrase not found\npdfjs-page-scale-width = Page Width\npdfjs-page-scale-fit = Page Fit\npdfjs-page-scale-auto = Automatic Zoom\npdfjs-page-scale-actual = Actual Size\npdfjs-page-scale-percent = { $scale }%\npdfjs-page-landmark =\n .aria-label = Page { $page }\npdfjs-loading-error = An error occurred while loading the PDF.\npdfjs-invalid-file-error = Invalid or corrupted PDF file.\npdfjs-missing-file-error = Missing PDF file.\npdfjs-unexpected-response-error = Unexpected server response.\npdfjs-rendering-error = An error occurred while rendering the page.\npdfjs-annotation-date-time-string = { DATETIME($dateObj, dateStyle: \"short\", timeStyle: \"medium\") }\npdfjs-text-annotation-type =\n .alt = [{ $type } Annotation]\npdfjs-password-label = Enter the password to open this PDF file.\npdfjs-password-invalid = Invalid password. Please try again.\npdfjs-password-ok-button = OK\npdfjs-password-cancel-button = Cancel\npdfjs-web-fonts-disabled = Web fonts are disabled: unable to use embedded PDF fonts.\npdfjs-editor-free-text-button =\n .title = Text\npdfjs-editor-color-picker-free-text-input =\n .title = Change text color\npdfjs-editor-free-text-button-label = Text\npdfjs-editor-ink-button =\n .title = Draw\npdfjs-editor-color-picker-ink-input =\n .title = Change drawing color\npdfjs-editor-ink-button-label = Draw\npdfjs-editor-stamp-button =\n .title = Add or edit images\npdfjs-editor-stamp-button-label = Add or edit images\npdfjs-editor-highlight-button =\n .title = Highlight\npdfjs-editor-highlight-button-label = Highlight\npdfjs-highlight-floating-button1 =\n .title = Highlight\n .aria-label = Highlight\npdfjs-highlight-floating-button-label = Highlight\npdfjs-comment-floating-button =\n .title = Comment\n .aria-label = Comment\npdfjs-comment-floating-button-label = Comment\npdfjs-editor-comment-button =\n .title = Comment\n .aria-label = Comment\npdfjs-editor-comment-button-label = Comment\npdfjs-editor-signature-button =\n .title = Add signature\npdfjs-editor-signature-button-label = Add signature\npdfjs-editor-highlight-editor =\n .aria-label = Highlight editor\npdfjs-editor-ink-editor =\n .aria-label = Drawing editor\npdfjs-editor-signature-editor1 =\n .aria-description = Signature editor: { $description }\npdfjs-editor-stamp-editor =\n .aria-label = Image editor\npdfjs-editor-remove-ink-button =\n .title = Remove drawing\npdfjs-editor-remove-freetext-button =\n .title = Remove text\npdfjs-editor-remove-stamp-button =\n .title = Remove image\npdfjs-editor-remove-highlight-button =\n .title = Remove highlight\npdfjs-editor-remove-signature-button =\n .title = Remove signature\npdfjs-editor-free-text-color-input = Color\npdfjs-editor-free-text-size-input = Size\npdfjs-editor-ink-color-input = Color\npdfjs-editor-ink-thickness-input = Thickness\npdfjs-editor-ink-opacity-input = Opacity\npdfjs-editor-stamp-add-image-button =\n .title = Add image\npdfjs-editor-stamp-add-image-button-label = Add image\npdfjs-editor-free-highlight-thickness-input = Thickness\npdfjs-editor-free-highlight-thickness-title =\n .title = Change thickness when highlighting items other than text\npdfjs-editor-add-signature-container =\n .aria-label = Signature controls and saved signatures\npdfjs-editor-signature-add-signature-button =\n .title = Add new signature\npdfjs-editor-signature-add-signature-button-label = Add new signature\npdfjs-editor-add-saved-signature-button =\n .title = Saved signature: { $description }\npdfjs-free-text2 =\n .aria-label = Text Editor\n .default-content = Start typing…\npdfjs-editor-comments-sidebar-title =\n { $count ->\n [one] Comment\n *[other] Comments\n }\npdfjs-editor-comments-sidebar-close-button =\n .title = Close the sidebar\n .aria-label = Close the sidebar\npdfjs-editor-comments-sidebar-close-button-label = Close the sidebar\npdfjs-editor-comments-sidebar-no-comments1 = See something noteworthy? Highlight it and leave a comment.\npdfjs-editor-comments-sidebar-no-comments-link = Learn more\npdfjs-editor-alt-text-button =\n .aria-label = Alt text\npdfjs-editor-alt-text-button-label = Alt text\npdfjs-editor-alt-text-edit-button =\n .aria-label = Edit alt text\npdfjs-editor-alt-text-dialog-label = Choose an option\npdfjs-editor-alt-text-dialog-description = Alt text (alternative text) helps when people can’t see the image or when it doesn’t load.\npdfjs-editor-alt-text-add-description-label = Add a description\npdfjs-editor-alt-text-add-description-description = Aim for 1-2 sentences that describe the subject, setting, or actions.\npdfjs-editor-alt-text-mark-decorative-label = Mark as decorative\npdfjs-editor-alt-text-mark-decorative-description = This is used for ornamental images, like borders or watermarks.\npdfjs-editor-alt-text-cancel-button = Cancel\npdfjs-editor-alt-text-save-button = Save\npdfjs-editor-alt-text-decorative-tooltip = Marked as decorative\npdfjs-editor-alt-text-textarea =\n .placeholder = For example, “A young man sits down at a table to eat a meal”\npdfjs-editor-resizer-top-left =\n .aria-label = Top left corner — resize\npdfjs-editor-resizer-top-middle =\n .aria-label = Top middle — resize\npdfjs-editor-resizer-top-right =\n .aria-label = Top right corner — resize\npdfjs-editor-resizer-middle-right =\n .aria-label = Middle right — resize\npdfjs-editor-resizer-bottom-right =\n .aria-label = Bottom right corner — resize\npdfjs-editor-resizer-bottom-middle =\n .aria-label = Bottom middle — resize\npdfjs-editor-resizer-bottom-left =\n .aria-label = Bottom left corner — resize\npdfjs-editor-resizer-middle-left =\n .aria-label = Middle left — resize\npdfjs-editor-highlight-colorpicker-label = Highlight color\npdfjs-editor-colorpicker-button =\n .title = Change color\npdfjs-editor-colorpicker-dropdown =\n .aria-label = Color choices\npdfjs-editor-colorpicker-yellow =\n .title = Yellow\npdfjs-editor-colorpicker-green =\n .title = Green\npdfjs-editor-colorpicker-blue =\n .title = Blue\npdfjs-editor-colorpicker-pink =\n .title = Pink\npdfjs-editor-colorpicker-red =\n .title = Red\npdfjs-editor-highlight-show-all-button-label = Show all\npdfjs-editor-highlight-show-all-button =\n .title = Show all\npdfjs-editor-new-alt-text-dialog-edit-label = Edit alt text (image description)\npdfjs-editor-new-alt-text-dialog-add-label = Add alt text (image description)\npdfjs-editor-new-alt-text-textarea =\n .placeholder = Write your description here…\npdfjs-editor-new-alt-text-description = Short description for people who can’t see the image or when the image doesn’t load.\npdfjs-editor-new-alt-text-disclaimer1 = This alt text was created automatically and may be inaccurate.\npdfjs-editor-new-alt-text-disclaimer-learn-more-url = Learn more\npdfjs-editor-new-alt-text-create-automatically-button-label = Create alt text automatically\npdfjs-editor-new-alt-text-not-now-button = Not now\npdfjs-editor-new-alt-text-error-title = Couldn’t create alt text automatically\npdfjs-editor-new-alt-text-error-description = Please write your own alt text or try again later.\npdfjs-editor-new-alt-text-error-close-button = Close\npdfjs-editor-new-alt-text-ai-model-downloading-progress = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)\n .aria-valuetext = Downloading alt text AI model ({ $downloadedSize } of { $totalSize } MB)\npdfjs-editor-new-alt-text-added-button =\n .aria-label = Alt text added\npdfjs-editor-new-alt-text-added-button-label = Alt text added\npdfjs-editor-new-alt-text-missing-button =\n .aria-label = Missing alt text\npdfjs-editor-new-alt-text-missing-button-label = Missing alt text\npdfjs-editor-new-alt-text-to-review-button =\n .aria-label = Review alt text\npdfjs-editor-new-alt-text-to-review-button-label = Review alt text\npdfjs-editor-new-alt-text-generated-alt-text-with-disclaimer = Created automatically: { $generatedAltText }\npdfjs-image-alt-text-settings-button =\n .title = Image alt text settings\npdfjs-image-alt-text-settings-button-label = Image alt text settings\npdfjs-editor-alt-text-settings-dialog-label = Image alt text settings\npdfjs-editor-alt-text-settings-automatic-title = Automatic alt text\npdfjs-editor-alt-text-settings-create-model-button-label = Create alt text automatically\npdfjs-editor-alt-text-settings-create-model-description = Suggests descriptions to help people who can’t see the image or when the image doesn’t load.\npdfjs-editor-alt-text-settings-editor-title = Alt text editor\npdfjs-editor-alt-text-settings-show-dialog-button-label = Show alt text editor right away when adding an image\npdfjs-editor-alt-text-settings-show-dialog-description = Helps you make sure all your images have alt text.\npdfjs-editor-alt-text-settings-close-button = Close\npdfjs-editor-highlight-added-alert = Highlight added\npdfjs-editor-freetext-added-alert = Text added\npdfjs-editor-ink-added-alert = Drawing added\npdfjs-editor-stamp-added-alert = Image added\npdfjs-editor-signature-added-alert = Signature added\npdfjs-editor-undo-bar-message-highlight = Highlight removed\npdfjs-editor-undo-bar-message-freetext = Text removed\npdfjs-editor-undo-bar-message-ink = Drawing removed\npdfjs-editor-undo-bar-message-stamp = Image removed\npdfjs-editor-undo-bar-message-signature = Signature removed\npdfjs-editor-undo-bar-message-comment = Comment removed\npdfjs-editor-undo-bar-message-multiple =\n { $count ->\n [one] { $count } annotation removed\n *[other] { $count } annotations removed\n }\npdfjs-editor-undo-bar-undo-button =\n .title = Undo\npdfjs-editor-undo-bar-undo-button-label = Undo\npdfjs-editor-undo-bar-close-button =\n .title = Close\npdfjs-editor-undo-bar-close-button-label = Close\npdfjs-editor-add-signature-dialog-label = This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use.\npdfjs-editor-add-signature-dialog-title = Add a signature\npdfjs-editor-add-signature-type-button = Type\n .title = Type\npdfjs-editor-add-signature-draw-button = Draw\n .title = Draw\npdfjs-editor-add-signature-image-button = Image\n .title = Image\npdfjs-editor-add-signature-type-input =\n .aria-label = Type your signature\n .placeholder = Type your signature\npdfjs-editor-add-signature-draw-placeholder = Draw your signature\npdfjs-editor-add-signature-draw-thickness-range-label = Thickness\npdfjs-editor-add-signature-draw-thickness-range =\n .title = Drawing thickness: { $thickness }\npdfjs-editor-add-signature-image-placeholder = Drag a file here to upload\npdfjs-editor-add-signature-image-browse-link =\n { PLATFORM() ->\n [macos] Or choose image files\n *[other] Or browse image files\n }\npdfjs-editor-add-signature-description-label = Description (alt text)\npdfjs-editor-add-signature-description-input =\n .title = Description (alt text)\npdfjs-editor-add-signature-description-default-when-drawing = Signature\npdfjs-editor-add-signature-clear-button-label = Clear signature\npdfjs-editor-add-signature-clear-button =\n .title = Clear signature\npdfjs-editor-add-signature-save-checkbox = Save signature\npdfjs-editor-add-signature-save-warning-message = You’ve reached the limit of 5 saved signatures. Remove one to save more.\npdfjs-editor-add-signature-image-upload-error-title = Couldn’t upload image\npdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.\npdfjs-editor-add-signature-image-no-data-error-title = Can’t convert this image into a signature\npdfjs-editor-add-signature-image-no-data-error-description = Please try uploading a different image.\npdfjs-editor-add-signature-error-close-button = Close\npdfjs-editor-add-signature-cancel-button = Cancel\npdfjs-editor-add-signature-add-button = Add\npdfjs-editor-delete-signature-button1 =\n .title = Remove saved signature\npdfjs-editor-delete-signature-button-label1 = Remove saved signature\npdfjs-editor-add-signature-edit-button-label = Edit description\npdfjs-editor-edit-signature-dialog-title = Edit description\npdfjs-editor-edit-signature-update-button = Update\npdfjs-show-comment-button =\n .title = Show comment\npdfjs-editor-edit-comment-popup-button-label = Edit comment\npdfjs-editor-edit-comment-popup-button =\n .title = Edit comment\npdfjs-editor-delete-comment-popup-button-label = Remove comment\npdfjs-editor-delete-comment-popup-button =\n .title = Remove comment\npdfjs-editor-edit-comment-dialog-title-when-editing = Edit comment\npdfjs-editor-edit-comment-dialog-save-button-when-editing = Update\npdfjs-editor-edit-comment-dialog-title-when-adding = Add comment\npdfjs-editor-edit-comment-dialog-save-button-when-adding = Add\npdfjs-editor-edit-comment-dialog-text-input =\n .placeholder = Start typing…\npdfjs-editor-edit-comment-dialog-cancel-button = Cancel\npdfjs-editor-add-comment-button =\n .title = Add comment\npdfjs-toggle-views-manager-button1 =\n .title = Manage pages\npdfjs-toggle-views-manager-notification-button =\n .title = Toggle Sidebar (document contains thumbnails/outline/attachments/layers)\npdfjs-toggle-views-manager-button1-label = Manage pages\npdfjs-views-manager-sidebar =\n .aria-label = Sidebar\npdfjs-views-manager-sidebar-resizer =\n .aria-label = Sidebar resizer\npdfjs-views-manager-view-selector-button =\n .title = Views\npdfjs-views-manager-view-selector-button-label = Views\npdfjs-views-manager-pages-title = Pages\npdfjs-views-manager-outlines-title1 = Document outline\n .title = Document outline (double-click to expand/collapse all items)\npdfjs-views-manager-attachments-title = Attachments\npdfjs-views-manager-layers-title1 = Layers\n .title = Layers (double-click to reset all layers to the default state)\npdfjs-views-manager-pages-option-label = Pages\npdfjs-views-manager-outlines-option-label = Document outline\npdfjs-views-manager-attachments-option-label = Attachments\npdfjs-views-manager-layers-option-label = Layers\npdfjs-views-manager-add-file-button =\n .title = Add file\npdfjs-views-manager-add-file-button-label = Add file\npdfjs-views-manager-pages-status-action-label =\n { $count ->\n [one] { $count } selected\n *[other] { $count } selected\n }\npdfjs-views-manager-pages-status-none-action-label = Select pages\npdfjs-views-manager-pages-status-action-button-label = Manage\npdfjs-views-manager-pages-status-copy-button-label = Copy\npdfjs-views-manager-pages-status-cut-button-label = Cut\npdfjs-views-manager-pages-status-delete-button-label = Delete\npdfjs-views-manager-pages-status-export-selected-button-label = Export selected…\npdfjs-views-manager-status-undo-cut-label =\n { $count ->\n [one] 1 page cut\n *[other] { $count } pages cut\n }\npdfjs-views-manager-pages-status-undo-copy-label =\n { $count ->\n [one] 1 page copied\n *[other] { $count } pages copied\n }\npdfjs-views-manager-pages-status-undo-delete-label =\n { $count ->\n [one] 1 page deleted\n *[other] { $count } pages deleted\n }\npdfjs-views-manager-status-undo-button-label = Undo\npdfjs-views-manager-status-done-button-label = Done\npdfjs-views-manager-status-close-button =\n .title = Close\npdfjs-views-manager-status-close-button-label = Close\npdfjs-views-manager-paste-button-label = Paste\npdfjs-views-manager-paste-button-before =\n .title = Paste before the first page\npdfjs-views-manager-paste-button-after =\n .title = Paste after page { $page }\npdfjs-new-badge-content = NEW\npdfjs-views-manager-waiting-for-file = Uploading file…\npdfjs-digital-signature-properties-button =\n .title = Digital signature properties\n .aria-label = Digital signature properties\npdfjs-digital-signature-properties-button-label = Digital signature properties\npdfjs-digital-signature-properties-banner-verified = Document was signed with a valid digital signature\npdfjs-digital-signature-properties-banner-unknown =\n { $count ->\n [one] Document signed but { $count } digital signature could not be verified\n *[other] Document signed but { $count } digital signatures could not be verified\n }\npdfjs-digital-signature-properties-banner-untrusted =\n { $count ->\n [one] Document signed with { $count } certificate that is not trusted\n *[other] Document signed with { $count } certificates that are not trusted\n }\npdfjs-digital-signature-properties-banner-expired =\n { $count ->\n [one] Document signed with { $count } expired certificate\n *[other] Document signed with { $count } expired certificates\n }\npdfjs-digital-signature-properties-banner-invalid =\n { $count ->\n [one] Document has { $count } invalid digital signature\n *[other] Document has { $count } invalid digital signatures\n }\npdfjs-digital-signature-properties-banner-revoked =\n { $count ->\n [one] Document signed with { $count } revoked certificate\n *[other] Document signed with { $count } revoked certificates\n }\npdfjs-digital-signature-properties-status-verified = Status: Signature verified\npdfjs-digital-signature-properties-status-invalid = Status: Signature invalid\npdfjs-digital-signature-properties-status-unknown = Status: Unable to verify (unsupported)\npdfjs-digital-signature-properties-certificate-trusted = Certificate: Trusted ({ $issuer })\npdfjs-digital-signature-properties-certificate-unknown = Certificate: Unavailable\npdfjs-digital-signature-properties-certificate-untrusted = Certificate: Untrusted\npdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer = Certificate: Unknown issuer ({ $issuer })\npdfjs-digital-signature-properties-certificate-untrusted-self-signed = Certificate: Self-signed ({ $issuer })\npdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer = Certificate: Untrusted issuer ({ $issuer })\npdfjs-digital-signature-properties-certificate-expired = Certificate: Expired\npdfjs-digital-signature-properties-certificate-expired-with-date = Certificate: Expired ({ DATETIME($dateObj, dateStyle: \"medium\") })\npdfjs-digital-signature-properties-certificate-revoked = Certificate: Revoked\npdfjs-digital-signature-properties-view-certificate = View certificate\npdfjs-digital-signature-properties-reason = Reason: { $reason }\npdfjs-digital-signature-properties-timestamp = Timestamp: { DATETIME($dateObj, dateStyle: \"short\", timeStyle: \"medium\") }\npdfjs-digital-signature-properties-sub-signatures =\n { $count ->\n [one] Sub-signature ({ $count })\n *[other] Sub-signatures ({ $count })\n }";
+ return createBundle(lang, text);
+ }
+}
+
+;// ./web/generic_scripting.js
+/* unused harmony import specifier */ var generic_scripting_getPdfFilenameFromUrl;
+
+async function docProperties(pdfDocument) {
+ const url = "",
+ baseUrl = "";
+ const {
+ info,
+ metadata,
+ contentDispositionFilename,
+ contentLength
+ } = await pdfDocument.getMetadata();
+ return {
+ ...info,
+ baseURL: baseUrl,
+ filesize: contentLength || (await pdfDocument.getDownloadInfo()).length,
+ filename: contentDispositionFilename || generic_scripting_getPdfFilenameFromUrl(url),
+ metadata: metadata?.getRaw(),
+ authors: metadata?.get("dc:creator"),
+ numPages: pdfDocument.numPages,
+ URL: url
+ };
+}
+class GenericScripting {
+ constructor(sandboxBundleSrc, wasmUrl) {
+ this._ready = new Promise((resolve, reject) => {
+ const sandbox = import(
+ /*webpackIgnore: true*/
+ /*@vite-ignore*/
+ sandboxBundleSrc);
+ sandbox.then(pdfjsSandbox => {
+ resolve(pdfjsSandbox.QuickJSSandbox(new URL(wasmUrl, location.href).href));
+ }).catch(reject);
+ });
+ }
+ async createSandbox(data) {
+ const sandbox = await this._ready;
+ sandbox.create(data);
+ }
+ async dispatchEventInSandbox(event) {
+ const sandbox = await this._ready;
+ setTimeout(() => sandbox.dispatchEvent(event), 0);
+ }
+ async destroySandbox() {
+ const sandbox = await this._ready;
+ sandbox.nukeSandbox();
+ }
+}
+
+;// ./web/generic_signature_storage.js
+
+
+
+
+
+const KEY_STORAGE = "pdfjs.signature";
+class SignatureStorage {
+ #eventBus;
+ #signatures = null;
+ #signal = null;
+ constructor(eventBus, signal) {
+ this.#eventBus = eventBus;
+ this.#signal = signal;
+ }
+ #save() {
+ localStorage.setItem(KEY_STORAGE, JSON.stringify(Object.fromEntries(this.#signatures)));
+ }
+ async getAll() {
+ if (this.#signal) {
+ window.addEventListener("storage", ({
+ key
+ }) => {
+ if (key === KEY_STORAGE) {
+ this.#signatures = null;
+ this.#eventBus?.dispatch("storedsignatureschanged", {
+ source: this
+ });
+ }
+ }, {
+ signal: this.#signal
+ });
+ this.#signal = null;
+ }
+ if (!this.#signatures) {
+ this.#signatures = new Map();
+ const data = localStorage.getItem(KEY_STORAGE);
+ if (data) {
+ for (const [key, value] of Object.entries(JSON.parse(data))) {
+ this.#signatures.set(key, value);
+ }
+ }
+ }
+ return this.#signatures;
+ }
+ async isFull() {
+ return (await this.size()) === 5;
+ }
+ async size() {
+ return (await this.getAll()).size;
+ }
+ async create(data) {
+ if (await this.isFull()) {
+ return null;
+ }
+ const uuid = getUuid();
+ this.#signatures.set(uuid, data);
+ this.#save();
+ return uuid;
+ }
+ async delete(uuid) {
+ const signatures = await this.getAll();
+ if (!signatures.has(uuid)) {
+ return false;
+ }
+ signatures.delete(uuid);
+ this.#save();
+ return true;
+ }
+}
+
+;// ./web/genericcom.js
+
+
+
+
+
+
+
+
+function initCom(app) {}
+class Preferences extends BasePreferences {
+ async _writeToStorage(prefObj) {
+ localStorage.setItem("pdfjs.preferences", JSON.stringify(prefObj));
+ }
+ async _readFromStorage(prefObj) {
+ return {
+ prefs: JSON.parse(localStorage.getItem("pdfjs.preferences"))
+ };
+ }
+}
+class ExternalServices extends BaseExternalServices {
+ constructor() {
+ super();
+ }
+ async createL10n() {
+ return new genericl10n_GenericL10n(AppOptions.get("localeProperties")?.lang);
+ }
+ createScripting() {
+ return new GenericScripting(AppOptions.get("sandboxBundleSrc"), AppOptions.get("wasmUrl"));
+ }
+ createSignatureStorage(eventBus, signal) {
+ return new SignatureStorage(eventBus, signal);
+ }
+ createSignatureVerifier() {
+ return null;
+ }
+}
+class MLManager {
+ async isEnabledFor(_name) {
+ return false;
+ }
+ async deleteModel(_service) {
+ return null;
+ }
+ isReady(_name) {
+ return false;
+ }
+ guess(_data) {}
+ toggleService(_name, _enabled) {}
+}
+
+;// ./web/new_alt_text_manager.js
+
+
+
+
+
+
+
+
+
+
+
+
+class NewAltTextManager {
+ #boundCancel = this.#cancel.bind(this);
+ #createAutomaticallyButton;
+ #currentEditor = null;
+ #cancelButton;
+ #descriptionContainer;
+ #dialog;
+ #disclaimer;
+ #downloadModel;
+ #downloadModelDescription;
+ #eventBus;
+ #firstTime = false;
+ #guessedAltText;
+ #hasAI = null;
+ #isEditing = null;
+ #imagePreview;
+ #imageData;
+ #isAILoading = false;
+ #wasAILoading = false;
+ #learnMore;
+ #notNowButton;
+ #overlayManager;
+ #textarea;
+ #title;
+ #uiManager;
+ #previousAltText = null;
+ constructor({
+ descriptionContainer,
+ dialog,
+ imagePreview,
+ cancelButton,
+ disclaimer,
+ notNowButton,
+ saveButton,
+ textarea,
+ learnMore,
+ errorCloseButton,
+ createAutomaticallyButton,
+ downloadModel,
+ downloadModelDescription,
+ title
+ }, overlayManager, eventBus) {
+ this.#cancelButton = cancelButton;
+ this.#createAutomaticallyButton = createAutomaticallyButton;
+ this.#descriptionContainer = descriptionContainer;
+ this.#dialog = dialog;
+ this.#disclaimer = disclaimer;
+ this.#notNowButton = notNowButton;
+ this.#imagePreview = imagePreview;
+ this.#textarea = textarea;
+ this.#learnMore = learnMore;
+ this.#title = title;
+ this.#downloadModel = downloadModel;
+ this.#downloadModelDescription = downloadModelDescription;
+ this.#overlayManager = overlayManager;
+ this.#eventBus = eventBus;
+ dialog.addEventListener("close", this.#close.bind(this));
+ dialog.addEventListener("contextmenu", event => {
+ if (event.target !== this.#textarea) {
+ event.preventDefault();
+ }
+ });
+ cancelButton.addEventListener("click", this.#boundCancel);
+ notNowButton.addEventListener("click", this.#boundCancel);
+ saveButton.addEventListener("click", this.#save.bind(this));
+ errorCloseButton.addEventListener("click", () => {
+ this.#toggleError(false);
+ });
+ createAutomaticallyButton.addEventListener("click", async () => {
+ const checked = createAutomaticallyButton.getAttribute("aria-pressed") !== "true";
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.alt_text.ai_generation_check",
+ data: {
+ status: checked
+ }
+ });
+ if (this.#uiManager) {
+ const isAltTextEnabled = await this.#uiManager.mlManager.isEnabledFor("altText");
+ this.#createAutomaticallyButton.disabled = true;
+ if (checked && !isAltTextEnabled) {
+ this.#textarea.value = "";
+ this.#setProgress();
+ this.#uiManager.setPreference("enableGuessAltText", true);
+ await this.#uiManager.mlManager.downloadModel("altText");
+ this.#setPref("enableAltTextModelDownload", true);
+ } else if (!checked && isAltTextEnabled) {
+ this.#uiManager.setPreference("enableGuessAltText", false);
+ await this.#uiManager.mlManager.deleteModel("altText");
+ this.#setPref("enableAltTextModelDownload", false);
+ }
+ this.#createAutomaticallyButton.disabled = false;
+ await this.#uiManager.mlManager.toggleService("altText", checked);
+ }
+ this.#toggleGuessAltText(checked, false);
+ });
+ textarea.addEventListener("focus", () => {
+ this.#wasAILoading = this.#isAILoading;
+ this.#toggleLoading(false);
+ this.#toggleTitleAndDisclaimer();
+ });
+ textarea.addEventListener("blur", () => {
+ if (!textarea.value) {
+ this.#toggleLoading(this.#wasAILoading);
+ }
+ this.#toggleTitleAndDisclaimer();
+ });
+ textarea.addEventListener("input", () => {
+ this.#toggleTitleAndDisclaimer();
+ });
+ textarea.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
+ eventBus.on("enableguessalttext", ({
+ value
+ }) => {
+ this.#toggleGuessAltText(value, false);
+ }, internalOpt);
+ this.#overlayManager.register(dialog);
+ this.#learnMore.addEventListener("click", () => {
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.alt_text.info",
+ data: {
+ topic: "alt_text"
+ }
+ });
+ });
+ }
+ #setPref(name, value) {
+ this.#eventBus.dispatch("setpreference", {
+ source: this,
+ name,
+ value
+ });
+ }
+ #toggleLoading(value) {
+ if (!this.#uiManager || this.#isAILoading === value) {
+ return;
+ }
+ this.#isAILoading = value;
+ this.#descriptionContainer.classList.toggle("loading", value);
+ }
+ #toggleError(value) {
+ if (!this.#uiManager) {
+ return;
+ }
+ this.#dialog.classList.toggle("error", value);
+ }
+ async #toggleGuessAltText(value, isInitial) {
+ if (!this.#uiManager) {
+ return;
+ }
+ this.#dialog.classList.toggle("aiDisabled", !value);
+ this.#createAutomaticallyButton.setAttribute("aria-pressed", value);
+ if (value) {
+ const {
+ altTextLearnMoreUrl
+ } = this.#uiManager.mlManager;
+ if (altTextLearnMoreUrl) {
+ this.#learnMore.href = altTextLearnMoreUrl;
+ }
+ this.#mlGuessAltText(isInitial);
+ } else {
+ this.#toggleLoading(false);
+ this.#isAILoading = false;
+ this.#toggleTitleAndDisclaimer();
+ }
+ }
+ #toggleNotNow() {
+ this.#notNowButton.classList.toggle("hidden", !this.#firstTime);
+ this.#cancelButton.classList.toggle("hidden", this.#firstTime);
+ }
+ #toggleAI(value) {
+ if (!this.#uiManager || this.#hasAI === value) {
+ return;
+ }
+ this.#hasAI = value;
+ this.#dialog.classList.toggle("noAi", !value);
+ this.#toggleTitleAndDisclaimer();
+ }
+ #toggleTitleAndDisclaimer() {
+ const visible = this.#isAILoading || this.#guessedAltText && this.#guessedAltText === this.#textarea.value;
+ this.#disclaimer.hidden = !visible;
+ const isEditing = this.#isAILoading || !!this.#textarea.value;
+ if (this.#isEditing === isEditing) {
+ return;
+ }
+ this.#isEditing = isEditing;
+ this.#title.setAttribute("data-l10n-id", isEditing ? "pdfjs-editor-new-alt-text-dialog-edit-label" : "pdfjs-editor-new-alt-text-dialog-add-label");
+ }
+ async #mlGuessAltText(isInitial) {
+ if (this.#isAILoading) {
+ return;
+ }
+ if (this.#textarea.value) {
+ return;
+ }
+ if (isInitial && this.#previousAltText !== null) {
+ return;
+ }
+ this.#guessedAltText = this.#currentEditor.guessedAltText;
+ if (this.#previousAltText === null && this.#guessedAltText) {
+ this.#addAltText(this.#guessedAltText);
+ return;
+ }
+ this.#toggleLoading(true);
+ this.#toggleTitleAndDisclaimer();
+ let hasError = false;
+ try {
+ const altText = await this.#currentEditor.mlGuessAltText(this.#imageData, false);
+ if (altText) {
+ this.#guessedAltText = altText;
+ this.#wasAILoading = this.#isAILoading;
+ if (this.#isAILoading) {
+ this.#addAltText(altText);
+ }
+ }
+ } catch (e) {
+ console.error(e);
+ hasError = true;
+ }
+ this.#toggleLoading(false);
+ this.#toggleTitleAndDisclaimer();
+ if (hasError && this.#uiManager) {
+ this.#toggleError(true);
+ }
+ }
+ #addAltText(altText) {
+ if (!this.#uiManager || this.#textarea.value) {
+ return;
+ }
+ this.#textarea.value = altText;
+ this.#toggleTitleAndDisclaimer();
+ }
+ #setProgress() {
+ this.#downloadModel.classList.toggle("hidden", false);
+ const callback = async ({
+ detail: {
+ finished,
+ total,
+ totalLoaded
+ }
+ }) => {
+ const ONE_MEGA_BYTES = 1e6;
+ totalLoaded = Math.min(0.99 * total, totalLoaded);
+ const totalSize = this.#downloadModelDescription.ariaValueMax = Math.round(total / ONE_MEGA_BYTES);
+ const downloadedSize = this.#downloadModelDescription.ariaValueNow = Math.round(totalLoaded / ONE_MEGA_BYTES);
+ this.#downloadModelDescription.setAttribute("data-l10n-args", JSON.stringify({
+ totalSize,
+ downloadedSize
+ }));
+ if (!finished) {
+ return;
+ }
+ this.#eventBus.off("loadaiengineprogress", callback);
+ this.#downloadModel.classList.toggle("hidden", true);
+ this.#toggleAI(true);
+ if (!this.#uiManager) {
+ return;
+ }
+ const {
+ mlManager
+ } = this.#uiManager;
+ mlManager.toggleService("altText", true);
+ this.#toggleGuessAltText(await mlManager.isEnabledFor("altText"), true);
+ };
+ this.#eventBus.on("loadaiengineprogress", callback, internalOpt);
+ }
+ async editAltText(uiManager, editor, firstTime) {
+ if (this.#currentEditor || !editor) {
+ return;
+ }
+ if (firstTime && editor.hasAltTextData()) {
+ editor.altTextFinish();
+ return;
+ }
+ this.#firstTime = firstTime;
+ const {
+ mlManager
+ } = uiManager;
+ const hasAI = !!mlManager;
+ this.#toggleTitleAndDisclaimer();
+ if (mlManager && !mlManager.isReady("altText")) {
+ if (mlManager.hasProgress) {
+ this.#setProgress();
+ } else {
+ this.#createAutomaticallyButton.setAttribute("aria-pressed", false);
+ }
+ } else {
+ this.#downloadModel.classList.toggle("hidden", true);
+ }
+ const isAltTextEnabledPromise = mlManager?.isEnabledFor("altText");
+ this.#currentEditor = editor;
+ this.#uiManager = uiManager;
+ this.#uiManager.removeEditListeners();
+ ({
+ altText: this.#previousAltText
+ } = editor.altTextData);
+ this.#textarea.value = this.#previousAltText ?? "";
+ const AI_MAX_IMAGE_DIMENSION = 224;
+ const MAX_PREVIEW_DIMENSION = 180;
+ let canvas, width, height;
+ if (mlManager) {
+ ({
+ canvas,
+ width,
+ height,
+ imageData: this.#imageData
+ } = editor.copyCanvas(AI_MAX_IMAGE_DIMENSION, MAX_PREVIEW_DIMENSION, true));
+ if (hasAI) {
+ this.#toggleGuessAltText(await isAltTextEnabledPromise, true);
+ }
+ } else {
+ ({
+ canvas,
+ width,
+ height
+ } = editor.copyCanvas(AI_MAX_IMAGE_DIMENSION, MAX_PREVIEW_DIMENSION, false));
+ }
+ canvas.setAttribute("role", "presentation");
+ const {
+ style
+ } = canvas;
+ style.width = `${width}px`;
+ style.height = `${height}px`;
+ this.#imagePreview.append(canvas);
+ this.#toggleNotNow();
+ this.#toggleAI(hasAI);
+ this.#toggleError(false);
+ try {
+ await this.#overlayManager.open(this.#dialog);
+ } catch (ex) {
+ this.#close();
+ throw ex;
+ }
+ }
+ #cancel() {
+ this.#currentEditor.altTextData = {
+ cancel: true
+ };
+ const altText = this.#textarea.value.trim();
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.alt_text.dismiss",
+ data: {
+ alt_text_type: altText ? "present" : "empty",
+ flow: this.#firstTime ? "image_add" : "alt_text_edit"
+ }
+ });
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.image_added",
+ data: {
+ alt_text_modal: true,
+ alt_text_type: "skipped"
+ }
+ });
+ this.#finish();
+ }
+ #finish() {
+ this.#overlayManager.closeIfActive(this.#dialog);
+ }
+ #close() {
+ const canvas = this.#imagePreview.firstElementChild;
+ canvas.remove();
+ canvas.width = canvas.height = 0;
+ this.#imageData = null;
+ this.#toggleLoading(false);
+ this.#uiManager?.addEditListeners();
+ this.#currentEditor.altTextFinish();
+ this.#uiManager?.setSelected(this.#currentEditor);
+ this.#currentEditor = null;
+ this.#uiManager = null;
+ }
+ #extractWords(text) {
+ return new Set(text.toLowerCase().split(/[^\p{L}\p{N}]+/gu).filter(Boolean));
+ }
+ #save() {
+ const altText = this.#textarea.value.trim();
+ this.#currentEditor.altTextData = {
+ altText,
+ decorative: false
+ };
+ this.#currentEditor.altTextData.guessedAltText = this.#guessedAltText;
+ if (this.#guessedAltText && this.#guessedAltText !== altText) {
+ const guessedWords = this.#extractWords(this.#guessedAltText);
+ const words = this.#extractWords(altText);
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.alt_text.user_edit",
+ data: {
+ total_words: guessedWords.size,
+ words_removed: guessedWords.difference(words).size,
+ words_added: words.difference(guessedWords).size
+ }
+ });
+ }
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.image_added",
+ data: {
+ alt_text_modal: true,
+ alt_text_type: altText ? "present" : "empty"
+ }
+ });
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.image.alt_text.save",
+ data: {
+ alt_text_type: altText ? "present" : "empty",
+ flow: this.#firstTime ? "image_add" : "alt_text_edit"
+ }
+ });
+ this.#finish();
+ }
+ destroy() {
+ this.#uiManager = null;
+ this.#finish();
+ }
+}
+class ImageAltTextSettings {
+ #createModelButton;
+ #dialog;
+ #eventBus;
+ #mlManager;
+ #overlayManager;
+ #showAltTextDialogButton;
+ constructor({
+ dialog,
+ createModelButton,
+ learnMore,
+ closeButton,
+ showAltTextDialogButton
+ }, overlayManager, eventBus, mlManager) {
+ this.#dialog = dialog;
+ this.#createModelButton = createModelButton;
+ this.#showAltTextDialogButton = showAltTextDialogButton;
+ this.#overlayManager = overlayManager;
+ this.#eventBus = eventBus;
+ this.#mlManager = mlManager;
+ const {
+ altTextLearnMoreUrl
+ } = mlManager;
+ if (altTextLearnMoreUrl) {
+ learnMore.href = altTextLearnMoreUrl;
+ }
+ dialog.addEventListener("contextmenu", noContextMenu);
+ createModelButton.addEventListener("click", async e => {
+ const checked = this.#togglePref("enableGuessAltText", e);
+ await (checked ? this.#download(true) : this.#delete(true));
+ await mlManager.toggleService("altText", checked);
+ this.#reportTelemetry({
+ type: "stamp",
+ action: "pdfjs.image.alt_text.settings_ai_generation_check",
+ data: {
+ status: checked
+ }
+ });
+ });
+ showAltTextDialogButton.addEventListener("click", e => {
+ const checked = this.#togglePref("enableNewAltTextWhenAddingImage", e);
+ this.#reportTelemetry({
+ type: "stamp",
+ action: "pdfjs.image.alt_text.settings_edit_alt_text_check",
+ data: {
+ status: checked
+ }
+ });
+ });
+ closeButton.addEventListener("click", this.#finish.bind(this));
+ learnMore.addEventListener("click", () => {
+ this.#reportTelemetry({
+ type: "stamp",
+ action: "pdfjs.image.alt_text.info",
+ data: {
+ topic: "ai_generation"
+ }
+ });
+ });
+ eventBus.on("enablealttextmodeldownload", ({
+ value
+ }) => {
+ if (value) {
+ this.#download(false);
+ } else {
+ this.#delete(false);
+ }
+ }, internalOpt);
+ this.#overlayManager.register(dialog);
+ }
+ #reportTelemetry(data) {
+ this.#eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "editing",
+ data
+ }
+ });
+ }
+ async #download(isFromUI = false) {
+ if (isFromUI) {
+ await this.#mlManager.downloadModel("altText");
+ this.#setPref("enableGuessAltText", true);
+ this.#mlManager.toggleService("altText", true);
+ this.#setPref("enableAltTextModelDownload", true);
+ }
+ }
+ async #delete(isFromUI = false) {
+ if (isFromUI) {
+ await this.#mlManager.deleteModel("altText");
+ this.#setPref("enableGuessAltText", false);
+ this.#setPref("enableAltTextModelDownload", false);
+ }
+ this.#createModelButton.setAttribute("aria-pressed", false);
+ }
+ async open({
+ enableGuessAltText,
+ enableNewAltTextWhenAddingImage
+ }) {
+ const {
+ enableAltTextModelDownload
+ } = this.#mlManager;
+ this.#createModelButton.setAttribute("aria-pressed", enableAltTextModelDownload && enableGuessAltText);
+ this.#showAltTextDialogButton.setAttribute("aria-pressed", enableNewAltTextWhenAddingImage);
+ await this.#overlayManager.open(this.#dialog);
+ this.#reportTelemetry({
+ type: "stamp",
+ action: "pdfjs.image.alt_text.settings_displayed"
+ });
+ }
+ #togglePref(name, {
+ target
+ }) {
+ const checked = target.getAttribute("aria-pressed") !== "true";
+ this.#setPref(name, checked);
+ target.setAttribute("aria-pressed", checked);
+ return checked;
+ }
+ #setPref(name, value) {
+ this.#eventBus.dispatch("setpreference", {
+ source: this,
+ name,
+ value
+ });
+ }
+ #finish() {
+ this.#overlayManager.closeIfActive(this.#dialog);
+ }
+}
+
+;// ./web/alt_text_manager.js
+
+
+class AltTextManager {
+ #clickAC = null;
+ #currentEditor = null;
+ #cancelButton;
+ #dialog;
+ #eventBus;
+ #hasUsedPointer = false;
+ #optionDescription;
+ #optionDecorative;
+ #overlayManager;
+ #saveButton;
+ #textarea;
+ #uiManager;
+ #previousAltText = null;
+ #resizeAC = null;
+ #svgElement = null;
+ #rectElement = null;
+ #container;
+ #telemetryData = null;
+ constructor({
+ dialog,
+ optionDescription,
+ optionDecorative,
+ textarea,
+ cancelButton,
+ saveButton
+ }, container, overlayManager, eventBus) {
+ this.#dialog = dialog;
+ this.#optionDescription = optionDescription;
+ this.#optionDecorative = optionDecorative;
+ this.#textarea = textarea;
+ this.#cancelButton = cancelButton;
+ this.#saveButton = saveButton;
+ this.#overlayManager = overlayManager;
+ this.#eventBus = eventBus;
+ this.#container = container;
+ const onUpdateUIState = this.#updateUIState.bind(this);
+ dialog.addEventListener("close", this.#close.bind(this));
+ dialog.addEventListener("contextmenu", event => {
+ if (event.target !== this.#textarea) {
+ event.preventDefault();
+ }
+ });
+ cancelButton.addEventListener("click", this.#finish.bind(this));
+ saveButton.addEventListener("click", this.#save.bind(this));
+ optionDescription.addEventListener("change", onUpdateUIState);
+ optionDecorative.addEventListener("change", onUpdateUIState);
+ textarea.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
+ this.#overlayManager.register(dialog);
+ }
+ #createSVGElement() {
+ if (this.#svgElement) {
+ return;
+ }
+ const svgFactory = new DOMSVGFactory();
+ const svg = this.#svgElement = svgFactory.createElement("svg");
+ svg.setAttribute("width", "0");
+ svg.setAttribute("height", "0");
+ const defs = svgFactory.createElement("defs");
+ svg.append(defs);
+ const mask = svgFactory.createElement("mask");
+ defs.append(mask);
+ mask.setAttribute("id", "alttext-manager-mask");
+ mask.setAttribute("maskContentUnits", "objectBoundingBox");
+ let rect = svgFactory.createElement("rect");
+ mask.append(rect);
+ rect.setAttribute("fill", "white");
+ rect.setAttribute("width", "1");
+ rect.setAttribute("height", "1");
+ rect.setAttribute("x", "0");
+ rect.setAttribute("y", "0");
+ rect = this.#rectElement = svgFactory.createElement("rect");
+ mask.append(rect);
+ rect.setAttribute("fill", "black");
+ this.#dialog.append(svg);
+ }
+ async editAltText(uiManager, editor) {
+ if (this.#currentEditor || !editor) {
+ return;
+ }
+ this.#createSVGElement();
+ this.#hasUsedPointer = false;
+ this.#clickAC = new AbortController();
+ const clickOpts = {
+ signal: this.#clickAC.signal
+ },
+ onClick = this.#onClick.bind(this);
+ for (const element of [this.#optionDescription, this.#optionDecorative, this.#textarea, this.#saveButton, this.#cancelButton]) {
+ element.addEventListener("click", onClick, clickOpts);
+ }
+ const {
+ altText,
+ decorative
+ } = editor.altTextData;
+ if (decorative === true) {
+ this.#optionDecorative.checked = true;
+ this.#optionDescription.checked = false;
+ } else {
+ this.#optionDecorative.checked = false;
+ this.#optionDescription.checked = true;
+ }
+ this.#previousAltText = this.#textarea.value = altText?.trim() || "";
+ this.#updateUIState();
+ this.#currentEditor = editor;
+ this.#uiManager = uiManager;
+ this.#uiManager.removeEditListeners();
+ this.#resizeAC = new AbortController();
+ this.#eventBus.on("resize", this.#setPosition.bind(this), {
+ signal: this.#resizeAC.signal,
+ ...internalOpt
+ });
+ try {
+ await this.#overlayManager.open(this.#dialog);
+ this.#setPosition();
+ } catch (ex) {
+ this.#close();
+ throw ex;
+ }
+ }
+ #setPosition() {
+ if (!this.#currentEditor) {
+ return;
+ }
+ const dialog = this.#dialog;
+ const {
+ style
+ } = dialog;
+ const {
+ x: containerX,
+ y: containerY,
+ width: containerW,
+ height: containerH
+ } = this.#container.getBoundingClientRect();
+ const {
+ innerWidth: windowW,
+ innerHeight: windowH
+ } = window;
+ const {
+ width: dialogW,
+ height: dialogH
+ } = dialog.getBoundingClientRect();
+ const {
+ x,
+ y,
+ width,
+ height
+ } = this.#currentEditor.getClientDimensions();
+ const MARGIN = 10;
+ const isLTR = this.#uiManager.direction === "ltr";
+ const xs = Math.max(x, containerX);
+ const xe = Math.min(x + width, containerX + containerW);
+ const ys = Math.max(y, containerY);
+ const ye = Math.min(y + height, containerY + containerH);
+ this.#rectElement.setAttribute("width", `${(xe - xs) / windowW}`);
+ this.#rectElement.setAttribute("height", `${(ye - ys) / windowH}`);
+ this.#rectElement.setAttribute("x", `${xs / windowW}`);
+ this.#rectElement.setAttribute("y", `${ys / windowH}`);
+ let left = null;
+ let top = Math.max(y, 0);
+ top += Math.min(windowH - (top + dialogH), 0);
+ if (isLTR) {
+ if (x + width + MARGIN + dialogW < windowW) {
+ left = x + width + MARGIN;
+ } else if (x > dialogW + MARGIN) {
+ left = x - dialogW - MARGIN;
+ }
+ } else if (x > dialogW + MARGIN) {
+ left = x - dialogW - MARGIN;
+ } else if (x + width + MARGIN + dialogW < windowW) {
+ left = x + width + MARGIN;
+ }
+ if (left === null) {
+ top = null;
+ left = Math.max(x, 0);
+ left += Math.min(windowW - (left + dialogW), 0);
+ if (y > dialogH + MARGIN) {
+ top = y - dialogH - MARGIN;
+ } else if (y + height + MARGIN + dialogH < windowH) {
+ top = y + height + MARGIN;
+ }
+ }
+ if (top !== null) {
+ dialog.classList.add("positioned");
+ if (isLTR) {
+ style.left = `${left}px`;
+ } else {
+ style.right = `${windowW - left - dialogW}px`;
+ }
+ style.top = `${top}px`;
+ } else {
+ dialog.classList.remove("positioned");
+ style.left = "";
+ style.top = "";
+ }
+ }
+ #finish() {
+ this.#overlayManager.closeIfActive(this.#dialog);
+ }
+ #close() {
+ this.#currentEditor._reportTelemetry(this.#telemetryData || {
+ action: "alt_text_cancel",
+ alt_text_keyboard: !this.#hasUsedPointer
+ });
+ this.#telemetryData = null;
+ this.#removeOnClickListeners();
+ this.#uiManager?.addEditListeners();
+ this.#resizeAC?.abort();
+ this.#resizeAC = null;
+ this.#currentEditor.altTextFinish();
+ this.#currentEditor = null;
+ this.#uiManager = null;
+ }
+ #updateUIState() {
+ this.#textarea.disabled = this.#optionDecorative.checked;
+ }
+ #save() {
+ const altText = this.#textarea.value.trim();
+ const decorative = this.#optionDecorative.checked;
+ this.#currentEditor.altTextData = {
+ altText,
+ decorative
+ };
+ this.#telemetryData = {
+ action: "alt_text_save",
+ alt_text_description: !!altText,
+ alt_text_edit: !!this.#previousAltText && this.#previousAltText !== altText,
+ alt_text_decorative: decorative,
+ alt_text_keyboard: !this.#hasUsedPointer
+ };
+ this.#finish();
+ }
+ #onClick(evt) {
+ if (evt.detail === 0) {
+ return;
+ }
+ this.#hasUsedPointer = true;
+ this.#removeOnClickListeners();
+ }
+ #removeOnClickListeners() {
+ this.#clickAC?.abort();
+ this.#clickAC = null;
+ }
+ destroy() {
+ this.#uiManager = null;
+ this.#finish();
+ this.#svgElement?.remove();
+ this.#svgElement = this.#rectElement = null;
+ }
+}
+
+;// ./web/annotation_editor_params.js
+
+
+class AnnotationEditorParams {
+ constructor(options, eventBus) {
+ this.eventBus = eventBus;
+ this.#bindListeners(options);
+ }
+ #bindListeners({
+ editorFreeTextFontSize,
+ editorFreeTextColor,
+ editorInkColor,
+ editorInkThickness,
+ editorInkOpacity,
+ editorStampAddImage,
+ editorFreeHighlightThickness,
+ editorHighlightShowAll,
+ editorSignatureAddSignature
+ }) {
+ const {
+ eventBus
+ } = this;
+ const dispatchEvent = (typeStr, value) => {
+ eventBus.dispatch("switchannotationeditorparams", {
+ source: this,
+ type: AnnotationEditorParamsType[typeStr],
+ value
+ });
+ };
+ editorFreeTextFontSize.addEventListener("input", function () {
+ dispatchEvent("FREETEXT_SIZE", this.valueAsNumber);
+ });
+ editorFreeTextColor.addEventListener("input", function () {
+ dispatchEvent("FREETEXT_COLOR", this.value);
+ });
+ let updateInkColor, updateInkOpacity;
+ if (FeatureTest.isAlphaColorInputSupported) {
+ editorInkColor.setAttribute("alpha", "");
+ editorInkOpacity.closest(".editorParamsSetter").remove();
+ let currentInkColor = "#000000";
+ let currentInkOpacity = 1;
+ editorInkColor.addEventListener("input", function () {
+ const rgba = getRGBA(this.value);
+ if (!rgba) {
+ return;
+ }
+ const [r, g, b, opacity] = rgba;
+ const hex = Util.makeHexColor(r, g, b);
+ currentInkColor = hex;
+ currentInkOpacity = opacity;
+ dispatchEvent("INK_COLOR_AND_OPACITY", {
+ color: hex,
+ opacity
+ });
+ });
+ updateInkColor = value => {
+ currentInkColor = value;
+ const alphaHex = Util.hexNums[Math.round(currentInkOpacity * 255)];
+ editorInkColor.value = currentInkColor + alphaHex;
+ };
+ updateInkOpacity = value => {
+ currentInkOpacity = value;
+ const alphaHex = Util.hexNums[Math.round(currentInkOpacity * 255)];
+ editorInkColor.value = currentInkColor + alphaHex;
+ };
+ } else {
+ editorInkColor.addEventListener("input", function () {
+ dispatchEvent("INK_COLOR", this.value);
+ });
+ editorInkOpacity.addEventListener("input", function () {
+ dispatchEvent("INK_OPACITY", this.valueAsNumber);
+ });
+ updateInkColor = value => {
+ editorInkColor.value = value;
+ };
+ updateInkOpacity = value => {
+ editorInkOpacity.value = value;
+ };
+ }
+ editorInkThickness.addEventListener("input", function () {
+ dispatchEvent("INK_THICKNESS", this.valueAsNumber);
+ });
+ editorStampAddImage.addEventListener("click", () => {
+ eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "editing",
+ data: {
+ action: "pdfjs.image.add_image_click"
+ }
+ }
+ });
+ dispatchEvent("CREATE");
+ });
+ editorFreeHighlightThickness.addEventListener("input", function () {
+ dispatchEvent("HIGHLIGHT_THICKNESS", this.valueAsNumber);
+ });
+ editorHighlightShowAll.addEventListener("click", function () {
+ const checked = this.getAttribute("aria-pressed") === "true";
+ this.setAttribute("aria-pressed", !checked);
+ dispatchEvent("HIGHLIGHT_SHOW_ALL", !checked);
+ });
+ editorSignatureAddSignature.addEventListener("click", () => {
+ dispatchEvent("CREATE");
+ });
+ eventBus.on("annotationeditorparamschanged", evt => {
+ for (const [type, value] of evt.details) {
+ switch (type) {
+ case AnnotationEditorParamsType.FREETEXT_SIZE:
+ editorFreeTextFontSize.value = value;
+ break;
+ case AnnotationEditorParamsType.FREETEXT_COLOR:
+ editorFreeTextColor.value = value;
+ break;
+ case AnnotationEditorParamsType.INK_COLOR:
+ updateInkColor(value);
+ break;
+ case AnnotationEditorParamsType.INK_THICKNESS:
+ editorInkThickness.value = value;
+ break;
+ case AnnotationEditorParamsType.INK_OPACITY:
+ updateInkOpacity(value);
+ break;
+ case AnnotationEditorParamsType.HIGHLIGHT_COLOR:
+ eventBus.dispatch("mainhighlightcolorpickerupdatecolor", {
+ source: this,
+ value
+ });
+ break;
+ case AnnotationEditorParamsType.HIGHLIGHT_THICKNESS:
+ editorFreeHighlightThickness.value = value;
+ break;
+ case AnnotationEditorParamsType.HIGHLIGHT_FREE:
+ editorFreeHighlightThickness.disabled = !value;
+ break;
+ case AnnotationEditorParamsType.HIGHLIGHT_SHOW_ALL:
+ editorHighlightShowAll.setAttribute("aria-pressed", value);
+ break;
+ }
+ }
+ }, internalOpt);
+ }
+}
+
+;// ./web/caret_browsing.js
+
+const PRECISION = 1e-1;
+class CaretBrowsingMode {
+ #mainContainer;
+ #toolBarHeight = 0;
+ #viewerContainer;
+ constructor(abortSignal, mainContainer, viewerContainer, toolbarContainer) {
+ this.#mainContainer = mainContainer;
+ this.#viewerContainer = viewerContainer;
+ if (!toolbarContainer) {
+ return;
+ }
+ this.#toolBarHeight = toolbarContainer.getBoundingClientRect().height;
+ const toolbarObserver = new ResizeObserver(entries => {
+ for (const entry of entries) {
+ if (entry.target === toolbarContainer) {
+ this.#toolBarHeight = Math.floor(entry.borderBoxSize[0].blockSize);
+ break;
+ }
+ }
+ });
+ toolbarObserver.observe(toolbarContainer);
+ abortSignal.addEventListener("abort", () => toolbarObserver.disconnect(), {
+ once: true
+ });
+ }
+ #isOnSameLine(rect1, rect2) {
+ const top1 = rect1.y;
+ const bot1 = rect1.bottom;
+ const mid1 = rect1.y + rect1.height / 2;
+ const top2 = rect2.y;
+ const bot2 = rect2.bottom;
+ const mid2 = rect2.y + rect2.height / 2;
+ return top1 <= mid2 && mid2 <= bot1 || top2 <= mid1 && mid1 <= bot2;
+ }
+ #isUnderOver(rect, x, y, isUp) {
+ const midY = rect.y + rect.height / 2;
+ return (isUp ? y >= midY : y <= midY) && rect.x - PRECISION <= x && x <= rect.right + PRECISION;
+ }
+ #isVisible(rect) {
+ return rect.top >= this.#toolBarHeight && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
+ }
+ #getCaretPosition(selection, isUp) {
+ const {
+ focusNode,
+ focusOffset
+ } = selection;
+ const range = document.createRange();
+ range.setStart(focusNode, focusOffset);
+ range.setEnd(focusNode, focusOffset);
+ const rect = range.getBoundingClientRect();
+ return [rect.x, isUp ? rect.top : rect.bottom];
+ }
+ static #caretPositionFromPoint(x, y) {
+ if (!document.caretPositionFromPoint) {
+ const {
+ startContainer: offsetNode,
+ startOffset: offset
+ } = document.caretRangeFromPoint(x, y);
+ return {
+ offsetNode,
+ offset
+ };
+ }
+ return document.caretPositionFromPoint(x, y);
+ }
+ #setCaretPositionHelper(selection, caretX, select, element, rect) {
+ rect ||= element.getBoundingClientRect();
+ if (caretX <= rect.x + PRECISION) {
+ if (select) {
+ selection.extend(element.firstChild, 0);
+ } else {
+ selection.setPosition(element.firstChild, 0);
+ }
+ return;
+ }
+ if (rect.right - PRECISION <= caretX) {
+ const {
+ lastChild
+ } = element;
+ if (select) {
+ selection.extend(lastChild, lastChild.length);
+ } else {
+ selection.setPosition(lastChild, lastChild.length);
+ }
+ return;
+ }
+ const midY = rect.y + rect.height / 2;
+ let caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
+ let parentElement = caretPosition.offsetNode?.parentElement;
+ if (parentElement && parentElement !== element) {
+ const elementsAtPoint = document.elementsFromPoint(caretX, midY);
+ const savedVisibilities = [];
+ for (const el of elementsAtPoint) {
+ if (el === element) {
+ break;
+ }
+ const {
+ style
+ } = el;
+ savedVisibilities.push([el, style.visibility]);
+ style.visibility = "hidden";
+ }
+ caretPosition = CaretBrowsingMode.#caretPositionFromPoint(caretX, midY);
+ parentElement = caretPosition.offsetNode?.parentElement;
+ for (const [el, visibility] of savedVisibilities) {
+ el.style.visibility = visibility;
+ }
+ }
+ if (parentElement !== element) {
+ if (select) {
+ selection.extend(element.firstChild, 0);
+ } else {
+ selection.setPosition(element.firstChild, 0);
+ }
+ return;
+ }
+ if (select) {
+ selection.extend(caretPosition.offsetNode, caretPosition.offset);
+ } else {
+ selection.setPosition(caretPosition.offsetNode, caretPosition.offset);
+ }
+ }
+ #setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX) {
+ if (this.#isVisible(newLineElementRect)) {
+ this.#setCaretPositionHelper(selection, caretX, select, newLineElement, newLineElementRect);
+ return;
+ }
+ this.#mainContainer.addEventListener("scrollend", this.#setCaretPositionHelper.bind(this, selection, caretX, select, newLineElement, null), {
+ once: true
+ });
+ newLineElement.scrollIntoView();
+ }
+ #getNodeOnNextPage(textLayer, isUp) {
+ while (true) {
+ const page = textLayer.closest(".page");
+ const pageNumber = parseInt(page.getAttribute("data-page-number"), 10);
+ const nextPage = isUp ? pageNumber - 1 : pageNumber + 1;
+ textLayer = this.#viewerContainer.querySelector(`.page[data-page-number="${nextPage}"] .textLayer`);
+ if (!textLayer) {
+ return null;
+ }
+ const walker = document.createTreeWalker(textLayer, NodeFilter.SHOW_TEXT);
+ const node = isUp ? walker.lastChild() : walker.firstChild();
+ if (node) {
+ return node;
+ }
+ }
+ }
+ moveCaret(isUp, select) {
+ const selection = document.getSelection();
+ if (selection.rangeCount === 0) {
+ return;
+ }
+ const {
+ focusNode
+ } = selection;
+ const focusElement = focusNode.nodeType !== Node.ELEMENT_NODE ? focusNode.parentElement : focusNode;
+ const root = focusElement.closest(".textLayer");
+ if (!root) {
+ return;
+ }
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
+ walker.currentNode = focusNode;
+ const focusRect = focusElement.getBoundingClientRect();
+ let newLineElement = null;
+ const nodeIterator = (isUp ? walker.previousSibling : walker.nextSibling).bind(walker);
+ while (nodeIterator()) {
+ const element = walker.currentNode.parentElement;
+ if (!this.#isOnSameLine(focusRect, element.getBoundingClientRect())) {
+ newLineElement = element;
+ break;
+ }
+ }
+ if (!newLineElement) {
+ const node = this.#getNodeOnNextPage(root, isUp);
+ if (!node) {
+ return;
+ }
+ if (select) {
+ const lastNode = (isUp ? walker.firstChild() : walker.lastChild()) || focusNode;
+ selection.extend(lastNode, isUp ? 0 : lastNode.length);
+ const range = document.createRange();
+ range.setStart(node, isUp ? node.length : 0);
+ range.setEnd(node, isUp ? node.length : 0);
+ selection.addRange(range);
+ return;
+ }
+ const [caretX] = this.#getCaretPosition(selection, isUp);
+ const {
+ parentElement
+ } = node;
+ this.#setCaretPosition(select, selection, parentElement, parentElement.getBoundingClientRect(), caretX);
+ return;
+ }
+ const [caretX, caretY] = this.#getCaretPosition(selection, isUp);
+ const newLineElementRect = newLineElement.getBoundingClientRect();
+ if (this.#isUnderOver(newLineElementRect, caretX, caretY, isUp)) {
+ this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX);
+ return;
+ }
+ while (nodeIterator()) {
+ const element = walker.currentNode.parentElement;
+ const elementRect = element.getBoundingClientRect();
+ if (!this.#isOnSameLine(newLineElementRect, elementRect)) {
+ break;
+ }
+ if (this.#isUnderOver(elementRect, caretX, caretY, isUp)) {
+ this.#setCaretPosition(select, selection, element, elementRect, caretX);
+ return;
+ }
+ }
+ this.#setCaretPosition(select, selection, newLineElement, newLineElementRect, caretX);
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.weak-map.get-or-insert.js
+var es_weak_map_get_or_insert = __webpack_require__(8454);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.weak-map.get-or-insert-computed.js
+var es_weak_map_get_or_insert_computed = __webpack_require__(9452);
+;// ./web/sidebar.js
+
+const RESIZE_TIMEOUT = 400;
+class Sidebar {
+ #initialWidth = 0;
+ #width = 0;
+ #coefficient;
+ #resizeTimeout = null;
+ #resizer;
+ #isResizerOnTheLeft;
+ #isKeyboardResizing = false;
+ #resizeObserver;
+ #prevX = 0;
+ constructor({
+ sidebar,
+ resizer,
+ toggleButton
+ }, ltr, isResizerOnTheLeft, globalAbortSignal) {
+ this._sidebar = sidebar;
+ this.#coefficient = ltr === isResizerOnTheLeft ? -1 : 1;
+ this.#resizer = resizer;
+ this.#isResizerOnTheLeft = isResizerOnTheLeft;
+ const style = window.getComputedStyle(sidebar);
+ this.#initialWidth = this.#width = parseFloat(style.getPropertyValue("--sidebar-width"));
+ resizer.ariaValueMin = parseFloat(style.getPropertyValue("--sidebar-min-width")) || 0;
+ resizer.ariaValueMax = parseFloat(style.getPropertyValue("--sidebar-max-width")) || Infinity;
+ resizer.ariaValueNow = this.#width;
+ this.#makeSidebarResizable();
+ toggleButton.addEventListener("click", this.toggle.bind(this));
+ this._isOpen = false;
+ sidebar.hidden = true;
+ globalAbortSignal?.addEventListener("abort", this.destroy.bind(this), {
+ once: true
+ });
+ this.#resizeObserver = new ResizeObserver(([{
+ borderBoxSize: [{
+ inlineSize
+ }]
+ }]) => {
+ if (!isNaN(this.#prevX)) {
+ this.#prevX += this.#coefficient * (inlineSize - this.#width);
+ }
+ this.#setWidth(inlineSize);
+ });
+ this.#resizeObserver.observe(sidebar);
+ }
+ #makeSidebarResizable() {
+ const sidebarStyle = this._sidebar.style;
+ let pointerMoveAC;
+ const cancelResize = () => {
+ this.#resizeTimeout = null;
+ this._sidebar.classList.remove("resizing");
+ pointerMoveAC?.abort();
+ pointerMoveAC = null;
+ this.#isKeyboardResizing = false;
+ this.onStopResizing();
+ this.#prevX = NaN;
+ };
+ this.#resizer.addEventListener("pointerdown", e => {
+ if (pointerMoveAC) {
+ cancelResize();
+ return;
+ }
+ this.onStartResizing();
+ const {
+ clientX
+ } = e;
+ stopEvent(e);
+ this.#prevX = clientX;
+ pointerMoveAC = new AbortController();
+ const {
+ signal
+ } = pointerMoveAC;
+ const sidebar = this._sidebar;
+ sidebar.classList.add("resizing");
+ const parentStyle = sidebar.parentElement.style;
+ parentStyle.minWidth = 0;
+ window.addEventListener("contextmenu", noContextMenu, {
+ signal
+ });
+ window.addEventListener("pointermove", ev => {
+ if (!pointerMoveAC || Math.abs(ev.clientX - this.#prevX) < 1) {
+ return;
+ }
+ stopEvent(ev);
+ sidebarStyle.width = `${Math.round(this.#width + this.#coefficient * (ev.clientX - this.#prevX))}px`;
+ }, {
+ signal,
+ capture: true
+ });
+ window.addEventListener("blur", cancelResize, {
+ signal
+ });
+ window.addEventListener("pointerup", ev => {
+ if (pointerMoveAC) {
+ cancelResize();
+ stopEvent(ev);
+ }
+ }, {
+ signal
+ });
+ });
+ this.#resizer.addEventListener("keydown", e => {
+ const {
+ key
+ } = e;
+ const isArrowLeft = key === "ArrowLeft";
+ if (isArrowLeft || key === "ArrowRight") {
+ if (!this.#isKeyboardResizing) {
+ this._sidebar.classList.add("resizing");
+ this.#isKeyboardResizing = true;
+ this.onStartResizing();
+ }
+ const base = e.ctrlKey || e.metaKey ? 10 : 1;
+ const dx = base * (isArrowLeft ? -1 : 1);
+ clearTimeout(this.#resizeTimeout);
+ this.#resizeTimeout = setTimeout(cancelResize, RESIZE_TIMEOUT);
+ sidebarStyle.width = `${Math.round(this.#width + this.#coefficient * dx)}px`;
+ stopEvent(e);
+ }
+ });
+ }
+ #setWidth(newWidth) {
+ this.#width = newWidth;
+ this.#resizer.ariaValueNow = Math.round(newWidth);
+ if (this.#isResizerOnTheLeft) {
+ this._sidebar.parentElement.style.insetInlineStart = `${(this.#initialWidth - newWidth).toFixed(3)}px`;
+ }
+ this.onResizing(newWidth);
+ }
+ get width() {
+ return this.#width;
+ }
+ set width(newWidth) {
+ this._sidebar.style.width = `${newWidth}px`;
+ }
+ onStartResizing() {}
+ onStopResizing() {}
+ onResizing(_newWidth) {}
+ toggle(visibility = !this._isOpen) {
+ this._sidebar.hidden = !(this._isOpen = visibility);
+ }
+ destroy() {
+ this.#resizeObserver?.disconnect();
+ this.#resizeObserver = null;
+ }
+}
+
+;// ./web/comment_manager.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class CommentManager {
+ #dialog;
+ #popup;
+ #sidebar;
+ static #hasForcedColors = null;
+ constructor(commentDialog, sidebar, eventBus, linkService, overlayManager, ltr, hasForcedColors, globalAbortSignal) {
+ const dateFormat = new Intl.DateTimeFormat(undefined, {
+ dateStyle: "long"
+ });
+ this.dialogElement = commentDialog.dialog;
+ this.#dialog = new CommentDialog(commentDialog, overlayManager, eventBus, ltr);
+ this.#popup = new CommentPopup(eventBus, dateFormat, ltr, this.dialogElement);
+ this.#sidebar = new CommentSidebar(sidebar, eventBus, linkService, this.#popup, dateFormat, ltr, globalAbortSignal);
+ this.#popup.sidebar = this.#sidebar;
+ CommentManager.#hasForcedColors = hasForcedColors;
+ }
+ setSidebarUiManager(uiManager) {
+ this.#sidebar.setUIManager(uiManager);
+ }
+ showSidebar(annotations) {
+ this.#sidebar.show(annotations);
+ }
+ hideSidebar() {
+ this.#sidebar.hide();
+ }
+ removeComments(ids) {
+ this.#sidebar.removeComments(ids);
+ }
+ selectComment(id) {
+ this.#sidebar.selectComment(null, id);
+ }
+ addComment(annotation) {
+ this.#sidebar.addComment(annotation);
+ }
+ updateComment(annotation) {
+ this.#sidebar.updateComment(annotation);
+ }
+ toggleCommentPopup(editor, isSelected, visibility, isEditable) {
+ if (isSelected) {
+ this.selectComment(editor.uid);
+ }
+ this.#popup.toggle(editor, isSelected, visibility, isEditable);
+ }
+ destroyPopup() {
+ this.#popup.destroy();
+ }
+ updatePopupColor(editor) {
+ this.#popup.updateColor(editor);
+ }
+ showDialog(uiManager, editor, posX, posY, options) {
+ return this.#dialog.open(uiManager, editor, posX, posY, options);
+ }
+ makeCommentColor(color, opacity) {
+ return CommentManager._makeCommentColor(color, opacity);
+ }
+ static _makeCommentColor(color, opacity) {
+ return this.#hasForcedColors ? null : findContrastColor(applyOpacity(color, opacity ?? 1), CSSConstants.commentForegroundColor);
+ }
+ destroy() {
+ this.#dialog.destroy();
+ this.#sidebar.hide();
+ this.#popup.destroy();
+ }
+}
+class CommentSidebar extends Sidebar {
+ #annotations = null;
+ #eventBus;
+ #boundCommentClick = this.#commentClick.bind(this);
+ #boundCommentKeydown = this.#commentKeydown.bind(this);
+ #closeButton;
+ #commentsList;
+ #commentCount;
+ #dateFormat;
+ #sidebarTitle;
+ #learnMoreUrl;
+ #linkService;
+ #popup;
+ #elementsToAnnotations = null;
+ #idsToElements = null;
+ #uiManager = null;
+ constructor({
+ learnMoreUrl,
+ sidebar,
+ sidebarResizer,
+ commentsList,
+ commentCount,
+ sidebarTitle,
+ closeButton,
+ commentToolbarButton
+ }, eventBus, linkService, popup, dateFormat, ltr, globalAbortSignal) {
+ super({
+ sidebar,
+ resizer: sidebarResizer,
+ toggleButton: commentToolbarButton
+ }, ltr, true, globalAbortSignal);
+ this.#sidebarTitle = sidebarTitle;
+ this.#commentsList = commentsList;
+ this.#commentCount = commentCount;
+ this.#learnMoreUrl = learnMoreUrl;
+ this.#linkService = linkService;
+ this.#closeButton = closeButton;
+ this.#popup = popup;
+ this.#dateFormat = dateFormat;
+ this.#eventBus = eventBus;
+ closeButton.addEventListener("click", () => {
+ eventBus.dispatch("switchannotationeditormode", {
+ source: this,
+ mode: AnnotationEditorType.NONE
+ });
+ });
+ const keyDownCallback = e => {
+ if (e.key === "ArrowDown" || e.key === "Home" || e.key === "F6") {
+ this.#commentsList.firstElementChild.focus();
+ stopEvent(e);
+ } else if (e.key === "ArrowUp" || e.key === "End") {
+ this.#commentsList.lastElementChild.focus();
+ stopEvent(e);
+ }
+ };
+ commentToolbarButton.addEventListener("keydown", keyDownCallback);
+ sidebar.addEventListener("keydown", keyDownCallback);
+ }
+ setUIManager(uiManager) {
+ this.#uiManager = uiManager;
+ }
+ show(annotations) {
+ this.#elementsToAnnotations = new WeakMap();
+ this.#idsToElements = new Map();
+ this.#annotations = annotations;
+ annotations.sort(this.#sortComments.bind(this));
+ if (annotations.length !== 0) {
+ const fragment = document.createDocumentFragment();
+ for (const annotation of annotations) {
+ fragment.append(this.#createCommentElement(annotation));
+ }
+ this.#setCommentsCount(fragment);
+ this.#commentsList.append(fragment);
+ } else {
+ this.#setCommentsCount();
+ }
+ this._sidebar.hidden = false;
+ this.#eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "commentSidebar",
+ data: {
+ numberOfAnnotations: annotations.length
+ }
+ }
+ });
+ }
+ hide() {
+ this._sidebar.hidden = true;
+ this.#commentsList.replaceChildren();
+ this.#elementsToAnnotations = null;
+ this.#idsToElements = null;
+ this.#annotations = null;
+ }
+ removeComments(ids) {
+ if (ids.length === 0 || !this.#idsToElements) {
+ return;
+ }
+ if (new Set(this.#idsToElements.keys()).difference(new Set(ids)).size === 0) {
+ this.#removeAll();
+ return;
+ }
+ for (const id of ids) {
+ this.#removeComment(id);
+ }
+ }
+ focusComment(id) {
+ const element = this.#idsToElements.get(id);
+ if (!element) {
+ return;
+ }
+ this._sidebar.scrollTop = element.offsetTop - this._sidebar.offsetTop;
+ for (const el of this.#commentsList.children) {
+ el.classList.toggle("selected", el === element);
+ }
+ }
+ updateComment(annotation) {
+ if (!this.#idsToElements) {
+ return;
+ }
+ const {
+ id,
+ creationDate,
+ modificationDate,
+ richText,
+ contentsObj,
+ popupRef
+ } = annotation;
+ if (!popupRef || !richText && !contentsObj?.str) {
+ this.#removeComment(id);
+ }
+ const element = this.#idsToElements.get(id);
+ if (!element) {
+ return;
+ }
+ const prevAnnotation = this.#elementsToAnnotations.get(element);
+ let index = binarySearchFirstItem(this.#annotations, a => this.#sortComments(a, prevAnnotation) >= 0);
+ if (index >= this.#annotations.length) {
+ return;
+ }
+ this.#setDate(element.firstElementChild, modificationDate || creationDate);
+ this.#setText(element.lastElementChild, richText, contentsObj);
+ this.#annotations.splice(index, 1);
+ index = binarySearchFirstItem(this.#annotations, a => this.#sortComments(a, annotation) >= 0);
+ this.#annotations.splice(index, 0, annotation);
+ if (index >= this.#commentsList.children.length) {
+ this.#commentsList.append(element);
+ } else {
+ this.#commentsList.insertBefore(element, this.#commentsList.children[index]);
+ }
+ }
+ #removeComment(id) {
+ const element = this.#idsToElements?.get(id);
+ if (!element) {
+ return;
+ }
+ const annotation = this.#elementsToAnnotations.get(element);
+ const index = binarySearchFirstItem(this.#annotations, a => this.#sortComments(a, annotation) >= 0);
+ if (index >= this.#annotations.length) {
+ return;
+ }
+ this.#annotations.splice(index, 1);
+ element.remove();
+ this.#idsToElements.delete(id);
+ this.#setCommentsCount();
+ }
+ #removeAll() {
+ this.#commentsList.replaceChildren();
+ this.#elementsToAnnotations = new WeakMap();
+ this.#idsToElements.clear();
+ this.#annotations.length = 0;
+ this.#setCommentsCount();
+ }
+ selectComment(element, id = null) {
+ if (!this.#idsToElements) {
+ return;
+ }
+ const hasNoElement = !element;
+ element ||= this.#idsToElements.get(id);
+ for (const el of this.#commentsList.children) {
+ el.classList.toggle("selected", el === element);
+ }
+ if (hasNoElement) {
+ element?.scrollIntoView({
+ behavior: "instant",
+ block: "center"
+ });
+ }
+ }
+ addComment(annotation) {
+ if (this.#idsToElements?.has(annotation.id)) {
+ return;
+ }
+ const {
+ popupRef,
+ contentsObj
+ } = annotation;
+ if (!popupRef || !contentsObj?.str) {
+ return;
+ }
+ const commentItem = this.#createCommentElement(annotation);
+ if (this.#annotations.length === 0) {
+ this.#commentsList.replaceChildren(commentItem);
+ this.#annotations.push(annotation);
+ this.#setCommentsCount();
+ return;
+ }
+ const index = binarySearchFirstItem(this.#annotations, a => this.#sortComments(a, annotation) >= 0);
+ this.#annotations.splice(index, 0, annotation);
+ if (index >= this.#commentsList.children.length) {
+ this.#commentsList.append(commentItem);
+ } else {
+ this.#commentsList.insertBefore(commentItem, this.#commentsList.children[index]);
+ }
+ this.#setCommentsCount();
+ }
+ #setCommentsCount(container = this.#commentsList) {
+ const count = this.#idsToElements.size;
+ this.#sidebarTitle.setAttribute("data-l10n-args", JSON.stringify({
+ count
+ }));
+ this.#commentCount.textContent = count;
+ if (count === 0) {
+ container.append(this.#createZeroCommentElement());
+ }
+ }
+ #createZeroCommentElement() {
+ const commentItem = document.createElement("li");
+ commentItem.classList.add("sidebarComment", "noComments");
+ const textDiv = document.createElement("div");
+ textDiv.className = "sidebarCommentText";
+ textDiv.setAttribute("data-l10n-id", "pdfjs-editor-comments-sidebar-no-comments1");
+ commentItem.append(textDiv);
+ if (this.#learnMoreUrl) {
+ const a = document.createElement("a");
+ a.setAttribute("data-l10n-id", "pdfjs-editor-comments-sidebar-no-comments-link");
+ a.href = this.#learnMoreUrl;
+ a.target = "_blank";
+ a.rel = "noopener noreferrer";
+ commentItem.append(a);
+ }
+ return commentItem;
+ }
+ #setDate(element, date) {
+ date = PDFDateString.toDateObject(date);
+ element.dateTime = date.toISOString();
+ element.textContent = this.#dateFormat.format(date);
+ }
+ #setText(element, richText, contentsObj) {
+ element.replaceChildren();
+ const html = richText?.str && (!contentsObj?.str || richText.str === contentsObj.str) ? richText.html : contentsObj?.str;
+ renderRichText({
+ html,
+ dir: contentsObj?.dir || "auto",
+ className: "richText"
+ }, element);
+ }
+ #createCommentElement(annotation) {
+ const {
+ id,
+ creationDate,
+ modificationDate,
+ richText,
+ contentsObj,
+ color,
+ opacity
+ } = annotation;
+ const commentItem = document.createElement("li");
+ commentItem.role = "button";
+ commentItem.className = "sidebarComment";
+ commentItem.tabIndex = -1;
+ commentItem.style.backgroundColor = color && CommentManager._makeCommentColor(color, opacity) || "";
+ const dateDiv = document.createElement("time");
+ this.#setDate(dateDiv, modificationDate || creationDate);
+ const textDiv = document.createElement("div");
+ textDiv.className = "sidebarCommentText";
+ this.#setText(textDiv, richText, contentsObj);
+ commentItem.append(dateDiv, textDiv);
+ commentItem.addEventListener("click", this.#boundCommentClick);
+ commentItem.addEventListener("keydown", this.#boundCommentKeydown);
+ this.#elementsToAnnotations.set(commentItem, annotation);
+ this.#idsToElements.set(id, commentItem);
+ return commentItem;
+ }
+ async #commentClick({
+ currentTarget
+ }) {
+ if (currentTarget.classList.contains("selected")) {
+ currentTarget.classList.remove("selected");
+ this.#popup._hide();
+ return;
+ }
+ const annotation = this.#elementsToAnnotations.get(currentTarget);
+ if (!annotation) {
+ return;
+ }
+ this.#popup._hide();
+ const {
+ id,
+ pageIndex,
+ rect
+ } = annotation;
+ const pageNumber = pageIndex + 1;
+ const pageVisiblePromise = this.#uiManager?.waitForEditorsRendered(pageNumber);
+ this.#linkService?.goToXY(pageNumber, rect[0], rect[3], {
+ center: "both"
+ });
+ this.selectComment(currentTarget);
+ await pageVisiblePromise;
+ this.#uiManager?.selectComment(pageIndex, id);
+ }
+ #commentKeydown(e) {
+ const {
+ key,
+ currentTarget
+ } = e;
+ switch (key) {
+ case "ArrowDown":
+ (currentTarget.nextElementSibling || this.#commentsList.firstElementChild).focus();
+ stopEvent(e);
+ break;
+ case "ArrowUp":
+ (currentTarget.previousElementSibling || this.#commentsList.lastElementChild).focus();
+ stopEvent(e);
+ break;
+ case "Home":
+ this.#commentsList.firstElementChild.focus();
+ stopEvent(e);
+ break;
+ case "End":
+ this.#commentsList.lastElementChild.focus();
+ stopEvent(e);
+ break;
+ case "Enter":
+ case " ":
+ this.#commentClick(e);
+ stopEvent(e);
+ break;
+ case "ShiftTab":
+ this.#closeButton.focus();
+ stopEvent(e);
+ break;
+ }
+ }
+ #sortComments(a, b) {
+ const dateA = PDFDateString.toDateObject(a.modificationDate || a.creationDate);
+ const dateB = PDFDateString.toDateObject(b.modificationDate || b.creationDate);
+ if (dateA !== dateB) {
+ if (dateA !== null && dateB !== null) {
+ return dateB - dateA;
+ }
+ return dateA !== null ? -1 : 1;
+ }
+ if (a.pageIndex !== b.pageIndex) {
+ return a.pageIndex - b.pageIndex;
+ }
+ if (a.rect[3] !== b.rect[3]) {
+ return b.rect[3] - a.rect[3];
+ }
+ if (a.rect[0] !== b.rect[0]) {
+ return a.rect[0] - b.rect[0];
+ }
+ if (a.rect[1] !== b.rect[1]) {
+ return b.rect[1] - a.rect[1];
+ }
+ if (a.rect[2] !== b.rect[2]) {
+ return a.rect[2] - b.rect[2];
+ }
+ return a.id.localeCompare(b.id);
+ }
+}
+class CommentDialog {
+ #dialog;
+ #editor;
+ #overlayManager;
+ #previousText = "";
+ #commentText = "";
+ #textInput;
+ #title;
+ #saveButton;
+ #saveButtonLabel;
+ #uiManager;
+ #prevDragX = 0;
+ #prevDragY = 0;
+ #dialogX = 0;
+ #dialogY = 0;
+ #isLTR;
+ #eventBus;
+ constructor({
+ dialog,
+ toolbar,
+ title,
+ textInput,
+ cancelButton,
+ saveButton
+ }, overlayManager, eventBus, ltr) {
+ this.#dialog = dialog;
+ this.#textInput = textInput;
+ this.#overlayManager = overlayManager;
+ this.#eventBus = eventBus;
+ this.#saveButton = saveButton;
+ this.#saveButtonLabel = saveButton.firstElementChild;
+ this.#title = title;
+ this.#isLTR = ltr;
+ const finishBound = this.#finish.bind(this);
+ dialog.addEventListener("close", finishBound);
+ dialog.addEventListener("contextmenu", e => {
+ if (e.target !== this.#textInput) {
+ e.preventDefault();
+ }
+ });
+ cancelButton.addEventListener("click", finishBound);
+ saveButton.addEventListener("click", this.#save.bind(this));
+ textInput.addEventListener("input", () => {
+ saveButton.disabled = textInput.value === this.#previousText;
+ });
+ textInput.addEventListener("keydown", e => {
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter" && !saveButton.disabled) {
+ this.#save();
+ }
+ });
+ let pointerMoveAC;
+ const cancelDrag = () => {
+ dialog.classList.remove("dragging");
+ pointerMoveAC?.abort();
+ pointerMoveAC = null;
+ };
+ toolbar.addEventListener("pointerdown", e => {
+ if (pointerMoveAC) {
+ cancelDrag();
+ return;
+ }
+ const {
+ clientX,
+ clientY
+ } = e;
+ stopEvent(e);
+ this.#prevDragX = clientX;
+ this.#prevDragY = clientY;
+ pointerMoveAC = new AbortController();
+ const {
+ signal
+ } = pointerMoveAC;
+ const {
+ innerHeight,
+ innerWidth
+ } = window;
+ dialog.classList.add("dragging");
+ window.addEventListener("pointermove", ev => {
+ if (!pointerMoveAC) {
+ return;
+ }
+ const {
+ clientX: x,
+ clientY: y
+ } = ev;
+ this.#setPosition(this.#dialogX + (x - this.#prevDragX) / innerWidth, this.#dialogY + (y - this.#prevDragY) / innerHeight);
+ this.#prevDragX = x;
+ this.#prevDragY = y;
+ stopEvent(ev);
+ }, {
+ signal
+ });
+ window.addEventListener("blur", cancelDrag, {
+ signal
+ });
+ window.addEventListener("pointerup", ev => {
+ if (pointerMoveAC) {
+ cancelDrag();
+ stopEvent(ev);
+ }
+ }, {
+ signal
+ });
+ });
+ overlayManager.register(dialog);
+ }
+ async open(uiManager, editor, posX, posY, options) {
+ if (editor) {
+ this.#uiManager = uiManager;
+ this.#editor = editor;
+ }
+ const {
+ contentsObj: {
+ str
+ },
+ color,
+ opacity
+ } = editor.getData();
+ const {
+ style: dialogStyle
+ } = this.#dialog;
+ if (color) {
+ dialogStyle.backgroundColor = CommentManager._makeCommentColor(color, opacity);
+ dialogStyle.borderColor = Util.makeHexColor(...color);
+ } else {
+ dialogStyle.backgroundColor = dialogStyle.borderColor = "";
+ }
+ this.#commentText = str || "";
+ const textInput = this.#textInput;
+ textInput.value = this.#previousText = this.#commentText;
+ if (str) {
+ this.#title.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-dialog-title-when-editing");
+ this.#saveButtonLabel.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-dialog-save-button-when-editing");
+ } else {
+ this.#title.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-dialog-title-when-adding");
+ this.#saveButtonLabel.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-dialog-save-button-when-adding");
+ }
+ if (options?.height) {
+ textInput.style.height = `${options.height}px`;
+ }
+ this.#uiManager?.removeEditListeners();
+ this.#saveButton.disabled = true;
+ const parentDimensions = options?.parentDimensions;
+ const {
+ innerHeight,
+ innerWidth
+ } = window;
+ if (editor.hasDefaultPopupPosition()) {
+ const {
+ dialogWidth,
+ dialogHeight
+ } = this._dialogDimensions;
+ if (parentDimensions) {
+ if (this.#isLTR && posX + dialogWidth > Math.min(parentDimensions.x + parentDimensions.width, innerWidth)) {
+ const buttonWidth = this.#editor.commentButtonWidth;
+ posX -= dialogWidth - buttonWidth * parentDimensions.width;
+ } else if (!this.#isLTR) {
+ const buttonWidth = this.#editor.commentButtonWidth * parentDimensions.width;
+ if (posX - dialogWidth < Math.max(0, parentDimensions.x)) {
+ posX = Math.max(0, posX);
+ } else {
+ posX -= dialogWidth - buttonWidth;
+ }
+ }
+ }
+ const height = Math.max(dialogHeight, options?.height || 0);
+ if (posY + height > innerHeight) {
+ posY = innerHeight - height;
+ }
+ if (posY < 0) {
+ posY = 0;
+ }
+ }
+ posX = MathClamp(posX / innerWidth, 0, 1);
+ posY = MathClamp(posY / innerHeight, 0, 1);
+ this.#setPosition(posX, posY);
+ await this.#overlayManager.open(this.#dialog);
+ textInput.focus();
+ }
+ async #save() {
+ this.#editor.comment = this.#textInput.value;
+ this.#finish();
+ }
+ get _dialogDimensions() {
+ const dialog = this.#dialog;
+ const {
+ style
+ } = dialog;
+ style.opacity = "0";
+ style.display = "block";
+ const {
+ width,
+ height
+ } = dialog.getBoundingClientRect();
+ style.opacity = style.display = "";
+ return shadow(this, "_dialogDimensions", {
+ dialogWidth: width,
+ dialogHeight: height
+ });
+ }
+ #setPosition(x, y) {
+ this.#dialogX = x;
+ this.#dialogY = y;
+ const {
+ style
+ } = this.#dialog;
+ style.left = `${100 * x}%`;
+ style.top = `${100 * y}%`;
+ }
+ #finish() {
+ if (!this.#editor) {
+ return;
+ }
+ const edited = this.#textInput.value !== this.#commentText;
+ this.#eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "comment",
+ data: {
+ edited
+ }
+ }
+ });
+ this.#editor?.focusCommentButton();
+ this.#editor = null;
+ this.#textInput.value = this.#previousText = this.#commentText = "";
+ this.#overlayManager.closeIfActive(this.#dialog);
+ this.#textInput.style.height = "";
+ this.#uiManager?.addEditListeners();
+ this.#uiManager = null;
+ }
+ destroy() {
+ this.#uiManager = null;
+ this.#editor = null;
+ this.#finish();
+ }
+}
+class CommentPopup {
+ #buttonsContainer = null;
+ #eventBus;
+ #commentDialog;
+ #dateFormat;
+ #editor = null;
+ #isLTR;
+ #container = null;
+ #text = null;
+ #time = null;
+ #prevDragX = 0;
+ #prevDragY = 0;
+ #posX = 0;
+ #posY = 0;
+ #previousFocusedElement = null;
+ #selected = false;
+ #visible = false;
+ constructor(eventBus, dateFormat, ltr, commentDialog) {
+ this.#eventBus = eventBus;
+ this.#dateFormat = dateFormat;
+ this.#isLTR = ltr;
+ this.#commentDialog = commentDialog;
+ this.sidebar = null;
+ }
+ get _popupWidth() {
+ const container = this.#createPopup();
+ const {
+ style
+ } = container;
+ style.opacity = "0";
+ style.display = "block";
+ document.body.append(container);
+ const width = container.getBoundingClientRect().width;
+ container.remove();
+ style.opacity = style.display = "";
+ return shadow(this, "_popupWidth", width);
+ }
+ #createPopup() {
+ if (this.#container) {
+ return this.#container;
+ }
+ const container = this.#container = document.createElement("div");
+ container.className = "commentPopup";
+ container.id = "commentPopup";
+ container.tabIndex = -1;
+ container.role = "dialog";
+ container.ariaModal = "false";
+ container.addEventListener("contextmenu", noContextMenu);
+ container.addEventListener("keydown", e => {
+ if (e.key === "Escape") {
+ this.toggle(this.#editor, true, false);
+ this.#previousFocusedElement?.focus();
+ stopEvent(e);
+ }
+ });
+ container.addEventListener("click", () => {
+ container.focus();
+ });
+ const top = document.createElement("div");
+ top.className = "commentPopupTop";
+ const time = this.#time = document.createElement("time");
+ time.className = "commentPopupTime";
+ const buttons = this.#buttonsContainer = document.createElement("div");
+ buttons.className = "commentPopupButtons";
+ const edit = document.createElement("button");
+ edit.classList.add("commentPopupEdit", "toolbarButton");
+ edit.tabIndex = 0;
+ edit.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-popup-button");
+ edit.ariaHasPopup = "dialog";
+ edit.ariaControlsElements = [this.#commentDialog];
+ const editLabel = document.createElement("span");
+ editLabel.setAttribute("data-l10n-id", "pdfjs-editor-edit-comment-popup-button-label");
+ edit.append(editLabel);
+ edit.addEventListener("click", () => {
+ const editor = this.#editor;
+ const height = parseFloat(getComputedStyle(this.#text).height);
+ this.toggle(editor, true, false);
+ editor.editComment({
+ height
+ });
+ });
+ edit.addEventListener("contextmenu", noContextMenu);
+ const del = document.createElement("button");
+ del.classList.add("commentPopupDelete", "toolbarButton");
+ del.tabIndex = 0;
+ del.setAttribute("data-l10n-id", "pdfjs-editor-delete-comment-popup-button");
+ const delLabel = document.createElement("span");
+ delLabel.setAttribute("data-l10n-id", "pdfjs-editor-delete-comment-popup-button-label");
+ del.append(delLabel);
+ del.addEventListener("click", () => {
+ this.#eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "comment",
+ data: {
+ deleted: true
+ }
+ }
+ });
+ const editor = this.#editor;
+ const savedData = editor.comment;
+ this.destroy();
+ if (savedData?.text) {
+ editor._uiManager.deleteComment(editor, savedData);
+ } else {
+ editor.comment = null;
+ }
+ editor.focus();
+ });
+ del.addEventListener("contextmenu", noContextMenu);
+ buttons.append(edit, del);
+ top.append(time, buttons);
+ const separator = document.createElement("hr");
+ const text = this.#text = document.createElement("div");
+ text.className = "commentPopupText";
+ container.append(top, separator, text);
+ let pointerMoveAC;
+ const cancelDrag = () => {
+ container.classList.remove("dragging");
+ pointerMoveAC?.abort();
+ pointerMoveAC = null;
+ };
+ top.addEventListener("pointerdown", e => {
+ if (pointerMoveAC) {
+ cancelDrag();
+ return;
+ }
+ const {
+ target,
+ clientX,
+ clientY
+ } = e;
+ if (buttons.contains(target)) {
+ return;
+ }
+ stopEvent(e);
+ const {
+ width: parentWidth,
+ height: parentHeight
+ } = this.#editor.parentBoundingClientRect;
+ this.#prevDragX = clientX;
+ this.#prevDragY = clientY;
+ pointerMoveAC = new AbortController();
+ const {
+ signal
+ } = pointerMoveAC;
+ container.classList.add("dragging");
+ window.addEventListener("pointermove", ev => {
+ if (!pointerMoveAC) {
+ return;
+ }
+ const {
+ clientX: x,
+ clientY: y
+ } = ev;
+ this.#setPosition(this.#posX + (x - this.#prevDragX) / parentWidth, this.#posY + (y - this.#prevDragY) / parentHeight, false);
+ this.#prevDragX = x;
+ this.#prevDragY = y;
+ stopEvent(ev);
+ }, {
+ signal
+ });
+ window.addEventListener("blur", cancelDrag, {
+ signal
+ });
+ window.addEventListener("pointerup", ev => {
+ if (pointerMoveAC) {
+ cancelDrag();
+ stopEvent(ev);
+ }
+ }, {
+ signal
+ });
+ });
+ return container;
+ }
+ updateColor(editor) {
+ if (this.#editor !== editor || !this.#visible) {
+ return;
+ }
+ const {
+ color,
+ opacity
+ } = editor.getData();
+ this.#container.style.backgroundColor = color && CommentManager._makeCommentColor(color, opacity) || "";
+ }
+ _hide(editor) {
+ const container = this.#createPopup();
+ container.classList.toggle("hidden", true);
+ container.classList.toggle("selected", false);
+ (editor || this.#editor)?.setCommentButtonStates({
+ selected: false,
+ hasPopup: false
+ });
+ this.#editor = null;
+ this.#selected = false;
+ this.#visible = false;
+ this.#text.replaceChildren();
+ this.sidebar.selectComment(null);
+ }
+ toggle(editor, isSelected, visibility = undefined, isEditable = true) {
+ if (!editor) {
+ this.destroy();
+ return;
+ }
+ if (isSelected) {
+ visibility ??= this.#editor === editor ? !this.#selected || !this.#visible : true;
+ } else {
+ if (this.#selected) {
+ return;
+ }
+ visibility ??= !this.#visible;
+ }
+ if (!visibility) {
+ this._hide(editor);
+ return;
+ }
+ this.#visible = true;
+ if (this.#editor !== editor) {
+ this.#editor?.setCommentButtonStates({
+ selected: false,
+ hasPopup: false
+ });
+ }
+ const container = this.#createPopup();
+ this.#buttonsContainer.classList.toggle("hidden", !isEditable);
+ container.classList.toggle("hidden", false);
+ container.classList.toggle("selected", isSelected);
+ this.#selected = isSelected;
+ this.#editor = editor;
+ editor.setCommentButtonStates({
+ selected: isSelected,
+ hasPopup: true
+ });
+ const {
+ contentsObj,
+ richText,
+ creationDate,
+ modificationDate,
+ color,
+ opacity
+ } = editor.getData();
+ container.style.backgroundColor = color && CommentManager._makeCommentColor(color, opacity) || "";
+ this.#text.replaceChildren();
+ const html = richText?.str && (!contentsObj?.str || richText.str === contentsObj.str) ? richText.html : contentsObj?.str;
+ if (html) {
+ renderRichText({
+ html,
+ dir: contentsObj?.dir || "auto",
+ className: "richText"
+ }, this.#text);
+ }
+ this.#time.textContent = this.#dateFormat.format(PDFDateString.toDateObject(modificationDate || creationDate));
+ this.#setPosition(...editor.commentPopupPosition, editor.hasDefaultPopupPosition());
+ editor.elementBeforePopup.after(container);
+ container.addEventListener("focus", ({
+ relatedTarget
+ }) => {
+ this.#previousFocusedElement = relatedTarget;
+ }, {
+ once: true
+ });
+ if (isSelected) {
+ setTimeout(() => container.focus(), 0);
+ }
+ }
+ #setPosition(x, y, correctPosition) {
+ if (!correctPosition) {
+ this.#editor.commentPopupPosition = [x, y];
+ } else {
+ const parentRect = this.#editor.parentBoundingClientRect;
+ const widthRatio = this._popupWidth / parentRect.width;
+ if (this.#isLTR && x + widthRatio > 1 || !this.#isLTR && x - widthRatio >= 0) {
+ const buttonWidth = this.#editor.commentButtonWidth;
+ x -= widthRatio - buttonWidth;
+ }
+ const margin = 0.01;
+ if (this.#isLTR) {
+ x = Math.max(x, -parentRect.x / parentRect.width + margin);
+ } else {
+ x = Math.min(x, (window.innerWidth - parentRect.x) / parentRect.width - widthRatio - margin);
+ }
+ }
+ this.#posX = x;
+ this.#posY = y;
+ const {
+ style
+ } = this.#container;
+ style.left = `${100 * x}%`;
+ style.top = `${100 * y}%`;
+ }
+ destroy() {
+ this._hide();
+ this.#container?.remove();
+ this.#container = this.#text = this.#time = null;
+ this.#prevDragX = this.#prevDragY = Infinity;
+ this.#posX = this.#posY = 0;
+ this.#previousFocusedElement = null;
+ }
+}
+
+;// ./web/base_download_manager.js
+
+
+
+class BaseDownloadManager {
+ #openBlobUrls = new WeakMap();
+ _triggerDownload(blobUrl, originalUrl, filename, isAttachment = false) {
+ throw new Error("Not implemented: _triggerDownload");
+ }
+ _getOpenDataUrl(blobUrl, filename, dest = null) {
+ throw new Error("Not implemented: _getOpenDataUrl");
+ }
+ downloadData(data, filename, contentType) {
+ const blobUrl = URL.createObjectURL(new Blob([data], {
+ type: contentType
+ }));
+ this._triggerDownload(blobUrl, blobUrl, filename, true);
+ }
+ openOrDownloadData(data, filename, dest = null) {
+ const isPdfData = isPdfFile(filename);
+ const contentType = isPdfData ? "application/pdf" : "";
+ if (isPdfData) {
+ const blobUrl = this.#openBlobUrls.getOrInsertComputed(data, () => URL.createObjectURL(new Blob([data], {
+ type: contentType
+ })));
+ try {
+ const viewerUrl = this._getOpenDataUrl(blobUrl, filename, dest);
+ window.open(viewerUrl);
+ return true;
+ } catch (ex) {
+ console.error("openOrDownloadData:", ex);
+ URL.revokeObjectURL(blobUrl);
+ this.#openBlobUrls.delete(data);
+ }
+ }
+ this.downloadData(data, filename, contentType);
+ return false;
+ }
+ download(data, url, filename) {
+ const blobUrl = data ? URL.createObjectURL(new Blob([data], {
+ type: "application/pdf"
+ })) : null;
+ this._triggerDownload(blobUrl, url, filename);
+ }
+}
+
+;// ./web/download_manager.js
+
+
+class DownloadManager extends BaseDownloadManager {
+ _triggerDownload(blobUrl, originalUrl, filename, isAttachment = false) {
+ if (!blobUrl && !isAttachment) {
+ if (!createValidAbsoluteUrl(originalUrl, "http://example.com")) {
+ throw new Error(`_triggerDownload - not a valid URL: ${originalUrl}`);
+ }
+ blobUrl = originalUrl + "#pdfjs.action=download";
+ }
+ const a = document.createElement("a");
+ a.href = blobUrl;
+ a.target = "_parent";
+ if ("download" in a) {
+ a.download = filename;
+ }
+ (document.body || document.documentElement).append(a);
+ a.click();
+ a.remove();
+ }
+ _getOpenDataUrl(blobUrl, filename, dest = null) {
+ let url = "?file=" + encodeURIComponent(blobUrl + "#" + filename);
+ if (dest) {
+ url += `#${escape(dest)}`;
+ }
+ return url;
+ }
+}
+
+;// ./web/editor_undo_bar.js
+
+
+
+class EditorUndoBar {
+ #closeButton = null;
+ #container;
+ #eventBus = null;
+ #focusTimeout = null;
+ #initController = null;
+ isOpen = false;
+ #message;
+ #showController = null;
+ #undoButton;
+ static #l10nMessages = Object.freeze({
+ highlight: "pdfjs-editor-undo-bar-message-highlight",
+ freetext: "pdfjs-editor-undo-bar-message-freetext",
+ stamp: "pdfjs-editor-undo-bar-message-stamp",
+ ink: "pdfjs-editor-undo-bar-message-ink",
+ signature: "pdfjs-editor-undo-bar-message-signature",
+ comment: "pdfjs-editor-undo-bar-message-comment",
+ _multiple: "pdfjs-editor-undo-bar-message-multiple"
+ });
+ constructor({
+ container,
+ message,
+ undoButton,
+ closeButton
+ }, eventBus) {
+ this.#container = container;
+ this.#message = message;
+ this.#undoButton = undoButton;
+ this.#closeButton = closeButton;
+ this.#eventBus = eventBus;
+ }
+ destroy() {
+ this.#initController?.abort();
+ this.#initController = null;
+ this.hide();
+ }
+ show(undoAction, messageData) {
+ if (!this.#initController) {
+ this.#initController = new AbortController();
+ const domOpts = {
+ signal: this.#initController.signal
+ };
+ const evtOpts = {
+ signal: this.#initController.signal,
+ ...internalOpt
+ };
+ const boundHide = this.hide.bind(this);
+ this.#container.addEventListener("contextmenu", noContextMenu, domOpts);
+ this.#closeButton.addEventListener("click", boundHide, domOpts);
+ this.#eventBus.on("beforeprint", boundHide, evtOpts);
+ this.#eventBus.on("download", boundHide, evtOpts);
+ }
+ this.hide();
+ if (typeof messageData === "string") {
+ this.#message.setAttribute("data-l10n-id", EditorUndoBar.#l10nMessages[messageData]);
+ } else {
+ this.#message.setAttribute("data-l10n-id", EditorUndoBar.#l10nMessages._multiple);
+ this.#message.setAttribute("data-l10n-args", JSON.stringify({
+ count: messageData
+ }));
+ }
+ this.isOpen = true;
+ this.#container.hidden = false;
+ this.#showController = new AbortController();
+ this.#undoButton.addEventListener("click", () => {
+ undoAction();
+ this.hide();
+ }, {
+ signal: this.#showController.signal
+ });
+ this.#focusTimeout = setTimeout(() => {
+ if (!this.#container.contains(document.activeElement)) {
+ this.#container.focus();
+ }
+ this.#focusTimeout = null;
+ }, 100);
+ }
+ hide() {
+ if (!this.isOpen) {
+ return;
+ }
+ this.isOpen = false;
+ this.#container.hidden = true;
+ this.#showController?.abort();
+ this.#showController = null;
+ if (this.#focusTimeout) {
+ clearTimeout(this.#focusTimeout);
+ this.#focusTimeout = null;
+ }
+ }
+}
+
+;// ./web/overlay_manager.js
+
+
+class OverlayManager {
+ #overlays = new WeakMap();
+ #active = null;
+ get active() {
+ return this.#active;
+ }
+ async register(dialog, canForceClose = false) {
+ if (typeof dialog !== "object") {
+ throw new Error("Not enough parameters.");
+ } else if (this.#overlays.has(dialog)) {
+ throw new Error("The overlay is already registered.");
+ }
+ this.#overlays.set(dialog, {
+ canForceClose
+ });
+ dialog.addEventListener("cancel", ({
+ target
+ }) => {
+ if (this.#active === target) {
+ this.#active = null;
+ }
+ });
+ }
+ async open(dialog) {
+ if (!this.#overlays.has(dialog)) {
+ throw new Error("The overlay does not exist.");
+ } else if (this.#active) {
+ if (this.#active === dialog) {
+ throw new Error("The overlay is already active.");
+ } else if (this.#overlays.get(dialog).canForceClose) {
+ await this.close();
+ } else {
+ throw new Error("Another overlay is currently active.");
+ }
+ }
+ this.#active = dialog;
+ dialog.showModal();
+ }
+ async close(dialog = this.#active) {
+ if (!this.#overlays.has(dialog)) {
+ throw new Error("The overlay does not exist.");
+ } else if (!this.#active) {
+ throw new Error("The overlay is currently not active.");
+ } else if (this.#active !== dialog) {
+ throw new Error("Another overlay is currently active.");
+ }
+ dialog.close();
+ this.#active = null;
+ }
+ async closeIfActive(dialog) {
+ if (this.#active === dialog) {
+ await this.close(dialog);
+ }
+ }
+}
+
+;// ./web/password_prompt.js
+
+class PasswordPrompt {
+ #activeCapability = null;
+ #updateCallback = null;
+ #reason = null;
+ constructor(options, overlayManager, isViewerEmbedded = false) {
+ this.dialog = options.dialog;
+ this.label = options.label;
+ this.input = options.input;
+ this.submitButton = options.submitButton;
+ this.cancelButton = options.cancelButton;
+ this.overlayManager = overlayManager;
+ this._isViewerEmbedded = isViewerEmbedded;
+ this.submitButton.addEventListener("click", this.#verify.bind(this));
+ this.cancelButton.addEventListener("click", this.close.bind(this));
+ this.input.addEventListener("keydown", e => {
+ if (e.keyCode === 13) {
+ this.#verify();
+ e.preventDefault();
+ }
+ });
+ this.overlayManager.register(this.dialog, true);
+ this.dialog.addEventListener("close", this.#cancel.bind(this));
+ }
+ async open() {
+ await this.#activeCapability?.promise;
+ this.#activeCapability = Promise.withResolvers();
+ try {
+ await this.overlayManager.open(this.dialog);
+ } catch (ex) {
+ this.#activeCapability.resolve();
+ throw ex;
+ }
+ const passwordIncorrect = this.#reason === PasswordResponses.INCORRECT_PASSWORD;
+ if (!this._isViewerEmbedded || passwordIncorrect) {
+ this.input.focus();
+ }
+ this.label.setAttribute("data-l10n-id", passwordIncorrect ? "pdfjs-password-invalid" : "pdfjs-password-label");
+ }
+ async close() {
+ this.overlayManager.closeIfActive(this.dialog);
+ }
+ #verify() {
+ const password = this.input.value;
+ if (password?.length > 0) {
+ this.#invokeCallback(password);
+ }
+ }
+ #cancel() {
+ this.#invokeCallback(new Error("PasswordPrompt cancelled."));
+ this.#activeCapability.resolve();
+ }
+ #invokeCallback(password) {
+ if (!this.#updateCallback) {
+ return;
+ }
+ this.close();
+ this.input.value = "";
+ this.#updateCallback(password);
+ this.#updateCallback = null;
+ }
+ async setUpdateCallback(updateCallback, reason) {
+ if (this.#activeCapability) {
+ await this.#activeCapability.promise;
+ }
+ this.#updateCallback = updateCallback;
+ this.#reason = reason;
+ }
+}
+
+;// ./web/base_tree_viewer.js
+
+
+const TREEITEM_SELECTED_CLASS = "selected";
+class BaseTreeViewer {
+ constructor(options) {
+ this.container = options.container;
+ this.eventBus = options.eventBus;
+ this._l10n = options.l10n;
+ this.reset();
+ }
+ reset() {
+ this._pdfDocument = null;
+ this._lastToggleIsShow = true;
+ this._currentTreeItem = null;
+ this.container.replaceChildren();
+ this.container.classList.remove("withNesting");
+ }
+ _dispatchEvent(count) {
+ throw new Error("Not implemented: _dispatchEvent");
+ }
+ _bindLink(element, params) {
+ throw new Error("Not implemented: _bindLink");
+ }
+ _normalizeTextContent(str) {
+ return removeNullCharacters(str, true) || "\u2013";
+ }
+ _addToggleButton(div, hidden = false) {
+ const toggler = document.createElement("div");
+ toggler.className = "treeItemToggler";
+ if (hidden) {
+ toggler.classList.add("treeItemsHidden");
+ }
+ div.prepend(toggler);
+ }
+ _toggleTreeItem(root, show = false) {
+ this._l10n.pause();
+ this._lastToggleIsShow = show;
+ for (const toggler of root.querySelectorAll(".treeItemToggler")) {
+ toggler.classList.toggle("treeItemsHidden", !show);
+ }
+ this._l10n.resume();
+ }
+ _toggleAllTreeItems() {
+ this._toggleTreeItem(this.container, !this._lastToggleIsShow);
+ }
+ _finishRendering(fragment, count, hasAnyNesting = false) {
+ if (hasAnyNesting) {
+ this.container.classList.add("withNesting");
+ this._lastToggleIsShow = !fragment.querySelector(".treeItemsHidden");
+ this.container.addEventListener("click", e => {
+ const {
+ target
+ } = e;
+ if (!target.classList.contains("treeItemToggler")) {
+ return;
+ }
+ stopEvent(e);
+ target.classList.toggle("treeItemsHidden");
+ if (e.shiftKey) {
+ const shouldShowAll = !target.classList.contains("treeItemsHidden");
+ this._toggleTreeItem(target.parentNode, shouldShowAll);
+ }
+ });
+ }
+ this._l10n.pause();
+ this.container.append(fragment);
+ this._l10n.resume();
+ this._dispatchEvent(count);
+ }
+ render(params) {
+ throw new Error("Not implemented: render");
+ }
+ _updateCurrentTreeItem(treeItem = null) {
+ if (this._currentTreeItem) {
+ this._currentTreeItem.classList.remove(TREEITEM_SELECTED_CLASS);
+ this._currentTreeItem = null;
+ }
+ if (treeItem) {
+ treeItem.classList.add(TREEITEM_SELECTED_CLASS);
+ this._currentTreeItem = treeItem;
+ }
+ }
+ _scrollToCurrentTreeItem(treeItem) {
+ if (!treeItem) {
+ return;
+ }
+ this._l10n.pause();
+ let currentNode = treeItem.parentNode;
+ while (currentNode && currentNode !== this.container) {
+ if (currentNode.classList.contains("treeItem")) {
+ const toggler = currentNode.firstElementChild;
+ toggler?.classList.remove("treeItemsHidden");
+ }
+ currentNode = currentNode.parentNode;
+ }
+ this._l10n.resume();
+ this._updateCurrentTreeItem(treeItem);
+ treeItem.scrollIntoView({
+ behavior: "instant",
+ block: "center",
+ inline: "center",
+ container: "nearest"
+ });
+ }
+}
+
+;// ./web/pdf_attachment_viewer.js
+
+
+
+
+
+class PDFAttachmentViewer extends BaseTreeViewer {
+ constructor(options) {
+ super(options);
+ this.downloadManager = options.downloadManager;
+ this.linkService = options.linkService;
+ this.eventBus.on("fileattachmentannotation", this.#appendAttachment.bind(this), internalOpt);
+ }
+ reset(keepRenderedCapability = false) {
+ super.reset();
+ this._attachments = null;
+ if (!keepRenderedCapability) {
+ this._renderedCapability = Promise.withResolvers();
+ }
+ this._pendingDispatchEvent = false;
+ }
+ async _dispatchEvent(attachmentsCount) {
+ this._renderedCapability.resolve();
+ if (attachmentsCount === 0 && !this._pendingDispatchEvent) {
+ this._pendingDispatchEvent = true;
+ await waitOnEventOrTimeout({
+ target: this.eventBus,
+ name: "annotationlayerrendered",
+ delay: 1000
+ });
+ if (!this._pendingDispatchEvent) {
+ return;
+ }
+ }
+ this._pendingDispatchEvent = false;
+ this.eventBus.dispatch("attachmentsloaded", {
+ source: this,
+ attachmentsCount
+ });
+ }
+ _bindLink(element, {
+ attachmentId,
+ content: fallbackContent,
+ description,
+ filename
+ }) {
+ if (description) {
+ element.title = description;
+ }
+ const openAttachment = async () => {
+ const content = attachmentId ? await this.linkService.getAttachmentContent(attachmentId) : fallbackContent;
+ if (content) {
+ this.downloadManager?.openOrDownloadData(content, filename);
+ }
+ };
+ element.onclick = () => {
+ openAttachment();
+ return false;
+ };
+ }
+ render({
+ attachments,
+ keepRenderedCapability = false
+ }) {
+ if (this._attachments) {
+ this.reset(keepRenderedCapability);
+ }
+ this._attachments = attachments || null;
+ if (!attachments) {
+ this._dispatchEvent(0);
+ return;
+ }
+ const fragment = document.createDocumentFragment();
+ const ul = document.createElement("ul");
+ fragment.append(ul);
+ let attachmentsCount = 0;
+ for (const [name, item] of attachments) {
+ const li = document.createElement("li");
+ ul.append(li);
+ const element = document.createElement("a");
+ li.append(element);
+ this._bindLink(element, {
+ ...item,
+ attachmentId: item.attachmentId ?? name
+ });
+ element.textContent = this._normalizeTextContent(item.filename);
+ attachmentsCount++;
+ }
+ this._finishRendering(fragment, attachmentsCount);
+ }
+ #appendAttachment(item) {
+ const renderedPromise = this._renderedCapability.promise;
+ renderedPromise.then(() => {
+ if (renderedPromise !== this._renderedCapability.promise) {
+ return;
+ }
+ const attachments = new Map(this._attachments);
+ if (attachments.has(item.filename)) {
+ return;
+ }
+ attachments.set(item.filename, item);
+ this.render({
+ attachments,
+ keepRenderedCapability: true
+ });
+ });
+ }
+}
+
+;// ./web/grab_to_pan.js
+
+const CSS_CLASS_GRAB = "grab-to-pan-grab";
+class GrabToPan {
+ #activateAC = null;
+ #mouseDownAC = null;
+ #scrollAC = null;
+ constructor({
+ element
+ }) {
+ this.element = element;
+ this.document = element.ownerDocument;
+ const overlay = this.overlay = document.createElement("div");
+ overlay.className = "grab-to-pan-grabbing";
+ }
+ activate() {
+ if (!this.#activateAC) {
+ this.#activateAC = new AbortController();
+ this.element.addEventListener("mousedown", this.#onMouseDown.bind(this), {
+ capture: true,
+ signal: this.#activateAC.signal
+ });
+ this.element.classList.add(CSS_CLASS_GRAB);
+ }
+ }
+ deactivate() {
+ if (this.#activateAC) {
+ this.#activateAC.abort();
+ this.#activateAC = null;
+ this.#endPan();
+ this.element.classList.remove(CSS_CLASS_GRAB);
+ }
+ }
+ ignoreTarget(node) {
+ return node.matches("a[href], a[href] *, input, textarea, button, button *, select, option");
+ }
+ #onMouseDown(event) {
+ if (event.button !== 0 || this.ignoreTarget(event.target)) {
+ return;
+ }
+ if (event.originalTarget) {
+ try {
+ event.originalTarget.tagName;
+ } catch {
+ return;
+ }
+ }
+ this.scrollLeftStart = this.element.scrollLeft;
+ this.scrollTopStart = this.element.scrollTop;
+ this.clientXStart = event.clientX;
+ this.clientYStart = event.clientY;
+ this.#mouseDownAC = new AbortController();
+ const boundEndPan = this.#endPan.bind(this),
+ mouseOpts = {
+ capture: true,
+ signal: this.#mouseDownAC.signal
+ };
+ this.document.addEventListener("mousemove", this.#onMouseMove.bind(this), mouseOpts);
+ this.document.addEventListener("mouseup", boundEndPan, mouseOpts);
+ this.#scrollAC = new AbortController();
+ this.element.addEventListener("scroll", boundEndPan, {
+ capture: true,
+ signal: this.#scrollAC.signal
+ });
+ stopEvent(event);
+ const focusedElement = document.activeElement;
+ if (focusedElement && !focusedElement.contains(event.target)) {
+ focusedElement.blur();
+ }
+ }
+ #onMouseMove(event) {
+ this.#scrollAC?.abort();
+ this.#scrollAC = null;
+ if (!(event.buttons & 1)) {
+ this.#endPan();
+ return;
+ }
+ const xDiff = event.clientX - this.clientXStart;
+ const yDiff = event.clientY - this.clientYStart;
+ this.element.scrollTo({
+ top: this.scrollTopStart - yDiff,
+ left: this.scrollLeftStart - xDiff,
+ behavior: "instant"
+ });
+ if (!this.overlay.parentNode) {
+ document.body.append(this.overlay);
+ }
+ }
+ #endPan() {
+ this.#mouseDownAC?.abort();
+ this.#mouseDownAC = null;
+ this.#scrollAC?.abort();
+ this.#scrollAC = null;
+ this.overlay.remove();
+ }
+}
+
+;// ./web/pdf_cursor_tools.js
+
+
+
+
+class PDFCursorTools {
+ #active = CursorTool.SELECT;
+ #prevActive = null;
+ constructor({
+ container,
+ eventBus,
+ cursorToolOnLoad = CursorTool.SELECT
+ }) {
+ this.container = container;
+ this.eventBus = eventBus;
+ this.#addEventListeners();
+ Promise.resolve().then(() => {
+ this.switchTool(cursorToolOnLoad);
+ });
+ }
+ get activeTool() {
+ return this.#active;
+ }
+ switchTool(tool) {
+ if (this.#prevActive !== null) {
+ return;
+ }
+ this.#switchTool(tool);
+ }
+ #switchTool(tool, disabled = false) {
+ if (tool === this.#active) {
+ if (this.#prevActive !== null) {
+ this.eventBus.dispatch("cursortoolchanged", {
+ source: this,
+ tool,
+ disabled
+ });
+ }
+ return;
+ }
+ const disableActiveTool = () => {
+ switch (this.#active) {
+ case CursorTool.SELECT:
+ break;
+ case CursorTool.HAND:
+ this._handTool.deactivate();
+ break;
+ case CursorTool.ZOOM:
+ }
+ };
+ switch (tool) {
+ case CursorTool.SELECT:
+ disableActiveTool();
+ break;
+ case CursorTool.HAND:
+ disableActiveTool();
+ this._handTool.activate();
+ break;
+ case CursorTool.ZOOM:
+ default:
+ console.error(`switchTool: "${tool}" is an unsupported value.`);
+ return;
+ }
+ this.#active = tool;
+ this.eventBus.dispatch("cursortoolchanged", {
+ source: this,
+ tool,
+ disabled
+ });
+ }
+ #addEventListeners() {
+ const {
+ eventBus
+ } = this;
+ eventBus.on("switchcursortool", evt => {
+ if (!evt.reset) {
+ this.switchTool(evt.tool);
+ } else if (this.#prevActive !== null) {
+ annotationEditorMode = AnnotationEditorType.NONE;
+ presentationModeState = PresentationModeState.NORMAL;
+ enableActive();
+ }
+ }, internalOpt);
+ let annotationEditorMode = AnnotationEditorType.NONE,
+ presentationModeState = PresentationModeState.NORMAL;
+ const disableActive = () => {
+ this.#prevActive ??= this.#active;
+ this.#switchTool(CursorTool.SELECT, true);
+ };
+ const enableActive = () => {
+ if (this.#prevActive !== null && annotationEditorMode === AnnotationEditorType.NONE && presentationModeState === PresentationModeState.NORMAL) {
+ this.#switchTool(this.#prevActive);
+ this.#prevActive = null;
+ }
+ };
+ eventBus.on("annotationeditormodechanged", ({
+ mode
+ }) => {
+ annotationEditorMode = mode;
+ if (mode === AnnotationEditorType.NONE) {
+ enableActive();
+ } else {
+ disableActive();
+ }
+ }, internalOpt);
+ eventBus.on("presentationmodechanged", ({
+ state
+ }) => {
+ presentationModeState = state;
+ if (state === PresentationModeState.NORMAL) {
+ enableActive();
+ } else if (state === PresentationModeState.FULLSCREEN) {
+ disableActive();
+ }
+ }, internalOpt);
+ }
+ get _handTool() {
+ return shadow(this, "_handTool", new GrabToPan({
+ element: this.container
+ }));
+ }
+}
+
+;// ./web/pdf_document_properties.js
+
+
+
+
+const NON_METRIC_LOCALES = ["en-us", "en-lr", "my"];
+const US_PAGE_NAMES = {
+ "8.5x11": "pdfjs-document-properties-page-size-name-letter",
+ "8.5x14": "pdfjs-document-properties-page-size-name-legal"
+};
+const METRIC_PAGE_NAMES = {
+ "297x420": "pdfjs-document-properties-page-size-name-a-three",
+ "210x297": "pdfjs-document-properties-page-size-name-a-four"
+};
+function getPageName(size, isPortrait, pageNames) {
+ const width = isPortrait ? size.width : size.height;
+ const height = isPortrait ? size.height : size.width;
+ return pageNames[`${width}x${height}`];
+}
+class PDFDocumentProperties {
+ #fieldData = null;
+ constructor({
+ dialog,
+ fields,
+ closeButton
+ }, overlayManager, eventBus, l10n, fileNameLookup, titleLookup) {
+ this.dialog = dialog;
+ this.fields = fields;
+ this.overlayManager = overlayManager;
+ this.l10n = l10n;
+ this._fileNameLookup = fileNameLookup;
+ this._titleLookup = titleLookup;
+ this.#reset();
+ closeButton.addEventListener("click", this.close.bind(this));
+ this.overlayManager.register(this.dialog);
+ eventBus.on("pagechanging", evt => {
+ this._currentPageNumber = evt.pageNumber;
+ }, internalOpt);
+ eventBus.on("rotationchanging", evt => {
+ this._pagesRotation = evt.pagesRotation;
+ }, internalOpt);
+ }
+ async open() {
+ await Promise.all([this.overlayManager.open(this.dialog), this._dataAvailableCapability.promise]);
+ const currentPageNumber = this._currentPageNumber;
+ const pagesRotation = this._pagesRotation;
+ if (this.#fieldData && currentPageNumber === this.#fieldData._currentPageNumber && pagesRotation === this.#fieldData._pagesRotation) {
+ this.#updateUI();
+ return;
+ }
+ const [{
+ info,
+ metadata,
+ contentLength
+ }, pdfPage] = await Promise.all([this.pdfDocument.getMetadata(), this.pdfDocument.getPage(currentPageNumber).catch(reason => {
+ console.error(`PDFDocumentProperties - unable to get page ${currentPageNumber}.`, reason);
+ return null;
+ })]);
+ const [fileName, fileSize, title, creationDate, modificationDate, pageSize, isLinearized] = await Promise.all([this._fileNameLookup(), this.#parseFileSize(contentLength), this._titleLookup(), this.#parseDate(metadata?.get("xmp:createdate"), info.CreationDate), this.#parseDate(metadata?.get("xmp:modifydate"), info.ModDate), this.#parsePageSize(pdfPage, pagesRotation), this.#parseLinearization(info.IsLinearized)]);
+ this.#fieldData = Object.freeze({
+ fileName,
+ fileSize,
+ title,
+ author: metadata?.get("dc:creator")?.join("\n") || info.Author,
+ subject: metadata?.get("dc:subject")?.join("\n") || info.Subject,
+ keywords: metadata?.get("pdf:keywords") || info.Keywords,
+ creationDate,
+ modificationDate,
+ creator: metadata?.get("xmp:creatortool") || info.Creator,
+ producer: metadata?.get("pdf:producer") || info.Producer,
+ version: info.PDFFormatVersion,
+ pageCount: this.pdfDocument.numPages,
+ pageSize,
+ linearized: isLinearized,
+ _currentPageNumber: currentPageNumber,
+ _pagesRotation: pagesRotation
+ });
+ this.#updateUI();
+ const {
+ length
+ } = await this.pdfDocument.getDownloadInfo();
+ if (contentLength === length) {
+ return;
+ }
+ const data = Object.assign(Object.create(null), this.#fieldData);
+ data.fileSize = await this.#parseFileSize(length);
+ this.#fieldData = Object.freeze(data);
+ this.#updateUI();
+ }
+ async close() {
+ this.overlayManager.close(this.dialog);
+ }
+ setDocument(pdfDocument) {
+ if (this.pdfDocument) {
+ this.#reset();
+ this.#updateUI();
+ }
+ if (!pdfDocument) {
+ return;
+ }
+ this.pdfDocument = pdfDocument;
+ this._dataAvailableCapability.resolve();
+ }
+ #reset() {
+ this.pdfDocument = null;
+ this.#fieldData = null;
+ this._dataAvailableCapability = Promise.withResolvers();
+ this._currentPageNumber = 1;
+ this._pagesRotation = 0;
+ }
+ #updateUI() {
+ if (this.#fieldData && this.overlayManager.active !== this.dialog) {
+ return;
+ }
+ for (const id in this.fields) {
+ const content = this.#fieldData?.[id];
+ this.fields[id].textContent = content || content === 0 ? content : "-";
+ }
+ }
+ async #parseFileSize(b = 0) {
+ const kb = b / 1024,
+ mb = kb / 1024;
+ return kb ? this.l10n.get(mb >= 1 ? "pdfjs-document-properties-size-mb" : "pdfjs-document-properties-size-kb", {
+ mb,
+ kb,
+ b
+ }) : undefined;
+ }
+ async #parsePageSize(pdfPage, pagesRotation) {
+ if (!pdfPage) {
+ return undefined;
+ }
+ let pageSizeInches = getPageSizeInches(pdfPage);
+ if (pagesRotation % 180 !== 0) {
+ pageSizeInches = {
+ width: pageSizeInches.height,
+ height: pageSizeInches.width
+ };
+ }
+ const isPortrait = isPortraitOrientation(pageSizeInches),
+ nonMetric = NON_METRIC_LOCALES.includes(this.l10n.getLanguage());
+ let sizeInches = {
+ width: Math.round(pageSizeInches.width * 100) / 100,
+ height: Math.round(pageSizeInches.height * 100) / 100
+ };
+ let sizeMillimeters = {
+ width: Math.round(pageSizeInches.width * 25.4 * 10) / 10,
+ height: Math.round(pageSizeInches.height * 25.4 * 10) / 10
+ };
+ let nameId = getPageName(sizeInches, isPortrait, US_PAGE_NAMES) || getPageName(sizeMillimeters, isPortrait, METRIC_PAGE_NAMES);
+ if (!nameId && !(Number.isInteger(sizeMillimeters.width) && Number.isInteger(sizeMillimeters.height))) {
+ const exactMillimeters = {
+ width: pageSizeInches.width * 25.4,
+ height: pageSizeInches.height * 25.4
+ };
+ const intMillimeters = {
+ width: Math.round(sizeMillimeters.width),
+ height: Math.round(sizeMillimeters.height)
+ };
+ if (Math.abs(exactMillimeters.width - intMillimeters.width) < 0.1 && Math.abs(exactMillimeters.height - intMillimeters.height) < 0.1) {
+ nameId = getPageName(intMillimeters, isPortrait, METRIC_PAGE_NAMES);
+ if (nameId) {
+ sizeInches = {
+ width: Math.round(intMillimeters.width / 25.4 * 100) / 100,
+ height: Math.round(intMillimeters.height / 25.4 * 100) / 100
+ };
+ sizeMillimeters = intMillimeters;
+ }
+ }
+ }
+ const [{
+ width,
+ height
+ }, unit, name, orientation] = await Promise.all([nonMetric ? sizeInches : sizeMillimeters, this.l10n.get(nonMetric ? "pdfjs-document-properties-page-size-unit-inches" : "pdfjs-document-properties-page-size-unit-millimeters"), nameId && this.l10n.get(nameId), this.l10n.get(isPortrait ? "pdfjs-document-properties-page-size-orientation-portrait" : "pdfjs-document-properties-page-size-orientation-landscape")]);
+ return this.l10n.get(name ? "pdfjs-document-properties-page-size-dimension-name-string" : "pdfjs-document-properties-page-size-dimension-string", {
+ width,
+ height,
+ unit,
+ name,
+ orientation
+ });
+ }
+ async #parseDate(metadataDate, infoDate) {
+ const dateObj = Date.parse(metadataDate) || PDFDateString.toDateObject(infoDate);
+ return dateObj ? this.l10n.get("pdfjs-document-properties-date-time-string", {
+ dateObj: dateObj.valueOf()
+ }) : undefined;
+ }
+ #parseLinearization(isLinearized) {
+ return this.l10n.get(isLinearized ? "pdfjs-document-properties-linearized-yes" : "pdfjs-document-properties-linearized-no");
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.regexp.escape.js
+var es_regexp_escape = __webpack_require__(6069);
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.typed-array.with.js
+var es_typed_array_with = __webpack_require__(9577);
+;// ./web/pdf_find_utils.js
+
+
+let wordSegmenter = null;
+let graphemeSegmenter = null;
+function isWordBreakAt(content, pos) {
+ graphemeSegmenter ||= new Intl.Segmenter(undefined, {
+ granularity: "grapheme"
+ });
+ const graphemes = graphemeSegmenter.segment(content);
+ const after = graphemes.containing(pos);
+ if (after.index !== pos) {
+ return false;
+ }
+ wordSegmenter ||= new Intl.Segmenter(undefined, {
+ granularity: "word"
+ });
+ const before = graphemes.containing(pos - 1).segment;
+ return wordSegmenter.segment(before + after.segment).containing(before.length).index === before.length;
+}
+function isEntireWord(content, startIdx, length) {
+ const endIdx = startIdx + length;
+ return (startIdx === 0 || isWordBreakAt(content, startIdx)) && (endIdx === content.length || isWordBreakAt(content, endIdx));
+}
+let NormalizeWithNFKC;
+function getNormalizeWithNFKC() {
+ if (!NormalizeWithNFKC) {
+ const ranges = [];
+ const range = [];
+ const diacriticsRegex = /^\p{M}$/u;
+ for (let i = 0; i < 65536; i++) {
+ if (i >= 0xd800 && i <= 0xdfff) {
+ continue;
+ }
+ const c = String.fromCharCode(i);
+ if (c.normalize("NFKC") !== c && !diacriticsRegex.test(c)) {
+ if (range.length !== 2) {
+ range[0] = range[1] = i;
+ continue;
+ }
+ if (range[1] + 1 !== i) {
+ if (range[0] === range[1]) {
+ ranges.push(String.fromCharCode(range[0]));
+ } else {
+ ranges.push(`${String.fromCharCode(range[0])}-${String.fromCharCode(range[1])}`);
+ }
+ range[0] = range[1] = i;
+ } else {
+ range[1] = i;
+ }
+ }
+ }
+ const rangesStr = ranges.join("");
+ if (!NormalizeWithNFKC) {
+ NormalizeWithNFKC = rangesStr;
+ } else if (rangesStr !== NormalizeWithNFKC) {
+ for (let i = 1; i < rangesStr.length; i++) {
+ if (rangesStr[i] !== NormalizeWithNFKC[i]) {
+ console.log(`Difference at index ${i}: ` + `U+${rangesStr.charCodeAt(i).toString(16).toUpperCase().padStart(4, "0")}` + `!== U+${NormalizeWithNFKC.charCodeAt(i).toString(16).toUpperCase().padStart(4, "0")}`);
+ break;
+ }
+ }
+ throw new Error("getNormalizeWithNFKC - update the `NormalizeWithNFKC` string.");
+ }
+ }
+ return NormalizeWithNFKC;
+}
+
+;// ./web/pdf_find_controller.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const FindState = {
+ FOUND: 0,
+ NOT_FOUND: 1,
+ WRAPPED: 2,
+ PENDING: 3
+};
+const CHARACTERS_TO_NORMALIZE = new Map([["\u2010", "-"], ["\u2018", "'"], ["\u2019", "'"], ["\u201A", "'"], ["\u201B", "'"], ["\u201C", '"'], ["\u201D", '"'], ["\u201E", '"'], ["\u201F", '"'], ["\u00BC", "1/4"], ["\u00BD", "1/2"], ["\u00BE", "3/4"]]);
+const DIACRITICS_EXCEPTION = new Set([0x3099, 0x309a, 0x094d, 0x09cd, 0x0a4d, 0x0acd, 0x0b4d, 0x0bcd, 0x0c4d, 0x0ccd, 0x0d3b, 0x0d3c, 0x0d4d, 0x0dca, 0x0e3a, 0x0eba, 0x0f84, 0x1039, 0x103a, 0x1714, 0x1734, 0x17d2, 0x1a60, 0x1b44, 0x1baa, 0x1bab, 0x1bf2, 0x1bf3, 0x2d7f, 0xa806, 0xa82c, 0xa8c4, 0xa953, 0xa9c0, 0xaaf6, 0xabed, 0x0c56, 0x0f71, 0x0f72, 0x0f7a, 0x0f7b, 0x0f7c, 0x0f7d, 0x0f80, 0x0f74]);
+let DIACRITICS_EXCEPTION_STR;
+const DIACRITICS_REG_EXP = /\p{M}+/gu;
+const SPECIAL_CHARS_REG_EXP = /([+^$|])|(\p{P}+)|(\s+)|(\p{M})|(\p{L})/gu;
+const SYLLABLES_REG_EXP = /[\uAC00-\uD7AF\uFA6C\uFACF-\uFAD1\uFAD5-\uFAD7]+/g;
+const SYLLABLES_LENGTHS = new Map();
+const FIRST_CHAR_SYLLABLES_REG_EXP = "[\\u1100-\\u1112\\ud7a4-\\ud7af\\ud84a\\ud84c\\ud850\\ud854\\ud857\\ud85f]";
+const NFKC_CHARS_TO_NORMALIZE = new Map();
+let noSyllablesRegExp = null;
+let withSyllablesRegExp = null;
+function normalize(text, options = {}) {
+ const syllablePositions = [];
+ let m;
+ while ((m = SYLLABLES_REG_EXP.exec(text)) !== null) {
+ let {
+ index
+ } = m;
+ for (const char of m[0]) {
+ let len = SYLLABLES_LENGTHS.get(char);
+ if (!len) {
+ len = char.normalize("NFD").length;
+ SYLLABLES_LENGTHS.set(char, len);
+ }
+ syllablePositions.push([len, index++]);
+ }
+ }
+ const hasSyllables = syllablePositions.length > 0;
+ const ignoreDashEOL = options.ignoreDashEOL ?? false;
+ let normalizationRegex;
+ if (!hasSyllables && noSyllablesRegExp) {
+ normalizationRegex = noSyllablesRegExp;
+ } else if (hasSyllables && withSyllablesRegExp) {
+ normalizationRegex = withSyllablesRegExp;
+ } else {
+ const replace = CHARACTERS_TO_NORMALIZE.keys().join("");
+ const toNormalizeWithNFKC = getNormalizeWithNFKC();
+ const CJK = "(?:\\p{Ideographic}|[\u3040-\u30FF])";
+ const HKDiacritics = "(?:\u3099|\u309A)";
+ const BrokenWord = `\\p{Ll}-\\n(?=\\p{Ll})|\\p{Lu}-\\n(?=\\p{L})`;
+ const regexps = [`[${replace}]`, `[${toNormalizeWithNFKC}]`, `${HKDiacritics}\\n`, "\\p{M}+(?:-\\n)?", `${BrokenWord}`, "\\S-\\n", `${CJK}\\n`, "\\n", hasSyllables ? FIRST_CHAR_SYLLABLES_REG_EXP : "\\u0000"];
+ normalizationRegex = new RegExp(regexps.map(r => `(${r})`).join("|"), "gmu");
+ if (hasSyllables) {
+ withSyllablesRegExp = normalizationRegex;
+ } else {
+ noSyllablesRegExp = normalizationRegex;
+ }
+ }
+ const rawDiacriticsPositions = [];
+ while ((m = DIACRITICS_REG_EXP.exec(text)) !== null) {
+ rawDiacriticsPositions.push([m[0].length, m.index]);
+ }
+ let normalized = text.normalize("NFD");
+ const positions = [0, 0];
+ let rawDiacriticsIndex = 0;
+ let syllableIndex = 0;
+ let shift = 0;
+ let shiftOrigin = 0;
+ let eol = 0;
+ let hasDiacritics = false;
+ normalized = normalized.replace(normalizationRegex, (match, p1, p2, p3, p4, p5, p6, p7, p8, p9, i) => {
+ i -= shiftOrigin;
+ if (p1) {
+ const replacement = CHARACTERS_TO_NORMALIZE.get(p1);
+ const jj = replacement.length;
+ for (let j = 1; j < jj; j++) {
+ positions.push(i - shift + j, shift - j);
+ }
+ shift -= jj - 1;
+ return replacement;
+ }
+ if (p2) {
+ const replacement = NFKC_CHARS_TO_NORMALIZE.getOrInsertComputed(p2, () => p2.normalize("NFKC"));
+ const jj = replacement.length;
+ for (let j = 1; j < jj; j++) {
+ positions.push(i - shift + j, shift - j);
+ }
+ shift -= jj - 1;
+ return replacement;
+ }
+ if (p3) {
+ hasDiacritics = true;
+ if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) {
+ ++rawDiacriticsIndex;
+ } else {
+ positions.push(i - 1 - shift + 1, shift - 1);
+ shift -= 1;
+ shiftOrigin += 1;
+ }
+ positions.push(i - shift + 1, shift);
+ shiftOrigin += 1;
+ eol += 1;
+ return p3.charAt(0);
+ }
+ if (p4) {
+ const hasTrailingDashEOL = p4.endsWith("\n");
+ const len = hasTrailingDashEOL ? p4.length - 2 : p4.length;
+ hasDiacritics = true;
+ let jj = len;
+ if (i + eol === rawDiacriticsPositions[rawDiacriticsIndex]?.[1]) {
+ jj -= rawDiacriticsPositions[rawDiacriticsIndex][0];
+ ++rawDiacriticsIndex;
+ }
+ for (let j = 1; j <= jj; j++) {
+ positions.push(i - 1 - shift + j, shift - j);
+ }
+ shift -= jj;
+ shiftOrigin += jj;
+ if (hasTrailingDashEOL) {
+ i += len - 1;
+ positions.push(i - shift + 1, 1 + shift);
+ shift += 1;
+ shiftOrigin += 1;
+ eol += 1;
+ return p4.slice(0, len);
+ }
+ return p4;
+ }
+ if (p5) {
+ if (ignoreDashEOL) {
+ shiftOrigin += 1;
+ eol += 1;
+ return p5.slice(0, -1);
+ }
+ const len = p5.length - 2;
+ positions.push(i - shift + len, 1 + shift);
+ shift += 1;
+ shiftOrigin += 1;
+ eol += 1;
+ return p5.slice(0, -2);
+ }
+ if (p6) {
+ shiftOrigin += 1;
+ eol += 1;
+ return p6.slice(0, -1);
+ }
+ if (p7) {
+ const len = p7.length - 1;
+ positions.push(i - shift + len, shift);
+ shiftOrigin += 1;
+ eol += 1;
+ return p7.slice(0, -1);
+ }
+ if (p8) {
+ positions.push(i - shift + 1, shift - 1);
+ shift -= 1;
+ shiftOrigin += 1;
+ eol += 1;
+ return " ";
+ }
+ if (i + eol === syllablePositions[syllableIndex]?.[1]) {
+ const newCharLen = syllablePositions[syllableIndex][0] - 1;
+ ++syllableIndex;
+ for (let j = 1; j <= newCharLen; j++) {
+ positions.push(i - (shift - j), shift - j);
+ }
+ shift -= newCharLen;
+ shiftOrigin += newCharLen;
+ }
+ return p9;
+ });
+ positions.push(normalized.length, shift);
+ const starts = new Uint32Array(positions.length >> 1);
+ const shifts = new Int32Array(positions.length >> 1);
+ for (let i = 0, ii = positions.length; i < ii; i += 2) {
+ starts[i >> 1] = positions[i];
+ shifts[i >> 1] = positions[i + 1];
+ }
+ return [normalized, [starts, shifts], hasDiacritics];
+}
+function getOriginalIndex(diffs, pos, len) {
+ if (!diffs) {
+ return [pos, len];
+ }
+ const [starts, shifts] = diffs;
+ const start = pos;
+ const end = pos + len - 1;
+ let i = binarySearchFirstItem(starts, x => x >= start);
+ if (starts[i] > start) {
+ --i;
+ }
+ let j = binarySearchFirstItem(starts, x => x >= end, i);
+ if (starts[j] > end) {
+ --j;
+ }
+ const oldStart = start + shifts[i];
+ const oldEnd = end + shifts[j];
+ const oldLen = oldEnd + 1 - oldStart;
+ return [oldStart, oldLen];
+}
+class PDFFindController {
+ #state = null;
+ #updateMatchesCountOnProgress = true;
+ #delay = 0;
+ #visitedPagesCount = 0;
+ #copiedPageData = null;
+ #savedPageData = null;
+ constructor({
+ linkService,
+ eventBus,
+ delay = 250,
+ updateMatchesCountOnProgress = true
+ }) {
+ this._linkService = linkService;
+ this._eventBus = eventBus;
+ this.#updateMatchesCountOnProgress = updateMatchesCountOnProgress;
+ this.#delay = delay;
+ this.onIsPageVisible = null;
+ this.#reset();
+ eventBus.on("find", this.#onFind.bind(this), internalOpt);
+ eventBus.on("findbarclose", this.#onFindBarClose.bind(this), internalOpt);
+ eventBus.on("pagesedited", this.#onPagesEdited.bind(this), internalOpt);
+ }
+ get highlightMatches() {
+ return this._highlightMatches;
+ }
+ get pageMatches() {
+ return this._pageMatches;
+ }
+ get pageMatchesLength() {
+ return this._pageMatchesLength;
+ }
+ get selected() {
+ return this._selected;
+ }
+ get state() {
+ return this.#state;
+ }
+ setDocument(pdfDocument) {
+ if (this._pdfDocument) {
+ this.#reset();
+ }
+ if (!pdfDocument) {
+ return;
+ }
+ this._pdfDocument = pdfDocument;
+ this._firstPageCapability.resolve();
+ }
+ #onFind(state) {
+ if (!state) {
+ return;
+ }
+ const pdfDocument = this._pdfDocument;
+ const {
+ type
+ } = state;
+ if (this.#state === null || this.#shouldDirtyMatch(state)) {
+ this._dirtyMatch = true;
+ }
+ this.#state = state;
+ if (type !== "highlightallchange") {
+ this.#updateUIState(FindState.PENDING);
+ }
+ this._firstPageCapability.promise.then(() => {
+ if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) {
+ return;
+ }
+ this.#extractText();
+ const findbarClosed = !this._highlightMatches;
+ const pendingTimeout = !!this._findTimeout;
+ if (this._findTimeout) {
+ clearTimeout(this._findTimeout);
+ this._findTimeout = null;
+ }
+ if (!type) {
+ this._findTimeout = setTimeout(() => {
+ this.#nextMatch();
+ this._findTimeout = null;
+ }, this.#delay);
+ } else if (this._dirtyMatch) {
+ this.#nextMatch();
+ } else if (type === "again") {
+ this.#nextMatch();
+ if (findbarClosed && this.#state.highlightAll) {
+ this.#updateAllPages();
+ }
+ } else if (type === "highlightallchange") {
+ if (pendingTimeout) {
+ this.#nextMatch();
+ } else {
+ this._highlightMatches = true;
+ }
+ this.#updateAllPages();
+ } else {
+ this.#nextMatch();
+ }
+ });
+ }
+ scrollMatchIntoView({
+ element = null,
+ pageIndex = -1,
+ matchIndex = -1
+ }) {
+ if (!this._scrollMatches || !element) {
+ return;
+ } else if (matchIndex === -1 || matchIndex !== this._selected.matchIdx) {
+ return;
+ } else if (pageIndex === -1 || pageIndex !== this._selected.pageIdx) {
+ return;
+ }
+ this._scrollMatches = false;
+ element.scrollIntoView({
+ block: "start",
+ inline: "center"
+ });
+ }
+ #reset() {
+ this._highlightMatches = false;
+ this._scrollMatches = false;
+ this._pdfDocument = null;
+ this._pageMatches = [];
+ this._pageMatchesLength = [];
+ this.#visitedPagesCount = 0;
+ this.#state = null;
+ this._selected = {
+ pageIdx: -1,
+ matchIdx: -1
+ };
+ this._offset = {
+ pageIdx: null,
+ matchIdx: null,
+ wrapped: false
+ };
+ this._extractTextPromises = [];
+ this._pageContents = [];
+ this._pageDiffs = [];
+ this._hasDiacritics = [];
+ this._matchesCountTotal = 0;
+ this._pagesToSearch = null;
+ this._pendingFindMatches = new Set();
+ this._resumePageIdx = null;
+ this._dirtyMatch = false;
+ clearTimeout(this._findTimeout);
+ this._findTimeout = null;
+ this.#copiedPageData = null;
+ this._firstPageCapability = Promise.withResolvers();
+ }
+ get #query() {
+ const {
+ query
+ } = this.#state;
+ if (typeof query === "string") {
+ if (query !== this._rawQuery) {
+ this._rawQuery = query;
+ [this._normalizedQuery] = normalize(query);
+ }
+ return this._normalizedQuery;
+ }
+ return (query || []).filter(Boolean).map(q => normalize(q)[0]);
+ }
+ #shouldDirtyMatch(state) {
+ const newQuery = state.query,
+ prevQuery = this.#state.query;
+ const newType = typeof newQuery,
+ prevType = typeof prevQuery;
+ if (newType !== prevType) {
+ return true;
+ }
+ if (newType === "string") {
+ if (newQuery !== prevQuery) {
+ return true;
+ }
+ } else if (JSON.stringify(newQuery) !== JSON.stringify(prevQuery)) {
+ return true;
+ }
+ switch (state.type) {
+ case "again":
+ const pageNumber = this._selected.pageIdx + 1;
+ const linkService = this._linkService;
+ return pageNumber >= 1 && pageNumber <= linkService.pagesCount && pageNumber !== linkService.page && !(this.onIsPageVisible?.(pageNumber) ?? true);
+ case "highlightallchange":
+ return false;
+ }
+ return true;
+ }
+ #convertToRegExpString(query, hasDiacritics) {
+ const {
+ matchDiacritics
+ } = this.#state;
+ let isUnicode = false;
+ const addExtraWhitespaces = (original, fixed) => {
+ if (original === query) {
+ return fixed;
+ }
+ if (query.startsWith(original)) {
+ return `${fixed}[ ]*`;
+ }
+ if (query.endsWith(original)) {
+ return `[ ]*${fixed}`;
+ }
+ return `[ ]*${fixed}[ ]*`;
+ };
+ query = query.replaceAll(SPECIAL_CHARS_REG_EXP, (match, p1, p2, p3, p4, p5) => {
+ if (p1) {
+ return addExtraWhitespaces(p1, RegExp.escape(p1));
+ }
+ if (p2) {
+ return addExtraWhitespaces(p2, RegExp.escape(p2));
+ }
+ if (p3) {
+ return "[ ]+";
+ }
+ if (matchDiacritics) {
+ return p4 || p5;
+ }
+ if (p4) {
+ return DIACRITICS_EXCEPTION.has(p4.charCodeAt(0)) ? p4 : "";
+ }
+ if (hasDiacritics) {
+ isUnicode = true;
+ return `${p5}\\p{M}*`;
+ }
+ return p5;
+ });
+ const trailingSpaces = "[ ]*";
+ if (query.endsWith(trailingSpaces)) {
+ query = query.slice(0, query.length - trailingSpaces.length);
+ }
+ if (matchDiacritics) {
+ if (hasDiacritics) {
+ DIACRITICS_EXCEPTION_STR ||= String.fromCharCode(...DIACRITICS_EXCEPTION);
+ isUnicode = true;
+ query = `${query}(?=[${DIACRITICS_EXCEPTION_STR}]|[^\\p{M}]|$)`;
+ }
+ }
+ return [isUnicode, query];
+ }
+ #calculateMatch(pageIndex) {
+ if (!this.#state) {
+ return;
+ }
+ const query = this.#query;
+ if (query.length === 0) {
+ return;
+ }
+ const pageContent = this._pageContents[pageIndex];
+ const matcherResult = this.match(query, pageContent, pageIndex);
+ const matches = this._pageMatches[pageIndex] = [];
+ const matchesLength = this._pageMatchesLength[pageIndex] = [];
+ const diffs = this._pageDiffs[pageIndex];
+ matcherResult?.forEach(({
+ index,
+ length
+ }) => {
+ const [matchPos, matchLen] = getOriginalIndex(diffs, index, length);
+ if (matchLen) {
+ matches.push(matchPos);
+ matchesLength.push(matchLen);
+ }
+ });
+ if (this.#state.highlightAll) {
+ this.#updatePage(pageIndex);
+ }
+ if (this._resumePageIdx === pageIndex) {
+ this._resumePageIdx = null;
+ this.#nextPageMatch();
+ }
+ const pageMatchesCount = matches.length;
+ this._matchesCountTotal += pageMatchesCount;
+ if (this.#updateMatchesCountOnProgress) {
+ if (pageMatchesCount > 0) {
+ this.#updateUIResultsCount();
+ }
+ } else if (++this.#visitedPagesCount === this._linkService.pagesCount) {
+ this.#updateUIResultsCount();
+ }
+ }
+ match(query, pageContent, pageIndex) {
+ const hasDiacritics = this._hasDiacritics[pageIndex];
+ let isUnicode = false;
+ if (typeof query === "string") {
+ [isUnicode, query] = this.#convertToRegExpString(query, hasDiacritics);
+ } else {
+ query = query.sort().reverse().map(q => {
+ const [isUnicodePart, queryPart] = this.#convertToRegExpString(q, hasDiacritics);
+ isUnicode ||= isUnicodePart;
+ return `(${queryPart})`;
+ }).join("|");
+ }
+ if (!query) {
+ return undefined;
+ }
+ const {
+ caseSensitive,
+ entireWord
+ } = this.#state;
+ const flags = `g${isUnicode ? "u" : ""}${caseSensitive ? "" : "i"}`;
+ query = new RegExp(query, flags);
+ const matches = [];
+ let match;
+ while ((match = query.exec(pageContent)) !== null) {
+ if (entireWord && !isEntireWord(pageContent, match.index, match[0].length)) {
+ continue;
+ }
+ matches.push({
+ index: match.index,
+ length: match[0].length
+ });
+ }
+ return matches;
+ }
+ #extractText() {
+ if (this._extractTextPromises.length > 0) {
+ return;
+ }
+ let deferred = Promise.resolve();
+ const textOptions = {
+ disableNormalization: true
+ };
+ const pdfDoc = this._pdfDocument;
+ for (let i = 0, ii = this._linkService.pagesCount; i < ii; i++) {
+ const {
+ promise,
+ resolve
+ } = Promise.withResolvers();
+ this._extractTextPromises[i] = promise;
+ deferred = deferred.then(async () => {
+ if (pdfDoc !== this._pdfDocument) {
+ resolve();
+ return;
+ }
+ try {
+ const pdfPage = await pdfDoc.getPage(i + 1);
+ const textContent = await pdfPage.getTextContent(textOptions);
+ if (pdfDoc !== this._pdfDocument) {
+ resolve();
+ return;
+ }
+ const strBuf = [];
+ for (const textItem of textContent.items) {
+ strBuf.push(textItem.str);
+ if (textItem.hasEOL) {
+ strBuf.push("\n");
+ }
+ }
+ [this._pageContents[i], this._pageDiffs[i], this._hasDiacritics[i]] = normalize(strBuf.join(""));
+ } catch (ex) {
+ if (pdfDoc !== this._pdfDocument) {
+ resolve();
+ return;
+ }
+ console.error(`Unable to get text content for page ${i + 1}`, ex);
+ [this._pageContents[i], this._pageDiffs[i], this._hasDiacritics[i]] = ["", null, false];
+ }
+ resolve();
+ });
+ }
+ }
+ #updatePage(index) {
+ if (this._scrollMatches && this._selected.pageIdx === index) {
+ this._linkService.page = index + 1;
+ }
+ this._eventBus.dispatch("updatetextlayermatches", {
+ source: this,
+ pageIndex: index
+ });
+ }
+ #updateAllPages() {
+ this._eventBus.dispatch("updatetextlayermatches", {
+ source: this,
+ pageIndex: -1
+ });
+ }
+ #nextMatch() {
+ const previous = this.#state.findPrevious;
+ const currentPageIndex = this._linkService.page - 1;
+ const numPages = this._linkService.pagesCount;
+ this._highlightMatches = true;
+ if (this._dirtyMatch) {
+ this._dirtyMatch = false;
+ this._selected.pageIdx = this._selected.matchIdx = -1;
+ this._offset.pageIdx = currentPageIndex;
+ this._offset.matchIdx = null;
+ this._offset.wrapped = false;
+ this._resumePageIdx = null;
+ this._pageMatches.length = 0;
+ this._pageMatchesLength.length = 0;
+ this.#visitedPagesCount = 0;
+ this._matchesCountTotal = 0;
+ this.#updateAllPages();
+ for (let i = 0; i < numPages; i++) {
+ if (this._pendingFindMatches.has(i)) {
+ continue;
+ }
+ this._pendingFindMatches.add(i);
+ this._extractTextPromises[i].then(() => {
+ this._pendingFindMatches.delete(i);
+ this.#calculateMatch(i);
+ });
+ }
+ }
+ const query = this.#query;
+ if (query.length === 0) {
+ this.#updateUIState(FindState.FOUND);
+ return;
+ }
+ if (this._resumePageIdx) {
+ return;
+ }
+ const offset = this._offset;
+ this._pagesToSearch = numPages;
+ if (offset.matchIdx !== null) {
+ const numPageMatches = this._pageMatches[offset.pageIdx].length;
+ if (!previous && offset.matchIdx + 1 < numPageMatches || previous && offset.matchIdx > 0) {
+ offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
+ this.#updateMatch(true);
+ return;
+ }
+ this.#advanceOffsetPage(previous);
+ }
+ this.#nextPageMatch();
+ }
+ #matchesReady(matches) {
+ const offset = this._offset;
+ const numMatches = matches.length;
+ const previous = this.#state.findPrevious;
+ if (numMatches) {
+ offset.matchIdx = previous ? numMatches - 1 : 0;
+ this.#updateMatch(true);
+ return true;
+ }
+ this.#advanceOffsetPage(previous);
+ if (offset.wrapped) {
+ offset.matchIdx = null;
+ if (this._pagesToSearch < 0) {
+ this.#updateMatch(false);
+ return true;
+ }
+ }
+ return false;
+ }
+ #nextPageMatch() {
+ if (this._resumePageIdx !== null) {
+ console.error("There can only be one pending page.");
+ }
+ let matches = null;
+ do {
+ const pageIdx = this._offset.pageIdx;
+ matches = this._pageMatches[pageIdx];
+ if (!matches) {
+ this._resumePageIdx = pageIdx;
+ break;
+ }
+ } while (!this.#matchesReady(matches));
+ }
+ #advanceOffsetPage(previous) {
+ const offset = this._offset;
+ const numPages = this._linkService.pagesCount;
+ offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
+ offset.matchIdx = null;
+ this._pagesToSearch--;
+ if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
+ offset.pageIdx = previous ? numPages - 1 : 0;
+ offset.wrapped = true;
+ }
+ }
+ #updateMatch(found = false) {
+ let state = FindState.NOT_FOUND;
+ const wrapped = this._offset.wrapped;
+ this._offset.wrapped = false;
+ if (found) {
+ const previousPage = this._selected.pageIdx;
+ this._selected.pageIdx = this._offset.pageIdx;
+ this._selected.matchIdx = this._offset.matchIdx;
+ state = wrapped ? FindState.WRAPPED : FindState.FOUND;
+ if (previousPage !== -1 && previousPage !== this._selected.pageIdx) {
+ this.#updatePage(previousPage);
+ }
+ }
+ this.#updateUIState(state, this.#state.findPrevious);
+ if (this._selected.pageIdx !== -1) {
+ this._scrollMatches = true;
+ this.#updatePage(this._selected.pageIdx);
+ }
+ }
+ #onPagesEdited({
+ pagesMapper,
+ type,
+ pageNumbers
+ }) {
+ if (this._extractTextPromises.length === 0) {
+ return;
+ }
+ if (type === "copy") {
+ const promises = new Map();
+ const contents = new Map();
+ const diffs = new Map();
+ const diacritics = new Map();
+ for (const pageNum of pageNumbers) {
+ promises.set(pageNum, this._extractTextPromises[pageNum - 1]);
+ contents.set(pageNum, this._pageContents[pageNum - 1]);
+ diffs.set(pageNum, this._pageDiffs[pageNum - 1]);
+ diacritics.set(pageNum, this._hasDiacritics[pageNum - 1]);
+ }
+ this.#copiedPageData = {
+ promises,
+ contents,
+ diffs,
+ diacritics
+ };
+ return;
+ }
+ if (type === "cancelCopy") {
+ this.#copiedPageData = null;
+ return;
+ }
+ if (type === "delete") {
+ this.#savedPageData = {
+ promises: this._extractTextPromises,
+ contents: this._pageContents,
+ diffs: this._pageDiffs,
+ diacritics: this._hasDiacritics
+ };
+ }
+ if (type === "cancelDelete") {
+ this._extractTextPromises = this.#savedPageData.promises;
+ this._pageContents = this.#savedPageData.contents;
+ this._pageDiffs = this.#savedPageData.diffs;
+ this._hasDiacritics = this.#savedPageData.diacritics;
+ return;
+ }
+ if (type === "cleanSavedData") {
+ this.#savedPageData = null;
+ return;
+ }
+ if (this._findTimeout) {
+ clearTimeout(this._findTimeout);
+ this._findTimeout = null;
+ }
+ this._resumePageIdx = null;
+ this._dirtyMatch = true;
+ const prevPromises = this._extractTextPromises;
+ const prevContents = this._pageContents;
+ const prevDiffs = this._pageDiffs;
+ const prevDiacritics = this._hasDiacritics;
+ const extractTextPromises = this._extractTextPromises = [];
+ const pageContents = this._pageContents = [];
+ const pageDiffs = this._pageDiffs = [];
+ const hasDiacritics = this._hasDiacritics = [];
+ for (let i = 1, ii = pagesMapper.pagesNumber; i <= ii; i++) {
+ const prevPageNumber = pagesMapper.getPrevPageNumber(i);
+ if (prevPageNumber < 0) {
+ const src = -prevPageNumber;
+ extractTextPromises.push(this.#copiedPageData?.promises.get(src) || Promise.resolve());
+ pageContents.push(this.#copiedPageData?.contents.get(src) ?? "");
+ pageDiffs.push(this.#copiedPageData?.diffs.get(src) ?? null);
+ hasDiacritics.push(this.#copiedPageData?.diacritics.get(src) ?? false);
+ continue;
+ }
+ extractTextPromises.push(prevPromises[prevPageNumber - 1] || Promise.resolve());
+ pageContents.push(prevContents[prevPageNumber - 1] ?? "");
+ pageDiffs.push(prevDiffs[prevPageNumber - 1] ?? null);
+ hasDiacritics.push(prevDiacritics[prevPageNumber - 1] ?? false);
+ }
+ if (this.#state) {
+ this.#nextMatch();
+ }
+ }
+ #onFindBarClose(evt) {
+ const pdfDocument = this._pdfDocument;
+ this._firstPageCapability.promise.then(() => {
+ if (!this._pdfDocument || pdfDocument && this._pdfDocument !== pdfDocument) {
+ return;
+ }
+ if (this._findTimeout) {
+ clearTimeout(this._findTimeout);
+ this._findTimeout = null;
+ }
+ if (this._resumePageIdx) {
+ this._resumePageIdx = null;
+ this._dirtyMatch = true;
+ }
+ this.#updateUIState(FindState.FOUND);
+ this._highlightMatches = false;
+ this.#updateAllPages();
+ });
+ }
+ #requestMatchesCount() {
+ const {
+ pageIdx,
+ matchIdx
+ } = this._selected;
+ let current = 0,
+ total = this._matchesCountTotal;
+ if (matchIdx !== -1) {
+ for (let i = 0; i < pageIdx; i++) {
+ current += this._pageMatches[i]?.length || 0;
+ }
+ current += matchIdx + 1;
+ }
+ if (current < 1 || current > total) {
+ current = total = 0;
+ }
+ return {
+ current,
+ total
+ };
+ }
+ #updateUIResultsCount() {
+ this._eventBus.dispatch("updatefindmatchescount", {
+ source: this,
+ matchesCount: this.#requestMatchesCount()
+ });
+ }
+ #updateUIState(state, previous = false) {
+ if (!this.#updateMatchesCountOnProgress && (this.#visitedPagesCount !== this._linkService.pagesCount || state === FindState.PENDING)) {
+ return;
+ }
+ this._eventBus.dispatch("updatefindcontrolstate", {
+ source: this,
+ state,
+ previous,
+ entireWord: this.#state?.entireWord ?? null,
+ matchesCount: this.#requestMatchesCount(),
+ rawQuery: this.#state?.query ?? null
+ });
+ }
+}
+
+;// ./web/pdf_find_bar.js
+
+
+
+
+
+const MATCHES_COUNT_LIMIT = 1000;
+class PDFFindBar {
+ #mainContainer;
+ #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this));
+ opened = false;
+ constructor(options, mainContainer, eventBus) {
+ this.bar = options.bar;
+ this.toggleButton = options.toggleButton;
+ this.findField = options.findField;
+ this.highlightAll = options.highlightAllCheckbox;
+ this.caseSensitive = options.caseSensitiveCheckbox;
+ this.matchDiacritics = options.matchDiacriticsCheckbox;
+ this.entireWord = options.entireWordCheckbox;
+ this.findMsg = options.findMsg;
+ this.findResultsCount = options.findResultsCount;
+ this.findPreviousButton = options.findPreviousButton;
+ this.findNextButton = options.findNextButton;
+ this.eventBus = eventBus;
+ this.#mainContainer = mainContainer;
+ const checkedInputs = new Map([[this.highlightAll, "highlightallchange"], [this.caseSensitive, "casesensitivitychange"], [this.entireWord, "entirewordchange"], [this.matchDiacritics, "diacriticmatchingchange"]]);
+ this.toggleButton.addEventListener("click", () => {
+ this.toggle();
+ });
+ this.findField.addEventListener("input", () => {
+ this.dispatchEvent("");
+ });
+ this.bar.addEventListener("keydown", ({
+ keyCode,
+ shiftKey,
+ target
+ }) => {
+ switch (keyCode) {
+ case 13:
+ if (target === this.findField) {
+ this.dispatchEvent("again", shiftKey);
+ } else if (checkedInputs.has(target)) {
+ target.checked = !target.checked;
+ this.dispatchEvent(checkedInputs.get(target));
+ }
+ break;
+ case 27:
+ this.close();
+ break;
+ }
+ });
+ this.findPreviousButton.addEventListener("click", () => {
+ this.dispatchEvent("again", true);
+ });
+ this.findNextButton.addEventListener("click", () => {
+ this.dispatchEvent("again", false);
+ });
+ for (const [elem, evtName] of checkedInputs) {
+ elem.addEventListener("click", () => {
+ this.dispatchEvent(evtName);
+ });
+ }
+ }
+ reset() {
+ this.updateUIState();
+ }
+ dispatchEvent(type, findPrev = false) {
+ this.eventBus.dispatch("find", {
+ source: this,
+ type,
+ query: this.findField.value,
+ caseSensitive: this.caseSensitive.checked,
+ entireWord: this.entireWord.checked,
+ highlightAll: this.highlightAll.checked,
+ findPrevious: findPrev,
+ matchDiacritics: this.matchDiacritics.checked
+ });
+ }
+ updateUIState(state, previous, matchesCount) {
+ const {
+ findField,
+ findMsg
+ } = this;
+ let findMsgId = "",
+ status = "";
+ switch (state) {
+ case FindState.FOUND:
+ break;
+ case FindState.PENDING:
+ status = "pending";
+ break;
+ case FindState.NOT_FOUND:
+ findMsgId = "pdfjs-find-not-found";
+ status = "notFound";
+ break;
+ case FindState.WRAPPED:
+ findMsgId = previous ? "pdfjs-find-reached-top" : "pdfjs-find-reached-bottom";
+ break;
+ }
+ findField.setAttribute("data-status", status);
+ findField.setAttribute("aria-invalid", state === FindState.NOT_FOUND);
+ findMsg.setAttribute("data-status", status);
+ if (findMsgId) {
+ findMsg.setAttribute("data-l10n-id", findMsgId);
+ } else {
+ findMsg.removeAttribute("data-l10n-id");
+ findMsg.textContent = "";
+ }
+ this.updateResultsCount(matchesCount);
+ }
+ updateResultsCount({
+ current = 0,
+ total = 0
+ } = {}) {
+ const {
+ findResultsCount
+ } = this;
+ if (total > 0) {
+ const limit = MATCHES_COUNT_LIMIT;
+ findResultsCount.setAttribute("data-l10n-id", total > limit ? "pdfjs-find-match-count-limit" : "pdfjs-find-match-count");
+ findResultsCount.setAttribute("data-l10n-args", JSON.stringify({
+ limit,
+ current,
+ total
+ }));
+ } else {
+ findResultsCount.removeAttribute("data-l10n-id");
+ findResultsCount.textContent = "";
+ }
+ }
+ open() {
+ if (!this.opened) {
+ this.#resizeObserver.observe(this.#mainContainer);
+ this.#resizeObserver.observe(this.bar);
+ this.opened = true;
+ toggleExpandedBtn(this.toggleButton, true, this.bar);
+ }
+ this.findField.select();
+ this.findField.focus();
+ }
+ close() {
+ if (!this.opened) {
+ return;
+ }
+ this.#resizeObserver.disconnect();
+ this.opened = false;
+ toggleExpandedBtn(this.toggleButton, false, this.bar);
+ this.eventBus.dispatch("findbarclose", {
+ source: this
+ });
+ }
+ toggle() {
+ if (this.opened) {
+ this.close();
+ } else {
+ this.open();
+ }
+ }
+ #resizeObserverCallback() {
+ const {
+ bar
+ } = this;
+ bar.classList.remove("wrapContainers");
+ const findbarHeight = bar.clientHeight;
+ const inputContainerHeight = bar.firstElementChild.clientHeight;
+ if (findbarHeight > inputContainerHeight) {
+ bar.classList.add("wrapContainers");
+ }
+ }
+}
+
+;// ./web/pdf_history.js
+
+
+
+
+
+const HASH_CHANGE_TIMEOUT = 1000;
+const POSITION_UPDATED_THRESHOLD = 50;
+const UPDATE_VIEWAREA_TIMEOUT = 1000;
+function getCurrentHash() {
+ return document.location.hash;
+}
+class PDFHistory {
+ #eventAC = null;
+ constructor({
+ linkService,
+ eventBus
+ }) {
+ this.linkService = linkService;
+ this.eventBus = eventBus;
+ this._initialized = false;
+ this._fingerprint = "";
+ this.reset();
+ this.eventBus.on("pagesinit", () => {
+ this._isPagesLoaded = false;
+ this.eventBus.on("pagesloaded", evt => {
+ this._isPagesLoaded = !!evt.pagesCount;
+ }, {
+ once: true,
+ ...internalOpt
+ });
+ }, internalOpt);
+ }
+ initialize({
+ fingerprint,
+ resetHistory = false,
+ updateUrl = false
+ }) {
+ if (!fingerprint || typeof fingerprint !== "string") {
+ console.error('PDFHistory.initialize: The "fingerprint" must be a non-empty string.');
+ return;
+ }
+ if (this._initialized) {
+ this.reset();
+ }
+ const reInitialized = this._fingerprint !== "" && this._fingerprint !== fingerprint;
+ this._fingerprint = fingerprint;
+ this._updateUrl = updateUrl === true;
+ this._initialized = true;
+ this.#bindEvents();
+ const state = window.history.state;
+ this._popStateInProgress = false;
+ this._blockHashChange = 0;
+ this._currentHash = getCurrentHash();
+ this._numPositionUpdates = 0;
+ this._uid = this._maxUid = 0;
+ this._destination = null;
+ this._position = null;
+ if (!this.#isValidState(state, true) || resetHistory) {
+ const {
+ hash,
+ page,
+ rotation
+ } = this.#parseCurrentHash(true);
+ if (!hash || reInitialized || resetHistory) {
+ this.#pushOrReplaceState(null, true);
+ return;
+ }
+ this.#pushOrReplaceState({
+ hash,
+ page,
+ rotation
+ }, true);
+ return;
+ }
+ const destination = state.destination;
+ this.#updateInternalState(destination, state.uid, true);
+ if (destination.rotation !== undefined) {
+ this._initialRotation = destination.rotation;
+ }
+ if (destination.dest) {
+ this._initialBookmark = JSON.stringify(destination.dest);
+ this._destination.page = null;
+ } else if (destination.hash) {
+ this._initialBookmark = destination.hash;
+ } else if (destination.page) {
+ this._initialBookmark = `page=${destination.page}`;
+ }
+ }
+ reset() {
+ if (this._initialized) {
+ this.#pageHide();
+ this._initialized = false;
+ this.#unbindEvents();
+ }
+ if (this._updateViewareaTimeout) {
+ clearTimeout(this._updateViewareaTimeout);
+ this._updateViewareaTimeout = null;
+ }
+ this._initialBookmark = null;
+ this._initialRotation = null;
+ }
+ push({
+ namedDest = null,
+ explicitDest,
+ pageNumber
+ }) {
+ if (!this._initialized) {
+ return;
+ }
+ if (namedDest && typeof namedDest !== "string") {
+ console.error("PDFHistory.push: " + `"${namedDest}" is not a valid namedDest parameter.`);
+ return;
+ } else if (!Array.isArray(explicitDest)) {
+ console.error("PDFHistory.push: " + `"${explicitDest}" is not a valid explicitDest parameter.`);
+ return;
+ } else if (!this.#isValidPage(pageNumber)) {
+ if (pageNumber !== null || this._destination) {
+ console.error("PDFHistory.push: " + `"${pageNumber}" is not a valid pageNumber parameter.`);
+ return;
+ }
+ }
+ const hash = namedDest || JSON.stringify(explicitDest);
+ if (!hash) {
+ return;
+ }
+ let forceReplace = false;
+ if (this._destination && (isDestHashesEqual(this._destination.hash, hash) || isDestArraysEqual(this._destination.dest, explicitDest))) {
+ if (this._destination.page) {
+ return;
+ }
+ forceReplace = true;
+ }
+ if (this._popStateInProgress && !forceReplace) {
+ return;
+ }
+ this.#pushOrReplaceState({
+ dest: explicitDest,
+ hash,
+ page: pageNumber,
+ rotation: this.linkService.rotation
+ }, forceReplace);
+ if (!this._popStateInProgress) {
+ this._popStateInProgress = true;
+ Promise.resolve().then(() => {
+ this._popStateInProgress = false;
+ });
+ }
+ }
+ pushPage(pageNumber) {
+ if (!this._initialized) {
+ return;
+ }
+ if (!this.#isValidPage(pageNumber)) {
+ console.error(`PDFHistory.pushPage: "${pageNumber}" is not a valid page number.`);
+ return;
+ }
+ if (this._destination?.page === pageNumber) {
+ return;
+ }
+ if (this._popStateInProgress) {
+ return;
+ }
+ this.#pushOrReplaceState({
+ dest: null,
+ hash: `page=${pageNumber}`,
+ page: pageNumber,
+ rotation: this.linkService.rotation
+ });
+ if (!this._popStateInProgress) {
+ this._popStateInProgress = true;
+ Promise.resolve().then(() => {
+ this._popStateInProgress = false;
+ });
+ }
+ }
+ pushCurrentPosition() {
+ if (!this._initialized || this._popStateInProgress) {
+ return;
+ }
+ this.#tryPushCurrentPosition();
+ }
+ back() {
+ if (!this._initialized || this._popStateInProgress) {
+ return;
+ }
+ const state = window.history.state;
+ if (this.#isValidState(state) && state.uid > 0) {
+ window.history.back();
+ }
+ }
+ forward() {
+ if (!this._initialized || this._popStateInProgress) {
+ return;
+ }
+ const state = window.history.state;
+ if (this.#isValidState(state) && state.uid < this._maxUid) {
+ window.history.forward();
+ }
+ }
+ get popStateInProgress() {
+ return this._initialized && (this._popStateInProgress || this._blockHashChange > 0);
+ }
+ get initialBookmark() {
+ return this._initialized ? this._initialBookmark : null;
+ }
+ get initialRotation() {
+ return this._initialized ? this._initialRotation : null;
+ }
+ #pushOrReplaceState(destination, forceReplace = false) {
+ const shouldReplace = forceReplace || !this._destination;
+ const newState = {
+ fingerprint: this._fingerprint,
+ uid: shouldReplace ? this._uid : this._uid + 1,
+ destination
+ };
+ this.#updateInternalState(destination, newState.uid);
+ let newUrl;
+ if (this._updateUrl && destination?.hash) {
+ const {
+ href,
+ protocol
+ } = document.location;
+ if (protocol !== "file:") {
+ newUrl = updateUrlHash(href, destination.hash);
+ }
+ }
+ if (shouldReplace) {
+ window.history.replaceState(newState, "", newUrl);
+ } else {
+ window.history.pushState(newState, "", newUrl);
+ }
+ }
+ #tryPushCurrentPosition(temporary = false) {
+ if (!this._position) {
+ return;
+ }
+ let position = this._position;
+ if (temporary) {
+ position = Object.assign(Object.create(null), this._position);
+ position.temporary = true;
+ }
+ if (!this._destination) {
+ this.#pushOrReplaceState(position);
+ return;
+ }
+ if (this._destination.temporary) {
+ this.#pushOrReplaceState(position, true);
+ return;
+ }
+ if (this._destination.hash === position.hash) {
+ return;
+ }
+ if (!this._destination.page && ( false || this._numPositionUpdates <= POSITION_UPDATED_THRESHOLD)) {
+ return;
+ }
+ let forceReplace = false;
+ if (this._destination.page >= position.first && this._destination.page <= position.page) {
+ if (this._destination.dest !== undefined || !this._destination.first) {
+ return;
+ }
+ forceReplace = true;
+ }
+ this.#pushOrReplaceState(position, forceReplace);
+ }
+ #isValidPage(val) {
+ return Number.isInteger(val) && val > 0 && val <= this.linkService.pagesCount;
+ }
+ #isValidState(state, checkReload = false) {
+ if (!state) {
+ return false;
+ }
+ if (state.fingerprint !== this._fingerprint) {
+ if (checkReload) {
+ if (typeof state.fingerprint !== "string" || state.fingerprint.length !== this._fingerprint.length) {
+ return false;
+ }
+ const [perfEntry] = performance.getEntriesByType("navigation");
+ if (perfEntry?.type !== "reload") {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (!Number.isInteger(state.uid) || state.uid < 0) {
+ return false;
+ }
+ if (state.destination === null || typeof state.destination !== "object") {
+ return false;
+ }
+ return true;
+ }
+ #updateInternalState(destination, uid, removeTemporary = false) {
+ if (this._updateViewareaTimeout) {
+ clearTimeout(this._updateViewareaTimeout);
+ this._updateViewareaTimeout = null;
+ }
+ if (removeTemporary && destination?.temporary) {
+ delete destination.temporary;
+ }
+ this._destination = destination;
+ this._uid = uid;
+ this._maxUid = Math.max(this._maxUid, uid);
+ this._numPositionUpdates = 0;
+ }
+ #parseCurrentHash(checkNameddest = false) {
+ const hash = unescape(getCurrentHash()).substring(1);
+ const params = parseQueryString(hash);
+ const nameddest = params.get("nameddest") || "";
+ let page = params.get("page") | 0;
+ if (!this.#isValidPage(page) || checkNameddest && nameddest.length > 0) {
+ page = null;
+ }
+ return {
+ hash,
+ page,
+ rotation: this.linkService.rotation
+ };
+ }
+ #updateViewarea({
+ location
+ }) {
+ if (this._updateViewareaTimeout) {
+ clearTimeout(this._updateViewareaTimeout);
+ this._updateViewareaTimeout = null;
+ }
+ this._position = {
+ hash: location.pdfOpenParams.substring(1),
+ page: this.linkService.page,
+ first: location.pageNumber,
+ rotation: location.rotation
+ };
+ if (this._popStateInProgress) {
+ return;
+ }
+ if ( true && this._isPagesLoaded && this._destination && !this._destination.page) {
+ this._numPositionUpdates++;
+ }
+ if (true) {
+ this._updateViewareaTimeout = setTimeout(() => {
+ if (!this._popStateInProgress) {
+ this.#tryPushCurrentPosition(true);
+ }
+ this._updateViewareaTimeout = null;
+ }, UPDATE_VIEWAREA_TIMEOUT);
+ }
+ }
+ #popState({
+ state
+ }) {
+ const newHash = getCurrentHash(),
+ hashChanged = this._currentHash !== newHash;
+ this._currentHash = newHash;
+ if (!state) {
+ this._uid++;
+ const {
+ hash,
+ page,
+ rotation
+ } = this.#parseCurrentHash();
+ this.#pushOrReplaceState({
+ hash,
+ page,
+ rotation
+ }, true);
+ return;
+ }
+ if (!this.#isValidState(state)) {
+ return;
+ }
+ this._popStateInProgress = true;
+ if (hashChanged) {
+ this._blockHashChange++;
+ waitOnEventOrTimeout({
+ target: window,
+ name: "hashchange",
+ delay: HASH_CHANGE_TIMEOUT
+ }).then(() => {
+ this._blockHashChange--;
+ });
+ }
+ const destination = state.destination;
+ this.#updateInternalState(destination, state.uid, true);
+ if (isValidRotation(destination.rotation)) {
+ this.linkService.rotation = destination.rotation;
+ }
+ if (destination.dest) {
+ this.linkService.goToDestination(destination.dest);
+ } else if (destination.hash) {
+ this.linkService.setHash(destination.hash);
+ } else if (destination.page) {
+ this.linkService.page = destination.page;
+ }
+ Promise.resolve().then(() => {
+ this._popStateInProgress = false;
+ });
+ }
+ #pageHide() {
+ if (!this._destination || this._destination.temporary) {
+ this.#tryPushCurrentPosition();
+ }
+ }
+ #bindEvents() {
+ if (this.#eventAC) {
+ return;
+ }
+ this.#eventAC = new AbortController();
+ const {
+ signal
+ } = this.#eventAC;
+ this.eventBus.on("updateviewarea", this.#updateViewarea.bind(this), {
+ signal,
+ ...internalOpt
+ });
+ window.addEventListener("popstate", this.#popState.bind(this), {
+ signal
+ });
+ window.addEventListener("pagehide", this.#pageHide.bind(this), {
+ signal
+ });
+ }
+ #unbindEvents() {
+ this.#eventAC?.abort();
+ this.#eventAC = null;
+ }
+}
+function isDestHashesEqual(destHash, pushHash) {
+ if (typeof destHash !== "string" || typeof pushHash !== "string") {
+ return false;
+ }
+ if (destHash === pushHash) {
+ return true;
+ }
+ const nameddest = parseQueryString(destHash).get("nameddest");
+ if (nameddest === pushHash) {
+ return true;
+ }
+ return false;
+}
+function isDestArraysEqual(firstDest, secondDest) {
+ function isEntryEqual(first, second) {
+ if (typeof first !== typeof second) {
+ return false;
+ }
+ if (Array.isArray(first) || Array.isArray(second)) {
+ return false;
+ }
+ if (first !== null && typeof first === "object" && second !== null) {
+ if (Object.keys(first).length !== Object.keys(second).length) {
+ return false;
+ }
+ for (const key in first) {
+ if (!isEntryEqual(first[key], second[key])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return first === second || Number.isNaN(first) && Number.isNaN(second);
+ }
+ if (!(Array.isArray(firstDest) && Array.isArray(secondDest))) {
+ return false;
+ }
+ if (firstDest.length !== secondDest.length) {
+ return false;
+ }
+ for (let i = 0, ii = firstDest.length; i < ii; i++) {
+ if (!isEntryEqual(firstDest[i], secondDest[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+;// ./web/pdf_layer_viewer.js
+
+
+
+
+
+class PDFLayerViewer extends BaseTreeViewer {
+ constructor(options) {
+ super(options);
+ const {
+ eventBus
+ } = this;
+ eventBus.on("optionalcontentconfigchanged", evt => {
+ this.#updateLayers(evt.promise);
+ }, internalOpt);
+ eventBus.on("resetlayers", () => {
+ this.#updateLayers();
+ }, internalOpt);
+ eventBus.on("togglelayerstree", this._toggleAllTreeItems.bind(this), internalOpt);
+ }
+ reset() {
+ super.reset();
+ this._optionalContentConfig = null;
+ this._optionalContentVisibility?.clear();
+ this._optionalContentVisibility = null;
+ }
+ _dispatchEvent(layersCount) {
+ this.eventBus.dispatch("layersloaded", {
+ source: this,
+ layersCount
+ });
+ }
+ _bindLink(element, {
+ groupId,
+ input
+ }) {
+ const setVisibility = () => {
+ const visible = input.checked;
+ this._optionalContentConfig.setVisibility(groupId, visible);
+ const cached = this._optionalContentVisibility.get(groupId);
+ if (cached) {
+ cached.visible = visible;
+ }
+ this.eventBus.dispatch("optionalcontentconfig", {
+ source: this,
+ promise: Promise.resolve(this._optionalContentConfig)
+ });
+ };
+ element.onclick = evt => {
+ if (evt.target === input) {
+ setVisibility();
+ return true;
+ } else if (evt.target !== element) {
+ return true;
+ }
+ input.checked = !input.checked;
+ setVisibility();
+ return false;
+ };
+ }
+ _setNestedName(element, {
+ name = null
+ }) {
+ if (typeof name === "string") {
+ element.textContent = this._normalizeTextContent(name);
+ return;
+ }
+ element.setAttribute("data-l10n-id", "pdfjs-additional-layers");
+ element.style.fontStyle = "italic";
+ this._l10n.translateOnce(element);
+ }
+ _addToggleButton(div, {
+ name = null
+ }) {
+ super._addToggleButton(div, name === null);
+ }
+ _toggleAllTreeItems() {
+ if (!this._optionalContentConfig) {
+ return;
+ }
+ super._toggleAllTreeItems();
+ }
+ render({
+ optionalContentConfig,
+ pdfDocument
+ }) {
+ if (this._optionalContentConfig) {
+ this.reset();
+ }
+ this._optionalContentConfig = optionalContentConfig || null;
+ this._pdfDocument = pdfDocument || null;
+ const groups = optionalContentConfig?.getOrder();
+ if (!groups) {
+ this._dispatchEvent(0);
+ return;
+ }
+ this._optionalContentVisibility = new Map();
+ const fragment = document.createDocumentFragment(),
+ queue = [{
+ parent: fragment,
+ groups
+ }];
+ let layersCount = 0,
+ hasAnyNesting = false;
+ while (queue.length > 0) {
+ const levelData = queue.shift();
+ for (const groupId of levelData.groups) {
+ const div = document.createElement("div");
+ div.className = "treeItem";
+ const element = document.createElement("a");
+ div.append(element);
+ if (typeof groupId === "object") {
+ hasAnyNesting = true;
+ this._addToggleButton(div, groupId);
+ this._setNestedName(element, groupId);
+ const itemsDiv = document.createElement("div");
+ itemsDiv.className = "treeItems";
+ div.append(itemsDiv);
+ queue.push({
+ parent: itemsDiv,
+ groups: groupId.order
+ });
+ } else {
+ const group = optionalContentConfig.getGroup(groupId);
+ const label = document.createElement("label");
+ const input = document.createElement("input");
+ label.append(input, document.createTextNode(this._normalizeTextContent(group.name)));
+ this._bindLink(element, {
+ groupId,
+ input
+ });
+ input.type = "checkbox";
+ input.checked = group.visible;
+ this._optionalContentVisibility.set(groupId, {
+ input,
+ visible: input.checked
+ });
+ element.append(label);
+ layersCount++;
+ }
+ levelData.parent.append(div);
+ }
+ }
+ this._finishRendering(fragment, layersCount, hasAnyNesting);
+ }
+ async #updateLayers(promise = null) {
+ if (!this._optionalContentConfig) {
+ return;
+ }
+ const pdfDocument = this._pdfDocument;
+ const optionalContentConfig = await (promise || pdfDocument.getOptionalContentConfig({
+ intent: "display"
+ }));
+ if (pdfDocument !== this._pdfDocument) {
+ return;
+ }
+ if (promise) {
+ for (const [groupId, cached] of this._optionalContentVisibility) {
+ const group = optionalContentConfig.getGroup(groupId);
+ if (group && cached.visible !== group.visible) {
+ cached.input.checked = cached.visible = !cached.visible;
+ }
+ }
+ return;
+ }
+ this.eventBus.dispatch("optionalcontentconfig", {
+ source: this,
+ promise: Promise.resolve(optionalContentConfig)
+ });
+ this.render({
+ optionalContentConfig,
+ pdfDocument: this._pdfDocument
+ });
+ }
+}
+
+;// ./web/pdf_outline_viewer.js
+
+
+
+
+
+
+class PDFOutlineViewer extends BaseTreeViewer {
+ constructor(options) {
+ super(options);
+ this.linkService = options.linkService;
+ this.downloadManager = options.downloadManager;
+ const {
+ eventBus
+ } = this;
+ eventBus.on("toggleoutlinetree", this._toggleAllTreeItems.bind(this), internalOpt);
+ eventBus.on("currentoutlineitem", this._currentOutlineItem.bind(this), internalOpt);
+ eventBus.on("pagechanging", evt => {
+ this._currentPageNumber = evt.pageNumber;
+ }, internalOpt);
+ eventBus.on("pagesloaded", evt => {
+ this._isPagesLoaded = !!evt.pagesCount;
+ this._currentOutlineItemCapability?.resolve(this._isPagesLoaded);
+ }, internalOpt);
+ eventBus.on("sidebarviewchanged", evt => {
+ this._sidebarView = evt.view;
+ }, internalOpt);
+ }
+ reset() {
+ super.reset();
+ this._outline = null;
+ this._pageNumberToDestHashCapability = null;
+ this._currentPageNumber = 1;
+ this._isPagesLoaded = null;
+ this._currentOutlineItemCapability?.resolve(false);
+ this._currentOutlineItemCapability = null;
+ }
+ _dispatchEvent(outlineCount) {
+ this._currentOutlineItemCapability = Promise.withResolvers();
+ if (outlineCount === 0 || this._pdfDocument?.loadingParams.disableAutoFetch) {
+ this._currentOutlineItemCapability.resolve(false);
+ } else if (this._isPagesLoaded !== null) {
+ this._currentOutlineItemCapability.resolve(this._isPagesLoaded);
+ }
+ this.eventBus.dispatch("outlineloaded", {
+ source: this,
+ outlineCount,
+ currentOutlineItemPromise: this._currentOutlineItemCapability.promise
+ });
+ }
+ _bindLink(element, {
+ url,
+ newWindow,
+ action,
+ attachmentId,
+ attachment,
+ dest,
+ setOCGState
+ }) {
+ const {
+ linkService
+ } = this;
+ if (url) {
+ linkService.addLinkAttributes(element, url, newWindow);
+ return;
+ }
+ if (action) {
+ element.href = linkService.getAnchorUrl("");
+ element.onclick = () => {
+ linkService.executeNamedAction(action);
+ return false;
+ };
+ return;
+ }
+ if (attachmentId && attachment) {
+ element.href = linkService.getAnchorUrl("");
+ const openAttachment = async () => {
+ const content = await linkService.getAttachmentContent(attachmentId);
+ if (content) {
+ this.downloadManager?.openOrDownloadData(content, attachment.filename);
+ }
+ };
+ element.onclick = () => {
+ openAttachment();
+ return false;
+ };
+ return;
+ }
+ if (setOCGState) {
+ element.href = linkService.getAnchorUrl("");
+ element.onclick = () => {
+ linkService.executeSetOCGState(setOCGState);
+ return false;
+ };
+ return;
+ }
+ element.href = linkService.getDestinationHash(dest);
+ element.onclick = evt => {
+ this._updateCurrentTreeItem(evt.target.parentNode);
+ if (dest) {
+ linkService.goToDestination(dest);
+ }
+ return false;
+ };
+ }
+ _setStyles(element, {
+ bold,
+ italic
+ }) {
+ if (bold) {
+ element.style.fontWeight = "bold";
+ }
+ if (italic) {
+ element.style.fontStyle = "italic";
+ }
+ }
+ _addToggleButton(div, {
+ count,
+ items
+ }) {
+ let hidden = false;
+ if (count < 0) {
+ let totalCount = items.length;
+ if (totalCount > 0) {
+ const queue = [...items];
+ while (queue.length > 0) {
+ const {
+ count: nestedCount,
+ items: nestedItems
+ } = queue.shift();
+ if (nestedCount > 0 && nestedItems.length > 0) {
+ totalCount += nestedItems.length;
+ queue.push(...nestedItems);
+ }
+ }
+ }
+ if (Math.abs(count) === totalCount) {
+ hidden = true;
+ }
+ }
+ super._addToggleButton(div, hidden);
+ }
+ _toggleAllTreeItems() {
+ if (!this._outline) {
+ return;
+ }
+ super._toggleAllTreeItems();
+ }
+ render({
+ outline,
+ pdfDocument
+ }) {
+ if (this._outline) {
+ this.reset();
+ }
+ this._outline = outline || null;
+ this._pdfDocument = pdfDocument || null;
+ if (!outline) {
+ this._dispatchEvent(0);
+ return;
+ }
+ const fragment = document.createDocumentFragment();
+ const queue = [{
+ parent: fragment,
+ items: outline
+ }];
+ let outlineCount = 0,
+ hasAnyNesting = false;
+ while (queue.length > 0) {
+ const levelData = queue.shift();
+ for (const item of levelData.items) {
+ const div = document.createElement("div");
+ div.className = "treeItem";
+ const element = document.createElement("a");
+ this._bindLink(element, item);
+ this._setStyles(element, item);
+ element.textContent = this._normalizeTextContent(item.title);
+ div.append(element);
+ if (item.items.length > 0) {
+ hasAnyNesting = true;
+ this._addToggleButton(div, item);
+ const itemsDiv = document.createElement("div");
+ itemsDiv.className = "treeItems";
+ div.append(itemsDiv);
+ queue.push({
+ parent: itemsDiv,
+ items: item.items
+ });
+ }
+ levelData.parent.append(div);
+ outlineCount++;
+ }
+ }
+ this._finishRendering(fragment, outlineCount, hasAnyNesting);
+ }
+ async _currentOutlineItem() {
+ if (!this._isPagesLoaded) {
+ throw new Error("_currentOutlineItem: All pages have not been loaded.");
+ }
+ if (!this._outline || !this._pdfDocument) {
+ return;
+ }
+ const pageNumberToDestHash = await this._getPageNumberToDestHash(this._pdfDocument);
+ if (!pageNumberToDestHash) {
+ return;
+ }
+ this._updateCurrentTreeItem(null);
+ if (this._sidebarView !== SidebarView.OUTLINE) {
+ return;
+ }
+ for (let i = this._currentPageNumber; i > 0; i--) {
+ const destHash = pageNumberToDestHash.get(i);
+ if (!destHash) {
+ continue;
+ }
+ const linkElement = this.container.querySelector(`a[href="${destHash}"]`);
+ if (!linkElement) {
+ continue;
+ }
+ this._scrollToCurrentTreeItem(linkElement.parentNode);
+ break;
+ }
+ }
+ async _getPageNumberToDestHash(pdfDocument) {
+ if (this._pageNumberToDestHashCapability) {
+ return this._pageNumberToDestHashCapability.promise;
+ }
+ this._pageNumberToDestHashCapability = Promise.withResolvers();
+ const pageNumberToDestHash = new Map(),
+ pageNumberNesting = new Map();
+ const queue = [{
+ nesting: 0,
+ items: this._outline
+ }];
+ while (queue.length > 0) {
+ const levelData = queue.shift(),
+ currentNesting = levelData.nesting;
+ for (const {
+ dest,
+ items
+ } of levelData.items) {
+ let explicitDest, pageNumber;
+ if (typeof dest === "string") {
+ explicitDest = await pdfDocument.getDestination(dest);
+ if (pdfDocument !== this._pdfDocument) {
+ return null;
+ }
+ } else {
+ explicitDest = dest;
+ }
+ if (Array.isArray(explicitDest)) {
+ const [destRef] = explicitDest;
+ if (destRef && typeof destRef === "object") {
+ pageNumber = pdfDocument.cachedPageNumber(destRef);
+ } else if (Number.isInteger(destRef)) {
+ pageNumber = destRef + 1;
+ }
+ if (Number.isInteger(pageNumber) && (!pageNumberToDestHash.has(pageNumber) || currentNesting > pageNumberNesting.get(pageNumber))) {
+ const destHash = this.linkService.getDestinationHash(dest);
+ pageNumberToDestHash.set(pageNumber, destHash);
+ pageNumberNesting.set(pageNumber, currentNesting);
+ }
+ }
+ if (items.length > 0) {
+ queue.push({
+ nesting: currentNesting + 1,
+ items
+ });
+ }
+ }
+ }
+ this._pageNumberToDestHashCapability.resolve(pageNumberToDestHash.size > 0 ? pageNumberToDestHash : null);
+ return this._pageNumberToDestHashCapability.promise;
+ }
+}
+
+;// ./web/pdf_presentation_mode.js
+
+
+const DELAY_BEFORE_HIDING_CONTROLS = 3000;
+const ACTIVE_SELECTOR = "pdfPresentationMode";
+const CONTROLS_SELECTOR = "pdfPresentationModeControls";
+const MOUSE_SCROLL_COOLDOWN_TIME = 50;
+const PAGE_SWITCH_THRESHOLD = 0.1;
+const SWIPE_MIN_DISTANCE_THRESHOLD = 50;
+const SWIPE_ANGLE_THRESHOLD = Math.PI / 6;
+class PDFPresentationMode {
+ #state = PresentationModeState.UNKNOWN;
+ #args = null;
+ #fullscreenChangeAC = null;
+ #windowAC = null;
+ constructor({
+ container,
+ pdfViewer,
+ eventBus
+ }) {
+ this.container = container;
+ this.pdfViewer = pdfViewer;
+ this.eventBus = eventBus;
+ this.contextMenuOpen = false;
+ this.mouseScrollTimeStamp = 0;
+ this.mouseScrollDelta = 0;
+ this.touchSwipeState = null;
+ }
+ async request() {
+ const {
+ container,
+ pdfViewer
+ } = this;
+ if (this.active || !pdfViewer.pagesCount || !container.requestFullscreen) {
+ return false;
+ }
+ this.#addFullscreenChangeListeners();
+ this.#notifyStateChange(PresentationModeState.CHANGING);
+ const promise = container.requestFullscreen();
+ this.#args = {
+ pageNumber: pdfViewer.currentPageNumber,
+ scaleValue: pdfViewer.currentScaleValue,
+ scrollMode: pdfViewer.scrollMode,
+ spreadMode: null,
+ annotationEditorMode: null
+ };
+ if (pdfViewer.spreadMode !== SpreadMode.NONE && !(pdfViewer.pageViewsReady && pdfViewer.hasEqualPageSizes)) {
+ console.warn("Ignoring Spread modes when entering PresentationMode, " + "since the document may contain varying page sizes.");
+ this.#args.spreadMode = pdfViewer.spreadMode;
+ }
+ if (pdfViewer.annotationEditorMode !== AnnotationEditorType.DISABLE) {
+ this.#args.annotationEditorMode = pdfViewer.annotationEditorMode;
+ }
+ try {
+ await promise;
+ pdfViewer.focus();
+ return true;
+ } catch {
+ this.#removeFullscreenChangeListeners();
+ this.#notifyStateChange(PresentationModeState.NORMAL);
+ }
+ return false;
+ }
+ get active() {
+ return this.#state === PresentationModeState.CHANGING || this.#state === PresentationModeState.FULLSCREEN;
+ }
+ #mouseWheel(evt) {
+ if (!this.active) {
+ return;
+ }
+ if (evt.target.closest?.(".mediaAnnotation")) {
+ return;
+ }
+ evt.preventDefault();
+ const delta = normalizeWheelEventDelta(evt);
+ const currentTime = Date.now();
+ const storedTime = this.mouseScrollTimeStamp;
+ if (currentTime > storedTime && currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) {
+ return;
+ }
+ if (this.mouseScrollDelta > 0 && delta < 0 || this.mouseScrollDelta < 0 && delta > 0) {
+ this.#resetMouseScrollState();
+ }
+ this.mouseScrollDelta += delta;
+ if (Math.abs(this.mouseScrollDelta) >= PAGE_SWITCH_THRESHOLD) {
+ const totalDelta = this.mouseScrollDelta;
+ this.#resetMouseScrollState();
+ const success = totalDelta > 0 ? this.pdfViewer.previousPage() : this.pdfViewer.nextPage();
+ if (success) {
+ this.mouseScrollTimeStamp = currentTime;
+ }
+ }
+ }
+ #notifyStateChange(state) {
+ this.#state = state;
+ this.eventBus.dispatch("presentationmodechanged", {
+ source: this,
+ state
+ });
+ }
+ #enter() {
+ this.#notifyStateChange(PresentationModeState.FULLSCREEN);
+ this.container.classList.add(ACTIVE_SELECTOR);
+ setTimeout(() => {
+ this.pdfViewer.scrollMode = ScrollMode.PAGE;
+ if (this.#args.spreadMode !== null) {
+ this.pdfViewer.spreadMode = SpreadMode.NONE;
+ }
+ this.pdfViewer.currentPageNumber = this.#args.pageNumber;
+ this.pdfViewer.currentScaleValue = "page-fit";
+ if (this.#args.annotationEditorMode !== null) {
+ this.pdfViewer.annotationEditorMode = {
+ mode: AnnotationEditorType.NONE
+ };
+ }
+ }, 0);
+ this.#addWindowListeners();
+ this.#showControls();
+ this.contextMenuOpen = false;
+ document.getSelection().empty();
+ }
+ #exit() {
+ const pageNumber = this.pdfViewer.currentPageNumber;
+ this.container.classList.remove(ACTIVE_SELECTOR);
+ setTimeout(() => {
+ this.#removeFullscreenChangeListeners();
+ this.#notifyStateChange(PresentationModeState.NORMAL);
+ this.pdfViewer.scrollMode = this.#args.scrollMode;
+ if (this.#args.spreadMode !== null) {
+ this.pdfViewer.spreadMode = this.#args.spreadMode;
+ }
+ this.pdfViewer.currentScaleValue = this.#args.scaleValue;
+ this.pdfViewer.currentPageNumber = pageNumber;
+ if (this.#args.annotationEditorMode !== null) {
+ this.pdfViewer.annotationEditorMode = {
+ mode: this.#args.annotationEditorMode
+ };
+ }
+ this.#args = null;
+ }, 0);
+ this.#removeWindowListeners();
+ this.#hideControls();
+ this.#resetMouseScrollState();
+ this.contextMenuOpen = false;
+ }
+ #mouseDown(evt) {
+ if (this.contextMenuOpen) {
+ this.contextMenuOpen = false;
+ evt.preventDefault();
+ return;
+ }
+ if (evt.button !== 0) {
+ return;
+ }
+ if (evt.target.href && evt.target.parentNode?.hasAttribute("data-internal-link")) {
+ return;
+ }
+ if (evt.target.closest?.(".mediaAnnotation")) {
+ return;
+ }
+ evt.preventDefault();
+ if (evt.shiftKey) {
+ this.pdfViewer.previousPage();
+ } else {
+ this.pdfViewer.nextPage();
+ }
+ }
+ #contextMenu() {
+ this.contextMenuOpen = true;
+ }
+ #showControls() {
+ if (this.controlsTimeout) {
+ clearTimeout(this.controlsTimeout);
+ } else {
+ this.container.classList.add(CONTROLS_SELECTOR);
+ }
+ this.controlsTimeout = setTimeout(() => {
+ this.container.classList.remove(CONTROLS_SELECTOR);
+ delete this.controlsTimeout;
+ }, DELAY_BEFORE_HIDING_CONTROLS);
+ }
+ #hideControls() {
+ if (!this.controlsTimeout) {
+ return;
+ }
+ clearTimeout(this.controlsTimeout);
+ this.container.classList.remove(CONTROLS_SELECTOR);
+ delete this.controlsTimeout;
+ }
+ #resetMouseScrollState() {
+ this.mouseScrollTimeStamp = 0;
+ this.mouseScrollDelta = 0;
+ }
+ #touchSwipe(evt) {
+ if (!this.active) {
+ return;
+ }
+ if (evt.target.closest?.(".mediaAnnotation")) {
+ this.touchSwipeState = null;
+ return;
+ }
+ if (evt.touches.length > 1) {
+ this.touchSwipeState = null;
+ return;
+ }
+ switch (evt.type) {
+ case "touchstart":
+ this.touchSwipeState = {
+ startX: evt.touches[0].pageX,
+ startY: evt.touches[0].pageY,
+ endX: evt.touches[0].pageX,
+ endY: evt.touches[0].pageY
+ };
+ break;
+ case "touchmove":
+ if (this.touchSwipeState === null) {
+ return;
+ }
+ this.touchSwipeState.endX = evt.touches[0].pageX;
+ this.touchSwipeState.endY = evt.touches[0].pageY;
+ evt.preventDefault();
+ break;
+ case "touchend":
+ if (this.touchSwipeState === null) {
+ return;
+ }
+ let delta = 0;
+ const dx = this.touchSwipeState.endX - this.touchSwipeState.startX;
+ const dy = this.touchSwipeState.endY - this.touchSwipeState.startY;
+ const absAngle = Math.abs(Math.atan2(dy, dx));
+ if (Math.abs(dx) > SWIPE_MIN_DISTANCE_THRESHOLD && (absAngle <= SWIPE_ANGLE_THRESHOLD || absAngle >= Math.PI - SWIPE_ANGLE_THRESHOLD)) {
+ delta = dx;
+ } else if (Math.abs(dy) > SWIPE_MIN_DISTANCE_THRESHOLD && Math.abs(absAngle - Math.PI / 2) <= SWIPE_ANGLE_THRESHOLD) {
+ delta = dy;
+ }
+ if (delta > 0) {
+ this.pdfViewer.previousPage();
+ } else if (delta < 0) {
+ this.pdfViewer.nextPage();
+ }
+ break;
+ }
+ }
+ #addWindowListeners() {
+ if (this.#windowAC) {
+ return;
+ }
+ this.#windowAC = new AbortController();
+ const {
+ signal
+ } = this.#windowAC;
+ const touchSwipeBind = this.#touchSwipe.bind(this);
+ window.addEventListener("mousemove", this.#showControls.bind(this), {
+ signal
+ });
+ window.addEventListener("mousedown", this.#mouseDown.bind(this), {
+ signal
+ });
+ window.addEventListener("wheel", this.#mouseWheel.bind(this), {
+ passive: false,
+ signal
+ });
+ window.addEventListener("keydown", this.#resetMouseScrollState.bind(this), {
+ signal
+ });
+ window.addEventListener("contextmenu", this.#contextMenu.bind(this), {
+ signal
+ });
+ window.addEventListener("touchstart", touchSwipeBind, {
+ signal
+ });
+ window.addEventListener("touchmove", touchSwipeBind, {
+ signal
+ });
+ window.addEventListener("touchend", touchSwipeBind, {
+ signal
+ });
+ }
+ #removeWindowListeners() {
+ this.#windowAC?.abort();
+ this.#windowAC = null;
+ }
+ #addFullscreenChangeListeners() {
+ if (this.#fullscreenChangeAC) {
+ return;
+ }
+ this.#fullscreenChangeAC = new AbortController();
+ window.addEventListener("fullscreenchange", () => {
+ if (document.fullscreenElement) {
+ this.#enter();
+ } else {
+ this.#exit();
+ }
+ }, {
+ signal: this.#fullscreenChangeAC.signal
+ });
+ }
+ #removeFullscreenChangeListeners() {
+ this.#fullscreenChangeAC?.abort();
+ this.#fullscreenChangeAC = null;
+ }
+}
+
+// EXTERNAL MODULE: ./node_modules/core-js/modules/es.iterator.every.js
+var es_iterator_every = __webpack_require__(1148);
+;// ./web/xfa_layer_builder.js
+
+class XfaLayerBuilder {
+ #cancelled = false;
+ div = null;
+ constructor({
+ pdfPage,
+ annotationStorage = null,
+ linkService,
+ xfaHtml = null
+ }) {
+ this.pdfPage = pdfPage;
+ this.annotationStorage = annotationStorage;
+ this.linkService = linkService;
+ this.xfaHtml = xfaHtml;
+ }
+ async render({
+ viewport,
+ intent = "display"
+ }) {
+ let xfaHtml;
+ if (intent === "print") {
+ xfaHtml = this.xfaHtml;
+ } else {
+ xfaHtml = await this.pdfPage.getXfa();
+ if (this.#cancelled || !xfaHtml) {
+ return {
+ textDivs: []
+ };
+ }
+ }
+ const hasDiv = !!this.div;
+ const params = {
+ viewport: viewport.clone({
+ dontFlip: true
+ }),
+ div: this.div ??= document.createElement("div"),
+ xfaHtml,
+ annotationStorage: this.annotationStorage,
+ linkService: this.linkService,
+ intent
+ };
+ return hasDiv ? XfaLayer.update(params) : XfaLayer.render(params);
+ }
+ cancel() {
+ this.#cancelled = true;
+ }
+ hide() {
+ if (!this.div) {
+ return;
+ }
+ this.div.hidden = true;
+ }
+}
+
+;// ./web/print_utils.js
+
+
+
+class BasePrintServiceFactory {
+ static initGlobals(app) {}
+ static get supportsPrinting() {
+ throw new Error("Not implemented: supportsPrinting");
+ }
+ static createPrintService(params) {
+ throw new Error("Not implemented: createPrintService");
+ }
+}
+function getXfaHtmlForPrinting(printContainer, pdfDocument) {
+ const xfaHtml = pdfDocument.allXfaHtml;
+ const linkService = new SimpleLinkService();
+ const scale = Math.round(PixelsPerInch.PDF_TO_CSS_UNITS * 100) / 100;
+ for (const xfaPage of xfaHtml.children) {
+ const page = document.createElement("div");
+ page.className = "xfaPrintedPage";
+ printContainer.append(page);
+ const builder = new XfaLayerBuilder({
+ pdfPage: null,
+ annotationStorage: pdfDocument.annotationStorage,
+ linkService,
+ xfaHtml: xfaPage
+ });
+ const viewport = XfaLayer.getPageViewport(xfaPage, {
+ scale
+ });
+ builder.render({
+ viewport,
+ intent: "print"
+ });
+ page.append(builder.div);
+ }
+}
+
+;// ./web/pdf_print_service.js
+
+
+
+
+
+
+
+let activeService = null;
+let dialog = null;
+let overlayManager = null;
+let viewerApp = {
+ initialized: false
+};
+function renderPage(activeServiceOnEntry, pdfDocument, pageNumber, size, printResolution, optionalContentConfigPromise, printAnnotationStoragePromise) {
+ const scratchCanvas = activeService.scratchCanvas;
+ const PRINT_UNITS = printResolution / PixelsPerInch.PDF;
+ scratchCanvas.width = Math.floor(size.width * PRINT_UNITS);
+ scratchCanvas.height = Math.floor(size.height * PRINT_UNITS);
+ const ctx = scratchCanvas.getContext("2d");
+ ctx.save();
+ ctx.fillStyle = "rgb(255, 255, 255)";
+ ctx.fillRect(0, 0, scratchCanvas.width, scratchCanvas.height);
+ ctx.restore();
+ return Promise.all([pdfDocument.getPage(pageNumber), printAnnotationStoragePromise]).then(function ([pdfPage, printAnnotationStorage]) {
+ const renderContext = {
+ canvas: scratchCanvas,
+ transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
+ viewport: pdfPage.getViewport({
+ scale: 1,
+ rotation: size.rotation
+ }),
+ intent: "print",
+ annotationMode: AnnotationMode.ENABLE_STORAGE,
+ optionalContentConfigPromise,
+ printAnnotationStorage
+ };
+ const renderTask = pdfPage.render(renderContext);
+ return renderTask.promise.catch(reason => {
+ if (!(reason instanceof RenderingCancelledException)) {
+ console.error(reason);
+ }
+ throw reason;
+ });
+ });
+}
+class PDFPrintService {
+ constructor({
+ pdfDocument,
+ pagesOverview,
+ printContainer,
+ printResolution,
+ printAnnotationStoragePromise = null
+ }) {
+ this.pdfDocument = pdfDocument;
+ this.pagesOverview = pagesOverview;
+ this.printContainer = printContainer;
+ this._printResolution = printResolution || 150;
+ this._optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
+ intent: "print"
+ });
+ this._printAnnotationStoragePromise = printAnnotationStoragePromise || Promise.resolve();
+ this.currentPage = -1;
+ this.scratchCanvas = document.createElement("canvas");
+ }
+ layout() {
+ this.throwIfInactive();
+ const body = document.querySelector("body");
+ body.setAttribute("data-pdfjsprinting", true);
+ const {
+ width,
+ height
+ } = this.pagesOverview[0];
+ const hasEqualPageSizes = this.pagesOverview.every(size => size.width === width && size.height === height);
+ if (!hasEqualPageSizes) {
+ console.warn("Not all pages have the same size. The printed result may be incorrect!");
+ }
+ this.pageStyleSheet = new CSSStyleSheet();
+ this.pageStyleSheet.replaceSync(`@page { size: ${width}pt ${height}pt;}`);
+ document.adoptedStyleSheets.push(this.pageStyleSheet);
+ }
+ destroy() {
+ if (activeService !== this) {
+ return;
+ }
+ this.printContainer.textContent = "";
+ const body = document.querySelector("body");
+ body.removeAttribute("data-pdfjsprinting");
+ if (this.pageStyleSheet) {
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter(styleSheet => styleSheet !== this.pageStyleSheet);
+ this.pageStyleSheet = null;
+ }
+ if (this._blobURLs) {
+ for (const url of this._blobURLs) {
+ URL.revokeObjectURL(url);
+ }
+ this._blobURLs = null;
+ }
+ this.scratchCanvas.width = this.scratchCanvas.height = 0;
+ this.scratchCanvas = null;
+ activeService = null;
+ ensureOverlay().then(function () {
+ overlayManager.closeIfActive(dialog);
+ });
+ }
+ renderPages() {
+ if (this.pdfDocument.isPureXfa) {
+ getXfaHtmlForPrinting(this.printContainer, this.pdfDocument);
+ return Promise.resolve();
+ }
+ const pageCount = this.pagesOverview.length;
+ const renderNextPage = (resolve, reject) => {
+ this.throwIfInactive();
+ if (++this.currentPage >= pageCount) {
+ renderProgress(pageCount, pageCount);
+ resolve();
+ return;
+ }
+ const index = this.currentPage;
+ renderProgress(index, pageCount);
+ renderPage(this, this.pdfDocument, index + 1, this.pagesOverview[index], this._printResolution, this._optionalContentConfigPromise, this._printAnnotationStoragePromise).then(this.useRenderedPage.bind(this)).then(function () {
+ renderNextPage(resolve, reject);
+ }, reject);
+ };
+ return new Promise(renderNextPage);
+ }
+ useRenderedPage() {
+ this.throwIfInactive();
+ const img = document.createElement("img");
+ this.scratchCanvas.toBlob(blob => {
+ const blobURL = URL.createObjectURL(blob);
+ img.src = blobURL;
+ (this._blobURLs ??= []).push(blobURL);
+ });
+ const wrapper = document.createElement("div");
+ wrapper.className = "printedPage";
+ wrapper.append(img);
+ this.printContainer.append(wrapper);
+ const {
+ promise,
+ resolve,
+ reject
+ } = Promise.withResolvers();
+ img.onload = resolve;
+ img.onerror = reject;
+ promise.catch(() => {});
+ return promise;
+ }
+ performPrint() {
+ this.throwIfInactive();
+ return new Promise(resolve => {
+ setTimeout(() => {
+ if (!this.active) {
+ resolve();
+ return;
+ }
+ print.call(window);
+ setTimeout(resolve, 20);
+ }, 0);
+ });
+ }
+ get active() {
+ return this === activeService;
+ }
+ throwIfInactive() {
+ if (!this.active) {
+ throw new Error("This print request was cancelled or completed.");
+ }
+ }
+}
+const print = window.print;
+window.print = function () {
+ if (activeService) {
+ console.warn("Ignored window.print() because of a pending print job.");
+ return;
+ }
+ ensureOverlay().then(function () {
+ if (activeService) {
+ overlayManager.open(dialog);
+ }
+ });
+ try {
+ dispatchEvent("beforeprint");
+ } finally {
+ if (!activeService) {
+ console.error("Expected print service to be initialized.");
+ ensureOverlay().then(function () {
+ overlayManager.closeIfActive(dialog);
+ });
+ } else {
+ const activeServiceOnEntry = activeService;
+ activeService.renderPages().then(() => activeServiceOnEntry.performPrint()).catch(() => {}).then(() => {
+ if (activeServiceOnEntry.active) {
+ abort();
+ }
+ });
+ }
+ }
+};
+function dispatchEvent(eventType) {
+ const event = new CustomEvent(eventType, {
+ bubbles: false,
+ cancelable: false,
+ detail: "custom"
+ });
+ window.dispatchEvent(event);
+}
+function abort() {
+ if (activeService) {
+ activeService.destroy();
+ dispatchEvent("afterprint");
+ }
+}
+function renderProgress(index, total) {
+ dialog ||= document.getElementById("printServiceDialog");
+ const progress = Math.round(100 * index / total);
+ const progressBar = dialog.querySelector("progress");
+ const progressPerc = dialog.querySelector(".relative-progress");
+ progressBar.value = progress;
+ progressPerc.setAttribute("data-l10n-args", JSON.stringify({
+ progress
+ }));
+}
+window.addEventListener("keydown", function (event) {
+ if (event.keyCode === 80 && (event.ctrlKey || event.metaKey) && !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
+ window.print();
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+}, true);
+if ("onbeforeprint" in window) {
+ const stopPropagationIfNeeded = function (event) {
+ if (event.detail !== "custom") {
+ event.stopImmediatePropagation();
+ }
+ };
+ window.addEventListener("beforeprint", stopPropagationIfNeeded);
+ window.addEventListener("afterprint", stopPropagationIfNeeded);
+}
+let overlayPromise;
+function ensureOverlay() {
+ if (!overlayPromise) {
+ overlayManager = viewerApp.overlayManager;
+ if (!overlayManager) {
+ throw new Error("The overlay manager has not yet been initialized.");
+ }
+ dialog ||= document.getElementById("printServiceDialog");
+ overlayPromise = overlayManager.register(dialog, true);
+ document.getElementById("printCancel").onclick = abort;
+ dialog.addEventListener("close", abort);
+ }
+ return overlayPromise;
+}
+class PDFPrintServiceFactory extends BasePrintServiceFactory {
+ static initGlobals(app) {
+ viewerApp = app;
+ }
+ static get supportsPrinting() {
+ return shadow(this, "supportsPrinting", true);
+ }
+ static createPrintService(params) {
+ if (activeService) {
+ throw new Error("The print service is created and active.");
+ }
+ return activeService = new PDFPrintService(params);
+ }
+}
+
+;// ./web/renderable_view.js
+const RenderingStates = {
+ INITIAL: 0,
+ RUNNING: 1,
+ PAUSED: 2,
+ FINISHED: 3
+};
+class RenderableView {
+ renderingId = "";
+ renderTask = null;
+ resume = null;
+ get renderingState() {
+ throw new Error("Abstract getter `renderingState` accessed");
+ }
+ set renderingState(state) {
+ throw new Error("Abstract setter `renderingState` accessed");
+ }
+ async draw() {
+ throw new Error("Not implemented: draw");
+ }
+}
+
+;// ./web/pdf_rendering_queue.js
+
+
+const CLEANUP_TIMEOUT = 30000;
+class PDFRenderingQueue {
+ #highestPriorityPage = null;
+ #idleTimeout = null;
+ #pdfThumbnailViewer = null;
+ #pdfViewer = null;
+ isThumbnailViewEnabled = false;
+ onIdle = null;
+ printing = false;
+ constructor() {
+ Object.defineProperty(this, "hasViewer", {
+ value: () => !!this.#pdfViewer
+ });
+ }
+ setViewer(pdfViewer) {
+ this.#pdfViewer = pdfViewer;
+ }
+ setThumbnailViewer(pdfThumbnailViewer) {
+ this.#pdfThumbnailViewer = pdfThumbnailViewer;
+ }
+ isHighestPriority(view) {
+ return this.#highestPriorityPage === view.renderingId;
+ }
+ renderHighestPriority(currentlyVisiblePages) {
+ if (this.#idleTimeout) {
+ clearTimeout(this.#idleTimeout);
+ this.#idleTimeout = null;
+ }
+ if (this.#pdfViewer.forceRendering(currentlyVisiblePages)) {
+ return;
+ }
+ if (this.isThumbnailViewEnabled && this.#pdfThumbnailViewer?.forceRendering()) {
+ return;
+ }
+ if (this.printing) {
+ return;
+ }
+ if (this.onIdle) {
+ this.#idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);
+ }
+ }
+ getHighestPriority(visible, views, scrolledDown, preRenderExtra = false, ignoreDetailViews = false) {
+ const visibleViews = visible.views,
+ numVisible = visibleViews.length;
+ if (numVisible === 0) {
+ return null;
+ }
+ for (let i = 0; i < numVisible; i++) {
+ const view = visibleViews[i].view;
+ if (!this.isViewFinished(view)) {
+ return view;
+ }
+ }
+ if (!ignoreDetailViews) {
+ for (let i = 0; i < numVisible; i++) {
+ const {
+ detailView
+ } = visibleViews[i].view;
+ if (detailView && !this.isViewFinished(detailView)) {
+ return detailView;
+ }
+ }
+ }
+ const firstId = visible.first.id,
+ lastId = visible.last.id;
+ if (lastId - firstId + 1 > numVisible) {
+ const visibleIds = visible.ids;
+ for (let i = 1, ii = lastId - firstId; i < ii; i++) {
+ const holeId = scrolledDown ? firstId + i : lastId - i;
+ if (visibleIds.has(holeId)) {
+ continue;
+ }
+ const holeView = views[holeId - 1];
+ if (!this.isViewFinished(holeView)) {
+ return holeView;
+ }
+ }
+ }
+ let preRenderIndex = scrolledDown ? lastId : firstId - 2;
+ let preRenderView = views[preRenderIndex];
+ if (preRenderView && !this.isViewFinished(preRenderView)) {
+ return preRenderView;
+ }
+ if (preRenderExtra) {
+ preRenderIndex += scrolledDown ? 1 : -1;
+ preRenderView = views[preRenderIndex];
+ if (preRenderView && !this.isViewFinished(preRenderView)) {
+ return preRenderView;
+ }
+ }
+ return null;
+ }
+ isViewFinished(view) {
+ return view.renderingState === RenderingStates.FINISHED;
+ }
+ renderView(view) {
+ switch (view.renderingState) {
+ case RenderingStates.FINISHED:
+ return false;
+ case RenderingStates.PAUSED:
+ this.#highestPriorityPage = view.renderingId;
+ view.resume();
+ break;
+ case RenderingStates.RUNNING:
+ this.#highestPriorityPage = view.renderingId;
+ break;
+ case RenderingStates.INITIAL:
+ this.#highestPriorityPage = view.renderingId;
+ view.draw().finally(() => {
+ this.renderHighestPriority();
+ }).catch(reason => {
+ if (reason instanceof RenderingCancelledException) {
+ return;
+ }
+ console.error("renderView:", reason);
+ });
+ break;
+ }
+ return true;
+ }
+}
+
+;// ./web/pdf_scripting_manager.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+class PDFScriptingManager {
+ #closeCapability = null;
+ #destroyCapability = null;
+ #docProperties = null;
+ #eventAC = null;
+ #eventBus = null;
+ #externalServices = null;
+ #objectIds = null;
+ #pdfDocument = null;
+ #pdfViewer = null;
+ #ready = false;
+ #scripting = null;
+ #willPrintCapability = null;
+ constructor({
+ eventBus,
+ externalServices = null,
+ docProperties = null
+ }) {
+ this.#eventBus = eventBus;
+ this.#externalServices = externalServices;
+ this.#docProperties = docProperties;
+ }
+ setViewer(pdfViewer) {
+ this.#pdfViewer = pdfViewer;
+ }
+ async setDocument(pdfDocument) {
+ if (this.#pdfDocument) {
+ await this.#destroyScripting();
+ }
+ this.#pdfDocument = pdfDocument;
+ if (!pdfDocument) {
+ return;
+ }
+ const [objects, calculationOrder, docActions] = await Promise.all([pdfDocument.getFieldObjects(), pdfDocument.getCalculationOrderIds(), pdfDocument.getJSActions()]);
+ if (!objects && !docActions) {
+ await this.#destroyScripting();
+ return;
+ }
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ if (objects) {
+ this.#objectIds = new Set();
+ for (const fields of objects.values()) {
+ for (const {
+ id
+ } of fields) {
+ this.#objectIds.add(id);
+ }
+ }
+ }
+ try {
+ this.#scripting = this.#initScripting();
+ } catch (error) {
+ console.error("setDocument:", error);
+ await this.#destroyScripting();
+ return;
+ }
+ const eventBus = this.#eventBus;
+ this.#eventAC = new AbortController();
+ const evtOpts = {
+ signal: this.#eventAC.signal,
+ ...internalOpt
+ };
+ eventBus.on("updatefromsandbox", event => {
+ if (event?.source === window) {
+ this.#updateFromSandbox(event.detail);
+ }
+ }, evtOpts);
+ eventBus.on("dispatcheventinsandbox", event => {
+ this.#scripting?.dispatchEventInSandbox(event.detail);
+ }, evtOpts);
+ eventBus.on("pagechanging", ({
+ pageNumber,
+ previous
+ }) => {
+ if (pageNumber === previous) {
+ return;
+ }
+ this.#dispatchPageClose(previous);
+ this.#dispatchPageOpen(pageNumber);
+ }, evtOpts);
+ eventBus.on("pagerendered", ({
+ pageNumber
+ }) => {
+ if (!this._pageOpenPending.has(pageNumber)) {
+ return;
+ }
+ if (pageNumber !== this.#pdfViewer.currentPageNumber) {
+ return;
+ }
+ this.#dispatchPageOpen(pageNumber);
+ }, evtOpts);
+ eventBus.on("pagesdestroy", async () => {
+ await this.#dispatchPageClose(this.#pdfViewer.currentPageNumber);
+ await this.#scripting?.dispatchEventInSandbox({
+ id: "doc",
+ name: "WillClose"
+ });
+ this.#closeCapability?.resolve();
+ }, evtOpts);
+ try {
+ const docProperties = await this.#docProperties(pdfDocument);
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ await this.#scripting.createSandbox({
+ objects,
+ calculationOrder,
+ appInfo: {
+ platform: navigator.platform,
+ language: navigator.language
+ },
+ docInfo: {
+ ...docProperties,
+ actions: docActions
+ }
+ });
+ eventBus.dispatch("sandboxcreated", {
+ source: this
+ });
+ } catch (error) {
+ console.error("setDocument:", error);
+ await this.#destroyScripting();
+ return;
+ }
+ await this.#scripting?.dispatchEventInSandbox({
+ id: "doc",
+ name: "Open"
+ });
+ await this.#dispatchPageOpen(this.#pdfViewer.currentPageNumber, true);
+ Promise.resolve().then(() => {
+ if (pdfDocument === this.#pdfDocument) {
+ this.#ready = true;
+ }
+ });
+ }
+ async dispatchWillSave() {
+ return this.#scripting?.dispatchEventInSandbox({
+ id: "doc",
+ name: "WillSave"
+ });
+ }
+ async dispatchDidSave() {
+ return this.#scripting?.dispatchEventInSandbox({
+ id: "doc",
+ name: "DidSave"
+ });
+ }
+ async dispatchWillPrint() {
+ if (!this.#scripting) {
+ return;
+ }
+ await this.#willPrintCapability?.promise;
+ this.#willPrintCapability = Promise.withResolvers();
+ try {
+ await this.#scripting.dispatchEventInSandbox({
+ id: "doc",
+ name: "WillPrint"
+ });
+ } catch (ex) {
+ this.#willPrintCapability.resolve();
+ this.#willPrintCapability = null;
+ throw ex;
+ }
+ await this.#willPrintCapability.promise;
+ }
+ async dispatchDidPrint() {
+ return this.#scripting?.dispatchEventInSandbox({
+ id: "doc",
+ name: "DidPrint"
+ });
+ }
+ get destroyPromise() {
+ return this.#destroyCapability?.promise || null;
+ }
+ get ready() {
+ return this.#ready;
+ }
+ get _pageOpenPending() {
+ return shadow(this, "_pageOpenPending", new Set());
+ }
+ get _visitedPages() {
+ return shadow(this, "_visitedPages", new Map());
+ }
+ async #updateFromSandbox(detail) {
+ const pdfViewer = this.#pdfViewer;
+ const isInPresentationMode = pdfViewer.isInPresentationMode || pdfViewer.isChangingPresentationMode;
+ const {
+ id,
+ siblings,
+ command,
+ value
+ } = detail;
+ if (!id) {
+ switch (command) {
+ case "clear":
+ console.clear();
+ break;
+ case "error":
+ console.error(value);
+ break;
+ case "layout":
+ if (!isInPresentationMode) {
+ const modes = apiPageLayoutToViewerModes(value);
+ pdfViewer.spreadMode = modes.spreadMode;
+ }
+ break;
+ case "page-num":
+ pdfViewer.currentPageNumber = value + 1;
+ break;
+ case "print":
+ await pdfViewer.pagesPromise;
+ this.#eventBus.dispatch("print", {
+ source: this
+ });
+ break;
+ case "println":
+ console.log(value);
+ break;
+ case "zoom":
+ if (!isInPresentationMode) {
+ pdfViewer.currentScaleValue = value;
+ }
+ break;
+ case "SaveAs":
+ this.#eventBus.dispatch("download", {
+ source: this
+ });
+ break;
+ case "FirstPage":
+ pdfViewer.currentPageNumber = 1;
+ break;
+ case "LastPage":
+ pdfViewer.currentPageNumber = pdfViewer.pagesCount;
+ break;
+ case "NextPage":
+ pdfViewer.nextPage();
+ break;
+ case "PrevPage":
+ pdfViewer.previousPage();
+ break;
+ case "ZoomViewIn":
+ if (!isInPresentationMode) {
+ pdfViewer.increaseScale();
+ }
+ break;
+ case "ZoomViewOut":
+ if (!isInPresentationMode) {
+ pdfViewer.decreaseScale();
+ }
+ break;
+ case "WillPrintFinished":
+ this.#willPrintCapability?.resolve();
+ this.#willPrintCapability = null;
+ break;
+ }
+ return;
+ }
+ if (isInPresentationMode && detail.focus) {
+ return;
+ }
+ delete detail.id;
+ delete detail.siblings;
+ const ids = siblings ? [id, ...siblings] : [id];
+ for (const elementId of ids) {
+ if (!this.#objectIds?.has(elementId)) {
+ continue;
+ }
+ const element = document.querySelector(`[data-element-id="${elementId}"]`);
+ if (element) {
+ element.dispatchEvent(new CustomEvent("updatefromsandbox", {
+ detail
+ }));
+ } else {
+ this.#pdfDocument?.annotationStorage.setValue(elementId, detail);
+ }
+ }
+ }
+ async #dispatchPageOpen(pageNumber, initialize = false) {
+ const pdfDocument = this.#pdfDocument,
+ visitedPages = this._visitedPages;
+ if (initialize) {
+ this.#closeCapability = Promise.withResolvers();
+ }
+ if (!this.#closeCapability) {
+ return;
+ }
+ const pageView = this.#pdfViewer.getPageView(pageNumber - 1);
+ if (pageView?.renderingState !== RenderingStates.FINISHED) {
+ this._pageOpenPending.add(pageNumber);
+ return;
+ }
+ this._pageOpenPending.delete(pageNumber);
+ const actionsPromise = (async () => {
+ const actions = await (!visitedPages.has(pageNumber) ? pageView.pdfPage?.getJSActions() : null);
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ await this.#scripting?.dispatchEventInSandbox({
+ id: "page",
+ name: "PageOpen",
+ pageNumber,
+ actions
+ });
+ })();
+ visitedPages.set(pageNumber, actionsPromise);
+ }
+ async #dispatchPageClose(pageNumber) {
+ const pdfDocument = this.#pdfDocument,
+ visitedPages = this._visitedPages;
+ if (!this.#closeCapability) {
+ return;
+ }
+ if (this._pageOpenPending.has(pageNumber)) {
+ return;
+ }
+ const actionsPromise = visitedPages.get(pageNumber);
+ if (!actionsPromise) {
+ return;
+ }
+ visitedPages.set(pageNumber, null);
+ await actionsPromise;
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ await this.#scripting?.dispatchEventInSandbox({
+ id: "page",
+ name: "PageClose",
+ pageNumber
+ });
+ }
+ #initScripting() {
+ this.#destroyCapability = Promise.withResolvers();
+ if (this.#scripting) {
+ throw new Error("#initScripting: Scripting already exists.");
+ }
+ return this.#externalServices.createScripting();
+ }
+ async #destroyScripting() {
+ this.#objectIds = null;
+ if (!this.#scripting) {
+ this.#pdfDocument = null;
+ this.#destroyCapability?.resolve();
+ return;
+ }
+ if (this.#closeCapability) {
+ await Promise.race([this.#closeCapability.promise, new Promise(resolve => {
+ setTimeout(resolve, 1000);
+ })]).catch(() => {});
+ this.#closeCapability = null;
+ }
+ this.#pdfDocument = null;
+ try {
+ await this.#scripting.destroySandbox();
+ } catch {}
+ this.#willPrintCapability?.reject(new Error("Scripting destroyed."));
+ this.#willPrintCapability = null;
+ this.#eventAC?.abort();
+ this.#eventAC = null;
+ this._pageOpenPending.clear();
+ this._visitedPages.clear();
+ this.#scripting = null;
+ this.#ready = false;
+ this.#destroyCapability?.resolve();
+ }
+}
+
+;// ./web/pdf_text_extractor.js
+/* unused harmony import specifier */ var pdf_text_extractor_internalOpt;
+
+class PdfTextExtractor {
+ #externalServices;
+ #textPromise;
+ #capability = Promise.withResolvers();
+ constructor(externalServices, pdfViewer, eventBus) {
+ this.#externalServices = externalServices;
+ eventBus.on("pagesinit", () => {
+ this.#capability.resolve(pdfViewer);
+ }, pdf_text_extractor_internalOpt);
+ eventBus.on("pagesdestroy", () => {
+ this.#capability.reject(new Error("pagesdestroy"));
+ this.#textPromise = null;
+ this.#capability = Promise.withResolvers();
+ }, pdf_text_extractor_internalOpt);
+ window.addEventListener("requestTextContent", ({
+ detail
+ }) => {
+ this.extractTextContent(detail.requestId);
+ });
+ }
+ async extractTextContent(requestId) {
+ if (!this.#textPromise) {
+ const textPromise = this.#textPromise = this.#capability.promise.then(pdfViewer => pdfViewer.getAllText());
+ textPromise.then(() => {
+ setTimeout(() => {
+ if (this.#textPromise === textPromise) {
+ this.#textPromise = null;
+ }
+ }, 5000);
+ });
+ }
+ this.#externalServices.reportText({
+ text: await this.#textPromise,
+ requestId
+ });
+ }
+}
+
+;// ./web/menu.js
+
+class Menu {
+ #triggeringButton;
+ #menu;
+ #menuItems;
+ #openMenuAC = null;
+ #menuAC = new AbortController();
+ #lastIndex = -1;
+ #onFocusOutBound = this.#onFocusOut.bind(this);
+ constructor(menuContainer, triggeringButton, menuItems) {
+ this.#menu = menuContainer;
+ this.#triggeringButton = triggeringButton;
+ this.#menuItems = Array.isArray(menuItems) ? menuItems : [...this.#menu.querySelectorAll("button")];
+ this.#setUpMenu();
+ }
+ #closeMenu() {
+ if (!this.#openMenuAC) {
+ return;
+ }
+ const menu = this.#menu;
+ this.#triggeringButton.ariaExpanded = "false";
+ this.#openMenuAC.abort();
+ this.#openMenuAC = null;
+ if (menu.contains(document.activeElement)) {
+ setTimeout(() => {
+ if (!menu.contains(document.activeElement)) {
+ this.#triggeringButton.focus();
+ }
+ }, 0);
+ }
+ this.#lastIndex = -1;
+ }
+ #openMenu() {
+ if (this.#openMenuAC) {
+ return;
+ }
+ const menu = this.#menu;
+ this.#triggeringButton.ariaExpanded = "true";
+ this.#openMenuAC = new AbortController();
+ const signal = AbortSignal.any([this.#menuAC.signal, this.#openMenuAC.signal]);
+ window.addEventListener("pointerdown", ({
+ target
+ }) => {
+ if (!this.#triggeringButton.contains(target) && !menu.contains(target)) {
+ this.#closeMenu();
+ }
+ }, {
+ signal
+ });
+ const closeMenu = this.#closeMenu.bind(this);
+ window.addEventListener("blur", closeMenu, {
+ signal
+ });
+ menu.addEventListener("focusout", this.#onFocusOutBound, {
+ signal
+ });
+ }
+ #onFocusOut({
+ relatedTarget
+ }) {
+ if (!this.#triggeringButton.contains(relatedTarget) && !this.#menu.contains(relatedTarget)) {
+ this.#closeMenu();
+ }
+ }
+ #setUpMenu() {
+ this.#triggeringButton.addEventListener("click", e => {
+ if (this.#openMenuAC) {
+ this.#closeMenu();
+ return;
+ }
+ this.#openMenu();
+ });
+ this.#triggeringButton.addEventListener("focusout", this.#onFocusOutBound);
+ const {
+ signal
+ } = this.#menuAC;
+ this.#menu.addEventListener("keydown", e => {
+ switch (e.key) {
+ case "Escape":
+ this.#closeMenu();
+ stopEvent(e);
+ break;
+ case "ArrowDown":
+ this.#goToNextItem(e.target, true);
+ stopEvent(e);
+ break;
+ case "ArrowUp":
+ this.#goToNextItem(e.target, false);
+ stopEvent(e);
+ break;
+ case "Home":
+ this.#goToFirstLast(false);
+ stopEvent(e);
+ break;
+ case "End":
+ this.#goToFirstLast(true);
+ stopEvent(e);
+ break;
+ default:
+ const {
+ key
+ } = e;
+ if (!/^\p{L}$/u.test(key)) {
+ break;
+ }
+ const char = key.toLocaleLowerCase();
+ this.#goToNextItem(e.target, true, item => item.textContent.trim().toLowerCase().startsWith(char));
+ stopEvent(e);
+ break;
+ }
+ }, {
+ signal,
+ capture: true
+ });
+ this.#menu.addEventListener("contextmenu", noContextMenu, {
+ signal
+ });
+ this.#menu.addEventListener("click", this.#closeMenu.bind(this), {
+ signal,
+ capture: true
+ });
+ this.#triggeringButton.addEventListener("keydown", e => {
+ switch (e.key) {
+ case " ":
+ case "Enter":
+ case "ArrowDown":
+ case "Home":
+ stopEvent(e);
+ if (!this.#openMenuAC) {
+ this.#openMenu();
+ }
+ this.#goToFirstLast(false);
+ break;
+ case "ArrowUp":
+ case "End":
+ stopEvent(e);
+ if (!this.#openMenuAC) {
+ this.#openMenu();
+ }
+ this.#goToFirstLast(true);
+ break;
+ case "Escape":
+ this.#closeMenu();
+ stopEvent(e);
+ break;
+ }
+ }, {
+ signal
+ });
+ }
+ #goToNextItem(element, forward, check = () => true) {
+ const index = this.#lastIndex === -1 ? this.#menuItems.indexOf(element) : this.#lastIndex;
+ const len = this.#menuItems.length;
+ const increment = forward ? 1 : len - 1;
+ for (let i = (index + increment) % len; i !== index; i = (i + increment) % len) {
+ const menuItem = this.#menuItems[i];
+ if (!menuItem.disabled && !menuItem.classList.contains("hidden") && check(menuItem)) {
+ menuItem.focus();
+ this.#lastIndex = i;
+ break;
+ }
+ }
+ }
+ #goToFirstLast(last = false) {
+ const i = this.#menuItems[last ? "findLastIndex" : "findIndex"](item => !item.disabled && !item.classList.contains("hidden"));
+ if (i >= 0) {
+ this.#menuItems[i].focus();
+ this.#lastIndex = i;
+ }
+ }
+ destroy() {
+ this.#closeMenu();
+ this.#menuAC?.abort();
+ this.#menuAC = null;
+ }
+}
+
+;// ./web/pdf_thumbnail_view.js
+
+
+
+
+const DRAW_UPSCALE_FACTOR = 2;
+const MAX_NUM_SCALING_STEPS = 3;
+const THUMBNAIL_WIDTH = 126;
+function getTempCanvas(width, height) {
+ const canvas = new OffscreenCanvas(width, height);
+ const ctx = canvas.getContext("2d", {
+ alpha: false
+ });
+ ctx.save();
+ ctx.fillStyle = "rgb(255, 255, 255)";
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+ return [canvas, ctx];
+}
+class PDFThumbnailView extends RenderableView {
+ #renderingState = RenderingStates.INITIAL;
+ constructor({
+ container,
+ eventBus,
+ id,
+ defaultViewport,
+ optionalContentConfigPromise,
+ linkService,
+ renderingQueue,
+ maxCanvasPixels,
+ maxCanvasDim,
+ pageColors,
+ enableSplitMerge = false
+ }) {
+ super();
+ this.id = id;
+ this.renderingId = `thumbnail${id}`;
+ this.pageLabel = null;
+ this.pdfPage = null;
+ this.rotation = 0;
+ this.viewport = defaultViewport;
+ this.pdfPageRotate = defaultViewport.rotation;
+ this._optionalContentConfigPromise = optionalContentConfigPromise || null;
+ this.maxCanvasPixels = maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
+ this.maxCanvasDim = maxCanvasDim || AppOptions.get("maxCanvasDim");
+ this.pageColors = pageColors || null;
+ this.eventBus = eventBus;
+ this.linkService = linkService;
+ this.renderingQueue = renderingQueue;
+ this.placeholder = null;
+ const thumbnailContainer = this.div = document.createElement("div");
+ thumbnailContainer.className = "thumbnail";
+ thumbnailContainer.setAttribute("page-number", id);
+ const imageContainer = this.imageContainer = document.createElement("div");
+ thumbnailContainer.append(imageContainer);
+ imageContainer.classList.add("thumbnailImageContainer", "missingThumbnailImage");
+ imageContainer.role = "button";
+ imageContainer.tabIndex = -1;
+ imageContainer.draggable = false;
+ imageContainer.setAttribute("page-number", id);
+ imageContainer.setAttribute("data-l10n-id", "pdfjs-thumb-page-title1");
+ imageContainer.setAttribute("data-l10n-args", this.#getPageL10nArgs(true));
+ const image = this.image = document.createElement("img");
+ imageContainer.append(image);
+ if (enableSplitMerge) {
+ const checkbox = this.checkbox = document.createElement("input");
+ checkbox.type = "checkbox";
+ checkbox.tabIndex = -1;
+ checkbox.setAttribute("data-l10n-id", "pdfjs-thumb-page-checkbox1");
+ checkbox.setAttribute("data-l10n-args", this.#getPageL10nArgs());
+ thumbnailContainer.append(checkbox);
+ this.pasteButton = null;
+ }
+ this.#updateDims();
+ container.append(thumbnailContainer);
+ }
+ clone(container, id) {
+ const thumbnailView = new PDFThumbnailView({
+ container,
+ id,
+ eventBus: this.eventBus,
+ defaultViewport: this.viewport,
+ optionalContentConfigPromise: this._optionalContentConfigPromise,
+ linkService: this.linkService,
+ renderingQueue: this.renderingQueue,
+ maxCanvasPixels: this.maxCanvasPixels,
+ maxCanvasDim: this.maxCanvasDim,
+ pageColors: this.pageColors,
+ enableSplitMerge: !!this.checkbox
+ });
+ const {
+ imageContainer
+ } = this;
+ if (!imageContainer.classList.contains("missingThumbnailImage")) {
+ thumbnailView.image.replaceWith(this.image.cloneNode(true));
+ thumbnailView.imageContainer.classList.remove("missingThumbnailImage");
+ }
+ return thumbnailView;
+ }
+ addPasteButton(pasteCallback) {
+ if (this.pasteButton) {
+ return;
+ }
+ const pasteButton = this.pasteButton = document.createElement("button");
+ pasteButton.classList.add("thumbnailPasteButton", "viewsManagerButton");
+ pasteButton.tabIndex = 0;
+ pasteButton.setAttribute("data-l10n-id", "pdfjs-views-manager-paste-button-after");
+ pasteButton.setAttribute("data-l10n-args", this.#getPageL10nArgs());
+ const span = document.createElement("span");
+ span.setAttribute("data-l10n-id", "pdfjs-views-manager-paste-button-label");
+ pasteButton.append(span);
+ pasteButton.addEventListener("click", () => {
+ pasteCallback(this.id);
+ });
+ if (this.id === 1) {
+ const prevPasteButton = this.prevPasteButton = pasteButton.cloneNode(true);
+ prevPasteButton.setAttribute("data-l10n-id", "pdfjs-views-manager-paste-button-before");
+ prevPasteButton.addEventListener("click", () => {
+ pasteCallback(0);
+ });
+ this.imageContainer.before(prevPasteButton);
+ }
+ this.imageContainer.after(pasteButton);
+ }
+ removePasteButton() {
+ this.pasteButton?.remove();
+ this.pasteButton = null;
+ this.prevPasteButton?.remove();
+ this.prevPasteButton = null;
+ }
+ toggleSelected(isSelected) {
+ if (this.checkbox) {
+ this.checkbox.checked = isSelected;
+ }
+ }
+ updateId(newId) {
+ this.id = newId;
+ this.renderingId = `thumbnail${newId}`;
+ this.div.setAttribute("page-number", newId);
+ this.imageContainer.setAttribute("page-number", newId);
+ this.setPageLabel(this.pageLabel);
+ }
+ #updateDims() {
+ const {
+ width,
+ height
+ } = this.viewport;
+ const ratio = width / height;
+ const canvasWidth = this.canvasWidth = THUMBNAIL_WIDTH;
+ const canvasHeight = this.canvasHeight = canvasWidth / ratio | 0;
+ this.scale = canvasWidth / width;
+ this.imageContainer.style.height = `${canvasHeight}px`;
+ }
+ get renderingState() {
+ return this.#renderingState;
+ }
+ set renderingState(state) {
+ this.#renderingState = state;
+ }
+ setPdfPage(pdfPage) {
+ this.pdfPage = pdfPage;
+ this.pdfPageRotate = pdfPage.rotate;
+ const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = pdfPage.getViewport({
+ scale: 1,
+ rotation: totalRotation
+ });
+ this.reset();
+ }
+ reset() {
+ this.cancelRendering();
+ this.renderingState = RenderingStates.INITIAL;
+ this.#updateDims();
+ const {
+ image,
+ imageContainer
+ } = this;
+ const url = image.src;
+ if (url) {
+ URL.revokeObjectURL(url);
+ image.src = "";
+ imageContainer.removeAttribute("data-l10n-id");
+ imageContainer.removeAttribute("data-l10n-args");
+ imageContainer.classList.add("missingThumbnailImage");
+ }
+ }
+ destroy() {
+ this.reset();
+ this.toggleCurrent(false);
+ this.div.remove();
+ }
+ update({
+ rotation = null
+ }) {
+ if (typeof rotation === "number") {
+ this.rotation = rotation;
+ }
+ const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = this.viewport.clone({
+ scale: 1,
+ rotation: totalRotation
+ });
+ this.reset();
+ }
+ toggleCurrent(isCurrent) {
+ const {
+ imageContainer
+ } = this;
+ if (isCurrent) {
+ imageContainer.ariaCurrent = "page";
+ imageContainer.tabIndex = 0;
+ if (this.checkbox) {
+ this.checkbox.tabIndex = 0;
+ }
+ } else {
+ imageContainer.ariaCurrent = false;
+ imageContainer.tabIndex = -1;
+ if (this.checkbox) {
+ this.checkbox.tabIndex = -1;
+ }
+ }
+ }
+ cancelRendering() {
+ if (this.renderTask) {
+ this.renderTask.cancel();
+ this.renderTask = null;
+ }
+ this.resume = null;
+ }
+ #getPageDrawContext(upscaleFactor = 1) {
+ const outputScale = new OutputScale();
+ const width = upscaleFactor * this.canvasWidth,
+ height = upscaleFactor * this.canvasHeight;
+ outputScale.limitCanvas(width, height, this.maxCanvasPixels, this.maxCanvasDim);
+ const canvas = document.createElement("canvas");
+ canvas.width = width * outputScale.sx | 0;
+ canvas.height = height * outputScale.sy | 0;
+ const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null;
+ return {
+ canvas,
+ transform
+ };
+ }
+ async #convertCanvasToImage(canvas) {
+ if (this.renderingState !== RenderingStates.FINISHED) {
+ throw new Error("#convertCanvasToImage: Rendering has not finished.");
+ }
+ const reducedCanvas = this.#reduceImage(canvas);
+ const {
+ imageContainer,
+ image
+ } = this;
+ const {
+ promise,
+ resolve
+ } = Promise.withResolvers();
+ reducedCanvas.toBlob(resolve);
+ const blob = await promise;
+ image.src = URL.createObjectURL(blob);
+ image.setAttribute("data-l10n-id", "pdfjs-thumb-page-canvas");
+ image.setAttribute("data-l10n-args", this.#getPageL10nArgs());
+ imageContainer.classList.remove("missingThumbnailImage");
+ }
+ async draw() {
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ console.error("Must be in new state before drawing");
+ return;
+ }
+ const {
+ pageColors,
+ pdfPage
+ } = this;
+ if (!pdfPage) {
+ this.renderingState = RenderingStates.FINISHED;
+ throw new Error("pdfPage is not loaded");
+ }
+ this.renderingState = RenderingStates.RUNNING;
+ const {
+ canvas,
+ transform
+ } = this.#getPageDrawContext(DRAW_UPSCALE_FACTOR);
+ const drawViewport = this.viewport.clone({
+ scale: DRAW_UPSCALE_FACTOR * this.scale
+ });
+ const renderContinueCallback = cont => {
+ if (!this.renderingQueue.isHighestPriority(this)) {
+ this.renderingState = RenderingStates.PAUSED;
+ this.resume = () => {
+ this.renderingState = RenderingStates.RUNNING;
+ cont();
+ };
+ return;
+ }
+ cont();
+ };
+ const renderContext = {
+ canvas,
+ transform,
+ viewport: drawViewport,
+ optionalContentConfigPromise: this._optionalContentConfigPromise,
+ pageColors
+ };
+ const renderTask = this.renderTask = pdfPage.render(renderContext);
+ renderTask.onContinue = renderContinueCallback;
+ let error = null;
+ try {
+ await renderTask.promise;
+ } catch (e) {
+ if (e instanceof RenderingCancelledException) {
+ return;
+ }
+ error = e;
+ } finally {
+ if (renderTask === this.renderTask) {
+ this.renderTask = null;
+ }
+ }
+ this.renderingState = RenderingStates.FINISHED;
+ await this.#convertCanvasToImage(canvas);
+ this.eventBus.dispatch("thumbnailrendered", {
+ source: this,
+ pageNumber: this.id,
+ pdfPage
+ });
+ if (error) {
+ throw error;
+ }
+ }
+ setImage(pageView) {
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ return;
+ }
+ const {
+ thumbnailCanvas: canvas,
+ pdfPage,
+ scale
+ } = pageView;
+ if (!canvas) {
+ return;
+ }
+ if (!this.pdfPage) {
+ this.setPdfPage(pdfPage);
+ }
+ if (scale < this.scale) {
+ return;
+ }
+ this.renderingState = RenderingStates.FINISHED;
+ this.#convertCanvasToImage(canvas);
+ }
+ #getReducedImageDims(canvas) {
+ const width = canvas.width << MAX_NUM_SCALING_STEPS,
+ height = canvas.height << MAX_NUM_SCALING_STEPS;
+ const outputScale = new OutputScale();
+ outputScale.sx = outputScale.sy = 1;
+ outputScale.limitCanvas(width, height, this.maxCanvasPixels, this.maxCanvasDim);
+ return [width * outputScale.sx | 0, height * outputScale.sy | 0];
+ }
+ #reduceImage(img) {
+ const {
+ canvas
+ } = this.#getPageDrawContext(1);
+ const ctx = canvas.getContext("2d", {
+ alpha: false,
+ willReadFrequently: false
+ });
+ if (img.width <= 2 * canvas.width) {
+ ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
+ return canvas;
+ }
+ let [reducedWidth, reducedHeight] = this.#getReducedImageDims(canvas);
+ const [reducedImage, reducedImageCtx] = getTempCanvas(reducedWidth, reducedHeight);
+ while (reducedWidth > img.width || reducedHeight > img.height) {
+ reducedWidth >>= 1;
+ reducedHeight >>= 1;
+ }
+ reducedImageCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, reducedWidth, reducedHeight);
+ while (reducedWidth > 2 * canvas.width) {
+ reducedImageCtx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, reducedWidth >> 1, reducedHeight >> 1);
+ reducedWidth >>= 1;
+ reducedHeight >>= 1;
+ }
+ ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight, 0, 0, canvas.width, canvas.height);
+ return canvas;
+ }
+ #getPageL10nArgs(hasTotal = false) {
+ return JSON.stringify({
+ page: this.pageLabel ?? this.id,
+ total: hasTotal ? this.linkService.pagesCount : undefined
+ });
+ }
+ setPageLabel(label) {
+ this.pageLabel = typeof label === "string" ? label : null;
+ this.imageContainer.setAttribute("data-l10n-args", this.#getPageL10nArgs(true));
+ this.image.setAttribute("data-l10n-args", this.#getPageL10nArgs());
+ this.checkbox?.setAttribute("data-l10n-args", this.#getPageL10nArgs());
+ }
+}
+
+;// ./web/pdf_thumbnail_viewer.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const SCROLL_OPTIONS = {
+ behavior: "instant",
+ block: "nearest",
+ inline: "nearest",
+ container: "nearest"
+};
+const DRAG_THRESHOLD_IN_PIXELS = 5;
+const PIXELS_TO_SCROLL_WHEN_DRAGGING = 20;
+const SPACE_FOR_DRAG_MARKER_WHEN_NO_NEXT_ELEMENT = 15;
+class PDFThumbnailViewer {
+ static #draggingScaleFactor = 0;
+ #enableMerge = false;
+ #enableSplitMerge = false;
+ #dragAC = null;
+ #abortSignal = undefined;
+ #externalDragActive = false;
+ #draggedContainer = null;
+ #thumbnailsPositions = null;
+ #lastDraggedOverIndex = NaN;
+ #selectedPages = null;
+ #draggedImageX = 0;
+ #draggedImageY = 0;
+ #draggedImageWidth = 0;
+ #draggedImageHeight = 0;
+ #draggedImageOffsetX = 0;
+ #draggedImageOffsetY = 0;
+ #dragMarker = null;
+ #pageNumberToRemove = NaN;
+ #currentScrollBottom = 0;
+ #currentScrollTop = 0;
+ #pagesMapper = null;
+ #manageExportButton = null;
+ #manageDeleteButton = null;
+ #manageCopyButton = null;
+ #manageCutButton = null;
+ #copiedThumbnails = null;
+ #savedThumbnails = null;
+ #deletedPageNumbers = null;
+ #copiedPageNumbers = null;
+ #boundPastePages = this.#pastePages.bind(this);
+ #isCut = false;
+ #isOneColumnView = false;
+ #scrollableContainerWidth = 0;
+ #scrollableContainerHeight = 0;
+ #statusLabel = null;
+ #statusBar = null;
+ #deselectButton = null;
+ #undoBar = null;
+ #undoLabel = null;
+ #undoButton = null;
+ #undoCloseButton = null;
+ #waitingBar = null;
+ #isInPasteMode = false;
+ #hasUndoBarVisible = false;
+ #newBadge = null;
+ constructor({
+ container,
+ eventBus,
+ linkService,
+ renderingQueue,
+ maxCanvasPixels,
+ maxCanvasDim,
+ pageColors,
+ abortSignal,
+ enableMerge,
+ enableSplitMerge,
+ enableNewBadge,
+ statusBar,
+ undoBar,
+ waitingBar,
+ manageMenu,
+ addFileComponent
+ }) {
+ this.scrollableContainer = container.parentElement;
+ this.container = container;
+ this.eventBus = eventBus;
+ this.linkService = linkService;
+ this.renderingQueue = renderingQueue;
+ this.maxCanvasPixels = maxCanvasPixels;
+ this.maxCanvasDim = maxCanvasDim;
+ this.pageColors = pageColors || null;
+ this.#abortSignal = abortSignal;
+ this.#enableMerge = enableMerge || false;
+ this.#enableSplitMerge = enableSplitMerge || false;
+ this.#statusLabel = statusBar?.viewsManagerStatusActionLabel || null;
+ this.#deselectButton = statusBar?.viewsManagerStatusActionDeselectButton || null;
+ this.#statusBar = statusBar?.viewsManagerStatusAction || null;
+ this.#undoBar = undoBar?.viewsManagerStatusUndo || null;
+ this.#undoLabel = undoBar?.viewsManagerStatusUndoLabel || null;
+ this.#undoButton = undoBar?.viewsManagerStatusUndoButton || null;
+ this.#undoCloseButton = undoBar?.viewsManagerStatusUndoCloseButton || null;
+ this.#waitingBar = waitingBar || null;
+ if (this.#enableSplitMerge && manageMenu) {
+ const {
+ button: menuButton,
+ menu,
+ copy,
+ cut,
+ delete: del,
+ exportSelected
+ } = manageMenu;
+ if (enableNewBadge) {
+ const newSpan = document.createElement("span");
+ newSpan.setAttribute("data-l10n-id", "pdfjs-new-badge-content");
+ newSpan.classList.add("newBadge");
+ menuButton.parentElement.before(newSpan);
+ this.#newBadge = newSpan;
+ }
+ eventBus.on("pagesloaded", () => {
+ menuButton.disabled = false;
+ }, {
+ once: true,
+ ...internalOpt
+ });
+ this._manageMenu = new Menu(menu, menuButton, [copy, cut, del, exportSelected]);
+ this.#manageExportButton = exportSelected;
+ exportSelected.addEventListener("click", this.#saveExtractedPages.bind(this));
+ this.#manageDeleteButton = del;
+ del.addEventListener("click", this.#deletePages.bind(this, "delete"));
+ this.#manageCopyButton = copy;
+ copy.addEventListener("click", this.#copyPages.bind(this));
+ this.#manageCutButton = cut;
+ cut.addEventListener("click", this.#cutPages.bind(this));
+ this.#toggleMenuEntries(false);
+ menuButton.disabled = true;
+ eventBus.on("editingaction", ({
+ name
+ }) => {
+ switch (name) {
+ case "copyPage":
+ this.#copyPages();
+ break;
+ case "cutPage":
+ this.#cutPages();
+ break;
+ case "deletePage":
+ this.#deletePages("delete");
+ break;
+ case "savePage":
+ this.#saveExtractedPages();
+ break;
+ }
+ }, internalOpt);
+ this.container.addEventListener("contextmenu", e => {
+ eventBus.dispatch("editingstateschanged", {
+ source: this,
+ details: {
+ thumbnailId: parseInt(e.target.closest(".thumbnailImageContainer")?.parentElement.getAttribute("page-number"), 10) ?? -1,
+ hasSelectedPages: !!this.#selectedPages?.size,
+ canDeletePages: this.#canDelete()
+ }
+ });
+ }, {
+ signal: abortSignal,
+ passive: true
+ });
+ this.#undoButton?.addEventListener("click", this.#undo.bind(this));
+ this.#undoCloseButton?.addEventListener("click", this.#dismissUndo.bind(this, true));
+ this.#deselectButton?.addEventListener("click", () => {
+ this.#clearSelection();
+ this.#toggleMenuEntries(false);
+ this.#updateStatus("select");
+ });
+ this.#deselectButton.classList.toggle("hidden", true);
+ if (this.#enableMerge && addFileComponent) {
+ const {
+ picker,
+ button
+ } = addFileComponent;
+ picker.addEventListener("change", () => {
+ const files = Array.from(picker.files ?? []);
+ if (files.length) {
+ this.#mergeFiles(files, this._currentPageNumber - 1);
+ }
+ });
+ button.addEventListener("click", () => {
+ picker.click();
+ });
+ this.#waitingBar.closeButton?.addEventListener("click", () => {
+ this.#toggleBar("status");
+ picker.value = "";
+ });
+ }
+ } else {
+ manageMenu.button.hidden = true;
+ }
+ this.scroll = watchScroll(this.scrollableContainer, this.#scrollUpdated.bind(this), abortSignal);
+ this.#resetView();
+ this.#addEventListeners();
+ }
+ #scrollUpdated() {
+ this.renderingQueue.renderHighestPriority();
+ }
+ async #mergeFiles(files, insertAfter) {
+ this.#toggleBar("waiting", "pdfjs-views-manager-waiting-for-file");
+ const entries = [];
+ for (const file of files) {
+ const isImage = file.type?.startsWith("image/");
+ if (!isImage && file.type !== "application/pdf") {
+ const magic = await file.slice(0, 5).text();
+ if (magic !== "%PDF-") {
+ continue;
+ }
+ }
+ if (isImage) {
+ let bitmap;
+ try {
+ bitmap = await PDFThumbnailViewer.#fileToImageBitmap(file);
+ } catch {
+ continue;
+ }
+ entries.push({
+ image: bitmap,
+ insertAfter
+ });
+ } else {
+ entries.push({
+ document: await file.bytes(),
+ insertAfter
+ });
+ }
+ }
+ if (entries.length === 0) {
+ this.#toggleBar("status");
+ return;
+ }
+ const pagesCount = this.#pagesMapper.pagesNumber;
+ const data = this.hasStructuralChanges() ? this.getStructuralChanges() : {
+ pageInfos: [{
+ document: null
+ }],
+ copyLevels: null
+ };
+ data.pageInfos.push(...entries);
+ this.eventBus.on("pagesloaded", () => {
+ this.#selectedPages = null;
+ this.#updateMenuEntries();
+ this.#toggleBar("status");
+ const newPagesCount = this.#pagesMapper.pagesNumber;
+ const insertedPagesCount = newPagesCount - pagesCount;
+ for (let i = insertAfter + 1, ii = insertAfter + 1 + insertedPagesCount; i < ii; i++) {
+ this._thumbnails[i].checkbox.checked = true;
+ this.#selectPage(i + 1, true);
+ }
+ if (insertedPagesCount) {
+ this.#updateCurrentPage(insertAfter + 2, true);
+ }
+ }, {
+ once: true,
+ ...internalOpt
+ });
+ this.#reportTelemetry({
+ action: "merge"
+ });
+ this.eventBus.dispatch("saveandload", {
+ source: this,
+ data
+ });
+ }
+ getThumbnail(index) {
+ return this._thumbnails[index];
+ }
+ #getVisibleThumbs() {
+ return getVisibleElements({
+ scrollEl: this.scrollableContainer,
+ views: this._thumbnails
+ });
+ }
+ #resetCurrentThumbnail(newPageNumber) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const thumbnailView = this._thumbnails[this._currentPageNumber - 1];
+ thumbnailView?.toggleCurrent(false);
+ this._currentPageNumber = newPageNumber;
+ }
+ scrollThumbnailIntoView(pageNumber) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const thumbnailView = this._thumbnails[pageNumber - 1];
+ if (!thumbnailView) {
+ console.error('scrollThumbnailIntoView: Invalid "pageNumber" parameter.');
+ return;
+ }
+ if (pageNumber !== this._currentPageNumber) {
+ this.#resetCurrentThumbnail(pageNumber);
+ thumbnailView.toggleCurrent(true);
+ }
+ const {
+ first,
+ last,
+ views
+ } = this.#getVisibleThumbs();
+ if (views.length > 0) {
+ let shouldScroll = false;
+ if (pageNumber <= first.id || pageNumber >= last.id) {
+ shouldScroll = true;
+ } else {
+ for (const {
+ id,
+ percent
+ } of views) {
+ if (id !== pageNumber) {
+ continue;
+ }
+ shouldScroll = percent < 100;
+ break;
+ }
+ }
+ if (shouldScroll) {
+ thumbnailView.div.scrollIntoView(SCROLL_OPTIONS);
+ }
+ }
+ this._currentPageNumber = pageNumber;
+ }
+ get pagesRotation() {
+ return this._pagesRotation;
+ }
+ set pagesRotation(rotation) {
+ if (!isValidRotation(rotation)) {
+ throw new Error("Invalid thumbnails rotation angle.");
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (this._pagesRotation === rotation) {
+ return;
+ }
+ this._pagesRotation = rotation;
+ const updateArgs = {
+ rotation
+ };
+ for (const thumbnail of this._thumbnails) {
+ thumbnail.update(updateArgs);
+ }
+ }
+ cleanup() {
+ for (const thumbnail of this._thumbnails) {
+ if (thumbnail.renderingState !== RenderingStates.FINISHED) {
+ thumbnail.reset();
+ }
+ }
+ }
+ #resetView() {
+ this._thumbnails = [];
+ this._currentPageNumber = 1;
+ this._pageLabels = null;
+ this._pagesRotation = 0;
+ this.container.textContent = "";
+ }
+ setDocument(pdfDocument) {
+ if (this.pdfDocument) {
+ this.#cancelRendering();
+ this.#resetView();
+ }
+ this.pdfDocument = pdfDocument;
+ if (!pdfDocument) {
+ return;
+ }
+ this.#pagesMapper = pdfDocument.pagesMapper;
+ const firstPagePromise = pdfDocument.getPage(1);
+ const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
+ intent: "display"
+ });
+ firstPagePromise.then(firstPdfPage => {
+ const pagesCount = pdfDocument.numPages;
+ const viewport = firstPdfPage.getViewport({
+ scale: 1
+ });
+ const fragment = document.createDocumentFragment();
+ for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ const thumbnail = new PDFThumbnailView({
+ container: fragment,
+ eventBus: this.eventBus,
+ id: pageNum,
+ defaultViewport: viewport.clone(),
+ optionalContentConfigPromise,
+ linkService: this.linkService,
+ renderingQueue: this.renderingQueue,
+ maxCanvasPixels: this.maxCanvasPixels,
+ maxCanvasDim: this.maxCanvasDim,
+ pageColors: this.pageColors,
+ enableSplitMerge: this.#enableSplitMerge
+ });
+ this._thumbnails.push(thumbnail);
+ }
+ this._thumbnails[0]?.setPdfPage(firstPdfPage);
+ const thumbnailView = this._thumbnails[this._currentPageNumber - 1];
+ thumbnailView.toggleCurrent(true);
+ this.container.append(fragment);
+ this.eventBus.dispatch("thumbnailsloaded", {
+ source: this
+ });
+ }).catch(reason => {
+ console.error("Unable to initialize thumbnail viewer", reason);
+ });
+ }
+ #cancelRendering() {
+ for (const thumbnail of this._thumbnails) {
+ thumbnail.cancelRendering();
+ }
+ }
+ setPageLabels(labels) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (!labels) {
+ this._pageLabels = null;
+ } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) {
+ this._pageLabels = null;
+ console.error("PDFThumbnailViewer_setPageLabels: Invalid page labels.");
+ } else {
+ this._pageLabels = labels;
+ }
+ for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
+ this._thumbnails[i].setPageLabel(this._pageLabels?.[i] ?? null);
+ }
+ }
+ async #ensurePdfPageLoaded(thumbView) {
+ if (thumbView.pdfPage) {
+ return thumbView.pdfPage;
+ }
+ try {
+ const pdfPage = await this.pdfDocument.getPage(thumbView.id);
+ if (!thumbView.pdfPage) {
+ thumbView.setPdfPage(pdfPage);
+ }
+ return pdfPage;
+ } catch (reason) {
+ console.error("Unable to get page for thumb view", reason);
+ return null;
+ }
+ }
+ #getScrollAhead(visible) {
+ if (visible.first?.id === 1) {
+ return true;
+ } else if (visible.last?.id === this._thumbnails.length) {
+ return false;
+ }
+ return this.scroll.down;
+ }
+ forceRendering() {
+ const visibleThumbs = this.#getVisibleThumbs();
+ const scrollAhead = this.#getScrollAhead(visibleThumbs);
+ const thumbView = this.renderingQueue.getHighestPriority(visibleThumbs, this._thumbnails, scrollAhead, false, true);
+ if (thumbView) {
+ this.#ensurePdfPageLoaded(thumbView).then(() => {
+ this.renderingQueue.renderView(thumbView);
+ });
+ return true;
+ }
+ return false;
+ }
+ hasStructuralChanges() {
+ return this.#pagesMapper?.hasBeenAltered() || false;
+ }
+ getStructuralChanges() {
+ return this.#pagesMapper?.getPageMappingForSaving() || null;
+ }
+ static #getScaleFactor(image) {
+ return PDFThumbnailViewer.#draggingScaleFactor ||= parseFloat(getComputedStyle(image).getPropertyValue("--thumbnail-dragging-scale"));
+ }
+ static #fitImageDimensions(width, height, {
+ minSide = 0,
+ maxSide
+ }) {
+ const longest = Math.max(width, height);
+ let scale = 1;
+ if (minSide > 0 && longest < minSide) {
+ scale = minSide / longest;
+ } else if (longest > maxSide) {
+ scale = maxSide / longest;
+ }
+ return scale === 1 ? {
+ width,
+ height
+ } : {
+ width: Math.max(1, Math.round(width * scale)),
+ height: Math.max(1, Math.round(height * scale))
+ };
+ }
+ static async #fileToImageBitmap(file) {
+ const MIN_RASTER_SIDE = 1024;
+ const MAX_RASTER_SIDE = 4096;
+ if (file.type !== "image/svg+xml") {
+ const bitmap = await createImageBitmap(file);
+ const {
+ width,
+ height
+ } = PDFThumbnailViewer.#fitImageDimensions(bitmap.width, bitmap.height, {
+ maxSide: MAX_RASTER_SIDE
+ });
+ if (width === bitmap.width && height === bitmap.height) {
+ return bitmap;
+ }
+ const canvas = new OffscreenCanvas(width, height);
+ const ctx = canvas.getContext("2d");
+ ctx.drawImage(bitmap, 0, 0, width, height);
+ bitmap.close();
+ return canvas.transferToImageBitmap();
+ }
+ const url = URL.createObjectURL(file);
+ try {
+ const image = new Image();
+ image.src = url;
+ await image.decode();
+ const {
+ width,
+ height
+ } = PDFThumbnailViewer.#fitImageDimensions(image.naturalWidth || MIN_RASTER_SIDE, image.naturalHeight || MIN_RASTER_SIDE, {
+ minSide: MIN_RASTER_SIDE,
+ maxSide: MAX_RASTER_SIDE
+ });
+ const canvas = new OffscreenCanvas(width, height);
+ const ctx = canvas.getContext("2d");
+ ctx.drawImage(image, 0, 0, width, height);
+ return canvas.transferToImageBitmap();
+ } finally {
+ URL.revokeObjectURL(url);
+ }
+ }
+ #updateThumbnails(currentPageNumber) {
+ this.#resetCurrentThumbnail(0);
+ let newCurrentPageNumber = 0;
+ const pagesMapper = this.#pagesMapper;
+ const prevThumbnails = this.#savedThumbnails = this._thumbnails;
+ const newThumbnails = this._thumbnails = [];
+ const fragment = document.createDocumentFragment();
+ const isCut = this.#isCut;
+ for (let i = 1, ii = pagesMapper.pagesNumber; i <= ii; i++) {
+ const prevPageNumber = pagesMapper.getPrevPageNumber(i);
+ if (prevPageNumber < 0) {
+ let thumbnail = this.#copiedThumbnails.get(-prevPageNumber);
+ thumbnail.checkbox.checked = false;
+ if (isCut) {
+ thumbnail.updateId(i);
+ fragment.append(thumbnail.div);
+ } else {
+ thumbnail = thumbnail.clone(fragment, i);
+ }
+ newThumbnails.push(thumbnail);
+ continue;
+ }
+ if (prevPageNumber === currentPageNumber) {
+ newCurrentPageNumber = i;
+ }
+ const newThumbnail = prevThumbnails[prevPageNumber - 1];
+ newThumbnails.push(newThumbnail);
+ newThumbnail.updateId(i);
+ newThumbnail.checkbox.checked = false;
+ fragment.append(newThumbnail.div);
+ }
+ this.container.replaceChildren(fragment);
+ return newCurrentPageNumber;
+ }
+ #onStartDragging(draggedThumbnail) {
+ this.#currentScrollTop = this.scrollableContainer.scrollTop;
+ this.#currentScrollBottom = this.#currentScrollTop + this.scrollableContainer.clientHeight;
+ this.#dragAC = new AbortController();
+ this.container.classList.add("isDragging");
+ this.#newBadge?.classList.add("hidden");
+ const startPageNumber = parseInt(draggedThumbnail.getAttribute("page-number"), 10);
+ this.#lastDraggedOverIndex = startPageNumber - 1;
+ if (!this.#selectedPages?.has(startPageNumber)) {
+ this.#pageNumberToRemove = startPageNumber;
+ this.#selectPage(startPageNumber, true);
+ }
+ for (const selected of this.#selectedPages) {
+ const thumbnail = this._thumbnails[selected - 1];
+ const placeholder = thumbnail.placeholder = document.createElement("div");
+ placeholder.classList.add("thumbnailImageContainer", "placeholder");
+ const {
+ div,
+ imageContainer
+ } = thumbnail;
+ div.classList.add("isDragging");
+ placeholder.style.height = getComputedStyle(imageContainer).height;
+ imageContainer.after(placeholder);
+ if (selected !== startPageNumber) {
+ imageContainer.classList.add("hidden");
+ continue;
+ }
+ if (this.#selectedPages.size === 1) {
+ imageContainer.classList.add("draggingThumbnail");
+ this.#draggedContainer = imageContainer;
+ continue;
+ }
+ const draggedContainer = this.#draggedContainer = document.createElement("div");
+ draggedContainer.classList.add("draggingThumbnail", "thumbnailImageContainer", "multiple");
+ draggedContainer.style.height = getComputedStyle(imageContainer).height;
+ imageContainer.replaceWith(draggedContainer);
+ imageContainer.classList.remove("thumbnailImageContainer");
+ draggedContainer.append(imageContainer);
+ draggedContainer.setAttribute("data-multiple-count", this.#selectedPages.size);
+ }
+ }
+ #onStopDragging(isDropping = false) {
+ const draggedContainer = this.#draggedContainer;
+ this.#draggedContainer = null;
+ const lastDraggedOverIndex = this.#lastDraggedOverIndex;
+ this.#lastDraggedOverIndex = NaN;
+ this.#dragMarker?.remove();
+ this.#dragMarker = null;
+ this.#dragAC.abort();
+ this.#dragAC = null;
+ this.#newBadge?.classList.remove("hidden");
+ this.container.classList.remove("isDragging");
+ for (const selected of this.#selectedPages) {
+ const thumbnail = this._thumbnails[selected - 1];
+ const {
+ div,
+ placeholder,
+ imageContainer
+ } = thumbnail;
+ placeholder.remove();
+ imageContainer.classList.remove("draggingThumbnail", "hidden");
+ div.classList.remove("isDragging");
+ }
+ if (draggedContainer.classList.contains("multiple")) {
+ const originalImageContainer = draggedContainer.firstElementChild;
+ draggedContainer.replaceWith(originalImageContainer);
+ originalImageContainer.classList.add("thumbnailImageContainer");
+ } else {
+ draggedContainer.style.translate = "";
+ }
+ const selectedPages = this.#selectedPages;
+ if (!isNaN(lastDraggedOverIndex) && isDropping && !(selectedPages.size === 1 && (selectedPages.has(lastDraggedOverIndex + 1) || selectedPages.has(lastDraggedOverIndex + 2)))) {
+ this._thumbnails[this._currentPageNumber - 1]?.toggleCurrent(false);
+ this._currentPageNumber = -1;
+ const newIndex = lastDraggedOverIndex + 1;
+ const pagesToMove = Array.from(selectedPages).sort((a, b) => a - b);
+ const pagesMapper = this.#pagesMapper;
+ const currentPageNumber = isNaN(this.#pageNumberToRemove) ? pagesToMove[0] : this.#pageNumberToRemove;
+ pagesMapper.movePages(selectedPages, pagesToMove, newIndex);
+ this.#updateCurrentPage(this.#updateThumbnails(currentPageNumber));
+ this.#thumbnailsPositions = null;
+ selectedPages.clear();
+ this.#pageNumberToRemove = NaN;
+ this.#toggleMenuEntries(false);
+ this.#updateStatus("select");
+ this.#reportTelemetry({
+ action: "move"
+ });
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper,
+ type: "move"
+ });
+ }
+ if (!isNaN(this.#pageNumberToRemove)) {
+ this.#selectPage(this.#pageNumberToRemove, false);
+ this.#pageNumberToRemove = NaN;
+ }
+ }
+ #clearSelection() {
+ for (const pageNumber of this.#selectedPages) {
+ this._thumbnails[pageNumber - 1].toggleSelected(false);
+ }
+ this.#selectedPages.clear();
+ }
+ #updateCurrentPage(currentPageNumber, forceFocus = false) {
+ setTimeout(() => {
+ this.forceRendering();
+ const newPageNumber = currentPageNumber || 1;
+ this.linkService.goToPage(newPageNumber);
+ const thumbnailView = this._thumbnails[newPageNumber - 1];
+ if (forceFocus || !this.container.contains(document.activeElement)) {
+ thumbnailView.imageContainer.focus();
+ }
+ }, 0);
+ }
+ #undo() {
+ this.#clearSelection();
+ this.#toggleMenuEntries(false);
+ this.#updateStatus("select");
+ if (this.#copiedThumbnails) {
+ this.#copiedThumbnails = null;
+ this.#pagesMapper.cancelCopy();
+ this.#togglePasteMode(false);
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper: this.#pagesMapper,
+ type: "cancelCopy"
+ });
+ }
+ this.#isCut = false;
+ if (this.#savedThumbnails) {
+ const currentThumb = this._thumbnails[this._currentPageNumber - 1];
+ currentThumb?.toggleCurrent(false);
+ const fragment = document.createDocumentFragment();
+ for (let i = 1, ii = this.#savedThumbnails.length; i <= ii; i++) {
+ const thumbnail = this.#savedThumbnails[i - 1];
+ thumbnail.updateId(i);
+ thumbnail.checkbox.checked = false;
+ fragment.append(thumbnail.div);
+ }
+ this.container.replaceChildren(fragment);
+ this._thumbnails = this.#savedThumbnails;
+ this.#savedThumbnails = null;
+ const newIdx = currentThumb ? this._thumbnails.indexOf(currentThumb) : -1;
+ this._currentPageNumber = newIdx + 1;
+ currentThumb?.toggleCurrent(newIdx !== -1);
+ this.#pagesMapper.cancelDelete();
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper: this.#pagesMapper,
+ type: "cancelDelete"
+ });
+ }
+ }
+ #dismissUndo(mustUpdateStatus) {
+ this.#copiedThumbnails = null;
+ if (this.#deletedPageNumbers) {
+ if (this.#savedThumbnails) {
+ for (const pageNumber of this.#deletedPageNumbers) {
+ this.#savedThumbnails[pageNumber - 1].destroy();
+ }
+ this.#savedThumbnails = null;
+ }
+ this.#deletedPageNumbers = null;
+ }
+ this.#isCut = false;
+ if (mustUpdateStatus) {
+ this.#updateStatus("select");
+ }
+ this.#togglePasteMode(false);
+ this.#pagesMapper.cleanSavedData();
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper: this.#pagesMapper,
+ type: "cleanSavedData"
+ });
+ }
+ #canDelete() {
+ const size = this.#selectedPages?.size || 0;
+ return size > 0 && size < this._thumbnails.length;
+ }
+ #toggleBar(type, message, args) {
+ this.#statusBar.classList.toggle("hidden", type !== "status");
+ this.#waitingBar.container.classList.toggle("hidden", type !== "waiting");
+ this.#undoBar.classList.toggle("hidden", type !== "undo");
+ this.#hasUndoBarVisible = type === "undo";
+ switch (type) {
+ case "waiting":
+ this.#waitingBar.label.setAttribute("data-l10n-id", message);
+ break;
+ case "undo":
+ this.#undoLabel.setAttribute("data-l10n-id", message);
+ if (args) {
+ this.#undoLabel.setAttribute("data-l10n-args", JSON.stringify(args));
+ }
+ break;
+ case "status":
+ if (args) {
+ this.#statusLabel.setAttribute("data-l10n-args", JSON.stringify(args));
+ } else {
+ this.#statusLabel.removeAttribute("data-l10n-args");
+ }
+ this.#newBadge?.classList.toggle("hidden", !!args);
+ this.#deselectButton.classList.toggle("hidden", !args);
+ break;
+ }
+ }
+ #togglePasteMode(enable) {
+ this.#isInPasteMode = enable;
+ if (enable) {
+ this.container.classList.add("pasteMode");
+ for (const thumbnail of this._thumbnails) {
+ thumbnail.addPasteButton(this.#boundPastePages);
+ }
+ } else {
+ this.container.classList.remove("pasteMode");
+ for (const thumbnail of this._thumbnails) {
+ thumbnail.removePasteButton();
+ }
+ }
+ }
+ #reportTelemetry(data) {
+ this.eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "pageOrganization",
+ data
+ }
+ });
+ }
+ #saveExtractedPages() {
+ this.#reportTelemetry({
+ action: "exportSelected"
+ });
+ this.eventBus.dispatch("saveextractedpages", {
+ source: this,
+ data: this.#pagesMapper.extractPages(this.#selectedPages)
+ });
+ this.#clearSelection();
+ this.#toggleMenuEntries(false);
+ this.#updateStatus("select");
+ }
+ #copyPages(clearSelection = true) {
+ if (!this.#isCut) {
+ this.#savedThumbnails = null;
+ this.#reportTelemetry({
+ action: "copy"
+ });
+ }
+ this.#updateStatus(this.#isCut ? "cut" : "copy");
+ const pageNumbersToCopy = this.#copiedPageNumbers = Uint32Array.from(this.#selectedPages).sort((a, b) => a - b);
+ const pagesMapper = this.#pagesMapper;
+ pagesMapper.copyPages(pageNumbersToCopy);
+ this.#copiedThumbnails = new Map();
+ for (const pageNumber of pageNumbersToCopy) {
+ this.#copiedThumbnails.set(pageNumber, this._thumbnails[pageNumber - 1]);
+ }
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper,
+ pageNumbers: pageNumbersToCopy,
+ type: "copy"
+ });
+ if (clearSelection) {
+ this.#clearSelection();
+ }
+ this.#togglePasteMode(true);
+ this.#toggleMenuEntries(false);
+ }
+ #cutPages() {
+ if (!this.#canDelete()) {
+ return;
+ }
+ this.#reportTelemetry({
+ action: "cut"
+ });
+ this.#isCut = true;
+ this.#copyPages(false);
+ this.#deletePages("cut");
+ }
+ #pastePages(index) {
+ this.#reportTelemetry({
+ action: "paste"
+ });
+ const pagesMapper = this.#pagesMapper;
+ const currentPageNumber = this.#copiedPageNumbers.includes(this._currentPageNumber) ? 0 : this._currentPageNumber;
+ pagesMapper.pastePages(index);
+ this.#updateThumbnails(currentPageNumber);
+ this.#updateCurrentPage(index + 1, true);
+ this.#thumbnailsPositions = null;
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper,
+ hasBeenCut: this.#isCut,
+ type: "paste"
+ });
+ this.#copiedThumbnails = null;
+ this.#isCut = false;
+ this.#togglePasteMode(false);
+ this.#toggleMenuEntries(false);
+ this.#updateStatus("select");
+ }
+ #deletePages(type = "delete") {
+ if (!this.#canDelete()) {
+ return;
+ }
+ const selectedPages = this.#selectedPages;
+ if (type === "delete") {
+ this.#reportTelemetry({
+ action: "delete"
+ });
+ this.#updateStatus("delete");
+ }
+ const pagesMapper = this.#pagesMapper;
+ const currentPageNumber = selectedPages.has(this._currentPageNumber) ? 0 : this._currentPageNumber;
+ const pagesToDelete = this.#deletedPageNumbers = Uint32Array.from(selectedPages).sort((a, b) => a - b);
+ pagesMapper.deletePages(pagesToDelete);
+ this.#updateCurrentPage(this.#updateThumbnails(currentPageNumber));
+ this.#thumbnailsPositions = null;
+ selectedPages.clear();
+ this.#updateMenuEntries();
+ this.eventBus.dispatch("pagesedited", {
+ source: this,
+ pagesMapper,
+ pageNumbers: pagesToDelete,
+ type
+ });
+ }
+ #updateMenuEntries() {
+ const size = this.#selectedPages?.size || 0;
+ this.#manageExportButton.disabled = this.#manageCopyButton.disabled = !size;
+ this.#manageDeleteButton.disabled = this.#manageCutButton.disabled = !this.#canDelete();
+ }
+ #toggleMenuEntries(enable) {
+ this.#manageExportButton.disabled = this.#manageDeleteButton.disabled = this.#manageCopyButton.disabled = this.#manageCutButton.disabled = !enable;
+ }
+ #updateStatus(type) {
+ if (!this.#statusBar || !this.#undoBar) {
+ return;
+ }
+ const count = this.#selectedPages?.size || 0;
+ if (type === "select") {
+ this.#statusLabel.setAttribute("data-l10n-id", count ? "pdfjs-views-manager-pages-status-action-label" : "pdfjs-views-manager-pages-status-none-action-label");
+ this.#toggleBar("status", "", count ? {
+ count
+ } : null);
+ return;
+ }
+ let l10nId;
+ switch (type) {
+ case "copy":
+ l10nId = "pdfjs-views-manager-pages-status-undo-copy-label";
+ break;
+ case "cut":
+ l10nId = "pdfjs-views-manager-status-undo-cut-label";
+ break;
+ case "delete":
+ l10nId = "pdfjs-views-manager-pages-status-undo-delete-label";
+ break;
+ }
+ this.#toggleBar("undo", l10nId, {
+ count
+ });
+ const isCopy = type === "copy";
+ this.#undoButton.firstElementChild.setAttribute("data-l10n-id", isCopy ? "pdfjs-views-manager-status-done-button-label" : "pdfjs-views-manager-status-undo-button-label");
+ this.#undoCloseButton.classList.toggle("hidden", isCopy);
+ }
+ #moveDraggedContainer(dx, dy) {
+ if (this.#isOneColumnView) {
+ dx = 0;
+ }
+ if (this.#draggedImageX + dx < 0 || this.#draggedImageX + this.#draggedImageWidth + dx > this.#scrollableContainerWidth) {
+ dx = 0;
+ }
+ if (this.#draggedImageY + dy < 0 || this.#draggedImageY + this.#draggedImageHeight + dy > this.#scrollableContainerHeight) {
+ dy = 0;
+ }
+ this.#draggedImageX += dx;
+ this.#draggedImageY += dy;
+ this.#draggedImageOffsetX += dx;
+ this.#draggedImageOffsetY += dy;
+ this.#draggedContainer.style.translate = `${this.#draggedImageOffsetX}px ${this.#draggedImageOffsetY}px`;
+ if (this.#draggedImageY + this.#draggedImageHeight > this.#currentScrollBottom) {
+ this.scrollableContainer.scrollTop = Math.min(this.scrollableContainer.scrollTop + PIXELS_TO_SCROLL_WHEN_DRAGGING, this.#scrollableContainerHeight);
+ } else if (this.#draggedImageY < this.#currentScrollTop) {
+ this.scrollableContainer.scrollTop = Math.max(this.scrollableContainer.scrollTop - PIXELS_TO_SCROLL_WHEN_DRAGGING, 0);
+ }
+ const positionData = this.#findClosestThumbnail(this.#draggedImageX + this.#draggedImageWidth / 2, this.#draggedImageY + this.#draggedImageHeight / 2);
+ this.#positionDragMarker(positionData);
+ }
+ #positionDragMarker(positionData) {
+ if (!positionData) {
+ return;
+ }
+ let dragMarker = this.#dragMarker;
+ if (!dragMarker) {
+ dragMarker = this.#dragMarker = document.createElement("div");
+ dragMarker.className = "dragMarker";
+ this.container.firstChild.before(dragMarker);
+ }
+ const [index, space] = positionData;
+ const dragMarkerStyle = dragMarker.style;
+ const {
+ bbox,
+ x: xPos
+ } = this.#thumbnailsPositions;
+ let x, y, width, height;
+ if (index < 0) {
+ if (xPos.length === 1) {
+ y = bbox[1] - SPACE_FOR_DRAG_MARKER_WHEN_NO_NEXT_ELEMENT;
+ x = bbox[0];
+ width = bbox[2];
+ } else {
+ y = bbox[1];
+ x = bbox[0] - SPACE_FOR_DRAG_MARKER_WHEN_NO_NEXT_ELEMENT;
+ height = bbox[3];
+ }
+ } else if (xPos.length === 1) {
+ y = bbox[index * 4 + 1] + bbox[index * 4 + 3] + space;
+ x = bbox[index * 4];
+ width = bbox[index * 4 + 2];
+ } else {
+ y = bbox[index * 4 + 1];
+ x = bbox[index * 4] + bbox[index * 4 + 2] + space;
+ height = bbox[index * 4 + 3];
+ }
+ dragMarkerStyle.translate = `${x}px ${y}px`;
+ dragMarkerStyle.width = width ? `${width}px` : "";
+ dragMarkerStyle.height = height ? `${height}px` : "";
+ }
+ #computeThumbnailsPosition() {
+ const positionsX = [];
+ const positionsY = [];
+ const positionsLastX = [];
+ const bbox = new Float32Array(this._thumbnails.length * 4);
+ let prevX = -Infinity;
+ let prevY = -Infinity;
+ let reminder = -1;
+ let firstRightX;
+ let lastRightX;
+ let firstBottomY;
+ for (let i = 0, ii = this._thumbnails.length; i < ii; i++) {
+ const {
+ div
+ } = this._thumbnails[i];
+ const {
+ offsetTop: y,
+ offsetLeft: x,
+ offsetWidth: w,
+ offsetHeight: h
+ } = div;
+ if (w === 0) {
+ return;
+ }
+ bbox[i * 4] = x;
+ bbox[i * 4 + 1] = y;
+ bbox[i * 4 + 2] = w;
+ bbox[i * 4 + 3] = h;
+ if (x > prevX) {
+ prevX = x + w / 2;
+ firstRightX ??= prevX + w;
+ positionsX.push(prevX);
+ }
+ if (y > prevY) {
+ if (reminder === -1 && positionsX.length > 1) {
+ reminder = ii % positionsX.length;
+ }
+ prevY = y + h / 2;
+ firstBottomY ??= prevY + h;
+ positionsY.push(prevY);
+ }
+ if (reminder > 0 && i >= ii - reminder) {
+ const cx = x + w / 2;
+ positionsLastX.push(cx);
+ lastRightX ??= cx + w;
+ }
+ }
+ let space;
+ if (positionsX.length > 1) {
+ space = (positionsX[1] - firstRightX) / 2;
+ } else if (positionsY.length > 1) {
+ space = (positionsY[1] - firstBottomY) / 2;
+ } else {
+ space = SPACE_FOR_DRAG_MARKER_WHEN_NO_NEXT_ELEMENT;
+ }
+ this.#thumbnailsPositions = {
+ x: positionsX,
+ y: positionsY,
+ lastX: positionsLastX,
+ space,
+ lastSpace: positionsLastX.length ? (positionsLastX.at(-1) - lastRightX) / 2 : space,
+ bbox
+ };
+ this.#isOneColumnView = positionsX.length === 1;
+ ({
+ clientWidth: this.#scrollableContainerWidth,
+ scrollHeight: this.#scrollableContainerHeight
+ } = this.scrollableContainer);
+ }
+ #addEventListeners() {
+ this.eventBus.on("resize", ({
+ source
+ }) => {
+ if (source.thumbnailsView === this.container) {
+ this.#computeThumbnailsPosition();
+ }
+ }, internalOpt);
+ this.container.addEventListener("keydown", e => {
+ const {
+ target
+ } = e;
+ const isCheckbox = target instanceof HTMLInputElement && target.type === "checkbox";
+ switch (e.key) {
+ case "ArrowLeft":
+ this.#goToNextItem(target, false, true, isCheckbox);
+ stopEvent(e);
+ break;
+ case "ArrowRight":
+ this.#goToNextItem(target, true, true, isCheckbox);
+ stopEvent(e);
+ break;
+ case "ArrowDown":
+ this.#goToNextItem(target, true, false, isCheckbox);
+ stopEvent(e);
+ break;
+ case "ArrowUp":
+ this.#goToNextItem(target, false, false, isCheckbox);
+ stopEvent(e);
+ break;
+ case "Home":
+ this.#focusThumbnailElement(this._thumbnails[0], isCheckbox);
+ stopEvent(e);
+ break;
+ case "End":
+ this.#focusThumbnailElement(this._thumbnails.at(-1), isCheckbox);
+ stopEvent(e);
+ break;
+ case "Enter":
+ case " ":
+ if (!isCheckbox) {
+ this.#goToPage(e);
+ }
+ break;
+ case "c":
+ if (this.#enableSplitMerge && (e.ctrlKey || e.metaKey) && this.#selectedPages?.size) {
+ this.#copyPages();
+ stopEvent(e);
+ }
+ break;
+ case "x":
+ if (this.#enableSplitMerge && (e.ctrlKey || e.metaKey) && this.#selectedPages?.size) {
+ this.#cutPages();
+ stopEvent(e);
+ }
+ break;
+ case "Delete":
+ case "Backspace":
+ if (this.#enableSplitMerge && !this.#isInPasteMode && this.#selectedPages?.size) {
+ this.#deletePages();
+ stopEvent(e);
+ }
+ break;
+ }
+ });
+ this.container.addEventListener("click", e => {
+ const {
+ target
+ } = e;
+ if (target instanceof HTMLInputElement) {
+ const pageNumber = parseInt(target.parentElement.getAttribute("page-number"), 10);
+ this.#selectPage(pageNumber, target.checked);
+ return;
+ }
+ this.#goToPage(e);
+ });
+ this.#addDragListeners();
+ this.#addExternalFileDropListeners();
+ }
+ #selectPage(pageNumber, checked) {
+ if (this.#hasUndoBarVisible) {
+ this.#dismissUndo(false);
+ }
+ const set = this.#selectedPages ??= new Set();
+ if (checked) {
+ set.add(pageNumber);
+ } else {
+ set.delete(pageNumber);
+ }
+ this.#updateMenuEntries();
+ this.#updateStatus("select");
+ }
+ #addDragListeners() {
+ if (!this.#enableSplitMerge) {
+ return;
+ }
+ this.container.addEventListener("pointerdown", e => {
+ const {
+ target: draggedImage,
+ clientX: clickX,
+ clientY: clickY,
+ pointerId: dragPointerId
+ } = e;
+ if (e.button !== 0 || this.#isInPasteMode || this._thumbnails.length === 1 || !isNaN(this.#lastDraggedOverIndex) || !draggedImage.classList.contains("thumbnailImageContainer")) {
+ return;
+ }
+ const thumbnail = draggedImage.parentElement;
+ const pointerDownAC = new AbortController();
+ const {
+ signal: pointerDownSignal
+ } = pointerDownAC;
+ let prevDragX = clickX;
+ let prevDragY = clickY;
+ let prevScrollTop = this.scrollableContainer.scrollTop;
+ const scaleFactor = PDFThumbnailViewer.#getScaleFactor(draggedImage);
+ this.#draggedImageOffsetY = ((scaleFactor - 1) * e.layerY + draggedImage.offsetTop) / scaleFactor;
+ if (this.#isOneColumnView) {
+ this.#draggedImageOffsetX = draggedImage.offsetLeft + (scaleFactor - 1) * 0.5 * draggedImage.offsetWidth / scaleFactor;
+ } else {
+ this.#draggedImageOffsetX = ((scaleFactor - 1) * e.layerX + draggedImage.offsetLeft) / scaleFactor;
+ }
+ this.#draggedImageX = thumbnail.offsetLeft + this.#draggedImageOffsetX;
+ this.#draggedImageY = thumbnail.offsetTop + this.#draggedImageOffsetY;
+ this.#draggedImageWidth = draggedImage.offsetWidth / scaleFactor;
+ this.#draggedImageHeight = draggedImage.offsetHeight / scaleFactor;
+ this.container.addEventListener("pointermove", ev => {
+ const {
+ clientX: x,
+ clientY: y,
+ pointerId
+ } = ev;
+ if (isNaN(this.#lastDraggedOverIndex)) {
+ if (pointerId !== dragPointerId || Math.abs(x - clickX) <= DRAG_THRESHOLD_IN_PIXELS && Math.abs(y - clickY) <= DRAG_THRESHOLD_IN_PIXELS) {
+ return;
+ }
+ this.#onStartDragging(thumbnail);
+ const stopDragging = (_e, isDropping = false) => {
+ this.#onStopDragging(isDropping);
+ pointerDownAC.abort();
+ };
+ const {
+ signal
+ } = this.#dragAC;
+ window.addEventListener("touchmove", stopEvent, {
+ passive: false,
+ signal
+ });
+ window.addEventListener("contextmenu", noContextMenu, {
+ signal
+ });
+ this.scrollableContainer.addEventListener("scrollend", () => {
+ const {
+ scrollableContainer: {
+ clientHeight,
+ scrollTop
+ }
+ } = this;
+ this.#currentScrollTop = scrollTop;
+ this.#currentScrollBottom = scrollTop + clientHeight;
+ const dy = scrollTop - prevScrollTop;
+ prevScrollTop = scrollTop;
+ this.#moveDraggedContainer(0, dy);
+ }, {
+ passive: true,
+ signal
+ });
+ window.addEventListener("pointerup", upEv => {
+ if (upEv.pointerId !== dragPointerId) {
+ return;
+ }
+ window.addEventListener("click", stopEvent, {
+ capture: true,
+ once: true,
+ signal
+ });
+ stopEvent(upEv);
+ stopDragging(upEv, true);
+ }, {
+ signal
+ });
+ window.addEventListener("blur", stopDragging, {
+ signal
+ });
+ window.addEventListener("pointercancel", stopDragging, {
+ signal
+ });
+ window.addEventListener("wheel", stopEvent, {
+ passive: false,
+ signal
+ });
+ window.addEventListener("keydown", kEv => {
+ if (kEv.key === "Escape" && !isNaN(this.#lastDraggedOverIndex)) {
+ stopDragging(kEv);
+ }
+ }, {
+ signal
+ });
+ }
+ const dx = x - prevDragX;
+ const dy = y - prevDragY;
+ prevDragX = x;
+ prevDragY = y;
+ this.#moveDraggedContainer(dx, dy);
+ }, {
+ passive: true,
+ signal: pointerDownSignal
+ });
+ window.addEventListener("pointerup", ({
+ pointerId
+ }) => {
+ if (pointerId !== dragPointerId) {
+ return;
+ }
+ pointerDownAC.abort();
+ }, {
+ signal: pointerDownSignal
+ });
+ window.addEventListener("dragstart", stopEvent, {
+ capture: true,
+ signal: pointerDownSignal
+ });
+ });
+ }
+ #addExternalFileDropListeners() {
+ if (!this.#enableMerge) {
+ return;
+ }
+ const container = this.container;
+ const signal = this.#abortSignal;
+ const hasMergeableItem = dataTransfer => {
+ if (!dataTransfer) {
+ return false;
+ }
+ for (const item of dataTransfer.items) {
+ if (item.kind === "file" && (item.type === "application/pdf" || item.type.startsWith("image/"))) {
+ return true;
+ }
+ }
+ return false;
+ };
+ const pointerInContainer = ({
+ clientX,
+ clientY
+ }) => {
+ const {
+ left,
+ right,
+ top,
+ bottom
+ } = container.getBoundingClientRect();
+ return clientX >= left && clientX < right && clientY >= top && clientY < bottom;
+ };
+ container.addEventListener("dragenter", e => {
+ if (this.#externalDragActive || !isNaN(this.#lastDraggedOverIndex) || !this._thumbnails.length || !hasMergeableItem(e.dataTransfer)) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ e.dataTransfer.dropEffect = "copy";
+ this.#externalDragActive = true;
+ this.container.classList.add("isDraggingFile");
+ this.#thumbnailsPositions = null;
+ this.#computeThumbnailsPosition();
+ this.#lastDraggedOverIndex = NaN;
+ }, {
+ signal
+ });
+ container.addEventListener("dragover", e => {
+ if (!this.#externalDragActive) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ e.dataTransfer.dropEffect = "copy";
+ if (!this.#thumbnailsPositions) {
+ return;
+ }
+ const rect = container.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+ const positionData = this.#findClosestThumbnail(x, y);
+ this.#positionDragMarker(positionData);
+ }, {
+ signal
+ });
+ container.addEventListener("dragleave", e => {
+ if (!this.#externalDragActive) {
+ return;
+ }
+ if (e.relatedTarget && container.contains(e.relatedTarget) || pointerInContainer(e)) {
+ return;
+ }
+ this.#endExternalFileDrag();
+ }, {
+ signal
+ });
+ container.addEventListener("drop", e => {
+ if (!this.#externalDragActive) {
+ return;
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ const files = Array.from(e.dataTransfer.files ?? []);
+ if (isNaN(this.#lastDraggedOverIndex) && this.#thumbnailsPositions) {
+ const rect = container.getBoundingClientRect();
+ this.#findClosestThumbnail(e.clientX - rect.left, e.clientY - rect.top);
+ }
+ const insertAfter = isNaN(this.#lastDraggedOverIndex) ? -1 : this.#lastDraggedOverIndex;
+ this.#endExternalFileDrag();
+ if (files.length) {
+ this.#mergeFiles(files, insertAfter);
+ }
+ }, {
+ signal
+ });
+ }
+ #endExternalFileDrag() {
+ this.#externalDragActive = false;
+ this.container.classList.remove("isDraggingFile");
+ this.#dragMarker?.remove();
+ this.#dragMarker = null;
+ this.#lastDraggedOverIndex = NaN;
+ }
+ #goToPage(e) {
+ const container = e.target.closest(".thumbnailImageContainer");
+ if (container) {
+ const pageNumber = parseInt(container.getAttribute("page-number"), 10);
+ this.linkService.goToPage(pageNumber);
+ stopEvent(e);
+ }
+ }
+ #focusThumbnailElement(thumbnail, focusCheckbox) {
+ if (focusCheckbox && thumbnail.checkbox) {
+ thumbnail.checkbox.focus();
+ } else {
+ thumbnail.imageContainer.focus();
+ }
+ }
+ #goToNextItem(element, forward, horizontal, navigateCheckboxes = false) {
+ let currentPageNumber = parseInt(element.parentElement.getAttribute("page-number"), 10);
+ if (isNaN(currentPageNumber)) {
+ currentPageNumber = this._currentPageNumber;
+ }
+ const increment = forward ? 1 : -1;
+ let nextThumbnail;
+ if (horizontal) {
+ const nextPageNumber = MathClamp(currentPageNumber + increment, 1, this._thumbnails.length + 1);
+ nextThumbnail = this._thumbnails[nextPageNumber - 1];
+ } else {
+ const currentThumbnail = this._thumbnails[currentPageNumber - 1];
+ const {
+ x: currentX,
+ y: currentY
+ } = currentThumbnail.div.getBoundingClientRect();
+ let firstWithDifferentY;
+ for (let i = currentPageNumber - 1 + increment; i >= 0 && i < this._thumbnails.length; i += increment) {
+ const thumbnail = this._thumbnails[i];
+ const {
+ x,
+ y
+ } = thumbnail.div.getBoundingClientRect();
+ if (!firstWithDifferentY && y !== currentY) {
+ firstWithDifferentY = thumbnail;
+ }
+ if (x === currentX) {
+ nextThumbnail = thumbnail;
+ break;
+ }
+ }
+ nextThumbnail ??= firstWithDifferentY;
+ }
+ if (nextThumbnail) {
+ this.#focusThumbnailElement(nextThumbnail, navigateCheckboxes);
+ }
+ }
+ #findClosestThumbnail(x, y) {
+ if (!this.#thumbnailsPositions) {
+ this.#computeThumbnailsPosition();
+ }
+ const {
+ x: positionsX,
+ y: positionsY,
+ lastX: positionsLastX,
+ space: spaceBetweenThumbnails,
+ lastSpace: lastSpaceBetweenThumbnails
+ } = this.#thumbnailsPositions;
+ const lastDraggedOverIndex = this.#lastDraggedOverIndex;
+ let xPos = lastDraggedOverIndex % positionsX.length;
+ let yPos = Math.floor(lastDraggedOverIndex / positionsX.length);
+ let xArray = yPos === positionsY.length - 1 ? positionsLastX : positionsX;
+ if (positionsY[yPos] <= y && y < (positionsY[yPos + 1] ?? Infinity) && xArray[xPos] <= x && x < (xArray[xPos + 1] ?? Infinity)) {
+ return null;
+ }
+ let index;
+ yPos = binarySearchFirstItem(positionsY, cy => y < cy);
+ if (this.#isOneColumnView) {
+ index = yPos - 1;
+ } else {
+ if (yPos === positionsY.length) {
+ yPos = positionsY.length - 1;
+ } else {
+ const dist1 = Math.abs(positionsY[yPos - 1] - y);
+ const dist2 = Math.abs(positionsY[yPos] - y);
+ yPos = dist1 < dist2 ? yPos - 1 : yPos;
+ }
+ xArray = yPos === positionsY.length - 1 && positionsLastX.length > 0 ? positionsLastX : positionsX;
+ xPos = binarySearchFirstItem(xArray, cx => x < cx) - 1;
+ if (yPos < 0) {
+ if (xPos <= 0) {
+ xPos = -1;
+ }
+ yPos = 0;
+ }
+ index = MathClamp(yPos * positionsX.length + xPos, -1, this._thumbnails.length - 1);
+ }
+ if (index === lastDraggedOverIndex) {
+ return null;
+ }
+ this.#lastDraggedOverIndex = index;
+ const space = yPos === positionsY.length - 1 && positionsLastX.length > 0 && xPos >= 0 ? lastSpaceBetweenThumbnails : spaceBetweenThumbnails;
+ return [index, space];
+ }
+}
+
+;// ./web/annotation_editor_layer_builder.js
+
+
+class AnnotationEditorLayerBuilder {
+ #annotationLayer = null;
+ #drawLayer = null;
+ #onAppend = null;
+ #structTreeLayer = null;
+ #textLayer = null;
+ #uiManager;
+ constructor(options) {
+ this.pageIndex = options.pageIndex;
+ this.accessibilityManager = options.accessibilityManager;
+ this.l10n = options.l10n;
+ this.l10n ||= new genericl10n_GenericL10n();
+ this.annotationEditorLayer = null;
+ this.div = null;
+ this._cancelled = false;
+ this.#uiManager = options.uiManager;
+ this.#annotationLayer = options.annotationLayer || null;
+ this.#textLayer = options.textLayer || null;
+ this.#drawLayer = options.drawLayer || null;
+ this.#onAppend = options.onAppend || null;
+ this.#structTreeLayer = options.structTreeLayer || null;
+ }
+ updatePageIndex(newPageIndex) {
+ this.pageIndex = newPageIndex;
+ this.annotationEditorLayer?.updatePageIndex(newPageIndex);
+ }
+ async render({
+ viewport,
+ intent = "display"
+ }) {
+ if (intent !== "display") {
+ return;
+ }
+ if (this._cancelled) {
+ return;
+ }
+ const clonedViewport = viewport.clone({
+ dontFlip: true
+ });
+ if (this.div) {
+ this.annotationEditorLayer.update({
+ viewport: clonedViewport
+ });
+ this.show();
+ return;
+ }
+ const div = this.div = document.createElement("div");
+ div.className = "annotationEditorLayer";
+ div.hidden = true;
+ div.dir = this.#uiManager.direction;
+ this.#onAppend?.(div);
+ this.annotationEditorLayer = new AnnotationEditorLayer({
+ uiManager: this.#uiManager,
+ div,
+ structTreeLayer: this.#structTreeLayer,
+ accessibilityManager: this.accessibilityManager,
+ pageIndex: this.pageIndex,
+ l10n: this.l10n,
+ viewport: clonedViewport,
+ annotationLayer: this.#annotationLayer,
+ textLayer: this.#textLayer,
+ drawLayer: this.#drawLayer
+ });
+ const parameters = {
+ viewport: clonedViewport,
+ div,
+ annotations: null,
+ intent
+ };
+ await this.annotationEditorLayer.render(parameters);
+ this.show();
+ }
+ update(viewport) {
+ if (this.div) {
+ this.annotationEditorLayer.update({
+ viewport: viewport.clone({
+ dontFlip: true
+ })
+ });
+ }
+ }
+ cancel() {
+ this._cancelled = true;
+ if (!this.div) {
+ return;
+ }
+ this.annotationEditorLayer.destroy();
+ }
+ hide() {
+ if (!this.div) {
+ return;
+ }
+ this.annotationEditorLayer.pause(true);
+ this.div.hidden = true;
+ }
+ show() {
+ if (!this.div || this.annotationEditorLayer.isInvisible) {
+ return;
+ }
+ this.div.hidden = false;
+ this.annotationEditorLayer.pause(false);
+ }
+}
+
+;// ./web/annotation_layer_builder.js
+
+
+
+
+
+
+class AnnotationLayerBuilder {
+ #annotations = null;
+ #commentManager = null;
+ #onAppend = null;
+ #eventAC = null;
+ #linksInjected = false;
+ constructor({
+ pdfPage,
+ linkService,
+ downloadManager,
+ annotationStorage = null,
+ imageResourcesPath = "",
+ renderForms = true,
+ enableComment = false,
+ commentManager = null,
+ enableScripting = false,
+ hasJSActionsPromise = null,
+ fieldObjectsPromise = null,
+ annotationCanvasMap = null,
+ accessibilityManager = null,
+ annotationEditorUIManager = null,
+ onAppend = null
+ }) {
+ this.pdfPage = pdfPage;
+ this.linkService = linkService;
+ this.downloadManager = downloadManager;
+ this.imageResourcesPath = imageResourcesPath;
+ this.renderForms = renderForms;
+ this.annotationStorage = annotationStorage;
+ this.enableComment = enableComment;
+ this.#commentManager = commentManager;
+ this.enableScripting = enableScripting;
+ this._hasJSActionsPromise = hasJSActionsPromise || Promise.resolve(false);
+ this._fieldObjectsPromise = fieldObjectsPromise || Promise.resolve(null);
+ this._annotationCanvasMap = annotationCanvasMap;
+ this._accessibilityManager = accessibilityManager;
+ this._annotationEditorUIManager = annotationEditorUIManager;
+ this.#onAppend = onAppend;
+ this.annotationLayer = null;
+ this.div = null;
+ this._cancelled = false;
+ this._eventBus = linkService.eventBus;
+ }
+ async render({
+ viewport,
+ intent = "display",
+ structTreeLayer = null,
+ optionalContentConfigPromise = null
+ }) {
+ if (this.div) {
+ const optionalContentConfig = await optionalContentConfigPromise;
+ if (this._cancelled || !this.annotationLayer) {
+ return;
+ }
+ this.annotationLayer.update({
+ viewport: viewport.clone({
+ dontFlip: true
+ }),
+ optionalContentConfig
+ });
+ return;
+ }
+ const [annotations, hasJSActions, fieldObjects, optionalContentConfig] = await Promise.all([this.pdfPage.getAnnotations({
+ intent
+ }), this._hasJSActionsPromise, this._fieldObjectsPromise, optionalContentConfigPromise]);
+ if (this._cancelled) {
+ return;
+ }
+ const div = this.div = document.createElement("div");
+ div.className = "annotationLayer";
+ this.#onAppend?.(div);
+ this.#initAnnotationLayer(viewport, structTreeLayer);
+ if (annotations.length === 0) {
+ this.#annotations = annotations;
+ setLayerDimensions(this.div, viewport);
+ return;
+ }
+ await this.annotationLayer.render({
+ annotations,
+ imageResourcesPath: this.imageResourcesPath,
+ renderForms: this.renderForms,
+ downloadManager: this.downloadManager,
+ enableComment: this.enableComment,
+ enableScripting: this.enableScripting,
+ hasJSActions,
+ fieldObjects,
+ optionalContentConfig
+ });
+ this.#annotations = annotations;
+ if (this.linkService.isInPresentationMode) {
+ this.#updatePresentationModeState(PresentationModeState.FULLSCREEN);
+ }
+ if (!this.#eventAC) {
+ this.#eventAC = new AbortController();
+ this._eventBus?.on("presentationmodechanged", evt => {
+ this.#updatePresentationModeState(evt.state);
+ }, {
+ signal: this.#eventAC.signal,
+ ...internalOpt
+ });
+ }
+ }
+ #initAnnotationLayer(viewport, structTreeLayer) {
+ this.annotationLayer = new AnnotationLayer({
+ div: this.div,
+ accessibilityManager: this._accessibilityManager,
+ annotationCanvasMap: this._annotationCanvasMap,
+ annotationEditorUIManager: this._annotationEditorUIManager,
+ annotationStorage: this.annotationStorage,
+ page: this.pdfPage,
+ viewport: viewport.clone({
+ dontFlip: true
+ }),
+ structTreeLayer,
+ commentManager: this.#commentManager,
+ linkService: this.linkService
+ });
+ }
+ cancel() {
+ this._cancelled = true;
+ this.#eventAC?.abort();
+ this.#eventAC = null;
+ this.annotationLayer?.destroy();
+ }
+ refreshCanvases() {
+ this.annotationLayer?.refreshCanvases();
+ }
+ hide() {
+ if (!this.div) {
+ return;
+ }
+ this.div.hidden = true;
+ }
+ hasEditableAnnotations() {
+ return !!this.annotationLayer?.hasEditableAnnotations();
+ }
+ async injectLinkAnnotations(inferredLinks) {
+ if (this.#annotations === null) {
+ throw new Error("`render` method must be called before `injectLinkAnnotations`.");
+ }
+ if (this._cancelled || this.#linksInjected) {
+ return;
+ }
+ this.#linksInjected = true;
+ const newLinks = this.#annotations.length ? this.#checkInferredLinks(inferredLinks) : inferredLinks;
+ if (!newLinks.length) {
+ return;
+ }
+ await this.annotationLayer.addLinkAnnotations(newLinks);
+ }
+ #updatePresentationModeState(state) {
+ if (!this.div) {
+ return;
+ }
+ let disableFormElements = false;
+ switch (state) {
+ case PresentationModeState.FULLSCREEN:
+ disableFormElements = true;
+ break;
+ case PresentationModeState.NORMAL:
+ break;
+ default:
+ return;
+ }
+ for (const section of this.div.childNodes) {
+ if (section.hasAttribute("data-internal-link") || section.classList.contains("mediaAnnotation")) {
+ continue;
+ }
+ section.inert = disableFormElements;
+ }
+ }
+ #checkInferredLinks(inferredLinks) {
+ function annotationRects(annot) {
+ if (!annot.quadPoints) {
+ return [annot.rect];
+ }
+ const rects = [];
+ for (let i = 2, ii = annot.quadPoints.length; i < ii; i += 8) {
+ const trX = annot.quadPoints[i];
+ const trY = annot.quadPoints[i + 1];
+ const blX = annot.quadPoints[i + 2];
+ const blY = annot.quadPoints[i + 3];
+ rects.push([blX, blY, trX, trY]);
+ }
+ return rects;
+ }
+ function intersectAnnotations(annot1, annot2) {
+ const intersections = [];
+ const annot1Rects = annotationRects(annot1);
+ const annot2Rects = annotationRects(annot2);
+ for (const rect1 of annot1Rects) {
+ for (const rect2 of annot2Rects) {
+ const intersection = Util.intersect(rect1, rect2);
+ if (intersection) {
+ intersections.push(intersection);
+ }
+ }
+ }
+ return intersections;
+ }
+ function areaRects(rects) {
+ let totalArea = 0;
+ for (const rect of rects) {
+ totalArea += Math.abs((rect[2] - rect[0]) * (rect[3] - rect[1]));
+ }
+ return totalArea;
+ }
+ return inferredLinks.filter(link => {
+ let linkAreaRects;
+ for (const annotation of this.#annotations) {
+ if (annotation.annotationType !== AnnotationType.LINK) {
+ continue;
+ }
+ const intersections = intersectAnnotations(annotation, link);
+ if (intersections.length === 0) {
+ continue;
+ }
+ linkAreaRects ??= areaRects(annotationRects(link));
+ if (areaRects(intersections) / linkAreaRects > 0.5) {
+ return false;
+ }
+ }
+ return true;
+ });
+ }
+}
+
+;// ./web/autolinker.js
+
+
+
+
+
+
+function DOMRectToPDF({
+ width,
+ height,
+ left,
+ top
+}, pdfPageView) {
+ if (width === 0 || height === 0) {
+ return null;
+ }
+ const pageBox = pdfPageView.textLayer.div.getBoundingClientRect();
+ const bottomLeft = pdfPageView.getPagePoint(left - pageBox.left, top - pageBox.top);
+ const topRight = pdfPageView.getPagePoint(left - pageBox.left + width, top - pageBox.top + height);
+ return Util.normalizeRect([bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]]);
+}
+function calculateLinkPosition(range, pdfPageView) {
+ const rangeRects = range.getClientRects();
+ if (rangeRects.length === 1) {
+ return {
+ rect: DOMRectToPDF(rangeRects[0], pdfPageView)
+ };
+ }
+ const rect = [Infinity, Infinity, -Infinity, -Infinity];
+ const quadPoints = [];
+ let i = 0;
+ for (const domRect of rangeRects) {
+ const normalized = DOMRectToPDF(domRect, pdfPageView);
+ if (normalized === null) {
+ continue;
+ }
+ quadPoints[i] = quadPoints[i + 4] = normalized[0];
+ quadPoints[i + 1] = quadPoints[i + 3] = normalized[3];
+ quadPoints[i + 2] = quadPoints[i + 6] = normalized[2];
+ quadPoints[i + 5] = quadPoints[i + 7] = normalized[1];
+ Util.rectBoundingBox(...normalized, rect);
+ i += 8;
+ }
+ return {
+ quadPoints,
+ rect
+ };
+}
+function textPosition(container, offset) {
+ let currentContainer = container;
+ do {
+ if (currentContainer.nodeType === Node.TEXT_NODE) {
+ const currentLength = currentContainer.textContent.length;
+ if (offset <= currentLength) {
+ return [currentContainer, offset];
+ }
+ offset -= currentLength;
+ } else if (currentContainer.firstChild) {
+ currentContainer = currentContainer.firstChild;
+ continue;
+ }
+ while (!currentContainer.nextSibling && currentContainer !== container) {
+ currentContainer = currentContainer.parentNode;
+ }
+ if (currentContainer !== container) {
+ currentContainer = currentContainer.nextSibling;
+ }
+ } while (currentContainer !== container);
+ throw new Error("Offset is bigger than container's contents length.");
+}
+function createLinkAnnotation({
+ url,
+ index,
+ length
+}, pdfPageView, id) {
+ const highlighter = pdfPageView._textHighlighter;
+ const [{
+ begin,
+ end
+ }] = highlighter._convertMatches([index], [length]);
+ const range = new Range();
+ range.setStart(...textPosition(highlighter.textDivs[begin.divIdx], begin.offset));
+ range.setEnd(...textPosition(highlighter.textDivs[end.divIdx], end.offset));
+ return {
+ id: `inferred_link_${id}`,
+ unsafeUrl: url,
+ url,
+ annotationType: AnnotationType.LINK,
+ rotation: 0,
+ ...calculateLinkPosition(range, pdfPageView),
+ borderStyle: null
+ };
+}
+class Autolinker {
+ static #index = 0;
+ static #regex;
+ static #numericTLDRegex;
+ static findLinks(text) {
+ this.#regex ??= /\b(?:https?:\/\/|mailto:|www\.)(?:[\S--[\p{P}<>]]|\/|[\S--[\[\]]]+[\S--[\p{P}<>]])+|(?=\p{L})[\S--[@\p{Ps}\p{Pe}<>]]{1,64}@([\S--[[\p{P}--\-]<>]]{1,63}(?:\.[\S--[[\p{P}--\-]<>]]{1,63})+)/gv;
+ const [normalizedText, diffs] = normalize(text, {
+ ignoreDashEOL: true
+ });
+ const matches = normalizedText.matchAll(this.#regex);
+ const links = [];
+ for (const match of matches) {
+ const [url, emailDomain] = match;
+ let raw;
+ if (url.startsWith("www.") || url.startsWith("http://") || url.startsWith("https://")) {
+ raw = url;
+ } else if (emailDomain) {
+ const hostname = URL.parse(`http://${emailDomain}`)?.hostname;
+ if (!hostname) {
+ continue;
+ }
+ this.#numericTLDRegex ??= /\.\d+$/;
+ if (this.#numericTLDRegex.test(hostname)) {
+ continue;
+ }
+ }
+ raw ??= url.startsWith("mailto:") ? url : `mailto:${url}`;
+ const absoluteURL = createValidAbsoluteUrl(raw, null, {
+ addDefaultProtocol: true
+ });
+ if (absoluteURL) {
+ const [index, length] = getOriginalIndex(diffs, match.index, url.length);
+ links.push({
+ url: absoluteURL.href,
+ index,
+ length
+ });
+ }
+ }
+ return links;
+ }
+ static processLinks(pdfPageView) {
+ return this.findLinks(pdfPageView._textHighlighter.textContentItemsStr.join("\n")).map(link => createLinkAnnotation(link, pdfPageView, this.#index++));
+ }
+}
+
+;// ./web/base_pdf_page_view.js
+
+
+class BasePDFPageView extends RenderableView {
+ #loadingId = null;
+ #renderError = null;
+ #renderingState = RenderingStates.INITIAL;
+ #showCanvas = null;
+ #startTime = 0;
+ #tempCanvas = null;
+ canvas = null;
+ div = null;
+ enableOptimizedPartialRendering = false;
+ enableSelectionRendering = true;
+ imagesRightClickMinSize = -1;
+ eventBus = null;
+ id = null;
+ imageCoordinates = null;
+ pageColors = null;
+ recordedBBoxes = null;
+ renderingQueue = null;
+ constructor(options) {
+ super();
+ this.eventBus = options.eventBus;
+ this.id = options.id;
+ this.pageColors = options.pageColors || null;
+ this.renderingQueue = options.renderingQueue;
+ this.enableOptimizedPartialRendering = options.enableOptimizedPartialRendering ?? false;
+ this.enableSelectionRendering = options.enableSelectionRendering !== false && FeatureTest.isBackdropFilterSupported;
+ this.imagesRightClickMinSize = options.imagesRightClickMinSize ?? -1;
+ this.minDurationToUpdateCanvas = options.minDurationToUpdateCanvas ?? 500;
+ }
+ get renderingState() {
+ return this.#renderingState;
+ }
+ set renderingState(state) {
+ if (state === this.#renderingState) {
+ return;
+ }
+ this.#renderingState = state;
+ if (this.#loadingId) {
+ clearTimeout(this.#loadingId);
+ this.#loadingId = null;
+ }
+ switch (state) {
+ case RenderingStates.PAUSED:
+ this.div.classList.remove("loading");
+ this.#startTime = 0;
+ this.#showCanvas?.(false);
+ break;
+ case RenderingStates.RUNNING:
+ this.div.classList.add("loadingIcon");
+ this.#loadingId = setTimeout(() => {
+ this.div.classList.add("loading");
+ this.#loadingId = null;
+ }, 0);
+ this.#startTime = Date.now();
+ break;
+ case RenderingStates.INITIAL:
+ case RenderingStates.FINISHED:
+ this.div.classList.remove("loadingIcon", "loading");
+ this.#startTime = 0;
+ break;
+ }
+ }
+ _createCanvas(onShow, hideUntilComplete = false) {
+ const {
+ pageColors
+ } = this;
+ const hasHCM = !!(pageColors?.background && pageColors?.foreground);
+ const prevCanvas = this.canvas;
+ const updateOnFirstShow = !prevCanvas && !hasHCM && !hideUntilComplete;
+ let canvas = this.canvas = document.createElement("canvas");
+ this.#showCanvas = isLastShow => {
+ if (updateOnFirstShow) {
+ let tempCanvas = this.#tempCanvas;
+ if (!isLastShow && this.minDurationToUpdateCanvas > 0) {
+ if (Date.now() - this.#startTime < this.minDurationToUpdateCanvas) {
+ return;
+ }
+ if (!tempCanvas) {
+ tempCanvas = this.#tempCanvas = canvas;
+ canvas = this.canvas = canvas.cloneNode(false);
+ onShow(canvas);
+ }
+ }
+ if (tempCanvas) {
+ const ctx = canvas.getContext("2d", {
+ alpha: false
+ });
+ ctx.drawImage(tempCanvas, 0, 0);
+ if (isLastShow) {
+ this.#resetTempCanvas();
+ } else {
+ this.#startTime = Date.now();
+ }
+ return;
+ }
+ onShow(canvas);
+ this.#showCanvas = null;
+ return;
+ }
+ if (!isLastShow) {
+ return;
+ }
+ if (prevCanvas) {
+ prevCanvas.replaceWith(canvas);
+ prevCanvas.width = prevCanvas.height = 0;
+ } else {
+ onShow(canvas);
+ }
+ };
+ return {
+ canvas,
+ prevCanvas
+ };
+ }
+ #renderContinueCallback = cont => {
+ this.#showCanvas?.(false);
+ if (this.renderingQueue && !this.renderingQueue.isHighestPriority(this)) {
+ this.renderingState = RenderingStates.PAUSED;
+ this.resume = () => {
+ this.renderingState = RenderingStates.RUNNING;
+ cont();
+ };
+ return;
+ }
+ cont();
+ };
+ _resetCanvas() {
+ const {
+ canvas
+ } = this;
+ if (!canvas) {
+ return;
+ }
+ canvas.remove();
+ canvas.width = canvas.height = 0;
+ this.canvas = null;
+ this.#resetTempCanvas();
+ }
+ #resetTempCanvas() {
+ if (this.#tempCanvas) {
+ this.#tempCanvas.width = this.#tempCanvas.height = 0;
+ this.#tempCanvas = null;
+ }
+ }
+ async _drawCanvas(options, onCancel, onFinish) {
+ const renderTask = this.renderTask = this.pdfPage.render(options);
+ renderTask.onContinue = this.#renderContinueCallback;
+ renderTask.onError = error => {
+ if (error instanceof RenderingCancelledException) {
+ onCancel();
+ this.#renderError = null;
+ }
+ };
+ let error = null;
+ try {
+ await renderTask.promise;
+ this.#showCanvas?.(true);
+ } catch (e) {
+ if (e instanceof RenderingCancelledException) {
+ return;
+ }
+ error = e;
+ this.#showCanvas?.(true);
+ } finally {
+ this.#renderError = error;
+ if (renderTask === this.renderTask) {
+ this.renderTask = null;
+ if (this.enableOptimizedPartialRendering) {
+ this.recordedBBoxes ??= renderTask.recordedBBoxes;
+ }
+ if (this.imagesRightClickMinSize !== -1) {
+ this.imageCoordinates ??= this.pdfPage.imageCoordinates;
+ }
+ }
+ }
+ this.renderingState = RenderingStates.FINISHED;
+ onFinish(renderTask);
+ if (error) {
+ throw error;
+ }
+ }
+ cancelRendering({
+ cancelExtraDelay = 0
+ } = {}) {
+ if (this.renderTask) {
+ this.renderTask.cancel(cancelExtraDelay);
+ this.renderTask = null;
+ }
+ this.resume = null;
+ }
+ dispatchPageRender() {
+ this.eventBus.dispatch("pagerender", {
+ source: this,
+ pageNumber: this.id
+ });
+ }
+ dispatchPageRendered(cssTransform, isDetailView) {
+ this.eventBus.dispatch("pagerendered", {
+ source: this,
+ pageNumber: this.id,
+ cssTransform,
+ isDetailView,
+ timestamp: performance.now(),
+ error: this.#renderError
+ });
+ }
+}
+
+;// ./web/draw_layer_builder.js
+
+class DrawLayerBuilder {
+ #drawLayer = null;
+ constructor(options) {
+ this.pageIndex = options.pageIndex;
+ this.textLayer = options.textLayer || null;
+ this.filterFactory = options.filterFactory || null;
+ this.pageColors = options.pageColors || null;
+ }
+ async render({
+ intent = "display"
+ }) {
+ if (intent !== "display" || this.#drawLayer || this._cancelled) {
+ return;
+ }
+ this.#drawLayer = new DrawLayer({
+ pageIndex: this.pageIndex,
+ textLayer: this.textLayer,
+ filterFactory: this.filterFactory,
+ pageColors: this.pageColors
+ });
+ }
+ cancel() {
+ this._cancelled = true;
+ this.#drawLayer?.destroy();
+ this.#drawLayer = null;
+ }
+ setParent(parent) {
+ this.#drawLayer?.setParent(parent);
+ }
+ getDrawLayer() {
+ return this.#drawLayer;
+ }
+}
+
+;// ./web/pdf_page_detail_view.js
+
+
+
+class PDFPageDetailView extends BasePDFPageView {
+ #detailArea = null;
+ renderingCancelled = false;
+ constructor({
+ pageView
+ }) {
+ super(pageView);
+ this.pageView = pageView;
+ this.renderingId = "detail" + this.id;
+ this.div = pageView.div;
+ }
+ setPdfPage(pdfPage) {
+ this.pageView.setPdfPage(pdfPage);
+ }
+ get pdfPage() {
+ return this.pageView.pdfPage;
+ }
+ get renderingState() {
+ return super.renderingState;
+ }
+ set renderingState(state) {
+ this.renderingCancelled = false;
+ super.renderingState = state;
+ }
+ reset({
+ keepCanvas = false
+ } = {}) {
+ const renderingCancelled = this.renderingCancelled || this.renderingState === RenderingStates.RUNNING || this.renderingState === RenderingStates.PAUSED;
+ this.cancelRendering();
+ this.renderingState = RenderingStates.INITIAL;
+ this.renderingCancelled = renderingCancelled;
+ if (!keepCanvas) {
+ this._resetCanvas();
+ }
+ }
+ #shouldRenderDifferentArea(visibleArea) {
+ if (!this.#detailArea) {
+ return true;
+ }
+ const minDetailX = this.#detailArea.minX;
+ const minDetailY = this.#detailArea.minY;
+ const maxDetailX = this.#detailArea.width + minDetailX;
+ const maxDetailY = this.#detailArea.height + minDetailY;
+ if (visibleArea.minX < minDetailX || visibleArea.minY < minDetailY || visibleArea.maxX > maxDetailX || visibleArea.maxY > maxDetailY) {
+ return true;
+ }
+ const {
+ width: maxWidth,
+ height: maxHeight,
+ scale
+ } = this.pageView.viewport;
+ if (this.#detailArea.scale !== scale) {
+ return true;
+ }
+ const paddingLeftSize = visibleArea.minX - minDetailX;
+ const paddingRightSize = maxDetailX - visibleArea.maxX;
+ const paddingTopSize = visibleArea.minY - minDetailY;
+ const paddingBottomSize = maxDetailY - visibleArea.maxY;
+ const MOVEMENT_THRESHOLD = 0.5;
+ const ratio = (1 + MOVEMENT_THRESHOLD) / MOVEMENT_THRESHOLD;
+ if (minDetailX > 0 && paddingRightSize / paddingLeftSize > ratio || maxDetailX < maxWidth && paddingLeftSize / paddingRightSize > ratio || minDetailY > 0 && paddingBottomSize / paddingTopSize > ratio || maxDetailY < maxHeight && paddingTopSize / paddingBottomSize > ratio) {
+ return true;
+ }
+ return false;
+ }
+ update({
+ visibleArea = null,
+ underlyingViewUpdated = false
+ } = {}) {
+ if (underlyingViewUpdated) {
+ this.cancelRendering();
+ this.renderingState = RenderingStates.INITIAL;
+ return;
+ }
+ if (!this.#shouldRenderDifferentArea(visibleArea)) {
+ return;
+ }
+ const {
+ viewport,
+ maxCanvasPixels,
+ capCanvasAreaFactor
+ } = this.pageView;
+ const visibleWidth = visibleArea.maxX - visibleArea.minX;
+ const visibleHeight = visibleArea.maxY - visibleArea.minY;
+ const visiblePixels = visibleWidth * visibleHeight * OutputScale.pixelRatio ** 2;
+ const maxDetailToVisibleLinearRatio = Math.sqrt(OutputScale.capPixels(maxCanvasPixels, capCanvasAreaFactor) / visiblePixels);
+ const maxOverflowScale = (maxDetailToVisibleLinearRatio - 1) / 2;
+ let overflowScale = Math.min(1, maxOverflowScale);
+ if (overflowScale < 0) {
+ overflowScale = 0;
+ }
+ const overflowWidth = visibleWidth * overflowScale;
+ const overflowHeight = visibleHeight * overflowScale;
+ const minX = Math.max(0, visibleArea.minX - overflowWidth);
+ const maxX = Math.min(viewport.width, visibleArea.maxX + overflowWidth);
+ const minY = Math.max(0, visibleArea.minY - overflowHeight);
+ const maxY = Math.min(viewport.height, visibleArea.maxY + overflowHeight);
+ const width = maxX - minX;
+ const height = maxY - minY;
+ this.#detailArea = {
+ minX,
+ minY,
+ width,
+ height,
+ scale: viewport.scale
+ };
+ this.reset({
+ keepCanvas: true
+ });
+ }
+ _getRenderingContext(canvas, transform) {
+ const baseContext = this.pageView._getRenderingContext(canvas, transform, false);
+ const recordedBBoxes = this.pdfPage.recordedBBoxes;
+ if (!recordedBBoxes || !this.enableOptimizedPartialRendering) {
+ return baseContext;
+ }
+ const {
+ viewport: {
+ width: vWidth,
+ height: vHeight
+ }
+ } = this.pageView;
+ const {
+ width: aWidth,
+ height: aHeight,
+ minX: aMinX,
+ minY: aMinY
+ } = this.#detailArea;
+ const detailMinX = aMinX / vWidth;
+ const detailMinY = aMinY / vHeight;
+ const detailMaxX = (aMinX + aWidth) / vWidth;
+ const detailMaxY = (aMinY + aHeight) / vHeight;
+ return {
+ ...baseContext,
+ operationsFilter(index) {
+ if (recordedBBoxes.isEmpty(index)) {
+ return false;
+ }
+ return recordedBBoxes.minX(index) <= detailMaxX && recordedBBoxes.maxX(index) >= detailMinX && recordedBBoxes.minY(index) <= detailMaxY && recordedBBoxes.maxY(index) >= detailMinY;
+ }
+ };
+ }
+ async draw() {
+ if (this.pageView.detailView !== this) {
+ return undefined;
+ }
+ const hideUntilComplete = this.pageView.renderingState === RenderingStates.FINISHED || this.renderingState === RenderingStates.FINISHED;
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ console.error("Must be in new state before drawing");
+ this.reset();
+ }
+ const {
+ div,
+ pdfPage,
+ viewport
+ } = this.pageView;
+ if (!pdfPage) {
+ this.renderingState = RenderingStates.FINISHED;
+ throw new Error("pdfPage is not loaded");
+ }
+ this.renderingState = RenderingStates.RUNNING;
+ const canvasWrapper = this.pageView._ensureCanvasWrapper();
+ const {
+ canvas,
+ prevCanvas
+ } = this._createCanvas(newCanvas => {
+ if (canvasWrapper.firstElementChild?.tagName === "CANVAS") {
+ canvasWrapper.firstElementChild.after(newCanvas);
+ } else {
+ canvasWrapper.prepend(newCanvas);
+ }
+ }, hideUntilComplete);
+ canvas.ariaHidden = true;
+ if (this.enableOptimizedPartialRendering) {
+ canvas.className = "detailView";
+ }
+ const {
+ width,
+ height
+ } = viewport;
+ const area = this.#detailArea;
+ const {
+ pixelRatio
+ } = OutputScale;
+ const transform = [pixelRatio, 0, 0, pixelRatio, -area.minX * pixelRatio, -area.minY * pixelRatio];
+ canvas.width = area.width * pixelRatio;
+ canvas.height = area.height * pixelRatio;
+ const {
+ style
+ } = canvas;
+ style.width = `${area.width * 100 / width}%`;
+ style.height = `${area.height * 100 / height}%`;
+ style.top = `${area.minY * 100 / height}%`;
+ style.left = `${area.minX * 100 / width}%`;
+ const renderingPromise = this._drawCanvas(this._getRenderingContext(canvas, transform), () => {
+ this.canvas?.remove();
+ this.canvas = prevCanvas;
+ }, () => {
+ this.pageView._refreshAnnotationLayer();
+ this.dispatchPageRendered(false, true);
+ });
+ div.setAttribute("data-loaded", true);
+ this.dispatchPageRender();
+ return renderingPromise;
+ }
+}
+
+;// ./web/struct_tree_layer_builder.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const PDF_ROLE_TO_HTML_ROLE = {
+ Document: null,
+ DocumentFragment: null,
+ Part: "group",
+ Art: "article",
+ Sect: "group",
+ Div: "group",
+ BlockQuote: "blockquote",
+ Aside: "note",
+ NonStruct: "none",
+ P: "paragraph",
+ H: "heading",
+ Title: null,
+ FENote: "note",
+ Sub: "group",
+ Lbl: null,
+ Span: null,
+ Em: "emphasis",
+ Strong: "strong",
+ Note: "note",
+ Code: "code",
+ Link: "link",
+ Annot: "note",
+ Form: "form",
+ Ruby: null,
+ RB: null,
+ RT: null,
+ RP: null,
+ Warichu: null,
+ WT: null,
+ WP: null,
+ L: "list",
+ LI: "listitem",
+ LBody: null,
+ Table: "table",
+ TR: "row",
+ TH: "columnheader",
+ TD: "cell",
+ THead: "rowgroup",
+ TBody: "rowgroup",
+ TFoot: "rowgroup",
+ Caption: "caption",
+ Figure: "figure",
+ Formula: null,
+ Artifact: null
+};
+const ARIA_ROLES_WITH_PROHIBITED_NAMES = new Set(["caption", "code", "emphasis", "generic", "none", "paragraph", "strong"]);
+const MathMLElements = new Set(["math", "merror", "mfrac", "mi", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mprescripts", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msubsup", "msup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover", "semantics"]);
+const MathMLNamespace = "http://www.w3.org/1998/Math/MathML";
+class MathMLSanitizer {
+ static get sanitizer() {
+ return shadow(this, "sanitizer", FeatureTest.isSanitizerSupported ? new Sanitizer({
+ elements: Array.from(MathMLElements.keys(), name => ({
+ name,
+ namespace: MathMLNamespace
+ })),
+ replaceWithChildrenElements: [{
+ name: "maction",
+ namespace: MathMLNamespace
+ }],
+ attributes: ["dir", "displaystyle", "mathbackground", "mathcolor", "mathsize", "scriptlevel", "encoding", "display", "linethickness", "intent", "arg", "form", "fence", "separator", "lspace", "rspace", "stretchy", "symmetric", "maxsize", "minsize", "largeop", "movablelimits", "width", "height", "depth", "voffset", "accent", "accentunder", "columnspan", "rowspan"],
+ comments: false
+ }) : null);
+ }
+}
+const HEADING_PATTERN = /^H(\d+)$/;
+class StructTreeLayerBuilder {
+ #promise;
+ #treeDom = null;
+ #treePromise;
+ #annotationIds = new Set();
+ #elementAttributes = new Map();
+ #pendingLinkOwnership = new Map();
+ #linkTextId = 0;
+ #structElementIdPrefix = `pdfjs_internal_struct_${getUuid()}_`;
+ #structElementIds = new Map();
+ #structElements = new Map();
+ #rawDims;
+ #elementsToAddToTextLayer = null;
+ #elementsToHideInTextLayer = null;
+ #elementsToStealFromTextLayer = null;
+ constructor(pdfPage, rawDims) {
+ this.#promise = pdfPage.getStructTree();
+ this.#rawDims = rawDims;
+ }
+ async render() {
+ if (this.#treePromise) {
+ return this.#treePromise;
+ }
+ const {
+ promise,
+ resolve,
+ reject
+ } = Promise.withResolvers();
+ this.#treePromise = promise;
+ try {
+ const tree = await this.#promise;
+ this.#collectStructElements(tree);
+ this.#collectAnnotations(tree);
+ this.#treeDom = this.#walk(tree);
+ } catch (ex) {
+ reject(ex);
+ }
+ this.#promise = null;
+ this.#treeDom?.classList.add("structTree");
+ resolve(this.#treeDom);
+ return promise;
+ }
+ async getAriaAttributes(annotationId, {
+ enableLinkOwnership = false
+ } = {}) {
+ try {
+ await this.render();
+ const ownership = this.#pendingLinkOwnership.get(annotationId);
+ if (ownership && enableLinkOwnership) {
+ const {
+ element,
+ ids
+ } = ownership;
+ element.removeAttribute("role");
+ if (ids.length > 0) {
+ this.#elementAttributes.getOrInsertComputed(annotationId, makeMap).set("aria-owns", ids.join(" "));
+ }
+ this.#pendingLinkOwnership.delete(annotationId);
+ }
+ return this.#elementAttributes.get(annotationId);
+ } catch {}
+ return null;
+ }
+ async getAnnotationIds() {
+ try {
+ await this.render();
+ return this.#annotationIds;
+ } catch {}
+ return null;
+ }
+ hide() {
+ if (this.#treeDom && !this.#treeDom.hidden) {
+ this.#treeDom.hidden = true;
+ }
+ }
+ show() {
+ if (this.#treeDom?.hidden) {
+ this.#treeDom.hidden = false;
+ }
+ }
+ #collectStructElements(node) {
+ if (!node) {
+ return;
+ }
+ if (node.structId) {
+ this.#structElements.getOrInsert(node.structId, node);
+ }
+ for (const child of node.children || []) {
+ this.#collectStructElements(child);
+ }
+ }
+ #collectAnnotations(node) {
+ if (!node) {
+ return;
+ }
+ if (node.type === "annotation") {
+ this.#annotationIds.add(node.id);
+ return;
+ }
+ for (const child of node.children || []) {
+ this.#collectAnnotations(child);
+ }
+ }
+ #getStructElementId(structId) {
+ return this.#structElementIds.getOrInsertComputed(structId, () => `${this.#structElementIdPrefix}${this.#structElementIds.size}`);
+ }
+ #getHeaderIds(headers) {
+ const result = [],
+ visited = new Set(),
+ pending = headers.toReversed();
+ while (pending.length > 0) {
+ const structId = pending.pop();
+ if (visited.has(structId)) {
+ continue;
+ }
+ visited.add(structId);
+ const header = this.#structElements.get(structId);
+ if (header?.role !== "TH") {
+ continue;
+ }
+ result.push(this.#getStructElementId(structId));
+ if (header.headers) {
+ for (let i = header.headers.length - 1; i >= 0; i--) {
+ pending.push(header.headers[i]);
+ }
+ }
+ }
+ return result;
+ }
+ #setAttributes(structElement, htmlElement) {
+ const {
+ alt,
+ colSpan,
+ headers,
+ id,
+ lang,
+ rowSpan,
+ short,
+ structId,
+ summary
+ } = structElement;
+ if (alt !== undefined) {
+ let added = false;
+ const label = removeNullCharacters(alt);
+ for (const child of structElement.children) {
+ if (child.type === "annotation") {
+ this.#elementAttributes.getOrInsertComputed(child.id, makeMap).set("aria-label", label);
+ added = true;
+ }
+ }
+ const role = htmlElement.getAttribute("role") || (htmlElement.localName === "span" ? "generic" : null);
+ if (!added && role !== "none") {
+ htmlElement.setAttribute(ARIA_ROLES_WITH_PROHIBITED_NAMES.has(role) ? "aria-description" : "aria-label", label);
+ }
+ }
+ if (id !== undefined) {
+ htmlElement.setAttribute("aria-owns", id);
+ }
+ if (structId !== undefined && this.#structElements.get(structId) === structElement) {
+ const elementId = this.#getStructElementId(structId);
+ if (short !== undefined) {
+ const abbreviation = document.createElement("span");
+ abbreviation.setAttribute("id", elementId);
+ abbreviation.setAttribute("aria-hidden", "true");
+ abbreviation.textContent = removeNullCharacters(short);
+ htmlElement.append(abbreviation);
+ } else {
+ htmlElement.setAttribute("id", elementId);
+ }
+ }
+ if (lang !== undefined) {
+ htmlElement.setAttribute("lang", removeNullCharacters(lang, true));
+ }
+ if (rowSpan !== undefined) {
+ htmlElement.setAttribute("aria-rowspan", rowSpan);
+ }
+ if (colSpan !== undefined) {
+ htmlElement.setAttribute("aria-colspan", colSpan);
+ }
+ if (headers?.length > 0) {
+ const headerIds = this.#getHeaderIds(headers);
+ if (headerIds.length > 0) {
+ htmlElement.setAttribute("aria-describedby", headerIds.join(" "));
+ }
+ }
+ if (summary !== undefined) {
+ htmlElement.setAttribute("aria-description", removeNullCharacters(summary));
+ }
+ }
+ #addImageInTextLayer(node, element) {
+ const {
+ alt,
+ bbox,
+ children
+ } = node;
+ const child = children?.[0];
+ if (!this.#rawDims || !alt || !bbox || child?.type !== "content") {
+ return false;
+ }
+ const {
+ id
+ } = child;
+ if (!id) {
+ return false;
+ }
+ element.setAttribute("aria-owns", id);
+ const img = document.createElement("span");
+ (this.#elementsToAddToTextLayer ||= new Map()).set(id, img);
+ img.setAttribute("role", "img");
+ img.setAttribute("aria-label", removeNullCharacters(alt));
+ const {
+ pageHeight,
+ pageX,
+ pageY
+ } = this.#rawDims;
+ const calc = "calc(var(--total-scale-factor) *";
+ const {
+ style
+ } = img;
+ style.width = `${calc}${bbox[2] - bbox[0]}px)`;
+ style.height = `${calc}${bbox[3] - bbox[1]}px)`;
+ style.left = `${calc}${bbox[0] - pageX}px)`;
+ style.top = `${calc}${pageHeight - bbox[3] + pageY}px)`;
+ return true;
+ }
+ updateTextLayer() {
+ if (this.#elementsToAddToTextLayer) {
+ for (const [id, img] of this.#elementsToAddToTextLayer) {
+ document.getElementById(id)?.append(img);
+ }
+ this.#elementsToAddToTextLayer.clear();
+ this.#elementsToAddToTextLayer = null;
+ }
+ if (this.#elementsToHideInTextLayer) {
+ for (const id of this.#elementsToHideInTextLayer) {
+ const elem = document.getElementById(id);
+ if (elem) {
+ elem.ariaHidden = true;
+ }
+ }
+ this.#elementsToHideInTextLayer.length = 0;
+ this.#elementsToHideInTextLayer = null;
+ }
+ if (this.#elementsToStealFromTextLayer) {
+ for (let i = 0, ii = this.#elementsToStealFromTextLayer.length; i < ii; i += 2) {
+ const element = this.#elementsToStealFromTextLayer[i];
+ const ids = this.#elementsToStealFromTextLayer[i + 1];
+ let textContent = "";
+ for (const id of ids) {
+ const elem = document.getElementById(id);
+ if (elem) {
+ textContent += elem.textContent.trim() || "";
+ elem.ariaHidden = "true";
+ }
+ }
+ if (textContent) {
+ element.textContent = textContent;
+ }
+ }
+ this.#elementsToStealFromTextLayer.length = 0;
+ this.#elementsToStealFromTextLayer = null;
+ }
+ }
+ #collectIds(node, ids) {
+ if (!node) {
+ return;
+ }
+ if ("id" in node) {
+ ids.push(node.id);
+ }
+ for (const kid of node.children || []) {
+ this.#collectIds(kid, ids);
+ }
+ }
+ #walk(node, parentNodes = []) {
+ if (!node) {
+ return null;
+ }
+ let element;
+ let visitChildren = true;
+ if ("role" in node) {
+ const {
+ role
+ } = node;
+ if (MathMLElements.has(role)) {
+ element = document.createElementNS(MathMLNamespace, role);
+ const ids = [];
+ (this.#elementsToStealFromTextLayer ||= []).push(element, ids);
+ for (const {
+ type,
+ id
+ } of node.children || []) {
+ if (type === "content" && id) {
+ ids.push(id);
+ }
+ }
+ } else {
+ element = document.createElement("span");
+ }
+ const match = role.match(HEADING_PATTERN);
+ if (match) {
+ element.setAttribute("role", "heading");
+ element.setAttribute("aria-level", match[1]);
+ } else if (PDF_ROLE_TO_HTML_ROLE[role]) {
+ let htmlRole = PDF_ROLE_TO_HTML_ROLE[role];
+ if (role === "TH") {
+ if (node.scope === "Row") {
+ htmlRole = "rowheader";
+ } else if (node.scope === "Column") {
+ htmlRole = "columnheader";
+ } else if (parentNodes.at(-1)?.role === "TR" && parentNodes.at(-2)?.role === "TBody") {
+ htmlRole = "rowheader";
+ }
+ } else if (role === "Caption") {
+ const parentRole = parentNodes.at(-1)?.role;
+ if (parentRole !== "Table" && parentRole !== "Figure") {
+ htmlRole = null;
+ }
+ }
+ if (htmlRole) {
+ element.setAttribute("role", htmlRole);
+ }
+ }
+ if (role === "Figure" && this.#addImageInTextLayer(node, element)) {
+ return element;
+ }
+ if (role === "Formula") {
+ if (node.mathML && MathMLSanitizer.sanitizer) {
+ visitChildren = false;
+ element.setHTML(node.mathML, {
+ sanitizer: MathMLSanitizer.sanitizer
+ });
+ this.#collectIds(node, this.#elementsToHideInTextLayer ||= []);
+ delete node.alt;
+ }
+ if (!node.mathML && node.children.length === 1 && node.children[0].role !== "math") {
+ element = document.createElementNS(MathMLNamespace, "math");
+ delete node.alt;
+ }
+ }
+ }
+ element ||= document.createElement("span");
+ this.#setAttributes(node, element);
+ if (node.children) {
+ if (node.children.length === 1 && !("role" in node.children[0]) && "id" in node.children[0] && element.getAttribute("role") !== "none") {
+ this.#setAttributes(node.children[0], element);
+ } else if (visitChildren) {
+ parentNodes.push(node);
+ for (const kid of node.children) {
+ element.append(this.#walk(kid, parentNodes));
+ }
+ parentNodes.pop();
+ }
+ }
+ if (node.role === "Link") {
+ const annotations = node.children?.filter(child => child.type === "annotation");
+ if (annotations?.length === 1) {
+ const annotation = annotations[0];
+ const ids = [];
+ for (const child of element.children) {
+ if (child.getAttribute("aria-owns") === annotation.id) {
+ continue;
+ }
+ child.id ||= `${this.#structElementIdPrefix}link_${this.#linkTextId++}`;
+ ids.push(child.id);
+ }
+ this.#pendingLinkOwnership.set(annotation.id, {
+ element,
+ ids
+ });
+ }
+ }
+ return element;
+ }
+}
+
+;// ./web/text_accessibility.js
+
+
+
+
+
+
+class TextAccessibilityManager {
+ #enabled = false;
+ #textChildren = null;
+ #textNodes = new Map();
+ #waitingElements = new Map();
+ setTextMapping(textDivs) {
+ this.#textChildren = textDivs;
+ }
+ static #compareElementPositions(e1, e2) {
+ const rect1 = e1.getBoundingClientRect();
+ const rect2 = e2.getBoundingClientRect();
+ if (rect1.width === 0 && rect1.height === 0) {
+ return +1;
+ }
+ if (rect2.width === 0 && rect2.height === 0) {
+ return -1;
+ }
+ const top1 = rect1.y;
+ const bot1 = rect1.y + rect1.height;
+ const mid1 = rect1.y + rect1.height / 2;
+ const top2 = rect2.y;
+ const bot2 = rect2.y + rect2.height;
+ const mid2 = rect2.y + rect2.height / 2;
+ if (mid1 <= top2 && mid2 >= bot1) {
+ return -1;
+ }
+ if (mid2 <= top1 && mid1 >= bot2) {
+ return +1;
+ }
+ const centerX1 = rect1.x + rect1.width / 2;
+ const centerX2 = rect2.x + rect2.width / 2;
+ return centerX1 - centerX2;
+ }
+ enable() {
+ if (this.#enabled) {
+ throw new Error("TextAccessibilityManager is already enabled.");
+ }
+ if (!this.#textChildren) {
+ throw new Error("Text divs and strings have not been set.");
+ }
+ this.#enabled = true;
+ this.#textChildren = this.#textChildren.slice();
+ this.#textChildren.sort(TextAccessibilityManager.#compareElementPositions);
+ if (this.#textNodes.size > 0) {
+ const textChildren = this.#textChildren;
+ for (const [id, nodeIndex] of this.#textNodes) {
+ const element = document.getElementById(id);
+ if (!element) {
+ this.#textNodes.delete(id);
+ continue;
+ }
+ this.#addIdToAriaOwns(id, textChildren[nodeIndex]);
+ }
+ }
+ for (const [element, isRemovable] of this.#waitingElements) {
+ this.addPointerInTextLayer(element, isRemovable);
+ }
+ this.#waitingElements.clear();
+ }
+ disable() {
+ if (!this.#enabled) {
+ return;
+ }
+ this.#waitingElements.clear();
+ this.#textChildren = null;
+ this.#enabled = false;
+ }
+ removePointerInTextLayer(element) {
+ if (!this.#enabled) {
+ this.#waitingElements.delete(element);
+ return;
+ }
+ const children = this.#textChildren;
+ if (!children?.length) {
+ return;
+ }
+ const {
+ id
+ } = element;
+ const nodeIndex = this.#textNodes.get(id);
+ if (nodeIndex === undefined) {
+ return;
+ }
+ const node = children[nodeIndex];
+ this.#textNodes.delete(id);
+ let owns = node.getAttribute("aria-owns");
+ if (owns?.includes(id)) {
+ owns = owns.split(" ").filter(x => x !== id).join(" ");
+ if (owns) {
+ node.setAttribute("aria-owns", owns);
+ } else {
+ node.removeAttribute("aria-owns");
+ node.setAttribute("role", "presentation");
+ }
+ }
+ }
+ #addIdToAriaOwns(id, node) {
+ const owns = node.getAttribute("aria-owns");
+ if (!owns?.includes(id)) {
+ node.setAttribute("aria-owns", owns ? `${owns} ${id}` : id);
+ }
+ node.removeAttribute("role");
+ }
+ addPointerInTextLayer(element, isRemovable) {
+ const {
+ id
+ } = element;
+ if (!id) {
+ return null;
+ }
+ if (!this.#enabled) {
+ this.#waitingElements.set(element, isRemovable);
+ return null;
+ }
+ if (isRemovable) {
+ this.removePointerInTextLayer(element);
+ }
+ const children = this.#textChildren;
+ if (!children?.length) {
+ return null;
+ }
+ const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0);
+ const nodeIndex = Math.max(0, index - 1);
+ const child = children[nodeIndex];
+ this.#addIdToAriaOwns(id, child);
+ this.#textNodes.set(id, nodeIndex);
+ const parent = child.parentNode;
+ return parent?.classList.contains("markedContent") ? parent.id : null;
+ }
+ moveElementInDOM(container, element, contentElement, isRemovable) {
+ const id = this.addPointerInTextLayer(contentElement, isRemovable);
+ if (!container.hasChildNodes()) {
+ container.append(element);
+ return id;
+ }
+ const children = Array.from(container.childNodes).filter(node => node !== element);
+ if (children.length === 0) {
+ return id;
+ }
+ const index = binarySearchFirstItem(children, node => TextAccessibilityManager.#compareElementPositions(element, node) < 0);
+ if (index === 0) {
+ children[0].before(element);
+ } else {
+ children[index - 1].after(element);
+ }
+ return id;
+ }
+}
+
+;// ./web/text_highlighter.js
+
+
+
+class TextHighlighter {
+ #eventAC = null;
+ constructor({
+ findController,
+ eventBus,
+ pageIndex
+ }) {
+ this.findController = findController;
+ this.matches = [];
+ this.eventBus = eventBus;
+ this.pageIdx = pageIndex;
+ this.textDivs = null;
+ this.textContentItemsStr = null;
+ this.enabled = false;
+ }
+ setTextMapping(divs, texts) {
+ this.textDivs = divs;
+ this.textContentItemsStr = texts;
+ }
+ enable() {
+ if (!this.textDivs || !this.textContentItemsStr) {
+ throw new Error("Text divs and strings have not been set.");
+ }
+ if (this.enabled) {
+ throw new Error("TextHighlighter is already enabled.");
+ }
+ this.enabled = true;
+ if (!this.#eventAC) {
+ this.#eventAC = new AbortController();
+ this.eventBus.on("updatetextlayermatches", evt => {
+ if (evt.pageIndex === this.pageIdx || evt.pageIndex === -1) {
+ this._updateMatches();
+ }
+ }, {
+ signal: this.#eventAC.signal,
+ ...internalOpt
+ });
+ }
+ this._updateMatches();
+ }
+ disable() {
+ if (!this.enabled) {
+ return;
+ }
+ this.enabled = false;
+ this.#eventAC?.abort();
+ this.#eventAC = null;
+ this._updateMatches(true);
+ }
+ _convertMatches(matches, matchesLength) {
+ if (!matches) {
+ return [];
+ }
+ const {
+ textContentItemsStr
+ } = this;
+ let i = 0,
+ iIndex = 0;
+ const end = textContentItemsStr.length - 1;
+ const result = [];
+ for (let m = 0, mm = matches.length; m < mm; m++) {
+ let matchIdx = matches[m];
+ while (i !== end && matchIdx >= iIndex + textContentItemsStr[i].length) {
+ iIndex += textContentItemsStr[i].length;
+ i++;
+ }
+ if (i === textContentItemsStr.length) {
+ console.error("Could not find a matching mapping");
+ }
+ const match = {
+ begin: {
+ divIdx: i,
+ offset: matchIdx - iIndex
+ }
+ };
+ matchIdx += matchesLength[m];
+ while (i !== end && matchIdx > iIndex + textContentItemsStr[i].length) {
+ iIndex += textContentItemsStr[i].length;
+ i++;
+ }
+ match.end = {
+ divIdx: i,
+ offset: matchIdx - iIndex
+ };
+ result.push(match);
+ }
+ return result;
+ }
+ _renderMatches(matches) {
+ if (matches.length === 0) {
+ return;
+ }
+ const {
+ findController,
+ pageIdx
+ } = this;
+ const {
+ textContentItemsStr,
+ textDivs
+ } = this;
+ const isSelectedPage = pageIdx === findController.selected.pageIdx;
+ const selectedMatchIdx = findController.selected.matchIdx;
+ const highlightAll = findController.state.highlightAll;
+ let prevEnd = null;
+ const infinity = {
+ divIdx: -1,
+ offset: undefined
+ };
+ function beginText(begin, className) {
+ const divIdx = begin.divIdx;
+ textDivs[divIdx].textContent = "";
+ return appendTextToDiv(divIdx, 0, begin.offset, className);
+ }
+ function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
+ let div = textDivs[divIdx];
+ if (div.nodeType === Node.TEXT_NODE) {
+ const span = document.createElement("span");
+ div.before(span);
+ span.append(div);
+ textDivs[divIdx] = span;
+ div = span;
+ }
+ const content = textContentItemsStr[divIdx].substring(fromOffset, toOffset);
+ const node = document.createTextNode(content);
+ if (className) {
+ const span = document.createElement("span");
+ span.className = `${className} appended`;
+ span.append(node);
+ div.append(span);
+ if (className.includes("selected")) {
+ return span;
+ }
+ return null;
+ }
+ div.append(node);
+ return 0;
+ }
+ let i0 = selectedMatchIdx,
+ i1 = i0 + 1;
+ if (highlightAll) {
+ i0 = 0;
+ i1 = matches.length;
+ } else if (!isSelectedPage) {
+ return;
+ }
+ let lastDivIdx = -1;
+ let lastOffset = -1;
+ for (let i = i0; i < i1; i++) {
+ const match = matches[i];
+ const begin = match.begin;
+ if (begin.divIdx === lastDivIdx && begin.offset === lastOffset) {
+ continue;
+ }
+ lastDivIdx = begin.divIdx;
+ lastOffset = begin.offset;
+ const end = match.end;
+ const isSelected = isSelectedPage && i === selectedMatchIdx;
+ const highlightSuffix = isSelected ? " selected" : "";
+ let selectedSpan = null;
+ if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
+ if (prevEnd !== null) {
+ appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
+ }
+ beginText(begin);
+ } else {
+ appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
+ }
+ if (begin.divIdx === end.divIdx) {
+ selectedSpan = appendTextToDiv(begin.divIdx, begin.offset, end.offset, "highlight" + highlightSuffix);
+ } else {
+ selectedSpan = appendTextToDiv(begin.divIdx, begin.offset, infinity.offset, "highlight begin" + highlightSuffix);
+ for (let n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
+ textDivs[n0].className = "highlight middle" + highlightSuffix;
+ }
+ beginText(end, "highlight end" + highlightSuffix);
+ }
+ prevEnd = end;
+ if (isSelected) {
+ findController.scrollMatchIntoView({
+ element: selectedSpan,
+ pageIndex: pageIdx,
+ matchIndex: selectedMatchIdx
+ });
+ }
+ }
+ if (prevEnd) {
+ appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
+ }
+ }
+ _updateMatches(reset = false) {
+ if (!this.enabled && !reset) {
+ return;
+ }
+ const {
+ findController,
+ matches,
+ pageIdx
+ } = this;
+ const {
+ textContentItemsStr,
+ textDivs
+ } = this;
+ let clearedUntilDivIdx = -1;
+ for (const match of matches) {
+ const begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
+ for (let n = begin, end = match.end.divIdx; n <= end; n++) {
+ const div = textDivs[n];
+ div.textContent = textContentItemsStr[n];
+ div.className = "";
+ }
+ clearedUntilDivIdx = match.end.divIdx + 1;
+ }
+ if (!findController?.highlightMatches || reset) {
+ return;
+ }
+ const pageMatches = findController.pageMatches[pageIdx] || null;
+ const pageMatchesLength = findController.pageMatchesLength[pageIdx] || null;
+ this.matches = this._convertMatches(pageMatches, pageMatchesLength);
+ this._renderMatches(this.matches);
+ }
+}
+
+;// ./web/text_layer_builder.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class TextLayerBuilder {
+ #abortSignal = null;
+ #enablePermissions = false;
+ #onAppend = null;
+ #renderingDone = false;
+ #textLayer = null;
+ static #textLayers = new Map();
+ static #selectionChangeAC = null;
+ constructor({
+ pdfPage,
+ highlighter = null,
+ accessibilityManager = null,
+ enablePermissions = false,
+ onAppend = null,
+ abortSignal = null
+ }) {
+ this.pdfPage = pdfPage;
+ this.highlighter = highlighter;
+ this.accessibilityManager = accessibilityManager;
+ this.#enablePermissions = enablePermissions === true;
+ this.#onAppend = onAppend;
+ this.#abortSignal = abortSignal;
+ this.div = document.createElement("div");
+ this.div.tabIndex = 0;
+ this.div.className = "textLayer";
+ }
+ async render({
+ viewport,
+ images,
+ textContentParams = null
+ }) {
+ if (this.#renderingDone && this.#textLayer) {
+ this.#textLayer.update({
+ viewport,
+ onBefore: this.hide.bind(this)
+ });
+ this.show();
+ return;
+ }
+ this.cancel();
+ this.#textLayer = new TextLayer({
+ textContentSource: this.pdfPage.streamTextContent(textContentParams || {
+ includeMarkedContent: true,
+ disableNormalization: true
+ }),
+ images,
+ container: this.div,
+ viewport
+ });
+ const {
+ textDivs,
+ textContentItemsStr
+ } = this.#textLayer;
+ this.highlighter?.setTextMapping(textDivs, textContentItemsStr);
+ this.accessibilityManager?.setTextMapping(textDivs);
+ await this.#textLayer.render();
+ this.#renderingDone = true;
+ const endOfContent = document.createElement("div");
+ endOfContent.className = "endOfContent";
+ this.div.append(endOfContent);
+ this.#bindMouse(endOfContent);
+ this.#onAppend?.(this.div);
+ this.highlighter?.enable();
+ this.accessibilityManager?.enable();
+ }
+ hide() {
+ if (!this.div.hidden && this.#renderingDone) {
+ this.highlighter?.disable();
+ this.div.hidden = true;
+ }
+ }
+ show() {
+ if (this.div.hidden && this.#renderingDone) {
+ this.div.hidden = false;
+ this.highlighter?.enable();
+ }
+ }
+ cancel() {
+ this.#textLayer?.cancel();
+ this.#textLayer = null;
+ this.#renderingDone = false;
+ this.div.replaceChildren();
+ this.highlighter?.disable();
+ this.accessibilityManager?.disable();
+ TextLayerBuilder.#removeGlobalSelectionListener(this.div);
+ }
+ #bindMouse(end) {
+ const {
+ div
+ } = this;
+ const abortSignal = this.#abortSignal;
+ const opts = abortSignal ? {
+ signal: abortSignal
+ } : null;
+ div.addEventListener("mousedown", () => {
+ div.classList.add("selecting");
+ }, opts);
+ div.addEventListener("copy", event => {
+ if (!this.#enablePermissions) {
+ const selection = document.getSelection();
+ event.clipboardData.setData("text/plain", removeNullCharacters(normalizeUnicode(selection.toString())));
+ }
+ stopEvent(event);
+ }, opts);
+ TextLayerBuilder.#textLayers.set(div, end);
+ TextLayerBuilder.#enableGlobalSelectionListener(abortSignal);
+ }
+ static #removeGlobalSelectionListener(textLayerDiv) {
+ this.#textLayers.delete(textLayerDiv);
+ if (this.#textLayers.size === 0) {
+ this.#selectionChangeAC?.abort();
+ this.#selectionChangeAC = null;
+ }
+ }
+ static #enableGlobalSelectionListener(globalAbortSignal) {
+ if (this.#selectionChangeAC) {
+ return;
+ }
+ this.#selectionChangeAC = new AbortController();
+ const signal = globalAbortSignal ? AbortSignal.any([this.#selectionChangeAC.signal, globalAbortSignal]) : this.#selectionChangeAC.signal;
+ const reset = (end, textLayer) => {
+ textLayer.append(end);
+ end.style.width = "";
+ end.style.height = "";
+ textLayer.classList.remove("selecting");
+ };
+ let isPointerDown = false;
+ document.addEventListener("pointerdown", () => {
+ isPointerDown = true;
+ }, {
+ signal
+ });
+ document.addEventListener("pointerup", () => {
+ isPointerDown = false;
+ this.#textLayers.forEach(reset);
+ }, {
+ signal
+ });
+ window.addEventListener("blur", () => {
+ isPointerDown = false;
+ this.#textLayers.forEach(reset);
+ }, {
+ signal
+ });
+ document.addEventListener("keyup", () => {
+ if (!isPointerDown) {
+ this.#textLayers.forEach(reset);
+ }
+ }, {
+ signal
+ });
+ var isFirefoxOrModernChromium, prevRange;
+ document.addEventListener("selectionchange", () => {
+ const selection = document.getSelection();
+ if (selection.rangeCount === 0) {
+ this.#textLayers.forEach(reset);
+ return;
+ }
+ const activeTextLayers = new Set();
+ for (let i = 0; i < selection.rangeCount; i++) {
+ const range = selection.getRangeAt(i);
+ for (const textLayerDiv of this.#textLayers.keys()) {
+ if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) {
+ activeTextLayers.add(textLayerDiv);
+ }
+ }
+ }
+ for (const [textLayerDiv, endDiv] of this.#textLayers) {
+ if (activeTextLayers.has(textLayerDiv)) {
+ textLayerDiv.classList.add("selecting");
+ } else {
+ reset(endDiv, textLayerDiv);
+ }
+ }
+ if (isFirefoxOrModernChromium === undefined) {
+ isFirefoxOrModernChromium = getComputedStyle(this.#textLayers.values().next().value).getPropertyValue("-moz-user-select") === "none";
+ if (!isFirefoxOrModernChromium) {
+ const chromiumVersion = navigator.userAgentData ? navigator.userAgentData.brands.find(({
+ brand
+ }) => brand === "Chromium")?.version : /\bChrome\/(\d+)\b/.exec(navigator.userAgent)?.[1];
+ isFirefoxOrModernChromium = !!chromiumVersion && parseInt(chromiumVersion, 10) >= 148;
+ }
+ }
+ if (isFirefoxOrModernChromium) {
+ return;
+ }
+ const range = selection.getRangeAt(0);
+ const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0);
+ let anchor = modifyStart ? range.startContainer : range.endContainer;
+ if (anchor.nodeType === Node.TEXT_NODE) {
+ anchor = anchor.parentNode;
+ }
+ if (anchor.classList?.contains("highlight")) {
+ anchor = anchor.parentNode;
+ }
+ if (!modifyStart && range.endOffset === 0) {
+ do {
+ while (!anchor.previousSibling) {
+ anchor = anchor.parentNode;
+ }
+ anchor = anchor.previousSibling;
+ } while (!anchor.childNodes.length);
+ }
+ const parentTextLayer = anchor.parentElement?.closest(".textLayer");
+ const endDiv = this.#textLayers.get(parentTextLayer);
+ if (endDiv) {
+ endDiv.style.width = parentTextLayer.style.width;
+ endDiv.style.height = parentTextLayer.style.height;
+ endDiv.style.userSelect = "text";
+ anchor.parentElement.insertBefore(endDiv, modifyStart ? anchor : anchor.nextSibling);
+ }
+ prevRange = range.cloneRange();
+ }, {
+ signal
+ });
+ }
+}
+
+;// ./web/pdf_page_view.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const DEFAULT_LAYER_PROPERTIES = null;
+const LAYERS_ORDER = new Map([["canvasWrapper", 0], ["textLayer", 1], ["annotationLayer", 2], ["annotationEditorLayer", 3], ["xfaLayer", 3]]);
+class PDFPageView extends BasePDFPageView {
+ #abortSignal = null;
+ #annotationMode = AnnotationMode.ENABLE_FORMS;
+ #canvasWrapper = null;
+ #commentManager = null;
+ #enableAutoLinking = true;
+ #hasRestrictedScaling = false;
+ #isEditing = false;
+ #layerProperties = null;
+ #needsRestrictedScaling = false;
+ #originalViewport = null;
+ #previousRotation = null;
+ #scaleRoundX = 1;
+ #scaleRoundY = 1;
+ #textLayerMode = TextLayerMode.ENABLE;
+ #userUnit = 1;
+ #useThumbnailCanvas = {
+ directDrawing: true,
+ initialOptionalContent: true,
+ regularAnnotations: true
+ };
+ #layers = [null, null, null, null];
+ constructor(options) {
+ super(options);
+ const {
+ container,
+ defaultViewport
+ } = options;
+ this.renderingId = "page" + this.id;
+ this.#layerProperties = options.layerProperties || DEFAULT_LAYER_PROPERTIES;
+ this.#abortSignal = options.abortSignal || null;
+ this.pdfPage = null;
+ this.pageLabel = null;
+ this.rotation = 0;
+ this.scale = options.scale || (/* inlined export .DEFAULT_SCALE */1);
+ this.viewport = defaultViewport;
+ this.pdfPageRotate = defaultViewport.rotation;
+ this._optionalContentConfigPromise = options.optionalContentConfigPromise || null;
+ this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
+ this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
+ this.imageResourcesPath = options.imageResourcesPath || "";
+ this.enableDetailCanvas = options.enableDetailCanvas ?? true;
+ this.maxCanvasPixels = options.maxCanvasPixels ?? AppOptions.get("maxCanvasPixels");
+ this.maxCanvasDim = options.maxCanvasDim || AppOptions.get("maxCanvasDim");
+ this.capCanvasAreaFactor = options.capCanvasAreaFactor ?? AppOptions.get("capCanvasAreaFactor");
+ this.#enableAutoLinking = options.enableAutoLinking !== false;
+ this.#commentManager = options.commentManager || null;
+ this.l10n = options.l10n;
+ this.l10n ||= new genericl10n_GenericL10n();
+ this._isStandalone = !this.renderingQueue?.hasViewer();
+ this._container = container;
+ this._annotationCanvasMap = null;
+ this.annotationLayer = null;
+ this.annotationEditorLayer = null;
+ this.textLayer = null;
+ this.xfaLayer = null;
+ this.structTreeLayer = null;
+ this.drawLayer = null;
+ this.detailView = null;
+ const div = document.createElement("div");
+ div.className = "page";
+ div.setAttribute("data-page-number", this.id);
+ div.setAttribute("role", "region");
+ div.setAttribute("data-l10n-id", "pdfjs-page-landmark");
+ div.setAttribute("data-l10n-args", JSON.stringify({
+ page: this.id
+ }));
+ this.div = div;
+ this.#setDimensions();
+ container?.append(div);
+ if (this._isStandalone) {
+ container?.style.setProperty("--scale-factor", this.scale * PixelsPerInch.PDF_TO_CSS_UNITS);
+ if (this.pageColors?.background) {
+ container?.style.setProperty("--page-bg-color", this.pageColors.background);
+ }
+ const {
+ optionalContentConfigPromise
+ } = options;
+ if (optionalContentConfigPromise) {
+ optionalContentConfigPromise.then(optionalContentConfig => {
+ if (optionalContentConfigPromise !== this._optionalContentConfigPromise) {
+ return;
+ }
+ this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility;
+ });
+ }
+ if (!options.l10n) {
+ this.l10n.translate(this.div);
+ }
+ }
+ }
+ clone(id) {
+ const clone = new PDFPageView({
+ container: null,
+ eventBus: this.eventBus,
+ pagesColors: this.pageColors,
+ renderingQueue: this.renderingQueue,
+ enableOptimizedPartialRendering: this.enableOptimizedPartialRendering,
+ minDurationToUpdateCanvas: this.minDurationToUpdateCanvas,
+ defaultViewport: this.viewport,
+ id,
+ layerProperties: this.#layerProperties,
+ abortSignal: this.#abortSignal,
+ scale: this.scale,
+ optionalContentConfigPromise: this._optionalContentConfigPromise,
+ textLayerMode: this.#textLayerMode,
+ annotationMode: this.#annotationMode,
+ imageResourcesPath: this.imageResourcesPath,
+ enableDetailCanvas: this.enableDetailCanvas,
+ maxCanvasPixels: this.maxCanvasPixels,
+ maxCanvasDim: this.maxCanvasDim,
+ capCanvasAreaFactor: this.capCanvasAreaFactor,
+ enableAutoLinking: this.#enableAutoLinking,
+ commentManager: this.#commentManager,
+ l10n: this.l10n
+ });
+ clone.setPdfPage(this.pdfPage.clone(id - 1));
+ return clone;
+ }
+ #addLayer(div, name) {
+ const pos = LAYERS_ORDER.get(name);
+ const oldDiv = this.#layers[pos];
+ this.#layers[pos] = div;
+ if (oldDiv) {
+ oldDiv.replaceWith(div);
+ return;
+ }
+ for (let i = pos - 1; i >= 0; i--) {
+ const layer = this.#layers[i];
+ if (layer) {
+ layer.after(div);
+ return;
+ }
+ }
+ this.div.prepend(div);
+ }
+ #setDimensions() {
+ const {
+ div,
+ viewport
+ } = this;
+ if (viewport.userUnit !== this.#userUnit) {
+ if (viewport.userUnit !== 1) {
+ div.style.setProperty("--user-unit", viewport.userUnit);
+ } else {
+ div.style.removeProperty("--user-unit");
+ }
+ this.#userUnit = viewport.userUnit;
+ }
+ if (this.pdfPage) {
+ if (this.#previousRotation === viewport.rotation) {
+ return;
+ }
+ this.#previousRotation = viewport.rotation;
+ }
+ setLayerDimensions(div, viewport, true, false);
+ }
+ updatePageNumber(newPageNumber) {
+ const oldPageNumber = this.id;
+ if (oldPageNumber !== newPageNumber) {
+ this.id = newPageNumber;
+ this.renderingId = `page${newPageNumber}`;
+ if (this.pdfPage) {
+ this.pdfPage.pageNumber = newPageNumber;
+ }
+ this.setPageLabel(this.pageLabel);
+ const {
+ div
+ } = this;
+ div.setAttribute("data-page-number", newPageNumber);
+ div.setAttribute("data-l10n-args", JSON.stringify({
+ page: newPageNumber
+ }));
+ this._textHighlighter.pageIdx = newPageNumber - 1;
+ }
+ this.#layerProperties.annotationEditorUIManager?.updatePageIndex(oldPageNumber - 1, newPageNumber - 1);
+ }
+ setPdfPage(pdfPage) {
+ if (this._isStandalone && (this.pageColors?.foreground === "CanvasText" || this.pageColors?.background === "Canvas")) {
+ this._container?.style.setProperty("--hcm-highlight-filter", pdfPage.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight"));
+ this._container?.style.setProperty("--hcm-highlight-selected-filter", pdfPage.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "Highlight"));
+ }
+ this.pdfPage = pdfPage;
+ this.pdfPageRotate = pdfPage.rotate;
+ const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = pdfPage.getViewport({
+ scale: this.scale * PixelsPerInch.PDF_TO_CSS_UNITS,
+ rotation: totalRotation
+ });
+ this.#setDimensions();
+ this.reset();
+ }
+ destroy() {
+ this.reset();
+ this.pdfPage?.cleanup();
+ }
+ deleteMe(isCut) {
+ if (isCut) {
+ this.div.remove();
+ return;
+ }
+ this.destroy();
+ this.#layerProperties.annotationEditorUIManager?.deletePage(this.id);
+ }
+ hasEditableAnnotations() {
+ return !!this.annotationLayer?.hasEditableAnnotations();
+ }
+ get _textHighlighter() {
+ return shadow(this, "_textHighlighter", new TextHighlighter({
+ pageIndex: this.id - 1,
+ eventBus: this.eventBus,
+ findController: this.#layerProperties.findController
+ }));
+ }
+ #dispatchLayerRendered(name, error) {
+ this.eventBus.dispatch(name, {
+ source: this,
+ pageNumber: this.id,
+ error
+ });
+ }
+ async #renderAnnotationLayer(textLayerPromise = null) {
+ const {
+ annotationLayer,
+ textLayer
+ } = this;
+ let error = null;
+ try {
+ await this.annotationLayer.render({
+ viewport: this.viewport,
+ intent: "display",
+ structTreeLayer: this.structTreeLayer,
+ optionalContentConfigPromise: this._optionalContentConfigPromise
+ });
+ } catch (ex) {
+ console.error("#renderAnnotationLayer:", ex);
+ error = ex;
+ } finally {
+ this.#dispatchLayerRendered("annotationlayerrendered", error);
+ }
+ if (this.#enableAutoLinking && textLayerPromise) {
+ this.#injectLinkAnnotations(textLayerPromise, annotationLayer, textLayer);
+ }
+ }
+ _refreshAnnotationLayer() {
+ if (this._annotationCanvasMap?.size) {
+ this.annotationLayer?.refreshCanvases();
+ }
+ }
+ async #renderAnnotationEditorLayer() {
+ let error = null;
+ try {
+ await this.annotationEditorLayer.render({
+ viewport: this.viewport,
+ intent: "display"
+ });
+ } catch (ex) {
+ console.error("#renderAnnotationEditorLayer:", ex);
+ error = ex;
+ } finally {
+ this.#dispatchLayerRendered("annotationeditorlayerrendered", error);
+ }
+ }
+ async #renderDrawLayer() {
+ try {
+ await this.drawLayer.render({
+ intent: "display"
+ });
+ } catch (ex) {
+ console.error("#renderDrawLayer:", ex);
+ }
+ }
+ async #renderXfaLayer() {
+ let error = null;
+ try {
+ const result = await this.xfaLayer.render({
+ viewport: this.viewport,
+ intent: "display"
+ });
+ if (result?.textDivs && this._textHighlighter) {
+ this.#buildXfaTextContentItems(result.textDivs);
+ }
+ } catch (ex) {
+ console.error("#renderXfaLayer:", ex);
+ error = ex;
+ } finally {
+ if (this.xfaLayer?.div) {
+ this.l10n.pause();
+ this.#addLayer(this.xfaLayer.div, "xfaLayer");
+ this.l10n.resume();
+ }
+ this.#dispatchLayerRendered("xfalayerrendered", error);
+ }
+ }
+ async #renderTextLayer() {
+ let error = null;
+ try {
+ await this.textLayer.render({
+ viewport: this.viewport,
+ images: this.imageCoordinates ? new TextLayerImages(this.imagesRightClickMinSize, this.imageCoordinates, this.viewport, () => this.canvas) : null
+ });
+ } catch (ex) {
+ if (ex instanceof AbortException) {
+ return;
+ }
+ console.error("#renderTextLayer:", ex);
+ error = ex;
+ }
+ this.#dispatchLayerRendered("textlayerrendered", error);
+ this.#renderStructTreeLayer();
+ }
+ async #renderStructTreeLayer() {
+ const treeDom = await this.structTreeLayer?.render();
+ if (treeDom) {
+ this.l10n.pause();
+ this.structTreeLayer?.updateTextLayer();
+ if (this.canvas && treeDom.parentNode !== this.canvas) {
+ this.canvas.append(treeDom);
+ }
+ this.l10n.resume();
+ }
+ this.structTreeLayer?.show();
+ }
+ async #buildXfaTextContentItems(textDivs) {
+ const text = await this.pdfPage.getTextContent();
+ const items = [];
+ for (const item of text.items) {
+ items.push(item.str);
+ }
+ this._textHighlighter.setTextMapping(textDivs, items);
+ this._textHighlighter.enable();
+ }
+ async #injectLinkAnnotations(textLayerPromise, annotationLayer, textLayer) {
+ let error = null;
+ try {
+ await textLayerPromise;
+ if (annotationLayer !== this.annotationLayer || textLayer !== this.textLayer) {
+ return;
+ }
+ await annotationLayer.injectLinkAnnotations(Autolinker.processLinks(this));
+ } catch (ex) {
+ console.error("#injectLinkAnnotations:", ex);
+ error = ex;
+ }
+ this.#dispatchLayerRendered("linkannotationsadded", error);
+ }
+ _resetCanvas() {
+ super._resetCanvas();
+ this.#originalViewport = null;
+ }
+ reset({
+ keepAnnotationLayer = false,
+ keepAnnotationEditorLayer = false,
+ keepXfaLayer = false,
+ keepTextLayer = false,
+ keepCanvasWrapper = false,
+ preserveDetailViewState = false
+ } = {}) {
+ const keepPdfBugGroups = this.pdfPage?._pdfBug ?? false;
+ this.cancelRendering({
+ keepAnnotationLayer,
+ keepAnnotationEditorLayer,
+ keepXfaLayer,
+ keepTextLayer
+ });
+ this.renderingState = RenderingStates.INITIAL;
+ const div = this.div;
+ const childNodes = div.childNodes,
+ annotationLayerNode = keepAnnotationLayer && this.annotationLayer?.div || null,
+ annotationEditorLayerNode = keepAnnotationEditorLayer && this.annotationEditorLayer?.div || null,
+ xfaLayerNode = keepXfaLayer && this.xfaLayer?.div || null,
+ textLayerNode = keepTextLayer && this.textLayer?.div || null,
+ canvasWrapperNode = keepCanvasWrapper && this.#canvasWrapper || null;
+ for (let i = childNodes.length - 1; i >= 0; i--) {
+ const node = childNodes[i];
+ switch (node) {
+ case annotationLayerNode:
+ case annotationEditorLayerNode:
+ case xfaLayerNode:
+ case textLayerNode:
+ case canvasWrapperNode:
+ continue;
+ }
+ if (keepPdfBugGroups && node.classList.contains("pdfBugGroupsLayer")) {
+ continue;
+ }
+ node.remove();
+ const layerIndex = this.#layers.indexOf(node);
+ if (layerIndex >= 0) {
+ this.#layers[layerIndex] = null;
+ }
+ }
+ div.removeAttribute("data-loaded");
+ if (annotationLayerNode) {
+ this.annotationLayer.hide();
+ }
+ if (annotationEditorLayerNode) {
+ this.annotationEditorLayer.hide();
+ }
+ if (xfaLayerNode) {
+ this.xfaLayer.hide();
+ }
+ if (textLayerNode) {
+ this.textLayer.hide();
+ }
+ this.structTreeLayer?.hide();
+ if (!keepCanvasWrapper && this.#canvasWrapper) {
+ this.#canvasWrapper = null;
+ this._resetCanvas();
+ }
+ if (!preserveDetailViewState) {
+ this.detailView?.reset({
+ keepCanvas: keepCanvasWrapper
+ });
+ if (!keepCanvasWrapper) {
+ this.detailView = null;
+ }
+ }
+ }
+ toggleEditingMode(isEditing) {
+ this.#isEditing = isEditing;
+ if (!this.hasEditableAnnotations()) {
+ return;
+ }
+ this.reset({
+ keepAnnotationLayer: true,
+ keepAnnotationEditorLayer: true,
+ keepXfaLayer: true,
+ keepTextLayer: true,
+ keepCanvasWrapper: true
+ });
+ }
+ updateVisibleArea(visibleArea) {
+ if (this.enableDetailCanvas) {
+ if (this.#needsRestrictedScaling && this.maxCanvasPixels > 0 && visibleArea) {
+ this.detailView ??= new PDFPageDetailView({
+ pageView: this,
+ enableOptimizedPartialRendering: this.enableOptimizedPartialRendering,
+ imagesRightClickMinSize: -1
+ });
+ this.detailView.update({
+ visibleArea
+ });
+ } else if (this.detailView) {
+ this.detailView.reset();
+ this.detailView = null;
+ }
+ }
+ }
+ update({
+ scale = 0,
+ rotation = null,
+ optionalContentConfigPromise = null,
+ drawingDelay = -1
+ }) {
+ this.scale = scale || this.scale;
+ if (typeof rotation === "number") {
+ this.rotation = rotation;
+ }
+ if (optionalContentConfigPromise instanceof Promise) {
+ this._optionalContentConfigPromise = optionalContentConfigPromise;
+ optionalContentConfigPromise.then(optionalContentConfig => {
+ if (optionalContentConfigPromise !== this._optionalContentConfigPromise) {
+ return;
+ }
+ this.#useThumbnailCanvas.initialOptionalContent = optionalContentConfig.hasInitialVisibility;
+ });
+ }
+ this.#useThumbnailCanvas.directDrawing = true;
+ const totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = this.viewport.clone({
+ scale: this.scale * PixelsPerInch.PDF_TO_CSS_UNITS,
+ rotation: totalRotation
+ });
+ this.#setDimensions();
+ if (this._isStandalone) {
+ this._container?.style.setProperty("--scale-factor", this.viewport.scale);
+ }
+ this.#computeScale();
+ if (this.canvas) {
+ const onlyCssZoom = this.#hasRestrictedScaling && this.#needsRestrictedScaling;
+ const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000;
+ if (postponeDrawing || onlyCssZoom) {
+ if (postponeDrawing && !onlyCssZoom && this.renderingState !== RenderingStates.FINISHED) {
+ this.cancelRendering({
+ keepAnnotationLayer: true,
+ keepAnnotationEditorLayer: true,
+ keepXfaLayer: true,
+ keepTextLayer: true,
+ cancelExtraDelay: drawingDelay
+ });
+ this.renderingState = RenderingStates.FINISHED;
+ this.#useThumbnailCanvas.directDrawing = false;
+ }
+ this.cssTransform({
+ redrawAnnotationLayer: true,
+ redrawAnnotationEditorLayer: true,
+ redrawXfaLayer: true,
+ redrawTextLayer: !postponeDrawing,
+ hideTextLayer: postponeDrawing
+ });
+ if (!postponeDrawing) {
+ this.detailView?.update({
+ underlyingViewUpdated: true
+ });
+ this.dispatchPageRendered(true, false);
+ }
+ return;
+ }
+ }
+ this.cssTransform({});
+ this.annotationEditorLayer?.update(this.viewport);
+ this.reset({
+ keepAnnotationLayer: true,
+ keepAnnotationEditorLayer: true,
+ keepXfaLayer: true,
+ keepTextLayer: true,
+ keepCanvasWrapper: true,
+ preserveDetailViewState: true
+ });
+ this.detailView?.update({
+ underlyingViewUpdated: true
+ });
+ }
+ #computeScale() {
+ const {
+ width,
+ height
+ } = this.viewport;
+ const outputScale = this.outputScale = new OutputScale();
+ if (this.maxCanvasPixels === 0) {
+ const invScale = 1 / this.scale;
+ outputScale.sx *= invScale;
+ outputScale.sy *= invScale;
+ this.#needsRestrictedScaling = true;
+ } else {
+ this.#needsRestrictedScaling = outputScale.limitCanvas(width, height, this.maxCanvasPixels, this.maxCanvasDim, this.capCanvasAreaFactor);
+ if (this.#needsRestrictedScaling && this.enableDetailCanvas) {
+ const factor = this.enableOptimizedPartialRendering ? 4 : 2;
+ outputScale.sx /= factor;
+ outputScale.sy /= factor;
+ }
+ }
+ }
+ cancelRendering({
+ keepAnnotationLayer = false,
+ keepAnnotationEditorLayer = false,
+ keepXfaLayer = false,
+ keepTextLayer = false,
+ cancelExtraDelay = 0
+ } = {}) {
+ super.cancelRendering({
+ cancelExtraDelay
+ });
+ if (this.textLayer && (!keepTextLayer || !this.textLayer.div)) {
+ this.textLayer.cancel();
+ this.textLayer = null;
+ }
+ if (this.annotationLayer && (!keepAnnotationLayer || !this.annotationLayer.div)) {
+ this.annotationLayer.cancel();
+ this.annotationLayer = null;
+ this._annotationCanvasMap = null;
+ }
+ if (this.structTreeLayer && !this.textLayer) {
+ this.structTreeLayer = null;
+ }
+ if (this.annotationEditorLayer && (!keepAnnotationEditorLayer || !this.annotationEditorLayer.div || !this.textLayer)) {
+ if (this.drawLayer) {
+ this.drawLayer.cancel();
+ this.drawLayer = null;
+ }
+ this.annotationEditorLayer.cancel();
+ this.annotationEditorLayer = null;
+ }
+ if (this.drawLayer && !this.textLayer) {
+ this.drawLayer.cancel();
+ this.drawLayer = null;
+ }
+ if (this.xfaLayer && (!keepXfaLayer || !this.xfaLayer.div)) {
+ this.xfaLayer.cancel();
+ this.xfaLayer = null;
+ this._textHighlighter?.disable();
+ }
+ }
+ cssTransform({
+ redrawAnnotationLayer = false,
+ redrawAnnotationEditorLayer = false,
+ redrawXfaLayer = false,
+ redrawTextLayer = false,
+ hideTextLayer = false
+ }) {
+ const {
+ canvas
+ } = this;
+ if (!canvas) {
+ return;
+ }
+ const originalViewport = this.#originalViewport;
+ if (this.viewport !== originalViewport) {
+ const relativeRotation = (360 + this.viewport.rotation - originalViewport.rotation) % 360;
+ if (relativeRotation === 90 || relativeRotation === 270) {
+ const {
+ width,
+ height
+ } = this.viewport;
+ const scaleX = height / width;
+ const scaleY = width / height;
+ canvas.style.transform = `rotate(${relativeRotation}deg) scale(${scaleX},${scaleY})`;
+ } else {
+ canvas.style.transform = relativeRotation === 0 ? "" : `rotate(${relativeRotation}deg)`;
+ }
+ }
+ if (redrawAnnotationLayer && this.annotationLayer) {
+ this.#renderAnnotationLayer();
+ }
+ if (redrawAnnotationEditorLayer && this.annotationEditorLayer) {
+ if (this.drawLayer) {
+ this.#renderDrawLayer();
+ }
+ this.#renderAnnotationEditorLayer();
+ }
+ if (redrawXfaLayer && this.xfaLayer) {
+ this.#renderXfaLayer();
+ }
+ if (this.textLayer) {
+ if (hideTextLayer) {
+ this.textLayer.hide();
+ this.structTreeLayer?.hide();
+ } else if (redrawTextLayer) {
+ this.#renderTextLayer();
+ }
+ }
+ }
+ get width() {
+ return this.viewport.width;
+ }
+ get height() {
+ return this.viewport.height;
+ }
+ getPagePoint(x, y) {
+ return this.viewport.convertToPdfPoint(x, y);
+ }
+ _ensureCanvasWrapper() {
+ let canvasWrapper = this.#canvasWrapper;
+ if (!canvasWrapper) {
+ canvasWrapper = this.#canvasWrapper = document.createElement("div");
+ canvasWrapper.classList.add("canvasWrapper");
+ this.#addLayer(canvasWrapper, "canvasWrapper");
+ }
+ return canvasWrapper;
+ }
+ _getRenderingContext(canvas, transform, recordOperations, recordImages) {
+ return {
+ canvas,
+ transform,
+ viewport: this.viewport,
+ annotationMode: this.#annotationMode,
+ optionalContentConfigPromise: this._optionalContentConfigPromise,
+ annotationCanvasMap: this._annotationCanvasMap,
+ pageColors: this.pageColors,
+ isEditing: this.#isEditing,
+ recordOperations,
+ recordImages
+ };
+ }
+ async draw() {
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ console.error("Must be in new state before drawing");
+ this.reset();
+ }
+ const {
+ div,
+ l10n,
+ pdfPage,
+ viewport
+ } = this;
+ if (!pdfPage) {
+ this.renderingState = RenderingStates.FINISHED;
+ throw new Error("pdfPage is not loaded");
+ }
+ this.renderingState = RenderingStates.RUNNING;
+ const canvasWrapper = this._ensureCanvasWrapper();
+ if (!this.textLayer && this.#textLayerMode !== TextLayerMode.DISABLE && !pdfPage.isPureXfa) {
+ this._accessibilityManager ||= new TextAccessibilityManager();
+ this.textLayer = new TextLayerBuilder({
+ pdfPage,
+ highlighter: this._textHighlighter,
+ accessibilityManager: this._accessibilityManager,
+ enablePermissions: this.#textLayerMode === TextLayerMode.ENABLE_PERMISSIONS,
+ onAppend: textLayerDiv => {
+ this.l10n.pause();
+ this.#addLayer(textLayerDiv, "textLayer");
+ this.l10n.resume();
+ },
+ abortSignal: this.#abortSignal
+ });
+ if (this.enableSelectionRendering) {
+ this.textLayer.div.classList.add("selectionRendering");
+ }
+ }
+ if (!this.annotationLayer && this.#annotationMode !== AnnotationMode.DISABLE) {
+ const {
+ annotationStorage,
+ annotationEditorUIManager,
+ downloadManager,
+ enableComment,
+ enableScripting,
+ fieldObjectsPromise,
+ hasJSActionsPromise,
+ linkService
+ } = this.#layerProperties;
+ this._annotationCanvasMap ||= new Map();
+ this.annotationLayer = new AnnotationLayerBuilder({
+ pdfPage,
+ annotationStorage,
+ imageResourcesPath: this.imageResourcesPath,
+ renderForms: this.#annotationMode === AnnotationMode.ENABLE_FORMS,
+ linkService,
+ downloadManager,
+ enableComment,
+ enableScripting,
+ hasJSActionsPromise,
+ fieldObjectsPromise,
+ annotationCanvasMap: this._annotationCanvasMap,
+ accessibilityManager: this._accessibilityManager,
+ annotationEditorUIManager,
+ commentManager: this.#commentManager,
+ onAppend: annotationLayerDiv => {
+ this.#addLayer(annotationLayerDiv, "annotationLayer");
+ }
+ });
+ }
+ const {
+ width,
+ height
+ } = viewport;
+ this.#originalViewport = viewport;
+ const {
+ canvas,
+ prevCanvas
+ } = this._createCanvas(newCanvas => {
+ canvasWrapper.prepend(newCanvas);
+ });
+ canvas.setAttribute("role", "presentation");
+ if (!this.outputScale) {
+ this.#computeScale();
+ }
+ const {
+ outputScale
+ } = this;
+ this.#hasRestrictedScaling = this.#needsRestrictedScaling;
+ const sfx = approximateFraction(outputScale.sx);
+ const sfy = approximateFraction(outputScale.sy);
+ const canvasWidth = canvas.width = floorToDivide(calcRound(width * outputScale.sx), sfx[0]);
+ const canvasHeight = canvas.height = floorToDivide(calcRound(height * outputScale.sy), sfy[0]);
+ const pageWidth = floorToDivide(calcRound(width), sfx[1]);
+ const pageHeight = floorToDivide(calcRound(height), sfy[1]);
+ outputScale.sx = canvasWidth / pageWidth;
+ outputScale.sy = canvasHeight / pageHeight;
+ if (this.#scaleRoundX !== sfx[1]) {
+ div.style.setProperty("--scale-round-x", `${sfx[1]}px`);
+ this.#scaleRoundX = sfx[1];
+ }
+ if (this.#scaleRoundY !== sfy[1]) {
+ div.style.setProperty("--scale-round-y", `${sfy[1]}px`);
+ this.#scaleRoundY = sfy[1];
+ }
+ const recordBBoxes = this.enableOptimizedPartialRendering && this.#hasRestrictedScaling && !this.recordedBBoxes;
+ const recordImages = this.imagesRightClickMinSize !== -1 && !this.imageCoordinates;
+ const transform = outputScale.scaled ? [outputScale.sx, 0, 0, outputScale.sy, 0, 0] : null;
+ const resultPromise = this._drawCanvas(this._getRenderingContext(canvas, transform, recordBBoxes, recordImages), () => {
+ prevCanvas?.remove();
+ this._resetCanvas();
+ }, renderTask => {
+ this.#useThumbnailCanvas.regularAnnotations = !renderTask.separateAnnots;
+ this.dispatchPageRendered(false, false);
+ }).then(async () => {
+ if (this.renderingState !== RenderingStates.FINISHED) {
+ return;
+ }
+ this.structTreeLayer ||= new StructTreeLayerBuilder(pdfPage, viewport.rawDims);
+ const textLayerPromise = this.textLayer ? this.#renderTextLayer() : null;
+ if (this.annotationLayer) {
+ await this.#renderAnnotationLayer(textLayerPromise);
+ }
+ this.drawLayer ||= new DrawLayerBuilder({
+ pageIndex: this.id,
+ textLayer: this.enableSelectionRendering ? this.textLayer?.div : null,
+ filterFactory: this.pdfPage?.filterFactory,
+ pageColors: this.pageColors
+ });
+ await this.#renderDrawLayer();
+ this.drawLayer.setParent(canvasWrapper);
+ const {
+ annotationEditorUIManager
+ } = this.#layerProperties;
+ if (!annotationEditorUIManager) {
+ return;
+ }
+ if (this.annotationLayer || this.#annotationMode === AnnotationMode.DISABLE) {
+ this.annotationEditorLayer ||= new AnnotationEditorLayerBuilder({
+ uiManager: annotationEditorUIManager,
+ pageIndex: this.id - 1,
+ l10n,
+ structTreeLayer: this.structTreeLayer,
+ accessibilityManager: this._accessibilityManager,
+ annotationLayer: this.annotationLayer?.annotationLayer,
+ textLayer: this.textLayer,
+ drawLayer: this.drawLayer.getDrawLayer(),
+ onAppend: annotationEditorLayerDiv => {
+ this.#addLayer(annotationEditorLayerDiv, "annotationEditorLayer");
+ }
+ });
+ this.#renderAnnotationEditorLayer();
+ }
+ });
+ if (pdfPage.isPureXfa) {
+ if (!this.xfaLayer) {
+ const {
+ annotationStorage,
+ linkService
+ } = this.#layerProperties;
+ this.xfaLayer = new XfaLayerBuilder({
+ pdfPage,
+ annotationStorage,
+ linkService
+ });
+ }
+ this.#renderXfaLayer();
+ }
+ div.setAttribute("data-loaded", true);
+ this.dispatchPageRender();
+ return resultPromise;
+ }
+ setPageLabel(label) {
+ this.pageLabel = typeof label === "string" ? label : null;
+ this.div.setAttribute("data-l10n-args", JSON.stringify({
+ page: this.pageLabel ?? this.id
+ }));
+ if (this.pageLabel !== null) {
+ this.div.setAttribute("data-page-label", this.pageLabel);
+ } else {
+ this.div.removeAttribute("data-page-label");
+ }
+ }
+ get thumbnailCanvas() {
+ const {
+ directDrawing,
+ initialOptionalContent,
+ regularAnnotations
+ } = this.#useThumbnailCanvas;
+ return directDrawing && initialOptionalContent && regularAnnotations ? this.canvas : null;
+ }
+}
+
+;// ./web/pdf_viewer.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const DEFAULT_CACHE_SIZE = 10;
+const PagesCountLimit = {
+ FORCE_SCROLL_MODE_PAGE: 10000,
+ FORCE_LAZY_PAGE_INIT: 5000,
+ PAUSE_EAGER_PAGE_INIT: 250
+};
+function isValidAnnotationEditorMode(mode) {
+ return Object.values(AnnotationEditorType).includes(mode) && mode !== AnnotationEditorType.DISABLE;
+}
+class PDFPageViewBuffer {
+ #buf = new Set();
+ #size = 0;
+ constructor(size) {
+ this.#size = size;
+ }
+ push(view) {
+ const buf = this.#buf;
+ if (buf.has(view)) {
+ buf.delete(view);
+ }
+ buf.add(view);
+ if (buf.size > this.#size) {
+ this.#destroyFirstView();
+ }
+ }
+ resize(newSize, idsToKeep = null) {
+ this.#size = newSize;
+ const buf = this.#buf;
+ if (idsToKeep) {
+ const ii = buf.size;
+ let i = 1;
+ for (const view of buf) {
+ if (idsToKeep.has(view.id)) {
+ buf.delete(view);
+ buf.add(view);
+ }
+ if (++i > ii) {
+ break;
+ }
+ }
+ }
+ while (buf.size > this.#size) {
+ this.#destroyFirstView();
+ }
+ }
+ has(view) {
+ return this.#buf.has(view);
+ }
+ [Symbol.iterator]() {
+ return this.#buf.keys();
+ }
+ #destroyFirstView() {
+ const firstView = this.#buf.keys().next().value;
+ firstView?.destroy();
+ this.#buf.delete(firstView);
+ }
+}
+class PDFViewer {
+ #buffer = null;
+ #altTextManager = null;
+ #annotationEditorHighlightColors = null;
+ #annotationEditorMode = AnnotationEditorType.NONE;
+ #annotationEditorUIManager = null;
+ #annotationMode = AnnotationMode.ENABLE_FORMS;
+ #commentManager = null;
+ #containerTopLeft = null;
+ #editorUndoBar = null;
+ #enableHighlightFloatingButton = false;
+ #enablePermissions = false;
+ #enableUpdatedAddImage = false;
+ #enableNewAltTextWhenAddingImage = false;
+ #enableAutoLinking = true;
+ #abortSignal = null;
+ #eventAC = null;
+ #minDurationToUpdateCanvas = 0;
+ #mlManager = null;
+ #panPosition = [NaN, NaN];
+ #printingAllowed = true;
+ #scrollTimeoutId = null;
+ #staleLocation = false;
+ #switchAnnotationEditorModeAC = null;
+ #switchAnnotationEditorModeTimeoutId = null;
+ #copyAllInProgress = false;
+ #hiddenCopyElement = null;
+ #previousContainerHeight = 0;
+ #resizeObserver = new ResizeObserver(this.#resizeObserverCallback.bind(this));
+ #scrollModePageState = null;
+ #scaleTimeoutId = null;
+ #signatureManager = null;
+ #supportsPinchToZoom = true;
+ #textLayerMode = TextLayerMode.ENABLE;
+ #viewerAlert = null;
+ #copiedPageViews = null;
+ #savedPageViews = null;
+ #deletedPageNumbers = null;
+ constructor(options) {
+ const viewerVersion = "6.3.289";
+ if (version !== viewerVersion) {
+ throw new Error(`The API version "${version}" does not match the Viewer version "${viewerVersion}".`);
+ }
+ this.container = options.container;
+ this.viewer = options.viewer || options.container.firstElementChild;
+ this.#viewerAlert = options.viewerAlert || null;
+ if (this.container?.tagName !== "DIV" || this.viewer?.tagName !== "DIV") {
+ throw new Error("Invalid `container` and/or `viewer` option.");
+ }
+ if (this.container.offsetParent && getComputedStyle(this.container).position !== "absolute") {
+ throw new Error("The `container` must be absolutely positioned.");
+ }
+ this.#resizeObserver.observe(this.container);
+ this.eventBus = options.eventBus;
+ this.linkService = options.linkService || new SimpleLinkService();
+ this.downloadManager = options.downloadManager || null;
+ this.findController = options.findController || null;
+ this.#altTextManager = options.altTextManager || null;
+ this.#commentManager = options.commentManager || null;
+ this.#signatureManager = options.signatureManager || null;
+ this.#editorUndoBar = options.editorUndoBar || null;
+ if (this.findController) {
+ this.findController.onIsPageVisible = pageNumber => this._getVisiblePages().ids.has(pageNumber);
+ }
+ this._scriptingManager = options.scriptingManager || null;
+ this.#textLayerMode = options.textLayerMode ?? TextLayerMode.ENABLE;
+ this.#annotationMode = options.annotationMode ?? AnnotationMode.ENABLE_FORMS;
+ this.#annotationEditorMode = options.annotationEditorMode ?? AnnotationEditorType.NONE;
+ this.#annotationEditorHighlightColors = options.annotationEditorHighlightColors || null;
+ this.#enableHighlightFloatingButton = options.enableHighlightFloatingButton === true;
+ this.#enableUpdatedAddImage = options.enableUpdatedAddImage === true;
+ this.#enableNewAltTextWhenAddingImage = options.enableNewAltTextWhenAddingImage === true;
+ this.imageResourcesPath = options.imageResourcesPath || "";
+ this.enablePrintAutoRotate = options.enablePrintAutoRotate || false;
+ this.removePageBorders = options.removePageBorders || false;
+ this.maxCanvasPixels = options.maxCanvasPixels;
+ this.maxCanvasDim = options.maxCanvasDim;
+ this.capCanvasAreaFactor = options.capCanvasAreaFactor;
+ this.enableDetailCanvas = options.enableDetailCanvas ?? true;
+ this.enableOptimizedPartialRendering = options.enableOptimizedPartialRendering ?? false;
+ this.enableSelectionRendering = options.enableSelectionRendering !== false;
+ this.imagesRightClickMinSize = options.imagesRightClickMinSize ?? -1;
+ this.l10n = options.l10n;
+ this.l10n ||= new genericl10n_GenericL10n();
+ this.#enablePermissions = options.enablePermissions || false;
+ this.pageColors = options.pageColors || null;
+ this.#mlManager = options.mlManager || null;
+ this.#supportsPinchToZoom = options.supportsPinchToZoom !== false;
+ this.#enableAutoLinking = options.enableAutoLinking !== false;
+ this.#minDurationToUpdateCanvas = options.minDurationToUpdateCanvas ?? 500;
+ this.defaultRenderingQueue = !options.renderingQueue;
+ if (this.defaultRenderingQueue) {
+ this.renderingQueue = new PDFRenderingQueue();
+ this.renderingQueue.setViewer(this);
+ } else {
+ this.renderingQueue = options.renderingQueue;
+ }
+ const {
+ abortSignal
+ } = options;
+ this.#abortSignal = abortSignal || null;
+ abortSignal?.addEventListener("abort", () => {
+ this.#resizeObserver.disconnect();
+ this.#resizeObserver = null;
+ }, {
+ once: true
+ });
+ this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this), abortSignal);
+ this.presentationModeState = PresentationModeState.UNKNOWN;
+ this._resetView();
+ if (this.removePageBorders) {
+ this.viewer.classList.add("removePageBorders");
+ }
+ this.#updateContainerHeightCss();
+ this.eventBus.on("thumbnailrendered", ({
+ pageNumber,
+ pdfPage
+ }) => {
+ const pageView = this._pages[pageNumber - 1];
+ if (!this.#buffer.has(pageView)) {
+ pdfPage?.cleanup();
+ }
+ }, internalOpt);
+ if (!options.l10n) {
+ this.l10n.translate(this.container);
+ }
+ }
+ get printingAllowed() {
+ return this.#printingAllowed;
+ }
+ get pagesCount() {
+ return this._pages.length;
+ }
+ getPageView(index) {
+ return this._pages[index];
+ }
+ getCachedPageViews() {
+ return new Set(this.#buffer);
+ }
+ get pageViewsReady() {
+ return this._pages.every(pageView => pageView?.pdfPage);
+ }
+ clearSelection() {
+ const selection = document.getSelection();
+ if (!selection || selection.isCollapsed) {
+ return;
+ }
+ for (let i = 0, ii = selection.rangeCount; i < ii; i++) {
+ if (selection.getRangeAt(i).intersectsNode(this.viewer)) {
+ selection.removeAllRanges?.();
+ selection.empty?.();
+ return;
+ }
+ }
+ }
+ get renderForms() {
+ return this.#annotationMode === AnnotationMode.ENABLE_FORMS;
+ }
+ get enableScripting() {
+ return !!this._scriptingManager;
+ }
+ get currentPageNumber() {
+ return this._currentPageNumber;
+ }
+ set currentPageNumber(val) {
+ if (!Number.isInteger(val)) {
+ throw new Error("Invalid page number.");
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (this._currentPageNumber !== val) {
+ this.clearSelection();
+ }
+ if (!this._setCurrentPageNumber(val, true)) {
+ console.error(`currentPageNumber: "${val}" is not a valid page.`);
+ }
+ }
+ _setCurrentPageNumber(val, resetCurrentPageView = false) {
+ if (this._currentPageNumber === val) {
+ if (resetCurrentPageView) {
+ this.#resetCurrentPageView();
+ }
+ return true;
+ }
+ if (!(0 < val && val <= this.pagesCount)) {
+ return false;
+ }
+ const previous = this._currentPageNumber;
+ this._currentPageNumber = val;
+ this.eventBus.dispatch("pagechanging", {
+ source: this,
+ pageNumber: val,
+ pageLabel: this._pageLabels?.[val - 1] ?? null,
+ previous
+ });
+ if (resetCurrentPageView) {
+ this.#resetCurrentPageView();
+ }
+ return true;
+ }
+ get currentPageLabel() {
+ return this._pageLabels?.[this._currentPageNumber - 1] ?? null;
+ }
+ set currentPageLabel(val) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ let page = val | 0;
+ if (this._pageLabels) {
+ const i = this._pageLabels.indexOf(val);
+ if (i >= 0) {
+ page = i + 1;
+ }
+ }
+ if (this._currentPageNumber !== page) {
+ this.clearSelection();
+ }
+ if (!this._setCurrentPageNumber(page, true)) {
+ console.error(`currentPageLabel: "${val}" is not a valid page.`);
+ }
+ }
+ get currentScale() {
+ return this._currentScale !== (/* inlined export .UNKNOWN_SCALE */0) ? this._currentScale : (/* inlined export .DEFAULT_SCALE */1);
+ }
+ set currentScale(val) {
+ if (isNaN(val)) {
+ throw new Error("Invalid numeric scale.");
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ this.#setScale(val, {
+ noScroll: false
+ });
+ }
+ get currentScaleValue() {
+ return this._currentScaleValue;
+ }
+ set currentScaleValue(val) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ this.#setScale(val, {
+ noScroll: false
+ });
+ }
+ get pagesRotation() {
+ return this._pagesRotation;
+ }
+ set pagesRotation(rotation) {
+ if (!isValidRotation(rotation)) {
+ throw new Error("Invalid pages rotation angle.");
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ rotation %= 360;
+ if (rotation < 0) {
+ rotation += 360;
+ }
+ if (this._pagesRotation === rotation) {
+ return;
+ }
+ this.clearSelection();
+ this._pagesRotation = rotation;
+ const pageNumber = this._currentPageNumber;
+ this.refresh(true, {
+ rotation
+ });
+ if (this._currentScaleValue) {
+ this.#setScale(this._currentScaleValue, {
+ noScroll: true
+ });
+ }
+ this.eventBus.dispatch("rotationchanging", {
+ source: this,
+ pagesRotation: rotation,
+ pageNumber
+ });
+ if (this.defaultRenderingQueue) {
+ this.update();
+ }
+ }
+ get firstPagePromise() {
+ return this.pdfDocument ? this._firstPageCapability.promise : null;
+ }
+ get onePageRendered() {
+ return this.pdfDocument ? this._onePageRenderedCapability.promise : null;
+ }
+ get pagesPromise() {
+ return this.pdfDocument ? this._pagesCapability.promise : null;
+ }
+ get _layerProperties() {
+ const self = this;
+ return shadow(this, "_layerProperties", {
+ get annotationEditorUIManager() {
+ return self.#annotationEditorUIManager;
+ },
+ get annotationStorage() {
+ return self.pdfDocument?.annotationStorage;
+ },
+ get downloadManager() {
+ return self.downloadManager;
+ },
+ get enableComment() {
+ return !!self.#commentManager;
+ },
+ get enableScripting() {
+ return !!self._scriptingManager;
+ },
+ get fieldObjectsPromise() {
+ return self.pdfDocument?.getFieldObjects();
+ },
+ get findController() {
+ return self.findController;
+ },
+ get hasJSActionsPromise() {
+ return self.pdfDocument?.hasJSActions();
+ },
+ get linkService() {
+ return self.linkService;
+ }
+ });
+ }
+ #setPrintingAllowed(isAllowed) {
+ this.#printingAllowed = isAllowed;
+ this.eventBus.dispatch("printingallowed", {
+ source: this,
+ isAllowed
+ });
+ }
+ #initializePermissions(permissions) {
+ const params = {
+ annotationEditorMode: this.#annotationEditorMode,
+ annotationMode: this.#annotationMode,
+ textLayerMode: this.#textLayerMode
+ };
+ if (!permissions) {
+ this.#setPrintingAllowed(true);
+ return params;
+ }
+ this.#setPrintingAllowed(permissions.has(PermissionFlag.PRINT_HIGH_QUALITY) || permissions.has(PermissionFlag.PRINT));
+ if (!permissions.has(PermissionFlag.COPY) && this.#textLayerMode === TextLayerMode.ENABLE) {
+ params.textLayerMode = TextLayerMode.ENABLE_PERMISSIONS;
+ }
+ if (!permissions.has(PermissionFlag.MODIFY_CONTENTS)) {
+ params.annotationEditorMode = AnnotationEditorType.DISABLE;
+ }
+ if (!permissions.has(PermissionFlag.MODIFY_ANNOTATIONS) && !permissions.has(PermissionFlag.FILL_INTERACTIVE_FORMS) && this.#annotationMode === AnnotationMode.ENABLE_FORMS) {
+ params.annotationMode = AnnotationMode.ENABLE;
+ }
+ return params;
+ }
+ async #onePageRenderedOrForceFetch(signal) {
+ if (document.visibilityState === "hidden" || !this.container.offsetParent || this._getVisiblePages().views.length === 0) {
+ return;
+ }
+ const hiddenCapability = Promise.withResolvers(),
+ ac = new AbortController();
+ document.addEventListener("visibilitychange", () => {
+ if (document.visibilityState === "hidden") {
+ hiddenCapability.resolve();
+ }
+ }, {
+ signal: AbortSignal.any([signal, ac.signal])
+ });
+ await Promise.race([this._onePageRenderedCapability.promise, hiddenCapability.promise]);
+ ac.abort();
+ }
+ async getAllText(interruptSignal = null) {
+ const texts = [];
+ const buffer = [];
+ for (let pageNum = 1, pagesCount = this.pdfDocument.numPages; pageNum <= pagesCount; ++pageNum) {
+ if (interruptSignal?.aborted) {
+ return null;
+ }
+ buffer.length = 0;
+ const page = await this.pdfDocument.getPage(pageNum);
+ const {
+ items
+ } = await page.getTextContent();
+ for (const item of items) {
+ if (item.str) {
+ buffer.push(item.str);
+ }
+ if (item.hasEOL) {
+ buffer.push("\n");
+ }
+ }
+ texts.push(removeNullCharacters(buffer.join("")));
+ }
+ return texts.join("\n");
+ }
+ #copyCallback(textLayerMode, event) {
+ const selection = document.getSelection();
+ const {
+ focusNode,
+ anchorNode
+ } = selection;
+ if (anchorNode && focusNode && selection.containsNode(this.#hiddenCopyElement)) {
+ if (this.#copyAllInProgress || textLayerMode === TextLayerMode.ENABLE_PERMISSIONS) {
+ stopEvent(event);
+ return;
+ }
+ this.#copyAllInProgress = true;
+ const {
+ classList
+ } = this.viewer;
+ classList.add("copyAll");
+ const keydownAC = new AbortController(),
+ interruptAC = new AbortController();
+ window.addEventListener("keydown", ev => {
+ if (ev.key === "Escape") {
+ interruptAC.abort();
+ }
+ }, {
+ signal: keydownAC.signal
+ });
+ this.getAllText(interruptAC.signal).then(async text => {
+ if (text !== null) {
+ await navigator.clipboard.writeText(text);
+ }
+ }).catch(reason => {
+ console.warn(`Something goes wrong when extracting the text: ${reason.message}`);
+ }).finally(() => {
+ this.#copyAllInProgress = false;
+ keydownAC.abort();
+ classList.remove("copyAll");
+ });
+ stopEvent(event);
+ }
+ }
+ setDocument(pdfDocument) {
+ if (this.pdfDocument) {
+ this.eventBus.dispatch("pagesdestroy", {
+ source: this
+ });
+ this._cancelRendering();
+ this._resetView();
+ this.findController?.setDocument(null);
+ this._scriptingManager?.setDocument(null);
+ this.#annotationEditorUIManager?.destroy();
+ this.#annotationEditorUIManager = null;
+ this.#annotationEditorMode = AnnotationEditorType.NONE;
+ this.#printingAllowed = true;
+ }
+ this.pdfDocument = pdfDocument;
+ if (!pdfDocument) {
+ return;
+ }
+ const pagesCount = pdfDocument.numPages;
+ const firstPagePromise = pdfDocument.getPage(1);
+ const optionalContentConfigPromise = pdfDocument.getOptionalContentConfig({
+ intent: "display"
+ });
+ const permissionsPromise = this.#enablePermissions ? pdfDocument.getPermissions() : Promise.resolve();
+ const {
+ eventBus,
+ pageColors,
+ viewer
+ } = this;
+ this.#eventAC = new AbortController();
+ const {
+ signal
+ } = this.#eventAC;
+ const evtOpts = {
+ signal,
+ ...internalOpt
+ };
+ if (pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) {
+ console.warn("Forcing PAGE-scrolling for performance reasons, given the length of the document.");
+ const mode = this._scrollMode = ScrollMode.PAGE;
+ eventBus.dispatch("scrollmodechanged", {
+ source: this,
+ mode
+ });
+ }
+ this._pagesCapability.promise.then(() => {
+ eventBus.dispatch("pagesloaded", {
+ source: this,
+ pagesCount
+ });
+ }, () => {});
+ const onBeforeDraw = evt => {
+ const pageView = this._pages[evt.pageNumber - 1];
+ if (!pageView) {
+ return;
+ }
+ this.#buffer.push(pageView);
+ };
+ eventBus.on("pagerender", onBeforeDraw, evtOpts);
+ const onAfterDraw = evt => {
+ if (evt.cssTransform || evt.isDetailView) {
+ return;
+ }
+ this._onePageRenderedCapability.resolve({
+ timestamp: evt.timestamp
+ });
+ eventBus.off("pagerendered", onAfterDraw);
+ };
+ eventBus.on("pagerendered", onAfterDraw, evtOpts);
+ Promise.all([firstPagePromise, permissionsPromise]).then(([firstPdfPage, permissions]) => {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ this._firstPageCapability.resolve(firstPdfPage);
+ this._optionalContentConfigPromise = optionalContentConfigPromise;
+ const {
+ annotationEditorMode,
+ annotationMode,
+ textLayerMode
+ } = this.#initializePermissions(permissions);
+ if (textLayerMode !== TextLayerMode.DISABLE) {
+ const element = this.#hiddenCopyElement = document.createElement("div");
+ element.id = "hiddenCopyElement";
+ element.style.cssText = "position:absolute;top:0;left:0;width:0;height:0;display:none";
+ viewer.before(element);
+ }
+ if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
+ const mode = annotationEditorMode;
+ if (pdfDocument.isPureXfa) {
+ console.warn("Warning: XFA-editing is not implemented.");
+ } else if (isValidAnnotationEditorMode(mode)) {
+ this.#annotationEditorUIManager = new AnnotationEditorUIManager(this.container, viewer, this.#viewerAlert, this.#altTextManager, this.#commentManager, this.#signatureManager, eventBus, pdfDocument, pageColors, this.#annotationEditorHighlightColors, this.#enableHighlightFloatingButton, this.#enableUpdatedAddImage, this.#enableNewAltTextWhenAddingImage, this.#mlManager, this.#editorUndoBar, this.#supportsPinchToZoom);
+ eventBus.dispatch("annotationeditoruimanager", {
+ source: this,
+ uiManager: this.#annotationEditorUIManager
+ });
+ if (mode !== AnnotationEditorType.NONE) {
+ this.#preloadEditingData(mode);
+ this.#annotationEditorUIManager.updateMode(mode);
+ }
+ } else {
+ console.error(`Invalid AnnotationEditor mode: ${mode}`);
+ }
+ }
+ const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : viewer;
+ const scale = this.currentScale;
+ const viewport = firstPdfPage.getViewport({
+ scale: scale * PixelsPerInch.PDF_TO_CSS_UNITS
+ });
+ viewer.style.setProperty("--scale-factor", viewport.scale);
+ if (pageColors?.background) {
+ viewer.style.setProperty("--page-bg-color", pageColors.background);
+ }
+ if (pageColors?.foreground === "CanvasText" || pageColors?.background === "Canvas") {
+ viewer.style.setProperty("--hcm-highlight-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight", "CanvasText", "Canvas", "HighlightText", "Highlight"));
+ viewer.style.setProperty("--hcm-highlight-selected-filter", pdfDocument.filterFactory.addHighlightHCMFilter("highlight_selected", "CanvasText", "Canvas", "HighlightText", "ButtonText"));
+ }
+ for (let pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ const pageView = new PDFPageView({
+ container: viewerElement,
+ eventBus,
+ id: pageNum,
+ scale,
+ defaultViewport: viewport.clone(),
+ optionalContentConfigPromise,
+ renderingQueue: this.renderingQueue,
+ textLayerMode,
+ annotationMode,
+ imageResourcesPath: this.imageResourcesPath,
+ maxCanvasPixels: this.maxCanvasPixels,
+ maxCanvasDim: this.maxCanvasDim,
+ capCanvasAreaFactor: this.capCanvasAreaFactor,
+ enableDetailCanvas: this.enableDetailCanvas,
+ enableOptimizedPartialRendering: this.enableOptimizedPartialRendering,
+ enableSelectionRendering: this.enableSelectionRendering,
+ imagesRightClickMinSize: this.imagesRightClickMinSize,
+ pageColors,
+ l10n: this.l10n,
+ layerProperties: this._layerProperties,
+ enableAutoLinking: this.#enableAutoLinking,
+ minDurationToUpdateCanvas: this.#minDurationToUpdateCanvas,
+ commentManager: this.#commentManager,
+ abortSignal: this.#abortSignal
+ });
+ this._pages.push(pageView);
+ }
+ this._pages[0]?.setPdfPage(firstPdfPage);
+ if (this._scrollMode === ScrollMode.PAGE) {
+ this.#ensurePageViewVisible();
+ } else if (this._spreadMode !== SpreadMode.NONE) {
+ this._updateSpreadMode();
+ }
+ eventBus.on("annotationeditorlayerrendered", evt => {
+ if (this.#annotationEditorUIManager) {
+ eventBus.dispatch("annotationeditormodechanged", {
+ source: this,
+ mode: this.#annotationEditorMode
+ });
+ }
+ }, {
+ once: true,
+ signal,
+ ...internalOpt
+ });
+ this.#onePageRenderedOrForceFetch(signal).then(async () => {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ this.findController?.setDocument(pdfDocument);
+ this._scriptingManager?.setDocument(pdfDocument);
+ if (this.#hiddenCopyElement) {
+ document.addEventListener("copy", this.#copyCallback.bind(this, textLayerMode), {
+ signal
+ });
+ }
+ if (pdfDocument.loadingParams.disableAutoFetch || pagesCount > PagesCountLimit.FORCE_LAZY_PAGE_INIT) {
+ this._pagesCapability.resolve();
+ return;
+ }
+ let getPagesLeft = pagesCount - 1;
+ if (getPagesLeft <= 0) {
+ this._pagesCapability.resolve();
+ return;
+ }
+ for (let pageNum = 2; pageNum <= pagesCount; ++pageNum) {
+ const promise = pdfDocument.getPage(pageNum).then(pdfPage => {
+ const pageView = this._pages[pageNum - 1];
+ if (!pageView.pdfPage) {
+ pageView.setPdfPage(pdfPage);
+ }
+ if (--getPagesLeft === 0) {
+ this._pagesCapability.resolve();
+ }
+ }, reason => {
+ console.error(`Unable to get page ${pageNum} to initialize viewer`, reason);
+ if (--getPagesLeft === 0) {
+ this._pagesCapability.resolve();
+ }
+ });
+ if (pageNum % PagesCountLimit.PAUSE_EAGER_PAGE_INIT === 0) {
+ await promise;
+ }
+ }
+ });
+ eventBus.dispatch("pagesinit", {
+ source: this
+ });
+ pdfDocument.getMetadata().then(({
+ info
+ }) => {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ if (info.Language) {
+ viewer.lang = info.Language;
+ }
+ });
+ if (this.defaultRenderingQueue) {
+ this.update();
+ }
+ }).catch(reason => {
+ console.error("Unable to initialize viewer", reason);
+ this._pagesCapability.reject(reason);
+ });
+ }
+ onPagesEdited({
+ pagesMapper,
+ type,
+ hasBeenCut,
+ pageNumbers
+ }) {
+ if (type === "copy") {
+ this.#copiedPageViews = new Map();
+ for (const pageNum of pageNumbers) {
+ this.#copiedPageViews.set(pageNum, this._pages[pageNum - 1]);
+ }
+ return;
+ }
+ if (type === "cancelCopy") {
+ this.#copiedPageViews = null;
+ return;
+ }
+ const isCut = type === "cut";
+ if (isCut || type === "delete") {
+ this.#savedPageViews = this._pages;
+ this.#deletedPageNumbers = pageNumbers;
+ }
+ if (type === "cancelDelete") {
+ this.#deletedPageNumbers = null;
+ if (!this.#savedPageViews) {
+ return;
+ }
+ const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : this.viewer;
+ if (viewerElement) {
+ this.#annotationEditorUIManager?.startUpdatePages();
+ const fragment = document.createDocumentFragment();
+ for (let i = 0, ii = this.#savedPageViews.length; i < ii; i++) {
+ const page = this.#savedPageViews[i];
+ page.updatePageNumber(i + 1);
+ fragment.append(page.div);
+ }
+ viewerElement.replaceChildren(fragment);
+ this.#annotationEditorUIManager?.endUpdatePages();
+ }
+ this._pages = this.#savedPageViews;
+ this.#savedPageViews = null;
+ return;
+ }
+ if (type === "cleanSavedData") {
+ if (this.#deletedPageNumbers) {
+ if (this.#savedPageViews) {
+ for (const pageNum of this.#deletedPageNumbers) {
+ this.#savedPageViews[pageNum - 1].deleteMe();
+ }
+ this.#savedPageViews = null;
+ }
+ this.#deletedPageNumbers = null;
+ }
+ return;
+ }
+ this._currentPageNumber = 0;
+ const prevPages = this._pages;
+ const newPages = this._pages = [];
+ this.#annotationEditorUIManager?.startUpdatePages();
+ for (let i = 1, ii = pagesMapper.pagesNumber; i <= ii; i++) {
+ const prevPageNumber = pagesMapper.getPrevPageNumber(i);
+ if (prevPageNumber < 0) {
+ let page = this.#copiedPageViews.get(-prevPageNumber);
+ if (hasBeenCut) {
+ page.updatePageNumber(i);
+ } else {
+ this.#annotationEditorUIManager?.clonePage(-prevPageNumber - 1, i - 1);
+ page = page.clone(i);
+ }
+ newPages.push(page);
+ continue;
+ }
+ const page = prevPages[prevPageNumber - 1];
+ newPages.push(page);
+ page.updatePageNumber(i);
+ }
+ this.#annotationEditorUIManager?.endUpdatePages();
+ if (type === "paste") {
+ this.#copiedPageViews = null;
+ }
+ const viewerElement = this._scrollMode === ScrollMode.PAGE ? null : this.viewer;
+ if (viewerElement) {
+ const fragment = document.createDocumentFragment();
+ for (const {
+ div
+ } of newPages) {
+ fragment.append(div);
+ }
+ viewerElement.replaceChildren(fragment);
+ }
+ setTimeout(() => {
+ this.forceRendering();
+ });
+ }
+ setPageLabels(labels) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (!labels) {
+ this._pageLabels = null;
+ } else if (!(Array.isArray(labels) && this.pdfDocument.numPages === labels.length)) {
+ this._pageLabels = null;
+ console.error(`setPageLabels: Invalid page labels.`);
+ } else {
+ this._pageLabels = labels;
+ }
+ for (let i = 0, ii = this._pages.length; i < ii; i++) {
+ this._pages[i].setPageLabel(this._pageLabels?.[i] ?? null);
+ }
+ }
+ _resetView() {
+ this._pages = [];
+ this._currentPageNumber = 1;
+ this._currentScale = (/* inlined export .UNKNOWN_SCALE */0);
+ this._currentScaleValue = null;
+ this._pageLabels = null;
+ this.#buffer = new PDFPageViewBuffer(DEFAULT_CACHE_SIZE);
+ this._location = null;
+ this._pagesRotation = 0;
+ this._optionalContentConfigPromise = null;
+ this._firstPageCapability = Promise.withResolvers();
+ this._onePageRenderedCapability = Promise.withResolvers();
+ this._pagesCapability = Promise.withResolvers();
+ this._scrollMode = ScrollMode.VERTICAL;
+ this._previousScrollMode = ScrollMode.UNKNOWN;
+ this._spreadMode = SpreadMode.NONE;
+ this.#scrollModePageState = {
+ previousPageNumber: 1,
+ scrollDown: true,
+ pages: []
+ };
+ this.#eventAC?.abort();
+ this.#eventAC = null;
+ this.viewer.textContent = "";
+ this._updateScrollMode();
+ this.viewer.removeAttribute("lang");
+ this.#hiddenCopyElement?.remove();
+ this.#hiddenCopyElement = null;
+ this.#cleanupTimeouts();
+ this.#cleanupSwitchAnnotationEditorMode();
+ }
+ #ensurePageViewVisible() {
+ if (this._scrollMode !== ScrollMode.PAGE) {
+ throw new Error("#ensurePageViewVisible: Invalid scrollMode value.");
+ }
+ const pageNumber = this._currentPageNumber,
+ state = this.#scrollModePageState,
+ viewer = this.viewer;
+ viewer.textContent = "";
+ state.pages.length = 0;
+ if (this._spreadMode === SpreadMode.NONE && !this.isInPresentationMode) {
+ const pageView = this._pages[pageNumber - 1];
+ viewer.append(pageView.div);
+ state.pages.push(pageView);
+ } else {
+ const pageIndexSet = new Set(),
+ parity = this._spreadMode - 1;
+ if (parity === -1) {
+ pageIndexSet.add(pageNumber - 1);
+ } else if (pageNumber % 2 !== parity) {
+ pageIndexSet.add(pageNumber - 1);
+ pageIndexSet.add(pageNumber);
+ } else {
+ pageIndexSet.add(pageNumber - 2);
+ pageIndexSet.add(pageNumber - 1);
+ }
+ const spread = document.createElement("div");
+ spread.className = "spread";
+ if (this.isInPresentationMode) {
+ const dummyPage = document.createElement("div");
+ dummyPage.className = "dummyPage";
+ spread.append(dummyPage);
+ }
+ for (const i of pageIndexSet) {
+ const pageView = this._pages[i];
+ if (!pageView) {
+ continue;
+ }
+ spread.append(pageView.div);
+ state.pages.push(pageView);
+ }
+ viewer.append(spread);
+ }
+ state.scrollDown = pageNumber >= state.previousPageNumber;
+ state.previousPageNumber = pageNumber;
+ }
+ _scrollUpdate() {
+ if (this.pagesCount === 0) {
+ return;
+ }
+ if (this.#scrollTimeoutId) {
+ clearTimeout(this.#scrollTimeoutId);
+ }
+ this.#scrollTimeoutId = setTimeout(() => {
+ this.#scrollTimeoutId = null;
+ this.update();
+ }, 100);
+ this.update();
+ }
+ #scrollIntoView(pageView, pageSpot = null) {
+ const {
+ div,
+ id
+ } = pageView;
+ if (this._currentPageNumber !== id) {
+ this._setCurrentPageNumber(id);
+ }
+ if (this._scrollMode === ScrollMode.PAGE) {
+ this.#ensurePageViewVisible();
+ this.update();
+ }
+ if (!pageSpot && !this.isInPresentationMode) {
+ const left = div.offsetLeft + div.clientLeft,
+ right = left + div.clientWidth;
+ const {
+ scrollLeft,
+ clientWidth
+ } = this.container;
+ if (this._scrollMode === ScrollMode.HORIZONTAL || left < scrollLeft || right > scrollLeft + clientWidth) {
+ pageSpot = {
+ left: 0,
+ top: 0
+ };
+ }
+ }
+ scrollIntoView(div, pageSpot);
+ if (!this._currentScaleValue && this._location) {
+ this._location = null;
+ }
+ }
+ #isSameScale(newScale) {
+ return newScale === this._currentScale || Math.abs(newScale - this._currentScale) < 1e-15;
+ }
+ panBy(dx, dy) {
+ const {
+ container
+ } = this;
+ const position = this.#panPosition;
+ const {
+ scrollLeft,
+ scrollTop
+ } = container;
+ const left = (Math.abs(scrollLeft - position[0]) < 1 ? position[0] : scrollLeft) - dx;
+ const top = (Math.abs(scrollTop - position[1]) < 1 ? position[1] : scrollTop) - dy;
+ position[0] = left;
+ position[1] = top;
+ container.scrollLeft = left;
+ container.scrollTop = top;
+ this.#staleLocation = true;
+ }
+ #refreshLocation() {
+ if (!this.#staleLocation) {
+ return;
+ }
+ const {
+ first
+ } = this._getVisiblePages();
+ if (first) {
+ this._updateLocation(first);
+ }
+ }
+ #setScaleUpdatePages(newScale, newValue, {
+ noScroll = false,
+ preset = false,
+ drawingDelay = -1,
+ origin = null,
+ pan = null
+ }) {
+ this._currentScaleValue = newValue.toString();
+ if (this.#isSameScale(newScale)) {
+ if (pan && !noScroll) {
+ this.panBy(pan[0], pan[1]);
+ }
+ if (preset) {
+ this.eventBus.dispatch("scalechanging", {
+ source: this,
+ scale: newScale,
+ presetValue: newValue
+ });
+ }
+ return;
+ }
+ this.clearSelection();
+ this.viewer.style.setProperty("--scale-factor", newScale * PixelsPerInch.PDF_TO_CSS_UNITS);
+ const postponeDrawing = drawingDelay >= 0 && drawingDelay < 1000;
+ this.refresh(true, {
+ scale: newScale,
+ drawingDelay: postponeDrawing ? drawingDelay : -1
+ });
+ if (postponeDrawing) {
+ this.#scaleTimeoutId = setTimeout(() => {
+ this.#scaleTimeoutId = null;
+ this.refresh();
+ }, drawingDelay);
+ }
+ const previousScale = this._currentScale;
+ this._currentScale = newScale;
+ if (!noScroll) {
+ this.#refreshLocation();
+ let page = this._currentPageNumber,
+ dest;
+ if (this._location && !(this.isInPresentationMode || this.isChangingPresentationMode)) {
+ page = this._location.pageNumber;
+ dest = [null, {
+ name: "XYZ"
+ }, this._location.left, this._location.top, null];
+ }
+ this.scrollPageIntoView({
+ pageNumber: page,
+ destArray: dest,
+ allowNegativeOffset: true
+ });
+ let dx = pan?.[0] ?? 0,
+ dy = pan?.[1] ?? 0;
+ if (Array.isArray(origin)) {
+ const scaleDiff = newScale / previousScale - 1;
+ const [top, left] = this.containerTopLeft;
+ dx -= (origin[0] - left) * scaleDiff;
+ dy -= (origin[1] - top) * scaleDiff;
+ }
+ if (dx || dy) {
+ this.panBy(dx, dy);
+ }
+ }
+ this.eventBus.dispatch("scalechanging", {
+ source: this,
+ scale: newScale,
+ presetValue: preset ? newValue : undefined
+ });
+ if (this.defaultRenderingQueue) {
+ this.update();
+ }
+ }
+ get #pageWidthScaleFactor() {
+ return this._spreadMode !== SpreadMode.NONE && this._scrollMode !== ScrollMode.HORIZONTAL ? 2 : 1;
+ }
+ #setScale(value, options) {
+ let scale = parseFloat(value);
+ if (scale > 0) {
+ options.preset = false;
+ this.#setScaleUpdatePages(scale, value, options);
+ } else {
+ const currentPage = this._pages[this._currentPageNumber - 1];
+ if (!currentPage) {
+ return;
+ }
+ let hPadding = (/* inlined export .SCROLLBAR_PADDING */40),
+ vPadding = (/* inlined export .VERTICAL_PADDING */5);
+ if (this.isInPresentationMode) {
+ hPadding = vPadding = 4;
+ if (this._spreadMode !== SpreadMode.NONE) {
+ hPadding *= 2;
+ }
+ } else if (this.removePageBorders) {
+ hPadding = vPadding = 0;
+ } else if (this._scrollMode === ScrollMode.HORIZONTAL) {
+ [hPadding, vPadding] = [vPadding, hPadding];
+ }
+ const pageWidthScale = (this.container.clientWidth - hPadding) / currentPage.width * currentPage.scale / this.#pageWidthScaleFactor;
+ const pageHeightScale = (this.container.clientHeight - vPadding) / currentPage.height * currentPage.scale;
+ switch (value) {
+ case "page-actual":
+ scale = 1;
+ break;
+ case "page-width":
+ scale = pageWidthScale;
+ break;
+ case "page-height":
+ scale = pageHeightScale;
+ break;
+ case "page-fit":
+ scale = Math.min(pageWidthScale, pageHeightScale);
+ break;
+ case "auto":
+ const horizontalScale = isPortraitOrientation(currentPage) ? pageWidthScale : Math.min(pageHeightScale, pageWidthScale);
+ scale = Math.min((/* inlined export .MAX_AUTO_SCALE */1.25), horizontalScale);
+ break;
+ default:
+ console.error(`#setScale: "${value}" is an unknown zoom value.`);
+ return;
+ }
+ options.preset = true;
+ this.#setScaleUpdatePages(scale, value, options);
+ }
+ }
+ #resetCurrentPageView() {
+ const pageView = this._pages[this._currentPageNumber - 1];
+ if (this.isInPresentationMode) {
+ this.#setScale(this._currentScaleValue, {
+ noScroll: true
+ });
+ }
+ this.#scrollIntoView(pageView);
+ }
+ pageLabelToPageNumber(label) {
+ if (!this._pageLabels) {
+ return null;
+ }
+ const i = this._pageLabels.indexOf(label);
+ if (i < 0) {
+ return null;
+ }
+ return i + 1;
+ }
+ scrollPageIntoView({
+ pageNumber,
+ destArray = null,
+ allowNegativeOffset = false,
+ ignoreDestinationZoom = false,
+ center = null
+ }) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const pageView = Number.isInteger(pageNumber) && this._pages[pageNumber - 1];
+ if (!pageView) {
+ console.error(`scrollPageIntoView: "${pageNumber}" is not a valid pageNumber parameter.`);
+ return;
+ }
+ if (this.isInPresentationMode || !destArray) {
+ this._setCurrentPageNumber(pageNumber, true);
+ return;
+ }
+ let x = 0,
+ y = 0;
+ let width = 0,
+ height = 0,
+ widthScale,
+ heightScale;
+ const changeOrientation = pageView.rotation % 180 !== 0;
+ const pageWidth = (changeOrientation ? pageView.height : pageView.width) / pageView.scale / PixelsPerInch.PDF_TO_CSS_UNITS;
+ const pageHeight = (changeOrientation ? pageView.width : pageView.height) / pageView.scale / PixelsPerInch.PDF_TO_CSS_UNITS;
+ let scale = 0;
+ switch (destArray[1].name) {
+ case "XYZ":
+ x = destArray[2];
+ y = destArray[3];
+ scale = destArray[4];
+ x = x !== null ? x : 0;
+ y = y !== null ? y : pageHeight;
+ break;
+ case "Fit":
+ case "FitB":
+ scale = "page-fit";
+ break;
+ case "FitH":
+ case "FitBH":
+ y = destArray[2];
+ scale = "page-width";
+ if (y === null && this._location) {
+ x = this._location.left;
+ y = this._location.top;
+ } else if (typeof y !== "number" || y < 0) {
+ y = pageHeight;
+ }
+ break;
+ case "FitV":
+ case "FitBV":
+ x = destArray[2];
+ width = pageWidth;
+ height = pageHeight;
+ scale = "page-height";
+ break;
+ case "FitR":
+ x = destArray[2];
+ y = destArray[3];
+ width = destArray[4] - x;
+ height = destArray[5] - y;
+ let hPadding = (/* inlined export .SCROLLBAR_PADDING */40),
+ vPadding = (/* inlined export .VERTICAL_PADDING */5);
+ if (this.removePageBorders) {
+ hPadding = vPadding = 0;
+ }
+ widthScale = (this.container.clientWidth - hPadding) / width / PixelsPerInch.PDF_TO_CSS_UNITS;
+ heightScale = (this.container.clientHeight - vPadding) / height / PixelsPerInch.PDF_TO_CSS_UNITS;
+ scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
+ break;
+ default:
+ console.error(`scrollPageIntoView: "${destArray[1].name}" is not a valid destination type.`);
+ return;
+ }
+ if (!ignoreDestinationZoom) {
+ if (scale && scale !== this._currentScale) {
+ this.currentScaleValue = scale;
+ } else if (this._currentScale === (/* inlined export .UNKNOWN_SCALE */0)) {
+ this.currentScaleValue = (/* inlined export .DEFAULT_SCALE_VALUE */"auto");
+ }
+ }
+ if (scale === "page-fit" && !destArray[4]) {
+ this.#scrollIntoView(pageView);
+ return;
+ }
+ const boundingRect = [pageView.viewport.convertToViewportPoint(x, y), pageView.viewport.convertToViewportPoint(x + width, y + height)];
+ let left = Math.min(boundingRect[0][0], boundingRect[1][0]);
+ let top = Math.min(boundingRect[0][1], boundingRect[1][1]);
+ if (center) {
+ if (center === "both" || center === "vertical") {
+ top -= (this.container.clientHeight - Math.abs(boundingRect[1][1] - boundingRect[0][1])) / 2;
+ }
+ if (center === "both" || center === "horizontal") {
+ left -= (this.container.clientWidth - Math.abs(boundingRect[1][0] - boundingRect[0][0])) / 2;
+ }
+ } else if (!allowNegativeOffset) {
+ left = Math.max(left, 0);
+ top = Math.max(top, 0);
+ }
+ this.#scrollIntoView(pageView, {
+ left,
+ top
+ });
+ }
+ _updateLocation(firstPage) {
+ this.#staleLocation = false;
+ const currentScale = this._currentScale;
+ const currentScaleValue = this._currentScaleValue;
+ const normalizedScaleValue = parseFloat(currentScaleValue) === currentScale ? Math.round(currentScale * 10000) / 100 : currentScaleValue;
+ const pageNumber = firstPage.id;
+ const currentPageView = this._pages[pageNumber - 1];
+ const container = this.container;
+ const topLeft = currentPageView.getPagePoint(container.scrollLeft - firstPage.x, container.scrollTop - firstPage.y);
+ const [left, top] = topLeft;
+ let pdfOpenParams = `#page=${pageNumber}`;
+ if (!this.isInPresentationMode) {
+ pdfOpenParams += `&zoom=${normalizedScaleValue},` + `${Math.round(left)},${Math.round(top)}`;
+ }
+ this._location = {
+ pageNumber,
+ scale: normalizedScaleValue,
+ top,
+ left,
+ rotation: this._pagesRotation,
+ pdfOpenParams
+ };
+ }
+ update() {
+ const visible = this._getVisiblePages();
+ const visiblePages = visible.views,
+ numVisiblePages = visiblePages.length;
+ if (numVisiblePages === 0) {
+ return;
+ }
+ const newCacheSize = Math.max(DEFAULT_CACHE_SIZE, 2 * numVisiblePages + 1);
+ this.#buffer.resize(newCacheSize, visible.ids);
+ for (const {
+ view,
+ visibleArea
+ } of visiblePages) {
+ view.updateVisibleArea(visibleArea);
+ }
+ for (const view of this.#buffer) {
+ if (!visible.ids.has(view.id)) {
+ view.updateVisibleArea(null);
+ }
+ }
+ this.renderingQueue.renderHighestPriority(visible);
+ const isSimpleLayout = this._spreadMode === SpreadMode.NONE && (this._scrollMode === ScrollMode.PAGE || this._scrollMode === ScrollMode.VERTICAL);
+ const currentPageNumber = this._currentPageNumber;
+ let stillFullyVisible = false;
+ for (const page of visiblePages) {
+ if (page.percent < 100) {
+ break;
+ }
+ if (page.id === currentPageNumber && isSimpleLayout) {
+ stillFullyVisible = true;
+ break;
+ }
+ }
+ this._setCurrentPageNumber(stillFullyVisible ? this._currentPageNumber : visiblePages[0].id);
+ this._updateLocation(visible.first);
+ this.eventBus.dispatch("updateviewarea", {
+ source: this,
+ location: this._location
+ });
+ }
+ #switchToEditAnnotationMode() {
+ const visible = this._getVisiblePages();
+ const pagesToRefresh = [];
+ const {
+ ids,
+ views
+ } = visible;
+ for (const page of views) {
+ const {
+ view
+ } = page;
+ if (!view.hasEditableAnnotations()) {
+ ids.delete(view.id);
+ continue;
+ }
+ pagesToRefresh.push(page);
+ }
+ if (pagesToRefresh.length === 0) {
+ return null;
+ }
+ this.renderingQueue.renderHighestPriority({
+ first: pagesToRefresh[0],
+ last: pagesToRefresh.at(-1),
+ views: pagesToRefresh,
+ ids
+ });
+ return ids;
+ }
+ containsElement(element) {
+ return this.container.contains(element);
+ }
+ focus() {
+ this.container.focus();
+ }
+ get _isContainerRtl() {
+ return getComputedStyle(this.container).direction === "rtl";
+ }
+ get isInPresentationMode() {
+ return this.presentationModeState === PresentationModeState.FULLSCREEN;
+ }
+ get isChangingPresentationMode() {
+ return this.presentationModeState === PresentationModeState.CHANGING;
+ }
+ get isHorizontalScrollbarEnabled() {
+ return this.isInPresentationMode ? false : this.container.scrollWidth > this.container.clientWidth;
+ }
+ get isVerticalScrollbarEnabled() {
+ return this.isInPresentationMode ? false : this.container.scrollHeight > this.container.clientHeight;
+ }
+ _getVisiblePages() {
+ const views = this._scrollMode === ScrollMode.PAGE ? this.#scrollModePageState.pages : this._pages,
+ horizontal = this._scrollMode === ScrollMode.HORIZONTAL,
+ rtl = horizontal && this._isContainerRtl;
+ return getVisibleElements({
+ scrollEl: this.container,
+ views,
+ sortByVisibility: true,
+ horizontal,
+ rtl
+ });
+ }
+ cleanup() {
+ for (const pageView of this._pages) {
+ if (pageView.renderingState !== RenderingStates.FINISHED) {
+ pageView.reset();
+ }
+ }
+ }
+ _cancelRendering() {
+ for (const pageView of this._pages) {
+ pageView.cancelRendering();
+ }
+ }
+ async #ensurePdfPageLoaded(pageView) {
+ if (pageView.pdfPage) {
+ return pageView.pdfPage;
+ }
+ try {
+ const pdfPage = await this.pdfDocument.getPage(pageView.id);
+ if (!pageView.pdfPage) {
+ pageView.setPdfPage(pdfPage);
+ }
+ return pdfPage;
+ } catch (reason) {
+ console.error("Unable to get page for page view", reason);
+ return null;
+ }
+ }
+ #getScrollAhead(visible) {
+ if (visible.first?.id === 1) {
+ return true;
+ } else if (visible.last?.id === this.pagesCount) {
+ return false;
+ }
+ switch (this._scrollMode) {
+ case ScrollMode.PAGE:
+ return this.#scrollModePageState.scrollDown;
+ case ScrollMode.HORIZONTAL:
+ return this.scroll.right;
+ }
+ return this.scroll.down;
+ }
+ forceRendering(currentlyVisiblePages) {
+ const visiblePages = currentlyVisiblePages || this._getVisiblePages();
+ const scrollAhead = this.#getScrollAhead(visiblePages);
+ const preRenderExtra = this._spreadMode !== SpreadMode.NONE && this._scrollMode !== ScrollMode.HORIZONTAL;
+ const ignoreDetailViews = this.#scaleTimeoutId !== null || this.#scrollTimeoutId !== null && visiblePages.views.some(page => page.detailView?.renderingCancelled);
+ const pageView = this.renderingQueue.getHighestPriority(visiblePages, this._pages, scrollAhead, preRenderExtra, ignoreDetailViews);
+ if (pageView) {
+ this.#ensurePdfPageLoaded(pageView).then(() => {
+ this.renderingQueue.renderView(pageView);
+ });
+ return true;
+ }
+ return false;
+ }
+ get hasEqualPageSizes() {
+ const firstPageView = this._pages[0];
+ for (let i = 1, ii = this._pages.length; i < ii; ++i) {
+ const pageView = this._pages[i];
+ if (pageView.width !== firstPageView.width || pageView.height !== firstPageView.height) {
+ return false;
+ }
+ }
+ return true;
+ }
+ getPagesOverview() {
+ let initialOrientation;
+ return this._pages.map(pageView => {
+ const viewport = pageView.pdfPage.getViewport({
+ scale: 1
+ });
+ const orientation = isPortraitOrientation(viewport);
+ if (initialOrientation === undefined) {
+ initialOrientation = orientation;
+ } else if (this.enablePrintAutoRotate && orientation !== initialOrientation) {
+ return {
+ width: viewport.height,
+ height: viewport.width,
+ rotation: (viewport.rotation - 90) % 360
+ };
+ }
+ return {
+ width: viewport.width,
+ height: viewport.height,
+ rotation: viewport.rotation
+ };
+ });
+ }
+ get optionalContentConfigPromise() {
+ if (!this.pdfDocument) {
+ return Promise.resolve(null);
+ }
+ if (!this._optionalContentConfigPromise) {
+ console.error("optionalContentConfigPromise: Not initialized yet.");
+ return this.pdfDocument.getOptionalContentConfig({
+ intent: "display"
+ });
+ }
+ return this._optionalContentConfigPromise;
+ }
+ set optionalContentConfigPromise(promise) {
+ if (!(promise instanceof Promise)) {
+ throw new Error(`Invalid optionalContentConfigPromise: ${promise}`);
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ if (!this._optionalContentConfigPromise) {
+ return;
+ }
+ this._optionalContentConfigPromise = promise;
+ this.refresh(false, {
+ optionalContentConfigPromise: promise
+ });
+ this.eventBus.dispatch("optionalcontentconfigchanged", {
+ source: this,
+ promise
+ });
+ }
+ get scrollMode() {
+ return this._scrollMode;
+ }
+ set scrollMode(mode) {
+ if (this._scrollMode === mode) {
+ return;
+ }
+ if (!isValidScrollMode(mode)) {
+ throw new Error(`Invalid scroll mode: ${mode}`);
+ }
+ if (this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE) {
+ return;
+ }
+ this._previousScrollMode = this._scrollMode;
+ this.clearSelection();
+ this._scrollMode = mode;
+ this.eventBus.dispatch("scrollmodechanged", {
+ source: this,
+ mode
+ });
+ this._updateScrollMode(this._currentPageNumber);
+ }
+ _updateScrollMode(pageNumber = null) {
+ const scrollMode = this._scrollMode,
+ viewer = this.viewer;
+ viewer.classList.toggle("scrollHorizontal", scrollMode === ScrollMode.HORIZONTAL);
+ viewer.classList.toggle("scrollWrapped", scrollMode === ScrollMode.WRAPPED);
+ if (!this.pdfDocument || !pageNumber) {
+ return;
+ }
+ if (scrollMode === ScrollMode.PAGE) {
+ this.#ensurePageViewVisible();
+ } else if (this._previousScrollMode === ScrollMode.PAGE) {
+ this._updateSpreadMode();
+ }
+ if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
+ this.#setScale(this._currentScaleValue, {
+ noScroll: true
+ });
+ }
+ this._setCurrentPageNumber(pageNumber, true);
+ this.update();
+ }
+ get spreadMode() {
+ return this._spreadMode;
+ }
+ set spreadMode(mode) {
+ if (this._spreadMode === mode) {
+ return;
+ }
+ if (!isValidSpreadMode(mode)) {
+ throw new Error(`Invalid spread mode: ${mode}`);
+ }
+ this.clearSelection();
+ this._spreadMode = mode;
+ this.eventBus.dispatch("spreadmodechanged", {
+ source: this,
+ mode
+ });
+ this._updateSpreadMode(this._currentPageNumber);
+ }
+ _updateSpreadMode(pageNumber = null) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const viewer = this.viewer,
+ pages = this._pages;
+ if (this._scrollMode === ScrollMode.PAGE) {
+ this.#ensurePageViewVisible();
+ } else {
+ viewer.textContent = "";
+ if (this._spreadMode === SpreadMode.NONE) {
+ for (const pageView of this._pages) {
+ viewer.append(pageView.div);
+ }
+ } else {
+ const parity = this._spreadMode - 1;
+ let spread = null;
+ for (let i = 0, ii = pages.length; i < ii; ++i) {
+ if (spread === null) {
+ spread = document.createElement("div");
+ spread.className = "spread";
+ viewer.append(spread);
+ } else if (i % 2 === parity) {
+ spread = spread.cloneNode(false);
+ viewer.append(spread);
+ }
+ spread.append(pages[i].div);
+ }
+ }
+ }
+ if (!pageNumber) {
+ return;
+ }
+ if (this._currentScaleValue && isNaN(this._currentScaleValue)) {
+ this.#setScale(this._currentScaleValue, {
+ noScroll: true
+ });
+ }
+ this._setCurrentPageNumber(pageNumber, true);
+ this.update();
+ }
+ #getPageAdvance(currentPageNumber, previous = false) {
+ switch (this._scrollMode) {
+ case ScrollMode.WRAPPED:
+ {
+ const {
+ views
+ } = this._getVisiblePages(),
+ pageLayout = new Map();
+ for (const {
+ id,
+ y,
+ percent,
+ widthPercent
+ } of views) {
+ if (percent === 0 || widthPercent < 100) {
+ continue;
+ }
+ pageLayout.getOrInsertComputed(y, makeArr).push(id);
+ }
+ for (const yArray of pageLayout.values()) {
+ const currentIndex = yArray.indexOf(currentPageNumber);
+ if (currentIndex === -1) {
+ continue;
+ }
+ const numPages = yArray.length;
+ if (numPages === 1) {
+ break;
+ }
+ if (previous) {
+ for (let i = currentIndex - 1, ii = 0; i >= ii; i--) {
+ const currentId = yArray[i],
+ expectedId = yArray[i + 1] - 1;
+ if (currentId < expectedId) {
+ return currentPageNumber - expectedId;
+ }
+ }
+ } else {
+ for (let i = currentIndex + 1, ii = numPages; i < ii; i++) {
+ const currentId = yArray[i],
+ expectedId = yArray[i - 1] + 1;
+ if (currentId > expectedId) {
+ return expectedId - currentPageNumber;
+ }
+ }
+ }
+ if (previous) {
+ const firstId = yArray[0];
+ if (firstId < currentPageNumber) {
+ return currentPageNumber - firstId + 1;
+ }
+ } else {
+ const lastId = yArray[numPages - 1];
+ if (lastId > currentPageNumber) {
+ return lastId - currentPageNumber + 1;
+ }
+ }
+ break;
+ }
+ break;
+ }
+ case ScrollMode.HORIZONTAL:
+ {
+ break;
+ }
+ case ScrollMode.PAGE:
+ case ScrollMode.VERTICAL:
+ {
+ if (this._spreadMode === SpreadMode.NONE) {
+ break;
+ }
+ const parity = this._spreadMode - 1;
+ if (previous && currentPageNumber % 2 !== parity) {
+ break;
+ } else if (!previous && currentPageNumber % 2 === parity) {
+ break;
+ }
+ const {
+ views
+ } = this._getVisiblePages(),
+ expectedId = previous ? currentPageNumber - 1 : currentPageNumber + 1;
+ for (const {
+ id,
+ percent,
+ widthPercent
+ } of views) {
+ if (id !== expectedId) {
+ continue;
+ }
+ if (percent > 0 && widthPercent === 100) {
+ return 2;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return 1;
+ }
+ nextPage() {
+ const currentPageNumber = this._currentPageNumber,
+ pagesCount = this.pagesCount;
+ if (currentPageNumber >= pagesCount) {
+ return false;
+ }
+ const advance = this.#getPageAdvance(currentPageNumber, false) || 1;
+ this.currentPageNumber = Math.min(currentPageNumber + advance, pagesCount);
+ return true;
+ }
+ previousPage() {
+ const currentPageNumber = this._currentPageNumber;
+ if (currentPageNumber <= 1) {
+ return false;
+ }
+ const advance = this.#getPageAdvance(currentPageNumber, true) || 1;
+ this.currentPageNumber = Math.max(currentPageNumber - advance, 1);
+ return true;
+ }
+ updateScale({
+ drawingDelay,
+ scaleFactor = null,
+ steps = null,
+ origin,
+ pan = null
+ }) {
+ if (steps === null && scaleFactor === null) {
+ throw new Error("Invalid updateScale options: either `steps` or `scaleFactor` must be provided.");
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ let newScale = this._currentScale;
+ if (scaleFactor > 0 && scaleFactor !== 1) {
+ newScale = Math.round(newScale * scaleFactor * 100) / 100;
+ } else if (steps) {
+ const delta = steps > 0 ? (/* inlined export .DEFAULT_SCALE_DELTA */1.1) : 1 / (/* inlined export .DEFAULT_SCALE_DELTA */1.1);
+ const round = steps > 0 ? Math.ceil : Math.floor;
+ steps = Math.abs(steps);
+ do {
+ newScale = round((newScale * delta).toFixed(2) * 10) / 10;
+ } while (--steps > 0);
+ }
+ newScale = MathClamp(newScale, (/* inlined export .MIN_SCALE */0.1), (/* inlined export .MAX_SCALE */25));
+ this.#setScale(newScale, {
+ noScroll: false,
+ drawingDelay,
+ origin,
+ pan
+ });
+ }
+ increaseScale(options = {}) {
+ this.updateScale({
+ ...options,
+ steps: options.steps ?? 1
+ });
+ }
+ decreaseScale(options = {}) {
+ this.updateScale({
+ ...options,
+ steps: -(options.steps ?? 1)
+ });
+ }
+ #updateContainerHeightCss(height = this.container.clientHeight) {
+ if (height !== this.#previousContainerHeight) {
+ this.#previousContainerHeight = height;
+ docStyle.setProperty("--viewer-container-height", `${height}px`);
+ }
+ }
+ #resizeObserverCallback(entries) {
+ for (const entry of entries) {
+ if (entry.target === this.container) {
+ this.#updateContainerHeightCss(Math.floor(entry.borderBoxSize[0].blockSize));
+ this.#containerTopLeft = null;
+ break;
+ }
+ }
+ }
+ get containerTopLeft() {
+ return this.#containerTopLeft ||= [this.container.offsetTop, this.container.offsetLeft];
+ }
+ #cleanupTimeouts() {
+ if (this.#scaleTimeoutId !== null) {
+ clearTimeout(this.#scaleTimeoutId);
+ this.#scaleTimeoutId = null;
+ }
+ if (this.#scrollTimeoutId !== null) {
+ clearTimeout(this.#scrollTimeoutId);
+ this.#scrollTimeoutId = null;
+ }
+ }
+ #cleanupSwitchAnnotationEditorMode() {
+ this.#switchAnnotationEditorModeAC?.abort();
+ this.#switchAnnotationEditorModeAC = null;
+ if (this.#switchAnnotationEditorModeTimeoutId !== null) {
+ clearTimeout(this.#switchAnnotationEditorModeTimeoutId);
+ this.#switchAnnotationEditorModeTimeoutId = null;
+ }
+ }
+ #preloadEditingData(mode) {
+ switch (mode) {
+ case AnnotationEditorType.STAMP:
+ this.#mlManager?.loadModel("altText");
+ break;
+ case AnnotationEditorType.SIGNATURE:
+ this.#signatureManager?.loadSignatures();
+ break;
+ }
+ }
+ get annotationEditorMode() {
+ return this.#annotationEditorUIManager ? this.#annotationEditorMode : AnnotationEditorType.DISABLE;
+ }
+ set annotationEditorMode({
+ mode,
+ editId = null,
+ isFromKeyboard = false,
+ mustEnterInEditMode = false,
+ editComment = false
+ }) {
+ if (!this.#annotationEditorUIManager) {
+ throw new Error(`The AnnotationEditor is not enabled.`);
+ }
+ if (this.#annotationEditorMode === mode) {
+ return;
+ }
+ if (!isValidAnnotationEditorMode(mode)) {
+ throw new Error(`Invalid AnnotationEditor mode: ${mode}`);
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ this.#preloadEditingData(mode);
+ const {
+ eventBus,
+ pdfDocument
+ } = this;
+ const updater = async () => {
+ this.#cleanupSwitchAnnotationEditorMode();
+ this.#annotationEditorMode = mode;
+ await this.#annotationEditorUIManager.updateMode(mode, editId, true, isFromKeyboard, mustEnterInEditMode, editComment);
+ if (mode !== this.#annotationEditorMode || pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ eventBus.dispatch("annotationeditormodechanged", {
+ source: this,
+ mode
+ });
+ };
+ if (mode === AnnotationEditorType.NONE || this.#annotationEditorMode === AnnotationEditorType.NONE) {
+ const isEditing = mode !== AnnotationEditorType.NONE;
+ if (!isEditing) {
+ this.pdfDocument.annotationStorage.resetModifiedIds();
+ }
+ this.cleanup();
+ for (const pageView of this._pages) {
+ pageView.toggleEditingMode(isEditing);
+ }
+ const idsToRefresh = this.#switchToEditAnnotationMode();
+ if (isEditing && idsToRefresh) {
+ this.#cleanupSwitchAnnotationEditorMode();
+ this.#switchAnnotationEditorModeAC = new AbortController();
+ const signal = AbortSignal.any([this.#eventAC.signal, this.#switchAnnotationEditorModeAC.signal]);
+ eventBus.on("pagerendered", ({
+ pageNumber
+ }) => {
+ idsToRefresh.delete(pageNumber);
+ if (idsToRefresh.size === 0) {
+ this.#switchAnnotationEditorModeTimeoutId = setTimeout(updater, 0);
+ }
+ }, {
+ signal,
+ ...internalOpt
+ });
+ return;
+ }
+ }
+ updater();
+ }
+ refresh(noUpdate = false, updateArgs = Object.create(null)) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ for (const pageView of this._pages) {
+ pageView.update(updateArgs);
+ }
+ this.#cleanupTimeouts();
+ if (!noUpdate) {
+ this.update();
+ }
+ }
+}
+
+;// ./web/secondary_toolbar.js
+
+
+
+
+class SecondaryToolbar {
+ #opts;
+ constructor(options, eventBus) {
+ this.#opts = options;
+ const buttons = [{
+ element: options.presentationModeButton,
+ eventName: "presentationmode",
+ close: true
+ }, {
+ element: options.printButton,
+ eventName: "print",
+ close: true
+ }, {
+ element: options.downloadButton,
+ eventName: "download",
+ close: true
+ }, {
+ element: options.viewBookmarkButton,
+ eventName: null,
+ close: true
+ }, {
+ element: options.firstPageButton,
+ eventName: "firstpage",
+ close: true
+ }, {
+ element: options.lastPageButton,
+ eventName: "lastpage",
+ close: true
+ }, {
+ element: options.pageRotateCwButton,
+ eventName: "rotatecw",
+ close: false
+ }, {
+ element: options.pageRotateCcwButton,
+ eventName: "rotateccw",
+ close: false
+ }, {
+ element: options.cursorSelectToolButton,
+ eventName: "switchcursortool",
+ eventDetails: {
+ tool: CursorTool.SELECT
+ },
+ close: true
+ }, {
+ element: options.cursorHandToolButton,
+ eventName: "switchcursortool",
+ eventDetails: {
+ tool: CursorTool.HAND
+ },
+ close: true
+ }, {
+ element: options.scrollPageButton,
+ eventName: "switchscrollmode",
+ eventDetails: {
+ mode: ScrollMode.PAGE
+ },
+ close: true
+ }, {
+ element: options.scrollVerticalButton,
+ eventName: "switchscrollmode",
+ eventDetails: {
+ mode: ScrollMode.VERTICAL
+ },
+ close: true
+ }, {
+ element: options.scrollHorizontalButton,
+ eventName: "switchscrollmode",
+ eventDetails: {
+ mode: ScrollMode.HORIZONTAL
+ },
+ close: true
+ }, {
+ element: options.scrollWrappedButton,
+ eventName: "switchscrollmode",
+ eventDetails: {
+ mode: ScrollMode.WRAPPED
+ },
+ close: true
+ }, {
+ element: options.spreadNoneButton,
+ eventName: "switchspreadmode",
+ eventDetails: {
+ mode: SpreadMode.NONE
+ },
+ close: true
+ }, {
+ element: options.spreadOddButton,
+ eventName: "switchspreadmode",
+ eventDetails: {
+ mode: SpreadMode.ODD
+ },
+ close: true
+ }, {
+ element: options.spreadEvenButton,
+ eventName: "switchspreadmode",
+ eventDetails: {
+ mode: SpreadMode.EVEN
+ },
+ close: true
+ }, {
+ element: options.imageAltTextSettingsButton,
+ eventName: "imagealttextsettings",
+ close: true
+ }, {
+ element: options.documentPropertiesButton,
+ eventName: "documentproperties",
+ close: true
+ }];
+ buttons.push({
+ element: options.openFileButton,
+ eventName: "openfile",
+ close: true
+ });
+ this.eventBus = eventBus;
+ this.opened = false;
+ this.#bindListeners(buttons);
+ this.reset();
+ }
+ get isOpen() {
+ return this.opened;
+ }
+ setPageNumber(pageNumber) {
+ this.pageNumber = pageNumber;
+ this.#updateUIState();
+ }
+ setPagesCount(pagesCount) {
+ this.pagesCount = pagesCount;
+ this.#updateUIState();
+ }
+ reset() {
+ this.pageNumber = 0;
+ this.pagesCount = 0;
+ this.#updateUIState();
+ this.eventBus.dispatch("switchcursortool", {
+ source: this,
+ reset: true
+ });
+ this.#scrollModeChanged({
+ mode: ScrollMode.VERTICAL
+ });
+ this.#spreadModeChanged({
+ mode: SpreadMode.NONE
+ });
+ }
+ #updateUIState() {
+ const {
+ firstPageButton,
+ lastPageButton,
+ pageRotateCwButton,
+ pageRotateCcwButton
+ } = this.#opts;
+ firstPageButton.disabled = this.pageNumber <= 1;
+ lastPageButton.disabled = this.pageNumber >= this.pagesCount;
+ pageRotateCwButton.disabled = this.pagesCount === 0;
+ pageRotateCcwButton.disabled = this.pagesCount === 0;
+ }
+ #bindListeners(buttons) {
+ const {
+ eventBus
+ } = this;
+ const {
+ toggleButton
+ } = this.#opts;
+ toggleButton.addEventListener("click", this.toggle.bind(this));
+ for (const {
+ element,
+ eventName,
+ close,
+ eventDetails
+ } of buttons) {
+ element.addEventListener("click", evt => {
+ if (eventName !== null) {
+ eventBus.dispatch(eventName, {
+ source: this,
+ ...eventDetails
+ });
+ }
+ if (close) {
+ this.close();
+ }
+ eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "buttons",
+ data: {
+ id: element.id
+ }
+ }
+ });
+ });
+ }
+ eventBus.on("cursortoolchanged", this.#cursorToolChanged.bind(this), internalOpt);
+ eventBus.on("scrollmodechanged", this.#scrollModeChanged.bind(this), internalOpt);
+ eventBus.on("spreadmodechanged", this.#spreadModeChanged.bind(this), internalOpt);
+ }
+ #cursorToolChanged({
+ tool,
+ disabled
+ }) {
+ const {
+ cursorSelectToolButton,
+ cursorHandToolButton
+ } = this.#opts;
+ toggleCheckedBtn(cursorSelectToolButton, tool === CursorTool.SELECT);
+ toggleCheckedBtn(cursorHandToolButton, tool === CursorTool.HAND);
+ cursorSelectToolButton.disabled = disabled;
+ cursorHandToolButton.disabled = disabled;
+ }
+ #scrollModeChanged({
+ mode
+ }) {
+ const {
+ scrollPageButton,
+ scrollVerticalButton,
+ scrollHorizontalButton,
+ scrollWrappedButton,
+ spreadNoneButton,
+ spreadOddButton,
+ spreadEvenButton
+ } = this.#opts;
+ toggleCheckedBtn(scrollPageButton, mode === ScrollMode.PAGE);
+ toggleCheckedBtn(scrollVerticalButton, mode === ScrollMode.VERTICAL);
+ toggleCheckedBtn(scrollHorizontalButton, mode === ScrollMode.HORIZONTAL);
+ toggleCheckedBtn(scrollWrappedButton, mode === ScrollMode.WRAPPED);
+ const forceScrollModePage = this.pagesCount > PagesCountLimit.FORCE_SCROLL_MODE_PAGE;
+ scrollPageButton.disabled = forceScrollModePage;
+ scrollVerticalButton.disabled = forceScrollModePage;
+ scrollHorizontalButton.disabled = forceScrollModePage;
+ scrollWrappedButton.disabled = forceScrollModePage;
+ const isHorizontal = mode === ScrollMode.HORIZONTAL;
+ spreadNoneButton.disabled = isHorizontal;
+ spreadOddButton.disabled = isHorizontal;
+ spreadEvenButton.disabled = isHorizontal;
+ }
+ #spreadModeChanged({
+ mode
+ }) {
+ const {
+ spreadNoneButton,
+ spreadOddButton,
+ spreadEvenButton
+ } = this.#opts;
+ toggleCheckedBtn(spreadNoneButton, mode === SpreadMode.NONE);
+ toggleCheckedBtn(spreadOddButton, mode === SpreadMode.ODD);
+ toggleCheckedBtn(spreadEvenButton, mode === SpreadMode.EVEN);
+ }
+ open() {
+ if (this.opened) {
+ return;
+ }
+ this.opened = true;
+ const {
+ toggleButton,
+ toolbar
+ } = this.#opts;
+ toggleExpandedBtn(toggleButton, true, toolbar);
+ }
+ close() {
+ if (!this.opened) {
+ return;
+ }
+ this.opened = false;
+ const {
+ toggleButton,
+ toolbar
+ } = this.#opts;
+ toggleExpandedBtn(toggleButton, false, toolbar);
+ }
+ toggle() {
+ if (this.opened) {
+ this.close();
+ } else {
+ this.open();
+ }
+ }
+}
+
+;// ./web/signature_manager.js
+
+
+
+
+
+
+
+
+
+const DEFAULT_HEIGHT_IN_PAGE = 40;
+class SignatureManager {
+ #addButton;
+ #tabsToAltText = null;
+ #clearButton;
+ #clearDescription;
+ #currentEditor;
+ #description;
+ #dialog;
+ #drawCurves = null;
+ #drawPlaceholder;
+ #drawPath = null;
+ #drawPathString = "";
+ #drawPoints = null;
+ #drawSVG;
+ #drawThickness;
+ #errorBar;
+ #errorDescription;
+ #errorTitle;
+ #extractedSignatureData = null;
+ #imagePath = null;
+ #imagePicker;
+ #imagePickerLink;
+ #imagePlaceholder;
+ #imageSVG;
+ #saveCheckbox;
+ #saveContainer;
+ #tabButtons;
+ #addSignatureToolbarButton;
+ #loadSignaturesPromise = null;
+ #typeInput;
+ #currentTab = null;
+ #currentTabAC = null;
+ #hasDescriptionChanged = false;
+ #eventBus;
+ #isStorageFull = false;
+ #l10n;
+ #overlayManager;
+ #editDescriptionDialog;
+ #signatureStorage;
+ #uiManager = null;
+ static #l10nDescription = null;
+ constructor({
+ dialog,
+ panels,
+ typeButton,
+ typeInput,
+ drawButton,
+ drawPlaceholder,
+ drawSVG,
+ drawThickness,
+ imageButton,
+ imageSVG,
+ imagePlaceholder,
+ imagePicker,
+ imagePickerLink,
+ description,
+ clearButton,
+ cancelButton,
+ addButton,
+ errorCloseButton,
+ errorBar,
+ errorTitle,
+ errorDescription,
+ saveCheckbox,
+ saveContainer
+ }, editSignatureElements, addSignatureToolbarButton, overlayManager, l10n, signatureStorage, eventBus) {
+ this.#addButton = addButton;
+ this.#clearButton = clearButton;
+ this.#clearDescription = description.lastElementChild;
+ this.#description = description.firstElementChild;
+ this.#dialog = dialog;
+ this.#drawSVG = drawSVG;
+ this.#drawPlaceholder = drawPlaceholder;
+ this.#drawThickness = drawThickness;
+ this.#errorBar = errorBar;
+ this.#errorTitle = errorTitle;
+ this.#errorDescription = errorDescription;
+ this.#imageSVG = imageSVG;
+ this.#imagePlaceholder = imagePlaceholder;
+ this.#imagePicker = imagePicker;
+ this.#imagePickerLink = imagePickerLink;
+ this.#overlayManager = overlayManager;
+ this.#saveCheckbox = saveCheckbox;
+ this.#saveContainer = saveContainer;
+ this.#addSignatureToolbarButton = addSignatureToolbarButton;
+ this.#typeInput = typeInput;
+ this.#l10n = l10n;
+ this.#signatureStorage = signatureStorage;
+ this.#eventBus = eventBus;
+ this.#editDescriptionDialog = new EditDescriptionDialog(editSignatureElements, overlayManager);
+ SignatureManager.#l10nDescription ||= Object.freeze({
+ signature: "pdfjs-editor-add-signature-description-default-when-drawing",
+ errorUploadTitle: "pdfjs-editor-add-signature-image-upload-error-title",
+ errorUploadDescription: "pdfjs-editor-add-signature-image-upload-error-description",
+ errorNoDataTitle: "pdfjs-editor-add-signature-image-no-data-error-title",
+ errorNoDataDescription: "pdfjs-editor-add-signature-image-no-data-error-description"
+ });
+ dialog.addEventListener("close", this.#close.bind(this));
+ dialog.addEventListener("contextmenu", e => {
+ const {
+ target
+ } = e;
+ if (target !== this.#typeInput && target !== this.#description) {
+ e.preventDefault();
+ }
+ });
+ dialog.addEventListener("drop", e => {
+ stopEvent(e);
+ });
+ cancelButton.addEventListener("click", this.#cancel.bind(this));
+ addButton.addEventListener("click", this.#add.bind(this));
+ clearButton.addEventListener("click", () => {
+ this.#reportTelemetry({
+ type: "signature",
+ action: "pdfjs.signature.clear",
+ data: {
+ type: this.#currentTab
+ }
+ });
+ this.#initTab(null);
+ }, {
+ passive: true
+ });
+ this.#description.addEventListener("input", () => {
+ this.#clearDescription.disabled = this.#description.value === "";
+ }, {
+ passive: true
+ });
+ this.#clearDescription.addEventListener("click", () => {
+ this.#description.value = "";
+ this.#clearDescription.disabled = true;
+ }, {
+ passive: true
+ });
+ errorCloseButton.addEventListener("click", () => {
+ errorBar.hidden = true;
+ }, {
+ passive: true
+ });
+ this.#initTabButtons(typeButton, drawButton, imageButton, panels);
+ imagePicker.accept = SupportedImageMimeTypes.join(",");
+ eventBus.on("storedsignatureschanged", this.#signaturesChanged.bind(this), internalOpt);
+ overlayManager.register(dialog);
+ }
+ #initTabButtons(typeButton, drawButton, imageButton, panels) {
+ const buttons = this.#tabButtons = new Map([["type", typeButton], ["draw", drawButton], ["image", imageButton]]);
+ const tabCallback = e => {
+ for (const [name, button] of buttons) {
+ if (button === e.target) {
+ button.setAttribute("aria-selected", true);
+ button.setAttribute("tabindex", 0);
+ panels.setAttribute("data-selected", name);
+ this.#initTab(name);
+ } else {
+ button.setAttribute("aria-selected", false);
+ button.setAttribute("tabindex", -1);
+ }
+ }
+ };
+ const buttonsArray = Array.from(buttons.values());
+ for (let i = 0, ii = buttonsArray.length; i < ii; i++) {
+ const button = buttonsArray[i];
+ button.addEventListener("click", tabCallback, {
+ passive: true
+ });
+ button.addEventListener("keydown", ({
+ key
+ }) => {
+ if (key !== "ArrowLeft" && key !== "ArrowRight") {
+ return;
+ }
+ buttonsArray[i + (key === "ArrowLeft" ? -1 : 1)]?.focus();
+ }, {
+ passive: true
+ });
+ }
+ }
+ #resetCommon() {
+ this.#hasDescriptionChanged = false;
+ this.#description.value = "";
+ if (this.#currentTab) {
+ this.#tabsToAltText.get(this.#currentTab).value = "";
+ }
+ }
+ #resetTab(name) {
+ switch (name) {
+ case "type":
+ this.#typeInput.value = "";
+ break;
+ case "draw":
+ this.#drawCurves = null;
+ this.#drawPoints = null;
+ this.#drawPathString = "";
+ this.#drawPath?.remove();
+ this.#drawPath = null;
+ this.#drawPlaceholder.hidden = false;
+ this.#drawThickness.value = 1;
+ break;
+ case "image":
+ this.#imagePlaceholder.hidden = false;
+ this.#imagePath?.remove();
+ this.#imagePath = null;
+ break;
+ }
+ }
+ #initTab(name) {
+ if (name && this.#currentTab === name) {
+ return;
+ }
+ if (this.#currentTab) {
+ this.#tabsToAltText.get(this.#currentTab).value = this.#description.value;
+ }
+ if (name) {
+ this.#currentTab = name;
+ }
+ this.#errorBar.hidden = true;
+ const reset = !name;
+ if (reset) {
+ this.#resetCommon();
+ } else {
+ this.#description.value = this.#tabsToAltText.get(this.#currentTab).value;
+ }
+ this.#clearDescription.disabled = this.#description.value === "";
+ this.#currentTabAC?.abort();
+ this.#currentTabAC = new AbortController();
+ switch (this.#currentTab) {
+ case "type":
+ this.#initTypeTab(reset);
+ break;
+ case "draw":
+ this.#initDrawTab(reset);
+ break;
+ case "image":
+ this.#initImageTab(reset);
+ break;
+ }
+ }
+ #disableButtons(value) {
+ if (!value || !this.#isStorageFull) {
+ this.#saveCheckbox.disabled = !value;
+ }
+ this.#clearButton.disabled = this.#addButton.disabled = this.#description.disabled = !value;
+ }
+ #initTypeTab(reset) {
+ if (reset) {
+ this.#resetTab("type");
+ }
+ this.#disableButtons(this.#typeInput.value);
+ const {
+ signal
+ } = this.#currentTabAC;
+ const options = {
+ passive: true,
+ signal
+ };
+ this.#typeInput.addEventListener("input", () => {
+ const {
+ value
+ } = this.#typeInput;
+ if (!this.#hasDescriptionChanged) {
+ this.#tabsToAltText.get("type").default = this.#description.value = value;
+ this.#clearDescription.disabled = value === "";
+ }
+ this.#disableButtons(value);
+ }, options);
+ this.#description.addEventListener("input", () => {
+ this.#hasDescriptionChanged = this.#typeInput.value !== this.#description.value;
+ }, options);
+ }
+ #initDrawTab(reset) {
+ if (reset) {
+ this.#resetTab("draw");
+ }
+ this.#disableButtons(this.#drawPath);
+ const {
+ signal
+ } = this.#currentTabAC;
+ const options = {
+ signal
+ };
+ let currentPointerId = NaN;
+ const drawCallback = e => {
+ const {
+ pointerId
+ } = e;
+ if (!isNaN(currentPointerId) && currentPointerId !== pointerId) {
+ return;
+ }
+ currentPointerId = pointerId;
+ e.preventDefault();
+ this.#drawSVG.setPointerCapture(pointerId);
+ const {
+ width: drawWidth,
+ height: drawHeight
+ } = this.#drawSVG.getBoundingClientRect();
+ let {
+ offsetX,
+ offsetY
+ } = e;
+ offsetX = Math.round(offsetX);
+ offsetY = Math.round(offsetY);
+ if (e.target === this.#drawPlaceholder) {
+ this.#drawPlaceholder.hidden = true;
+ }
+ if (!this.#drawCurves) {
+ this.#drawCurves = {
+ width: drawWidth,
+ height: drawHeight,
+ thickness: parseInt(this.#drawThickness.value, 10),
+ curves: []
+ };
+ this.#disableButtons(true);
+ const svgFactory = new DOMSVGFactory();
+ const path = this.#drawPath = svgFactory.createElement("path");
+ path.setAttribute("stroke-width", this.#drawThickness.value);
+ this.#drawSVG.append(path);
+ this.#drawSVG.addEventListener("pointerdown", drawCallback, options);
+ this.#drawPlaceholder.removeEventListener("pointerdown", drawCallback);
+ if (this.#description.value === "") {
+ this.#l10n.get(SignatureManager.#l10nDescription.signature).then(description => {
+ this.#tabsToAltText.get("draw").default = description;
+ this.#description.value ||= description;
+ this.#clearDescription.disabled = this.#description.value === "";
+ });
+ }
+ }
+ this.#drawPoints = [offsetX, offsetY];
+ this.#drawCurves.curves.push({
+ points: this.#drawPoints
+ });
+ this.#drawPathString += `M ${offsetX} ${offsetY}`;
+ this.#drawPath.setAttribute("d", this.#drawPathString);
+ const finishDrawAC = new AbortController();
+ const listenerDrawOptions = {
+ signal: AbortSignal.any([signal, finishDrawAC.signal])
+ };
+ this.#drawSVG.addEventListener("contextmenu", noContextMenu, listenerDrawOptions);
+ this.#drawSVG.addEventListener("pointermove", evt => {
+ evt.preventDefault();
+ let {
+ offsetX: x,
+ offsetY: y
+ } = evt;
+ x = Math.round(x);
+ y = Math.round(y);
+ const drawPoints = this.#drawPoints;
+ if (x < 0 || y < 0 || x > drawWidth || y > drawHeight || x === drawPoints.at(-2) && y === drawPoints.at(-1)) {
+ return;
+ }
+ if (drawPoints.length >= 4) {
+ const [x1, y1, x2, y2] = drawPoints.slice(-4);
+ this.#drawPathString += `C${(x1 + 5 * x2) / 6} ${(y1 + 5 * y2) / 6} ${(5 * x2 + x) / 6} ${(5 * y2 + y) / 6} ${(x2 + x) / 2} ${(y2 + y) / 2}`;
+ } else {
+ this.#drawPathString += `L${x} ${y}`;
+ }
+ drawPoints.push(x, y);
+ this.#drawPath.setAttribute("d", this.#drawPathString);
+ }, listenerDrawOptions);
+ this.#drawSVG.addEventListener("pointerup", evt => {
+ const {
+ pointerId: pId
+ } = evt;
+ if (!isNaN(currentPointerId) && currentPointerId !== pId) {
+ return;
+ }
+ currentPointerId = NaN;
+ evt.preventDefault();
+ this.#drawSVG.releasePointerCapture(pId);
+ finishDrawAC.abort();
+ if (this.#drawPoints.length === 2) {
+ this.#drawPathString += `L${this.#drawPoints[0]} ${this.#drawPoints[1]}`;
+ this.#drawPath.setAttribute("d", this.#drawPathString);
+ }
+ }, listenerDrawOptions);
+ };
+ if (this.#drawCurves) {
+ this.#drawSVG.addEventListener("pointerdown", drawCallback, options);
+ } else {
+ this.#drawPlaceholder.addEventListener("pointerdown", drawCallback, options);
+ }
+ this.#drawThickness.addEventListener("input", () => {
+ const {
+ value: thickness
+ } = this.#drawThickness;
+ this.#drawThickness.setAttribute("data-l10n-args", JSON.stringify({
+ thickness
+ }));
+ if (!this.#drawCurves) {
+ return;
+ }
+ this.#drawPath.setAttribute("stroke-width", thickness);
+ this.#drawCurves.thickness = thickness;
+ }, options);
+ }
+ #showError(type) {
+ this.#errorTitle.setAttribute("data-l10n-id", SignatureManager.#l10nDescription[`error${type}Title`]);
+ this.#errorDescription.setAttribute("data-l10n-id", SignatureManager.#l10nDescription[`error${type}Description`]);
+ this.#errorBar.hidden = false;
+ }
+ #initImageTab(reset) {
+ if (reset) {
+ this.#resetTab("image");
+ }
+ this.#disableButtons(this.#imagePath);
+ const {
+ signal
+ } = this.#currentTabAC;
+ const options = {
+ signal
+ };
+ const passiveOptions = {
+ passive: true,
+ signal
+ };
+ this.#imagePickerLink.addEventListener("keydown", e => {
+ const {
+ key
+ } = e;
+ if (key === "Enter" || key === " ") {
+ stopEvent(e);
+ this.#imagePicker.click();
+ }
+ }, options);
+ this.#imagePicker.addEventListener("click", () => {
+ this.#dialog.classList.toggle("waiting", true);
+ }, passiveOptions);
+ this.#imagePicker.addEventListener("change", async () => {
+ const file = this.#imagePicker.files?.[0];
+ if (!file || !SupportedImageMimeTypes.includes(file.type)) {
+ this.#showError("Upload");
+ this.#dialog.classList.toggle("waiting", false);
+ return;
+ }
+ await this.#extractSignature(file);
+ }, passiveOptions);
+ this.#imagePicker.addEventListener("cancel", () => {
+ this.#dialog.classList.toggle("waiting", false);
+ }, passiveOptions);
+ this.#imagePlaceholder.addEventListener("dragover", e => {
+ const {
+ dataTransfer
+ } = e;
+ for (const {
+ type
+ } of dataTransfer.items) {
+ if (!SupportedImageMimeTypes.includes(type)) {
+ continue;
+ }
+ dataTransfer.dropEffect = dataTransfer.effectAllowed === "copy" ? "copy" : "move";
+ stopEvent(e);
+ return;
+ }
+ dataTransfer.dropEffect = "none";
+ }, options);
+ this.#imagePlaceholder.addEventListener("drop", e => {
+ const {
+ dataTransfer: {
+ files
+ }
+ } = e;
+ if (!files?.length) {
+ return;
+ }
+ for (const file of files) {
+ if (SupportedImageMimeTypes.includes(file.type)) {
+ this.#extractSignature(file);
+ break;
+ }
+ }
+ stopEvent(e);
+ this.#dialog.classList.toggle("waiting", true);
+ }, options);
+ }
+ async #extractSignature(file) {
+ let data;
+ try {
+ data = await this.#uiManager.imageManager.getFromFile(file);
+ } catch (e) {
+ console.error("SignatureManager.#extractSignature.", e);
+ }
+ if (!data) {
+ this.#showError("Upload");
+ this.#dialog.classList.toggle("waiting", false);
+ return;
+ }
+ const lineData = this.#extractedSignatureData = this.#currentEditor.getFromImage(data.bitmap);
+ if (!lineData) {
+ this.#showError("NoData");
+ this.#dialog.classList.toggle("waiting", false);
+ return;
+ }
+ const {
+ outline
+ } = lineData;
+ this.#imagePlaceholder.hidden = true;
+ this.#disableButtons(true);
+ const svgFactory = new DOMSVGFactory();
+ const path = this.#imagePath = svgFactory.createElement("path");
+ this.#imageSVG.setAttribute("viewBox", outline.viewBox);
+ this.#imageSVG.setAttribute("preserveAspectRatio", "xMidYMid meet");
+ this.#imageSVG.append(path);
+ path.setAttribute("d", outline.toSVGPath());
+ this.#tabsToAltText.get("image").default = file.name;
+ if (this.#description.value === "") {
+ this.#description.value = file.name || "";
+ this.#clearDescription.disabled = this.#description.value === "";
+ }
+ this.#dialog.classList.toggle("waiting", false);
+ }
+ #getOutlineForType() {
+ return this.#currentEditor.getFromText(this.#typeInput.value, window.getComputedStyle(this.#typeInput));
+ }
+ #getOutlineForDraw() {
+ const {
+ width,
+ height
+ } = this.#drawSVG.getBoundingClientRect();
+ return this.#currentEditor.getDrawnSignature(this.#drawCurves, width, height);
+ }
+ #reportTelemetry(data) {
+ this.#eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: {
+ type: "editing",
+ data
+ }
+ });
+ }
+ #addToolbarButton(signatureData, uuid, description) {
+ const {
+ curves,
+ areContours,
+ thickness,
+ width,
+ height
+ } = signatureData;
+ const maxDim = Math.max(width, height);
+ const outlineData = SignatureExtractor.processDrawnLines({
+ lines: {
+ curves,
+ thickness,
+ width,
+ height
+ },
+ pageWidth: maxDim,
+ pageHeight: maxDim,
+ rotation: 0,
+ innerMargin: 0,
+ mustSmooth: false,
+ areContours
+ });
+ if (!outlineData) {
+ return;
+ }
+ const {
+ outline
+ } = outlineData;
+ const svgFactory = new DOMSVGFactory();
+ const div = document.createElement("div");
+ const button = document.createElement("button");
+ button.addEventListener("click", () => {
+ this.#eventBus.dispatch("switchannotationeditorparams", {
+ source: this,
+ type: AnnotationEditorParamsType.CREATE,
+ value: {
+ signatureData: {
+ lines: {
+ curves,
+ thickness,
+ width,
+ height
+ },
+ mustSmooth: false,
+ areContours,
+ description,
+ uuid,
+ heightInPage: DEFAULT_HEIGHT_IN_PAGE
+ }
+ }
+ });
+ });
+ div.append(button);
+ div.classList.add("toolbarAddSignatureButtonContainer");
+ const svg = svgFactory.create(1, 1, true);
+ button.append(svg);
+ const span = document.createElement("span");
+ span.ariaHidden = true;
+ button.append(span);
+ button.classList.add("toolbarAddSignatureButton");
+ button.type = "button";
+ span.textContent = description;
+ button.setAttribute("data-l10n-id", "pdfjs-editor-add-saved-signature-button");
+ button.setAttribute("data-l10n-args", JSON.stringify({
+ description
+ }));
+ button.tabIndex = 0;
+ const path = svgFactory.createElement("path");
+ svg.append(path);
+ svg.setAttribute("viewBox", outline.viewBox);
+ svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
+ if (areContours) {
+ path.classList.add("contours");
+ }
+ path.setAttribute("d", outline.toSVGPath());
+ const deleteButton = document.createElement("button");
+ div.append(deleteButton);
+ deleteButton.classList.add("toolbarButton", "deleteButton");
+ deleteButton.setAttribute("data-l10n-id", "pdfjs-editor-delete-signature-button1");
+ deleteButton.type = "button";
+ deleteButton.tabIndex = 0;
+ deleteButton.addEventListener("click", async () => {
+ if (await this.#signatureStorage.delete(uuid)) {
+ div.remove();
+ this.#reportTelemetry({
+ type: "signature",
+ action: "pdfjs.signature.delete_saved",
+ data: {
+ savedCount: await this.#signatureStorage.size()
+ }
+ });
+ }
+ });
+ const deleteSpan = document.createElement("span");
+ deleteButton.append(deleteSpan);
+ deleteSpan.setAttribute("data-l10n-id", "pdfjs-editor-delete-signature-button-label1");
+ this.#addSignatureToolbarButton.before(div);
+ }
+ async #signaturesChanged() {
+ const parent = this.#addSignatureToolbarButton.parentElement;
+ while (parent.firstElementChild !== this.#addSignatureToolbarButton) {
+ parent.firstElementChild.remove();
+ }
+ this.#loadSignaturesPromise = null;
+ await this.loadSignatures(true);
+ }
+ getSignature(params) {
+ return this.open(params);
+ }
+ async loadSignatures(reload = false) {
+ if (!this.#addSignatureToolbarButton || !reload && this.#addSignatureToolbarButton.previousElementSibling || !this.#signatureStorage) {
+ return;
+ }
+ if (!this.#loadSignaturesPromise) {
+ this.#loadSignaturesPromise = this.#signatureStorage.getAll().then(async signatures => [signatures, await Promise.all(Array.from(signatures.values(), ({
+ signatureData
+ }) => SignatureExtractor.decompressSignature(signatureData)))]);
+ if (!reload) {
+ return;
+ }
+ }
+ const [signatures, signaturesData] = await this.#loadSignaturesPromise;
+ this.#loadSignaturesPromise = null;
+ let i = 0;
+ for (const [uuid, {
+ description
+ }] of signatures) {
+ const data = signaturesData[i++];
+ if (!data) {
+ continue;
+ }
+ data.curves = data.outlines.map(points => ({
+ points
+ }));
+ delete data.outlines;
+ this.#addToolbarButton(data, uuid, description);
+ }
+ }
+ async renderEditButton(editor) {
+ const button = document.createElement("button");
+ button.classList.add("altText", "editDescription");
+ button.tabIndex = 0;
+ if (editor.description) {
+ button.title = editor.description;
+ }
+ const span = document.createElement("span");
+ button.append(span);
+ span.setAttribute("data-l10n-id", "pdfjs-editor-add-signature-edit-button-label");
+ button.addEventListener("click", () => {
+ this.#editDescriptionDialog.open(editor);
+ }, {
+ passive: true
+ });
+ return button;
+ }
+ async open({
+ uiManager,
+ editor
+ }) {
+ this.#tabsToAltText ||= new Map(this.#tabButtons.keys().map(name => [name, {
+ value: "",
+ default: ""
+ }]));
+ this.#uiManager = uiManager;
+ this.#currentEditor = editor;
+ this.#uiManager.removeEditListeners();
+ const isStorageFull = this.#isStorageFull = await this.#signatureStorage.isFull();
+ this.#saveContainer.classList.toggle("fullStorage", isStorageFull);
+ this.#saveCheckbox.checked = !isStorageFull;
+ await this.#overlayManager.open(this.#dialog);
+ const tabType = this.#tabButtons.get("type");
+ tabType.focus();
+ tabType.click();
+ }
+ #cancel() {
+ this.#finish();
+ }
+ #finish() {
+ this.#overlayManager.closeIfActive(this.#dialog);
+ }
+ #close() {
+ if (this.#currentEditor._drawId === null) {
+ this.#currentEditor.remove();
+ }
+ this.#uiManager?.addEditListeners();
+ this.#currentTabAC?.abort();
+ this.#currentTabAC = null;
+ this.#uiManager = null;
+ this.#currentEditor = null;
+ this.#resetCommon();
+ for (const [name] of this.#tabButtons) {
+ this.#resetTab(name);
+ }
+ this.#disableButtons(false);
+ this.#currentTab = null;
+ this.#tabsToAltText = null;
+ }
+ async #add() {
+ let data;
+ const type = this.#currentTab;
+ switch (type) {
+ case "type":
+ data = this.#getOutlineForType();
+ break;
+ case "draw":
+ data = this.#getOutlineForDraw();
+ break;
+ case "image":
+ data = this.#extractedSignatureData;
+ break;
+ }
+ let uuid = null;
+ const description = this.#description.value;
+ if (this.#saveCheckbox.checked) {
+ const {
+ newCurves,
+ areContours,
+ thickness,
+ width,
+ height
+ } = data;
+ const signatureData = await SignatureExtractor.compressSignature({
+ outlines: newCurves,
+ areContours,
+ thickness,
+ width,
+ height
+ });
+ uuid = await this.#signatureStorage.create({
+ description,
+ signatureData
+ });
+ if (uuid) {
+ this.#addToolbarButton({
+ curves: newCurves.map(points => ({
+ points
+ })),
+ areContours,
+ thickness,
+ width,
+ height
+ }, uuid, description);
+ } else {
+ console.warn("SignatureManager.add: cannot save the signature.");
+ }
+ }
+ const altText = this.#tabsToAltText.get(type);
+ this.#reportTelemetry({
+ type: "signature",
+ action: "pdfjs.signature.created",
+ data: {
+ type,
+ saved: !!uuid,
+ savedCount: await this.#signatureStorage.size(),
+ descriptionChanged: description !== altText.default
+ }
+ });
+ this.#currentEditor.addSignature(data, DEFAULT_HEIGHT_IN_PAGE, this.#description.value, uuid);
+ this.#finish();
+ }
+ destroy() {
+ this.#uiManager = null;
+ this.#finish();
+ }
+}
+class EditDescriptionDialog {
+ #currentEditor;
+ #previousDescription;
+ #description;
+ #dialog;
+ #overlayManager;
+ #signatureSVG;
+ #uiManager;
+ constructor({
+ dialog,
+ description,
+ cancelButton,
+ updateButton,
+ editSignatureView
+ }, overlayManager) {
+ const descriptionInput = this.#description = description.firstElementChild;
+ this.#signatureSVG = editSignatureView;
+ this.#dialog = dialog;
+ this.#overlayManager = overlayManager;
+ dialog.addEventListener("close", this.#close.bind(this));
+ dialog.addEventListener("contextmenu", e => {
+ if (e.target !== this.#description) {
+ e.preventDefault();
+ }
+ });
+ cancelButton.addEventListener("click", this.#cancel.bind(this));
+ updateButton.addEventListener("click", this.#update.bind(this));
+ const clearDescription = description.lastElementChild;
+ clearDescription.addEventListener("click", () => {
+ descriptionInput.value = "";
+ clearDescription.disabled = true;
+ updateButton.disabled = this.#previousDescription === "";
+ });
+ descriptionInput.addEventListener("input", () => {
+ const {
+ value
+ } = descriptionInput;
+ clearDescription.disabled = value === "";
+ updateButton.disabled = value === this.#previousDescription;
+ editSignatureView.setAttribute("aria-label", value);
+ }, {
+ passive: true
+ });
+ overlayManager.register(dialog);
+ }
+ async open(editor) {
+ this.#uiManager = editor._uiManager;
+ this.#currentEditor = editor;
+ this.#previousDescription = this.#description.value = editor.description;
+ this.#description.dispatchEvent(new Event("input"));
+ this.#uiManager.removeEditListeners();
+ const {
+ areContours,
+ outline
+ } = editor.getSignaturePreview();
+ const svgFactory = new DOMSVGFactory();
+ const path = svgFactory.createElement("path");
+ this.#signatureSVG.append(path);
+ this.#signatureSVG.setAttribute("viewBox", outline.viewBox);
+ path.setAttribute("d", outline.toSVGPath());
+ if (areContours) {
+ path.classList.add("contours");
+ }
+ await this.#overlayManager.open(this.#dialog);
+ }
+ async #update() {
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.signature.edit_description",
+ data: {
+ hasBeenChanged: true
+ }
+ });
+ this.#currentEditor.description = this.#description.value;
+ this.#finish();
+ }
+ #cancel() {
+ this.#currentEditor._reportTelemetry({
+ action: "pdfjs.signature.edit_description",
+ data: {
+ hasBeenChanged: false
+ }
+ });
+ this.#finish();
+ }
+ #finish() {
+ this.#overlayManager.closeIfActive(this.#dialog);
+ }
+ #close() {
+ this.#uiManager?.addEditListeners();
+ this.#uiManager = null;
+ this.#currentEditor = null;
+ this.#signatureSVG.firstElementChild.remove();
+ }
+}
+
+;// ./web/digital_signature_properties_manager.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+const STATUS_ROW_VERIFIED = "pdfjs-digital-signature-properties-status-verified";
+const STATUS_ROW_INVALID = "pdfjs-digital-signature-properties-status-invalid";
+const STATUS_ROW_UNKNOWN = "pdfjs-digital-signature-properties-status-unknown";
+const STATUS_INFO = {
+ verified: {
+ priority: 0,
+ severity: "verified",
+ bannerId: "pdfjs-digital-signature-properties-banner-verified",
+ statusId: STATUS_ROW_VERIFIED
+ },
+ unknown: {
+ priority: 1,
+ severity: "error",
+ bannerId: "pdfjs-digital-signature-properties-banner-unknown",
+ statusId: STATUS_ROW_UNKNOWN
+ },
+ untrusted: {
+ priority: 2,
+ severity: "warn",
+ bannerId: "pdfjs-digital-signature-properties-banner-untrusted",
+ statusId: STATUS_ROW_VERIFIED
+ },
+ expired: {
+ priority: 3,
+ severity: "warn",
+ bannerId: "pdfjs-digital-signature-properties-banner-expired",
+ statusId: STATUS_ROW_VERIFIED
+ },
+ revoked: {
+ priority: 4,
+ severity: "error",
+ bannerId: "pdfjs-digital-signature-properties-banner-revoked",
+ statusId: STATUS_ROW_VERIFIED
+ },
+ invalid: {
+ priority: 5,
+ severity: "error",
+ bannerId: "pdfjs-digital-signature-properties-banner-invalid",
+ statusId: STATUS_ROW_INVALID
+ }
+};
+const CERT_L10N_IDS = {
+ trusted: "pdfjs-digital-signature-properties-certificate-trusted",
+ unknown: "pdfjs-digital-signature-properties-certificate-unknown",
+ untrusted: "pdfjs-digital-signature-properties-certificate-untrusted",
+ expired: "pdfjs-digital-signature-properties-certificate-expired",
+ revoked: "pdfjs-digital-signature-properties-certificate-revoked"
+};
+const CERT_EXPIRED_WITH_DATE_L10N_ID = "pdfjs-digital-signature-properties-certificate-expired-with-date";
+function untrustedCertLabel(errorCode, issuerCN) {
+ const code = (errorCode || "").toUpperCase();
+ const args = issuerCN ? {
+ issuer: issuerCN
+ } : null;
+ if (code.includes("UNKNOWN_ISSUER") && args) {
+ return {
+ id: "pdfjs-digital-signature-properties-certificate-untrusted-unknown-issuer",
+ args
+ };
+ }
+ if (code.includes("SELF_SIGNED") && args) {
+ return {
+ id: "pdfjs-digital-signature-properties-certificate-untrusted-self-signed",
+ args
+ };
+ }
+ if (code.includes("UNTRUSTED_ISSUER") && args) {
+ return {
+ id: "pdfjs-digital-signature-properties-certificate-untrusted-untrusted-issuer",
+ args
+ };
+ }
+ return {
+ id: "pdfjs-digital-signature-properties-certificate-untrusted",
+ args: null
+ };
+}
+function expirationDateForCert(cert) {
+ if (!cert) {
+ return null;
+ }
+ const now = Date.now();
+ const entries = Array.isArray(cert.chain) && cert.chain.length ? cert.chain : [cert];
+ for (const entry of entries) {
+ if (typeof entry?.notAfter !== "string" || !entry.notAfter) {
+ continue;
+ }
+ const date = new Date(entry.notAfter);
+ const ts = date.getTime();
+ if (Number.isFinite(ts) && ts < now) {
+ return date;
+ }
+ }
+ return null;
+}
+class SignaturePropertiesManager {
+ #appConfig;
+ #verifier;
+ #eventBus;
+ #signatures = [];
+ #results = new Map();
+ #pendingVerify = new Set();
+ #isOpen = false;
+ #isLoading = false;
+ #needsRender = false;
+ #pdfDocument = null;
+ constructor({
+ appConfig,
+ verifier,
+ eventBus
+ }) {
+ this.#appConfig = appConfig;
+ this.#verifier = verifier;
+ this.#eventBus = eventBus;
+ const button = appConfig.signaturePropertiesButton;
+ for (let i = 0; i < 3; i++) {
+ const dot = document.createElement("span");
+ dot.className = "loadingDot";
+ button.append(dot);
+ }
+ button.addEventListener("click", () => {
+ this.#toggle();
+ });
+ }
+ get isOpen() {
+ return this.#isOpen;
+ }
+ close() {
+ if (this.#isOpen) {
+ this.#close();
+ }
+ }
+ shouldCloseOnClick(target) {
+ if (!this.#isOpen) {
+ return false;
+ }
+ return !(this.#appConfig.signaturePropertiesButton.contains(target) || this.#appConfig.signaturePropertiesPanel.contains(target));
+ }
+ async setDocument(pdfDocument) {
+ if (this.#pdfDocument) {
+ this.#signatures = [];
+ this.#results.clear();
+ this.#pendingVerify.clear();
+ this.#needsRender = false;
+ this.#hideButton();
+ this.#close();
+ this.#updateButtonState();
+ }
+ this.#pdfDocument = pdfDocument;
+ if (!pdfDocument) {
+ return;
+ }
+ this.#isLoading = true;
+ this.#render();
+ let signatures;
+ try {
+ signatures = await pdfDocument.getSignatures();
+ } catch (ex) {
+ console.warn("getSignatures failed:", ex);
+ }
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ this.#signatures = signatures || [];
+ this.#isLoading = false;
+ if (this.#signatures.length === 0) {
+ this.#hideButton();
+ return;
+ }
+ this.#showButton();
+ for (const sig of this.#signatures) {
+ this.#results.set(sig.id, {
+ status: "unknown",
+ errorCode: null,
+ message: null,
+ certificate: null,
+ documentModifiedAfterSigning: !sig.coversWholeDocument,
+ modificationsAfterSignature: sig.modificationsAfterSignature
+ });
+ }
+ this.#render();
+ this.#updateButtonState();
+ for (const sig of this.#signatures) {
+ this.#verify(sig, pdfDocument);
+ }
+ }
+ #showButton() {
+ const root = this.#appConfig.signaturePropertiesButton.parentElement;
+ if (root) {
+ root.hidden = false;
+ }
+ const sep = this.#appConfig.signaturePropertiesSeparator;
+ if (sep) {
+ sep.hidden = false;
+ }
+ }
+ #hideButton() {
+ const root = this.#appConfig.signaturePropertiesButton.parentElement;
+ if (root) {
+ root.hidden = true;
+ }
+ const sep = this.#appConfig.signaturePropertiesSeparator;
+ if (sep) {
+ sep.hidden = true;
+ }
+ }
+ #toggle() {
+ if (this.#isOpen) {
+ this.#close();
+ } else {
+ this.#open();
+ }
+ }
+ #open() {
+ this.#isOpen = true;
+ this.#eventBus?.dispatch("switchannotationeditormode", {
+ source: this,
+ mode: AnnotationEditorType.NONE
+ });
+ this.#eventBus?.dispatch("findbarclose", {
+ source: this
+ });
+ this.#appConfig.signaturePropertiesPanel.classList.remove("hidden");
+ this.#appConfig.signaturePropertiesButton.setAttribute("aria-expanded", "true");
+ if (this.#needsRender) {
+ this.#render();
+ }
+ }
+ #close() {
+ this.#isOpen = false;
+ this.#appConfig.signaturePropertiesPanel.classList.add("hidden");
+ this.#appConfig.signaturePropertiesButton.setAttribute("aria-expanded", "false");
+ }
+ get #worst() {
+ let worst = "verified";
+ for (const r of this.#results.values()) {
+ if (r?.status && STATUS_INFO[r.status].priority > STATUS_INFO[worst].priority) {
+ worst = r.status;
+ }
+ }
+ return worst;
+ }
+ get #bannerState() {
+ if (this.#results.size === 0) {
+ return {
+ worst: "unknown",
+ severity: "error",
+ count: 0
+ };
+ }
+ const worst = this.#worst;
+ let count = 0;
+ for (const r of this.#results.values()) {
+ if (r?.status === worst) {
+ count++;
+ }
+ }
+ return {
+ worst,
+ severity: STATUS_INFO[worst].severity,
+ count
+ };
+ }
+ #render() {
+ if (!this.#isOpen) {
+ this.#needsRender = true;
+ return;
+ }
+ this.#needsRender = false;
+ const list = this.#appConfig.signaturePropertiesList;
+ const banner = this.#appConfig.signaturePropertiesBanner;
+ const fragment = document.createDocumentFragment();
+ if (this.#isLoading) {
+ banner.hidden = true;
+ list.replaceChildren();
+ return;
+ }
+ const {
+ worst,
+ severity,
+ count
+ } = this.#bannerState;
+ banner.replaceChildren();
+ banner.hidden = false;
+ banner.className = `sigBanner ${severity}`;
+ banner.setAttribute("data-l10n-id", STATUS_INFO[worst].bannerId);
+ banner.setAttribute("data-l10n-args", JSON.stringify({
+ count
+ }));
+ const byParent = new Map();
+ const topLevel = [];
+ for (const sig of this.#signatures) {
+ if (sig.parentId) {
+ byParent.getOrInsertComputed(sig.parentId, makeArr).push(sig);
+ } else {
+ topLevel.push(sig);
+ }
+ }
+ const everythingFine = severity === "verified";
+ for (const sig of topLevel) {
+ fragment.append(this.#renderCard(sig, byParent, 0, everythingFine));
+ }
+ list.replaceChildren(fragment);
+ }
+ #renderCard(sig, byParent, depth, everythingFine) {
+ const subs = byParent.get(sig.id) || [];
+ const li = document.createElement("li");
+ li.classList.add("sigCard");
+ if (depth === 0 && everythingFine) {
+ li.classList.add("sigCard--top-allfine");
+ }
+ const result = this.#results.get(sig.id);
+ const subjectCN = result?.certificate?.subjectCN;
+ if (subjectCN) {
+ const signer = document.createElement("div");
+ signer.className = "signer";
+ signer.textContent = subjectCN;
+ li.append(signer);
+ }
+ const statusRow = document.createElement("div");
+ statusRow.classList.add("row", `status--${result.status}`);
+ const statusLabel = document.createElement("span");
+ statusLabel.setAttribute("data-l10n-id", STATUS_INFO[result.status].statusId);
+ statusRow.append(statusLabel);
+ li.append(statusRow);
+ if (result.status === "invalid" && result.message) {
+ const reason = document.createElement("div");
+ reason.className = "detail";
+ reason.setAttribute("data-l10n-id", "pdfjs-digital-signature-properties-reason");
+ reason.setAttribute("data-l10n-args", JSON.stringify({
+ reason: result.message
+ }));
+ li.append(reason);
+ }
+ const cert = result.certificate;
+ let certKind = "unknown";
+ if (cert) {
+ switch (result.status) {
+ case "verified":
+ certKind = "trusted";
+ break;
+ case "expired":
+ certKind = "expired";
+ break;
+ case "revoked":
+ certKind = "revoked";
+ break;
+ case "untrusted":
+ certKind = "untrusted";
+ break;
+ default:
+ certKind = "unknown";
+ }
+ }
+ if (result.status !== "invalid") {
+ const certRow = document.createElement("div");
+ certRow.classList.add("row", `cert--${certKind}`);
+ const certLabel = document.createElement("span");
+ let l10nId = CERT_L10N_IDS[certKind];
+ let l10nArgs = null;
+ if (cert?.issuerCN && certKind === "trusted") {
+ l10nArgs = {
+ issuer: cert.issuerCN
+ };
+ } else if (certKind === "expired") {
+ const date = expirationDateForCert(cert);
+ if (date) {
+ l10nId = CERT_EXPIRED_WITH_DATE_L10N_ID;
+ l10nArgs = {
+ dateObj: date.valueOf()
+ };
+ }
+ } else if (certKind === "untrusted") {
+ const label = untrustedCertLabel(result.errorCode, cert?.issuerCN);
+ l10nId = label.id;
+ l10nArgs = label.args;
+ }
+ certLabel.setAttribute("data-l10n-id", l10nId);
+ if (l10nArgs) {
+ certLabel.setAttribute("data-l10n-args", JSON.stringify(l10nArgs));
+ }
+ certRow.append(certLabel);
+ li.append(certRow);
+ }
+ if (result.status === "untrusted" && result.message) {
+ const detail = document.createElement("div");
+ detail.className = "detail";
+ detail.textContent = result.message;
+ li.append(detail);
+ }
+ if (result.status === "expired" && result.message) {
+ const detail = document.createElement("div");
+ detail.className = "detail";
+ detail.textContent = result.message;
+ li.append(detail);
+ }
+ const signingDate = PDFDateString.toDateObject(sig.signingTime);
+ if (signingDate) {
+ const ts = document.createElement("div");
+ ts.className = "detail";
+ ts.setAttribute("data-l10n-id", "pdfjs-digital-signature-properties-timestamp");
+ ts.setAttribute("data-l10n-args", JSON.stringify({
+ dateObj: signingDate.valueOf()
+ }));
+ li.append(ts);
+ }
+ if (cert && typeof this.#verifier?.viewCertificate === "function") {
+ const viewCert = document.createElement("button");
+ viewCert.className = "viewCert";
+ viewCert.type = "button";
+ viewCert.setAttribute("data-l10n-id", "pdfjs-digital-signature-properties-view-certificate");
+ viewCert.addEventListener("click", e => {
+ e.stopPropagation();
+ this.#verifier.viewCertificate(cert);
+ });
+ li.append(viewCert);
+ }
+ if (subs.length > 0) {
+ const subList = document.createElement("ul");
+ subList.classList.add("signaturePropertiesList", "nested");
+ for (const sub of subs) {
+ subList.append(this.#renderCard(sub, byParent, depth + 1, everythingFine));
+ }
+ if (depth === 0) {
+ const details = document.createElement("details");
+ details.className = "subSignatures";
+ details.open = true;
+ const summary = document.createElement("summary");
+ summary.setAttribute("data-l10n-id", "pdfjs-digital-signature-properties-sub-signatures");
+ summary.setAttribute("data-l10n-args", JSON.stringify({
+ count: this.#countDescendants(sig.id, byParent)
+ }));
+ details.append(summary);
+ details.append(subList);
+ li.append(details);
+ } else {
+ li.append(subList);
+ }
+ }
+ return li;
+ }
+ #countDescendants(id, byParent) {
+ const direct = byParent.get(id);
+ if (!direct) {
+ return 0;
+ }
+ let total = direct.length;
+ for (const sub of direct) {
+ total += this.#countDescendants(sub.id, byParent);
+ }
+ return total;
+ }
+ async #verify(signature, pdfDocument) {
+ if (!this.#verifier || this.#pendingVerify.has(signature.id)) {
+ return;
+ }
+ this.#pendingVerify.add(signature.id);
+ this.#render();
+ let result;
+ try {
+ const bytes = await pdfDocument.getSignatureData(signature.id);
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ if (!bytes) {
+ throw new Error("missing signature data");
+ }
+ result = await this.#verifier.verify({
+ ...signature,
+ ...bytes
+ });
+ } catch (ex) {
+ console.warn("signature verify failed:", ex);
+ result = {
+ status: "unknown",
+ errorCode: "BRIDGE_ERROR",
+ message: ex?.message ?? null,
+ certificate: null,
+ documentModifiedAfterSigning: !signature.coversWholeDocument,
+ modificationsAfterSignature: signature.modificationsAfterSignature
+ };
+ }
+ this.#pendingVerify.delete(signature.id);
+ if (pdfDocument !== this.#pdfDocument) {
+ return;
+ }
+ this.#results.set(signature.id, result);
+ this.#render();
+ this.#updateButtonState();
+ }
+ #updateButtonState() {
+ const button = this.#appConfig.signaturePropertiesButton;
+ button.classList.remove("state-loading", "state-verified", "state-warn", "state-error");
+ if (this.#signatures.length === 0) {
+ return;
+ }
+ if (this.#pendingVerify.size > 0) {
+ button.classList.add("state-loading");
+ return;
+ }
+ switch (this.#worst) {
+ case "invalid":
+ case "revoked":
+ case "unknown":
+ button.classList.add("state-error");
+ break;
+ case "expired":
+ case "untrusted":
+ button.classList.add("state-warn");
+ break;
+ default:
+ button.classList.add("state-verified");
+ }
+ }
+}
+
+;// ./web/toolbar.js
+
+
+
+
+class Toolbar {
+ #colorPicker = null;
+ #opts;
+ constructor(options, eventBus, toolbarDensity = 0) {
+ this.#opts = options;
+ this.eventBus = eventBus;
+ const buttons = [{
+ element: options.previous,
+ eventName: "previouspage"
+ }, {
+ element: options.next,
+ eventName: "nextpage"
+ }, {
+ element: options.zoomIn,
+ eventName: "zoomin"
+ }, {
+ element: options.zoomOut,
+ eventName: "zoomout"
+ }, {
+ element: options.print,
+ eventName: "print"
+ }, {
+ element: options.download,
+ eventName: "download"
+ }, {
+ element: options.editorCommentButton,
+ eventName: "switchannotationeditormode",
+ eventDetails: {
+ get mode() {
+ const {
+ classList
+ } = options.editorCommentButton;
+ return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.POPUP;
+ }
+ }
+ }, {
+ element: options.editorFreeTextButton,
+ eventName: "switchannotationeditormode",
+ eventDetails: {
+ get mode() {
+ const {
+ classList
+ } = options.editorFreeTextButton;
+ return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.FREETEXT;
+ }
+ }
+ }, {
+ element: options.editorHighlightButton,
+ eventName: "switchannotationeditormode",
+ eventDetails: {
+ get mode() {
+ const {
+ classList
+ } = options.editorHighlightButton;
+ return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.HIGHLIGHT;
+ }
+ }
+ }, {
+ element: options.editorInkButton,
+ eventName: "switchannotationeditormode",
+ eventDetails: {
+ get mode() {
+ const {
+ classList
+ } = options.editorInkButton;
+ return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.INK;
+ }
+ }
+ }, {
+ element: options.editorStampButton,
+ eventName: "switchannotationeditormode",
+ eventDetails: {
+ get mode() {
+ const {
+ classList
+ } = options.editorStampButton;
+ return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.STAMP;
+ }
+ },
+ telemetry: {
+ type: "editing",
+ data: {
+ action: "pdfjs.image.icon_click"
+ }
+ }
+ }, {
+ element: options.editorSignatureButton,
+ eventName: "switchannotationeditormode",
+ eventDetails: {
+ get mode() {
+ const {
+ classList
+ } = options.editorSignatureButton;
+ return classList.contains("toggled") ? AnnotationEditorType.NONE : AnnotationEditorType.SIGNATURE;
+ }
+ }
+ }];
+ this.#bindListeners(buttons);
+ this.#updateToolbarDensity({
+ value: toolbarDensity
+ });
+ this.reset();
+ }
+ #updateToolbarDensity({
+ value
+ }) {
+ let name = "normal";
+ switch (value) {
+ case 1:
+ name = "compact";
+ break;
+ case 2:
+ name = "touch";
+ break;
+ }
+ document.documentElement.setAttribute("data-toolbar-density", name);
+ }
+ setPageNumber(pageNumber, pageLabel) {
+ this.pageNumber = pageNumber;
+ this.pageLabel = pageLabel;
+ this.#updateUIState(false);
+ }
+ setPagesCount(pagesCount, hasPageLabels) {
+ this.pagesCount = pagesCount;
+ this.hasPageLabels = hasPageLabels;
+ this.#updateUIState(true);
+ }
+ setPageScale(pageScaleValue, pageScale) {
+ this.pageScaleValue = (pageScaleValue || pageScale).toString();
+ this.pageScale = pageScale;
+ this.#updateUIState(false);
+ }
+ reset() {
+ this.#colorPicker = null;
+ this.pageNumber = 0;
+ this.pageLabel = null;
+ this.hasPageLabels = false;
+ this.pagesCount = 0;
+ this.pageScaleValue = (/* inlined export .DEFAULT_SCALE_VALUE */"auto");
+ this.pageScale = (/* inlined export .DEFAULT_SCALE */1);
+ this.#updateUIState(true);
+ this.updateLoadingIndicatorState();
+ this.#editorModeChanged({
+ mode: AnnotationEditorType.DISABLE
+ });
+ }
+ #bindListeners(buttons) {
+ const {
+ eventBus
+ } = this;
+ const {
+ editorHighlightColorPicker,
+ editorHighlightButton,
+ pageNumber,
+ scaleSelect
+ } = this.#opts;
+ const self = this;
+ for (const {
+ element,
+ eventName,
+ eventDetails,
+ telemetry
+ } of buttons) {
+ element.addEventListener("click", evt => {
+ if (eventName !== null) {
+ eventBus.dispatch(eventName, {
+ source: this,
+ ...eventDetails,
+ isFromKeyboard: evt.detail === 0
+ });
+ }
+ if (telemetry) {
+ eventBus.dispatch("reporttelemetry", {
+ source: this,
+ details: telemetry
+ });
+ }
+ });
+ }
+ pageNumber.addEventListener("click", function () {
+ this.select();
+ });
+ pageNumber.addEventListener("change", function () {
+ eventBus.dispatch("pagenumberchanged", {
+ source: self,
+ value: this.value
+ });
+ });
+ eventBus.on("pagesedited", ({
+ pagesMapper
+ }) => {
+ const pagesCount = pagesMapper.pagesNumber;
+ if (pagesCount !== this.pagesCount) {
+ this.setPagesCount(pagesCount, this.hasPageLabels);
+ }
+ }, internalOpt);
+ scaleSelect.addEventListener("change", function () {
+ if (this.value === "custom") {
+ return;
+ }
+ eventBus.dispatch("scalechanged", {
+ source: self,
+ value: this.value
+ });
+ });
+ scaleSelect.addEventListener("click", function ({
+ target
+ }) {
+ if (this.value === self.pageScaleValue && target.tagName.toUpperCase() === "OPTION") {
+ this.blur();
+ }
+ });
+ scaleSelect.oncontextmenu = noContextMenu;
+ eventBus.on("annotationeditormodechanged", this.#editorModeChanged.bind(this), internalOpt);
+ eventBus.on("showannotationeditorui", ({
+ mode
+ }) => {
+ switch (mode) {
+ case AnnotationEditorType.HIGHLIGHT:
+ editorHighlightButton.click();
+ break;
+ }
+ }, internalOpt);
+ eventBus.on("toolbardensity", this.#updateToolbarDensity.bind(this), internalOpt);
+ if (editorHighlightColorPicker) {
+ eventBus.on("annotationeditoruimanager", ({
+ uiManager
+ }) => {
+ const cp = this.#colorPicker = new ColorPicker({
+ uiManager
+ });
+ uiManager.setMainHighlightColorPicker(cp);
+ editorHighlightColorPicker.append(cp.renderMainDropdown());
+ }, internalOpt);
+ eventBus.on("mainhighlightcolorpickerupdatecolor", ({
+ value
+ }) => {
+ this.#colorPicker?.update(value);
+ }, internalOpt);
+ }
+ }
+ #editorModeChanged({
+ mode
+ }) {
+ const {
+ editorCommentButton,
+ editorCommentParamsToolbar,
+ editorFreeTextButton,
+ editorFreeTextParamsToolbar,
+ editorHighlightButton,
+ editorHighlightParamsToolbar,
+ editorInkButton,
+ editorInkParamsToolbar,
+ editorStampButton,
+ editorStampParamsToolbar,
+ editorSignatureButton,
+ editorSignatureParamsToolbar
+ } = this.#opts;
+ toggleExpandedBtn(editorCommentButton, mode === AnnotationEditorType.POPUP, editorCommentParamsToolbar);
+ toggleExpandedBtn(editorFreeTextButton, mode === AnnotationEditorType.FREETEXT, editorFreeTextParamsToolbar);
+ toggleExpandedBtn(editorHighlightButton, mode === AnnotationEditorType.HIGHLIGHT, editorHighlightParamsToolbar);
+ toggleExpandedBtn(editorInkButton, mode === AnnotationEditorType.INK, editorInkParamsToolbar);
+ toggleExpandedBtn(editorStampButton, mode === AnnotationEditorType.STAMP, editorStampParamsToolbar);
+ toggleExpandedBtn(editorSignatureButton, mode === AnnotationEditorType.SIGNATURE, editorSignatureParamsToolbar);
+ editorCommentButton.disabled = editorFreeTextButton.disabled = editorHighlightButton.disabled = editorInkButton.disabled = editorStampButton.disabled = editorSignatureButton.disabled = mode === AnnotationEditorType.DISABLE;
+ }
+ #updateUIState(resetNumPages = false) {
+ const {
+ pageNumber,
+ pagesCount,
+ pageScaleValue,
+ pageScale
+ } = this;
+ const opts = this.#opts;
+ if (resetNumPages) {
+ if (this.hasPageLabels) {
+ opts.pageNumber.type = "text";
+ opts.numPages.setAttribute("data-l10n-id", "pdfjs-page-of-pages");
+ } else {
+ opts.pageNumber.type = "number";
+ opts.numPages.setAttribute("data-l10n-id", "pdfjs-of-pages");
+ opts.numPages.setAttribute("data-l10n-args", JSON.stringify({
+ pagesCount
+ }));
+ }
+ opts.pageNumber.max = pagesCount;
+ }
+ if (this.hasPageLabels) {
+ opts.pageNumber.value = this.pageLabel;
+ opts.numPages.setAttribute("data-l10n-args", JSON.stringify({
+ pageNumber,
+ pagesCount
+ }));
+ } else {
+ opts.pageNumber.value = pageNumber;
+ }
+ opts.previous.disabled = pageNumber <= 1;
+ opts.next.disabled = pageNumber >= pagesCount;
+ opts.zoomOut.disabled = pageScale <= (/* inlined export .MIN_SCALE */0.1);
+ opts.zoomIn.disabled = pageScale >= (/* inlined export .MAX_SCALE */25);
+ let predefinedValueFound = false;
+ for (const option of opts.scaleSelect.options) {
+ if (option.value !== pageScaleValue) {
+ option.selected = false;
+ continue;
+ }
+ option.selected = true;
+ predefinedValueFound = true;
+ }
+ if (!predefinedValueFound) {
+ opts.customScaleOption.selected = true;
+ opts.customScaleOption.setAttribute("data-l10n-args", JSON.stringify({
+ scale: Math.round(pageScale * 10000) / 100
+ }));
+ }
+ }
+ updateLoadingIndicatorState(loading = false) {
+ const {
+ pageNumber
+ } = this.#opts;
+ pageNumber.classList.toggle("loading", loading);
+ }
+}
+
+;// ./web/view_history.js
+
+
+
+const DEFAULT_VIEW_HISTORY_CACHE_SIZE = 20;
+class ViewHistory {
+ constructor(fingerprint, cacheSize = DEFAULT_VIEW_HISTORY_CACHE_SIZE) {
+ this._initializedPromise = this._readFromStorage().then(databaseStr => {
+ const database = JSON.parse(databaseStr || "{}");
+ let index = -1;
+ if (!Array.isArray(database.files)) {
+ database.files = [];
+ } else {
+ while (database.files.length >= cacheSize) {
+ database.files.shift();
+ }
+ index = database.files.findIndex(branch => branch.fingerprint === fingerprint);
+ }
+ if (index === -1) {
+ index = database.files.push({
+ fingerprint
+ }) - 1;
+ }
+ this.file = database.files[index];
+ this.database = database;
+ });
+ }
+ async _writeToStorage() {
+ const databaseStr = JSON.stringify(this.database);
+ localStorage.setItem("pdfjs.history", databaseStr);
+ }
+ async _readFromStorage() {
+ return localStorage.getItem("pdfjs.history");
+ }
+ async set(name, val) {
+ await this._initializedPromise;
+ this.file[name] = val;
+ return this._writeToStorage();
+ }
+ async setMultiple(properties) {
+ await this._initializedPromise;
+ for (const name in properties) {
+ this.file[name] = properties[name];
+ }
+ return this._writeToStorage();
+ }
+ async get(name, defaultValue) {
+ await this._initializedPromise;
+ const val = this.file[name];
+ return val !== undefined ? val : defaultValue;
+ }
+ async getMultiple(properties) {
+ await this._initializedPromise;
+ const values = Object.create(null);
+ for (const name in properties) {
+ const val = this.file[name];
+ values[name] = val !== undefined ? val : properties[name];
+ }
+ return values;
+ }
+}
+
+;// ./web/views_manager.js
+
+
+
+
+const SIDEBAR_WIDTH_VAR = "--viewsManager-width";
+const SIDEBAR_RESIZING_CLASS = "viewsManagerResizing";
+const UI_NOTIFICATION_CLASS = "pdfSidebarNotification";
+class ViewsManager extends Sidebar {
+ static #l10nDescription = null;
+ #hasAnimations = !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
+ constructor({
+ elements: {
+ outerContainer,
+ sidebarContainer,
+ toggleButton,
+ resizer,
+ thumbnailButton,
+ outlineButton,
+ attachmentsButton,
+ layersButton,
+ thumbnailsView,
+ outlinesView,
+ attachmentsView,
+ layersView,
+ viewsManagerAddFile: {
+ button: viewsManagerAddFileButton
+ },
+ viewsManagerCurrentOutlineButton,
+ viewsManagerSelectorButton,
+ viewsManagerSelectorOptions,
+ viewsManagerHeaderLabel,
+ viewsManagerStatus
+ },
+ eventBus,
+ l10n,
+ enableMerge = false,
+ enableSplitMerge = false,
+ globalAbortSignal
+ }) {
+ super({
+ sidebar: sidebarContainer,
+ resizer,
+ toggleButton
+ }, l10n.getDirection() === "ltr", false, globalAbortSignal);
+ this.isOpen = false;
+ this.active = SidebarView.THUMBS;
+ this.isInitialViewSet = false;
+ this.isInitialEventDispatched = false;
+ this.onToggled = null;
+ this.onUpdateThumbnails = null;
+ this.outerContainer = outerContainer;
+ this.sidebarContainer = sidebarContainer;
+ this.toggleButton = toggleButton;
+ this.resizer = resizer;
+ this.thumbnailButton = thumbnailButton;
+ this.outlineButton = outlineButton;
+ this.attachmentsButton = attachmentsButton;
+ this.layersButton = layersButton;
+ this.thumbnailsView = thumbnailsView;
+ this.outlinesView = outlinesView;
+ this.attachmentsView = attachmentsView;
+ this.layersView = layersView;
+ this.viewsManagerAddFileButton = viewsManagerAddFileButton;
+ this.viewsManagerCurrentOutlineButton = viewsManagerCurrentOutlineButton;
+ this.viewsManagerHeaderLabel = viewsManagerHeaderLabel;
+ this.viewsManagerStatus = viewsManagerStatus;
+ this.eventBus = eventBus;
+ if (!enableSplitMerge) {
+ viewsManagerStatus.hidden = true;
+ }
+ this._enableSplitMerge = enableSplitMerge;
+ this._enableMerge = enableMerge;
+ if (!enableMerge) {
+ viewsManagerAddFileButton.hidden = true;
+ }
+ this.menu = new Menu(viewsManagerSelectorOptions, viewsManagerSelectorButton, [thumbnailButton, outlineButton, attachmentsButton, layersButton]);
+ ViewsManager.#l10nDescription ||= Object.freeze({
+ pagesTitle: "pdfjs-views-manager-pages-title",
+ outlinesTitle: "pdfjs-views-manager-outlines-title1",
+ attachmentsTitle: "pdfjs-views-manager-attachments-title",
+ layersTitle: "pdfjs-views-manager-layers-title1",
+ notificationButton: "pdfjs-toggle-views-manager-notification-button",
+ toggleButton: "pdfjs-toggle-views-manager-button1"
+ });
+ this.#addEventListeners();
+ }
+ reset() {
+ this.isInitialViewSet = false;
+ this.isInitialEventDispatched = false;
+ this.#hideUINotification(true);
+ this.switchView(SidebarView.THUMBS);
+ this.outlineButton.disabled = this.attachmentsButton.disabled = this.layersButton.disabled = false;
+ this.viewsManagerCurrentOutlineButton.disabled = true;
+ }
+ get visibleView() {
+ return this.isOpen ? this.active : SidebarView.NONE;
+ }
+ setInitialView(view = SidebarView.NONE) {
+ if (this.isInitialViewSet) {
+ return;
+ }
+ this.isInitialViewSet = true;
+ if (view === SidebarView.NONE || view === SidebarView.UNKNOWN) {
+ this.#dispatchEvent();
+ return;
+ }
+ this.switchView(view, true);
+ if (!this.isInitialEventDispatched) {
+ this.#dispatchEvent();
+ }
+ }
+ switchView(view, forceOpen = false) {
+ const isViewChanged = view !== this.active;
+ let forceRendering = false;
+ let titleL10nId = null;
+ switch (view) {
+ case SidebarView.NONE:
+ if (this.isOpen) {
+ this.close();
+ }
+ return;
+ case SidebarView.THUMBS:
+ titleL10nId = "pagesTitle";
+ if (this.isOpen && isViewChanged) {
+ forceRendering = true;
+ }
+ break;
+ case SidebarView.OUTLINE:
+ titleL10nId = "outlinesTitle";
+ if (this.outlineButton.disabled) {
+ return;
+ }
+ break;
+ case SidebarView.ATTACHMENTS:
+ titleL10nId = "attachmentsTitle";
+ if (this.attachmentsButton.disabled) {
+ return;
+ }
+ break;
+ case SidebarView.LAYERS:
+ titleL10nId = "layersTitle";
+ if (this.layersButton.disabled) {
+ return;
+ }
+ break;
+ default:
+ console.error(`PDFSidebar.switchView: "${view}" is not a valid view.`);
+ return;
+ }
+ this.viewsManagerStatus.hidden = !this._enableSplitMerge || view !== SidebarView.THUMBS;
+ this.viewsManagerAddFileButton.hidden = !this._enableMerge || view !== SidebarView.THUMBS;
+ this.viewsManagerCurrentOutlineButton.hidden = view !== SidebarView.OUTLINE;
+ this.viewsManagerHeaderLabel.setAttribute("data-l10n-id", ViewsManager.#l10nDescription[titleL10nId] || "");
+ this.active = view;
+ toggleSelectedBtn(this.thumbnailButton, view === SidebarView.THUMBS, this.thumbnailsView);
+ toggleSelectedBtn(this.outlineButton, view === SidebarView.OUTLINE, this.outlinesView);
+ toggleSelectedBtn(this.attachmentsButton, view === SidebarView.ATTACHMENTS, this.attachmentsView);
+ toggleSelectedBtn(this.layersButton, view === SidebarView.LAYERS, this.layersView);
+ if (forceOpen && !this.isOpen) {
+ this.open();
+ return;
+ }
+ if (forceRendering) {
+ this.onUpdateThumbnails();
+ this.onToggled();
+ }
+ if (isViewChanged) {
+ this.#dispatchEvent();
+ }
+ }
+ open() {
+ if (this.isOpen) {
+ return;
+ }
+ this.isOpen = true;
+ this.onResizing(this.width);
+ this._sidebar.hidden = false;
+ toggleExpandedBtn(this.toggleButton, true);
+ this.switchView(this.active);
+ if (this.#hasAnimations) {
+ queueMicrotask(() => {
+ this.outerContainer.classList.add("viewsManagerMoving", "viewsManagerOpen");
+ });
+ } else {
+ this.outerContainer.classList.add("viewsManagerOpen");
+ this.eventBus.dispatch("resize", {
+ source: this
+ });
+ }
+ if (this.active === SidebarView.THUMBS) {
+ this.onUpdateThumbnails();
+ }
+ this.onToggled();
+ this.#dispatchEvent();
+ this.#hideUINotification();
+ }
+ close(evt = null) {
+ if (!this.isOpen) {
+ return;
+ }
+ this.isOpen = false;
+ this._sidebar.hidden = true;
+ toggleExpandedBtn(this.toggleButton, false);
+ this.outerContainer.classList.add("viewsManagerMoving");
+ this.outerContainer.classList.remove("viewsManagerOpen");
+ this.onToggled();
+ this.#dispatchEvent();
+ if (evt?.detail > 0) {
+ this.toggleButton.blur();
+ }
+ }
+ toggle(evt = null) {
+ super.toggle();
+ if (this.isOpen) {
+ this.close(evt);
+ } else {
+ this.open();
+ }
+ }
+ #dispatchEvent() {
+ if (this.isInitialViewSet) {
+ this.isInitialEventDispatched ||= true;
+ }
+ this.eventBus.dispatch("sidebarviewchanged", {
+ source: this,
+ view: this.visibleView
+ });
+ }
+ #showUINotification() {
+ this.toggleButton.setAttribute("data-l10n-id", ViewsManager.#l10nDescription.notificationButton);
+ if (!this.isOpen) {
+ this.toggleButton.classList.add(UI_NOTIFICATION_CLASS);
+ }
+ }
+ #hideUINotification(reset = false) {
+ if (this.isOpen || reset) {
+ this.toggleButton.classList.remove(UI_NOTIFICATION_CLASS);
+ }
+ if (reset) {
+ this.toggleButton.setAttribute("data-l10n-id", ViewsManager.#l10nDescription.toggleButton);
+ }
+ }
+ #addEventListeners() {
+ const {
+ eventBus,
+ outerContainer
+ } = this;
+ if (this.#hasAnimations) {
+ this.sidebarContainer.addEventListener("transitionend", evt => {
+ if (evt.target === this.sidebarContainer) {
+ outerContainer.classList.remove("viewsManagerMoving");
+ eventBus.dispatch("resize", {
+ source: this
+ });
+ }
+ });
+ }
+ this.viewsManagerHeaderLabel.addEventListener("dblclick", e => {
+ if (this.active === SidebarView.OUTLINE) {
+ eventBus.dispatch("toggleoutlinetree", {
+ source: this
+ });
+ return;
+ }
+ if (this.active === SidebarView.LAYERS) {
+ eventBus.dispatch("resetlayers", {
+ source: this
+ });
+ }
+ });
+ this.thumbnailButton.addEventListener("click", () => {
+ this.switchView(SidebarView.THUMBS);
+ });
+ this.outlineButton.addEventListener("click", () => {
+ this.switchView(SidebarView.OUTLINE);
+ });
+ this.attachmentsButton.addEventListener("click", () => {
+ this.switchView(SidebarView.ATTACHMENTS);
+ });
+ this.layersButton.addEventListener("click", () => {
+ this.switchView(SidebarView.LAYERS);
+ });
+ this.viewsManagerCurrentOutlineButton.addEventListener("click", () => {
+ eventBus.dispatch("currentoutlineitem", {
+ source: this
+ });
+ });
+ const onTreeLoaded = (count, button, view) => {
+ button.disabled = !count;
+ if (count) {
+ this.#showUINotification();
+ } else if (this.active === view) {
+ this.switchView(SidebarView.THUMBS);
+ }
+ };
+ eventBus.on("outlineloaded", evt => {
+ onTreeLoaded(evt.outlineCount, this.outlineButton, SidebarView.OUTLINE);
+ evt.currentOutlineItemPromise.then(enabled => {
+ if (!this.isInitialViewSet) {
+ return;
+ }
+ this.viewsManagerCurrentOutlineButton.disabled = !enabled;
+ });
+ }, internalOpt);
+ eventBus.on("attachmentsloaded", evt => {
+ onTreeLoaded(evt.attachmentsCount, this.attachmentsButton, SidebarView.ATTACHMENTS);
+ }, internalOpt);
+ eventBus.on("layersloaded", evt => {
+ onTreeLoaded(evt.layersCount, this.layersButton, SidebarView.LAYERS);
+ }, internalOpt);
+ eventBus.on("presentationmodechanged", evt => {
+ if (evt.state === PresentationModeState.NORMAL && this.visibleView === SidebarView.THUMBS) {
+ this.onUpdateThumbnails();
+ }
+ }, internalOpt);
+ }
+ onStartResizing() {
+ this.outerContainer.classList.add(SIDEBAR_RESIZING_CLASS);
+ }
+ onStopResizing() {
+ this.eventBus.dispatch("resize", {
+ source: this
+ });
+ this.outerContainer.classList.remove(SIDEBAR_RESIZING_CLASS);
+ }
+ onResizing(newWidth) {
+ docStyle.setProperty(SIDEBAR_WIDTH_VAR, `${newWidth}px`);
+ }
+}
+
+;// ./web/app.js
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+const FORCE_PAGES_LOADED_TIMEOUT = 10000;
+const ViewOnLoad = {
+ UNKNOWN: -1,
+ PREVIOUS: 0,
+ INITIAL: 1
+};
+const PDFViewerApplication = {
+ initialBookmark: document.location.hash.substring(1),
+ _initializedCapability: {
+ ...Promise.withResolvers(),
+ settled: false
+ },
+ appConfig: null,
+ pdfDocument: null,
+ pdfLoadingTask: null,
+ printService: null,
+ pdfViewer: null,
+ pdfThumbnailViewer: null,
+ pdfRenderingQueue: null,
+ pdfPresentationMode: null,
+ pdfDocumentProperties: null,
+ pdfLinkService: null,
+ pdfTextExtractor: null,
+ pdfHistory: null,
+ viewsManager: null,
+ pdfOutlineViewer: null,
+ pdfAttachmentViewer: null,
+ pdfLayerViewer: null,
+ pdfCursorTools: null,
+ pdfScriptingManager: null,
+ store: null,
+ downloadManager: null,
+ overlayManager: null,
+ preferences: new Preferences(),
+ toolbar: null,
+ secondaryToolbar: null,
+ eventBus: null,
+ l10n: null,
+ annotationEditorParams: null,
+ signaturePropertiesManager: null,
+ imageAltTextSettings: null,
+ isInitialViewSet: false,
+ isViewerEmbedded: window.parent !== window,
+ url: "",
+ baseUrl: "",
+ mlManager: null,
+ _downloadUrl: "",
+ _eventBusAC: null,
+ _windowAC: null,
+ _globalAbortController: new AbortController(),
+ documentInfo: null,
+ metadata: null,
+ _contentDispositionFilename: null,
+ _contentLength: null,
+ _saveInProgress: false,
+ _wheelUnusedTicks: 0,
+ _wheelUnusedFactor: 1,
+ _touchManager: null,
+ _touchUnusedTicks: 0,
+ _touchUnusedFactor: 1,
+ _PDFBug: null,
+ _hasAnnotationEditors: false,
+ _title: document.title,
+ _printAnnotationStoragePromise: null,
+ _isCtrlKeyDown: false,
+ _caretBrowsing: null,
+ _isScrolling: false,
+ editorUndoBar: null,
+ _printPermissionPromise: null,
+ async initialize(appConfig) {
+ this.appConfig = appConfig;
+ try {
+ await this.preferences.initializedPromise;
+ } catch (ex) {
+ console.error("initialize:", ex);
+ }
+ if (AppOptions.get("pdfBugEnabled")) {
+ await this._parseHashParams();
+ }
+ let mode;
+ switch (AppOptions.get("viewerCssTheme")) {
+ case 1:
+ mode = "light";
+ break;
+ case 2:
+ mode = "dark";
+ break;
+ }
+ if (mode) {
+ docStyle.setProperty("color-scheme", mode);
+ }
+ this.l10n = await this.externalServices.createL10n();
+ document.getElementsByTagName("html")[0].dir = this.l10n.getDirection();
+ this.l10n.translate(appConfig.appContainer || document.documentElement);
+ if (this.isViewerEmbedded && AppOptions.get("externalLinkTarget") === LinkTarget.NONE) {
+ AppOptions.set("externalLinkTarget", LinkTarget.TOP);
+ }
+ await this._initializeViewerComponents();
+ this.bindEvents();
+ this.bindWindowEvents();
+ this._initializedCapability.settled = true;
+ this._initializedCapability.resolve();
+ },
+ async _parseHashParams() {
+ const hash = document.location.hash.substring(1);
+ if (!hash) {
+ return;
+ }
+ const {
+ mainContainer,
+ viewerContainer
+ } = this.appConfig,
+ params = parseQueryString(hash);
+ const loadPDFBug = async () => {
+ if (this._PDFBug) {
+ return;
+ }
+ const {
+ PDFBug
+ } = await import(
+ /*webpackIgnore: true*/
+ /*@vite-ignore*/
+ AppOptions.get("debuggerSrc"));
+ this._PDFBug = PDFBug;
+ };
+ if (params.get("disableworker") === "true") {
+ try {
+ GlobalWorkerOptions.workerSrc ||= AppOptions.get("workerSrc");
+ await import(
+ /*webpackIgnore: true*/
+ /*@vite-ignore*/
+ PDFWorker.workerSrc);
+ AppOptions.set("workerPort", null);
+ } catch (ex) {
+ console.error("_parseHashParams:", ex);
+ }
+ }
+ if (params.has("textlayer")) {
+ switch (params.get("textlayer")) {
+ case "off":
+ AppOptions.set("textLayerMode", TextLayerMode.DISABLE);
+ break;
+ case "visible":
+ case "shadow":
+ case "hover":
+ viewerContainer.classList.add(`textLayer-${params.get("textlayer")}`);
+ try {
+ await loadPDFBug();
+ this._PDFBug.loadCSS();
+ } catch (ex) {
+ console.error("_parseHashParams:", ex);
+ }
+ break;
+ }
+ }
+ if (params.has("pdfbug")) {
+ const enabled = params.get("pdfbug").split(",");
+ try {
+ await loadPDFBug();
+ this._PDFBug.init(mainContainer, enabled);
+ } catch (ex) {
+ console.error("_parseHashParams:", ex);
+ }
+ const debugOpts = {
+ pdfBug: true,
+ fontExtraProperties: true
+ };
+ if (globalThis.StepperManager?.enabled) {
+ debugOpts.minDurationToUpdateCanvas = 0;
+ }
+ AppOptions.setAll(debugOpts);
+ }
+ if (params.has("locale")) {
+ AppOptions.set("localeProperties", {
+ lang: params.get("locale")
+ });
+ }
+ const opts = {
+ disableAutoFetch: x => x === "true",
+ disableFontFace: x => x === "true",
+ disableHistory: x => x === "true",
+ disableRange: x => x === "true",
+ disableStream: x => x === "true",
+ verbosity: x => x | 0
+ };
+ for (const name in opts) {
+ const check = opts[name],
+ key = name.toLowerCase();
+ if (params.has(key)) {
+ AppOptions.set(name, check(params.get(key)));
+ }
+ }
+ },
+ async _initializeViewerComponents() {
+ const {
+ appConfig,
+ externalServices,
+ l10n,
+ mlManager
+ } = this;
+ const abortSignal = this._globalAbortController.signal;
+ const eventBus = new EventBus();
+ this.eventBus = AppOptions.eventBus = eventBus;
+ mlManager?.setEventBus(eventBus, abortSignal);
+ const overlayManager = this.overlayManager = new OverlayManager();
+ const renderingQueue = this.pdfRenderingQueue = new PDFRenderingQueue();
+ renderingQueue.onIdle = this._cleanup.bind(this);
+ const linkService = this.pdfLinkService = new PDFLinkService({
+ eventBus,
+ externalLinkTarget: AppOptions.get("externalLinkTarget"),
+ externalLinkRel: AppOptions.get("externalLinkRel"),
+ ignoreDestinationZoom: AppOptions.get("ignoreDestinationZoom")
+ });
+ const supportsDownloading = AppOptions.get("supportsDownloading");
+ const downloadManager = this.downloadManager = supportsDownloading ? new DownloadManager() : null;
+ if (appConfig.secondaryToolbar?.downloadButton) {
+ appConfig.secondaryToolbar.downloadButton.hidden = !supportsDownloading;
+ }
+ if (appConfig.toolbar?.download) {
+ appConfig.toolbar.download.hidden = !supportsDownloading;
+ }
+ const findController = this.findController = new PDFFindController({
+ linkService,
+ eventBus,
+ updateMatchesCountOnProgress: true
+ });
+ const pdfScriptingManager = this.pdfScriptingManager = new PDFScriptingManager({
+ eventBus,
+ externalServices,
+ docProperties: this._scriptingDocProperties.bind(this)
+ });
+ const container = appConfig.mainContainer,
+ viewer = appConfig.viewerContainer;
+ const annotationEditorMode = AppOptions.get("annotationEditorMode");
+ const hasForcedColors = AppOptions.get("forcePageColors") || window.matchMedia("(forced-colors: active)").matches;
+ const pageColors = hasForcedColors ? {
+ background: AppOptions.get("pageColorsBackground"),
+ foreground: AppOptions.get("pageColorsForeground")
+ } : null;
+ const enableMerge = AppOptions.get("enableMerge");
+ const enableSplitMerge = AppOptions.get("enableSplitMerge");
+ let altTextManager;
+ if (AppOptions.get("enableUpdatedAddImage")) {
+ altTextManager = appConfig.newAltTextDialog ? new NewAltTextManager(appConfig.newAltTextDialog, overlayManager, eventBus) : null;
+ } else {
+ altTextManager = appConfig.altTextDialog ? new AltTextManager(appConfig.altTextDialog, container, overlayManager, eventBus) : null;
+ }
+ if (appConfig.editorUndoBar) {
+ this.editorUndoBar = new EditorUndoBar(appConfig.editorUndoBar, eventBus);
+ }
+ const signatureManager = AppOptions.get("enableSignatureEditor") && appConfig.addSignatureDialog ? new SignatureManager(appConfig.addSignatureDialog, appConfig.editSignatureDialog, appConfig.annotationEditorParams?.editorSignatureAddSignature || null, overlayManager, l10n, externalServices.createSignatureStorage(eventBus, abortSignal), eventBus) : null;
+ const commentManager = AppOptions.get("enableComment") && appConfig.editCommentDialog ? new CommentManager(appConfig.editCommentDialog, {
+ learnMoreUrl: AppOptions.get("commentLearnMoreUrl"),
+ sidebar: appConfig.annotationEditorParams?.editorCommentsSidebar || null,
+ sidebarResizer: appConfig.annotationEditorParams?.editorCommentsSidebarResizer || null,
+ commentsList: appConfig.annotationEditorParams?.editorCommentsSidebarList || null,
+ commentCount: appConfig.annotationEditorParams?.editorCommentsSidebarCount || null,
+ sidebarTitle: appConfig.annotationEditorParams?.editorCommentsSidebarTitle || null,
+ closeButton: appConfig.annotationEditorParams?.editorCommentsSidebarCloseButton || null,
+ commentToolbarButton: appConfig.toolbar?.editorCommentButton || null
+ }, eventBus, linkService, overlayManager, l10n.getDirection() === "ltr", hasForcedColors, abortSignal) : null;
+ const maxCanvasPixels = AppOptions.get("maxCanvasPixels"),
+ maxCanvasDim = AppOptions.get("maxCanvasDim"),
+ capCanvasAreaFactor = AppOptions.get("capCanvasAreaFactor");
+ const pdfViewer = this.pdfViewer = new PDFViewer({
+ container,
+ viewer,
+ viewerAlert: appConfig.viewerAlert,
+ eventBus,
+ renderingQueue,
+ linkService,
+ downloadManager,
+ altTextManager,
+ commentManager,
+ signatureManager,
+ editorUndoBar: this.editorUndoBar,
+ findController,
+ scriptingManager: AppOptions.get("enableScripting") && pdfScriptingManager,
+ l10n,
+ textLayerMode: AppOptions.get("textLayerMode"),
+ annotationMode: AppOptions.get("annotationMode"),
+ annotationEditorMode,
+ annotationEditorHighlightColors: AppOptions.get("highlightEditorColors"),
+ enableHighlightFloatingButton: AppOptions.get("enableHighlightFloatingButton"),
+ enableUpdatedAddImage: AppOptions.get("enableUpdatedAddImage"),
+ enableNewAltTextWhenAddingImage: AppOptions.get("enableNewAltTextWhenAddingImage"),
+ imageResourcesPath: AppOptions.get("imageResourcesPath"),
+ enablePrintAutoRotate: AppOptions.get("enablePrintAutoRotate"),
+ maxCanvasPixels,
+ maxCanvasDim,
+ capCanvasAreaFactor,
+ enableDetailCanvas: AppOptions.get("enableDetailCanvas"),
+ enablePermissions: AppOptions.get("enablePermissions"),
+ enableOptimizedPartialRendering: AppOptions.get("enableOptimizedPartialRendering"),
+ enableSelectionRendering: AppOptions.get("enableSelectionRendering"),
+ imagesRightClickMinSize: AppOptions.get("imagesRightClickMinSize"),
+ pageColors,
+ mlManager,
+ abortSignal,
+ supportsPinchToZoom: this.supportsPinchToZoom,
+ enableAutoLinking: AppOptions.get("enableAutoLinking"),
+ minDurationToUpdateCanvas: AppOptions.get("minDurationToUpdateCanvas")
+ });
+ renderingQueue.setViewer(pdfViewer);
+ linkService.setViewer(pdfViewer);
+ pdfScriptingManager.setViewer(pdfViewer);
+ if (appConfig.viewsManager?.thumbnailsView) {
+ const {
+ viewsManager
+ } = appConfig;
+ this.pdfThumbnailViewer = new PDFThumbnailViewer({
+ container: viewsManager.thumbnailsView,
+ eventBus,
+ renderingQueue,
+ linkService,
+ maxCanvasPixels,
+ maxCanvasDim,
+ pageColors,
+ abortSignal,
+ enableSplitMerge,
+ enableMerge,
+ enableNewBadge: AppOptions.get("enableNewBadge"),
+ statusBar: viewsManager.viewsManagerStatusBar,
+ undoBar: viewsManager.viewsManagerUndoBar,
+ manageMenu: viewsManager.manageMenu,
+ waitingBar: viewsManager.viewsManagerWaitingBar,
+ addFileComponent: viewsManager.viewsManagerAddFile
+ });
+ renderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
+ }
+ if (!this.isViewerEmbedded && !AppOptions.get("disableHistory")) {
+ this.pdfHistory = new PDFHistory({
+ linkService,
+ eventBus
+ });
+ linkService.setHistory(this.pdfHistory);
+ }
+ if (!this.supportsIntegratedFind && appConfig.findBar) {
+ this.findBar = new PDFFindBar(appConfig.findBar, appConfig.principalContainer, eventBus);
+ }
+ if (appConfig.annotationEditorParams) {
+ if (annotationEditorMode !== AnnotationEditorType.DISABLE) {
+ const editorSignatureButton = appConfig.toolbar?.editorSignatureButton;
+ if (editorSignatureButton && AppOptions.get("enableSignatureEditor")) {
+ editorSignatureButton.parentElement.hidden = false;
+ }
+ const editorCommentButton = appConfig.toolbar?.editorCommentButton;
+ if (editorCommentButton && AppOptions.get("enableComment")) {
+ editorCommentButton.parentElement.hidden = false;
+ }
+ this.annotationEditorParams = new AnnotationEditorParams(appConfig.annotationEditorParams, eventBus);
+ } else {
+ for (const id of ["editorModeButtons", "editorModeSeparator"]) {
+ document.getElementById(id)?.classList.add("hidden");
+ }
+ }
+ }
+ if (mlManager && appConfig.secondaryToolbar?.imageAltTextSettingsButton) {
+ this.imageAltTextSettings = new ImageAltTextSettings(appConfig.altTextSettingsDialog, overlayManager, eventBus, mlManager);
+ }
+ if (appConfig.documentProperties) {
+ this.pdfDocumentProperties = new PDFDocumentProperties(appConfig.documentProperties, overlayManager, eventBus, l10n, () => this._docFilename, () => this._docTitle);
+ }
+ if (appConfig.secondaryToolbar?.cursorHandToolButton) {
+ this.pdfCursorTools = new PDFCursorTools({
+ container,
+ eventBus,
+ cursorToolOnLoad: AppOptions.get("cursorToolOnLoad")
+ });
+ }
+ if (appConfig.toolbar) {
+ this.toolbar = new Toolbar(appConfig.toolbar, eventBus, AppOptions.get("toolbarDensity"));
+ }
+ if (appConfig.secondaryToolbar) {
+ if (AppOptions.get("enableAltText") && this.imageAltTextSettings) {
+ appConfig.secondaryToolbar.imageAltTextSettingsButton?.classList.remove("hidden");
+ appConfig.secondaryToolbar.imageAltTextSettingsSeparator?.classList.remove("hidden");
+ }
+ this.secondaryToolbar = new SecondaryToolbar(appConfig.secondaryToolbar, eventBus);
+ }
+ if (this.supportsFullscreen && appConfig.secondaryToolbar?.presentationModeButton) {
+ this.pdfPresentationMode = new PDFPresentationMode({
+ container,
+ pdfViewer,
+ eventBus
+ });
+ }
+ if (appConfig.passwordOverlay) {
+ this.passwordPrompt = new PasswordPrompt(appConfig.passwordOverlay, overlayManager, this.isViewerEmbedded);
+ }
+ if (appConfig.viewsManager?.outlinesView) {
+ this.pdfOutlineViewer = new PDFOutlineViewer({
+ container: appConfig.viewsManager.outlinesView,
+ eventBus,
+ l10n,
+ linkService,
+ downloadManager
+ });
+ }
+ if (appConfig.viewsManager?.attachmentsView) {
+ this.pdfAttachmentViewer = new PDFAttachmentViewer({
+ container: appConfig.viewsManager.attachmentsView,
+ eventBus,
+ l10n,
+ downloadManager,
+ linkService
+ });
+ }
+ if (appConfig.viewsManager?.layersView) {
+ this.pdfLayerViewer = new PDFLayerViewer({
+ container: appConfig.viewsManager.layersView,
+ eventBus,
+ l10n
+ });
+ }
+ if (appConfig.viewsManager) {
+ this.viewsManager = new ViewsManager({
+ elements: appConfig.viewsManager,
+ eventBus,
+ l10n,
+ enableMerge,
+ enableSplitMerge,
+ globalAbortSignal: abortSignal
+ });
+ this.viewsManager.onToggled = this.forceRendering.bind(this);
+ this.viewsManager.onUpdateThumbnails = () => {
+ for (const pageView of pdfViewer.getCachedPageViews()) {
+ if (pageView.renderingState === RenderingStates.FINISHED) {
+ this.pdfThumbnailViewer.getThumbnail(pageView.id - 1)?.setImage(pageView);
+ }
+ }
+ this.pdfThumbnailViewer.scrollThumbnailIntoView(pdfViewer.currentPageNumber);
+ };
+ }
+ },
+ async run(config) {
+ await this.initialize(config);
+ const {
+ appConfig,
+ eventBus
+ } = this;
+ let file;
+ const queryString = document.location.search.substring(1);
+ const params = parseQueryString(queryString);
+ file = params.get("file") ?? AppOptions.get("defaultUrl");
+ file = URL.parse(file)?.href ?? file.replaceAll("#", "%23");
+ validateFileURL(file);
+ const fileInput = this._openFileInput = document.createElement("input");
+ fileInput.id = "fileInput";
+ fileInput.hidden = true;
+ fileInput.type = "file";
+ fileInput.value = null;
+ document.body.append(fileInput);
+ fileInput.addEventListener("change", function (evt) {
+ const {
+ files
+ } = evt.target;
+ if (!files?.length) {
+ return;
+ }
+ eventBus.dispatch("fileinputchange", {
+ source: this,
+ fileInput: evt.target
+ });
+ });
+ appConfig.mainContainer.addEventListener("dragover", function (evt) {
+ for (const item of evt.dataTransfer.items) {
+ if (item.type === "application/pdf") {
+ evt.dataTransfer.dropEffect = evt.dataTransfer.effectAllowed === "copy" ? "copy" : "move";
+ stopEvent(evt);
+ return;
+ }
+ }
+ });
+ appConfig.mainContainer.addEventListener("drop", function (evt) {
+ if (evt.dataTransfer.files?.[0].type !== "application/pdf") {
+ return;
+ }
+ stopEvent(evt);
+ eventBus.dispatch("fileinputchange", {
+ source: this,
+ fileInput: evt.dataTransfer
+ });
+ });
+ if (!AppOptions.get("supportsDocumentFonts")) {
+ AppOptions.set("disableFontFace", true);
+ this.l10n.get("pdfjs-web-fonts-disabled").then(msg => {
+ console.warn(msg);
+ });
+ }
+ const togglePrintingButtons = visible => {
+ appConfig.toolbar?.print?.classList.toggle("hidden", !visible);
+ appConfig.secondaryToolbar?.printButton.classList.toggle("hidden", !visible);
+ };
+ if (!this.supportsPrinting) {
+ togglePrintingButtons(false);
+ } else {
+ eventBus.on("printingallowed", ({
+ isAllowed
+ }) => togglePrintingButtons(isAllowed), internalOpt);
+ }
+ if (!this.supportsFullscreen) {
+ appConfig.secondaryToolbar?.presentationModeButton.classList.add("hidden");
+ }
+ if (this.supportsIntegratedFind) {
+ appConfig.findBar?.toggleButton?.classList.add("hidden");
+ }
+ if (file) {
+ this.open({
+ url: file
+ });
+ } else {
+ this._hideViewBookmark();
+ }
+ },
+ get externalServices() {
+ return shadow(this, "externalServices", new ExternalServices());
+ },
+ get initialized() {
+ return this._initializedCapability.settled;
+ },
+ get initializedPromise() {
+ return this._initializedCapability.promise;
+ },
+ updateZoom(steps, scaleFactor, origin, pan = null) {
+ if (this.pdfViewer.isInPresentationMode) {
+ return;
+ }
+ this.pdfViewer.updateScale({
+ drawingDelay: AppOptions.get("defaultZoomDelay"),
+ steps,
+ scaleFactor,
+ origin,
+ pan
+ });
+ },
+ zoomIn() {
+ this.updateZoom(1);
+ },
+ zoomOut() {
+ this.updateZoom(-1);
+ },
+ zoomReset() {
+ if (this.pdfViewer.isInPresentationMode) {
+ return;
+ }
+ this.pdfViewer.currentScaleValue = (/* inlined export .DEFAULT_SCALE_VALUE */"auto");
+ },
+ touchPinchCallback(origin, prevDistance, distance, panX, panY) {
+ const pan = [panX, panY];
+ if (this.supportsPinchToZoom) {
+ const newScaleFactor = this._accumulateFactor(this.pdfViewer.currentScale, distance / prevDistance, "_touchUnusedFactor");
+ this.updateZoom(null, newScaleFactor, origin, pan);
+ } else {
+ const PIXELS_PER_LINE_SCALE = 30;
+ const ticks = this._accumulateTicks((distance - prevDistance) / PIXELS_PER_LINE_SCALE, "_touchUnusedTicks");
+ this.updateZoom(ticks, null, origin, pan);
+ }
+ },
+ touchPanCallback(dx, dy) {
+ const {
+ pdfViewer
+ } = this;
+ if (!this.pdfDocument || pdfViewer.isInPresentationMode) {
+ return;
+ }
+ pdfViewer.panBy(dx, dy);
+ },
+ touchPinchEndCallback() {
+ this._touchUnusedTicks = 0;
+ this._touchUnusedFactor = 1;
+ },
+ get pagesCount() {
+ return this.pdfDocument ? this.pdfDocument.numPages : 0;
+ },
+ get page() {
+ return this.pdfViewer.currentPageNumber;
+ },
+ set page(val) {
+ this.pdfViewer.currentPageNumber = val;
+ },
+ get supportsPrinting() {
+ return shadow(this, "supportsPrinting", AppOptions.get("supportsPrinting") && PDFPrintServiceFactory.supportsPrinting);
+ },
+ get supportsFullscreen() {
+ return shadow(this, "supportsFullscreen", document.fullscreenEnabled);
+ },
+ get supportsPinchToZoom() {
+ return shadow(this, "supportsPinchToZoom", AppOptions.get("supportsPinchToZoom"));
+ },
+ get supportsIntegratedFind() {
+ return shadow(this, "supportsIntegratedFind", AppOptions.get("supportsIntegratedFind"));
+ },
+ get loadingBar() {
+ const barElement = document.getElementById("loadingBar");
+ const bar = barElement ? new ProgressBar(barElement) : null;
+ return shadow(this, "loadingBar", bar);
+ },
+ get supportsMouseWheelZoomCtrlKey() {
+ return shadow(this, "supportsMouseWheelZoomCtrlKey", AppOptions.get("supportsMouseWheelZoomCtrlKey"));
+ },
+ get supportsMouseWheelZoomMetaKey() {
+ return shadow(this, "supportsMouseWheelZoomMetaKey", AppOptions.get("supportsMouseWheelZoomMetaKey"));
+ },
+ get supportsCaretBrowsingMode() {
+ return AppOptions.get("supportsCaretBrowsingMode");
+ },
+ moveCaret(isUp, select) {
+ this._caretBrowsing ||= new CaretBrowsingMode(this._globalAbortController.signal, this.appConfig.mainContainer, this.appConfig.viewerContainer, this.appConfig.toolbar?.container);
+ this._caretBrowsing.moveCaret(isUp, select);
+ },
+ setTitleUsingUrl(url = "", downloadUrl = null) {
+ this.url = url;
+ this.baseUrl = updateUrlHash(url, "", true);
+ if (downloadUrl) {
+ this._downloadUrl = downloadUrl === url ? this.baseUrl : updateUrlHash(downloadUrl, "", true);
+ }
+ if (isDataScheme(url)) {
+ this._hideViewBookmark();
+ }
+ let title = getPdfFilenameFromUrl(url, "");
+ if (!title) {
+ try {
+ title = decodeURIComponent(getFilenameFromUrl(url));
+ } catch {}
+ }
+ this.setTitle(title || url);
+ },
+ setTitle(title = this._title) {
+ this._title = title;
+ if (this.isViewerEmbedded) {
+ return;
+ }
+ const hasChangesIndicator = this._hasChanges() && !this.pdfRenderingQueue.printing;
+ document.title = `${hasChangesIndicator ? "* " : ""}${title}`;
+ },
+ get _docFilename() {
+ return this._contentDispositionFilename || getPdfFilenameFromUrl(this.url);
+ },
+ get _docTitle() {
+ const {
+ documentInfo,
+ metadata
+ } = this;
+ const title = metadata?.get("dc:title");
+ if (title) {
+ if (title !== "Untitled" && !/[\uFFF0-\uFFFF]/.test(title)) {
+ return title;
+ }
+ }
+ return documentInfo.Title;
+ },
+ _hideViewBookmark() {
+ const {
+ secondaryToolbar
+ } = this.appConfig;
+ secondaryToolbar?.viewBookmarkButton.classList.add("hidden");
+ if (secondaryToolbar?.presentationModeButton.classList.contains("hidden")) {
+ document.getElementById("viewBookmarkSeparator")?.classList.add("hidden");
+ }
+ },
+ async close() {
+ this._unblockDocumentLoadEvent();
+ this._hideViewBookmark();
+ if (!this.pdfLoadingTask) {
+ return;
+ }
+ if (this._hasChanges() && this._annotationStorageModified) {
+ try {
+ await this.downloadOrSave();
+ } catch {}
+ }
+ const promises = [];
+ promises.push(this.pdfLoadingTask.destroy());
+ this.pdfLoadingTask = null;
+ if (this.pdfDocument) {
+ this.pdfDocument = null;
+ this.pdfThumbnailViewer?.setDocument(null);
+ this.pdfViewer.setDocument(null);
+ this.pdfLinkService.setDocument(null);
+ this.pdfDocumentProperties?.setDocument(null);
+ this.signaturePropertiesManager?.setDocument(null);
+ }
+ this.pdfLinkService.externalLinkEnabled = true;
+ this.store = null;
+ this.isInitialViewSet = false;
+ this.url = "";
+ this.baseUrl = "";
+ this._downloadUrl = "";
+ this.documentInfo = null;
+ this.metadata = null;
+ this._contentDispositionFilename = null;
+ this._contentLength = null;
+ this._saveInProgress = false;
+ this._hasAnnotationEditors = false;
+ promises.push(this.pdfScriptingManager.destroyPromise, this.passwordPrompt.close());
+ this.setTitle();
+ this.viewsManager?.reset();
+ this.pdfOutlineViewer?.reset();
+ this.pdfAttachmentViewer?.reset();
+ this.pdfLayerViewer?.reset();
+ this.pdfHistory?.reset();
+ this.findBar?.reset();
+ this.toolbar?.reset();
+ this.secondaryToolbar?.reset();
+ this._PDFBug?.cleanup();
+ await Promise.all(promises);
+ },
+ async open(args) {
+ if (this.pdfLoadingTask) {
+ await this.close();
+ }
+ const workerParams = AppOptions.getAll(OptionKind.WORKER);
+ Object.assign(GlobalWorkerOptions, workerParams);
+ if (args.data && isPdfFile(args.filename)) {
+ this._contentDispositionFilename = args.filename;
+ } else if (args.url) {
+ this.setTitleUsingUrl(args.originalUrl || args.url, args.url);
+ }
+ const apiParams = AppOptions.getAll(OptionKind.API);
+ const loadingTask = getDocument({
+ ...apiParams,
+ ...args
+ });
+ this.pdfLoadingTask = loadingTask;
+ loadingTask.onPassword = (updateCallback, reason) => {
+ if (this.isViewerEmbedded) {
+ this._unblockDocumentLoadEvent();
+ }
+ this.pdfLinkService.externalLinkEnabled = false;
+ this.passwordPrompt.setUpdateCallback(updateCallback, reason);
+ this.passwordPrompt.open();
+ };
+ loadingTask.onProgress = evt => this.progress(evt.percent);
+ return loadingTask.promise.then(pdfDocument => {
+ this.load(pdfDocument);
+ }, reason => {
+ if (loadingTask !== this.pdfLoadingTask) {
+ return undefined;
+ }
+ if (this.loadingBar) {
+ this.loadingBar.percent ||= 0;
+ }
+ let key = "pdfjs-loading-error";
+ if (reason instanceof InvalidPDFException) {
+ key = "pdfjs-invalid-file-error";
+ } else if (reason instanceof ResponseException) {
+ key = reason.missing ? "pdfjs-missing-file-error" : "pdfjs-unexpected-response-error";
+ }
+ return this._documentError(key, {
+ message: reason.message
+ }).then(() => {
+ throw reason;
+ });
+ });
+ },
+ async download() {
+ if (!this.downloadManager) {
+ return;
+ }
+ let data;
+ try {
+ data = await (this.pdfDocument ? this.pdfDocument.getData() : this.pdfLoadingTask.getData());
+ } catch {}
+ this.downloadManager.download(data, this._downloadUrl, this._docFilename);
+ },
+ async save() {
+ if (!this.downloadManager) {
+ return;
+ }
+ if (this._saveInProgress) {
+ return;
+ }
+ this._saveInProgress = true;
+ await this.pdfScriptingManager.dispatchWillSave();
+ try {
+ const data = await this.pdfDocument.saveDocument();
+ this.downloadManager.download(data, this._downloadUrl, this._docFilename);
+ } catch (reason) {
+ console.error(`Error when saving the document:`, reason);
+ await this.download();
+ } finally {
+ await this.pdfScriptingManager.dispatchDidSave();
+ this._saveInProgress = false;
+ }
+ const editorStats = this.pdfDocument?.annotationStorage.editorStats;
+ if (editorStats) {
+ this.externalServices.reportTelemetry({
+ type: "editing",
+ data: {
+ type: "save",
+ stats: editorStats
+ }
+ });
+ }
+ },
+ async downloadOrSave() {
+ if (!this.downloadManager) {
+ return;
+ }
+ this.pdfViewer._layerProperties.annotationEditorUIManager?.endCurrentEditing();
+ const {
+ classList
+ } = this.appConfig.appContainer;
+ classList.add("wait");
+ if (this.pdfThumbnailViewer?.hasStructuralChanges()) {
+ this.externalServices.reportTelemetry({
+ type: "pageOrganization",
+ data: {
+ action: "save"
+ }
+ });
+ await this.onSavePages({
+ data: this.pdfThumbnailViewer.getStructuralChanges()
+ });
+ } else {
+ await (this.pdfDocument?.annotationStorage.size > 0 ? this.save() : this.download());
+ }
+ delete this._mergedDocumentNeedsSaving;
+ this.setTitle();
+ classList.remove("wait");
+ },
+ async _documentError(key, moreInfo = null) {
+ this._unblockDocumentLoadEvent();
+ const message = await this._otherError(key || "pdfjs-loading-error", moreInfo);
+ this.eventBus.dispatch("documenterror", {
+ source: this,
+ message,
+ reason: moreInfo?.message ?? null
+ });
+ },
+ async _otherError(key, moreInfo = null) {
+ const message = await this.l10n.get(key);
+ const moreInfoText = [`PDF.js v${version || "?"} (build: ${build || "?"})`];
+ if (moreInfo) {
+ moreInfoText.push(`Message: ${moreInfo.message}`);
+ if (moreInfo.stack) {
+ moreInfoText.push(`Stack: ${moreInfo.stack}`);
+ } else {
+ if (moreInfo.filename) {
+ moreInfoText.push(`File: ${moreInfo.filename}`);
+ }
+ if (moreInfo.lineNumber) {
+ moreInfoText.push(`Line: ${moreInfo.lineNumber}`);
+ }
+ }
+ }
+ console.error(`${message}\n\n${moreInfoText.join("\n")}`);
+ return message;
+ },
+ progress(percent) {
+ if (!this.loadingBar || percent <= this.loadingBar.percent) {
+ return;
+ }
+ this.loadingBar.percent = percent;
+ if (this.pdfDocument?.loadingParams.disableAutoFetch ?? AppOptions.get("disableAutoFetch")) {
+ this.loadingBar.setDisableAutoFetch();
+ }
+ },
+ load(pdfDocument) {
+ this.pdfDocument = pdfDocument;
+ this._printPermissionPromise = new Promise(resolve => {
+ this.eventBus.on("printingallowed", ({
+ isAllowed
+ }) => {
+ resolve(isAllowed);
+ }, {
+ once: true,
+ ...internalOpt
+ });
+ });
+ pdfDocument.getDownloadInfo().then(({
+ length
+ }) => {
+ this._contentLength = length;
+ this.loadingBar?.hide();
+ firstPagePromise.then(() => {
+ this.eventBus.dispatch("documentloaded", {
+ source: this
+ });
+ });
+ });
+ const pageLayoutPromise = pdfDocument.getPageLayout().catch(() => {});
+ const pageModePromise = pdfDocument.getPageMode().catch(() => {});
+ const openActionPromise = pdfDocument.getOpenAction().catch(() => {});
+ this.toolbar?.setPagesCount(pdfDocument.numPages, false);
+ this.secondaryToolbar?.setPagesCount(pdfDocument.numPages);
+ this.pdfLinkService.setDocument(pdfDocument);
+ this.pdfDocumentProperties?.setDocument(pdfDocument);
+ const pdfViewer = this.pdfViewer;
+ pdfViewer.setDocument(pdfDocument);
+ const {
+ firstPagePromise,
+ onePageRendered,
+ pagesPromise
+ } = pdfViewer;
+ this.pdfThumbnailViewer?.setDocument(pdfDocument);
+ const storedPromise = (this.store = new ViewHistory(pdfDocument.fingerprints[0])).getMultiple({
+ page: null,
+ zoom: (/* inlined export .DEFAULT_SCALE_VALUE */"auto"),
+ scrollLeft: "0",
+ scrollTop: "0",
+ rotation: null,
+ sidebarView: SidebarView.UNKNOWN,
+ scrollMode: ScrollMode.UNKNOWN,
+ spreadMode: SpreadMode.UNKNOWN
+ }).catch(() => {});
+ firstPagePromise.then(pdfPage => {
+ this.loadingBar?.setWidth(this.appConfig.viewerContainer);
+ this._initializeAnnotationStorageCallbacks(pdfDocument);
+ Promise.all([animationStarted, storedPromise, pageLayoutPromise, pageModePromise, openActionPromise]).then(async ([timeStamp, stored, pageLayout, pageMode, openAction]) => {
+ const viewOnLoad = AppOptions.get("viewOnLoad");
+ this._initializePdfHistory({
+ fingerprint: pdfDocument.fingerprints[0],
+ viewOnLoad,
+ initialDest: openAction?.get("dest")
+ });
+ const initialBookmark = this.initialBookmark;
+ const zoom = AppOptions.get("defaultZoomValue");
+ let hash = zoom ? `zoom=${zoom}` : null;
+ let rotation = null;
+ let sidebarView = AppOptions.get("sidebarViewOnLoad");
+ let scrollMode = AppOptions.get("scrollModeOnLoad");
+ let spreadMode = AppOptions.get("spreadModeOnLoad");
+ if (stored?.page && viewOnLoad !== ViewOnLoad.INITIAL) {
+ hash = `page=${stored.page}&zoom=${zoom || stored.zoom},` + `${stored.scrollLeft},${stored.scrollTop}`;
+ rotation = parseInt(stored.rotation, 10);
+ if (sidebarView === SidebarView.UNKNOWN) {
+ sidebarView = stored.sidebarView | 0;
+ }
+ if (scrollMode === ScrollMode.UNKNOWN) {
+ scrollMode = stored.scrollMode | 0;
+ }
+ if (spreadMode === SpreadMode.UNKNOWN) {
+ spreadMode = stored.spreadMode | 0;
+ }
+ }
+ if (pageMode && sidebarView === SidebarView.UNKNOWN) {
+ sidebarView = apiPageModeToSidebarView(pageMode);
+ }
+ if (pageLayout && scrollMode === ScrollMode.UNKNOWN && spreadMode === SpreadMode.UNKNOWN) {
+ const modes = apiPageLayoutToViewerModes(pageLayout);
+ spreadMode = modes.spreadMode;
+ }
+ this.setInitialView(hash, {
+ rotation,
+ sidebarView,
+ scrollMode,
+ spreadMode
+ });
+ this.eventBus.dispatch("documentinit", {
+ source: this
+ });
+ await Promise.race([pagesPromise, new Promise(resolve => {
+ setTimeout(resolve, FORCE_PAGES_LOADED_TIMEOUT);
+ })]);
+ if (!initialBookmark && !hash) {
+ return;
+ }
+ if (pdfViewer.hasEqualPageSizes) {
+ return;
+ }
+ this.initialBookmark = initialBookmark;
+ pdfViewer.currentScaleValue = pdfViewer.currentScaleValue;
+ this.setInitialView(hash);
+ }).catch(() => {
+ this.setInitialView();
+ }).then(function () {
+ pdfViewer.update();
+ });
+ });
+ pagesPromise.then(() => {
+ this._unblockDocumentLoadEvent();
+ this._initializeAutoPrint(pdfDocument, openActionPromise);
+ }, reason => {
+ this._documentError("pdfjs-loading-error", {
+ message: reason.message
+ });
+ });
+ onePageRendered.then(data => {
+ this.externalServices.reportTelemetry({
+ type: "pageInfo",
+ timestamp: data.timestamp
+ });
+ if (this.pdfOutlineViewer) {
+ pdfDocument.getOutline().then(outline => {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ this.pdfOutlineViewer.render({
+ outline,
+ pdfDocument
+ });
+ });
+ }
+ if (this.pdfAttachmentViewer) {
+ pdfDocument.getAttachments().then(attachments => {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ this.pdfAttachmentViewer.render({
+ attachments
+ });
+ });
+ }
+ if (this.pdfLayerViewer) {
+ pdfViewer.optionalContentConfigPromise.then(optionalContentConfig => {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ this.pdfLayerViewer.render({
+ optionalContentConfig,
+ pdfDocument
+ });
+ });
+ }
+ });
+ this._initializePageLabels(pdfDocument);
+ this._initializeMetadata(pdfDocument);
+ },
+ async _scriptingDocProperties(pdfDocument) {
+ if (!this.documentInfo) {
+ await new Promise(resolve => {
+ this.eventBus.on("metadataloaded", resolve, {
+ once: true,
+ ...internalOpt
+ });
+ });
+ if (pdfDocument !== this.pdfDocument) {
+ return null;
+ }
+ }
+ if (!this._contentLength) {
+ await new Promise(resolve => {
+ this.eventBus.on("documentloaded", resolve, {
+ once: true,
+ ...internalOpt
+ });
+ });
+ if (pdfDocument !== this.pdfDocument) {
+ return null;
+ }
+ }
+ return {
+ ...this.documentInfo,
+ baseURL: this.baseUrl,
+ filesize: this._contentLength,
+ filename: this._docFilename,
+ metadata: this.metadata?.getRaw(),
+ authors: this.metadata?.get("dc:creator"),
+ numPages: this.pagesCount,
+ URL: this.url
+ };
+ },
+ async _initializeAutoPrint(pdfDocument, openActionPromise) {
+ const [openAction, jsActions] = await Promise.all([openActionPromise, this.pdfViewer.enableScripting ? null : pdfDocument.getJSActions()]);
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ let triggerAutoPrint = openAction?.get("action") === "Print";
+ if (jsActions) {
+ console.warn("Warning: JavaScript support is not enabled");
+ for (const [name, actions] of jsActions) {
+ if (triggerAutoPrint) {
+ break;
+ }
+ switch (name) {
+ case "WillClose":
+ case "WillSave":
+ case "DidSave":
+ case "WillPrint":
+ case "DidPrint":
+ continue;
+ }
+ triggerAutoPrint = actions.some(js => AutoPrintRegExp.test(js));
+ }
+ }
+ if (triggerAutoPrint) {
+ this.triggerPrinting();
+ }
+ },
+ async _initializeMetadata(pdfDocument) {
+ const {
+ info,
+ metadata,
+ contentDispositionFilename,
+ contentLength,
+ hasStructTree
+ } = await pdfDocument.getMetadata();
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ this.externalServices.reportTelemetry({
+ type: "taggedPDF",
+ data: hasStructTree
+ });
+ this.documentInfo = info;
+ this.metadata = metadata;
+ this._contentDispositionFilename ??= contentDispositionFilename;
+ this._contentLength ??= contentLength;
+ console.log(`PDF ${pdfDocument.fingerprints[0]} [${info.PDFFormatVersion} ` + `${(metadata?.get("pdf:producer") || info.Producer || "-").trim()} / ` + `${(metadata?.get("xmp:creatortool") || info.Creator || "-").trim()}` + `] (PDF.js: ${version || "?"} [${build || "?"}])`);
+ const pdfTitle = this._docTitle;
+ if (pdfTitle) {
+ this.setTitle(`${pdfTitle} - ${this._contentDispositionFilename || this._title}`);
+ } else if (this._contentDispositionFilename) {
+ this.setTitle(this._contentDispositionFilename);
+ }
+ if (info.IsXFAPresent && !info.IsAcroFormPresent && !pdfDocument.isPureXfa) {
+ if (pdfDocument.loadingParams.enableXfa) {
+ console.warn("Warning: XFA Foreground documents are not supported");
+ } else {
+ console.warn("Warning: XFA support is not enabled");
+ }
+ } else if ((info.IsAcroFormPresent || info.IsXFAPresent) && !this.pdfViewer.renderForms) {
+ console.warn("Warning: Interactive form support is not enabled");
+ }
+ if (info.IsSignaturesPresent) {
+ const success = this._maybeInitSignatureProperties(pdfDocument);
+ if (!success) {
+ console.warn("Warning: Digital signatures validation is not supported");
+ }
+ }
+ this.eventBus.dispatch("metadataloaded", {
+ source: this
+ });
+ },
+ _maybeInitSignatureProperties(pdfDocument) {
+ if (!AppOptions.get("enableSignatureVerification")) {
+ return false;
+ }
+ const verifier = this.externalServices.createSignatureVerifier();
+ if (!verifier) {
+ return false;
+ }
+ if (pdfDocument !== this.pdfDocument) {
+ return true;
+ }
+ this.signaturePropertiesManager ??= new SignaturePropertiesManager({
+ appConfig: this.appConfig.toolbar,
+ verifier,
+ eventBus: this.eventBus
+ });
+ this.signaturePropertiesManager.setDocument(pdfDocument);
+ return true;
+ },
+ async _initializePageLabels(pdfDocument) {
+ const labels = await pdfDocument.getPageLabels();
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ if (!labels || AppOptions.get("disablePageLabels")) {
+ return;
+ }
+ const numLabels = labels.length;
+ let standardLabels = 0,
+ emptyLabels = 0;
+ for (let i = 0; i < numLabels; i++) {
+ const label = labels[i];
+ if (label === (i + 1).toString()) {
+ standardLabels++;
+ } else if (label === "") {
+ emptyLabels++;
+ } else {
+ break;
+ }
+ }
+ if (standardLabels >= numLabels || emptyLabels >= numLabels) {
+ return;
+ }
+ const {
+ pdfViewer,
+ pdfThumbnailViewer,
+ toolbar
+ } = this;
+ pdfViewer.setPageLabels(labels);
+ pdfThumbnailViewer?.setPageLabels(labels);
+ toolbar?.setPagesCount(numLabels, true);
+ toolbar?.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);
+ },
+ _initializePdfHistory({
+ fingerprint,
+ viewOnLoad,
+ initialDest = null
+ }) {
+ if (!this.pdfHistory) {
+ return;
+ }
+ this.pdfHistory.initialize({
+ fingerprint,
+ resetHistory: viewOnLoad === ViewOnLoad.INITIAL || !!this._mergedDocumentNeedsSaving,
+ updateUrl: AppOptions.get("historyUpdateUrl")
+ });
+ if (this.pdfHistory.initialBookmark) {
+ this.initialBookmark = this.pdfHistory.initialBookmark;
+ this.initialRotation = this.pdfHistory.initialRotation;
+ }
+ if (initialDest && !this.initialBookmark && viewOnLoad === ViewOnLoad.UNKNOWN) {
+ this.initialBookmark = JSON.stringify(initialDest);
+ this.pdfHistory.push({
+ explicitDest: initialDest,
+ pageNumber: null
+ });
+ }
+ },
+ _hasChanges() {
+ return this.pdfDocument?.annotationStorage.size > 0 || this.pdfThumbnailViewer?.hasStructuralChanges() || this._mergedDocumentNeedsSaving === true;
+ },
+ _initializeAnnotationStorageCallbacks(pdfDocument) {
+ if (pdfDocument !== this.pdfDocument) {
+ return;
+ }
+ const {
+ annotationStorage
+ } = pdfDocument;
+ annotationStorage.onSetModified = () => {
+ this._annotationStorageModified = true;
+ };
+ annotationStorage.onResetModified = () => {
+ delete this._annotationStorageModified;
+ };
+ annotationStorage.onAnnotationEditor = typeStr => {
+ this._hasAnnotationEditors = !!typeStr;
+ this.setTitle();
+ };
+ },
+ setInitialView(storedHash, {
+ rotation,
+ sidebarView,
+ scrollMode,
+ spreadMode
+ } = {}) {
+ const setRotation = angle => {
+ if (isValidRotation(angle)) {
+ this.pdfViewer.pagesRotation = angle;
+ }
+ };
+ const setViewerModes = (scroll, spread) => {
+ if (isValidScrollMode(scroll)) {
+ this.pdfViewer.scrollMode = scroll;
+ }
+ if (isValidSpreadMode(spread)) {
+ this.pdfViewer.spreadMode = spread;
+ }
+ };
+ this.isInitialViewSet = true;
+ this.viewsManager?.setInitialView(sidebarView);
+ setViewerModes(scrollMode, spreadMode);
+ if (this.initialBookmark) {
+ setRotation(this.initialRotation);
+ delete this.initialRotation;
+ this.pdfLinkService.setHash(this.initialBookmark);
+ this.initialBookmark = null;
+ } else if (storedHash) {
+ setRotation(rotation);
+ this.pdfLinkService.setHash(storedHash);
+ }
+ this.toolbar?.setPageNumber(this.pdfViewer.currentPageNumber, this.pdfViewer.currentPageLabel);
+ this.secondaryToolbar?.setPageNumber(this.pdfViewer.currentPageNumber);
+ this.pdfViewer.currentScaleValue ||= (/* inlined export .DEFAULT_SCALE_VALUE */"auto");
+ },
+ _cleanup() {
+ if (!this.pdfDocument) {
+ return;
+ }
+ this.pdfViewer.cleanup();
+ this.pdfThumbnailViewer?.cleanup();
+ this.pdfDocument.cleanup(AppOptions.get("fontExtraProperties"));
+ },
+ forceRendering() {
+ this.pdfRenderingQueue.printing = !!this.printService;
+ this.pdfRenderingQueue.isThumbnailViewEnabled = this.viewsManager?.visibleView === SidebarView.THUMBS;
+ this.pdfRenderingQueue.renderHighestPriority();
+ },
+ beforePrint() {
+ this._printAnnotationStoragePromise = this.pdfScriptingManager.dispatchWillPrint().catch(() => {}).then(() => this.pdfDocument?.annotationStorage.print);
+ if (this.printService) {
+ return;
+ }
+ if (!this.supportsPrinting || !this.pdfViewer.printingAllowed) {
+ this._otherError("pdfjs-printing-not-supported");
+ return;
+ }
+ if (!this.pdfViewer.pageViewsReady) {
+ this.l10n.get("pdfjs-printing-not-ready").then(msg => {
+ window.alert(msg);
+ });
+ return;
+ }
+ this.printService = PDFPrintServiceFactory.createPrintService({
+ pdfDocument: this.pdfDocument,
+ pagesOverview: this.pdfViewer.getPagesOverview(),
+ printContainer: this.appConfig.printContainer,
+ printResolution: AppOptions.get("printResolution"),
+ printAnnotationStoragePromise: this._printAnnotationStoragePromise
+ });
+ this.forceRendering();
+ this.setTitle();
+ this.printService.layout();
+ if (this._hasAnnotationEditors) {
+ this.externalServices.reportTelemetry({
+ type: "editing",
+ data: {
+ type: "print",
+ stats: this.pdfDocument?.annotationStorage.editorStats
+ }
+ });
+ }
+ },
+ afterPrint() {
+ if (this._printAnnotationStoragePromise) {
+ this._printAnnotationStoragePromise.then(() => {
+ this.pdfScriptingManager.dispatchDidPrint();
+ });
+ this._printAnnotationStoragePromise = null;
+ }
+ if (this.printService) {
+ this.printService.destroy();
+ this.printService = null;
+ this.pdfDocument?.annotationStorage.resetModified();
+ }
+ this.forceRendering();
+ this.setTitle();
+ },
+ rotatePages(delta) {
+ this.pdfViewer.pagesRotation += delta;
+ },
+ requestPresentationMode() {
+ this.pdfPresentationMode?.request();
+ },
+ async triggerPrinting() {
+ if (this.supportsPrinting && (await this._printPermissionPromise)) {
+ window.print();
+ }
+ },
+ bindEvents() {
+ if (this._eventBusAC) {
+ return;
+ }
+ const ac = this._eventBusAC = new AbortController();
+ const opts = {
+ signal: ac.signal,
+ ...internalOpt
+ };
+ const {
+ eventBus,
+ externalServices,
+ pdfDocumentProperties,
+ pdfViewer,
+ preferences
+ } = this;
+ eventBus.on("resize", onResize.bind(this), opts);
+ eventBus.on("hashchange", onHashchange.bind(this), opts);
+ eventBus.on("beforeprint", this.beforePrint.bind(this), opts);
+ eventBus.on("afterprint", this.afterPrint.bind(this), opts);
+ eventBus.on("pagerender", onPageRender.bind(this), opts);
+ eventBus.on("pagerendered", onPageRendered.bind(this), opts);
+ eventBus.on("updateviewarea", onUpdateViewarea.bind(this), opts);
+ eventBus.on("pagechanging", onPageChanging.bind(this), opts);
+ eventBus.on("scalechanging", onScaleChanging.bind(this), opts);
+ eventBus.on("rotationchanging", onRotationChanging.bind(this), opts);
+ eventBus.on("sidebarviewchanged", onSidebarViewChanged.bind(this), opts);
+ eventBus.on("pagemode", onPageMode.bind(this), opts);
+ eventBus.on("namedaction", onNamedAction.bind(this), opts);
+ eventBus.on("presentationmodechanged", evt => pdfViewer.presentationModeState = evt.state, opts);
+ eventBus.on("presentationmode", this.requestPresentationMode.bind(this), opts);
+ eventBus.on("switchannotationeditormode", evt => pdfViewer.annotationEditorMode = evt, opts);
+ eventBus.on("print", this.triggerPrinting.bind(this), opts);
+ eventBus.on("download", this.downloadOrSave.bind(this), opts);
+ eventBus.on("firstpage", () => this.page = 1, opts);
+ eventBus.on("lastpage", () => this.page = this.pagesCount, opts);
+ eventBus.on("nextpage", () => pdfViewer.nextPage(), opts);
+ eventBus.on("previouspage", () => pdfViewer.previousPage(), opts);
+ eventBus.on("zoomin", this.zoomIn.bind(this), opts);
+ eventBus.on("zoomout", this.zoomOut.bind(this), opts);
+ eventBus.on("zoomreset", this.zoomReset.bind(this), opts);
+ eventBus.on("pagenumberchanged", onPageNumberChanged.bind(this), opts);
+ eventBus.on("scalechanged", evt => pdfViewer.currentScaleValue = evt.value, opts);
+ eventBus.on("rotatecw", this.rotatePages.bind(this, 90), opts);
+ eventBus.on("rotateccw", this.rotatePages.bind(this, -90), opts);
+ eventBus.on("optionalcontentconfig", evt => pdfViewer.optionalContentConfigPromise = evt.promise, opts);
+ eventBus.on("switchscrollmode", evt => pdfViewer.scrollMode = evt.mode, opts);
+ eventBus.on("scrollmodechanged", onViewerModesChanged.bind(this, "scrollMode"), opts);
+ eventBus.on("switchspreadmode", evt => pdfViewer.spreadMode = evt.mode, opts);
+ eventBus.on("spreadmodechanged", onViewerModesChanged.bind(this, "spreadMode"), opts);
+ eventBus.on("imagealttextsettings", onImageAltTextSettings.bind(this), opts);
+ eventBus.on("documentproperties", () => pdfDocumentProperties?.open(), opts);
+ eventBus.on("findfromurlhash", onFindFromUrlHash.bind(this), opts);
+ eventBus.on("updatefindmatchescount", onUpdateFindMatchesCount.bind(this), opts);
+ eventBus.on("updatefindcontrolstate", onUpdateFindControlState.bind(this), opts);
+ eventBus.on("fileinputchange", onFileInputChange.bind(this), opts);
+ eventBus.on("openfile", onOpenFile.bind(this), opts);
+ eventBus.on("pagesedited", this.onPagesEdited.bind(this), opts);
+ eventBus.on("saveextractedpages", this.onSavePages.bind(this), opts);
+ eventBus.on("saveandload", this.onSaveAndLoad.bind(this), opts);
+ },
+ bindWindowEvents() {
+ if (this._windowAC) {
+ return;
+ }
+ this._windowAC = new AbortController();
+ const {
+ eventBus,
+ appConfig: {
+ mainContainer
+ },
+ pdfViewer,
+ _windowAC: {
+ signal
+ }
+ } = this;
+ this._touchManager = new TouchManager({
+ container: window,
+ isPinchingDisabled: () => pdfViewer.isInPresentationMode,
+ isPinchingStopped: () => this.overlayManager?.active,
+ onPinching: this.touchPinchCallback.bind(this),
+ onPinchEnd: this.touchPinchEndCallback.bind(this),
+ onPanning: this.touchPanCallback.bind(this),
+ signal
+ });
+ function addWindowResolutionChange(evt = null) {
+ if (evt) {
+ pdfViewer.refresh();
+ }
+ const mediaQueryList = window.matchMedia(`(resolution: ${OutputScale.pixelRatio}dppx)`);
+ mediaQueryList.addEventListener("change", addWindowResolutionChange, {
+ once: true,
+ signal
+ });
+ }
+ addWindowResolutionChange();
+ window.addEventListener("wheel", onWheel.bind(this), {
+ passive: false,
+ signal
+ });
+ window.addEventListener("click", onClick.bind(this), {
+ signal
+ });
+ window.addEventListener("keydown", onKeyDown.bind(this), {
+ signal
+ });
+ window.addEventListener("keyup", onKeyUp.bind(this), {
+ signal
+ });
+ window.addEventListener("resize", () => eventBus.dispatch("resize", {
+ source: window
+ }), {
+ signal
+ });
+ window.addEventListener("hashchange", () => {
+ eventBus.dispatch("hashchange", {
+ source: window,
+ hash: document.location.hash.substring(1)
+ });
+ }, {
+ signal
+ });
+ window.addEventListener("beforeprint", () => eventBus.dispatch("beforeprint", {
+ source: window
+ }), {
+ signal
+ });
+ window.addEventListener("afterprint", () => eventBus.dispatch("afterprint", {
+ source: window
+ }), {
+ signal
+ });
+ window.addEventListener("updatefromsandbox", evt => {
+ eventBus.dispatch("updatefromsandbox", {
+ source: window,
+ detail: evt.detail
+ });
+ }, {
+ signal
+ });
+ window.addEventListener("beforeunload", onBeforeUnload.bind(this), {
+ signal
+ });
+ if (!("onscrollend" in document.documentElement)) {
+ return;
+ }
+ ({
+ scrollTop: this._lastScrollTop,
+ scrollLeft: this._lastScrollLeft
+ } = mainContainer);
+ let scrollendTimeoutID, scrollAbortController;
+ const scrollend = () => {
+ ({
+ scrollTop: this._lastScrollTop,
+ scrollLeft: this._lastScrollLeft
+ } = mainContainer);
+ clearTimeout(scrollendTimeoutID);
+ if (this._isScrolling) {
+ scrollAbortController.abort();
+ scrollAbortController = null;
+ this._isScrolling = false;
+ }
+ };
+ const scroll = () => {
+ if (this._isCtrlKeyDown) {
+ return;
+ }
+ if (this._lastScrollTop === mainContainer.scrollTop && this._lastScrollLeft === mainContainer.scrollLeft) {
+ return;
+ }
+ if (!this._isScrolling) {
+ scrollAbortController = new AbortController();
+ const abortSignal = AbortSignal.any([scrollAbortController.signal, signal]);
+ mainContainer.addEventListener("scrollend", scrollend, {
+ signal: abortSignal
+ });
+ mainContainer.addEventListener("blur", scrollend, {
+ signal: abortSignal
+ });
+ this._isScrolling = true;
+ }
+ clearTimeout(scrollendTimeoutID);
+ scrollendTimeoutID = setTimeout(scrollend, 100);
+ };
+ mainContainer.addEventListener("scroll", scroll, {
+ passive: true,
+ signal
+ });
+ },
+ unbindEvents() {
+ this._eventBusAC?.abort();
+ this._eventBusAC = null;
+ },
+ unbindWindowEvents() {
+ this._windowAC?.abort();
+ this._windowAC = null;
+ this._touchManager = null;
+ },
+ async testingClose() {
+ this.unbindEvents();
+ this.unbindWindowEvents();
+ this._globalAbortController?.abort();
+ this._globalAbortController = null;
+ this.findBar?.close();
+ await Promise.all([this.l10n?.destroy(), this.close()]);
+ },
+ onPagesEdited(data) {
+ this.pdfViewer.onPagesEdited(data);
+ },
+ async onSavePages({
+ data: {
+ pageInfos,
+ copyLevels
+ }
+ }) {
+ if (!this.downloadManager) {
+ return;
+ }
+ if (!this.pdfDocument) {
+ return;
+ }
+ const modifiedPdfBytes = await this.pdfDocument.extractPages(pageInfos, copyLevels);
+ if (!modifiedPdfBytes) {
+ console.error("Something wrong happened when saving the edited PDF.\nPlease file a bug.");
+ return;
+ }
+ this.downloadManager.download(modifiedPdfBytes, this._downloadUrl, this._docFilename);
+ },
+ async onSaveAndLoad({
+ data: {
+ pageInfos,
+ copyLevels
+ }
+ }) {
+ if (!this.pdfDocument) {
+ return;
+ }
+ const modifiedPdfBytes = await this.pdfDocument.extractPages(pageInfos, copyLevels);
+ if (!modifiedPdfBytes) {
+ console.error("Something wrong happened when saving the edited PDF.\nPlease file a bug.");
+ return;
+ }
+ this._mergedDocumentNeedsSaving = true;
+ this.open({
+ data: modifiedPdfBytes,
+ filename: this._docFilename
+ });
+ },
+ _accumulateTicks(ticks, prop) {
+ if (this[prop] > 0 && ticks < 0 || this[prop] < 0 && ticks > 0) {
+ this[prop] = 0;
+ }
+ this[prop] += ticks;
+ const wholeTicks = Math.trunc(this[prop]);
+ this[prop] -= wholeTicks;
+ return wholeTicks;
+ },
+ _accumulateFactor(previousScale, factor, prop) {
+ if (factor === 1) {
+ return 1;
+ }
+ const target = MathClamp(previousScale * factor * this[prop], (/* inlined export .MIN_SCALE */0.1), (/* inlined export .MAX_SCALE */25));
+ const newScale = Math.round(target * 100) / 100;
+ this[prop] = target / newScale;
+ return newScale / previousScale;
+ },
+ _unblockDocumentLoadEvent() {
+ document.blockUnblockOnload?.(false);
+ this._unblockDocumentLoadEvent = () => {};
+ },
+ get scriptingReady() {
+ return this.pdfScriptingManager.ready;
+ }
+};
+initCom(PDFViewerApplication);
+PDFPrintServiceFactory.initGlobals(PDFViewerApplication);
+{
+ const HOSTED_VIEWER_ORIGINS = new Set(["null", "http://mozilla.github.io", "https://mozilla.github.io"]);
+ var validateFileURL = function (file) {
+ if (!file) {
+ return;
+ }
+ const viewerOrigin = URL.parse(window.location)?.origin || "null";
+ if (HOSTED_VIEWER_ORIGINS.has(viewerOrigin)) {
+ return;
+ }
+ const fileOrigin = URL.parse(file, window.location)?.origin;
+ if (fileOrigin === viewerOrigin) {
+ return;
+ }
+ const ex = new Error("file origin does not match viewer's");
+ PDFViewerApplication._documentError("pdfjs-loading-error", {
+ message: ex.message
+ });
+ throw ex;
+ };
+ var onFileInputChange = function (evt) {
+ if (this.pdfViewer?.isInPresentationMode) {
+ return;
+ }
+ const file = evt.fileInput.files[0];
+ this.open({
+ url: URL.createObjectURL(file),
+ originalUrl: encodeURIComponent(file.name)
+ });
+ };
+ var onOpenFile = function (evt) {
+ this._openFileInput?.click();
+ };
+}
+function onPageRender({
+ pageNumber
+}) {
+ if (pageNumber === this.page) {
+ this.toolbar?.updateLoadingIndicatorState(true);
+ }
+}
+function onPageRendered({
+ pageNumber,
+ isDetailView,
+ error
+}) {
+ if (pageNumber === this.page) {
+ this.toolbar?.updateLoadingIndicatorState(false);
+ }
+ if (!isDetailView && this.viewsManager?.visibleView === SidebarView.THUMBS) {
+ const pageView = this.pdfViewer.getPageView(pageNumber - 1);
+ const thumbnailView = this.pdfThumbnailViewer?.getThumbnail(pageNumber - 1);
+ if (pageView) {
+ thumbnailView?.setImage(pageView);
+ }
+ }
+ if (error) {
+ this._otherError("pdfjs-rendering-error", error);
+ }
+}
+function onPageMode({
+ mode
+}) {
+ let view;
+ switch (mode) {
+ case "thumbs":
+ view = SidebarView.THUMBS;
+ break;
+ case "bookmarks":
+ case "outline":
+ view = SidebarView.OUTLINE;
+ break;
+ case "attachments":
+ view = SidebarView.ATTACHMENTS;
+ break;
+ case "layers":
+ view = SidebarView.LAYERS;
+ break;
+ case "none":
+ view = SidebarView.NONE;
+ break;
+ default:
+ console.error('Invalid "pagemode" hash parameter: ' + mode);
+ return;
+ }
+ this.viewsManager?.switchView(view, true);
+}
+function onNamedAction(evt) {
+ switch (evt.action) {
+ case "GoToPage":
+ this.appConfig.toolbar?.pageNumber.select();
+ break;
+ case "Find":
+ if (!this.supportsIntegratedFind) {
+ this.findBar?.toggle();
+ }
+ break;
+ case "Print":
+ this.triggerPrinting();
+ break;
+ case "SaveAs":
+ this.downloadOrSave();
+ break;
+ }
+}
+function onSidebarViewChanged({
+ view
+}) {
+ this.pdfRenderingQueue.isThumbnailViewEnabled = view === SidebarView.THUMBS;
+ if (this.isInitialViewSet) {
+ this.store?.set("sidebarView", view).catch(() => {});
+ }
+}
+function onUpdateViewarea({
+ location
+}) {
+ if (this.isInitialViewSet) {
+ this.store?.setMultiple({
+ page: location.pageNumber,
+ zoom: location.scale,
+ scrollLeft: location.left,
+ scrollTop: location.top,
+ rotation: location.rotation
+ }).catch(() => {});
+ }
+ if (this.appConfig.secondaryToolbar) {
+ this.appConfig.secondaryToolbar.viewBookmarkButton.href = this.pdfLinkService.getAnchorUrl(location.pdfOpenParams);
+ }
+}
+function onViewerModesChanged(name, evt) {
+ if (this.isInitialViewSet && !this.pdfViewer.isInPresentationMode) {
+ this.store?.set(name, evt.mode).catch(() => {});
+ }
+}
+function onResize() {
+ const {
+ pdfDocument,
+ pdfViewer,
+ pdfRenderingQueue
+ } = this;
+ if (pdfRenderingQueue.printing && window.matchMedia("print").matches) {
+ return;
+ }
+ if (!pdfDocument) {
+ return;
+ }
+ const currentScaleValue = pdfViewer.currentScaleValue;
+ if (currentScaleValue === "auto" || currentScaleValue === "page-fit" || currentScaleValue === "page-width") {
+ pdfViewer.currentScaleValue = currentScaleValue;
+ }
+ pdfViewer.update();
+}
+function onHashchange(evt) {
+ const hash = evt.hash;
+ if (!hash) {
+ return;
+ }
+ if (!this.isInitialViewSet) {
+ this.initialBookmark = hash;
+ } else if (!this.pdfHistory?.popStateInProgress) {
+ this.pdfLinkService.setHash(hash);
+ }
+}
+function onPageNumberChanged(evt) {
+ const {
+ pdfViewer
+ } = this;
+ if (evt.value !== "") {
+ this.pdfLinkService.goToPage(evt.value);
+ }
+ if (evt.value !== pdfViewer.currentPageNumber.toString() && evt.value !== pdfViewer.currentPageLabel) {
+ this.toolbar?.setPageNumber(pdfViewer.currentPageNumber, pdfViewer.currentPageLabel);
+ }
+}
+function onImageAltTextSettings() {
+ this.imageAltTextSettings?.open({
+ enableGuessAltText: AppOptions.get("enableGuessAltText"),
+ enableNewAltTextWhenAddingImage: AppOptions.get("enableNewAltTextWhenAddingImage")
+ });
+}
+function onFindFromUrlHash(evt) {
+ this.eventBus.dispatch("find", {
+ source: evt.source,
+ type: "",
+ query: evt.query,
+ caseSensitive: false,
+ entireWord: false,
+ highlightAll: true,
+ findPrevious: false,
+ matchDiacritics: true
+ });
+}
+function onUpdateFindMatchesCount({
+ matchesCount
+}) {
+ if (this.supportsIntegratedFind) {
+ this.externalServices.updateFindMatchesCount(matchesCount);
+ } else {
+ this.findBar?.updateResultsCount(matchesCount);
+ }
+}
+function onUpdateFindControlState({
+ state,
+ previous,
+ entireWord,
+ matchesCount,
+ rawQuery
+}) {
+ if (this.supportsIntegratedFind) {
+ this.externalServices.updateFindControlState({
+ result: state,
+ findPrevious: previous,
+ entireWord,
+ matchesCount,
+ rawQuery
+ });
+ } else {
+ this.findBar?.updateUIState(state, previous, matchesCount);
+ }
+}
+function onScaleChanging(evt) {
+ this.toolbar?.setPageScale(evt.presetValue, evt.scale);
+ this.pdfViewer.update();
+}
+function onRotationChanging(evt) {
+ if (this.pdfThumbnailViewer) {
+ this.pdfThumbnailViewer.pagesRotation = evt.pagesRotation;
+ }
+ this.forceRendering();
+ this.pdfViewer.currentPageNumber = evt.pageNumber;
+}
+function onPageChanging({
+ pageNumber,
+ pageLabel
+}) {
+ this.toolbar?.setPageNumber(pageNumber, pageLabel);
+ this.secondaryToolbar?.setPageNumber(pageNumber);
+ if (this.viewsManager?.visibleView === SidebarView.THUMBS) {
+ this.pdfThumbnailViewer?.scrollThumbnailIntoView(pageNumber);
+ }
+ const currentPage = this.pdfViewer.getPageView(pageNumber - 1);
+ this.toolbar?.updateLoadingIndicatorState(currentPage?.renderingState === RenderingStates.RUNNING);
+}
+function onWheel(evt) {
+ const {
+ pdfViewer,
+ supportsMouseWheelZoomCtrlKey,
+ supportsMouseWheelZoomMetaKey,
+ supportsPinchToZoom
+ } = this;
+ if (pdfViewer.isInPresentationMode) {
+ return;
+ }
+ const deltaMode = evt.deltaMode;
+ let scaleFactor = Math.exp(-evt.deltaY / 100);
+ const isBuiltInMac = false;
+ const isPinchToZoom = evt.ctrlKey && !this._isCtrlKeyDown && deltaMode === WheelEvent.DOM_DELTA_PIXEL && evt.deltaX === 0 && (Math.abs(scaleFactor - 1) < 0.05 || isBuiltInMac) && evt.deltaZ === 0;
+ const origin = [evt.clientX, evt.clientY];
+ if (isPinchToZoom || evt.ctrlKey && supportsMouseWheelZoomCtrlKey || evt.metaKey && supportsMouseWheelZoomMetaKey) {
+ evt.preventDefault();
+ if (this._isScrolling || document.visibilityState === "hidden" || this.overlayManager.active) {
+ return;
+ }
+ if (isPinchToZoom && supportsPinchToZoom) {
+ scaleFactor = this._accumulateFactor(pdfViewer.currentScale, scaleFactor, "_wheelUnusedFactor");
+ this.updateZoom(null, scaleFactor, origin);
+ } else {
+ const delta = normalizeWheelEventDirection(evt);
+ let ticks = 0;
+ if (deltaMode === WheelEvent.DOM_DELTA_LINE || deltaMode === WheelEvent.DOM_DELTA_PAGE) {
+ ticks = Math.abs(delta) >= 1 ? Math.sign(delta) : this._accumulateTicks(delta, "_wheelUnusedTicks");
+ } else {
+ const PIXELS_PER_LINE_SCALE = 30;
+ ticks = this._accumulateTicks(delta / PIXELS_PER_LINE_SCALE, "_wheelUnusedTicks");
+ }
+ this.updateZoom(ticks, null, origin);
+ }
+ }
+}
+function closeSecondaryToolbar({
+ target
+}) {
+ if (!this.secondaryToolbar?.isOpen) {
+ return;
+ }
+ const {
+ toolbar,
+ secondaryToolbar
+ } = this.appConfig;
+ if (this.pdfViewer.containsElement(target) || toolbar?.container.contains(target) && !secondaryToolbar?.toolbar.contains(target) && !secondaryToolbar?.toggleButton.contains(target)) {
+ this.secondaryToolbar.close();
+ }
+}
+function closeEditorUndoBar(evt) {
+ if (!this.editorUndoBar?.isOpen) {
+ return;
+ }
+ if (this.appConfig.secondaryToolbar?.toolbar.contains(evt.target)) {
+ this.editorUndoBar.hide();
+ }
+}
+function closeSignatureProperties({
+ target
+}) {
+ if (this.signaturePropertiesManager?.shouldCloseOnClick(target)) {
+ this.signaturePropertiesManager.close();
+ }
+}
+function onBeforeUnload(evt) {
+ if (this._hasChanges()) {
+ evt.preventDefault();
+ evt.returnValue = "";
+ return false;
+ }
+ return true;
+}
+function onClick(evt) {
+ closeSecondaryToolbar.call(this, evt);
+ closeEditorUndoBar.call(this, evt);
+ closeSignatureProperties.call(this, evt);
+}
+function onKeyUp(evt) {
+ if (evt.key === "Control") {
+ this._isCtrlKeyDown = false;
+ }
+}
+function onKeyDown(evt) {
+ this._isCtrlKeyDown = evt.key === "Control";
+ if (this.editorUndoBar?.isOpen && evt.keyCode !== 9 && evt.keyCode !== 16 && !((evt.keyCode === 13 || evt.keyCode === 32) && getActiveOrFocusedElement() === this.appConfig.editorUndoBar.undoButton)) {
+ this.editorUndoBar.hide();
+ }
+ if (this.overlayManager.active) {
+ return;
+ }
+ const {
+ eventBus,
+ pdfViewer
+ } = this;
+ const isViewerInPresentationMode = pdfViewer.isInPresentationMode;
+ let handled = false,
+ ensureViewerFocused = false;
+ const cmd = (evt.ctrlKey ? 1 : 0) | (evt.altKey ? 2 : 0) | (evt.shiftKey ? 4 : 0) | (evt.metaKey ? 8 : 0);
+ if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) {
+ switch (evt.keyCode) {
+ case 70:
+ if (!this.supportsIntegratedFind && !evt.shiftKey) {
+ this.findBar?.open();
+ handled = true;
+ }
+ break;
+ case 71:
+ if (!this.supportsIntegratedFind) {
+ const {
+ state
+ } = this.findController;
+ if (state) {
+ const newState = {
+ source: window,
+ type: "again",
+ findPrevious: cmd === 5 || cmd === 12
+ };
+ eventBus.dispatch("find", {
+ ...state,
+ ...newState
+ });
+ }
+ handled = true;
+ }
+ break;
+ case 61:
+ case 107:
+ case 187:
+ case 171:
+ this.zoomIn();
+ handled = true;
+ break;
+ case 173:
+ case 109:
+ case 189:
+ this.zoomOut();
+ handled = true;
+ break;
+ case 48:
+ case 96:
+ if (!isViewerInPresentationMode) {
+ setTimeout(() => {
+ this.zoomReset();
+ });
+ handled = false;
+ }
+ break;
+ case 38:
+ if (isViewerInPresentationMode || this.page > 1) {
+ this.page = 1;
+ handled = true;
+ ensureViewerFocused = true;
+ }
+ break;
+ case 40:
+ if (isViewerInPresentationMode || this.page < this.pagesCount) {
+ this.page = this.pagesCount;
+ handled = true;
+ ensureViewerFocused = true;
+ }
+ break;
+ }
+ }
+ if (cmd === 1 || cmd === 8) {
+ switch (evt.keyCode) {
+ case 83:
+ eventBus.dispatch("download", {
+ source: window
+ });
+ handled = true;
+ break;
+ case 79:
+ {
+ eventBus.dispatch("openfile", {
+ source: window
+ });
+ handled = true;
+ }
+ break;
+ }
+ }
+ if (cmd === 3 || cmd === 10) {
+ switch (evt.keyCode) {
+ case 80:
+ this.requestPresentationMode();
+ handled = true;
+ this.externalServices.reportTelemetry({
+ type: "buttons",
+ data: {
+ id: "presentationModeKeyboard"
+ }
+ });
+ break;
+ case 71:
+ if (this.appConfig.toolbar) {
+ this.appConfig.toolbar.pageNumber.select();
+ handled = true;
+ }
+ break;
+ }
+ }
+ if (handled) {
+ if (ensureViewerFocused && !isViewerInPresentationMode) {
+ pdfViewer.focus();
+ }
+ evt.preventDefault();
+ return;
+ }
+ const curElement = getActiveOrFocusedElement();
+ const curElementTagName = curElement?.tagName.toUpperCase();
+ if (curElementTagName === "INPUT" || curElementTagName === "TEXTAREA" || curElementTagName === "SELECT" || curElementTagName === "BUTTON" && evt.keyCode === 32 || curElement?.isContentEditable) {
+ if (evt.keyCode !== 27) {
+ return;
+ }
+ }
+ if (cmd === 0) {
+ let turnPage = 0,
+ turnOnlyIfPageFit = false;
+ switch (evt.keyCode) {
+ case 38:
+ if (this.supportsCaretBrowsingMode) {
+ this.moveCaret(true, false);
+ handled = true;
+ break;
+ }
+ case 33:
+ if (pdfViewer.isVerticalScrollbarEnabled) {
+ turnOnlyIfPageFit = true;
+ }
+ turnPage = -1;
+ break;
+ case 8:
+ if (!isViewerInPresentationMode) {
+ turnOnlyIfPageFit = true;
+ }
+ turnPage = -1;
+ break;
+ case 37:
+ if (this.supportsCaretBrowsingMode) {
+ return;
+ }
+ if (pdfViewer.isHorizontalScrollbarEnabled) {
+ turnOnlyIfPageFit = true;
+ }
+ case 75:
+ case 80:
+ turnPage = -1;
+ break;
+ case 27:
+ if (this.secondaryToolbar?.isOpen) {
+ this.secondaryToolbar.close();
+ handled = true;
+ }
+ if (this.signaturePropertiesManager?.isOpen) {
+ this.signaturePropertiesManager.close();
+ handled = true;
+ }
+ if (!this.supportsIntegratedFind && this.findBar?.opened) {
+ this.findBar.close();
+ handled = true;
+ }
+ break;
+ case 40:
+ if (this.supportsCaretBrowsingMode) {
+ this.moveCaret(false, false);
+ handled = true;
+ break;
+ }
+ case 34:
+ if (pdfViewer.isVerticalScrollbarEnabled) {
+ turnOnlyIfPageFit = true;
+ }
+ turnPage = 1;
+ break;
+ case 32:
+ if (!isViewerInPresentationMode) {
+ turnOnlyIfPageFit = true;
+ }
+ turnPage = 1;
+ break;
+ case 39:
+ if (this.supportsCaretBrowsingMode) {
+ return;
+ }
+ if (pdfViewer.isHorizontalScrollbarEnabled) {
+ turnOnlyIfPageFit = true;
+ }
+ case 74:
+ case 78:
+ turnPage = 1;
+ break;
+ case 36:
+ if (isViewerInPresentationMode || this.page > 1) {
+ this.page = 1;
+ handled = true;
+ ensureViewerFocused = true;
+ }
+ break;
+ case 35:
+ if (isViewerInPresentationMode || this.page < this.pagesCount) {
+ this.page = this.pagesCount;
+ handled = true;
+ ensureViewerFocused = true;
+ }
+ break;
+ case 83:
+ this.pdfCursorTools?.switchTool(CursorTool.SELECT);
+ break;
+ case 72:
+ this.pdfCursorTools?.switchTool(CursorTool.HAND);
+ break;
+ case 82:
+ this.rotatePages(90);
+ break;
+ case 115:
+ this.viewsManager?.toggle();
+ break;
+ }
+ if (turnPage !== 0 && (!turnOnlyIfPageFit || pdfViewer.currentScaleValue === "page-fit")) {
+ if (turnPage > 0) {
+ pdfViewer.nextPage();
+ } else {
+ pdfViewer.previousPage();
+ }
+ handled = true;
+ }
+ }
+ if (cmd === 4) {
+ switch (evt.keyCode) {
+ case 32:
+ if (!isViewerInPresentationMode && pdfViewer.currentScaleValue !== "page-fit") {
+ break;
+ }
+ pdfViewer.previousPage();
+ handled = true;
+ break;
+ case 38:
+ this.moveCaret(true, true);
+ handled = true;
+ break;
+ case 40:
+ this.moveCaret(false, true);
+ handled = true;
+ break;
+ case 82:
+ this.rotatePages(-90);
+ break;
+ }
+ }
+ if (!handled && !isViewerInPresentationMode) {
+ if (evt.keyCode >= 33 && evt.keyCode <= 40 || evt.keyCode === 32 && curElementTagName !== "BUTTON") {
+ ensureViewerFocused = true;
+ }
+ }
+ if (ensureViewerFocused && !pdfViewer.containsElement(curElement)) {
+ pdfViewer.focus();
+ }
+ if (handled) {
+ evt.preventDefault();
+ }
+}
+
+;// ./web/viewer.js
+
+
+
+
+
+const AppConstants = {
+ LinkTarget: LinkTarget,
+ RenderingStates: RenderingStates,
+ ScrollMode: ScrollMode,
+ SpreadMode: SpreadMode
+};
+window.PDFViewerApplication = PDFViewerApplication;
+window.PDFViewerApplicationConstants = AppConstants;
+window.PDFViewerApplicationOptions = AppOptions;
+function getViewerConfiguration() {
+ return {
+ appContainer: document.body,
+ principalContainer: document.getElementById("mainContainer"),
+ mainContainer: document.getElementById("viewerContainer"),
+ viewerContainer: document.getElementById("viewer"),
+ viewerAlert: document.getElementById("viewer-alert"),
+ toolbar: {
+ container: document.getElementById("toolbarContainer"),
+ numPages: document.getElementById("numPages"),
+ pageNumber: document.getElementById("pageNumber"),
+ scaleSelect: document.getElementById("scaleSelect"),
+ customScaleOption: document.getElementById("customScaleOption"),
+ previous: document.getElementById("previous"),
+ next: document.getElementById("next"),
+ zoomIn: document.getElementById("zoomInButton"),
+ zoomOut: document.getElementById("zoomOutButton"),
+ print: document.getElementById("printButton"),
+ editorCommentButton: document.getElementById("editorCommentButton"),
+ editorCommentParamsToolbar: document.getElementById("editorCommentParamsToolbar"),
+ editorFreeTextButton: document.getElementById("editorFreeTextButton"),
+ editorFreeTextParamsToolbar: document.getElementById("editorFreeTextParamsToolbar"),
+ editorHighlightButton: document.getElementById("editorHighlightButton"),
+ editorHighlightParamsToolbar: document.getElementById("editorHighlightParamsToolbar"),
+ editorHighlightColorPicker: document.getElementById("editorHighlightColorPicker"),
+ editorInkButton: document.getElementById("editorInkButton"),
+ editorInkParamsToolbar: document.getElementById("editorInkParamsToolbar"),
+ editorStampButton: document.getElementById("editorStampButton"),
+ editorStampParamsToolbar: document.getElementById("editorStampParamsToolbar"),
+ editorSignatureButton: document.getElementById("editorSignatureButton"),
+ editorSignatureParamsToolbar: document.getElementById("editorSignatureParamsToolbar"),
+ signaturePropertiesButton: document.getElementById("signaturePropertiesButton"),
+ signaturePropertiesPanel: document.getElementById("signaturePropertiesPanel"),
+ signaturePropertiesContainer: document.getElementById("signaturePropertiesContainer"),
+ signaturePropertiesBanner: document.getElementById("signaturePropertiesBanner"),
+ signaturePropertiesList: document.getElementById("signaturePropertiesList"),
+ signaturePropertiesSeparator: document.getElementById("signaturePropertiesSeparator"),
+ download: document.getElementById("downloadButton")
+ },
+ secondaryToolbar: {
+ toolbar: document.getElementById("secondaryToolbar"),
+ toggleButton: document.getElementById("secondaryToolbarToggleButton"),
+ presentationModeButton: document.getElementById("presentationMode"),
+ openFileButton: document.getElementById("secondaryOpenFile"),
+ printButton: document.getElementById("secondaryPrint"),
+ downloadButton: document.getElementById("secondaryDownload"),
+ viewBookmarkButton: document.getElementById("viewBookmark"),
+ firstPageButton: document.getElementById("firstPage"),
+ lastPageButton: document.getElementById("lastPage"),
+ pageRotateCwButton: document.getElementById("pageRotateCw"),
+ pageRotateCcwButton: document.getElementById("pageRotateCcw"),
+ cursorSelectToolButton: document.getElementById("cursorSelectTool"),
+ cursorHandToolButton: document.getElementById("cursorHandTool"),
+ scrollPageButton: document.getElementById("scrollPage"),
+ scrollVerticalButton: document.getElementById("scrollVertical"),
+ scrollHorizontalButton: document.getElementById("scrollHorizontal"),
+ scrollWrappedButton: document.getElementById("scrollWrapped"),
+ spreadNoneButton: document.getElementById("spreadNone"),
+ spreadOddButton: document.getElementById("spreadOdd"),
+ spreadEvenButton: document.getElementById("spreadEven"),
+ imageAltTextSettingsButton: document.getElementById("imageAltTextSettings"),
+ imageAltTextSettingsSeparator: document.getElementById("imageAltTextSettingsSeparator"),
+ documentPropertiesButton: document.getElementById("documentProperties")
+ },
+ viewsManager: {
+ outerContainer: document.getElementById("outerContainer"),
+ toggleButton: document.getElementById("viewsManagerToggleButton"),
+ sidebarContainer: document.getElementById("viewsManager"),
+ resizer: document.getElementById("viewsManagerResizer"),
+ thumbnailButton: document.getElementById("thumbnailsViewMenu"),
+ outlineButton: document.getElementById("outlinesViewMenu"),
+ attachmentsButton: document.getElementById("attachmentsViewMenu"),
+ layersButton: document.getElementById("layersViewMenu"),
+ viewsManagerSelectorButton: document.getElementById("viewsManagerSelectorButton"),
+ viewsManagerSelectorOptions: document.getElementById("viewsManagerSelectorOptions"),
+ thumbnailsView: document.getElementById("thumbnailsView"),
+ outlinesView: document.getElementById("outlinesView"),
+ attachmentsView: document.getElementById("attachmentsView"),
+ layersView: document.getElementById("layersView"),
+ viewsManagerAddFile: {
+ button: document.getElementById("viewsManagerAddFileButton"),
+ picker: document.getElementById("viewsManagerAddFilePicker")
+ },
+ viewsManagerCurrentOutlineButton: document.getElementById("viewsManagerCurrentOutlineButton"),
+ viewsManagerHeaderLabel: document.getElementById("viewsManagerHeaderLabel"),
+ viewsManagerStatus: document.getElementById("viewsManagerStatus"),
+ viewsManagerStatusBar: {
+ viewsManagerStatusAction: document.getElementById("viewsManagerStatusAction"),
+ viewsManagerStatusActionDeselectButton: document.getElementById("viewsManagerStatusActionDeselectButton"),
+ viewsManagerStatusActionLabel: document.getElementById("viewsManagerStatusActionLabel")
+ },
+ viewsManagerUndoBar: {
+ viewsManagerStatusUndo: document.getElementById("viewsManagerStatusUndo"),
+ viewsManagerStatusUndoLabel: document.getElementById("viewsManagerStatusUndoLabel"),
+ viewsManagerStatusUndoButton: document.getElementById("viewsManagerStatusUndoButton"),
+ viewsManagerStatusUndoCloseButton: document.getElementById("viewsManagerStatusUndoCloseButton")
+ },
+ viewsManagerWaitingBar: {
+ container: document.getElementById("viewsManagerStatusWaiting"),
+ closeButton: document.getElementById("viewsManagerStatusWaitingCloseButton"),
+ label: document.getElementById("viewsManagerStatusWaitingLabel")
+ },
+ manageMenu: {
+ button: document.getElementById("viewsManagerStatusActionButton"),
+ menu: document.getElementById("viewsManagerStatusActionOptions"),
+ copy: document.getElementById("viewsManagerStatusActionCopy"),
+ cut: document.getElementById("viewsManagerStatusActionCut"),
+ delete: document.getElementById("viewsManagerStatusActionDelete"),
+ exportSelected: document.getElementById("viewsManagerStatusActionExport")
+ }
+ },
+ findBar: {
+ bar: document.getElementById("findbar"),
+ toggleButton: document.getElementById("viewFindButton"),
+ findField: document.getElementById("findInput"),
+ highlightAllCheckbox: document.getElementById("findHighlightAll"),
+ caseSensitiveCheckbox: document.getElementById("findMatchCase"),
+ matchDiacriticsCheckbox: document.getElementById("findMatchDiacritics"),
+ entireWordCheckbox: document.getElementById("findEntireWord"),
+ findMsg: document.getElementById("findMsg"),
+ findResultsCount: document.getElementById("findResultsCount"),
+ findPreviousButton: document.getElementById("findPreviousButton"),
+ findNextButton: document.getElementById("findNextButton")
+ },
+ passwordOverlay: {
+ dialog: document.getElementById("passwordDialog"),
+ label: document.getElementById("passwordText"),
+ input: document.getElementById("password"),
+ submitButton: document.getElementById("passwordSubmit"),
+ cancelButton: document.getElementById("passwordCancel")
+ },
+ documentProperties: {
+ dialog: document.getElementById("documentPropertiesDialog"),
+ closeButton: document.getElementById("documentPropertiesClose"),
+ fields: {
+ fileName: document.getElementById("fileNameField"),
+ fileSize: document.getElementById("fileSizeField"),
+ title: document.getElementById("titleField"),
+ author: document.getElementById("authorField"),
+ subject: document.getElementById("subjectField"),
+ keywords: document.getElementById("keywordsField"),
+ creationDate: document.getElementById("creationDateField"),
+ modificationDate: document.getElementById("modificationDateField"),
+ creator: document.getElementById("creatorField"),
+ producer: document.getElementById("producerField"),
+ version: document.getElementById("versionField"),
+ pageCount: document.getElementById("pageCountField"),
+ pageSize: document.getElementById("pageSizeField"),
+ linearized: document.getElementById("linearizedField")
+ }
+ },
+ altTextDialog: {
+ dialog: document.getElementById("altTextDialog"),
+ optionDescription: document.getElementById("descriptionButton"),
+ optionDecorative: document.getElementById("decorativeButton"),
+ textarea: document.getElementById("descriptionTextarea"),
+ cancelButton: document.getElementById("altTextCancel"),
+ saveButton: document.getElementById("altTextSave")
+ },
+ newAltTextDialog: {
+ dialog: document.getElementById("newAltTextDialog"),
+ title: document.getElementById("newAltTextTitle"),
+ descriptionContainer: document.getElementById("newAltTextDescriptionContainer"),
+ textarea: document.getElementById("newAltTextDescriptionTextarea"),
+ disclaimer: document.getElementById("newAltTextDisclaimer"),
+ learnMore: document.getElementById("newAltTextLearnMore"),
+ imagePreview: document.getElementById("newAltTextImagePreview"),
+ createAutomatically: document.getElementById("newAltTextCreateAutomatically"),
+ createAutomaticallyButton: document.getElementById("newAltTextCreateAutomaticallyButton"),
+ downloadModel: document.getElementById("newAltTextDownloadModel"),
+ downloadModelDescription: document.getElementById("newAltTextDownloadModelDescription"),
+ error: document.getElementById("newAltTextError"),
+ errorCloseButton: document.getElementById("newAltTextCloseButton"),
+ cancelButton: document.getElementById("newAltTextCancel"),
+ notNowButton: document.getElementById("newAltTextNotNow"),
+ saveButton: document.getElementById("newAltTextSave")
+ },
+ altTextSettingsDialog: {
+ dialog: document.getElementById("altTextSettingsDialog"),
+ createModelButton: document.getElementById("createModelButton"),
+ learnMore: document.getElementById("altTextSettingsLearnMore"),
+ showAltTextDialogButton: document.getElementById("showAltTextDialogButton"),
+ altTextSettingsCloseButton: document.getElementById("altTextSettingsCloseButton"),
+ closeButton: document.getElementById("altTextSettingsCloseButton")
+ },
+ addSignatureDialog: {
+ dialog: document.getElementById("addSignatureDialog"),
+ panels: document.getElementById("addSignatureActionContainer"),
+ typeButton: document.getElementById("addSignatureTypeButton"),
+ typeInput: document.getElementById("addSignatureTypeInput"),
+ drawButton: document.getElementById("addSignatureDrawButton"),
+ drawSVG: document.getElementById("addSignatureDraw"),
+ drawPlaceholder: document.getElementById("addSignatureDrawPlaceholder"),
+ drawThickness: document.getElementById("addSignatureDrawThickness"),
+ imageButton: document.getElementById("addSignatureImageButton"),
+ imageSVG: document.getElementById("addSignatureImage"),
+ imagePlaceholder: document.getElementById("addSignatureImagePlaceholder"),
+ imagePicker: document.getElementById("addSignatureFilePicker"),
+ imagePickerLink: document.getElementById("addSignatureImageBrowse"),
+ description: document.getElementById("addSignatureDescription"),
+ clearButton: document.getElementById("clearSignatureButton"),
+ saveContainer: document.getElementById("addSignatureSaveContainer"),
+ saveCheckbox: document.getElementById("addSignatureSaveCheckbox"),
+ errorBar: document.getElementById("addSignatureError"),
+ errorTitle: document.getElementById("addSignatureErrorTitle"),
+ errorDescription: document.getElementById("addSignatureErrorDescription"),
+ errorCloseButton: document.getElementById("addSignatureErrorCloseButton"),
+ cancelButton: document.getElementById("addSignatureCancelButton"),
+ addButton: document.getElementById("addSignatureAddButton")
+ },
+ editSignatureDialog: {
+ dialog: document.getElementById("editSignatureDescriptionDialog"),
+ description: document.getElementById("editSignatureDescription"),
+ editSignatureView: document.getElementById("editSignatureView"),
+ cancelButton: document.getElementById("editSignatureCancelButton"),
+ updateButton: document.getElementById("editSignatureUpdateButton")
+ },
+ annotationEditorParams: {
+ editorCommentsSidebar: document.getElementById("editorCommentsSidebar"),
+ editorCommentsSidebarCount: document.getElementById("editorCommentsSidebarCount"),
+ editorCommentsSidebarTitle: document.getElementById("editorCommentsSidebarTitle"),
+ editorCommentsSidebarCloseButton: document.getElementById("editorCommentsSidebarCloseButton"),
+ editorCommentsSidebarList: document.getElementById("editorCommentsSidebarList"),
+ editorCommentsSidebarResizer: document.getElementById("editorCommentsSidebarResizer"),
+ editorFreeTextFontSize: document.getElementById("editorFreeTextFontSize"),
+ editorFreeTextColor: document.getElementById("editorFreeTextColor"),
+ editorInkColor: document.getElementById("editorInkColor"),
+ editorInkThickness: document.getElementById("editorInkThickness"),
+ editorInkOpacity: document.getElementById("editorInkOpacity"),
+ editorStampAddImage: document.getElementById("editorStampAddImage"),
+ editorSignatureAddSignature: document.getElementById("editorSignatureAddSignature"),
+ editorFreeHighlightThickness: document.getElementById("editorFreeHighlightThickness"),
+ editorHighlightShowAll: document.getElementById("editorHighlightShowAll")
+ },
+ printContainer: document.getElementById("printContainer"),
+ editorUndoBar: {
+ container: document.getElementById("editorUndoBar"),
+ message: document.getElementById("editorUndoBarMessage"),
+ undoButton: document.getElementById("editorUndoBarUndoButton"),
+ closeButton: document.getElementById("editorUndoBarCloseButton")
+ },
+ ...{},
+ editCommentDialog: {
+ dialog: document.getElementById("commentManagerDialog"),
+ toolbar: document.getElementById("commentManagerToolbar"),
+ title: document.getElementById("commentManagerTitle"),
+ textInput: document.getElementById("commentManagerTextInput"),
+ cancelButton: document.getElementById("commentManagerCancelButton"),
+ saveButton: document.getElementById("commentManagerSaveButton")
+ }
+ };
+}
+function webViewerLoad() {
+ const config = getViewerConfiguration();
+ const event = new CustomEvent("webviewerloaded", {
+ bubbles: true,
+ cancelable: true,
+ detail: {
+ source: window
+ }
+ });
+ try {
+ parent.document.dispatchEvent(event);
+ } catch (ex) {
+ console.error("webviewerloaded:", ex);
+ document.dispatchEvent(event);
+ }
+ PDFViewerApplication.run(config);
+}
+document.blockUnblockOnload?.(true);
+if (document.readyState === "interactive" || document.readyState === "complete") {
+ webViewerLoad();
+} else {
+ document.addEventListener("DOMContentLoaded", webViewerLoad, true);
+}
+
+export { PDFViewerApplication, AppConstants as PDFViewerApplicationConstants, AppOptions as PDFViewerApplicationOptions };
+
+//# sourceMappingURL=viewer.mjs.map
\ No newline at end of file
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_JBIG2 b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_JBIG2
new file mode 100644
index 0000000..37a329c
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_JBIG2
@@ -0,0 +1,196 @@
+// Copyright 2014 The PDFium Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ 1. Definitions.
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+ END OF TERMS AND CONDITIONS
+ APPENDIX: How to apply the Apache License to your work.
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+ Copyright [yyyy] [name of copyright owner]
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ https://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_OPENJPEG b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_OPENJPEG
new file mode 100644
index 0000000..e8fa410
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_OPENJPEG
@@ -0,0 +1,39 @@
+/*
+ * The copyright in this software is being made available under the 2-clauses
+ * BSD License, included below. This software may be subject to other third
+ * party and contributor rights, including patent rights, and no such rights
+ * are granted under this license.
+ *
+ * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
+ * Copyright (c) 2002-2014, Professor Benoit Macq
+ * Copyright (c) 2003-2014, Antonin Descampe
+ * Copyright (c) 2003-2009, Francois-Olivier Devaux
+ * Copyright (c) 2005, Herve Drolon, FreeImage Team
+ * Copyright (c) 2002-2003, Yannick Verschueren
+ * Copyright (c) 2001-2003, David Janssens
+ * Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
+ * Copyright (c) 2012, CS Systemes d'Information, France
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_JBIG2 b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_JBIG2
new file mode 100644
index 0000000..f1845ba
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_JBIG2
@@ -0,0 +1,13 @@
+Copyright 2026 Mozilla Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_OPENJPEG b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_OPENJPEG
new file mode 100644
index 0000000..623929b
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_OPENJPEG
@@ -0,0 +1,22 @@
+Copyright (c) 2024, Mozilla Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_QCMS b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_QCMS
new file mode 100644
index 0000000..9cf1062
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_PDFJS_QCMS
@@ -0,0 +1,19 @@
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_QCMS b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_QCMS
new file mode 100644
index 0000000..eec8246
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/LICENSE_QCMS
@@ -0,0 +1,21 @@
+qcms
+Copyright (C) 2009-2024 Mozilla Corporation
+Copyright (C) 1998-2007 Marti Maria
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/jbig2.wasm b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/jbig2.wasm
new file mode 100644
index 0000000..254e1e4
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/jbig2.wasm differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/jbig2_nowasm_fallback.js b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/jbig2_nowasm_fallback.js
new file mode 100644
index 0000000..c86528f
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/jbig2_nowasm_fallback.js
@@ -0,0 +1,15 @@
+/* THIS FILE IS GENERATED - DO NOT EDIT */
+async function JBig2(moduleArg={}){var moduleRtn;var Module=moduleArg;var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var _scriptName=import.meta.url;var scriptDirectory="";var readAsync;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var WebAssembly={Memory:function(opts){this.buffer=new ArrayBuffer(opts["initial"]*65536)},Module:function(binary){},Instance:function(module,info){this.exports=(
+// EMSCRIPTEN_START_ASM
+function instantiate(ha){var a;var b=new Uint8Array(123);for(var c=25;c>=0;--c){b[48+c]=52+c;b[65+c]=c;b[97+c]=26+c}b[43]=62;b[47]=63;function i(j,k,l){var d,e,c=0,f=k,g=l.length,h=k+(g*3>>2)-(l[g-2]=="=")-(l[g-1]=="=");for(;c>4;if(f>2;if(f>>0;s=s>>>0;if(q+s>a.length)throw"trap: invalid memory.fill";a.fill(u,q,q+s)}function ga(n){var v=new ArrayBuffer(16777216);var w=new Int8Array(v);var x=new Int16Array(v);var y=new Int32Array(v);var z=new Uint8Array(v);var A=new Uint16Array(v);var B=new Uint32Array(v);var C=new Float32Array(v);var D=new Float64Array(v);var E=Math.imul;var F=Math.fround;var G=Math.abs;var H=Math.clz32;var I=Math.min;var J=Math.max;var K=Math.floor;var L=Math.ceil;var M=Math.trunc;var N=Math.sqrt;var O=n.a;var P=O.a;var Q=O.b;var R=O.c;var S=O.d;var T=O.e;var U=O.f;var V=O.g;var W=O.h;var X=O.i;var Y=72736;var Z=0;
+// EMSCRIPTEN_START_FUNCS
+function yc(a){var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,q=0,r=0,s=0,u=0,v=0,C=0,D=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0;J=Y-16|0;Y=J;a:{b:{c:{d:{c=y[a+4>>2];b=y[c+8>>2];i=y[c+4>>2];e:{if(b>>>0>i>>>0){break e}if((b|0)==(i|0)){aa=2;break c}R=a+80|0;while(1){if(b>>>0>i>>>0){break e}if(i-b>>>0<11){break c}f:{g:{h:{m=y[R>>2];i:{if(!m){b=na(72);w[b+4|0]=0;y[b>>2]=0;t(b+8|0,0,64);y[J+4>>2]=0;ib(R,b);ac(J+4|0);j:{c=y[a+80>>2];k:{if(ra(y[a+4>>2],c)){break k}if(va(y[a+4>>2],c+4|0)){break k}b=y[a+4>>2];d=y[b+8>>2];g=y[b>>2];l:{m:{if(B[b+4>>2]<=d>>>0){w[J+15|0]=0;break m}d=z[d+g|0];w[J+15|0]=d;if(d>>>0<224){break m}if(ra(b,c+8|0)){break k}b=y[c+8>>2]&536870911;y[c+8>>2]=b;if(b>>>0>64){break k}g=y[a+4>>2];i=y[g+8>>2];d=i+(b+8>>>3|0)|0;if(d>>>0>>0){break l}h=g;g=y[g+4>>2];y[h+8>>2]=d>>>0>>0?d:g;break l}if(va(b,J+15|0)){break k}b=z[J+15|0]>>>5|0;y[c+8>>2]=b}g=z[c+4|0];n:{if(!b){break n}d=y[c>>2];xc(c+12|0,b);b=0;d=(d>>>0>65536?4:d>>>0>256?2:1)-1|0;while(1){if(y[c+8>>2]<=(b|0)){break n}o:{p:{switch(d-1|0){default:if(va(y[a+4>>2],J+15|0)){break k}m=z[J+15|0];y[y[c+12>>2]+(b<<2)>>2]=m;break o;case 0:if(Wa(y[a+4>>2],J+12|0)){break k}m=A[J+12>>1];y[y[c+12>>2]+(b<<2)>>2]=m;break o;case 1:break e;case 2:break p}}if(ra(y[a+4>>2],J+8|0)){break k}m=y[J+8>>2];y[y[c+12>>2]+(b<<2)>>2]=m}b=b+1|0;if(B[c>>2]>m>>>0){continue}break}break k}b=y[a+4>>2];q:{if(!(g&64)){if(va(b,J+15|0)){break k}y[c+24>>2]=z[J+15|0];break q}if(ra(b,c+24|0)){break k}}if(!ra(y[a+4>>2],c+28|0)){break j}}ib(R,0);break i}b=y[a+4>>2];d=y[b+20>>2];y[c+40>>2]=y[b+16>>2];y[c+44>>2]=d;b=y[b+8>>2];y[c+48>>2]=1;y[c+36>>2]=b;y[a+84>>2]=b;m=y[a+80>>2]}r:{while(1){h=0;c=0;f=Y-368|0;Y=f;b=2;s:{t:{u:{v:{w:{x:{y:{z:{A:{B:{C:{D:{E:{F:{G:{H:{I:{J:{K:{L:{M:{N:{O:{P:{Q:{R:{S:{T:{U:{d=z[m+4|0]&63;switch(d-16|0){case 0:break T;case 1:case 2:case 3:case 5:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 21:case 25:case 28:case 29:case 30:case 31:break B;case 4:case 6:case 7:break S;case 20:case 22:case 23:break R;case 24:case 26:case 27:break Q;case 32:break P;case 33:break O;case 34:break N;case 35:break u;case 36:break M;case 37:break L;default:break U}}V:{switch(d|0){case 0:b=0;s=0;F=0;N=0;e=Y-272|0;Y=e;l=1;if(!Wa(y[a+4>>2],e+118|0)){j=na(56);y[j+40>>2]=0;y[j+32>>2]=0;y[j+36>>2]=0;y[j+24>>2]=0;y[j+28>>2]=0;y[j+16>>2]=0;y[j+20>>2]=0;h=A[e+118>>1];c=h&1;w[j|0]=c;d=h>>>10&3;w[j+3|0]=d;g=h&12288;w[j+2|0]=(g|0)!=0;i=(h&254)>>>1&1;w[j+1|0]=i;Q=j+16|0;W:{X:{Y:{if(!c){c=d?2:8;d=j+44|0;while(1){if((b|0)!=(c|0)){g=b+d|0;b=b+1|0;if(!va(y[a+4>>2],g)){continue}break W}break}if(z[j+1|0]!=1){break X}if(!z[j+2|0]){break Y}break X}if(g|!i){break X}}c=j+52|0;b=0;while(1){if((b|0)==4){break X}d=b+c|0;b=b+1|0;if(!va(y[a+4>>2],d)){continue}break}break W}if(ra(y[a+4>>2],j+12|0)){break W}if(ra(y[a+4>>2],j+8|0)|B[j+12>>2]>65535|B[j+8>>2]>65535){break W}b=y[m+8>>2];i=(b|0)>0?b:0;b=0;while(1){if((b|0)==(i|0)){c=1;k=0;b=0;while(1)if((b|0)==(i|0)){Z:{_:{$:{aa:{ba:{ca:{da:{ea:{fa:{if(!(c&1)){break fa}y[j+4>>2]=k;U=Ub(e+104|0,k);n=y[U>>2];ga:{if((n|0)==y[U+4>>2]){break ga}b=y[m+8>>2];q=(b|0)>0?b:0;c=1;k=0;while(1){if((q|0)==(F|0)){break ga}ha:{b=Ma(a,y[y[m+12>>2]+(F<<2)>>2]);if(z[b+4|0]&63){break ha}b=y[b+56>>2];g=y[b+24>>2];d=y[b+28>>2]-g>>2;b=0;while(1){if((b|0)==(d|0)){g=0;i=0;if(c&1){b=d+k|0;g=b>>>0>=d>>>0;i=g?b:0}k=i;c=g;break ha}i=b+k|0;if(!(i>>>0>=b>>>0&c)){break fa}y[n+(i<<2)>>2]=y[g+(b<<2)>>2];b=b+1|0;continue}}F=F+1|0;continue}}bb(Q,U);ia:{if(z[j|0]!=1){break ia}b=h>>>2&3;if((b|0)==2){break Z}d=h>>>4&3;if((d|0)==2){break Z}ja:{ka:{switch(b|0){case 0:c=sa(a,4);b=0;break ja;case 1:c=sa(a,5);b=0;break ja;default:break ka}}b=Ga(a,m,0);if(!b){break Z}c=y[b+68>>2];b=1}y[j+28>>2]=c;la:{ma:{switch(d|0){case 0:c=sa(a,2);break la;case 1:c=sa(a,3);break la;default:break ma}}c=Ga(a,m,b);if(!c){break Z}b=b+1|0;c=y[c+68>>2]}y[j+32>>2]=c;na:{if(!(h&64)){c=sa(a,1);break na}c=Ga(a,m,b);if(!c){break Z}b=b+1|0;c=y[c+68>>2]}y[j+36>>2]=c;if(z[j+1|0]!=1){break ia}oa:{if(!(h&128)){b=sa(a,1);break oa}b=Ga(a,m,b);if(!b){break Z}b=y[b+68>>2]}y[j+40>>2]=b}W=z[j+1|0];V=z[j|0];b=z[j+3|0];c=z[j+2|0];y[e+100>>2]=0;y[e+92>>2]=0;y[e+96>>2]=0;y[e+88>>2]=0;y[e+80>>2]=0;y[e+84>>2]=0;c=c?1024:8192;b=b?(b|0)==1?8192:1024:65536;pa:{if(!(!(h&256)|!s)){if(!(V&1)){d=Sb(e+92|0,y[s+56>>2]);if((b|0)!=y[e+96>>2]-y[d>>2]>>3){break _}}if(!(W&1)){break pa}b=Sb(e+80|0,y[s+56>>2]+12|0);if((c|0)==y[e+84>>2]-y[b>>2]>>3){break pa}break _}if(!(V&1)){kb(e+92|0,b)}if(!(W&1)){break pa}kb(e+80|0,c)}b=y[m+44>>2];d=b;c=y[m+40>>2];y[e+64>>2]=c;y[e+68>>2]=b;g=y[m+36>>2];y[e+72>>2]=g;y[m+52>>2]=2;qa:{if(!(b|c)|z[a+48|0]!=1){break qa}i=y[a+108>>2];b=i;while(1){b=y[b+4>>2];if((i|0)==(b|0)){break qa}if((c|0)!=y[b+8>>2]|(d|0)!=y[b+12>>2]|(g|0)!=y[b+16>>2]){continue}break}c=Ad(y[b+24>>2]);y[e+120>>2]=0;Rb(m+56|0,c);Za(e+120|0);zd(y[a+108>>2],e- -64|0,b+24|0);c=y[a+108>>2];d=y[b>>2];g=y[b+4>>2];y[d+4>>2]=g;y[g>>2]=d;y[c+8>>2]=y[c+8>>2]-1;oc(b);break aa}if(!(V&1)){u=Ra(y[a+4>>2]);y[e+60>>2]=u;I=y[e+92>>2];d=y[e+96>>2];C=y[e+80>>2];g=y[e+84>>2];ba=Fa();y[e+268>>2]=ba;ca=Fa();y[e+252>>2]=ca;da=Fa();y[e+248>>2]=da;ea=Fa();y[e+244>>2]=ea;i=y[j+8>>2]+y[j+4>>2]|0;b=0;while(1){c=b;b=b+1|0;if(i>>>0>1<>>0){continue}break}_=I+3240|0;S=g-C>>3;P=Cd(e+120|0,c&255);O=gb(e+256|0,y[j+8>>2]);G=d-I>>3;X=G>>>0>405;i=0;F=0;while(1){ra:{sa:{ta:{b=y[j+8>>2];if(b>>>0>i>>>0){y[e+240>>2]=0;Aa(ba,u,e+236|0);F=y[e+236>>2]+F|0;if(F>>>0>65535){break ta}K=0;while(1){ua:{l=Aa(ca,u,e+232|0);if(!l|B[j+8>>2]<=i>>>0){break ua}l=1;K=y[e+232>>2]+K|0;if(K>>>0>65535){break ua}if(!(!F|!K)){va:{wa:{xa:{ya:{za:{if(!z[j+1|0]){r=qb();y[e+228>>2]=r;y[r+8>>2]=F;y[r+4>>2]=K;w[r|0]=0;b=z[j+3|0];w[r+1|0]=0;w[r+2|0]=0;w[r+3|0]=b;w[r+16|0]=z[j+44|0];w[r+17|0]=z[j+45|0];w[r+18|0]=z[j+46|0];w[r+19|0]=z[j+47|0];w[r+20|0]=z[j+48|0];w[r+21|0]=z[j+49|0];w[r+22|0]=z[j+50|0];w[r+23|0]=z[j+51|0];Aa:{switch(b|0){case 0:if(xd(r)){D=nc(r,u,I,G,0);break wa}D=mc(r,u,I,G,0);break wa;case 1:if(wd(r)){D=nc(r,u,I,G,1);break wa}D=mc(r,u,I,G,1);break wa;case 2:if(Qb(r)){D=nc(r,u,I,G,2);break wa}D=mc(r,u,I,G,2);break wa;default:break Aa}}if(!Qb(r)){break za}D=xa(K,F);y[e+160>>2]=D;if(!qa(D)){break ya}b=y[r+4>>2];if(!b){break fa}b=b-1|0;L=b>>>3|0;T=(b&7)+1|0;g=0;k=0;n=0;c=0;while(1){Ba:{Ca:{if(B[r+8>>2]>n>>>0){ja(e+192|0,D,n);h=y[e+196>>2];q=y[e+192>>2];if(z[r+1|0]!=1){b=c;break Ca}if(z[u|0]){break ya}if(!X){break fa}b=0;d=ka(u,_);if((d|0)==(c|0)){break Ca}y[e+184>>2]=h;y[e+180>>2]=q;y[e+172>>2]=k;y[e+168>>2]=g;b=y[e+184>>2];y[e+8>>2]=y[e+180>>2];y[e+12>>2]=b;b=y[e+172>>2];y[e>>2]=y[e+168>>2];y[e+4>>2]=b;Pa(e+8|0,e);c=c^d;break Ba}y[e+160>>2]=0;break xa}c=0;H=0;Da:{if(!n){Ea:{while(1){k=7;v=0;if((H|0)==(L|0)){break Ea}Fa:{while(1){if((k|0)>=0){if(z[u|0]){break Fa}if(c>>>0>=G>>>0){break fa}d=ka(u,(c<<3)+I|0);c=d|c<<1&1006;v=d<>>0>>0){break ya}}k=0;v=0;while(1){if((k|0)==(T|0)){break Da}if(z[u|0]){break ya}if(c>>>0>=G>>>0){break fa}d=ka(u,(c<<3)+I|0);c=d|c<<1&1006;v=d<<7-k|v;k=k+1|0;continue}}if(!k){break fa}$=k-1|0;H=z[g|0];k=H>>>1&112;d=0;while(1){Ga:{if((d|0)!=(L|0)){if((d|0)==($|0)){break fa}s=d+1|0;H=z[s+g|0]|H<<8;c=7;v=0;while(1){if((c|0)<0){break Ga}if(z[u|0]){break ya}if(k>>>0>=G>>>0){break fa}M=ka(u,(k<<3)+I|0);k=M|(H>>>c+1&16|k<<1&1006);v=M<>>0>=G>>>0){break fa}g=ka(u,(k<<3)+I|0);k=g|(d>>>8-c&16|k<<1&1006);v=g<<7-c|v;c=c+1|0;continue}break}break Da}if((d|0)==(h|0)){break fa}w[d+q|0]=v;d=s;continue}}if(h>>>0<=L>>>0){break fa}w[q+L|0]=v;c=b}n=n+1|0;g=q;k=h;continue}}Aa(da,u,e+180|0);d=y[e+180>>2];if(d>>>0>=2){g=wa(6);y[e+168>>2]=g;h=wa(8);y[e+160>>2]=h;k=wa(11);y[e+228>>2]=k;l=wa(15);y[e+224>>2]=l;n=wa(15);y[e+220>>2]=n;q=wa(15);y[e+216>>2]=q;s=wa(15);y[e+212>>2]=s;r=wa(1);y[e+208>>2]=r;c=Yb();y[e+204>>2]=c;b=z[j|0];y[c+20>>2]=1;y[c+16>>2]=d;y[c+12>>2]=F;y[c+8>>2]=K;w[c+1|0]=1;w[c|0]=b;b=y[j+4>>2]+i|0;y[c+24>>2]=b;d=Ub(e+192|0,b);b=y[j+4>>2];v=y[j+16>>2];if(b>>>0>y[j+20>>2]-v>>2>>>0){break fa}M=b;b=y[d>>2];vd(v,M,b,y[e+196>>2]-b>>2);v=b+(y[j+4>>2]<<2)|0;D=y[O>>2];b=0;while(1)if((b|0)==(i|0)){bb(c+40|0,d);x[c+4>>1]=0;y[c+52>>2]=0;y[c+56>>2]=1;w[c+3|0]=0;y[c+88>>2]=r;y[c+84>>2]=s;y[c+80>>2]=q;y[c+76>>2]=n;y[c+72>>2]=l;y[c+68>>2]=k;y[c+64>>2]=h;y[c+60>>2]=g;w[c+2|0]=z[j+2|0];w[c+92|0]=z[j+52|0];w[c+93|0]=z[j+53|0];w[c+94|0]=z[j+54|0];w[c+95|0]=z[j+55|0];b=Bd(c,u,C,S,P);y[e+176>>2]=0;oa(e+240|0,b);la(e+176|0);b=y[e+240>>2];ya(d);pc(e+204|0);pa(e+208|0);pa(e+212|0);pa(e+216|0);pa(e+220|0);pa(e+224|0);pa(e+228|0);pa(e+160|0);pa(e+168|0);if(!b){break ta}break va}else{H=b<<2;y[H+v>>2]=y[D+H>>2];b=b+1|0;continue}}b=0;if((d|0)!=1){break va}c=y[j+4>>2];Ac(y[P+36>>2],u,e+192|0);b=y[e+192>>2];if(b>>>0>=c+i>>>0){break ta}c=y[j+4>>2];if(c>>>0>b>>>0){b=y[Q>>2]+(b<<2)|0}else{b=b-c|0;c=y[O>>2];if(b>>>0>=y[O+4>>2]-c>>2>>>0){break fa}b=c+(b<<2)|0}c=y[b>>2];if(!c){break ta}Aa(y[P+28>>2],u,e+168|0);Aa(y[P+32>>2],u,e+160|0);b=db();y[e+228>>2]=b;y[b+8>>2]=F;y[b+4>>2]=K;d=z[j+2|0];y[b+20>>2]=c;w[b|0]=d;y[b+12>>2]=y[e+168>>2];c=y[e+160>>2];w[b+1|0]=0;y[b+16>>2]=c;w[b+24|0]=z[j+52|0];w[b+25|0]=z[j+53|0];w[b+26|0]=z[j+54|0];w[b+27|0]=z[j+55|0];b=cb(b,u,C,S);y[e+224>>2]=0;oa(e+240|0,b);la(e+224|0);b=y[e+240>>2];Ua(e+228|0);if(!b){break ta}break va}D=xa(K,F);y[e+160>>2]=D;Ha:{Ia:{if(!qa(D)){break Ia}n=0;Qa(D,0);h=0;c=0;b=0;while(1){Ja:{Ka:{if(B[r+8>>2]>b>>>0){ja(e+192|0,D,b);g=y[e+196>>2];q=y[e+192>>2];if(z[r+1|0]!=1){d=c;break Ka}if(z[u|0]){break Ia}if(!X){break fa}d=0;k=ka(u,_);if((k|0)==(c|0)){break Ka}y[e+184>>2]=g;y[e+180>>2]=q;y[e+172>>2]=h;y[e+168>>2]=n;d=y[e+184>>2];y[e+24>>2]=y[e+180>>2];y[e+28>>2]=d;d=y[e+172>>2];y[e+16>>2]=y[e+168>>2];y[e+20>>2]=d;c=c^k;D=y[e+160>>2];Pa(e+24|0,e+16|0);break Ja}y[e+160>>2]=0;break Ha}H=0;L=0;if(z[r+2|0]==1){ja(e+192|0,y[r+12>>2],b);L=y[e+192>>2];H=y[e+196>>2]}D=y[e+160>>2];ja(e+192|0,D,w[r+17|0]+b|0);T=y[e+196>>2];$=y[e+192>>2];s=z[n|0]>>>6|0;k=y[D+8>>2];c=!h|(k|0)<2?0:s&1;v=!h|(k|0)<=0?c:s&2|c;s=0;c=0;while(1){if(B[r+4>>2]<=c>>>0){c=d;break Ja}La:{Ma:{if(z[r+2|0]==1){if(ia(y[y[r+12>>2]+8>>2],c,L,H)){break Ma}}k=ia(k,w[r+16|0]+c|0,$,T);if(z[u|0]){break Ia}k=v<<5|k<<4|s;if(k>>>0>=G>>>0){break fa}M=ka(u,(k<<3)+I|0);k=y[D+8>>2];if(!M){break Ma}La(k,c,q,g,1);k=y[D+8>>2];M=1;break La}M=0}v=ia(k,c+2|0,n,h)|v<<1&30;c=c+1|0;s=s<<1&14|M;continue}}b=b+1|0;n=q;h=g;continue}}D=0}la(e+160|0);break wa}D=0}la(e+160|0)}y[e+192>>2]=0;oa(e+240|0,D);la(e+192|0);b=y[e+240>>2];ua(e+228|0);if(!b){break ua}}c=y[O>>2];y[e+240>>2]=0;oa((i<<2)+c|0,b)}i=i+1|0;continue}break}b=l^1;break sa}y[e+200>>2]=0;y[e+192>>2]=0;y[e+196>>2]=0;ud(e+192|0,b+y[j+4>>2]|0);g=y[e+192>>2];i=0;b=0;k=0;Na:{while(1){if(y[j+8>>2]+y[j+4>>2]>>>0>b>>>0){Aa(ea,u,e+160|0);d=y[e+160>>2];c=d+b|0;if(!(c>>>0<=y[j+8>>2]+y[j+4>>2]>>>0&c>>>0>=d>>>0)){break Na}Pb(e+180|0,g,0,b);sd(e+168|0,y[e+180>>2],y[e+184>>2],d,i);k=(i&1?d:0)+k|0;i=(i^-1)&1;b=c;continue}break}if(B[j+12>>2]>>0){break Na}N=lc();d=y[O>>2];b=0;l=0;while(1){c=y[j+4>>2];if(c+y[j+8>>2]>>>0<=b>>>0){break Na}if(!(!(y[g+(b>>>3&536870908)>>2]>>>b&1)|B[j+12>>2]<=l>>>0)){Oa:{if(b>>>0>>0){c=y[y[Q>>2]+(b<<2)>>2];if(!c){i=0;break Oa}i=kc(c);break Oa}c=d+(b-c<<2)|0;i=y[c>>2];y[c>>2]=0}rd(N,i);l=l+1|0}b=b+1|0;continue}}Ob(e+192|0);break ra}b=0}la(e+240|0);if(b){continue}}break}$a(O);qc(P);Ea(e+244|0);Ea(e+248|0);Ea(e+252|0);Ea(e+268|0);y[e+120>>2]=0;Rb(m+56|0,N);Za(e+120|0);if(y[m+56>>2]){ta(y[a+4>>2]);b=y[a+4>>2];c=y[b+8>>2];if(c>>>0<=4294967293){g=b;c=c+2|0;b=y[b+4>>2];y[g+8>>2]=b>>>0>c>>>0?c:b}ua(e+60|0);break ba}ua(e+60|0);break $}g=y[e+80>>2];b=y[e+84>>2];n=y[a+4>>2];q=qd(n);y[e+268>>2]=q;C=gb(e+120|0,y[j+8>>2]);y[e+264>>2]=0;y[e+256>>2]=0;y[e+260>>2]=0;if(!z[j+1|0]){xc(e+256|0,y[j+8>>2])}u=b-g>>3;y[e+252>>2]=0;s=0;d=0;Pa:while(1){if(B[j+8>>2]<=d>>>0){break da}if(za(q,y[j+28>>2],e+160|0)){break ea}s=y[e+160>>2]+s|0;if(s>>>0>65535){break ea}F=0;c=0;i=d;while(1){b=za(q,y[j+32>>2],e+248|0);y[e+244>>2]=b;Qa:{Ra:{Sa:{Ta:{Ua:{switch(b|0){case 0:if(B[j+8>>2]<=i>>>0){break ea}c=y[e+248>>2]+c|0;if(c>>>0>65535){break ea}if(!c|!s){break Qa}if(z[j+1|0]!=1){break Ra}if(za(q,y[j+40>>2],e+240|0)){break ea}oa(e+252|0,0);h=y[e+240>>2];if(h>>>0<2){break Ta}v=wa(6);y[e+236>>2]=v;D=wa(8);y[e+232>>2]=D;H=wa(11);y[e+228>>2]=H;I=wa(15);y[e+224>>2]=I;G=wa(15);y[e+220>>2]=G;K=wa(15);y[e+216>>2]=K;O=wa(15);y[e+212>>2]=O;b=1;P=wa(1);y[e+208>>2]=P;l=Yb();y[e+204>>2]=l;k=z[j|0];y[l+20>>2]=1;y[l+16>>2]=h;y[l+12>>2]=s;y[l+8>>2]=c;w[l+1|0]=1;w[l|0]=k;h=y[j+4>>2]+i|0;y[l+24>>2]=h;r=Ed(e+192|0,h);k=y[j+8>>2]+y[j+4>>2]|0;while(1){h=b;b=b+1|0;if(k>>>0>1<>>0){continue}break};h=h&255;k=y[r>>2];L=y[l+24>>2];b=0;while(1)if((b|0)==(L|0)){bb(l+28|0,r);h=Ub(e+180|0,y[l+24>>2]);b=y[j+4>>2];k=y[j+16>>2];if(b>>>0>y[j+20>>2]-k>>2>>>0){break fa}M=b;b=y[h>>2];vd(k,M,b,y[e+184>>2]-b>>2);L=b+(y[j+4>>2]<<2)|0;k=y[C>>2];b=0;while(1)if((b|0)==(i|0)){bb(l+40|0,h);x[l+4>>1]=0;y[l+52>>2]=0;y[l+56>>2]=1;w[l+3|0]=0;y[l+88>>2]=P;y[l+84>>2]=O;y[l+80>>2]=K;y[l+76>>2]=G;y[l+72>>2]=I;y[l+68>>2]=H;y[l+64>>2]=D;y[l+60>>2]=v;w[l+2|0]=z[j+2|0];w[l+92|0]=z[j+52|0];w[l+93|0]=z[j+53|0];w[l+94|0]=z[j+54|0];w[l+95|0]=z[j+55|0];b=Dd(l,n,g,u);y[e+176>>2]=0;oa(e+252|0,b);la(e+176|0);b=y[e+252>>2];ya(h);ya(r);pc(e+204|0);pa(e+208|0);pa(e+212|0);pa(e+216|0);pa(e+220|0);pa(e+224|0);pa(e+228|0);pa(e+232|0);pa(e+236|0);if(b){break Sa}break ea}else{N=b<<2;y[N+L>>2]=y[k+N>>2];b=b+1|0;continue}}else{N=k+(b<<3)|0;y[N+4>>2]=b;y[N>>2]=h;b=b+1|0;continue};case 1:break Ua;default:break ea}}Va:{if(!z[j+1|0]){if(za(q,y[j+36>>2],e+192|0)){break ea}ta(n);y[e+180>>2]=0;Wa:{if(!y[e+192>>2]){if((F|0)>65535){break Va}b=F+7>>>3|0;c=se(b,0,s);if(Z){break Va}h=y[n+4>>2];k=y[n+8>>2];if(h>>>0>>0){break fa}if(c>>>0>h-k>>>0){break Va}c=0;h=xa(F,s);y[e+248>>2]=0;oa(e+180|0,h);la(e+248|0);v=y[e+180>>2];while(1){if((c|0)==(s|0)){break Wa}ja(e+168|0,v,c);l=y[n+8>>2];h=y[n+4>>2];if(l>>>0>h>>>0|b>>>0>h-l>>>0|b>>>0>B[e+172>>2]){break fa}if(b){if(b){p(y[e+168>>2],y[n>>2]+l|0,b)}l=y[n+8>>2]}h=b+l|0;if(h>>>0>=l>>>0){k=y[n+4>>2];y[n+8>>2]=h>>>0>>0?h:k}c=c+1|0;continue}}b=qb();y[e+248>>2]=b;y[b+8>>2]=s;y[b+4>>2]=F;w[b|0]=1;hb(b,e+180|0,n);ta(n);ua(e+248|0);v=y[e+180>>2]}Xa:{if(!v){break Xa}c=d>>>0>i>>>0?d:i;h=y[C>>2];b=0;k=y[e+256>>2];while(1){if((c|0)==(d|0)){break Xa}l=d<<2;r=l+k|0;F=sb(v,b,0,y[r>>2],s);y[e+248>>2]=0;oa(h+l|0,F);d=d+1|0;la(e+248|0);b=y[r>>2]+b|0;continue}}la(e+180|0)}d=i;continue Pa}la(e+180|0);break ea}if((h|0)!=1){k=y[C>>2];b=y[e+252>>2];break Sa}r=y[j+8>>2]+y[j+4>>2]|0;b=1;l=1;while(1){k=b;b=b+1|0;h=l;l=h+1|0;if(r>>>0>1<>>0){continue}break}y[e+192>>2]=h;h=k&255;l=0;b=0;while(1){if((b|0)!=(h|0)){if(wb(n,e+192|0)){break ea}b=b+1|0;l=y[e+192>>2]|l<<1;continue}break}b=y[j+4>>2];if(b+i>>>0<=l>>>0){break ea}k=y[C>>2];if(b>>>0>l>>>0){b=y[Q>>2]+(l<<2)|0}else{b=l-b|0;if(b>>>0>=y[C+4>>2]-k>>2>>>0){break fa}b=(b<<2)+k|0}h=y[b>>2];if(!h){break ea}b=wa(15);y[e+180>>2]=b;l=wa(1);y[e+236>>2]=l;Ya:{if(za(q,b,e+232|0)){break Ya}if(za(q,b,e+228|0)){break Ya}if(za(q,l,e+244|0)){break Ya}ta(n);r=y[n+8>>2];y[e+192>>2]=r;b=db();y[e+224>>2]=b;y[b+8>>2]=s;y[b+4>>2]=c;l=z[j+2|0];y[b+20>>2]=h;w[b|0]=l;y[b+12>>2]=y[e+232>>2];h=y[e+228>>2];l=0;w[b+1|0]=0;y[b+16>>2]=h;w[b+24|0]=z[j+52|0];w[b+25|0]=z[j+53|0];w[b+26|0]=z[j+54|0];w[b+27|0]=z[j+55|0];h=Ra(n);y[e+220>>2]=h;b=cb(b,h,g,u);y[e+216>>2]=0;oa(e+252|0,b);la(e+216|0);b=y[e+252>>2];if(b){ta(n);l=y[n+8>>2];if(l>>>0<=4294967293){h=l+2|0;l=y[n+4>>2];l=h>>>0>>0?h:l;y[n+8>>2]=l}l=y[e+244>>2]==(l-r|0)}ua(e+220|0);Ua(e+224|0);pa(e+236|0);pa(e+180|0);if(l){break Sa}break ea}pa(e+236|0);pa(e+180|0);break ea}y[e+252>>2]=0;oa((i<<2)+k|0,b);if(z[j+1|0]){break Qa}}y[y[e+256>>2]+(i<<2)>>2]=c}F=c+F|0;i=i+1|0;continue}}}o()}b=0;break ca}i=wa(1);y[e+248>>2]=i;y[e+200>>2]=0;y[e+192>>2]=0;y[e+196>>2]=0;ud(e+192|0,y[j+8>>2]+y[j+4>>2]|0);g=y[e+192>>2];l=0;b=0;k=0;Za:{while(1){if(y[j+8>>2]+y[j+4>>2]>>>0>b>>>0){_a:{$a:{if(za(q,i,e+244|0)){break $a}d=y[e+244>>2];c=d+b|0;if(c>>>0>>0){break $a}if(c>>>0<=y[j+8>>2]+y[j+4>>2]>>>0){break _a}}b=0;break Za}Pb(e+180|0,g,0,b);sd(e+160|0,y[e+180>>2],y[e+184>>2],d,l);k=(l&1?d:0)+k|0;l=(l^-1)&1;b=c;continue}break}b=0;if(B[j+12>>2]>>0){break Za}b=lc();d=y[C>>2];l=0;i=0;while(1){c=y[j+4>>2];if(c+y[j+8>>2]>>>0<=l>>>0){break Za}if(!(!(y[g+(l>>>3&536870908)>>2]>>>l&1)|B[j+12>>2]<=i>>>0)){ab:{if(c>>>0>l>>>0){c=y[y[Q>>2]+(l<<2)>>2];if(!c){c=0;break ab}c=kc(c);break ab}h=d+(l-c<<2)|0;c=y[h>>2];y[h>>2]=0}rd(b,c);i=i+1|0}l=l+1|0;continue}}Ob(e+192|0);pa(e+248|0)}la(e+252|0);Ja(e+256|0);$a(C);Ua(e+268|0);y[e+120>>2]=0;Rb(m+56|0,b);Za(e+120|0);if(!y[m+56>>2]){break $}ta(y[a+4>>2])}if(z[a+48|0]!=1){break aa}fa=e,ga=Ad(y[m+56>>2]),y[fa+120>>2]=ga;b=y[a+108>>2];l=y[b+8>>2];while(1){if(l>>>0>=2){c=y[b>>2];d=y[c>>2];g=y[c+4>>2];y[d+4>>2]=g;y[g>>2]=d;y[b+8>>2]=y[b+8>>2]-1;oc(c);l=l-1|0;b=y[a+108>>2];continue}break}c=b;b=e+120|0;zd(c,e- -64|0,b);Za(b)}l=0;if(!(z[e+119|0]&2)){break _}if(!(V&1)){b=y[m+56>>2];y[e+48>>2]=y[e+92>>2];c=y[e+96>>2];d=y[e+100>>2];y[e+96>>2]=0;y[e+100>>2]=0;y[e+52>>2]=c;y[e+56>>2]=d;y[e+92>>2]=0;c=b;b=e+48|0;pd(c,b);Ja(b)}if(!(W&1)){break _}b=y[m+56>>2];y[e+36>>2]=y[e+80>>2];c=y[e+84>>2];d=y[e+88>>2];y[e+84>>2]=0;y[e+88>>2]=0;y[e+40>>2]=c;y[e+44>>2]=d;y[e+80>>2]=0;c=b+12|0;b=e+36|0;pd(c,b);Ja(b);break _}l=1}Ja(e+80|0);Ja(e+92|0)}ya(U);break W}else{d=Ma(a,y[y[m+12>>2]+(b<<2)>>2]);if(!(z[d+4|0]&63)){g=0;if(c&1){c=y[d+56>>2];c=y[c+28>>2]-y[c+24>>2]>>2;g=c+k|0;n=g;g=c>>>0<=g>>>0;k=g?n:0}else{k=0}s=d;c=g}b=b+1|0;continue}}c=b<<2;b=b+1|0;if(Ma(a,y[c+y[m+12>>2]>>2])){continue}break}}ya(Q);ma(j)}Y=e+272|0;b=l;break u;case 1:case 2:case 3:case 5:break B;case 4:case 6:case 7:break V;default:break K}}b=1;if(z[a+49|0]!=1){break u}if(tb(a,f+332|0)){break u}d=f+14|0;if(Wa(y[a+4>>2],d)){break u}c=y[f+332>>2];if(c-1>>>0>65534){break u}q=y[f+336>>2];if(q-1>>>0>65534){break u}h=Yb();y[f+308>>2]=h;y[h+12>>2]=q;y[h+8>>2]=c;c=A[f+14>>1];g=c&1;w[h|0]=g;w[h+2|0]=c>>>15;y[h+56>>2]=c>>>4&3;y[h+52>>2]=c>>>7&3;w[h+3|0]=c>>>6&1;w[h+4|0]=c>>>9&1;y[h+20>>2]=1<<(c>>>2&3);i=(c&254)>>>1&1;w[h+1|0]=i;k=c>>>10&31;w[h+5|0]=(k>>>0>15?-32:0)|k;bb:{if(g){if(Wa(y[a+4>>2],d)){break v}if(z[h+1|0]!=1){break w}if(!z[h+2|0]){break bb}break w}if(!i|c<<16>>16<0){break w}}c=h+92|0;d=0;while(1){if((d|0)==4){break w}g=c+d|0;d=d+1|0;if(!va(y[a+4>>2],g)){continue}break}break v}g=na(12);y[g+8>>2]=0;y[g>>2]=0;y[g+4>>2]=0;if(va(y[a+4>>2],f+352|0)){break y}b=1;if(va(y[a+4>>2],g+1|0)){break x}if(va(y[a+4>>2],g+2|0)){break x}if(ra(y[a+4>>2],g+4|0)){break x}i=y[g+4>>2];if(i>>>0>65535){break x}b=z[f+352|0];d=b&1;w[g|0]=d;b=b>>>1&3;w[g+8|0]=b;y[m+52>>2]=3;if(d){d=y[a+4>>2];b=wc(g);y[f+24>>2]=b;if(b){y[f+332>>2]=0;hb(b,f+332|0,d);cb:{d=y[f+332>>2];if(!d){break cb}c=vc(i+1|0);b=0;while(1){if(b>>>0>i>>>0){break cb}h=z[g+1|0];h=sb(d,E(h,b),0,h,z[g+2|0]);k=y[c+4>>2];y[f+312>>2]=0;oa((b<<2)+k|0,h);b=b+1|0;la(f+312|0);continue}}la(f+332|0)}ua(f+24|0);y[f+332>>2]=0;Xb(m+60|0,c);Zb(f+332|0);if(!y[m+60>>2]){break y}ta(y[a+4>>2]);b=0;break x}k=b?(b|0)==1?8192:1024:65536;l=ab(k,8);y[f+336>>2]=k;y[f+332>>2]=l;n=Ra(y[a+4>>2]);y[f+16>>2]=n;d=wc(g);y[f+312>>2]=d;if(!d){break z}w[d+1|0]=0;w[d+2|0]=0;w[d+3|0]=b;h=z[g+1|0];w[d+17|0]=0;w[d+16|0]=0-h;if(!b){w[d+22|0]=254;w[d+23|0]=254;w[d+18|0]=253;w[d+19|0]=255;w[d+20|0]=2;w[d+21|0]=254}y[f+356>>2]=0;y[f+40>>2]=0;y[f+32>>2]=l;y[f+36>>2]=k;y[f+28>>2]=n;y[f+24>>2]=f+356;b=Wb(d,f+24|0);y[f+40>>2]=0;while(1){if((b|0)==3){b=Vb(d,f+24|0);continue}break}y[d+44>>2]=0;y[d+48>>2]=0;y[d+36>>2]=0;y[d+40>>2]=0;y[d+28>>2]=0;y[d+32>>2]=0;if(!y[f+356>>2]){break A}c=vc(i+1|0);b=0;while(1){if(b>>>0>i>>>0){break A}d=sb(y[f+356>>2],E(b,h),0,h,z[g+2|0]);k=y[c+4>>2];y[f>>2]=0;oa((b<<2)+k|0,d);b=b+1|0;la(f);continue}}b=1;if(z[a+49|0]!=1){break u}q=na(56);y[q+16>>2]=0;db:{if(tb(a,f+312|0)){break db}if(va(y[a+4>>2],f+14|0)){break db}if(ra(y[a+4>>2],q+32|0)){break db}if(ra(y[a+4>>2],q+36|0)){break db}if(ra(y[a+4>>2],q+40|0)){break db}if(ra(y[a+4>>2],q+44|0)){break db}if(Wa(y[a+4>>2],q+48|0)){break db}if(Wa(y[a+4>>2],q+50|0)){break db}C=y[q+32>>2];if(C-1>>>0>65534){break db}e=y[q+36>>2];if(e-1>>>0>65534){break db}v=y[f+312>>2];if(v-1>>>0>65534){break db}k=y[f+316>>2];if(k-1>>>0>65534){break db}y[q+4>>2]=k;y[q>>2]=v;d=z[f+14|0];F=d&1;w[q+8|0]=F;w[q+20|0]=d>>>7;i=d>>>3|0;K=i&1;w[q+28|0]=K;s=d>>>1&3;w[q+9|0]=s;g=d>>>4|0;y[q+24>>2]=(g&7)==4?4:g&3;if(y[m+8>>2]!=1){break db}g=Ma(a,y[y[m+12>>2]>>2]);if(!g|(z[g+4|0]&63)!=16){break db}g=y[g+60>>2];if(!g){break db}j=y[g>>2];if(!j){break db}y[q+12>>2]=j;y[q+16>>2]=g+4;b=y[y[g+4>>2]>>2];g=y[b+8>>2];w[q+52|0]=g;r=y[b+12>>2];w[q+53|0]=r;y[m+52>>2]=1;eb:{fb:{gb:{if(d&1){d=y[a+4>>2];b=1;while(1){c=b;b=b+1|0;if(j>>>0>1<>>0){continue}break}x[f+80>>1]=0;y[f+36>>2]=0;y[f+48>>2]=0;y[f+52>>2]=0;y[f+56>>2]=0;y[f+60>>2]=0;y[f+64>>2]=0;y[f+68>>2]=0;y[f+72>>2]=0;y[f+84>>2]=0;y[f+88>>2]=0;y[f+92>>2]=0;y[f+96>>2]=0;y[f+100>>2]=0;y[f+32>>2]=e;y[f+28>>2]=C;w[f+24|0]=F;b=c&255;g=gb(f+332|0,b);i=y[g>>2];c=(i+(b<<2)|0)-4|0;hb(f+24|0,c,d);h=0;hb:{if(!y[c>>2]){break hb}ta(d);c=y[d+8>>2];if(c>>>0<=4294967292){c=c+3|0;h=y[d+4>>2];y[d+8>>2]=c>>>0>>0?c:h}b=b-2|0;while(1){if((b|0)>=0){c=i+(b<<2)|0;hb(f+24|0,c,d);h=0;if(!y[c>>2]){break hb}ta(d);h=y[d+8>>2];if(h>>>0<=4294967292){h=h+3|0;l=y[d+4>>2];y[d+8>>2]=h>>>0>>0?h:l}fb(y[c>>2],0,0,0,0,y[c+4>>2],2);b=b-1|0;continue}break}h=uc(q,g)}b=h;$a(g);y[f+356>>2]=0;oa(m- -64|0,b);la(f+356|0);if(!y[m+64>>2]){break eb}ta(y[a+4>>2]);break gb}b=s?(s|0)==1?8192:1024:65536;d=ab(b,8);y[f+4>>2]=b;y[f>>2]=d;Q=Ra(y[a+4>>2]);y[f+308>>2]=Q;n=0;y[f+16>>2]=0;l=b;ib:{if(!(i&1)){break ib}b=xa(C,e);y[f+24>>2]=0;oa(f+16|0,b);b=r&255;O=1-b|0;D=0-(b>>>0>1)|0;b=g&255;P=1-b|0;H=0-(b>>>0>1)|0;la(f+24|0);n=y[f+16>>2];jb:while(1){if(!c&(e|0)==(h|0)){break ib}ja(f+24|0,n,h);b=y[q+44>>2];L=A[q+48>>1];g=se(h,c,L);r=b+g|0;b=Z+(b>>31)|0;V=g>>>0>r>>>0?b+1|0:b;b=y[q+40>>2];N=A[q+50>>1];g=se(h,c,N);I=b+g|0;b=Z+(b>>31)|0;U=g>>>0>I>>>0?b+1|0:b;g=0;i=0;W=y[f+28>>2];_=y[f+24>>2];while(1)if(!i&(g|0)==(C|0)){h=h+1|0;c=h?c:c+1|0;continue jb}else{S=y[n+8>>2];b=se(g,i,N);u=r-b|0;G=V-(Z+(b>>>0>r>>>0)|0)|0;b=G>>8;X=(G&255)<<24|u>>>8;T=se(g,i,L);u=T+I|0;G=Z+U|0;M=S;G=u>>>0>>0?G+1|0:G;S=(G&255)<<24|u>>>8;u=G>>8;La(M,g,_,W,k>>>0<=X>>>0&(b|0)>=0|(b|0)>0|(P>>>0>S>>>0&(H|0)>=(u|0)|(u|0)<(H|0)|((b|0)<=(D|0)&O>>>0>X>>>0|(b|0)<(D|0))|(v>>>0<=S>>>0&(u|0)>=0|(u|0)>0)));g=g+1|0;i=g?i:i+1|0;continue}}}g=d;b=1;while(1){c=b;b=b+1|0;if(j>>>0>1<>>0){continue}break}y[f+48>>2]=0;y[f+52>>2]=0;x[f+80>>1]=0;y[f+56>>2]=0;y[f+60>>2]=0;y[f+64>>2]=0;y[f+68>>2]=0;y[f+72>>2]=0;y[f+84>>2]=0;y[f+88>>2]=0;y[f+92>>2]=0;y[f+96>>2]=0;y[f+100>>2]=0;y[f+32>>2]=e;y[f+28>>2]=C;w[f+24|0]=F;y[f+36>>2]=n;w[f+26|0]=K;w[f+25|0]=0;w[f+27|0]=s;kb:{if(s>>>0>=2){x[f+40>>1]=65282;break kb}x[f+40>>1]=65283;if(s){break kb}x[f+46>>1]=65278;x[f+42>>1]=65533;x[f+44>>1]=65026}b=c&255;c=gb(f+356|0,b);h=y[c>>2];n=b-1|0;d=n;lb:{mb:{while(1){if((d|0)<0){break mb}y[f+352>>2]=0;y[f+348>>2]=0;y[f+340>>2]=g;y[f+344>>2]=l;y[f+336>>2]=Q;y[f+332>>2]=f+352;b=Wb(f+24|0,f+332|0);y[f+348>>2]=0;while(1){if((b|0)==3){b=Vb(f+24|0,f+332|0);continue}break}y[f+68>>2]=0;y[f+72>>2]=0;y[f+60>>2]=0;y[f+64>>2]=0;y[f+52>>2]=0;y[f+56>>2]=0;b=y[f+352>>2];nb:{if(!b){break nb}y[f+352>>2]=0;i=h+(d<<2)|0;oa(i,b);if((d|0)>=(n|0)){break nb}fb(y[i>>2],0,0,0,0,y[i+4>>2],2)}d=d-1|0;la(f+352|0);if(b){continue}break}b=0;break lb}b=uc(q,c)}$a(c);la(f+16|0);y[f+24>>2]=0;oa(m- -64|0,b);la(f+24|0);if(!y[m+64>>2]){break fb}ta(y[a+4>>2]);b=y[a+4>>2];c=y[b+8>>2];if(c>>>0<=4294967293){g=b;c=c+2|0;b=y[b+4>>2];y[g+8>>2]=b>>>0>c>>>0?c:b}ua(f+308|0);Ha(f)}if((z[m+4|0]&63)==20){b=0;break db}ob:{if(z[a+50|0]){break ob}b=y[y[a+24>>2]-4>>2];if(z[b+17|0]!=1){break ob}c=k+y[f+324>>2]|0;d=y[a+32>>2];if((c|0)<=y[d+12>>2]){break ob}eb(d,c,z[b+16|0])}b=y[f+320>>2];g=b;h=b>>31;b=y[f+324>>2];c=b;d=b>>31;b=z[f+328|0];fb(y[a+32>>2],g,h,c,d,y[m+64>>2],(b&7)==4?4:b&3);b=0;oa(m- -64|0,0);break db}ua(f+308|0);Ha(f)}b=1}ma(q);break u}b=1;if(z[a+49|0]!=1){break u}g=a+76|0;d=y[a+76>>2];if(!d){c=qb();y[f+24>>2]=c;pb:{qb:{if(tb(a,a+88|0)){break qb}if(va(y[a+4>>2],f+332|0)){break qb}d=y[a+92>>2];if((d|0)<0){break qb}i=y[a+88>>2];if((i|0)<0){break qb}y[c+8>>2]=d;y[c+4>>2]=i;d=z[f+332|0];i=d&1;w[c|0]=i;h=d>>>1&3;w[c+3|0]=h;w[c+1|0]=d>>>3&1;if(i){break pb}i=c+16|0;d=0;if(!h){while(1){if((d|0)==8){break pb}h=d+i|0;d=d+1|0;if(!va(y[a+4>>2],h)){continue}break qb}}while(1){if((d|0)==2){break pb}h=d+i|0;d=d+1|0;if(!va(y[a+4>>2],h)){continue}break}}ua(f+24|0);break u}w[c+2|0]=0;y[f+24>>2]=0;Va(g,c);ua(f+24|0);d=y[g>>2]}y[m+52>>2]=1;rb:{if(z[d|0]==1){hb(d,m- -64|0,y[a+4>>2]);if(!y[m+64>>2]){Va(g,0);break D}ta(y[a+4>>2]);break rb}if(y[a+60>>2]==y[a+64>>2]){b=z[d+3|0];kb(a+60|0,b?(b|0)==1?8192:1024:65536)}c=a+72|0;h=f;b=y[a+72>>2];if(b){d=b}else{d=Ra(y[a+4>>2]);y[f+24>>2]=0;Va(c,d);ua(f+24|0);d=y[a+72>>2]}y[h+28>>2]=d;d=m- -64|0;y[f+24>>2]=d;h=y[a+64>>2];i=y[a+60>>2];y[f+40>>2]=0;y[f+32>>2]=i;y[f+36>>2]=h-i>>3;i=y[a+76>>2];sb:{if(!b){b=Wb(i,f+24|0);break sb}b=Vb(i,f+24|0)}y[a+56>>2]=b;if((b|0)==3){if((z[m+4|0]&63)==36){break B}tb:{if(z[a+50|0]){break tb}b=y[y[a+24>>2]-4>>2];if(z[b+17|0]!=1){break tb}c=y[a+92>>2]+y[a+100>>2]|0;g=y[a+32>>2];if((c|0)<=y[g+12>>2]){break tb}eb(g,c,z[b+16|0])}b=y[a+76>>2];c=y[b+64>>2]+y[a+96>>2]|0;g=c;i=c>>31;c=y[b+68>>2]+y[a+100>>2]|0;h=b- -64|0;b=z[a+104|0];tc(y[a+32>>2],g,i,c,c>>31,y[d>>2],h,(b&7)==4?4:b&3);break B}b=y[a+76>>2];y[b+44>>2]=0;y[b+48>>2]=0;y[b+36>>2]=0;y[b+40>>2]=0;y[b+28>>2]=0;y[b+32>>2]=0;Va(c,0);y[a+64>>2]=y[a+60>>2];if(!y[d>>2]){y[a+56>>2]=-1;Va(g,0);break D}ta(y[a+4>>2]);b=y[a+4>>2];c=y[b+8>>2];if(c>>>0>4294967293){break rb}d=b;c=c+2|0;b=y[b+4>>2];y[d+8>>2]=b>>>0>c>>>0?c:b}if((z[m+4|0]&63)!=36){ub:{if(z[a+50|0]){break ub}b=y[y[a+24>>2]-4>>2];if(z[b+17|0]!=1){break ub}c=y[a+92>>2]+y[a+100>>2]|0;d=y[a+32>>2];if((c|0)<=y[d+12>>2]){break ub}eb(d,c,z[b+16|0])}b=y[a+76>>2];c=y[b+64>>2]+y[a+96>>2]|0;d=c;i=c>>31;c=y[b+68>>2]+y[a+100>>2]|0;h=b- -64|0;b=z[a+104|0];tc(y[a+32>>2],d,i,c,c>>31,y[m+64>>2],h,(b&7)==4?4:b&3);oa(m- -64|0,0)}b=0;Va(g,0);break u}b=1;if(z[a+49|0]!=1){break u}if(tb(a,f+24|0)){break u}if(va(y[a+4>>2],f+352|0)){break u}i=y[f+24>>2];if(i-1>>>0>65534){break u}g=y[f+28>>2];if(g-1>>>0>65534){break u}d=0;y[f+312>>2]=0;c=db();y[f+356>>2]=c;y[c+8>>2]=g;y[c+4>>2]=i;b=z[f+352|0];h=b&1;w[c|0]=h;w[c+1|0]=b>>>1&1;vb:{wb:{if(h){break wb}h=c+24|0;while(1){if((d|0)==4){break wb}b=1;k=d+h|0;d=d+1|0;if(!va(y[a+4>>2],k)){continue}break}break vb}h=y[m+8>>2];xb:{if((h|0)>0){d=0;b=1;while(1){if((d|0)==(h|0)){break vb}i=Ma(a,y[y[m+12>>2]>>2]);if(!i){break vb}k=(z[i+4|0]&63)-4|0;k=(k<<6|(k&252)>>>2)&255;if(!(1<>>0<=9:0)){d=d+1|0;continue}break}b=i- -64|0;break xb}d=sb(y[a+32>>2],y[f+32>>2],y[f+36>>2],i,g);y[f+332>>2]=0;b=f+312|0;oa(b,d);la(f+332|0)}b=y[b>>2];y[c+12>>2]=0;y[c+16>>2]=0;y[c+20>>2]=b;d=z[c|0];i=d?1024:8192;b=ab(i,8);y[f+336>>2]=i;y[f+332>>2]=b;i=Ra(y[a+4>>2]);y[f>>2]=i;y[m+52>>2]=1;c=cb(c,i,b,d?1024:8192);y[f+16>>2]=0;b=m- -64|0;oa(b,c);la(f+16|0);c=1;yb:{if(!y[m+64>>2]){break yb}ta(y[a+4>>2]);c=y[a+4>>2];d=y[c+8>>2];if(d>>>0<=4294967293){h=c;d=d+2|0;c=y[c+4>>2];y[h+8>>2]=c>>>0>d>>>0?d:c}c=0;if((z[m+4|0]&63)==40){break yb}zb:{if(z[a+50|0]){break zb}c=y[y[a+24>>2]-4>>2];if(z[c+17|0]!=1){break zb}d=g+y[f+36>>2]|0;g=y[a+32>>2];if((d|0)<=y[g+12>>2]){break zb}eb(g,d,z[c+16|0])}c=y[f+32>>2];d=c;i=c>>31;c=y[f+36>>2];g=c;h=c>>31;c=z[f+40|0];fb(y[a+32>>2],d,i,g,h,y[b>>2],(c&7)==4?4:c&3);oa(b,0);c=0}b=c;ua(f);Ha(f+332|0)}Ua(f+356|0);la(f+312|0);break u}c=na(20);y[c+16>>2]=0;y[c+8>>2]=0;y[c+12>>2]=0;y[c>>2]=0;y[c+4>>2]=0;y[f+24>>2]=c;if(ra(y[a+4>>2],c)){break E}if(ra(y[a+4>>2],c+4|0)){break E}if(ra(y[a+4>>2],c+8|0)){break E}if(ra(y[a+4>>2],c+12|0)){break E}if(va(y[a+4>>2],f+356|0)){break E}if(Wa(y[a+4>>2],f+312|0)){break E}w[c+16|0]=z[f+356|0]>>>2&1;g=A[f+312>>1];b=g&32767;x[c+18>>1]=b;w[c+17|0]=g>>>15;d=y[c+4>>2];if((d|0)!=-1){break J}if(g<<16>>16>=0){w[c+17|0]=1}if(z[a+50|0]){break F}d=b;break G}w[a+49|0]=0;break u}c=y[a+4>>2];d=y[c+8>>2];b=d+y[m+28>>2]|0;if(b>>>0>>0){break B}g=c;c=y[c+4>>2];y[g+8>>2]=b>>>0>>0?b:c;break B}c=y[a+4>>2];d=y[c+8>>2];b=d+y[m+28>>2]|0;if(b>>>0>>0){break B}g=c;c=y[c+4>>2];y[g+8>>2]=b>>>0>>0?b:c;break B}y[m+52>>2]=4;k=m+68|0;vb(k,0);g=y[a+4>>2];d=na(44);w[d+1|0]=0;t(d+4|0,0,40);if((va(g,f+356|0)|0)==-1){break I}b=1;i=z[f+356|0];w[d+1|0]=i&1;Ab:{Bb:{if((ra(g,f+332|0)|0)==-1){break Bb}if((ra(g,f+312|0)|0)==-1){break Bb}c=y[f+332>>2];h=y[f+312>>2];if((c|0)>(h|0)){break Bb}l=(i>>>4&7)+1|0;i=(i>>>1&7)+1|0;pb(d,0);y[f+28>>2]=c;w[f+24|0]=1;b=c;while(1){if((Ia(g,i,y[d+8>>2]+(y[d+4>>2]<<3)|0)|0)==-1){break Ab}if((Ia(g,l,y[d+20>>2]+(y[d+4>>2]<<2)|0)|0)==-1){break Ab}n=y[d+20>>2];q=y[d+4>>2]<<2;if(B[n+q>>2]>63){break Ab}y[q+y[d+32>>2]>>2]=b;b=y[n+(y[d+4>>2]<<2)>>2];if((b|0)>31){break Ab}if(z[Na(f+24|0,1<>2];if((h|0)>(b|0)){continue}break}if((Ia(g,i,y[d+8>>2]+(y[d+4>>2]<<3)|0)|0)==-1){break Ab}y[y[d+20>>2]+(y[d+4>>2]<<2)>>2]=32;if((c|0)==-2147483648){break Ab}y[y[d+32>>2]+(y[d+4>>2]<<2)>>2]=c-1;pb(d,1);if((Ia(g,i,y[d+8>>2]+(y[d+4>>2]<<3)|0)|0)==-1){break Ab}y[y[d+20>>2]+(y[d+4>>2]<<2)>>2]=32;y[y[d+32>>2]+(y[d+4>>2]<<2)>>2]=h;pb(d,1);b=y[d+4>>2];if(z[d+1|0]==1){if((Ia(g,i,y[d+8>>2]+(b<<3)|0)|0)==-1){break Ab}b=y[d+4>>2]+1|0;y[d+4>>2]=b}c=y[d+8>>2];if(y[d+12>>2]-c>>3>>>0>>0){break t}c=ob(c,b);w[d|0]=c;y[f+24>>2]=d;b=1;if(!c){break H}b=0;y[f+24>>2]=0;vb(k,d);ta(y[a+4>>2]);break H}w[d|0]=0;y[f+24>>2]=d;break H}break I}if((d|0)!=62){break B}c=y[a+4>>2];d=y[c+8>>2];b=d+y[m+28>>2]|0;if(b>>>0>>0){break B}g=c;c=y[c+4>>2];y[g+8>>2]=b>>>0>>0?b:c;break B}if(!z[a+50|0]){break G}break F}w[d|0]=0;y[f+24>>2]=d;b=1}pa(f+24|0);break u}b=xa(y[c>>2],d);y[f+332>>2]=0;oa(a+32|0,b);la(f+332|0)}if(qa(y[a+32>>2])){break C}y[a+56>>2]=-1}$b(f+24|0)}b=1;break u}Qa(y[a+32>>2],z[c+16|0]);Cb:{Db:{b=y[a+24>>2];h=y[a+28>>2];Eb:{if(b>>>0>>0){y[f+24>>2]=0;y[b>>2]=c;b=b+4|0;break Eb}d=y[a+20>>2];g=b-d|0;k=g>>2;i=k+1|0;if(i>>>0>=1073741824){break Db}b=0;h=h-d|0;l=h>>1;i=h>>>0>=2147483644?1073741823:i>>>0>>0?l:i;if(i){if(i>>>0>=1073741824){break Cb}b=na(i<<2)}y[f+24>>2]=0;h=b+g|0;y[h>>2]=c;c=h-(k<<2)|0;if(g){p(c,d,g)}y[a+28>>2]=(i<<2)+b;b=h+4|0;y[a+24>>2]=b;y[a+20>>2]=c;if(!d){break Eb}ma(d)}w[a+49|0]=1;y[a+24>>2]=b;$b(f+24|0);break B}Ba();o()}jb();o()}b=0;break u}la(f+356|0)}ua(f+312|0);y[f+24>>2]=0;Xb(m+60|0,c);Zb(f+24|0);if(y[m+60>>2]){ta(y[a+4>>2]);b=y[a+4>>2];c=y[b+8>>2];if(c>>>0<=4294967293){d=b;c=c+2|0;b=y[b+4>>2];y[d+8>>2]=b>>>0>c>>>0?c:b}ua(f+16|0);Ha(f+332|0);b=0;break x}ua(f+16|0);Ha(f+332|0)}b=1}ma(g);break u}if(ra(y[a+4>>2],h+16|0)){break v}c=y[a+4>>2];g=y[c>>2];c=y[c+4>>2];if((c|0)<0){break t}d=c>>>27&15;c=((c&134217727)<<5|g>>>27)&-32;if(!d&c>>>0>=2147483648|d){break t}if(!d&B[h+16>>2]>c>>>0){break v}n=0;b=y[m+8>>2];c=(b|0)>0?b:0;d=0;while(1){if((c|0)==(d|0)){i=1;b=0;while(1)if((b|0)==(c|0)){if(!(i&1)){break t}y[h+24>>2]=n;l=Ub(f+356|0,n);k=y[l>>2];Fb:{if((k|0)==y[l+4>>2]){break Fb}b=y[m+8>>2];s=(b|0)>0?b:0;i=1;n=0;c=0;while(1){if((c|0)==(s|0)){break Fb}Gb:{b=Ma(a,y[y[m+12>>2]+(c<<2)>>2]);if(z[b+4|0]&63){break Gb}b=y[b+56>>2];g=y[b+24>>2];d=y[b+28>>2]-g>>2;b=0;while(1){if((b|0)==(d|0)){g=0;if(i&1){b=d+n|0;d=b>>>0>=d>>>0;g=d;n=d?b:0}else{n=0}i=g;break Gb}C=b+n|0;if(!(C>>>0>=b>>>0&i)){break t}y[k+(C<<2)>>2]=y[g+(b<<2)>>2];b=b+1|0;continue}}c=c+1|0;continue}}bb(h+40|0,l);Hb:{Ib:{Jb:{Kb:{if(!z[h|0]){c=y[h+24>>2];b=0;while(1){d=b;b=b+1|0;if(c>>>0>1<>>0){continue}break}break Kb}n=y[h+24>>2];b=0;while(1){if((b|0)!=35){c=b<<3;b=b+1|0;if(!Ia(y[a+4>>2],4,c+(f+24|0)|0)){continue}break Jb}break}if(!ob(f+24|0,35)){break Jb}i=Ed(f+312|0,n);k=y[i>>2];c=0;Lb:while(1){Mb:{Nb:{Ob:{if((c|0)<(n|0)){d=0;y[f+20>>2]=0;w[f+16|0]=1;Pb:while(1){if(wb(y[a+4>>2],f+352|0)){break Nb}g=Tb(f+16|0);if(z[g|0]!=1){break Nb}b=0;C=y[f+20>>2]|y[f+352>>2];s=(C|0)>=0;y[g>>2]=s;j=g;g=s?C:0;y[j+4>>2]=g;if(!s){break t}d=d+1|0;while(1){if((b|0)==35){continue Pb}s=(f+24|0)+(b<<3)|0;if(!(y[s>>2]==(d|0)&(g|0)==y[s+4>>2])){b=b+1|0;continue}break}break}if(b>>>0<=31){y[k+(c<<3)>>2]=b;break Mb}g=y[a+4>>2];Qb:{switch(b-33|0){default:if(Ia(g,2,f+352|0)){break Nb}d=3;break Ob;case 1:if(Ia(g,7,f+352|0)){break Nb}d=11;break Ob;case 0:break Qb}}d=3;if(!Ia(g,3,f+352|0)){break Ob}break Nb}b=y[i+4>>2];if(!ob(k,b-k>>3)){break Nb}y[f+4>>2]=b;y[f>>2]=k;y[f+8>>2]=y[i+8>>2];d=0;y[i+8>>2]=0;y[i>>2]=0;y[i+4>>2]=0;ya(i);if((b|0)==(k|0)){break Ib}ta(y[a+4>>2]);bb(h+28|0,f);ya(f);b=1;if(z[h|0]!=1){break Kb}c=A[f+14>>1];g=c>>>12&3;if((g|0)==2){break Hb}k=c>>>10&3;if((k|0)==2){break Hb}n=c>>>8&3;if((n|0)==2){break Hb}i=c&3;if((i|0)==2){break Hb}s=c>>>6&3;if((s|0)==2){break Hb}Rb:{Sb:{switch(i|0){case 0:i=0;j=sa(a,6);break Rb;case 1:i=0;j=sa(a,7);break Rb;default:break Sb}}C=Ga(a,m,0);if(!C){break Hb}i=1;j=y[C+68>>2]}y[h+60>>2]=j;Tb:{Ub:{switch((c>>>2&3)-1|0){default:j=sa(a,8);break Tb;case 0:j=sa(a,9);break Tb;case 1:j=sa(a,10);break Tb;case 2:break Ub}}C=Ga(a,m,i);if(!C){break Hb}i=i+1|0;j=y[C+68>>2]}y[h+64>>2]=j;Vb:{Wb:{switch((c>>>4&3)-1|0){default:j=sa(a,11);break Vb;case 0:j=sa(a,12);break Vb;case 1:j=sa(a,13);break Vb;case 2:break Wb}}C=Ga(a,m,i);if(!C){break Hb}i=i+1|0;j=y[C+68>>2]}y[h+68>>2]=j;Xb:{Yb:{switch(s|0){case 0:j=sa(a,14);break Xb;case 1:j=sa(a,15);break Xb;default:break Yb}}s=Ga(a,m,i);if(!s){break Hb}i=i+1|0;j=y[s+68>>2]}y[h+72>>2]=j;Zb:{_b:{switch(n|0){case 0:n=sa(a,14);break Zb;case 1:n=sa(a,15);break Zb;default:break _b}}n=Ga(a,m,i);if(!n){break Hb}i=i+1|0;n=y[n+68>>2]}y[h+76>>2]=n;$b:{ac:{switch(k|0){case 0:n=sa(a,14);break $b;case 1:n=sa(a,15);break $b;default:break ac}}k=Ga(a,m,i);if(!k){break Hb}i=i+1|0;n=y[k+68>>2]}y[h+80>>2]=n;bc:{cc:{switch(g|0){case 0:g=sa(a,14);break bc;case 1:g=sa(a,15);break bc;default:break cc}}g=Ga(a,m,i);if(!g){break Hb}i=i+1|0;g=y[g+68>>2]}y[h+84>>2]=g;if(!(c&16384)){fa=h,ga=sa(a,1),y[fa+88>>2]=ga;break Kb}c=Ga(a,m,i);if(!c){break Hb}y[h+88>>2]=y[c+68>>2];break Kb}s=y[f+352>>2]+d|0;if((s|0)<=0){break Mb}g=c+s|0;if((g|0)>(n|0)){break Nb}d=0;b=(b|0)==32&(c|0)>0;c=k+(c<<3)|0;C=c-8|0;while(1)if((d|0)==(s|0)){c=g;continue Lb}else{y[c+(d<<3)>>2]=b?y[C>>2]:0;d=d+1|0;continue}}y[f+8>>2]=0;y[f>>2]=0;y[f+4>>2]=0;ya(i);break Ib}c=c+1|0;continue}}i=0;y[f+312>>2]=0;y[f+316>>2]=0;if(z[h+1|0]==1){b=z[h+2|0];c=b?1024:8192;g=ab(c,8);y[f+24>>2]=0;rc(f+312|0,g);y[f+316>>2]=c;y[f+28>>2]=0;Ha(f+24|0);i=b?1024:8192}y[m+52>>2]=1;dc:{ec:{fc:{gc:{if(z[h|0]==1){b=Dd(h,y[a+4>>2],y[f+312>>2],i);y[f+24>>2]=0;oa(m- -64|0,b);la(f+24|0);if(!y[m+64>>2]){break ec}ta(y[a+4>>2]);break gc}c=Ra(y[a+4>>2]);y[f>>2]=c;b=Cd(f+24|0,d&255);c=Bd(h,c,y[f+312>>2],i,b);y[f+16>>2]=0;oa(m- -64|0,c);la(f+16|0);if(!y[m+64>>2]){break fc}ta(y[a+4>>2]);c=y[a+4>>2];d=y[c+8>>2];if(d>>>0<=4294967293){g=c;d=d+2|0;c=y[c+4>>2];y[g+8>>2]=c>>>0>d>>>0?d:c}qc(b);ua(f)}b=0;if((z[m+4|0]&63)==4){break dc}hc:{if(z[a+50|0]){break hc}b=y[y[a+24>>2]-4>>2];if(z[b+17|0]!=1){break hc}c=q+y[f+344>>2]|0;d=y[a+32>>2];if((c|0)<=y[d+12>>2]){break hc}eb(d,c,z[b+16|0])}b=y[f+340>>2];g=b;h=b>>31;b=y[f+344>>2];c=b;d=b>>31;b=z[f+348|0];fb(y[a+32>>2],g,h,c,d,y[m+64>>2],(b&7)==4?4:b&3);oa(m- -64|0,0);b=0;break dc}qc(b);ua(f)}b=1}Ha(f+312|0);break Hb}y[f+8>>2]=0;y[f>>2]=0;y[f+4>>2]=0}ya(f);b=1}ya(l);break v}else{d=Ma(a,y[y[m+12>>2]+(b<<2)>>2]);if(!(z[d+4|0]&63)){g=0;if(i&1){d=y[d+56>>2];d=y[d+28>>2]-y[d+24>>2]>>2;g=d+n|0;i=g;g=d>>>0<=g>>>0;n=g?i:0}else{n=0}i=g}b=b+1|0;continue}}b=1;g=d<<2;d=d+1|0;if(Ma(a,y[g+y[m+12>>2]>>2])){continue}break}}pc(f+308|0)}Y=f+368|0;break s}o()}if(y[a+56>>2]!=3){break r}b=y[a+4>>2];c=y[b+8>>2];b=y[b+4>>2];if(c>>>0>b>>>0){break e}if((b|0)!=(c|0)){continue}break}y[a+52>>2]=2;break c}ic:{switch(b|0){default:ib(R,0);break i;case 0:break ic;case 2:break d}}g=y[R>>2];b=y[g+28>>2];if((b|0)==-1){break g}c=y[a+84>>2];b=b+c|0;if(b>>>0>=c>>>0){break h}}aa=1;break c}y[a+84>>2]=b;d=y[a+4>>2];c=y[d+4>>2];y[d+8>>2]=b>>>0>>0?b:c;break f}d=y[a+4>>2];b=y[d+8>>2];if(b>>>0>4294967291){break f}b=b+4|0;c=y[d+4>>2];y[d+8>>2]=b>>>0>>0?b:c}b=y[a+12>>2];i=y[a+16>>2];jc:{if(b>>>0>>0){y[R>>2]=0;y[b>>2]=g;b=b+4|0;break jc}c=y[a+8>>2];b=b-c|0;k=b>>2;d=k+1|0;if(d>>>0>=1073741824){break b}i=i-c|0;h=i>>1;d=i>>>0>=2147483644?1073741823:d>>>0>>0?h:d;if(d){if(d>>>0>=1073741824){break a}i=na(d<<2)}else{i=0}y[a+80>>2]=0;h=b+i|0;y[h>>2]=g;g=h-(k<<2)|0;if(b){p(g,c,b)}y[a+16>>2]=i+(d<<2);b=h+4|0;y[a+12>>2]=b;y[a+8>>2]=g;if(c){ma(c)}d=y[a+4>>2]}y[a+12>>2]=b;b=y[d+8>>2];i=y[d+4>>2];if(b>>>0<=i>>>0){continue}break}}o()}ib(R,0)}Y=J+16|0;return aa}Ba();o()}jb();o()}function cb(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0;e=Y-96|0;Y=e;f=y[a+8>>2];g=y[a+4>>2];a:{if(!(f-1>>>0<65535&g-1>>>0<=65534)){n=xa(g,f);break a}b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{if(!z[a|0]){l:{if(z[a+24|0]!=255|z[a+25|0]!=255|(z[a+26|0]!=255|z[a+27|0]!=255)){break l}if(y[a+12>>2]){break l}k=y[a+20>>2];if((g|0)!=y[k+8>>2]){break l}if(!qa(k)){break b}p=y[a+4>>2];f=y[a+8>>2];n=xa(p,f);y[e+44>>2]=n;if(!qa(n)){break d}q=d;A=c;c=y[a+20>>2];G=y[c+8>>2];x=y[c+12>>2];c=y[a+16>>2];if(!((1-x|0)<=(c|0)&(c|0)<(x|0))){y[a+16>>2]=0}K=(f|0)>0?f:0;L=x+1|0;E=x-1|0;H=A+128|0;while(1){if((l|0)!=(K|0)){if(z[a+1|0]==1){if(z[b|0]){break d}if((d|0)==16|d>>>0<16){break k}C=ka(b,H)^C}ja(e+32|0,n,l);i=0;m:{if(!l){u=0;s=0;k=0;break m}ja(e+72|0,n,l-1|0);s=y[e+76>>2];if(!s){break k}u=y[e+72>>2];k=z[u|0]<<4}c=y[a+16>>2];y[e+88>>2]=0;y[e+92>>2]=0;y[e+80>>2]=0;y[e+84>>2]=0;y[e+72>>2]=0;y[e+76>>2]=0;y[e+16>>2]=0;y[e+8>>2]=0;y[e+12>>2]=0;g=l-c|0;if(!((g|0)<=0|(g|0)>(x|0))){ja(e+48|0,y[a+20>>2],g-1|0);c=y[e+52>>2];y[e+76>>2]=c;f=y[e+48>>2];y[e+72>>2]=f;if(!c){break k}c=z[f|0];y[e+8>>2]=c;i=c&192}j=0;c=0;n:{if((g|0)<0){break n}c=0;if((g|0)>=(x|0)){break n}ja(e+48|0,y[a+20>>2],g);c=y[e+52>>2];y[e+84>>2]=c;f=y[e+48>>2];y[e+80>>2]=f;if(!c){break k}c=z[f|0];y[e+12>>2]=c;c=c>>>3&24}if(!((g|0)<-1|(g|0)>=(E|0))){ja(e+48|0,y[a+20>>2],g+1|0);g=y[e+52>>2];y[e+92>>2]=g;f=y[e+48>>2];y[e+88>>2]=f;if(!g){break k}g=z[f|0];y[e+16>>2]=g;j=g>>>6|0}o:{if(!C){h=c|(k&3072|i)|j;r=0;v=y[e+32>>2];I=y[e+36>>2];m=0;p:while(1){if((m|0)>=(p|0)){break o}q:{if(!l){break q}k=k<<8;if((p|0)<=(m+8|0)){break q}c=(m>>>3|0)+1|0;if(c>>>0>=s>>>0){break k}k=z[c+u|0]<<4|k}r:{if((L+y[a+16>>2]|0)<(l|0)){y[e+16>>2]=0;y[e+8>>2]=0;y[e+12>>2]=0;g=0;i=0;c=0;break r}c=(m>>>3|0)+1|0;i=e+8|0;f=0;g=(G|0)<=(m+8|0);while(1){if((f|0)!=24){j=(e+72|0)+f|0;t=y[j+4>>2];s:{if(!t){break s}D=y[i>>2]<<8;y[i>>2]=D;if(g){break s}if(c>>>0>=t>>>0){break k}y[i>>2]=D|z[c+y[j>>2]|0]}i=i+4|0;f=f+8|0;continue}break}g=y[e+12>>2];i=y[e+8>>2];c=y[e+16>>2]}f=0;j=r+p|0;j=(j|0)>0?j:0;D=(j|0)>=8?8:j;j=0;while(1){if((f|0)==(D|0)){c=m>>>3|0;if(c>>>0>=I>>>0){break k}w[c+v|0]=j;r=r-8|0;m=m+8|0;continue p}if(h>>>0>=q>>>0){break k}F=ka(b,A+(h<<3)|0);t=7-f|0;j=F<>>13-f&1|(g>>>10-f&8|(i>>>t&64|(k>>>t&1024|h<<1&6582|F<<9)));f=f+1|0;continue}}}Jb(e+48|0,a,l);i=c|(k&3072|i)|j;c=0;v=y[e+32>>2];I=y[e+36>>2];D=y[e+60>>2];F=y[e+56>>2];r=0;while(1){if((c|0)>=(p|0)){break o}t:{if(!l){g=c+8|0;break t}k=k<<8;g=c+8|0;if((p|0)<=(g|0)){break t}f=(c>>>3|0)+1|0;if(f>>>0>=s>>>0){break k}k=z[f+u|0]<<4|k}j=c>>>3|0;m=j+1|0;f=0;h=e+8|0;while(1){u:{if((f|0)==24){f=0;m=r+p|0;m=(m|0)>0?m:0;J=(m|0)>=8?8:m;N=y[e+16>>2];M=y[e+12>>2];O=y[e+8>>2];m=0;while(1){if((f|0)==(J|0)){break u}t=y[y[a+20>>2]+8>>2];P=c+f|0;h=ia(t,P,F,D);v:{if(z[a+1|0]==1){if(Ib(t,P,h,e+48|0)){break v}}if(z[b|0]){break d}if(i>>>0>=q>>>0){break k}h=ka(b,A+(i<<3)|0)}t=7-f|0;i=N>>>13-f&1|(M>>>10-f&8|(k>>>t&1024|i<<1&6582|h<<9|O>>>t&64));f=f+1|0;m=h<>2];w:{if(!J){break w}N=y[h>>2]<<8;y[h>>2]=N;if((g|0)>=(G|0)){break w}if(m>>>0>=J>>>0){break k}y[h>>2]=N|z[m+y[t>>2]|0]}h=h+4|0;f=f+8|0;continue}break}if(j>>>0>=I>>>0){break k}w[j+v|0]=m;r=r-8|0;c=g;continue}}l=l+1|0;continue}break}y[e+44>>2]=0;break c}n=xa(g,f);y[e+44>>2]=n;if(!qa(n)){break f}Qa(n,0);A=c;u=c+128|0;c=0;while(1){if(B[a+8>>2]>c>>>0){if(z[a+1|0]==1){if(z[b|0]){break f}if((d|0)==16|d>>>0<16){break k}m=ka(b,u)^m}ja(e+32|0,n,c);f=e+72|0;ja(f,n,c-1|0);g=y[e+76>>2];q=y[e+72>>2];dd(f,a,c);f=0;k=y[n+8>>2];f=!g|(k|0)<2?f:z[q|0]>>>6&1;if(!(!g|(k|0)<=0)){f=z[q|0]>>>6&2|f}y[e+8>>2]=f;y[e+12>>2]=0;r=y[a+20>>2];f=y[r+8>>2];k=y[a+12>>2];i=1-k|0;l=y[e+72>>2];j=y[e+76>>2];h=0-k|0;Q=e,R=ia(f,i,l,j)|ia(f,h,l,j)<<1,y[Q+16>>2]=R;l=y[e+80>>2];j=y[e+84>>2];s=ia(f,i,l,j);p=s|ia(f,h,l,j)<<1;s=k^-1;Q=e,R=p|ia(f,s,l,j)<<2,y[Q+20>>2]=R;j=i;k=y[e+88>>2];i=y[e+92>>2];l=ia(f,j,k,i);Q=e,R=l|ia(f,h,k,i)<<1|ia(f,s,k,i)<<2,y[Q+24>>2]=R;f=e+48|0;ja(f,r,w[a+27|0]+(c-y[a+16>>2]|0)|0);k=y[e+52>>2];h=y[e+48>>2];ja(f,n,w[a+25|0]+c|0);f=y[e+52>>2];i=y[e+48>>2];x:{if(!m){l=q;q=g;j=i;i=f;g=k;r=h;f=0;k=y[e+32>>2];s=y[e+36>>2];while(1){if(B[a+4>>2]<=f>>>0){break x}p=e+8|0;h=cd(a,y[n+8>>2],p,f,r,g,j,i);if(z[b|0]){break f}if(d>>>0<=h>>>0){break k}bd(a,n,p,f,ka(b,A+(h<<3)|0),e+72|0,l,q,k,s);f=f+1|0;continue}}Jb(e+48|0,a,c);l=q;q=g;j=i;i=f;g=k;r=h;f=0;k=y[e+32>>2];s=y[e+36>>2];p=y[e+60>>2];C=y[e+56>>2];while(1){if(B[a+4>>2]<=f>>>0){break x}x=y[y[a+20>>2]+8>>2];h=ia(x,f,C,p);y:{if(z[a+1|0]==1){if(Ib(x,f,h,e+48|0)){break y}}h=cd(a,y[n+8>>2],e+8|0,f,r,g,j,i);if(z[b|0]==1){break f}if(d>>>0<=h>>>0){break k}h=ka(b,A+(h<<3)|0)}bd(a,n,e+8|0,f,h,e+72|0,l,q,k,s);f=f+1|0;continue}}c=c+1|0;continue}break}y[e+44>>2]=0;break e}z:{if(y[a+12>>2]){break z}k=y[a+20>>2];if((g|0)!=y[k+8>>2]){break z}if(!qa(k)){break b}q=y[a+4>>2];f=y[a+8>>2];n=xa(q,f);y[e+44>>2]=n;if(!qa(n)){break h}A=d;m=c;c=y[a+20>>2];x=y[c+8>>2];p=y[c+12>>2];c=y[a+16>>2];if(!((1-p|0)<=(c|0)&(c|0)<(p|0))){y[a+16>>2]=0}t=(f|0)>0?f:0;K=p-1|0;L=m- -64|0;while(1){A:{B:{if((l|0)!=(t|0)){if(z[a+1|0]==1){if(z[b|0]){break h}if((d|0)==8|d>>>0<8){break k}G=ka(b,L)^G}ja(e+32|0,n,l);i=0;C:{if(!l){C=0;s=0;k=0;break C}ja(e+72|0,n,l-1|0);s=y[e+76>>2];if(!s){break k}C=y[e+72>>2];k=z[C|0]<<1}c=y[a+16>>2];y[e+88>>2]=0;y[e+92>>2]=0;y[e+80>>2]=0;y[e+84>>2]=0;y[e+72>>2]=0;y[e+76>>2]=0;y[e+16>>2]=0;y[e+8>>2]=0;y[e+12>>2]=0;g=l-c|0;if(!((g|0)<=0|(g|0)>(p|0))){ja(e+48|0,y[a+20>>2],g-1|0);c=y[e+52>>2];y[e+76>>2]=c;f=y[e+48>>2];y[e+72>>2]=f;if(!c){break k}c=z[f|0];y[e+8>>2]=c;i=c>>>2&32}j=0;c=0;D:{if((g|0)<0){break D}c=0;if((g|0)>=(p|0)){break D}ja(e+48|0,y[a+20>>2],g);c=y[e+52>>2];y[e+84>>2]=c;f=y[e+48>>2];y[e+80>>2]=f;if(!c){break k}c=z[f|0];y[e+12>>2]=c;c=c>>>4&12}if(!((g|0)<-1|(g|0)>=(K|0))){ja(e+48|0,y[a+20>>2],g+1|0);g=y[e+52>>2];y[e+92>>2]=g;f=y[e+48>>2];y[e+88>>2]=f;if(!g){break k}g=z[f|0];y[e+16>>2]=g;j=g>>>6|0}if(G){break B}h=c|(k&384|i)|j;f=0;u=y[e+32>>2];E=y[e+36>>2];r=0;E:while(1){if((f|0)>=(q|0)){break A}F:{if(!l){c=f+8|0;break F}k=k<<8;c=f+8|0;if((q|0)<=(c|0)){break F}g=(f>>>3|0)+1|0;if(g>>>0>=s>>>0){break k}k=z[g+C|0]<<1|k}g=f>>>3|0;j=g+1|0;i=e+8|0;f=0;while(1){if((f|0)==24){f=0;i=r+q|0;i=(i|0)>0?i:0;j=(i|0)>=8?8:i;H=y[e+16>>2];v=y[e+12>>2];I=y[e+8>>2];i=0;while(1){if((f|0)==(j|0)){if(g>>>0>=E>>>0){break k}w[g+u|0]=i;r=r-8|0;f=c;continue E}if(h>>>0>=A>>>0){break k}D=ka(b,m+(h<<3)|0);F=7-f|0;i=D<>>13-f&1|(v>>>11-f&4|(I>>>9-f&32|(k>>>F&128|h<<1&794|D<<6)));f=f+1|0;continue}}H=(e+72|0)+f|0;v=y[H+4>>2];G:{if(!v){break G}I=y[i>>2]<<8;y[i>>2]=I;if((c|0)>=(x|0)){break G}if(j>>>0>=v>>>0){break k}y[i>>2]=I|z[j+y[H>>2]|0]}i=i+4|0;f=f+8|0;continue}}}y[e+44>>2]=0;break g}Jb(e+48|0,a,l);i=c|(k&384|i)|j;c=0;E=y[e+32>>2];H=y[e+36>>2];v=y[e+60>>2];I=y[e+56>>2];u=0;while(1){if((c|0)>=(q|0)){break A}H:{if(!l){g=c+8|0;break H}k=k<<8;g=c+8|0;if((q|0)<=(g|0)){break H}f=(c>>>3|0)+1|0;if(f>>>0>=s>>>0){break k}k=z[f+C|0]<<1|k}r=c>>>3|0;j=r+1|0;f=0;h=e+8|0;while(1){I:{if((f|0)==24){f=0;h=q+u|0;h=(h|0)>0?h:0;D=(h|0)>=8?8:h;F=y[e+16>>2];J=y[e+12>>2];N=y[e+8>>2];j=0;while(1){if((f|0)==(D|0)){break I}M=y[y[a+20>>2]+8>>2];O=c+f|0;h=ia(M,O,I,v);J:{if(z[a+1|0]==1){if(Ib(M,O,h,e+48|0)){break J}}if(z[b|0]){break h}if(i>>>0>=A>>>0){break k}h=ka(b,m+(i<<3)|0)}M=7-f|0;i=F>>>13-f&1|(J>>>11-f&4|(N>>>9-f&32|(k>>>M&128|i<<1&794|h<<6)));f=f+1|0;j=h<>2];K:{if(!F){break K}J=y[h>>2]<<8;y[h>>2]=J;if((g|0)>=(x|0)){break K}if(j>>>0>=F>>>0){break k}y[h>>2]=J|z[j+y[D>>2]|0]}h=h+4|0;f=f+8|0;continue}break}if(r>>>0>=H>>>0){break k}w[r+E|0]=j;u=u-8|0;c=g;continue}}l=l+1|0;continue}}n=xa(g,f);y[e+32>>2]=n;if(!qa(n)){break j}Qa(n,0);g=c;t=c- -64|0;while(1){if(B[a+8>>2]>u>>>0){if(z[a+1|0]==1){if(z[b|0]){break j}if((d|0)==8|d>>>0<8){break k}r=ka(b,t)^r}ja(e+8|0,n,u);c=e+72|0;ja(c,n,u-1|0);k=y[e+76>>2];A=y[e+72>>2];dd(c,a,u);h=0;c=y[n+8>>2];h=!k|(c|0)<2?h:z[A|0]>>>6&1;h=!k|(c|0)<=0?h:z[A|0]>>>6&2|h;c=y[y[a+20>>2]+8>>2];m=y[a+12>>2];f=0-m|0;p=y[e+72>>2];C=y[e+76>>2];ia(c,f,p,C);l=ia(c,f,p,C);j=1-m|0;q=y[e+80>>2];s=y[e+84>>2];i=ia(c,j,q,s)|ia(c,f,q,s)<<1|ia(c,m^-1,q,s)<<2;x=y[e+88>>2];G=y[e+92>>2];j=ia(c,j,x,G)|ia(c,f,x,G)<<1;L:{if(!r){m=0;K=y[e+12>>2];L=y[e+8>>2];f=0;while(1){if(B[a+4>>2]<=f>>>0){break L}if(z[b|0]){break j}c=i<<2|l<<5|m<<6|h<<7|j;if(c>>>0>=d>>>0){break k}m=ka(b,g+(c<<3)|0);La(y[n+8>>2],f,L,K,m);l=y[a+12>>2];h=ia(y[n+8>>2],f+2|0,A,k)|h<<1&6;c=y[y[a+20>>2]+8>>2];E=f-l|0;l=ia(c,E+1|0,p,C);E=E+2|0;i=ia(c,E,q,s)|i<<1&6;j=ia(c,E,x,G)|j<<1&2;f=f+1|0;continue}}Jb(e+48|0,a,u);c=0;K=y[e+12>>2];L=y[e+8>>2];E=y[e+60>>2];H=y[e+56>>2];f=0;while(1){if(B[a+4>>2]<=f>>>0){break L}v=y[y[a+20>>2]+8>>2];m=ia(v,f,H,E);M:{if(z[a+1|0]==1){if(Ib(v,f,m,e+48|0)){break M}}if(z[b|0]==1){break j}c=i<<2|l<<5|c<<6|h<<7|j;if(c>>>0>=d>>>0){break k}m=ka(b,g+(c<<3)|0)}La(y[n+8>>2],f,L,K,m);l=y[a+12>>2];h=ia(y[n+8>>2],f+2|0,A,k)|h<<1&6;c=y[y[a+20>>2]+8>>2];v=f-l|0;l=ia(c,v+1|0,p,C);v=v+2|0;i=ia(c,v,q,s)|i<<1&6;j=ia(c,v,x,G)|j<<1&2;f=f+1|0;c=m;continue}}u=u+1|0;continue}break}y[e+32>>2]=0;break i}o()}n=0}la(e+32|0);break a}n=0}la(e+44|0);break a}n=0}la(e+44|0);break a}n=0}la(e+44|0);break a}}Y=e+96|0;return n}function Zc(a,b,c,d,e,f,g,h){var i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;i=Y-32|0;Y=i;j=d-(c>>>0<1048577)|0;l=f-(e>>>0<1048577)|0;a:{if((j|0)==-1&c-1048577>>>0<4292870143|(j|0)!=-1|((l|0)==-1&e-1048577>>>0<4292870143|(l|0)!=-1)){break a}p=y[h>>2];q=y[h+8>>2];j=y[h+4>>2];m=y[h+12>>2];y[i+28>>2]=y[b+8>>2];w[i+24|0]=1;l=Yc(i+24|0,c);v=z[l|0];k=y[i+28>>2];h=y[b+12>>2];y[l>>2]=1;y[l+4>>2]=h;l=Yc(l,e);h=m-j|0;m=y[i+28>>2];x=z[l|0]?(h|0)<(m|0)?h:m:h;l=0-e&f>>31;if((x|0)<=(l|0)){break a}h=q-p|0;m=v?(h|0)<(k|0)?h:k:h;h=0-c&d>>31;if((m|0)<=(h|0)){break a}b:{c:{p=h+p|0;if((p|0)<0){break c}c=!!c&(d|0)>=0|(d|0)>0?c:0;n=c+(m-h|0)|0;D=-1<<0-n;E=-1>>>c|0;v=j+l|0;k=h&31;j=x-l|0;q=c&31;d=!!e&(f|0)>=0|(f|0)>0?e:0;l=c>>>5|0;p=p>>>5|0;if((c^n-1)>>>0<=31){c=D&E;if((h^m-1)>>>0>=32){h=0;j=(j|0)>0?j:0;k=k-q|0;q=32-k|0;m=p<<2;while(1){if((h|0)==(j|0)){break a}f=i+8|0;Ca(f,a,h+v|0);e=y[i+12>>2];n=y[i+8>>2];Ca(f,b,d+h|0);if(!e){break b}f=y[i+12>>2];if(!f){break b}if(e>>>0>>0){break c}y[i+20>>2]=e-p;y[i+16>>2]=m+n;e=_a(i+16|0);if(!y[i+20>>2]|f>>>0>>0|(f|0)==(l|0)){break c}f=y[i+8>>2]+(l<<2)|0;n=(te(e,24)&16711935|te(e&16711935,8))<>2]>>2];n=n|(te(e&16711935,8)|te(e,24)&16711935)>>>q;e=y[f>>2];e=Oa(g,n,te(e&16711935,8)|te(e,24)&16711935,c);I=f,J=te(e&16711935,8)|te(e,24)&16711935,y[I>>2]=J;h=h+1|0;continue}}h=0;f=(j|0)>0?j:0;if(k>>>0>q>>>0){k=k-q|0;q=p<<2;while(1){if((f|0)==(h|0)){break a}j=i+16|0;Ca(j,a,h+v|0);e=y[i+20>>2];m=y[i+16>>2];Ca(j,b,d+h|0);if(!e){break b}j=y[i+20>>2];if(!j){break b}if((e|0)==(p|0)|e>>>0>>0|((j|0)==(l|0)|j>>>0>>0)){break c}e=y[i+16>>2]+(l<<2)|0;n=e;j=y[m+q>>2];j=(te(j&16711935,8)|te(j,24)&16711935)<>2];e=Oa(g,j,te(e&16711935,8)|te(e,24)&16711935,c);I=n,J=te(e&16711935,8)|te(e,24)&16711935,y[I>>2]=J;h=h+1|0;continue}}k=q-k|0;q=p<<2;while(1){if((f|0)==(h|0)){break a}j=i+16|0;Ca(j,a,h+v|0);e=y[i+20>>2];m=y[i+16>>2];Ca(j,b,d+h|0);if(!e){break b}j=y[i+20>>2];if(!j){break b}if((e|0)==(p|0)|e>>>0>>0|((j|0)==(l|0)|j>>>0>>0)){break c}e=y[i+16>>2]+(l<<2)|0;n=e;j=y[m+q>>2];j=(te(j&16711935,8)|te(j,24)&16711935)>>>k|0;e=y[e>>2];e=Oa(g,j,te(e&16711935,8)|te(e,24)&16711935,c);I=n,J=te(e&16711935,8)|te(e,24)&16711935,y[I>>2]=J;h=h+1|0;continue}}x=n&31;A=(y[a+16>>2]>>>2)-(h>>>5)|0;if(k>>>0<=q>>>0){if((k|0)==(q|0)){k=0;e=((n|0)/32|0)-(c+31>>>5|0)|0;if((e|0)<0){break c}A=(j|0)>0?j:0;t=p<<2;d:while(1){if((k|0)==(A|0)){break a}f=i+8|0;Ca(f,a,k+v|0);c=y[i+12>>2];j=y[i+8>>2];Ca(f,b,d+k|0);if(!c){break b}h=y[i+12>>2];if(!h){break b}if(c>>>0>>0){break c}y[i+20>>2]=c-p;y[i+16>>2]=j+t;if(h>>>0>>0){break c}j=h-l|0;y[i+12>>2]=j;y[i+8>>2]=y[i+8>>2]+(l<<2);if(q){c=_a(i+16|0);f=gc(f);h=te(c,24)&16711935|te(c&16711935,8);c=y[f>>2];c=Oa(g,h,te(c&16711935,8)|te(c,24)&16711935,E);I=f,J=te(c&16711935,8)|te(c,24)&16711935,y[I>>2]=J;j=y[i+12>>2]}if(e>>>0>j>>>0){break c}c=y[i+16>>2];if(B[i+20>>2]>>0){break c}h=y[i+8>>2];u=e<<2;m=h+u|0;n=y[i+20>>2];f=c;while(1)if((h|0)==(m|0)){if(x){if((e|0)==(n|0)|e>>>0>n>>>0|(e|0)==(j|0)){break c}c=y[f+u>>2];f=te(c&16711935,8)|te(c,24)&16711935;c=y[m>>2];c=Oa(g,f,te(c&16711935,8)|te(c,24)&16711935,D);I=m,J=te(c&16711935,8)|te(c,24)&16711935,y[I>>2]=J}k=k+1|0;continue d}else{r=y[c>>2];s=te(r&16711935,8)|te(r,24)&16711935;r=y[h>>2];r=Eb(g,s,te(r&16711935,8)|te(r,24)&16711935);I=h,J=te(r&16711935,8)|te(r,24)&16711935,y[I>>2]=J;c=c+4|0;h=h+4|0;continue}}}m=0;e=((n|0)/32|0)-(c+31>>>5|0)|0;if((e|0)<0){break c}n=q-k|0;u=32-n|0;F=(j|0)>0?j:0;G=p<<2;e:while(1){if((m|0)==(F|0)){break a}f=i+8|0;Ca(f,a,m+v|0);c=y[i+12>>2];h=y[i+8>>2];Ca(f,b,d+m|0);if(!c){break b}f=y[i+12>>2];if(!f){break b}if(c>>>0>>0){break c}c=c-p|0;y[i+20>>2]=c;y[i+16>>2]=h+G;if(x){if(c>>>0>>0){break c}y[i+20>>2]=A}if(f>>>0>>0){break c}k=f-l|0;y[i+12>>2]=k;y[i+8>>2]=y[i+8>>2]+(l<<2);c=_a(i+16|0);j=te(c&16711935,8)|te(c,24)&16711935;if(q){c=gc(i+8|0);f=y[c>>2];f=Oa(g,j>>>n|0,te(f&16711935,8)|te(f,24)&16711935,E);h=te(f&16711935,8);I=c,J=te(f,24)&16711935|h,y[I>>2]=J;k=y[i+12>>2]}if(e>>>0>k>>>0){break c}c=y[i+16>>2];if(B[i+20>>2]>>0){break c}h=y[i+8>>2];C=e<<2;t=h+C|0;r=y[i+20>>2];f=c;while(1)if((h|0)==(t|0)){if(x){if(e>>>0>r>>>0){break c}h=j<>2];h=(te(c&16711935,8)|te(c,24)&16711935)>>>n|h}if((e|0)==(k|0)){break c}c=y[t>>2];c=Oa(g,h,te(c&16711935,8)|te(c,24)&16711935,D);I=t,J=te(c&16711935,8)|te(c,24)&16711935,y[I>>2]=J}m=m+1|0;continue e}else{H=j<>2];j=te(j&16711935,8)|te(j,24)&16711935;s=y[h>>2];s=Eb(g,H|j>>>n,te(s&16711935,8)|te(s,24)&16711935);I=h,J=te(s&16711935,8)|te(s,24)&16711935,y[I>>2]=J;c=c+4|0;h=h+4|0;continue}}}m=0;e=((n|0)/32|0)-(c+31>>>5|0)|0;if((e|0)<0){break c}n=k-q|0;t=32-n|0;F=(j|0)>0?j:0;G=p<<2;f:while(1){if((m|0)==(F|0)){break a}f=i+8|0;Ca(f,a,m+v|0);c=y[i+12>>2];h=y[i+8>>2];Ca(f,b,d+m|0);if(!c){break b}f=y[i+12>>2];if(!f){break b}if(c>>>0>>0){break c}c=c-p|0;y[i+20>>2]=c;y[i+16>>2]=h+G;if(x){if(c>>>0>>0){break c}y[i+20>>2]=A}if(f>>>0>>0){break c}k=f-l|0;y[i+12>>2]=k;y[i+8>>2]=y[i+8>>2]+(l<<2);c=i+16|0;f=_a(c);j=te(f&16711935,8)|te(f,24)&16711935;if(q){c=_a(c);f=gc(i+8|0);h=j<>2];c=Oa(g,h|j>>>t,te(c&16711935,8)|te(c,24)&16711935,E);I=f,J=te(c&16711935,8)|te(c,24)&16711935,y[I>>2]=J;k=y[i+12>>2]}if(e>>>0>k>>>0){break c}c=y[i+16>>2];if(B[i+20>>2]>>0){break c}h=y[i+8>>2];C=e<<2;u=h+C|0;r=y[i+20>>2];f=c;while(1)if((h|0)==(u|0)){if(x){if(e>>>0>r>>>0){break c}h=j<>2];h=(te(c&16711935,8)|te(c,24)&16711935)>>>t|h}if((e|0)==(k|0)){break c}c=y[u>>2];c=Oa(g,h,te(c&16711935,8)|te(c,24)&16711935,D);I=u,J=te(c&16711935,8)|te(c,24)&16711935,y[I>>2]=J}m=m+1|0;continue f}else{H=j<>2];j=te(j&16711935,8)|te(j,24)&16711935;s=y[h>>2];s=Eb(g,H|j>>>t,te(s&16711935,8)|te(s,24)&16711935);I=h,J=te(s&16711935,8)|te(s,24)&16711935,y[I>>2]=J;c=c+4|0;h=h+4|0;continue}}}o()}}Y=i+32|0}function Dd(a,b,c,d){var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0;f=Y-128|0;Y=f;n=xa(y[a+8>>2],y[a+12>>2]);y[f+124>>2]=n;if(qa(n)){Qa(n,z[a+4|0]);k=qd(b);y[f+116>>2]=k;e=0;a:{if(za(k,y[a+68>>2],f+120|0)){break a}y[f+108>>2]=y[f+120>>2];w[f+104|0]=1;q=Db(f+104|0,y[a+20>>2]);e=q;g=y[f+108>>2];h=0-g|0;y[e>>2]=z[e|0]&(g|0)!=-2147483648;y[e+4>>2]=h;y[f+100>>2]=0;w[f+96|0]=1;b:{c:{d:{e:while(1){if(B[a+16>>2]>r>>>0){if(za(k,y[a+68>>2],f+92|0)){break b}y[f+84>>2]=y[f+92>>2];e=1;w[f+80|0]=1;g=Db(f+80|0,y[a+20>>2]);s=Vc(q,y[g>>2],y[g+4>>2]);y[f+76>>2]=0;w[f+72|0]=1;while(1){f:{if(e&1){if(za(k,y[a+60>>2],f+8|0)){break b}h=Na(f+96|0,y[f+8>>2]);e=y[h+4>>2];y[f+72>>2]=y[h>>2];y[f+76>>2]=e;break f}g:{switch(za(k,y[a+64>>2],f+8|0)|0){case 0:break g;case 1:continue e;default:break b}}Na(Na(f+72|0,y[f+8>>2]),w[a+5|0])}e=1;j=0;g=y[a+20>>2];if((g|0)!=1){while(1){h=e;e=e+1|0;if(g>>>0>1<>>0){continue}break}if(Ia(b,h,f+8|0)){break b}j=z[f+8|0]}e=y[s+4>>2];if(!(y[s>>2]&1)){break b}h=e+j|0;e=h&(e^-1);if((e|0)<0){break b}t=(e|0)>=0?h:0;j=0;y[f+68>>2]=0;w[f+64|0]=1;h:while(1){if(wb(b,f+8|0)){break b}e=Tb(f- -64|0);if(z[e|0]!=1){break b}h=y[f+68>>2]|y[f+8>>2];g=(h|0)>=0;y[e>>2]=g;h=g?h:0;y[e+4>>2]=h;if(!g){break d}j=j+1|0;l=y[a+28>>2];i=y[a+24>>2];e=0;while(1){if((e|0)==(i|0)){continue h}g=l+(e<<3)|0;if(!(y[g>>2]==(j|0)&(h|0)==y[g+4>>2])){e=e+1|0;continue}break}break}i:{j:{k:{if(!z[a+1|0]){w[f+60|0]=0;y[f+56>>2]=0;break k}h=y[b>>2];g=y[b+8>>2];if(g>>>0>=B[b+4>>2]){break b}g=z[g+h|0];h=y[b+12>>2];_b(b);w[f+60|0]=0;y[f+56>>2]=0;if(g>>>7-h&1){break j}}Uc(f+56|0,y[y[a+40>>2]+(e<<2)>>2]);break i}if(za(k,y[a+72>>2],f+52|0)){break c}if(za(k,y[a+76>>2],f+48|0)){break c}if(za(k,y[a+80>>2],f+44|0)){break c}if(za(k,y[a+84>>2],f+40|0)){break c}if(za(k,y[a+88>>2],f+36|0)){break c}ta(b);j=y[y[a+40>>2]+(e<<2)>>2];if(!j){break c}l=y[f+52>>2];h=l>>31;e=y[j+8>>2]+l|0;if(e>>>0>>0?h+1|0:h){break c}i=y[f+48>>2];g=i>>31;h=i+y[j+12>>2]|0;if(h>>>0>>0?g+1|0:g){break c}g=y[b+8>>2];Cb(f+8|0,l,2,y[f+44>>2]);Cb(f+28|0,i,2,y[f+40>>2]);if(!(w[f+32|0]&1)|z[f+12|0]!=1){break c}i=db();y[f+24>>2]=i;y[i+8>>2]=h;y[i+4>>2]=e;e=z[a+2|0];y[i+20>>2]=j;w[i|0]=e;y[i+12>>2]=y[f+8>>2];e=y[f+28>>2];j=0;w[i+1|0]=0;y[i+16>>2]=e;w[i+24|0]=z[a+92|0];w[i+25|0]=z[a+93|0];w[i+26|0]=z[a+94|0];w[i+27|0]=z[a+95|0];e=Ra(b);y[f+20>>2]=e;if(fc(Tc(f+56|0,cb(i,e,c,d)))){ta(b);e=y[b+8>>2];if(e>>>0<=4294967293){h=e+2|0;e=y[b+4>>2];e=e>>>0>h>>>0?h:e;y[b+8>>2]=e}j=y[f+36>>2]==(e-g|0)}ua(f+20|0);Ua(f+24|0);if(!j){break c}}e=f+56|0;if(fc(e)){i=y[Xa(e)+8>>2];e=Xa(e);p=y[a+56>>2];j=y[e+12>>2];l:{m:{l=z[a+3|0];if(!l){e=z[f+72|0];if((p&-2)!=2){break m}if(!(e&1)){break c}g=y[f+76>>2];h=g>>31;e=i-1|0;m=e;e=e+g|0;g=m>>>0>e>>>0?h+1|0:h;g=e>>>0<2147483648&(g|0)<=0|(g|0)<0;y[f+72>>2]=0|g;y[f+76>>2]=g?e:0;if(!g){break c}break l}e=z[f+72|0];n:{switch(p|0){default:if(!(e&1)){break c}break l;case 0:case 2:break n}}if(!(e&1)){break c}g=y[f+76>>2];h=g>>31;e=j-1|0;m=e;e=e+g|0;h=m>>>0>e>>>0?h+1|0:h;g=e>>>0<2147483648&(h|0)<=0|(h|0)<0;y[f+72>>2]=0|g;y[f+76>>2]=g?e:0;if(g){break l}break c}if(!(e&1)){break c}}g=y[f+76>>2];Rc(f+8|0,l,p,g,t,i,j);m=Xa(f+56|0);e=y[f+8>>2];h=e;i=e>>31;e=y[f+12>>2];Hb(m,n,h,i,e,e>>31,y[a+52>>2]);e=y[f+16>>2];if(e){h=g>>31;m=e;e=e+g|0;g=m>>>0>e>>>0?h+1|0:h;h=e;g=e>>>0<2147483648&(g|0)<=0|(g|0)<0;e=0;y[f+72>>2]=e|g;y[f+76>>2]=g?h:0}r=r+1|0}mb(f+56|0);e=0;continue}}break}y[f+124>>2]=0;e=n;break a}o()}mb(f+56|0)}e=0}Ua(f+116|0)}la(f+124|0);Y=f+128|0;return e}function Bd(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0,C=0,D=0,E=0,F=0;f=Y-112|0;Y=f;k=xa(y[a+8>>2],y[a+12>>2]);y[f+108>>2]=k;g=0;a:{if(!qa(k)){break a}o=y[e>>2];g=0;if(!Aa(o,b,f+104|0)){break a}t=y[e+36>>2];u=y[e+32>>2];v=y[e+28>>2];x=y[e+24>>2];A=y[e+20>>2];C=y[e+16>>2];D=y[e+12>>2];E=y[e+8>>2];F=y[e+4>>2];Qa(k,z[a+4|0]);y[f+100>>2]=y[f+104>>2];w[f+96|0]=1;p=Db(f+96|0,y[a+20>>2]);e=p;h=y[f+100>>2];g=0-h|0;y[e>>2]=z[e|0]&(h|0)!=-2147483648;y[e+4>>2]=g;y[f+92>>2]=0;w[f+88|0]=1;e=y[a+16>>2];b:{c:while(1){if(e>>>0>m>>>0){y[f+84>>2]=0;w[f+80|0]=1;if(!Aa(o,b,f+76|0)){break b}y[f+68>>2]=y[f+76>>2];e=1;w[f+64|0]=1;g=Db(f- -64|0,y[a+20>>2]);q=Vc(p,y[g>>2],y[g+4>>2]);while(1){d:{if(e&1){Aa(F,b,f+4|0);e=Na(f+88|0,y[f+4>>2]);g=y[e+4>>2];y[f+80>>2]=y[e>>2];y[f+84>>2]=g;break d}if(!Aa(E,b,f+4|0)){e=y[a+16>>2];continue c}Na(Na(f+80|0,y[f+4>>2]),w[a+5|0])}e=y[a+16>>2];if(m>>>0>=e>>>0){continue c}y[f+60>>2]=0;if(y[a+20>>2]!=1){Aa(D,b,f+60|0)}e=y[q+4>>2];if(!(y[q>>2]&1)){break b}g=y[f+60>>2];n=e+g|0;if(((e^n)&(g^n))<0){break b}Ac(t,b,f+56|0);e=y[f+56>>2];if(e>>>0>=B[a+24>>2]){break b}e:{f:{g:{h:{i:{if(!z[a+1|0]){y[f+52>>2]=0;w[f+48|0]=0;y[f+44>>2]=0;break i}Aa(C,b,f+52|0);g=y[f+52>>2];w[f+48|0]=0;y[f+44>>2]=0;if(g){break h}}Uc(f+44|0,y[y[a+40>>2]+(e<<2)>>2]);break g}Aa(A,b,f+40|0);Aa(x,b,f+36|0);Aa(v,b,f+32|0);Aa(u,b,f+28|0);h=y[y[a+40>>2]+(e<<2)>>2];if(!h){break f}i=y[f+40>>2];g=i>>31;e=y[h+8>>2]+i|0;if(e>>>0>>0?g+1|0:g){break f}j=y[f+36>>2];g=j>>31;l=j+y[h+12>>2]|0;g=l>>>0>>0?g+1|0:g;if((g|0)==1|g>>>0>1){break f}Cb(f+4|0,i,1,y[f+32>>2]);Cb(f+20|0,j,1,y[f+28>>2]);if(!(w[f+24|0]&1)|z[f+8|0]!=1){break f}g=db();y[f+16>>2]=g;y[g+8>>2]=l;y[g+4>>2]=e;e=z[a+2|0];y[g+20>>2]=h;w[g|0]=e;y[g+12>>2]=y[f+4>>2];e=y[f+20>>2];w[g+1|0]=0;y[g+16>>2]=e;w[g+24|0]=z[a+92|0];w[g+25|0]=z[a+93|0];w[g+26|0]=z[a+94|0];w[g+27|0]=z[a+95|0];Tc(f+44|0,cb(g,b,c,d));Ua(f+16|0)}i=0;e=f+44|0;if(!fc(e)){break e}l=y[Xa(e)+8>>2];e=Xa(e);j=y[a+56>>2];r=y[e+12>>2];j:{k:{l:{s=z[a+3|0];if(!s){e=z[f+80|0];if((j&-2)!=2){break l}if(!(e&1)){break j}g=y[f+84>>2];e=g>>31;h=l-1|0;g=g+h|0;h=h>>>0>g>>>0?e+1|0:e;e=g;g=e>>>0<2147483648&(h|0)<=0|(h|0)<0;y[f+80>>2]=0|g;y[f+84>>2]=g?e:0;if(g){break k}break e}e=z[f+80|0];m:{switch(j|0){default:if(e&1){break k}break e;case 0:case 2:break m}}if(!(e&1)){break j}e=y[f+84>>2];g=e>>31;h=r-1|0;e=e+h|0;g=h>>>0>e>>>0?g+1|0:g;g=e>>>0<2147483648&(g|0)<=0|(g|0)<0;y[f+80>>2]=0|g;y[f+84>>2]=g?e:0;if(g){break k}break e}if(!(e&1)){break e}}g=y[f+84>>2];Rc(f+4|0,s,j,g,n,l,r);i=Xa(f+44|0);e=y[f+4>>2];h=e;j=e>>31;e=y[f+8>>2];Hb(i,k,h,j,e,e>>31,y[a+52>>2]);h=y[f+12>>2];if(h){e=g>>31;g=g+h|0;h=g>>>0>>0?e+1|0:e;e=g;g=e>>>0<2147483648&(h|0)<=0|(h|0)<0;h=0;y[f+80>>2]=g|h;y[f+84>>2]=g?e:0}i=1;m=m+1|0;break e}y[f+80>>2]=0;y[f+84>>2]=0;break e}i=0}mb(f+44|0);e=0;if(i){continue}break}break b}break}y[f+108>>2]=0;g=k;break a}g=0}la(f+108|0);Y=f+112|0;return g}function eb(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,q=0,r=0;j=Y-32|0;Y=j;a:{b:{c:{if(!qa(a)){break c}k=y[a+12>>2];if((k|0)>=(b|0)){break c}g=y[a+16>>2];if((268435452/(g|0)|0)<(b|0)){break c}if((k|0)<0){break b}d=g>>31;q=se(g,d,k);k=Z;if((k|0)==1|k>>>0>1){break b}g=se(g,d,b);d=Z;if((d|0)==1|d>>>0>1){break b}d:{if(z[a+4|0]==1){k=y[a>>2];y[a>>2]=0;y[j+20>>2]=0;_c(a,j+20|0);y[j+28>>2]=0;if(!d&g>>>0>2147479550|d){break a}e:{if(!k){g=Ya(g);break e}if(!g){ma(k);g=0;break e}f:{if(g>>>0>4294967239){break f}m=g>>>0<=8?8:g+3&-4;d=m+8|0;g=k;r=g-4|0;i=r;f=y[i>>2];e=f+i|0;h=y[e>>2];g:{h:{i:{if((h|0)!=y[(e+h|0)-4>>2]){h=f+h|0;if(h>>>0>=d+16>>>0){f=y[e+4>>2];e=y[e+8>>2];y[f+8>>2]=e;y[e+4>>2]=f;f=d+i|0;e=h-d|0;y[f>>2]=e;y[(f+(e&-4)|0)-4>>2]=e|1;e=y[f>>2]-8|0;j:{if(e>>>0<=127){n=(e>>>3|0)-1|0;break j}h=H(e);n=((e>>>29-h^4)-(h<<2)|0)+110|0;if(e>>>0<=4095){break j}e=((e>>>30-h^2)-(h<<1)|0)+71|0;n=e>>>0>=63?63:e}e=n;h=e<<4;y[f+4>>2]=h+6080;h=h+6088|0;y[f+8>>2]=y[h>>2];y[h>>2]=f;y[y[f+8>>2]+4>>2]=f;h=y[1779];f=e&31;if((e&63)>>>0>=32){f=1<>>32-f}y[1778]=e|y[1778];y[1779]=f|h;y[i>>2]=d;y[(i+(d&-4)|0)-4>>2]=d;e=1;break g}if(d>>>0>h>>>0){break i}d=y[e+4>>2];f=y[e+8>>2];y[d+8>>2]=f;y[f+4>>2]=d;y[i>>2]=h;y[(i+(h&-4)|0)-4>>2]=h;e=1;break g}if(f>>>0>=d+16>>>0){y[i>>2]=d;y[(i+(d&-4)|0)-4>>2]=d;i=d+i|0;d=f-d|0;y[i>>2]=d;y[(i+(d&-4)|0)-4>>2]=d|1;d=y[i>>2]-8|0;k:{if(d>>>0<=127){e=(d>>>3|0)-1|0;break k}f=H(d);e=((d>>>29-f^4)-(f<<2)|0)+110|0;if(d>>>0<=4095){break k}d=((d>>>30-f^2)-(f<<1)|0)+71|0;e=d>>>0>=63?63:d}f=e;d=f<<4;y[i+4>>2]=d+6080;d=d+6088|0;y[i+8>>2]=y[d>>2];y[d>>2]=i;y[y[i+8>>2]+4>>2]=i;i=y[1779];d=f&31;if((f&63)>>>0>=32){f=1<>>32-d}y[1778]=e|y[1778];y[1779]=f|i;e=1;break g}e=1;if(d>>>0<=f>>>0){break h}}e=0}}if(e){break e}g=Ya(m);if(!g){break f}l=y[r>>2]-8|0;l=l>>>0>m>>>0?m:l;if(l){p(g,k,l)}ma(k);l=g}g=l}if(!g){break a}nb(a,g);Ha(j+28|0);break d}Da(j+20|0,a);k=y[j+20>>2];l=y[j+24>>2];nb(a,ab(g,1));Da(j+12|0,a);if(l>>>0>B[j+16>>2]){break b}if(!l){break d}p(y[j+12>>2],k,l)}y[a+12>>2]=b;Da(j+20|0,a);a=y[j+24>>2];if(q>>>0>a>>>0){break b}c=0-c|0;b=q+y[j+20>>2]|0;a=a-q|0;while(1){if((a|0)<=0){break c}w[b|0]=c;a=a-1|0;b=b+1|0;continue}}Y=j+32|0;return}o()}rb();o()}function nc(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0;f=Y-48|0;Y=f;v=xa(y[a+4>>2],y[a+8>>2]);y[f+44>>2]=v;a:{b:{if(!qa(v)){break b}c:{m=y[a+4>>2];if(!m){break c}n=y[a+8>>2];L=e?n:n&2147483647;e=e<<1;B=e+2448|0;G=e+2466|0;C=e+2442|0;H=e+2436|0;I=e+2430|0;M=e+2460|0;N=e+2454|0;O=e+2424|0;e=m-1|0;p=e>>>3|0;J=(e&7)+1|0;n=0;m=0;e=0;while(1){d:{e:{if((x|0)!=(L|0)){ja(f+36|0,v,x);r=y[f+40>>2];s=y[f+36>>2];if(z[a+1|0]!=1){t=e;break e}if(z[b|0]){break b}h=A[O>>1];if(h>>>0>=d>>>0){break c}t=0;h=ka(b,(h<<3)+c|0);if((h|0)==(e|0)){break e}y[f+32>>2]=r;y[f+28>>2]=s;y[f+24>>2]=m;y[f+20>>2]=n;t=y[f+32>>2];y[f+8>>2]=y[f+28>>2];y[f+12>>2]=t;t=y[f+24>>2];y[f>>2]=y[f+20>>2];y[f+4>>2]=t;Pa(f+8|0,f);e=e^h;break d}y[f+44>>2]=0;break a}f:{g:{h:{if(x>>>0<=1){i=0;k=0;l=(x|0)!=1;if(!l){if(!m){break c}k=z[n|0]}q=A[I>>1];g=A[H>>1]&k>>>q;while(1){if((i|0)!=(p|0)){if(!l){e=i+1|0;if(e>>>0>=m>>>0){break c}k=z[e+n|0]|k<<8}j=0;e=7;while(1){if((e|0)>=0){if(z[b|0]){break b}if(d>>>0<=g>>>0){break c}u=A[B>>1]&k>>>e+q|(A[C>>1]&g)<<1;h=ka(b,(g<<3)+c|0);g=u|h;j=h<>>0<=g>>>0){break c}u=A[B>>1]&h>>>l-e|(A[C>>1]&g)<<1;i=ka(b,(g<<3)+c|0);g=u|i;j=i<<7-e|j;e=e+1|0;continue}}if(!g|!m|(m-1>>>0>>0|p>>>0>r>>>0)|g-1>>>0
>>0){break c}k=z[n|0];F=A[I>>1];K=A[N>>1];D=z[i|0]<>1]&k>>>F|D&A[M>>1];u=p+s|0;h=n;l=s;while(1){i:{E=D<<8;if((l|0)==(u|0)){break i}h=h+1|0;k=z[h|0]|k<<8;i=i+1|0;D=E|z[i|0]<=0){if(z[b|0]){break b}if(d>>>0<=g>>>0){break c}E=A[B>>1]&k>>>e+F|(A[G>>1]&D>>>e|(A[C>>1]&g)<<1);q=ka(b,(g<<3)+c|0);g=E|q;j=q<>>0<=g>>>0){break c}h=ka(b,(g<<3)+c|0);i=7-j|0;e=h<>1]&l>>>q-j|(A[G>>1]&E>>>i|(A[C>>1]&g)<<1));j=j+1|0;continue}}if(p>>>0>=r>>>0){break c}w[p+s|0]=j;break f}if(p>>>0>=r>>>0){break c}w[u|0]=e}e=t}x=x+1|0;i=n;g=m;n=s;m=r;continue}}o()}v=0}la(f+44|0);Y=f+48|0;return v}function ic(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;a:{b:{c:{d:{if(!z[a+1|0]){g=y[a+60>>2];break d}f=y[b+4>>2];if(z[f|0]){break a}h=y[c>>2];if(h>>>0>=B[b+12>>2]){break c}g=y[a+60>>2]^ka(f,y[b+8>>2]+(h<<3)|0);y[a+60>>2]=g}if(g){ed(a,y[y[b>>2]>>2]);break b}f=y[a+24>>2];if(f>>>0<=1){if((f|0)==1){if(!y[a+40>>2]){break c}j=z[y[a+36>>2]]}i=y[c+12>>2]&j>>>y[c+8>>2];h=(f|0)!=1;while(1){if((d|0)!=(k|0)){if(!h){f=k+1|0;if(f>>>0>=B[a+40>>2]){break c}j=z[f+y[a+36>>2]|0]|j<<8}g=7;l=0;while(1){if((g|0)>=0){f=y[b+4>>2];if(z[f|0]){break a}if(B[b+12>>2]<=i>>>0){break c}f=ka(f,y[b+8>>2]+(i<<3)|0);i=f|(y[c+16>>2]&j>>>y[c+8>>2]+g|(y[c+4>>2]&i)<<1);l=f<>2]<=k>>>0){break c}w[y[a+44>>2]+k|0]=l;k=k+1|0;continue}break}f=j<<8;g=0;l=0;while(1){if((e|0)!=(g|0)){h=y[b+4>>2];if(z[h|0]){break a}if(B[b+12>>2]<=i>>>0){break c}h=ka(h,y[b+8>>2]+(i<<3)|0);j=7-g|0;l=h<>2]&f>>>j+y[c+8>>2]|(y[c+4>>2]&i)<<1);g=g+1|0;continue}break}if(B[a+48>>2]<=d>>>0){break c}w[y[a+44>>2]+d|0]=l;break b}if(!y[a+32>>2]|!y[a+40>>2]){break c}j=z[y[a+36>>2]];k=z[y[a+28>>2]]<>2];i=y[c+12>>2]&j>>>y[c+8>>2]|k&y[c+24>>2];f=0;while(1){e:{if((d|0)!=(f|0)){h=f+1|0;if(h>>>0>=B[a+32>>2]|h>>>0>=B[a+40>>2]){break c}k=z[h+y[a+28>>2]|0]<>2]|k<<8;j=z[h+y[a+36>>2]|0]|j<<8;g=7;l=0;while(1){if((g|0)<0){break e}m=y[b+4>>2];if(z[m|0]){break a}if(B[b+12>>2]<=i>>>0){break c}m=ka(m,y[b+8>>2]+(i<<3)|0);i=m|(y[c+16>>2]&j>>>y[c+8>>2]+g|(y[c+28>>2]&k>>>g|(y[c+4>>2]&i)<<1));l=m<>2];if(z[h|0]){break a}if(B[b+12>>2]<=i>>>0){break c}k=ka(h,y[b+8>>2]+(i<<3)|0);h=7-g|0;f=k<>2]&l>>>h+y[c+8>>2]|(y[c+28>>2]&j>>>h|(y[c+4>>2]&i)<<1));g=g+1|0;continue}break}if(B[a+48>>2]<=d>>>0){break c}w[y[a+44>>2]+d|0]=f;break b}if(B[a+48>>2]<=f>>>0){break c}w[y[a+44>>2]+f|0]=l;f=h;continue}}o()}return 1}return 0}function pe(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;c=Y-48|0;Y=c;m=y[b+4>>2];t=y[b+12>>2];u=y[b+8>>2];g=y[y[b>>2]>>2];ja(c+40|0,g,y[a+24>>2]-1|0);ja(c+32|0,g,y[a+24>>2]-2|0);A=u+317736|0;n=y[c+36>>2];p=y[c+32>>2];d=y[a+24>>2];C=t>>>0>39717;q=4;a:{while(1){b:{c:{if(B[a+8>>2]>d>>>0){j=y[c+44>>2];k=y[c+40>>2];ja(c+32|0,g,d);h=y[c+36>>2];r=y[c+32>>2];y[c+40>>2]=r;y[c+44>>2]=h;d:{e:{f:{if(!z[a+1|0]){d=y[a+60>>2];break f}if(z[m|0]){break b}if(!C){break e}d=y[a+60>>2]^ka(m,A);y[a+60>>2]=d}if(d){y[c+20>>2]=j;y[c+16>>2]=k;y[c+24>>2]=r;y[c+28>>2]=h;y[c+8>>2]=r;y[c+12>>2]=h;h=y[c+20>>2];y[c>>2]=y[c+16>>2];y[c+4>>2]=h;Pa(c+8|0,c);break d}i=0;v=0;x=0;if(z[a+2|0]==1){ja(c+32|0,y[a+12>>2],y[a+24>>2]);x=y[c+36>>2];v=y[c+32>>2]}d=c+32|0;ja(d,g,y[a+24>>2]+w[a+17|0]|0);D=y[c+36>>2];E=y[c+32>>2];ja(d,g,y[a+24>>2]+w[a+19|0]|0);F=y[c+36>>2];G=y[c+32>>2];ja(d,g,y[a+24>>2]+w[a+21|0]|0);H=y[c+36>>2];I=y[c+32>>2];ja(d,g,y[a+24>>2]+w[a+23|0]|0);J=y[c+36>>2];K=y[c+32>>2];e=y[g+8>>2];i=!n|(e|0)<2?i:z[p|0]>>>6&1;i=!n|(e|0)<=0?i:z[p|0]>>>6&2|i;f=0;f=!j|(e|0)<3?f:z[k|0]>>>5&1;f=!j|(e|0)<2?f:z[k|0]>>>5&2|f;f=!j|(e|0)<=0?f:z[k|0]>>>5&4|f;s=0;d=0;while(1){if(B[a+4>>2]<=d>>>0){break d}g:{h:{if(z[a+2|0]==1){if(ia(y[y[a+12>>2]+8>>2],d,v,x)){break h}}l=ia(e,w[a+16|0]+d|0,E,D);L=ia(e,w[a+18|0]+d|0,G,F);M=ia(e,w[a+20|0]+d|0,I,H);e=ia(e,w[a+22|0]+d|0,K,J);if(z[m|0]){break b}e=f<<5|i<<12|l<<4|L<<10|M<<11|e<<15|s;if(e>>>0>=t>>>0){break e}l=ka(m,(e<<3)+u|0);e=y[g+8>>2];if(!l){break h}La(e,d,r,h,1);e=y[g+8>>2];l=1;break g}l=0}i=ia(e,d+2|0,p,n)|i<<1&6;f=ia(e,d+3|0,k,j)|f<<1&30;d=d+1|0;s=s<<1&14|l;continue}}o()}h=y[b+16>>2];if(!h){break c}if(!(_[y[y[h>>2]+8>>2]](h)|0)){break c}y[a+24>>2]=y[a+24>>2]+1;q=3}y[a+52>>2]=q;break a}d=y[a+24>>2]+1|0;y[a+24>>2]=d;p=k;n=j;continue}break}q=-1}Y=c+48|0;return q|0}
+function mc(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0;f=Y-48|0;Y=f;i=xa(y[a+4>>2],y[a+8>>2]);y[f+44>>2]=i;a:{b:{if(!qa(i)){break b}Qa(i,0);K=e|2;L=5-e|0;M=4-e|0;k=e>>>1|0;N=k^3;j=e<<1;O=j+2490|0;P=j+2484|0;Q=j+2478|0;R=j+2472|0;S=k^1;T=2-k|0;x=e&1;U=x+1|0;V=j+2424|0;j=0;k=0;while(1){c:{d:{e:{if(B[a+8>>2]>m>>>0){ja(f+36|0,i,m);t=y[f+40>>2];u=y[f+36>>2];if(z[a+1|0]!=1){n=g;break e}if(z[b|0]){break b}h=A[V>>1];if(h>>>0>=d>>>0){break d}n=0;h=ka(b,(h<<3)+c|0);if((h|0)==(g|0)){break e}y[f+32>>2]=t;y[f+28>>2]=u;y[f+24>>2]=k;y[f+20>>2]=j;n=y[f+32>>2];y[f+8>>2]=y[f+28>>2];y[f+12>>2]=n;n=y[f+24>>2];y[f>>2]=y[f+20>>2];y[f+4>>2]=n;g=g^h;i=y[f+44>>2];Pa(f+8|0,f);break c}y[f+44>>2]=0;break a}C=0;D=0;E=0;if(z[a+2|0]==1){ja(f+36|0,y[a+12>>2],m);E=y[f+40>>2];D=y[f+36>>2]}g=f+36|0;i=y[f+44>>2];ja(g,i,w[a+17|0]+m|0);W=y[f+40>>2];X=y[f+36>>2];F=0;G=0;H=0;I=0;J=0;if(!e){ja(g,i,w[a+19|0]+m|0);C=y[f+40>>2];F=y[f+36>>2];ja(g,i,w[a+21|0]+m|0);G=y[f+40>>2];H=y[f+36>>2];ja(g,i,w[a+23|0]+m|0);J=y[f+36>>2];I=y[f+40>>2]}h=y[i+8>>2];p=ia(h,U,r,s)|ia(h,x,r,s)<<1;p=!s|(e|0)!=1|(h|0)<=0?p:z[r|0]>>>5&4|p;q=ia(h,T,j,k)|ia(h,S,j,k)<<1;q=!k|e>>>0>1|(h|0)<=0?q:z[j|0]>>>5&4|q;v=0;g=0;while(1){if(B[a+4>>2]<=g>>>0){g=n;break c}f:{g:{if(z[a+2|0]==1){if(ia(y[y[a+12>>2]+8>>2],g,D,E)){break g}}if(z[b|0]){break b}l=q<>1]|v;if(!e){l=ia(h,w[a+18|0]+g|0,F,C)<<10|ia(h,w[a+20|0]+g|0,H,G)<<11|ia(h,w[a+22|0]+g|0,J,I)<<15|l}if(d>>>0<=l>>>0){break d}l=ka(b,(l<<3)+c|0);h=y[i+8>>2];if(!l){break g}La(h,g,u,t,1);h=y[i+8>>2];l=1;break f}l=0}p=(ia(h,g+K|0,r,s)|p<<1)&A[Q>>1];q=(ia(h,g+N|0,j,k)|q<<1)&A[P>>1];g=g+1|0;v=A[O>>1]&(l|v<<1);continue}}o()}m=m+1|0;r=j;s=k;j=u;k=t;continue}}i=0}la(f+44|0);Y=f+48|0;return i}function ke(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0;k=Y-16|0;Y=k;h=y[b+4>>2];l=y[b+12>>2];m=y[b+8>>2];n=y[y[b>>2]>>2];if(!y[a+48>>2]){Da(k+8|0,n);d=y[k+12>>2];y[a+44>>2]=y[k+8>>2];y[a+48>>2]=d}a:{b:{c:{d=y[a+4>>2];if(!d){break c}r=m+3240|0;d=d-1|0;i=d>>>3|0;p=(d&7)+1|0;c=y[a+24>>2];s=l>>>0>405;while(1){d:{if(B[a+8>>2]<=c>>>0){c=4}else{e:{if(!z[a+1|0]){c=y[a+60>>2];break e}if(z[h|0]){break b}if(!s){break c}c=y[a+60>>2]^ka(h,r);y[a+60>>2]=c}f:{if(c){ed(a,n);break f}c=0;g=0;g:{if(!y[a+24>>2]){h:{while(1){e=7;f=0;if((g|0)==(i|0)){break h}i:{while(1){if((e|0)>=0){if(z[h|0]){break i}if(c>>>0>=l>>>0){break c}d=ka(h,(c<<3)+m|0);c=d|c<<1&1006;f=d<>2]<=g>>>0){break c}w[y[a+44>>2]+g|0]=f;g=g+1|0;continue}break}if(g>>>0>>0){break b}}e=0;f=0;while(1){if((e|0)==(p|0)){break g}if(z[h|0]){break b}if(c>>>0>=l>>>0){break c}d=ka(h,(c<<3)+m|0);c=d|c<<1&1006;f=d<<7-e|f;e=e+1|0;continue}}if(!y[a+40>>2]){break c}g=z[y[a+36>>2]];e=g>>>1&112;d=0;while(1){j:{if((d|0)!=(i|0)){j=d+1|0;if(j>>>0>=B[a+40>>2]){break c}g=z[j+y[a+36>>2]|0]|g<<8;c=7;f=0;while(1){if((c|0)<0){break j}if(z[h|0]){break b}if(e>>>0>=l>>>0){break c}q=ka(h,(e<<3)+m|0);e=q|(g>>>c+1&16|e<<1&1006);f=q<>>0>=l>>>0){break c}j=ka(h,(e<<3)+m|0);e=j|(d>>>8-c&16|e<<1&1006);f=j<<7-c|f;c=c+1|0;continue}break}if(B[a+48>>2]<=i>>>0){break c}w[y[a+44>>2]+i|0]=f;break f}if(B[a+48>>2]<=d>>>0){break c}w[y[a+44>>2]+d|0]=f;d=j;continue}}if(B[a+48>>2]<=i>>>0){break c}w[y[a+44>>2]+i|0]=f}Kb(a,n);d=y[b+16>>2];if(!d){break d}if(!(_[y[y[d>>2]+8>>2]](d)|0)){break d}y[a+24>>2]=y[a+24>>2]+1;c=3}y[a+52>>2]=c;break a}c=y[a+24>>2]+1|0;y[a+24>>2]=c;continue}}o()}c=-1}Y=k+16|0;return c|0}function $d(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;g=Y-80|0;Y=g;w[g+72|0]=0;y[g+68>>2]=0;i=c+31>>>3&536870908;k=E(i,d);h=yd(k,1);y[g>>2]=0;j=g+68|0;nb(j,h);Ha(g);a:{b:{if(!qa(j)){break b}j=Nb(j);h=g+56|0;y[g+60>>2]=h;y[g+56>>2]=h;y[g+64>>2]=0;y[g+48>>2]=0;y[g+52>>2]=0;l=a;y[g+32>>2]=a;y[g+36>>2]=b;y[g>>2]=c;h=e;y[g+24>>2]=h;y[g+28>>2]=f;y[g+16>>2]=0;y[g+20>>2]=0;y[g+40>>2]=j;y[g+44>>2]=k;y[g+8>>2]=0;y[g+12>>2]=0;y[g+4>>2]=d;y[g+48>>2]=i;a=se(d,0,i);if(Z|a>>>0>k>>>0){break a}e=j;while(1){if((a|0)>0){w[e|0]=0;a=a-1|0;e=e+1|0;continue}break}a=b;b=g+56|0;a=zc(na(116),l,a,b,0);if(f){b=zc(na(116),h,f,b,1);y[g+76>>2]=0;zb(a,b);Ab(g+76|0)}e=c+7>>>3|0;y[g+76>>2]=0;f=g+52|0;zb(f,a);Ab(g+76|0);c:{d:{b=y[g+52>>2];a=y[b>>2];if(!a){break d}if(!yc(a)){break d}y[b+56>>2]=-1;a=0;break c}y[b+52>>2]=0;a=na(20);y[a+16>>2]=0;y[a+8>>2]=0;y[a+12>>2]=0;w[a+4|0]=0;y[a>>2]=0;e:{if((c|d)<0|i>>>0>268435452){break e}h=i<<3;if((h|0)<(c|0)|(!(!i|(d|0)<=0|k)|(2147483616/(h>>>0)|0)<(d|0))){break e}y[a+16>>2]=i;y[a+12>>2]=d;y[a+8>>2]=c;y[g+76>>2]=j;_c(a,g+76|0)}y[g+76>>2]=0;oa(b+32|0,a);la(g+76|0);w[b+50|0]=1;a=id(b)}f:{while(1){g:{a=a&1;h:{b=y[y[g+52>>2]+56>>2];if((b|0)!=4){break h}zb(g+52|0,0);b=-1;if(!a){break h}i:{b=E(y[g+48>>2],y[g+4>>2]);if(b>>>0>B[g+44>>2]){break i}a=y[g+40>>2];if(a&3){break i}c=(b&-4)+a|0;b=4;while(1){if((a|0)==(c|0)){break h}y[a>>2]=y[a>>2]^-1;a=a+4|0;continue}}o()}j:{switch(b-3|0){case 0:break j;case 1:break g;default:break f}}a=id(y[g+52>>2]);continue}break}X(Nb(g+68|0)|0,e|0,i|0,d|0)}Ab(f);if(!y[g+64>>2]){break b}a=y[g+60>>2];b=y[a>>2];c=y[y[g+56>>2]+4>>2];y[b+4>>2]=c;y[c>>2]=b;y[g+64>>2]=0;while(1){if((g+56|0)==(a|0)){break b}b=y[a+4>>2];oc(a);a=b;continue}}ub(g+68|0);Y=g+80|0;return}o()}function Ya(a){var b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;a:{b:{while(1){if(a>>>0>4294967239){break b}b=y[1779];c=b;f=y[1778];a=a>>>0<=8?8:a+3&-4;c:{if(a>>>0<=127){d=(a>>>3|0)-1|0;break c}e=H(a);d=((a>>>29-e^4)-(e<<2)|0)+110|0;if(a>>>0<=4095){break c}e=((a>>>30-e^2)-(e<<1)|0)+71|0;d=e>>>0>=63?63:e}g=d;d=g&31;if((g&63)>>>0>=32){e=0;b=b>>>d|0}else{e=b>>>d|0;b=((1<>>d}if(b|e){while(1){d=e;d:{if(d|b){c=d-1|0;e=c+1|0;f=c;c=b-1|0;f=(c|0)!=-1?e:f;e=H(d^f);e=(e|0)==32?H(b^c)+32|0:e;c=63-e|0;Z=0-(e>>>0>63)|0;break d}Z=0;c=64}f=c;c=f&31;if((f&63)>>>0>=32){e=0;h=d>>>c|0}else{e=d>>>c|0;h=((1<>>c}g=f+g|0;b=g<<4;d=y[b+6088>>2];c=b+6080|0;e:{if((d|0)!=(c|0)){b=dc(d,a);if(b){break a}b=y[d+4>>2];f=y[d+8>>2];y[b+8>>2]=f;y[f+4>>2]=b;y[d+8>>2]=c;y[d+4>>2]=y[c+4>>2];y[c+4>>2]=d;y[y[d+4>>2]+8>>2]=d;g=g+1|0;b=(e&1)<<31|h>>>1;e=e>>>1|0;break e}j=y[1779];f=g&63;b=f;d=b&31;if(b>>>0>=32){b=0;c=-1>>>d|0}else{b=-1>>>d|0;c=b|(1<>>0>=32){b=c<>>32-d|b<>>0>=32){b=-1<>>32-b}k=c&-2;c=f&31;if(f>>>0>=32){f=0;c=b>>>c|0}else{f=b>>>c|0;c=((1<>>c}b=c|i;Z=d|f;y[1778]=y[1778]&b;y[1779]=Z&j;b=h^1}if(b|e){continue}break}f=y[1778];c=y[1779]}e=H(c);d=63-((e|0)==32?H(f)+32|0:e)|0;f:{if(!(c|f)){g=0;break f}b=d<<4;g=y[b+6088>>2];if(!c&f>>>0<1073741824){break f}e=98;c=b+6080|0;if((c|0)==(g|0)){break f}while(1){b=dc(g,a);if(b){break a}g=y[g+8>>2];if((c|0)==(g|0)){break f}b=e;e=b-1|0;if(b){continue}break}}if(Fd(a+48|0)){continue}break}if(!g){break b}e=(d<<4)+6080|0;if((e|0)==(g|0)){break b}while(1){b=dc(g,a);if(b){break a}g=y[g+8>>2];if((e|0)!=(g|0)){continue}break}}b=0}return b}function Ld(a,b){a=a|0;b=+b;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;c=a<<3;o=c+7136|0;i=D[c+7168>>3];if(i!=0){l=D[o>>3];m=J(l,b);b=m-l;if(b<0x10000000000000000&b>=0){d=~~b>>>0;if(G(b)>=1){c=~~(b>0?I(K(b*2.3283064365386963e-10),4294967295):L((b-+(~~b>>>0>>>0))*2.3283064365386963e-10))>>>0}else{c=0}}else{c=0}if(i<0x10000000000000000&i>=0){h=~~i>>>0;if(G(i)>=1){e=~~(i>0?I(K(i*2.3283064365386963e-10),4294967295):L((i-+(~~i>>>0>>>0))*2.3283064365386963e-10))>>>0}else{e=0}}else{e=0}a:{b:{c:{d:{e:{f:{g:{h:{i:{j:{k:{if(c){if(!h){break k}if(!e){break j}f=H(e)-H(c)|0;if(f>>>0<=31){break i}break c}if((e|0)==1|e>>>0>1){break c}Z=0;c=(d>>>0)/(h>>>0)|0;break a}if(!d){break h}if(!e|e-1&e){break g}c=c>>>ue(e)|0;Z=0;break a}if(!(h-1&h)){break f}k=(H(h)+33|0)-H(c)|0;j=0-k|0;break d}k=f+1|0;j=63-f|0;break d}Z=0;c=(c>>>0)/(e>>>0)|0;break a}f=H(e)-H(c)|0;if(f>>>0<31){break e}break c}if((h|0)==1){break b}h=ue(h);e=h&31;if((h&63)>>>0>=32){c=c>>>e|0}else{f=c>>>e|0;c=((1<>>e}Z=f;break a}k=f+1|0;j=63-f|0}f=k&63;g=f&31;if(f>>>0>=32){f=0;n=c>>>g|0}else{f=c>>>g|0;n=((1<>>g}j=j&63;g=j&31;if(j>>>0>=32){c=d<>>32-g|c<>>31;f=n<<1|c>>>31;g=s-(p+(f>>>0>j>>>0)|0)>>31;q=g&h;n=f-q|0;f=p-((e&g)+(f>>>0>>0)|0)|0;c=c<<1|d>>>31;d=r|d<<1;r=g&1;k=k-1|0;if(k){continue}break}}Z=c<<1|d>>>31;c=r|d<<1;break a}d=0;c=0}Z=c;c=d}d=Z;c=c+1|0;d=c?d:d+1|0;l=(+(c>>>0)+ +(d>>>0)*4294967296)*i+l;m=l-m}D[o>>3]=l;Q(a|0,+m)|0;a=(a|0)==2?27:(a|0)==1?26:14;c=a-1|0;l:{if(y[1780]>>>c&1){y[1782]=y[1782]|1<>2];if(c){_[c|0](a)}}}function ne(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0,C=0,D=0,E=0,F=0;c=Y-48|0;Y=c;n=y[b+4>>2];t=y[b+12>>2];u=y[b+8>>2];i=y[y[b>>2]>>2];ja(c+40|0,i,y[a+24>>2]-1|0);ja(c+32|0,i,y[a+24>>2]-2|0);C=u+15528|0;l=y[c+36>>2];m=y[c+32>>2];e=y[a+24>>2];D=t>>>0>1941;p=4;a:{while(1){b:{c:{if(B[a+8>>2]>e>>>0){j=y[c+44>>2];k=y[c+40>>2];ja(c+32|0,i,e);h=y[c+36>>2];q=y[c+32>>2];y[c+40>>2]=q;y[c+44>>2]=h;d:{e:{f:{if(!z[a+1|0]){e=y[a+60>>2];break f}if(z[n|0]){break b}if(!D){break e}e=y[a+60>>2]^ka(n,C);y[a+60>>2]=e}if(e){y[c+20>>2]=j;y[c+16>>2]=k;y[c+24>>2]=q;y[c+28>>2]=h;y[c+8>>2]=q;y[c+12>>2]=h;h=y[c+20>>2];y[c>>2]=y[c+16>>2];y[c+4>>2]=h;Pa(c+8|0,c);break d}f=0;v=0;x=0;if(z[a+2|0]==1){ja(c+32|0,y[a+12>>2],y[a+24>>2]);x=y[c+32>>2];v=y[c+36>>2]}ja(c+32|0,i,y[a+24>>2]+w[a+17|0]|0);E=y[c+36>>2];F=y[c+32>>2];d=y[i+8>>2];f=!l|(d|0)<3?f:z[m|0]>>>5&1;f=!l|(d|0)<2?f:z[m|0]>>>5&2|f;f=!l|(d|0)<=0?f:z[m|0]>>>5&4|f;g=0;g=!j|(d|0)<3?g:z[k|0]>>>5&1;g=!j|(d|0)<2?g:z[k|0]>>>5&2|g;g=!j|(d|0)<=0?g:z[k|0]>>>5&4|g;s=0;e=0;while(1){if(B[a+4>>2]<=e>>>0){break d}g:{h:{if(z[a+2|0]==1){if(ia(y[y[a+12>>2]+8>>2],e,x,v)){break h}}d=ia(d,w[a+16|0]+e|0,F,E);if(z[n|0]){break b}d=g<<4|f<<9|d<<3|s;if(d>>>0>=t>>>0){break e}r=ka(n,(d<<3)+u|0);d=y[i+8>>2];if(!r){break h}La(d,e,q,h,1);d=y[i+8>>2];r=1;break g}r=0}A=e+3|0;f=ia(d,A,m,l)|f<<1&14;g=ia(d,A,k,j)|g<<1&30;e=e+1|0;s=s<<1&6|r;continue}}o()}h=y[b+16>>2];if(!h){break c}if(!(_[y[y[h>>2]+8>>2]](h)|0)){break c}y[a+24>>2]=y[a+24>>2]+1;p=3}y[a+52>>2]=p;break a}e=y[a+24>>2]+1|0;y[a+24>>2]=e;m=k;l=j;continue}break}p=-1}Y=c+48|0;return p|0}function le(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0,C=0,D=0,E=0;c=Y-48|0;Y=c;l=y[b+4>>2];s=y[b+12>>2];t=y[b+8>>2];i=y[y[b>>2]>>2];ja(c+40|0,i,y[a+24>>2]-1|0);ja(c+32|0,i,y[a+24>>2]-2|0);A=t+1832|0;m=y[c+36>>2];n=y[c+32>>2];d=y[a+24>>2];C=s>>>0>229;a:{while(1){b:{c:{if(B[a+8>>2]<=d>>>0){d=4}else{j=y[c+44>>2];k=y[c+40>>2];ja(c+32|0,i,d);f=y[c+36>>2];p=y[c+32>>2];y[c+40>>2]=p;y[c+44>>2]=f;d:{e:{f:{if(!z[a+1|0]){d=y[a+60>>2];break f}if(z[l|0]){break b}if(!C){break e}d=y[a+60>>2]^ka(l,A);y[a+60>>2]=d}if(d){y[c+20>>2]=j;y[c+16>>2]=k;y[c+24>>2]=p;y[c+28>>2]=f;y[c+8>>2]=p;y[c+12>>2]=f;f=y[c+20>>2];y[c>>2]=y[c+16>>2];y[c+4>>2]=f;Pa(c+8|0,c);break d}g=0;u=0;v=0;if(z[a+2|0]==1){ja(c+32|0,y[a+12>>2],y[a+24>>2]);v=y[c+32>>2];u=y[c+36>>2]}ja(c+32|0,i,y[a+24>>2]+w[a+17|0]|0);D=y[c+36>>2];E=y[c+32>>2];e=y[i+8>>2];g=!m|(e|0)<2?g:z[n|0]>>>6&1;g=!m|(e|0)<=0?g:z[n|0]>>>6&2|g;h=0;h=!j|(e|0)<2?h:z[k|0]>>>6&1;h=!j|(e|0)<=0?h:z[k|0]>>>6&2|h;r=0;d=0;while(1){if(B[a+4>>2]<=d>>>0){break d}g:{h:{if(z[a+2|0]==1){if(ia(y[y[a+12>>2]+8>>2],d,v,u)){break h}}e=ia(e,w[a+16|0]+d|0,E,D);if(z[l|0]){break b}e=h<<3|g<<7|e<<2|r;if(e>>>0>=s>>>0){break e}q=ka(l,(e<<3)+t|0);e=y[i+8>>2];if(!q){break h}La(e,d,p,f,1);e=y[i+8>>2];q=1;break g}q=0}x=d+2|0;g=ia(e,x,n,m)|g<<1&6;h=ia(e,x,k,j)|h<<1&14;d=d+1|0;r=r<<1&2|q;continue}}o()}f=y[b+16>>2];if(!f){break c}if(!(_[y[y[f>>2]+8>>2]](f)|0)){break c}y[a+24>>2]=y[a+24>>2]+1;d=3}y[a+52>>2]=d;break a}d=y[a+24>>2]+1|0;y[a+24>>2]=d;n=k;m=j;continue}break}d=-1}Y=c+48|0;return d|0}function ec(a,b,c,d,e,f,g,h){var i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,A=0,C=0,D=0,E=0;k=((b&536870911)<<3|a>>>29)&-8;m=e;n=g;p=d;q=f;r=1;e=-1;a:{b:{c:while(1){j=r&1;u=j?326:325;v=j?1392:1056;w=j?325:326;x=j?1056:1392;d:while(1){A=e+1|0;t=e>>>3|0;C=t+q|0;D=1<<((e^-1)&7);d=y[c>>2];E=(e|0)<0;while(1){if(d>>>0>=k>>>0){break b}if(E){f=1}else{if(n>>>0<=t>>>0){break a}f=(z[C|0]&D)!=0}d=h;g=d;l=f^1;i=cc(q,n,d,A,l);s=d;e:{if((i|0)>=(d|0)){break e}f:{if((f|0)==(j|0)){l=f;break f}i=cc(q,n,h,i+1|0,f)}s=h;if((d|0)<=(i|0)){break e}g=i;s=cc(q,n,d,i+1|0,l)}d=s;g:{f=0;h:{if(Ka(a,b,c)){break h}if(B[c>>2]>=k>>>0){break b}i=Ka(a,b,c);if(B[c>>2]>=k>>>0){break b}l=Ka(a,b,c);f=l?1:-1;if(i){break h}if(l){d=0;while(1){f=bc(x,w,a,b,c);d=f+d|0;if((f|0)>63){continue}break}d=(e>>>31|0)+d|0;if((d|0)<0){break b}f=d+e|0;if(!j){lb(p,m,h,e,f)}d=0;while(1){e=bc(v,u,a,b,c);d=e+d|0;if((e|0)>63){continue}break}if((d|0)<0){break b}e=d+f|0;if(j){lb(p,m,h,f,e)}if((e|0)<(h|0)){continue d}break b}if(B[c>>2]>=k>>>0){break b}if(Ka(a,b,c)){if(!j){lb(p,m,h,e,d)}e=d;if((d|0)<(h|0)){continue d}break b}if(B[c>>2]>=k>>>0){break b}d=Ka(a,b,c);if(B[c>>2]>=k>>>0){break b}i=Ka(a,b,c);f=i?2:-2;if(d){break h}d=y[c>>2];if(!i){break g}if(d>>>0>=k>>>0){break b}f=Ka(a,b,c)?3:-3}d=f+g|0;if(!j){lb(p,m,h,e,d)}if((d|0)<=(e|0)|(d|0)>=(h|0)){break b}r=r^1;e=d;continue c}if(d>>>0>=k>>>0){break b}f=Ka(a,b,c);d=y[c>>2];if(f){d=d+3|0;y[c>>2]=d;continue}break}break}break}y[c>>2]=d+5}return}o()}function uc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0;f=Y-32|0;Y=f;m=xa(y[a>>2],y[a+4>>2]);y[f+28>>2]=m;a:{if(!qa(m)){break a}Qa(m,z[a+20|0]);b:{while(1){if(!k&l>>>0>=B[a+36>>2]|k){y[f+28>>2]=0;d=m;break a}d=y[b>>2];g=y[b+4>>2];e=0;y[f+24>>2]=0;y[f+16>>2]=0;y[f+20>>2]=0;c=g-d|0;h=c>>2;c:{d:{if((d|0)==(g|0)){j=0;break d}if(h>>>0>=536870912){break c}j=na(c<<1);y[f+16>>2]=j;e=(h<<3)+j|0;y[f+24>>2]=e;c=j;while(1){if((c|0)!=(e|0)){y[c>>2]=0;y[c+4>>2]=0;c=c+8|0;continue}break}y[f+20>>2]=e}if(h>>>0>e-j>>3>>>0){break b}c=j;while(1){if((d|0)==(g|0)){e:{c=y[a+44>>2];d=se(l,k,A[a+48>>1]);e=c+d|0;q=e;c=Z+(c>>31)|0;r=d>>>0>e>>>0?c+1|0:c;c=y[a+40>>2];d=se(l,k,A[a+50>>1]);e=c+d|0;s=e;c=Z+(c>>31)|0;t=d>>>0>e>>>0?c+1|0:c;g=0;e=0;f:while(1){if(!e&B[a+32>>2]<=g>>>0|e){break e}i=y[b>>2];p=y[b+4>>2]-i>>2;c=0;d=0;while(1){h=c&255;if(h>>>0>=p>>>0){c=y[a+12>>2]-1|0;h=y[y[y[a+16>>2]>>2]+((c>>>0>>0?c:d)<<2)>>2];d=se(g,e,A[a+48>>1]);c=d+s|0;i=Z+t|0;d=c>>>0>>0?i+1|0:i;i=se(g,e,A[a+50>>1]);p=q-i|0;u=(d&255)<<24|c>>>8;n=d>>8;c=r-(Z+(i>>>0>q>>>0)|0)|0;d=c>>8;Hb(h,m,u,n,(c&255)<<24|p>>>8,d,y[a+24>>2]);g=g+1|0;e=g?e:e+1|0;continue f}else{n=(h<<3)+j|0;d=d|ia(y[y[i+(h<<2)>>2]+8>>2],g,y[n>>2],y[n+4>>2])<>2],l);e=y[f+12>>2];y[c>>2]=y[f+8>>2];y[c+4>>2]=e;c=c+8|0;d=d+4|0;continue}break}l=l+1|0;k=l?k:k+1|0;ya(f+16|0);continue}break}Ba()}o()}la(f+28|0);Y=f+32|0;return d}function sb(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,q=0,r=0,s=0,t=0,u=0;f=Y-16|0;Y=f;a:{j=xa(d,e);if(!qa(j)){break a}if(!qa(a)|(b|0)<0|(c|0)<0|y[a+8>>2]<=(b|0)){break a}g=y[a+12>>2];if((g|0)<=(c|0)){break a}b:{if(!(b&7)){d=y[a+16>>2];b=b>>>3|0;if(d>>>0<=b>>>0){break b}d=d-b|0;e=y[j+16>>2];d=d>>>0>>0?d:e;if(!d){break b}e=0;h=g-c|0;i=y[j+12>>2];h=(h|0)<(i|0)?h:i;h=(h|0)>0?h:0;while(1){if((e|0)==(h|0)){break a}ja(f+8|0,a,c+e|0);i=y[f+12>>2];if(i>>>0>>0|d>>>0>i-b>>>0){break b}i=y[f+8>>2];ja(f,j,e);if(d>>>0>B[f+4>>2]){break b}if(d){p(y[f>>2],b+i|0,d)}e=e+1|0;continue}}h=b>>>5|0;e=y[a+16>>2]>>>2|0;if(h>>>0>=e>>>0){break b}d=y[j+16>>2]>>>2|0;if(!d){break b}e=e-h|0;i=d>>>0>e>>>0?e:d;q=b&31;d=g-c|0;e=y[j+12>>2];d=(d|0)<(e|0)?d:e;r=(d|0)>0?d:0;s=b^-1;c:while(1){if((l|0)==(r|0)){break a}d=f+8|0;ja(d,a,c+l|0);e=y[f+8>>2];if(e&3){break b}g=y[f+12>>2]>>>2|0;if(g>>>0>>0){break b}y[f+12>>2]=g-h;y[f+8>>2]=e+(h<<2);Ca(f,j,l);if(B[f+4>>2]>>0){break b}e=y[f>>2];g=_a(d);d=y[f+8>>2];n=y[f+12>>2];k=i>>>0>n>>>0?n:i;if(k>>>0>B[f+12>>2]){break b}k=(k<<2)+e|0;g=te(g,24)&16711935|te(g&16711935,8);while(1)if((e|0)==(k|0)){if(i>>>0>n>>>0){d=g<>2]=u}l=l+1|0;continue c}else{m=g<>2];g=te(g&16711935,8)|te(g,24)&16711935;m=m|g>>>1>>>s;t=e,u=te(m&16711935,8)|te(m,24)&16711935,y[t>>2]=u;d=d+4|0;e=e+4|0;continue}}}o()}Y=f+16|0;return j}function je(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,x=0,A=0;c=Y-48|0;Y=c;i=y[b+4>>2];q=y[b+12>>2];r=y[b+8>>2];h=y[y[b>>2]>>2];ja(c+40|0,h,y[a+24>>2]-1|0);u=r+3240|0;d=y[a+24>>2];v=q>>>0>405;j=4;a:{while(1){b:{c:{if(B[a+8>>2]>d>>>0){k=y[c+44>>2];l=y[c+40>>2];ja(c+32|0,h,d);f=y[c+36>>2];m=y[c+32>>2];y[c+40>>2]=m;y[c+44>>2]=f;d:{e:{f:{if(!z[a+1|0]){d=y[a+60>>2];break f}if(z[i|0]){break b}if(!v){break e}d=y[a+60>>2]^ka(i,u);y[a+60>>2]=d}if(d){y[c+20>>2]=k;y[c+16>>2]=l;y[c+24>>2]=m;y[c+28>>2]=f;y[c+8>>2]=m;y[c+12>>2]=f;f=y[c+20>>2];y[c>>2]=y[c+16>>2];y[c+4>>2]=f;Pa(c+8|0,c);break d}g=0;s=0;t=0;if(z[a+2|0]==1){ja(c+32|0,y[a+12>>2],y[a+24>>2]);t=y[c+36>>2];s=y[c+32>>2]}ja(c+32|0,h,y[a+24>>2]+w[a+17|0]|0);x=y[c+36>>2];A=y[c+32>>2];e=y[h+8>>2];g=!k|(e|0)<2?g:z[l|0]>>>6&1;g=!k|(e|0)<=0?g:z[l|0]>>>6&2|g;p=0;d=0;while(1){if(B[a+4>>2]<=d>>>0){break d}g:{h:{if(z[a+2|0]==1){if(ia(y[y[a+12>>2]+8>>2],d,s,t)){break h}}e=ia(e,w[a+16|0]+d|0,A,x);if(z[i|0]){break b}e=g<<5|e<<4|p;if(e>>>0>=q>>>0){break e}n=ka(i,(e<<3)+r|0);e=y[h+8>>2];if(!n){break h}La(e,d,m,f,1);e=y[h+8>>2];n=1;break g}n=0}g=ia(e,d+2|0,l,k)|g<<1&30;d=d+1|0;p=p<<1&14|n;continue}}o()}f=y[b+16>>2];if(!f){break c}if(!(_[y[y[f>>2]+8>>2]](f)|0)){break c}y[a+24>>2]=y[a+24>>2]+1;j=3}y[a+52>>2]=j;break a}d=y[a+24>>2]+1|0;y[a+24>>2]=d;continue}break}j=-1}Y=c+48|0;return j|0}function Hd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;c=y[b+56>>2];d=y[b+60>>2];f=b+48|0;Hc(c,d,f);h=((d&536870911)<<3|c>>>29)&-8;if(h>>>0<=B[b+48>>2]){y[a>>2]=0;y[a+4>>2]=0;return}Ic(y[b+64>>2],y[b+68>>2]);i=b- -64|0;c=y[b+44>>2];a:{if((c|0)<0){e=y[b+64>>2];c=y[b+68>>2]-e|0;d=0;l=c;g=y[b+76>>2];c=y[b+80>>2]-g|0;ec(y[b+56>>2],y[b+60>>2],f,e|d,l,d|g,c,y[b+4>>2]);Gc(b+76|0,i);break a}if(!c){d=y[b+64>>2];c=y[b+68>>2]-d|0;Fc(y[b+56>>2],y[b+60>>2],f,d,c,y[b+4>>2]);break a}e=Ka(y[b+56>>2],y[b+60>>2],f);g=y[b+64>>2];c=y[b+68>>2]-g|0;d=y[b+56>>2];j=y[b+60>>2];b:{if(e){Fc(d,j,f,g,c,y[b+4>>2]);break b}l=d;d=0;e=c;k=y[b+76>>2];c=y[b+80>>2]-k|0;ec(l,j,f,d|g,e,d|k,c,y[b+4>>2])}Gc(b+76|0,i)}if(z[b+53|0]==1){Hc(y[b+56>>2],y[b+60>>2],f)}c:{d:{e:{if(z[b+52|0]!=1){break e}d=y[f>>2];if(h>>>0<=d>>>0){break e}e=d+7&-8;i=y[b+56>>2];g=y[b+60>>2];while(1){c=d>>>3|0;h=c+i|0;j=1<<((d^-1)&7);k=c>>>0>>0;c=1;f:{while(1){if(!c|d>>>0>=e>>>0){break f}if(!k){break d}if(z[h|0]&j){c=0;w[b+52|0]=0;continue}break}d=d+1|0;continue}break}if(!c){break e}y[f>>2]=e}c=y[b+64>>2];if(!z[b+54|0]){d=y[b+68>>2]-c|0;break c}if(c&3){break d}d=y[b+68>>2]-c|0;e=c+(d&-4)|0;b=c;while(1){if((b|0)==(e|0)){break c}y[b>>2]=y[b>>2]^-1;b=b+4|0;continue}}o()}y[a+4>>2]=d;y[a>>2]=c}function hd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;d=Y-32|0;Y=d;i=y[a+24>>2];y[d+16>>2]=0;a:{b:{switch(z[a+3|0]){case 0:c=xd(a)?3:4;break a;case 1:c=wd(a)?5:6;break a;case 2:c=Qb(a)?7:8;break a;default:break b}}c=Qb(a)?9:10}e=Y-48|0;Y=e;y[e+24>>2]=0;if(c){y[e+16>>2]=0;y[e+12>>2]=c;y[e+8>>2]=2600;g=e+8|0;y[e+24>>2]=g}h=e+8|0;c:{if((h|0)==(d|0)){break c}c=y[d+16>>2];if((g|0)==(h|0)){if((d|0)==(c|0)){f=e+32|0;_[y[y[g>>2]+12>>2]](g,f);c=y[e+24>>2];_[y[y[c>>2]+16>>2]](c);y[e+24>>2]=0;c=y[d+16>>2];_[y[y[c>>2]+12>>2]](c,h);c=y[d+16>>2];_[y[y[c>>2]+16>>2]](c);y[d+16>>2]=0;y[e+24>>2]=h;_[y[y[e+32>>2]+12>>2]](f,d);_[y[y[e+32>>2]+16>>2]](f);y[d+16>>2]=d;break c}_[y[y[g>>2]+12>>2]](g,d);c=y[e+24>>2];_[y[y[c>>2]+16>>2]](c);y[e+24>>2]=y[d+16>>2];y[d+16>>2]=d;break c}if((d|0)==(c|0)){f=e+8|0;_[y[y[c>>2]+12>>2]](c,f);c=y[d+16>>2];_[y[y[c>>2]+16>>2]](c);y[d+16>>2]=y[e+24>>2];y[e+24>>2]=f;break c}y[e+24>>2]=c;y[d+16>>2]=g}gd(e+8|0);Y=e+48|0;c=y[y[b>>2]>>2];f=y[d+16>>2];y[d+28>>2]=b;if(f){f=_[y[y[f>>2]+24>>2]](f,a,d+28|0)|0;y[a+64>>2]=0;y[a+52>>2]=f;b=y[c+8>>2];y[a+68>>2]=i;y[a+72>>2]=b;y[a+76>>2]=y[a+24>>2];if((f|0)==4){y[a+24>>2]=0}gd(d);Y=d+32|0;return f}a=Fb(4);y[a>>2]=5228;P(a|0,5240,11);o()}function hb(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,q=0,r=0,s=0,t=0,u=0;d=Y-32|0;Y=d;h=xa(y[a+4>>2],y[a+8>>2]);y[d+8>>2]=h;Da(d,h);a:{l=y[d+4>>2];if(!l){oa(b,0);y[a+52>>2]=-1;break a}b:{f=y[h+16>>2];if((f|0)<0|!f){break b}j=y[c+12>>2]+(y[c+8>>2]<<3)|0;i=y[a+8>>2];n=y[a+4>>2];q=y[c>>2];r=y[c+4>>2];k=y[d>>2];y[d+20>>2]=0;y[d+12>>2]=0;y[d+16>>2]=0;g=d+12|0;y[d+24>>2]=g;jc(g,f);e=y[d+16>>2];g=f+e|0;while(1){if((e|0)!=(g|0)){w[e|0]=255;e=e+1|0;continue}break}w[d+28|0]=1;y[d+16>>2]=g;fd(d+24|0);m=y[d+12>>2];g=y[d+16>>2];y[d+24>>2]=j;j=0;s=(i|0)>0?i:0;e=0;g=g-m|0;t=e|m;while(1){if((j|0)!=(s|0)){i=k;e=f;if(l>>>0>>0){break b}while(1){if((e|0)>0){w[i|0]=255;e=e-1|0;i=i+1|0;continue}break}ec(q,r,d+24|0,k|u,f,t,g,n);if(f>>>0>g>>>0){break b}if(f){p(m,k,f)}j=j+1|0;l=l-f|0;k=f+k|0;continue}break}f=y[d+24>>2];g=d+12|0;ya(g);y[c+12>>2]=f&7;y[c+8>>2]=f>>>3;Da(g,h);e=y[d+12>>2];c=e+y[d+16>>2]|0;while(1)if((c|0)==(e|0)){y[a+64>>2]=0;y[a+52>>2]=4;c=y[h+8>>2];y[a+68>>2]=0;y[a+72>>2]=c;y[a+76>>2]=y[h+12>>2];y[d+8>>2]=0;oa(b,h);break a}else{w[e|0]=z[e|0]^-1;e=e+1|0;continue}}o()}la(d+8|0);Y=d+32|0}function ae(a,b,c,d,e,f,g,h,i,j){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;var k=0,l=0;k=Y-16|0;Y=k;l=i?i:c;a:{if((l|0)<=0){break a}j=j?j:d;if((j|0)<=0|(j|l)>>>0>65535){break a}i=na(88);y[i+40>>2]=0;y[i+32>>2]=-1;y[i+36>>2]=0;y[i+20>>2]=1;y[i+24>>2]=1;y[i+16>>2]=j;y[i+12>>2]=l;y[i+8>>2]=j;y[i+4>>2]=l;y[i+56>>2]=a;y[i+60>>2]=b;w[i+54|0]=(h|0)!=0;w[i+53|0]=(f|0)!=0;w[i+52|0]=(g|0)!=0;y[i+48>>2]=0;y[i+44>>2]=e;y[i>>2]=2e3;a=l+31>>>3&16380;y[i+28>>2]=a;od(i- -64|0,a);od(i+76|0,y[i+28>>2]);e=c+7>>>3|0;W(E(e,d)|0);a=0;while(1){b:{if((a|0)==(d|0)){break b}c:{j=y[i+32>>2];b=a+1|0;if((j|0)==(b|0)){j=y[i+40>>2];c=y[i+36>>2];break c}d:{if(!((j|0)>=0&(a|0)>=(j|0))){j=0;if(!(_[y[y[i>>2]+12>>2]](i)|0)){break b}c=0;break d}c=1}while(1){if(!c){y[i+32>>2]=j;c=1;continue}e:{if((a|0)>(j|0)){_[y[y[i>>2]+16>>2]](k+8|0,i);j=y[i+32>>2]+1|0;break e}_[y[y[i>>2]+16>>2]](k+8|0,i);j=y[k+12>>2];c=y[k+8>>2];y[i+36>>2]=c;y[i+40>>2]=j;y[i+32>>2]=y[i+32>>2]+1;break c}c=0;continue}}if(!j){break b}V(c|0,e|0,E(a,e)|0);a=b;continue}break}_[y[y[i>>2]+4>>2]](i)}Y=k+16|0}function Fd(a){var b=0,c=0,d=0,e=0,f=0,g=0,h=0;b=y[1508];c=a+7&-8;a=c+7|0;d=a>>>0<7?1:d;e=a&-8;a=e+b|0;a:{b:{if(!(a>>>0>>0?d+1|0:d)){if(a>>>0<=$()<<16>>>0){break b}if(R(a|0)|0){break b}}y[1516]=48;b=-1;break a}y[1508]=a}d=b;if((d|0)!=-1){a=d+c|0;y[a-4>>2]=16;f=a-16|0;y[f>>2]=16;b=y[1776];if(b){e=y[b+8>>2]}else{e=0}c:{d:{if((e|0)==(d|0)){e=y[d-4>>2]&-2;g=d-e|0;h=y[g-4>>2];y[b+8>>2]=a;b=h&-2;a=g-b|0;if(y[(a+y[a>>2]|0)-4>>2]&1){f=y[a+4>>2];g=y[a+8>>2];y[f+8>>2]=g;y[g+4>>2]=f;b=(b+(c+e|0)|0)-16|0;y[a>>2]=b;break c}a=d-16|0;break d}y[d>>2]=16;y[d+8>>2]=a;y[d+4>>2]=b;y[d+12>>2]=16;y[1776]=d;a=d+16|0}b=f-a|0;y[a>>2]=b}y[((b&-4)+a|0)-4>>2]=b|1;c=y[a>>2]-8|0;e:{if(c>>>0<=127){b=(c>>>3|0)-1|0;break e}e=H(c);b=((c>>>29-e^4)-(e<<2)|0)+110|0;if(c>>>0<=4095){break e}b=((c>>>30-e^2)-(e<<1)|0)+71|0;b=b>>>0>=63?63:b}c=b<<4;y[a+4>>2]=c+6080;c=c+6088|0;y[a+8>>2]=y[c>>2];y[c>>2]=a;y[y[a+8>>2]+4>>2]=a;c=y[1779];a=b&31;if((b&63)>>>0>=32){b=1<>>32-a}y[1778]=e|y[1778];y[1779]=b|c}return(d|0)!=-1}function Bb(a,b){var c=0,d=0,e=0;c=Y+-64|0;Y=c;d=y[a>>2];e=y[d-8>>2];d=y[d-4>>2];a:{if(y[d+4>>2]==y[b+4>>2]){a=e?0:a;break a}e=a+e|0;if((e|0)<=(a|0)){y[c+16>>2]=0;y[c+20>>2]=0;y[c+12>>2]=b;y[c+8>>2]=a;y[c+4>>2]=d;y[c+24>>2]=0;y[c+28>>2]=0;y[c+32>>2]=0;y[c+36>>2]=0;y[c+40>>2]=0;y[c+44>>2]=0;y[c+48>>2]=0;y[c+60>>2]=0;y[c+52>>2]=1;y[c+56>>2]=16777216;_[y[y[d>>2]+20>>2]](d,c+4|0,e,e,1,0);if(y[c+28>>2]){break a}}y[c+16>>2]=0;y[c+20>>2]=0;y[c+12>>2]=5336;y[c+8>>2]=a;y[c+4>>2]=b;y[c+24>>2]=0;y[c+28>>2]=0;y[c+32>>2]=0;y[c+36>>2]=0;y[c+40>>2]=0;y[c+44>>2]=0;y[c+48>>2]=0;y[c+52>>2]=0;a=0;w[c+55|0]=0;w[c+56|0]=0;w[c+57|0]=0;w[c+58|0]=0;y[c+60>>2]=0;w[c+59|0]=1;_[y[y[d>>2]+24>>2]](d,c+4|0,e,1,0);b:{switch(y[c+40>>2]){case 0:a=y[c+44>>2]==1?y[c+32>>2]==1?y[c+36>>2]==1?y[c+24>>2]:0:0:0;break a;case 1:break b;default:break a}}if(y[c+28>>2]!=1){if(y[c+44>>2]|y[c+32>>2]!=1|y[c+36>>2]!=1){break a}}a=y[c+20>>2]}Y=c- -64|0;return a}function ud(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;d=Y-32|0;Y=d;a:{b:{c:{d:{e:{c=y[a+4>>2];if(c>>>0>>0){g=b-c|0;f=y[a+8>>2];e=f<<5;if(!(g>>>0>e>>>0|c>>>0>e-g>>>0)){y[a+4>>2]=b;e=c&31;b=y[a>>2]+(c>>>3&536870908)|0;break b}y[d+16>>2]=0;y[d+8>>2]=0;y[d+12>>2]=0;if((b|0)<0){break e}c=2147483647;if(e>>>0<=1073741822){e=f<<6;b=b+31&-32;c=b>>>0>>0?e:b;if((c|0)<0){break e}}e=(c-1>>>5|0)+1|0;b=na(e<<2);y[d+24>>2]=0;y[d+28>>2]=0;y[d+8>>2]=b;y[d+20>>2]=0;y[d+16>>2]=e;y[d+24>>2]=0;Ob(d+20|0);e=y[a+4>>2];y[d+12>>2]=e+g;if((e|0)<=0){break d}f=y[a>>2];h=e>>>5|0;c=h<<2;if(!(!h|!c)){p(b,f,c)}b=(h<<2)+b|0;e=e&31;if(!e){break d}f=y[c+f>>2];c=y[b>>2];y[b>>2]=(f^c)&-1>>>32-e^c;break c}y[a+4>>2]=b;break a}Ba();o()}e=0}c=y[a>>2];y[a>>2]=y[d+8>>2];y[d+8>>2]=c;c=y[a+4>>2];y[a+4>>2]=y[d+12>>2];y[d+12>>2]=c;c=y[a+8>>2];y[a+8>>2]=y[d+16>>2];y[d+16>>2]=c;Ob(d+8|0)}Xc(b,e,g);Pb(d+20|0,b,e,g)}Y=d+32|0}function cc(a,b,c,d,e){var f=0,g=0,h=0,i=0;a:{b:{if((c|0)<=(d|0)){break b}h=e-1|0;c:{f=(d|0)/8|0;g=f<<3;if((g|0)!=(d|0)){if(b>>>0<=f>>>0){break a}f=(z[a+f|0]^h)&255>>>d-g;if(f){break c}f=(d+7|0)/8|0}g=(c+7|0)/8|0;d:{if((c|0)<57){break d}i=g-8|0;if((i|0)<=(f|0)){break d}d=e?1718:1726;while(1){if((f|0)>=(i|0)){break d}if(b>>>0>>0|b-f>>>0<=7){break a}e=a+f|0;if((z[d|0]|z[d+1|0]<<8|(z[d+2|0]<<16|z[d+3|0]<<24))!=(z[e|0]|z[e+1|0]<<8|(z[e+2|0]<<16|z[e+3|0]<<24))|(z[e+4|0]|z[e+5|0]<<8|(z[e+6|0]<<16|z[e+7|0]<<24))!=(z[d+4|0]|z[d+5|0]<<8|(z[d+6|0]<<16|z[d+7|0]<<24))){break d}f=f+8|0;continue}}b=b>>>0>>0?f:b;d=(f|0)>(g|0)?f:g;e=h&255;while(1){if((d|0)==(f|0)){break b}if((b|0)==(f|0)){break a}g=z[a+f|0];if((g|0)!=(e|0)){a=z[((g^h)&255)+1734|0]+(f<<3)|0;return(a|0)>(c|0)?c:a}else{f=f+1|0;continue}}}c=g+z[f+1734|0]|0}return c}o()}function dc(a,b){var c=0,d=0,e=0,f=0,g=0;e=a+4|0;d=e+7&-8;c=y[a>>2];if(d+b>>>0<=(c+a|0)-4>>>0){f=y[a+4>>2];g=y[a+8>>2];y[f+8>>2]=g;y[g+4>>2]=f;if((d|0)!=(e|0)){d=d-e|0;f=a-(y[a-4>>2]&-2)|0;e=d+y[f>>2]|0;y[f>>2]=e;y[(f+(e&-4)|0)-4>>2]=e;a=a+d|0;c=c-d|0;y[a>>2]=c}a:{if(b+24>>>0<=c>>>0){e=a+b|0;c=(c-b|0)-8|0;y[e+8>>2]=c;g=e+8|0;y[(g+(c&-4)|0)-4>>2]=c|1;d=y[e+8>>2]-8|0;b:{if(d>>>0<=127){c=(d>>>3|0)-1|0;break b}f=H(d);c=((d>>>29-f^4)-(f<<2)|0)+110|0;if(d>>>0<=4095){break b}c=((d>>>30-f^2)-(f<<1)|0)+71|0;c=c>>>0>=63?63:c}d=c<<4;y[e+12>>2]=d+6080;d=d+6088|0;y[e+16>>2]=y[d>>2];y[d>>2]=g;y[y[e+16>>2]+4>>2]=g;d=y[1778];f=y[1779];e=c&31;if((c&63)>>>0>=32){c=1<>>32-e}y[1778]=g|d;y[1779]=c|f;c=b+8|0;y[a>>2]=c;b=(c&-4)+a|0;break a}b=a+c|0}y[b-4>>2]=c;a=a+4|0}else{a=0}return a}function ma(a){a=a|0;var b=0,c=0,d=0,e=0,f=0;if(a){b=a-4|0;f=y[b>>2];c=f;d=b;e=y[a-8>>2];a=e&-2;if((a|0)!=(e|0)){d=b-a|0;c=y[d+4>>2];e=y[d+8>>2];y[c+8>>2]=e;y[e+4>>2]=c;c=a+f|0}a=b+f|0;b=y[a>>2];if((b|0)!=y[(a+b|0)-4>>2]){f=y[a+4>>2];a=y[a+8>>2];y[f+8>>2]=a;y[a+4>>2]=f;c=b+c|0}y[d>>2]=c;y[((c&-4)+d|0)-4>>2]=c|1;b=y[d>>2]-8|0;a:{if(b>>>0<=127){a=(b>>>3|0)-1|0;break a}c=H(b);a=((b>>>29-c^4)-(c<<2)|0)+110|0;if(b>>>0<=4095){break a}a=((b>>>30-c^2)-(c<<1)|0)+71|0;a=a>>>0>=63?63:a}b=a<<4;y[d+4>>2]=b+6080;b=b+6088|0;y[d+8>>2]=y[b>>2];y[b>>2]=d;y[y[d+8>>2]+4>>2]=d;b=y[1778];c=y[1779];d=a&31;if((a&63)>>>0>=32){a=1<>>32-d}y[1778]=e|b;y[1779]=a|c}}function ob(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;d=Y-32|0;Y=d;g=(b<<3)+a|0;b=a;while(1){if((b|0)==(g|0)){a:{b=f+1|0;i=md(d+20|0,b);j=md(d+8|0,b);h=y[i>>2];b=a;while(1)if((b|0)==(g|0)){y[h>>2]=0;k=((f|0)>0?f:0)+1|0;l=y[j>>2];c=1;while(1){if((c|0)==(k|0)){c=k;break a}b=c<<2;e=b-4|0;y[d+4>>2]=y[e+l>>2];w[d|0]=1;if(z[Tb(Na(d,y[e+h>>2]))|0]!=1){break a}e=y[d+4>>2];y[b+l>>2]=e;b=a;while(1){if((b|0)!=(g|0)){if(y[b>>2]==(c|0)){y[b+4>>2]=e;e=e+1|0}b=b+8|0;continue}break}c=c+1|0;continue}}else{c=(y[b>>2]<<2)+h|0;y[c>>2]=y[c>>2]+1;b=b+8|0;continue}}}else{c=y[b>>2];f=(c|0)>(f|0)?c:f;b=b+8|0;continue}break}ya(j);ya(i);Y=d+32|0;return(c|0)>(f|0)}function za(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0;e=Y-16|0;Y=e;y[e+12>>2]=0;w[e+8|0]=1;h=-1;a:{b:while(1){if((wb(y[a>>2],e+4|0)|0)==-1){break a}d=Tb(e+8|0);if(z[d|0]!=1){break a}g=y[e+12>>2]|y[e+4>>2];f=(g|0)>=0;y[d>>2]=f;g=f?g:0;y[d+4>>2]=g;if(f){i=i+1|0;f=y[b+4>>2];d=0;while(1){if((d|0)==(f|0)){continue b}j=y[b+8>>2]+(d<<3)|0;if(y[j>>2]!=(i|0)|y[j+4>>2]!=(g|0)){d=d+1|0;continue}else{if((f-1|0)==(d|0)){h=1;if(w[b+1|0]&1){break a}}h=-1;f=y[a>>2];a=d<<2;if((Ia(f,y[a+y[b+20>>2]>>2],e+4|0)|0)==-1){break a}h=0;f=y[a+y[b+32>>2]>>2];a=y[e+4>>2];y[c>>2]=f+((y[b+4>>2]+(z[b+1|0]?-3:-2)|0)==(d|0)?0-a|0:a);break a}}}break}o()}Y=e+16|0;return h}function lb(a,b,c,d,e){var f=0,g=0,h=0;a:{d=(d|0)>0?d:0;f=(e|0)>=0?(c|0)<(e|0)?c:e:0;if((d|0)>=(f|0)){break a}b:{h=d>>>3|0;if(h>>>0>=b>>>0){break b}e=d&7;c=a+h|0;g=f-1|0;f=g>>>3|0;if((f|0)==(h|0)){a=g&7;while(1){if(a>>>0>>0){break a}w[c|0]=z[c|0]+(-1<<7-e);e=e+1|0;continue}}d=z[c|0];while(1)if((e|0)==8){w[c|0]=d;if(b>>>0<=f>>>0){break b}d=(g&7)+1|0;g=a+f|0;c=z[g|0];e=0;while(1)if((d|0)==(e|0)){w[g|0]=c;c=h+1|0;if(c>>>0>=f>>>0){break a}e=f+(h^-1)|0;if(e>>>0>b-c>>>0){break b}c=a+c|0;while(1){if((e|0)<=0){break a}w[c|0]=0;e=e-1|0;c=c+1|0;continue}}else{c=(-1<<7-e)+c|0;e=e+1|0;continue}}else{d=(-1<<7-e)+d|0;e=e+1|0;continue}}o()}}function ka(a,b){var c=0,d=0,e=0,f=0;c=y[b+4>>2];if(c>>>0<47){c=E(c,6);e=A[c+2080>>1];d=y[a+8>>2]-e|0;y[a+8>>2]=d;c=c+2080|0;f=y[a+4>>2];a:{if(d>>>0>f>>>16>>>0){if(d&32768){return z[b|0]}if(d>>>0>>0){d=z[b|0]^1;e=z[c+3|0];if(z[c+4|0]==1){w[b|0]=d&1}y[b+4>>2]=e;b=d&1;break a}y[b+4>>2]=z[c+2|0];b=z[b|0];break a}y[a+4>>2]=f-(d<<16);b:{if(d>>>0>>0){y[b+4>>2]=z[c+2|0];b=z[b|0];break b}d=z[b|0]^1;f=z[c+3|0];if(z[c+4|0]==1){w[b|0]=d&1}y[b+4>>2]=f;b=d&1}y[a+8>>2]=e}c=y[a+12>>2];while(1){if(!c){Dc(a);c=y[a+12>>2]}c=c-1|0;y[a+12>>2]=c;d=y[a+8>>2];y[a+8>>2]=d<<1;y[a+4>>2]=y[a+4>>2]<<1;if(!(d&16384)){continue}break}return b}o()}function xc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;a:{b:{c=y[a+4>>2];e=y[a>>2];g=c-e|0;h=g>>2;c:{if(h>>>0>>0){f=b-h|0;d=y[a+8>>2];if(f>>>0<=d-c>>2>>>0){b=(f<<2)+c|0;while(1){if((b|0)!=(c|0)){y[c>>2]=0;c=c+4|0;continue}break}y[a+4>>2]=b;return}if(b>>>0>=1073741824){break b}c=d-e|0;d=c>>1;d=c>>>0>=2147483644?1073741823:b>>>0>>0?d:b;if(d>>>0>=1073741824){break a}i=na(d<<2);b=i+g|0;f=b+(f<<2)|0;c=b;while(1){if((c|0)!=(f|0)){y[c>>2]=0;c=c+4|0;continue}break}b=b-(h<<2)|0;if(g){p(b,e,g)}y[a+8>>2]=(d<<2)+i;y[a+4>>2]=f;y[a>>2]=b;if(!e){break c}ma(e);return}if(b>>>0>=h>>>0){break c}y[a+4>>2]=(b<<2)+e}return}Ba();o()}jb();o()}function Td(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;a:{if(Sa(a,y[b+8>>2],e)){if(y[b+28>>2]==1|y[b+4>>2]!=(c|0)){break a}y[b+28>>2]=d;return}if(Sa(a,y[b>>2],e)){if(!(y[b+16>>2]!=(c|0)&y[b+20>>2]!=(c|0))){if((d|0)!=1){break a}y[b+32>>2]=1;return}y[b+32>>2]=d;b:{if(y[b+44>>2]==4){break b}x[b+52>>1]=0;a=y[a+8>>2];_[y[y[a>>2]+20>>2]](a,b,c,c,1,e);if(z[b+53|0]==1){y[b+44>>2]=3;if(!z[b+52|0]){break b}break a}y[b+44>>2]=4}y[b+20>>2]=c;y[b+40>>2]=y[b+40>>2]+1;if(y[b+36>>2]!=1|y[b+24>>2]!=2){break a}w[b+54|0]=1;return}a=y[a+8>>2];_[y[y[a>>2]+24>>2]](a,b,c,d,e)}}function kb(a,b){var c=0,d=0,e=0,f=0,g=0;a:{c=y[a+4>>2];d=y[a>>2];e=c-d>>3;if(e>>>0>>0){g=b-e|0;f=y[a+8>>2];if(g>>>0<=f-c>>3>>>0){b=(g<<3)+c|0;while(1){if((b|0)!=(c|0)){y[c+4>>2]=0;w[c|0]=0;c=c+8|0;continue}break}y[a+4>>2]=b;return}d=Bc(d,f,b);b=y[a+4>>2]-y[a>>2]|0;e=0;if(d){e=yb(d)}b=b+e|0;g=b+(g<<3)|0;c=b;while(1){if((c|0)!=(g|0)){y[c+4>>2]=0;w[c|0]=0;c=c+8|0;continue}break}f=b;b=y[a>>2];c=y[a+4>>2]-b|0;f=f-c|0;if(c){p(f,b,c)}y[a+4>>2]=g;y[a>>2]=f;y[a+8>>2]=(d<<3)+e;if(!b){break a}ma(b);return}if(b>>>0>=e>>>0){break a}y[a+4>>2]=d+(b<<3)}}function ad(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;a:{e=y[a+4>>2];c=y[a>>2];f=e-c|0;d=f>>3;b:{if(d>>>0>>0){d=b-d|0;g=y[a+8>>2];if(d>>>0<=g-e>>3>>>0){ld(a,d);return}if(b>>>0>=536870912){break a}h=d<<3;e=f;c=g-c|0;d=c>>2;f=c>>>0>=2147483640?536870911:b>>>0>>0?d:b;g=yb(f);c=e+g|0;d=h+c|0;b=c;while(1){if((b|0)!=(d|0)){y[b>>2]=0;y[b+4>>2]=0;b=b+8|0;continue}break}e=c;b=y[a>>2];c=y[a+4>>2]-b|0;e=e-c|0;if(c){p(e,b,c)}y[a+4>>2]=d;y[a>>2]=e;y[a+8>>2]=g+(f<<3);if(!b){break b}ma(b);return}if(b>>>0>=d>>>0){break b}y[a+4>>2]=c+(b<<3)}return}Ba();o()}function Gb(a,b){var c=0,d=0,e=0,f=0,g=0,h=0;a:{e=y[a+4>>2];c=y[a>>2];f=e-c|0;d=f>>2;b:{if(d>>>0>>0){d=b-d|0;g=y[a+8>>2];if(d>>>0<=g-e>>2>>>0){kd(a,d);return}if(b>>>0>=1073741824){break a}h=d<<2;e=f;c=g-c|0;d=c>>1;f=c>>>0>=2147483644?1073741823:b>>>0>>0?d:b;g=Lb(f);c=e+g|0;d=h+c|0;b=c;while(1){if((b|0)!=(d|0)){y[b>>2]=0;b=b+4|0;continue}break}e=c;b=y[a>>2];c=y[a+4>>2]-b|0;e=e-c|0;if(c){p(e,b,c)}y[a+4>>2]=d;y[a>>2]=e;y[a+8>>2]=g+(f<<2);if(!b){break b}ma(b);return}if(b>>>0>=d>>>0){break b}y[a+4>>2]=c+(b<<2)}return}Ba();o()}function Rc(a,b,c,d,e,f,g){y[a+8>>2]=0;a:{b:{if(!(b&255)){c:{switch(c|0){case 1:y[a+4>>2]=e;y[a>>2]=d;y[a+8>>2]=f-1;return;case 3:y[a+4>>2]=e;break a;case 0:y[a>>2]=d;y[a+8>>2]=f-1;y[a+4>>2]=(e-g|0)+1;return;case 2:break c;default:break b}}y[a+4>>2]=(e-g|0)+1;break a}d:{switch(c|0){case 1:y[a+4>>2]=d;y[a>>2]=e;y[a+8>>2]=g-1;return;case 3:y[a+4>>2]=d;y[a+8>>2]=g-1;y[a>>2]=(e-f|0)+1;return;case 0:y[a>>2]=e;y[a+4>>2]=(d-g|0)+1;return;case 2:break d;default:break b}}y[a+4>>2]=(d-g|0)+1;y[a>>2]=(e-f|0)+1}return}y[a>>2]=(d-f|0)+1}function bc(a,b,c,d,e){var f=0,g=0,h=0,i=0,j=0,k=0;k=((d&536870911)<<3|c>>>29)&-8;a:{b:while(1){c:{if(b>>>0<=f>>>0){break c}g=-1;i=z[a+f|0];if((i|0)==255){break a}h=y[e>>2];if(h>>>0>=k>>>0){break a}g=h>>>3|0;if(g>>>0>=d>>>0){break c}g=z[c+g|0];y[e>>2]=h+1;j=g>>>((h^-1)&7)&1|j<<1;f=f+1|0;h=f+E(i,3)|0;while(1){if((f|0)>=(h|0)){continue b}if(b>>>0<=f>>>0){break c}if(z[a+f|0]==(j|0)){c=f+1|0;if(c>>>0>=b>>>0){break c}d=b;b=f+2|0;if(d>>>0<=b>>>0){break c}g=z[a+c|0]|z[a+b|0]<<8;break a}else{f=f+3|0;continue}}}break}o()}return g}function Ia(a,b,c){var d=0,e=0,f=0,g=0;e=-1;g=y[a>>2];a:{f=y[a+8>>2];d=y[a+4>>2];if(f>>>0>=d>>>0){break a}b:{if((d|0)==536870912|d>>>0>536870912){break b}f=y[a+12>>2]+(f<<3)|0;if(f>>>0>(((d&536870911)<<3|g>>>29)&-8)>>>0){break a}y[c>>2]=0;g=y[a>>2];d=y[a+4>>2];if((d|0)==536870912|d>>>0>536870912){break b}d=((d&536870911)<<3|g>>>29)&-8;e=d>>>0>>0?d-f|0:b;while(1){if(!e){e=0;break a}b=y[a+8>>2];if(b>>>0>=B[a+4>>2]){break b}y[c>>2]=z[b+y[a>>2]|0]>>>7-y[a+12>>2]&1|y[c>>2]<<1;_b(a);e=e-1|0;continue}}o()}return e}function Aa(a,b,c){var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;f=Y-16|0;Y=f;i=ka(b,y[a>>2]+8|0);d=i|2;while(1){a:{if((e|0)==5){e=5;break a}g=ka(b,y[a>>2]+(d<<3)|0);d=g|d<<1;if(!g){break a}e=e+1|0;continue}break}g=0;e=e<<3;h=y[e+2364>>2];h=(h|0)>0?h:0;k=e+2364|0;e=0;while(1){if((e|0)!=(h|0)){j=ka(b,y[a>>2]+(d<<3)|0);d=j|d<<1;d=(d|0)>255?d&255|256:d;g=g<<1|j;e=e+1|0;continue}break}w[f+8|0]=1;y[f+12>>2]=y[k+4>>2];d=0;e=0;if(z[Na(f+8|0,g)|0]){a=y[f+12>>2];b=a>>31;d=i?b-(a^b)|0:a;e=!i|(d|0)!=0}y[c>>2]=d;Y=f+16|0;return e}function Sb(a,b){var c=0,d=0,e=0,f=0,g=0;a:{if((a|0)!=(b|0)){f=y[b+4>>2];d=y[b>>2];b=f-d|0;c=y[a>>2];if(b>>>0<=y[a+8>>2]-c>>>0){e=y[a+4>>2];g=e-c|0;if(b>>>0>g>>>0){if((c|0)!=(e|0)){if(g){p(c,d,g)}e=y[a+4>>2]}b=d+g|0;d=f-b|0;if(!(!d|(b|0)==(f|0))){p(e,b,d)}y[a+4>>2]=d+e;return a}if(!(!b|(d|0)==(f|0))){p(c,d,b)}y[a+4>>2]=b+c;return a}jd(a);e=Bc(y[a>>2],y[a+8>>2],b>>3);if(e>>>0>=536870912){break a}c=yb(e);y[a+4>>2]=c;y[a>>2]=c;y[a+8>>2]=c+(e<<3);if(!(!b|(d|0)==(f|0))){p(c,d,b)}y[a+4>>2]=b+c}return a}Ba();o()}function me(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0;d=Y-16|0;Y=d;f=y[y[b>>2]>>2];if(!y[a+48>>2]){Da(d+8|0,f);c=y[d+12>>2];y[a+44>>2]=y[d+8>>2];y[a+48>>2]=c}c=y[a+4>>2];if(c){c=c-1|0;g=c>>>3|0;h=(c&7)+1|0;c=y[a+24>>2];while(1){a:{b:{if(B[a+8>>2]<=c>>>0){c=4}else{if(!ic(a,b,2560,g,h)){c=-1;break b}Kb(a,f);e=y[b+16>>2];c=y[a+24>>2];if(!e|(c>>>0)%50){break a}e=_[y[y[e>>2]+8>>2]](e)|0;c=y[a+24>>2];if(!e){break a}y[a+24>>2]=c+1;c=3}y[a+52>>2]=c}Y=d+16|0;return c|0}c=c+1|0;y[a+24>>2]=c;continue}}o()}function qe(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0;d=Y-16|0;Y=d;e=y[y[b>>2]>>2];if(!y[a+48>>2]){Da(d+8|0,e);c=y[d+12>>2];y[a+44>>2]=y[d+8>>2];y[a+48>>2]=c}c=y[a+4>>2];if(c){f=y[a+8>>2]&2147483647;c=c-1|0;g=c>>>3|0;h=(c&7)+1|0;c=y[a+24>>2];while(1){a:{b:{if(c>>>0>=f>>>0){c=4}else{if(!ic(a,b,2496,g,h)){c=-1;break b}Kb(a,e);c=y[b+16>>2];if(!c){break a}if(!(_[y[y[c>>2]+8>>2]](c)|0)){break a}y[a+24>>2]=y[a+24>>2]+1;c=3}y[a+52>>2]=c}Y=d+16|0;return c|0}c=y[a+24>>2]+1|0;y[a+24>>2]=c;continue}}o()}function zc(a,b,c,d,e){var f=0,g=0;y[a>>2]=0;f=na(24);y[f+8>>2]=0;y[f+12>>2]=0;g=b;b=(c|0)==268435456|c>>>0<268435456;y[f>>2]=b?g:0;y[f+4>>2]=b?c:0;y[f+16>>2]=0;y[f+20>>2]=0;y[a+8>>2]=0;y[a+12>>2]=0;y[a+4>>2]=f;y[a+16>>2]=0;y[a+20>>2]=0;y[a+24>>2]=0;y[a+28>>2]=0;y[a+32>>2]=0;c=na(64);y[a+36>>2]=c;b=c- -64|0;y[a+44>>2]=b;f=0;while(1){if((f|0)!=64){y[c+f>>2]=0;f=f+4|0;continue}break}y[a+52>>2]=10;w[a+49|0]=0;w[a+50|0]=0;w[a+48|0]=e;y[a+40>>2]=b;t(a+56|0,0,49);w[a+112|0]=0;y[a+108>>2]=d;return a}function Wc(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0;a:{c=y[a+4>>2];d=y[a+8>>2];b:{if(c>>>0>>0){e=y[b>>2];y[b>>2]=0;y[c>>2]=e;b=c+4|0;break b}f=y[a>>2];e=c-f|0;h=e>>2;c=h+1|0;if(c>>>0>=1073741824){break a}d=d-f|0;g=d>>1;g=d>>>0>=2147483644?1073741823:c>>>0>>0?g:c;c:{if(!g){c=e;d=0;break c}d=Lb(g);f=y[a>>2];c=y[a+4>>2]-f|0;h=c>>2}i=y[b>>2];y[b>>2]=0;b=d+e|0;y[b>>2]=i;e=b-(h<<2)|0;if(c){p(e,f,c)}y[a+8>>2]=(g<<2)+d;b=b+4|0;y[a+4>>2]=b;y[a>>2]=e;if(!f){break b}ma(f)}y[a+4>>2]=b;return}Ba();o()}function zb(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){ac(c+80|0);ua(c+76|0);ua(c+72|0);Ja(c+60|0);b=y[c+36>>2];if(b){a=y[c+40>>2];while(1){if((a|0)!=(b|0)){a=pa(a-4|0);continue}break}y[c+40>>2]=b;ma(y[c+36>>2])}la(c+32|0);b=y[c+20>>2];if(b){a=y[c+24>>2];while(1){if((a|0)!=(b|0)){a=$b(a-4|0);continue}break}y[c+24>>2]=b;ma(y[c+20>>2])}b=y[c+8>>2];if(b){a=y[c+12>>2];while(1){if((a|0)!=(b|0)){a=ac(a-4|0);continue}break}y[c+12>>2]=b;ma(y[c+8>>2])}a=y[c+4>>2];y[c+4>>2]=0;if(a){ma(a)}ma(Ab(c))}}function oe(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0;d=Y-16|0;Y=d;e=y[y[b>>2]>>2];if(!y[a+48>>2]){Da(d+8|0,e);c=y[d+12>>2];y[a+44>>2]=y[d+8>>2];y[a+48>>2]=c}c=y[a+4>>2];if(c){c=c-1|0;f=c>>>3|0;g=(c&7)+1|0;c=y[a+24>>2];while(1){a:{b:{if(B[a+8>>2]<=c>>>0){c=4}else{if(!ic(a,b,2528,f,g)){c=-1;break b}Kb(a,e);c=y[b+16>>2];if(!c){break a}if(!(_[y[y[c>>2]+8>>2]](c)|0)){break a}y[a+24>>2]=y[a+24>>2]+1;c=3}y[a+52>>2]=c}Y=d+16|0;return c|0}c=y[a+24>>2]+1|0;y[a+24>>2]=c;continue}}o()}function Qd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;if(y[b+4>>2]==5604){b=y[a+12>>2];a:{if(b){a=5592;if(Bb(b,5480)){break a}}a=5600}y[c>>2]=a;return 1}e=y[a+8>>2];b:{c:{if(!(e&24)){d=Bb(b,5432);if(!d){break c}c=1;if(!Sa(a,b,(y[d+8>>2]&24)!=0)){break c}break b}c=1;if(Sa(a,b,1)){break b}}c=0;b=Bb(b,5532);if(!b){break b}d=y[b+8>>2];if(d&(e^-1)&7|(d^-1)&e&96|y[y[a+12>>2]+4>>2]!=y[y[b+12>>2]+4>>2]){break b}c=y[y[a+16>>2]+4>>2]==y[y[b+16>>2]+4>>2]}return c|0}function Wb(a,b){var c=0,d=0,e=0,f=0,g=0;e=Y-16|0;Y=e;a:{b:{f=y[a+4>>2];if(f-1>>>0<=65534){g=y[a+8>>2];if(g-1>>>0<65535){break b}}y[a+52>>2]=4;a=4;break a}y[a+52>>2]=2;c=y[b>>2];d=y[c>>2];if(!d){d=xa(f,g);y[e+12>>2]=0;oa(c,d);la(e+12|0);d=y[c>>2]}if(!qa(d)){oa(c,0);y[a+52>>2]=-1;a=-1;break a}Qa(y[c>>2],0);y[a+60>>2]=0;x[a+56>>1]=1;y[a+24>>2]=0;y[a+28>>2]=0;y[a+32>>2]=0;y[a+36>>2]=0;y[a+40>>2]=0;y[a+44>>2]=0;y[a+48>>2]=0;a=hd(a,b)}Y=e+16|0;return a}function Ba(){var a=0,b=0,c=0,d=0;c=Fb(8);y[c>>2]=5828;a=4883;b=0;a:{if(!z[4883]){break a}b:{c:{while(1){a=a+1|0;if(!(a&3)){break c}if(z[a|0]){continue}break}break b}while(1){b=a;a=a+4|0;d=y[b>>2];if(((16843008-d|d)&-2139062144)==-2139062144){continue}break}while(1){a=b;b=a+1|0;if(z[a|0]){continue}break}}b=a-4883|0}a=na(b+13|0);y[a+8>>2]=0;y[a+4>>2]=b;y[a>>2]=b;a=a+12|0;b=b+1|0;if(b){p(a,4883,b)}y[c>>2]=5876;y[c+4>>2]=a;P(c|0,5888,1);o()}function Gc(a,b){var c=0,d=0,e=0,f=0,g=0;a:{if((a|0)!=(b|0)){f=y[b+4>>2];e=y[b>>2];d=f-e|0;c=y[a+8>>2];b=y[a>>2];if(d>>>0<=c-b>>>0){g=y[a+4>>2];c=g-b|0;if(c>>>0>>0){if(!(!c|(b|0)==(g|0))){p(b,e,c)}Ec(a,c+e|0,f);return}if(!(!d|(e|0)==(f|0))){p(b,e,d)}y[a+4>>2]=b+d;return}if(b){y[a+4>>2]=b;ma(b);y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;c=0}if((d|0)<0){break a}b=c<<1;jc(a,c>>>0>=1073741823?2147483647:b>>>0>d>>>0?b:d);Ec(a,e,f)}return}Ba();o()}function Dc(a){var b=0,c=0,d=0,e=0,f=0;e=255;b=y[a+16>>2];a:{if(z[a+1|0]==255){f=8;d=y[b+8>>2];c=d+1|0;if(c>>>0>=B[b+4>>2]){break a}c=z[c+y[b>>2]|0];if(c>>>0>143){break a}Cc(b);w[a+1|0]=c;y[a+4>>2]=(y[a+4>>2]-(c<<9)|0)+65024;b=y[a+16>>2];d=y[b+8>>2];f=7;break a}Cc(b);f=8;b=y[a+16>>2];d=y[b+8>>2];c=y[b>>2];e=B[b+4>>2]>d>>>0?z[c+d|0]:e;w[a+1|0]=e;y[a+4>>2]=(y[a+4>>2]-(e<<8)|0)+65280}y[a+12>>2]=f;if(B[b+4>>2]<=d>>>0){w[a|0]=1}}function Ib(a,b,c,d){var e=0,f=0,g=0,h=0,i=0;f=b-1|0;g=y[d>>2];e=y[d+4>>2];a:{if((ia(a,f,g,e)|0)!=(c|0)){break a}if((ia(a,b,g,e)|0)!=(c|0)){break a}h=b+1|0;if((ia(a,h,g,e)|0)!=(c|0)){break a}g=y[d+8>>2];e=y[d+12>>2];if((ia(a,f,g,e)|0)!=(c|0)){break a}if((ia(a,h,g,e)|0)!=(c|0)){break a}e=f;f=y[d+16>>2];d=y[d+20>>2];if((ia(a,e,f,d)|0)!=(c|0)){break a}if((ia(a,b,f,d)|0)!=(c|0)){break a}i=(ia(a,h,f,d)|0)==(c|0)}return i}function ja(a,b,c){var d=0,e=0;d=Y-16|0;Y=d;a:{b:{c:{if(!(!(!qa(b)|(c|0)<0)&y[b+12>>2]>(c|0))){w[d+8|0]=0;break c}e=y[b+16>>2];if((e|0)<0){break b}c=se(e,0,c);if(Z){break b}y[d+8>>2]=c;e=1}w[d+12|0]=e;break a}o()}d:{e:{if(!z[d+12|0]){y[a>>2]=0;y[a+4>>2]=0;break e}Da(d,b);e=y[d+4>>2];c=y[d+8>>2];if(e>>>0>>0){break d}b=y[b+16>>2];if(b>>>0>e-c>>>0){break d}e=y[d>>2];y[a+4>>2]=b;y[a>>2]=c+e}Y=d+16|0;return}o()}function nd(a,b){var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;d=a+8|0;t(d,0,36);b=E(b,12);c=y[b+3072>>2];y[a+4>>2]=c;w[a+1|0]=z[b+3064|0];ad(d,c);Gb(a+20|0,c);Gb(a+32|0,c);b=y[b+3068>>2];d=b+(c<<3)|0;g=y[a+32>>2];h=y[a+20>>2];c=y[a+8>>2];while(1){if((b|0)!=(d|0)){y[c+(e<<3)>>2]=z[b|0];f=e<<2;y[f+h>>2]=z[b+1|0];y[g+f>>2]=y[b+4>>2];b=b+8|0;e=e+1|0;continue}break}i=a,j=ob(c,y[a+12>>2]-c>>3),w[i|0]=j;return a}function bd(a,b,c,d,e,f,g,h,i,j){var k=0,l=0;La(y[b+8>>2],d,i,j,e);i=y[a+12>>2];j=y[c>>2];b=ia(y[b+8>>2],d+2|0,g,h);y[c+4>>2]=e;y[c>>2]=b|j<<1&2;e=y[c+8>>2];a=y[a+20>>2];b=(d-i|0)+2|0;k=c,l=ia(y[a+8>>2],b,y[f>>2],y[f+4>>2])|e<<1&2,y[k+8>>2]=l;d=y[c+12>>2];k=c,l=ia(y[a+8>>2],b,y[f+8>>2],y[f+12>>2])|d<<1&6,y[k+12>>2]=l;d=y[c+16>>2];k=c,l=ia(y[a+8>>2],b,y[f+16>>2],y[f+20>>2])|d<<1&6,y[k+16>>2]=l}function Fc(a,b,c,d,e,f){var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;l=((b&536870911)<<3|a>>>29)&-8;h=1;while(1){a:{if(B[c>>2]>=l>>>0){break a}i=h&1;n=i?325:326;g=i?1056:1392;j=0;while(1){k=bc(g,n,a,b,c);if((k|0)<0){while(1){if(B[c>>2]>=l>>>0){break a}if(!Ka(a,b,c)){continue}break}break a}j=j+k|0;if(k>>>0>63){continue}break}g=j+m|0;if(!i){lb(d,e,f,m,g)}h=h^1;m=g;if((f|0)>(g|0)){continue}}break}}function Pd(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;a:{if(Sa(a,y[b+8>>2],e)){if(y[b+28>>2]==1|y[b+4>>2]!=(c|0)){break a}y[b+28>>2]=d;return}if(!Sa(a,y[b>>2],e)){break a}if(!(y[b+16>>2]!=(c|0)&y[b+20>>2]!=(c|0))){if((d|0)!=1){break a}y[b+32>>2]=1;return}y[b+20>>2]=c;y[b+32>>2]=d;y[b+40>>2]=y[b+40>>2]+1;if(!(y[b+36>>2]!=1|y[b+24>>2]!=2)){w[b+54|0]=1}y[b+44>>2]=4}}function Vd(a,b,c){a=a|0;b=b|0;c=c|0;var d=0,e=0;d=Y+-64|0;Y=d;a:{e=1;b:{if(y[a+4>>2]==y[b+4>>2]){break b}b=Bb(b,5384);e=0;if(!b){break b}e=y[c>>2];if(!e){break a}t(d+8|0,0,56);w[d+59|0]=1;y[d+16>>2]=-1;y[d+12>>2]=a;y[d+4>>2]=b;y[d+52>>2]=1;_[y[y[b>>2]+28>>2]](b,d+4|0,e,1);a=y[d+28>>2];if((a|0)==1){y[c>>2]=y[d+20>>2]}e=(a|0)==1}Y=d- -64|0;return e|0}Qc();o()}function Pc(a,b,c,d){w[a+53|0]=1;a:{if(y[a+4>>2]!=(c|0)){break a}w[a+52|0]=1;c=y[a+16>>2];b:{if(!c){y[a+36>>2]=1;y[a+24>>2]=d;y[a+16>>2]=b;if((d|0)!=1){break a}if(y[a+48>>2]==1){break b}break a}if((b|0)==(c|0)){c=y[a+24>>2];if((c|0)==2){y[a+24>>2]=d;c=d}if(y[a+48>>2]!=1){break a}if((c|0)==1){break b}break a}y[a+36>>2]=y[a+36>>2]+1}w[a+54|0]=1}}function Cd(a,b){var c=0,d=0,e=0;d=a,e=Fa(),y[d>>2]=e;d=a,e=Fa(),y[d+4>>2]=e;d=a,e=Fa(),y[d+8>>2]=e;d=a,e=Fa(),y[d+12>>2]=e;d=a,e=Fa(),y[d+16>>2]=e;d=a,e=Fa(),y[d+20>>2]=e;d=a,e=Fa(),y[d+24>>2]=e;d=a,e=Fa(),y[d+28>>2]=e;d=a,e=Fa(),y[d+32>>2]=e;c=na(16);w[c+12|0]=b;y[c+8>>2]=0;y[c>>2]=0;y[c+4>>2]=0;kb(c,1<>2]=c;return a}function kc(a){var b=0,c=0,d=0,e=0;b=Y-16|0;Y=b;c=na(20);w[c+4|0]=0;y[c>>2]=0;y[c+8>>2]=y[a+8>>2];d=y[a+12>>2];y[c+12>>2]=d;e=y[a+16>>2];y[c+16>>2]=e;Da(b+8|0,a);a:{b:{if(!y[b+12>>2]){break b}nb(c,td(e,d));Da(b,c);a=y[b+8>>2];e=0;d=y[b+12>>2];if(d>>>0>B[b+4>>2]){break a}if(!d|!(d|e)){break b}p(y[b>>2],a,d)}Y=b+16|0;return c}o()}function sd(a,b,c,d,e){var f=0,g=0,h=0,i=0;a:{if(!d){break a}if(e&1){f=b;g=d;if(c){e=32-c|0;f=d>>>0>>0?d:e;y[b>>2]=y[b>>2]|-1<>>e-f;g=d-f|0;f=b+4|0}i=g>>>5|0;e=i;h=f;while(1){if(e){y[h>>2]=-1;e=e-1|0;h=h+4|0;continue}break}e=g&31;if(!e){break a}f=(i<<2)+f|0;y[f>>2]=y[f>>2]|-1>>>32-e;break a}Xc(b,c,d)}Pb(a,b,c,d)}function ed(a,b){var c=0,d=0,e=0;c=Y-32|0;Y=c;a:{d=y[a+40>>2];if(d){e=y[a+48>>2];y[c+24>>2]=y[a+44>>2];y[c+28>>2]=e;b=y[b+16>>2];if(b>>>0>d>>>0){break a}a=y[a+36>>2];y[c+20>>2]=b;y[c+16>>2]=a;a=y[c+28>>2];y[c+8>>2]=y[c+24>>2];y[c+12>>2]=a;a=y[c+20>>2];y[c>>2]=y[c+16>>2];y[c+4>>2]=a;Pa(c+8|0,c)}Y=c+32|0;return}o()}function ra(a,b){var c=0,d=0,e=0,f=0,g=0;a:{d=y[a+8>>2];f=d+3|0;c=y[a+4>>2];if(f>>>0>>0){if(c>>>0<=d>>>0){break a}g=d+1|0;if(g>>>0>=c>>>0){break a}e=c;c=d+2|0;if(e>>>0<=c>>>0){break a}e=b;b=y[a>>2];y[e>>2]=z[b+g|0]<<16|z[b+d|0]<<24|z[b+c|0]<<8|z[b+f|0];y[a+8>>2]=y[a+8>>2]+4;a=0}else{a=-1}return a}o()}function dd(a,b,c){var d=0;d=Y-32|0;Y=d;ja(d+24|0,y[b+20>>2],(y[b+16>>2]^-1)+c|0);y[a>>2]=y[d+24>>2];y[a+4>>2]=y[d+28>>2];ja(d+16|0,y[b+20>>2],c-y[b+16>>2]|0);y[a+8>>2]=y[d+16>>2];y[a+12>>2]=y[d+20>>2];ja(d+8|0,y[b+20>>2],(c-y[b+16>>2]|0)+1|0);y[a+16>>2]=y[d+8>>2];y[a+20>>2]=y[d+12>>2];Y=d+32|0}function xa(a,b){var c=0,d=0;c=na(20);y[c+16>>2]=0;y[c+8>>2]=0;y[c+12>>2]=0;w[c+4|0]=0;y[c>>2]=0;a:{if(a-2147483617>>>0<2147483680|(b|0)<=0){break a}d=a+31&2147483616;if(2147483616/(d>>>0)>>>0>>0){break a}y[c+12>>2]=b;y[c+8>>2]=a;a=d>>>3|0;y[c+16>>2]=a;nb(c,td(a,b))}return c}function Sa(a,b,c){var d=0;if(!c){return y[a+4>>2]==y[b+4>>2]}if((a|0)==(b|0)){return 1}c=y[a+4>>2];a=z[c|0];b=y[b+4>>2];d=z[b|0];a:{if(!a|(d|0)!=(a|0)){break a}while(1){d=z[b+1|0];a=z[c+1|0];if(!a){break a}b=b+1|0;c=c+1|0;if((a|0)==(d|0)){continue}break}}return(a|0)==(d|0)}function Pa(a,b){var c=0,d=0,e=0;a:{c=y[a+4>>2];b:{if(!c){break b}if(!y[b+4>>2]){a=y[a>>2];while(1){if((c|0)<=0){break b}w[a|0]=0;c=c-1|0;a=a+1|0;continue}}e=y[b>>2];d=y[b+4>>2];c=y[a>>2];b=0;if(1&B[a+4>>2]>>0){break a}if(!(b|d)|!d){break b}p(c,e,d)}return}o()}function Ad(a){var b=0,c=0,d=0,e=0,f=0,g=0;d=Y-16|0;Y=d;e=lc();f=e+24|0;g=y[a+28>>2];c=y[a+24>>2];while(1){if((c|0)!=(g|0)){b=y[c>>2];if(b){b=kc(b)}else{b=0}y[d+12>>2]=b;b=d+12|0;Wc(f,b);c=c+4|0;la(b);continue}break}c=Sb(e,a);Sb(c+12|0,a+12|0);Y=d+16|0;return c}function Jb(a,b,c){var d=0;d=Y-32|0;Y=d;ja(d+24|0,y[b+20>>2],c-1|0);y[a>>2]=y[d+24>>2];y[a+4>>2]=y[d+28>>2];ja(d+16|0,y[b+20>>2],c);y[a+8>>2]=y[d+16>>2];y[a+12>>2]=y[d+20>>2];ja(d+8|0,y[b+20>>2],c+1|0);y[a+16>>2]=y[d+8>>2];y[a+20>>2]=y[d+12>>2];Y=d+32|0}function Oc(a,b,c){var d=0;d=y[a+36>>2];if(!d){y[a+24>>2]=c;y[a+16>>2]=b;y[a+36>>2]=1;y[a+20>>2]=y[a+56>>2];return}a:{if(!(y[a+20>>2]!=y[a+56>>2]|y[a+16>>2]!=(b|0))){if(y[a+24>>2]!=2){break a}y[a+24>>2]=c;return}w[a+54|0]=1;y[a+24>>2]=2;y[a+36>>2]=d+1}}function Ra(a){var b=0,c=0,d=0,e=0;b=na(20);y[b+16>>2]=a;w[b|0]=0;c=255;d=y[a>>2];e=y[a+4>>2];a=y[a+8>>2];if(e>>>0>a>>>0){c=z[a+d|0]}w[b+1|0]=c;y[b+4>>2]=((c^-1)&255)<<16;Dc(b);y[b+8>>2]=32768;y[b+4>>2]=y[b+4>>2]<<7;y[b+12>>2]=y[b+12>>2]-7;return b}function Xc(a,b,c){var d=0,e=0;if(b){d=32-b|0;e=c>>>0>>0?c:d;y[a>>2]=y[a>>2]&(-1<>>d-e^-1);c=c-e|0;a=a+4|0}e=c>>>5|0;b=e;d=a;while(1){if(b){y[d>>2]=0;b=b-1|0;d=d+4|0;continue}break}b=c&31;if(b){a=(e<<2)+a|0;y[a>>2]=y[a>>2]&(-1>>>32-b^-1)}}function tb(a,b){var c=0;c=1;a:{if(ra(y[a+4>>2],b)){break a}if(ra(y[a+4>>2],b+4|0)){break a}if(ra(y[a+4>>2],b+8|0)){break a}if(ra(y[a+4>>2],b+12|0)){break a}if(va(y[a+4>>2],b+16|0)|(y[b>>2]>4096|y[b+4>>2]>4096)&z[a+112|0]==1){break a}c=0}return c}function zd(a,b,c){var d=0,e=0;d=na(32);e=y[b+12>>2];y[d+16>>2]=y[b+8>>2];y[d+20>>2]=e;e=y[b+4>>2];y[d+8>>2]=y[b>>2];y[d+12>>2]=e;b=y[c>>2];y[c>>2]=0;y[d>>2]=a;y[d+24>>2]=b;b=y[a+4>>2];y[d+4>>2]=b;y[b>>2]=d;y[a+4>>2]=d;y[a+8>>2]=y[a+8>>2]+1}function Ga(a,b,c){var d=0,e=0,f=0,g=0;d=y[b+8>>2];g=(d|0)>0?d:0;d=0;while(1){a:{if((d|0)==(g|0)){e=0;break a}e=Ma(a,y[y[b+12>>2]+(d<<2)>>2]);if(!(!e|(z[e+4|0]&63)!=53)){if((c|0)==(f|0)){break a}f=f+1|0}d=d+1|0;continue}break}return e}function Ub(a,b){var c=0;y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;a:{if(b){if(b>>>0>=1073741824){break a}c=b<<2;b=na(c);y[a>>2]=b;c=b+c|0;y[a+8>>2]=c;while(1){if((b|0)!=(c|0)){y[b>>2]=0;b=b+4|0;continue}break}y[a+4>>2]=c}return a}Ba();o()}function gb(a,b){var c=0;y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;a:{if(b){if(b>>>0>=1073741824){break a}c=Lb(b);y[a>>2]=c;b=(b<<2)+c|0;y[a+8>>2]=b;while(1){if((b|0)!=(c|0)){y[c>>2]=0;c=c+4|0;continue}break}y[a+4>>2]=b}return a}Ba();o()}function od(a,b){var c=0,d=0;c=Y-16|0;Y=c;y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;y[c+8>>2]=a;if(b){jc(a,b);d=b;b=y[a+4>>2];d=d+b|0;while(1){if((b|0)!=(d|0)){w[b|0]=0;b=b+1|0;continue}break}y[a+4>>2]=d}w[c+12|0]=1;fd(c+8|0);Y=c+16|0}function Kc(a,b){var c=0,d=0,e=0;c=Y-16|0;Y=c;d=z[a+4|0];if((d|0)==255){a=Fb(4);y[a>>2]=5288;P(a|0,5300,2);o()}y[c+4>>2]=c+3;e=y[b+4>>2];y[c+8>>2]=y[b>>2];y[c+12>>2]=e;a=_[y[(c+8|0)+(d<<2)>>2]](c+4|0,a)|0;Y=c+16|0;return a}function qb(){var a=0;a=na(80);x[a+56>>1]=0;y[a+12>>2]=0;y[a+24>>2]=0;y[a+28>>2]=0;y[a+32>>2]=0;y[a+36>>2]=0;y[a+40>>2]=0;y[a+44>>2]=0;y[a+48>>2]=0;y[a+60>>2]=0;y[a+64>>2]=0;y[a+68>>2]=0;y[a+72>>2]=0;y[a+76>>2]=0;return a}function Yb(){var a=0;a=na(96);y[a+44>>2]=0;y[a+48>>2]=0;y[a+36>>2]=0;y[a+40>>2]=0;y[a+28>>2]=0;y[a+32>>2]=0;y[a+60>>2]=0;y[a+64>>2]=0;y[a+68>>2]=0;y[a+72>>2]=0;y[a+76>>2]=0;y[a+80>>2]=0;y[a+84>>2]=0;y[a+88>>2]=0;return a}function La(a,b,c,d,e){a:{if(!(!d|(b|0)<0|(a|0)<=(b|0))){a=b>>>3|0;b=1<<((b^-1)&7);if(e){if(a>>>0>=d>>>0){break a}a=a+c|0;w[a|0]=b|z[a|0];return}if(a>>>0>=d>>>0){break a}a=a+c|0;w[a|0]=z[a|0]&(b^-1)}return}o()}function id(a){var b=0,c=0,d=0;y[a+56>>2]=2;c=1;b=4;d=y[a+52>>2];a:{b:{if((d|0)==5){break b}if((d|0)>=3){y[a+52>>2]=5;break b}b=yc(a);c=!b;if(y[a+56>>2]==3){break a}y[a+52>>2]=5;b=b?-1:4}y[a+56>>2]=b}return c}function se(a,b,c){var d=0,e=0,f=0,g=0,h=0;e=c>>>16|0;d=a>>>16|0;h=E(e,d);f=c&65535;a=a&65535;g=E(f,a);d=(g>>>16|0)+E(d,f)|0;a=(d&65535)+E(a,e)|0;Z=h+E(b,c)+(d>>>16)+(a>>>16)|0;return g&65535|a<<16}function Ma(a,b){var c=0,d=0;c=y[a>>2];a:{if(c){c=Ma(c,b);if(c){break a}}d=y[a+12>>2];a=y[a+8>>2];while(1){if((a|0)==(d|0)){return 0}c=y[a>>2];a=a+4|0;if(y[c>>2]!=(b|0)){continue}break}}return c}function xd(a){var b=0;a:{if(z[a+16|0]!=3|z[a+17|0]!=255|(z[a+18|0]!=253|z[a+19|0]!=255)){break a}if(z[a+20|0]!=2|z[a+21|0]!=254|(z[a+22|0]!=254|z[a+23|0]!=254)){break a}b=z[a+2|0]^1}return b&1}function Wa(a,b){var c=0,d=0,e=0;a:{c=y[a+8>>2];e=c+1|0;d=y[a+4>>2];if(e>>>0>>0){if(c>>>0>=d>>>0){break a}d=b;b=y[a>>2];x[d>>1]=z[b+c|0]<<8|z[b+e|0];y[a+8>>2]=c+2;a=0}else{a=-1}return a}o()}function Kb(a,b){var c=0;c=y[a+40>>2];y[a+28>>2]=y[a+36>>2];y[a+32>>2]=c;c=y[a+48>>2];b=y[b+16>>2];if(c>>>0>>0){o()}y[a+40>>2]=c;y[a+48>>2]=c-b;c=y[a+44>>2];y[a+36>>2]=c;y[a+44>>2]=b+c}function cd(a,b,c,d,e,f,g,h){return y[c+16>>2]|y[c+12>>2]<<3|y[c+8>>2]<<6|ia(y[y[a+20>>2]+8>>2],w[a+26|0]+(d-y[a+12>>2]|0)|0,e,f)<<8|y[c+4>>2]<<9|y[c>>2]<<10|ia(b,w[a+24|0]+d|0,g,h)<<12}function sa(a,b){var c=0,d=0,e=0;d=Y-16|0;Y=d;e=b<<2;c=y[e+y[a+36>>2]>>2];if(!c){b=nd(na(44),b);c=y[a+36>>2];y[d+12>>2]=0;vb(c+e|0,b);pa(d+12|0);c=y[y[a+36>>2]+e>>2]}Y=d+16|0;return c}function bb(a,b){var c=0;c=y[a>>2];if(c){y[a+4>>2]=c;ma(c);y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0}y[a>>2]=y[b>>2];y[a+4>>2]=y[b+4>>2];y[a+8>>2]=y[b+8>>2];y[b+8>>2]=0;y[b>>2]=0;y[b+4>>2]=0}function Hc(a,b,c){var d=0,e=0;e=((b&536870911)<<3|a>>>29)&-8;d=y[c>>2];a:{while(1){if(B[c>>2]>=e>>>0){break a}if(!Ka(a,b,c)){continue}break}if(y[c>>2]-d>>>0>11){break a}y[c>>2]=d}}function Ed(a,b){var c=0;y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;a:{if(b){if(b>>>0>=536870912){break a}c=yb(b);y[a+4>>2]=c;y[a>>2]=c;y[a+8>>2]=(b<<3)+c;ld(a,b)}return a}Ba();o()}function Jc(a,b){var c=0,d=0,e=0;c=Y-16|0;Y=c;d=z[a+4|0];if((d|0)!=255){e=y[b+4>>2];y[c+8>>2]=y[b>>2];y[c+12>>2]=e;_[y[(c+8|0)+(d<<2)>>2]](c+7|0,a)}w[a+4|0]=255;Y=c+16|0}function Tc(a,b){var c=0;c=Y-16|0;Y=c;y[c+8>>2]=0;a:{if(z[a+4|0]==1){oa(a,b);break a}mb(a);w[a+4|0]=1;y[a>>2]=b}y[c+12>>2]=0;la(c+12|0);la(c+8|0);Y=c+16|0;return a}function Db(a,b){var c=0;if(z[a|0]==1){c=y[a+4>>2];b=se(c,c>>31,b);c=Z;c=!(b- -2147483648>>>0<2147483648?c+1|0:c);b=c?b:0}else{b=0}y[a>>2]=c;y[a+4>>2]=b;return a}function Ac(a,b,c){var d=0,e=0,f=0;d=1;while(1){e=z[a+12|0];if(e>>>0<=(f&255)>>>0){y[c>>2]=(-1<>2]+(d<<3)|0)|d<<1;f=f+1|0;continue}break}}function Hb(a,b,c,d,e,f,g){var h=0,i=0;h=Y-16|0;Y=h;if(qa(a)){i=y[a+12>>2];y[h+8>>2]=y[a+8>>2];y[h+12>>2]=i;y[h>>2]=0;y[h+4>>2]=0;Zc(a,b,c,d,e,f,g,h)}Y=h+16|0}function Cb(a,b,c,d){var e=0;e=Y-16|0;Y=e;y[e+12>>2]=d;d=1;w[e+8|0]=1;a:{if(!z[Na(e+8|0,b>>c)|0]){d=0;w[a|0]=0;break a}y[a>>2]=y[e+12>>2]}w[a+4|0]=d;Y=e+16|0}function qc(a){var b=0;b=y[a+36>>2];y[a+36>>2]=0;if(b){ma(Ja(b))}Ea(a+32|0);Ea(a+28|0);Ea(a+24|0);Ea(a+20|0);Ea(a+16|0);Ea(a+12|0);Ea(a+8|0);Ea(a+4|0);Ea(a)}function Qa(a,b){var c=0,d=0;c=Y-16|0;Y=c;Da(c+8|0,a);d=0-b|0;a=y[c+12>>2];b=y[c+8>>2];while(1){if((a|0)>0){w[b|0]=d;a=a-1|0;b=b+1|0;continue}break}Y=c+16|0}function md(a,b){var c=0;y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;if(b>>>0>=1073741824){Ba();o()}c=Lb(b);y[a+4>>2]=c;y[a>>2]=c;y[a+8>>2]=(b<<2)+c;kd(a,b);return a}function pb(a,b){var c=0;c=y[a+4>>2];if(b){c=c+1|0;y[a+4>>2]=c}b=y[a+12>>2]-y[a+8>>2]>>3;if(b>>>0<=c>>>0){b=b+16|0;ad(a+8|0,b);Gb(a+20|0,b);Gb(a+32|0,b)}}function jc(a,b){var c=0;a:{if((b|0)>=0){if(b>>>0>2147479550){break a}c=Ya(b);if(!c){break a}y[a+4>>2]=c;y[a>>2]=c;y[a+8>>2]=b+c;return}Ba();o()}rb();o()}function _c(a,b){var c=0;a:{if(!z[a+4|0]){c=y[b>>2];if((c|0)==y[a>>2]){break a}y[b>>2]=0;y[a>>2]=c;return}ub(a);c=y[b>>2];y[b>>2]=0;w[a+4|0]=0;y[a>>2]=c}}function Ud(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;if(Sa(a,y[b+8>>2],f)){Pc(b,c,d,e);return}a=y[a+8>>2];_[y[y[a>>2]+20>>2]](a,b,c,d,e,f)}function Eb(a,b,c){a:{switch(a|0){case 1:return b&c;case 2:return b^c;case 3:return b^c^-1;default:o();case 0:b=b|c;break;case 4:break a}}return b}function wc(a){var b=0,c=0,d=0;c=E(z[a+1|0],y[a+4>>2]+1|0);if(c>>>0<=65535){d=z[a+2|0];b=qb();a=z[a|0];y[b+8>>2]=d;y[b+4>>2]=c;w[b|0]=a}return b}function Tb(a){var b=0,c=0,d=0;a:{if(z[a|0]!=1){break a}b=y[a+4>>2];if((b|0)<0){break a}c=b>>>0<1073741824;d=b<<1}y[a>>2]=c;y[a+4>>2]=d;return a}function Vc(a,b,c){var d=0;if(!(b&1)|z[a|0]!=1){b=0;c=0}else{b=y[a+4>>2];d=b;b=b+c|0;c=((d^b)&(b^c))>=0;b=c?b:0}y[a>>2]=c;y[a+4>>2]=b;return a}function ld(a,b){var c=0;c=y[a+4>>2];b=c+(b<<3)|0;while(1){if((b|0)==(c|0)){y[a+4>>2]=b}else{y[c>>2]=0;y[c+4>>2]=0;c=c+8|0;continue}break}}function fe(a,b,c){a=a|0;b=b|0;c=c|0;var d=0;d=y[a+4>>2];a=y[a+8>>2];b=(a>>1)+b|0;c=y[c>>2];if(a&1){d=y[d+y[b>>2]>>2]}return _[d|0](b,c)|0}function Da(a,b){var c=0,d=0;d=Nb(b);a:{c=y[b+16>>2];if((c|0)>=0){b=y[b+12>>2];b=se(b,b>>31,c);if(!Z){break a}}o()}y[a+4>>2]=b;y[a>>2]=d}function Sd(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;if(y[a+4>>2]==y[y[b+8>>2]+4>>2]){Oc(b,c,d);return}a=y[a+8>>2];_[y[y[a>>2]+28>>2]](a,b,c,d)}function vd(a,b,c,d){if(b>>>0<=d>>>0){b=(b<<2)+a|0;while(1){if((a|0)!=(b|0)){y[c>>2]=y[a>>2];c=c+4|0;a=a+4|0;continue}break}return}o()}function ia(a,b,c,d){a:{if(!d|(b|0)<0|(a|0)<=(b|0)){a=0}else{a=b>>>3|0;if(a>>>0>=d>>>0){break a}a=z[a+c|0]>>>((b^-1)&7)&1}return a}o()}function wb(a,b){var c=0,d=0;d=y[a>>2];c=y[a+8>>2];if(c>>>0>2]){y[b>>2]=z[d+c|0]>>>7-y[a+12>>2]&1;_b(a);a=0}else{a=-1}return a}function Yc(a,b){var c=0,d=0;if(z[a|0]==1){c=y[a+4>>2];d=c-b|0;c=((c^d)&(b^c))>=0;b=c?d:0}else{b=0;c=0}y[a>>2]=c;y[a+4>>2]=b;return a}function Na(a,b){var c=0,d=0;if(z[a|0]==1){c=y[a+4>>2];d=c+b|0;c=((d^c)&(b^d))>=0;b=c?d:0}else{b=0;c=0}y[a>>2]=c;y[a+4>>2]=b;return a}function nb(a,b){var c=0;c=Y-16|0;Y=c;a:{if(z[a+4|0]==1){rc(a,b);break a}ub(a);w[a+4|0]=1;y[a>>2]=b}y[c+12>>2]=0;Ha(c+12|0);Y=c+16|0}function $a(a){var b=0,c=0;b=y[a>>2];if(b){c=y[a+4>>2];while(1){if((c|0)!=(b|0)){c=la(c-4|0);continue}break}y[a+4>>2]=b;ma(y[a>>2])}}function va(a,b){var c=0,d=0;d=y[a>>2];c=y[a+8>>2];if(c>>>0>2]){w[b|0]=z[d+c|0];y[a+8>>2]=y[a+8>>2]+1;a=0}else{a=-1}return a}function re(){var a=0,b=0,c=0;while(1){b=a<<4;c=b+6080|0;y[b+6084>>2]=c;y[b+6088>>2]=c;a=a+1|0;if((a|0)!=64){continue}break}Fd(48)}function Sc(a){a=a|0;var b=0,c=0,d=0;y[a>>2]=5828;b=y[a+4>>2];c=b-4|0;d=y[c>>2]-1|0;y[c>>2]=d;if((d|0)<0){ma(b-12|0)}return a|0}function kd(a,b){var c=0;c=y[a+4>>2];b=c+(b<<2)|0;while(1){if((b|0)==(c|0)){y[a+4>>2]=b}else{y[c>>2]=0;c=c+4|0;continue}break}}function Ca(a,b,c){var d=0;d=Y-16|0;Y=d;ja(d+8|0,b,c);b=y[d+8>>2];if(b&3){o()}c=y[d+12>>2];y[a>>2]=b;y[a+4>>2]=c>>>2;Y=d+16|0}function Ec(a,b,c){var d=0;d=y[a+4>>2];while(1){if((b|0)!=(c|0)){w[d|0]=z[b|0];d=d+1|0;b=b+1|0;continue}break}y[a+4>>2]=d}function Pb(a,b,c,d){a:{if((d|0)>=0){d=c+d|0;c=d>>>5|0;break a}d=c+d|0;c=(d-31|0)/32|0}y[a+4>>2]=d&31;y[a>>2]=(c<<2)+b}function Ka(a,b,c){var d=0;d=c;c=y[c>>2];y[d>>2]=c+1;d=b;b=c>>>3|0;if(d>>>0<=b>>>0){o()}return z[a+b|0]>>>((c^-1)&7)&1}function ta(a){var b=0,c=0;if(y[a+12>>2]){b=y[a+8>>2]+1|0;if(b){c=y[a+4>>2];y[a+8>>2]=b>>>0>>0?b:c}y[a+12>>2]=0}}function yd(a,b){var c=0;c=se(b,0,a);if(Z|c>>>0>2147479550){a=0}else{b=E(a,b);a=Ya(b);if(b?a:0){t(a,0,b)}}return a}function ib(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){pa(c+68|0);la(c- -64|0);Zb(c+60|0);Za(c+56|0);Ja(c+12|0);ma(c)}}function Bc(a,b,c){if(c>>>0>=536870912){Ba();o()}a=b-a|0;b=a>>2;return a>>>0>=2147483640?536870911:b>>>0>c>>>0?b:c}function pd(a,b){jd(a);y[a>>2]=y[b>>2];y[a+4>>2]=y[b+4>>2];y[a+8>>2]=y[b+8>>2];y[b+8>>2]=0;y[b>>2]=0;y[b+4>>2]=0}function gd(a){var b=0;a:{b=a;a=y[a+16>>2];if((b|0)==(a|0)){b=16}else{if(!a){break a}b=20}_[y[b+y[a>>2]>>2]](a)}}function Vb(a,b){var c=0;c=y[a+52>>2];if((c|0)==3){if(A[a+56>>1]!=1){y[a+52>>2]=-1;return-1}c=hd(a,b)}return c}function ie(a){a=a|0;var b=0,c=0;b=na(12);y[b>>2]=2600;c=y[a+8>>2];y[b+4>>2]=y[a+4>>2];y[b+8>>2]=c;return b|0}function _b(a){var b=0;b=y[a+12>>2];a:{if((b|0)==7){y[a+8>>2]=y[a+8>>2]+1;b=0;break a}b=b+1|0}y[a+12>>2]=b}function _a(a){var b=0,c=0;b=y[a+4>>2];if(!b){o()}c=y[a>>2];y[a>>2]=c+4;y[a+4>>2]=b-1;return y[c>>2]}function Uc(a,b){a:{b:{if(!z[a+4|0]){if(y[a>>2]!=(b|0)){break b}break a}mb(a);w[a+4|0]=0}y[a>>2]=b}}function Od(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;if(Sa(a,y[b+8>>2],f)){Pc(b,c,d,e)}}function gc(a){var b=0,c=0;b=y[a+4>>2];if(!b){o()}c=y[a>>2];y[a>>2]=c+4;y[a+4>>2]=b-1;return c}function he(a,b){a=a|0;b=b|0;var c=0;y[b>>2]=2600;c=y[a+8>>2];y[b+4>>2]=y[a+4>>2];y[b+8>>2]=c}function rd(a,b){var c=0;c=Y-16|0;Y=c;y[c+12>>2]=b;b=a+24|0;a=c+12|0;Wc(b,a);la(a);Y=c+16|0}function jd(a){var b=0;b=y[a>>2];if(b){y[a+4>>2]=b;ma(b);y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0}}function Cc(a){var b=0,c=0;b=y[a+8>>2]+1|0;if(b){c=a;a=y[a+4>>2];y[c+8>>2]=a>>>0>b>>>0?b:a}}function tc(a,b,c,d,e,f,g,h){a:{if(!qa(a)){break a}if(!qa(f)){break a}Zc(f,a,b,c,d,e,h,g)}}function vb(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){ya(c+32|0);ya(c+20|0);ya(c+8|0);ma(c)}}function te(a,b){var c=0,d=0;c=b&31;d=(-1<>>c|0;c=a;a=0-b&31;return d|(c&-1>>>a)<>2]==y[y[b+8>>2]+4>>2]){Oc(b,c,d)}}function Jd(a){a=a|0;var b=0;b=y[a+60>>2];a=y[a+48>>2]+7>>>3|0;return(a>>>0>b>>>0?b:a)|0}function Ic(a,b){b=b-a|0;while(1){if((b|0)>0){w[a|0]=255;b=b-1|0;a=a+1|0;continue}break}}function Rb(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){$a(c+24|0);Ja(c+12|0);ma(Ja(c))}}function Fa(){var a=0;a=na(12);y[a+8>>2]=0;y[a>>2]=0;y[a+4>>2]=0;kb(a,512);return a}function Nc(a){a=a|0;y[a+36>>2]=0;y[a+40>>2]=0;ya(a+76|0);ya(a- -64|0);return a|0}function td(a,b){if(4294967295/(b>>>0)>>>0<=a>>>0){rb();o()}return ab(E(a,b),1)}function Lc(a,b){var c=0;return(z[a+16|0]!=(b|0)|z[a+17|0]!=255?c:z[a+2|0]^1)&1}function pc(a){var b=0;b=y[a>>2];y[a>>2]=0;if(b){ya(b+40|0);ya(b+28|0);ma(b)}}function Id(a){a=a|0;Ic(y[a+76>>2],y[a+80>>2]);y[a+48>>2]=0;return 1}function Xb(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){$a(c+4|0);ma(c)}}function Ja(a){var b=0;b=y[a>>2];if(b){y[a+4>>2]=b;ma(b)}return a}function oa(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){ub(c);ma(c)}}function $b(a){var b=0;b=y[a>>2];y[a>>2]=0;if(b){ma(b)}return a}function vc(a){var b=0;b=na(16);y[b>>2]=a;gb(b+4|0,a);return b}function ee(a,b){a=a|0;b=b|0;return(y[b+4>>2]==2888?a+4|0:0)|0}function Lb(a){if(a>>>0>=1073741824){jb();o()}return na(a<<2)}function yb(a){if(a>>>0>=536870912){jb();o()}return na(a<<3)}function jb(){var a=0;a=Fb(4);y[a>>2]=5724;P(a|0,5780,2);o()}function Ea(a){var b=0;b=y[a>>2];y[a>>2]=0;if(b){ma(Ja(b))}}function na(a){a=Ya(a>>>0<=1?1:a);if(!a){Qc();o()}return a}function ya(a){var b=0;b=y[a>>2];if(b){y[a+4>>2]=b;ma(b)}}function Va(a,b){var c=0;c=y[a>>2];y[a>>2]=b;if(c){ma(c)}}function fb(a,b,c,d,e,f,g){if(qa(a)){Hb(f,a,b,c,d,e,g)}}function Ua(a){var b=0;b=y[a>>2];y[a>>2]=0;if(b){ma(b)}}function ue(a){if(a){return 31-H(a-1^a)|0}return 32}
+function db(){var a=0;a=na(28);y[a+20>>2]=0;return a}function ab(a,b){a=yd(a,b);if(!a){rb();o()}return a}function rc(a,b){var c=0;c=y[a>>2];y[a>>2]=b;ma(c)}function qd(a){var b=0;b=na(4);y[b>>2]=a;return b}function lc(){var a=0;a=na(36);t(a,0,36);return a}function rb(){y[(Y-16|0)+12>>2]=6036;sc();o()}function Wd(a,b,c){a=a|0;b=b|0;c=c|0;return 0}function Oa(a,b,c,d){return(Eb(a,b,c)^c)&d^c}function Mb(a,b){a=a|0;b=b|0;return y[b>>2]}function ge(a){a=a|0;_[y[y[a>>2]+4>>2]](a)}function fd(a){if(!z[a+4|0]){ya(y[a>>2])}}function Zd(a){a=a|0;T();S(a+128|0);o()}function Ob(a){a=y[a>>2];if(a){ma(a)}}function Md(a){a=a|0;return y[a+4>>2]}function Gd(a){a=a|0;return Ya(a)|0}function Fb(a){return Ya(a|80)+80|0}function wa(a){return nd(na(44),a)}function ce(a,b){a=a|0;b=b|0;Ha(b)}function be(a,b){a=a|0;b=b|0;la(b)}function qa(a){return(Nb(a)|0)!=0}function fc(a){return(Xa(a)|0)!=0}function de(a){a=a|0;return 2868}function Yd(a){a=a|0;return 4890}function Xd(a){a=a|0;return 4864}function Xa(a){return Kc(a,4944)}function Nd(a){a=a|0;return 4913}function Nb(a){return Kc(a,2416)}function xb(a){a=a|0;return a|0}function pa(a){vb(a,0);return a}function oc(a){Za(a+24|0);ma(a)}function la(a){oa(a,0);return a}function ac(a){ib(a,0);return a}function Ab(a){zb(a,0);return a}function Mc(a){a=a|0;ma(Sc(a))}function Kd(a){a=a|0;ma(Nc(a))}function wd(a){return Lc(a,3)}function _d(a){a=a|0;sc();o()}function Qb(a){return Lc(a,2)}function $c(a,b){a=a|0;b=b|0}function Ta(a){a=a|0;ma(a)}function ub(a){Jc(a,4856)}function mb(a){Jc(a,4936)}function ua(a){Va(a,0)}function Zb(a){Xb(a,0)}function Za(a){Rb(a,0)}function Qc(){sc();o()}function Ha(a){rc(a,0)}function sc(){U();o()}function hc(a){a=a|0}
+// EMSCRIPTEN_END_FUNCS
+a=z;m(n);var _=[null,Sc,xb,qe,pe,oe,ne,me,le,ke,je,xb,Nc,Kd,Jd,Id,Hd,Mb,Mb,xb,Ta,ie,he,hc,ge,fe,ee,de,$c,ce,$c,be,Mb,Mb,Zd,_d,Ta,Yd,Ta,Xd,xb,Ta,hc,hc,Wd,Ta,Qd,Ta,Nd,Mc,Md,Mc,Ta,Vd,Od,Pd,Rd,Ta,Ud,Td,Sd];function $(){return v.byteLength>>16}function ea(fa){fa=fa|0;var aa=$()|0;var ba=aa+fa|0;if(aa{Module["instantiateWasm"](info,(inst,mod)=>{resolve(receiveInstance(inst,mod))})})}wasmBinaryFile??=findWasmBinary();var result=instantiateSync(wasmBinaryFile,info);return receiveInstance(result[0])}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var HEAP16;var HEAP32;var HEAP8;var HEAPF32;var HEAPF64;var HEAPU16;var HEAPU32;var HEAPU8;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var onPostRuns=[];var addOnPostRun=cb=>onPostRuns.push(cb);var onPreRuns=[];var addOnPreRun=cb=>onPreRuns.push(cb);var noExitRuntime=true;class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>2]=type}get_type(){return HEAPU32[this.ptr+4>>2]}set_destructor(destructor){HEAPU32[this.ptr+8>>2]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>2]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12]=caught}get_caught(){return HEAP8[this.ptr+12]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13]=rethrown}get_rethrown(){return HEAP8[this.ptr+13]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>2]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>2]}}var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);uncaughtExceptionCount++;abort()};var __abort_js=()=>abort("");var runtimeKeepaliveCounter=0;var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};var timers={};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{return func()}catch(e){handleException(e)}finally{maybeExit()}};var _emscripten_get_now=()=>performance.now();var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id,timeout_ms};return 0};function _createImageData(size){Module.imageData=new Uint8Array(size)}var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var oldHeapSize=wasmMemory.buffer.byteLength;var pages=(size-oldHeapSize+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};function _setImageData(array_ptr,pitch8,pitch32,height){if(pitch32===pitch8){Module.imageData=new Uint8ClampedArray(HEAPU8.subarray(array_ptr,array_ptr+pitch32*height));return}const destSize=pitch8*height;const imageData=Module.imageData=new Uint8ClampedArray(destSize);for(let srcStart=array_ptr,destStart=0;destStart{HEAP8.set(array,buffer)};{if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(Module["print"])out=Module["print"];if(Module["printErr"])err=Module["printErr"];if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].shift()()}}}Module["writeArrayToMemory"]=writeArrayToMemory;var _malloc,_free,_jbig2_decode,_ccitt_decode,__emscripten_timeout,memory,__indirect_function_table,wasmMemory;function assignWasmExports(wasmExports){_malloc=Module["_malloc"]=wasmExports["l"];_free=Module["_free"]=wasmExports["m"];_jbig2_decode=Module["_jbig2_decode"]=wasmExports["n"];_ccitt_decode=Module["_ccitt_decode"]=wasmExports["o"];__emscripten_timeout=wasmExports["p"];memory=wasmMemory=wasmExports["j"];__indirect_function_table=wasmExports["__indirect_function_table"]}var wasmImports={a:___cxa_throw,f:__abort_js,e:__emscripten_runtime_keepalive_clear,b:__setitimer_js,h:_createImageData,c:_emscripten_resize_heap,d:_proc_exit,i:_setImageData,g:_setLineData};function run(){preRun();function doRun(){Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve?.(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}var wasmExports;wasmExports=createWasm();run();if(runtimeInitialized){moduleRtn=Module}else{moduleRtn=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject})}
+;return moduleRtn}export default JBig2;
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/openjpeg.wasm b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/openjpeg.wasm
new file mode 100644
index 0000000..5acce73
Binary files /dev/null and b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/openjpeg.wasm differ
diff --git a/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/openjpeg_nowasm_fallback.js b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/openjpeg_nowasm_fallback.js
new file mode 100644
index 0000000..0df96ae
--- /dev/null
+++ b/app/web/vendor/pdfjs/6.3.289-app1/web/wasm/openjpeg_nowasm_fallback.js
@@ -0,0 +1,17 @@
+/* THIS FILE IS GENERATED - DO NOT EDIT */
+async function OpenJPEG(moduleArg={}){var moduleRtn;var Module=moduleArg;var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var _scriptName=import.meta.url;var scriptDirectory="";var readAsync;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){try{scriptDirectory=new URL(".",_scriptName).href}catch{}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=console.log.bind(console);var err=console.error.bind(console);var wasmBinary;var WebAssembly={Memory:function(opts){this.buffer=new ArrayBuffer(opts["initial"]*65536)},Module:function(binary){},Instance:function(module,info){this.exports=(
+// EMSCRIPTEN_START_ASM
+function instantiate(Aa){var a;var b=new Uint8Array(123);for(var c=25;c>=0;--c){b[48+c]=52+c;b[65+c]=c;b[97+c]=26+c}b[43]=62;b[47]=63;function i(j,k,l){var d,e,c=0,f=k,g=l.length,h=k+(g*3>>2)-(l[g-2]=="=")-(l[g-1]=="=");for(;c>4;if(f>2;if(f>>0;A=A>>>0;if(z+A>a.length)throw"trap: invalid memory.fill";a.fill(v,z,z+A)}function B(z,C,A){a.copyWithin(z,C,C+A)}function D(){throw new Error("abort")}function za(n){var E=new ArrayBuffer(16777216);var F=new Int8Array(E);var G=new Int16Array(E);var H=new Int32Array(E);var I=new Uint8Array(E);var J=new Uint16Array(E);var K=new Uint32Array(E);var L=new Float32Array(E);var M=new Float64Array(E);var N=Math.imul;var O=Math.fround;var P=Math.abs;var Q=Math.clz32;var R=Math.min;var S=Math.max;var T=Math.floor;var U=Math.ceil;var V=Math.trunc;var W=Math.sqrt;var X=n.a;var Y=X.a;var Z=X.b;var _=X.c;var $=X.d;var aa=X.e;var ba=X.f;var ca=X.g;var da=X.h;var ea=X.i;var fa=X.j;var ga=X.k;var ha=X.l;var ia=X.m;var ja=X.n;var ka=X.o;var la=X.p;var ma=X.q;var na=94240;var oa=0;var pa=0;var qa=0;
+// EMSCRIPTEN_START_FUNCS
+function Zc(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,z=0,A=0,C=0,D=0,E=0,M=0,P=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=O(0),ha=0,ia=0,ja=0,ka=0,la=0,ma=0,oa=0,pa=0,qa=0,sa=0,ta=0,ua=0,va=0,wa=0;Y=na-96|0;na=Y;C=H[a+8>>2];a:{b:{c:{if(!H[a>>2]){g=N(H[C+16>>2]-H[C+8>>2]|0,H[C+20>>2]-H[C+12>>2]|0)<<2;c=Ia(g);H[C+60>>2]=c;if(!c){Ba(H[a+32>>2],1,8023,0);d=a+28|0;break b}if(!g){break c}y(c,0,g);break c}c=H[C+60>>2];if(!c){break c}Ca(c);H[C+60>>2]=0}if(!H[H[a+28>>2]>>2]){break a}oa=H[a+16>>2];c=H[oa+28>>2]+N(H[oa+24>>2],152)|0;va=H[c-152>>2];wa=H[c-144>>2];pa=H[a+20>>2];qa=H[a+12>>2];ua=H[a+4>>2];d=a+28|0;d:{q=H[b+4>>2];f=0;e:{if((q|0)<=0){break e}k=H[b>>2];c=0;f:{while(1){g=k+N(c,12)|0;if(!H[g>>2]){break f}c=c+1|0;if((q|0)!=(c|0)){continue}break}f=0;break e}f=H[g+4>>2]}if(f){break d}f=Ea(1,156);if(!f){Ba(H[a+32>>2],1,6313,0);break b}H[f+140>>2]=0;c=0;k=H[b+4>>2];g:{if((k|0)==2147483647){break g}g=H[b>>2];if((k|0)>0){while(1){q=g+N(c,12)|0;if(!H[q>>2]){k=H[q+8>>2];if(k){ra[k|0](H[q+4>>2]);g=H[b>>2]}b=g+N(c,12)|0;H[b+8>>2]=15;H[b+4>>2]=f;c=1;break g}c=c+1|0;if((k|0)!=(c|0)){continue}break}}g=Ha(g,N(k,12)+12|0);c=0;if(!g){break g}H[b>>2]=g;c=H[b+4>>2];g=g+N(c,12)|0;H[g+8>>2]=15;H[g+4>>2]=f;H[g>>2]=0;H[b+4>>2]=c+1;c=1}if(c){break d}Ba(H[a+32>>2],1,8338,0);b=H[f+116>>2];if(b){Ca(b);H[f+116>>2]=0}b=H[f+120>>2];if(b){Ca(b);H[f+120>>2]=0}Ca(H[f+148>>2]);Ca(f);break b}H[f+144>>2]=H[a+24>>2];E=H[a+40>>2];_=H[a+36>>2];S=H[a+32>>2];j=H[pa+808>>2];b=H[qa+16>>2];h:{V=H[pa+16>>2];i:{if(V&64){k=na-304|0;na=k;j:{if(j){if(_){Ba(S,1,3219,0);break j}Ba(S,1,3219,0);break j}i=H[f+116>>2];c=H[C+20>>2]-H[C+12>>2]|0;b=H[C+16>>2]-H[C+8>>2]|0;g=N(c,b);k:{l:{if(g>>>0>K[f+132>>2]){Ca(i);j=g<<2;i=Ia(j);H[f+116>>2]=i;if(!i){i=0;break j}H[f+132>>2]=g;break l}if(!i){break k}j=g<<2}if(!j){break k}y(i,0,j)}i=H[f+120>>2];m:{if(K[f+136>>2]>2639){break m}Ca(i);i=Ia(10560);H[f+120>>2]=i;if(i){break m}i=0;break j}H[f+136>>2]=2640;y(i,0,10560);H[f+128>>2]=c;H[f+124>>2]=b;n=H[C+24>>2];if(!n){i=1;break j}q=H[C+28>>2];i=1;n:{o:{p:{q:{j=H[C+52>>2];r:{if(j){g=j&3;c=H[C+4>>2];i=0;s:{if(j>>>0>=4){b=j&-4;while(1){o=c+(i<<3)|0;h=H[o+28>>2]+(H[o+20>>2]+(H[o+12>>2]+(H[o+4>>2]+h|0)|0)|0)|0;i=i+4|0;z=z+4|0;if((b|0)!=(z|0)){continue}break}if(!g){break s}}while(1){h=H[(c+(i<<3)|0)+4>>2]+h|0;i=i+1|0;l=l+1|0;if((g|0)!=(l|0)){continue}break}}if(!H[f+144>>2]&(j|0)==1){break o}if(K[f+152>>2]>=h>>>0){break r}z=Ha(H[f+148>>2],h);if(z){break q}i=0;break j}if(!H[f+144>>2]){break j}}z=H[f+148>>2];if(z){break p}i=0;break j}H[f+152>>2]=h;H[f+148>>2]=z}if(!H[C+52>>2]){h=0;break n}j=H[C+4>>2];h=0;i=0;while(1){g=i<<3;c=g+j|0;b=H[c+4>>2];if(b){B(h+z|0,H[c>>2],b)}j=H[C+4>>2];h=H[(g+j|0)+4>>2]+h|0;i=i+1|0;if(i>>>0>2]){continue}break}break n}z=H[H[C+4>>2]>>2]}i=0;j=0;c=H[C+40>>2];g=0;t:{if(!c){break t}b=H[C>>2];j=H[b+8>>2];g=0;if((c|0)==1){break t}g=H[b+32>>2]}c=n-q|0;j=g+j|0;u:{if(!j){l=0;break u}i=1;b=H[C>>2];p=H[b>>2];l=0;if((j|0)==1){i=0;break u}l=H[b+24>>2]}P=c+1|0;ha=H[f+116>>2];s=H[f+120>>2];X=H[C+12>>2];x=H[C+20>>2];ca=H[C+8>>2];D=H[C+16>>2];v:{w:{x:{y:{z:{A:{B:{C:{if(!(!i|l)){if(!_){break C}Ba(S,2,10806,0);j=1;break B}if(j>>>0<4){break B}if(_){H[k+112>>2]=j;Ba(S,1,9590,k+112|0);break v}H[k+96>>2]=j;Ba(S,1,9590,k+96|0);i=0;break j}Ba(S,2,10806,0);i=H[C+24>>2];if(i>>>0>30){break A}e=1;if(i>>>0>=P>>>0){break y}break w}i=H[C+24>>2];if(i>>>0<=30){break z}if(!_){break A}H[k+32>>2]=H[C+24>>2];Ba(S,1,12302,k+32|0);break v}H[k>>2]=i;Ba(S,1,12302,k);i=0;break j}if(i>>>0>>0){break x}if(j>>>0<2){e=j;break y}if((i|0)!=(P|0)){e=j;break y}e=1;if(I[26384]){break y}if(!_){F[26384]=1;H[k+64>>2]=j;Ba(S,2,10299,k- -64|0);break y}if(!I[26384]){F[26384]=1;H[k+80>>2]=j;Ba(S,2,10299,k+80|0)}}if(!(!(p>>>0<2|h>>>0
>>0)&l+p>>>0<=h>>>0)){if(_){i=0;Ba(S,1,9532,0);break j}i=0;Ba(S,1,9532,0);break j}U=p+z|0;b=I[U-1|0];i=b<<4|I[U-2|0]&15;if(!(!(i>>>0<2|(b|0)==255)&(i|0)<=(p|0))){if(_){i=0;Ba(S,1,15305,0);break j}i=0;Ba(S,1,15305,0);break j}sa=H[C+28>>2];H[k+272>>2]=0;H[k+280>>2]=0;H[k+264>>2]=0;H[k+268>>2]=0;H[k+296>>2]=0;H[k+300>>2]=0;H[k+284>>2]=0;H[k+288>>2]=0;b=i-1|0;H[k+276>>2]=b;o=(p+z|0)-i|0;H[k+256>>2]=o;q=I[o|0];c=8;H[k+272>>2]=8;j=o+1|0;H[k+256>>2]=j;g=i-2|0;H[k+276>>2]=g;n=(b|0)==1?q|15:q;b=0;q=b;H[k+264>>2]=n;H[k+268>>2]=b;H[k+280>>2]=!b&(n|0)==255;u=o&3;D:{E:{if((u|0)==3){break E}v=0;if(!((n|0)!=255|(b|0)!=0|I[j|0]<=143)){break D}b=255;b=i>>>0>=3?I[j|0]:b;h=i-3|0;H[k+276>>2]=h;o=!q&(n|0)==255;c=o?15:16;H[k+272>>2]=c;R=j+(i>>>0>2)|0;H[k+256>>2]=R;b=(g|0)==1?b|15:b;g=0;H[k+280>>2]=!g&(b|0)==255;g=b;j=n;b=o?7:8;o=b&31;if((b&63)>>>0>=32){m=j<>>32-o|q<>2]=n;H[k+268>>2]=b;if((u|0)==2){break E}o=255;v=0;if(!((g|0)!=255|(r|0)!=0|I[R|0]<=143)){break D}o=i>>>0>=4?I[R|0]:o;j=i-4|0;H[k+276>>2]=j;R=R+(i>>>0>3)|0;H[k+256>>2]=R;b=(h|0)==1?o|15:o;o=0;m=o;H[k+280>>2]=!m&(b|0)==255;o=!r&(g|0)==255;c=(o?7:8)+c|0;H[k+272>>2]=c;g=b;h=n;b=o?7:8;r=b&31;if((b&63)>>>0>=32){o=h<>>32-r|q<>2]=n;H[k+268>>2]=b;if((u|0)==1){break E}v=0;if(!((g|0)!=255|(m|0)!=0|I[R|0]<=143)){break D}b=255;b=i>>>0>=5?I[R|0]:b;H[k+276>>2]=i-5;H[k+256>>2]=R+(i>>>0>4);o=0;b=(j|0)==1?b|15:b;H[k+280>>2]=1&(b|0)==255;g=!m&(g|0)==255;c=(g?7:8)+c|0;H[k+272>>2]=c;j=n;g=g?7:8;h=g&31;if((g&63)>>>0>=32){E=j<>>32-h|q<>2]=n;H[k+268>>2]=b}b=n;c=64-c|0;g=c&31;if((c&63)>>>0>=32){w=b<>>32-g|q<>2]=b;H[k+268>>2]=w;v=1}if(!v){if(_){i=0;Ba(S,1,11470,0);break j}i=0;Ba(S,1,11470,0);break j}A=D-ca|0;o=0;m=i;r=i-2|0;H[k+244>>2]=r;c=p+z|0;b=c-3|0;H[k+224>>2]=b;g=I[c-2|0];c=g>>>0>143;H[k+248>>2]=c;q=0;n=g>>>4|0;H[k+232>>2]=n;H[k+236>>2]=0;h=(n&7)==7?3:4;H[k+240>>2]=h;g=(b&3)+1|0;R=g>>>0>>0?g:r;F:{G:{if(r){while(1){i=c;u=b;b=b-1|0;H[k+224>>2]=b;g=I[u|0];c=g>>>0>143;H[k+248>>2]=c;j=h&31;if((h&63)>>>0>=32){E=g<>>32-j;j=g<>2]=n;q=q|E;H[k+236>>2]=q;h=(i&1?(g&127)==127?7:8:8)+h|0;H[k+240>>2]=h;o=o+1|0;if((R|0)!=(o|0)){continue}break}j=r-R|0;H[k+244>>2]=j;if(h>>>0>32){break F}if((j|0)>=4){o=H[u-4>>2];H[k+224>>2]=u-5;H[k+244>>2]=j-4;break G}if((j|0)<=0){o=0;break G}H:{if((R|0)==(m-3|0)){i=24;o=0;break H}E=j&1;r=j&2147483646;i=24;o=0;g=0;while(1){u=b-1|0;H[k+224>>2]=u;R=I[b|0];b=b-2|0;H[k+224>>2]=b;H[k+244>>2]=j-1;u=I[u|0];j=j-2|0;H[k+244>>2]=j;o=R<>2]=b-1;b=I[b|0];H[k+244>>2]=j-1;o=b<>2]=r-R}u=o&255;H[k+248>>2]=u>>>0>143;g=c?(o&2130706432)==2130706432?7:8:8;c=g+(o>>>0<=2415919103?8:(o&8323072)==8323072?7:8)|0;i=o>>>16&255;b=c+(i>>>0<=143?8:(o&32512)==32512?7:8)|0;j=o>>>8&255;H[k+240>>2]=b+((j>>>0<=143?8:(o&127)==127?7:8)+h|0);b=i<>>24|j<>>0>=32){o=b<>>32-c;b=b<>2]=b|n;H[k+236>>2]=o|q}Zb(k+192|0,z,p-m|0,255);b=0;I:{if(e>>>0<2){break I}Zb(k+160|0,U,l,0);b=0;if((e|0)==2){break I}n=0;q=0;o=0;H[k+152>>2]=1;H[k+144>>2]=0;H[k+136>>2]=0;H[k+140>>2]=0;c=l;i=c-1|0;H[k+148>>2]=i;b=(p+z|0)+c|0;g=b-1|0;H[k+128>>2]=g;R=g&3;J:{if((c|0)<=0){b=g;break J}b=b-2|0;H[k+128>>2]=b;n=I[g|0]}H[k+136>>2]=n;H[k+140>>2]=0;p=n>>>0>143;H[k+152>>2]=p;l=(n&127)==127?7:8;H[k+144>>2]=l;K:{if(!R){break K}u=c-2|0;H[k+148>>2]=u;L:{if((c|0)<2){g=b;break L}g=b-1|0;H[k+128>>2]=g;o=I[b|0]}p=o>>>0>143;H[k+152>>2]=p;b=l&31;if((l&63)>>>0>=32){m=o<>>32-b;b=o<>2]=q;H[k+140>>2]=m;l=(n>>>0<=143?8:(o&127)==127?7:8)+l|0;H[k+144>>2]=l;if((R|0)==1){b=g;n=q;q=m;c=i;i=u;break K}h=c-3|0;H[k+148>>2]=h;M:{if((c|0)<3){j=g;break M}j=g-1|0;H[k+128>>2]=j;aa=I[g|0]}p=aa>>>0>143;H[k+152>>2]=p;b=l&31;if((l&63)>>>0>=32){E=aa<>>32-b;b=aa<>2]=n;H[k+140>>2]=b;l=(o>>>0<=143?8:(aa&127)==127?7:8)+l|0;H[k+144>>2]=l;if((R|0)==2){b=j;c=u;i=h;break K}i=c-4|0;H[k+148>>2]=i;o=0;N:{if((c|0)<4){b=j;break N}b=j-1|0;H[k+128>>2]=b;o=I[j|0]}p=o>>>0>143;H[k+152>>2]=p;c=l&31;if((l&63)>>>0>=32){w=o<>>32-c;c=o<>2]=n;H[k+140>>2]=c;l=(aa>>>0<=143?8:(o&127)==127?7:8)+l|0;H[k+144>>2]=l;c=h}if(l>>>0<=32){O:{if((c|0)>=5){g=H[b-3>>2];H[k+148>>2]=c-5;H[k+128>>2]=b-4;break O}g=0;if((c|0)<2){break O}c=24;while(1){j=b-1|0;H[k+128>>2]=j;b=I[b|0];o=i-1|0;H[k+148>>2]=o;g=b<>>0>1;b=j;c=c-8|0;i=o;if(h){continue}break}}h=g&255;H[k+152>>2]=h>>>0>143;i=p?(g&2130706432)==2130706432?7:8:8;c=i+(g>>>0<=2415919103?8:(g&8323072)==8323072?7:8)|0;o=g>>>16&255;b=c+(o>>>0<=143?8:(g&32512)==32512?7:8)|0;j=g>>>8&255;H[k+144>>2]=b+((j>>>0<=143?8:(g&127)==127?7:8)+l|0);b=o<>>24|j<>>0>=32){m=b<>>32-c;b=b<>2]=b|n;H[k+140>>2]=m|q}b=1}aa=b;$=x-X|0;ta=P+1|0;F[s+2112|0]=0;u=s+2112|0;g=Ya(k+256|0);if((A|0)>0){P=sa-1|0;l=s;j=u;b=0;c=ha;z=0;while(1){R=z;h=J[(b<<8|(lb(k+224|0)&127)<<1)+16656>>1];P:{if(b){break P}b=g-2|0;h=(b|0)==-1?h:0;if((g|0)>1){g=b;break P}g=Ya(k+256|0)}q=H[k+236>>2];n=H[k+232>>2];i=H[k+240>>2];x=h>>>4|0;p=H[l>>2]|(x&3|h>>>2&48)<>2]=p;E=h&16;b=h>>>5&7|E>>>4;o=i;i=h&7;z=o-i|0;n=((1<>>i;q=q>>>i|0;o=n;i=0;if((A|0)>(R|2)){i=J[(b<<8|(n&127)<<1)+16656>>1];Q:{if(b){break Q}b=g-2|0;i=(b|0)==-1?i:0;if((g|0)>1){g=b;break Q}g=Ya(k+256|0)}b=i&7;z=z-b|0;n=((1<>>b;q=q>>>b|0;o=n;b=i>>>4&1|i>>>5&7}H[l>>2]=p|(i<<2&768|i&48)<>>2&2|h>>>3&1;R:{if((p|0)!=3){break R}m=g-2|0;p=(m|0)==-1?4:3;if((g|0)>1){g=m;break R}g=Ya(k+256|0)}S:{if(!p){H[k+120>>2]=1;H[k+124>>2]=1;o=0;break S}if(p>>>0<=2){m=I[(o&7)+20804|0];w=m>>>2&7;r=m&3;m=(((-1<>>r)+(m>>>5|0)|0)+1|0;o=(p|0)==1;H[k+124>>2]=o?1:m;H[k+120>>2]=o?m:1;o=r+w|0;break S}v=o;o=I[(o&7)+20804|0];U=o&3;m=v>>>U|0;if((p|0)==3){X=(o>>>5|0)+1|0;if((U|0)==3){H[k+124>>2]=m&1|2;o=o>>>2&7;H[k+120>>2]=X+((-1<>>1);o=o+4|0;break S}r=I[(m&7)+20804|0];p=r&3;m=m>>>p|0;w=o>>>2&7;H[k+120>>2]=X+(m&(-1<>>2&7;H[k+124>>2]=(((-1<>>w)+(r>>>5|0)|0)+1;o=o+(p+(w+U|0)|0)|0;break S}r=I[(m&7)+20804|0];p=r&3;m=m>>>p|0;w=o>>>2&7;H[k+120>>2]=((m&(-1<>>5|0)|0)+3;o=r>>>2&7;H[k+124>>2]=(((-1<>>w)+(r>>>5|0)|0)+3;o=o+(w+(p+U|0)|0)|0}T:{X=H[k+120>>2];if(X>>>0<=ta>>>0){w=H[k+124>>2];if(w>>>0<=ta>>>0){break T}}if(_){i=0;Ba(S,1,15756,0);break j}i=0;Ba(S,1,15756,0);break j}H[k+240>>2]=z-o;m=o&31;if((o&63)>>>0>=32){o=0;q=q>>>m|0}else{o=q>>>m|0;q=((1<>>m}H[k+232>>2]=q;H[k+236>>2]=o;o=i&240|x&15;z=R+4|0;q=(z|0)<=(A|0)?255:255>>>(z-A<<1)|0;x=($|0)>1?q:q&85;if(o&(x^-1)){if(_){i=0;Ba(S,1,12194,0);break j}i=0;Ba(S,1,12194,0);break j}U:{V:{if(E){n=Ma(k+192|0);p=X+(h<<19>>31)|0;H[k+208>>2]=H[k+208>>2]-p;m=H[k+204>>2];q=H[k+200>>2];r=p&31;if((p&63)>>>0>=32){o=0;q=m>>>r|0}else{o=m>>>r|0;q=((1<>>r}H[k+200>>2]=q;H[k+204>>2]=o;T=(n&(-1<>>8&1)<
>2]=T}W:{if(h&32){n=Ma(k+192|0);p=X+(h<<18>>31)|0;H[k+208>>2]=H[k+208>>2]-p;m=H[k+204>>2];q=H[k+200>>2];r=p&31;if((p&63)>>>0>=32){o=0;q=m>>>r|0}else{o=m>>>r|0;q=((1<>>r}H[k+200>>2]=q;H[k+204>>2]=o;q=n&(-1<>>9&1)<
>2]=q+2<
>>0>q>>>0?n:q)|128;break W}if(!(x&2)){break W}H[(A<<2)+c>>2]=0}p=c+4|0;X:{Y:{if(h&64){n=Ma(k+192|0);r=X+(h<<17>>31)|0;H[k+208>>2]=H[k+208>>2]-r;m=H[k+204>>2];q=H[k+200>>2];E=r&31;if((r&63)>>>0>=32){o=0;q=m>>>E|0}else{o=m>>>E|0;q=((1<>>E}H[k+200>>2]=q;H[k+204>>2]=o;q=(n&(-1<>>10&1)<>2]=q}F[j+1|0]=0;Z:{if(h&128){n=Ma(k+192|0);r=X-(h>>>15|0)|0;H[k+208>>2]=H[k+208>>2]-r;m=H[k+204>>2];q=H[k+200>>2];E=r&31;if((r&63)>>>0>=32){o=0;q=m>>>E|0}else{o=m>>>E|0;q=((1<>>E}H[k+200>>2]=q;H[k+204>>2]=o;q=n&(-1<>>11&1)<>2]=q+2<>2]=0}m=c+8|0;_:{$:{if(i&16){n=Ma(k+192|0);p=w+(i<<19>>31)|0;H[k+208>>2]=H[k+208>>2]-p;h=H[k+204>>2];q=H[k+200>>2];r=p&31;if((p&63)>>>0>=32){o=0;q=h>>>r|0}else{o=h>>>r|0;q=((1<>>r}H[k+200>>2]=q;H[k+204>>2]=o;p=(n&(-1<>>8&1)<
>2]=p}aa:{if(i&32){n=Ma(k+192|0);p=w+(i<<18>>31)|0;H[k+208>>2]=H[k+208>>2]-p;h=H[k+204>>2];q=H[k+200>>2];r=p&31;if((p&63)>>>0>=32){o=0;q=h>>>r|0}else{o=h>>>r|0;q=((1<>>r}H[k+200>>2]=q;H[k+204>>2]=o;q=n&(-1<>>9&1)<
>2]=q+2<
>>0>q>>>0?n:q)|128;break aa}if(!(x&32)){break aa}H[m+(A<<2)>>2]=0}m=c+12|0;ba:{ca:{if(i&64){n=Ma(k+192|0);p=w+(i<<17>>31)|0;H[k+208>>2]=H[k+208>>2]-p;h=H[k+204>>2];q=H[k+200>>2];r=p&31;if((p&63)>>>0>=32){o=0;q=h>>>r|0}else{o=h>>>r|0;q=((1<>>r}H[k+200>>2]=q;H[k+204>>2]=o;p=(n&(-1<>>10&1)<
>2]=p}j=j+2|0;F[j|0]=0;da:{if(i&128){n=Ma(k+192|0);p=w-(i>>>15|0)|0;H[k+208>>2]=H[k+208>>2]-p;h=H[k+204>>2];q=H[k+200>>2];r=p&31;if((p&63)>>>0>=32){o=0;q=h>>>r|0}else{o=h>>>r|0;q=((1<>>r}H[k+200>>2]=q;H[k+204>>2]=o;i=n&(-1<>>11&1)<
>2]=i+2<
>>0<128){break da}H[m+(A<<2)>>2]=0}Z=Z^16;l=(R&4)+l|0;c=c+16|0;if((z|0)<(A|0)){continue}break}}ia=V&8;ja=s+1584|0;ka=s+1056|0;fa=s+528|0;if(($|0)>=3){la=N(A,12);ma=A<<3;da=sa-1|0;b=sa-2|0;t=3<>>1&2147483644)+4|0;r=2;while(1){R=r;T=I[u|0];F[u|0]=0;Z=Z&-17^2;ea:{if((A|0)<=0){r=r+2|0;break ea}b=R&4?fa:s;r=R+2|0;j=ha+(N(A,R)<<2)|0;p=0;c=u;E=0;while(1){V=p;P=T&255;i=I[c+1|0]>>>5&4|(P>>>7|E);h=J[(i<<8|(lb(k+224|0)&127)<<1)+18704>>1];fa:{if(i){break fa}i=g-2|0;h=(i|0)==-1?h:0;if((g|0)>1){g=i;break fa}g=Ya(k+256|0)}q=H[k+236>>2];n=H[k+232>>2];i=H[k+240>>2];l=H[b>>2]|(h>>>4&3|h>>>2&48)<