From d0e0331562d0b1a526e762462a2dcb11a7c82f2b Mon Sep 17 00:00:00 2001 From: Tommyli2026 Date: Mon, 1 Jun 2026 13:06:36 +0800 Subject: [PATCH 1/3] Create ustarminer.json --- vendors/ustarminer.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 vendors/ustarminer.json diff --git a/vendors/ustarminer.json b/vendors/ustarminer.json new file mode 100644 index 0000000..2d62718 --- /dev/null +++ b/vendors/ustarminer.json @@ -0,0 +1,16 @@ +{ + "name": "Ustarminer", + "slug": "ustarminer", + "website": "https://ustarminer.com", + "region": "Asia Pacific", + "country": "Hongkong", + "description": "Professional distributor of genuine Bitaxe solo miners. We are the creators of the Starminer APP, available on Google Play and the Apple App Store—the only specialized companion application of its kind in the world for managing your solo mining experience.", + "active": true, + "social": { + "x": "https://x.com/StarMiner01", + "instagram": "", + "youtube": "https://www.youtube.com/@starminer-s7o", + "tiktok": "", + "nostr": "" + } +} From 68ed730a37aad0eda5acbdc5094f44399bda40ab Mon Sep 17 00:00:00 2001 From: Tommyli2026 Date: Mon, 1 Jun 2026 13:21:59 +0800 Subject: [PATCH 2/3] Add files via upload --- logos/ustarminer.png | Bin 0 -> 29303 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 logos/ustarminer.png diff --git a/logos/ustarminer.png b/logos/ustarminer.png new file mode 100644 index 0000000000000000000000000000000000000000..d4881b2bd99cd9b2a1f85f408ef30fb9a7eae70e GIT binary patch literal 29303 zcmeFZWmJ@J)HgbWfJiFcEiED~T@p%5Nec)_2qG;=OLqxKH%Lo^fHX)8NJ&YjNQ#_2 z|K~hwz321!`nqtj7BkG;bKTdq_pde~YATO#u_>?-2n4R8f~*Dtff9}UkA(q0dDkW| z2;XkLQqX&iK;V5v{zpmRz@tPU=n#ssQd(|lJL#@&L>5!s`ziA?^U({p6cyg7Noz{p z*rcOlFqA?^xsh<kCQSHPAAV`de9es0(g2i^Ry&9M5Z%Rh=Swf`rl*Jk0d_% z^1!n`jRfNcz;8MRlAt15%+T;}o5OR9{Xf2>gGa+T+$#Tj8aMqrOnhGW3HSf^HIx3| zxAps<7r80$f4<@WeGpdt|1QG+??p&%B2p)!$MS3HG}$wQz5I(?HcunVu*n7M)~(mB ztb>L)lvtf}fdK&lCS$pZRuhFWO){p)XD0gy`l+!LyjRH;4W}D0e4owA!N7o;{?Jw4 z*0ywZ*>unQzgII~?TsNoM>$>aEdTEpC-(5(nc91M+ zA=NMLAl!h4myQZ|LoCW~u%FkNdNGO~DX2Pcj*)Ze*95d>lsm0gC8wA%1RehrN4;SY2B~ zL6mB5KZ)=?Kb7MAKF=ye(4TwTBEn-&?}yJ%THa@+<^oB5X6n5*aTaeF!nzm+Yy}2* zDI$(nq9n$?_@XJ6X%95cOqFO9u?h(#N772Du*8KtX1QZwX{pf}gsYgR5u=pnborvA zaeMUyp<9~DkmoBq8Je&6+EP~fx*w~m-Bx51biwXuF9`vOp(?ZPx zfvt%m|LzFNoVS-J?;|5IVpcNZ#LBeP)ZR6`USH0M5|=hL&5{we&@cM?FTpTLdz-#Z zfDGqoyE|gV@#hy`?6nN9BgIm^Y7Fg?$)z)!H+mSemK@4GYy(1J!KUwGkGXwhlAAEr z{C}@qw}uyK8VAeg_|BLm!e#2`=I1RpIka^K(fWLiq<)AH`kcZ_yS0X!yJKK68-nHN z=(sUnfPZna8Lu=8oL4sICXJ;q9A_WoAMof}xSGy#W zqMv?QP;fBGgBRbv{%rT>m3Kd=Wf9G!$bC=owzCMesF;{~PEC%ajSag>hWHRh zhru2Da*Rq{L8WX~jg{_*O}Mq@)ib^3yfIy7^l#PaH^Z>4_ZM1@SL0M;wM&>2l;pBm z`>P7v`wKkKrSb^O*#?p%RN`2kY>cZ)l#K|OO%*>aVddlupRlQwDK4vessC?sDn9X} zqOi^ptDvf?`?(x*|G1`+5ehjD3ojWC@tBoM%8+HF(;D{X9}oC}IS-ja`IM%&x46ZN z7n=I|6zO7~i67mTZ{C(WEIzEz#cmKokZd>Rdbvsbnb0)J=feh8bsI|!zu|Y3B!XFTN)R%zTVzUQe&^t zO_>YrF6{yp>Wj^S3@V(jpRO<4u1m%wcWOUK`D2WxJb2-d>`Nu?l^ldet@QEZNBe6W zJ=fCzdAXxo2L+4&&eBT-QvH2xFV;vy!^4?s^>w(K+?T}gM(KZMOt;cSElpoPM!$PL}hGj?CciLQxQIz_4V~}*dq>?-6r_>`1%z; zAF#8JJDu$mFoOI+5caKG zedfGZX-BG=P_+u}WCuia4#RS?_jmDwj_U zc>Ep`R3wty8q2%2_Ul(aEPsvFX!bMSEXHl)yLFgf%!Ct;=r5MT?rEs26Y6ow^HSWh z-p=rej*1#Kd`{;_rYjD2{(0kU?aN2&!*|)oG>LJ|2b1sPon}3XqQS$6 zjgFR#Woo$k-^E6CkAQi6p@y00ep1*cU-pTIlc;GEkC`js1vnES)hIgm>|EH&L7F0

