From 9a87f0f12e959d8201e5a3fe2dd46d2a1a29d687 Mon Sep 17 00:00:00 2001 From: Lova ANDRIARIMALALA <43842786+Xpirix@users.noreply.github.com> Date: Wed, 31 Jan 2024 18:14:25 +0300 Subject: [PATCH] Multi parent folders validator (#349) * Show a warning when a plugin has multiple parent folders * Add a multi parents plugin to testfiles --- qgis-app/plugins/tests/test_validator.py | 48 +++++++++++++++++- .../tests/testfiles/multi_parents_plugin.zip_ | Bin 0 -> 45713 bytes qgis-app/plugins/validator.py | 16 ++++-- qgis-app/plugins/views.py | 33 ++++++++++++ 4 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 qgis-app/plugins/tests/testfiles/multi_parents_plugin.zip_ diff --git a/qgis-app/plugins/tests/test_validator.py b/qgis-app/plugins/tests/test_validator.py index 62414a9a..7a0e7e4e 100644 --- a/qgis-app/plugins/tests/test_validator.py +++ b/qgis-app/plugins/tests/test_validator.py @@ -233,4 +233,50 @@ def test_plugin_without_license(self): charset="utf8", ) ) - ) \ No newline at end of file + ) + +class TestMultipleParentFoldersValidator(TestCase): + """Test if zipfile contains multiple parent folders """ + + def setUp(self) -> None: + multi_parents_plugin = os.path.join(TESTFILE_DIR, "multi_parents_plugin.zip_") + self.multi_parents_plugin_package = open(multi_parents_plugin, "rb") + valid_plugin = os.path.join(TESTFILE_DIR, "valid_plugin.zip_") + self.single_parent_plugin_package = open(valid_plugin, "rb") + + def tearDown(self): + self.multi_parents_plugin_package.close() + self.single_parent_plugin_package.close() + + def _get_value_by_attribute(self, attribute, data): + for key, value in data: + if key == attribute: + return value + return None + def test_plugin_with_multiple_parents(self): + result = validator( + InMemoryUploadedFile( + self.multi_parents_plugin_package, + field_name="tempfile", + name="testfile.zip", + content_type="application/zip", + size=39889, + charset="utf8", + ) + ) + multiple_parent_folders = self._get_value_by_attribute('multiple_parent_folders', result) + self.assertIsNotNone(multiple_parent_folders) + + def test_plugin_with_single_parent(self): + result = validator( + InMemoryUploadedFile( + self.single_parent_plugin_package, + field_name="tempfile", + name="testfile.zip", + content_type="application/zip", + size=39889, + charset="utf8", + ) + ) + multiple_parent_folders = self._get_value_by_attribute('multiple_parent_folders', result) + self.assertIsNone(multiple_parent_folders) diff --git a/qgis-app/plugins/tests/testfiles/multi_parents_plugin.zip_ b/qgis-app/plugins/tests/testfiles/multi_parents_plugin.zip_ new file mode 100644 index 0000000000000000000000000000000000000000..ace51b2c4a08190f936152db8fb07580a8a1a2de GIT binary patch literal 45713 zcma%j1C%ArmTtMaY}>YN+crEMPcT5ZKrUv^E(W&trmi*&YN}8`pw3llW`BvR z2MiD}*aI*S5E$y8pDX@R@>lx}C_-08IkUXUnG6&N=n@hLh~V!^{;AKv6kudyZ$ac#7q6g#chMp1TY44?C%$Kk{|f1Ley zq__ss`=q>)=2;MBm-2f*qK=KNJH=1URGolEP(SdFW_v_vxZvNAODmyx$``GgXHZp5gSXc zU<}lZ{=|ns&x+)72U!bGzO3tRO;Wk`agLo!#^>O1jboJcNnV0z6KdmkV8qAQjVRvz z%nNp{+k$jnHw|bsS;hUV$M`ZKS#hPKa}n1FyB8IZ3I3*@b}5hP18sdlgaHkUKF3X> zu}P#@TV_XfQd2BNwTyzP=OLB|tU&^pYeaWh_1Eq0!D3tOO)+3&4sT(WFhc@6K%gM~ zrC*Ixhvf?FNOG>M^B@f4o?s zm{E9xBSU_&Ts%ZddgQ7EgqchGU4DGGcx-3`vKDL1(XO;kDp^PrI2?+4$Q#>MTwrdjlIYXveYLHw9PBYEXR_OW7(a{ z&=RGFsvj)XmZCnFjXU{RnKWlStT$cfEZ;1la(f|HOe5FA$&@?VyQ4P~6^n`6Qi+H2 ze`HE02G4d^w2a)*CC@WQ@RIJKXJ6TwX33h+-Qt!r8(~JmW$FJmzU(JOSADaBsetrk z-v~$N%?;&a418gn*gVmtK|{1DEWe5FcYrZ{zkAumw9O6}Y$~4;= zLz$34=bp4)X4esXa~FBSbTkxMri1A>2?WE@dOz-W1AkqU*aH5$_pNuul8S=?0kOdV z0iplh`y7l7Tz;27UgVv(HsZypj)7xOuA(y(r ziy3~?O`t(4mdqf~xA*h4kd&esE}I2H_tBJQu{YnG;C(IfdU8{61aa>VhZ*W*kiT{@ zx|esGttX5L%T@((`xU5GpM>44L`{ziW`bIE-keWh?b3m)ofo%V$JZ;z{z-?kJQHqs zR&mPSjbUfler|fa*PLAPx*^pw`j|P}E!?V+GdXVIwgMgb_Flg8{_(PU`0;XhZo_U9 z!^gS$u#>)XYMdQi9wzVu<`5^7Z?Lz>3;2R0bs#;d=RN6Sdvho*U}jL0Q02I`S$Fa{B#O(UxT*D};DYENYHGfhGA zP>qyvTIU>mf76rFa|nQh{BRI7Cm0e;@(0)n6bnf{D(;R!&=S{+P6@bqkBJfyD!{hD z1a-r%yplC_x(Ur811Xq_0#iWope%6gT*BDz0dR+TQsulF2xeK9b4mhOJ|(@Jxa|0+4>Y&O8qGIm^@aJXI`0 zxK}2=QQM^ojnoXHO&eV?oH!2INi#*035|7f51zkJhQ!ZWMy!O!im-q;F07D#RnGH0 zjBkDit8KWlZ7b%J%FwAgQkRx`a!87= zKi)zs8bvT1JADkcU}zbTN=`Lv*TE=-ixAXX>R|#YazZ32%gPeF+{`j#4jLy?iq-#>c7drMsDa6n{v;fZSzDFvoy$8 zGAr9yJ$c5dO)@02JDR#>Xg{Bl7cA?CRY4Xs=|az-v5$tIFK%kF_m23_QCIG_+rFmZ zb0@3DK~4zXgVsC^Uhv@=PeHxD%Ak}TsC0nR@9N7~!ufBbokF#&RTEhzT_X35CC}3X zZYO@7H{Ar&S+H~GK63fB_5wytyh?(AQk;>-=u@ry;zw#dJ3l!mi&a{}P38h3syY$v zs@bf;deQ?am!ge96#cnIr{rkfH_!Aj%y5WSjIqr)6!`}9fK8vC@h_9)*+ThlHRa(7 zgkWsPFA-A3_#bD3S^Kbj${PFASWUf027g7Re*+eOVFD3jWO3*}QRy#1`Fm6XnAqFV zJJ|h?A?drKyaXIH_Fwwoq$EX^|Fjr?1oIojpEHt=x$B<>*jZUZ7^r3n_vFt7gt3f- zDA3nmpS-Tpq(66{93-`zfq-C8{t{rIj4aGQHz8f5xCd|b~Hj3Qe3Adn%yP6%Nd>MI>NyCXV-bZlEmf_U)6&_T0imJ3voIRNn+_ z2oQgqFI-oHfnpXG__0i}o~D0u452E&En*suC3VGQqT2eN|j zJb0-6zM42R0ln&jHGQ(XU(Vp+^9Ae_3Qc21P%PWjpoSjM#k96YNZ`vq+5e$clEjrb zOMIG%K9wynwH*vf8l=U&?j124WND%~I$<15gjr`bzyTqJ{zYnCEY(5QSx`dMA?Uva z6x;?>CKb&^w!zDx3D}NZkD|VXv@WmuwG{0zO%?6GE&8N|VQVV)|Np%+jC7j0IvV@|R ziJ5)4!5`zw*C(3AVj9_jR2r~kCB8K8;8Y%D!75fwxsHv-`r}Ld;)(+N()}^sML=T2a%(pc;D76{!ZU~wBN(Bkqq*@>eEA*z`T~qrxJuUa7#8o2x zSF6ZMQ}fjO>j%&q|NRI!Tf6?5IMK^Aba{06p5#V+lid%i3bR|~L=gu4{%84KdFB4w?<>JxmtVs@s5eX`bja}Yw|ojvc^Ynf#GTqe6BC@8f42b ze~31;FTXY$PH&=b#EZ#FQ|B0e$`6h7$*;ME9iKq&tt4tL{Av)j^`KVS8S_au(d$vq z?#dO#^lDF`Kxmxb!0f$)Qx;rlsw*NyZE&y&G#RfDUixUcKQDyHQ&e7&$MKV%XL_NU z{#=mqH$ZuN&2$v`qmc+RzG|~hSP?~&LT)#l>B zLgxCndsxQS`k>4@C_~0S7ZW{sCw4X3TQY%v92H1POkT7`*f8ktU`IRrn-VY-5D*&9 zpJ4F!u=3AWjsN_P@vq>H)|UM`C$is@fe@=VMq9)Iy8;XYh;D|RQ(v>3)2KcHI!tgX zWhRc+LZYhf)z0VBTi61FwA~u$ZumlK7|Xy8$JRuhgw3PZFXWUl<1WLLNppd@q|r)^ zTJpPPhNtv8NTYMHshIRSd*7+m--{1?Ggw&P;<76# zlp%-eMK(Uv8xsji{Q z&u6H0<>&4Na{U1_!J85FIsbw7=iV$s1WHqO9R~02%YG=*-RsN1vjBfnLwF2p)q+(u zFs09ABjQBa#APeGKz&z*WQ(ACd3Y(G)DvyZ zdFgBl`T6|_J&ZZ&obev8j-R~=eN?1D0T5{E6Jk%a^iTTE8{Ze94U)*eQslArby*1f ziWF;?9;6HU$qcm)WWG9QXPhp)8T19z>&7n3nbS${8&GsO9|aZhu9k42F`VkrLR|wR zsrKb*(Xe#r$(q}B#l`nmp^~r^23=;I5KS3W192;mMfq|X8PLhx+azvb-1Hf>fKu;a zwxSQfyI0_@JCZ!%rOn7XMJhByheuXSRR!H}(rqZqb4?==m803E`IMbrH00ESKTWli zusMm=0C^Gad4>*x8sI;jXm+REI~c_FUVpFYa@0Jv{Pq(tetQ2t#Urxgw60wJ+itm< zbBM{UeKoyhcAk_+^CjaOrlnB+?{MgMod6*b8Q(P~KQtejf`dfFR$X}n>nXMVyQzvV zC^lPivH9okM=24pA03`%A)njb_zM2sKRG{q>pY|my<^|=O_9Kv2snL_J9$&>{b^$% zr?p4uzwWl4r!O3{+6u5dqvipSZ0Sv5Lm1a>-@Wu7>egP3bTabv+>4Opa+6}5hvo%c z3HkOjSNeFTy-y*by>&Q^ufP#&y+`|O^?t~D+-^9=2Ojl&;CBl_Xn5%Ae6QH+QGq=p z6@ahOvk|?O46IaY7HJF8lj}k=;z+`#p`zJFl%a+*)rqqtfkjKrX^2BJP3RNXOe8M~ z)GnkV3o5@)^0At&0ta`jBeAeKnHcy`s6gCYBvA*FC_%LwK6m?4T8WVsxc%U9RM1Un zq&0J$RM7DlUIq~njX2K~D!S^{w!+u28+GAFq;-d;fZst;uwAKJG){YT z_7hU?`z6}yPb(=;m**HY=(YQ8vUqEnpN$Q?B-d^XZe{i!@O7~IK;RMC-k8J>ymEnK zYtid^Dsrb5kkmFPLEs%^=rsqw{{(BGO8!Wu4na@RlG|n;D9VX?57J%NiC7Hh+y?U; zDmIF7vwHp<<}`M2CCAG*+@BokHow=Dz%O(`og{MRrGS4vpYZ_yR8q^~CSNVXLxOTn zCePoBeq^pYNWo*C7c}gnuk0_xVhTd@3Y1;772Od&M4N97XwX^si4@=p$&O|Jhw{H~rAQEjY7Ah~Sa3jtSoH%e2qCV}Gn|=?>l+t$VhE(}(#S z%GkPUa*jJ41N|Ghr~c@EPQW#Nz^>JZqbF99#OBC-dP6X|c;&lX(=9Wr1SW_Ip z4m8Lw!V;6gBk&SE;S&8g@oTi;DGe!#?FH?eJ7QSF#G!1^)#7Rx(uMvzy6T;=&FGSf z*pF!vkH(d6+SIaVkAf*xrQL^~JovN2v*+o#1cj+r?NfD+J5{s0rt&@s6@`4Lu{@7~ zHi00xY>h0)V&e}#r{BtQzl@wWjKYnD;Gpq*S1{aPFSGB1X$$T2%4$LTo{ryS=UfO- zT+f7kgOg$IahZ}u=NseXgzo980S#UoO&x92VY`r$oqKC|aZe|Cwi43QWj7E63q8MS zACcyEJmzZ%#V86jNXC6vhJHwhCB*)&#G%}*WLZFC`(Qi4l-;FA(3TdL0!p6Ay(Nb8 zf)-JM2s^fu?RtIS#@}gAKlSPobVp#KfLca@Wp~Z9fI$tL%@^f7BTq$W@Nh|%3zpGB zpx=ok$9SiPz1lfzZ#u=>N*&*2sfbt;n>YMsWruHR*9Ioms`V#Om~02WghYzhN>oF0 zpvNNY85mdQoO(xMciVF8$q%|)x^$u73KjOlQL+W20ULHht6s=@Rr#TmLy`~Hf<9>l zLpoQ%A%fovx==$y#yIEH%H#vODJrJ)Mt}~oE|UFV4Zn{z4S4vXG$#p`Univ-Ax)PR z+?SM>M?DrInz>8Nt9YpFzqJR=VAW+RUNx1{6#P}-ExGEk?|7AoCriiHzsQgP|+ zAwl#+#p4`Cw1Q7I$!9e{fgi~1p$urI8S2s*+KnWtCWcnZ+ZRLzuy9-1G*24% z?*w#osEbd72s?JiW>B*dZ7do(y%QeGRv4#t?HEYWK&=P=e?lrK>m>Dk`+YXNKMT8O ze+1+2kjmD~#mLmi#faX;!{r|fNJ@PIrvCy_*~WKRfeOKjy}dvO>ipb{9}5dq4Mc>c zlFf)0-c)i6Jwl5iZ@zoL5{Sgyz(2t+;t8G{{FCiaV5z8`Xb~l6^ND@P0!=DFR+ke@ zEGEvk{L+;l;G4m4Ar0`jRuoVbphh^)9f~sVVV5v7IYyB*sghHe2uQ?`?{mqG2|Mx& zuHE!Gwn)<0B;eUPlThVn`Q3c|cRX4T#)} zyU#ixgVjn&AJN3-8L**8Ho4(7bKEeN;HWTz*HxR+pEM11R?qY}@R*?>t<=2UqPvMC zv@8Y5+`*}<@sN4S4;!>;j{}IjPl-?Zzp)|YO1BH-D(7ufbP1^8Ms+2=ytH!dn|L#3 z2>f%lGcDVcmkW^(fc}8jc?lpOTSl_AalyHb~}tK+;rlHzB9 z_9c?0PpdY2yV5agF0P{^CY3xST7sI`P}mY+nj{JfqRUDMN0ai^z18MY*cWBNUL$Lh zAoz6R{4rH*HnEdCU1)LV$%q~OhH!ZD@@nK^a=m59isiy1fnO?MV0$u0%#rJLIPGdT zIh^bNxpJ|6lWE*RGr!o*e8hqA{H!4G^ep47p>0h*)Zir}ZG9QZZ9s~adYo>=-*cY+ zrLVF0n1(=*YUinyT#4`%JoG78OZM_aJ2_d@527}`Q9N#Cd)ZJx>3!JlfJS#yZ14Aa zf3v4>CGa_{Krne%6qg2B+q{96N9Ss8JuauM=4MpUKOs~gbsMTxR6{+lrKc5aVL@mi zVofDZ^VM$JZYP5dRU%gbY*uWG#!yt(mW<$m@uh{m>_mbSoW%A;nw=y^?wLM~kbF%<^J8B_3x}V8-^SU8x(fo}w#1 z6}$QtPw`Oo-6TvIiYDi}D^Jb=!qQIs;o$1rh8nw;u0H0S@`8EJzRyOslGTqd>7T*4 zQNoMo>uZOHaOc0*_Ic_^U`Q|Y6s(21h~=V?MPx%Q&-q1e4QGAIhkcJe#4`t@nY34 z9NN6K$I*%nCV6#S-Kq)oQ;o*T@E7rdTb0}@TNC_f9Z!tZ$X#!ccCh5FA4)r+ot&dq zn--OU(do!8OpJM1CCO0zmT8`N(;H&~sI>tVUK2;vyAfy_Wt5$s>gsf386)5KT8$OtOheF`^MeZKTz zJSCv-z?kH*e#r0AxX$(E0?gijuVzx<@YpQhr?Z>9$H3ANwBwxRg1gG5_^93RtAc=2 zyk2k*FXh(nu$KxsQclwCTyy9917{-6KvgF#cA4-lul?|Y3@oL=aYZv1!7 zwa#7;vY|4(t5FJ@aAHZ*R^A9fpMYdNR{kx`wO{7)AVchdl@KvpN-Gy-Fpl-?fyQX~ zBc69&{q6fZK(<8BgrvEHEm#d9uhP{Bhjcn z9LZL%aEfNvp_^grDLlS}3$IRv^X7;uE4bsp>)49`sE9%|Vc4I&;nQ@!21>MH@QLeY zJ-6CLFeOGpem|2Zan<&vL>TIZzZd=k1#qB2I9hoXN+og+ISWC_~Q-n&d4 z4jWnFRR{MV72BjFcgQ@HD8eh_j$|%IVD(6$gLzHx{`@}ojsBVCyU-NKns!8LMPiqV zsxT1{0m|EeGn7fkI7F?j6iN`AGZ2k~^i63aH5R=5taWDwwOJ;ChnJ4g1iAWQh0}b_JXx~C17{Ymkp%Cz9z2~moA)Q6 zs}H3z;(Ei1sTI^wK;g(h_v*=8i=K!zA*_Kb$i|pMXSS(j%t_6x-2gpP)F|Bsm5EN^ zpio-uWss!>B7G19qCy<%k zH`f>-rL@4rO;q^Z?$PLkVS-og(VRjKZj`Tf(oA<#C za~6|c;*MwSwhlTmLB*)`YN|0 zh1+EE&XZ>w;m0(S1FeG_#N<>NY6j6*iYjT+8WaR4hHmvOkew=ID5bLrBn7)#!X@2i zRa%F~`+oN;pk_X!&Va;=X;+!R1W1k(}YuRsVVQ98HC9l0uX$UcVS7?&c5{i4um@EIh=4KWH$ z#1asT@)%dKC_4IKA=M6SE!YAHqjA{Lq{ED;3?3TxJGS%4$Ae@;l*)aaPnuW?R?>Xx za3u_cAQoeZys;Y*c5Ocs$<6W(0lTmCW=fu;pI8f+31;6K-y#7VAhkAlt#N~(d+l{( zNRw{W_M>I`)09OloJWsbDOt;A@nWVAv?ekhN9@GFxBtqqg?hGB{5vY%ZH80xZR@3n zLIr&7I#OJ?gjH-I4$(_d(k0*=E!!4Y?eWzXvb=i>7m5XiZ(E|y7ea==plAlU_c5la zfWZmTqHyFZ3Sn1LsmDFSp2!>_ zr@Xxzn(WUxo=2>iu9zJ3bb}j!5_T6eCu>AWMe7gsJq6XRE1VpLh%Nc4kPOSTq%Bc2 zrOGMLQa2G{M;GP37!_DL5snb8yrn`t2ZJpO9*vky`DaX{Za&v36pEIR09Up|HVU;k z^}?Mc9cAQNh%)kKtK}(??yv~~A{k`CXU+jFo0job0PEZu?HzFJ5=)ja#vxmiz4w%I zD&TtiWqY~JjN%byXj@&gHfu7qyY~bf_|z0GG7R@ASUloe5l}+Q^Crsl(yjE4U^wTl z|5;-)b{uV6%i00>NqOz~^#Bf)ro)GViQJ6tW>Y=dlpV0(H>T}CFhH@RIt|YR*_gr$ zUZ5NWT@!^-6f_P?0jZ-{>_MxSEMbMI;A$_5*NWB(F%|B`HZS)^zy;NiX z6n6d4W0~%+l)J++@X&4tkmgE0f}zFa!3$gYl*@K#hDKvximy@fU08h!i$ShRPCO}q z@^U0cgrqlc_=jz@0$af-G5^p)OQ*qHf%$e2YIde}6ln|yDzA_D;SG)2t{P}OxL|*= z-98gw(ovL}?l~Yyi%ScjA=M_BY{=Fta~QMRTH7agW5sZ)huEb1QX7P$X6~3r42G71 zjkVG)JwDf6pl)fWsayyy8F-TN3X;>ojJT9>7h}#a73I)qU`qwn#4scE@V$a$RVh`X z4P!C-Xr%Chx5)UCQhPfX!C6{b8Nh2h@WF;2)qt ze|$99iLNCF7fMDpRYNUpYIb^_DFUr+hdW<&FV9qK)w2W%QMJXOYstDJ}B^k;;P8;5@Y_*C@!BK~5Sp9^0iDK8sv|u%tmh%d1KceKj3)!j! zs`MsFYn8H#JC2rFBx?lU#K6b)AQ>qMvQg7JtPi#cuaE`?YLd0dQY)1@7PPGk(WB>> ztuWpEQ)(2hketYfa!B8JSp~CJlcsbk1GU@vf`K_;&MtGBmXdpIZqNBZzp9fjcAgkm z%Q*K&33Dq=Nd_AhnN9SIUnwg!2>);kdFVa4pqT4Ms8b^Oi8*I+WztDGpl%tN$I&i` zSvOgRIX)>W_s&6LeL@+a=~T^3u`NxHsCa`bIXLL~tIcp|0&Yk0rVRX$MdpchC`fQ-&~K@0xJBYZ3> z4nhkqRgqpoNKXQEIfr=oBBRp`2K8o1{MEFm{LKhx*B z(BM&LO)G0Lhy}OTbRwBlOHKM@v5ai5w$X=_UsX&!9YyEA!q)qhlhyqdo zqH^%qLB~udD&@TE+^)54rI4m%2@e^+uwDN9-HE9|gYJ2+ znAN_*#RP5mol@wz+C<~#d?<&noJz6aqI&*~OY`Sr>jMpzHBzNr8dV__m;%;B_J_() zwVQW=z?lT!f?06{wlIl@>-fot+`d32NKVfCjLymI4fmaJm6=2M(-7E)G5vEXYSS@9gm)U)(f94dki9L zx*e3YeuevT4MQ*vFho*U0r(+4uCS!%+`kUCawRJQQrzJ4@9xK$u?muO-u*TNC{g=( zuvvpj+FVpD>U3!Mr~y9+yQ@$`*n#u0O7|PAS)441RO#;}uBf;<5y=W&Yl|pkm5z|% zkIEAX_Zcr#7SaRw(?i(I>P4LDy{APG66z%s`|U;Ol?dMeF2cEp3h2Lyt9BE>M-d83XgnHG|Q0IgLzngsoqjLX7r<6=h86)c8d{v6R<^B@US%TRyp^rcqkQUSuo1w1=NI zQg^UU&{F%lj27WLR*U%s(LN<&o|?nSCYV$NgN1nQuyOD(0U zM&1R9!8!2->FvHM4moCv?NDDe?;ooJn&ghlYLKxy1>3pwz6SO^hc`kNo=>=1rv>%! zm+H@s8uAs=w`LjJiA$^{jO%Q4O`Pi(S9tlU!GRRFsaY*;=w#um!JKcV_3_XU<)HiB z4fpSElOOL(RE7DtqI>|*#3i&T_R^ElB7kz!mhJEG_*=y(P9v2WVmOw;^ac5rIvD8m zHrAoT?;%?wG9)aNhO-OFj=N_h)JD%UiUu7Emq%5axU&3ZF8p5H7k2piImhF0Nwa$X(`dZp$)VK}kE3#Q--gG{K{jt3 zB;+O2M>oMV0x_Qqo2O?BxpysM1ZIB2iz(C?_h;@I5u<3? zS3!Q5`L2do;`g?nbg8xapy1rSaEr`E(cl@zApZLd98H%nC(1)5-^vAkdnGzXf&0XY z|G1u#=9O)Jo5V3Jl(?%Fz<-jM$54xlOFQ&(nD@_tow)Zi%=s0UJN&_5&Upjc({gCX zi}_=i$Ju#{z#sqqxa}q&$Ff>{uV)t8<2=D1|J{}wQ*LtJ@ZF3v+qmrvW8UAZ|McT5 zJkaylAG8$GzXOX`ZnEXAuWa432(BAWXx4PClp~Df&XzX|ULx0144WArL10T^@?&q{ z!f+yKgrJVE$1>-2@5F)e#7%H?dB^rm*Wv?;Qh;SEZ2oQd2#}XMwM@|UqX$-^g^vaE zRyw$cF9s5&4u~~o@){-re|vrB_;BYXbvUcGe(=~4T7SnO&*gRG{AT*~KnR}w*sUA( zm*KAES`R)yY&{j6_!e9#iB13Byf4w`;Y)s;GjCijJ_Tq6G7?TbbSpo;{HO6NXO`1b z?es?-vSzec_q_xMZ4IB}-1o`xJ(f@`+>f19d_(dZl)(l3?CTj{QgRO zM9Kp`UOIevcrgW!wFKXhmh&t}LIP2Dp`}inzly&+8T;yk*{=_|S+`h{O8X|`KLfAw zL*ie8>mbM#}cQ z-+yf_gL?V!Vg_2+=zL^m9xLSmowBzb*Hi!4!DH`e)4<9|Me6zCJ+kK&F#OtL5WXL2NugZ|D32w-J%Hh~MzT!-mnN^jMA#wtV=9u)xJ$Uo zT$i;St&AlC+g-zlE9{qc{IO(ljT=$C6mmHiKN*>7|2FYUMgwM_67$h?eY71yvq@yg zyhG)8@@j3hrDJy6WBWH^bLWH^jfhI>*=Eh)mj3sK;UeWvAPvqPr_sbX3Dxjrj!yu- z!9G2vZy_GxsZkhAi<5|i1u-zE{)Ie_^$2`cL67-h21TMJo&I2TTiAfdECRJ;q67N& z5EgQn?zp+Rjzi9nvlwsbh(&cVUcb8t6j^|Z(BfxX-JA(H)mLKNTFdO0)I8!>e{iF0 zj?H<`du7&;I7hK|Vh8jxkIpT!&4zCHJlFK;v*Brd)bgZio3+rGdB!!Xj}?9B2;U#x zp2)mYlG)Vy-fxWX>(^UUjNQvxa~tan=0tW!v|h{!Fx-oi1!!afg5}YJ=M_IR`eaL; z#L6Ko1h&^z72(~+Uw$DFasCnkIhr&toOCy!cH?y3-E*>7=`cs7LB3U`lZ+D9`Uet0 z6P%%kfkuE#cHFK4FwFKh9;Aj(eK4)_tuL`}PCH>?4L93y%v!V9V9 zCu79JZTsA$%3z#LtaqUcOWTsx1R5n07s)##(1swfBzTaHdrMQm9x zl?_I7XU_11pVV9d%P#_-8|y3%4fY~olY$1$*&oYCBi#4&wqIVi&p`J#*T{v(G)stT z@G2L1H~vRao%UDsBqFQsC~_V~_Vz4m5i1=>Y^G3Mbm-8E{JtHL99cb4Qf>DptY^Pd zZ-p<**hJ29#K}oIYhTY9h+AqW8gHkPme29iHachBWPTDoRpBkly6fWRf8w_kBrG}t zh}$<@lR3L8$mD z@(N12H@*Z*8sI_K(oHQ^pi72qf7_(~G<;9F*_`%O%vd>AEcG z_S|TagffhuxI=NaHG9?me1wv7wqX%P%emZ5lQjGINJul*pml3|=)njz-m<}XOiU;a zgJ{O=Cppb)={`4^*dnR+m+0cmu?g|zZreSNo|>G|jqUh0#C85?K|HcSad*|M`t+=T zWt|^&qxjr z=Pm6fbH!Q*Bbf*vhyJEU!Jta#OPjj?jxR9cQ7r`Cryru>Sz!<1zGeOW*FWk`{>d@@ zizfE(2jbuN(*7cY{aXdgUxg;6T>_^6V+BjH8Q2~L$RAyQ*s4VTLeoFEWlm^_36oetR{CNX>ssQaA39ii4C z9DbDb8j~Z2Zab511{{oJbP?HVqu<B5z(^ z$HzhU*?!E2`=)F91Qk|tFin_k?Jv73fKT!Ay=3x(Jc>i}xlCHY0DDfu?ZAM3I7c(*qOk_jA`9MhaEa&et$1XN$7S zX4@%)i?5XT`BQy7*;?Pz8-k1O8Bpq7&G!^nBR{J(T~C&s?3{u{;#uEJmCz}9`pIl4 z=tA!d6{xK{Zu)MGnmpo0_LCmDEZQ0T|5FXsx{i!;^uoM=>K_Zl z{X=jj{+AYLXYA=>X6Iz&>|*9b?`UiDk9}hPGtz&xPaKmh7q`ZU7w0LNF)$e&Xld;_s_pxFu0D zb2q&>zlVoiqMc@dN0Af~EtSBv#8r|3KkM++zFx~Qa6ni?y!k`5a|B}rN5aIt5x6*g zkaCY}T7ES)zz~KvBL-C98!!8y4Gpj!PycLx0&no;e5CtEC zLJmXCcqyG1p-=_m?zJUVsZ5W`zHl_h53`Gew}>AxIB}Ie7q> z3^$=<(foB3R%@Z3^bt(ZzB+e0@mtwQToXy%)!=lL#{nZ*p@QB)hjf;kz+xftM8{Cj zI*Kd6;3|@d-2<`OiVMJUi4GZ^IBw@YnlWxkS(nso+RltMR>tc5i(D#^sBO&(GjbKv z!)h(R*gUgxet`HUE`Bbf-3pv{m`>#MNk!<`W*QJRz4RY9?TKqG!kC)GBGZrQ_sR*K zU38LpN~{9rhm=amr@GJ*sZ6Ig!k<+1KY{vNM?? zDxG_9-@*UMWBAKn*DbE{%>D#Swm+~%4Y4?chpHP~H#7RC~vFp>nA z9Rz9{A?c|nbZi^%eBoXulXVRhnzR1L{OlxF&_n$zY)w&OhWM%R1!!a=>K)|9%cJfY z%V@e)&F_#&6HNjpknn&(uuv=**3a}+-5l>l3^&lf2Jmmm=5|%q4ohDwE~Xq%l4&`Nz7scMCZp)?$`;^G?|y-h&7nLuqSI8~1-7?YoxTPeWxZnjy~AxN zkn(VUiaVG71SZmd(cyojMi(a|J7*gs7l6Ipe`Lr1rsrL%|IChk(DCIm@*+_nFzsxZ zim+1iIpDuaOsbprrJXw7-;`prJ@nkO>DkF{Z*J~DP1%>t{eOq;?j4yjr`yyMdN^46 zgbL~G?F9P7OA(V{;vC;1<4a%UJGx!fL44BTB6;Y9Xt=n5L#_*lLEs*&L6*AP63zh6 z>|-nmO~OZsfZSZ$T01!*N(TwnJQ_yHYkqiypkX;__O<_3;|}J@PPhRZnc9nCpbFQE zL$$RdiL;#swWAYpC(;E5__<#TPyK|A>XSj>0zHdm1QFT4>SdpG8Y@ER{mzNwOwK7I zwPOR<0M|Yzlmw~Au>`)NqB!k+fyOSENEvENS*-$HL$uf}uJ^Kp`Ed|X+{FA-`G~5L zNr9Vs5(DE-0V7J`&a-pc#@WHkAna19h$9%bs{Th`!vUB{F;aKt2KMc{dz2QbYd}y^ zHvRy1?tSIsv5DwYa*Gx$OEx***U~X!>t?WxuM;dA1le-9Tzsa330GHFKRNVx$qtBX zTTY+3CH@qkLCbfm;=pV2e7GEGo>ZyRuHOn~>6q;|s6#x70;&khzY7xIbi42lqsjB^hRh zHOGV8@&$M&x#aeiR6=X6+#z-i^>-aI$C3?PXU@O4YRB{cTW6y{oNiX zfiiYpFY+=7kx@1a>>Gv8#d?PNc6Zr5O#z>E^idS;RL{Fh2jDgh^$@IM&f3>*lE>c4fh|ESRZ z7Zuh2B2xUjzn%R-qxtYNR)5fF6wui)HZ0y+5rKtJ^NDB_T^n)}>)S&TZK+f+Jf+(Y z`ew;)iCd*P3QF1Xd!O@i?$>^Z;J%c^rgYGJk}1riJh+_`Dqi~J;H8YV6u6MBG2$Q= zwCbWE7EK(4&;`SK)!3>rJ|aqx^6}|k!YB=@))0>1mCIz>dEjBZ&5ni@b}VhaK~PqW z4PoWe)@r>7YI$zom`UT%TY8aibEu4KOz;qV@f>VHnn=y=vGSn(V0vcS>%wQrWfVNW z{UXnhRj%3!0+2XiM(T^u0bt;z!2p;j!d}{#G+@y?y)WdA6xFZo$*B|eqcHQhA$f|x zCGoR2$NR?~E-p^U7omV<^+}B6th7wJ!8(yvDO$+r@)9=ou_8+Np!%^4h@7Lbn-ec_ zA90l0yts_w1U(PpLWYU)onLbU#KGS{ubU|69lWScy`iVIr?p>gL_ zGP$ZM@#h9EyWHYU%=%}P(4$-oNnB7+nK~)(uQXDAW5*2GVhaOmC#1jVlB#wA&yod_ zo#Qx-3j9W?S9R_ewRIglVw~49tsSe>h#H%dY>Zd?JEN3NcXMCnZ>0fSbm88(oig#Z zljzyCfH-a}_X2JUMR+=2@5hEI<-s$iy(6(eIwP(>_Bo>+_z>=;kZ-^6vHZxuQ}IRC z$M-o%ER{!%C_G-`4g8A{u^>SjhDoxEr?!8b)30m2GeO2D;@5e0W|DNBez=4q#(e|> z>c>+y1h~9riyL){~R-S({VB8=1|3D88PFDX@-gS0=aCe7~ zRR=-7*}3ey2}?yMm*%FACCcxfm8O>z?gPfJ5&F!bpOyZ`#A4zMBVyu=M%-QJL#wxG6ExrTADBDjmAFzFw z+HJIy623vbf+rl1K~+wQSC9tMT*EPZ(YKDY zZHGye)B1uaI&A0<7Z%PwQ{u-AKk}xi6+U~JY?y6txp)(b;`Y1BRUuu#9ug;kuvK4b zj@gpv`oG)Od`$NoWB@V`k$yVPr!Frld)wXwhQkfME4E+&pKei=)m*dkOc8{1Ahl8MWv(X9NOR=`4+p-h95{PnA2R+oSuspei3 zvBdrAWswlnC9Dr=ed`FIkE>Cx3oYx_D#b0hAL`P4u~k1S)l+$@r%MdXIVwwmKN9VK zsxfzS3gCydEF;9_=0LP`6&esk_GrJe==r5@@xwjF&yTLYcsQZQ^gr+NMk-A0dN?_8 zd-{F$+!%9x{U6G{G0L(o%QkE)!?tbPwr$(C9hqU5ZGrRjoFTf%qduZDt#DmZ0&&Ei4gJkU1v-%ku#I=Hh3OFjv3r2UpF zAvE2er~B;b_Tib&wlgs|1`XuJQxlG%-zwcoBY(k)q;S?(9C!R7JZ8mE3rs;LmY9Z4 z4;qLcCXP%C^&O9akfgjwFleQiUDii!#vyzo)ZVDF_PishP3W&WAXv*pWvC3=^?Lmb z|B)?}xZ-&}S&W@jXsk^f(c^>FQD-biG5in4`M(fE@#=h>@HhOC`F>^pKOAD#7XK>* zGEtnc?WafRyhHVpqDmpgmoGE!4-g7j6ryrGf#jGLRCPHYhbQ;bdi3VTS5WG8ySYBh}Lc)*%NS}sN*J*?Z zBHrt_xl;0C|1wv}5^!hyS`wjH?ee(iNgzw*Z|V;70x8#~2>NPYN)Yt4$QE^W2fg1xKEorc7YTHlt%@w+t#)4COXR&AaK{Ic-pl+j5kfQM!=KcV zC79`r%QS`o^eWJL)}jxo7nlu&D{MW7G0NB(q=5+9Fo4xw!f$j8rNpaS=#p^>wW@5K zSOPuCK6#}lO8t0)+y1Y}rAr{l=lc7txfPQy-Wcy3P3&(1Tw%jsmvyuTJq;nM5a>N#3gsWAF_!TgM~#Vp)0BHC-*)% zm$Yf|qsdX{#f%*@zx#%UhJ?{VP--iL4O>yDkBUPjjiA;sQB0wliaqE{V`41?5U%r+ z$Nj5a-qI(i3rYnLHvGOk{fl`B zBvLqOv0gW7f!YnJV)>uwhg|et%FGsi`L2EEA(9eB7h?1(5`fUu&EiaS+%pDIJ8Z;q zKV2jDLc_|WumxJj@1I9Gf$XF~rh_3mnSkZ8#o4R1fhSPw8!w}q-mbVrOlP81oJ9$3 zv+e+6%Ehu0vl2nollD!z7-tJd#wRIp=ZpwZy8~s++Xo&SJAtMteFJ^;4+b%|#D*_( z+vrO-7@VP7vs;pEK|dvGnd#lOOCGUf4LkMC+?`#Y_8PQpHQ;n4m1xskWZz=(57rKE zr|z!TucO57HW9}@Byin`bTV|N870@qRNCs%lWu6gHV|hSIKcg(p+g0W#hB~ZkQPy&-J-X-mWmX#Nbu0{qZ!tE?*8uA(KVL zb$Bk`U;FlrSu=b@k8r$OJ6}PnPASU-EKe{T5(~-QkF1QMfU*T&HCV69?zYU`_e}1z zCA#416H|&kQWG18Vw~rXbw9VTjIb`#?pmIJl8F&MdakKlQradN7{@53V%pD&;hNdY>^n^6k#pABF%8BYqjAV&H z<0&{7mC!E`C&*Y;g6|J&i9vb<8hcYIA(AdVQ^Ou;H*Ih>N;rOe-rhclMcT(3qP|+S z=TFW1o41Q67AkLWK+x+YTv$8z0v!Z$X;UNTG9?3fPYu9dssR@UP2Z&S|J0$MN-TXy zgn=kcuq#{xQXw_Bg}@ZdAokj>py`x9#{S)(Ug|1jyialsn?|`-HMdvaqT#hod)JxR zeW{w){4yii{(Q&(zSGY5BKb>YOPJk@({7!cQmzDk`#_1la+B1k_(Nm|69{FIO&f(^ zZZc03-v1ponNU*6z)zxR*qh-GU#kfLrK$B0soid7ui8RDg-i*EvyJjCOI`)B$F7Nm z^-s8KQcorBU@?*vCWKjsFVLB>9s;P5y_s))LnJ60IYTMOhpU%;sk86?KAv)p;tdgQPZ(m4o!Lg5aY&%AE!kjpm6(#PU0%Vpxs#-E99YEP<1Y zp4l$O|-}T%FzejG-_h&>i-}*Tr zuk9X@)?be2o30`QYw?8CxjO#i;|`%*hDv%`mg=S(kaV=(J_BtD1bhVg3V9-%R*VPS zNgb#=oYo|obc4baX7|cADlj4q&eD?L-JKhF1oSP>MMA8_qLJYX3fjkU$tVyzt@ zCMX%|MhYUu*Qzio2mT5-1guBxBZwu)?jy*a?z`!ZMa=Hb>y~s)wdb<0aB;a;s%M&G zA`vVr!5dTu?zapQ($>}Q;8^qG%u0dJN*2;y}uz6t4vG86wzM z!z}t8u9>X8U;*^`)um-)7_RJ%ikk4uu29Y_OLi6!?C0nyQ*A`JGmmiDa=`x00CzLp+X(+jCIEG&x{+9QP3>#m zDV&6CU`@}I7`xxnpIpfyI*XMc)uO~(DGd6O-1?Jv8G@FjNYGfy3hK&OJ$>8+p;M)i zlnbSvIw208#$AVq`pP3X&RrI&F68#tuwr< zp!WK9=JX>X0H%lcdXy3n8-eScl1<%kVqety>L z(HCR}(zFb!H0?GcU~aLz3cVvg`BT#TjrWskr-h9&m=%k%VwWZ{wcGondIlMzeNP&&@}j8HAsMO4i7AQXrx_&K#X&SDuI3 zHad%}4&$61+u90mmqMu7dzjNyK=sNwmyRooq%BYuFu@mr`A2j|F$Dbb{KVaD8Ffo< z*PAPwo{qjzcsc`~$I7YAu|*f4M)5`xjD@ zLFIsT3iKHAZiJ67Ik`tLy!Kew(3sDsow<{^gl_q5t|iS0D2xz{gVGFH4~zet5=A|j zfLtIAHbhJp#1}C;TV%lwvC@=0+``{V*xDKiB*lT>zhLAe5x|=Z&A8Z8a*)wKR8;Q$ zft;zHRB|tfif>5T#8LI9>Q=f9#;ZX$0ZfIkr2GI{uC3)Wkd3f?2 zOz_TW_UTrW=u;a7qDrBMj@nO9o=hcepiFiEcobV1(VsCKjPKXcJyZ>*@`mgY>=@^4 z!nLfZ{z-3bDm6VXY%oiLsWEab{RTb7V7XjI7k62$=UVCgb5(==@x}ES`EVX^>%A~c9GpDE ztF}4Smm)foV{8`&2PJzNEGRR=vYsd{=dxV90MTGgu6r~AI%QRxhG{FF1r8Icg_9aE zyG_SQ+mdu1lxt(YuboQP~c&Ln2aLqMybF`X0rDuFAQa>VNZQLx(+&&&w znlIuCDJ<>}_~6l$HT&=5^7AM^kG+3&?gie2AycXz@i^Gur?<{_%!(+KRQL{)GrXPK zz1fyLO$XCsI=jAhrJ0X+ezhml)&4@hl~_aE0KJvV(b|tIekfw`V-8!| z+A)fdg2CV|e5YR^7_##;XBCv@4$}X8>ypCO$&PeN+HyBM_P4gU_5dins@Pd0d80Fm zbaTmmDtwh20EMF&wAT}a391odmH29A1>^fE^%=?NvQ5isIzhhI!;fe61myU%vZ($^ z=q0vNqP4~#-LtA6y{_x|0?_9bT`=TJh8w%Sp(5Fm9^O`IUThL@S9`LIag(_Pm=*{%F3`&p4&E3(3i%9-e}pYbPQhX_}WXNi^PQ zZs!q^1<|L$HxeIZ<^qSS$=v|5C#?whL3Z&*Sh39J!{}zLB0kD4`ZK!Qpe${#Dpd|y z4@b~EWo5niKn0erUsWG(yuJq} zh^bfb9esGwvO{8gL!!%NDPQ|EAr{DY*#6NRrVaois(kcok%*&Pab=*_+pCXFwpb#}Bbj4xC>e;uUQm5|G=2f+mjXp0GKEyuibTeF`N6wQh5mRi-uz^m(T z+gEqQT#&FQg5yO@w%8JKS7%2)#La=5C2#Ip_X6pA?1;neTJBsV3G>315=2F1z3Q1U z6m%}t(f7^Y!JwKGc(~Z(4w*N>tT^0UD|S3w<`-9Yz3jB3(!p43z6H*dk&kXy%^uXs zFUlkP5(eN{BQhPSp-Qh|vmviK*Tlaf*&QZiennCvar%CY#k}Q7=Di}flj!Sl*X6je zrScm4k>$fDt;km|sSmt8bIvO!DirLAntO;VsVI^&&ND{J6Fh&vgvn4>}$-mm(5lQd^ehx_+4|eBB?7P^h z=R`^3c^2U7qSTGUNerX^cBX0SzFI zRF&i6gg4;GhUXC&wjFU}GBs8?u@tL1Q4n#SGm{+)7B`O>Bn{0ph9-Ae0fhhyC4|!P z!Th60FoBQ$&kDvg+L_}7jju;P?q^G@c?4X;a{^#f`sfpq-6+{@apm7 zAF{%&j0;u8nIS9Yxn(Q&+2xu>r41X#&sWFFeyT$2>(dHNJDgoJN|65;0s)TKvb(g& zdgw6QEQq45d^wG)ni+yW-x}iSin^Qlta}(tX<AaC1RTu*xhSZg~Ip0(1>rWfG)63x@giy=5jqR7Ylr^Dm$uhr(GyLNUzn zvA5U|r!e2)56=)|s@F9RXk}RYe+0K6f!vnV2t_os>(JlaeN`sf%Z+t7G}KZmab_y8 zw;)L=Qvxm$`qo%$Lc*`wD#*qb36f$=i=oDeF`)v9G3djP)GfYyz=gek^PCZgkTH%0 z8DNkp&{ND8R(JK8T%ErkgCI9!88k4O${$7`CCD6VRO{WxajnBTa{`R1Ph`4&igeJe zl5j!4d})N;gJ09;3g6!i&qouo6*W>i}6d%2GxgA~cHCr`4 zlz**n4O?NzqI_@$L~F3o0sbs|HfCDU9QeSt%DZ;1V}2yZgM%tc)P$iFl-JCkgE8rw zS|~02Lw$dSA-33nNP>LIPG^er(@1*+(Xxz|SQ*PT**!N2-)vC5_+2H&QUf|2y&{kH zBCV`ycQqA{s-pZf>p~r~&@tnd{mZdb*8|X&fg*CFad#0dKahFcn|@e=`ogiAvYxkwKR0pd*php_{v(o1?%A%v_x=W9RLt^0I#gb+$+s&{!vQz zj-$zHwwtXP%Z12dO+a+db*aDnP^C-RbZOaUODN@LH8bXkL~&OAaZnjs9O;MSom`qx zKiY%8YbjOZtoTpJTs%tvbCF%7Gt$tOfVrJ(l6^`bW9x-fO)A(5-IhO9Bye4Ec=7FB z1@Kp#U(82Xp57Y2PTznz-5)-j`mLfqclM|b zf;M4z2SV7ud=MLfk&M?%_ZbjrbF!EjqZ2T8&X8r<{gsD zYY8!j*3?6j9rBbx;RZh1P)_1LB5`jsQzxsnAl)eO7`!zYuqqUF7;E5;0&(Lp;e-xP zFv{#>P(IrE<~`GkJpd@PT%P2AJmKp(EAHo z;9CnhUPqu-=U+mLn}Es8;ps2!TY=#7G7OL6^1s>RR2 z^RxRds^bES`!44V{H!*?qu7P!rE@|EP5a1>JJ#3Qmjr%=L@*4w+r=CZ^ACCV#l{8k zBZPz83e~_|1zKb{bkDSZkw~rsZNR!Qn_f`e6irWK;w5JU@-NTJ6yOi_?B=nsd@i!9 zLmt^X>MQCy7tJY2BSLU~=-+NCRE@{I7vxE7gKP(@&j~W-7BlvNK|mh|&4lly*)`S;%*ZKbDK| zo|@+Di->S7-YTDeg@Se1=N<8s6`NqUQzg?6N+f^5DXkC@DeH(WfWq~-EbwUX6f<{CA2;}*&Jm&oI|z8syvtl z*Bti=*@EM96y(rKlkHy-h!yM)JBxq*_yH^Dvt4`V*Jf{j$~Tr0g#6$y1)jv)#NPt(fYkw{^}pJ!@sVpJh=V368~=Z{io3Oe|7-=4>#5-Wt+cLsn2RX2V$JY zyykUpO4=Zs5MzU)!p1jlls9Xi!7y7*WCu>=_X5{5!TPXW8EEbE=J*AMpBX-J~S?fb~IOG=fDm?uWa^efP`e zVL*qavyyQnm0;?kFy3cnG;@cu?sm7-704qXS;`hN-6v`kC+FRyY1Z#aRep~SwqsuF zz^dqb-F4W-KNcqb7^Z9MUh+WOfJwRRf8BF;aYSw9MdHnSeh@w(oD(-)jp@vwrp(W$ zJ%GidwXX-YD%!_*Lv#MJunnH!^Wj6ZAA~g98x8#B%^vktN3&`q1Q)&3WWsY}WP;dt zGR`Lz^_%_}7pkn+P-0q3^8q)&Ym{bM-3@0u!Ez<(CQP@^xR-4-y)g?|XDIDubEb+^ zOZ~AT6{@ueC`Bk9n=i8#y+G5=7?2fumD{=@;FqcEiA04Je=0S&r{LK$PH_jn*0R&i zxo(OFrBCTlASAa+~ zS~7QetD+oKcbwmnm~I&eM)K*&OzOe3eU9q+ZS6@oM#2%OC&*#`hd z^g>eON46+};u*!hb|XB|`CEY~LIZ z8h3+pGSkX?o%hedgSfWe)@WRPJ9cjTu>FiinXM=FsJFX8PotYZr)Zmxy(-|s)-8wZ z{x0|YwK2smFySk{|u#5<;x%0nM$$xFke?cXOsMvf@6M*^j?Fsyt zpYR{lRD)4R{>`6eE8x#6^&3Wn563vetRjI#C2`-Q$G7m0mqlt`-_TK#@a^tEnDXj~ zfLcX;^M$nD$Hb{>To&W?S*ddr?&l!=DY~S9R>e{gOIDi0A|s_$Khv|d*fV1&1WQ&N zexJ!*)x-7f>Fa(&{bPPUI0Pe|)&oGfPuHbF2TL%!m3P;cCh|<+EBH*58oPF71**pb zmz;^tra^d`CYYdt8vPhRj2K28sLAx0Ta%~l=??8}5{$4NIEn#wA)=nB6CI()3QRK& zONV-jZA2e}TY%<4UBvQCE|B?pApoN<8-Jf!6GYcN`HF#OC(87C)jYazl$HcG6x+xa zX2L)S4+80j65alHFXkr>(?U^EIlxDXrpj-vYjg;^pgeoXoH|5on*0c1ph>adi#zs^ zVYpa){_~q1Ky=h-fnRVN=NX4)?2zBdJ;fr%-8x+n%cSN0r{YvWog?>3HXLa8w}1k% zbGO6rUb%kksUeH$hD-+(_F-T?gihf2Bf1;KL1RylL$?JI(82TT1V=6(k1aysQc@tb zTH~2WJms1~jEUp5XU3-XYYIpD&a{%%4LfZ#9n3+_Z%Et80Lvi^2yH> zDZedN&%Nmqjr=-w*cW{EPrGcET&Jr`kFy;kj$7&lL@jXAiv+=$GgKvPI%H^o(F(>b z>8}a;wP4B%Fl!|H%4L+ZYsPQH`?yIlEwYi&mrN5*DEeI25?u=|eo)4x==5#|-|~{E zmuDsAuPWM>kAqMy9M_Rl$xuFSH-gH*s#aUCJ2Rr#+Xxa@@q#5U{mLbKMv-Vk3Gfn7 zAs^^eSWQiXeh#Oo;1zYF1&ImLi!4SQ;q}0VTV~?*#8DiI`l=;zsg1}_HqhxRdDO3r zbC`iiaq7o8>}hJTK!q&zRra;Z8q;31%e1Y$Nt_!$fz`!q&?X9{2v<>r z;>@S~lKQ;e5g>MWwT#CEdH>7%vT~i{!N^EU5}#Y==ZjTIzbPNW6KY~Es!JyiZVSjb zPW;^2T`1}7kQ`sPyMt()ntjM)Ow{$|CQ0U8WyAbXAQULqz=0|1Oa8|{IKBTWeGx|} zD)MjZsT=Hnv!>fyyO>$n>bclk+Zh=Dhlui5{r?NYX$;!8h{Af^;X92|0S+1pnvgTvx7 zZ*vURsxwW#K9cpUF{xs~E&J+C4U3XLIkOq5z1dWRB-g+Ba=9^}nf!}#8H5P6<`L&6!~0S;GYM za7&1Cvj^^Gb2QP2Z0mmdXfwjc(LnQ|4MrLZNzA=!rcFSTcpoUBRJ}QgiA*v7#$7OV zdijou?gE!?E_9=Syv~t`477kSx(9j@({kl;`+kVwL;b;?r9<;G5CsSpg%+ZF+R?<> zT@ldF-0fFL(GjnS-(kIbZV*7Wpb$78Nh zxI!{mjDmwkueyD>9`JElx*xRVk;nwI)?al8()Ec;a%0|~D+a+>%Gb%<<=8%Eot~aw z;k{n{s4xvT_u}c28Sj5asIpFK>EOtyT>x_)$jLZy+IIATQx-Uj9cu%|(V2@G;uEkN zoe6<^z$@?YUD{%}jd=P6@uW%!iUy@Zf0G6v?+!p(n~OM_Ntgqpi;!B0a)ml6PTmxO znPu{vV~@ZfIF5iw*qo?Cs)I||ZMjjhxkHL0KfZK$_;3aJZ-XMD0I~kuNr!=1bJzLB zQPl_)pb}@sJhp;{T zCs+;q=KIGfWkyAg)QUdweHJq#N*XARJw{TU8ggMZHp?f~EPQE;I{r%K$li?~)$$i& zepG(NL7Y&-{4t)`VC_{#S=)3hhUIa{V9mpd?36=UU&2M;0>s&|Va~AC%la&6ny_mp zq9%Vk%`{TKT*7|{$*7>JX)%lkae3JWDQI`d^v!6fuI<95v4_g871Gar5Q_oiK( zd-)Jg##>v%WZqzC9@;>Ft$r!l{=oRmZXexO z6A7070Gvg(6W=WMJuC+WPn6^;*bG zbfx!S?_Ja0mCW639uf#(K&u~zEB|Bvf?<7j*oaEGB~%iV{=ogo12%rUNbRAKa1Hj z=^)1xW7jPhRg!%~uXk4|oL4GOx(O8yT_#b_DbWN}+^~Brdm%mA+`(UlwT^`o*|qTy z0xiSU0Q3;RJfjfFG_MyO(e;o?bjD^rxX=RGkNMJr_pS(~_!if=Nvs>@fi*U}k;$Zy z%cndgX|af-OI&%@Wq(#uM+D(dMmbd(hK-d`hXnpQ=G<`=hnul$-E}*3iu353aCHI* z=>)E1ZvChiEzVC9UOfMkF={aV>e0@&iBbw95_6Q}kw5c4j$eCo9J)UDmh^@vBInfK zp@qT()A~~*;yQkE@_(XjdVUZ)1D-yqKfey}K}hQmAeH7j<7nC!H-oZc9&MOkKt5}= zwU*4RKY{B69(-hkEErOZ)z1q$D4^I2lk<7sJ5stdz|8wqpTs#UB&9H}V2WhKiyF|e zwA=RjNY`?J`QD(_NS^b%T=%R26W^VJrz~Yg@D*Ys% zCm8lCwA}63zQ-#iEyyUPJ*prGUOHzjj~ZFBQLa&{VbYZHefpa%>+kJr-wu%f{QT2= z9Va743wvj$e`|mK%hUM3wm<*nDVf_WZ*Km6+}rn;y(`F}d{|HU0ZCTJ6m;t+VM^0tBA03l-HTuu*1nr(LTX8EVr$4<~ee z81=ksW#D~;dv7OMR$&bovJ^g>}5vy8XTCC3qN$I~f2;wim=lJHTQ*#6zvL#ZEv2oF06bY!YA zHOvH^YTHAz zw1&qA+8>lb1Td7EvvlEM;4NNFtsgq9EpH#_V9gYew;klaQLU{(@^X71QA{|2%(Y@( zy@vBc1fXi{nol3w#Q$8QzQ);HK!HKO-DA$GUdKS&2t?vpt)$*AsOnCFx~cxLel_k> zEsYkYYBXd!*g+-+nVzHe%)YxLw%xuUGa`C zwlv?3Dm2y>w%`7-f2j9=A)m%5_Sq6Lz;qo^ZLGElj^k=L_@@FPQKFPKE|p`N^h#I4 zN^p*ei%@-b;gWacLt7sGsmsav$b7nxJTx|`4n*5Cpiehj(D<^wXUcH>F%VlRND-q& zNu&n_6>~LZC1CXo3JWcTHLQ_XdU|)t)=*OGt7ARG-m2x9}gmDk~ zh&=nuiWTSCaCv@0sEj!tcYU&8$llfy4x^dU%IAN-UYcd&2T9UZ22~$0_XT#ob(OFP zB5$@9?@KHtJGk}e6&E!9AYsdmVeD4m&_lF8ELBfg$}*0W645B&TTghdX5o1MH2DLx z9(c_H2RBX2910M>VNkg9pE?MC1zA)6H7m{X`}oJg&j28m)CmY$tYF107o&+}~9)wGt58l*= z_Qq$TgU0|8&t-gEy|sG*1lFT?;ncuGj!3)7;nl!*a&ly5$Ia+IdAcn++ZcANkXP*y z>aCdQoQ|WlX|5~^cX63W{~*$Q@m8w3CZt6wC>Q)ih5S1OQu)F%s~D?^T=IaGR`blV zh%sy3B@2p1ZG@@_$Gnnl;#5XCy`_mp#t#6DwMC_sGLo&ofI3`nugu74QEQ?>L3cKC zfY@L)6Q~13d9R$D#+E>_iP19q^jXGI2es@jWtF^z@|0P@sdH|+RNHJAl#-4z5iGI2 z)GWW6H+A=CfbG6J#@5G-ab0cgUzTqlL zG|Q}IsSK{A-?7ccnjAqs>Eyb{jm5zFDaXuIiRrO}^RUO{7I{eke=raB6f9B)%au7L zsLMo4D0P25!y1QsHWJ)R=Z$YwB;7cBK7Y8E$I9kpx=n@7ouW+dFzfzNMJz zB&*~ajy6+|!%{3SsHCAa7cNP88916Gbz=#irsWTxV&B7T8DVs(Xk@9n!k)4Q@SgYY z4LwfY#i$AKp(BL3=mgY;pe;M2&00RGu`(s3V-`4{4wicv{8SgKzj}eSMszA-I`6%? zLg&TcnnTuj!H|VCWIqa%J>lK^nfvEpi-YvNVAMdDo9wfbMNZk$X+XBz`YsGGnk(wcM}!Z~Rw4YWprtmwcZx@-9oAV(70(K)BXttoQg`?_|`3J>gx}u+cl97K=#F z;gFgFMv=kF{4n%M5B+1mTLf_qkeFtm5?rlYBNdLbSF2HzkY7anBw^3YjqWSLZqMrL z>*>miTFZudR$5BsC><98Hu5 zkqu>6l=ufQi|p(gyhFW+IwU+8M9d_S@ly9~CMKO|tK^2lPd7sNLH`C$1AkfrvfCf? ztTb*aKn{c?goM5qKqFf)0EE}c9CPi#IjX@##K=*Ct<{f%#|riW~vR`uGOf_L+fs*MUaEqN$rAOJlv?&R^`=z5Ovw-dvsOqeCf`KX?PR)IP#a zvmr{mt^W+DSfHhsBYmeb{75E^^!6ueG=#0a(q}h6#hAJjiwvNQVl?ohg4i3cHZOeQ z;{rR_KLbC(9=J2#g#Ia0*YC`Exm4;lA;D%MX-gX*oqT5#rZ>5AKr&r z*lx``NYBmnLt0SZ55Jh2La|*qGFO!WZ0ug`XNbF1>UOpaA5O7pFj%T~Q`KyRBk3GT zzu)~`hpMgTr?=ZrK{cUYFUCuN zOqTPZW{Vr2c(RQZY~%CiF1f69Nb8&i9kSdx?+SzQQL)5+JRqfd2gCKu*&cu@?1lx&11TYF^ zYel#WY>M6)RKx?6r#5Y-tneZ42R=y~t+5sNik6HY!?j65 zDEF1~f?Ji&oMa^9B}r*y`#T2{X?-szNlJSzpA&aCbMX5Ge%-!3%v02hv5_Q9%Dx~yx|4d=T&l48xaY$OQG zsZePlz2X#{#Eq2PZ96C;U4lNWTtznJom;j3$l|GEF#fc$5 zaA69zCcf&23yQWw-DQ-@aN+}CaS{{qjXo=!uAgd_APlQV9QV9sN(Aoim+E(o*qQp_ zcfDWz!0E*AV1@~c(v1{0!wMHf#BxCUP_?xL8S~y+9B>%bFG(kQn zwSGV0$Gu1FAuc@RFH&znauh7wKPY#C{VUOAZXT29lv0-jm?IaO1UZQlTWXq|tO2@F zPQ!%;!h}|QK)bwQg0s54H#i5sXSr?!-;v@h{nvM>W5jmoyQ^}_aS6E&eJ*%JOvS8_ zkHVHU>T(neRpGOl(sQa%va3H@;*nTpWa0WkW0+~~yzMeXqOB99(HYPC1)n^1-hROG zmK`cC4ua$f2O!Y`1j$&;CFOgYR4j8=rgSXg*by?`=qC3W=ib?cz5_5F(7oMN*E78N zSFldrNn@9g(v-@bcL|q)^+&PBhB2a?QAP(}wO{f@yfeNQ-)2MwM^?aw(SDa%c@>6cHWLOP`lO;tB-r^JGXU?I z9}$lcXPYq8&>680{`^8|A4W79g4fr?^Ki5)3A|^e?NyTo%N6W?1q^Z<^&}&2hii5RctSsH<32Jka9W4RjkXq3ZZ(Xg-RpwE^YK6(@^D+wIYjI@OF#p&V33)s!aebw?s**KOpogY_IHf&RvG5=yJ9POB&vaVOIYf6}D% z;(2YP;L*TLPkk=cnR}!AJM8}pdy#ZE*8TYAw3@$RKk9#l{r|4+|Hq`a|3Ta{QPQzP zWJsOk z!Y%U}v4mPQ(uWHHtmhXeSZME~dT;>QCR6fX%>}q?zdZ1LSNUy5M69JlpA>n~n}48c zMj6R}sHf1YJBIc_OcrA9^%{hcX@(W)!3?i(#r$X;5N#|o*BadZnW1_R+Mew$Ib1;Y zsLzk8i~o3*`Q)rwPIQ4H#8HuHAr@%0K5L5(skmd95OM6LXpm}xgEk{Kw8l)_WW%O~ zQ7f7J)EQ+T5uoX`5mNyonJ%qH+iiLmIhUE7Zb<&bgCxF?xksMi=)#4KYz%|4uR+GPWdBv$G@CjH0V24u(f zZO3AJ)ErF+J2u>sl2l%O_rdUC4K&Lx$S<&*3fjl_uwOOPJ0BfUQJ{RheV7+!KXy+o zL7~m(B!5tCxjX{>waflBH~mk!oE8l1w*Mc*bd;m{%H%hfA@faD{nLK^+mj4TX`TPq zNH!UHp16K`n9Vn;K(|o`Lw)-J3H$b&_~ZWI{N*abA~?%=|qy&z$gwFlp`{5KIOl?*nh&Pm24Y1@c32i8P>K=#?JKZ(y(>ekb`RlMdn>e zrZX7ELz?Ue#~Cw{gjj1a>Y*+*KS6$rfYMS7kv6BIgJJWe8pW1J7V?MjQ|7Xow}N|<-Zf<u%wN6l>o`*u_A#*QV^Fjec5 zh{#4EL~xslz-VY*)3<77X6tyjX>02Neqwjb;C*stL)(OE$2pcj|e+!#vD5 z=pM46q1a9oX25}TwWLlMpZq4B$pZw2H|UG>gsy)1O}Ut2xE*S zlXA}B%NBX4Skz6odT15Tfz2FrAfXva+ctSbykvPCm^3v4uJo960(sB*9|0)zN3zTh z?5_wz#<4orrc>d77<;31zGR6-_|E}(>_n(Ozg^^DLj(CPNmsXhUI1Jo)2`3NQzC$Z z*I}|O>l4-TY5F_lGNS=aKzMoj@Pbn^EH#w@U#>LrldDe~iAVk93kFL?GwvgzFthfDeoziygcQ7JBCkN2EZ4jKvvoUg%VCC`gmMkKn& zd5;X8fj)18RA1bzuSJR={ytqg5_E$_x8O$8?VBj=80Gfp%QcgdBdn(UMzDr@!R7Ox*cbQ4kn4-OlHQX(H~K-ogWpLwZt%?_e(y&~pzPtg z&?isfymUNKQU+zU4

e!8J&w8*5)xZ?{e4vCMu8BS5tv4x5h;XcD+{fkT#SzMTmz z;7cO1q6xM}#VYzF2NUkC4oIy-t{p4H!L*It13MK8MiEPKfdQ;N9Qqj-VySF=DnHw} z@`-CeR9}4W)Uq0%w!syjXoWl)Z%2ydIv)EVux1WWU!PKrEOq3)eoK&~%X8f||79JT z9d!pXe%Ve#U*;Nb@pt^)K^FLSX^O*6S`lp_Zf;p5I+XO{;Doe(mTRGzk>A?G_>#X` z=@6{)`eaIVzm5z0Uib7}reuU|!m5vK(5&uut9(C`VwiL!md#y>zC*&G8l>um@-+ia z!so6a>Xb=YW6}W$UY(sM3ck@F+W=i4d@LCwW{TwZp{k5of)-D$aUKe}cHL(xWSBzc zS8I*nt}3<8Mam;ap&hX)t>L&L1C#mg1KkG4?l*|(9Woyo4}i!Yo?St=N$#5Edch!G zElC^5sB0~RFV~yt+_f;fXdv@ajP@d=@@wDtXVVu`Rn1>lDAw+;a|pQs#wK5`m`;1- za=3r5$)S4EDuAN2PBOGoZFe7BAd`c{$s_FM|J13Q<*Gde#y0hvw{qb`&4&Pgt~o*% zy4|8ek?N zy!MzQ?$j*Dkc)`=jmbhC`!2H%$#Yk9IU?OwDO2Y~CnLb(Jb)Yh;GQAPJ0iH>JM&4S z{S*p(LE$m;Nc<);h`aulhuGXSe5Q@2Ep)cbPc?U|yP{+%CDS_PCCak8gg0j#Oy`nH z->#Y39eK>A@6CO$_mHr`e+I}5->#D8SrV%Ja`#d;v!?_(InPnz%ExFut(a*b+EO8) zvF>!={CP?LNs0G(AwDTT{eP_NA$$dU2#~F_1aeWsKkmT-np+#2xUkzhoM`<1=2##y zSWKarlh9{tOFMv3Y@{d;m1fplY&(~FI`)c9nZaP{6^?;Jca2aHHvNZh=eqfMl)U+S z?6(E)kC}BeixroXaIUbuvUQAi=JYQqY$?R|6b@!*+e>JPaUhOE-aRTo7T)nJmH3`H zadQLEw=tPNP62pbzl;FdWee$F1aK<8GVN`A^i(qUHNA`TgSp}+Rb=Imx3{XF61(IF z^1bjcNx>j$lI6PO<}Z!!fU|~AZg=+`Zq1tlm+AWGz%p%Co8=XNjALg1@Jk}K!CC&B zS$UDMpAB83)RO4j&__sn`WnPP&jOD^B^^;Czh>?epk8L?g7Nbh}TM4R2~ss^p}p&2>VvSjn#C0uA+7 z-n_G0s{dZGs%UMxbE0F!G@Zr9@tT5DNz2DRkd?dp4+Wc?JsJxD(U-WrJU3AO&=1Y- z$B+3E65@o_G8lIT)vsAw-BY`C^io%&e=B80eQK;+&CW=3*d0e=XuwTFYN?FnMP{-F z-$ia_i^)c!eRkS9hyK~rplm0#mCBoO7!CSjZ);IUD>s!?C&-6g31t02b^{k>`#l^j z2g!OjL$zoRP!>d(Oj8O12Q18QRu;?y{7m?KG&S>+JjGwE(V=v@PvD9gANn zS`7jvIjou#D>xfA>+*5q%q9>5#VCOVWM%7?>a+Gm^k&Auo9Vek*ycV4MnBj+dF*W} z=;Im|OjwH&->hG2o&__@alDN34!-89(d58I1%Twp+^%-8OLuE~K$|n9?Pc;_G-alV z#b<$~yfT<6X~OX7lfGv??Q{1e%ylK1sp7ge6$Dv23?;)q#-rC5jr#VGnwYF1nOT)k@plGB8t3`aUETRmPSDf`~`oqv*1~lcz>ah z79iQO@8y+j^aUf+$n3rF~MllbviX7@_>d zrY=NPr=qJvZn|o=gJzQ0Rp}ZHJ2F&z6!6&yPKe7Q?DI=)F~%iq0# zS>7bLb%;LGDYx(S#v}A&`3uebNw=!$HdKV=@R)sa>XC!&H*%0o*ZWD>>wEGZbIuPM zIS6l|U=9!UgDp)+By6$YZ-(UxE!bymhA^jiS2TqR3aoB0h;^2H8QB#>uP?-uuW&wa z3#agAi>2aX#YWn87(`lp#P*nsjf2q}1N=@7$T85Wg)`KhXF8d^3FNBWA(NF zKy%0}LXMkPL6+8HD&M_^kK!_m>?bF{LV<5S+c1u4OT`rG1#t2pSqKsBsL~9c>ijx& ze067bya92^6&=qp0_wNq8G4s1=44;^#J{SLXj<8ris6oG1f~R}>G(OdnvSXp>yARyfh9(P(DEd3B+VkkM^47s;s)&B^q5Of_QXdBCgq_ zHKSO|E=_@t@1Dk>Q4S>+tInXF?od{I@0Kri`Gdgdw! zq#o;4XucyJm4MZx_`$(?vw_-&c&ACWDt(M6JLQT~3Ht`T5WY)>JmF&>#WhG{_dMO#g2qpOqE$YLOU5wpQ!3w`I_(wc~8 z_osrAJYF>y`@v-kI+-loZV7rq;P`kgNwcuV(f%HzfIO`XzGv?&vk@2s4=sq>8HpxjxZW?WPYkK^yJ&AYshFx*@F?QY>hgT3(U3`NVlijpvS1^M z`SQJJ-vEVYmSqnTGD2Mn2{|?F3299jjD+9aZtyS`G7oD^qF>KXwte%~BO3S40g}gt z^^^B>$;r)I%(Vk%v5!53j$&Wzh7V3MX5fxoU|B`DK06Au@`iXSuj_cWyTnA07NNXu zY<)qJt{xZig?zW7NgG#ILE>=>iq|$~&Giwgt7nV`5_l2MwTx{eX%JQ+mvi^1S ziOCm*5 zFh|YvMw20RI<736`BDeVg8o&>R9gp!c=cqkt4!y$&^)hlse8PXIpcv7(OKB3cn_R2 zNS77L+!N(4OLsh+NE+B>EXjQ}({#NvrHX3mZ8@T|$(Fyoi(Le&ta=9?fG{i?CwoYz z=?TvLVKla#5z>L$8*-sDT}`N53Zsbt;<0-<-|3ARKg=&N7k}ENd&mO7x}&sS5y;k~ zKWP%Y4Bl{^9`emJ#b%{!f6v3w{>gH(7H7pv5-kh&7HK3n1UZ_+Y-NIzdc9k`Gz{#g zc*7-T`d#X*$t#LN0NpbN!h4Gpq$1KTVPyp%mz1xngZ-UZZZRD3COU^W7Oj`ZaIRfw zo_SIiPriY-iswv3O%|)dG#F472>2o(^*ItCjx1W@CZFW4yeHO@I?2P?_nfBbVI_Y% zf@fAEwx+i)9mC3iymMRK5yFgc<@QAnw%$^<-(0@YxNl<-G9-XhdoHAVUZzyP{gZYZy95PLR6PiC&4PYSKfb>`U8H{v!oczfsj{B zU$1OQ^OU$FvCwe@=sz9G;lg1v6#(}(<>2-_i!~H{sdxC;pNt;&#~?uQViumm&{im~ z;b&CC_J*L{Cu`|nQcAbKks>u(2JDfg<*WoU*7P!Ule9A26-z;3i&Vp{7Q_Qex>-FMKv(#~k%wj1 zdNeqihc_V^?+8Y!;pg`v!0#W3?>aa_6bOv|kN2ZQd-MBd5Xm1Z+_ODjAV}p9c0+?d zz89rwpLo6~AfB%aNE;zzB!wy~!nq)PdT(-6f4^Oc(1<8@V#^p!Sr(3iU7^~xFkb)h z5riPnr;4hj<|@CX8I>FH9QW)VMA46CB+RC~vyN$-jlYbxr{16xPnOP8Y)Zv1fNxKIBB&U~?XW)%KQYE9){0b-r`{_Ss|Uj?PSLV&H_!>YW_Rwi z%WFEvK7OlH=>3t(QBlz&>c%M5=zwh7YotC=ryB8O-Mbq(E+&rd=uo^cC ze6x6CCueFKHG;Bh5cRwX(LPv@!t*yGLT$evqRzq6Q8Aw*Nd(^j4hvhco$ z@&v?%#LoRNUV!BC2%-iZk&SD=UM_|scmf0C`R7?MXx{O@#wSOK$&EGx^MpD6t5S?< zH>`=HDI)?w2}X~pO1We1+9s;E+e9??>^C4!f}QFem3SWJf>4!I5YsK6o0P1kw)*H! ziRq1RNPMvJPpCPPa0w+!H8!>!AzBDHKpc8>=-}0wI02;7PABNSx^Y8()o3}O1$3-6` zaU&C#i4)^WZ4GSm%3aNsy#y&s(DgJKUYXw-_M9Y|ST23ELb9iYp2@0KsO6<&KO0LV zH3FKCAk!#+P=cIJ&tqg=Q)9mHp;N`Coh$RI6PhC6UiMWcU|V5kU1?!ck`;56th+e6 z4C~AkWsUh-+!RhQeYHoSpxhE`c@NjidTyM>l^}eQ6?BGvJ1)`>#0$v@`gsg^z85}u z(|bpw^-72AXO$weHkOJVP|vlh`MlAtdsHh%N~b46+qy%E_N|xzb0C?pR%SJEiEVvQTD^gTk6%i-GW>djlLOPyHOi`s5h+62#B z2^XG`t4(-*IBvmbO3(Fp>2n6rW{Rvj)yEliGLh6GCNLNJJQ)g$wDy4+N1mT>;D^N~ zsxbY@?+i=(0?q0EX}#{c#5Eh2D@o+tcc#)%1}CI2uSem(+c2ys|8dppCc+a3p^qd2 z7UFR_VFl7UOXiYae-K@#emM6i7(KyH(#cq$k`jGiq6&`|zl>K=vbodsqfC}ihItun z*Sm)UD&4{Cc-Gjs94hWzd9E2Ux8uUm#Dr!)?>MBW_{2{=KIrE~(!>E)k4N#URD)hujgOjD+Q}C#Y>G2uKdOT4w{E z6w!q4C@-^092g*Hpqr2^XTU#z5FZ&rv6mD);3+n&+6IIK>d86N>Qj=*njm^<$nL_6 z0ZpYovHFCh2||5}%wcPI*U`qtirvWc{&53-i+ws?5{CHFmmt{Ci{QT=fi^$~4G!BJ z;wECZwf+n6snNIn(9|xVLr&Wu&LZ2+6ix5pEgh3g|Sr#0) z-DNm%ML7v6Weut0zHaTzJ$oEa`x-jO{{7(ogNuLwoqaXjaJW$WPp05+NAR?x;Ux!Q zX9p_Juc*gea~i^J>-y)3azX>mVu9C{gQfB3J&Ojec`)$fJup}v zpuk^wj@7~b#B(wjP#$>ME?A!Zzw?}mc>Rg&wDaJ_x?sudfWI~hu5ics2;jxFUGk{Eq2Nr6CC2UuHLSnBWCoVCkGi&!U5ycE@rre{U9) z2VQdpmPb+SEFK5PyJsq}oR1A&@d1`i7_x7`EMLbf!B3T#kM$qU#{;ii0L$}E`d1!! z9fR{Rz*lvLWuTS+mEpK$|J8Uu9|L@yYFLIMrL!2|W&m8(>htlz7lMZ6Yf%1`?~Jn0 zf2V=oNAPtfVQJcL!qJ>YO+bMEa>qb{;VS~c0=pQ%0sp+roC6!as0%DMo-rIYT#1+S z*$rPc;uL$s3)2h^`_~#0=Ocj6j6NkO_VNe85uDzCzvM~(iRpB2`FE3t{ylxDf^PH` zHgHV;=6@b8a0J|7*YxczC+PoKl!)6rnj9Uj1;pC+fB4;Vhy5*B#N z8x9yY^72p6XHQi4CsHk6IOu=E?f%}+(7hBs*bdg)<0ZU`?O? zJvdC9#-CWuZUQabn~MNMdGB<+6fTLT}l0Na{~-}C$zzwjrHv)l6TEBncC zq{aTeE&sWM|3q@y5O{|$Y(oyuAUSmp{|WuW!A{GH%eXU<92K#kuJy8|Kk$+ZK4Jkza%auK=`a6rDJcnAookbgu#_#c(+FopmC literal 0 HcmV?d00001 diff --git a/qgis-app/plugins/validator.py b/qgis-app/plugins/validator.py index 0e7c0d31..e1482bd4 100644 --- a/qgis-app/plugins/validator.py +++ b/qgis-app/plugins/validator.py @@ -210,8 +210,20 @@ def validator(package): errors="replace", ) - # Checks that package_name exists + # Metadata list, also usefull to pass warnings to the main view + metadata = [] + namelist = zip.namelist() + # Check if the zip file contains multiple parent folders + # If it is, show a warning for now + try: + parent_folders = list(set([str(name).split('/')[0] for name in namelist])) + if len(parent_folders) > 1: + metadata.append(("multiple_parent_folders", ', '.join(parent_folders))) + except: + pass + + # Checks that package_name exists try: package_name = namelist[0][: namelist[0].index("/")] except: @@ -238,8 +250,6 @@ def validator(package): if initname not in namelist: raise ValidationError(_("Cannot find __init__.py in plugin package.")) - # Checks metadata - metadata = [] # First parse metadata.txt if metadataname in namelist: try: diff --git a/qgis-app/plugins/views.py b/qgis-app/plugins/views.py index 29d71cc4..956e3409 100644 --- a/qgis-app/plugins/views.py +++ b/qgis-app/plugins/views.py @@ -494,6 +494,17 @@ def plugin_upload(request): ) del form.cleaned_data["license_recommended"] + if form.cleaned_data.get("multiple_parent_folders"): + parent_folders = form.cleaned_data.get("multiple_parent_folders") + messages.warning( + request, + _( + f"Your plugin includes multiple parent folders: {parent_folders}. Please be aware that only the first folder has been recognized. It is strongly advised to have a single parent folder." + ), + fail_silently=True, + ) + del form.cleaned_data["multiple_parent_folders"] + except (IntegrityError, ValidationError, DjangoUnicodeDecodeError) as e: connection.close() messages.error(request, e, fail_silently=True) @@ -1202,6 +1213,17 @@ def _version_create(request, plugin, version, is_trusted=False): ) del form.cleaned_data["license_recommended"] + if form.cleaned_data.get("multiple_parent_folders"): + parent_folders = form.cleaned_data.get("multiple_parent_folders") + messages.warning( + request, + _( + f"Your plugin includes multiple parent folders: {parent_folders}. Please be aware that only the first folder has been recognized. It is strongly advised to have a single parent folder." + ), + fail_silently=True, + ) + del form.cleaned_data["multiple_parent_folders"] + _main_plugin_update(request, new_object.plugin, form) _check_optional_metadata(form, request) return HttpResponseRedirect(new_object.plugin.get_absolute_url()) @@ -1276,6 +1298,17 @@ def _version_update(request, plugin, version, is_trusted=False): ) del form.cleaned_data["license_recommended"] + if form.cleaned_data.get("multiple_parent_folders"): + parent_folders = form.cleaned_data.get("multiple_parent_folders") + messages.warning( + request, + _( + f"Your plugin includes multiple parent folders: {parent_folders}. Please be aware that only the first folder has been recognized. It is strongly advised to have a single parent folder." + ), + fail_silently=True, + ) + del form.cleaned_data["multiple_parent_folders"] + except (IntegrityError, ValidationError, DjangoUnicodeDecodeError) as e: messages.error(request, e, fail_silently=True) connection.close()