From b0444a52c614dc8ba1f27024fcef853329be3c41 Mon Sep 17 00:00:00 2001 From: lockbitchat Date: Sun, 27 Sep 2026 16:23:03 -0400 Subject: [PATCH] v6.8.12: new design for exchanging invitations --- CHANGELOG.md | 6 + README.md | 4 +- ar/index.html | 38 ++-- assets/app.css | 2 +- assets/screenshots/web-verification.png | Bin 129700 -> 100629 bytes de/index.html | 38 ++-- dist/app-boot.js | 6 +- dist/app-boot.js.map | 4 +- dist/app.js | 18 +- dist/app.js.map | 6 +- doc/CRYPTOGRAPHY.md | 4 +- docs/cryptography/index.html | 4 +- es/index.html | 38 ++-- fa/index.html | 38 ++-- fr/index.html | 38 ++-- he/index.html | 38 ++-- hi/index.html | 38 ++-- index.html | 36 ++-- ko/index.html | 38 ++-- locales/ar.json | 28 +-- locales/de.json | 28 +-- locales/en.json | 28 +-- locales/es.json | 28 +-- locales/fa.json | 28 +-- locales/fr.json | 28 +-- locales/he.json | 28 +-- locales/hi.json | 28 +-- locales/ko.json | 26 ++- locales/ru.json | 28 +-- locales/uk.json | 28 +-- locales/ur.json | 26 ++- locales/zh.json | 26 ++- meta.json | 14 +- package.json | 2 +- ru/index.html | 38 ++-- sitemap.xml | 46 ++-- src/app.jsx | 276 ++++++++++++++++-------- src/components/ui/DownloadApps.jsx | 2 +- src/i18n/dict/ar.js | 28 +-- src/i18n/dict/de.js | 28 +-- src/i18n/dict/en.js | 28 +-- src/i18n/dict/es.js | 28 +-- src/i18n/dict/fa.js | 28 +-- src/i18n/dict/fr.js | 28 +-- src/i18n/dict/he.js | 28 +-- src/i18n/dict/hi.js | 28 +-- src/i18n/dict/ko.js | 26 ++- src/i18n/dict/ru.js | 28 +-- src/i18n/dict/uk.js | 28 +-- src/i18n/dict/ur.js | 26 ++- src/i18n/dict/zh.js | 26 ++- src/styles/components.css | 1 + sw.js | 2 +- tests/rtl-layout.test.mjs | 7 + uk/index.html | 38 ++-- ur/index.html | 38 ++-- zh/index.html | 38 ++-- 57 files changed, 919 insertions(+), 693 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 550d9d8..91a87cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v6.8.12 — New design for exchanging invitations + +New design for the screens where you exchange invitations and answers with your +peer, and for the safety code check. The download buttons now give you desktop +version 1.0.5. + ## v6.8.8 — Project support section Added a section to support the project. diff --git a/README.md b/README.md index 3167f0e..4008e84 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ No accounts. No servers storing your messages. No installation required. [![License: MIT](https://img.shields.io/badge/License-MIT-f0892a.svg)](LICENSE) -[![Version](https://img.shields.io/badge/version-6.8.8-3ecf8e.svg)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-6.8.12-3ecf8e.svg)](CHANGELOG.md) [![Get it from the Snap Store](https://snapcraft.io/securebit-chat/badge.svg)](https://snapcraft.io/securebit-chat) [![PWA](https://img.shields.io/badge/PWA-installable-3ecf8e.svg)](#install-as-an-app) [![Encryption](https://img.shields.io/badge/crypto-ECDH%20P--384%20%C2%B7%20AES--256--GCM-blue.svg)](#security-model) @@ -31,7 +31,7 @@ From the web app at [securebit.chat](https://securebit.chat) — no install, no | Open a channel | Verify the safety code | | :---: | :---: | -| ![The landing page, with the option to create a channel or join one with an invitation](assets/screenshots/web-start.png) | ![The security verification screen, showing a seven-digit safety code to compare with the other person](assets/screenshots/web-verification.png) | +| ![The landing page, with the option to create a channel or join one with an invitation](assets/screenshots/web-start.png) | ![The Verify your peer screen: a seven-digit safety code to read aloud, boxes to type it in, and You and Peer confirmation marks](assets/screenshots/web-verification.png) | | Your device generates the keys and a one-time invitation. Nothing touches a server. | Compare the code out of band. Until both sides confirm, the chat stays locked. | | Encrypted conversation | Voice and video | diff --git a/ar/index.html b/ar/index.html index 98ff329..e0af179 100644 --- a/ar/index.html +++ b/ar/index.html @@ -30,18 +30,18 @@ - + - + - + @@ -116,7 +116,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -264,7 +264,7 @@ - + - - + + - + - + - + - - + + bOcL6Ws;YtLq=$mwk-dd>IkT$o>7n=ePZu#~NwBn|^41Z2#@{ z;j6qyl0!=XNK9=djpf8nj#Op+MZ?xZl=0@**FkN0+gBBi6d;97A0yw~YpD>N=^eiN ztt{=w3 zC3>!GJwNxM@?oJuWPeh7zt)@A84J$$4Bk~DE8R|HxETsf11Noh*mvH$1! z@oE z3RbDX8kdx5+(SSHp{xVc51Q$XDdlEpCPUaZsatrczK8t?Ijg69iZT4kH&D@O+AKO} zN;zfP0;%NhWAm*P z8huNxamEY=aZA>92KDCX8Eaqmw6jZXsk83YmlZ)$Eo`$KZX%NmO<^6n6gR_jvORTd zZ}E0hv&6hry_x;JK%zj!fE{+(Fy2wkD`z9?P&c=r-(K)@SYB@LfVRE4=Z(+NX0Ob` zg&%;k;3YV@D3P|Yx&HZpO_5C|8ow~gmiLUBGZ%~)AJd&aQygIuakZ63H?)&S zmg)NI!teO+?k^O!#J28irN_j?l*EK<7Q`sqrfb&xeEA73MlF{4=W=Y=X!^E-({^@&LI<*riRfhxoUn*=_d5U*Ury9DzUJ@tVjk*|}ZJD}6!_gE*mJM(=LpHhjk?l%KEqfVV$Mg@k|d7?$H_3s+& z>ixdGD8Qvt|3&)YJ>A_~T+G5Y)C)WdVm7beeibWlcH~FA_K!iSaq8&soL(;vz@mmn4@$aKIeth}$JL$HwqaDBK zlod*WLA>8G!_5p|A7Fb!Jn1R&Y5GKnOs{;ie1HAKF+PxZ@N%cB50`c_)jE1@YA)-? zbqzHQr5^bnqn;`wUZdym$MCvQYbVz=#Hi4ytFtC#Uorr)f!1@ThDf21=-`TqDkk&@ zI(B>w%{PuiHg$XvQ%(8t6Mp{EX`d*>c{@%;Ih2g8jHE1S#d`7MqQTnT`jE1arkROFaXZ0F!ECh}VLgh;!C+2soD*VATuMPI1AVoMP0-4Sf9=*9qAs#-oLG6J&Y&JY z!Uf5=^@O`$rC(S?t@L3js5Bo_i|N96VXPF9iUL8Xz&nkkMw1|1nZ(3%?{fh^`!TKv z^C+b*rOBq&lcyn%LZq`K7|-vXon+mY?&NuRY4{3#*hC9DEHgq>B`Naw;@flQ&J@!J zaoMsX`HRHUE;in%mpoRD2)O^~d+x*BhmWiSK0Y@HG|(FEu_EPs{)Lc88ztCiv+bxV_BTu921*^erwJ}z>khXcC%bUrIeIF9eq(m%7pdw1s zEVL!;4e>Uz)hyY(K>a)p6f zQVphuVZ-qbEe=sbyhFJ|9Aca7XV~o`-nQPg?9eOz+LP=Zt*J(vL$ZnM@fPG@I*Mkn zQTY@tW>Q|zY2m5=;>N)}v3J-Hrk{wn`S_Q9yGJgxE=Yk>ipDGF)Jl9d`UM6BY6Q^W zm7-@&jusM5c#_1x=kF3&C;aGQDd)4Lij7YHxx-3))8fj1Acm=HgIO(hP&5 z(lARW>+7={5Kojb{`#SMOT1}nkrWoS+wczT+t8U)P_*oHr)vN3Ns?0H$=wW^=czqeIrCdwSIX;lYCaaO){xO zsIJlIi@~l@Em(4WbiBb~uS20;K_Os@FbZ}sVlfPw;2ZaWHuaP89NSjQsmG}&PG@k( z$c`U~?<{>*b&Ps@K1fbbeiC|P{h@knkd{{Q1IQ!J=X`}6GMAydgggCKLU>#J5r_Rb zwT_mTU0ca~7qxdK4yBNp))_@gHg1l44&5uQyaf(wL&hGDJ)j!S8hh+b;@D#C;(X|x zlZDNv=@p4fANvy1_%iyHl>Dylwfd$OKz3hj|7aoH#KsH%cwURXfEx6gIN2T%z<`Cl z%4J2Kdo}tKKF=e>$3Bgvx{goT*E$63?3N;%GB(QB9BXZ$@C9TWc65VwYAN7(fG}pO z-eW=dXd@Prh1qEAY&_bV!{MiwrnrOOk!E_^)}xr>M-|%Tg#)jhd|5ASA6lJ`fjTW$ zttm;($hhr1-LFs&pKJj)*^x+Iw@zdZ{3gy~*(BPG+U(Tp)m@sN@4GK2E{}Y-Z{Y?( z*MlLuhr^jJP|THRb`JmR!QuzV{q)tkHXH;~6(1F&M0~epIcGJ?H}XVXQC!I<_zh|M z#kD1Y4W|RCdDr4;Vv|zF&y+Ogm*3M?bSWZlrG2DnMz>MCv!cwJe6Sc5DZaB?sVqKC zF+@XR>i;=86s9SRccF;5*6m20bwO7(!sbHyuk z8aSc^{!vg~rl9@nn1bRlCCC3c)}y@j?=n;r6j2ToH2*I14EX%>_YQagwg3G|{oxhG zY2e#M;1!WY^*^O)eY2?l=a^aoxJGeLU-i)=;8Wkq-Nwen!`{_%pFV>GoH*n5@Tms{ z1?$Z}FUm)HH#R9Ks3sf?j6IFDG-a(^A;Ol{t}kqaeIagt?n5E(D+?S#Y&N%AHG5A_H(3!8A0HoKA8}z_{@mB{g{zmR!nJFE8u~wf|LUiwgYEye-2xuGXCG||IyBWp8f9{Puv}BfT{df&;H%Wf1dk~@_)uBtK;Bn<7|B2 z0RkA!pV5fl6$6Gt_R@b>HT1A?S9OH|H9Zyo*X;gX`9ClIcg4TjeEPp_iiwKK{AZj0 zap~VxM){l1+ZQZqgYTJPa&as_%4~ilt>5?FMFm?8A(=n9Tg#MjnhTeHF|N5{ zV*17UX{-VBo1E_$iX29YH*u!UxFO8ZUYf%Aj~6|H-*~D5`@MSme%|i)>$9^xIlwmT zJsKVzO^%_Zq{)j_E;J}#U3C;-2F>1q@V4J)RHmS$`LDOUbY*u`@9Q&HLnx@|c*wkc zys6x5!pbD~PX&gagoOAU2J!x+``f+$)zmGGkdP`tUT>AZH~v?Fyi5v8-0qQP$_4Tr z;L%B=Xa1pwDZx}U^+Pyu%Lim< zfG0%xDb-3jLAF7EZWrFwa7)X@hw#AS*_j)Hv*tv-!eiXaR)*K!A}1*hUR|1}$TVW{ zfbQdk%?GndRPg&MmLt|Gm|qs1iS)DM)>P%}*&R3R8kG4H%dPdM54u?D)Ti+|EYUZi z%ytb-Y_G|Tc@ssa$+*cYnD~}zO0Up9Qst$dVNC58YcapWd*gUiU}u`wHWkQQ{8J3{ zWQddwR)#AXeKe1SE4^Nhzv|z&;68ij(>$M&RU8>}U`&aony0BhqmiFr7G(Ubv9WOn zRKVVRIRJ4dm(JD zu@Unq^1HZd^wVo(OsYPK%IZ}8is!Y6I#W|qJ7RPV%sqFteK^7cJeV6+Od^p)wIPt= zsOO-#gDU))t?^kyHXTtDLqm2_RyM8(pi;?rGuKBehn58V4T1+=RKRdf&@bfA3cR@+XnU*`y z$rO-oJGlvc*IYnZdbk0T2=|XVZ*Ej%YwxQ+&rpeCfq~EVmJgmJJjjsLpr7|qqVpW*Y(jJe$3!@or>d3tFJ;s+Qa;&y% zG$utj!ILrwhi|B7WI0HMIk=;Rl`x~ zra=@6jrD-;DHZ4Dwh2#vYYsl>O)Zj5h=Vy9X0LXYxYXpi?R_Fb2%8mr&i(JT*ZQO6 zzG=ONTS%vCN9yc?p?EN4Fefrt^H(?!TX#T@)sJ$OYNuu8lQqRNtf-Qx%^b(PVzz zB$X-&DJKxl%LN}7+)OxhDJL@nbUd4@bRStZ^N8&_)I`6vJ)VjK1O1c zMQXo(Wrb$LR~%e7HEup8WH=?GNhaV4S0eE&p_i{g>mK{p`kLoW4I5rnXmzE-D6Z-} z6@=T9C&^R6N1O!G-bs$a&d(u2O+Qh@Q)EA82xQ%_#_d zxwItR4g!H-1oqvQS?b*vK-18B1?7fLZ~S%^{USFXJ!uU*Lv5Zeau6x4!Mu^=j7D;Lqai-y zQcVY0P^q^x^=wqBcP^0eLha1A1ZET#f_zd_wT**Rb0L`e3Dq7Vp{ePl+|ak|h1xTz zuiMrmOr<&(*7Bc?>R3uSr`b6z8IJQ!2fgQ%#@O_8Z(R1cxOFNvcgx8UhD`*YM{}QS z5eakAb*gH(IL_n#Cp%C=$UZe;N9n|a063i|N1f`yLzwNPs_{(HO8$Cbeg-lgdOY7q zs>s&cAINU=#v;bXI}{1#&eM%Sgn*{K0HosxOlP9bb(-slIDMiTK$yr^#m!clAK57# zu^)AV8`nJ!UlaRq$4L^BlKvD8%>v%gp(J6`_3Ul=qaWtSYHL`|Z*Sj%j^Is)0!Oja z``?JT6C#6U+!kU-zJkVJp}}kI=G94J3qzx8oez$%x>FvUZaW$&W1?BRx87%}t!c4Cou}sp#9$OgRcIbb(vKQ30jT9QT@n5{hB{ zsHU3W8sZ`wAtI=KNJni=L!^P3G-ZlqC$0CBCbr+mTG<*cq$b_MPdA^SsApBP4++V^E7N{zkc6N$lj(AS()w=9PKM9KPQMZ^ z`=z0MYF4)??cm7B2-0^eN9T=+?tA=Lv_h821^$4{Ac72oIb5|a@*IaGYOIkU;ad0( z3D}sO{64YZ^bg!QN>_}@llrY#pMcV-=yki`MZ5aT)lxqTo0_KK!N~_!Ur*NsUA=FF z_@-iJh~tv;Ztc*BRc}E$2xd8MK+wnu4vbr}!ttgm;X70Og$?cb{^&w7;bp~B!1;kg zN0Xb5BL_6Rv%&enGt}I>-Kcc$NfVCa{XunSo8FMq88_E@Ss<2>(G2Nv7xTdN>ZxjE zU+_WRf;aZ9Bm5_Cv5&ICm3A|+Pcg*JD5XlJlbxn-J`HPANPqlebfrUh11<=6wguO8 zvUh?pJ2^Bto}OXKHf=pCvR=8+1NObS@Pi9Eb-|@IZ;;z}hH|LU)vqTNTT-{N-CR9I zJ)$XHR-zWIVn$32%GQx47QH^K3SO%sK5JTLX~mVta!5rQf$F@mpr!hQ#nknjXkb-cX(q_kBpThnN0pG z(*NtL@HgeBl%h8)&Qdv@jp^*{FPH~6*2(#C?Msx*Fd`&j9#rbxiRSFIp_lRg6 zzto-7>cVRTA`S|@WWTr3aCLH|x4-g={JuM#OB1l;P5?{VzF@s!tDU0_=_$(;Huj#S z5@dx&p|F69)}?zPz|XHxJ=8mLk$|jfm+O5kvYdr1G&KAx44 z9`RT1MHMQ1FSqGAp7djAHYdED#pv!C7SwsJl#70U!_*PT?Lsg4%OhuR`Uq1+WT4wS zZXZjF-Efr!Kw&5c~PR(Q42$` z1-i<0#}Q+gEo&&H*ki4iJ<@_BZQxL~UTf}oLpKiZySo{oEQNwJ6TF$IbZ`uwK-IU&rFPqb+eexxmr$*=;pDgg@C&!)W(Jqh6+yYNgUP1dU$?&S&^ ztG4Tpwp8kmP>lvnEo<%QG0ebVmz!!(IRzqRnfEANTU}-IXOJ*hH#|)0XuN}1J^6YQ z@%v;kb1S5-TXoXAl&a5I(j@yrU?W>(YP*-Ww=dn4m~@Bb&|b3GM7a&T3M##R4@ZUm zW?7-IH#u~@?*eB+udOrjFqZ2+?%Wtt54MBZjcWe_1_Ia99kPlJX`2DG`!4PB5#OrX~onAHJT!d zx}Vi~5F+iK6-}G4YS!PVzqWtBV6@?Qy9ax?R(kg8cAl1r3Y^9e&n4qN95CBB;nIMY zEX^oBlUVOGR)RbsOp_+5t4hbyeK59F)4{1hThZp*n?4Xa)e{o#v)u&IsX*{uOphDajI zui(va?#fK!1k?s-Y%4_4=7|#V;|ZE{HeBJUgjwqn#sT!&(DKL*N|=@xCAryO&vsn! z9Xz)uNR6&m%jwY8B+5ERMN*rUo$;Z{0M>V?UbXX?wZT)BzM>W~u>F`LS`A;>EjPh)fx5yeevoQ}ZG zTgJf{H6<;Qtf=O#==1@9J{EC3!J&#d=KhnN{V z)YNl}T~aK3J7!fd@IhIkmOl)yISArf-f-AJ>;(_Pg94($Uc`dU%}W)YRNWb<_0`Qv z>|au;uJhfRW9&p$rj;))@-lS%x_W8IJ2pEC=5AtQqVl@1Sqr_`>qH-#Pi2I7GVt;; z7|k+H*xQT3!?Fz3;4UewU^D*VI8}+*ugbtKki^Ac5K(iOqC-?R|WLFD~nHx+`!ZVlfOv0 zLa00n!>j8p;irSxXe$c831iIBb#(zMXc}y(vV>WsR(472)GRv3BT4=S1hj@XTN=n2 zdpVM4))C!q=$oHW^Ng9%DNtyOG}}AFU})Fg(SgRBF~ok|G>-Spob6aev@7{-r$p6r zXc_i^V%F9;TD7pu`$A^*-}m$oo7timAf%wl?dxMx9l-&qj0(r=&!0c*5aDh*9(v>O zgIjc9o9&?|O0)AHRSe5vJ|i&8A{hrW4~M}$z07dMJ$E*&IZ3RYt?8I@oQdqz3{mA8 zZNe5p+_e$ZDeF0+`w)|*2@%tpW^XBm@zTI~miUWNth8}n!QqmI2>wg9?6=?1v9#6R zPD3f(8aMrBp)vIOrlw3fy6^7R9L!WEpP6rxmRp)i233??W)11cBHfwnHm+QGZ-Po)Naa8dBptk%Z&BVRyW z2>R(KxF{S4E*HPGbzMLUVYYNh#Cdqj!{&Xa|K@78BuKwzd8Ysd1I@3>&kLcnqhD=B zjK3m-{4t&d@Qb|TJV(dV15;Bhu=DfOygSc7Jwk<4dFlw9j(iR3^V|`K`S9g-HkKll zy}S~m=DxOMbRQ~QQhLV;4L-xL#zbn^!;I9tf%{0XQsVY=oXO#3mo8ospBWJ@G#EB9 zIB6{%rO2JSf$XCQKn{ZI9ewxiL7&+9ll1LELE2W zocMh@LSEo2FX}X-&}g}R^*4`CHk|wypg2TTBkrr70TG^2x7yGXM&|Az%?4*=~WVw^&0P{=78_CNa z&xNlXk;z8rG#_WJS9%u|w;t?XPamEfXAd1S;DNOY`7P9tl<(A}Qmu~rvXf-ZI>gDw zDEe1*yqo1%_^jw@Y+)2vv6{r+DN=tgDOyLHQ&-Tt;q-g;@2=#pH5B^vwsNzafRd3g zh}@c@q*)9D0QKklA8Q_v@kT(EltcjTuGqF($RXc?g)klCW?$r!PfqvAV5!O!|9|Mf zJM9}6E4Ev!Zvm63T=?bFPJoQQlG0-A-)*7(Gu4U#Ki)AT-s5UWGYwUtLDvT}6Z2b| z->#>U-4E-PQOPp#6ckiLkFuB_`!caAJjwrbhmFi!hOY3w+rVPeT|8bW(*1Oxq^*;X zka%$PQHCfnGxzsPArf1=qNzdlKGW39~HB!<5gFgTN(V#FCc*>ZfMHN_TH(7!2n8cOpZWg3P%ZpU0(!oCn=N2RjQ<^bz)*-xTQ<$XffK_q-x_E3Uyh4HJZyg@i^rz;|BjG ztf&Zd^<`Pgo`ugR$b|d*OoTm$r1S2kkFK=s_+8&O%`q2sE}58`LdHye!cAZPNJIu6 zfKIg8Y=*IHn)GOkr zpxTLX*O&SOXv_pCiCi}lZlf#gs?O2VM<|8W8+pvule5S_u>i;n&oBagwdAh57O4fcfA^c0 zmlp~EO*UBSO;l`flRQiOcJPqKF;i1cqz^7S9LsWX)(>eWG8Rc@MQx(a#$4W9o$l87 z`og{mK=BYSbQnx&YXBA=3i;q0Z_GqjPO&`dY z{9>j(UB2=4GDz>q6+`usWvy#>?NaqRLk-E7HW zj5h%JfYcfk{kDyl6;NYiYyCl^V`FT{+suIPM)dW?iDs$%E-4`l{JPiR8_%t@2)yg8 zNTW`-)Uw~qdh0Xw?pxu?mnsQ|GZ5`(CQr_hLcbh8HZvsgi;jl>({j3qK;UzEAA*wJ z{&*p+9a?l4?Wl_{HghsPezt~io%8{(MR7C5v$&3to>iLH$4s)8F0qGxx{-zR&t}Az z#4V<$c+!@(1JvUAChj(}yfqn;gt1!Z4@tS=iQ?zy7fkIvf2yAO(5!$V2O$+n=TmVxe?C}w7+ zvvnJi3li(|sO)I!VZ+5R*dOUdsr+4rukJ}b3q-FiiS!$M>K1utZd`l>c>VCECx)X# zL)du5CVGBZ{&W zgUv;E8I62#Qk@|iY__hpHh(GN6U*Nt%aG<6W;)8!u*urmRUOFq)KpNd>#f<1m}AXP zyLT_VhC&U_Oi!7912Vi#b*9MrEu@2(VIH~A9oWuQJf@r_u@H7gqIqY4c2u4Cu78Ro z)sUVtMB6_gpbhsac-olk6sLefzrcK)932~`H$qM{WE#BlsS@unUee;p6frJK*?9*} ztlypE?0xM;&iN)VJ;i=<2p*1NB4XssUZ?b`c z#obVAeimX~wF~G6kTS3tDL2`H{8={jegs$+vy)i`DQBs;fMjdBU1N6fiN|ah5KfzE zgjS2Iim{{2o09ZrC&_iOLYe1_=IxUewaCUaCvzQ6pOTJOObnzH*vnV(T~6dJUD?7L z^yREsL!Irt$gdn4$Q|R%h1S^7oNAvr4dH{PRHtcc-}54;bLZZ~bJnOEs1-p?;z?en zmaa8BmtW;`0438@&4sBvU&!;Tt&93)H06dgy_wca_rpwBmhKx1+2}sX`x?=S};#5Q&Dy>0=vvrL>i6-x=~_H8CS?o&W75+)59N*vvd2KiYpagyFnGzXMRi+7 z@L?h2m9b$1w8YqRD^5;qwH~0^#tWo!b<0&8XDOCX=*lr%AakH+>+?V08p218e}oH@H0`aQk+^5qkOp zl`$>6>x*#HZ%cR5ZtZMhm8{92s|r|fv2C83dq0HODpKDMPdZu;!T}5=z-fY*`~h;= zAjThgGv%gRgm7O zQ0Mad&K0z)8?ci)?F=_628EXPC2Hpb_;T{PfcXJT=vn2sOXGoUX)E>{4EDHgtwajt z)3}2jntyV)s`@ebsB3Gy%!=?nKJdoR9aZkbEbzXW9rU>4V& z$PU`>^S&(aU^xcZ(*|3Y!4qZ=mC~&&ESjk?jtuhR!5B)Vsd1Znl=%n(Mlfv*tob8{ z0EjiaoyC#NJJSq7%VX;R|6mG);TKU_$CLfUw1yL6lXDfuA3o*Qb}o;?ICQ;GKY#sb z`lK<4v|~;$#5MeCb|>>B4B&mI0D3hQvNdJYTyy5as)e+Jj60{8u`9JG7kItkA&7R>7^e38oBd9#I%ApQwz=rk+PS zJml5KG!b4a;D`0SdxWIW#Jy=8ggxV1k8s^&e1C)^8ese7JeO^b&`rdmD(!tU`%jyI z0HG9%aw$!~!GfbxchH}M9)vLQMGoa^ti|J_gv z?(w9uK+LEi6ne4;o%SIrlvYkHLM}=AnM7(cM6qb{so-Dg>sL&94rzJgN5KA2%z~wH zv^mxRw5qDtrcl-7MNH33tZQIy(29mRVO}AWa5JGR z0%X?<#&Y(V4PU$F$dnB!Mb1y`Sf2X_4{sehsMmR?bO}L!qer0%X6~~wxgf-b;XYh} zQB`MWw~)5Dm2k6;S0^K|R@_I%bT3bSKOub=@F^{e8R6Qji@ZGp_Au;kLd>9MgTsTlZ{VuO?X_mTQs{^#*8+UQ%q?yqU` z0!f`K9pp0U2znwOFcW%OweIy1?j&L=Xpcj6|0tJR;RT;|8oiVQyrg6s%L0gTssd;? zF9giJ=}?t$&3;#bUmHW`E8_E8R3O|Wf~yi%!H1i$_f<4%IZdCUneiW%DIZOq;EbU? ztl4wr*VoZszg_?dEv4IFj+)uXvn8qPaxaL)+DFeSrvV1L_1tjW6`8q_${&o)+Fz?t z5;qc781wjlPc;No_0N98PB%@H7F|j0n8VR36af8lV8GxpK$p~;U5?bbHPIM!bj)i% z#dV&IcnT8xhlApR9zSZjjq+)TZF^*HzL~X02@tmFrk;apgptzVABu;A@sSw~KmxB? z-Ogs_iyv@wZvn#^-_dKkuRF}^N?r**qRZ15>-7`4Ux$xSE1p)qDL+jJDr#dH{pjp!C!#SjMh# zY`&A4#W}V4dF4vrNyTvZnX8qUj%b&-ym@AVqvj_;v-(aG8Nst-1*J2c|3ViTDKqwJM4{kIXs_YLjWxw72%Sf`4qejti)9ibOjiK*!C5FVsKPoGH}0U zWb;R(&DB#jAeoUUNm#d*@3&_-%hgs!Pk$F17M8@Tn?RO6oZj&Ao@u_v;F~|^ z{(w8zfZt#3NnrCTqbh^-MxvyAHHns*5!1jxq zCU3NQbNHVkEIJpq&3@G0HTY>{Wb~^0IYL&)?Q{PU@s;fw_JfA^I3Q-5vs^w?haWX5 zDi`B`ndRH^=EmnR8ZiigZ1fAQeZNx{XUyB|H$IcvZWvXwqK_@~x~!jF;!n}B^vhpp z>rz|hyhr=m+}_}YWAX?!&>gmvauCLV-%_OMxSUhocfh4~#p{m}F%SHeFm98K-L#N$ zTmeLLO)Gh+4GZ@g6!vGv6eb%aD!q&w{A2f8gSzZwZHCxSU=wfuX%C_by$zqy`ub~@ z*A{x14_#I8Vn72<*YS@s09;|@i!b5#jn3X%j+MeJ2iYAtcf@f5_+4P>F67%};h-NH{LK{y_r|9ElOjK5kV^mZ=3_vFRH)xOIz0S4v39jfZf2y8 zl?s#U+9)&Wi4{577QsfFABT+qQ750`)+00$QU?KS23YA1E1sTKl#Dw@Wb{ zrKhFRgD=Ua0p%*Gd_bm8TIyxc7p@n`bNPj;ZB z_`M}8vae73Xgj&d-UoAV3fE(@bUKFR%LA*#6A$ZKa@)l5>npY|Yp56PNUPbcenb>~i>&R+u*w_MNX?9zkOG~zl1 zSp0>}>c;~X7904bY8_B1x#!V3f~+bQumP}D0b8lc@NWw$`M`i{cjmqT*-2qxVHpNv zwzj;yY1NOhTlT!^dh`xobtcma>T9IKQCy*;C0~i#e91iO_-MQ}G8)Kp#M7QE6~mpr zjgIP@#a@ZeCwg+)?kx76?Z;vvS7}C*?AaBOqu=M(@STun9b#ab-Jp`<;&anB#6hb+ zo}v&yf(&uBcdnAxzgV65ezU*|qJ+bPyho7t?j@<1HpI1=o>L4wI>;!}xrI8!uVHJ~ zO7><9?>RDmH}mMlW2jzOEpNeLCbU0wm!Dmxw`H<~+H^=^_GL|KJtJA7)o|wmQ-QgL z2@A9K(>ox7jtCl%wNZ%W^sQ<`gzJ?V$CKrh<-lj$hSW!A|7k;>si)=T+|1|`=|39I zWytC_jx5|#9f?^GIpgGt+vTV+{hjR$q4P8p^4t1h5)`CPm&_(;%n0)YZbs8-ymV;>*}~@HJ8n z*j=`)JKh$kpCf!2fMpjKPXYUoYb0n=L%3$x-@jI2GDt9@rC;eJjk~IknPe8YCE3*c z0l>mX2+h>yTbLHpKS2a~W2#PJ7easX00>T80W~1H=~r;DT^&;myFy4ehT3|VmRiv ze3bG>!3l_OADdLU6yp-MnrrQ+j~B+c12H?(&JZjNWi_oOr+d%GJ%})=RM8hDWcQk=>01gb2zio_OPm z9P|45(mBpG{Qg+C5qSh91x=MuFr$^?0{R+U3A#NJ?#-Y4;?B}M!?=Q!P#HsmUAT~a zCrY`|obXSXEy@sWJq0nB2M>!2vEd zZyE$r*EK2KwX-a>m$y6LU(Y_2OznNOYHhd<%Pi%8>y-cpey+l}U1HwUBH#(f4j1Y- zLMxuA?A(srtg5R+$8pMC<_~3|cM_b6&`NBpbx4I}nwX#ir+qitN^Oe9wi@NhN(q4^ z$L?%e97jLKbMZ25HZ0Dt)5MSkU#j2{zY{PvmR!~TDuy`M-~`dN8r_ck@U_8_U?;!X zFu(dEiQ|&lf-IrNQ?&w#l$7(^{xZ#j^~U9+f8$K#zi`scuJxt&`$=HqRd3>E+oDdH z+`KOpGE`98C#@cb(z&7VQ40XYxNu+Vz5^cryIJ5%a7yz)Bgj4%$+C6FU-9K!M6q$1 z*p({VURl>cQITENQQz3uSj*>;3y%1#GG-7w*)@>lb}^VNe*g^2iZ1QKCV$=)=%Ch5 zR8TUYCbjLD_WEEl!kb+tIX~+X39fr^`lw-4Wn=@jAYr8Wk!^Fe^F#cp>^T=fI0v#ed8X~BJjvwpk?%FUkEw{KL>3o9j&>bI6!$kY3DF+%UUjYcPZ+VURM*?L7H_E@ppnf6Adx*^1ol?K z<%Qp%ha;@_g4`K6Wq)5S9ve%#IJ;DeVh{4va=iY)@mwCE3`b!8e;dUfeJQkgk~VVyb9Y_JbE^= z_Do1+*McnQZy^{u5DqSL=yvi$H)yG}m|Tykx8VmFk@{Ukolx z{u;D`5);D-0=VZm1z&MYUQ7LH*93)Q--OKkdN;7g*cC5*Nrd4;AiQcAg`>RpHWVx~ zfEf5dO-f2CYR|uT0g!f`fpFYy52Ze8bBgQ*wA95>C_JH!n>1h|@I^(`XYPB~X3@Ki z=1}UZKS$QuqRh`&6`l(}B$Sv`wV*|;k9l2AD;OxUt86s{?46H;DE2qZjuQxR1Nq== zQS$pN0O`FC$*%Zq~3N)=VSTBSu1B9 z00&w6%@QmX7%B zt>kBlO=$|rwySPg>a^_{uALTwK(K#yhciTP!wW?OR{qW_GV%MyvGC0lvIGvyWVWcs~Bq2$cn*p9S@XrWt`^AhO>DT zie!;#RwBEKOPBi|WN+T+i5J=ZA*%QfyBH{RpiOzpiXbmwGwtr z^Wmll-}=S|!dX&-MPwR8Bb=h#1#S9})Mb6VS9}zf9vMom;$o7r*sPB_$ED>e5{VM{ zappFBOlS;1oGct^a*%wE;d;8dHbFr_Nj-%^ppk9;`JP*UpQGkU)`uO*(-RXe=g#dE z!CMa-@d7?+)Eh2qn=nLMiSi7DoY&|9h*?jYIEHVP^SmW?e36`A5#D zmhMJ=&;69sWZL}emd(EbWeeZZ56s`6+rO??UI2tKlH9aRWPLG^_3-im46KX@;h%E$ zyjXyNtvtAuLiZ1S5S0N`KV5!hWOQnOP*@&O2++m+UiFsyhpEL7|?qHgCSep=N#Le%c+ca%NC#Qzsl; zTK4uWZ0ES7x5&v3Nw&{m9@C9sW;Yu#2RIzQlO~Z29QK#EM7XA)))5(D{|swKaehjFPd>S*a|6kD99i z*H^{^6_+~f0OnBmdFJBe*jRqAAn+?#>p}w*(zWSlQ_s|FUBW}nRorzC?U=LVEW3J> z%7(Tc^dO<@16ZU4L3@_ZFJq<4@LqE^|B@G zhZz=#n{XRba;nmSTR+g)A8eUbNTd+}e&$L@NlmnbA3+wn6OnGSdfatA@sIYU>snt1 z6Dn>n9~&7OPAvACDEMml7o;M)+g7cYq=6TLJcVG8)3+;`o+>ukeP~)=0M;v5|aK1iYxBWwp z*!hZEJOm)aK9NxG?d_e%fe2Kg*itcL$A_D&Bqz!u$m+h=O+6cu&0}+We~%s3P4MFr z;zL|^KdBd~jmC1K&~4%B=RM0cuu?A7ZrBP$6gAVBuc6YvL4sveOs*%YJ(E9lbQonm zRVN4#Su**b5-6qA!(cBpW;9;E&Q58_<}-U&V8aTpysdam)N_T6bf7-$JPJ@(C{gUMJLM=yB>Xe@_Hp1LZL z)lnAHdK3ID;TIi=^%}BnvWQ=G-Kngk#77OENilKzC44#b1#ZOvqbQmjkQCJFigk-a zeJk3P68IlIn*R1v1ou5Z|5)SWLaDpT!BD?P+@GJjOvhbCU&F^Sr!tANa*_5-xm})- zF$g!~&#A5L8WY<-+DCdQY*~Luk@RMEL<)(mr7_IhStqUc%P6QTwD$5Z&-d9SIyu32 zymGwnqrT^`PhB(Vy94l9DPp=)+>j6O zGtA)*mHE#f3#T;C59l5d`3mFq=IK+ouj}Cdw|ai$jooq8NtX5#vnqtalCk8iMyW~Z z6?iVKQ<<-l{WmPgQ?~7uNq0TGu{C|mQVt1sS(R)tTz}bgF%2d<2%7o2EMvd77XX92 z$_mk`c2L1JKSw^Lj4ofyZ&9*>%e>r?LONxu%D@{_t@7$U8mX~ZA&aAAN-M9f@rI8Nj%_Q=%!Cy4A*T`)pwFY>yN-n{+MupYJ zbXO;Siiz5{EN1h)wJ8)g+jrj%4G0(Pu9~}Z6stCEB4lS2Kmn|y^b~6*(2x4p($b@u~RsRQ_VBTG}eC`L9e&W=Z`nd8HL)T3Po>GrR1)^ zfR@Q#bBKeRnm^ z`7rj$zmnWxwyDsHW`!z8n(;H?PzH(iQYf=i+7?C70m&QG)CPg?`<|V!P$b5d##K)r z>o{5xD{$Qz#psQ1v*Z3E3vQ)O{P*-90L%DH1$Uy9zw4&PUk~!_ zHMvuzuO*}^U{Y<-o$*KwS%dGAmd;Zlgr3_zv|b5^-)1!_OfKxuPTf*hRdwl^tPxfX zq{6WYl;{v2sR3q%pwHB|1y=X5Ro(PT=|?5|jL5#8{EjY}smQBC)IFTk4WYaY$!kAA zKi>)Q%_}FNBngKtI$k2{_E56KGYa7sgaB*!w^T}WGZjZ)rI?VbW#p@d? z!Oa_o2t5UD#td6-)~!k8ODEdSJNsMGfwZrIUy|+quX^x5+`Rwz zM-J*muqC|MzvmKj^S_nCKYcP&;FB43Nw@p{-JfaDId^AFlX!-L{^QcW-(4&PJgz~v zFFOCjE9~U-vbHQzV?IFl`%S3Gtd%x_QjAJ18!dFMWvN05HM@~{cuR^Z)HF<{qzN+@ z({!{P;8agg3f{2vq31CK^_21N!55|2%lLQP`q^JJ3$q&FhV6zwrdZIdnkhug+a ztotOpaz&#n_xd8oVO4Ry=+VznyN?FC;&!?loDxI%>y{;^0YlBU{T>TCjg`9UhP2Q| zLm?`6KQi6M^&ZpZTZ_9!WbS)AN00g(yFIP{9;j3_U}c+?&DIt7gcry$nva+biuZ`& zz5(nz0J7(j6;tLWwC4ZC&D9s8s=8nGWx)E*TUXOPidjwjP0_Rz0wT)cU2&71@v@yc}v)0^IL)z z;kUUHTaAZE^1m;oS@G8m8rLZ!tx9^FhSE_{+Rj7C8!gp&8~Jx&u!M0VGEbs8-Nuom zp|FEqd&!ilyqCM4T=-Ls5iZMgo=Z|5T!+-NYf)I+a*U_q&kyujFIv7_{970XxxGys<_egcRB8lGn!ID z`wc_+lWapgbC~Pq-l^AXFFZUv0SE!1lPh61A^LQGvvZXXtg5c$pLRi6aW7xy^OjKc z;t_b%zY@OoT^B$IBlu5EOQ*~#@UQ<$>>^ss{{EYX6@V_n(0>_&S z)47ghr)#q~vh*?>CbM!BUNQHRC#yk+!ps}f?U{tYq}#TC2@f)&M6}M>5_>4!)Q-RJ zZyy>*cdcH(ugOTZH;tr&?AOL6Byp(!1$Pe~qWx9hF|>tzJ@F`2rYRg5@LAIlW3>1T z`%R<>VryK7&C&#!JoNByffjCjs0d$zg4UCmqSI3^TcY?E**fv-gSH z&Ji_y6*pW$Lh9INmK1!@%FrKMmDfWgUozs-=j7+JyDeo;Cg3Ge+Wy7=%_tXnlF+Ro zDe2o|V zqvLjOnkHz8XCZ(aeNdk(9Z{nUF*wN1!P0>csH>?tliSpXekNGzKZe0f%mCnwuJSo_ z>HuLQfR%=~d<0vA)kPiVecB4iXyW_ZcH7{*h>=^Ya}yHImQjbCyeS^(l~v6px2e2H z9Jpl^uY!^;)4frtux9_6dxsuL3b_P2xOZC`UbEo`Qc+P3gR(qrh^2|i=Di>_ZS6Ib z1z|3emR790?&h}J^&&~pB9|+ukIc+-L$Usd#eMe@d1>RoA!!4NwNkxS3H{v|)GKeN zGmciFBb`281oo94aw+1iewN4>HYI!r>d^fGVAylz7$rYgd%bVbGL_V~t55S+^Q`v` z9#(iPg4`pz7$G(zaTi~@6f+)`VnAL5l)qoHYKk>)5Y~BHP4(f5srf|JPR66X-V|~D zcz9mbAjrF#^(5*}O5HU84J3N#xQ*WO9+u$hV|zYoxQT&pCrG@_d>M`GdXtlp!KixI zRQvh`ZDU?#?Xl_BjGW9&?$t~aIS6r2oH|`gUm@%RW_1-emjzIviE9jjZqi+VO83a~ zTdykTz9r7e3Tl<&!t)Y7M8DY>U)UPN)mr^%&sB^%RIknUn z{C~wC$Y%^=*e1!AkZ+<1TuEX2`o#4v#K+Wb_F=&|m@2d1v@9#-b>qn56Lbp|bm>TE@yHU;x(q7B^U%VQ)+(2vPRrUQ_oRvZ z4KP(G+9`)8HFZBThK@LqN7m~5ZrrZJV@8<@3Ha0tZc+;sg*~PW$rOyvXNjm#W`irc zs_S)XNyJNkY1{xB;{`XLN;Qse6d9|v>qVRp$~Vt_CcoC!-tt^sN3GhzKZ+rUsGZtD z+Q3v@*FHggG(#-t63*L?AGgq$>M1kO8CLX}NpaMVFm5%3f0D#cv-pj7{nU;3`Z$IB z4m#JE-N|wDb*m?r$RKMlw6_JWBS4^ztsvpGPbxTl8q{^HOZ|&v5eL^-^*|SvJ{t^Q zE!nM$bI6zZ)y~Dboxw4H)p+PO6G(z z>6-|3nzYu+hcR-a#4Kw9iD(z&$P&=LKbq)y%9|fs`#^P+nFNy5kAx5TknBdN>y-gw zt^K(y|6(e!HizY2QGkP~tcQ|mvCZ3@+^NtlGOPr6pGQ79D}*_o*_LKHH(;K0p2v@m z0F%)xV!`bMC0#0LS|a4+D4pGXa!hRXyoxvg_lK4N_>Ac}=iSTN+6jkt27ZK&Z6)F* zxzPgwIE-VH*^i4@_;`kR6%IWq0)!A}L*CQrLT9hNkCK8ITjl7yUKrD*hSkRl!{m~j zImrH|#D3ln>s+vzv`86R;!=**+7v2_NO@5j|58Rj-6*fl^Qpyky-2Ek#+n4tou3BZ zy;LN><}J+l*Hdb-jXTYCd3gBtrIW~^4k_4lNVJ|BPki%c_oc14LPWj36J&-OM5iQp zPr_r>j%axbdc=`pJhhAYb=CMT_Ov*?_@Vw&*s^zQZMU*X4p+v1+6{`&MFhEUIMHj={ns>Y!vQWm zIdf$3{oohFHz!t2kMBLruy~sBVMsD4(nWa0nRbv-@N1{bvv@+$#r=B#PqVvzJ*QK0 z2KK%fBu8qCcB^NOf$y85rFLR{bm$_sfVmfX{AhdmBZz}tebL`~sniAS|B-rH(;F)S zZOd6O$9$M$>HRDrdsw@+0ChQfjD3R(U)_Zzz*NkM+P@}N{Q7u$O{sVijj%^&Bs-KG z7RYTrO6`JUstbieagiWZu!wAio1sTbg*^DM>-#ES(DGOkM6`n5LQd?ysyrt)eX--{ zaI8bYTQ`=8xo6_`Lzy`?Nn@V=MXfi$?}v38zPO{KI;HKaXuux$E$-vn&_YMm3iuxjDmFGb3-d&01YS-1_KBXAAEl5@R zil`5fvOY&)FlEwo?)2Np+TBqULI}Vm??gk|Kq_Qs6#OzORj=6UuCDRNOaPR|k_+er z6sv&qGC!+ZN-WEXCi35X{cgFGxa{VA9{Nx$@6SG ziIL+ko(KuxaLta5tvX_6ev%@intQ25dv*|O4xLt4zOw@`Yp-B_f=*WTQw=%YfPjtm z{Q%JEJ{0&MK|H7Sl{p%6fxj>H0gH~grDf^4(p}NW1=N5N0FnXHl}>aML{koJmxeLD zLi#<4l;}Vv50|P>Ma9MaOU}J4Zp6-1zNZECyKgNlHv3x{(|h&wM~c$xYWp29<2So2 z-}Y0il^?yT=*D1ZRbCgopU%?tM$CP_)64I$8sOh8TxQT3;!Co(zcKes6xrM(bo8ZX z?HP~5!Dd88T($cg6?6-YrVXw)1VALRB*(Q1Ju==xcNg4c{#+SbRu{p+{P;s%lq-$8 zzhdYJ2f<&ZpD|1=!i+8I28ZznrkqExsw!seuLo{#J5P{WK-8F3F;X*cLOD4TwyAts zci)wM52ag=#O1s*{-KrjAjkHB-C)<$_3e=IEOSvu$0)(wVMQ^kjF*rg3*(HJs_quZ z)8z8<)J*Csp2BFF30xLF3DJ0$8GweOFVRtAurfEV z^)F&~ZK&qo9)Z~BbyN0;&aF+Iy;w%WmA8c^Gd@hT(z-sqH7;(5&Xk4Z>p`&K5#C~k zrGCASH*~HLPrq%!|8m(g^fH3(hTrMCM+WQxfqw(D)c9fj)L~l_Rhi5rQHOi{j+GpJF-mWI*heWZ9ntP&o-as$=J za9m_*W2?&TScO(Jd8(Ct)&yc*5TYDITQ<8|IBT0_|Nig@)b=N}nK}u!RGKYJO@pAJ z?2dbzQ=n|)=Z&s9{i}Z6KGprG;-n8F z%ft*3DbNxZ>Cm#}Y6uXFIwJ!#$EbCV_}`)|SFFI67956&d3dI@pkC{h0N3phB&F(% z1z*DYZKuR3rQ9c~Gq9EN%uFVq(iJbb707CGZ6`q@)-;w>wXqV6a%?{etCZb+3G@Pv>?{TS6P%oY5upS22{kFe!%ay`R^d%obmb_i|*ZPd$qwh}> z*u5(MT2UwSvii(vFM1~idZieq6Bpv3s2HmzXNSL%|Ogb=)WQ z{2Y)N=f4P;t>o?8x+<5Zi_;pEc`}V&UT(vdB{1<^l~Qw4Q`rhHRc8A)0hwwfwY7qv zBm0^HAdBNMfe!LS@Ff_h8 zMExk>RiRatuFv4dGRu-d0k=FN?r)zoffl+le90)7ijEGDjKy!1^$j*J1@GPTaI3M{ zx8B$d?}?3C1YK>EF0?3HWx9DCi-t>wU-R<`Azxhp=HTa$?$vMATJ~+a+-0brKl#up z8*^I#;Vm$0-?;R&kFU#o1|ccrQSPY+N`BnO`%cFrhdHJZ`C4I}>8QlqB&NT$$JY#E zJs`fgrot2Z{iAzhvGJ$Cf}Uma^3i)UUN42PYc5@a;R@L*2aHcmt&NSj)$3HWYpJVe zuBmSOBc^A9x+93aHr7kiYS|+2%k16)VzuSI#yVNVrLix%_DFlsi7|i2#uJxQCHt!| zlUTDAb{*SVU5Iab8R~I~=L77tu`=D+B^?t$Q(OpIYOQE{loZ!8 z=j`QF(|Mmt+0_}-S|{h(ue9GvV29BUx^{8ilD1`YISNv(2nn~vC!^gEKgtJ~LbmGF z509qOWup!ROl#Myi_6=L*VS(Fn|*sP2`Y6TNRFB9>M>PR=749{<5G>El{vn9b=9c* z{BrTl*w2e8kD#o)cC39UC;ae0VY&j{tL_Ru zYoo*U(tQ!AP@=<-rm4>(sBaN}lgs$fhH3f17eaoSmPRr~85g6#Ziw_mpm= zcl1agRO*!}aH?IF1xzMLSnoCJ=0YS3Es8RDKh_&ZfsVF(5p&!l(7cFP?6KUg%&5^S zofQ9G^{wD3xdkSpW74=j)zb1QP8mpAl-VwA3HkZr_nUE%F~5g|=M<;_@vHW<%tR}{ zKx677aD_;SP{qnOCi?moAwRYd{l|EAn=JzMf6{FK_;1BKte^L-Sl6bSKev~t z`>6SN=F^!f82DEAoi;X(&*b|{sjNqIWr*PpkBvdqmNVbk8cKehWQm5{fK%0juFxj& z&Rh8kx^F_y&Q@!$e9;-Q&v50FwiD^*U6P|G4el6t78{=PsBE=Ruxv8e_Li`0nW1o3 zuwdfeapKUhOWDIK&m$i`et!M+rF+MZ_qB;!GETP58UY=E%E*tHH{N30RqxjF zAi9vfMAz=gsY*$T)5A3(?a7VZTe1uI^ox;SzKq)H-4JvM=GU+sueix5&rAqdFLxy8 z?rv~ZgpKs}zD%`NT@*N?a%DltZKB8 z4W;21G8--!#2%W_Um1AI)*^FzqUd!{gl8LZ5QXIX)xI?UiMK3|RZ~|0op9q|?pnnq zwO4R1-U4l{*oRXRRC@OIgoA5@reo6zZvyKw6_d)GsB(0q5=w`7Nv#<4%AG0$skrmv zrd@=BZ*ojZYU1UaaJ+1I_sH|~F8`TNEv=cm6x%sv+tEIgBJEa9^KB-ku@)LyF7weF zjB?SWQo%Q73W=$>5H#brEce%E99S2$P8$&+G}^gSpDC(6j4SH7b!}mji2O_GW(bVq2w_)0%B%5!emq!z+CtV>3QCBkJ2K3h32c0MPw8gf0GYmtA_SJswL zXw;Kv-D>IV>`5ulBp*AESSd7+&Ru&$7A>tU9mCdUF;dj0TVm58^GwKojL!4?!S29Q5c1nMv`=Y%nm@#*()jHT9-L%!2B8^&PUaTjBSv=*CBCiKX*QDOKE86|4fs+Dc3Y)P`zYXQ;K-CZb-=QzvEgjd+1 zNZ`_L&77jHFqHEU$t}NoS6MAJdl%&vArm&8h10gVWoya##h7_1*9T*dnk;G^V@!?I zc~L^dFT zV}H1?v0Hq0E8yC_+7>JNO__&X1x2_gxuIpe4=5s}mxuB@4aTbM;jLc}o9;=6Tvf@C z+t?(GVu$VuHHqx_EZhYh(PG1;rvB(qj-r?X?$S~%rMyW=i-^hq59+KfhYm$+7Vf|* z=Dyq9#nfQj9gjn0L$hK!)BNqoeYnF!9LiAO=b?;Tv;5T;2N|Y9O@x0e;lKa1vcxkq zeawWHhD36+e!4E1-&mo_Uq0EC-NqXm?|}}( zcH_w|Wj4_vw1R_rQ2UE2h?FK{ywZh*OSMnEn`8q`ZB}G>K9>2cQSn%bR5)$a;DvJ6 z$Tc2pRWeo)*<7(;rVMOh)(lI6P9x0e2Q`&vuRCnd2$hs)@}57nX-%AnCrA*#)PJFa5`b3Hi9j!cIDxg?6 z#5*1*D|EC@#Gb}!S+PK_Rm(Y4proRo5owe+K&Y*a8! zp3TT)J7c(ty#X=pxDjHN$FTzTurX1vI;Z<>T2Mfs#ODa+=;c(PwvKf7k*SOOx0;GlaV1dCkREa18FGaI7d} zlU(+W^fa3an4FhH^)u?O<(JTTp$MMrCpf;oI2a-eWn!{*7GGZpk^SMSuSZvjU?wT4mG9D`VFJ=Won>r<5!m>S7#-z&! zze8A!~KyV9O5q1IZz2>&yj4Sk6x*b&mq-re!}djw6+1O zrI`It<`dK(o7omI&XqAJWu7>o=KNehe&RY5767Mi(z%;ES_aKw6H=dbxUQ0xkc4)Z zZGg1<8plhS#?Dx;)av}$U@W&aS+xmfan$8+-x_PVndDk8Xj%se)qGWz$6aVrFKLdS z5PG9f^e@H;tXMJ!*3IT-hTOXT?pV7z=;#-0=D_#Nc*#GoY>H%RzBr|Sx@c1ko2W(y zNg&D;2D+s&tIswE&z@PC7fK?fT&RJiwbEBP;-9=5&c&B8v~d(N+B%nI{{t___RCgN zpo-a@A~HRbyUaM@qtb49yUpO8Q383^vs~G8Z#|8)1#&lTSXVoF9_#g(kS)bk)t{g$ znIV55S+`&#v3B|ngEgoV=B{23)H20Z z$Zo0dnni6rr5LLA#+JoKYEmL&@+P@;!p||#9wx|lBL3H%7>8na4#v(bkYn;o+Ad?c ze|{H?W}dq<Q_so z&XE$nO}PE-*Y~Z9koMLy%+eL~Z%mQ5(@mB-G+pBLrT?Y+MQ)L`S(uoZ5YqW_e_RUh z?e_zcl-_NYtK4P8W)9|3-T9XyTmJISM>n@RrTR-Mj-RU~I!M90YVK0st-H*;Oqb+p z65D7T8}WYM?ldh)+aUV@tdYt+rf>G;-fet8pN30fB4-y&%*@s$uh4~kc~17PE%Z8y ze&;hWKCVOQSej)c8$?~u^){+-u(z$Vv#9j>6ITC>UNEoaOh~3$0{6zR&s_N=Qf6_p zr@g(Do#PvYCyWdCehu+_gvgItk=uu6U{=B&0$@ac@1jfOJB$qT{rgs}reMk40!FBd{+r4;vmE%Ejvubdp}{Ay4TOWIAfkj?@WR%jyWh{U#)lE)WUJHmTD5P!oLA^>Z?`7vJP9Y){N?Lf)sqHbZYs7blrv;w zzF<%J`MsfZDTX8um9?}mp1n_V(biHDHQ#QQ7Au%Et?v$1ORRNIIt)-BMy6V@vi4zJ z%|5cr!>o36bU1KZZ!gFM)i=Yp-uM7|b2{mx*|EvE*jNGDKojelcK4Vv_QM^)ZqX1K zv}s&p^-?23%(;4ce`^% zxh)w~cEjE&e^JVMnNDaFut6Vlr1ap==G~hi{oEl5A9aJ%n$TE zHumb3S{eHwqy8fpXvj>Wc+kt}U(gLI+$9dAwj4F=?#~B??d|2u*!xZNB+DhTg{)*{ zYlCWWaGX7I>gu|ijRIpnh`SqiN~HERtE2lf*k1!5;A7@#Dm6W`Y))r;yUiVb&MPNk z`TGMI8H>9$v()oe-N3)4j@7ay)Ll$wuV-bor*&25T~;e-X;~z)4VzBrgu4@!_sARZ zHre(=i2BAQwvr!Lb8v46jH4=_>p}M%EbO{|Uhz3Rl&Ysl1HH<03=eeINq_6y?Q2+Q zoMDVly6xSBGSr&np-29jePI@SZRarL*2j^ZO7ppA8iEtAxP4UtvLSJ*3}@}%C$fsH z?LHgZ+oOJ`D>s{=IkW868?KyamZMpo>nhYx^`lv?`Q9ztVWfcFQ|Mmf`2Bq2{#KO2 z={3?WX?=ZtIEve*vbA>Omylk-#&BMAF9$9~68pfzd*UmO<$16AouBBone`3O?^zm6 zg{R_-Q?P2yx_=M5L)IR{VTAbE&xD?$dtz<;bvfyA-@Y=mZ?Aj)G$SK&z3pD8pK_X% zuTkOwC5MVc&_svQ4`hZ1K0dyiTZ}+eoPoN#&DDP|!*#DQ>KYot>+Z@jv~SP!q<@%0 ztD48I%^ltGKjLLy7(5WxNliQcB~TZzh_NmP7Ww*0>QC1A&g^fbF%GKj)40$q0%EHvpC3P7K&M_d ze<0Uycqcmf2Jr0bw}znE@Y!{%1cIq~fA~xsS^>VGg17xrWHyk=oWAc*JLAglU%mN+ zCr9t(O;%3M)9_084W7%tZ{dgc1?bx!28jXxK3qVlypBKGt)LK3hxd(XM-+*5df=Gw^Cl83&07=nmSX0dKvor>o_T2zdn^q68hdWCp%NQblObQ$nmE0>5@fIl<9p| zR_;6dKdqK~XVzP&;59YW_V(3}37>lXOBLT{#jQC~TzVURSyb#l{0R4tB2rRn6&@$B z2w5HqM)}y)_vSS`T0@0zG!A?^3+z!8WPbJLsp!4N>2Kb-erv~%%tyBiY!(dk0c{xD zDy%M_tMYwZ>@75J>qO;JPZB|CDRP&ufA{qmiq8}}zOwR>;uVVTa>(y*_1XqBzj3r% z5?_89qH`PYj2|l|=H_BW?JdwGj{}e4Z|GnYz+gs0CILjED znOz;q(m6&a4sT|<`#pque%n*&{fg7@fFOOR)^aU*wbzoa%xTI7~}^=pi7?+jpz?#6{bMz zU$OK(8uS?xWt^tPM-A34D2%6w`}=|^e53pFgO29IwXRV+o0)ED3GgoFP$jL`Thrdxi zL&-daXyQbu;NIy!Bvx}t8Sxo6akbdo=;)9!zf($WyFPgpn3K8!EphR*O7E@Qs}eDR zMe>Z(dRuEMl9D)+=aXV&I1M%H87N%6_l7jDb`&NjH?)4@nb54(yV!mE_g+uyf+25p z1hlC0vUNVdFOb+OYS-R=D$r0)7WFJQ*6yCXmq#J+2K6VX~mb5{EC*p19lcU&!v3u!{-LLIu}GC6 zE;9<{c`|oP)>tUa$JU091`ISc+n*4S+AaK$pLo$49Ktk~S!Q~sWzMi&^zX$3cDlPh zVrM5ffcUqFpC8+0Wh{C5k7~QO$8<{t`FaIcbY?9a93rE9!lU zzh43$b`O5n)Z=#J{z!=8jZQunne`JnQJ`FUSJ=|JZE+5X*H)N$LTf8B)FQRoFur?q-s zhI_wG^FP+)zE@lG*tES9a5i$kh#DAMSnT5TxY$k8uIL;*OH(_UjE~o$%#Y|lq1V|X z;j8*(h?0p(M5fV~K8xV~-q>>?mc{~DwZ-W!yvoYTQ))4UEY(+Sw(yI*{n#rMj+ncc zjIpbv?Eid->2Hkh8jfD}2#@@VGtR?=X{Niq!^6`=lbxM%`QPJWVmuaZX=%~Rl~**x zJ)^h6oJy!;GyVEN?-*DY*EpWJ-}`ia1);knQIErpIKzz<#yV#OW|vCjeHwnnAWqZZ z^a)w1C?Nj4@8z3V0cnDb5qiJg_D)0{`$;ul+v7ji>U_WdNXsr)pYIB0oaE-8yYkyf zIX}~0Y~X}D1p0gb`MEzXalVUe7qKVn__-ziZP5PX65xrFWx?suot?S;zrUwW_JUXW zS~p?%pDXcyZuip#EXyb-9^C(si9eqyd5sk8X|=7m;s3tfD*AT~V+^!JzqR>)UG4vi zWdSZtVAwPIht~y%|JaRJSR)$*iNDXtKed)!ln8y9R4&Jp?N!eg3Q@P?+~Tfr%3vze z)K~6v%+DM8Mn+P&J{>zUu8~Mh@8XGxaniuxvVQz^m1nMCbKeU4(*Kd|yWlm+5Ec`2 zt*F@6f^c+TU|h-$c^;~{Hr+MD1?tA!XIPuban9FgcBI(IXJfAQ+z9~&k`NG6GCq5X z8Oo=>PD!aPpqWxw_*kdPu3d6k;{rx%@3%7m+#~r5Ufj8vq0_(aeQancMs%r>&`UJ%Wt$TQtR-oxSGiV~?1S9TDTv?aU3FbD-Z;Y1w zg!chLErNv(?;Mm}oOEI~T;r?~{q(KOKA7N0ks%*Picb)PXby@(sMl>qSe+bl2El97 z_PblsIe#DQXQ0=-=I0ZYrvLDoghWKJEZ@GZUk4bzKA*|Wu&5}iQ!s){=orj-3?ZoD z(|hq^r4@7m&WfQ-^J^(4o#qHBUDK|ojuI-5_^ICEO3(0)digAxid+BWjo;?x3&%wh z0bU14(F~a0$E~x9M8$E#5!ou_ceuHSdfGcxq1o=H^SdXeNo4~kE=ewWMy<244a!Gj zvPxeQhcrD$lSUQXM`-iS!)J&Vj1`Z$OU>;pmdw*^U!W+ay7@;eRTacfOm)y}e2b1$ z+?W`nUs}W^5y)T<#~bWlFPtB)ac=CQq9UDVf_BSFPAl0=^1+?BL6q!V%H{L}NTk*S zzYO36I5`e2E-YwHjIRREcu`43g$y5mQ~q67@ee{x2R+>L#=^?VLP%TZdJ)m%`{VMAJckP~^e=D6QqD4i1(r^8oKtqPx>?#=N$t4wn z_dTWznttz7YSv+p@At?^#!%6@*Kgi9yEfC$Jb`UcNq%yXdu3*8YnLdaYD{h3)zw9t z*4@?CX6N;kgM%-_-G&WriI-_3klFIG`QgK!EQ^A}zR08`BeeFzsLP)D!lXuNwmWPy z4D8p%6+*DhKTb^-wu%*Z51DTCJAb%0J28JWcO%t7GZ+1oy^G5tZ7177S%**9L4xHh zIQSvi?v~b;LQ7WLZ<$r#P$(oBr0|pql@Xo~xk1M$>1uUKke!k z7-SoEikJZ-m(`-2LeO+?W}S7<%NK$~PU9Wf$;rJEyU+DE=i5`jGBAz~@;9Cw?fHU8 z>BeW{Yc-!fJz=+g>~V~3Fx9iKRvnP%T(Ru&dQ0*X#z5J@^p142yV zN|J2f9*4Ebh4(Y{M~-J)$FuCG(v&o|Ha0pufW>0-2chQ%<(VZYZw4SoPErZ{ZDL_( z%|UedAOI!=EWuNcE;@X|i?!9w8n1JYBS>G776Yh3hy6z3<9lRmJqLHqNI4g%PyIdj zTi4Gg%nA+GI1?bCXFF$4^f~V7)VcAx&61sQ=~S!zB$}?Y1&Z!$OPKp{X>)fzKHb@V zYa`%Qsy+6RQG5shZ4#X%rFMb+wn;~F`(P@hW7o&A9-T~_#beeo>H2jrC$nt|T4B|#lWost2-~%M zn=K^Su zA#(_gZHQSw*Bvjg#~B}e2^y1>Y#xM$3*wu{8|yWRAKB$(J)5=42+TjAP3us92(23! zuldYcF3YAG$B2q+(v0v9xUt|5Qb<04F)g!(-ml|T)@pN&v#s3iGw(-+ZAvI3=lwL{ zLz`$0qY(ad$F)iG!laVp?~O~sXZfcRYxP*G6*Gzc~xMOpO;q`p?&><=PzAZ0frnot>M_W{8Wb7M2s-53S*X;EznA^IDW!!x@WYwscSA~97(5At5vB~zZoHHw*)h3 zlvzLN7e47KFO7R_P}MBhi!%naQ*4}5Kwu`z!)`{$i{C%86xso8I%xShDr)~A z>5P{wYAYddyujtFg-d=_xr;>HsD?6*DH!5@9pH*6A4UliOzpRDn|T&*LHIWYc)Pmr z48o}3e$h`{3ZlSGz7So=)y1J}%!{t1?x8{YVvY?iR%dRWh?*YmT2`pguiFsz=o% zIWOKcjY7s=QT*k0kF#KXF|JUbze)LL!0}d2L~J?E5)27Bgx4?T4fLh8YOsz4s=@TV z_=OW7nmC)cjKz)&Rd3}j!J&ZNgZJ}dglD~aoe8Q zcL(IQ$6T&Aaar$Y$Xkp6SV%O1Q+ZHUc*FRz*rwN|D--Eeo@W>Ho3+){-rPmYu`pP7 zne-{_?5gMKJhrw=z^hdDfTaYa`LugCvrf`3)YcHTmHm#lYH=)1ljj2#D8zlD4yd zsOyOyYix$^PcdUW7PW_an?$7b3#qhRW&u%gz0}4k53WWSpKJY8yjo5QgUHsOR}L=y zD|~4Xyk~X9?dM8?f9Y3n`A>iRrt}%1prT*Io#DkD4+e!6uqc3K@J_s-YYTR-vYvs% zXi2u3gMP@;3vKPC%HtpGCq>mJ_L%T{{%HHpc&Rvb>l&ae74i7~_Kz#f_wHm`Trabc zsd8et?^yDDdZPX;IpSG`;X?vGli8!Doz2&*D-La~{bJU@sd;3y@njA;O@NSm{ow9i zfdnel?Q1%rWu+IymYa#GXZA~SqER}P$Kqgg24KaoP=9zT7bLkw+RToDow%O3M10h> zgA20%()JbQ=URo;Q_BCJ;n6<=Oc5>8uzTB!UCd-c>TwO#oz!r7MtYAX?3NTZH<{}Z zjp`UhWN%jqq{A-mjM!tn(Q0MjIThkC9H zr`rqxwBXaV^hMf4qd8cPXi32sut%=w(c|N<0kC0(q`XJrj_&)NMnZE-fVH0PQ7gtt za_;>)aMCQBzwTcqqJFvYT04hzF_pFaG(!4Ocxk(=)UzD55uCtoSU8JUbw$N6wDmn0 zKzoY{RU5i{q%vh%gFxIR%eg|;+RxTNM9ouy?23QOHW8<{A{K;r(7lxCDiqJ}I9S!T ze%MSJK%UmY)|n{SYJ-buImz@qe3O-(z3ZU0EdQzod!s*7am<$9kAfuAf}Wp4g= z3{)$fe6)9UM^7&JKeJa~FJ27HhBd;A2w;}{uDcK6n*2@J4V_l&)1tOtG29#L8T>j6 zmm_Yw0FM*Se&nbI-9s(@n4o25$&c3FE{f89Ms7C+56F5!1RMvB%%2MPq6>ap{ao9U zFC*0!QDreP#;75+aPw8uE!m*@^C8J>vnFT2(6lS*O-|W5AEC=THC-od_+Cm6l#Q5f zbkGQx3_Q~&!8Gbcia93* zWqDu*vOm}MfH7w`&ZI&i-Af=SskUO%-vzXNGbrd;)#I}&b`i%Nlk^Cutf!A%a|`pg z9cJtF8xPlk=__5&wLJN};5@9;6R~J4wB&4xnMK!j%eo2m{8pXrSUgT^LMkqQ8nuQ? zq9U(gE2}aR@c>P_^e`$@=0=WYaf<{3g&{d-v&m)5Gufi>fgVIa3FlfB*UP{x=4+0r zfEMzbNp+pU5$OX=Z`rHNrhW~bU^w-1ZBx6k=YZatMb2 zff0|}epc&{$NTy9i3;nq%2$d$g$AuLu8!|{txDf%=dyO}`f>IY@YUu=H|`a)6(}SL z2_A=@Z7g9zbSpQN9htt9AI;I74L75KKQo$YCSF^&PIuB5g#cHn<+AvaW>YwdyTYl! z=(6NleR!|Vh8~bNpV>HVwln31U~uyr;qEZU;}v+mQw%}uO-7Sw@BhPM1f0f!f5GqZ`3b-wc)0I>ZOh8V$EIq#SHtCmrEQdei z{gs&#vAhQIL##i7e`(Eg3HLezS;}L}uCh%Z9%^NN{d74z>;4Sa41rg3 zE5Kgq%mXszt<8(}_B)f%7e1XO8&GcREpE5MN0oXEy>$nRD3I|O^ zmV&a8NKVZW9Nw3q(OdTZ1f>94O5nMpe#UYhH@s(E;?%ZgeSpoHGHq2q9ShEjZTxT zi;62toy`d>S^D_%D!ZVvwl*p#+Z~KHdAzqdX|>pSGZa^SMHoY$#mq>eGDaL_?bEyo-e-#`1MYR^+PVGh{yIbc{eU7WUkK#(`73>@(K0UD_;&R7)D7z~D*`3^lT z3jCmLzERA8$%1^;Wu?du8=(hw3gYkk3mAy6)yAP$5erl3Dgv^K`3qhHITR z-VepNpB^mLK7Eh90NQD9@JD#Ht^dFWqt4VmOvCWv8Q8F(b#CpZSmo?JBo`Gmgq`b* zV@$eboRAqVrGT`#><3Yl+_SEoANZa}o-YE{eI9{D~}EVK=p3dfqq>5R_OXC{F9?7*XIGiIZx~d$0(;@M;TW zf*!kVeoiWB{vqX}J1!r`<+lb##ZVZm*VOMfv-^g+uciTK)IV5Mm|gJB<^1~7s-QKP zyW4qr3=E3lp8+CPQ5{5pkFV1v=!nsA`k7AW>o_@L=Deh-8AP~fm{(lzL~ea@D&pcejJS+LZSz>(Y}08X8#|bwpl#)p^a&$YaqcM+kkLQe|sv zi#0@!O!%z1L;UyyK~uJMV6F^{0GM;4-~3@=CXgu+A9PFaIKY&TfFsSJmgL~g8bX0Y zL#S;gK(Z)~|Nl|<)?ra@ZTznyh=ihaBT7k%NT-ORA|)}@fPm6nLk%S%4Jv|kNVnt+ zrKHk5NOug~F~nK8U-#>N-}C;?b)7%Xb)A2__GTDnp7pF}t$W?~_xrgkzdxD;PZ5R7 zTtU=@T&^Q})?!4zuuh%s+{~hLe44=;8_)X9x$w~v(5xr3#;JH%&KW*|88U zQc5f~5N%Fs$((4KZ4md^%?An3({Wv)K-ff8m3y27K{=x%+_sHETNo;q6+-SzZT&95 zdh4=u?{+oR&=NNMGatPqD<%CJO&Z-6QBlnB2C&$l+k9viD#jp`caJUDTM+?c!?V`Sjd_zpLP16&1XQuSyC(boKfQWlq+fWb3hkME3q& znIO7;G3pK*2S-T=UwbGA#H=jpu}N*mRBVvUM4hUD^u#ySRw;h?oJpvh?C0_tibAp^ zvkMfYvzQI`+~hA;Eq?E=Qc@teLtMMr-2(DBd&PK+w7(OXy_6vfsdqXx*15hka}-92qFoE#+;uqJ`K^wVTEJ%O=@zC5`?C-M($h~S zYd$=Bi#=xIU0NGs2b1I4X&MT|``2;EJCXT1SMhL(AxJCyxfuSLLI<)0;Gr9*_j(rn z_qYFNK?K}0*Eb*^YprBN`1>;c`>%-uxaepSmZ zW;y(s*8XSZBw6r$NH4!`{xy~U`P#p}clRYQ`feB4q5p^C3+U`qUGv}*?|)y&@9*~i zc34JX*u)=|(KA*ol=~x&NrAq@K-_5+>RE9V_{1T6tR~GV^ET^tpwL*pu;QLu=8g1+ zZpFx|>ghZTONA(gu&g7+Sg5Jm*&jS9;I@Ga3E)fn^QKSM-U2lbI#BaCiHwROxp(iw z_}GmJAe*U~7{SQxB>{CnP;juN4nrmCr`Zq)#Dn=TtgWJae78x-$Z+Pi-&+Sp#Kkde zZ4-E;#&~QAt*H~)0w9H=eo8@beAPSc2M>DSjd!A8^^znmE-oMSJifOc{V3?lS~#$e zE|MU4GcYyTK$@7m`#BTeuOn?tVg8Fvzb#kr!T^sZTdOvL;5#`>&H$zch$3Bm;LF$*2q zl>S5v^s#X>wRsSGroCl|L8@8GsYnM0v${UE+y;+DyINM*{Vuf;5QH~H_ZM}c@xuw812lkw18Gr!Q(68TR&yjUtSX#Vc-kHD1>IF zq3}o?>_dLW0BwxVUF&hIuHwqd&+;>~y91{pZ<~XKWO!e{e(krlb@B9)@4VsB4%O)= zYtyIAg93Gn)h2pk7HFZK%~?v@xV*7WH*OD?0>8gbX>F+#S_ zoTmf#1E~0n{51|DyGezwsL(}6UPwQQ+~!w!jwz{u1365Lh+_^xW~5E703J!qy?W5q z<9STnjDd=kl|qcTTbL+5U@Pbh1-S(e%bwf`11@bvyr#&z`Rb8gOt6BzO-d@|}zrN40sUUsU7)TOg8%z)kvSjNwD<*AaXIKo? zI1S#%#Vw;C_weUFT4L_4I&X+MjNM_Go9M|H>W`*vq?TPZWHDn{UyoI5d7cLRD>E6j zJJ*St$n}WK!0&X8gZWSodZjU9zPkOdx-wE)&9PDyjb2U)`Y#oG0Vu3Yp&uNx*P53agp`!B$tc`V^3QEvp zd}j?}|9P7~QG)OA@X;w%uO~^WSgP%N!-^T%K?$l4;y6GU+7$Axju*Z&SngimzM|i z1Cy+RT7B+;-n&jK8YHjqAA;7^LblTy;1t)|*da}_$x=nLj~?J)seUz1oc19_CLV}+ zkP$j6Dm0ym;xr&#V}^;dIJ-+y^0?}P^U6@9lA7aK8)*oG2*bpOzKyBd9o{01TWwc>&*vP5x?zac=KX0!aeqLe zB0;Y@OP~eX9(&)^Zm7;PsY#2Xwe|9_b3;8K>917hforY2Ycu)M&}FRcvCN4JD&Lcs z`=(;d-Epf&JOX>WQ$xjRER+0xcqADbl5TK`*@(ou`tQP3Kw`O&^&!3_w1QGXWucohUb7&r)}JRT%tAUlXiHXErUZa24Qb3wpQ$9 zNlH%c7RIVTOB59a;cO;1WDt&vg1AMekIVV?Bamx3Iaa03TE?4-d-ig2a+VSbBh~Sy zHRV2f50L^)~@6)VFDT1(o9ApnTfO#md^^;rnTR-I1&54BAs>vx`=n5gpbDDeamji#yX= zXQh&DjH)}21bPAV%o^EFYWrs_kxXj%mz5t=7FO(CAi#-!`68qCt4c=%t35Z^(YcWv8CcC7Vj_z0g~>W zez%3mnZG`*jxs!mf_SV<$BcRqr*eh$1SsMIK^708~xv+q(+`?J|i`;t9muyP9 z%vTcOpf>oxXFW^#_DMX*xM*@d6ff+{WaehAkhx_isTg~|Nv3m~W$)=tdirq}W4K1G zyI+Zz`+--m8M|l-sx6vl-|k9mu4c(Rk_}BQ=?Mz#!dnBy0MvwH z>v5>oOM7+laSsd^MIV`bBRr(!MIA5bjpf`qO>fAILq6=Tvo}OK5zKS?b%=Sp@855dH`hi1Rf2?MEMww35=6T^m@4OI0`sS{^Qu>-(+Vg$ z^r}s*jM`(Y>?NBD-jFzj8av}*cjPuszHU<=%0GR$a{Mf=1VP{TkxP4Yu0R-^ed9Y! z%epdK>2#`{d*rbC2hlA-ee*@|_JWjq!705n(Jzk&wXG2k-9b56!e7QdO2>Kr(|YV% z*B=t*mN>e_0}FXTuP1hP?0TmEP|_g&?gI^j!U8ap9pIqN?SU;^0aEBOhJAX;L)=t? zom~Mzna6NmbuotSSegFVFjw)(p4T``0(tIfkACc9v$ln5&qUcUS~AeP5wqu#xFEKB z$=^Vu*dRT0TT7`nTzv0y0>etli}kZm=iLF%G6r4+Ez!BO!ymiv@GjwA`yyOrVL4yv zb+$K>n_#S|ncea2&RM&Bk_3l4=pVb&6+QoK`#x-qR#csO+8EDyC z)qdkEfhSBwWvM0}D1%ExZ=?LQKrawR{Kg@7H;irsdS$fSGMK=IxSrm1k&$G8y}mir z{M^VV{~^{gHQZ`7{7CJLegEdgB|i#qfLsq?;f7S+6*O$7&21ZgH9g43ZSzB4%xzDM zjD-U>(>UC`izkgS%HyX*{7Z;%y-10 z0`j#dY#BAf^lbZC^qq%GKMfj}<8^dt>2$@}IDMPeF_BGsfi>QJ`b0JAX2t?2j8{ov z>Iu3^@m&O0HMWvmh#AY?elYuDHCj1t;Mv)@2Z36kEH~^Pn9<+kD;bT=?o3t zGC8VVmQ4fFg-4ig^DQjLAAde%ev!JITU`8Yep4z!D1XS|>W=|#SgpZZ!KTb*yZtrj z+KWL?ZBWW`2-X}8`z2>ulDT=Phj0jr)%a%)#O=A%+7I_SF1-pfxmQ1{UETyff8;^1 z>vi!&-b8!aN*Q6vJh(Kt1CrT@3whdQ=@-e!$qzgN<%nIGnssViYeH}K3G~S1evQ&M zP_HSITriXq`xuixQo*d0L)++sL-ff@p#7-IpkBT7!u#nDMR!=!TN$#5qHbuE%wL58 zD{;%YqL7Dj^?w` zAoOhOCtTh&nKGJAi(-o#sn}O7SlrgXjk|b_tQZPbpt4Jr% zMzSj=SC&eSGv#HM`eF-?Iq`^V`s7=sK)}Pca!=n1kQ0P#-V#jPNtrz#Yvs`wO*%?o`CMd6Lj7mf95xWad=r?QCJ&ZK8Do z6N&ZS9}g2cE{7ISAihRb=oGigZ!?!8uQ6Xs61E@KC=cCL$Ia)7jiV7~?f6u1n^%GC z&A@XPHtVPhJ)`j=j-!RVcp=0jbGie&+{&tR^j}KSmgVO}W@9YP%xrEb7xaP#)uW?5 z5A%~ApXp2aVcQPW)?9J_cE^B>}^K7*xE0 zd{FuwZM@xmb=7tP&|4hse$7_U)M5FMisOz=yIC1IVhFUwqy?>T?-bHhSx;E;v?aTK zCaz;*St5r8IuOSP1rtEqO_MSjp9wpt5%Bk#Gxa}N3}N`@Tl$!!(QNcn=I|H0D-hKW zpKM^OA75t077#l!m;cyh^EPjf*<>k5*f_xKGnnv_x)9o#Jd?`HMl4N7Pk*?;aZ$xl zirH$ZCTxA8F0(AuiU-os^+fgEbpg{}rmn;EXx$>pxSGedoG%}5vR1$HdPedjB5IMX zShHeK7VC9Ac9Vz1N9?NaDW5imm`0znMRO?oq{ZiNvgm&)C}=)1w`&ek6Mp(Zbxe6c zGpeZEVF@25nzJKqwPr%mb>A}wn)8AbE!$}%F55nHBg89#CtwbQMEYT9OWiolTS$$j zIPB85Ze`?Gs)s--6O0D%XQZ+6&mhMZYTdm5VnUi)3=!9c9NXdWshEvIkS8#gL0h_?zZoC8Q#f@XF5PrtC?Qi zynZQxwP4k-AH(K3fYZ5ik0OU8?;atsA2?0EqP-oBAnFxSK*wx){89yf=JTFatXhi4 zDgLL3pyrtr)@KmGDuUk4v$qnS-F~72#Gc8hdr`O5*1CBOn@fY-1a%rCivU?fio(ZX zq)LV|iaG-0I91=o;y>p+k&X8>B9a95Jwm_M`Qs@3>ebCu?MQ7U=_vBfcSRg24qv?( z*YaqMEBssHuo)4TfoNzdSfeAUuG?Bg5AZVa{BS&SPrWYA%`-vK7?4V~!t5aq*k$w0 z`q>qPuQPW)yC7;en;Z-UtWDb~Snua-ZrbG-fhKN7g;YCT-4vclmW32-6+EZVP**Sp zq{Oz-oSNv0rQCud8AGm4=1nE$i$<5I`ZVnC&V55#O!5Y+ z^?u4LavwSEQF+++JEG&;a~|Yr4>T!-X$?@(i#o*z#}ea!lh2BMmP_=@1mx4jK8e75 z;wQ}I=o@%_%5AD^NctCuHYk^Ip7T<OQi0M~R+zeOF{0#0F_93(p$k`OOnM z+T80BRZpdYVcA3pBOdREXy+m~Jot%-@uOm~n+CJ19Ak%xDDMtY%A$e`vcd5?_N7~o zhg8;GbrQ~n)A^T)vtYWuf=I?1ZuSt}YWpZYJ$H%8t95{0RIN}4f!@p|eQUO$w5!&l5zNjyQ{LXS$xM`aGCp0$9cQBtFDOI9;DX2r4fjrkSAq(KdNg zuif%?^8Ps>SL+*E)-h^^;RWZF2~y*B`NElAu1(v&X6tQlPHoejwk1j--iMPOEH^0v zYeUfAe%Bj+8B7RabB_sBpquNQ#5da7FjbQ*ta;cHfnvma=V$}0BJ8ig%T!6CW+l({ zEL|HtXV#zp6AY^3lpIzMkexy+<;aX@CDgcd;E)$I!j~LtTRFdTu>~ZV6`||T{vt65sQK(6mB(XoUQnP&; zFEuqa^eerD`)5&BH8ZKXYYxFRGIcQz8=<>#hHE1=0>uSa=U8F6G9$SVN6YwoMlJ## z33Id^+0W=@r0qV$JyT($AIKO8zZ}h-P@z@19P&x$^U1NgCvR9hBKE}OeTk0YB6UC4 z3AG$5GQI=QarRDqg9C5Wk@M6s!m>sJ+2j0j!zpnDrdiz5E077hsxU!v|m z{{AVKfvmr-RgsYTe)pE}jFoX&o%^AWr+VrEk1JfOTV;JSHbLdUVkD8(@NWwn<54_yJRGK<@KD)xQDx*O(dbCCYCEakM- zIx=<&+n&ZDs7Fl`DqvoIwX{3I<0f&{?lS7Y_;G=2)6LBCMtIaz_b#*g(eW}aCE^EJ zOZ%si)oRDnPnPSG11@M;l+AtF=wq$7g$oDNQ&gZFBPDX#^@ov9osFYypDq}b=^(Y}>B z+_c$jxGZdx>10=ru9=sKJ5myB<(jA3zkTh8aNrO+zA{0#MVr)66-P--H0U;!wf36j zwt1=j?Te7rvZih7y1j&a&s6&|8}<7nF}CVI?&RYw1`}dgYbi4R&CEEj5*cIf&_T70eU{)Kt*A3^XBMJ4Sn1HF z@q{Vom%S+9y?FY`N-&f0zbcE9-)?yo#c^-bjqyiB?T+hAF1=&^m8dgOyvdI2_uyIo zJ#qhUiiOEtBtWIJts>*~yW;n&%J%g{{wDH7^29!5`)$$$R~i_j3J;-ce-#>?i$LK- zVrW}&?;r1xDkOP=4?K8O}h=@sg>^udCX#@i1I(4x@v$ob05N01BTpD6icG zVXvOAMZGVcK8SQa>d6J@n|W$#p51-js=5%7kU#=zgZY*(4%RkgoPMV*yBWbvxK>>B zn*{RL^(=;X$+U(wR`#D{7p8fX9w?iIN5-I>^w67=t9*pG|oh3fbg?3OLq$F|69P%jZA>WOol^kx<`<+}8VTm~1$8rR{2>)@r zz3CYvt_TYso_jNFHY}NB34D$+&fdmRFg#=H|(L-@SW5lh%XX^9}%0 zt^>apB{dCA4Yt>4Az=ON>0)?(+SeF!3NC@;{E6f1xdEG*$5Bmc*PqF?&zEo1OZbLm06b*<_g%B+ap|zg6y48uV z&Fb*(pvSw`y(0aG4O?>@VgUd}Lh)cum+roa4I3L9J~%yuYNoGR7ZYFpDe+iWS04~n zifMV`*hXh(obAX1I@R1;vkM9a4OMCIz60k#r<$#*8nncvZO_HbrW*Hfi<9A7(G1%U?D=Ip2G)4hLum)HL4>XVt2)yt&Vg!Nd z*0qPRcyX5+a3warsb4G=u0BHJkjN}+Kl(040cE}=H~QfwXkNI?!fxaX{2MNM!-ciu zuFF>`SU}$D)n;h97zuX}5aiJe>d9*qPwP`~FvqB?K`T7^YddkC;eE8Ln4g{XH|@&+ zRhWBMi47QBO+EzzhYI%%;BzM<>EiJZB+2ykBcKqL!}|F3B@EMHE?uPCNTTG6UX@#~89qzb7@oVnRuBuv=-JkhwDW&fh-m z3X;jQhzdUazbP=k7SnFLi->!3Hc>)C`t?i{3~F*}ojSt&3+<2qGIFxg;-?+O zv$^jd4%h_?JEO9)>~Mw!ffta(a(~E$#LPQXH9RL3fQM)f5AW1rJPCml;xqEpX3Nl8gs5r?mh z18OWXL^k@6TN|xW;Z@6yW5|jz(<%Ut;P!0}QLQx?uf`d)RvD_aO+XlQ#VKh|E4(Zo ztA%R=hFn$f*K@c-F>$l&+l~o-nq@VLVQ^uzpg{)R-s*^boNShGCoO zMqZM2hRw>@xHLrMfrL>zCB>@=7vr=|_qM}UMow?YwRs;OX-Qe>lKH(dl)C2lRql4s z+W4rNh+b^SK*HQ$<0(Zc=om0NBPS+lKksl|8xKXC_I{2=1abH0zc5$MUguln*Y}F( zKexzA6)a-*r3KGx-!B6E}z$-2KA)kQp4VngP;AR*n`dV99A^3EpD z_^f-BQub+QlBD^qNp5?TZYU9^BrLnsD;{CD2gsQ}o1jr{lp+qkRnl{_YNB{$>*T zWBbvT&&^#Ld!5(x&Hvg!j3&$DdAB7zVGodtdb!#E>8_^!^nws9z11@J9f48puKb~1 zoyR~zw(CbWZb;!M5_Fo_vG0l(o|z$|ps13{*}^qoW6hPBNKI8O=4+6dR?+p4zJ)0> zkFFsS_E$`jSmM?kXeOhHlDh7J_{cops_(WrjbrZFEVKR|aB2)CWbJMQr;L8L8_ap` z`|Q<|(oouJ0rO@BUXVTffn$zWS_NA#J+a$2I@p|_XW^Lu6aWi@JprB{MTRZp#-wG+ zT;smsDp2T*bU~}jlWw&YJ13Ak{F+C6RZ|l!=yD<>bNJg-=mnHic65Jgi!NZnWTd9& zQy$`u&E07!@I8OXH5sT_jErI?V-_5p97k%NUH=ZhqpTFBW9k6d1s*zYVg<~1P2yIo zIbq)AS7jVs`10YSdWpe4%AOq(1+7y3gM)tJZcd08_8tvKC*~~yK|z0zAFGPVCdMUZ zA4t+|iPOy?Uj=SVq!7FE_8SKGVZdm(!)%r_Z>^&8M%X=Eiw0qJyI8qC`{=_>m+3}Z zil7M(x3b_K;zY@vl+3XKT2Z|;UcM7|VT-0`+Nvr;r?y7l8tY3mntgJbl@jyLA&$b*F}PvO8OQG;}?I?ZtiV33>l zRTAg#ul!t{V@ZuUj_Asr4xhi*Lf2)hW5(Di0&!O>L;$5~BJPofrK47dt^Yd2(x_tr z6d`nMJ}zTU*3Tli>IDWLnL#1EC2aVozXP$GSU;=Sq6T{!qFQ-S#m$+9ec< zFr3pOV-+^wcdCB6@sY#1KdZ;-dBO0=%)5h}*b)G}EzzOo%S_AA6x6h)CgFD66MWi=&2OOl|e< zE$j(UxC0@C&J*<||99`~D6&+#7XIZMnS8+d^_Dr&5t-EKpX-w|5jN8WGvxx)J|is` z?-MZL-4GWL;$Y8S41*we)o9c!)^c?kzP#obea&v17hgmyqLv|rWtk&-|C+4yD@)5z z#7kT)u5o4EB(Q$-mlt*}H%ROasgzR=k*uA5h+(V9iEnBM2;ZTuAvT_SoL?}$CSClD zu@UQ)n18dHun$lPbJYgO4_RzIYEm_O(5V%g>sm*w&fM90C(jx5crkU6m`(lSdrlaw zyrT8ugj>A7EA@`ICG$m{br4g(jDxOIw(<#-uqDaec%-)u4+(a9mjzY_| zG@AEi>;n1pxHZ2Q0|?^uYFB)0ISJ*wKAO7#je$PsM=TMLQ|JadiBQBbvzzNO-^(ok zFjBs1_ZASL93#>nwVR*dVuj}4BLtx04cB_}!Rk4KwbVy#A!-Q(%b<>Xm$&-6Ii9($ zs==Gz$QN%W?~v)~cjb~vEa97gJz0s1Jv$wt@<^|G_vP>N6JWxGOV!7Jc>N&Q)>OG@ z-D5uqdaN2xe5SfBAS&8oR<9o0ojJ0T_U>}dYi$jUS#F)NFg+-Abyc3kc%EidJz~ah#mhTQMSk(qr2$0Z_*A={){dN}T2&IrwPAqvq40Hdt0Ong z&FK}gJi}w6D13HxXI*ccT}juGH5XexNP~?jpD`o#@C^A!l5MG_vF5Qbk2)K0*NKj#9^l({1o62pdspdTC@tZ_w~?_ z*L00K+guOyHh+u(iMl*Zq;~Od>K?rV$T$3YQs7};wUf6t_7J9wH-8_xUR-&i0|hyA z1UD;=uo>`bqf_H!7ptC^dTBAqWCX=v9z^LOz%V!jV5TWn`CE#!4 zxgYb)j#+ZsADv|DTBu?K*97@5ho+niqk4okW9Smn499*lG?4{XCX|J@JYD58dQS~$ z=awK}7?RlUKfTW|{9@)wBE@Eq%n~7Nv6;}CL9WatZLjAr@;W`=b2^p6kp=37$Q408 zPTlH8P;g0N?9mI}T%D*ZbX0h^O&`vxTnh&r?YPk+j}#47&pw&3eA;k{IAf(LAwpocJO9)I$n@>A@&Uf7Y0TgMNSm3fmxt!o zxo{U8<#(W9^x!b7w<{N!0l&vfLCo}D#g5((DbDd--%6Ua#ZcbqV&^qstXNrbn~6PI zL)Tw#_Qs975S%CepJ@hXMQqm>L!p<@zu$GGO1$OcZ_LWA2+o%{M8EIOzmf@mE^$vd zz!x&*hhqQU{{K!n{QX-up90v)4pcyADpLutuVeEYqf{gt%%^9@e`97q1k zB-!tT#-FeK+V;FlZvn2Edf%g>|9UAUqeJpH3*fH|1$f6hAcB6+>5TLD5B~GwZsvnP zCS$2U?R}{=lSx_&;S3!@ccaj|DO%XPg63k|G3xt@qmN(xcgu0^*e0h zK$*Y(N6Pvroi~H_aBaiH4ZFdZjc>2 zw$)>PeDD0Wu3=ql9ILtz$ql}OC=1x~VId(T|2c8~J-q?P2t2KZ^lyLDW&gN@fBolI zI&gV4hOgrPd&>Ws*5KEYtp$Q5=f^J6fM3Bhi(SY0-%o`oK#RGxd>6X-za1G9=cWz8 zd2hBqKmMOXFv<%aF44!$|7H^Zdtm?d{f;h!U#aCKlKD3$_&@*NWEeO&j`QAA_}^FE z{mc6i>T(nRf3I_}=NG*9!y;|5{`XbaJ^)k5y8V*!{~o+bLogryAE(Su_-(@fyh$6A z*Pk#Er=+LPsn=6cQ8Dsu*Bn|;*S^50w4ix7IF<(~*LVGnEUm1p?2*%I6Rx$8k+G0m zxW`z>Qq9IHn^kCL?f5c(w}kFoU(asx>H1uJS@`?EP{cMcu+ELsh3#Pdb9N?cV}o8g z(odg0U7V=%j1c1JSq1PLp!d#&an?Tl-Uh6#fToW(H#b+&8C?mRYmKr2I@dkX_98Rp3Jh=5J5 zM#6aPN&?HTNxDG-9+eZkNn7@R-Y4%h;)w4o7p;0fKb=!zL;MUp~gm`0-S(!p0 z%v^!<=v3YXjY*oZe^@Z6yirxxz3R5Vwp$4l0IL|c2C7(U6u9yR06(${HV3-KDbO61 za4b+Ro+-i;_~&gNs6MYMxdXx5(mO#z9$H$iR*6{8R5ExROclNSh7~RfV5goXunFaN zqjNQ9b#yFUoog2H9aUOQYEr_foJ==D35jnBedQg(B^;tOEI6Ci!N9&9=)Nf-#C6}W zy-EM{rVQzo&t&hUgfj=`<6(BNuH(cmm7KBhpNXFmyZe@)dn-E*5cqO7WcPj=@LcEL zwz_ob%{j?z3V3G;>HuU#d?mEurvbW0WVj`WjKgQo_8Sg`^V?Ct2*h;T0=n#NvBOys zs}hfsBU^KBr@Fj=^EUTN9^Nu;ZnCy#1nQ?+*%!Q#pxLoret!NbZtUq3!v}viSIhFa zcmhR@j?#k0OJ6n$U^N^%ZmVUWZ-FL#Bl@(^V>kEQC+ZAPryS;wq<64gY-NI@T9b=oVvVjWoc?! zY?*e4X=gtN>#1X##MbxQ=gwTa%7w(F;aXO~CK+X13yy4VoET-Opg*%5c|Z@^b*D!* zzktUNxHA)Pv-s_$dBFzr!feh?mh+Y!17UOIT8iEUVWMk;YS-()NNgOT>c;8%am0p+ zQ70)xa5f#!lU;p4P|}5o(8(w1KOFH05MvvR$vG?^IUTq(VenAb@j{X-I(rH*z>55~ zAX-BcbKe}@J5?(>KOvn_`Pvknu^dX>{T2Bwy zinqFzQzii?s`|E?3K5%<`h~;uF-)nda%=DGVB3f%I|WoAq3Q+k_00$+M}V?wsq)(0 z^a#z4cyY1J$IPz{^t!nUX3h?8-!)P~YcznJV@cbT0z(p+8?Gc~)aiC!=u&(FNBHMO>WcDi1t4%?W7 zdRJv2Bho~Q7dqk=5^Cx&Rdt4#C%#?o^L#0Fb)M~BTKsHMgC7W!j%QgLv?q=RZ$l?V zVQYj(FKS}zAF4bwL0)wX2WQHWBuO+iw}1@yyt5|m`KTp}VPRL#*%}xA(Jl9;5-t`# z3%}qRtHfsD1^}k~d?SEUg+ERjq5w#Q(O3AXR&#G^`0j+uLIU}g)ebLz ze*HQ?;W-!OU0BbEv%-gsIYKHiYgH{P#DmVD`>&s0eZ_(6FwmCQQr2#UT048?dO@a& zrPby6lXv;)zJf(zMMc1wm-#>zgE-#esIQuU=c1TV$H@MCu`k?IqjqgvhJ)$dPBu1Q zMYPU3F3tA%j8x_xo~(P;;TGIe%gR473+W-ZtZ-T#wpq@vaIMTmI<5`u9#6g@@(1U6 zR}=RsKMGgDavyuYo~`PWy^;KqgHztF=)K$%j>fb6i6btahZyJM%@#Puncbg6LFil3 zCF3M`xnw{=%^tPewHm?WT>#`VNw=3g@5m}ehIf5Kz2`@&>Yr`=vbZn$S#B?MRlM99 zOUcjg5H%rdHY-qb{E<^-e@pKExX(tjU~SJEosM8kJ71SSp!nEJWMDn=`*3tn<5PDI z_1aGwV9r^>u01H%z^c9CmJ8A&l*V-cNQSWM&3v}$+N>QOgVmX znF;mvvBHAM#ZbS-$ZYZZ1ODijzgE92-HTY`XmOZo*!gnl^{;=(xRW;&w$bb_-F64A zk{6AWoq{Yv%O(DfXpx>rGaU&dODK!(Vcbq9-_GiIItPAO;8t%hSH>DwGb z&5K4JP-NvW@MWNv*;mv}a+bB(vgpl~l|+V9ZPhhVprdzP-|@ThI$vns%2NWf^_^~K zPL+g0p~i5O+hR(9#k04U=nq;js&J%Uxt8KcS$P=4X|9#u5W2hL)jg}td}}xdcs?aJ zQ~1NkLkkxII}4vXc+#Gtopj;~+a-TpzZ$F5S8d145T8F=fhNadlh!Y#?ctA~gVhgZ zF}uo#KYY!GAJau6O=7Kb%~e25LHM0Pv4Sk98Jc^fIaX#n3Hi=*?MQV&d|!rw)$MRD z8eSE-U5Z{1(ij+uMe658ly;v6)hIfedQP0~Rh(#))d7N9Q++YR4P+CrmhX2|s zg~37;WzU`UkHy^VxzxoZ5lczT&o2M-X-Z#x$19|vHjv&*Z2X+wc{`51TBVzU2cM8^ z7z*DV7-!BYP=aSKJLWy&H|501wuKK{y?UFY&?CoF(_i(Nj43Dh0C?QD3H+mOafU4S zIuOnbIR0Rc_T@JptSmvh?)_YFPaOF%m~JS(^!a_B+dlb3MJKes1~WFJga5O24G>nY z?T^9qD$zN)?u5|U=l0Cz)K~r1@L%#L6-&RO(-TPmd~NYb=+E1$+xsc@X=}4!SO&r& z%j^*o#fAZjQ?_G{C_lA9m(lU@`EUjyo9=lo560tZin>y(sen}-PCnl~n^#X)0NH|G&KN%ts`I@pKYy(2AuW0xY?(Zq`-%J2tnnU4 zONEZM9F+`P5s;L#x#&6x_c@NUH41%>`z-s6=c|Bf(uIrGy9s>kkN=L5z<98eQ09`@ z-wSxhfSk83yr4doe7@i1H#miQ9_ul5oNYzdtuP$&WP}wr56YfOo^FN*m=_@CpD4ir zHE2Zk%+s#D|H>i1JZjYdjoceH4}bnJ1$m!h)tPb0WcQBJU@6|ZbBm}uS?D$Z>SG@D z2HA$RsEsWT=5M=rlSzZ^QxtIYMlV5eN?dikORYEvYqvW^^V;?(W}HxFahfH=a9!xC z+_zJ3GH4K9h&SBk;@K5W0_Ko;#*#e>MU+j?BZ`2|P8WTkh#c39pE#jIwZnehX*4mo z(*@g)%Kp65UQ!Rdg+@<;>kbH#q#tlBO`GU}cJl706P0Zxlg%@u*~N~LCE;L681JEm zHJTNS1CXERmO}rJ%h@w4uI&LcNDzI5YqV@tg*%|lbPWa^0SNRdZZ*EGbD##AZMDVy^0y@8e_Y%SIDtfCsXuBBkTd^T>&}+(KyXgGxOp z=3h(_ka@6Yf_WSMX8qSiMsb0a?&m@P8qD;6$8X-YIHXeS)tC}V3}2EP#5jiA} zx-kxwx!v1fni$pkv;a?}XD$mxo!J?iO0vcAi_?xQr{~*Tj=Gmug_$Cq-=A%CrD_No6XKASG2m-Y z2XTnW^fy(JuAKskUk#kpGY%&~mZx6e1|N<${zZPSH}k0jIN$p3Z4=cxwz}-D=LyR5u&GL$a6esJaqQ$Kk?yA{8ZO`bf zWIdi@@c8~_%4K{0&~Gcz^Yrlch~1@MVW$Yry8%rBwLb^s0@g0q^?<5qsFUWwPNpQB zX>=gI3PdkwRJDMl;}3j?@^`?G3X%>QS;Ks*&{x#5YDz zV*oc9!s)Cv*q*6H>lgY!Ru!k#0QYa;Hnb)7@stk%w@|O8_Ts04ml_nNBVZxN>Fx0x zHs{1C$IsgC3LaF0Y=IrdL;#OLA$%FjI>#I5*Ht2Mt~lpnj+Mp#2yU+Qr+C#v;n{|e zsRC(T94AoU-Vla?K>zI9LQtrv5bLwg$u=Fa{Pd~77uYe5$ibMytFbyqS^0!2dM zfgH37c!D;A^GwADQYKvi>CnTibURaFl{L|M`Uy10I?8Wiv!C#AWQiB2lUh3%-Pcd| zf4+`SQncNmL9rVBny&k16Zfygfc4p)wE$NG#mTf5QYFRWSdDFmLnd<!_%>9$BOz5Uc)>u4*{5)&X<8-9?0g!V*s6 zw|N~S1s#bMnM%1;asS$jKInM~JGXgW%lc!P0(X~9OX^!<{g@>uh5Tmb(#(jFaaF z8(RDvih zQIF7KcJJu$lX2oEcYhDo4`~d?p2R@ zIdQNk$FUr9jf+KlKf5E!T^#fXfy{}Xe{#U1bQS5iyt3>;WL-uC6_f9SjDnzEA8dbC z=`VFCzQ0dtMirk&DjRpit~k%|HJ@)?$*wqICm?AfevSRtq5SW)+)P*Mfw8Qt?7^a} zB%1CMx>NOTc41R6MF1d^HqbAI`YI&?rA2LW@Vnjp{qUn=cR$Z{R}|M2I5%!FmP+D8 zAuD5%E@YR(2w`QZ^NwIy#1y*Ij|N^&xoyt1W3Pi6nK*Tt@YIRsX37W~C`JPo>Ctj3 zmX@Y2pm|M&T37cxRB~KL-?9UTP}FCn&fMq2h`PP9vnwE=VOdNyLX1Y>_M?m7M@yOc z+vTjKWo3tt20-&++KKS_zOgz_PjJvWAUcy!zmRL6W-4q|wK`Fc9$+0pv9DVUjyA^1 zIs>GMES9ccl~(W4hpt`B`B|NQZ&^t5*M63x?FHFFOL(gO3T}TNY}DA2Hx$RB@kdB& z!^o!R7!rMSpp?sCd)iS_8)<3F&P;r9*L`3H|0T!?uF~aD8bM_`p<=|C9EqyEkO4*BXs@7Hp2VB&J=in&5_9=7DabgV|cN=@Fq#Bd;` zQEC#YXnyzp{gtsQ$zEy+4LQn; z+ig5`#I?Km)-JeKugohAIbGL|L2yN=cTi7Jk1KhQlDzOhTid*HF*W#D+H#YUT92*) z7@}Vt^hVdNP^59}xd=9|xm@|R24Z1fapst0Qo{Pj8W`?{CFs~=W(C2?#=p3$>^`Q~ zo*JPr;^fp>tYouOB;d)3lYpKaC^zKFd2n&Y2PfR6Vo77UIXv6KGE*4p$eFG&jih(W zJ3y)igjK~L`x*00sYusy%ponsfcQ#ayv{A+&f_pjEeowie}vYZ4%l??LolS2!;1Fy z!HP}EN)UTIbLtRaduJSVTdx_%%Rht#4L`M zwWjXk*1#{$;EPMIvEXf&-3ehNSbKQBD6l0+rPkD>Rn}d32DxX!vb9i($|dVZj&5daP&lfqi4*MgxP@4~#Th2u z&bC5XBEg#X%gH>Ik}P{yq#^g@88xA*p>(uS*T7WsXHYQQ6~ zIpZ%9NQJP;KH2^j?%}~dn%|q4X`t~~CRj7f8Ip&g~%T=VXWNt^?R`Rv*ILR_vQ9gsft*rdj z4pn{AyI(1pX*oyoBNQj8cf~mQ1b*5A>A)6vm_U=AZHl*#C-*_GS@{?#15UPn z9LP!21RH{fEe|=8ms$!p)?0iOu-{=@tv>(s|BNx|$XZ3Q_OEaMbA|_qP(_CpKv}j_ zGcqC@aW)2rQWD>dG3{X!HS(i!`r9P|>@F{0pq9ER319rXtzR9wk6*vVjb#2NP!g4t_(DRDx^7JQPz0AE$_i15^tzx3_jJxEdl`*h*kP3P#pe)hXB|Nrp+AFjR> zVv98Nuf+>cgS=PEdam%5Q|+#4liaa@d5V@PClgD{%pFL^1K{BH1QL}k38VkL2w-Jz zu=0qBEsCmtpc_r7tSM#%!kBcO00fDF|E}*A+8k$Zn5+5wyRnoGfFdTp1z3}tJmj29 zmgaWod+!tE(XMz6Xe-u-fJcuFe7XEKo7Rt$?C13zkc#iJ%vd@`{i^{LB|Mf6jtq(2 zqxSf3*#WOiXO{XPN+2e1>tBTv??f9rkX|L9t?;8``O~{o3eup<5O-UEe>n2r-@QNe zN*(m_-OeK2(U%^PzUeZrdqg8$w;GYK{zi|KoYmJDi`r$71wfM+aiSlwkX1_&2Bj$8#xRU`l+>>a0EL z7d$f80qm#9SCsG~760qG6NG%_je4Tb-xk-Ox2cmekHzCN#{K*0aSVTo65Is;mjV#5 zMs%8tECkeeE22!=w?4f3>vd90K$~o=evoIv9t^GEn5@Lj$b5UWn)zce#;jb~C)zpQ3^G2&Y zG>{Ur0LYc~bV@QmFEN$v=RrW6BQJM|5=5=+>PY09x`PqQ{2%dh$hHP02kUzK4)k<& zBW&F^4hCuu-AB9k!zI$KMX|%{xHK8An-PeY{BrWmAojaZ1n!!tQ!XxFR{Kb5(w|ZH zGwNX+bt)WJGYxiVQ)_&*q9y$T>K>&D<_``IhSBf#i?34P){Ft)Wko6EqUoPK&#YpB zkHIh`mzN6y?Nbu_LEtSNLD4xRT>DIN%ZRw1yvSwjAMxwzG8^6Xe=?AB4xV1Q)}AR_wxcx z$z5nPMqPsKea&pjJz0yHVSu2ISXpT#3$CxPcbw14fJG@ww9nrLwK@d6+#az+ttuH3 z6hK@-dWOu9eL}7zIWUAPae>#Mf#R9|eVXs?x`&`v$!S0WQxsB8W8hNgH(KtHAA*E< z1P2FmeKVx$5L<^*^9cq4C~y$)qVy$aWDJqaFIv@)UsO@W_q=g;dNu1WLR>fD?)!!dNc=DwH&`GcmP%h4jmXWlW1MfwXGNn!8h18Bi1Un8*(d?dg`ZuD z&_OXlixl$bU<~*QVe0`qsU%|flZ0XesI294HwZXzS@k{V7Py$LNO0s;4(^TNy|+X~ zEg>PcTIf7k>Mx`N8xWgDDs6qc3zh}k72D%G3!|0`?GV;@m%G3pZX-jv#u%R>jWem6 zR5G(~g%{1osYpKxDfQMxmtR{DuC*OuU` zM!wscBdu_9ESSHouKUSdB!bngqR%=dcHcP;Jk)k~TYGusp7?P0qmr^RU5uco|NF#i zmEW!}a7Z-ErhHAnlLH%U^#os414!S-D874EhgV`;f04|id42+A3Tg(G%$e`_w8eC9 zB@4!GEe64y9^-{b2JhH^`&e%f~iJ? zt3f)RBNjcn&OL6a)OmrdTv;5NODGKrENsnP1mbped4z%U=2M$-QT$V{l%$+3;mES8 z-6XeBo4Zs#v{H3-u(u|0U$59XoaI`Pa?cqZudOv)SP?fy@39~Dd{{z@&JJFC)>Z>{ z>~VaBZl2>Ui}*)GOP4}r7U8y>0MG$gkIdvqF?gfEi`y`Op5Fe{14@I;Nk5h7$RUPX z4HEb$h`jymF#}I`Q5h@pJFH#lH;wdo8(${rGHcwAfPQ}As135;>+_qw);d+rmZgXG z141k4XxYI2`NZSe&flzkax>;=fb)tM4jp~5a;wyaHWV{dem|Gc4xK65zcpb{4SZ__ zW9D_r<;GR({-Er^fJ{oG?-vlRO1g!$sjjVMgbP}zD~j2vYj12<*ZuHzwXr6#>#Ai1 z`CLr;JbL?U4^Qj+2hV3Go?qfrPl78SpQSkNNz%2vr4u%CRTpHf)o3kl^p&mlGTB^Z z#A#6J7kReeC=EGty(5A|o_QaS;5?!rI$f;`7R=WkFx{w`l=56F67HpBa+iLEM!*;l$-j=V^zRs@Uu2miZG+`$#r33J)CIT)f9dRuCE8e8$wiN$ z!pFzwpklf~(=s(u)h5)s^#sOKvZ@K zkbHtmU>i4p^L9GEDAq=sMs}#^VH80Q9oOv`CXjqbFwXfd&6X;h%jodwaAAVND={p#&zmy#+B8c z`|vTr1W6r!kZy*w_U+AhJ3FsCA31mN5l|Q6R(jNxcL=8V>hha0 z6#6b!wgQCq=?zz{*fc1>0rE;&D*plriItytm)*Y70tqv8i)nZ8tbx8FQuylqqN}$3 zE7^V!M)Xg46712bbRa^kG(=1}(tA~s_6Jn)jUuq8=S zyA+bv3@OYspIFuTW%8QeHtw&wPZfMq(T0dvwut(v?Zz>_x1V*N6tzzyY_VhNNUltE zZG+nQ_;`W+1}!qZDg>fhPswlH5^+KimE_@0HE2JOVqax?sD3NpSrf1un)%xwZxw<{ z*JL&T2WH1m>Q$qsy?{#sZPZb`lI-CpACaM=MPr84I76$96t`pozBw5qRJF%C%fiWs zB^06L$FFJ4W3Y99$f4Z?8{kW>&;rwRH} zbL*Qq^tgPdyLIXK*b6%LF;tvHl`Ez|(7Wgo)3gO{LgavwXz?m8{sK=eQ0~9W@AEG@g#-BN>+YYg{X{PdNp9dOE+ z2SLxn{J94k(^0-g#9Rm?2i-X@KfnCk>szmgclP`Gy8FUpQk|G^+RF`~-rtz~VhG&A z%sY*bNk>xZbezu5U2<-p8=CQ4@i?Tr0pCo+a>gt4YoBVpd9nYnv*o(2C{vN2lWcu$aG=k+uDRLF;%^W@ zCOH@|MEK0BUuzGBEyYjtvEJU4;|wh_wClNoXA2#ysaycJJELq6j$tAo{!j4j7Zs>1ou4S@)xB;=Pcd!=C=<>a3bdo z-nJU9^CL#}Yv$KZPzLHY+FO>rLBBak?5ciecVMY>OwA;J$)?BWN-TLtEL4_7lz!)i ztjPx%bjkj(WvLkk?!ZH{gOT{`5f%|mb^1zfzXrz?-n2`IkB5u&E+A%EyM|6^tDV3A z?OYQTzpOgz>aBmr>*bZG?m{YE2gDLxnHy1x^8*J`h0nr;qoFQPiMJb~Nu#hVv1`qu z*RCfljpCuiD4;WahIdm}PkYb<**FJGY*DqK#G~_Vtbhlr$_>xzGMBb*6LCk~5QVcd zP(%5G%FKz&48ydznpf=yc?sjj0_TUr>5Qq$HguD!b{$#h7e9Mcyi-b-;fOjVe!TLL ztf5`L6g)Y(9=|g6Le|o?PbpHjO&9LrX|qHT4cNLiB&U>VN2B`tXQ4BMdTE*Bd3r3B z?<%K@40oSj!645&Wx0ma#FNEGv0X;_-g~4^E0}FGbF(>pvTaAW+mzydgg7gSt1q8s zXhLpUmVs$AiwLVHkS9kt$WH-c`_P1>lt>iYI1ji?sy!c^R>8*`ps`DF9c^Q;m| z;@TT&qo!PG*`j{77|}evEsCt6uy0IYHIq)@hi+{}eBIkrd;H-1*#J*~zB~=km-+jv z@8BV_)8~H9R8rfC!K=e|4n-@9&P%$O&oct|D~7%yFVW9-!t8fx3#bQeLl0gR4tI(K zQ5ZHZzA>{b${QC4h_^vOCrtIV;%;mff7WG?MXHjX|$4+4MlTn|F3*?;0kVGHf2DO}_$PIymq>Tt0=C97&_9aXi$!`(O_N&IQ?tX7UY|_6hpTAaSPk`8AP}$ctPq)Xguf3^kFhGe53F&B{ z2V-%8O19U>7^>4=KGZ*Q=m6x+8NFfx`21H*n*59JqY%0c!@a=;`zivqCH_#qNa$JJ zrtFo>S7B?M2K{!f_e64{ht9oew>q7x*t*iNB{6hZ0Hw(gTf}ry=E+K@;9rC$b0n$i zP=q+8<>;9huZSN` zASRP~#_xSsreB+{e1C0wE<9qj;p>ae*G{P187uwrJ<1JWr{cUCNr6AyN&)!zJE<_z z5qzFuz)1Y#Y<)w_F%f06LYn0r@$Cu(H=7aX7HVF_hxNc??})!Bbsf!~CwSUu195f{Tm#ZgbivJk={c?{(ii>ZcE} z?`3j-mNsv1`Gh-D;KjCQZ_(TBXBI_+kvj>>h^@3d3YOBs~w%^eN> z-X0{R!By_2UpL>qF64Q`c%tt3su1uv;S3URD^Q7-9dXPiMVz4J8q@UVg$tjbE)xuH z&NX%IpDxJtSKx*`;tKI{vPpD1-|676@|?}i`6OqeI{H!cIX6A6wk&m(G#=GtElPU^ zy%!%j{ z8LVg%DG1UP6=9vB^S#2H7KFCR2uV$sqRq;oUo42jt~(O0Q!j(HJXwjjgPW?8akPH55f%1bLl8Cyu#%vk(uWr z0)3aoi1g^%&isg&ET~rLbGdR}9asfDdAOKQf?mYwBi*;6>M|pI8Z>?1ZLuuyd}5fJ zt{V?YAUiD@Avx)M!b>6c?Q4#HHA`(PyceW;cyAgwVS3wP)|$^Vn>l$;Xc|1yesqy{ z^{`rlSt~SPw{Yfiyx-lu?bIX<2Um@GXLbqJOQLt7wQHRNyo6eKlC#2jI}n1j9q}iD zJrK6d=(8H-wJzN^f5<#NKECa(9p2>g* zOqHZ^HJXL)(y$x`BeWTQ%cMLzS{(AEy~e~OY-Wvnw{Lcomc$U#P)X@s}aGmjm1{`OOaR=E#4@ER(S36iLO z^&tR3p)zURJALEf51jIkV=%e`m?0nA`;YiL!2Y@;HNFIN0-YOm?3Y=2Ll*d6*Yo_+ z&81Ml>#l{#N_G6*FhGMD8S@BIavR*>+*?J3El$|osXFVk$wVRlTc7{(9=u4wy7=0W zUy%#ReON;~Hocs7Y_uwtjU%XT-17VFP(OzM2^bF44xeIwy&89kshkbCsWQoZgYVUe zx6;3qohD#a+3cNgc0c;f->+s?sRENx>SZr{{piboUjyWskAR9yD_Kv^c=VwBV~hNo z$p4vEyc5>?Adu6f%oFk>LFUhUe|;+D1c9QenKze?#-si;5I{=jK9Vq zg#k0(yHq*V@@pmk{1*2q>HmYnPqIGoGV~^@=Wg<^p-NrBB_4boNcw{=00CqL=6Ho5 z8rQ9mT|*H{&y&IU!VdA`ctXFly67S)&$dfEKed~mP4V0baN!8rHCozwUT(odbN2rz zQ#|eXv9Tr&$}Ec#?}+AJeX9Cag}nO3@n>@?3pnZV4HlL-B0U`XQWqS)ig^5kjQO!H zEZiUHt0@FciI04ZJkv2?9FiZo_G{$=<^U=-p8HPIpDic_!qiTU)QMX2`VfInfp_U> zvpb%+>6B?!D3mR=+6zYAgjx6az?KqQ5lutd$vfG}_6*v|Mu9TTHxlq7aW?lRxDWNN zS;S7>{AJ$(v+pTBwbk~inn2m)(qtLd&!uPe=+u(0QD}Q@BsmLLJ<&@$iPSQ`9<$NK zBiW)>BP%N_PnLr3z`!5xE|hC3itw3Yc-PT-+YbeI)@X$`mxkwvQ%5jG`sI}@H#Rm) zUNg&ESIr7j*raWI3}*k8Y?6}^!{_AszmMG{|K_weqgSFr3-U!N5axn9aR&98pFJ}~ z4&S(@HwKK@s+C>fq|s?O#g(woK;vfOq(YqOlAiCmS2Kg1ZLZKwk4vJYJjbZ8Fo5$Y8e> z=b4obSYM$yTmf zYmy5H3E?>1n)OO;BjIHVES}s`G|A4_`Cb(}t9g_zyqm2&D>=Hp&@23PKRleI8P>bK z@Oq(aUM-1xbnjN@>wtjzr+W-4@oR6YY;kfG-~{5IZ)D?rj>Ioj9^yls2%Tkn)2JKj zNA!jI-x66|vnfth${bAoHSlpk>MzUk@dHa4Mr z2+&nssUF;~do*%M75m8V(4QbHoT`r@6G0XI8G1cF3{tX5pZ)Q3ZvLb&E7dbgjuU1|SBmw0$^Q2TW4s#yyF;DEb?-794A zMyZ!O{ds&8JGtLSixNo|_-d@?*YS4!s$(#0=}Jltyg?yTjVVD+4^?>)DA z@kFDEJM9)WxlK1Qu0x%HTAeLd5=PbioY}u{%HMv^15cKg){F{?H6?WFK9kw;PEj)X zxi(W_-*sdu+@8P|QdYutEL?m);?4m@NVNznq{AiH;-G(H^-zwCjH-8YYwMX8ALRWe zRY=;P@$`a(r&5W7_}eD0NtuPY>Q+6Y)$38E3u0jG=w9cn=;!(imQ_x@40RWhm*?Lw z<}L`iPJv(&vx+q?+qHSsZ}pXD{xbl4OohxwX7~1L9R}Kn9Oy7Y<;8y8@~0GJqz3fj zU-l)!Ga=+6Y^jDI8vz2j; z3j%M7JvsJ0J1|7AyvOlI4?#O#>ql8c*(Unx$#Uj0tl$9)CkcE9d8O%e&JbzP+S6`7K=&Zi{VEi$lYs$$ddxzXHHDgJDvqZISGqh)q?w(hF)5F35D{Q_TdO?XuaVzi z75_Fyh}F|Kj8%m7Jlw~r^9qW#kIRc|duDh!I^A#L(G)!YyBqUCO>~PrpVpoz`Qg(1 zu33jc;cocCo65)N)*ge!S{*X5DWabM#r9^24o$#$;EN-1S?M^&SM>{X#7@MfZ&m1D zK7g=5DcY#27Yz6LMm!!psW_Rmk#!+F#sN8$t+om%nYOH?K%q~KA z_r;H#0G!s5Nf%(*5Q`AjC;bbqlzvZ2I(xbr^=T578>iJ`GoII6ov@+QmjH=O6>Q?_ z+pP5Ecgqv;`mIL=cmjB4ZuyOl)g!kaP|(^mogsRum1omET!R0o(dX_Zm1v(iXVWPb z{I?GHds8y=Tmi~G`)VQYzw7qQDiYxN8X#0ZsH4Wx|k0`*UQ!qoIXo+o*O=Tm@& z?B@jjdGkM?KD@%ApguM?{l{~uZQKP3DA0}?tbg>lV*%_yFIEbT4F9j^YvB1CkjVA# z(U)WR>Nt(_EEC<)=TcVzdYV2sBxI6lzsi@6){l$yZO13n?-C z42usR2~vP5R*;gyv*&mX!C<%mUj_erB*}#sg&=)Jxie!JcrQZL20NeBIKZ$;!njA0*+OQ6=rQ*mL6Ker?U)(v=@ zPJy+*_*{n|AO=9e;_ujP{c@D5QvpbiFTh$wKJ+VPw(dp0o44ii4en#)(g1`?c=Mrm&BzA~?9(U22s+ zzl-`%6lxq~-H>I(mkHz;`aDLzE%C6&GOWuzH)MkBcSO4S@yh4+m0Y=pusv|BNym6% z>KY?_Qs=)vO6e;(@U2OQ4%+B8WMs2z46P11k>Lcr1_$=aXH7j~#H%3jA*#B%v9chs z0Kh-O6w9A)Mhs4nikQ%_&~AK?LyBgm3dV`ohH2y75fD8GkSwQ(J@Si5$7{yx37Jm! z8G0FfkCNQJi7U`8zPC3cNvx>Ye(+*efyE}ku}wBn-@c`eH40)B%yo`&3wp}nsi(+Np z1aNz&TRkXwuf~3e?%Vfd=rT>^@~kc`9Wd-0T;x}DU{T!TS6qME886z0@WV1>nUw55 z!T}vsAb29~_mbP9PbsMSla8?C7YYAdw^s^M(qG;Q7mMqoOKq@0*wjb^&LGuuU;FwN z0vwW8G?T;gln!w$0FM(oRzQ*>EYfdJS-heWQ|3nk;8#xWeN`h=fI9?IiZt(cv!+h(A!}CTvv9(w?3^bY5 zdo|3D2A9m`xQXf;+#oa?^1fa==L?3sGEaa>#7I*Hj;>q=<8f|xUD0wN`oR0EQL}r}l zWAae$oXxj_Ma1ml47jX{&6M&lZb@qv>y4_Z_bMIlV9eO;`(0}*cFc$ z^mTPv#&M{K`#y6KIiKJ$9pebd3W7%uFmXA~*iNzP?W($6KSmzEdG*9C|L-f~jpJ*d zjh6Y*Udx@0LnB*y;{k+>r+^DEQh5rDY?(+|eA5L~@zWNkXM}4(3Cl|OsB$cFFz(>I zm80pZM$A{B;zTE}HA-ZFwUMA59I}9o?$%(3dWgbm;8^9ujZU#3O}FLU(L=%m(Zl#< zZ`SH%pE`@=<=24UF`7!na67{Z$9?exrGfj_r<2Ai;G zGYCB4M#z-Pdg8kDaMfdExXqys0`~FOFC0HICn`qx5SdhBaz*ZzCkV6DEK0ezNJ`>L z$6d@Q5x|IsDt0>BxdY0U>Zs+&gV{#v?^j6<7yR~b0X}1|?+bMYlGKZ};$nL%jRMe{ zUY7RuTagbJ)K!bkOLuP#rZ9VK)XbgX|31inm*tFZq&RovMU_tc*fr)juBB3$_yPli zuv~SlxXGudQzocv&2g{M-MsczuUP0r0?ktGZr%z=r3(Qi?j(mD8|fNl$;2r~R)QDy z8!Q2g@0s6qDfLS4^|;XjK^t8$omwEig~Ch{9Qho93|iWAWk5?h6l z_bb+Y60J?P*QR`VQ$dQO7+@@y1o$fU>LsX!2Tg*tdP|BGv&+!IVd7G^`)Ug^L82JB$KO9)K|pe@k0xu1JLJ=}|FzySmyq z%dgm+DeU*3&WkjBh$7Gsd=iE<=4Wq(KNY8kBG_+t!(O`7^M?!eri?uVWdRv`KprO& z|CO=i@@X8r)F23>P{sDOx4?7Lx~@W1S-HHk6;wO5UOqrh#?B{4FBzbc3Zbg3z;75W zfwyl+RW-~1aD7^FoataZthN>47OU?af`S2Cx-T|7T>LiSgtkkV&wHDb9|8iC>-@S# zzgJF14A~`&@Q=SzS6W@s4zOp5DirkENRKomgk19^nO|OBw?A}2m^9GbLE7j#JEszU z{ZyS!mG{^S=wty|IQ^_WGWUpnmdS}naHXaOO&!d=A$%PrE!wR#($OKzSiONIdv?D1 zV?kph5m^w`N02Jv2y!%G#hns;(^LCFMm?FSsh9SEKo=V+U{;%%%IE0wimm7*Y~uan z8Bf#1P6{%5eZz(Zsa`6d0t#z%tdvN6Q9g` zx$hT!Ot-IS6!9nzTK1la^9?8k^dhnXw;II~ov|z9vRl(i^QDf0p6li%Z5y%af+5u0 zJvO>kJ{)5of((%xvB|{B+4tOylPda3x~<25V7iL%+2c&-Z$zP^F~IlChriR3IzkjN z?ZnY8agGXD0zZ_D=o~2lQ8T6hrCs@~swy(CW<6e}dPZ7W(%f7w>h~`9L(q(57R{qd zNG>xRtURzm4<<=Sx=41dZqG@`W%jw-%E3yATL^Sv3ESlkQ0>z3wSbKXz?#)^Py0ZBdL#XUobj7q$_$=L40$;X|6vjT zm^`~*OzsM%IvBLE}C{0XEEQ@js_^Rn8WzgEGo*BXLXr@*X+>lBqJ9x z>^873C4A9ezb-O-0N8NGC63c-Z}Yi}(s{JC%larux~Z1J2Kv6E3V{0eN+}8GmV`|7 z^z?;MCS*!+ae8}hM(Cozz~f~RkM$IHznax8gm1;Z+!PGhpiL%bu@?5dTIcmqQr$=K z^G@8|Pc`Y`{rr+RV+)DPcOiLlI^cr~aPcT*u$cZ-Wu)d#^i&FPUNszk=)AV2ONcfk z_S)t0E^WDze_u&b?|1^NFt@j|>O*4;pvv;#(f79NW{r!$d=THU%E$zTLzOnMuVk3e z`9qhOuKCvGfMl>6?Bx4P^Zegtmz@s|A`L$(I84(UupY!~kI{`vj_7Pp%9V%s494W; zJupO`9eI^XTs_y$;`4wR@-C9;wHNMcjlt!15Ix)q_;BLHM#w3KYKmi~nm>h)EzW<9 zs{Q`JfNv}i2oo^MJAm?Cjg*Xo-Tt-(#_LYdq+Ft}PI-Joq*r~nFmgS@=7v^_)p_T?S}xRQtu*@d`v&lR`_A5_!Jp&+-*6lY&aB~@0o z8X-4Yk1L+J0klZ~XQ-)NjcvLCLUwJ}fGg#|S&HBk{UxanUZ)8qe_obSuTRa&+@9}6 z=~wQwIB}$frIPFpSI1tv5!JfmLZs;=^a{)_l$*RReQv@g^hCZD^uT3ol*L3zr-2I=e z4W@~mn4ZM>4xsdDJqA=jS3E;xn=gb77#B~;3l;``piqv!=^sNFSdSX1z!u?8;J5y- zlq&^)|F;=NU<^Iv1L1`%^mq`XTrq81l@2bej49 zION;1M_vV5c_m})?p{IJcpaCq$uo%$4DlvxD=AL4AAlff*y{)4N4vo$!+hpt>&@Gj zUvAxERy%PH4zyFMQ?n!h7MBci@-zrgY8OGsKMrR?#y^Sx*4}R!czNowj7WT0{wsoN zh+8QI{>V#}8*HEh(%`g1k3auR5@IW0Gg|yGGr$0MxWK^MiK`s{f}&8eCrOnT7V^GV zd(>x7x%l;i-eqR^1%Ihe#HYy?qKN88KG2p47QMU>b!R|3IAY|fq%-9cDIX9N>23Cy zW;?PLY@t#duge_E>l@K87^)QN_0Bq-ymc&~2*Nh2*uP-dV2C|yVr<-%Vb5lBXAwYv z<_($eWATq2UG5L>PpD;SSlVmN*teBghy>rcP;>?eY?eR%hzr=!MIYW;rrlM(`0$d- z4g6{d>Pyx)sb5n8CMEh#z)ed_%gg=IcbsrO1S-}f!HNy`lRq#C|B@!BktHP?$er2b zr=&4Ahm(wGV8k=ZC7MMyNuS51wM6?L^LwFqEKKvrD5a$E=SNUeV$p8`W^m4$q`n51 z*n9M=3Se>n#R;VH8Xr-hay`q#?H}jb4~XIuozRoCB*esZ1*UD<}Sg@J0hs; zjUH71V0d+#IYvRZ<#Pt@-H)F^9vV*saB>Psi9I_isPY8Bft2f|ElFWUuQ`s(t7OJA zr14+`GW7d+{3Gm{4+4UGC@Y_S&Ts)jWIRZ)krI8%lj0f9gBWcE6yg|a3%~zu52>i* zdm_UGYpv&BIq{s*czrC&LK8KYqVro0aS{n!aPvyf=qOXAY&>-*99KbEUm}pgvbqWwK&hrXjmUw=su3`&(H0HVKZU4jE`#ar6Ogm5uOcYn1u_3qlC_#liP|4*B>av#ahy z-Pm{|!t#H_ESeFl!`ve?%A?(sN@5|Pv@9zt3(|xuoyK77On|eow^GzNU~v!V8aeH1slU^wsXjFrx>gwtZaq(a_ngI{Q+3PWQ zL(O@P-&drG-HJz0@CXxvHd=Ws`)$QEm(e8gky-UCH{(n0zzYYqM9uiOcE4{Qvb{&S z0`G?}c5Eyu5-z0`In^gABs8}BlnLqEQ!gge?@-E8^M#-uOLz+`{ttsNp*A84N{z&r4s$II2Czt$&A z@qSWX?`r{=Y#8yzhD%6$oY5xxX{|i5dKnZ;6?$ReejOZoXip4q{w2IhB?Tn|P4tj3 zn*0Lp5k}%jnjkQ5jw@paU8vG8TfCw!Zdi8`z&BUIEWkhwiaT9cF^S_&ZfqO}HL*M^ z#4I}W$=u6r2PpZ_fzz!hK!R49t5et}Gj`wC$j{HO%M+-`Sf8s#c{_TgWqpMn>nDdC z%Ebkm%aEq+uBRdH6ow9B_S$_f3oN@ItW%Lx+3*1+)liehv7a9wA#Qm0d7rVSgs*{`VW330vhUkcjm=E+5iW!5= zQ@ShS^A5N!cSIm>k#ll-Gf9LMpr~4@J$mo(n_^Jfy|*DS;wsx`jER!k^^Yj$1$0A- z=9j&54`j6tWyqk&xmN^zpM4-iu&Vj7aQp|*CDL6xhANRjV2)Zdv;>x+i3}4Fi9aI= zY^6B-FSR*H4F9v@Qc2kaFR9<9i;bZ+h`L{{a1ZS7lJ!T*GCt!7((Fe(nmlP_gqI_O zc5gcgONL0H2H<%^nd<^p2Gydr_M;D}pP6G;F^r5uS1YKOYRg!6^OCfYQj0?w$Al~{ zU@rQp1grx-HJ_Y_hyj6K*EovuzAe#C(MMDWYu!^^^E;a2gT8=ZMS?1*7uC?Xio826FY=)-1+ky@b@Qmc0S2$jEkZDtWo0q_(*46b@1!FNo zlhQ>97;>)Sz*kfY-Jv6do-k;J*q4Umn?SG0uM=`sgim8M#k(oVV-E#Q)n#q59|TFW zHidARi#Tb;T~V*EPX2v5^IzaubnfBSrEI?e=hh~uT%U2<_AUdo%&S)56uwYr9LxPN zT}nfplkHrGnG<6Q$1$$zZ*CQG$#aDZw`io0TdM?}YfO)}bY#WAc!Sb)EHzu4R>2`)m(VdJf6 zP-r(qt(X6)S&|liM*H)xqs9mvH9Lyu|4x+2JdX!m%0@!5OAM}srLgh$QN5ltdEAfF z?X?tNBz0&(bGh{^gx)!|&5e}8pSvN`Nf=MUy|fGpS5tf3Gltg zTznL_&)ZG{sB5G}F>Ra0oE_N0H`d}OHa86dB(#BeqUm2h5pmmQN!t1H!nV4nIl6~RdEe3VpTN# z;MTQhkW;)3>*OQLmr-l)hRYd1D}igLQPxDUJ&9RE{p##RtH#FePLT0O{cNeY5M>v4 z3Zy!hPXlQ5%BW+Vs_o_X^tKX() zN4IAVZm$pR&6b1CSSuN!vW8+M9ymI7F{y_XE%m*tm6a9tQ$XHjyWD$g7?e1(!Db!o zAJpXM4>79S5gpz)sqogBmzQ!7F)QwNxqxWL0h+$Nmui@%eR|Mm&w_2M1^Y__Z@(}n z?D}k^yieh8z47(sq&m%w?%k#)IpT)z%At2f1aGK@A*DH3KmADd*-7l=DG!6;E@$T0 zj>*}*uh2(h^p}D18U)miTklRjl^VyntXn^-or zqswpn!4wJZXQQ$H`!gAS-f~9}Y~b{wJU1|>6Ghl6jcflFWS0L?f5rlv)A1j~9_fl; zrwy{5Kf*l|Fi7)cS_Vb`zSJ*={sNF)Na08h#%2zO@_N5|*H#HdLMe^X!?A5u1c zkgBWc{sd$75W(s31Yf7n;$DA+DXpnguzBg$U05*k=XcYxH&rrm2074X4R^syyHp}7 z-B>R-xBUnX0Y7)<4_g%U{l}pKy_n=E2r@fcc)#H}h{Th&nq9wqHdN%y7!L@Z8lK=| zkmVB(pJvuB5WQKUca1f1@@7&4xY{`PPN*J5=f37nnxjogk~MMYXh6S*RjYou*QGaS z5xE1lsu*6)i`R!DH2YunCMPR#zPc}<0LSu|`#+dvew|#_y3C~FXG1S6%%YONe$qp- zz6+F1$~%!Fr7e98cL%9h0dK==SGmj|oZ|od3aq9Ot^e~NjqNNP5$ z=#SC;+aChpDk4sDJW5=1^lK_4;5{hEHj=`#q>M_3t0sa?Y4Lo7F z|M+TtP4dz9{iX1L5aYA`&H?)CAy^fSKyXa(zq?|6bnhMQ0R&jw)KcTzM>fIHz9i9t z0m8?xs$TkMh5u*!%qqaeQGN{K_V*$2=W8h307)!DY5&q){`3IkF`cL;P^tJ^d;g== z0gOBTh_%qY9)K+P)9R5=lwgLq072!Ee*xJR|3Tz}3!%DrrF`z{as;>n3bgI;CVzTU z!eWXYtFu@XdQ@j9Dg_!Xk|y_6_~f|X#=Y5*8~ix_ zy=8YY5h|8FS%T~hu5=d7pww+PUHd0VIzWdRBqMIbd?&=E@jg7o$H(`bDdF{3JC*Ys z8h=0ED!@T!Z?`97#ZU*N$|^_i6XzP{D4m22#^}LD>9w%2%gWg)Ew*xdbrJ9iWH-djf>-& z6~6`;HiAW$zL&vDk5em@g#iB6p$&XtGI>Hm!u^)gyrt#2xh;%{h`F9+Oo_@3i}+%@ zt$vxrm&Tn51_uTKSu%j8(u2Byv|qXOddG3#JQ{L!6RxKYGx-S;W=MM2dte-K~DSQBf<%EN(9TAR=B!aps1NL|i zdx*R`#U)plkPG>B7p@v0hL4W~2eXhpa;`KX<`uPz6C5ln_KwpwLX!iI5XQu&@j)90 z$GYk1^n!<7S!C z1o$Um(9@DO0UN?5?Xgi@w&II;4!{on-W|EL#-qznGT&=ZVEn>u8O;CAcggKLiLh$A zY6*t**V={)(nYlVALBNzFc}~E7_**HPrD3soI1F73xLm|&Kz#zQ z{qNq#e%W7V@xRoI67l^HaRg9chEg0wLq{LruNY`(maalONH04y0IO?G~TqfnA>3*8dDdhbR5 zqj%1yLwy#F15H5%>#N7{O{s~vsF_P5p7VWu@`5kc$7tEtt94yW)4>foT8rI!we+PY zew+FWCcAv3JbMR;dfBmDyZ$P%Il}8(%Nerh_73x7qmP==5>?n2@{BJ{n7+1&85E8F-Wm8g633d@(r|KJz{)Tu1@=r9`cUzz?~Ke$iE(!@G#FCnX~T!wcY!Cy6mye@Q}pPVdS7+Go9~gWbCP8_|BV($M6tG#^7$ z!Jdc5CdzInA-DQwx#3AXhwoS2e>jqbpx_=>7c@O_^kiXnR60d3=B{G#X3N9Urqq~A zrDkieyd^|p!-PbGkpFV7XTPwp)ou#Zruck0_0vJbYpH_4($ZLQ7X_D^%qe0yu}pNe zN3qyi%kiC+!WzTAEzqBZczFr0rHdL!&iH>3_BN<^NEw|Nljn5-Onx zsgP`yExVGGwUm9&G8kKyv2O{LEM=JxLdY`4HZzv7rL5VP!7#{fjIl4n@V(D@pZBTW z$LAmTK8~O6`^G(UUDxY+UC-C{d}(TyJAZx)o-KypCB?-HcPr88=kYI!42t7hcOwmqDkNn(m{J9}--qeRA`nv?vg) zO-|#>lX9Sm=Hvw(^}2;LscPRwoH@l}iba})Q`HZ2c7P^)yrLuXE$IIgnBd1uAE}AC z-rc{4sBZBcE682~QjHcx^_*+T!f9ECf(d1^^+r~Jsy4hd@nYcR=(S`C$9JC9_)*j3 z0aaf8a=VF7{jL79GGqDE#~ExZp0~+<7KG-@gEx>^TsFcVLn<&${*&X|Rw|^ete^o= zdBDS{4l8?3mC8~$yg0_h7q)?xnUt>55vnTE1fddSWdTV=$SXsi?Zwra1C3 zixn~_IDUCJ=i?+@K!8j_ynoT8vf8>mL1K4+go9uSt3V=95mbkkEcl{*)=|Rk?Dg3- z2+-8tZDVp{W5YMnj4p>&#I&HkJU(k~RS{#eRcKaQA6@N%XGz&WYjMp%k`)S;04DNP z>2JEuw<;xMqN|-{^xQ{hztVq8{u9I90#od0=kB_J2#X&82l?=c!N6PC0@~d_3yc0T zwd>|j6$N$Q=>!rnTf4eqpt42pjsiS)aX_yG6}HcuYyK=&hEgv8pN-Jlq9HZLLCP+N z?1k6NZ5y=)Zl;YE4h~Nmu&f@)C3(i1Ks)0sOH$cXJp-c$tP#F}GN_WcjA<1@Zw?F8 zINi=`=S2D-0Fv46n=}#lEM}y0V7nTZ{y6&SH&y@TAy;_rZu4cv-Hjngh4H|35)Zuw znDYn`i&EkGfmEaHTZZbov8ih9giJ0@*Z_X1P0RPe$m(V9_3Qy^I$QOoB~|F+>Y_m6E{@28{%*q3Qom(9ncFJ;tkU|v{V*TVqBP#SsBX{( zZI~EhTRpYwaPtLK2FteL{4tsA_?JbFbgu!dRekKs;NVMVl_uo*(jS=q(NUOxc(q^1 z1`5J%nZ>ba=<7ogd%v`DWN^mlB)!mT%s_|Kt#c-|Fe5M78#m6I89fprRkuHXMpq4E zDAN4Ax+O0wTi__p7~RxZkU#_|vI4i#Zk-ODo{;wbPjGAe31B^H>Acye{qTn|-+S`= z#82dIcx=%*O8Mw#!pi~n(g%cEtzH`|g(tHbQst7pZJ6EY8TiIMVXotRp8=hbY-AeM}u=qY_alaN)8SiBlnPawJ_V z|F*lv-hWK1kB^VqFGH>=EBt0jjej`%(xx~JHE>}jtnTKbM$Nr?D{vsbo7T*+`UYUjxT|N@;fWz2sT^1ucNc-Iie4ObdhU)Y~cR7>zlbYsEV{4+X%S#7lYT-AE z{zFMxmrMKN`Q4nGVKu)%y}zATe?B`8m`3e&;dMN}KmPgmc7So$`}xK%WyHUojLks+ zoTQdNCVcd_$3Km;`#}Ce^1a9#Ki~M@P36wsgF>G!Ko012{2 zX5+cvgyyFM;36gP{`1?X%8&hDe-H^Q5u149FJt=c1O63(e?{P5E%2`v`1c_A_aOKe z3;c@({y%|(OgjuWj~tQKd~o;nlb>kmx2u1l;lI$3_H55d)um-qU9K&;3&X+I$F8r{`#c(vqQ}n1LpTE%N;EGJIU`$ zm2}6hVL}z}jJuCEy?P?){raxkk4yT$Bw+rO%<;(MXWwx@AwP6v$NS0{CWb4yyK_o& zyYL>9X0Qd7uedofbY;)0qnSH?hJAh_dKZS{Vx8kD+#l@yYdIibjz$RzI^B=4z5xSu z0}R)};Z$l3zxC||KfPIXqzbcIG^~_`VuL7VMeYS{wh4hQbU#eU2yvNXLAbjO`g;agxh| z!MDZ33)^9p0>urwIRu4#;``WNV&H!dM(|j$PaS(ncB8V2P{q6qn~6S9`pvowe?YE! z7i;*~klk@`DSO78mH3&Fk%0a^Rp_r3ydJLDrZkZ8GB@)fN`uW>!!c>L{21hNk;^f` zk0~rYn&2+t?OxW~lxDsWq|2sjk|Sb*>(2J;PJ4&iljiq=y{Mf(2+ylECmO0;q0CPt zy}02s;+&1o0KYTM}B#UObsx z*;q%_1d`t1AWbJ5{_=JF6rn$_%z1+o&d^5&T{~~jgCQukoNCK7A#@FcvYC3K6lbWU zs}q@eJ>*6-K9wQa0;GP#LOf);M{7m8txRPS6*7bpDM6_(=?)7DH-{;bxxopyLKRzu zg{+MC*_@}6Vn=<_8dcYlPc+#&S)2ob0s%#OwP#!eG+Jzpk!nDsiCj%^<8umb-=BlgRjyI*=}OYiCbu8>!q1!G97 zGjJzEUf@wQ3zb$)X~5#WbIe)#kpv%B-BWFM3l(>y7Zx%12#SZtB1u1bRXpj7RzO zV1!tm2-P0Fl1mIyLerE44_6T0|2gX^1W;Zu6fru^)fjaGB5+YWiow1FU*i@T?8rBSVKUDECr>3&sQB3os7 zcYo$p$m$fnfpaFzm5*gD>_IhmGolW|G8V<&P-Dxe@Y9d>%No8Hjxj=dJrX*mg~al* z?~@z_rYBK_aasP~e8$gGe4Y>g2!vYRQLua`Z7By{xR4rG>*HR#M_>wHFv;*|TU&Sy zZz4B{=-F5HV6g(zuF9?Ps{R)Q{%1)4xh*>}wd?Dv0E(25!FO$-C3uESU1{=5}dr8wmwh6ghPZ|%<{G&n-(CXq(@y@f5s4Ql)7{}OBirh@)WK9J-T1}B=3}-Xh#D7mRC$yKPq6a39Dh2ke0gW zf9L>=f-_i!bAqgw5@-DEa zymQThs1m>3vG8S-XGWLyreLbS4}WnFbc`>8VC(-#So~kS5~LVTk=o|X(ZxX11>-h% znv50SnIzWo$}mK$?Vs(bh?ykUrY$9O;vpNw79^bf2i|TkqUj%mX@$Sq$QYh(VTlkA8|=xf9H{u*iCLj zV#ZqcGfcRdtl$B@9y2YVFq}21yc+t!A%Og1FD-5HT?ii^`MvUi4EfUI>7>C$oKH+a z6RjwyTCEqd3ogEnd1s!S3vNP84sCYFK3-i2w&2&xH;gs_@!;DZmeKWm>#&&2>rd*` zMS4_$91>O-&7`j!tcs+?gUl2P>x(2xz6+a=Z1QyrR5-Qo`#U(QuY>+BZT(vgfu#+; z`0-f=S*ur;BFp^dY(7Cz#7t^Qw8Y@ zw>J?XAa)=2dZw}F>;{w1UjO7OqG_|)B1On|enEccD^?_~M%#2hykpM<@!2R~vV%_C zN}hMj&j;?eO%iv-T1QO7Ifr610m0XSH`&k}*kT{;Z1(O>zf75D>rrU zn0fW#kku`%MQAY4crNM0>X zX_^+<|K=etP@aL=XBHs&Fs9z#-Je6}Y8yenF_Y zlBZglNq;Qc6kMU({Sf>5bgX8_Mm-k9UgJ`eXEkuINCtZ0_pShcDSAVyj3A7WkcItd zJ0w3SUS+%S@$S^F$c3)uvWrZQnWa97f@=#z^@)VBoTJVTL)s%LdzgL3dZL?30s zy_Z6`y7-g9>6hJ9cg(%;vk<4i4x54v>u1|5TXdMhI1PL_dMY@cXPdkmAk0-^4Kwzw zk5RV=QX`Dil#|~M-5$&}$@BTXA3 z0xf!_dr@iuD`EWsA54X|9(J2cz`uD)7A$TJHL(g2x-X)#Jpz@H7uYt}22YORp5nk% zTJtLeHZ^5|L4lrp3rI9hV^Y`ox%Iu^WsOpziR{jhLgrM;Q~x`)=NZ2;9I|_k9($sA zKv5g^;L`(+v6H%?=KT*J>CQXoCR_WuJG3fww&`uPi5qs*J=ap3)eP->ZY+?#oa_mQ zvO*Z!)?~C)Js*I4>`&NQvt+M-l6bty!LHXl;NMU(+4a7l_sBrPG^O&+zzn5n?3Nrx z5K5Hud6N`Hs+GiYre1B+;~eD)7gyZRjCP9CV~A>gjE&x@AXE~TS**C&Q~Pexx4iGETF#7A zESFsDFPP+V^y&E}?fU1DRkujdeaw`=bSG!1suXi<@2J5w(9r@RmJGubBWxM+adFw| z@yS@7#Gc}O#3rHEe~ahlAQW2s>UGB#Sc@Dxw8c;;dO4npkRW0ki96V2gg0-MF~H+r z>t~WhOr$P~EOEZ2gF@P-^J%`>;N;<0=z{u)jx^J)C+bB*C}NQ|os!%tXsed@UlpYw2$K5*h}lt7+E%L^6? zl1G&*$g4ah<+XE+kB$0_;;IUbv!}08!%l?I#1OkGYXrouAW5})1@q8p>BnA)VdzoA z)CmnX39S0escTq7k=U_6mfryT7o;OVBM_PqzNmAZJ*eQY z++cO4W=H+10*PEv<%2a56T#Y|XRr2|10pC4q**_=yn05bvi1&>Sg_Go*gzR49t>L; z>&2++vTE$CAL!7V5iG1j{h*jC#2H#9c`$ND+*xgy(}ofI-B=**RPk1Cu+fxxu%i%}s6G~BbcDi@j)5Oxq`|w%o>Mf3AVy$Ie$YM2=%wW1Y1rw`z_mxeGe2%OX@ot)aVGz* zZ3dj`8>Gn2|J~-R6bpohF&=`y(NIpZKv)5 z2b&HvdX7-I(cL`?r`8l%AMH;QaZPigQ-t@D`elP_>jp}95|tMp*{npCmw2l;$xCT zhnfsdjN+~0kFASH`>{+_1g~$DRx2t^?$W{bh=r82;ed-I-=+8zahWI{iwPTkJz2^Ne)4s-frtGu?OW1B|WlU?1yg^9Pj? z-8FV9#nkNU)CrQe_UJz(rq5>9vA1f0&N=KX4nEOf`0zfCbu+4Y1`}@G)cqh)(C9;c zdSO^i>cm3yYl*>1s+wVAXOssRKR@4pzSf!_Dlj|Q)Zlvi%;3#AM& z(-0ao%Q`9T!&xyhL1;#Nx&47WL!i(}q#}mYlwSkW*!VV#6%rLg;Z@lwKu;7)`;ie; z#mE=r4M#f5Ne*$xGV-*&4&`Xl8!cUH)l!2%lNN;>BHv>e@yF2A zZHF0#*P%fPwp||w0&SbE=JR>gBfTrd6Z>N9^RyGLw@DtWWH}Q41f!d&h`Q0UX-K;` z>KDRAD=2uB(VeW~KH6O*@rSX z)Z8;?2!76^t{aFljlj_8FMry&;~_^p{iF@=ur`Fzi1XfD_}JPehusMWSnNS@Mb(PDjOK{bm>?03O^3<*>g{5I zW}+T{a4!6h_W`(_IdxTk-0CdAiVzG&dX48lgXtVWm}6#sER4xRjiE3j+AK?S z|K?psTswrs{bRt&PEoi{}(rHpcFGnWhU{^jl9=ugPI*hbe5c-bbdSrBYWMg@N zG|wf{ehTi}1-AThhT|%3)!BNm;c(?5dg82XV80bIFBoQx(jmV+>FrokxY1(ACD8jY ze~xjt)@gUj7@HIBe68cu7HTt_X9?TaNKFB7%Nmsu&QKvEO&-BSxnd@hk6rj$DXht{q<4i>~>z*~o9Z{SVM}Jy!ATGRc%aN33`wMz6t$ z&RfW`{kPnvJkcPNTJY@G+omKqRmG%)nmF z06pLXR4M{D_(9;1)sGmqGOhO&_=&=$Qp;^FEIfjPS3a&LOnmGcNH9=dH|BuHy@|6>3~ zqA>SaFA0WE_VHAKKaw*LQGp{Su1@-QP{x0;;csaHvQw_-8l`Ecj0{j}h^&xa4^qu)r7$ znC@pIeg2@D_j`-u**{&0G4tRVW=6a?L*IR6)D|Rbp{F!<^^B$yHt`EmgR*0G?WUA? zzu!@Z!!Xswu1gQkv9oU-!8|uM`r-gMsKtlqZ^H@rp2nEYd+-(AwFnQG$VB-DweBhX zs}$U28ph6N$Ly7!@)Qh%OYVkzD@T;ehHPvFuq-X8K8Z#>JBMW@VDt!GlV%^59o3AF z93J7ga_oeT#wYZ<=h;CtRD-dDCmsCjPT{sK=9^N9btaHIg64lfo+oiFI7)GI&9Mi z4*@z5&ZEsTXsBrI;pxUAY!?Eh>hDh1{9LGjQ${aC&SQ80pRB?jo>}jkyIy$a_ANB-|g39tBNi4Ab^=Fx52%T zGQKkG>5PQsl-D)!>9A+i1BdC*Q?@Ku#qJo=*|H-%tCO>eU&Zk!)njR0tKWopyxF}{ zNm{m3Sod<Nz#bEuwv zA=X;TgI(rFuE=6PcQab#KLelpf$+gcuDrUF=7P&6d|mkxV0yZ_M6uku0o;qQw**%? zqsmnLGa8E&E;J!C-`rZTCPX5-BJ>VbKf`p}N&~Vl`k(M0Q@RfEq~q zI)i-`^6j|O~R@Nuyc zOrs&$H`BRH7p9tJoY0cX&#!kaQcUt*(W7V9G)8L!U*G;PMIWNe0CkR1tf$CMQqU1v zxIi&dlWN++8ll}CWbc}Hfk!*?N#1<3h5F;m?6e=+D3Y3y^wyJ!OFM<=^^JHddspp7 z-o|RTIfcoBQMaLpt-~m^T?~(jjU&F@!P#n5R$7^xE28pm$`{th5h6VYK=T87KW>oT z(M_^z6mYwA0K(kP6sen9U&9%1tm7&jf%;r~WxkWKd3o+-$08ysvLh04?D0qzq2{in z?x8lq_27H-rlUnI;gn>ucE3T@V+pY2>3asVK67W`SKM$UdHlHqtMINy0SY>ekA(J7 zFD6)(zfmB+HbQ}kiETCEQ!Pp>OeM_!A^3pw)@I}pvHrxNM}P)}e2C;RZ8^h)dX{{S z;rBhs_w6S8yKaIw#X;fOU<*nBYoGEDe+T6n-P?4tx7P-`EPSe}GHP_!MJp6tcX!;0 z8njV+JlAsg8Q**C#~J!dCOg9Xaj$RQxG|*tj{CIaxBPCiJJC1IcLnBOarSCnHwvNo zM#@w>(5`Cdw7GpTpQ3kZrGkB7j85R$&2)rU1gY+hFFlXeop8JG)@u})!_a$-RPggq zb(U_H)lqqmF3vm_n{!BNE$$FRtq(4XopRKBp1AbxDfcWlq0Ez&S{-{@{0V}0{%!^D zWhNaUu;^uZYwM(v?Y(iq<7ENtHZ^Y`a&6PEF_S`5bkdo6pytxU1&)!zG(>OBkpFDu zrws16j;zT2D6eFff#(9gnteU{&kIb9-#O7k1aurr?_s_3A~do6uNwB7?%+mM_@<}4 zzNM};K3C+W>KU2YytjzALcr)kpQ|qjnr0V(Rwt)3{;79>9r#eB`(g!}`r)QI!t3}0 zU0R<>0v$BYY9k}#WVGINm%cJ3&Q@iPGt6^!A$)*KIfY>aUK$M7@4XD?N{yl9Ym-+h zkG1Tg3I2Yf%#S~h)E4srhab35qnlU_5&or(+27`i`EA-hN}Mo#s{8YavRCC5w?36r zrn3spCx|QYNO@%l#wO?@j_GR<%R`Q}h2x`JR5f^2+HT6nL)8+tY$JP~N!^mo;&!H? zv6JQpb{=o=(9(v1X5s~#tcR6X6x5u7$k$Kz*WXtz_7odIp4k>G4-Jlor>8zI=pCw} z5gSSAsyxZL*O5@m8w*Qh!1XwJc&%k#!b2gxxzzccGFX1Yu+mp`2269?kl8SKaN23U zLoARE1 zVFZ<`l_WOSII=v;v@RsjyT=;yrC+kQs)y3c!`F=2&# zjb#pZfgy~fLqe?PxGoVfeiBt!Xp*;1j? zhp@z|7Ee&DEnl|1b{9rFT@8fc-I9Q7X=t?Y$*=J544`WGiM~W%YcDVTKe%;UP__PP zBhQ*lT-VxB&3d&YoeE;j?iAkaAk1&ZEbv}q6W=t))(FgTEN%Pw z9JsK;aPj@&UY(0Ub$3p^7ad1Dr%@J~8qZ>|Ic@~H|LYSU<(3c zDlkS~+L|s+BNzDXubIUFHQsio_88z*$(Wn;>GJSuh{ur5|49T%r}8l~XzR&XRA?2Y z;lRYCBs}I|eS&UkEYLh<1Tx>n-#&$S=v~MIZEFK+)~3?KIp1yIF>NXeq(=roMY11I z71y0uZa8xryvQl*r5MF2mm%u!>5Cm7zr^T87*vK;8|CY)BPK!Z?H&&ne`T-uTVw#_ z(eb{{?zopw3wayXHl3nJ-_i+*Tu|!0wwfrT*GkX2v0H%K@$uBHueTX9{0J6x6&jZd z*eeGr5ighcZV8`fXNSrV(T{Nl`;4tB@~fv)vXWz=W&sa0Q!lKjmCvU7PC)~AF1rFG z<93A6RX-D!rb7|qA7A8U9a_r-WcVJ_rGQWAXKz@Kd zcD0U@u@ztu$9&4kxgt`tT>_Lrr<6RKyhk5UwWkFFeZuSro7X;Ro_A)o7x!N`Us~Ub zn(~vJAs?2I<<5JZcoc49)|1ltKKr3)F21zK5amc70AR+_8{!-$)*vWs|t(QNJEQg7P6o+*55 zt~=9pd)Xpzd>CM(v2zC0C+o_@`{dGdH#)olV*>UF-HF=GAGD zK!X985#JbT05x5+TQf0H*xriJKFKJ%tR&KIZc!BKcF9C~O?xVoHIO%gG&f);nPZuQy^t3te&p~Xxz)>9}@JdN1iWjKGZ8M z_v%(beH(J^vk7)~wOiCemP7@`Tb?_2?j5R{0I9{K29TbSr@v6Sj(TA5ays#U6b$MG zNY$kr22)*ZsDKHB*#+4%Jdl+x z>Mb0;31JWq69@8poKSb$yXC906G;emHS7+L`IbtteotbR^Onn23m+Hs)vMz|-R9{| zno2l!4`1!grBUT(-+)mzw9!97`FH`{cW@mzl);rWiE%O&CJx`ak~yi<-GU~Si@vRb z>tBgwBkk{8-nCxqI4v~VCGVwi8DQ(o7}w_-W1&LlKpgThM#3tk-ab!e~@8^I^g+_%PU; z-b=vHY-_VEY$_y~rOoVMDn_=}Q;@+llLk)y;h|P$)o^WRaf}#eIcW_GlQC1%U=cCB z1oUl40gC3etQ{P_hYTi0aoQ{n=Z97ieaFJrk2)y4U0UL-n9JB$?NVa24T8eWs;K-} zE;)~sKLVtlJ6d)%1{zFDNS3Hp_VM+d&QTz*lsywQp(N0$)!i8ZXccC*?w;MYpUSU* zhoS-6!9K~yYran{ss##Je${S&0V(rzy6# zxl_V_Zur3eM^V8!!Pe>g$}H_DP6r9DplMef+}@028;9qJ5UXi94m55^3p!dT#NCDP z@O`LTtiOI_a3ODaP{=413e?uO0y|XDtme+H3i(9n^Rp+ExhzY4VAS}YthU9MoF}ox zg4-r#w)ZJ#vN$&ljKm7ZCl@~m&W0)K1O|6k-sN^~CngT~I~=wM7hNi;W<03jRB1}1 z-cl}i4q7XzbE-q{1r&T^nre12D0}~WJ)!cG$?0Re5zD=o%Z82%q6zc!3H0p3u`naE z^^X_|Y_fAe{=h6p0w~p6RcR>8b(i2d{~b%?pFpHyHU2aK)&cFx3&X27Ul*7KzPfPB z<@#yb2!~f`EfoNymr|X3)H6#E zY66KLaqn%%VG3tK3cmLmrotK)iDA_SEJfE*qc

R@Iapiu$gnQLH7&8k&s472NLD z9Q=63KTp|@-YyJ%N@~)yVl>_T(Lgh0oiYJtG%n>K<%-&fe@2iulN`1p4FdEZRymDQ zz3ZHv4yFkh=Q*1oXmAP895DbVX`>3z@`8GvNZk5}&|geY;quo%FeEcnYz&}w)JMd@ z1K#%?QV8qcp5CS$`L+u1Hnad7^g_T{U)s@QGIg}Dy>ApKey6FC9C3+F-M!-oC#9vQ zb2Gj}Ie6ErDFf^-LM8V7hBm7mt2@R22QN<#ox50wp1^r`u~G^6Joq&P1?JPX1=Phg(jWgOc*9AxkVY440Dzv3 zjOs6K!XvJ2jwPnlswejRr4B9lCx^CXWMpzBQL4d=na7MmZO zw~EY!Yqrn8+puE_<8Tvc4S={+ZnZ~EWU#+Y9OKXv(HGEt>2Ts{u) zOcD%%E;2m6n~SUGYcx0=4mE;+BggsS$B^@Asq+}03eM&ZkDGKV;wO;`8@UximW%06 zbkpje_mw2b-tuxVZbW>o5A`&@oE$*rH1NbT-@K_453ADhN~FO{_C6JN7xFWy4G5tw zp+TQ*sPW$wU#?cAoP0!Y={diMH7bKFeWXT8{s^tao%tJN)$($0inA2Kp zo4xwy!>rp9+EP4mLICw3f?)a6#mW zU4mDWmZqu!s1vt|B|_V9hzFHovM}|y=^fudL9KxK0HMi;vBE;t*L$C4odz1YxcWad zGys}T1jgm&mYk%gZ*G#`JZ=E+Wyl`vxvj252j0PtJ0)bQM7Q!ljq^nPe90DetY&_> z3X1Jfj<;b{|rXO)DoX{dYG>z9r%5kx{9A zXXyFFPZl=6%`SY@nT;~CnYqwC2O zbpja*MszeWg7a;K%;+9vN>o+mQJ0WhBc|X4<_2B5u`nx@2f*R6*>BJ|jM*G|^HfGf?DAlg!6sSMM1e314I*Ev7G#K}>&|Oa#+;}~ zX!0gTQre_DghjkrZgp5b@z#w(QO^kN{-Cml-`kqgV_p54Znt>08>iN5T3Y0V=5<$^ zSlgDyNaw-XsjRvy3C{HG8Roh`mSKH{PvxT+aIiCCm^OudS7-^zhK7_~9Yib-4i`j+ zHtOEIWXLuf$^NGoxg#csTzZW(`*fDiN_|#${R7w0C8=GbyE*$NDO~z`vY-X;?mPfV zF3DWe@>}sO*-g}|mJJEbE)_!7BDDHgB2^2G)aJNMm5kQe2#k*D(bc?LlEc*o(TNwJ zvMOb1X|(Ty+RvhVzj1zLUCK?gVljOcHW1idhE1IxO|2rpPNblFqZ-}&a$`%oLHksT zW2~D;Q&M=^Vb6veKS?bQSxgpy^e_JR_Wb4#caREj+ui*>K~pH1Fy^3=GR&B@@#I*? zQf-6Qw5rmW80wyirS!tt!si%K0T&3dR}9r?#~wRV2ik1-;Q)H@$ID1fgPxcK7hYd_ zwLw;7Z}oth*!so>_y}{TmMBN7h*F?_MOapdvcZ5}%u`$|^LMeQGmt7jf!-ny;>!mE$BGfCYx(%(+RmFbpbLiqC2kRFdw)OV zv#9p&^jjeomt6&w42>~c=_GPUdM@|Uxr4P1PZX9b3hI{Lg4@&p8=Kd{dvFMP$3%aWz>LyK?Ju6yc!GGsWCNwRFjP1FNypB8=t^aCd! zyJe?x;1oIfy=N@2SD{SFGS;0u#+W0<>&_6qI3?>ASxhD*c$c#db3hES2GY@in!Uo= zS?SZm*^zd3FK5F^g!7CruCAra&fw8U#O}&747i~qfJfkzE>{@}rNyN!G2rtRiIsNN zRl7QO3l?nD#a3p=0&~D;aq;F{+n;fi0Xgd{F9w5;^0pVB4^bRA1|aYai@?kKA8UsS zg?x`Xx7FToFU_(>q8fhf2L4~CWiSKPLibWxIidzM{B}XyE7K4m&gjD~Zk4kEmz>LN zx|=4$Yn@`Zd+!TpRhh8HYoWdqwKebYa5zTfIrA}=prBFgqvLT&VO5XX=N8Q%>oA7e z+>-~iE&CpBq5o9XbzhiirNB31i#;cqEalee<-Yj#wV*73&PY+w(Re|eY2Yb?v*lsc zy=G*uXKt?kKAjzgv>q~U8JI6j&9iITf)M=Ts73YmfQSVPPHRm(G%)B2yr4qGl@b5X z4+C;=)Gj8rl-Wo;;x&r(*)XQl&&keq51WWvUtj-jczNC3YxXWQ4W zoTQ6T^p>5Ihr*@73yegO=J=rNlk*EDN zaQc&SZ6MHtR4mr-ddH_s58)FZPieldF@Lp7Tc;mrsUQsiJ~?2bDk65f8Rfz>vdgYwzbz=(|bpl832g(&ZNSSAkMyGC`->vaZ!CX2+E{f*ESVxl`D zud^2&$zI%yq;7G&m8{}la?Q9nF_BEnKb+0h?>DQ!Pj@eKwBZcJ@l`&>%TcYD@4Ih5 zpnbc~Am28c*mkn$a%A7x8KXRJ#46tvLHay=QD%K@zknX7r4YY-OR^kJ1Juyg{|kmV$?X!4t1^hRTqqfI}vOI5GGh0$pm@-RVIhoMG%)Yk@ z*9)q>35rXM_|9=&n&y&_FV`$@WGKT%rBt2PEjrWhOAj(ze>)@J+lanfH(Hz`X>xB= zlDM>CNeibKC{o4@vFfk6c-h*n;VZaD&il?P6SEE}V6N3hm_PSU%MZ}2zT@^&VBpm? zsb|MzIZ}+*h-i(7ZGF!<5HmNClls!o5WjwU$y3i3*XPZYUWfSm2Z+Oq1W&o zH)0VY4SP$QN}Nc>&`j@e&iSqA)a4~&!W8|r^DIsGNuLV6zo^Oz{Z8}vT>%^U`wJdV ziB+!AQQdu-8$opCsiP%F#SKnB`81FvuLc!UP_Gn2nvDv>F40QB`LxP@hHGR|Mw|uI z39Wp__kO&UnbvaWdEm>?a^S#L$IKIyKXuzd-0N}!@uVMY3bIK7O8uru7}F1_d8cmq0cdegvmG!P!4nttoG9{ z$t-y~a~)o-VGs{F4r4RfeK>T@?IL5;`^!e#4`shR{z3f1>WA46CI!ibb611E8ei9f z*gh1vknlnOt$xt>hr(6?liCva$mN@tvO~+;J!Wn>+)TU(@yCRTzOD6LZO6?@Oh<19 zx|4gcN?hk{VVLUP4BA@U8vo7kTlFnxbI6p^d)7^g;0uft_zQ~u3I5(K_f)2Hc#Ib-G%EK?P)H`IivZqIrBM%>Y@d%icl%0Y`Y@n)LwO7 zjmd29m-XRq)4!-3-Ph}~?(*(3lb57_Wu`LvOTqdA?mpt3NI_cBbmrya(ia(Ovx#!l zRI+^8rB-8y0kWbb9Q1!gXqNBy_wAUl)oLis~3vETf6h+USG| z#)_1sRF?whbmwhn*JZt->p#D)crH1*1iL6NN&I?;E7(oP#Vlb5ZH5^K1pBFfGOXGU zH)cwjO7U$z`u=3(wZnu_f5hu0v-?lRUb{DM-qnBCn{F}Ky@s6e?udHBM`9nu~C z1*(N}7rDla6B)yt6 zq|f(|Z_NC?xkgWwg-n_8=p6dj$S(S)ZL2M%Eu*br-;<;`F{i;F$hb*tBDM^>hY>G> zR8p7nme`m1tQyTXx#T!kVPCjjbk>_5S^C}HiTQCh4=tJB zH#ibCTRmLf5xgF~g6PQazO~G~SjHXXQz~HD#6hCY811o`cYLVat~)P7m)1J#kmx6h}%VbQhUZ2UP_= zptPd88_@2r=`TT94vO;U4``icn@(tD=@UrcjvuEXzBO_=;db(~$F~^dj;{oSehkSA z@nnXw)IX`=4!puAx!~|4NNaM0sx*A&!OYwn?k&zOjxE#{3+)lDJgw&yi+en;>ON&g z-BGYsXusRR&hmmej`pF&YT_~7;^*|wwNBTa7<%djlr0SQ>YR4K3r-6u3T>J9GMSYK zT_2`2-pKtNu@e0mSnWLq9fOFmOkAB{os2T<^7*tLXAm#Jx=Cky^`g1E#b>jN7YP3J zErM~)akYGs=CY6Ud&ubyqp_c_NC10IH@D8_pi+~ z%N_U$eg%syjlt?);#St3C~Gm5o&I(Fn|ZK(LX@q8#o zvC@9*7;!6OM(L})+4!Y;CL1@eu};ireYXV!YeyKrTidvHdA+(((9#|r?ExN@SZf%A z_w9FV*yH04oN&ZR=kAg>Fwrrs3Dd!I5NJfrVadca6~9Aho%!aAu1~!g$IlsUpw|0C z11s`jekR){yy4l*jj&t0&$?eObfVSGvt1Lj5_yV(Rv3n<1x=sqKDo#5nsh;U@aNos z^C1Jq@KQ3rh^~jy>{#H=x1E5+4xTx~YgShUsrBjf)@C!7i;Tl zc_+3TUFHSwd!eG`8_wgQwXhR|uKHwr9sV438B3kV7revnKv&0?jy7eDl+WTQm<}#s z-rhx=M|{zf0K=rTiNSt#U}3o0-Th)hKwoEHx52fB9A<}WLZa7%Mh+Z%yN@9=kPI1F zpBzHzETU~y-RJOVR3cGm>_l$cd<|RUhTgc;;O05`_=@oMu1s&xKzLh9g(TDAkE5}@ zyVKpl19in!#q*O78u{VWgk$#y7PbmMJ~`ZzBc@At@Dw4krzVk7BJutC;Rm(Ty~X7V ze)lGc?@=7FCnr|3lg8;;!-?KYe@0zwy6~*$vZkD~*Ts)G;*yLE>1^}K55jQ0lJAVK z3hm@?@ZmJwW|=ps;}WM&)b=GI51COHj+_V#FZV%@vRnM!0N?eanbu2lMMWY`;F^Mn zl=ub_8E{1md?bh&|L0nc_&(9OzsgC7h=Qz$NdH+!3HUz!i2y#QZT|6nE;5ja9Qf-B z@NrKi`B!Z+_tbO$x;|$E+#`CbF7xsw@U3p*Xl7>TWNGi5y}6VO6kKq4q3uLOboK7( zhxn!1olPPll3XhdEoUu71rZZ_D37tJ{cAHGcc{Z@KSW~gBETio%-NXL9cpXmB;qc9 z>#rIj!1ZY{?=9B9syN$--_lZ4VU@9WG-DOudC2qdmIR2El~v5q)LcaEncP2{1AmF% zvUGNK5aH!@b93Wy$J{^-ZYK{rXJdD6JEzwoY_Sbv;<8flAor!3xnK{|px||M6;?a{QVt+m2f0h1wfd6Qrb!LnIEdB2m z|84-bvvQVr{LhE{SMh(eIvuZwij}*Wt@bl3C?Eus^Lz&HcsxW=N5Nz^1PnGt%GA-T*Dr~SjOXb|1SJERY zdq>9S8Ylgl%0|EPuKg5VGd7-99-X5mmZpl3{+P7lEczj80(o(6^B=Ae_^g?E)nc6Zk?}C)zRBp2! zSzU4gMx&#nY~QRYi8XDGTF2yAImmWvdV6|syxi6{Hkd}DWt;E$`|-%=rm~X0&Segya&NUI@?)d>-q~5Y zuwd>3?FcH}s-$H~p12KiLDbjPiBX5*CRY29SH{`9+5VguiaX&_DI^oSyHASISe`L3 zV*1+$T5d^6$)b7bVN_tA{20O}7Bw{F?haO0pIzk_P-{yN<7JV%!J7)w2WQx*y$Was z86%hw7X7hos_tXM)>FUVI5M6wSw?ddcW!QSnyTewM&#~j=;_&Rz$WontUatY$+0Up z=Ehqi`*9i_o(d$wb2UIS=^^KsJ>@>%}kX?PPIS7-2I= zvaCFYdxr=zZTm{dN+-BTR~Nm=F@}Pd(^0!M?tbO{q9guIxs>P?!F_hok5Ah7x4(2IVv2Q_P}FjLd_j&x@!f$zG6|(Blo~%^LDA&D1I5{n@XAV{3nU!x zs*A9WW>Kb_lI_O7J)%BiaZe|FNjh~h*V5WLUf+GXZGv(aF+4Qd2;bw=1cS{+ z!K2&YRSnt6ODPR2Pfwru@^QJD>8>s#4~c3{$`901Yg^=-Gn8kBV(KKZy^>Ox;uj$f z|47{4557M4D&52sE6GN9wSI|%GzFi`?Qt6CmB<-!7feA~Y1_n@zSX{1_29Z5qV?S5 zvu1FvC~VIb->K~VdNCQcrA(7_$&g3cO7f@CnlY?D=zQ+aAf^ch?+iJUUF;7zcPNr6T>Q5OV%{I~|Shb06d!o~N#^dt!ODM=idVyfO` zESFyAGaq3&-Xzb@%`MF@Za^>mh@17>Ebo)B;jQ0|4EhF&M@$B>c>h{&z{k37wZ)FW zCU%k?;GZUks=RUehC$X71mijjbTq_Z8EvNJXjX z_1$GY=`Y2+>_ar`_b{~I-TyS?e#Wf*8@`a{^@W}U=+Defwj(_wVc}{`H3OTC!>%Z# zrS&KB1OrswyNhfV))ZbA%3bBudd?q{9^dPh@S5)2Ysq?ypXYF*SvL`Z@INfnl9ZGno3)NG;Gu3zdx6_l4rvQAFZi5k1swskYo+1cbAIH3R+$wqW4uZ-0+7_?+ITmu*uwJ*LG}*`*UAjAPAXgmQsgzlrA)s);m`_`kzEx> zdia2=G~7g&f((R>8jm_;1)zG!anA`;{5U1PkgbAy399yr6x=c4wF85qE3EdW-cfrt z6DX$6f6>Bx8ov-%T*4bO$en-+kE9Z z3EvNp+JA?9-R8Kl%!n{i+01%5UBT&qQhQp-Z&*pcZhaF_NafwUjV-O?KYyy>!%u#P ztDr;&_kB8;+(u}X#om}ET`eZnBrD-D=?J3|f9GQZ?2E~|=f!(pX@2wi90Vsh|9rU@ zQ>n+$vhr@P@dV$vHxtZzDWRd|2K(R?#S%iyWu;;h?P2fEEy2QxVA&p)`XylMu-Bsb zUryv-f6Bd+YCLB!U0^`a5c)839eMPY68rNNFE#Ok7p5Kt$ypmWRTgXbIZ9Q4-LTo}r>#01pKux0XD(T}V?)cX zwChT>(t$tTZ=96a`k?H;>FSj;(^Im&4N7=y_A$sDl#U8}imLUj%gq(uttRMDWcVx= z(#7!TuNY&0#PPw<^^!3$G1lQ?+h6MO;~SR>ujj1|Hy($6%?fm-V>?0}iagbkk;x!O zP%`lB`f7t);w5c{9&kN)@FdjYaCez`Zv}Y|w+dzjrsbEz45Ct7TRRTEUpq;KszU*; zSq3z3raJp&8sc8SN1g2Kc?_D)u_NZL|JqCb(hgHe?<4=sngVn7>5oqM6x08O{sAW`eqz625lZ>%9Avs6&%vTEd7ilF5R3FrZV-7C zcerWIg!=_f%?f_20angSlJWG+65s8YVJm@ugQXbw5O5Ng$dYvA(kvDq^4azZ*p4{N z%~@!tp`@Q`@gN&li)wrKOU=5?sb3+e3R5nJDbu&79Q?2lOFVAl^}c*aNS@tCVFcsT zqsnFXGiVXA`=W*&L1kOUSdQ$(t2!zQ6}VNyRb+O43}i{%qWA4ogfXVlzBDot(1{&^ zEofz9V^xY03(Q1)Eq1E8D0Wp$V%?25bXm0N=g=t^4i5W>UO-u$r6*; z1Db9Ou8-HkeO6=(@(jqnL-bvu$p=v#+y=GsbNohSf=swsBxU`|lxDJ+o9yeh zcJ6Y?l`aiBbx2?GxYkr;Q?*P*`ST0OPEipOZrYz1fSKQuEtTR~9$h@LI%R zqf(Acm#%xs3 zl=n)*;Xf+#_vi*PjkH&Jbt*;xbsbvL%cfiRyMRWk@kX8lH9A>EvEH<^ti*koqhM%w z&)I{3gV=7*Mb%x=#*&!cWZ7JCRaeg_)ZTf$#4EO%(~-XAFfK_vx+3heI}k*uuGvFZ z23r3Hl#e z*oy@ej3SXHIJuAr1at#_)E15AbRt^z{=;Ly=D)6-^se3S1G}u}fx|JU#sV``s9XQm zy(27%`5D*4Ay>^JJu7OlO<%&k&q*bLFnLmM@3b*dZ}0}c*-DL}_W6CAsADH z*sV`eu{qQw$l`~QRt{uyToCYf!{LgK&vA|C`gylvTdFf61*1C`GUpZ<0;>@F9OB|V z`NB5VB53Y8vn+I@Av_+wH1;9us08=ICAUaMeq~2&lPba9+6r-)MY9)J;ihcaz1ciz zUycn5w_{5kBB`!UgUbkA)`3L5eIAfwZJa8v#a-+RAQfsCynZBv3)ntAzM?FATZ?c^RSGe+|+2 z_ALo@h>I>>-G-E`sm9U=?fPW-k^V0e!J4J2ilQQyP9UPkrF#t23?Pu%4OKgfDeKUy zD=XH}!7M?7F?MIniI;*s0yY7}{9a?8tV8W-6Z;uvfEIdOyaz6xnD6GT2xSy>w=7W6 zCU}@-m0B9+&FI(c-kcn64_$4o5@yrd)%#}HtyFxyKI`ztuP&Y9=!vX`H5rqBo0ohbZ{@bGgqx?sEMwKM1n5Rf;E=L#-&zwXT&!q$^NA5uXhmx4)3K9->k&3bTzt z_?x*h6;&pso!A+&lNr_I_KBsb^etFTh0SdA$dJTXFtF zg>WpUvY1es6I93??76to{CiUgukL#qC#Dobt&_7X;f=KWjh13t#-+$y7ncu1!IR2k zD-9`KU7!?xvn~$6l?}(&ZOyX#f1G{99GT*|qEY;Vn_HZQWJ651bmq#&R*g47WU>J* zY?)YY-a~~~*m1oo;*A>pl2&=@R?R9NBG8CV=U!b33x z+Wwth|1%O}zEXx{hcuf=1mvBZsE4UZfcQ;lM`9@DX@0JWEpu#to4oWCi+n2oeIU!`ki0;QjFZgEd4~k-Q-dvfcG@QSo0xP=uKZW1wP!fP13>kR8eF8js^!{Jjl0h`26;YE1|vVDpG7 zzu2XsY@&&lo?=|0@wH^JehnJ*YL$>#q3&zuZ%*DM`YH$^6 zDYcZmy)0s#MiVevSjhdHY!1Yj(Lo22o6fjsT7ctc5^ZeD_vAP1cDY1X3o3`p9Q9#z zb857~`Uf*y)ON z1q=jbs`v&~QyTTr%-^^2Yh!|$IBB4s)W+q2ycOe{0W0qw-6zAMi==hQ>OLrt)_u5N zdht&a7%@fyw?4X_Kc}!2^-(rDjUarKL?4QsF5-0C+1WYzrte=%7%)wmzLUD5k5d`? zu#zsnc&wReBd(vGs<}~JQ&ThTTopogmU?Gq{-$;!_5*nl9c-%F}$@#Zt* zN?JI{j6|Nsd)5l@^RwWD+-P3N5eJk4YDU5tJeEflIB{E5G_>JnRKwBx3HC!rS#UFf zDi~j87$f^|zi~M~B!+QZOH96K0wnu0C1W9Cv^qbbV^X_DRm9|h?zunK4y8j-{f6;lx=Al?W zp;Y3}Y4nxarq~soQcRXH&7`=PL^QqDKU!|_r&%<5Lb1Di$0mc=-{jdDuX385j+FKF z71U1VX#a55)&t6%udq&GNn7;)?ESAES+z+i+@t2>UMK#UjQFcZDRv<7t;9NZ)?EHy z8Ng3<^-f?CI)O>pm1Vtq_bYF3`Gd2T?FuM!ac=I;bjkI{BoudUH8BYN%|59k0i09* zPEk*}Fd~w1P|jOHLBUE)hsRl~$a+Aw)E9Bo$M*b;H1TP=EJMTB*X^^!*3G}c9_};} z5!-J|2Hhk+W6Z!JhMZy-s)yg4M$TU2h$9lxy3UiEj-+Sbe<)8z;r@J?w$J#C3_s9B zYMYW~^WKTm_seG__kjCN_vu-un7%5D1%;k1q@BD{O$qKgzk(b3gS_?nfa zB`^PgWeBdw!NGC-MOznd5?|b5vg$n7iB?+V;76FiwlKe3<7loal6VqU#nbmmi%$l2 ze>fHVxjs^pq=$5yoX(s)%q9m1WSZLA#$a%CgW&kE2@oB{Bqf;uk@@u2h)KMmipmlj zxS~$;hNx@e*X-=dAg!LB9!&%9k;;sN+4j(V7x`DO6v8h%;;Bb<3bqg5AyncS&HNC$*!Y_kk=B$`<#;^LGHy z$=ZCZVVTvS`N(IE?2#3e^6#d>pFeH4X3C|FqOFw0N`Jc1D(;rVE)jxDLM7}#+xx5&P7v4$NE)l zGE>Xc6->2L0t$uNVqX!@+nRcDxgWoV8#bg28nk9l@#=aZ{2=Vy8J2fS=z?=1t{{lX zIZ=!osq%a(VVQ5Y>TqKnQ`rIAks~;QaiZQwq(JUxJNS544^=g;sH04HZs@su&|hS% zNa51cD{N7nyA5G`OiPmSlyxZV+4CEsR%sLV3V(|0sX@9M0pud+b#-*=B3*$X^5~9D zcTCbEHzQqL-bV<#K9GJ6j*gB#ga@dt6eq+&rs(VL-X*WMFK(ImT_ON_hoAZkSa&ZwSVSndG*j@9@bB zn4B>4pRJ~TQ{3^2M9h}MkRSh?j(^yaenY@^9e0&7pKaP$AASRDm&_4q3GC1Q|1!3z zjX(uLw2AoN+&6j;7`LF`7mW7LlvcpH`2ZF0TpgZ&bH9lOuzr`eXq(p0npeO*_d5n< z?whqCk;uI^bu~4#y%Vqv&l~#gW2O?yWd9tNQRam^fJ(PiOHGK5HUj|dm`|UKb8~Yg z>@)ow#3(M36W1^5=;##W=60^Et`g7+h9#SAT@LQv*UtSpNe}f%J*nL3pO~4O>lhoS z0eWB8$*J5ButP!Jj~-qkl}nY9|9$0d+awI2S1@mCYHA+xqjqj@E-yr!5m|VHcCT%6 zj)AK(9V$yp2lDds6`Og8)g=+yRDKc^PXsFu@JgudyhIj3yTs_&SePvDMze%e+5I!d z^_HwgyfeOKJTdVm7bj;K8m&Ve{UqGTinQ^DP=)c`)ctrK&&g$REeOP-t*vc>^X^cQ zu@+Tq^I0y&ML(%nK&RhDn7nV%N0_mWFuk=1(!b^KOlm_CHw(42+>8JqXe!1(=Nb@^ zf^J_34;dNRgbgI^$}~?g9ciF})P@XM-66?6Uf#*#Aa9M3v)neL`(!m2-NE(wwD}wg zx5k*dvV-8a9V&b$!hvm;#%`}EbU`=Peli0xb(ZWly}v4Sk4?=bwMAdQ5@0$ky<40* zjce+8>37Y|%~jeGLX=reez7S0B_wSo~7vEK}2m}z3yt_jKKZuNpdGtcp zly}SDbKXQkm}~#U?6OL=0elFr(JqHg_@;G6MrW? z?)HEODcRsPBCTp)46Xwi)305nr}tpR0GKelO)v?%ig3?MoxWD}u7jp#%>2TF4&YW9 zUYVevJj)HncJQ2X0*-^iu9q}hm z1wHQ*Uc6a*wA~Gz`S!tebLuH<%8%R@aP1}xX4F#-KPR~iY3~)WtO z*#6e@0wN7m?MgT-UCBQSo~v_8=5v_sv%S@++`IwgleKF%TPRz!7-hcHP9*yrdr&*j9|GWlVY%Vaj2-M~s{=lI zf%e|WDU3}0fyHa{DGY;|Fs~fnQ^jw`HomqQF2ZHcMZV%G<%KU(de`3ltYh=Q$|{#_ zjvuy^_Pk}Djl^Jh+ULw=4$<=?Ca(is-Pxh6fnIm0Thbupsen;MHA<#x_hE<2*_g(o z?#AC2rW#HNEF&o=M;5i~HLGj0EGJd)S;ooDkNN@aii+FLrRS0>!{HK#Ifc5F zy>5I?3kvE@c`JtCZccyj{95fK!7f1r_oVoerjgePVPDt7qnca4=GRqj9XgUtbbp4> za8dQb4cJ1Qg_o|#B}GtZ#>*^`tfi{-j&w76q5K*5#oi=l9-jril+w;9b_}HP5DWmM zm5@8njh!nLi_SKvfQt>FFyNB7s3`h8#Z|QKl|+hr;I*OQVOUfCLv?W*SpE!H%5$rY z0W(tCw)c%z83E~R07SPT31GQkes9fUFw8kCu3euyy@e{r9E0@%j4umGbBZO%REaj! zAMPLHS$4Z7b?xg>Omsvii$2HM;)LD7Q|3@1>&IY9Y;5CE^klVMJb7NGJDKjhT%{UZc$OpyGd_oV)UOD^;840T9K-eKUM?B=Mj9f za%!AeF{`UJ=*GQ-xa*?AI=5C+T+vnyBLJwj#7*Pq=y-ITElIE{o5I^kj-G;|kNXFUW4K4b( zPWVc0Hnwi3x7>#??1S5*0_mcTjdvD$CZZth@#=RAb;J|jv|mRWHNU0V)C`DlkB2aE zMI6^Q;zb36+f(1jngkcYv;S`I(=5puH4)p>skoLCXdjE-y^9dPiG>D_=?Tqc=Qf1zIuR9gD$MPTCbW9@oHsx3XL!wh!AMMY&fPg6Vh->PCK1YKaH&XR#-{ zx13wqBX&3|P&_rw(M=a9-N7I7K)-Sbz9jOvkD+MBrP8H_WMXi(z>_EL-~y7K<}ZNv zszO+SG+G<}ZeduHVL9|QtbhhIq~OOEZ3nXy4a5^-VjS;iVVC#{QgPEkEJ&`Rs+Qs6 z+}y1#3)9Sl5mdS{5Csajt=kq45l-MmzUP!}I`vbHoV6t)M1?AnY~4 zZDhG{U9odmqfFv13ttL6S!k z2A<1z8B#>uit0Dul_LP@$z*@hr;$AO-Im7vXAJ;5psr>wJ(y>kxdsr7Q&!WVnD{Ya z!)NmNcZVbzuzKczFT2z{CLPuH^Y zazewVv@BdNd!$`xM`g1p`{eC%R4Jm6lzqW{DSHXx7zUDCn)x(0+y@bM+@qsL>+ z9wY;+2E{T-b;bGnNntuWxa0oSGk2?zDd^@t$RHqY*zkmh+Kqn6d-;{&rtdy5mugGu zu&??stc!O`$>HHWY9)FdtDgwZLCz5|=BSpj`~BEDICyI%{iU(aqSG z%LM!>@3;)W$aYlo$cs7Q#ems9^$NU_byzK#&jvn#zNLmq*zZiCUZQ?&8vzNlz3pzB z`p0f7zjBeLomZ$m06e=s+D}OW={TPup(gH%$EK`!{`&EEPy$T}aK0z6aSdSa5&Vre zd``FlY*RooZG_3~$Y!Y-hJYUqrr1gPjR0w~wdL%Tz3jW}?Ae4n=3>f!^PWT`9l*-@ zLa^74H-jcIAL+T)j&@=(<8CLMq%}PP#x10$3|j)$o*K0Vr9&{9<`o!q#YX>|Z(Tv<%4tX?kmykYV4zVNIV zRxi0b|I%$kv}YKf(a_Lfh&R6b=j#ypP4o7qR{0hTK5TE%*uj8I=`}fa!8G&% zwdneo;kxyf@#9NdfSpAi>@ZY7_^nSMdT*k+_1tU78*7R`j{SbQ$KqAB}di848%DBQwzZW(nS;CU`(+I9Ots}>=GvfBY ze7{?Mv{yIfL_^5xlH~m|$Z6{|DbOh|i3>TI8Mt-UPz@jrN=i!T-dZ(~)m!Lp6i8)1 z(n>8!^A@97d<=Fdgy)qBf+AfCBVa$ilw#?-(Y$}RpZlYle3i?Fs>h!yi!v^mSkLzN zkI=QChE%2#tmCd*O*BGGUfiJpw{0HciZQ?jGzQ3&J4g_pMeiko4>bnB-+|0Knd|b` zSlFhHs;cq+9rEdY*m7Xn;x8{6fdXr8E|Lm$9XZ>N^S@C6hO#T&rXPe{LYtX%hMa$wqA{R zf%)K9Q+5`}3ZxY8WH6sEdXlHv{ z+E>@iZ4w?^sE?22)^>~`|IVQAoQp*x2KQ^<%qFC%xqCgtO>aq_A=sySC{@>w7_!MZ zg^~s50too{x+N?1lD{pEN^x&5Sh*~`0ag>r)msr?a}__H0mD9ToV+SMLX&du+WVDn zmLO-8lN$!v24sJrilo9giz@xG$&Tn*BstU;6pUo`Ak0G z`rf^Hm5Qu-d2iZH0nt;NhxN;*_IIWFK$dQ0wTyIGy{d~`y9sbtUZ0*ssI*jR)C)a9 zL54kT$Z+GKc~Si5!T0y|?k3JmuL1doxq44QD0&I*5w4%z1AtyNPXc3TLG8*S%cjLM zNkVVbEC(VM!_fA>$hER+SfIQ$OyevHPDmiZc9wbRWQ)+^M7NgSH`18Tm6peafj5P| zL?MSqe!UJhr$>*pDA<4qZit{5&43~f*NOB}Z_xp`b=^v6zLDG3%va{FJh-&>D4VE* zQ6oSrzpsGx!Mr|00ylkT&MX(0DH3_#OXylO-I$wY8$(;z|Y;10EK zM(LZsL0~gprQWVyTd1O4^P*9@=lcDgQsUCnOcFz~FYov{z8B`$iQM~+;_2dKY;8D1 zvWH@$Aw!-4MV^zK?qJ0FJL(Ar^zFpeW&omr7{c3NOLikA6D$y+eC8VahU#WFEp2VP z1cCa|h8-Yp;xL0GFuQik7#9~++K#Su=k&Z&TFRP&fct>D6N?+;wH@oV8@y>u&uS|D zsutoa-J9}P^pn;U+1&@BWP_@@6yrl*&ZZ1Y8SVaM%9z29`5#CBWylT!1V~J~metLrB!O%Qb4L17+A!61$02<7Y3 zn~83u7T-0>nHrzknT=It=K+-DXHYys(PgvYiFLb10}SxdUlBbsIk*S-SsAEFcl|^^ni1HZJbEYfizK1pb}iT6?}ysmI_B z)c$2XVf|A*(!^e$LJjsJxpvfwuA*JC0RA=G;#=P~2IP>zfmB%YJ`#96`=bnqRs)$E z6U4?)B3s?g2&QT=00x!(lz`^Ff6burm}-N(z-6{$a2#uCt9LeGplRvKQW-#r(Af0G z9;!pVl=9&R$8cnQMVc~w8HgK9h)+twa$iaZ4IlSg>*l2v78M~61KS-$hhPx6HL8Y9 zyl`XM&Zqs;cM;V#N3V#4@16sXw>Q;hu1V z)Z5`jFL&)h!fj#Y)$wQ=4{VczbbrEUg&K#vMtpWO8Nc#Zx~jpfin z8g{{*euZ-ioDdii5<)9L;|g?NPq_q-0}{WXeR0#3vsB$}om0%=c|J`pa3Hd* z+(~Y?*~x+8PJ%C|TX|X85g~V<<1Ck=Y3VAEa0k=d>+9?1%t1>|4@G)C7o>e2-n2>6 zk5}F30eAvvzKh}6{;FrdIx?rA1!HJVdiq$aetB)ZmdInrl2H zAh(Q{;MySS*aLTeW3#l=t}_|?Gnr244G) zfZ!6-mYwYb&`23s0t~dE|9=4gpUl7&21^?o1OP>UgBZR1Q^5f#K2I8eFGw5|L~~7n zn5>qJOcvk}DSj9IQeyj0xK3bUr}SU{3*bL{xYkB;4mgyp1N5#VFaOc71H!(7g$^UjHXKM z@`b~Ng!mh_7-XTQs_ObaC1tQ}Z{h)vUNVF2uOk7^+;fT_e)xliE&+&KIzN7F_h+@u zs^4n2Ve5yUayPUM3>tVVeNH4W=30n&jyj-{>vUw|I6uL%4iRg{+v<6vzfaqu5jENXEF?RJef{ zR(aq0G|Xn?GY=uJx_({T6+m19jJSH#)Cbo>_+s2u@*ipt7m%od=fke^4e^4s>5r9? z#qK^}p_E4`C@K~PeWPSZzDzQAp&@krl8Cst_?lC$z1#k}zJUFN*Q7xOODMRxv|ZS^ z<<4XXfJ?-gWhV*n>t*3h2KHXb%NJBsd;=UtQ$Y2N`kljjoq*o<37M2eM>Cbd@q7Lb z?si(d#r5feIw`9I9I3;f4V(sK=_hKQ?Yk73eL2%`E`^`QZQ!qYsV`K`H%pD0sR0RlpN;Ko*mAu(9-YEbum5RN&dmLmKbpUFLp#CP10U|K-sW(mPD?{0x!4sA1$w zY@bIS2U4Q<%G*Zd<#oMNBFh88`Xqe<=&xRdF`f_5DqYds(In4XfLdE`6X8Z;&Oe9n zb8aRHK(io2c_RD$X+LQqzPflEfnqZvwAm6!PFeB?b)P?LP&=ZeX8>UcOcm^C9kY}H z4iR4JP`TcYT8ggMQI0|~V0mi_A8}m-lH2^uGaT*`&Px#h>Ng}aYZA_ZrX0?Yl`0ko zXLMvCH@#othBFqHT})$IVu>^6+nU~-VLUpX8c7isx2S_#7v|>BS&EDWRqi4C6DT2i zyFBGWPCL}4r+x*}Xu#%4UL@07LFLP%ySn6k3ckulS5|wA-o8E9S`sE{sJwLm;LzJ} zux5-KV~EuxI{g39^%hW3ep~;zASj{2NGd%jAW}-Hzzo75C{j`i0wN;a-Jl>Pse~fk zLw9!!NH;QcclQwgGx)vtzQ6x_-?e7BT;upW=j^lhK07}#k1k4(iY`BO>SZ&ehi^j`_GJBw{j*#esa@q>B`N^BOIHqhah83-NS zuEKSsOV2{h1m#%cRcV4mW%=gFu#wSF^=yu~NZj1v!*{#YvX3nPr;hu3^Sxuly-Z|Z zq_Y=2K-fqADqSvn9aTT@dIfLqkMe!bGOGn|SW&Wyx;ojX!G{|S8MVp-RWyR8n|spI zB*W89ZN{yky5q-BT}+gxXowB_PG)t5Y>kQIO)~k#?5<|d6)_a4zAn`FEm3)NG^>bh zyCBRcJgO!yzSlUA#HgZOgmfGbd%w5LdP2=rxfv?oB-E1;WaFHt+ZRMM)7#r?veauO z7Hrpz8W|p*#jxaBWhSq~`#VNPvRl-n)R~iDuIh zPkBKV9$Jxsxq*gP>flV^Uk zxK&ih=e^e(h*zz~Zfhy9Cat(Iv-RVI#Dg(zs3r2jOntNyfc!aYG_r*#=zC@1Ko$auXm!~eFEs2x3U4kqc2#oys!VMCmY9Jjyz z4EZl2M{rHmWB5nImz70os{g|pa~CZE{>@nL=6?@rfLfkPY(3n;PQ&7V)y$xr%@q8g zB6;e6uk#=2u*cTJZ7g{A{5PW6tanvoX3(*xztVL2hyRaD zVEj}8e8-Rgo6VPpC|#0Z3a|ziY}kr5Qw1xMX@lIGjDJd9!?1$47Nx? zt^QES(8$R0j&=0k3cTtLY{{=Cra%8DsDlQDMy(|Sebq%@!w0?tzyuJfmt0fFbXSx2 z8o)>FKvI5gcJ}be?ZiOE6$2NUE!1my`AO8kzym{(tehnTosMet6G}S8lLxkQG;UuV ztF2!;o+aq??;v$lTWHr(OLV>-gn7jrcnAk=VFKN*OQ43)Mrqurw3)#zJG-xrRV{pH z)QLmg@8}Zu>8f1!p7fqgi@SCJprrqDB#fNAyes~`JP40iF*PqaqF)Kmr_@e_@fF58 z6d$GfhxbUJdt9;@7~U;a&!gmeEVp)^Y)A$f#Dovn6n5yte@-||^tdMI&KzVps0q5l zu|Fu(>Ij;bzyuBkHPdHh%*`AmVtyvfy+3$=9#nkmha{#ae+$!N($RN!MDD}_Wyb3| z(L~u%^C(+E8CXp!*+!oZMC;=+`YYK1nh$(6mFP=_a~JqWfKBdL9^_ z>c`AW&h)J5yB3=k%t7qyW7sK+k2=UR&o4p_;3E&bN1lS zSgqlZep?GtBHsl0=S(@c`D`40(>*%AoqbPyxrBn}fVCO$z%|BHa_4G(Z1!Nl1eWO> zSPdsw4dJvilQk(bTHMF4B*G?Z8*0dK} zK1`;OQab>FW8Qc?=kvb>%A*rEJz5WOKyf4eAk#7bnHxL3NHah1{{!5Si+j~yb7&cU zhUBXLH(fo&*lkjqQ3n!AN3ot{EZ4nL{T?uqu3XP_t$b3a?re0;_cl#Tcu0WXTyp{pe5G)ujDvN*lJ6(=c3d*0=*5 zAXMPLZ;jKIr+SE7gnGVGd(e0B3%?Hxz5EnpO_RR1H%zDfUC5$$?E{>g;&}H6`1!gw zO9rF)C%k@tRkDpfGQ3XHi{Au(zBILLA*%b0;49Q4{!Gx*-GRJn_>mIW|GQyg>sy;h zesO8(wp<3`%ZPV;L~Q*aX0c}u+A6|djQ1QuCnJFu?4ixtT@!crMCw8wLS-3G6f`2Q z9FtJvSoDf)U84pvLfwpu!mB(cGcWqsjd1#+ebWA*P=T}7$w~=+N-GQ$Cl3Pml$e*m z!h3P)eF*`h`6%A;_J$hAwRJ{l(6i)#}tftN~C-OLExB=<8s6R{zxD_kJX5rvI- z-L{6NddMRAz8-rn+x817nK1IfU1Qdbs#!XQOf-0z+(o_J$H|E7Z8|WC4PNROOZd#x z?NZyVF7<%gNe`RLuhl18JTWsGVsM)|H<{nr(sv3luLR$VLb01BdSesHk1wU*^S$NE zbVQFpettd&H+Pr#sGlDZi4g_u0=9o2m|+vHpk@;=vBRdiqN0w1T+gRZpY|O-L-lbtLtA*UcI1seXxazd0I6uB!d?M7J~`eCr~>Wz9``iW$p8?3y{FYIf*? zEG~TNcS*!p(zsLnX3v$e_NyNQt{iX`O|?woaFkAt%d=E&5IJBT8W{Jb%9Rjvm3C*B zPP1z%qg0iYu!WKZc{-@0Jj0mg>^U1c{63=3Ha+B=eFHkxwISycZ3ZGH(h-3s*6l_n z0m?5V+l(f*Fn#mWD9hc`;YaFf@6kaM%^}+6{Gaf5@%=Pu{y9>x&~t70zEiYol|R>5 z4vP7L*IJ>Zr%~A}f%ncP&I8LvFD@MFGF*+6WMq8+ZUf?m#uR|D(9-ad-KsN&uCV5R zWp|)hM~0Tno>SOMShs*3K~JhHVjA`rlaP2r-ZJLHk7sW*y@Xl;sFWBI>e6TZgK0!ZE9T zpa7MIUSG>@3~k&N-mwpgOb<^1gi&X)3EB|Y?72qS4*noYFw|hEd}m`gZ;ak)wFjoE z#X8;fut8FEgS#q*pDyTNWb^T>XP>YZRX5xt5jKZm2|SyesL9I5@|=6^CZ*4L3C#J! zqlXf3vJpK5$=`Se&nLXVbPyg*m;EvrVN0MU>G2Io6r?(tw1%|t9D(iHF!YosC*MtR zw+3A@)9i-oS-H90X#ST`0u8ns%r@B_Z@1_0$ffl2MXgiN6 zT|K=&*99xF1-S2lFYi#B>CzSXfOq$rY(bx#*6i9HrM0M-7;R!oj$I5Wd`Q`P>o7N9 zyWN`ViRu*-b@9@$Y@J&}34GE_r6s~{9GidzmFdA7Y5f7`wXxkSuL-ag3gZ&~uGx9d z`Ps^XII7Dh2`+l$!g85p^U%T76hX#4?0G(w&hCo2UCvT|njPNP+ItL`AM`qD8UVR8 zFmq@_3;PUMAe-tc9f;SyE6Ns8Y1((jIB)yP$775aJB0W>GYiDT!r>Kse0nDaiP?g&$PYCdhy!bzICi0vBh@zs? zS=Mthq>~lM$3KqWwoM*$Sm;^><#+o$Zw8u=aYp<5d$`0_G92HayN7N5lv#Njz~Pub z=QO5fB_MM2Lrr&g?lI`%3zZb@%BuG4!2~Wmc8C#thHZ7Bg?lWDJFOm+Z0bNyoFBP5 z>9qY7FlO`BF3&~1XWO)wnJ>y@7Bwa#DX$ZW+gS3-RCyH>Mf5*p0ty?AyIWlmc(>5h z488HXd?vhp3}7ahUG0f5zYpp?ip?fI0%)ILP?w}GCK}#H{~gq}AFth&?%YPcU6UE8 zM)r<@-nWgnYvg|ZC~PyHLxwl-TOB0UicQqTl1(_w2kot)CH?*6*u1K0Z+IBpb{_ld zL2~;lqBmI-d;sRf+aVp)B5?Kj7J%!*#la*sal(96QEg#nV0%PXLnF&fyo8G5kqBO; z!zt2wA7`s3iF8rg%jFd<>F0}HW?&BV+{=bFf?MrEaKc1)dBtKSbrg5S6J4I|Uiw?Y z{+!MHWo?EIz~e$RsCq@I!Fp;{22#}|ag+;V_S27uIGmyie+>rgqtV-2LHB1}=6|Fb zj}$JAKY2Qk%Vb#utoDg<;NTakYQ7=+G@3X5&2D3Sj7d0)IE(CtcR0}kW(}w-nn961 zbq*z^@1Px| z_R-DY?C-CsqciL%hKmae9jSkXg^g(z-GdiJbqoJV56T@8OAC`o=+ZigER7b%-P(wr zy~Y3cV5x;Y7C%28DF3YYI~*84pqRGXrdzs2Xgk&+kQ5kd<=B=Mq$R~LJ7U@3l}{Rv z;!^{tM?&#q)6qk7%RKz?XK^4TB`)vv4PY3_x`($UT~d5%mhi1ONB*@={{xZDTCE1c zjucN@A~NxeFW1Z(;{4D6Agi}w7@*8_hI^eYyc|HUduCm?D6k;yAFnJ$HY# zi7J+uRVu@fB&CQ!`7B%W^uuC>Q@YFcx7aQ4=m4ZyVxInLc@;>$!%g?PlxYa|76-Pm zVUwwx;?!c|lF@As(n;BEvf_KxgGo9)ug$9V8t5tIq69<=Bkf1;I~JLwgn%$$UbTJq z_ZE!l2X=EMtd`WL0DU`IUBW1AWb9f>ZO>D)-2$&TJDz|)7gskFA2d~zS5w!BFF+9NIEacy2KDyW<4{mQ$87v7_$ro$64)8j|GMGm5KfQ{2J)PO-Dj)&HF=K!W1`Nj|cX>r@xRHmrz83tXB z4kUI1pO{!#QG=Nd50p0PH_iEP2Yng<1{1o%F312)YFx8! zx{RtY0p&L%%KWA>GDQGR>hk`4)XM1=sBLL@KIvEQ*re@bc3cd&(IyFLUv_nt=*Ix; z{aCpTD3ueZKiU6C9T2e+azAd!y*krZ85uM>GuwjYk{)JKmrJRJcDuq0wD+(E%?W-z z>PzWTnvlg#*+qVs=hsEyrVxzNGladJgM(w&Tvho~6}}geW#D0zGG=)Tl+bvS`E?L0 zr`)f?%}Yyb;VPXBH5bbt7}pf#yb|MjytQvQRQIW`+U6~CIv_9GS1oNJ$)w z7V|POb`VMN4^)omJV-P#WH5}_JUei!m2=;#C+_k_juP6gmn~ojN7t(kNMM1TI=&Mn z^^Zj8l_w2<-HzQyL;8!p5Y2vD(_z3MHXVDxuMX&AR<;)H6CPNIJj8#PVzLI3>v5np>jGAN_Zz*+@Qt%;lAfH z{S1#lTPIZzebC^X;|HQe7l6`{b6MH_U>`>JgNPQJwB=F5dm`3V_xpX~#MZ9R7gxLP zBG>cDg;sqB84G~W5WI?eZ1*-6UuiPY-&FFvm}GW%*D8g1cAzUZ1|C83K`YZAt4w)H zaZyT}hC9Az=G~S^Ql*xRxV%)7D{3kOd7!DL+FQ|3gvVm~&c++3$yyi|=!uz=WdF$f zYs?L+lf$iQxL00-g&)#%Fa9|yi=o`v{B~fMl4aoYoOF=Ebu-zs789vrNS~DHT!>V_ zdVO@bdG3NIeelWWaQJS;^VPPam*-V7@uK9{7A-XX#%8|cxVxf;Bx1P}yCT63@I~3r zd|>`Jb_t$*(lh~GTX8X&*p66QGY_uInx}D6vk}gmiQOt;49C2iF}Rv^KA$>QS81bQ zE-C4td21Y)WXIkCqocw#45x9+OSJ>cr8%r>D+W%ejR)0x!mh=MPHjC-S*aw`YG2&# ztZQT+IpUE59;zd>+ba;O$yn0+B+CW*tX7}8i(T@<{cH5L-jD0*>WQ!`&k7bi_8;}2 zr(oI;#eahh$UU;S@EA$uK_Exl7%F1VuarfGFFST!BPiB+JADfAamEEQHsn~oI#I)| zv`wE2`rN&OOYSHwgzvp>ifTD4r@6WVq2>gUfW)~U^N%2+*d`X)TpBCiXa-TOBoJ{r zqT2qfJjTC0deJP-Sccz!LxEL5wL2sH3vzjF&B_rfISSc*)f(kP)rK{##F>J_fBe{M z>J;j1ZQX*e$v2rm;iQi0&pcK?;rrJU4$c?5jPLrO9*)@f)Nv*+7uLjMF>il9$S1Ts)<+ZS z>dqFY?4zWtJfO>%!NAqjq_f(unEFSWTZ92=bKp7mo|Ug}-{w^j=*UNBzOhSXKu?ge&mT0dJ?Gk7=2i zyE=@+B2VS+Ry@UeV6Op=%bA)u{Hjt%2KUjGCtgAHQ&yG539+h5+c)~Z?O~$@b(D)z zYC*{_2ih{9DEFl?%s3WpJV7=g-^lyp%IB zJD!xlSOrNpP1>&}1=lY$n+G=RU}#08Np@X+?{gyP4Mr)XK}#!7HWhHRPlz};~aNZV4GirFmi zB|OjCyy)v!90rnBKml$PpFzH=5o*4~3x32wfD-5=BKALxxPpI(G763EJj|l+bX<>Y zuL&6{+5Rg;%ugBjpO(#hwmJ`b4(GKIQ$Mu{gAM;R^1f=~xM+4$0cdTIF>^Zk8lCnE z)x|D0j_7!O11n?@T#c9yGMuF33CK{vp16{Qx)gh!Aw`0;O9GUy4gL%Z29B91>MTpY zb8Mn;)61zU?%ZGfGlxp--mBbE8Dus2wb--I@PZZgcChUoZF4OmZ4WAJQHuvhydg)c*sM6A|)F0=) z*jx|vKRPBulAFzu?!9fq!+J{Z9uZyBEX_#l>oPojt6JJd<u zzT^@yWc61L=l(|ziza+N{^MEV;cDzpt`VqTH9`OrIa^@$kTgNp=}bU=Dz-iYk(!yg zy6KUcxUCo;KO(Hp&ZXj&RzXle;WF$cM^55*uraX`u+1Ny7Ft|h{#*Txek@2o5;07wH4rWnnG9t|(>u%lu*~;P1Znxl zhQ?zK_c)Zp_Q>Qix6fV@Q~ojq2oW=wNI|pss^jGm(n-@|tPA^#!z`ZeQ7-%|XTxB& zh7M>M$_G`qUYmQpqy!uJ`45YxeBQ`K^7O#pvJ-IKzkeO0e+^}0N#J$g1^tA@YYGGh zw&IswCoUUj@d8BBZo%C8gH-(8+n~wQZxs~tPRP!VkL3mQALY|zpRrkB^nyoZDZ-^V4LYtS*8wWIGrXS7h)$If4LVvU!_ zJvCXKoTh!lBm?35CVC1A3IsL<;**bh)Meh<{!v~VNCs(p(+m}nX{Jn9`Q=xNifc29 zqJR4P7nO^M*b^C&MsmbDcDl46NbLj63Gn={Q8c;jxZ50U6N{LG022{wwE8>H-5FdW zTe_GaeX2e*4Jv6X9TKa~jx$npm6bEQmBWfaAY~S##3Q29%;B_}CmHm_+A9ee9LTPd zcvYD*gJGX2$Zl-}BDVIJ$yufVM8w+9GbLBNw7vb=&220z1#*%=zT`TpTIi%#e#6!K zM%b~AV<3RcsN5&p1kIxD8q3Se;+J6ee#vj-ks59g$8RN9e|5bVDdJ>Gy}?Yc*7gi_ zCj$6yI-oteF0Qsy*vf#~GKy2PvYp;>5yqfCdz-FJswTXuI_~iNj}r-78S=gfCar=( zZR|JB-6WMxoDfgkn^FkhudR=?b*P;_=?NQ!u5BgFnKjb~oeH^|ToYi?`!4D(e~F2Z z^tlw99^u@tC(H1z>R;>2DtgM^NXIUE|d`$8Z3`@SXJBcgYe1Mw?#$om8~V4$e}Z7GW6E+WgGB0<&n%3Tfd zj~}I_l|_|S1L@ElxA(i_KT}qXR5{r(P*2pA_3CIPUKhw(oa-&!_=CS1BP+(L36 zChBV_K|1%a^%Qe}(YdS8NDzluh1Nm?H7%O>BEI#Zp`N~HcYjjCS>>un6Er~?is|$U zW`lcgW{+peYOK6SU|f=+YC|PQb1pFit=7Ndw86QxZ&vcSE@qg-9HEq8tix<_B>LelWbNoidNEx@<4Z{ zo6LT+z)VI02Cv#(L48rWf8s-eYlb}Ha+46nLx|$ZvexS1vYsE(E+8Jpp0i_50DMRZ z%yqBEk|Y^U3dX=#ac`Mmf6Vxp;1|p0U~`taU1#}OuxJZ&Z{f$DiV#VH;FH6tgB!Nn zKAM6Lv~NPbjb_ib&22yHMI5p;*(`a%N(pbJ-#&CtBH5;f)VK; zRno_m)=NUB-EnnIxIAK}Y+s)jK174UnZvP=$**e!U-V+f`i_|o0N7~k8{U(pKfI`B z7t9(yOE$E+_X^W5hHrDG6m%9g>kUS4rr1 z(R^fW5C=$08O}t-2A4p^Vr*IJ?0gJQ?3x78nYL#APwA%zbNK{-FYi3^SQKiY(xRK5 zCXTIfrt%p|F0pvOF=I(x#BBbv)?eSV z_Icq48?N(b9Eeqf{_NwmKZ6o=DdOJHx`Ogk=256Sz{(l2?1z5cTOUJtzBPX4d54?h z-gQ#>f&%q7F0O1%l&|<0Vc@QrXjFuTL*AoHHWqifO?|e06y88|lfRzjnz3Lm3EmOh zZ9Usx6FM9%GpXWn9POpdd{gi{!8*@hUmNQ2yue)wU36bi`d)5}CgS7vNob$IixN@` zNuK1+Uylno@EaR_BOK9#6p|{uf*?Sg_Za$Kko*MdXFpYc)a-Q{66yMT`0Fj+PEVbL zpRHB?Ywe(G#Z5mQ`i_D=zAHCCgLvw(dNbl=ZuSx`mzIE~1*#2!HIUp-P#?-XYA4Rr;NZkLwKDEW@Y1!6ZC2mTC4!h!?bMQ5&w6f5JG|<+h3E7Kzdv2+HOsC$G~(j#5zg60_{4&<2vb$GSz;7FGU+} zrqNhLbRl2`N5+$7Fq+%8;r!(n{HlUGW%X&oZ0op+-g%D!zK`Ll98|fWdYmgEUu&nS zMne5j-jTNGZ=BBcfjbmpJT!UV3qB=r#gP!Xyn63u?&*?;X+u*TGuN1ztj4>+T1aht zizQy)fl@vV+wvh5aXm>x=W16;q|yu9*Dj+*{7R*)xqC8b7cN5}q5E?Kdcv;y5Z@O` z%XObIGNsoQ>YO7%i(miVqD67ny^0pRdA2oi*!*o)s1u}ki9tImZ`0${To;aCA;tML zwqJV`BqO5Uy(oN8{C&UaXV~#)4TK4qj5I@hcc9PwFwpoI$eZ@ccT`Yo34FBAwUirs z0Qtc=>MhyVTURTVqDJd-b%Asf_Vg#&F!oZ_s1>#p66iD0|9msoa3myr$A5&B+v9#7$;uE8$|27z6l37J2M;tIs_}%x zPT$Ej<`?QSEPHa=e3HxC(}`6S{0ce#$Y3Le35C6I=0smLd6hgVw82muHa1LZdedG} zSGh$Fh+VT>oN1%R$^1?n0F$+y4r5rGvMSi(4e|QB&AsRDUBs>on;8Fzd7CW*A(o zo6$&HTV&YZlX^%tX@>yz!N&U@Di7#g53#LX^!c@;1adf`P$30SAmG0<J@xRKB@c}{Oxfqk{cj-}?uYV%Ku=MOMCHQ{!((hdF`SbIw zjS7p9@B9~E+heck_qP>Fwr<+d1ZCtS@It*spFR6h^FX5v=dg7qN%%rV-eHp87B5++ zMFu@s?sVMaxVZS`weZA_J$qwmwy54qA82Wf8_;4`Dy4y&N?3{L3LR1uT#_1-VCtd~ z#F4Eo)bFXc1cfOtXJYQZVFk9^GT!w0=f_aBa;;Mz**zPUbFAGEXN&j3&Gq}4ak@s( zToE$EwT(s^gOvzI8$z(sPq;lkY?>5U?vZr=#xq(OOhe8d{d^{h;mw6b2=Q3FYO=)8 zrT6;_Oxl&L&(0YGSH$#dUZ^9+Ji_nJ&5aE~pjWs~JI_x97js%#$bg)84sWtJLNda+E%Xnwrl+c;eNO#NchcW~#3 zDiIr&-}t#M58a*g<%`beS0*4QCtt4m!TyaC4mNi)Saf&haF?NjaMAB2xTmnRa>TVc za!`(NVLfeZd5Zle4F|g#sC^Iv+;nX5=H~5gC1psOIPNcFgTc%nMgV$%E-)b*ODa*k z+aPu}6Y9f$`r6c)_m2MsnR*BT@$Mb9`^IY7^yr;rD#~HcId~E8H-)_gGB-E(_3T^` z)FD0&ihEs>5!80SN)2{W{mVFU7G!Lv;*VX62bF8|-ZM==zAZVue|TicvV+9xo^;8$ zUA>nlcz=3NQ|MJ4E|_5NDP!W3&%r@dbs)wjm|k70in1Gkczn528`M6`cAO{~RDN=D z@`dlYj{jdyf5GSq_es=#acqoWlS7!_^NJSfcZ(;SSuiKMHNrono>P2N-Qz*M|>p(n9GD-^)$$WA61QYbayV z#5GZL`F96#=QDwF{?9YMbnlq;M{PcRHP{;GM^(b;qs2G2wec=F`=Edls zvRhC*w!$u+SFIq`^El z0rd7DDeU15qaxg+X9Qd>NR)_^v(R6K?T62yFZCBM>-pk49U zUsIi3T{Fpkf29N9$}o^vu-~O?%IP|cq=ac5ITP1&#oGC59%k1q@J?(TzFmM+tFn}v z83+Qo6H`TljE5F8V}nm@l2dO!+@Tt5K%<-8p*sl?xlFme>fIK zfY3^xW^E34mdMDIgWVq~HZc;r&l zI{A4WKC2fR@fa#EVo_3^NjSrJ!`zE-S~TCk;_#*CL)CTCo(w4V_|p+_yS`1KT}evs z8MUwi%NRnih&F_Fgd6|8HGs71C*e)ss#4z;FW)6u{bCnQ7DP~)ezWHVJ9ndTFBg+( z#$RpIALD)&Fc=f9c43MsMY`!jnC7s6|rrHIW0YRbroGmIjGNG43 zX|Qht(SSRfEdAE4ud!!`{eW8{4)Hz94Sm~kb=fH@Hg*FH*I6;GIpsPSwUVnSG8$51 z>%aK`ogk4?u~EHI3Zzd`-EwmMPXP)5Qjr0y-GFcw+@6SXpE_ES+Ahf9Sz=-grS zD0$H7XAG3^Us_7N!5yHolg68BCi34UK&+43qN9N~R<@p1Liw70ba_NwNof%@y(}e~ zl2m};V=3^k%K*|yS&r-8ie}5&io|Gx=B&vIXeF8gsB;u{Q(ih_StaA^mR37&L2$*n zf5Y@(MeBT;c(?@nT#RuShvVq`LRn& zyMjYlIpCi3uV@6|1Hj?-zM1@MsVRGHCDqvnp<>!C!SUhGwEyHE7?N{J6Mfm~tf*b+ zqMIHmG1~yH!XoTwmYKWvV<`#zq!z^HX#G1+n+2=qm@OqsCH%)NBQ&2hN$##&lfVw| z4<$;<+3gMVIde^LvCLX3#-=Og6uqqkQNCRDGE0eo#`*G($!8bhzDLksQ~JyC>s%ht zHb_z_X$r}?)C)@gV?vzXWJG~O%K^FU;_@8lxs`0)HV!iN3>|zEIAA~j!n-5kN+g04 z&KYwZ9i5#3BEjyP_^8Q5_2;?ij^DrY7iJGcoDXx=tB!dOzyvzDG+{`1xT%hod7XqQ zXf8S%M!s@z%Fqc~zBtqEn`y^M+DjSI$n4n4%-J8_ z)aAeh)%(PHvAbtOeLm49vF>B1b1T#%Rko@*)pA%not|3q;)Zz@a4A+WDf`|%=i=`p z3YLrhdZ{IkvtAV0H5TL;k|6yq^iCsQ?`gEB+xNyZz>`2w5HNm|5hcirdlk5|rQqzx z$b38pmwofY-dKJ7#5tq)@uOo;LGH*B341|GzK(M-pV|26L?cH@zF{g|BAwt%%x>S@ zI@nS8w}ZkL4}^Mqe@4nl2GQr0Bj&j@D_c5Z&r?8cM9JLDUH%4-%ZNkQj|!Ebn$Da? zAoHL&dbi$8lI&BeoLdjJ=dPFc-40UuKBw+w!FS9N+$bcwbNDNt!zL17L|+(KCvwd2 zC#tHy&frqz{ePyywkfVHyKowQiql|SCwmo614fp-IHYP^gegR0KX-0*Ae zzqtNMJ<1tLqmwfHV+JndHt8nL*ayzAkLnj8kqfqM3=U+k z8HSTYCqL?r>T~`{w1*U^7wT)5IYaD~FMh*M(0H)J$sgG&jXijMd#vEQ-uU40FRHi` z^!td46V>}fk6yw;DjLf+@8TaKVl?SNqH3sPz_9R%@*D83KZJaXrdCDYO+r3()rBJP|SR z-OZF;A&pLd(QUHHo%VB#BG$A5T=@S(pq(M`P0?mFG=B$r@Xwp zCbb_R_8{PDgJpuHTlQIhjV=jbM;@O{s7}lz4;udlzL`fqBcq2P|NI-xzmE0A<3Qsa*pTIx3K>h7f;a7CnGMiqB^Tud7Pf+wnl}uLX?=m3Y0&p zx&C_vd@pcMO0z1zXUp51{&vb}OT77PB{cgO>lAt%--&A(Jx$5Q#< z9F#}MH@|z$S4L&TH<8Ewdii%xUK(basG!GV42vxhXdS}7rShh6~#5viDmi&LID@sf(94jAlfPhEg+$n;Gb#XylKK84H2U9f2yl0IT^0EBJectBR{??UFb0~j z?=6gg#^13tPEJwp{P%hOXSbp=O!8Y4>;b4}Z!Q=TIDyY}1m*Ytvma4Qh*ULOs-nbr zDobZ_^3kvd-+59>lOWs%*%HnE_1K^{iPELt`sDzYcW@w&0xrGJIKz+qA|Z4^<{s=} zET&3b`OnKmXYQE)zK>&YYl$nv>VCwZ>M&`u@F}gK6Wj-QUJ0MXBHUJ!go-i2Z6cPq zRj=8_XMWkfx%)4&13GrMU^U7IGN{#m4wVr?z_?zlAGJ2Jzx-i-o=#-Rl7zv^3tz%> zX0XMJ1-30%W$?x5=fJ29b$3U!u=Ob2XdxP*C9yL|kj(yv{a1-n{fIOaTs_)$AeF2f(9)t6z9esSg=5A2 zcFxTR;-Q2-UJLn){L;Uk1au!k|H{}9BTpfTdow5fmb8_m(R)xg!^jYM0Q zC-~g8KM9;zo^ZGvo>Zk0`HzNlk=WOjwAd^Tb!_wv4IFmHIg(w_94kpc2?*dGH~%u` zWq14c!Vz&d2!nM>Ok`Q@oF^a=ZVx9Ae@bsilIBu51+6{)@YtoGqR=MQ&w1qP#q~<+ zafMO7;JeWEcX40HFP^yxxYO{~|6rHPq-okeN3P^?L0IlsS$3gl}jm6qX`oJqX0sCj6(IT_Ow+cO2rKt{1xx!?1aL@ zgoumqo4lXsvvgHQrvD*xjJOn}n0a&dytCJuUY6t;IrIqc#HBF z(-;q#F-7;{#Fz@Y+UL(;536c3%U`Ow`z!*IeA! z1%Cs_r4wdlgxATGBpW5rvA1kf{N}S37M%KMKSS&Ew@mbt0cZW?1-t!KRSgvtX$A>& z9q|s`D9BN*kvf8r=C=jqCb1(GLdvaQ>~4aoqcTd8lWV=n1pzi|MMFPJ=}SBYLJ00q z;~>=CAQG3!Wi|O*YOhabT!@Cp;mzP$8m*XRng6JXY1z0Qgw$3=g&znJS7cR`*gYou zQXVsN(WBC}291P z&JeJNN0b3JbhL0SoQN?89UyEm74Phn1?0KEb`-C^g)Y8tlXKlBqd7P|n6T3V*uOH1 zUXR~DQK$moWb+0_jJC$dS%$9Sr`v;4o01m+>Axz>hYBd)Eoi#yztzI4PwqnjO6-iH z2(F&;1(%tJLzzWgQ7aN-!`9b)OuZZ=xI~!8Y~UraZo4)WD#kYcX9v1=+i^isd+D@> z>Wfi}?QSP1H*4V83FK`~)_tbL_tO_N=)Kcsgf6!+@)kWFR5vSQmJE#SMp@v!8)3$! ze`H?U?h`;Skt-eykaLsg3?xd00QLdZhoGPG?MBOGPz<06>D;`LJZ*>k%-tVdQn*soKJs94Wny$<*s%hUKOavemC9WXla#Fkt?* zPDlyQaE)6{07F8YxX?(j3XVc_C7AwMW(wd2*8y@cuSW!@O}Xvb^2(t#!>wDOHhSC& zi%;HxZ_Akd@aoD?4maiG5}A|srNnLH$w!zUyv-lgZMpKku`LGDwHDC$o^96Nu>Y3e z@dUufbJEjHXuF@cLyB{=sfo|GSP$j2hM&?6-clHD*L%(Eac@uQ-!w-s#sFQ{{4M49 z-{BNe4{{dwQi&H|=1tU&g{vqQ;xBRteCEi`MO9})~cT>UDJKQTyL{7 z*m0ejC+@W~77c$A3vKL(lamgr2NN(rubDyVaCvOtXNNk1_M7hj`r$#@P8WQ_)bQCZ zo7f$j2#z=Jq4X}y>(~Lc>&T4khd8$$gennQ&9_^)0kG=TBP?KjsWewvBcd9NGU~-b z1{W_xXt|bQqH2z4oX!9iWjPkR`V>=hUP0&&5WDj#3ua>_B2P-(FoJC|=o~FL8IkXY z=-H;Fao90+9eGIbuc9Q_>tf>{64Ci2bz9iUY|EWZ%RC-y&pM3EY3EVF4aeQZDbQN> z;GmhtEb{OLIp>)$7*e|qwpDBZ1GAE8%N()87`9Hh_5xz83xhGzv`r@W|E?_ApHe9#O)JtDHqj*~h8Pptsh2r)8~ zsY-{Pj|FCfnQ!KI1Z$3Dq%%C=2wY}&w>2XzUWLeS_@JdC)9G-^+k|UT>u)ss!l;>+ z0fupPe_t^5wRSWKZORJ(~a<}-3HX++ydY>viHBt?oL9~I^4EJ$# z|Fup;2k3D;d|Q_I@}&d^J=`_Zre3C(lwW3d|NV9oRZz((!lioq_kEU6(0$0*^YTvu zCTf2y8uc3It-3@|h;9(-`>{z4HCQrR>}CSkgiP}^39KPi!-21T z_f>gDkX*CBhIWEDe4;~_S|l=S;Lm~X!u!QLMML8}Prv;t0|}#T*Vz0t_2uig9yT62 zgPG?=54cMwan1VPaX+Lgg)l!ONB3o@a+AeyS6PReQAm_Pt8dT_Phea|8~Y17pR^I@ zi;TvIIJH-|e&YralfIiC(lMHiw$7e<&#r{@-W6c%WM+5UaGKz?_*HiIN#v_Z=9VAQ zc)EDjr63ZRYj2EaG*A41Mq$5Kn)OJf(~_SV%FJ=TBjS$M>P+8u5&+m=M*%S%E3alsmWYpJw!X8NPb|N6N9 zn3x8*r~~@_7n=N#!|&IQP&;qeL&zu=CbLXcHHXo8I^Ll0;j_e;OSkHsxL%thi)oe3T=?u`CH?4kze*Y^AwV zKM^a#2im#qKnyW@E^Mw@&nJk$J+qr4j+pj$^$4l)tr-+rcZVQ_;9G`jj(`Ohn9he#O?W^B zMkDkT5qv?sw{(E5`OHg10^O7zC4!+iP zkRg`*#jLpv7)S+M$)q)U?=Z@e`TB{zSSGZbyczFbDt+{)%XMCnt38+RW`Bd$2-Y07 z3T!mSYX{b03p94B-Sw3?PZv324UC&$P%B&opgLw^TxTKEmoU%WAVemR*dN4*SAop) zFpzhl3~MU}bE>mJgDvHl^t!I|hp$7LP91}|)svSMh6r+!elor~D5*Kk+C#No>NU+Z zl{z3@{lM|ch4hE>_J?eXk2mP;CvmtB_XRzEwTuGOma{(cn0z?2+CvGF6nxlqenJ9| z_^PEp!&}mx_x~Ok-nc!P@k=@!2J9~`gP`RX}9g--%#FvV#gj-`} zXK%i2_oLof(f8e}z|KlZ7A^(z1~}lHVzd#{R@dT5r}kOlN4^+vTbg3TKCGOdbe%`m zdW-s-QxleVI4^s|hg(sF1QIA%Wy)&8PYuDwi{_`b>S22o`o36*tm_|{VcrW~#BVq@M*eJWk zAs4eOX$(|v`Nu1Q_p<<5o@0a;VSj`6QTIYuRUQ4?Ww|@6jlN_uwAXZ??oi5Cq#8^9 zF4}DmxEe@6!xVk}1eo%Wc|GA>ra9H|^t)B7jFTpYW#-kJHh!D`A9Y{h6;=0t{irA< zF`$IRz#t{v9l{Vw38-{ScQ*)v3{oOU=Kz9AcXvu7(jkp>_rQC2;`{ikKj2-9#TsCS zIrrQ<=YG!K`?EL6q-eSB_)5AMniS0V$#=V6p6_1JaZ#j8?GoB297qqmWL}aX^zl7L zz95_)Bc(*16u^tnQ1St7S>V~98C)`-#*t2eOETgG^%VTd90 z@?i z4<8GK8x;I@sScxqvi=2#8&{VDl7mEbRxp_x#3;u1$ zY2`QxQcoC7Y(vtm%>^!du`F!|GDmm@Bb{(EA>xYo0*LF`mBeC@+Z zY+_;)NhC#60vR&WHg1?~anpE41AF#tq@t%!UnbYvE&#eusujm{(QFHMBC&JiN4oA( z)FW0(vnjm;2qt|u_U*KP+X>}h12kma|I685IL!6!*Utg-;T29yf*a(ZGaR+GKtJn1 zjQa6><%P_>eid%njzU}1icK3=NZ-k_MY>U|G^J{`u64_968DXM;r&odx2cDDU?V_h z2&)A-UEM=$r2r2>n@+T?A9u+8@b%+!Gz^bn;3e-leZJkW?YJ9W(v8{%;a43B6ZlHL z2N}>);UdXiH25pDC+$)@HK4v?Sz$sl{(_AK*{LT=K!q8sATgkv4tE@~r4qjm10o^rQc2RfoZu&&--3=8=s+|wt<}UX8D^M6eGt0%tXbV^+ z_)v{$x#F5+(C+fb>a+x8H(~`OhNUV|OKiU8{@i^0-JP=g1JH)N^C!ZvMV<4iOPyP6C~T|Tluo^}?!jCmHiUo1Tw0V1 z*`HL(MMxg7qF{!sTID?;kG4hThweg#(mpdiQ!^`)p#yTr$(4A156zKz?c?eThg}#h z!LQ)4pu%AGP`8t#$!)OfT)NUb8|uB3*3e;L+qCuBCnG#Tie|`;gW}|~`rRxsw64_4 zgY5cLC)@5PWQmB$1R}UvD;(Z^T>*D45MImUoq?}|9oR-yT*pgM@TqtL`-UDpFJmv5 z-jkNb^4vzUvxfj+Xc*2e%o1w{jGgbovJpm7#k5P}G+NjSoIfh!BqKtU<8hq#E-NAz z-XnUpnz04FoZA*@(eBQZ51(d_B_-{h`mQ8q?f%xluNS@tTH(ov;uV~DBl~(2WsVH! zPd&%cZ!MpKokN)?uz+C3BDormz*l<6#b-oQz$q;I>u~_T3kUA{D&XJ8!&an2Ng%ez zKmHPz{t5d7HfOUL!-6~DzoN1CZm@lzj%M*avpyco*w>ls@`@dtn!Oj=spCsnUU9V| z)qoPVnP;^kjgVWr+STOTig)Bpr;Q`;E8oPGsltazzRtY@dS|f@gsz3m+tYbc4P*uJqoR zvaW$xWWxzAbc4pY#s4<;hQK*+tDCDouG`jtv$;gokjy=3a_mbQody%vJC9*tg>%#% z9+dY>w1d;%eJ9yFdd$0ang87FSVutY(Jn>drd=`i@gij{y!BXc! zh<=6lxyvyKlhT|;_)@F5^~7z2R_HHU2dYi!iXR1 z=xqgCDl=Xh(WtABNrmJs&@;(U5K1OA9RW5_Y{+P?%}+)c!(%TrFpZRh5`zq|y@Mo5 zEswXRr-7h`1)a4jgp`+?k zK|H0Cx)~_Yww*2+l(3Dc>7l`UN)jTFsTbbzcK275#20icY)Ich5Cx(pGqaJ{;X;KZ zb~ip`?667U{AZENre=lLse@;K5w1F3=2aTi9YS|`Y6<=xA(SKX_3n#nUT;Tq;rOw# za{9D-B+r%-^+(HaibtXn%7mgY8~Ai@o@PbCk4)R7YXdUc!7v?RUmm`>{*iJ2JYb zzTQgDY0SpifhDW;XeTt3iV@uZViQa<_{GxG)oS!H8!j|gxn4J*ifWmIz(^W`B+U+s zcunF^qEdnMIFJ$9n1`$t;RK=#tlHsJCS+&XtVk+n26D-?Fc$I*DAuOrmBGa`;+n4Q z^Ec3o##Ym{J@J6LYcLxmM7nCurdyA-hrdW+83y>J6}0H+ZFy-nnr@L#fH!#%q=SKd z9)i`eiq1Orq-L)&@MugqM(A7u(`ZnSguawT$mPYQV{L9kDB-%Pl+_!NiFe}O`1*Bn zKlAX09!OqK&swT@S4GkpREy?!%H|>d4VVSQ71-od*BVvbzwMK}tenuWIJ28$K>aNi zw5II9-v7vqzJK+|QtRcw*Bn-);R{I7n1*h0@%gvS$|Qz}{h4 z+zcEouM?^vvM!!V-xOuDp>PlK>cz6a89+`}sQ=^gm@B>6i@ueCgRr?Y|v8ia;DLTK)l+S-=6)}yVLsaQyH&G>f6qSkys^tUa<4G0F>y{3Oew}00g&qQvDzB_*YIGxyC%vB><^E|0`Q@cAn zPuoD(k7@5_!GiJ|i2zo<=aN5r5BcnASS0Hkf)in`mVYR}_?_fdi2)zv=wuH8)_)2a zs+*?Z#Mee=)ZkVbdE(WWuxM4@O)aOcGxrD+qHU8ju&K{7V%X7o*E;>c==rVR#_4yD z7SP60^tv{`O|39S9RB((7srT{oxzF@@5{HEM{Bo@xEI`(_VTjsThRUcw&1`pWk6lk ztPp?qFY)-Fca?UT#(;4)qz755bFu7ib1RPaA@;RRaZIfv)8ER>f8pr=kf-2DN#Fn< zrs`Myhlc-8$@ZTI?`yA_y6vfNT)!R7Z#?Or<9J994z7z{ed}L1cRwE{2peE=ig`YKg0O#L6;nuh`qi%;os@n>tX!%CF=kR{wOd1rIdd! z!{OV00ClKpZoaAZ?EQ8{pfd;j&0(+@NI6&v*8}Dgb43nh!-l41q;~jDwhzl%Jr`m}1RJMwqt;kn|&Q{p^0&(GJWl8_m zi}ase{A2Q{Gv?6obV>Bb$nY&D5C z)osQm<;+A+Z+FmfFh<#^yVz?nHU^-w9eNU zFv-4*fY6}oFI|{RGoWa_Nl7!hKR48w^M^h?QvNKgMJl#oDrb=EvN=&hW^?iZq>;G* zPA30J6kVHWfJajd$fo=T^nAS=cYU;E^e)mx&%23^I9{%@9r2%k6C#=b_Ea5;z(okN zo#p^K5ja}pUCidftlKfNKvDpV$_*|TS60Zbz`xTHg2e+A|5xDljjZK|E_YL6DT2Jy zx9x=Y@|;@TbFI@Aa-b96^Q|yD#vFu4vIj&TY#+#O>`k;Db?omwH6!*EF2z19q8V#0 z7bcTPd^ciaRWqQrD&|7A!Kjt}$~PD~jJXhFs=5(p+=0>2%shRb8lK+G2H&~I1W{~3je_`McCI3*q-L$*cU2p)i)jA$C@^$h&+Tc~* z8qwP3E;|0GW|B}D4OmnOJ0G7EAoD9A9V<0gWos^VqE|}crrrmn`WE2b^1aV-b;0b5fbTC#k`gyJr!alanDJyCs)^VOR7&y zvfrIIqGMfNx8z_4p{}LE6%I?;TaA7wI$Y{k^F|v7vIO+ZPT!6r`d1MfLit>Cf*@Ntin9l-f%DMD%=|?cV zDFqzHbW3!bEyH)yDA%bk-71|Tmp{C2r&V-@2BmEV5q+%1h zHe2bc)8{HI-_kw#gFepn*U*nJ5{_>msIJMe=lDuaG2wHvpz~f*!s+S4l^nNN6Z${m z7%B}=u_(mEM??QzMxS+{;RoU4K;Wi5Ze2h{+>4e8Y&2>B&o>h=Tv|#eO0aL`I_=DN zX4I?Tq+Neu#An*aM0D!jg2R_6E-8j#{q?2y^4T#|ANd31r2;QU5o^N%>xyY}r0Qh( zrb3)ngHK+fD2mp%r;4c{$zmRQM3vJUx9dMyY#frvZ~q~zw-RW9ok29JD*${m*2hb- zBb)kueb?iL;1prq_zcv$Hl6Pc=%N*pJ@SqhZWE^6xl3Z!f!~dv4tM}kLh5XVni=nl z-5@~bzN`dn{J8Vh)Oagxz@rJ6N!z<{I6sXbu<<`dDaca+ZF^lJyTJ#cs|)PjJ67&X zA2sSXsiCBvMfQojn}YpT<-u;(!s>`sYhx6v)=`S*dfq9KeQ26HAob!g+D{hR73@Gr z9t|DI5zs5I{G>Z>C5%YeA%V-FiEK#gzkw#<=Rru#eFvo$dR~SD+YILYD6@Go+lvpF zr;#LX!*HcESfh^n5;vdOfc`ojpUifsRL-90fBpJNJq;t5UcNB zX1jZ8#w%dd_KRJW2FFknkflcncE|e81AW4a{X_vuE|a8{7iR0nS+Oauz&hVGR>$RI zaLibx$Dyf@LJzkVDRwxqF8|22r)YyMR-K4~m3OXA&BVD^$@yxAF`(6B&Wbq6Ee`++ zbw0XX4HDLQ3HLQTnbh(NMIoBw5d&Byd^2vn-Y0XMgnFdez$NGCviF)XUZh zm!pO`psR4cR(LDP41L#e>^*dW1rXi`h4$h0Ea}nAiti1Why<^Z)B4NB{7Sab^cXt1LE zWa772Qvh<7Pcu+QVnANa_;{wzjt=j2_*|ai0umF|j{T@V0fXCZ2cPf{h)d4-`K*|} zvTue=>I!~kiraj@=*@yeVk6J^xWG8o=T6^5&Q_uF7c@x1^gH%g_IDuLP3XSn%CA>a z#oFO?Xi6|Ch`mXV+aPEInL*19qVyOLx!BpRCGm_QPVGB(&RA7#O#?Y%361d5ZSXlY z_J4$;A!s<6-`8bFWnjvUMO=kORK69t?le&nIgC4BfI>NMK#K4UqCx1=L&zTftLwzb z_|DOEN&0oN!Tlda)$bRA5-aWh-Id^qhZi6OMIOOxAnL9A}G(Y)JKWSk=cn2J{=WNW1yfH%K{( zo%}4YBH6pQAa?tu^20SowjSq_VZzWK86D$vYf*+bcgg$`7)+6m;|T+-V2T+60%p8i z^hvVftv1uudBn>>L=i1Xn=^IYR*toDG=bI|(u%^Kb8Q}tf5bfwzdlcZXE#RIl+os!B4BUgdb&mH7O)kIgEn$cWx; z_PhK}xZ+9eD|!R|C*sjUmPdZ*mtr-7KR?KQy4N7nON#oN*aqEMX&5sP<7KOU+bugQ z{DE_K4jaON5pN)WMAJ^iPE851mg8oMI9wkc59>k{3xPI&ts?*KExeP}LF#!7?~pFgvsypKn+u$+F#3FIej)&WRw^z&ppp?L?KL)#Vh_wtInfL z>aIh)pf%(0oP!-qldam!9~3w;eEEBkA5*oUwsmEVNM(BY%2sR(3TDmw4Uim?1yF~H zE{Qur?@#|g6K>^(^PjCOTOvG$Geif&LhIc3rJ+xRT0=Z7L;Hap2uBfd`EcO<`8B`} z*vvC}i|lo7haTQ04n4g2%jOuQo04Hqz`}vdr^R7`RqryAn5JSr-t!8TrE8UBW%V<7 zhd4M7LIyu$H)*9Foh*@^~lBbG>NfT~@_qszkTO0fm-&C$2bFhDK3Mlzn#@hQZ z!${DHGRH~y?b7sUuvxyi^(OpS#xoa02%1h8_2mSabxi~)SYZ~BMiG)CrgQOhJBZpZ zP8RT(u@Y7=V&Kn9F0bqBg`ET!@{ZY-AetiZ>$v!MmRg31@gc!=x z-3oN;ynH=TZqRWrj*%SY74_$bKuWZD-D@Y5K9H@XCp7*#0^UX`;xUXg`9&ra#|Bqf z4#m(LB4Sq?lQB>Lr?Fi<#j(%5+=O3R6VVtrO0Tqh##7p%sQ>=ajlSF`BX=c4L?Kyy z9LP9`T~n>)s3PGuHWpT`Y|XG@WnsHouKL!w@La}3$BEf$j0xWQ$L2G-Z?RP^q9b(k zsFPj7JX=^MkTn)YiHylk+!=YMsA!v50ep1EiE0cazTvm8l>KLw$MzeVRr%1ybo$!` z48wQ5iIGEHK<}@BSTzcH|E4hLk2e6Y0lml=tlBD+WYh?Q#|JR~4=ch9kKqz`k$Pw1 zL5~a57Z(>RYql@HV7@?bBlL!G0=>t?aaGEdDPVX?8lq~g)$Byp`0j22_L5?u#8%9n zp*|q(YK=w{%GpGez6tD*56eHo1%~J)zAr>vb%E|g%(L;W{F?f;+eJl0Z5}JhdPkqh zq$etyD)g1cqP6*BE=dW$w z-a#A<8r=)-T_58iqzJy0_K`WdlOHPM4NIa4m!i9b<$|3`b8Gu*-S^g!{z+T59T=TC z6>Q63x-DGtm9VusdJmaD7alUpP@tFx$1Yy z*xx?pe&E~@MrQk&6)_~Goz+NJZnrldOi#&ERPK39dHE?suj~LeCap6D^nCCyn-hSdyc7RrtNUar;Tli-4+w#vzY#zWy9Ml9)+#R&bDpCyJG}is zACpuJ&xKtAMb=cvBXhdqrNx6IYb4_P+Sr@IH?r-tBN$ql=v2p#BJ1G=u*|xh<`SYT zjc4yyIv9W5rw$q&o-4K~hi~*H@{NMkvEE-F&eSep2kU1>n&B6(W+Np$k--qBSvR9_ zC7NACuo+zA?a?rGKRY7>zAn^#kvil+DuAXsQg$Vt3us5CxUn7!ma~hx+gC*rbreDE zu?G1OHp7ntjDQpQ7TD{&f~^|I>X<`H5I&FNGI6bg$H)ct$U|_K+w~W-Xk~VQ<2SP= zN&US5bvL`umms`&gU9`~IoB%;M>2bw`{+h&T1WX=c>3Y^n>2oGdl+P6ct(4xU^hR5 zlm$)}L$5;hO^0D?WJPQVQD$tS&tI+@^{0r$_{Msb7fN2h7Xzp*3H;v6UB;uU@V&=< z!@+OxxU1`zweuq~dUB(Da5=tOhl;5e>==CUdfx8z4&?^?>aFQpmKic;nQuYqnb*-T=}W&URNc0tA4- zLX7H*^wL3*zI-c_Ij64Iu0{#rAaD6kKIN*+%0@hu=v>XRW@P1VD#u8Hp6O-L(Jo&4 zN0-Iit?$_d&Os!-z5SiR-5xX#5}a7zb0wd?5lxiPAtaVj;x@((EHvst65MRtm?TB{ z{6}*^-5cK0xHe~v^y2a0 zqe=*GU{hmrfL1@g3!I#Mo^%E#rpW+qRuTFRn_Rm$cK4Y!?3ppx4&IC%h1pK6NF`f^ zkYBE5;MMVuj<5MZ%Wt@(BW#0FuSW-)9w^-75RmV(74*GKqBNbPw1gR?{{AwUmX;+OVazbpIbEzCIT8viBX31D8lw7hbthA=-y)|B$aEpwyo;y_uLklY_+zzDU)yu zt`2)wMLIiHM93_K;V8!#kL~F`0flS8*RQ*G>9A-h#SVuT%In?m?1mQDF6Rq!DLPWT zj~EHdNAq<4AZ0*ciV-4fkmEz2GOEE%L`EjX08J>WUo6W5Q!bPrK zuk9I;k$(T%wi7su>Q{&@uruN!TWvrV?IbfC2NSZD9pEW*@BMNqy2Ll`!VJslo-h#( z@M^sTqi<<-QFLgGJ-cUvl<6~YxVLaV-xgB4imJkFn}X-NZiChbPko5h5)UK2`oe`T zDW8php7#jEv4_K}VYglD;__F@dJx^B?*iHJWPJphbURXw*zl>ovi6 zgrVi_MJZnnKO~?CQh#gb-znXvN(tY$nJ66;jp!_pLxV;-kG+$XO3^@jiT1#zQfipd zaAvf@rvTFlLmuOuc6$Uu{xQkgNM6m-u@w2kZ?U4COHUR-UzZ`i3l+f!LH|pz>Mpkx z0d4TFd0cC)vTsKc6DEX_5Xs$;p(@ANd7nQ^n>$4xMiGYEmkRX;?U;eP5Ixcc_kAL| zHG-xmep>x00=iDU6|zQf-Bu3R<6S)I(jXp4!%2v2d0V#WYp%;dkl<+QIk@4*p$cD# zq>-7#DQ-5tYN9MZKzFrqXjf<~Oq4Y^GukS|q)y7w*}x=+j0A7dV!8FF=+GgIXix@R z${#ba^(hgLSh`8{c5ZQe$kD^%o0@mHpptb+S{0^sJs#XsdxgEKdj? z_^PW-;RAbln*+Y3v%KK+9!wXQ1gGBcV|H2(;wyDMgYcc;swQdVN77V=pLFV(Smy4x3=>VZwLdo;7U3F-Za1-Bh=rJkGJ4ep9 z)^)D^0<@BJk4~F+d~WfXFv8ZBUEr{pLhFVADYcW>@!&b4b`a5j(tZXzixJSbj#7JY zUYM%gdBK*hFLqHFqTSO2aoM~4iR$wVTs5{rrUE#*ZCh-OXe;*4SBtH0HnpIsp#&x=hThFyqLA0IVbm2 zL7Sov2HN98dFha|v>-T<8_jvuU9oq9OFZ-X4~cdj5fDHK8Rkd|AVf&nVTOqh-sIVE zRPvsou29Gn?E``vh=p{#HEPyfePPOUyor6mmyMXt<{g(~MjP0H<>{#dt~q3rwj29v z2MVdB>2T#Qkp%_~e4~>|FNJx}fAO)W>um5Bkv}~{z`x0{#v4M~;J>c1r>v?p?{O6k z-<}A*CjJ;xNe$0mLSs$)>QHwIEt1&k^jY?VZ~QM^g)X`-|)Q^n3L97jP$_s7kWv&Nt&0CX&R5?ce#0HY)z zN509Ikt^`r^umm3OtdKZ(?@dcno_G?(i##{u7N)y7?*7|!*_XVv8thQ6JZJPfg&?q z8~vCswBObf=JqS|%Mr8H+Cl;Xbu8ba$%20@@prMuVpPMqWgz2;QB7F^2aj*sN+>3V z{@GM&0eRo3#UlR&u%|Mwp$|Y4vF*&OYxe~sI^bs^YMPyvmi9c_*gHHq$0%~k?|=wn z@w28npJ@B{g5*#^VjWT@_`6S!wi8amI^`a^Abu7+(fSdFciloWm!o@4Q>Aeb$WGh( zhS~GJiu#vULcE5^8b=nF%e~fa{j9s@I6b_g-o;*km=nd6=B$K4|0cN71|b9VRvC!| zq<^`W{zhp13(`{E{6Pc8>XGzZ?*AsqfGH6L7*&|f(^v2R9mYdCKO|B@CZ+c+^NaCk z>guceucc3;EiLHl2Srn|ggrYqHMPhV%qQay0#T;T@5*uNV)|OI2Fh7ScurB_ai=b_TORRo8FwRKC}Zok~OD@i;-FdOmzgMV+bg#$s2k+5oyq;SI#BHW-DfywaO)dWfx}=g64vl-1bgOXsTg_3 zOZXI-ZEaiYXNH?aonRzMNsBUcQVly8m&^=>DPd;N^g+6_mYt z?Th*KJv!?G!`Y~!RC0K0qD*UdqH6x#S8J9Rbd7D{#FNl|CPAWLKZ@yr^cJIp=RLH~ z-<=87QJynB2;p%A_;r;WTe80tZ@*+vxE;oMRySh@&ZKlWxiO64rW3=*L+ILbQ!=Yp zzzBxRwU>vla%R$82rXN_D;*D?0m zK<8+4JHP%+bHBj~#ZGq)2C`Ndme=wCq#O;V>>HaXZ4|wmct+12A<{&krPu#AnGURv zz$KJ9{vq$*OK1QCgX#nIdv5EA;c^U(bh}W0x8_T#@&G|V)CG;*U$bLAP=Jyz@F?f~ z`lalpH)qTKqv_1{>NQB3c*#-M-?>H9!8eC-T1nmUvc*S zM}4Jnk8}m&jb9DIsm-TQ2a~kl+{{P#b6Q4uy&h;ymEa zyvMX$|0JsPdwXuUSW`^#21voyF3=Uwy<1!BhQltMLtJjaqR+H22t73X{zqY|2d&XZ zjFM6#ot{*&QH9jY4~LOa-_Jwr6YodJh_qj~$bpkS{400f=s*dysVT_iu}uWr6rwDm ztu-OLU@Y2oimZmE9B3Fy{yKIfiMWiXA5kKSHQE3Wd9oNaXK!k$+5InxBFd;$U-W)P zWiiOgj?W{Td;0-r!);LbzP`|lvHn}S%D&38!UVAL5_Gc zq*InZ#JKR^)deB`2E-~*6C45N(#d+Fl!w}Ou9=J8v1OTmnC7@bbT1P-(Tawe3oBLAqwuDTDakt6wgk^z8QRk^ygXL5t zP0(iX)^e{_vekgrwI z?)9y^yF`HMCP6)*`HBU+QHN^1*#O3=zBVv|sU2@lE_loHc^Y2*)*0ZHTo$M~~#*(kpaq9o^i&ry2|C%Bbrf;unS^l}-@2ai? z(}6q)cB%sl+EmSU`Qa3>>p3?Jc@Q)S^5uGnFYwked=c*hJHYB>mGTycY|FvHqb8m! zTWgWssKVk$yYuQm)Bf1cS$fB(!ST6Jm}Rg}Af_b-)OGW0%5$K#gmk@6>%T4DuxZFtVwKzbDMU>^quLDBul`$Zp%JdS#bZA)kCT;v5S^@hZ2*qUvB$~4`3Y7AI7HHHV5e628O=f|v6({T<1zE*+3 zO`*=f^{R&w&DsH&I8zgZ10EW?XkXqfh1~#|bx&Mda!0d#Lxk}A9b9rNax+3L1n0&~ zT@a`bzGAA)k>q+Dt}O-j5xFpmDCc3=IxfR=A-svaEWv*S62|s8{t}xfzRBAR7`z$% zTzuWCB%hVO2F{rse>?YKZ_%rLzx2X&5I#!NP;cGve zB<0y#=mU5IW&xYvK4+CLH8+HN{ZT}vBy!nD3NRED-ofv{qZHQn-w1-TmRM|T13C(H zec@eH%2CWSL{=c&PFge*L{U;9BXIW65fzyd=iY=DHckGgCcd(y64~&#oL6unn%4UL zzDXNkZB>2;aI_{jA699j|mHxUOgriTsXGdzz8(n&Z3Tqp*8 z*GH^Tn6WnHqVCgQURZjDQNwTHK}Ek^=v1=LKel)`fKD$8><+i31{0^R`S^`-uFZ$d zIDAtZRlFtKM6ueO=RV2(74E70y99v8LK+JP7{HB3@V22Bb2s$7=C9D`F+rN0 zjTJxU>z{p32wF`QhxGda2YumL7qKEdd3AL%7Sf{1qUREvmlP->owZr5X@#U^-(En>zFH5t5-F5+`{cFL#Oa9|l!3;* z?(@p|yQxJSN$?EK7TK4y@td5@gYLCika}R}c`G58g8X=`dlcpeI3X+zc#z4^*}y)* zSgEUXHTL5@PnU@0(WFD+uhvIxUt>m976Nvf4u6;Y#yc}bw8yMLdZnu@6^3o}x`;^= z!-vXl2+Mm&OVU_b1-NVgKRmlQ&^xsIXt9gXWM!i4tNin|!HghGB%GGeIy9}?dXgyU zeQ;%fofGPiPXi8XCgPnVli(hFgJB0}+?uMIM$6ytZ|Fp#K@tjaY9OS$H1{?-dwMwM z_LE(o9tACg%25OqgHF~2yLV>YqG;{8xiLgPy6v$N!SC*c)WErE!fD>a3L(@_hZ*-P z3|c%0O@n>1@Uuc>70zzhhzHpsw#fMM`3&%{OUmqo)wfh@3hXh6hxlNlMVy)jg7)y2k!+iS_bD>BR#r`-o=Gt1R=VTT8x03 zq0Pn^Cf%OFq-kp2j-`3|_S02z znJPan?c1-nD&s(qOAjnx-J*YqNHfj_(6wf!kObRy4OkIQU8>qiC&8WCR(O>#v0reV zdG=FTM6qxC@_V0n+jc{%)-%9Vk0+R-7H$cf^m>es$cGU1qOMXz>Qh6tvTBcIl)%*yH<29_zxKNO(y?u!Gs-ktHV9m4^Qce@k!sMIc?BJq zCZcOg6;LOMR{VQmK%r&~>1NkwK9hPaQHm_2T_b@cc7KP|KYFwi$cHpVBn3SFHPi~1 zQa4Zof;0O!gg4nxgvN4Bu?mSJiTcF5A~xksxR3A8N=Hy`s`AM1%}83n$>+Y}OE zez>W?uk)25$-a^wh0hS5QAu07Y-YqBu~r+_C4QMa*%>agy5-=Mj6isX&v$v|w|s_= z0$mWJxi{WQ@wXCD=4N%qeDHIpuxeWg4OP8FYqcN@e&YN(2caJ}fB?MW@^T7yK1PMG zY>BuNn{s~E=+C!?=W^1aDIY0`{YstSt~+Ezxr}ITirhO7Ji)yJjcK1uMRCAU;gcI)#Q^d2rG&w3&uL8zQafb$vdrPP(D=H%7ABbn_WiK_8AQZ-LVe-+Q0Eod_OqY(DMzN$RGWyb{D?|5kCM<5vgIeeRPw+ zU-@`TL_Sn_hx-#SzS}M_?Jw*!cgP@k5e67)ByI9{6X5O` za}{kia}9_u)5LDm_`nEY6Ev;V#ndBB8KvF_#F)P@%)q|=om69I(5jn;?<%@M)FD9t z-%%TpF3nJr=!xWvF3h^C;{m*NjQ73>o{?RWD5NAqI4_UI;=aLs2vJkyq0}qu0$m;J z&8P+v`?y0OrtCj=7k*V6%p4Im!(wZNCIfHXn_(Jj)fBf16j*0su}y>_IG3^ zUV~{45wVUv@Dx6B*YG3>c}|?EWIkD*C$duat}rAnL_Hkm=LT1>RY%gFPJhWN5W%5I(S1b2M<*i8|+Un|o^7S@n1R&Gc4v_US`hUjoM zT~eldR~`!^U}da%Xf6PQUZwKU&)trz#Z6tK&oA1;5}#>*S;XeC?ro&Xu`bljUN3`GUOdy=m)14j|B7u9K{8Yx`8#?g$1ZoXe|LY+D5 z9jFPyh#?5DtWTk&hu4o)_-* z?p3Q6`(BD`odXTnzB_6e@fAq~+=cWv(V^wd)SU~q9vgQfOEHEs zSZZx*HWg<(rs-e~zeEMhA)fKG1L(X>7@vf%!_^-}A07CDv?J1Npd&o6ma`$cb89Wh zb>=pmFwNMU>o1@9^H1%ePWLNjePV;h!L*f`O?FV8e>Zo8=4B08-e`&}lEo9R#@;J) zcvH31Emkg|S7ca)xnQ7((56k@1=6Lu9kBsq5k%_O8?yJ)_8rrg@D6D?g~!}SCeZto zT01v{7)q(n4gnrtm^ci=J08#{ad(!HA(UguJ9p|g%WD*5=>nU8SkXel(yd{DsD@6V zde~tQ_Tj@@zk3YP#g`rRZ)qJndM9^M?GYQGmFj(RrNQP0wPV0@agNmbc8>Nath+%6 zQ=$kLp&*odyNsI-IEO^%VUEz_q1gqfokTJvIzO#>RtRm1b8bzFYN-S`oC#m#AzSTE zXdSvi=bLC|xZ12;i$aWte^O6$#Z1EXWVD?L^e|osZlNe03P9u`@%Lg6d~$EK+Q-?y z5wfDe=@_j)QjqIxlZfDiz!1n z)(^&7_PjQX>&{6VvBgD%-5Lc8t>gTPNv-Qdu5#tt4>jssgONFkMTk1SgUjTVyKMX< zcVAQcHEHW#j^4?hcG%jU@#{40t9AV@jra9lbk4ecNBHJU{1^R~`x_HwEgh9V_OaCN z^Na5HL=ipOEGe`qL4S+|`C{g&!!UvyeAA82z ziq&o(o6B<{6a~s3k{friSM&t1{3MQrPAx^?#L9*Qo;L#A&X~7Q%x7-s*17 zlf0~!5XPxX+tLZF2TH99SH?#>-+e$p=IHdjq%VXobs~!0fBKzYj4`IERq~pv6bn6H z*tGCc*ZBHraaV3Dh;m(hjf6p7m2a0O;$h9R>pKvi4%nNdddGa0;N6T3FFH~Y{h-~)v8oXQ094r{}bmi3!mf&ETJE}c^wI*`DbU6K0Y9V@~kos>&8+J z9`xXGVENZ^=O*#MVL_jX2%s}QFCS+7x_}fMPR=tBaB33MdHBp`upGI`*!hA23(hm_ zFKAPSlkAzGCZ?%)o^8PPJVLODhqq{k>&q!naO~r2o|7ne=yu3;JZsA7YkBcCG!O3&c$J;H5=8s2?Yb ztNFE)ZTUdF_*fBJ(b92Ey6{rw*`cR|(f%X#(S0Q`RP>MHj)<%oxrzL@_0L}CIm(=$ zehNGo^np)O%2k{l`!SbYaSm>e%SSZ~?@KJZBV!|agm%0JFXC;2j40wqx*b92pm;jQ zy&uEF6M9)7)KxzhbCu2N!NN1&s=q=*NpSrZ_2M^X+a%+{nT1b0?j-VkkufqbiH4p6nH53igLBP!xoJ%-7)RyIaO8PqCny} zjeBj0JDU`bxfqZ6^q~EEomciaJ)7v*tf*ACc`EW)X^~juWnI^th(|-J*Fw zOSLa7QgBo|F#pU*}kYZ*TR)K_KwA z%zP146@%5FFqXnWl&Dmb(t+37!ogvd=u7tO)B{H6l;P3R8IY~sRs&YQ97TyunYAP2 z>5tRT;E&!=PL{96Lo0GR5f(2InfU{k)o2;wYTa2gO4al&GiJ$}se&(o5P!Vo{5v22 zM*kyKRD8T6@GPa9NPP? z=zY>e9%ju-@2{zwZ5TQ?Sgc}%HGJ`YA+nb9!#%Ad{?nzl>WYFMud|rS%6F90!a>Kc zeVK?1?_f%qieLTNqKbJ&X{gnLw=>=J8)L@2PxW*s-+emR{4_$`8|5=OTQuq-Uub$X z-0_R&peK{os%o*e%T)E4$ys#kIz}0T3g7jHpxc5^Kn|Xt(Y*n^*S~&>NDC85g6ZSL zf>V@`>hUr#tUkypyCYe8+HaqA&-VCR6YB zUk@Zh?=|kspzq!BTYsIq>o9HR+w=JTpIli@G&~wg7}>*Ge6on*K7TSJ2_HV4w-c)i z;re1;8KGLLYXees|2*e@b42`m6!CMqTKxOnHn!P`QKkIPL&N3l?9fJm;U#czZTy@!*Fvn?N0b-Q2%Wleo0vPJIm3rAOD*F z|Mu?S$0|aqpS{T}meT*n5jZ>&Z%kCxeHngz`u^w3F%}hHzvgo-&n5kDZ~V`X{~t^M zL)Y{d4X)n~Zyejn)ip@}O6)@B2%GYIl2m$5C((gexcP0}Poo!oXG_d8RBX?JnP-;%}f7bVN)@|k|Mgc`FZ)no=QR0 zuw~z-*loc{p$|Mz?v?VR46#ox>dX^3wD+^p4Ygk|qxtDzNz2IF&mG zAm=lL@$l#eY40zk8+v8^&?R~&=b%<1p;1tkPFp&{H;L*q`a0fsRs01@jBimVsnfpK zWO8J{il^eF%Dc30!WI?IP*8N7ikca42Y;Q8RXv>fWoCVxFxgZ6wPbxY+0kXb*zm8b zexo3eho_8Yw}^8Dq;5CgJd?A1@#2MeyjnNd6HNBf<6HFxy- z_4lO@or0>XgVVvTw6vlEDyMv^C0(O`s&N=S@r=ja3xfz*%2(#0pCwL9A7!oNmngv; zD6vVjGh#crQlSwjFKE}+W-wKXnO>aV{w4(%TlaqMQvNdXJp&^y?MGuGpIFV#VS=@a z?XrR4o1M)5=79#7*c%om@`VFMf=(KF6SmVHqb9g%FJha=RK99dV0~Jz*v3vKdTy%Y zX#ON8S%dhS#TWnPm#$l@DqqcUAC;>PHc!3kC3=|Xx_|k0pm1M&wVb{G9p(Qc?kxkF z?AtzIK@kN30|aUG5)h=M8$m2uItC)$AdF5WR0IqJq&r58j?o|uBS(#{!NzD9FycMY zOTF*seV(uH>!)$LopGGU|LFhk=Mu-5jP%eHcYeiQR#-Yn_%LXb1obsx6E7j!)^9?G`%SkRvdMTbDCy2}WyuJ2(+q zlcJ%`w?FN>O-djdt)DFphlkC5xenDHuFBJ$Es}Eo;_Rj!okY#$>TBw3Xj-IjM<{e^ z{Sfz1TiYTV3Y9)G?DkIGky_;My+P$`Iu(ElUFvlar^mFH8YZ6EITCq){|eP`0lcmw zV4H~C+Q*D9Ty3wCd7we7SMKsp46V21+a5Xu|MT;Pob~K#l&swe=!dzoIpm~nlZ&JL zZ&rH=k#%pTAkPFDZ!(OQB4I*t7s;9OD_@ajqL-A)c=Jc!mMW8OgwyA&3i~NKj|X2j zgH#Q_9XxheBe4tPIzOBz^W@>)5063FtRUC0Y6@K)v0|nR>@>NF52jW>GzXAXe_?2U zG7v9C3DE`hgSAQs2Qnph84q#a`9f6M^E}ZPkg{$fg-)nsW0*B}1^4{rHl@vTbyh~T z#LI{0?x4O-DU>H%$2b;z7n*vz2wb)N<@lS$hw+@4)}YN2*5IhOVK*&>^=R^W#Zgqa z3w`KO=y$QH-ubt2xPPSox%CqNx}eB8r&a2u)%eIuurLGp%#%!WV3cZD(7=T0xge9} zrI6L;lzxGZ2!A&L20m+fK&HjifEAwlAbO2P6Od^d+EML3;iZox0j3`J}P&eh+@pem7G9&J{5iOKArZpRwXDYUTAg0v7laT=jcZe zzpQo~xE?!^)ZKXTQr`o6$842x<7my6K!~bjmC&k>iPvdBPEW4#(6dnUU?Dt*_dFx! zi-x<lpaM&p84}Du?45lCOQ78=3^dD!Ob-7f)5eKgL`poJb8E=o}mt>dyH4_9odfSGqHAmA6OSjgy=SYse3$??5NGM@{~BEsn4A2osDSU z!u$^oQ*^KLH8bpLhg3~~ACVz}p`o>qAhP_U;9imSny^Rdp$ol$RIb=_#JzkU#?21& zC!1z&y3|Iv3Yl@T zXwtbd?l^tfz82XzU?Ze`%-E*`)4b7URxq~I@5nT7yB{itq*&mZ*p0;+3_D&WY30nH zBEk2i);r%BJZL)0TL9m@APe|mYDnIV-;P%%*@yt7s+8cqOFONRqRZG+I5bCTpQEl} zVq<KCR--qvfKy<@zIt;nI@#Cy7d>Y#UHeOdIS!2Zw3;- zJTea#Q$g_M&+-kho%*-5)(q3Y(K0>wDq~a-p?U%xZ2`+*%fOCJ>bRl0|5SnTvn_A? zc17xn!H}DRgR5_uyt)H_#vC$IM3>yRb9&2vhd2R*H&iRrl_f#$o%J^v(_W@~7^Q_| ztjvCX)ApQHOaynW6i0q-8FtD;fsIRa5Vj`g*lcaBf=*XZ zk2|l;a{tmv(X*8<%18GnZ@BuDN>$q`j!4xhmXdbmjbY3CK+u)@{aNZIL)?cMq_K>_0uj$w7t?wl za{x)Jto$LnrwI6z_2AHccs}cpHoic^$e9UwZ9L!BOkks`5e%s9JDKs3L1)6d$`2$>F$`BbAN~>5vQdMa0jWH-Axwha zZR#=*vVQBG81K7YE^(r#<98a{H#R=S`D4Y;?hfw5n}3KRoOujr%@d0HzD%a}mEu+1 zXG0>~MI>K;qo0h@a4rg}V)L7M!)tGzKsKO&OD`Muf8%UgxLYD?W%ivZ8SsBihxp+@yWX1564566-{rNR zXzSR*)uZ5h6nazpSV*DsZrlk=SAT+8Rgyk%yyr40R76lw#QuXrVQwzxs;`-|`+P-j zh@Adj>()_w?G^o>W`l+k2og*dpB6LyPRSZ*s8vT}*f}p-oNgkUHlw+4${_Hx)eGW< zc;~3V@0`@ZPfkzD`}zlN#wkw~?1ig}S{aBe28T8^JauoI0m7!HSSD#&n0Ox1 zgJ6QhYCSAl4Qj%1{K@p3pzylG73j&9m2d=-DZ!56CR&*y>v+w~cuzO9rsg`SmjcK0 zW=y?@ko}@(^k%v|e{+!EW+Jceo+-s~DA)c-2+bs$TZjjB5@q5k{CKv7NqP>H=`>DI zJ8hjAL6J4(UPL^U9}?TtRUzSE_8F!7BR@%Hi39mQZ;L0AOA3oYp!z^^48iA>}drHGWK?*mPl*lF%glYnbK2P3M zw265yq5^Rq?vyuf2?6k|t7StF_=Wlj#-VGuGXlzA3ES>E7~RtHUihLaTGZO4PPf;v zDrgX5Zz8Z0-HNifWoFLrR(s&0BS$JhQ#Fh~X8^-gcuE_8~;8o3{#5 zkc!kg)INv>CtrKp%2Ro$+IowKk{C~GZ^9h>E|pnIGYs!mw_$EM>cOli4K~dFu0?Ha zJ`^-4?WtRd>aAbLUmu~+pIdm&^;0J{Z@e4v3z$dA$^TZ7bA(P;3t6>;J~;E}EP-4} zn3zt{(B@WRqf+#Trs8Q)&b*@qO`$8Y(LpBLd2t(;=?)u=I&F4IXi-M5U&oZXYpF8V z`s@btb_A2NOG}hKG7P1AIZx6G$qK7@c?eN`p}F*MMWI51c6j>ujhh-pp{1eW3l!!{ zMZz^m)<+5@Ji0kiyCT?%t+z*kYs|K^3+BSsov_+WXF0LVkSiRFKS772w1^o~9VKqB zxCP1&V?i3al<1p^6kbNt_UE_EOO_^j)5zx`9c8ob_~eW(sX|K!`&|~^Ig!1xrsFXS z?&9s#VevGh`s1;U1?kgPY196zjL|-`!K!A^mF8$5UkW@Qx5vxq0ARoU@OPu(@& zhZ*PcX(k=CIy8q1Is|jpZ+%w1Hc#3puN|PjnWAt%Fn+Gt$kxwS&V9E$t46#$zoNkBgs-Eo0((hv$u~!UA!7Am?9;{ETGc1eo=#dMJhfv>5$Q!u2q$&@lSZdhl+l z$>EbMqD5!8A^pu7vnp|pO3vJzOWH?C6kfOj*}Z7rJ)O~$iNn#4x)3MLk)xT}WM)01 zdg-!tJ0iM#DCi1w_mwW=$6>O%6%nv!%IAhTz5L zwU|rw@Pima0gG%RcqMqG>tDlZdJiaW-K8vH`BR1YA;WB4xE&>qu`gwI+Z4?5V$RH> zb!E5$cmRgDnWE9w@yV?P8^*`cI-`^!eKrkgmUZacpri6{4`)k*o7l_4yE_!j4_}e& zLbAds0E13WG3l)^x;2Dhj3KLpUvpQZp3!%hZ|KxdnX-(b+=6`7U|9*QQg1dBHez~? zz5P<{7)ZBBBaWM)HC+Op+|&3B@<}3#q}9gkDF^ZVZFgh|<}IvN<@C6#7P&v-x3Ruw z92|BlPkE|R@m{^Ki!wk^I{%7OXT-N=4`U%)4bE(95#_cW3OI9{yq*^xw@v##j$r$C z`_BU}ykH(H#ON=VI=am+W(D#~J7t7CBS}g;z*RT-VtB*URc{c1V5+(kS!)Fay!J~! zcoze886`M)5hLrh21`u`9++PU^DXi9UBh>l?Ur%J^KyMVdpl_iEM*dp}*{ ztH~UH$%~%&R%V};(^^EZEz=_OUVtAT7$;J1?6y6ajzGZ8@-Zy&sem9BhY|EJYpsHnqNnTTwvYha+WH zJ@IIqAw{3*g-!!N+;#Sp4VF~E;>~{&4*L_-%2F2cDki`}3-qqRkA@I?RG1e4m=b)_ zVS>u=cv0PhqOtV{i|B-RPJ;rA;XM59iKgpacf9awG0S=KpiY?ey8DoOrew!d%;>@A zvCBc#i#JoXm1$Alw8HK<&Nv^%6}#R7QZgh(VAm-wZ0eRI=3~%oMv?@Yq2%O8d*rAE zCt3y?C*8wiJ32PN2w@!wu9)zC8?7N!Fc7?Li8F)aSF7_*j%QPNrsk+Wc6p(SG&3jy zTakrVsP!vzXADvfgMnD7t^SacN$ZVcMepp=}|Aydhzq&S_<~7m{D4!0QXn1Tf4hpBGUv{C$@UXSE{T} zD%4(R`-&90JaaP66lfjF>qWw(mU9JIL^($Iu7*n7ONJVJ&D1>w3nWcVSsf`uk6lV_ zm7vf(3Fi-WiyWzQeaDsqCoVe7IU`3C?;3U5Ar3$=5#lU$?7BYZ)6d;hffmQ%KI-Qh zOA6?{wN{QqdVFRtHkn&|QvEF&nL0PuJPDgj84yF|vPNvH>X{h3>4xNG!Vc7ZE=Al9 zYs{q}-SU2p@m5u$J_!n{cFkoz+(jmls*DlQiR;;Yv;wc`VbPyhmv`mbe_60JReygs zN=AX_f6DhHYBDSBS4?KKi_A@T3VArk6T+W zmTd@3PrikC?0pYiy=_)<-+lGU;yi~py?U6Y9$%eUyyv_;=h20oxi1Oi|f*ttp&&4#ON$|ywIszh78K? zM(VjSN?Q~Yhi*ajdAZ_U2Q#ETK8gEXsm!TBJ;bPQzq$l&U@Ip)TG``j zSpOQSKHG4}uxI?(H%vam(MayS!H)L&Zc!SQYz2cgIYU^!&{2!LIfQajnM%Au(BQ4u zkmN>B8h_j``OWA6-INIVFtfiMoX1)XvNS{=Nx4Nk#4jN(+k7{S@tj-bJ&yE{EMsT4 z6YZm!sziCLk9WJ_lHU~0ugdCnO@Yga;C76x_m;_qzv~(|)93BCXBbw)h;jMITjciR zH?E`EyGKktqG6z<)2Z{bbM-LpNc|Xb@Jc){c#IzU^dW?hH>{_6d`Zp!X7r|8bRDLf zw*?(pC1!LyjLy~Pl~mM|=n{X0%*VLTH$#KVgKye=ha1`Ch`HeE$^~nD+nkNZs(Uy2 zB2*3=4kS$)VI@Q;pimkd?ROHGAnaO<@_5lBZZttzE?u88f_%2_aS0iC2 z*e085+dT8I7Nkw9#1OQ>qxAz3HC!Ukx8pxL$7K!V2s*&1)85qTii-* z`myA*JEb-;y>#PdBDkFGeD=xGtsE30r^*Bo?0AauyRKYBJ`dC<4>zcvV<^AeTkx6+ zzA=hxb!7^1OGne%igOXibyuZmyIG+hprh;@tV*1lgMYkhHrsNGl2p&rbv0Xlo zm6>h5^CeS@rjIXGhRG; z1pUg4A;oy)VZG{i*r)jgdPJgU9Q(b?Jmc~+hGi+YcIqObFrRtemE-gj>T-#);c65< zw?mnUsr-)dx;E>tyMLSpyfjM*>mh)|{?}`y%=T}(Q|~y)jAsgQ98u74w4uIjQ^99M z9Oqs0l4ywUJLQ1YrHf$-Fo#KU==1sWHrk-x{D?xR1$!*4Q(N<^%P0c@Y9f$} zxZkdg;KC~|URt@BejVrDXDOX&!`nQ~Zp5*`g-(S5Gu(n1+HCRo_!=>)QS0K8huJ6`fdZ!jAY!va}Tb^|_ zf9)se?ZI-o`GElr$*n?Z6>0tt;oa2HUdIXN$0I5edkmvb-lbR=gmZ#_)sGE<`Z2E6 zmf+8mCqGGM2Reblb6+0y@;g0%^TiFU>5OwB}a&!D(8onvpoAQnUTdaMd>x&%^(VX)yY|q&f+#KLtD%j9JwIyegw|W#f~g3v6*V%{Kd>}wi4La9b1QeH zFA#mq7V<6CWZD=d19cvTUrXR5QM~ajV-qc<)#JK~#MTbm6i1ep zzk~|#<#F%1w_blcw>&LFl2Z2*Z3RUzrATyC^te|KJS;MHJFQLY=W~$g0v)wa5mNX+ zP4BxLyA|Q1fdN^8B&+;)&D8=p5*Q5_MUrU>0p9H~`yvTPiQ&WlM&}pUU^bBo!K#FnZ zRIfFaN>%%1S%WfGj6k^Lyp$H0GE#1LVbcd@<^{DgWz1PZcg!E{R|pBh=Z7@6hb?ZC@F z*Gho**@%UDlHH#X3nKPp)x5?gTA#97^TR;XhR7`cM=5D<3am*t$?YfU!~}(GgP#eG z0FCH}hKPmnWrwfTM&gn@NG|BeGIy!bGHk(|;O%}@X)f!qilV*!o^@`N`P+ zGmh(3IDH38Kr#*G7}9Mu0rt1`wZbwtv_b-*c*ZMB48 z7`qPT(e9ckeVq^bec-CHnpzR@dqH(J9si1v5HT9|Y_-vBXoNQMNQyN#j1&T`elqxU zD38?S-phhm0dD$2W{u$EVOyem-nI_5yXUx!O@gfN4-Rd5K1nynxa0wS;W|Sjsy&B^ z#rbc0MkQc(RY%lF+6(xx~mjI5xT8xgWnfDlf=HG-lL@-tT$}SZ(G0^!oj9` zJiTYdi=f-88tUqp(^`&526O3a?34t@cPk;Ct(7*hbZV2VPZG_&ZA zANJoa{U8Gx&3Y(3j6`BFqiI$T0&kPvZ`0LD+mxXiF4gx>^XDP43-)nat&eEA>Azw# zWp;BY+oWPj%uU~}`k2VQ)>^ga?t7pLlNxasY1L?04ZgVqTMD#O7sRAmkw{ZLwHbY9 zYpoTN#;p|Omw}+FtFhKfPR!+giugufT|OZv5!4OwNKO_&=z_m_?hAL|^zjfU<=W

*QeZtN?%Ou5#(H-jsNg*~EeUbp)D6J|8{BH4p7hCB~FX5JNYc!v8!42=W2~MBrmpyV;3?c=>!h#@kxYF!Av&qh>5hu z0@WokA`o%N7);MjV)AD7rFa+()eyZx4@nu=SSYB4WaPDIPMRhte9e}+eQT9F^c*yc zwf5QSBh?uQDYQeMz*dFRtoLKHOPf$uEMg22ioO@W8|uR#-_!5ZKUz*zwq#2!&ROm# zr7akm-6eI^s^pV89PO&5>Lc)V#CF!c3SnRm_vEqm9*alVJ}i*B+V64S!l%%AND#Sx zrOG<{%a&6|ELF`?fqC_(SSkPFX=++Fyqa$@&mlU5z~1N z8D=&>W}?Ps89*Pgk1#5IRKT5A{OXI>3}gAfWaZa@c~ve>!t~gsn0_@|c3@{NZ|XC* z?!6UNYuEW}=8R#2c;YK^`;jb6@U#;1guWGryj3Pt%K`iOomCtw&bc#`d}>0xgb1)V z%uIxbm*Rif=wF8Vh~x@iWw*j+R5lsQ`EKk~}|Ai=bq1~sAooCtO(*NyD z|M#cIz$oK7yQE`e*q>nQzprz3<2CvJ5Y(SP(=>pLDUwm7^G~7Te>~VFcTwX1ap?D- z0cyYuqWE(Pdb2+s_E(bf=j<11;?Mt&L%;uQU_UFAWe|rK|IH?TpZJ#$2o2%?hcskf zMgp!qeBk_(vEQdVN66v=1_!OJt<|UjAA-Zf!xOQ&QE<32RG}=RZkT`YoLlOmbCC+< ziL~P1ADJisk8jJMvUlfxI4D3x(bX_fjfFs_S2O71q>9C?<$;MMg!9i-ibR zCITqm2tg?xEjh`x`w@R$RA2os?|fX}%?Vg8J))fm!{d3?)2shZwj&9@efuT}N~@Ys zC;9};-pw9j9IgP<+J+*SJm*!^s$=Ip&L$YxAuuZH=5)<5Tf6KJ)4PZ3pEHR_!zt!l z!$^rK7%%lZ=cG7hqDl>Ryj}eIQ(IC}QwN5f`)m%Hf$^b9t&nI#z4?dM=p#MW@yCbT z-whR#gpZxj4`9%S!^!nJZUgt(mRW!jiR}HO+Y!vJ0D_#4~_kmt^Yr6l5PcqI|UmrO;P1P~ozas9nuZ^3{0;b-$od4IU zx8!tH*U00u`ENjf3{d*-eq#Xu2WVntC@B+N2DSG{6@+?SAz3sg$ zCmaM!i3@rIJgwyxZ~bC)4Gb2#qN25R+9y_1f@GEL^t&jj*^WH&@07&}k%$Q-84m94 zrg`qfzj4mbsyb*FD^s+v2!X1XP5Iy)ns2BK?MrN`T?30;PjxJt}1>k1DrL>+gGeeN}n&{N}y*#X7V=j~@aQbLTyKd?mXD^9^4@T1vAH}8L#8q+hk1etsfr0If<3g+k zGd=QYrDPimd^PIxP~D>Nz1d{!G*43(PyKR=!;}gy$zS6w!V$1~@q#!+^TFRC=LVgd zsv;0&1g`${?X1swHH(2$%Qwa=!w97-Z1IKnfjwKC03NVdo{p2J$nFr;?3hK;77GR&0W)Xv-G4|SlctQwN(AO|w5ejO zpI#vPHoT2CE-KI3HF6!Jy7@q*VrFlDL%iNOpJLJxlP|sN39w4$Qt*6TeK}cV@GtWC(;$;~Y9yjY7AG)%!O#>mvxg;(4XxB1Q#BM zoMWg-n-@{L``dS4r6UN6fa#1(RBe;{^%ylX|AW6+4uBu{?&cb~yH~$zv6?E&Rjnv0 zYJ59^O7t3*?LN3^3oo)qU?mB%x$kG9D9t%ckNYD|y5!Ws2^=#BA*$H&vNF$4xqNPj zqFlHZ_ypLoSmA-oB?PjF&AO@L;uoZ1U6SY4mX|LnMBU$Ip%eHgAehY^Tc+J~a*S`9 zYfBXATne9}{RbKuk67k4-UvxT3Gl_L_&lf~3#Z_{s=R5Z(KPLC|; zG|Ni`+oL_x@Onv2MqIf|QvgY|N7%TE?!D3|tJjh(H*MM4HW4v3v88#fOW#x$Mu&zL z@D*UpO{T}M0EDH$>T4nuzk`kj_UkX-1*^FfvQzyL$y-3R&$P!bs=#_$_ z`n~&wzT&<{ARgwbYGAaeb6dCb3kufw>+)Mi5alYOW~^m-Fiq7o))P0qGfT-`weWxmK6kXu zv(q4?mt>D%sqsA)W3q8y?But*GN;~@bh2XPd9~K}n6B;!Ksm7l)hXD0oOZtdamr>J ziZfhpf0P2YBt4ntOZ#^- z0+2XB32B*d>0hI~`m)cdCnTTls2CNk4GNL+ePv03DI%1{5s2Bz4BEpP0Ep`fp!+8K zo!WJj_O-hfLcZ&}vjEH7sf3I7-k8OztOapxnt*y=Ha7c?I|5>1cQmfxP4jl$@3eYq z69U&zBKcgVMDzo8X-tkn^6J!P`1Izc%kEKr#mUeJ6L zOFy)evokaI+NT-k_1V6$_&2DLEHhc6wFX8MzW2S@s&+w6NRwL^LaPSV_~PFuBlljnY8gz6VnHybhoKr zOlidpH4`j#KpUBlm@EtcKRkwT=4rOxwO4g51b z6>y%|+Y2I(9Mb84Yy#X)Qi_2SsVTQy=miCW_LMM#l=;0(8^pk*|2=}^wZ3`^0oyRC zE6?ku`Tg`|nO-n__mmXb+L`rwvc%wCCq|R8WHJG7fPGtBm2z-$>JR=W zO^+M&*`LG#!D+zfpY;b@yTU#p@Z`^Z7{vro4vo zgL|MOX{dpb&vgu-Ld9kQ%Yg@a7KcKf(rcx$U$!5E)1mye+_eQ_FOnjnl%@?mYjdDk z^~2L*X{a>VuE^HYe8E_i-j&^KR>@)4U09+5NXXN$S04JLOCFlRleWtTy!z1_ee36d z?uwhi*c~8nmLa^--{A2#Z*7m>m}3ha@b+VNC3Qt`{L2WLt{fgOuG2QN_1Chh%tv!E6AW-p@u(aPuHO z#80F8Q3$9p^t=AZ{_{xhKFc^cIb}m2TQ9X|gM7ur#m^^L^NBr;d~=S_gQ{=++3~Vm zVQ1%a3Xizh*nP?GBWX>oXDVKF7m$5i9dw5uj!eh5Oayq5f-TmkH9j^c99WY z%0~3_SuxLFW){%noA4rYmES8VfQ6KOG{eiS{bSzQSse+Em9eXO0O<0c3m-xcvJRe#l#l^G0JZ>b7=14CG#%slt?Dmh zi1PYBUJg*Z+YoZ?-#t@5Wki40&gN?>qWSZx00sJ?Ei=mv`n)MAr4jtEJ~gue3g#V^ z_a8Mvpw-Nr?38L_W7Eu4F>&1GC+s|C#W_@H7G7D~#19BV%K?;9{6= z#}=w+Jns#g;hJSoo6F|S!&}`azbbou+CU=|db#(nrZdkFwgCGyTR+}1-dgBj+~A+0yNNt!*fT+(DT^C}QU z!9=5LeI>C4K=nIwVPY1FBmz~C}s8vycfqYWTZ-Th<-z%(+R zjo3-yb0C+YahF3sO>y z`!*fY919EV-|#?Xj{8zPD@HbN*-kGSYH8gBfIDrF9Ap6Is9SXaTFHm27yyc#v|m>X z8Op&(j^oEEKqAU*s;DjiTUs)m(e{+;`pA$*$jV?=NM~oKs*#byMR5s%H3!}AHr+-H zxkD=r0dIX7;R)g+aLi>Xmmi0_be>WIPZNY;P%HqU4lkGP>79H_OmV>1w|#6Utrw;L zuV%NO?JgH*Tl!^~&g=*~FF{ZVNeZJo5YU&osBseoc182xP)vSD?>7b%csyis3WaLF zs`Fn+qY3Vs1-PUJQ?R*WpuKoJ-dfo-%#cHri%oq z>`IyemN@a0s;avZ0Iz)AMC3j78rC3hfLbh~X}rt^Z!4`AQLd@4PghX8C#i++VBE?P z3d#jQVV>^yIN0MFoD0L@mOf9sa>e}CQ(h6%9R$C34(;3bVZ?w{34#`NUKEUHe`MsC;Pw(6}aIfL11~6+kfMt3p zmBm!Dd4QiHWZfI(#Td0m9cg_EJ~43a zK}-b|93woAmg3@?RD8Dv3!Ua$Kf3BEqgI)Y`UJ`CLVWOh)pi;VF1cbnK*`E+@tgL3Aq_+wX;km)v%eYPM_XFCDegIqa-Vh548HfDIv`IuB8+V?>@v2ke^y(-W+_zJWC2WnUnUfC~?bxwq-lByP<6HC<*4 zbgRWA9487xFp=s}AramS%@2o3w9Y6o9_GPo0b}V_dq)S;E0BZHW0(itM;Kg=sG8cq zF~DuEGc!+-nz{Q(%|qR;Ubt@TwI(T9(gS30=#!*2py9sy%vt~;%#*pSWPiSvR2u}$U+hkIWUoCt zW>*CmLT&b?Pf=a70Cr3+<1pAITMir?5(7(;y0;J~?Ni@8(Fa3Nzb%*qrKm1+<@bGPOZFlnm!0)P#-`{ zn7Cdq=6kw+dW_nr@bhxs$2zQUnF-i7b$+wBBJ#-J8c4RdPk??w8rNyi27u@9>#qx3Rd%`3aIrSNRZsu*BigDDv4;Dv9q<^ znNglkv-SYHWxBFw6`*w1Y>*_>npv>#WhcZ;KoPq336sx+P2XsfL*0RSYoTW2>i%Zg zNm?PGJxRr%_(lI|1q3fp#l2p5tlObZXFukh3+>Zx(*Yu&5EtYo&2eLO=Ib zSk$dGeQewtAT?oyYBwue9xYgQQhtI=Jxcw7!J^SSFL%Et9l4jjV+c|9Q=;CWYgeA? z$G~`}(;}qMvjyRpm+BApx%QL+rsbs&6(95s$xutCQhU3k-@$7z04E~uA~*cY@cy(4 zGWCQcR7SoBX6wZo+VjO`U7j#ya7vynk3fcuqBP06fPACH>*nM1>b=w^fgpbp?e)re z<@(C+QJU=#)DEn*1py238i0w5f1Sr`Y3z^_wM8&lAQks9Kppg!aK4XZO*NzaV|+oM z8bK;6R!->al1c%O$7Z!g*Gbe!A@z7vd5ZC6AUDFS)nXqQz09izGh()L9@ziaq=-{=2m-M(f|K4;Swo&fL>fTgDLxHU9&b!TUzgDv{BXLi8{jjZ6W+#uMG zwpW@nu5<4dfS$~y955v{?j+W`v<}#IGFJYEIGtn&;LnvZvhPoo7iwMgrr;?ddzJ<^ zch03nctB>)3#@P+((>p~Ck(nuA9SefkL+vq_WGTKN==q_Eb4ntQrGBuPQFRqb>|{NsR{Vg47a;15d^<~e-7zbAL!#zd>|wZ1 zycOuqLA-UOx{1lxkz615jYeW@l{uYOsu<9_u=1Ui0&k%Ob+c4F4MA`c6G8b1gk=6b zlF{Rb0CHH8Sf1d{J8QLe9&s|V6beygajd|4&G6o@vKx>^Edy&tPS}*}-(dAjS+1}r zC)*+*h?@@*UzyA)@5`>fw!M|2(TLrM@xjsouhE(nkWl7xvI!g@7lHe+$z{RQev3a$pMdEDB$Av=j*vQxA)4;RA(e8E)!m@n&jE@7 z10-%xasueY=?%9GQx@(CM-{wz47#eM1@!(Il{xaf4;HoaNZnGH6c901Vy|%9j>o%9 zPm2`D$C#^`PE=jVZejWJw=I*@?Zl=B+HOg0d3&_3>DxWo&KCDPIXW;t*!tQ8kdR;- zOBIKn<%W;9F?vbNAFvsL$LrR8Mh@gBb_jx4iR#eiQBfFEJLVNWF@Ac+K!>ue8P7e;{JQY_w6Oq6J$3t>E?s~u=_!*$&R?) z5u=jA9TcN2Kq@Sbfj2MgXW+SPC+PqR$(gQv0O7rw9#6_P=tDJnk9SZTOU+}rI$I$2 zPZEIUNPy`(O!D5kM-i}#@D9otj|Nq{9#rN5*!dV?W+mvXB@?Hj##MaM>48#xUwqSJ zU0JZeJGH3|U z(cR#60^I+UW?lpT!67HGgK?KF(S2aG9A8Ly$12NTgBmq>mAYe=Ja+O~FBBkT?PVa! zASv86IQ&PQ3kN+tbf{b3Uh3h;(=uf~B&dMX5mg;?Ly8TqQQcNMvZFLYA()O<<047A#l$7jF zr!CNaqJV)7h#_6(=>kSUP9h*N(a$}AuQjk=dwTM%Bla|ymqFKkWA}=XgNBM*c5d9V zvC5E{a3CSEfySwwnn=#f6VRt1k$c(SO72shn31#%fCPF6GT8QciGT>OfG10J&F^%b z$AdUuw)=$D4g<+8xU%lE4ra{u!P=b8fg)&2gvBnB_?BGm(5P-2vh~_AuL)vbV#hNYoQuT=U5-O41*#P=4_a|Hil}>QCxlGbJ z4yAG#5gD{Q{C$zuSzt@WvCoBrzROSWc_xeusFTFrQi_$m;?O;DJtMy^`FU(+T|q@% zs~6mS!jdbx?s$0=bKD$B*>{koY)6DT&+s+Hb46!)nwS=^Q{VO#IpCGLZklD#IfQxG zx!qCyzgOyM_8lG&wKbCe$M{lTeM5h+C&?gX_Jm_InQuT5yG9M5?W;{T;upzoYQ8Ve z*)*rJN7ub6Y9#DX^!jAzRZalP1SH^0^5sQEv=VP3jI1XKR2E!+pKG8{Xyt- zOutlY?$@m<+gfC3Xz+i7`RFV_;s$3BUhA{4Q{2`MYx{eA^8nLt>Y)(LQ$+DH8HiUK z3O@VebbGmm$MUL2t0+C4@jmJgf5w>-mLogmNZ@6abBar*5Q2ro+sG{L{=2b%(?BVMV_~%Puq(jGF z@d_inu%=}hU28C^Msjhjbvf2h>1>HFle5rxlFj~?=sE?l|NeLd@N*lgNL>E&H~w9w zKVXA40Q*h+8rlDkkN^HDNd+cj%2hq{@7d(cOZwMdE4o+}9)rnWKmM#+|GqWJBKeK7 zB~424?;HQL`}a>tGW5}pjtB2tTmSb9gbxApAw)y^;@?sHU*qWCiUyX{&&N>#~zJkw8jHnwpct z&L=3?*XyD1f&EnN|L>06$9nwuu@rC@wXCdclYgpS6l=%=%+M!aZy(m>r>*V5 zhSH7C?a(6P2V$G$PUrvh2jGq=V(1s8M6$5rPXn=29@0^aJQ#=l2}!&P3KhDrxU&OV z@2oA7IN#>TUy)Vapt>_y1z?+^G|9jI61;u(H=&Tm#bY-69DDY^pc?ks6M=q?J1&2A z3lQnKIr&cS{?vyp4=1x2c62Z_NfFQ&dRi|ex(eN?pb6pn&Eu|9B>C~&j>L%2MsEri zF}FpYUOeL~FJQEQkYc+!)b^@WCoTfR&SfzZl9+G#^@RFdqen23J2>;WfBQD>+2uRPYOhgny)SmB#=^2QXbXGyXSrR z((F%jgv$E*_0GV>P>kegWeANp;KUj>L6r?abp$H=?EAQ4mjFQCyCKsu{BCCkx8~^6 z-P}U9jx)ugq1oi@Sg^2*!38KtHD);eMxuaV-5&-#t9h}?6cn0IQE z`jq!S7w9ZmSS;0anQ7Myz~Qq?KZ`y{Jga+2aAXFtQa0EIXEJC|dCkfS{C>9N5gIUv zW>OS}=_Yh%7?X5-$(LVJ9M2oLsrW&&{VNSe_Sf|EruuYLP~Bcaf|rN8H#!=b6R_>O zRd+cujQR7uOTvFSE%GyAZZf89)n#Rk2)l5t=jkOTH#LQ<*W-12_EWM>-XN4`?jXbEGv$}rp>);Nt*KJ9Z8nakLecwF)_zMwt zNcsK+`TI6HI`S1K#~uxf{n`6D%3BZGE#l2;dXIit+0&k?nBN<8^xm7dCL(_|Sn?w7 zyLaybMr}@`hCTCK%=fLCEwND>|PA0~(D_7OL-{Qd|+umP-1Y?U~U z0B7m7ol=|JhxdDHy*vO`Z6S)C$Yb!2od6Vr5HuEM!ryVbg7YA){mAKJ>wk`IGsa zqaORkMZNM>{Iv`3(rRnrV`G-o5qSQyJ}aezowGwCOP>CRe%}azNm=v~H>k%vS*L&Y zzWyhRW50v@8ai;>r_6f%XNCx5Z4ShWtdCB>t;=_4E+@Oq4kN`s{+7N2K#0IvYA>DN zKbUFDQNQ+W$LzN1Z<>BImzG?{-kRlDCvXNAU=9Jhhq-iLkEkb`D@#KnnAK*N(D-jN5|Fo6I;P$o8>1Ex$$zd z||R^Fg^lacTEjA4=%1Qd#N^ieccSOEC`zuWEeWO`B)2zsNI{b!-bM-wOhK8l_rCFTfIiGvU<*@Sw)M*5(f6ahUgLJVT+pe^B)a|g%;mGK=UgwfHG=kwDNfC?^dJT)_oRqSIbWI{CN~`@JZu z-QZ9VnfX0OYHX%m8Q(O?Ey8Es0i+A;!O)@7)zkdb{@#M~sDb6-mf?f!@kQ4@cv{Qw zT1p7g8(gXoqQU|Lx6k4EMG}}MdqK3Sk^HnTA1n<-5v!8hsdN1a=AC}#OHX0{U;hn* zyk{_}-*5lhC4vADjZTfI$Kxtn2iRA{3wE8ruP0kR$L70-b0;Grx)R93NRQUE9wvU4 z-lO?Ksg&7SCg^Iy#G!IRUB`P;LOq|OD`I0$wf32P-cqrlirV2X8d!6%X^+<*!fqqe zXlw2qE^3x*i>;O9yFyp*e+`1Ds2qM(_PPbzY->k=bcLOsr}y(-RIb%}i1|Ln9|1=D z^8p3#w(`j~FG6HuFXBq)vq7UsF~gms5SP9z4-_7BH(?#*_O!o9n3ERGOxOq)gkvWk zjGf>n?{%E4Q^1drF0PLbhm0ae%0xKEz#<>(tt_bvmPq{uaU|b`i8O=qeU2;;1joOL z4N$9k8e6okSBk1!*jU>dK;nqa>|Wj2%v*WRo!=c{GX$8M47R%~KZ~6Liz(DJ?*nWf zK12IhX6;UAf_NR-^6Kj5HzbG~z+3Z1d5C3>KTpjS9snT~HsfXZ$F-K0mYY0Yrrk*^ zYq!08H-D)`dYI{)=iu31imSTs7MurebeL zL~(87p2O_3x%K-{$Wo7MjYcI`!&%)P?AM<`D!}cpon`0l6b5OJW_}&2#zu$REhsQ` zX8`Nq(n%Haa1U=e`0YJB z#7+%Xk-}vdJ76Znkb6WoogC%7);Yrz5CD0NPv4BMS*f!sYh5&bD|>KdM5i;)Gw~RzK>XcH+)}+iW5#&elHHV@S_^K}WR2SBhYMZph8gxKZ{oPQ}Q` z=%|8vr2xyc|D^LGmTXq^y8UutOO-8aq{hz4?<*5?@B*;kr?y-Hq2DxRb~GQtME&>&-fKb@FiJ4> zb2S}2b`im1p8hb){JP^{b|5|o_ZJSthEEhC&VTdYur_fj)!QRLmssZ;U!2T8Q+hrW6 zS*T~-S9)h{N1oHI*yrY_sH+dDonAvlK>SOwLs<#e+b(0hE1~(h+*b+2wtZ*jT&du- zwb!d-V)kzUCL(ykVtP1#1C&KbC1<#7K~rTquS|cVRuNkzko7?EwiloK$?cb3*@ZP$duzmkV@=vCEu z99+A$$Y`=@yJAoOCEFq|>=A{s4#|t>yf-CO(>{5HJmy)Uwx|6;xlp{N=7XbJsNmN5 zP@u#dV&gG7+S#y6P;VT2Bn0+~#QPg!Ge;Q$`(dAQ_DuvgqBshl=oQh_=s%XwOrFAs z-_H)0DVaRh*7;1YLV!_aO|mFy_kxs5bFM&OWk${eBR|~~Y`IsYs zU~My6Z+jp*=(7B%mPFN4FWhdsw`I>MpAdg!a_4i+@$-l9^3ddJ>+!zTi=x1@FB+6D ztD`I-XxeyBUSzn^`PiHQZ-0vqeY{0^?*$>R>g|iRMC@@0I;$OuQ z*-WRquhpPNx^tBAzz%iLQM}`Se5;7xVxZ#T3W!Ns!Ft|ONw{B&s+oWWkTg9W{s~10 zv^2f1UaK9gv60wLB{&EhM_-o1bFfyPY&fyDVKK3j2PHuBNgc%~!Q6vaHQWo<~l6b1eTIq~w?hR>dDUNg%lFM;8@W>(P8l~weCz%L-udZSVbVKdd zARtzd!F?&+f+&|1(23qF)M%rMB<~g5>ToA_3TtVbP4hw$W-?z)^mpGFUhEeI>a8Fuj7K7@n1@z#ABjB6q%SNq`xKOc!y5m8Kz3#6*hf}oA zEQgf?CXQE>D}u-IxJ2hL@?ggd$8C6JTCjKXo4Gb#eTGJPdlR5z1f;m3(WAW zzV3?mv^Q?p5;RU$J`#GOz5V2ud%uRx$7)y*=>P&83Ce}4>WmJhpm~(Qu#l~gSYUIrD*T)?-b4el` zWUEJC2@}Yz8F#_euJB1spTU(ycMxq89rlArukK*{q`<;H*yGoP7ixu!!Z_UHs>JcG zk-^ri;_QY*cdhNnEd3M5qj}+@1!XSYRJU*WUqSB3D5nbB@{efcyq(Id8YzWGbTO^j z7RSKB+(Pb?-ruOXQ%&~s)WBTudqEu6H$JYmn~?t^(pL;yQvVtDJnj2XXlAggz?tq` z_M1*tAiBd`HzN{hV+t#?6Tf}z?1Dp~I+SpD*t~X!NBU)|%!ePAcx3Fh2C{I^5r)t6 z%)buS>N@OiA8%Ra%3?$=#;^}}8?~~=*R^fRXM|q+QbvNxadjoroEwu0#7rR9{8|wy^lEJuZ219U_1I) zwNdU_%b*m4j>W){;$T&CPXCvCOdFlSyhiV7@@*;7M;qN{MrfA)ergL$b{P3%tEF=GKj>J8c?5Ud2MXjG*P_N3~4thQ7F{@GuF~nXKYwix2$2M47>iBfh8rRlaa=XGQ&8ttfyNSHAZ^C1DrTjGY%TY zQE}YF7ttJCt7(U>0$~T)UIX5CwH00h$%-w7#bu#O#e0@juGCFV+6j+i4K>CxgrK6A z-LMs|TuiLn6iQx5$m0ssQH{G|^(;2v#hFz4O4i_X9G+wiB;1&~f4(>V-6miA%IF;x z{`ve%wB*8X*}i+Xn}hxte{>iB*(ly(e56;x$-#Gq#i2`t9HdEBZCYa~{ zrHJu`ur^*k{k#8m3O0fJ1{LMmi}j1ZN;1nwc%Q#81qX-0CVYwkB9Y;`|h(GG9`mC~WaupzZI!~p;CB}Qkx`}_OD za>BPRo_>`{@q(YrPmr^D-nS27zHky+S!^64%hN7!yJ77A%mE?a^Rd@m*OiiPi=7&5 zI!sJR7slU-Lr(6-f`1$!=L`{QmC8_C|*XT*+#=+p=;7Bbl?rYLJy89CUY+&4^z_C$FeF!~o zxaTvbyN8DuO}-5LMs#fXH^GG;--_tb>(c1)x&H1v{3}#?UKwFC^k>=B=)Y0k{UQ}v z`)__ja2`#+SE1+PJL=HlVIY-%a_a%f-48bi zi>H(I^fnj<|GOJ6&qbp1p`--IKr+mAhj|0Tres!xK#K>AMBrjb)qZpfCzm>90%_^l zq}qXT5Subhp(O|%yTe(;8vYvnRe+lm$V#(i$ccrfW^Ai8{=S(2LTd-k$4T-A%*`@!s z@aJ_3@fUbpGhP#3I-k)C7;nC{wmwoQI_(Y^$mBay{V23NT=2^xlKh>^s`UC?`TS-X z=n$VuOZiJmN-$+!&x&5r;s-*W;$mKKQcuZ|Cuvpx{I0^vYMK)9;x{F_@q%GQV;Ia-#q<-?S0Mqyjr>hK^q9j4!7wMdw0OZ zeC2Fdfs*a&!hPibMwPOMT~bZfIA&XI5Z{eg`pg3OD{fI%u|qE4c#8{m-&( zf_`kVKRTb$i`eRtl1bHtrPI-~NMGkhPgPrJn8r6e+F(H5K{vX9i zu>iAR9ERVUH(p4?La+N0*ah>LwRbLa)DgyE zs8^kuGD$U{PF9Nz-IMA$WZRZ!XZ(I}KjVf^6cza4`I4#Ajckn6)1Kd<; zslAzxJfvg4PqdU-!1|~Q|G}wQ@%w?+P*D;0|JX{fxLkx3R8$?M@62x5)WkDYorG?(WI;t$3fGgDLP$?N%M6((au<{9YpF&R>lZ0qF^C4G>aWb9hM2P0PrHfP7n ztmG^9W+@xM;Z_w{^~7guuhZ=)%f`YY3>vG3m2>bD#MU)@`=&p?GENyGG}&69S_t^BahW=;|KyB)JUC!J?An$s;Qp8v=K_=V-U&g5R(rxSyrHrjuwR zt;_UI1XaSB^(_c;~t3+C3)}PAy=F0OrQk;DCE~bZUwnIfSd&usRrxJm4z45 z5l{1lnL&Cp4gvr~1oE+~YlB8mXtKv>=;!4ZeRY9TU+&Jd_kY!OsM`KnK791T+7%Hv zSDygiCQI%kR?gX}o!Pf|oii?^K~?>>rnaOv7E+b*d`?epBBZQ$%WpQ0maY4a1)G0& zsC;?I%9d4&HTh`lh-SlsJJs*dnrlV|jza?NZ%h);rBR;(`w`W+P2Ev_Z0)u&xe5d8 zqgL0|%DH;zQGaYhq6-}1=GK^%8*mMWP<1+rg`_U0!@c8y-7Q=;BGaM-OGZe;ZIj~u z8mlzPXlge1#;ls=-rdLTd5a}G+uH#kX@kHM0&rg+*J@zgDB$*yEL3i4tPPjky= zKkm>edk!soA5pfoBtQGLRQ^yLH8vQ8g3Z-5uXHzDA{aB>8YZ9ZS}8gH(cNq$(Wxfd zudGuvD>L@fHLFkSO@`p)B@8E~lr6{aFOzH+znbp0{&4D{p>dl|Eimhy1ciqDyuIc{ z#iw2u*Q0av_mghTR(ss9 z0JMX{%cy{ubotmIP+o|wBYA?F#$)+9Oh*p3*}Piz-kqC*A)oh)NBwPHFkg4s+a&cql0op74f5aa zJ^?xY#zUnR!FnF1A6$;^dDkp{^jWchu6Z%`z}=S?*Vh{eDm2$Yil9}}cS@^k!TY=A zaQA4a{}mcn6`{G0gH^jZ9+Ay`JN2%G5YRHN@a*Tg_Xy|+;bMQ6jXgmvmAngbqyya$!Z|q;pH`X zJ!ji^X@m0chmA6}JvMtUVStLRtt$N}XSOT+h}; zMW`v=8?TG%t@?Wk*kR~-(*6Ag-npwFnQ{-ObxY|b0Gw$oUM?hbHtcAjV%}%ovO~48 zov?wjS+v-ImLX^W$o%9A!eK89T<}&O3itth!uHJ`8V~m%l;?{H{@geR@wz(8Fa)f%MdFI0i$Dz}tId#>mRpWtUPD@Gll(;tw9T)DR+6MVu z`V@Sy#?HsJ6B#jsi`tJ8w;6&wDn_DmvhTWPHf<_!tb063U9@ z;m~pR#k-Td|BJS&=aW!uFtu}q$EUW0)$dnmvB3@HH6h7X_mm~vkaCA(Ft=j7>iv)% zKr`MXw}9^tKzVEiIk(oUS#zLu;)j#uC%^~}PFM*L;3hSn>wNaXQ*}AzRyC z+2IoijEHM`Hfs={RJ9F*U%J4=Q{YA0YVJF1k&$cLRL+=eRe1e^hLSa~ckuK+u8$em zJlyK8E;vjj@EQtye&neKZ}9h*Ud7L}+m5ygPr!zLA9Ncsc<37U3IzLh)p*%dAcEEl zBafVid`^tT`I`i5SITsbj8*rwD=`a)>ReZ+=~ZYkZgWnXV5#9`;x?tk#*e$rSvhxF z+bi$*`Q4YupSdUEE)RM4rOeB#hK30N$ZFJ*`e0XAqK6pY%gGIh&rzv2ZImgjxj$B- zN^=`Upd}un#-TiVA&!h?p?Un?)#|h@Q*X%O< zZjIJ5jBHl*al^2Pew9}Fm7VR?gH$_i4^I4HSPhSAyIxnp!S~P8kbN?4-Xogtk~PirDDU3ZK~2 z?8E^7nzK&aF>&GJM3He=Fq`U_c_81t*|;hHpC&&?f0PNVFfK2KMd#|250lHc9Jq#F z7xnSJb-BeEPQMbpl3#KRd|aG0pYK>U+uR)cn~ZQ}Ln!jhoAh%hWZ5Y-6KgiUdhYvN z@MF3~r>y0cb393|Ino_(<4mBABjUan4{`oN{&8W(B;R}I9a#R%vasBEsCU^Ko{~1iK<6RW{XlVJtcLHygLy(`zaX4V()!`GG8=G1)C$?7H zgG1|(uNfj+KJJ`=R~T|3;c!c9GJI3@*BwprQR6^pde{MLK1bQ0Hyj4CW*#q#Ap(fU zE)9lysVTt0;bJ|)1=cs1E-(vnJ~zXaezQ#ACcJ%PX6w%@-ch=xtgN++umqb>+Kq4@CobKl>GzVK zhhk%)-j#UlT(EVR$MVe8be!SZg)fvV=|(;l8}1XUT=pJ^8>I-^W5inSi8M_);Mb2T znr6KsTMiG~G>?CJ(|A|obYu)s3GVJvSb&0-Nc&>^)tQVvwp^_QqG$${JB|J$kLFdM zZD}M5)Wpdxz4c|VGn;BA&lyh{{K{T9YGF~?0l{?nShsC8UX|hHh08&&ibRgu5NPT- z8KcW(vUkn1iALl%n!9nGOf!SZ?a&%u#h2xfyQuzr@1~Zg^I9-Yw&JWdx6u+D( z1ob?C$5sNx_8f$2un-)9Y#R4c(crqBTpL%~VNi}yhohu{n)8;#R!1MwzTRe!Txt_r z<7jWT_2pC02=I5B4(T~O-@xm779gxJ4geUE$Dy6L=`G@z@m0aVgqg7HHl{t0t|94FsN zcizUz>p=jqH%j9_qI*NAx}<1lh*}*_*b2&a6ver>>Dve0V7mB}o^<;O!*Gmk7P5EB z8c{DhVBCnMy%W1jyfkB=3HzGd#;;kb)_S>6RX8Gj{W9(Woq@*7Oz$F&YP*R2wam?4 ze`T+*rFVl`!`>gl8kvroYO@Bvc$Q?>+9^FNAIRZAs@06N5o;ITFFm$Qv|KQqC;AL( z2QExT&&E;9Bh|^=Sh_F!Eik1xXwKytTB5eux3|=QDzxLcwZ!0d63$Vr;ZzAcw#tgM za;#}oG%i%m>7Fg#Sxl?4tbSr%njld(Dl{fNjfGqS3(-kEu~ z`qU0$RGMs=IFLGb$*wE%=?7!_$)8q}qMQG(LoYV0)BdxzY2Wo8iEGzg6IKg~^|2*W zzF>Yz5q^Kanb@khti^(Ij+Yk`Zg`Qg`bqjz+EEfbDk70mV=Us*evPpKyuQdGWvil< zws6vxNP(g~%V#^oo&tJ#`E65FMJw;SW{X$ebqyHzWwDitm-fa`vn8M&1Ig>ebWB=2 z>`cnvXb&+@8VLwe&ikQ%GP_!KpfeB||k zrJg|U{*xs(YqgJ&&co9B!Z`D=k0CFud5T@VR)&j5n_lQer{}d#dQbm>kouVb$ZYj# z=-)2+$Dn_qr%M$Ktx+sCBf~x2J@IAfXyYVLuEFYf`;S~6*Bd%j(87h^MUkxnuS@h)ZZ=zukPgTn%o_B1!V-5p(d ziaknB0c_W5%&4K`ya$pE*Q2m`C?OHQZ1v*_!Fl@~=5~7g>Q`)-qT8-E9~vRbx(@sR zipN*a;Y)xSNlG>T{;h9jF(p=0eDJ7P7_(?n@Nera$mo;r8>NbqQ)SIaxn zf6sm(jM^oX#g>78plfCU?a6@lv>!fvcmqJmbxhBM<^V|1xXG~ocr4t&=8IwU zUm63DG3V|sm{hszQLStSnh>-7_(C{FeqE8&+UEy%`fyG$SZ2i(GK{s)%+f8x4tbh>r zGlc@y`HyIGkK(-k$^7uiewxnfC1zr z)9}uh&P*6X`+6HWR7)j}(qE|wzop^G6u9RBHKpB!Db*q-Pn)}DF@PK37hn734Tm`HT+H$GyPcNSiEjS_##Qdm20(&P(k zs{ATwEKDZbDsp&g96}l%gynE^+rt0?#b3a{{9iAMRrUx4MTxtI8 zElX8{FO~VcYSh_pZ_V6&&x?m!d@9vI08+ZZvMpWxi1_<X|_Uo!8eOeD&f8b1>uR$6G|c!?c?GhY9Ws-UUJqF(&V<)Stc(}bv?Z;pg4 z9xqI=26WTjH{VOj_r0_6c#cKXtnm+a97N_hWw3EJO^`MAWZiAradCar!YUp%3pTn>Rxu zrVJB3P4JJC7BjuxBQnDb@n2iXXEP*m|15*w7eF?SItG8lI<-Kj(E2;cUm?w;F1ZFH z11@`!jVgJZu`Du{Nj2t*29@^4Y=(Vyl#M~l^nfmQyIwYZLAF1s-#mfXCan8Jef?>} z>%r=!_LIsTn zgRW|iq{GeB4f9J?iMcjqKJ+Q+ytw5ohr9Q8by9|L06lYX^V|O4sWcPEP-TCNm8q-2 zaN4Y_O+(2y#xdRW9sYjv3EMuPifM*-#+06`$J znzm0?^5LTdr0|u$fKe&PQr7t&lZ~%Tcbx)vI!L#f$b7_QelSU~7B=#+b3Jn~F z1cgYRjV!COJI#d0KAP-J(1r4d+lUL~-|P_FeokWBZ}NQN(L7%Qp0IEOECSinJ3=v{ zpkk6BjzKhfWo4J(Dnao0rAr1bK0Y^!Jn^K~wy8-Tpx2ID9?WUi&r9t^=SJaM0JaQ* zrSC`BCqjex&vKjyETXI`0xgmV_lEWcgSn44$fzoWO3KO^lU~RLzm|PVXr_cg1Z70- ztS#eHu0hFZ4i*v-mDS0%s?JK;AqAVr{&eHVE3agrcgm}f(=!%7Fy09It2i|bI49{j zTtRLJ?5(V%`j`nV-=yjY35lO&SW=LrsU{j0QM8n3jZn^>Dc?Z`&AF^d&F5|v>Ic<&lZWFYDfb+oG+FI?hyD?~NN52Z2;pF+-YrK0L6KEcs zH*o+$fOBbN#=lxmUeo&VNAw zEoy|hj5gd(5D0{)-gnv0&CnnE9BlWq9c~0|6f1Lc(E8a=8c|?W?%fhmVBVcn1uoc1 z5~V(KYEp3s-+fIbAc+3AE%q}-skwz+Wu6JCNYF5D(j)dvBVQ|UTg-DGmv3mF@bNZV zF~d7pW<~%^NOA^qTJD}D1jeQ$F8Xn=nmo8GaOfq;!`HC(rSXQ`{B z(d&ikJniteq#sOP+a=68dPquf8oW^ssHYHPVQ_Znz%*&BlO{h}ag=QfAz zz{`f5+%0||T0PQkp9OE`(w*k2Yn?2AF>1;6wB2pBd8yxmJ$hEG{b2)9&(TwtXv%(i?71&HU9poHny#S z9!(}Df22|Yl;~W0p4oflT%|e~F!C;@)A)UGQ6g?*BvQWL{y_QrVRwD5Oy_c1X${A+ z&sbZ0iTy0D-_84y5ZG1>G9bx6rXs`B{%GN4hi=ry3rw<({ILo)jwYp zz*}Iw!SgSY&ji~~9kZ=dV78Qt=#~A`udNn!ID)2dtq;YLAQmn2^2O?s*&+Vf!BkG( zllHmy{Tfu1B9+!gRzI0g+Fyh;l|LC^+h$VCs&HRNZwI_@!MeQ`wN#)uUpR#~l1hrL zj70uKwoj*h_DTYnOUCcqP3~G1PO=PFqK`4bu+)SBJ@d1NlFeKu}9(G z7%6=+BD$V#cF|0Bobz`I`4#OeJ$aK|CX*URBAc$2WHG$0&*-Rm`*LBuUPbwr>(s;L z`K$s{-^~lj?MjF6Ha=guwnO0d2tS;sr7fEWC8Sh}n(Q6ur9lqs24As+D^^qnQF4`6 z#5RhsGWoNn-O|0sveO!`SS`!eH1qx$$2Be$4lbYM*xc%8NLD>%#uYxn#0>Xdz1v;+ zZ~1#JpZ3cHB#Od^okX?IVxZ7x9+q3&H;0?|Wo*9l#ZNOEWt$1}@-I;>&uCO1NFBg_ z)UCk9ct@W}tqtfIpk@x&hXl}bMIW5*Y7tK3}i685Vf z=7&wWu5QJCALdDHW1=jgOBgAMjTNkwG3a1yyHR{ltw9e=>P<3$`8XhEf5B^CG z?>Bt%_pGdr_DZEx`2ML8Z<6Fq{FWM*+%B=+Urbi9t~*(`?j(G^%r{ji2hgE{)q~?5 z#P@a^eDcE|HUW&mw1h}}MFkd8sM}HQ-mDWMmCc&}zC-ZRY#4zaS=VllEJB5tAB8_F z3x@^gGo*KXxkPWE6x{q1WGLl?H2HgYG`vqfF&Ww(DmFm09o47ii;7#iP42DNUs{q{ zD;qcHZA<^MXuO|reT^&O?ZOk0B!wo4g+U@qGdc11q;aEHlPId3a{`_kRsAc>U$I;wWud4>dLnVzpyaf07Jhxx-9*SC) zZrQAT(|4V33P)6<;FJQ(V+&IG`@`EuhjK9~-OttBthXG5E0@e_X?d!HxgbR19{pS$ ztG@eQ+vzi{M^;v*X|@*i(8wB?r8Vi6a47Vc->%SwzKv! zPRB^-=nHF8Do@+pMM|z~KK7mch|pkK=ZGew&(ei|*6ml|w_mjyx$Pu3G0$~RQlAxb z)Bf>`CR~`Mdf+0lA7khv&JMSDirD2SibRA66cVzNJ~`zzQ7t~UTiPy#x)@e}c;sH+ zYU{`Mw0Dw`XyV|AvVQSor!_zCV98gBid~$SlAOKCSXQ$0o@-D zM%J^r+{}lHTq2W|1Ch;LawK|V{iG1*-+rmxFs(uB5vtkJ@?cc$2WKmcDz>5BX30?=c}9jZPcX3bPd z*c~L?%KOfsz|c>@D9#GWwIK?BqKa&;JCGCF{bf|Ym+YoFUt)_(jPF24@30n=I9utF z&=hZlXX-Wm)^;+Xd%JM;uspkghH4F>!^&}MY!^KsPPZ1-{A};obdSYC0;}Gcy)tp3k_whBcNhEP~+skOg<&ZsD-3V zRIkC;r>@Xml~-6lYScEZY(1DIR>Jmi=u<>AUWy5x5IJ~?h)X{R9-j?4px#a>sKfXsKaJr!3A)^v1rT&}uOkfw*z~>W?eb)AdV&-aDG( z*{IsNWEZ=qpO%7^C2oJThLkE>juSzgh7gF#M3H*Hdf?cIEPO6_QJ0QD?kqKE+Q8_S z3ku;IMX`b9Nv=<{L|v?1?Ux4DQQ0Dr5-)ZN6$I z6Gx2uoD}4i3m(pYzfxZ};Sf3Hqzu{8Ki-Lku1cYlY2Ac8k0L}qUV+1i#iGs5G8xnu z!C6fm=O^vCIa9#%Q$M^TSf&}-$Ak>;EJ4+kd}|aT7wdC&Bd8y;b6%cdbnh&(7Qp8YJ%Xy3*v7ke9b?^hrXt_~j(}h+1 z(d1zg8opF5foifY!HdW@w%sn?3kye)kcCOL;3gc1_aq`UEt_}Q(>o03d-sUeC4)>C zx@E1pAC1!@^|LL>#XK?9H!|0;mB+XBhYqJ54E)^g*tlCtSG2)G`D11eCetYEt(b%l z+Pi=DNheh=SuR75cL+qiR}D;)^euxLxa#&B)*HFjKu6#=7?|pIhxTm?a2oW&sv0N~ z=3Wp-&%AM;tJ9s?ipqrlf84$GTa;VWKdcB!h%_ijNlHqq)Bu9gA>D{{cMP2(rP5u3 zAe}>lbc1vwokKI^z}nVYe-J89E$l9rh64WqPiE^t}xia4I4{bk9+ zcGz;~0cv;kYM@}vFCXisk~>Yu+YSBxW3nlBGL=h}i_>PxNE;}x$)Qa<`Tcx&+Tf+n z^J6_3s!heOw1X-Kzguy5!(1>JDbEGLOE?%$^~Q3VCCavz39*i&0?CLUXjjrt1HhB> zG~FtGf?zlb;m3DQl{@~czAY;U%A^DjG)h`pR#p7kneI1_?bK4`saJDe)CaZi|Ejyp zp>r1xSD#Tb8w>EKz2*7Syw<+;<8Jf4Z6}}!}EWAEDq`teyV1ZQB-&4JMo@&_w-$LnWNJtF;)4I6$-1G zzT{KA{Gji+Ld%(qSVLTMRejCuk8RJ2=N&u`3!aU&DEi~Z4jXR0qelvAu}JFd?^#Zq zm>t2PrjRUhKZ_1*!obSMxEBlA_SbO>2mjFCyLa_?bnepF*|B#qS>^E@mA1P=<*)EL z(qwJ8T;;;stH%}bJcWMaZ|Badi!Q@nH!p}p``h($@C1C>-9`7fAK_a$F3h8OK}25k z2`{+0;+u}O>;l=rFZX7mxy|G{!L#wXssZnbKki$je~(1lX( g_y5Cr42* zgPhH3?!5Vv%UH4rS?7L_dta^14*W9Iqn^*B zTiJ-~v5X0??yqOeb8G!cdvOUg`sxol$^CSHe>%yieSYmghm3H-wL)VpsJ*a;C$Hh4 z*!qG*7NQ^JsxG_X#cBC%33X!ZDWS8<>g&CgnD1Qsm9^SAWHiKt4w2vTo2cpg@@i#| z*g0DVqIA#FT@Ga0d?CiDo-Zc)E-#D5%ps}|{bI<0JV=j;lHD<$*@yLp@AlY>#Xcbxb>vAW%@?iKiX4-Cqp%lN99sGyGavFU7O;fsq7>yC8)`Ey$Kt8D@m)!G@E zgG&oc62~o6Mhm{6k{JHOPvFH__*Uusy_L@wXZm3dHpk?aTBP-^&6x9z$;m}$aSnQ= z{-vKzrVMq2I}T3Gc;@g~UR<8+@(@NZV3TZC9QEVtQ~s%~eF1E1;;9U8{d0>mpo**s zl2D{hP-T&itymc3niyYSbFRt$3) zyCjj^)+P%cR$Vx>^kpd9FwYt#mD}K1(f(|Hjh4M~-kcDg>#?Azfpc?8{TRxkS^c2} zNdpZNf0u{471HDdoG1X;hD|d%uVQHM*B7m%*6&|v*({{7FqrkZ*DyUO3WBNwfy&{~ z`!|d!4W8i`%T+IWy8K$Scn!WzY}gJ358Ij+FfeG8IY}pMxB-bzvMC4gyR>*zS6h>2 z&1a-jP*FXr`#M!?q4Pt8VY+YI7%NI}_VeHCXhYC*tV4n-aY2xyZA{X93zjnhef_7G z+hO&yMGiaKc-Fjm1tT$#kx9&)hPci0%XkQP(mgijy%(-q45a#tw9Nh{GHYD&YU$+* zn-bGe9ZZVxW2tpTR^xqRB2qo@EtggQJ3WgktkF|*?{FliM^xj(xkEYH2M=B{MHjk! z6f}EMw1Gc6uhTQ7X7_S#;m~xd60Bkjaex*N;1SdH{bW4-efvE88MqrH)#Jeba|?kD zG_X%^Vqc^cC`Oaib(@&#XLF!)=Fh`j-8CM0!pFkk)1)^O7Pgv%;!&sqEP!8j8V2Y@1S^dAx>%#>IrwV#fReg){^i`IlKli-R4ZG(Mv58u|u9upt$ zG+SM+1BT~Gf8|*2!ia<_|HW3s zw4HOOUbn9{pCeSqqhCiV>tW6QIR9Ga>wwnPz2}K@YSAloLPsqu4|c+waONHJa_3#a(UQa`V1RgW3SO5w>f@i23xt_ zP04wwVH=ePq6xg^Z!Kxw7jZu(t&?YKg-D&9mj>!AUK$d}@s>A@pkwn$8H02; zLGV(qviDt^L}O&kMz5?OslZ7yd1Zcucneo_U~bDyc+y_iu0XIwjhj$-`$AohwwUA5 zVt9?pWDjdxx#IM5CfW_H3AOq>(0(#A%7w2;ffRea1r(tko@5O4@dPemXuz0bVOVJ0shv>+AyD9N63_|B|INHZ>< z37c^_6k;m+d{Kl*&Dq!ga)GCH*CHjMWp|{zV+k!+wPKR5VPKzdmeLX(lX6FAq`WLa zCGTvid+bYZt%&s3_=I&TAt`PGl5s4EyS;k-NRz~y;m`zO4SK@e^__+R(P^;M5;S&> zKnA>nBJ`wS#TiC7yY*zpU9h^dnKkd_apru_T=jT6U+X*AHe2|tba=sWWy9;(#=7m% zKt3kFSEWO9o$g3{r#g4|c$j!$zrK^jR3-U7k+tMU7kZljd```qXMDfQV&Nlx|tTVl=|uLLt)7B1{n$K+4EP0&(?_15e>FiZCA1Jd~3pDdJ* zIh*U&wLm2f7_<%Ni8(9U;EAnB0y`Z_0)3xa<1TYafF4lHSvxj_uTOr2vie=Q9&U#1? zH-CtuWg&`Fy0?d46KY!}pi5Ul${sySbceycHRg@A19zEM-doxoQJt=r#)xvYP-Be+ zT~O^=MxZYwTV)NL%pR=Fuexj|MQ<9xh&+zm^?rP8CFF2$tpCN(UMPmPr&Q_BpWx(d zjI>NdR+&;aY$3$5<)!^0izo&4?1En%ILf+@xfV(F_;a9$}7Vv zS;+@(&)(@Ls-tzsr@vdN7>A2$*L1y}SDvkC)hNqw$Q2;jQHF65xomGFZb_o(mcIor z)99LMhT`yq=A2dSUzV5oX`>C5ke+u{?C+zF62BKQnOH9?+hQnWqlU>S(vO|s)*Sh8 z2SFzsT3wXQ3X2cjiu!BkoS>6Y+TH4>YrWC&6X@)5`_yq(ypA>Uq#P(CMW5MTBg#2J zLpTrNI(=CpjXwX}Q~~!_Kn6Rms+g2{667l#{eyf1t;i@I^J(ff2`Qa2TTfP7oBpmc z@!_MG?=)SJ7&ZF^Q7>tywnGy-b7cc-9i*K;lXkM=itB?%B(WpfEt%d5xFY96L%p`!XzaA)>vs%6Z3~)xWQ@~QM<_& z8Af}m^iiqO^btz**}(0gV#@*PciVjDBxVu1Pv^^>hX(OqQd)M!m=bMvPsrB=x;(St zvQ*=JnNqqKi5spj7z8;BPSC+vpFZFy-yAS!p!Ve^CF^Bgsr&TXkAji_Kgw#6MAvBj z&mQg;Qm7QD1Vf`7tz*cMiO!gaFHn*m%;HDbXBfH0AkSUesjN)RWLcQiYOuJ>vBIBo zgdY}fMX5pCyMn=HbAw}iHyFFxogj83bqyoW09^C*R07-IcuXLGKtHm@8T`;qYXj4ifjlQ@`nOZc%qEC`Y zD*RsL>pMT>euBJ$?0uImHO2*V8;S+yv49XQXO6|_xH-Pa0t5Dm#Df*Og`s5u4I1Y) z)rxD&*q}Flh4k{>3~7?y&My#^O!$jyU)OjaKqu!Fd4NCkPp*p#npAFf;z%%4-QJ~x z-rOe-vDw;o-zbsPNn~|(jV71_YrqVN(-O*T2(SBnuz1PvA1r|GqW@W)*D$Gjn7VXTa?2puP54=hq!k%!(ztx_r@d&yMy6X9E|3p#-w^v zRv?cb=_Yqz^ysLR{+H`2><&q%8R>B6*nlQ0S$oPXq73MvL4OuMSXkD`D0XU+&@79c z)BW3LFXVF?AR}Ym{k&=0+nbuNowJYb0l&Kr!+x(G-`(rvX{ks+oUej@{+n((><^;B zs*WlXr%Nz>g&WKlHx}~c?j`T;8eQxg330r0#U!H@zsn?W^JL1Lh5MJu>Qr59)Sh=p z%+P$j1O5Jhqg?W0R+&R*!?83iyLFnlylGYl&cSXX-Wii(*JvHM8Myv-t+5?@qGGI{ z!ue8w6ec<$#LquJLCWjXG8z=A~RaY6`gaNUdLeuaz5hPHf0am&@ttE>LZ_zYB+*zX_OAVV@SYg}&?nAV68eZ~w zjKnXUiMML`8|`8YIjxs}D=AZ@qE{5z`K7B`<6!pOS}5GbhXoC~g2`tN73<01fksJX zQAFVHsp%lSM85d3In5J@NDs}%Ng?qLWF#8L?du3dRU6bU(C9l zE1#K-mEt#0-?efjT^G~yWVvuvATRE%9~d1ZR)#T^5fwW4LF?T0%&e@|AkXW3SC(t6 z=87N|4AY@ys=T}VgBGRwg8hConJ}vZ7bsM3aeGE@v0z51;lnQ2GHE5x?oI!_m#jd) z8-rDYb=DR8`W1+eRQ+>l>95f2zBr$jzHxnn_=s!o17MAy){25Ugmo*h2ktya+A)6- zp9g?y7(YhJ`aaHG|BQDu1dk+Y;!%Ue2(otP{j-MT5-97020P={_rAkhK}Zs9&S|)q zh?KDhFORZ|E@%P+P`Zf%!%(zVGK~da82N%C@IG1dj!%)hLZE0GV*=#d)5YB89`8jS zl0CHj$%A8wcYCbiv3Tn=HL1U*ihTq)+!8d~)@W+Q>k`n%GjDA&R$G*sF~p)EH1_(E zEFHJv3~yj>|rik9}FHg{(DgZgOWJsrs#l~)h zZ%pmR?3haHmQ>Kn&!u`u$A_#uJ6Urtg7G+_i0m^*)bDA%o}5a7seR^&7B4L)cBh7N z((HU`nJ+KY5l(<#=p<)&xa5#dmEn9k5imb)6T)+Fptl!HEI20tvhb7c-bY|jq^=-4 zAKCQcZ~&3d?|j@?TBHKnNMa4sPyVW(#^c{SSpQZYRT=qI+ICbTs7$QkNerFU^a{OI z1%9xKkKGl}UUF>HfW@FP{_{ua4eF83Zrd8p&xB&lTa*Ju$o7~t5eHfq9}KE>2ZL!R zXb6D#Q@ohK&|edx#I)UZslEQiQbMHSwXeH6*M`cwj!C5@LSQBp>%EQkw^Oa>jb#phNU&k zpU#ifIncb%9u#~Rr*0@ZOI;{yVKPJ=aUMdog#HGR+B}HoIh@_8Ld77{H@L*`Mt!P0 z4R4ZtP=!B-Rj9Vn5!ZIe{>lFLBv)F`v%}s}*k}A)`GV)%ZzLkSzeRTIyol~HQf$5J z&4w0PPZU1kFL52=7z2>!wV2ibipM`(&1SwGB$(3`A->Wc;=eASl zle{w+iO~@4$Toi5`TDz^3%M+vn5}E1Mn$+{O^M7zFLC?biFbq8+4pV>{#aDgHU#C$ zs4wAqu!Ggk=2t7+@jp~`b$_kS@!pB3)w!>|-l`pI7~vE9bhcaDGB~OV2^ZT~73o74 zCfGRkAtFBuk++uW+p74-4+F)w3M59c*6HgKAZf=(Udp)5obRVv%Al*UQ`;ZPKSw4I z(&fsEuvh9%z2g$kySE9z`<&Z9cNis{@v@UWFdSQn#;^I3P{w!}0{__EDUv#hyimn! zn)tOzu+&1cS9%9mzH&q<13*I9DK)6>Grx7-Q4wU)u=Z|l3H`7_faa(>%0;|q`D28F z0HvH6lKynF89yiNnmP)KU0Ym4a?157kT)7`hfBIl(VSv@40-8(ps9(_tgC&KY2E;e z&OvL`#s>RmsI(^YZr>3%gK`xt=py0p!#nE|S?RM>ZSr>MV}=9nNwWhVYPH=Qm^rpF zK9Yw3VR9tPz}ZC}U%sukvH{C<);Z_SYF%(eW~-Kpn*m*2-*CP&W1^4^vkR)CFQ_WP zmdjlK1}NyeIIzCPa~7lAT!sJy5`XrJq&W6r-Yc?n7__q+ndMe{RiL4mx72NhIpWxY zZ$#w6oD}1b&sQ+Vt08t|ILDVs8WhrZX=UZK_98Xbt~_S0b2Om z*U-~ajC>oHlz8_kD(AT}Se{{Dy^5%20Kb_He|uy?QfezInGwu#)@5!gK=-_rJtbbL z`qoz5AbCkUP-^xhHNvx&nLux(C!syO%<8bqL1>Ib&Hu8{_54GVRY4D)cv3v$re`v2 z)I^)0BD03NnGU&)?$Zl{b}K$HjE1>zd0B#MN`?_&YH(E!+<)lGM)L+*%ErltUkg!%dTfyv32F!d2uCDjNJ zMr&`x-OIR-wcE=EPpsV5)j8AZ%CfTW)NJFoPMBxVW9PCsD$F6#s01h)OV>(&=_63* zjt}Dk()d}CPT#Vp>=y@@RGp5CC+6<^xl>>Dr~FEm#n1Www822{Bb-gdv8eWeUkFU6QETbr>=q-#<-t=qn*M^`6E1E;Ug5;C0Xc>7Qz? zfez$!+ZRzUl$*ua>&XW1-MiO(aeClOHr;-)o_|P=2^IcChf6hKn^RP5djGRZDD^h& zmoG1=J$@9w3K(e;%}eAbFcj6>i5~x8F)R;v6Dg7qDl$VwiaTJ72zh&ue(_o%v4XLZ zg=Xu!GI>x_!b(0xg~}7@bFN5L#*2_6|IAa5*5##yWG|pS6N|(zgBvO*M1g!>M^ahk zKez*p_o;r#lq~xZ>jby-x%nzUkBSPO*8=TRE{CSr_)Fh2jL33yzDH$+DB!tdKrC=0 zRNl(PZ79r-;%=lYeTnqkXx?%jvQL~ojB*lURHn9o4nfa6>}hqR(2+vlP`rS<8}5DY zNIGC(#W)Oqwb~<4q|Q&Tzb-=citO28c#Q6l;(G-6W|`4 ztuXHhsCCjyGb*@n(Hbw&lA*Qcb!nJuiS=9&v<*EF{Yo()hdj8Mx|LYclt=7x?z~4` z_a)t2tu1#ff!aa5Ch@b>Ds?9vG6PL2>*eI+WK)4wjYNRaKujRs1np#fBGh!^sZq)` z$XYKVt5hwFbMw!hS$7n7z_&&_9?{1JYd7lZLU~_aY)QK0DP1@IhuUbT+dzMG337&# z+AitglDy3P7Ch~^GU=Bq(C=#TB;}GJ)U5_2p&O#NkxeBV`z0|yOX7#9$i;Vm4Qfi# zVVs@l4))i={A~Xw7o%OuBFB?fEmEGD1bH9%kVecAyz5De(0e{5mM_aV=3Mt~;ALZI3 zIZ`Yt$)kPl4*Anv@9k2emdqJ(Hksol(w{=2p2~iC0kq+z_W~{Ayy+jae>Z3p!6EoI zS)6t(Op9)!q>`SohX4%J6lvL+#Cv;oT&3mW#B)N}R^gd~rHDVkKP+Z$}3v-z&0E`=ds=XW(|EEXO@E?3-6r zA7JTSD)9A@*!;Y{qjVZ>T=1*9(@FO2sgE020s9Twn}HF@=lAa3?P@a~%XfB#n4~lw zvZVY(#1M+!fO99HxW=ly337)cK%ZIEpOx{I5i+YUS&5I`fuAI+7uP7JKl!YpRJCfE zD@!n&IFRca^mevQKq0Nu=`xy&OU|M14bvOgBRxqJljE;pvZy_rNEtG}62EFJELF6{ z!K%K}*;e^*H+?P?2gr&O3qBq7_G;1c-!?Ic!*kpk=l8xM3*oO?C-Q4gCcg%3j7Qu{ za*#QU{sDypt~K5i&oVUi zHSS&7SnyEw$rAbbi>KZ1+v&Rqm1XQ(%K{tiao>n)Chdr>I(Mo?ohwi|)h*$oKw{lY z1e68^`~hyQT^3f>kdl%jAj-)+oqDbampTk&mozESZlYIfMD*(66-)MKJuHp$BKyin zV9sEcd(YWrTVe^it&NTUUC-LOvF*`f8ox{$y{2!+s_XJ(HfQe%%idWpmlR5#W`i-c zMQ&b&ae*Ss(?vWaju6lfaf>(~H+gQA7|A6f4aG>H9w6?0J>FB)B{b^f8aoj%IM8L= z66H185_J;_C2GE+)OVME{Q0<6T84*3xfcB%b5B)HZC#UuEp|4~ zZQdV?RXXzn8SzB;`0sIpMMXs?zF06MqW8x8dHKx%ZRxPOQ}MW2w=0G}G!Ae7{Lszy zk|`D_kBkQr$gSRzITHTPi17lv-$RX}q-pcz&Kmb~ZtxEo2wEM6E$hVRfn1Bo@dTyF ziz+RY&O2@b%UXEFX2YfKZJ_(ZX1yGpWe00oCT|~sGiv0JyiI7HZBM-T{v+F`B;BSS zfLf9Fc2S>y<~)P?W_VJfg8J(P0$)GTVTI&Xul1osOKyAOM*50b>W zsBXKn#lR!l3p_G^4i3K4SvU#=FjSU>*{O9FqN>)3`QSY1)+9=Dsuop0-Nm@lZi4zO zz&dw0K}K(`H4hQ=+_}w<8h+AjxdGzp6s2*bov3QE6xY;tIRqMREo;|i5bcKSFOYV> zn=rciNsuAg_KYvBO@BNM9qH)FGqfM&_A!H*C^{d9&7?y(7E#x_tJ2bb6gd^X%Rj#7 zZbH;L_nxi1wrX?`7Q%}!^$<{|#xevLB21+5kFEpfO~RmL`NiN?*K8Il^w8Vv=vBD4 z4u`bhor{v5E<&m7H5nQNf@=x8{B4@qK0ux3L-&~v!ty5a6^~x@Zga&na44@lN;nK} zs2*VDeAkf_9os4R<}`#Q@HZl<#b}C- zhC~H=_OI@ie&LFgCUT_VSwzL38;K-$_hKY^c>r4=auojJCZvKcQ}1qLv8+#cOns9y z6Dk3$hw|a~5B|lRCBTgh>Cj+8Uq!hSgp}$3VPV}lH(RB}vNe?9a5>aa%z^c7>ijrh zfk=4#_u9$9Wuk&s7$1ZCmeRLQ^as*`%`opL|K%u*e1G`&hLt@iQJ=#FY$S#129{ly z3GgraKhqHPXg3}?L>z=wg<{$po8PS>Gu$^k70!$vlVV~c-6!+nzW&Co<(CBE>@QOe z9}k_Z$wY!unY=qwf(@kGJ`%@=i4<8OBjMGM6QF15_j;PwWI{t`jPibNXz;vUQPW{S zplN_~*#RcgiG&LLc_AVwwe?xAgdOQ7s)V)esEli`v~S~)*BVfA2q^so$^k1cclXRPGH!CgoHL=)W&Pt&#)Q=t z^{C|I7W09dni6#2%#(1R0=R_yy^E!l0%7H5`1J;96q5yYajJnM)_FWqPIh(TkZ8d+ z36CQ}yp8E0tnni9++!igh=4#G@8KpHr%lEL_}y|{drI^BEt#zTwHM)nke}}K*M-mC z>ImckF1@Wk*8Z#;ZB5UqIVjC68&z4YzIKLjK1=yBwJYM=6oEF&PhIx@W;}xr74M*UJ zweQ4`Q`KB_owbtT;gv}S-HA}sc$~zK7+#E0ZsU@>sw$M#Ihx#z-MxJ$!vP>!hb=RKj99D>>hrIcKyYIui2i`y(XY8=Jtu)lXQ==!Fn2BRJ7)~as|+h$xtH# zL7bc?Qs%bS+Z55-Z_yCWD4TDCkc$vnm7zCwantB)h-D*{4N(WSVxy=0kJxpQkR>oG z^hxOFUSs`=3d&!$2;p~JpA6zVQQ>YFT$DqgUZlo0zS-sz>6^8ubhX%MUXXTj~J z5rvEvo($ZyqdbBUKXV4{NM^!tuRTjFA8=OCS(@=rr9F1`9q*G*NvL^vctAO9TW4D! zG$^Pj(?T?%^&IeOZtoTiz+Vt{^o#>Fviev_;J`U02^3zU)ukNCsr`H>=!n_GT2YVL zJdD`y8j)RE5?CfoumEH~;717dr*b17V)HJr=9oMd;)r{@=XwMZ+ zF9&*~F6DNi5PjWDKu!lRSEGm&q1r;39^um$Qa#!(ym$$+IiuxeTBdwmh#@%{fk_zh z@8^;HUKzX}NrJF?@QB2Y8U@uOL$T%}N{Mj7DoD)QrrP(~&4@PX1p3D#u075kn$%%3 zXML+JGc9eCVSWgId(Z@_h1olJ>A{nm=xhiP5}l26++2?Vj4zD_J;~bmQRV9M-fgWf z&=k8qXo9uub1OOdKAj<}`UgjS?eosydNsz@_2>Nyw)+UfA&vq3{!)t(U;>52`ijkB z9$KfT%43!u$O_j^1{-iWVz@UTPk^+&KuTz9-W7yTjJUR<5yGXTJ2bpaC^#_YBkIU^ zt@p(Kpgp*i>A}b2<$YyZ9__T5&Ix+KZ>nz@YkmscoSgxOdD?w9kk^O>Q%(fQ)hoGL zRo%lU0zyt+Es0UM_oKlTC@CN)%sf14&A;BD88aa*Z<~xH7}R3LK%Sqzz@JR6O|rFP zEYm3ay?{swgrt^D3wTEs8SX*x&Wo&qTGk#X!^3iY&0i_PW zd6XQF?`LH>_7n5B4R1xI&~e?6ZUvBjMBC^5XH?EdxA{TgemOyfQB(Zw1>K$BQic;EB~ybfmjnVUNdCq1!(p zuCI|L0i9XIrFXbW7&k9Ho(?)u+o%t3^Xra@ED>zg-XbAC%wLpzH@%BDvGAB~ zFtFm9y@cKh$GsZ`sfTrC6^kqFdC=!0H2z$OSC#@zZFja_CgT?Y(~CPW_5)k60!PIk(#M>{+I)~13U9@CTIN|oHUH_Qa` z4-ztk{w>?>VL-|d)n=B(S}MnL3BDcey7u~zIqMa$a>WKAOU%q|G=$Z5#FN&rtwbl` zTuTf)8)$z!J6YWNk2}Do7Xe|-9_=oS>;e&ooMNaC2<|t_^zr#O^NCkO{+n^eR+9)1 z-+`Ci#{bkRUpvQ{oSa|VeKdl+L0~adn~vt1w%;D$N(bzOMBV8y=X5zYGqO6(@$kN( zwGOq7?=3xV3RGcg%GqMcsh4>KqT*SP89COpo<0njQEgMlcWPc$Q2&@kP_c&E74yEE z{V5s6EuUMcxD>Z>pP(+(-yPG8JzqQDy*g&sQ8IK?a!_(`kX1V32`cDuJDu(BkyU!2 z?*U%{I$B(JAg3t$j&z2xXX;;DUA(2!$T)Aj%(|BQ;yZ+NVB*~5wdWzQ{X(^`2f_Nc zE=CHrQ-Y#4Rc8)XcH#h}CeST!`T=qt)tj!)UciHS6`*~h#V(ylmCcKhE8&7oRk)d2 zK6r%>cp2yzefa92>MUiQ(E$>5l>!V?Fbp36PJ<~1FpxriLH(URgF!bPdA(T(2XsEE z*il=3{piV77_!1lE{>IyyiT&9RD|dsJX!&wd6U14ef7A|p%%UzWu^|dgIrmz;Q-A> z*GPe`!Lu%`Rd~O9`>xsEhPS#LiHvON3?ArNEwk>sjE^+5U7Svc07JRTr;esnMS*)S zU9_HR<>z-DCCzTC=ASQL)69d0z3Vts(^~$!4>~9ueT}tSywcTGc(x-RE(sRc3gs#* zxS+YRM;@GD)B{??W3Op@Z>3}&?L0X*vV+GnI+WSwf4fpw-XL2C?uxP33<2^iJ&r3K z|By%NeG;=W#HJ;})#ePKP^pfSfc5;WB6Sh1n5mJXyvpQ1Z>9VQtx$_|jWXLwG*ge` z%~Sz?oC*foVAmYiEq49xIh;y|@}&WEd_sEfFv0j(#Gfy*I z%zhGGHR~1L!wiP{3n^ zVDR-Y@qj$bYV^OFm1C!#4nRyOh!NUHN+$=Px`)+th!VXjs`=oDgqRg0(EhzH~@@wh+C=c|ORmU-IPf^KFgm6q^Z#%Y~H!2|p z&IcO0SEP%P+`Js<`K*M3|B{;0=s0A>f^J~)f!5?xaUFzC%6sWT=$ix(I_QoBpK zMYj`=>_m|iQv9`HFll({I!*Z5BkaRI66mb`x{g%y{-3uDeDLy_?TW-S{poIZz-^lX z>>3bn`UVmhSL)v*3WV}uxFZ-1nAWY^JEp;Q0)OU|%8azfx{O?BG5-~z>8XJzsE**1 z-sMpQ!-*(C10z;6M8I7ZYMB}^@!nK>MDJ?*Y=Ef1dNxf& z!}ROl4AeF*e zQZywM;ycI9f(gt5!HZIXIq8clKewmg>#^%-K#fxxJ9JLIe`x!P)Y>qtl4T`_(xfdw zkC4eR2KI*I6}W>GK@1d|;+I9>6Zad!fGGGmN_>Q#TN7zBwP|$!nmG(f^)pY!oHH~ zj{&;I0P`uT0JLvx^t^ZGx53{+$^o(AXCv3QQg}DUU|}MjIYVj{3_ehiyWrsSjJ)xK z<-ojZDrT*=2@z_65Mef@95Yk4K$1wsou;|GyHkjn*&!W?OpmLS3#Kfxjo$D&7H4<= z>2I%h{i{!y1PoMerBN~Hbf{jX>gGVUm^z;7Mt{f0*RcL6iKiMjzvFxYF!BSg!_CWp zDRZ&PvASiGU4G2dt`s_{SrJscMKKVCbabg{b`h`vkDGL69e#Cfjv$~LuiJw^KfH|` z{d7P=u2_!eLTd%(=VOH2^t_cXr#0p!)4|u=$j28>;=+Tesz3*E4J4|4|z+&|4(9^hg%_ zKVSUOiQm5hwF74C*rV~o|KDN$_orUKJ#(*$TKp#KUq0S^O4SFX$-9#OOZeZ}{;yBo zE5HK@2kG4Z4-y900A7(EC|gtBaQ%P3{YIq7wY@I#2*3Y--;QAR+C#wGhq*9TV*maB z002Djz)Ed4!rA|4bl^LCU?XeQUQ3{f`uG1+3?u>%*l7=6d#JyV@KOx$==!thEC2%G zUr98U0Umh4YWnXg{=exUr2;gK%?gFc=l?+>CmrxWB2oDtWBWhv@eaeG_yvuH_+VVS zw!e@Vj|bRzU-0B#8335g{~y%Adr(4Cd``k%A_es@wNV&r77yb07k(DGB3Yn0t8flz z{p?f0isv}`07}4{FeTsNPDy|Ls|xckBJ?&z!bGVZ5zZD(;!-q`XGF(dWATo6FkgO&DCXQZI zCUj^050RT+P4x=IEWdSbR8?$I6pbQp+^uL0>|`_w-l)(5ApHHG9TSU7%qJm2`0l)Vj_LwQ8M)n5# zG^YD}lsppgAGC+asjvGnBag;|LIWw$tcQG;IU%*h^e6d`#c!9w&xD{X-%CgHs&xL# zHQi7&#Vq5F0MSQ&8?E9dI!C^7qmot?X~CJY!kEa);;C_7T*nivJBJfZ=`vq@R1JRW z%_KZH^Hw#AvWyw}zf(hynrP^)Q2xr;=1pYuiRoVP(gVeUUr(L*AaCI^B-sjel$ogZ zHC}?xMw%vD8=iLt)JHufB`goc(%Wb%9f6W#7XY!$|20ol^;CABu}zi-eznx6R`Rk{ z)$3u(Rr{j(^q^D-O8nV{N^YXK1xEs*$eh3bc(&L83D&nB|C!mg)$RW~6k>s(mwVuR zAoOX6=4$zkt;1lFrdoj`F>EwfF1w!v$xM_&rnzWsZ`bGH7A%v*Mu!{Swb_Gmt#|Y( z@y6q$Frv*;MBMOyXFkA>wCn}3?Q~!M=~JBdSU8hp8Ls+c%*IboK`}>uqD#>b&%2xj zn=C|lYomtYsUSx^4vb@@t9?kH&}X(y?4ZEGcKa_gUla9KcpKOT2a47uPJ_M zhU}^hN`Y&x5$`#k@%1xR^!2!ub^#46)l=sq+{|pm?%FON~n~2%bNwe<8DD~cdvUJe?F$e zkZ^vJ#}%4QB!M0_crF#TETZKv zZFhjdy(9RNEX;5++k{E7T3jJ_+(@B~5y?!JVg<6-7s0A7DbZ}EF0@w|c65G+``LgI ze3l}ldt}f2`zDqWlSBgUzL@6kQ00HhzL6M*-m_C3Rd*nJrXWA$9K5U9> zHLsL}MbnDNoTQjp-*>bS`6JLGEt>fmkCo%ea0tJrZWEd7o*#d?XOp23QQne})k&|U z;VUc0$$+g$%(GTW_AfjZC0n`acm87!fD+3Ppx(B+Z{Mu0LR|877nhxep!e*<3<-;> z6*>4^1{@q%vl(z#@v#_o0H!t&wgMsY3qFAtW^S5gWEq;-=sC&ERBhs;^}3+`qKhU#9o0fzn9m zmNx;>uFyf&s>P;i=j9Go5_#V-0hSBb7ar;wS2>Z?1am(X&!8c$$k*ouCsDSD&DC}M z_dou457DFw`K;sC6EnjX%BXjfj;xQfB)KO9FHVz)+eqp)nMVzQ$Rw94bzMF{!W{;N zB=EaG&7Q;Nn^I+1d-Xc(TXny}p^*8i#FE?`_=Jy>(*CdixBm zYW=VK7)1Pq)uBaUyq)g;``gu`1^WaqmmcM-uVN`)MdOd+DLvFUR|dIJtr( z9FUcTL3aC=#LN>KEaSiWzk2edUp=AqtK6%?+>}#b(Fxj2mHitN`f%3zWx7+1>HWm& z*?s|4k?Bw>?n1>Nz%X74gZkG*jY9lx@$l7{bdaPhKKsJc>D+u|$j!TOR)zYv;b7<| zDm*k-ExdX9s!Imw&XAC(Ce2zXKTRD_>|={uk;k~s!xkrBeR+8HVYc#QTw73cB77OK zRr=2w<0{+u&3L!B14&XQb zvjBL3c2FaQQ#X$@9%tij(^B2)3~*fyU6FBp(?~8wuDjEpr~Tz~wVp(jOkeHl$O+&Nq%jFLavK(Uo^;@JToKO5Ab3 zL~*;L#}FPsB42EQwC9fXqu`j>N0XopIxR-O^4GENp>Se9V^R-v>)>Hvljn<9emC;P zOB3sHLP_(tEWAZR*SPp3NYHwf=9|2o29lKc(ww+cLRa&;AfJtI$H^rC+D#p-Yd$DT zWHwEqAruqm0p#)lHFNXOI_t!0#YIarPc)ct@-G1ks(lH_GJ58j>sX<(w>)a-%hRr! zwMkB+4WjzGsmlZ3!iis?u-dem0pkh5dOL{wnjO~EjBKrCvoAcWB<4ZbRH54*&N-cq zXP?A!w!oPy5QlaWBEO>JEc$o5BWqWV(bLX@}`^&r-LR33LUb80&o`p(;-7(ui#QzoREuvIMO3y|djDz&HQv>V2T_ih@w$mBaYVE%m;_^KD z42NA^9@)W4Rb>6ZA6E5eV!dWFPRx9EYhAs&zCi6?pRb1(s{TjG0R4AWOpUB#MG@8$ z=Xio5#*~jnzoz*7yS0j5wvS3a7r%EshGekM*lA@1{)n5Br|J3N547``Ik(x%wXuSp z&`;3gmYw02M0oI23Iv?|{NY*sMq(&z{pwVKA2({) z52=GT*gpfPFJIS&z604zTa!-fL(!4;j-lDLR`7 ztKm3lHDg=gepx^St*679tT^(8U7c|8)$ByVGju8k&aId)3eZNo?;UDxJUZ%c@$vL1 z%iU2NI?i9uAb^2SFROU|YnQjYOT5~{#3}HvK0{#TEe<8^W*kW9`p4ucW%p79-w7V3 z+)L)i75iaYKM8zz+~sl7^x0l!wk`9>P^-eMPIk!p8FDtd+hV$%De;G^g|viP! zn)S!$Kesbr;a5`}l&Yhg=z?yS*`!AUu+KB?TaU1m9hm88ji8@n!lrTs24NQ#8Qdu= zdBk<+R@*L}ml3jzHud*v$XyQ}fTv$iU#46gJ#E;2G*pJCKHNUCYFTtdbqA&*K(_;M z^Z`}K)r>pqRJ4OH?0C*b`{B{~DX%svm1ALzZbZ`N>d)+X5e^bs>Xh5ufrxE*!0GM@j}xy>^Dj}UaeX{~bY;sP zT9SA~eYCh!-zeZVBa;9#!5~)SoK(rsYWS6*+u(e>y*p~MamT;rUfq?|d2OXp9{K)& zeMWdXbDY?;!0xo()aqOAY3EKu@JVY1Z0j-twv>$LxE|)TWr%Iu$bXCS7}#Q*V;U>TDM*1IX~rdW#wwv=W&!@vlX$^&~ka? zWbA8}YU9zu?-;unsgYm92WV4R1K!;Am#O^(BYqqW+@R$nx<6 z@4{_nkDm!EoA40XhExhQ@6wf-k;Gbc{0IG6-mw3#xGxW8yWbvus+3Yo7qr%T)V{Y= z?aEVHik8~9qLv`midaIm#Zzi2wJ)*P9$N$RpEN8OsjSE z6ZQfAlT)xOHScC=$Zoi!8f38{vIG|NeEl4(-=8$Q)?cI6JpX_+0#&>Gvyn_Nip1yL z(Z(0)A`Twna;1B}V0aW}^8Mt;JDg*&@FmY0PvyXy!LwLn)i{r48=6i|EuH-^x4yd2 z{g@?<(51uX#&q2S3+6yMa(j8)ZdUpu!UO0Hn))VH>m`s{iWc+q)-VSD9iu<4Da9oh zGmM6mRmQrJpuu>B(<}89slvD#SLl6C!F8}{{F6v>S77dKsk79jijZ`bo%=3P?#SR& z+}4e};}JuT-fnZN$EI;!Xcz7+c#AQi-VJ||zGlL=244cw+qv8!FSlUlhk1l$Axo^z zV}j7}`?wVRILpt*mhE-MA}Oii38baUGURZefO|_y!>Ee%ooH>ZbeA#mDUzP*Q?Slk zqD_m+2*$+{O|n!CB&wJKnT;gBt{FZrJGs`$qbPHAyk%$mPH^Dg(Gb~9uT+fbuw6D(>zy9%Ks4~{_D z)sFYuDm5O`AnC8FXwvsUgBJ{u_87D4GUL7S0ZlM#RC@CL*~6T96RL(z*kil$qQEC= z+0hXXNTQf$%pB;lolA_nk%}C*l;@1@{y5U&lHnr#y|-t>d~}O@)xej)2Gb?4=+0eR zI2u7Up3F7M*_$p6ENMe}4^diFYl<)RP&y%i8AwTGr9dVIX1O#BFILfYplauNKTXiHvh6aH|_H)&r42zFgjM&l@wP;kgt~dIj z>}|Icoqmo4op9w=8i=(G*_>-(F0RLXoci5%3DajUrf$v(DYOoOR9rw-On~SP$5VIV zXyZF}6+NS1HDQth(Jz`F4=fQpK#!85XpF z^Dn3DKOHr782!idQxlAVE(KD+afsLL;QJq>Mty~e3`(SSh76bpL-Cq@^&bnh%> z>rYP!Hfr815aBptTc2e&82efm3NTf4)byYF(=#8tmD zXa0D-6UXBdct0l~tSw9x7v$c3vZD#Z1qW-j*IEVywwnm+9>KT(C&6|94eT%2mzl!4 z2dro`0e@b5lbaB!!_h_(BI4l+r=xNjQv|S4WB1gR0bg+UC!NFjjrD4FTWD3-`tGGb zv-b0x(DB_Vhk)D$#EXW1=Rg009$^XFyfMA#6#2cwQw_-lsYi#e4bTIgwxsX5Pd2M9 z`)Yt|7l2M4Q`(nbQ!-*=B02YWC?}KOzjZUK1++2TRlY#taD*}p?`$B9rS`_si)3_ko#qMglpfPwFxRRpg})rvkC1kd8ptxst8 z&Nwq@vvF}ZtI=;q1NsTcAyEu%;Kqp7u}C$h@gJ1_7r!jChDpDcpL(ysCt=}s>~T9v-n?w$ z6BT364y_=*k(_8Z0;9inBFZv4`@$06{^5n1yO5Nk4Y1^?RfVV{C2yu491_L;>9et} za`w8={fh1{ajjoV*fmr_S9WgH>^<9yyu61E9IveF-{(eX@-E&f{dlGm%ue%#tC{0U zv9!E-0GF_Azh-oPkFG&%**wK7* zK#3|aHuzD(sF$Vpor_?ysjy9sg(x$Q!JEllYFOqp4YO4>8e$RzSsiAw9|>0 zRG|{Ok|)YI9hFfHBFG!Z!E7(?>ZO%HH318K&+szTC@9(k7O+ zbhj%4xQ=3C0jIg*ld+NiQI_&QfKWn4l#u#{7TfAW;`Ja*ly&Qj*0GeXMuuLDG48C%B98)IRqE zBwrolA{M_J@GNUHKmGd^T=C6_wpp{oa9XiK`|#hz;%>RR;sebq(%~=f>cw6ADH^3$ z1Q2%bx@qdy9CBq~~5T8)5SH=e$>_8Kg;k#A^DYE zz^Vn)-$M>|m6N+>T#IGa5|7xw7f-z~p^Xc2ptTVh)paeq@8k6}pplA`?q!_%aj_|K z&P%)^zC0n`#19Ttr3biVTxb9U1RT-8%$WRp@Vjftb z{(ngJ9CjKV2L}hf)ZPnqWWXv1)g;TvQAMQRmATcbFIE-s%f$9do8U(^(*=gbDc6>4 z9ByWcy`T-VVR`rlv+4C>Xtb*2<|uDeYFDYaNSqyTOf0hHkqUEQ%e~`bl;>N}BXpf| z1-}}4FDcs&?RZw6by+WLXk_GB!=3O7zEZv0Sf5v%8aA-Y?PE`*CNJXn9&~e=`V^kp z2QbRRuB@W(J(i)Gl$z;Rm$8u8SWD%3{X|G4M#24(H%&Z)kLF~sxl7vqQ+JrNKN$Ql zZa#1A$+Y^nzcLc z&d$M#QVBS!V;{>$G(&i{J3}>i#={pzH3gXiG$HV4fJbqB!J}NYIA4eQXLrUJfue1m zO+EBsm27`QNrCd0R|{C@rPSv(o{Z?@s-gEnJ>2vCCPq!%*?Yb;1#chQG^U=J_sza6 zyrO^YyfH&S;w_PjfjzmE8UknoPSH*D6=LFj6rgIM?E0pOXn4f~sm8$QSi@K9&I|?6 zgH`r4g;cCKrZ>FKCY`~rJ;YG1ZZE}N*h-`yqnq7P@cvhA*?+6Cu&HZw=U^Use1m!M zrnL5UWBV!bf`Bf0l_b3GaLK^b)xzs0D-9aBCn`mVwEF6Ydv!0E1ZbN795_$a*ze~g zRC|MPJECd)V%M?2==TkFEqoE9{bWJynC_McgLc4~49gdmK!ttD;-O$hPh7&r&*d(F z6`iDiU}wT*cc{(l?Kw%YnFQ|R9hdmYK1bYbGASK=<6LH8L8`i-2V|KGirGM%6deFmvT^f;C4tQJ;kMXZHy6aL$7#mAXx^ThW$*HsGXAz|$fJy0nOb@V|#xDPg#bOU- zI<3S-@u=s~ad8d@wRxwSxas(r2`|BfUy`3aRdAQs#o6YqW>TcO+$%xaL&R{f+4j=h@ zL6yv;a*z`l+FXctCD5Luou)Yja-do4&S`$!NE;OgFC~+ zv$5^$)rCZxOF_n5xI*JnShL~mOZ3{)DD@Nu*8FAA z_J2N}jdwG-_W=~p>7%j!KSt8OKdFeYpk7E&-^acZ){BtcAmp6xc+u!=dF}J2Exjq$ z$t-Bf4MAzpR2jkzO~zJtz&hyC@NeOz>wgYxQEeTH*e(yzn$I0+q73xOwZ>&CYHGYc ze{yqiUE=fH7K<-{y6&w(!}8D4SS>fJmUTy88a?_rzH|=%s<$_=!BVKexT=5`j;;0{ z00DVwJ{X45Ir`-!&4^@9+g?zX$li@7!t;mskKUz8?+GiwG;3eBsEhT7^Awq%4#DrA z4z-trmuwEeM+`7)-sjKS^l1*)W+zpJgUbj;?fDLmaJT@QV2}(AQ|{V~I<#f0{3%ZQ z_VY-C-U#VY+L_Lc*HIGb7GmG_Jb;s%udH8o{tcX#cIjWwr~+)H#v?>@MEz^kXB&rw zrxN03B(C}IaQooT+O>zJm}9f^L{{R>>jL-GYg(An*X*Uu3;FJ_2?aK)=@cftq)&h+ zEsGbb)3;~GzGh~nW-{czfsM&Isp0N;+zH7E=5AtRqi(XkNs2daOab4kEPIwq_dCO? zKWC)hl@IEtPwiGyl_zxIw1Y(>e|f}$Ty)&YVlTu@u^uxE>BFW%6H8>V$D@bIangFT*Wp?0=VXGyQtrl5@oNdCVueRq038ra&-dG()M=D1Ui14Ljj%V(Vg$f z35?&bB97H%A%J6dFZ z2D#Eoo_gUG6&GwyAa1k4l=vHNc56%EykoDaqJqMT(Su#=^0EtKoW$Lix^EP@ZRa32h;Ah@p9sA)p z;kQ3`Rb&)Ao!x~GUox`&Bvqh66iN20*BW9Hl)Z^jW z5K}@{QZx?AScq-3ymdm^;4gg&OI$&xq-kdomDTgEZ*PABLt1wd~Bq&9IOcIQa7hQ3@h<*scx8AXbjkIDA>PpdxLiqE%U})TE)^@!AST-dS#&SSuGu(T! z9CtE+I_&ktX8BJ6*sZ+6AhQfm1c`v0Mv?KJi1&J$XM#j2@5rL6V0^Im7SVsYq_CDS zeCrv~?9}6KMwaDf2{&8%2}(A+hXSDO#sa;c|Hc%z)@r4#nv-Y9P6mERS8DHRi;_wM zxyahLSB`I@g*dfAi9}Aj+aAwB54NK5^Sr0v)P(yO6*)Q9BL9J9oAA%r6|T}rcE__0 z6XmzhuJm-}4&yWYN%H*)SL7Ra9Y#h=3OX2a0WD#?gOUJ0e9h($cD{t7SO3#4qpGZ?)u} zrEMv^Vut!$O4CgLSeurF=WW?3_d=gyY+LNxS5DNxq_lmkXEU3Vm5cM&vdINB}8Ks&xU-$O*hCe3`Lr>}; zE4sGy_b0?)&Gs30fi)`tsMeP^3T%{}2AmCjm8XMuDo)H-iI?YzZ>2Vdmp+^+iNc&{ zOeAKwH&>W#6qFs~P(IzNTa~r$!((mIj_umhO_M0%`b8yWRouP;SPn|qI3a9|!%mN2 zSjx6ep_{a!&nX>47|y|Ru8q3Z5eSn=&Ehih^*WJd$kEED_F~&4sB*yVk#}7g;YF%c zG7~L}$^H@j+56L5vHpjd1O8XHx3_-tJt$n}@+ilXd=w)W+2=a4y0Ea27phg+R?n{* zO7K&Ke<5fZF+#z8ksBVCwl%GxJ0K*1QUdhX1~E82LM>=BC&r*Z!}&9#1f?X6$w>Ke z-;bbW3*WYP`}FbzAeuW((<-{q^;;g z(8i=H&9@f^0vauD!&02PH&jE84-)+3T4AW0Px__LI-`_$L-{z})QbxdG-3f!L6p!b zeoN)*-HmWkT<^idDODu}_{=%ath#!d&~Q5g<*mO`LHBpEt`O>9Jxp|D5S~DP+jwCS zaqe`e_0|vLE{>M6r_G27pEAgjl7G@CI`jQUD`&~-=X!MII-kq%aa{ZO{fK6I&|dyv^U>2~-0>B{P1#|!GR(J!jrCC=XVwAhMw2s_cX~X%CiD?(%Bc(Fy+QL?6 z0b=sScj-;0HzVYa)IRXmckzanb5+U>K{aL(s6AkPzz!R7rw@lGZ=A-f94$|SpAc8` zLY$nP@ug*z7mYL~{HOho!B+&=j?)F_Dm+`T6eS6wh_lKYEb=~jBP*)sAQ!R&etzFf z`yO#TK6;JbK#lw&x;1!Nm7((b8R{Jb}AXe%Ud&RDDW9Q!e|>Z z;}^8k=&;X_0<57_L|{?Koov~36Qes5AY2gS)<%xXDdiFjX64!S-ZC#ewbFbq6MhKm zSAcEwg%wJ>CS0~k(E7Iz{Cpo(NbA1qSm#73TO&@1Qni`(c=%LvKrL`O#EH&Zw=nlf z(dEqcc76~=nRUR|u4~o6 zjl1>a2r(v*(##jEFsjK+{%jMlxabx9;>FkVi$rW+7P6U~xIfRU#`W3;u1Dx!@8q0j zt6cjWM&57dRdt!47t&0fhz%-Y{#~~JVtX@ADpeAGRoq`Sb_)W9ZI-52; zY5KHnzy`Mj4gKKBjE$B;Jx5F(Ne0bxN-^-iMVocOT2CSd_MO#&M(RB#T{nWJX^$VC zpxWPo&vNU2NxfA%aj_Xa=i9}@5TA!>l|^>oG0h3rowd^SeJD5l^dzypsLC|jM$Ug@ z(CAM6>9+>F%FAv_VNlH@UOdj_TB*p@yY6EyOIiLXgWAo~)8?OT>sUM0No^j==(uV$ z#YRnq65k2&AT%SHu#}U;s07~h<9(`hxkzuU4iIgCke+XIzs>!oQtvdAGP(g`L(G_E zsEy@Ta&mB3BRh*fZp(SvmJTB#r&};f$K(=g5O&dy+S5JgaM3hfi_rJu$2bZSq{4!d zevHpq;W#5F^bf`i)1tA+$ZNYgs-S0@)99?yg5EdOz2xDB9!{y~c#!{+bpaLP{)JK? z5WeT^v3a#mgT%?_xVmnP>+NfZ!E=tnbICX zedh^S=(0Pp42N0PyTg$isGdG$-$*jPl^hK^*yK|R-2FQeew0wxK`c7-m0Km&3R1dH8-oSPz7es zIr|D6eLAz)b69A=@N=1!->Bx~3YLbGdmV8#(U-@nenarubzVhPz|UNQ#3_!np671^ zBx?#N9W0dXx2PSL8bGS1BeWxWasd^0#By4WR^3$8$zgFtEke(bTb&u}6yXMs zH6On-+k>$QIV_aU+mGN3k$ejaC1Y&28o~YtvhZAfcN)y(Kbkf;c~6GuQ?;48(&9lSp2<3+VQ zkc;DK&e=C!V+;Y(!Iary$RHvE==i{!)H{8g+A`0*QD^i?KU~_>NVd3wZ7)B^1mgOF z;CZ^Qwi^I})n65gB@Kp4Um-3JI_wktPhXQeJ%hz5s7sj}<&@Q15L!=BUe>&%vC~!l zh){)(y+2qsFVIn{#m`cwId);Fy)}8s>^C=oD8R5Fv#^lnH}mzUF*-cVw*FIrN~$u> z+GL?SJsQ=4?Id~wxj^FAk#h2+6y!^N%a(fvG_41IS~h*;pmea#!?{0zn96JP*>iMG zOuX9YN)Jv9@LSRtE1NOqcW0$%W@HTTLJrEpU;lhHz+NMgiH_5lnw|adq-a0g*Z<{9 z@wZ6DlvuZlpaF}nSY9=@K4Z}&jp;!n68+!kxG#2l{jWb8Qhj$0ls^7b16oUo_^#b4 z?dSSmOp`j<2XBP0Nr?DE2%ihAQNBNl$P9y>kg18q$mZ|QE-@iM7V^TX@ zdv|FEE%^Z$?yu{++1D4lbTkn5?%e{zNED9VoV9^R8C*4?we(EQqOPLK%nfakgyLGKP$Z=I$3fFF=PMk zY(UwRNxywCS4yBHC;Lcay7k;%iS-@)8oUf+ux|!JjvhK>HB_2N1wHPn)opRW24aEm zclbHQpyttipYaaW=p`{iSD=M+oFgK-s|Fa=6@`!Tn@6p7GtHn8&`O2f#HxncGCMb*S#pm9soN@G#l2yy9UToNuHGC z>8UqgHLLcRFg@Mk`d<*h6@kmgD$V36VCMTda8}gf(*e+mjLBGtQ~!s_zR_L}3}x!b zS3h_l1wvorGD~F}pe?yWb)JH?J(hwa>KBgxPc-}gxFvG>@#L63&>qWN`UpuOu< z?BO*=ocyKn8*8+{u_cdX;`#I0e=y%YG}=CLXg_~k|WM9>!|QmXTSVy=h~0}>E%|s zv_0G8<@7n$6#u!sqcD_JcsKfI)VzKZQ<<3w;L44Jos|Z*EM=VJwV$>%#ywdD#%x2; zQq!760Kye}AuPzIh?v(f0$fVcOuR6@GM;CWAHeyQgLmY~*WKl%@GDl+icQ=#FxD z#>6Qf`Gg5|P5iI5txT&E>$DCs4?we5+6SBPL;EqQAE)I#je7o?WbIF>;EY`qy~UpM zr-YwGqUb+Ck;qv7vw1$^@oiHhRE4Og#$oCzNgw+c(njqh)TRhIQ%r6WY>Z7D6&*4} zSQ`ou)7L~n38Qq$HltDRnp_I3v2AN92!`aXn$;;wf>r{jOR=?~+`pa@L|Hd{^{Vqg z)ZAn($aV?p~9lpx;)c-sVOR}pv$!5Yd`Bnj@yIqj%a<1 z9c#~!TO7L1gS2#OzohSuF5yaDqWPQ$KQz&+4e-VXdbwo4xp7R)iL8P2nb+ZG1(diA zxgrbJCfq8^z}t15rNO9Ut@cyIp+c=HHu`-E+~lzj6t;ZT1C^I>=c#uv|FEA~M~zPH z1g}bCmOJt>xgl*$M=4DpSUs_waBnZH(vh`!-#I3ij?1}$mliw^z4zX^?uP5i~ z|5;9+Bs>LN)8Q*HZm?t&l`C%?%J6ZwAI+Zf?=BJywz1@G!!1F2kJw?1A1{nq!OytST^{eIxB|WXBhk=;6>PNc=4gwF+;>p*Nch+J z$stLb4cBrR^YRG^!3vwDIVGE>0<^E6F0znj-1K~6NAjfo(5jy#YQ9j{Ld6tOXK9fG zk&`xe$Npa)PZ9&{ahM_}yDy3p0^l1J=p6~v_CJ0^7EX45mmma$>#bgBKKdd<^H;iV z{osT9p6>~M_zLk=joFXmZiMlBug!8jZojThvH`qNrxa|A)OtJ|cgIMKV3tB(z8uld zQe5QQSWi&7wRe~R7sxIC{g&*nBzo^VcUGnqhW2Zfu8MEhQzFqwTV9tn-LgTCA>Vqr zFb@@AEZj8b%5pYA8UeNqWZGj$S%^NL!sH)~$DS1erc@6!+13z0S*Y<{l$3=g`4U*p$KTbp`xJ0M$LIOXVUnLJ z=`yk#tRyqWy8BtZm616P+@QpRlCIF+JUhjHmu@68j}M2?V(gRx8_sZk@)(e15~q8a zqJCu+Sons!=ZcVe{3C}{LUxNXlW$zJ5-!&|Y=2bfh+0h%JR1Bcd^C6m zw7u|svst3n?Vnvf{tNHj9QF2dFaiVw8r9Fd_ms!D_z&0T&vR(a8wv@RUGB~RfA(!( zB)C#HHz|fU1&+!Z+O$5jJJT=BNme&H=ed3>!oV9UM>Q$(MCddA6{kJ@M<(#q2I@16 z@^%^vda$3tTLbQsKA!+N>YCij{@NL2^;?lbxA>=Lri81hBxswtgS4%#Q_0cTe_YG; zaIAF#GW{1$|NJ_zLTQPRb;9Hg0kRYqG*TmhGX)I4gYn1zT>Ce_5eDZWbduuSpvig4 zBH>@7N$4pW^xzfJ!~NtCpea(T@~Np&x#sXis zwQ?%h!a-o@mYc+ zq6Fb?KjW_9{PG;PIQ(d1teoMXLnI7k>W=x=I41|-p5Ad9@3>nHT}O3C=~5nP{;*^0 zX1b0X52?21Uy8yM_%%cS{Y0rm$4N8^K3?4X;iMLiMkFuRyDf0|WzQX^15#Q#wZ>Wd zS^J@QZO4v63#5IPE2#q%W0ikou8&-Ak@Z2%HO?K@l4X57djO^tr}pMsikyuIS4>?3 zJ_=*j9BD!7al;@&$er`>rXsE|0&DRxU!93I-Zgvu*WJ|2%=Ib62eGpxL9y7T+8=@L XjlTB7 diff --git a/de/index.html b/de/index.html index 34e6ee6..56a4a42 100644 --- a/de/index.html +++ b/de/index.html @@ -30,18 +30,18 @@ - + - + - + @@ -116,7 +116,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -264,7 +264,7 @@ - + - - + + - + - + - + - - + + "),typeof C!="string"&&!ut(C)&&(C=xs(C),typeof C!="string"))throw $e("dirty is not a string, aborting");if(!e.isSupported)return C;rr||hr(l),e.removed=[];let $=sr&&typeof C!="string"&&ut(C);if($){let we=E?E(C):C.nodeName;if(typeof we=="string"){let Ee=re(we);if(!X[Ee]||ct[Ee])throw $e("root node is forbidden and cannot be sanitized in-place")}if(xt(C))throw $e("root node is clobbered and cannot be sanitized in-place");try{pr(C)}catch(Ee){throw hi(C),Ee}}else if(ut(C))y=fi(""),v=y.ownerDocument.importNode(C,!0),v.nodeType===ke.element&&v.nodeName==="BODY"||v.nodeName==="HTML"?y=v:y.appendChild(v),pr(v);else{if(!Xe&&!Le&&!Be&&C.indexOf("<")===-1)return _&&Tt?R(C):C;if(y=fi(C),!y)return Xe?null:Tt?A:""}y&&ir&&De(y.firstChild);let ae=pi($?C:y);try{for(;L=ae.nextNode();)yi(L),Si(L),et(L.content)&&It(L.content)}catch(we){throw $&&hi(C),we}if($)return ht(e.removed,we=>{we.element&&ts(we.element)}),Le&&fr(C),C;if(Xe){if(Le&&fr(y),vt)for(V=ge.call(y.ownerDocument);y.firstChild;)V.appendChild(y.firstChild);else V=y;return(ie.shadowroot||ie.shadowrootmode)&&(V=U.call(r,V,!0)),V}let ne=Be?y.outerHTML:y.innerHTML;return Be&&X["!doctype"]&&y.ownerDocument&&y.ownerDocument.doctype&&y.ownerDocument.doctype.name&&oe(Us,y.ownerDocument.doctype.name)&&(ne=" -`+ne),Le&&(ne=At(ne)),_&&Tt?R(ne):ne},e.setConfig=function(){let C=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};hr(C),rr=!0},e.clearConfig=function(){Ze=null,rr=!1,_=x,A=""},e.isValidAttribute=function(C,l,y){Ze||hr({});let v=re(C),L=re(l);return gi(v,L,y)},e.addHook=function(C,l){typeof l=="function"&&tt(I[C],l)},e.removeHook=function(C,l){if(l!==void 0){let y=ws(I[C],l);return y===-1?void 0:Es(I[C],y,1)[0]}return Ti(I[C])},e.removeHooks=function(C){I[C]=[]},e.removeAllHooks=function(){I=Fi()},e}var Ui=Oi();var Mt=class s{static _keyMetadata=new WeakMap;static _messageSanitizer=null;static sortObjectKeys(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(s.sortObjectKeys);let t={};return Object.keys(e).sort().forEach(r=>{t[r]=s.sortObjectKeys(e[r])}),t}static assertCryptoKey(e,t=null,r=[]){if(!(e instanceof CryptoKey))throw new Error("Expected CryptoKey");if(t&&e.algorithm?.name!==t)throw new Error(`Expected algorithm ${t}, got ${e.algorithm?.name}`);for(let i of r)if(!e.usages||!e.usages.includes(i))throw new Error(`Missing required key usage: ${i}`)}static arrayBufferToBase64(e){let t="",r=new Uint8Array(e),i=r.byteLength;for(let n=0;n=4294967296-4294967296%t);i+=e[a%t]}return i}static async calculateSecurityLevel(e){let t=0,r=100,i={};try{if(!e||!e.securityFeatures)return console.warn("Security manager not fully initialized, using fallback calculation"),{level:"INITIALIZING",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:"Security system initializing...",isRealData:!1};let n="full",a=!1;try{let h=await s.verifyEncryption(e);h.passed?(t+=20,i.verifyEncryption={passed:!0,details:h.details,points:20}):i.verifyEncryption={passed:!1,details:h.details,points:0}}catch(h){i.verifyEncryption={passed:!1,details:`Encryption check failed: ${h.message}`,points:0}}try{let h=await s.verifyECDHKeyExchange(e);h.passed?(t+=15,i.verifyECDHKeyExchange={passed:!0,details:h.details,points:15}):i.verifyECDHKeyExchange={passed:!1,details:h.details,points:0}}catch(h){i.verifyECDHKeyExchange={passed:!1,details:`Key exchange check failed: ${h.message}`,points:0}}try{let h=await s.verifyMessageIntegrity(e);h.passed?(t+=10,i.verifyMessageIntegrity={passed:!0,details:h.details,points:10}):i.verifyMessageIntegrity={passed:!1,details:h.details,points:0}}catch(h){i.verifyMessageIntegrity={passed:!1,details:`Message integrity check failed: ${h.message}`,points:0}}try{let h=await s.verifyECDSASignatures(e);h.passed?(t+=15,i.verifyECDSASignatures={passed:!0,details:h.details,points:15}):i.verifyECDSASignatures={passed:!1,details:h.details,points:0}}catch(h){i.verifyECDSASignatures={passed:!1,details:`Digital signatures check failed: ${h.message}`,points:0}}try{let h=await s.verifyRateLimiting(e);h.passed?(t+=5,i.verifyRateLimiting={passed:!0,details:h.details,points:5}):i.verifyRateLimiting={passed:!1,details:h.details,points:0}}catch(h){i.verifyRateLimiting={passed:!1,details:`Rate limiting check failed: ${h.message}`,points:0}}try{let h=await s.verifyMetadataProtection(e);h.passed?(t+=10,i.verifyMetadataProtection={passed:!0,details:h.details,points:10}):i.verifyMetadataProtection={passed:!1,details:h.details,points:0}}catch(h){i.verifyMetadataProtection={passed:!1,details:`Metadata protection check failed: ${h.message}`,points:0}}try{let h=await s.verifyPerfectForwardSecrecy(e);h.passed?(t+=10,i.verifyPerfectForwardSecrecy={passed:!0,details:h.details,points:10}):i.verifyPerfectForwardSecrecy={passed:!1,details:h.details,points:0}}catch(h){i.verifyPerfectForwardSecrecy={passed:!1,details:`PFS check failed: ${h.message}`,points:0}}await s.verifyNestedEncryption(e)?(t+=5,i.nestedEncryption={passed:!0,details:"Nested encryption active",points:5}):i.nestedEncryption={passed:!1,details:"Nested encryption failed",points:0},await s.verifyPacketPadding(e)?(t+=5,i.packetPadding={passed:!0,details:"Packet padding active",points:5}):i.packetPadding={passed:!1,details:"Packet padding failed",points:0},await s.verifyAdvancedFeatures(e)?(t+=10,i.advancedFeatures={passed:!0,details:"Advanced features active",points:10}):i.advancedFeatures={passed:!1,details:"Advanced features failed",points:0};let o=Math.round(t/r*100),c=10,d=Object.values(i).filter(h=>h.passed).length;return{level:o>=85?"HIGH":o>=65?"MEDIUM":o>=35?"LOW":"CRITICAL",score:o,color:o>=85?"green":o>=65?"orange":o>=35?"yellow":"red",verificationResults:i,timestamp:Date.now(),details:`Real verification: ${t}/${r} security checks passed (${d}/${c} available)`,isRealData:!0,passedChecks:d,totalChecks:c,sessionType:n,maxPossibleScore:100}}catch(n){return console.error("Security level calculation failed:",n.message),{level:"UNKNOWN",score:0,color:"red",verificationResults:{},timestamp:Date.now(),details:`Verification failed: ${n.message}`,isRealData:!1}}}static async verifyEncryption(e){try{if(!e.encryptionKey)return{passed:!1,details:"No encryption key available"};let t=["Test encryption verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"A".repeat(1e3)];for(let r of t){let n=new TextEncoder().encode(r),a=crypto.getRandomValues(new Uint8Array(12)),o=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e.encryptionKey,n),c=await crypto.subtle.decrypt({name:"AES-GCM",iv:a},e.encryptionKey,o);if(new TextDecoder().decode(c)!==r)return{passed:!1,details:`Decryption mismatch for: ${r.substring(0,20)}...`}}return{passed:!0,details:"AES-GCM encryption/decryption working correctly"}}catch(t){return console.error("Encryption verification failed:",t.message),{passed:!1,details:`Encryption test failed: ${t.message}`}}}static async verifyECDHKeyExchange(e){try{if(!e.ecdhKeyPair||!e.ecdhKeyPair.privateKey||!e.ecdhKeyPair.publicKey)return{passed:!1,details:"No ECDH key pair available"};let t=e.ecdhKeyPair.privateKey.algorithm.name,r=e.ecdhKeyPair.privateKey.algorithm.namedCurve;if(t!=="ECDH")return{passed:!1,details:`Invalid key type: ${t}, expected ECDH`};if(r!=="P-384"&&r!=="P-256")return{passed:!1,details:`Unsupported curve: ${r}, expected P-384 or P-256`};try{if(!await crypto.subtle.deriveKey({name:"ECDH",public:e.ecdhKeyPair.publicKey},e.ecdhKeyPair.privateKey,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]))return{passed:!1,details:"Key derivation failed"}}catch(i){return{passed:!1,details:`Key derivation test failed: ${i.message}`}}return{passed:!0,details:`ECDH key exchange working with ${r} curve`}}catch(t){return console.error("ECDH verification failed:",t.message),{passed:!1,details:`ECDH test failed: ${t.message}`}}}static async verifyECDSASignatures(e){try{if(!e.ecdsaKeyPair||!e.ecdsaKeyPair.privateKey||!e.ecdsaKeyPair.publicKey)return{passed:!1,details:"No ECDSA key pair available"};let t=["Test ECDSA signature verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"B".repeat(2e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.privateKey,n);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.publicKey,a,n))return{passed:!1,details:`Signature verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"ECDSA digital signatures working correctly"}}catch(t){return console.error("ECDSA verification failed:",t.message),{passed:!1,details:`ECDSA test failed: ${t.message}`}}}static async verifyMessageIntegrity(e){try{if(!e.macKey||!(e.macKey instanceof CryptoKey))return{passed:!1,details:"MAC key not available or invalid"};let t=["Test message integrity verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0446\u0435\u043B\u043E\u0441\u0442\u043D\u043E\u0441\u0442\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"C".repeat(3e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"HMAC",hash:"SHA-256"},e.macKey,n);if(!await crypto.subtle.verify({name:"HMAC",hash:"SHA-256"},e.macKey,a,n))return{passed:!1,details:`HMAC verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"Message integrity (HMAC) working correctly"}}catch(t){return console.error("Message integrity verification failed:",t.message),{passed:!1,details:`Message integrity test failed: ${t.message}`}}}static async verifyRateLimiting(e){try{let t=s.rateLimiter;if(!t||typeof t.checkMessageRate!="function")return{passed:!1,details:"Rate limiter is not available"};let r=`selftest_${crypto.getRandomValues(new Uint32Array(1))[0]}`,i=3;for(let a=0;a0}catch(t){return console.error("Nested encryption verification failed:",t.message),!1}}static async verifyPacketPadding(e){try{if(!e.paddingConfig||!e.paddingConfig.enabled)return!1;let i=new TextEncoder().encode("Test packet padding verification"),n=Math.floor(Math.random()*(e.paddingConfig.maxPadding-e.paddingConfig.minPadding))+e.paddingConfig.minPadding,a=new Uint8Array(i.byteLength+n);return a.set(new Uint8Array(i),0),a.byteLength>=i.byteLength+e.paddingConfig.minPadding}catch(t){return s.secureLog.log("error","Packet padding verification failed",{error:t.message}),!1}}static async verifyAdvancedFeatures(e){try{let t=e.fakeTrafficConfig&&e.fakeTrafficConfig.enabled,r=e.decoyChannelsConfig&&e.decoyChannelsConfig.enabled,i=e.antiFingerprintingConfig&&e.antiFingerprintingConfig.enabled;return t||r||i}catch(t){return s.secureLog.log("error","Advanced features verification failed",{error:t.message}),!1}}static async verifyMutualAuth(e){try{return!e.isVerified||!e.verificationCode?!1:e.isVerified&&e.verificationCode.length>0}catch(t){return s.secureLog.log("error","Mutual auth verification failed",{error:t.message}),!1}}static async verifyNonExtractableKeys(e){let t=[["encryptionKey",e?.encryptionKey],["macKey",e?.macKey],["metadataKey",e?.metadataKey]];for(let[r,i]of t){if(!i||!(i instanceof CryptoKey))return!1;if(i.extractable!==!1)return s.secureLog.log("error","Session key is extractable",{keyName:r}),!1}return!0}static async verifyEnhancedValidation(e){try{return e.securityFeatures?e.securityFeatures.hasEnhancedValidation||e.securityFeatures.hasEnhancedReplayProtection:!1}catch(t){return s.secureLog.log("error","Enhanced validation verification failed",{error:t.message}),!1}}static async verifyPFS(e){try{return e.securityFeatures&&e.securityFeatures.hasPFS===!0&&e.keyRotationInterval&&e.currentKeyVersion!==void 0&&e.keyVersions&&e.keyVersions instanceof Map}catch(t){return s.secureLog.log("error","PFS verification failed",{error:t.message}),!1}}static rateLimiter={messages:new Map,connections:new Map,locks:new Map,async checkMessageRate(e,t=60,r=6e4){if(typeof e!="string"||e.length>256)return!1;let i=`msg_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkMessageRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.messages.has(i)||this.messages.set(i,[]);let o=this.messages.get(i).filter(c=>n-c=t?!1:(o.push(n),this.messages.set(i,o),!0)}finally{this.locks.delete(i)}},async checkConnectionRate(e,t=5,r=3e5){if(typeof e!="string"||e.length>256)return!1;let i=`conn_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkConnectionRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.connections.has(i)||this.connections.set(i,[]);let o=this.connections.get(i).filter(c=>n-c=t?!1:(o.push(n),this.connections.set(i,o),!0)}finally{this.locks.delete(i)}},cleanup(){let e=Date.now(),t=36e5;for(let[r,i]of this.messages.entries()){if(this.locks.has(r))continue;let n=i.filter(a=>e-ae-a3e4&&this.locks.delete(r)}}};static validateSalt(e){if(!e||e.length!==64)throw new Error("Salt must be exactly 64 bytes");if(new Set(e).size<16)throw new Error("Salt has insufficient entropy");return!0}static secureLog={logs:[],maxLogs:100,isProductionMode:!1,init(){this.isProductionMode=this._detectProductionMode(),this.isProductionMode&&console.log("[SecureChat] Production mode detected - sensitive logging disabled")},_detectProductionMode(){return typeof process<"u"&&!0||!window.DEBUG_MODE&&!window.DEVELOPMENT_MODE||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")},log(e,t,r={}){let i=this.sanitizeContext(r),n={timestamp:Date.now(),level:e,message:t,context:i,id:crypto.getRandomValues(new Uint32Array(1))[0]};if(this.logs.push(n),this.logs.length>this.maxLogs&&(this.logs=this.logs.slice(-this.maxLogs)),this.isProductionMode)if(e==="error")console.error(`\u274C [SecureChat] ${t} [ERROR_CODE: ${this._generateErrorCode(t)}]`);else if(e==="warn")console.warn(`\u26A0\uFE0F [SecureChat] ${t}`);else return;else e==="error"?console.error(`\u274C [SecureChat] ${t}`,{errorType:i?.constructor?.name||"Unknown"}):e==="warn"?console.warn(`\u26A0\uFE0F [SecureChat] ${t}`,{details:i}):console.log(`[SecureChat] ${t}`,i)},_generateErrorCode(e){let t=e.split("").reduce((r,i)=>(r=(r<<5)-r+i.charCodeAt(0),r&r),0);return Math.abs(t).toString(36).substring(0,6).toUpperCase()},sanitizeContext(e){if(!e||typeof e!="object")return e;let t=[/key/i,/secret/i,/password/i,/token/i,/signature/i,/challenge/i,/proof/i,/salt/i,/iv/i,/nonce/i,/hash/i,/fingerprint/i,/mac/i,/private/i,/encryption/i,/decryption/i],r={};for(let[i,n]of Object.entries(e))t.some(o=>o.test(i)||typeof n=="string"&&o.test(n))?r[i]="[REDACTED]":typeof n=="string"&&n.length>100?r[i]=n.substring(0,100)+"...[TRUNCATED]":n instanceof ArrayBuffer||n instanceof Uint8Array?r[i]=`[${n.constructor.name}(${n.byteLength||n.length} bytes)]`:n&&typeof n=="object"&&!Array.isArray(n)?r[i]=this.sanitizeContext(n):r[i]=n;return r},getLogs(e=null){return e?this.logs.filter(t=>t.level===e):[...this.logs]},clearLogs(){this.logs=[]},async sendErrorToServer(e,t,r={}){if(this.isProductionMode)try{let i={errorCode:e,timestamp:Date.now(),userAgent:navigator.userAgent.substring(0,100),url:window.location.href.substring(0,100)};window.DEBUG_MODE&&console.log("[SecureChat] Error logged to server:",i)}catch{}}};static async generateECDHKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-384"},!1,["deriveKey","deriveBits"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-256"},!1,["deriveKey","deriveBits"])}}catch(e){throw s.secureLog.log("error","ECDH key generation failed",{error:e.message}),new Error("Failed to create keys for secure exchange")}}static async generateECDSAKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-384"},!1,["sign","verify"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"])}}catch(e){throw s.secureLog.log("error","ECDSA key generation failed",{error:e.message}),new Error("Failed to generate keys for digital signatures")}}static async signData(e,t){try{let r=new TextEncoder,i=typeof t=="string"?r.encode(t):t;try{let n=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},e,i);return Array.from(new Uint8Array(n))}catch(n){s.secureLog.log("warn","SHA-384 signing failed, trying SHA-256",{error:n.message});let a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e,i);return Array.from(new Uint8Array(a))}}catch(r){throw s.secureLog.log("error","Data signing failed",{error:r.message}),new Error("Failed to sign data")}}static async verifySignature(e,t,r){try{let i=new TextEncoder,n=typeof r=="string"?i.encode(r):r,a=new Uint8Array(t);try{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},e,a,n)}catch{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e,a,n)}}catch(i){throw s.secureLog.log("error","Signature verification failed",{error:i.message}),new Error("Failed to verify digital signature")}}static async validateKeyStructure(e,t="ECDH"){try{if(!Array.isArray(e)||e.length===0)throw new Error("Invalid key data format");let r=new Uint8Array(e);if(r.length<50)throw new Error("Key data too short - invalid SPKI structure");if(r.length>2e3)throw new Error("Key data too long - possible attack");let i=s.parseASN1(r);if(!i||i.tag!==48)throw new Error("Invalid SPKI structure - missing SEQUENCE tag");if(i.children.length!==2)throw new Error(`Invalid SPKI structure - expected 2 elements, got ${i.children.length}`);let n=i.children[0];if(n.tag!==48)throw new Error("Invalid AlgorithmIdentifier - not a SEQUENCE");let a=n.children[0];if(a.tag!==6)throw new Error("Invalid algorithm OID - not an OBJECT IDENTIFIER");let o=a.value,c=s.oidToString(o),u={ECDH:["1.2.840.10045.2.1"],ECDSA:["1.2.840.10045.2.1"],RSA:["1.2.840.113549.1.1.1"],"AES-GCM":["2.16.840.1.101.3.4.1.6","2.16.840.1.101.3.4.1.46"]}[t];if(!u)throw new Error(`Unknown algorithm: ${t}`);if(!u.includes(c))throw new Error(`Invalid algorithm OID: expected ${u.join(" or ")}, got ${c}`);if(t==="ECDH"||t==="ECDSA"){if(n.children.length<2)throw new Error("Missing curve parameters for EC key");let m=n.children[1];if(m.tag!==6)throw new Error("Invalid curve OID - not an OBJECT IDENTIFIER");let p=s.oidToString(m.value);if(!{"1.2.840.10045.3.1.7":"P-256","1.3.132.0.34":"P-384"}[p])throw new Error(`Invalid or unsupported curve OID: ${p}`)}let h=i.children[1];if(h.tag!==3)throw new Error("Invalid public key - not a BIT STRING");if(h.value[0]!==0)throw new Error(`Invalid BIT STRING - unexpected unused bits: ${h.value[0]}`);if(t==="ECDH"||t==="ECDSA"){let m=h.value.slice(1);if(m[0]!==4)throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${m[0].toString(16)}`);let p={"P-256":65,"P-384":97},g=s.oidToString(n.children[1].value)==="1.2.840.10045.3.1.7"?"P-256":"P-384",b=p[g];if(m.length!==b)throw new Error(`Invalid EC point size for ${g}: expected ${b}, got ${m.length}`)}try{let m=t==="ECDSA"||t==="ECDH"?{name:t,namedCurve:"P-384"}:{name:t},p=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,m,!1,p)}catch(m){if(t==="ECDSA"||t==="ECDH")try{let p={name:t,namedCurve:"P-256"},S=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,p,!1,S)}catch(p){throw new Error(`Key import validation failed: ${p.message}`)}else throw new Error(`Key import validation failed: ${m.message}`)}return!0}catch(r){throw s.secureLog.log("error","Key structure validation failed",{error:r.message,algorithm:t}),new Error(`Invalid key structure: ${r.message}`)}}static parseASN1(e,t=0){if(t>=e.length)return null;let r=e[t],i=t+1;if(i>=e.length)throw new Error("Truncated ASN.1 structure");let n=e[i],a=i+1;if(n&128){let d=n&127;if(d>4)throw new Error("ASN.1 length too large");n=0;for(let u=0;u=e.length)throw new Error("Truncated ASN.1 length");n=n<<8|e[a+u]}a+=d}if(a+n>e.length)throw new Error("ASN.1 structure extends beyond data");let o=e.slice(a,a+n),c={tag:r,length:n,value:o,children:[]};if(r===48||r===49){let d=0;for(;d2)throw new Error(`Invalid OID first component: ${r[0]}`);if((r[0]===0||r[0]===1)&&r[1]>39)throw new Error(`Invalid OID second component: ${r[1]} (must be <= 39 for first component ${r[0]})`);return!0}static async exportPublicKeyWithSignature(e,t,r="ECDH"){try{if(!["ECDH","ECDSA"].includes(r))throw new Error("Invalid key type");let i=await crypto.subtle.exportKey("spki",e),n=Array.from(new Uint8Array(i));await s.validateKeyStructure(n,r);let a={keyType:r,keyData:n,timestamp:Date.now(),version:"4.0"},o=JSON.stringify(a),c=await s.signData(t,o);return{...a,signature:c}}catch(i){throw s.secureLog.log("error","Public key export failed",{error:i.message,keyType:r}),new Error(`Failed to export ${r} key: ${i.message}`)}}static async importSignedPublicKey(e,t,r="ECDH"){try{if(!e||typeof e!="object")throw new Error("Invalid signed package format");let{keyType:i,keyData:n,timestamp:a,version:o,signature:c}=e;if(!i||!n||!a||!c)throw new Error("Missing required fields in signed package");if(!s.constantTimeCompare(i,r))throw new Error(`Key type mismatch: expected ${r}, got ${i}`);if(Date.now()-a>36e5)throw new Error("Signed key package is too old");await s.validateKeyStructure(n,i);let h=JSON.stringify({keyType:i,keyData:n,timestamp:a,version:o});if(!await s.verifySignature(t,c,h))throw new Error("Invalid signature on key package - possible MITM attack");let p=new Uint8Array(n);try{let S=i==="ECDH"?{name:"ECDH",namedCurve:"P-384"}:{name:"ECDSA",namedCurve:"P-384"},g=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,S,!1,g)}catch(S){s.secureLog.log("warn","Elliptic curve P-384 import failed, switching curve",{error:S.message});let g=i==="ECDH"?{name:"ECDH",namedCurve:"P-256"}:{name:"ECDSA",namedCurve:"P-256"},b=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,g,!1,b)}}catch(i){throw s.secureLog.log("error","Signed public key import failed",{error:i.message,expectedKeyType:r}),new Error(`Failed to import the signed key: ${i.message}`)}}static async exportPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=Array.from(new Uint8Array(t));return await s.validateKeyStructure(r,"ECDH"),r}catch(t){throw s.secureLog.log("error","Legacy public key export failed",{error:t.message}),new Error("Failed to export the public key")}}static async importPublicKey(e){try{await s.validateKeyStructure(e,"ECDH");let t=new Uint8Array(e);try{return await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-384"},!1,[])}catch(r){return s.secureLog.log("warn","P-384 import failed, trying P-256",{error:r.message}),await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-256"},!1,[])}}catch(t){throw s.secureLog.log("error","Legacy public key import failed",{error:t.message}),new Error("Failed to import the public key")}}static isKeyTrusted(e){if(e instanceof CryptoKey){let t=s._keyMetadata.get(e);return t?t.trusted===!0:!1}else if(e&&e._securityMetadata)return e._securityMetadata.trusted===!0;return!1}static async importPublicKeyFromSignedPackage(e,t=null,r={}){try{if(!e||!e.keyData||!e.signature)throw new Error("Invalid signed key package format");let n=["keyData","signature","keyType","timestamp","version"].filter(m=>!e[m]);if(n.length>0)throw s.secureLog.log("error","Missing required fields in signed package",{missingFields:n,availableFields:Object.keys(e)}),new Error(`Required fields are missing in the signed package: ${n.join(", ")}`);if(!t)throw s.secureLog.log("error","SECURITY VIOLATION: Signed package received without verifying key",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,securityRisk:"HIGH - Potential MITM attack vector"}),new Error("CRITICAL SECURITY ERROR: Signed key package received without a verification key. This may indicate a possible MITM attack attempt. Import rejected for security reasons.");await s.validateKeyStructure(e.keyData,e.keyType||"ECDH");let a={...e};delete a.signature;let o=JSON.stringify(a);if(!await s.verifySignature(t,e.signature,o))throw s.secureLog.log("error","SECURITY BREACH: Invalid signature detected - MITM attack prevented",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,attackPrevented:!0}),new Error("CRITICAL SECURITY ERROR: Invalid key signature detected. This indicates a possible MITM attack attempt. Key import rejected.");let d=await s.calculateKeyFingerprint(e.keyData),u=new Uint8Array(e.keyData),h=e.keyType||"ECDH";try{let m=await crypto.subtle.importKey("spki",u,{name:h,namedCurve:"P-384"},!1,h==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(m,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),m}catch(m){s.secureLog.log("warn","P-384 import failed, trying P-256",{error:m.message});let p=await crypto.subtle.importKey("spki",u,{name:h,namedCurve:"P-256"},!1,h==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(p,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),p}}catch(i){throw s.secureLog.log("error","Signed package key import failed",{error:i.message,securityImplications:"Potential security breach prevented"}),new Error(`Failed to import the public key from the signed package: ${i.message}`)}}static async deriveSharedKeys(e,t,r){try{if(!(e instanceof CryptoKey))throw s.secureLog.log("error","Private key is not a CryptoKey",{privateKeyType:typeof e,privateKeyAlgorithm:e?.algorithm?.name}),new Error("The private key is not a valid CryptoKey.");if(!(t instanceof CryptoKey))throw s.secureLog.log("error","Public key is not a CryptoKey",{publicKeyType:typeof t,publicKeyAlgorithm:t?.algorithm?.name}),new Error("The public key is not a valid CryptoKey.");if(!r||r.length!==64)throw new Error("Salt must be exactly 64 bytes for enhanced security");let i=new Uint8Array(r),n=new TextEncoder,a,o=null;try{o=await crypto.subtle.deriveBits({name:"ECDH",public:t},e,256),a=await crypto.subtle.importKey("raw",o,{name:"HKDF",hash:"SHA-256"},!1,["deriveKey","deriveBits"])}catch(b){throw s.secureLog.log("error","ECDH derivation failed",{error:b.message}),b}finally{o&&(s.zeroizeBuffer(o),o=null)}let c;c=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-encryption-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let d;d=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-authentication-v4")},a,{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"]);let u;u=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("perfect-forward-secrecy-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let h;h=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("metadata-protection-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let m=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("double-ratchet-root-v1")},a,256),p=new Uint8Array(m),S=null,g;try{S=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("fingerprint-generation-v4")},a,256),g=await s.generateKeyFingerprint(new Uint8Array(S))}finally{S&&(s.zeroizeBuffer(S),S=null)}if(!(c instanceof CryptoKey))throw s.secureLog.log("error","Derived message key is not a CryptoKey",{messageKeyType:typeof c,messageKeyAlgorithm:c?.algorithm?.name}),new Error("The derived message key is not a valid CryptoKey.");if(!(d instanceof CryptoKey))throw s.secureLog.log("error","Derived MAC key is not a CryptoKey",{macKeyType:typeof d,macKeyAlgorithm:d?.algorithm?.name}),new Error("The derived MAC key is not a valid CryptoKey.");if(!(u instanceof CryptoKey))throw s.secureLog.log("error","Derived PFS key is not a CryptoKey",{pfsKeyType:typeof u,pfsKeyAlgorithm:u?.algorithm?.name}),new Error("The derived PFS key is not a valid CryptoKey.");if(!(h instanceof CryptoKey))throw s.secureLog.log("error","Derived metadata key is not a CryptoKey",{metadataKeyType:typeof h,metadataKeyAlgorithm:h?.algorithm?.name}),new Error("The derived metadata key is not a valid CryptoKey.");return{messageKey:c,macKey:d,pfsKey:u,metadataKey:h,ratchetRoot:p,fingerprint:g,timestamp:Date.now(),version:"4.0"}}catch(i){throw s.secureLog.log("error","Enhanced key derivation failed",{error:i.message,errorStack:i.stack,privateKeyType:typeof e,publicKeyType:typeof t,saltLength:r?.length,privateKeyAlgorithm:e?.algorithm?.name,publicKeyAlgorithm:t?.algorithm?.name}),new Error(`Failed to create shared encryption keys: ${i.message}`)}}static async generateKeyFingerprint(e){let t=new Uint8Array(e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).slice(0,12).map(n=>n.toString(16).padStart(2,"0")).join(":")}static generateMutualAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(48)),t=Date.now(),r=crypto.getRandomValues(new Uint8Array(16));return{challenge:Array.from(e),timestamp:t,nonce:Array.from(r),version:"4.0"}}static async createAuthProof(e,t,r){try{if(!e||!e.challenge||!e.timestamp||!e.nonce)throw new Error("Invalid challenge structure");let i=Date.now()-e.timestamp;if(i>12e4)throw new Error("Challenge expired");let n={challenge:e.challenge,timestamp:e.timestamp,nonce:e.nonce,responseTimestamp:Date.now(),publicKeyHash:await s.hashPublicKey(r)},a=JSON.stringify(n),o=await s.signData(t,a),c={...n,signature:o,version:"4.0"};return s.secureLog.log("info","Authentication proof created",{challengeAge:Math.round(i/1e3)+"s"}),c}catch(i){throw s.secureLog.log("error","Authentication proof creation failed",{error:i.message}),new Error(`Failed to create cryptographic proof: ${i.message}`)}}static async verifyAuthProof(e,t,r){try{if(await new Promise(u=>setTimeout(u,Math.floor(Math.random()*20)+5)),s.assertCryptoKey(r,"ECDSA",["verify"]),!e||!t||!r)throw new Error("Missing required parameters for proof verification");let i=["challenge","timestamp","nonce","responseTimestamp","publicKeyHash","signature"];for(let u of i)if(!e[u])throw new Error(`Missing required field: ${u}`);if(!s.constantTimeCompareArrays(e.challenge,t.challenge)||e.timestamp!==t.timestamp||!s.constantTimeCompareArrays(e.nonce,t.nonce))throw new Error("Challenge mismatch - possible replay attack");let n=Date.now()-e.responseTimestamp;if(n>18e5)throw new Error("Proof response expired");let a=await s.hashPublicKey(r);if(!s.constantTimeCompare(e.publicKeyHash,a))throw new Error("Public key hash mismatch");let o={...e};delete o.signature;let c=JSON.stringify(o);if(!await s.verifySignature(r,e.signature,c))throw new Error("Invalid proof signature");return s.secureLog.log("info","Authentication proof verified successfully",{responseAge:Math.round(n/1e3)+"s"}),!0}catch(i){throw s.secureLog.log("error","Authentication proof verification failed",{error:i.message}),new Error(`Failed to verify cryptographic proof: ${i.message}`)}}static async hashPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Public key hashing failed",{error:t.message}),new Error("Failed to create hash of the public key")}}static generateAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(32));return Array.from(e)}static generateVerificationCode(){let e="0123456789ABCDEF",t=e.length,r="";for(let i=0;i<6;i++){let n;do n=crypto.getRandomValues(new Uint8Array(1))[0];while(n>=256-256%t);r+=e[n%t]}return r.match(/.{1,2}/g).join("-")}static async encryptMessage(e,t,r,i,n,a=0){try{if(!e||typeof e!="string")throw new Error("Invalid message format");s.assertCryptoKey(t,"AES-GCM",["encrypt"]),s.assertCryptoKey(r,"HMAC",["sign"]),s.assertCryptoKey(i,"AES-GCM",["encrypt"]);let o=new TextEncoder,c=o.encode(e),d=crypto.getRandomValues(new Uint8Array(12)),u=crypto.getRandomValues(new Uint8Array(12)),h=Date.now(),m=16-c.length%16,p=new Uint8Array(c.length+m);p.set(c);let S=crypto.getRandomValues(new Uint8Array(m));p.set(S,c.length);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:d},t,p),b={id:n,timestamp:h,sequenceNumber:a,originalLength:c.length,version:"4.0"},w=JSON.stringify(s.sortObjectKeys(b)),M=await crypto.subtle.encrypt({name:"AES-GCM",iv:u},i,o.encode(w)),F={messageIv:Array.from(d),messageData:Array.from(new Uint8Array(g)),metadataIv:Array.from(u),metadataData:Array.from(new Uint8Array(M)),version:"4.0"},k=s.sortObjectKeys(F),E=JSON.stringify(k),_=await crypto.subtle.sign("HMAC",r,o.encode(E));return F.mac=Array.from(new Uint8Array(_)),F}catch(o){throw s.secureLog.log("error","Message encryption failed",{error:o.message,messageId:n}),new Error(`Failed to encrypt the message: ${o.message}`)}}static async decryptMessage(e,t,r,i,n=null){try{s.assertCryptoKey(t,"AES-GCM",["decrypt"]),s.assertCryptoKey(r,"HMAC",["verify"]),s.assertCryptoKey(i,"AES-GCM",["decrypt"]);let a=["messageIv","messageData","metadataIv","metadataData","mac","version"];for(let x of a)if(!e[x])throw new Error(`Missing required field: ${x}`);let o={...e};delete o.mac;let c=s.sortObjectKeys(o),d=JSON.stringify(c);if(!await crypto.subtle.verify("HMAC",r,new Uint8Array(e.mac),new TextEncoder().encode(d)))throw s.secureLog.log("error","MAC verification failed",{payloadFields:Object.keys(e),macLength:e.mac?.length}),new Error("Message authentication failed - possible tampering");let h=new Uint8Array(e.metadataIv),m=new Uint8Array(e.metadataData),p=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},i,m),S=new TextDecoder().decode(p),g=JSON.parse(S);if(!g.id||!g.timestamp||g.sequenceNumber===void 0||!g.originalLength)throw new Error("Invalid metadata structure");let b=Date.now()-g.timestamp;if(b>18e5)throw new Error("Message expired (older than 30 minutes)");if(n!==null){if(g.sequenceNumbern+10)throw new Error(`Sequence number gap too large: expected around ${n}, got ${g.sequenceNumber}`)}let w=new Uint8Array(e.messageIv),M=new Uint8Array(e.messageData),F=await crypto.subtle.decrypt({name:"AES-GCM",iv:w},t,M),E=new Uint8Array(F).slice(0,g.originalLength),A=new TextDecoder().decode(E);return s.secureLog.log("info","Message decrypted successfully",{messageId:g.id,sequenceNumber:g.sequenceNumber,messageAge:Math.round(b/1e3)+"s"}),{message:A,messageId:g.id,timestamp:g.timestamp,sequenceNumber:g.sequenceNumber}}catch(a){throw s.secureLog.log("error","Message decryption failed",{error:a.message}),new Error(`Failed to decrypt the message: ${a.message}`)}}static _getMessageSanitizer(){if(s._messageSanitizer)return s._messageSanitizer;if(typeof window>"u"||!window?.document)throw new Error("DOMPurify requires a browser-like window for message sanitization");return s._messageSanitizer=Ui(window),s._messageSanitizer}static sanitizeMessage(e){if(typeof e!="string")throw new Error("Message must be a string");let t=s._getMessageSanitizer().sanitize(e,{ALLOWED_TAGS:[],ALLOWED_ATTR:[],ALLOW_UNKNOWN_PROTOCOLS:!1,FORBID_TAGS:["script","style","svg","math","template"],FORBID_ATTR:["style"],KEEP_CONTENT:!0,RETURN_TRUSTED_TYPE:!1,USE_PROFILES:{html:!1,svg:!1,svgFilters:!1,mathMl:!1}});return String(t).trim().substring(0,2e3)}static generateSalt(){return Array.from(crypto.getRandomValues(new Uint8Array(64)))}static async calculateKeyFingerprint(e){try{let t=new TextEncoder,r=new Uint8Array(e),i=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(i)).map(o=>o.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Key fingerprint calculation failed",{error:t.message}),new Error("Failed to compute the key fingerprint")}}static constantTimeCompare(e,t){let r=typeof e=="string"?e:JSON.stringify(e),i=typeof t=="string"?t:JSON.stringify(t);if(r.length!==i.length){let a=0;for(let o=0;o0&&arguments[0]!==void 0?arguments[0]:{};hr(C),rr=!0},e.clearConfig=function(){Ze=null,rr=!1,_=x,A=""},e.isValidAttribute=function(C,l,y){Ze||hr({});let v=re(C),L=re(l);return gi(v,L,y)},e.addHook=function(C,l){typeof l=="function"&&tt(I[C],l)},e.removeHook=function(C,l){if(l!==void 0){let y=ws(I[C],l);return y===-1?void 0:Es(I[C],y,1)[0]}return Ti(I[C])},e.removeHooks=function(C){I[C]=[]},e.removeAllHooks=function(){I=Fi()},e}var Ui=Oi();var Mt=class s{static _keyMetadata=new WeakMap;static _messageSanitizer=null;static sortObjectKeys(e){if(typeof e!="object"||e===null)return e;if(Array.isArray(e))return e.map(s.sortObjectKeys);let t={};return Object.keys(e).sort().forEach(r=>{t[r]=s.sortObjectKeys(e[r])}),t}static assertCryptoKey(e,t=null,r=[]){if(!(e instanceof CryptoKey))throw new Error("Expected CryptoKey");if(t&&e.algorithm?.name!==t)throw new Error(`Expected algorithm ${t}, got ${e.algorithm?.name}`);for(let i of r)if(!e.usages||!e.usages.includes(i))throw new Error(`Missing required key usage: ${i}`)}static arrayBufferToBase64(e){let t="",r=new Uint8Array(e),i=r.byteLength;for(let n=0;n=4294967296-4294967296%t);i+=e[a%t]}return i}static async calculateSecurityLevel(e){let t=0,r=100,i={};try{if(!e||!e.securityFeatures)return console.warn("Security manager not fully initialized, using fallback calculation"),{level:"INITIALIZING",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:"Security system initializing...",isRealData:!1};let n="full",a=!1;try{let h=await s.verifyEncryption(e);h.passed?(t+=20,i.verifyEncryption={passed:!0,details:h.details,points:20}):i.verifyEncryption={passed:!1,details:h.details,points:0}}catch(h){i.verifyEncryption={passed:!1,details:`Encryption check failed: ${h.message}`,points:0}}try{let h=await s.verifyECDHKeyExchange(e);h.passed?(t+=15,i.verifyECDHKeyExchange={passed:!0,details:h.details,points:15}):i.verifyECDHKeyExchange={passed:!1,details:h.details,points:0}}catch(h){i.verifyECDHKeyExchange={passed:!1,details:`Key exchange check failed: ${h.message}`,points:0}}try{let h=await s.verifyMessageIntegrity(e);h.passed?(t+=10,i.verifyMessageIntegrity={passed:!0,details:h.details,points:10}):i.verifyMessageIntegrity={passed:!1,details:h.details,points:0}}catch(h){i.verifyMessageIntegrity={passed:!1,details:`Message integrity check failed: ${h.message}`,points:0}}try{let h=await s.verifyECDSASignatures(e);h.passed?(t+=15,i.verifyECDSASignatures={passed:!0,details:h.details,points:15}):i.verifyECDSASignatures={passed:!1,details:h.details,points:0}}catch(h){i.verifyECDSASignatures={passed:!1,details:`Digital signatures check failed: ${h.message}`,points:0}}try{let h=await s.verifyRateLimiting(e);h.passed?(t+=5,i.verifyRateLimiting={passed:!0,details:h.details,points:5}):i.verifyRateLimiting={passed:!1,details:h.details,points:0}}catch(h){i.verifyRateLimiting={passed:!1,details:`Rate limiting check failed: ${h.message}`,points:0}}try{let h=await s.verifyMetadataProtection(e);h.passed?(t+=10,i.verifyMetadataProtection={passed:!0,details:h.details,points:10}):i.verifyMetadataProtection={passed:!1,details:h.details,points:0}}catch(h){i.verifyMetadataProtection={passed:!1,details:`Metadata protection check failed: ${h.message}`,points:0}}try{let h=await s.verifyPerfectForwardSecrecy(e);h.passed?(t+=10,i.verifyPerfectForwardSecrecy={passed:!0,details:h.details,points:10}):i.verifyPerfectForwardSecrecy={passed:!1,details:h.details,points:0}}catch(h){i.verifyPerfectForwardSecrecy={passed:!1,details:`PFS check failed: ${h.message}`,points:0}}await s.verifyNestedEncryption(e)?(t+=5,i.nestedEncryption={passed:!0,details:"Nested encryption active",points:5}):i.nestedEncryption={passed:!1,details:"Nested encryption failed",points:0},await s.verifyPacketPadding(e)?(t+=5,i.packetPadding={passed:!0,details:"Packet padding active",points:5}):i.packetPadding={passed:!1,details:"Packet padding failed",points:0},await s.verifyAdvancedFeatures(e)?(t+=10,i.advancedFeatures={passed:!0,details:"Advanced features active",points:10}):i.advancedFeatures={passed:!1,details:"Advanced features failed",points:0};let o=Math.round(t/r*100),c=10,d=Object.values(i).filter(h=>h.passed).length;return{level:o>=85?"HIGH":o>=65?"MEDIUM":o>=35?"LOW":"CRITICAL",score:o,color:o>=85?"green":o>=65?"orange":o>=35?"yellow":"red",verificationResults:i,timestamp:Date.now(),details:`Real verification: ${t}/${r} security checks passed (${d}/${c} available)`,isRealData:!0,passedChecks:d,totalChecks:c,sessionType:n,maxPossibleScore:100}}catch(n){return console.error("Security level calculation failed:",n.message),{level:"UNKNOWN",score:0,color:"red",verificationResults:{},timestamp:Date.now(),details:`Verification failed: ${n.message}`,isRealData:!1}}}static async verifyEncryption(e){try{if(!e.encryptionKey)return{passed:!1,details:"No encryption key available"};let t=["Test encryption verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"A".repeat(1e3)];for(let r of t){let n=new TextEncoder().encode(r),a=crypto.getRandomValues(new Uint8Array(12)),o=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e.encryptionKey,n),c=await crypto.subtle.decrypt({name:"AES-GCM",iv:a},e.encryptionKey,o);if(new TextDecoder().decode(c)!==r)return{passed:!1,details:`Decryption mismatch for: ${r.substring(0,20)}...`}}return{passed:!0,details:"AES-GCM encryption/decryption working correctly"}}catch(t){return console.error("Encryption verification failed:",t.message),{passed:!1,details:`Encryption test failed: ${t.message}`}}}static async verifyECDHKeyExchange(e){try{if(!e.ecdhKeyPair||!e.ecdhKeyPair.privateKey||!e.ecdhKeyPair.publicKey)return{passed:!1,details:"No ECDH key pair available"};let t=e.ecdhKeyPair.privateKey.algorithm.name,r=e.ecdhKeyPair.privateKey.algorithm.namedCurve;if(t!=="ECDH")return{passed:!1,details:`Invalid key type: ${t}, expected ECDH`};if(r!=="P-384"&&r!=="P-256")return{passed:!1,details:`Unsupported curve: ${r}, expected P-384 or P-256`};try{if(!await crypto.subtle.deriveKey({name:"ECDH",public:e.ecdhKeyPair.publicKey},e.ecdhKeyPair.privateKey,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]))return{passed:!1,details:"Key derivation failed"}}catch(i){return{passed:!1,details:`Key derivation test failed: ${i.message}`}}return{passed:!0,details:`ECDH key exchange working with ${r} curve`}}catch(t){return console.error("ECDH verification failed:",t.message),{passed:!1,details:`ECDH test failed: ${t.message}`}}}static async verifyECDSASignatures(e){try{if(!e.ecdsaKeyPair||!e.ecdsaKeyPair.privateKey||!e.ecdsaKeyPair.publicKey)return{passed:!1,details:"No ECDSA key pair available"};let t=["Test ECDSA signature verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"B".repeat(2e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.privateKey,n);if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e.ecdsaKeyPair.publicKey,a,n))return{passed:!1,details:`Signature verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"ECDSA digital signatures working correctly"}}catch(t){return console.error("ECDSA verification failed:",t.message),{passed:!1,details:`ECDSA test failed: ${t.message}`}}}static async verifyMessageIntegrity(e){try{if(!e.macKey||!(e.macKey instanceof CryptoKey))return{passed:!1,details:"MAC key not available or invalid"};let t=["Test message integrity verification","\u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0446\u0435\u043B\u043E\u0441\u0442\u043D\u043E\u0441\u0442\u0438","Special chars: !@#$%^&*()_+-=[]{}|;:,.<>?","Large data: "+"C".repeat(3e3)];for(let r of t){let n=new TextEncoder().encode(r),a=await crypto.subtle.sign({name:"HMAC",hash:"SHA-256"},e.macKey,n);if(!await crypto.subtle.verify({name:"HMAC",hash:"SHA-256"},e.macKey,a,n))return{passed:!1,details:`HMAC verification failed for: ${r.substring(0,20)}...`}}return{passed:!0,details:"Message integrity (HMAC) working correctly"}}catch(t){return console.error("Message integrity verification failed:",t.message),{passed:!1,details:`Message integrity test failed: ${t.message}`}}}static async verifyRateLimiting(e){try{let t=s.rateLimiter;if(!t||typeof t.checkMessageRate!="function")return{passed:!1,details:"Rate limiter is not available"};let r=`selftest_${crypto.getRandomValues(new Uint32Array(1))[0]}`,i=3;for(let a=0;a0}catch(t){return console.error("Nested encryption verification failed:",t.message),!1}}static async verifyPacketPadding(e){try{if(!e.paddingConfig||!e.paddingConfig.enabled)return!1;let i=new TextEncoder().encode("Test packet padding verification"),n=Math.floor(Math.random()*(e.paddingConfig.maxPadding-e.paddingConfig.minPadding))+e.paddingConfig.minPadding,a=new Uint8Array(i.byteLength+n);return a.set(new Uint8Array(i),0),a.byteLength>=i.byteLength+e.paddingConfig.minPadding}catch(t){return s.secureLog.log("error","Packet padding verification failed",{error:t.message}),!1}}static async verifyAdvancedFeatures(e){try{let t=e.fakeTrafficConfig&&e.fakeTrafficConfig.enabled,r=e.decoyChannelsConfig&&e.decoyChannelsConfig.enabled,i=e.antiFingerprintingConfig&&e.antiFingerprintingConfig.enabled;return t||r||i}catch(t){return s.secureLog.log("error","Advanced features verification failed",{error:t.message}),!1}}static async verifyMutualAuth(e){try{return!e.isVerified||!e.verificationCode?!1:e.isVerified&&e.verificationCode.length>0}catch(t){return s.secureLog.log("error","Mutual auth verification failed",{error:t.message}),!1}}static async verifyNonExtractableKeys(e){let t=[["encryptionKey",e?.encryptionKey],["macKey",e?.macKey],["metadataKey",e?.metadataKey]];for(let[r,i]of t){if(!i||!(i instanceof CryptoKey))return!1;if(i.extractable!==!1)return s.secureLog.log("error","Session key is extractable",{keyName:r}),!1}return!0}static async verifyEnhancedValidation(e){try{return e.securityFeatures?e.securityFeatures.hasEnhancedValidation||e.securityFeatures.hasEnhancedReplayProtection:!1}catch(t){return s.secureLog.log("error","Enhanced validation verification failed",{error:t.message}),!1}}static async verifyPFS(e){try{return e.securityFeatures&&e.securityFeatures.hasPFS===!0&&e.keyRotationInterval&&e.currentKeyVersion!==void 0&&e.keyVersions&&e.keyVersions instanceof Map}catch(t){return s.secureLog.log("error","PFS verification failed",{error:t.message}),!1}}static rateLimiter={messages:new Map,connections:new Map,locks:new Map,async checkMessageRate(e,t=60,r=6e4){if(typeof e!="string"||e.length>256)return!1;let i=`msg_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkMessageRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.messages.has(i)||this.messages.set(i,[]);let o=this.messages.get(i).filter(c=>n-c=t?!1:(o.push(n),this.messages.set(i,o),!0)}finally{this.locks.delete(i)}},async checkConnectionRate(e,t=5,r=3e5){if(typeof e!="string"||e.length>256)return!1;let i=`conn_${e}`;if(this.locks.has(i))return await new Promise(n=>setTimeout(n,Math.floor(Math.random()*10)+5)),this.checkConnectionRate(e,t,r);this.locks.set(i,!0);try{let n=Date.now();this.connections.has(i)||this.connections.set(i,[]);let o=this.connections.get(i).filter(c=>n-c=t?!1:(o.push(n),this.connections.set(i,o),!0)}finally{this.locks.delete(i)}},cleanup(){let e=Date.now(),t=36e5;for(let[r,i]of this.messages.entries()){if(this.locks.has(r))continue;let n=i.filter(a=>e-ae-a3e4&&this.locks.delete(r)}}};static validateSalt(e){if(!e||e.length!==64)throw new Error("Salt must be exactly 64 bytes");if(new Set(e).size<16)throw new Error("Salt has insufficient entropy");return!0}static secureLog={logs:[],maxLogs:100,isProductionMode:!1,init(){this.isProductionMode=this._detectProductionMode(),this.isProductionMode&&console.log("[SecureChat] Production mode detected - sensitive logging disabled")},_detectProductionMode(){return typeof process<"u"&&!0||!window.DEBUG_MODE&&!window.DEVELOPMENT_MODE||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")},log(e,t,r={}){let i=this.sanitizeContext(r),n={timestamp:Date.now(),level:e,message:t,context:i,id:crypto.getRandomValues(new Uint32Array(1))[0]};if(this.logs.push(n),this.logs.length>this.maxLogs&&(this.logs=this.logs.slice(-this.maxLogs)),this.isProductionMode)if(e==="error")console.error(`\u274C [SecureChat] ${t} [ERROR_CODE: ${this._generateErrorCode(t)}]`);else if(e==="warn")console.warn(`\u26A0\uFE0F [SecureChat] ${t}`);else return;else e==="error"?console.error(`\u274C [SecureChat] ${t}`,{errorType:i?.constructor?.name||"Unknown"}):e==="warn"?console.warn(`\u26A0\uFE0F [SecureChat] ${t}`,{details:i}):console.log(`[SecureChat] ${t}`,i)},_generateErrorCode(e){let t=e.split("").reduce((r,i)=>(r=(r<<5)-r+i.charCodeAt(0),r&r),0);return Math.abs(t).toString(36).substring(0,6).toUpperCase()},sanitizeContext(e){if(!e||typeof e!="object")return e;let t=[/key/i,/secret/i,/password/i,/token/i,/signature/i,/challenge/i,/proof/i,/salt/i,/iv/i,/nonce/i,/hash/i,/fingerprint/i,/mac/i,/private/i,/encryption/i,/decryption/i],r={};for(let[i,n]of Object.entries(e))t.some(o=>o.test(i)||typeof n=="string"&&o.test(n))?r[i]="[REDACTED]":typeof n=="string"&&n.length>100?r[i]=n.substring(0,100)+"...[TRUNCATED]":n instanceof ArrayBuffer||n instanceof Uint8Array?r[i]=`[${n.constructor.name}(${n.byteLength||n.length} bytes)]`:n&&typeof n=="object"&&!Array.isArray(n)?r[i]=this.sanitizeContext(n):r[i]=n;return r},getLogs(e=null){return e?this.logs.filter(t=>t.level===e):[...this.logs]},clearLogs(){this.logs=[]},async sendErrorToServer(e,t,r={}){if(this.isProductionMode)try{let i={errorCode:e,timestamp:Date.now(),userAgent:navigator.userAgent.substring(0,100),url:window.location.href.substring(0,100)};window.DEBUG_MODE&&console.log("[SecureChat] Error logged to server:",i)}catch{}}};static async generateECDHKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-384"},!1,["deriveKey","deriveBits"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDH",namedCurve:"P-256"},!1,["deriveKey","deriveBits"])}}catch(e){throw s.secureLog.log("error","ECDH key generation failed",{error:e.message}),new Error("Failed to create keys for secure exchange")}}static async generateECDSAKeyPair(){try{try{return await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-384"},!1,["sign","verify"])}catch(e){return s.secureLog.log("warn","Elliptic curve P-384 generation failed, switching curve",{error:e.message}),await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"])}}catch(e){throw s.secureLog.log("error","ECDSA key generation failed",{error:e.message}),new Error("Failed to generate keys for digital signatures")}}static async signData(e,t){try{let r=new TextEncoder,i=typeof t=="string"?r.encode(t):t;try{let n=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},e,i);return Array.from(new Uint8Array(n))}catch(n){s.secureLog.log("warn","SHA-384 signing failed, trying SHA-256",{error:n.message});let a=await crypto.subtle.sign({name:"ECDSA",hash:"SHA-256"},e,i);return Array.from(new Uint8Array(a))}}catch(r){throw s.secureLog.log("error","Data signing failed",{error:r.message}),new Error("Failed to sign data")}}static async verifySignature(e,t,r){try{let i=new TextEncoder,n=typeof r=="string"?i.encode(r):r,a=new Uint8Array(t);try{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},e,a,n)}catch{return await crypto.subtle.verify({name:"ECDSA",hash:"SHA-256"},e,a,n)}}catch(i){throw s.secureLog.log("error","Signature verification failed",{error:i.message}),new Error("Failed to verify digital signature")}}static async validateKeyStructure(e,t="ECDH"){try{if(!Array.isArray(e)||e.length===0)throw new Error("Invalid key data format");let r=new Uint8Array(e);if(r.length<50)throw new Error("Key data too short - invalid SPKI structure");if(r.length>2e3)throw new Error("Key data too long - possible attack");let i=s.parseASN1(r);if(!i||i.tag!==48)throw new Error("Invalid SPKI structure - missing SEQUENCE tag");if(i.children.length!==2)throw new Error(`Invalid SPKI structure - expected 2 elements, got ${i.children.length}`);let n=i.children[0];if(n.tag!==48)throw new Error("Invalid AlgorithmIdentifier - not a SEQUENCE");let a=n.children[0];if(a.tag!==6)throw new Error("Invalid algorithm OID - not an OBJECT IDENTIFIER");let o=a.value,c=s.oidToString(o),u={ECDH:["1.2.840.10045.2.1"],ECDSA:["1.2.840.10045.2.1"],RSA:["1.2.840.113549.1.1.1"],"AES-GCM":["2.16.840.1.101.3.4.1.6","2.16.840.1.101.3.4.1.46"]}[t];if(!u)throw new Error(`Unknown algorithm: ${t}`);if(!u.includes(c))throw new Error(`Invalid algorithm OID: expected ${u.join(" or ")}, got ${c}`);if(t==="ECDH"||t==="ECDSA"){if(n.children.length<2)throw new Error("Missing curve parameters for EC key");let m=n.children[1];if(m.tag!==6)throw new Error("Invalid curve OID - not an OBJECT IDENTIFIER");let p=s.oidToString(m.value);if(!{"1.2.840.10045.3.1.7":"P-256","1.3.132.0.34":"P-384"}[p])throw new Error(`Invalid or unsupported curve OID: ${p}`)}let h=i.children[1];if(h.tag!==3)throw new Error("Invalid public key - not a BIT STRING");if(h.value[0]!==0)throw new Error(`Invalid BIT STRING - unexpected unused bits: ${h.value[0]}`);if(t==="ECDH"||t==="ECDSA"){let m=h.value.slice(1);if(m[0]!==4)throw new Error(`Invalid EC point format: expected uncompressed (0x04), got 0x${m[0].toString(16)}`);let p={"P-256":65,"P-384":97},g=s.oidToString(n.children[1].value)==="1.2.840.10045.3.1.7"?"P-256":"P-384",b=p[g];if(m.length!==b)throw new Error(`Invalid EC point size for ${g}: expected ${b}, got ${m.length}`)}try{let m=t==="ECDSA"||t==="ECDH"?{name:t,namedCurve:"P-384"}:{name:t},p=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,m,!1,p)}catch(m){if(t==="ECDSA"||t==="ECDH")try{let p={name:t,namedCurve:"P-256"},S=t==="ECDSA"?["verify"]:[];await crypto.subtle.importKey("spki",r.buffer,p,!1,S)}catch(p){throw new Error(`Key import validation failed: ${p.message}`)}else throw new Error(`Key import validation failed: ${m.message}`)}return!0}catch(r){throw s.secureLog.log("error","Key structure validation failed",{error:r.message,algorithm:t}),new Error(`Invalid key structure: ${r.message}`)}}static parseASN1(e,t=0){if(t>=e.length)return null;let r=e[t],i=t+1;if(i>=e.length)throw new Error("Truncated ASN.1 structure");let n=e[i],a=i+1;if(n&128){let d=n&127;if(d>4)throw new Error("ASN.1 length too large");n=0;for(let u=0;u=e.length)throw new Error("Truncated ASN.1 length");n=n<<8|e[a+u]}a+=d}if(a+n>e.length)throw new Error("ASN.1 structure extends beyond data");let o=e.slice(a,a+n),c={tag:r,length:n,value:o,children:[]};if(r===48||r===49){let d=0;for(;d2)throw new Error(`Invalid OID first component: ${r[0]}`);if((r[0]===0||r[0]===1)&&r[1]>39)throw new Error(`Invalid OID second component: ${r[1]} (must be <= 39 for first component ${r[0]})`);return!0}static async exportPublicKeyWithSignature(e,t,r="ECDH"){try{if(!["ECDH","ECDSA"].includes(r))throw new Error("Invalid key type");let i=await crypto.subtle.exportKey("spki",e),n=Array.from(new Uint8Array(i));await s.validateKeyStructure(n,r);let a={keyType:r,keyData:n,timestamp:Date.now(),version:"4.0"},o=JSON.stringify(a),c=await s.signData(t,o);return{...a,signature:c}}catch(i){throw s.secureLog.log("error","Public key export failed",{error:i.message,keyType:r}),new Error(`Failed to export ${r} key: ${i.message}`)}}static async importSignedPublicKey(e,t,r="ECDH"){try{if(!e||typeof e!="object")throw new Error("Invalid signed package format");let{keyType:i,keyData:n,timestamp:a,version:o,signature:c}=e;if(!i||!n||!a||!c)throw new Error("Missing required fields in signed package");if(!s.constantTimeCompare(i,r))throw new Error(`Key type mismatch: expected ${r}, got ${i}`);if(Date.now()-a>36e5)throw new Error("Signed key package is too old");await s.validateKeyStructure(n,i);let h=JSON.stringify({keyType:i,keyData:n,timestamp:a,version:o});if(!await s.verifySignature(t,c,h))throw new Error("Invalid signature on key package - possible MITM attack");let p=new Uint8Array(n);try{let S=i==="ECDH"?{name:"ECDH",namedCurve:"P-384"}:{name:"ECDSA",namedCurve:"P-384"},g=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,S,!1,g)}catch(S){s.secureLog.log("warn","Elliptic curve P-384 import failed, switching curve",{error:S.message});let g=i==="ECDH"?{name:"ECDH",namedCurve:"P-256"}:{name:"ECDSA",namedCurve:"P-256"},b=i==="ECDH"?[]:["verify"];return await crypto.subtle.importKey("spki",p,g,!1,b)}}catch(i){throw s.secureLog.log("error","Signed public key import failed",{error:i.message,expectedKeyType:r}),new Error(`Failed to import the signed key: ${i.message}`)}}static async exportPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=Array.from(new Uint8Array(t));return await s.validateKeyStructure(r,"ECDH"),r}catch(t){throw s.secureLog.log("error","Legacy public key export failed",{error:t.message}),new Error("Failed to export the public key")}}static async importPublicKey(e){try{await s.validateKeyStructure(e,"ECDH");let t=new Uint8Array(e);try{return await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-384"},!1,[])}catch(r){return s.secureLog.log("warn","P-384 import failed, trying P-256",{error:r.message}),await crypto.subtle.importKey("spki",t,{name:"ECDH",namedCurve:"P-256"},!1,[])}}catch(t){throw s.secureLog.log("error","Legacy public key import failed",{error:t.message}),new Error("Failed to import the public key")}}static isKeyTrusted(e){if(e instanceof CryptoKey){let t=s._keyMetadata.get(e);return t?t.trusted===!0:!1}else if(e&&e._securityMetadata)return e._securityMetadata.trusted===!0;return!1}static async importPublicKeyFromSignedPackage(e,t=null,r={}){try{if(!e||!e.keyData||!e.signature)throw new Error("Invalid signed key package format");let n=["keyData","signature","keyType","timestamp","version"].filter(m=>!e[m]);if(n.length>0)throw s.secureLog.log("error","Missing required fields in signed package",{missingFields:n,availableFields:Object.keys(e)}),new Error(`Required fields are missing in the signed package: ${n.join(", ")}`);if(!t)throw s.secureLog.log("error","SECURITY VIOLATION: Signed package received without verifying key",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,securityRisk:"HIGH - Potential MITM attack vector"}),new Error("CRITICAL SECURITY ERROR: Signed key package received without a verification key. This may indicate a possible MITM attack attempt. Import rejected for security reasons.");await s.validateKeyStructure(e.keyData,e.keyType||"ECDH");let a={...e};delete a.signature;let o=JSON.stringify(a);if(!await s.verifySignature(t,e.signature,o))throw s.secureLog.log("error","SECURITY BREACH: Invalid signature detected - MITM attack prevented",{keyType:e.keyType,keySize:e.keyData.length,timestamp:e.timestamp,version:e.version,attackPrevented:!0}),new Error("CRITICAL SECURITY ERROR: Invalid key signature detected. This indicates a possible MITM attack attempt. Key import rejected.");let d=await s.calculateKeyFingerprint(e.keyData),u=new Uint8Array(e.keyData),h=e.keyType||"ECDH";try{let m=await crypto.subtle.importKey("spki",u,{name:h,namedCurve:"P-384"},!1,h==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(m,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),m}catch(m){s.secureLog.log("warn","P-384 import failed, trying P-256",{error:m.message});let p=await crypto.subtle.importKey("spki",u,{name:h,namedCurve:"P-256"},!1,h==="ECDSA"?["verify"]:[]);return s._keyMetadata.set(p,{trusted:!0,verificationStatus:"VERIFIED_SECURE",verificationTimestamp:Date.now()}),p}}catch(i){throw s.secureLog.log("error","Signed package key import failed",{error:i.message,securityImplications:"Potential security breach prevented"}),new Error(`Failed to import the public key from the signed package: ${i.message}`)}}static async deriveSharedKeys(e,t,r){try{if(!(e instanceof CryptoKey))throw s.secureLog.log("error","Private key is not a CryptoKey",{privateKeyType:typeof e,privateKeyAlgorithm:e?.algorithm?.name}),new Error("The private key is not a valid CryptoKey.");if(!(t instanceof CryptoKey))throw s.secureLog.log("error","Public key is not a CryptoKey",{publicKeyType:typeof t,publicKeyAlgorithm:t?.algorithm?.name}),new Error("The public key is not a valid CryptoKey.");if(!r||r.length!==64)throw new Error("Salt must be exactly 64 bytes for enhanced security");let i=new Uint8Array(r),n=new TextEncoder,a,o=null;try{o=await crypto.subtle.deriveBits({name:"ECDH",public:t},e,256),a=await crypto.subtle.importKey("raw",o,{name:"HKDF",hash:"SHA-256"},!1,["deriveKey","deriveBits"])}catch(b){throw s.secureLog.log("error","ECDH derivation failed",{error:b.message}),b}finally{o&&(s.zeroizeBuffer(o),o=null)}let c;c=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-encryption-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let d;d=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("message-authentication-v4")},a,{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"]);let u;u=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("perfect-forward-secrecy-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let h;h=await crypto.subtle.deriveKey({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("metadata-protection-v4")},a,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"]);let m=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("double-ratchet-root-v1")},a,256),p=new Uint8Array(m),S=null,g;try{S=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:i,info:n.encode("fingerprint-generation-v4")},a,256),g=await s.generateKeyFingerprint(new Uint8Array(S))}finally{S&&(s.zeroizeBuffer(S),S=null)}if(!(c instanceof CryptoKey))throw s.secureLog.log("error","Derived message key is not a CryptoKey",{messageKeyType:typeof c,messageKeyAlgorithm:c?.algorithm?.name}),new Error("The derived message key is not a valid CryptoKey.");if(!(d instanceof CryptoKey))throw s.secureLog.log("error","Derived MAC key is not a CryptoKey",{macKeyType:typeof d,macKeyAlgorithm:d?.algorithm?.name}),new Error("The derived MAC key is not a valid CryptoKey.");if(!(u instanceof CryptoKey))throw s.secureLog.log("error","Derived PFS key is not a CryptoKey",{pfsKeyType:typeof u,pfsKeyAlgorithm:u?.algorithm?.name}),new Error("The derived PFS key is not a valid CryptoKey.");if(!(h instanceof CryptoKey))throw s.secureLog.log("error","Derived metadata key is not a CryptoKey",{metadataKeyType:typeof h,metadataKeyAlgorithm:h?.algorithm?.name}),new Error("The derived metadata key is not a valid CryptoKey.");return{messageKey:c,macKey:d,pfsKey:u,metadataKey:h,ratchetRoot:p,fingerprint:g,timestamp:Date.now(),version:"4.0"}}catch(i){throw s.secureLog.log("error","Enhanced key derivation failed",{error:i.message,errorStack:i.stack,privateKeyType:typeof e,publicKeyType:typeof t,saltLength:r?.length,privateKeyAlgorithm:e?.algorithm?.name,publicKeyAlgorithm:t?.algorithm?.name}),new Error(`Failed to create shared encryption keys: ${i.message}`)}}static async generateKeyFingerprint(e){let t=new Uint8Array(e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).slice(0,12).map(n=>n.toString(16).padStart(2,"0")).join(":")}static generateMutualAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(48)),t=Date.now(),r=crypto.getRandomValues(new Uint8Array(16));return{challenge:Array.from(e),timestamp:t,nonce:Array.from(r),version:"4.0"}}static async createAuthProof(e,t,r){try{if(!e||!e.challenge||!e.timestamp||!e.nonce)throw new Error("Invalid challenge structure");let i=Date.now()-e.timestamp;if(i>12e4)throw new Error("Challenge expired");let n={challenge:e.challenge,timestamp:e.timestamp,nonce:e.nonce,responseTimestamp:Date.now(),publicKeyHash:await s.hashPublicKey(r)},a=JSON.stringify(n),o=await s.signData(t,a),c={...n,signature:o,version:"4.0"};return s.secureLog.log("info","Authentication proof created",{challengeAge:Math.round(i/1e3)+"s"}),c}catch(i){throw s.secureLog.log("error","Authentication proof creation failed",{error:i.message}),new Error(`Failed to create cryptographic proof: ${i.message}`)}}static async verifyAuthProof(e,t,r){try{if(await new Promise(u=>setTimeout(u,Math.floor(Math.random()*20)+5)),s.assertCryptoKey(r,"ECDSA",["verify"]),!e||!t||!r)throw new Error("Missing required parameters for proof verification");let i=["challenge","timestamp","nonce","responseTimestamp","publicKeyHash","signature"];for(let u of i)if(!e[u])throw new Error(`Missing required field: ${u}`);if(!s.constantTimeCompareArrays(e.challenge,t.challenge)||e.timestamp!==t.timestamp||!s.constantTimeCompareArrays(e.nonce,t.nonce))throw new Error("Challenge mismatch - possible replay attack");let n=Date.now()-e.responseTimestamp;if(n>18e5)throw new Error("Proof response expired");let a=await s.hashPublicKey(r);if(!s.constantTimeCompare(e.publicKeyHash,a))throw new Error("Public key hash mismatch");let o={...e};delete o.signature;let c=JSON.stringify(o);if(!await s.verifySignature(r,e.signature,c))throw new Error("Invalid proof signature");return s.secureLog.log("info","Authentication proof verified successfully",{responseAge:Math.round(n/1e3)+"s"}),!0}catch(i){throw s.secureLog.log("error","Authentication proof verification failed",{error:i.message}),new Error(`Failed to verify cryptographic proof: ${i.message}`)}}static async hashPublicKey(e){try{let t=await crypto.subtle.exportKey("spki",e),r=await crypto.subtle.digest("SHA-384",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Public key hashing failed",{error:t.message}),new Error("Failed to create hash of the public key")}}static generateAuthChallenge(){let e=crypto.getRandomValues(new Uint8Array(32));return Array.from(e)}static generateVerificationCode(){let e="0123456789ABCDEF",t=e.length,r="";for(let i=0;i<6;i++){let n;do n=crypto.getRandomValues(new Uint8Array(1))[0];while(n>=256-256%t);r+=e[n%t]}return r.match(/.{1,2}/g).join("-")}static async encryptMessage(e,t,r,i,n,a=0){try{if(!e||typeof e!="string")throw new Error("Invalid message format");s.assertCryptoKey(t,"AES-GCM",["encrypt"]),s.assertCryptoKey(r,"HMAC",["sign"]),s.assertCryptoKey(i,"AES-GCM",["encrypt"]);let o=new TextEncoder,c=o.encode(e),d=crypto.getRandomValues(new Uint8Array(12)),u=crypto.getRandomValues(new Uint8Array(12)),h=Date.now(),m=16-c.length%16,p=new Uint8Array(c.length+m);p.set(c);let S=crypto.getRandomValues(new Uint8Array(m));p.set(S,c.length);let g=await crypto.subtle.encrypt({name:"AES-GCM",iv:d},t,p),b={id:n,timestamp:h,sequenceNumber:a,originalLength:c.length,version:"4.0"},w=JSON.stringify(s.sortObjectKeys(b)),M=await crypto.subtle.encrypt({name:"AES-GCM",iv:u},i,o.encode(w)),F={messageIv:Array.from(d),messageData:Array.from(new Uint8Array(g)),metadataIv:Array.from(u),metadataData:Array.from(new Uint8Array(M)),version:"4.0"},k=s.sortObjectKeys(F),E=JSON.stringify(k),_=await crypto.subtle.sign("HMAC",r,o.encode(E));return F.mac=Array.from(new Uint8Array(_)),F}catch(o){throw s.secureLog.log("error","Message encryption failed",{error:o.message,messageId:n}),new Error(`Failed to encrypt the message: ${o.message}`)}}static async decryptMessage(e,t,r,i,n=null){try{s.assertCryptoKey(t,"AES-GCM",["decrypt"]),s.assertCryptoKey(r,"HMAC",["verify"]),s.assertCryptoKey(i,"AES-GCM",["decrypt"]);let a=["messageIv","messageData","metadataIv","metadataData","mac","version"];for(let x of a)if(!e[x])throw new Error(`Missing required field: ${x}`);let o={...e};delete o.mac;let c=s.sortObjectKeys(o),d=JSON.stringify(c);if(!await crypto.subtle.verify("HMAC",r,new Uint8Array(e.mac),new TextEncoder().encode(d)))throw s.secureLog.log("error","MAC verification failed",{payloadFields:Object.keys(e),macLength:e.mac?.length}),new Error("Message authentication failed - possible tampering");let h=new Uint8Array(e.metadataIv),m=new Uint8Array(e.metadataData),p=await crypto.subtle.decrypt({name:"AES-GCM",iv:h},i,m),S=new TextDecoder().decode(p),g=JSON.parse(S);if(!g.id||!g.timestamp||g.sequenceNumber===void 0||!g.originalLength)throw new Error("Invalid metadata structure");let b=Date.now()-g.timestamp;if(b>18e5)throw new Error("Message expired (older than 30 minutes)");if(n!==null){if(g.sequenceNumbern+10)throw new Error(`Sequence number gap too large: expected around ${n}, got ${g.sequenceNumber}`)}let w=new Uint8Array(e.messageIv),M=new Uint8Array(e.messageData),F=await crypto.subtle.decrypt({name:"AES-GCM",iv:w},t,M),E=new Uint8Array(F).slice(0,g.originalLength),A=new TextDecoder().decode(E);return s.secureLog.log("info","Message decrypted successfully",{messageId:g.id,sequenceNumber:g.sequenceNumber,messageAge:Math.round(b/1e3)+"s"}),{message:A,messageId:g.id,timestamp:g.timestamp,sequenceNumber:g.sequenceNumber}}catch(a){throw s.secureLog.log("error","Message decryption failed",{error:a.message}),new Error(`Failed to decrypt the message: ${a.message}`)}}static _getMessageSanitizer(){if(s._messageSanitizer)return s._messageSanitizer;if(typeof window>"u"||!window?.document)throw new Error("DOMPurify requires a browser-like window for message sanitization");return s._messageSanitizer=Ui(window),s._messageSanitizer}static sanitizeMessage(e){if(typeof e!="string")throw new Error("Message must be a string");let t=s._getMessageSanitizer().sanitize(e,{ALLOWED_TAGS:[],ALLOWED_ATTR:[],ALLOW_UNKNOWN_PROTOCOLS:!1,FORBID_TAGS:["script","style","svg","math","template"],FORBID_ATTR:["style"],KEEP_CONTENT:!0,RETURN_TRUSTED_TYPE:!1,USE_PROFILES:{html:!1,svg:!1,svgFilters:!1,mathMl:!1}});return String(t).trim().substring(0,2e3)}static generateSalt(){return Array.from(crypto.getRandomValues(new Uint8Array(64)))}static async calculateKeyFingerprint(e){try{let t=new TextEncoder,r=new Uint8Array(e),i=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(i)).map(o=>o.toString(16).padStart(2,"0")).join("")}catch(t){throw s.secureLog.log("error","Key fingerprint calculation failed",{error:t.message}),new Error("Failed to compute the key fingerprint")}}static constantTimeCompare(e,t){let r=typeof e=="string"?e:JSON.stringify(e),i=typeof t=="string"?t:JSON.stringify(t);if(r.length!==i.length){let a=0;for(let o=0;oa.toLowerCase()===t);if(r)return r;let i=t.split("-")[0],n=Ke.find(a=>a.toLowerCase().split("-")[0]===i);if(n)return n}return null}function Xs({pathname:s="/",stored:e=null,languages:t=[]}={}){let r=Bi(s);return r||(Qs(s)?"en":e&&Ke.includes(e)?e:Ys(t)||"en")}function Qs(s){return s==="/"||s==="/index.html"}function Js(s,e="/"){let t=Bi(e),i=(t?String(e).slice(t.length+1):String(e)).replace(/^\/+/,"");return s==="en"?`/${i}`:`/${s}/${i}`}function Hi(s){try{localStorage.setItem(Vi,s)}catch{}}function Zs(){try{return localStorage.getItem(Vi)}catch{return null}}var Lt=null;function Ge(){if(Lt)return Lt;let s=typeof window>"u"?null:window;return!s||!s.location?"en":(Lt=Xs({pathname:s.location.pathname||"/",stored:Zs(),languages:s.navigator?.languages||[]}),Lt)}function ea(s=Ge()){return it[s]?.dir==="rtl"?"rtl":"ltr"}function Pt(s=Ge()){return ea(s)==="rtl"}function $i(s=Ge()){return Pt(s)?-1:1}function Oe(s,e=Ge()){let t=Dt(e)?.[s]??Dt("en")?.[s];return Array.isArray(t)?t:[]}function Gi({pathname:s="/",active:e="en"}={}){return Ke.map(t=>({code:t,href:Js(t,s),hrefLang:it[t]?.htmlLang||t,label:it[t]?.nativeName||t,abbr:it[t]?.abbr||t.toUpperCase(),dir:it[t]?.dir||"ltr",isCurrent:t===e}))}function f(s,e,t=Ge()){let r=Dt(t)?.[s]??zi[t]?.[s]??Dt("en")?.[s]??s;return e?String(r).replace(/\{(\w+)\}/g,(i,n)=>Object.prototype.hasOwnProperty.call(e,n)?String(e[n]):i):r}var Ie=class s{static#e=null;static#n=Symbol("SecureFileTransferContext");static getInstance(){return this.#e||(this.#e=new s),this.#e}#t=null;#r=!1;#i="high";setFileTransferSystem(e){if(!(e instanceof je))throw new Error("Invalid file transfer system instance");this.#t=e,this.#r=!0}getFileTransferSystem(){return this.#t}isActive(){return this.#r&&this.#t!==null}deactivate(){this.#r=!1,this.#t=null}getSecurityLevel(){return this.#i}setSecurityLevel(e){["low","medium","high"].includes(e)&&(this.#i=e)}},ee=class{static#e=new Set(["File size exceeds maximum limit","Unsupported file type","Transfer timeout","Connection lost","Invalid file data","File transfer failed","Transfer cancelled","Network error","File not found","Permission denied"]);static sanitizeError(e){let t=e.message||e;for(let r of this.#e)if(t.includes(r))return r;return console.error("\u{1F512} Internal file transfer error:",{message:e.message,stack:e.stack,timestamp:new Date().toISOString()}),"File transfer failed"}static logSecurityEvent(e,t={}){console.warn("\u{1F512} Security event:",{event:e,timestamp:new Date().toISOString(),...t})}},Ft=class{static async signFileMetadata(e,t){try{let i=new TextEncoder().encode(JSON.stringify({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,fileHash:e.fileHash,timestamp:e.timestamp,version:e.version||"2.0"})),n=await crypto.subtle.sign("RSASSA-PKCS1-v1_5",t,i);return Array.from(new Uint8Array(n))}catch(r){throw ee.logSecurityEvent("signature_failed",{error:r.message}),new Error("Failed to sign file metadata")}}static async verifyFileMetadata(e,t,r){try{let n=new TextEncoder().encode(JSON.stringify({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,fileHash:e.fileHash,timestamp:e.timestamp,version:e.version||"2.0"})),a=new Uint8Array(t),o=await crypto.subtle.verify("RSASSA-PKCS1-v1_5",r,a,n);return o||ee.logSecurityEvent("invalid_signature",{fileId:e.fileId}),o}catch(i){return ee.logSecurityEvent("verification_failed",{error:i.message}),!1}}},Kt=class{static MAX_MESSAGE_SIZE=1024*1024;static isMessageSizeValid(e){let t=JSON.stringify(e),r=new Blob([t]).size;if(r>this.MAX_MESSAGE_SIZE)throw ee.logSecurityEvent("message_too_large",{size:r,limit:this.MAX_MESSAGE_SIZE}),new Error("Message too large");return!0}},vr=class{constructor(){this.locks=new Map}async withLock(e,t){for(;this.locks.has(e);)await this.locks.get(e);let r,i=new Promise(n=>{r=n});this.locks.set(e,i);try{return await t()}finally{this.locks.delete(e),r()}}},nt=class{constructor(e,t){this.maxRequests=e,this.windowMs=t,this.requests=new Map}isAllowed(e){let t=Date.now(),r=t-this.windowMs;this.requests.has(e)||this.requests.set(e,[]);let n=this.requests.get(e).filter(a=>a>r);return this.requests.set(e,n),n.length>=this.maxRequests?(ee.logSecurityEvent("rate_limit_exceeded",{identifier:e,requestCount:n.length,limit:this.maxRequests}),!1):(n.push(t),!0)}},qe=class{static secureWipe(e){if(e instanceof ArrayBuffer){let t=new Uint8Array(e);crypto.getRandomValues(t)}else e instanceof Uint8Array&&crypto.getRandomValues(e)}static secureDelete(e,t){e[t]&&(this.secureWipe(e[t]),delete e[t])}},je=class{constructor(e,t,r,i,n,a){if(this.webrtcManager=e,this.onProgress=t,this.onComplete=r,this.onError=i,this.onFileReceived=n,this.onIncomingFileRequest=a,!e)throw new Error("webrtcManager is required for EnhancedSecureFileTransfer");Ie.getInstance().setFileTransferSystem(this),this.atomicOps=new vr,this.rateLimiter=new nt(10,6e4),this.signingKey=null,this.verificationKey=null,this.CHUNK_SIZE=16*1024,this.MAX_RECEIVE_CHUNK_SIZE=64*1024,this.MAX_FILE_SIZE=100*1024*1024,this.MAX_CONCURRENT_TRANSFERS=3,this.CHUNK_TIMEOUT=3e4,this.RETRY_ATTEMPTS=3,this.FILE_TYPE_RESTRICTIONS={pdf:{extensions:[".pdf"],mimeTypes:["application/pdf","application/x-pdf","application/acrobat"],maxSize:50*1024*1024,category:"PDF",description:"PDF"},text:{extensions:[".txt"],mimeTypes:["text/plain","application/txt"],maxSize:10*1024*1024,category:f("fileType.text"),description:"TXT"},images:{extensions:[".jpg",".jpeg",".png",".gif",".webp",".bmp",".ico"],mimeTypes:["image/jpeg","image/jpg","image/pjpeg","image/png","image/gif","image/webp","image/bmp","image/x-windows-bmp","image/x-icon","image/vnd.microsoft.icon"],maxSize:25*1024*1024,category:f("fileType.images"),description:"JPG, JPEG, PNG, GIF, WEBP, BMP, ICO"},archives:{extensions:[".zip"],mimeTypes:["application/zip","application/x-zip","application/x-zip-compressed","multipart/x-zip"],maxSize:100*1024*1024,category:f("fileType.archives"),description:"ZIP"},voice:{extensions:[".webm",".ogg",".oga",".opus",".m4a",".mp4",".mp3",".wav"],mimeTypes:["audio/webm","audio/ogg","audio/opus","audio/mp4","audio/mpeg","audio/mp3","audio/wav","audio/x-m4a","audio/aac"],maxSize:20*1024*1024,category:"Voice",description:f("fileType.voice")}},this.BLOCKED_EXTENSIONS=new Set([".exe",".bat",".cmd",".sh",".js",".msi",".dmg",".app",".jar",".scr",".ps1",".vbs",".html",".svg"]),this._genericMimeTypes=new Set(["application/octet-stream","application/binary"]),this._allowedMimeTypes=new Set;for(let o of Object.values(this.FILE_TYPE_RESTRICTIONS))for(let c of o.mimeTypes)this._allowedMimeTypes.add(c);this.activeTransfers=new Map,this.receivingTransfers=new Map,this.pendingIncomingTransfers=new Map,this.transferQueue=[],this.pendingChunks=new Map,this.incomingOfferLimiter=new nt(5,6e4),this.incomingChunkLimiter=new nt(6e4,6e4),this.incomingTransferChunkLimiters=new Map,this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE=3e4,this.MAX_PENDING_INCOMING_TRANSFERS=3,this.MAX_AUTO_ACCEPT_VOICE_SIZE=4*1024*1024,this.MAX_AUTO_ACCEPT_VOICE_SESSION_BYTES=64*1024*1024,this.autoAcceptedVoiceBytes=0,this.sessionKeys=new Map,this.processedChunks=new Set,this.transferNonces=new Map,this.receivedFileBuffers=new Map,this.MAX_RETAINED_RECEIVED_FILE_BUFFERS=3,this.setupFileMessageHandlers(),this.webrtcManager&&(this.webrtcManager.fileTransferSystem=this)}getFileType(e){let t=String(e?.name||"").toLowerCase(),r=t.lastIndexOf("."),i=r>=0?t.substring(r):"",n=String(e?.type||"").toLowerCase();for(let[a,o]of Object.entries(this.FILE_TYPE_RESTRICTIONS)){if(!o.extensions.includes(i))continue;if(!n||this._genericMimeTypes.has(n)||this._allowedMimeTypes.has(n))return{type:a,category:o.category,description:o.description,maxSize:o.maxSize,allowed:!0,extension:i,mimeType:n}}return{type:"blocked",category:f("fileType.unsupported"),description:"Allowed: JPG, JPEG, PNG, GIF, WEBP, BMP, ICO, PDF, TXT, ZIP",maxSize:this.MAX_FILE_SIZE,allowed:!1,extension:i,mimeType:n}}validateFile(e){let t=this.getFileType(e),r=[],n=String(e?.name||"").toLowerCase(),a=n.lastIndexOf("."),o=a>=0?n.substring(a):"";return this.BLOCKED_EXTENSIONS.has(o)&&r.push(`File rejected: ${o} files are not allowed for security reasons.`),e.size>t.maxSize&&r.push(`File size (${this.formatFileSize(e.size)}) exceeds maximum allowed for ${t.category} (${this.formatFileSize(t.maxSize)})`),!t.allowed&&!this.BLOCKED_EXTENSIONS.has(o)&&r.push(`File rejected: unsupported file type. Supported types: ${t.description}`),e.size>this.MAX_FILE_SIZE&&r.push(`File size (${this.formatFileSize(e.size)}) exceeds general limit (${this.formatFileSize(this.MAX_FILE_SIZE)})`),{isValid:r.length===0,errors:r,fileType:t,fileSize:e.size,formattedSize:this.formatFileSize(e.size)}}normalizeDisplayFileName(e){return String(e||"").normalize("NFKC").replace(/[\u0000-\u001F\u007F]/g,"").replace(/[\\/]+/g,"_").trim().slice(0,255)}validateIncomingMetadata(e){let t=[];(!e||typeof e!="object")&&t.push("Invalid file transfer metadata"),(!e?.fileId||typeof e.fileId!="string")&&t.push("Invalid file id"),(!Number.isSafeInteger(e?.fileSize)||e.fileSize<=0)&&t.push("Invalid file size"),(!Number.isSafeInteger(e?.totalChunks)||e.totalChunks<=0)&&t.push("Invalid chunk count"),(!Number.isSafeInteger(e?.chunkSize)||e.chunkSize<=0||e.chunkSize>this.MAX_RECEIVE_CHUNK_SIZE)&&t.push("Invalid chunk size"),(!Array.isArray(e?.salt)||e.salt.length!==32)&&t.push("Invalid salt");let r=typeof e?.fileName=="string"?e.fileName:"",i=this.normalizeDisplayFileName(r);if((!r||r!==r.trim()||/[\u0000-\u001F\u007F]/.test(r)||/[\\/]/.test(r)||r==="."||r===".."||i.length===0)&&t.push("Dangerous file name"),t.length===0){let c=this.validateFile({name:i,size:e.fileSize,type:e.fileType||"application/octet-stream"});c.isValid||t.push(...c.errors)}let a=!!e?.isVoice,o=a?this.rejectVoiceAutoAcceptReason(e):null;return{isValid:t.length===0,errors:t,displayName:i,isVoice:a&&!o,voiceRejection:o}}rejectVoiceAutoAcceptReason(e){let t=String(e?.fileType||"").toLowerCase(),r=e?.fileSize;return t.startsWith("audio/")?this.FILE_TYPE_RESTRICTIONS.voice.mimeTypes.includes(t)?!Number.isSafeInteger(r)||r<=0||r>this.MAX_AUTO_ACCEPT_VOICE_SIZE?`too large to auto-accept (${this.formatFileSize(r||0)} > ${this.formatFileSize(this.MAX_AUTO_ACCEPT_VOICE_SIZE)})`:this.autoAcceptedVoiceBytes+r>this.MAX_AUTO_ACCEPT_VOICE_SESSION_BYTES?"session auto-accept budget for voice notes is exhausted":null:`unsupported audio MIME type (${t})`:`not an audio MIME type (${t||"absent"})`}formatFileSize(e){if(e===0)return"0 B";let t=1024,r=["B","KB","MB","GB"],i=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,i)).toFixed(2))+" "+r[i]}getSupportedFileTypes(){let e={};for(let[t,r]of Object.entries(this.FILE_TYPE_RESTRICTIONS))e[t]={category:r.category,description:r.description,extensions:r.extensions,maxSize:this.formatFileSize(r.maxSize),maxSizeBytes:r.maxSize};return e}getFileTypeInfo(){return{supportedTypes:this.getSupportedFileTypes(),generalMaxSize:this.formatFileSize(this.MAX_FILE_SIZE),generalMaxSizeBytes:this.MAX_FILE_SIZE,restrictions:this.FILE_TYPE_RESTRICTIONS}}arrayBufferToBase64(e){let t=e instanceof Uint8Array?e:new Uint8Array(e),r="",i=t.byteLength;for(let n=0;n{this.webrtcManager.dataChannel&&(clearInterval(e),this.setupMessageInterception())},100);setTimeout(()=>{clearInterval(e)},5e3);return}this.setupMessageInterception()}setupMessageInterception(){try{if(!this.webrtcManager.dataChannel)return;this.webrtcManager&&(this.webrtcManager.fileTransferSystem=this),this.webrtcManager.dataChannel.onmessage&&(this.originalOnMessage=this.webrtcManager.dataChannel.onmessage),this.webrtcManager.dataChannel.onmessage=async e=>{try{if(e.data.length>Kt.MAX_MESSAGE_SIZE){console.warn("\u{1F512} Message too large, ignoring"),ee.logSecurityEvent("oversized_message_blocked");return}if(typeof e.data=="string")try{let t=JSON.parse(e.data);if(Kt.isMessageSizeValid(t),this.isFileTransferMessage(t)){await this.handleFileMessage(t);return}}catch(t){if(t.message==="Message too large")return}if(this.originalOnMessage)return this.originalOnMessage.call(this.webrtcManager.dataChannel,e)}catch(t){if(console.error("\u274C Error in file system message interception:",t),this.originalOnMessage)return this.originalOnMessage.call(this.webrtcManager.dataChannel,e)}}}catch(e){console.error("\u274C Failed to set up message interception:",e)}}isFileTransferMessage(e){return!e||typeof e!="object"||!e.type?!1:["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_chunk_request","file_transfer_complete","file_transfer_error"].includes(e.type)}async handleFileMessage(e){try{if(!this.webrtcManager.fileTransferSystem)try{if(typeof this.webrtcManager.initializeFileTransfer=="function"){this.webrtcManager.initializeFileTransfer();let t=0,r=50;for(;!this.webrtcManager.fileTransferSystem&&tsetTimeout(i,100)),t++;if(!this.webrtcManager.fileTransferSystem)throw new Error("File transfer system initialization timeout")}else throw new Error("initializeFileTransfer method not available")}catch(t){if(console.error("\u274C Failed to initialize file transfer system:",t),e.fileId){let r={type:"file_transfer_error",fileId:e.fileId,error:"File transfer system not available",timestamp:Date.now()};await this.sendSecureMessage(r)}return}switch(e.type){case"file_transfer_start":await this.handleFileTransferStart(e);break;case"file_transfer_response":this.handleTransferResponse(e);break;case"file_chunk":await this.handleFileChunk(e);break;case"chunk_confirmation":this.handleChunkConfirmation(e);break;case"file_chunk_request":await this.handleChunkRequest(e);break;case"file_transfer_complete":this.handleTransferComplete(e);break;case"file_transfer_error":this.handleTransferError(e);break;default:console.warn("\u26A0\uFE0F Unknown file message type:",e.type)}}catch(t){if(console.error("\u274C Error handling file message:",t),e.fileId){let r={type:"file_transfer_error",fileId:e.fileId,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(r)}}}async deriveFileSessionKey(e){try{if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("WebRTC session data not available");let t=crypto.getRandomValues(new Uint8Array(32)),r=new TextEncoder,i=r.encode(this.webrtcManager.keyFingerprint),n=r.encode(e),a=new Uint8Array(this.webrtcManager.sessionSalt),o=new Uint8Array(i.length+a.length+t.length+n.length),c=0;o.set(i,c),c+=i.length,o.set(a,c),c+=a.length,o.set(t,c),c+=t.length,o.set(n,c);let d=await crypto.subtle.digest("SHA-256",o),u=await crypto.subtle.importKey("raw",d,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return this.sessionKeys.set(e,{key:u,salt:Array.from(t),created:Date.now()}),{key:u,salt:Array.from(t)}}catch(t){throw console.error("\u274C Failed to derive file session key:",t),t}}async deriveFileSessionKeyFromSalt(e,t){try{if(!t||!Array.isArray(t)||t.length!==32)throw new Error(`Invalid salt: ${t?.length||0} bytes`);if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("WebRTC session data not available");let r=new TextEncoder,i=r.encode(this.webrtcManager.keyFingerprint),n=r.encode(e),a=new Uint8Array(t),o=new Uint8Array(this.webrtcManager.sessionSalt),c=new Uint8Array(i.length+o.length+a.length+n.length),d=0;c.set(i,d),d+=i.length,c.set(o,d),d+=o.length,c.set(a,d),d+=a.length,c.set(n,d);let u=await crypto.subtle.digest("SHA-256",c),h=await crypto.subtle.importKey("raw",u,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return this.sessionKeys.set(e,{key:h,salt:t,created:Date.now()}),h}catch(r){throw console.error("\u274C Failed to derive session key from salt:",r),r}}_emitTransferProgress(e,t){if(typeof this.onProgress!="function"||!e)return;let r=e.totalChunks||0,i=t==="up"?e.sentChunks||0:e.receivedCount||0,n=r>0?Math.min(100,Math.round(i/r*100)):0;try{this.onProgress({fileId:e.fileId,uiId:e.uiId||null,direction:t,progress:n,transferredChunks:i,totalChunks:r,isVoice:!!e.isVoice,voice:e.voice||null})}catch{}}async sendFile(e,t={}){try{if(!this.webrtcManager)throw new Error("WebRTC Manager not initialized");let r=this.getClientIdentifier();if(!this.rateLimiter.isAllowed(r))throw ee.logSecurityEvent("rate_limit_exceeded",{clientId:r}),new Error("Rate limit exceeded. Please wait before sending another file.");if(!e||!e.size)throw new Error("Invalid file object");let i=this.validateFile(e);if(!i.isValid){let m=i.errors.join(". ");throw new Error(m)}if(this.activeTransfers.size>=this.MAX_CONCURRENT_TRANSFERS)throw new Error("Maximum concurrent transfers reached");let n=`file_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,a=await this.calculateFileHash(e),o=await this.deriveFileSessionKey(n),c=o.key,d=o.salt,u={fileId:n,file:e,fileHash:a,sessionKey:c,salt:d,totalChunks:Math.ceil(e.size/this.CHUNK_SIZE),sentChunks:0,confirmedChunks:0,startTime:Date.now(),status:"preparing",retryCount:0,lastChunkTime:Date.now(),isVoice:!!(t&&t.voice),voice:t&&t.voice?t.voice:null,uiId:t&&t.uiId?t.uiId:null};this.activeTransfers.set(n,u),this.transferNonces.set(n,0);let h=new Promise((m,p)=>{u.resolveConsent=m,u.rejectConsent=p,u.consentTimeout=setTimeout(()=>{u.consentTimeout=null,p(new Error("Transfer timeout"))},3e4)});return await this.sendFileMetadata(u),await h,await this.startChunkTransmission(u),n}catch(r){let i=ee.sanitizeError(r);throw console.error("\u274C File sending failed:",i),this.onError&&this.onError(i),new Error(i)}}async sendFileMetadata(e){try{let t={type:"file_transfer_start",fileId:e.fileId,fileName:e.file.name,fileSize:e.file.size,fileType:e.file.type||"application/octet-stream",fileHash:e.fileHash,totalChunks:e.totalChunks,chunkSize:this.CHUNK_SIZE,salt:e.salt,timestamp:Date.now(),version:"2.0"};if(e.isVoice&&(t.isVoice=!0,e.voice&&(t.voice=e.voice)),this.signingKey)try{t.signature=await Ft.signFileMetadata(t,this.signingKey),console.log("\u{1F512} File metadata signed successfully")}catch(r){ee.logSecurityEvent("signature_failed",{fileId:e.fileId,error:r.message})}await this.sendSecureMessage(t),e.status="metadata_sent"}catch(t){let r=ee.sanitizeError(t);throw console.error("\u274C Failed to send file metadata:",r),e.status="failed",new Error(r)}}async startChunkTransmission(e){try{e.status="transmitting";let t=e.file,r=e.totalChunks;for(let i=0;i{let r=this.activeTransfers.get(e.fileId);r&&r.status!=="completed"&&this.cleanupTransfer(e.fileId)},18e4)}async handleChunkRequest(e){let t=this.activeTransfers.get(e?.fileId);if(!t||!t.file)return;let r=Array.isArray(e.missing)?e.missing:[];if(r.length===0)return;this._armSenderIdleTimeout(t),t.status="transmitting";let n=r.slice(0,512);for(let a of n)if(!(!Number.isInteger(a)||a<0||a>=t.totalChunks))try{let o=a*this.CHUNK_SIZE,c=Math.min(o+this.CHUNK_SIZE,t.file.size),d=await this.readFileChunk(t.file,o,c);await this.sendFileChunk(t,a,d),await this.waitForBackpressure()}catch(o){console.warn("\u26A0\uFE0F Failed to retransmit chunk",a,ee.sanitizeError(o))}t.status==="transmitting"&&(t.status="waiting_confirmation"),this._armSenderIdleTimeout(t)}async readFileChunk(e,t,r){try{return await e.slice(t,r).arrayBuffer()}catch(i){let n=ee.sanitizeError(i);throw console.error("\u274C Failed to read file chunk:",n),new Error(n)}}async sendFileChunk(e,t,r){try{let i=e.sessionKey,n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},i,r),o=this.arrayBufferToBase64(new Uint8Array(a)),c={type:"file_chunk",fileId:e.fileId,chunkIndex:t,totalChunks:e.totalChunks,nonce:Array.from(n),encryptedDataB64:o,chunkSize:r.byteLength,timestamp:Date.now()};await this.waitForBackpressure(),await this.sendSecureMessage(c)}catch(i){let n=ee.sanitizeError(i);throw console.error("\u274C Failed to send file chunk:",n),new Error(n)}}async sendSecureMessage(e){let t=JSON.stringify(e),r=this.webrtcManager?.dataChannel,i=10,n=0,a=o=>new Promise(c=>setTimeout(c,o));for(;;)try{if(!r||r.readyState!=="open")throw new Error("Data channel not ready");await this.waitForBackpressure(),r.send(t);return}catch(o){let c=String(o?.message||""),d=c.includes("send queue is full")||c.includes("bufferedAmount"),u=o?.name==="OperationError";if((d||u)&&ne.bufferedAmountLowThreshold&&await new Promise(r=>{let i=()=>{e.removeEventListener("bufferedamountlow",i),r()};e.addEventListener("bufferedamountlow",i,{once:!0})});return}let t=4*1024*1024;for(;e.bufferedAmount>t;)await new Promise(r=>setTimeout(r,20))}catch{}}async calculateFileHash(e){try{let t=await e.arrayBuffer(),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(n=>n.toString(16).padStart(2,"0")).join("")}catch(t){throw console.error("\u274C File hash calculation failed:",t),t}}async handleFileTransferStart(e){try{let t=this.getClientIdentifier();if(!this.incomingOfferLimiter.isAllowed(t))throw new Error("Incoming file request rate limit exceeded");let r=this.validateIncomingMetadata(e);if(!r.isValid)throw new Error(r.errors.join(". "));if(e.signature&&this.verificationKey)try{if(!await Ft.verifyFileMetadata(e,e.signature,this.verificationKey))throw ee.logSecurityEvent("invalid_metadata_signature",{fileId:e.fileId}),new Error("Invalid file metadata signature");console.log("\u{1F512} File metadata signature verified successfully")}catch(n){throw ee.logSecurityEvent("verification_failed",{fileId:e.fileId,error:n.message}),new Error("File metadata verification failed")}if(this.receivingTransfers.has(e.fileId)||this.pendingIncomingTransfers.has(e.fileId))return;if(this.pendingIncomingTransfers.size>=this.MAX_PENDING_INCOMING_TRANSFERS)throw new Error("Too many pending incoming file requests");r.voiceRejection&&console.warn(`Voice auto-accept declined, falling back to consent: ${r.voiceRejection}`);let i={...e,isVoice:r.isVoice,fileName:r.displayName,receivedAt:Date.now()};this.pendingIncomingTransfers.set(e.fileId,i),r.isVoice&&(this.autoAcceptedVoiceBytes+=e.fileSize),typeof this.onIncomingFileRequest=="function"?this.onIncomingFileRequest({fileId:i.fileId,fileName:i.fileName,fileSize:i.fileSize,mimeType:i.fileType||"application/octet-stream",isVoice:r.isVoice,voice:i.voice||null}):await this.rejectIncomingFile(e.fileId,f("file.consentUnavailable"))}catch(t){let r=ee.sanitizeError(t);console.error("\u274C Failed to handle file transfer start:",r);let i={type:"file_transfer_response",fileId:e.fileId,accepted:!1,error:r,timestamp:Date.now()};await this.sendSecureMessage(i)}}async handleFileChunk(e){return this.atomicOps.withLock(`chunk-${e.fileId}`,async()=>{try{let t=this.receivingTransfers.get(e.fileId);if(!t||t._assembled||t.status==="completed")return;if(!this._isIncomingChunkAllowed(e.fileId)){console.warn("\u26A0\uFE0F Incoming file chunk rate limit exceeded; cleaning up transfer:",e.fileId),this.cleanupReceivingTransfer(e.fileId);return}if(t.lastChunkTime=Date.now(),t.receivedChunks.has(e.chunkIndex))return;if(e.chunkIndex<0||e.chunkIndex>=t.totalChunks)throw new Error(`Invalid chunk index: ${e.chunkIndex}`);let r=new Uint8Array(e.nonce),i;if(e.encryptedDataB64)i=this.base64ToUint8Array(e.encryptedDataB64);else if(e.encryptedData)i=new Uint8Array(e.encryptedData);else throw new Error("Missing encrypted data");let n=await crypto.subtle.decrypt({name:"AES-GCM",iv:r},t.sessionKey,i);if(n.byteLength!==e.chunkSize)throw new Error(`Chunk size mismatch: expected ${e.chunkSize}, got ${n.byteLength}`);t.receivedChunks.set(e.chunkIndex,n),t.receivedCount++,this._emitTransferProgress(t,"down");let a={type:"chunk_confirmation",fileId:e.fileId,chunkIndex:e.chunkIndex,timestamp:Date.now()};await this.sendSecureMessage(a),t.receivedCount===t.totalChunks&&await this.assembleFile(t)}catch(t){let r=ee.sanitizeError(t);console.warn("\u26A0\uFE0F Dropping unprocessable file chunk (will be re-requested):",e.chunkIndex,r)}})}_isIncomingChunkAllowed(e){let t=this.getClientIdentifier();return this.incomingChunkLimiter.isAllowed(t)?(this.incomingTransferChunkLimiters.has(e)||this.incomingTransferChunkLimiters.set(e,new nt(this.MAX_INCOMING_CHUNKS_PER_TRANSFER_PER_MINUTE,6e4)),this.incomingTransferChunkLimiters.get(e).isAllowed(e)?!0:(ee.logSecurityEvent("incoming_chunk_transfer_rate_limit_exceeded",{clientId:t,fileId:e}),!1)):(ee.logSecurityEvent("incoming_chunk_aggregate_rate_limit_exceeded",{clientId:t,fileId:e}),!1)}async assembleFile(e){if(!e._assembled){e._assembled=!0;try{e.status="assembling";for(let u=0;uu+h.length,0);if(r!==e.fileSize)throw new Error(`File size mismatch: expected ${e.fileSize}, got ${r}`);let i=new Uint8Array(r),n=0;for(let u of t)i.set(u,n),n+=u.length;if(await this.calculateFileHashFromData(i)!==e.fileHash)throw new Error("File integrity check failed - hash mismatch");let o=i.buffer,c=new Blob([o],{type:e.fileType});if(e.endTime=Date.now(),e.status="completed",this._storeReceivedFileBuffer(e.fileId,{buffer:o,type:e.fileType,name:e.fileName,size:e.fileSize}),this.onFileReceived){let u=async()=>{let p=await this.getBlob(e.fileId);if(!p)throw new Error("This file is no longer available for download.");return p},h=async()=>{let p=await u();return URL.createObjectURL(p)},m=p=>{try{URL.revokeObjectURL(p)}catch{}};this.onFileReceived({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,mimeType:e.fileType,transferTime:e.endTime-e.startTime,isVoice:!!e.isVoice,voice:e.voice||null,fileBlob:c,getBlob:u,getObjectURL:h,revokeObjectURL:m})}let d={type:"file_transfer_complete",fileId:e.fileId,success:!0,timestamp:Date.now()};await this.sendSecureMessage(d),e._stallTimer&&(clearInterval(e._stallTimer),e._stallTimer=null),e.receivedChunks&&e.receivedChunks.clear(),e.sessionKey=null}catch(t){console.error("\u274C File assembly failed:",t),e.status="failed",this.onError&&this.onError(`File assembly failed: ${t.message}`);let r={type:"file_transfer_complete",fileId:e.fileId,success:!1,error:t.message,timestamp:Date.now()};await this.sendSecureMessage(r),this.cleanupReceivingTransfer(e.fileId)}}}async calculateFileHashFromData(e){try{let t=await crypto.subtle.digest("SHA-256",e);return Array.from(new Uint8Array(t)).map(i=>i.toString(16).padStart(2,"0")).join("")}catch(t){throw console.error("\u274C Hash calculation failed:",t),t}}handleTransferResponse(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;e.accepted?(t.status="accepted",t.consentTimeout&&clearTimeout(t.consentTimeout),t.consentTimeout=null,t.resolveConsent?.(),t.resolveConsent=null,t.rejectConsent=null):(t.status="rejected",t.consentTimeout&&clearTimeout(t.consentTimeout),t.consentTimeout=null,t.rejectConsent?.(new Error(e.error||"Transfer rejected")),t.rejectConsent=null,t.resolveConsent=null,this.onError&&this.onError(`Transfer rejected: ${e.error||"Unknown reason"}`),this.cleanupTransfer(e.fileId))}catch(t){console.error("\u274C Failed to handle transfer response:",t)}}handleChunkConfirmation(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;t.confirmedChunks++,t.lastChunkTime=Date.now(),t.status==="waiting_confirmation"&&this._armSenderIdleTimeout(t)}catch(t){console.error("\u274C Failed to handle chunk confirmation:",t)}}handleTransferComplete(e){try{let t=this.activeTransfers.get(e.fileId);if(!t)return;e.success?(t.status="completed",t.endTime=Date.now(),this.onComplete&&this.onComplete({fileId:t.fileId,fileName:t.file.name,fileSize:t.file.size,transferTime:t.endTime-t.startTime,status:"completed"})):(t.status="failed",this.onError&&this.onError(`Transfer failed: ${e.error||"Unknown error"}`)),this.cleanupTransfer(e.fileId)}catch(t){console.error("\u274C Failed to handle transfer completion:",t)}}handleTransferError(e){try{let t=this.activeTransfers.get(e.fileId);t&&(t.status="failed",this.cleanupTransfer(e.fileId));let r=this.receivingTransfers.get(e.fileId);r&&(r.status="failed",this.cleanupReceivingTransfer(e.fileId)),this.onError&&this.onError(`Transfer error: ${e.error||"Unknown error"}`)}catch(t){console.error("\u274C Failed to handle transfer error:",t)}}getActiveTransfers(){return Array.from(this.activeTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.file?.name||"Unknown",fileSize:e.file?.size||0,progress:Math.round(e.sentChunks/e.totalChunks*100),totalChunks:e.totalChunks||0,transferredChunks:e.sentChunks||0,status:e.status,startTime:e.startTime}))}getReceivingTransfers(){return Array.from(this.receivingTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.fileName||"Unknown",fileSize:e.fileSize||0,progress:Math.round(e.receivedCount/e.totalChunks*100),totalChunks:e.totalChunks||0,transferredChunks:e.receivedCount||0,status:e.status,startTime:e.startTime}))}getPendingIncomingTransfers(){return Array.from(this.pendingIncomingTransfers.values()).map(e=>({fileId:e.fileId,fileName:e.fileName,fileSize:e.fileSize,mimeType:e.fileType||"application/octet-stream",receivedAt:e.receivedAt}))}async acceptIncomingFile(e){let t=this.pendingIncomingTransfers.get(e);if(!t)return!1;let r=await this.deriveFileSessionKeyFromSalt(e,t.salt);return this.receivingTransfers.set(e,{fileId:e,fileName:t.fileName,fileSize:t.fileSize,fileType:t.fileType||"application/octet-stream",fileHash:t.fileHash,totalChunks:t.totalChunks,chunkSize:t.chunkSize||this.CHUNK_SIZE,sessionKey:r,salt:t.salt,receivedChunks:new Map,receivedCount:0,startTime:Date.now(),lastChunkTime:Date.now(),status:"receiving",isVoice:!!t.isVoice,voice:t.voice||null}),this.pendingIncomingTransfers.delete(e),await this.sendSecureMessage({type:"file_transfer_response",fileId:e,accepted:!0,timestamp:Date.now()}),this._startReceiverStallDetector(e),!0}_startReceiverStallDetector(e){let n=this.receivingTransfers.get(e);n&&(n._stallTimer&&clearInterval(n._stallTimer),n._lastProgressCount=n.receivedCount||0,n._lastProgressTime=Date.now(),n._stallTimer=setInterval(async()=>{let a=this.receivingTransfers.get(e);if(!a||a._stallTimer!==n._stallTimer){clearInterval(n._stallTimer);return}if(a.status==="completed"||a._assembled){clearInterval(a._stallTimer),a._stallTimer=null;return}if(a.receivedCount!==a._lastProgressCount&&(a._lastProgressCount=a.receivedCount,a._lastProgressTime=Date.now()),!(a.receivedCount>=a.totalChunks)&&!(Date.now()-(a.lastChunkTime||0)<5e3)){if(Date.now()-a._lastProgressTime>18e4){clearInterval(a._stallTimer),a._stallTimer=null,a.status="failed",this.onError&&this.onError("File transfer stalled \u2014 no data received. Please try again."),this.cleanupReceivingTransfer(e);return}await this._requestMissingChunks(e)}},2500))}async _requestMissingChunks(e){let t=this.receivingTransfers.get(e);if(!t||!t.receivedChunks)return;let r=256,i=[];for(let n=0;nthis.MAX_RETAINED_RECEIVED_FILE_BUFFERS;){let r=this.receivedFileBuffers.keys().next().value;this._discardReceivedFileBuffer(r)}}_discardReceivedFileBuffer(e){let t=this.receivedFileBuffers.get(e);if(!t)return;try{t.buffer&&(qe.secureWipe(t.buffer),new Uint8Array(t.buffer).fill(0))}catch{}this.receivedFileBuffers.delete(e);let r=this.receivingTransfers.get(e);r&&(r.status==="completed"||r._assembled)&&(r._stallTimer&&(clearInterval(r._stallTimer),r._stallTimer=null),this.receivingTransfers.delete(e))}cleanupReceivingTransfer(e){try{this.pendingChunks.delete(e);let t=this.receivingTransfers.get(e);if(t){if(t._stallTimer&&(clearInterval(t._stallTimer),t._stallTimer=null),t.receivedChunks&&t.receivedChunks.size>0){for(let[n,a]of t.receivedChunks)try{a&&(a instanceof ArrayBuffer||a instanceof Uint8Array)&&(qe.secureWipe(a),a instanceof ArrayBuffer?new Uint8Array(a).fill(0):a instanceof Uint8Array&&a.fill(0))}catch(o){console.warn("\u26A0\uFE0F Failed to securely wipe chunk:",o)}t.receivedChunks.clear()}if(t.sessionKey)try{t.sessionKey=null}catch(n){console.warn("\u26A0\uFE0F Failed to clear session key:",n)}if(t.salt)try{Array.isArray(t.salt)&&t.salt.fill(0),t.salt=null}catch(n){console.warn("\u26A0\uFE0F Failed to clear salt:",n)}for(let[n,a]of Object.entries(t))a&&typeof a=="object"&&(a instanceof ArrayBuffer||a instanceof Uint8Array?qe.secureWipe(a):Array.isArray(a)&&a.fill(0),t[n]=null)}this.receivingTransfers.delete(e),this.sessionKeys.delete(e),this.incomingTransferChunkLimiters.delete(e);let r=this.receivedFileBuffers.get(e);if(r)try{r.buffer&&(qe.secureWipe(r.buffer),new Uint8Array(r.buffer).fill(0));for(let[n,a]of Object.entries(r))a&&typeof a=="object"&&((a instanceof ArrayBuffer||a instanceof Uint8Array)&&qe.secureWipe(a),r[n]=null);this.receivedFileBuffers.delete(e)}catch(n){console.warn("\u26A0\uFE0F Failed to securely clear file buffer:",n),this.receivedFileBuffers.delete(e)}let i=[];for(let n of this.processedChunks)n.startsWith(e)&&i.push(n);for(let n of i)this.processedChunks.delete(n);if(typeof global<"u"&&global.gc)try{global.gc()}catch{}console.log(`\u{1F512} Memory safely cleaned for file transfer: ${e}`)}catch(t){throw console.error("\u274C Error during secure memory cleanup:",t),this.receivingTransfers.delete(e),this.sessionKeys.delete(e),this.receivedFileBuffers.delete(e),this.pendingChunks.delete(e),new Error(`Memory cleanup failed: ${t.message}`)}}getTransferStatus(e){if(this.activeTransfers.has(e)){let t=this.activeTransfers.get(e);return{type:"sending",fileId:t.fileId,fileName:t.file.name,progress:Math.round(t.sentChunks/t.totalChunks*100),status:t.status,startTime:t.startTime}}if(this.receivingTransfers.has(e)){let t=this.receivingTransfers.get(e);return{type:"receiving",fileId:t.fileId,fileName:t.fileName,progress:Math.round(t.receivedCount/t.totalChunks*100),status:t.status,startTime:t.startTime}}return null}getSystemStatus(){return{initialized:!0,activeTransfers:this.activeTransfers.size,receivingTransfers:this.receivingTransfers.size,totalTransfers:this.activeTransfers.size+this.receivingTransfers.size,maxConcurrentTransfers:this.MAX_CONCURRENT_TRANSFERS,maxFileSize:this.MAX_FILE_SIZE,chunkSize:this.CHUNK_SIZE,hasWebrtcManager:!!this.webrtcManager,isConnected:this.webrtcManager?.isConnected?.()||!1,hasDataChannel:!!this.webrtcManager?.dataChannel,dataChannelState:this.webrtcManager?.dataChannel?.readyState,isVerified:this.webrtcManager?.isVerified,hasEncryptionKey:!!this.webrtcManager?.encryptionKey,hasMacKey:!!this.webrtcManager?.macKey,linkedToWebRTCManager:this.webrtcManager?.fileTransferSystem===this,supportedFileTypes:this.getSupportedFileTypes(),fileTypeInfo:this.getFileTypeInfo()}}cleanup(){Ie.getInstance().deactivate(),this.webrtcManager&&this.webrtcManager.dataChannel&&this.originalOnMessage&&(this.webrtcManager.dataChannel.onmessage=this.originalOnMessage,this.originalOnMessage=null),this.webrtcManager&&this.originalProcessMessage&&(this.webrtcManager.processMessage=this.originalProcessMessage,this.originalProcessMessage=null),this.webrtcManager&&this.originalRemoveSecurityLayers&&(this.webrtcManager.removeSecurityLayers=this.originalRemoveSecurityLayers,this.originalRemoveSecurityLayers=null);for(let e of this.activeTransfers.keys())this.cleanupTransfer(e);for(let e of this.receivingTransfers.keys())this.cleanupReceivingTransfer(e);this.atomicOps&&this.atomicOps.locks.clear(),this.rateLimiter&&this.rateLimiter.requests.clear(),this.incomingChunkLimiter&&this.incomingChunkLimiter.requests.clear(),this.incomingTransferChunkLimiters.clear(),this.pendingChunks.clear(),this.pendingIncomingTransfers.clear(),this.activeTransfers.clear(),this.receivingTransfers.clear(),this.transferQueue.length=0,this.sessionKeys.clear(),this.transferNonces.clear(),this.processedChunks.clear();for(let e of Array.from(this.receivedFileBuffers.keys()))this._discardReceivedFileBuffer(e);this.clearKeys()}onSessionUpdate(e){this.sessionKeys.clear()}diagnoseFileTransferIssue(){return{timestamp:new Date().toISOString(),fileTransferSystem:{initialized:!!this,hasWebrtcManager:!!this.webrtcManager,webrtcManagerType:this.webrtcManager?.constructor?.name,linkedToWebRTCManager:this.webrtcManager?.fileTransferSystem===this},webrtcManager:{hasDataChannel:!!this.webrtcManager?.dataChannel,dataChannelState:this.webrtcManager?.dataChannel?.readyState,isConnected:this.webrtcManager?.isConnected?.()||!1,isVerified:this.webrtcManager?.isVerified,hasEncryptionKey:!!this.webrtcManager?.encryptionKey,hasMacKey:!!this.webrtcManager?.macKey,hasKeyFingerprint:!!this.webrtcManager?.keyFingerprint,hasSessionSalt:!!this.webrtcManager?.sessionSalt},securityContext:{contextActive:Ie.getInstance().isActive(),securityLevel:Ie.getInstance().getSecurityLevel(),hasAtomicOps:!!this.atomicOps,hasRateLimiter:!!this.rateLimiter},transfers:{activeTransfers:this.activeTransfers.size,receivingTransfers:this.receivingTransfers.size,pendingChunks:this.pendingChunks.size,sessionKeys:this.sessionKeys.size},fileTypeSupport:{supportedTypes:this.getSupportedFileTypes(),generalMaxSize:this.formatFileSize(this.MAX_FILE_SIZE),restrictions:Object.keys(this.FILE_TYPE_RESTRICTIONS)}}}async debugKeyDerivation(e){try{if(!this.webrtcManager.keyFingerprint||!this.webrtcManager.sessionSalt)throw new Error("Session data not available");let t=await this.deriveFileSessionKey(e),r=await this.deriveFileSessionKeyFromSalt(e,t.salt),i=new TextEncoder().encode("test data"),n=crypto.getRandomValues(new Uint8Array(12)),a=await crypto.subtle.encrypt({name:"AES-GCM",iv:n},t.key,i),o=await crypto.subtle.decrypt({name:"AES-GCM",iv:n},r,a);if(new TextDecoder().decode(o)==="test data")return{success:!0,message:"All tests passed"};throw new Error("Decryption verification failed")}catch(t){return console.error("\u274C Key derivation test failed:",t),{success:!1,error:t.message}}}registerWithWebRTCManager(){if(!this.webrtcManager)throw new Error("WebRTC manager not available");this.webrtcManager.fileTransferSystem=this,this.webrtcManager.setFileMessageHandler=e=>{this.webrtcManager._fileMessageHandler=e},this.webrtcManager.setFileMessageHandler(e=>this.handleFileMessage(e))}static createFileMessageFilter(e){return async t=>{try{if(typeof t.data=="string"){let r=JSON.parse(t.data);if(e.isFileTransferMessage(r))return await e.handleFileMessage(r),!0}}catch{}return!1}}setSigningKey(e){if(!e||!(e instanceof CryptoKey))throw new Error("Invalid private key for signing");this.signingKey=e,console.log("\u{1F512} Signing key set successfully")}setVerificationKey(e){if(!e||!(e instanceof CryptoKey))throw new Error("Invalid public key for verification");this.verificationKey=e,console.log("\u{1F512} Verification key set successfully")}async generateSigningKeyPair(){try{let e=await crypto.subtle.generateKey({name:"RSASSA-PKCS1-v1_5",modulusLength:2048,publicExponent:new Uint8Array([1,0,1]),hash:"SHA-256"},!0,["sign","verify"]);return this.signingKey=e.privateKey,this.verificationKey=e.publicKey,console.log("\u{1F512} RSA key pair generated successfully"),e}catch(e){let t=ee.sanitizeError(e);throw console.error("\u274C Failed to generate signing key pair:",t),new Error(t)}}clearKeys(){this.signingKey=null,this.verificationKey=null,console.log("\u{1F512} Security keys cleared")}getSecurityStatus(){return{signingEnabled:this.signingKey!==null,verificationEnabled:this.verificationKey!==null,contextActive:Ie.getInstance().isActive(),securityLevel:Ie.getInstance().getSecurityLevel()}}getClientIdentifier(){return this.webrtcManager?.connectionId||this.webrtcManager?.keyFingerprint?.substring(0,16)||"default-client"}destroy(){Ie.getInstance().deactivate(),this.clearKeys(),console.log("\u{1F512} File transfer system destroyed safely")}};var Ue=typeof navigator<"u"&&/AppleWebKit/.test(navigator.userAgent)&&!/Chrome|Chromium|Edg\//.test(navigator.userAgent),st={opusFmtp:{minptime:10,useinbandfec:1,usedtx:1,stereo:0,maxaveragebitrate:32e3,cbr:0},preferRed:!0,sender:{maxBitrate:4e4,priority:"high",networkPriority:"high"}},Re={codecPreferenceOrder:["VP9","AV1","H264","VP8"],vp9:{preferredScalabilityMode:"L3T3_KEY",simulcast:[{rid:"low",scaleResolutionDownBy:4,maxBitrate:15e4,scalabilityMode:"L1T3"},{rid:"mid",scaleResolutionDownBy:2,maxBitrate:5e5,scalabilityMode:"L1T3"},{rid:"high",scaleResolutionDownBy:1,maxBitrate:15e5,scalabilityMode:"L1T3"}],degradationPreference:"balanced"},av1:{scalabilityMode:"L1T3",maxBitrate:12e5,degradationPreference:"maintain-framerate"},simulcast:[{rid:"low",scaleResolutionDownBy:4,maxBitrate:15e4},{rid:"mid",scaleResolutionDownBy:2,maxBitrate:5e5},{rid:"high",scaleResolutionDownBy:1,maxBitrate:15e5}],networkPriority:"medium"},qi={twccUri:"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",video:{rtcpFb:["transport-cc","nack","nack pli","ccm fir","goog-remb"],twcc:!0},audio:{rtcpFb:["transport-cc","nack"],twcc:!0}},Tr={intervalMs:1e3,loss:{highPct:.1,recoverPct:.03,audioProtectPct:.25},rtt:{highMs:300,recoverMs:150},stepDownPct:.2,stepUpPct:.1,minVideoBitrate:1e5,recoverStableTicks:5,cpuScaleStep:1.5};function ta(s){return s.indexOf(`\r `)!==-1?`\r `:` @@ -42,7 +42,7 @@ Please wait for real-time cryptographic verification to complete.`,"sec.verifica `,n=new Blob([i],{type:"application/javascript"}),a=new Worker(URL.createObjectURL(n)),o=setTimeout(()=>{a.terminate(),r(new Error("Worker cleanup timeout"))},5e3);a.onmessage=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),c.data.success?t(c.data):r(new Error(c.data.error))},a.onerror=c=>{clearTimeout(o),a.terminate(),URL.revokeObjectURL(n),r(c)},a.postMessage(e)})}async _cleanupInMainThread(e){let{type:t,data:r}=e;switch(t){case"cleanup_arrays":let i=0,n=100;for(;ic++),await this._asyncSleep(1);return{success:!0,cleaned:c};default:return{success:!0,message:"Unknown cleanup type"}}}_initializeMutexSystem(){this._keyOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._cryptoOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._connectionOperationMutex={locked:!1,queue:[],lockId:null,lockTimeout:null,lockTime:null,operationCount:0},this._keySystemState={isInitializing:!1,isRotating:!1,isDestroying:!1,lastOperation:null,lastOperationTime:Date.now(),operationId:null,concurrentOperations:0,maxConcurrentOperations:1},this._operationCounters={keyOperations:0,cryptoOperations:0,connectionOperations:0,totalOperations:0,failedOperations:0},this._secureLog("info","\u{1F512} Enhanced mutex system initialized with atomic protection",{mutexes:["keyOperation","cryptoOperation","connectionOperation"],timestamp:Date.now(),features:["atomic_operations","race_condition_protection","enhanced_state_tracking"]})}_hardenDebugModeReferences(){this._secureLog("info","\u{1F512} XSS Hardening: Debug mode references already replaced")}_initializeUnifiedScheduler(){this._maintenanceScheduler=setInterval(()=>{this._executeMaintenanceCycle()},3e5),this._secureLog("info","\u{1F527} Unified maintenance scheduler initialized (5-minute cycle)"),this._activeTimers=new Set([this._maintenanceScheduler])}_trackActiveTimer(e){return e&&(this._activeTimers||(this._activeTimers=new Set),this._activeTimers.add(e),e)}_untrackActiveTimer(e){e&&this._activeTimers&&this._activeTimers.delete(e)}_setSASMaterialReady(e,t){this._sasLocalFingerprint=e,this._sasRemoteFingerprint=t}_isVerificationReady(){let e=!!(this.peerConnection?.localDescription&&this.peerConnection?.remoteDescription),t=this.dataChannel?.readyState==="open",r=typeof this.verificationCode=="string"&&this.verificationCode.trim().length>0,i=typeof this._sasLocalFingerprint=="string"&&this._sasLocalFingerprint.trim().length>0&&typeof this._sasRemoteFingerprint=="string"&&this._sasRemoteFingerprint.trim().length>0;return e&&t&&r&&i}_notifyVerificationReadyIfPossible(){return this._isVerificationReady()?(this._verificationUiOpened||(this._verificationUiOpened=!0,this.onStatusChange?.("verifying"),this.onVerificationRequired?.(this.verificationCode)),!0):!1}_countIceCandidatesInSDP(e){return typeof e!="string"?0:(e.match(/^a=candidate:/gm)||[]).length}_summarizeIceCandidatesInSDP(e){let t={total:0,host:0,srflx:0,relay:0,prflx:0,unknown:0};if(typeof e!="string")return t;for(let r of e.match(/^a=candidate:.*$/gm)||[]){t.total+=1;let n=r.match(/\btyp\s+(host|srflx|relay|prflx)\b/i)?.[1]?.toLowerCase();n&&Object.prototype.hasOwnProperty.call(t,n)?t[n]+=1:t.unknown+=1}return t}_describeIceCandidatesInSDP(e){return typeof e!="string"?[]:(e.match(/^a=candidate:.*$/gm)||[]).map(t=>{let r=t.slice(12).trim().split(/\s+/),i=r.findIndex(u=>u.toLowerCase()==="typ"),n=r[4]||"",a=r[5]||"",o=i>=0&&r[i+1]||"unknown",c=(r[2]||"unknown").toLowerCase(),d="unknown";return/\.local$/i.test(n)?d="mdns":/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(n)?d="private-ipv4":/^\d{1,3}(\.\d{1,3}){3}$/.test(n)?d="public-ipv4":n.includes(":")&&(d="ipv6"),{candidateType:o,protocol:c,addressKind:d,portPresent:!!a,tcpType:(()=>{let u=r.findIndex(h=>h.toLowerCase()==="tcptype");return u>=0&&r[u+1]||null})()}})}_logIceCandidateDiagnostics(e,t,r={}){let i=this._summarizeIceCandidatesInSDP(t),n=this._describeIceCandidatesInSDP(t);return console.info(`[SecureBit ICE] ${e}`,{candidateSummary:i,candidateDetails:n,candidateDetailsJson:JSON.stringify(n),...r}),{candidateSummary:i,candidateDetails:n}}_hasOnlyMdnsHostCandidates(e){let t=this._summarizeIceCandidatesInSDP(e),r=this._describeIceCandidatesInSDP(e);return t.total>0&&t.srflx===0&&t.relay===0&&t.prflx===0&&r.every(i=>i.candidateType==="host"&&i.addressKind==="mdns")}_warnIfRemoteCandidatesNeedRelay(e,t){if(!this._hasOnlyMdnsHostCandidates(t))return!1;let r=e==="answer"?"Connection warning: the response contains only browser-masked mDNS host candidates and no server-reflexive or TURN relay candidates. This network/browser combination may not connect until TURN is configured.":"Connection warning: the invitation contains only browser-masked mDNS host candidates and no server-reflexive or TURN relay candidates. This network/browser combination may not connect until TURN is configured.";return this._secureLog("warn","Remote ICE candidates require TURN or usable non-mDNS candidates",{context:e,candidateSummary:this._summarizeIceCandidatesInSDP(t),candidateDetails:this._describeIceCandidatesInSDP(t)}),this.deliverMessageToUI(r,"system"),!0}async _collectIceFailureDiagnostics(){if(!this.peerConnection?.getStats)return null;try{let e=await this.peerConnection.getStats(),t=new Map,r=[];return e.forEach(i=>{(i.type==="local-candidate"||i.type==="remote-candidate")&&t.set(i.id,{type:i.type,candidateType:i.candidateType,protocol:i.protocol,address:i.address||i.ip||null,port:i.port||null,networkType:i.networkType||null})}),e.forEach(i=>{i.type==="candidate-pair"&&r.push({state:i.state,nominated:!!i.nominated,writable:!!i.writable,bytesSent:i.bytesSent||0,bytesReceived:i.bytesReceived||0,currentRoundTripTime:i.currentRoundTripTime??null,local:t.get(i.localCandidateId)||null,remote:t.get(i.remoteCandidateId)||null})}),{pairCount:r.length,states:r.reduce((i,n)=>(i[n.state||"unknown"]=(i[n.state||"unknown"]||0)+1,i),{}),pairs:r}}catch(e){return{error:e?.message||"Failed to collect ICE diagnostics"}}}_storePendingOfferContext(){this._pendingOfferContext={sessionSalt:Array.isArray(this.sessionSalt)?[...this.sessionSalt]:null,sessionId:this.sessionId||null,connectionId:this.connectionId||null,keyFingerprint:this.keyFingerprint||null,createdAt:Date.now()}}_restorePendingOfferContextIfNeeded(){if(Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64)return!0;let t=this._pendingOfferContext?.sessionSalt;return!Array.isArray(t)||t.length!==64?!1:(this.sessionSalt=[...t],!this.sessionId&&this._pendingOfferContext.sessionId&&(this.sessionId=this._pendingOfferContext.sessionId),!this.connectionId&&this._pendingOfferContext.connectionId&&(this.connectionId=this._pendingOfferContext.connectionId),!this.keyFingerprint&&this._pendingOfferContext.keyFingerprint&&(this.keyFingerprint=this._pendingOfferContext.keyFingerprint),this._secureLog("warn","Restored pending offer context before applying answer",{pendingContextAgeMs:Date.now()-(this._pendingOfferContext.createdAt||Date.now())}),!0)}_clearPendingOfferContext(){this._pendingOfferContext?.sessionSalt&&this._secureWipeMemory(this._pendingOfferContext.sessionSalt,"pendingOfferContext.sessionSalt"),this._pendingOfferContext=null}_executeMaintenanceCycle(){try{this._secureLog("info","\u{1F527} Starting maintenance cycle"),this._cleanupLogs(),this._auditLoggingSystemSecurity(),this._verifyAPIIntegrity(),this._validateCryptographicSecurity(),this._syncSecurityFeaturesWithTariff(),this._cleanupResources(),this._enforceResourceLimits(),this.isConnected&&this.isVerified&&this._monitorKeySecurity(),this._debugMode&&this._monitorGlobalExposure(),this._secureLog("info","\u{1F527} Maintenance cycle completed successfully")}catch(e){this._secureLog("error","\u274C Maintenance cycle failed",{errorType:e?.constructor?.name||"Unknown",message:e?.message||"Unknown error"}),this._emergencyCleanup().catch(t=>{this._secureLog("error","Emergency cleanup failed",{errorType:t?.constructor?.name||"Unknown"})})}}_enforceResourceLimits(){let e=[];this._logCounts.size>this._resourceLimits.maxLogEntries&&e.push("log_entries"),this.messageQueue.length>this._resourceLimits.maxMessageQueue&&e.push("message_queue"),this._ivTrackingSystem&&this._ivTrackingSystem.ivHistory.size>this._resourceLimits.maxIVHistory&&e.push("iv_history"),this.processedMessageIds.size>this._resourceLimits.maxProcessedMessageIds&&e.push("processed_message_ids"),this.decoyChannels.size>this._resourceLimits.maxDecoyChannels&&e.push("decoy_channels"),this._fakeTrafficMessages&&this._fakeTrafficMessages.length>this._resourceLimits.maxFakeTrafficMessages&&e.push("fake_traffic_messages"),this.chunkQueue.length>this._resourceLimits.maxChunkQueue&&e.push("chunk_queue"),this.packetBuffer&&this.packetBuffer.size>this._resourceLimits.maxPacketBuffer&&e.push("packet_buffer"),e.length>0&&(this._secureLog("warn","\u26A0\uFE0F Resource limit violations detected",{violations:e}),this._emergencyCleanup().catch(t=>{this._secureLog("error","Emergency cleanup failed",{errorType:t?.constructor?.name||"Unknown"})}))}async _emergencyCleanup(){this._secureLog("warn","\u{1F6A8} EMERGENCY: Resource limits exceeded, performing emergency cleanup");try{if(this._logCounts.clear(),this._secureLog("info","\u{1F9F9} Emergency: All logs cleared"),this.messageQueue.length=0,this._secureLog("info","\u{1F9F9} Emergency: Message queue cleared"),this._ivTrackingSystem&&(this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","\u{1F9F9} Enhanced Emergency: IV tracking system cleared")),this.processedMessageIds.clear(),this._secureLog("info","\u{1F9F9} Emergency: Processed message IDs cleared"),this.decoyChannels){for(let[e,t]of this.decoyTimers)t&&clearTimeout(t);this.decoyChannels.clear(),this.decoyTimers.clear(),this._secureLog("info","\u{1F9F9} Enhanced Emergency: Decoy channels cleared")}this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null),this._fakeTrafficMessages&&(this._fakeTrafficMessages.length=0,this._secureLog("info","\u{1F9F9} Enhanced Emergency: Fake traffic messages cleared")),this.chunkQueue.length=0,this._secureLog("info","\u{1F9F9} Emergency: Chunk queue cleared"),this.packetBuffer&&(this.packetBuffer.clear(),this._secureLog("info","\u{1F9F9} Emergency: Packet buffer cleared")),this._secureMemoryManager.isCleaning=!0,this._secureMemoryManager.cleanupQueue.length=0,this._secureMemoryManager.memoryStats.lastCleanup=Date.now(),await this._scheduleAsyncCleanup(async()=>{this._secureLog("info","\u{1F9F9} Enhanced Emergency: Starting natural memory cleanup");for(let e=0;e<3;e++)this._secureLog("info",`\u{1F9F9} Enhanced Emergency: Cleanup cycle ${e+1}/3`),await this._performNaturalCleanup();this._secureLog("info","\u{1F9F9} Enhanced Emergency: Natural cleanup completed")},0),this._secureMemoryManager.isCleaning=!1,this._secureLog("info","\u2705 Enhanced emergency cleanup completed successfully")}catch(e){this._secureLog("error","\u274C Enhanced emergency cleanup failed",{errorType:e?.constructor?.name||"Unknown",message:e?.message||"Unknown error"}),this._secureMemoryManager.isCleaning=!1}}_validateEmergencyCleanup(e){let t={messageQueueSize:this.messageQueue.length,processedIdsSize:this.processedMessageIds.size,packetBufferSize:this.packetBuffer?this.packetBuffer.size:0,ivTrackingSize:this._ivTrackingSystem?this._ivTrackingSystem.usedIVs.size:0,decoyChannelsSize:this.decoyChannels?this.decoyChannels.size:0};return{messageQueueCleared:t.messageQueueSize===0,processedIdsCleared:t.processedIdsSize===0,packetBufferCleared:t.packetBufferSize===0,ivTrackingCleared:t.ivTrackingSize===0,decoyChannelsCleared:t.decoyChannelsSize===0,allCleared:t.messageQueueSize===0&&t.processedIdsSize===0&&t.packetBufferSize===0&&t.ivTrackingSize===0&&t.decoyChannelsSize===0}}_cleanupResources(){let e=Date.now();this.processedMessageIds.size>this._emergencyThresholds.processedMessageIds&&(this.processedMessageIds.clear(),this._secureLog("info","\u{1F9F9} Old processed message IDs cleared")),this._ivTrackingSystem&&this._cleanupOldIVs(),this.cleanupOldKeys(),window.EnhancedSecureCryptoUtils&&window.EnhancedSecureCryptoUtils.rateLimiter&&window.EnhancedSecureCryptoUtils.rateLimiter.cleanup(),this._secureLog("info","\u{1F9F9} Resource cleanup completed")}_monitorKeySecurity(){this._keyStorageStats.activeKeys>10&&this._secureLog("warn","\u26A0\uFE0F High number of active keys detected. Consider rotation.")}_sendHeartbeat(e=!1){try{return this.dataChannel&&this.dataChannel.readyState==="open"?(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.HEARTBEAT,ack:e,timestamp:Date.now()})),this._heartbeatConfig.lastHeartbeat=Date.now(),this._secureLog("debug",e?"\u{1F493} Heartbeat ack sent":"\u{1F493} Heartbeat sent"),!0):!1}catch(t){return this._secureLog("error","\u274C Heartbeat failed:",{errorType:t?.constructor?.name||"Unknown",message:t?.message||"Unknown error"}),!1}}_validateInputData(e,t="unknown"){let r={isValid:!1,sanitizedData:null,errors:[],warnings:[]};try{if(e==null)return r.errors.push("Data cannot be null or undefined"),r;if(typeof e=="string")return e.length>this._inputValidationLimits.maxStringLength?(r.errors.push(`String too long: ${e.length} > ${this._inputValidationLimits.maxStringLength}`),r):(r.sanitizedData=this._sanitizeInputString(e),r.isValid=!0,r);if(typeof e=="object"){let i=new WeakSet,n=(o,c="")=>{if(!(o===null||typeof o!="object")){if(i.has(o)){r.errors.push(`Circular reference detected at path: ${c}`);return}if(i.add(o),c.split(".").length>this._inputValidationLimits.maxObjectDepth){r.errors.push(`Object too deep: ${c.split(".").length} > ${this._inputValidationLimits.maxObjectDepth}`);return}if(Array.isArray(o)&&o.length>this._inputValidationLimits.maxArrayLength){r.errors.push(`Array too long: ${o.length} > ${this._inputValidationLimits.maxArrayLength}`);return}for(let d in o)o.hasOwnProperty(d)&&n(o[d],c?`${c}.${d}`:d)}};if(n(e),r.errors.length>0)return r;let a=this._calculateObjectSize(e);return a>this._inputValidationLimits.maxMessageSize?(r.errors.push(`Object too large: ${a} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),r):(r.sanitizedData=this._sanitizeInputObject(e),r.isValid=!0,r)}return e instanceof ArrayBuffer?e.byteLength>this._inputValidationLimits.maxMessageSize?(r.errors.push(`ArrayBuffer too large: ${e.byteLength} bytes > ${this._inputValidationLimits.maxMessageSize} bytes`),r):(r.sanitizedData=e,r.isValid=!0,r):(r.errors.push(`Unsupported data type: ${typeof e}`),r)}catch(i){return r.errors.push(`Validation error: ${i.message}`),this._secureLog("error","\u274C Input validation failed",{context:t,errorType:i?.constructor?.name||"Unknown",message:i?.message||"Unknown error"}),r}}_calculateObjectSize(e){try{let t=JSON.stringify(e);return new TextEncoder().encode(t).length}catch{return 1024*1024}}_sanitizeInputString(e){return typeof e!="string"||(e=e.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g,""),e=e.replace(/\r\n?/g,` `),e=e.replace(/\n{3,}/g,` -`),e=e.trim()),e}_sanitizeInputObject(e){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(r=>this._sanitizeInputObject(r));let t={};for(let r in e)if(e.hasOwnProperty(r)){let i=e[r];typeof i=="string"?t[r]=this._sanitizeInputString(i):typeof i=="object"?t[r]=this._sanitizeInputObject(i):t[r]=i}return t}_checkRateLimit(e="message"){let t=Date.now();return this._rateLimiter||(this._rateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._rateLimiter.lastReset>6e4&&(this._rateLimiter.messageCount=0,this._rateLimiter.lastReset=t),t-this._rateLimiter.lastBurstReset>1e3&&(this._rateLimiter.burstCount=0,this._rateLimiter.lastBurstReset=t),this._rateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Rate limit burst exceeded",{context:e}),!1):this._rateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Rate limit exceeded",{context:e}),!1):(this._rateLimiter.messageCount++,this._rateLimiter.burstCount++,!0)}_checkInboundRateLimit(e="incoming_message"){let t=Date.now();return this._inboundRateLimiter||(this._inboundRateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._inboundRateLimiter.lastReset>6e4&&(this._inboundRateLimiter.messageCount=0,this._inboundRateLimiter.lastReset=t),t-this._inboundRateLimiter.lastBurstReset>1e3&&(this._inboundRateLimiter.burstCount=0,this._inboundRateLimiter.lastBurstReset=t),this._inboundRateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Inbound message burst limit exceeded; dropping message",{context:e}),!1):this._inboundRateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Inbound message rate limit exceeded; dropping message",{context:e}),!1):(this._inboundRateLimiter.messageCount++,this._inboundRateLimiter.burstCount++,!0)}_initializeSecureKeyStorage(){this._masterKeyManager=new jt,this._secureKeyStorage=new Gt(this._masterKeyManager),this._keyStorageStats={totalKeys:0,activeKeys:0,lastAccess:null,lastRotation:null},this._secureLog("info","\u{1F510} Enhanced secure key storage initialized")}setMasterKeyPasswordCallback(e){this._masterKeyManager&&this._masterKeyManager.setPasswordRequiredCallback(e)}setMasterKeySessionExpiredCallback(e){this._masterKeyManager&&this._masterKeyManager.setSessionExpiredCallback(e)}lockMasterKey(){this._masterKeyManager&&this._masterKeyManager.lock()}isMasterKeyUnlocked(){return this._masterKeyManager?this._masterKeyManager.isUnlocked():!1}getMasterKeySessionStatus(){return this._masterKeyManager?this._masterKeyManager.getSessionStatus():null}async _ensureFileTransferReady(){try{if(this.fileTransferSystem)return!0;if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.isVerified)throw new Error("Connection not verified");this.initializeFileTransfer();let e=0,t=50;for(;!this.fileTransferSystem&&esetTimeout(r,100)),e++;if(!this.fileTransferSystem)throw new Error("File transfer system initialization timeout");return!0}catch(e){return this._secureLog("error","\u274C _ensureFileTransferReady failed",{errorType:e?.constructor?.name||"Unknown",hasMessage:!!e?.message}),!1}}_getSecureKey(e){return this._secureKeyStorage.retrieveKey(e)}async _setSecureKey(e,t){if(!(t instanceof CryptoKey))return this._secureLog("error","\u274C Attempt to store non-CryptoKey"),!1;let r=await this._secureKeyStorage.storeKey(e,t,{version:this.currentKeyVersion,type:t.algorithm.name});return r&&this._secureLog("info",`\u{1F511} Key ${e} stored securely with encryption`),r}_validateKeyValue(e){return e instanceof CryptoKey&&e.algorithm&&e.usages&&e.usages.length>0}_secureWipeKeys(){this._secureKeyStorage.secureWipeAll(),this._masterKeyManager&&this._masterKeyManager.lock(),this._secureLog("info","\u{1F9F9} All keys securely wiped and encrypted storage cleared")}_validateKeyStorage(){return this._secureKeyStorage instanceof Gt}_getKeyStorageStats(){let e=this._secureKeyStorage.getStorageStats();return{totalKeysCount:e.totalKeys,activeKeysCount:e.totalKeys,hasLastAccess:e.metadata.some(t=>t.lastAccessed),hasLastRotation:!!this._keyStorageStats.lastRotation,storageType:"SecureKeyStorage",timestamp:Date.now()}}_rotateKeys(){let e=Array.from(this._secureKeyStorage.keys());this._secureKeyStorage.clear(),this._keyStorageStats.lastRotation=Date.now(),this._keyStorageStats.activeKeys=0,this._secureLog("info",`\u{1F504} Key rotation completed. ${e.length} keys rotated`)}_emergencyKeyWipe(){this._secureWipeKeys(),this._secureLog("error","\u{1F6A8} EMERGENCY: All keys wiped due to security threat")}_startKeySecurityMonitoring(){this._secureLog("info","\u{1F527} Key security monitoring moved to unified scheduler")}_validateKeyConstantTime(e){let t=0;try{let r=e instanceof CryptoKey;t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.algorithm);t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.type);t+=r?1:0}catch{t+=0}try{let r=e&&e.extractable!==void 0;t+=r?1:0}catch{t+=0}return t===4}_validateKeyPairConstantTime(e){if(!e||typeof e!="object")return!1;let t=this._validateKeyConstantTime(e.privateKey),r=this._validateKeyConstantTime(e.publicKey);return t&&r}_initializeSecureLogging(){this._logLevels={error:0,warn:1,info:2,debug:3,trace:4},this._currentLogLevel=this._isProductionMode?this._logLevels.error:this._logLevels.info,this._logCounts=new Map,this._maxLogCount=this._isProductionMode?5:50,this._resourceLimits={maxLogEntries:this._isProductionMode?100:1e3,maxMessageQueue:1e3,maxIVHistory:1e4,maxProcessedMessageIds:5e3,maxDecoyChannels:100,maxFakeTrafficMessages:500,maxChunkQueue:200,maxPacketBuffer:1e3},this._emergencyThresholds={logEntries:this._resourceLimits.maxLogEntries*.8,messageQueue:this._resourceLimits.maxMessageQueue*.8,ivHistory:this._resourceLimits.maxIVHistory*.8,processedMessageIds:this._resourceLimits.maxProcessedMessageIds*.8},this._inputValidationLimits={maxStringLength:1e5,maxObjectDepth:10,maxArrayLength:1e3,maxMessageSize:1024*1024,maxConcurrentMessages:10,rateLimitMessagesPerMinute:60,rateLimitBurstSize:10},this._absoluteBlacklist=new Set(["encryptionKey","macKey","metadataKey","privateKey","publicKey","ecdhKeyPair","ecdsaKeyPair","peerPublicKey","nestedEncryptionKey","verificationCode","sessionSalt","keyFingerprint","sessionId","authChallenge","authProof","authToken","sessionToken","password","token","secret","credential","signature","apiKey","accessKey","secretKey","privateKey","hash","digest","nonce","iv","cipher","seed","entropy","random","salt","fingerprint","jwt","bearer","refreshToken","accessToken","fileHash","fileSignature","transferKey","chunkKey"]),this._safeFieldsWhitelist=new Set(["timestamp","type","status","state","level","isConnected","isVerified","isInitiator","version","count","total","active","inactive","success","failure","readyState","connectionState","iceConnectionState","activeFeaturesCount","totalFeatures","stage","errorType","errorCode","phase","attempt"]),this._initializeLogSecurityMonitoring(),this._secureLog("info",`\u{1F527} Enhanced secure logging initialized (Production: ${this._isProductionMode})`)}_initializeLogSecurityMonitoring(){this._logSecurityViolations=0,this._maxLogSecurityViolations=3}_auditLoggingSystemSecurity(){let e=0;for(let[r,i]of this._logCounts.entries())i>this._maxLogCount*2&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Excessive log count detected: ${r}`));let t=Array.from(this._logCounts.keys());for(let r of t)this._containsSensitiveContent(r)&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Sensitive content in log key: ${r}`));this._logSecurityViolations+=e,this._logSecurityViolations>=this._maxLogSecurityViolations&&(this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Logging system disabled due to security violations"))}_secureLogShim(...e){try{if(!Array.isArray(e)||e.length===0)return;let t=e[0],r=e.slice(1);if(r.length===0){this._secureLog("info",String(t||""));return}if(r.length===1){this._secureLog("info",String(t||""),r[0]);return}this._secureLog("info",String(t||""),{additionalArgs:r,argCount:r.length})}catch{try{this._originalConsole?.log&&this._originalConsole.log(...e)}catch{}}}_setupOwnLogger(){this.logger={log:(e,t)=>this._secureLog("info",e,t),info:(e,t)=>this._secureLog("info",e,t),warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:(e,t)=>this._secureLog("debug",e,t)},s.DEBUG_MODE?this._secureLog("info","\u{1F512} Own logger created - development mode"):this._secureLog("info","\u{1F512} Own logger created - production mode")}_setupProductionLogging(){this._isProductionMode&&(this.logger={log:()=>{},info:()=>{},warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:()=>{}},this._secureLog("info","Production logging mode activated"))}_secureLog(e,t,r=null){if(r&&!this._auditLogMessage(t,r)){this._originalConsole?.error?.("SECURITY: Logging blocked due to potential data leakage");return}if(this._logLevels[e]>this._currentLogLevel)return;let i=`${e}:${t.substring(0,50)}`,n=this._logCounts.get(i)||0;if(n>=this._maxLogCount)return;this._logCounts.set(i,n+1);let a=null;if(r&&(a=this._sanitizeLogData(r),this._containsSensitiveContent(JSON.stringify(a)))){this._originalConsole?.error?.("ECURITY: Sanitized data still contains sensitive content - blocking log");return}if(this._isProductionMode){if(e==="error"){let c=this._sanitizeString(t);this._originalConsole?.error?.(c)}return}let o=this._originalConsole?.[e]||this._originalConsole?.log;a?o(t,a):o(t)}_sanitizeLogData(e){if(typeof e=="string")return this._sanitizeString(e);if(!e||typeof e!="object")return e;let t={};for(let[i,n]of Object.entries(e)){let a=i.toLowerCase(),o=["key","secret","token","password","credential","auth","fingerprint","salt","signature","private","encryption","mac","metadata","session","jwt","bearer","hash","digest","nonce","iv","cipher","seed","entropy"];if(this._absoluteBlacklist.has(i)||o.some(d=>a.includes(d))){t[i]="[SENSITIVE_DATA_BLOCKED]";continue}if(this._safeFieldsWhitelist.has(i)){typeof n=="string"?t[i]=this._sanitizeString(n):t[i]=n;continue}if(typeof n=="boolean"||typeof n=="number")t[i]=n;else if(typeof n=="string")t[i]=this._sanitizeString(n);else if(n instanceof ArrayBuffer||n instanceof Uint8Array)t[i]=`[${n.constructor.name}( bytes)]`;else if(n&&typeof n=="object")try{t[i]=this._sanitizeLogData(n)}catch{t[i]="[RECURSIVE_SANITIZATION_FAILED]"}else t[i]=`[${typeof n}]`}let r=JSON.stringify(t);return this._containsSensitiveContent(r)?{error:"SANITIZATION_FAILED_SENSITIVE_CONTENT_DETECTED"}:t}_sanitizeString(e){if(typeof e!="string"||e.length===0)return e;let t=[/[a-f0-9]{16,}/i,/[a-f0-9]{8,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[A-Za-z0-9+/]{12,}/,/[A-Za-z0-9+/=]{10,}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/[A-Z2-7]{12,}/,/[A-Za-z0-9\-_]{16,}/,/[A-Za-z0-9\.\-_]{16,}/,/\b[A-Za-z0-9]{12,}\b/,/\b[A-Za-z0-9]{8,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/END\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i,/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/,/\b\d{3}-\d{2}-\d{4}\b/,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/,/(fingerprint|hash|digest|signature)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(encryption|mac|metadata)[\s]*key[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(session|auth|jwt|bearer)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i];for(let r of t)if(r.test(e))return"[SENSITIVE_DATA_REDACTED]";return this._hasHighEntropy(e)?"[HIGH_ENTROPY_DATA_REDACTED]":this._hasSuspiciousDistribution(e)?"[SUSPICIOUS_DATA_REDACTED]":e.length>50?e.substring(0,20)+"...[TRUNCATED]":e}_containsSensitiveContent(e){return typeof e!="string"?!1:[/[a-f0-9]{16,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/\b[A-Za-z0-9]{12,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i].some(r=>r.test(e))||this._hasHighEntropy(e)||this._hasSuspiciousDistribution(e)}_hasHighEntropy(e){if(e.length<8)return!1;let t={};for(let n of e)t[n]=(t[n]||0)+1;let r=e.length,i=0;for(let n of Object.values(t)){let a=n/r;i-=a*Math.log2(a)}return i>4.5}_hasSuspiciousDistribution(e){return e.length<8?!1:(e.match(/[a-f0-9]/gi)||[]).length>=e.length*.8||(e.match(/[A-Za-z0-9+/=]/g)||[]).length>=e.length*.9||new Set(e).size/e.length>.8&&e.length>16}_detectProductionMode(){return typeof process<"u"&&!0||!this._debugMode||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")}_setupSecureGlobalAPI(){this._secureLog("info","Starting secure global API setup");let e={};typeof this.sendMessage=="function"&&(e.sendMessage=this.sendMessage.bind(this)),e.getConnectionStatus=()=>({isConnected:this.isConnected?this.isConnected():!1,isVerified:this.isVerified||!1,connectionState:this.peerConnection?.connectionState||"disconnected"}),e.getSecurityStatus=()=>({securityLevel:"maximum",stage:"initialized",activeFeaturesCount:Object.values(this.securityFeatures||{}).filter(Boolean).length}),typeof this.sendFile=="function"&&(e.sendFile=this.sendFile.bind(this)),e.getFileTransferStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),typeof this.disconnect=="function"&&(e.disconnect=this.disconnect.bind(this));let t={...e,getConfiguration:()=>({fakeTraffic:this._config.fakeTraffic.enabled,decoyChannels:this._config.decoyChannels.enabled,packetPadding:this._config.packetPadding.enabled,antiFingerprinting:this._config.antiFingerprinting.enabled}),emergency:{}};typeof this._emergencyUnlockAllMutexes=="function"&&(t.emergency.unlockAllMutexes=this._emergencyUnlockAllMutexes.bind(this)),typeof this._emergencyRecoverMutexSystem=="function"&&(t.emergency.recoverMutexSystem=this._emergencyRecoverMutexSystem.bind(this)),typeof this._emergencyDisableLogging=="function"&&(t.emergency.disableLogging=this._emergencyDisableLogging.bind(this)),typeof this._resetLoggingSystem=="function"&&(t.emergency.resetLogging=this._resetLoggingSystem.bind(this)),t.getFileTransferSystemStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),this._secureLog("info","API methods available",{sendMessage:!!e.sendMessage,getConnectionStatus:!!e.getConnectionStatus,getSecurityStatus:!!e.getSecurityStatus,sendFile:!!e.sendFile,getFileTransferStatus:!!e.getFileTransferStatus,disconnect:!!e.disconnect,getConfiguration:!!t.getConfiguration,emergencyMethods:Object.keys(t.emergency).length}),Object.freeze(t),Object.freeze(t.emergency),this._createProtectedGlobalAPI(t),this._setupMinimalGlobalProtection(),this._secureLog("info","Secure global API setup completed successfully")}_createProtectedGlobalAPI(e){this._secureLog("info","Creating protected global API"),window.secureBitChat?this._secureLog("warn","\u26A0\uFE0F Global API already exists, skipping setup"):this._exportAPI(e)}_exportAPI(e){this._secureLog("info","Exporting API to window.secureBitChat"),!this._importantMethods||!this._importantMethods.defineProperty?(this._secureLog("error","\u274C Important methods not available for API export, using fallback"),Object.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0})):this._importantMethods.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0}),this._secureLog("info","\u{1F512} Secure API exported to window.secureBitChat")}_setupMinimalGlobalProtection(){this._protectGlobalAPI(),this._secureLog("info","\u{1F512} Minimal global protection activated")}_storeImportantMethods(){this._importantMethods={defineProperty:Object.defineProperty,getOwnPropertyDescriptor:Object.getOwnPropertyDescriptor,freeze:Object.freeze,consoleLog:console.log,consoleError:console.error,consoleWarn:console.warn},this._secureLog("info","\u{1F512} Important methods stored locally",{defineProperty:!!this._importantMethods.defineProperty,getOwnPropertyDescriptor:!!this._importantMethods.getOwnPropertyDescriptor,freeze:!!this._importantMethods.freeze})}_setupSimpleProtection(){this._secureLog("info","\u{1F512} Simple protection activated - no monitoring")}_preventGlobalExposure(){this._secureLog("info","\u{1F512} No global exposure prevention - using secure API export only")}_verifyAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C SECURITY ALERT: Secure API has been removed!"),!1;let t=["sendMessage","getConnectionStatus","disconnect"].filter(r=>typeof window.secureBitChat[r]!="function");return t.length>0?(this._secureLog("error","\u274C SECURITY ALERT: API tampering detected, missing methods:",{errorType:t?.constructor?.name||"Unknown"}),!1):!0}catch(e){return this._secureLog("error","\u274C SECURITY ALERT: API integrity check failed:",{errorType:e?.constructor?.name||"Unknown"}),!1}}_auditGlobalExposure(){return this._secureLog("info","\u{1F512} Global exposure check completed at initialization"),[]}_startSecurityAudit(){this._secureLog("info","\u{1F512} Security audit completed at initialization - no periodic monitoring")}_protectGlobalAPI(){if(!window.secureBitChat){this._secureLog("warn","\u26A0\uFE0F Global API not found during protection setup");return}try{this._validateAPIIntegrityOnce()&&this._secureLog("info","\u{1F512} Global API protection verified")}catch(e){this._secureLog("error","\u274C Failed to verify global API protection",{errorType:e.constructor.name,errorMessage:e.message})}}_validateAPIIntegrityOnce(){try{if(!this._importantMethods||!this._importantMethods.getOwnPropertyDescriptor){let e=Object.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}else{let e=this._importantMethods.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}return this._secureLog("info","\u2705 API integrity validated"),!0}catch(e){return this._secureLog("error","\u274C API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_secureWipeMemory(e,t="unknown"){if(e)try{e instanceof ArrayBuffer?this._secureWipeArrayBuffer(e,t):e instanceof Uint8Array?this._secureWipeUint8Array(e,t):Array.isArray(e)?this._secureWipeArray(e,t):typeof e=="string"?this._secureWipeString(e,t):e instanceof CryptoKey?this._secureWipeCryptoKey(e,t):typeof e=="object"&&this._secureWipeObject(e,t),this._secureMemoryManager.memoryStats.totalCleanups++}catch(r){this._secureMemoryManager.memoryStats.failedCleanups++,this._secureLog("error","\u274C Secure memory wipe failed",{context:t,errorType:r.constructor.name,errorMessage:r.message})}}_secureWipeArrayBuffer(e,t){if(!(!e||e.byteLength===0))try{let r=new Uint8Array(e);crypto.getRandomValues(r),r.fill(0),r.fill(255),r.fill(0),this._secureLog("debug","\u{1F512} ArrayBuffer securely wiped",{context:t,size:e.byteLength})}catch(r){this._secureLog("error","\u274C Failed to wipe ArrayBuffer",{context:t,errorType:r.constructor.name})}}_secureWipeUint8Array(e,t){if(!(!e||e.length===0))try{crypto.getRandomValues(e),e.fill(0),e.fill(255),e.fill(0),this._secureLog("debug","\u{1F512} Uint8Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe Uint8Array",{context:t,errorType:r.constructor.name})}}_secureWipeArray(e,t){if(!(!Array.isArray(e)||e.length===0))try{e.forEach((r,i)=>{r!=null&&this._secureWipeMemory(r,`${t}[${i}]`)}),e.fill(null),this._secureLog("debug","\u{1F512} Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe array",{context:t,errorType:r.constructor.name})}}_secureWipeString(e,t){return this._secureLog("debug","String secret cannot be wiped in JS (immutable) \u2014 reference dropped only",{context:t,length:e?e.length:0}),!1}_secureWipeCryptoKey(e,t){return!e||!(e instanceof CryptoKey)||(this._secureLog("debug","CryptoKey cannot be wiped from JS \u2014 handle dropped, material is non-extractable",{context:t,type:e.type,extractable:e.extractable}),e.extractable&&this._secureLog("error","Extractable key reached the wipe path \u2014 material may persist in memory",{context:t})),!1}_secureWipeObject(e,t){if(!(!e||typeof e!="object"))try{for(let[r,i]of Object.entries(e))i!=null&&this._secureWipeMemory(i,`${t}.${r}`),e[r]=null;this._secureLog("debug","\u{1F512} Object securely wiped",{context:t,properties:Object.keys(e).length})}catch(r){this._secureLog("error","\u274C Failed to wipe object",{context:t,errorType:r.constructor.name})}}_secureCleanupCryptographicMaterials(){try{if(this.ecdhKeyPair&&(this._secureWipeMemory(this.ecdhKeyPair,"ecdhKeyPair"),this.ecdhKeyPair=null),this.ecdsaKeyPair&&(this._secureWipeMemory(this.ecdsaKeyPair,"ecdsaKeyPair"),this.ecdsaKeyPair=null),this.encryptionKey&&(this._secureWipeMemory(this.encryptionKey,"encryptionKey"),this.encryptionKey=null),this.macKey&&(this._secureWipeMemory(this.macKey,"macKey"),this.macKey=null),this.metadataKey&&(this._secureWipeMemory(this.metadataKey,"metadataKey"),this.metadataKey=null),this.nestedEncryptionKey&&(this._secureWipeMemory(this.nestedEncryptionKey,"nestedEncryptionKey"),this.nestedEncryptionKey=null),this.sessionSalt&&(this._secureWipeMemory(this.sessionSalt,"sessionSalt"),this.sessionSalt=null),this.sessionId&&(this._secureWipeMemory(this.sessionId,"sessionId"),this.sessionId=null),this.verificationCode&&(this._secureWipeMemory(this.verificationCode,"verificationCode"),this.verificationCode=null),this.peerPublicKey&&(this._secureWipeMemory(this.peerPublicKey,"peerPublicKey"),this.peerPublicKey=null),this.keyFingerprint&&(this._secureWipeMemory(this.keyFingerprint,"keyFingerprint"),this.keyFingerprint=null),this.connectionId&&(this._secureWipeMemory(this.connectionId,"connectionId"),this.connectionId=null),this._clearPendingOfferContext(),this._ratchet){try{this._ratchet.destroy()}catch{}this._ratchet=null}this._peerSupportsRatchet=!1,this._secureLog("info","\u{1F512} Cryptographic materials securely cleaned up")}catch(e){this._secureLog("error","\u274C Failed to cleanup cryptographic materials",{errorType:e.constructor.name,errorMessage:e.message})}}async _forceGarbageCollection(){try{await this._performNaturalCleanup(),this._secureLog("debug","\u{1F512} Natural memory cleanup performed")}catch(e){this._secureLog("error","\u274C Failed to perform natural cleanup",{errorType:e.constructor.name})}}async _performPeriodicMemoryCleanup(){try{this._secureMemoryManager.isCleaning=!0;let e=this.sessionMode==="ratchet"&&this.isConnected&&this.dataChannel&&this.dataChannel.readyState==="open",t=this._pendingOfferContext?Date.now()-(this._pendingOfferContext.createdAt||0):1/0,r=!!this._pendingOfferContext&&Array.isArray(this._pendingOfferContext.sessionSalt)&&this._pendingOfferContext.sessionSalt.length===64&&t100&&this.messageQueue.splice(0,this.messageQueue.length-50).forEach((a,o)=>{this._secureWipeMemory(a,`periodicCleanup[${o}]`)}),this.processedMessageIds&&this.processedMessageIds.size>1e3&&this.processedMessageIds.clear(),await this._forceGarbageCollection(),this._secureLog("debug","\u{1F512} Periodic memory cleanup completed")}catch(e){this._secureLog("error","\u274C Error during periodic memory cleanup",{errorType:e.constructor.name,errorMessage:e.message})}finally{this._secureMemoryManager.isCleaning=!1}}_createSecureErrorMessage(e,t="unknown"){try{let r=this._categorizeError(e),i=this._getSafeErrorMessage(r,t);return this._secureLog("error","Internal error occurred",{category:r,context:t,errorType:e?.constructor?.name||"Unknown",timestamp:Date.now()}),this._trackErrorFrequency(r),i}catch(r){return this._secureLog("error","Error handling failed",{originalError:e?.message||"Unknown",handlingError:r.message}),"An unexpected error occurred"}}_categorizeError(e){if(!e||!e.message)return this._secureErrorHandler.errorCategories.UNKNOWN;let t=e.message.toLowerCase();return t.includes("crypto")||t.includes("key")||t.includes("encrypt")||t.includes("decrypt")||t.includes("sign")||t.includes("verify")||t.includes("ecdh")||t.includes("ecdsa")?this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC:t.includes("network")||t.includes("connection")||t.includes("timeout")||t.includes("webrtc")||t.includes("peer")?this._secureErrorHandler.errorCategories.NETWORK:t.includes("invalid")||t.includes("validation")||t.includes("format")||t.includes("type")?this._secureErrorHandler.errorCategories.VALIDATION:t.includes("system")||t.includes("internal")||t.includes("memory")||t.includes("resource")?this._secureErrorHandler.errorCategories.SYSTEM:this._secureErrorHandler.errorCategories.UNKNOWN}_getSafeErrorMessage(e,t){let r={[this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC]:{key_generation:"Security initialization failed",key_import:"Security verification failed",key_derivation:"Security setup failed",encryption:"Message security failed",decryption:"Message verification failed",signature:"Authentication failed",default:"Security operation failed"},[this._secureErrorHandler.errorCategories.NETWORK]:{connection:"Connection failed",timeout:"Connection timeout",peer:"Peer connection failed",webrtc:"Communication failed",default:"Network operation failed"},[this._secureErrorHandler.errorCategories.VALIDATION]:{format:"Invalid data format",type:"Invalid data type",structure:"Invalid data structure",default:"Validation failed"},[this._secureErrorHandler.errorCategories.SYSTEM]:{memory:"System resource error",resource:"System resource unavailable",internal:"Internal system error",default:"System operation failed"},[this._secureErrorHandler.errorCategories.UNKNOWN]:{default:"An unexpected error occurred"}},i=r[e]||r[this._secureErrorHandler.errorCategories.UNKNOWN],n="default";return t.includes("key")||t.includes("crypto")?n=e===this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC?"key_generation":"default":t.includes("connection")||t.includes("peer")?n=e===this._secureErrorHandler.errorCategories.NETWORK?"connection":"default":(t.includes("validation")||t.includes("format"))&&(n=e===this._secureErrorHandler.errorCategories.VALIDATION?"format":"default"),i[n]||i.default}_trackErrorFrequency(e){let t=Date.now();t-this._secureErrorHandler.lastErrorTime>6e4&&this._secureErrorHandler.errorCounts.clear();let r=this._secureErrorHandler.errorCounts.get(e)||0;this._secureErrorHandler.errorCounts.set(e,r+1),this._secureErrorHandler.lastErrorTime=t;let i=Array.from(this._secureErrorHandler.errorCounts.values()).reduce((n,a)=>n+a,0);i>this._secureErrorHandler.errorThreshold&&(this._secureErrorHandler.isInErrorMode=!0,this._secureLog("warn","\u26A0\uFE0F High error frequency detected - entering error mode",{totalErrors:i,threshold:this._secureErrorHandler.errorThreshold}))}_throwSecureError(e,t="unknown"){let r=this._createSecureErrorMessage(e,t);throw new Error(r)}_getErrorHandlingStats(){return{errorCounts:Object.fromEntries(this._secureErrorHandler.errorCounts),isInErrorMode:this._secureErrorHandler.isInErrorMode,lastErrorTime:this._secureErrorHandler.lastErrorTime,errorThreshold:this._secureErrorHandler.errorThreshold}}_resetErrorHandlingSystem(){this._secureErrorHandler.errorCounts.clear(),this._secureErrorHandler.isInErrorMode=!1,this._secureErrorHandler.lastErrorTime=0,this._secureLog("info","\u{1F504} Error handling system reset")}_getMemoryManagementStats(){return{totalCleanups:this._secureMemoryManager.memoryStats.totalCleanups,failedCleanups:this._secureMemoryManager.memoryStats.failedCleanups,lastCleanup:this._secureMemoryManager.memoryStats.lastCleanup,isCleaning:this._secureMemoryManager.isCleaning,queueLength:this._secureMemoryManager.cleanupQueue.length}}_validateAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C Global API not found during integrity validation"),!1;let e=["sendMessage","getConnectionStatus","getSecurityStatus","sendFile","disconnect"],t=e.filter(a=>!window.secureBitChat[a]||typeof window.secureBitChat[a]!="function");if(t.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - missing methods",{missingMethods:t}),!1;let r={test:!0},n=e.map(a=>{try{return window.secureBitChat[a].bind(r)}catch{return null}}).filter(a=>a===null);if(n.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - method binding issues",{unboundMethods:n.length}),!1;try{let a="_integrity_test_"+Date.now();return Object.defineProperty(window.secureBitChat,a,{value:"test",writable:!0,configurable:!0}),this._secureLog("error","\u274C Global API integrity validation failed - API is mutable"),delete window.secureBitChat[a],!1}catch{this._secureLog("debug","\u2705 Global API immutability verified")}return this._secureLog("info","\u2705 Global API integrity validation passed"),!0}catch(e){return this._secureLog("error","\u274C Global API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_validateCryptographicSecurity(){let e=["hasRateLimiting"],t=e.filter(n=>!this.securityFeatures[n]);t.length>0&&(this._secureLog("error","\u{1F6A8} CRITICAL: Missing critical rate limiting feature",{missing:t,currentFeatures:this.securityFeatures,action:"Rate limiting will be forced enabled"}),t.forEach(n=>{this.securityFeatures[n]=!0,this._secureLog("warn",`\u26A0\uFE0F Forced enable critical: ${n} = true`)}));let r=Object.keys(this.securityFeatures).filter(n=>this.securityFeatures[n]),i=["hasEncryption","hasECDH","hasECDSA"].filter(n=>this.securityFeatures[n]);return this._secureLog("info","\u2705 Cryptographic security validation passed",{criticalFeatures:e.length,availableFeatures:r.length,encryptionFeatures:i.length,totalSecurityFeatures:r.length,note:"Encryption features will be enabled after key generation",currentState:{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasRateLimiting:this.securityFeatures.hasRateLimiting}}),!0}_syncSecurityFeaturesWithTariff(){this._secureLog("info","\u2705 All security features enabled by default - no payment required"),["hasEncryption","hasECDH","hasECDSA","hasMutualAuth","hasMetadataProtection","hasEnhancedReplayProtection","hasNonExtractableKeys","hasRateLimiting","hasEnhancedValidation","hasPFS","hasNestedEncryption","hasPacketPadding","hasPacketReordering","hasAntiFingerprinting","hasFakeTraffic","hasDecoyChannels","hasMessageChunking"].forEach(t=>{this.securityFeatures[t]=!0}),this._secureLog("info","\u2705 All security features enabled by default",{enabledFeatures:Object.keys(this.securityFeatures).filter(t=>this.securityFeatures[t]).length,totalFeatures:Object.keys(this.securityFeatures).length})}_emergencyShutdown(e="Security breach"){this._secureLog("error","\u274C EMERGENCY SHUTDOWN: ${reason}");try{this.encryptionKey=null,this.macKey=null,this.metadataKey=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.messageQueue=[],this.processedMessageIds.clear(),this.packetBuffer.clear(),this.onStatusChange&&this.onStatusChange("security_breach"),this._secureLog("info","\u{1F512} Emergency shutdown completed")}catch(t){this._secureLog("error","\u274C Error during emergency shutdown:",{errorType:t?.constructor?.name||"Unknown"})}}_finalizeSecureInitialization(){if(this._startKeySecurityMonitoring(),!this._verifyAPIIntegrity()){this._secureLog("error","\u274C Security initialization failed");return}this._startSecurityMonitoring(),this._logCleanupInterval=this._trackActiveTimer(setInterval(()=>{this._cleanupLogs()},3e5)),this._secureLog("info","\u2705 Secure WebRTC Manager initialization completed"),this._secureLog("info","\u{1F512} Global exposure protection: Monitoring only, no automatic removal")}_startSecurityMonitoring(){this._secureLog("info","\u{1F527} Security monitoring moved to unified scheduler")}_validateConnection(e=!0){let t=this.dataChannel&&this.dataChannel.readyState==="open",r=this.isVerified,i=t&&r;if(!i&&e){if(!t)throw new Error("Data channel not ready");if(!r)throw new Error("Connection not verified")}return i}_enforceVerificationGate(e="unknown",t=!0){if(!this.isVerified){let r=`SECURITY VIOLATION: ${e} blocked - connection not cryptographically verified`;if(this._secureLog("error",r,{operation:e,isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey),timestamp:Date.now()}),t)throw new Error(r);return!1}return!0}_setVerifiedStatus(e,t="unknown",r=null){if(e){if(!this.encryptionKey||!this.macKey)throw new Error("Cannot set verified=true without encryption keys");if(!t||t==="unknown")throw new Error("Cannot set verified=true without specifying verification method");if(t.includes("SAS")&&!this.localVerificationConfirmed)throw this._secureLog("error","Blocked verified transition without local SAS confirmation",{verificationMethod:t,localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed}),new Error("Cannot set verified=true without local SAS confirmation");this._secureLog("info","Connection verified through cryptographic verification",{verificationMethod:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,keyFingerprint:this.keyFingerprint,timestamp:Date.now(),verificationData:r?"provided":"none"})}this.isVerified=e,e?this.onStatusChange("connected"):this.onStatusChange("disconnected")}markGroupLinkVerified(e="group_roster_signature"){let t=this._sbq2;if(!this._isSbq2()||!t||!t.completed||!t.proofVerified||!t.keysDerived)throw new Error("Group link cannot be released: the in-band handshake has not completed");if(!this.encryptionKey||!this.macKey)throw new Error("Group link cannot be released: session keys are missing");if(this.isVerified)return!0;this.localVerificationConfirmed=!0,this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this._setVerifiedStatus(!0,"GROUP_ROSTER_SIGNATURE",{reason:e,timestamp:Date.now()}),this._enforceVerificationGate("group_link_release",!1),this.onStatusChange?.("verified");try{this.processMessageQueue()}catch{}return!0}_createFileMessageAAD(e,t=null){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in _createFileMessageAAD. Manager may not be fully initialized.");return this._createMessageAAD(e,t,!0)}_validateFileMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);if(Date.now()-r.timestamp>18e5)throw new Error("AAD timestamp too old - possible replay attack");return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}_validateIncomingSequenceNumber(e,t="unknown"){try{if(!this.replayProtectionEnabled)return!0;if(typeof e!="number"||!Number.isFinite(e))return this._secureLog("warn","Missing or non-numeric sequence number - rejecting",{receivedType:typeof e,context:t,timestamp:Date.now()}),!1;if(ethis.expectedSequenceNumber+this.maxSequenceGap)return this._secureLog("warn","Sequence number gap too large - possible DoS attack",{received:e,expected:this.expectedSequenceNumber,gap:e-this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.has(e))return this._secureLog("warn","Duplicate sequence number detected - replay attack",{received:e,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.add(e),this.replayWindow.size>this.replayWindowSize){let r=Math.min(...this.replayWindow);this.replayWindow.delete(r)}if(e===this.expectedSequenceNumber)for(this.expectedSequenceNumber++;this.replayWindow.has(this.expectedSequenceNumber-this.replayWindowSize-1);)this.replayWindow.delete(this.expectedSequenceNumber-this.replayWindowSize-1);return this._secureLog("debug","Sequence number validation successful",{received:e,expected:this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!0}catch(r){return this._secureLog("error","Sequence number validation failed",{error:r.message,context:t,timestamp:Date.now()}),!1}}_validateMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(!this._validateIncomingSequenceNumber(r.sequenceNumber,r.messageType))throw new Error("Sequence number validation failed - possible replay or DoS attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}getAntiReplayStatus(){let e={replayProtectionEnabled:this.replayProtectionEnabled,replayWindowSize:this.replayWindowSize,currentReplayWindowSize:this.replayWindow.size,sequenceNumber:this.sequenceNumber,expectedSequenceNumber:this.expectedSequenceNumber,maxSequenceGap:this.maxSequenceGap,replayWindowEntries:Array.from(this.replayWindow).sort((t,r)=>t-r)};return this._secureLog("info","Anti-replay status retrieved",e),e}configureAntiReplayProtection(e){try{if(e.windowSize!==void 0){if(e.windowSize<16||e.windowSize>1024)throw new Error("Replay window size must be between 16 and 1024");this.replayWindowSize=e.windowSize}if(e.maxGap!==void 0){if(e.maxGap<10||e.maxGap>1e3)throw new Error("Max sequence gap must be between 10 and 1000");this.maxSequenceGap=e.maxGap}return e.enabled!==void 0&&(this.replayProtectionEnabled=e.enabled),this._secureLog("info","Anti-replay protection configured",e),!0}catch(t){return this._secureLog("error","Failed to configure anti-replay protection",{error:t.message}),!1}}async getRealSecurityLevel(){try{let e={ecdhKeyExchange:!!this.ecdhKeyPair,ecdsaSignatures:!!this.ecdsaKeyPair,aesEncryption:!!this.encryptionKey,messageIntegrity:!!this.hmacKey,replayProtection:this.replayProtectionEnabled,dtlsFingerprint:!!(this.expectedDTLSFingerprint&&this._peerDTLSFingerprint),sasCode:!!this.verificationCode&&this.localVerificationConfirmed===!0,metadataProtection:!0,trafficObfuscation:!0,perfectForwardSecrecy:this.isRatchetActive?.()===!0,rateLimiter:!0,connectionId:this.connectionId,keyFingerprint:this.keyFingerprint,currentSecurityLevel:"maximum",timestamp:Date.now()},t=await this.calculateAndReportSecurityLevel();return t?{...t,...e}:{...e,level:"INITIALIZING",score:0,isRealData:!1}}catch(e){throw this._secureLog("error","Failed to calculate real security level",{error:e.message}),e}}_extractDTLSFingerprintFromSDP(e){try{if(!e||typeof e!="string")throw new Error("Invalid SDP provided");let t=/a=fingerprint:([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/g,r=[],i;for(;(i=t.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()});if(r.length===0){let a=/fingerprint\s*=\s*([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/gi;for(;(i=a.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()})}if(r.length===0)throw this._secureLog("warn","No DTLS fingerprints found in SDP - this may be normal for some WebRTC implementations",{sdpLength:e.length,sdpPreview:e.substring(0,200)+"..."}),new Error("No DTLS fingerprints found in SDP");return[...r].sort((a,o)=>{let c=a.algorithm==="sha-256",d=o.algorithm==="sha-256";if(c!==d)return c?-1:1;let u=a.algorithm.localeCompare(o.algorithm);return u!==0?u:a.fingerprint.localeCompare(o.fingerprint)})[0].fingerprint}catch(t){throw this._secureLog("error","Failed to extract DTLS fingerprint from SDP",{error:t.message,sdpLength:e?.length||0}),new Error(`DTLS fingerprint extraction failed: ${t.message}`)}}async _validateDTLSFingerprint(e,t,r="unknown"){try{if(!e||!t)throw new Error("Missing fingerprint for validation");let i=e.toLowerCase().replace(/:/g,""),n=t.toLowerCase().replace(/:/g,"");if(i!==n)throw this._secureLog("error","DTLS fingerprint mismatch - possible MITM attack",{context:r,timestamp:Date.now()}),new Error(`DTLS fingerprint mismatch - possible MITM attack in ${r}`);return this._secureLog("info","DTLS fingerprint validation successful",{context:r,timestamp:Date.now()}),!0}catch(i){throw this._secureLog("error","DTLS fingerprint validation failed",{error:i.message,context:r}),i}}async _computeSAS(e,t,r){try{if(!e){let b=[];throw e||b.push("keyMaterialRaw"),new Error(`Missing required parameters for SAS computation: ${b.join(", ")}`)}let i=new TextEncoder,n=(b,w)=>{if(typeof b!="string"||b.trim().length===0)throw new Error(`Security error: ${w} must be a non-empty DTLS fingerprint string for SAS computation`);return b.trim().toLowerCase()},a=n(t,"localFP"),o=n(r,"remoteFP"),c=i.encode("webrtc-sas|"+[a,o].sort().join("|")),d;if(e instanceof ArrayBuffer)d=e;else if(e instanceof Uint8Array)d=e.buffer;else if(typeof e=="string"){let b=e.replace(/:/g,"").replace(/\s/g,""),w=new Uint8Array(b.length/2);for(let M=0;M>>0,g=String(S%1e7).padStart(7,"0");return this._secureLog("info","SAS code computed successfully",{localFP:a.substring(0,16)+"...",remoteFP:o.substring(0,16)+"...",sasLength:g.length,timestamp:Date.now()}),g}catch(i){throw this._secureLog("error","SAS computation failed",{error:i.message,keyMaterialType:typeof e,hasLocalFP:!!t,hasRemoteFP:!!r,timestamp:Date.now()}),new Error(`SAS computation failed: ${i.message}`)}}_dispatchAppEvent(e){if(!this._emitGlobalEvents)return!1;try{return document.dispatchEvent(e)}catch{return!1}}_isSbq2(){return this._handshakeMode==="sbq2"}_latchHandshakeMode(e){if(this._handshakeMode&&this._handshakeMode!==e)throw new Error(`handshake format cannot change mid-session (${this._handshakeMode} -> ${e})`);this._handshakeMode=e}_sbq2State(){return this._sbq2||(this._sbq2={role:null,localDescriptor:null,remoteDescriptor:null,localBlob:null,remoteBlob:null,remoteCommitment:null,transcript:null,peerEcdhKey:null,peerEcdsaKey:null,blobSent:!1,proofSent:!1,proofVerified:!1,keysDerived:!1,pendingProof:null,completed:!1,timer:null,startedAt:0}),this._sbq2}_sbq2Abort(e,t){let r=this._sbq2;r?.timer&&(clearTimeout(r.timer),r.timer=null),this._secureLog("error","SBQ2 handshake aborted",{code:e});try{this.deliverMessageToUI(t,"system")}catch{}try{this.onStatusChange?.("failed")}catch{}try{this.disconnect()}catch{}}async _exportSpki(e){return new Uint8Array(await crypto.subtle.exportKey("spki",e))}async _sbq2BuildLocalBlob(e){if(!this.ecdhKeyPair?.publicKey||!this.ecdsaKeyPair?.publicKey)throw new Error("SBQ2: key pairs are not ready");let t=Cn({role:e,ecdhSpki:await this._exportSpki(this.ecdhKeyPair.publicKey),ecdsaSpki:await this._exportSpki(this.ecdsaKeyPair.publicKey)}),i=await Ht(async a=>new Uint8Array(await crypto.subtle.digest("SHA-256",a)),t),n=this._sbq2State();return n.role=e,n.localBlob=t,{blob:t,commitment:i}}async _sbq2BuildDescriptor(e,{bindingTag:t=null,lifetimeMs:r=600*1e3}={}){let i=this.peerConnection?.localDescription?.sdp;if(!i)throw new Error("SBQ2: no local description to encode");let n=e===de.OFFER?ve.OFFER:ve.ANSWER,{commitment:a}=await this._sbq2BuildLocalBlob(n),o=bn(i),c=_n({type:e,expiresAtMs:Date.now()+r,sdpFields:{...o,candidates:Pr(o.candidates)},commitment:a,...e===de.ANSWER?{bindingTag:t}:{}}),d=this._sbq2State();return d.localDescriptor=c,this._secureLog("info","SBQ2 descriptor built",{type:e===de.OFFER?"offer":"answer",bytes:c.length,candidates:Pr(o.candidates).length}),{bytes:c,text:vn(c)}}_sbq2AdoptRemoteDescriptor(e,t){let r=Fr(e);if(r.type!==t)throw new Error(`expected an ${t===de.OFFER?"invitation":"answer"}, got the other kind`);if(!r.commitment)throw new Error("the invitation carries no key commitment");let i=this._sbq2State();return i.remoteDescriptor=e,i.remoteCommitment=r.commitment,r}async _runSbq2KeyExchange(){let e=this._sbq2State();if(!(e.completed||e.blobSent)){if(e.startedAt=Date.now(),!e.localBlob||!e.localDescriptor||!e.remoteDescriptor||!e.remoteCommitment){this._sbq2Abort("incomplete_state","The secure handshake could not start because the connection setup is incomplete. Please start a new invitation.");return}e.timer=setTimeout(()=>{e.completed||this._sbq2Abort("timeout","The other side did not complete the secure handshake in time. Please try connecting again.")},s.SBQ2_KEY_EXCHANGE_TIMEOUT_MS);try{this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_BLOB,v:2,blob:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(e.localBlob.buffer.slice(e.localBlob.byteOffset,e.localBlob.byteOffset+e.localBlob.byteLength))})),e.blobSent=!0,this._secureLog("info","SBQ2 key blob sent",{bytes:e.localBlob.length})}catch{this._sbq2Abort("blob_send_failed","The secure handshake could not be sent. Please try connecting again.")}}}async _sbq2HandleHandshakeFrame(e){let t=s.MESSAGE_TYPES,r=this._sbq2State();if(!this._isSbq2()){this._secureLog("error","Rejected SBQ2 handshake frame on a non-SBQ2 session",{messageType:e?.type});return}try{if(e.type===t.KEY_BLOB){if(r.remoteBlob){this._sbq2Abort("duplicate_blob","The secure handshake was sent twice. The connection has been closed for safety.");return}let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.blob||"")));await Mn(crypto.subtle,i,r.remoteCommitment);let n=kn(i),a=r.role===ve.OFFER?ve.ANSWER:ve.OFFER;if(n.role!==a){this._sbq2Abort("role_mismatch","The other side sent the wrong kind of handshake. The connection has been closed for safety.");return}r.remoteBlob=i,r.peerEcdhKey=await crypto.subtle.importKey("spki",n.ecdhSpki,{name:"ECDH",namedCurve:"P-384"},!1,[]),r.peerEcdsaKey=await crypto.subtle.importKey("spki",n.ecdsaSpki,{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),await this._sbq2CompleteExchange();return}if(e.type===t.KEY_PROOF){let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.sig||"")));if(!r.transcript||!r.peerEcdsaKey){r.pendingProof=i;return}await this._sbq2VerifyProof(i);return}}catch(i){let n=i?.code||"handshake_failed",a=n==="commitment_mismatch"?"The key material does not match the invitation you scanned. This can mean someone tampered with the connection, so it has been closed.":"The secure handshake failed. The connection has been closed for safety.";this._sbq2Abort(n,a)}}async _sbq2CompleteExchange(){let e=this._sbq2State();if(e.keysDerived||!e.remoteBlob||!e.localBlob)return;this._peerSupportsRatchet=!0;let t=e.role===ve.OFFER;e.transcript=An({offerDescriptor:t?e.localDescriptor:e.remoteDescriptor,answerDescriptor:t?e.remoteDescriptor:e.localDescriptor,offerBlob:t?e.localBlob:e.remoteBlob,answerBlob:t?e.remoteBlob:e.localBlob}),this.sessionSalt=await xn(crypto.subtle,e.transcript),this.peerPublicKey=e.peerEcdhKey,this.peerECDHPublicKey=e.peerEcdhKey;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,e.peerEcdhKey,this.sessionSalt);await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),await this._initializeRatchet(r,t),e.keysDerived=!0;let i=new Uint8Array(await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},this.ecdsaKeyPair.privateKey,Vr(e.transcript)));if(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_PROOF,sig:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(i.buffer)})),e.proofSent=!0,e.pendingProof){let n=e.pendingProof;e.pendingProof=null,await this._sbq2VerifyProof(n)}}async _sbq2VerifyProof(e){let t=this._sbq2State();if(t.proofVerified)return;if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},t.peerEcdsaKey,e,Vr(t.transcript))){this._sbq2Abort("bad_proof","The other side could not prove it owns its identity key. The connection has been closed for safety.");return}t.proofVerified=!0,this.verificationCode=await Rn(crypto.subtle,{ecdhPrivateKey:this.ecdhKeyPair.privateKey,peerEcdhPublicKey:t.peerEcdhKey,transcript:t.transcript});let i=this.expectedDTLSFingerprint,n=this._peerDTLSFingerprint;i&&n&&this._setSASMaterialReady(i,n),t.completed=!0,t.timer&&(clearTimeout(t.timer),t.timer=null),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this._secureLog("info","SBQ2 in-band key exchange complete",{elapsedMs:Date.now()-t.startedAt,ratchetActive:this.isRatchetActive?.()===!0});try{this.onKeyExchange?.(this.keyFingerprint)}catch{}this._notifyVerificationReadyIfPossible(),this.initiateVerification()}_decodeKeyFingerprint(e){try{if(!e||typeof e!="string")throw new Error("Invalid hex string provided");return window.EnhancedSecureCryptoUtils.hexToUint8Array(e)}catch(t){throw this._secureLog("error","Key fingerprint decoding failed",{error:t.message,inputType:typeof e,inputLength:e?.length||0}),new Error(`Key fingerprint decoding failed: ${t.message}`)}}_emergencyWipeOnFingerprintMismatch(e="DTLS fingerprint mismatch"){try{this._secureLog("error","\u{1F6A8} EMERGENCY: Initiating security wipe due to fingerprint mismatch",{reason:e,timestamp:Date.now()}),this._secureWipeKeys(),this._secureWipeMemory(this.encryptionKey,"emergency_wipe"),this._secureWipeMemory(this.macKey,"emergency_wipe"),this._secureWipeMemory(this.metadataKey,"emergency_wipe"),this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this.isVerified=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.disconnect(),this.deliverMessageToUI("\u{1F6A8} SECURITY BREACH: Connection terminated due to fingerprint mismatch. Possible MITM attack detected!","system")}catch(t){this._secureLog("error","Failed to perform emergency wipe",{error:t.message})}}getCurrentDTLSFingerprint(){try{if(!this.expectedDTLSFingerprint)throw new Error("No DTLS fingerprint available - connection not established");return this.expectedDTLSFingerprint}catch(e){throw this._secureLog("error","Failed to get current DTLS fingerprint",{error:e.message}),e}}disableStrictDTLSValidation(){this.strictDTLSValidation=!1,this._secureLog("warn","\u26A0\uFE0F Strict DTLS validation disabled - security reduced",{timestamp:Date.now()}),this.deliverMessageToUI("\u26A0\uFE0F DTLS validation disabled for debugging","system")}enableStrictDTLSValidation(){this.strictDTLSValidation=!0,this._secureLog("info","\u2705 Strict DTLS validation re-enabled",{timestamp:Date.now()}),this.deliverMessageToUI("\u2705 DTLS validation re-enabled","system")}async _initializeRatchet(e,t){let r=e?.ratchetRoot;if(!r)return!1;if(!this._peerSupportsRatchet)return this._secureLog("warn","Peer did not advertise Double Ratchet \u2014 falling back to static session keys",{localVersion:s.RATCHET_VERSION}),window.EnhancedSecureCryptoUtils.zeroizeBuffer(r),!1;try{let i=this.peerPublicKey||this.peerECDHPublicKey;if(!i||!this.ecdhKeyPair?.privateKey)throw new Error("handshake ECDH keys unavailable");let n=new zt;return await n.init({sharedSecret:r,sessionSalt:new Uint8Array(this.sessionSalt||[]),selfPrivateKey:this.ecdhKeyPair.privateKey,remotePublicKey:i,isInitiator:t}),this._ratchet=n,this.securityFeatures.hasPFS=!0,this._secureLog("info","\u{1F510} Double Ratchet active \u2014 per-message forward secrecy enabled",{role:t?"initiator":"responder"}),!0}catch(i){return this._ratchet=null,this.securityFeatures.hasPFS=!1,this._secureLog("error","Double Ratchet initialisation failed \u2014 continuing with static session keys",{errorType:i?.constructor?.name||"Unknown"}),!1}finally{window.EnhancedSecureCryptoUtils.zeroizeBuffer(r)}}isRatchetActive(){return!!this._ratchet?.isInitialised}async _generateEphemeralECDHKeys(){try{this._secureLog("info","\u{1F511} Generating ephemeral ECDH keys for PFS",{sessionStartTime:this.sessionStartTime,timestamp:Date.now()});let e=await window.EnhancedSecureCryptoUtils.generateECDHKeyPair();if(!e||!this._validateKeyPairConstantTime(e))throw new Error("Ephemeral ECDH key pair validation failed");let t=this.currentSession?.sessionId||`session_${Date.now()}`;return this.ephemeralKeyPairs.set(t,{keyPair:e,timestamp:Date.now(),sessionId:t}),this._secureLog("info","\u2705 Ephemeral ECDH keys generated for PFS",{timestamp:Date.now()}),e}catch(e){throw this._secureLog("error","\u274C Failed to generate ephemeral ECDH keys",{error:e.message}),new Error(`Ephemeral key generation failed: ${e.message}`)}}async _hardWipeOldKeys(){try{this._secureLog("info","\u{1F9F9} Performing hard wipe of old keys for PFS",{oldKeysCount:this.oldKeys.size,timestamp:Date.now()});for(let[e,t]of this.oldKeys.entries())t.encryptionKey&&this._secureWipeMemory(t.encryptionKey,"pfs_key_wipe"),t.macKey&&this._secureWipeMemory(t.macKey,"pfs_key_wipe"),t.metadataKey&&this._secureWipeMemory(t.metadataKey,"pfs_key_wipe"),t.encryptionKey=null,t.macKey=null,t.metadataKey=null,t.keyFingerprint=null;this.oldKeys.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Hard wipe of old keys completed for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to perform hard wipe of old keys",{error:e.message})}}async _wipeEphemeralKeys(){try{this._secureLog("info","\u{1F9F9} Wiping ephemeral keys for PFS",{ephemeralKeysCount:this.ephemeralKeyPairs.size,timestamp:Date.now()});for(let[e,t]of this.ephemeralKeyPairs.entries())t.keyPair?.privateKey&&this._secureWipeMemory(t.keyPair.privateKey,"ephemeral_key_wipe"),t.keyPair?.publicKey&&this._secureWipeMemory(t.keyPair.publicKey,"ephemeral_key_wipe"),t.keyPair=null,t.timestamp=null,t.sessionId=null;this.ephemeralKeyPairs.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Ephemeral keys wiped for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to wipe ephemeral keys",{error:e.message})}}async _encryptFileMessage(e,t){try{if(!this.encryptionKey)throw new Error("No encryption key available for file message");let r=typeof e=="string"?e:JSON.stringify(e),n={type:"encrypted_file_message",encryptedData:await window.EnhancedSecureCryptoUtils.encryptDataWithAAD(r,this.encryptionKey,t),aad:t,timestamp:Date.now(),keyFingerprint:this.keyFingerprint};return JSON.stringify(n)}catch(r){throw this._secureLog("error","Failed to encrypt file message",{error:r.message}),new Error(`File message encryption failed: ${r.message}`)}}async _decryptFileMessage(e){try{let t=JSON.parse(e);if(t.type!=="encrypted_file_message")throw new Error("Invalid encrypted file message type");if(t.keyFingerprint!==this.keyFingerprint)throw new Error("Key fingerprint mismatch in encrypted file message");let r=this._validateMessageAAD(t.aad,"file_message");if(!this.encryptionKey)throw new Error("No encryption key available for file message decryption");return{decryptedData:await window.EnhancedSecureCryptoUtils.decryptDataWithAAD(t.encryptedData,this.encryptionKey,t.aad),aad:r}}catch(t){throw this._secureLog("error","Failed to decrypt file message",{error:t.message}),new Error(`File message decryption failed: ${t.message}`)}}_validateEncryptionKeys(e=!0){let t=!!(this.encryptionKey&&this.macKey&&this.metadataKey);if(!t&&e)throw new Error("Encryption keys not initialized");return t}async _tryReinitializeEncryptionKeys(){try{if(this.encryptionKey&&this.macKey&&this.metadataKey)return!0;let e=!!(this.ecdhKeyPair?.privateKey&&(this.peerPublicKey||this.peerECDHPublicKey)),t=this.peerPublicKey||this.peerECDHPublicKey;if(!e||!t||!this.sessionSalt)return!1;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,t,this.sessionSalt);return await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),!!(this.encryptionKey&&this.macKey&&this.metadataKey)}catch(e){return this._secureLog("error","Failed to reinitialize encryption keys",{error:e.message}),!1}}_isFileMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type&&t.type.startsWith("file_")}catch{return!1}return typeof e=="object"&&e.type?e.type.startsWith("file_"):!1}_isSystemMessage(e){let t=[s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.SECURITY_UPGRADE,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY];if(typeof e=="string")try{let r=JSON.parse(e);return t.includes(r.type)}catch{return!1}return typeof e=="object"&&e.type?t.includes(e.type):!1}_isFakeMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type===s.MESSAGE_TYPES.FAKE||t.isFakeTraffic===!0}catch{return!1}return typeof e=="object"&&e!==null?e.type===s.MESSAGE_TYPES.FAKE||e.isFakeTraffic===!0:!1}_withErrorHandling(e,t,r=null){try{return e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}async _withAsyncErrorHandling(e,t,r=null){try{return await e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}_getMessageType(e){if(typeof e=="string")try{return JSON.parse(e).type||null}catch{return null}return typeof e=="object"&&e!==null&&e.type||null}_resetNotificationFlags(){this.lastSecurityLevelNotification=null,this.verificationNotificationSent=!1,this.verificationInitiationSent=!1,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.disconnectNotificationSent=!1,this.reconnectionFailedNotificationSent=!1,this.peerDisconnectNotificationSent=!1,this.connectionClosedNotificationSent=!1,this.fakeTrafficDisabledNotificationSent=!1,this.advancedFeaturesDisabledNotificationSent=!1,this.securityUpgradeNotificationSent=!1,this.lastSecurityUpgradeStage=null,this.securityCalculationNotificationSent=!1,this.lastSecurityCalculationLevel=null}_isFilteredMessage(e){return Object.values(s.FILTERED_RESULTS).includes(e)}_cleanupLogs(){this._logCounts.size>500&&(this._logCounts.clear(),this._secureLog("debug","\u{1F9F9} Log counts cleared due to size limit"));let e=Date.now(),t=3e5,r=0;for(let[i,n]of this._logCounts.entries())n>10&&r++;r>20&&(this._logCounts.clear(),this._secureLog("warn","\u{1F6A8} Emergency log cleanup due to suspicious patterns")),this._logSecurityViolations>0&&r<5&&(this._logSecurityViolations=Math.max(0,this._logSecurityViolations-1)),(!this._lastIVCleanupTime||Date.now()-this._lastIVCleanupTime>3e5)&&(this._cleanupOldIVs(),this._lastIVCleanupTime=Date.now()),(!this._secureMemoryManager.memoryStats.lastCleanup||Date.now()-this._secureMemoryManager.memoryStats.lastCleanup>6e5)&&(this._performPeriodicMemoryCleanup().catch(i=>{this._secureLog("error","Periodic cleanup failed",{errorType:i?.constructor?.name||"Unknown"})}),this._secureMemoryManager.memoryStats.lastCleanup=Date.now())}_getLoggingStats(){let e={isProductionMode:this._isProductionMode,debugMode:this._debugMode,currentLogLevel:this._currentLogLevel,logCountsSize:this._logCounts.size,maxLogCount:this._maxLogCount,securityViolations:this._logSecurityViolations||0,maxSecurityViolations:this._maxLogSecurityViolations||3,systemStatus:this._currentLogLevel===-1?"DISABLED":"ACTIVE"},t={};for(let[r,i]of Object.entries(e))typeof i=="string"&&this._containsSensitiveContent(i)?t[r]="[SENSITIVE_DATA_REDACTED]":t[r]=i;return t}async _emergencyDisableLogging(){this._currentLogLevel=-1,this._logCounts.clear(),this._logSecurityViolations&&(this._logSecurityViolations=0),this._secureLog=()=>{arguments[0]==="error"&&this._originalConsole?.error&&this._originalConsole.error("\u{1F6A8} SECURITY: Logging system disabled - potential data exposure prevented")},this._originalSanitizeString=this._sanitizeString,this._originalSanitizeLogData=this._sanitizeLogData,this._originalAuditLogMessage=this._auditLogMessage,this._originalContainsSensitiveContent=this._containsSensitiveContent,this._sanitizeString=()=>"[LOGGING_DISABLED]",this._sanitizeLogData=()=>({error:"LOGGING_DISABLED"}),this._auditLogMessage=()=>!1,this._containsSensitiveContent=()=>!0,await this._performNaturalCleanup(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Secure logging system disabled due to potential data exposure")}_resetLoggingSystem(){this._secureLog("info","\u{1F527} Resetting logging system after emergency shutdown"),this._sanitizeString=this._originalSanitizeString||(e=>e),this._sanitizeLogData=this._originalSanitizeLogData||(e=>e),this._auditLogMessage=this._originalAuditLogMessage||(()=>!0),this._containsSensitiveContent=this._originalContainsSensitiveContent||(()=>!1),this._logSecurityViolations=0,this._secureLog("info","\u2705 Logging system reset successfully")}_auditLogMessage(e,t){if(!t||typeof t!="object")return!0;let r=JSON.stringify(t);if(this._containsSensitiveContent(e))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log message"),!1;if(this._containsSensitiveContent(r))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log data"),!1;let i=["secret","token","password","credential","auth","fingerprint","salt","signature","private_key","api_key","private","encryption","mac","metadata","session","jwt","bearer","key","hash","digest","nonce","iv","cipher"],n=r.toLowerCase();for(let a of i)if(n.includes(a)&&!this._safeFieldsWhitelist.has(a))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: Dangerous pattern detected in log: ${a}`),!1;for(let[a,o]of Object.entries(t))if(typeof o=="string"&&this._hasHighEntropy(o))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: High entropy value detected in log field: ${a}`),!1;return!0}initializeFileTransfer(){try{if(this._sessionAlive===!1)return;if(this._secureLog("info","\u{1F527} Initializing Enhanced Secure File Transfer system..."),this.fileTransferSystem){this._secureLog("info","\u2705 File transfer system already initialized");return}if(!!!(this.dataChannel&&this.dataChannel.readyState==="open")){if(this._secureLog("warn","\u26A0\uFE0F Data channel not open, deferring file transfer initialization"),this.dataChannel){let i=()=>{this._secureLog("info","\u{1F504} DataChannel opened, initializing file transfer..."),this.initializeFileTransfer()};this.dataChannel.addEventListener("open",i,{once:!0})}return}if(!this.isVerified){this._secureLog("warn","\u26A0\uFE0F Connection not verified yet, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(500);return}if(this.fileTransferSystem&&(this._secureLog("info","\u{1F9F9} Cleaning up existing file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),!this.encryptionKey||!this.macKey){this._secureLog("warn","\u26A0\uFE0F Encryption keys not ready, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(1e3);return}let t=i=>{try{this._secureLog("info","\u{1F3C1} Sender transfer summary",{summary:i}),this.onFileProgress&&this.onFileProgress({type:"complete",...i})}catch(n){this._secureLog("warn","\u26A0\uFE0F onComplete handler failed:",{details:n.message})}};this.fileTransferSystem=new je(this,this.onFileProgress||null,t,this.onFileError||null,this.onFileReceived||null,this.onIncomingFileRequest||null),this._fileTransferActive=!0,this._secureLog("info","\u2705 Enhanced Secure File Transfer system initialized successfully");let r=this.fileTransferSystem.getSystemStatus();this._secureLog("info","\u{1F50D} File transfer system status after init",{status:r})}catch(e){this._secureLog("error","\u274C Failed to initialize file transfer system",{errorType:e.constructor.name}),this.fileTransferSystem=null,this._fileTransferActive=!1}}_scheduleFileTransferInitRetry(e){if(this._sessionAlive===!1)return null;this._fileTransferInitRetryTimers||(this._fileTransferInitRetryTimers=new Set);let t=this._trackActiveTimer(setTimeout(()=>{this._fileTransferInitRetryTimers.delete(t),this._untrackActiveTimer(t),this._sessionAlive!==!1&&this.initializeFileTransfer()},e));return this._fileTransferInitRetryTimers.add(t),t}async initializeEnhancedSecurity(){try{await this.generateNestedEncryptionKey(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration()}catch(e){this._secureLog("error","\u274C Failed to initialize enhanced security",{errorType:e.constructor.name})}}getSafeRandomInt(e,t){if(!Number.isInteger(e)||!Number.isInteger(t))throw new Error("getSafeRandomInt requires integer min and max");if(e>=t)throw new Error("min must be less than max");let r=t-e+1,i=Math.ceil(Math.log2(r)),n=Math.ceil(i/8),a=(1<=r);return e+o}getSafeRandomFloat(e,t,r=1e3){if(typeof e!="number"||typeof t!="number")throw new Error("getSafeRandomFloat requires numeric min and max");if(e>=t)throw new Error("minFloat must be less than maxFloat");let i=this.getSafeRandomInt(0,r),n=(t-e)/r;return e+i*n}generateFingerprintMask(){return{timingOffset:this.getSafeRandomInt(0,1500),sizeVariation:this.getSafeRandomFloat(.75,1.25,1e3),noisePattern:Array.from(crypto.getRandomValues(new Uint8Array(64))),headerVariations:["X-Client-Version","X-Session-ID","X-Request-ID","X-Timestamp","X-Signature","X-Secure","X-Encrypted","X-Protected","X-Safe","X-Anonymous","X-Private"],noiseIntensity:this.getSafeRandomInt(50,150),sizeMultiplier:this.getSafeRandomFloat(.75,1.25,1e3),timingVariation:this.getSafeRandomInt(100,1100)}}configureSecurityForSession(){this._secureLog("info","\u{1F527} Configuring security - all features enabled by default"),this.sessionConstraints={},Object.keys(this.securityFeatures).forEach(e=>{this.sessionConstraints[e]=!0}),this.applySessionConstraints(),this._secureLog("info","\u2705 Security configured - all features enabled",{constraints:this.sessionConstraints}),this._validateCryptographicSecurity()||(this._secureLog("error","\u{1F6A8} CRITICAL: Cryptographic security validation failed after session configuration"),this.onStatusChange&&this.onStatusChange("security_breach",{type:"crypto_security_failure",message:"Cryptographic security validation failed after session configuration"})),this.notifySecurityLevel(),setTimeout(()=>{this.calculateAndReportSecurityLevel()},s.TIMEOUTS.SECURITY_CALC_DELAY)}applySessionConstraints(){this.sessionConstraints&&(Object.keys(this.sessionConstraints).forEach(e=>{switch(this.securityFeatures[e]=!0,e){case"hasFakeTraffic":this.fakeTrafficConfig.enabled=!0,this.isConnected()&&this.startFakeTrafficGeneration();break;case"hasDecoyChannels":this.decoyChannelConfig.enabled=!0,this.isConnected()&&this.initializeDecoyChannels();break;case"hasPacketReordering":this.reorderingConfig.enabled=!0;break;case"hasAntiFingerprinting":this.antiFingerprintingConfig.enabled=!0;break;case"hasMessageChunking":this.chunkingConfig.enabled=!0;break}}),this._secureLog("info","\u2705 All security features enabled by default",{constraints:this.sessionConstraints,currentFeatures:this.securityFeatures}))}_sanitizeIncomingChatMessage(e){return typeof e!="string"?e:window.EnhancedSecureCryptoUtils.sanitizeMessage(e)}deliverMessageToUI(e,t="received",r=null){try{if(this._secureLog("debug","\u{1F4E4} deliverMessageToUI called",{message:e,type:t,messageType:typeof e,hasOnMessage:!!this.onMessage}),typeof e=="object"&&e.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(e.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI: ${e.type}`);return}if(typeof e=="string"&&e.trim().startsWith("{"))try{let n=JSON.parse(e);if(n.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(n.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI (string): ${n.type}`);return}}catch{}let i=t==="received"?this._sanitizeIncomingChatMessage(e):e;if(this.onMessage){let n=r&&typeof this._sanitizeMessageMeta=="function"?this._sanitizeMessageMeta(r):null;this._secureLog("debug","\u{1F4E4} Calling this.onMessage callback",{message:i,type:t}),this.onMessage(i,t,n||void 0)}else this._secureLog("warn","\u26A0\uFE0F this.onMessage callback is null or undefined")}catch(i){this._secureLog("error","\u274C Failed to deliver message to UI:",{errorType:i?.constructor?.name||"Unknown"})}}notifySecurityLevel(){if(this.lastSecurityLevelNotification==="maximum")return;if(this.lastSecurityLevelNotification="maximum",this.onMessage&&this.deliverMessageToUI("\u{1F6E1}\uFE0F Maximum Security Active - All features enabled","system"),this.onMessage){let t=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r.replace("has","").replace(/([A-Z])/g," $1").trim().toLowerCase()).slice(0,5);this.deliverMessageToUI(`\u{1F527} Active: ${t.join(", ")}...`,"system")}}cleanupDecoyChannels(){for(let[e,t]of this.decoyTimers.entries())clearTimeout(t);this.decoyTimers.clear();for(let[e,t]of this.decoyChannels.entries())t.readyState==="open"&&t.close();this.decoyChannels.clear(),this._secureLog("info","\u{1F9F9} Decoy channels cleaned up")}async generateNestedEncryptionKey(){try{this.nestedEncryptionKey=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(e){throw this._secureLog("error","\u274C Failed to generate nested encryption key:",{errorType:e?.constructor?.name||"Unknown"}),e}}async applyNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;try{let t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"nestedEncryption"),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this.nestedEncryptionKey,e),i=new Uint8Array(s.SIZES.NESTED_ENCRYPTION_IV_SIZE+r.byteLength);return i.set(t,0),i.set(new Uint8Array(r),s.SIZES.NESTED_ENCRYPTION_IV_SIZE),this._secureLog("debug","\u2705 Nested encryption applied with secure IV",{ivSize:t.length,dataSize:e.byteLength,encryptedSize:r.byteLength}),i.buffer}catch(t){return this._secureLog("error","\u274C Nested encryption failed:",{errorType:t?.constructor?.name||"Unknown",errorMessage:t?.message||"Unknown error"}),t.message.includes("emergency mode")&&(this.securityFeatures.hasNestedEncryption=!1,this._secureLog("warn","\u26A0\uFE0F Nested encryption disabled due to IV emergency mode")),e}}async removeNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;if(!(e instanceof ArrayBuffer)||e.byteLengtht.length-4?(this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid packet padding size, skipping removal"),e):t.slice(4,4+i).buffer}catch(t){return this._debugMode&&this._secureLog("error","\u274C Packet padding removal failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}startFakeTrafficGeneration(){if(!this.fakeTrafficConfig.enabled||!this.isConnected())return;if(this.fakeTrafficTimer){this._secureLog("warn","\u26A0\uFE0F Fake traffic generation already running");return}let e=async()=>{if(!this.isConnected()){this.stopFakeTrafficGeneration();return}try{let n=this.generateFakeMessage();await this.sendFakeMessage(n);let a=this.fakeTrafficConfig.randomDecoyIntervals?this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minInterval,Math.min(this.fakeTrafficConfig.maxInterval,6e4)):this.fakeTrafficConfig.minInterval,o=Math.max(a,s.TIMEOUTS.FAKE_TRAFFIC_MIN_INTERVAL);this.fakeTrafficTimer=setTimeout(e,o)}catch(n){this._debugMode&&this._secureLog("error","\u274C Fake traffic generation failed:",{errorType:n?.constructor?.name||"Unknown"}),this.stopFakeTrafficGeneration()}},t=s.TIMEOUTS.DECOY_INITIAL_DELAY,r=Math.min(this.fakeTrafficConfig.maxInterval,3e4),i=this.getUnbiasedRandomInRange(t,r);this.fakeTrafficTimer=setTimeout(e,i)}stopFakeTrafficGeneration(){this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null)}generateFakeMessage(){let e=this.getUnbiasedRandomInRange(0,this.fakeTrafficConfig.patterns.length-1),t=this.fakeTrafficConfig.patterns[e],r=this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minSize,this.fakeTrafficConfig.maxSize),i=crypto.getRandomValues(new Uint8Array(r));return{type:s.MESSAGE_TYPES.FAKE,pattern:t,data:Array.from(i).map(n=>n.toString(16).padStart(2,"0")).join(""),timestamp:Date.now(),size:r,isFakeTraffic:!0,source:"fake_traffic_generator",fakeId:crypto.getRandomValues(new Uint32Array(1))[0].toString(36)}}emergencyDisableAdvancedFeatures(){this._secureLog("error","\u{1F6A8} Emergency disabling advanced security features due to errors"),this.securityFeatures.hasNestedEncryption=!1,this.securityFeatures.hasPacketReordering=!1,this.securityFeatures.hasAntiFingerprinting=!1,this.reorderingConfig.enabled=!1,this.antiFingerprintingConfig.enabled=!1,this.packetBuffer.clear(),this.emergencyDisableFakeTraffic(),this._secureLog("info","\u2705 Advanced features disabled, keeping basic encryption"),this.advancedFeaturesDisabledNotificationSent||(this.advancedFeaturesDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Advanced security features temporarily disabled due to compatibility issues","system"))}async sendFakeMessage(e){if(this._validateConnection(!1))try{this._secureLog("debug","\u{1F3AD} Sending fake message",{hasPattern:!!e.pattern,sizeRange:e.size>100?"large":"small"});let t=JSON.stringify({...e,type:s.MESSAGE_TYPES.FAKE,isFakeTraffic:!0,timestamp:Date.now()}),r=new TextEncoder().encode(t),i=await this.applySecurityLayers(r,!0);this.dataChannel.send(i),this._secureLog("debug","\u{1F3AD} Fake message sent successfully",{pattern:e.pattern})}catch(t){this._secureLog("error","\u274C Failed to send fake message",{error:t.message})}}checkFakeTrafficStatus(){let e={fakeTrafficEnabled:this.securityFeatures.hasFakeTraffic,fakeTrafficConfigEnabled:this.fakeTrafficConfig.enabled,timerActive:!!this.fakeTrafficTimer,patterns:this.fakeTrafficConfig.patterns,intervals:{min:this.fakeTrafficConfig.minInterval,max:this.fakeTrafficConfig.maxInterval}};return this._debugMode&&this._secureLog("info","\u{1F3AD} Fake Traffic Status",{status:e}),e}emergencyDisableFakeTraffic(){this._debugMode&&this._secureLog("error","\u{1F6A8} Emergency disabling fake traffic"),this.securityFeatures.hasFakeTraffic=!1,this.fakeTrafficConfig.enabled=!1,this.stopFakeTrafficGeneration(),this._debugMode&&this._secureLog("info","\u2705 Fake traffic disabled"),this.fakeTrafficDisabledNotificationSent||(this.fakeTrafficDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Fake traffic emergency disabled","system"))}async _applySecurityLayersWithoutMutex(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayersWithoutMutex:",{errorType:r?.constructor?.name||"Unknown"}),e}}async processChunkedMessage(e){try{if(!this.chunkingConfig.addChunkHeaders)return this.processMessage(e);let t=new Uint8Array(e);if(t.length<16)return this.processMessage(e);let r=new DataView(t.buffer,0,16),i=r.getUint32(0,!1),n=r.getUint32(4,!1),a=r.getUint32(8,!1),o=r.getUint32(12,!1),c=t.slice(16,16+o);this.chunkQueue[i]||(this.chunkQueue[i]={chunks:new Array(a),received:0,timestamp:Date.now()});let d=this.chunkQueue[i];if(d.chunks[n]=c,d.received++,this._secureLog("debug",`\u{1F4E6} Received chunk ${n+1}/${a} for message ${i}`),d.received===a){let u=d.chunks.reduce((p,S)=>p+S.length,0),h=new Uint8Array(u),m=0;for(let p of d.chunks)h.set(p,m),m+=p.length;await this.processMessage(h.buffer),delete this.chunkQueue[i],this._secureLog("info",`\u{1F4E6} Chunked message ${i} reassembled and processed`)}}catch(t){this._secureLog("error","\u274C Chunked message processing failed:",{errorType:t?.constructor?.name||"Unknown"})}}initializeDecoyChannels(){if(!(!this.decoyChannelConfig.enabled||!this.peerConnection)){if(this.decoyChannels.size>0){this._secureLog("warn","\u26A0\uFE0F Decoy channels already initialized, skipping...");return}try{let e=Math.min(this.decoyChannelConfig.maxDecoyChannels,this.decoyChannelConfig.decoyChannelNames.length);for(let t=0;t.5,maxRetransmits:Math.floor(Math.random()*3)});this.setupDecoyChannel(i,r),this.decoyChannels.set(r,i)}this._debugMode&&this._secureLog("info",`\u{1F3AD} Initialized ${e} decoy channels`)}catch(e){this._debugMode&&this._secureLog("error","\u274C Failed to initialize decoy channels:",{errorType:e?.constructor?.name||"Unknown"})}}}setupDecoyChannel(e,t){e.onopen=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" opened`),this.startDecoyTraffic(e,t)},e.onmessage=r=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Received decoy message on "${t}": ${r.data?.length||"undefined"} bytes`)},e.onclose=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" closed`),this.stopDecoyTraffic(t)},e.onerror=r=>{this._debugMode&&this._secureLog("error",`\u274C Decoy channel "${t}" error`,{error:r.message})}}startDecoyTraffic(e,t){let r=async()=>{if(e.readyState==="open")try{let n=this.generateDecoyData(t);e.send(n);let a=this.decoyChannelConfig.randomDecoyIntervals?Math.random()*15e3+1e4:2e4;this.decoyTimers.set(t,setTimeout(()=>r(),a))}catch(n){this._debugMode&&this._secureLog("error",`\u274C Failed to send decoy data on "${t}"`,{error:n.message})}},i=Math.random()*1e4+5e3;this.decoyTimers.set(t,setTimeout(()=>r(),i))}stopDecoyTraffic(e){let t=this.decoyTimers.get(e);t&&(clearTimeout(t),this.decoyTimers.delete(e))}generateDecoyData(e){let t={sync:()=>JSON.stringify({type:"sync",timestamp:Date.now(),sequence:Math.floor(Math.random()*1e3),data:Array.from(crypto.getRandomValues(new Uint8Array(32))).map(r=>r.toString(16).padStart(2,"0")).join("")}),status:()=>JSON.stringify({type:"status",status:["online","away","busy"][Math.floor(Math.random()*3)],uptime:Math.floor(Math.random()*3600),data:Array.from(crypto.getRandomValues(new Uint8Array(16))).map(r=>r.toString(16).padStart(2,"0")).join("")}),heartbeat:()=>JSON.stringify({type:"heartbeat",timestamp:Date.now(),data:Array.from(crypto.getRandomValues(new Uint8Array(24))).map(r=>r.toString(16).padStart(2,"0")).join("")}),metrics:()=>JSON.stringify({type:"metrics",cpu:Math.random()*100,memory:Math.random()*100,network:Math.random()*1e3,data:Array.from(crypto.getRandomValues(new Uint8Array(20))).map(r=>r.toString(16).padStart(2,"0")).join("")}),debug:()=>JSON.stringify({type:"debug",level:["info","warn","error"][Math.floor(Math.random()*3)],message:"Debug message",data:Array.from(crypto.getRandomValues(new Uint8Array(28))).map(r=>r.toString(16).padStart(2,"0")).join("")})};return t[e]?t[e]():Array.from(crypto.getRandomValues(new Uint8Array(64))).map(r=>r.toString(16).padStart(2,"0")).join("")}addReorderingHeaders(e){if(!this.reorderingConfig.enabled)return e;try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8,i=new ArrayBuffer(r),n=new DataView(i);this.reorderingConfig.useSequenceNumbers&&n.setUint32(0,this.sequenceNumber++,!1),this.reorderingConfig.useTimestamps&&n.setUint32(4,Date.now(),!1),n.setUint32(this.reorderingConfig.useTimestamps?8:4,t.length,!1);let a=new Uint8Array(r+t.length);return a.set(new Uint8Array(i),0),a.set(t,r),a.buffer}catch(t){return this._secureLog("error","\u274C Failed to add reordering headers:",{errorType:t?.constructor?.name||"Unknown"}),e}}async processReorderedPacket(e){if(!this.reorderingConfig.enabled)return this.processMessage(e);try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8;if(t.lengtht.length-r||o<=0)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid reordered packet data size, processing directly"),this.processMessage(e);let c=t.slice(r,r+o);try{let d=new TextDecoder().decode(c),u=JSON.parse(d);if(u.type==="fake"||u.isFakeTraffic===!0){this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Reordered fake message: ${u.pattern||"unknown"}`);return}}catch{}this.packetBuffer.set(n,{data:c.buffer,timestamp:a||Date.now()}),await this.processOrderedPackets()}catch(t){return this._secureLog("error","\u274C Failed to process reordered packet:",{errorType:t?.constructor?.name||"Unknown"}),this.processMessage(e)}}async processOrderedPackets(){let e=Date.now(),t=this.reorderingConfig.reorderTimeout;for(;;){let r=this.lastProcessedSequence+1,i=this.packetBuffer.get(r);if(i){try{let n=new TextDecoder().decode(i.data),a=JSON.parse(n);if(a.type==="fake"||a.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Ordered fake message: ${a.pattern||"unknown"}`),this.packetBuffer.delete(r),this.lastProcessedSequence=r;continue}}catch{}await this.processMessage(i.data),this.packetBuffer.delete(r),this.lastProcessedSequence=r}else{let n=this.findOldestPacket();if(n&&e-n.timestamp>t){this._secureLog("warn","\u26A0\uFE0F Packet ${oldestPacket.sequence} timed out, processing out of order");try{let a=new TextDecoder().decode(n.data),o=JSON.parse(a);if(o.type==="fake"||o.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Timed out fake message: ${o.pattern||"unknown"}`),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence;continue}}catch{}await this.processMessage(n.data),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence}else break}}this.cleanupOldPackets(e,t)}findOldestPacket(){let e=null;for(let[t,r]of this.packetBuffer.entries())(!e||r.timestampt&&(this._secureLog("warn","\u26A0\uFE0F \u{1F5D1}\uFE0F Removing timed out packet ${sequence}"),this.packetBuffer.delete(r))}applyAntiFingerprinting(e){if(!this.antiFingerprintingConfig.enabled)return e;try{let t=e;return this.antiFingerprintingConfig.addNoise&&(t=this.addNoise(t)),this.antiFingerprintingConfig.randomizeSizes&&(t=this.randomizeSize(t)),this.antiFingerprintingConfig.maskPatterns&&(t=this.maskPatterns(t)),this.antiFingerprintingConfig.useRandomHeaders&&(t=this.addRandomHeaders(t)),t}catch(t){return this._secureLog("error","\u274C Anti-fingerprinting failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}addNoise(e){let t=new Uint8Array(e),r=this.getUnbiasedRandomInRange(8,40),i=crypto.getRandomValues(new Uint8Array(r)),n=new Uint8Array(t.length+r);return n.set(t,0),n.set(i,t.length),n.buffer}randomizeSize(e){let t=new Uint8Array(e),r=this.fingerprintMask.sizeVariation,i=Math.floor(t.length*r);if(i>t.length){let n=crypto.getRandomValues(new Uint8Array(i-t.length)),a=new Uint8Array(i);return a.set(t,0),a.set(n,t.length),a.buffer}else if(i=256-256%this.fingerprintMask.headerVariations.length);let d=this.fingerprintMask.headerVariations[c%this.fingerprintMask.headerVariations.length],u;do u=crypto.getRandomValues(new Uint8Array(1))[0];while(u>=256-256%16);let h=crypto.getRandomValues(new Uint8Array(u%16+4)),m=new DataView(n.buffer,a);m.setUint32(0,h.length+8,!1),m.setUint32(4,this.hashString(d),!1),n.set(h,a+8);let p=this.calculateChecksum(n.slice(a,a+8+h.length));new DataView(n.buffer,a+8+h.length).setUint32(0,p,!1),a+=8+h.length+4}return n.set(t,a),n.buffer}hashString(e){let t=0;for(let r=0;r50)try{if(/^[A-Za-z0-9+/=]+$/.test(r.trim())&&(this._debugMode&&this._secureLog("debug","\u{1F513} Applying standard decryption..."),r=await window.EnhancedSecureCryptoUtils.decryptData(r,this.encryptionKey),this._debugMode&&this._secureLog("debug","\u2705 Standard decryption successful"),typeof r=="string")){try{let n=JSON.parse(r);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Legacy fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}r=new TextEncoder().encode(r).buffer}}catch(i){return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Standard decryption failed:",{details:i.message}),e}if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&r.byteLength>12)try{if(r=await this.removeNestedEncryption(r),r instanceof ArrayBuffer)try{let i=new TextDecoder().decode(r),n=JSON.parse(i);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Nested fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Nested decryption failed - skipping this layer:",{details:i.message})}if(this.securityFeatures.hasPacketReordering&&this.reorderingConfig.enabled&&r instanceof ArrayBuffer)try{let i=this.reorderingConfig.useTimestamps?12:8;if(r.byteLength>i)return await this.processReorderedPacket(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Reordering processing failed - using direct processing:",{details:i.message})}if(this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer)try{r=this.removePacketPadding(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Padding removal failed:",{details:i.message})}if(this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer)try{r=this.removeAntiFingerprinting(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Anti-fingerprinting removal failed:",{details:i.message})}if(r instanceof ArrayBuffer&&(r=new TextDecoder().decode(r)),typeof r=="string")try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Final check fake message: ${i.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}return r}catch(t){return this._secureLog("error","\u274C Critical error in removeSecurityLayers:",{errorType:t?.constructor?.name||"Unknown"}),e}}removeAntiFingerprinting(e){return e}async applySecurityLayers(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:r?.constructor?.name||"Unknown"}),e}}_sanitizeMessageMeta(e){if(!e||typeof e!="object")return null;let t={};if(typeof e.mid=="string"&&e.mid.length>0&&e.mid.length<=64&&(t.mid=e.mid.replace(/[^A-Za-z0-9_-]/g,"").slice(0,64)),e.code===!0&&(t.code=!0),e.once===!0&&(t.once=!0),Number.isFinite(e.onceTtl)){let r=Math.floor(e.onceTtl);r>=1&&r<=3600&&(t.onceTtl=r)}if(Number.isFinite(e.ttl)){let r=Math.floor(e.ttl);r>=5&&r<=86400&&(t.ttl=r)}return Object.keys(t).length?t:null}sendMessageDelete(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_DELETE,messageId:e.slice(0,64)})}sendDeliveryReceipt(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_RECEIPT,messageId:e.slice(0,64)})}async sendMessage(e,t=null){let r=this._validateInputData(e,"sendMessage");if(!r.isValid){let i=`Input validation failed: ${r.errors.join(", ")}`;throw this._secureLog("error","\u274C Input validation failed in sendMessage",{errors:r.errors,dataType:typeof e,dataLength:e?.length||e?.byteLength||0}),new Error(i)}if(!this._checkRateLimit("sendMessage"))throw new Error("Rate limit exceeded for message sending");if(this._enforceVerificationGate("sendMessage"),!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not ready");try{if(this.encryptionKey&&this.macKey&&this.metadataKey||await this._tryReinitializeEncryptionKeys(),this._secureLog("debug","sendMessage called",{hasDataChannel:!!this.dataChannel,dataChannelReady:this.dataChannel?.readyState==="open",isInitiator:this.isInitiator,isVerified:this.isVerified,connectionReady:this.peerConnection?.connectionState==="connected"}),this._secureLog("debug","\u{1F50D} sendMessage DEBUG",{dataType:typeof r.sanitizedData,isString:typeof r.sanitizedData=="string",isArrayBuffer:r.sanitizedData instanceof ArrayBuffer,dataLength:r.sanitizedData?.length||r.sanitizedData?.byteLength||0}),typeof r.sanitizedData=="string")try{let n=JSON.parse(r.sanitizedData);if(n.type&&n.type.startsWith("file_")){this._secureLog("debug","\u{1F4C1} File message detected - applying full encryption with AAD",{type:n.type});let a=this._createFileMessageAAD(n.type,n.data),o=await this._encryptFileMessage(r.sanitizedData,a);return this.dataChannel.send(o),!0}}catch{}if(typeof r.sanitizedData=="string"){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available. Manager may not be fully initialized.");let n=this._createMessageAAD("message",{content:r.sanitizedData}),a={type:"message",data:r.sanitizedData,timestamp:Date.now(),aad:n};return t&&typeof t=="object"&&(a.meta=this._sanitizeMessageMeta(t)),await this.sendSecureMessage(a)}this._secureLog("debug","\u{1F510} Applying security layers to non-string data");let i=await this._applySecurityLayersWithLimitedMutex(r.sanitizedData,!1);return this.dataChannel.send(i),!0}catch(i){throw this._secureLog("error","\u274C Failed to send message",{error:i.message,errorType:i.constructor.name}),i}}async _applySecurityLayersWithLimitedMutex(e,t=!1){return this._withMutex("cryptoOperation",async r=>{try{let i=e;return t?(this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&i instanceof ArrayBuffer&&(i=await this.applyNestedEncryption(i)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&i instanceof ArrayBuffer&&(i=this.applyPacketReordering(i)),this.securityFeatures.hasPacketPadding&&i instanceof ArrayBuffer&&(i=this.applyPacketPadding(i)),this.securityFeatures.hasAntiFingerprinting&&i instanceof ArrayBuffer&&(i=this.applyAntiFingerprinting(i)),this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i)}catch(i){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:i?.constructor?.name||"Unknown"}),e}},3e3)}async sendSystemMessage(e){if(e.type==="verification_request"||e.type==="verification_response"||e.type==="verification_required"||this._enforceVerificationGate("sendSystemMessage",!1),!this.dataChannel||this.dataChannel.readyState!=="open")return this._secureLog("warn","\u26A0\uFE0F Cannot send system message - data channel not ready"),!1;try{let r=JSON.stringify({type:e.type,data:e,timestamp:Date.now()});return this._secureLog("debug","\u{1F527} Sending system message",{type:e.type}),this.dataChannel.send(r),!0}catch(r){return this._secureLog("error","\u274C Failed to send system message:",{errorType:r?.constructor?.name||"Unknown"}),!1}}async processMessage(e){try{if(this._noteInboundActivity?.(),this._secureLog("debug","\uFFFD\uFFFD Processing message",{dataType:typeof e,isArrayBuffer:e instanceof ArrayBuffer,hasData:!!(e?.length||e?.byteLength)}),typeof e=="string")try{let i=JSON.parse(e),n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(i.type==="encrypted_file_message"){this._secureLog("debug","\u{1F4C1} Encrypted file message detected in processMessage");try{let{decryptedData:a,aad:o}=await this._decryptFileMessage(e),c=JSON.parse(a);if(this._secureLog("debug","\u{1F4C1} File message decrypted successfully",{type:c.type,aadMessageType:o.messageType}),this.fileTransferSystem&&typeof this.fileTransferSystem.handleFileMessage=="function"){await this.fileTransferSystem.handleFileMessage(c);return}}catch(a){this._secureLog("error","\u274C Failed to decrypt file message",{error:a.message});return}}if(i.type&&n.includes(i.type)){this._secureLog("warn","\u26A0\uFE0F Unencrypted file message detected - this should not happen in secure mode",{type:i.type}),this._secureLog("error","\u274C Dropping unencrypted file message for security",{type:i.type});return}if(i.type==="enhanced_message"){if(this._secureLog("debug","\u{1F510} Enhanced message detected in processMessage"),!this._checkInboundRateLimit("processMessage:enhanced_message"))return;try{let a=await window.EnhancedSecureCryptoUtils.decryptMessage(i.data,this.encryptionKey,this.macKey,this.metadataKey),o=JSON.parse(a.data);if(a.metadata&&a.metadata.sequenceNumber!==void 0&&!this._validateIncomingSequenceNumber(a.metadata.sequenceNumber,"enhanced_message")){this._secureLog("warn","\u26A0\uFE0F Enhanced message sequence number validation failed - possible replay attack",{received:a.metadata.sequenceNumber,expected:this.expectedSequenceNumber});return}o.type==="message"&&this.onMessage&&o.data&&this.deliverMessageToUI(o.data,"received",o.meta);return}catch(a){this._secureLog("error","\u274C Failed to decrypt enhanced message",{error:a.message});return}}if(i.type===s.MESSAGE_TYPES.MESSAGE){this._secureLog("error","Rejected unencrypted frame in processMessage",{messageType:"message"});return}if(i.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(i.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:i.type});return}let a=s.MESSAGE_TYPES;if(i.type===a.MESSAGE_DELETE){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelete?.(o.slice(0,64))}catch{}return}if(i.type===a.MESSAGE_RECEIPT){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelivered?.(o.slice(0,64))}catch{}return}if([a.CALL_OFFER,a.CALL_ANSWER,a.CALL_ICE,a.CALL_DECLINE,a.CALL_END].includes(i.type)){try{await this._handleCallSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C Call signal handling failed",{errorType:o?.constructor?.name})}return}if([a.ICE_RESTART_OFFER,a.ICE_RESTART_ANSWER,a.ICE_RESTART_REQUEST].includes(i.type)){try{await this._handleIceRestartSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:o?.constructor?.name})}return}return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn","\u{1F3AD} Fake message blocked in processMessage",{pattern:i.pattern});return}}catch{this._secureLog("error","Rejected malformed (non-JSON) frame in processMessage",{dataLength:typeof e=="string"?e.length:0});return}let t=await this._processEncryptedDataWithLimitedMutex(e);if(t==="FAKE_MESSAGE_FILTERED"||t==="FILE_MESSAGE_FILTERED"||t==="SYSTEM_MESSAGE_FILTERED")return;if(!t){this._secureLog("warn","\u26A0\uFE0F No data returned from removeSecurityLayers");return}let r;if(typeof t=="string")try{let i=JSON.parse(t);if(i.type&&fileMessageTypes.includes(i.type)){this._secureLog("debug","\u{1F4C1} File message detected after decryption",{type:i.type}),this.fileTransferSystem&&await this.fileTransferSystem.handleFileMessage(i);return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Post-decryption fake message blocked: ${i.pattern}`);return}i.type==="message"&&i.data?r=i.data:r=t}catch{r=t}else if(t instanceof ArrayBuffer)r=new TextDecoder().decode(t);else if(t&&typeof t=="object"&&t.message)r=t.message;else{this._secureLog("warn","\u26A0\uFE0F Unexpected data type after processing:",{details:typeof t});return}if(r&&r.trim().startsWith("{"))try{let i=JSON.parse(r);if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Final fake message check blocked: ${i.pattern}`);return}let n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error","heartbeat","verification","verification_response","peer_disconnect","key_rotation_signal","key_rotation_ready","security_upgrade","ice_restart_offer","ice_restart_answer","ice_restart_request"];if(i.type&&n.includes(i.type)){this._secureLog("warn",`\u{1F4C1} Final system/file message check blocked: ${i.type}`);return}}catch{}r&&this._secureLog("error","Rejected unauthenticated payload at the end of processMessage",{messageLength:typeof r=="string"?r.length:0})}catch(t){this._secureLog("error","\u274C Failed to process message:",{errorType:t?.constructor?.name||"Unknown"})}}async _processEncryptedDataWithLimitedMutex(e){return this._withMutex("cryptoOperation",async t=>{this._secureLog("debug","\u{1F510} Processing encrypted data with limited mutex",{operationId:t,dataType:typeof e});try{return await this.removeSecurityLayers(e)}catch(r){return this._secureLog("error","\u274C Error processing encrypted data",{operationId:t,errorType:r.constructor.name}),e}},2e3)}notifySecurityUpdate(){try{this._secureLog("debug","\u{1F512} Notifying about security level update",{isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasLastCalculation:!!this.lastSecurityCalculation}),this._dispatchAppEvent?.(new CustomEvent("security-level-updated",{detail:{timestamp:Date.now(),manager:"webrtc",webrtcManager:this,isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),lastCalculation:this.lastSecurityCalculation}})),setTimeout(()=>{},100),this.lastSecurityCalculation&&this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:this.lastSecurityCalculation,webrtcManager:this,timestamp:Date.now()}}))}catch(e){this._secureLog("error","\u274C Error in notifySecurityUpdate",{error:e.message})}}handleSystemMessage(e){switch(this._secureLog("debug","\u{1F527} Handling system message:",{type:e.type}),e.type){case"heartbeat":this.handleHeartbeat(e);break;case"verification":this.handleVerificationRequest(e.data);break;case"verification_response":this.handleVerificationResponse(e.data);break;case"sas_code":this.handleSASCode(e.data);break;case"verification_confirmed":this.handleVerificationConfirmed(e.data);break;case"verification_both_confirmed":this.handleVerificationBothConfirmed(e.data);break;case"peer_disconnect":this.handlePeerDisconnectNotification(e);break;case"key_rotation_signal":this._secureLog("debug","\u{1F504} Key rotation signal received (ignored for stability)");break;case"key_rotation_ready":this._secureLog("debug","\u{1F504} Key rotation ready signal received (ignored for stability)");break;case"security_upgrade":this._secureLog("debug","\u{1F512} Security upgrade notification received:",{type:e.type});break;default:this._secureLog("debug","\u{1F527} Unknown system message type:",{type:e.type})}}enableStage2Security(){this.sessionConstraints?.hasPacketReordering&&(this.securityFeatures.hasPacketReordering=!0,this.reorderingConfig.enabled=!0),this.sessionConstraints?.hasAntiFingerprinting&&(this.securityFeatures.hasAntiFingerprinting=!0,this.antiFingerprintingConfig.enabled=!0,this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!0),this.notifySecurityUpgrade(2),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage3Security(){this._secureLog("info","\u{1F512} Enabling Stage 3 features (traffic obfuscation)"),this.sessionConstraints?.hasMessageChunking&&(this.securityFeatures.hasMessageChunking=!0,this.chunkingConfig.enabled=!0),this.sessionConstraints?.hasFakeTraffic&&(this.securityFeatures.hasFakeTraffic=!0,this.fakeTrafficConfig.enabled=!0,this.startFakeTrafficGeneration()),this.notifySecurityUpgrade(3),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage4Security(){if(this._secureLog("info","\u{1F512} Enabling Stage 4 features (maximum safety)"),this.sessionConstraints?.hasDecoyChannels&&this.isConnected()&&this.isVerified){this.securityFeatures.hasDecoyChannels=!0,this.decoyChannelConfig.enabled=!0;try{this.initializeDecoyChannels()}catch(e){this._secureLog("warn","\u26A0\uFE0F Decoy channels initialization failed:",{details:e.message}),this.securityFeatures.hasDecoyChannels=!1,this.decoyChannelConfig.enabled=!1}}this.sessionConstraints?.hasAntiFingerprinting&&(this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!1),this.notifySecurityUpgrade(4),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}forceSecurityUpdate(){setTimeout(()=>{this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate()},100)}getSecurityStatus(){let e=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r);return{stage:4,securityLevel:"maximum",activeFeatures:e,totalFeatures:Object.keys(this.securityFeatures).length,activeFeaturesCount:e.length,activeFeaturesNames:e,sessionConstraints:this.sessionConstraints}}notifySecurityUpgrade(e){let t={1:"Basic Enhanced",2:"Medium Security",3:"High Security",4:"Maximum Security"},r=`\u{1F512} Security upgraded to Stage ${e}: ${t[e]}`;if((!this.securityUpgradeNotificationSent||this.lastSecurityUpgradeStage!==e)&&(this.securityUpgradeNotificationSent=!0,this.lastSecurityUpgradeStage=e,this.onMessage&&this.deliverMessageToUI(r,"system")),this.dataChannel&&this.dataChannel.readyState==="open")try{let n={type:"security_upgrade",stage:e,stageName:t[e],message:r,timestamp:Date.now()};this._secureLog("debug","\u{1F512} Sending security upgrade notification to peer:",{type:n.type,stage:n.stage}),this.dataChannel.send(JSON.stringify(n))}catch(n){this._secureLog("warn","\u26A0\uFE0F Failed to send security upgrade notification to peer:",{details:n.message})}let i=this.getSecurityStatus()}async calculateAndReportSecurityLevel(){try{if(!window.EnhancedSecureCryptoUtils)return this._secureLog("warn","\u26A0\uFE0F EnhancedSecureCryptoUtils not available for security calculation"),null;if(!this.isConnected()||!this.isVerified||!this.encryptionKey||!this.macKey)return this._secureLog("debug","\u26A0\uFE0F WebRTC not ready for security calculation",{connected:this.isConnected(),verified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey}),null;this._secureLog("debug","\u{1F50D} Calculating real security level",{managerState:"ready",hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey)});let e=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this);if(this._secureLog("info","Real security level calculated",{hasSecurityLevel:!!e.level,scoreRange:e.score>80?"high":e.score>50?"medium":"low",checksRatio:`${e.passedChecks}/${e.totalChecks}`,isRealCalculation:e.isRealData}),this.lastSecurityCalculation=e,this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:e,webrtcManager:this,timestamp:Date.now(),source:"calculateAndReportSecurityLevel"}})),e.isRealData&&this.onMessage&&(!this.securityCalculationNotificationSent||this.lastSecurityCalculationLevel!==e.level)){this.securityCalculationNotificationSent=!0,this.lastSecurityCalculationLevel=e.level;let t=`Security Level: ${e.level} (${e.score}%) - ${e.passedChecks}/${e.totalChecks} checks passed`;this.deliverMessageToUI(t,"system")}return e}catch(e){return this._secureLog("error","Failed to calculate real security level",{errorType:e.constructor.name}),null}}async autoEnableSecurityFeatures(){this._secureLog("info","Starting graduated security activation - all features enabled");let e=()=>this.isConnected()&&this.isVerified&&this.connectionAttempts===0&&this.messageQueue.length===0&&this.peerConnection?.connectionState==="connected";await this.calculateAndReportSecurityLevel(),this.notifySecurityUpgrade(1),setTimeout(async()=>{e()&&(this.enableStage2Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage3Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage4Security(),await this.calculateAndReportSecurityLevel())},2e4))},15e3))},1e4)}async establishConnection(){try{await this.initializeEnhancedSecurity(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels()}catch(e){throw this._secureLog("error","\u274C Failed to establish enhanced connection:",{errorType:e?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),e}}_clearVerificationStates(){try{this.localVerificationConfirmed=!1,this.remoteVerificationConfirmed=!1,this.bothVerificationsConfirmed=!1,this.isVerified=!1,this.verificationCode=null,this.pendingSASCode=null,this.sasValidationAttempts=0,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.keyFingerprint=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.connectionId=null,this.processedMessageIds.clear(),this.verificationNotificationSent=!1,this.verificationInitiationSent=!1}catch(e){this._secureLog("error","\u274C Error clearing verification states:",{errorType:e?.constructor?.name||"Unknown"})}}startPeriodicCleanup(){this._secureLog("info","\u{1F527} Periodic cleanup moved to unified scheduler")}async calculateSecurityLevel(){return await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this)}shouldRotateKeys(){return!this.isConnected()||!this.isVerified?!1:Date.now()-this.lastKeyRotation>this.keyRotationInterval||this.messageCounter%100===0}async rotateKeys(){return this._withMutex("keyOperation",async e=>{if(this._secureLog("info","\u{1F504} Starting key rotation with mutex",{operationId:e}),!this.isConnected()||!this.isVerified)return this._secureLog("warn"," Key rotation aborted - connection not ready",{operationId:e,isConnected:this.isConnected(),isVerified:this.isVerified}),!1;if(this._keySystemState.isRotating)return this._secureLog("warn"," Key rotation already in progress",{operationId:e}),!1;try{this._keySystemState.isRotating=!0,this._keySystemState.lastOperation="rotation",this._keySystemState.lastOperationTime=Date.now();let t={type:"key_rotation_signal",newVersion:this.currentKeyVersion+1,timestamp:Date.now(),operationId:e};if(this.dataChannel&&this.dataChannel.readyState==="open")this.dataChannel.send(JSON.stringify(t));else throw new Error("Data channel not ready for key rotation");return this._hardWipeOldKeys(),new Promise(r=>{this.pendingRotation={newVersion:this.currentKeyVersion+1,operationId:e,resolve:r,timeout:setTimeout(()=>{this._secureLog("error"," Key rotation timeout",{operationId:e}),this._keySystemState.isRotating=!1,this.pendingRotation=null,r(!1)},1e4)}})}catch(t){return this._secureLog("error"," Key rotation failed in critical section",{operationId:e,errorType:t.constructor.name}),this._keySystemState.isRotating=!1,!1}},1e4)}cleanupOldKeys(){let e=Date.now(),t=s.LIMITS.MAX_KEY_AGE,r=0;for(let[i,n]of this.oldKeys.entries())e-n.timestamp>t&&(n.encryptionKey&&this._secureWipeMemory(n.encryptionKey,"pfs_cleanup_wipe"),n.macKey&&this._secureWipeMemory(n.macKey,"pfs_cleanup_wipe"),n.metadataKey&&this._secureWipeMemory(n.metadataKey,"pfs_cleanup_wipe"),n.encryptionKey=null,n.macKey=null,n.metadataKey=null,n.keyFingerprint=null,this.oldKeys.delete(i),r++,this._secureLog("info","\u{1F9F9} Old PFS keys hard wiped and cleaned up",{version:i,age:Math.round((e-n.timestamp)/1e3)+"s",timestamp:Date.now()}));r>0&&this._secureLog("info",`PFS cleanup completed: ${r} keys hard wiped`,{timestamp:Date.now()})}getKeysForVersion(e){let t=this.oldKeys.get(e);return t&&t.encryptionKey&&t.macKey&&t.metadataKey?{encryptionKey:t.encryptionKey,macKey:t.macKey,metadataKey:t.metadataKey}:e===this.currentKeyVersion&&this.encryptionKey&&this.macKey&&this.metadataKey?{encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey}:(window.EnhancedSecureCryptoUtils.secureLog.log("error","No valid keys found for version",{requestedVersion:e,currentVersion:this.currentKeyVersion,availableVersions:Array.from(this.oldKeys.keys())}),null)}_hasTurnServer(){return(this._config.webrtc.iceServers||[]).some(e=>(Array.isArray(e.urls)?e.urls:[e.urls]).some(r=>typeof r=="string"&&r.toLowerCase().startsWith("turn:")))}_buildPeerConnectionConfig(){let e=this._isRelayOnlyMode(),t={iceServers:this._config.webrtc.iceServers,iceCandidatePoolSize:10,bundlePolicy:"balanced"};return e&&(t.iceTransportPolicy="relay"),t}_summarizeIceServerConfig(e=[]){let t={serverCount:0,stun:0,turn:0,turns:0,hasCredentials:!1};for(let r of e||[]){t.serverCount+=1,(r?.username||r?.credential)&&(t.hasCredentials=!0);let i=Array.isArray(r?.urls)?r.urls:[r?.urls];for(let n of i){let a=String(n||"").toLowerCase();a.startsWith("stun:")&&(t.stun+=1),a.startsWith("turn:")&&(t.turn+=1),a.startsWith("turns:")&&(t.turns+=1)}}return t}_isRelayOnlyMode(){return this._config.webrtc.privacyMode==="relay-only"}_setRelayOnlyMode(e){let t=e===!0;this._config.webrtc.privacyMode=t?"relay-only":"standard",this._config.webrtc.relayOnly=t}_warnIfTurnMissing(){if(this._ipLeakWarningShown)return;this._ipLeakWarningShown=!0;let e=this._isRelayOnlyMode(),t=this._hasTurnServer(),r=null;e&&!t?r="Privacy mode is relay-only, but no TURN server is configured. Relay-only mode cannot connect until TURN is configured; STUN alone does not hide IP addresses.":!e&&!t?r="Privacy warning: relay-only mode is disabled and no TURN server is configured. Direct WebRTC connections may expose host or server-reflexive IP addresses; STUN alone does not provide IP protection.":e||(r="Privacy warning: relay-only mode is disabled. Direct WebRTC connectivity may expose host or server-reflexive IP addresses even when TURN is available."),r&&this.deliverMessageToUI(r,"system")}createPeerConnection(){this._sessionAlive=!0;let e=this._buildPeerConnectionConfig();this._warnIfTurnMissing(),console.info("[SecureBit ICE] peer connection config",this._summarizeIceServerConfig(e.iceServers)),this.peerConnection=new RTCPeerConnection(e),this._callAudioSender=null,this._callVideoSender=null,this.peerConnection.onconnectionstatechange=()=>{let t=this.peerConnection.connectionState;console.info("[SecureBit ICE] connection state changed",{connectionState:t,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState}),t==="connected"&&!this.isVerified?this._notifyVerificationReadyIfPossible():t==="connected"&&this.isVerified?this._onPathRecovered()||this.onStatusChange("connected"):t==="disconnected"?this.intentionalDisconnect?(this.onStatusChange("disconnected"),setTimeout(()=>this.disconnect(),100)):this.isVerified?this._onPathDegraded("ice_disconnected"):console.warn(`[SecureBit ICE] State is ${t} but not verified yet. Keeping session open for manual exchange.`):t==="closed"?(this._resetReconnectState(),this.onStatusChange("disconnected"),this._clearVerificationStates(),this.intentionalDisconnect&&setTimeout(()=>this.disconnect(),100)):t==="failed"?(this._collectIceFailureDiagnostics().then(r=>{console.warn("[SecureBit ICE] failure diagnostics",r),this._noteIceFailureDiagnostics(r)}),this.isVerified?this._onPathLost("ice_failed"):console.warn("[SecureBit ICE] State is failed but not verified yet. Keeping session open for manual exchange.")):this.isReconnecting()&&(t==="connecting"||t==="new")||this.onStatusChange(t)},this.peerConnection.oniceconnectionstatechange=()=>{console.info("[SecureBit ICE] ICE connection state changed",{connectionState:this.peerConnection.connectionState,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState})},this.peerConnection.onicecandidateerror=t=>{console.warn("[SecureBit ICE] ICE candidate error",{url:t.url,errorCode:t.errorCode,errorText:t.errorText})},this.peerConnection.ontrack=t=>{try{this._refreshRemoteStream()}catch(r){this._secureLog("warn","\u26A0\uFE0F ontrack handling failed",{errorType:r?.constructor?.name})}},this.peerConnection.ondatachannel=t=>{t.channel.label==="securechat"?(this.dataChannel=t.channel,this.setupDataChannel(t.channel)):t.channel.label==="heartbeat"&&(this.heartbeatChannel=t.channel)}}setupDataChannel(e){this.dataChannel=e;let t=!1,r=async()=>{if(!t){t=!0;try{this.dataChannel&&typeof this.dataChannel.bufferedAmountLowThreshold=="number"&&(this.dataChannel.bufferedAmountLowThreshold=1024*1024)}catch{}if(this._handshakeMode==="sbq2")try{await this._runSbq2KeyExchange()}catch(i){this._secureLog("error","SBQ2 key exchange failed to start",{errorType:i?.constructor?.name||"Unknown"}),this._sbq2Abort("start_failed","The secure handshake could not be started. Please try connecting again.");return}try{await this.establishConnection(),this.initializeFileTransfer()}catch(i){this._secureLog("error","Error in establishConnection:",{errorType:i?.constructor?.name||"Unknown"})}if(this.pendingSASCode&&this.dataChannel&&this.dataChannel.readyState==="open")try{let i={type:"sas_code",data:{code:this.pendingSASCode,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(i)),this.pendingSASCode=null}catch{}else this.pendingSASCode;this.isVerified?(this.onStatusChange("connected"),this.processMessageQueue(),setTimeout(async()=>{await this.calculateAndReportSecurityLevel(),this.autoEnableSecurityFeatures(),this.notifySecurityUpdate()},500)):(this._notifyVerificationReadyIfPossible(),this.initiateVerification()),this.startHeartbeat()}};this.dataChannel.onopen=r,this.dataChannel.readyState==="open"&&Promise.resolve().then(()=>r()).catch(i=>{this._secureLog("error","Deferred data channel open handling failed",{errorType:i?.constructor?.name||"Unknown"})}),this.dataChannel.onclose=()=>{this._resetReconnectState?.(),this._teardownRecoveryLifecycleListeners?.(),this.intentionalDisconnect?(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed","system"))):(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed. Check connection status.","system"))),this._wipeEphemeralKeys(),this.stopHeartbeat(),this.isVerified=!1},this.dataChannel.onmessage=async i=>{try{if(this._noteInboundActivity?.(),typeof i.data=="string")try{let n=JSON.parse(i.data),a=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(n.type&&a.includes(n.type)){if(!this._enforceVerificationGate("file_message_receive",!1)){this._secureLog("error","Dropped file message received before verification",{messageType:n.type});return}if(!this.fileTransferSystem)try{if(this.isVerified&&this.dataChannel&&this.dataChannel.readyState==="open"){this.initializeFileTransfer();let o=0,c=30;for(;!this.fileTransferSystem&&osetTimeout(d,100)),o++}}catch(o){this._secureLog("error","Failed to initialize file transfer system for receiver:",{errorType:o?.constructor?.name||"Unknown"})}if(this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}this._secureLog("warn","\u26A0\uFE0F File transfer system not ready, attempting lazy init...");try{if(await this._ensureFileTransferReady(),this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}}catch(o){this._secureLog("error","Lazy init of file transfer failed:",{errorType:o?.message||o?.constructor?.name||"Unknown"})}this._secureLog("error","No file transfer system available for:",{errorType:n.type?.constructor?.name||"Unknown"});return}if(n.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(n.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:n.type});return}let o=s.MESSAGE_TYPES;if(n.type===o.MESSAGE_DELETE){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelete?.(c.slice(0,64))}catch{}return}if(n.type===o.MESSAGE_RECEIPT){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelivered?.(c.slice(0,64))}catch{}return}if([o.CALL_OFFER,o.CALL_ANSWER,o.CALL_ICE,o.CALL_DECLINE,o.CALL_END].includes(n.type)){try{await this._handleCallSignal(n.type,n.data||{})}catch{}return}if([o.ICE_RESTART_OFFER,o.ICE_RESTART_ANSWER,o.ICE_RESTART_REQUEST].includes(n.type)){try{await this._handleIceRestartSignal(n.type,n.data||{})}catch(c){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:c?.constructor?.name})}return}return}if(n.type===s.MESSAGE_TYPES.KEY_BLOB||n.type===s.MESSAGE_TYPES.KEY_PROOF){await this._sbq2HandleHandshakeFrame(n);return}if(n.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","sas_code","peer_disconnect","security_upgrade"].includes(n.type)){this.handleSystemMessage(n);return}if(n.type===s.MESSAGE_TYPES.RATCHET_MESSAGE){await this._processRatchetMessage(n);return}if(n.type==="enhanced_message"&&n.data){await this._processEnhancedMessageWithoutMutex(n);return}this._secureLog("error","Rejected unencrypted frame on the chat channel",{messageType:typeof n.type=="string"?n.type.slice(0,32):typeof n.type});return}catch{this._secureLog("error","Rejected malformed (non-JSON) frame on the chat channel",{dataLength:typeof i.data=="string"?i.data.length:0});return}else i.data instanceof ArrayBuffer&&await this._processBinaryDataWithoutMutex(i.data)}catch(n){this._secureLog("error","Failed to process message in onmessage:",{errorType:n?.constructor?.name||"Unknown"})}}}async _processBinaryDataWithoutMutex(e){try{if(!this._checkInboundRateLimit("binary_message"))return;let t=e;if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&t instanceof ArrayBuffer&&t.byteLength>12)try{t=await this.removeNestedEncryption(t)}catch{this._secureLog("warn","Nested decryption failed, continuing with original data")}if(this.securityFeatures.hasPacketPadding&&t instanceof ArrayBuffer)try{t=this.removePacketPadding(t)}catch{this._secureLog("warn","Packet padding removal failed, continuing with original data")}if(this.securityFeatures.hasAntiFingerprinting&&t instanceof ArrayBuffer)try{t=this.removeAntiFingerprinting(t)}catch{this._secureLog("warn","Anti-fingerprinting removal failed, continuing with original data")}if(t instanceof ArrayBuffer){let r=new TextDecoder().decode(t);try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return}catch{}this._secureLog("error","Rejected unauthenticated binary frame on the chat channel",{byteLength:e?.byteLength||0})}}catch(t){this._secureLog("error","Error processing binary data:",{errorType:t?.constructor?.name||"Unknown"})}}async _processRatchetMessage(e){try{if(!this._checkInboundRateLimit("ratchet_message"))return;if(!this.isRatchetActive()){this._secureLog("error","Received a ratchet message but no ratchet is active");return}if(typeof e?.h!="string"||typeof e?.c!="string"){this._secureLog("error","Malformed ratchet message frame");return}let t=await this._ratchet.decrypt(e.h,e.c);try{let r=JSON.parse(t);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.deliverMessageToUI(t,"received")}catch(t){this._secureLog("error","Failed to decrypt ratchet message",{errorType:t?.constructor?.name||"Unknown"})}}async _processEnhancedMessageWithoutMutex(e){try{if(!this._checkInboundRateLimit("enhanced_message"))return;if(!this.encryptionKey||!this.macKey||!this.metadataKey){this._secureLog("error","Missing encryption keys for enhanced message");return}let t=await window.EnhancedSecureCryptoUtils.decryptMessage(e.data,this.encryptionKey,this.macKey,this.metadataKey);if(!this._validateIncomingSequenceNumber(t?.sequenceNumber,"enhanced_message")){this._secureLog("error","Rejected chat message failing anti-replay validation",{messageId:t?.messageId?"present":"absent"});return}if(t&&t.message){try{let r=JSON.parse(t.message);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.onMessage&&this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.onMessage&&this.deliverMessageToUI(t.message,"received")}else this._secureLog("warn","No message content in decrypted result")}catch(t){this._secureLog("error","Error processing enhanced message:",{errorType:t?.constructor?.name||"Unknown"})}}_generateOperationId(){return`op_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async _acquireMutex(e,t,r=5e3){let i=`_${e}Mutex`,n=this[i];if(!n)throw this._secureLog("error",`Unknown mutex: ${e}`,{mutexPropertyName:i,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex: ${e}. Available: ${this._getAvailableMutexes().join(", ")}`);if(!t||typeof t!="string")throw new Error("Invalid operation ID for mutex acquisition");return new Promise((a,o)=>{(()=>{if(n.lockId===t){this._secureLog("warn",`Mutex '${e}' already locked by same operation`,{operationId:t}),a();return}if(!n.locked)n.locked=!0,n.lockId=t,n.lockTime=Date.now(),this._secureLog("debug",`Mutex '${e}' acquired atomically`,{operationId:t,lockTime:n.lockTime}),n.lockTimeout=setTimeout(()=>{this._handleMutexTimeout(e,t,r)},r),a();else{let d={resolve:a,reject:o,operationId:t,timestamp:Date.now(),timeout:setTimeout(()=>{let u=n.queue.findIndex(h=>h.operationId===t);u!==-1&&(n.queue.splice(u,1),o(new Error(`Mutex acquisition timeout for '${e}'`)))},r)};n.queue.push(d),this._secureLog("debug",`Operation queued for mutex '${e}'`,{operationId:t,queueLength:n.queue.length,currentLockId:n.lockId})}})()})}_releaseMutex(e,t){if(!e||typeof e!="string")throw new Error("Invalid mutex name provided for release");if(!t||typeof t!="string")throw new Error("Invalid operation ID provided for mutex release");let r=`_${e}Mutex`,i=this[r];if(!i)throw this._secureLog("error",`Unknown mutex for release: ${e}`,{mutexPropertyName:r,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex for release: ${e}`);if(i.lockId!==t)throw this._secureLog("error","CRITICAL: Invalid mutex release attempt - potential race condition",{mutexName:e,expectedLockId:i.lockId,providedOperationId:t,mutexState:{locked:i.locked,lockTime:i.lockTime,queueLength:i.queue.length}}),new Error(`Invalid mutex release attempt for '${e}': expected '${i.lockId}', got '${t}'`);if(!i.locked)throw this._secureLog("error","CRITICAL: Attempting to release unlocked mutex",{mutexName:e,operationId:t,mutexState:{locked:i.locked,lockId:i.lockId,lockTime:i.lockTime}}),new Error(`Attempting to release unlocked mutex: ${e}`);try{i.lockTimeout&&(clearTimeout(i.lockTimeout),i.lockTimeout=null);let n=i.lockTime?Date.now()-i.lockTime:0;i.locked=!1,i.lockId=null,i.lockTime=null,this._secureLog("debug",`Mutex released successfully: ${e}`,{operationId:t,lockDuration:n,queueLength:i.queue.length}),this._processNextInQueue(e)}catch(n){throw this._secureLog("error","Error during mutex release queue processing",{mutexName:e,operationId:t,errorType:n.constructor.name,errorMessage:n.message}),i.locked=!1,i.lockId=null,i.lockTime=null,i.lockTimeout=null,n}}_processNextInQueue(e){let t=this[`_${e}Mutex`];if(!t){this._secureLog("error",`Mutex not found for queue processing: ${e}`);return}if(t.queue.length===0)return;if(t.locked){this._secureLog("warn",`Mutex '${e}' is still locked, skipping queue processing`,{lockId:t.lockId,queueLength:t.queue.length});return}let r=t.queue.shift();if(!r){this._secureLog("warn",`Empty queue item for mutex '${e}'`);return}if(!r.operationId||!r.resolve||!r.reject){this._secureLog("error",`Invalid queue item structure for mutex '${e}'`,{hasOperationId:!!r.operationId,hasResolve:!!r.resolve,hasReject:!!r.reject});return}try{r.timeout&&clearTimeout(r.timeout),this._secureLog("debug",`Processing next operation in queue for mutex '${e}'`,{operationId:r.operationId,queueRemaining:t.queue.length,timestamp:Date.now()}),setTimeout(async()=>{try{await this._acquireMutex(e,r.operationId,5e3),this._secureLog("debug",`Queued operation acquired mutex '${e}'`,{operationId:r.operationId,acquisitionTime:Date.now()}),r.resolve()}catch(i){this._secureLog("error",`Queued operation failed to acquire mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message,timestamp:Date.now()}),r.reject(new Error(`Queue processing failed for '${e}': ${i.message}`)),setTimeout(()=>{this._processNextInQueue(e)},50)}},10)}catch(i){this._secureLog("error",`Critical error during queue processing for mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message});try{r.reject(new Error(`Queue processing critical error: ${i.message}`))}catch(n){this._secureLog("error","Failed to reject queue item",{originalError:i.message,rejectError:n.message})}setTimeout(()=>{this._processNextInQueue(e)},100)}}_getAvailableMutexes(){let e=[],t=Object.getOwnPropertyNames(this);for(let r of t)if(r.endsWith("Mutex")&&r.startsWith("_")){let i=r.slice(1,-5);e.push(i)}return e}async _withMutex(e,t,r=5e3){let i=this._generateOperationId();if(!this._validateMutexSystem())throw this._secureLog("error","Mutex system not properly initialized",{operationId:i,mutexName:e}),new Error("Mutex system not properly initialized. Call _initializeMutexSystem() first.");let n=this[`_${e}Mutex`];if(!n)throw new Error(`Mutex '${e}' not found`);let a=!1;try{await this._acquireMutex(e,i,r),a=!0;let o=`${e}Operations`;this._operationCounters&&this._operationCounters[o]!==void 0&&this._operationCounters[o]++;let c=await t(i);return c===void 0&&t.name!=="cleanup"&&this._secureLog("warn","Mutex operation returned undefined result",{operationId:i,mutexName:e,operationName:t.name}),c}catch(o){throw this._secureLog("error","Error in mutex operation",{operationId:i,mutexName:e,errorType:o.constructor.name,errorMessage:o.message,mutexAcquired:a,mutexState:n?{locked:n.locked,lockId:n.lockId,queueLength:n.queue.length}:"null"}),e==="keyOperation"&&this._handleKeyOperationError(o,i),(o.message.includes("timeout")||o.message.includes("race condition"))&&this._emergencyUnlockAllMutexes("errorHandler"),o}finally{if(a)try{await this._releaseMutex(e,i),n.locked&&n.lockId===i&&(this._secureLog("error","Mutex release verification failed",{operationId:i,mutexName:e}),n.locked=!1,n.lockId=null,n.lockTimeout=null)}catch(o){this._secureLog("error","Error releasing mutex in finally block",{operationId:i,mutexName:e,releaseErrorType:o.constructor.name,releaseErrorMessage:o.message}),n.locked=!1,n.lockId=null,n.lockTimeout=null}}}_validateMutexSystem(){let e=["keyOperation","cryptoOperation","connectionOperation"];for(let t of e){let r=`_${t}Mutex`,i=this[r];if(!i||typeof i!="object")return this._secureLog("error",`Missing or invalid mutex: ${t}`,{mutexPropertyName:r,mutexType:typeof i}),!1;let n=["locked","queue","lockId","lockTimeout"];for(let a of n)if(!(a in i))return this._secureLog("error",`Mutex ${t} missing property: ${a}`),!1}return!0}_emergencyRecoverMutexSystem(){this._secureLog("warn","Emergency mutex system recovery initiated");try{if(this._emergencyUnlockAllMutexes("emergencyRecovery"),this._initializeMutexSystem(),!this._validateMutexSystem())throw new Error("Mutex system validation failed after recovery");return this._secureLog("info","Mutex system recovered successfully with validation"),!0}catch(e){this._secureLog("error","Failed to recover mutex system",{errorType:e.constructor.name,errorMessage:e.message});try{return this._initializeMutexSystem(),this._secureLog("warn","Forced mutex system re-initialization completed"),!0}catch(t){return this._secureLog("error","CRITICAL: Forced re-initialization also failed",{originalError:e.message,reinitError:t.message}),!1}}}async _generateEncryptionKeys(){return this._withMutex("keyOperation",async e=>{this._secureLog("info","Generating encryption keys with atomic mutex",{operationId:e});let t=this._keySystemState;if(t.isInitializing){this._secureLog("warn","Key generation already in progress, waiting for completion",{operationId:e,lastOperation:t.lastOperation,lastOperationTime:t.lastOperationTime});let r=0,i=50;for(;t.isInitializing&&rsetTimeout(n,100)),r++;if(t.isInitializing)throw new Error("Key generation timeout - operation still in progress after 5 seconds")}try{t.isInitializing=!0,t.lastOperation="generation",t.lastOperationTime=Date.now(),t.operationId=e,this._secureLog("debug","Atomic key generation state set",{operationId:e,timestamp:t.lastOperationTime});let r=null,i=null;try{if(r=await this._generateEphemeralECDHKeys(),!r||!r.privateKey||!r.publicKey)throw new Error("Ephemeral ECDH key pair validation failed");if(!this._validateKeyPairConstantTime(r))throw new Error("Ephemeral ECDH keys are not valid CryptoKey instances");this._secureLog("debug","Ephemeral ECDH keys generated and validated for PFS",{operationId:e,privateKeyType:r.privateKey.algorithm?.name,publicKeyType:r.publicKey.algorithm?.name,isEphemeral:!0})}catch(n){this._secureLog("error","Ephemeral ECDH key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ephemeral_ecdh_key_generation")}try{if(i=await window.EnhancedSecureCryptoUtils.generateECDSAKeyPair(),!i||!i.privateKey||!i.publicKey)throw new Error("ECDSA key pair validation failed");if(!this._validateKeyPairConstantTime(i))throw new Error("ECDSA keys are not valid CryptoKey instances");this._secureLog("debug","ECDSA keys generated and validated",{operationId:e,privateKeyType:i.privateKey.algorithm?.name,publicKeyType:i.publicKey.algorithm?.name})}catch(n){this._secureLog("error","ECDSA key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ecdsa_key_generation")}if(!r||!i)throw new Error("One or both key pairs failed to generate");return this._enableSecurityFeaturesAfterKeyGeneration(r,i),this._secureLog("info","Encryption keys generated successfully with atomic protection",{operationId:e,hasECDHKeys:!!(r?.privateKey&&r?.publicKey),hasECDSAKeys:!!(i?.privateKey&&i?.publicKey),generationTime:Date.now()-t.lastOperationTime}),{ecdhKeyPair:r,ecdsaKeyPair:i}}catch(r){throw this._secureLog("error","Key generation failed, resetting state",{operationId:e,errorType:r.constructor.name}),r}finally{t.isInitializing=!1,t.operationId=null,this._secureLog("debug","Key generation state reset",{operationId:e})}})}_enableSecurityFeaturesAfterKeyGeneration(e,t){try{e&&e.privateKey&&e.publicKey&&(this.securityFeatures.hasEncryption=!0,this.securityFeatures.hasECDH=!0,this._secureLog("info","ECDH encryption features enabled")),t&&t.privateKey&&t.publicKey&&(this.securityFeatures.hasECDSA=!0,this._secureLog("info","ECDSA signature features enabled")),this.securityFeatures.hasEncryption&&(this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasNonExtractableKeys=!0,this._secureLog("info","Additional encryption-dependent features enabled")),e&&this.ephemeralKeyPairs.size>0&&(this.securityFeatures.hasPFS=!0,this._secureLog("info","Perfect Forward Secrecy enabled with ephemeral keys")),this._secureLog("info","Security features updated after key generation",{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasMetadataProtection:this.securityFeatures.hasMetadataProtection,hasEnhancedReplayProtection:this.securityFeatures.hasEnhancedReplayProtection,hasNonExtractableKeys:this.securityFeatures.hasNonExtractableKeys,hasPFS:this.securityFeatures.hasPFS})}catch(r){this._secureLog("error","Failed to enable security features after key generation",{errorType:r.constructor.name,errorMessage:r.message})}}_emergencyUnlockAllMutexes(e="unknown"){let t=["keyOperation","cryptoOperation","connectionOperation","emergencyRecovery","systemShutdown","errorHandler"];if(!t.includes(e))throw this._secureLog("error","UNAUTHORIZED emergency mutex unlock attempt",{callerContext:e,authorizedCallers:t,timestamp:Date.now()}),new Error(`Unauthorized emergency mutex unlock attempt by: ${e}`);let r=["keyOperation","cryptoOperation","connectionOperation"];this._secureLog("error","EMERGENCY: Unlocking all mutexes with authorization and state cleanup",{callerContext:e,timestamp:Date.now()});let i=0,n=0;if(r.forEach(a=>{let o=this[`_${a}Mutex`];if(o)try{o.lockTimeout&&clearTimeout(o.lockTimeout);let c={locked:o.locked,lockId:o.lockId,lockTime:o.lockTime,queueLength:o.queue.length};o.locked=!1,o.lockId=null,o.lockTimeout=null,o.lockTime=null;let d=0;o.queue.forEach(u=>{try{u.reject&&typeof u.reject=="function"&&(u.reject(new Error(`Emergency mutex unlock for ${a} by ${e}`)),d++)}catch(h){this._secureLog("warn","Failed to reject queue item during emergency unlock",{mutexName:a,errorType:h.constructor.name})}}),o.queue=[],i++,this._secureLog("debug",`Emergency unlocked mutex: ${a}`,{previousState:c,queueRejectCount:d,callerContext:e})}catch(c){n++,this._secureLog("error",`Error during emergency unlock of mutex: ${a}`,{errorType:c.constructor.name,errorMessage:c.message,callerContext:e})}}),this._keySystemState)try{let a={...this._keySystemState};this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null,this._keySystemState.concurrentOperations=0,this._secureLog("debug","Emergency reset key system state",{previousState:a,callerContext:e})}catch(a){this._secureLog("error","Error resetting key system state during emergency unlock",{errorType:a.constructor.name,errorMessage:a.message,callerContext:e})}this._secureLog("info","Emergency mutex unlock completed",{callerContext:e,unlockedCount:i,errorCount:n,totalMutexes:r.length,timestamp:Date.now()}),setTimeout(()=>{this._validateMutexSystemAfterEmergencyUnlock()},100)}_handleKeyOperationError(e,t){this._secureLog("error","Key operation error detected, initiating recovery",{operationId:t,errorType:e.constructor.name,errorMessage:e.message}),this._keySystemState&&(this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null),this.ecdhKeyPair=null,this.ecdsaKeyPair=null,this.encryptionKey=null,this.macKey=null,this.metadataKey=null,(e.message.includes("timeout")||e.message.includes("race condition"))&&(this._secureLog("warn","Race condition or timeout detected, triggering emergency recovery"),this._emergencyRecoverMutexSystem())}_generateSecureIV(e=12,t="general"){if(this._ivTrackingSystem.emergencyMode)throw this._secureLog("error","CRITICAL: IV generation blocked - emergency mode active due to IV reuse"),new Error("IV generation blocked - emergency mode active");let r=0,i=100;for(;ro.toString(16).padStart(2,"0")).join("");if(this._ivTrackingSystem.usedIVs.has(a)){if(this._ivTrackingSystem.collisionCount++,this._secureLog("error","CRITICAL: IV reuse detected!",{context:t,attempt:r,collisionCount:this._ivTrackingSystem.collisionCount,ivString:a.substring(0,16)+"..."}),this._ivTrackingSystem.collisionCount>5)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to excessive IV reuse"),new Error("Emergency mode: Excessive IV reuse detected");continue}if(!this._validateIVEntropy(n)){if(this._ivTrackingSystem.entropyValidation.entropyFailures++,this._secureLog("warn","Low entropy IV detected",{context:t,attempt:r,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures}),this._ivTrackingSystem.entropyValidation.entropyFailures>10)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to low entropy IVs"),new Error("Emergency mode: Low entropy IVs detected");continue}return this._ivTrackingSystem.usedIVs.add(a),this._ivTrackingSystem.ivHistory.set(a,{timestamp:Date.now(),context:t,attempt:r}),this.sessionId&&(this._ivTrackingSystem.sessionIVs.has(this.sessionId)||this._ivTrackingSystem.sessionIVs.set(this.sessionId,new Set),this._ivTrackingSystem.sessionIVs.get(this.sessionId).add(a)),this._validateRNGQuality(),this._secureLog("debug","Secure IV generated",{context:t,attempt:r,ivSize:e,totalIVs:this._ivTrackingSystem.usedIVs.size}),n}throw this._secureLog("error",`Failed to generate unique IV after ${i} attempts`,{context:t,totalIVs:this._ivTrackingSystem.usedIVs.size}),new Error(`Failed to generate unique IV after ${i} attempts`)}_validateIVEntropy(e){this._ivTrackingSystem.entropyValidation.entropyTests++;let t=new Array(256).fill(0);for(let S=0;S0){let g=t[S]/n;i-=g*Math.log2(g)}r.shannon=i;let o=Math.max(...t)/n;r.min=-Math.log2(o);let c=0;for(let S=0;S<256;S++)if(t[S]>0){let g=t[S]/n;c+=g*g}r.collision=-Math.log2(c);let d=Array.from(e).map(S=>String.fromCharCode(S)).join(""),u=this._estimateCompressedLength(d);r.compression=(1-u/n)*8,r.quantum=this._calculateQuantumResistantEntropy(e);let h=this._detectAdvancedSuspiciousPatterns(e),m=this._ivTrackingSystem.entropyValidation.minEntropy,p=r.shannon>=m&&r.min>=m*.8&&r.collision>=m*.9&&r.compression>=m*.7&&r.quantum>=m*.6&&!h;return p||this._secureLog("warn","Enhanced IV entropy validation failed",{shannon:r.shannon.toFixed(2),min:r.min.toFixed(2),collision:r.collision.toFixed(2),compression:r.compression.toFixed(2),quantum:r.quantum.toFixed(2),minThreshold:m,hasSuspiciousPatterns:h}),p}_estimateCompressedLength(e){let t=0,r=0;for(;ri&&(i=o,n=r-a)}i>=3?(t+=3,r+=i):(t+=1,r+=1)}return t}_calculateQuantumResistantEntropy(e){let t=0;this._detectQuantumVulnerablePatterns(e)&&(t-=2);let i=this._analyzeBitDistribution(e);t+=i.score;let n=this._detectPeriodicity(e);return t-=n*.5,Math.max(0,Math.min(8,t))}_detectQuantumVulnerablePatterns(e){let t=[[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,1,0,1,0,1,0,1],[1,0,1,0,1,0,1,0]];for(let r of t)for(let i=0;i<=e.length-r.length;i++){let n=!0;for(let a=0;a>>0).toString(2).split("1").length-1;let i=(r-t)/r,n=t/r,a=Math.abs(.5-n);return{score:Math.max(0,8-a*16),zeroRatio:i,oneRatio:n,deviation:a}}_detectPeriodicity(e){if(e.length<16)return 0;let t=0;for(let r=2;r<=e.length/2;r++){let i=0,n=0;for(let a=0;a0){let a=i/n;t=Math.max(t,a)}}return t}_detectAdvancedSuspiciousPatterns(e){let t=[[0,1,2,3,4,5,6,7],[255,254,253,252,251,250,249,248],[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,255,0,255,0,255,0,255],[255,0,255,0,255,0,255,0]];for(let n of t)for(let a=0;a<=e.length-n.length;a++){let o=!0;for(let c=0;cn<3).length>e.length*.3}_calculateLocalEntropy(e){let r=[];for(let i=0;i<=e.length-8;i++){let n=e.slice(i,i+8),a={};for(let c of n)a[c]=(a[c]||0)+1;let o=0;for(let c of Object.values(a)){let d=c/8;o-=d*Math.log2(d)}r.push(o)}return r}_detectSuspiciousIVPatterns(e){let t=e.every(n=>n===0),r=e.every(n=>n===255);if(t||r)return!0;let i=0;for(let n=1;n=3)return!0;for(let n=2;n<=Math.floor(e.length/2);n++)for(let a=0;a<=e.length-n*2;a++){let o=e.slice(a,a+n),c=e.slice(a+n,a+n*2);if(o.every((d,u)=>d===c[u]))return!0}return!1}async _cleanupOldIVs(){let e=Date.now(),t=18e5,r=0,i=[];if(this._ivTrackingSystem.ivHistory.size>this._ivTrackingSystem.maxIVHistorySize){let n=Array.from(this._ivTrackingSystem.ivHistory.entries()),a=n.slice(0,n.length-this._ivTrackingSystem.maxIVHistorySize);for(let[o]of a)i.push(o),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0)}for(let[n,a]of this._ivTrackingSystem.ivHistory.entries())e-a.timestamp>t&&(i.push(n),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0));i.length>0&&this._processCleanupBatch(i);for(let[n,a]of this._ivTrackingSystem.sessionIVs.entries())if(a.size>this._ivTrackingSystem.maxSessionIVs){let o=Array.from(a),c=o.slice(0,o.length-this._ivTrackingSystem.maxSessionIVs);for(let d of c)a.delete(d),this._ivTrackingSystem.usedIVs.delete(d),this._ivTrackingSystem.ivHistory.delete(d),r++}r>50&&await this._performNaturalCleanup(),r>0&&this._secureLog("debug",`Enhanced cleanup: ${r} old IVs removed`,{cleanedCount:r,remainingIVs:this._ivTrackingSystem.usedIVs.size,remainingHistory:this._ivTrackingSystem.ivHistory.size,memoryPressure:this._calculateMemoryPressure()})}_processCleanupBatch(e){for(let t of e)this._ivTrackingSystem.usedIVs.delete(t),this._ivTrackingSystem.ivHistory.delete(t)}_calculateMemoryPressure(){let e=this._ivTrackingSystem.usedIVs.size,t=this._resourceLimits.maxIVHistory;return Math.min(100,Math.floor(e/t*100))}_getIVTrackingStats(){return{totalIVs:this._ivTrackingSystem.usedIVs.size,collisionCount:this._ivTrackingSystem.collisionCount,entropyTests:this._ivTrackingSystem.entropyValidation.entropyTests,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures,rngTests:this._ivTrackingSystem.rngValidation.testsPerformed,weakRngDetected:this._ivTrackingSystem.rngValidation.weakRngDetected,emergencyMode:this._ivTrackingSystem.emergencyMode,sessionCount:this._ivTrackingSystem.sessionIVs.size,lastCleanup:this._lastIVCleanupTime||0}}_resetIVTrackingSystem(){this._secureLog("warn","Resetting IV tracking system"),this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.entropyValidation.entropyTests=0,this._ivTrackingSystem.entropyValidation.entropyFailures=0,this._ivTrackingSystem.rngValidation.testsPerformed=0,this._ivTrackingSystem.rngValidation.weakRngDetected=!1,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","IV tracking system reset completed")}_validateRNGQuality(){let e=Date.now();if(this._ivTrackingSystem.rngValidation.testsPerformed%1e3===0)try{let t=[];for(let n=0;n<100;n++)t.push(crypto.getRandomValues(new Uint8Array(12)));let r=t.map(n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("")),i=new Set(r);i.size<95&&(this._ivTrackingSystem.rngValidation.weakRngDetected=!0,this._secureLog("error","CRITICAL: Weak RNG detected in validation test",{uniqueIVs:i.size,totalTests:t.length})),this._ivTrackingSystem.rngValidation.lastValidation=e}catch(t){this._secureLog("error","RNG validation failed",{errorType:t.constructor.name})}this._ivTrackingSystem.rngValidation.testsPerformed++}_handleMutexTimeout(e,t,r){let i=this[`_${e}Mutex`];if(!i){this._secureLog("error",`Mutex '${e}' not found during timeout handling`);return}if(i.lockId!==t){this._secureLog("warn",`Timeout for different operation ID on mutex '${e}'`,{expectedOperationId:t,actualLockId:i.lockId,locked:i.locked});return}if(!i.locked){this._secureLog("warn",`Timeout for already unlocked mutex '${e}'`,{operationId:t});return}try{let n=i.lockTime?Date.now()-i.lockTime:0;this._secureLog("warn",`Mutex '${e}' auto-released due to timeout`,{operationId:t,lockDuration:n,timeout:r,queueLength:i.queue.length}),i.locked=!1,i.lockId=null,i.lockTimeout=null,i.lockTime=null,setTimeout(()=>{try{this._processNextInQueue(e)}catch(a){this._secureLog("error",`Error processing queue after timeout for mutex '${e}'`,{errorType:a.constructor.name,errorMessage:a.message})}},10)}catch(n){this._secureLog("error",`Critical error during mutex timeout handling for '${e}'`,{operationId:t,errorType:n.constructor.name,errorMessage:n.message});try{this._emergencyUnlockAllMutexes("timeoutHandler")}catch(a){this._secureLog("error","Emergency unlock failed during timeout handling",{originalError:n.message,emergencyError:a.message})}}}_validateMutexSystemAfterEmergencyUnlock(){let e=["keyOperation","cryptoOperation","connectionOperation"],t=0;this._secureLog("info","Validating mutex system after emergency unlock"),e.forEach(r=>{let i=this[`_${r}Mutex`];if(!i){t++,this._secureLog("error",`Mutex '${r}' not found after emergency unlock`);return}i.locked&&(t++,this._secureLog("error",`Mutex '${r}' still locked after emergency unlock`,{lockId:i.lockId,lockTime:i.lockTime})),i.lockId!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has lock ID after emergency unlock`,{lockId:i.lockId})),i.lockTimeout!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has timeout after emergency unlock`)),i.queue.length>0&&(t++,this._secureLog("error",`Mutex '${r}' still has queue items after emergency unlock`,{queueLength:i.queue.length}))}),this._keySystemState&&(this._keySystemState.isInitializing||this._keySystemState.isRotating||this._keySystemState.isDestroying)&&(t++,this._secureLog("error","Key system state not properly reset after emergency unlock",{isInitializing:this._keySystemState.isInitializing,isRotating:this._keySystemState.isRotating,isDestroying:this._keySystemState.isDestroying})),t===0?this._secureLog("info","Mutex system validation passed after emergency unlock"):(this._secureLog("error","Mutex system validation failed after emergency unlock",{validationErrors:t}),setTimeout(()=>{this._emergencyRecoverMutexSystem()},1e3))}_getMutexSystemDiagnostics(){let e={timestamp:Date.now(),systemValid:this._validateMutexSystem(),mutexes:{},counters:{...this._operationCounters},keySystemState:{...this._keySystemState}};return["keyOperation","cryptoOperation","connectionOperation"].forEach(r=>{let i=`_${r}Mutex`,n=this[i];n?e.mutexes[r]={locked:n.locked,lockId:n.lockId,queueLength:n.queue.length,hasTimeout:!!n.lockTimeout}:e.mutexes[r]={error:"not_found"}}),e}async createSecureOffer(){return this._withMutex("connectionOperation",async e=>{this._secureLog("info","Creating secure offer with mutex",{operationId:e,connectionAttempts:this.connectionAttempts,currentState:this.peerConnection?.connectionState||"none"});try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this.connectionAttempts=0,this.sessionSalt=window.EnhancedSecureCryptoUtils.generateSalt(),this._secureLog("debug","Session salt generated",{operationId:e,saltLength:this.sessionSalt.length,isValidSalt:Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64});let t=await this._generateEncryptionKeys();if(this.ecdhKeyPair=t.ecdhKeyPair,this.ecdsaKeyPair=t.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdhKeyPair?.publicKey)throw new Error("Failed to generate valid ECDH key pair");if(!this.ecdsaKeyPair?.privateKey||!this.ecdsaKeyPair?.publicKey)throw new Error("Failed to generate valid ECDSA key pair");let r=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdhKeyPair.publicKey)),i=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdsaKeyPair.publicKey));if(!r||!i)throw new Error("Failed to generate key fingerprints");this._secureLog("info","Generated unique key pairs for MITM protection",{operationId:e,hasECDHFingerprint:!!r,hasECDSAFingerprint:!!i,fingerprintLength:r.length,timestamp:Date.now()});let n=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),a=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!n||typeof n!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!a||typeof a!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.isInitiator=!0,this.onStatusChange("connecting"),this.createPeerConnection(),this.dataChannel=this.peerConnection.createDataChannel("securechat",{ordered:!0}),this.setupDataChannel(this.dataChannel),this._secureLog("debug","Data channel created",{operationId:e,channelLabel:this.dataChannel.label,channelOrdered:this.dataChannel.ordered});let o=await this.peerConnection.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});await this.peerConnection.setLocalDescription(o);try{let b=this._extractDTLSFingerprintFromSDP(o.sdp);this.expectedDTLSFingerprint=b,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:b,context:"offer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${b}`,"system")}catch(b){this._secureLog("error","Failed to extract DTLS fingerprint from offer",{error:b.message})}let c=Date.now(),d=await this.waitForIceGathering(),u=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),h=u.total;if(!d&&h===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the invitation would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");if(this._secureLog(h>0?"info":"warn","ICE candidates captured for offer export",{candidateSummary:u,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),this._logIceCandidateDiagnostics("offer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),d||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the invitation. Connectivity may still fail on restrictive networks.","system"),h===0&&this.deliverMessageToUI("No ICE candidates were gathered for the invitation yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed",{operationId:e,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState}),this.verificationCode=window.EnhancedSecureCryptoUtils.generateVerificationCode(),!this.verificationCode||this.verificationCode.lengthb.toString(16).padStart(2,"0")).join(""),!this.sessionId||this.sessionId.length!==s.SIZES.SESSION_ID_LENGTH*2)throw new Error("Failed to generate valid session ID");this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(b=>b.toString(16).padStart(2,"0")).join(""),this._storePendingOfferContext();let p={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},S=Date.now(),g={t:"offer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:S,e:n,d:a,sl:this.sessionSalt,si:this.sessionId,ci:this.connectionId,vc:this.verificationCode,ac:m,slv:"MAX",dr:s.RATCHET_VERSION,kf:{e:r.substring(0,12),d:i.substring(0,12)}};try{let b=this.validateEnhancedOfferData(g)}catch(b){throw new Error(`Offer package validation error: ${b.message}`)}if(this._secureLog("info","Enhanced secure offer created successfully",{operationId:e,version:g.version,hasECDSA:!0,hasMutualAuth:!0,hasSessionId:!!g.sessionId,securityLevel:p.level,timestamp:S,capabilitiesCount:10}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"offer",timestamp:S,securityLevel:p.level,operationId:e}})),s.SBQ2_SEND_ENABLED){this._latchHandshakeMode("sbq2");let{text:b}=await this._sbq2BuildDescriptor(de.OFFER);return{t:"offer",sbq2:b}}return this._latchHandshakeMode("sb1"),g}catch(t){throw this._secureLog("error","Enhanced secure offer creation failed in critical section",{operationId:e,errorType:t.constructor.name,errorMessage:t.message,phase:this._determineErrorPhase(t),connectionAttempts:this.connectionAttempts}),this._cleanupFailedOfferCreation(),this.onStatusChange("disconnected"),t}},6e4)}_determineErrorPhase(e){let t=e.message.toLowerCase();return t.includes("rate limit")?"rate_limiting":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("fingerprint")?"fingerprinting":t.includes("export")||t.includes("signature")?"key_export":t.includes("peer connection")?"webrtc_setup":t.includes("offer")||t.includes("sdp")?"sdp_creation":t.includes("verification")?"verification_setup":t.includes("session")?"session_setup":t.includes("validation")?"package_validation":"unknown"}_cleanupFailedOfferCreation(){try{this._secureCleanupCryptographicMaterials(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during offer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed offer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during offer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}_updateSecurityFeatures(e){let t={...this.securityFeatures};try{Object.assign(this.securityFeatures,e),this._secureLog("debug","Security features updated",{updatedCount:Object.keys(e).length,totalFeatures:Object.keys(this.securityFeatures).length})}catch(r){throw this.securityFeatures=t,this._secureLog("error","Security features update failed, rolled back",{errorType:r.constructor.name}),r}}async _createSbq2Answer(e){return this._withMutex("connectionOperation",async t=>{try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this._latchHandshakeMode("sbq2");let r=Ur(String(e.sbq2)),i=this._sbq2AdoptRemoteDescriptor(r,de.OFFER),{sdp:n}=Kr(i);this.isInitiator=!1,this.onStatusChange("connecting");let a=await this._generateEncryptionKeys();if(this.ecdhKeyPair=a.ecdhKeyPair,this.ecdsaKeyPair=a.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdsaKeyPair?.privateKey)throw new Error("Failed to generate valid key pairs");this.createPeerConnection(),this._peerDTLSFingerprint=Array.from(i.fingerprint,d=>d.toString(16).padStart(2,"0").toUpperCase()).join(":"),await this.peerConnection.setRemoteDescription({type:"offer",sdp:n}),await this.peerConnection.setLocalDescription(await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})),this.expectedDTLSFingerprint=this._extractDTLSFingerprintFromSDP(this.peerConnection.localDescription.sdp),await this.waitForIceGathering();let o=async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),{text:c}=await this._sbq2BuildDescriptor(de.ANSWER,{bindingTag:await Or(o,r)});return this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:Date.now(),operationId:t}})),{t:"answer",sbq2:c}}catch(r){throw this._secureLog("error","SBQ2 answer creation failed",{operationId:t,errorType:r?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),r}},6e4)}async createSecureAnswer(e){return e&&typeof e.sbq2=="string"?this._createSbq2Answer(e):this._withMutex("connectionOperation",async t=>{this._secureLog("info","Creating secure answer with mutex",{operationId:t,hasOfferData:!!e,offerType:e?.type,offerVersion:e?.version,offerTimestamp:e?.timestamp});try{if(this._resetNotificationFlags(),this._secureLog("debug","Starting enhanced offer validation",{operationId:t,hasOfferData:!!e,offerType:e?.type,hasECDHKey:!!e?.ecdhPublicKey,hasECDSAKey:!!e?.ecdsaPublicKey,hasSalt:!!e?.salt}),!this.validateEnhancedOfferData(e))throw new Error("Invalid connection data format - failed enhanced validation");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkConnectionRate(this.rateLimiterId))throw new Error("Connection rate limit exceeded. Please wait before trying again.");let r=e.ts||e.timestamp,i=e.v||e.version;if(!r||!i)throw new Error("Missing required security fields in offer data \u2013 possible MITM attack");let n=Date.now()-r,a=18e5;if(n>a)throw this._secureLog("error","Offer data is too old - possible replay attack",{operationId:t,offerAge:Math.round(n/1e3),maxAllowedAge:Math.round(a/1e3),timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Offer data is too old \u2013 possible replay attack"),new Error("Offer data is too old \u2013 possible replay attack");let o=i;if(o!==s.PROTOCOL_VERSION)throw this._secureLog("warn","Protocol version mismatch detected",{operationId:t,expectedVersion:s.PROTOCOL_VERSION,receivedVersion:o}),new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${o}`);if(this.sessionSalt=e.sl||e.salt,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,!Array.isArray(this.sessionSalt))throw new Error("Invalid session salt format - must be array");let c=64;if(this.sessionSalt.length!==c)throw new Error(`Invalid session salt length: expected ${c}, got ${this.sessionSalt.length}`);let d=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);this._secureLog("info","Session salt validated successfully",{operationId:t,saltLength:this.sessionSalt.length,saltFingerprint:d.substring(0,8)});let u=await this._generateEncryptionKeys();if(this.ecdhKeyPair=u.ecdhKeyPair,this.ecdsaKeyPair=u.ecdsaKeyPair,!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw this._secureLog("error","Local ECDH private key is not a CryptoKey",{operationId:t,hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a valid CryptoKey");let h;try{let R=e.d||e.ecdsaPublicKey;h=await crypto.subtle.importKey("spki",new Uint8Array(R.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"])}catch(R){this._throwSecureError(R,"ecdsa_key_import")}let m;try{let R=e.e||e.ecdhPublicKey;m=await window.EnhancedSecureCryptoUtils.importSignedPublicKey(R,h,"ECDH")}catch(R){this._secureLog("error","Failed to import signed ECDH public key",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"ecdh_key_import")}if(!(m instanceof CryptoKey))throw this._secureLog("error","Peer ECDH public key is not a CryptoKey",{operationId:t,publicKeyType:typeof m,publicKeyAlgorithm:m?.algorithm?.name}),new Error("Peer ECDH public key is not a valid CryptoKey");this.peerPublicKey=m;let p;try{this._secureLog("debug","About to call deriveSharedKeys",{operationId:t,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),p=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,m,this.sessionSalt),this._secureLog("debug","deriveSharedKeys completed successfully",{operationId:t,hasMessageKey:!!p.messageKey,hasMacKey:!!p.macKey,hasPfsKey:!!p.pfsKey,hasMetadataKey:!!p.metadataKey,hasFingerprint:!!p.fingerprint})}catch(R){this._secureLog("error","Failed to derive shared keys",{operationId:t,errorType:R.constructor.name,errorMessage:R.message,errorStack:R.stack,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),this._throwSecureError(R,"key_derivation")}if(await this._setEncryptionKeys(p.messageKey,p.macKey,p.metadataKey,p.fingerprint),await this._initializeRatchet(p,!1),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw this._secureLog("error","Invalid key types after derivation",{operationId:t,encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey}),new Error("Invalid key types after derivation");this.verificationCode=e.vc||e.verificationCode||null,this._secureLog("info","Encryption keys derived and set successfully",{operationId:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0});let S;if(e.authChallenge)try{S=await window.EnhancedSecureCryptoUtils.createAuthProof(e.authChallenge,this.ecdsaKeyPair.privateKey,this.ecdsaKeyPair.publicKey)}catch(R){this._secureLog("error","Failed to create authentication proof",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"authentication_proof_creation")}else this._secureLog("warn","No auth challenge in offer - mutual auth disabled",{operationId:t});if(this.isInitiator=!1,this.onStatusChange("connecting"),this.onKeyExchange(this.keyFingerprint),this.createPeerConnection(),this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp)}catch(R){this._secureLog("warn","Could not extract peer DTLS fingerprint from offer",{error:R.message,context:"offer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");try{this._secureLog("debug","Setting remote description from offer",{operationId:t,sdpLength:e.sdp?.length||0}),await this.peerConnection.setRemoteDescription(new RTCSessionDescription({type:"offer",sdp:e.s||e.sdp})),this._logIceCandidateDiagnostics("remote offer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("offer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully",{operationId:t,signalingState:this.peerConnection.signalingState})}catch(R){this._secureLog("error","Failed to set remote description",{error:R.message,operationId:t}),this._throwSecureError(R,"webrtc_remote_description")}this._secureLog("debug","Remote description set successfully",{operationId:t,connectionState:this.peerConnection.connectionState,signalingState:this.peerConnection.signalingState});let g;try{g=await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})}catch(R){this._throwSecureError(R,"webrtc_create_answer")}try{await this.peerConnection.setLocalDescription(g)}catch(R){this._throwSecureError(R,"webrtc_local_description")}try{let R=this._extractDTLSFingerprintFromSDP(g.sdp);this.expectedDTLSFingerprint=R,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:R,context:"answer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${R}`,"system")}catch(R){this._secureLog("error","Failed to extract DTLS fingerprint from answer",{error:R.message})}try{let R=this._extractDTLSFingerprintFromSDP(e.s||e.sdp),ue=this.expectedDTLSFingerprint,K=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(K,ue,R),this._setSASMaterialReady(ue,R)}catch(R){throw this._secureLog("error","SAS computation failed in createSecureAnswer (Answer side)",{errorType:R?.constructor?.name||"Unknown"}),new Error(`SAS computation failed: ${R.message}`)}let b=Date.now(),w=await this.waitForIceGathering(),M=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),F=M.total;if(!w&&F===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the response would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");this._secureLog(F>0?"info":"warn","ICE candidates captured for answer export",{candidateSummary:M,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-b,iceGatheringCompleted:w}),this._logIceCandidateDiagnostics("answer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-b,iceGatheringCompleted:w}),w||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the response. Connectivity may still fail on restrictive networks.","system"),F===0&&this.deliverMessageToUI("No ICE candidates were gathered for the response yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed for answer",{operationId:t,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState});let k=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),E=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!k||typeof k!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!k.keyData||!k.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!k.keyData,hasSignature:!!k.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!E||typeof E!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!E.keyData||!E.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!E.keyData,hasSignature:!!E.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");let _={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},A=Date.now(),x={t:"answer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:A,e:k,d:E,ap:S,slv:"MAX",dr:s.RATCHET_VERSION,sc:{sf:d.substring(0,12),kd:!0,ma:!0}},T=x.s||x.sdp,Y=x.e||x.ecdhPublicKey,B=x.d||x.ecdsaPublicKey;if(!T||!Y||!B)throw new Error("Generated answer package is incomplete");return this._secureLog("info","Enhanced secure answer created successfully",{operationId:t,version:x.version,hasECDSA:!0,hasMutualAuth:!!S,hasSessionConfirmation:!!x.sessionConfirmation,securityLevel:_.level,timestamp:A,processingTime:A-e.timestamp}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:A,securityLevel:_.level,operationId:t}})),setTimeout(async()=>{try{let R=await this.calculateAndReportSecurityLevel();R&&(this.notifySecurityUpdate(),this._secureLog("info","Post-connection security level calculated",{operationId:t,level:R.level}))}catch(R){this._secureLog("error","Error calculating post-connection security",{operationId:t,errorType:R.constructor.name})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(this._secureLog("info","Retrying security calculation",{operationId:t}),await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate(),x}catch(r){throw this._secureLog("error","Enhanced secure answer creation failed in critical section",{operationId:t,errorType:r.constructor.name,errorMessage:r.message,phase:this._determineAnswerErrorPhase(r),offerAge:e?.timestamp?Date.now()-e.timestamp:"unknown"}),this._cleanupFailedAnswerCreation(),this.onStatusChange("disconnected"),this.onAnswerError&&(r.message.includes("too old")||r.message.includes("replay")?this.onAnswerError("replay_attack",r.message):r.message.includes("MITM")||r.message.includes("signature")?this.onAnswerError("security_violation",r.message):r.message.includes("validation")||r.message.includes("format")?this.onAnswerError("invalid_format",r.message):this.onAnswerError("general_error",r.message)),r}},6e4)}_determineAnswerErrorPhase(e){let t=e.message.toLowerCase();return t.includes("validation")||t.includes("format")?"offer_validation":t.includes("rate limit")?"rate_limiting":t.includes("replay")||t.includes("too old")?"replay_protection":t.includes("salt")?"salt_validation":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("import")||t.includes("ecdsa")||t.includes("ecdh")?"key_import":t.includes("signature")||t.includes("mitm")?"signature_verification":t.includes("derive")||t.includes("shared")?"key_derivation":t.includes("auth")||t.includes("proof")?"authentication":t.includes("remote description")||t.includes("local description")?"webrtc_setup":t.includes("answer")||t.includes("sdp")?"sdp_creation":t.includes("export")?"key_export":t.includes("security level")?"security_calculation":"unknown"}_cleanupFailedAnswerCreation(){try{this._clearPendingOfferContext(),this._secureCleanupCryptographicMaterials(),this.currentKeyVersion=0,this.keyVersions.clear(),this.oldKeys.clear(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during answer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed answer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during answer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}async _setEncryptionKeys(e,t,r,i){return this._withMutex("keyOperation",async n=>{if(this._secureLog("info","Setting encryption keys with mutex",{operationId:n}),!(e instanceof CryptoKey)||!(t instanceof CryptoKey)||!(r instanceof CryptoKey))throw new Error("Invalid key types provided");if(!i||typeof i!="string")throw new Error("Invalid key fingerprint provided");let a={encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey,keyFingerprint:this.keyFingerprint};try{return this.encryptionKey=e,this.macKey=t,this.metadataKey=r,this.keyFingerprint=i,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._secureLog("info","Encryption keys set successfully",{operationId:n,hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasFingerprint:!!this.keyFingerprint}),!0}catch(o){throw this.encryptionKey=a.encryptionKey,this.macKey=a.macKey,this.metadataKey=a.metadataKey,this.keyFingerprint=a.keyFingerprint,this._secureLog("error","Key setting failed, rolled back",{operationId:n,errorType:o.constructor.name}),o}})}async _handleSbq2Answer(e){if(!this._isSbq2())throw new Error("Received a new-format response to an old-format invitation. Please start a new invitation.");let t=this._sbq2State(),r=Ur(String(e.sbq2)),i=Fr(r);if(i.type!==de.ANSWER)throw new Error("That code is an invitation, not a response to one.");if(!i.commitment)throw new Error("The response carries no key commitment");let a=await Or(async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),t.localDescriptor),o=0;for(let d=0;dd.toString(16).padStart(2,"0").toUpperCase()).join(":");let{sdp:c}=Kr(i);await this.peerConnection.setRemoteDescription({type:"answer",sdp:c}),this._secureLog("info","SBQ2 answer accepted; awaiting in-band key exchange",{bytes:r.length})}async handleSecureAnswer(e){if(e&&typeof e.sbq2=="string")return this._handleSbq2Answer(e);try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid answer data structure",{hasAnswerData:!!e,answerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Answer data must be a non-null object");let t=e.t==="answer"&&e.s,r=e.type==="enhanced_secure_answer"&&e.sdp;if(!t&&!r)throw this._secureLog("error","CRITICAL: Invalid answer format",{type:e.type||e.t,hasSdp:!!(e.sdp||e.s)}),new Error("CRITICAL SECURITY FAILURE: Invalid answer format - hard abort required");let i=e.v||e.version;if(i!==s.PROTOCOL_VERSION)throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${i||"unknown"}`);let n=e.ecdhPublicKey||e.e,a=e.ecdsaPublicKey||e.d;if(!n||typeof n!="object"||Array.isArray(n))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure in answer",{hasEcdhKey:!!n,ecdhKeyType:typeof n,isArray:Array.isArray(n),availableKeys:Object.keys(e)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDH public key structure");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature in answer",{hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!a||typeof a!="object"||Array.isArray(a))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure in answer",{hasEcdsaKey:!!a,ecdsaKeyType:typeof a,isArray:Array.isArray(a)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDSA public key structure");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature in answer",{hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");let o=e.ts||e.timestamp,c=e.v||e.version;if(!o||!c)throw new Error("Missing required fields in response data \u2013 possible MITM attack");if(e.sessionId&&this.sessionId&&e.sessionId!==this.sessionId)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Session ID mismatch detected - possible MITM attack",{}),new Error("Session ID mismatch \u2013 possible MITM attack");let d=Date.now()-e.timestamp;if(d>36e5)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Answer data is too old - possible replay attack",{answerAge:d,timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Response data is too old \u2013 possible replay attack"),new Error("Response data is too old \u2013 possible replay attack");i!==s.PROTOCOL_VERSION&&window.EnhancedSecureCryptoUtils.secureLog.log("warn","Incompatible protocol version in answer",{expectedVersion:s.PROTOCOL_VERSION,receivedVersion:i});let u=await crypto.subtle.importKey("spki",new Uint8Array(a.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),h=await window.EnhancedSecureCryptoUtils.importPublicKeyFromSignedPackage(n,u);if(this._restorePendingOfferContextIfNeeded(),!this.sessionSalt||this.sessionSalt.length!==64)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid session salt detected - possible session hijacking",{saltLength:this.sessionSalt?this.sessionSalt.length:0}),new Error("Missing pending offer context. Apply the response in the original creator window that generated the invitation.");let m=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);if(window.EnhancedSecureCryptoUtils.secureLog.log("info","Session salt integrity verified",{saltFingerprint:m.substring(0,8)}),!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Local ECDH private key is not a CryptoKey in handleSecureAnswer",{hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a CryptoKey");if(!(h instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Peer ECDH public key is not a CryptoKey in handleSecureAnswer",{publicKeyType:typeof h,publicKeyAlgorithm:h?.algorithm?.name}),new Error("Peer ECDH public key is not a CryptoKey");this.peerPublicKey=h,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,this.connectionId||(this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(g=>g.toString(16).padStart(2,"0")).join(""));let p=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,h,this.sessionSalt);if(this.encryptionKey=p.messageKey,this.macKey=p.macKey,this.metadataKey=p.metadataKey,this.keyFingerprint=p.fingerprint,await this._initializeRatchet(p,!0),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid key types after derivation in handleSecureAnswer",{encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey,encryptionKeyAlgorithm:this.encryptionKey?.algorithm?.name,macKeyAlgorithm:this.macKey?.algorithm?.name,metadataKeyAlgorithm:this.metadataKey?.algorithm?.name}),new Error("Invalid key types after export");this._secureLog("info","Encryption keys set in handleSecureAnswer",{hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasPFS=!0,this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0}),this.onKeyExchange(this.keyFingerprint);try{let g=this._extractDTLSFingerprintFromSDP(e.sdp||e.s),b=this.expectedDTLSFingerprint,w=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(w,b,g),this._setSASMaterialReady(b,g),this.pendingSASCode=this.verificationCode,this._secureLog("info","SAS verification code generated for MITM protection (Offer side)",{sasCode:this.verificationCode,localFP:b.substring(0,16)+"...",remoteFP:g.substring(0,16)+"...",timestamp:Date.now()})}catch(g){this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{errorType:g?.constructor?.name||"Unknown"}),this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{error:g.message,stack:g.stack,timestamp:Date.now()})}if(this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp||e.s)}catch(g){this._secureLog("warn","Could not extract peer DTLS fingerprint from answer",{error:g.message,context:"answer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");let S=e.sdp||e.s;if(this.peerConnection?.signalingState!=="have-local-offer"){this._secureLog("warn","Ignoring answer outside have-local-offer state",{signalingState:this.peerConnection?.signalingState||"unknown"});return}this._secureLog("debug","Setting remote description from answer",{sdpLength:S?.length||0,usingCompactSDP:!e.sdp&&!!e.s}),await this.peerConnection.setRemoteDescription({type:"answer",sdp:S}),this._logIceCandidateDiagnostics("remote answer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("answer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully from answer",{signalingState:this.peerConnection.signalingState}),setTimeout(async()=>{try{await this.calculateAndReportSecurityLevel()&&this.notifySecurityUpdate()}catch(g){this._secureLog("error","Error calculating security after connection:",{errorType:g?.constructor?.name||"Unknown"})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate()}catch(t){throw this._secureLog("error","Enhanced secure answer handling failed",{errorType:t.constructor.name}),this.onStatusChange("failed"),this.onAnswerError&&(t.message.includes("too old")||t.message.includes("\u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0441\u0442\u0430\u0440\u044B\u0435")?this.onAnswerError("replay_attack",t.message):t.message.includes("MITM")||t.message.includes("signature")||t.message.includes("\u043F\u043E\u0434\u043F\u0438\u0441\u044C")?this.onAnswerError("security_violation",t.message):this.onAnswerError("general_error",t.message)),t}}initiateVerification(){this.isInitiator?this.verificationInitiationSent||(this.verificationInitiationSent=!0,this.deliverMessageToUI("CRITICAL: Compare verification code with peer out-of-band (voice/video/in-person) to prevent MITM attack!","system"),this.deliverMessageToUI(`Your verification code: ${this.verificationCode}`,"system"),this.deliverMessageToUI("Ask peer to confirm this exact code before allowing traffic!","system")):this.deliverMessageToUI("Waiting for verification code from peer...","system")}_validateSASCode(e){if(!e||typeof e!="string"||!this.verificationCode||typeof this.verificationCode!="string")return!1;let t=e.replace(/[-\s]/g,"").toUpperCase(),r=this.verificationCode.replace(/[-\s]/g,"").toUpperCase();return t.length!==r.length?!1:window.EnhancedSecureCryptoUtils.constantTimeCompare(t,r)}confirmVerification(e){try{if(!this._validateSASCode(e))throw this.sasValidationAttempts=(this.sasValidationAttempts||0)+1,this._secureLog("warn","SAS validation failed: user entered incorrect code",{attempts:this.sasValidationAttempts,maxAttempts:s.MAX_SAS_ATTEMPTS}),this.sasValidationAttempts>=s.MAX_SAS_ATTEMPTS?(this.deliverMessageToUI("Verification failed 3 times. Session reset for safety.","system"),this.disconnect(),new Error("SAS_MAX_ATTEMPTS")):new Error("SAS_MISMATCH");this.localVerificationConfirmed=!0,this.sasValidationAttempts=0;let t={type:"verification_confirmed",data:{timestamp:Date.now(),verificationMethod:"MANUAL_SAS_ENTRY",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(t)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed(),this.deliverMessageToUI("Code verified locally. Waiting for peer confirmation...","system"),this.processMessageQueue()}catch(t){throw t.message==="SAS_MISMATCH"?this.deliverMessageToUI("Verification failed: the code you entered is incorrect.","system"):t.message!=="SAS_MAX_ATTEMPTS"&&(this._secureLog("error","SAS verification failed:",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("SAS verification failed","system")),t}}_checkBothVerificationsConfirmed(){if(this.localVerificationConfirmed&&this.remoteVerificationConfirmed&&!this.bothVerificationsConfirmed){this.bothVerificationsConfirmed=!0;let e={type:"verification_both_confirmed",data:{timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_COMPLETE"}};this.dataChannel.send(JSON.stringify(e)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{try{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")}catch(t){this._secureLog("error","Verified transition rejected - aborting session",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("Verification could not be completed safely. Connection aborted.","system"),this.disconnect()}},2e3)}}handleVerificationConfirmed(e){this.remoteVerificationConfirmed=!0,this.deliverMessageToUI("Peer confirmed the verification code. Waiting for your confirmation...","system"),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed()}handleVerificationBothConfirmed(e){if(!this.bothVerificationsConfirmed){if(!this.localVerificationConfirmed){this._secureLog("error","Peer claimed mutual SAS confirmation before local confirmation - possible MITM attack",{localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,timestamp:Date.now()}),this.deliverMessageToUI("Verification protocol violation: peer claimed confirmation before you verified the code. Connection aborted for safety.","system"),this.disconnect();return}this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")},2e3)}}handleVerificationRequest(e){if(this._validateSASCode(e?.code)){let t={type:"verification_response",data:{ok:!0,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTED"}};this.dataChannel.send(JSON.stringify(t)),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI("SAS verification successful! MITM protection confirmed. Channel is now secure!","system")),this.processMessageQueue()}else{let t={type:"verification_response",data:{ok:!1,timestamp:Date.now(),reason:"code_mismatch"}};this.dataChannel.send(JSON.stringify(t)),this._secureLog("error","SAS verification failed - possible MITM attack",{receivedCodeLength:typeof e?.code=="string"?e.code.length:0,timestamp:Date.now()}),this.deliverMessageToUI("SAS verification failed! Possible MITM attack detected. Connection aborted for safety!","system"),this.disconnect()}}handleSASCode(e){if(!e?.code||typeof e.code!="string"){this._secureLog("warn","Invalid SAS announcement received from peer");return}if(!this.verificationCode){this._secureLog("error","Received peer SAS announcement before local SAS was derived - refusing to adopt it",{timestamp:Date.now()}),this.deliverMessageToUI("Verification failed: no locally derived code to compare against. Connection aborted for safety.","system"),this.disconnect();return}if(!this._validateSASCode(e.code)){this._secureLog("error","Peer-announced SAS does not match locally computed SAS"),this.deliverMessageToUI("Version or SAS mismatch detected. Connection aborted for safety.","system"),this.disconnect();return}this._notifyVerificationReadyIfPossible(),this._secureLog("info","Peer SAS announcement matched locally derived code",{timestamp:Date.now()})}handleVerificationResponse(e){e.ok===!0?(this._secureLog("info","Mutual SAS verification completed - MITM protection active",{verificationMethod:e.verificationMethod||"SAS",securityLevel:e.securityLevel||"MITM_PROTECTED",timestamp:Date.now()}),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI(" Mutual SAS verification complete! MITM protection active. Channel is now secure!","system")),this.processMessageQueue()):(this._secureLog("error","Peer SAS verification failed - connection not secure",{responseData:e,timestamp:Date.now()}),this.deliverMessageToUI("Peer verification failed! Connection not secure!","system"),this.disconnect())}validateOfferData(e){return e&&e.type==="enhanced_secure_offer"&&e.sdp&&e.publicKey&&e.salt&&e.verificationCode&&Array.isArray(e.publicKey)&&Array.isArray(e.salt)&&e.salt.length===32}validateEnhancedOfferData(e){try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid offer data structure",{hasOfferData:!!e,offerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Offer data must be a non-null object");let t=e.v===s.PROTOCOL_VERSION&&e.e&&e.d,r=e.version===s.PROTOCOL_VERSION&&e.ecdhPublicKey&&e.ecdsaPublicKey;if(!(t?["offer"].includes(e.t):["enhanced_secure_offer","secure_offer"].includes(e.type)))throw new Error("Invalid offer type");if(t){let a=["e","d","sl","vc","si","ci","ac","slv"];for(let c of a)if(!e[c])throw new Error(`Missing required v4.1 compact field: ${c}`);if(!e.e||typeof e.e!="object"||Array.isArray(e.e))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure");if(!e.d||typeof e.d!="object"||Array.isArray(e.d))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure");if(!Array.isArray(e.sl)||e.sl.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");if(typeof e.vc!="string"||e.vc.length<6)throw new Error("Invalid verification code format");if(!["MAX","HIGH","MED","LOW"].includes(e.slv))throw new Error("Invalid security level");let o=Date.now()-e.ts;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");this._secureLog("info","v4.1 compact offer validation passed",{version:e.v,hasECDH:!!e.e,hasECDSA:!!e.d,hasSalt:!!e.sl,hasVerificationCode:!!e.vc,securityLevel:e.slv,offerAge:Math.round(o/1e3)+"s"})}else if(r){let a=["ecdhPublicKey","ecdsaPublicKey","salt","verificationCode","authChallenge","timestamp","version","securityLevel"];for(let c of a)if(!e[c])throw new Error(`Missing v4.1 field: ${c}`);if(!Array.isArray(e.salt)||e.salt.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");let o=Date.now()-e.timestamp;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");if(!e.ecdhPublicKey||typeof e.ecdhPublicKey!="object"||Array.isArray(e.ecdhPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure",{hasEcdhKey:!!e.ecdhPublicKey,ecdhKeyType:typeof e.ecdhPublicKey,isArray:Array.isArray(e.ecdhPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure - hard abort required");if(!e.ecdsaPublicKey||typeof e.ecdsaPublicKey!="object"||Array.isArray(e.ecdsaPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure",{hasEcdsaKey:!!e.ecdsaPublicKey,ecdsaKeyType:typeof e.ecdsaPublicKey,isArray:Array.isArray(e.ecdsaPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure - hard abort required");if(!e.ecdhPublicKey.keyData||!e.ecdhPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature",{hasKeyData:!!e.ecdhPublicKey.keyData,hasSignature:!!e.ecdhPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!e.ecdsaPublicKey.keyData||!e.ecdsaPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature",{hasKeyData:!!e.ecdsaPublicKey.keyData,hasSignature:!!e.ecdsaPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");if(typeof e.verificationCode!="string"||e.verificationCode.length<6)throw new Error("Invalid SAS verification code format - MITM protection required");this._secureLog("info","v4.1 offer validation passed",{version:e.version,hasSecurityLevel:!!e.securityLevel?.level,offerAge:Math.round(o/1e3)+"s"})}else{let a=e.v||e.version||"unknown";throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${a}`)}let n=t?e.s:e.sdp;if(typeof n!="string"||!n.includes("v=0"))throw new Error("Invalid SDP structure");return!0}catch(t){throw this._secureLog("error","CRITICAL: Security validation failed - hard abort required",{error:t.message,errorType:t.constructor.name,timestamp:Date.now()}),new Error(`CRITICAL SECURITY VALIDATION FAILURE: ${t.message}`)}}async sendSecureMessage(e){let t=this._validateInputData(e,"sendSecureMessage");if(!t.isValid){let r=`Input validation failed: ${t.errors.join(", ")}`;throw this._secureLog("error","Input validation failed in sendSecureMessage",{errors:t.errors,messageType:typeof e}),new Error(r)}if(!this._checkRateLimit("sendSecureMessage"))throw new Error("Rate limit exceeded for secure message sending");if(this._enforceVerificationGate("sendSecureMessage"),!this.isConnected())throw t.sanitizedData&&typeof t.sanitizedData=="object"&&t.sanitizedData.type&&t.sanitizedData.type.startsWith("file_")?new Error("Connection not ready for file transfer. Please ensure the connection is established and verified."):(this.messageQueue.push(t.sanitizedData),new Error("Connection not ready. Message queued for sending."));return this._withMutex("cryptoOperation",async r=>{if(!this.isConnected()||!this.isVerified)throw new Error("Connection lost during message preparation");if(!this.encryptionKey||!this.macKey||!this.metadataKey)throw new Error("Encryption keys not initialized");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkMessageRate(this.rateLimiterId))throw new Error("Message rate limit exceeded (60 messages per minute)");try{let i=typeof t.sanitizedData=="string"?t.sanitizedData:JSON.stringify(t.sanitizedData),n=window.EnhancedSecureCryptoUtils.sanitizeMessage(i),a=`msg_${Date.now()}_${this.messageCounter++}`;if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in sendSecureMessage. Manager may not be fully initialized.");let o=e.aad||this._createMessageAAD("enhanced_message",{content:n}),c;if(this._ratchet?.canEncrypt){let{header:d,ciphertext:u}=await this._ratchet.encrypt(n);c={type:s.MESSAGE_TYPES.RATCHET_MESSAGE,h:d,c:u,version:"5.0"}}else c={type:"enhanced_message",data:await window.EnhancedSecureCryptoUtils.encryptMessage(n,this.encryptionKey,this.macKey,this.metadataKey,a,JSON.parse(o).sequenceNumber),keyVersion:this.currentKeyVersion,version:"4.0"};this.dataChannel.send(JSON.stringify(c)),typeof t.sanitizedData=="string"&&this.deliverMessageToUI(t.sanitizedData,"sent"),this._secureLog("debug","Secure message sent successfully",{operationId:r,messageLength:n.length,keyVersion:this.currentKeyVersion})}catch(i){throw this._secureLog("error","Secure message sending failed",{operationId:r,errorType:i.constructor.name}),i.message.includes("Session expired")?new Error("Session expired. Please enter your password to unlock."):i.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):i.message.includes("Connection lost")?new Error("Connection lost. Please check your Internet connection."):i.message.includes("Rate limit exceeded")?new Error("Message rate limit exceeded. Please wait before sending another message."):i}},2e3)}processMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected()&&this.isVerified;){let e=this.messageQueue.shift();this.sendSecureMessage(e).catch(console.error)}}startHeartbeat(){this._heartbeatConfig={enabled:!0,interval:s.TIMEOUTS.HEARTBEAT_INTERVAL,lastHeartbeat:0},this.stopHeartbeat(!0),this._heartbeatTimer=setInterval(()=>{this._heartbeatConfig?.enabled&&this.dataChannel?.readyState==="open"&&this._sendHeartbeat()},s.TIMEOUTS.HEARTBEAT_INTERVAL),this._trackActiveTimer(this._heartbeatTimer),this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!1,this._startLivenessWatchdog(),this._setupRecoveryLifecycleListeners(),this._secureLog("info","\u{1F504} Liveness watchdog started",{heartbeatMs:s.TIMEOUTS.HEARTBEAT_INTERVAL,probeAfterMs:s.TIMEOUTS.LIVENESS_PROBE_AFTER,probeTimeoutMs:s.TIMEOUTS.LIVENESS_PROBE_TIMEOUT})}stopHeartbeat(e=!1){!e&&this._heartbeatConfig&&(this._heartbeatConfig.enabled=!1),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._activeTimers?.delete(this._heartbeatTimer),this._heartbeatTimer=null),e||this._stopLivenessWatchdog()}handleHeartbeat(e){this._lastInboundAt=Date.now(),this._livenessProbeAt=0;let t=e?.ack===!0||e?.data?.ack===!0;t||this._sendHeartbeat(!0),this._secureLog("debug",t?"\u{1F493} Heartbeat ack received":"\u{1F493} Heartbeat probe received")}_noteInboundActivity(){this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!0}_startLivenessWatchdog(){this._stopLivenessWatchdog(),this._livenessTimer=setInterval(()=>{try{this._checkLiveness()}catch(e){this._secureLog("error","\u274C Liveness check failed",{errorType:e?.constructor?.name||"Unknown"})}},s.TIMEOUTS.LIVENESS_CHECK_INTERVAL),this._trackActiveTimer(this._livenessTimer)}_stopLivenessWatchdog(){this._livenessTimer&&(clearInterval(this._livenessTimer),this._activeTimers?.delete(this._livenessTimer),this._livenessTimer=null)}_checkLiveness(){if(!this.isVerified||this._reconnect.phase!=="idle"||this.dataChannel?.readyState!=="open"||!this._lastInboundAt||!this._livenessArmed)return;let e=s.TIMEOUTS,t=Date.now();if(this.peerConnection?.connectionState==="connected"){this._livenessProbeAt=0;return}if(this._livenessProbeAt){if(t-this._livenessProbeAt"u"||this._recoveryLifecycleBound||(this._recoveryLifecycleBound=!0,this._onDeviceOnline=()=>{this.isVerified&&(this.isReconnecting()?(this._secureLog("info","\u{1F504} Device back online \u2014 retrying immediately"),this._attemptIceRestart()):this._checkLiveness())},this._onVisibilityRestored=()=>{typeof document>"u"||document.visibilityState!=="visible"||this.isVerified&&(this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._reconnect.phase==="idle"&&this.dataChannel?.readyState==="open"&&(this._livenessProbeAt=Date.now(),this._sendHeartbeat(!1),this._secureLog("info","\u{1F504} returned to foreground, probing peer")))},window.addEventListener("online",this._onDeviceOnline),typeof document<"u"&&document.addEventListener("visibilitychange",this._onVisibilityRestored))}_teardownRecoveryLifecycleListeners(){!this._recoveryLifecycleBound||typeof window>"u"||(this._recoveryLifecycleBound=!1,this._onDeviceOnline&&window.removeEventListener("online",this._onDeviceOnline),this._onVisibilityRestored&&typeof document<"u"&&document.removeEventListener("visibilitychange",this._onVisibilityRestored),this._onDeviceOnline=null,this._onVisibilityRestored=null)}_resetReconnectState(){let e=this._reconnect;e&&(e.graceTimer&&(clearTimeout(e.graceTimer),this._activeTimers?.delete(e.graceTimer)),e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer)),e.restartTimer&&(clearTimeout(e.restartTimer),this._activeTimers?.delete(e.restartTimer)),e.graceTimer=null,e.retryTimer=null,e.restartTimer=null,e.phase="idle",e.attempts=0,e.startedAt=0,e.inFlightAt=0,e.barrenFailures=0,e.pendingRole=null)}_onPathDegraded(e="ice_disconnected"){this.isVerified&&this._reconnect.phase==="idle"&&(this._reconnect.phase="grace",this._reconnect.startedAt=Date.now(),this._secureLog("info","\u{1F504} path degraded, holding grace window",{reason:e}),this.onStatusChange("reconnecting"),this._reconnect.graceTimer=setTimeout(()=>{if(this._reconnect.graceTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},s.TIMEOUTS.ICE_DISCONNECT_GRACE),this._trackActiveTimer(this._reconnect.graceTimer))}_onPathLost(e="ice_failed"){this.isVerified&&(this._reconnect.phase==="restarting"||this._reconnect.phase==="exhausted"||(this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.graceTimer&&(clearTimeout(this._reconnect.graceTimer),this._activeTimers?.delete(this._reconnect.graceTimer),this._reconnect.graceTimer=null),this._secureLog("info","\u{1F504} path lost, restarting ICE",{reason:e}),this._attemptIceRestart()))}_noteIceFailureDiagnostics(e){if(this.isReconnecting()&&e){if(e.pairCount>0){this._reconnect.barrenFailures=0;return}this._reconnect.barrenFailures=(this._reconnect.barrenFailures||0)+1,!(this._reconnect.barrenFailuress.TIMEOUTS.RECONNECT_MAX_DURATION){this._giveUpAutoReconnect("timeout");return}if(e.inFlightAt&&Date.now()-e.inFlightAt=2&&r>s.TIMEOUTS.RECOVERY_SILENCE_LIMIT){this._secureLog("warn","\u26A0\uFE0F nothing has reached us since the drop \u2014 the channel cannot carry a renegotiation",{silentForMs:r,attempts:e.attempts}),this._giveUpAutoReconnect("no_signalling_path");return}e.phase="restarting",e.attempts+=1,e.inFlightAt=Date.now(),this._secureLog("info","\u{1F504} ICE restart attempt",{attempt:e.attempts,role:this.isInitiator?"offerer":"answerer"});try{this.isInitiator?await this._sendIceRestartOffer():await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_REQUEST,timestamp:Date.now()})}catch(i){this._secureLog("warn","\u26A0\uFE0F ICE restart attempt failed to send",{errorType:i?.constructor?.name||"Unknown"})}this._scheduleReconnectRetry()}_scheduleReconnectRetry(){let e=this._reconnect;e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer));let t=s.RECONNECT_BACKOFF,r=t[Math.min(Math.max(e.attempts-1,0),t.length-1)];e.retryTimer=setTimeout(()=>{if(e.retryTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},r),this._trackActiveTimer(e.retryTimer)}_applyCurrentIceServers(e){try{if(!e||typeof e.getConfiguration!="function"||typeof e.setConfiguration!="function")return;let t=this._config?.webrtc?.iceServers;if(!Array.isArray(t)||t.length===0)return;e.setConfiguration({...e.getConfiguration(),iceServers:t})}catch(t){this._secureLog("warn","Could not refresh ICE servers before restart",{errorType:t?.constructor?.name||"Unknown"})}}async _sendIceRestartOffer(){let e=this.peerConnection;if(!e)return;if(this._applyCurrentIceServers(e),e.signalingState==="have-local-offer")try{await e.setLocalDescription({type:"rollback"})}catch{}let t=await e.createOffer({iceRestart:!0});await e.setLocalDescription(t),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_OFFER,sdp:e.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart offer sent")}_currentRemoteDtlsFingerprint(){let e=this.peerConnection?.currentRemoteDescription?.sdp||this.peerConnection?.remoteDescription?.sdp;if(!e)return null;try{return this._extractDTLSFingerprintFromSDP(e)}catch{return null}}async _assertSameRemoteIdentity(e,t){let r=this._currentRemoteDtlsFingerprint();if(!r)throw new Error(`Cannot verify peer identity for ${t}`);let i=this._extractDTLSFingerprintFromSDP(e);await this._validateDTLSFingerprint(i,r,t)}async _handleIceRestartSignal(e,t){let r=s.MESSAGE_TYPES,i=this.peerConnection;if(i)switch(this._noteInboundActivity(),e){case r.ICE_RESTART_REQUEST:{if(!this.isInitiator)return;this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this._reconnect.phase="restarting",this.onStatusChange("reconnecting")),await this._sendIceRestartOffer();return}case r.ICE_RESTART_OFFER:{if(!t.sdp)return;await this._assertSameRemoteIdentity(t.sdp,"ice_restart_offer"),this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.phase="restarting",this._applyCurrentIceServers(i),await i.setRemoteDescription({type:"offer",sdp:t.sdp});let n=await i.createAnswer();await i.setLocalDescription(n),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:r.ICE_RESTART_ANSWER,sdp:i.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart answer sent");return}case r.ICE_RESTART_ANSWER:{if(!t.sdp)return;if(i.signalingState!=="have-local-offer"){this._secureLog("warn","\u26A0\uFE0F Ignoring restart answer in unexpected state",{signalingState:i.signalingState});return}await this._assertSameRemoteIdentity(t.sdp,"ice_restart_answer"),await i.setRemoteDescription({type:"answer",sdp:t.sdp}),this._reconnect.inFlightAt=0,this._secureLog("debug","\u{1F504} ICE restart answer applied");return}default:}}_giveUpAutoReconnect(e){this._resetReconnectState(),this._reconnect.phase="exhausted",this._teardownRecoveryLifecycleListeners?.(),this._secureLog("warn","\u26A0\uFE0F automatic reconnection exhausted \u2014 ending session",{reason:e}),this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Could not restore the connection. This chat is being closed and its data wiped \u2014 start a new one to continue.","system")),this.onStatusChange("recovery_failed"),this._clearVerificationStates()}_stopAllTimers(){this._secureLog("info","Stopping all timers and cleanup scheduler"),this._maintenanceScheduler&&(clearInterval(this._maintenanceScheduler),this._maintenanceScheduler=null),this.stopHeartbeat?.(),this._resetReconnectState?.(),this._activeTimers&&(this._activeTimers.forEach(e=>{e&&(clearInterval(e),clearTimeout(e))}),this._activeTimers.clear()),this._fileTransferInitRetryTimers&&this._fileTransferInitRetryTimers.clear(),this._logCleanupInterval=null,this._secureLog("info","All timers stopped successfully")}waitForIceGathering(e=s.TIMEOUTS.ICE_GATHERING_TIMEOUT,t=s.TIMEOUTS.ICE_GATHERING_HARD_TIMEOUT){return new Promise(r=>{let i=this.peerConnection;if(!i){r(!1);return}if(i.iceGatheringState==="complete"){r(!0);return}let n=!1,a=null,o=null,c=()=>{try{let h=this.peerConnection?.localDescription?.sdp;return h?this._summarizeIceCandidatesInSDP(h).total>0:!1}catch{return!1}},d=h=>{if(!n){n=!0,a&&(clearTimeout(a),this._untrackActiveTimer?.(a)),o&&(clearTimeout(o),this._untrackActiveTimer?.(o));try{i.removeEventListener("icegatheringstatechange",u)}catch{}r(h)}},u=()=>{this.peerConnection?.iceGatheringState==="complete"&&d(!0)};i.addEventListener("icegatheringstatechange",u),a=setTimeout(()=>{c()&&d(!1)},e),this._trackActiveTimer?.(a),o=setTimeout(()=>d(!1),Math.max(t,e)),this._trackActiveTimer?.(o)})}retryConnection(){this._secureLog("info","Retrying connection",{attempt:this.connectionAttempts,maxAttempts:this.maxConnectionAttempts}),this.onStatusChange("retrying")}isConnected(){let e=!!this.dataChannel,r=this.dataChannel?.readyState==="open",i=this.isVerified,n=this.peerConnection?.connectionState;return this.dataChannel&&this.dataChannel.readyState==="open"&&this.isVerified}getConnectionInfo(){return{fingerprint:this.keyFingerprint,isConnected:this.isConnected(),isVerified:this.isVerified,connectionState:this.peerConnection?.connectionState,iceConnectionState:this.peerConnection?.iceConnectionState,verificationCode:this.verificationCode}}handleUnexpectedDisconnect(){this.sendDisconnectNotification(),this.isVerified=!1,this.disconnectNotificationSent||(this.disconnectNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Connection lost. Attempting to reconnect...","system")),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"connection_lost",timestamp:Date.now()}}))}sendDisconnectNotification(){try{if(this.dataChannel&&this.dataChannel.readyState==="open"){let e={type:"peer_disconnect",timestamp:Date.now(),reason:this.intentionalDisconnect?"user_disconnect":"connection_lost"};for(let t=0;t<3;t++)try{this.dataChannel.send(JSON.stringify(e)),window.EnhancedSecureCryptoUtils.secureLog.log("info","Disconnect notification sent",{reason:e.reason,attempt:t+1});break}catch(r){t===2&&window.EnhancedSecureCryptoUtils.secureLog.log("error","Failed to send disconnect notification",{error:r.message})}}}catch(e){window.EnhancedSecureCryptoUtils.secureLog.log("error","Could not send disconnect notification",{error:e.message})}}attemptReconnection(){return!this.isVerified||this.dataChannel?.readyState!=="open"?(this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Unable to reconnect. A new connection is required.","system")),!1):(this._resetReconnectState(),this.reconnectionFailedNotificationSent=!1,this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting"),this._attemptIceRestart(),!0)}handlePeerDisconnectNotification(e){let t=e.reason||"unknown",r=t==="user_disconnect"?"manually disconnected.":"connection lost.";this.peerDisconnectNotificationSent||(this.peerDisconnectNotificationSent=!0,this.deliverMessageToUI(`Peer ${r}`,"system")),this.onStatusChange("peer_disconnected"),this.intentionalDisconnect=!1,this.isVerified=!1,this.stopHeartbeat(),this.onKeyExchange(""),this.onVerificationRequired(""),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:t,timestamp:Date.now()}})),this._peerDisconnectCleanupTimer||(this._peerDisconnectCleanupTimer=this._trackActiveTimer(setTimeout(()=>{let i=this._peerDisconnectCleanupTimer;this._peerDisconnectCleanupTimer=null,this._untrackActiveTimer(i),this._sessionAlive!==!1&&this.disconnect()},2e3))),window.EnhancedSecureCryptoUtils.secureLog.log("info","Peer disconnect notification processed",{reason:t})}disconnect(){try{this._sessionAlive=!1;try{this._stopAdaptation?.()}catch{}try{this._stopLocalMediaPermanently?.()}catch{}this._callAudioSender=null,this._callVideoSender=null,this._callGroupContext=null,this._externalMediaStream=null,this._callStateListeners?.clear?.(),this.intentionalDisconnect=!0,window.EnhancedSecureCryptoUtils.secureLog.log("info","Starting intentional disconnect"),this.sendDisconnectNotification(),this._teardownRecoveryLifecycleListeners?.(),this._stopAllTimers(),this._peerDisconnectCleanupTimer=null,this.stopHeartbeat(),this.stopFakeTrafficGeneration();for(let e of this.decoyTimers.entries())clearTimeout(e[1]);this.decoyTimers.clear(),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null);for(let e of this.decoyChannels.values())e.readyState==="open"&&e.close();this.decoyChannels.clear(),this.heartbeatChannel&&(this.heartbeatChannel.close(),this.heartbeatChannel=null),this.isVerified=!1,this.processedMessageIds.clear(),this.messageCounter=0,this.packetBuffer.clear(),this.chunkQueue=[],this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this._secureCleanupCryptographicMaterials(),this.keyVersions.clear(),this.oldKeys.clear(),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.replayWindow.clear(),this._clearVerificationStates(),this.securityFeatures={hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0},this.dataChannel&&(this.dataChannel.close(),this.dataChannel.onopen=null,this.dataChannel.onclose=null,this.dataChannel.onmessage=null,this.dataChannel.onerror=null,this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection.onconnectionstatechange=null,this.peerConnection.ondatachannel=null,this.peerConnection=null),this.messageQueue&&this.messageQueue.length>0&&(this.messageQueue.forEach((e,t)=>{this._secureWipeMemory(e,`messageQueue[${t}]`)}),this.messageQueue=[]),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during disconnect",{errorType:e?.constructor?.name||"Unknown"})}),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"user_disconnect",timestamp:Date.now()}})),this._dispatchAppEvent?.(new CustomEvent("connection-cleaned",{detail:{timestamp:Date.now(),reason:"user_cleanup"}})),this.onStatusChange("disconnected"),this.onKeyExchange(""),this.onVerificationRequired(""),this._secureLog("info","Connection securely cleaned up with complete memory wipe")}catch(e){this._secureLog("error","\u274C Error during enhanced disconnect:",{errorType:e?.constructor?.name||"Unknown"})}finally{this.intentionalDisconnect=!1}}async sendFile(e,t={}){if(this._enforceVerificationGate("sendFile"),!this.isConnected())throw new Error("Connection not ready for file transfer. Please ensure the connection is established.");if(!this.fileTransferSystem&&(this.initializeFileTransfer(),await new Promise(r=>setTimeout(r,500)),!this.fileTransferSystem))throw new Error("File transfer system could not be initialized. Please try reconnecting.");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready. Please wait for connection to be fully established.");try{return await this.fileTransferSystem.sendFile(e,t)}catch(r){throw this._secureLog("error","File transfer error:",{errorType:r?.constructor?.name||"Unknown"}),r.message.includes("Connection not ready")?new Error("Connection not ready for file transfer. Check connection status."):r.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):r.message.includes("Transfer timeout")?new Error("File transfer timeout. Check connection and try again."):r}}getFileTransfers(){if(!this.fileTransferSystem)return{sending:[],receiving:[]};try{let e=[],t=[];return typeof this.fileTransferSystem.getActiveTransfers=="function"?e=this.fileTransferSystem.getActiveTransfers():this._secureLog("warn","getActiveTransfers method not available in file transfer system"),typeof this.fileTransferSystem.getReceivingTransfers=="function"?t=this.fileTransferSystem.getReceivingTransfers():this._secureLog("warn","getReceivingTransfers method not available in file transfer system"),{sending:e||[],receiving:t||[]}}catch(e){return this._secureLog("error","Error getting file transfers:",{errorType:e?.constructor?.name||"Unknown"}),{sending:[],receiving:[]}}}getFileTransferStatus(){if(!this.fileTransferSystem)return{initialized:!1,status:"not_initialized",message:"File transfer system not initialized"};let e=this.fileTransferSystem.getActiveTransfers(),t=this.fileTransferSystem.getReceivingTransfers();return{initialized:!0,status:"ready",activeTransfers:e.length,receivingTransfers:t.length,totalTransfers:e.length+t.length}}cancelFileTransfer(e){return this.fileTransferSystem?this.fileTransferSystem.cancelTransfer(e):!1}cleanupFileTransferSystem(){return this.fileTransferSystem?(this._secureLog("info","\u{1F9F9} Force cleaning up file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,!0):!1}reinitializeFileTransfer(){try{return this.fileTransferSystem&&this.fileTransferSystem.cleanup(),this.initializeFileTransfer(),!0}catch(e){return this._secureLog("error","Failed to reinitialize file transfer system:",{errorType:e?.constructor?.name||"Unknown"}),!1}}setFileTransferCallbacks(e,t,r,i=null){this.onFileProgress=e,this.onFileReceived=t,this.onFileError=r,this.onIncomingFileRequest=i,this.fileTransferSystem&&(this.fileTransferSystem.onProgress=e,this.fileTransferSystem.onFileReceived=t,this.fileTransferSystem.onError=r,this.fileTransferSystem.onIncomingFileRequest=i)}getPendingIncomingFiles(){return this.fileTransferSystem?this.fileTransferSystem.getPendingIncomingTransfers():[]}async acceptIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.acceptIncomingFile(e):!1}async rejectIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.rejectIncomingFile(e):!1}async getReceivedFileObjectURL(e){return this.fileTransferSystem?this.fileTransferSystem.getObjectURL(e):null}revokeReceivedFileObjectURL(e){this.fileTransferSystem&&this.fileTransferSystem.revokeObjectURL(e)}async handleSessionActivation(e){try{this.currentSession=e;let t=!!(this.encryptionKey&&this.macKey);e.sessionId&&this.onStatusChange("connected"),setTimeout(()=>{try{this.initializeFileTransfer()}catch(i){this._secureLog("warn","File transfer initialization failed during session activation:",{details:i.message})}},1e3),this.fileTransferSystem&&this.isConnected()&&typeof this.fileTransferSystem.onSessionUpdate=="function"&&this.fileTransferSystem.onSessionUpdate({keyFingerprint:this.keyFingerprint,sessionSalt:this.sessionSalt,hasMacKey:!!this.macKey})}catch(t){this._secureLog("error","Failed to handle session activation:",{errorType:t?.constructor?.name||"Unknown"})}}checkFileTransferReadiness(){let e={hasFileTransferSystem:!!this.fileTransferSystem,hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,ready:!1};return e.ready=e.hasFileTransferSystem&&e.hasDataChannel&&e.dataChannelState==="open"&&e.isConnected&&e.isVerified,e}forceReinitializeFileTransfer(){try{return this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),setTimeout(()=>{this.initializeFileTransfer()},500),!0}catch(e){return this._secureLog("error","Failed to force reinitialize file transfer:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferDiagnostics(){let e={timestamp:new Date().toISOString(),webrtcManager:{hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,isInitiator:this.isInitiator,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,hasSessionSalt:!!this.sessionSalt},fileTransferSystem:null,globalState:{fileTransferActive:this._fileTransferActive||!1,hasFileTransferSystem:!!this.fileTransferSystem,fileTransferSystemType:this.fileTransferSystem?"EnhancedSecureFileTransfer":"none"}};if(this.fileTransferSystem)try{e.fileTransferSystem=this.fileTransferSystem.getSystemStatus()}catch(t){e.fileTransferSystem={error:t.message}}return e}getSupportedFileTypes(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getSupportedFileTypes()}catch(e){return{error:e.message}}}validateFile(e){if(!this.fileTransferSystem)return{isValid:!1,errors:["File transfer system not initialized"],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"};try{return this.fileTransferSystem.validateFile(e)}catch(t){return{isValid:!1,errors:[t.message],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"}}}getFileTypeInfo(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getFileTypeInfo()}catch(e){return{error:e.message}}}async forceInitializeFileTransfer(e={}){let t=new AbortController,{signal:r=t.signal,timeout:i=6e3}=e;r&&r!==t.signal&&r.addEventListener("abort",()=>t.abort());try{if(!this.isVerified)throw new Error("Connection not verified");if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready");this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this.initializeFileTransfer();let n=0,a=50,o=100,c=a*o,d=new Promise((u,h)=>{let m=()=>{if(t.signal.aborted){h(new Error("Operation cancelled"));return}if(this.fileTransferSystem){u(!0);return}if(n>=a){h(new Error(`Initialization timeout after ${c}ms`));return}n++,setTimeout(m,o)};m()});if(await Promise.race([d,new Promise((u,h)=>setTimeout(()=>h(new Error(`Global timeout after ${i}ms`)),i))]),this.fileTransferSystem)return!0;throw new Error("Force initialization timeout")}catch(n){return n.name==="AbortError"||n.message.includes("cancelled")?(this._secureLog("info","File transfer initialization cancelled by user"),{cancelled:!0}):(this._secureLog("error","Force file transfer initialization failed:",{errorType:n?.constructor?.name||"Unknown",message:n.message,attempts}),{error:n.message,attempts})}}cancelFileTransferInitialization(){try{return this.fileTransferSystem?(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,this._fileTransferActive=!1,this._secureLog("info","File transfer initialization cancelled"),!0):!1}catch(e){return this._secureLog("error","Failed to cancel file transfer initialization:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferSystemStatus(){if(!this.fileTransferSystem)return{available:!1,status:"not_initialized"};try{let e=this.fileTransferSystem.getSystemStatus();return{available:!0,status:e.status||"unknown",activeTransfers:e.activeTransfers||0,receivingTransfers:e.receivingTransfers||0,systemType:"EnhancedSecureFileTransfer"}}catch(e){return this._secureLog("error","Failed to get file transfer system status:",{errorType:e?.constructor?.name||"Unknown"}),{available:!1,status:"error",error:e.message}}}_validateNestedEncryptionSecurity(){if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey)try{let e=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest1"),t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest2");return e.every((i,n)=>i===t[n])?(this._secureLog("error","CRITICAL: Nested encryption security validation failed - IVs are identical!"),!1):this._getIVTrackingStats().totalIVs<2?(this._secureLog("error","CRITICAL: IV tracking system not working properly"),!1):(this._secureLog("info","Nested encryption security validation passed - secure IV generation working"),!0)}catch(e){return this._secureLog("error","CRITICAL: Nested encryption security validation failed:",{errorType:e.constructor.name,errorMessage:e.message}),!1}return!0}getCallState(){return{...this.callState}}addCallStateListener(e){return typeof e!="function"?()=>{}:(this._callStateListeners.add(e),()=>this._callStateListeners.delete(e))}removeCallStateListener(e){this._callStateListeners.delete(e)}setCallGroupContext(e){this._callGroupContext=typeof e=="string"&&e?e:null,this._updateCallState({}),this._callGroupContext&&this._pendingCallOffer&&this.callState.phase==="incoming"&&this.acceptCall().catch(t=>{this._secureLog("warn","\u26A0\uFE0F Failed to answer a group call leg that was already ringing",{errorType:t?.constructor?.name})})}setExternalMediaStream(e){this._externalMediaStream=e||null}_usingExternalMedia(){return!!this._externalMediaStream&&this.localMediaStream===this._externalMediaStream}getRemoteMediaStream(){return this.remoteMediaStream}getLocalMediaStream(){return this.localMediaStream}_refreshRemoteStream(){let e=this.peerConnection;if(!e||typeof e.getReceivers!="function")return;let t=e.getReceivers().map(n=>n.track).filter(n=>n&&(n.kind==="audio"||n.kind==="video")&&n.readyState==="live"),r=this.remoteMediaStream?this.remoteMediaStream.getTracks():[];r.length===t.length&&r.every(n=>t.includes(n))||(this.remoteMediaStream=new MediaStream(t)),this._updateCallState({remoteHasVideo:t.some(n=>n.kind==="video")})}_scheduleRemoteRefresh(){this._refreshRemoteStream(),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},300),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},1200)}_updateCallState(e){this.callState={...this.callState,...e,groupCallId:this._callGroupContext};let t=this.getCallState();t.phase==="active"?this._startAdaptation():t.phase==="idle"&&this._stopAdaptation();try{this.onCallStateChanged?.(t)}catch{}for(let r of this._callStateListeners)try{r(t)}catch{}if(typeof document<"u")try{this._dispatchAppEvent?.(new CustomEvent("securebit-call-state",{detail:{managerId:this._managerId||null,state:t}}))}catch{}}_callCanStart(){let e=typeof this.isConnected=="function"?this.isConnected():!1,t=this.dataChannel&&this.dataChannel.readyState==="open";return!!(e&&t&&this.isVerified&&!this.isReconnecting())}async _sendCallSignal(e,t){return await this.sendSystemMessage({type:e,...t})}_audioConstraints(){return{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}}_videoConstraints(){return{facingMode:this._callFacingMode,width:{ideal:1280},height:{ideal:720}}}async _acquireLocalMedia(e){let t=this._externalMediaStream||await navigator.mediaDevices.getUserMedia({audio:this._audioConstraints(),video:e?this._videoConstraints():!1});this.localMediaStream=t;let r=this.peerConnection,i=t.getAudioTracks()[0]||null,n=t.getVideoTracks()[0]||null;return i&&(this._callAudioSender?await this._callAudioSender.replaceTrack(i):this._callAudioSender=r.addTrack(i,t)),n&&(this._callVideoSender?await this._callVideoSender.replaceTrack(n):this._callVideoSender=r.addTrack(n,t)),this._applyCallCodecPrefs(),t}_stopLocalMediaPermanently(){try{if(this.localMediaStream&&!this._usingExternalMedia())for(let e of this.localMediaStream.getTracks())try{e.stop()}catch{}}catch{}this.localMediaStream=null}_applyCallCodecPrefs(){try{let e=this.peerConnection?.getTransceivers?.()||[],t=e.find(i=>i.sender&&i.sender===this._callAudioSender);t&&Ji(t);let r=e.find(i=>i.sender&&i.sender===this._callVideoSender);r&&sn(r)}catch{}}_mungeCallSdp(e){try{let t=Cr(e,st.opusFmtp);return t=Qi(t,qi),t}catch{return e}}async _setLocalMunged(e){let t=this.peerConnection;try{await t.setLocalDescription({type:e.type,sdp:this._mungeCallSdp(e.sdp)});return}catch{try{await t.setLocalDescription({type:e.type,sdp:Cr(e.sdp,st.opusFmtp)});return}catch{await t.setLocalDescription(e)}}}async _applyCallSenderParams(){try{this._callAudioSender&&await Zi(this._callAudioSender,{}),this._callVideoSender&&await an(this._callVideoSender,{})}catch{}}_startAdaptation(){if(!(this._adaptationController||!this.peerConnection))try{this._adaptationController=new Nt(this.peerConnection,{getVideoSender:()=>this._callVideoSender,ceilingBitrate:15e5,onQuality:e=>{e!==this.callState.quality&&this._updateCallState({quality:e})}}),this._adaptationController.start()}catch{}}_stopAdaptation(){if(this._adaptationController){try{this._adaptationController.stop()}catch{}this._adaptationController=null}}_notifyCallMediaError(e,t){let r=e?.name||"",i=t?"camera/microphone":"microphone",n,a;r==="NotAllowedError"?(a="permission_denied",n=`\u26A0\uFE0F Call not started \u2014 ${i} access is blocked. Allow it for this site in the browser, and enable your browser under System Settings \u2192 Privacy & Security \u2192 ${t?"Camera/Microphone":"Microphone"}, then try again.`):r==="NotFoundError"||r==="OverconstrainedError"?(a="device_not_found",n=`\u26A0\uFE0F Call not started \u2014 no ${i} found on this device.`):r==="NotReadableError"||r==="AbortError"?(a="device_busy",n=`\u26A0\uFE0F Call not started \u2014 your ${i} is in use by another app. Close it and try again.`):(a="media_failed",n=`\u26A0\uFE0F Call not started \u2014 could not access ${i}${r?" ("+r+")":""}.`);try{this.deliverMessageToUI(n,"system")}catch{}return a}async startCall(e=!1){if(!this._callCanStart())throw this._updateCallState({error:"not_verified"}),new Error("Calls require a connected, SAS-verified session.");if(this.callState.active){this._secureLog("warn","\u26A0\uFE0F startCall ignored \u2014 a call is already active");return}let t=crypto?.randomUUID?.()||String(Date.now())+Math.random().toString(36).slice(2);this._updateCallState({active:!0,phase:"outgoing",withVideo:e,callId:t,micEnabled:!0,cameraEnabled:e,remoteHasVideo:!1,error:null});try{await this._acquireLocalMedia(e),this._callMakingOffer=!0;let r=await this.peerConnection.createOffer();await this._setLocalMunged(r),this._callMakingOffer=!1,await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:t,withVideo:e,sdp:this.peerConnection.localDescription.sdp})}catch(r){this._callMakingOffer=!1,this._secureLog("error","\u274C startCall failed",{errorType:r?.constructor?.name});let i=this._notifyCallMediaError(r,e);throw await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:i}),r}}async _onIncomingCallOffer(e){if(this.callState.active&&(this.callState.phase==="active"||this.callState.phase==="connecting")){await this._answerCallOffer(e,!0),e.withVideo&&this._updateCallState({withVideo:!0});return}this._pendingCallOffer=e,this._updateCallState({active:!0,phase:"incoming",withVideo:!!e.withVideo,callId:e.callId,remoteHasVideo:!!e.withVideo,error:null}),this._callGroupContext&&await this.acceptCall()}async _answerCallOffer(e,t=!1){await this.peerConnection.setRemoteDescription({type:"offer",sdp:e.sdp}),t||await this._acquireLocalMedia(!!e.withVideo);let r=await this.peerConnection.createAnswer();await this._setLocalMunged(r),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_ANSWER,{callId:e.callId,sdp:this.peerConnection.localDescription.sdp})}async acceptCall(){let e=this._pendingCallOffer;if(e){this._pendingCallOffer=null,this._updateCallState({phase:"connecting",cameraEnabled:!!e.withVideo});try{await this._answerCallOffer(e,!1),this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(t){this._secureLog("error","\u274C acceptCall failed",{errorType:t?.constructor?.name});let r=this._notifyCallMediaError(t,!!e.withVideo);try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:e.callId})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:r})}}}async declineCall(){let e=this.callState.callId;this._pendingCallOffer=null,await this._sendCallSignal(s.MESSAGE_TYPES.CALL_DECLINE,{callId:e}),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1})}async endCall(e=!0){let t=this.callState.callId;if(e&&t)try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:t})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,micEnabled:!0,cameraEnabled:!1,remoteHasVideo:!1,callId:null,quality:null})}async _teardownCallMedia(){this._stopAdaptation();let e=this.peerConnection;try{if(this.localMediaStream&&!this._usingExternalMedia())for(let t of this.localMediaStream.getTracks())try{t.stop()}catch{}if(e)for(let t of[this._callAudioSender,this._callVideoSender].filter(Boolean))try{await t.replaceTrack(null)}catch{}}catch{}this.localMediaStream=null,this.remoteMediaStream=null,this._callMakingOffer=!1;try{this.peerConnection&&(this.peerConnection.signalingState==="have-local-offer"||this.peerConnection.signalingState==="have-local-pranswer")&&await this.peerConnection.setLocalDescription({type:"rollback"})}catch{}}setMicEnabled(e){this.localMediaStream&&this.localMediaStream.getAudioTracks().forEach(t=>{t.enabled=e}),this._updateCallState({micEnabled:e})}toggleMic(){this.setMicEnabled(!this.callState.micEnabled)}async setCameraEnabled(e){if(!e){this.localMediaStream&&this.localMediaStream.getVideoTracks().forEach(r=>{r.enabled=!1}),this._updateCallState({cameraEnabled:!1});return}let t=this.localMediaStream?.getVideoTracks?.()||[];if(t.length){t.forEach(r=>{r.enabled=!0}),this._updateCallState({cameraEnabled:!0,withVideo:!0});return}await this.upgradeToVideo()}async toggleCamera(){await this.setCameraEnabled(!this.callState.cameraEnabled)}async upgradeToVideo(){if(this.localMediaStream)try{let t=(await navigator.mediaDevices.getUserMedia({video:this._videoConstraints()})).getVideoTracks()[0];if(!t)return;await this.addVideoTrack(t)}catch(e){this._secureLog("error","\u274C upgradeToVideo failed",{errorType:e?.constructor?.name}),this._updateCallState({cameraEnabled:!1,error:"camera_failed"})}}async addVideoTrack(e){!e||!this.localMediaStream||!this.peerConnection||(this.localMediaStream.getVideoTracks().includes(e)||this.localMediaStream.addTrack(e),this._callVideoSender?await this._callVideoSender.replaceTrack(e):this._callVideoSender=this.peerConnection.addTrack(e,this.localMediaStream),this._applyCallCodecPrefs(),this._updateCallState({cameraEnabled:!0,withVideo:!0}),await this._renegotiateCall())}async replaceVideoTrack(e){!e||!this._callVideoSender||await this._callVideoSender.replaceTrack(e)}async switchCamera(){if(!(!this._callVideoSender||!this.localMediaStream)){this._callFacingMode=this._callFacingMode==="user"?"environment":"user";try{let t=(await navigator.mediaDevices.getUserMedia({video:{facingMode:this._callFacingMode}})).getVideoTracks()[0],r=this.localMediaStream.getVideoTracks()[0];if(r){this.localMediaStream.removeTrack(r);try{r.stop()}catch{}}this.localMediaStream.addTrack(t),await this._callVideoSender.replaceTrack(t)}catch(e){this._secureLog("warn","\u26A0\uFE0F switchCamera failed",{errorType:e?.constructor?.name})}}}async _renegotiateCall(){if(!this._callMakingOffer)try{this._callMakingOffer=!0;let e=await this.peerConnection.createOffer();await this._setLocalMunged(e),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:this.callState.callId,withVideo:this.callState.withVideo,sdp:this.peerConnection.localDescription.sdp})}finally{this._callMakingOffer=!1}}async _handleCallSignal(e,t){let r=s.MESSAGE_TYPES;switch(e){case r.CALL_OFFER:{await this._onIncomingCallOffer(t);return}case r.CALL_ANSWER:{try{this.peerConnection.signalingState==="have-local-offer"&&await this.peerConnection.setRemoteDescription({type:"answer",sdp:t.sdp}),this.callState.phase==="outgoing"&&this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(i){this._secureLog("warn","\u26A0\uFE0F Failed to apply call answer",{errorType:i?.constructor?.name})}return}case r.CALL_ICE:{try{t.candidate&&await this.peerConnection.addIceCandidate(t.candidate)}catch{}return}case r.CALL_DECLINE:{await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1,error:"declined"});return}case r.CALL_END:{await this.endCall(!1);return}default:return}}},Gt=class{constructor(e=null){this._keyStore=new WeakMap,this._keyMetadata=new Map,this._keyReferences=new Map,this._masterKeyManager=e||new jt,this._persistentStorage=new Br(this._masterKeyManager),this._setupMasterKeyCallbacks(),setTimeout(()=>{this.validateStorageIntegrity()||this._secureLog("error","CRITICAL: Key storage integrity check failed")},100)}_secureLog(e,t,r={}){try{let i=typeof window<"u"&&window.EnhancedSecureCryptoUtils?.secureLog||null;if(i&&typeof i.log=="function"){i.log(e,`[KeyStorage] ${t}`,r);return}}catch{}e==="error"?console.error(`[KeyStorage] ${t}`):e==="warn"&&console.warn(`[KeyStorage] ${t}`)}_setupMasterKeyCallbacks(){this._masterKeyManager.setPasswordRequiredCallback((e,t)=>{this._secureLog("error","Master key password requested but no password UI is installed",{isRetry:!!e}),t(null)}),this._masterKeyManager.setSessionExpiredCallback(e=>{console.warn(`Master key session expired: ${e}`)}),this._masterKeyManager.setUnlockedCallback(()=>{console.log("Master key unlocked successfully")})}setPasswordCallback(e){this._masterKeyManager.setPasswordRequiredCallback(e)}setSessionExpiredCallback(e){this._masterKeyManager.setSessionExpiredCallback(e)}async _ensureMasterKeyUnlocked(){this._masterKeyManager.isUnlocked()||await this._masterKeyManager.unlock()}async storeKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");try{return t.extractable?(await this._persistentStorage.storeExtractableKey(e,t,r),this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0,encrypted:!0}),!0):(this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!1,persistent:!1,encrypted:!1}),!0)}catch(i){return this._secureLog("error","Failed to store key securely",{errorType:i?.constructor?.name||"Unknown"}),!1}}async retrieveKey(e){try{if(this._keyReferences.has(e)){let r=this._keyMetadata.get(e);return r&&(r.lastAccessed=Date.now()),this._keyReferences.get(e)}let t=await this._persistentStorage.retrieveKey(e);if(t){this._keyReferences.set(e,t);let r=this._keyMetadata.get(e);return this._keyMetadata.set(e,{...r,lastAccessed:Date.now(),restoredFromPersistent:!0}),t}return null}catch(t){return this._secureLog("error","Failed to retrieve key",{errorType:t?.constructor?.name||"Unknown"}),null}}async _encryptKeyData(e){let t=typeof e=="object"?JSON.stringify(e):e,i=new TextEncoder().encode(t);await this._ensureMasterKeyUnlocked();let{encryptedData:n,iv:a}=await this._masterKeyManager.encryptBytes(i),o=new Uint8Array(a.length+n.byteLength);return o.set(a,0),o.set(n,a.length),o}async _decryptKeyData(e){let t=e.slice(0,12),r=e.slice(12);await this._ensureMasterKeyUnlocked();let i=await this._masterKeyManager.decryptBytes(r,t),a=new TextDecoder().decode(i);try{return JSON.parse(a)}catch{return i}}async secureWipe(e){let t=this._keyReferences.get(e);t&&(this._keyStore.delete(t),this._keyReferences.delete(e),this._keyMetadata.delete(e)),await this._performNaturalCleanup()}async secureWipeAll(){try{await this._persistentStorage.clearAll()}catch(e){this._secureLog("error","Failed to clear persistent storage",{errorType:e?.constructor?.name||"Unknown"})}this._keyReferences.clear(),this._keyMetadata.clear(),this._keyStore=new WeakMap,await this._performNaturalCleanup()}validateStorageIntegrity(){let e=[];for(let[t,r]of this._keyMetadata.entries())r.extractable===!0&&r.encrypted!==!0&&e.push({keyId:t,type:"EXTRACTABLE_KEY_NOT_ENCRYPTED",metadata:r}),r.extractable===!1&&r.encrypted===!0&&e.push({keyId:t,type:"NON_EXTRACTABLE_KEY_ENCRYPTED",metadata:r});return e.length>0?(this._secureLog("error","Storage integrity violations detected",{violationCount:e.length}),!1):!0}async getStorageStats(){let e=await this._persistentStorage.getStorageStats();return{totalKeys:this._keyReferences.size,memoryKeys:this._keyReferences.size,persistentKeys:e.persistentKeys,metadata:Array.from(this._keyMetadata.entries()).map(([t,r])=>({id:t,created:r.created,lastAccessed:r.lastAccessed,age:Date.now()-r.created,persistent:r.persistent||!1})),persistent:e}}async listAllKeys(){try{let e=Array.from(this._keyMetadata.entries()).map(([i,n])=>({keyId:i,...n,location:"memory"})),r=(await this._persistentStorage.listStoredKeys()).map(i=>({...i,location:"persistent"}));return{memoryKeys:e,persistentKeys:r,totalCount:e.length+r.length}}catch(e){return this._secureLog("error","Failed to list keys",{errorType:e?.constructor?.name||"Unknown"}),{memoryKeys:[],persistentKeys:[],totalCount:0,error:e.message}}}async deleteKey(e){try{return this._keyReferences.delete(e),this._keyMetadata.delete(e),await this._persistentStorage.deleteKey(e),!0}catch(t){return this._secureLog("error","Failed to delete key",{errorType:t?.constructor?.name||"Unknown"}),!1}}},qt=class{constructor(e="SecureKeyStorage",t=1){this.dbName=e,this.version=t,this.db=null,this.KEYS_STORE="encrypted_keys",this.METADATA_STORE="key_metadata",this.SALT_STORE="master_salt"}async initialize(){return new Promise((e,t)=>{let r=indexedDB.open(this.dbName,this.version);r.onerror=()=>{t(new Error(`Failed to open IndexedDB: ${r.error}`))},r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=i=>{let n=i.target.result;if(!n.objectStoreNames.contains(this.KEYS_STORE)){let a=n.createObjectStore(this.KEYS_STORE,{keyPath:"keyId"});a.createIndex("timestamp","timestamp",{unique:!1}),a.createIndex("algorithm","algorithm",{unique:!1})}if(!n.objectStoreNames.contains(this.METADATA_STORE)){let a=n.createObjectStore(this.METADATA_STORE,{keyPath:"keyId"});a.createIndex("created","created",{unique:!1}),a.createIndex("lastAccessed","lastAccessed",{unique:!1})}n.objectStoreNames.contains(this.SALT_STORE)||n.createObjectStore(this.SALT_STORE,{keyPath:"id"})}})}async storeEncryptedKey(e,t,r,i,n,a,o={}){if(!this.db)throw new Error("Database not initialized");let c=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite"),d={keyId:e,encryptedData:Array.from(new Uint8Array(t)),iv:Array.from(new Uint8Array(r)),algorithm:i,usages:n,type:a},u={keyId:e,...o};return new Promise((h,m)=>{let p=c.objectStore(this.KEYS_STORE).put(d),S=c.objectStore(this.METADATA_STORE).put(u);c.oncomplete=()=>h(),c.onerror=()=>m(new Error(`Failed to store key: ${c.error}`))})}async getEncryptedKey(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.KEYS_STORE],"readonly").objectStore(this.KEYS_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>{let o=a.result;o&&(o.encryptedData=new Uint8Array(o.encryptedData),o.iv=new Uint8Array(o.iv)),i(o)},a.onerror=()=>n(new Error(`Failed to retrieve key: ${a.error}`))})}async updateKeyMetadata(e,t){if(!this.db)throw new Error("Database not initialized");let i=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((n,a)=>{let o=i.get(e);o.onsuccess=()=>{let c=o.result;if(c){Object.assign(c,t);let d=i.put(c);d.onsuccess=()=>n(),d.onerror=()=>a(new Error(`Failed to update metadata: ${d.error}`))}else a(new Error(`Key metadata not found: ${e}`))},o.onerror=()=>a(new Error(`Failed to get metadata: ${o.error}`))})}async getKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>i(a.result||null),a.onerror=()=>n(new Error(`Failed to get metadata: ${a.error}`))})}async putKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.put(e);a.onsuccess=()=>i(),a.onerror=()=>n(new Error(`Failed to store metadata: ${a.error}`))})}async deleteKey(e){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite");return new Promise((r,i)=>{let n=t.objectStore(this.KEYS_STORE).delete(e),a=t.objectStore(this.METADATA_STORE).delete(e);t.oncomplete=()=>r(),t.onerror=()=>i(new Error(`Failed to delete key: ${t.error}`))})}async listKeys(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((r,i)=>{let n=t.getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>i(new Error(`Failed to list keys: ${n.error}`))})}async storeMasterSalt(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.SALT_STORE],"readwrite").objectStore(this.SALT_STORE),i={id:"master_salt",salt:Array.from(new Uint8Array(e))};return new Promise((n,a)=>{let o=r.put(i);o.onsuccess=()=>n(),o.onerror=()=>a(new Error(`Failed to store salt: ${o.error}`))})}async getMasterSalt(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.SALT_STORE],"readonly").objectStore(this.SALT_STORE);return new Promise((r,i)=>{let n=t.get("master_salt");n.onsuccess=()=>{let a=n.result;r(a?new Uint8Array(a.salt):null)},n.onerror=()=>i(new Error(`Failed to retrieve salt: ${n.error}`))})}async clearAll(){if(!this.db)throw new Error("Database not initialized");let e=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE,this.SALT_STORE],"readwrite");return new Promise((t,r)=>{let i=e.objectStore(this.KEYS_STORE).clear(),n=e.objectStore(this.METADATA_STORE).clear(),a=e.objectStore(this.SALT_STORE).clear();e.oncomplete=()=>t(),e.onerror=()=>r(new Error(`Failed to clear database: ${e.error}`))})}close(){this.db&&(this.db.close(),this.db=null)}},Br=class{constructor(e,t=null){this._masterKeyManager=e,this._indexedDB=t||new qt,this._dbInitialized=!1,this._keyCache=new WeakMap,this._keyReferences=new Map}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}async _ensureMasterKeyUnlocked(){typeof this._masterKeyManager.isUnlocked=="function"&&!this._masterKeyManager.isUnlocked()&&await this._masterKeyManager.unlock()}async storeExtractableKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");if(!t.extractable)throw new Error("Key must be extractable for persistent storage");try{await this._ensureDBInitialized();let i=await crypto.subtle.exportKey("jwk",t),{encryptedData:n,iv:a}=await this._encryptKeyData(i),o=await this._encryptMetadata({...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0});await this._indexedDB.storeEncryptedKey(e,n,a,t.algorithm,t.usages,t.type,o);let c=await this._importAsNonExtractable(i,t.algorithm,t.usages);return this._keyReferences.set(e,c),!0}catch(i){throw new Error(`Failed to store extractable key: ${i.message}`)}}async retrieveKey(e){try{if(this._keyReferences.has(e))return this._keyReferences.get(e);await this._ensureDBInitialized();let t=await this._indexedDB.getEncryptedKey(e);if(!t)return null;let r=await this._decryptKeyData(t.encryptedData,t.iv),i=await this._importAsNonExtractable(r,t.algorithm,t.usages);return this._keyReferences.set(e,i),await this._updateEncryptedMetadata(e,{lastAccessed:Date.now()}),i}catch(t){throw new Error(`Failed to retrieve key: ${t.message}`)}}async deleteKey(e){try{return await this._ensureDBInitialized(),await this._indexedDB.deleteKey(e),this._keyReferences.delete(e),!0}catch(t){throw new Error(`Failed to delete key: ${t.message}`)}}async listStoredKeys(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys(),t=[];for(let r of e){let i=await this._readMetadataWithMigration(r);i&&t.push({keyId:r.keyId,...i})}return t}catch(e){throw new Error(`Failed to list keys: ${e.message}`)}}async clearAll(){try{return await this._ensureDBInitialized(),await this._indexedDB.clearAll(),this._keyReferences.clear(),!0}catch(e){throw new Error(`Failed to clear storage: ${e.message}`)}}async _encryptKeyData(e){let t=JSON.stringify(e),r=new TextEncoder().encode(t);return await this._ensureMasterKeyUnlocked(),await this._masterKeyManager.encryptBytes(r)}async _decryptKeyData(e,t){await this._ensureMasterKeyUnlocked();let r=await this._masterKeyManager.decryptBytes(e,t),i=new TextDecoder().decode(r);return JSON.parse(i)}async _encryptMetadata(e){let t=new TextEncoder().encode(JSON.stringify(e));await this._ensureMasterKeyUnlocked();let{encryptedData:r,iv:i}=await this._masterKeyManager.encryptBytes(t);return{metadataVersion:1,encryptedMetadata:Array.from(r),metadataIv:Array.from(i)}}async _decryptMetadataRecord(e){if(!e?.encryptedMetadata||!e?.metadataIv)throw new Error("Encrypted metadata missing");await this._ensureMasterKeyUnlocked();let t=await this._masterKeyManager.decryptBytes(new Uint8Array(e.encryptedMetadata),new Uint8Array(e.metadataIv));return JSON.parse(new TextDecoder().decode(t))}async _readMetadataWithMigration(e){if(!e)return null;if(e.encryptedMetadata)try{return await this._decryptMetadataRecord(e)}catch{return null}let{keyId:t,...r}=e,i={keyId:t,...await this._encryptMetadata(r)};return await this._indexedDB.putKeyMetadataRecord(i),r}async _updateEncryptedMetadata(e,t){let r=await this._indexedDB.getKeyMetadataRecord(e);if(!r)throw new Error(`Key metadata not found: ${e}`);let i=await this._readMetadataWithMigration(r);if(!i)throw new Error(`Key metadata corrupted: ${e}`);await this._indexedDB.putKeyMetadataRecord({keyId:e,...await this._encryptMetadata({...i,...t})})}async _importAsNonExtractable(e,t,r){return await crypto.subtle.importKey("jwk",e,t,!1,r)}async getStorageStats(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys();return{totalKeys:e.length,memoryKeys:this._keyReferences.size,persistentKeys:e.length,lastAccessed:e.reduce((t,r)=>Math.max(t,r.lastAccessed||0),0)}}catch(e){return{totalKeys:0,memoryKeys:this._keyReferences.size,persistentKeys:0,lastAccessed:0,error:e.message}}}},jt=class{constructor(e=null){this._keyHandle=null,this._isUnlocked=!1,this._sessionTimeout=null,this._lastActivity=null,this._sessionTimeoutMs=3600*1e3,this._inactivityTimeoutMs=1800*1e3,this._pbkdf2Iterations=31e4,this._saltSize=32,this._indexedDB=e||new qt,this._dbInitialized=!1,this._onPasswordRequired=null,this._onSessionExpired=null,this._onUnlocked=null}setPasswordRequiredCallback(e){this._onPasswordRequired=e}setSessionExpiredCallback(e){this._onSessionExpired=e}setUnlockedCallback(e){this._onUnlocked=e}_setupEventListeners(){typeof document<"u"&&(document.addEventListener("visibilitychange",()=>{document.hidden?this._handleFocusOut():this._handleFocusIn()}),window.addEventListener("blur",()=>this._handleFocusOut()),window.addEventListener("focus",()=>this._handleFocusIn()),["mousedown","mousemove","keypress","scroll","touchstart"].forEach(e=>{document.addEventListener(e,()=>this._updateActivity(),{passive:!0})}))}_handleFocusOut(){this._isUnlocked&&this._startInactivityTimer(this._inactivityTimeoutMs)}_handleFocusIn(){this._isUnlocked&&this._resetSessionTimer()}_updateActivity(){this._lastActivity=Date.now(),this._isUnlocked&&this._resetSessionTimer()}_startSessionTimer(){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("timeout")},this._sessionTimeoutMs)}_startInactivityTimer(e){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("inactivity")},e)}_resetSessionTimer(){this._isUnlocked&&this._startSessionTimer()}_clearTimers(){this._sessionTimeout&&(clearTimeout(this._sessionTimeout),this._sessionTimeout=null)}_expireSession(e="unknown"){this._isUnlocked&&(this._secureWipeMasterKey(),this._isUnlocked=!1,this._onSessionExpired&&this._onSessionExpired(e))}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}_generateSalt(){return crypto.getRandomValues(new Uint8Array(this._saltSize))}async _getOrCreateSalt(){await this._ensureDBInitialized();let e=await this._indexedDB.getMasterSalt();return e||(e=this._generateSalt(),await this._indexedDB.storeMasterSalt(e)),e}async _deriveKeyFromPassword(e,t){try{let r=await crypto.subtle.importKey("raw",new TextEncoder().encode(e),"PBKDF2",!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:this._pbkdf2Iterations,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,["encrypt","decrypt","wrapKey","unwrapKey"])}catch(r){throw new Error(`Key derivation failed: ${r.message}`)}}async _requestPassword(e=!1){if(!this._onPasswordRequired)throw new Error("Password callback not set");return new Promise((t,r)=>{this._onPasswordRequired(e,i=>{i?t(i):r(new Error("Password not provided"))})})}async unlock(e=null){try{e||(e=await this._requestPassword(!1));let t=await this._getOrCreateSalt();return this._keyHandle=await this._deriveKeyFromPassword(e,t),this._isUnlocked=!0,this._lastActivity=Date.now(),this._startSessionTimer(),e=null,this._onUnlocked&&this._onUnlocked(),{success:!0}}catch(t){throw e=null,t}}lock(){this._expireSession("manual")}async encryptBytes(e){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let t=crypto.getRandomValues(new Uint8Array(12)),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return{encryptedData:new Uint8Array(r),iv:t}}async decryptBytes(e,t){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let r=await crypto.subtle.decrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return new Uint8Array(r)}isUnlocked(){return this._isUnlocked&&this._keyHandle!==null}getSessionStatus(){return{isUnlocked:this._isUnlocked,lastActivity:this._lastActivity,sessionTimeoutMs:this._sessionTimeoutMs,inactivityTimeoutMs:this._inactivityTimeoutMs}}_secureWipeMasterKey(){this._keyHandle&&(this._keyHandle=null),this._clearTimers()}destroy(){this._secureWipeMasterKey(),this._isUnlocked=!1,typeof document<"u"&&(document.removeEventListener("visibilitychange",this._handleFocusOut),window.removeEventListener("blur",this._handleFocusOut),window.removeEventListener("focus",this._handleFocusIn))}};var $n=wi(Pn());var Fn="6.8.8";var Hr=()=>{if(Ke.length<2)return null;let[s,e]=React.useState(!1),t=React.useRef(null),r=typeof window<"u"?window.location.pathname:"/",i=Gi({pathname:r,active:Ge()}),n=i.find(c=>c.isCurrent)||i[0];React.useEffect(()=>{if(!s)return;let c=u=>{t.current&&!t.current.contains(u.target)&&e(!1)},d=u=>{u.key==="Escape"&&e(!1)};return document.addEventListener("pointerdown",c),document.addEventListener("keydown",d),()=>{document.removeEventListener("pointerdown",c),document.removeEventListener("keydown",d)}},[s]);let a=React.createElement("button",{key:"trigger",type:"button",onClick:()=>e(c=>!c),"aria-haspopup":"menu","aria-expanded":s?"true":"false","aria-label":f("language.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"7px 10px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:s?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",fontSize:"12.5px",fontWeight:600,cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"c"},n?n.abbr:""),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:s?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),o=React.createElement("div",{key:"menu",role:"menu",className:"sb-scroll",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:s?"block":"none",minWidth:"170px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",maxHeight:"min(62vh, 420px)",overflowY:"auto",overscrollBehavior:"contain"}},i.map(c=>React.createElement("a",{key:c.code,href:c.href,hrefLang:c.hrefLang,lang:c.hrefLang,dir:c.dir,role:"menuitem","aria-current":c.isCurrent?"page":void 0,onClick:()=>Hi(c.code),style:{display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",fontSize:"13px",fontWeight:c.isCurrent?600:500,color:c.isCurrent?"var(--sb-text-2)":"var(--sb-text-6)",background:c.isCurrent?"rgba(var(--sb-ink), 0.06)":"transparent",textDecoration:"none",whiteSpace:"nowrap"}},[React.createElement("span",{key:"a",style:{fontSize:"11px",fontWeight:700,letterSpacing:"0.4px",color:"var(--sb-text-9)",width:"22px",flex:"none",textAlign:"start"}},c.abbr),React.createElement("span",{key:"n"},c.label)])));return React.createElement("nav",{ref:t,"aria-label":f("language.label"),style:{position:"relative",display:"inline-flex"}},[a,o])};window.LanguageSwitcher=Hr;var ot={system:'',light:'',dark:''},$r=(s,e,t)=>React.createElement("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:t,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",dangerouslySetInnerHTML:{__html:s}}),Gr=()=>{let s=typeof window<"u"?window.SecureBitTheme:null;if(!s)return null;let[e,t]=React.useState(!1),[r,i]=React.useState(()=>s.get()),[n,a]=React.useState(()=>s.resolved()),o=React.useRef(null);React.useEffect(()=>s.subscribe((p,S)=>{i(p),a(S)}),[]),React.useEffect(()=>{if(!e)return;let p=g=>{o.current&&!o.current.contains(g.target)&&t(!1)},S=g=>{g.key==="Escape"&&t(!1)};return document.addEventListener("pointerdown",p),document.addEventListener("keydown",S),()=>{document.removeEventListener("pointerdown",p),document.removeEventListener("keydown",S)}},[e]);let c=[{mode:"system",icon:ot.system,label:f("theme.system")},{mode:"light",icon:ot.light,label:f("theme.light")},{mode:"dark",icon:ot.dark,label:f("theme.dark")}],d=r==="system"?ot.system:n==="light"?ot.light:ot.dark,u=c.find(p=>p.mode===r)||c[0],h=React.createElement("button",{key:"trigger",type:"button",onClick:()=>t(p=>!p),"aria-haspopup":"menu","aria-expanded":e?"true":"false","aria-label":f("theme.label")+": "+u.label,title:f("theme.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"8px 9px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:e?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"i",style:{display:"grid",placeItems:"center"}},$r(d,15,1.9)),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:e?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),m=React.createElement("div",{key:"menu",role:"menu",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:e?"block":"none",minWidth:"158px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))"}},c.map(p=>{let S=p.mode===r;return React.createElement("button",{key:p.mode,type:"button",role:"menuitemradio","aria-checked":S?"true":"false",onClick:()=>{s.set(p.mode),t(!1)},style:{width:"100%",display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",border:"none",fontSize:"13px",fontFamily:"inherit",fontWeight:S?600:500,color:S?"var(--sb-text-2)":"var(--sb-text-6)",background:S?"rgba(var(--sb-ink), 0.06)":"transparent",cursor:"pointer",textAlign:"start",whiteSpace:"nowrap"}},[React.createElement("span",{key:"i",style:{flex:"none",display:"grid",placeItems:"center",width:"16px",color:S?"var(--sb-orange)":"var(--sb-text-9)"}},$r(p.icon,14,1.9)),React.createElement("span",{key:"l",style:{flex:1}},p.label),S&&React.createElement("span",{key:"c",style:{flex:"none",display:"grid",placeItems:"center",color:"var(--sb-orange)"}},$r('',12,2.6))])}));return React.createElement("div",{ref:o,style:{position:"relative",display:"inline-flex"}},[h,m])};window.ThemeSwitcher=Gr;var Ma=`v${Fn}`,La=({status:s,fingerprint:e,verificationCode:t,onDisconnect:r,isConnected:i,securityLevel:n,webrtcManager:a})=>{let[o,c]=React.useState(null),[d,u]=React.useState(0),[h,m]=React.useState(!1),[p,S]=React.useState(0),[g,b]=React.useState("unknown");React.useEffect(()=>{let G=!1,U=0,I=async()=>{let N=Date.now();if(!(N-U<1e4)&&!G){G=!0,U=N;try{if(!a||!i)return;let z=a,W=null;if(typeof z.getRealSecurityLevel=="function"?W=await z.getRealSecurityLevel():typeof z.calculateAndReportSecurityLevel=="function"?W=await z.calculateAndReportSecurityLevel():W=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(z),W&&W.isRealData!==!1){let Z=o?.score||0,be=W.score||0;Z!==be||!o?(c(W),u(N)):window.DEBUG_MODE}}catch{}finally{G=!1}}};if(i&&(I(),!o||o.score<50)){let N=setInterval(()=>{!o||o.score<50?I():clearInterval(N)},5e3);setTimeout(()=>clearInterval(N),3e4)}let D=setInterval(I,3e4);return()=>clearInterval(D)},[a,i]),React.useEffect(()=>{let G=I=>{setTimeout(()=>{u(0)},100)},U=I=>{I.detail&&I.detail.securityData&&(c(I.detail.securityData),u(Date.now()))};return document.addEventListener("security-level-updated",G),document.addEventListener("real-security-calculated",U),window.forceHeaderSecurityUpdate=I=>{I&&window.EnhancedSecureCryptoUtils?window.EnhancedSecureCryptoUtils.calculateSecurityLevel(I).then(D=>{D&&D.isRealData!==!1&&(c(D),u(Date.now()))}).catch(D=>{}):u(0)},()=>{document.removeEventListener("security-level-updated",G),document.removeEventListener("real-security-calculated",U)}},[]),React.useEffect(()=>{m(!0),S(0),b("premium")},[]),React.useEffect(()=>{m(!0),S(0),b("premium")},[]),React.useEffect(()=>{let G=N=>{m(!0),S(0),b("premium")},U=()=>{c(null),u(0),m(!1),S(0),b("unknown")},I=()=>{c(null),u(0)},D=()=>{c(null),u(0),m(!1),S(0),b("unknown")};return document.addEventListener("force-header-update",G),document.addEventListener("peer-disconnect",I),document.addEventListener("connection-cleaned",U),document.addEventListener("disconnected",D),()=>{document.removeEventListener("force-header-update",G),document.removeEventListener("peer-disconnect",I),document.removeEventListener("connection-cleaned",U),document.removeEventListener("disconnected",D)}},[]);let w=async G=>{if(G&&(G.button===2||G.ctrlKey||G.metaKey)&&r&&typeof r=="function"){r();return}G.preventDefault(),G.stopPropagation();let U=null;if(a&&window.EnhancedSecureCryptoUtils)try{U=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(a)}catch{}if(!U&&!o){alert(f("sec.verificationWait"));return}let I=U||o;I||(I={level:"UNKNOWN",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:f("sec.verificationUnavailable"),isRealData:!1,passedChecks:0,totalChecks:0});let D=`REAL-TIME SECURITY VERIFICATION +`),e=e.trim()),e}_sanitizeInputObject(e){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(r=>this._sanitizeInputObject(r));let t={};for(let r in e)if(e.hasOwnProperty(r)){let i=e[r];typeof i=="string"?t[r]=this._sanitizeInputString(i):typeof i=="object"?t[r]=this._sanitizeInputObject(i):t[r]=i}return t}_checkRateLimit(e="message"){let t=Date.now();return this._rateLimiter||(this._rateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._rateLimiter.lastReset>6e4&&(this._rateLimiter.messageCount=0,this._rateLimiter.lastReset=t),t-this._rateLimiter.lastBurstReset>1e3&&(this._rateLimiter.burstCount=0,this._rateLimiter.lastBurstReset=t),this._rateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Rate limit burst exceeded",{context:e}),!1):this._rateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Rate limit exceeded",{context:e}),!1):(this._rateLimiter.messageCount++,this._rateLimiter.burstCount++,!0)}_checkInboundRateLimit(e="incoming_message"){let t=Date.now();return this._inboundRateLimiter||(this._inboundRateLimiter={messageCount:0,lastReset:t,burstCount:0,lastBurstReset:t}),t-this._inboundRateLimiter.lastReset>6e4&&(this._inboundRateLimiter.messageCount=0,this._inboundRateLimiter.lastReset=t),t-this._inboundRateLimiter.lastBurstReset>1e3&&(this._inboundRateLimiter.burstCount=0,this._inboundRateLimiter.lastBurstReset=t),this._inboundRateLimiter.burstCount>=this._inputValidationLimits.rateLimitBurstSize?(this._secureLog("warn","\u26A0\uFE0F Inbound message burst limit exceeded; dropping message",{context:e}),!1):this._inboundRateLimiter.messageCount>=this._inputValidationLimits.rateLimitMessagesPerMinute?(this._secureLog("warn","\u26A0\uFE0F Inbound message rate limit exceeded; dropping message",{context:e}),!1):(this._inboundRateLimiter.messageCount++,this._inboundRateLimiter.burstCount++,!0)}_initializeSecureKeyStorage(){this._masterKeyManager=new jt,this._secureKeyStorage=new Gt(this._masterKeyManager),this._keyStorageStats={totalKeys:0,activeKeys:0,lastAccess:null,lastRotation:null},this._secureLog("info","\u{1F510} Enhanced secure key storage initialized")}setMasterKeyPasswordCallback(e){this._masterKeyManager&&this._masterKeyManager.setPasswordRequiredCallback(e)}setMasterKeySessionExpiredCallback(e){this._masterKeyManager&&this._masterKeyManager.setSessionExpiredCallback(e)}lockMasterKey(){this._masterKeyManager&&this._masterKeyManager.lock()}isMasterKeyUnlocked(){return this._masterKeyManager?this._masterKeyManager.isUnlocked():!1}getMasterKeySessionStatus(){return this._masterKeyManager?this._masterKeyManager.getSessionStatus():null}async _ensureFileTransferReady(){try{if(this.fileTransferSystem)return!0;if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.isVerified)throw new Error("Connection not verified");this.initializeFileTransfer();let e=0,t=50;for(;!this.fileTransferSystem&&esetTimeout(r,100)),e++;if(!this.fileTransferSystem)throw new Error("File transfer system initialization timeout");return!0}catch(e){return this._secureLog("error","\u274C _ensureFileTransferReady failed",{errorType:e?.constructor?.name||"Unknown",hasMessage:!!e?.message}),!1}}_getSecureKey(e){return this._secureKeyStorage.retrieveKey(e)}async _setSecureKey(e,t){if(!(t instanceof CryptoKey))return this._secureLog("error","\u274C Attempt to store non-CryptoKey"),!1;let r=await this._secureKeyStorage.storeKey(e,t,{version:this.currentKeyVersion,type:t.algorithm.name});return r&&this._secureLog("info",`\u{1F511} Key ${e} stored securely with encryption`),r}_validateKeyValue(e){return e instanceof CryptoKey&&e.algorithm&&e.usages&&e.usages.length>0}_secureWipeKeys(){this._secureKeyStorage.secureWipeAll(),this._masterKeyManager&&this._masterKeyManager.lock(),this._secureLog("info","\u{1F9F9} All keys securely wiped and encrypted storage cleared")}_validateKeyStorage(){return this._secureKeyStorage instanceof Gt}_getKeyStorageStats(){let e=this._secureKeyStorage.getStorageStats();return{totalKeysCount:e.totalKeys,activeKeysCount:e.totalKeys,hasLastAccess:e.metadata.some(t=>t.lastAccessed),hasLastRotation:!!this._keyStorageStats.lastRotation,storageType:"SecureKeyStorage",timestamp:Date.now()}}_rotateKeys(){let e=Array.from(this._secureKeyStorage.keys());this._secureKeyStorage.clear(),this._keyStorageStats.lastRotation=Date.now(),this._keyStorageStats.activeKeys=0,this._secureLog("info",`\u{1F504} Key rotation completed. ${e.length} keys rotated`)}_emergencyKeyWipe(){this._secureWipeKeys(),this._secureLog("error","\u{1F6A8} EMERGENCY: All keys wiped due to security threat")}_startKeySecurityMonitoring(){this._secureLog("info","\u{1F527} Key security monitoring moved to unified scheduler")}_validateKeyConstantTime(e){let t=0;try{let r=e instanceof CryptoKey;t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.algorithm);t+=r?1:0}catch{t+=0}try{let r=!!(e&&e.type);t+=r?1:0}catch{t+=0}try{let r=e&&e.extractable!==void 0;t+=r?1:0}catch{t+=0}return t===4}_validateKeyPairConstantTime(e){if(!e||typeof e!="object")return!1;let t=this._validateKeyConstantTime(e.privateKey),r=this._validateKeyConstantTime(e.publicKey);return t&&r}_initializeSecureLogging(){this._logLevels={error:0,warn:1,info:2,debug:3,trace:4},this._currentLogLevel=this._isProductionMode?this._logLevels.error:this._logLevels.info,this._logCounts=new Map,this._maxLogCount=this._isProductionMode?5:50,this._resourceLimits={maxLogEntries:this._isProductionMode?100:1e3,maxMessageQueue:1e3,maxIVHistory:1e4,maxProcessedMessageIds:5e3,maxDecoyChannels:100,maxFakeTrafficMessages:500,maxChunkQueue:200,maxPacketBuffer:1e3},this._emergencyThresholds={logEntries:this._resourceLimits.maxLogEntries*.8,messageQueue:this._resourceLimits.maxMessageQueue*.8,ivHistory:this._resourceLimits.maxIVHistory*.8,processedMessageIds:this._resourceLimits.maxProcessedMessageIds*.8},this._inputValidationLimits={maxStringLength:1e5,maxObjectDepth:10,maxArrayLength:1e3,maxMessageSize:1024*1024,maxConcurrentMessages:10,rateLimitMessagesPerMinute:60,rateLimitBurstSize:10},this._absoluteBlacklist=new Set(["encryptionKey","macKey","metadataKey","privateKey","publicKey","ecdhKeyPair","ecdsaKeyPair","peerPublicKey","nestedEncryptionKey","verificationCode","sessionSalt","keyFingerprint","sessionId","authChallenge","authProof","authToken","sessionToken","password","token","secret","credential","signature","apiKey","accessKey","secretKey","privateKey","hash","digest","nonce","iv","cipher","seed","entropy","random","salt","fingerprint","jwt","bearer","refreshToken","accessToken","fileHash","fileSignature","transferKey","chunkKey"]),this._safeFieldsWhitelist=new Set(["timestamp","type","status","state","level","isConnected","isVerified","isInitiator","version","count","total","active","inactive","success","failure","readyState","connectionState","iceConnectionState","activeFeaturesCount","totalFeatures","stage","errorType","errorCode","phase","attempt"]),this._initializeLogSecurityMonitoring(),this._secureLog("info",`\u{1F527} Enhanced secure logging initialized (Production: ${this._isProductionMode})`)}_initializeLogSecurityMonitoring(){this._logSecurityViolations=0,this._maxLogSecurityViolations=3}_auditLoggingSystemSecurity(){let e=0;for(let[r,i]of this._logCounts.entries())i>this._maxLogCount*2&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Excessive log count detected: ${r}`));let t=Array.from(this._logCounts.keys());for(let r of t)this._containsSensitiveContent(r)&&(e++,this._originalConsole?.error?.(`\u{1F6A8} LOG SECURITY: Sensitive content in log key: ${r}`));this._logSecurityViolations+=e,this._logSecurityViolations>=this._maxLogSecurityViolations&&(this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Logging system disabled due to security violations"))}_secureLogShim(...e){try{if(!Array.isArray(e)||e.length===0)return;let t=e[0],r=e.slice(1);if(r.length===0){this._secureLog("info",String(t||""));return}if(r.length===1){this._secureLog("info",String(t||""),r[0]);return}this._secureLog("info",String(t||""),{additionalArgs:r,argCount:r.length})}catch{try{this._originalConsole?.log&&this._originalConsole.log(...e)}catch{}}}_setupOwnLogger(){this.logger={log:(e,t)=>this._secureLog("info",e,t),info:(e,t)=>this._secureLog("info",e,t),warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:(e,t)=>this._secureLog("debug",e,t)},s.DEBUG_MODE?this._secureLog("info","\u{1F512} Own logger created - development mode"):this._secureLog("info","\u{1F512} Own logger created - production mode")}_setupProductionLogging(){this._isProductionMode&&(this.logger={log:()=>{},info:()=>{},warn:(e,t)=>this._secureLog("warn",e,t),error:(e,t)=>this._secureLog("error",e,t),debug:()=>{}},this._secureLog("info","Production logging mode activated"))}_secureLog(e,t,r=null){if(r&&!this._auditLogMessage(t,r)){this._originalConsole?.error?.("SECURITY: Logging blocked due to potential data leakage");return}if(this._logLevels[e]>this._currentLogLevel)return;let i=`${e}:${t.substring(0,50)}`,n=this._logCounts.get(i)||0;if(n>=this._maxLogCount)return;this._logCounts.set(i,n+1);let a=null;if(r&&(a=this._sanitizeLogData(r),this._containsSensitiveContent(JSON.stringify(a)))){this._originalConsole?.error?.("ECURITY: Sanitized data still contains sensitive content - blocking log");return}if(this._isProductionMode){if(e==="error"){let c=this._sanitizeString(t);this._originalConsole?.error?.(c)}return}let o=this._originalConsole?.[e]||this._originalConsole?.log;a?o(t,a):o(t)}_sanitizeLogData(e){if(typeof e=="string")return this._sanitizeString(e);if(!e||typeof e!="object")return e;let t={};for(let[i,n]of Object.entries(e)){let a=i.toLowerCase(),o=["key","secret","token","password","credential","auth","fingerprint","salt","signature","private","encryption","mac","metadata","session","jwt","bearer","hash","digest","nonce","iv","cipher","seed","entropy"];if(this._absoluteBlacklist.has(i)||o.some(d=>a.includes(d))){t[i]="[SENSITIVE_DATA_BLOCKED]";continue}if(this._safeFieldsWhitelist.has(i)){typeof n=="string"?t[i]=this._sanitizeString(n):t[i]=n;continue}if(typeof n=="boolean"||typeof n=="number")t[i]=n;else if(typeof n=="string")t[i]=this._sanitizeString(n);else if(n instanceof ArrayBuffer||n instanceof Uint8Array)t[i]=`[${n.constructor.name}( bytes)]`;else if(n&&typeof n=="object")try{t[i]=this._sanitizeLogData(n)}catch{t[i]="[RECURSIVE_SANITIZATION_FAILED]"}else t[i]=`[${typeof n}]`}let r=JSON.stringify(t);return this._containsSensitiveContent(r)?{error:"SANITIZATION_FAILED_SENSITIVE_CONTENT_DETECTED"}:t}_sanitizeString(e){if(typeof e!="string"||e.length===0)return e;let t=[/[a-f0-9]{16,}/i,/[a-f0-9]{8,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[A-Za-z0-9+/]{12,}/,/[A-Za-z0-9+/=]{10,}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/[A-Z2-7]{12,}/,/[A-Za-z0-9\-_]{16,}/,/[A-Za-z0-9\.\-_]{16,}/,/\b[A-Za-z0-9]{12,}\b/,/\b[A-Za-z0-9]{8,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/END\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i,/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/,/\b\d{3}-\d{2}-\d{4}\b/,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/,/(fingerprint|hash|digest|signature)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(encryption|mac|metadata)[\s]*key[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i,/(session|auth|jwt|bearer)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i];for(let r of t)if(r.test(e))return"[SENSITIVE_DATA_REDACTED]";return this._hasHighEntropy(e)?"[HIGH_ENTROPY_DATA_REDACTED]":this._hasSuspiciousDistribution(e)?"[SUSPICIOUS_DATA_REDACTED]":e.length>50?e.substring(0,20)+"...[TRUNCATED]":e}_containsSensitiveContent(e){return typeof e!="string"?!1:[/[a-f0-9]{16,}/i,/[A-Za-z0-9+/]{16,}={0,2}/,/[1-9A-HJ-NP-Za-km-z]{16,}/,/[A-Z2-7]{16,}={0,6}/,/\b[A-Za-z0-9]{12,}\b/,/BEGIN\s+(PRIVATE|PUBLIC|RSA|DSA|EC)\s+KEY/i,/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,/(api[_-]?key|token|secret|password|credential)[\s]*[:=][\s]*[A-Za-z0-9\-_]{8,}/i].some(r=>r.test(e))||this._hasHighEntropy(e)||this._hasSuspiciousDistribution(e)}_hasHighEntropy(e){if(e.length<8)return!1;let t={};for(let n of e)t[n]=(t[n]||0)+1;let r=e.length,i=0;for(let n of Object.values(t)){let a=n/r;i-=a*Math.log2(a)}return i>4.5}_hasSuspiciousDistribution(e){return e.length<8?!1:(e.match(/[a-f0-9]/gi)||[]).length>=e.length*.8||(e.match(/[A-Za-z0-9+/=]/g)||[]).length>=e.length*.9||new Set(e).size/e.length>.8&&e.length>16}_detectProductionMode(){return typeof process<"u"&&!0||!this._debugMode||window.location.hostname&&!window.location.hostname.includes("localhost")&&!window.location.hostname.includes("127.0.0.1")&&!window.location.hostname.includes(".local")||typeof window.webpackHotUpdate>"u"&&!window.location.search.includes("debug")}_setupSecureGlobalAPI(){this._secureLog("info","Starting secure global API setup");let e={};typeof this.sendMessage=="function"&&(e.sendMessage=this.sendMessage.bind(this)),e.getConnectionStatus=()=>({isConnected:this.isConnected?this.isConnected():!1,isVerified:this.isVerified||!1,connectionState:this.peerConnection?.connectionState||"disconnected"}),e.getSecurityStatus=()=>({securityLevel:"maximum",stage:"initialized",activeFeaturesCount:Object.values(this.securityFeatures||{}).filter(Boolean).length}),typeof this.sendFile=="function"&&(e.sendFile=this.sendFile.bind(this)),e.getFileTransferStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),typeof this.disconnect=="function"&&(e.disconnect=this.disconnect.bind(this));let t={...e,getConfiguration:()=>({fakeTraffic:this._config.fakeTraffic.enabled,decoyChannels:this._config.decoyChannels.enabled,packetPadding:this._config.packetPadding.enabled,antiFingerprinting:this._config.antiFingerprinting.enabled}),emergency:{}};typeof this._emergencyUnlockAllMutexes=="function"&&(t.emergency.unlockAllMutexes=this._emergencyUnlockAllMutexes.bind(this)),typeof this._emergencyRecoverMutexSystem=="function"&&(t.emergency.recoverMutexSystem=this._emergencyRecoverMutexSystem.bind(this)),typeof this._emergencyDisableLogging=="function"&&(t.emergency.disableLogging=this._emergencyDisableLogging.bind(this)),typeof this._resetLoggingSystem=="function"&&(t.emergency.resetLogging=this._resetLoggingSystem.bind(this)),t.getFileTransferSystemStatus=()=>({initialized:!!this.fileTransferSystem,status:"ready",activeTransfers:0,receivingTransfers:0}),this._secureLog("info","API methods available",{sendMessage:!!e.sendMessage,getConnectionStatus:!!e.getConnectionStatus,getSecurityStatus:!!e.getSecurityStatus,sendFile:!!e.sendFile,getFileTransferStatus:!!e.getFileTransferStatus,disconnect:!!e.disconnect,getConfiguration:!!t.getConfiguration,emergencyMethods:Object.keys(t.emergency).length}),Object.freeze(t),Object.freeze(t.emergency),this._createProtectedGlobalAPI(t),this._setupMinimalGlobalProtection(),this._secureLog("info","Secure global API setup completed successfully")}_createProtectedGlobalAPI(e){this._secureLog("info","Creating protected global API"),window.secureBitChat?this._secureLog("warn","\u26A0\uFE0F Global API already exists, skipping setup"):this._exportAPI(e)}_exportAPI(e){this._secureLog("info","Exporting API to window.secureBitChat"),!this._importantMethods||!this._importantMethods.defineProperty?(this._secureLog("error","\u274C Important methods not available for API export, using fallback"),Object.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0})):this._importantMethods.defineProperty(window,"secureBitChat",{value:e,writable:!1,configurable:!1,enumerable:!0}),this._secureLog("info","\u{1F512} Secure API exported to window.secureBitChat")}_setupMinimalGlobalProtection(){this._protectGlobalAPI(),this._secureLog("info","\u{1F512} Minimal global protection activated")}_storeImportantMethods(){this._importantMethods={defineProperty:Object.defineProperty,getOwnPropertyDescriptor:Object.getOwnPropertyDescriptor,freeze:Object.freeze,consoleLog:console.log,consoleError:console.error,consoleWarn:console.warn},this._secureLog("info","\u{1F512} Important methods stored locally",{defineProperty:!!this._importantMethods.defineProperty,getOwnPropertyDescriptor:!!this._importantMethods.getOwnPropertyDescriptor,freeze:!!this._importantMethods.freeze})}_setupSimpleProtection(){this._secureLog("info","\u{1F512} Simple protection activated - no monitoring")}_preventGlobalExposure(){this._secureLog("info","\u{1F512} No global exposure prevention - using secure API export only")}_verifyAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C SECURITY ALERT: Secure API has been removed!"),!1;let t=["sendMessage","getConnectionStatus","disconnect"].filter(r=>typeof window.secureBitChat[r]!="function");return t.length>0?(this._secureLog("error","\u274C SECURITY ALERT: API tampering detected, missing methods:",{errorType:t?.constructor?.name||"Unknown"}),!1):!0}catch(e){return this._secureLog("error","\u274C SECURITY ALERT: API integrity check failed:",{errorType:e?.constructor?.name||"Unknown"}),!1}}_auditGlobalExposure(){return this._secureLog("info","\u{1F512} Global exposure check completed at initialization"),[]}_startSecurityAudit(){this._secureLog("info","\u{1F512} Security audit completed at initialization - no periodic monitoring")}_protectGlobalAPI(){if(!window.secureBitChat){this._secureLog("warn","\u26A0\uFE0F Global API not found during protection setup");return}try{this._validateAPIIntegrityOnce()&&this._secureLog("info","\u{1F512} Global API protection verified")}catch(e){this._secureLog("error","\u274C Failed to verify global API protection",{errorType:e.constructor.name,errorMessage:e.message})}}_validateAPIIntegrityOnce(){try{if(!this._importantMethods||!this._importantMethods.getOwnPropertyDescriptor){let e=Object.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}else{let e=this._importantMethods.getOwnPropertyDescriptor(window,"secureBitChat");if(!e||e.configurable)throw new Error("secureBitChat must not be reconfigurable!")}return this._secureLog("info","\u2705 API integrity validated"),!0}catch(e){return this._secureLog("error","\u274C API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_secureWipeMemory(e,t="unknown"){if(e)try{e instanceof ArrayBuffer?this._secureWipeArrayBuffer(e,t):e instanceof Uint8Array?this._secureWipeUint8Array(e,t):Array.isArray(e)?this._secureWipeArray(e,t):typeof e=="string"?this._secureWipeString(e,t):e instanceof CryptoKey?this._secureWipeCryptoKey(e,t):typeof e=="object"&&this._secureWipeObject(e,t),this._secureMemoryManager.memoryStats.totalCleanups++}catch(r){this._secureMemoryManager.memoryStats.failedCleanups++,this._secureLog("error","\u274C Secure memory wipe failed",{context:t,errorType:r.constructor.name,errorMessage:r.message})}}_secureWipeArrayBuffer(e,t){if(!(!e||e.byteLength===0))try{let r=new Uint8Array(e);crypto.getRandomValues(r),r.fill(0),r.fill(255),r.fill(0),this._secureLog("debug","\u{1F512} ArrayBuffer securely wiped",{context:t,size:e.byteLength})}catch(r){this._secureLog("error","\u274C Failed to wipe ArrayBuffer",{context:t,errorType:r.constructor.name})}}_secureWipeUint8Array(e,t){if(!(!e||e.length===0))try{crypto.getRandomValues(e),e.fill(0),e.fill(255),e.fill(0),this._secureLog("debug","\u{1F512} Uint8Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe Uint8Array",{context:t,errorType:r.constructor.name})}}_secureWipeArray(e,t){if(!(!Array.isArray(e)||e.length===0))try{e.forEach((r,i)=>{r!=null&&this._secureWipeMemory(r,`${t}[${i}]`)}),e.fill(null),this._secureLog("debug","\u{1F512} Array securely wiped",{context:t,size:e.length})}catch(r){this._secureLog("error","\u274C Failed to wipe array",{context:t,errorType:r.constructor.name})}}_secureWipeString(e,t){return this._secureLog("debug","String secret cannot be wiped in JS (immutable) \u2014 reference dropped only",{context:t,length:e?e.length:0}),!1}_secureWipeCryptoKey(e,t){return!e||!(e instanceof CryptoKey)||(this._secureLog("debug","CryptoKey cannot be wiped from JS \u2014 handle dropped, material is non-extractable",{context:t,type:e.type,extractable:e.extractable}),e.extractable&&this._secureLog("error","Extractable key reached the wipe path \u2014 material may persist in memory",{context:t})),!1}_secureWipeObject(e,t){if(!(!e||typeof e!="object"))try{for(let[r,i]of Object.entries(e))i!=null&&this._secureWipeMemory(i,`${t}.${r}`),e[r]=null;this._secureLog("debug","\u{1F512} Object securely wiped",{context:t,properties:Object.keys(e).length})}catch(r){this._secureLog("error","\u274C Failed to wipe object",{context:t,errorType:r.constructor.name})}}_secureCleanupCryptographicMaterials(){try{if(this.ecdhKeyPair&&(this._secureWipeMemory(this.ecdhKeyPair,"ecdhKeyPair"),this.ecdhKeyPair=null),this.ecdsaKeyPair&&(this._secureWipeMemory(this.ecdsaKeyPair,"ecdsaKeyPair"),this.ecdsaKeyPair=null),this.encryptionKey&&(this._secureWipeMemory(this.encryptionKey,"encryptionKey"),this.encryptionKey=null),this.macKey&&(this._secureWipeMemory(this.macKey,"macKey"),this.macKey=null),this.metadataKey&&(this._secureWipeMemory(this.metadataKey,"metadataKey"),this.metadataKey=null),this.nestedEncryptionKey&&(this._secureWipeMemory(this.nestedEncryptionKey,"nestedEncryptionKey"),this.nestedEncryptionKey=null),this.sessionSalt&&(this._secureWipeMemory(this.sessionSalt,"sessionSalt"),this.sessionSalt=null),this.sessionId&&(this._secureWipeMemory(this.sessionId,"sessionId"),this.sessionId=null),this.verificationCode&&(this._secureWipeMemory(this.verificationCode,"verificationCode"),this.verificationCode=null),this.peerPublicKey&&(this._secureWipeMemory(this.peerPublicKey,"peerPublicKey"),this.peerPublicKey=null),this.keyFingerprint&&(this._secureWipeMemory(this.keyFingerprint,"keyFingerprint"),this.keyFingerprint=null),this.connectionId&&(this._secureWipeMemory(this.connectionId,"connectionId"),this.connectionId=null),this._clearPendingOfferContext(),this._ratchet){try{this._ratchet.destroy()}catch{}this._ratchet=null}this._peerSupportsRatchet=!1,this._secureLog("info","\u{1F512} Cryptographic materials securely cleaned up")}catch(e){this._secureLog("error","\u274C Failed to cleanup cryptographic materials",{errorType:e.constructor.name,errorMessage:e.message})}}async _forceGarbageCollection(){try{await this._performNaturalCleanup(),this._secureLog("debug","\u{1F512} Natural memory cleanup performed")}catch(e){this._secureLog("error","\u274C Failed to perform natural cleanup",{errorType:e.constructor.name})}}async _performPeriodicMemoryCleanup(){try{this._secureMemoryManager.isCleaning=!0;let e=this.sessionMode==="ratchet"&&this.isConnected&&this.dataChannel&&this.dataChannel.readyState==="open",t=this._pendingOfferContext?Date.now()-(this._pendingOfferContext.createdAt||0):1/0,r=!!this._pendingOfferContext&&Array.isArray(this._pendingOfferContext.sessionSalt)&&this._pendingOfferContext.sessionSalt.length===64&&t100&&this.messageQueue.splice(0,this.messageQueue.length-50).forEach((a,o)=>{this._secureWipeMemory(a,`periodicCleanup[${o}]`)}),this.processedMessageIds&&this.processedMessageIds.size>1e3&&this.processedMessageIds.clear(),await this._forceGarbageCollection(),this._secureLog("debug","\u{1F512} Periodic memory cleanup completed")}catch(e){this._secureLog("error","\u274C Error during periodic memory cleanup",{errorType:e.constructor.name,errorMessage:e.message})}finally{this._secureMemoryManager.isCleaning=!1}}_createSecureErrorMessage(e,t="unknown"){try{let r=this._categorizeError(e),i=this._getSafeErrorMessage(r,t);return this._secureLog("error","Internal error occurred",{category:r,context:t,errorType:e?.constructor?.name||"Unknown",timestamp:Date.now()}),this._trackErrorFrequency(r),i}catch(r){return this._secureLog("error","Error handling failed",{originalError:e?.message||"Unknown",handlingError:r.message}),"An unexpected error occurred"}}_categorizeError(e){if(!e||!e.message)return this._secureErrorHandler.errorCategories.UNKNOWN;let t=e.message.toLowerCase();return t.includes("crypto")||t.includes("key")||t.includes("encrypt")||t.includes("decrypt")||t.includes("sign")||t.includes("verify")||t.includes("ecdh")||t.includes("ecdsa")?this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC:t.includes("network")||t.includes("connection")||t.includes("timeout")||t.includes("webrtc")||t.includes("peer")?this._secureErrorHandler.errorCategories.NETWORK:t.includes("invalid")||t.includes("validation")||t.includes("format")||t.includes("type")?this._secureErrorHandler.errorCategories.VALIDATION:t.includes("system")||t.includes("internal")||t.includes("memory")||t.includes("resource")?this._secureErrorHandler.errorCategories.SYSTEM:this._secureErrorHandler.errorCategories.UNKNOWN}_getSafeErrorMessage(e,t){let r={[this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC]:{key_generation:"Security initialization failed",key_import:"Security verification failed",key_derivation:"Security setup failed",encryption:"Message security failed",decryption:"Message verification failed",signature:"Authentication failed",default:"Security operation failed"},[this._secureErrorHandler.errorCategories.NETWORK]:{connection:"Connection failed",timeout:"Connection timeout",peer:"Peer connection failed",webrtc:"Communication failed",default:"Network operation failed"},[this._secureErrorHandler.errorCategories.VALIDATION]:{format:"Invalid data format",type:"Invalid data type",structure:"Invalid data structure",default:"Validation failed"},[this._secureErrorHandler.errorCategories.SYSTEM]:{memory:"System resource error",resource:"System resource unavailable",internal:"Internal system error",default:"System operation failed"},[this._secureErrorHandler.errorCategories.UNKNOWN]:{default:"An unexpected error occurred"}},i=r[e]||r[this._secureErrorHandler.errorCategories.UNKNOWN],n="default";return t.includes("key")||t.includes("crypto")?n=e===this._secureErrorHandler.errorCategories.CRYPTOGRAPHIC?"key_generation":"default":t.includes("connection")||t.includes("peer")?n=e===this._secureErrorHandler.errorCategories.NETWORK?"connection":"default":(t.includes("validation")||t.includes("format"))&&(n=e===this._secureErrorHandler.errorCategories.VALIDATION?"format":"default"),i[n]||i.default}_trackErrorFrequency(e){let t=Date.now();t-this._secureErrorHandler.lastErrorTime>6e4&&this._secureErrorHandler.errorCounts.clear();let r=this._secureErrorHandler.errorCounts.get(e)||0;this._secureErrorHandler.errorCounts.set(e,r+1),this._secureErrorHandler.lastErrorTime=t;let i=Array.from(this._secureErrorHandler.errorCounts.values()).reduce((n,a)=>n+a,0);i>this._secureErrorHandler.errorThreshold&&(this._secureErrorHandler.isInErrorMode=!0,this._secureLog("warn","\u26A0\uFE0F High error frequency detected - entering error mode",{totalErrors:i,threshold:this._secureErrorHandler.errorThreshold}))}_throwSecureError(e,t="unknown"){let r=this._createSecureErrorMessage(e,t);throw new Error(r)}_getErrorHandlingStats(){return{errorCounts:Object.fromEntries(this._secureErrorHandler.errorCounts),isInErrorMode:this._secureErrorHandler.isInErrorMode,lastErrorTime:this._secureErrorHandler.lastErrorTime,errorThreshold:this._secureErrorHandler.errorThreshold}}_resetErrorHandlingSystem(){this._secureErrorHandler.errorCounts.clear(),this._secureErrorHandler.isInErrorMode=!1,this._secureErrorHandler.lastErrorTime=0,this._secureLog("info","\u{1F504} Error handling system reset")}_getMemoryManagementStats(){return{totalCleanups:this._secureMemoryManager.memoryStats.totalCleanups,failedCleanups:this._secureMemoryManager.memoryStats.failedCleanups,lastCleanup:this._secureMemoryManager.memoryStats.lastCleanup,isCleaning:this._secureMemoryManager.isCleaning,queueLength:this._secureMemoryManager.cleanupQueue.length}}_validateAPIIntegrity(){try{if(!window.secureBitChat)return this._secureLog("error","\u274C Global API not found during integrity validation"),!1;let e=["sendMessage","getConnectionStatus","getSecurityStatus","sendFile","disconnect"],t=e.filter(a=>!window.secureBitChat[a]||typeof window.secureBitChat[a]!="function");if(t.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - missing methods",{missingMethods:t}),!1;let r={test:!0},n=e.map(a=>{try{return window.secureBitChat[a].bind(r)}catch{return null}}).filter(a=>a===null);if(n.length>0)return this._secureLog("error","\u274C Global API integrity validation failed - method binding issues",{unboundMethods:n.length}),!1;try{let a="_integrity_test_"+Date.now();return Object.defineProperty(window.secureBitChat,a,{value:"test",writable:!0,configurable:!0}),this._secureLog("error","\u274C Global API integrity validation failed - API is mutable"),delete window.secureBitChat[a],!1}catch{this._secureLog("debug","\u2705 Global API immutability verified")}return this._secureLog("info","\u2705 Global API integrity validation passed"),!0}catch(e){return this._secureLog("error","\u274C Global API integrity validation failed",{errorType:e.constructor.name,errorMessage:e.message}),!1}}_validateCryptographicSecurity(){let e=["hasRateLimiting"],t=e.filter(n=>!this.securityFeatures[n]);t.length>0&&(this._secureLog("error","\u{1F6A8} CRITICAL: Missing critical rate limiting feature",{missing:t,currentFeatures:this.securityFeatures,action:"Rate limiting will be forced enabled"}),t.forEach(n=>{this.securityFeatures[n]=!0,this._secureLog("warn",`\u26A0\uFE0F Forced enable critical: ${n} = true`)}));let r=Object.keys(this.securityFeatures).filter(n=>this.securityFeatures[n]),i=["hasEncryption","hasECDH","hasECDSA"].filter(n=>this.securityFeatures[n]);return this._secureLog("info","\u2705 Cryptographic security validation passed",{criticalFeatures:e.length,availableFeatures:r.length,encryptionFeatures:i.length,totalSecurityFeatures:r.length,note:"Encryption features will be enabled after key generation",currentState:{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasRateLimiting:this.securityFeatures.hasRateLimiting}}),!0}_syncSecurityFeaturesWithTariff(){this._secureLog("info","\u2705 All security features enabled by default - no payment required"),["hasEncryption","hasECDH","hasECDSA","hasMutualAuth","hasMetadataProtection","hasEnhancedReplayProtection","hasNonExtractableKeys","hasRateLimiting","hasEnhancedValidation","hasPFS","hasNestedEncryption","hasPacketPadding","hasPacketReordering","hasAntiFingerprinting","hasFakeTraffic","hasDecoyChannels","hasMessageChunking"].forEach(t=>{this.securityFeatures[t]=!0}),this._secureLog("info","\u2705 All security features enabled by default",{enabledFeatures:Object.keys(this.securityFeatures).filter(t=>this.securityFeatures[t]).length,totalFeatures:Object.keys(this.securityFeatures).length})}_emergencyShutdown(e="Security breach"){this._secureLog("error","\u274C EMERGENCY SHUTDOWN: ${reason}");try{this.encryptionKey=null,this.macKey=null,this.metadataKey=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.messageQueue=[],this.processedMessageIds.clear(),this.packetBuffer.clear(),this.onStatusChange&&this.onStatusChange("security_breach"),this._secureLog("info","\u{1F512} Emergency shutdown completed")}catch(t){this._secureLog("error","\u274C Error during emergency shutdown:",{errorType:t?.constructor?.name||"Unknown"})}}_finalizeSecureInitialization(){if(this._startKeySecurityMonitoring(),!this._verifyAPIIntegrity()){this._secureLog("error","\u274C Security initialization failed");return}this._startSecurityMonitoring(),this._logCleanupInterval=this._trackActiveTimer(setInterval(()=>{this._cleanupLogs()},3e5)),this._secureLog("info","\u2705 Secure WebRTC Manager initialization completed"),this._secureLog("info","\u{1F512} Global exposure protection: Monitoring only, no automatic removal")}_startSecurityMonitoring(){this._secureLog("info","\u{1F527} Security monitoring moved to unified scheduler")}_validateConnection(e=!0){let t=this.dataChannel&&this.dataChannel.readyState==="open",r=this.isVerified,i=t&&r;if(!i&&e){if(!t)throw new Error("Data channel not ready");if(!r)throw new Error("Connection not verified")}return i}_enforceVerificationGate(e="unknown",t=!0){if(!this.isVerified){let r=`SECURITY VIOLATION: ${e} blocked - connection not cryptographically verified`;if(this._secureLog("error",r,{operation:e,isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey),timestamp:Date.now()}),t)throw new Error(r);return!1}return!0}_setVerifiedStatus(e,t="unknown",r=null){if(e){if(!this.encryptionKey||!this.macKey)throw new Error("Cannot set verified=true without encryption keys");if(!t||t==="unknown")throw new Error("Cannot set verified=true without specifying verification method");if(t.includes("SAS")&&!this.localVerificationConfirmed)throw this._secureLog("error","Blocked verified transition without local SAS confirmation",{verificationMethod:t,localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed}),new Error("Cannot set verified=true without local SAS confirmation");this._secureLog("info","Connection verified through cryptographic verification",{verificationMethod:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,keyFingerprint:this.keyFingerprint,timestamp:Date.now(),verificationData:r?"provided":"none"})}this.isVerified=e,e?this.onStatusChange("connected"):this.onStatusChange("disconnected")}markGroupLinkVerified(e="group_roster_signature"){let t=this._sbq2;if(!this._isSbq2()||!t||!t.completed||!t.proofVerified||!t.keysDerived)throw new Error("Group link cannot be released: the in-band handshake has not completed");if(!this.encryptionKey||!this.macKey)throw new Error("Group link cannot be released: session keys are missing");if(this.isVerified)return!0;this.localVerificationConfirmed=!0,this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this._setVerifiedStatus(!0,"GROUP_ROSTER_SIGNATURE",{reason:e,timestamp:Date.now()}),this._enforceVerificationGate("group_link_release",!1),this.onStatusChange?.("verified");try{this.processMessageQueue()}catch{}return!0}_createFileMessageAAD(e,t=null){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in _createFileMessageAAD. Manager may not be fully initialized.");return this._createMessageAAD(e,t,!0)}_validateFileMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);if(Date.now()-r.timestamp>18e5)throw new Error("AAD timestamp too old - possible replay attack");return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}_validateIncomingSequenceNumber(e,t="unknown"){try{if(!this.replayProtectionEnabled)return!0;if(typeof e!="number"||!Number.isFinite(e))return this._secureLog("warn","Missing or non-numeric sequence number - rejecting",{receivedType:typeof e,context:t,timestamp:Date.now()}),!1;if(ethis.expectedSequenceNumber+this.maxSequenceGap)return this._secureLog("warn","Sequence number gap too large - possible DoS attack",{received:e,expected:this.expectedSequenceNumber,gap:e-this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.has(e))return this._secureLog("warn","Duplicate sequence number detected - replay attack",{received:e,context:t,timestamp:Date.now()}),!1;if(this.replayWindow.add(e),this.replayWindow.size>this.replayWindowSize){let r=Math.min(...this.replayWindow);this.replayWindow.delete(r)}if(e===this.expectedSequenceNumber)for(this.expectedSequenceNumber++;this.replayWindow.has(this.expectedSequenceNumber-this.replayWindowSize-1);)this.replayWindow.delete(this.expectedSequenceNumber-this.replayWindowSize-1);return this._secureLog("debug","Sequence number validation successful",{received:e,expected:this.expectedSequenceNumber,context:t,timestamp:Date.now()}),!0}catch(r){return this._secureLog("error","Sequence number validation failed",{error:r.message,context:t,timestamp:Date.now()}),!1}}_validateMessageAAD(e,t=null){try{let r=JSON.parse(e);if(r.sessionId!==(this.currentSession?.sessionId||"unknown"))throw new Error("AAD sessionId mismatch - possible replay attack");if(r.keyFingerprint!==(this.keyFingerprint||"unknown"))throw new Error("AAD keyFingerprint mismatch - possible key substitution attack");if(!this._validateIncomingSequenceNumber(r.sequenceNumber,r.messageType))throw new Error("Sequence number validation failed - possible replay or DoS attack");if(t&&r.messageType!==t)throw new Error(`AAD messageType mismatch - expected ${t}, got ${r.messageType}`);return r}catch(r){throw this._secureLog("error","AAD validation failed",{error:r.message,aadLength:typeof e=="string"?e.length:0}),new Error(`AAD validation failed: ${r.message}`)}}getAntiReplayStatus(){let e={replayProtectionEnabled:this.replayProtectionEnabled,replayWindowSize:this.replayWindowSize,currentReplayWindowSize:this.replayWindow.size,sequenceNumber:this.sequenceNumber,expectedSequenceNumber:this.expectedSequenceNumber,maxSequenceGap:this.maxSequenceGap,replayWindowEntries:Array.from(this.replayWindow).sort((t,r)=>t-r)};return this._secureLog("info","Anti-replay status retrieved",e),e}configureAntiReplayProtection(e){try{if(e.windowSize!==void 0){if(e.windowSize<16||e.windowSize>1024)throw new Error("Replay window size must be between 16 and 1024");this.replayWindowSize=e.windowSize}if(e.maxGap!==void 0){if(e.maxGap<10||e.maxGap>1e3)throw new Error("Max sequence gap must be between 10 and 1000");this.maxSequenceGap=e.maxGap}return e.enabled!==void 0&&(this.replayProtectionEnabled=e.enabled),this._secureLog("info","Anti-replay protection configured",e),!0}catch(t){return this._secureLog("error","Failed to configure anti-replay protection",{error:t.message}),!1}}async getRealSecurityLevel(){try{let e={ecdhKeyExchange:!!this.ecdhKeyPair,ecdsaSignatures:!!this.ecdsaKeyPair,aesEncryption:!!this.encryptionKey,messageIntegrity:!!this.hmacKey,replayProtection:this.replayProtectionEnabled,dtlsFingerprint:!!(this.expectedDTLSFingerprint&&this._peerDTLSFingerprint),sasCode:!!this.verificationCode&&this.localVerificationConfirmed===!0,metadataProtection:!0,trafficObfuscation:!0,perfectForwardSecrecy:this.isRatchetActive?.()===!0,rateLimiter:!0,connectionId:this.connectionId,keyFingerprint:this.keyFingerprint,currentSecurityLevel:"maximum",timestamp:Date.now()},t=await this.calculateAndReportSecurityLevel();return t?{...t,...e}:{...e,level:"INITIALIZING",score:0,isRealData:!1}}catch(e){throw this._secureLog("error","Failed to calculate real security level",{error:e.message}),e}}_extractDTLSFingerprintFromSDP(e){try{if(!e||typeof e!="string")throw new Error("Invalid SDP provided");let t=/a=fingerprint:([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/g,r=[],i;for(;(i=t.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()});if(r.length===0){let a=/fingerprint\s*=\s*([a-zA-Z0-9-]+)\s+([A-Fa-f0-9:]+)/gi;for(;(i=a.exec(e))!==null;)r.push({algorithm:i[1].toLowerCase(),fingerprint:i[2].trim()})}if(r.length===0)throw this._secureLog("warn","No DTLS fingerprints found in SDP - this may be normal for some WebRTC implementations",{sdpLength:e.length,sdpPreview:e.substring(0,200)+"..."}),new Error("No DTLS fingerprints found in SDP");return[...r].sort((a,o)=>{let c=a.algorithm==="sha-256",d=o.algorithm==="sha-256";if(c!==d)return c?-1:1;let u=a.algorithm.localeCompare(o.algorithm);return u!==0?u:a.fingerprint.localeCompare(o.fingerprint)})[0].fingerprint}catch(t){throw this._secureLog("error","Failed to extract DTLS fingerprint from SDP",{error:t.message,sdpLength:e?.length||0}),new Error(`DTLS fingerprint extraction failed: ${t.message}`)}}async _validateDTLSFingerprint(e,t,r="unknown"){try{if(!e||!t)throw new Error("Missing fingerprint for validation");let i=e.toLowerCase().replace(/:/g,""),n=t.toLowerCase().replace(/:/g,"");if(i!==n)throw this._secureLog("error","DTLS fingerprint mismatch - possible MITM attack",{context:r,timestamp:Date.now()}),new Error(`DTLS fingerprint mismatch - possible MITM attack in ${r}`);return this._secureLog("info","DTLS fingerprint validation successful",{context:r,timestamp:Date.now()}),!0}catch(i){throw this._secureLog("error","DTLS fingerprint validation failed",{error:i.message,context:r}),i}}async _computeSAS(e,t,r){try{if(!e){let b=[];throw e||b.push("keyMaterialRaw"),new Error(`Missing required parameters for SAS computation: ${b.join(", ")}`)}let i=new TextEncoder,n=(b,w)=>{if(typeof b!="string"||b.trim().length===0)throw new Error(`Security error: ${w} must be a non-empty DTLS fingerprint string for SAS computation`);return b.trim().toLowerCase()},a=n(t,"localFP"),o=n(r,"remoteFP"),c=i.encode("webrtc-sas|"+[a,o].sort().join("|")),d;if(e instanceof ArrayBuffer)d=e;else if(e instanceof Uint8Array)d=e.buffer;else if(typeof e=="string"){let b=e.replace(/:/g,"").replace(/\s/g,""),w=new Uint8Array(b.length/2);for(let M=0;M>>0,g=String(S%1e7).padStart(7,"0");return this._secureLog("info","SAS code computed successfully",{localFP:a.substring(0,16)+"...",remoteFP:o.substring(0,16)+"...",sasLength:g.length,timestamp:Date.now()}),g}catch(i){throw this._secureLog("error","SAS computation failed",{error:i.message,keyMaterialType:typeof e,hasLocalFP:!!t,hasRemoteFP:!!r,timestamp:Date.now()}),new Error(`SAS computation failed: ${i.message}`)}}_dispatchAppEvent(e){if(!this._emitGlobalEvents)return!1;try{return document.dispatchEvent(e)}catch{return!1}}_isSbq2(){return this._handshakeMode==="sbq2"}_latchHandshakeMode(e){if(this._handshakeMode&&this._handshakeMode!==e)throw new Error(`handshake format cannot change mid-session (${this._handshakeMode} -> ${e})`);this._handshakeMode=e}_sbq2State(){return this._sbq2||(this._sbq2={role:null,localDescriptor:null,remoteDescriptor:null,localBlob:null,remoteBlob:null,remoteCommitment:null,transcript:null,peerEcdhKey:null,peerEcdsaKey:null,blobSent:!1,proofSent:!1,proofVerified:!1,keysDerived:!1,pendingProof:null,completed:!1,timer:null,startedAt:0}),this._sbq2}_sbq2Abort(e,t){let r=this._sbq2;r?.timer&&(clearTimeout(r.timer),r.timer=null),this._secureLog("error","SBQ2 handshake aborted",{code:e});try{this.deliverMessageToUI(t,"system")}catch{}try{this.onStatusChange?.("failed")}catch{}try{this.disconnect()}catch{}}async _exportSpki(e){return new Uint8Array(await crypto.subtle.exportKey("spki",e))}async _sbq2BuildLocalBlob(e){if(!this.ecdhKeyPair?.publicKey||!this.ecdsaKeyPair?.publicKey)throw new Error("SBQ2: key pairs are not ready");let t=Cn({role:e,ecdhSpki:await this._exportSpki(this.ecdhKeyPair.publicKey),ecdsaSpki:await this._exportSpki(this.ecdsaKeyPair.publicKey)}),i=await Ht(async a=>new Uint8Array(await crypto.subtle.digest("SHA-256",a)),t),n=this._sbq2State();return n.role=e,n.localBlob=t,{blob:t,commitment:i}}async _sbq2BuildDescriptor(e,{bindingTag:t=null,lifetimeMs:r=600*1e3}={}){let i=this.peerConnection?.localDescription?.sdp;if(!i)throw new Error("SBQ2: no local description to encode");let n=e===de.OFFER?ve.OFFER:ve.ANSWER,{commitment:a}=await this._sbq2BuildLocalBlob(n),o=bn(i),c=_n({type:e,expiresAtMs:Date.now()+r,sdpFields:{...o,candidates:Pr(o.candidates)},commitment:a,...e===de.ANSWER?{bindingTag:t}:{}}),d=this._sbq2State();return d.localDescriptor=c,this._secureLog("info","SBQ2 descriptor built",{type:e===de.OFFER?"offer":"answer",bytes:c.length,candidates:Pr(o.candidates).length}),{bytes:c,text:vn(c)}}_sbq2AdoptRemoteDescriptor(e,t){let r=Fr(e);if(r.type!==t)throw new Error(`expected an ${t===de.OFFER?"invitation":"answer"}, got the other kind`);if(!r.commitment)throw new Error("the invitation carries no key commitment");let i=this._sbq2State();return i.remoteDescriptor=e,i.remoteCommitment=r.commitment,r}async _runSbq2KeyExchange(){let e=this._sbq2State();if(!(e.completed||e.blobSent)){if(e.startedAt=Date.now(),!e.localBlob||!e.localDescriptor||!e.remoteDescriptor||!e.remoteCommitment){this._sbq2Abort("incomplete_state","The secure handshake could not start because the connection setup is incomplete. Please start a new invitation.");return}e.timer=setTimeout(()=>{e.completed||this._sbq2Abort("timeout","The other side did not complete the secure handshake in time. Please try connecting again.")},s.SBQ2_KEY_EXCHANGE_TIMEOUT_MS);try{this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_BLOB,v:2,blob:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(e.localBlob.buffer.slice(e.localBlob.byteOffset,e.localBlob.byteOffset+e.localBlob.byteLength))})),e.blobSent=!0,this._secureLog("info","SBQ2 key blob sent",{bytes:e.localBlob.length})}catch{this._sbq2Abort("blob_send_failed","The secure handshake could not be sent. Please try connecting again.")}}}async _sbq2HandleHandshakeFrame(e){let t=s.MESSAGE_TYPES,r=this._sbq2State();if(!this._isSbq2()){this._secureLog("error","Rejected SBQ2 handshake frame on a non-SBQ2 session",{messageType:e?.type});return}try{if(e.type===t.KEY_BLOB){if(r.remoteBlob){this._sbq2Abort("duplicate_blob","The secure handshake was sent twice. The connection has been closed for safety.");return}let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.blob||"")));await Mn(crypto.subtle,i,r.remoteCommitment);let n=kn(i),a=r.role===ve.OFFER?ve.ANSWER:ve.OFFER;if(n.role!==a){this._sbq2Abort("role_mismatch","The other side sent the wrong kind of handshake. The connection has been closed for safety.");return}r.remoteBlob=i,r.peerEcdhKey=await crypto.subtle.importKey("spki",n.ecdhSpki,{name:"ECDH",namedCurve:"P-384"},!1,[]),r.peerEcdsaKey=await crypto.subtle.importKey("spki",n.ecdsaSpki,{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),await this._sbq2CompleteExchange();return}if(e.type===t.KEY_PROOF){let i=new Uint8Array(window.EnhancedSecureCryptoUtils.base64ToArrayBuffer(String(e.sig||"")));if(!r.transcript||!r.peerEcdsaKey){r.pendingProof=i;return}await this._sbq2VerifyProof(i);return}}catch(i){let n=i?.code||"handshake_failed",a=n==="commitment_mismatch"?"The key material does not match the invitation you scanned. This can mean someone tampered with the connection, so it has been closed.":"The secure handshake failed. The connection has been closed for safety.";this._sbq2Abort(n,a)}}async _sbq2CompleteExchange(){let e=this._sbq2State();if(e.keysDerived||!e.remoteBlob||!e.localBlob)return;this._peerSupportsRatchet=!0;let t=e.role===ve.OFFER;e.transcript=An({offerDescriptor:t?e.localDescriptor:e.remoteDescriptor,answerDescriptor:t?e.remoteDescriptor:e.localDescriptor,offerBlob:t?e.localBlob:e.remoteBlob,answerBlob:t?e.remoteBlob:e.localBlob}),this.sessionSalt=await xn(crypto.subtle,e.transcript),this.peerPublicKey=e.peerEcdhKey,this.peerECDHPublicKey=e.peerEcdhKey;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,e.peerEcdhKey,this.sessionSalt);await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),await this._initializeRatchet(r,t),e.keysDerived=!0;let i=new Uint8Array(await crypto.subtle.sign({name:"ECDSA",hash:"SHA-384"},this.ecdsaKeyPair.privateKey,Vr(e.transcript)));if(this.dataChannel.send(JSON.stringify({type:s.MESSAGE_TYPES.KEY_PROOF,sig:window.EnhancedSecureCryptoUtils.arrayBufferToBase64(i.buffer)})),e.proofSent=!0,e.pendingProof){let n=e.pendingProof;e.pendingProof=null,await this._sbq2VerifyProof(n)}}async _sbq2VerifyProof(e){let t=this._sbq2State();if(t.proofVerified)return;if(!await crypto.subtle.verify({name:"ECDSA",hash:"SHA-384"},t.peerEcdsaKey,e,Vr(t.transcript))){this._sbq2Abort("bad_proof","The other side could not prove it owns its identity key. The connection has been closed for safety.");return}t.proofVerified=!0,this.verificationCode=await Rn(crypto.subtle,{ecdhPrivateKey:this.ecdhKeyPair.privateKey,peerEcdhPublicKey:t.peerEcdhKey,transcript:t.transcript});let i=this.expectedDTLSFingerprint,n=this._peerDTLSFingerprint;i&&n&&this._setSASMaterialReady(i,n),t.completed=!0,t.timer&&(clearTimeout(t.timer),t.timer=null),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this._secureLog("info","SBQ2 in-band key exchange complete",{elapsedMs:Date.now()-t.startedAt,ratchetActive:this.isRatchetActive?.()===!0});try{this.onKeyExchange?.(this.keyFingerprint)}catch{}this._notifyVerificationReadyIfPossible(),this.initiateVerification()}_decodeKeyFingerprint(e){try{if(!e||typeof e!="string")throw new Error("Invalid hex string provided");return window.EnhancedSecureCryptoUtils.hexToUint8Array(e)}catch(t){throw this._secureLog("error","Key fingerprint decoding failed",{error:t.message,inputType:typeof e,inputLength:e?.length||0}),new Error(`Key fingerprint decoding failed: ${t.message}`)}}_emergencyWipeOnFingerprintMismatch(e="DTLS fingerprint mismatch"){try{this._secureLog("error","\u{1F6A8} EMERGENCY: Initiating security wipe due to fingerprint mismatch",{reason:e,timestamp:Date.now()}),this._secureWipeKeys(),this._secureWipeMemory(this.encryptionKey,"emergency_wipe"),this._secureWipeMemory(this.macKey,"emergency_wipe"),this._secureWipeMemory(this.metadataKey,"emergency_wipe"),this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this.isVerified=null,this.verificationCode=null,this.keyFingerprint=null,this.connectionId=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.disconnect(),this.deliverMessageToUI("\u{1F6A8} SECURITY BREACH: Connection terminated due to fingerprint mismatch. Possible MITM attack detected!","system")}catch(t){this._secureLog("error","Failed to perform emergency wipe",{error:t.message})}}getCurrentDTLSFingerprint(){try{if(!this.expectedDTLSFingerprint)throw new Error("No DTLS fingerprint available - connection not established");return this.expectedDTLSFingerprint}catch(e){throw this._secureLog("error","Failed to get current DTLS fingerprint",{error:e.message}),e}}disableStrictDTLSValidation(){this.strictDTLSValidation=!1,this._secureLog("warn","\u26A0\uFE0F Strict DTLS validation disabled - security reduced",{timestamp:Date.now()}),this.deliverMessageToUI("\u26A0\uFE0F DTLS validation disabled for debugging","system")}enableStrictDTLSValidation(){this.strictDTLSValidation=!0,this._secureLog("info","\u2705 Strict DTLS validation re-enabled",{timestamp:Date.now()}),this.deliverMessageToUI("\u2705 DTLS validation re-enabled","system")}async _initializeRatchet(e,t){let r=e?.ratchetRoot;if(!r)return!1;if(!this._peerSupportsRatchet)return this._secureLog("warn","Peer did not advertise Double Ratchet \u2014 falling back to static session keys",{localVersion:s.RATCHET_VERSION}),window.EnhancedSecureCryptoUtils.zeroizeBuffer(r),!1;try{let i=this.peerPublicKey||this.peerECDHPublicKey;if(!i||!this.ecdhKeyPair?.privateKey)throw new Error("handshake ECDH keys unavailable");let n=new zt;return await n.init({sharedSecret:r,sessionSalt:new Uint8Array(this.sessionSalt||[]),selfPrivateKey:this.ecdhKeyPair.privateKey,remotePublicKey:i,isInitiator:t}),this._ratchet=n,this.securityFeatures.hasPFS=!0,this._secureLog("info","\u{1F510} Double Ratchet active \u2014 per-message forward secrecy enabled",{role:t?"initiator":"responder"}),!0}catch(i){return this._ratchet=null,this.securityFeatures.hasPFS=!1,this._secureLog("error","Double Ratchet initialisation failed \u2014 continuing with static session keys",{errorType:i?.constructor?.name||"Unknown"}),!1}finally{window.EnhancedSecureCryptoUtils.zeroizeBuffer(r)}}isRatchetActive(){return!!this._ratchet?.isInitialised}async _generateEphemeralECDHKeys(){try{this._secureLog("info","\u{1F511} Generating ephemeral ECDH keys for PFS",{sessionStartTime:this.sessionStartTime,timestamp:Date.now()});let e=await window.EnhancedSecureCryptoUtils.generateECDHKeyPair();if(!e||!this._validateKeyPairConstantTime(e))throw new Error("Ephemeral ECDH key pair validation failed");let t=this.currentSession?.sessionId||`session_${Date.now()}`;return this.ephemeralKeyPairs.set(t,{keyPair:e,timestamp:Date.now(),sessionId:t}),this._secureLog("info","\u2705 Ephemeral ECDH keys generated for PFS",{timestamp:Date.now()}),e}catch(e){throw this._secureLog("error","\u274C Failed to generate ephemeral ECDH keys",{error:e.message}),new Error(`Ephemeral key generation failed: ${e.message}`)}}async _hardWipeOldKeys(){try{this._secureLog("info","\u{1F9F9} Performing hard wipe of old keys for PFS",{oldKeysCount:this.oldKeys.size,timestamp:Date.now()});for(let[e,t]of this.oldKeys.entries())t.encryptionKey&&this._secureWipeMemory(t.encryptionKey,"pfs_key_wipe"),t.macKey&&this._secureWipeMemory(t.macKey,"pfs_key_wipe"),t.metadataKey&&this._secureWipeMemory(t.metadataKey,"pfs_key_wipe"),t.encryptionKey=null,t.macKey=null,t.metadataKey=null,t.keyFingerprint=null;this.oldKeys.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Hard wipe of old keys completed for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to perform hard wipe of old keys",{error:e.message})}}async _wipeEphemeralKeys(){try{this._secureLog("info","\u{1F9F9} Wiping ephemeral keys for PFS",{ephemeralKeysCount:this.ephemeralKeyPairs.size,timestamp:Date.now()});for(let[e,t]of this.ephemeralKeyPairs.entries())t.keyPair?.privateKey&&this._secureWipeMemory(t.keyPair.privateKey,"ephemeral_key_wipe"),t.keyPair?.publicKey&&this._secureWipeMemory(t.keyPair.publicKey,"ephemeral_key_wipe"),t.keyPair=null,t.timestamp=null,t.sessionId=null;this.ephemeralKeyPairs.clear(),await this._performNaturalCleanup(),this._secureLog("info","\u2705 Ephemeral keys wiped for PFS",{timestamp:Date.now()})}catch(e){this._secureLog("error","\u274C Failed to wipe ephemeral keys",{error:e.message})}}async _encryptFileMessage(e,t){try{if(!this.encryptionKey)throw new Error("No encryption key available for file message");let r=typeof e=="string"?e:JSON.stringify(e),n={type:"encrypted_file_message",encryptedData:await window.EnhancedSecureCryptoUtils.encryptDataWithAAD(r,this.encryptionKey,t),aad:t,timestamp:Date.now(),keyFingerprint:this.keyFingerprint};return JSON.stringify(n)}catch(r){throw this._secureLog("error","Failed to encrypt file message",{error:r.message}),new Error(`File message encryption failed: ${r.message}`)}}async _decryptFileMessage(e){try{let t=JSON.parse(e);if(t.type!=="encrypted_file_message")throw new Error("Invalid encrypted file message type");if(t.keyFingerprint!==this.keyFingerprint)throw new Error("Key fingerprint mismatch in encrypted file message");let r=this._validateMessageAAD(t.aad,"file_message");if(!this.encryptionKey)throw new Error("No encryption key available for file message decryption");return{decryptedData:await window.EnhancedSecureCryptoUtils.decryptDataWithAAD(t.encryptedData,this.encryptionKey,t.aad),aad:r}}catch(t){throw this._secureLog("error","Failed to decrypt file message",{error:t.message}),new Error(`File message decryption failed: ${t.message}`)}}_validateEncryptionKeys(e=!0){let t=!!(this.encryptionKey&&this.macKey&&this.metadataKey);if(!t&&e)throw new Error("Encryption keys not initialized");return t}async _tryReinitializeEncryptionKeys(){try{if(this.encryptionKey&&this.macKey&&this.metadataKey)return!0;let e=!!(this.ecdhKeyPair?.privateKey&&(this.peerPublicKey||this.peerECDHPublicKey)),t=this.peerPublicKey||this.peerECDHPublicKey;if(!e||!t||!this.sessionSalt)return!1;let r=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,t,this.sessionSalt);return await this._setEncryptionKeys(r.messageKey,r.macKey,r.metadataKey,r.fingerprint),!!(this.encryptionKey&&this.macKey&&this.metadataKey)}catch(e){return this._secureLog("error","Failed to reinitialize encryption keys",{error:e.message}),!1}}_isFileMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type&&t.type.startsWith("file_")}catch{return!1}return typeof e=="object"&&e.type?e.type.startsWith("file_"):!1}_isSystemMessage(e){let t=[s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.SECURITY_UPGRADE,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY];if(typeof e=="string")try{let r=JSON.parse(e);return t.includes(r.type)}catch{return!1}return typeof e=="object"&&e.type?t.includes(e.type):!1}_isFakeMessage(e){if(typeof e=="string")try{let t=JSON.parse(e);return t.type===s.MESSAGE_TYPES.FAKE||t.isFakeTraffic===!0}catch{return!1}return typeof e=="object"&&e!==null?e.type===s.MESSAGE_TYPES.FAKE||e.isFakeTraffic===!0:!1}_withErrorHandling(e,t,r=null){try{return e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}async _withAsyncErrorHandling(e,t,r=null){try{return await e()}catch(i){return this._debugMode&&this._secureLog("error","\u274C ${errorMessage}:",{errorType:i?.constructor?.name||"Unknown"}),r}}_getMessageType(e){if(typeof e=="string")try{return JSON.parse(e).type||null}catch{return null}return typeof e=="object"&&e!==null&&e.type||null}_resetNotificationFlags(){this.lastSecurityLevelNotification=null,this.verificationNotificationSent=!1,this.verificationInitiationSent=!1,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.disconnectNotificationSent=!1,this.reconnectionFailedNotificationSent=!1,this.peerDisconnectNotificationSent=!1,this.connectionClosedNotificationSent=!1,this.fakeTrafficDisabledNotificationSent=!1,this.advancedFeaturesDisabledNotificationSent=!1,this.securityUpgradeNotificationSent=!1,this.lastSecurityUpgradeStage=null,this.securityCalculationNotificationSent=!1,this.lastSecurityCalculationLevel=null}_isFilteredMessage(e){return Object.values(s.FILTERED_RESULTS).includes(e)}_cleanupLogs(){this._logCounts.size>500&&(this._logCounts.clear(),this._secureLog("debug","\u{1F9F9} Log counts cleared due to size limit"));let e=Date.now(),t=3e5,r=0;for(let[i,n]of this._logCounts.entries())n>10&&r++;r>20&&(this._logCounts.clear(),this._secureLog("warn","\u{1F6A8} Emergency log cleanup due to suspicious patterns")),this._logSecurityViolations>0&&r<5&&(this._logSecurityViolations=Math.max(0,this._logSecurityViolations-1)),(!this._lastIVCleanupTime||Date.now()-this._lastIVCleanupTime>3e5)&&(this._cleanupOldIVs(),this._lastIVCleanupTime=Date.now()),(!this._secureMemoryManager.memoryStats.lastCleanup||Date.now()-this._secureMemoryManager.memoryStats.lastCleanup>6e5)&&(this._performPeriodicMemoryCleanup().catch(i=>{this._secureLog("error","Periodic cleanup failed",{errorType:i?.constructor?.name||"Unknown"})}),this._secureMemoryManager.memoryStats.lastCleanup=Date.now())}_getLoggingStats(){let e={isProductionMode:this._isProductionMode,debugMode:this._debugMode,currentLogLevel:this._currentLogLevel,logCountsSize:this._logCounts.size,maxLogCount:this._maxLogCount,securityViolations:this._logSecurityViolations||0,maxSecurityViolations:this._maxLogSecurityViolations||3,systemStatus:this._currentLogLevel===-1?"DISABLED":"ACTIVE"},t={};for(let[r,i]of Object.entries(e))typeof i=="string"&&this._containsSensitiveContent(i)?t[r]="[SENSITIVE_DATA_REDACTED]":t[r]=i;return t}async _emergencyDisableLogging(){this._currentLogLevel=-1,this._logCounts.clear(),this._logSecurityViolations&&(this._logSecurityViolations=0),this._secureLog=()=>{arguments[0]==="error"&&this._originalConsole?.error&&this._originalConsole.error("\u{1F6A8} SECURITY: Logging system disabled - potential data exposure prevented")},this._originalSanitizeString=this._sanitizeString,this._originalSanitizeLogData=this._sanitizeLogData,this._originalAuditLogMessage=this._auditLogMessage,this._originalContainsSensitiveContent=this._containsSensitiveContent,this._sanitizeString=()=>"[LOGGING_DISABLED]",this._sanitizeLogData=()=>({error:"LOGGING_DISABLED"}),this._auditLogMessage=()=>!1,this._containsSensitiveContent=()=>!0,await this._performNaturalCleanup(),this._originalConsole?.error?.("\u{1F6A8} CRITICAL: Secure logging system disabled due to potential data exposure")}_resetLoggingSystem(){this._secureLog("info","\u{1F527} Resetting logging system after emergency shutdown"),this._sanitizeString=this._originalSanitizeString||(e=>e),this._sanitizeLogData=this._originalSanitizeLogData||(e=>e),this._auditLogMessage=this._originalAuditLogMessage||(()=>!0),this._containsSensitiveContent=this._originalContainsSensitiveContent||(()=>!1),this._logSecurityViolations=0,this._secureLog("info","\u2705 Logging system reset successfully")}_auditLogMessage(e,t){if(!t||typeof t!="object")return!0;let r=JSON.stringify(t);if(this._containsSensitiveContent(e))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log message"),!1;if(this._containsSensitiveContent(r))return this._emergencyDisableLogging(),this._originalConsole?.error?.("\u{1F6A8} SECURITY BREACH: Sensitive content detected in log data"),!1;let i=["secret","token","password","credential","auth","fingerprint","salt","signature","private_key","api_key","private","encryption","mac","metadata","session","jwt","bearer","key","hash","digest","nonce","iv","cipher"],n=r.toLowerCase();for(let a of i)if(n.includes(a)&&!this._safeFieldsWhitelist.has(a))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: Dangerous pattern detected in log: ${a}`),!1;for(let[a,o]of Object.entries(t))if(typeof o=="string"&&this._hasHighEntropy(o))return this._emergencyDisableLogging(),this._originalConsole?.error?.(`\u{1F6A8} SECURITY BREACH: High entropy value detected in log field: ${a}`),!1;return!0}initializeFileTransfer(){try{if(this._sessionAlive===!1)return;if(this._secureLog("info","\u{1F527} Initializing Enhanced Secure File Transfer system..."),this.fileTransferSystem){this._secureLog("info","\u2705 File transfer system already initialized");return}if(!!!(this.dataChannel&&this.dataChannel.readyState==="open")){if(this._secureLog("warn","\u26A0\uFE0F Data channel not open, deferring file transfer initialization"),this.dataChannel){let i=()=>{this._secureLog("info","\u{1F504} DataChannel opened, initializing file transfer..."),this.initializeFileTransfer()};this.dataChannel.addEventListener("open",i,{once:!0})}return}if(!this.isVerified){this._secureLog("warn","\u26A0\uFE0F Connection not verified yet, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(500);return}if(this.fileTransferSystem&&(this._secureLog("info","\u{1F9F9} Cleaning up existing file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),!this.encryptionKey||!this.macKey){this._secureLog("warn","\u26A0\uFE0F Encryption keys not ready, deferring file transfer initialization"),this._scheduleFileTransferInitRetry(1e3);return}let t=i=>{try{this._secureLog("info","\u{1F3C1} Sender transfer summary",{summary:i}),this.onFileProgress&&this.onFileProgress({type:"complete",...i})}catch(n){this._secureLog("warn","\u26A0\uFE0F onComplete handler failed:",{details:n.message})}};this.fileTransferSystem=new je(this,this.onFileProgress||null,t,this.onFileError||null,this.onFileReceived||null,this.onIncomingFileRequest||null),this._fileTransferActive=!0,this._secureLog("info","\u2705 Enhanced Secure File Transfer system initialized successfully");let r=this.fileTransferSystem.getSystemStatus();this._secureLog("info","\u{1F50D} File transfer system status after init",{status:r})}catch(e){this._secureLog("error","\u274C Failed to initialize file transfer system",{errorType:e.constructor.name}),this.fileTransferSystem=null,this._fileTransferActive=!1}}_scheduleFileTransferInitRetry(e){if(this._sessionAlive===!1)return null;this._fileTransferInitRetryTimers||(this._fileTransferInitRetryTimers=new Set);let t=this._trackActiveTimer(setTimeout(()=>{this._fileTransferInitRetryTimers.delete(t),this._untrackActiveTimer(t),this._sessionAlive!==!1&&this.initializeFileTransfer()},e));return this._fileTransferInitRetryTimers.add(t),t}async initializeEnhancedSecurity(){try{await this.generateNestedEncryptionKey(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration()}catch(e){this._secureLog("error","\u274C Failed to initialize enhanced security",{errorType:e.constructor.name})}}getSafeRandomInt(e,t){if(!Number.isInteger(e)||!Number.isInteger(t))throw new Error("getSafeRandomInt requires integer min and max");if(e>=t)throw new Error("min must be less than max");let r=t-e+1,i=Math.ceil(Math.log2(r)),n=Math.ceil(i/8),a=(1<=r);return e+o}getSafeRandomFloat(e,t,r=1e3){if(typeof e!="number"||typeof t!="number")throw new Error("getSafeRandomFloat requires numeric min and max");if(e>=t)throw new Error("minFloat must be less than maxFloat");let i=this.getSafeRandomInt(0,r),n=(t-e)/r;return e+i*n}generateFingerprintMask(){return{timingOffset:this.getSafeRandomInt(0,1500),sizeVariation:this.getSafeRandomFloat(.75,1.25,1e3),noisePattern:Array.from(crypto.getRandomValues(new Uint8Array(64))),headerVariations:["X-Client-Version","X-Session-ID","X-Request-ID","X-Timestamp","X-Signature","X-Secure","X-Encrypted","X-Protected","X-Safe","X-Anonymous","X-Private"],noiseIntensity:this.getSafeRandomInt(50,150),sizeMultiplier:this.getSafeRandomFloat(.75,1.25,1e3),timingVariation:this.getSafeRandomInt(100,1100)}}configureSecurityForSession(){this._secureLog("info","\u{1F527} Configuring security - all features enabled by default"),this.sessionConstraints={},Object.keys(this.securityFeatures).forEach(e=>{this.sessionConstraints[e]=!0}),this.applySessionConstraints(),this._secureLog("info","\u2705 Security configured - all features enabled",{constraints:this.sessionConstraints}),this._validateCryptographicSecurity()||(this._secureLog("error","\u{1F6A8} CRITICAL: Cryptographic security validation failed after session configuration"),this.onStatusChange&&this.onStatusChange("security_breach",{type:"crypto_security_failure",message:"Cryptographic security validation failed after session configuration"})),this.notifySecurityLevel(),setTimeout(()=>{this.calculateAndReportSecurityLevel()},s.TIMEOUTS.SECURITY_CALC_DELAY)}applySessionConstraints(){this.sessionConstraints&&(Object.keys(this.sessionConstraints).forEach(e=>{switch(this.securityFeatures[e]=!0,e){case"hasFakeTraffic":this.fakeTrafficConfig.enabled=!0,this.isConnected()&&this.startFakeTrafficGeneration();break;case"hasDecoyChannels":this.decoyChannelConfig.enabled=!0,this.isConnected()&&this.initializeDecoyChannels();break;case"hasPacketReordering":this.reorderingConfig.enabled=!0;break;case"hasAntiFingerprinting":this.antiFingerprintingConfig.enabled=!0;break;case"hasMessageChunking":this.chunkingConfig.enabled=!0;break}}),this._secureLog("info","\u2705 All security features enabled by default",{constraints:this.sessionConstraints,currentFeatures:this.securityFeatures}))}_sanitizeIncomingChatMessage(e){return typeof e!="string"?e:window.EnhancedSecureCryptoUtils.sanitizeMessage(e)}deliverMessageToUI(e,t="received",r=null){try{if(this._secureLog("debug","\u{1F4E4} deliverMessageToUI called",{message:e,type:t,messageType:typeof e,hasOnMessage:!!this.onMessage}),typeof e=="object"&&e.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(e.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI: ${e.type}`);return}if(typeof e=="string"&&e.trim().startsWith("{"))try{let n=JSON.parse(e);if(n.type&&[s.MESSAGE_TYPES.FILE_TRANSFER_START,s.MESSAGE_TYPES.FILE_TRANSFER_RESPONSE,s.MESSAGE_TYPES.FILE_CHUNK,s.MESSAGE_TYPES.CHUNK_CONFIRMATION,s.MESSAGE_TYPES.FILE_TRANSFER_COMPLETE,s.MESSAGE_TYPES.FILE_TRANSFER_ERROR,s.MESSAGE_TYPES.HEARTBEAT,s.MESSAGE_TYPES.VERIFICATION,s.MESSAGE_TYPES.VERIFICATION_RESPONSE,s.MESSAGE_TYPES.VERIFICATION_CONFIRMED,s.MESSAGE_TYPES.VERIFICATION_BOTH_CONFIRMED,s.MESSAGE_TYPES.PEER_DISCONNECT,s.MESSAGE_TYPES.KEY_ROTATION_SIGNAL,s.MESSAGE_TYPES.KEY_ROTATION_READY,s.MESSAGE_TYPES.SECURITY_UPGRADE].includes(n.type)){this._debugMode&&this._secureLog("warn",`\u{1F6D1} Blocked system/file message from UI (string): ${n.type}`);return}}catch{}let i=t==="received"?this._sanitizeIncomingChatMessage(e):e;if(this.onMessage){let n=r&&typeof this._sanitizeMessageMeta=="function"?this._sanitizeMessageMeta(r):null;this._secureLog("debug","\u{1F4E4} Calling this.onMessage callback",{message:i,type:t}),this.onMessage(i,t,n||void 0)}else this._secureLog("warn","\u26A0\uFE0F this.onMessage callback is null or undefined")}catch(i){this._secureLog("error","\u274C Failed to deliver message to UI:",{errorType:i?.constructor?.name||"Unknown"})}}notifySecurityLevel(){if(this.lastSecurityLevelNotification==="maximum")return;if(this.lastSecurityLevelNotification="maximum",this.onMessage&&this.deliverMessageToUI("\u{1F6E1}\uFE0F Maximum Security Active - All features enabled","system"),this.onMessage){let t=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r.replace("has","").replace(/([A-Z])/g," $1").trim().toLowerCase()).slice(0,5);this.deliverMessageToUI(`\u{1F527} Active: ${t.join(", ")}...`,"system")}}cleanupDecoyChannels(){for(let[e,t]of this.decoyTimers.entries())clearTimeout(t);this.decoyTimers.clear();for(let[e,t]of this.decoyChannels.entries())t.readyState==="open"&&t.close();this.decoyChannels.clear(),this._secureLog("info","\u{1F9F9} Decoy channels cleaned up")}async generateNestedEncryptionKey(){try{this.nestedEncryptionKey=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}catch(e){throw this._secureLog("error","\u274C Failed to generate nested encryption key:",{errorType:e?.constructor?.name||"Unknown"}),e}}async applyNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;try{let t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"nestedEncryption"),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this.nestedEncryptionKey,e),i=new Uint8Array(s.SIZES.NESTED_ENCRYPTION_IV_SIZE+r.byteLength);return i.set(t,0),i.set(new Uint8Array(r),s.SIZES.NESTED_ENCRYPTION_IV_SIZE),this._secureLog("debug","\u2705 Nested encryption applied with secure IV",{ivSize:t.length,dataSize:e.byteLength,encryptedSize:r.byteLength}),i.buffer}catch(t){return this._secureLog("error","\u274C Nested encryption failed:",{errorType:t?.constructor?.name||"Unknown",errorMessage:t?.message||"Unknown error"}),t.message.includes("emergency mode")&&(this.securityFeatures.hasNestedEncryption=!1,this._secureLog("warn","\u26A0\uFE0F Nested encryption disabled due to IV emergency mode")),e}}async removeNestedEncryption(e){if(!this.nestedEncryptionKey||!this.securityFeatures.hasNestedEncryption)return e;if(!(e instanceof ArrayBuffer)||e.byteLengtht.length-4?(this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid packet padding size, skipping removal"),e):t.slice(4,4+i).buffer}catch(t){return this._debugMode&&this._secureLog("error","\u274C Packet padding removal failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}startFakeTrafficGeneration(){if(!this.fakeTrafficConfig.enabled||!this.isConnected())return;if(this.fakeTrafficTimer){this._secureLog("warn","\u26A0\uFE0F Fake traffic generation already running");return}let e=async()=>{if(!this.isConnected()){this.stopFakeTrafficGeneration();return}try{let n=this.generateFakeMessage();await this.sendFakeMessage(n);let a=this.fakeTrafficConfig.randomDecoyIntervals?this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minInterval,Math.min(this.fakeTrafficConfig.maxInterval,6e4)):this.fakeTrafficConfig.minInterval,o=Math.max(a,s.TIMEOUTS.FAKE_TRAFFIC_MIN_INTERVAL);this.fakeTrafficTimer=setTimeout(e,o)}catch(n){this._debugMode&&this._secureLog("error","\u274C Fake traffic generation failed:",{errorType:n?.constructor?.name||"Unknown"}),this.stopFakeTrafficGeneration()}},t=s.TIMEOUTS.DECOY_INITIAL_DELAY,r=Math.min(this.fakeTrafficConfig.maxInterval,3e4),i=this.getUnbiasedRandomInRange(t,r);this.fakeTrafficTimer=setTimeout(e,i)}stopFakeTrafficGeneration(){this.fakeTrafficTimer&&(clearTimeout(this.fakeTrafficTimer),this.fakeTrafficTimer=null)}generateFakeMessage(){let e=this.getUnbiasedRandomInRange(0,this.fakeTrafficConfig.patterns.length-1),t=this.fakeTrafficConfig.patterns[e],r=this.getUnbiasedRandomInRange(this.fakeTrafficConfig.minSize,this.fakeTrafficConfig.maxSize),i=crypto.getRandomValues(new Uint8Array(r));return{type:s.MESSAGE_TYPES.FAKE,pattern:t,data:Array.from(i).map(n=>n.toString(16).padStart(2,"0")).join(""),timestamp:Date.now(),size:r,isFakeTraffic:!0,source:"fake_traffic_generator",fakeId:crypto.getRandomValues(new Uint32Array(1))[0].toString(36)}}emergencyDisableAdvancedFeatures(){this._secureLog("error","\u{1F6A8} Emergency disabling advanced security features due to errors"),this.securityFeatures.hasNestedEncryption=!1,this.securityFeatures.hasPacketReordering=!1,this.securityFeatures.hasAntiFingerprinting=!1,this.reorderingConfig.enabled=!1,this.antiFingerprintingConfig.enabled=!1,this.packetBuffer.clear(),this.emergencyDisableFakeTraffic(),this._secureLog("info","\u2705 Advanced features disabled, keeping basic encryption"),this.advancedFeaturesDisabledNotificationSent||(this.advancedFeaturesDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Advanced security features temporarily disabled due to compatibility issues","system"))}async sendFakeMessage(e){if(this._validateConnection(!1))try{this._secureLog("debug","\u{1F3AD} Sending fake message",{hasPattern:!!e.pattern,sizeRange:e.size>100?"large":"small"});let t=JSON.stringify({...e,type:s.MESSAGE_TYPES.FAKE,isFakeTraffic:!0,timestamp:Date.now()}),r=new TextEncoder().encode(t),i=await this.applySecurityLayers(r,!0);this.dataChannel.send(i),this._secureLog("debug","\u{1F3AD} Fake message sent successfully",{pattern:e.pattern})}catch(t){this._secureLog("error","\u274C Failed to send fake message",{error:t.message})}}checkFakeTrafficStatus(){let e={fakeTrafficEnabled:this.securityFeatures.hasFakeTraffic,fakeTrafficConfigEnabled:this.fakeTrafficConfig.enabled,timerActive:!!this.fakeTrafficTimer,patterns:this.fakeTrafficConfig.patterns,intervals:{min:this.fakeTrafficConfig.minInterval,max:this.fakeTrafficConfig.maxInterval}};return this._debugMode&&this._secureLog("info","\u{1F3AD} Fake Traffic Status",{status:e}),e}emergencyDisableFakeTraffic(){this._debugMode&&this._secureLog("error","\u{1F6A8} Emergency disabling fake traffic"),this.securityFeatures.hasFakeTraffic=!1,this.fakeTrafficConfig.enabled=!1,this.stopFakeTrafficGeneration(),this._debugMode&&this._secureLog("info","\u2705 Fake traffic disabled"),this.fakeTrafficDisabledNotificationSent||(this.fakeTrafficDisabledNotificationSent=!0,this.onMessage&&this.deliverMessageToUI("\u{1F6A8} Fake traffic emergency disabled","system"))}async _applySecurityLayersWithoutMutex(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayersWithoutMutex:",{errorType:r?.constructor?.name||"Unknown"}),e}}async processChunkedMessage(e){try{if(!this.chunkingConfig.addChunkHeaders)return this.processMessage(e);let t=new Uint8Array(e);if(t.length<16)return this.processMessage(e);let r=new DataView(t.buffer,0,16),i=r.getUint32(0,!1),n=r.getUint32(4,!1),a=r.getUint32(8,!1),o=r.getUint32(12,!1),c=t.slice(16,16+o);this.chunkQueue[i]||(this.chunkQueue[i]={chunks:new Array(a),received:0,timestamp:Date.now()});let d=this.chunkQueue[i];if(d.chunks[n]=c,d.received++,this._secureLog("debug",`\u{1F4E6} Received chunk ${n+1}/${a} for message ${i}`),d.received===a){let u=d.chunks.reduce((p,S)=>p+S.length,0),h=new Uint8Array(u),m=0;for(let p of d.chunks)h.set(p,m),m+=p.length;await this.processMessage(h.buffer),delete this.chunkQueue[i],this._secureLog("info",`\u{1F4E6} Chunked message ${i} reassembled and processed`)}}catch(t){this._secureLog("error","\u274C Chunked message processing failed:",{errorType:t?.constructor?.name||"Unknown"})}}initializeDecoyChannels(){if(!(!this.decoyChannelConfig.enabled||!this.peerConnection)){if(this.decoyChannels.size>0){this._secureLog("warn","\u26A0\uFE0F Decoy channels already initialized, skipping...");return}try{let e=Math.min(this.decoyChannelConfig.maxDecoyChannels,this.decoyChannelConfig.decoyChannelNames.length);for(let t=0;t.5,maxRetransmits:Math.floor(Math.random()*3)});this.setupDecoyChannel(i,r),this.decoyChannels.set(r,i)}this._debugMode&&this._secureLog("info",`\u{1F3AD} Initialized ${e} decoy channels`)}catch(e){this._debugMode&&this._secureLog("error","\u274C Failed to initialize decoy channels:",{errorType:e?.constructor?.name||"Unknown"})}}}setupDecoyChannel(e,t){e.onopen=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" opened`),this.startDecoyTraffic(e,t)},e.onmessage=r=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Received decoy message on "${t}": ${r.data?.length||"undefined"} bytes`)},e.onclose=()=>{this._debugMode&&this._secureLog("debug",`\u{1F3AD} Decoy channel "${t}" closed`),this.stopDecoyTraffic(t)},e.onerror=r=>{this._debugMode&&this._secureLog("error",`\u274C Decoy channel "${t}" error`,{error:r.message})}}startDecoyTraffic(e,t){let r=async()=>{if(e.readyState==="open")try{let n=this.generateDecoyData(t);e.send(n);let a=this.decoyChannelConfig.randomDecoyIntervals?Math.random()*15e3+1e4:2e4;this.decoyTimers.set(t,setTimeout(()=>r(),a))}catch(n){this._debugMode&&this._secureLog("error",`\u274C Failed to send decoy data on "${t}"`,{error:n.message})}},i=Math.random()*1e4+5e3;this.decoyTimers.set(t,setTimeout(()=>r(),i))}stopDecoyTraffic(e){let t=this.decoyTimers.get(e);t&&(clearTimeout(t),this.decoyTimers.delete(e))}generateDecoyData(e){let t={sync:()=>JSON.stringify({type:"sync",timestamp:Date.now(),sequence:Math.floor(Math.random()*1e3),data:Array.from(crypto.getRandomValues(new Uint8Array(32))).map(r=>r.toString(16).padStart(2,"0")).join("")}),status:()=>JSON.stringify({type:"status",status:["online","away","busy"][Math.floor(Math.random()*3)],uptime:Math.floor(Math.random()*3600),data:Array.from(crypto.getRandomValues(new Uint8Array(16))).map(r=>r.toString(16).padStart(2,"0")).join("")}),heartbeat:()=>JSON.stringify({type:"heartbeat",timestamp:Date.now(),data:Array.from(crypto.getRandomValues(new Uint8Array(24))).map(r=>r.toString(16).padStart(2,"0")).join("")}),metrics:()=>JSON.stringify({type:"metrics",cpu:Math.random()*100,memory:Math.random()*100,network:Math.random()*1e3,data:Array.from(crypto.getRandomValues(new Uint8Array(20))).map(r=>r.toString(16).padStart(2,"0")).join("")}),debug:()=>JSON.stringify({type:"debug",level:["info","warn","error"][Math.floor(Math.random()*3)],message:"Debug message",data:Array.from(crypto.getRandomValues(new Uint8Array(28))).map(r=>r.toString(16).padStart(2,"0")).join("")})};return t[e]?t[e]():Array.from(crypto.getRandomValues(new Uint8Array(64))).map(r=>r.toString(16).padStart(2,"0")).join("")}addReorderingHeaders(e){if(!this.reorderingConfig.enabled)return e;try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8,i=new ArrayBuffer(r),n=new DataView(i);this.reorderingConfig.useSequenceNumbers&&n.setUint32(0,this.sequenceNumber++,!1),this.reorderingConfig.useTimestamps&&n.setUint32(4,Date.now(),!1),n.setUint32(this.reorderingConfig.useTimestamps?8:4,t.length,!1);let a=new Uint8Array(r+t.length);return a.set(new Uint8Array(i),0),a.set(t,r),a.buffer}catch(t){return this._secureLog("error","\u274C Failed to add reordering headers:",{errorType:t?.constructor?.name||"Unknown"}),e}}async processReorderedPacket(e){if(!this.reorderingConfig.enabled)return this.processMessage(e);try{let t=new Uint8Array(e),r=this.reorderingConfig.useTimestamps?12:8;if(t.lengtht.length-r||o<=0)return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Invalid reordered packet data size, processing directly"),this.processMessage(e);let c=t.slice(r,r+o);try{let d=new TextDecoder().decode(c),u=JSON.parse(d);if(u.type==="fake"||u.isFakeTraffic===!0){this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Reordered fake message: ${u.pattern||"unknown"}`);return}}catch{}this.packetBuffer.set(n,{data:c.buffer,timestamp:a||Date.now()}),await this.processOrderedPackets()}catch(t){return this._secureLog("error","\u274C Failed to process reordered packet:",{errorType:t?.constructor?.name||"Unknown"}),this.processMessage(e)}}async processOrderedPackets(){let e=Date.now(),t=this.reorderingConfig.reorderTimeout;for(;;){let r=this.lastProcessedSequence+1,i=this.packetBuffer.get(r);if(i){try{let n=new TextDecoder().decode(i.data),a=JSON.parse(n);if(a.type==="fake"||a.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Ordered fake message: ${a.pattern||"unknown"}`),this.packetBuffer.delete(r),this.lastProcessedSequence=r;continue}}catch{}await this.processMessage(i.data),this.packetBuffer.delete(r),this.lastProcessedSequence=r}else{let n=this.findOldestPacket();if(n&&e-n.timestamp>t){this._secureLog("warn","\u26A0\uFE0F Packet ${oldestPacket.sequence} timed out, processing out of order");try{let a=new TextDecoder().decode(n.data),o=JSON.parse(a);if(o.type==="fake"||o.isFakeTraffic===!0){this._secureLog("warn",`\u{1F3AD} BLOCKED: Timed out fake message: ${o.pattern||"unknown"}`),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence;continue}}catch{}await this.processMessage(n.data),this.packetBuffer.delete(n.sequence),this.lastProcessedSequence=n.sequence}else break}}this.cleanupOldPackets(e,t)}findOldestPacket(){let e=null;for(let[t,r]of this.packetBuffer.entries())(!e||r.timestampt&&(this._secureLog("warn","\u26A0\uFE0F \u{1F5D1}\uFE0F Removing timed out packet ${sequence}"),this.packetBuffer.delete(r))}applyAntiFingerprinting(e){if(!this.antiFingerprintingConfig.enabled)return e;try{let t=e;return this.antiFingerprintingConfig.addNoise&&(t=this.addNoise(t)),this.antiFingerprintingConfig.randomizeSizes&&(t=this.randomizeSize(t)),this.antiFingerprintingConfig.maskPatterns&&(t=this.maskPatterns(t)),this.antiFingerprintingConfig.useRandomHeaders&&(t=this.addRandomHeaders(t)),t}catch(t){return this._secureLog("error","\u274C Anti-fingerprinting failed:",{errorType:t?.constructor?.name||"Unknown"}),e}}addNoise(e){let t=new Uint8Array(e),r=this.getUnbiasedRandomInRange(8,40),i=crypto.getRandomValues(new Uint8Array(r)),n=new Uint8Array(t.length+r);return n.set(t,0),n.set(i,t.length),n.buffer}randomizeSize(e){let t=new Uint8Array(e),r=this.fingerprintMask.sizeVariation,i=Math.floor(t.length*r);if(i>t.length){let n=crypto.getRandomValues(new Uint8Array(i-t.length)),a=new Uint8Array(i);return a.set(t,0),a.set(n,t.length),a.buffer}else if(i=256-256%this.fingerprintMask.headerVariations.length);let d=this.fingerprintMask.headerVariations[c%this.fingerprintMask.headerVariations.length],u;do u=crypto.getRandomValues(new Uint8Array(1))[0];while(u>=256-256%16);let h=crypto.getRandomValues(new Uint8Array(u%16+4)),m=new DataView(n.buffer,a);m.setUint32(0,h.length+8,!1),m.setUint32(4,this.hashString(d),!1),n.set(h,a+8);let p=this.calculateChecksum(n.slice(a,a+8+h.length));new DataView(n.buffer,a+8+h.length).setUint32(0,p,!1),a+=8+h.length+4}return n.set(t,a),n.buffer}hashString(e){let t=0;for(let r=0;r50)try{if(/^[A-Za-z0-9+/=]+$/.test(r.trim())&&(this._debugMode&&this._secureLog("debug","\u{1F513} Applying standard decryption..."),r=await window.EnhancedSecureCryptoUtils.decryptData(r,this.encryptionKey),this._debugMode&&this._secureLog("debug","\u2705 Standard decryption successful"),typeof r=="string")){try{let n=JSON.parse(r);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Legacy fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}r=new TextEncoder().encode(r).buffer}}catch(i){return this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Standard decryption failed:",{details:i.message}),e}if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&r.byteLength>12)try{if(r=await this.removeNestedEncryption(r),r instanceof ArrayBuffer)try{let i=new TextDecoder().decode(r),n=JSON.parse(i);if(n.type==="fake"||n.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Nested fake message: ${n.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Nested decryption failed - skipping this layer:",{details:i.message})}if(this.securityFeatures.hasPacketReordering&&this.reorderingConfig.enabled&&r instanceof ArrayBuffer)try{let i=this.reorderingConfig.useTimestamps?12:8;if(r.byteLength>i)return await this.processReorderedPacket(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Reordering processing failed - using direct processing:",{details:i.message})}if(this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer)try{r=this.removePacketPadding(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Padding removal failed:",{details:i.message})}if(this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer)try{r=this.removeAntiFingerprinting(r)}catch(i){this._debugMode&&this._secureLog("warn","\u26A0\uFE0F Anti-fingerprinting removal failed:",{details:i.message})}if(r instanceof ArrayBuffer&&(r=new TextDecoder().decode(r)),typeof r=="string")try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return this._debugMode&&this._secureLog("warn",`\u{1F3AD} BLOCKED: Final check fake message: ${i.pattern||"unknown"}`),"FAKE_MESSAGE_FILTERED"}catch{}return r}catch(t){return this._secureLog("error","\u274C Critical error in removeSecurityLayers:",{errorType:t?.constructor?.name||"Unknown"}),e}}removeAntiFingerprinting(e){return e}async applySecurityLayers(e,t=!1){try{let r=e;return t?(this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&r instanceof ArrayBuffer&&(r=await this.applyNestedEncryption(r)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&r instanceof ArrayBuffer&&(r=this.applyPacketReordering(r)),this.securityFeatures.hasPacketPadding&&r instanceof ArrayBuffer&&(r=this.applyPacketPadding(r)),this.securityFeatures.hasAntiFingerprinting&&r instanceof ArrayBuffer&&(r=this.applyAntiFingerprinting(r)),this.encryptionKey&&typeof r=="string"&&(r=await window.EnhancedSecureCryptoUtils.encryptData(r,this.encryptionKey)),r)}catch(r){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:r?.constructor?.name||"Unknown"}),e}}_sanitizeMessageMeta(e){if(!e||typeof e!="object")return null;let t={};if(typeof e.mid=="string"&&e.mid.length>0&&e.mid.length<=64&&(t.mid=e.mid.replace(/[^A-Za-z0-9_-]/g,"").slice(0,64)),e.code===!0&&(t.code=!0),e.once===!0&&(t.once=!0),Number.isFinite(e.onceTtl)){let r=Math.floor(e.onceTtl);r>=1&&r<=3600&&(t.onceTtl=r)}if(Number.isFinite(e.ttl)){let r=Math.floor(e.ttl);r>=5&&r<=86400&&(t.ttl=r)}return Object.keys(t).length?t:null}sendMessageDelete(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_DELETE,messageId:e.slice(0,64)})}sendDeliveryReceipt(e){return typeof e!="string"||!e?!1:this.sendSystemMessage({type:s.MESSAGE_TYPES.MESSAGE_RECEIPT,messageId:e.slice(0,64)})}async sendMessage(e,t=null){let r=this._validateInputData(e,"sendMessage");if(!r.isValid){let i=`Input validation failed: ${r.errors.join(", ")}`;throw this._secureLog("error","\u274C Input validation failed in sendMessage",{errors:r.errors,dataType:typeof e,dataLength:e?.length||e?.byteLength||0}),new Error(i)}if(!this._checkRateLimit("sendMessage"))throw new Error("Rate limit exceeded for message sending");if(this._enforceVerificationGate("sendMessage"),!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not ready");try{if(this.encryptionKey&&this.macKey&&this.metadataKey||await this._tryReinitializeEncryptionKeys(),this._secureLog("debug","sendMessage called",{hasDataChannel:!!this.dataChannel,dataChannelReady:this.dataChannel?.readyState==="open",isInitiator:this.isInitiator,isVerified:this.isVerified,connectionReady:this.peerConnection?.connectionState==="connected"}),this._secureLog("debug","\u{1F50D} sendMessage DEBUG",{dataType:typeof r.sanitizedData,isString:typeof r.sanitizedData=="string",isArrayBuffer:r.sanitizedData instanceof ArrayBuffer,dataLength:r.sanitizedData?.length||r.sanitizedData?.byteLength||0}),typeof r.sanitizedData=="string")try{let n=JSON.parse(r.sanitizedData);if(n.type&&n.type.startsWith("file_")){this._secureLog("debug","\u{1F4C1} File message detected - applying full encryption with AAD",{type:n.type});let a=this._createFileMessageAAD(n.type,n.data),o=await this._encryptFileMessage(r.sanitizedData,a);return this.dataChannel.send(o),!0}}catch{}if(typeof r.sanitizedData=="string"){if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available. Manager may not be fully initialized.");let n=this._createMessageAAD("message",{content:r.sanitizedData}),a={type:"message",data:r.sanitizedData,timestamp:Date.now(),aad:n};return t&&typeof t=="object"&&(a.meta=this._sanitizeMessageMeta(t)),await this.sendSecureMessage(a)}this._secureLog("debug","\u{1F510} Applying security layers to non-string data");let i=await this._applySecurityLayersWithLimitedMutex(r.sanitizedData,!1);return this.dataChannel.send(i),!0}catch(i){throw this._secureLog("error","\u274C Failed to send message",{error:i.message,errorType:i.constructor.name}),i}}async _applySecurityLayersWithLimitedMutex(e,t=!1){return this._withMutex("cryptoOperation",async r=>{try{let i=e;return t?(this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i):(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&i instanceof ArrayBuffer&&(i=await this.applyNestedEncryption(i)),this.securityFeatures.hasPacketReordering&&this.reorderingConfig?.enabled&&i instanceof ArrayBuffer&&(i=this.applyPacketReordering(i)),this.securityFeatures.hasPacketPadding&&i instanceof ArrayBuffer&&(i=this.applyPacketPadding(i)),this.securityFeatures.hasAntiFingerprinting&&i instanceof ArrayBuffer&&(i=this.applyAntiFingerprinting(i)),this.encryptionKey&&typeof i=="string"&&(i=await window.EnhancedSecureCryptoUtils.encryptData(i,this.encryptionKey)),i)}catch(i){return this._secureLog("error","\u274C Error in applySecurityLayers:",{errorType:i?.constructor?.name||"Unknown"}),e}},3e3)}async sendSystemMessage(e){if(e.type==="verification_request"||e.type==="verification_response"||e.type==="verification_required"||this._enforceVerificationGate("sendSystemMessage",!1),!this.dataChannel||this.dataChannel.readyState!=="open")return this._secureLog("warn","\u26A0\uFE0F Cannot send system message - data channel not ready"),!1;try{let r=JSON.stringify({type:e.type,data:e,timestamp:Date.now()});return this._secureLog("debug","\u{1F527} Sending system message",{type:e.type}),this.dataChannel.send(r),!0}catch(r){return this._secureLog("error","\u274C Failed to send system message:",{errorType:r?.constructor?.name||"Unknown"}),!1}}async processMessage(e){try{if(this._noteInboundActivity?.(),this._secureLog("debug","\uFFFD\uFFFD Processing message",{dataType:typeof e,isArrayBuffer:e instanceof ArrayBuffer,hasData:!!(e?.length||e?.byteLength)}),typeof e=="string")try{let i=JSON.parse(e),n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(i.type==="encrypted_file_message"){this._secureLog("debug","\u{1F4C1} Encrypted file message detected in processMessage");try{let{decryptedData:a,aad:o}=await this._decryptFileMessage(e),c=JSON.parse(a);if(this._secureLog("debug","\u{1F4C1} File message decrypted successfully",{type:c.type,aadMessageType:o.messageType}),this.fileTransferSystem&&typeof this.fileTransferSystem.handleFileMessage=="function"){await this.fileTransferSystem.handleFileMessage(c);return}}catch(a){this._secureLog("error","\u274C Failed to decrypt file message",{error:a.message});return}}if(i.type&&n.includes(i.type)){this._secureLog("warn","\u26A0\uFE0F Unencrypted file message detected - this should not happen in secure mode",{type:i.type}),this._secureLog("error","\u274C Dropping unencrypted file message for security",{type:i.type});return}if(i.type==="enhanced_message"){if(this._secureLog("debug","\u{1F510} Enhanced message detected in processMessage"),!this._checkInboundRateLimit("processMessage:enhanced_message"))return;try{let a=await window.EnhancedSecureCryptoUtils.decryptMessage(i.data,this.encryptionKey,this.macKey,this.metadataKey),o=JSON.parse(a.data);if(a.metadata&&a.metadata.sequenceNumber!==void 0&&!this._validateIncomingSequenceNumber(a.metadata.sequenceNumber,"enhanced_message")){this._secureLog("warn","\u26A0\uFE0F Enhanced message sequence number validation failed - possible replay attack",{received:a.metadata.sequenceNumber,expected:this.expectedSequenceNumber});return}o.type==="message"&&this.onMessage&&o.data&&this.deliverMessageToUI(o.data,"received",o.meta);return}catch(a){this._secureLog("error","\u274C Failed to decrypt enhanced message",{error:a.message});return}}if(i.type===s.MESSAGE_TYPES.MESSAGE){this._secureLog("error","Rejected unencrypted frame in processMessage",{messageType:"message"});return}if(i.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(i.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:i.type});return}let a=s.MESSAGE_TYPES;if(i.type===a.MESSAGE_DELETE){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelete?.(o.slice(0,64))}catch{}return}if(i.type===a.MESSAGE_RECEIPT){let o=i?.data?.messageId??i?.messageId;if(typeof o=="string"&&o)try{this.onMessageDelivered?.(o.slice(0,64))}catch{}return}if([a.CALL_OFFER,a.CALL_ANSWER,a.CALL_ICE,a.CALL_DECLINE,a.CALL_END].includes(i.type)){try{await this._handleCallSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C Call signal handling failed",{errorType:o?.constructor?.name})}return}if([a.ICE_RESTART_OFFER,a.ICE_RESTART_ANSWER,a.ICE_RESTART_REQUEST].includes(i.type)){try{await this._handleIceRestartSignal(i.type,i.data||{})}catch(o){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:o?.constructor?.name})}return}return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn","\u{1F3AD} Fake message blocked in processMessage",{pattern:i.pattern});return}}catch{this._secureLog("error","Rejected malformed (non-JSON) frame in processMessage",{dataLength:typeof e=="string"?e.length:0});return}let t=await this._processEncryptedDataWithLimitedMutex(e);if(t==="FAKE_MESSAGE_FILTERED"||t==="FILE_MESSAGE_FILTERED"||t==="SYSTEM_MESSAGE_FILTERED")return;if(!t){this._secureLog("warn","\u26A0\uFE0F No data returned from removeSecurityLayers");return}let r;if(typeof t=="string")try{let i=JSON.parse(t);if(i.type&&fileMessageTypes.includes(i.type)){this._secureLog("debug","\u{1F4C1} File message detected after decryption",{type:i.type}),this.fileTransferSystem&&await this.fileTransferSystem.handleFileMessage(i);return}if(i.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","peer_disconnect","security_upgrade"].includes(i.type)){this.handleSystemMessage(i);return}if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Post-decryption fake message blocked: ${i.pattern}`);return}i.type==="message"&&i.data?r=i.data:r=t}catch{r=t}else if(t instanceof ArrayBuffer)r=new TextDecoder().decode(t);else if(t&&typeof t=="object"&&t.message)r=t.message;else{this._secureLog("warn","\u26A0\uFE0F Unexpected data type after processing:",{details:typeof t});return}if(r&&r.trim().startsWith("{"))try{let i=JSON.parse(r);if(i.type==="fake"){this._secureLog("warn",`\u{1F3AD} Final fake message check blocked: ${i.pattern}`);return}let n=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error","heartbeat","verification","verification_response","peer_disconnect","key_rotation_signal","key_rotation_ready","security_upgrade","ice_restart_offer","ice_restart_answer","ice_restart_request"];if(i.type&&n.includes(i.type)){this._secureLog("warn",`\u{1F4C1} Final system/file message check blocked: ${i.type}`);return}}catch{}r&&this._secureLog("error","Rejected unauthenticated payload at the end of processMessage",{messageLength:typeof r=="string"?r.length:0})}catch(t){this._secureLog("error","\u274C Failed to process message:",{errorType:t?.constructor?.name||"Unknown"})}}async _processEncryptedDataWithLimitedMutex(e){return this._withMutex("cryptoOperation",async t=>{this._secureLog("debug","\u{1F510} Processing encrypted data with limited mutex",{operationId:t,dataType:typeof e});try{return await this.removeSecurityLayers(e)}catch(r){return this._secureLog("error","\u274C Error processing encrypted data",{operationId:t,errorType:r.constructor.name}),e}},2e3)}notifySecurityUpdate(){try{this._secureLog("debug","\u{1F512} Notifying about security level update",{isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasLastCalculation:!!this.lastSecurityCalculation}),this._dispatchAppEvent?.(new CustomEvent("security-level-updated",{detail:{timestamp:Date.now(),manager:"webrtc",webrtcManager:this,isConnected:this.isConnected(),isVerified:this.isVerified,hasKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),lastCalculation:this.lastSecurityCalculation}})),setTimeout(()=>{},100),this.lastSecurityCalculation&&this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:this.lastSecurityCalculation,webrtcManager:this,timestamp:Date.now()}}))}catch(e){this._secureLog("error","\u274C Error in notifySecurityUpdate",{error:e.message})}}handleSystemMessage(e){switch(this._secureLog("debug","\u{1F527} Handling system message:",{type:e.type}),e.type){case"heartbeat":this.handleHeartbeat(e);break;case"verification":this.handleVerificationRequest(e.data);break;case"verification_response":this.handleVerificationResponse(e.data);break;case"sas_code":this.handleSASCode(e.data);break;case"verification_confirmed":this.handleVerificationConfirmed(e.data);break;case"verification_both_confirmed":this.handleVerificationBothConfirmed(e.data);break;case"peer_disconnect":this.handlePeerDisconnectNotification(e);break;case"key_rotation_signal":this._secureLog("debug","\u{1F504} Key rotation signal received (ignored for stability)");break;case"key_rotation_ready":this._secureLog("debug","\u{1F504} Key rotation ready signal received (ignored for stability)");break;case"security_upgrade":this._secureLog("debug","\u{1F512} Security upgrade notification received:",{type:e.type});break;default:this._secureLog("debug","\u{1F527} Unknown system message type:",{type:e.type})}}enableStage2Security(){this.sessionConstraints?.hasPacketReordering&&(this.securityFeatures.hasPacketReordering=!0,this.reorderingConfig.enabled=!0),this.sessionConstraints?.hasAntiFingerprinting&&(this.securityFeatures.hasAntiFingerprinting=!0,this.antiFingerprintingConfig.enabled=!0,this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!0),this.notifySecurityUpgrade(2),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage3Security(){this._secureLog("info","\u{1F512} Enabling Stage 3 features (traffic obfuscation)"),this.sessionConstraints?.hasMessageChunking&&(this.securityFeatures.hasMessageChunking=!0,this.chunkingConfig.enabled=!0),this.sessionConstraints?.hasFakeTraffic&&(this.securityFeatures.hasFakeTraffic=!0,this.fakeTrafficConfig.enabled=!0,this.startFakeTrafficGeneration()),this.notifySecurityUpgrade(3),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}enableStage4Security(){if(this._secureLog("info","\u{1F512} Enabling Stage 4 features (maximum safety)"),this.sessionConstraints?.hasDecoyChannels&&this.isConnected()&&this.isVerified){this.securityFeatures.hasDecoyChannels=!0,this.decoyChannelConfig.enabled=!0;try{this.initializeDecoyChannels()}catch(e){this._secureLog("warn","\u26A0\uFE0F Decoy channels initialization failed:",{details:e.message}),this.securityFeatures.hasDecoyChannels=!1,this.decoyChannelConfig.enabled=!1}}this.sessionConstraints?.hasAntiFingerprinting&&(this.antiFingerprintingConfig.randomizeSizes=!0,this.antiFingerprintingConfig.maskPatterns=!0,this.antiFingerprintingConfig.useRandomHeaders=!1),this.notifySecurityUpgrade(4),setTimeout(()=>{this.calculateAndReportSecurityLevel()},500)}forceSecurityUpdate(){setTimeout(()=>{this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate()},100)}getSecurityStatus(){let e=Object.entries(this.securityFeatures).filter(([r,i])=>i===!0).map(([r])=>r);return{stage:4,securityLevel:"maximum",activeFeatures:e,totalFeatures:Object.keys(this.securityFeatures).length,activeFeaturesCount:e.length,activeFeaturesNames:e,sessionConstraints:this.sessionConstraints}}notifySecurityUpgrade(e){let t={1:"Basic Enhanced",2:"Medium Security",3:"High Security",4:"Maximum Security"},r=`\u{1F512} Security upgraded to Stage ${e}: ${t[e]}`;if((!this.securityUpgradeNotificationSent||this.lastSecurityUpgradeStage!==e)&&(this.securityUpgradeNotificationSent=!0,this.lastSecurityUpgradeStage=e,this.onMessage&&this.deliverMessageToUI(r,"system")),this.dataChannel&&this.dataChannel.readyState==="open")try{let n={type:"security_upgrade",stage:e,stageName:t[e],message:r,timestamp:Date.now()};this._secureLog("debug","\u{1F512} Sending security upgrade notification to peer:",{type:n.type,stage:n.stage}),this.dataChannel.send(JSON.stringify(n))}catch(n){this._secureLog("warn","\u26A0\uFE0F Failed to send security upgrade notification to peer:",{details:n.message})}let i=this.getSecurityStatus()}async calculateAndReportSecurityLevel(){try{if(!window.EnhancedSecureCryptoUtils)return this._secureLog("warn","\u26A0\uFE0F EnhancedSecureCryptoUtils not available for security calculation"),null;if(!this.isConnected()||!this.isVerified||!this.encryptionKey||!this.macKey)return this._secureLog("debug","\u26A0\uFE0F WebRTC not ready for security calculation",{connected:this.isConnected(),verified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey}),null;this._secureLog("debug","\u{1F50D} Calculating real security level",{managerState:"ready",hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey)});let e=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this);if(this._secureLog("info","Real security level calculated",{hasSecurityLevel:!!e.level,scoreRange:e.score>80?"high":e.score>50?"medium":"low",checksRatio:`${e.passedChecks}/${e.totalChecks}`,isRealCalculation:e.isRealData}),this.lastSecurityCalculation=e,this._dispatchAppEvent?.(new CustomEvent("real-security-calculated",{detail:{securityData:e,webrtcManager:this,timestamp:Date.now(),source:"calculateAndReportSecurityLevel"}})),e.isRealData&&this.onMessage&&(!this.securityCalculationNotificationSent||this.lastSecurityCalculationLevel!==e.level)){this.securityCalculationNotificationSent=!0,this.lastSecurityCalculationLevel=e.level;let t=`Security Level: ${e.level} (${e.score}%) - ${e.passedChecks}/${e.totalChecks} checks passed`;this.deliverMessageToUI(t,"system")}return e}catch(e){return this._secureLog("error","Failed to calculate real security level",{errorType:e.constructor.name}),null}}async autoEnableSecurityFeatures(){this._secureLog("info","Starting graduated security activation - all features enabled");let e=()=>this.isConnected()&&this.isVerified&&this.connectionAttempts===0&&this.messageQueue.length===0&&this.peerConnection?.connectionState==="connected";await this.calculateAndReportSecurityLevel(),this.notifySecurityUpgrade(1),setTimeout(async()=>{e()&&(this.enableStage2Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage3Security(),await this.calculateAndReportSecurityLevel(),setTimeout(async()=>{e()&&(this.enableStage4Security(),await this.calculateAndReportSecurityLevel())},2e4))},15e3))},1e4)}async establishConnection(){try{await this.initializeEnhancedSecurity(),this.fakeTrafficConfig.enabled&&this.startFakeTrafficGeneration(),this.decoyChannelConfig.enabled&&this.initializeDecoyChannels()}catch(e){throw this._secureLog("error","\u274C Failed to establish enhanced connection:",{errorType:e?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),e}}_clearVerificationStates(){try{this.localVerificationConfirmed=!1,this.remoteVerificationConfirmed=!1,this.bothVerificationsConfirmed=!1,this.isVerified=!1,this.verificationCode=null,this.pendingSASCode=null,this.sasValidationAttempts=0,this._verificationUiOpened=!1,this._sasLocalFingerprint=null,this._sasRemoteFingerprint=null,this.keyFingerprint=null,this.expectedDTLSFingerprint=null,this._peerDTLSFingerprint=null,this.connectionId=null,this.processedMessageIds.clear(),this.verificationNotificationSent=!1,this.verificationInitiationSent=!1}catch(e){this._secureLog("error","\u274C Error clearing verification states:",{errorType:e?.constructor?.name||"Unknown"})}}startPeriodicCleanup(){this._secureLog("info","\u{1F527} Periodic cleanup moved to unified scheduler")}async calculateSecurityLevel(){return await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(this)}shouldRotateKeys(){return!this.isConnected()||!this.isVerified?!1:Date.now()-this.lastKeyRotation>this.keyRotationInterval||this.messageCounter%100===0}async rotateKeys(){return this._withMutex("keyOperation",async e=>{if(this._secureLog("info","\u{1F504} Starting key rotation with mutex",{operationId:e}),!this.isConnected()||!this.isVerified)return this._secureLog("warn"," Key rotation aborted - connection not ready",{operationId:e,isConnected:this.isConnected(),isVerified:this.isVerified}),!1;if(this._keySystemState.isRotating)return this._secureLog("warn"," Key rotation already in progress",{operationId:e}),!1;try{this._keySystemState.isRotating=!0,this._keySystemState.lastOperation="rotation",this._keySystemState.lastOperationTime=Date.now();let t={type:"key_rotation_signal",newVersion:this.currentKeyVersion+1,timestamp:Date.now(),operationId:e};if(this.dataChannel&&this.dataChannel.readyState==="open")this.dataChannel.send(JSON.stringify(t));else throw new Error("Data channel not ready for key rotation");return this._hardWipeOldKeys(),new Promise(r=>{this.pendingRotation={newVersion:this.currentKeyVersion+1,operationId:e,resolve:r,timeout:setTimeout(()=>{this._secureLog("error"," Key rotation timeout",{operationId:e}),this._keySystemState.isRotating=!1,this.pendingRotation=null,r(!1)},1e4)}})}catch(t){return this._secureLog("error"," Key rotation failed in critical section",{operationId:e,errorType:t.constructor.name}),this._keySystemState.isRotating=!1,!1}},1e4)}cleanupOldKeys(){let e=Date.now(),t=s.LIMITS.MAX_KEY_AGE,r=0;for(let[i,n]of this.oldKeys.entries())e-n.timestamp>t&&(n.encryptionKey&&this._secureWipeMemory(n.encryptionKey,"pfs_cleanup_wipe"),n.macKey&&this._secureWipeMemory(n.macKey,"pfs_cleanup_wipe"),n.metadataKey&&this._secureWipeMemory(n.metadataKey,"pfs_cleanup_wipe"),n.encryptionKey=null,n.macKey=null,n.metadataKey=null,n.keyFingerprint=null,this.oldKeys.delete(i),r++,this._secureLog("info","\u{1F9F9} Old PFS keys hard wiped and cleaned up",{version:i,age:Math.round((e-n.timestamp)/1e3)+"s",timestamp:Date.now()}));r>0&&this._secureLog("info",`PFS cleanup completed: ${r} keys hard wiped`,{timestamp:Date.now()})}getKeysForVersion(e){let t=this.oldKeys.get(e);return t&&t.encryptionKey&&t.macKey&&t.metadataKey?{encryptionKey:t.encryptionKey,macKey:t.macKey,metadataKey:t.metadataKey}:e===this.currentKeyVersion&&this.encryptionKey&&this.macKey&&this.metadataKey?{encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey}:(window.EnhancedSecureCryptoUtils.secureLog.log("error","No valid keys found for version",{requestedVersion:e,currentVersion:this.currentKeyVersion,availableVersions:Array.from(this.oldKeys.keys())}),null)}_hasTurnServer(){return(this._config.webrtc.iceServers||[]).some(e=>(Array.isArray(e.urls)?e.urls:[e.urls]).some(r=>typeof r=="string"&&r.toLowerCase().startsWith("turn:")))}_buildPeerConnectionConfig(){let e=this._isRelayOnlyMode(),t={iceServers:this._config.webrtc.iceServers,iceCandidatePoolSize:10,bundlePolicy:"balanced"};return e&&(t.iceTransportPolicy="relay"),t}_summarizeIceServerConfig(e=[]){let t={serverCount:0,stun:0,turn:0,turns:0,hasCredentials:!1};for(let r of e||[]){t.serverCount+=1,(r?.username||r?.credential)&&(t.hasCredentials=!0);let i=Array.isArray(r?.urls)?r.urls:[r?.urls];for(let n of i){let a=String(n||"").toLowerCase();a.startsWith("stun:")&&(t.stun+=1),a.startsWith("turn:")&&(t.turn+=1),a.startsWith("turns:")&&(t.turns+=1)}}return t}_isRelayOnlyMode(){return this._config.webrtc.privacyMode==="relay-only"}_setRelayOnlyMode(e){let t=e===!0;this._config.webrtc.privacyMode=t?"relay-only":"standard",this._config.webrtc.relayOnly=t}_warnIfTurnMissing(){if(this._ipLeakWarningShown)return;this._ipLeakWarningShown=!0;let e=this._isRelayOnlyMode(),t=this._hasTurnServer(),r=null;e&&!t?r="Privacy mode is relay-only, but no TURN server is configured. Relay-only mode cannot connect until TURN is configured; STUN alone does not hide IP addresses.":!e&&!t?r="Privacy warning: relay-only mode is disabled and no TURN server is configured. Direct WebRTC connections may expose host or server-reflexive IP addresses; STUN alone does not provide IP protection.":e||(r="Privacy warning: relay-only mode is disabled. Direct WebRTC connectivity may expose host or server-reflexive IP addresses even when TURN is available."),r&&this.deliverMessageToUI(r,"system")}createPeerConnection(){this._sessionAlive=!0;let e=this._buildPeerConnectionConfig();this._warnIfTurnMissing(),console.info("[SecureBit ICE] peer connection config",this._summarizeIceServerConfig(e.iceServers)),this.peerConnection=new RTCPeerConnection(e),this._callAudioSender=null,this._callVideoSender=null,this.peerConnection.onconnectionstatechange=()=>{let t=this.peerConnection.connectionState;console.info("[SecureBit ICE] connection state changed",{connectionState:t,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState}),t==="connected"&&!this.isVerified?this._notifyVerificationReadyIfPossible():t==="connected"&&this.isVerified?this._onPathRecovered()||this.onStatusChange("connected"):t==="disconnected"?this.intentionalDisconnect?(this.onStatusChange("disconnected"),setTimeout(()=>this.disconnect(),100)):this.isVerified?this._onPathDegraded("ice_disconnected"):console.warn(`[SecureBit ICE] State is ${t} but not verified yet. Keeping session open for manual exchange.`):t==="closed"?(this._resetReconnectState(),this.onStatusChange("disconnected"),this._clearVerificationStates(),this.intentionalDisconnect&&setTimeout(()=>this.disconnect(),100)):t==="failed"?(this._collectIceFailureDiagnostics().then(r=>{console.warn("[SecureBit ICE] failure diagnostics",r),this._noteIceFailureDiagnostics(r)}),this.isVerified?this._onPathLost("ice_failed"):console.warn("[SecureBit ICE] State is failed but not verified yet. Keeping session open for manual exchange.")):this.isReconnecting()&&(t==="connecting"||t==="new")||this.onStatusChange(t)},this.peerConnection.oniceconnectionstatechange=()=>{console.info("[SecureBit ICE] ICE connection state changed",{connectionState:this.peerConnection.connectionState,iceConnectionState:this.peerConnection.iceConnectionState,iceGatheringState:this.peerConnection.iceGatheringState})},this.peerConnection.onicecandidateerror=t=>{console.warn("[SecureBit ICE] ICE candidate error",{url:t.url,errorCode:t.errorCode,errorText:t.errorText})},this.peerConnection.ontrack=t=>{try{this._refreshRemoteStream()}catch(r){this._secureLog("warn","\u26A0\uFE0F ontrack handling failed",{errorType:r?.constructor?.name})}},this.peerConnection.ondatachannel=t=>{t.channel.label==="securechat"?(this.dataChannel=t.channel,this.setupDataChannel(t.channel)):t.channel.label==="heartbeat"&&(this.heartbeatChannel=t.channel)}}setupDataChannel(e){this.dataChannel=e;let t=!1,r=async()=>{if(!t){t=!0;try{this.dataChannel&&typeof this.dataChannel.bufferedAmountLowThreshold=="number"&&(this.dataChannel.bufferedAmountLowThreshold=1024*1024)}catch{}if(this._handshakeMode==="sbq2")try{await this._runSbq2KeyExchange()}catch(i){this._secureLog("error","SBQ2 key exchange failed to start",{errorType:i?.constructor?.name||"Unknown"}),this._sbq2Abort("start_failed","The secure handshake could not be started. Please try connecting again.");return}try{await this.establishConnection(),this.initializeFileTransfer()}catch(i){this._secureLog("error","Error in establishConnection:",{errorType:i?.constructor?.name||"Unknown"})}if(this.pendingSASCode&&this.dataChannel&&this.dataChannel.readyState==="open")try{let i={type:"sas_code",data:{code:this.pendingSASCode,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(i)),this.pendingSASCode=null}catch{}else this.pendingSASCode;this.isVerified?(this.onStatusChange("connected"),this.processMessageQueue(),setTimeout(async()=>{await this.calculateAndReportSecurityLevel(),this.autoEnableSecurityFeatures(),this.notifySecurityUpdate()},500)):(this._notifyVerificationReadyIfPossible(),this.initiateVerification()),this.startHeartbeat()}};this.dataChannel.onopen=r,this.dataChannel.readyState==="open"&&Promise.resolve().then(()=>r()).catch(i=>{this._secureLog("error","Deferred data channel open handling failed",{errorType:i?.constructor?.name||"Unknown"})}),this.dataChannel.onclose=()=>{this._resetReconnectState?.(),this._teardownRecoveryLifecycleListeners?.(),this.intentionalDisconnect?(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed","system"))):(this.onStatusChange("disconnected"),this._clearVerificationStates(),this.connectionClosedNotificationSent||(this.connectionClosedNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Enhanced secure connection closed. Check connection status.","system"))),this._wipeEphemeralKeys(),this.stopHeartbeat(),this.isVerified=!1},this.dataChannel.onmessage=async i=>{try{if(this._noteInboundActivity?.(),typeof i.data=="string")try{let n=JSON.parse(i.data),a=["file_transfer_start","file_transfer_response","file_chunk","chunk_confirmation","file_transfer_complete","file_transfer_error"];if(n.type&&a.includes(n.type)){if(!this._enforceVerificationGate("file_message_receive",!1)){this._secureLog("error","Dropped file message received before verification",{messageType:n.type});return}if(!this.fileTransferSystem)try{if(this.isVerified&&this.dataChannel&&this.dataChannel.readyState==="open"){this.initializeFileTransfer();let o=0,c=30;for(;!this.fileTransferSystem&&osetTimeout(d,100)),o++}}catch(o){this._secureLog("error","Failed to initialize file transfer system for receiver:",{errorType:o?.constructor?.name||"Unknown"})}if(this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}this._secureLog("warn","\u26A0\uFE0F File transfer system not ready, attempting lazy init...");try{if(await this._ensureFileTransferReady(),this.fileTransferSystem){await this.fileTransferSystem.handleFileMessage(n);return}}catch(o){this._secureLog("error","Lazy init of file transfer failed:",{errorType:o?.message||o?.constructor?.name||"Unknown"})}this._secureLog("error","No file transfer system available for:",{errorType:n.type?.constructor?.name||"Unknown"});return}if(n.type&&s.POST_VERIFICATION_CONTROL_TYPES.has(n.type)){if(!this._enforceVerificationGate("control_frame_receive",!1)){this._secureLog("error","Dropped control frame received before verification",{messageType:n.type});return}let o=s.MESSAGE_TYPES;if(n.type===o.MESSAGE_DELETE){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelete?.(c.slice(0,64))}catch{}return}if(n.type===o.MESSAGE_RECEIPT){let c=n?.data?.messageId??n?.messageId;if(typeof c=="string"&&c)try{this.onMessageDelivered?.(c.slice(0,64))}catch{}return}if([o.CALL_OFFER,o.CALL_ANSWER,o.CALL_ICE,o.CALL_DECLINE,o.CALL_END].includes(n.type)){try{await this._handleCallSignal(n.type,n.data||{})}catch{}return}if([o.ICE_RESTART_OFFER,o.ICE_RESTART_ANSWER,o.ICE_RESTART_REQUEST].includes(n.type)){try{await this._handleIceRestartSignal(n.type,n.data||{})}catch(c){this._secureLog("error","\u274C ICE restart signal handling failed",{errorType:c?.constructor?.name})}return}return}if(n.type===s.MESSAGE_TYPES.KEY_BLOB||n.type===s.MESSAGE_TYPES.KEY_PROOF){await this._sbq2HandleHandshakeFrame(n);return}if(n.type&&["heartbeat","verification","verification_response","verification_confirmed","verification_both_confirmed","sas_code","peer_disconnect","security_upgrade"].includes(n.type)){this.handleSystemMessage(n);return}if(n.type===s.MESSAGE_TYPES.RATCHET_MESSAGE){await this._processRatchetMessage(n);return}if(n.type==="enhanced_message"&&n.data){await this._processEnhancedMessageWithoutMutex(n);return}this._secureLog("error","Rejected unencrypted frame on the chat channel",{messageType:typeof n.type=="string"?n.type.slice(0,32):typeof n.type});return}catch{this._secureLog("error","Rejected malformed (non-JSON) frame on the chat channel",{dataLength:typeof i.data=="string"?i.data.length:0});return}else i.data instanceof ArrayBuffer&&await this._processBinaryDataWithoutMutex(i.data)}catch(n){this._secureLog("error","Failed to process message in onmessage:",{errorType:n?.constructor?.name||"Unknown"})}}}async _processBinaryDataWithoutMutex(e){try{if(!this._checkInboundRateLimit("binary_message"))return;let t=e;if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey&&t instanceof ArrayBuffer&&t.byteLength>12)try{t=await this.removeNestedEncryption(t)}catch{this._secureLog("warn","Nested decryption failed, continuing with original data")}if(this.securityFeatures.hasPacketPadding&&t instanceof ArrayBuffer)try{t=this.removePacketPadding(t)}catch{this._secureLog("warn","Packet padding removal failed, continuing with original data")}if(this.securityFeatures.hasAntiFingerprinting&&t instanceof ArrayBuffer)try{t=this.removeAntiFingerprinting(t)}catch{this._secureLog("warn","Anti-fingerprinting removal failed, continuing with original data")}if(t instanceof ArrayBuffer){let r=new TextDecoder().decode(t);try{let i=JSON.parse(r);if(i.type==="fake"||i.isFakeTraffic===!0)return}catch{}this._secureLog("error","Rejected unauthenticated binary frame on the chat channel",{byteLength:e?.byteLength||0})}}catch(t){this._secureLog("error","Error processing binary data:",{errorType:t?.constructor?.name||"Unknown"})}}async _processRatchetMessage(e){try{if(!this._checkInboundRateLimit("ratchet_message"))return;if(!this.isRatchetActive()){this._secureLog("error","Received a ratchet message but no ratchet is active");return}if(typeof e?.h!="string"||typeof e?.c!="string"){this._secureLog("error","Malformed ratchet message frame");return}let t=await this._ratchet.decrypt(e.h,e.c);try{let r=JSON.parse(t);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.deliverMessageToUI(t,"received")}catch(t){this._secureLog("error","Failed to decrypt ratchet message",{errorType:t?.constructor?.name||"Unknown"})}}async _processEnhancedMessageWithoutMutex(e){try{if(!this._checkInboundRateLimit("enhanced_message"))return;if(!this.encryptionKey||!this.macKey||!this.metadataKey){this._secureLog("error","Missing encryption keys for enhanced message");return}let t=await window.EnhancedSecureCryptoUtils.decryptMessage(e.data,this.encryptionKey,this.macKey,this.metadataKey);if(!this._validateIncomingSequenceNumber(t?.sequenceNumber,"enhanced_message")){this._secureLog("error","Rejected chat message failing anti-replay validation",{messageId:t?.messageId?"present":"absent"});return}if(t&&t.message){try{let r=JSON.parse(t.message);if(r.type==="fake"||r.isFakeTraffic===!0)return;if(r&&r.type==="message"&&typeof r.data=="string"){this.onMessage&&this.deliverMessageToUI(r.data,"received",r.meta);return}}catch{}this.onMessage&&this.deliverMessageToUI(t.message,"received")}else this._secureLog("warn","No message content in decrypted result")}catch(t){this._secureLog("error","Error processing enhanced message:",{errorType:t?.constructor?.name||"Unknown"})}}_generateOperationId(){return`op_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}async _acquireMutex(e,t,r=5e3){let i=`_${e}Mutex`,n=this[i];if(!n)throw this._secureLog("error",`Unknown mutex: ${e}`,{mutexPropertyName:i,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex: ${e}. Available: ${this._getAvailableMutexes().join(", ")}`);if(!t||typeof t!="string")throw new Error("Invalid operation ID for mutex acquisition");return new Promise((a,o)=>{(()=>{if(n.lockId===t){this._secureLog("warn",`Mutex '${e}' already locked by same operation`,{operationId:t}),a();return}if(!n.locked)n.locked=!0,n.lockId=t,n.lockTime=Date.now(),this._secureLog("debug",`Mutex '${e}' acquired atomically`,{operationId:t,lockTime:n.lockTime}),n.lockTimeout=setTimeout(()=>{this._handleMutexTimeout(e,t,r)},r),a();else{let d={resolve:a,reject:o,operationId:t,timestamp:Date.now(),timeout:setTimeout(()=>{let u=n.queue.findIndex(h=>h.operationId===t);u!==-1&&(n.queue.splice(u,1),o(new Error(`Mutex acquisition timeout for '${e}'`)))},r)};n.queue.push(d),this._secureLog("debug",`Operation queued for mutex '${e}'`,{operationId:t,queueLength:n.queue.length,currentLockId:n.lockId})}})()})}_releaseMutex(e,t){if(!e||typeof e!="string")throw new Error("Invalid mutex name provided for release");if(!t||typeof t!="string")throw new Error("Invalid operation ID provided for mutex release");let r=`_${e}Mutex`,i=this[r];if(!i)throw this._secureLog("error",`Unknown mutex for release: ${e}`,{mutexPropertyName:r,availableMutexes:this._getAvailableMutexes(),operationId:t}),new Error(`Unknown mutex for release: ${e}`);if(i.lockId!==t)throw this._secureLog("error","CRITICAL: Invalid mutex release attempt - potential race condition",{mutexName:e,expectedLockId:i.lockId,providedOperationId:t,mutexState:{locked:i.locked,lockTime:i.lockTime,queueLength:i.queue.length}}),new Error(`Invalid mutex release attempt for '${e}': expected '${i.lockId}', got '${t}'`);if(!i.locked)throw this._secureLog("error","CRITICAL: Attempting to release unlocked mutex",{mutexName:e,operationId:t,mutexState:{locked:i.locked,lockId:i.lockId,lockTime:i.lockTime}}),new Error(`Attempting to release unlocked mutex: ${e}`);try{i.lockTimeout&&(clearTimeout(i.lockTimeout),i.lockTimeout=null);let n=i.lockTime?Date.now()-i.lockTime:0;i.locked=!1,i.lockId=null,i.lockTime=null,this._secureLog("debug",`Mutex released successfully: ${e}`,{operationId:t,lockDuration:n,queueLength:i.queue.length}),this._processNextInQueue(e)}catch(n){throw this._secureLog("error","Error during mutex release queue processing",{mutexName:e,operationId:t,errorType:n.constructor.name,errorMessage:n.message}),i.locked=!1,i.lockId=null,i.lockTime=null,i.lockTimeout=null,n}}_processNextInQueue(e){let t=this[`_${e}Mutex`];if(!t){this._secureLog("error",`Mutex not found for queue processing: ${e}`);return}if(t.queue.length===0)return;if(t.locked){this._secureLog("warn",`Mutex '${e}' is still locked, skipping queue processing`,{lockId:t.lockId,queueLength:t.queue.length});return}let r=t.queue.shift();if(!r){this._secureLog("warn",`Empty queue item for mutex '${e}'`);return}if(!r.operationId||!r.resolve||!r.reject){this._secureLog("error",`Invalid queue item structure for mutex '${e}'`,{hasOperationId:!!r.operationId,hasResolve:!!r.resolve,hasReject:!!r.reject});return}try{r.timeout&&clearTimeout(r.timeout),this._secureLog("debug",`Processing next operation in queue for mutex '${e}'`,{operationId:r.operationId,queueRemaining:t.queue.length,timestamp:Date.now()}),setTimeout(async()=>{try{await this._acquireMutex(e,r.operationId,5e3),this._secureLog("debug",`Queued operation acquired mutex '${e}'`,{operationId:r.operationId,acquisitionTime:Date.now()}),r.resolve()}catch(i){this._secureLog("error",`Queued operation failed to acquire mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message,timestamp:Date.now()}),r.reject(new Error(`Queue processing failed for '${e}': ${i.message}`)),setTimeout(()=>{this._processNextInQueue(e)},50)}},10)}catch(i){this._secureLog("error",`Critical error during queue processing for mutex '${e}'`,{operationId:r.operationId,errorType:i.constructor.name,errorMessage:i.message});try{r.reject(new Error(`Queue processing critical error: ${i.message}`))}catch(n){this._secureLog("error","Failed to reject queue item",{originalError:i.message,rejectError:n.message})}setTimeout(()=>{this._processNextInQueue(e)},100)}}_getAvailableMutexes(){let e=[],t=Object.getOwnPropertyNames(this);for(let r of t)if(r.endsWith("Mutex")&&r.startsWith("_")){let i=r.slice(1,-5);e.push(i)}return e}async _withMutex(e,t,r=5e3){let i=this._generateOperationId();if(!this._validateMutexSystem())throw this._secureLog("error","Mutex system not properly initialized",{operationId:i,mutexName:e}),new Error("Mutex system not properly initialized. Call _initializeMutexSystem() first.");let n=this[`_${e}Mutex`];if(!n)throw new Error(`Mutex '${e}' not found`);let a=!1;try{await this._acquireMutex(e,i,r),a=!0;let o=`${e}Operations`;this._operationCounters&&this._operationCounters[o]!==void 0&&this._operationCounters[o]++;let c=await t(i);return c===void 0&&t.name!=="cleanup"&&this._secureLog("warn","Mutex operation returned undefined result",{operationId:i,mutexName:e,operationName:t.name}),c}catch(o){throw this._secureLog("error","Error in mutex operation",{operationId:i,mutexName:e,errorType:o.constructor.name,errorMessage:o.message,mutexAcquired:a,mutexState:n?{locked:n.locked,lockId:n.lockId,queueLength:n.queue.length}:"null"}),e==="keyOperation"&&this._handleKeyOperationError(o,i),(o.message.includes("timeout")||o.message.includes("race condition"))&&this._emergencyUnlockAllMutexes("errorHandler"),o}finally{if(a)try{await this._releaseMutex(e,i),n.locked&&n.lockId===i&&(this._secureLog("error","Mutex release verification failed",{operationId:i,mutexName:e}),n.locked=!1,n.lockId=null,n.lockTimeout=null)}catch(o){this._secureLog("error","Error releasing mutex in finally block",{operationId:i,mutexName:e,releaseErrorType:o.constructor.name,releaseErrorMessage:o.message}),n.locked=!1,n.lockId=null,n.lockTimeout=null}}}_validateMutexSystem(){let e=["keyOperation","cryptoOperation","connectionOperation"];for(let t of e){let r=`_${t}Mutex`,i=this[r];if(!i||typeof i!="object")return this._secureLog("error",`Missing or invalid mutex: ${t}`,{mutexPropertyName:r,mutexType:typeof i}),!1;let n=["locked","queue","lockId","lockTimeout"];for(let a of n)if(!(a in i))return this._secureLog("error",`Mutex ${t} missing property: ${a}`),!1}return!0}_emergencyRecoverMutexSystem(){this._secureLog("warn","Emergency mutex system recovery initiated");try{if(this._emergencyUnlockAllMutexes("emergencyRecovery"),this._initializeMutexSystem(),!this._validateMutexSystem())throw new Error("Mutex system validation failed after recovery");return this._secureLog("info","Mutex system recovered successfully with validation"),!0}catch(e){this._secureLog("error","Failed to recover mutex system",{errorType:e.constructor.name,errorMessage:e.message});try{return this._initializeMutexSystem(),this._secureLog("warn","Forced mutex system re-initialization completed"),!0}catch(t){return this._secureLog("error","CRITICAL: Forced re-initialization also failed",{originalError:e.message,reinitError:t.message}),!1}}}async _generateEncryptionKeys(){return this._withMutex("keyOperation",async e=>{this._secureLog("info","Generating encryption keys with atomic mutex",{operationId:e});let t=this._keySystemState;if(t.isInitializing){this._secureLog("warn","Key generation already in progress, waiting for completion",{operationId:e,lastOperation:t.lastOperation,lastOperationTime:t.lastOperationTime});let r=0,i=50;for(;t.isInitializing&&rsetTimeout(n,100)),r++;if(t.isInitializing)throw new Error("Key generation timeout - operation still in progress after 5 seconds")}try{t.isInitializing=!0,t.lastOperation="generation",t.lastOperationTime=Date.now(),t.operationId=e,this._secureLog("debug","Atomic key generation state set",{operationId:e,timestamp:t.lastOperationTime});let r=null,i=null;try{if(r=await this._generateEphemeralECDHKeys(),!r||!r.privateKey||!r.publicKey)throw new Error("Ephemeral ECDH key pair validation failed");if(!this._validateKeyPairConstantTime(r))throw new Error("Ephemeral ECDH keys are not valid CryptoKey instances");this._secureLog("debug","Ephemeral ECDH keys generated and validated for PFS",{operationId:e,privateKeyType:r.privateKey.algorithm?.name,publicKeyType:r.publicKey.algorithm?.name,isEphemeral:!0})}catch(n){this._secureLog("error","Ephemeral ECDH key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ephemeral_ecdh_key_generation")}try{if(i=await window.EnhancedSecureCryptoUtils.generateECDSAKeyPair(),!i||!i.privateKey||!i.publicKey)throw new Error("ECDSA key pair validation failed");if(!this._validateKeyPairConstantTime(i))throw new Error("ECDSA keys are not valid CryptoKey instances");this._secureLog("debug","ECDSA keys generated and validated",{operationId:e,privateKeyType:i.privateKey.algorithm?.name,publicKeyType:i.publicKey.algorithm?.name})}catch(n){this._secureLog("error","ECDSA key generation failed",{operationId:e,errorType:n.constructor.name}),this._throwSecureError(n,"ecdsa_key_generation")}if(!r||!i)throw new Error("One or both key pairs failed to generate");return this._enableSecurityFeaturesAfterKeyGeneration(r,i),this._secureLog("info","Encryption keys generated successfully with atomic protection",{operationId:e,hasECDHKeys:!!(r?.privateKey&&r?.publicKey),hasECDSAKeys:!!(i?.privateKey&&i?.publicKey),generationTime:Date.now()-t.lastOperationTime}),{ecdhKeyPair:r,ecdsaKeyPair:i}}catch(r){throw this._secureLog("error","Key generation failed, resetting state",{operationId:e,errorType:r.constructor.name}),r}finally{t.isInitializing=!1,t.operationId=null,this._secureLog("debug","Key generation state reset",{operationId:e})}})}_enableSecurityFeaturesAfterKeyGeneration(e,t){try{e&&e.privateKey&&e.publicKey&&(this.securityFeatures.hasEncryption=!0,this.securityFeatures.hasECDH=!0,this._secureLog("info","ECDH encryption features enabled")),t&&t.privateKey&&t.publicKey&&(this.securityFeatures.hasECDSA=!0,this._secureLog("info","ECDSA signature features enabled")),this.securityFeatures.hasEncryption&&(this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasNonExtractableKeys=!0,this._secureLog("info","Additional encryption-dependent features enabled")),e&&this.ephemeralKeyPairs.size>0&&(this.securityFeatures.hasPFS=!0,this._secureLog("info","Perfect Forward Secrecy enabled with ephemeral keys")),this._secureLog("info","Security features updated after key generation",{hasEncryption:this.securityFeatures.hasEncryption,hasECDH:this.securityFeatures.hasECDH,hasECDSA:this.securityFeatures.hasECDSA,hasMetadataProtection:this.securityFeatures.hasMetadataProtection,hasEnhancedReplayProtection:this.securityFeatures.hasEnhancedReplayProtection,hasNonExtractableKeys:this.securityFeatures.hasNonExtractableKeys,hasPFS:this.securityFeatures.hasPFS})}catch(r){this._secureLog("error","Failed to enable security features after key generation",{errorType:r.constructor.name,errorMessage:r.message})}}_emergencyUnlockAllMutexes(e="unknown"){let t=["keyOperation","cryptoOperation","connectionOperation","emergencyRecovery","systemShutdown","errorHandler"];if(!t.includes(e))throw this._secureLog("error","UNAUTHORIZED emergency mutex unlock attempt",{callerContext:e,authorizedCallers:t,timestamp:Date.now()}),new Error(`Unauthorized emergency mutex unlock attempt by: ${e}`);let r=["keyOperation","cryptoOperation","connectionOperation"];this._secureLog("error","EMERGENCY: Unlocking all mutexes with authorization and state cleanup",{callerContext:e,timestamp:Date.now()});let i=0,n=0;if(r.forEach(a=>{let o=this[`_${a}Mutex`];if(o)try{o.lockTimeout&&clearTimeout(o.lockTimeout);let c={locked:o.locked,lockId:o.lockId,lockTime:o.lockTime,queueLength:o.queue.length};o.locked=!1,o.lockId=null,o.lockTimeout=null,o.lockTime=null;let d=0;o.queue.forEach(u=>{try{u.reject&&typeof u.reject=="function"&&(u.reject(new Error(`Emergency mutex unlock for ${a} by ${e}`)),d++)}catch(h){this._secureLog("warn","Failed to reject queue item during emergency unlock",{mutexName:a,errorType:h.constructor.name})}}),o.queue=[],i++,this._secureLog("debug",`Emergency unlocked mutex: ${a}`,{previousState:c,queueRejectCount:d,callerContext:e})}catch(c){n++,this._secureLog("error",`Error during emergency unlock of mutex: ${a}`,{errorType:c.constructor.name,errorMessage:c.message,callerContext:e})}}),this._keySystemState)try{let a={...this._keySystemState};this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null,this._keySystemState.concurrentOperations=0,this._secureLog("debug","Emergency reset key system state",{previousState:a,callerContext:e})}catch(a){this._secureLog("error","Error resetting key system state during emergency unlock",{errorType:a.constructor.name,errorMessage:a.message,callerContext:e})}this._secureLog("info","Emergency mutex unlock completed",{callerContext:e,unlockedCount:i,errorCount:n,totalMutexes:r.length,timestamp:Date.now()}),setTimeout(()=>{this._validateMutexSystemAfterEmergencyUnlock()},100)}_handleKeyOperationError(e,t){this._secureLog("error","Key operation error detected, initiating recovery",{operationId:t,errorType:e.constructor.name,errorMessage:e.message}),this._keySystemState&&(this._keySystemState.isInitializing=!1,this._keySystemState.isRotating=!1,this._keySystemState.isDestroying=!1,this._keySystemState.operationId=null),this.ecdhKeyPair=null,this.ecdsaKeyPair=null,this.encryptionKey=null,this.macKey=null,this.metadataKey=null,(e.message.includes("timeout")||e.message.includes("race condition"))&&(this._secureLog("warn","Race condition or timeout detected, triggering emergency recovery"),this._emergencyRecoverMutexSystem())}_generateSecureIV(e=12,t="general"){if(this._ivTrackingSystem.emergencyMode)throw this._secureLog("error","CRITICAL: IV generation blocked - emergency mode active due to IV reuse"),new Error("IV generation blocked - emergency mode active");let r=0,i=100;for(;ro.toString(16).padStart(2,"0")).join("");if(this._ivTrackingSystem.usedIVs.has(a)){if(this._ivTrackingSystem.collisionCount++,this._secureLog("error","CRITICAL: IV reuse detected!",{context:t,attempt:r,collisionCount:this._ivTrackingSystem.collisionCount,ivString:a.substring(0,16)+"..."}),this._ivTrackingSystem.collisionCount>5)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to excessive IV reuse"),new Error("Emergency mode: Excessive IV reuse detected");continue}if(!this._validateIVEntropy(n)){if(this._ivTrackingSystem.entropyValidation.entropyFailures++,this._secureLog("warn","Low entropy IV detected",{context:t,attempt:r,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures}),this._ivTrackingSystem.entropyValidation.entropyFailures>10)throw this._ivTrackingSystem.emergencyMode=!0,this._secureLog("error","CRITICAL: Emergency mode activated due to low entropy IVs"),new Error("Emergency mode: Low entropy IVs detected");continue}return this._ivTrackingSystem.usedIVs.add(a),this._ivTrackingSystem.ivHistory.set(a,{timestamp:Date.now(),context:t,attempt:r}),this.sessionId&&(this._ivTrackingSystem.sessionIVs.has(this.sessionId)||this._ivTrackingSystem.sessionIVs.set(this.sessionId,new Set),this._ivTrackingSystem.sessionIVs.get(this.sessionId).add(a)),this._validateRNGQuality(),this._secureLog("debug","Secure IV generated",{context:t,attempt:r,ivSize:e,totalIVs:this._ivTrackingSystem.usedIVs.size}),n}throw this._secureLog("error",`Failed to generate unique IV after ${i} attempts`,{context:t,totalIVs:this._ivTrackingSystem.usedIVs.size}),new Error(`Failed to generate unique IV after ${i} attempts`)}_validateIVEntropy(e){this._ivTrackingSystem.entropyValidation.entropyTests++;let t=new Array(256).fill(0);for(let S=0;S0){let g=t[S]/n;i-=g*Math.log2(g)}r.shannon=i;let o=Math.max(...t)/n;r.min=-Math.log2(o);let c=0;for(let S=0;S<256;S++)if(t[S]>0){let g=t[S]/n;c+=g*g}r.collision=-Math.log2(c);let d=Array.from(e).map(S=>String.fromCharCode(S)).join(""),u=this._estimateCompressedLength(d);r.compression=(1-u/n)*8,r.quantum=this._calculateQuantumResistantEntropy(e);let h=this._detectAdvancedSuspiciousPatterns(e),m=this._ivTrackingSystem.entropyValidation.minEntropy,p=r.shannon>=m&&r.min>=m*.8&&r.collision>=m*.9&&r.compression>=m*.7&&r.quantum>=m*.6&&!h;return p||this._secureLog("warn","Enhanced IV entropy validation failed",{shannon:r.shannon.toFixed(2),min:r.min.toFixed(2),collision:r.collision.toFixed(2),compression:r.compression.toFixed(2),quantum:r.quantum.toFixed(2),minThreshold:m,hasSuspiciousPatterns:h}),p}_estimateCompressedLength(e){let t=0,r=0;for(;ri&&(i=o,n=r-a)}i>=3?(t+=3,r+=i):(t+=1,r+=1)}return t}_calculateQuantumResistantEntropy(e){let t=0;this._detectQuantumVulnerablePatterns(e)&&(t-=2);let i=this._analyzeBitDistribution(e);t+=i.score;let n=this._detectPeriodicity(e);return t-=n*.5,Math.max(0,Math.min(8,t))}_detectQuantumVulnerablePatterns(e){let t=[[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,1,0,1,0,1,0,1],[1,0,1,0,1,0,1,0]];for(let r of t)for(let i=0;i<=e.length-r.length;i++){let n=!0;for(let a=0;a>>0).toString(2).split("1").length-1;let i=(r-t)/r,n=t/r,a=Math.abs(.5-n);return{score:Math.max(0,8-a*16),zeroRatio:i,oneRatio:n,deviation:a}}_detectPeriodicity(e){if(e.length<16)return 0;let t=0;for(let r=2;r<=e.length/2;r++){let i=0,n=0;for(let a=0;a0){let a=i/n;t=Math.max(t,a)}}return t}_detectAdvancedSuspiciousPatterns(e){let t=[[0,1,2,3,4,5,6,7],[255,254,253,252,251,250,249,248],[0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255],[0,255,0,255,0,255,0,255],[255,0,255,0,255,0,255,0]];for(let n of t)for(let a=0;a<=e.length-n.length;a++){let o=!0;for(let c=0;cn<3).length>e.length*.3}_calculateLocalEntropy(e){let r=[];for(let i=0;i<=e.length-8;i++){let n=e.slice(i,i+8),a={};for(let c of n)a[c]=(a[c]||0)+1;let o=0;for(let c of Object.values(a)){let d=c/8;o-=d*Math.log2(d)}r.push(o)}return r}_detectSuspiciousIVPatterns(e){let t=e.every(n=>n===0),r=e.every(n=>n===255);if(t||r)return!0;let i=0;for(let n=1;n=3)return!0;for(let n=2;n<=Math.floor(e.length/2);n++)for(let a=0;a<=e.length-n*2;a++){let o=e.slice(a,a+n),c=e.slice(a+n,a+n*2);if(o.every((d,u)=>d===c[u]))return!0}return!1}async _cleanupOldIVs(){let e=Date.now(),t=18e5,r=0,i=[];if(this._ivTrackingSystem.ivHistory.size>this._ivTrackingSystem.maxIVHistorySize){let n=Array.from(this._ivTrackingSystem.ivHistory.entries()),a=n.slice(0,n.length-this._ivTrackingSystem.maxIVHistorySize);for(let[o]of a)i.push(o),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0)}for(let[n,a]of this._ivTrackingSystem.ivHistory.entries())e-a.timestamp>t&&(i.push(n),r++,i.length>=100&&(this._processCleanupBatch(i),i.length=0));i.length>0&&this._processCleanupBatch(i);for(let[n,a]of this._ivTrackingSystem.sessionIVs.entries())if(a.size>this._ivTrackingSystem.maxSessionIVs){let o=Array.from(a),c=o.slice(0,o.length-this._ivTrackingSystem.maxSessionIVs);for(let d of c)a.delete(d),this._ivTrackingSystem.usedIVs.delete(d),this._ivTrackingSystem.ivHistory.delete(d),r++}r>50&&await this._performNaturalCleanup(),r>0&&this._secureLog("debug",`Enhanced cleanup: ${r} old IVs removed`,{cleanedCount:r,remainingIVs:this._ivTrackingSystem.usedIVs.size,remainingHistory:this._ivTrackingSystem.ivHistory.size,memoryPressure:this._calculateMemoryPressure()})}_processCleanupBatch(e){for(let t of e)this._ivTrackingSystem.usedIVs.delete(t),this._ivTrackingSystem.ivHistory.delete(t)}_calculateMemoryPressure(){let e=this._ivTrackingSystem.usedIVs.size,t=this._resourceLimits.maxIVHistory;return Math.min(100,Math.floor(e/t*100))}_getIVTrackingStats(){return{totalIVs:this._ivTrackingSystem.usedIVs.size,collisionCount:this._ivTrackingSystem.collisionCount,entropyTests:this._ivTrackingSystem.entropyValidation.entropyTests,entropyFailures:this._ivTrackingSystem.entropyValidation.entropyFailures,rngTests:this._ivTrackingSystem.rngValidation.testsPerformed,weakRngDetected:this._ivTrackingSystem.rngValidation.weakRngDetected,emergencyMode:this._ivTrackingSystem.emergencyMode,sessionCount:this._ivTrackingSystem.sessionIVs.size,lastCleanup:this._lastIVCleanupTime||0}}_resetIVTrackingSystem(){this._secureLog("warn","Resetting IV tracking system"),this._ivTrackingSystem.usedIVs.clear(),this._ivTrackingSystem.ivHistory.clear(),this._ivTrackingSystem.sessionIVs.clear(),this._ivTrackingSystem.collisionCount=0,this._ivTrackingSystem.entropyValidation.entropyTests=0,this._ivTrackingSystem.entropyValidation.entropyFailures=0,this._ivTrackingSystem.rngValidation.testsPerformed=0,this._ivTrackingSystem.rngValidation.weakRngDetected=!1,this._ivTrackingSystem.emergencyMode=!1,this._secureLog("info","IV tracking system reset completed")}_validateRNGQuality(){let e=Date.now();if(this._ivTrackingSystem.rngValidation.testsPerformed%1e3===0)try{let t=[];for(let n=0;n<100;n++)t.push(crypto.getRandomValues(new Uint8Array(12)));let r=t.map(n=>Array.from(n).map(a=>a.toString(16).padStart(2,"0")).join("")),i=new Set(r);i.size<95&&(this._ivTrackingSystem.rngValidation.weakRngDetected=!0,this._secureLog("error","CRITICAL: Weak RNG detected in validation test",{uniqueIVs:i.size,totalTests:t.length})),this._ivTrackingSystem.rngValidation.lastValidation=e}catch(t){this._secureLog("error","RNG validation failed",{errorType:t.constructor.name})}this._ivTrackingSystem.rngValidation.testsPerformed++}_handleMutexTimeout(e,t,r){let i=this[`_${e}Mutex`];if(!i){this._secureLog("error",`Mutex '${e}' not found during timeout handling`);return}if(i.lockId!==t){this._secureLog("warn",`Timeout for different operation ID on mutex '${e}'`,{expectedOperationId:t,actualLockId:i.lockId,locked:i.locked});return}if(!i.locked){this._secureLog("warn",`Timeout for already unlocked mutex '${e}'`,{operationId:t});return}try{let n=i.lockTime?Date.now()-i.lockTime:0;this._secureLog("warn",`Mutex '${e}' auto-released due to timeout`,{operationId:t,lockDuration:n,timeout:r,queueLength:i.queue.length}),i.locked=!1,i.lockId=null,i.lockTimeout=null,i.lockTime=null,setTimeout(()=>{try{this._processNextInQueue(e)}catch(a){this._secureLog("error",`Error processing queue after timeout for mutex '${e}'`,{errorType:a.constructor.name,errorMessage:a.message})}},10)}catch(n){this._secureLog("error",`Critical error during mutex timeout handling for '${e}'`,{operationId:t,errorType:n.constructor.name,errorMessage:n.message});try{this._emergencyUnlockAllMutexes("timeoutHandler")}catch(a){this._secureLog("error","Emergency unlock failed during timeout handling",{originalError:n.message,emergencyError:a.message})}}}_validateMutexSystemAfterEmergencyUnlock(){let e=["keyOperation","cryptoOperation","connectionOperation"],t=0;this._secureLog("info","Validating mutex system after emergency unlock"),e.forEach(r=>{let i=this[`_${r}Mutex`];if(!i){t++,this._secureLog("error",`Mutex '${r}' not found after emergency unlock`);return}i.locked&&(t++,this._secureLog("error",`Mutex '${r}' still locked after emergency unlock`,{lockId:i.lockId,lockTime:i.lockTime})),i.lockId!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has lock ID after emergency unlock`,{lockId:i.lockId})),i.lockTimeout!==null&&(t++,this._secureLog("error",`Mutex '${r}' still has timeout after emergency unlock`)),i.queue.length>0&&(t++,this._secureLog("error",`Mutex '${r}' still has queue items after emergency unlock`,{queueLength:i.queue.length}))}),this._keySystemState&&(this._keySystemState.isInitializing||this._keySystemState.isRotating||this._keySystemState.isDestroying)&&(t++,this._secureLog("error","Key system state not properly reset after emergency unlock",{isInitializing:this._keySystemState.isInitializing,isRotating:this._keySystemState.isRotating,isDestroying:this._keySystemState.isDestroying})),t===0?this._secureLog("info","Mutex system validation passed after emergency unlock"):(this._secureLog("error","Mutex system validation failed after emergency unlock",{validationErrors:t}),setTimeout(()=>{this._emergencyRecoverMutexSystem()},1e3))}_getMutexSystemDiagnostics(){let e={timestamp:Date.now(),systemValid:this._validateMutexSystem(),mutexes:{},counters:{...this._operationCounters},keySystemState:{...this._keySystemState}};return["keyOperation","cryptoOperation","connectionOperation"].forEach(r=>{let i=`_${r}Mutex`,n=this[i];n?e.mutexes[r]={locked:n.locked,lockId:n.lockId,queueLength:n.queue.length,hasTimeout:!!n.lockTimeout}:e.mutexes[r]={error:"not_found"}}),e}async createSecureOffer(){return this._withMutex("connectionOperation",async e=>{this._secureLog("info","Creating secure offer with mutex",{operationId:e,connectionAttempts:this.connectionAttempts,currentState:this.peerConnection?.connectionState||"none"});try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this.connectionAttempts=0,this.sessionSalt=window.EnhancedSecureCryptoUtils.generateSalt(),this._secureLog("debug","Session salt generated",{operationId:e,saltLength:this.sessionSalt.length,isValidSalt:Array.isArray(this.sessionSalt)&&this.sessionSalt.length===64});let t=await this._generateEncryptionKeys();if(this.ecdhKeyPair=t.ecdhKeyPair,this.ecdsaKeyPair=t.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdhKeyPair?.publicKey)throw new Error("Failed to generate valid ECDH key pair");if(!this.ecdsaKeyPair?.privateKey||!this.ecdsaKeyPair?.publicKey)throw new Error("Failed to generate valid ECDSA key pair");let r=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdhKeyPair.publicKey)),i=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(await crypto.subtle.exportKey("spki",this.ecdsaKeyPair.publicKey));if(!r||!i)throw new Error("Failed to generate key fingerprints");this._secureLog("info","Generated unique key pairs for MITM protection",{operationId:e,hasECDHFingerprint:!!r,hasECDSAFingerprint:!!i,fingerprintLength:r.length,timestamp:Date.now()});let n=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),a=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!n||typeof n!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!a||typeof a!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:e}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:e,hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.isInitiator=!0,this.onStatusChange("connecting"),this.createPeerConnection(),this.dataChannel=this.peerConnection.createDataChannel("securechat",{ordered:!0}),this.setupDataChannel(this.dataChannel),this._secureLog("debug","Data channel created",{operationId:e,channelLabel:this.dataChannel.label,channelOrdered:this.dataChannel.ordered});let o=await this.peerConnection.createOffer({offerToReceiveAudio:!1,offerToReceiveVideo:!1});await this.peerConnection.setLocalDescription(o);try{let b=this._extractDTLSFingerprintFromSDP(o.sdp);this.expectedDTLSFingerprint=b,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:b,context:"offer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${b}`,"system")}catch(b){this._secureLog("error","Failed to extract DTLS fingerprint from offer",{error:b.message})}let c=Date.now(),d=await this.waitForIceGathering(),u=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),h=u.total;if(!d&&h===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the invitation would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");if(this._secureLog(h>0?"info":"warn","ICE candidates captured for offer export",{candidateSummary:u,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),this._logIceCandidateDiagnostics("offer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-c,iceGatheringCompleted:d}),d||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the invitation. Connectivity may still fail on restrictive networks.","system"),h===0&&this.deliverMessageToUI("No ICE candidates were gathered for the invitation yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed",{operationId:e,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState}),this.verificationCode=window.EnhancedSecureCryptoUtils.generateVerificationCode(),!this.verificationCode||this.verificationCode.lengthb.toString(16).padStart(2,"0")).join(""),!this.sessionId||this.sessionId.length!==s.SIZES.SESSION_ID_LENGTH*2)throw new Error("Failed to generate valid session ID");this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(b=>b.toString(16).padStart(2,"0")).join(""),this._storePendingOfferContext();let p={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},S=Date.now(),g={t:"offer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:S,e:n,d:a,sl:this.sessionSalt,si:this.sessionId,ci:this.connectionId,vc:this.verificationCode,ac:m,slv:"MAX",dr:s.RATCHET_VERSION,kf:{e:r.substring(0,12),d:i.substring(0,12)}};try{let b=this.validateEnhancedOfferData(g)}catch(b){throw new Error(`Offer package validation error: ${b.message}`)}if(this._secureLog("info","Enhanced secure offer created successfully",{operationId:e,version:g.version,hasECDSA:!0,hasMutualAuth:!0,hasSessionId:!!g.sessionId,securityLevel:p.level,timestamp:S,capabilitiesCount:10}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"offer",timestamp:S,securityLevel:p.level,operationId:e}})),s.SBQ2_SEND_ENABLED){this._latchHandshakeMode("sbq2");let{text:b}=await this._sbq2BuildDescriptor(de.OFFER);return{t:"offer",sbq2:b}}return this._latchHandshakeMode("sb1"),g}catch(t){throw this._secureLog("error","Enhanced secure offer creation failed in critical section",{operationId:e,errorType:t.constructor.name,errorMessage:t.message,phase:this._determineErrorPhase(t),connectionAttempts:this.connectionAttempts}),this._cleanupFailedOfferCreation(),this.onStatusChange("disconnected"),t}},6e4)}_determineErrorPhase(e){let t=e.message.toLowerCase();return t.includes("rate limit")?"rate_limiting":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("fingerprint")?"fingerprinting":t.includes("export")||t.includes("signature")?"key_export":t.includes("peer connection")?"webrtc_setup":t.includes("offer")||t.includes("sdp")?"sdp_creation":t.includes("verification")?"verification_setup":t.includes("session")?"session_setup":t.includes("validation")?"package_validation":"unknown"}_cleanupFailedOfferCreation(){try{this._secureCleanupCryptographicMaterials(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during offer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed offer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during offer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}_updateSecurityFeatures(e){let t={...this.securityFeatures};try{Object.assign(this.securityFeatures,e),this._secureLog("debug","Security features updated",{updatedCount:Object.keys(e).length,totalFeatures:Object.keys(this.securityFeatures).length})}catch(r){throw this.securityFeatures=t,this._secureLog("error","Security features update failed, rolled back",{errorType:r.constructor.name}),r}}async _createSbq2Answer(e){return this._withMutex("connectionOperation",async t=>{try{if(this._resetNotificationFlags(),!this._checkRateLimit())throw new Error("Connection rate limit exceeded. Please wait before trying again.");this._latchHandshakeMode("sbq2");let r=Ur(String(e.sbq2)),i=this._sbq2AdoptRemoteDescriptor(r,de.OFFER),{sdp:n}=Kr(i);this.isInitiator=!1,this.onStatusChange("connecting");let a=await this._generateEncryptionKeys();if(this.ecdhKeyPair=a.ecdhKeyPair,this.ecdsaKeyPair=a.ecdsaKeyPair,!this.ecdhKeyPair?.privateKey||!this.ecdsaKeyPair?.privateKey)throw new Error("Failed to generate valid key pairs");this.createPeerConnection(),this._peerDTLSFingerprint=Array.from(i.fingerprint,d=>d.toString(16).padStart(2,"0").toUpperCase()).join(":"),await this.peerConnection.setRemoteDescription({type:"offer",sdp:n}),await this.peerConnection.setLocalDescription(await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})),this.expectedDTLSFingerprint=this._extractDTLSFingerprintFromSDP(this.peerConnection.localDescription.sdp),await this.waitForIceGathering();let o=async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),{text:c}=await this._sbq2BuildDescriptor(de.ANSWER,{bindingTag:await Or(o,r)});return this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:Date.now(),operationId:t}})),{t:"answer",sbq2:c}}catch(r){throw this._secureLog("error","SBQ2 answer creation failed",{operationId:t,errorType:r?.constructor?.name||"Unknown"}),this.onStatusChange("disconnected"),r}},6e4)}async createSecureAnswer(e){return e&&typeof e.sbq2=="string"?this._createSbq2Answer(e):this._withMutex("connectionOperation",async t=>{this._secureLog("info","Creating secure answer with mutex",{operationId:t,hasOfferData:!!e,offerType:e?.type,offerVersion:e?.version,offerTimestamp:e?.timestamp});try{if(this._resetNotificationFlags(),this._secureLog("debug","Starting enhanced offer validation",{operationId:t,hasOfferData:!!e,offerType:e?.type,hasECDHKey:!!e?.ecdhPublicKey,hasECDSAKey:!!e?.ecdsaPublicKey,hasSalt:!!e?.salt}),!this.validateEnhancedOfferData(e))throw new Error("Invalid connection data format - failed enhanced validation");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkConnectionRate(this.rateLimiterId))throw new Error("Connection rate limit exceeded. Please wait before trying again.");let r=e.ts||e.timestamp,i=e.v||e.version;if(!r||!i)throw new Error("Missing required security fields in offer data \u2013 possible MITM attack");let n=Date.now()-r,a=18e5;if(n>a)throw this._secureLog("error","Offer data is too old - possible replay attack",{operationId:t,offerAge:Math.round(n/1e3),maxAllowedAge:Math.round(a/1e3),timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Offer data is too old \u2013 possible replay attack"),new Error("Offer data is too old \u2013 possible replay attack");let o=i;if(o!==s.PROTOCOL_VERSION)throw this._secureLog("warn","Protocol version mismatch detected",{operationId:t,expectedVersion:s.PROTOCOL_VERSION,receivedVersion:o}),new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${o}`);if(this.sessionSalt=e.sl||e.salt,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,!Array.isArray(this.sessionSalt))throw new Error("Invalid session salt format - must be array");let c=64;if(this.sessionSalt.length!==c)throw new Error(`Invalid session salt length: expected ${c}, got ${this.sessionSalt.length}`);let d=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);this._secureLog("info","Session salt validated successfully",{operationId:t,saltLength:this.sessionSalt.length,saltFingerprint:d.substring(0,8)});let u=await this._generateEncryptionKeys();if(this.ecdhKeyPair=u.ecdhKeyPair,this.ecdsaKeyPair=u.ecdsaKeyPair,!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw this._secureLog("error","Local ECDH private key is not a CryptoKey",{operationId:t,hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a valid CryptoKey");let h;try{let R=e.d||e.ecdsaPublicKey;h=await crypto.subtle.importKey("spki",new Uint8Array(R.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"])}catch(R){this._throwSecureError(R,"ecdsa_key_import")}let m;try{let R=e.e||e.ecdhPublicKey;m=await window.EnhancedSecureCryptoUtils.importSignedPublicKey(R,h,"ECDH")}catch(R){this._secureLog("error","Failed to import signed ECDH public key",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"ecdh_key_import")}if(!(m instanceof CryptoKey))throw this._secureLog("error","Peer ECDH public key is not a CryptoKey",{operationId:t,publicKeyType:typeof m,publicKeyAlgorithm:m?.algorithm?.name}),new Error("Peer ECDH public key is not a valid CryptoKey");this.peerPublicKey=m;let p;try{this._secureLog("debug","About to call deriveSharedKeys",{operationId:t,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),p=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,m,this.sessionSalt),this._secureLog("debug","deriveSharedKeys completed successfully",{operationId:t,hasMessageKey:!!p.messageKey,hasMacKey:!!p.macKey,hasPfsKey:!!p.pfsKey,hasMetadataKey:!!p.metadataKey,hasFingerprint:!!p.fingerprint})}catch(R){this._secureLog("error","Failed to derive shared keys",{operationId:t,errorType:R.constructor.name,errorMessage:R.message,errorStack:R.stack,privateKeyType:typeof this.ecdhKeyPair.privateKey,publicKeyType:typeof m,saltLength:this.sessionSalt?.length,privateKeyAlgorithm:this.ecdhKeyPair.privateKey?.algorithm?.name,publicKeyAlgorithm:m?.algorithm?.name}),this._throwSecureError(R,"key_derivation")}if(await this._setEncryptionKeys(p.messageKey,p.macKey,p.metadataKey,p.fingerprint),await this._initializeRatchet(p,!1),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw this._secureLog("error","Invalid key types after derivation",{operationId:t,encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey}),new Error("Invalid key types after derivation");this.verificationCode=e.vc||e.verificationCode||null,this._secureLog("info","Encryption keys derived and set successfully",{operationId:t,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this._updateSecurityFeatures({hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0}),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0});let S;if(e.authChallenge)try{S=await window.EnhancedSecureCryptoUtils.createAuthProof(e.authChallenge,this.ecdsaKeyPair.privateKey,this.ecdsaKeyPair.publicKey)}catch(R){this._secureLog("error","Failed to create authentication proof",{operationId:t,errorType:R.constructor.name}),this._throwSecureError(R,"authentication_proof_creation")}else this._secureLog("warn","No auth challenge in offer - mutual auth disabled",{operationId:t});if(this.isInitiator=!1,this.onStatusChange("connecting"),this.onKeyExchange(this.keyFingerprint),this.createPeerConnection(),this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp)}catch(R){this._secureLog("warn","Could not extract peer DTLS fingerprint from offer",{error:R.message,context:"offer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");try{this._secureLog("debug","Setting remote description from offer",{operationId:t,sdpLength:e.sdp?.length||0}),await this.peerConnection.setRemoteDescription(new RTCSessionDescription({type:"offer",sdp:e.s||e.sdp})),this._logIceCandidateDiagnostics("remote offer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("offer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully",{operationId:t,signalingState:this.peerConnection.signalingState})}catch(R){this._secureLog("error","Failed to set remote description",{error:R.message,operationId:t}),this._throwSecureError(R,"webrtc_remote_description")}this._secureLog("debug","Remote description set successfully",{operationId:t,connectionState:this.peerConnection.connectionState,signalingState:this.peerConnection.signalingState});let g;try{g=await this.peerConnection.createAnswer({offerToReceiveAudio:!1,offerToReceiveVideo:!1})}catch(R){this._throwSecureError(R,"webrtc_create_answer")}try{await this.peerConnection.setLocalDescription(g)}catch(R){this._throwSecureError(R,"webrtc_local_description")}try{let R=this._extractDTLSFingerprintFromSDP(g.sdp);this.expectedDTLSFingerprint=R,this._secureLog("info","Generated DTLS fingerprint for out-of-band verification",{fingerprint:R,context:"answer_creation"}),this.deliverMessageToUI(`DTLS fingerprint ready for verification: ${R}`,"system")}catch(R){this._secureLog("error","Failed to extract DTLS fingerprint from answer",{error:R.message})}try{let R=this._extractDTLSFingerprintFromSDP(e.s||e.sdp),ue=this.expectedDTLSFingerprint,K=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(K,ue,R),this._setSASMaterialReady(ue,R)}catch(R){throw this._secureLog("error","SAS computation failed in createSecureAnswer (Answer side)",{errorType:R?.constructor?.name||"Unknown"}),new Error(`SAS computation failed: ${R.message}`)}let b=Date.now(),w=await this.waitForIceGathering(),M=this._summarizeIceCandidatesInSDP(this.peerConnection.localDescription?.sdp),F=M.total;if(!w&&F===0)throw this.deliverMessageToUI("No network candidates could be gathered, so the response would not be usable. This usually means a VPN or firewall is blocking STUN/TURN. Try turning the VPN off, switching network, or adding your own TURN server in Advanced network settings.","system"),new Error("ICE gathering produced no candidates \u2014 check VPN/firewall or configure a TURN server");this._secureLog(F>0?"info":"warn","ICE candidates captured for answer export",{candidateSummary:M,iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-b,iceGatheringCompleted:w}),this._logIceCandidateDiagnostics("answer export",this.peerConnection.localDescription?.sdp,{iceGatheringState:this.peerConnection.iceGatheringState,iceGatheringDurationMs:Date.now()-b,iceGatheringCompleted:w}),w||this.deliverMessageToUI("ICE gathering timed out before completion, but available candidates were included in the response. Connectivity may still fail on restrictive networks.","system"),F===0&&this.deliverMessageToUI("No ICE candidates were gathered for the response yet. The peer connection may fail unless network candidates become available.","system"),this._secureLog("debug","ICE gathering completed for answer",{operationId:t,iceGatheringState:this.peerConnection.iceGatheringState,connectionState:this.peerConnection.connectionState});let k=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdhKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDH"),E=await window.EnhancedSecureCryptoUtils.exportPublicKeyWithSignature(this.ecdsaKeyPair.publicKey,this.ecdsaKeyPair.privateKey,"ECDSA");if(!k||typeof k!="object")throw this._secureLog("error","CRITICAL: ECDH key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDH key export validation failed - hard abort required");if(!k.keyData||!k.signature)throw this._secureLog("error","CRITICAL: ECDH key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!k.keyData,hasSignature:!!k.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key export incomplete - hard abort required");if(!E||typeof E!="object")throw this._secureLog("error","CRITICAL: ECDSA key export failed - invalid object structure",{operationId:t}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export validation failed - hard abort required");if(!E.keyData||!E.signature)throw this._secureLog("error","CRITICAL: ECDSA key export incomplete - missing keyData or signature",{operationId:t,hasKeyData:!!E.keyData,hasSignature:!!E.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key export incomplete - hard abort required");let _={level:"MAXIMUM",score:100,color:"green",details:"All security features enabled by default",passedChecks:10,totalChecks:10,isRealData:!0},A=Date.now(),x={t:"answer",s:this.peerConnection.localDescription.sdp,v:s.PROTOCOL_VERSION,ts:A,e:k,d:E,ap:S,slv:"MAX",dr:s.RATCHET_VERSION,sc:{sf:d.substring(0,12),kd:!0,ma:!0}},T=x.s||x.sdp,Y=x.e||x.ecdhPublicKey,B=x.d||x.ecdsaPublicKey;if(!T||!Y||!B)throw new Error("Generated answer package is incomplete");return this._secureLog("info","Enhanced secure answer created successfully",{operationId:t,version:x.version,hasECDSA:!0,hasMutualAuth:!!S,hasSessionConfirmation:!!x.sessionConfirmation,securityLevel:_.level,timestamp:A,processingTime:A-e.timestamp}),this._dispatchAppEvent?.(new CustomEvent("new-connection",{detail:{type:"answer",timestamp:A,securityLevel:_.level,operationId:t}})),setTimeout(async()=>{try{let R=await this.calculateAndReportSecurityLevel();R&&(this.notifySecurityUpdate(),this._secureLog("info","Post-connection security level calculated",{operationId:t,level:R.level}))}catch(R){this._secureLog("error","Error calculating post-connection security",{operationId:t,errorType:R.constructor.name})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(this._secureLog("info","Retrying security calculation",{operationId:t}),await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate(),x}catch(r){throw this._secureLog("error","Enhanced secure answer creation failed in critical section",{operationId:t,errorType:r.constructor.name,errorMessage:r.message,phase:this._determineAnswerErrorPhase(r),offerAge:e?.timestamp?Date.now()-e.timestamp:"unknown"}),this._cleanupFailedAnswerCreation(),this.onStatusChange("disconnected"),this.onAnswerError&&(r.message.includes("too old")||r.message.includes("replay")?this.onAnswerError("replay_attack",r.message):r.message.includes("MITM")||r.message.includes("signature")?this.onAnswerError("security_violation",r.message):r.message.includes("validation")||r.message.includes("format")?this.onAnswerError("invalid_format",r.message):this.onAnswerError("general_error",r.message)),r}},6e4)}_determineAnswerErrorPhase(e){let t=e.message.toLowerCase();return t.includes("validation")||t.includes("format")?"offer_validation":t.includes("rate limit")?"rate_limiting":t.includes("replay")||t.includes("too old")?"replay_protection":t.includes("salt")?"salt_validation":t.includes("key pair")||t.includes("generate")?"key_generation":t.includes("import")||t.includes("ecdsa")||t.includes("ecdh")?"key_import":t.includes("signature")||t.includes("mitm")?"signature_verification":t.includes("derive")||t.includes("shared")?"key_derivation":t.includes("auth")||t.includes("proof")?"authentication":t.includes("remote description")||t.includes("local description")?"webrtc_setup":t.includes("answer")||t.includes("sdp")?"sdp_creation":t.includes("export")?"key_export":t.includes("security level")?"security_calculation":"unknown"}_cleanupFailedAnswerCreation(){try{this._clearPendingOfferContext(),this._secureCleanupCryptographicMaterials(),this.currentKeyVersion=0,this.keyVersions.clear(),this.oldKeys.clear(),this.peerConnection&&(this.peerConnection.close(),this.peerConnection=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.isInitiator=!1,this.isVerified=!1,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._updateSecurityFeatures({hasEncryption:!1,hasECDH:!1,hasECDSA:!1,hasMutualAuth:!1,hasMetadataProtection:!1,hasEnhancedReplayProtection:!1,hasNonExtractableKeys:!1,hasEnhancedValidation:!1,hasPFS:!1}),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during answer cleanup",{errorType:e?.constructor?.name||"Unknown"})}),this._secureLog("debug","Failed answer creation cleanup completed with secure memory wipe")}catch(e){this._secureLog("error","Error during answer creation cleanup",{errorType:e.constructor.name,errorMessage:e.message})}}async _setEncryptionKeys(e,t,r,i){return this._withMutex("keyOperation",async n=>{if(this._secureLog("info","Setting encryption keys with mutex",{operationId:n}),!(e instanceof CryptoKey)||!(t instanceof CryptoKey)||!(r instanceof CryptoKey))throw new Error("Invalid key types provided");if(!i||typeof i!="string")throw new Error("Invalid key fingerprint provided");let a={encryptionKey:this.encryptionKey,macKey:this.macKey,metadataKey:this.metadataKey,keyFingerprint:this.keyFingerprint};try{return this.encryptionKey=e,this.macKey=t,this.metadataKey=r,this.keyFingerprint=i,this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),this._secureLog("info","Encryption keys set successfully",{operationId:n,hasAllKeys:!!(this.encryptionKey&&this.macKey&&this.metadataKey),hasFingerprint:!!this.keyFingerprint}),!0}catch(o){throw this.encryptionKey=a.encryptionKey,this.macKey=a.macKey,this.metadataKey=a.metadataKey,this.keyFingerprint=a.keyFingerprint,this._secureLog("error","Key setting failed, rolled back",{operationId:n,errorType:o.constructor.name}),o}})}async _handleSbq2Answer(e){if(!this._isSbq2())throw new Error("Received a new-format response to an old-format invitation. Please start a new invitation.");let t=this._sbq2State(),r=Ur(String(e.sbq2)),i=Fr(r);if(i.type!==de.ANSWER)throw new Error("That code is an invitation, not a response to one.");if(!i.commitment)throw new Error("The response carries no key commitment");let a=await Or(async d=>new Uint8Array(await crypto.subtle.digest("SHA-256",d)),t.localDescriptor),o=0;for(let d=0;dd.toString(16).padStart(2,"0").toUpperCase()).join(":");let{sdp:c}=Kr(i);await this.peerConnection.setRemoteDescription({type:"answer",sdp:c}),this._secureLog("info","SBQ2 answer accepted; awaiting in-band key exchange",{bytes:r.length})}async handleSecureAnswer(e){if(e&&typeof e.sbq2=="string")return this._handleSbq2Answer(e);try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid answer data structure",{hasAnswerData:!!e,answerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Answer data must be a non-null object");let t=e.t==="answer"&&e.s,r=e.type==="enhanced_secure_answer"&&e.sdp;if(!t&&!r)throw this._secureLog("error","CRITICAL: Invalid answer format",{type:e.type||e.t,hasSdp:!!(e.sdp||e.s)}),new Error("CRITICAL SECURITY FAILURE: Invalid answer format - hard abort required");let i=e.v||e.version;if(i!==s.PROTOCOL_VERSION)throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${i||"unknown"}`);let n=e.ecdhPublicKey||e.e,a=e.ecdsaPublicKey||e.d;if(!n||typeof n!="object"||Array.isArray(n))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure in answer",{hasEcdhKey:!!n,ecdhKeyType:typeof n,isArray:Array.isArray(n),availableKeys:Object.keys(e)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDH public key structure");if(!n.keyData||!n.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature in answer",{hasKeyData:!!n.keyData,hasSignature:!!n.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!a||typeof a!="object"||Array.isArray(a))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure in answer",{hasEcdsaKey:!!a,ecdsaKeyType:typeof a,isArray:Array.isArray(a)}),new Error("CRITICAL SECURITY FAILURE: Missing or invalid ECDSA public key structure");if(!a.keyData||!a.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature in answer",{hasKeyData:!!a.keyData,hasSignature:!!a.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");let o=e.ts||e.timestamp,c=e.v||e.version;if(!o||!c)throw new Error("Missing required fields in response data \u2013 possible MITM attack");if(e.sessionId&&this.sessionId&&e.sessionId!==this.sessionId)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Session ID mismatch detected - possible MITM attack",{}),new Error("Session ID mismatch \u2013 possible MITM attack");let d=Date.now()-e.timestamp;if(d>36e5)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Answer data is too old - possible replay attack",{answerAge:d,timestamp:e.timestamp}),this.onAnswerError&&this.onAnswerError("replay_attack","Response data is too old \u2013 possible replay attack"),new Error("Response data is too old \u2013 possible replay attack");i!==s.PROTOCOL_VERSION&&window.EnhancedSecureCryptoUtils.secureLog.log("warn","Incompatible protocol version in answer",{expectedVersion:s.PROTOCOL_VERSION,receivedVersion:i});let u=await crypto.subtle.importKey("spki",new Uint8Array(a.keyData),{name:"ECDSA",namedCurve:"P-384"},!1,["verify"]),h=await window.EnhancedSecureCryptoUtils.importPublicKeyFromSignedPackage(n,u);if(this._restorePendingOfferContextIfNeeded(),!this.sessionSalt||this.sessionSalt.length!==64)throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid session salt detected - possible session hijacking",{saltLength:this.sessionSalt?this.sessionSalt.length:0}),new Error("Missing pending offer context. Apply the response in the original creator window that generated the invitation.");let m=await window.EnhancedSecureCryptoUtils.calculateKeyFingerprint(this.sessionSalt);if(window.EnhancedSecureCryptoUtils.secureLog.log("info","Session salt integrity verified",{saltFingerprint:m.substring(0,8)}),!(this.ecdhKeyPair?.privateKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Local ECDH private key is not a CryptoKey in handleSecureAnswer",{hasKeyPair:!!this.ecdhKeyPair,privateKeyType:typeof this.ecdhKeyPair?.privateKey,privateKeyAlgorithm:this.ecdhKeyPair?.privateKey?.algorithm?.name}),new Error("Local ECDH private key is not a CryptoKey");if(!(h instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Peer ECDH public key is not a CryptoKey in handleSecureAnswer",{publicKeyType:typeof h,publicKeyAlgorithm:h?.algorithm?.name}),new Error("Peer ECDH public key is not a CryptoKey");this.peerPublicKey=h,this._peerSupportsRatchet=e.dr===s.RATCHET_VERSION,this.connectionId||(this.connectionId=Array.from(crypto.getRandomValues(new Uint8Array(8))).map(g=>g.toString(16).padStart(2,"0")).join(""));let p=await window.EnhancedSecureCryptoUtils.deriveSharedKeys(this.ecdhKeyPair.privateKey,h,this.sessionSalt);if(this.encryptionKey=p.messageKey,this.macKey=p.macKey,this.metadataKey=p.metadataKey,this.keyFingerprint=p.fingerprint,await this._initializeRatchet(p,!0),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.messageCounter=0,this.processedMessageIds.clear(),this.replayWindow.clear(),!(this.encryptionKey instanceof CryptoKey)||!(this.macKey instanceof CryptoKey)||!(this.metadataKey instanceof CryptoKey))throw window.EnhancedSecureCryptoUtils.secureLog.log("error","Invalid key types after derivation in handleSecureAnswer",{encryptionKeyType:typeof this.encryptionKey,macKeyType:typeof this.macKey,metadataKeyType:typeof this.metadataKey,encryptionKeyAlgorithm:this.encryptionKey?.algorithm?.name,macKeyAlgorithm:this.macKey?.algorithm?.name,metadataKeyAlgorithm:this.metadataKey?.algorithm?.name}),new Error("Invalid key types after export");this._secureLog("info","Encryption keys set in handleSecureAnswer",{hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,mitmProtection:"enabled",signatureVerified:!0}),this.securityFeatures.hasMutualAuth=!0,this.securityFeatures.hasMetadataProtection=!0,this.securityFeatures.hasEnhancedReplayProtection=!0,this.securityFeatures.hasPFS=!0,this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.keyVersions.set(0,{salt:this.sessionSalt,timestamp:this.lastKeyRotation,messageCount:0}),this.onKeyExchange(this.keyFingerprint);try{let g=this._extractDTLSFingerprintFromSDP(e.sdp||e.s),b=this.expectedDTLSFingerprint,w=this._decodeKeyFingerprint(this.keyFingerprint);this.verificationCode=await this._computeSAS(w,b,g),this._setSASMaterialReady(b,g),this.pendingSASCode=this.verificationCode,this._secureLog("info","SAS verification code generated for MITM protection (Offer side)",{sasCode:this.verificationCode,localFP:b.substring(0,16)+"...",remoteFP:g.substring(0,16)+"...",timestamp:Date.now()})}catch(g){this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{errorType:g?.constructor?.name||"Unknown"}),this._secureLog("error","SAS computation failed in handleSecureAnswer (Offer side)",{error:g.message,stack:g.stack,timestamp:Date.now()})}if(this.strictDTLSValidation)try{this._peerDTLSFingerprint=this._extractDTLSFingerprintFromSDP(e.sdp||e.s)}catch(g){this._secureLog("warn","Could not extract peer DTLS fingerprint from answer",{error:g.message,context:"answer_validation"})}else this._secureLog("info","DTLS fingerprint validation disabled - proceeding without validation");let S=e.sdp||e.s;if(this.peerConnection?.signalingState!=="have-local-offer"){this._secureLog("warn","Ignoring answer outside have-local-offer state",{signalingState:this.peerConnection?.signalingState||"unknown"});return}this._secureLog("debug","Setting remote description from answer",{sdpLength:S?.length||0,usingCompactSDP:!e.sdp&&!!e.s}),await this.peerConnection.setRemoteDescription({type:"answer",sdp:S}),this._logIceCandidateDiagnostics("remote answer applied",this.peerConnection.remoteDescription?.sdp,{signalingState:this.peerConnection.signalingState}),this._warnIfRemoteCandidatesNeedRelay("answer",this.peerConnection.remoteDescription?.sdp),this._secureLog("debug","Remote description set successfully from answer",{signalingState:this.peerConnection.signalingState}),setTimeout(async()=>{try{await this.calculateAndReportSecurityLevel()&&this.notifySecurityUpdate()}catch(g){this._secureLog("error","Error calculating security after connection:",{errorType:g?.constructor?.name||"Unknown"})}},1e3),setTimeout(async()=>{(!this.lastSecurityCalculation||this.lastSecurityCalculation.score<50)&&(await this.calculateAndReportSecurityLevel(),this.notifySecurityUpdate())},3e3),this.notifySecurityUpdate()}catch(t){throw this._secureLog("error","Enhanced secure answer handling failed",{errorType:t.constructor.name}),this.onStatusChange("failed"),this.onAnswerError&&(t.message.includes("too old")||t.message.includes("\u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0441\u0442\u0430\u0440\u044B\u0435")?this.onAnswerError("replay_attack",t.message):t.message.includes("MITM")||t.message.includes("signature")||t.message.includes("\u043F\u043E\u0434\u043F\u0438\u0441\u044C")?this.onAnswerError("security_violation",t.message):this.onAnswerError("general_error",t.message)),t}}initiateVerification(){this.isInitiator?this.verificationInitiationSent||(this.verificationInitiationSent=!0,this.deliverMessageToUI("CRITICAL: Compare verification code with peer out-of-band (voice/video/in-person) to prevent MITM attack!","system"),this.deliverMessageToUI(`Your verification code: ${this.verificationCode}`,"system"),this.deliverMessageToUI("Ask peer to confirm this exact code before allowing traffic!","system")):this.deliverMessageToUI("Waiting for verification code from peer...","system")}_validateSASCode(e){if(!e||typeof e!="string"||!this.verificationCode||typeof this.verificationCode!="string")return!1;let t=e.replace(/[-\s]/g,"").toUpperCase(),r=this.verificationCode.replace(/[-\s]/g,"").toUpperCase();return t.length!==r.length?!1:window.EnhancedSecureCryptoUtils.constantTimeCompare(t,r)}confirmVerification(e){try{if(!this._validateSASCode(e))throw this.sasValidationAttempts=(this.sasValidationAttempts||0)+1,this._secureLog("warn","SAS validation failed: user entered incorrect code",{attempts:this.sasValidationAttempts,maxAttempts:s.MAX_SAS_ATTEMPTS}),this.sasValidationAttempts>=s.MAX_SAS_ATTEMPTS?(this.deliverMessageToUI("Verification failed 3 times. Session reset for safety.","system"),this.disconnect(),new Error("SAS_MAX_ATTEMPTS")):new Error("SAS_MISMATCH");this.localVerificationConfirmed=!0,this.sasValidationAttempts=0;let t={type:"verification_confirmed",data:{timestamp:Date.now(),verificationMethod:"MANUAL_SAS_ENTRY",securityLevel:"MITM_PROTECTION_REQUIRED"}};this.dataChannel.send(JSON.stringify(t)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed(),this.deliverMessageToUI("Code verified locally. Waiting for peer confirmation...","system"),this.processMessageQueue()}catch(t){throw t.message==="SAS_MISMATCH"?this.deliverMessageToUI("Verification failed: the code you entered is incorrect.","system"):t.message!=="SAS_MAX_ATTEMPTS"&&(this._secureLog("error","SAS verification failed:",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("SAS verification failed","system")),t}}_checkBothVerificationsConfirmed(){if(this.localVerificationConfirmed&&this.remoteVerificationConfirmed&&!this.bothVerificationsConfirmed){this.bothVerificationsConfirmed=!0;let e={type:"verification_both_confirmed",data:{timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTION_COMPLETE"}};this.dataChannel.send(JSON.stringify(e)),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{try{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")}catch(t){this._secureLog("error","Verified transition rejected - aborting session",{errorType:t?.constructor?.name||"Unknown"}),this.deliverMessageToUI("Verification could not be completed safely. Connection aborted.","system"),this.disconnect()}},2e3)}}handleVerificationConfirmed(e){this.remoteVerificationConfirmed=!0,this.deliverMessageToUI("Peer confirmed the verification code. Waiting for your confirmation...","system"),this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this._checkBothVerificationsConfirmed()}handleVerificationBothConfirmed(e){if(!this.bothVerificationsConfirmed){if(!this.localVerificationConfirmed){this._secureLog("error","Peer claimed mutual SAS confirmation before local confirmation - possible MITM attack",{localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,timestamp:Date.now()}),this.deliverMessageToUI("Verification protocol violation: peer claimed confirmation before you verified the code. Connection aborted for safety.","system"),this.disconnect();return}this.remoteVerificationConfirmed=!0,this.bothVerificationsConfirmed=!0,this.onVerificationStateChange&&this.onVerificationStateChange({localConfirmed:this.localVerificationConfirmed,remoteConfirmed:this.remoteVerificationConfirmed,bothConfirmed:this.bothVerificationsConfirmed}),this.deliverMessageToUI("Both parties confirmed! Opening secure chat in 2 seconds...","system"),setTimeout(()=>{this._setVerifiedStatus(!0,"MUTUAL_SAS_CONFIRMED",{code:this.verificationCode,timestamp:Date.now()}),this._enforceVerificationGate("mutual_confirmed",!1),this.onStatusChange?.("verified")},2e3)}}handleVerificationRequest(e){if(this._validateSASCode(e?.code)){let t={type:"verification_response",data:{ok:!0,timestamp:Date.now(),verificationMethod:"SAS",securityLevel:"MITM_PROTECTED"}};this.dataChannel.send(JSON.stringify(t)),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI("SAS verification successful! MITM protection confirmed. Channel is now secure!","system")),this.processMessageQueue()}else{let t={type:"verification_response",data:{ok:!1,timestamp:Date.now(),reason:"code_mismatch"}};this.dataChannel.send(JSON.stringify(t)),this._secureLog("error","SAS verification failed - possible MITM attack",{receivedCodeLength:typeof e?.code=="string"?e.code.length:0,timestamp:Date.now()}),this.deliverMessageToUI("SAS verification failed! Possible MITM attack detected. Connection aborted for safety!","system"),this.disconnect()}}handleSASCode(e){if(!e?.code||typeof e.code!="string"){this._secureLog("warn","Invalid SAS announcement received from peer");return}if(!this.verificationCode){this._secureLog("error","Received peer SAS announcement before local SAS was derived - refusing to adopt it",{timestamp:Date.now()}),this.deliverMessageToUI("Verification failed: no locally derived code to compare against. Connection aborted for safety.","system"),this.disconnect();return}if(!this._validateSASCode(e.code)){this._secureLog("error","Peer-announced SAS does not match locally computed SAS"),this.deliverMessageToUI("Version or SAS mismatch detected. Connection aborted for safety.","system"),this.disconnect();return}this._notifyVerificationReadyIfPossible(),this._secureLog("info","Peer SAS announcement matched locally derived code",{timestamp:Date.now()})}handleVerificationResponse(e){e.ok===!0?(this._secureLog("info","Mutual SAS verification completed - MITM protection active",{verificationMethod:e.verificationMethod||"SAS",securityLevel:e.securityLevel||"MITM_PROTECTED",timestamp:Date.now()}),this.verificationNotificationSent||(this.verificationNotificationSent=!0,this.deliverMessageToUI(" Mutual SAS verification complete! MITM protection active. Channel is now secure!","system")),this.processMessageQueue()):(this._secureLog("error","Peer SAS verification failed - connection not secure",{responseData:e,timestamp:Date.now()}),this.deliverMessageToUI("Peer verification failed! Connection not secure!","system"),this.disconnect())}validateOfferData(e){return e&&e.type==="enhanced_secure_offer"&&e.sdp&&e.publicKey&&e.salt&&e.verificationCode&&Array.isArray(e.publicKey)&&Array.isArray(e.salt)&&e.salt.length===32}validateEnhancedOfferData(e){try{if(!e||typeof e!="object"||Array.isArray(e))throw this._secureLog("error","CRITICAL: Invalid offer data structure",{hasOfferData:!!e,offerDataType:typeof e,isArray:Array.isArray(e)}),new Error("CRITICAL SECURITY FAILURE: Offer data must be a non-null object");let t=e.v===s.PROTOCOL_VERSION&&e.e&&e.d,r=e.version===s.PROTOCOL_VERSION&&e.ecdhPublicKey&&e.ecdsaPublicKey;if(!(t?["offer"].includes(e.t):["enhanced_secure_offer","secure_offer"].includes(e.type)))throw new Error("Invalid offer type");if(t){let a=["e","d","sl","vc","si","ci","ac","slv"];for(let c of a)if(!e[c])throw new Error(`Missing required v4.1 compact field: ${c}`);if(!e.e||typeof e.e!="object"||Array.isArray(e.e))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure");if(!e.d||typeof e.d!="object"||Array.isArray(e.d))throw new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure");if(!Array.isArray(e.sl)||e.sl.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");if(typeof e.vc!="string"||e.vc.length<6)throw new Error("Invalid verification code format");if(!["MAX","HIGH","MED","LOW"].includes(e.slv))throw new Error("Invalid security level");let o=Date.now()-e.ts;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");this._secureLog("info","v4.1 compact offer validation passed",{version:e.v,hasECDH:!!e.e,hasECDSA:!!e.d,hasSalt:!!e.sl,hasVerificationCode:!!e.vc,securityLevel:e.slv,offerAge:Math.round(o/1e3)+"s"})}else if(r){let a=["ecdhPublicKey","ecdsaPublicKey","salt","verificationCode","authChallenge","timestamp","version","securityLevel"];for(let c of a)if(!e[c])throw new Error(`Missing v4.1 field: ${c}`);if(!Array.isArray(e.salt)||e.salt.length!==64)throw new Error("Salt must be exactly 64 bytes for v4.1");let o=Date.now()-e.timestamp;if(o>36e5)throw new Error("Offer is too old (older than 1 hour)");if(!e.ecdhPublicKey||typeof e.ecdhPublicKey!="object"||Array.isArray(e.ecdhPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDH public key structure",{hasEcdhKey:!!e.ecdhPublicKey,ecdhKeyType:typeof e.ecdhPublicKey,isArray:Array.isArray(e.ecdhPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDH public key structure - hard abort required");if(!e.ecdsaPublicKey||typeof e.ecdsaPublicKey!="object"||Array.isArray(e.ecdsaPublicKey))throw this._secureLog("error","CRITICAL: Invalid ECDSA public key structure",{hasEcdsaKey:!!e.ecdsaPublicKey,ecdsaKeyType:typeof e.ecdsaPublicKey,isArray:Array.isArray(e.ecdsaPublicKey)}),new Error("CRITICAL SECURITY FAILURE: Invalid ECDSA public key structure - hard abort required");if(!e.ecdhPublicKey.keyData||!e.ecdhPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDH key missing keyData or signature",{hasKeyData:!!e.ecdhPublicKey.keyData,hasSignature:!!e.ecdhPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDH key missing keyData or signature");if(!e.ecdsaPublicKey.keyData||!e.ecdsaPublicKey.signature)throw this._secureLog("error","CRITICAL: ECDSA key missing keyData or signature",{hasKeyData:!!e.ecdsaPublicKey.keyData,hasSignature:!!e.ecdsaPublicKey.signature}),new Error("CRITICAL SECURITY FAILURE: ECDSA key missing keyData or signature");if(typeof e.verificationCode!="string"||e.verificationCode.length<6)throw new Error("Invalid SAS verification code format - MITM protection required");this._secureLog("info","v4.1 offer validation passed",{version:e.version,hasSecurityLevel:!!e.securityLevel?.level,offerAge:Math.round(o/1e3)+"s"})}else{let a=e.v||e.version||"unknown";throw new Error(`Version mismatch: expected protocol ${s.PROTOCOL_VERSION}, received ${a}`)}let n=t?e.s:e.sdp;if(typeof n!="string"||!n.includes("v=0"))throw new Error("Invalid SDP structure");return!0}catch(t){throw this._secureLog("error","CRITICAL: Security validation failed - hard abort required",{error:t.message,errorType:t.constructor.name,timestamp:Date.now()}),new Error(`CRITICAL SECURITY VALIDATION FAILURE: ${t.message}`)}}async sendSecureMessage(e){let t=this._validateInputData(e,"sendSecureMessage");if(!t.isValid){let r=`Input validation failed: ${t.errors.join(", ")}`;throw this._secureLog("error","Input validation failed in sendSecureMessage",{errors:t.errors,messageType:typeof e}),new Error(r)}if(!this._checkRateLimit("sendSecureMessage"))throw new Error("Rate limit exceeded for secure message sending");if(this._enforceVerificationGate("sendSecureMessage"),!this.isConnected())throw t.sanitizedData&&typeof t.sanitizedData=="object"&&t.sanitizedData.type&&t.sanitizedData.type.startsWith("file_")?new Error("Connection not ready for file transfer. Please ensure the connection is established and verified."):(this.messageQueue.push(t.sanitizedData),new Error("Connection not ready. Message queued for sending."));return this._withMutex("cryptoOperation",async r=>{if(!this.isConnected()||!this.isVerified)throw new Error("Connection lost during message preparation");if(!this.encryptionKey||!this.macKey||!this.metadataKey)throw new Error("Encryption keys not initialized");if(!window.EnhancedSecureCryptoUtils.rateLimiter.checkMessageRate(this.rateLimiterId))throw new Error("Message rate limit exceeded (60 messages per minute)");try{let i=typeof t.sanitizedData=="string"?t.sanitizedData:JSON.stringify(t.sanitizedData),n=window.EnhancedSecureCryptoUtils.sanitizeMessage(i),a=`msg_${Date.now()}_${this.messageCounter++}`;if(typeof this._createMessageAAD!="function")throw new Error("_createMessageAAD method is not available in sendSecureMessage. Manager may not be fully initialized.");let o=e.aad||this._createMessageAAD("enhanced_message",{content:n}),c;if(this._ratchet?.canEncrypt){let{header:d,ciphertext:u}=await this._ratchet.encrypt(n);c={type:s.MESSAGE_TYPES.RATCHET_MESSAGE,h:d,c:u,version:"5.0"}}else c={type:"enhanced_message",data:await window.EnhancedSecureCryptoUtils.encryptMessage(n,this.encryptionKey,this.macKey,this.metadataKey,a,JSON.parse(o).sequenceNumber),keyVersion:this.currentKeyVersion,version:"4.0"};this.dataChannel.send(JSON.stringify(c)),typeof t.sanitizedData=="string"&&this.deliverMessageToUI(t.sanitizedData,"sent"),this._secureLog("debug","Secure message sent successfully",{operationId:r,messageLength:n.length,keyVersion:this.currentKeyVersion})}catch(i){throw this._secureLog("error","Secure message sending failed",{operationId:r,errorType:i.constructor.name}),i.message.includes("Session expired")?new Error("Session expired. Please enter your password to unlock."):i.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):i.message.includes("Connection lost")?new Error("Connection lost. Please check your Internet connection."):i.message.includes("Rate limit exceeded")?new Error("Message rate limit exceeded. Please wait before sending another message."):i}},2e3)}processMessageQueue(){for(;this.messageQueue.length>0&&this.isConnected()&&this.isVerified;){let e=this.messageQueue.shift();this.sendSecureMessage(e).catch(console.error)}}startHeartbeat(){this._heartbeatConfig={enabled:!0,interval:s.TIMEOUTS.HEARTBEAT_INTERVAL,lastHeartbeat:0},this.stopHeartbeat(!0),this._heartbeatTimer=setInterval(()=>{this._heartbeatConfig?.enabled&&this.dataChannel?.readyState==="open"&&this._sendHeartbeat()},s.TIMEOUTS.HEARTBEAT_INTERVAL),this._trackActiveTimer(this._heartbeatTimer),this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!1,this._startLivenessWatchdog(),this._setupRecoveryLifecycleListeners(),this._secureLog("info","\u{1F504} Liveness watchdog started",{heartbeatMs:s.TIMEOUTS.HEARTBEAT_INTERVAL,probeAfterMs:s.TIMEOUTS.LIVENESS_PROBE_AFTER,probeTimeoutMs:s.TIMEOUTS.LIVENESS_PROBE_TIMEOUT})}stopHeartbeat(e=!1){!e&&this._heartbeatConfig&&(this._heartbeatConfig.enabled=!1),this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._activeTimers?.delete(this._heartbeatTimer),this._heartbeatTimer=null),e||this._stopLivenessWatchdog()}handleHeartbeat(e){this._lastInboundAt=Date.now(),this._livenessProbeAt=0;let t=e?.ack===!0||e?.data?.ack===!0;t||this._sendHeartbeat(!0),this._secureLog("debug",t?"\u{1F493} Heartbeat ack received":"\u{1F493} Heartbeat probe received")}_noteInboundActivity(){this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._livenessArmed=!0}_startLivenessWatchdog(){this._stopLivenessWatchdog(),this._livenessTimer=setInterval(()=>{try{this._checkLiveness()}catch(e){this._secureLog("error","\u274C Liveness check failed",{errorType:e?.constructor?.name||"Unknown"})}},s.TIMEOUTS.LIVENESS_CHECK_INTERVAL),this._trackActiveTimer(this._livenessTimer)}_stopLivenessWatchdog(){this._livenessTimer&&(clearInterval(this._livenessTimer),this._activeTimers?.delete(this._livenessTimer),this._livenessTimer=null)}_checkLiveness(){if(!this.isVerified||this._reconnect.phase!=="idle"||this.dataChannel?.readyState!=="open"||!this._lastInboundAt||!this._livenessArmed)return;let e=s.TIMEOUTS,t=Date.now();if(this.peerConnection?.connectionState==="connected"){this._livenessProbeAt=0;return}if(this._livenessProbeAt){if(t-this._livenessProbeAt"u"||this._recoveryLifecycleBound||(this._recoveryLifecycleBound=!0,this._onDeviceOnline=()=>{this.isVerified&&(this.isReconnecting()?(this._secureLog("info","\u{1F504} Device back online \u2014 retrying immediately"),this._attemptIceRestart()):this._checkLiveness())},this._onVisibilityRestored=()=>{typeof document>"u"||document.visibilityState!=="visible"||this.isVerified&&(this._lastInboundAt=Date.now(),this._livenessProbeAt=0,this._reconnect.phase==="idle"&&this.dataChannel?.readyState==="open"&&(this._livenessProbeAt=Date.now(),this._sendHeartbeat(!1),this._secureLog("info","\u{1F504} returned to foreground, probing peer")))},window.addEventListener("online",this._onDeviceOnline),typeof document<"u"&&document.addEventListener("visibilitychange",this._onVisibilityRestored))}_teardownRecoveryLifecycleListeners(){!this._recoveryLifecycleBound||typeof window>"u"||(this._recoveryLifecycleBound=!1,this._onDeviceOnline&&window.removeEventListener("online",this._onDeviceOnline),this._onVisibilityRestored&&typeof document<"u"&&document.removeEventListener("visibilitychange",this._onVisibilityRestored),this._onDeviceOnline=null,this._onVisibilityRestored=null)}_resetReconnectState(){let e=this._reconnect;e&&(e.graceTimer&&(clearTimeout(e.graceTimer),this._activeTimers?.delete(e.graceTimer)),e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer)),e.restartTimer&&(clearTimeout(e.restartTimer),this._activeTimers?.delete(e.restartTimer)),e.graceTimer=null,e.retryTimer=null,e.restartTimer=null,e.phase="idle",e.attempts=0,e.startedAt=0,e.inFlightAt=0,e.barrenFailures=0,e.pendingRole=null)}_onPathDegraded(e="ice_disconnected"){this.isVerified&&this._reconnect.phase==="idle"&&(this._reconnect.phase="grace",this._reconnect.startedAt=Date.now(),this._secureLog("info","\u{1F504} path degraded, holding grace window",{reason:e}),this.onStatusChange("reconnecting"),this._reconnect.graceTimer=setTimeout(()=>{if(this._reconnect.graceTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},s.TIMEOUTS.ICE_DISCONNECT_GRACE),this._trackActiveTimer(this._reconnect.graceTimer))}_onPathLost(e="ice_failed"){this.isVerified&&(this._reconnect.phase==="restarting"||this._reconnect.phase==="exhausted"||(this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.graceTimer&&(clearTimeout(this._reconnect.graceTimer),this._activeTimers?.delete(this._reconnect.graceTimer),this._reconnect.graceTimer=null),this._secureLog("info","\u{1F504} path lost, restarting ICE",{reason:e}),this._attemptIceRestart()))}_noteIceFailureDiagnostics(e){if(this.isReconnecting()&&e){if(e.pairCount>0){this._reconnect.barrenFailures=0;return}this._reconnect.barrenFailures=(this._reconnect.barrenFailures||0)+1,!(this._reconnect.barrenFailuress.TIMEOUTS.RECONNECT_MAX_DURATION){this._giveUpAutoReconnect("timeout");return}if(e.inFlightAt&&Date.now()-e.inFlightAt=2&&r>s.TIMEOUTS.RECOVERY_SILENCE_LIMIT){this._secureLog("warn","\u26A0\uFE0F nothing has reached us since the drop \u2014 the channel cannot carry a renegotiation",{silentForMs:r,attempts:e.attempts}),this._giveUpAutoReconnect("no_signalling_path");return}e.phase="restarting",e.attempts+=1,e.inFlightAt=Date.now(),this._secureLog("info","\u{1F504} ICE restart attempt",{attempt:e.attempts,role:this.isInitiator?"offerer":"answerer"});try{this.isInitiator?await this._sendIceRestartOffer():await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_REQUEST,timestamp:Date.now()})}catch(i){this._secureLog("warn","\u26A0\uFE0F ICE restart attempt failed to send",{errorType:i?.constructor?.name||"Unknown"})}this._scheduleReconnectRetry()}_scheduleReconnectRetry(){let e=this._reconnect;e.retryTimer&&(clearTimeout(e.retryTimer),this._activeTimers?.delete(e.retryTimer));let t=s.RECONNECT_BACKOFF,r=t[Math.min(Math.max(e.attempts-1,0),t.length-1)];e.retryTimer=setTimeout(()=>{if(e.retryTimer=null,this.peerConnection?.connectionState==="connected"){this._onPathRecovered();return}this._attemptIceRestart()},r),this._trackActiveTimer(e.retryTimer)}_applyCurrentIceServers(e){try{if(!e||typeof e.getConfiguration!="function"||typeof e.setConfiguration!="function")return;let t=this._config?.webrtc?.iceServers;if(!Array.isArray(t)||t.length===0)return;e.setConfiguration({...e.getConfiguration(),iceServers:t})}catch(t){this._secureLog("warn","Could not refresh ICE servers before restart",{errorType:t?.constructor?.name||"Unknown"})}}async _sendIceRestartOffer(){let e=this.peerConnection;if(!e)return;if(this._applyCurrentIceServers(e),e.signalingState==="have-local-offer")try{await e.setLocalDescription({type:"rollback"})}catch{}let t=await e.createOffer({iceRestart:!0});await e.setLocalDescription(t),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:s.MESSAGE_TYPES.ICE_RESTART_OFFER,sdp:e.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart offer sent")}_currentRemoteDtlsFingerprint(){let e=this.peerConnection?.currentRemoteDescription?.sdp||this.peerConnection?.remoteDescription?.sdp;if(!e)return null;try{return this._extractDTLSFingerprintFromSDP(e)}catch{return null}}async _assertSameRemoteIdentity(e,t){let r=this._currentRemoteDtlsFingerprint();if(!r)throw new Error(`Cannot verify peer identity for ${t}`);let i=this._extractDTLSFingerprintFromSDP(e);await this._validateDTLSFingerprint(i,r,t)}async _handleIceRestartSignal(e,t){let r=s.MESSAGE_TYPES,i=this.peerConnection;if(i)switch(this._noteInboundActivity(),e){case r.ICE_RESTART_REQUEST:{if(!this.isInitiator)return;this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this._reconnect.phase="restarting",this.onStatusChange("reconnecting")),await this._sendIceRestartOffer();return}case r.ICE_RESTART_OFFER:{if(!t.sdp)return;await this._assertSameRemoteIdentity(t.sdp,"ice_restart_offer"),this._reconnect.phase==="idle"&&(this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting")),this._reconnect.phase="restarting",this._applyCurrentIceServers(i),await i.setRemoteDescription({type:"offer",sdp:t.sdp});let n=await i.createAnswer();await i.setLocalDescription(n),await this.waitForIceGathering(s.TIMEOUTS.ICE_RESTART_GATHERING,s.TIMEOUTS.ICE_RESTART_GATHERING),await this.sendSystemMessage({type:r.ICE_RESTART_ANSWER,sdp:i.localDescription.sdp,timestamp:Date.now()}),this._secureLog("debug","\u{1F504} ICE restart answer sent");return}case r.ICE_RESTART_ANSWER:{if(!t.sdp)return;if(i.signalingState!=="have-local-offer"){this._secureLog("warn","\u26A0\uFE0F Ignoring restart answer in unexpected state",{signalingState:i.signalingState});return}await this._assertSameRemoteIdentity(t.sdp,"ice_restart_answer"),await i.setRemoteDescription({type:"answer",sdp:t.sdp}),this._reconnect.inFlightAt=0,this._secureLog("debug","\u{1F504} ICE restart answer applied");return}default:}}_giveUpAutoReconnect(e){this._resetReconnectState(),this._reconnect.phase="exhausted",this._teardownRecoveryLifecycleListeners?.(),this._secureLog("warn","\u26A0\uFE0F automatic reconnection exhausted \u2014 ending session",{reason:e}),this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Could not restore the connection. This chat is being closed and its data wiped \u2014 start a new one to continue.","system")),this.onStatusChange("recovery_failed"),this._clearVerificationStates()}_stopAllTimers(){this._secureLog("info","Stopping all timers and cleanup scheduler"),this._maintenanceScheduler&&(clearInterval(this._maintenanceScheduler),this._maintenanceScheduler=null),this.stopHeartbeat?.(),this._resetReconnectState?.(),this._activeTimers&&(this._activeTimers.forEach(e=>{e&&(clearInterval(e),clearTimeout(e))}),this._activeTimers.clear()),this._fileTransferInitRetryTimers&&this._fileTransferInitRetryTimers.clear(),this._logCleanupInterval=null,this._secureLog("info","All timers stopped successfully")}waitForIceGathering(e=s.TIMEOUTS.ICE_GATHERING_TIMEOUT,t=s.TIMEOUTS.ICE_GATHERING_HARD_TIMEOUT){return new Promise(r=>{let i=this.peerConnection;if(!i){r(!1);return}if(i.iceGatheringState==="complete"){r(!0);return}let n=!1,a=null,o=null,c=()=>{try{let h=this.peerConnection?.localDescription?.sdp;return h?this._summarizeIceCandidatesInSDP(h).total>0:!1}catch{return!1}},d=h=>{if(!n){n=!0,a&&(clearTimeout(a),this._untrackActiveTimer?.(a)),o&&(clearTimeout(o),this._untrackActiveTimer?.(o));try{i.removeEventListener("icegatheringstatechange",u)}catch{}r(h)}},u=()=>{this.peerConnection?.iceGatheringState==="complete"&&d(!0)};i.addEventListener("icegatheringstatechange",u),a=setTimeout(()=>{c()&&d(!1)},e),this._trackActiveTimer?.(a),o=setTimeout(()=>d(!1),Math.max(t,e)),this._trackActiveTimer?.(o)})}retryConnection(){this._secureLog("info","Retrying connection",{attempt:this.connectionAttempts,maxAttempts:this.maxConnectionAttempts}),this.onStatusChange("retrying")}isConnected(){let e=!!this.dataChannel,r=this.dataChannel?.readyState==="open",i=this.isVerified,n=this.peerConnection?.connectionState;return this.dataChannel&&this.dataChannel.readyState==="open"&&this.isVerified}getConnectionInfo(){return{fingerprint:this.keyFingerprint,isConnected:this.isConnected(),isVerified:this.isVerified,connectionState:this.peerConnection?.connectionState,iceConnectionState:this.peerConnection?.iceConnectionState,verificationCode:this.verificationCode}}handleUnexpectedDisconnect(){this.sendDisconnectNotification(),this.isVerified=!1,this.disconnectNotificationSent||(this.disconnectNotificationSent=!0,this.deliverMessageToUI("\u{1F50C} Connection lost. Attempting to reconnect...","system")),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"connection_lost",timestamp:Date.now()}}))}sendDisconnectNotification(){try{if(this.dataChannel&&this.dataChannel.readyState==="open"){let e={type:"peer_disconnect",timestamp:Date.now(),reason:this.intentionalDisconnect?"user_disconnect":"connection_lost"};for(let t=0;t<3;t++)try{this.dataChannel.send(JSON.stringify(e)),window.EnhancedSecureCryptoUtils.secureLog.log("info","Disconnect notification sent",{reason:e.reason,attempt:t+1});break}catch(r){t===2&&window.EnhancedSecureCryptoUtils.secureLog.log("error","Failed to send disconnect notification",{error:r.message})}}}catch(e){window.EnhancedSecureCryptoUtils.secureLog.log("error","Could not send disconnect notification",{error:e.message})}}attemptReconnection(){return!this.isVerified||this.dataChannel?.readyState!=="open"?(this.reconnectionFailedNotificationSent||(this.reconnectionFailedNotificationSent=!0,this.deliverMessageToUI("Unable to reconnect. A new connection is required.","system")),!1):(this._resetReconnectState(),this.reconnectionFailedNotificationSent=!1,this._reconnect.startedAt=Date.now(),this.onStatusChange("reconnecting"),this._attemptIceRestart(),!0)}handlePeerDisconnectNotification(e){let t=e.reason||"unknown",r=t==="user_disconnect"?"manually disconnected.":"connection lost.";this.peerDisconnectNotificationSent||(this.peerDisconnectNotificationSent=!0,this.deliverMessageToUI(`Peer ${r}`,"system")),this.onStatusChange("peer_disconnected"),this.intentionalDisconnect=!1,this.isVerified=!1,this.stopHeartbeat(),this.onKeyExchange(""),this.onVerificationRequired(""),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:t,timestamp:Date.now()}})),this._peerDisconnectCleanupTimer||(this._peerDisconnectCleanupTimer=this._trackActiveTimer(setTimeout(()=>{let i=this._peerDisconnectCleanupTimer;this._peerDisconnectCleanupTimer=null,this._untrackActiveTimer(i),this._sessionAlive!==!1&&this.disconnect()},2e3))),window.EnhancedSecureCryptoUtils.secureLog.log("info","Peer disconnect notification processed",{reason:t})}disconnect(){try{this._sessionAlive=!1;try{this._stopAdaptation?.()}catch{}try{this._stopLocalMediaPermanently?.()}catch{}this._callAudioSender=null,this._callVideoSender=null,this._callGroupContext=null,this._externalMediaStream=null,this._callStateListeners?.clear?.(),this.intentionalDisconnect=!0,window.EnhancedSecureCryptoUtils.secureLog.log("info","Starting intentional disconnect"),this.sendDisconnectNotification(),this._teardownRecoveryLifecycleListeners?.(),this._stopAllTimers(),this._peerDisconnectCleanupTimer=null,this.stopHeartbeat(),this.stopFakeTrafficGeneration();for(let e of this.decoyTimers.entries())clearTimeout(e[1]);this.decoyTimers.clear(),this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null);for(let e of this.decoyChannels.values())e.readyState==="open"&&e.close();this.decoyChannels.clear(),this.heartbeatChannel&&(this.heartbeatChannel.close(),this.heartbeatChannel=null),this.isVerified=!1,this.processedMessageIds.clear(),this.messageCounter=0,this.packetBuffer.clear(),this.chunkQueue=[],this._wipeEphemeralKeys(),this._hardWipeOldKeys(),this._secureCleanupCryptographicMaterials(),this.keyVersions.clear(),this.oldKeys.clear(),this.currentKeyVersion=0,this.lastKeyRotation=Date.now(),this.sequenceNumber=0,this.expectedSequenceNumber=0,this.replayWindow.clear(),this._clearVerificationStates(),this.securityFeatures={hasEncryption:!0,hasECDH:!0,hasECDSA:!0,hasMutualAuth:!0,hasMetadataProtection:!0,hasEnhancedReplayProtection:!0,hasNonExtractableKeys:!0,hasRateLimiting:!0,hasEnhancedValidation:!0,hasPFS:!0},this.dataChannel&&(this.dataChannel.close(),this.dataChannel.onopen=null,this.dataChannel.onclose=null,this.dataChannel.onmessage=null,this.dataChannel.onerror=null,this.dataChannel=null),this.peerConnection&&(this.peerConnection.close(),this.peerConnection.onconnectionstatechange=null,this.peerConnection.ondatachannel=null,this.peerConnection=null),this.messageQueue&&this.messageQueue.length>0&&(this.messageQueue.forEach((e,t)=>{this._secureWipeMemory(e,`messageQueue[${t}]`)}),this.messageQueue=[]),this._forceGarbageCollection().catch(e=>{this._secureLog("error","Cleanup failed during disconnect",{errorType:e?.constructor?.name||"Unknown"})}),this._dispatchAppEvent?.(new CustomEvent("peer-disconnect",{detail:{reason:"user_disconnect",timestamp:Date.now()}})),this._dispatchAppEvent?.(new CustomEvent("connection-cleaned",{detail:{timestamp:Date.now(),reason:"user_cleanup"}})),this.onStatusChange("disconnected"),this.onKeyExchange(""),this.onVerificationRequired(""),this._secureLog("info","Connection securely cleaned up with complete memory wipe")}catch(e){this._secureLog("error","\u274C Error during enhanced disconnect:",{errorType:e?.constructor?.name||"Unknown"})}finally{this.intentionalDisconnect=!1}}async sendFile(e,t={}){if(this._enforceVerificationGate("sendFile"),!this.isConnected())throw new Error("Connection not ready for file transfer. Please ensure the connection is established.");if(!this.fileTransferSystem&&(this.initializeFileTransfer(),await new Promise(r=>setTimeout(r,500)),!this.fileTransferSystem))throw new Error("File transfer system could not be initialized. Please try reconnecting.");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready. Please wait for connection to be fully established.");try{return await this.fileTransferSystem.sendFile(e,t)}catch(r){throw this._secureLog("error","File transfer error:",{errorType:r?.constructor?.name||"Unknown"}),r.message.includes("Connection not ready")?new Error("Connection not ready for file transfer. Check connection status."):r.message.includes("Encryption keys not initialized")?new Error("Session expired due to inactivity. Please reconnect to the chat."):r.message.includes("Transfer timeout")?new Error("File transfer timeout. Check connection and try again."):r}}getFileTransfers(){if(!this.fileTransferSystem)return{sending:[],receiving:[]};try{let e=[],t=[];return typeof this.fileTransferSystem.getActiveTransfers=="function"?e=this.fileTransferSystem.getActiveTransfers():this._secureLog("warn","getActiveTransfers method not available in file transfer system"),typeof this.fileTransferSystem.getReceivingTransfers=="function"?t=this.fileTransferSystem.getReceivingTransfers():this._secureLog("warn","getReceivingTransfers method not available in file transfer system"),{sending:e||[],receiving:t||[]}}catch(e){return this._secureLog("error","Error getting file transfers:",{errorType:e?.constructor?.name||"Unknown"}),{sending:[],receiving:[]}}}getFileTransferStatus(){if(!this.fileTransferSystem)return{initialized:!1,status:"not_initialized",message:"File transfer system not initialized"};let e=this.fileTransferSystem.getActiveTransfers(),t=this.fileTransferSystem.getReceivingTransfers();return{initialized:!0,status:"ready",activeTransfers:e.length,receivingTransfers:t.length,totalTransfers:e.length+t.length}}cancelFileTransfer(e){return this.fileTransferSystem?this.fileTransferSystem.cancelTransfer(e):!1}cleanupFileTransferSystem(){return this.fileTransferSystem?(this._secureLog("info","\u{1F9F9} Force cleaning up file transfer system"),this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,!0):!1}reinitializeFileTransfer(){try{return this.fileTransferSystem&&this.fileTransferSystem.cleanup(),this.initializeFileTransfer(),!0}catch(e){return this._secureLog("error","Failed to reinitialize file transfer system:",{errorType:e?.constructor?.name||"Unknown"}),!1}}setFileTransferCallbacks(e,t,r,i=null){this.onFileProgress=e,this.onFileReceived=t,this.onFileError=r,this.onIncomingFileRequest=i,this.fileTransferSystem&&(this.fileTransferSystem.onProgress=e,this.fileTransferSystem.onFileReceived=t,this.fileTransferSystem.onError=r,this.fileTransferSystem.onIncomingFileRequest=i)}getPendingIncomingFiles(){return this.fileTransferSystem?this.fileTransferSystem.getPendingIncomingTransfers():[]}async acceptIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.acceptIncomingFile(e):!1}async rejectIncomingFile(e){return this.fileTransferSystem?this.fileTransferSystem.rejectIncomingFile(e):!1}async getReceivedFileObjectURL(e){return this.fileTransferSystem?this.fileTransferSystem.getObjectURL(e):null}revokeReceivedFileObjectURL(e){this.fileTransferSystem&&this.fileTransferSystem.revokeObjectURL(e)}async handleSessionActivation(e){try{this.currentSession=e;let t=!!(this.encryptionKey&&this.macKey);e.sessionId&&this.onStatusChange("connected"),setTimeout(()=>{try{this.initializeFileTransfer()}catch(i){this._secureLog("warn","File transfer initialization failed during session activation:",{details:i.message})}},1e3),this.fileTransferSystem&&this.isConnected()&&typeof this.fileTransferSystem.onSessionUpdate=="function"&&this.fileTransferSystem.onSessionUpdate({keyFingerprint:this.keyFingerprint,sessionSalt:this.sessionSalt,hasMacKey:!!this.macKey})}catch(t){this._secureLog("error","Failed to handle session activation:",{errorType:t?.constructor?.name||"Unknown"})}}checkFileTransferReadiness(){let e={hasFileTransferSystem:!!this.fileTransferSystem,hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,ready:!1};return e.ready=e.hasFileTransferSystem&&e.hasDataChannel&&e.dataChannelState==="open"&&e.isConnected&&e.isVerified,e}forceReinitializeFileTransfer(){try{return this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),setTimeout(()=>{this.initializeFileTransfer()},500),!0}catch(e){return this._secureLog("error","Failed to force reinitialize file transfer:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferDiagnostics(){let e={timestamp:new Date().toISOString(),webrtcManager:{hasDataChannel:!!this.dataChannel,dataChannelState:this.dataChannel?.readyState,isConnected:this.isConnected(),isVerified:this.isVerified,isInitiator:this.isInitiator,hasEncryptionKey:!!this.encryptionKey,hasMacKey:!!this.macKey,hasMetadataKey:!!this.metadataKey,hasKeyFingerprint:!!this.keyFingerprint,hasSessionSalt:!!this.sessionSalt},fileTransferSystem:null,globalState:{fileTransferActive:this._fileTransferActive||!1,hasFileTransferSystem:!!this.fileTransferSystem,fileTransferSystemType:this.fileTransferSystem?"EnhancedSecureFileTransfer":"none"}};if(this.fileTransferSystem)try{e.fileTransferSystem=this.fileTransferSystem.getSystemStatus()}catch(t){e.fileTransferSystem={error:t.message}}return e}getSupportedFileTypes(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getSupportedFileTypes()}catch(e){return{error:e.message}}}validateFile(e){if(!this.fileTransferSystem)return{isValid:!1,errors:["File transfer system not initialized"],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"};try{return this.fileTransferSystem.validateFile(e)}catch(t){return{isValid:!1,errors:[t.message],fileType:null,fileSize:e?.size||0,formattedSize:"0 B"}}}getFileTypeInfo(){if(!this.fileTransferSystem)return{error:"File transfer system not initialized"};try{return this.fileTransferSystem.getFileTypeInfo()}catch(e){return{error:e.message}}}async forceInitializeFileTransfer(e={}){let t=new AbortController,{signal:r=t.signal,timeout:i=6e3}=e;r&&r!==t.signal&&r.addEventListener("abort",()=>t.abort());try{if(!this.isVerified)throw new Error("Connection not verified");if(!this.dataChannel||this.dataChannel.readyState!=="open")throw new Error("Data channel not open");if(!this.encryptionKey||!this.macKey)throw new Error("Encryption keys not ready");this.fileTransferSystem&&(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null),this.initializeFileTransfer();let n=0,a=50,o=100,c=a*o,d=new Promise((u,h)=>{let m=()=>{if(t.signal.aborted){h(new Error("Operation cancelled"));return}if(this.fileTransferSystem){u(!0);return}if(n>=a){h(new Error(`Initialization timeout after ${c}ms`));return}n++,setTimeout(m,o)};m()});if(await Promise.race([d,new Promise((u,h)=>setTimeout(()=>h(new Error(`Global timeout after ${i}ms`)),i))]),this.fileTransferSystem)return!0;throw new Error("Force initialization timeout")}catch(n){return n.name==="AbortError"||n.message.includes("cancelled")?(this._secureLog("info","File transfer initialization cancelled by user"),{cancelled:!0}):(this._secureLog("error","Force file transfer initialization failed:",{errorType:n?.constructor?.name||"Unknown",message:n.message,attempts}),{error:n.message,attempts})}}cancelFileTransferInitialization(){try{return this.fileTransferSystem?(this.fileTransferSystem.cleanup(),this.fileTransferSystem=null,this._fileTransferActive=!1,this._secureLog("info","File transfer initialization cancelled"),!0):!1}catch(e){return this._secureLog("error","Failed to cancel file transfer initialization:",{errorType:e?.constructor?.name||"Unknown"}),!1}}getFileTransferSystemStatus(){if(!this.fileTransferSystem)return{available:!1,status:"not_initialized"};try{let e=this.fileTransferSystem.getSystemStatus();return{available:!0,status:e.status||"unknown",activeTransfers:e.activeTransfers||0,receivingTransfers:e.receivingTransfers||0,systemType:"EnhancedSecureFileTransfer"}}catch(e){return this._secureLog("error","Failed to get file transfer system status:",{errorType:e?.constructor?.name||"Unknown"}),{available:!1,status:"error",error:e.message}}}_validateNestedEncryptionSecurity(){if(this.securityFeatures.hasNestedEncryption&&this.nestedEncryptionKey)try{let e=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest1"),t=this._generateSecureIV(s.SIZES.NESTED_ENCRYPTION_IV_SIZE,"securityTest2");return e.every((i,n)=>i===t[n])?(this._secureLog("error","CRITICAL: Nested encryption security validation failed - IVs are identical!"),!1):this._getIVTrackingStats().totalIVs<2?(this._secureLog("error","CRITICAL: IV tracking system not working properly"),!1):(this._secureLog("info","Nested encryption security validation passed - secure IV generation working"),!0)}catch(e){return this._secureLog("error","CRITICAL: Nested encryption security validation failed:",{errorType:e.constructor.name,errorMessage:e.message}),!1}return!0}getCallState(){return{...this.callState}}addCallStateListener(e){return typeof e!="function"?()=>{}:(this._callStateListeners.add(e),()=>this._callStateListeners.delete(e))}removeCallStateListener(e){this._callStateListeners.delete(e)}setCallGroupContext(e){this._callGroupContext=typeof e=="string"&&e?e:null,this._updateCallState({}),this._callGroupContext&&this._pendingCallOffer&&this.callState.phase==="incoming"&&this.acceptCall().catch(t=>{this._secureLog("warn","\u26A0\uFE0F Failed to answer a group call leg that was already ringing",{errorType:t?.constructor?.name})})}setExternalMediaStream(e){this._externalMediaStream=e||null}_usingExternalMedia(){return!!this._externalMediaStream&&this.localMediaStream===this._externalMediaStream}getRemoteMediaStream(){return this.remoteMediaStream}getLocalMediaStream(){return this.localMediaStream}_refreshRemoteStream(){let e=this.peerConnection;if(!e||typeof e.getReceivers!="function")return;let t=e.getReceivers().map(n=>n.track).filter(n=>n&&(n.kind==="audio"||n.kind==="video")&&n.readyState==="live"),r=this.remoteMediaStream?this.remoteMediaStream.getTracks():[];r.length===t.length&&r.every(n=>t.includes(n))||(this.remoteMediaStream=new MediaStream(t)),this._updateCallState({remoteHasVideo:t.some(n=>n.kind==="video")})}_scheduleRemoteRefresh(){this._refreshRemoteStream(),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},300),setTimeout(()=>{try{this._refreshRemoteStream()}catch{}},1200)}_updateCallState(e){this.callState={...this.callState,...e,groupCallId:this._callGroupContext};let t=this.getCallState();t.phase==="active"?this._startAdaptation():t.phase==="idle"&&this._stopAdaptation();try{this.onCallStateChanged?.(t)}catch{}for(let r of this._callStateListeners)try{r(t)}catch{}if(typeof document<"u")try{this._dispatchAppEvent?.(new CustomEvent("securebit-call-state",{detail:{managerId:this._managerId||null,state:t}}))}catch{}}_callCanStart(){let e=typeof this.isConnected=="function"?this.isConnected():!1,t=this.dataChannel&&this.dataChannel.readyState==="open";return!!(e&&t&&this.isVerified&&!this.isReconnecting())}async _sendCallSignal(e,t){return await this.sendSystemMessage({type:e,...t})}_audioConstraints(){return{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0}}_videoConstraints(){return{facingMode:this._callFacingMode,width:{ideal:1280},height:{ideal:720}}}async _acquireLocalMedia(e){let t=this._externalMediaStream||await navigator.mediaDevices.getUserMedia({audio:this._audioConstraints(),video:e?this._videoConstraints():!1});this.localMediaStream=t;let r=this.peerConnection,i=t.getAudioTracks()[0]||null,n=t.getVideoTracks()[0]||null;return i&&(this._callAudioSender?await this._callAudioSender.replaceTrack(i):this._callAudioSender=r.addTrack(i,t)),n&&(this._callVideoSender?await this._callVideoSender.replaceTrack(n):this._callVideoSender=r.addTrack(n,t)),this._applyCallCodecPrefs(),t}_stopLocalMediaPermanently(){try{if(this.localMediaStream&&!this._usingExternalMedia())for(let e of this.localMediaStream.getTracks())try{e.stop()}catch{}}catch{}this.localMediaStream=null}_applyCallCodecPrefs(){try{let e=this.peerConnection?.getTransceivers?.()||[],t=e.find(i=>i.sender&&i.sender===this._callAudioSender);t&&Ji(t);let r=e.find(i=>i.sender&&i.sender===this._callVideoSender);r&&sn(r)}catch{}}_mungeCallSdp(e){try{let t=Cr(e,st.opusFmtp);return t=Qi(t,qi),t}catch{return e}}async _setLocalMunged(e){let t=this.peerConnection;try{await t.setLocalDescription({type:e.type,sdp:this._mungeCallSdp(e.sdp)});return}catch{try{await t.setLocalDescription({type:e.type,sdp:Cr(e.sdp,st.opusFmtp)});return}catch{await t.setLocalDescription(e)}}}async _applyCallSenderParams(){try{this._callAudioSender&&await Zi(this._callAudioSender,{}),this._callVideoSender&&await an(this._callVideoSender,{})}catch{}}_startAdaptation(){if(!(this._adaptationController||!this.peerConnection))try{this._adaptationController=new Nt(this.peerConnection,{getVideoSender:()=>this._callVideoSender,ceilingBitrate:15e5,onQuality:e=>{e!==this.callState.quality&&this._updateCallState({quality:e})}}),this._adaptationController.start()}catch{}}_stopAdaptation(){if(this._adaptationController){try{this._adaptationController.stop()}catch{}this._adaptationController=null}}_notifyCallMediaError(e,t){let r=e?.name||"",i=t?"camera/microphone":"microphone",n,a;r==="NotAllowedError"?(a="permission_denied",n=`\u26A0\uFE0F Call not started \u2014 ${i} access is blocked. Allow it for this site in the browser, and enable your browser under System Settings \u2192 Privacy & Security \u2192 ${t?"Camera/Microphone":"Microphone"}, then try again.`):r==="NotFoundError"||r==="OverconstrainedError"?(a="device_not_found",n=`\u26A0\uFE0F Call not started \u2014 no ${i} found on this device.`):r==="NotReadableError"||r==="AbortError"?(a="device_busy",n=`\u26A0\uFE0F Call not started \u2014 your ${i} is in use by another app. Close it and try again.`):(a="media_failed",n=`\u26A0\uFE0F Call not started \u2014 could not access ${i}${r?" ("+r+")":""}.`);try{this.deliverMessageToUI(n,"system")}catch{}return a}async startCall(e=!1){if(!this._callCanStart())throw this._updateCallState({error:"not_verified"}),new Error("Calls require a connected, SAS-verified session.");if(this.callState.active){this._secureLog("warn","\u26A0\uFE0F startCall ignored \u2014 a call is already active");return}let t=crypto?.randomUUID?.()||String(Date.now())+Math.random().toString(36).slice(2);this._updateCallState({active:!0,phase:"outgoing",withVideo:e,callId:t,micEnabled:!0,cameraEnabled:e,remoteHasVideo:!1,error:null});try{await this._acquireLocalMedia(e),this._callMakingOffer=!0;let r=await this.peerConnection.createOffer();await this._setLocalMunged(r),this._callMakingOffer=!1,await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:t,withVideo:e,sdp:this.peerConnection.localDescription.sdp})}catch(r){this._callMakingOffer=!1,this._secureLog("error","\u274C startCall failed",{errorType:r?.constructor?.name});let i=this._notifyCallMediaError(r,e);throw await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:i}),r}}async _onIncomingCallOffer(e){if(this.callState.active&&(this.callState.phase==="active"||this.callState.phase==="connecting")){await this._answerCallOffer(e,!0),e.withVideo&&this._updateCallState({withVideo:!0});return}this._pendingCallOffer=e,this._updateCallState({active:!0,phase:"incoming",withVideo:!!e.withVideo,callId:e.callId,remoteHasVideo:!!e.withVideo,error:null}),this._callGroupContext&&await this.acceptCall()}async _answerCallOffer(e,t=!1){await this.peerConnection.setRemoteDescription({type:"offer",sdp:e.sdp}),t||await this._acquireLocalMedia(!!e.withVideo);let r=await this.peerConnection.createAnswer();await this._setLocalMunged(r),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_ANSWER,{callId:e.callId,sdp:this.peerConnection.localDescription.sdp})}async acceptCall(){let e=this._pendingCallOffer;if(e){this._pendingCallOffer=null,this._updateCallState({phase:"connecting",cameraEnabled:!!e.withVideo});try{await this._answerCallOffer(e,!1),this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(t){this._secureLog("error","\u274C acceptCall failed",{errorType:t?.constructor?.name});let r=this._notifyCallMediaError(t,!!e.withVideo);try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:e.callId})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",error:r})}}}async declineCall(){let e=this.callState.callId;this._pendingCallOffer=null,await this._sendCallSignal(s.MESSAGE_TYPES.CALL_DECLINE,{callId:e}),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1})}async endCall(e=!0){let t=this.callState.callId;if(e&&t)try{await this._sendCallSignal(s.MESSAGE_TYPES.CALL_END,{callId:t})}catch{}await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,micEnabled:!0,cameraEnabled:!1,remoteHasVideo:!1,callId:null,quality:null})}async _teardownCallMedia(){this._stopAdaptation();let e=this.peerConnection;try{if(this.localMediaStream&&!this._usingExternalMedia())for(let t of this.localMediaStream.getTracks())try{t.stop()}catch{}if(e)for(let t of[this._callAudioSender,this._callVideoSender].filter(Boolean))try{await t.replaceTrack(null)}catch{}}catch{}this.localMediaStream=null,this.remoteMediaStream=null,this._callMakingOffer=!1;try{this.peerConnection&&(this.peerConnection.signalingState==="have-local-offer"||this.peerConnection.signalingState==="have-local-pranswer")&&await this.peerConnection.setLocalDescription({type:"rollback"})}catch{}}setMicEnabled(e){this.localMediaStream&&this.localMediaStream.getAudioTracks().forEach(t=>{t.enabled=e}),this._updateCallState({micEnabled:e})}toggleMic(){this.setMicEnabled(!this.callState.micEnabled)}async setCameraEnabled(e){if(!e){this.localMediaStream&&this.localMediaStream.getVideoTracks().forEach(r=>{r.enabled=!1}),this._updateCallState({cameraEnabled:!1});return}let t=this.localMediaStream?.getVideoTracks?.()||[];if(t.length){t.forEach(r=>{r.enabled=!0}),this._updateCallState({cameraEnabled:!0,withVideo:!0});return}await this.upgradeToVideo()}async toggleCamera(){await this.setCameraEnabled(!this.callState.cameraEnabled)}async upgradeToVideo(){if(this.localMediaStream)try{let t=(await navigator.mediaDevices.getUserMedia({video:this._videoConstraints()})).getVideoTracks()[0];if(!t)return;await this.addVideoTrack(t)}catch(e){this._secureLog("error","\u274C upgradeToVideo failed",{errorType:e?.constructor?.name}),this._updateCallState({cameraEnabled:!1,error:"camera_failed"})}}async addVideoTrack(e){!e||!this.localMediaStream||!this.peerConnection||(this.localMediaStream.getVideoTracks().includes(e)||this.localMediaStream.addTrack(e),this._callVideoSender?await this._callVideoSender.replaceTrack(e):this._callVideoSender=this.peerConnection.addTrack(e,this.localMediaStream),this._applyCallCodecPrefs(),this._updateCallState({cameraEnabled:!0,withVideo:!0}),await this._renegotiateCall())}async replaceVideoTrack(e){!e||!this._callVideoSender||await this._callVideoSender.replaceTrack(e)}async switchCamera(){if(!(!this._callVideoSender||!this.localMediaStream)){this._callFacingMode=this._callFacingMode==="user"?"environment":"user";try{let t=(await navigator.mediaDevices.getUserMedia({video:{facingMode:this._callFacingMode}})).getVideoTracks()[0],r=this.localMediaStream.getVideoTracks()[0];if(r){this.localMediaStream.removeTrack(r);try{r.stop()}catch{}}this.localMediaStream.addTrack(t),await this._callVideoSender.replaceTrack(t)}catch(e){this._secureLog("warn","\u26A0\uFE0F switchCamera failed",{errorType:e?.constructor?.name})}}}async _renegotiateCall(){if(!this._callMakingOffer)try{this._callMakingOffer=!0;let e=await this.peerConnection.createOffer();await this._setLocalMunged(e),await this._applyCallSenderParams(),await this._sendCallSignal(s.MESSAGE_TYPES.CALL_OFFER,{callId:this.callState.callId,withVideo:this.callState.withVideo,sdp:this.peerConnection.localDescription.sdp})}finally{this._callMakingOffer=!1}}async _handleCallSignal(e,t){let r=s.MESSAGE_TYPES;switch(e){case r.CALL_OFFER:{await this._onIncomingCallOffer(t);return}case r.CALL_ANSWER:{try{this.peerConnection.signalingState==="have-local-offer"&&await this.peerConnection.setRemoteDescription({type:"answer",sdp:t.sdp}),this.callState.phase==="outgoing"&&this._updateCallState({phase:"active"}),this._scheduleRemoteRefresh()}catch(i){this._secureLog("warn","\u26A0\uFE0F Failed to apply call answer",{errorType:i?.constructor?.name})}return}case r.CALL_ICE:{try{t.candidate&&await this.peerConnection.addIceCandidate(t.candidate)}catch{}return}case r.CALL_DECLINE:{await this._teardownCallMedia(),this._updateCallState({active:!1,phase:"idle",withVideo:!1,remoteHasVideo:!1,error:"declined"});return}case r.CALL_END:{await this.endCall(!1);return}default:return}}},Gt=class{constructor(e=null){this._keyStore=new WeakMap,this._keyMetadata=new Map,this._keyReferences=new Map,this._masterKeyManager=e||new jt,this._persistentStorage=new Br(this._masterKeyManager),this._setupMasterKeyCallbacks(),setTimeout(()=>{this.validateStorageIntegrity()||this._secureLog("error","CRITICAL: Key storage integrity check failed")},100)}_secureLog(e,t,r={}){try{let i=typeof window<"u"&&window.EnhancedSecureCryptoUtils?.secureLog||null;if(i&&typeof i.log=="function"){i.log(e,`[KeyStorage] ${t}`,r);return}}catch{}e==="error"?console.error(`[KeyStorage] ${t}`):e==="warn"&&console.warn(`[KeyStorage] ${t}`)}_setupMasterKeyCallbacks(){this._masterKeyManager.setPasswordRequiredCallback((e,t)=>{this._secureLog("error","Master key password requested but no password UI is installed",{isRetry:!!e}),t(null)}),this._masterKeyManager.setSessionExpiredCallback(e=>{console.warn(`Master key session expired: ${e}`)}),this._masterKeyManager.setUnlockedCallback(()=>{console.log("Master key unlocked successfully")})}setPasswordCallback(e){this._masterKeyManager.setPasswordRequiredCallback(e)}setSessionExpiredCallback(e){this._masterKeyManager.setSessionExpiredCallback(e)}async _ensureMasterKeyUnlocked(){this._masterKeyManager.isUnlocked()||await this._masterKeyManager.unlock()}async storeKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");try{return t.extractable?(await this._persistentStorage.storeExtractableKey(e,t,r),this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0,encrypted:!0}),!0):(this._keyReferences.set(e,t),this._keyMetadata.set(e,{...r,created:Date.now(),lastAccessed:Date.now(),extractable:!1,persistent:!1,encrypted:!1}),!0)}catch(i){return this._secureLog("error","Failed to store key securely",{errorType:i?.constructor?.name||"Unknown"}),!1}}async retrieveKey(e){try{if(this._keyReferences.has(e)){let r=this._keyMetadata.get(e);return r&&(r.lastAccessed=Date.now()),this._keyReferences.get(e)}let t=await this._persistentStorage.retrieveKey(e);if(t){this._keyReferences.set(e,t);let r=this._keyMetadata.get(e);return this._keyMetadata.set(e,{...r,lastAccessed:Date.now(),restoredFromPersistent:!0}),t}return null}catch(t){return this._secureLog("error","Failed to retrieve key",{errorType:t?.constructor?.name||"Unknown"}),null}}async _encryptKeyData(e){let t=typeof e=="object"?JSON.stringify(e):e,i=new TextEncoder().encode(t);await this._ensureMasterKeyUnlocked();let{encryptedData:n,iv:a}=await this._masterKeyManager.encryptBytes(i),o=new Uint8Array(a.length+n.byteLength);return o.set(a,0),o.set(n,a.length),o}async _decryptKeyData(e){let t=e.slice(0,12),r=e.slice(12);await this._ensureMasterKeyUnlocked();let i=await this._masterKeyManager.decryptBytes(r,t),a=new TextDecoder().decode(i);try{return JSON.parse(a)}catch{return i}}async secureWipe(e){let t=this._keyReferences.get(e);t&&(this._keyStore.delete(t),this._keyReferences.delete(e),this._keyMetadata.delete(e)),await this._performNaturalCleanup()}async secureWipeAll(){try{await this._persistentStorage.clearAll()}catch(e){this._secureLog("error","Failed to clear persistent storage",{errorType:e?.constructor?.name||"Unknown"})}this._keyReferences.clear(),this._keyMetadata.clear(),this._keyStore=new WeakMap,await this._performNaturalCleanup()}validateStorageIntegrity(){let e=[];for(let[t,r]of this._keyMetadata.entries())r.extractable===!0&&r.encrypted!==!0&&e.push({keyId:t,type:"EXTRACTABLE_KEY_NOT_ENCRYPTED",metadata:r}),r.extractable===!1&&r.encrypted===!0&&e.push({keyId:t,type:"NON_EXTRACTABLE_KEY_ENCRYPTED",metadata:r});return e.length>0?(this._secureLog("error","Storage integrity violations detected",{violationCount:e.length}),!1):!0}async getStorageStats(){let e=await this._persistentStorage.getStorageStats();return{totalKeys:this._keyReferences.size,memoryKeys:this._keyReferences.size,persistentKeys:e.persistentKeys,metadata:Array.from(this._keyMetadata.entries()).map(([t,r])=>({id:t,created:r.created,lastAccessed:r.lastAccessed,age:Date.now()-r.created,persistent:r.persistent||!1})),persistent:e}}async listAllKeys(){try{let e=Array.from(this._keyMetadata.entries()).map(([i,n])=>({keyId:i,...n,location:"memory"})),r=(await this._persistentStorage.listStoredKeys()).map(i=>({...i,location:"persistent"}));return{memoryKeys:e,persistentKeys:r,totalCount:e.length+r.length}}catch(e){return this._secureLog("error","Failed to list keys",{errorType:e?.constructor?.name||"Unknown"}),{memoryKeys:[],persistentKeys:[],totalCount:0,error:e.message}}}async deleteKey(e){try{return this._keyReferences.delete(e),this._keyMetadata.delete(e),await this._persistentStorage.deleteKey(e),!0}catch(t){return this._secureLog("error","Failed to delete key",{errorType:t?.constructor?.name||"Unknown"}),!1}}},qt=class{constructor(e="SecureKeyStorage",t=1){this.dbName=e,this.version=t,this.db=null,this.KEYS_STORE="encrypted_keys",this.METADATA_STORE="key_metadata",this.SALT_STORE="master_salt"}async initialize(){return new Promise((e,t)=>{let r=indexedDB.open(this.dbName,this.version);r.onerror=()=>{t(new Error(`Failed to open IndexedDB: ${r.error}`))},r.onsuccess=()=>{this.db=r.result,e()},r.onupgradeneeded=i=>{let n=i.target.result;if(!n.objectStoreNames.contains(this.KEYS_STORE)){let a=n.createObjectStore(this.KEYS_STORE,{keyPath:"keyId"});a.createIndex("timestamp","timestamp",{unique:!1}),a.createIndex("algorithm","algorithm",{unique:!1})}if(!n.objectStoreNames.contains(this.METADATA_STORE)){let a=n.createObjectStore(this.METADATA_STORE,{keyPath:"keyId"});a.createIndex("created","created",{unique:!1}),a.createIndex("lastAccessed","lastAccessed",{unique:!1})}n.objectStoreNames.contains(this.SALT_STORE)||n.createObjectStore(this.SALT_STORE,{keyPath:"id"})}})}async storeEncryptedKey(e,t,r,i,n,a,o={}){if(!this.db)throw new Error("Database not initialized");let c=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite"),d={keyId:e,encryptedData:Array.from(new Uint8Array(t)),iv:Array.from(new Uint8Array(r)),algorithm:i,usages:n,type:a},u={keyId:e,...o};return new Promise((h,m)=>{let p=c.objectStore(this.KEYS_STORE).put(d),S=c.objectStore(this.METADATA_STORE).put(u);c.oncomplete=()=>h(),c.onerror=()=>m(new Error(`Failed to store key: ${c.error}`))})}async getEncryptedKey(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.KEYS_STORE],"readonly").objectStore(this.KEYS_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>{let o=a.result;o&&(o.encryptedData=new Uint8Array(o.encryptedData),o.iv=new Uint8Array(o.iv)),i(o)},a.onerror=()=>n(new Error(`Failed to retrieve key: ${a.error}`))})}async updateKeyMetadata(e,t){if(!this.db)throw new Error("Database not initialized");let i=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((n,a)=>{let o=i.get(e);o.onsuccess=()=>{let c=o.result;if(c){Object.assign(c,t);let d=i.put(c);d.onsuccess=()=>n(),d.onerror=()=>a(new Error(`Failed to update metadata: ${d.error}`))}else a(new Error(`Key metadata not found: ${e}`))},o.onerror=()=>a(new Error(`Failed to get metadata: ${o.error}`))})}async getKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.get(e);a.onsuccess=()=>i(a.result||null),a.onerror=()=>n(new Error(`Failed to get metadata: ${a.error}`))})}async putKeyMetadataRecord(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.METADATA_STORE],"readwrite").objectStore(this.METADATA_STORE);return new Promise((i,n)=>{let a=r.put(e);a.onsuccess=()=>i(),a.onerror=()=>n(new Error(`Failed to store metadata: ${a.error}`))})}async deleteKey(e){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE],"readwrite");return new Promise((r,i)=>{let n=t.objectStore(this.KEYS_STORE).delete(e),a=t.objectStore(this.METADATA_STORE).delete(e);t.oncomplete=()=>r(),t.onerror=()=>i(new Error(`Failed to delete key: ${t.error}`))})}async listKeys(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.METADATA_STORE],"readonly").objectStore(this.METADATA_STORE);return new Promise((r,i)=>{let n=t.getAll();n.onsuccess=()=>r(n.result),n.onerror=()=>i(new Error(`Failed to list keys: ${n.error}`))})}async storeMasterSalt(e){if(!this.db)throw new Error("Database not initialized");let r=this.db.transaction([this.SALT_STORE],"readwrite").objectStore(this.SALT_STORE),i={id:"master_salt",salt:Array.from(new Uint8Array(e))};return new Promise((n,a)=>{let o=r.put(i);o.onsuccess=()=>n(),o.onerror=()=>a(new Error(`Failed to store salt: ${o.error}`))})}async getMasterSalt(){if(!this.db)throw new Error("Database not initialized");let t=this.db.transaction([this.SALT_STORE],"readonly").objectStore(this.SALT_STORE);return new Promise((r,i)=>{let n=t.get("master_salt");n.onsuccess=()=>{let a=n.result;r(a?new Uint8Array(a.salt):null)},n.onerror=()=>i(new Error(`Failed to retrieve salt: ${n.error}`))})}async clearAll(){if(!this.db)throw new Error("Database not initialized");let e=this.db.transaction([this.KEYS_STORE,this.METADATA_STORE,this.SALT_STORE],"readwrite");return new Promise((t,r)=>{let i=e.objectStore(this.KEYS_STORE).clear(),n=e.objectStore(this.METADATA_STORE).clear(),a=e.objectStore(this.SALT_STORE).clear();e.oncomplete=()=>t(),e.onerror=()=>r(new Error(`Failed to clear database: ${e.error}`))})}close(){this.db&&(this.db.close(),this.db=null)}},Br=class{constructor(e,t=null){this._masterKeyManager=e,this._indexedDB=t||new qt,this._dbInitialized=!1,this._keyCache=new WeakMap,this._keyReferences=new Map}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}async _ensureMasterKeyUnlocked(){typeof this._masterKeyManager.isUnlocked=="function"&&!this._masterKeyManager.isUnlocked()&&await this._masterKeyManager.unlock()}async storeExtractableKey(e,t,r={}){if(!(t instanceof CryptoKey))throw new Error("Only CryptoKey objects can be stored");if(!t.extractable)throw new Error("Key must be extractable for persistent storage");try{await this._ensureDBInitialized();let i=await crypto.subtle.exportKey("jwk",t),{encryptedData:n,iv:a}=await this._encryptKeyData(i),o=await this._encryptMetadata({...r,created:Date.now(),lastAccessed:Date.now(),extractable:!0,persistent:!0});await this._indexedDB.storeEncryptedKey(e,n,a,t.algorithm,t.usages,t.type,o);let c=await this._importAsNonExtractable(i,t.algorithm,t.usages);return this._keyReferences.set(e,c),!0}catch(i){throw new Error(`Failed to store extractable key: ${i.message}`)}}async retrieveKey(e){try{if(this._keyReferences.has(e))return this._keyReferences.get(e);await this._ensureDBInitialized();let t=await this._indexedDB.getEncryptedKey(e);if(!t)return null;let r=await this._decryptKeyData(t.encryptedData,t.iv),i=await this._importAsNonExtractable(r,t.algorithm,t.usages);return this._keyReferences.set(e,i),await this._updateEncryptedMetadata(e,{lastAccessed:Date.now()}),i}catch(t){throw new Error(`Failed to retrieve key: ${t.message}`)}}async deleteKey(e){try{return await this._ensureDBInitialized(),await this._indexedDB.deleteKey(e),this._keyReferences.delete(e),!0}catch(t){throw new Error(`Failed to delete key: ${t.message}`)}}async listStoredKeys(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys(),t=[];for(let r of e){let i=await this._readMetadataWithMigration(r);i&&t.push({keyId:r.keyId,...i})}return t}catch(e){throw new Error(`Failed to list keys: ${e.message}`)}}async clearAll(){try{return await this._ensureDBInitialized(),await this._indexedDB.clearAll(),this._keyReferences.clear(),!0}catch(e){throw new Error(`Failed to clear storage: ${e.message}`)}}async _encryptKeyData(e){let t=JSON.stringify(e),r=new TextEncoder().encode(t);return await this._ensureMasterKeyUnlocked(),await this._masterKeyManager.encryptBytes(r)}async _decryptKeyData(e,t){await this._ensureMasterKeyUnlocked();let r=await this._masterKeyManager.decryptBytes(e,t),i=new TextDecoder().decode(r);return JSON.parse(i)}async _encryptMetadata(e){let t=new TextEncoder().encode(JSON.stringify(e));await this._ensureMasterKeyUnlocked();let{encryptedData:r,iv:i}=await this._masterKeyManager.encryptBytes(t);return{metadataVersion:1,encryptedMetadata:Array.from(r),metadataIv:Array.from(i)}}async _decryptMetadataRecord(e){if(!e?.encryptedMetadata||!e?.metadataIv)throw new Error("Encrypted metadata missing");await this._ensureMasterKeyUnlocked();let t=await this._masterKeyManager.decryptBytes(new Uint8Array(e.encryptedMetadata),new Uint8Array(e.metadataIv));return JSON.parse(new TextDecoder().decode(t))}async _readMetadataWithMigration(e){if(!e)return null;if(e.encryptedMetadata)try{return await this._decryptMetadataRecord(e)}catch{return null}let{keyId:t,...r}=e,i={keyId:t,...await this._encryptMetadata(r)};return await this._indexedDB.putKeyMetadataRecord(i),r}async _updateEncryptedMetadata(e,t){let r=await this._indexedDB.getKeyMetadataRecord(e);if(!r)throw new Error(`Key metadata not found: ${e}`);let i=await this._readMetadataWithMigration(r);if(!i)throw new Error(`Key metadata corrupted: ${e}`);await this._indexedDB.putKeyMetadataRecord({keyId:e,...await this._encryptMetadata({...i,...t})})}async _importAsNonExtractable(e,t,r){return await crypto.subtle.importKey("jwk",e,t,!1,r)}async getStorageStats(){try{await this._ensureDBInitialized();let e=await this._indexedDB.listKeys();return{totalKeys:e.length,memoryKeys:this._keyReferences.size,persistentKeys:e.length,lastAccessed:e.reduce((t,r)=>Math.max(t,r.lastAccessed||0),0)}}catch(e){return{totalKeys:0,memoryKeys:this._keyReferences.size,persistentKeys:0,lastAccessed:0,error:e.message}}}},jt=class{constructor(e=null){this._keyHandle=null,this._isUnlocked=!1,this._sessionTimeout=null,this._lastActivity=null,this._sessionTimeoutMs=3600*1e3,this._inactivityTimeoutMs=1800*1e3,this._pbkdf2Iterations=31e4,this._saltSize=32,this._indexedDB=e||new qt,this._dbInitialized=!1,this._onPasswordRequired=null,this._onSessionExpired=null,this._onUnlocked=null}setPasswordRequiredCallback(e){this._onPasswordRequired=e}setSessionExpiredCallback(e){this._onSessionExpired=e}setUnlockedCallback(e){this._onUnlocked=e}_setupEventListeners(){typeof document<"u"&&(document.addEventListener("visibilitychange",()=>{document.hidden?this._handleFocusOut():this._handleFocusIn()}),window.addEventListener("blur",()=>this._handleFocusOut()),window.addEventListener("focus",()=>this._handleFocusIn()),["mousedown","mousemove","keypress","scroll","touchstart"].forEach(e=>{document.addEventListener(e,()=>this._updateActivity(),{passive:!0})}))}_handleFocusOut(){this._isUnlocked&&this._startInactivityTimer(this._inactivityTimeoutMs)}_handleFocusIn(){this._isUnlocked&&this._resetSessionTimer()}_updateActivity(){this._lastActivity=Date.now(),this._isUnlocked&&this._resetSessionTimer()}_startSessionTimer(){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("timeout")},this._sessionTimeoutMs)}_startInactivityTimer(e){this._clearTimers(),this._sessionTimeout=setTimeout(()=>{this._expireSession("inactivity")},e)}_resetSessionTimer(){this._isUnlocked&&this._startSessionTimer()}_clearTimers(){this._sessionTimeout&&(clearTimeout(this._sessionTimeout),this._sessionTimeout=null)}_expireSession(e="unknown"){this._isUnlocked&&(this._secureWipeMasterKey(),this._isUnlocked=!1,this._onSessionExpired&&this._onSessionExpired(e))}async _ensureDBInitialized(){this._dbInitialized||(await this._indexedDB.initialize(),this._dbInitialized=!0)}_generateSalt(){return crypto.getRandomValues(new Uint8Array(this._saltSize))}async _getOrCreateSalt(){await this._ensureDBInitialized();let e=await this._indexedDB.getMasterSalt();return e||(e=this._generateSalt(),await this._indexedDB.storeMasterSalt(e)),e}async _deriveKeyFromPassword(e,t){try{let r=await crypto.subtle.importKey("raw",new TextEncoder().encode(e),"PBKDF2",!1,["deriveKey"]);return await crypto.subtle.deriveKey({name:"PBKDF2",salt:t,iterations:this._pbkdf2Iterations,hash:"SHA-256"},r,{name:"AES-GCM",length:256},!1,["encrypt","decrypt","wrapKey","unwrapKey"])}catch(r){throw new Error(`Key derivation failed: ${r.message}`)}}async _requestPassword(e=!1){if(!this._onPasswordRequired)throw new Error("Password callback not set");return new Promise((t,r)=>{this._onPasswordRequired(e,i=>{i?t(i):r(new Error("Password not provided"))})})}async unlock(e=null){try{e||(e=await this._requestPassword(!1));let t=await this._getOrCreateSalt();return this._keyHandle=await this._deriveKeyFromPassword(e,t),this._isUnlocked=!0,this._lastActivity=Date.now(),this._startSessionTimer(),e=null,this._onUnlocked&&this._onUnlocked(),{success:!0}}catch(t){throw e=null,t}}lock(){this._expireSession("manual")}async encryptBytes(e){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let t=crypto.getRandomValues(new Uint8Array(12)),r=await crypto.subtle.encrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return{encryptedData:new Uint8Array(r),iv:t}}async decryptBytes(e,t){if(!this._isUnlocked||!this._keyHandle)throw new Error("Master key is locked");this._updateActivity();let r=await crypto.subtle.decrypt({name:"AES-GCM",iv:t},this._keyHandle,e);return new Uint8Array(r)}isUnlocked(){return this._isUnlocked&&this._keyHandle!==null}getSessionStatus(){return{isUnlocked:this._isUnlocked,lastActivity:this._lastActivity,sessionTimeoutMs:this._sessionTimeoutMs,inactivityTimeoutMs:this._inactivityTimeoutMs}}_secureWipeMasterKey(){this._keyHandle&&(this._keyHandle=null),this._clearTimers()}destroy(){this._secureWipeMasterKey(),this._isUnlocked=!1,typeof document<"u"&&(document.removeEventListener("visibilitychange",this._handleFocusOut),window.removeEventListener("blur",this._handleFocusOut),window.removeEventListener("focus",this._handleFocusIn))}};var $n=wi(Pn());var Fn="6.8.12";var Hr=()=>{if(Ke.length<2)return null;let[s,e]=React.useState(!1),t=React.useRef(null),r=typeof window<"u"?window.location.pathname:"/",i=Gi({pathname:r,active:Ge()}),n=i.find(c=>c.isCurrent)||i[0];React.useEffect(()=>{if(!s)return;let c=u=>{t.current&&!t.current.contains(u.target)&&e(!1)},d=u=>{u.key==="Escape"&&e(!1)};return document.addEventListener("pointerdown",c),document.addEventListener("keydown",d),()=>{document.removeEventListener("pointerdown",c),document.removeEventListener("keydown",d)}},[s]);let a=React.createElement("button",{key:"trigger",type:"button",onClick:()=>e(c=>!c),"aria-haspopup":"menu","aria-expanded":s?"true":"false","aria-label":f("language.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"7px 10px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:s?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",fontSize:"12.5px",fontWeight:600,cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"c"},n?n.abbr:""),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:s?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),o=React.createElement("div",{key:"menu",role:"menu",className:"sb-scroll",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:s?"block":"none",minWidth:"170px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",maxHeight:"min(62vh, 420px)",overflowY:"auto",overscrollBehavior:"contain"}},i.map(c=>React.createElement("a",{key:c.code,href:c.href,hrefLang:c.hrefLang,lang:c.hrefLang,dir:c.dir,role:"menuitem","aria-current":c.isCurrent?"page":void 0,onClick:()=>Hi(c.code),style:{display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",fontSize:"13px",fontWeight:c.isCurrent?600:500,color:c.isCurrent?"var(--sb-text-2)":"var(--sb-text-6)",background:c.isCurrent?"rgba(var(--sb-ink), 0.06)":"transparent",textDecoration:"none",whiteSpace:"nowrap"}},[React.createElement("span",{key:"a",style:{fontSize:"11px",fontWeight:700,letterSpacing:"0.4px",color:"var(--sb-text-9)",width:"22px",flex:"none",textAlign:"start"}},c.abbr),React.createElement("span",{key:"n"},c.label)])));return React.createElement("nav",{ref:t,"aria-label":f("language.label"),style:{position:"relative",display:"inline-flex"}},[a,o])};window.LanguageSwitcher=Hr;var ot={system:'',light:'',dark:''},$r=(s,e,t)=>React.createElement("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:t,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",dangerouslySetInnerHTML:{__html:s}}),Gr=()=>{let s=typeof window<"u"?window.SecureBitTheme:null;if(!s)return null;let[e,t]=React.useState(!1),[r,i]=React.useState(()=>s.get()),[n,a]=React.useState(()=>s.resolved()),o=React.useRef(null);React.useEffect(()=>s.subscribe((p,S)=>{i(p),a(S)}),[]),React.useEffect(()=>{if(!e)return;let p=g=>{o.current&&!o.current.contains(g.target)&&t(!1)},S=g=>{g.key==="Escape"&&t(!1)};return document.addEventListener("pointerdown",p),document.addEventListener("keydown",S),()=>{document.removeEventListener("pointerdown",p),document.removeEventListener("keydown",S)}},[e]);let c=[{mode:"system",icon:ot.system,label:f("theme.system")},{mode:"light",icon:ot.light,label:f("theme.light")},{mode:"dark",icon:ot.dark,label:f("theme.dark")}],d=r==="system"?ot.system:n==="light"?ot.light:ot.dark,u=c.find(p=>p.mode===r)||c[0],h=React.createElement("button",{key:"trigger",type:"button",onClick:()=>t(p=>!p),"aria-haspopup":"menu","aria-expanded":e?"true":"false","aria-label":f("theme.label")+": "+u.label,title:f("theme.label"),style:{display:"flex",alignItems:"center",gap:"6px",padding:"8px 9px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:e?"rgba(var(--sb-ink), 0.06)":"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-4)",font:"inherit",cursor:"pointer",transition:"background .15s, color .15s"}},[React.createElement("span",{key:"i",style:{display:"grid",placeItems:"center"}},$r(d,15,1.9)),React.createElement("svg",{key:"v",width:11,height:11,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",style:{transform:e?"rotate(180deg)":"none",transition:"transform .18s"},dangerouslySetInnerHTML:{__html:''}})]),m=React.createElement("div",{key:"menu",role:"menu",style:{position:"absolute",top:"calc(100% + 6px)",insetInlineEnd:0,zIndex:60,display:e?"block":"none",minWidth:"158px",padding:"5px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",boxShadow:"0 14px 34px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))"}},c.map(p=>{let S=p.mode===r;return React.createElement("button",{key:p.mode,type:"button",role:"menuitemradio","aria-checked":S?"true":"false",onClick:()=>{s.set(p.mode),t(!1)},style:{width:"100%",display:"flex",alignItems:"center",gap:"10px",padding:"8px 10px",borderRadius:"8px",border:"none",fontSize:"13px",fontFamily:"inherit",fontWeight:S?600:500,color:S?"var(--sb-text-2)":"var(--sb-text-6)",background:S?"rgba(var(--sb-ink), 0.06)":"transparent",cursor:"pointer",textAlign:"start",whiteSpace:"nowrap"}},[React.createElement("span",{key:"i",style:{flex:"none",display:"grid",placeItems:"center",width:"16px",color:S?"var(--sb-orange)":"var(--sb-text-9)"}},$r(p.icon,14,1.9)),React.createElement("span",{key:"l",style:{flex:1}},p.label),S&&React.createElement("span",{key:"c",style:{flex:"none",display:"grid",placeItems:"center",color:"var(--sb-orange)"}},$r('',12,2.6))])}));return React.createElement("div",{ref:o,style:{position:"relative",display:"inline-flex"}},[h,m])};window.ThemeSwitcher=Gr;var Ma=`v${Fn}`,La=({status:s,fingerprint:e,verificationCode:t,onDisconnect:r,isConnected:i,securityLevel:n,webrtcManager:a})=>{let[o,c]=React.useState(null),[d,u]=React.useState(0),[h,m]=React.useState(!1),[p,S]=React.useState(0),[g,b]=React.useState("unknown");React.useEffect(()=>{let G=!1,U=0,I=async()=>{let N=Date.now();if(!(N-U<1e4)&&!G){G=!0,U=N;try{if(!a||!i)return;let z=a,W=null;if(typeof z.getRealSecurityLevel=="function"?W=await z.getRealSecurityLevel():typeof z.calculateAndReportSecurityLevel=="function"?W=await z.calculateAndReportSecurityLevel():W=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(z),W&&W.isRealData!==!1){let Z=o?.score||0,be=W.score||0;Z!==be||!o?(c(W),u(N)):window.DEBUG_MODE}}catch{}finally{G=!1}}};if(i&&(I(),!o||o.score<50)){let N=setInterval(()=>{!o||o.score<50?I():clearInterval(N)},5e3);setTimeout(()=>clearInterval(N),3e4)}let D=setInterval(I,3e4);return()=>clearInterval(D)},[a,i]),React.useEffect(()=>{let G=I=>{setTimeout(()=>{u(0)},100)},U=I=>{I.detail&&I.detail.securityData&&(c(I.detail.securityData),u(Date.now()))};return document.addEventListener("security-level-updated",G),document.addEventListener("real-security-calculated",U),window.forceHeaderSecurityUpdate=I=>{I&&window.EnhancedSecureCryptoUtils?window.EnhancedSecureCryptoUtils.calculateSecurityLevel(I).then(D=>{D&&D.isRealData!==!1&&(c(D),u(Date.now()))}).catch(D=>{}):u(0)},()=>{document.removeEventListener("security-level-updated",G),document.removeEventListener("real-security-calculated",U)}},[]),React.useEffect(()=>{m(!0),S(0),b("premium")},[]),React.useEffect(()=>{m(!0),S(0),b("premium")},[]),React.useEffect(()=>{let G=N=>{m(!0),S(0),b("premium")},U=()=>{c(null),u(0),m(!1),S(0),b("unknown")},I=()=>{c(null),u(0)},D=()=>{c(null),u(0),m(!1),S(0),b("unknown")};return document.addEventListener("force-header-update",G),document.addEventListener("peer-disconnect",I),document.addEventListener("connection-cleaned",U),document.addEventListener("disconnected",D),()=>{document.removeEventListener("force-header-update",G),document.removeEventListener("peer-disconnect",I),document.removeEventListener("connection-cleaned",U),document.removeEventListener("disconnected",D)}},[]);let w=async G=>{if(G&&(G.button===2||G.ctrlKey||G.metaKey)&&r&&typeof r=="function"){r();return}G.preventDefault(),G.stopPropagation();let U=null;if(a&&window.EnhancedSecureCryptoUtils)try{U=await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(a)}catch{}if(!U&&!o){alert(f("sec.verificationWait"));return}let I=U||o;I||(I={level:"UNKNOWN",score:0,color:"gray",verificationResults:{},timestamp:Date.now(),details:f("sec.verificationUnavailable"),isRealData:!1,passedChecks:0,totalChecks:0});let D=`REAL-TIME SECURITY VERIFICATION `;if(D+=`Security Level: ${I.level} (${I.score}%) `,D+=`Verification Time: ${new Date(I.timestamp).toLocaleTimeString()} @@ -102,7 +102,7 @@ ${I.details||f("sec.verificationDone")}`,I.isRealData?D+=` border: 1px solid var(--sb-surface-5); `,z.textContent=D,N.appendChild(z),N.addEventListener("click",Z=>{Z.target===N&&document.body.removeChild(N)});let W=Z=>{Z.key==="Escape"&&(document.body.removeChild(N),document.removeEventListener("keydown",W))};document.addEventListener("keydown",W),document.body.appendChild(N)},F=(()=>{switch(s){case"connected":return{text:f("status.connected"),className:"status-connected",badgeClass:"bg-green-500/10 text-green-400 border-green-500/20"};case"verifying":return{text:f("status.verifying"),className:"status-verifying",badgeClass:"bg-purple-500/10 text-purple-400 border-purple-500/20"};case"connecting":return{text:f("status.connecting"),className:"status-connecting",badgeClass:"bg-blue-500/10 text-blue-400 border-blue-500/20"};case"retrying":return{text:f("status.retrying"),className:"status-connecting",badgeClass:"bg-yellow-500/10 text-yellow-400 border-yellow-500/20"};case"failed":return{text:f("status.error"),className:"status-failed",badgeClass:"bg-red-500/10 text-red-400 border-red-500/20"};case"reconnecting":return{text:f("status.reconnecting"),className:"status-connecting",badgeClass:"bg-yellow-500/10 text-yellow-400 border-yellow-500/20"};case"peer_disconnected":return{text:f("status.peerDisconnected"),className:"status-failed",badgeClass:"bg-orange-500/10 text-orange-400 border-orange-500/20"};default:return{text:f("status.notConnected"),className:"status-disconnected",badgeClass:"bg-gray-500/10 text-gray-400 border-gray-500/20"}}})(),k=i?o||n:null,_=(()=>{if(!k)return{tooltip:f("sec.verificationInProgress"),isVerified:!1,dataSource:"loading"};let G=k.isRealData!==!1,U=`${k.level} (${k.score}%)`;return G?{tooltip:`${U} - Real-time verification \u2705 Right-click or Ctrl+click to disconnect`,isVerified:!0,dataSource:"real"}:{tooltip:`${U} - Estimated (connection establishing...) -Right-click or Ctrl+click to disconnect`,isVerified:!1,dataSource:"estimated"}})();React.useEffect(()=>(window.debugHeaderSecurity=void 0,()=>{delete window.debugHeaderSecurity}),[o,d,i,a,k,_]);let A=k?k.color==="green"?"var(--sb-green)":k.color==="orange"?"var(--sb-orange)":k.color==="yellow"?"var(--sb-yellow)":"var(--sb-red)":"var(--sb-green)",x=i?"var(--sb-green-solid)":["connecting","verifying","retrying","reconnecting"].includes(s)?"var(--sb-yellow-solid)":s==="failed"?"var(--sb-red-solid)":"var(--sb-text-9)",T=x==="var(--sb-green-solid)"?"rgba(var(--sb-green-rgb), 0.16)":x==="var(--sb-yellow-solid)"?"rgba(var(--sb-yellow-rgb), 0.16)":x==="var(--sb-red-solid)"?"rgba(var(--sb-red-rgb), 0.16)":"rgba(var(--sb-text-9-rgb), 0.16)",Y="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",B=!i,[R,ue]=React.useState(!1);React.useEffect(()=>{let G=()=>ue((window.scrollY||window.pageYOffset||0)>8);return G(),window.addEventListener("scroll",G,{passive:!0}),()=>window.removeEventListener("scroll",G)},[]);let K="blur(20px) saturate(180%)",O="background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease, border-color .25s ease",Q={paddingTop:"var(--sb-safe-top, 0px)",paddingBottom:"var(--sb-bar-extra, 0px)"},J={position:"fixed",top:0,left:0,right:0,...Q},ge=B?R?{...J,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)",transition:O}:{...J,background:"transparent",backdropFilter:"blur(0px) saturate(100%)",WebkitBackdropFilter:"blur(0px) saturate(100%)",borderBottom:"1px solid transparent",transition:O}:{...Q,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"};return React.createElement("header",{className:B?"header-minimal z-50":"header-minimal sticky top-0 z-50",style:ge},[React.createElement("div",{key:"container",className:"max-w-7xl mx-auto",style:{padding:"0 20px"}},[React.createElement("div",{key:"content",className:"flex items-center justify-between",style:{height:"var(--sb-bar-h, 64px)",gap:"16px"}},[React.createElement("div",{key:"left",style:{display:"flex",alignItems:"center",gap:"12px",minWidth:0}},[React.createElement("div",{key:"logo",style:{width:"36px",height:"36px",flex:"none",display:"grid",placeItems:"center"}},React.createElement("img",{src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{width:"100%",height:"100%",objectFit:"contain",display:"block"}})),React.createElement("div",{key:"txt",style:{lineHeight:1.2,minWidth:0}},[React.createElement("div",{key:"r1",style:{display:"flex",alignItems:"baseline",gap:"7px"}},[React.createElement("span",{key:"n",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-2)"}},"SecureBit"),React.createElement("span",{key:"v",style:{fontFamily:Y,fontSize:"10px",fontWeight:500,color:"var(--sb-text-faint)"}},Ma)]),React.createElement("div",{key:"r2",className:"hidden sm:block",style:{fontSize:"11px",color:"var(--sb-text-9)",fontWeight:500}},f("hdr.tagline"))])]),React.createElement("div",{key:"right",style:{display:"flex",alignItems:"center",gap:"9px"}},[B&&React.createElement(Hr,{key:"lang"}),B&&React.createElement(Gr,{key:"theme"}),!B&&React.createElement("button",{key:"net",type:"button",onClick:()=>window.dispatchEvent(new CustomEvent("securebit:open-network-settings")),title:f("hdr.netSettingsTitle"),"aria-label":f("hdr.netSettings"),className:"sb-disconnect",style:{display:"grid",placeItems:"center",width:"38px",height:"38px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-6)",cursor:"pointer",transition:"all .15s"}},React.createElement("i",{className:"fas fa-network-wired",style:{fontSize:"13px"}})),!B&&k&&React.createElement("div",{key:"sec",onClick:w,onContextMenu:G=>{G.preventDefault(),typeof r=="function"&&r()},title:_.tooltip,className:"sb-secpill",style:{display:"flex",alignItems:"center",gap:"8px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-shield-halved",style:{fontSize:"13px",color:A}}),React.createElement("span",{key:"l",className:"hidden sm:inline",style:{fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-2)"}},f(`secLevel.${k.level}`)===`secLevel.${k.level}`?String(k.level):f(`secLevel.${k.level}`)),React.createElement("span",{key:"s",style:{fontFamily:Y,fontSize:"11.5px",color:"var(--sb-text-7)"}},k.score+"%")]),!B&&React.createElement("div",{key:"status",style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 13px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)"}},[React.createElement("span",{key:"dot",style:{width:"7px",height:"7px",borderRadius:"50%",background:x,boxShadow:"0 0 0 3px "+T}}),React.createElement("span",{key:"t",className:"hidden sm:inline",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-4)"}},F.text)]),i&&React.createElement("button",{key:"dc",onClick:r,className:"sb-disconnect",style:{display:"flex",alignItems:"center",gap:"7px",padding:"8px 14px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"transparent",color:"var(--sb-text-6)",fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:"pointer",transition:"all .15s"}},[React.createElement("i",{key:"i",className:"fas fa-power-off",style:{fontSize:"12px"}}),React.createElement("span",{key:"t",className:"sb-hide-sm"},f("hdr.disconnect"))])])])])])};window.EnhancedMinimalHeader=La;var Jt="1.0.4",qr=`https://github.com/SecureBitChat/securebit-desktop/releases/download/v${Jt}`,Da=()=>{let s=[{id:"web",name:"Web App",subtitle:"Browser Version",icon:"fas fa-globe",platform:"Web",isActive:!0,url:"https://securebit.chat/",color:"green"},{id:"windows",name:"Windows",subtitle:"Desktop App",icon:"fab fa-windows",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64-setup.exe`,color:"blue"},{id:"macos",name:"macOS",subtitle:"Desktop App",icon:"fab fa-safari",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64.dmg`,color:"gray"},{id:"linux",name:"Linux",subtitle:"Desktop App",icon:"fab fa-linux",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_amd64.AppImage`,color:"orange"},{id:"ios",name:"iOS",subtitle:"iPhone & iPad",icon:"fab fa-apple",platform:"Mobile",isActive:!1,url:"https://apps.apple.com/app/securebit-chat/",color:"white"},{id:"android",name:"Android",subtitle:"Google Play",icon:"fab fa-android",platform:"Mobile",isActive:!1,url:"https://play.google.com/store/apps/details?id=com.securebit.chat",color:"green"},{id:"chrome",name:"Chrome",subtitle:"Browser Extension",icon:"fab fa-chrome",platform:"Browser",isActive:!1,url:"#",color:"yellow"},{id:"edge",name:"Edge",subtitle:"Browser Extension",icon:"fab fa-edge",platform:"Browser",isActive:!1,url:"#",color:"blue"},{id:"opera",name:"Opera",subtitle:"Browser Extension",icon:"fab fa-opera",platform:"Browser",isActive:!1,url:"#",color:"red"},{id:"firefox",name:"Firefox",subtitle:"Browser Extension",icon:"fab fa-firefox-browser",platform:"Browser",isActive:!1,url:"#",color:"orange"}],e=c=>{c.isActive&&window.open(c.url,"_blank")},t=s.filter(c=>c.platform==="Desktop"||c.platform==="Web"),r=s.filter(c=>c.platform==="Mobile"),i=s.filter(c=>c.platform==="Browser"),n="w-28 h-28",a={green:"text-green-500",blue:"text-blue-500",gray:"text-gray-500",orange:"text-orange-500",red:"text-red-500",white:"text-white",yellow:"text-yellow-400"},o=c=>React.createElement("div",{key:c.id,className:`group relative ${n} rounded-2xl overflow-hidden card-minimal cursor-pointer`},[React.createElement("i",{key:"bg-icon",className:`${c.icon} absolute text-[3rem] ${c.isActive?a[c.color]:"text-white/10"} top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none transition-all duration-500 group-hover:scale-105`}),React.createElement("div",{key:"overlay",className:"absolute inset-0 bg-black/30 backdrop-blur-md flex flex-col items-center justify-center text-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"},[React.createElement("h4",{key:"name",className:"text-sm font-semibold text-primary mb-1"},c.name),React.createElement("p",{key:"subtitle",className:"text-xs text-secondary mb-2"},c.subtitle),c.isActive?React.createElement("button",{key:"btn",onClick:()=>e(c),className:"px-2 py-1 rounded-xl bg-emerald-500 text-black font-medium hover:bg-emerald-600 transition-colors text-xs"},c.id==="web"?"Launch":"Download"):React.createElement("span",{key:"coming",className:"text-gray-400 font-medium text-xs"},"Coming Soon")])]);return React.createElement("div",{className:"mt-20 px-6"},[React.createElement("div",{key:"header",className:"text-center max-w-3xl mx-auto mb-12"},[React.createElement("h3",{key:"title",className:"text-3xl font-bold text-primary mb-3"},"Download SecureBit.chat"),React.createElement("p",{key:"subtitle",className:"text-secondary text-lg mb-5"},"Stay secure on every device. Choose your platform and start chatting privately.")]),React.createElement("div",{key:"desktop-row",className:"hidden sm:flex justify-center flex-wrap gap-6 mb-6"},t.map(o)),React.createElement("div",{key:"mobile-row",className:"flex justify-center gap-6 mb-6"},r.map(o)),React.createElement("div",{key:"browser-row",className:"flex justify-center gap-6"},i.map(o))])};window.DownloadApps=Da;var Pa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let p=window.matchMedia("(max-width:767px)"),S=()=>e(p.matches);return p.addEventListener?p.addEventListener("change",S):p.addListener(S),()=>{p.removeEventListener?p.removeEventListener("change",S):p.removeListener(S)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",n="'Manrope', system-ui, -apple-system, sans-serif",a="https://docs.google.com/forms/d/e/1FAIpQLSc9ijV9PCoyXkus6vEx1OWwvwAsLq8fKS6-H5BmX-c-bvia6w/viewform?usp=dialog",o=[{id:"aegis",name:"Aegis Investment",logo:"/logo/aegis.png",logoHeight:"42px",url:"https://aegis-investment.com/",desc:f("partners.aegis.desc"),role:f("partners.aegis.role"),delay:".5s"},{id:"furi",name:"FuriLabs",logo:"/logo/furi-160.png",logoHeight:"54px",url:"https://furilabs.com/",desc:f("partners.furilabs.desc"),role:f("partners.furilabs.role"),delay:".56s"}],c=(p,S,g,b,w)=>React.createElement("svg",{className:w,width:S,height:S,viewBox:"0 0 24 24",fill:"none",stroke:g,strokeWidth:b,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:p}}),d=p=>React.createElement("span",{key:"role",style:{fontFamily:i,fontSize:"10.5px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.2px",padding:"6px 11px",borderRadius:"8px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",whiteSpace:"nowrap"}},p),u=p=>React.createElement("a",{key:p.id,href:p.url,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",padding:"30px 30px 26px",display:"flex",flexDirection:"column",textDecoration:"none",color:"inherit",transition:"transform .28s cubic-bezier(.2,.7,.3,1), border-color .28s cubic-bezier(.2,.7,.3,1)",animation:`ptUp ${p.delay} cubic-bezier(.2,.7,.3,1)`},onMouseEnter:S=>{S.currentTarget.style.transform="translateY(-4px)",S.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.13)"},onMouseLeave:S=>{S.currentTarget.style.transform="none",S.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.06)"}},[React.createElement("div",{key:"logo",style:{display:"flex",alignItems:"center",marginBottom:"30px",height:"54px"}},React.createElement("img",{src:p.logo,alt:p.name,loading:"lazy",decoding:"async",style:{height:p.logoHeight,width:"auto",maxWidth:"190px",objectFit:"contain",display:"block"}})),React.createElement("h3",{key:"name",style:{margin:"0 0 9px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},p.name),React.createElement("p",{key:"desc",style:{margin:"0 0 22px",fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},p.desc),React.createElement("div",{key:"foot",style:{marginTop:"auto",paddingTop:"6px",display:"flex",alignItems:"center",gap:"12px"}},[d(p.role)])]),h=React.createElement("a",{key:"invite",href:a,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-bg)",border:"1px dashed rgba(var(--sb-ink), 0.12)",padding:"30px",display:"flex",flexDirection:"column",justifyContent:"space-between",textDecoration:"none",color:"inherit",transition:"border-color .28s cubic-bezier(.2,.7,.3,1)",animation:"ptUp .62s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-orange-rgb), 0.4)"},onMouseLeave:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.12)"}},[React.createElement("div",{key:"top"},[React.createElement("div",{key:"icon",style:{width:"48px",height:"48px",borderRadius:"13px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.28)",marginBottom:"24px"}},c('',23,r,1.9)),React.createElement("h3",{key:"title",style:{margin:"0 0 8px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},f("partners.inviteTitle")),React.createElement("p",{key:"desc",style:{margin:0,fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("partners.inviteDesc"))]),React.createElement("span",{key:"btn",style:{marginTop:"26px",width:"100%",display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"10px",padding:"15px 20px",borderRadius:"12px",border:"none",background:r,color:"var(--sb-on-accent)",fontFamily:n,fontSize:"15px",fontWeight:700,cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",boxSizing:"border-box",transition:"background .2s cubic-bezier(.2,.7,.3,1), transform .2s cubic-bezier(.2,.7,.3,1)"}},[f("partners.inviteCta"),c('',17,"currentColor",2.2,"sb-mirror-rtl")])]),m=React.createElement("div",{key:"inner",style:{maxWidth:"1240px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{marginBottom:"44px"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:i,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"14px"}},f("partners.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:s?"30px":"40px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.04,color:"var(--sb-text-1)"}},f("partners.heading"))]),React.createElement("div",{key:"cards",style:{display:"flex",gap:"18px",alignItems:"stretch",flexWrap:"wrap"}},[...o.map(u),h])]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:n,padding:s?"48px 0":"72px 0",background:"radial-gradient(1100px 640px at 50% -6%, rgba(var(--sb-orange-rgb), 0.055), transparent 62%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ptUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),m])};window.BecomePartner=Pa;var Fa=()=>{let[s,e]=React.useState(0),[t,r]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let E=window.matchMedia("(max-width:767px)"),_=()=>r(E.matches);return E.addEventListener?E.addEventListener("change",_):E.addListener(_),()=>{E.removeEventListener?E.removeEventListener("change",_):E.removeListener(_)}},[]);let i="var(--sb-orange)",n="var(--sb-orange-solid)",a="radial-gradient(130% 90% at 28% 0%, rgba(var(--sb-orange-rgb), 0.11), transparent 60%), var(--sb-surface)",o="rgba(var(--sb-orange-rgb), 0.3)",c="var(--sb-bg)",d="rgba(var(--sb-ink), 0.06)",u="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",h="'Manrope', system-ui, -apple-system, sans-serif",m=[{num:"01",title:[f("unique.s1.titleTop"),f("unique.s1.titleBottom")],collapsed:f("unique.s1.collapsed"),desc:f("unique.s1.desc"),tags:Oe("unique.s1.tags"),icon:''},{num:"02",title:[f("unique.s2.titleTop"),f("unique.s2.titleBottom")],collapsed:f("unique.s2.collapsed"),desc:f("unique.s2.desc"),tags:Oe("unique.s2.tags"),icon:''},{num:"03",title:[f("unique.s3.titleTop"),f("unique.s3.titleBottom")],collapsed:f("unique.s3.collapsed"),desc:f("unique.s3.desc"),tags:Oe("unique.s3.tags"),icon:''},{num:"04",title:[f("unique.s4.titleTop"),f("unique.s4.titleBottom")],collapsed:f("unique.s4.collapsed"),desc:f("unique.s4.desc"),tags:Oe("unique.s4.tags"),icon:''},{num:"05",title:[f("unique.s5.titleTop"),f("unique.s5.titleBottom")],collapsed:f("unique.s5.collapsed"),desc:f("unique.s5.desc"),tags:Oe("unique.s5.tags"),icon:''}],p=(E,_,A,x)=>React.createElement("svg",{width:_,height:_,viewBox:"0 0 24 24",fill:"none",stroke:A,strokeWidth:x,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:E}}),S=E=>e(_=>(_+E+m.length)%m.length),g=(E,_,A)=>React.createElement("button",{key:E,onClick:_,"aria-label":E,className:"sb-mirror-rtl",style:{width:"46px",height:"46px",display:"grid",placeItems:"center",borderRadius:"50%",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.025)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:x=>{x.currentTarget.style.borderColor=o,x.currentTarget.style.color=i},onMouseLeave:x=>{x.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",x.currentTarget.style.color="var(--sb-text-4)"}},p(A,18,"currentColor",2.1)),b=E=>React.createElement("span",{key:E,style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",fontFamily:u,fontSize:"11.5px",fontWeight:500,color:"var(--sb-text-6)"}},[React.createElement("span",{key:"dot",style:{width:"5px",height:"5px",borderRadius:"50%",background:"var(--sb-green-solid)"}}),E]),w=E=>React.createElement("div",{key:"exp",style:{height:"100%",display:"flex",flexDirection:"column",justifyContent:t?"flex-start":"space-between",gap:t?"18px":0,padding:t?"24px 22px":"32px 34px",minWidth:t?"auto":"320px",animation:"wuUp .42s cubic-bezier(.2,.7,.3,1)"}},[React.createElement("div",{key:"top",style:{display:"flex",alignItems:"center",justifyContent:"space-between"}},[React.createElement("div",{key:"ic",style:{width:"54px",height:"54px",borderRadius:"15px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.13)",border:"1px solid rgba(var(--sb-orange-rgb), 0.3)"}},p(E.icon,26,n,1.9)),React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"13px",fontWeight:600,color:"var(--sb-text-9)"}},E.num)]),React.createElement("div",{key:"mid"},[React.createElement("h3",{key:"h",style:{margin:"0 0 12px",fontSize:t?"24px":"30px",fontWeight:800,letterSpacing:"-0.7px",lineHeight:1.08,color:"var(--sb-text-1)"}},[E.title[0],React.createElement("br",{key:"br"}),E.title[1]]),React.createElement("p",{key:"p",style:{margin:0,fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-6)",maxWidth:"380px"}},E.desc)]),React.createElement("div",{key:"tags",style:{display:"flex",flexWrap:"wrap",gap:"8px"}},E.tags.map(b))]),M=E=>t?React.createElement("div",{key:"col",style:{display:"flex",alignItems:"center",gap:"16px",padding:"20px 22px"}},[React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)"}},E.collapsed)]):React.createElement("div",{key:"col",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"space-between",padding:"24px 0"}},[React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{writingMode:"vertical-rl",transform:"rotate(180deg)",fontSize:"17px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)",whiteSpace:"nowrap"}},E.collapsed),p(E.icon,22,"var(--sb-text-faint)",1.8)]),F=m.map((E,_)=>{let A=s===_;return React.createElement("div",{key:_,onClick:()=>e(_),onMouseEnter:x=>{A||(x.currentTarget.style.filter="brightness(1.18)")},onMouseLeave:x=>{x.currentTarget.style.filter="none"},style:{flex:t?"none":A?6.2:1,minWidth:t?"auto":"72px",position:"relative",borderRadius:"18px",overflow:"hidden",cursor:"pointer",background:A?a:c,border:"1px solid "+(A?o:d),color:"var(--sb-text-7)",transition:"flex .46s cubic-bezier(.2,.7,.3,1), background .3s ease, border-color .3s ease, filter .2s ease"}},A?w(E):M(E))}),k=React.createElement("div",{key:"inner",style:{maxWidth:"1180px",margin:"0 auto",padding:t?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{display:"flex",alignItems:"flex-end",justifyContent:"space-between",gap:"24px",marginBottom:"28px"}},[React.createElement("div",{key:"titles"},[React.createElement("div",{key:"eyebrow",style:{fontFamily:u,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.4px",marginBottom:"12px"}},f("unique.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:t?"28px":"38px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("unique.heading"))]),React.createElement("div",{key:"nav",style:{display:"flex",alignItems:"center",gap:"10px",flex:"none"}},[g("prev",()=>S(-1),''),g("next",()=>S(1),'')])]),React.createElement("div",{key:"accordion",style:{display:"flex",flexDirection:t?"column":"row",gap:t?"12px":"14px",height:t?"auto":"440px"}},F)]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:h,padding:t?"44px 0":"64px 0",background:"radial-gradient(1100px 700px at 18% 8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes wuUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}"}}),k])};window.UniqueFeatureSlider=Fa;function Ka(){let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let w=window.matchMedia("(max-width:767px)"),M=()=>e(w.matches);return w.addEventListener?w.addEventListener("change",M):w.addListener(M),()=>{w.removeEventListener?w.removeEventListener("change",M):w.removeListener(M)}},[]);let t="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",r="'Manrope', system-ui, -apple-system, sans-serif",i=[{v:"v1.0",k:"r1",status:"released"},{v:"v1.5",k:"r2",status:"released"},{v:"v2.0",k:"r3",status:"released"},{v:"v3.0",k:"r4",status:"released"},{v:"v3.5",k:"r5",status:"released"},{v:"v4.5",k:"r6",status:"released"},{v:"v5.0",k:"r7",status:"released"},{v:"v5.5",k:"r8",status:"released"},{v:"v6.0",k:"r9",status:"current"},{v:"v6.5",k:"r10",status:"dev"},{v:"v7.0",k:"r11",status:"planned"},{v:"v7.5",k:"r12",status:"research"},{v:"v8.0",k:"r13",status:"research"}].map(w=>({...w,title:f(`roadmap.${w.k}.title`),sub:f(`roadmap.${w.k}.sub`),date:f(`roadmap.${w.k}.date`),features:Oe(`roadmap.${w.k}.features`)})),n={released:{solid:"var(--sb-green-solid)",line:"rgba(var(--sb-green-rgb), 0.32)"},current:{solid:"var(--sb-orange-solid)",line:"rgba(var(--sb-orange-rgb), 0.32)"},dev:{solid:"var(--sb-yellow-2-solid)",line:"rgba(var(--sb-ink), 0.08)"},planned:{solid:"var(--sb-text-7)",line:"rgba(var(--sb-ink), 0.08)"},research:{solid:"var(--sb-text-9)",line:"rgba(var(--sb-ink), 0.08)"}},[a,o]=React.useState({}),c=w=>a[w]===void 0?i[w].status==="current":a[w],d=w=>o(M=>({...M,[w]:!c(w)})),u=i.length,h=i.filter(w=>w.status==="released"||w.status==="current").length,m=u-h,p=(h/u*100).toFixed(1)+"%",[S,g]=f("roadmap.progress",{total:u}).split("{shipped}"),b=w=>w==="released"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-green-rgb), 0.16),rgba(var(--sb-green-rgb), 0.16)), var(--sb-bg)",border:"1px solid rgba(var(--sb-green-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:"2.4",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M5 13l4 4 10-11"}))):w==="current"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-orange-rgb), 0.2),rgba(var(--sb-orange-rgb), 0.2)), var(--sb-bg)",border:"1px solid var(--sb-orange-solid)",zIndex:2,animation:"rmPulse 2.4s ease-out infinite"}},React.createElement("span",{style:{width:"9px",height:"9px",borderRadius:"50%",background:"var(--sb-orange-solid)"}})):w==="dev"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-yellow-2-rgb), 0.15),rgba(var(--sb-yellow-2-rgb), 0.15)), var(--sb-bg)",border:"1px solid rgba(var(--sb-yellow-2-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-yellow-2-solid)",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M12 3a9 9 0 1 0 9 9"}))):React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"var(--sb-bg)",border:`1px ${w==="research"?"dashed":"solid"} rgba(var(--sb-ink), 0.18)`,zIndex:2}},React.createElement("span",{style:{width:"7px",height:"7px",borderRadius:"50%",background:n[w].solid}}));return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:r,padding:s?"48px 0":"64px 0",background:"radial-gradient(1200px 720px at 50% -8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},React.createElement("style",{dangerouslySetInnerHTML:{__html:"@keyframes rmExp{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes rmPulse{0%,100%{box-shadow:0 0 0 0 rgba(var(--sb-orange-rgb), 0.18)}60%{box-shadow:0 0 0 9px rgba(var(--sb-orange-rgb), 0)}}"}}),React.createElement("div",{style:{maxWidth:"1040px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},React.createElement("div",{style:{marginBottom:"30px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"13px"}},f("roadmap.eyebrow")),React.createElement("h2",{style:{margin:"0 0 14px",fontSize:s?"27px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("roadmap.heading")),React.createElement("p",{style:{margin:0,fontSize:"15.5px",lineHeight:1.6,color:"var(--sb-text-7)",maxWidth:"660px"}},f("roadmap.subheading"))),React.createElement("div",{style:{display:"flex",alignItems:"center",gap:"18px",flexWrap:"wrap",padding:"18px 22px",borderRadius:"14px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",marginBottom:"36px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"12px",fontWeight:600,color:"var(--sb-text-2)",whiteSpace:"nowrap"}},S,React.createElement("span",{style:{color:"var(--sb-green)"}},h),g),React.createElement("div",{style:{flex:"1 1 240px",minWidth:"200px",height:"8px",borderRadius:"99px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.06)",overflow:"hidden"}},React.createElement("div",{style:{height:"100%",width:p,background:"linear-gradient(90deg, var(--sb-green), var(--sb-orange))"}})),React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},f("roadmap.upcoming",{upcoming:m}))),i.map((w,M)=>{let F=n[w.status],k=c(M),E=Md(M),style:{display:"flex",alignItems:"center",gap:s?"11px":"16px",padding:s?"16px 16px":"18px 22px",cursor:"pointer",transition:"background .18s ease"},onMouseEnter:_=>{_.currentTarget.style.background="rgba(var(--sb-ink), 0.018)"},onMouseLeave:_=>{_.currentTarget.style.background="transparent"}},React.createElement("div",{style:{flex:"none",minWidth:"52px",textAlign:"center",padding:"7px 10px",borderRadius:"9px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.07)",fontFamily:t,fontSize:"13px",fontWeight:700,color:w.status==="current"?"var(--sb-orange)":"var(--sb-text-4)"}},w.v),React.createElement("div",{style:{flex:1,minWidth:0}},React.createElement("div",{style:{fontSize:s?"15.5px":"17px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},w.title),!s&&React.createElement("div",{style:{marginTop:"3px",fontSize:"13.5px",color:"var(--sb-text-6)"}},w.sub)),React.createElement("div",{style:{flex:"none",display:"flex",alignItems:"center",gap:s?"8px":"14px"}},!s&&React.createElement("span",{style:{fontFamily:t,fontSize:"12px",fontWeight:500,color:"var(--sb-text-7)",whiteSpace:"nowrap",minWidth:"74px",textAlign:"end"}},w.date),React.createElement("span",{style:{color:"var(--sb-text-9)",display:"inline-flex",transition:"transform .22s cubic-bezier(.2,.7,.3,1)",transform:k?"rotate(180deg)":"rotate(0deg)"}},React.createElement("svg",{width:"17",height:"17",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.1",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M6 9l6 6 6-6"}))))),k&&React.createElement("div",{style:{padding:"4px 22px 22px 22px",animation:"rmExp .24s cubic-bezier(.2,.7,.3,1)"}},React.createElement("div",{style:{fontFamily:t,fontSize:"10px",fontWeight:600,color:"var(--sb-text-faint)",textTransform:"uppercase",letterSpacing:"1.2px",marginBottom:"14px",paddingTop:"14px",borderTop:"1px solid rgba(var(--sb-ink), 0.05)"}},f("roadmap.keyFeatures")),React.createElement("div",{style:{display:"grid",gridTemplateColumns:s?"1fr":"1fr 1fr",gap:"11px 28px"}},w.features.map((_,A)=>React.createElement("div",{key:A,style:{display:"flex",alignItems:"flex-start",gap:"10px"}},React.createElement("span",{style:{flex:"none",marginTop:"7px",width:"5px",height:"5px",borderRadius:"50%",background:F.solid}}),React.createElement("span",{style:{fontSize:"13.5px",lineHeight:1.5,color:"var(--sb-text-4)"}},_)))))))})))}window.Roadmap=Ka;var Et=[{id:"usdt",tab:"USDT",coin:"Tether USDT",badge:"trx",address:"TMopDoco5EwJB1QvQYsuhjUJdMvzPXNQYu"},{id:"btc",tab:"BTC",coin:"Bitcoin",badge:null,address:"bc1qnmc2xl7p0pxcy6lzf2tyf52wnslgzkgaq9kxpr"},{id:"eth",tab:"ETH",coin:"Ethereum",badge:null,address:"0xCDfDfaD4EC1fa657C3d2A7EFabc1cb751bf1dAf7"}],jr=s=>`/assets/crypto/${s}.svg`,Wr="__sbScrollToDonate",Yr="securebit:scroll-to-donate",Na=5e3,Xr=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches),[t,r]=React.useState(0),[i,n]=React.useState(!1),[a,o]=React.useState(0),c=React.useRef(null),d=React.useRef(null),u=React.useRef(null);React.useEffect(()=>{let K=window.matchMedia("(max-width:767px)"),O=()=>e(K.matches);return K.addEventListener?K.addEventListener("change",O):K.addListener(O),()=>{K.removeEventListener?K.removeEventListener("change",O):K.removeListener(O),clearTimeout(u.current)}},[]),React.useEffect(()=>{let K=null,O=()=>{let Q=window[Wr];window[Wr]=0,!(!Q||Date.now()-Q>Na)&&(clearTimeout(K),K=setTimeout(()=>{let J=d.current;if(!J)return;let ge=window.matchMedia("(prefers-reduced-motion: reduce)").matches;J.scrollIntoView({behavior:ge?"auto":"smooth",block:"center"})},350))};return O(),document.addEventListener(Yr,O),()=>{document.removeEventListener(Yr,O),clearTimeout(K)}},[]);let h=Et[t],m=K=>{let O=(K+Et.length)%Et.length;O!==t&&(o(K>t?1:-1),r(O),n(!1))},p=K=>{let O=K.touches[0];c.current={x:O.clientX,y:O.clientY}},S=K=>{let O=c.current;if(c.current=null,!O)return;let Q=K.changedTouches[0],J=Q.clientX-O.x,ge=Q.clientY-O.y;if(Math.abs(J)<40||Math.abs(J)0:J<0;m(t+(G?1:-1))},g=async()=>{try{await navigator.clipboard.writeText(h.address)}catch{let O=document.createElement("textarea");O.value=h.address,document.body.appendChild(O),O.select();try{document.execCommand("copy")}catch{}O.remove()}n(!0),clearTimeout(u.current),u.current=setTimeout(()=>n(!1),1800)},b="'Manrope', system-ui, -apple-system, sans-serif",w="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",M={borderRadius:"14px",background:"var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)"},F=React.createElement("div",{key:"tabs",role:"tablist",style:{...M,display:"flex",gap:"6px",padding:"5px",marginBottom:"14px"}},Et.map((K,O)=>{let Q=O===t;return React.createElement("button",{key:K.id,type:"button",role:"tab","aria-selected":Q,onClick:()=>m(O),style:{flex:"1 1 0",minWidth:0,display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"9px",padding:"11px 10px",borderRadius:"10px",border:"none",cursor:"pointer",fontFamily:b,fontSize:"14px",fontWeight:700,transition:"all .18s",background:Q?"var(--sb-surface-2)":"transparent",color:Q?"var(--sb-text-1)":"var(--sb-text-7)",boxShadow:Q?"inset 0 0 0 1px rgba(var(--sb-orange-rgb), 0.45)":"none"}},[React.createElement("span",{key:"ic",style:{position:"relative",flex:"none",width:"22px",height:"22px"}},[React.createElement("img",{key:"logo",src:jr(K.id),alt:"",width:22,height:22,style:{display:"block",width:"22px",height:"22px"}}),K.badge&&React.createElement("img",{key:"badge",src:jr(K.badge),alt:"",width:11,height:11,style:{position:"absolute",right:"-3px",bottom:"-3px",width:"11px",height:"11px",borderRadius:"50%",border:"1.5px solid var(--sb-surface-2)",background:"var(--sb-surface-2)"}})]),K.tab])})),k=React.createElement("button",{key:"copy",type:"button",onClick:g,style:{flex:"none",display:"inline-flex",alignItems:"center",gap:"8px",padding:"12px 16px",borderRadius:"10px",fontFamily:b,fontSize:"13.5px",fontWeight:700,cursor:"pointer",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-2)",border:"1px solid rgba(var(--sb-ink), 0.1)",transition:"all .18s"},onMouseEnter:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.09)"},onMouseLeave:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.05)"}},[i?React.createElement("svg",{key:"ok",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}):React.createElement("svg",{key:"cp",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),React.createElement("span",{key:"l","aria-live":"polite"},i?f("donate.copied"):f("donate.copy"))]),E=React.createElement("div",{key:"addr",style:{...M,display:"flex",alignItems:"center",gap:"12px",padding:"8px 8px 8px 18px"}},[React.createElement("div",{key:"tx",style:{flex:1,minWidth:0}},[React.createElement("div",{key:"net",style:{fontSize:"11.5px",fontWeight:600,color:"var(--sb-text-9)",marginBottom:"2px"}},f(`donate.net.${h.id}`)),React.createElement("div",{key:"a",title:h.address,dir:"ltr",style:{fontFamily:w,fontSize:"14px",color:"var(--sb-text-2)",letterSpacing:"0.3px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},h.address.slice(0,8)+"\u2026"+h.address.slice(-8))]),k]),_=React.createElement("div",{key:"warn",style:{display:"flex",alignItems:"center",gap:"7px",marginTop:"14px",fontSize:"12px",color:"var(--sb-text-9)"}},[React.createElement("svg",{key:"i",width:13,height:13,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-orange-solid)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{flex:"none"},dangerouslySetInnerHTML:{__html:''}}),f(`donate.warn.${h.id}`)]),A=React.createElement("div",{key:"left",style:{flex:"1 1 440px",minWidth:0,padding:s?"32px 22px 8px":"44px",display:"flex",flexDirection:"column"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:w,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.8px",marginBottom:"14px"}},f("donate.eyebrow")),React.createElement("h2",{key:"title",style:{margin:"0 0 10px",fontSize:s?"28px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("donate.title")),React.createElement("p",{key:"desc",style:{margin:"0 0 30px",fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("donate.description")),F,E,_]),x=Pt()?-1:1,T=a===0?"none":`${a*x>0?"cdInEnd":"cdInStart"} .28s cubic-bezier(.2,.7,.3,1)`,Y=React.createElement("div",{key:"plate",onTouchStart:p,onTouchEnd:S,style:{position:"relative",width:"232px",height:"232px",padding:"14px",borderRadius:"20px",background:"#fff",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",border:"1px solid rgba(var(--sb-ink), 0.07)",overflow:"hidden",touchAction:"pan-y",userSelect:"none"}},React.createElement("div",{key:h.id,style:{position:"relative",width:"100%",height:"100%",animation:T}},[React.createElement("img",{key:"qr",src:`/assets/crypto/qr-${h.id}.svg`,alt:f("donate.qrAlt",{coin:h.coin}),width:204,height:204,draggable:!1,style:{display:"block",width:"100%",height:"100%",imageRendering:"pixelated"}}),React.createElement("div",{key:"logo",style:{position:"absolute",left:"50%",top:"50%",transform:"translate(-50%,-50%)",width:"48px",height:"48px",borderRadius:"12px",background:"#fff",display:"grid",placeItems:"center"}},React.createElement("img",{src:jr(h.id),alt:"",width:34,height:34,draggable:!1,style:{display:"block",width:"34px",height:"34px"}}))])),B=s&&React.createElement("div",{key:"dots","aria-hidden":!0,style:{display:"flex",justifyContent:"center",gap:"7px",marginTop:"18px"}},Et.map((K,O)=>React.createElement("span",{key:K.id,style:{width:O===t?"18px":"7px",height:"7px",borderRadius:"4px",transition:"all .25s",background:O===t?"var(--sb-orange-solid)":"rgba(var(--sb-ink), 0.16)"}}))),R=React.createElement("div",{key:"right",style:{flex:"0 0 auto",minWidth:s?0:"300px",margin:"0 auto",padding:s?"24px 22px 32px":"44px",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[Y,B]),ue=React.createElement("div",{key:"card",style:{width:"100%",maxWidth:"1000px",position:"relative",overflow:"hidden",borderRadius:"24px",background:"radial-gradient(520px 420px at 100% 50%, rgba(var(--sb-orange-rgb), 0.09), transparent 70%), var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.07)",display:"flex",flexWrap:"wrap",alignItems:"stretch",animation:"cdUp .45s cubic-bezier(.2,.7,.3,1)"}},[A,R]);return React.createElement("section",{id:"donate",ref:d,style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",color:"var(--sb-text-2)",fontFamily:b,padding:s?"48px 18px":"64px 32px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:'@keyframes cdUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes cdInEnd{from{opacity:0;transform:translateX(36px)}to{opacity:1;transform:none}}@keyframes cdInStart{from{opacity:0;transform:translateX(-36px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion: reduce){#donate [style*="cdIn"]{animation:none!important}}'}}),ue])};Xr.SCROLL_FLAG=Wr;Xr.SCROLL_EVENT=Yr;window.DonateCrypto=Xr;var Oa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let u=window.matchMedia("(max-width:767px)"),h=()=>e(u.matches);return u.addEventListener?u.addEventListener("change",h):u.addListener(h),()=>{u.removeEventListener?u.removeEventListener("change",h):u.removeListener(h)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'Manrope', system-ui, -apple-system, sans-serif",n="https://github.com/SecureBitChat/securebit-chat/",a="mailto:lockbitchat@tutanota.com",o=React.createElement("a",{key:"gh",href:n,target:"_blank",rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:r,color:"var(--sb-on-accent)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:u=>{u.currentTarget.style.background="var(--sb-orange-hi)",u.currentTarget.style.transform="translateY(-2px)"},onMouseLeave:u=>{u.currentTarget.style.background=r,u.currentTarget.style.transform="none"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"currentColor",dangerouslySetInnerHTML:{__html:''}}),f("community.github")]),c=React.createElement("a",{key:"fb",href:a,rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:"rgba(var(--sb-ink), 0.03)",color:"var(--sb-text-2)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",border:"1px solid rgba(var(--sb-ink), 0.1)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:u=>{u.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.24)",u.currentTarget.style.background="rgba(var(--sb-ink), 0.06)"},onMouseLeave:u=>{u.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",u.currentTarget.style.background="rgba(var(--sb-ink), 0.03)"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.9,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),f("community.feedback")]),d=React.createElement("div",{key:"card",style:{position:"relative",overflow:"hidden",maxWidth:"860px",width:"100%",borderRadius:"24px",background:"radial-gradient(700px 360px at 50% 0%, rgba(var(--sb-orange-rgb), 0.1), transparent 65%), var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)",padding:s?"40px 24px 36px":"56px 56px 48px",textAlign:"center",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))"}},[React.createElement("div",{key:"hairline",style:{position:"absolute",top:0,left:"50%",transform:"translateX(-50%)",width:"180px",height:"1px",background:"linear-gradient(90deg, transparent, rgba(var(--sb-orange-rgb), 0.7), transparent)"}}),React.createElement("img",{key:"icon",src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{display:"inline-block",width:"64px",height:"64px",objectFit:"contain",marginBottom:"22px",animation:"ccUp .4s cubic-bezier(.2,.7,.3,1)"}}),React.createElement("h2",{key:"title",style:{margin:"0 0 16px",fontSize:s?"28px":"36px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("community.title")),React.createElement("p",{key:"desc",style:{margin:"0 auto 32px",maxWidth:"560px",fontSize:"16px",lineHeight:1.65,color:"var(--sb-text-6)"}},f("community.description")),React.createElement("div",{key:"btns",style:{display:"flex",gap:"14px",justifyContent:"center",flexWrap:"wrap"}},[o,c]),React.createElement("div",{key:"snap",style:{display:"flex",justifyContent:s?"center":"flex-end",marginTop:"28px"}},React.createElement("a",{href:"https://snapcraft.io/securebit-chat",target:"_blank",rel:"noopener noreferrer","aria-label":"Get it from the Snap Store",style:{display:"inline-flex",opacity:.9,transition:"opacity .2s"},onMouseEnter:u=>{u.currentTarget.style.opacity=1},onMouseLeave:u=>{u.currentTarget.style.opacity=.9}},React.createElement("img",{src:"/assets/badges/snap-store.svg",alt:"Get it from the Snap Store",width:182,height:56,loading:"lazy",style:{display:"block"}})))]);return React.createElement("section",{style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",fontFamily:i,padding:s?"48px 18px":"64px 48px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ccUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),d])};window.CommunityCTA=Oa;var Ua=({webrtcManager:s,isConnected:e,pendingIncomingFiles:t=[],onIncomingDecision:r,showDropzone:i=!0})=>{let[n,a]=React.useState(!1),[o,c]=React.useState({sending:[],receiving:[]}),d=React.useRef(null);React.useEffect(()=>{if(!e||!s)return;let A=setInterval(()=>{let x=s.getFileTransfers();c(x)},500);return()=>clearInterval(A)},[e,s]),React.useEffect(()=>{e||c({sending:[],receiving:[]})},[e]);let u=async _=>{if(!e||!s){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435.");return}if(!s.isConnected()||!s.isVerified){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0444\u0430\u0439\u043B\u043E\u0432. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F.");return}for(let A of _)try{let x=s.validateFile(A);if(!x.isValid){let T=x.errors.join(". ");alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${T}`);continue}await s.sendFile(A)}catch(x){x.message.includes(f("file.notReady"))?alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0441\u0435\u0439\u0447\u0430\u0441. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430.`):x.message.includes(f("file.tooLarge"))||x.message.includes("exceeds maximum")?alert(`\u0424\u0430\u0439\u043B ${A.name} \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439: ${x.message}`):x.message.includes(f("file.maxConcurrent"))?alert("\u0414\u043E\u0441\u0442\u0438\u0433\u043D\u0443\u0442 \u043B\u0438\u043C\u0438\u0442 \u043E\u0434\u043D\u043E\u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0442\u0435\u043A\u0443\u0449\u0438\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447."):x.message.includes(f("file.typeNotAllowed"))?alert(`\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 ${A.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F: ${x.message}`):alert(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${A.name}: ${x.message}`)}},h=_=>{_.preventDefault(),a(!1);let A=Array.from(_.dataTransfer.files);u(A)},m=_=>{_.preventDefault(),a(!0)},p=_=>{_.preventDefault(),a(!1)},S=_=>{let A=Array.from(_.target.files);u(A),_.target.value=""},g=_=>{if(_===0)return"0 B";let A=1024,x=["B","KB","MB","GB"],T=Math.floor(Math.log(_)/Math.log(A));return parseFloat((_/Math.pow(A,T)).toFixed(2))+" "+x[T]},b=_=>{switch(_){case"metadata_sent":case"preparing":return"fas fa-cog fa-spin";case"transmitting":case"receiving":return"fas fa-exchange-alt fa-pulse";case"assembling":return"fas fa-puzzle-piece fa-pulse";case"completed":return"fas fa-check text-green-400";case"failed":return"fas fa-times text-red-400";default:return"fas fa-circle"}},w=_=>{switch(_){case"metadata_sent":return"\u041F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0430...";case"transmitting":return"\u041E\u0442\u043F\u0440\u0430\u0432\u043A\u0430...";case"receiving":return"\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435...";case"assembling":return"\u0421\u0431\u043E\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u0430...";case"completed":return"\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E";case"failed":return"\u041E\u0448\u0438\u0431\u043A\u0430";default:return _}},M=(_,A)=>{let x=_.totalChunks||0,T=_.transferredChunks||0,Y=_.status==="completed",B=x>0?Math.min(x,32):24,R;return Y?R=B:x>0?R=Math.floor(T/x*B):R=Math.floor((_.progress||0)/100*B),R=Math.max(0,Math.min(B,R)),React.createElement("div",{key:"progress"},[React.createElement("div",{key:"squares",style:{display:"flex",flexWrap:"wrap",gap:"3px",marginBottom:"7px"}},Array.from({length:B},(ue,K)=>React.createElement("div",{key:K,style:{width:"11px",height:"11px",borderRadius:"2px",background:K0?`${Math.min(T,x)} / ${x} chunks`:`${(_.progress||0).toFixed(0)}%`)])])},F=_=>_.status==="completed",k=async(_,A)=>{typeof r=="function"&&await r(_,A),c(s.getFileTransfers())};return e?s&&s.isConnected()&&s.isVerified?React.createElement("div",{className:"file-transfer-component"},[i&&React.createElement("div",{key:"drop-zone",onDrop:h,onDragOver:m,onDragLeave:p,style:{position:"relative",border:"1.5px dashed "+(n?"rgba(var(--sb-orange-rgb), 0.7)":"rgba(var(--sb-ink), 0.14)"),borderRadius:"14px",background:n?"rgba(var(--sb-orange-rgb), 0.07)":"var(--sb-surface)",padding:"24px 22px",textAlign:"center",transition:"all .15s"}},[React.createElement("div",{key:"icon-box",style:{width:"42px",height:"42px",margin:"0 auto 10px",borderRadius:"12px",display:"grid",placeItems:"center",background:"rgba(var(--sb-ink), 0.04)",border:"1px solid rgba(var(--sb-ink), 0.08)"}},React.createElement("i",{className:"fas fa-arrow-up-from-bracket",style:{color:"var(--sb-text-6)",fontSize:"18px"}})),React.createElement("div",{key:"title",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-2)"}},f("file.drop")),React.createElement("div",{key:"sub",style:{fontSize:"12px",color:"var(--sb-text-8)",marginTop:"4px"}},f("file.dropHint")),React.createElement("button",{key:"browse",type:"button",onClick:()=>d.current?.click(),className:"sb-send",style:{marginTop:"14px",display:"inline-flex",alignItems:"center",gap:"7px",padding:"9px 16px",borderRadius:"9px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-folder-open",style:{fontSize:"13px"}}),f("file.browse")])]),i&&React.createElement("input",{key:"file-input",ref:d,type:"file",multiple:!0,className:"hidden",onChange:S}),t.length>0&&React.createElement("div",{key:"incoming-consent",className:"mt-4 space-y-2"},t.map(_=>React.createElement("div",{key:_.fileId,style:{borderRadius:"12px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",padding:"12px 14px"}},[React.createElement("div",{key:"info",style:{marginBottom:"12px",display:"flex",alignItems:"center",gap:"11px"}},[React.createElement("div",{key:"ic",style:{flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.22)"}},React.createElement("i",{className:"fas fa-file-arrow-down",style:{color:"var(--sb-orange)",fontSize:"15px"}})),React.createElement("div",{key:"text",style:{minWidth:0}},[React.createElement("div",{key:"title",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-2)"}},f("file.incoming")),React.createElement("div",{key:"meta",style:{fontSize:"11.5px",color:"var(--sb-text-8)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},`${_.fileName} \xB7 ${g(_.fileSize)} \xB7 ${_.mimeType}`)])]),React.createElement("div",{key:"actions",style:{display:"flex",gap:"8px"}},[React.createElement("button",{key:"accept",onClick:()=>k(_.fileId,!0),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",padding:"8px 14px",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-check",style:{fontSize:"12px"}}),f("file.accept")]),React.createElement("button",{key:"reject",onClick:()=>k(_.fileId,!1),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"rgba(var(--sb-red-rgb), 0.08)",color:"var(--sb-red)",padding:"8px 14px",fontSize:"13px",fontWeight:600,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-xmark",style:{fontSize:"12px"}}),f("file.reject")])])]))),(o.sending.length>0||o.receiving.length>0)&&React.createElement("div",{key:"transfers",className:"active-transfers mt-4"},[React.createElement("h4",{key:"title",style:{display:"flex",alignItems:"center",gap:"8px",fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-7)",marginBottom:"10px"}},[React.createElement("i",{key:"icon",className:"fas fa-right-left",style:{fontSize:"12px"}}),f("file.title")]),...o.sending.map(_=>React.createElement("div",{key:`send-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-up",style:{color:"var(--sb-orange)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(_.fileSize))]),React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])]),M(_,"var(--sb-orange)")])),...o.receiving.map(_=>React.createElement("div",{key:`recv-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-down",style:{color:"var(--sb-green)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(_.fileSize))]),React.createElement("div",{key:"actions",className:"flex items-center space-x-2"},[_.status==="completed"?React.createElement("button",{key:"download",className:"text-green-400 hover:text-green-300 text-xs flex items-center",onClick:async()=>{try{let A=await s.getReceivedFileObjectURL(_.fileId);if(!A){alert(f("file.gone"));return}let x=document.createElement("a");x.href=A,x.download=_.fileName||"file",x.click(),setTimeout(()=>s.revokeReceivedFileObjectURL(A),1e4)}catch(A){alert(A.message||f("file.gone"))}}},[React.createElement("i",{key:"i",className:"fas fa-download me-1"}),f("file.download")]):null,React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])])]),M(_,"var(--sb-green)")]))])]):React.createElement("div",{className:"p-4 text-center text-yellow-600"},[React.createElement("i",{key:"icon",className:"fas fa-exclamation-triangle me-2"}),"\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F... \u041F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u0431\u0443\u0434\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043F\u043E\u0441\u043B\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438."]):React.createElement("div",{className:"p-4 text-center text-muted"},f("file.needConnection"))};window.FileTransferComponent=Ua;var ze=Object.freeze({MAX_SERVERS:10,MAX_URLS_PER_SERVER:8,MAX_STRING_LENGTH:512}),Jo=Object.freeze(["stun","stuns","turn","turns"]),za=/^(stuns?|turns?):/i,Va=/^(\[[0-9a-f:]+\]|[a-z0-9.-]+)(:\d{1,5})?$/i,Ba=/^transport=(udp|tcp)$/i;function On(s){for(let e=0;eze.MAX_STRING_LENGTH)return f("iceUrl.tooLong");if(On(e))return f("iceUrl.badChars");let t=e.match(za);if(!t)return f("iceUrl.badScheme");let r=e.slice(t[0].length),[i,n,...a]=r.split("?");return a.length>0?f("iceUrl.badQuery"):i?Va.test(i)?n!==void 0&&!Ba.test(n)?f("iceUrl.badTransport"):null:f("iceUrl.badHost"):f("iceUrl.noHost")}function Un(s){return typeof s=="string"&&/^turns?:/i.test(s.trim())}function Kn(s,e){return s==null||s===""?null:typeof s!="string"?`${e} must be a string`:s.length>ze.MAX_STRING_LENGTH?`${e} is too long`:On(s)?`${e} contains invalid characters`:null}function Nn(s){let e=[],t=[],r=[];return Array.isArray(s)?s.length===0?{servers:[],errors:[],warnings:[]}:s.length>ze.MAX_SERVERS?(e.push(f("iceErr.tooMany",{max:ze.MAX_SERVERS})),{servers:[],errors:e,warnings:t}):(s.forEach((i,n)=>{let a=`Server #${n+1}`;if(!i||typeof i!="object"){e.push(f("iceErr.invalidEntry",{label:a}));return}let o=Array.isArray(i.urls)?i.urls:[i.urls];if(o.length===0||o.length>ze.MAX_URLS_PER_SERVER){e.push(f("iceErr.urlCount",{label:a,max:ze.MAX_URLS_PER_SERVER}));return}let c=[],d=!1;for(let p of o){let S=Ha(p);if(S){e.push(`${a}: ${S}`);continue}let g=p.trim();c.push(g),Un(g)&&(d=!0)}if(c.length===0)return;let u=Kn(i.username,`${a} username`);u&&e.push(u);let h=Kn(i.credential,`${a} credential`);h&&e.push(h);let m={urls:c.length===1?c[0]:c};i.username&&(m.username=String(i.username)),i.credential&&(m.credential=String(i.credential)),d&&(!m.username||!m.credential)&&t.push(f("iceErr.turnCreds",{label:a})),r.push(m)}),{servers:r,errors:e,warnings:t}):{servers:[],errors:[f("iceErr.notArray")],warnings:[]}}function zn(s){if(typeof s!="string"||!s.trim())return{servers:[],errors:[],warnings:[]};let e=s.trim();if(e.startsWith("[")||e.startsWith("{")){let r;try{r=JSON.parse(e)}catch{return{servers:[],errors:[f("iceErr.invalidJson")],warnings:[]}}let i=Array.isArray(r)?r:[r];return Nn(i)}let t=e.split(` +Right-click or Ctrl+click to disconnect`,isVerified:!1,dataSource:"estimated"}})();React.useEffect(()=>(window.debugHeaderSecurity=void 0,()=>{delete window.debugHeaderSecurity}),[o,d,i,a,k,_]);let A=k?k.color==="green"?"var(--sb-green)":k.color==="orange"?"var(--sb-orange)":k.color==="yellow"?"var(--sb-yellow)":"var(--sb-red)":"var(--sb-green)",x=i?"var(--sb-green-solid)":["connecting","verifying","retrying","reconnecting"].includes(s)?"var(--sb-yellow-solid)":s==="failed"?"var(--sb-red-solid)":"var(--sb-text-9)",T=x==="var(--sb-green-solid)"?"rgba(var(--sb-green-rgb), 0.16)":x==="var(--sb-yellow-solid)"?"rgba(var(--sb-yellow-rgb), 0.16)":x==="var(--sb-red-solid)"?"rgba(var(--sb-red-rgb), 0.16)":"rgba(var(--sb-text-9-rgb), 0.16)",Y="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",B=!i,[R,ue]=React.useState(!1);React.useEffect(()=>{let G=()=>ue((window.scrollY||window.pageYOffset||0)>8);return G(),window.addEventListener("scroll",G,{passive:!0}),()=>window.removeEventListener("scroll",G)},[]);let K="blur(20px) saturate(180%)",O="background .25s ease, backdrop-filter .25s ease, -webkit-backdrop-filter .25s ease, border-color .25s ease",Q={paddingTop:"var(--sb-safe-top, 0px)",paddingBottom:"var(--sb-bar-extra, 0px)"},J={position:"fixed",top:0,left:0,right:0,...Q},ge=B?R?{...J,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)",transition:O}:{...J,background:"transparent",backdropFilter:"blur(0px) saturate(100%)",WebkitBackdropFilter:"blur(0px) saturate(100%)",borderBottom:"1px solid transparent",transition:O}:{...Q,background:"rgba(var(--sb-bg-rgb), 0.72)",backdropFilter:K,WebkitBackdropFilter:K,borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"};return React.createElement("header",{className:B?"header-minimal z-50":"header-minimal sticky top-0 z-50",style:ge},[React.createElement("div",{key:"container",className:"max-w-7xl mx-auto",style:{padding:"0 20px"}},[React.createElement("div",{key:"content",className:"flex items-center justify-between",style:{height:"var(--sb-bar-h, 64px)",gap:"16px"}},[React.createElement("div",{key:"left",style:{display:"flex",alignItems:"center",gap:"12px",minWidth:0}},[React.createElement("div",{key:"logo",style:{width:"36px",height:"36px",flex:"none",display:"grid",placeItems:"center"}},React.createElement("img",{src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{width:"100%",height:"100%",objectFit:"contain",display:"block"}})),React.createElement("div",{key:"txt",style:{lineHeight:1.2,minWidth:0}},[React.createElement("div",{key:"r1",style:{display:"flex",alignItems:"baseline",gap:"7px"}},[React.createElement("span",{key:"n",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-2)"}},"SecureBit"),React.createElement("span",{key:"v",style:{fontFamily:Y,fontSize:"10px",fontWeight:500,color:"var(--sb-text-faint)"}},Ma)]),React.createElement("div",{key:"r2",className:"hidden sm:block",style:{fontSize:"11px",color:"var(--sb-text-9)",fontWeight:500}},f("hdr.tagline"))])]),React.createElement("div",{key:"right",style:{display:"flex",alignItems:"center",gap:"9px"}},[B&&React.createElement(Hr,{key:"lang"}),B&&React.createElement(Gr,{key:"theme"}),!B&&React.createElement("button",{key:"net",type:"button",onClick:()=>window.dispatchEvent(new CustomEvent("securebit:open-network-settings")),title:f("hdr.netSettingsTitle"),"aria-label":f("hdr.netSettings"),className:"sb-disconnect",style:{display:"grid",placeItems:"center",width:"38px",height:"38px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",color:"var(--sb-text-6)",cursor:"pointer",transition:"all .15s"}},React.createElement("i",{className:"fas fa-network-wired",style:{fontSize:"13px"}})),!B&&k&&React.createElement("div",{key:"sec",onClick:w,onContextMenu:G=>{G.preventDefault(),typeof r=="function"&&r()},title:_.tooltip,className:"sb-secpill",style:{display:"flex",alignItems:"center",gap:"8px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)",cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-shield-halved",style:{fontSize:"13px",color:A}}),React.createElement("span",{key:"l",className:"hidden sm:inline",style:{fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-2)"}},f(`secLevel.${k.level}`)===`secLevel.${k.level}`?String(k.level):f(`secLevel.${k.level}`)),React.createElement("span",{key:"s",style:{fontFamily:Y,fontSize:"11.5px",color:"var(--sb-text-7)"}},k.score+"%")]),!B&&React.createElement("div",{key:"status",style:{display:"flex",alignItems:"center",gap:"8px",padding:"8px 13px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.02)"}},[React.createElement("span",{key:"dot",style:{width:"7px",height:"7px",borderRadius:"50%",background:x,boxShadow:"0 0 0 3px "+T}}),React.createElement("span",{key:"t",className:"hidden sm:inline",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-4)"}},F.text)]),i&&React.createElement("button",{key:"dc",onClick:r,className:"sb-disconnect",style:{display:"flex",alignItems:"center",gap:"7px",padding:"8px 14px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"transparent",color:"var(--sb-text-6)",fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:"pointer",transition:"all .15s"}},[React.createElement("i",{key:"i",className:"fas fa-power-off",style:{fontSize:"12px"}}),React.createElement("span",{key:"t",className:"sb-hide-sm"},f("hdr.disconnect"))])])])])])};window.EnhancedMinimalHeader=La;var Jt="1.0.5",qr=`https://github.com/SecureBitChat/securebit-desktop/releases/download/v${Jt}`,Da=()=>{let s=[{id:"web",name:"Web App",subtitle:"Browser Version",icon:"fas fa-globe",platform:"Web",isActive:!0,url:"https://securebit.chat/",color:"green"},{id:"windows",name:"Windows",subtitle:"Desktop App",icon:"fab fa-windows",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64-setup.exe`,color:"blue"},{id:"macos",name:"macOS",subtitle:"Desktop App",icon:"fab fa-safari",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_x64.dmg`,color:"gray"},{id:"linux",name:"Linux",subtitle:"Desktop App",icon:"fab fa-linux",platform:"Desktop",isActive:!0,url:`${qr}/SecureBit.Chat_${Jt}_amd64.AppImage`,color:"orange"},{id:"ios",name:"iOS",subtitle:"iPhone & iPad",icon:"fab fa-apple",platform:"Mobile",isActive:!1,url:"https://apps.apple.com/app/securebit-chat/",color:"white"},{id:"android",name:"Android",subtitle:"Google Play",icon:"fab fa-android",platform:"Mobile",isActive:!1,url:"https://play.google.com/store/apps/details?id=com.securebit.chat",color:"green"},{id:"chrome",name:"Chrome",subtitle:"Browser Extension",icon:"fab fa-chrome",platform:"Browser",isActive:!1,url:"#",color:"yellow"},{id:"edge",name:"Edge",subtitle:"Browser Extension",icon:"fab fa-edge",platform:"Browser",isActive:!1,url:"#",color:"blue"},{id:"opera",name:"Opera",subtitle:"Browser Extension",icon:"fab fa-opera",platform:"Browser",isActive:!1,url:"#",color:"red"},{id:"firefox",name:"Firefox",subtitle:"Browser Extension",icon:"fab fa-firefox-browser",platform:"Browser",isActive:!1,url:"#",color:"orange"}],e=c=>{c.isActive&&window.open(c.url,"_blank")},t=s.filter(c=>c.platform==="Desktop"||c.platform==="Web"),r=s.filter(c=>c.platform==="Mobile"),i=s.filter(c=>c.platform==="Browser"),n="w-28 h-28",a={green:"text-green-500",blue:"text-blue-500",gray:"text-gray-500",orange:"text-orange-500",red:"text-red-500",white:"text-white",yellow:"text-yellow-400"},o=c=>React.createElement("div",{key:c.id,className:`group relative ${n} rounded-2xl overflow-hidden card-minimal cursor-pointer`},[React.createElement("i",{key:"bg-icon",className:`${c.icon} absolute text-[3rem] ${c.isActive?a[c.color]:"text-white/10"} top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none transition-all duration-500 group-hover:scale-105`}),React.createElement("div",{key:"overlay",className:"absolute inset-0 bg-black/30 backdrop-blur-md flex flex-col items-center justify-center text-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"},[React.createElement("h4",{key:"name",className:"text-sm font-semibold text-primary mb-1"},c.name),React.createElement("p",{key:"subtitle",className:"text-xs text-secondary mb-2"},c.subtitle),c.isActive?React.createElement("button",{key:"btn",onClick:()=>e(c),className:"px-2 py-1 rounded-xl bg-emerald-500 text-black font-medium hover:bg-emerald-600 transition-colors text-xs"},c.id==="web"?"Launch":"Download"):React.createElement("span",{key:"coming",className:"text-gray-400 font-medium text-xs"},"Coming Soon")])]);return React.createElement("div",{className:"mt-20 px-6"},[React.createElement("div",{key:"header",className:"text-center max-w-3xl mx-auto mb-12"},[React.createElement("h3",{key:"title",className:"text-3xl font-bold text-primary mb-3"},"Download SecureBit.chat"),React.createElement("p",{key:"subtitle",className:"text-secondary text-lg mb-5"},"Stay secure on every device. Choose your platform and start chatting privately.")]),React.createElement("div",{key:"desktop-row",className:"hidden sm:flex justify-center flex-wrap gap-6 mb-6"},t.map(o)),React.createElement("div",{key:"mobile-row",className:"flex justify-center gap-6 mb-6"},r.map(o)),React.createElement("div",{key:"browser-row",className:"flex justify-center gap-6"},i.map(o))])};window.DownloadApps=Da;var Pa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let p=window.matchMedia("(max-width:767px)"),S=()=>e(p.matches);return p.addEventListener?p.addEventListener("change",S):p.addListener(S),()=>{p.removeEventListener?p.removeEventListener("change",S):p.removeListener(S)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",n="'Manrope', system-ui, -apple-system, sans-serif",a="https://docs.google.com/forms/d/e/1FAIpQLSc9ijV9PCoyXkus6vEx1OWwvwAsLq8fKS6-H5BmX-c-bvia6w/viewform?usp=dialog",o=[{id:"aegis",name:"Aegis Investment",logo:"/logo/aegis.png",logoHeight:"42px",url:"https://aegis-investment.com/",desc:f("partners.aegis.desc"),role:f("partners.aegis.role"),delay:".5s"},{id:"furi",name:"FuriLabs",logo:"/logo/furi-160.png",logoHeight:"54px",url:"https://furilabs.com/",desc:f("partners.furilabs.desc"),role:f("partners.furilabs.role"),delay:".56s"}],c=(p,S,g,b,w)=>React.createElement("svg",{className:w,width:S,height:S,viewBox:"0 0 24 24",fill:"none",stroke:g,strokeWidth:b,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:p}}),d=p=>React.createElement("span",{key:"role",style:{fontFamily:i,fontSize:"10.5px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.2px",padding:"6px 11px",borderRadius:"8px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",whiteSpace:"nowrap"}},p),u=p=>React.createElement("a",{key:p.id,href:p.url,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",padding:"30px 30px 26px",display:"flex",flexDirection:"column",textDecoration:"none",color:"inherit",transition:"transform .28s cubic-bezier(.2,.7,.3,1), border-color .28s cubic-bezier(.2,.7,.3,1)",animation:`ptUp ${p.delay} cubic-bezier(.2,.7,.3,1)`},onMouseEnter:S=>{S.currentTarget.style.transform="translateY(-4px)",S.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.13)"},onMouseLeave:S=>{S.currentTarget.style.transform="none",S.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.06)"}},[React.createElement("div",{key:"logo",style:{display:"flex",alignItems:"center",marginBottom:"30px",height:"54px"}},React.createElement("img",{src:p.logo,alt:p.name,loading:"lazy",decoding:"async",style:{height:p.logoHeight,width:"auto",maxWidth:"190px",objectFit:"contain",display:"block"}})),React.createElement("h3",{key:"name",style:{margin:"0 0 9px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},p.name),React.createElement("p",{key:"desc",style:{margin:"0 0 22px",fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},p.desc),React.createElement("div",{key:"foot",style:{marginTop:"auto",paddingTop:"6px",display:"flex",alignItems:"center",gap:"12px"}},[d(p.role)])]),h=React.createElement("a",{key:"invite",href:a,target:"_blank",rel:"noopener noreferrer",style:{flex:"1 1 320px",minWidth:s?"auto":"300px",borderRadius:"18px",background:"var(--sb-bg)",border:"1px dashed rgba(var(--sb-ink), 0.12)",padding:"30px",display:"flex",flexDirection:"column",justifyContent:"space-between",textDecoration:"none",color:"inherit",transition:"border-color .28s cubic-bezier(.2,.7,.3,1)",animation:"ptUp .62s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-orange-rgb), 0.4)"},onMouseLeave:p=>{p.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.12)"}},[React.createElement("div",{key:"top"},[React.createElement("div",{key:"icon",style:{width:"48px",height:"48px",borderRadius:"13px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.28)",marginBottom:"24px"}},c('',23,r,1.9)),React.createElement("h3",{key:"title",style:{margin:"0 0 8px",fontSize:"21px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},f("partners.inviteTitle")),React.createElement("p",{key:"desc",style:{margin:0,fontSize:"14.5px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("partners.inviteDesc"))]),React.createElement("span",{key:"btn",style:{marginTop:"26px",width:"100%",display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"10px",padding:"15px 20px",borderRadius:"12px",border:"none",background:r,color:"var(--sb-on-accent)",fontFamily:n,fontSize:"15px",fontWeight:700,cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",boxSizing:"border-box",transition:"background .2s cubic-bezier(.2,.7,.3,1), transform .2s cubic-bezier(.2,.7,.3,1)"}},[f("partners.inviteCta"),c('',17,"currentColor",2.2,"sb-mirror-rtl")])]),m=React.createElement("div",{key:"inner",style:{maxWidth:"1240px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{marginBottom:"44px"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:i,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"14px"}},f("partners.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:s?"30px":"40px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.04,color:"var(--sb-text-1)"}},f("partners.heading"))]),React.createElement("div",{key:"cards",style:{display:"flex",gap:"18px",alignItems:"stretch",flexWrap:"wrap"}},[...o.map(u),h])]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:n,padding:s?"48px 0":"72px 0",background:"radial-gradient(1100px 640px at 50% -6%, rgba(var(--sb-orange-rgb), 0.055), transparent 62%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ptUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),m])};window.BecomePartner=Pa;var Fa=()=>{let[s,e]=React.useState(0),[t,r]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let E=window.matchMedia("(max-width:767px)"),_=()=>r(E.matches);return E.addEventListener?E.addEventListener("change",_):E.addListener(_),()=>{E.removeEventListener?E.removeEventListener("change",_):E.removeListener(_)}},[]);let i="var(--sb-orange)",n="var(--sb-orange-solid)",a="radial-gradient(130% 90% at 28% 0%, rgba(var(--sb-orange-rgb), 0.11), transparent 60%), var(--sb-surface)",o="rgba(var(--sb-orange-rgb), 0.3)",c="var(--sb-bg)",d="rgba(var(--sb-ink), 0.06)",u="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",h="'Manrope', system-ui, -apple-system, sans-serif",m=[{num:"01",title:[f("unique.s1.titleTop"),f("unique.s1.titleBottom")],collapsed:f("unique.s1.collapsed"),desc:f("unique.s1.desc"),tags:Oe("unique.s1.tags"),icon:''},{num:"02",title:[f("unique.s2.titleTop"),f("unique.s2.titleBottom")],collapsed:f("unique.s2.collapsed"),desc:f("unique.s2.desc"),tags:Oe("unique.s2.tags"),icon:''},{num:"03",title:[f("unique.s3.titleTop"),f("unique.s3.titleBottom")],collapsed:f("unique.s3.collapsed"),desc:f("unique.s3.desc"),tags:Oe("unique.s3.tags"),icon:''},{num:"04",title:[f("unique.s4.titleTop"),f("unique.s4.titleBottom")],collapsed:f("unique.s4.collapsed"),desc:f("unique.s4.desc"),tags:Oe("unique.s4.tags"),icon:''},{num:"05",title:[f("unique.s5.titleTop"),f("unique.s5.titleBottom")],collapsed:f("unique.s5.collapsed"),desc:f("unique.s5.desc"),tags:Oe("unique.s5.tags"),icon:''}],p=(E,_,A,x)=>React.createElement("svg",{width:_,height:_,viewBox:"0 0 24 24",fill:"none",stroke:A,strokeWidth:x,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:E}}),S=E=>e(_=>(_+E+m.length)%m.length),g=(E,_,A)=>React.createElement("button",{key:E,onClick:_,"aria-label":E,className:"sb-mirror-rtl",style:{width:"46px",height:"46px",display:"grid",placeItems:"center",borderRadius:"50%",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.025)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:x=>{x.currentTarget.style.borderColor=o,x.currentTarget.style.color=i},onMouseLeave:x=>{x.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",x.currentTarget.style.color="var(--sb-text-4)"}},p(A,18,"currentColor",2.1)),b=E=>React.createElement("span",{key:E,style:{display:"inline-flex",alignItems:"center",gap:"7px",padding:"7px 12px",borderRadius:"9px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"rgba(var(--sb-ink), 0.025)",fontFamily:u,fontSize:"11.5px",fontWeight:500,color:"var(--sb-text-6)"}},[React.createElement("span",{key:"dot",style:{width:"5px",height:"5px",borderRadius:"50%",background:"var(--sb-green-solid)"}}),E]),w=E=>React.createElement("div",{key:"exp",style:{height:"100%",display:"flex",flexDirection:"column",justifyContent:t?"flex-start":"space-between",gap:t?"18px":0,padding:t?"24px 22px":"32px 34px",minWidth:t?"auto":"320px",animation:"wuUp .42s cubic-bezier(.2,.7,.3,1)"}},[React.createElement("div",{key:"top",style:{display:"flex",alignItems:"center",justifyContent:"space-between"}},[React.createElement("div",{key:"ic",style:{width:"54px",height:"54px",borderRadius:"15px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.13)",border:"1px solid rgba(var(--sb-orange-rgb), 0.3)"}},p(E.icon,26,n,1.9)),React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"13px",fontWeight:600,color:"var(--sb-text-9)"}},E.num)]),React.createElement("div",{key:"mid"},[React.createElement("h3",{key:"h",style:{margin:"0 0 12px",fontSize:t?"24px":"30px",fontWeight:800,letterSpacing:"-0.7px",lineHeight:1.08,color:"var(--sb-text-1)"}},[E.title[0],React.createElement("br",{key:"br"}),E.title[1]]),React.createElement("p",{key:"p",style:{margin:0,fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-6)",maxWidth:"380px"}},E.desc)]),React.createElement("div",{key:"tags",style:{display:"flex",flexWrap:"wrap",gap:"8px"}},E.tags.map(b))]),M=E=>t?React.createElement("div",{key:"col",style:{display:"flex",alignItems:"center",gap:"16px",padding:"20px 22px"}},[React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{fontSize:"16px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)"}},E.collapsed)]):React.createElement("div",{key:"col",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"space-between",padding:"24px 0"}},[React.createElement("span",{key:"n",style:{fontFamily:u,fontSize:"12px",fontWeight:600,color:"var(--sb-text-faint)"}},E.num),React.createElement("span",{key:"l",style:{writingMode:"vertical-rl",transform:"rotate(180deg)",fontSize:"17px",fontWeight:800,letterSpacing:"-0.2px",color:"var(--sb-text-4)",whiteSpace:"nowrap"}},E.collapsed),p(E.icon,22,"var(--sb-text-faint)",1.8)]),F=m.map((E,_)=>{let A=s===_;return React.createElement("div",{key:_,onClick:()=>e(_),onMouseEnter:x=>{A||(x.currentTarget.style.filter="brightness(1.18)")},onMouseLeave:x=>{x.currentTarget.style.filter="none"},style:{flex:t?"none":A?6.2:1,minWidth:t?"auto":"72px",position:"relative",borderRadius:"18px",overflow:"hidden",cursor:"pointer",background:A?a:c,border:"1px solid "+(A?o:d),color:"var(--sb-text-7)",transition:"flex .46s cubic-bezier(.2,.7,.3,1), background .3s ease, border-color .3s ease, filter .2s ease"}},A?w(E):M(E))}),k=React.createElement("div",{key:"inner",style:{maxWidth:"1180px",margin:"0 auto",padding:t?"0 18px":"0 40px"}},[React.createElement("div",{key:"head",style:{display:"flex",alignItems:"flex-end",justifyContent:"space-between",gap:"24px",marginBottom:"28px"}},[React.createElement("div",{key:"titles"},[React.createElement("div",{key:"eyebrow",style:{fontFamily:u,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.4px",marginBottom:"12px"}},f("unique.eyebrow")),React.createElement("h2",{key:"h2",style:{margin:0,fontSize:t?"28px":"38px",fontWeight:800,letterSpacing:"-1.1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("unique.heading"))]),React.createElement("div",{key:"nav",style:{display:"flex",alignItems:"center",gap:"10px",flex:"none"}},[g("prev",()=>S(-1),''),g("next",()=>S(1),'')])]),React.createElement("div",{key:"accordion",style:{display:"flex",flexDirection:t?"column":"row",gap:t?"12px":"14px",height:t?"auto":"440px"}},F)]);return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:h,padding:t?"44px 0":"64px 0",background:"radial-gradient(1100px 700px at 18% 8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes wuUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}"}}),k])};window.UniqueFeatureSlider=Fa;function Ka(){let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let w=window.matchMedia("(max-width:767px)"),M=()=>e(w.matches);return w.addEventListener?w.addEventListener("change",M):w.addListener(M),()=>{w.removeEventListener?w.removeEventListener("change",M):w.removeListener(M)}},[]);let t="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",r="'Manrope', system-ui, -apple-system, sans-serif",i=[{v:"v1.0",k:"r1",status:"released"},{v:"v1.5",k:"r2",status:"released"},{v:"v2.0",k:"r3",status:"released"},{v:"v3.0",k:"r4",status:"released"},{v:"v3.5",k:"r5",status:"released"},{v:"v4.5",k:"r6",status:"released"},{v:"v5.0",k:"r7",status:"released"},{v:"v5.5",k:"r8",status:"released"},{v:"v6.0",k:"r9",status:"current"},{v:"v6.5",k:"r10",status:"dev"},{v:"v7.0",k:"r11",status:"planned"},{v:"v7.5",k:"r12",status:"research"},{v:"v8.0",k:"r13",status:"research"}].map(w=>({...w,title:f(`roadmap.${w.k}.title`),sub:f(`roadmap.${w.k}.sub`),date:f(`roadmap.${w.k}.date`),features:Oe(`roadmap.${w.k}.features`)})),n={released:{solid:"var(--sb-green-solid)",line:"rgba(var(--sb-green-rgb), 0.32)"},current:{solid:"var(--sb-orange-solid)",line:"rgba(var(--sb-orange-rgb), 0.32)"},dev:{solid:"var(--sb-yellow-2-solid)",line:"rgba(var(--sb-ink), 0.08)"},planned:{solid:"var(--sb-text-7)",line:"rgba(var(--sb-ink), 0.08)"},research:{solid:"var(--sb-text-9)",line:"rgba(var(--sb-ink), 0.08)"}},[a,o]=React.useState({}),c=w=>a[w]===void 0?i[w].status==="current":a[w],d=w=>o(M=>({...M,[w]:!c(w)})),u=i.length,h=i.filter(w=>w.status==="released"||w.status==="current").length,m=u-h,p=(h/u*100).toFixed(1)+"%",[S,g]=f("roadmap.progress",{total:u}).split("{shipped}"),b=w=>w==="released"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-green-rgb), 0.16),rgba(var(--sb-green-rgb), 0.16)), var(--sb-bg)",border:"1px solid rgba(var(--sb-green-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:"2.4",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M5 13l4 4 10-11"}))):w==="current"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-orange-rgb), 0.2),rgba(var(--sb-orange-rgb), 0.2)), var(--sb-bg)",border:"1px solid var(--sb-orange-solid)",zIndex:2,animation:"rmPulse 2.4s ease-out infinite"}},React.createElement("span",{style:{width:"9px",height:"9px",borderRadius:"50%",background:"var(--sb-orange-solid)"}})):w==="dev"?React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"linear-gradient(rgba(var(--sb-yellow-2-rgb), 0.15),rgba(var(--sb-yellow-2-rgb), 0.15)), var(--sb-bg)",border:"1px solid rgba(var(--sb-yellow-2-rgb), 0.4)",zIndex:2}},React.createElement("svg",{width:"15",height:"15",viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-yellow-2-solid)",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M12 3a9 9 0 1 0 9 9"}))):React.createElement("div",{style:{position:"absolute",insetInlineStart:"13px",top:"16px",width:"28px",height:"28px",borderRadius:"50%",display:"grid",placeItems:"center",background:"var(--sb-bg)",border:`1px ${w==="research"?"dashed":"solid"} rgba(var(--sb-ink), 0.18)`,zIndex:2}},React.createElement("span",{style:{width:"7px",height:"7px",borderRadius:"50%",background:n[w].solid}}));return React.createElement("section",{style:{width:"100%",color:"var(--sb-text-2)",fontFamily:r,padding:s?"48px 0":"64px 0",background:"radial-gradient(1200px 720px at 50% -8%, rgba(var(--sb-orange-rgb), 0.05), transparent 60%), var(--sb-bg)"}},React.createElement("style",{dangerouslySetInnerHTML:{__html:"@keyframes rmExp{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes rmPulse{0%,100%{box-shadow:0 0 0 0 rgba(var(--sb-orange-rgb), 0.18)}60%{box-shadow:0 0 0 9px rgba(var(--sb-orange-rgb), 0)}}"}}),React.createElement("div",{style:{maxWidth:"1040px",margin:"0 auto",padding:s?"0 18px":"0 40px"}},React.createElement("div",{style:{marginBottom:"30px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.6px",marginBottom:"13px"}},f("roadmap.eyebrow")),React.createElement("h2",{style:{margin:"0 0 14px",fontSize:s?"27px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("roadmap.heading")),React.createElement("p",{style:{margin:0,fontSize:"15.5px",lineHeight:1.6,color:"var(--sb-text-7)",maxWidth:"660px"}},f("roadmap.subheading"))),React.createElement("div",{style:{display:"flex",alignItems:"center",gap:"18px",flexWrap:"wrap",padding:"18px 22px",borderRadius:"14px",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.06)",marginBottom:"36px"}},React.createElement("div",{style:{fontFamily:t,fontSize:"12px",fontWeight:600,color:"var(--sb-text-2)",whiteSpace:"nowrap"}},S,React.createElement("span",{style:{color:"var(--sb-green)"}},h),g),React.createElement("div",{style:{flex:"1 1 240px",minWidth:"200px",height:"8px",borderRadius:"99px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.06)",overflow:"hidden"}},React.createElement("div",{style:{height:"100%",width:p,background:"linear-gradient(90deg, var(--sb-green), var(--sb-orange))"}})),React.createElement("div",{style:{fontFamily:t,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"0.8px",whiteSpace:"nowrap"}},f("roadmap.upcoming",{upcoming:m}))),i.map((w,M)=>{let F=n[w.status],k=c(M),E=Md(M),style:{display:"flex",alignItems:"center",gap:s?"11px":"16px",padding:s?"16px 16px":"18px 22px",cursor:"pointer",transition:"background .18s ease"},onMouseEnter:_=>{_.currentTarget.style.background="rgba(var(--sb-ink), 0.018)"},onMouseLeave:_=>{_.currentTarget.style.background="transparent"}},React.createElement("div",{style:{flex:"none",minWidth:"52px",textAlign:"center",padding:"7px 10px",borderRadius:"9px",background:"var(--sb-bg-deep)",border:"1px solid rgba(var(--sb-ink), 0.07)",fontFamily:t,fontSize:"13px",fontWeight:700,color:w.status==="current"?"var(--sb-orange)":"var(--sb-text-4)"}},w.v),React.createElement("div",{style:{flex:1,minWidth:0}},React.createElement("div",{style:{fontSize:s?"15.5px":"17px",fontWeight:800,letterSpacing:"-0.4px",color:"var(--sb-text-1)"}},w.title),!s&&React.createElement("div",{style:{marginTop:"3px",fontSize:"13.5px",color:"var(--sb-text-6)"}},w.sub)),React.createElement("div",{style:{flex:"none",display:"flex",alignItems:"center",gap:s?"8px":"14px"}},!s&&React.createElement("span",{style:{fontFamily:t,fontSize:"12px",fontWeight:500,color:"var(--sb-text-7)",whiteSpace:"nowrap",minWidth:"74px",textAlign:"end"}},w.date),React.createElement("span",{style:{color:"var(--sb-text-9)",display:"inline-flex",transition:"transform .22s cubic-bezier(.2,.7,.3,1)",transform:k?"rotate(180deg)":"rotate(0deg)"}},React.createElement("svg",{width:"17",height:"17",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.1",strokeLinecap:"round",strokeLinejoin:"round"},React.createElement("path",{d:"M6 9l6 6 6-6"}))))),k&&React.createElement("div",{style:{padding:"4px 22px 22px 22px",animation:"rmExp .24s cubic-bezier(.2,.7,.3,1)"}},React.createElement("div",{style:{fontFamily:t,fontSize:"10px",fontWeight:600,color:"var(--sb-text-faint)",textTransform:"uppercase",letterSpacing:"1.2px",marginBottom:"14px",paddingTop:"14px",borderTop:"1px solid rgba(var(--sb-ink), 0.05)"}},f("roadmap.keyFeatures")),React.createElement("div",{style:{display:"grid",gridTemplateColumns:s?"1fr":"1fr 1fr",gap:"11px 28px"}},w.features.map((_,A)=>React.createElement("div",{key:A,style:{display:"flex",alignItems:"flex-start",gap:"10px"}},React.createElement("span",{style:{flex:"none",marginTop:"7px",width:"5px",height:"5px",borderRadius:"50%",background:F.solid}}),React.createElement("span",{style:{fontSize:"13.5px",lineHeight:1.5,color:"var(--sb-text-4)"}},_)))))))})))}window.Roadmap=Ka;var Et=[{id:"usdt",tab:"USDT",coin:"Tether USDT",badge:"trx",address:"TMopDoco5EwJB1QvQYsuhjUJdMvzPXNQYu"},{id:"btc",tab:"BTC",coin:"Bitcoin",badge:null,address:"bc1qnmc2xl7p0pxcy6lzf2tyf52wnslgzkgaq9kxpr"},{id:"eth",tab:"ETH",coin:"Ethereum",badge:null,address:"0xCDfDfaD4EC1fa657C3d2A7EFabc1cb751bf1dAf7"}],jr=s=>`/assets/crypto/${s}.svg`,Wr="__sbScrollToDonate",Yr="securebit:scroll-to-donate",Na=5e3,Xr=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches),[t,r]=React.useState(0),[i,n]=React.useState(!1),[a,o]=React.useState(0),c=React.useRef(null),d=React.useRef(null),u=React.useRef(null);React.useEffect(()=>{let K=window.matchMedia("(max-width:767px)"),O=()=>e(K.matches);return K.addEventListener?K.addEventListener("change",O):K.addListener(O),()=>{K.removeEventListener?K.removeEventListener("change",O):K.removeListener(O),clearTimeout(u.current)}},[]),React.useEffect(()=>{let K=null,O=()=>{let Q=window[Wr];window[Wr]=0,!(!Q||Date.now()-Q>Na)&&(clearTimeout(K),K=setTimeout(()=>{let J=d.current;if(!J)return;let ge=window.matchMedia("(prefers-reduced-motion: reduce)").matches;J.scrollIntoView({behavior:ge?"auto":"smooth",block:"center"})},350))};return O(),document.addEventListener(Yr,O),()=>{document.removeEventListener(Yr,O),clearTimeout(K)}},[]);let h=Et[t],m=K=>{let O=(K+Et.length)%Et.length;O!==t&&(o(K>t?1:-1),r(O),n(!1))},p=K=>{let O=K.touches[0];c.current={x:O.clientX,y:O.clientY}},S=K=>{let O=c.current;if(c.current=null,!O)return;let Q=K.changedTouches[0],J=Q.clientX-O.x,ge=Q.clientY-O.y;if(Math.abs(J)<40||Math.abs(J)0:J<0;m(t+(G?1:-1))},g=async()=>{try{await navigator.clipboard.writeText(h.address)}catch{let O=document.createElement("textarea");O.value=h.address,document.body.appendChild(O),O.select();try{document.execCommand("copy")}catch{}O.remove()}n(!0),clearTimeout(u.current),u.current=setTimeout(()=>n(!1),1800)},b="'Manrope', system-ui, -apple-system, sans-serif",w="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",M={borderRadius:"14px",background:"var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)"},F=React.createElement("div",{key:"tabs",role:"tablist",style:{...M,display:"flex",gap:"6px",padding:"5px",marginBottom:"14px"}},Et.map((K,O)=>{let Q=O===t;return React.createElement("button",{key:K.id,type:"button",role:"tab","aria-selected":Q,onClick:()=>m(O),style:{flex:"1 1 0",minWidth:0,display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"9px",padding:"11px 10px",borderRadius:"10px",border:"none",cursor:"pointer",fontFamily:b,fontSize:"14px",fontWeight:700,transition:"all .18s",background:Q?"var(--sb-surface-2)":"transparent",color:Q?"var(--sb-text-1)":"var(--sb-text-7)",boxShadow:Q?"inset 0 0 0 1px rgba(var(--sb-orange-rgb), 0.45)":"none"}},[React.createElement("span",{key:"ic",style:{position:"relative",flex:"none",width:"22px",height:"22px"}},[React.createElement("img",{key:"logo",src:jr(K.id),alt:"",width:22,height:22,style:{display:"block",width:"22px",height:"22px"}}),K.badge&&React.createElement("img",{key:"badge",src:jr(K.badge),alt:"",width:11,height:11,style:{position:"absolute",right:"-3px",bottom:"-3px",width:"11px",height:"11px",borderRadius:"50%",border:"1.5px solid var(--sb-surface-2)",background:"var(--sb-surface-2)"}})]),K.tab])})),k=React.createElement("button",{key:"copy",type:"button",onClick:g,style:{flex:"none",display:"inline-flex",alignItems:"center",gap:"8px",padding:"12px 16px",borderRadius:"10px",fontFamily:b,fontSize:"13.5px",fontWeight:700,cursor:"pointer",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-2)",border:"1px solid rgba(var(--sb-ink), 0.1)",transition:"all .18s"},onMouseEnter:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.09)"},onMouseLeave:K=>{K.currentTarget.style.background="rgba(var(--sb-ink), 0.05)"}},[i?React.createElement("svg",{key:"ok",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-green-solid)",strokeWidth:2.4,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}):React.createElement("svg",{key:"cp",width:15,height:15,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),React.createElement("span",{key:"l","aria-live":"polite"},i?f("donate.copied"):f("donate.copy"))]),E=React.createElement("div",{key:"addr",style:{...M,display:"flex",alignItems:"center",gap:"12px",padding:"8px 8px 8px 18px"}},[React.createElement("div",{key:"tx",style:{flex:1,minWidth:0}},[React.createElement("div",{key:"net",style:{fontSize:"11.5px",fontWeight:600,color:"var(--sb-text-9)",marginBottom:"2px"}},f(`donate.net.${h.id}`)),React.createElement("div",{key:"a",title:h.address,dir:"ltr",style:{fontFamily:w,fontSize:"14px",color:"var(--sb-text-2)",letterSpacing:"0.3px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"}},h.address.slice(0,8)+"\u2026"+h.address.slice(-8))]),k]),_=React.createElement("div",{key:"warn",style:{display:"flex",alignItems:"center",gap:"7px",marginTop:"14px",fontSize:"12px",color:"var(--sb-text-9)"}},[React.createElement("svg",{key:"i",width:13,height:13,viewBox:"0 0 24 24",fill:"none",stroke:"var(--sb-orange-solid)",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",style:{flex:"none"},dangerouslySetInnerHTML:{__html:''}}),f(`donate.warn.${h.id}`)]),A=React.createElement("div",{key:"left",style:{flex:"1 1 440px",minWidth:0,padding:s?"32px 22px 8px":"44px",display:"flex",flexDirection:"column"}},[React.createElement("div",{key:"eyebrow",style:{fontFamily:w,fontSize:"11px",fontWeight:600,color:"var(--sb-text-9)",textTransform:"uppercase",letterSpacing:"1.8px",marginBottom:"14px"}},f("donate.eyebrow")),React.createElement("h2",{key:"title",style:{margin:"0 0 10px",fontSize:s?"28px":"34px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.08,color:"var(--sb-text-1)"}},f("donate.title")),React.createElement("p",{key:"desc",style:{margin:"0 0 30px",fontSize:"15px",lineHeight:1.6,color:"var(--sb-text-7)"}},f("donate.description")),F,E,_]),x=Pt()?-1:1,T=a===0?"none":`${a*x>0?"cdInEnd":"cdInStart"} .28s cubic-bezier(.2,.7,.3,1)`,Y=React.createElement("div",{key:"plate",onTouchStart:p,onTouchEnd:S,style:{position:"relative",width:"232px",height:"232px",padding:"14px",borderRadius:"20px",background:"#fff",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.45 * var(--sb-shadow-k)))",border:"1px solid rgba(var(--sb-ink), 0.07)",overflow:"hidden",touchAction:"pan-y",userSelect:"none"}},React.createElement("div",{key:h.id,style:{position:"relative",width:"100%",height:"100%",animation:T}},[React.createElement("img",{key:"qr",src:`/assets/crypto/qr-${h.id}.svg`,alt:f("donate.qrAlt",{coin:h.coin}),width:204,height:204,draggable:!1,style:{display:"block",width:"100%",height:"100%",imageRendering:"pixelated"}}),React.createElement("div",{key:"logo",style:{position:"absolute",left:"50%",top:"50%",transform:"translate(-50%,-50%)",width:"48px",height:"48px",borderRadius:"12px",background:"#fff",display:"grid",placeItems:"center"}},React.createElement("img",{src:jr(h.id),alt:"",width:34,height:34,draggable:!1,style:{display:"block",width:"34px",height:"34px"}}))])),B=s&&React.createElement("div",{key:"dots","aria-hidden":!0,style:{display:"flex",justifyContent:"center",gap:"7px",marginTop:"18px"}},Et.map((K,O)=>React.createElement("span",{key:K.id,style:{width:O===t?"18px":"7px",height:"7px",borderRadius:"4px",transition:"all .25s",background:O===t?"var(--sb-orange-solid)":"rgba(var(--sb-ink), 0.16)"}}))),R=React.createElement("div",{key:"right",style:{flex:"0 0 auto",minWidth:s?0:"300px",margin:"0 auto",padding:s?"24px 22px 32px":"44px",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[Y,B]),ue=React.createElement("div",{key:"card",style:{width:"100%",maxWidth:"1000px",position:"relative",overflow:"hidden",borderRadius:"24px",background:"radial-gradient(520px 420px at 100% 50%, rgba(var(--sb-orange-rgb), 0.09), transparent 70%), var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.07)",display:"flex",flexWrap:"wrap",alignItems:"stretch",animation:"cdUp .45s cubic-bezier(.2,.7,.3,1)"}},[A,R]);return React.createElement("section",{id:"donate",ref:d,style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",color:"var(--sb-text-2)",fontFamily:b,padding:s?"48px 18px":"64px 32px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:'@keyframes cdUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes cdInEnd{from{opacity:0;transform:translateX(36px)}to{opacity:1;transform:none}}@keyframes cdInStart{from{opacity:0;transform:translateX(-36px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion: reduce){#donate [style*="cdIn"]{animation:none!important}}'}}),ue])};Xr.SCROLL_FLAG=Wr;Xr.SCROLL_EVENT=Yr;window.DonateCrypto=Xr;var Oa=()=>{let[s,e]=React.useState(typeof window<"u"&&window.matchMedia("(max-width:767px)").matches);React.useEffect(()=>{let u=window.matchMedia("(max-width:767px)"),h=()=>e(u.matches);return u.addEventListener?u.addEventListener("change",h):u.addListener(h),()=>{u.removeEventListener?u.removeEventListener("change",h):u.removeListener(h)}},[]);let t="var(--sb-orange)",r="var(--sb-orange-solid)",i="'Manrope', system-ui, -apple-system, sans-serif",n="https://github.com/SecureBitChat/securebit-chat/",a="mailto:lockbitchat@tutanota.com",o=React.createElement("a",{key:"gh",href:n,target:"_blank",rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:r,color:"var(--sb-on-accent)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",boxShadow:"0 8px 24px rgba(var(--sb-orange-rgb), 0.28)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:u=>{u.currentTarget.style.background="var(--sb-orange-hi)",u.currentTarget.style.transform="translateY(-2px)"},onMouseLeave:u=>{u.currentTarget.style.background=r,u.currentTarget.style.transform="none"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"currentColor",dangerouslySetInnerHTML:{__html:''}}),f("community.github")]),c=React.createElement("a",{key:"fb",href:a,rel:"noopener noreferrer",style:{display:"inline-flex",alignItems:"center",gap:"11px",padding:"15px 26px",borderRadius:"13px",background:"rgba(var(--sb-ink), 0.03)",color:"var(--sb-text-2)",textDecoration:"none",fontSize:"15.5px",fontWeight:700,letterSpacing:"-0.2px",border:"1px solid rgba(var(--sb-ink), 0.1)",whiteSpace:"nowrap",transition:"all .2s cubic-bezier(.2,.7,.3,1)"},onMouseEnter:u=>{u.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.24)",u.currentTarget.style.background="rgba(var(--sb-ink), 0.06)"},onMouseLeave:u=>{u.currentTarget.style.borderColor="rgba(var(--sb-ink), 0.1)",u.currentTarget.style.background="rgba(var(--sb-ink), 0.03)"}},[React.createElement("svg",{key:"i",width:20,height:20,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.9,strokeLinecap:"round",strokeLinejoin:"round",dangerouslySetInnerHTML:{__html:''}}),f("community.feedback")]),d=React.createElement("div",{key:"card",style:{position:"relative",overflow:"hidden",maxWidth:"860px",width:"100%",borderRadius:"24px",background:"radial-gradient(700px 360px at 50% 0%, rgba(var(--sb-orange-rgb), 0.1), transparent 65%), var(--sb-bg)",border:"1px solid rgba(var(--sb-ink), 0.07)",padding:s?"40px 24px 36px":"56px 56px 48px",textAlign:"center",boxShadow:"0 24px 60px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))"}},[React.createElement("div",{key:"hairline",style:{position:"absolute",top:0,left:"50%",transform:"translateX(-50%)",width:"180px",height:"1px",background:"linear-gradient(90deg, transparent, rgba(var(--sb-orange-rgb), 0.7), transparent)"}}),React.createElement("img",{key:"icon",src:"/logo/securebit-mark.svg",alt:"SecureBit",style:{display:"inline-block",width:"64px",height:"64px",objectFit:"contain",marginBottom:"22px",animation:"ccUp .4s cubic-bezier(.2,.7,.3,1)"}}),React.createElement("h2",{key:"title",style:{margin:"0 0 16px",fontSize:s?"28px":"36px",fontWeight:800,letterSpacing:"-1px",lineHeight:1.05,color:"var(--sb-text-1)"}},f("community.title")),React.createElement("p",{key:"desc",style:{margin:"0 auto 32px",maxWidth:"560px",fontSize:"16px",lineHeight:1.65,color:"var(--sb-text-6)"}},f("community.description")),React.createElement("div",{key:"btns",style:{display:"flex",gap:"14px",justifyContent:"center",flexWrap:"wrap"}},[o,c]),React.createElement("div",{key:"snap",style:{display:"flex",justifyContent:s?"center":"flex-end",marginTop:"28px"}},React.createElement("a",{href:"https://snapcraft.io/securebit-chat",target:"_blank",rel:"noopener noreferrer","aria-label":"Get it from the Snap Store",style:{display:"inline-flex",opacity:.9,transition:"opacity .2s"},onMouseEnter:u=>{u.currentTarget.style.opacity=1},onMouseLeave:u=>{u.currentTarget.style.opacity=.9}},React.createElement("img",{src:"/assets/badges/snap-store.svg",alt:"Get it from the Snap Store",width:182,height:56,loading:"lazy",style:{display:"block"}})))]);return React.createElement("section",{style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:"var(--sb-bg)",fontFamily:i,padding:s?"48px 18px":"64px 48px"}},[React.createElement("style",{key:"kf",dangerouslySetInnerHTML:{__html:"@keyframes ccUp{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}"}}),d])};window.CommunityCTA=Oa;var Ua=({webrtcManager:s,isConnected:e,pendingIncomingFiles:t=[],onIncomingDecision:r,showDropzone:i=!0})=>{let[n,a]=React.useState(!1),[o,c]=React.useState({sending:[],receiving:[]}),d=React.useRef(null);React.useEffect(()=>{if(!e||!s)return;let A=setInterval(()=>{let x=s.getFileTransfers();c(x)},500);return()=>clearInterval(A)},[e,s]),React.useEffect(()=>{e||c({sending:[],receiving:[]})},[e]);let u=async _=>{if(!e||!s){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435.");return}if(!s.isConnected()||!s.isVerified){alert("\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0444\u0430\u0439\u043B\u043E\u0432. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F.");return}for(let A of _)try{let x=s.validateFile(A);if(!x.isValid){let T=x.errors.join(". ");alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D: ${T}`);continue}await s.sendFile(A)}catch(x){x.message.includes(f("file.notReady"))?alert(`\u0424\u0430\u0439\u043B ${A.name} \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0441\u0435\u0439\u0447\u0430\u0441. \u041F\u0440\u043E\u0432\u0435\u0440\u044C\u0442\u0435 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0441\u043D\u043E\u0432\u0430.`):x.message.includes(f("file.tooLarge"))||x.message.includes("exceeds maximum")?alert(`\u0424\u0430\u0439\u043B ${A.name} \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439: ${x.message}`):x.message.includes(f("file.maxConcurrent"))?alert("\u0414\u043E\u0441\u0442\u0438\u0433\u043D\u0443\u0442 \u043B\u0438\u043C\u0438\u0442 \u043E\u0434\u043D\u043E\u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447. \u0414\u043E\u0436\u0434\u0438\u0442\u0435\u0441\u044C \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0442\u0435\u043A\u0443\u0449\u0438\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u0447."):x.message.includes(f("file.typeNotAllowed"))?alert(`\u0422\u0438\u043F \u0444\u0430\u0439\u043B\u0430 ${A.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F: ${x.message}`):alert(`\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${A.name}: ${x.message}`)}},h=_=>{_.preventDefault(),a(!1);let A=Array.from(_.dataTransfer.files);u(A)},m=_=>{_.preventDefault(),a(!0)},p=_=>{_.preventDefault(),a(!1)},S=_=>{let A=Array.from(_.target.files);u(A),_.target.value=""},g=_=>{if(_===0)return"0 B";let A=1024,x=["B","KB","MB","GB"],T=Math.floor(Math.log(_)/Math.log(A));return parseFloat((_/Math.pow(A,T)).toFixed(2))+" "+x[T]},b=_=>{switch(_){case"metadata_sent":case"preparing":return"fas fa-cog fa-spin";case"transmitting":case"receiving":return"fas fa-exchange-alt fa-pulse";case"assembling":return"fas fa-puzzle-piece fa-pulse";case"completed":return"fas fa-check text-green-400";case"failed":return"fas fa-times text-red-400";default:return"fas fa-circle"}},w=_=>{switch(_){case"metadata_sent":return"\u041F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0430...";case"transmitting":return"\u041E\u0442\u043F\u0440\u0430\u0432\u043A\u0430...";case"receiving":return"\u041F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435...";case"assembling":return"\u0421\u0431\u043E\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u0430...";case"completed":return"\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E";case"failed":return"\u041E\u0448\u0438\u0431\u043A\u0430";default:return _}},M=(_,A)=>{let x=_.totalChunks||0,T=_.transferredChunks||0,Y=_.status==="completed",B=x>0?Math.min(x,32):24,R;return Y?R=B:x>0?R=Math.floor(T/x*B):R=Math.floor((_.progress||0)/100*B),R=Math.max(0,Math.min(B,R)),React.createElement("div",{key:"progress"},[React.createElement("div",{key:"squares",style:{display:"flex",flexWrap:"wrap",gap:"3px",marginBottom:"7px"}},Array.from({length:B},(ue,K)=>React.createElement("div",{key:K,style:{width:"11px",height:"11px",borderRadius:"2px",background:K0?`${Math.min(T,x)} / ${x} chunks`:`${(_.progress||0).toFixed(0)}%`)])])},F=_=>_.status==="completed",k=async(_,A)=>{typeof r=="function"&&await r(_,A),c(s.getFileTransfers())};return e?s&&s.isConnected()&&s.isVerified?React.createElement("div",{className:"file-transfer-component"},[i&&React.createElement("div",{key:"drop-zone",onDrop:h,onDragOver:m,onDragLeave:p,style:{position:"relative",border:"1.5px dashed "+(n?"rgba(var(--sb-orange-rgb), 0.7)":"rgba(var(--sb-ink), 0.14)"),borderRadius:"14px",background:n?"rgba(var(--sb-orange-rgb), 0.07)":"var(--sb-surface)",padding:"24px 22px",textAlign:"center",transition:"all .15s"}},[React.createElement("div",{key:"icon-box",style:{width:"42px",height:"42px",margin:"0 auto 10px",borderRadius:"12px",display:"grid",placeItems:"center",background:"rgba(var(--sb-ink), 0.04)",border:"1px solid rgba(var(--sb-ink), 0.08)"}},React.createElement("i",{className:"fas fa-arrow-up-from-bracket",style:{color:"var(--sb-text-6)",fontSize:"18px"}})),React.createElement("div",{key:"title",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-2)"}},f("file.drop")),React.createElement("div",{key:"sub",style:{fontSize:"12px",color:"var(--sb-text-8)",marginTop:"4px"}},f("file.dropHint")),React.createElement("button",{key:"browse",type:"button",onClick:()=>d.current?.click(),className:"sb-send",style:{marginTop:"14px",display:"inline-flex",alignItems:"center",gap:"7px",padding:"9px 16px",borderRadius:"9px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-folder-open",style:{fontSize:"13px"}}),f("file.browse")])]),i&&React.createElement("input",{key:"file-input",ref:d,type:"file",multiple:!0,className:"hidden",onChange:S}),t.length>0&&React.createElement("div",{key:"incoming-consent",className:"mt-4 space-y-2"},t.map(_=>React.createElement("div",{key:_.fileId,style:{borderRadius:"12px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-surface)",padding:"12px 14px"}},[React.createElement("div",{key:"info",style:{marginBottom:"12px",display:"flex",alignItems:"center",gap:"11px"}},[React.createElement("div",{key:"ic",style:{flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-orange-rgb), 0.12)",border:"1px solid rgba(var(--sb-orange-rgb), 0.22)"}},React.createElement("i",{className:"fas fa-file-arrow-down",style:{color:"var(--sb-orange)",fontSize:"15px"}})),React.createElement("div",{key:"text",style:{minWidth:0}},[React.createElement("div",{key:"title",style:{fontSize:"13px",fontWeight:600,color:"var(--sb-text-2)"}},f("file.incoming")),React.createElement("div",{key:"meta",style:{fontSize:"11.5px",color:"var(--sb-text-8)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},`${_.fileName} \xB7 ${g(_.fileSize)} \xB7 ${_.mimeType}`)])]),React.createElement("div",{key:"actions",style:{display:"flex",gap:"8px"}},[React.createElement("button",{key:"accept",onClick:()=>k(_.fileId,!0),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"none",background:"var(--sb-orange-solid)",color:"var(--sb-on-accent)",padding:"8px 14px",fontSize:"13px",fontWeight:700,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-check",style:{fontSize:"12px"}}),f("file.accept")]),React.createElement("button",{key:"reject",onClick:()=>k(_.fileId,!1),style:{display:"inline-flex",alignItems:"center",gap:"6px",borderRadius:"8px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"rgba(var(--sb-red-rgb), 0.08)",color:"var(--sb-red)",padding:"8px 14px",fontSize:"13px",fontWeight:600,cursor:"pointer"}},[React.createElement("i",{key:"i",className:"fas fa-xmark",style:{fontSize:"12px"}}),f("file.reject")])])]))),(o.sending.length>0||o.receiving.length>0)&&React.createElement("div",{key:"transfers",className:"active-transfers mt-4"},[React.createElement("h4",{key:"title",style:{display:"flex",alignItems:"center",gap:"8px",fontSize:"12.5px",fontWeight:600,color:"var(--sb-text-7)",marginBottom:"10px"}},[React.createElement("i",{key:"icon",className:"fas fa-right-left",style:{fontSize:"12px"}}),f("file.title")]),...o.sending.map(_=>React.createElement("div",{key:`send-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-up",style:{color:"var(--sb-orange)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(_.fileSize))]),React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])]),M(_,"var(--sb-orange)")])),...o.receiving.map(_=>React.createElement("div",{key:`recv-${_.fileId}`,style:{borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.07)",background:"var(--sb-surface)",padding:"12px",marginBottom:"8px"}},[React.createElement("div",{key:"header",className:"flex items-center justify-between mb-2"},[React.createElement("div",{key:"info",className:"flex items-center"},[React.createElement("i",{key:"icon",className:"fas fa-arrow-down",style:{color:"var(--sb-green)",fontSize:"13px",marginInlineEnd:"8px"}}),React.createElement("span",{key:"name",className:"font-medium text-sm",style:{color:"var(--sb-text-2)"}},_.fileName),React.createElement("span",{key:"size",className:"text-xs ms-2",style:{color:"var(--sb-text-8)"}},g(_.fileSize))]),React.createElement("div",{key:"actions",className:"flex items-center space-x-2"},[_.status==="completed"?React.createElement("button",{key:"download",className:"text-green-400 hover:text-green-300 text-xs flex items-center",onClick:async()=>{try{let A=await s.getReceivedFileObjectURL(_.fileId);if(!A){alert(f("file.gone"));return}let x=document.createElement("a");x.href=A,x.download=_.fileName||"file",x.click(),setTimeout(()=>s.revokeReceivedFileObjectURL(A),1e4)}catch(A){alert(A.message||f("file.gone"))}}},[React.createElement("i",{key:"i",className:"fas fa-download me-1"}),f("file.download")]):null,React.createElement("button",{key:"cancel",onClick:()=>s.cancelFileTransfer(_.fileId),className:"text-red-400 hover:text-red-300 text-xs"},[React.createElement("i",{className:"fas fa-times"})])])]),M(_,"var(--sb-green)")]))])]):React.createElement("div",{className:"p-4 text-center text-yellow-600"},[React.createElement("i",{key:"icon",className:"fas fa-exclamation-triangle me-2"}),"\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F... \u041F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u0431\u0443\u0434\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043F\u043E\u0441\u043B\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438."]):React.createElement("div",{className:"p-4 text-center text-muted"},f("file.needConnection"))};window.FileTransferComponent=Ua;var ze=Object.freeze({MAX_SERVERS:10,MAX_URLS_PER_SERVER:8,MAX_STRING_LENGTH:512}),Jo=Object.freeze(["stun","stuns","turn","turns"]),za=/^(stuns?|turns?):/i,Va=/^(\[[0-9a-f:]+\]|[a-z0-9.-]+)(:\d{1,5})?$/i,Ba=/^transport=(udp|tcp)$/i;function On(s){for(let e=0;eze.MAX_STRING_LENGTH)return f("iceUrl.tooLong");if(On(e))return f("iceUrl.badChars");let t=e.match(za);if(!t)return f("iceUrl.badScheme");let r=e.slice(t[0].length),[i,n,...a]=r.split("?");return a.length>0?f("iceUrl.badQuery"):i?Va.test(i)?n!==void 0&&!Ba.test(n)?f("iceUrl.badTransport"):null:f("iceUrl.badHost"):f("iceUrl.noHost")}function Un(s){return typeof s=="string"&&/^turns?:/i.test(s.trim())}function Kn(s,e){return s==null||s===""?null:typeof s!="string"?`${e} must be a string`:s.length>ze.MAX_STRING_LENGTH?`${e} is too long`:On(s)?`${e} contains invalid characters`:null}function Nn(s){let e=[],t=[],r=[];return Array.isArray(s)?s.length===0?{servers:[],errors:[],warnings:[]}:s.length>ze.MAX_SERVERS?(e.push(f("iceErr.tooMany",{max:ze.MAX_SERVERS})),{servers:[],errors:e,warnings:t}):(s.forEach((i,n)=>{let a=`Server #${n+1}`;if(!i||typeof i!="object"){e.push(f("iceErr.invalidEntry",{label:a}));return}let o=Array.isArray(i.urls)?i.urls:[i.urls];if(o.length===0||o.length>ze.MAX_URLS_PER_SERVER){e.push(f("iceErr.urlCount",{label:a,max:ze.MAX_URLS_PER_SERVER}));return}let c=[],d=!1;for(let p of o){let S=Ha(p);if(S){e.push(`${a}: ${S}`);continue}let g=p.trim();c.push(g),Un(g)&&(d=!0)}if(c.length===0)return;let u=Kn(i.username,`${a} username`);u&&e.push(u);let h=Kn(i.credential,`${a} credential`);h&&e.push(h);let m={urls:c.length===1?c[0]:c};i.username&&(m.username=String(i.username)),i.credential&&(m.credential=String(i.credential)),d&&(!m.username||!m.credential)&&t.push(f("iceErr.turnCreds",{label:a})),r.push(m)}),{servers:r,errors:e,warnings:t}):{servers:[],errors:[f("iceErr.notArray")],warnings:[]}}function zn(s){if(typeof s!="string"||!s.trim())return{servers:[],errors:[],warnings:[]};let e=s.trim();if(e.startsWith("[")||e.startsWith("{")){let r;try{r=JSON.parse(e)}catch{return{servers:[],errors:[f("iceErr.invalidJson")],warnings:[]}}let i=Array.isArray(r)?r:[r];return Nn(i)}let t=e.split(` `).map(r=>r.trim()).filter(Boolean).map(r=>({urls:r}));return Nn(t)}function Vn(s){return Array.isArray(s)?s.some(e=>(Array.isArray(e?.urls)?e.urls:[e?.urls]).some(Un)):!1}var Ve=window.React,$a=["# One URL per line, e.g.:","stun:stun.example.com:3478","turn:turn.example.com:3478?transport=udp","","# Or paste JSON for servers with credentials:",'[{"urls":"turns:turn.example.com:5349","username":"user","credential":"secret"}]'].join(` `);async function Ga(s,e=6e3){let t={host:0,srflx:0,relay:0};if(typeof RTCPeerConnection>"u")return{...t,error:f("ice.errUnavailable")};let r;try{r=new RTCPeerConnection({iceServers:s})}catch(i){return{...t,error:i.message||f("ice.errInvalid")}}return new Promise(i=>{let n=!1,a=()=>{if(!n){n=!0,clearTimeout(o);try{r.close()}catch{}i(t)}},o=setTimeout(a,e);r.onicecandidate=c=>{if(!c.candidate){a();return}let d=c.candidate.candidate||"";/ typ host/.test(d)?t.host++:/ typ srflx/.test(d)?t.srflx++:/ typ relay/.test(d)&&t.relay++};try{r.createDataChannel("securebit-ice-test"),r.createOffer().then(c=>r.setLocalDescription(c)).catch(()=>a())}catch{a()}})}var qa=({isOpen:s,onClose:e,initial:t,hasSaved:r,onApply:i,onForget:n,embedded:a})=>{if(!s)return null;let[o,c]=Ve.useState(t?.useCustom||!1),[d,u]=Ve.useState(t?.serversText||""),[h,m]=Ve.useState(t?.privacyMode==="relay-only"),[p,S]=Ve.useState(t?.persisted||!1),[g,b]=Ve.useState("idle"),[w,M]=Ve.useState(null),F=o?zn(d):{servers:[],errors:[],warnings:[]},k=Vn(F.servers),E=!o||F.servers.length>0&&F.errors.length===0,_=async()=>{b("running"),M(null);let U=await Ga(F.servers);M(U),b("done")},A=()=>{E&&i({useCustom:o,servers:o?F.servers:[],privacyMode:h?"relay-only":"standard",serversText:d},p)},x=async()=>{n&&await n(),S(!1)},T=Ve.createElement,Y="var(--sb-orange)",B="var(--sb-green)",R="var(--sb-orange-solid)",ue="var(--sb-green-solid)",K="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",O=(U,I,D,N,z)=>T("button",{type:"button",onClick:I,style:Object.assign({width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${U?"rgba(var(--sb-orange-rgb), 0.45)":"rgba(var(--sb-ink), 0.07)"}`,background:U?"rgba(var(--sb-orange-rgb), 0.06)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"},z||{})},[T("span",{key:"ring",style:{flex:"none",width:"18px",height:"18px",marginTop:"1px",borderRadius:"50%",border:`1.5px solid ${U?Y:"rgba(var(--sb-ink), 0.22)"}`,display:"grid",placeItems:"center"}},T("span",{style:{width:"8px",height:"8px",borderRadius:"50%",background:U?R:"transparent"}})),T("span",{key:"tx",style:{flex:1}},[T("span",{key:"t",style:{display:"block",fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},D),T("span",{key:"d",style:{display:"block",fontSize:"12.5px",color:"var(--sb-text-7)",marginTop:"2px"}},N)])]),Q=(U,I,D,N,z,W)=>T("button",{type:"button",onClick:I,style:{width:"100%",textAlign:"start",display:"flex",alignItems:"flex-start",gap:"12px",padding:"14px 15px",borderRadius:"13px",border:`1px solid ${U?"rgba(var(--sb-green-rgb), 0.3)":"rgba(var(--sb-ink), 0.07)"}`,background:U?"rgba(var(--sb-green-rgb), 0.05)":"var(--sb-surface)",color:"inherit",fontFamily:"inherit",cursor:"pointer",transition:"all .15s",marginBottom:"10px"}},[T("span",{key:"tx",style:{flex:1}},[T("span",{key:"r1",style:{display:"flex",alignItems:"center",gap:"8px"}},[T("span",{key:"t",style:{fontSize:"14px",fontWeight:700,color:"var(--sb-text-1)"}},D),W&&T("span",{key:"b",style:{fontSize:"10px",fontWeight:700,color:B,padding:"2px 7px",borderRadius:"5px",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.22)"}},W)]),T("span",{key:"d",style:{display:"block",fontSize:"12.5px",lineHeight:1.5,color:"var(--sb-text-7)",marginTop:"3px"}},N)]),T("span",{key:"tr",style:{flex:"none",width:"42px",height:"24px",borderRadius:"99px",background:U?z||ue:"rgba(var(--sb-ink), 0.08)",border:`1px solid ${U?z||B:"rgba(var(--sb-ink), 0.12)"}`,position:"relative",transition:"all .18s",marginTop:"1px"}},T("span",{style:{position:"absolute",top:"2px",insetInlineStart:"2px",width:"18px",height:"18px",borderRadius:"50%",background:"#fff",transform:U?`translateX(${18*$i()}px)`:"translateX(0)",transition:"transform .18s"}}))]),J=[];if(J.push(T("p",{key:"intro",style:{margin:"0 0 18px",fontSize:"13.5px",lineHeight:1.6,color:"var(--sb-text-6)"}},f("ice.intro"))),J.push(O(!o,()=>c(!1),f("ice.publicTitle"),f("ice.publicDesc"))),J.push(O(o,()=>c(!0),f("ice.customTitle"),f("ice.customDesc",{max:ze.MAX_SERVERS}),o?{marginBottom:"14px"}:null)),o){let U=[];U.push(T("div",{key:"ta",style:{borderRadius:"13px",border:"1px solid rgba(var(--sb-ink), 0.08)",background:"var(--sb-bg-deep)",overflow:"hidden",marginBottom:"12px"}},T("textarea",{dir:"ltr",value:d,onChange:D=>u(D.target.value),rows:5,spellCheck:!1,autoComplete:"off",placeholder:$a,style:{width:"100%",resize:"vertical",border:"none",outline:"none",background:"transparent",color:"var(--sb-text-code)",fontFamily:K,fontSize:"12px",lineHeight:1.65,padding:"13px 14px",minHeight:"104px"}}))),F.errors.length>0&&U.push(T("ul",{key:"err",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-red)",fontSize:"12.5px"}},F.errors.slice(0,6).map((D,N)=>T("li",{key:N},D)))),F.warnings.length>0&&U.push(T("ul",{key:"warn",style:{margin:"0 0 10px",paddingInlineStart:"18px",color:"var(--sb-yellow)",fontSize:"12.5px"}},F.warnings.slice(0,6).map((D,N)=>T("li",{key:N},D)))),F.servers.length>0&&F.errors.length===0&&U.push(T("p",{key:"ok",style:{margin:"0 0 10px",fontSize:"12.5px",color:B}},`${F.servers.length} server(s) parsed${k?" (TURN present)":" (STUN only \u2014 does not hide IP)"}.`)),U.push(T("div",{key:"note",style:{display:"flex",alignItems:"flex-start",gap:"9px",padding:"12px 13px",borderRadius:"11px",border:"1px solid rgba(var(--sb-green-rgb), 0.18)",background:"rgba(var(--sb-green-rgb), 0.05)",marginBottom:"12px"}},[T("i",{key:"i",className:"fas fa-info-circle",style:{color:B,fontSize:"13px",marginTop:"2px",flex:"none"}}),T("span",{key:"t",style:{fontSize:"12px",lineHeight:1.55,color:"var(--sb-green-muted)"}},[f("ice.turnNote"),T("span",{key:"m",style:{fontFamily:K,color:B}},"turns:"),f("ice.turnNoteTls")])]));let I=g==="done"&&w&&!w.error?B:"var(--sb-text-4)";U.push(T("div",{key:"test",style:{display:"flex",alignItems:"center",gap:"12px",flexWrap:"wrap",marginBottom:"4px"}},[T("button",{key:"btn",type:"button",disabled:!E||g==="running",onClick:_,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"10px 15px",borderRadius:"10px",border:`1px solid ${g==="done"&&w&&!w.error?"rgba(var(--sb-green-rgb), 0.4)":"rgba(var(--sb-ink), 0.1)"}`,background:g==="done"&&w&&!w.error?"rgba(var(--sb-green-rgb), 0.08)":"rgba(var(--sb-ink), 0.04)",color:I,fontFamily:"inherit",fontSize:"13px",fontWeight:600,cursor:!E||g==="running"?"not-allowed":"pointer",opacity:!E||g==="running"?.6:1}},[T("i",{key:"i",className:g==="running"?"fas fa-circle-notch":"fas fa-play-circle",style:g==="running"?{animation:"sbSpin 1s linear infinite"}:null}),g==="running"?f("ice.testing"):f("ice.test")]),g==="done"&&w?T("span",{key:"res",style:{fontSize:"12px",color:w.error?"var(--sb-red)":"var(--sb-text-7)"}},w.error?`Test failed: ${w.error}`:w.srflx>0||w.relay>0?`STUN ${w.srflx>0?"OK":"none"} \xB7 TURN ${w.relay>0?"OK":"none"} \xB7 host ${w.host}`:`host ${w.host} \xB7 this browser hides STUN/TURN candidates from the test \u2014 your servers still apply to real connections`):null])),J.push(T("div",{key:"custom",style:{marginBottom:"16px"}},U))}J.push(Q(h,()=>m(!h),f("ice.relayTitle"),f("ice.relayDesc"),B,f("ice.relayBadge"))),h&&o&&!k&&J.push(T("p",{key:"relaywarn",style:{margin:"-4px 0 10px",fontSize:"12.5px",color:"var(--sb-yellow)"}},f("ice.relayWarning"))),J.push(Q(p,()=>S(!p),f("ice.persist"),f("ice.persistDesc"),Y));let ge=[];return r&&ge.push(T("button",{key:"forget",type:"button",onClick:x,style:{marginInlineEnd:"auto",padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(var(--sb-red-rgb), 0.3)",background:"transparent",color:"var(--sb-red)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.forget"))),ge.push(T("button",{key:"cancel",type:"button",onClick:e,style:{padding:"11px 18px",borderRadius:"11px",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"transparent",color:"var(--sb-text-5)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:600,cursor:"pointer"}},f("ice.cancel"))),ge.push(T("button",{key:"apply",type:"button",onClick:A,disabled:!E,style:{display:"inline-flex",alignItems:"center",gap:"8px",padding:"11px 20px",borderRadius:"11px",border:"none",background:R,color:"var(--sb-on-accent)",fontFamily:"inherit",fontSize:"13.5px",fontWeight:700,cursor:E?"pointer":"not-allowed",opacity:E?1:.5,boxShadow:"0 6px 18px rgba(var(--sb-orange-rgb), 0.28)"}},[T("i",{key:"i",className:"fas fa-check"}),f("ice.apply")])),T("div",{className:"sb-ice-overlay",style:a?{position:"absolute",inset:0,zIndex:60,display:"flex",flexDirection:"column",background:"var(--sb-bg)",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}:{position:"fixed",inset:0,zIndex:60,display:"flex",flexDirection:"column",alignItems:"stretch",background:"var(--sb-bg)",animation:"sbSlideUp .32s cubic-bezier(.2,.7,.3,1)"}},[T(Ve.Fragment,{key:"panel"},[T("div",{key:"head",style:{display:"flex",alignItems:"center",gap:"12px",padding:"20px 24px",borderBottom:"1px solid rgba(var(--sb-ink), 0.06)"}},[T("div",{key:"ic",style:{width:"38px",height:"38px",flex:"none",display:"grid",placeItems:"center",borderRadius:"10px",background:"rgba(var(--sb-ink), 0.03)",border:"1px solid rgba(var(--sb-ink), 0.06)"}},T("i",{className:"fas fa-sliders-h",style:{color:"var(--sb-text-4)",fontSize:"15px"}})),T("div",{key:"tx",style:{flex:1,lineHeight:1.25}},[T("div",{key:"t",style:{fontSize:"16.5px",fontWeight:800,letterSpacing:"-0.3px",color:"var(--sb-text-1)"}},f("ice.title")),T("div",{key:"s",style:{fontSize:"12px",color:"var(--sb-text-8)"}},f("ice.subtitle"))]),T("button",{key:"x",type:"button",onClick:e,style:{width:"32px",height:"32px",flex:"none",display:"grid",placeItems:"center",borderRadius:"9px",border:"none",background:"rgba(var(--sb-ink), 0.04)",color:"var(--sb-text-7)",cursor:"pointer"}},T("i",{className:"fas fa-times"}))]),T("div",{key:"body",className:"custom-scrollbar",style:{flex:1,overflowY:"auto",padding:"20px 24px"}},J),T("div",{key:"foot",style:{display:"flex",alignItems:"center",justifyContent:"flex-end",gap:"10px",padding:"16px 24px",borderTop:"1px solid rgba(var(--sb-ink), 0.06)",background:"var(--sb-bg-deep)",borderRadius:"0"}},ge)])])};window.IceServerSettings=qa;var ja=({webrtcManager:s,peerTitle:e})=>{let t=React.createElement,r="'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace",i={lock:'',minimize:'',expand:'',user:'',micOn:'',micOff:'',camOn:'',camOff:'',flip:'',phone:'',phoneHangup:''},n=(N,z,W)=>t("span",{style:{display:"grid",placeItems:"center",width:z+"px",height:z+"px"},dangerouslySetInnerHTML:{__html:`${N}`}}),[a,o]=React.useState(()=>s?.getCallState?.()||{phase:"idle",active:!1}),[c,d]=React.useState(!1),[u,h]=React.useState(0),m=React.useRef(null),p=React.useRef(null),S=React.useRef(null);React.useEffect(()=>{if(!s)return;let N=W=>o(W),z=s.onCallStateChanged;return s.onCallStateChanged=N,o(s.getCallState?s.getCallState():{phase:"idle",active:!1}),()=>{s.onCallStateChanged===N&&(s.onCallStateChanged=z||null)}},[s]);let g=a.phase||"idle",b=!!a.active,w=!!a.withVideo||!!a.remoteHasVideo;if(React.useEffect(()=>{let N=s?.getRemoteMediaStream?.(),z=s?.getLocalMediaStream?.(),W=(Z,be,_e)=>{if(!Z||!be)return;Z.srcObject!==be&&(Z.muted=_e,Z.srcObject=be);let me=Z.play&&Z.play();me&&me.catch&&me.catch(()=>{})};W(p.current,N,!1,"remoteAudio"),W(m.current,N,!0,"remoteVideo"),W(S.current,z,!0,"selfVideo")}),React.useEffect(()=>{if(g!=="active"){h(0);return}let N=Date.now(),z=setInterval(()=>h(Math.floor((Date.now()-N)/1e3)),1e3);return()=>clearInterval(z)},[g]),React.useEffect(()=>{g==="idle"&&d(!1)},[g]),!b||g==="idle"||g==="ended"||a.groupCallId)return null;let M=N=>`${String(Math.floor(N/60)).padStart(2,"0")}:${String(N%60).padStart(2,"0")}`,F=g==="outgoing"||g==="connecting",k=g==="outgoing"?f("call.ringing"):g==="connecting"?f("call.connecting"):g==="active"?M(u):f("call.ringing"),E=e||f("call.peer"),_={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), 0.1)",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"},A={..._,background:"var(--sb-red-strong-solid)",color:"#fff",border:"1px solid transparent"},x={width:"56px",height:"56px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"var(--sb-red-strong-solid)",color:"#fff",cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-red-strong-rgb), 0.35)",transition:"transform .15s"},T=N=>({width:"36px",height:"36px",borderRadius:"9px",display:"grid",placeItems:"center",border:"1px solid rgba(var(--sb-ink), "+(N?"0.15":"0.1")+")",background:N?"rgba(0,0,0,0.35)":"rgba(var(--sb-ink), 0.04)",color:N?"#fff":"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}),Y=t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"4px",fontSize:"11px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,11,2),f("call.encryptedShort")]),B={excellent:{bars:4,color:"var(--sb-green)",solid:"var(--sb-green-solid)",label:f("call.qualityExcellent")},good:{bars:3,color:"var(--sb-green)",solid:"var(--sb-green-solid)",label:f("call.qualityGood")},fair:{bars:2,color:"var(--sb-yellow)",solid:"var(--sb-yellow-solid)",label:f("call.qualityFair")},poor:{bars:1,color:"var(--sb-red)",solid:"var(--sb-red-solid)",label:f("call.qualityWeak")}},R=N=>{let z=B[a.quality];if(!z)return null;let W=t("span",{key:"bars",style:{display:"inline-flex",alignItems:"flex-end",gap:"2px",height:"14px"}},[0,1,2,3].map(Z=>t("span",{key:Z,style:{width:"3px",height:5+Z*3+"px",borderRadius:"1px",background:Zs?.acceptCall?.(),K=()=>s?.declineCall?.(),O=()=>{d(!1),s?.endCall?.()},Q=()=>s?.toggleMic?.(),J=()=>s?.toggleCamera?.(),ge=()=>s?.switchCamera?.(),G=()=>s?.upgradeToVideo?.(),U=t("audio",{key:"ra",ref:p,autoPlay:!0,playsInline:!0,style:{display:"none"}}),I=(N,z,W)=>t("div",{key:N,style:{display:"flex",flexDirection:"column",alignItems:"center",gap:"8px"}},[z,t("span",{key:"l",style:{fontFamily:r,fontSize:"10.5px",color:"var(--sb-text-7)"}},W)]),D=(N,z)=>t("div",{key:"av",style:{position:"relative",width:"120px",height:"120px",marginBottom:"28px",display:"grid",placeItems:"center"}},[z&&t("span",{key:"p1",style:{position:"absolute",inset:0,borderRadius:"50%",border:"1.5px solid rgba(var(--sb-orange-rgb), 0.5)",animation:"sbCallPulse 2s ease-out infinite"}}),z&&t("span",{key:"p2",style:{position:"absolute",inset:0,borderRadius:"50%",border:"1.5px solid rgba(var(--sb-orange-rgb), 0.4)",animation:"sbCallPulse 2s ease-out infinite",animationDelay:"1s"}}),t("div",{key:"c",style:{width:"104px",height:"104px",borderRadius:"50%",display:"grid",placeItems:"center",background:"radial-gradient(circle at 35% 30%, var(--sb-surface-4), var(--sb-surface))",border:"1px solid rgba(var(--sb-ink), 0.1)",boxShadow:"0 12px 30px rgba(var(--sb-shadow-rgb), calc(0.4 * var(--sb-shadow-k)))",color:"var(--sb-text-7)"}},n(i.user,N,1.6))]);return g==="incoming"?t("div",{style:{position:"absolute",inset:0,zIndex:40,display:"flex",flexDirection:"column",background:"radial-gradient(680px 460px at 50% 36%, rgba(var(--sb-orange-rgb), 0.08), transparent 70%), var(--sb-bg-deep)",animation:"sbExpand .2s ease"}},[U,t("div",{key:"top",style:{flex:"none",display:"flex",alignItems:"center",justifyContent:"flex-start",padding:"16px 18px"}},t("span",{style:{display:"inline-flex",alignItems:"center",gap:"7px",fontSize:"12px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,13,2),f("call.encrypted")])),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[D(46,!0),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},E),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},a.withVideo?f("call.incomingVideo"):f("call.incoming"))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"48px",padding:"28px 24px 40px"}},[I("dec",t("button",{onClick:K,title:f("call.decline"),style:{...x,width:"62px",height:"62px"}},n(i.phoneHangup,24,1.9)),f("call.decline")),I("acc",t("button",{onClick:ue,title:f("call.accept"),style:{width:"62px",height:"62px",borderRadius:"50%",display:"grid",placeItems:"center",border:"none",background:"var(--sb-green-solid)",color:"var(--sb-on-green)",cursor:"pointer",boxShadow:"0 8px 24px rgba(var(--sb-green-rgb), 0.35)"}},n(i.phone,24,1.9)),f("call.accept"))])]):c?t("div",{style:{position:"absolute",bottom:"18px",insetInlineEnd:"18px",zIndex:40,width:"236px",borderRadius:"14px",overflow:"hidden",background:"var(--sb-surface)",border:"1px solid rgba(var(--sb-ink), 0.1)",boxShadow:"0 18px 44px rgba(var(--sb-shadow-rgb), calc(0.55 * var(--sb-shadow-k)))",animation:"sbExpand .18s ease"}},[U,w&&t("div",{key:"v",style:{position:"relative",height:"132px",background:"#111"}},[t("video",{key:"rv",ref:m,autoPlay:!0,muted:!0,playsInline:!0,style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}}),!a.remoteHasVideo&&t("div",{key:"off",style:{position:"absolute",inset:0,display:"grid",placeItems:"center",background:"linear-gradient(120deg,var(--sb-grad-1),var(--sb-grad-2))",color:"var(--sb-text-9)"}},n(i.camOff,22,1.8)),t("span",{key:"s",style:{position:"absolute",top:"8px",insetInlineStart:"9px",fontFamily:r,fontSize:"11px",fontWeight:600,color:"#fff",padding:"3px 7px",borderRadius:"6px",background:"rgba(0,0,0,0.5)"}},k)]),t("div",{key:"bar",style:{display:"flex",alignItems:"center",gap:"11px",padding:"11px 12px"}},[t("span",{key:"ic",style:{position:"relative",flex:"none",width:"34px",height:"34px",borderRadius:"9px",display:"grid",placeItems:"center",background:"rgba(var(--sb-green-rgb), 0.1)",border:"1px solid rgba(var(--sb-green-rgb), 0.25)",color:"var(--sb-green)"}},n(i.user,16,1.9)),t("div",{key:"tx",style:{flex:1,minWidth:0}},[t("div",{key:"n",style:{fontSize:"13px",fontWeight:700,color:"var(--sb-text-1)",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"}},E),t("div",{key:"s",style:{display:"flex",alignItems:"center",gap:"7px",fontFamily:r,fontSize:"11px",color:"var(--sb-text-6)"}},[(w?f("call.videoPrefix"):f("call.voicePrefix"))+k,g==="active"&&R(!0)])]),t("button",{key:"exp",onClick:()=>d(!1),title:f("call.expand"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"rgba(var(--sb-ink), 0.05)",color:"var(--sb-text-4)",cursor:"pointer",transition:"all .15s"}},n(i.expand,15,2)),t("button",{key:"end",onClick:O,title:f("call.end"),style:{flex:"none",width:"32px",height:"32px",borderRadius:"8px",display:"grid",placeItems:"center",border:"none",background:"var(--sb-red-strong-solid)",color:"#fff",cursor:"pointer",transition:"transform .15s"}},n(i.phoneHangup,15,2))])]):w?t("div",{style:{position:"absolute",inset:0,zIndex:40,overflow:"hidden",background:"var(--sb-bg-deepest)",animation:"sbExpand .2s ease"}},[U,a.remoteHasVideo?t("video",{key:"rv",ref:m,autoPlay:!0,muted:!0,playsInline:!0,style:{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover",background:"var(--sb-bg-deepest)"}}):t("div",{key:"ph",style:{position:"absolute",inset:0,background:"linear-gradient(120deg, var(--sb-grad-1), var(--sb-grad-2), var(--sb-grad-3))",backgroundSize:"200% 200%",animation:"sbLiveBg 9s ease-in-out infinite",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"18px"}},[t("div",{key:"a",style:{width:"120px",height:"120px",borderRadius:"50%",display:"grid",placeItems:"center",background:"radial-gradient(circle at 35% 30%, var(--sb-surface-4), var(--sb-surface))",border:"1px solid rgba(var(--sb-ink), 0.1)",color:"var(--sb-text-6)"}},n(i.user,54,1.5)),t("div",{key:"t",style:{fontSize:"15px",fontWeight:600,color:"var(--sb-text-7)"}},f("call.peerCameraOff"))]),t("div",{key:"top",style:{position:"absolute",top:0,left:0,right:0,display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:"14px",padding:"18px 20px",background:"linear-gradient(180deg, rgba(0,0,0,0.55), transparent)"}},[t("div",{key:"l"},[t("div",{key:"n",style:{fontSize:"18px",fontWeight:800,letterSpacing:"-0.3px",color:"#fff"}},E),t("div",{key:"s",style:{display:"inline-flex",alignItems:"center",gap:"9px",marginTop:"4px"}},[t("span",{key:"st",style:{fontFamily:r,fontSize:"12.5px",fontWeight:500,color:"var(--sb-text-2)"}},k),Y,g==="active"&&R(!1)])]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:{flex:"none",...T(!0)}},n(i.minimize,16,2))]),t("div",{key:"self",style:{position:"absolute",bottom:"108px",insetInlineEnd:"18px",width:"132px",height:"176px",borderRadius:"14px",overflow:"hidden",border:"1px solid rgba(var(--sb-ink), 0.16)",boxShadow:"0 12px 30px rgba(var(--sb-shadow-rgb), calc(0.5 * var(--sb-shadow-k)))",background:"#111"}},[t("video",{key:"sv",ref:S,autoPlay:!0,muted:!0,playsInline:!0,style:{width:"100%",height:"100%",objectFit:"cover",transform:"scaleX(-1)",display:"block"}}),!a.cameraEnabled&&t("div",{key:"off",style:{position:"absolute",inset:0,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"8px",background:"var(--sb-surface)",color:"var(--sb-text-9)"}},[n(i.camOff,24,1.8),t("span",{key:"t",style:{fontSize:"10.5px",color:"var(--sb-text-9)",fontFamily:r}},f("call.cameraOff"))])]),t("div",{key:"ctrls",style:{position:"absolute",bottom:0,left:0,right:0,display:"flex",alignItems:"center",justifyContent:"center",gap:"18px",padding:"22px 24px 28px",background:"linear-gradient(0deg, rgba(0,0,0,0.6), transparent)"}},[t("button",{key:"mute",onClick:Q,title:f("call.mute"),style:a.micEnabled?_:A},n(a.micEnabled?i.micOn:i.micOff,21,1.9)),t("button",{key:"cam",onClick:J,title:f("call.camera"),style:a.cameraEnabled?_:A},n(a.cameraEnabled?i.camOn:i.camOff,21,1.8)),t("button",{key:"flip",onClick:ge,title:f("call.flipCamera"),style:_},n(i.flip,21,1.8)),t("button",{key:"end",onClick:O,title:f("call.end"),style:x},n(i.phoneHangup,22,1.9))])]):t("div",{style:{position:"absolute",inset:0,zIndex:40,display:"flex",flexDirection:"column",background:"radial-gradient(680px 460px at 50% 36%, rgba(var(--sb-orange-rgb), 0.08), transparent 70%), var(--sb-bg-deep)",animation:"sbExpand .2s ease"}},[U,t("div",{key:"top",style:{flex:"none",display:"flex",alignItems:"center",justifyContent:"space-between",padding:"16px 18px"}},[t("span",{key:"enc",style:{display:"inline-flex",alignItems:"center",gap:"7px",fontSize:"12px",fontWeight:600,color:"var(--sb-green)"}},[n(i.lock,13,2),f("call.encrypted")]),t("button",{key:"min",onClick:()=>d(!0),title:f("call.minimize"),style:T(!1)},n(i.minimize,16,2))]),t("div",{key:"mid",style:{flex:1,display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center"}},[D(46,F),t("div",{key:"nm",style:{fontSize:"24px",fontWeight:800,letterSpacing:"-0.5px",color:"var(--sb-text-1)"}},E),t("div",{key:"st",style:{fontFamily:r,fontSize:"14px",fontWeight:500,color:"var(--sb-text-6)",marginTop:"8px"}},k),g==="active"&&t("div",{key:"q",style:{marginTop:"12px"}},R(!1))]),t("div",{key:"ctrls",style:{flex:"none",display:"flex",alignItems:"flex-start",justifyContent:"center",gap:"26px",padding:"28px 24px 34px"}},[I("mute",t("button",{onClick:Q,title:f("call.mute"),style:a.micEnabled?_:A},n(a.micEnabled?i.micOn:i.micOff,22,1.9)),a.micEnabled?"Mute":f("call.muted")),I("video",t("button",{onClick:G,title:f("call.addVideo"),style:_},n(i.camOn,22,1.8)),f("call.video")),I("end",t("button",{onClick:O,title:f("call.end"),style:x},n(i.phoneHangup,22,1.9)),f("call.endShort"))])])};typeof window<"u"&&(window.CallUIComponent=ja);window.EnhancedSecureCryptoUtils=Mt;window.EnhancedSecureWebRTCManager=$t;window.EnhancedSecureFileTransfer=je;window.NotificationIntegration=$n.NotificationIntegration;var Wa=()=>{try{let s=[];for(let e=0;e(window.__qrReady||(window.__qrReady=import("/dist/qr-local.js").then(()=>{window.dispatchEvent(new Event("securebit:qr-ready"))}).catch(s=>{console.warn("QR bundle failed to load:",s&&s.message),window.__qrReady=null})),window.__qrReady),Ya=()=>{typeof window.requestIdleCallback=="function"?window.requestIdleCallback(Bn,{timeout:3e3}):setTimeout(Bn,1200)},Hn=()=>{Wa(),typeof window.initializeApp=="function"?window.initializeApp():window.DEBUG_MODE&&console.error("initializeApp is not defined on window"),Ya()};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Hn):Hn(); /** diff --git a/dist/app-boot.js.map b/dist/app-boot.js.map index 1d2fb13..df98530 100644 --- a/dist/app-boot.js.map +++ b/dist/app-boot.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/notifications/SecureNotificationManager.js", "../src/notifications/NotificationIntegration.js", "../node_modules/dompurify/src/utils.ts", "../node_modules/dompurify/src/tags.ts", "../node_modules/dompurify/src/attrs.ts", "../node_modules/dompurify/src/regexp.ts", "../node_modules/dompurify/src/purify.ts", "../src/crypto/EnhancedSecureCryptoUtils.js", "../src/i18n/generated.js", "../src/i18n/dict/en.js", "../src/i18n/index.js", "../src/transfer/EnhancedSecureFileTransfer.js", "../src/network/webrtc/config.js", "../src/network/webrtc/sdp.js", "../src/network/webrtc/audio.js", "../src/network/webrtc/video.js", "../src/network/webrtc/adaptation/metrics.js", "../src/network/webrtc/adaptation/controller.js", "../src/crypto/DoubleRatchet.js", "../src/network/descriptor/sbq2.js", "../src/network/descriptor/keyexchange.js", "../src/network/EnhancedSecureWebRTCManager.js", "../src/scripts/app-boot.js", "../package.json", "../src/components/ui/LanguageSwitcher.jsx", "../src/components/ui/ThemeSwitcher.jsx", "../src/components/ui/Header.jsx", "../src/components/ui/DownloadApps.jsx", "../src/components/ui/BecomePartner.jsx", "../src/components/ui/UniqueFeatureSlider.jsx", "../src/components/ui/Roadmap.jsx", "../src/components/ui/DonateCrypto.jsx", "../src/components/ui/CommunityCTA.jsx", "../src/components/ui/FileTransfer.jsx", "../src/network/iceServers.js", "../src/components/ui/IceServerSettings.jsx", "../src/components/ui/CallUI.jsx"], - "sourcesContent": ["/**\n * Secure and Reliable Notification Manager for P2P WebRTC Chat\n * Follows best practices: OWASP, MDN, Chrome DevRel\n * \n * @version 1.0.0\n * @author SecureBit Team\n * @license MIT\n */\n\nclass SecureChatNotificationManager {\n constructor(config = {}) {\n // Safely read Notification permission (iOS Safari may not define Notification)\n this.permission = (typeof Notification !== 'undefined' && Notification && typeof Notification.permission === 'string')\n ? Notification.permission\n : 'denied';\n this.isTabActive = this.checkTabActive(); // Initialize with proper check\n this.unreadCount = 0;\n this.originalTitle = document.title;\n this.notificationQueue = [];\n this.maxQueueSize = config.maxQueueSize || 5;\n this.rateLimitMs = config.rateLimitMs || 2000; // Spam protection\n this.lastNotificationTime = 0;\n this.trustedOrigins = config.trustedOrigins || [];\n \n // Secure context flag\n this.isSecureContext = window.isSecureContext;\n \n // Cross-browser compatibility for Page Visibility API\n this.hidden = this.getHiddenProperty();\n this.visibilityChange = this.getVisibilityChangeEvent();\n \n this.initVisibilityTracking();\n this.initSecurityChecks();\n }\n\n /**\n * Initialize security checks and validation\n * @private\n */\n initSecurityChecks() {\n // Security checks are performed silently\n }\n\n /**\n * Get hidden property name for cross-browser compatibility\n * @returns {string} Hidden property name\n * @private\n */\n getHiddenProperty() {\n if (typeof document.hidden !== \"undefined\") {\n return \"hidden\";\n } else if (typeof document.msHidden !== \"undefined\") {\n return \"msHidden\";\n } else if (typeof document.webkitHidden !== \"undefined\") {\n return \"webkitHidden\";\n }\n return \"hidden\"; // fallback\n }\n\n /**\n * Get visibility change event name for cross-browser compatibility\n * @returns {string} Visibility change event name\n * @private\n */\n getVisibilityChangeEvent() {\n if (typeof document.hidden !== \"undefined\") {\n return \"visibilitychange\";\n } else if (typeof document.msHidden !== \"undefined\") {\n return \"msvisibilitychange\";\n } else if (typeof document.webkitHidden !== \"undefined\") {\n return \"webkitvisibilitychange\";\n }\n return \"visibilitychange\"; // fallback\n }\n\n /**\n * Check if tab is currently active using multiple methods\n * @returns {boolean} True if tab is active\n * @private\n */\n checkTabActive() {\n // Primary method: Page Visibility API\n if (this.hidden && typeof document[this.hidden] !== \"undefined\") {\n return !document[this.hidden];\n }\n \n // Fallback method: document.hasFocus()\n if (typeof document.hasFocus === \"function\") {\n return document.hasFocus();\n }\n \n // Ultimate fallback: assume active\n return true;\n }\n\n /**\n * Initialize page visibility tracking (Page Visibility API)\n * @private\n */\n initVisibilityTracking() {\n // Primary method: Page Visibility API with cross-browser support\n if (typeof document.addEventListener !== \"undefined\" && typeof document[this.hidden] !== \"undefined\") {\n document.addEventListener(this.visibilityChange, () => {\n this.isTabActive = this.checkTabActive();\n \n if (this.isTabActive) {\n this.resetUnreadCount();\n this.clearNotificationQueue();\n }\n });\n }\n\n // Fallback method: Window focus/blur events\n window.addEventListener('focus', () => {\n this.isTabActive = this.checkTabActive();\n if (this.isTabActive) {\n this.resetUnreadCount();\n }\n });\n\n window.addEventListener('blur', () => {\n this.isTabActive = this.checkTabActive();\n });\n\n // Page unload cleanup\n window.addEventListener('beforeunload', () => {\n this.clearNotificationQueue();\n });\n }\n\n /**\n * Request notification permission (BEST PRACTICE: Only call in response to user action)\n * Never call on page load!\n * @returns {Promise} Permission granted status\n */\n async requestPermission() {\n // Secure context check\n if (!this.isSecureContext || !('Notification' in window)) {\n return false;\n }\n\n if (this.permission === 'granted') {\n return true;\n }\n\n if (this.permission === 'denied') {\n return false;\n }\n\n try {\n this.permission = await Notification.requestPermission();\n return this.permission === 'granted';\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Update page title with unread count\n * @private\n */\n updateTitle() {\n if (this.unreadCount > 0) {\n document.title = `(${this.unreadCount}) ${this.originalTitle}`;\n } else {\n document.title = this.originalTitle;\n }\n }\n\n /**\n * XSS Protection: Sanitize input text\n * @param {string} text - Text to sanitize\n * @returns {string} Sanitized text\n * @private\n */\n sanitizeText(text) {\n if (typeof text !== 'string') {\n return '';\n }\n \n // Remove HTML tags and potentially dangerous characters\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .substring(0, 500); // Length limit\n }\n\n /**\n * Validate icon URL (XSS protection)\n * @param {string} url - URL to validate\n * @returns {string|null} Validated URL or null\n * @private\n */\n validateIconUrl(url) {\n if (!url) return null;\n \n try {\n const parsedUrl = new URL(url, window.location.origin);\n \n // Only allow HTTPS and data URLs\n if (parsedUrl.protocol === 'https:' || parsedUrl.protocol === 'data:') {\n // Check trusted origins if specified\n if (this.trustedOrigins.length > 0) {\n const isTrusted = this.trustedOrigins.some(origin => \n parsedUrl.origin === origin\n );\n return isTrusted ? parsedUrl.href : null;\n }\n return parsedUrl.href;\n }\n \n return null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Rate limiting for spam protection\n * @returns {boolean} Rate limit check passed\n * @private\n */\n checkRateLimit() {\n const now = Date.now();\n if (now - this.lastNotificationTime < this.rateLimitMs) {\n return false;\n }\n this.lastNotificationTime = now;\n return true;\n }\n\n /**\n * Send secure notification\n * @param {string} senderName - Name of message sender\n * @param {string} message - Message content\n * @param {Object} options - Notification options\n * @returns {Notification|null} Created notification or null\n */\n notify(senderName, message, options = {}) {\n // Abort if Notifications API is not available (e.g., iOS Safari)\n if (typeof Notification === 'undefined') {\n return null;\n }\n // Update tab active state before checking\n this.isTabActive = this.checkTabActive();\n \n // Only show if tab is NOT active (user is on another tab or minimized)\n if (this.isTabActive) {\n return null;\n }\n\n // Permission check\n if (this.permission !== 'granted') {\n return null;\n }\n\n // Rate limiting\n if (!this.checkRateLimit()) {\n return null;\n }\n\n // Data sanitization (XSS Protection)\n const safeSenderName = this.sanitizeText(senderName || 'Unknown');\n const safeMessage = this.sanitizeText(message || '');\n const safeIcon = this.validateIconUrl(options.icon) || '/logo/icon-192x192.png';\n\n // Queue overflow protection\n if (this.notificationQueue.length >= this.maxQueueSize) {\n this.clearNotificationQueue();\n }\n\n try {\n \n const notification = new Notification(\n `${safeSenderName}`,\n {\n body: safeMessage.substring(0, 200), // Length limit\n icon: safeIcon,\n badge: safeIcon,\n tag: `chat-${options.senderId || 'unknown'}`, // Grouping\n requireInteraction: false, // Don't block user\n silent: options.silent || false,\n // Vibrate only for mobile and if supported\n vibrate: navigator.vibrate ? [200, 100, 200] : undefined,\n // Safe metadata\n data: {\n senderId: this.sanitizeText(options.senderId),\n timestamp: Date.now(),\n // Don't include sensitive data!\n }\n }\n );\n\n // Increment counter\n this.unreadCount++;\n this.updateTitle();\n\n // Add to queue for management\n this.notificationQueue.push(notification);\n\n // Safe click handler\n notification.onclick = (event) => {\n event.preventDefault(); // Prevent default behavior\n window.focus();\n notification.close();\n \n // Safe callback\n if (typeof options.onClick === 'function') {\n try {\n options.onClick(options.senderId);\n } catch (error) {\n console.error('[Notifications] Error in onClick handler:', error);\n }\n }\n };\n\n // Error handler\n notification.onerror = (event) => {\n console.error('[Notifications] Error showing notification:', event);\n };\n\n // Auto-close after reasonable time\n const autoCloseTimeout = Math.min(options.autoClose || 5000, 10000);\n setTimeout(() => {\n notification.close();\n this.removeFromQueue(notification);\n }, autoCloseTimeout);\n\n return notification;\n \n } catch (error) {\n console.error('[Notifications] Failed to create notification:', error);\n return null;\n }\n }\n\n /**\n * Remove notification from queue\n * @param {Notification} notification - Notification to remove\n * @private\n */\n removeFromQueue(notification) {\n const index = this.notificationQueue.indexOf(notification);\n if (index > -1) {\n this.notificationQueue.splice(index, 1);\n }\n }\n\n /**\n * Clear all notifications\n */\n clearNotificationQueue() {\n this.notificationQueue.forEach(notification => {\n try {\n notification.close();\n } catch (error) {\n // Ignore errors when closing\n }\n });\n this.notificationQueue = [];\n }\n\n /**\n * Reset unread counter\n */\n resetUnreadCount() {\n this.unreadCount = 0;\n this.updateTitle();\n }\n\n /**\n * Get current status\n * @returns {Object} Current notification status\n */\n getStatus() {\n return {\n permission: this.permission,\n isTabActive: this.isTabActive,\n unreadCount: this.unreadCount,\n isSecureContext: this.isSecureContext,\n queueSize: this.notificationQueue.length\n };\n }\n}\n\n/**\n * Secure integration with WebRTC\n */\nclass SecureP2PChat {\n constructor() {\n this.notificationManager = new SecureChatNotificationManager({\n maxQueueSize: 5,\n rateLimitMs: 2000,\n trustedOrigins: [\n window.location.origin,\n // Add other trusted origins for CDN icons\n ]\n });\n \n this.dataChannel = null;\n this.peerConnection = null;\n this.remotePeerName = 'Peer';\n this.messageHistory = [];\n this.maxHistorySize = 100;\n }\n\n /**\n * Initialize when user connects\n */\n async init() {\n // Initialize notification manager silently\n }\n\n /**\n * Method for manual permission request (called on click)\n * @returns {Promise} Permission granted status\n */\n async enableNotifications() {\n const granted = await this.notificationManager.requestPermission();\n return granted;\n }\n\n /**\n * Setup DataChannel with security checks\n * @param {RTCDataChannel} dataChannel - WebRTC data channel\n */\n setupDataChannel(dataChannel) {\n if (!dataChannel) {\n console.error('[Chat] Invalid DataChannel');\n return;\n }\n\n this.dataChannel = dataChannel;\n \n // Setup handlers\n this.dataChannel.onmessage = (event) => {\n this.handleIncomingMessage(event.data);\n };\n\n this.dataChannel.onerror = (error) => {\n // Handle error silently\n };\n }\n\n /**\n * XSS Protection: Validate incoming messages\n * @param {string|Object} data - Message data\n * @returns {Object|null} Validated message or null\n * @private\n */\n validateMessage(data) {\n try {\n const message = typeof data === 'string' ? JSON.parse(data) : data;\n \n // Check message structure\n if (!message || typeof message !== 'object') {\n throw new Error('Invalid message structure');\n }\n\n // Check required fields\n if (!message.text || typeof message.text !== 'string') {\n throw new Error('Invalid message text');\n }\n\n // Message length limit (DoS protection)\n if (message.text.length > 10000) {\n throw new Error('Message too long');\n }\n\n return {\n text: message.text,\n senderName: message.senderName || 'Unknown',\n senderId: message.senderId || 'unknown',\n timestamp: message.timestamp || Date.now(),\n senderAvatar: message.senderAvatar || null\n };\n \n } catch (error) {\n console.error('[Chat] Message validation failed:', error);\n return null;\n }\n }\n\n /**\n * Secure handling of incoming messages\n * @param {string|Object} data - Message data\n * @private\n */\n handleIncomingMessage(data) {\n const message = this.validateMessage(data);\n \n if (!message) {\n return;\n }\n\n // Save to history (with limit)\n this.messageHistory.push(message);\n if (this.messageHistory.length > this.maxHistorySize) {\n this.messageHistory.shift();\n }\n\n // Display in UI (with sanitization)\n this.displayMessage(message);\n\n // Send notification only if tab is inactive\n this.notificationManager.notify(\n message.senderName,\n message.text,\n {\n icon: message.senderAvatar,\n senderId: message.senderId,\n onClick: (senderId) => {\n this.scrollToLatestMessage();\n }\n }\n );\n\n // Optional: sound (with check)\n if (!this.notificationManager.isTabActive) {\n this.playNotificationSound();\n }\n }\n\n /**\n * XSS Protection: Safe message display\n * @param {Object} message - Message to display\n * @private\n */\n displayMessage(message) {\n const container = document.getElementById('messages');\n if (!container) {\n return;\n }\n\n const messageEl = document.createElement('div');\n messageEl.className = 'message';\n \n // Use textContent to prevent XSS\n const nameEl = document.createElement('strong');\n nameEl.textContent = message.senderName + ': ';\n \n const textEl = document.createElement('span');\n textEl.textContent = message.text;\n textEl.style.wordWrap = 'break-word';\n textEl.style.overflowWrap = 'break-word';\n textEl.style.whiteSpace = 'normal';\n \n const timeEl = document.createElement('small');\n timeEl.textContent = new Date(message.timestamp).toLocaleTimeString();\n \n messageEl.appendChild(nameEl);\n messageEl.appendChild(textEl);\n messageEl.appendChild(document.createElement('br'));\n messageEl.appendChild(timeEl);\n \n container.appendChild(messageEl);\n this.scrollToLatestMessage();\n }\n\n /**\n * Safe sound playback\n * @private\n */\n playNotificationSound() {\n try {\n // Use only local audio files\n const audio = new Audio('/assets/audio/notification.mp3');\n audio.volume = 0.3; // Moderate volume\n \n // Error handling\n audio.play().catch(error => {\n // Handle audio error silently\n });\n } catch (error) {\n // Handle audio creation error silently\n }\n }\n\n /**\n * Scroll to latest message\n * @private\n */\n scrollToLatestMessage() {\n const container = document.getElementById('messages');\n if (container) {\n container.scrollTop = container.scrollHeight;\n }\n }\n\n /**\n * Get status\n * @returns {Object} Current chat status\n */\n getStatus() {\n return {\n notifications: this.notificationManager.getStatus(),\n messageCount: this.messageHistory.length,\n connected: this.dataChannel?.readyState === 'open'\n };\n }\n}\n\n// Export for use in other modules\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = { SecureChatNotificationManager, SecureP2PChat };\n}\n\n// Global export for browser usage\nif (typeof window !== 'undefined') {\n window.SecureChatNotificationManager = SecureChatNotificationManager;\n window.SecureP2PChat = SecureP2PChat;\n}\n", "/**\n * Notification Integration Module for SecureBit WebRTC Chat\n * Integrates secure notifications with existing WebRTC architecture\n * \n * @version 1.0.0\n * @author SecureBit Team\n * @license MIT\n */\n\nimport { SecureChatNotificationManager } from './SecureNotificationManager.js';\n\nclass NotificationIntegration {\n constructor(webrtcManager) {\n this.webrtcManager = webrtcManager;\n this.notificationManager = new SecureChatNotificationManager({\n maxQueueSize: 10,\n rateLimitMs: 1000, // Reduced from 2000ms to 1000ms\n trustedOrigins: [\n window.location.origin,\n // Add other trusted origins for CDN icons\n ]\n });\n \n this.isInitialized = false;\n this.originalOnMessage = null;\n this.originalOnStatusChange = null;\n this.processedMessages = new Set(); // Track processed messages to avoid duplicates\n }\n\n /**\n * Initialize notification integration\n * @returns {Promise} Initialization success\n */\n async init() {\n try {\n if (this.isInitialized) {\n return true;\n }\n\n // Store original callbacks\n this.originalOnMessage = this.webrtcManager.onMessage;\n this.originalOnStatusChange = this.webrtcManager.onStatusChange;\n\n\n // Wrap the original onMessage callback.\n // IMPORTANT: forward ALL arguments (incl. per-message `meta`) so the app\n // still receives view-once / disappearing / unsend metadata.\n this.webrtcManager.onMessage = (message, type, ...rest) => {\n this.handleIncomingMessage(message, type, rest[0]);\n\n // Call original callback if it exists\n if (this.originalOnMessage) {\n this.originalOnMessage(message, type, ...rest);\n }\n };\n\n // Wrap the original onStatusChange callback\n this.webrtcManager.onStatusChange = (status) => {\n this.handleStatusChange(status);\n \n // Call original callback if it exists\n if (this.originalOnStatusChange) {\n this.originalOnStatusChange(status);\n }\n };\n\n // Also hook into the deliverMessageToUI method if it exists.\n // IMPORTANT: forward ALL arguments (incl. per-message `meta`) to the\n // original, otherwise view-once / disappearing / unsend metadata is lost.\n if (this.webrtcManager.deliverMessageToUI) {\n this.originalDeliverMessageToUI = this.webrtcManager.deliverMessageToUI.bind(this.webrtcManager);\n this.webrtcManager.deliverMessageToUI = (message, type, ...rest) => {\n this.handleIncomingMessage(message, type, rest[0]);\n this.originalDeliverMessageToUI(message, type, ...rest);\n };\n }\n\n this.isInitialized = true;\n return true;\n\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Handle incoming messages and trigger notifications\n * @param {*} message - Message content\n * @param {string} type - Message type\n * @private\n */\n handleIncomingMessage(message, type, meta) {\n try {\n // Create a unique key for this message to avoid duplicates\n const messageKey = `${type}:${typeof message === 'string' ? message : JSON.stringify(message)}`;\n \n // Skip if we've already processed this message\n if (this.processedMessages.has(messageKey)) {\n return;\n }\n \n // Mark message as processed\n this.processedMessages.add(messageKey);\n \n // Clean up old processed messages (keep only last 100)\n if (this.processedMessages.size > 100) {\n const messagesArray = Array.from(this.processedMessages);\n this.processedMessages.clear();\n messagesArray.slice(-50).forEach(msg => this.processedMessages.add(msg));\n }\n \n \n // Only process chat messages, not system messages\n if (type === 'system' || type === 'file-transfer' || type === 'heartbeat') {\n return;\n }\n\n // Extract message information\n const messageInfo = this.extractMessageInfo(message, type);\n if (!messageInfo) {\n return;\n }\n\n // PRIVACY: a view-once or disappearing message must not be copied into the\n // OS notification. Notifications are shown only while the tab is in the\n // background \u2014 i.e. typically on a lock screen \u2014 and once the OS has the\n // text it lands in the notification centre, in backups and on the user's\n // other synced devices. From there the app can no longer delete it, so the\n // message the UI destroys after 30 seconds outlives itself indefinitely.\n // Show that something arrived; never what it said.\n const isEphemeral = !!meta && typeof meta === 'object' &&\n (meta.once === true || (Number.isFinite(meta.ttl) && meta.ttl > 0));\n const notificationText = isEphemeral ? 'Sent you a private message' : messageInfo.text;\n\n // Send notification\n const notificationResult = this.notificationManager.notify(\n messageInfo.senderName,\n notificationText,\n {\n icon: messageInfo.senderAvatar,\n senderId: messageInfo.senderId,\n onClick: (senderId) => {\n this.focusChatWindow();\n }\n }\n );\n\n } catch (error) {\n // Handle error silently\n }\n }\n\n /**\n * Handle status changes\n * @param {string} status - Connection status\n * @private\n */\n handleStatusChange(status) {\n try {\n // Clear notifications when connection is lost\n if (status === 'disconnected' || status === 'failed') {\n this.notificationManager.clearNotificationQueue();\n this.notificationManager.resetUnreadCount();\n }\n } catch (error) {\n // Handle error silently\n }\n }\n\n /**\n * Extract message information for notifications\n * @param {*} message - Message content\n * @param {string} type - Message type\n * @returns {Object|null} Extracted message info or null\n * @private\n */\n extractMessageInfo(message, type) {\n try {\n let messageData = message;\n\n // Handle different message formats\n if (typeof message === 'string') {\n try {\n messageData = JSON.parse(message);\n } catch (e) {\n // Plain text message\n return {\n senderName: 'Peer',\n text: message,\n senderId: 'peer',\n senderAvatar: null\n };\n }\n }\n\n // Handle structured message data\n if (typeof messageData === 'object' && messageData !== null) {\n return {\n senderName: messageData.senderName || messageData.name || 'Peer',\n text: messageData.text || messageData.message || messageData.content || '',\n senderId: messageData.senderId || messageData.id || 'peer',\n senderAvatar: messageData.senderAvatar || messageData.avatar || null\n };\n }\n\n return null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * Focus chat window when notification is clicked\n * @private\n */\n focusChatWindow() {\n try {\n window.focus();\n \n // Scroll to bottom of messages if container exists\n const messagesContainer = document.getElementById('messages');\n if (messagesContainer) {\n messagesContainer.scrollTop = messagesContainer.scrollHeight;\n }\n } catch (error) {\n // Handle error silently\n }\n }\n\n /**\n * Request notification permission\n * @returns {Promise} Permission granted status\n */\n async requestPermission() {\n try {\n return await this.notificationManager.requestPermission();\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Get notification status\n * @returns {Object} Notification status\n */\n getStatus() {\n return this.notificationManager.getStatus();\n }\n\n /**\n * Clear all notifications\n */\n clearNotifications() {\n this.notificationManager.clearNotificationQueue();\n this.notificationManager.resetUnreadCount();\n }\n\n /**\n * Cleanup integration\n */\n cleanup() {\n try {\n if (this.isInitialized) {\n // Restore original callbacks\n if (this.originalOnMessage) {\n this.webrtcManager.onMessage = this.originalOnMessage;\n }\n if (this.originalOnStatusChange) {\n this.webrtcManager.onStatusChange = this.originalOnStatusChange;\n }\n if (this.originalDeliverMessageToUI) {\n this.webrtcManager.deliverMessageToUI = this.originalDeliverMessageToUI;\n }\n\n // Clear notifications\n this.clearNotifications();\n\n this.isInitialized = false;\n }\n } catch (error) {\n // Handle error silently\n }\n }\n}\n\n// Export for use in other modules\nif (typeof module !== 'undefined' && module.exports) {\n module.exports = { NotificationIntegration };\n}\n\n// Global export for browser usage\nif (typeof window !== 'undefined') {\n window.NotificationIntegration = NotificationIntegration;\n}\n", "const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n} = Object;\n\nlet { freeze, seal, create } = Object; // eslint-disable-line import/no-mutable-exports\nlet { apply, construct } = typeof Reflect !== 'undefined' && Reflect;\n\nif (!freeze) {\n freeze = function (x: T): T {\n return x;\n };\n}\n\nif (!seal) {\n seal = function (x: T): T {\n return x;\n };\n}\n\nif (!apply) {\n apply = function (\n func: (thisArg: any, ...args: any[]) => T,\n thisArg: any,\n ...args: any[]\n ): T {\n return func.apply(thisArg, args);\n };\n}\n\nif (!construct) {\n construct = function (Func: new (...args: any[]) => T, ...args: any[]): T {\n return new Func(...args);\n };\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayIndexOf = unapply(Array.prototype.indexOf);\nconst arrayLastIndexOf = unapply(Array.prototype.lastIndexOf);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst arraySlice = unapply(Array.prototype.slice);\nconst arraySplice = unapply(Array.prototype.splice);\nconst arrayIsArray = Array.isArray;\n\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\n\nconst numberToString = unapply(Number.prototype.toString);\nconst booleanToString = unapply(Boolean.prototype.toString);\nconst bigintToString =\n typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);\nconst symbolToString =\n typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);\n\nconst objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\nconst objectToString = unapply(Object.prototype.toString);\n\nconst regExpTest = unapply(RegExp.prototype.test);\n\nconst typeErrorCreate = unconstruct(TypeError);\n\n/**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param func - The function to be wrapped and called.\n * @returns A new function that calls the given function with a specified thisArg and arguments.\n */\nfunction unapply(\n func: (thisArg: any, ...args: any[]) => T\n): (thisArg: any, ...args: any[]) => T {\n return (thisArg: any, ...args: any[]): T => {\n if (thisArg instanceof RegExp) {\n thisArg.lastIndex = 0;\n }\n\n return apply(func, thisArg, args);\n };\n}\n\n/**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param func - The constructor function to be wrapped and called.\n * @returns A new function that constructs an instance of the given constructor function with the provided arguments.\n */\nfunction unconstruct(\n Func: new (...args: any[]) => T\n): (...args: any[]) => T {\n return (...args: any[]): T => construct(Func, args);\n}\n\n/**\n * Add properties to a lookup table\n *\n * @param set - The set to which elements will be added.\n * @param array - The array containing elements to be added to the set.\n * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns The modified set with added elements.\n */\nfunction addToSet(\n set: Record,\n array: readonly unknown[],\n transformCaseFunc: ReturnType> = stringToLowerCase\n): Record {\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n\n if (!arrayIsArray(array)) {\n return set;\n }\n\n let l = array.length;\n while (l--) {\n let element = array[l];\n\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n (array as unknown[])[l] = lcElement;\n }\n\n element = lcElement;\n }\n }\n\n set[element as string] = true;\n }\n\n return set;\n}\n\n/**\n * Clean up an array to harden against CSPP\n *\n * @param array - The array to be cleaned.\n * @returns The cleaned version of the array\n */\nfunction cleanArray(array: T[]): Array {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n\n return array;\n}\n\n/**\n * Shallow clone an object\n *\n * @param object - The object to be cloned.\n * @returns A new object that copies the original.\n */\nfunction clone>(object: T): T {\n const newObject = create(null);\n\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n\n if (isPropertyExist) {\n if (arrayIsArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (\n value &&\n typeof value === 'object' &&\n value.constructor === Object\n ) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n\n return newObject;\n}\n\n/**\n * Convert non-node values into strings without depending on direct property access.\n *\n * @param value - The value to stringify.\n * @returns A string representation of the provided value.\n */\nfunction stringifyValue(value: unknown): string {\n switch (typeof value) {\n case 'string': {\n return value;\n }\n\n case 'number': {\n return numberToString(value);\n }\n\n case 'boolean': {\n return booleanToString(value);\n }\n\n case 'bigint': {\n return bigintToString ? bigintToString(value) : '0';\n }\n\n case 'symbol': {\n return symbolToString ? symbolToString(value) : 'Symbol()';\n }\n\n case 'undefined': {\n return objectToString(value);\n }\n\n case 'function':\n case 'object': {\n if (value === null) {\n return objectToString(value);\n }\n\n const valueAsRecord = value as Record;\n const valueToString = lookupGetter(valueAsRecord, 'toString');\n\n if (typeof valueToString === 'function') {\n const stringified = valueToString(valueAsRecord);\n\n return typeof stringified === 'string'\n ? stringified\n : objectToString(stringified);\n }\n\n return objectToString(value);\n }\n\n default: {\n return objectToString(value);\n }\n }\n}\n\n/**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param object - The object to look up the getter function in its prototype chain.\n * @param prop - The property name for which to find the getter function.\n * @returns The getter function found in the prototype chain or a fallback function.\n */\nfunction lookupGetter>(\n object: T,\n prop: string\n): ReturnType> | (() => null) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n\n object = getPrototypeOf(object);\n }\n\n function fallbackValue(): null {\n return null;\n }\n\n return fallbackValue;\n}\n\nfunction isRegex(value: unknown): value is RegExp {\n try {\n regExpTest(value as RegExp, '');\n return true;\n } catch {\n return false;\n }\n}\n\nexport {\n // Array\n arrayForEach,\n arrayIndexOf,\n arrayIsArray,\n arrayLastIndexOf,\n arrayPop,\n arrayPush,\n arraySlice,\n arraySplice,\n // Object\n entries,\n freeze,\n getPrototypeOf,\n getOwnPropertyDescriptor,\n isFrozen,\n setPrototypeOf,\n seal,\n clone,\n create,\n objectHasOwnProperty,\n objectToString,\n // RegExp\n regExpTest,\n isRegex,\n // String\n stringIndexOf,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringTrim,\n // Other conversion\n stringifyValue,\n // Errors\n typeErrorCreate,\n // Other\n lookupGetter,\n addToSet,\n // Reflect\n unapply,\n unconstruct,\n};\n", "import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'a',\n 'abbr',\n 'acronym',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blink',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'center',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'content',\n 'data',\n 'datalist',\n 'dd',\n 'decorator',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'dir',\n 'div',\n 'dl',\n 'dt',\n 'element',\n 'em',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'font',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'head',\n 'header',\n 'hgroup',\n 'hr',\n 'html',\n 'i',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'marquee',\n 'menu',\n 'menuitem',\n 'meter',\n 'nav',\n 'nobr',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'search',\n 'section',\n 'select',\n 'shadow',\n 'slot',\n 'small',\n 'source',\n 'spacer',\n 'span',\n 'strike',\n 'strong',\n 'style',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'tt',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n] as const);\n\nexport const svg = freeze([\n 'svg',\n 'a',\n 'altglyph',\n 'altglyphdef',\n 'altglyphitem',\n 'animatecolor',\n 'animatemotion',\n 'animatetransform',\n 'circle',\n 'clippath',\n 'defs',\n 'desc',\n 'ellipse',\n 'enterkeyhint',\n 'exportparts',\n 'filter',\n 'font',\n 'g',\n 'glyph',\n 'glyphref',\n 'hkern',\n 'image',\n 'inputmode',\n 'line',\n 'lineargradient',\n 'marker',\n 'mask',\n 'metadata',\n 'mpath',\n 'part',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialgradient',\n 'rect',\n 'stop',\n 'style',\n 'switch',\n 'symbol',\n 'text',\n 'textpath',\n 'title',\n 'tref',\n 'tspan',\n 'view',\n 'vkern',\n] as const);\n\nexport const svgFilters = freeze([\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n] as const);\n\n// List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\nexport const svgDisallowed = freeze([\n 'animate',\n 'color-profile',\n 'cursor',\n 'discard',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignobject',\n 'hatch',\n 'hatchpath',\n 'mesh',\n 'meshgradient',\n 'meshpatch',\n 'meshrow',\n 'missing-glyph',\n 'script',\n 'set',\n 'solidcolor',\n 'unknown',\n 'use',\n] as const);\n\nexport const mathMl = freeze([\n 'math',\n 'menclose',\n 'merror',\n 'mfenced',\n 'mfrac',\n 'mglyph',\n 'mi',\n 'mlabeledtr',\n 'mmultiscripts',\n 'mn',\n 'mo',\n 'mover',\n 'mpadded',\n 'mphantom',\n 'mroot',\n 'mrow',\n 'ms',\n 'mspace',\n 'msqrt',\n 'mstyle',\n 'msub',\n 'msup',\n 'msubsup',\n 'mtable',\n 'mtd',\n 'mtext',\n 'mtr',\n 'munder',\n 'munderover',\n 'mprescripts',\n] as const);\n\n// Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\nexport const mathMlDisallowed = freeze([\n 'maction',\n 'maligngroup',\n 'malignmark',\n 'mlongdiv',\n 'mscarries',\n 'mscarry',\n 'msgroup',\n 'mstack',\n 'msline',\n 'msrow',\n 'semantics',\n 'annotation',\n 'annotation-xml',\n 'mprescripts',\n 'none',\n] as const);\n\nexport const text = freeze(['#text'] as const);\n", "import { freeze } from './utils.js';\n\nexport const html = freeze([\n 'accept',\n 'action',\n 'align',\n 'alt',\n 'autocapitalize',\n 'autocomplete',\n 'autopictureinpicture',\n 'autoplay',\n 'background',\n 'bgcolor',\n 'border',\n 'capture',\n 'cellpadding',\n 'cellspacing',\n 'checked',\n 'cite',\n 'class',\n 'clear',\n 'color',\n 'cols',\n 'colspan',\n 'command',\n 'commandfor',\n 'controls',\n 'controlslist',\n 'coords',\n 'crossorigin',\n 'datetime',\n 'decoding',\n 'default',\n 'dir',\n 'disabled',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'download',\n 'draggable',\n 'enctype',\n 'enterkeyhint',\n 'exportparts',\n 'face',\n 'for',\n 'headers',\n 'height',\n 'hidden',\n 'high',\n 'href',\n 'hreflang',\n 'id',\n 'inert',\n 'inputmode',\n 'integrity',\n 'ismap',\n 'kind',\n 'label',\n 'lang',\n 'list',\n 'loading',\n 'loop',\n 'low',\n 'max',\n 'maxlength',\n 'media',\n 'method',\n 'min',\n 'minlength',\n 'multiple',\n 'muted',\n 'name',\n 'nonce',\n 'noshade',\n 'novalidate',\n 'nowrap',\n 'open',\n 'optimum',\n 'part',\n 'pattern',\n 'placeholder',\n 'playsinline',\n 'popover',\n 'popovertarget',\n 'popovertargetaction',\n 'poster',\n 'preload',\n 'pubdate',\n 'radiogroup',\n 'readonly',\n 'rel',\n 'required',\n 'rev',\n 'reversed',\n 'role',\n 'rows',\n 'rowspan',\n 'spellcheck',\n 'scope',\n 'selected',\n 'shape',\n 'size',\n 'sizes',\n 'slot',\n 'span',\n 'srclang',\n 'start',\n 'src',\n 'srcset',\n 'step',\n 'style',\n 'summary',\n 'tabindex',\n 'title',\n 'translate',\n 'type',\n 'usemap',\n 'valign',\n 'value',\n 'width',\n 'wrap',\n 'xmlns',\n] as const);\n\nexport const svg = freeze([\n 'accent-height',\n 'accumulate',\n 'additive',\n 'alignment-baseline',\n 'amplitude',\n 'ascent',\n 'attributename',\n 'attributetype',\n 'azimuth',\n 'basefrequency',\n 'baseline-shift',\n 'begin',\n 'bias',\n 'by',\n 'class',\n 'clip',\n 'clippathunits',\n 'clip-path',\n 'clip-rule',\n 'color',\n 'color-interpolation',\n 'color-interpolation-filters',\n 'color-profile',\n 'color-rendering',\n 'cx',\n 'cy',\n 'd',\n 'dx',\n 'dy',\n 'diffuseconstant',\n 'direction',\n 'display',\n 'divisor',\n 'dur',\n 'edgemode',\n 'elevation',\n 'end',\n 'exponent',\n 'fill',\n 'fill-opacity',\n 'fill-rule',\n 'filter',\n 'filterunits',\n 'flood-color',\n 'flood-opacity',\n 'font-family',\n 'font-size',\n 'font-size-adjust',\n 'font-stretch',\n 'font-style',\n 'font-variant',\n 'font-weight',\n 'fx',\n 'fy',\n 'g1',\n 'g2',\n 'glyph-name',\n 'glyphref',\n 'gradientunits',\n 'gradienttransform',\n 'height',\n 'href',\n 'id',\n 'image-rendering',\n 'in',\n 'in2',\n 'intercept',\n 'k',\n 'k1',\n 'k2',\n 'k3',\n 'k4',\n 'kerning',\n 'keypoints',\n 'keysplines',\n 'keytimes',\n 'lang',\n 'lengthadjust',\n 'letter-spacing',\n 'kernelmatrix',\n 'kernelunitlength',\n 'lighting-color',\n 'local',\n 'marker-end',\n 'marker-mid',\n 'marker-start',\n 'markerheight',\n 'markerunits',\n 'markerwidth',\n 'maskcontentunits',\n 'maskunits',\n 'max',\n 'mask',\n 'mask-type',\n 'media',\n 'method',\n 'mode',\n 'min',\n 'name',\n 'numoctaves',\n 'offset',\n 'operator',\n 'opacity',\n 'order',\n 'orient',\n 'orientation',\n 'origin',\n 'overflow',\n 'paint-order',\n 'path',\n 'pathlength',\n 'patterncontentunits',\n 'patterntransform',\n 'patternunits',\n 'points',\n 'preservealpha',\n 'preserveaspectratio',\n 'primitiveunits',\n 'r',\n 'rx',\n 'ry',\n 'radius',\n 'refx',\n 'refy',\n 'repeatcount',\n 'repeatdur',\n 'restart',\n 'result',\n 'rotate',\n 'scale',\n 'seed',\n 'shape-rendering',\n 'slope',\n 'specularconstant',\n 'specularexponent',\n 'spreadmethod',\n 'startoffset',\n 'stddeviation',\n 'stitchtiles',\n 'stop-color',\n 'stop-opacity',\n 'stroke-dasharray',\n 'stroke-dashoffset',\n 'stroke-linecap',\n 'stroke-linejoin',\n 'stroke-miterlimit',\n 'stroke-opacity',\n 'stroke',\n 'stroke-width',\n 'style',\n 'surfacescale',\n 'systemlanguage',\n 'tabindex',\n 'tablevalues',\n 'targetx',\n 'targety',\n 'transform',\n 'transform-origin',\n 'text-anchor',\n 'text-decoration',\n 'text-rendering',\n 'textlength',\n 'type',\n 'u1',\n 'u2',\n 'unicode',\n 'values',\n 'viewbox',\n 'visibility',\n 'version',\n 'vert-adv-y',\n 'vert-origin-x',\n 'vert-origin-y',\n 'width',\n 'word-spacing',\n 'wrap',\n 'writing-mode',\n 'xchannelselector',\n 'ychannelselector',\n 'x',\n 'x1',\n 'x2',\n 'xmlns',\n 'y',\n 'y1',\n 'y2',\n 'z',\n 'zoomandpan',\n] as const);\n\nexport const mathMl = freeze([\n 'accent',\n 'accentunder',\n 'align',\n 'bevelled',\n 'close',\n 'columnalign',\n 'columnlines',\n 'columnspacing',\n 'columnspan',\n 'denomalign',\n 'depth',\n 'dir',\n 'display',\n 'displaystyle',\n 'encoding',\n 'fence',\n 'frame',\n 'height',\n 'href',\n 'id',\n 'largeop',\n 'length',\n 'linethickness',\n 'lquote',\n 'lspace',\n 'mathbackground',\n 'mathcolor',\n 'mathsize',\n 'mathvariant',\n 'maxsize',\n 'minsize',\n 'movablelimits',\n 'notation',\n 'numalign',\n 'open',\n 'rowalign',\n 'rowlines',\n 'rowspacing',\n 'rowspan',\n 'rspace',\n 'rquote',\n 'scriptlevel',\n 'scriptminsize',\n 'scriptsizemultiplier',\n 'selection',\n 'separator',\n 'separators',\n 'stretchy',\n 'subscriptshift',\n 'supscriptshift',\n 'symmetric',\n 'voffset',\n 'width',\n 'xmlns',\n]);\n\nexport const xml = freeze([\n 'xlink:href',\n 'xml:id',\n 'xlink:title',\n 'xml:space',\n 'xmlns:xlink',\n] as const);\n", "import { seal } from './utils.js';\n\nexport const MUSTACHE_EXPR = seal(/{{[\\w\\W]*|^[\\w\\W]*}}/g);\nexport const ERB_EXPR = seal(/<%[\\w\\W]*|^[\\w\\W]*%>/g);\nexport const TMPLIT_EXPR = seal(/\\${[\\w\\W]*/g);\nexport const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]+$/); // eslint-disable-line no-useless-escape\nexport const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\nexport const IS_ALLOWED_URI = seal(\n /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nexport const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nexport const ATTR_WHITESPACE = seal(\n /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nexport const DOCTYPE_NAME = seal(/^html$/i);\nexport const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n\n// Markup-significant character probes used by _sanitizeElements.\n// Shared module-level instances are safe despite the sticky /g flags:\n// unapply() resets lastIndex for RegExp receivers before every call.\nexport const ELEMENT_MARKUP_PROBE = seal(/<[/\\w!]/g);\nexport const COMMENT_MARKUP_PROBE = seal(/<[/\\w]/g);\nexport const FALLBACK_TAG_CLOSE = seal(/<\\/no(script|embed|frames)/i);\nexport const SELF_CLOSING_TAG = seal(/\\/>/i);\n", "/* eslint-disable @typescript-eslint/indent */\n\nimport type { Config, UseProfilesConfig } from './config';\nimport type { DOMPurify, HooksMap, HookFunction, WindowLike } from './types';\nimport * as TAGS from './tags.js';\nimport * as ATTRS from './attrs.js';\nimport * as EXPRESSIONS from './regexp.js';\nimport {\n addToSet,\n clone,\n entries,\n freeze,\n seal,\n arrayForEach,\n arrayIsArray,\n arrayLastIndexOf,\n arrayPop,\n arrayPush,\n arraySplice,\n stringMatch,\n stringReplace,\n stringToLowerCase,\n stringToString,\n stringIndexOf,\n stringTrim,\n regExpTest,\n isRegex,\n typeErrorCreate,\n lookupGetter,\n create,\n objectHasOwnProperty,\n stringifyValue,\n} from './utils.js';\n\nexport type { Config } from './config';\n\nexport type {\n DOMPurify,\n RemovedElement,\n RemovedAttribute,\n HookName,\n NodeHook,\n ElementHook,\n DocumentFragmentHook,\n UponSanitizeElementHook,\n UponSanitizeAttributeHook,\n UponSanitizeElementHookEvent,\n UponSanitizeAttributeHookEvent,\n WindowLike,\n} from './types';\n\ndeclare const VERSION: string;\n\n// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\nconst NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5, // Deprecated\n entityNode: 6, // Deprecated\n processingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12, // Deprecated\n};\n\nconst getGlobal = function (): WindowLike {\n return typeof window === 'undefined' ? null : window;\n};\n\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param trustedTypes The policy factory.\n * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\nconst _createTrustedTypesPolicy = function (\n trustedTypes: TrustedTypePolicyFactory,\n purifyHostElement: HTMLScriptElement\n) {\n if (\n typeof trustedTypes !== 'object' ||\n typeof trustedTypes.createPolicy !== 'function'\n ) {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n },\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn(\n 'TrustedTypes policy ' + policyName + ' could not be created.'\n );\n return null;\n }\n};\n\nconst _createHooksMap = function (): HooksMap {\n return {\n afterSanitizeAttributes: [],\n afterSanitizeElements: [],\n afterSanitizeShadowDOM: [],\n beforeSanitizeAttributes: [],\n beforeSanitizeElements: [],\n beforeSanitizeShadowDOM: [],\n uponSanitizeAttribute: [],\n uponSanitizeElement: [],\n uponSanitizeShadowNode: [],\n };\n};\n\n/**\n * Resolve a set-valued configuration option: a fresh set built from\n * cfg[key] when it is an own array property (seeded with a clone of\n * options.base when given, case-normalized via options.transform),\n * the fallback set otherwise.\n *\n * @param cfg the cloned, prototype-free configuration object\n * @param key the configuration property to read\n * @param fallback the set to use when the option is absent or not an array\n * @param options transform and optional base set to merge into\n * @returns the resolved set\n */\nconst _resolveSetOption = function (\n cfg: Config,\n key: keyof Config,\n fallback: Record,\n options: {\n transform: Parameters[2];\n base?: Record;\n }\n): Record {\n return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key])\n ? addToSet(\n options.base ? clone(options.base) : {},\n cfg[key] as readonly unknown[],\n options.transform\n )\n : fallback;\n};\n\nfunction createDOMPurify(window: WindowLike = getGlobal()): DOMPurify {\n const DOMPurify: DOMPurify = (root: WindowLike) => createDOMPurify(root);\n\n DOMPurify.version = VERSION;\n\n DOMPurify.removed = [];\n\n if (\n !window ||\n !window.document ||\n window.document.nodeType !== NODE_TYPE.document ||\n !window.Element\n ) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n\n return DOMPurify;\n }\n\n let { document } = window;\n\n const originalDocument = document;\n const currentScript: HTMLScriptElement =\n originalDocument.currentScript as HTMLScriptElement;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || (window as any).MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes,\n } = window;\n\n const ElementPrototype = Element.prototype;\n\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const remove = lookupGetter(ElementPrototype, 'remove');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');\n const getAttributes = lookupGetter(ElementPrototype, 'attributes');\n const getNodeType =\n Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;\n const getNodeName =\n Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n\n let trustedTypesPolicy;\n let emptyHTML = '';\n\n // The instance's own internal Trusted Types policy. Unlike a caller-supplied\n // `TRUSTED_TYPES_POLICY`, this is created at most once \u2014 Trusted Types throws\n // on duplicate policy names \u2014 and is the only policy allowed to persist\n // across configurations and survive `clearConfig()`.\n let defaultTrustedTypesPolicy;\n let defaultTrustedTypesPolicyResolved = false;\n\n // Tracks whether we are already inside a call to the configured Trusted Types\n // policy (`createHTML` or `createScriptURL`). If a supplied policy callback\n // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would\n // re-enter the policy and recurse until the stack overflows. We detect that\n // re-entry and throw a clear, actionable error instead. The guard is shared\n // across both callbacks, because either one re-entering `sanitize` triggers\n // the same unbounded recursion.\n let IN_TRUSTED_TYPES_POLICY = 0;\n const _assertNotInTrustedTypesPolicy = function (): void {\n if (IN_TRUSTED_TYPES_POLICY > 0) {\n throw typeErrorCreate(\n 'A configured TRUSTED_TYPES_POLICY callback (createHTML or ' +\n 'createScriptURL) must not call DOMPurify.sanitize, as that causes ' +\n 'infinite recursion. Do not pass a policy whose callbacks wrap ' +\n 'DOMPurify as TRUSTED_TYPES_POLICY; see the \"DOMPurify and Trusted ' +\n 'Types\" section of the README.'\n );\n }\n };\n\n const _createTrustedHTML = function (html: string): string {\n _assertNotInTrustedTypesPolicy();\n\n IN_TRUSTED_TYPES_POLICY++;\n try {\n return trustedTypesPolicy.createHTML(html);\n } finally {\n IN_TRUSTED_TYPES_POLICY--;\n }\n };\n\n const _createTrustedScriptURL = function (scriptUrl: string): string {\n _assertNotInTrustedTypesPolicy();\n\n IN_TRUSTED_TYPES_POLICY++;\n try {\n return trustedTypesPolicy.createScriptURL(scriptUrl);\n } finally {\n IN_TRUSTED_TYPES_POLICY--;\n }\n };\n\n // Lazily resolve (and cache) the instance's internal default policy.\n // Resolution is attempted at most once: a successful `createPolicy` cannot be\n // repeated (Trusted Types throws on duplicate names), and a failed or\n // unsupported attempt must not be retried on every parse.\n const _getDefaultTrustedTypesPolicy = function () {\n if (!defaultTrustedTypesPolicyResolved) {\n defaultTrustedTypesPolicy = _createTrustedTypesPolicy(\n trustedTypes,\n currentScript\n );\n defaultTrustedTypesPolicyResolved = true;\n }\n\n return defaultTrustedTypesPolicy;\n };\n\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName,\n } = document;\n const { importNode } = originalDocument;\n\n let hooks = _createHooksMap();\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported =\n typeof entries === 'function' &&\n typeof getParentNode === 'function' &&\n implementation &&\n implementation.createHTMLDocument !== undefined;\n\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT,\n } = EXPRESSIONS;\n\n let { IS_ALLOWED_URI } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [\n ...TAGS.html,\n ...TAGS.svg,\n ...TAGS.svgFilters,\n ...TAGS.mathMl,\n ...TAGS.text,\n ]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [\n ...ATTRS.html,\n ...ATTRS.svg,\n ...ATTRS.mathMl,\n ...ATTRS.xml,\n ]);\n\n /*\n * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false,\n },\n })\n );\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */\n const EXTRA_ELEMENT_HANDLING = Object.seal(\n create(null, {\n tagCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n attributeCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null,\n },\n })\n );\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with ... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (\u00A77.3.3)\n * - DOM Tree Accessors (\u00A73.1.5)\n * - Form Element Parent-Child Relations (\u00A74.10.3)\n * - Iframe srcdoc / Nested WindowProxies (\u00A74.8.5)\n * - HTMLCollection (\u00A74.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES: UseProfilesConfig | false = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n const DEFAULT_FORBID_CONTENTS = addToSet({}, [\n 'annotation-xml',\n 'audio',\n 'colgroup',\n 'desc',\n 'foreignobject',\n 'head',\n 'iframe',\n 'math',\n 'mi',\n 'mn',\n 'mo',\n 'ms',\n 'mtext',\n 'noembed',\n 'noframes',\n 'noscript',\n 'plaintext',\n 'script',\n // mirrors the selected