1Yb2{>{6|vNtycyHROv#FenI%Od&rkETsG1jv>Sds9O0K?)^emOeonNx znPMNl@$0_Rs>04(!yQ}-zE}Fcc4lOq_ZQH7u3K{SdqjQyi3Z`2`yC%2Qxdau_SVmL z>2kgZ4KGzpx@Vlbye!R|f)oGYgEZ7MCai4O*&CtpyEHbnAF{Kvt)T1Utq8`~;>Gnz zvc&m%UtbA^Mn<;gGuya-72dWCc}X{DH*~PnxwN~>RlZYa-gn!e!KrIVeO|ZGWj9pJ z^CVL_iTi2dB^39OCRYc8R2PE6&yRGjBGXo!iQHij;y8>8KX zLNF|GJ-0d7&`;4jQVhQwY$5+tn!Ol z<@jhQ8oe?cw?pVb@TvP~yO$J}S5I`HXP z9p3J2jg*r{Z1Zlls(4q0sp^t1CQW^aI`3fZ(upX=_9Ek2{S7Gs1tPhlKY#L|o*w=F z{knJGxY0QTr;CM`DAlSjmf1e4rBTDkUp^;mp~X|v%#4A}@$=u(QIlN3{8klyXPVWl z(b!;lWmBp48v7yrD*aOPT3zeK*0-+5y`JCa8ST+b=Ypc5@TH}tf3B?sLbamf=y6 zYX5A(W1EYKiAif#^kiqoAM=^Sh6&Bkv(H}~eEvozo-VGdX_sj*7F(|3MkJXU_`=qD zB1JUNsxNEN64cz>{K|MB5exTLr$gHnhN`Nn^Y(XKYinyE_ak#_cWE^>f*J}g*;;Hw z^oI}Fgcf4)wwceInIl;}pRy66qp&AnM~R(~Sq^;&gx2HUL|sx=x}JO_6h?ZlJM0b% zDr?`Z4QCNJGt?Pex(JEu*f*l_VnxpST+%W!j)zBilrDxiE7-96?8(dad=M+$;WrSr zb7yy!DZf7&e$=?K8nPnfy2pu%`q$#w$d+?-jlTP0^PGX8tifAY-hh>!C?rU#ayN+B z8RQfdJ7${^MM&y&qTMk{eqY{dM4$S|T`QIXMaox@$v&uorXKc{v(5MLjytM2(zxk( z#y(g4sQ#!tUei28M5`;8`)!Z5zn6{HJ`?0LI1^U0p=VE^@LSgLFwI(cGOF_=ibjm* zc{dK9?KD9)t29v;_6oO#rY1cWs&r?^s$G-Ie#dxc(8^e#c|+oD>O20!B;1mz0(Qls z1ppq)%N-Id$bM;mflJ_twxZtLkOtlR?eJ8Z>DwB4wMe7l;qJoQVVN@_(~M=u%tm=x=Q&D@6zgHDSl zsi)L$Pa_);K8TYhx0ps_hp znP9njcxX>|^VCrY5d6wllPT!zRc9Qnvbe=*a3Fm9&Yk=Ae}y(`M7%C$UK|`AcK6T@ z1*;Tv9&b7)LDWW<)jGcvDgvJ-BR`f z(SQP%C9co$fzN4MG&r=LV*~~UZp;@5`uX{pu%)}K_WaqtzZt05J1}&EP>KM3qUags zEs1NYGX2`deBB+44$XL;Iy8IQ@Q%jUdD30Q;xIt4kuxVEo6Al zHivwCYl-geF_AfCbVZvk{wCCA|A$n>GG#RDJ6RNTtST)VuB#Uvx6G@idu=(?$61~z z2GDI=8iY9^G7aaOTnk|PO`291TU-D$v+4-A>3r~03W=|{jawhf1miK|mqj{bi-~!m zTUb~Cw{juV+Q6|OFPT(=GPCL%P&zARkN@rsrm{8Ne4|Sa_3U-N;vM5m1g$ZJ#D(yW z>erNFmxEYGe@?Q6t6yjWkup>eQ8g5CjUCEq_Qmr1ARl!e(F@3Mvp0rO zhd=V`SJ@9drl><7_`{GW49MfJ!}+>Jb*&+VqmeBt9P`8FF7rxVV1O}CO>rjq394rv z%LL(=LJPrzmR$N!*X1{vfUOX20y=ze1R3)_)|opPA9+Jc`N(WMnug#BJ290AMU9OD0$Y>TC#o z@?+o{toQH702FwnugI7h9IX8){o$MJxVx&cKz^#b9$S_KKIWc~#KAyAB68e-HxGMv zQ7ZNjH#-{;mp6-~sC-n&G*uOsl4>#2gE;*y zu}>DgtNof=L=~TQb*d7eQ;2&Bkw?h8+l7Bie`xGExTbwott?ENq+gbgM=dfE%dFgA z)}?Mq(!a~b#&*2dv_A%1R0*m;>_GAm2|G9Mn4c=ChSe)F>xtX&<-WnUnl(O>Jxr=S zz*_vAu1l`#xVKZRxH*{fJ6G&1n#nwhlO-MUVsGCW9v|-vR*xYPn z!_4V6F)8T+4;owVaDn!z1XQv{Y9ujmeaHSFI?32OP(x#EBSGhGTt*aW1la`>wS?EZ z&vxhO**5ZO&@tKg`O`yjFxUkstft>DK__Ppxqc2zuc+q zF$nQ>-kVElJ^w`s$H816HT^qZ{OtO-bY&!>dy+1a0Ia6hrdDLQhg~%q5?4@|IW37%9f(IQrqrHAk5^0jVjZ{@5e0=( zN=k~8|8b4=cpCRm@ngjVRaF3?Z??bZ2`+lY0sG@13!Jh2q(yqqC>O}2T8qaU>xse_ z8)JFqRl1MOYd=_U8MnrpnPn^HsK+rCnTv^;2@#WS7S$`Lnpekfil|X2*eGF7j<~;~ z#M*X={%;p(P$NRKbpOH4^)Kk(oi~yeVR*ay@ms7Xm=LZ}nz|r}SQ=~6Xc1uPOMhU(I9>>EHm>Yo5h-hh5vrMy&FZWZ~I37fJ|J%gGJ~+*i@~0^nEahb9C5oG| zp@%D^^*$yHVc-0KgB0bCcdCaq;Ii20=zbPs90B_rX?Fh&r@XSCMk|55_XGdSLf8ET zB1%eSRk1%raCsS}+PCz|EN4VDG`L3#)rX^13g~O~nNuIh$_jBAHNOwVzSXN{;5LqH z{;%0RSG!1|Ua@6VxAf)ztmy5h?C|xYep9D^a4;L>mN>wG4ZnYl1%~xGFPZVyS}lZ& zzO=F)-lI0>B{wI>!O*WVXLI-Ph|_0|QBsRhBA~{}^4jX-1~RQj5h0%llt;hTX0+aM z#cKCQZNhifc=@Hr0EF@d?0%?OS+R=2=5+=Xh|Q8SwLbpLp+)iIM;g3ZyfST>=RJ{G z;o*G26Ny#b8e(Xb!s=@nya$KA_SfPSx_SQ; zNaOlU_(qBo7Gvs?FvZ4lC@su$wRi~p+a>RGt1{hFbr`eZV=9`MvZZTpZ=Wd9x%WZ% zHA}jvdzD5`VWe*wke~(cOFNs1LPF3~M_vz$JyKLuO!%(RdSOEjoGqzFKZL2M^!wpP zPSgmn3TOwhGq%kZ7_qUj(!MAt|6L*Cp7nqM+BLZZUbdv$cA22MuI~H$Igc277x5Xe zZr;4flQL-aeTU}k;!LaYx>R`Ibo#yN*{|9CiZ|QZ1_~lk96Ck^#m^!Dsa@ zIhl;lY6JltNXFLIHg7ynCwMN6L$}t3*!${_4waY(kw7Xg5_baejOr~6RsQPz`w#En z2Y$*I-^Yh1k_+kc`F~rW z)DaUAjr1pQD8@1sYZl-!Gc&8J$9xP8Jw|Rw5YF=OCDK&obJ~|k8+flY{^@voczE<3 zvygJD0jo6xQf56Q!)j47~>*)TPhTfEk<_FztVf}!_qnU5mEoR4Dj z>hy)CxjBFgkFmj&{pcCn*u2s#Hj8RK^8^WdkQHlRPJJ`&CwBF@r+aPhh#OEuf-K~s zqM{XUhi2#3Qc_Z(x0$z1lOK~{N&g{jbQbN7SOS4jx6NBj`;$RPS{fB7*C=QhCL1GJ z_4}=tbXcgi0+dHbPD`5l&p=ifK3oc>WjLI3pSDF$P`V-E{osV zMu%3I{d^-mKR+?-4#Ydqab;qebjvIe%wdu!Ut)54Og>Ljk(f3T+s;=Jd%Em*1C)zS zOT#Id3{9RU3#Sys19%jeVLWqG(ZA+M>UF{sk5VRQW zeM_D}E-<7+q4GF6Ys98i!7WNjs|7pGlqGp+1iJV!!;FC(p;i?i>z2Q0?rQB1M;$w=lgH4RN0vPFby6j>ypDn7_VQl?on07KYYuf6%9j$`0^-_G#9n0fkA zI~bp~duL{UCCONz!|c8k(Iilg4uGbIa2^>11@T*37tSuW%VRP!Fl+U>Qq7f=LdRFW zWk@UrHg)p|($)!nt*}>BWUno~@;n{Y8Ayz)DJ}}>9{q)2Kq)qlW^0eXS>-<7e7Ha zn?Us6iym4Z*?~kZWpCdwRF!m*o2f$>QUs>esNSuux|LqS3qIFqUWZ+zYBw29_I^aP zG`Tzv=nA(y<&zm_i6A7T!BbVmFPyZQwhhS6Hd{4l@QaTpN|W%Rf%eeb-|wfC$IhiW z_7TXTKLFp%r`y^a3s1|>Dp=Q60`AEC46nRUXd@={YNZt-AIlw;Z0fPjb+LL zBud6_!$f1N`Ps5z(k5`yMs6>`3-Ae+Kq`Wg5IxI0WZu|&CY)X-sCSJkG4><_1Ua(T zznY``{Jh?0ze9?%Hk%ad1SkotU*zBEb1^)8h}jt&^(9X^iGYSC5^R?abKWeU>wj(l zXsP$wS}b|rY-s_m_cgT_1gFsEu;)A1#&p9SXMRyNU4sC_CRavAMzpLf3$b9EiGwfk zY;lLv&#w;WT^CJZ1wnxjoj`rHGeXbw_MiXO|7HQGgi+OB8C<5lH>uP$snn-`&(Pf5 zGE%6{$Y(!C=IHo`fOZiJU-SUsCnJrhv^BnssD>LbDqr;{iVGZhK9{$(CkJi z-s=6ngfciv;vW_`i>zVeEFHGYx|{-D$D?=MPUl@w5XiUJE;qt8Ha6BR(-wNZ)}NqT zZTaLWEpBIh1Z7;N<(^Xfxwkse;b9N$^Yf#%=_c2E2$Pf288Qj)W&?T25PAXxffSM4 z>gp;TGxLp2a`N7xp}H>$bE|70hMwvLxL8t*`7ve^RNq;bwS*QjdTwm&gQkp;k@Q}MfbA}G5D z?6CTaRN>fyqz-U}piHm&!zY8jd=8x|Y8D~RiS_ZoTv?CHvQ4m!<@jwTqEByu_A31P zmzur($I|9z)cygEOnALeBp z_5(!xuJzx=OWves-Jkz@tXo#6@IH7@CP`Nb&^Hif?n7`xvylGAqXRc6P?q=u`7sjl2`TI@V<8CuJ z_O<zSI6V3x-B03v2pjLiIm4)WEaYx z?ui{7k9UsdJi;eXw-yOeGqC*{*;cnyvc^#X%Q#kVcW_YZOM@>F4h-%NG-it_-4AB{ zy}e&1iZqd;69M}BY-}-)<1a5V-u~iA9@TR-0W2c8;D%OhIpn19?CGRR2hSehg$C{b zr-)^j_gFD8F$X7y^0=z1R(uptN8$V-g9N0cGUZe7)v5M_+pKy9LD@driH3+SnR-Z7 z?QI~2q+h4=J`y6XTj<60jijdG3YU9uI^^cG0 z%`ON)dyA0w2mWaaL|#Z;WUJMj^VWf6$>o1yrQHvrcRA!AhAanD9$;3#7!JB>*x%jt zCx7r_8SGDtpH>v#FzCO1;J;Pg_OHSgUd55Jgt^*bOhr$L zHnur9gjnC@x7<%q$qV`Xh>Whu%q6)C8T_;3HA zJrF9pG!-KzrUaG}*KQSiR~&$C4cHkrkls+VQ7(v^EHo7@Gir!+DmT~65;sm1d;90g zby00zq!N^o=wKBYk+Ps4buVRZ-t3{)a93ha^*XGbGHUwd*=yGDKl<0UJh_6K8yVMy z7Yen6NAmY_Jub@LS%(%j{DYD~$WZM$^mm%g3b- z9-EYW2hZjB+r#~6qw)ejKh*yI{%kM-!WQ118X{{+U{FvjtH>wYLJdVCLPEKFZGW+M z7h0l@G45=J;cD6P^z{!9=M1I#WEFh$2(8h_4|L9*+$uEf#5i6G{>^$%F!jiZ`X#lT zhuH2+ZK}uVmYhhsymkbI$kudaODBV-W%X#0HEV>$mv<<0y5AZ#*O0!h$FGzZR5-al zi{800Orh`JXTq^lheSd8CzHate+QjW@y8wPyc&*`A>k|!$ipq!1(L0%_U4bbO3KxC zf81wMEFQCOv%okSkukKMEPfiF>M19HpXa-C=1KX-`*<|g$b_QImIk)&F*H;mvPWxcbFVK0?Ch_Klu3yOQU0yFcD!&dqtTv-7H{ zSNeXtn_d6_eXQklfrIvuMu~DG;^mv%Nsp0edezZ(|KOs+!epEvGcXoGsa%iTo!B0I zq`+9zD^tQ8q0gS8tXz<#W8|KKjeW$gJ|mHfxn{#h&?pj=U5Dy56T9 zpX;kKtECRPwhOrJT(Zq{@l9%KvH(J%qxqloBkM;25W&yyWCyS73rns5Il z3XVH&-HT32A{9)m-edWns~7B)Y;@j~epY9n7aooSJDPQ~<0bFFFUOtf`w-2!4Ll!G zB}kim7219Q)bk`t3!gV=!tO^*NbB9p%S*{Kq=+MTe(r6XUgU9x_gg}L8OV8gDP`=6X zl{$!C=JSN#MusBOG{Ew7^YmQ8lkECI1fw?oR#>EUWGJ? zBrL7bf1Q6lP0`Miz;ICxrxEL(H|23fIKJ7IBtU5~+UFq>o{0oeRYBqf>_H)|eHa z6;xXJaI(nEOq2K7#nSFU;KXIKWjI2-Ky7MdcektG~a8&1>~7^f*aCfaY`EGYFO|wwK4D^*KUm`FkX^ z^~cIpBgBu>b&(Q2H-GX&Y>OYjxB)2_YO#wRe!X)B?0RW?d)r*Ko&If}K`MiU1g$K( z6v19&L)spCe9NM&`d2UpLLnFOkn`1zc(0Rt%?GH!Hv<-dGRr>#W|R5036qeVBxw9* z&#Q9{?9#MGv*LG}x~@DR`E%)ryzj<8m7@#$v73o#8u&90v zSI?1e@Cpa=X$niJprX?18*_gu?Cp-q(~07z+d&yRL~;{l&qyPdQ-AjSk;r@=jK?}c zx^Mt5LuyM`$JQVG{_TeY5bv6g`Z?VGov#~;D`S}IqczX&T{161yxZYq{ffx3G z{TAfzOq0$&J1_}xpTTxL(%)0?L>z_B2Q%c&|N*})aQTy`wQb(ZB z>tEpmzf9KwlaUF%%Cw~!+--k*I)As#sM-=22SX-r4TbsjE>*3KTGqdP(O?`FoN5;iP!0YW>LLwsP&Sf{tudgOXtR0u# zP;KNMEiHG23GPe}&fhAim<#8P$n+8ezhMwUU>|@x}Bf*;kcIDR%vQK4_V zpi%@uQ@@O)wY3#URW#F041W|oJ@U{Mtp%AuJ)Hij{-gdP*o*^D2Od6beekIu=|dG} zI+G$9j|sxa=jsg{v@9S~1n5$c=LH$w9pHfSn0>|i`t>WMH@v?9?nQ~u{oK*nNk~lY zyVApvVUsK380v>m>k3l~?)#s<6Cv*_DiDlf+Rsdi~i_|Zd4 z=3D4k%nt@RF#6avz50i>+%pmuQGRuIVmPI$1E2JQ1Q`fmj~q4}bwE@E*?4i}d18Tf zng09t?KGozk7WYib>ojmnwTfa_EdS#Om#see1KGnsoj9O zI>AQQ{m7elSbqMy+{Z*9@oz95b#cw#u{>oIA#tLo?1V^pPtY6nv)!UEu*xJedIt0x z7(XX0U*FzdH=2bNk~62u$hrxk`uh=3QH8%hc=ffbE6Zh9*Q%Cc z+LmOx7ek#OIx#T_49k`Bw$IDp>%i{DfnaAuM~5^Hw2Ifi2D>5gwjT@FATSdG7KN~Y zg}n-A=a-!W1Ghxd@oZ|b1t{Ci`J~J5k@vMYEQ%u|Ant<@xiah0F*dzi^wGKSF3~P~ z_4mvXlEucFrErlDZ({*d^x||MYzzG0Q^CK-<4>bTSzE($9KAl5f9@u=$alM$Ig1(=qDAACixh-++KO9(j3gnz+ubDGVx_{FNk4A zGZ6;F>dT!U^6;(-4K&Z#b|Xpt%kP}Fi>>o{(etnZFQ#Yem8U*ocOia3EQs!VP@y#&|?MMBlQUZWhhY@C4pMAjD(PcBxrhC zm(OMb>(ADt3>f|da1nBe{y2k5dKyvmQ`UQ6e*L4R)sGrB&}-;L zn@dqrsK)3l9I;6LH-O0I!z3$z@ks zTbtyAphF~xU}j*W(LGaCVqwT;L1Y5t-1t$;(R#Lgt5mlV_40H-xXY|adn@01+|r6@ zk&K+2oB*8|*s|$JX1ng+HI3DEQpr3GVXyB%sbQ;uxPuIBWoPFQl9RJtS3nS72Iv+9 z9e=Lut{wkl?P0OBw3H%v_eIj@?D7%_zDo22b4L2B1UZGTPS%RG`Vk=ZBXdu>^{?m` z+*WXdDMF4OcFzgTiBtVsWKk!w;J5n`52S-xRYyG~p0%K^Lca|1Fg_!l_^z(W3(`3; zR;PRO(2zFRdWLhrhAWO& zU@e|iyCjg4aR$Uhl_>@O zK2FgSHs^hYuDd&5*cqo5rY5*l`FexI_>mUpDS zGDoo>0SJoKch3iXW{!V3OSL&*Xd&{)XS-)*)0RUXQ37@sDc?Q{%dLO=nE&FDm`s5R zi&{&4BZy0iL#d0(pt$5r8F@w^Lv>0@N=`yahTrmg9bNE;NI2{kThozYzR<9+oL@t! z;}Cea0>V=RJu>t(!#1IRW-(B#8x0dr&A?#pN&3m!BKIfX`WR#zHugSe_Vf2IcV8Sz z6?_i4vT3-WK>iXLX=y?NPz4Y69zKXkj76;?6mi*kk2FvCn?6zK>gL)AgmZ6U{~u4GW!tl1UN0a8>8v z&!^F{@y!bRc@bm`4YumNuvWfZZQ}d)?@x-WLSE{=88M~uvN`8BTlYBbq zk}?#6B@HEB?;jO}bc7U&{?R`xuzPN!qd+v&Z8_xbL0ueQS~|EjFq%Mico;!QMTA6J z)ICTs#IgOgh0By#+K#<5C21Sx$&cMMV7^!RGO-sNchsZU4o2 zO%_;|fSX1e-@MGt&+lJ@T-!7H^-q6yXgoHuY*MHEZru9RXfg$5mM(GOwS%$49C*K> zze7(*gQH9jyk!+T#=v;v0c-6*IPEyv|r)zrPVPHBNxokSU0e&<&VDcSZ%Ju7{?? z1Ka7c{8`Cl&_I%A1qe{+n879^nRg8$bLb@MzVfw{?4eSFd2qVk9CbHX^k(Mj(i8-a z*iS>V2RpRo;+&ygxOYB>N2Ny{S~);kBV z!P5o&ZvJUW`}@dPA7qfABO8_(SGl{p|F;EU&t%ru*Xyr?8Q%`r@YTkMX*6A?eapq! zK1aEM!v-(;=BAL_0Ud;l7&oPPVgBYFAQP}vX0r^SNgjN?<6k10s8YbeA6;b!GN|Nu z{x{la#4E_F4W>UNrEhOnc=DtRCU>GgevDjRHUp&-%MX$M4XvF%3-kaq5-xqMO~;Er zyJ2TRhYCV5@8DlaWE0Rct0CzF&da?13zskUmmx_{# z7kxcFJ=QbOsR2hlJ^#Y#5YNxZ0EW`5Uyo-f=%7%%?vn&D^3}9&z&|4MtdcD&A2!girq?<3ofkF7NYJa()_#5eukL7wZOn2MU3 z+Kp;+dmP|1SW*N8fEw?$o}oevSBFbg7D^x`c-6so?y6|zc+K3YNA|P|6O{K@+LT#F zEgk@$@6`qK8sHp}%(e^CxZm@Wfki(2;e@!wS7TH4=PCtK{{&eM(evWhg zvQaCfE4B-8E-+B;;OIzJUcPZoKKF6b`T4mi)H?;`CxLwiGimAp9oY;-Ea{KT&2xWC z+4&(-C$ZHD2xw{VC21zIwK;$oUXpg<4GPi0;h*3>+d!4=WHSw#b!m;;0ACpjw6`Y1 zICS!Nl3}ds$TMB!O{0yc6vQoL)eSw2dL|-#tcQ8iRqi^J7`KU6RaeKPq};r;vmeb4 z^uPJT)}lx{t}g)mKPF~o;9<9fAo&i4Yg9nM9UqbsWcD6TdbytzCwxFr@6DHg?{1e(#A7i0Qlc@2aGI$?&o7s#|=E zsX9z?=C$O9eMv3hf~w=>WLl|xMOUU-z}@=yNV#CYT)zeTu1b1mz5I z{H`b`piMV;<~-P$Cx9NM1OX84H)6+-e+S1JMm1#BnG*D6*lUACoHrzqH;S}pVnXWz z{B&y&X{zh(&8hUlwaymoqw1doL@{CD! z%H%Q-4%h_7L)Q^E(xgtIa-MsSkEaeB^x5)=oT=8mD^fa{?)jRZe`g4y$zajeB0 zUxiI1eRwIts2dTa#KfcTP|y?rkTEGDGin(AS#zh=tDXm&JsHs|In1?%4C(|58buZ% zsOD^Kl>NV>sDxuZPWPU~%F8Gx-7Bdn*xboAS9rivLkLh_hJGtjf-Z|c@m zIj!qTi{dgxFPGU|y`xIWv32%hS5Fdx#U|61Q0_(sF5PN zA?#yU;5A%$aBzSvmay|$8UzBq!bJr8Q$1C>hk)vt(TE4;?|9ll#TU?R^%Cyr=wRP@ z8D)x``_Z&I-kK~K+h!v_GHt_0{UF#@P}8HSH^-jv{>Clwz`8n8*~2ZnXC5sy4-YpoB}f5C>Kk%D)xJFoYL{tM@~&V{W#X%ZeGG)x@A*0eqBd9F%E~IwhqMh2Uc%xv zjAT8Bn99NFX}Ov_`ELj)9(LkO7>KcUGrI{aJd=dov-T-er_+SzixppgM8xE#h@K(1 z+!4@6&ENv?X6*$0=-xxGgA}Hef&vfIo36bA(9MgqxzCFVK1yrF|Bm;&ZEU>HPO7#w zQh5}-7Q^^x6=UK^^!o2_u;%@3X%dj$f8X!ND3S&S2DQtzE6{%ruA#(dK`?)E0U|}T zFRW+r*#9>RF#Iv$dQn&SUk(*8u~=h?;}Mxj@kd~cam+73#0Yz_1meyODD#%peZQR( z)|I{y2M3*O(+jZ{I)|&tft#DYCkU3d7l>vFAA)0%y3~Ir7g+kvR`{um_4Y!tuzKXjra&zO6ax-Pgg^?sg-Z=-2v;2qKEEp`0KkyZG zoPdvD2F6Un-b$&al!*x)DjItR=??M)cC)}V87eZaHP`UEWQPF&uyr`C#KID(Jv5*6 z#PaZ?64Y-g57s}N=zKs`yWLdnDA^xEQZlQ8hKQgPEPmy%Jy{YAC`9MXE8)k3Qu^L&AXw}TT!0Y13S4sDnJmg2}D4;re$t;_vb+VN{ zlYE2uafbHWzkmNA9TMMcUiS7Hjx{ov0m59p^X6@C*VCb{D{IAC`|4ABAaO*-UDg~yXa~^{)p##y6eyVePesPyed75 z1PpT@J(vKc;@oX`E`f)boBeA9a|T*GWqyBA&0oAo%3V-;o-Fc)-N=27Soq`7<#Zh_ za1IduN_gna3=Go7FLNHF%)I7<;VuPMyJ_#27pb6isikdixu?Nd?Y(bPs}Cbo+Cpt_ z&Huu_UpuAXce4HKBA}}g%M=hC40Fpay0yin1CDLpSDB*~0~XdqAayOC4WX+RdvcpjI+hPf#UX2jE8|G`@9*o9=5p%ij(ui&a5Fv~e|+)6 zg0Y;=_>*a|7W?BgA;R*OlMkI=p1qK;T!3La0ME7kyn_*-t&_YG8@Fc-iHLZUtd!&B z30f~6q<8{guFM2tdecXjv{TMr(4hd1Xp12Bz&62qPRO1EIn{)dp5ej4uVZ-wpfDaN zoxaxYv>C}fGLnSY7Wbwl=ll0X)M2pd%P@;o$SZ(2J73Q@1V>&+WX*N>qgZ)k+wIGH zpij&`->G*bUQlg~M!xIw=r~876YgS3MSQUr{-Tg!<4%=@oeF}6_Y+6)3#)sWXpV_W zPr2#V_V@Q|3Z{SxDfjH^5)$7DOa?*6YJ|X!#?~KjCIg@afoFYD{&E@jqH%M1Mcx#9 z?Z}&|6FOB@tvw|L%_Xe$?Imh`BYiW-uxDp0Q6-$6b3y=~Q5qT=@UG?^NWdf6m}__d zCK@UNOo48Ie3fQhp*9gFq;iBnC=*(B(uucN9w)19o*<`7$jLVoS}}!GP2X&cRF3WT zMA7<>g3w9Ivg}jdqFqLK1;Y!SK)u=1^8^?eI;>B(U~UQKcjbvcU!J)!LVhN!RTsTX z<=N8J+CZE1zWCep?wqvLK48aS>X+5b0ZCg8+67^~U{?+r$-(d6B^50o(*xd=@$jGk zsSD;ud$29Q#Gv}|yyi#f)bj$^UmJ_%v?8vXsH*!E6){6upOrqxve{^to>73SoISn* z2^9g9?Mm!a4e3#msl_KHr(HJOc{rFpV#e?@`~vF+I<2k<w=Uy}4bU zI9`>f%AIoA&Rt(`gS;{xv% zU+3rEw2mLS`INx-ONSD%nz=;`Lw)90`{zP0hR{$}1`=J4Qf`JWIVp4!>#*#1baG0l z=veewOia!G{^9?EyS z^5h%0ND2#D!Iq!@S6c2c!}uPKY)*dg=3OJVr9dYZ|K?x7XuILn3@w}9+~wpPv~#GF z!Ss=VbgIkVbfoub!-+SA__8V4lfAYgiSyMs*tLJAyVE#?g*^YIjc>a;U)F!mJCs zZb}G>C>m6_y4M(ad3gytCSFf``<52c1r&P1$MZ+bWqcYc#laV}vr`@8r7*dS zmDKWU$P+Ja|5MpZ6Lr50Dn=Kq;U`K+o55&*9ZJ>f^?TqcbdD;Oo}8{FDOcLf4rAfk z?eXS!rZi|pe+Oq|cO~s137Es4&D@};hCoAO;5{mwy}Uf$^p}sINZ1tqRRM>WEJ7X` z211^r!2BPM1<=}w|INU5T^uROXI4(kg!8Z4=*%`~S^aB0i?S1OPOVp_ous6!+zIVJ z3hvfQNqMW&?9)Tb@$Em{PuslTHeYO&Y^^#+3a9TiSMwv?D-iP1RSYnOVMv+^vWQ!+ z;azKG(W693*o``mPJ^1&vR3eh1BLLvDR* z*u&Ek!sIj--ma-nkU3@u&;5i4PR@&+Q7dOAiq&&4kQ36#KgLqiqYi(J1GHqM3kAGd znKJF#I~`U@my-n4(=7ONE-)B~Y*2*6#A_}Ole~vO1W20s^>N|ldRq#db>s-68zj|` zv#()YsHsDL_CxKdKXw$Of;5NJ6%o^q9=mRi-9Uaq80m%#hs6q!K#)dS>Fy9gK~OrC zl8^=wap(|`7(z8Qp83afl1{W`k+u7Ch3lq)4piojoU-m}u@!D=p<$#277B;z)&pMci#12;q zEtZB(jC8n%jXQdv*|)AR1;k&(YvwYhDLb*KevIKrU}g$}t)O*i<&9ojMx)`3%fAS? zvohzFz6d9jdzI=SymRE_yHo{dpHB%aAQc9*==sI^s}^@_YcT+}@yf2kZV4G1lNij? z&FXT!oAy;)+VA*>*ors{OUvy2Zwd^4-RZafU|IzoDup} zo$uyX>HQB)5H|k?ircXAv3n-JyNRWGd&6hW1T+hv>h`WK*OT&|N$dZ7-xP#;OW*)~ zYt#TQQ-sS&7WYH9K4L3`KvuA^{iED-@*ju8VA>(zga*FOJ6(%ld-6F$X@Kop?(5x6 zF4c>GbDk$T{IZ*q3_$$R2Lvn* zC_$_B>|(tZM@3Qbwakl(et9Hksr*ynQLf}S@x!7xm#(G<9P2az5Vsz z?nY(STIeza)8uV>!AyYc8ps*o3=I#*^a6t@6rw@s?su1yfQfp#DpmyyPI)+=m`Ww` zGD<97e9CKIiL?pYmlyn0FUrU%C!+CgpdFB(O&SXZ?%gNcP%hjnnLb4x-1+?N^#)&Gb?k{+N1mY1ixx zK9)+`6JA4u8aI@J(<%wWX7z2mk#DwY#YIKjw7hQB_NZP|^ylYgyu~1W8EPA5d&=UR^Lbr>Js@9B`AtfA4x& zW(Ft4Q}Cd$*!AqX1*Hdc4Pc@dX zo6o+8hN%&&uTOwVXw3w4??&sb3#aE|6F214Nyy2wd21I=Pj4<4D+uEu9B*opUx}1L z=ON8~Z{7#=U~RnSd1`ewGX<}~lCvKKS9Hx1ltOrkJTOZ@L-r30lsV5oR!NhfhIop~ zja3+oXN@n8DdDn(0O|UoFSE71qeITAZ1Lv8BfLSd(GzBsdfa7~02{AAX#wU^U#tMEG5dJ{rbpI3YWw&uDDd#@%lvg0)5@y+aQG1Yb#_196qm& zcO0APq=5auXYTa;0T-X}uQ>;V6}o=Dbn?^jT>fO#D%}Kn1Pl6MKywcd4;zu)9B$#Q zrqcJdXTVbqM`bS54d`rF5Su+YY)@T3An}QbJy7R%s4<8G=ox77`P3r?v=JOi+`@T) z@4Rm~-!Juqp=opU(<6;2L}a4?+zd# z*Io_i%(^CABJDZR(E3Essl%P!0(syxCTGpbsSMfEQbqZ(`&H^Pq)@zo%{U)%*YThj z*k?bCw5ro}XdN_L$wnqb01{~T4s(UQ0Vxmxy~N1;BAp4eVsG2%eN+rutqF%jx>s184*?Y#j%$o0G=4-t;fO>rHD$6(O6x-lyZci^t~PL`P| z6zOc=2QM=wjDn9Zwwf`{B}q&bFkI)BoHGzu!S&+*+|5r#0L8c^MbyQ>|7V7I*bcw} zGmv-n(&xGU(&OSQ#?K6jq!1vfy(MI;<80k7#rRa690)BSo<<+mn76j7nwb3Ix(2y_ zk8!7#qtX+@x0j7ysC0c_?Pz|~oY)WMYt^XG^rT6L4D|KkOVdVxAi6Nfk|E&KX%EUk z*PUR<5qPs&Y6?TY80HMbNbS)7Z1|H6N_#~@J^^rqNrC}#puj8;&@lt4+rqnIM56*S z1&UzJnMm5lb>A3!pO>dO>~{)o#5j9G#RemD%qPApI&pE$(OU36Dac2r)z+ zJspNL95@2*OLWdI+l@`CkhvD@#qiumZ#Bq zSlbSVX0Vf0SHByJICm z4j7h?17fwicCC`)a0kg(ZnMeLsHvl64leC>WN&k4d|}DS2pDRyPzZ-MK!gpKhmWB8 zV~|(GI6n?HwuI_SkE0z6gyEfWH=ieJYHi?B?;P8Rs3CD7!77#@Ft3?tEc=g5#HttV z*#My_w>bl1{BSDK4X*X8w#)TmQ=8=g$V}UB&47}mJTdOo_mB3^7=1!IMC&0Pj5-;r6roJ~Fl&IwMwRsIbm>;&IWT0AcStiXI zSl;Ruo@5jit$I+`4)vzA;>Pg8TaeJ?sb{_O^XJJ$(e)9DK zvt%QeL+k^sDA_=+8sDpf$CwWeA^?ns^@Z`l_zV8HWGcDmS}JykX2&!4Ao2N&Qo^qr}aJ%EwcKeN3G}^ z+!7a-2Z^yR9}NfhO`SLUO+WB`n-&0k0mh`+WqF|4hSRuO+VH;KZ!;v51BfI}Bj0T~ z9pw^XFd=r#5;?=Y1dC(}>cmwn1H>(dP@zcXOy~}>=WG-LJ;wd)NWPjWEFb=+rS>8h zORbX}_ZbT^RTgmGeLSH+2a16(Kc52`+q9r#AT^)`V-JlZOopyAJ9~ukP_N#%s!i9w z0-^-f)xm(U}S%e%iMo=;ue~~Q*yGrxFib*DZ{wPE50QRv0#GjGv z*{#28qJZ+Yia0JsAzMuw&k5ZjE(%VX#5R}y;d0wiL13@O?TEkhW8>gV&zi*42M1rb zu&05L7Xta)yyENl7`zxp;cIxIv!DH6UAn(1^YPYw16*=37kc04^l)22z>q&IA#pSl zE{75Qfd&SW6GRhu$|FC%kBlt+6a0F^NEjl)^7HfQ)$WU3z{U9&4o@`YNqA_z2++skjRaBy(E&OA8X?nWY;;RZWyy%_as0z@u4CI&ko zAmBu(;p$|&i?cIES_{>C7DkCSpqCe%8#>H)Dj$`Z9jArCoFoCcVdvM*J{~Of;egim zK;$?T_V=8}oUh(g{mEuC%4Onr8c<3zt;X1yL0YyeXPA5q7|sMNyQrX8MGi!YyGYqa ze*D-9GN2kMHUrUQ&GS3#CK98&*(aBiQ#Fa-Af4j?1rZe1(2=L+LWMaT*WA}erkw-|`g>=W zoKG=&nW;uR^`}w9jZ%f16=bk^XeRw@t_23lf+o{*KK}VPp96b10=}qf8Yf@Hb`zt6 z{F9H+wLl}QayFWhVry>sH7hTV1dy$#Oc8#QBHV8(XVg|6QXfDdQ3fV` zMDA=!l~6@Z=uM%|SHw~oxwvouT4)CFkpERb%RPq)T1L zB!iw$h}$>|Vax&1r7U!qvdKajK zgE)ovVPP>)_Q7Wr@9E?9J~9z;cy#y}+Di*eiAbm}ZvT#muz0lC{h1x8|CLp(Y&-cZ z^}iQZspQGKtdcysL=5LoinPnCf2`1yTZT2g(6H%@Yfz4^l99St(-aNhmH%lw!5A2L ziC4K*d(KTEf;OMm(7H@-$lJUH|0)qd%$%~4#?z-6e*q?D;phMMt9NsZKB$QifQ2}q zI1|_N>+4&YrBAnls^dyJ%r%f+qo}aj5(EMP1c*F%8-x=V)1@yAM=N|nSlEoBfLjSq zOia9d`Euv>Ec*}|OxnmjN-IUzy;sZQHKm?jN1=&{k>C}3_`O_kPI~okyYxZ>ALUFh z($H>`JSg)yQqw0TQPY07Bo!JoWh0}&q;5GfYA=I5@4D*RZ4mDnB;>d)9QuG~Jt_z< zAU5D^^{&_HwgQ+-rm9hsUNqoo?O#VDMs3MJ-3nUQ_;X*#dJ%xI;FcR|ilA&wo)6`r z2uG4tf(Wty$16>EDc(Oom%gx*W-Ek8P94lHY|e*UCLNufG1JZT6w(aF`B1%n*pKT0 zD_vaDy3Q%lc|8i!4U|BxySDSCSmiaX#MWn>u@Rjvdp40$n}nrWo59W1as zZVB73?VQUiq$fau>M+J7&}asYxdNbW?Wn5x<763PI)*0n$%l&NF6{3~!{C0f8 ztM@|@L~A*?ih!zI#>Le>-ktXhpfe`N{ND&6PK+DSHq4dAZSO9;wKn<^E1A}{M>r!rmc1ZLf%?%^4`9kQSaxP0o6J;|7yoGfVf@0qCAOrFHq zpt-=Uz08+~TcYmP&>Tl|J$D(rCEy!OwU4{(vRM}s7smqKXn*#r*w1L$Jp>0g78cnR z%rgQUKs7}x?ydrt-{5C%);Su{kS~7NFD|WS=U8u8I;;$15vzcJI=qhgg-LS@3yQ0M zd0J5@<=VPBbC{P`hz&FBf3CS&Yppr- zGlrQ)9ZY;?hYo7zH;qH}x^Ld;rJ}CrwK;$OyF}vtA6rp#tnziT5Jzb~`&HoD$EO)dA8^&-SPfx$d5$!jKHbZFzPAGjf}OjX>6B+rP94QJImWLj z!a(Y}Le6Gn#HJn>W{2t*=dUy3!$8Cy&!XERIv~1cUPYydY7h6m%tCK~F|V;|49t$< zrKORmEf@~J&mrY@PIooo#=f)m98-MF5hi=So4#oQqDc$vmhnyJyEu>3$@8C=reXMc zNYTkpd*E|89b(ZMc5`NS*5x4_i3>-&i-nhB(jBA;Kc%LwldVDFjRiUG`@Wavug7$> zyl~E+&f`ac!J}a=s!m7nZa>Sy9%q?uk!krq$WVUYY8{&y^YAe2ay#tEY_J2+OYg;> zk$^GeY1hJoqqft7`FwUZWq+f3gX%br1M~*Z1RLMBkk|W;7cro}Rn*ff_&_JFCv~#; z;K*fI`n|ftWc2bqTZTn+!}h{w>(>M{Vk#=QSxFz{m%(~7NSI%^d{EH7s`}|(huv#H zy_K`%Kem|f^wToJT7X5tDkmqm(4XM)?^-0%vE&lzWH1H>8;B(Nev5XI9kYWs= zJETlLK6ROyo#z2H`rnVX2w;jH!*B_^u=63Yusjr8w1X&4jWYAQuh4;8GSC)u>- z2`kr;Ub&cXJK(4jXJ%$-h@!xruZNLCJe3`>nSC!z@xj&iLTBz;VH=~Wp z=HB@Vu*$P*+8wI)_B7)V5MOi)uoO}@|2Z2oWjwq z^(-^Duu%4w{Q^ClZjF0!aPS~yR$mKNzPS@^`;$S0gRw8{3Vw_g;>df$m)m{qkUBYe zS@H4XUr7RHm~k^j+Iaib1Xq^Lur!kp`W`k8HV8P)d=Zv}U6#X_Tw%}t-kyzCd|Vy8 zwbcw=Tix>APbEfmw}7>~NgwK24nj5@2LG)~8p`tK;ywp;9)roY6)*qYBfom}JwN5m zW?VY5u@5V``m>-g_Jmnyz5M9bM<5Wmot?i6cx>ncMjg@$HUwE>)4w#OOd^$k_tT>~ z^LEH<=#WRKFL06qaH$A>Xi){qR_pgVLt;)dq1=Y(w`(I+Ph$AkJ2T}jV%`z1UX<9C zYO?E?nq`{rcRI`sC4N;Ne6RRwBqI>HNlrz@*s$@B>GnHGmUYxmv?q(pU2Bjx3%>l5 zaYvNcu+&I0S-|Waq~FN&q)Bpt1|=pvozJ0eKY{9_QRb2g?=Z=ooda-na$Kk6jhnvx z4w+Kr5I*seq^@knFj}`kZGU52Sv5t1?bULJV8D3|#LG{Ax86s@q$M*w-*vXwjBgz8Q9pIXV zO1iy8UKzlL=F-#spe^7_*mWxV?lH-`d?6z(Kox(DaIl*C{^|4==lkrM$9pTh(zfHw zJo-X>HyAg2{FIGO8x~uT<|ILxrzMxLWx%9ZC;=T*9ThCcmHL1m z@^R)Tnjh~`QZwExg-*s!H!M>T7$Muy@2wV7F@S~)-r*HOz9YPd9=57uj&8fnvf~-7 zl5%e&!HC0cEn_lmH-T2lRc2!or7+=VRbu0zDzg$Y7`>@|u77KYn3ONbsFomLtl3M= z(6mkk7dn~-*1Nam^eSvih(va4?bd;1<-lBZpx}_Jca5zm`>gfkgP2X|P#qJJ4ed=h zCv$44%`DmWJYHshZOB}X;|S;^bbz=Wgp){nct&oI2IDlCf@d<+Zp=auYbf*;%m6II zb0dC%-g4{DL-0A@G@g8;oiKz@lU|$jz`C;Vz_;dDKkK&sWg&3k_+S>u^`8SyplMSSypgfX&avz9f4Xd{-8=KOY@&pt`4 zI-j>3yVz6$L*Nfq*f(u@^%|(J3xsnkPQTtsQY%5wSjz)bFm7pm+K(D=(m7eiQPGod^*pNy=A9J zOl47%5Ph$}IR89eI72V7=KKiW$m1$uc#a}ZVTDduc=rw}P*Tukp>SuG`1AbMmoq`9 zUpm|S+hoQJrJsc&GQV34uFieI!&9_Z{Tck$?U{mvc*scI0XhZ}&C|stas{dP1zp=2 zz1%woptxFB`K&<-AIoO#ZiMU7A6bZ@*O<4nGHf81V-L%W1=671qc8z^dN2|5j;SJB z_vP&)|7Ja}we4uy*x6U8z&kn5ON|cK%HPs&_V)Dr&b=-r2QFQDhBGSk+IS?SXuw_C zv^U|Bv>8}XeI%FKk`uns#s)f&sl{}Uu^DZx0DZ(c#5C&scs1*<&JyzL7xvn}{p*5) z{o63Nk7fSt>jq7bXR|>yzZ79!&}^-sAi$>G=HArNtvwE_(8RO?kxgzH1l1(BW={7z!?3 zk`JhF)tYfO=@xSAPs!)9F8Ucj->qQ!fQ(J$Q}9O`q1!^}wI>WJJ~f3q%^52O z5jHrWD~N{-feP`GZcBA8F7YSYC3;L;&x@mQ@X*MSvaG^xPR2z|ho->$^X=1T&c>5Q z^truLqCS5wj5t-@*3sHLw>n_rR!o-~Z`~x~qn7ZD!aT^~)(^xnxtfWV3;^`?r_KU! zEmqOzb92a-9>e1z9%u=821!_HgOOLbzK#Gi=L(jVY^v!I`72*Zw0yQHd8Y@|q#veM zGgX!vU&P!WvBM`I$XofU#if;II#dPiNReK}W9|gg#J;&61xD1*Ge*drx*?bEKRK0( z+HK!r+L;&=Zf!&EKHC~9KI8toX}l3BvlqtfUB`?YWCXf1PC%c@K=EY#XTn-bYvQ%F zA=pim$@Q;gk7!JhF>32aXMZ(J=!j+4@}fa3K0(heJTqDk#e zl35n33;nATU;$gxBK-H;w9I~UhE$O=C`2MSQtBKJYA2Ivsgiz9hTfcvy!PbX zvnN;Zh8|eoX%Hao>(-j*)HYn<3-FR5Bb#M~-)*2M!lfpCx5~VPL(a8YU)*7+`_4Xo zw$}B0{ZigY86EDw-9>jCWGeDhQ-84tp??6k+WFnWSTXkZzFYv!mAAR32m^}neV?19 zU$I{fRo_hTt-8$ohSKOz8n(i-&GLzb0SXbds$cm^p-Yy>>BLd;Pi~n_zj-U-zQ=(H z69SyQ@s$D+i;3BJGeArRnwYIlF1}e{*>xKHgS^E(emr_Kd>~E72oauFu)sRrXkGV{ znu_s%zKb3Z$Cgt!_&RR+nuOGF^1>CqM7yW-q=tsxGr|0wjevxixj*>QgGZ1SE)yE6 zcmo%ol=RgvcthqVm|v596({)rfB65e#{c2kz{T=Xy+9Whydxp)vtvzEz^qC+GR(64 z5&Gv6)v{~zN`duNQqpm4`E7j6cMsDr>sgO{`SCcTRzCqVbM^R==jH!h;<5dgGPyV% zup)m=aB)${Z1C8F?nNurVC3Me(4-gJ!2pS;Fnw`JX+0#v(YTiko+OE-B&YhQ Date: Thu, 4 Jun 2026 12:13:16 +0200 Subject: [PATCH 3/3] Add PR metadata validation --- .github/workflows/validate-vendor.yml | 10 ++- MAINTAINERS.md | 5 +- package.json | 3 +- scripts/validate-pr.mjs | 93 +++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 scripts/validate-pr.mjs diff --git a/.github/workflows/validate-vendor.yml b/.github/workflows/validate-vendor.yml index ac4fa1c..6ce5fe3 100644 --- a/.github/workflows/validate-vendor.yml +++ b/.github/workflows/validate-vendor.yml @@ -2,11 +2,14 @@ name: ✅ Validate Vendor PR on: pull_request: + types: [opened, edited, synchronize, reopened, ready_for_review] paths: - "vendors/**" - - "vendors/_schema.json" - "logos/**" - - "scripts/validate-all.mjs" + - "scripts/**" + - "package.json" + - "package-lock.json" + - ".github/workflows/validate-vendor.yml" permissions: contents: read @@ -30,3 +33,6 @@ jobs: - name: Run repository validator run: npm run validate + + - name: Run PR metadata validator + run: npm run validate:pr diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 43bb898..d23e42b 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -102,6 +102,7 @@ Both trigger the sync on merge. Both are transparent — the change is visible i ```bash npm install -npm run validate # validate all vendor files locally -npm run sync # manual sync (requires FRAMER_PROJECT_URL and FRAMER_API_KEY exported in your shell) +npm run validate # validate all vendor files locally +npm run validate:pr # validates PR title/body in GitHub Actions; skips locally without GITHUB_EVENT_PATH +npm run sync # manual sync (requires FRAMER_PROJECT_URL and FRAMER_API_KEY exported in your shell) ``` diff --git a/package.json b/package.json index 3dc1d63..42bde01 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "type": "module", "scripts": { "sync": "node scripts/sync-to-framer.mjs", - "validate": "node scripts/validate-all.mjs" + "validate": "node scripts/validate-all.mjs", + "validate:pr": "node scripts/validate-pr.mjs" }, "dependencies": { "framer-api": "0.1.1" diff --git a/scripts/validate-pr.mjs b/scripts/validate-pr.mjs new file mode 100644 index 0000000..12df9de --- /dev/null +++ b/scripts/validate-pr.mjs @@ -0,0 +1,93 @@ +/** + * validate-pr.mjs + * + * Validates PR title/body hygiene using the GitHub pull_request event payload. + * Run in CI with: npm run validate:pr + */ + +import fs from "node:fs" + +const eventPath = process.env.GITHUB_EVENT_PATH + +if (!eventPath) { + console.log("Skipping PR metadata validation: GITHUB_EVENT_PATH is not set") + process.exit(0) +} + +let payload +try { + payload = JSON.parse(fs.readFileSync(eventPath, "utf-8").replace(/^\uFEFF/, "")) +} catch (err) { + console.error(`Failed to read GitHub event payload: ${err.message}`) + process.exit(1) +} + +const pr = payload.pull_request +if (!pr) { + console.log("Skipping PR metadata validation: event is not a pull_request") + process.exit(0) +} + +const title = pr.title.trim() +const body = pr.body || "" +const errors = [] +const titleMatch = title.match(/^(Add vendor|Update vendor|Remove vendor|Deactivate vendor): .+/) +const prType = titleMatch?.[1] + +if (!titleMatch) { + errors.push("PR title must start with one of: 'Add vendor:', 'Update vendor:', 'Remove vendor:', or 'Deactivate vendor:'") +} + +const placeholders = [ + "Your shop name", + "https://yourshop.com", + "Your X, Discord, Instagram, TikTok, Nostr, or other public link", +] + +for (const placeholder of placeholders) { + if (body.includes(placeholder)) { + errors.push(`Replace PR template placeholder: ${placeholder}`) + } +} + +if (!/\|\s*\*\*Shop name\*\*\s*\|\s*\S/.test(body)) { + errors.push("PR body must include a completed Shop name row") +} + +if (!/\|\s*\*\*Website\*\*\s*\|\s*https:\/\/\S+/.test(body)) { + errors.push("PR body must include a completed HTTPS Website row") +} + +if (!/\|\s*\*\*Where to find you in the community\*\*\s*\|\s*\S/.test(body)) { + errors.push("PR body must include a completed community contact row") +} + +const confirmationRows = [ + "I sell genuine Bitaxe hardware", + "My shop is live and active", + "I am reachable in the community", + "I use the correct name `Bitaxe` on my Bitaxe product pages", + "My Bitaxe product pages use real product photos", + "My Bitaxe product pages link to `https://bitaxe.org`", + "I do not sell Bitaxe-derived products in ways that violate Bitaxe open-source license terms", + "I am not aware of open fraud or counterfeit reports about my shop", + "I understand listings can be removed if confirmed issues arise", +] + +if (prType === "Add vendor" || prType === "Update vendor") { + for (const label of confirmationRows) { + const escapedLabel = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + const rowPattern = new RegExp(`\\|\\s*${escapedLabel}\\s*\\|\\s*(Yes|No)\\s*\\|`, "i") + if (!rowPattern.test(body)) { + errors.push(`Vendor confirmation must be answered Yes/No: ${label}`) + } + } +} + +if (errors.length > 0) { + console.error("PR metadata validation failed:") + for (const error of errors) console.error(`- ${error}`) + process.exit(1) +} + +console.log("PR metadata is valid")