DGr zgR##3UGlKcY4K@yUPh|`3+K_d!7jC;*5==`FAW7tb2=2`&}w`_j<|2x@{Pgdr^oM3 zj0363T{^bTT&*HK+jdRusy6j$A-WNKaKU;y@mDCUg<}BlIx(Rg&FIQ z|2Z-7>I4NRSaJaC*W@tICmb^;ZBfndGBV(p1p9otau62!(GdFlP-Zq@rf#tv0@`Pd z>{GXnO5ikobDNV88b8)S>t_{(cl%}St&<7IbZxzLXU+UNog{zUDp_Sk#m*Fn4G1?@ z=aK^;&X LNLIT{%0){M$^&Dy^|&u!7`) z(ms}a-Aq6KXOTCfx*<1~#{`a}zp#1=Idq`S0Oa&Fr$PhWG<{AuF?f$!0cv>mK@F;Q z)(}4I7Sb*?(vP46wG0vQa{rB#-r-@I1^eSZIxXgE^&>fh)3sit#0p6buSYIx-njx~ zkfcsws%2@hyI~6rd&Wjk;vm1$j0FDm=dDd!a7a#j+T@!1^MR6qR=ySD4imh?0%X@e zkWT_orw6fk5h>@a#s>%*`3Iyvv8JLdrt2p=s$>%p!74f_#?!P*V8QKO9u{g*2~%X; zJ=#C!tsZj{+B$J7 r5rVu&%r&PCS|WSL9>oo86)&TB)S>Vae)o z%PW-)PLZ7@yqlycVBn=@xOnt%?tM*tn waIaQ-n#R|SqY@M&Ov zA9E969A6B;iV^wXY=8v&qae^g51ip6u&C#)r|b2KmiiBO^)@2d_m%T-$3r|-7@Edw z3A8DzU;E<+EkOrf7?xer+KD2Ps9h$3r1+F#)2I80gm|wJ2Trbh3qT9&+qbYdmunvP zkoh>5&u0m|u&KP?x$^bzA^!r=b`-d;q9{Bo*p9x%`mX}TnkU{FO?PH4PxwLiL;(d3 zA+qU |>4Q#;hwJ(lbfxTjVSyGBN2GC!_Npiuzvhr_;6K);6nyN~@J(K4!CpqtP zx#IBg{wKM~erj~un2WRuGg+Y|;Khs;149t!*DdO;TQF-_n6Cv>AF8uw4_Q17pD3(` z7e3MHPv^HOshfUZFSX|AVX}L~Z20muOJm^i6~V`MQqVg%dKRF&CYl!ge=B(RFirg+ z4ekck-Od(z(38~}jw&f~5Fm=fu22_Jf ?Od`hn(t?REvOVjr4O-F6lG83A$h#9D6+TVkgnP0k1r z?Bbs+Fx3fw;D`a@{C7|Qek8lN0tkWrRg<)gDE+E=4?&5L2O%h0VB)=Q_bCI!v_DCN z+?A2Vu@C{rXkl# A_^lo#Lmt|r zVgNBJ1_ds0Pc^Sbrm&yuS9jmomi{xG#p(ydn4)PN3taGy$itJFi$k?pSy{id{u>?3 zC#o*9Q~Ht8R4A-~_k>8{7j|Oyh ?KZ2<1$h zjCRYR)4hZ8Mx8`of@bbN*@*m;{g> zJ0NN<7va6tq-ExiALEB!*YezG$d$#_;&RO7gt7B%>BFU_6YNpP$pMEG2z$Ly!skE= zxvoHo;`x=FRx03d)n6-Y)?#iaYBQ#l+Id;DX5Yn>$W{RP!*}M-Wqfo+zU<6R5em}m z4APwuHwdIZ(5+Fs1K*SS4gTS>NydqK;N}4Lsupsse}+yL7KZ0mv|fLbdf>7@$^5zK zAEVCPC6#)zGjziS{N^p-x8Iz-axE7p{4rQ@4Jkt>*ERV_s$6IP3CZvXMk9beA+V-n z>GK E`QiJBL%>A@jxI!^)wzg;7^J|yHZWTvtK`6xY- zwHj3;?d0)wd5{gh&4(k%F{wZJ=)-#|k(OSFy2B^SI0cn^v%lhUty5F)sGtU0zS%6S z6sqFYi?*T=FLa|o_rYRV@4{c%dT7;s?xoUJETtDjR5`@%L^%#^H`aPxwcN@Bl{j}? zK=q{(T1>Zpsh;7|fu>?Osk58gChZy-W{L%-6N$JtlwbEuc?pB7p`8$s)RCJ#0OBSp z6q#dA8o;N_|J9-^_)Ylvk{fLho+QP;$nY}#G0Hx|*abk;(BX)@3nd>BN!wr4Pe%PM z876^l?>oWk;AoCakA*V;ny{dw!E$5lelz# V2Y~76_El2gLRU5MjJzii z2J-PnRi6<+QV}QpyH}NQb`i2wP46Kk9nGN^_*CVNg*&&mjj_o8z3MiUa{AT w6FO7k2&qSciU5q za{BKWzfnHPm77E=DKTl(ue}KmI@?IP@_3Ug$+X{*I%evZ0Nuo>Ohu)NVNp$V#Ya^x zG1bD$D8AoXJrMR!O0jzeQBf8nP*L>9Fd8W zIb=Diz-F7|HjEehxN&J69Vj}MlYi7^K0dPlgNSKMElWwE^uPF}ca-Un_OS47F S2rmH?TC-i6;^lgNY8EJ*m>!b??@G zS;NyP#V=w`5-1`J>zh1P*-`_Of_$lapncXtpI2dRVgMuPjzt&7W-JH%Km;bZlc5M@ z^S}a*Amk{De+q@O0B9yZu8^OC$RYvh)vbU=Z1L>xAU%XC`I< DucD|FK{c9S7b^y#e?=dTrNcC0d-{0wetu?6y8gHx_W=5DVQ-oCGQ z7Y=Jp4{DaWqg>rmD@(gd)dVsKfqYmn?;Zm+KRZnv#rqk-B}j^DZYPDBn$`Gz%%umt z%3K5>qJU4fD2bj+%WgVRbo{l;buf(e=uuE7Y0YR6|LDgp(lW&c2V8tm7?yd?40#WX z-Vb4)m*j}jHwy?5llch@G=R!#tO96fgLx$zMRGtItHYo5qy|Udv}9)g(8&1dhqK0A zpJna90XANEs{#lPc!Q|)7WNR>+91lmLuNG8NI)@c_D@wRZS#Zk_7nv4+;F5mprX5lrW)js+a$yVo^gz!_;hbyI8R>q&r z3pq#phYRP| yn*4(pe9(j+V1QD0tq!F!)2m04kH|pjag6!1C=DIjK|A~e zb>CL7j;8tdTMFC1yrUsO?MoYq8&II!O%00BdSzqR+Jh#y9p%cT;Qr!OAX35a_=mmC zr}1-cuF}vm=0)PGhaC%XUF1# ?6VldDMdk9!doO~ zmZWcOSan8$^R58TV)>#f%LqwwfKQ?LUx(MPsh@OMwTjrm^8PXn#GXqcU{BoB>PxPQ z8E@@CxExja*L<}@wxuK65PEiqzD%FQ@1zxR{kG|Fbh7}YB9lPioMIWZf
Vj3C;2R zN9-OhEI=Kl$k+${zPt(atK~UG4G>-$yE8o;9fr6zq6_Vb1Tk1)eq#W_5OL?@E<8qw zTiBNF9B&n2h|Sj3TP#vg!0jmUCgUqZeg_1{=LqH_0082o^W9Ad%IDaU=T?~NuliRi z{mP+*VTgpUb4Q8u<)HvIC_ttj#j_rTDT%!&nO!^)gpdnDh_b@`e|dyd==KuMM>g#8 zIpRi^C*Y }kO `AFYXA%KNXGU zA3`|+`kS5>m{TagAB@n#>a~Ur@=LiuGg8MVf@!5KYk-2W?tR!VL)UljyNl|?V{1MN z{AHd(beR28MJn!`#h6rQ9R<+8bW^kt)Z4z-SJpfU$27`i!nk^01VWZ~s=P-HF43-f zwoYpMFuf-%9&b|BOWb^m^S6_WEQ-f99i|0hJoSz3w MGLl5(b!KN+5lJh22k&RqCBzs>KW&Y }nM>pVb^iBhm^+WZ$x`SMSl6f$@YsLIut> x%UFG5Z7>SiK?J+)WF2oMKg0JQodY*WXAPcbH=76I zG@@7jsDGB7X~3MdJ3mHy^YT!qy6z8?X}ojAL_J+FGK6KmJY8=7w(P+zH5KxDGA4d$ z;#p?}$a4OgF}drDJCR$b=%G6ccczl2dJO@)%ViZ6oRv}B_Y(DH*f#?uasAXf23uw0 zis)VzL&+cSZ{O51i^3i8y*>vbWI2X??`a~FT0$EI!i9_efEA%koZ=SfG{8tKo=SpX zDz!v`$g+5fDKR^Q&1;jk#A(l)mX?};X+JAqVTdWHq~u=_GWotO5b}GU|Aq3ZaSbW} zpo=Vq6sKoNJ*I;*`=Y@b5|(sZUrh@jC|S54hm;|WJW%vqgG=@pm7etIQH-5|MQ<`6 z>5ouhxeud1Go#C05L}9j#(8PW#;_u?P3_}iI2zKIyFAeNZ`KN=)|cq8OhfJeGJx;z z4uHdXCjx$#xK|rpR}((_oH?y7&z86%7c{xYGyxY==1&JA0S7tBOXsFXpC7#sZPh22 zySyj{62ET=MhM2g9$y{jFbhFHqjn2NJ!>iU6%iqGY+>#ddo!g6_mqNnN!uBq3cTQ- z^d%(NN!*N3kp7mf-KwI;5sN<;b^hw|h+~L{QJGz@`j6V6gkbPYSq%xrx9`9NrJ}h= z8PC5nhiy>%)YRDfpXM2^Zc|AuU0u|v$IpBOBFvrH1SlMuQ>hGfRp)gULV0#L#;gci zWZVtnD+kl*>2N(eP^bVABIAZy^B~`()Wp{!?t3ES`PLCh$nV#1{jkITfUxb$wu@P& zSb?XDxBsP}ts^i$aU4)K=BDUo_3ag39##a>8zZeQW)@f_>70nQc|D}hcUx}=;Fdio zNxV0QqTbtTUAUV~_`bU+=i6_NhhnRbHV%Z-R6#$EKEwX?j;C|xp~b~vZFpZ|-6-&5 zB!A>|W)%-Y(j qlyVPrt -HNj$G4H~5vi$F(=sHq<03tihbI^05wm5Q6DG;(NY<6GW z7N!e|{xUG3|A|h=V`y=hB!(YEBsPy_2V!?$XjNa!4U YL5^ XZYHydvq^i8roFEo-?YXP3?!DR4K;huh}+S#`+7ifSQ zHPO0dYN5Xv&R@^(q06FMB3RkiqL@n(jc~}fE{VN?n@O6JfX@wLY2OTIbb@WGmuEGd z5!DsbwuLMxlq=}PeRLD-Kt2XNBY-eT9|uMs2^{ASL^FusgP(2)PXqw`9-}l9=Gp4^ zZSBT~`LNH9Id5ish$kuQT?v0S;)uUdVx1!JeZVL~{Hmf?G_8B+w@XP|A%L16SeRXa z&wE9f|H*SP$`Kw#1-B{}fwCzVC-G{-Cca>(f)2-*87yS}&ZtypWuVtng1_XxhlG;H z+)peM-_<;pqWi?KpRNm7J>zd56=2qRq58MVdVBmO6lNf)S~elIbl%$uKa70&Q;!xO zZ{lSJ864cAG3oaFO;J}X;xKe`;IOg1{OjOMPZj67*PYg#a(vC=5uVsgBe5~K4^bl@ z{1n2SF69F{BJb|tfkuqe#Ty}T%aFsjKUDkEJZWqkPFuZZ8g0G V}!Nq>60XFw++*E-GQ@{NxvT8WcaXY* 7*ZKXJx0~nLl5gEo29XxrP;;DC!ACuRUQabB^1RU>%gF&H z7xB`PlX +1f$(u>^d436~5WC~#V`0hjU|Fi4)|Dol1?UG1^ zzBeb!lD~F6--7}JENp1a(Z4e64B)>p$L35+2ct`%b0j%Yh|g3rm-SZ2^&n8YAd%Nf z;CiFoD0+(s@n9hl!>hAA(rYdiRv^<8cNuqiUs tgiviSdG1sM~a2hkN ziMN()*q3Ks5aTwwa+7qXFGHm55Qm}9?3uYHPv5PzA2e+Iw~@LhxkwFG9i{dac(^92 zVUURtedWlH%NP=a`gFh%rm8#5W0HGiVD;VB&20hCNmza~jLcVzuOR||sH^`E>jO3C zVuJ dfB%ZrhCcTnw(@1Xg=!@+>mNbQL`^bb?`B(~=x4@4)DIwx;= ziSz3(q_@6vO_akRRtG!7@tWbGQ~Tn+6cuO)^{)K1l@gy@&s*oWUYhSU?|OBSqyuqD z$(*H$SheHcB_0faF23Qi*=I&uK#Lq{F0NL-@r0NL3bR75D|wc+20u}15;F86n?(%= zE;`p(j^}1)W0eiW#gByFQu=J6ml$8M8iH eO!tOr_rD1&p$I^%o zZ;vnQUc4ioF2Q-}o{&Jhg9vYht*xWO^IP)orWiSJb=39OB5yyRvj>j+p3F?s<)baq z3l8eyZW qJByH0LIRi0={lO#D6&LUAS!u^8P& zan1p*@XuHPPZ36x)CcBURf)|rlz1%52Z_T=nI2PJr2}Q @Lq4xgUb4d zQ>2miDVPh))?sV$7t6n&`nibkR-Htb4FS3ovujcQH6rByzAB-co1^r2D^xw q!0&~7 z?EY~XLg+~^8iy}bSlpyyO}k)wl{!kzIp=1P)s2|O;mF6b*?dl?eVb}b40y|WV?kZj zx;{+5f6RViuXg_h0X~ZRLuHI%P1wFR0;i=fnBDKAUStzc1=GI>F;q<`sU>DQyH5A) z%tC&&U#q4pu9P&$pVIFEI6&{x9rK7 q8v3#@* zvJGVUxj|!;Z;& FS4P46Fzl~}7*>A);ajF4S6@pluFy{uXkB@N}3I>! q3}}E1f%~C(R9_^^1&ATs6fnlHQtJR8<%aCHxZ@Bp^)~DIJ2!f^3#|ldoU6w8PL} z4%uxyacE*U^dp2@)|dy5sn7tlS-2*OVUT%~hNh^r1AH(N`7qyI{?tfeI(|xF6K<7E zhK&y)@bmc%PQ8(~SnUw>6#1Vs-Kr;Jv|*#$## l*T5zSIk{aDL=h)R^0yr<=JxRj2;Z+uOeb*CIDbkT#UID;;CA$$ZI%1O-ZMi)j z>1+fu(K=}Wj5p Y{nFa{v~rsDbi0fGzT=)P#$| %cJQxE8QN#VFu=49~WI$^3%Qu1mw%U)8j%Wdv zJ3P_Q6!J-Hm7w&Fo-ux?Tq6ePo_(eYWf>OWdwqt3iw)T4hw_rBmn%Cd-m~@aLy=qo zD6bjhx7&(-18~!gu71Gs9K|Ub#gz$nK+<4`;^bX{AsQftRc^c@{h=%bEeym!;ZMnp zT?KkQyWc?9{}Tz~B|YejDcuyJOc`-zBGz&Nz(|*^ZfwR{?J;?I&w;pz8FvdiVI idzx|1D(q+RQ$I#! U<)lQh3oI-@A)bL=B0J1J-Gj09$P1WMbeonLfrl zF)CyvUH5-4`LgEhaHMrA2IBmVC$^$e%cG(spDZSuw+@HKG`QzoeUFFB^ v1f7%yrJ%8j9!Iin}!;j;|mqHTtI|Dd$Ex@hoRhB1~3d?LN7UNe%ZUw2~kCvhF z&9aaMlImh`LdU>#B)cGeWGP#i_7;CSnzM<QYCJM8G<(~h1)6Sf`3`Eg EMF-#c&2T3~)p>JuiqitYMq)FLxhQnRoemlycVq4AwY-PT{`U5z>Fsn?x= zj+Y?xz?sla11r+)kKS?57jVeoGWRFsS&5&gq0sH3An0)PGj+Y~An_uFVC_ C)ui^7xRfemLOR^T+F05;UpY2Yw zUBvIln+=Qgo`~V1HBc{`+GC`MN!9)!vGcyu&w!GPandNRr ?efZ!IademRK-QZhyD2%5h!YKFBeJ7GC3A%KO4h; z(m5-)g##BUR>ObFu ?X55v=rxY?`3X)Z202Vy1&Q36%Csp1fi+W3?3|jxuYbLq8f>#hm4FmMW=;9 zU(C+W^2r?A-h3 D?O=+H=fzN$-{9BgF29kG*P^SmzxL_P>?gMy-oX zU+3OlZqe2n)%yMMuX5wTpb>QX>!WK`nSU;pbn&L}+~r&$j2;+@o0gScTH++u^QJ`A z EiP8P59MpF-)^h+kFUb{SW RF OsJ&$k&nGlx4)C*d@4HQ_So9Vj6k|ZbsT{SHTk##t z7;NW(L+9FpRIc92X^O!t&LQ(}R1{EOVqmP59LGB>^)snw2Yrx|V^=CfNit$!HJs8y z7AG=tfQBqIKAh(5Mi_{bY&>AbL}fti!}@AwYgK1B(-)I%F?xQSAPIK#zIS;0S-}2t zbZPQOJd0nJ0Bd3NzN$eX^zKRP%SlB2=40=@s)R@i609@{W`T)SK`U7{)N$eXkftBz zfc~QWO@t rTY*64}1ihMC!{1nt#lkW1#j(i(& zMrHHqoS{aUMvAK~;s318M8vH0j8&0U-L X>a&V89 z8TvF3MM?11-94snSju<}o=^?JieP0Q6npOk;h~mip7sIOtDJ+tn<>6fD J1;- zF%Mu}6mb?B|Arvfo=g834B_lt(#AEJ5e;|ux1EyciCdwcJ2JxX9@qKAW|;daa}}|? z^r*)w!m*HP{8j)oT=mM)OnVuD@~wq6H$vuW^LZvnC-=RX1Ew 6ei7uU( z+1fQXJn!JnuhhPbg87v^)9TpbjHe+b@z6+x$)$j3{~ESncja zf$8Rs{)BVjkm-ecE5BjNMJ+fIWpPEDLhOugD>tGo{8skDh!eu9B8=WTG;oeSpkwPW zr3Kq#`;+N*A*+5HxJ{1ozD$?m1J`lJEo`yu;wC3og=P7p2Gm5O@9ppG%_L7Vcf7|e zz$!6LcK_ZFBZPwh5cSBY%cZETb6kbj>g+An0sQ9*RKp%OIRpT{7AW&Y*ATbh)1%jd zFCJpEat=E)sG9o{TB=@iB+}*1_{ jJ`=bGQU9Sn9BWdrGdq*DiiYR3q{(%DLCw6B zfh{f_pt?${W!47HegypHJ0k8z%YD% +2YWr3 zyD&czU_XCvn4*Zjkaez+&E7*OnEAMYPRQXYt3#?=3;PUuwA1!^_CNcg5A|1~TR~VD z7_i&Iq(FC*z`_kaAB$C}{qk*H9e{t ytM^+;x}zG(x_f9LzdVoxq2<&}TciTtU%IPq@^NEyx)#6!bR;?()@X@!K%KjPSD zOS`sxiJjBznr->k2to54Gu-kG9lyC8i}tBfI=!Z0OA4Yp0=UVmV_zE=!Ju<=^jMFH zsf{Yp(dFKj)D9tG_N{-6v%*qZ>M*&)!8A(fj!S3LZaC(%Uc%72==a3Q3C}Wn{>83e z-Y?;ljx3+rOpnH*H2dhHKt$^h(2k0?-yn8=fo{jNO6&*}6a0}%+{8sn0F1>KJ$A1Y zAuXF?w-bm=540o$M}6tQN3cCORXq_#e+Zg|->UF}4Fc_kFd8w1l0b}9OxcOK+|Idx zy5hJI51DGjO+&Qe84Fy-ctiOidyCOgeDb!yQdL$}3jesIlQ3^zbAA23s6p&=gi7IS zdx>g)9nwe`#rt8?``&Ud!>Inf#^And0m)QHtweHSag8@V>S_RVZ*!WWeKoV?-Br^| z;oy;Tj{lNySBY+1mt|KfvAUHk y~_04$f@L3!dTVnCPA8hhQ#b~B~ zBF((cLA(ibzEytdU%W0bmOltC6XIxCRi4LLW1dg9f7{4^pupoEr>}p;8u7kDCVcCY z)gxM3+ejNCygmK_Z@K>6qO|HP>BWb0Xm5i35Jq6?kG=#DHub~o#8@tQNUOL!w1P}W z8oGSJkFEMu8hZ4HRzd`^FRfTZmAWWU9c`0RD#B|#+xFeV6x1vl4K+vqEI2~A>AO2z z%syhk%yRNb`>Rs@drz6i9O^vQ1QrUBj8A2_;y{jBJ*~4YXM|JROE uKAs!Uk zs(anvlEq!V%zee9#lB4S)h+K?ZZ#;tnROu6 |D6CAqv2mNBg=%k&uu4ZOt2_to>TBU`1yRP?GyNM zA&Qd6UWgQUL6vwyOa(dtswA-Ze84)RQdNghdj}=uL)a4nvV!4idLQfG1i2w?QbAMY z3p7o;2)AA +;|>@ciP1R(O;*R zp}+EM97Mp15u86MLLQFU@Vt5M&m)wigsCpLzx~CH^n6SCB~io&4;k(u4}JUPSC&wh z24Uurj677eDI%3crLQgoOwv<^7G7KR4G)(My+JOiS>%&cCr<6o2#Iy`!#kMjsnpZN z7mox({mt(K8ImET9^LgwC}}6oF>AA`yA(-|t9)P)0-b~G-?XEPP-L@PKn4-9w1g0# z;%SoCaDioU7~#ARqea1XD^arF?_N{>6%{>ANM;rYX9DHNwt$infN!q{O`@ZPPVp#m z&%1GtHj*AM;*c79^$BCr14L)7@o;1x( #OHoQxuQ<=k@(a bdodvz}8 zb0912GN0$vHKFgXp>QjqDig`T@5y!_Ms|AA#H}d=^?2X Af wh9uPbF)7 Ag<6I7YZ%LlW;^I7#wN5=~H{nGOdY>mp)p8}^wgXqcG!iYuV`Wr@)^aW| zJ9*C+R 7F?0&8UFHw$IKOT z_Ud6>A8_tWLM9QzRV5A@q>@fXYE<+^Vr6TW_T3(KYyGMGVm7~fhZwWuzR#QH)&ML& z`id?QZ_oe9d(-dwcdTZ(Nf3fVc?atIfE%L^>LYvoLiw2m;)U_$M)ZM9rIq;{Wg- zw8uAsCuZc^PI+;WB(WnB(-_li(P|M842%s4`?bGiKwBolB{%c@Q~!p6R(75D3cCg| zoG+ehe@M6Nm+XI>)EJ|+QJ#6VXmFRT-$$(&B8(D}_3*Ey4m6!DQ0SnFDp)ZVEAW>G zXykPA*}oRyy=6tyQ_LPBco_CPUYz}I`I`bX(c{6@(Z)WU4Jh#YCDqZ!WInKfaLAW& zzGGvWX<$qt+3`w~DskXwpEik(YCK*lgz-I|f@+YmKWc!lbk1)lj@03RunIi6Iv|~e z&Q@(*I9kk*!hX#r>5M^#so~I3`dC_=>+HWz(yJ9aT5z3Vi M-V38j%-W1${S zA?mF!Gyj7G`+%3P4$KO3AT=#50U&<(62DGNq4WEMEgD^V>Cv}O*uH<>c2K*{T4fC| z)r$yp6o3lT|1dFSlg@IgWp%fMla-{QOOp@&Z@o}|!HbNalFSv4N_l>$v4lMcb(Py@ z2-!9@OA@oII4s_NN*HS1+ohfp2vf*fyf(GTh}Nrk Y44$spq4cOO ?L{$O$ePpleqajqp3u{!%ib9A{ z89MwLfO;ME2xDk*63FM;*pb 7Jzcl!%)H#B zPptlwd-6Vu!rSH#J*>IT9A>k@xMoTO`-iET_J2LSB(EPGvmFay^ubPLcef!}uq7*e zOg#>$5MY5vldrT-X&W&JC9?tVr<&W6kA agFI5N ad_d8JN(IZG3E)H z7Gm_*$xs3fW+I2CVzWW@h?+mLdR^dNH0R>zE{XM`={a~{>kx v@YIj|*HgQ4gd;DSWPCw=elHH;ED7*OTy4~9~Ysk|18vLYvxs6An z@b1ygvHVX?xeySd1452|I@ANb7=z%Z3z4l7Ha6l#)hR6v`{<(+s!>8|4CK?h0$yfO zVpP*%!)?N+22 wSNZIXve8`x;n`tz9kamWLt&uC)^^=b8Zhn z$MxLjQ4OA!Rrke yIud>islQPTDn0hj^!|diZiD_$TW=ZGM)$-GC%8+Y zxI1leE2X# I?<3AuzgblA_HmvQ{ic_p$>X zANvovK;3gmNA$Al8|Of}doN;-eTq=<2J3To*16YeQv>F$Fq4Q@a6}^^AMM>q1C750 zScNn0f1}1)+*qOa+{m?H5@J9{nS--z$U!2P;dYb?ZD!!J&kEo 8CBr6jTY3r5dq~iD?Bj zsMz$+l7K3P09E7$u9LZtqS*lkZJjwx8E3Vp7vFHyuEz0o)Yz;W<5wfYH)OWSf1|d| z&7A%|=_-v!xXL?>;Y_N67uVkB@CcKE&cB|UlYu_6!T&fPT;w3+SYexy^Vy_@X^4jQ z<_b=&?!ufiR)ID(2kAtgr=XpZ)V_6IsN{nxDQL&i x+!#sKkXykP?PtOAx zDA@DAsJ&TK)E)~Avl12Dr+^CgLsdM6`*Hji?guph69aBTP=3VtLTECt|F3$D|H1*Y z{|g5c`7a#M{{Ka|`_J--CYd?az_D#uk+Z4|-Y$u%gf`9l9xQ9Tmy?D1m5yK51+Dv>IUs>xp*w!s0!PSogm!>k1l!-8UM*LxmtpwAv9Ay z7Dyi C$3o({TID}3UY0BAEm84A`@< kx|(z&wtmhAv<-S;PG&;AVC|GD CTBc5cSpV+isq&DK{kK^w7ac;Q_d|$SJ8tzvH#bE(5JA^$~Stlhl zUB=zja3<#y$fiz1jVfQhq@MOiH51DhPLclk)Ex|dUi?f*4DKNP82X^MOh~a8E6;bC zH(Pn_p}}yh%K{_ES-dw&??Zmrjt@ Fh8j1v%9D-)m6yMA-qbmw4$i*d2pP zE{kH&NnfboTrvxw<~n7`QsUW4Wz2y{D_)M4-`lvln$j}Hze9Py5LjkeD*m7*c(2id zN3Am$f$%k6l}dniZs$5v{IC*a0nEMuCWIHE@l?rWkb5cCKfB2qtr-o2ROZk6#wV%r zsR4K2_KWle?1n2EG2*6wzWAUtBM4+llSnuK?>6Vt3aR&L4Z=sTnWzLtko!+CZl@iN z#J8~(Q9gSCA^eh2#fAl+g~?@j4tbHVv7u6rQEwniv9GQgm ZK1Ojg?-{QhHhV`LAZ%m@L;jJ4i-NEyp@+ zyp;$=KOWpa?w75xzq`+k1Mv+wN4oE0lIloSiNL*?8eblm%aHN>LQjIcDJ^{0Co0Nh zE|Hx_s=|JuzP^<}b;C10RQ#KTB^JqvG!*O`Qp`i7Pt?8A8=2bxCVS%qOV`*jasc|( ze|W#cc8U 2f0X%Y_FKM zcRq!uJxy&Q=$)UzV<~?1JxD=b;r9UI38@InKssayg)_6*E5z}TCevD~Da=BsKrAd` zsESHb0l0#K6RJXo)dIETmr)hPN~jH-wDqwf9)jxk-(En9>i7R5IJKBsRg__JG*ZO9 z`G*_T$lYl;@+(+g+;12~C2xYvIgQg+3w5(7KFR!-FX(ZeiX!=Cg{*EQrLp2c5YD54 zb6pgNW+1C@`k>vxF1=>l6mb4Nb$E9L4u`j!jQDNKUPZw~GNvTrl8;`JJXKJ5h$nRZ zu^`&se1z;sj~})}s(^XUPYe1zZHuTtl_*i}49M#a)If6;x&n@FN}LnJYmftVCc!{? zML{? W)zCNY2kf7Q{yUoL?L4$aq?a%`M5o=jUpfhz7sA*zPI_4Sq z;1sX@S(#9!l?4nQo3f{Gkx;%1?JsZRA{05FE+=%9FN>nUJk}!b `g7h8OtT$8Yk3it=EfRoo&%WM~Bk-^hW#-!`8iZ=1LY2{Pv5M;e|c%N!NQNt}CVQ zs-%7IB(lCeB+Opv?5$P~fAU?i0n@9v`H&%NN>dhhe@Xy@(`s4Tk7A)4jD)c)a2f>7 z@#no;rm}kutGHT~kZ#hg?i@ry6-Qu0J}({sd }mVh^132X~3aPBRe$BZ|8V5I~QT zX&B7dgeZuKHt`lc>v&gfk#?_YaQ@2Y($7x?in_ wSl^GZ#b!4(>$ zZ;owTC0-fQ))DG|fQ2&clxXv 9wEV1f=|7}5ij!*>v!YlHZ|l }Sslbp;JR z%&rxw{ luae$Pzt=}7gIm#dcNz4SZc*{>Qd}an3J5S-hhiX zy2#(QY6g30bJX6K7A`c=bEnKfR-6KK~TcQJVVM?M!Gkg( Y?ld zk7AQ7zrjVy So#N>6gOVw@a&|7xy1zql_$^cUorp=GrEL+o+vNB>6o8JO(Z? z;&!}$3p7hIDBrfjzQYGaOy};!$;tj1X!b72e5T#^X`}%)=9BTpF8unr>wQetYh_uf z$Q`e3uxdq@aOoRx_EJj+2O*A+tTo7IhpfL7D#;L{{j{tUdjK3=F7n(v;rE=4Occtd zfhLwm`Ysf3wz~ZatUVdvHgojOc?TBW{84{ef5;7%hIKnd9*nQ(h`x>J`t?#2k8I%i zt6Nkm7@T*2ViDe*8uVeqYs!~)STe(& 8W5{f-Y= 8pmk b-kkf|X}`?)@gk2FEWLCO&dl0sqB<72B*YNnGB>kyG??KZfAM$sil5LW zvbrAq&oJD7%);%%Zzf5>H!aGJrx>JFF&1IksMWRbLfbQzw?3ih6iY&C+KS DSE()x%|;Qb@~iv z0i)s8C7PSbvNlt80v;LwyL|m|%F0xwN{1+RqbA`H$5h1%5xn_zt7xaqe}0^?3@nEo zNI9L6;*O|Z{@CJlw4>+<^zTaMPv@R5l$=e?p2jI^0N$#KRT;z)= `?Nwps`X9y#k@M;&DP1>=##Q7g84MlUP^a+Pidg`DsPT79Bvva; zedU1&O;PO(sr}Z-_IB;2LkDSHK5`&ST)bOc>&+B1qV1oc#Y!8UM!Yt+zIG?JS?_gH zsj|nBc}}{@ n7xg6lX`B>i& zt4Bgl+1D-}Sh-ca6e6K)D$^p=@Xu^2YpnnKTd+c?er5|uv_b@iSOj`2U$twYb`#Xu z{Pj_guz&q`>23|?yOGtq4z?$Q=5*V;@C;1LKI39%B5d8J<`Fyg=?U;@jE}E+!V*22C&_H?s#Pe4zliwoCfS zJ#&JR&+Jx5>J9>Oay-_37kBRCWVK5l?5>h#1MCz2!8oqcvia6kJb+Y2`!oJ~Avmp` zCRH&SAc{m`re>8CG>8xV(gN(WZ>Zemc0cCQ;mJ@$vTfwnU`ue~+M564^N~?FH-{p+ zh*pf1UW#M*Gx7%i+?dkY?BzPzP%QHgNf*$;i*rC*Pt7R*E-p>tEz0n=0C*ovr3qGP zDWjaHVBu!swxty9R|1#pNf8jC9_Ivfl=NCohD7yZ5;b>wGGDx?ds{KZ^W~WYP-I>- z+SZqc^+tl@#~c1mN;M{yoBFrl3zp{>1EN8MGlT!cwO`vMIs$O^Wem~$UFkR^kvsfK z_$~Uzp}UH;&2j6=B_D^llqkrkGv`Gd+gRaqr0ZEba@yxWU96Sj2Fgj6yp)$;rV>;< zPp8wx;S501#i%rk_6z@@omE8O^(Wr|to0GQGF@&8q@@Jm=x(q(S+s(xS`R|^r=S79 z80Hi+)IN(I(00!XkLgIrw~*tVWdLOy3y%E6L;I=TSxB}+AwtI6r13L%#$iusknN^* z6b~}w`GOqzYnx2|Vvxc%t=jeOV*6IbxJ(&bQ3_tcxLw+`7o37X$@22U*~BrIxuh-H zJy;1##ELA(=I#EB@Fk!v>b`4pzh#3%RdQXw3F$5EWU`HrSt-D+@(`Ng2~oa%a0CRp zyGL^Q_Wau bU;`d @{ai(T0ZS`m9;uhN(jQ zAO8{6m#gMciU6EcYL$Qn8fgv#Zk7?*rP(3*WXit%aFJ;FDtl8Qnk7yj)^ANv`~ReE zFWMc&Pq`Sn_$9sFGML?ctWC)uXX39C TBo)6-rsCJe+4sHo3z2Tp)}=6u z8R=lAOwL0v!(%b^D2Odull0Vvxd6(Dh;Gp=EYd{?y#=xlMEPXu=n)^hCV9jX9-)Oj zL^^h&V(K6q`?;`qiSjnhGt z+)3T-N3pJZ@W5* 60hwUCp+(rVM_cGKbQ z?bzt1+GT|G(@kkNE%Wx2HRo{XkbCMo3E{q|&V1-3x#WgEWsq6(F6{%jp_kF!Ir2{3 zKFCE_QRiOBiySW9<>VAkDoR%dFWa!_qX-_CLfg9RUnwz*bP&e$tv-TlQ_+|Z6FQEw znA~${`f1kT+fVa@{qBIlvdEm&rvb1URgW%>%M`59tD2bvG#M{eukg?+H%@HzL;i7e z;kYG+Agsvc2609JqYq=%4ce(qPodV$)YQiaRa568u3^@;lKQg-; ?UL*-JB-K~L>UsLj4uUm{-=YJjUGZ}M(V~Mm*{>lim z1~?#%mo$xE@v7NM!bkJ~b~d>mL@_*lq|S6i#m}x)uvs2lM^A`&^Y8MVUiR=`i22k4 z^C}L0fAo=|19XO;mz3lgRHizi7(#C=s27Q04!t`JvPU5O$ooWP^!k8t)awd8`Gf!} z3X?n{u0A(2F-)mOiuIQt`QLHz2my!Ir^A~NH0;cS!RFoRk+N=2NN)0UB2^jCAvK_s z;69nL*AtZKU^M4A(tR|Og8yT 6VAMnxV)n;;W0j31A z6yTtQ=TYc~!WuJtw*y0-6BHR7eW0R-W&0kzcNs*nx~lSV<5w?pPpb55;o3sqDQa85 zLhTHTN~XfTvbGi5cRL@O ex=$XJ^nWrH`{5xA%umRkEj2}b-v1e&8Ic9!QhRN4gZ)7X?#6AzWgBlh zW%m46Wmsec`+?Nsm{=>sWeY$X-6gG$sc5yQi9IiETy^!Aj0DqpdOis3PUslg!k}RU z38TcVG8<;dd%znx8-oIajdSiPJLy+6P;I*a{Il)hn17ilYqPFMFj{-Mk=JQIu(!Zn zz2jJA8SHvT4-Na;=K+1^|3^2)ON^ZU;KPRp1u47uy2+_p1DdC($tw3FMxLRSZ7{?X z-~8=#WGf0SHbK*6o(*I>TaLdM9c!6!8*<)XKdl$*A=Wrl6CnFzKgo!DA kj;eQ3_j=z;v3b0A?+$})d)@-Sw4W)rY zR?}Q%uYkef7C8 ggTV5(dJM`2_l9{5e$hqOp&GpM z55w$NGHSuuBQtCbjbK6`a768smkcsl)UEf`Q<&vxVr8CKSR~6$me%VuX0j-K3Zr_f zfPo2Jv0~3@iHV8P87Jn=NJ`PWk6kpD8)CEc+ePd=p=~Bt#V>nHSEwHWT%exEW0%M3 znT9boEiAj m(@6yT5vxl<`x|2`i1aq@G~@I#qDj1;{4N&Q zLmr2-Qo+L-x^{pXZ4U|?8Ftu4^fK&OVJiIBK4xZBE(9s_+a9R_P%s&CWB_MSb?~C| z^)5F@> Xl82xAXd7l3;m{y} @wpB;^|BN_8*$`McG z%Bhg^b3A@Fw@{{@rZ4!St-6=B?f|lQf8pTeV&`eiKbJVdt$USib3+J^ulUupkY$ z5r9BB(`zN;pzJlxXnB*xC^{T8$eaqV1kz^(wnanpT@W6Hm;~r{4;OsYebRLlhdvD` zl$U6MJcZHoaC 5*1m09x|jK)Rr*-QQt^v-s|q@$4*R40=jzylZ3vd= i2O#0{K?YDS_f|4=_m40w47X!r_9Lt%h;6 z2DDZ{d$+T`C@G!m<)%@>1rJYB=|5My41F5O9r$*A<02DDOCVjc)I^~}6)BFx{F^c6 zU=6nIsK69X62rqBu1<@ZFF8*gFfQ|NQw5Z2BpIXB4(Eze2OQMM`q=1z5&p1>Ng_8C zM1nL(JoXcaT-%yFNMQ<3iXJ@Q$ZD)04&sCJF>HWLy8NP#F8`ughQwHs-p=AP`n|BG zlKA9@C5Myc31(!F_T1hWGld+4aZdcDzbLR^OLVh*CoX-~J7{8|L?sb)$ArUdH4W?Z zId|am_rJKlD-q)h&Zx%TkF9V7uhqU|RF3a_*qQoe(DQ39Wo|D3G&_eRcFynUi4p@a zbl<&peV{g}$(J^5j`c0>QTlC{JRUr&iD^o-`g7+~bA1z9I?FrJ_i9h8=_(_*y(5!p zm1U)1Uea|cgD!M~K4*;n-?=_ALoAWj7&;||it!Y> ?u0VE>FAPq(SexxGNJ&FGSdo>HHPW_S@7<{fkdKKmw%V^szT`= zBA+f`Y39n`7Q99--B;X?wrXwBGbsF5lq?=fu~z(yKED5*K``Q-4f{KQHblv-x)pj5 zwtl8BQ=sPTsJO`&opwGa_wFXs1?S5D*+wolM<~%RR0d9U7xyfVa+4*X!LxPza=?pN zqOX<=nMT58%RnxA0!a+g b}~2Kw05z29#PIX#V(J~pbPFtO-*fKBb34v=0W z+LTDH;ALAya7vPxYvt0=Zz*zn%XT6oc6ixDyk(9cwGM?B+TX13f4?JF>0xJ%-4f*| zn$DYUVTe6tNh1>*HHEzd$BD{Y*Xn9>@PgOCxjYeG#N63WRSj@SGc3N`3+0@`9ns)p zd-c-5AOY&63|>h(%RX_rX!@FJXkZL}UOIwe#|^C2m1L@wiVev`wuq9IbbU3JC#FP?grG8Ol z2ymq}R7uxLax|}Q(ed+eWWJ&fPD&}MfewhKN8{3F=`+2%{V?gY0|fs*Pa7n5Ua~H@`q14v2YiL0$6{5b &_SMJbea(YPzULbGXn5M$LdVAwZe^r;1ZRqvbtvy=F0yV91*}SQ=jw zv=r`1&CF4#V9?`*NpJtrGR<@dq mnbsx)DXX?{>i70?7Err8ch*f(! zD&ZdiHEGprxau$h{#i{_3KIGF+PT>Dw7Wl@*ps<9D0B&BUY%;0p$xOVN5c&I__q1W z;G 8KD#k_rH35drnrbIQPK`P6$Ydt7|ksQc+=$&w2{0JED z75#evE~O`=T~=ZC3oPK-e)r61GPFMEa$Nq;M$IOMr_kTOJ3g~h(T%Kfdu4zgnnA62 z41aDC(q=iZbzS6bHzTq-=QDeQaAeWY^54(G*oFJ4zjt{><{K$miPrVzKgTa)){{hg zGfDhxCCAM;f9=i+Ho6fck_p @dFfp+f?9n~#*s%3{bI8=n(*n)H1@}&wTmxIpkp74JfKC$9D1-wMsQA>QH>*=2f z5FO%;cug!JXAq(>5sjW4IAj89&~5 P*61){OEiZ`#Ncl^B&W8<2Fs{?f>tTtL(^ zhEikuWCZ*|%q8?sWhpv1r7ZmY)~8JZ5^=0JBccu8O2SL`A{%PiMtYD6z5>C=#yDWW z(a4yIpv;dQ!k9)Su5?lkbt(0BCO1ULF!;?CC+6rDYC36P2Xz0$NRdP%MmP?Vo4@9M zCGE;n5@5w|@+VjmVtrqzi?^V~GMkY}8VD(q61K|ynjJrkSYk$5;excfBxF6aFCdWj zEbu^iTfL0HG3#ycQ3N9{=F*FN@x@QO#0^D~7P0#d_-e_G2t}rr%D96jL3m6Nk;@b+ zOBIk*N3HLC+{|rZQR e_9qf znX0AQqMxFLh9GY?VF$ba#3+%Fio5B0LHI=jeaj*`-G}zCrc_{bCaa@D&_@!aII`p$ z5sy`de2(^CjaJMRwHX3HoxvpaMa)5XfcW9GoM(Rn;Bnc_JA2RlrnfSn6m=}ZT#vCz zj$|UED6JR9HG9FL0!L43w*5X$RZop)Bxj@uW<2lwssg_O $#abkjiBoy~Sx4@VG0tlLby?>0!Hk5_HGWc**2} #6(Xu($ z6F J{)M5z2!kW+{GGQHzkOOXSIihCnLk zs<`0yvSC~2Gi?ZyrjIC{`T3R{c^ugN;OS=!o`^yf?9GxP4Yq$PPn{Ca_j~fAJyOU= zn9Rh9 5S-UfiKP+1_tlWIEPLH9MlS(4^{;1(PYVk%{>!I&M`uQJ$L(5 zNmy{ILgSe%EUPGCW7Mv}5fQ2F`fUfgKGAf{pFKZw%;jv{#EAE (Krcs6-$QHUz^Alh(8zs zVJ5Zn!}4k}Mt&Jqz$80Y4FFmAWXQI|z`NmFrywZ6m68h{^rHC6_Y3M!3YD{;1QeW# zK>Ll#+plYZpM?6b&l{BMUjoVtkR1*X$0J92Ham}ZBGA}l$dI0GyBzy@{~d4tI-r7E z;HPqFf>9xbd|Uq=UVI%t%+>*iJn4@ 8Yj(fZ*|#MnpR z5W)UvM~R%;_b|+1at?UonUAn6R_Zf#aQl1 G?{c#2B^ literal 0 HcmV?d00001 From c344127b5714d01366f2e0b57d649d744182d55e Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Mon, 12 May 2025 16:10:29 +0300 Subject: [PATCH 2/4] revert file name --- .../anatomy/reproducible-builds.md | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docs/smart-contracts/anatomy/reproducible-builds.md diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md new file mode 100644 index 0000000000..1f2b4c5b3d --- /dev/null +++ b/docs/smart-contracts/anatomy/reproducible-builds.md @@ -0,0 +1,112 @@ +--- +id: reproducible-builds +title: Reproducible Builds +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +Reproducible builds let different people build the same program and get the exact same outputs as one another. It helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract user can build it themselves and check that the binaries are identical. + +## Problem + + + From 5d19d39b59813e815c77c497ebb0e93c3ddf1d5b Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Fri, 16 May 2025 15:55:21 +0300 Subject: [PATCH 3/4] fix: grammar --- .../anatomy/reproducible-builds.md | 83 ++----------------- 1 file changed, 5 insertions(+), 78 deletions(-) diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md index 1f2b4c5b3d..4f0eb9d7de 100644 --- a/docs/smart-contracts/anatomy/reproducible-builds.md +++ b/docs/smart-contracts/anatomy/reproducible-builds.md @@ -1,26 +1,25 @@ ---- id: reproducible-builds title: Reproducible Builds --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Reproducible builds let different people build the same program and get the exact same outputs as one another. It helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract user can build it themselves and check that the binaries are identical. +Reproducible builds allow different people to build the same program and produce identical outputs. This helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract, users can build it themselves and check that the binaries match exactly. ## Problem+ +If you will build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billion other factors in your build environment thus, the Rust community has a long story of fighting this issue. + +To achieve reproducible builds NEAR utilizes several components such as [NEP-330-Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com) and [SourceScan](https://github.com/SourceScan). + +:::info +In order to make use of reproducible builds, you will need [Docker](https://docker.com) installed on your machine +::: + +When initializing your project with `cargo near new` the generated `Cargo.toml` will include information of the build environment and repository. + +```toml +# ... +repository = "https://github.com/ +/ " +# ... +[package.metadata.near.reproducible_build] +image = "sourcescan/cargo-near:0.13.5-rust-1.85.1" +image_digest = "sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3" +passed_env = [] +container_build_command = [ + "cargo", + "near", + "build", + "non-reproducible-wasm", + "--locked", +] +# ... +``` + +When deploying with `cargo near deploy`, this information is used to clone the repository and compile the contract in a Docker container. + +The compiling process will add method `contract_source_metadata` to the contract **with no changes to the contracts code or logic** that will return the resulted metadata. + +After the contract is deployed, we can see the metadata by calling the method `contract_source_metadata` eg. + +```zsh +near view contract_source_metadata + + INFO --- Result ------------------------- + | { + | "build_info": { + | "build_command": [ + | "cargo", + | "near", + | "build", + | "non-reproducible-wasm", + | "--locked" + | ], + | "build_environment": "sourcescan/cargo-near:0.13.5-rust-1.85.1@sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3", + | "contract_path": "", + | "output_wasm_path": null, + | "source_code_snapshot": " " + | }, + | "link": " ", + | "standards": [ + | { + | "standard": "nep330", + | "version": "1.3.0" + | } + | ], + | "version": "0.1.0" + | } + | ------------------------------------ +``` + +## Verify and Publish +In order to verify and publish your contracts code we can use [NearBlocks](https://nearblocks.io) to trigger the verification process. Navigate to the contracts account page and under the **Contract** tab you will see the **Verify and Publish** button. After the verification process is completed the contract's source code along with the metadata would be publicly accessible on NearBlocks on the `Contract -> Contract Code` Tab. + + + +For a step-by-step guide on how to verify your contract, check out the [Verification Guide](https://github.com/SourceScan/verification-guide) bellow. + +## Additional Resources + +- [Verifying Smart Contracts on NEAR: Step-by-Step Guide](https://github.com/SourceScan/verification-guide) +- [Tools Community Call #10 - Introducing Reproducible Builds (video)](https://youtu.be/RBIAcQj7nFs?t=1742) + + + + +For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. + +When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. + +### Ensuring Reproducible Python Contracts + +To ensure your Python contracts are reproducible: + +1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. + +2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. + +3. **Document Python version**: Make sure to document which Python version your contract was developed with. + +4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. + + +From 1c293f61456d02eef5749597c9c240b338593485 Mon Sep 17 00:00:00 2001 From: Lyudmil Ivanov <55487633+flmel@users.noreply.github.com> Date: Fri, 16 May 2025 16:13:29 +0300 Subject: [PATCH 4/4] fix --- .../anatomy/reproducible-builds.md | 81 ++++++++++++++++++- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/docs/smart-contracts/anatomy/reproducible-builds.md b/docs/smart-contracts/anatomy/reproducible-builds.md index 4f0eb9d7de..4d3082e12d 100644 --- a/docs/smart-contracts/anatomy/reproducible-builds.md +++ b/docs/smart-contracts/anatomy/reproducible-builds.md @@ -1,22 +1,23 @@ +--- id: reproducible-builds title: Reproducible Builds --- import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -Reproducible builds allow different people to build the same program and produce identical outputs. This helps users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract, users can build it themselves and check that the binaries match exactly. +Reproducible builds let different people build the same program and get the exact same outputs as one another. They help users trust that deployed contracts are built correctly and correspond to the source code. To verify your contract, users can build it themselves and check that the binaries are identical. ## Problem -If you will build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billion other factors in your build environment thus, the Rust community has a long story of fighting this issue. +If you build your contract on two different machines, you're likely to get two similar but not identical binaries. Your build artifact can be affected by locale, timezone, build path, and many other factors in your environment. As a result, the Rust community has a long history of addressing this issue. -To achieve reproducible builds NEAR utilizes several components such as [NEP-330-Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com) and [SourceScan](https://github.com/SourceScan). +To achieve reproducible builds, NEAR uses several components, such as [NEP-330 Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com), and [SourceScan](https://github.com/SourceScan). :::info -In order to make use of reproducible builds, you will need [Docker](https://docker.com) installed on your machine +To use reproducible builds, you need to have [Docker](https://docker.com) installed on your machine. ::: -When initializing your project with `cargo near new` the generated `Cargo.toml` will include information of the build environment and repository. +When initializing your project with `cargo near new`, the generated `Cargo.toml` will include information about the build environment and repository. ```toml # ... @@ -38,75 +37,3 @@ container_build_command = [ "--locked", ] # ... -``` - -When deploying with `cargo near deploy`, this information is used to clone the repository and compile the contract in a Docker container. - -The compiling process will add method `contract_source_metadata` to the contract **with no changes to the contracts code or logic** that will return the resulted metadata. - -After the contract is deployed, we can see the metadata by calling the method `contract_source_metadata` eg. - -```zsh -near view -contract_source_metadata - - INFO --- Result ------------------------- - | { - | "build_info": { - | "build_command": [ - | "cargo", - | "near", - | "build", - | "non-reproducible-wasm", - | "--locked" - | ], - | "build_environment": "sourcescan/cargo-near:0.13.5-rust-1.85.1@sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3", - | "contract_path": "", - | "output_wasm_path": null, - | "source_code_snapshot": " " - | }, - | "link": " ", - | "standards": [ - | { - | "standard": "nep330", - | "version": "1.3.0" - | } - | ], - | "version": "0.1.0" - | } - | ------------------------------------ -``` - -## Verify and Publish -In order to verify and publish your contracts code we can use [NearBlocks](https://nearblocks.io) to trigger the verification process. Navigate to the contracts account page and under the **Contract** tab you will see the **Verify and Publish** button. After the verification process is completed the contract's source code along with the metadata would be publicly accessible on NearBlocks on the `Contract -> Contract Code` Tab. - - - -For a step-by-step guide on how to verify your contract, check out the [Verification Guide](https://github.com/SourceScan/verification-guide) bellow. - -## Additional Resources - -- [Verifying Smart Contracts on NEAR: Step-by-Step Guide](https://github.com/SourceScan/verification-guide) -- [Tools Community Call #10 - Introducing Reproducible Builds (video)](https://youtu.be/RBIAcQj7nFs?t=1742) - - - - -For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. - -When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. - -### Ensuring Reproducible Python Contracts - -To ensure your Python contracts are reproducible: - -1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. - -2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. - -3. **Document Python version**: Make sure to document which Python version your contract was developed with. - -4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. - - -\ No newline at end of file -If you build your contract on two different machines, you're likely to get two similar but not identical binaries. Your build artifact can be affected by locale, timezone, build path, and many other factors in your environment. As a result, the Rust community has a long history of addressing this issue. +If you build your contract on two different machines, most likely you will get two similar but not identical binaries. Your build artifact can be affected by the locale, timezone, build path, and billions of other factors in your build environment. Thus, the Rust community has a long history of addressing this issue. -To achieve reproducible builds, NEAR uses several components, such as [NEP-330 Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com), and [SourceScan](https://github.com/SourceScan). +To achieve reproducible builds, NEAR utilizes several components such as [NEP-330-Source Metadata](https://github.com/near/NEPs/blob/master/neps/nep-0330.md), [cargo-near](https://github.com/near/cargo-near), [Docker](https://docker.com), and [SourceScan](https://github.com/SourceScan). :::info -To use reproducible builds, you need to have [Docker](https://docker.com) installed on your machine. +In order to make use of reproducible builds, you will need [Docker](https://docker.com) installed on your machine. ::: When initializing your project with `cargo near new`, the generated `Cargo.toml` will include information about the build environment and repository. @@ -37,3 +38,75 @@ container_build_command = [ "--locked", ] # ... +``` + +When deploying with `cargo near deploy`, this information is used to clone the repository and compile the contract in a Docker container. + +The compiling process will add the method `contract_source_metadata` to the contract **with no changes to the contract's code or logic** that will return the resulting metadata. + +After the contract is deployed, we can see the metadata by calling the method `contract_source_metadata`, e.g.: + +```zsh +near view +contract_source_metadata + + INFO --- Result ------------------------- + | { + | "build_info": { + | "build_command": [ + | "cargo", + | "near", + | "build", + | "non-reproducible-wasm", + | "--locked" + | ], + | "build_environment": "sourcescan/cargo-near:0.13.5-rust-1.85.1@sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3", + | "contract_path": "", + | "output_wasm_path": null, + | "source_code_snapshot": " " + | }, + | "link": " ", + | "standards": [ + | { + | "standard": "nep330", + | "version": "1.3.0" + | } + | ], + | "version": "0.1.0" + | } + | ------------------------------------ +``` + +## Verify and Publish +In order to verify and publish your contract's code, we can use [NearBlocks](https://nearblocks.io) to trigger the verification process. Navigate to the contract's account page and under the **Contract** tab, you will see the **Verify and Publish** button. After the verification process is completed, the contract's source code along with the metadata will be publicly accessible on NearBlocks on the `Contract -> Contract Code` tab. + + + +For a step-by-step guide on how to verify your contract, check out the [Verification Guide](https://github.com/SourceScan/verification-guide). + +## Additional Resources + +- [Verifying Smart Contracts on NEAR: Step-by-Step Guide](https://github.com/SourceScan/verification-guide) +- [Tools Community Call #10 - Introducing Reproducible Builds (video)](https://youtu.be/RBIAcQj7nFs?t=1742) + + + + +For Python smart contracts, reproducibility is less of an issue since the Python SDK doesn't compile to WebAssembly directly. Instead, the Python code is executed in a Python-to-WASM interpreter that's embedded in the contract runtime. + +When you deploy a Python smart contract, you're deploying your Python source code directly (or in a lightly processed form), rather than a compiled binary. This makes the deployment process more deterministic, as there's less opportunity for build environment factors to influence the resulting artifact. + +### Ensuring Reproducible Python Contracts + +To ensure your Python contracts are reproducible: + +1. **Pin your dependencies**: If your contract uses any third-party libraries, make sure to specify exact versions. + +2. **Use consistent formatting**: Use tools like Black or YAPF to ensure consistent code formatting. + +3. **Document Python version**: Make sure to document which Python version your contract was developed with. + +4. **Avoid system-specific code**: Don't rely on features that might behave differently across operating systems. + + +