From cd3edb9e7a8b0e7d04fe7cb8f278f6ea6f2c8a0a Mon Sep 17 00:00:00 2001 From: Gregor Sturm Date: Thu, 30 Jan 2025 13:40:29 +0100 Subject: [PATCH] Add python stages (#98) * Add python stages * Update CHANGELOG * Fix dvc.yaml * Update docs --- .coverage | Bin 0 -> 282624 bytes CHANGELOG.md | 6 +- docs/getting_started.md | 3 +- docs/user_guide/templates.md | 4 +- pyproject.toml | 1 + src/dso/_quarto.py | 2 +- src/dso/cli/_create.py | 4 +- .../init/default/.pre-commit-config.yaml | 7 ++ .../stage/{quarto => quarto_ipynb}/.gitignore | 0 .../stage/{quarto => quarto_ipynb}/README.md | 0 src/dso/templates/stage/quarto_ipynb/dvc.yaml | 11 +++ .../{quarto => quarto_ipynb}/params.in.yaml | 0 .../{quarto => quarto_ipynb}/src/.gitignore | 0 .../quarto_ipynb/src/{{ stage_name }}.ipynb | 64 ++++++++++++++++++ src/dso/templates/stage/quarto_py/.gitignore | 7 ++ src/dso/templates/stage/quarto_py/README.md | 3 + src/dso/templates/stage/quarto_py/dvc.yaml | 11 +++ .../params.in.yaml} | 0 .../templates/stage/quarto_py/src/.gitignore | 6 ++ .../stage/quarto_py/src/{{ stage_name }}.qmd | 25 +++++++ src/dso/templates/stage/quarto_r/.gitignore | 7 ++ src/dso/templates/stage/quarto_r/README.md | 3 + .../stage/{quarto => quarto_r}/dvc.yaml | 0 .../templates/stage/quarto_r/params.in.yaml | 0 .../templates/stage/quarto_r/src/.gitignore | 6 ++ .../src/{{ stage_name }}.qmd | 0 tests/conftest.py | 2 +- tests/test_create.py | 2 +- 28 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 .coverage rename src/dso/templates/stage/{quarto => quarto_ipynb}/.gitignore (100%) rename src/dso/templates/stage/{quarto => quarto_ipynb}/README.md (100%) create mode 100644 src/dso/templates/stage/quarto_ipynb/dvc.yaml rename src/dso/templates/stage/{quarto => quarto_ipynb}/params.in.yaml (100%) rename src/dso/templates/stage/{quarto => quarto_ipynb}/src/.gitignore (100%) create mode 100644 src/dso/templates/stage/quarto_ipynb/src/{{ stage_name }}.ipynb create mode 100644 src/dso/templates/stage/quarto_py/.gitignore create mode 100644 src/dso/templates/stage/quarto_py/README.md create mode 100644 src/dso/templates/stage/quarto_py/dvc.yaml rename src/dso/templates/stage/{quarto/input/.gitkeeptemplate => quarto_py/params.in.yaml} (100%) create mode 100644 src/dso/templates/stage/quarto_py/src/.gitignore create mode 100644 src/dso/templates/stage/quarto_py/src/{{ stage_name }}.qmd create mode 100644 src/dso/templates/stage/quarto_r/.gitignore create mode 100644 src/dso/templates/stage/quarto_r/README.md rename src/dso/templates/stage/{quarto => quarto_r}/dvc.yaml (100%) create mode 100644 src/dso/templates/stage/quarto_r/params.in.yaml create mode 100644 src/dso/templates/stage/quarto_r/src/.gitignore rename src/dso/templates/stage/{quarto => quarto_r}/src/{{ stage_name }}.qmd (100%) diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..0d22eb78e6d877d831e818e0317e6cbb1e910e49 GIT binary patch literal 282624 zcmeEv2b>$l_5X~t>SfQp+vjfMB3EqVc5c|lHtrZ>YzBHjGODiK$wKNj1h=i1M zBwkgT4y(CuXHsef8|dI?Fx0Uxj>f-dQZP~hf0b6N;1P*rB&H-AOKa4|k@$ryT3T&L z^B=%N)JRpFeWP?(_RoixCe=zcsm4QUioeCMNX2mX@aFAqN4HL$=xHjJNlAv_|DFR% z13zdh%EC%`P)JKwu(vNyD)CTQO^qy7@+Ayu@SY86UfQG<3#7HuXe5rsjHe>$h!!tZ z8`MxHtyUbgfFqgGavxA$VQJu58(D!i^1sYt6=9*t<>XLj2W^e|!k)u-_k=H>{N$ND|hHqR~>V5}OSB>r!4hz~;g> z6UZq;NwS7ks%5_jZ+b-8#$FcQp|m`zl^@78WK2qh1_FIS?rW8qc!)KX6e~kWt5cIo zl{z~6Tiz`kX(9o2#=7j?=Jh)ib@CJlj?Ig1y@%b=tyeER0o7Y+Jl~3z| z+K)k}&;GL>@XG8bZLhpYZ5&mnM4>lHD3K&IS?GiL2vEwtSfRj|m2xeUM*gyYB0bsI z)Aqjn0d4=z=^nl{9KR0DdzqF>MPOKE!&d5;+)qn~hLsfSg;GOH%QY>kDsetGz+Ws( z0cIpsitq6KQE6t|Gg6K08C7*d@ttym3+v`rL8HsHFA!oeC0>youh=lmp9+0HYn%*+ zcOvkIr9+`nrl5(oduHyT+267rEBE}-3D609YD}r%&7Dh~VUN29q)T1`h{ zYAO2)z6=tpUP+aPk}CWX#?s+Kt^bV%thRzsb&jeF2 zsK=DtYiIvyIe;YXe%Z#CrO@HRY^RVXOm_w9VE^O@taIZvSkASO`&M?Y;~wsVx1{p7 z1pZ(A6g5!PKv4rl4HPv{)Id=KMGX`+P}D$C14RuKHBi*R|2_>^sf9Y&`rjh|oyZ?U zQv4J(P}D$C14RuKHBi(*Q3FK{6g5!PKv4rl4HPv{)WH9n8t_`IedL^p#~7Jfdv(hi z0ZbZw^ymq0D3wKim&otRU;MvWz~WmMHBi(*Q3FK{6g5!PKv4rl4HPv{)Id=KMGX`+ zP}D$9172$%n%f1ixUIch*-Zc&e4&$k9{buP`CIuv@+b29@;~L>@~iR-^3(ET@`Lid z@?G*R^6%tp#Nye&@Y9Nu+s?|_B6_~B5;UqXds>x9cA&rLBNGwp1(gLIF)OcMW z8YvGX8q;AdK7RDraRG34R7WM0Pz|_lr2@$exY|SmjY=#Uh-(#U3cNv*g8(pM0w6fH zB(#*81kA)hz*J4ZWUiqaL#!JBh_xmlrb0?oNv6`QikNo$o2T8F8V3i%L}RQJFoPzP zHLb8BCi>>VpMzCuItYHdl@Zo!9@`0?*Wt%J zPf0}JIg2~ObNc+4=LB;uwD7b=9pGube$><2RJO1L9@gz}9+p;9Fw%96~3P3Wi~R7bqxV%nP`p zCIE?OrmCtj5M&WQ_#CIk190m^X%r^2zyX*DE2%K(wB8M1DZyY$3Wj|a`XG>0>yt2r z2H==Wpi+a`QZiq9n85>FtrOrx%{X#!F)a>`?f@EMs;zaH0Lj-TK~_+JOxOWZ)IuOv z%BWhUgjgvVV$3G68gp#})&Nm(%m=s{3E)JvjT~H9(`shPV zxGC}hv#@v5SWvwQr?7O~jv%CCcT9(L^p3uej@SVSIjUKKbZGNzNC!8ULOQ4!5;DNp z2x&iqeZQ~K9n#)nPwAtWV(Ee=2FB6aEr{}}1M+C5(C zB<=7A&~{NLIdq_6E~*-ISPJH|T)`c`@0BysEc_8IgM+d9i_(tEaN zoF6#t&MTZJxOTXvz>^O7Nl1E#3R3F9*8hW3k{&SwuweZ^s8-TdGcfb(|AFG76SbRL|M!nedeDrr^7VhIS(TYz|MxQsF~9!ro0Rmb0+mAR?G%;twH84QH8*s{ zlt>(UT5=lz9t}N%A{sEQCS#Gf!d6-2w*We9lcZ-vfx@0CxC1bEj_%IcMXkri-FJ2YM=BYp&c1$Z^*@i)R*dS|RQENukNqS7! zYc(b+Dg%I7p@vd{O-iDYy%MXDuK;??Hc8(q4En$tNu?X3ux*@ZtjhH*^nG_XGPqr9 zXtzfVFA1Ms|NTopaw9ted*eYhrd3CRNi`9LAc&wJHr#hf!*C`{Jyan^all9L_4MY1m#UA6BJm7uh{kLD{u(e(I9Sl*hCRP(-eK zqQ`m8CB5MlvLCtdP1w)mh@`I+rJH377jybC_PqdTewb%ei9}nNNQV~2VCKIJ*8eyt zS=bc0yU4jlZhh0XoU)NOybVOFmh{!43Y&tSJ`rHuJ!ARMMtXX6kgYO$ikz5-BaKR; zF{Bj|ywUe8sfPOsxcmdEpr%Zl{6kR(8u6y#>1>a z74|9>ifN8ta(Pf-I!4HPv{)Id=KMGX`+P}D$C14RuKHBi(*Q3FK{{4dmi)#`IG z|9_YKBrDw<@c;h;?g4mDeoOwF{IdMK{G@kI;Kt5{L z(bf+iYq64PWK6S%SS;Pk;HTrtPO?8YQ!XWao3j6(MrfCr@SBk{{p7M9Z+XFMf{;%} zg|@g{GvLRaXWYJfOp81n#M0?EzXFaFW1t*P?=<*9&uQggMMj8s`BWQq=>w*23seMd z3+!+GFQ0znAKvFF8`J$Qc*+>~pS7jw^=*|UO|{H_!^&0UOc1I181~3j$2>5!<}q*= z`OZf6Z-)oJ-MZ_;)|suXPrbegp{?Y*?bmGY(nN;dfPdS&rMr`~xLdCs``7MZ&Esf! zz){w;@zh@Im)0nOn=7rPiIB2BErjlE-TG0*s1d`u_nHEQnLOp+tzUlc#kWiL$?!}6 zzuT z$ys%-gm;=HOKfVXZZB46VVA-PV5=fQvf<#W}3_+<&9_6bbq z6FT-D5BV|UPny@2qfIHl_tg3B$CH|N&EK)cS^A#`x)Jd9Yan0j zx3E7acX}{miBYz3G-RjuElF6(8&5yAV`~|)R9#NSeGH{&YI1ZRX0Z^jURKsZ9nO+H z)-6q~^wU;)>g+?tR(xPP%ZEu$dlnO;jhpB({o36pEMfEl^DHh3*Eo< zt3986viq@T|CIi=*WGu~CipUZ_Q3a{#^A*syWLT81!cUHP@C6x z{5Unq<|Y;$UX4;qX;~9M^3Tr8_Rn~xRh~|UOn+hX+l^cPwNsPnupga3qvx!N@dSR&o3O{ohUB-Q4H5&uDM7S|(54wSE5wSGK;jeFoLl z5v=Nt8zD{ZKknPsz-x6E*7{HHyM5oTs;ADLws+Cd|9SG*$}hg^nTYjkeSi19J+$SV zTQ8v7|9*B=?|s1sUs;;k@YdgFN&Q}*L|&60J(_C=v{hEJ=hk1o-|zKjK7G`3R=2%h zf6$_|zTD*4+vkl0xhnog?+3R()CUyVZx(?s^>R;~aHvNNdtz^uV z=L}f(@O>TkegL%!t(CTH-M#%>gSXMLv+w@w%5VR8RMQ4{Nhc|TN(KS`YufW>x3VU+ zBWYS-VPge+N}5RTCQ{0nNq**7HU6au6UL7}wxp>)sH}{X?MwB6KP({~N}Vh4`z(2? z=T}6zxr}V#KRNxp=N--wq-+oMk(Mi&^By3jcHPf^%b?-I5kO$A0zRWhbsr1`A2)c_ z+U>h~S%^fM=#8ywTi-dk)zg0v{ATW;7cIjs+oiqyB9!pBlkC0s?*2Hquk{=K+t$_Z z#+?JA(t&_x})@i^(PF1zkmv34`Z~NysS!jaC?97XKWd@DC(TsM7E#p zSunuWX%OgdW7pnga|d;_4LYMsDZK8;(#~bKKQMCHDXnuz(-*t?dDac>2R~lcZ|>la z?tN^gwCsaB_HVCB?3?m(>nZOCPM-OXZ(9FWLiSkRu{h#=p;NL_TOud0)_8=pOS^ESdFvKtv+Qh+4E{*&&&s7yIc3~CSzXTM#+v>`_X=T zCe85QH?!m3dq05h-6xms4U_>RkQtVy$8Y<>JG5&bc(KuaIuohm`2HnM={wr=u-BS) z4D1a*U(oyEYsqshmZpVMtQPXd@ZEM&`cMg(wdz&ywRAq^o!AS$6z#Q2?FJ^KWb)%v zpsyjL@BYXl`I*-C7^#m^&rEse@>JrPdlG+tX5T$k&puVlx%0!V)wBb-^yT@h)^}+d zL~dPm|8MN~|9f@ItVYnob*JrwXOa7wnyw$T@rI+$EW2TqKA_3cGK-e7pF@e^g&=KW z;~p)Aq?EAFyUoP;>}Pu0$bdgB!<6Y4{z@X2Z(H}bF5Nei^%d8(mNh|pH2S@H(akRM z&H6@iX6x=|&^IBC!MzSR)B=Tdf=EGYi=xHl9dI zN*6XgQa;w=be8H)XA=}0eh!}!QreyU6F~WgsgcnBJwVTMdvqS^-ShsL_LA0_+23aW zstn$9Xm|L^GKh-O)U~k`_`0q2<4*>D-e&`8X`S>r`S~_)U&o%AW%YG|-}dfuVQY|lb;c-5m(K9dk)6N!`I{pt`FxZ1%9v!g&$O-`I>C^Dl#7Wo2IOX58{MR!zYdegbhLf!U)@Te%az^V82xAnp%2;eoOYy$)9xb4t9dx7W1(*|1<(qsr;wOR?=N|I^b&^p~JV# zwzFPKVl(6a+hFElNDbfM9#=(M*Do^}kInc}C_`po#9GcW13f8_Do_B^z7y~GfX zIiSS3ueQtgTFab0Kib!EY#{rKQXs_X_0whWD|*gCc3Q96Zrzw2+t@d5IBKC~ft5YJ zBwyt%9EdhqET3K}lc~&0z2GyKSVClPcUY^jAC?vTrW<$>!lRlu6)3vk*M|^2k1zG+ z)je{JojCXGv`UYG%lxe$f6}XrSiX|T&t7S*+#~O4+2iQb0>e`FLlqQ$R+0O`_j75- z781oDGdi^FZY}%@tMu%@p`GAkyJ!F10{?1pT-uM6wSZqgnM-H`#qTyva^&#CXJ@}W zdq*8evvv%EbVlg1?e&RG)SlDj3$$3GX+ukGe}99{F(eOi2U~o zto;8h|4F`2zDvGYzE-|UzDzz}K1<#qZnq3d|&uJ^1b8R<9pTj7vGbwVn&p!bj7JG?h~f8)Kvdx`gF-ZQ*S-gF(|BI(N)n z;a=xn;a=!2b5C-Qb`N&tolyTz_-D=z7xikn0}Tt*&cfujL}w*{){S zCReR1>V2Sj$<5S9m5>`990#+!>2~RN(pAzW(z((p(iSNtRZEI=qO?>xR+=tNkVZ%Yq#ja<+{yft-Gwhx87v^we=U)^Q~uCo2>QLxK*{DY+Y$R&N|CF*&478VU2=+ zoRY<5p=Z)Fxo`$OgA1qA)46aOJ&g;e(o?x`3O$7jJLnEBG}C4-7}Vf`PQm|(J-LZC zabY{%&V_As8yB|Htz6hbw{T%I-OPnebQ2dEX(JaJXag7OX+0O}XdM?aG{c27O>-ed zQ(Q>WBo}HaMCM`dlb{JMXjJ1uoW{8jqcJW-X_N~!w1x}Sw3-VM8sS2ihPhBhtGG}} zE4iRjl?xTLf(s!U;zBts=Ym2NE^MT*uwyS4q(Lrhpc}Zbp04M@$@F9{tfT9=a1uR< z3v20GE}TeDaxX_h$JpF5F4(n?jg8YIDKPNxu!e!(#E?i13<-#T85-wa!F6P2T^!QoKMc@!g=I8 zF8qxAj0-!-PA;5F&gH^6!A(oJr2)!WrZYE}TwI=fY{^G%lPn(VOdq}#V+wrv|`Teo7iWeaATH)FPG6K0K#m^CzD zR$q@Bh*>a**@g|6tzVDX$tPpBZXISPorKxiwV0iF zB4%sWV0OX@n5|xo*{W5Ttz3!OiWQhGUyj+bWtc5pirMkUW42@oW{VeNwrCM%#~p{+ z!iAVESb*95`IsGhEN1iOVK#RzW^?9XHhVT^vu0sdR)*QknV8L(f!Xxwm`$68+0?0+ z9dit3Q>I`xc`{~`CSi8;(U?t~h}nb*n2jHg*|>3-jU9{Gm@$|I0+@{+joGMCn2j8X z*@zLC9d#6D!-r!wY#3%khhjEl2xfx^V>W0IW&;OeHedi|{rh89T8de}ewg*`i&>vO znDy?BS+8E0_3VjRj~yb5Z) zHQ-ke^sWWZf+gPh;9D@&I}yAKhC@_^KHhHL4&Y&6^R$AG!DpTi!OP(9p4Y+8;91WT z;AwEb=MUg(aD(SJ;B9c3=K}CIIL)Jj$3e!UfzLt6vmU$-mU|X~-@#1J6!1J4m+nu%1L2?U-Qa`pg8OOkLU_=9FZdzc;{F|YBK*>Q3HTzM_XzMy=;!VMo(Vp;1AG&{b$tQe3Gcby0{?`U zUC)Du!XvI-;G=Md>n8A0xZ3p#@Kf07Is-fvwz}%USE0tGg15q2*GlkLnD3ee9t#s) z0q|KE=;{Mr3mse@@LOngehr=rA3EOw--XwmFM;>M6V5+@|H2=fw}A)4Z=6?x55on{ zbHIy1cWwqh2F)1(Plol*HQ>vz$T<(Z8KyYLgFnMiXMgZ$=;D;Yr@`vj2VM=IINk@p zhTV==!L#9M$7A5zaIfPo@NW2>;~Ma9xWsWDcsQKm*bY7pDMt*v92Cbo@N-z|SO}gD z(;bt**I|TXFnBxkaC8EH2Zw`#$HN!)kHP2RE&JcV>*0C(li>HT%YF}dKHOx#7JMIm zVZR8xAI`8hga1Rly%szmRC^G7AXeI!fEUCp`&96Q2-t^%Cqy56H}Hk<*lpkq@wM$U z@P~NE_IL1zc**uG_(c54c0YJU+-AE0{35QjT?U>J=h#jI--yk&40uOGY$5QESYulb z9uo6xGr>nK^~rVv^Hp08mV$25j%6w?|^t1*pW8pgB=(@IQLOe-)AVOox zbUmggW4aF0lQ3P2>4})G!Sn=7S7W*g)0LR6z;rpL%P?Jv>G7B@!E`aEi!eP7(}kEW zz;r&Q$6`7U)47<=!E`pJvoI~gbS9=VFrAL+G)$*rdJLvhFrAF)ButOSbRwn`FddKS zI84W4ItJ4KrlT<(h3QC4M__ssro%BEhUrjDhhRDw(?OUH#B>0r{V^@Yv>&E@G3|qC zZ%lh(+7r_rn0Cjs8>U?`?Sg4%OgmxP5z`Ksf;S@Y2i#C0MgBJ<|C^Ej&B*^|84o00#`$p2>Ke>3vG8ToG@{|)57f&4d+{|55kK>i!Ze*^h%ApZ^I zzk&QWkpBkq-$4Ew$bSR*Zy^5-i!Ze*^h%ApZ^Izk&QWkpBkq-$4Ew$bSR*Zy^5- zi!Ze*^h%ApZ^Izk&QWkpBkq-$4Ew$bSR*Zy^5-i!Ze*^h%ApZ^Izk&QWkpBkq z-$4Ew$bSR*Zy^5-&Sl{`L84Yb>zQ}{MV8HI`Usf{_Dtp9r>>#|8?ZQj{Mh=|2pztNB--`e;xU+ zBmZ^ezmELZk^egKUq}Ay$bTLAuOt6;&Sl{`L84Yb>zQ}{MV8H zI`Usf{_Dtp9r>>#|8?ZQj{Mh=|2pztNB--`e;xU+BmZ^ezmELZk^egKUq}Ay$bTLA zuOt6;&Sl{`L84Yb>zQ}{MV8HI`Usf{_Dtp9r>>#|8?ZQj{Mh= z|2pztNB--`e;xU+BmZ^ezmELZk^egKUq}Ay$baUI?z8I1e;xU+BmZ^ezmELZk^egK zUq}Ay$bTLAuOt6; zN4_K7k?lx!Q-O5`L`5*dkvL_Q)Nk&Q@3X##J0Un%nT-8|S5xaXbSiTkWMXi7Q^XqFYGpdG8l)2wW-n1dFHB1smRf;Km) z)U&ev6|TTuFPxHdv?$(!OI|hyF0Ao3uw3*t=Gb#GJw7db{0qfX?fU6(y`*a*>uy0s z<;0cgOnE!pD$%&}laca+;8u#(@%%_Ek?pRJ&9=tl(~=$$sbhvYKdDqi)Ob1vx#|u1=Q;hb&LFgH%OV=do$Ep&e$0=wcq5Xb%|@4jGNKD`mNG%|_DgJ0nH(+-6=w zq;i!~#pX8T8PPhOmuO$UjiMpvROBUu7R>yWeu2 ze2(L1jy_J0`*_#uuCQ&MTs>Y`s(cclhV~UhzeBRdfNCg(}+VEF&6nNuvGw zw^nrbxg?=hwJT;qcrhcPc92>|(rZLcZI*-5n7SZ*|2Df%4T`jt#40GI~cBm0JUQ!A9uo<0 z;t8w5nOOTB!)DP`Ju%UKnqUZrEN>5~*GT#rk;)CG8xxUu725%MQS?T7utH5F)sTWG zSL8Y2MJtcQm1H9;+FwNPBn5+!cqAPRGO#B_gR!YyZrkd4(VSfNy=Jh6#s3>jVnp64 zclZC!Kh5{FZ=LsDZwBuBJI7P%zRf+w^$b{YPjLjc6JZnG8t(Ix@VY-6636DDTM;j~=JrqcVl1e%h4y4kVWUMNw1`97_bKYHxAKq`_}MM@-ky~Wd_5s8y6I5EE zg(C4vjj6S_NrhzXQemg`iC!ilrnMS1&X`&Y7i*cKR%n&+I4+mtJpfWMp(ZowNR%lR zZn`pst4URXc|Ra(-2l;y5kyTUv2WG7ngkeP0~eGq*#!X27_thcImdSf%>IYNn^ZD{ z<8!b|O$S3-yfVUi&0{;k^E&*P=P8K@JZEu7cut=m^PFHzO)C{jT7jo6>Htsc^`oBF zHZxpU0uSqUI1fv!DVXUnT`>vXYoYw(9#v405kEX?&EdS&513#D>mtc?2F%ssb@0}8 zK7bN6=?GRtU~&kZOez?L`CXu(h%qnVikbi% z04BmpiW#oey8$dE7)(jQJT)EB;(?@EpM)ti0LNScl^V>J5(eTh%-{j87H$Ln{D!wf7^dq2YP>2E zXDy$t{|AvOBA+352EY5E;2l5H`-FD|+;$gtf9F2aJ>B)3OL2bTJk{CDajRpx{RMl( z_N{HFt&eo4G|T$3wZih5rODEn{+doD&%=Wb{s}LHa;+Am&SV5O6M~6Is0IoYULYJP zs%Z&8s+tc-D@B$G4Aj^JA$}|X37giV@}gQ*Fsa7*B)fVZ;H?!|uwW(FPsZ6wuy!tB z30r((+0=%FmP`jLwPXyJg4!H_6t;%okTI<~0u7DtLes)?wA&I{pL04cP+ zrNe5Bbs)86q6?Q+lQG!+jRtd&RWkunXu|_VvOyp*1Av5W3}G-=_T_1CedktwO(j5&w{b>J3JN8gfbF!$&lcFVzEf6bR#-r)J_2;p`BNSTB&5B z=^!F9HAW@_q^K1h4y4%15NeWWDBNVh$=%TaC2CQ}rw8#&G>XFxYh@DwPG~EGnO#al zj>IMiFB;4eV9OC!bWpUK@c<`kPR=#iwh6Lm9Dx0}9Tk{(z)Tdk+Q-7fgmtzBheH*a zSOVwxi7_T2Mz!qrWjp|g!e(*>WsE5i#)jl*z%yer5lsKIXdPcUjRH(jE2qLkJ~l{$ z#bF%g2T;`XNPvxr8qEq+3%e%~B^ud;sI?;iRoDnnfU3qK;3dimnmP&~YfLC;Iue7; zDJ90%I_cqNX%~+e%QcPdg=dBVsu@(`2b-19PT3?ZHPj>xbJz&Fk!FUNR8}@LrIVRZ z8qYWQ`u{E>Uo4M=7<|ipZ~5wd9`BXjaS(rQjr&9QR(D6&b*||UldT$ViNDw}+WwIJ zM2J*o*t$tKNYkxPSyx%!u+-4+=uX<7+;#Bf|4;nW>KN!s@c13g#PAp|8U-v-vt-yr zz=Q1oo*Dx6YH9#Y)bO20%O2mwssT*YtSb-3Hu7*V(jovSYTccOi@~Bh%J;VF!T>1h zh$0UdRU2SCG!Tp_iLCWiU6q-*ZPPKW(hLO`oW(>{02I|W_+kVOV$^at0)n)r9 zTYcMPG!g(N#dPBIUxNLP=F+)4_-$8Y&2uT@kjg7v2a^LYMn#r5qPn)j>cK zN{fV2QNh_}b3MZXrX0PEBMb}dzd-4@oBf3yAC0UbUtBUvu03~cW%$id; zQUzzuRbjq#3a=KeM3wEsL&>UF0g}*838wMsB(9QTD*;Q?G!92$h6Ni6*;C&Y04HjS zif~{KoYr7Bm+5i2Xg$VMC6!6C4yt;YXsncq(|v}uR5Vs~h8_2^4TI?MfF*R6#+Q_Q z%PG7B(1Z^Bu=!HOW;5DiKoYf{Kq3Z1Dr_3pM=H``Ji=Hcx@Zg!k&Y9M6s%7wtP6HK zw~*eXoJdWcI7IdDyBn(aHgblu#J9A+!2w~F+j%AvLuH@lLz%opkJlY`A0Q@g1tY;?Ihz$Oh!>drs!TOI+ z^vQjuum=rh;Se}$q)x7HgvN5PM)XrS$mGfiy)~HW29#tKa{>O>{HOA{Xo+ zSVa3*1>sO4do)I#GJ~~kdkAC~uvQhV(*q0u?FmU2<{+BmPjv>|;~LOdo!leRWi1C7 zR-*|{9o83IYepF>BMq$YVPi45T4b1oTp970Kdi(nz_yZs{=p2cf`4u6SPepfjskEA?kEC!Exf?p0b)ws2&X(I_22E2nk=&*;xz~&_5(2zr5@2M; z=HKK-(-5_I6n%eh5*d6X*A#ObR^-8-d{QNPw5wE=e7E)LCP~kTZeDFO(SkvpJZuK{ zp}GQDyLa*@ks%;*ya-0LKz#^TgTQ`zqZ#^Tn6QdR`$u%vz`@}0nIxLA(mrMkOK7MIvv3SmO?#VCPMCeOX+Kzf;?VRvh;mpfY-l>PHESoc7D?!)$lk z7DDv@DvbW$({iI_I(?d+Ox@(-pXQ{$R%gC?!t82bXE+#&g1%~%?x%3S@oSllC z7bHBh@QHDqdG;xX^TZ$Eju(zJDv8FB7HC`H#B}EWCu%D=52#f%Ml0AMUsPvKfTFe* zt0VDhWn6$8&#{?!jm~`kL~T81;qq?r37xtAi84scq6J~!D4vc~MsU_&tuqHeQO5>3 zeKLCm&}OyHoc;uZp|dM8g}M9*W=b*xszj%RgwEXk1lOICYK(`1=%tD!WbS@~O9*Z= zFdJZPA*PG;^~+KvYkkh};yQEo6V;bx@w5cgU)HiRsxyZ_!TPL=Knxk~=dUw|KT)R% z+48|b0@$j)Y%?GVZhqw4KP*% zG3sjpP*lW^m3S2z)RI<_HVo~6wM;r|txxuE zmh^g)${UG+wIlS>IqdI5?lZP4a%F_|oaEbWlD^fX;<5->;6u#3esZUp--z5YZ&%`S zg&)9uY9g`PhG4Q+9_UDcMNA$%i!4A639F)3X2i53w z#NUY3np5v086%GDt3(>q3a%ZXQx!Ybq7K-xH+me=*J>LFsC~PnZ#Vm83h-?vbe{Q0 zskEcWL-=gxnX}YqJqP(({2U621)W&Aie}Q(FEZ|Yu8dhOTTQ6Fn409_=V%9!wl&$3 z!9~}}M%*1{ZPj7|A{d;peJlvg$Pg)F8Sxt?bV=XSKwFnYUUy5^!~K6(F#rFf{4M^~zJL3+`Z{`lCzW|;dS3K|-TU1a zxQDqOa4mBF!`Wbc$yx>R{x(@8dM@osu5f(r$k_j5KgHg`cBO5^PrnEjdG{mp@W@&L za1jP~m=Lj^>|%3qV=&7>i^z*a8l8WyyvzWCmGDuK=I9r`(J9|5BaE!IL*q7M;0-pcxNSh?5 z^%G2sW78sSoYNg@}cK4Itz;{Dw1T*L5P{|!Cfu| zr>r$Pi;yeIVm*hOvrDYjSqNQG2A4UsY-rh(&Z6gvibI+MYad@Bu8WMI+rS)Uz~Mkk zfQ_AkSDdAE7D88aF_Ae1Did~%^%=(lm|VSV`4&Qk#j|v zDd(UM2nP_?S=?MjaA|Wcn6PH3*9QZjD3ixr8M90}AVx=AA7nyN>y>02_9?i(z(4>L zWn`HzYCgEtiy$$5;1IM7P$S!X$Gvu#4ThB3eCm*k!S|&i_FB$9f{WIodH*rzequO+aD8Z zdM5xDH6Mnq2gX=tna3|~VWVwI?+Az{G~xsLB4+>JkGxHs4u@giZ{KWv$M%&iBYh%8 zm+w2eMX*!V%DvXh^?^U7I$Agh{fF0MTpfgRX5Vr=*i>o!f`+@#ew@Zf4 zyf@&k9f5KMVpWBheRBlOPH3Ib!%w!4bD$>j?-8m=gS`#w=xGK#zYVMDx==D{4g6i0 z%@0iT@yr8fr$Sojftyze<>x5`>tE6u> zk6hW_E^9|gn~qGU4@WSO8Z{kGYMCl_Ejmp>uoS~%x*B+AlXo(tag$qFwl?Bweb&v9 zZa*?_z($=&C9}4s+l~k!bHm8)_<~;Dt1_;mF`akSe^=h1Q!q1Ip4-jU~cLDuT0* zSpNRMv*oV-tNmkqyL`*MyS*{be$P1&+y7>Fnd^DiM(01B8K=#0p<}T9HTyaCQrjI6 z|L+Zm0?=wb-#Wx{pJkba(DUg)lkWek(b;V{qK?&hsy9ylOYIJrhj_|_GO)B+(wnS%l;`BS5J zWTFf%uFnTJQ72oub9Z)&LpJ(o!H$k6p5nUKPzBPRsz==9k&5@<>9;diI z)dYyu3YEV#8LsZRnx(KeLruHQ-NM+2y+ zvv_tfBUq?o{Ae(v%p0lJ>JtG~RA5;p-pIf>b{^C1c#aGrYl&kutn908U)xTX=2%~{ zG+WCpoh*ClZykH+1o9|ZYwIiBC7&k`@&D1k!1tOj=H2f-&pXibd(UF`Kiu_hx9cj` zM6du@l(zs7c`jYW4jN%L5va^yAc+kk&u;Tz*_aJ3^eI-kx_99)X6Stfs<|q zxlDX>fI@~-XwskC`SdS0%)@ZMrN$M0kc30`=8N*m6|OnE8hsgJrF=aAH*GzV>-couwkf7mTW(D>PVgjA2N#jO*|AC+ur&@7R*k zchXrjE;oDs=vnHW>3+d|f^QnxO%&PbyUViD^A!EN)XjRmb&BP2c+9~+BJF)@Gq8^W zmm9&sDGPN0ca^}xQmId=QJCvOBe2Yc3+jwsh4Z0IGFAn)$?$DHAO0~G>j#5Rz$s2D z2zxET8nrQ)*1!}R>^OmfFU&+ZHqR&7zPhvmsj%=wjIQd7a1clS8uG< zw%uK688320T8PO!Oc-Y-h>Uw#2#DiIHiEuoqFK$Ou$$i{vKPp1DIXAUh1?0t{g6vg zgDgN)jI-z~(cV0%rp>d+aK5Gm00Eg}_h3l{&cj)umC=Q=+CJ94~*BPhCW`Oh($XYXvcOcfcy`d}{rMk&ml#WLG$ z;H*E7Wfm;)UK2da&bh=xK_`gx3Cm9E8<!3cX}szZuSgu-{GF>y3;k#c|O?w*W2H=ueUv8n=U;kg{&V~x4`Xx z=UKYat7!oK{0MxKI=lZ=lwk-TRB^c%${pweB{iMhgeuB{sU2vVjb}-n-I!`lF=3(v zMw0;AptI{zMHx&USWKltD_4V6(Z)oW&CSv}yD>E;Y~{cvgSl!gXbH7CyE;{r?M=HW zT6VK9rnB2qMVS|J%)+&2T4$H0idAiX8rrs*P_47eQ$?AO^J3<2#H-fX-Kk>1@|U>j zK0O8zfey=i<_GLM72Z@62rHXnN;&``B*5|s4)jBjL>N{y0VP_c!G(EYyuD5L=uvo~ zUV>WB4|<`3Mx|Tz8h9Pgk$9cL*O2vUc#VN3zD6P$iABk8t2;idTF$WMJ7*xtNxG*&cyi4gD z09KSycstk#cxNH1Zqe66m5bX-=M!Rf5#WEhC2x~{vcUT0b2xr8U*St+M})2VIso4; zh-`-fZ|mry`bmH<%B3oc-v(E$uLU?!Q&{G8rSGxnQ`&~<%Z#b)^v5wCi+Z_(;B+EmV z_TT>FHULB#J)|I(WTJ4~qC;T!UlF#Al~H19G|;HTqB(=m9*$}L_P_J<9Ty@c+Z z6_hX)QnHSKJ>ky8S~HXikWnScV*H>9=m0oRtuYUmI|L7fi|jS?Kr5pf`XdgLt|8qI zc8ny_K8d#<7LXN)MTeTj<@`m)-F=UeAAV1|$m6b5T@_9U59my~iPwG39buSRR8L3X zcE_}W2f@rBEocVSx!ry#9IMC7fJ>>#2u7b{Zj>WUL&eUkT+>+a*5QrBtlJjBDou-m zu??V(HmmP~eJX&3n=BD_lvy1|K3siYuqqH|6IL(?=I-AaY}ULYdj(IxES19WQ-PH@ z#w5{{E1@k$nsrH@$^ z8Ddj!0PJd3KZi#w?9wj`-!;UnE}fYofMWrx&OxyH`oN4qGjHY7+r(1lqSR(DLk8-q z2b%-`6c*k286I4x9ZzKqMQL}St|A;VTc1#!w5LcbKR%x?&!BnOaCZLRpCpKU2HgL5 znSY4ydf!Cv1KxR_Cp~N3@3=R+W!Fv@byhoeJC@k*wD-2%Y?~}SBCWN4Y}KuuEWfrK zO&_JJ$y@MnqN4s}cf{)9SQERqsKM^y5WN4^W{F;7u!}eZ7cRfNtuZ=?M~kURe&1)6 zQ37b9qSWz<;|9bLLk1*KArm=L&VV>!_yJ2)r;?>3<9{%!l&ev;! z1p8!{Nbo?~u&`6Ol|vW94eu5BAM#$XGsbMap?Y+`;er?IebX_S(S^9LNA6B8F8wR<@Qk!va`>?KUAW1v^HCP7F$?8B{zXEU#g3$eP60 z8w3!+ST&SX(%`X}f-}CK&e@d{Id9%~fR{;~z8#Q7-O|<$ISIbK;8zo6jx}k08vu*4 z1ZW2ggHkqxep25Guwrd;^P0}tpfu`R0JPqm>cuMypj*fmIH7L_Y_Supe1R)5fWa1h z6F_b?r??eLT7g+c!OiV)y%FHWF5#G|19K_C31wPu06?)+&e=V0QWBNSoC{hITmKIx zD~No)+~5C{f35FrU)a0XYj`_*?(+oQpSqjfon60k&2YZxj5zi?&UXy6-(jC&d(l=d zeJ-6T^|Ib0@hYc1@RMd5}3@E?dr5Y@Z z=u&}Y;*njd4Hi9Al<5bLY5}1%xNl&!!D5FB2Ln{#S=eB4Lj_h=TMU^RgGCG#wMfb< zF&nX_+F+qVg=>*Vtf@9wgix_y`6x|MV*-GQ+IGq7F&7@E$`}uDqP8YD9B*Yc#yCI{ zPLQninr4gzG*MH}yc!F(AFGTp!ZpdGh9!*vAc>j?@v?D~i-MqUNn^B0pa??(2%e z4NIv2vk5PJ_-bPSJp8b>LBId-0u9v|{o%Qy#>Wr@My?4|MK!pam+dmw7^T9|SiE(< z-pLsK08Klb3i$zkSGg+);OOF^>i6@mvN-2-3h1f}>4`7QL zrE}Q0xD2GUOcJ9|Cyd?zDr(E%K+x>1+AEA+06F|{>NeLN*c~nqM6RGQ#EqWtP*EEJ z`P1XJ)BhTy2LOs{ebEN6OD`y%+u|Vos7&Oa$^HDd`ltK;>^s@}fp?47?YY!5-2Dgl zajw^0nsdMNXU_hPI~@z`ui9&D|FIcVw%MgKEkCzjOiz(ISbJFfOmu=H6nvL72Zf0Ol0DXxy#_s5gN**5SH&12l6*B2Qx`# zDn(DV_8=FyECJmu8C^tKx)i?1K`H@UQK64kvfJmh%B-tevpT^`Qp=-S_Kx;TfTvr{ z)I>p>q?ID0krY-#VcC-yscN&x*fIx!&h2i~h{&)_2LT5AQgG1b;lQd*#xAVuu*gu0 zh2>@kMf_STs)>w2cmQVG$s(-~8IZXButs}`bSbNj#H*EYfx1X4!i_#jGepZu=j>mo@l&J4PtHEaNClgzRYtf@&w^$s%o{OV%7WS1 zCXoX~IMS#jU=dgl1e@#>$>TJDix;rnlJkf4huUjR< z@dG+&ol1uF2Ye6gD@QGaV7k$;8i@reQd-~#%$o{lqDi=*DHX)^9b5S;RY@hmf@#v9 ziwwVbs5gj4_{9>JnYQvTEI%kw$(n!AOLdE6*vzhhw#7E9f{V>s?iMN`%qC>?B9RTe zu=cYqn^bkUNO#z2`JR!U$a^vhUxe!*q`@T^dGjuM^>#_$evp^?Nv_E_1bRU?ORs?7 z5tlnL9S|KDuCrbm5U0 zBPw%u`Ceddr^rj6JD58Eh)fRg9cnY#>!E*Ua>vLuP&hf+DRM8SeIvkGX~L{S7!1$? z=iRV9$(Dok6tfOOa=_XB8HT;XtOLIsHb4Ag6~N$|&1z^l_(F;qrd2pQ^iJ}1Fe~-B z%>I8M`7MzzmPh!1@1N&;(H8>y|I@ww;0Ayh?p^M=t|wf_JKuCh!TSF!M-Tgr_Gz|f zZDHv@(&u;@-Eq}JGqkCyH?Ff$%^obZO+^8s|jmxc|9CMwe66PydOH$q1Z7Bf_o86nv9!2%X+ta9!kH3o|kD#~uA z4UStr*BC4&sCYD9Yf*!R1QoB!tO0GpI1%7P*>1I|vY-pBG1dsyCpLn-P5udhCeS7y zS^+e-;Ooz^P`Jsx;WUV3UBjG20}- zYzGiGW|;(-ZT3l{3;;!WG!(Xjg2o;;W&)@{XF2dUk5@+6_FaBaEyD3M=7h69>hd%`<&Lq`zi6 ztwY3Y*f?V?|4$-MN!y{aOXq{BOjQ+h#0>jMp$1#+!3!pY;G_f2To8{n83Qj(^csD{ z%yw5eIfa25jD=7i59@Zx@R`&L7rsM*%E7BJy2M1TzWTK2>i#$btt9t>zi zu3HReqvJWhYz>`sabn&OGzX^Z7iV z=kxSWVWUg6w-hMov_^r=nZw-@YNO;_)CO};x-1)Jpo+?Jn3`FUw-{WhmNY?htB`%b z$`F@p1Ti8wSLF3*1d;VXY$dkbTLg$X8t_+(@eD}^RdDiJGyvMFqgABhoBR7}Z^5}} zTChczn^BUdH17O!fkD)|10(M;prFObdlq{|5iN-d?@})1USU{ooWc{2f2Eg7}qJb228K*o?#>0JzHYOP}!v@}HoT)t)em8R&u zDO($b-V7D1RDsOg8fKJ+?O`hG|C`9M%HC+Nvh%jjjn)iRD64ZpP>_G%xq6{_9V zk)q=j(ZjCx!EC68Os7DPR>Q9L!N#cO7(|=FSmk3zN3~;ng$7|W7*)PF6kof&yD;z; z9nVT1^AM_5rytGt(Yr@78f+#lkq`btHC(DI1ZZW1quj?lh-$HcrgS}F6xb?mjgL7K z)vnhIgKoBgvf9Voi)!8bL^OO?`Ixs+ty^AL!&l;b@ILA_YA}C|uJ+a%-e7+?CDok$ zWj2VY8CUt>tyJ?aC~D|k;bSgLwOGl8hhDk(XniF0>THwU~HCU@O#T-4b|gm5+G^)ne?8fRF0&CEf=Qq33G%GGb{) zk^eW5E|LEe-`BC$VYc67?|@wZy;ZU_TFPSTVk*pM-~r%-X{E8=SZ1g*Eapu5kMz@o z9l~(#F5Sa)?N6@#C8OYVXe67nEW09YF%-hFkCGI1&*s-$@V^V^NKV1q=NzCKM!6)Z zji48wtfjnd6v2|3FRDB{|pfe_j1{y(A*qM`Kl zS-GL0sH}vI%Y2V>&Y0N+8JRL;c0X4gOmiE_^sp5y-%U#;nX^_8#iNV=6eOYuxMIph}YALNPtCc0KC>@%d z4A~H7{f99~FAcj?1p}sVm=QJv!1EeP%PZic41x2Un#Kj&@PGn6ET_+tmeSh_=#0XW zyfj5RDy<}Yc^NY-CwHE`HLru{HV|4NNCg`83c0Yh99Gk4(6ar958AS`AT?jExUH6_ zqbIeLS#N^`bcQ zmV9J@n0n`BUu?LVMV zQ&=doW1erQ+BB5?WwV0i`I6O!rFgBA8+8(3soJQc#FW=mu!5?J zft_feVX2p9{h2CXKaI}&qeN|GTUKE`Nk~2Q1qRyb=P9zzph>AL^u)$1tZNcgT-QX? zKZ*)yM)?_;*^zCiD&Kk9*F>}Q1*lNzO8^sUA%qY`gebjjUmt+iPW({jgXVS+Ltjug z$|mCh+%=9qHCmC!`sY$M z7I0sx=_tI-@*gWcEAT$j&unPt-od{+%O=fYT^cT$8Ox@gb53JQ#Q zJ8O7M7cMw6xmaA3&#IrdXlZpW3VsGmYRF3Le2n%4h?=qUW+Gla@0e{GT}f#L?8_w; zW)$GWD6=TPNG1XIwT2`JqY!mi${o~jb2`;tdhKKGTHPI=naeRh6!Cff&P zJ^k)zt7cNH;O(o?L22~R(=6grJd%%8`?TBryt(Wx?>sZS>mNZEJ zua1c^Z#MTcZ9}5=&`yDN3ba$8odWF?Xs5vcpDCc`ygAzaQj43r=$)AvMS_&3)>0xG zyyA6@n_etP*;>G3+NrY7Fm8%RkTSFY2|EDHXBanGGk_Vg9vL@LO@{%|l^D%AZZ%DZ zGoYJmYkttue7E4gZ^AYG*u1(9%O_a-ABf2|A21i1zA-H|9yP8q>J8T! z?D|{uHsL10p!34|-v-{ot)oVK{_DeXAG3U@miSnk;}+~yvh5d1?@Nd5i9;p%qaOqP zDGLP<#7R?85a&N262%Owe2Y*6YFWc*gF{xYqlOn&KZByp0^p#Q(fa?4LliA4ee<=eiWZgm2q&N_ z=4n?IQShTku*x@AyH*&{M2nmXl>4sMt`$arD;jtezN-LQEi*)IIWR9DnlUAjdN20P z0c^Fzh}*!1V3F+6v)Ff~c0eN@)5?8UXkWpKuHhQr=&%{!e+YmJGgWz^B8x!6zphVwD++5LdNts&-AXg)mV~QZo521`3_Ep+%HJ zH;kXRb!CaBG6lG3GzX8yrNxzHiElER$}(-p(d^7rS^sB|V}*l*bbq6*%BHjWtz_|A z^sxMQ%3N+bWhybAGL{%l8A|lu>X!($!hGGkx+(lC{4DN6ZXta}S^s(YztYb<1FEIv z)291xWpHP;4_*Pa8uk>(Q5?R~2bX|am3swL%i%v=k?Sb&F<*ch@lr{4MsX(7#w+zP zAAkkgaBz!JpDG`G|EXrWwGDekE!vuWqoY@69so7!)uS-@k)L?U=wn_0J8Dw}QJDPL zOFPV)!V#cq=1qUPS}^r*@zO5od~gS-nzyc>#-g>CcI@vlr+{kNS#N_zn?0W9$&lb< z9s$qICQp>zDGavEEucn&Z5v{Q?M_wrO3+nlG%uG;XQs)MAbHoBd~gPMj>;cikyZGZ zcR-EGAKq@2Z4k0uck;nepjPD%17DI~R+0qv?NGvq=77p2Q1Flzu^( zE>-&AM^LNE2%{3!Ay)X*^dQ)#GNLJ=G)A}()T%Ltfwxg{tMoBvf*NfSgi(lU3*|nz z6V&SHDGa{(=!v-x)VAbN3zSM9b0DY@cq~pb&;c`(LuD{^#CVVM!JnX3v!ZDIlqkLG zVqYd`pwZrc^Hj{>gPTFERt(W4XZPq4n$^c*Z0}G%@{w(!^{7>{cC_4Y85#3d%p&vm z=5^*CrpHZ_$!Gk)m}{svY&4``{eQPURj(8NCgj30z`MG2x}kh6e-od=9dJzMu6Nwe zrO@&Jyc?jrjgmHtx`i*s5^zUBPH}b;uv`kA$daTC1?jwBk6(*j zLfSM(kk0>AIcAi|-dCc@*khU?b@)Xb87X&$hbjDZyiAbde-(0RD?vH92bJBU&<8UF zsq?SGD~#x9bP%v%tTk=l01f5rz^p^zb-$v;e*|kmORUU zJ?&cBR)=MRH1`+LZpe!4!WBvRd5e><37K0|IDE*^VM!%?Nf{7fWy^2;z6U<3H0YSx?rEWfD8gYi8> zo@3GDMBECs22kjjV2XpOda0s4&KB@=o0>`)B`b2|^>R}4ejPw^acWYv8DyA68Nlw# z1u64CQFW0ZjsH*Ye{%gAncB82+?EvOXJr>hFWva**9y|u-za<7lFP|%mHSkt{~ymi zLB{>YxrQ$cxw=2=2J=I>C-}eUPw6-49l{@k^Bo%;UF{FsN7>%8U2gr@y3EpKx!H1F z%wsVl&Ci>sn%+01!TSGgXKBd4teaHV6<>uXYe|yqkcIJbafWPlDJe}cj*wOW=c7q! zOJD;nO|~)1xSTVq>rLzDV#H7}NgA4?0|l^xC`oFzg?E9PYM*WPsUyI%U^Blcht&f= zP(x!G5%8r&Mfr>2HjBYOUqf>(5%}SaVt&9mD0|e%$@gC=NXviG>hWhR&LU?aNk6uc zlY?&MT5aH>ii=?KtweQbXAw?b4rR(TjR2#Z9t@(Hs)LK-pCuZ)Tx%r>#Wks^X56OF zifr$5`?WN@6@8-j-?i*E!uMC{bUw9^j3o8m17qP8II`!WsY(F_6 z`&nI;Jb#D)EzM#OPij|8K!sxPk8IF8 zu^C#J!r@=WOg2?r2DXOUvMWi)e%UM*2QvQyI~8Qe?zjXsb?U=}jVjtcEQhaAeHaKI z0W8yGB$u~%!7cfk%vZwwT^g#7t&Rb=OjEcmby=zjb>;G+lqH(XABwYcvdfD+>@=iU zllf8e-px`?%EuO)IPH-=eQ3fqk?C~{yXG?a|K3!l`2Q=j1#NSzyRB0!TP;Ilw#E!K zKWQFi+HM+UeBLBf6GWvS}4~>M!&x%LH$vjZ$evVOzIGLC9 z{%%0!9N36xt{uh6ykzyq0TGRK+0I%$Edu}Ok|mwLEAX*sqiYa0UaHs=j&=@F;qLD2fca6UTplhVi9)=!mytl&d1bl5dKeEG7<#(X^Ra-g~4D8iH56IpKsl z;*+MzAEP3GjN3y4VX7ZkvZI%|uVtr>ySxtutn zZRD|CF^TgVfQm+ncG2XCQYgUkMh_%3Qf-MwqIt^L>~}%x;1_^P|8vMMKlZyI#rSnV zs@pk4Dym6U`g!eIw6X$(FhzDoZgvLSJznkS0A8a>i~>H2S7UT{Q#?P9Gt?M{^7DiW z!J(_sFEphZ{~goGxZ2p!aff4w{Z;z{+d*5U&1t>gI^6Px@U{67bBbxV<(inIF`_P+ zfAxRe0BDt7O@WSR_wr2R3-snksJnYDJI0j_fWTF4^Ntd2gT!g3YV+kNcf5rVKVn-- zYVPeSu47wvABX?w$OW6`^VOOjD$tppcOjDpzgTrx1=$%T&{+bk%OTM?SJiSc+50kf z7%*4=chYle?t3b9EG)~{4_%fHuzb9I0EtG?`P>XUJv|LzHTS>eU7*Fi%l& zDP+E&_QH-Drohhc<*IT@#$q;AU7&tjTUjh0E6!BC(@KL`sXW#fXQ*E&PoC_rdg&M%hFDsB8%@tsRo~`PjrdanVEza{`N`lf&P`$sBAp+7^^&w^F z%MP(GQGIH#xTqW@TBLf3U@R_&@%wBh{~xD2K@Q2Gx39BXY#VH5>sqVMvR-$>be^R{ z%$>#>V{gMv243$G>V)Mn-OTry<4t$BTEVwJv{Rs+0{`EkfQAymaGsJGWp|4orJ)K* zNiG(4nPt#mi5y$+0w%pw6O=u)oIA@VHBcU`VlSr`7r#}_Bgr28g@2e3?iM)zqBWQbZ7IahOMuS zEnx1LhDHCe7#nX_?Eh~d$7=gA`$}8LR%LCluC~-!JTb>(O3f!=|No$Aq4Dp=nTG9# zME#%iLxq4aQ}=;xK7W8O|ihvQ?4@i53HBKA$W1j{``xWcZ>% zD)WD4Ik2Fhh;6%6`Nu;3MXmj~vw>#5VZ!3uZ0~WEe+!ugFrf!aoWSHImM4v&t^^j|6PBY??;bZsZ;;RpP%8K-Ka&5doA@T)_-* z;sB|zlpTu|`bPk2h6WWI79U#f9}a+O`6-Pq<_dVI3)`pm4+Bh%gq>T~p%GSw%;`{c zSLagZw8)b!`|Qci%2WIoNp^oSaO$H{#VZ|0vjqBCWh~pc+gjsKLM3UW4$x9b&0QQQ zGDJIyv_ha|C#Tik669b910#*(V1ELm@EjA`Q-gquM%q(9flJgFxXOP4xJ9i2xDES8 zjLAd{`BeG`YS*7cfVb>wt?{3)T}z38k22&_;U56_8V$`6_+dU=C(i$GusSVITE@nF8k1)}Y2IM&YP#Pv#JIzFiQ!X2 zp@GxitnVQ_DvZ{>rn{04^10jz&dWKF$!{Dy{xmR&T6+SiGiD`C$tsyq0Go)Z5u=?R z|00z^re>D61$nK?AgBBoB=dN$CSfO+6}K*BnIBH>RqJS2T}~=nQha4;+2Yo4J$^X0 zSGA~<@;$9V7WtVId$sl&6pQ9CHj~t{KJ@tEwqDgjrWWS3E~LlL+|;YdLaCmD)*uV~ z%sG9UN-I9bLNh(tIjJ}&htW%njm!PaBfVNH{Rq6)Wi0YDPxNZ>4udJfyD}Ra4TYI( zCvd6%Nan8kiLk5_FolQjtjb6RmmR$g{t zX}F+;e&#P;t!>5Tb{Hc-31*xOg5vJj1KXs*?)ZjEWvV^8~NffRV-|;hFVy z+5bnH;tpq_AI{&U@xP?~{~XiYrGEHwSIymVq(sbJP%(4soW!7iJOEPjE4t@cj=Xtflfqj%Poy@8UX;*6Ee&?Sq1GFD?fehFQFhN#uq zz%#F8C21Lj6=`gLxwMG+)hW#@EMvp+3jZV!W4V^tD1+t-|3r-emqOtWC0^xs1F%{< zqGzQ)+7@%64d5026aZIiOYm&KQP)fIWQFuq{s|fvJTo^tbD5%Qz~uk!rgh}F-VtlR z-EOz7x7J&8ET36s$Gi}8zWE+Ad)Xe^DbP-Vb_%pppq&Ek6lkZwZ%zTpAb4$RiF;=j zS9nUHZGsbzilp3(RWS1a=fZgfd8K(P;2F}Bk(H&`?xrs!tKj`*Zc2Z~65zk!k(uYo zg~U%1vkJ}j%IIs!B6z!=BdSEO2_IY2L8*h_{bjCne>>7-=auFb$n^O}atPjE z=I-{lLn-Pom%cie2&E}C)=VPCK?fwG;B}lM4vMDC=bBRnK0%7JJun^`VdQ4Q$h>n{ zvI*WET2kgm2u0K9kfay9mUDtmG#cM(jz+V=!e})9t)`E&v-QH!z=LY4yR`zIU7nfk zVLN*=M}DcM;!!KO(WU)NIsbov95*_;*&nnIx9zmevc7L!XgO#pjtRxw7}MSSpgGy} zqG^WlL*rt@QNwD3Nq@V(zwo4xqT2;6fc?COYviuuy3hl^`LsaE(6g2qNK|X*nC->S zTioWT(X*CR206E&%~8&Be>Fg=d9*S&dvR*(<0Fs1O66kC$;oI7a*fI$uPiHU4YI^v z36N?DrZfJz(vt_bovopI{HxV2Xii>RkgHS%d3n)~Kvt*>GPNYDbt#Mec40l>_-r^s__4u;^SIvdWw8d@aCCmL;Dp%`N9M89AC67N-)vsed_ZHWatZE4T&}Izm~w|k6HzT)IM|XrTE=y z@$&UIH64Pat;j1bErUW<;R=+`t|p^Iv`Er!d%R&;Dd> zN=5#Ei+!jqV7uJ{xlA@%aAr0SLy6n<253IK{BgXWYW)O=C^O?0W z`iq(i$mTL;!rCZ<_L3HBfa0>kLRsjGUWW6^G_{u;5Q>LW9C_joh-{Ng(sRe~)H~^RVXH#THO4sTDu|Os3i?Yi3)pK&o z3fdYgU(2glnKIb6Mzz`ce-eF7j*sjg*>AKDu{&+MY%kmHw#8Y?t(n#tR$H}x`}HUN&HN zFt#cwE9r@(rqF)~@xxzjw78Sw_9K^M{L=-*PpXzU#pNRqp;IVi@{q7}49jxPm>vC> zy}=PR=&7k18Gjktc{r333hnx2l?+-(4b=}+cNVGtqw=>s192t_#DpFi`e9rqkuk8t z=oZu0^(3&GzgD)5m*W)4-X7okhgiiek@oK>^8ZYgm`^AjH zZk9CHVc$ zk3!do7J5lf3zx4y|EZo9qjk!0Vcv$`-}(-6Vy~X$JRS&~nQ&jA;!j4J@a$7YQAjla z;hF|~pG9@?EC2fJ>!((J`u1O+`0y{?NnFagP0j@u6Yu1b$zaPe?GFSFZ;`T6Mo!Sh zjYtoOCi0+;Tyz4I<58XHLy3BV8g{bo4Agzlo9f=#X{I?LqEkI+ot@5zM|4ya+@Y&? zUp}5pHSqu*swVm}SlxJRwYTeu6l8!nJCUfPH}MoO;`y`^jXQxRZrnJLrJ+DZV^jVK zPP|Po$NwNl;_|Qq`Qh(BgqkM2bP{J6!Dv1rw&!sCjv2n-VxM?B1s#+Q@)Dg9Gqn)+oZgc6I5A%@(^P&}@CL)Fe?yiQ0yKJk|EBKxCw@r@9grgaTA|&4-GqtQi!54 zZUE1dRdTxnoYCYA>MF$$_kGAXI*3vbJS54YT~3$gHe3% zfWgNls(i-u&!*6Xh9dzT=}+%SS!5))+y&69^-qemD>xL|Wlpe9x$3G5Z|A1Fl~STM zABjC$GD;sqyad!Zj(535fKVsJw&l`mDOdnLrrDi?Z)YLG(*4OL7cZ)s^@uNrYtZq8ACA7bK0w-l( zz^ZQM1;Xe)!_I_~_O1Bca{Gqf)r~uIc5NJ2cge_;Z%-@ne^(6#P|LxGIY zN20N=*QXw;DSXa)=*gFRfspYN35gjG5OIw+ALyU>_3zvdoAmUk?#?&*Pa5F7CFIF& zY}|MFqn$jrE`&sNz3Q7nW~IpNDu(~qJqhwvlxjok$I{+szdJnj&71O9$2Wd@#1S(P z#ON|`g!8sNAuMdWgtOu{<1u#xNBACZIl&l!fAK$z?r z*L!Q`8+IwJA0yU;e#amB)|KYpoENHfRQi_QyR+-~LuYi9yyeD()K_1KtviHTMQh~( zYig@+@+xiAy>a`oEoYt^C@un$CUT>aaf3fG_*qxCm>o;vbe@eB2u_iDisVAqK(xs? zXZQyrMhqW5)hYG?$=u{_Ea`<0oz%f)xOi6s7 zAFz36(MRv2gfkZyde+q*O=}FDmd=E(I#_5r4@qLr``xGdjtRIMkT6FO^}~dhuYYXb z6N@hvq^^BfGa1sS(=Ipznf7$o??U4~zFZ;~1q+vWQ8X&~WYTK~UraP59kFu_orrat z6xa?b?D%9y=QQtSx9+|AA@RaNS7OxUxN0-qsYk&CVeiZRHqREHavi$%>O_2j3S*fu zwi=z9lkrk@AEK^-!I$KlrifI%(K0>3+%XaKOYhRtJtZ+#pLkto7tkH#>g0ZM$Dq`; zp~)nk*corRrhh!5Q{$)fJ@Wh;DMIR@r<$sBJdGE96k7Xj(!!K4PKW;Gq#*nn8w-1* zVA8_g3jZ;rcV^8xe&TS&=|z7&=6>j#`2#`lx^Fp}F^APS3tMd&brk&A6HIxjpf=Q0 zOUa*9apeCvo{JBTnqYq+CARMQLrC|6!&R5$21m%8!HaJ`al+caOD`Zcq*o^rVu$x} znuG>UeATKeHJ;ZK@zZ<0`Vj32@ZyY%bUb}}eyxFAFFR@CoR2R8O?Fu??14o2J?3P0 zB^pkn-@FKY4Gr0Tgct0LYC&(wk&<^WI&e>k=iO&LpTFDqY|idoIWbP}knSj?e_?l4 z$fS!hzu&^u|8@GUc;Zeyv>u&yUB%Z4n>SFueoGc7^jo}yga+Qx>DACut^?iq(X=_& zb`}$9>zo(=WO(tLs{#`%K!=Cd-;BKI1yOt?G5yhj*SjB`BPED@U?S&Y@hCA6!c}A~ zn{(mfA{Gw%$h7;I)G{*2v2OXw=!>re;?IPdLYFnBu)gBqkXuB1^u~X7`(Mp;`q~P* zK2+-iy@@K)>WmO-1(ZXp*X*nP*V5qOKj>&z2adLf93w-zbne|5EQ|Dc$^s1g_%iR;r1be__!Q-5pl+v^R^P)hi1_$xQ?>>r0Dsc~p# zT`FAQ*Q(Ib@6J2kYY_!PqmI*ERo33dUN{dI%+ z&Ykc$sMG1YJ{!c*@l{28lZ(3^E9%mrBcc;KzI;t#KSmy)Z8F3n${rhI=)itEbm{2C z?*M1v+l$sYF!xLcXi7IY*h>fJwBt7cBLWMoi+6RjvE*zC(GpfTtcY}35yR0Q9nIo9 zT3D)<%1v+@COD;DF|6+x!{m>{Ax^ySi(9V$e&QmEA1-qD6wiEXyHRwYoKfM}SVa!40F4Xu8Ana-c-`n7ZZ5(lahtc+Ig35A1&|5S3XSUIvWi>}AFZG0+qAbq2Z7-*vY3HGyukl(AIK zTe+~L;UMaraSoFa$zsvr^OFp$*Am#w_`ikZHVMQTug~!MG9<329=VNSGgCQ)bngzo zIpz0Vn+9E46@2-!YXt^jOsf({lD7G+)45IEk2J;(O$xtofgv`m9Pj8!w1=mgbv4zx z^eCb7M+eT}r|Veu&gLo)D1bPT=fB_Lps^SxqQey8GpQ~PYc&?@j(XKqTEinN->N7= zN4@@uTg#i5S)0i{Xs&@w!JBo$8y(QOAN{U}oA`QxHth{92|9v-ps`l~!%{eK8S>4h ztVqOPmE0-pU=} zUgZAF-OX(TB1({!O9nk}_NCLh(<{-fjpnK_lCgpWH~}0aSGmiN8*v;iEJ%VF&wj&% zt;TH=TNB}e?*j5WqH4c!Tpd>Ate&0Ur?3xL@W|IXIgxUuO`x*iLi{9F1w>U0tjOkm z;(6aGQ$Q9SLO-ly**oK;cXAoTnRY&@_a)HI^`7P)kv$mEmbc+ALixP(n# z&Tz_+!E3Ic?iBOCTEnKMBw_-CtCCW_ddTFKZ>S{?<(UmYoPhfI!Vp7GAkNY&b>joS zd!SSD#=yLod70a%VC_ijwlY_IB4&^cJGpe1AsuL;_E85U4kfHgN%-7zY4N48Cb9>( z>}uBi%&cxoo6(nM(VcW`(OpCn87PyB!~nkgcT2^~*(hkaz(92;^a;`;nmEO)ubJ0{ z{Wh=^Y+C^V!=dw4m+OYW6j6|RRRNB7Ox4Se?n&8Qy{mr9ck^F%8|c%Kbzi%Oj%k=O z=4wn2t0tn~p+RroIrMI>`ee5W`=1(KZrCz@wITTNp+obz0f#KK*FtfgCoJ;}Z}+B8 zZvQ-C>)Iz?IkMHVUk`?@Ph()?1|+);RVR7zJ3jpd+PD^+v3LF*w`9-1qx04C?$Bo% z-c2`j+52+3F_{A5=6A?r*pi zrIRa=PTXV%C32I6IQMauj~^V8Xd1N|6!EO)o6=~*8=?!VI;R9sn5Y{!Ob|i4i7YL- zI8pu~rSBf^bj7T~hh0{^3ire6-J7xOpimz=5J!Vpc5zMvL zde7fJDENKPCt~jtaxeIM=$3=e^TSsnMefSyHcPM4o~s(S{OiP)Z?~L?r@F^U*xSG6 zBsYMuHwkZ!<977X4NKMy4^FzI-wJ$m>59`khb7*aD83QgDNx|eKNmf6>W)2!CrEP* zO+tO_3*CsfmLXmDvO1Z*DYjBP^(^H_V=V^8i7&yUyM&(}YWli%=W#uq-i`QFyxKGc z+%v%BEJlKaV!jUk-Q*xtE@vbvU(TmqLYxa*cWyTsu*-Ayu>0)MXOG?D6*-p)6=QNH z>zwX%05r*CZZb`AQd}(6JD^aBO-m2<19@8aYK^n9NXDj!-#)ifR=ELRAh;&EW3S^; z9WEESl^8^l0o6gb&6xV~hQvhNAwL!ZZtEoLL?`Y<_K20O{9}^$8#~GOL>paG!*_tI zgf1iwUS7zcFD_)mS54zbpfTIt-JNf>5J&DoCKBHab|dN`p2U`3dI-Z10vMSvdlfmd z?qQXngwwzjoXz;%UK)vv{IX;`MpayU6o3Gu3qDKHA=9)#TJ76tm)BdWFHdsT&4yAr zSS_F5THX23CH@y0I`((t%e|+tC44w^>Y2vIlp)KIV$m}GPHwlAbK#}n2H;MjGKJ<` ziR5xKSnF8VO?-@fDWmsNR_KFf(K*SShv!at{D2wG)Ld40SFXZYXRp!!DK>t14l>Wp z;p;zp%4{+L3m^e(L;%MFf|K0~E_Ms-@J1gnI+oxg*Al$XH8W;$XP|f+y>uymc_V_TReudzOOUJW#D00#%EhQ zhV!+HXNv5B)%W#Zoz6h2(a-?zL?DOfJvu$OLTWQ&zp2p6@`Q%E&Xdu9cxcUYX zk8abS4ClACR*1hEiQHEYnb?JP8?1{hqtAp=b~T}czzl~4-gy-gBwTgUcFTMWj)nmj z@qOkXX3Ctx-vt^PLT|XajVvk1X9&dUbj73Hy@~I7C6XjxX>ifo6Fz$UlKhWnEuMDA z1hKc@as^(*U2(^8(;gDyF2}>L%eU?A@sfTXjTS%9iT`RG64cc^pOMO_I4QM?OoKiS zrQECw8Z4>%89ty8(J}|^WZMIVy+_}vqPFl7g#@iN;hye?ysI*Sh<-K zk4$UGK0|va&^Cuy-ME5fGkXA~kFmO^fyF&0!z`q=&ocG61izy%Ss>I+Gz3h^alz0y z)*F=5wj+Z%=S;jzn7J>uNf1xXJguM4n`R&;c1CQFvrNZb-1M1Ldf&SaX~;B`-n($x z1Wa-^-_dw0P~+Svg%cdQv%vhqWaPOFfAgxTrl=7R_S)&05Q#gB4xb!;b?BSgRe@{2 z;Z}Z)Qi;U2hG`#;xf=FSL#j~C?Pxlg#x*?u`14IiEH&}9wR%(?r5eY*K(4w=Kwh4L z^kr!1XP6?O8H!^FQzX-#&qDiNtld^yRrbu^9Q5Jgqk0ku?^xhEOa=CdQy+Y@sk*Ut z=k6D|blz|=qU;yXbWFjoYf5A*o8o*kC!=udJ583SdH+*4+@ARV7zK1}{Xdc(BF7=e zwT=N>X_)bV@gIh- z4DT7{8OG_4>H7(%h4+MKg+B=^g*@R(p`Xx2_lj;9|0chjPv$#t61S9F$n~Oc=>-7$ z-$Sf44hz>rd>syRRtWqcX)Ge=(ep|iA6Sl#w>e-*$&L+N0qc;GU;;V&Bw^!nU9bG)L3l`Y7>q>e$^7OX*h~2^`ocQBkQ&Ct`kQioI$}5 zxDfP5gnJ8p`MvUC9M7OvqYJ!;JX~iyMMC<}sX!=*$GGiWjx>yAJByx-yymf!M(N6v zIOnRrO@Hows*!P^>9KWnY~1F?AzP6gHL=TIGR1|IwBak4a^$84&Luwu(mI*YnF0_| zrDT(avI>inw;km7KYeMCXALCiHn<+g-q0s+U3x^noajy+dT8)O!%-aO?F?OD5an6u zhL=(1u1^i4lRO~NHKE$0+@`Tb(%6T`&TxpME(?yH{4pm!KP55{LhQris!NrUSDE4eG|HQ_gP184yINDi)-ISSrslaf%&-RW^TPT&SgL-0I@ z{u)jd{tu|^%33FN5?PjAPq$71bReH<$Pg6^5+veOXnkQApN=Zm!^Kw0L0IthY>&h{-wBj z0@JuB9mx|%FRr+dhI99`ng@B#m--{&6>@hJ*&USm(M4{BP2_Z_besmvkotkfJ|{gG zj$}XB_d9Da?s;_N%flJJ>^ajEZyJ+61*}F5XbtXvAktb#xtGwJzQcz`Sp!Bi!l66_ z94I(>@i)_{`l>!h9xDI*!PhQPXdeL(+!EOujl}%)Z?MFrH2bq9`OrR9>dW{ghW^z0 z{rJW$oWicr@y^!GB81Hz6o!S--K0cNa2Wj&G$xum`KCr`CsD@dD7kZmbRGk;^sHWC zayAZ)l@fqdBHb^) zRW5>*EA?UZcPafLDw^F2)ae5e^|)tsiv8qzqj-2HTI66k(YSJsa;J;rV$DciA&>TIl}$@$oY`>3Pop-wlG*c95aZrK+i zpUhy_ZSgUF4ovv)o)HJ*Dfo&mR&vP%sM+>|yr0Ulnmk>KXVqb+E$k5?IDVczdH-uS zDPWH*`Qc6U@SJlUq+3k?(ovnkDNb8bvI>+DCi6Q!cpwnY*WkE6wXPN%zM*tm*;PVP5PA9r#iA6i|4-6M~&Ov>q+^gUlZurXyE8@`nAgnqOMBc&3=ZFxX9(308Q zJ35P#<=w~h1W_q5OWEDarbx{}3}eyEe|S^(+KHW#L1t=^+zZ$%_a%WNL-ukDbmW?G z#T@{${bv13&6%*9t!uw~&;N(KfBsN;o8L@9n~qjba{Wmk*xj}Xx>&~7bN@iaI0J5? z2S}LKNV_RPd)S6GYSQXz|-mAP)JZU2Mfa&J154@QV%fk zK)QR?-Mjl#-k$YjZBO@~z8<9OE_Fxz2)b)2udF_jLZOC_tZsIs=s}hi1%3NcO9iJNZ60=*k)d_hPExFgI)DvpV3lh#CquV9eX>zNz07bl5kQ@3hy>M zztQblV!RZi`5@P0Rgm>Dyu3i4ymgy?8-1m>`pIsVI^ok;`rWXt9etNc9YM17J?XZl zq-Gi@H}E-cYT(<+dYQCM)H zdF>!kp|&W?$+0{{on23ReB-(&$M!eI*Pncd0w-Q=n)^O`rv$MBr4uDYT3)|MJp1*8 z9~eGv!?L&TdH3}VWw^(zK@QIOM>b&$}mV*zO*(+;^xbi2XU=y#;sX+Ymm7$ z0)?msg<$J?gaB(-MCa25@~@n&atCDMKqYq+Bgvn!!4^k0q1N&`*>TsKZn9G4yA$2PDO2W2Hr4=# z(2ZY&xfZd3$4NK2=TPBRV4-qcS4gFsww1VMWfO>%B+$3Y}ZGL7^w)g0~zMho;mq4p1^@KU-#mH)(LX{T4O@JlbXSV|vcs?6SNZm+HKzxEJNf-* zde8m33pe1;j@+ajOPpJ$NWA-VbB+=Xt?o z>Ld8Ut-Oho@sKQ%iIJ@nZ8&`-bPb3jx?S}7&SB|;I`lVE%~1#B{+!s~-DnEPb9y%| zKdp%NGM(QOFHU~I6W6M!`J2?`e|9`tZ%bsd$ zvhBA0#kR?oYU^M<#Eivn3E{z!%Gt~UKeAfRL^Npr&OwXG78XJvAjh`Cd zHEuILYTRPH-FSmB&zNd-8%G)k8oNUm;C;i>hDQuFhU*L?3<>&>ezU$ez_o{V3ba$8 zodW;IC}5LH&_i~oW2YOAZTX?WTrL%}@uiTy2cq>wJ#!aOqFX1TuMTkHVf_xNy6n(I zG8&eTce>s7pl*k-=lGMpmp>iM@l&SoU%q#==;kjSd&Y7Nw@zDe@Lu}l|0Ku@9X_`t?BP4`H<*<6$~pfj^Z&VwB_?pQ_c*pTvvTERB`gqmZzZm)2)6dS9SE%Csm(dq{o0DUdXOv z&+M*y3ZJmQ>XEPHgpNT3qsb+CP+&LJp?scfGKt2&Q{(5MjQFO{KYwLHW!z~a=a7n! zq&FSqhu^t*^GktU!WB{>LoI=hu&+Y88q-L2&X^qhJq44vaz5CfL?a(;G*ebb3f^?= z4}IR2C@xdzpWwoHDac!2B0j(;iJvc-`o)n0+fH`xBozS606JU~$bKPE-Ysc=_6ycU z2BVaZXgeKp8Kq_N-M6k@(o)=wp>Jwt+-m*n#-ttP-FBCMg}>K_4+(7iJ=b5#!~09= z>zbR!S;v*v1t$iBWKSPDKOoTCi=Vu6P`?|@k7GhKoa-j#BIPhTSaYxMrQ~2Rpv!d7 zQGM`52>#im9K7pJ2Wq_QUwO%n0x!XHEPYjDG8v_8+}r8joK4D-Q+-)8bKU066>(jp zOgs;w{WT8X7N_aX-D3wkLo0cj6)!EuiwX2aO|Q{b-cI$RjwVogVi&Kt@zqJ2FatJ9 z8FHqdb4Dp$z6;ivr8L~dQf-Y(XOb4--btU;@SUY=aXXOy1sd+T{r2mUIUH#B@jETj zLd18WPZ6KK*eP9uCl`IfQc)*d1&g#mPOy(}s9ntWmFDAVCVhN*-_7Dd(LFPGo@*wi zXbm?bEfbG$u_+4)l2e+;<}tl#FUxADWkUb;SiE7c!%gxLlMaQ+Z%q6wF364Ns4veo zBApz<@;p$5ijPFm9$8C?JqBI~J%o6Z$W{q_I!;rKP7^h7;iL>2f}4Oyo8THE%?0iY z=_5>RySbn1&p|dw4mwIQ#eD}ZZxf_=>1tMpar7Zex8}ffE{Rre+VTVs8Lc|ssE6Zw z)}+)p4z8b|+*%Hu zYpLe7YA~7DCDbzYM>%$Lks)Ivf})2hdf`? zI4d;PCe6Y7?)3gD?vF$1twghQC7xsHp9_`@>nvS?`+@Wi68lbtXq@!Z_yuwF5AvxB0<*n+x%ib5D38~UwfOR zRKRi4o`FXl(q*{qO}j}Pa%SC^q!+ z9KQU^eGizd3DT{p9>{zRseb19=g&wp+$gP>+zZ_0CP=cmoN?4a1ONoQakI6wiH=Lp z(s8*i+}$@JCUSxx;+~_eTzVqaRN-C;LJfZH@?pzF++lAlz@d$R0bF=w+2W{!-7%R# zc3=SN*@^QYB8b0L_#?Nw`}Cfdm$F+FCSCpkC>Aib%)!b)Xp-m1qm@_eT4SVx(F`N9 z1dx%73P1!$MSofrKhtqyHyS4vRt&rtS?#f;(On~H zA7p4vN&;~xiV+FC$rTFqxY89w3Q<_M()vO5QQZJhC(@-vE&z2SWqP+jN4m&mghpIH zHLx|IPQ;&j^CiczKzJE?Qywj~JM#7$1YD9r*x*=bj&4$>vKOQ5%T zTFcIrkd3>8G*gcI`|0M*@$~-E48&bZZ=GItNA|yJbos&g49yE4%doxO-C*nS{4;+a zOXkxbT&wRWO-IUp^d`$pWGE#E#IEC{X^1VSH&`s;oJ9HkZ&yBDuKM)x(o}rDie7L2 zz<&{BhuPC4w$P3aqC4?A*PrQNbt)e?451b56{dEVF2?sG=(XsC?7pYIhKrY`;N=8* zwarV1n-le=l8v}Q(qyEVN3XO=akfX7kH1Ws#5#wb^m23pQFOe1_xF%E4DDD>&+N4Z zcc1e0WAtg@`k*zQsHP6}51>&+wxS?DkdsnJp=p=zw{(yu0)Yg2NzQO9*~J)$DZ3H3 zkOC}D5ILv7ZV;@V3*0pU6x?l~zKac$a%vcA&#` zFCF+-$K9ivuGTdgmGdI&m)uBjoO>`T8Fbu`MJ#{hPK}6+1uMdL+Y;p zofroNPQ{D(#fDjIByr$z*YA?OPD@e5LO4V53Vn z&X8=J-qckmjALVyiz^~?g6S0W_+K$?Hm$`vUNoi|#~PE3T?{`M#^~=8W`Thl1-rWy?sGr> zP16LngAAd11h>`8b}HjI);3&LeuS58Qs#0_uhDY~+Fj&k!mf3)4hB|8_}|S%c5Fo@ z@3rpQ_D=q`0!x=cdzaX}Y}2wk=UA|OcMYf04e+w9%T!KQPejf&I+VgK&=dw!DNsG` zCLrs6UK^6m;%t15E*%2z0vj)skwRj3^5B81X@Qq*P)fr%w(aRUG^*Yxkb#}hKIuXP zx#iL_G6ocJJdq2cJ)w#8O<@9hhm2IWK4nmV41gRAcWfBipDRReTo*6fa2&*0o;%&H=23lUFP&&j!_G&y*I>tN!AxISLCTR4d`Gh+pj5N$|d z_a|IeuL)^}aHf41QI%2^az27?n3wI@WpTz;TR1TV2cMWOw+`rP5E>$pF0_7=*MN_l zoWY>)<7GM}lQ_Ni#4fqOPLUcK6>0>*3nbPWr+NiOyBJP5LPmLJL-C=|`cP=U@_!mm^4}yA!aA;>#&j)DhdJu}lK8iRh%SKfAB~Bg{Sww)Hej+p{sgxga zsgqN)YlzZW1t(0Tn zL8bY~+trPB*#lHV?nRVqTQi!rODvc06c{v- z$?c{+jHIXsR$Mp!D9A1>Y{lQ55R*VKkk}tpft4ok35Pfu5x^~4{~lv->_>sdb)Ua4 zzvLM2#`R2R^F<<;T+x(#i_qOmXc!~pG_HC5ATjV3s#poGu2MB#4x!Lpoab-+o9`e5 zth?~Pmr1H(O^cewIQmFySkt1$ldp!F{vHaw9g+_?=okfbCaagqgE~WRsS;_%$<1?X zsyuIX0frlYtcc|5DXm6=(RAkTWha3mLHghj>LU)7k__D=X|c2lMD|T0mN%rb2YwCarEK}ujbq1PF=Bed%H65XCp7JcNP_=91xh^MBpqqxAptte&hQ;kLs#Vz_W zP1IQfSDNd`qT}%7Oy}t$P)Nbt!%!001*>q57U>wzPN<>$&%f*OnQXrUNGIp~VGHA# z8pjjWk0axQTzdV}NOn4Yv|FYoV}`o^Rr?S8yZY!B?+(b%Kq_eH>v8Gnfw%yP(3)pK zhnirqnO1|fgH!<`B+w7fJ=XuNp*j8bUsO1}zf_L6OQ~LNbMhx=zqtBKE9I1@n(OcE z3CU@cAT@~9#7TaDREE1$I^p_>w9V1njSHkwRKeZDBFm`gemv5jxBs?Npq&Ek6lkYF zI|a0&z_HMortiwf$#PI{>_02i2E43pJQX?+s%7t+K9#q7L+t2C4hIFc{=XQi&h{(q zL+yR+U2UJ)-nZRh+lX`jzgT~7m8@f}=Ud~goh@Hk_FCStthHoVrdm43?2FkGQxKCG zGdE^d%*2>(F(z}Zd6hZSJlXV|=|R(NrUFx{@jl~n!*SRGeAaM{VYdDQ;d|kF>?52f zbkj}OCG&^)5BRtEyLcGq;$Gpla<_3lt{kGIcPb;V**gydbSyV7Rpg{p?_4$s>dnn{ zH?EAI;AUD?sUpOq{;{Bn+-VpnGr9%WrA__!5Ph>nkI5t^v2M&gMH#xlrd56_;_z4}Zw<$hOP;YA z@S-^=o5szL>}D^Uzuxpos5vsc-x`s=ljm6?&h+GlXSzB4)Ng1s^%+A@qkHd|Fpn+Dny?LbGUJCB z@}0-_wlmMCVI*)o?BC zS!c(hpLE~G2e_VtyzF#g9(S4Zxy!ki2E7?%C-nEJlS>7!{T+?#ja_3ZTd*erD2>FLi_OZIaS}jf& z__}wX>-6H1_h)eNA zv!gLXX2d;NQlnsOy7qd;XGdUXyka*A`r(seCs>C2&;!-l2U18>y|zFqFBY!S9Bp;w zcd9+@8o5#|QH2;5FbJ84I}72e#2@4vIl=7bt4`!UXArsP*KXW0Ey5o#68Y)JjLMu` z?cEO@INl8n8Ao0#mS&FO)(P10^a}qSRk?A?klQLJ#=p+0l5vK!XWzaThR=AX;y-Tv z&aEfp@h6VQw zE|D53AGI8A;m3s*v~vVJ7!?>~^59clptPkJBXXZ|FNyU^1lNOWQtw!;SR}y%)*dmg zHblUs{hE~PC30+c#qoH>@#2OS|Ijdq=0#q6T715^)B>z>@LgIu=#ujW^p;?l{p0XD zSxmtY;j{QBh$I>*1Z&?y3qLQ+qMagF4k#okIqBx?ALGu-x@Jr*B*8qTR{pe?8qppO zGAvs1?5|Kj^T(6R0TQ`Q4#Cip(Z&xy9^QRN3fQpx4{{#Vi{0>(|1y|Kqwpl zn^^qIgEfqHh)@Dw-6HV75DNlM!U2tFR`n9fpI2Du1(DC5kd4{}WKk0@S$MLTk&<%? z*e*-rBX)nZCb;&;VzyX77uIdf8oU7bkPEk01M1#KTG?@EmK zJ<+km9U~K;bWdc_I<+i5V6Pi(2Ny$>*wayn6&o!DcFEaemZ)S&aGbhiEmU!QoL-o= zjXqu|1LvVY5-dItFO#+jzuD8A&8^WTvgxvNdD$p5H)@|HqJ(HJX`^ zH6ClVrGpP6*EYbIXCV|U3oCa2NzAAW=iXk zx8I#ov>j zY7bXv6N`^G8$laHGYZMK&(EBlbWe73dqb#a%UMrH3zw;lnx zq>xn~cF3mn?_&-jJ-|BwPKVzls$^L8U{hyWZ+adnEX`<^sD$f5odd~Pv0??(i-DC& zSF0{B7lqb!Cntr&C0YDBSsu?6A#!kq(%CUq7^IM}`M%ikpO-;Mkn9LvKd`ZWW+np_ zp`|{>ssq0jq;)Q;eycXXWLmp)ee=^Z8(Dm$))1P7C&rIUNCT*k_DT`LIuZ)zJ}lbs zUGQA5fkLbW*)>{=c`QDfN~4)nw=w{w(G0$Cwh=6Gcd^3!tYsSJt9U9R;c^!#-QXJo zB!-$w;T71~forop(P*f2Pnnc-LR2O1zTMPM)8d4D@2g^^!*T0S@uF9?`6GxCWL2y* zT+7=jP@U$ML*ybSm|@j~wVh!cF|Vjdq%EAbdPkM0CI!DgFvECjA z|9VD)RNm{$Cg-V~5A-2@Nhl0MB@#Er!5;c36dgIz5Juh?N?9Zd?=`6QP!>}oeQY5l zcxxA5{k{?;aTm|>cZ!iyi`~&NKS*b5!!7@M^}2K;vN~xMet$iGJ5lS&`~@2%Z$1nM zZisP4cgA)!(8Ul>I&J{DH%3LNSH)P zeEheqBt<$g36?|T&1_!pNxZ)GdmF&gMzt`TsxbG_^k{n#>|I$lZLs!US@c}X#t;PZt9|2RH zChtxmmmj^Xr(0EFxg(6k-525%558PV4TU6t2R!)zZVFNC`c@L$f#ro1UReBVgwd%S z`Uz0aJs7V7yttAR+CGG|hwogQ*ZG$uhoTYbK^hB1BH#@V7rEqxw>o|WV-eE+SaNbS zKOn0~Vo-_3;NutN{xO8WkO59u1OBe2IRO6QAA=i=i&wXET`m^*G0}Sl9d-B+H%QrJ zYgKYjA>1E)HuWiQ7cGxoejWA0$(4t({+GEQ^?RRP=u;>Ir*r{R3Bwp5HFGCAVm z_5Bz@A-aaHBwjY6VtMqUxtvpNE2Be1XK)nAy8y-Hroi1yKv=6nqfnNh#0=ET5 zs>jvUs-yN*yQ*!}rV#!AwEtKC_x_#!7yKLibNxg8ZT%VkWWURI)OW!5iLcD}s_zNk zgT4~qGT%bq6yGRcKVK(bjxW;}^vT|{-oxJSy)Sq-c<%x`!Oh;Nx0Sb{H_e;im6g*l zlHhA)i}H-}h_XsqqRdn#Dnpe%N;9R7qIrJz{NUN)cCS zWv*9UkGgugnu2BF3wf)&NnS5|q!ZG|QcQY9dYT=gKhQGzB7KbBMd#5dja0s4;EMl; zQ<}}Yd+q6mEH;c~7p(G-)M&|UvNK162guA@E!DKS3sPIUn?ZlKVKB9vNLt;);`k9V zHb2Sc-KctW*SiTHKr~a_0L|ZOHt$n4p&wWctB%_U0r_Ef5{7$KMYnk$DviEBi?m}W z2)Sp0Vsn?GAl>OUHJf_}rPB9iwS1Vr-lC~C_Xx_RJEqGtM2a3$)evtTQTRj#2a8$M z?gEdZL+JK{(8=fok%xb2zK}q`TVQU<%pkmaFrAJA888JowRsAoftM? z`1D7hKIUaW`DPh5T}@%a4Kqh*gu!u01Xsg4cnYSXb@6Pk z-RVE@HE$%iUD(vd#`@OR2JPP+a@)PuCLz77Cxdz77egD!QEC|`WEuT$ahdX9G9J#B7xxKjJ z)bTxK8$A7NY|n@3Yk%b@mqQ0?os=Hlw$7CgedM(Mm0K*w6AY8{$M+|d2=ioo26DKOpb$YWn?a1Hlr%$|THt#&Nr!Qj`Zkb5v zX#W{s*~SQ+_Zac-CBMzP6v=cW&v3bp&3hHS=}VQ_;exT975-}(fIHqg+}~~jrDA5$ z7x|VL7k{U6K{zE;P6~vDC6>;&3jB9IxW!i!+@sxdtOT0}w#cL}{Jr|TX7m0=Dt(?r z_`7tzRL$nyjwbXuSPC<8uy^iucuN>y7^rIVUPS}??8WBLE{SO3C{``6%{vc?^qJj* zXtvFJ3sL$s+y6}tWH=2DN2&0sUF6M%HzB+rmQ+^rrMfXY_i&0`7j|hzpL(|GswevD^A15WeUjbqNgH>%&HDr$=@V1tG0Y^6`nQy;+Pt68fIiO1&3T0b z@6AVc5(w+bI|PaJvHR+~Qf%HOXht`D`^evW3e-ulc_$%A*MH{n*Nal@r_l!oeew`&obnQ@Zu4et3;MvTMW2)MUDf$H(5OEQlkY^CZu6FJ8eKc!Y%{!8 zm&X=O+WRvDwrJAc_v-D(M}NPD`fT2$O``X1nDF6vpPhsY_w3vB1Z?5%dP(%|0dsr6 zMI^#Pkggfjs;iR(!=_kycOSHIpg<6oIa}&Arot^tJ{}wY>mCbme9k z8BEIkwgQXEbj4=qv{+u-151hYR<_rp+it*Vbos)2;h<1*y;YlgkcH^7%yn|ji_~w+ zu$WApU+ylIT)Hh`cAK5*Q7UyHs^PO4tVyEQF!%X%uT5bgk(#?LC18VP1v(Oj0_SVY zXsB4+$0kUNKXEJ8QiMzIlRXx9s?jLefh_Ji6QqmhFx6TFFhm#KICx3Cj4IYb+_LcD zuxc&9EejH3PtGiLY1VvLOr`Ui-Hb(|DAqj8I&V&ukTn-zHl2GPe^CEUu`^7wZo%Dd z8F1g-t~Nd1$yTg6xZ9jB5|gdj02|TS_uwwVZI_Y#kEL3(U_&mQwa{z7v329kHKwg{ ztq3NN6_?Fb@1P;F#1vc^&&GcB4ao5T4y=4-hL^>(c4>xThuAR8B znKc2>csgNo{L%E`kZ$=b19>q^p2wVzk8i^LW;O6XFD zylEFV_P;!tjN5zX=>toCXg;XpiI0lU-8HK5%spQ(rc931D6i;Wy0fA-YhaCm3mZVk zVCnrWu2jDJ|6T)kx``Eq%p+)2tj)M~<3DkgyV5A#8*6Bdh8+gc(S&3f^lJOS_&oH_ z++qn#3Zo$RTsjJZoSo@M6*fHs!rSm09_vk-S>KJOOXN&hh1&kHrIDTgdTiC z_LIhGV!~Vq1!^SC8V>8*)8T~;8~nIELMgH1%}aaj3K`u(;F3n97S=GxFqsZ3A(xM> z??-#BB<1|~WZ^0d=-b}#MAM@9eo_k>w|ftts#fRwd^67)3S|QQilLE<2bK~DUr$^P zg(4w)lTV}#nYoHgt{UOz$*&QcpMMobK;n;OZsX3nEs1? zK>u3*RNt*{*WcD((_hq|(o6LR^fmhJx}z`A=jt=`$@&<5nBHISt#{Qs>aF!`y}q8Q z*U*#nfbQ1f+Ij7yb`)$0-)moLpJ?xEG3_mFllGkUxb}#4pLVCVLNm36+H7r_HbEPu z4b}>^9$IIuoz_BYtku!dwUCye`7|kTIdCTMN8oUvJn&86Gl)sJBk)e(b%;y&bYOkp z!NA>tRe@!JrGa^YqQFgov4P=%0f8F=-C*v5+(1sCL7-M3HBdF61v~+wUQkb|zo|c| z`_+Bw9`yrttGZczMSWghgx5o&+6r<$kcs!i28YE3ms^{dQ( z!GFSk*#Cq7OaDhO1Hxwi%l@bR>-_im@9;bRMgCd-oBUD#V3-rJtG~U!xxWF}MM8ev z@Ah5so%a3aJLvlcyd~cEz3Y3;_q^{hu#w#5Tj4AA%>@sN@xI}{8+|=|5npRx6JKp# zs;`RA=cC^9-s9e1y!*Xhct7-R^SuDWTtnrceHnq_Xcmix1G0{ zx4t**t>)FdF6FZFCsUq=ilIKa!Bc6L8o`dCC;3@J<@{IBf^z`<0 z@wD~icXIPR8%1Rr^^LcMwbcT zP)7ipVylZ$i=w+fgQ%FM*knMf2!EoO77MVHE)`%2T_V6@x>$fkbddlH=|TY(&;SbLboaX4BaM%%Zadm`P^}P(+Iam_cU(xCzjp+f{1Oa}`vhz=59ARQ>c06IW`{r z6QC>YDnLHX7oZF6B0y)_S%5s6CqRTo1n5LN3DA*t6rcm`AV7QCUVwJAod9iVTLIe8 zHUi|*Tmf3s)&jJmtpsRETME#Ewh*8>Z7x7F+Dw2Pnj=6q%@&|3Z7M($+C+fHw6Oq< zXd?j{(uM*wpbZ45PwNX%kJb~QF0Cs-9a=|#+O)O+Su{(4TC|n`nKV;?44NT8n1%&_ z+1La~qiF)vq%{RdrKtkcpfv=j4&Pt!sZ60M0)%KtfNHdw0Le62fU2~r07*1SfGV_# z0EskFfCLy3ga-`57dHet)dkR~CP07&1W>6efS>vW@KK)tUg{MO!hz_;XE0lp#M2=F!eT7a*}R|4!K`vmxsd?~;e z?L~z*hBUR@Co@ufRD+?0(?Y165vDfp#ZzdZUJ_YT>^YS zJ`mu2^1c8&$xZ>@Bku{YgX|DsJJ~M4HnL5Ctz@eJF%lD?jFbuRE_qjgcgQ;eyiMK~ zU<=tIz-F>pfVaq70=!Ay6yOc=h5)aV*9CZuye7b_~X9akMJR`u<Ts|C1&+#$d!vPyv4 z$?XE%25zhPbgv{U1z15=2yiR8Rew*L3Ptjs3uQFHE9wmnCY6I^@Iti#*areZXBwyV^NJ6 zgDM(DHF`9vQKL|e9Eobg2voy|qZ&30)zG1+h73V9crdC#gHR0|h-$z9RQ>y-y75L- z{raIQEJW3}FRDI$P~C6?s@}a(_3DMHXHQf;dY~#OK-IlFs&3s-b?u5OKOa?>E~q+p zMwOR`DiT4}sS~P>9Z_}YfU13aRPEZKYTFi7n>MI&b5XT!jjB~ER4rSgYS98!^X90U zHA9t?gDN{4Rnw-ZnlwSxxG}0mjZiggh^j#YRQ2nls#gzH-MXmi)In9dHma;FRJCfM z%FINSk%1~4MwOn9DlH9F&6=oEQ&H8ZfvS3SR4FN_LLpSus-a3wMpd;cs-z@TRjQy$ zOhlECfGQY7rR%6P4OJk3N>x$${iu9CR9-JCMM359pmMuWxm>7Z8I>fVV&I_W^?H5k zCOU|nArRxQ6#Bxe)n)2pb+$T19it9`Z~xuY4r&Xvp_-|ts6o{OUI1tOzxxmQzx99W z|G;17e;vF59``@wU*litH~jPb)BO|tBmDjSJ^gw9Tz^x49e+)KlHc!Vz6&s4;9=hn zzAs@Gf$hG{zL$MZ`_}pH^WEWde2aXud^h=`Fq)u`uPa0uZ0>8|%kYJKy3g&s;yvyC z&3n-Mjd!p2eeb*8*SybrAM-v4egrGL#ooE#OEBI$+_j++ymXc-Cf*m-8t@h z?sRvu8}6y=lIxV~SC|>`E7vEk_grtgUU5C^TJKuxy3@7XwZt{YHPtoNHPlt;>h9|3 zYUyg^s^zNgN^mK1Ts|uwlYf%GlRuMp$uap2`9+w4;bHl17-?b3^W_=xM0unO}kLdS+g~-wu=tcS@eUv^B ztV3P&wt9|UPfypA!7?Okm$XybuUfhG6iqS0EO6BbVi3wZU4m)&jI*tpsSvS_;sD zwGf~=Yc4=D)(k)2L$6+}=*qeZkk9f3=)$@P(3y1>Adlq<5MdDkIIzVY)e)dJt1Unl%Mzd#t0h1t%M>7kWe5;vVFA)vx&Ub` zO@NxLrU0odRe&0-h5*%BbpcXXiU1)N5}+EZCO|Sv7N9DtDnJrT5}*pJB0wTb6d-{m z2oPjJ0d%GdpfOE=01F5JQ;!PZXMO>E%qM`Cc?D3IB7lc^1aLFA04@fPAipUxM1Dme zF-ZUj1}gw%Q~Gg(jNsVr{w}1pa%r_f&L)C ze!5?P@9Fmfd`G_%;9L5w0N>DW1o)bMEx=dwD*^V=eFA(*zZBpL`h@_W)6WI?jD9A- zr}R?+_R_rq?4f%E_=J8Uz{m7s0Y0K13GgBPP=MWZw*b57E&)EE9|-V1eP4i`bf*CC z(f0({L3aqSoo*Lk8{Hx-~M#}_vm%b~&JMjJz+UlZU}`ll0GTG6Z8oI9;c5B@ECnefDLqm0PE>` z0ZM790PE;F0Uo7~3h)ShM1Y6s!vZ`+9}?g}`k(+0&<6xqOV?+{=WT_wQn^mYNRTbRMje%-c=%42AHo7H0Th>05Di*KoKhvUWU=78PJL8!f;nHcEhzY@`4q*a!iJv*7{^W5Wa(%7zLs zgbfj3FdHnuAT~&Vfoz}v1K0oo`m_E5+{kVepdafeKp`s>pfBqyKp)mefE(Bi0`z9R z1?a_k3DA@E6rcy|AwU5u5THBjE;EVkW@ST31 zc9S+zOVzZ%fxwr64S_oXR-iU~Pk&Xl;cNL=bpY4~H260D8rT4e;2Zb=e;a>&-!|Xl zFbd!n-(=rFUjd8&2zW1hfAwzh-shd;o#O4|?Es$t8D3pEsr;mTrOZ>ty5sJp?%D3q z?l!JX(C=OB>g$TQH2HIRs@zBhZ#ZeE^d!5Tjbly0kN+k*5(3Q~6hVC9ZrZzLn7t*nNrv4o0 zF@i&7M27!=s&$nSBWRApy*J0QG*-HrpSE<0&q`f(#WN{>ZrwP5=YKpWoxig5^3t*c z7?L7={r$Ba?&aB&)!bBLMd5uJ5G0U9^26{N$0ADw4Rm->4-H_@_6M|Lz>_u^9Qeh zC2M3!`0Z-BDWta1G0Zc{6#Shu{yc$mQVi~O@CpIfa~SamqbcD5>&Q12Gu0sHH;>bJCk(&a_FgmLi`F{`BR?25NI4uV22l+h?jamvRR*nI1<}$P zINV2g088AoJ~676!)W@V75H{A61JLo`YhOqrx={*t>u{x_ae?`2^+{**!Pcti!xKH zuOMM@Rk7QNK_X0ZxC3!23pTjhT$4Q;qR~o@&R-oe)0roBYeOi4<({?lv|dW1Frf2L zXk$753H~Gg7>*eTWf6C&1cg)S8oCP4C_4;ma!N>0%8aO9qP8^%v9&Oa@HrxhVkMyy zJT@FA+?${G!ALBeK~!%ohr2I#1K(Nc#Jz^;fuTtCATNw%4~~aDlrwx7B~5U+H*+Qn zY;x@+%$-Qw2~=^=p_!>;=~BnfDY20GXOYVpiz!Uhv*NVZ4HE}3h!@cjCbSX14&&lD zC@qE|3Rwm?z=!!Flni= zV^BBbATZ#KND_?3;}AB*VjQ}C4tHr!VjlJDI(a^a`?M!9w{>g6su~V=XK%&8dRIUQ z6dIa?@pYn*u6T%9PZ=ZjFDL`x4J#JB1g6JLe1T4)E*?qV{?CZjmDGHZSL;gkyeatY?wi~I6nK6 zF|&lYdysBwf|^J(ZSDo1Pp_~o%EQ!H2n9Kx{{W{O|8=g58rs}Jeh|IP7P~@ngun?) z*&$#7Y=jhs64mxNpqL}+vAlAg5wfC`j?kj^Nj7(}uSd_nK8{=z@i<{)H=oTN?UU%aXVnjA(B`i8 zVS3i`$%-5%5yE^ncd<{RXP#Y^K|?loug|8ZVVVO24-KM3hMA&`1e?3tXVO0zc|PmG z_8EI3>2eL5d)l|6ry9ty0y1BeHI#unQCdNa@itDB(v6;EY2@8Iu3VZFugH1(z@2;~ zQ^Y+F*cW?B)FRU#8BTtW)g7~!yC81Pg@ zhztX?X~5<#`_<`*cX{EHSjgsX`PuaN<`0Q{SC+S6O;!)_KhbM*H~mEVNAmZ%0h@c~ zSEt9Ougcn0gM@Ny?vp>3!t{b~K$uiGv=R%ub7h!tjpV|S4LEdOtRPe*n=_T146Qs~ z++4G{>wYTzjllpSC`={S<_`Qt^ysOo^-7El&2OVdJb@@{Mh@&ZFlobG5PhZ@1lN4I zm0nqWuYd!Gqa^HB`_!xO@sB7@elC&Sim^vGv5u}t`tV(JFch{yND<2gjF zX>-^Aw)F5O7~n-tbc(>n%Li6@LZR$FJHuLv-{!*slIbsrMIkXt249 zem?ziuKFre_~**v@5HYhFOL5fj~{?}DZaVA{iEm8hS^d6gUx6;XHGc*6(k|)VjSkH z43CS#V+UF57WKjNGDIq$^@gXl5LNKl~KBX({G{Dl z_mF|qV{=bsX~Nracf=3`ff9|^!FwSWF`#S-uXtg`Xq34y0s|Hx6K|{Yd_{yL&|n^c;Q_D&iL+MRd<>t! z7igGoWI^8lzme7^`X~A}{Z+k*c2+x}J*7PaUt(*3M}0w{O&~F#fdBkY>c`+Auv%T9 zPJ@2G$A8&>%wO*R!v8*a0Ic`l1Caq2`TP32!k7IbZ`}K(_Z|37|1kKYf2^!k+9-8B zFL;)F`nXMZw(E%NOV>8=_Fmy?C7*y^{;TrSa*4c9o&;a2Q>3q@b>N5HS86O(mo#>P zeNA7ctLY><5Ki*{tJK)x_1Q2smypP4qMRQy8KSoYp+iIlL~h*>uiNR4qsKqZx!j@q zjPvi7C+W}Y4zKLe*ex(1WCYZ`5t`-j8n1xOAxA6UOYl0Cec^vxQ6UXGy!MN**|2`I zO{&4~@fT0vM8bXgppYx+~YD!}TLOwo>xTt}qO{ z;^TZuqOY*jr`qt46eCcyw)5Ola{B{+{-5jqb=iQhJ=n$x z!$Y5y2yb0h5-CwLO7b1Z&u8P|XZT{8!-wCsXEWik@n?zOHmWgVz*ZRIO$H@8ygtuj zFsw{l4&wu869_}(b$F$o$Yv0d6m)nk9%j=a3K46<&n1%X@XEX+yBY4z{owk>Vw{uW z;QUv2(<%LciFLO%e? zl0Zz$Rt~S}r?Dxp@Pm#+gfR2TxOlIH73C9X*^7cRibSILITv$RjASp4FZc-@WOT!%LWiWpG+$agpJH#(#ueDlQOSC+sY z&>D_Ws0$hyV9M~e)G5Rwp?OZ7Uuk&wv7!PAiHj0K#_#zOGUyvp}9zc_;cp(CZ$ z9bTokU}MPSm7;__@J0lNGkAQuI9Qd-EDBkRx7UF&=lo@QH3g#$ufl)oFkCzyA66H- z`Z}X|gCLcSW~Ikh#^+ZYy7QXHjzb8lz|*;Sdi=nFH!kguzxB`K!BUtHIES_XPbX_R zyz1}9M!~|7QG#!{h3u^*G{}Yt4sQ!&GN|y3CbTJ3vH3LU@X9{S;6*bhSOg_Nd_jlT z`e8Qw@6zt-4C804Fr1$JO0zvxDlfaToUi^yc1|+TZY_bE#s~%`!W&Qg5q^V>)_oj4 z=FP0mhF0zY3;-@%n+~K3Sq^Uw6|g}(2Twmy7!Obsfks$rupFv)IX4`mbe=Pi7ydLhkmosFRu=P4 zJq8bGWs<|?JKc#!?eaZt!M=FBUQw@Kj@xA^k^Y4kizotF!*B&r3$9e8SULCexl6@#D_NBj(W zs3M9&(JE+W)Sbqe7ctX8ZL4s*I%`L@;3SVJD+FPlh^54iQ;O|U)8GXzUOh}syy zdAOm{3EmdFCWSQu6QJP=A+r#}^+I_-^&70rdl`5QFqbc$4>;J?WPORT8=3%N&Eaj$ zRMv-(#{4zKsye)t*?`>u_pBu~R;*}4_}g+wU8gs!@56e-E8#tIdfp6DhnQYIjZi7x z0yu^9rlGJ5dAie!-^F397wlJB*6Ua`2w7LUI5z49*FGx4l=4{C3z z!(H-zICr6w*NNaRk+YX2pVJ99bUJ(Gg04CpVIjmiRxE+(UpC9Q;yD#i(jM2oER){TNOycw#dY)%#JB(+V=zW366KX#x)* z1YzUvTiNflgw@HcCGQ=Nui~_Tr8=y|59(SHsz)R6xRP>@(;U`ntU1eangJ?c&CdQ< zr3B)1@L%~W#rPsj=P1jnlLOg8Eax*u;fsLR$%e&5mi^g7vf0IH3Z-ewtSOw?d~$xf zq_p=go=@f*(Gp_;KUj!9w!IfH;_rk-aE8CP)5S_SFAl<@Y{a_1C3LSvid@w@_`a9$ z`L0}rO039)Mt}Ukwb$Z->2EOz4fHBmn8a4W9H8;y${cNASEZfP1TJYVYjV)ll#+3M zSDoHL5;_pY=yzx6j3>gg?s(cm>8dm(d!M94d+T)7!tmJN*7aLR45gFP81`NY^TS=1 z3|*fe7y$J?G+JTIIqZ1#eFrTVu;xcrr7@D#3>X(ALFk3M2^hO$@Fft7w2_-Y#o7?? z6xQ&f^md=+9r4QkLxedE`0=i$Dwn7`$!P%l)ng4l^GsF$ilN6^I`#2z^%oL(t7nv< z#`ud-`D@=D@Tj6KXT{ah4+SAZ*kn#U{?1{n9y6{O<(|lVm_i#1peRiL2%^?$gwk8L)N~gYIgCf0q==8zGIFI^3^m6e}L)zY`*h!UiJiwzY$e#HCQ8u z`#%j~i}{)(wR!yTFlk!3`6Gpe4J86g(D?>Mhtzhs15{525%Y{cb`)b-h|EkVI5j{` zt2*2(ssUR_TF#^~|5clSmhEuos3-&b&786d3BS}-?wA~1OCo5q6)R%!n~M~Vl9=9MQvw0WwKfzoO@5Jt&IX&;-+sCpLa%w@Dr|fvs?|K$I*|*Or zD2Q0Rc@86k;s-w5yROsm!||qXoq2Oh9HvK5E?z!!xU4K*cIXs8{b<>NcyW9kzf|J@ zw<`sVveKg0n196SPc z={xi?eKW)X+^9bXqrBJa59{|sEWkVT6}qi2h0)$~ARgcpeS#j^=D?)D7>Fb|Fwi&9BhV$#AU#Ad^H{D)`Iwg)xh1)ue$tkh%xvlcvKwr|LFe?;tcNb?}A8!@A%(< zScA{`pMYqC5BTqfc!Rh4P4Kh0#XkdL4vzDWgs6l4{JkLVU?&)P(cItIUl(Ez*6>$_ z=!0Ir1n~#Y`A$Lv!k=M=hHreI`#y#!gj;=EAP(V6zGom3;Um8LAr|57Fk?fpZ-H+% z#3P*K8v_vu2m1O#Ou{a{4iJ?v$JY?z5~jl(k5zmDp9f+SUhdO)PZ z4xZK!>#(7xHbgs2@l=6$haL}wh=*s~$06q7A@_cWdibgPLx_7=2D4ng0`pQl1+fnw za^DNl4_CTvh<`ZGJrg1zPJpp3L*4z|H$W7`Ja;>YgV@wvA0i>vbXS8|h<>*Vq9I;z z{R#0954(PZh=^ah_CQR;?XGtqD&oto=O8ZPI@bdb8SxI+tq>b=k?R(Sj(C%69K=T) z?CJ**61%!OL5#%auEr20F~d~@;w0)WFGNbbBAq9)!Y-wtsTi{%9nIq_!j!5JeDmj^=h#2#`Nh@aS6&ViSMNRp#TBp^8f zlqyO;N*_uuN(H3{r5mLSCB%emEtHukGf;+6rlU+lSrcU{ z${HxEqf9{=LRk%EGRmqblTcPcnTRq0CD{F;9CVb(e;fI4BmZsWzm5F2k^eUG-$wr1 z$bTF8ZzKP0Lc@!_{e*tJ+dB2kDN!!Bjb_q$akbWvK`5e zTt})S(~;=NbEG-497&EGM~WlEk>JR0q&Kn~$&K7bY9q6e*vM<7HL@B>jhseGBcqYf z$Y-Q8vKh&YTt+G*laa{CW27;%7)gvAMhYW?k-*4bq%X1;$&1`Y>LPQIxX4?iEwUC# zi=0KuB4d%T$XBE*vK7gSTt%uPQ<131Q=}=f6iJF4MT#Ork)X&=q$jcy$%))VY9cd{ zn8-_{C9)DpiJU}AA|sKI$Va3jvJuIMTtq4&6Oo9>L!=?H5J`v}L<%AUIRUvN!2Ccq z(Jw;$|3CC2(EI;h->2_|*ls)YcOkmlCU9qe66OGS5F)&-hJL@LFNRqFilEm&9^$+W z(Qkx4e>aF6&{l5&J^p$y6F@4&dkgA5i1=0ka{-*ve%F41sBhmwU;h*B18o~betTWp z2(jND*B*s_{u*r+#D6oOmp@0Fu1$s*a3i!q5CyKMmJdDrT&)>If~y1l`|4VfrfCZF z?k__;xD$b+(6|2~@HNDQ`v`jWvB2iQtAQ7xU%w&naNxc`3H0h6m>pn#U{+vSU}7K| z7zU#m`oMUG&VlxUR&c@B)AbU#UIN!k;CcyMFM;bNaJ>Ysm%#NBxLyL+OW^;d1f*ry zomz(dsb$!qT82HUW!R-!#`{##GVIhl*sFK2Tkl}M-ocK&gFSl(yY>$D?H%mgJJ`E- zuzT-d|K7n4zJon{2fO$V_VFF;p};{)frF+32W7C3eA3~QszLRkxCCdv$yXf$xp zYT%&Rz(Ko#gN6eKEe8&o4ji-{IA}a@(0bsY`M^Q@frADF2Q3H=nh+ecAvkD6aJUuW F{{bDLE)W0! literal 0 HcmV?d00001 diff --git a/CHANGELOG.md b/CHANGELOG.md index 44d3778..8faa890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning][]. ## [Unreleased] +### New features + +- Add templates for Python stages (`quarto_py`, `quarto_ipynb`) ([#98](https://github.com/Boehringer-Ingelheim/dso/pull/98)). + ### Documentation - Update documentation, finalizing the most important sections of the user guide. @@ -27,7 +31,7 @@ and this project adheres to [Semantic Versioning][]. - Do not change the configuration of the root logger, only the `dso` logger. Changing the root logger had side-effects on other libraries when importing `dso` in Python ([#80](https://github.com/Boehringer-Ingelheim/dso/pull/80)). -### New Features +### New features - Paths in `params.in.yaml` files declared with `!path` can now be compiled to absolute instead of relative paths ([#78](https://github.com/Boehringer-Ingelheim/dso/pull/78)). - Python API that mirrors `dso-r` functionality (e.g. to be used from Jupyter notebooks) ([#30](https://github.com/Boehringer-Ingelheim/dso/pull/30)) diff --git a/docs/getting_started.md b/docs/getting_started.md index 66be16b..d709bba 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -79,7 +79,8 @@ For more details, please refer to [Configuration files](user_guide/params_files. ## Implementing a stage -A stage is a single step in your analysis and usually generates some kind of output data from input data. The input data can also be supplied by previous stages. To create a stage, use the `dso create stage` command and select either the _bash_ or _quarto_ template as a starting-point. +A stage is a single step in your analysis and usually generates some kind of output data from input data. The input data can also be supplied by previous stages. To create a stage, use the `dso create stage` command and select either the _bash_ or one of the _quarto_ +[templates](user_guide/templates.md) as a starting-point. The essential files of a stage are: diff --git a/docs/user_guide/templates.md b/docs/user_guide/templates.md index 5eff4d8..29199ea 100644 --- a/docs/user_guide/templates.md +++ b/docs/user_guide/templates.md @@ -19,7 +19,9 @@ Folder templates: Stage templates: -- [quarto](https://github.com/Boehringer-Ingelheim/dso/tree/main/src/dso/templates/stage/quarto) - Template for quarto notebook in R +- [quarto_r](https://github.com/Boehringer-Ingelheim/dso/tree/main/src/dso/templates/stage/quarto) - Template for quarto notebook in R +- [quarto_py](https://github.com/Boehringer-Ingelheim/dso/tree/main/src/dso/templates/stage/quarto) - Template for quarto notebook in Python (quarto markdown (`.qmd`) format) +- [quarto_r](https://github.com/Boehringer-Ingelheim/dso/tree/main/src/dso/templates/stage/quarto) - Template for quarto notebook in Python (jupyter notebook (`.ipynb`) format) - [bash](https://github.com/Boehringer-Ingelheim/dso/tree/main/src/dso/templates/stage/bash) - Template for executing a bash snippet The source code of the templates can be [inspected on GitHub](https://github.com/Boehringer-Ingelheim/dso/tree/main/src/dso/templates). diff --git a/pyproject.toml b/pyproject.toml index 331cacd..38c19cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ dependencies = [ "ruamel-yaml", "svgutils", "tomli; python_version<='3.10'", + "uv", ] optional-dependencies.dev = [ "hatch", "pre-commit" ] diff --git a/src/dso/_quarto.py b/src/dso/_quarto.py index 5aed78e..c5b4655 100644 --- a/src/dso/_quarto.py +++ b/src/dso/_quarto.py @@ -69,7 +69,7 @@ def render_quarto(quarto_dir: Path, report_dir: Path, before_script: str, cwd: P {before_script} - quarto render "{quarto_dir}" --output-dir "{report_dir}" {quiet} {pandocfilter} + quarto render "{quarto_dir}" --execute --output-dir "{report_dir}" {quiet} {pandocfilter} """ ) res = subprocess.run(script, shell=True, executable="/bin/bash", cwd=cwd) diff --git a/src/dso/cli/_create.py b/src/dso/cli/_create.py index c5ac4b5..964387c 100644 --- a/src/dso/cli/_create.py +++ b/src/dso/cli/_create.py @@ -14,7 +14,9 @@ # list of stage template with description - can be later populated also from external directories STAGE_TEMPLATES = { "bash": "Execute a simple bash snippet or call an external script (e.g. nextflow)", - "quarto": "Generate a report using quarto", + "quarto_r": "Generate a quarto report using R (qmd file)", + "quarto_py": "Generate a quarto report using Python (qmd file)", + "quarto_ipynb": "Generate a quarto report using Python (ipynb file)", } # Create help text for CLI listing all templates STAGE_TEMPLATE_TEXT = "\n".join(f" * __{name}__: {description}" for name, description in STAGE_TEMPLATES.items()) diff --git a/src/dso/templates/init/default/.pre-commit-config.yaml b/src/dso/templates/init/default/.pre-commit-config.yaml index 93a218c..fb96620 100644 --- a/src/dso/templates/init/default/.pre-commit-config.yaml +++ b/src/dso/templates/init/default/.pre-commit-config.yaml @@ -24,6 +24,13 @@ repos: # args: [--fix, --exit-non-zero-on-fix] # - id: ruff-format # types_or: [python, pyi, jupyter] + + # for ipynb files in `src` directories: we never want to commit any output as rendered output files + # are tracked by dvc + - repo: https://github.com/kynan/nbstripout + rev: "0.8.1" + hooks: + - id: nbstripout - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: diff --git a/src/dso/templates/stage/quarto/.gitignore b/src/dso/templates/stage/quarto_ipynb/.gitignore similarity index 100% rename from src/dso/templates/stage/quarto/.gitignore rename to src/dso/templates/stage/quarto_ipynb/.gitignore diff --git a/src/dso/templates/stage/quarto/README.md b/src/dso/templates/stage/quarto_ipynb/README.md similarity index 100% rename from src/dso/templates/stage/quarto/README.md rename to src/dso/templates/stage/quarto_ipynb/README.md diff --git a/src/dso/templates/stage/quarto_ipynb/dvc.yaml b/src/dso/templates/stage/quarto_ipynb/dvc.yaml new file mode 100644 index 0000000..aea486d --- /dev/null +++ b/src/dso/templates/stage/quarto_ipynb/dvc.yaml @@ -0,0 +1,11 @@ +stages: + {{ stage_name }}: + params: + - dso.quarto + deps: + - src/{{ stage_name }}.ipynb + outs: + - output + - report/{{ stage_name }}.html + cmd: + - uv run dso exec quarto . diff --git a/src/dso/templates/stage/quarto/params.in.yaml b/src/dso/templates/stage/quarto_ipynb/params.in.yaml similarity index 100% rename from src/dso/templates/stage/quarto/params.in.yaml rename to src/dso/templates/stage/quarto_ipynb/params.in.yaml diff --git a/src/dso/templates/stage/quarto/src/.gitignore b/src/dso/templates/stage/quarto_ipynb/src/.gitignore similarity index 100% rename from src/dso/templates/stage/quarto/src/.gitignore rename to src/dso/templates/stage/quarto_ipynb/src/.gitignore diff --git a/src/dso/templates/stage/quarto_ipynb/src/{{ stage_name }}.ipynb b/src/dso/templates/stage/quarto_ipynb/src/{{ stage_name }}.ipynb new file mode 100644 index 0000000..35270a6 --- /dev/null +++ b/src/dso/templates/stage/quarto_ipynb/src/{{ stage_name }}.ipynb @@ -0,0 +1,64 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# | label: load_libraries\n", + "\n", + "import pandas as pd\n", + "\n", + "from dso import read_params, stage_here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the stage-specific 'params.yaml' config using the `read_params(..)` function. This function specifically loads\n", + "only the stage-dependent parameters that are defined in the 'params' section of the 'dvc.yaml' file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# | label: read_params\n", + "\n", + "params = read_params(\"{{ stage_path }}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To locate your files relative to the stage path use `stage_here(..)`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# | label: obtain_files_relative_to_stage_dir\n", + "\n", + "# e.g.\n", + "samplesheet = pd.read_csv(stage_here(params[\"samplesheet\"]))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/src/dso/templates/stage/quarto_py/.gitignore b/src/dso/templates/stage/quarto_py/.gitignore new file mode 100644 index 0000000..0d1f731 --- /dev/null +++ b/src/dso/templates/stage/quarto_py/.gitignore @@ -0,0 +1,7 @@ +/log +/tmp +/temp +/input/* +!/input/*.dvc +/output/* +/report/* diff --git a/src/dso/templates/stage/quarto_py/README.md b/src/dso/templates/stage/quarto_py/README.md new file mode 100644 index 0000000..cdb3c0f --- /dev/null +++ b/src/dso/templates/stage/quarto_py/README.md @@ -0,0 +1,3 @@ +# {{ stage_name }} + +{{ stage_description }} diff --git a/src/dso/templates/stage/quarto_py/dvc.yaml b/src/dso/templates/stage/quarto_py/dvc.yaml new file mode 100644 index 0000000..130e1a0 --- /dev/null +++ b/src/dso/templates/stage/quarto_py/dvc.yaml @@ -0,0 +1,11 @@ +stages: + {{ stage_name }}: + params: + - dso.quarto + deps: + - src/{{ stage_name }}.qmd + outs: + - output + - report/{{ stage_name }}.html + cmd: + - uv run dso exec quarto . diff --git a/src/dso/templates/stage/quarto/input/.gitkeeptemplate b/src/dso/templates/stage/quarto_py/params.in.yaml similarity index 100% rename from src/dso/templates/stage/quarto/input/.gitkeeptemplate rename to src/dso/templates/stage/quarto_py/params.in.yaml diff --git a/src/dso/templates/stage/quarto_py/src/.gitignore b/src/dso/templates/stage/quarto_py/src/.gitignore new file mode 100644 index 0000000..e2a7536 --- /dev/null +++ b/src/dso/templates/stage/quarto_py/src/.gitignore @@ -0,0 +1,6 @@ +/.quarto/ +/*.html +# temporary quarto files +*.rmarkdown +/_quarto.yml +/*_files/ diff --git a/src/dso/templates/stage/quarto_py/src/{{ stage_name }}.qmd b/src/dso/templates/stage/quarto_py/src/{{ stage_name }}.qmd new file mode 100644 index 0000000..535dd53 --- /dev/null +++ b/src/dso/templates/stage/quarto_py/src/{{ stage_name }}.qmd @@ -0,0 +1,25 @@ +```{python} +# | label: load_libraries + +from dso import read_params, stage_here +import pandas as pd +``` + +Load the stage-specific 'params.yaml' config using the `read_params(..)` function. This function specifically loads +only the stage-dependent parameters that are defined in the 'params' section of the 'dvc.yaml' file. + +```{python} +#| label: read_params + +params = read_params("{{ stage_path }}") +``` + + +To locate your files relative to the stage path use `stage_here(..)`. + +```{python} +# | label: obtain_files_relative_to_stage_dir + +# e.g. +samplesheet = pd.read_csv(stage_here(params["samplesheet"])) +``` diff --git a/src/dso/templates/stage/quarto_r/.gitignore b/src/dso/templates/stage/quarto_r/.gitignore new file mode 100644 index 0000000..0d1f731 --- /dev/null +++ b/src/dso/templates/stage/quarto_r/.gitignore @@ -0,0 +1,7 @@ +/log +/tmp +/temp +/input/* +!/input/*.dvc +/output/* +/report/* diff --git a/src/dso/templates/stage/quarto_r/README.md b/src/dso/templates/stage/quarto_r/README.md new file mode 100644 index 0000000..cdb3c0f --- /dev/null +++ b/src/dso/templates/stage/quarto_r/README.md @@ -0,0 +1,3 @@ +# {{ stage_name }} + +{{ stage_description }} diff --git a/src/dso/templates/stage/quarto/dvc.yaml b/src/dso/templates/stage/quarto_r/dvc.yaml similarity index 100% rename from src/dso/templates/stage/quarto/dvc.yaml rename to src/dso/templates/stage/quarto_r/dvc.yaml diff --git a/src/dso/templates/stage/quarto_r/params.in.yaml b/src/dso/templates/stage/quarto_r/params.in.yaml new file mode 100644 index 0000000..e69de29 diff --git a/src/dso/templates/stage/quarto_r/src/.gitignore b/src/dso/templates/stage/quarto_r/src/.gitignore new file mode 100644 index 0000000..e2a7536 --- /dev/null +++ b/src/dso/templates/stage/quarto_r/src/.gitignore @@ -0,0 +1,6 @@ +/.quarto/ +/*.html +# temporary quarto files +*.rmarkdown +/_quarto.yml +/*_files/ diff --git a/src/dso/templates/stage/quarto/src/{{ stage_name }}.qmd b/src/dso/templates/stage/quarto_r/src/{{ stage_name }}.qmd similarity index 100% rename from src/dso/templates/stage/quarto/src/{{ stage_name }}.qmd rename to src/dso/templates/stage/quarto_r/src/{{ stage_name }}.qmd diff --git a/tests/conftest.py b/tests/conftest.py index 671674d..9abfd18 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,7 +31,7 @@ def quarto_stage(dso_project) -> Path: runner = CliRunner() stage_name = "quarto_stage" chdir(dso_project) - runner.invoke(dso_create, ["stage", stage_name, "--template", "quarto", "--description", "a quarto stage"]) + runner.invoke(dso_create, ["stage", stage_name, "--template", "quarto_r", "--description", "a quarto stage"]) with (Path(stage_name) / "src" / f"{stage_name}.qmd").open("w") as f: f.write( dedent( diff --git a/tests/test_create.py b/tests/test_create.py index 68fcfd7..2042798 100644 --- a/tests/test_create.py +++ b/tests/test_create.py @@ -7,7 +7,7 @@ from dso.cli import dso_create -@pytest.mark.parametrize("template", ["bash", "quarto"]) +@pytest.mark.parametrize("template", ["bash", "quarto_r", "quarto_py", "quarto_ipynb"]) def test_create_stage(dso_project, template): runner = CliRunner() chdir(dso_project)