From 0dfd965952529bb3807f5f814f460857cf52b612 Mon Sep 17 00:00:00 2001 From: Jonathan Zhu <3010705+JonathanZhu11@users.noreply.github.com> Date: Mon, 24 Sep 2018 11:59:34 -0700 Subject: [PATCH] Initial Commit Working version of sqlmlutils in Python and R Supports: - Stored Procedures - Execute in SQL - Package Management Known Issues: - Cannot execute Stored Procedures with Output Parameters - No dependency resolution on uninstall in Python Package Management --- AirlineTestDB.bak | Bin 0 -> 5361664 bytes CONTRIBUTING.md | 14 + LICENSE | 38 +- Python/LICENSE | 25 + Python/MANIFEST | 19 + Python/README.md | 220 ++ Python/buildandinstall.cmd | 2 + Python/dist/sqlmlutils-0.5.0.zip | Bin 0 -> 20730 bytes Python/setup.py | 25 + Python/sqlmlutils/__init__.py | 6 + Python/sqlmlutils/connectioninfo.py | 55 + .../sqlmlutils/packagemanagement/__init__.py | 1 + .../packagemanagement/dependencyresolver.py | 60 + .../packagemanagement/download_script.py | 26 + .../sqlmlutils/packagemanagement/messages.py | 11 + .../packagemanagement/outputcapture.py | 9 + .../packagemanagement/packagesqlbuilder.py | 130 ++ .../packagemanagement/pipdownloader.py | 82 + .../sqlmlutils/packagemanagement/pkgutils.py | 29 + Python/sqlmlutils/packagemanagement/scope.py | 20 + .../packagemanagement/servermethods.py | 78 + .../packagemanagement/sqlpackagemanager.py | 176 ++ Python/sqlmlutils/sqlbuilder.py | 467 ++++ Python/sqlmlutils/sqlpythonexecutor.py | 209 ++ Python/sqlmlutils/sqlqueryexecutor.py | 90 + Python/sqlmlutils/storedprocedure.py | 36 + Python/tests/execute_function_test.py | 168 ++ Python/tests/package_helper_functions.py | 13 + Python/tests/package_management_file_test.py | 266 +++ Python/tests/package_management_pypi_test.py | 232 ++ .../samples/sample_linear_regression_test.py | 24 + .../tests/samples/sample_scatter_plot_test.py | 35 + .../samples/sample_simple_function_test.py | 14 + .../tests/samples/sample_stored_procedure.py | 47 + .../test_packages/testpackageA-0.0.1.zip | Bin 0 -> 1005 bytes .../test_packages/testpackageA-0.0.2.zip | Bin 0 -> 1029 bytes .../test_packages/testpackageA/MANIFEST | 4 + .../testpackageA/dist/testpackageA-0.0.1.zip | Bin 0 -> 1005 bytes .../test_packages/testpackageA/setup.py | 9 + .../testpackageA/testpackageA/ClassA.py | 8 + .../testpackageA/testpackageA/__init__.py | 1 + Python/tests/scripts/test_script.py | 9 + .../scripts/test_script_no_out_params.py | 9 + Python/tests/scripts/test_script_no_params.py | 9 + Python/tests/scripts/test_script_out_param.py | 7 + .../tests/scripts/test_script_sproc_out_df.py | 10 + Python/tests/stored_procedure_test.py | 461 ++++ R/DESCRIPTION | 19 + R/LICENSE | 25 + R/NAMESPACE | 17 + R/R/executeInSQL.R | 293 +++ R/R/sqlPackage.R | 2047 +++++++++++++++++ R/R/storedProcedure.R | 378 +++ R/R/storedProcedureScripting.R | 220 ++ R/README.md | 151 ++ R/buildandinstall.cmd | 5 + R/dist/sqlmlutils_0.5.0.zip | Bin 0 -> 88130 bytes R/man/checkSproc.Rd | 46 + R/man/connectionInfo.Rd | 38 + R/man/createSprocFromFunction.Rd | 83 + R/man/dropSproc.Rd | 44 + R/man/executeFunctionInSQL.Rd | 40 + R/man/executeSQLQuery.Rd | 27 + R/man/executeScriptInSQL.Rd | 25 + R/man/executeSproc.Rd | 49 + R/man/sql_install.packages.Rd | 40 + R/man/sql_installed.packages.Rd | 42 + R/man/sql_remove.packages.Rd | 41 + R/sqlmlutils.Rproj | 21 + R/tests/testthat.R | 7 + R/tests/testthat/helper-Setup.R | 27 + R/tests/testthat/scripts/script.txt | 7 + R/tests/testthat/scripts/script2.txt | 5 + R/tests/testthat/scripts/script3.R | 2 + R/tests/testthat/test.executeInSqlTests.R | 203 ++ R/tests/testthat/test.storedProcedureTests.R | 319 +++ README.md | 44 +- 77 files changed, 7392 insertions(+), 27 deletions(-) create mode 100644 AirlineTestDB.bak create mode 100644 CONTRIBUTING.md create mode 100644 Python/LICENSE create mode 100644 Python/MANIFEST create mode 100644 Python/README.md create mode 100644 Python/buildandinstall.cmd create mode 100644 Python/dist/sqlmlutils-0.5.0.zip create mode 100644 Python/setup.py create mode 100644 Python/sqlmlutils/__init__.py create mode 100644 Python/sqlmlutils/connectioninfo.py create mode 100644 Python/sqlmlutils/packagemanagement/__init__.py create mode 100644 Python/sqlmlutils/packagemanagement/dependencyresolver.py create mode 100644 Python/sqlmlutils/packagemanagement/download_script.py create mode 100644 Python/sqlmlutils/packagemanagement/messages.py create mode 100644 Python/sqlmlutils/packagemanagement/outputcapture.py create mode 100644 Python/sqlmlutils/packagemanagement/packagesqlbuilder.py create mode 100644 Python/sqlmlutils/packagemanagement/pipdownloader.py create mode 100644 Python/sqlmlutils/packagemanagement/pkgutils.py create mode 100644 Python/sqlmlutils/packagemanagement/scope.py create mode 100644 Python/sqlmlutils/packagemanagement/servermethods.py create mode 100644 Python/sqlmlutils/packagemanagement/sqlpackagemanager.py create mode 100644 Python/sqlmlutils/sqlbuilder.py create mode 100644 Python/sqlmlutils/sqlpythonexecutor.py create mode 100644 Python/sqlmlutils/sqlqueryexecutor.py create mode 100644 Python/sqlmlutils/storedprocedure.py create mode 100644 Python/tests/execute_function_test.py create mode 100644 Python/tests/package_helper_functions.py create mode 100644 Python/tests/package_management_file_test.py create mode 100644 Python/tests/package_management_pypi_test.py create mode 100644 Python/tests/samples/sample_linear_regression_test.py create mode 100644 Python/tests/samples/sample_scatter_plot_test.py create mode 100644 Python/tests/samples/sample_simple_function_test.py create mode 100644 Python/tests/samples/sample_stored_procedure.py create mode 100644 Python/tests/scripts/test_packages/testpackageA-0.0.1.zip create mode 100644 Python/tests/scripts/test_packages/testpackageA-0.0.2.zip create mode 100644 Python/tests/scripts/test_packages/testpackageA/MANIFEST create mode 100644 Python/tests/scripts/test_packages/testpackageA/dist/testpackageA-0.0.1.zip create mode 100644 Python/tests/scripts/test_packages/testpackageA/setup.py create mode 100644 Python/tests/scripts/test_packages/testpackageA/testpackageA/ClassA.py create mode 100644 Python/tests/scripts/test_packages/testpackageA/testpackageA/__init__.py create mode 100644 Python/tests/scripts/test_script.py create mode 100644 Python/tests/scripts/test_script_no_out_params.py create mode 100644 Python/tests/scripts/test_script_no_params.py create mode 100644 Python/tests/scripts/test_script_out_param.py create mode 100644 Python/tests/scripts/test_script_sproc_out_df.py create mode 100644 Python/tests/stored_procedure_test.py create mode 100644 R/DESCRIPTION create mode 100644 R/LICENSE create mode 100644 R/NAMESPACE create mode 100644 R/R/executeInSQL.R create mode 100644 R/R/sqlPackage.R create mode 100644 R/R/storedProcedure.R create mode 100644 R/R/storedProcedureScripting.R create mode 100644 R/README.md create mode 100644 R/buildandinstall.cmd create mode 100644 R/dist/sqlmlutils_0.5.0.zip create mode 100644 R/man/checkSproc.Rd create mode 100644 R/man/connectionInfo.Rd create mode 100644 R/man/createSprocFromFunction.Rd create mode 100644 R/man/dropSproc.Rd create mode 100644 R/man/executeFunctionInSQL.Rd create mode 100644 R/man/executeSQLQuery.Rd create mode 100644 R/man/executeScriptInSQL.Rd create mode 100644 R/man/executeSproc.Rd create mode 100644 R/man/sql_install.packages.Rd create mode 100644 R/man/sql_installed.packages.Rd create mode 100644 R/man/sql_remove.packages.Rd create mode 100644 R/sqlmlutils.Rproj create mode 100644 R/tests/testthat.R create mode 100644 R/tests/testthat/helper-Setup.R create mode 100644 R/tests/testthat/scripts/script.txt create mode 100644 R/tests/testthat/scripts/script2.txt create mode 100644 R/tests/testthat/scripts/script3.R create mode 100644 R/tests/testthat/test.executeInSqlTests.R create mode 100644 R/tests/testthat/test.storedProcedureTests.R diff --git a/AirlineTestDB.bak b/AirlineTestDB.bak new file mode 100644 index 0000000000000000000000000000000000000000..b07e9fe9b1c83759b157bc153f443c28a65b6a3e GIT binary patch literal 5361664 zcmeEv34j&F@psSLxA)0%
r3GDvM z2nblL^q(i}MG`nT*dqr{2=>TK=}!eS2slCTnSv(?o-g>T zg6|dlnBeV#e=j&L>Gl#_Em)t8gLE#H`?-Rf1%FHMqk?}bI6Rl3t!{%V8O~c)V~{*@ zwM!06ags^OQhF5ryOE@lB$7M^|2?uh{wbK^l55?#6Miz^_9moi^8DmvQd3Dr6mBFb zmz==HY%aOQCFl9cbza;lpR^ar7(aQJCw)VD>Gb3gsYKGXM7fqAZjbEsYw;U=WY6v~ zezIrah{ZnXRxfTpIq8v?_@tFfjxY6*yp5K4A((tV zq#go%RQasS?VtO4VtrzMVqBsuu`}nMoQ9n0oJ7vH_^Nn)d|13VzALsqmWsVndQsuS zJuWJ4Dy+lr|1d5dlYRfY$aExb_W$qj+cG}FQlu}!MueUS7QXuXX>Z!=Ojxf19}X@f zAz-xRRBcv|1+jucL*i8JDw(SNzQE8dRv6YAu6u#cYV8W&M(PaA2I~RrN~-mT@uACH zn~Qe)-wVU4ALbb&)w6 V3s4Hr{LoRj}|;p z@EpNQ1>Yrjqu`$i{%^tm6kN(m0kGfAkC1!&jZ}l&+kNxDA@>gp-YWRFg5ML|MOL@^ z3$77-f#9nJFBE)-;Qtc*Bf+}_|4ncwskcW89wzvF!B+~tUhqo64+*y4Q2ko&-xXXW zZRBvlrwFbUe1+ia1b=(rev;t%g1;*GUcrwE-Y)p}g5&1Z0@X`!wcyhQUn+R6;AX+!68xy( zp9 VNT75t#!X9VvQ{Aa<1@+(ju!9xU}D|njVF9}{D_yNIB34U4dUcnt?3E(inCkh@X zc(ULx2>wsOYXm W!Dk4r6C8eYymw2i)qTR@qYNLcQZ 8jHj(^b&u@cdljQY}ocB~95+l8&WJ8d= zMaO;C^ ufm-8KgzF-Z;{b8e7ql04_lF3$v{Q`(Z% zl{13m5>5W+$s2=YljMSiBYzl(#3cE`2j`?CpZ4~b(~&!F`&p1|is7FR-|%c8?gnki z6}N8>BwE~d@&vQ_YVx>Pn4b|CXz>2 z+?0;IVD~fW$UBl L7WgF3Y|-zYmg4k`M1X<`;oT4Ee-!Z%ju%ZNXzf zvPtry8Rx$kh{TW=|LG?|vZ Ty}1+rRNx|V8C2izl>YD z=Hd~) `m;P98xFk&hk1%gq&HLA~Hc!A*i?l@w1sSP$}+&Gl&s%x9)LL7suV z$a5O-9er)N-cJXX65+@Lkq06VL>`Dd5P87$z)yPAxxfDp0F~eW^Y{H2hUsCzrx)E; zdYHb)-iyFx_$|)=`~Rzlj~oedR?xryCm|A=kewYmm+|ofoCnHt8Qb%0M*d95kb}UV z%5Lua+HmvZ4zItDYyB#160CLs+U1Am#ox~eW4bW!5WHQmeMR$sdoJU8NiXf8dnc%D z$K<6|vBwfd=Q4&4bo3t}nAUUuH_v4}Qq|%x$20W7jpyMMkhEDl=#v@wtdOnBeYhtx z1}*>4&t~j!BD&-pcF1mLDnF{@={Ciu+unG(mEZ66VJf%E)2*dhENwphlaw$&4#d8K zflqhxJAM)!C^}IMxNcwQ#>Z|SoGRDz1TPT$6~WfO93%-PI#*mBByeERzj-mM-rLP% zP6sh?#wcCVUjmQ@W67A)*^MVjS)v`M-+;Htl1y-`hxpW14<03FW%(M^ga3!Bhk4B+ zmGr6yuiF>GU)=H=Fv1vv+`Wse&yNzi`N_A|S1o++{3nw}3g-yoLf02j6XcezyrGh* zbbm439296%w^*Y2L^b~Zf2Heh^uE&dnmrqGw$e2&arZ)48S2_!%~-mrnwOW{+3ue- zaiNcamH7Wc>F$G_8fY*eUvN_2DRrUXnS#G8c$MJq3Vu%TYl7wVj- Dpk)ln;Gr V96=~y4M*FlK6!S>S+!) z9(hm_afv!}9P|evy~HSRvfD8_D8b3mH!=EIC60dU aCr0MPl*zDgle lX70!y2a&dku0uqj7L_At?A(dwx;%NQ8vePiz%*>5x!Q= z>m*q12G+gS06RVVnh
jaZ h#HhBBAe+w8uO}=&Er#Z%G5B@2tmylU?GBY!Zw(g2)4r2O p;%%Q^m*pYp1;`5qWl}QfAQ_)Cc2%jNs_}ER;3EC$u zn>s&`A|!=zq2QT F0+{eR}E*Wmghx^H%^wEBDOVUcSb8sW^$jAA~DOY-+pX^Bw@{?O#=@a~9FOtBP zj!9RVJxUr&_(QEr_9EeL=V{1{Ee)B@Nkbm#CwrER@{?PVxC5kWxYFrGVi#{~xNMS! z%(W7itdh6`g!gWA3++rWUFj;9e3qZ=MKaD$_6$77PfjIq2T0Xig#T{byOJc59N2cz zi+duNuCy2TC4O=;iC##D%lzb4kW855Cwtim>^w-a39|E`JFdi`O~_NN99Oz^SP+{W zGbFaY=ik3hReu}%4jGb*2NsV!E%*5QhE4AL-J!oc_m-hc7B6m>vE^9U#Q-nb-^-BI z239seDj5u#__6*A|JH5K%>E*KJiv{Dr;E=Q2);$|I>DO-|4Q&Xf(xYlssx`b_#DAg z1vd%)n&A5dKPh;J;I{?m$v99cc(CBJ1Ya)rTEWW&-zWHS!M_l^M{o`c3g8GHD0r;k z%LHE|_&)^SBlrh``DHlaO~G;&i|Q% XHL0l} z^K~LG5|_*u4Lq{jhxH7T&5s{}VJhWD5{*Z;bUc5vr|}%?y6WF>m}+q|9~h66OFqx< zs-#N}Y%!d2$?ZLQC5OXYK&s|){CA7E+9d}DHIhvTY^Ph|N(Z*nZA~&}#x2|F+9A!5 z<@K*2xQhuTPgSM)sh$#XS7KKh32wIL#gR^e^DIvS(e+i^@jEVi1_B4(r{#gp(kv#Q zU)PQ7F{oW%R$<4 HE0 z+DBTeh@@(IxU{58>j|2kOtDPk2n2aZ|5wY@mTP;Jtu0ezNqghiDTO1$WqRzC7-*>^ zv-xpDyOgP^+$_@++bLftvu%;>^m=(2)Y2@*{@69``N4%Pn|xd_(0AVJFm5|dg50hU zo*;j;FO+%hmj2MqnNA_u1U3PetUxw_v&SGA1a27ZBinaaQhHBBSK1?U>%cVR;`HQB zhHUE-?lkDWh7%y$7}AeYCqu%kxh-i%si1_e+b^PSFN&LVShv4__21MPc=)?R(z2Km z&u`t@uHz4FphFn~bvyMu`X@pvsZl%r3)gM?k 9V)PXP#!xwtlD~*{yg9m&}rO$vcLd$U^T_CX<#7Nl&`Lm1ZS#BjId}kgDM; z^e)+(kp&)!T9cHeG~1vnt&${?+#Ua2vbWABC(-z8Bjw#C4e#~+O!eNA(DnX=oCUG3 z&>H~O`^{4C?c%P*wCR)3r*r+2f#vG;=`YxVO@iF65U%%MqoDv>V&9Vc>4vNp2);$| zI>DO-|4Q&Xf(t~yO7O{o&k;OTaFbxu9(Io~>Y kqdQYaQ1iIn{a#N4*Se<{ykqe^{p8 | zXrbU{!Bv7;Bm^!D5T+U=OI<@onA>1uNIh)(kl>s3UhQG`=++*OEZu#uOeMij44MJh z_1H3J`6ja;J>T8rzVd~!F=`Cp-5&(^ukQvZdwiL*9y-rKmR+qmU!qD?0S1G&{fVH? zTmUn?5 |ZY}0%C^*w)?co4*)j8F5148M8rR!evP`Zb5(+N zTe*K%%rdG {2v$peCf+wa!Uqw z>fGrM9e><0UcRp9!=)SZ>h$mbdD6?_V@!?}fVh6-s_(TtuL^f8-XjopAh4IQ@blEM zf3Vk?Fg}IMVe~OIT+P5s%Juj^6K#1s!W_J=JW7pFsEz*yf1}l@YNCEY`)bvIt2yfP z@WveYVYa$P|DUMl >*N5oj0jEah++%5#>w;{SO$ z{NHI8wmgnQxlB<}`}lBMkAGyzG@3;8$ODlFA`e6!h&&K^Ao4)ufye`q2O `Dd5P2Z-K;(gJ9+;nl-~ajYRb0i49KW9-#Pw^bdFrpd`{0gD zzR{J$1z+K^@YGk&TxPE`<4ZHMLY$cUqIZaq<#tH#EX;@%c_8vY `Dd z5P2Z-K;(hQ1Ca+J4@4e_JP>&x@<8N)$ODlFA`e6!h&&K^Ao4)ufye`q2mTE_@HlpM zh{f^U b*ch!$#+z~6LdVxP%K33Noe+aJ#ymEYc+Xy~SJDUL+tH-w( zx)_Q}%LT2w{*- M4c-=tr+nobiPkj2{h|m5T;1j2xDGu7w3;Clp zSAaf8J-O8KjLtN~Gh3%*_vP;nok|=;Z0Tp<^YXKG`X)}=UXIvi!{WJ!+1O!t^oi#` zL+b%rPe^gg0?OL-nGe!ug65B-1L(cfRj~G2lo0&~ko@!lue G{jpq}LVnqt&^HX$I1vueia& z7^FHG_Ra#`v$+himB{-QNPiacN(n!ob=A}bZzBiPNY}nn@OwjprDr#Kn4$)$J(9Oh zY56C(e(s!>KiK7)`c0qAf@QbfZhck^y
ty sH%3kNtThJ@yTi&@jE3&AAsh+YHM&5WDEI|6pI(pxex3*C*_^ zdV$VygJo~}Y?F_0|7q=D+vp7)_P{I|Ymw^5m)Xo)Z@rK|w*RTRWKqV#GkLH)+lQc> zgwHg)!*|?lh4u6bq0`sFwgG-WGpv$l`+iGn+m@g&^1(DP1Pk4aA#7DsRHM+C*Ph5D z>mvIaC3Mz{KJc0UbWqmjskBpM=<`1CQUl^MJd06+B4hkd&vQg$%J8S~*oN3gPC~kK z(5INT0GWPu+Rw~)c+8n3Jm&uhU7~D5lXd%LOPq|_qeO;&2>KNM6drxi8*PC(XAW$M zH1^|$b)0l~V_J^TjL-e`9_1oDQ =o z>$ULASk1OkFM8PCNqDBbZJl6x@Tc(1yu|QKdaO$(&t~q%+Q#0NdZ?GeGySyT89nq3 z{fgR@Q?AgAujaru);rTbcM+ax8@5H$7bYJ1$!nMJr_fCqnQ>z-tV{GOZj-JO8q@6w z%cr6~v8GQEx~Yf$dgJk!Zg0`?OV~I~8QH#&Jree9lXzK1<)UkIw7(y>&o%Yej3H(- zDAVQ*&(z~-GNU2~AbQ5u*#TZ$c*a(bXXkL;g>P*2&*9LjglBB!eAnvFLH#xMus)T8 z&ayY!?1#G1DsadP&f9Z@$9#BYhH??Q$%Ef#n0X1$lr#Grj&<;-%)L1_^?`TWK3%{@ zk>R*}EM&|aWe#Te>EzjendcGCA-Y4_jAxkH3Y}wkCDTTZ%`Du^6J`qE%xBCak4 hi`XttiYw1tnbI#BC6?-Q>@7XzE1?atW z%XVjas &t9`RaqX$l=_s0X}6f&;Hul%KRA_j#-?u z@@bPZ38l&;p2J)j_9pE8Ch3{@RHiF3y>Z=Jr(^hbj#@ALD)5g){8Pl5pp;TQWc*^A z=6ubJUe-tOr|{XXE42mwxhLwp@HtlWhW1R@!qRV$9M2R!#|zFuj6YbXS*m94UnVjf zH&}kg2G$ePKbt r<^0|*s z`Mrg2)){CkM=`^zl75cqR=RzhwF>1Ud@~=i{iDZk6h71L>FN)3^_ZqdAA~X7^sDUC zJo*XnjiIw2^XP+JI{Pb+ej@y3;9^1TMZ!l+H z!ehJl^G;;l5gyyTpLY`Lj_}ytIghq>T02a8xAZ}%C&qTRcTe6c8@6$eK3ElqJlnNL zhgCvnTlVNDsjGy}Htf+)R)s?E6QB=KMM6J3KtDwl3;hVtxgKEiRZThJ^$qa`vYdo> zWQaEiE#g|?^$YP%P$#>3M}>HU75pW7{X@JHQBS%F@8}SZ$N!bea|YW@H}s==rXw`d zPTBWd13JfynMlVxZ?WARfl-IgC2WNpgC@g%_C7sD#yq35zcyPfaug^No>@B}k0XP9 zvVb3jZ`Nik-+KnRO89J7m9Wa_+c9X6I#Kv+U%fToYz1m1DuvH>X87#AX6Ssd*R=7o zz4`U+)1T#=wI`-O34JohF!OZSr{5rW)y&DvdLPTi(9GP|%!iDh4V`l_Z;r+~VCbBO z`PVK73f;^hIium2!8zJMHAr|IZ@O!Hrt0#raj~!WkEvIQJp0>BYcVH^jP2{qoQ|Fx zs7?|d>ka47rZ+dEvCS{*PbEfPuI ieEQbR*F0UD7X8aP1n2IV z^y%l|d U#gho4AhpadAg>LL)8}**MmGEd^__^EiOkK5eBGdrUv31qdH_SWwabs~~Yj>n! z)<{rygic#IzcJ4cTyHS)w6`3!ZyrjLPZ6vibA(5m!{s+uc(l1YYNhE7kz1kD-g4BZ zD|B5pPbE`@N1J MNr@iY7~?iA&^#@1!{aFmW#2E?^&8g|&77a>jk=|%T;bDyy?uVNp0xVLkJO>X zS3+{O8@H{S YX_-*SA%1d~rEz-8OeO{i(FyBXL zKl1mMnPQFf<^6a_vB^g-*9Q6>bw_y2L$KcBvti-UcFvv6Z!TOT;;I$og-_f2NZR(v z$E@t5_ZAsbX5Oy^lMr8}@JyK*9&P8kbzFEXGyaZ5I&(ukB|KARhG+CpFNMc?Uk(kf zPhJIYnDtd2Ly^u8)H6K#;Yim anj!ZI5@mm-XD)V^xppo@KqZlvVfIP`1BpSJ|qv6~*g|n~Lj-$5p&up(+ (YB&-UAA;v-)&{LRJZBfYP${TR@H5BX? EP0`(*50bb<6KI zs<^ngfANN*0bK@kE$zC$%j;dXcG=KnRhNZb_H^CWbwk&cU7Nbrbsg2UzRSv@4V6um zD=W8F4yhbpSy!~ZWN%4Hm%c^&3Y&^Hlq8Fai&mEGDqLT ;3C%>X(NB*#qVFeRQ@(W7KQ_i^Z7H6Nc(`j|8%eR(KFJD}~ zyS%t!ZTa@RO?fSOi}UL9c61t-*V<`&=X*L;cOH BFGVJodJGLdZKDHv(6kFSIa7Wc?daR=3_>SXZdx|SMZ7CiQ zTi!80wpYF0affQ?xEbdLZ0XpnhIE?HsV?L9|9rgR_y0!#a~aHj|F3@t#698Z&P`_3 z)!b(I|F3-i&*;peTZYKmkfZPa+qfhmL>`Dd5P2Z-K;(hQ1Ca+J4@4e_JP>&x@<8N) z$ODlFA`e6!h&&K^Ao4)ufye`q2O zyN>AC7nr}u^Yg9}ggoER^KTxt@6RA*g?`=1rcw;A=uXEAIsD+^RCPT5%xk7*6M#85 z&7QB{n3tyJ;AI Sjud>ux=7&9BZ(YWLNY-Lhq z9%Aack33brggFWp@ikqZ*KShh$Eh)O(}$4yIf#`n#PPK$^Qn#b7 Q){VoYuS1m-GO7XM0~I0D2} z^GBSgpl?T`SL5rf?7_{I@vnIs?Dmh<7Sm^3fl}s166|#+2YOj!89zXasa2l<%g%?5 z>`C}awy}*bpT^X^p8(rNp#^b_=WFf!DA0^r#!9|l7*iD(H%DXZmEr2M7~RLKemy`2 zo#B=bAqTc+O*eAZN(mpt2&%0zvx$$(s)HCwwN+-8@r@6`SHU*vAGwYX%(D(|95W?p zW*r~(I3Kj!?L)MG%uM6Mn1uyX3Hm3 E{?cdJ{cErwBt9On@z`ZfKEht`_?)#J`$H7QCaFn) zJp-0GewD$1y^vju@Fy@z5n3R>8L# g5l-!AL<`~&DG1CM&y+?Q}-TRKM3Ic1Y9$%zu>x#e4Wp6Y8)V(Pp| k7L0E>}6ZT~A&y?nl}-UqNelu9MdEJCRV0IiUx&3}Wum(Lw)2Vm{M zWzIz8mHDD>Gp_#wz}_{9Yo@gi*L4UcpO>mj0ls{?emxyBo4 D akcX>^sE1t^SNrb<9(TJJ-z4#DK} zIrSVMT|WCkCR0B3(hK;RAe_%{0+L9dwtoO6FQ4C0-vO{Z{BgYw;5}_-$1xaz{m_ja zcB-9#_ilbH&i2VNW&QQ*D)oaO#3a6 IcO`vobhS+G{J)atREYZP8Gru0CQ9O&2Ov8iTBidfWvT)r{@=e)I)&zkXw8T z0x)&gW0JE?tyAk0H>;Zglw&$wlL|9z>as- X;og_~~sX$*`Ye;^z+l z!T6%P$ODlFA`b*TV7A1vpK#9!GXD+lo&{9xTIz5N;FxXu^WWqYr~&|8^5OO8;c@uN zE2IAW->}j}S&lsLA$cI`&x4Mf2)G@vqGp*hEVQ2R69A>FKu>}{3D OfM?TtL|`1-qsFv_yw*Z{!Y9uaevN9 zx#MHMiOtTB#W1owWvBXl;v;aw3#BgXeIGWkFwX(@_x~#2L%|oTZu=Rfvq80fio|9$ zKN~tY_4?4k9n_wL`n3K#9n1dwX>*nuiJu6#9|wPSn}Qz#xYGuIOdp3`+DAfaT(%UV z9RRX `Dd5P2Z-K;(hQ z1Ca+J4@4e_JP>&x^1%Op547UVgIL`E`#-;yBJj&RrEcjxUGe>L{^W0e|F8D_{=ea$ z-^OWM*#RG6#Z->sYx@yI9*8^;c_8vY `Dd5P2Z-K;(hQ1Ca+J4@4e_ zJP>&x@<8N)$ODlFA`e6!h&&K^Ao4)ufye_Ni3jleKR0}i>!0{>agn4F*T4VgslWC< z3KakE|3~?L|NlkjFD(;=Ea=iKydW#)zHJbsXS<8O{?F!}h!=Sv@<8N)$ODlFA`e6! zh&&K^Ao4)ufye`q2O `Dd5P2Z-K;(hQ1OE;lcs$GZ z|2+R|Zto?kKd}Gz|FOQ`|0gD2pLZZXVgCRgId=2`_xfi#h`U;uW7_5ozg2zqYf4$n z9SHJcIcgC8PQYoxb8*&Xy*{1U= N?LOZqz30bdpLnNjetC zB%PDgN$O-AMsT^h495}7!+Fp=4cw#^%c3^|XXTC*y-7I6fM>e%H1|oMT@8D=VFJ^R zBaZ7OZHsN%V{jt!=@Q2r=ud{_JVTi$CWYh4$r8^nH4FzWm^@4Yt`BI>)^_A((I2bE zsxw6Ya_CN0SHY47_@hC4g9kRuqF3Tg4)c_UxV|iTve@P+sgkGy))s0`l0zS+7|#w} zqwVSNFUB!XJY!17_% P&!Ay#bU0B$}M%kb4f7Y@_qxzZZ*cRks4jwvZbuQ>$}U z>o#m@70_ifehSbZ*G%)rxF>D%-|tl~#qY|y3!vTwh|+S%G0m;GABDj5%8UP~{s`!s z+vIFV9289@1{3|u@B;vqT9F2AdLGw2jfDCCWnzt51Goa^)hMMk6}*1}@{u-edja?K z!-Tu;R!xQ8xmh4-7?b0jFKKDJpTAFE^1PM?#KW|CIE$A*v|K _ z@HT Ng-R+QdURZN5$@ zzF*xBAfGTB{XFy48-Hz~3a4a#@WBqmLz`cMfM@R|>Jk8TMuA6ssP^Uqs9%zgdV{!j z;JPb 3A$|;q9^}m)*vP&!3_L?zAzu386)-77KfG0VZywK)4%d60 zIXxfp%=4>|oxp(ney?-Ast4d!1IzN#E@P$kTI!+WQvj{ZKf*3V!}?1*KPVciSe7>C zDqN)NCwD@R^@??KH?En7*Kkjo=_l9atpjkLx)1PMKrPx7)BFu&Mj @+^Oyam|1P6+5Q$lQmuzRZG8i})-SIXtxzifAZg%01HUBh%ehbS+MZ**6?(jX z60i%`v}HH$Ni*erN*?Rfl*=!hG VZv$ALst^}#-h*pzo-OS!#+Fr7v I|KWfnMyLLWi#Bo6#(vVw56;o!KzJU?F{A _9wB`yFU_`TL#X^G|)3CTA3QjO Uj^78j0PEmjH z#c=*^1k^&Fw!I5^FMpS-%K@~9!1k6ce JG=6>-^m`9aa=)#m{qX(-13bp31vblC>_0{Y{cHvbLxq?vk|$V&id=Vt&* zu;{ZKa!hj{XkNaqR96Dt1${f>$Ok^ueANJG?+(O4oBob#o3C&`QjPk{d}W$vvl~fb zu1cHV3)uT(^ j-^Xvvfsj=~&5N<%= zxPM{(=hWu_^*v1*wEJM^+0BTL^&%Y{Xr5gRs7Ah+_xBM&3xb(vqeKBK!21J$6_IJM zpWlu2rX!q)d+teEjec^yx;4&qj< icd25bR+0{VE?f1bq+B Fdz5y=?A#)i$H%~od33Z z8?Ybw0!iDQX`cNk;PH+f)Q}z+#}F42YJrZKXWy=PZY<+C7)S<$($BLOBAtNPzi=}i zy6ii{z%y*8gGXO*&6YCs!&`-Qd3Atry+0AK3-Zi!9P-{g`}^wq02@Es^@lmn-UH~5 zI!;@2kgn}dJ}7!zalUHP-2#5PesUCaStouEsKqt&z)q1g(@*|6kIxYCq*8poP>|V( zz%+9qHwtoQp50Y-1&l)5-;X#zKIDGqbO76hLR_>dFOaViRRUoAgpB<^beV_Ifd06q z%^d>yx-9Q90OKeGP>=<9a3L+jFK)o;!O+ z;PV9QNw#s4&lA%T4{h!gu=hdrAfN($>vr(ie;%s6{{Zwy8p{!A zb7!OzhxshmJ99g$&H#LO3Ye}t?j4Y!O(nj3y;yXXIt##T6Y8cPmUh1VF7%+L4g)CI z&NRD#K$ jP+oJZ 23gT1=3*ub*TBHt<$hZ+JLxdb1$)%{rU$*Th&&8wO9I+HtX8W(4`Hx z0aoIgHnXCVX6ogFyafP|)G>f6@YP|MX8@N6@^!8{7cd39QQ+|hg+tAk0~m{PAB(tX z6BpI(_;^CGsh5ae1MSS#kFdV3M?AE-GGMRw{8Rzn|K_=!&sMt$h=(>GhIG97_LtO` z0O5HDas+t){f&^X#hjWp_J-bA ~Ec?$K{3ZoB4JjWEd7>uAR)w zJm2Q{U!{8(rLG24As*UTg>)LA&w6rU{;TR$K*iH0jVjO&cD_9f@gb_TaG?42Qoulz zakUz(>eOack+Ut{93LCsAKMgbj8(_>ftu<2|4O9D@BfbmX8L^gV82!4Gv `Dd5P2Z-K;(hQ1Ca+J4@4e_Jn;X^0}EqyG5!623~zV1`~UL| zTS7PeZpE>c>*B}Yj=#wB8;3fCn-DBq@Wh+1*y~KV1aIvghX@$QvGUVC5km*nO7;v~ z^L7CL0f-oceI>4Wi`T?7gxFUJn=e}sLhO2B+n3@)?5l-M6VqtV%&t8vJG(*H^G)1g z(>|Y_JzLlr@;xUz`wU?>0jJ3r$>e-V*c8E+fD6Rue5;fkz7 e4T{gv6HM0b2GDzeDpu^K;(hQ1Ca+J4@4e_JP>&x@<8N)$ODlF zA`e6!h&&K^Ao4)ufye`q2O t zoY+6qPW71jhFYMu$Ldtqcx`-OJjTsfxG9qc{>o42ik;)}oBv@uW1j*h_eg~P9kJ~U zu!TR5-okCXvO-?flZm}GPjU+hKnfwI@`hckG5!G-B9O-IU1$t}+X|3&rpBZw)f0g< zT4wDXAT;jkWocg)n&IIFa6AHa4+qX60Z@iOS~;+#acdRQ_?x?pk2xj{nRjW_Aq|^D zxHP^yL0ShN&B`%d8y|O8pj;Bz=Jzn6ahEYG$6wDWXLn%0t*Yzd(X8$yAB{U=5H8m= za~=Gj+7_=PMQ{9zf33rp>LR@xH12Om@6JHr{RIg0I=yS5 iLs6a{Azi6vrxn-CAw5o768fsH*-<-}IjW)Ap+_0) ze&Lj@Ze6JNz^GGIiPm2&bE=+QruXFG1}Z7&|0e#7;-1pmUs&SQPhR8<*tW#kbonA@ z;ZK)1#lYi!zQn26zQmb0X_2$GZjrP3szpxYi%XnR;PvM %|b2su-g|uqlU#o_y zx71qz`Xd`W0hm60sZ;yZLT4rfs}RPWwoa`qxl3{X{Q8G(*Lkh3Gd}jmRSz9*ufOu; zg-+|prOx4CvIfy#SM_>VZ@s^!*B!2Yc&~KE-vN+ ie**;VfW)YgU05L~YxvlM%Y9jQvLSmca7Z>jT5(AYwlpUXNXu)lXAK^>OG zzR$0t>(v0r?%uJ`**I#ca~$p`Ak@xSr{0c#L45)6?n*EJ3FH%O)qFY1`XIpW^Gi{i z-X7E!=HPfh5@}YCUh1%avgv*$HdqY?_|vV2Zy3j($(hp~(A$)c^-dY$orw4o=Pz|w zuigig;Cd2(d0hiO-;46nHT!$|)7^=3VY+LlWlooT0{zOgmm}Woi2t6mmO6`(-q_B~ z&M&~=o}bKX70QUcftT(p>J@-L-BptA)+-O3F54i}&PTlC5dW|j7CHk?U+R>B#(K02 zz`Q0=c6tvg&{@7;iFH&R0seF+O8E|`KXAIt>x3KUIVq&O8S!(}VLhuZJ5QYlm;f02 z%Y{zE(+l;!kIXOaIkEE|#XbG}={7?KY}I`A!KFJMun*}DLtrnzaIBQm7Z*9)i;#I` zn>-Rcn{EQFs|w&xcZ1}&e#U{*rG0EK7VbI2q 7Llx z?8oa*cYx%#c+P>-rJv*IsduAH2mEBATfW*3?El1lecAr4U77IC2c;eBKHT=@rp}fu zp69e)u++H`6^VAQY+0vX>tN1b2-pod#=muLvr}>PBB%7Gc~1T9^PE*P7qv;Bb&}A6 zvbpEnW@p^ aT!}pie+vK96+AgTZu1BswYDwEMrk{?6(U zGhSQ%YcDqO_5I;OXU{Xn_l=0}-DzGrR)?79Skw|GH9ITMUg|uL$mnOLdr9F%dgnZU zew!{d@$8v*aP{M}h%5h0^gGCF0;4w5d>``yV(!gX4Zm% Hm-$_Zyfh$eKp)He`t9Hz zfy*(Dax5Jv>6&r$5ykx;{pGtBGSnS6^}y*;j`ILw0(~4u4mkJYJ@?d9h;KfwSKid@ zJo4l+r}dd-PCoi1&ix4Q-n&-4tIYoW6JNSbpY?HSY^Y+JXB%un=7vCS+njakiJo_> zy8$b1HT7aSuz&8O55Lf{rvLXhK*@w=r}iuJoD(Eore6?yJ^ngi@2j`z_mJt&ieD^q zxF^}>bC){dxluUw?*LlS=2K|@cLwY=;|=X)8x7m5D|a|D-#zDFEwFbt0-vMkhyACo zQ^WHYtHpp!@gB$zzXq&9A2k1S&Cb&>Ovj6M*CF>=y+3irct7AwJ2P;v<2CSC?KO*> zlO*14)$7zNhj)&%txs8N{Gd*A<4C$!Z7ytoY s&=VU z2ffzM1pA~drKW#*73s0xFwaG1e{$R^ZY@qssKRs9&VZcR7nnSI{zHD(W@iHAUiQh6 zulM@~-U#4*YR)2OIpiMZ4Il~ohAOkKEmZXx7^H834Do*<&_2!|rxcp~eP0KUd-syR z5&HSa+jo3&6AI0KyyUllPrM7b8glD#ZQ~=Id&v)bb(!Pl12Pj3Y^Ta}M;2bDxL@+b zSC%>4FPVCbi&z2Y0~tB9Kl7enFLM|t*}G6z)<9+ru5G$!7kK-CbFXd6r698n;Xa=n z>2;u$;(3kxiu0av?L)YiHvp!4Rsr^a1Pp^5_b{J{ll&ML`KuAEedPt8i*sLi((Qb! z3S;4XwC!)e`AJaCe(g9N5kM(h4@&UdlEm}iH$b!Xg?yezz`Dt^26#Ufat)YA-h%7N zfW1%R`4@rtPa-h>q8wAtI9D2mu=OI$#Sr#<4)Y9zVuV!_FsDUeJ%^g2tW9^QGUp!A zw)JR_yD``LJY Ljw z%#<6?pWzuGDLlvTz})Rh@RA57{z_E|_*d+Qs`gv+jTlRCJz(=PXDnbB;$Mt8=oHYB z2*y8W==0Aec3 ms-xk1>7KkC!<+w=Q!yzq1gW-^CQqQd8qG z9zdW9 9~S`_Up3+&otXYH@zg3#^~o<#1Gs>h z5pn@!E{Cs5;5T;0j3 Qj1nd0M`5oMC-drG!1biR&jCP07uuGE|x)pwKkJi+Hb`%L(}v<>Pr ze)c28JV~kw{lPBu #S{i?*k e z3`Ux}v2VX#V@LblkuxDS9qpg~rPN@Q&HCx ui zCYpXHtjB&k8)Ql^n+|!Y4Cx(6??Cog{lr&{5BmT}+l%yu NiUpU{tfe-T}$UVQ{f=iS2I5~=Q!-V zex9=eVH`pNVH14Nh%f+Q`?7gXGr}l@{m}1=cs2mn^BQ6266hj~Lr5TO!m~Qhd)Rem zv$OHyX6O5;SYCSOeBlk?)g$yp*m*{?vjSlpLIPpa*k-2@VF1E*= *0U)1bu zK&VIPi?9>xE-Mgt4slB(o_|I+JNz2kOK+N*251Ct0K)du5f{QJg#BX>7eYNkUxb~| zU4gI(a^rv#ydDKx5C$M@$C^nq!YG6j0P`{aatvM!UwZwGIe(Y^js1mplZ?N724a7$ z8=n-Uy>C>D)habVwq7;IHme tQm2f>Er8eU3tdoNe&Cus;WWWx1asUWTw##n+@8Q^O2S%$ z+%qA6DffR8%rn~vy#<$OZzPkND1CvhPIS`75tdA8mt5 g z(IXGnRFGM-TyksDk~zA$ nW*^8;qsW)Qzajt({jkhf);~c+PIAd-WHdJa<$KmSpIM0^n zT+UY4=>Nxoel5-un+oc2Y6`gZsM0LncSmR|O-~!c>$%fo!f8ncIDIe$5Z8!+qJR$C zCJJyRm|)^g6N8=JNv@Jw+9u8z?0nM*=;$G%$AOrlfSprF4DLkKwZXPOBam#H1Yb!d zWK6>LEM5$ZC7E=Sun!&?W3YXe5eO9?b1_+4ki~`>0f98Ru!DF;8@?QfA&m{o0s?7V z{i}cgV=%$>gPqKI*$fFxmKu{$;E1?MBV#V+1O(FL;)el&T}cz4ufi0_5}RiOMMR(y zhb{i} A~UfAfn{k<6>v-S6$gzoQaix$L=mu$1YpD+FWCKIu;_~j*)H4of>3`dN1 z1x^kbXtFmQ7&g)vl}Z}ie*bMhXf0UJw{`#<1-A-@^EKQm_(8$X2;M39&w>l3pY0=f zh~RStPZRtl!7BtmAowZ4FAKK)HXn!yhY3DW@HoMf1%E;Ce+phB_zA%;3jTxOM6QXq zT<{>lX9%tnJWudVf>#UPB>3lo-x3_-sxzQW@bQAj2);ycqu^zN?-u-h!P^ACA^3g4 z-Ps5L0|bv0e39VK3tlYvn}Qz^{Jh}T1^+{ER~c)L7Mv7(q2QT B&d?$;l+{0I8Z|@ZU{R$DITv$puoE?Ad*6fJ{k1s^&QS4@grZRZ|@%8|i_5 zvS-O4KiSLW3F*mvO~*~rvzrS|F4?pD6hGNZ@>D Ct|&mQFIsGXi9g2&tMg@!z#XB}pXt zEc{PHKF3dH+$M00cBMV?_%Ipw(BRLpuC! *uBX{zXb&`lRRkQo8 zj(Kh*G>(v}>C-uGmb~>`DXFO-Uv$D>J+f!u*Dic3-;Kn}PHxN33e%A1?S8a4NY+WN zFMf!ohewh(tG`9led7+TNnU*IvXUTKN3!D11)NERBe^8^kv=Zj%lw4 dxIePAhu0V0FQb z1(OPD3Mvbp>G4eIGhG*!l*Ql4*_QM7P6Y*T<&`GtRE)iL`~ykoBEfO}`+uJLYj4hD z*{5-4J)tAszY__f`De5)_T6T< &x@<8N)$ODlFA`e6!h&&K^Ao4)ufye`q2O `Dd5P2Z-z$eTD$-Mo!k1PEC&mZ^Wc<&4-hMnH|5@}40(q9;^@BG)p_`)hh_@2&P z2>*#-p~oM$ziqEG;S#-j{BW@KmM=OkE6cZD35-95z 0mdTcb(8 zF<7u^@;-&YH}VZXY%Tr9VBrm I? z`=J@GeI`wQ(7<3JoaR5EY4~1w8co&_1`7-1f?i1>bVtu)_+d?cEx}+RoaTE-)9}NZ zeC3J3Lbwj`3kAauYjSrfyTcTQQG0zMMK@WYz8cX#c=rSfa? z{#XRc_ `{g^7V23 z3OUsPs|~{cWN%*n9ktK!J AW 9jAkxq44!5%P4*__x7D=$P$o_GCgFa_q-pyhs~K)9>`B7? z(CMIgr9yiMeGSsqr*NHaZelcTsfa?GI>cHK9vzIPEtO1~WnhF$#c0}6$)qWtUV-h^ zzOlGFw0s)Pa6YYvXhRAiT|SLwIG^G6$(X|VG@9XjE`X$k6fTZLpiJ9*vSyjurP*qo zsWAE`h5yGQ7{2Er_DzT8A)^`gkj*FQDTH+M1fv=D5Itfcg^TV8VGkM2L-CN&40|X% zI%M{cZJ*Y{u;xH8!tK+f*#R5|3lG6H`DQrK9^!~(_~BB?2ZzCezh$RDJQ>08! a~3qi^8};GLYIQal{X6VI)yL~!SKV@hUW?4n(#$v zhUW<;&G0-Sta&3e!}A2Ad7yd1GH9B4MA%yPie?^w3&3h$u2Z<@6M*4|HQDAFEQIUO zSHUp+uqMCtWv~#g@!tf)@WYxt!C|nl+NYWVkx(=u4_ z&*M`d@_EJZ! MNouNc0kc_xItK7OUBRtvU0bpm69nL~s%Z69wnhlnPnQwY?f zjDJKjX|n%j2y2p-LP)m~VKfuqGK4ij(weYQ^V_Cr`}j