From f34120c0777abd4f2053179a6d0e0ad15c7b1fb3 Mon Sep 17 00:00:00 2001 From: aliabid94 Date: Fri, 17 Feb 2023 15:31:02 -0800 Subject: [PATCH] Support large files try 2 (#3191) * changes * changes * changes * changes * changes * changes * changes * changes * changes * changes * changes * changes * changes * chagnes * changes * changes * changes * changes * changes * changes * chnages * changes * changes * merge * changes * changes * changes * changes * changes * changes --------- Co-authored-by: Abubakar Abid --- CHANGELOG.md | 1 + demo/zip_files/.gitignore | 1 + demo/zip_files/run.ipynb | 2 +- demo/zip_files/run.py | 2 +- demo/zip_files/tmp.zip | Bin 183862 -> 0 bytes gradio/processing_utils.py | 15 +++ gradio/routes.py | 29 ++++- test/test_files/alphabet.txt | 1 + test/test_routes.py | 11 ++ ui/packages/app/src/api.ts | 25 ++++ .../Dataset/ExampleComponents/File.svelte | 2 +- .../app/src/components/File/File.svelte | 58 ++++++++-- ui/packages/app/src/components/File/types.ts | 6 - .../UploadButton/UploadButton.svelte | 19 +++- ui/packages/file/src/File.svelte | 2 +- ui/packages/file/src/FilePreview.svelte | 28 ++--- ui/packages/file/src/FileUpload.svelte | 17 +-- ui/packages/file/src/utils.ts | 4 - ui/packages/model3D/src/Model3D.svelte | 3 +- ui/packages/model3D/src/utils.ts | 4 - ui/packages/upload-button/package.json | 3 +- .../upload-button/src/UploadButton.svelte | 41 ++++--- ui/packages/upload-button/src/types.ts | 7 -- ui/packages/upload/src/Upload.svelte | 70 +++++++----- ui/packages/upload/src/types.ts | 1 + ui/packages/upload/src/utils.ts | 10 ++ ui/pnpm-lock.yaml | 107 +++--------------- 27 files changed, 265 insertions(+), 204 deletions(-) create mode 100644 demo/zip_files/.gitignore delete mode 100644 demo/zip_files/tmp.zip create mode 100644 test/test_files/alphabet.txt delete mode 100644 ui/packages/app/src/components/File/types.ts delete mode 100644 ui/packages/upload-button/src/types.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b218b454c..e61f40722a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ By [@dawoodkhan82](https://github.com/dawoodkhan82) in [PR 3165](https://github. * Fixes `gr.utils.delete_none` to only remove props whose values are `None` from the config by [@abidlabs](https://github.com/abidlabs) in [PR 3188](https://github.com/gradio-app/gradio/pull/3188) * Fix bug where embedded demos were not loading files properly by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3177](https://github.com/gradio-app/gradio/pull/3177) * The `change` event is now triggered when users click the 'Clear All' button of the multiselect DropDown component by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3195](https://github.com/gradio-app/gradio/pull/3195) +* Stops File component from freezing when a large file is uploaded by [@aliabid94](https://github.com/aliabid94) in [PR 3191](https://github.com/gradio-app/gradio/pull/3191) * Support Chinese pinyin in Dataframe by [@aliabid94](https://github.com/aliabid94) in [PR 3206](https://github.com/gradio-app/gradio/pull/3206) * The `clear` event is now triggered when images are cleared by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3218](https://github.com/gradio-app/gradio/pull/3218) * Fix bug where auth cookies where not sent when connecting to an app via http by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 3223](https://github.com/gradio-app/gradio/pull/3223) diff --git a/demo/zip_files/.gitignore b/demo/zip_files/.gitignore new file mode 100644 index 0000000000..8e9b8f2027 --- /dev/null +++ b/demo/zip_files/.gitignore @@ -0,0 +1 @@ +tmp.zip \ No newline at end of file diff --git a/demo/zip_files/run.ipynb b/demo/zip_files/run.ipynb index f8f70a15cb..21810513c7 100644 --- a/demo/zip_files/run.ipynb +++ b/demo/zip_files/run.ipynb @@ -1 +1 @@ -{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: zip_files"]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('files')\n", "!wget -q -O files/titanic.csv https://github.com/gradio-app/gradio/raw/main/demo/zip_files/files/titanic.csv\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/zip_files/tmp.zip"]}, {"cell_type": "code", "execution_count": null, "id": 44380577570523278879349135829904343037, "metadata": {}, "outputs": [], "source": ["import os\n", "from zipfile import ZipFile\n", "\n", "import gradio as gr\n", "\n", "\n", "def zip_files(files):\n", " with ZipFile(\"tmp.zip\", \"w\") as zipObj:\n", " for idx, file in enumerate(files):\n", " zipObj.write(file.name, \"file\" + str(idx))\n", " return \"tmp.zip\"\n", "\n", "demo = gr.Interface(\n", " zip_files,\n", " gr.File(file_count=\"multiple\", file_types=[\"text\", \".json\", \".csv\"]),\n", " \"file\",\n", " examples=[[[os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\")]]], \n", " cache_examples=True\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file +{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: zip_files"]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["# Downloading files from the demo repo\n", "import os\n", "os.mkdir('files')\n", "!wget -q -O files/titanic.csv https://github.com/gradio-app/gradio/raw/main/demo/zip_files/files/titanic.csv"]}, {"cell_type": "code", "execution_count": null, "id": 44380577570523278879349135829904343037, "metadata": {}, "outputs": [], "source": ["import os\n", "from zipfile import ZipFile\n", "\n", "import gradio as gr\n", "\n", "\n", "def zip_files(files):\n", " with ZipFile(\"tmp.zip\", \"w\") as zipObj:\n", " for idx, file in enumerate(files):\n", " zipObj.write(file.name, file.name.split(\"/\")[-1])\n", " return \"tmp.zip\"\n", "\n", "demo = gr.Interface(\n", " zip_files,\n", " gr.File(file_count=\"multiple\", file_types=[\"text\", \".json\", \".csv\"]),\n", " \"file\",\n", " examples=[[[os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\"), \n", " os.path.join(os.path.abspath(''),\"files/titanic.csv\")]]], \n", " cache_examples=True\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/zip_files/run.py b/demo/zip_files/run.py index 191bf4aab4..1ae6436c67 100644 --- a/demo/zip_files/run.py +++ b/demo/zip_files/run.py @@ -7,7 +7,7 @@ import gradio as gr def zip_files(files): with ZipFile("tmp.zip", "w") as zipObj: for idx, file in enumerate(files): - zipObj.write(file.name, "file" + str(idx)) + zipObj.write(file.name, file.name.split("/")[-1]) return "tmp.zip" demo = gr.Interface( diff --git a/demo/zip_files/tmp.zip b/demo/zip_files/tmp.zip deleted file mode 100644 index c98df4f931e47a80a96d9e70d287f45a2349847f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183862 zcmaI9%Tip~lC8bX&VM@Fta|4G!qh318A%cZ*CscKOo5~=v{P2q3qc4X6%eWbq)oQZ z`<_?$zcJi>t`&f)(spG^u-2N>r(cI(=KDAQ>;L;df7Ab+e)#3%f9${bzkmOKfBT#M z_rLkOFVop%?fv-nc5-t$S^Rdfa(2J?KK(wqSb2Xw|OHj>F2X= zEAPjP^Q)DQ)AO&ByOmet#bo7R{CRq_a&-N9y!bk~__x0gSJqZWD=+pJ>xHeqhS!bcUxzdeT>8ty@#bm~wa;f9<|GuBx4vr_|yQ{&=lj-bX za5{b%yq`>Fy(MmXiNoP&XKl2yIa(dA91Pb-BEV+QZ;w}MX^`*JbT*rguX*Lo;voq* z(yu}2?a{{O+RD!AT2N1mW^bqS#W)}Soii+|$0MV)o$YNN+1T6}t*rdx-~PVM-$U}# z^Mmo??&={v`f++a=MRJ5^MjiketNjQvBiRit2z^OWujEz8}wSZ|C~%`1WqX z!e7sC@5Y0Z$^2%#xTuq7eb9encXw@fWqr81wjC?q)!(kX&`HNTbnfqN&&P|wr@_mk z+4Oe&c>+cMn9i;yGnivM*qNo zFEsz0ju)5rlg0FIGWc+R*BB|-?&b!Y+*;jUd2OlK|@VL006#MZY~H{s(Ue51XM_=#78v`rT0^YgFT;PXtguGd)VRuQ|+VaGRY*RR>r zOY#tTN&HdbH@+#x(?M;D%xg%)2+_&|946!bFl-`UylJ=< zZxK&Goe$G<$!D_V(f#G*X43dk2Q=DQ-`ZSXS>Ih9O1cq>p_B+rlfq|Bv^qGr8ZTx@ z_tGm&)b))GgmH!Q@bY)#!+)^t$zt$+Hop1VG{pUEdJo?nT~82eR<+>&`xme0^Ti#^ z*sC9}SL3_sb*I8&U0ZM++Ev?vd)Lj?D=%I> zz;r3#aZr)pUr?e1)C!fx?RF)QTQpG#1Z0TuZ0t1?lWI#dSN|d3GZktCbfY z=NI$E{L7c(pV@TY-wC8%M|62`7p14~vomkzpNsqRt9v%IGB}*ytRgix_mkP+D4*U4 z&1RFowFakduWqlW!XBlbJ^Lo7q4a+l)i@)`qXcmhl0EH-Af#Md314ChVr-y(_2&KU z9Xk`r+plK`R8hxTYVQ&UpyQ<^%;py7%;G}Hj3hBqGFOxFg)Jva_vqpW=5lbHTiXgp z^q9T zme9Bae*QXM6p=+peqDBGcLjCnHEi>j@aZXjM)KP67|G6O_sI_plbT!JkOC+@}i#&FvzbwkU90()089O34$j&BApE%9i%_t5rYeuq

8$|mOcOGT(N zd_~NOO&Ok){u9q(F~P=`OYY~+4t^zmnBL-ipxQTvt8g=1q!-H{hK7fe@8hsbK1ogx zcAne~4rMCa+fZ88CsH#zeKi9KeH0(&1T<-~`$X&S?rim7_1C@C4OnZ0RCc_zkxs+O z|njc&3tz8%PYM8^Q-a(qy)Z*2l*Fq z&LDr2y{qdwa#MlLDh%Y}oGV zRv9mJgJ1D>e)|I}R51l^82%F`Y>Xs467pX;2t1A*YyVh>R4dwzz%lJTM%FRV;A}RT z@OS9!2c+wG{4We$w=cQbd_Q#dHX$26w^YxeVn70{Wa3u@sCQR$UYEP#TI z@W6wWVIbnfC9}OAU*M%%2|BX*;r{Zn1XGR& z5n~FWeLp@SOF}p+FQzPsLk!sW?fm;hoQoyF!rsn_XX>1G;BB_+#>IB7vVcs?0Y$gAm;mSSW(3L>FTL5&_Zp5J43nsm{7sSh?|BbLy*hQEV z`RP4X)_luNcxz{EWgi3kZ-2*i^7+H9D1abgFzfzw@l|Y(3NSojU59u;NBrB7RsI2i z9cQ?eVc6N%`CNyX6yTlXSq0D=s2PX3Yda`(;E33CvftU=1n@BB@ z1m$`z5UtM6gt4T!e0Iy9J}SBM>DjeC)7 zxU36QMLIS;A0H#WA$l6#kxDLjXFK_kSTjTFKc;Z>&0obrh(0?R5l1_cMmGl|V-{?> zf1li-H-Zy5mTy;h%m?>q>L2+A9MeXN5%vJGmOR2)R-m0Qcn_dS*ufjZ=}xNgm!A~_ zn9IvJMxJ63d)J>A7=yv@O{TR{Fs{{i*uue(&>3kMrE|HRym)Z6nBUC5&F^RPWb3_e z;5u{u*iph;-a;6L8{kTc;b9B}+efiav>q!skxLL5UF>}*XMJ;Pb))?K?S^1YigeS< zd%44?qfUH76^%A_b;r}&8^BUI-JMr0@U2y8Jv3EtRwN*r2 z2P32cM;L+7szo|GK=U8KQO$X1rl@I9M^dbGYh#m>AFel#aVOQ@r!fe^O&t~P0HInP zR1n>0!uCpjSSk;BIlG!n7C5klAN>xS?T^3RO>awYrReHuHoTi`!fyQh>G|Pg0c6;0 zfWX;{C$3x2562DWM*-Pkz@F53UBOy1UFg3uEd#p;}W((JW1E$s~h~o_B3eIVq zhGhMZ(7>)f1m_$~W*mDi$%i)K(CWx^u>9J_NH}4`sdtlEQ7$mpbr%QXu+)?3h)d~5 zWL)d~w0a~k8f}6f`WJC7e^v)uZbFN z&#$hh7wIv)o&bZ9SjjW6DN9e9097oxB{J?gks^@KZz0mV`NEnXad*<9&NIkv|AVy5 z%GPLgB%^&eTpJvMg<~+t)mV=n&QU}*8Hk~S-H(FlLC}Cs!TskqJ$%L(3XhG3yZ8k# ztqx`gv26X`jBoDd380;UJWq2qJY|~&YK#BE3B^;%mhUGV;?3k7MU>)kC$aBDBNUOW z2;N-Jir`iAU4%k!XgC)+wmY&7gO@M(`y2h|ix-3|J%hrF;ESafC6|7>BB2lpvBD>K z>$ZV1cIwd_o9h^WZ5Tu<^^gsj3dx@hd5jl@_JXpF&2Ya&FwR(9;xmpHBzt!HF5VE{ zRV8DJrVvuQw*r*Nl`Ay_kvCONr??V@IGo+hA54oN1YUG#3N)4ij0OP?`J)x|*?9K# z&&lle`&15@4+gAZJa{7=LWJ8LkB*TK5@e$V>>k8!GDtt2liYNWlOD3^vveSYwCE@- zRLbd)IL%x5F!?$aUl1XEoL-cgGoqz0!Vm^N%byuK`2<5$O71!1WL5-D&@ZoV;LAn^ z0*BC2`d(Rq~?yl~nD?M~F0P5}C;gpT9>hV+l@U=VdH16wL0=wjZqE@6& zh8R_E{r%+Y9Hn}lMhY`QJXR|YW{E`aU_CRvX!aie`U5g`z+CeJmfmX*EgIdH>uwT& z3^}S4=O~c`%wkp4L3v%?qKD+wa-;)wjy=3?=zs@(y${k+obZo(lHXW7ptrV_@S+0v zAUa#eMGCNbb7!zmfGwKXE{dd20wiLKTR|R~lWM%N9ud;hj9(>_jv)g!JfuQ?x6<@s zN@`cq>pzP$hGrhi2#Ni8OD2sUA;Ko`9!Sw9-fz#IDGD%+yALh@X5$tcuOf?r#+~6o#o6=!Dm|0koChIzrP~#9&uTYEM}M`JPX|k7t8V;|H>T zbwp01|4d!mQGgDQ(ddlD2?oX$MmTvaX?+An<9f0b(enIsd{yEKj*5azLU<3xFYSUS zmpV(J=f)SrS#b!jfG+R;oPQbY;bhcFhC`>?ieU4had0Ubqhh=Q+t<-h{M1MYYr_cU z?DeqzuLeg5i}SyGr7ce2~8HWTd?7=_UEipv524bNtYvW5`hGX~L0h zo?h7}OcO&^I%&TlE_Q;QqJMdIKSRBayHhn8P)Ck88zeWxN4LxL_JK+qNpt5doz1`W zQYmG(rQGfBB(ISo@(Yf~Ur7MsW`s^)DcI7lWVEJ}JNVaN`HkXYhs8MV=U=D?E7?PR28#vCPlaW50Lx*=7Ly;zaTlbEF6M(^ z;iR_hFWf?aAn28>Qy!C?16~kzVwN6Z1W%9b4r`F+3gjH54!kfH;^P(*p?>-X74I+- z%L++Zl3f2!u3Kk>@_2Wnzg1|KHhaf+$LpsMPFvsW`JDsU9bXgR6L3kbU87N_oTzDaKZC9@ad z_hfpr5BvHT!-*gqmxm<$YqNYsG=am>_Y+dA+8xZAt9f~JF{O6w6F=#Pj__0XT6hFo zD_dKuNMPnS1USs$76SK|S$z=-H`dzGN49v6qB zh!So}4lkJC@SYGiWyGW%X3C8G4lu{4l8i%VmRQB>>Fj2F*_?2E_$#slWENk%;J=s3 zKvFdl;PYm<+NF4MhAYvej974>5+<#xQ8eX*!@dT31c78Te}}LCT?XOR)K;aVuvF6Why{yr8~{IEiwo!EZMh59AS=_l&qr zOQrBen@XQ-RswD46ck(Br=It&L&m(wKc-)M_D6gHHBkCwTzWxn<(~kui?qMbzZchM zm?h$3w3dh~Y2eF`Q^rTro4G)OKgZY8(#Ahc8e5+A7Nb(v2yAywhSLHHD(v*d3;$)X zouQQQ2}WC^bwYPxY$XTIP$35gSJTfoW25U*4yhI79Fy7JpZ@^B9{2Ld>ZQXcfUg^6{8XeW6nPmZmJxyouAuB?@P_!ome&38JA#hWZ4sCYFW8N$UWGF>Xqs2@VrX(Q`7-(J zSh!Nas{J0|3w&;wBz_M*k{=Bx0K263=|mRH{@X1W5#%V(56|^UVX?MRg%aqJ^_|si z8IJ>e1-YWQYW9$h$5GzCiiy93saq~OlTquNYZ#wq(4lE=!iC>)Bqu|BX~U-hyKvtC5YK41r-VzyQ+Nsa(1ElKo?54el?5Wytnn!s=~#mKm&r+}R-RNKca5?ff+ zCl-K8+CaTUNqj6f9R#AME}%fc)N>*Obluw6QI$|tZw)J#1x9z?<(PoW5n>(H0LZ|`Rrk4gxy@^H=*xjLB zFQ$w2sM=7LD%Z1K>8<}i%r#l1@xfe1K2qEX&o5T z+rtyMn1EQ40}Wn$OHmiL_~3yTS4y%aYN!KPYjptYmHA2q4qYD?Z2e4YuS05o-rA&P zbblXzoqx^*d>)Q-ef+92OxWID-N-s(<#(uTvXyxsYsSey># zXw%sE>-)tm@F|K7ov-7t+DRxuZEK@Ql_lz@0MMU5>vsfwbQeH^BTe{ZqWBypLzReY zm~PZ`v;-;h<=5=@YY~=85sDHKx;`y7kjR8?z~LY_kRFkN@h?fs!yuXV?&#H}4zFeAIN)maVWxOT{P~pF7m?B$g zbzMiPE%CcJQ7SkH6|Z!#IpNLJ7<5qZJ=G`EZ}}YC)(&!)0Z@yx88xhgAOG!I%>tlQmFRJsX*DW!S0rYkL z`4&SQ8#$X^P`0p)(;2gb4jZE#R1?6MROWg@Z=gee{YAiE$7y%EODv>)CD#W1sP`oT z+@`X?WeV#??OB76hAPdBJnHfZd~$7&1xT2TKMy-t6wcgUr$kO{An@Err8g-HOYj8+ zHx0fJfN7?nl@+HjX%XhJ+C35wWYH>2C~k0m3&VlSSC3_>MxPxMAX7PP4>Vb~)bQ|I z3KCoPJ-mZ*V||YDZP2il9TD~6W^>aqsruM>Q|dUh|LWr&pzdNQ6()~X@TU%NQv8b4 zj0DA()h(48jjFuG;Ou*sUl4gP-|q(-l=fj-$WFvN#E+cdDJcv{IU{mv2_WzOW|10tMS#Wm5c%Tf-VA5 z+%!KR?Zx_NOTl&>W@Wm%ATPau$lx?X@qBqe7tTUf=}q~=+GmBNy~**L1Y;)I26qzr$i_1%okKS`;+?6NtF~GEpF)S zapz~AQr0xlbg&_ruYyzYURbW%YO6C{s^}GCez&;C6r?M&`LocAehyBKg`7+tnm3Vn zaxu-@xv-vGP@0v@Yi$ZwZhT|EAEKZQxhH575!?o{U<9NK_0d zDpG7zT`#OP6+APb``i=`i8a-^ddC4)&6QL2FQAFkhMcVIv{WJjc zh3VE?qcDwA>=cqN7o^a|Pu8_Z%b>@jYLsvg^v@hB4LO;`C zcmzTrK-99SNYPtaVf{fH6PEI$L34$qEDspSJhD>5l$MhpQo-UODnTl$ zGFC*~u2FER2@U1uLm&f^rQ=FQ$U7I4pro8+4kc$B%jtZWFek(Ddf4x!au*(xYlf;; zbX^C_TTI-F5fV5SMyWii>uw^CiqpA_89RB8a(p&u0POLxqfy3>N-zVb$wMatp>+w- zb_Iav2!QXHFv-Lx^U7`15iNnak|AD!O{DZ;gl=s4jrGb^0epO(If1YJ1+NTVI*> zNEZI=4&CYi*lJsSWWw!n;nSkH6$)a1oCArA+Pv{_y!b(4rQ3CNaE!Hop@s!7Uk6*D1%nbLg9>dM?6Oa9p*H>{bO(j^Wy;tu!Z!f zrQ{JvnL*TWR4$(}B zL#s522=nsf9$Vmy>upC0b3DI2BEJkMnBDx9%jyB$ORQo>!4Kcy7rWTPDJ*HGW}p)r za@{pJ%AbEyGBcb0D;bU+Pt35@!ZJ821*$!~_&8Qwpi6yed?u-vPi8Jx)r@lJX)PrG zg0~^!IZ4H{;m%iy)3WjE!b^1u(4&Q-^s^aN*R@(l)$gMWpzefneR1`<5L;D~Ha(LNIZsqFa=OJs_bQ;As7Z%5{=X_Ki|A=*ayN zT&sW17SmR0p6(rb!f{yh%>;&t;M5*PS|F7VC1uynl52WGWyF5JSLafniR4yPdKioy zd^unXhSr2)1qlib4KMfcxjhfLXacpw*J5Kj7`K!hJ^+Kz0aZ@wU_4#iBp}*~r;^q_ zAtBYEayY~BoT7efip9-;gN~*HeH_=p6}YTM0~ODRFN&(*n@k@eiKKc_#o*Xb z?}$M{cGavTPo&;EJJT!@Te&!ENwiGxQqu8gF+EShW@GY`l;b)muxYyY`EztCNeWc3N?~(A z_5=B~-SNV&qF_V@TOcJePidSgW92%EIALd`a}j7PdjaGcaJ;)iaf*u710}cM&u|KeN@CvRB~(QoKqGEk=`4BW@uS{7N1k6ulZ3i3&-2V(>DLP zjyxhTixA;U=XBI}h547%NSd8zg4WdG_iB`ngvUxD;J7SBf>2p2818D?*Y-{|qsfUV zO?@^0CcZ@m4yoXFkNe;_eKlnPkcv(e48-xi;V$-USA)BF(>_L0X93n@^LR4(o?)f3 zu2pkcM-eOPO@WZQS!YTN9V_vg^g@rvBA58A;4#n~c#m4YpiqsaS7XcKM<$@Kf7-6+f&C+%O|- zK_Wtd=EFIo#8>xJb>G3%_LB!ED1m+~tRv%p8oa{UF?|h}@L+v?aKIr;jGR}J7>>uY zFRc$tmVg5xzRg}m;cvXE-n{k~T-if?TWytPVAE^m%0fC9#Gad$LWQL?~P!FT~G zbgZV`2PK=BW(Hnv*MRGe~!y1 zYkmy%6HEG64Y6Jde4k!BnDd_k15=jyeSNi;rUNEuu%<8;>jF7ZJqn>od4;B~dHzl3 zm9lJU6ueTRBw2!L3?7j)lAfiSwVFod9`X|E+%?FAPzj7>anmnbfQ1qz>NS$8JkNVl z*WV97tAOGn=*wNXN|;~TT@$;&h|~V1*obxasj-V#9J8R+|eSj7m2s_-` zU>+yTb6`(>0wOEn~bt=b2>e=2>Z!KZ8C{JmkFmbwn zRRtM*iTqoW9a7a^Nwp!7}3iJJ}EjiSx6Bjr?A6WgcepzH1c_I#=Th$a)8JuYMNF>AunP5??gyo zx~`%aqndkSAZ5xzmL@oi99PPhjS6FwPa@+^Gqs@`KdXWmrEt9f(pu8LU^=gfZF*-P z3~V{yUJ9bg;7DhffUJb>kMAvC7~ut;3WY*R=q&8SHzr7-ngVY%+~bj$N|LaT3QqQM z1NITr=#O)8b_7P;*;KNPW^Qw_(MrDGFXR=G9Ues$FViojz#@y{Vxf+_nc#X_$je+o z6aK~V^xHSmS|uUBV~iV$*I2-D539oFvC&O}S$nJzUNdinSFy(OAi^QJ1PN|0fB>-g z6Cc89GNg;>^{&llQe}UmYb!KSz=QUpu2TLMtS1?FM8oqP6w^3m38T+8rtqtlKo=qb zzbL(BSMBtNj55o3GSAk~R{a7wydRAcMQ7!B#SCy&OMMTpaTTLaIIBn~HhZ8FNG5Gz zwr;P;MD)ikL&vnqThe6I2V;<9fnro>jE?9M&!^M7Ch7cGig;HUjJ}*ZTP6}$D@W_( zP$4clsx*aAEyW~{8#u7;!720=-838Ap*f}c+F2XN;Z1!_hxU^+5xtvJ4kICgT)Xtk zXH~ON66s*B!A{RdGYZKzsDUAGfmb0>65tTSfYgri=mqxAC@NN->Z57M!YqkT3-Y4% z7t|HJs_5ZOKkm~RIcLT?9u55n;cG-`w17|HS!MEZ?Vp(ms=f#rALk`iF{UCR_5}j- zHA`e`Ju-v*s;bQ(Zj`o+T>YQ;QX1MIP75wG z?Rnj+`M-+3(Sdw?FP)xCDNTi+rnE&pE8jtSF3S}|3mCJ+6Q}tC;OwG@vq75L5Ms<* za&Q&SM7*egkaC`>dZzGNEgj|UnJM6U8vWqWT8G$Gl0v&w`mV@eK=LVy@|7P3M}t?I z(bFkQp5tXq>P3WFG6s=~_Z=|J=uZ4ER~#ajJfASWkqzb_Td)z1R%DNHMxil120>*< zd0OH0x=Q2)G8&S5tHQFxb62tiVZIO+|(yJJZ*fXEJDc%us}iOlYRH#m+pGZt#@np&(ak9M2;&wgHZ>o$2c0i#e=`!e3u4-Bx7UREW(|pbg zCf}f9ipu3Ok}^JO<$fcb5sqBwcDGp9XG6$@Z~+Mx!ZoT?SM{~P1ZGNeBgTO=YU4>e zWb9qIZ@<@t{w-D^*&-uQFNh$Wdb(@OKzoI)6~C+c@lG~LzND3XP2G)KzDhDWU(Ng1 z%wTLXM04MnTs5b;p!+F9&B@Z&_X8raG`Jjb3H564a$`sDT|OCfPEOVfS-2ubNGeJ{ zk$w?Y4Fk8idg|da1*o6%gy)3&&L*D`DQ2-Xr!`DbuektL?t?|RGrWoI2*1OavK{$E zFAv7mM(2D|C)w6(Xs0a!f4#A4^3{SLZ>MVTU@Jm;2yg=M3?=!vM;&2kHIk~t_Zxae z{iSV+CrvLPNPe|dO^loclO%Mqd`f&gz5DAKnNAn{U_ePrFAeUpHfT*F9P_NZ-~<2| zHRaI}8GX*bUEzZ7-32n)5ypHWt53@^p(OcT@Ixd{#=7!kjB&fYZ8YY+cYtzg^15ek zUH2-;!0B$`diMq1$uhP{C-U`!Rv2bssdm&)YK*Ib*@C4i3$~{*iqcZo6U*z3V(fuN zR4t);VN3!>0HmeYaKsSMKrb z7Pkgx`u)ojdThq5>T91pL=&&-$>40x%bM-P4$x(Aa`4Ih!gwGWqYqn4k8mcE1}pmX zk*i(nlkyPdNf`pfZxH7fi3By{lu1S7ow<$ufT+NSoC&dg4V_9%aoM!x;0lb)&dSCr z`DMPYC#zNK@q8zHxUX4KbG7Sm(T|7+EMK9b5NT0%pJ_;4FM`@%`gle92XVrfCd$5} zKhvvFJdM1)9eM_OI_0g+=W3FOk8bf?PLfap zZkA&&7gGIXyza=ITk@IFuyt5V39NFpx7}lv9xgdEfBTF}d`KgN8c~(p)uiU3dg+*l zEwURhnEfyL0nVE7!IQ}qC2&n21Nc8T;ZfB(D!+(YnNelUs^UxLvb5I{9;c`v1k9KU z60^U%HP|PhlNW3JTqYrsv$1^M$&C-Qd2;~8n(UIcD%VlBVGbkb$3*!yH!|K3pbTZZ zy%Tcy^68e7PqG zB!V&J@`0Pp`BY)m%dFtIKaIGAun7dQddNyXTl|;KitVvsz-@Y5;Hj zro(Oxdz!)<9=g+Ex6Y@*B&X+~w^_|;FF8g~tkP=P&n(Uc03V@DU|5P&> zQ$K6PvVZ&nb$}@AR@SrOycv&uTo7dGI3Z(k7FpEa-N`>V>CvsCVQx0TTU;-kWTTQ} zZ>QY0kYKzuSM%w#!fLc=Gs+ODuG3MQ+{$)S^Xim(dF)_7>a56#xujiz-rFk$Ll^}b!nA}z> zp_zj}J4Q%@=2-;VPaE{0dxU(NugBHIc6K$spy8t0w_Ro~9@xT>W?PbPag+BUGn~d8 zK9GR_T6(r0b2+Hx0a-&;Wu!6Oa1soj$RdbmBJU538Ax(Ov`t=Lxjg!>!XwzINrNip zpL883LT-g|7vb`IPmlTxe(MdgRPU^OI*659bY` z_uVbIbbhSe1KjD0%}#Bgb^TzM%jsLEcxspVQ)_sbJ08=Af>()OIA<^%H89AMkNj{v zy#?`TicN?MuK<@KqVI~9HO|T>esGV6j*IEG_a?=I%xLykzEn@N;kaKqkscomOkXp5 z;AqKEcBnq`AM6d4j@~fn%)3q}o}wR7cM^+0(5o|)awK3sY><<^%*?vsay z*;Lpj(^vbFZ=WKHvQ?HD_I$(sAn!;Mo*Jk0Ur+N?CWbX2{`s`U7czlv41T-z4GcbV z1;ePGp2jy5tB90tQ&e_L$CSiY0_rvOK8wq%R`a1!qNleCf#DRN;&EFGFqW(D z7j&jnMb#5^1D32BW3y5HSpPK@2-27a2dY$EXl&zQ7LgK48&7sl?(1`_lEx9Ckdyg3 zPC{k)JH4baK@yJ}3_dBXv}8*pGKMP<3E+XyV>tE}z+M%0E5c5tlq)n7@P?;l*Yr2U zOFq$C-S(#5Lz)l2mG)eO8CRLE2n_4$I6UrxWSU%OJDo*?*ZrRu71XOv9MXmcocQA?LCgeG$IEhAYQ8 zo>zIF6Kcc~*Vi7J9)JM|tuOuMv=k4$2h5I&ZXUxu{W^H*|4%K(^=E9m=$6bFJJmDXu&Vo--g9PFP#ne$fhh@+!u)G>TKX+ zhgzXC9?lt3T)qpX#WAt6yI|AA^ia$0gsg*!r}gdzIIFhYX9VS=+!a+-N8ZIwFC*ok z8y8h~M_0@INB3r@DbzLe>)!EzdXnx`&|~K6H=JQj)O$PqO5{H!>mVChOf571#8Co( z==y6m2+tr+YQHQVD!sK&*>SxK1jXhCSCxqv0>Y1Aa}zPagcehn9Z&Ah8ACOAKcC_2 zR;;RU(oy>}K?N5E#?n;Q2i^1NiUW9t>TY;(Ip{UH+e17c))ozzSs?wT2 zsU%T1qS=ggrMMI*z`I;jxtvO%cK08Ui;9PE4`oTJA0c+wYiUTBP8!>AXaOi2FqK8; z!-UI>W)}jO+0)U@Im7D4=OmCCH>F^^mxG7WmU>fYpCaSr<`?>l39QGmP2tU;hHfeo z#&U7L7#1hLnFjpS+Uh;$AL@al8?G`&<6AJhUJ@>xEqZ@ov>on&l^3^%fJ!hb3#L9@ z9_ldr)_-oiu6G+2n~<12uAkp<=a__4*V$xKQ)LFZ{!_!Ri&wNDX*>D>O54R^GWWnN z1s2l^x@389mI`%m#6{a^AzP|+Aq7=4q;GFPpX0x|6MjsO+ddO9cyUE2kVHJx3 zvZ*@DAdX`OJf^%TiC2(921Du(%SsR;GH{PBNZRnrIq2i@WfvCwc5}&;;R|30bfL$S zoi z)p<;AIFhU)&k3?8xe_NMAQt5BC5IT_tkNH+VDri*IP~k_L)13*3#fe{x<7fN-Jg7jm+6;@Rbh>fs4S1+wLv*j zX?Mq;BEwowcga1d9wWvI@iTbi-M`0-^4OET162;$>+ti;C0yf|JLg52bkTw)k)HZO zySAx}$fDjZ9WUHf#m7ekdRn-%V|Mw_^o#x%-E zRXXbc!5oaRS7ZpT?%`DoS@-6wcnD{Af6S%I47EoPMV~HG4hE+H)yfj0?vKv-WsC@J@jY3=v&SqG_BTP~ioc+m6 z{K|8aQ>X*i_p#qqcpb~%(nrFGo> zO1PquMi|=q3~MpI#9Mu!3MbaWU6U<>w0UW{d!}?!7v(X0@;R$jOi*ESTk^yiHQB)l z4Fud6;JczrdPkLvoC63_FTQ5fM^{khJv_OUW`jhRJ+31$S3|Q%bmgtHr{rQLU3rwf zY)H?r4`{iwN{E7ez$x-p#JR{5*Z0}L6zAntsg;mQ4)%g<%(gryZ8L{cQ!kN3#iQ!# z53`l%cP4NGWN9$9x&oQ6A6Jz13MCxe2F~$phZ>4G*GYKMY4U#VG{QKkaHJHEqw<2A zHJq?Flp6EXxDE#MyH$C(lnGJ`vuSfc2U1k7*mM#AcErsS7Nkc2+`MAdSoqm@|9-}e zaMRx7d7ra5wtG!10rcM9(pIIeVYztC$#|*~pk{vZ%BsgU+<=f3@1_d*O7W^F&m4op z$~{J$u{RPUjk=tea}VgKF7O%ut4hH0Q*;jYBfJ#YiI8VkEZ@l8a%HWB( z{KDhAOgB{yFX23l4t_=a_m}F6UA{WXm^15Bzj_Z=X68q%x?M`d3!Z?{kF;$sTG<3! z39dPRJ*R&qR72#CmPVdty++od33m_Y=Lo45_3#7zo)6qJ&oBc#C%uZJhI-0I_NFA9 z0LH1TuYUu5>aQ%L8m(+{%e||Q7*iY@)DWiXz@{^>WpA?DT6spxRl6ltSD%`nQAe%m zy)fJgWb+aG8pg_78#~2 z0pE0A#$|6*vDvP2-V^Em_Nkkh|qmP}u0M{{d@l5F*5}7~> zRdJ^;a28Cw02K9Xc!DiIpX~d`{Cf@n#V>oVyPjBM>AR_VPiV)zPw4Lq#CiFKQ_QM! zPKpdMgq!@ytL<8Y#G!GiNj7)AjG)O?rLVYH7NodSMo#YX1|sFB-9jp^w*qlWo)D|FdxwBq#2t5$)`udQXK7n$0M?Ss+2*%uaWXmP> z;~5p7K$AQCRlmm$968B^RxTWbnZF0s%49=OEzLmo#+3%;``Rzr2ad6B=-G4vj2D!7 zF$LaVJ;+Hx`E-QP!#uuZNX*!XBeSEv_`*n*Pl4f+s(WeNR_niMo5WLiW7Q;}5`PLr zTLT{sM|=%$ed$qgAdfmW)@I?q1~d2Tygy9;>NjwN4Fu7_;P^&V^Ru&5yseOqa$Tmq zBA5hcjdv)_Yeg{h^NAjUiVY9>;iKXxqBL!D+SlOBFu(f&m*PB|XvBRV+_3Kzk(KCI@a1-*MpUrm8fC~O-%dn9j}Huk zC~i!gd7nP2B|*fS+n^q-&5zTlW*r$_ZY0+v_iV>2h{)G&0BM2#Vhkz3S2SW!GOMnN zeU>0i;{+5hJ0Oz(EX*_Bgp4zMd+?zV*JhP8-O;b_b$2jM?QmtE*Gjl5(-gKUJZ`@R zIDhh)dImajN%@X%{_2$wcXtf{CUDn)Mg+y%Qe!@O+ga2Qz|0IMne-Yy@JyWW1J8T> zE^#rO15vAtE+V5mWG9e0-CZ}B=l6B+P~;Fd1Nc+Cj}42PN)H)_+U|>RE~UK5-U%Pz zxtp|U*5gX9mP;el<35p`nU(7RMVETfSdB7vm3?YUM*uUbdwE1&kOmG{By>vOw)gR7 z#HkSAJw;=hLIAkiP=Td#Ab-Et@1X?Rh(7G%SnQ!~#!?q-zX`S|8gAOtcGpdli=`+f zVXQfGa#G?zy(EZlI<*u67S73|E6UuQs{{IYHI6x=p~|_53f!J>w|k4DDcF8_z{3Hs zug=FAC>BIT-6HXyRyB~0Wo{~axOLSRR;f;?TCkS;P8d^ucZD+VU@tWTQ5T3;&>|^& zk;wlEeNdStV*2is$%$O5j88iKHux{KqIa=Cf`T{-p{LVPASSSyey3vMlHNZiWD=U> z7Mv*Qa4cGaW;7i-e&TNXt3-+-A}Owv&x0)JLcyg7q`I*V@4tM}jHe5ML?>Kog1hO$ z0r1~ez(rViuROMn=09qff1G!}g2g#feM}PqH7yRvHsr`i73;*!uS+N^!t0YcH0`5m z{7v_4iCMbYd=jMVDPxj9D&- zHLHp@zcx00f34BUam(S+^>uGPWO}w#fNcW*(^eOyPMhct%NK;9doz?y*4j~B*Q#NB zAoRg(ajIQ>Ux_Pj4Jxnr7*MrgeJ)$z^|-~3$y$lyromBUASMXMXLGo4>c0|!$VM;% z9Xvp)A+@zN7o1GO3A`$`4Son~MC0Xhi`e8M`f?#ubZrTaQ*Rl^h}GBi?2OUA?CY2+Wymo@sbB z_DvET5sIQvWY8&lB0w-&rDZy%#Od`yp3A>z#GCg=SN&)1@s1Tf$CG(Ps$-&|O{!6G zf;6fVTIjTPWtlnTu}amfCvp_Nu9F9;#nA1a<_&DaxA0}lt?y@piQ={VC^R5!rja*7Kd!IxH`d3qLun3mRC=g-; zV3yc>Isj7tUAQ;<(jjY(qL!xhZaP^N1f!WdNbU)YeU2ha*2f38+^vQ9FFD|6Q}%l> zzrFUf97+_z+0NLiGm0!iG)%Cp8~C;tSvUdzw*O1F+`wT=*W3tK<_bs6xpjvfn(wZM zF1rF(u2ui~o2|-WG4bm2(wx$}^HN);s~lBu`kr&OR)Q51-!!IOiQX7uKkot| z=1;GucddSBGxkSaIhjsWv?(NaC$Wv2@|)CmS@mV9!B(ZLj+GLxGoq#}DXc+Kqyjq< z8}E`Eqw5vqbtrd(^4W6giqk%E-Z=}T@>cEEoLK5W+Lp!O6DniF6rGTRz=-GOk zSow7_`mH_aWc-E9)P3*fU-YZqBD{fLyd99gWxP62smEoAP|i_t-e*_$cSZ}WN6^xl zR{qo^F@qbk^QH{<<8j^^iy7@33rOt}1c@o5l6<*GC)^MbO zVy$N^V2F>3%c*~kM~T4*liqruXa|z+_JF~YueGHO;(8lZ+5U}4SxstTZH zYc>{-#}_D_6>LZiX#w1kq&_6#yBv2IchxLVDnSt3i$euH`W>42lM>~gHVLeTMAJ#q zW6f@F7yF4BXJo6iTUrR(k*GvA&^wRRGos z1xDYyW}xL611`koG={s%ymVt4bwQ(@HU$e&24F7Y{xb!BH%!60{n`n3?nPl1o>h&l z&+|y zmZ5Qw42$Uck=RSAj@Syy_jajxpC%JE`$wd>Wn~CCYZOzehyH+F!b%i_l~!*SlNnXP zkW2LWaw(QxA}}#G`qKy+Gk)K4B8xBLq(bnL4AcTwG{r=QC1(&D8Buub#KeB=J9riu=hi=`Fjciy% z@Z*k34>&nQ93@i@4_OIDH$>`W%E0yS(`wo(R158dKIv;GzghIxZLib&+h6u)VClRC z23;Mz!+F>Bd$TY2Xt|c^2|%(@-x@W!hw}3(k~t;MWq6mef2O0R%l!I&_5G@^SZsIP z`LZQZ)80bY#-ga_zj)#J>d_>`EP+4RTOF_|>D+SHt-W{?vqF~!hc3B=3VBfceOfqF zH$sF$Q)7rV#Pa+_dp`0xhPx1zHCVG&W{M8e?^P{e#j0s2%)DimdRHQw=7wuZ1y|7f zS}(~8fOr3XLQ1-!XvC%(2o;yMT=g0`O-<#xSP0vwT$kqGSVtUBaANPCe^2i<-VqNl z1Cn!uvC>ENIYW(OJhz4qr2SR6Q9YaprOb`_* zidxzq4aKEKgP({db?ZoG0c9unxj$`C~Ue+gpCURu} zJCP^qVW!QK1GpZ9r;iTxW(kdklpcD@2qi&hZ+-vE(SC67I=xFO$R{}yKY z`0nkm@48Vn%KJ1E>Xg${#-uN#7NY*jOALcA*ECKH> zcL2}8C-7lTgY4b+c2nt_oBIn5>ANkZ%dhc^nyaFtsD|CG$}b(v=dG}f=CfS8tyy(n zK+%S0aO` zs*cH~u444SO$gSe*y_ER2`$g;Y|fp0IGep%&8{|yE{R@e5)3FtmkhD{82?JltS^V_ zrTZnqNZI4)$ZbzIS`-Hq1oAkm+$T9E-UF1i6rXL)uJl626{Cufnfly9?Ngta68MB{_f3zx$7FyM`gnS7Z)_}GduCX++ zY0Jqd)c+gJireecJJuJg*{ceAmq+cInpfGCHfqgO3kLSI2ws z^>76@VGrmDXKRByFJfEHKuI$Zp-%qFUW{bF!^QY(biq;m{#Tt(gqYTjOP3q&Zw|Sr zf=enefKs{Dc;$*Z0lnTULn(T`nNQ2ZV`Yo!7fIt+`6v#T+NWSw`ueZO%~a?#Qb((> zpm}6~z5aN5rSw#PpHj8maeSg+ot6oHWg><;?`nAQmJ?1KRFBYI7`)_F;rl$>G`8iL zfqlXLnOrAjGljD(x@bNNUJrk4sm7?B`3CMdK@FYL2vqzh&-j0Y8=aYAdtD&ITgT(C zb8PDkZE^V`_GYih<)M!P7q?yUibHZc+098se^(>ib9w{i8B&mwOqX1ob-ZynM>xBr z{4Y>`9-P&7QzEJ65_fr2bIF!Fu3%mU6yRADi-l()R5m>wF59a#hLJyL!>A|7O0nul zJh$)cxJUI`O=drY(%dXc_g|CJt?)keBt=%JGyJQ4jHX1>nJVZ3N_{VW%lMXF4RD3x)9(nZRQT*t^HvM4^1lfL&UQ~xXz`(BtuhBQK z4FjCmA}6wUO9zk6UWkGg=5&;B1#n!T5BiWbkw@eFK$v7qB?pxQB=5Z<@otNu{=w4nHY3NB+(Ea3e%xq~=_M^LL~(cIrx zQXS{Yc!^+Emn{{9#>_vSM=evn(0uW5WU?Zex|-8PMg~U1SY%dYemicc^Ep@N6a%@LiS40yS;b0JP5CCH z6sB{ob8eRrR5ef6)1}Xo&eeNYOq7T4~hRo-VK8C7f5fc?Eg~L!yq6b(7vAi=>Z2gUrugPJNs##L3WTY@pq3i0Fmu=imEs!e8 za`u;f{n8d8c~5-$ZS1Cb6sz6&o8g+Vm#;{Az9GBEwl`r2I;(sin*_{u3Vs4Ie>$5b zpDkSrClWTMr@ZX~EL7&%{A%v5A5?8L{FDBp73h{4v>5sx>A-gHO|#c%DM?&tDI9;V zC)y@n9O)fR592gy-c=<&8$%goeNH2>OCOEs#_l|PwRI*rT|?C%xVG>XT9wsQ-pNc> zCF4^|<0+_M)|$hUZLeK+;{51)T`73F6qcA*09gbq7dEkNT$IP8Z(CS#N>|#POWl8; zbMMQvKmkyq(BbHheq6APM)zJChFC5=`QWUi06Wr9#BL|yLN8ZSaM@w-OdrWrUf`k* zERWqCEN~Z^%>^YbIiN{f)@+O-WT(3lFw=v}3qVHXa%2z#LLB7WUp!o8!2IT3-lRQjbm!fjGVnzd z5s>5KJt_)~7QpSwUj2sYXGY*52bM)V40E%e4-8Nc*mPYzYt zZOROy#l%%r3XMv~rm=g@UEZ#ImV>l(hK_Y}1K!Hu_26ystCqyZws65TDA#?_(gGGK z+02`+9zTmSs&+Y^R5UMpX-#C#N|AHQM**APa|V8 zjo@ligPF$N`gy%2#V$P1gNb!Fly~)3v0q`#r_(MFY!9NgmmW+X;CTGw>+P4MNh|E@ zhX;NGw|fzCA`pjI5pCSQk9-@|B3&@mBplk04{FzZ1Z;9_V#EG@$_LR!tPHDd{i8cN z&+czg6~5$rfi*h2|4SnRdrBO|FQC(|m(B#t_h%P&Zacn_Dmi}(Se$zKEqB8g%P7i* zipuV>(yg5Az|1wDJV_ai5UPlye=9-=*JHp|gl;0wKG`{R%9ghSssnLn;WP-wGu@4AQk%k*)|?>xgic{b!H!yC*>x@(KP`gTxdXg(piecp zB?%S>#5DzL3I?d+3e2+!;HkaKb{UVNFh zqLrR;4E}!9WwBk^t+&kEN+|d@JcF-axlTa0Ab}1}+c~-N0I7Y#ORm>0Q!m_kaY5b zsKsFvV6+R`YF9Q4AC-PmR#Pr&S5@QcAMZw!uay}rbyle`kPttMr=9Aw+y<}v$<&K& z=XlVfukn_25QRYI)A6q^CWo5u3iFWcF;)$ zj1CUQ@al1%t84mj`nj~2zl-q`_f#5KTojr#1~@14@PaJzjr<-Ji<65!`xt_^Dgtmy zqf)(8rw><)<^{i>TydY`__KnXcg#Hk*2`!%iJ4l>d|k~5-b-rMk8?Us^Bj6NlLirY zNT$m5V;8S*I)%kmI_rof+)o+;{|8s%FtnF$43t~fdlX)=>u8&q3sR<5eKVcG#Z-C4 z5>l-;W(+3gwoEOeg;|xsiqN5G8s5#>IYE}wrc3e7;PjmOaq1g8rQyUchw~`X3G~Aa zR&sqFz`^)}g=`-`nOo_a&w`ht1!{zg&zyXKMYM8RhuxH=rL@A}1M8V;$aDnFpuW{gzX!=E@dM& zZSe+>GP#NrT4%LHi)uwmom`)dLw;QK?ObYBeQ!Ib#VdeJTK0F^F4hk)yzi&iPpdej^`?7)z)UqJakzCPc4}54GtSr#xy74hSlnub z8F+nvNxD+EG{?!-Z0B5refi3Js<6SGUOVf9ea=;3T+Ix8!(!4;%(G=iB?Yt!U`$gp zD@Y$Eva<;AthM6nF$KDn&;Cx0wuFuaQ&b~W-kxsxpkoUW!y5Md`k!5&uHoNi z>6#7MnR;@BBnbM8&WH;x##OXm=Z&Xb$M~p3p#sqll)Fr;M1~Wy4p9&*Z==;ZZC8Tp z9Wh>F#X0LHzwF9SXtSfTy9!8Z79a&n=uY)z}luJb!+*ia1W6V6Sw1>6((9mQ(1Dss!$pf>-Kx9;V_o{X`%@N${d`MBI}jj=dT1Pv=k2&|}*z&q$i zzlXUt&7{BMQZcSXAmD94p=>qGub!M;3I?h4v2VIly;hD3yZA`sca>4>C$Q@U_PNWs z)zAwIVJM9B$I1wo2&N#oDqOGG!`+63cLf_IF%Oe2VSGp*odd&=w%bt%V6kMBE`_~dA zz0;bhW|M!7iNI4kJhFN%UU2Aah*Lyy4hqu%KG^h1AK1#h&@KODHiK@*H618LzMhm* zrkn;P5=-w0rG{o=<*n9gr&3TH=A+~I{CUg-0ZON`1FU&4bPz&#GZz2qMilK-ztqS1 zHR+x(Oc{c`rze8i@up!C`ozi8Skjis*CclH)~jl>T~@FBP}JAN0RCei9NtV-jZ()z z%83}5r9J`pVOvllJ&sBQV;TL%u69t^j+xG0KRlUbkl~Eg210L~tsYP$z4zfahRCle z;Gzek2GH(QvWZ(p(?~n~QxTRfM0qUl_AE(B>h4%tz{-*0xY((jm%P+Em5{|%8VHW5 z*bnA@u52D#1lKAW9Y0uFVR-nTv^E3QCX_<6NfhM_LxM7Q=J*!QpIr8)MH`&rCA|rN zgoWZ=w^WIDscOvnp18FqNmc1MWnz{tjou&fWdbi)iI)ah!XJM2xWrI8PrEF_8Q zm@dAZ8uc_FGll-lu%+d*)A0U0>hf98Og9{cHX<(Z#fVAWe=e>7F~ZlZef+e!}+bSq5mUW;_%yg zoSxH$aGhaoD>+-j2y^A694iRKkKIWNu3<3YIzshygR_TD5we@?zfZVft2+zhM%JFH z#Umiw=f!%XxD#6R8v1x=qX_WKigYAl^_9)rypDUreV%^S3vX8=E!WMPrbxD1s3POca zvn&U*s!n#QZ;HIzeQJ$&wE0!NMEK-s6SGMpuEWq$oF;@>W+n!-P3bF zze{NFx%){ZjlCY(9WRLI4z8v-atsC48ha8LdMXlG#Vn+Mg2l`1DJf4zarRG1)7-IH zyQ|zE55S`>RzuX@>}uYPolyRiOHn`EU(9Fi!e8z6F@R}bq*5oO4*3O%=KaMo)SGHH z*OEce6R60#tny1|1cKit=UvtB{UycfJr_TgBiIssis;04GF+#`lPZ?^H!8vJ(=&_Q z_DQaRlwdjnXe5~#10<$M>cRuAo4oGk$Wok8V3o}*0-o!NI=k`RXLeol%*rJ|bvEb6I;nT}rs1%USS; zCaIa#bjw2*&w0=3L=r8yv&&tqvOW1t^po6?=JjmnEU6Z8y2CZ)TzF6ul(iY$4(XmjCM1I=E5HdV|I;(L)Lfk zjZN}Noa>11%ek&(57?O4MCZYrzH~s+dR-B zASfnEB~ZV59fCf5v#VK;*UH6-#lH6@2{Db20XL$_pg=HH?4p6i;9zn8KwVab?n_r5v6Lb*JR4m>!Y|B2d-U~ZVPt0oU!nuJ>Kk7E zYaZ9)R<)QE9pLn@3`vBgWnROHAz5YB{C523wB=89kL-loAjj8`=mj&R#xs?sdapT_Dcj{=uX-upgClX5MP2@>a;XQ!9NUL#Qa=192ou>*#BU zkJhOtc_XE=Y$8w(cVIOH2H~aN&;M$-5GKe%r;?|_r-~B0i8JeJJ=%*byVlZUBvg}U&_s;4>Pe><=K1{K4grMMwofiP4$X+x zF+*+Iy`;ufv?Q);@DR#_AsSY!TSq)@8A5d z|L_0&P5*cL;g^s9vH#-#{{8>`?Qi6@aAg`1+J)7>Dq6u%It=D;`TCsR{UO|21YV74(+Kb$bEU>T z7+^`jTeksi1#TR`@Q_pJ2Zj>#loFmOxUwjo;Oh5eFznniZi)ivaMN`9U)?kK6ThmK zIzIpJdz`G}3B6CL!06||A)NH|3r0=*H?p3^c(hqKuby!!kVsjk(pgKT>iRVuIDSCy z4zGmfdbKNkP&^*t8gdK*$LqjL1T&Qc*B-o9@m-Ysu|7I2y zIaE^)`8xEK^C4ah^OGppBm4^e@*LBo?e~PUbvl}0g4E*A_OQ14mw=|el=-``G4rRvB74vvfwFzA86M4=zR; z9O56{T%I!`;y(x!)6F72lt2i(5ULsBZ)Hl-Hl;@#H&!)%)B!y;L`1`0K+-YMrAj0$ zy&^vhwghX3F{*4xdYbR4stIRa%8b+jfdSXn<6C9AX5e4E2H2-Q;Bm$l`sjjoULL+0 z$7l@(%1i24eoX3~SH!%%2}Q9kRf~4MqQOjL;nf37m!cjhc$4(RkCuxWocECDG2zO_ zdhld!0mV{MyLQvry%bFZ)eR-8(d*S0@TgY)L{}+_ zmkHUs{Wi->U^!PsCaJN6;xpn2Kg`#NJ zo!1Zl%o2lCeNs6SLCya~5hF6Ygc69}1ji9y=ft6mDl@dNzySigp1i5$YCL^#UR;hR(`nj}=IQ!2bC z8q|OJPm5R`Bd!wxNV72I66i)lAQOrrV@yHItwdJ099CeQmzH?69HsQP7Y=c0TXY#n z$6sCo`FQ%G2*}msAhH_8f-@M2@(uTTxzOA0a5ja#EHDl|%C*brR8@C&uSbmI&@?>| ziu&aljJ{cnTe!ZA51Hj0#x7+Lj4`t+Hj#6GO>oa?qd++%h=r(KnYID4QfZwfCI8dt zjcVyRoO}oIXyd`;QW0a^4Gv{0+uI6=keV?DRcfXZGapo@nbCP1zwYkHfJ6mZ}P||JkM8~(&>8wDV?Vr{NAgW&1+xe}>gQlZVP$02% zGe9Nezj6?iPl6`2b%<%uZk4UFU)+g_RH*tr0cP~S)dNZ>UO?++QrLD_wU9EDESOS9U89^Fx_mSgT2xrVw`l5pj^*Ia&m>^e>%|ue3Drf^#TzGn(?n* z`V-x026+2Wg4B~BE-=SM>|_(k>AacU5iq@ZFfW{ST7`8SXe5K*))Jt793%DrndWse z2T!HHF6b}`#g4opLf7zUe2gSg@yNrm>G}8=ao6{$1|G<`gLkT(hgdU1>OZE;gt@7a zUlM)xLU}+$(ycte859J9;xhC`oCL?Bi#nKsN1J`MD{lW9o`c`k;Z9;^;P8*whTYdTSN@^F6+ zN$hWx8kcwY4P1vjYq5nC39q5Y0}0pwSHgLbB6GfkP3*S>88_V}EB&mZ zlH5484+4^D+dm$+i5EP})0%SC8-pmHTq;oWY4ZNE)LnZjnHapr-W9Q2eg(0NRNx3B z5L&epA<&A8fJnJC=i%rH801KbCFpVr=pJpcenYCgPfQ(bePf_nWfWJa ztm#)!VH##q@0f66U$Ln=3lq8$_-KSa+B^(A8LMHQmGG=C)7GgrybJr)(j-wK!dLu( zHlya54jdZnZTSjFx;&Lt^ ztQ2-REcIlu8&CE&fY-t6tlwoMTF9zftSCsJ1-_owclBkLH6ZC#b?CMn@!Hjxi6?1g zn1MuE?r!i(HCUw|k#Pytr`01_8ZNxukgrBkVdV&10;#QWbJ^sCZUmEdgOlh`$r-U5qhNaKwSi8-{i($5iJdr% z$Cid)58b`PtC-c16Xd8@19_h2YB);UEG~1!f8m657@GQF=28+I>!D)M6puTJeJ2{B zh-5|Z=6Y5{CHn0R4d)`qrdt^_x{Fz5`p<51TAU9r0{2{cQTmggu1F}PIm$i^&?`KQHl_BW?Z>Q6Dv6S$x zG=WUXn4&3!)UR6sDvqm)QPmmyHK$ArYE+@3`oXja2ru*1w#-Yp^P$Jc$wX0-@+YMi zG0ofuLx9FzJviL7O?57M20ADm^|{+U2y$eQ&RCoD(9=UUeR3D9RC{1TvIF##(;;!1 zxA0-o%3?lFFG|fB(cNTF_$)?pJDydmnU ze2wbFKtRL5>Bc?0Awt3feOgR_Y;?7pOWhw`{`EgbdB4eKqM(kNi|1; zKOWz^!zptEpC3Qv552omoaT`ODzHmSS9u-!WQbAq*56N-H< z410Lp&;bvcb|0jpIN=}nB)_qE)P=PsxKM=wd=S#F<01uEy}2{kC%_g>oCFL5`ltm8 zD4+HxNtA%Rp0@i*$*mgSy|blh{PMfW5G~j6^P6Ij=OYc~t?@IP4$EYhK3nA2%!i=D4A0y>g{*)3&>ncy2gG#M0@^{gZ)$m9_Zi>gQrD zEzt5=Vm;hGe>Q3F0A+ZVb54GCC70g4f-%kpoPun#9s*#+7w^? z)Wz~*_=M^QhCI5}F5YH%1FI!|zJ}fO7Z+wp>o)2^8sGH9sY&Wa=QK`2A`~A8@i& z<%%{!vOvUh#THktd*t^#;_SqYR>pASn3)49jfpwQjsB*DEd{P?X*e4dVtUco;l=s< zJ+%le%53c-qX}b@RPxHw+i);acJY!SR7p~k>{6tSC^_VG?^ob~HLz3APb)@<1gIDz ze{y|}cpb8x`K=Bh{LR)$mVuMOiqFZGHjrYqY1uw)0ns1<(m8DJB(1qV2P%F_pCi!6 z%#+em(50V<-9sfRIo>*U^Zd=go7aHwNmGa2tjli;8QdP3388GoAG_DYaZvI?gVTdwUB4ak?wS3=pVpy-^o8CLQ7P=A6|$hd zUFy2x#MI&q&!6RajN$Bf_7nphhrBP5t%~n?_13+6;8ci?$BsBq7!|MFXRHE}&WW0t zy!*;6FVDkJEEVjaCNIG0l3ARx!|^5-whv0ihx0ud-W*|H|1gXQ+;Le*!oRl5Rzwo$ zl5nvIv1)e^Yp#X@B~>cC;crIQ5qb(+i!3ju4DH;719N97#E%!rzn(Vrv-H5W;x5|! z-ra4jL`CM^=CzLJ=D-|h`@nC@2qr*Wd(;HLF8k-2Ly_dkRPH!lr)8-ss!Mzam3Wi; zrpJZ7AU*u1I)6N$VG7W+84|*GN#@G@=(V<-N!qhV*GeuA=gUW%C6XF|49r2nUBI{- zjx4bXsy5Ufkad&|PY)7B7H{^OPtmB3^Oh>raUPhSQ{!EVh{c8!FsZV+1UDzi#;(1q zG&RE^Jbr>|`ABRh%QcU?qVct;W)Imu)a+@pfj^veENN0DeTHMp~kGjt=!g1&5>D9YdZaB6CnbXI#(%C}A4$+d|$gd(wQZ5I52MLIXxGkw4vH;w)fB z#b|M;h51FsWd*6KMSlSigjy0lY zp$L`8TH)tEs8t}Jv?mxIUCY0#$-(Vd#0kpDCL#?{Y~Iz7k2qYNH=O>e#e$Vjq5|M| ztI63Q?Nm#JVYf$sP8?1>j@R+xZv^xrCOgNy<)`=RNlvVM@J``raAIHdOWgfW4#h~f zs4-ZV`5Erk)IRmaN=9)k3lbsfiEyX_;M65W9@-GsO4o(q!4#e0ax5jb3YLgKs9p7a*}5!&hCc1ty2vE4 zIHs*x{8+$_O<82?1b_8u)4v9Km1UIFN~p`v4TiYG!zatd2j$yDzGFk@?C2nzw~?R} z+PF!Qn8^Vym|CN`rk!cyNFaB+b~h5Lh1N+^<$5+Ny!Bs~AU$;!(h<1j)SsAdGzAcK zL5-N$CM9P=4=R(8-x`Fd=JnnlmH-IS8@MkS@;OOe=;DJPytoBsbr$?w1<1XZ_GU%C zdS8q6gsopmZM7Zr=PgZ|1MMCx=uM8%T@D!1#M=6et;~cpZ+sMa%jO3cA(gdElCL;v!zeaU3f1f1uCu^cbn;Dukj? zIr#kfZC|A?ai*h}m5vN1<)#%U`on2Ae^qI+CD;L( zXJjtb`Zeo`mVqudDQ3t@m&as3DgQ|^)Jl<7LrY&MmPE_qvN1mHBGEI^gUT4));JWA zCd^A2<1`EZ$pcWax}%jO=rmMyFrt)jkStk|ufJ&T0|p&0h}nio0&J5Na_%6zT{3VV zKKC{m*czeDOKVifar^n{U|_TyVp3JwrlF^FC`0eILqyt6f_4#eT&t0k+^op2h7$Q0 zJh$x%OFuSpvOFctdy3N;v*gG3x9EwD__speOy~`-=;u!y{<=<^(><_|`juE4=SRLT zy{#V5N7QKwn?~)q3Ly=Znu(0-ImmefZ=4%s1`;MCdqUH=eG(@wuTvl=HV}C3TIx;m z!UVn`;ie%&0x*3Vl(J$J=2?V#ta6V81X;8a6N(xf-$Ft;)go4qsTw0WCP1cPrbDvF zrn!cPpOcW-qVHiHlo`vipe1Y@By2@Ty!}+?y#s9%>KL^D8gUO$cM+5llbIQcx&_$w zD^fDz6o05{sg!7Bs`2d3Gdz}1<@0xE zUH@~UAvSI%A8(q8w61YJo57@MVpSZn6c`lR(IXAb@~O~x8mF~ViViO?7)s#E&%C9~ zX(A3wuOd#Rc+ELEe82l&K9@>*MVWuSyv7u0x#Yiay{PAig&Zw@G;1R9+eF`MxbJYq#_5$l8YSC;&tR8 zQJ8R^S!11{f8lsIA*7v$6}N;b#S_02M5Y9g`hypLe=`H~h3Gc#Dgn^kToJBmLJC#< zL|uoo6rB<)=Gh?|Wz$-M`#7dB%C+h~67oq#EP6bVq<72{gi|?uD4Dnqjus4?$!@Wi zHgi2a(ISu_`M6nJPSxV}6G_YSc)qy!GEaL8qYnfs!oDb)WxYrWpdw;zlspGRE^7%F z2e!lpE$0Ovg^CwSdrQuh$*|)zm1f5}qJ?BQMoHtB$J~sf_(?Y@$W1FjSYz@?Sc4kj zmCLoY)dP-rifrRhg4jP0+yg7Wbd)c!#g#He7oR9LDOfy8ayz9DH0#rWS@(~g^7DlN!s`G9lj;eY= zB-d~-aR9eF4Q^k@wIfk#=184y#5ZzPL?E;-A==IWkZ?Kx-;tKCnAOp$VjJ~}379J$ z;uYvbXD485)>N)dUgq5aeB{^x?JsC$cIT<$`0n7N?Lwb@Zx#o@Rt)_`ucCJ`;Zst$ z6pF)sy#f-~Y4gTM^ULo9M%-^{G0Q5sncBAXSEha@Bxas(aq-RSWhYu5+PPY>D6aN{ zG-%~46wavgiZDGg%wq*?AA>WP9;wA9cvW1o22v)I-ZF`36AkF+8PFvn3LYC1WzsXr zWLd%w$j>bo!pl4-mSwie-bHyZ%>6+ZIO00=@HWNs>q#f0&5C6WK=*`H*fy8Bd;dN^ z?7oFVSdvUvRrj9Qkn^s=Q9gboW#)YOuVTetfujgaJXJAkYkMwF@g1i|gvuJ)t6Ee_pF{ zX(S?<6%`%^V+UUj*n*}tZqK#}5)={|S|0JaJvX^%3^k!^kuepFI|>dT0FCK#D<*X? zU$VK_W=o#RP5Op}RA)z6KPRu>lH&5>e?Z66HmMzsUJ@(T6%WCOO^2emUHKP8&?3c> z141g-6e5rV35ew>ZRdybY6~yeOB##ItEw0phx^3Hw)lEQ!z9yp+7z>L^=uQ?se*4t z$6n=&ipjZo?}$c1Hq|U7K-n2fh2e+&I?m4Zj-1mcQ$j=|ZB8)CmjX;oicG@^|B~!e zB7M|+(;Tkdj|>|v9AubO0{nR8=sgO)Yq2S8gUMi-EVuXeut)pbY{@|SijJ5Xlb9W% z;H;GCZua#4s zm*Dsm>!5!C%w8fmCPYniJ_w9fV4aUVX8j$|Kr8ABI!U3Qjsb4e@v61+Iu!KK#4n2lv>!kSDIe!KH-4p za5Ooi)$kD4=u=@LiALzlpt~a~;vy>O_vwmz$^;?8d-Jz6Ez8e30)X*IW>NIQG38=u zoBo_f9v+z48uz6e9rayd{>3%oX2+R0Yx3}i9OXmdu@VRpU8CQV=w#%a{?l=;*VD8#Kfse6=5u;!W37aUw^HZ|PQgVqNB3 z)>VX#RQ#3H!7CtBiJMKj#89zfnTM7(OFfx}b>CrX+sU&dguv(v>&o~)HD2NF=)NY)eRFemz$HujIj+RZ z=-hw)zSUs~bD`>Z+y)LGfmaVdJWy2*50liF1ks8MAc$~k!feN;T#%&arw*j zpaRpv3^Vx`RR=`3`3TbHFUYhRUg%UM$aL4;@Vx%ZNXS0_L?%3CoEta$N*Sxl ze)Jmn@HSU2yB*V2g#!M55@~)ibsudYS-CrU!^wiF*Cvt~gH(6sCV98GywL59e$p0y zdVLB#&0b$FzO{D0_WOX4w062VLLCCeF>!Z2atm=xSHXAz zB6O~zU7DY3MH(nru3LiU2<(&j*A@S8&n3$G)TzW>auz?yM4FwfzUujZg3K;HuDV<2 zutYj!8d*ypZQ36kplQ7T=_zE;(4H6NKL1Rgs1iV;beHY$H*)8ie~$C=jM zDm`Brw>XCF3{t0<;+Y=$`!>Z0a?TDTe4^GaKFgdyGdV~qMBklpE<;=S6ipx&NY>uQ z)^Tr=IpbYxgSh1@{UB!z7_co1!%_LaA*#5Je=~b~3$MzDbu>Ry>6}9muzj&YGa?7DEcpD@8ltQa-l{)zB!^OvW*<|2MVaJd^F_FKdtHe^E z`?T8E$NR}B-S~Y7(*Y9@;|akpjK#7*M$}Z23TFu7nnbNa4PljHmyQP4e6 z4|$e6cQrDhb3Pc$B}12nBWWnnP)MruJRh&B{=O4}4=662z9dE?F8t`>J&_ANp(Ts0 zWFf@twO^FO;A0O8>vv5MKp&t4hl6dM^$%>RZxQe^{n7F46sax6#6}9}oxPZUQh`>> z#Gpr~(sAK>wl}G*#f{dBNKI6(wTEdOg3^oIoK7e6Q8NHij!l>?%@~U=NL!i7bz}Z3 zJ&QL}me+s5^La9r6OZA=c?_yrGlirGe>*v!|1f?R@|Rjh@JU2f?~0KuN<2&BtwIW0 z0>f;6#n7ukheJHk<=^Rr+=2AJx!`}{EQ&elQp24GPb!H5h#s)XcW1wnUG)Tr4AD8v z)S7PmDhpyOnd>(oEt}(Y`CvK>W_vf>eGstu+{2uk6HNricavrb)gRwTq71_%+zTv~ z9(m5hPHbbG6tXF>R+FbhR61z7z&lpP3Aq6Kkkc63xnx$j#2@7Y#umxxBT+VuvQI~~fX=uxS z;W)gXN&h=?$m2xuT(1E(XakN;;&UxC!sw)U4L+aoJA&@?8x*owODD8ffTSCI!)NU5j%L3?mV+ zD&lc;h?@ba9A)hVw$Df^R-Ed!&yaf7D|l6%hc~@mr?cgl8S7YU`Vq|6 z4yDmOboy@_e`p|)wVUFS${0%?0D<|GDYCVmQ2Nd`<0K-rWy_gd~A5A>82`VYf(r!S?Z4WhK5GNVkq?(ynhb-q!7{PbEfy|^iarW`PYR(n>qgXEkf z5Ko5`FlLD*PVoi6+3Aq&l%|>`Ke~weRk&HasAM|5sDO|ryfMWONxtl2DWPesCMl-c zgUD5!GXIv|pyXvh@)_Hgx@P3c?6G?EbX~-Aun?0~V4)U_fu-Vo#I(MC75%4kQ2cyE z`$jgH|JuN|Ftj3ij4{d?GYuwA*?BdQLrmmyjU~an&V_nyXHxpN<&Ef}Ha6)3M89lnYj!gl<5; zR2mKBfI!QmOQ%n^jFwGjQ9&eaBiC>bLj{@fHz*dOb7XLi;Lw_mZyJVl$jH>+|~!{rm8E0;SwC){_kcneF>Td*0ep^Ap$0!VoT zi!f(+6WbAfhcXon%d9$R_=n?3owF_15Gp$Y{)Q9?*=j+LS2Yh^NDr`k0G=TvZ{$eI z)hWePVXz^ozobpkq|XZolApG$i7iLL#0j03J@4@A&s%spO>mER9m3#FYlGM*grlEz zcTQv)0-o73F)(zp`f`Q|zV|hd$$l`V3$ZvQ%ea!XA_PB#T6(WOeON?AB|>B_l@5Dq}sU3nJrkVqF{U1+_0q7=S8%# zkdMu%8QK>O87`?z0!ARZ!jQi$nt%qHA>pf2!YghHHvNgcXzEt-F2#=E1M%+N`)bH= zh`iQ$RDsr;<)@x}cS~lqbdjjanbj<%XI2Y@4!T{;k@q^%juT9R#tE0<8ptor@eZ`v|P3$4%=UUVD6ApDwf`Lgtp*OWGu^mT;$Uc=#kg-p?LuG98CEfDg zosnW0wL+xGFm|>OO4EoPqDhSr_MJCv`>@gv%3vO2+pw{y?Djr8%ogD9SVHeAnr309 zV^0&Qe$ifc%avQQnUS!tvT1%2z$#GSforVN5+G*gZ=W#4hcH6O0A?k*94D~R}c(lOa+eF zf4DQ-$DxxIYy6y}V<1}(+p5lL96o1Ej9pSz^oRXDAI^jf77JYsudHP>gcka2pA%#f!a=jWfv z#=c_+gxWE-rdU33H6EB2+?A&F7C7_Gkv3b7rRkVz)J5F0Jj0S>AqRCvSod6WRq$+8 zZB`46o3gOhFM39SVNaj%eK*}{(Qpz3I5ddl_#NnNW^>v~jusU8b!SNOyWRT|qKRJ< zJ@cb4iMa((J1II!-$Z$U27sNY7t>%OzTC|JhxRZ-N!=p z`(9iwt}2w!R`jtGLMk-(BG7(XF9OXG@@+n8Maw5=^HT~gs(jmN=AwZe3~9C{{uVX) zyHdlc%uya<@V}Rw9epl4wLBngsH}`shW8x=gC;Tw;ug>Q6>SFcIKtarAHxoH#8Q;Z z&-~%4I1zFyj2o**vokx2TT(|Y3(Zlr82n%FX|2xS+0e++=F*KC^84U;e)8n>$Ge8m zdv;4Moxj%Z0q*q07E8a6)b)cHFzKX^+9{rTNdKvOSeT3eMmHefmEsr183acTOevK| z^W_zYM-yy7En3%l(z4oF`Nj{f2}NLHMt+;KU^Fl%BbwvNC;3G82|(HWP>l}?CPY?9 zW;Yxy9x`rqg9~j9m5jb`&>4O@UM!4jArlhCQAkblVCC9v$N*2L%Z50b`Q_Pc)sgdUQ$$j>(lSGz-?u#|c^fJ`B~Hn|LGn~2hBd(c`Lx-WV*=fnJ^Snl z4CZn-?wDROhVqb6F z=1gh>Lxe<5`s+9dmBH8L2MQC!@tDEjlaflEUL2s2r$eGAECD9MiRZ!Od7urJq&d@Au^jbXg`A8J%!9JtOJMUp3GEkI7{9fDVyv7);t6 z-H5m$$FgaC5w^g6XO43{k8_@rJO~O&%L@y7!iz!yG`AnF4FU2JFdKJ01PJCSlhOVE zlZ)~BExKL&9vDp+K_f<^v8ow6AX~)em~pV*_Nn%PKIj|v2Qc9K_oE3~@C*94VX>T- z#54HFwltiZBjk_}+Hl8GLuUMV$1tw4T}UmCj+J-Xnffr@)Uw|Y&qHAt>AbrE&YF_z zJL2Rc-4&{?EAPJ3od`K-;-d2IsA^e#?{9XPf~_C?eedave3E`E73unmJFJd+&zGO@ z{Fm^KbYu~=)c6e%?ZVtDD!7k(ruz!%m&rpVxAsXpu6Kc;SlwW%(h);I_#tF20=KKc z8=6mHay+_zM;ofy%hfryZsHNBCLN2yIzp|cP6Y!4b(D_FG`CkXUXgzy+3E>kJvas- z^vYlLd82wZZelP&Bx2IV%ed=PAXQXlKYPRyLY7#zvcfj#1CzY$nlZN8Lq~7~Yb$eJ zM4+toU(JtGC90M4Ukvl@<7`5^$~GWm$xnT%>fMCSQw_1OigeV0J0dioccB&tUAeNe6xLxBRk%SDyRsQ_x9e?TlM z9>P47CaHRa*x^vpkT9JjHeeLOqmCG&GV8orFwE%uQ~C=HwP??8P zmwHoBQ61yr;t%SJajfUkO-&eGR3ywtt7dVsn<>E0n^x^Pf5-=pYPgCRwVC#L3}I}M z)(oNTG6z;x+#bsjV^kDu%%e~19hN6}yf9w3U@65QIz6_(mOp=A9=uj_qH#7UQ7baY z_)kTFidM8B-T{l@Aoo@<_bUcQF9kTNC3H#iU@R5t-d2LN(L#2V=|Tv~#;HsNivd>h za)D&CwKPW_V_mw*Rkgdx#W-LUivhB!Jj*y7`wUo2IVg!&5JCn+8k=P$2oVvuwE;=@ z{cHI@?3!Ytkpvy2r-X#m&o+OvTX0WokW|-&UT@rYrpq^Y0pSU=>EBD4hM{_Jf zdTkdVmDU@ldyn-io}q{u{(+B1l*`d5&tq}Hm1Guqc91t#1P|~Re<0SY<}8t5`KvaaLO6L)FEUqQm+!QzZMrig6Cn{qR>yXSCQK|!X~~D z4grx_^OGN8W%^}0AxPsjBCAioJ5*|Sr%xTjy+L-#JZMr8?PAgO;&0KTJoaSkK$%0f zI{Z9+3GeaaZoDXxuCv%vAis$(q-*QS2rugGlJUY_m3(}Nqo;*CItEFS=Y~5IA5C4F zAGPXcY0Rs!z{wDlrbzn=p40@6TcjI(!1T-SvUU0R##CGKJ&X=s)|sR>TXrhONS1F-V%X$BZE@#eM`MagCb&k7cc3liAFx(`kcAU#Vb)~xAgx|n?4B;2 zIUA>ECOB8o|S4wYN&fEJJ6+Xk!By9`g zrY`YApW>Ck>A{THF8k`U1(Zta5Yf@R{Ef%_uTpqATz;^_LzIHGo|M~4hZl1`iVA*t z{MR4UmTNjX%9u0jQ@#2CE7S8MR^5gY@q!y*^qRCCyp`=1RwMb6`jrq35kH!=JOy;n z`ZEtrxO*5shj6us#~>!c;nnKv8O;o^ob)QLn$uG>a_Ew91Q@5ZzHtJ5%CAhLV$2Ft z?wx%^o8s7@nlM!z5S4)~dXouqiZhz8hLcTtMjW-G_rh??k^8TKIiBuwsj|(R={Ow+0l9k5tYt>yRgXr&J^%%$H}7vP_xL;Py^@1Ac2h>!A4BsmCqI74D8@I;g|DosO%D- ziXv2?DwCpg#-K6wS;F*#;vaFh=RsazlF91c|8y;uN&nNl*bM-A# z{ISb!tFFh_n0z-yFQtjA>xBMJK%A!&PEo6lImt6b5pMHuUTrT85{1T4lPvDK6Hb$} zN*^;=7NocfBaC(N`0dp~O0Ks6`OE!N<8~j@6ue>uzFV50$bD&v*>(Vo7nFMO3A{Y}AtMFh(+@%q^Y}!On6P0-dPluqCIOOQ zcq8jx61QKObrMfuja89AHm+_3d>9<@HLUf?qoP0_wQsD=LVpcr9`n3kEq{&$9H9e2 zbWk{+iDr6sl!~_%(ov?%a!7(n-ZS1IH?JkZP|v6H5L9e<$PXWWBdX*o*2cWy+5aLO zvTbVwxxbGy!hQ<&MgzPR;%p)1bc>R-&1k;|Wrq6Q54aTL*@uST_sRwPUJ=33F@rC+ z6FH)SCGVk3i@zO+;yhl_45FwpapryMs3wevHFsZ5d`(VMt7csp_1y&5#P@8+D+tfm zW&mMmmT2Aziqt?1enr%d-kdwuGK1Gy2HP})a+o4 z+Ku1$d99eMB2A&I!s7OVfb$n`$!DM8yK_if zkOB^8By^!~-MhXSQ7Q-UlB6+pApqQMsK6v0$lo98JrqFOy1T1x-m#e!ppzBlR|G0mH4<=ib4{`nlmORAr90_fcT;}s|W@Qp1ri-G)C6uzyCw!ue6s<>~={2D@89^QD&A!*mL@wclv;n15;jP!X)o8;FDxd_%42K1Ie zMV*&iCJP~>!f`w%E&I0d?|kNXm&f1;#2u?w6>olGZ2bDOS|`Vp!^6*?hyIXh*^&Xa z4g618U8Fi~BR_1DaWGVGO5wI#JF@FqHjFQXI+z`9wfpxKxMFHhS;bEQRojRjr!DY$ z%wqdwEyZ!$;3zy09faev*<3i~U$H<$BWQsR9w5<>L}bYYB@=K0uS#jTZkKhp4&Mh6 z-GHa<7Q8}0XHBs+hkL0|ZTjK^U}3)&Z$IDWfu(xi5JpwEV;^G^G8|*%KhOTGok&** zPzDCu-4*!R((tw&z|wAFns@W#p1JtNEZs^+__Ww*ILkz@dS#D{Cgb~e_Q*$fUkX@L zY3R{Cyl>22vkLYe3UtAGy;odXp{++Gp78^9b|XEfj{wnYc;4pEWg(_-Pl z+(1;SIbk2wifx-CvCgm&kT-gpTsXOlt?t(35OT$CP1Taldtbf~jc&o@R9%1vB)1t$ zAt9dxQqsG}ure}L>r(j_v4@Sj_ie;ujay|hPB*bIRmP3{#v4p!udc5Wh)5bsKxd%;gt44j2*H4@ zcj9+2i?8EZW5(GmgY`NwfW@>p&2 z!NF$%GO9Ta7lSHyS}M5$Ts?uG13ARZZxt8m;jfiFnf9Bj<{~Z*Csa@~YGv;%=&j3H z!vvYK10k5)>AApSFxpKQ$S9vtH!-}S!N!PYPsA}+7az!G#2l3kL(X#N>Cz!<)&~~2 zw;FgMX6ASGfC$lB*D$)(*a~(%$10C)Vqeli=)|i*=8m(xlJwQH15^8+J96)V{Q28S zzpCMEDFgp7hA?VW>MKAh@8%__{e^gcJ0)C<(=J<-gDO-rPaBAcs3P0b)#SB zpQ#Ou8+U8H}gGJlUs>xN+1aCjkX&-ypbM?yij=1A$vSPFj|FWI#FWu{xbfe z7H{4kRrPO~mpV5JTVH7>%@>C7emuOO&jQj zFJa5V`ZnvwXfR&9mLG`*xNZDa9dtf=RP9(>ylR>gr)%pFJW z4vZrw5+xh)!5vp?!3+}v{A9^~4^~&7S2&8FNl^%6JAJFJ6rD;~N)fG64d3=63Mb&- zr!bjvgZ!I}xe>1XBPPZyuF}{a&}C=f%Cs8C-|SQji;h=sCw)r4zAFUR=OaTEoPIE_ zb{xWD$2LmbMkS8QrUWafOe;U{1R?rQZ>DvvF?A;F*BUvQMpTq3q{Pj`Hg3u<$?vl0 z%T$A%3Ryi>NWAWdoU%M&HIgC}*pE0l*|8h7h;{4+$-Cpw6}NrlxO0N2IaRwACzd#n zv}G~ago@bEMJH_Toht7lkz`)>KJb2%eTAe61(#9SOw^r3myl8QkxaNH ziAW?A2&*Cxf3r}7Ttih6 z6-Pu^WW7#kr-D^A?}58*D-X2o4m|;J^10K$W=@nK#M_l3DnumW@+hjJ__rDau~Px9 zHu$vk8L{gue`}kQW624u4L=oPW6kzN`5ketNAvHl^T~bjeOnf!n_-+cUUN7fYWT1D zl_np?qvTl;HLnLl9jZHP7}7woveX0**i2Az`MiQP_+Yq6&uOpC+FJyGN3?kXFN8A* z6Uz~N#J+ViDppV!pqd$=VNL+53ZQ0dRu=2+3lz=@G9-tz0PYAetFz*<5Ky?Ib@}@&a}q>*psh%$(f~|F z%s-RkcR?4dt52P=^F-ukVObG^a@+d6k2GHQ$-84YKN>>uL=ErWweAo_QK$f}VpIWE z4%}$uRxgS+GP*l^l&9jI(3J0CIKEXYxYNqGh+%$LdTCPSIiBJLWEGbT_d#R%Dx5kW z%LAn>@%cT7N@rU!ts_j8){QQNvBszk6*Mk3;EFUbTh=hMCZTh`Bj9ELn>k+H^5PHX z7BOlba(M));uYi?(rqOD8Ubl-w$BZVQ|u&jHz=ai>?Jy4D+u4KDz^4MK%-UcAD-fl zg(1gTt(a0gj16{iD-jG9T7bvgXD&U(rBn1d#S$z-ATTjE%B^r3(|_M_Ad4?zq;lZJ z8Hfc&G(|^->7LhIWoICltE{q@u)0?@l#64-#zIonTg2d%kheC3YX^O37VX18WDH#6 zcZ7dzpcSF}f`$wO2#O~LuV$2WIvZri>YVMZ*YtI8J{QKK`1V@q-i}|*<86kp_d~Jy zOC^!zqn5}#jLd-wMww$_D1pJ?ZlGOJ1Zfijj6e6(Bn!7Ppx0U*F&`n0WQ`!m%=voD z&~oVFHrj9%6}x!6$_`xzYUW)jI(z`RyPlwf&B~GR&{{UTvvh`R)L*Bu?yuSKl{~Roxw~$qHclH9~9isqi1RE{aQZ)f^HsV{YCif72UPTh8__-AC zB>LxbRCk%bzr6eMu174k8FwDGq|>yu(92ll_53$4oS&_ALd+ES1B(3Elw@w1>y}=; ziC&?T#-S6lP%aOGe>@Aj>Yyc$R70u45KD+@|3zCqvN<*$a;U7qQn4aaRG5CNYyk^a z>JruSmR{;TMK;w9V@d^AQ2Sah$qaxOe>);1-B2`qQ#FK&p)F@aA*WAMu`U+EHY(Po z{x_BpPZt=mUvGcU@EY%k2j~IGJx0_|HmdKL(|C&I*6@MUzj8OKh7;zLaK621(2i9! zckya|+Eiz&=q}Vf9ACSY{}^AeRB|S8B!*-4v?dm)XPP_OgrbmVB!sh ztM!(#Q?4{-Q{R}%)l3i(sS`D~uQkObM}xo7napcK<}uz>pK+Yd8SyHeW%YyHaoCB^ ztLN&JHK{m;-&du55@;f-0MNr38oXy`()|^B8WZkbEJnrG$nC5{C`IRqxmz$cJC`^o%!%fe``6@Va- z#@1+p2&~YNcny8pb(=h|B6WOk0w;3m z>$nq@RrA^FA8=QvJ?MJlcg%$K%BCGhpd^{_P!~V579+{;(dGP8RKbz`{;!X zv&l-wCT*%BT+f>p8M;UEo&cLaPEGZHbU|q@ty`pbbc~{MgcN}oyqK1R+ zJuxO$6}HcoxZ?sb^o~NH ze3OHG{}yg^WQy%|M~1h~=bu*SR`p3PZlDNG1nczBHOIweSG?j8v7M~uB%{CQ2oFYY zpgbES9coANVnYkl#?V`ACM#ND~KMD~NtkjU=H;#KcL)*ti z+8QfC>o**yYNUFETWr(=+_`?oidguqF>GasTdF+0{*1;?q2l4_SmaTUNAjZ^+l~7fQ0S10NdxE@yY-r%b7P*nVD=K(&_d*o3Fq4|cG_j4_NxC){T~6y@6Y};e`n2J zGRjr^%l^dNzKAPTwfz(Et~ys=LuImvhzga$V5lO|1GIuj-VrK3@t1X>l_GXx7?Bx@jo^QzNu?O1_1eH~u z$EJI;o`Oh$%y0H)$!AN}s{0P)7nbq^Ctz`9C#$oSt9}r*QSeXrk5Zs3a?q~Hmj9WC zP@8+x^fgjS92Zh5%7Gqa*~D*$dPkGP7>&YeD)89|$|&n?5{X^sqkbzA6J^i$L|im)kwkPiCbb?0b~)dT-d||QbbwzKw&gl z8M1_k(paO7{VyIkiY4JE;ccfgO}dCq_Y^Rn2g3_MMr3lxW0ayYZ*!dcmp|IPw)8b+6HOf5A7KcW1WS@!)$| zm#s2Bq*`$sFy0br22o;?b7LE!rg*y5Tz*jTEIVmw3_aE41_Cv+C$s0dF=r#Nu^mh> z^`>)Ow4{Jpiu3vFqUYmhaz^DY`(*9SOX*uBnR0ci6gDm!Fj_P|7_$jb(=A%Zl4NSb zhNmTYzCa7DkNYt$)zxedfmX(FJ+EeIth`>36q+AQI*;xSb(3m$Bo(XRkC)vMY!4!~Cl96#@O1wD z)7ASt6EYbXU5q_Cx(9v()4gyxVTea)5pCSIk8B&|BAqf2ISks@KUA(+*jepA%)xP< z@z`^7I0$hBzkp7gUb+)7Uth}p_5(1GhqL`1 zun%8N~?&l;WwhGx8GYAoQo>QtGpMhF+DW;&Ug@ zQA(dS`c-+!!y+`9`X;#1V^bCp#DAm7#} zp{kA>W;NB4qc)9H0vky-*9tRI8w?vsWd1kzPi1iQa+Gab<1FmE@a+A+j4WFJ&@)sy+<`(;a78I&Wt;3(IsEFM&J>pA_l5(<8XW$@|K zQcjt|MSIJ3PtH7mtD<4hW*Qqh>`LB#0K{R+2PT-ObatxmY>##{CHk}ynFsuMsONcr z*Ke`RWup#s&YVuEd6MN81jeKIF1q%1b*YRf$WKYJf>f~>hgl#^ldG`b+YQSBO#V_G+dO$1}lLYIi5;z!Y=X~ zMbx};AKHVl6_m{ICIHYU?0`HcFNjBZ+uQvD{0FDMW1T)xtz z=u3*hV&IrVPU4agHl%c0+CbkeUjkyb(@6%5E)K#7Lc*uWwLe1`CiNpknA^@jUDpgB${NwDhS-~$CXUtQazm=2og1$#s zF6qtYVWw0wT~{%J_mYzJ^@@tqyoX^jX&mA%!Bm-k?BX#-rwJh})87tR0+ZT#()9OF zM&i)4mud`zTdzF|tJrz8P0htord0iFc@7nm87~31e3bQ-^T##VWoc6w^^z_#w4H^__k)ia;I4O36DMN+)55cc? z)6;cB3aST}%w~t18SBKuVjN)}&Hf49H+xdTMr7Lj4N?(^RV33os-?52Qlym0_1U=O z^{j8lQZwuOfn!>{0?5Reh5|1-`M7#Z zguHIXQh3^5vj|^-EYnZRj(AXUEP9*Buu6+0(^J%_Cl^5@34Kj{p0I6bge);8CQwnI zR`H0^oBjfUnJP@;a_dTL)chWiaoT>kTR01l@}APm)nGBS;b7PQYJ9qyf19MMH)L1!#0UuxjEhc>3o6D`v|Z+=H)a_kCsx)*%XNBC0j?MLc!?Efubcd`Ge0?-U8UWXLsGo} zNf-mIujy0J5uKlKNTBD=%ywSbBQ2ykHwF?ofe;p#{H-|Gi>s972nn=N7cS+IuyTA! zn#DAvxaz5%iGhIR>F)5ojIC;KSbNasEukbqTicx73Tus(WGrA(N;bQLuZO!3gD??S zj1Pvw`~HwHqVF3;X1hoq)6`46y{kr4vTR$uewxa5_h9Kzal4LL;VLR=DpM|46+(k# z-La+`3S(KXnI|%=Mr-*+7Vj>1ufOaQAd=_HxDh4ro_AF1%;fi0Gl)GwsBmofm zs*3=uTsn2Gr`z45Ee|fEDc0ygp#kcWl2a< zvtua%D?^IwioI3hdeOuZ*x(KS3H#+}eZiV2XeYQ3+y}})uiP^1`7$I+NX=NFeM_k?tnrXseNF)3b zx601b{m11QAV%1lwU1w>I4O0{Z&~ZVkq`2B{4JW8{UV0L8r=1|bZnK$bJVWU58TM) z*>#+0B+6W?#c+Nrbm+e&OALN%kK=cgA$(4^wxyg+Fv46pA;)q8v14~rgR2=#n2wx! zn!#B^ClA?0_TLsv*y?v-+{n^X?ND&Y_Ia`1DC*=ahJrrc8S(wuof8!>fh?Ub{xz47 z>hD9|c*E;uejGJ_!BM5~5YgvhDP_ZE;|PJZZ%_-jcexqq82~Wqv#WkG5C^QG4ggp{}+Qil1ICXRoeL zSLdy1wf4FWVA>X`Tz5i;{6MUEeL97DQ_SXC(kZ$D6DAdoJM42WxQH^3*D37L_WzJ znWkU}9ToemjYL9Z)l4LyBn?}T{WyQS`i^bhg%%I;_-$j7G;h%2X0*jpZV|TlrleOE zseu5~ zAx98`0DME<7V<1k2(Y}T0dXZi2w_~T034e!nFgOlk-E5Ssd4lp&RwS1g?rgj>v$0KcD^QHRF4RO*)%L znIwu?3^UPop$Jpst9ecAdNp63t#w0I*Sk^uRYXallJZ8dEU$&P(L5*cg7s!Q~Jx220(4%xiPei_x=jd5;$fG z7p&X(lhh9WwO5+?iul>qmU4#*_i&7fliL5`v7vfe_AicslI;eGlcLutLl{PN&>~_U ze*`#vp%$po8{Le)cXfR+9ZIMlqXTJ765b9ipm3}zFuwXjp z5JE#s60AzrCl3b5Lpa?Y`xQe}+=)yR`6-_;Vq(%P`C2psrJMW26f>lxx#h{FPEvp! zXY4?YlYxqfNsuyc}}@}Pljl@u+&m2qTPVv-Rk^D>O{ksJrAU8sXR>{)WZ9N6{dPg zM5@KJ8@Og&M+ySI5L#g_IWb8AL%G>Dp-&`+d0O=c*ehaDho|6pkCBP;Qf{lz%sbBj z6PM%)s^bG-I;O_?c~@Nal({O6C6%@a0w8GRbC&7lYL;-_x%gy`q(0ZOtZg)Xt4H*> zz+{!tXxYPb9l8zu;~b2n8@-u&PL2sIMRe6zs0i3$Dha`P44DoYI>>wSsH*1A#$1#f z{@sD6+1CAgO7yM5!`%v6ozPqfcOoTnq=mM|Fc}@l(A9s^=?&~hDV-U&+O4=1eD2W7 zc*q=7B=CVa;-&TTHN;2h)Qz~2LRnT3h=;FWH8=)grCzUoHXATO7Alq86+T5gAuG!t ztWaVMb--;2R#x2*lPN6A0&tCv0XXLfLLYHPT`flk&$5@6K7~Us;7ueE?X3pxv~;*N zKDdhmk+ShD11Uzdp3>B&%_TLiq9tu$FKI~!8%S7@a)qxnNVy87r-L}sXLL^|=i8zc zKrdeY^?&@I|Ih!@|2uy5$Ls&t|Ly<%-~ZqL`d|9L|BL_j9<8#8(~AhCZ_BgO-%qYV z)F~eR{pGuJ{`2q8A*bI@7XSKv?*so_zCHQ!JM2PFyw_NLAccf;7QY`5S-<%GkPbs6 z1)l!j|GV_ZFdxr8J$eX6D=i{j5f#PUVt@*v$Wn<=F0A@h5jX^8e2h9ejn5h8hcLGY zyc*S}7T^PMrNlj$p-I479{}14+&F;XIZmM;C`!;%Qg|Za%B*;VsXy>w=(#CwiU8=i zX&U{HuW9^=T~$k+zx$tSjI5^%YM)YoQO|)vxESOMN=^GWvYyF!lv%`(5&pXjc3zp9 zsbtn9RXyC=tq0fv!wj#4=7!vr5ftamyqhuPC=8lBcpk7~wOWbNFy(lhWpk?6(Zamt z%4P#n8Hp^IA<2r<97eWi1v!{nJ25?;s6WwcngE8+qw~Mf;y7`-ZocT=UtGN-&huu> zRUj!&RnlCQDq{xB)YUiG)4eFA-u_bR*HE?stc?O)8oof|TO7 z#YK2YxaQM1nJx;+tq2vT-Qyt@4*4fhoy(qf@bvl|1-FN`)jtF@ja=sMLX-5L28$e^ zK^$eiAgvp0X;YwY4!;F=;FgWT15N@j$)cwcAmK~0$@TlLt|H@Bz03-#4)j| zB+)Mt81RO@fMmWzmnx7jd4<_ZV*#*H)8D9QNLrdN$*KusUc!vf0geG<>#?meTr=|z zKLhNOAFv*=<$Pp^^763NxJFAbP+mgEvSU*AJjUl8Iuymalr7qAMT42}!s8zhU9x%> zPFF@z;z!eD2FE>Qc`O*&SPvde8`xFAnu(YS-EYx9&4i9zi}ff9W(S+w{GXFBDt_|fZ;!IWgAeRb+KI~}1cEO&+CZsd9sRW@$N4UZuTel+!;hiJAd{U6W6;x=jmm}E>OZ9gIOBXwPx z0I%f(20*tbVt;BxEyqB}qmD%mDO~kNHLaE4mo*60%NF26hgYpbaJ8BRZ%&owUbN;L zho>0aP?}mHbY^HN*2%23{t`xSkHoXF zBjre?zdE&xOWC5+KstSS3B=>6i^3sSk%NxaC>E4KOO!8|*V9CAo5NWYcBjBNbUkQ4RG(;5Bia^BqaDL!P9vl}~!AQ)q2RlVuH^*JuT>0aUcbBiQ_Wo-C1RYV}da+|+4{u^>CuAQ_qM=c0J>4^L-4D{DYP zfVv6)13xF)be}CdY1qW!dD7>^#hjz5!=O7`Xt4mpoSDZ#H~I*!>1w)L}`YszPwH2;F2O3zGSOykgkT2voD{YCit>0coQ?!`&@=0 z<(91>gqin^!65QG;Ixq#WaisoeMPQpNiZ26z2+g0+M0wSSXnWJ1=+=r93)zmI1n24 zYK1?OOWv&dO-fb+e3V(H>};dUyt z9qL4O`XI`hZ8=Hnz;u#XE^0*p#215D_vso86`WQJHp@ELgL5RIfgEx~{sE31ci4h0 zpH?efVx9o+Bn+C{rgJU3w*Q4d2aYh)CPk5^viJ_g#rGo%W44!1ddq1dadLx+IFI+&WwKy;ZJ0z3E=sUVx)nC7+{Wx*m)Dq>DJ7{Ens@nU=EyhScP>Q zs3n8n1{XzD(}-iF{6A5@PWs>}_16g&frIOBszN^D>`jw1+ zAr%Q$Sdql^7Oizx^v?_4+^oHpc z=cnFwf>NXH0S1r*8%R%lXmH~=eOoiKrDn&qf+l+Jp>^(4QyE*xxZJZuisJKXn=_b< zq6(!o{T)=8f|-;%J~)xD$W)bu30(<%G(sO`9^o7ctD&Ej@T?wb>!J-;&~~*XNo0ud z6@MTpvN{}eaBe7eH{kWFb_P|A1N8B3^{tI7GRi>Xc!Hqs8nmAKeEs72-(N(y2AirG zw=T=!pgTC=(>kUb&^eejl+y$Yob_*^0T<_RZnUQ1+H;bT*RtT!>dNHdLaz6>G}^T- zqaqqHoC^pmnOz1;Jz3<&lfwqk)Mjrx7yw}9HEW6$2?>j96LL;pa^Ss1wNI>df^{?7V6pH39pmXm6cBdc(Qzaiup#Q`@%hJ3~ z?|JI|$Ky;g2L2^%- zDKkwyQwCd}McqdjNVY#zF}|}EqoE&d+?zcD3rAt77mDO)>vi2?Kd%MTgP;MOg8P$+ zJFuN7jK?O;uQy!1!>j1kksaj7R|9!o=4!Y~>nu=P?3c9R)%C-~r64%kL&>1Y9$&@w zoi#!b$#cS*gSHB;Qi^_iL&LduGE1{!I(Nz4pKk20F)nB8KcTG_G^ym7}QRMjOrggi-7PlUad2wP2)j_r>6#G0X*no3g2HqNiPh&{3Vc&4W0Obkb>SlNNef$UdLk1uNAa=#Xp& zJ^6G4Kh0ZswPmz)I(n(yZCTKP)u+(Qc`s?(kWSrv|Zq-ijG5rZdlC+c* za|HO~+k0Oz%3Q$b$Ej4I32$F~?48mvC`C(GdL8m)1EuP%zg*B&Wx4pAN-BCD*UI%> zPRa_iHH$&A5A<7cBsEB(1|@i48i9Wx)7?ivA4q$Zq8v<{4PX}8djpi$4S)g3tK~=r zau^!}UbkU~2T8jR(ovM~pVtJx(Rk#Am22qCxlDB5#--oHL<+EadzY>|Mi;~pK9idc z5>P(nPvR&6d4sh3Mar!T-@UU*H~t)zFwNoTmm-kcJq`M;#gbImlCrL{#Zsq@ytxNb zL}$QJpUDgGN_vQwDmTO>T}R9CW~fgD-EWKOI<~|e(L5ivDjspSqef+Zfevqzj%*Mb z1q4zUVln$8+|MAa)jehTZBEN2TBFa~6*-LlD{*Z{3R$s^MyE4@GthS9;4w>C2ct1P z^DN&T&q+uRQsq8-T`7ML0YIgK#wrql^BY2z&Z;dX?lFznzJ8?n3ix94A;O?jZbgv! zMz!HaWX3C;`&wrxdTK|=-$MwdY|TZ2O&`w=VHWXfg@_Kj5$?o~=D4A0y>g{*)3&>n zcy2gG#Iezt`zHehD{Jx3)z3v$HKcyCe3n=bh3(HK?H!;D&vMSnqm`0RXyN&I0cb#6 zy~KP5&@&mzv!@|}E$gd_r2A8>27DgWQ0I>?(E}=bvpXaxfsBc=mtTJn5Man=H)os# z>C70g4f-%kpoPun#9s*#+7w^?%ooEaR6j7}FsKp3(QH{|3*?vFG5-#9(um`el?^IIN7RlMH?YmAmX`Vi!0YX@_Qa}cH%}WW8O4o=0HkgVou5v z2d^Y-DR5m&!`Y}1(~HIqFV5%hsYPf}W@{HkZZIZEC9f>K4F@Cn{*xs`sFI{6*`=1# z1yJ{X1@4LlJ8@3XPb)?UBRIy$pIn~MD40#yzSOG40hEg#qe)OwoT8tntE^1P zOSb-nI&lyLy;kZxkz601q%C^Ft;?`%G8tm3cUXgHvmtfhudxsxl?a!k8Wk!piomj5 zQrYZk224DOsFV0geW7KgTbJbQ|Pjziv;$X3Poyn5^2J#Z>S z$74qvD2$3%?lV>aN#{h(Ox}IvmY3&YD3%I#P?Hznbjd7E+2ME-7r75g#)tDg8QvUW zU;i+S2;6a5NW#Ci%T`1ZSb)4_P*KU_(gWLyyJ+)!cek|?6`6ON*E*h?19P111HUaHfH>_v&0*$0o@)+8k|$HS z<9MBxrK+ed@f}p+P41f>uXsUv_)T^Gcs|1vplLHCgzu8fmHE+B?r0HflSO8au9aLK z&X|`ABRh%QcU?qVct;W)Imu)a+@pfj^veENN0D zeT+$RzbanYsA8Xk%jMggzG3tI>HMp~kGjvmBXH;F>D9YdZaB6i?L9X}YN@Vt?J?f? z8~Ifv>yuD3dv<~HfFC*YL5W+nWHJbi7!^L*wnUU5atMmUX(NQ=fW63Re{D%VPD7TI zK=A5yL4{Tv5CO zS+rqP>T^_(?6CtA>iCv5Gxb5Dn4+83WZF)?c0laB)X%? zQYwg>Xnvsqqg03wab(T{W>kz8hgz6lWL#E|s#+B2CTmf5tYQJaXmg_xzlC=2yv>LWhYOd5uPOo6q(Ji5t1Xga;6D#dnJ5&-4 z?c^_KXRAfleZ2YcPPL`^SrfjjBpM@e{Tg4fk46;9Rh(*?V7bSEUN`v`7k(qtAOC@m zbKTnF7^kBtKTh@xG=Bi2CE5A)&4MKolGz2XIaz+g+Y6GX7?(MiT*`n>B`CD!=cCUC zKOft|CxUpXnWkX|A1E?X7Kz0wze8zwjHuf!?YYpJN|aa){q>vOsQ--zfIE-}>ck5< zfn>e9HA=(VDtL9Yc)xgSUpN^cLdn}sfjfGkx- zyPjAqdTMqkxHP>0q&yC=6=agTtOt=rZA?Ls3tHIqSaiy3k9}Y@sn9u7-$?rKaV1AU ze;sZN0d(~2`5`|wC1HKWHO{FuNDb4|2%enJPk&%WBwF=L8SM%kR*d(3vC1g8dMAzy zH2NSA6+Q?|r0wF4dI@_ituqgwl1>k5&ajV4Z%ZZ;hQcxuFLQNc{^kZDErA{`hcl#* zFRLV&$3+bMh##)ai{4O#N@T6@^B>eIkWbnZ4399?7HV1oemXFTI6*ntM5G~#&AS@% z5r?buhSOiQSg`U*Q~>;LH8~rkoocBt?Dh!IiNmSK@j71ojeuUnWRZ7eSHZh1OKH4L z`a45$Jz1SnbvAgkJkPNT6|=TtNkYY{T8D{s@-Bi%((1HjikIKCLgu`Ec0s3*dq3V>6W6nSVvTq|7{h6hu0 zhRdYZrAQcLbcF3X{vO7H!HmL zUzZ>~br#YQxaHKJm~S)%5OwkHli4OEXF?B3J`mCr5?jsdy*(@ex@i+*D0%;!q%L&v z!4F>C0<$^`e$MV#Q{@3{R^+SqwOCKs`jymH+d+Tc(xgRn-Gc?ai8LvI+xgP`R1qe0 zFa12qUEZuvm(nI%+K023TGrkD^4bU#$n32Sw3GlsSzOD(3TYaW=*cw$ziD>&8@(qP zuv5$!TgOwIZAGXo9TPc#-onXP`|{dV011vX<`dw^=TI5SM5GE_l~hp@q{x?FGs#7m zq$1=>5GcMg$J)T*8ls}K7H>ud2eE;)hzyLsr$&L2k&4&h$Xm3m&!C`NO`Zp?Stl;y zMI6VWGXDqqEKiS-YOX>k3YCM;pWpUX`Vwbq8z$GEjtnN{rWGgp#uFE)28bEHS0-Z4pnSYW<*xHJf^SN0dBlvsFfnEhL*kw zEQyxIWn+BYMWSb-2bD3pt#K$KO_-N5#%UJ*lLw$;bw?}RpSiA5m%wk;*c~C4ELoAS zzi96R1|2Vm*@pQX+hm2DJIHRA4BUs$9T;`d^N8BKw7z%!isz?;fzfh^NmXf^hMv-) z487Y95otRK+C|)LtwvIEvm(D5O5|hk+_oz${n*IK@{~01DNbk1k{{pSq9-=u-wJ&* zp*OsupFeT<>pE>t_rOBxS7L3PANjuYwtDdUBhFB}F>23M2x+L)%!s2-Z{Uq{gUmp} zWMofh8n;j4#N~Ag0ZC^MF2K?~S6NZ5*wc>Af&dk5Mk z)Ip*CHR2wi?jk59CNnb>bqhw|SEOXbDgIE^QYq2M%DbGYUr*jcvJICm|MIz1(ksgR>*Y13K+7fn zh3iEu$e|Tw)JhR3+L;u3@a6(8s4=Zj7Q;H{kDTqu7iuS$u z`X((iO8hT2*YLUNHf4#Y4OTo#^ZYY|Wa=waLr8JAjWIJD~jqt<3H`RUF?P ze6(HYv+vE~0N9G5zvxv>#i{_72SSS#Uax?}b=th~(fsl|ff4sxTFkOaZl<-(elvF)rv)NwI8HGD`%l_Mx9sGks-r8R=^e|ID_etT5N(>#U*PX zWish4lZZCafPS6Ds@7}4awgb%T+d`4El$v@HoWU5UDyy#j|0~SBg`TYks-Am#P%dtRpvBgCMjo zp49-)I{9gFDL>HG`ON56xe6P>0o#8opw3BNUj+>ysKGQy}kxN#>Dv8Yj*%R9tuh;IqVq>HmvD(fau3FEbLs`C;YpJE;K4}jTA1jmG^iOx@_+BzS3%=$aDfL7FzDj%Z) zre&2)1+q5*&)y?=3hubaOU1U;JWhA;sdr%>%JtHfFg775C6W%rAQhQn|Hm{Ls=a3; z1C+QUMX80od!^~s?h_7p4o8zSS`80zjXo77l4yj!47xj_A}*qWexI(mr%Vu{R(JlE zre*nAM*uJ$$t;RqINmOnw&~A#X9)RB<9li*M;xdSYGXT-H^Dj#T`W)WIttQ;C~Ry2MbiVws1QHcLI7_mR$f=Y%*0 z5tSIQ2|`&{kYMa9RXfg4!~X|58XwcCwvwGqPdVa1juzi@?T093I5C%P(v7ldu;mI% z#d=e-JNOx_ckHtHN`7EOSZEun=JnN9X};-*5?|fp+CmP5fOo#@5kg?}g>_~8pBk@l zcXVHq<-WN&JK&PVMvg1-GCKF4zi)L|!d$329=8EHN8r`N4-Zt8!^0%?B|)^}0th0U znlRh3DHmiZ!zWonFOFHK1|nA5de`&t6WkvCg*!Qi2-A<~pNCrHaO5)Me1CrP2#N2lZ) zECsA+Uj_RB7w5)(X;Q|jvLC$$KCDq>kT*KSg#!M55@~)ibsudYS-CrU!^yI1*Cvt~ zgH(6sCV98GywL59elkw`^!gNfn!UbUd~5A~?*Yhr-M=Iu<*@sGkLffV>cCs8Xzg@! zggOL_W8&_5ayEH%7iZoELT(<}A8kMsAS^Zf!~CT&dCE;tDPW&z?*7rc#;eM+I#w@Mv+_Tl2= zylgUXrm$nkpP0yB(p6$9(0y9%>*M`oly3Y!gz10@i1CEr7sg^)AR}rjNrf{6aZRFD zp@y(Zu}epbYRmKm1@)p)nTI?}p1T^E&^aHB<&vRG!;v(UXecCAdY+G0Re#?J!3Pu< zPG1tE5f^^+@Sezpp3suTRbSfPeu4j9b+FIOby@=FA3?%`#)Y#e=A=svcOE=B?clIw zzmi?`1c(gLIn2}=D*q}AVk?>JHy|yW<8}F9It*reH{5*?u=(7>oSPF(1jl!iW(n0F z-$NP`7fL{Xe9)Q>jZ7HhcITmA^QRThL#d+!5CaFeG{8rJ9y8^U2S7J(7_m4c2qU1j#S zIA%*Uk;8+ubMGXe5@S$8JG6}fin*J`l7!i02$Z&x3@LbE0=nP{NLV-E0uIQoxA05pp(bw+UI1X`L2eZPTC564K(yE zlY;2CuEjYAhLH$Z74bMa#La+Ij!<$~O z)7f&&jCHIv{Rrl3htkdhI{mkeKQxfY+D&muWsD^cfWUmp6xmu&D1B#}aT1Z*vgJ%a zN%6($hwnL5rqAdrHT4M(^pq6(55sk*FQujpqO_ngqfET+@#BUVU zH06LHwA!<>9eB3V6+;Rbv&0go_yXYUbjWr}Q_YeeT}1sV+$>&HGMzP30wGO!V~QV= zeA&fPLepCm`az?$2a&5dW&SO_LCMR2YWC+c%?0e$=Cq|U!&1&T&<*I9N~3`s5NLUH>GUa9wX6z@`Oov^xM1Q9(N+)HDXHTk13qfuej&TF z6uD&kI9{k(*4t_iUI^D#g}SP)g)=izni^3K0Ct_@r5U(w;l5+73-w$4g?NjIK)oQG zbn@vwqXyb5Ty)ECl|SBj(}6B_as2-`b}q?rWl4JOhqVS8_X5IlQf#wKCYi*GL%fn? z5qvbjPMT^KB!WaF2?PZYOd)47lbP0_xwfM%XbakczW;akbIuKbQg>Qc6_auAJr95T z@9wmIropUCk>ZSQtMLg=O+BHMZ0bFOo#xWRG&LtnU(Y&~XloA&K3t1>wRgF&V|bTu z2APwc^}_8}E;28{rta;k9My371nA1;4$m3xJ6XJgrRXi#jMh*^LvaD5JO+y}XSB_T z-=R#|j(Gguev5xNpVT?qat)!frNG|+fsm~h^mtYC&=u(+>>dHn5R$hrl5%xQF;yCD z0QHx&DVp?o5rX8W4K?w|SunP++j-gZ4!{0+2T!L7?h&s;8r-lph>b!x`dN49M5ZCZ zGkYcu44tgLoMD3RevQavKN!=6Se%k&TuE9H5Dqm3JLrt6G(?^m+>D)PFf zZ(V#Hu1>T6(WOeOO9O`}=UeWQ0jsWz^1W-BaJS+Lz}reR1*oiA*QUC75~ z)C}#5282s0lL#Y_U17-IBbtClG($|JQ^G553O4PaC<) zwcaWZQI?cLfY=S9{5m4}boiYT(O73LW8cRs@FizLY)`YB(ifkqwrpI1lG*uj<32!( z)G}47wcg*!7VZ<4)J*NVT%rD)&MH??5o!J*pKv;!~Ll8VQ-l0lAvWMm9E7lq7x*% zRsra^eBqUWJj8A$4bh>MmV=It=#E@!GL`uH4W%xlLu8-ICdk+)-KjD*`I>Hd@6YgS zqE-lq3}a_2LTMVYLo}%|!oKsSZ66l=!1-2BngPp@R011|%I@y7!)yWmjwST2qG=W; z9D53+`c8Y@N3PtG&5VSFl}+=L1XcwFws&NPriDw+%-=p?h!1ImkO4x;oh_;#s+W#> z*dn`uOtm;x$i`VSK6tb^0|M9NF#-R(Iy|Z~jo=qiy#A=NW`+0~rPm}LC$AtF%rO-> zX7BOVY!8P{R;=Ua932DMdfHZXR^#wF$HdqrWmU#ew`LBHoFCK46DF8{=x>Oi46xn7 zhf@@nm$l+d-{Yo+;pd9!)YDPp+O`s-V?n|G^efPXhD%*H$sx%?QBShX8fA$ znIC;k&MgA9lcJ;aO@sqPST|VDhVy28@y#VpmiEapmVZSSl}W<5eY2zC+{znfvI&gw zOT|exDmnIY$+U$G##?eVn@%gd1sjE>I(2MR{S~%Zb$U>wt&Tn1-$yu|Y`f`Z9RtV7 zg$ak{^69eA!6uC-uY3Tts1nce%a5j^@&+)6H|)_BV$@GqUO1+dT9d-)$ee1}X9>p!Gqn3r{s9FsEulKZ8XYg!jWNCBhRt@NZki+Ih4x5e0fF0 zqX{-bEm{{jY+T+BT2?zN-}wGDsR&HWz_%F%qk%b@(HvJk!4qwefU^0a8Xpu)h^&yz zZa7*zF0?gNGJ3;7XZY#GV&SScWI{%9lv0yCP@A0vQ9I^ZjYZONpqgkgaAzf? z4zj}$Z;QnIZ%eWhMA46~KVRzu0J@ObuJ@e}lG>z>R@+exl>672*lp}Xr6)_KzBGM$ zbaV50seTm<)EznBHbsE41TAd~T2FX*I7}fy$=hJ3ij)~~T?Af^| zFqq5b3}g3QbVfH3tHPdYQ$#kylf!UU0@|eZgu%9#AI}=*Lr|h+nS4QU&?zyTqEpo1 zMrEMH+a!{5^&_A&xhhak;0DZD)y8JSI)U~7ZK)tgBN_~-5_KW59S<{$6jNGx@+7&h zcW!egwSgf5kdyv8PC{k!b@`FP1aUlOF!4!ArHL*P%SZqT)JAw9FL?{4w!NwL@H2Url3qUAU61XcG+oClr$Vxn{GDT=${Dn&XC*~{ zi$qdv>+Le;n6B*$ZpMNt{j3Uqzb{uXF*@OHdPdThziOUki58R913E;yVK8ZPbR*)1 zoXe*5Mc4uxMvikmzvetAc@XN-GfEEvFxl3K4P&5gI4#9PuL)-3u7?1@JY_Pv{}U|6 z`8#yG_&s7YVFZma8g;$R+yQ72pJV31e%Pbh2l}9I*iVE3KYSQX&Bu5#sqtGP+J(7QRIq`22FIlIOYl(1tvz7J^)4bPRyUZcbi_~~{17r1f!kH!4b7*p z>^i!BPaCS)>(ys$-SSl<+pM&XqE=IF@P< zqk1-OVlY7@V$#LSyz5g!s;J6-_J}2fENBFw!XDBGCVAO4V{Emjj^GH^R_45jK&bWa z&5u(hs+IF|hWYk!HlbZ*8;~;cA4t67WE6ks;0czfV>%s36SH=oX>PX|ItWgbdh>Pa5gs}yz8A97( z4y>%WU6v!ps4UosqfhG{mM3|f-dn=fY%7M{K0gh^bE@>W&rHZ<@l^|`jkS!ryNI}^+m8oDcz)D^(kZiV= z=E!5LOE`_sS!s#5!w!Xdd_&y+V;+FU-en$m& z7pK>Z-zwvKm|w`Ft~i^4xF5%~ks-6${#V8hGd3<;0gjO0w81d{kV2#RM*vb(rvxuK z#Q0_vAUFk^D|eoRU!npGIU_K22-%C&s|4)%;^HQF9;Ph{{WLocY~vU5T7`e#46#MoMh&;_7p&{?C-?Xyp;q zliY2YxDB{6d{_F0;$a=Qy)lN+$~mJ=*5ekFKBfa zJD5m9Z<WZ-{z9sFhLV> z+zo~_YwwoFn3aAhX~Gz5EIVr#(CO?XxIa3zo{=FqyM|U#Wc|$os6nExg}}=T~=`{ z$}Fh;nEIjy4DvAD(Zn0>3GPoPkt!Y4gXV^hM0@4r*UTR(sO&d*=z$ks6<<%6m*0T4 zwqS=Kqt};1a7m^g>O@g@LdgVYJxC?q;f>vqHbF?L_xhx_H-mAZ`2Ag~TQKaH7998) zl}(w^e0o9IXqH?Pr4WV~}=xX&uGkh9m4pFws%&qmP zVIG(kEMZhlEsX9vrHQv1Hs{6+hSA2h5ne9V+zZsfMoVr<^nzClc~%z1nnIK=#h`KL z=p7jr{eF6V*c7&PhY4d5~5wEq70sPH<6f z!zY`Q7^}CUP+>D$^2TX3*~1Af2)HrBc14y9SCxdE4G2;$0zzJPK$-V&YbwnKi7vCz zp@^$Rvl_k z8Y{Cc_etB#33}iqc#RGfiz;sh-pW#0*BUwvLR@LafY65((u7Dwd;H>)`zi2c&}sGml45SZUBEQr3t5_HdKl|!0CrpG}4v*(NXHjf_O)P=vy{)CKN?k*8@tULg zQV^h~esW~hx(;_h$bxrMK)w>Z0_B-vFj$#m#2tGh(bA|}Th2X5K0WZPbhYi@BfAFE z$n^I8ey=!7G2-{?^w?^%l42YsPCmL-a;3nSEg;N@m>W3}$QAz!d0g?RZUSLkNhQ(@ z0;Qb+SS~TPipg-=cr&dPz#s*I3g??2-3T7sx_0><+!a<`l&brZglya2la=YxS&lV7r)V}7?y!?${`Cp~*bh!Lri-#x$YdtA91&0@N9z+GdJpSvC zYRfep9p#ua>r=h@&~9V1l4)%y5ihtEj9!zrgSWDYyAxCc_>%gS5Dk$(nzTG6=%Do{ z4oz|QFn$iM2$tFD`j#|-s#c<1!&D%*w5>OvvlMgn(~4PsVPJ89E(jJ-uch@~tUv zn-jfSc8O1A z5h_uYpeUU&QJD&o=xh*;zIO5gjALf-OvxQtR!x9bfan)SO#b-Tz2R}T{CtYv-&WtU z0VsCaUDfsY8k6s)=%qAqb)BKV6C%#j38$!4=bYpjq6jznlULhIgG8Y*)Fg|$?uFB2 zROzn_mL*c$g%QTOc>L~aA%W{nsn6X%HE#D;nu1rZz;{a%6uB=AIKEkVG=6!BdXC3N z4$j#hyqYSbNHK<=4R$A};&^#_bs9(p%Y2dyUF)Qw-`bM7Bo>N{<4>EGk7MVR*dj<= z=B(EoOiu`xPM3tF6_mp|^7U1KV9vy&lA00KehZSj$6xh3c3{s*DztLpgdX|#M71*6 z5Zg~Rur?l!?`ywgAGpSv(6i|T7%wRG;uCm%b|WJN;nNR75A*m$k(jVyM|wwnSSA4i zFuaAjm&EN?W}U=SLyu5JZ<7##66to6yGqCg(CZ>-Hie=W>B;=GTSe~twlp#zEN zpm01B&GhUn6>qCZN0~0m0R)r0=Xi(Qyas}yo=@jt^l)R_!*67jT*ca$H$40Aq(e4s zjbIe+;f%1K3VWjg-YMd2A!WElN!n(#KY%hr{q9A$6yw>4hTnJWf_-m?nDAVF^C!#oyW12w}HD;W7k2H1E2F-fbx5KqsB~5qu^J~ox#;ASx z;~uXSb5*7(bX8c~UJ&8@#XIl}ROFKKonQPpM0onF0fGt48mNYfo0WpP^|q715J1c{ zCs_;yA6O<%_z6C+_AXH|l*6GGj4nK*yksYkx!uPuFb`3al?tSeuE|VfP&7L1G7@Z< z7XewwmAQ4p`&jNi+EnW?lB>Ch5g5##S-B3P=n^k#t5M3XvQKU4FkpIh_YTPmQovzE zLKphhz3ZD1rE&nT0gb5(0m0oC6_~(*{QaTcLkYA;_jlCIJ2sO7bW#PY96=Sq)`^Ch zcDvkl)5pb9l#+0)IdgIn;)Hrh5MT6W6~SO(oX~-QTWurCT%0TVe{(jEKBBTD^%5Eg z$ldL4u{Q*LSiRiw&q;n!em9a^eUuJ((DSGz>GAM|l5OO-N zh0ub<^ecghOAh?DAd}EIx5A0y4*Q~5RAyU8(>cet%(g$vC|-CZMU}F7AaV^9oOmEr zjdgJS;e&cSohnFl#84B=O#=sr|26;@ZsE1^*t(j3DPT+7_lRI|j#M8b=Id^8glvP4 z9I0ZRnE5q?vOK);n1c`3(D<9xoN(yPCq_D7(kA(hQZ5Q>D+ctAK}DUHTqcW@MTO&d zOj`DB%2bwW#JhY!9D%%J^{V2{PaGS+K3D7Hm~wb{em?YvOv@Go*e2nB%IX5@w26kW zO~%16Y(fgRVeLTIH8hMbggTflZngXOmAGPRP+7%K397bOpJ5BUUeGaDrL}N`gQM_3 zbP$fuW^>_`f5ifkji3cO@c@a2BqB>L4ugaf@v4-T>vmap>+pRL(Jk<_*^*ZX=&{AS zd#O-u`syRW!hS8@e!k5EOZC1XjjC?PKE@_wIL5#~&;D9Fk*-hJhPUYi zmUa`CGJeZphm1<7dN3~+x zoT`i90pK>rQUK(GZ3Estrj?PY zT9?Yd$UQu~zhNUDYupmci7(zg;@KqlpV34W&;5rVo~hT>$1XK(wX|S>0TtAZkbFh0 z$#QYhi~F85a=IN0Q)S%9Z@j^Ga(sQ2frzBB4CoB>pJ6OR3n3U{>z(+W%;M{K)|hcN zOCi_EQ5Ut*bz1p~W&^rl3%-2<77*-NNq!p!P4Z{9S~CcgIf{HSb+ud%hiJU4v)oW= z`RIm>5i@W<@E5f17`;jhMZIVpL#D|vJ`m_D@XEZhr_1kH#!DjNoV={#LJWX<|OOvw6hfftKBpx&w_S?U@_ zw;Ef)uIE_gu}SVrS_qwZHOO2w-D;tbh=ZwT2d4Ie`+`R868ZDDlYUjh*&qY|<`}}L zQK_#`<)f#l#dC7R_-a?CHuI0s@9jVnV7;a}4KpDGtXo&z5qvtX`(S}@P?9NQTmpV5JUI%F>*PVO7@GcR+CVpa30oG{ zw^=`CgYn|E`~Vu@w(;jO$E#XvK;i2R7#2ivzi>5gryYGD%J39H?nXF{9FG|rraR^ zCSz_CSH6jfF;s1)r0ry81g=c0as16z<*?{@^={Iq^y~W)TRtBds>JCB<7&$(EOzY3 zgxjdZQB_)|kXC+PnLEf~Pg{1C0Y{yOcCHO9jzJwZVRm$qA zQsQ+-V9N4@)kum|U_avIWanc)`zn&AD7cKmW} znmCR?i=asLib2;~#mcUe(r=XuNAnM4rmly{zsOg;MezoHsOG64h&Bk7%G{Hx(agM% zb7$9I9WAgNK}yHe&)M6?iRs+f{o9n{UT^2EMozx{F`}eZ$Dbu+RDC29ZV3;)kd42I9X|i*-MPzk(Ed9MUVnJ5k+TCazP%`c_18Spyvez zY5NZ1P^dkK!(wy`w((w{I-pYPn1;#ST3a^1d<OFb_;^cFu&u0cokm4PrRdAZiqo|7FPc;Z)s}foo*3l!aB5%CY zD1U34lViyVtPMX^#KxNKiSQk9u1E7fT<4Sfa%zQZ18#byPD0G|UNsstQoEH7kqt_61631sQ@NtpIl;`MjM;&?LL!?w`xIxy! zDOIAC-hW!G&naJ304s;Al-8N{7%&iSqK<_S%dj!a{Mmn zf_3$&Gj^Vc+$=0BQc&_04)Q+Ic-;ec$8v63gyM-B-o0<#A&R0<0bIqX0<0Xk(ZE(O ziZ(L4J3Giz@p00W?{PT3RV%pF%DBj3{vmj2Qsrkn#S6$PE*b8F#`0A-b>@I=L6-RZ zE<~lXt(?{orb_EZ7s6O$)P@Qg7aMRz8kj9>m|2t1x!;kf0C*a&Zh7(3i}`|4^N`B{ zq>5LNYe=^d_%#C3+H8*-mZGtf%-x`fQnQ!nh^@ftS5<87eGrXSv441qTNZ{KXSHHV zb9Zd8i(83cu+SoS%zft4Q(PLN&nf1U0}dw<9O^=a)0qDImJ?Zg5hIlYFU~+LFrq0s zGEDcp<|?CLdsb6rFJX1BYA6@ShK+@!s<(*23y`-qglh|ZXcq0mKx7PD<9B2;WCdCg zy02)+Fa$yI#NgG;vQB4%Y+0SNz4e;D9-PmGu_(U1R=T(4SMzwAA?*E7Z2npxvV7DM znTL@%P{Am3EDR+u7~D;0R}=wkLILCR4o$LfD+7A1)e-X%;z-sA0%XqDJBF4+7kANy ztEkw;udD3PwXbI01<~OH$lY~-4mK-C!b59lcB6ELmVMucv3p`C?~sxGrP;X}E~ANE z3;tD}U&iXg))1Dv{g|pq!aRFlumxL&R^4B zm)BQ6?R_Se&Ram$+@HO|c*iKf8o@@(wNy<2oQ?QatI1u2pI4E@DSj@+JIVg}9MxUs z=hydN-}i{cHsj92mUNo77J3@D!ui=+C&Yxn?^EQ*rX+LAT(|V%P4o)w6D#?{ z#4MD{gWw;}!mhd_L?lo2nsH3~f0Z3ORk6%5||2wo$n*^}n%V0z%aG6pDT1SwhnAFQfzDzskz+mEys*@T!Ka>D;Jfym5# zg8p8W-;nRHeS0e+=QL_Xn^j`z3tb~j>OyKE_&faMI~3`Z6LbwOrO`qg-1sX-U9+QX z5A!JsONe)uIZ#=r;}r$6U%$0UrOz*}Pt~OFs)Q~};HuPDMORS;yIYlC+Fz~G!*JXu z*KTbV1&g#C9q^cp_Jj(#!Z-69nifdRqxug&b9tn$-*Kx{E-2v6D8lP=%80IJk!S84 z!qdFt@na%2h&no(8pY^_n;cl{VypLJ44eb*FU#y?^?8MU7_piin?#kwP?-b)+Czbd z*nOH_F1%vxb|+e-&K5^MZd!8Upiu3>4XgAq{XNzmNuq= zbJ9PCGH7%k>uC;N)m*VJUQ&&Y(zz(=3D3q2n|L;*fHP1W(px5SMUIWb2QVPINRHN#Q(bo<`!8gAD9t!3iNufG^H49vp6JlC~gJi>@Itg@~eClmkahu z%qA-xo3yD4-A2l2rC^&yhVGHPceaUhrl$Ja64Z9QLKL4-ur6hSUeULzysPHLTTVFf zg5jWhPmGCGh3#`^(byJZ(>zn{soBHbe4QtoDIBT4&bmlGzhsC%DotRhMIdLs5O-W4 zhTc;Mly5?E{(r)a&P=hr?#S@g`TWxg-Ksvx#SIj}@v4A_t~o9)yW$lGH?yHzi{rAu}TK1ENT-BVJ!<=&^91Z0Ic!@k-> zX^J&r0lOnasjo$E>EBXoJOs?dI?~WscVJ3b1$F(RS9Fvg1|JZoK^QUbz=VF=`>Dhe zQ=<}Q{hTH_EvZ<_lX&T9h&b!S7T+$Gvyh*h2NRO7DC)2?dkP78b5`KhofVWM?D_kM>n<^ zn>pZQ`$49e*ySM%{Ojxq@&>Y@ffHNgMs}~L;L+VHqM(J@EKyvcns2;OlSkTns4nvT zkX(R2Bx-Nr!S=V9F^16yeQgt2^H&UlAd01)V?k()nV|vG<+KhqL*9O+{G?t~;;Ldg zOUFTE$#_xw$$SYoqmjEA7iL@UflXj69)Cipc1|UP_pR{N*i=3>D7K%R%jgt~ZrCPw z5SOqPYE>_q>+4FYqjjx+6lOJSsX}P<{Ns5{3E&IO77s%v5y{|cURQed&>e~NI|7V|bSRBH;w0o-T|D^uUk2@GGlA`jur~@z|!rl}g2~n=v zU-l>F_C;K&s_i$#yXsth4TWS85mi(QgQ1E<_t6Uegt(5aKUeZKDJ)Vo6TwPG3iTAS zuBNuAQM7iqH^VezFQ4G_d_z``ZEr#lR91N&o9@ke z3VI@Be!DkIK3lR@-FG0ru#~qAz~ahIR%a_${UB)0QP0NFRKWFUyqhA?7bQ&b`ZM|X$1Nwqr?i>zg5p$z^d1f_^g zT6(G1l|2f`1F--uK|zked6&3+^kY;CZVA*vC9KIzvac6sU0q+6qH}EH8xknjG#YeM zuU%MU-$sg1wcu)9gXzZI>Uq5-`7S&#go(E+f%Q_pUljt=47e4Gwg(a0lLylVcsl>% z)76JO6OasyF2)`m-2=aY>0Y>;FvI~`L>ss5Bilw;q*DeWhe7-1M&+6nJFESNIXKQ! z-j6C`Wmv82*JgB{Twft7$dUqsz|ASbGRS#X)f?`vR*2+y_YTPwXDvAHIkngMwtS0$ zF_}VTCKS@_LE$Cc++RYG!JMByjXix71Z#4~Vh@=i(+1*C-orWbMqn0T@3DeFc0n{l zQ7e{A>KAn#wthL_jiMPVFE*h*Yj_?Qn(>;cv4HEUQ)Rv$l}sFENpvz>RxxiOux12d zCm=G)uIC5*1OOYm&Shh#g%i87gO>*M3pH-Z1B(k{Ou+*=1EBc$AWhmFdKF5==MK(O zmM{aNlYWqOXeOlA1d-be6@c##)Q2L(rcu>wobrgyrAHX?m6c0zX9k}jC?qbt>xOfZ zb5p*OyY;B=;23O_yjll60dCIM%rPT0AX`VDhk4> zQLR)*8`P6wy(u~-O)OUi4sD#=N|yZrWyjfpisbSz>5X|hSDfqWgGm~iRG8Fs_%iz-| z#tCQ&64AkByC)+L;HqdC^h+8WI_v^(ZxiA$u_)Z4 z0DZy^$aC_7z~X@PjdDRNmdb`b&iKKe1f&4i>L@>J{|wnGwumSBIB;| z3Wl=fVe&^`#nEyh{8R7}<~tz(hLje4gqtt$IvIr~&z#bdJmbOAi!YZz{U*Q{l!tdN zUujbGCB{}TgOX4%yv4-1nJ@+j36X@id_4_@?A+We;4H^>Zvra zs3;_9G;q%EVtpsbH+r#vSX`Wrc!33WwU}`FV2{!IDaQ6=M{aA zuw2rc&BIKoX1cCo1n(tv`2ra^-uEiweJjFVzFm@-tz-zfZQ zH$7c9q@a3m$!vDInXyhhEXGmHquD>9`({r{*oaJWZRfOj1tAk-os`|%eTRxr9Zx`Bk1*$#x}MleQV!N*9B!>eh5|1-`F-_{ z40+v*rSP=BW)Z&noS1$ZI%2!>SoAiLVU-q1!c)|!Cl^5@34Kj{p0I6bge);8CQwnI zR&hY-O@D!cnJP@;a_dTL)chEkaoT>!EZ!`|;!-Qrz?18bq$@S0Ic~OkJLe*7%U9l0 zzy?=(?ff#^<6h-yRL{WYEGF&5yjyxy0-%)x<1;m}66r%lc8vhdS}H!71JJE3{{#%5 z^_}v`ImZf9R3TMPPqz@DTn!dO8xD5;_r|BI`L{{BdP8#`s++?ZvEoLE^K4eO-p8E^a*K3>L(v)4_2*~m|RvLo1CIV9B! z5WpDG`kFok9ntv-hXi`=%xvd{J#MQ(E6^UMNC|cxx}@@4udY&-BP7s9UAUA-!piX_ zX%^EW#Z^!BObkRwp6(8Rl(ALq4QmhDyd{(*Xlt9ZQ)#WSl8gmRO37yT@bz#PVh|?c zit)ivc;6oqM)ZBF$ZQAc{*_i(-q${DRzklk*tB zAaDWOraM(@WxufdM{2*TjN+KUt{2$mF5^~BFU*7?Fw&+eC0s0+j9^r_UbBn2jR~=X zn`FI0#1$6G&u4UzP~+_7oW}G+Kb(@t+J=4Xwhb8rTzeb#iE_C9*l}IOiK<0xthiJ4 zQ)B!YYFP_Fd!&mzsweaS`8e2Eih^tNYW*<@N$)s($>p|d47t3f^_st6*V!RX9ZFS6 z5g%-FWejZPUheA6py{|i2cXF3W#Lx;t;st=s3DnHdBa-mR0@jAT)U2U@8)z606LWw zV9kP|f{=qZVewzRMbS>xOTAg0lkSNFNEhriH4$LPn}jLglbSdUwg2kGZrb{_%510N zmA};Kt78EFV~;qzi3;&(qIyb5IU@!pska3D&@Bj&fub^kF&$8cUhSc<9TS~sYfkt( zV_0E~)doUtoZR0BB)xn5j3)9A%aW9& zX2((jR)!SU6?-e-deHUyVT?Ez28=c>nTOoMpUqCcEwE%@?lL$)M zCe0D%&KzGs`HPQ3w`d2ac*)QK5VugY>yj$A$&|9f_r%nm+*hUJl!=)PjoU6ePVCVU$CM_Q_Sx6GqK3#k}CF+X^naTC1hb<+aUBdhGh|4>JW}0vq(g?rA zt+MlU|LyXOAV%1lwU6&YoCMwTTh{t-u;A#dFrX#1G zW^mTf$wPLL{kH`Zw)$N-Ze-~xEFKQo9xv7#MV*|*P|(LaBfmepccKC&B1@ka|79*A z)!&D_@rKvS{5Wda z)rBF=AcwPLt*p+!gufQ%wYd6tL80UTFhieczqXJSaNQxds$kP0)+a_Xa|L4GubEn$ zm_3gZ&z&PrOw(d%bs1{O)g3b_%ctgk^)*9-cg-geHx4zjJ6;ga?Vl~PT_#at-Y=XFl~zz)}7QLKM-qPpH4%)DQ0sm=@i`x64A6Q&=aqlkPeYPf#qYFCf9M(=v7eW93b(Dq%7QL+~j%hBMUg8 zf>lL_%cMOe8`{8nz(&asF=g2ex?^T0F?(ca2HXyg`eb(H2X&McU$f-W9jiV1Zci9%)u=#2d+)s;= zTnG{Wi#a|XfDMH**SjUVT9D@%`KC}zKqYpZUlOT)DqDzK;~fi1*YI5zgTAtyP1`{+ zW#}lD6^SRHM=dCvdWD8P7yL_?dEU&PstV#gLEL`(&eZZsV89&N)&{L4h3)lb6(ohK zdL!}RT;7Qho&;$Uu?l^_;RGD*FrouH?&-(QdZD8;a8(p?1OoQMeD<%`jPDsXX*7?J zB+6L~GtqXS2vg(nye4)X&zEOw-H_GwZd8AjQBta;yb&zRYsK4fZAutOJM(g(F8L~r z<{lu7dMN6DPHI$Pk869khs;#}5cj zU#JCY^hP(M?_OPBOotNc$LK&BlZ3ZJ3n<={w|+K1!OG|jEf zvsYww+RTki^b-N4{$wn^@jH^14H~$d?O$HsfXhnPeKPWhrC1(lFeVt(U{=(HX=s@~Qjt-t>FD-ovhhD&&NFv%>4cuwzaA$sS2L~c$ z<5?zB9MO78Q=2xI)NvIp=^^%#mbCv62`f^r^pyrFH+0VY>m{~V5uPX$+N1`>mm|xT z=*8>jfBz5v{Ez?qcly5<$3MOKm%ShU+kgB&fA@F#|9|qojsN(c|5g9}0WI_3-~Y%@ oyhM*Y{P#cdxBvb3e&m str: + prefix, extension = self.get_prefix_and_extension(file.filename) + output_file_obj = tempfile.NamedTemporaryFile( + delete=False, dir=upload_dir, suffix=f"{extension}", prefix=f"{prefix}_" + ) + async with aiofiles.open(output_file_obj.name, "wb") as output_file: + while True: + content = await file.read(100 * 1024 * 1024) + if not content: + break + await output_file.write(content) + return str(utils.abspath(output_file_obj.name)) + def download_temp_copy_if_needed(self, url: str) -> str: """Downloads a file and makes a temporary file path for a copy if does not already exist. Otherwise returns the path to the existing temp file.""" diff --git a/gradio/routes.py b/gradio/routes.py index 5d3fe1ad85..ccb1453d0c 100644 --- a/gradio/routes.py +++ b/gradio/routes.py @@ -10,6 +10,7 @@ import mimetypes import os import posixpath import secrets +import tempfile import traceback from collections import defaultdict from copy import deepcopy @@ -21,7 +22,7 @@ import httpx import markupsafe import orjson import pkg_resources -from fastapi import Depends, FastAPI, HTTPException, WebSocket, status +from fastapi import Depends, FastAPI, File, HTTPException, UploadFile, WebSocket, status from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import ( FileResponse, @@ -43,6 +44,7 @@ from gradio.context import Context from gradio.data_classes import PredictBody, ResetBody from gradio.documentation import document, set_documentation_group from gradio.exceptions import Error +from gradio.processing_utils import TempFileManager from gradio.queueing import Estimation, Event from gradio.utils import cancel_tasks, run_coro_in_background, set_task_name @@ -109,6 +111,7 @@ class App(FastAPI): self.lock = asyncio.Lock() self.queue_token = secrets.token_urlsafe(32) self.startup_events_triggered = False + self.uploaded_file_dir = str(utils.abspath(tempfile.mkdtemp())) super().__init__(**kwargs) def configure_app(self, blocks: gradio.Blocks) -> None: @@ -297,17 +300,19 @@ class App(FastAPI): ) abs_path = str(utils.abspath(path_or_url)) in_app_dir = utils.abspath(app.cwd) in utils.abspath(path_or_url).parents - created_by_app = str(utils.abspath(path_or_url)) in set().union( - *blocks.temp_file_sets - ) + created_by_app = abs_path in set().union(*blocks.temp_file_sets) in_file_dir = any( ( utils.abspath(dir) in utils.abspath(path_or_url).parents for dir in blocks.file_directories ) ) + was_uploaded = ( + utils.abspath(app.uploaded_file_dir) + in utils.abspath(path_or_url).parents + ) - if in_app_dir or created_by_app or in_file_dir: + if in_app_dir or created_by_app or in_file_dir or was_uploaded: range_val = request.headers.get("Range", "").strip() if range_val.startswith("bytes=") and "-" in range_val: range_val = range_val[6:] @@ -514,6 +519,20 @@ class App(FastAPI): async def get_queue_status(): return app.get_blocks()._queue.get_estimation() + @app.post("/upload", dependencies=[Depends(login_check)]) + async def upload_file( + files: List[UploadFile] = File(...), + ): + output_files = [] + file_manager = TempFileManager() + for input_file in files: + output_files.append( + await file_manager.save_uploaded_file( + input_file, app.uploaded_file_dir + ) + ) + return output_files + @app.on_event("startup") @app.get("/startup-events") async def startup_events(): diff --git a/test/test_files/alphabet.txt b/test/test_files/alphabet.txt new file mode 100644 index 0000000000..e85d5b4528 --- /dev/null +++ b/test/test_files/alphabet.txt @@ -0,0 +1 @@ +abcdefghijklmnopqrstuvwxyz \ No newline at end of file diff --git a/test/test_routes.py b/test/test_routes.py index 8934113f6e..23858cf07f 100644 --- a/test/test_routes.py +++ b/test/test_routes.py @@ -54,6 +54,17 @@ class TestRoutes: response = test_client.get("/config/") assert response.status_code == 200 + def test_upload_route(self, test_client): + response = test_client.post( + "/upload", files={"files": open("test/test_files/alphabet.txt", "r")} + ) + assert response.status_code == 200 + file = response.json()[0] + assert "alphabet" in file + assert file.endswith(".txt") + with open(file) as saved_file: + assert saved_file.read() == "abcdefghijklmnopqrstuvwxyz" + def test_predict_route(self, test_client): response = test_client.post( "/api/predict/", json={"data": ["test"], "fn_index": 0} diff --git a/ui/packages/app/src/api.ts b/ui/packages/app/src/api.ts index ce7605d900..1d27a28745 100644 --- a/ui/packages/app/src/api.ts +++ b/ui/packages/app/src/api.ts @@ -36,6 +36,10 @@ interface PostResponse { error?: string; [x: string]: any; } +export interface UploadResponse { + error?: string; + files?: Array; +} const QUEUE_FULL_MSG = "This application is too busy. Keep trying!"; const BROKEN_CONNECTION_MSG = "Connection errored out."; @@ -55,6 +59,27 @@ export async function post_data( const output: PostResponse = await response.json(); return [output, response.status]; } + +export async function upload_files( + root: string, + files: Array +): Promise { + const formData = new FormData(); + files.forEach((file) => { + formData.append("files", file); + }); + try { + var response = await fetch(`${root}upload`, { + method: "POST", + body: formData + }); + } catch (e) { + return { error: BROKEN_CONNECTION_MSG }; + } + const output: UploadResponse["files"] = await response.json(); + return { files: output }; +} + interface UpdateOutput { __type__: string; [key: string]: unknown; diff --git a/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte b/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte index 4ea8f985cc..79d869a605 100644 --- a/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte +++ b/ui/packages/app/src/components/Dataset/ExampleComponents/File.svelte @@ -1,5 +1,5 @@ @@ -51,7 +88,12 @@ padding={false} {elem_id} > - + {#if mode === "dynamic"} {:else} - + {/if} diff --git a/ui/packages/app/src/components/File/types.ts b/ui/packages/app/src/components/File/types.ts deleted file mode 100644 index 97f5abcdc2..0000000000 --- a/ui/packages/app/src/components/File/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface FileData { - name: string; - size: number; - data: string; - is_example: false; -} diff --git a/ui/packages/app/src/components/UploadButton/UploadButton.svelte b/ui/packages/app/src/components/UploadButton/UploadButton.svelte index bd6e391070..5b60a04b64 100644 --- a/ui/packages/app/src/components/UploadButton/UploadButton.svelte +++ b/ui/packages/app/src/components/UploadButton/UploadButton.svelte @@ -3,21 +3,34 @@ import type { Styles } from "@gradio/utils"; import type { FileData } from "@gradio/upload"; import { UploadButton } from "@gradio/upload-button"; + import { upload_files } from "../../api"; + import { blobToBase64 } from "@gradio/upload"; import { _ } from "svelte-i18n"; export let style: Styles = {}; export let elem_id: string = ""; export let visible: boolean = true; export let label: string; - export let value: null | FileData | Array; + export let value: null | FileData; export let file_count: string; export let file_types: Array = ["file"]; + export let root: string; async function handle_upload({ detail }: CustomEvent) { value = detail; + console.log(detail); await tick(); - dispatch("change", value); - dispatch("upload", detail); + upload_files(root, [detail.blob!]).then(async (response) => { + if (response.error) { + detail.data = await blobToBase64(detail.blob!); + } else { + detail.orig_name = detail.name; + detail.name = response.files![0]; + detail.is_file = true; + } + dispatch("change", value); + dispatch("upload", detail); + }); } const dispatch = createEventDispatcher<{ diff --git a/ui/packages/file/src/File.svelte b/ui/packages/file/src/File.svelte index fc8440a17f..4befa7a401 100644 --- a/ui/packages/file/src/File.svelte +++ b/ui/packages/file/src/File.svelte @@ -21,6 +21,6 @@ diff --git a/ui/packages/file/src/FilePreview.svelte b/ui/packages/file/src/FilePreview.svelte index 6c0e6edeb8..c3d9a13fd9 100644 --- a/ui/packages/file/src/FilePreview.svelte +++ b/ui/packages/file/src/FilePreview.svelte @@ -2,11 +2,7 @@ import type { FileData } from "@gradio/upload"; import { Download } from "@gradio/icons"; import { IconButton } from "@gradio/atoms"; - import { - display_file_name, - download_files, - display_file_size - } from "./utils"; + import { display_file_name, display_file_size } from "./utils"; export let value: FileData | FileData[]; @@ -24,13 +20,19 @@ - - Download - + {#if file.data} + + Download + + {:else} + Uploading... + {/if} {/each} @@ -52,7 +54,7 @@ margin-bottom: var(--size-7); width: var(--size-full); max-height: var(--size-60); - overflow-y: scroll; + overflow-y: auto; color: var(--color-text-body); } .file { diff --git a/ui/packages/file/src/FileUpload.svelte b/ui/packages/file/src/FileUpload.svelte index 0f195e6c05..2089245444 100644 --- a/ui/packages/file/src/FileUpload.svelte +++ b/ui/packages/file/src/FileUpload.svelte @@ -14,7 +14,9 @@ export let file_count: string = "single"; export let file_types: string[] | null = null; - async function handle_upload({ detail }: CustomEvent) { + async function handle_upload({ + detail + }: CustomEvent>) { value = detail; await tick(); dispatch("change", value); @@ -28,10 +30,10 @@ } const dispatch = createEventDispatcher<{ - change: FileData | null; + change: Array | FileData | null; clear: undefined; drag: boolean; - upload: FileData; + upload: Array | FileData; error: string; }>(); @@ -55,16 +57,17 @@ -{#if value === null} +{#if value} + + +{:else} -{:else} - - {/if} diff --git a/ui/packages/file/src/utils.ts b/ui/packages/file/src/utils.ts index 30401457e3..5fc7753eee 100644 --- a/ui/packages/file/src/utils.ts +++ b/ui/packages/file/src/utils.ts @@ -19,10 +19,6 @@ export const display_file_name = (value: FileData): string => { } else return str; }; -export const download_files = (value: FileData): string => { - return value.data; -}; - export const display_file_size = ( value: FileData | Array ): string => { diff --git a/ui/packages/model3D/src/Model3D.svelte b/ui/packages/model3D/src/Model3D.svelte index 430c04be31..bac77b6b17 100644 --- a/ui/packages/model3D/src/Model3D.svelte +++ b/ui/packages/model3D/src/Model3D.svelte @@ -2,7 +2,6 @@ import type { FileData } from "@gradio/upload"; import { BlockLabel, IconButton } from "@gradio/atoms"; import { File, Download } from "@gradio/icons"; - import { download_files } from "./utils"; export let value: FileData | null; export let clearColor: Array = [0, 0, 0, 0]; @@ -81,7 +80,7 @@

diff --git a/ui/packages/model3D/src/utils.ts b/ui/packages/model3D/src/utils.ts index 30401457e3..5fc7753eee 100644 --- a/ui/packages/model3D/src/utils.ts +++ b/ui/packages/model3D/src/utils.ts @@ -19,10 +19,6 @@ export const display_file_name = (value: FileData): string => { } else return str; }; -export const download_files = (value: FileData): string => { - return value.data; -}; - export const display_file_size = ( value: FileData | Array ): string => { diff --git a/ui/packages/upload-button/package.json b/ui/packages/upload-button/package.json index 75f8271093..57d56835af 100644 --- a/ui/packages/upload-button/package.json +++ b/ui/packages/upload-button/package.json @@ -9,6 +9,7 @@ "private": true, "dependencies": { "@gradio/button": "workspace:^0.0.1", - "@gradio/utils": "workspace:^0.0.1" + "@gradio/utils": "workspace:^0.0.1", + "@gradio/upload": "workspace:^0.0.1" } } diff --git a/ui/packages/upload-button/src/UploadButton.svelte b/ui/packages/upload-button/src/UploadButton.svelte index 664dde7346..f1c060a8d2 100644 --- a/ui/packages/upload-button/src/UploadButton.svelte +++ b/ui/packages/upload-button/src/UploadButton.svelte @@ -2,7 +2,7 @@ import { Button } from "@gradio/button"; import type { Styles } from "@gradio/utils"; import { createEventDispatcher } from "svelte"; - import type { FileData } from "./types"; + import type { FileData } from "@gradio/upload"; import { type } from "@testing-library/user-event/dist/type"; export let style: Styles = {}; @@ -35,33 +35,30 @@ const loadFiles = (files: FileList) => { let _files: Array = Array.from(files); - if (!files.length || !window.FileReader) { + if (!files.length) { return; } if (file_count === "single") { _files = [files[0]]; } - var all_file_data: Array = []; + var all_file_data: Array = []; _files.forEach((f, i) => { - let ReaderObj = new FileReader(); - ReaderObj.readAsDataURL(f); - ReaderObj.onloadend = function () { - all_file_data[i] = include_file_metadata - ? { - name: f.name, - size: f.size, - data: this.result as string - } - : (this.result as string); - if ( - all_file_data.filter((x) => x !== undefined).length === files.length - ) { - dispatch( - "load", - file_count == "single" ? all_file_data[0] : all_file_data - ); - } - }; + all_file_data[i] = include_file_metadata + ? { + name: f.name, + size: f.size, + data: "", + blob: f + } + : f; + if ( + all_file_data.filter((x) => x !== undefined).length === files.length + ) { + dispatch( + "load", + file_count == "single" ? all_file_data[0] : all_file_data + ); + } }); }; diff --git a/ui/packages/upload-button/src/types.ts b/ui/packages/upload-button/src/types.ts deleted file mode 100644 index d747ba8492..0000000000 --- a/ui/packages/upload-button/src/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface FileData { - name: string; - orig_name?: string; - size?: number; - data: string; - is_file?: boolean; -} diff --git a/ui/packages/upload/src/Upload.svelte b/ui/packages/upload/src/Upload.svelte index b2162734f5..1cfab91ae9 100644 --- a/ui/packages/upload/src/Upload.svelte +++ b/ui/packages/upload/src/Upload.svelte @@ -1,6 +1,7 @@ diff --git a/ui/packages/upload/src/types.ts b/ui/packages/upload/src/types.ts index d747ba8492..6c61c6a631 100644 --- a/ui/packages/upload/src/types.ts +++ b/ui/packages/upload/src/types.ts @@ -3,5 +3,6 @@ export interface FileData { orig_name?: string; size?: number; data: string; + blob?: File; is_file?: boolean; } diff --git a/ui/packages/upload/src/utils.ts b/ui/packages/upload/src/utils.ts index 7ed63c225c..5147784b5d 100644 --- a/ui/packages/upload/src/utils.ts +++ b/ui/packages/upload/src/utils.ts @@ -35,3 +35,13 @@ export function normalise_file( } return file; } + +export const blobToBase64 = (blob: File): Promise => { + const reader = new FileReader(); + reader.readAsDataURL(blob); + return new Promise((resolve) => { + reader.onloadend = () => { + resolve(reader.result as string); + }; + }); +}; diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index b45e4bbb8f..9abde11124 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: 5.4 +lockfileVersion: 5.3 importers: @@ -48,7 +48,7 @@ importers: '@tailwindcss/forms': 0.5.0_tailwindcss@3.1.6 '@testing-library/dom': 8.11.3 '@testing-library/svelte': 3.1.0_svelte@3.49.0 - '@testing-library/user-event': 13.5.0_gzufz4q333be4gqfrvipwvqt6a + '@testing-library/user-event': 13.5.0_@testing-library+dom@8.11.3 autoprefixer: 10.4.4_postcss@8.4.6 babylonjs: 5.18.0 babylonjs-loaders: 5.18.0 @@ -65,15 +65,15 @@ importers: postcss-nested: 5.0.6_postcss@8.4.6 postcss-prefix-selector: 1.16.0_postcss@8.4.6 prettier: 2.6.2 - prettier-plugin-css-order: 1.3.0_ob5okuz2s5mlecytbeo2erc43a - prettier-plugin-svelte: 2.7.0_3cyj5wbackxvw67rnaarcmbw7y + prettier-plugin-css-order: 1.3.0_postcss@8.4.6+prettier@2.6.2 + prettier-plugin-svelte: 2.7.0_prettier@2.6.2+svelte@3.49.0 sirv: 2.0.2 sirv-cli: 2.0.2 svelte: 3.49.0 - svelte-check: 2.8.0_mgmdnb6x5rpawk37gozc2sbtta + svelte-check: 2.8.0_postcss@8.4.6+svelte@3.49.0 svelte-i18n: 3.3.13_svelte@3.49.0 - svelte-preprocess: 4.10.6_mlkquajfpxs65rn6bdfntu7nmy - tailwindcss: 3.1.6_postcss@8.4.6 + svelte-preprocess: 4.10.6_62d50a01257de5eec5be08cad9d3ed66 + tailwindcss: 3.1.6 tinyspy: 0.3.0 typescript: 4.7.4 vite: 2.9.9 @@ -373,9 +373,11 @@ importers: packages/upload-button: specifiers: '@gradio/button': workspace:^0.0.1 + '@gradio/upload': workspace:^0.0.1 '@gradio/utils': workspace:^0.0.1 dependencies: '@gradio/button': link:../button + '@gradio/upload': link:../upload '@gradio/utils': link:../utils packages/utils: @@ -725,7 +727,7 @@ packages: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.1.6_postcss@8.4.6 + tailwindcss: 3.1.6 dev: false /@testing-library/dom/7.31.2: @@ -766,7 +768,7 @@ packages: svelte: 3.49.0 dev: false - /@testing-library/user-event/13.5.0_gzufz4q333be4gqfrvipwvqt6a: + /@testing-library/user-event/13.5.0_@testing-library+dom@8.11.3: resolution: {integrity: sha512-5Kwtbo3Y/NowpkbRuSepbyMFkZmHgD+vPzYB/RJ4oxt5Gj/avFFBYjhw27cqSVPVw/3a67NK1PbiIr9k4Gwmdg==} engines: {node: '>=10', npm: '>=6'} peerDependencies: @@ -2981,19 +2983,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.1 - dev: true - - /postcss-import/14.1.0_postcss@8.4.6: - resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} - engines: {node: '>=10.0.0'} - peerDependencies: - postcss: ^8.0.0 - dependencies: - postcss: 8.4.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.1 - dev: false /postcss-js/4.0.0_postcss@8.4.21: resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} @@ -3003,17 +2992,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.21 - dev: true - - /postcss-js/4.0.0_postcss@8.4.6: - resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.3.3 - dependencies: - camelcase-css: 2.0.1 - postcss: 8.4.6 - dev: false /postcss-less/6.0.0_postcss@8.4.6: resolution: {integrity: sha512-FPX16mQLyEjLzEuuJtxA8X3ejDLNGGEG503d2YGZR5Ask1SpDN8KmZUMpzCvyalWRywAn1n1VOA5dcqfCLo5rg==} @@ -3052,24 +3030,6 @@ packages: lilconfig: 2.0.6 postcss: 8.4.21 yaml: 1.10.2 - dev: true - - /postcss-load-config/3.1.4_postcss@8.4.6: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 2.0.6 - postcss: 8.4.6 - yaml: 1.10.2 - dev: false /postcss-nested/5.0.6_postcss@8.4.21: resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} @@ -3079,7 +3039,6 @@ packages: dependencies: postcss: 8.4.21 postcss-selector-parser: 6.0.9 - dev: true /postcss-nested/5.0.6_postcss@8.4.6: resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} @@ -3157,7 +3116,7 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /prettier-plugin-css-order/1.3.0_ob5okuz2s5mlecytbeo2erc43a: + /prettier-plugin-css-order/1.3.0_postcss@8.4.6+prettier@2.6.2: resolution: {integrity: sha512-wOS4qlbUARCoiiuOG0TiB/j751soC3+gUnMMva5HVWKvHJdLNYqh+jXK3MvvixR6xkJVPxHSF7rIIhkHIuHTFg==} engines: {node: '>=14'} peerDependencies: @@ -3172,7 +3131,7 @@ packages: - postcss dev: false - /prettier-plugin-svelte/2.7.0_3cyj5wbackxvw67rnaarcmbw7y: + /prettier-plugin-svelte/2.7.0_prettier@2.6.2+svelte@3.49.0: resolution: {integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==} peerDependencies: prettier: ^1.16.4 || ^2.0.0 @@ -3659,7 +3618,7 @@ packages: - sugarss dev: true - /svelte-check/2.8.0_mgmdnb6x5rpawk37gozc2sbtta: + /svelte-check/2.8.0_postcss@8.4.6+svelte@3.49.0: resolution: {integrity: sha512-HRL66BxffMAZusqe5I5k26mRWQ+BobGd9Rxm3onh7ZVu0nTk8YTKJ9vu3LVPjUGLU9IX7zS+jmwPVhJYdXJ8vg==} hasBin: true peerDependencies: @@ -3672,7 +3631,7 @@ packages: picocolors: 1.0.0 sade: 1.8.1 svelte: 3.49.0 - svelte-preprocess: 4.10.6_mlkquajfpxs65rn6bdfntu7nmy + svelte-preprocess: 4.10.6_62d50a01257de5eec5be08cad9d3ed66 typescript: 4.7.4 transitivePeerDependencies: - '@babel/core' @@ -3763,7 +3722,7 @@ packages: typescript: 4.5.5 dev: true - /svelte-preprocess/4.10.6_mlkquajfpxs65rn6bdfntu7nmy: + /svelte-preprocess/4.10.6_62d50a01257de5eec5be08cad9d3ed66: resolution: {integrity: sha512-I2SV1w/AveMvgIQlUF/ZOO3PYVnhxfcpNyGt8pxpUVhPfyfL/CZBkkw/KPfuFix5FJ9TnnNYMhACK3DtSaYVVQ==} engines: {node: '>= 9.11.2'} requiresBuild: true @@ -3883,40 +3842,6 @@ packages: resolve: 1.22.1 transitivePeerDependencies: - ts-node - dev: true - - /tailwindcss/3.1.6_postcss@8.4.6: - resolution: {integrity: sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==} - engines: {node: '>=12.13.0'} - hasBin: true - peerDependencies: - postcss: ^8.0.9 - dependencies: - arg: 5.0.2 - chokidar: 3.5.3 - color-name: 1.1.4 - detective: 5.2.1 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.2.11 - glob-parent: 6.0.2 - is-glob: 4.0.3 - lilconfig: 2.0.6 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.6 - postcss-import: 14.1.0_postcss@8.4.6 - postcss-js: 4.0.0_postcss@8.4.6 - postcss-load-config: 3.1.4_postcss@8.4.6 - postcss-nested: 5.0.6_postcss@8.4.6 - postcss-selector-parser: 6.0.10 - postcss-value-parser: 4.2.0 - quick-lru: 5.1.1 - resolve: 1.22.1 - transitivePeerDependencies: - - ts-node - dev: false /then-request/6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==}