From 5ff8960b7b310dbe4f3f037338a5738ea031f515 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Tue, 26 Aug 2025 16:44:10 +1000 Subject: [PATCH] feat: Add initial internal node option --- .gitignore | 2 + FireWalletBrowser.bsdesign | Bin 343534 -> 344794 bytes README.md | 2 + account.py | 213 ++++++++++++++++++++++++++++++++++++- hsdconfig.json | 8 ++ main.py | 24 +++-- server.py | 2 +- templates/settings.html | 42 ++++---- templates/welcome.html | 47 ++++++++ 9 files changed, 310 insertions(+), 30 deletions(-) create mode 100644 hsdconfig.json create mode 100644 templates/welcome.html diff --git a/.gitignore b/.gitignore index f73a8c4..d8ad3fb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ cache/ build/ dist/ hsd/ +hsd-data/ +hsd.lock diff --git a/FireWalletBrowser.bsdesign b/FireWalletBrowser.bsdesign index 3e627ef733c7c56a9d750c3f7fe134af96428d63..6eb424148cb738aaec6d8ff3e85ba6b4f3821490 100644 GIT binary patch delta 29301 zcmb@tRal(cqHT*5!QI{6T>}a3?hxDwP9SLE9)cI{65JuUTX1)Gm*9HIw6*45a`*Yp zd8+4n82{*__0~@wFctzaqdvf(vxrUd1a)-#ng*JJ2bw|znnKo^0{9w$n+wTjrE3-% z3KN|9+dT545&Zk?p_5)m$rO{*BP(y&znbC4- zLgPf?RL6w)xMYSGj1-oz`Mqi_K316wd_Ey8{3Qu;)Ej4;Qqh&5|uwWXFikBo{+8 zaiisfT2Wb;A-^bu?6tlQrB(bMlN1Z3xOy~_^ign`q|;*vUcm4sG=mjvSyND4BKZ^S zb%LNF&Y~jO(Od&5zLnrb*|pMpJ0&W9I-ga?GJu9aj_(^sN)2IpKfwF&F^vp~*(OyT zhk3bUAdO;}*}FHZ_|gb=4Sjf#WUBqEecu>(d;dw5`$DRcmT zK~+c9Pw5GvgfnX3hpti&WEYJ&cx38|{Z=p+0wmGyz$wfOi9DdJ;YQL4lyGc??(<`X zKgN<{=EotHYM$uBsj<$In{i?4l}=rVp{H9`p;ZWxF&rJTw!y>HmHbLaSaE6QPDVls ze!Z<(n6>^6LuxsOUnV}8M6x9*?vvpAO-~wX?{pW5-O9ye+Z``GbbLoM04hFTm`G_2 zE0EXZvtTcHaW|8Ung7O1=p^a>oFcc_GT#7cR(Z>$JkgTbygptRKk8 zIB4ek5Q%Jkqq;zFT@4Ea>;C{-D$~9Tttn&(>#rMoHGWwv|w1YTLnjUP-2R*MGz3T0XR%8 z-!jywOgXH>QaSlyxSTu@qhqC!>t%+t-m-Lgl37>5COH=)Z$-APeFiX>?87I_(ZIiw zLt|YD5_Y?@y>D>lSMPx_2+&d}KCS3%^$6DRVx8?>w?ijcH5FGL`eL3WT@FpKp#l*V`q5rWg$&V8iN ztZOj((FRz-_V)ri@;1{6JLC;D6U1SK7exG_>=eks)N!34Nk|58n|UCMuAm+>CDq7r zrF&DCk~mMg*oL#}Pa|7l9!h35>}lzW2CBzdpv;Sll2(D?7cfw;i^IOmYPHb zo0qK}SA$(hn*~=#Bt3I&^^#QrKWDgv$wi5wwdov3%uK2|Z*gQE%)V#i1M&XhX-ZzE*SzQR`Y)U)byIxr7*y5jd= zxh{Ud`S&DpRo1t!+Rmdq2&rwT@0;lcSliZAM%-XiW@+SSJ$k zvf}-{c0GgDHx%*Z4e@jQr>`6@pm)K$f@RI$uEex&$z+#ZM$2;bGU`FPez5X{QbRv; zvS}LtV{(#Fd3zFcQQ(QDTU;0O$oUKXIZSx^sF|Y^9P&(kn{iPjyjSw4u;{>s-(5en&g`*TK{~uEJrA2FHh*(%a;3YA61Ag zj8DJ}aUriTFt9bs7n!@p$FCa@JKwAzjiS`WxAKI5Ed&MCJ3x0{rsa?iO3zgw+VD2I z4EN7xIe5CX~l&4p>^zDHBhuf0^B{`xWX0k&=iJrME(o`{Bv-xteXVW$d z-T87K7q&uL%5-rrL7{*4;*}1 z;5;iGxUHUGv$DX97qnmSzpa)g+h*n4X`L!c)1}!jXDyvY)(K}1&T*CZ@Q`3Uj?yWZ zoF{EuYDXr8*{cj}IIrN3lk!xg?gQV=5M0OsPux-j7Z|aFU&Qb)Se(wV< zcLS(__oAz<3R5ywFGbwErm%_hccSID_36rSChzabJ&s;v*w#8=6uU9G6}inAVHLs( zf{0``z-aa1D@brN`$cY%d|@d`+xD)?xes`W!g+sca<8kb*eNG*eiem<9ix3&oTL`| zDRYaqZt)}I@?rpX4am51ru2AwOKbEJ(YJ;T^6vp)&=7_xyLd4bZT#SVFP^cpF)-r; zjPuY%G!x3WeT>!JX{SHtD)4N3qye?{0LaKLJcE5j! zwOQTZZZ4bf4urN8Dt6NFpL>{_FGe%R~K7wOGLHuGY|JY_Kenm(Z*i z9P;X>!p~|@*?Ohl{AgN^xz)JTD<`VHpSJb=WSg7w6h}Ojok15yP&`43p z=9QYTlN}q-&%Xg?ELFyToKY^Ljc%WWp=t40v*LQQWI;dwk#bS#&|Rm~?8*uLNw+we zpTUrRwq(H0+UH~DeT-iA#I;<0`_1KZ!p1-a_Bv`%TP^JHk#`N%8G-iNsUUZWs=0<(!Va=(Z%};`PfAmnKm8KTuMMTdh z>{}?6Oa1~#h+XqtX7SpD@3f^0*R86yv2UgQ+NEHBW^l08;>e>Cv$51@4-2SLj5wy3 z4hM)l!8zdr8_{v(Ah$xo$k{OlY{R^^7jb_?yR*S5!Sx_IY(XV`waw1hWi`}dJP$&S z*F1Ml2ueL~`Z%7ePRrFcbiIn|;;9?sHwLOG&IV)>i<4U`t?zzSi zBv?M2{E(9IB%f;i{!#*$Qh;-^T=236=;LZ<09j7u=gPE1cTsZ7H7CK8`|f$LP!!xa zGFR{r#<3vcY_KmPT*D0C=hn(0FSF<>g^DiMwF9LavKtMPI_Es;nWvQ7(+9*rC4V+VTGO&dcV?sXRe7~|-2FyuwDtt;(pymA z0DuOZA5`}G1AJRQAd}L}LFZPO$B+;z-z31GD$n2A^&CZ3G~p&H5gFPFL%hb0AxZU25NCxUsVpk!6dQ_=;EPkbu9LQ%^<0Ue z4%f$+;`RkD>qVCe8zKb1(Rd{&5>-|>4(o*=$_o*0n>Oj`TFR3SL3D#E@I^YMVo_Hq zKU&tRFlR+0A!o5bt;1~+C+z#WBY4}xH zJLI6mK|m&i<0y!42tWuV=G8W6L1wj>eV`*!)I|e41u%{$zv&ni&Fcz4`r_20|MK zgi?GqD89SZWc1?+Afv5}6*`QmoG-$HR2zH?eOtY-{jDZkb7~aSHVhCz`+`)42fgd7 zWy&jBiLE#S(tiPwAVHCU7)Jo2*bVvxZiy9f$!&QIcMB4(40vQnxp7M=ppX#&4TR$h z=f%c_>cp3dk`0$*W^rLgR7GsC!{N;mcy5ZyY==QE}9F3#GSygdPt`EN{8 z(^M{W1tZo1_IX=_n37S#=0?9}bFEP|nig7p+Xp2Y3A<6Ybp6;KD7fxX-wy25t>|TQ%OCFNgTJQe7fZZAx{9j!Mi|_695tL zO3=gvK;ZSfBToXtff8^zqU}4BGm%>S>ehV*R8Za8)#5V|g+FPVMSS-c4e5W)5{9VgZrTOVmokVb7AxVVwy_pL3UW0TDg zJLLHws=tmIMCX4wW@`g~9y1OrN?9T5pBBa*oz3L~3uzvptgwiK<wQ2ayo zygEV6sMt^LRlP;AT8B}N<xk?kT}z^Lx`10C1wdq%WOr&D2$C={z+_FqdqW> z+SY4x)&ixN4L5KOwmmAFOY_r}jU9<_3CMy1CX$?t&*_w{u?%FRu%UxE7KpkY9?r8H zdnfC@rTMugd=+HTN-{oF`;?zuutrO*?h;hPO^WIkwiEw%-v@XIibD|J2!M@%U_Gu| z@c;f}0eo?%=DG>f{lV$?C{X!|-!>R03m+~Yd%|O@W7$Q#OmXc;(<^=ChQ6xseb)&b zup-=4k7Uh`8!OWB6wAigfZ>Fhdi$x6y#3N8VGQkhnUd$UYQ~-WNn03stHVXMLi&Z^ zo+A%BEhZx)u|z1ne1e!0zWb-u;9mG>iM(Zj3UKb+SuIb~4dddo;dZ5~+ojTm5<#_N z{_88#$kZwDB2bMNDMFmylA-SZLS2~sHm!r0$+LxRg)hV6iqEAcF&i0u(e z&HyV{BkCS8mCJ1!H8uODKf8VB8u1)^cxTpOJ8!j<0=dV5Q}eFO1%c$sPVIICAVWh| z3^do-oB#TlKC^dfaoH8&W%osrDv3V9W}du4BL3LGY)UpE;7UVsJ+AX}-Kf(i^uQR( zD+s_Rf3<1v612rIRru)pC@63Q@N3`EGBY93xint}N!n``>2|_oLuPoAe&uTojI~P) zU8O{@85$X|b5>q(!HCKfN-%c=h_?i503bD(1T~nPQcP#SQ;MGu8&0}kJ%w<3BX)=+ zKp4SDSOq2@W5tjdA~6g(fMz&ma$FtZ%ZF<)qAJB)x=UTXlCgS}d)K4E5?QUJg*Mr% z_T*^pg&qoA@d84i!efCR*o3}5g}5&>mdoZzItpHx+0K$>Fp?$Zyf4ORbPMu5HSFdzrwo2lvu@4?bb_Fisg)PaXr{OX?v)Q=y zNnYo3!9$hI{0Y%wl!0=n{PANyyiXkthLMzD`UCVB6;c8nK1-Zj+X|MCnbmLVp9rwm zAJqL^9$)y0247M8LWyP2iRdLnUjfvi{(3c1cQ%snRISs2FrCZ!s99s%Gm>^De%hFS z>YW;{FS_|7y-PRL7*zyLggs|TZ|O@|zy7)1ce3YXT;fEYQ_~f1#41|oxFU-#2nf>{ zF@hQzB~!ua!l&2l-X`dn$IIHY0t#eT(svT*o@Y!dfu4)5GHt_0##5ojfa zzq#tCRG)uF6>kD8pG!7pet^I~O%Exw)?;x$&%LT`r$;fz*G2^6tQZ zg@Cd5c6l~ZUHm!qWU2c{J`atJ(ewv~tYe&$k}DjlUrEo}PukcTTc+j}RC8=e2AVceeF{GS2an80 zG|8H0lvW`KHT6f&Ke<(Iv=F8-5)y(_Oi9^GxY87n8}7zH|3Uh3BvDs(JO#{MA0jn( z195Kblsz@uC`2efAF)iR6<80fC-)&h!a^*CY}4>;yULqvq5v9m7hl+UU-O^WL8-%< zeoL5=m3SDNd@kLxB0B>!EHiv%b55(vP^5UTxtZ`5EQ9zu;8DiZgc7zUGLPmWb zeU$dC+vXnDm2~x2dwCOL$|Nto$^PWv862$xHe$aXO#)Aj!XMO0*-g=bcAgyTXffOZ zHG_ZSr?ow39SPibO>vxJyu(Zx&%YDBO(auzq2j=_SXSlN zB){?3BV0&yj#Q_zAD}vmEbXuyYBJ`zecE$$b^sdgWS2;g=^!%BK+ny|{ZB|}nw{G{AQ1Xzz?hJFa(_{xNsK5y)48wX#mfLE7DY;hNY(L*)9I3au`6>p7YW6c0D+ z#S)vvl{z;T7(p4ODsfwjDj{d`o0KWTnO-e?4f9P=+wt{UJ zyyJ_kWk>?NsM<{+>(sK+f@<8*(xkaWH6SO=P36W><#)O4otmi)d z0g4uqptBN04Gu*F%;`|I3F1*sTQ$8!y}~#q(Z>CObvf|1I(8%29kvvWPtW-a_pegP zm(=7Gi;C6r&JPWc6$Hf?tlwMsaFRxSeCcdS2Qajp%S=@iWs(=gGs`s@|qU#sD zJ&PipuDSI{xRtL85um1EGR|bPKRzD+5T4T%3|*J}_3JcQhzJcDZY>aC5u@j4ZhpR0 zlwc=SyX52}RQw@Qx+z5LX$T3qsvCjRI9t`GAAWioR<-v#pO!M4t}DaW8D#pri5iFw z=|**k>X2p`mIK`y8TrJ}n2&j8{HKQ|m&6dvsTFEq{ z>MlVi%1APHGp|(G-3cp@sf4&xqe|V*mib}!k<{Z8yZJYn5s)kr6gxhqywp+b!>8n6 zSee2*ogXpfUe0~lq#N&~2UmWao4}KFdS~m@+QzUYM=hHdwc4~8yaUtk;!K5%dDGIC3JMA-)8j~Hv~o1w z$JYM5B_ehFG)so3?2vR(&Sgbb-#3SqWZmtz8TxBEI~gRgy9}aO`cP&v;s*`( z9p-g+H@sE1bLIH~(^D;(8fm3BBnMMqQO&jR;c3nOpgT^MW!4n-il;>*qR(}-H+#u6 zB9OXdmi_fwJ0=yAlFb%%wXT_7CD@f|hdT#;Vi?9^J4&kO5mo9e46sV2Orp#h>(fFc z2$8EpW{%Yh?BWfW9mH}Hp^0tsTA+)2T1!JF?*mVY8S3Xt-S!a=S3?j=@1E=@)oNt? z;Nb>cg&%ZO7wggfwuCkie%CMUP2#tlS^1tBtsrlK=$L4t#)tE(a#tg#^8P&CXqrGE zk1*l}nZkzyn4_vvQ*AkQSgRwnR9CHq#uOe<`@-js=;$Tc$0F3_<)~W{oo~O#h$q7& z5ht;J%T7v!FK`~wu6`%*r4qsAW~i6z*a+VRPZRNDi2$5ibH&A6lfXUAIZdS2Rlg8A zk5!YhAg7z*teqbl%hF+DjV>EbgL4 zg$fU#y#x1a>?pDlQs=M`D+-kK>h}W+0()pT*Qh2YI~sY1m5bqlL%D`DTmb??p_tG< z(8Jlg!F;gSwG+YSiNn8 zIUNEq-;Hzn;Z)N;bZ1}4#BMO8^o@R@eEr8`UE&7;ViO}FldPueno0R%EENw5CdIoM3L?SDVwFpGLwi z{LkAX>`w6Ae5-_|Z<#B>bRP7Lz^RtTZmJ=gFw=BSKf<4WoEK`sq@a>(#Q7?AsD88r zdn#3OsBqNRa4R;YdCEH!&p6AP%fi9_U@)>D-NBM|j48PG>wbs=C{IP6$m8 zw1)DFtH^+jELXEcuFM@|Nzzem&RDM61n*EPBI|7nd~SP^w&6az(qF@tjRvEG{+$Nb z-YpaNY;(=$P{5?dvAl69mE#Rk=>`Tz2o&i|Pik~!)ilJ9>TaR_!oUQ`D#t(S*)hBV zj7Q%)h!D8F-^oeY+vTO7RJ7CVwphB8mp8ZUudMljC1-`Xo<-e0KIOx}+$3fhMqa6B z-+4)(FM=%xBX+ba;oE4BzFbB1ZYCmQl$9z@gdvsH?RN|e;F0Qytp;YTn)8VDpa3Q1 z;B|qXFSaiy;$XbGq#L7Pt{bM|dhS0IXTK#OU1t?MK{k6p z;(zCcAaF*ON4k!Nr;U1XtU+pT$NlzI3a~_bSa`+i-xO^LP2wPR7Y~8hYnNOZW&4Ky z4iRNgGc}^u{C@Km2@Rm)S;Acm}eQrz%I#EP>Mj z*Y-D-3wo}ctc%byR5rhPW5mPr^Hr@m&RdC>vJH7q-~Y0q8(UZu8-ht~gTLAm~0qlY#9~~xh zl3Gy3adBI5JxpSR?Zk!S$Ql{%lS8dO?lXuAv7q+XSQlhDEjm3S^TT`CQ8-VsjW1+;5hX@>@f}@O!QvU{PJ4V~Au`TxnGh95%|S zOl1z=3~1vgfE=_p2*85~wgmx(03@sxswt$As=KbZ-lA{C_$}1mR6%(;jvnRSX6XqR zGely4*!+@u+TmbOG1nwEIEd6O0rEHm7y^ZuT^};6+rr>SZu^(k+gT%%FV0rnTxOWf zP|fL4enBdGA{_G~Cc&V$`rj_PApM-*U8}8((*;0F(KseJfW75Fmz4wMyoy5|0g7wr zty|P^!s?|_r~StHR@X{;o}C4M}@=w$-g14n14lF76l0Zgt&G#jcZ{xP{KsT8NritL2L6` z0`*1PI?9YU1Z$&KpqvRNBPF5gE`J7Ak>NxdHT(s32_Lsgo8O(UDAad zrSB?Y%HrD@$WGBB_^^*-(9N}a>6)EdWf{3#qw+0DGg+$8rYc~G1+J2wYM=|U-D$UhI2vwJB{ zn0=`K$y(6iz;q^_&T_>sH0{XBo3JAe=6WXnt{$mD#`-uN=)LZKFhP+=b7gi9RY&z| z3r(S>4=kS(iD`wmVEh<#ogB?utfUhMBOh{C_X@_mUgmE;2yfs*0;Yi7F|o%OnK_}e zGr$?9!PKm3Tj^vq?ZPeNnU|K4)$6J+0@Z8^a)aD)%c5nhWGriy7bYhs%|6xmYe}Pr z=|3zOARR^lkCEV9=N^W9;I@3ZV&>sY@NJxReLZpP+wUzP38)xVu{lfl0<^-3zK4xm z86^5~&AL7|wDPAKU_kj!~A$Bi(%zEYoaI7%ki z%FODm0DX^wNSltgi0qNArPn(f3<|)h4)$tQDnBJ;5i8`Hrgw^cxy;pIXQ7@~ zmKbZI>4RQ)PnWb1U_Qan11=EHuxLE*zkbcg25mCjTB=UZzb23}wYjEzUgaY%EgtkM z&OXSFc{KKFscp{zM z2i{6iBApZ?t!y{^)k0HfOLg4M--RpLTuxm|TDqPJoYTNUP*Wn1>+nm4{X$&mEjRI6 zvv_eS!vpG0)*=QRh*3@gn%VTLBV+d{dV~mntDUdDZy*w@u4ixYy-mv_Eq7ti;V4w2 zV5YR^;3Odjj-^KKTo?kVWk=6BoyP+dyS=?Jb~j$zXPL>W%?Zy))~rXA$B2P0j276; zn?Ny$je+?;@m6j=)bDu9mE5N}lK_!1c-1xE(hzz>QNMvNMVct`m_h19`kYG_suAhQeKG`!zkk~+TXq}{vO?{Aj!Wjxw=f}JJ?Yi(zJvQ(3p zeO7G7?IRQ@j$P~m19%7i1Hxlp0^g)*9vpu#nP~V3aiXvPYw#EgNIp=FnJ9 z)mX-y^xijgk5HQ*F>Nt@)0L#Oe6CZ&6FxRchU5zL;eRyDO&|KsqBYs;tIc?R^~=TF zM#QucXudcg%~$tXvy{+32?ND?7*C5GDu1Nl3<=Z$2Soyp6ZspO!tpQ21RcRa5y~yI zjV1mAO_}Hi)!NL|9UCkP-~clI5h7x3jDO=&)|(XV!L<&r{g}}v&SNB}O&8i-R!SWN zk`+DJE0zK+H34vezOjEYD6=W|H+T60ryKkCW?>7JP9j`Wo@TMDGN%O7{fjYK~Qy?s|sZ~a4_Ej*SSLuW%zP2@wgym`G?Q~iOE>l zT!LLBrG~&|m1k;)-+4`8Z^>Cn_~$JkIOOuR4W1E`AJ8tmuV(tmJtbp-33Z=s-5mY% zt&;4?AD9Uwe+iKIds3kNSr+_+UhZ^YN4kb@6Eu?JP2th1xE%})U=8tKruH1bAFn9i zr7hu0szsu`(U$x4PR`Vs+ecPlU3to`d1ACo(81v37(H@x-yu?(Ck=n?{o4DD1L zTH}lV&-Rikg6uhXn%%*2P*f{`4k+@$@k+aNK4k_2zM+K4x0C(fd%UAX|IyEN6RzT1b;QSGHx2GKD2PIW;72r#yr*#00K9*riuk4CUIxUjQi6YD=vtelq-1 zD`2Sag|+WnBY=5C6SXDIFRuGzZdcKL+LTI0%)rdfuMTpi@3n*MGXSX5hUbi5y*a!N zk8dPYeo@a`NbH8SF^m5MY`Tmc>uV{n#PuphP(b(S)FeLUuEu z)2?sTWWQH+z%!{{k^?0ot9%=-wf(1> z;XW3vw3Bdd3k9{>x{3dh$?M4EWoDSEI4Nl$^Mgx-Yplp?p%$58e7aWnkW*3b+2mXP z0?}p=2B<>f5#k537QL0V(l)GrFcjNRLIcQ4Yd)(N7l;2AHPQy+#b`J)Gg7P-h8W|6 z$2oxSM$Q%KOFa2S2Dja+DKNOZqp?i{8$-R*`vPjI!?-;ay>v0;9Ae1a`D8>^p47N3 zl}jI~${`~2VN4ddc6YbJ`=tHsvUSw6I_boI-gO6D+^@3NU8`JD`K*Azs0%+!b6q|l z6nw+k7|l7pJ^XsQdc0Z-LvorY77bbLtHuHfx(CREkAtS~0i57-AovG>GUA-}A#Ty3 zpBr1FbNV^R>H)w6?g~nJ0O%o4D&)X68_&l~@+5oXc_D+|JOW7H9&0XT^upb>X$3wa z(r@LA*NRMpiowj;eOwWFkcEQxkzX#@W!6hgO-scM17!Xv%P6I5;>yDEJ_{~DMh2NY z0vO($m~vjVseuw60p#%4A_6Z;U!*QFh-E?Dj{qgc4&8dI)ue)P}qlX)svD2oo(Q5Y^!Ipk(YuLSKJpKcWfLp$T5!LUh_#Uaz-(7;i zxREn#d+rk(m@Xv4?Wp$lfs+gZawVOhWGIB&e1T{%w-0#z(^;Z7TTA|1D}p40E|ZY3 zUkX1I`WwT}~AmDbVcD5K^8cFOZMXeSuSqbsV1+qw!2*pbOyJ{{N zVzRzV{XY^DfLLp-q1;DJ7!^@ggwImqM)$TBcD)HJc6smV^;hB0Q2Pd_dJ-1)U&W#ldG{ z&I>|h73OzPh_*-{cEV`PImX_V1u$6$YEUWuxIg&0_cxO$lYb&@x$Zt6u@tm`14RcR zyA68t3WtE4@2S?&LpnddK~GI=Z21RY=@DBv=<9 z-t(@PM8NCgz<>P+|CV8!`J zF>V8x-H-%dBtrRRj$TG-v)4Cs%*ZH}tWV6@YMP6He_2R1X?=V0dB`hnoi_#~*Q*qt zz2;+8wtNYN8;-j82NAE7_6{&l%~FHa2R4r%4Du5QnsS{G^ZJ+`8IlyruYN-}O5%j7 zS5r84V-uRo2C}Rfs{hkZ3WwBL;Jf_2kxN~De9d$~amE;mn-Y;2-C}J7RYpIwj{gR2 z{@*hjynlfe&5Y61HHhBULN}mJZgU^EO38AQf-r-a%@DudCJZ)~izg9YQUL&k2OTYCy2Cx0j zf|f1k;4I8VXP`U;5hNjYQf&(B&Qj86*8=DJ(SUt*O0+}+*sC^`HYKDJH5CEF&$|07`QWo{(QV#CeompXngSm^c zTM9i^uBCXtCq}ahOtr(901QN?n2`Gn*i;t%6MJe4({>z77!@>qKkN@=U327I9^GbN z=MXYXQ-p03gzKI~;ei{+!HdyXWOZmT+k(xP=Y(sMHwWlINGP}{m8lBvKadCLk$L;@ zLMRMAG0OVS<;}kgZzg}lE4&rBReEJ30XnMp-(9W-S%FCzf?~{lf~^mh&UwLL^oo zocFK&P8ycPaheHrur84}E5tZJ+l(KCO9m(AO@v&jNk*S;YLxAyPBa z+Hj`pEP$LnrE@K+ubtyB)WU$9ou$@oA9foRDltm0(`5balFQXO1^yk>ZvrhTgZ`^P z>!;`dqx?647V-(>RiGV1MaQ`Nr4oG(Gj*a;`@v|P?aBc~vU#c#m(PPn4@E88bw2I% z2WzR|e`PI)5avJ&hPxvpVcy;m+}MD>1X=<1KmA$isq2^D{aFh@)aG<{)_cGu+`I3B zmG$uBy=L1_zmmaoEtpCcf=g`jzBaM@f>3)CcZIJp`B>J?+KK^jLlndvbFei8LR#>B zqG)>>n<5l3doz2IJs4VIvOX#_z?A_*tg^Mg8n8olznMu* z=Fn|WH%p=F9CbMYCZ^`T9b8-W6x8{xBQ!CNP2)ogHtVQefwa_@%N2Matbt6ax~}~e z13_!=_O~{1vWvFRxi(jVdHG59ylD=c_`|W@Tqhn*@Ki2e*N=$u#@^!n<98CEoN#z{ zY}2=@3sy(ff@eebiyX2{!@3!@v_o#E6vSLW%b%c>3(#wlp;d8P-ge7!TsSAZ4#rT5 zkEGyply%?Hoq|{r@N5MBJ`tb;mCoTnA@_&MMiOUI7Gi&Yc%MB_j8fmapEb0C1NjAE zHR3IUR2DZmsWj>`miMG6XPq-#HgPEKSYPh{i`6pvn~hAu*Sp zJa9P6s^oR1{^~sc` z%ZUxmGt2AB?SE=NiGON8HGgV9@0I>p`+28@+y776&xPDy+Ru2^@gF?K;BVT`)PLI= zK$0@NcbfcU{+53Mr%)LkP{7S&+EY-q&i?-7t zAGMAhRTsn<4$MJ|5K#R8feMi#KufzmN3}F2u}@LTfb5T7#b;9J0*dQ_C%)mXfV`^=!A9e86bF*Ltrbw~F@P5Q0kn4vPyjZ$exAm5vLSfp0>4;>qOLMyPf1BMRDwAa z&3u|sUW8kItFbr3WBm!UVY_PKx!8)Il5=X%{)?`%j&yPSM0$EUS8)#EkaDu(|u~=p`elwgV9n!vRS930d?!o}p zG_-DxUM;T!nt0kRc~ABi`|Xl07yUnDYKi=u1a`ft-rH$sGe1foodA=0r^AH+`Z_BU z8tUXxvT|Y{hZ<%c%|kfdoS1?lKW=7I({$glJ{3xvWKcGUcHrP%j`Q_2{fk(`AP&5O zX1V!>i1>m?SWKd5=*f&laU1Ul$OjX+aj2QhXfnrc=Ma(|paMJ1Bf};mob|ODj|U~? zBe5P;3tX@hOgV^gCrFXX^`Sb&M5;1V};Fag!DXBEYCajC9tyr`kro>)jl>ZtLfh0Mi|4`Tv&bx8hp+FVB z52ads>CKugo`Y+yqaRBq#pf+jO}%D^{>e*cC%31UEcM$#p@dD%-j3O@g;Sc6g@Lk% z)zrK-MzVH+Wg5{0t_G?i(}ps4z^{a4P3LvLO3{XJ8KjQ|M9hdyskzOcjoe1`o#&{l zCmoMW8?#PT;wa?8>wk@8iMbo$(S=2nSnF#y4Qfv-YMHq=X$y1do9M+hEc;#uvQUzL z4rCMc&y%t-q#~2FgW|+I=lQ2wmihJX!=50kV1UmlOFy?IlYz6Cn|M0BtB~Pe_>1MjDT zbo3(!n#SsTID?26dB`(30oo52rx&Xl3hh8B8Y2t`;LGt&SO9CNV%)*%Q;x{@q}!K( zD{%o#?k7D2aQoyD#Y@$68IrRD>P&CJr_lgWg|>3t{Vt5EVxlP)VCA2KSxGd&e;dr6 zU&MQ6Ydq>G&`MX4JVn2~exbxYGXT(RgyDa~Ulm2a$o*`!SE)!Kd8h3IHQ=+A28Avy z>^**{Z#U&6faSDP8F#88N}Cn0Wjv%x@vh*}P9fuQhF-T4A^HTe{OX7TU zvmoS&oycE5?h=>>7&6#`hB@1YM&IEE=kBL@=Sm|zf7S3UjD8h>>y;c%tpoY2bmG97 z_~g0qQ^7F_vb<(7_2TIw=dRwpS@ygsBo1X&COM(@6`?icEJvD=ez8)y4B zYpZ%K5DMv@`m)#{vFcJKLI84NAzlJgY_&7*$=L@L_N_ zF$k4NF17pB+Z>`|b{%n?UEF)0Cyj_deJ~vjU#f+GqZJd+Vi5WNDm$y7I@Wbv;{`YA?|Yti zFe_u>OX?YMzI1WE5cGkTa_ZTL0{pP+-g`wq?MFwC4B}dQNTBY-0)w4CdoSluWgdqj zk6lwzHO9~tL-^v)6cbHo0Hg&h#e<~CQ%aas?% z_aLA_yHJpnQd+5d;8M+$=BvY-rZ2yS&kq=05K)y&aDYe%kXk@-$%}~<0V-@!&g~e5 z;U-Ibso;k5zRdVlzr2c(?LmIp-mK>i2vAOmg6ngFO&QY z>&s=+7xVH`Yydnv3>a-xaNUf=eJ!@xOJHZruAYMBj#0(CNH6_dLT45tS6MzV{Y+;j zrZir*q}~nD%Kt=buu0s%qBW*H=c(0dJ37~2$@+Kt?30Eem$)ae@1`(uqs<~Ug<{QhC4y&9C+^8PfIqdFfDG(=?< zw*@=!(${ZsbNTm>QL*^Y_pc%2<|ksw22oKeR>D>UmkQ9BJleg%s8q*P=EbtkR^wowJ0bT8@UOc;D;bpQJ(@XTdmSJL2P5UAw-_aKl- z2Etj#;13b7-UZ&|i%=Q6rO{{#&(EIL)0T@!P7|!-NR7*@xg-SHmSCHa@1}n+Rt*DD zW)|*AN6a1^NkEy(S3DHTv<{0e|*E`TwI2%IKecP@6s)|LB9F z|BQV1zYqAJluX9y)hKLM8;X?0pUuU%zC_^LiF9^FFH-qz9p3qYPl9>74UQo!DqY7W zXJSK=fifodU_-irouwx8;XvY`J^+2ekG(>KTM?IxtoKD`vXPPnHz4q3u=V$i7LU%p z6kQ5;AfCdPOn(JRW(Cx0Ls)49{ z0-12VJD&`V2WgCXHg8TyL6^U0OD)@RH%Sm46ar37exE!(2SE+C(wSV22dN0!p8Sdj z8Ss~BE1o=v4~YlOj~A{O@kp8cjs$7`e-4j$$%d7J|1q=2Jpft_MSxd*wgcVS~f-Z1CIii4r^ybGzPmjhoFK%ZVj1l@WKU6 zLIvCw>&fG(B)Bm>u{|AfzV(hU&vb+X)=%8u8W*pBey3oL*a7({%DAxLw1ooL_m!Hd ze87G)jg%kVB?hO9gD0E2&r#r>7iyBRjNb{w--bVK-ft`EuB6zy*~Gke32voPBqhVA zFbo7oHwePsM%J_5qlr{DNYH&_X5sxHWfT#976^Vun|g=deu6=5MQ2O-8O@sEx0g}f_ux?p~j^2lcm+lx;y$^!K4C_&mT|bj^hLSHb+# za6dZTIFoO=7{Y={^^-3pGRkJV5zbww;!tDHoRb6DhxhqWLGk1inujW>_#W-?FI=ZQ z1T`UmZ1owLV}FE3%>b>Qz%yo6y$ZGp9)y~!x?Dbu5`9_{S&|xR3nF@qNpO)W=gaC(LfPR_<>>@bx&`CN>o) zdr?+s!9V*d^R3uw`l(RW0QaE~57u2)2@4vcmCCVoXfHhh@MoD1nN4eRfkdwUf{oR3 zq!)heOL>bz1754+-ZIAPLPPN!$1E;YZM}RwALyZRg0z;GYx!x-l1lO{q4DINi?z*t zy4_k(+;Zk%s$~s*!_caK`ubyKs%3l&M{%p5IoLZKy%pg+?2ydoN2CNl$RVnYsjEQQ z@N!h_FiOB80uo(e32@6tNY~qU41{(S=h8J3mV*MuF+gcYnx4=^ILuIL`Z8c*;!+=W zRIXO7$>6bUQ_$Lq>0zO(MRCq+X^y1>Q%u-rT238n7BiG-F?`a4S8hzj+q(G(f;m3W*BYV8)yo+Q%1@3y3(>ZioNv>Vfkf9k z&(mVwSCW^)h&U9Tre7&=Lu+rax(Dk`_hndI42L)+NNk~UspIgkk7j@0#M2CAotc}A zmSa&9ur1=o73nUA+L{`IlG-{2y%CV*kT*J-ll^cIpTA!S=^j^m#;nbG22t@;I1ivD0j@yq$>2PZ zHyEYZKwn~W$aXiV(IBQHenB9^QiZ`_^xAO9D+r3GwKS<{ljVNtYGlxHfJaQIXQ1yp z-4r%0qDJdIy`Ks25R!nphD`mXejcm$btO98L6#5RKQD)`J*o}IJSKc`4Kk7ZtBi-D zJC^r6b2JsNc2B|HTeio({t z;ML)6tR$6@!mzOz$&F#8FVh4iN3?tTD>zeVM!-lS>74Do_DX>`8!LjEl7%5^wQd~j zeFL$XmY{2rz6WdX9U!EbW-)lp`CCq`*jN4fSmvcq@qOJWrBa)<7Jyr2TCcB}{H3uR zmU-*3=^N+->g0+3x=dqdAUq8$Hi!wdLdb`KY&Z zdC_B1IxkC(beES+ac1N+@krrntRK$=Os5;}PWLlr8tw>Ij+W*Gw9;*~o}n<>5Okze z>+fbU=ifx6S{iCxhya+*f3z;_G<^D@n_`Rms98l58Q(h%PvgMOZcQMr(l zWr(%jMxZ00`|Z71{IZTa$dnOd;)+6ECi_~ZDzI$i980~@fBNKQ?_bE#h6w@L)R^I;7D{?G=hI+92#UbQ}I8IV%3r;dUW zm57vYCrOgJw9RNFQgn}%4z?rOc^e0day>5<20_tMd|;gZBKwMG5^W0$@6k{%Y|6Lr z^}sT*bnd9jtpvBbp#GFu|K+ky?H(aqn{<#}^CggdjGv8Cx5C8ZHFs6DAprRD2tXyS z!H_mj>~5H8M^6MDw$JE8U+Rn`&OSErN!@|f9D^xJ84ME1rgDS@2l628jC9+ySs4hg z0=?8UK@Xx9nj25s&#up|oM71UlF6j#<*Fnte7jrfxHCJ-M7oSIPepN3`H`b6Hh53f zF2d&vWj&pbi|2hKd+`88eE@##FFCZ^i~ooRC~c0Ls-MmJhq?tEK0{vV4hG-Aolh1D zSc=*gjwNtIQptQ<0u8CeR4XvzL2z4F%8dwgVpW$__E8_$GGY^$CK`0508InG6XbZ; z!1i6>W>xuW5T_UV%*sQ3kCN*S-~3M2rW^G0I_)RnN@3zIO-aS-7r3|RRiR0AIESNZRz7yl(BC?)if$=u{> zx2uxK!j!JwtZgBS!%+S@x!`Mj7Rba%4;so(J+9@5ca^VV+}D(NaI~_8*SLbo2qmoUMDCkuRRM;ZrweLFLlK7H2NUt4x0gw7`D}v@^cK z7EeKDj&@&o;4~JIlm-6>jfgF?9#?7>nZ|DM4)9RxTxlrZ)dfHr+ol;=YBt0>-SN1% zpcbYYQJAwjyR`5g^HPh6pmP#;$7R#&mapf(ugwGFPw_#}yOF%o(TlTRNioGl$n5Mo z#?Lb}!3CHNtm&&c5`^k>1Yi(kYV}ood?i9~K66yIJ4f`2xwK0~;IlfEsYY#nMG1*D zp_OLU+b8Uxr~@1i>XYi(ojTc8|fXt+Wn850QfQnfCQeYK`BP#fe zRFM4C;dE68c4^zXwy$a%sx&H#U%49Dx@)(Kv+aMi4$=h+NG&;hFh*OW^jPck z5e{gTCym%R6bG-|*ABSmb#x?FmN8%x4-VGk%ylHv6ad(CYJ^|6#Pq9N_v1;Ecgocj z2%yMk)1U=Ml?Z6;a!z=Z>Jkz`v3Fr7&tp=i4=C(*EYHzWtsEv_zk9c|i`1t>&)-H;n~h+El7X$QD>c`W-fN z2PNyw-WPlIq`E0tQ>c!Vh9T5YHDV*AFf4dP4X9foe=?tTBc;3#i0;g+*ZxK<0JG5b zgW%VEiGPE7dNDHlfQm#9=FikP3o{bW36aTU9w~*2 z%umEjDfnc-4r?Q*T!1Oc)L{($)e@wbq{*T5g1`y6_d3KfOF5MX51z#RcUDS!JJ-Tc zpo2fR&}X)y%0*EMBF{ zPhO;XCD?@nZN{U!biYk&pRF#A=)41*H9Y+X*tm66yp1!N<-~#|TRC^fy=TIYZ}Qe6 zmLIlnt~$pfa<5m=*XfgU`>mxR>w^VQyr-GGhC6;I&deU0wbjIUVwY~IgjtcH5Wvr0 z+qq^2>LZPPnl=z!KQ|dX`gL{+yn{A`)13TAonlLp9s-Z9AY=^vGQXxoY!J*&K5a%6 zm!oF%N6p{M-GHjIznRTz)G9aA%I)QwW52m9 zf;j-Nws~oc1~2VMJ>PD>$iNW{!pb%MwjDWP9U)Je*05MJzyvC21`N_UERK?lf%ko( zdQ+|2v1qhOW$UxTA3P~Y&+!!3Upn5S&a*ISH|d)a7&9X!8Y=p@4oHbo0TaVg91s>V zV>kmRd->{3C&rlhH0DbpShS0^xAn$_VotW-Qr9^bTI*EL4zU<)bkZ(T>`cpa^&G(D z6ohnoS)F+VVwiNc=^&4;P9Gfgd4L9DTsJu;v-O{=&j&CybhDQhwyde_gNey@hsVU^ zIyFBXM+z;E=5ye*+-Kxy0dmV`jdw7oEtbbitm}$%vVxX}=-G?wG-*yZH#aTZ>)IEG z8OS;toV%=wVyqEi8`t;Cz;S^5^kl3!z=0(*E^v3w4WHXNsHI4)qA`mUtN@J=Laxfp z<1r@4$V%IHFRyv;EhMj_>tCzW4KeEzhptFFi5>{8=WoZHDdMc4fDw&B8)K4NCP=4I zzfA+T_Kg%SX8qe+zuXBWJ_KW@uhRx=kPDb$p5k60aQiE>gxGTA`I z&$%vNY*UYSzC+^=%S6Yly((2!E;V(j@Ki(@X^jV)JNvhxIpwuo2~?y>sS_XHp-0Z> zmk#sRyDgXi81NJqC;xz;-TsF;Z`es6hO2`>+3M=#90K_~;=JdIKa`Mmz7vjugw<0|xWFSfdYZ7OMkV6q{q{F{ah(5JKrJDEqws8tNEh!%@h zx+fgmS?V7y5QkR|or)+2PZ}KjrYN4PdMvN1+QssI0qySnE6cNYgM=lr_dfUM2$bhc z``$dsj@t_#kTbrykb0aNj%phe?VD}VK#1jwTLc;#nHaMPe#^l?AvyvKEHOkl>OfB~ zhpg~y(oYhU8!rI^s5q6dtI(cuhj9~~@!`0W(SiBn^Hqw0Xe2368v6cGmAXb)r&_dx{6(WtJpi~Bzr9+cFegJ$E$Aq3M1u<$+_B#HK+i?*f~Ly= zE%AzogM7%d+2Z;I*kPDp3Nhu?pcp5qwcU{SB0z6-Dq0`A3|s z>f;>jiQVz~s&=(s(sf_=mTF80TzHEChUY&P=Ph%7ApM9sQ3;*t{B;H)oGN@GvS4%| z>{4_rx|wvvXQcD3Ke47_NN3hOhb@wfz(Ja)8aaVrw&XxMjy4mVLc)%IsQBEb|+~*|>=AUY>Iu%QlcL>bG%} z+^D&-y+(&Mi(Lx!>0ABz-Ow)@KpzF}7dcI+=sEb6)JG@k`@;0+Uo|D1eu+swCeXvO zYk58ywlZwd%hR&zSp;AgWw@EmoCn(qX||b>X?7m4%&HIDSWV(*hd*_F2=q~@gznKbZI!}nOvb;xCMpW}}I zkx>EvFCq2MjOr*KQ*QfrL}mUnqRLeLUm_|pDtiday|%+_e{L&-)y#^5_pkLruo!a` zLYK^_B`sB(BEK}nTAR!xlra7!fYRJS$2@%_=UMG4-?{lyf(36yN%1Lsf&n|RzxO8n z+kbrxaY=JJF24n<{Jx)rA4Y^3*xy$06$4YT`6XV_?hcOJNUw;BHT-@VIRw zt~;~y=il1edhS?g$034urbmur0gCM(WvohusP(!ja0}9+%T>k0#-p_5@@NWXFeiRvMTXC}q-JW&aSSUPkZ#QmaE^^bn6)bK zB2Y(KIvMVu#7)sp@*?wq+4X$7txS5zFVJv_%|bZ6(aAr-S}!wcpB*NhRm8$`|-` zv}`^?eQ6NKdWRIp`Q!51Aw|=~8441TAL8y!S#3jyOK$)D>npiDK$5%DQl zV5Y2vgY0f~f#ewOE1p&x0{IzoK%VwuYRI7)oPIlsS!?qQh3I`2tCM9yeM`iOfu{Ad zMtvj)`^>Z*Z*x8cAW>B|pP!FUn?AaMQ)@ABXTAY31p%XGRCx35Im4M4yty#Yhyr|3 z9S^~j_#6tqYHdlV)gEqE1L4|_32qX6zus{bry%?C_O!F|d`a;oN73thoyQX96&}y) znQxmzrT+aY;1#OYj6#q5c%fV_kFda}LW4;gz7h)`jgq1a(DB_49XG5nCnCy1^LHzV zhY>gDQr7E(uc;(6-lJbKc{S;hhxpsZlN<504phfXz^x|*^Nh4Rc08GZ{;yK@r8CCH zYYe@>7jC;+NFV;|B_yeo5LFTO;kc`~zJ=TA542|6>ij2VJA800TsanpV<$aIuV%tTci_WF|IXWR*K z!gf1qjysmR+)(rYr}f!C{-_{1*dvN@*DnzN`LjkhgF}t1b*N4QWknSja(a~($)0J_ zO$EWUEez)78s+9`P9K^7s52MC=3`CX(TuxX58jmIWYxgu;mr;$4_9;V*d<)%Ed8)Scd&byXW?Mf2gka1wLiCcI3V1SV2$O2lv z{g`?R;QP{YXpN2uORi3ua0K&PbnyCK&6BhTx#vKhCKo1$bd}9aFr=;1?@gp^6VgdB zO?Hnze)C=ghp2i#Slx(9)r@Q;l*jR-c?0w6MTSf!ge-#=u0JB~nwIvN3b^$$97aBl z$&yej^_uumt4_ivhb_1s%j$_BE|#7v(!BYo=o1MYNZvtE+MQ19tpzE$A2^I-o*u7;wP5tg6^eiM4Sq zvA=)taPW!0NwlHdCS50KH3Q&`r1+HUIi(8>*jN04k%gfB{uKDF+SC4|!{F>RENxl| zpwoh)cAkg4R&Q;&Fj6w2rbpA^;ceWUvaPs*-Ckod7}RUZ8y!W=>;q==^T2b^wUUnP zYD*`Mt6DIi&&_Li+?&gQbH8TOVqo<9loZR6S$<2*-ahXxc zj>CRVqeo}z$>&i~eU2J<<7C|KcG$uUkVdty9f-n|_W|E9Xt1gPRS6k)G~vQS|Bg^W z)A5D_4Mmb1Yl%9KxgD6VLQ7tmFUP}g;G)tj_5FY(c#^DV^D*&OZXJ7~+o(2siMM~X zB|(Nn5aK*5!daTpF%WX3=b;%bOnOt_r1tx>bQpDe{b0v2sygugDiIM0X&maKi@D7d z&B`NiKM5jBKKy1Dqf=RMbkRo*=%|#VD2`DjnQvR5BJkJ=5e;0`iNzm-+8r5x2x0En z(y-IbAm=m5DI5!UQo3&1J%$T58nV8sU*Rq!Pq%lmxLL#`Byv5wOdTzbn%tr;-Ivzt zsrA+4VPu)~#>fIC4X-)Z*~{w!2q0A-zj?}wysas6!AQRxY#!?hYD+zX0Rx+mkS3@Q z`qOeGqbJ$krOkc}=1Vw76{tMUudX_}2fnCg9bUgc^Y;J>Al^KkpU1pzs(wrn2{8Q5 zj=Hx!F_~n;MMJ(H!GQw5fugyEMQ7~9?S9A=lu`D6zV@JK802yO5@i)*gsl6D3$?pHh63Wz1*V5CW-9m zRJY9I1e>{TAOO!e-aF{8)@koMnc4Kh(g427H#a#q+~9o1vzq?VH$35w;E;u(!q5a(c?IzXYtBn$abEhCg+cMvS z=#zt2S^G+6hc#lK5>cpl$s$*_oJ6R0pCnTMuuK?D?fi5wwA9(zwK3zn-E^dvzn6@5 zU#j|h&-niHbJaz`QLm2oR}<5=8jD&;$0_Wa-_cbzPhoT`>7Nwrypf|#g_0vHmg z@yBX>Gm4KtsY7iUVaO4Kod@2*RYyBBbv3rk1jGb?NiK4v5d0OaHYZ4UbWFdG zG!$UV`5vABc&+ObU#9C0g}H|$XmtLSd&%PE!?6h-wuWQ_kv0h|r+Jew;mU$(y$mL* zNiKQu!PR|)J`?%^phD4~6&GG-8o+v*Xq3m_>A2pVBQzGQ6_hWZI}w?+V=Sh;mK#O* zwepNw|K;+u?9L<*#5HGI_W6KF9Rqlv~?q=Zwwz_yxh0f5d-|I#1-QqCreW!A+o2ANO zUY%oFU0O+97ehKE_dp#9ztiVzO8_{6v52pM7%LiLKEFeh(0KSt2X zbLU(~&#!!~&t#GaDWezk-LMZneQSO2|8aL2`d}$?x}EFAosO6r-^WuQ4G4^dr4)Xp zHhVaqa>3Yf^&}Atu}*^PDq3)I9wd8oW|I+m%^Fq3{j@R#aw`Llrb$>7u`urkW*Ssq zeyfbdOQFNtQ_hM9!J*Vb4>RmaA^bXOw*uz+xZw3l-T-G~kgW|*qViQM z!Pk5Aa+(4Mf2AOC^>T)4afK6BGw;|)U=IWPg1qb7usQ_0vsgAAsHXp@$PZo*W|an?Nn~Vlqp`NvQU52_EYRkEM(9_?!897yt?rTa(oh$W!k< zJX*E_#Ue4sX<$U}kBP>x*FHo8T4x3ozC|ln+454sRuElL_HpXHSkp)Up*Clj_k|Ez z>ahY;myH6YyG@OzTuGK66vCXKv8oaSIUdu^fz!3u&agL<#o1dS+xk?oQlR4E5@T*wdefyuAkLCYuq!$v zN*Hyr?WJ5*vxlGPI)?ZCfYFvfJ?kK!8cV-YD+T>I>Gzc>H1lQl3dy~5%IR$7T}kT_6vW0pEQRsV_{|WB#bD`u#XHi}982@WY02iIpE_soXkpasuk!{}U8l>}7e@7a> YSVgkUBkuCn)_3S{liC7W*jOO{1!dRcx&QzG delta 27209 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 a&*&^}ukX?j5W2j3ff dict[str, bool]: + prerequisites = { + "node": False, + "npm": False, + "git": False, + "hsd": False + } + + # Check if node is installed and get version + nodeSubprocess = subprocess.run(["node", "-v"], capture_output=True, text=True) + if nodeSubprocess.returncode == 0: + major_version = int(nodeSubprocess.stdout.strip().lstrip('v').split('.')[0]) + if major_version >= HSD_CONFIG.get("minNodeVersion", 20): + prerequisites["node"] = True + + # Check if npm is installed + npmSubprocess = subprocess.run(["npm", "-v"], capture_output=True, text=True) + if npmSubprocess.returncode == 0: + major_version = int(npmSubprocess.stdout.strip().split('.')[0]) + if major_version >= HSD_CONFIG.get("minNPMVersion", 8): + prerequisites["npm"] = True + + # Check if git is installed + gitSubprocess = subprocess.run(["git", "-v"], capture_output=True, text=True) + if gitSubprocess.returncode == 0: + prerequisites["git"] = True + + # Check if hsd is installed + if os.path.exists("./hsd/bin/hsd"): + prerequisites["hsd"] = True + + + + + return prerequisites + + + +def hsdInit(): + if not HSD_INTERNAL_NODE: + return + prerequisites = checkPreRequisites() + + PREREQ_MESSAGES = { + "node": "Install Node.js from https://nodejs.org/en/download (Version >= {minNodeVersion})", + "npm": "Install npm (version >= {minNPMVersion}) - usually comes with Node.js", + "git": "Install Git from https://git-scm.com/downloads"} + + + # Check if all prerequisites are met (except hsd) + if not all(prerequisites[key] for key in prerequisites if key != "hsd"): + print("HSD Internal Node prerequisites not met:") + for key, value in prerequisites.items(): + if not value: + print(f" - {key} is missing or does not meet the version requirement.") + exit(1) + return + + # Check if hsd is installed + if not prerequisites["hsd"]: + print("HSD not found, installing...") + # If hsd folder exists, remove it + if os.path.exists("hsd"): + os.rmdir("hsd") + + # Clone hsd repo + gitClone = subprocess.run(["git", "clone", "--depth", "1", "--branch", HSD_CONFIG.get("version", "latest"), "https://github.com/handshake-org/hsd.git", "hsd"], capture_output=True, text=True) + if gitClone.returncode != 0: + print("Failed to clone hsd repository:") + print(gitClone.stderr) + exit(1) + print("Cloned hsd repository.") + # Install hsd dependencies + print("Installing hsd dependencies...") + npmInstall = subprocess.run(["npm", "install"], cwd="hsd", capture_output=True, text=True) + if npmInstall.returncode != 0: + print("Failed to install hsd dependencies:") + print(npmInstall.stderr) + exit(1) + print("Installed hsd dependencies.") + +def hsdStart(): + global HSD_PROCESS + if not HSD_INTERNAL_NODE: + return + + # Check if hsd was started in the last 30 seconds + if os.path.exists("hsd.lock"): + lock_time = os.path.getmtime("hsd.lock") + if time.time() - lock_time < 30: + print("HSD was started recently, skipping start.") + return + else: + os.remove("hsd.lock") + + print("Starting HSD...") + # Create a lock file + with open("hsd.lock", "w") as f: + f.write(str(time.time())) + + # Config lookups with defaults + chain_migrate = HSD_CONFIG.get("chainMigrate", False) + wallet_migrate = HSD_CONFIG.get("walletMigrate", False) + spv = HSD_CONFIG.get("spv", False) + + # Base command + cmd = [ + "node", + "./hsd/bin/hsd", + f"--network={HSD_NETWORK}", + f"--prefix={os.path.join(os.getcwd(), 'hsd-data')}", + f"--api-key={HSD_API}", + "--agent=FireWallet", + "--http-host=127.0.0.1", + "--log-console=false" + ] + + # Conditionally add migration flags + if chain_migrate: + cmd.append(f"--chain-migrate={chain_migrate}") + if wallet_migrate: + cmd.append(f"--wallet-migrate={wallet_migrate}") + if spv: + cmd.append("--spv") + + + # Launch process + HSD_PROCESS = subprocess.Popen( + cmd, + cwd=os.getcwd(), + text=True + ) + + print(f"HSD started with PID {HSD_PROCESS.pid}") + + atexit.register(hsdStop) + + # Handle Ctrl+C + try: + signal.signal(signal.SIGINT, lambda s, f: (hsdStop(), sys.exit(0))) + signal.signal(signal.SIGTERM, lambda s, f: (hsdStop(), sys.exit(0))) + except: + pass + + +def hsdStop(): + global HSD_PROCESS + + if HSD_PROCESS is None: + return + + print("Stopping HSD...") + + # Send SIGINT (like Ctrl+C) + HSD_PROCESS.send_signal(signal.SIGINT) + + try: + HSD_PROCESS.wait(timeout=10) # wait for graceful exit + print("HSD shut down cleanly.") + except subprocess.TimeoutExpired: + print("HSD did not exit yet, is it alright???") + + # Clean up lock file + if os.path.exists("hsd.lock"): + os.remove("hsd.lock") + + HSD_PROCESS = None + +def hsdRestart(): + hsdStop() + time.sleep(2) + hsdStart() + + +checkPreRequisites() +hsdInit() +hsdStart() +# endregion \ No newline at end of file diff --git a/hsdconfig.json b/hsdconfig.json new file mode 100644 index 0000000..9484276 --- /dev/null +++ b/hsdconfig.json @@ -0,0 +1,8 @@ +{ +"version": "v8.0.0", +"chainMigrate":4, +"walletMigrate":7, +"minNodeVersion":20, +"minNpmVersion":8, +"spv": true +} \ No newline at end of file diff --git a/main.py b/main.py index 4b2300b..911a1ba 100644 --- a/main.py +++ b/main.py @@ -1150,14 +1150,13 @@ def settings(): if not os.path.exists(".git"): return render_template("settings.html", account=account, - hsd_version=account_module.hsdVersion(False), - error=error,success=success,version="Error") + error=error,success=success,version="Error",internal=account_module.HSD_INTERNAL_NODE) info = gitinfo.get_git_info() if not info: return render_template("settings.html", account=account, hsd_version=account_module.hsdVersion(False), - error=error,success=success,version="Error") + error=error,success=success,version="Error",internal=account_module.HSD_INTERNAL_NODE) branch = info['refs'] if branch != "main": @@ -1172,7 +1171,7 @@ def settings(): version += ' (New version available)' return render_template("settings.html", account=account, hsd_version=account_module.hsdVersion(False), - error=error,success=success,version=version) + error=error,success=success,version=version,internal=account_module.HSD_INTERNAL_NODE) @app.route('/settings/') def settings_action(action): @@ -1189,19 +1188,21 @@ def settings_action(action): if 'error' in resp: return redirect("/settings?error=" + str(resp['error'])) return redirect("/settings?success=Rescan started") - elif action == "resend": + + if action == "resend": resp = account_module.resendTXs() if 'error' in resp: return redirect("/settings?error=" + str(resp['error'])) return redirect("/settings?success=Resent transactions") - elif action == "zap": + if action == "zap": resp = account_module.zapTXs(request.cookies.get("account")) if type(resp) == dict and 'error' in resp: return redirect("/settings?error=" + str(resp['error'])) return redirect("/settings?success=Zapped transactions") - elif action == "xpub": + + if action == "xpub": xpub = account_module.getxPub(request.cookies.get("account")) content = "

" content += f"" @@ -1212,6 +1213,12 @@ def settings_action(action): title="xPub Key", content=f"{xpub}{content}") + if action == "restart": + resp = account_module.hsdRestart() + return render_template("message.html", account=account, + title="Restarting", + content="The node is restarting. This may take a minute or two. You can close this window.") + return redirect("/settings?error=Invalid action") @app.route('/settings/upload', methods=['POST']) @@ -1259,6 +1266,9 @@ def login(): wallets = account_module.listWallets() wallets = render.wallets(wallets) + # If there are no wallets redirect to either register or import + if len(wallets) == 0: + return redirect("/welcome") if 'message' in request.args: return render_template("login.html", diff --git a/server.py b/server.py index 396a7a7..f8e1153 100644 --- a/server.py +++ b/server.py @@ -32,7 +32,7 @@ def gunicornServer(): gunicorn_app.run() -if __name__ == '__main__': +if __name__ == '__main__': # Check if --gunicorn is in the command line arguments if "--gunicorn" in sys.argv: gunicornServer() diff --git a/templates/settings.html b/templates/settings.html index c3499bd..e7cba1d 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -69,24 +69,30 @@

Node Settings

HSD Version: v{{hsd_version}} -
Settings that affect all wallets
-
    -
  • -
    Rescan -

    Rescan

    Rescan the blockchain for transactions -
    -
  • -
  • -
    Resend -

    Resend unconfirmed transactions

    Resend any transactions that haven't been mined yet. -
    -
  • -
  • -
    Zap -

    Delete unconfirmed transactions

    This will only remove pending tx from the wallet older than 20 minutes (~ 2 blocks) -
    -
  • -
+
Settings that affect all wallets
    +
  • +
    Rescan +

    Rescan

    Rescan the blockchain for transactions +
    +
  • +
  • +
    Resend +

    Resend unconfirmed transactions

    Resend any transactions that haven't been mined yet. +
    +
  • +
  • +
    Zap +

    Delete unconfirmed transactions

    This will only remove pending tx from the wallet older than 20 minutes (~ 2 blocks) +
    +
  • + {% if internal %} +
  • +
    Restart Node +

    Restart Internal Node

    This will attempt to restart the HSD node +
    +
  • + {% endif %} +
diff --git a/templates/welcome.html b/templates/welcome.html new file mode 100644 index 0000000..44b8944 --- /dev/null +++ b/templates/welcome.html @@ -0,0 +1,47 @@ + + + + + + + Welcome to FireWallet + + + + + + + + + + + +
+
+
+

{{error}}

+
+
+
+
+ +
+
+
+
+

Welcome to FireWallet!

+
+ +
+
+
+
+
+
+
+
+ + + + + \ No newline at end of file