From 43bd56a32815b58f37318eb66e71f021c713622e Mon Sep 17 00:00:00 2001 From: Roland Gruber Date: Sat, 21 May 2011 10:55:48 +0000 Subject: [PATCH] added quota management (RFE 1811449) --- lam/HISTORY | 4 +- lam/docs/manual-sources/howto.xml | 61 ++- .../images/mod_systemQuotas.png | Bin 0 -> 44083 bytes .../manual-sources/images/schema_quota.png | Bin 0 -> 725 bytes lam/lib/modules/systemQuotas.inc | 378 ++++++++++++++++++ 5 files changed, 437 insertions(+), 6 deletions(-) create mode 100644 lam/docs/manual-sources/images/mod_systemQuotas.png create mode 100644 lam/docs/manual-sources/images/schema_quota.png create mode 100644 lam/lib/modules/systemQuotas.inc diff --git a/lam/HISTORY b/lam/HISTORY index cacc030c..aeff1aba 100644 --- a/lam/HISTORY +++ b/lam/HISTORY @@ -1,5 +1,7 @@ August 2011 3.5.0 - - New module "General information": shows internal data about accounts (e.g. creation time) + - New modules: + -> "General information": shows internal data about accounts (e.g. creation time) + -> "Quota": manage filesystem quota inside LDAP (Linux DiskQuota) (RFE 1811449) - inetOrgPerson: New attributes o, employeeNumber, initials - Unix: Support to create home directories on multiple servers and also for existing users - Server information shows data from cn=monitor diff --git a/lam/docs/manual-sources/howto.xml b/lam/docs/manual-sources/howto.xml index 255c68de..74938409 100644 --- a/lam/docs/manual-sources/howto.xml +++ b/lam/docs/manual-sources/howto.xml @@ -1651,12 +1651,19 @@ Have fun!
- Quota + Filesystem quota (lamdaemon) You can manage file system quotas with LAM. This requires to - setup lamdaemon. File system quotas - are not stored inside LAM but managed directly on the specified - servers. + setup lamdaemon. LAM connects to + your server via SSH and manages the disk filesystem quotas. The quotas + are stored directly on the filesystem. This is the default mechanism + to store quotas for most systems. + + Please add the module "Quota (quota)" for users to your LAM + server profile to enable this feature. + + If you store the quota information directly inside LDAP please + see the next section. @@ -1667,6 +1674,30 @@ Have fun!
+
+ Filesystem quota (LDAP) + + You can store your filesystem quotas directly in LDAP. See + Linux + DiskQuota for details since it requires quota tools that + support LDAP. You will need to install the quota LDAP schema to manage + the object class "systemQuotas". + + Please add the module "Quota (systemQuotas)" for users to your + LAM server profile to enable this feature. + + If you store the quota information on the filesystem please see + the previous section. + + + + + + + + +
+
Kolab @@ -3724,6 +3755,26 @@ Have fun! + + + + + + + + Filesystem quotas + + systemQuotas + + quota.schema + + Linux + DiskQuota + + + + @@ -3739,7 +3790,7 @@ Have fun! Part of OpenLDAP installation - These account type is only available in LAM Pro. + This account type is only available in LAM Pro. diff --git a/lam/docs/manual-sources/images/mod_systemQuotas.png b/lam/docs/manual-sources/images/mod_systemQuotas.png new file mode 100644 index 0000000000000000000000000000000000000000..6111796405a65aadd77ed38ae37c718fb0b5564d GIT binary patch literal 44083 zcmZ^Lby!s07w*uZNGM8(G}1^(NlJGk4bt5pC5VWEv@`X?|Azvq-@;VG7*w6+TZaZ3UIeMFi*{HTRMP#|Q)Mb%$?+(_}zyVLr+DQ#RZ z#1;R>vy8lE-A zkPAQjcj8e5U)+8N_PbBZCokWP`?@bDT9~hFEsuMe$30qmK!F+X@8b@umKgSuq)+FBxe{1z<@ofVfV zC28P)1HTQIrHx}X+nzI+9;r;o=W5=mr-D=GT3H3|dN9wacT7y2l92}gcY13}XFOY) zpq$U;`J1#7sV~o$B?pO|BotE`MDw4`-5&LDp#0zUQ;@S9ZB5@rRiJj@$xIl8-uF6Tu>8Mo z>;E?oO~*{P{+S7e`-*8o`a^US(hqhH4_U2m3yDpqZNCz0Xj~1sz6xpl!3N*6jK@f# z)AFwB>dvyVD!RMBJM?u?RWvZ&0-4&2Sc`zc}`7Ao95eb2?M6b`4^l_E^)$3M4$ef zx_3@-4_GK)os>UN&d-ue$u8CznIGJ{`>QDUD@yW7&9jNro^dUznU0zE!nP=CsayAX z9oI)#ZrpgUBz)o8_enICQDZ({r`!?=(HcR{78&4Lv82JN)Jqw7he@+*db&aTtNCkm z91c!SZ#k1|n_DECo14QYCDk3${MKl6w)zTZFD;|V!K0ab{j8Tos`B+pzUpR3KxWY& z8EjM2S8`5Ys*7Iih7UEQ4=Yg~C>OesMx2XV6MIMyb*|9dKrri7J6>I0obz&X|6Lo* z%~eV>_-d~3D}?Zdcq3))#9nS9dtB=E(O~zxa%gDCq4AUz+X$Z2P1=dm^E`DcjXWURM$d+dwJ8qXFJmOe%?~;=@+K!ib?l0HZzsz*BlZtrI{nnf>UZ*Jh-Mi!6R&u3}yzDQ}kE^)Q zVMcMN)PwEGKeW^dzwV?Cg}oL!Da4l!|y6 zBaF??&R$_N+M{+?$hM=a%ja-o98RNCNIK|bYiwifI1>?K)S&qJorkggt?_nJ)%LK@ z!7mvlB_&x|>>D@EE{?kURJnt3>waE=0#71CH@31YCnqP; zC(RBV9egEFmJYyB~o-?mjMLujap3cNrP<5v2nY z@hs{4l*MOc7m2;i-l=-;dkB)pw)8f6hG6lhf4@H?8lM04ektrHt6p`f(f0tjw4}0E zY17|4_gB*VmZSMxmWgt@!p!xnQK%P|mbl$Fo|(~tJ4L-W`0`vLUo|_4$AQ%*;fd#7 zcQOys>|~A0jl0axN{wELxm?fBHeoc4gt+*@+TdHfAG8Ml9OoYCFpm&DoS(m(_^iS7 z;$k$Ad|wV;*kA50(5d%5*zNWii(#&&?&9u1uAuf#KJ zJHs86nRUM0@8+rPq!4`a#Jo4P-f5x5`)Es}NXM-ulo;NU%;TUaEp0iN)7|t6MPE;E zvDwMV35E`T|DHNjfP0trE3L#Q-Cvjh$??+Tsc^DaeQh7}n(`c4`925TJ%g;2`WX7%WuNLp`vhch8 zQPDX-Dfg42ku1oC_W+#msVgmbq%GNO36tkp?qv`OGc$7tAroCE z&h6vlW9jHDfp1U1cWiA7VT1sk6HX?X0q|m_6n+VYi}U?nx7!Xg4T8M9)h~AE>%IP3 zPn0wGHB5fiC?J1%Yz&d(>hg?@()9FTO(BV^|Dv>$+%Z$ktlOkDT)*+9@5$cM5_^%# zO^Ytm;4RuWzwM+Aw%M{nRik&PRv3|vCz(2j#}Ct9oSIYvpg)3kdT4#Fotm0yLSkG2v_Ln=*2n}j2s*Up*2(; zNrcB|+l@be{;YFd%lH(?CQmNp^CDX|w&CLNH-xtimDdPmFeF&gG_bZ-a=&k2nNob* z5fqqvUj_=aN+1ev|E?;rpQ^2}9(MNdU^8s^W{>=HCa1LYk+5(h{A7)a@RV&C%Tvh& zcU)OsK5T!OHd*iO(VHqLe0A=!FVNe_67!o-afQGinu2LZ*c&zC2woDLX$u*@w&n zVJSTZ)(;!8xY7yU^8l6$LXKkUlM@K@uz1goezN*Cg<;2Xw>CEy>eX=2(k^Z4s?NES z(v}>Jj*DJ!ywA!)!9x#ygdX!sS9`yU`PhoQJ^G!tyOFXNdckZStCv=DfB$ZOrc{1@ zeq3A}cDw1t(bm-2ey=c?I2yvMDv(?*I?KBwm*MnqQ@7T2jjiGMM+{R&q4qtY!G|)c zva%guW&y9S4*`#@!cT#}XV=$l92|PTt}|{=)m0T0*=0(GA!e64&Fp73`1S&z4R%m)##pg_U8UV`NK~e9Wnk%s^P^McHO@=mW3HFyCt%wy?J%$Pu9;> zOz9w1shaHSl6P_0zsF{xzeo zsWVT}!os43XxsB7IZq4_V@M>U#%J|>)nA>R1rSFeM;IF$L(o3ms@pyu_Nk^qC^z_= z+#=&gMMu9y!j4efqRDlz3rw7C|SZEct#JL%+_Q43H_@jcg3PG2^{^bPpdEs58Fo@}?FR z@;=-EY`oO$?(SYjFtvo9W2=V8XzA|c#E`d}{$o>+Az1D5a!wtd#P$v3>&i9~_nwEx5nzB@ z#2n3zO;J%%NHy*fyfLb6XWId>v9Z&SMQgFCsi^Lgk%Vdj9^WP`qumXy}gMF8!c(+Hi#uW4%6p= zhj+}%w|`tO3Bt%4R^;9%Gdnv$qb7vx8sML+?W@ZOVS7zhvF+OrF~y9GW+AiZ$R|FB z#ZZ+6_lA>k5Sp5rWqL)LZvz8YTlU&y3kwUUTL@M9Y|YK%Iv<;c62H`OQ>mWnSiHQf zJm;c44RUi1QErfDM?{uonO78|A-7(=D!+;F*WG24)3KTG%33NhB=V3r9yJpJWG7@; z^7Z9~*Z6x!SJ(UO&jX7UU+RI60g!RA=xJ%8V`15Z*b4|0+@QvB?gx~BsN;ha&T$YG zY$vOC2eRc}y?W&p@0>Z_XXJS(Nk>5;q8$u55`yj`);!o9DT&daJ5XwPrV;bIu0lyQ zH96_}29kPoW7pDaz+Y>rNvD*vtq|3J*LiFMGBNM@s151+iQt{1zkdZ?mgQT+$#B>J zru}UWzAeeN6b$P@#_MQwu-ac{3MCMB=Lk1R_xINrU}c*d8&6!8yPgyg^gm6<_AFy$ zW)5W&YR`6lx~Gy4F{)tL8sfp^9Z245@D7xw#;Z%xJ9q975Ik3J|4piiNw&P%`nZx3sLPj7r2W^YGE zV(dxfZKGo3Sj5QZF11k_PEpRHpC+>VYoG3(Gu>(pBfb96($Z3xoH&4jV1iI`mVf!e zesB-tCXtb`@%K?%2*M7led&OR$vDmB!9{w7uY4{}-7G9tnwpyO)p9$u8P)S1nRg}3 z_+3qPb=g80|J9-w-6S=Sp*zR+F6#HLu0q$ffy>LwsX7lW&G|on`0XdF6_Ot(CMQ?H zd_z5nJxIaJ1pLe%Qa=m`>C36f9|_>d*NO@SY3VU2tRUzf$Jfw@06GD}1h|nya5oB% zuT+VNi8t=C-WPB$Oi7tq?a#c&s>kav{RHx-Uee&P z-)F!S8_ZFFlItHBH^t9qN^ulQ!fg$?jxqK#fE>gQR37LU7);D})~<_nY(jwbfE7C# z)gcK=NJ>JI;1Lw`ooVo`bKjhQujHKnO@wi2VFB(v71C)^Vj{!6QNT3-<^cdD(uxvAwYHbD{9&dtT4I#Q?M$bV{kV2e)~Qn*5=b zPvi)_p<8L|36};*Wv1RczR@$FQ&3P4!Y+h7W=t_h#~rW@SWb%}^p}5TXC2QD?MO+J zA+Q9@^N4J5CuhKX0Y66m*p`Tr1_0fWW(WP`mXC>LYPM|Bw9sXn#@Xw5TeN5^JB^$E z*;(~N(qeBX^6e(okSJzS0v@fUrdqZZ4{i_ZzJdWgHI6K8gp;*;;`N4_Y0Cg^YTf6>Z;8IKXy7Y2{WE2@7Y#Xn@OG`{~=s{iQ9J4n^G zWY?!)r!t4B1GS17@a>)@O;Y{{QN4OhvGm1hDwIQhqh14pzfdslN8D$)+)0;Ejs9#s zto7glo8XfHoeEh3)I&*HG_%FCmj29NzP^TcDhRJA!R*Zb41f(2Iy2~Lu(J9Q&yZu6 zVry$_!>ZN4*rh_e@bWrbAMKr-)N4qJiemRVScMX7H3t_5CoCi+BL*E6mCIoo0OL&r z5m+GE4P0DctgIo&-81x|#FV|=2_!BUa;!~Mbo8}ROrf3=WOH$G9RRSwB^Nr_-?sr5 z$fQ3zewZJtg6n%{@=yfnVl4Omu zr0L}$pYSLhA^>nBqlA*;;y}6@0m{WDR``pjZBU*Tz#K;N&fNF(V7%N)?K^!}$3&^| zQ+fHDh#{!Sl+uK}re2&M?_QnFT)7Uuee))T*C{~t&&tXuoLxgI1>*_0Gcz!>|NedU zwO2@Os|8~8vr5}Uz4tLOF;I=H(apxwX9Kuh=}q%H-bpVh0q|+($+I<>8)5%k6z}qQ z0XMTkz-eCm*|P)+Ovn>qB;3(;yVn5RVMeGWAvf0oIK)MJ+j94uMa+OZECH5u?^=XI z$xjN~7Fw4Leg9hh3L&1J&UafED%ANq{CEA=^XIlBC2TH>?-oAtRdsh=W_p__CCr|x z)IQs0sePIe(WG=-iiwNM!^x=&ERkd;U`FjS)Ar-tg%euYHK18jh5d??h4}gTsi{pS z%B>KkkUw^Ib|8Qwnt&s4n5yN5Pz@AtWMm{{3*X&e_j0g(&yStp9*Sv%gc=~&0L|DZ zM+_`ZYU%?bB17UawmxztdiG zL8#UTIwfR(6o}M!DcOgA|DySS$W@%Kb~5?Vj3px@16h>caYqE$>^s&Lvf&ic{TVxE$LuA9 zo+qj|u|Mzqx)%}8QpfH%n_25NXltA0^>+aMru4I_Et2d<=JK(jp%FD`c&JGJ;76X` z-oMAjpwzjJ{T;DPd)a24aT+BC`fR?ImU$&5B^B3)8xZQi6W2VUp~-@<3Yi0 zey91sd;*4SNSL@cZw?Vo*Ljpc@f8%Tl=@_CVPRo@etvaztj1*pT$wm$yusHy;(=gj zoE!LvzdwTX`bY+FKra09V`uM2zJ={=2L}g3C|n_91_cJvR|SbN)!P8@ahv;rc5(o8 zN5%f$=lt_`>FS71`rERB9m~O(d*|}}YjdR?E%}quJWUqgme9Iv+5GPmk@7-ChBLtOIj|URIiFS1 zQckqw8_s+%L`M9qi8}o&2zcVl^EaI-0&&H~#0xD`eurJQf2~)NdEU2^#E>?ZiZ9(A z`&KiwHAS29u?!veCD)76WZMC9znJODqL@q*O}HCp5q-!uYB`hoH3Qkte}%>}l{CKG zmVX>>a954?E+woP=pvEz^}dh`>g(%qp3;TVtqvDx0l0?R29px3U;~2VM|QADX66kL zG7#7J8UPV8BAbh!{}dp&yu7@tn;V&sPjzM{^(d$Dk3cYpsYbsvJgVH@FyoxPKMI$t zLEZ9+9A;1rL;VVcBlxnPv-2K+H7LMywOr-pyPz;md*Z1IG(4<$=c~IpNzZp?zXQ?Y z;pCLa=aN(W2Er1PZY8sDWmT2m$zC>%Oa?u&2p9{fbYE=8Ii?Q4c48yCySsstYm4wZ zp2N@vfvnh($76G1X>Cm#GztB=*BH1$CyTd#HUqm|Sy}m5hkpf72QUDVt$v7|^Aneo z?&=JBIy$<&1*k)Ak_&w#k7v}7Ez;aKQ7cOClif~2$06C6X$0A%<@^9pCfsc748QH? z!GPcg&s|5pMAq%LsfZd(hrL32RDH*VftU9f90e}K@a0MNWEg}oauO122ZtHpBH7s3 z>{Zi*e34O5KtouYpZ{S|>#u^2Xi63Io!86Z$|OLHjZb7{=UA2vouk)i6b+Qie2DFg zUl(#YpF1N*_{(*5caaPFG)Gv-r%`qe8s@lAhY@@esJ2h3UFwV-RoLJ8{u7&!k;uHp zmWamfEsG}7 z)Bkz_Qr%}of-7t~Z<3wjA#xN778gF8Z&n>~as;yI%66yf@6LXg>+p(WW#O@#n5uDc zAQ#?x$TFIT)!qTe!;A9U5gG2>;CcP217O}k3CHwm-P^R zJQjc|ejrc0z0a;Sx3Moz!z;!heE`JJB>*ldEM#69QMSzXP=Fd7fKN(Pl(CgnVpNpV z{<6Zm9cU9x;QOu{fmRuIS^t72L?a~8_JToU2pGmU|AiZWTN&u3NZZxL6T{R24Zdf znRBVBe_wPkYA^y_5a_W`ptVp|HWWm1(s>#ALiS8;g?g@H@5Ux~7)iFziCISBVl$Sv;mo~}k?5kLgOimAYHG4Yxr?)hy!_@h zwG9KDy8rps2}o@9-@XCWXl`dW1uV$^%HMkNH>luJM+XOms@bxTO_uV|5k&m1mcXQ* z*ap*BdF+8cjv3)zT2Wy)QaBD!b?E@YyPJo{JycPi3sM}lwt}YF@2{`5N(kTpyh1}m zfvOtLSChIUQNNJ_FjOr!JSA>q9nUusR9J2hAddaP}_9MTW zti#DMI6fE=xUfQf?8rxOxFXs^z1rpsy z`1|@VUzupvlRYzBTwJxghubq(pogQN-#q?PPy$^2P@|t8s{@Q?X=!O~{ReCmv=*w~ zj|tXcRaV(m;&`YY9v%-e0r|ZFm;4j{oRGh$|G{(Ve)omzcNgpbo@l9krIqdKx z9`l~b^L3t`GG=o-Gdt40oT-`{>?D%Mh5#ED?Yj^ncnC~HR(3YSGzGGx#Uc`77DSSP z8#`x9@rD5b0Wd{oL!G_=3!$Dt$9-Ts76$0GK%)SPm~!Y`dCbnf3vZa;D=#kxmEfAz zgF6SL;N@f(O#`apuc@gib(5DTOYuP0KnA~-=OXU&?ZNQQp3sK#S3}p!O)41>RCb`svQMr32flpX6m;tX@-dn(^S0;WoL;&MM#MA@d|lCH80bN+k0#; zM$IAe*p}vJerKD$2wvAVr^PmmxHvvGyFzWwi)leQ#ETQv(y{@+#D(|w7+qX8<5O~1 zY$CM6bkGpf(-WqEFQ53?m&xp_GpOyI9kF!8cFwla%9>8qsCB73aVR9wG_r?1C@$uc zptpQ9OyMc(w{OmFVPUuWE?!IVbsDd6m8T2C$xsig1#UGqAxGFBEzA2;%sH~mVwaa^ z4t)2~5Vp3q&S@gypFP~&6%~7|Jo&~X;{yW&ftubofmDHk`=Bizpn5#+&pUgJ6l{r( zj*iN0tXka@6FTA1s*lFH$zMoAGgUK}R-KvT&+XfQjGG{7xGRWX{Uf`ahz^#u)J5+;dn3EE|# z!g<)MMN|ec4O9@|DL7l86KSNxP#C&z5SAl_i8L}ZzDFrVMVl6BzH|{o3KfzKy7?lO zK%}Xwt6zIf2l12~cFKq)E_;?`-IonX9bH{vuLDd3W)o0WS5FQeB7M3^gaVZfGAaTy zlEbXyTd~Oc&Bb|iV!weqw{Jst5^?=(6T3+ZnBxU>0ztJhAQ`ZBtssG26K%HCdUr$W zafPk`pOE&+$;p|Sw32Vu)89@&c1(g!rd*KQYn^$Z>Mcr3GX#Es*aTqf8OXy8pt>O} z2eN``WWWc@D=I)WXoUt5XEgydKIrWreKQwwhlwuHt2#&33gaRsps2`wk&Ixz-1uqY z%L{_@^Hc$T>+^H#MwN(-CvB58CV)uM5g&!@gxxo61ipL}u+aVT939d8OIxeBaQmk+ z_S#xNSQsj3BYZvn36}v`*%K3%S0c4C-np-2g*C}_nU0vV`Cs(nCvaK@0`Zf0f>(Xzdk_c{ld&u>-xQ? zXA6|%GEYG7^R0@CicoOYGO+1YLyMNazFqAvBoVN80LCxQfK<|Xpc#^}y0X$r-FJM7 zu{6?V$V7PO!Gi}-7Aq+z)I&wgGvkx#Et5V-vPl{AO?ayM8M_@miNeUl%*(H(A>U z<-kb)HMf!y?K~>0Z?sAnA*n_&V~6xQl1eZmY2I?e>>ThpaHLi$aY-Sx*78V z!^+)#;OE*;&ejsNLL6XNFNMtUAI$rUaJb^^%_ zme2T4dV_NS%>2G|dR7*VT71Fa4&0 zFcTAVN61kgLRa@X$0hVlK%A$18noKdB%k`k6WWfxS+)?RvGlue9w@q9L;|M0W{8Am z{VvaI?iZ@oIGc_0K_2WQRc&o;UEh+lULB61R}nL4VZjVYNjcQD`4Na^(h@p10+m}w z#p7X;6U%Jm<{v-ip~qpW%o=i$X8(jt6 zl9wO|pk~K79QWoVbjm80l5>l;rt3)w2>#(h?Vmutf<~y$sf1qA)f!^2+}f9I9y7i? z&WqADq@$3mJN5PTJ$W8$VR_uX{r9{UqOxPjvpes^$4_zmn%0dMoUi{Dx6JrZ%1(SM zhCvPVAFHu2g<(a}R4r2_f4mF=tZey=o0#}mn8=if&{yKb+;=%Ol_MvMTt#!yPChY& zD$mj>MF0G8Urkk=f#EX_X@~sBRYpUd%C4pFDDM|dhtr>i4;R?zM|H#+z6rXkB%_id z>>%J~oec(+W!@bRRTQ#FJgZVXiwmDi3oESz;R6Goomr){C+uI#v+CSqU7b{TY!fo# zzv$Pkcpvf8(&n@3m5x_`DgOuUo$pGm-MD8P{Xqi*m*0JDZzxaDvnYnaGgGo1Dz*9- z>GQvKCD;(3R3Q-Dr+;HJTDaWfyRT|1)e7btLQAvgSDxMn=?~=aJs??NoR!|+_7gFK zvqC})XGa2pe#Nq~sw}#i?k%Aq4$ME)7gmiwH&bN+g22beZ*Ol0tPUPI?5i|RdK>sV z9uRH0xw$zwqJ;(2KS7KKe89lK@TC4pV0V=<_PdN1%U#5>YtUA84W-UPIpEC-Kv*a! zgoTH@ySa5&$>5N1@q!2s)d?IR`Sg>yxn1iUzzSTqS=7&|gGh3;G5!Jg)wno!(7t$B zJx71e%n0-HCX8Ndz0k#1HUYp=7@`Nz8IU%I-tWWj!5=<+2$;CbqGLN%`xh!L=)v^S zM!OcxeV~~HZpOOe6m-J92GblJ>XIV$SuV@I+3Od|youi^+LXT~QZ1i)0T3%VIM^yb zALQA^O9G@kwOn^sS9NRIz0UF>GJ(pHXJ76+qo=gge*igGN>Xx<^bR4RMuU%M2CsZQ zBy`Z4(V@9>H0wp-3))~jLubu)eo=^wI^LRry0iY<;3Ll=YKnbC3PZtTq zVjzHUhnfoSQSEdl08e)rJ%L5T{j*26@aRpojL}#+WF{_hJf1MxhMjY z(wr(iMx_HGLW?K%j;5bESXEYHZpwc1lh1oYrCJbCFlL@FfHUF}D>ZBKKHM**HXZM?Gb_?jYc zbhy}F94b2exg;Q9{w;{m2P7DaN-cXCz zDD{D=3_(;^SC_|jOnEM4t1J}^3-l9Fyg*QgiCW&R3_n7Hmd>xx!ge_Z`a}aHC*Q4o zXPqkh>wbbT$%U;gR)?e*+z-&Lkhl22#m8~|S#GL%x`nor; z&2SQuKcFQ5Th-s7nH5@;Za-9H1~3L@b*xK5_^*9Cl6UnHs{F5J9}UAo>>lAJ2zuX& zE&Dv`cy+oi`sBxT@A=X86y#!(>~gTri?hEACORs8LQbQWnRc+jxn}{MG-Ac>;0ECH%PUXQA5RXIoGqDV6ErWxc6cqji`t{By3lEh*Z(!8D zJR>KScvYzL<;mRc2S|{}2uccU)6Qju$(#0msd$+0sQQ&#Jk;qBf&MgB55?#avGi%x zeMN;q%P(}78IcjSVlIRb0Z|xq>1U|XDOBi6vhSdZ{;gFsV3@Wf>F~FD-)292M72mH z8Y(JZ(-kOligHR;r^xig;MD(Fb?LWkT5zgY{RN4MKfZYqZftO6O0DdtG~8d(cZzxv z6=@{on)f?ZFkX0`;Kp4aCxL)(Z!Kpki}#NWX+k-~FfFfK3D&y_9<^Xnl61T+RmXFV z`;-ujKxh*zG_HE(B1H1V-@Pn-ofsk=!`_1FPk|TKjCeoX#}$8 zq$5IusgTg0{E@ojuY`t)tkQ#qFlQ9ajH1VLi4`IKkoWR=SWw9u*hhnhOpvBKi?Y5E zvST_lHug(TqFP6Y`g;NO4Yy9!U{sL;Lkb$Xr`iT|xW{;g9jUlT2y_a}z%%qv_FyCj zjja$Ok|q~?qW}al{^H$75W|`J4os00jpPhnt`#W>hr0{~!iz%4e2IX2R;O zC`E=ym-s7OyQNTq;fAh2RXWUbcENYZ=`qW6@y7j4{;D}EzD{yzNHnsZ$fA$N9*=RA z>4;ho*BNX3wDr9CgyY`vI}6Ey-vAv2S%m%#Gfs9WvVWp9jCc{ufTB*tu7;ICv0CY$ zej&LXrILaj7PlEV+l;yQN+r)b>kbDaAt}$+OR<2HK-K59nCh>wA zRVaI=y+j-;BDB@4J=cL*E2D{s5EEbG6?;z9@w<!$>z%LC&4yPPuCG9|#(Bhpt#}db13Kd4>qF^tfA`1*1A6e%V8& zE{zg4ev9#%yn$Pl(czbq#-@rvNS5?!ND09-as$P?%J`e6QQ}sIL*Y?z@#WqKJQ;`B zkXQd$-0iT(B-!$J(D37nsLAR6-E7uY_oi%PW%njRgr@1|`3Viy>yKZ24)sFz7B-(e zInTLMW!@-uPgg~TnVLTpdO>Ep#)7o+c<&e-#Eqk>!WA>pMd;BG*nu)Zmk~}V^k|-( z%nj48M~C}fW*$iwA!WvL*m4E$J>z(3H4}!K{M%k@ zr4XV8vPt#%My1Y)#33Q&6r6U~JnK=%Qn|Zq$yp?B(L;IG^sHa9b6$5+6@8qEfA6vU z=%9?qIzBPZI)}#i$GG@~ZTT^W7ZIUv# z22Zch+_(8m{&eE~>syOcO$jxOT1h{X%IkFY~T! zZ>(S$k}!2lbjlp%{N{n|4Z+FI-xGJ4tabl)?xLONYo_SbRN|K#&ah2la!L@y{(UX< z8DnLSG*SKFxyEw^K~IIB>HKV186n%o7qfkqT-I)=wdNNJp zeIj&OGk|gQ^g334_0Qih_r8Cq>h@vChL#JGupq*} zl52r@Cx-gsD$Lj}*b#uTuJ>2|dw%Y+b|mKi=fd7#QBn}JAZRE8@nm1&Q6NP8 z*(Lo~BLdulyvhREBmD-WL7Z7rFTR32r&fvvOu6Np5JPi>a_NQB^Z2x6!ST z8T=Cv`L>k(pJm0yYkAj9gknU~`pO8=aA-tw<$#36S3PQ-n55q~6v znY_JPi;|%WR@7*pTdG@KM&-EB$H#*&(N9Vn^1|AgVvtyzwP-jwZPtrz5{Ewf>UyZ4 zhBf=Ew$R@W{`%E7x2GbHMndY`g@c2}(eiyX?fZL4#{Vot+dE`T@t1UYJWbt$FOI^3 zac&cJ2fW_k5h11)*^#jq`V@1w0;?tnsY>GNDnD zD|A3bvJ4++=wxE7^CX`~w+vT6&G&_G&|M*Eyhc7T`i%+cKeHaB%(%<*0$+?iI}mQ^ z4l2Tk*@86??-hFoRAQ)@*#r@9jYILp7PVtHj$Yxnl)n~k@yAU)ag4Selt>@Gf6(a>M*#tiy(kNx4U&xF!8AVB`#8^kcnKKqlNm z%oGECu`PXcaBuMb6n}n&Cjt|xMTBDU^?L~h4%d6D6y#(vi65UGf4Y{Mw;Q+LKJe?y zuv&VHWfeg0tQDvdEE{9ZrT&4|%&eceB1`3U7M(ivqqW0|+`20As|*L5$*=$HN5&?O z7JQRVjc=f2w5PsJKqPNLWUoSPL0OXhFvy$&+vxu9){q~EYUD^j*q&F;WgwU-*$Gjj z-Z26QrO$543$o@?)r^bD&iNz%S>?4Pj=F;7UCL57J5!OmQ)n?|M7{CP)@k;@-HJan z7M^SYiJPSYin;6n~?AW zHCAgWG!G>Mr(jwOGXOHP41QM?0HMuEo7Yog#FW=QT{$=NC290&8Y zX)`<_+7WzvEQW)Kq+xuA+#jp#*^k-#)OBFzJXD1ab3%gp$wA1fZB_P^hQ|7eNaaxm z%N6&@dh(DtQ)lH+lY7zLhAFx7Q1qm$_~8noOiFY@Kn(Md_zUYT}0I4hvGzo4Q>%gnCB@p0Zl|`mqAEW0@Td8;&Ez>+3JUq zi&dhQRYlo+TWH*mr9?yzCEk5cxV(^x~Wz?OMnW|NXKJ3$P z&T#N?kK5oGYqwhSzTyx-4=ufq5qW0G*LfH`qLm(l{|aGN9fHoFqn?qF-B08uL7yE> z!`>pU5_5Z1A$e!eV=KgU^_k#i&xwJ8hS|qLdg=fQ4k~|&1nmSj2jjK%lf6@4N+A_# zSwgf@dV40`@f$sgceBY@I1~O9|9$A0LNLd96X+-)zoB*W0W?5EAq@iENL~K@f9@^N zRM_lc07dD?D0a#~NHhc1TQqp0cai+v_n9fiODr)`Qp(Eeao-@7&(U5;Y}Y)R5l=dr zy4^l49C~K8SV7h%vLa07Bduc5CUp}Z6=)$V@m=n>V$n1*(dvwZl;WBF^h};BA7XFa zdW_JxImo;slmT~wlNalKG%)&zgx3Ey?#u6e=FdAS!;BI-<6kY z#*<0QZg(q&nw;FCr#TcmX}B%dd%g0)qU(HV#&2OJf%ZUpD0f(w`(TSoCOUu1^fP(G z7r&(WFybXtPZlx7tLc|qp(FG&EQz=&+jIH_a}Szu#UjL)hCh3>*0{vCgryCBTUtq} zy?JVUcy(D%iu-A5ARdp>!o)E0Xo}W&?xFRl)o8h=l1xUrR0a~l-|UQXqCJLWtEfhg zXQHj#qA8RX9g#P;=D0#*L9n-d*-s9YHMo? z8kZMZ;m79G*$t&$FAxRzy}0xg7nU{u0_zWbh<^_cojpph5FoF^_X0fsKqut3KC(7i zvJFb*VzXAU9x<<@e|&s=Rh5>}Y*TeLQ?1whd~xXglduS-1)yD7p~H)TL8jq)(HTMgbvg$5P#SJtD&LeCdN+wwR&Y9zyxYFyj9R@=xj=o{Wnt%Z>z zsjbcYtUdQ=Ti1VIcfSKyGU6nCwy6CcrFX>n_NXvyum57xx@Q=FIjgch$i84MC6Q(l z`sdP#Jg`LRQ%pGV*~O2voFKAs8ceaiRqarf2j64KKA^?)GktmMvKacu;5oWq%rY;f zPVi$I`G@x&8Swk@P<6_*$C|c&V3*8yr9H&EXa1WlccnmgF{7ecU#M$896KqN+Kfvo zcLed7X=VG92_L%8PMiM0YkI*M^1O&SO+tpr@kj%Y$Mo6I{tbIi;DBE`zC=M%!wgTe zEQ|k!^e*(By7DW_7IDs^1UWif;(+OM(1vgHh^ea+K*LqlK~*sA;!G?GqeVc zzA=m%)*UhJ4%!ty3xi|(W4nWUR>%Dx6q32<8BOpOS+pyC7LLBQpdRzEXbE;+>P~) zvsi3-2{9$`Y}e?%O+^8s-iUM?E6K5oc8Y4*pv`80t#PH*r|uhiewDjVa2!*_DG=X8 zMOMth#78oUo>N|$J(V`TGCO*6zxts$0 zs;5a9te63?es6B=(ee@dg(Kc9gye;coAcGGbkL(<2jb(S65j4gFzP{d!Rt=2ycNLr z&YVK$QGaOg@@Se&C2hx|iPR%S=<@jY+c7GQzMm6wnj<&O|7w&^eq0Z2k>TOA-@bhV zwir5m`1vkCrzhoV8~@A%TVE(XReboM2HzV2(g>W&%4%4>lM7we%=DJ7&~ydeSdtMB z1~a94-`u#@;RXEkXjyg%?9R?K2?kTy`dy_}^)8OZ7rs^GBpY@dEtgn3L^K+Hc#RR! znG5YF#Q@KW`~>&b)sTk=bu~i!8kF0^N4}hxhh_BBtl%5o_+0 zOIvpceJe*-X1MGJOin{35)-ZK3v&1$A#BHMOVr{^NKag^+<#2AMx+s28+>uz?|uK0 zQ-fhDLd0|^(OxiU`14?~ckdjq=S$MhTw8lyy9(pia;xTbo^`#(2&R_mww=s+>s|Di zOaS-)F!q)~b!}0!CLT1n2X}{H!QF$q2MF%&8eEg0L4v!xy9P~gClK7-r5E=}Rad|6 z>RWYxBpkwFpS9PXYs@jf@tvlgUemVPb;<8!V8!bO9|ht&<=B&Bv!Spd7&FvuJYvs3 z@@=yILo@Ds-CqP}pf7kr1Y8NYewUwbe)jTPHI}Ov+G^b*{EQxqA9}%2V;x<}`eOke z9F~SaFY40aux~P1s(fVYq_h;h4!wRnBs`JSe*>o={m}y|TD@{_0Ox6m0~qgm@p;fmtEp zy{xuIlG*Abw(TMcyv3CN(zP!?TW+*U!*=5llkU~=AM3tA=)syAj%X_y84m(kIz>sk zQjOj?q|%wwxM<#~+Bxo@D7^mQck6uV@S!{upF0+__Nu!snxVdw<{(i}FI^v`Ej0k> z2c7az|9XOFJ+j0mGiqG2LwK$nqFIM~z(%TONAwa)k?nbfWBZ}>iZfan5dYiQ^<`vn}_+%J2DnbGt= z05AwRpn<1suDAE~-o>W(>Dh90)CB#%oU|J7hy{W)Ye}Am;~>~sFHB_jSUMSj&ukem zJXBOvzQ@PUSUr&piRRj^5LEwrmQnNv2Qx;2C-u?%(klUhO}#b|Ulu$hs8d-&VSdqdQFA8_BLH6Ge->NgtoE`lGVr_V5?8FS6n&YbrYLXz|COrUZ7!XCA>=M`znrIgj`*tT*F+Li{m;D7;#k1M z>vyRp{sH%4I)~@;uicEt$sg=&4>!-(8xrp!7@yWo!1X3(Ydh&rX*%)OvXWhTaG1k+ zZZo?+L>M2Znk!o%xV`$UIfrN>`Nqq8hKKlUZr-t$MgLJ%0pFdcF4SB2k7Umf^1I&` z4BC);S#E|At(pwpe$um|bi(_KO z8)BGDb6k`}=ws$e=BgYT$E2nhM;L1gS3ypOd|_z4c&;9-(ffBy`{w=Hgzxuu&w?XC z=MNL({1Y&)@Rt|%(P;h6N`w8xt!_`p_pXLY@JIJoU8o0c%uhC}M`<)rOTjBGj!@P< zqCIw0)DFrO!)@g}YZ{Ro%v`p2wr3mo`n-*NzS|o??wz+M=SI<_)XyFpSFHzgO!>5c zqR>q;dvyC)>j_b1*E^oX1YOY1zI}hiH92G~U!EyW$GR#eNU(*E>AL#Oh z=*unN(B>OHa>6&=Hk;z=k>k!aN$L-UM4_kf1;X6I{*)joJ6tL}kRlnUXV!SEp)mV3 zxRxRC#GrY&=5OD3y!JIs7b0M`d~K%2bjosSz@XD_XJkvrsRa4|> zaPA}de91|p@AD5yYt;f@EVSRZE3m4;LbSmF1(uOH$IHCM4`1G6m?LL99k9bhWn0QN zNk!#+m8LYt3q|@hCiNR5!lFJ^nLbhUpuerTqelhek5gtvNLk9#`7bDANLD4hKX|k_ ze;6f9D0{-eV9XB5<^wE8F75E41_TDCJtg((2XG_*6zClL!9F-Un}o@Rd;yHC&ML>w zcjwq02^s>x7SYL+&wV5 zA<0wIS`Xe`7if8-jD?M}C{;dt^5b$g?;GgFTC8=SoeVPDK>-I$vEnff6YHo#PF&33LLKP>EEnl5+id;@=K@akwvof2cF z*$}1^nMyBiWB%eGb?+ql>eRt@x~O}ZC;q3<#Ja>(LF_g7o7H7h2xH?o6y$@0&CTD9 zigS(BF&xuMw!at6U(%Ku#u$!|E9^TtWto!|)9%eq3^K&Yy}C*TW~^L`#oWpt+U^Fv zwtLS$pTzT^5OU79?x){>K1RrWePyT5r-a4%cg7%QaS~Nq3`KmGEE~rpPm3s zZ$2L0%i{$eugB9#G`-s!XaBI!Ye$DFXD1gtA-mll?Ea1!Fk>%GdZsMx=<;kSP+eQ< zs{F3|Y3<&wI8oxz_cv;#DK!D=I#09dtd+$|wU9_+dvepMp}LYtHkh*|@>->{M&*ma zK?BlXh?Y9jc(>%;-RDA4OxevP%}uw?^Qk)phF4bVwQH$KeX81d6~l=QjH0~i;FSEN zkv+a%ewB-h;d{1vF^GM8-R|W^AY^B;7X;&dyu6m3?R$7=^N#3nFvj<3x>zWC`d>H+ zgN`B3^Uc{ISGjIe3$J48hnym5LD%6l@U1zt`!ml1JYkkL7IlDArnK1z-HxU8G64&b zBuf=kN%}1umQGk%nh{4PA0tBi;}lkMtWvW$v%h>XQ{e&*J}mO-6|*z#&^+E@`*|ZX3O((?RRXb~9r?d;1eG#1AD5Dq{em0G}6R zmg$Hl@Ig=JNFWI=0VkJky_LF=?W_Bh&;4h4dAWpdr57CXE;fn3v4ePLZ`g#mWCuM~ zeu1FnWM6VCSX{oRr1d?E_aT=>tcqaeG$Z-HNG>dR7Brg5ZUuWOq;WApWchazJMVma zyjeS_c0?dyx-%QwSM1I?V+?lBb#ii&mhsG^;#9j^@&0vveJ^HrxZ?hKWOhw5=ADff zNt5;mFv8m+qW>(h%RC2P{tYx?GkBkN#?o#u?3b~}@g5%u&gXb|?%KQ+8!L#AIn@a3 zX6r2DC#jbqNSo|4cveeX54ItGx4O?Qun+2Yq~nqJ?@uXqz8o)6L3~ZUFOxAbv?J&f!}=skXW#h@A0MC9@`om3c-?*o_;r;x-@vS?gNh<5Hw@Zjqwb!7 z#UXN@wkz6g0ld}p;W}-*Z3VXPIPwhqK-03WKQhE`*{bf7?Xd@Qzn6pS@&|6aRm|tq z+i$24&CRfnmBn&9*VtSo?#P7&g0{=^VXbcN?lQ8n{}_^Gsg~If7xSToh{p|^>YkG4 zRTMEc4-bd7SlnfiMO&iq#!~MbBYyrohR^=nv2x4X{9?>JUKconN>NJg`nJses-(i? zC!LCnD{pHH-C@w=`=2VF+IA`f5xycalmSIhpC3Lju+)aTy4~#mu2wcJI1KgrU_QPK zT%Hl)F2I$FjVNJkywPB*>wjk&wyFYrhkg%7zkmZw3Z96^DNix8LoXBz2gn1kCL>Nr z7%Ef%sM-bw25jc5su?@76%O=drKLN;5OmBtp4Umo=O=IP>qqKQy$hl51_FG(Rkx+f z%a2k1`ghw0PH!)nnN72ySO*@LOv(EDsd_47W3RCrEKG78AJBh(F_G0RP*Wg11zd~q zwa!0T-SJJ81<`C2r%0iUBfLC3Rx&8+cIM{RyWGBeDjR`K@?v3%ggoRuV82fgv>1z% z$dM(o(&f9eJy}N~^v~ek8Uy?E@`^sMyKe@rOung@SIOB-INsds+EFf6(_|*9t7YfX{mVX;kBcS2!^;cL4sW8V6l9}=TaUQP zX82{ho80bui_rG&HdAN&)9jE4^p};D4DV}ZU7@C1v;snM*s;)Cl+kSz8>%Nj{*hHQHBYk9K#HwYtCXejfS@ppjLK?52_1qcOlk zRiWE>3|xA^8!T?^1VwNkV==V&mR|Ohql{ZFw1)fAGOW+<|8uMpo-LnAm7ZqW zyoZ7sltxl1qRK;ab7`$yrqTHL3hpPC%k56i7rJk_=Drh@v>8gH=Bwm4_G}q4yEs&( zy}yf5Un9Kqt3YTTEz5Ik z-(uyIwNHp%cphERMMStmidl}*ichKahQ2>;Q9NM=1Ihm?oSl)r3W5qN&44VF9t<$} z+;e%XAAI6{ra_cb0P$$e!i8K zQhfA#lObP4#M&2;bAE1fvf@2Zlk!k%uDu1UoA1d{5D~!~el1=8s^<<-fcvG!B$(Z5 zPuwjJQ#?CAzu(QJBJr&g*ZkZzF*6td*)I6Fo2K}}t;x_1Mn1j$`1&l#m<79+mcGd0 zM(hS-?!0MRJh(o}Qxw!!H+mu_u5dr51e1EVw;s@41!Jv*_rs~&H&IbS-6zhh(@D** zB^PE+?)LbL&z~Mk5hAFJ3?cwOYcM;S0Dt|Vn9gK$$l=~@CW$)6mx$;H^&Nk|Ei|Ta z(K#4uAQ5z;b`iFRn7>$B@9X2Up7R-qX!56!iVdG{W&oQ|*yDC-NlxrDhYrV$kjw35 zc#(+v36+1VS7@Bu1P&WSH=0-=U_fYz2)FUUF}uIZN1!kJh58d5Md=4RbvRBWE9ikwF{$KqbbFuzt+QYI zNS~OHKpU8(^maU@TdTOH`rGZp!*WN4!M8RqpkNtf* zxZJ#E%lv?1m+LLHa%vY!e=^lNG9ce-NXRQuZsv8f|F}@ND1;N4vub!bo;>2e+%WUE zZt4C0uA&K8KGw6~1D33FLDkmuNU@9&}LS3Ow2Bk0$#}X1y)r z>L&1T(d8=N93D^Ovz)on1%gkZ60P~zyNQYNhY*)eZ*I>`!dk7QqnX-^Fp}}2*f++J zR!vKVw2`$~F6i$H0?~7{8qztt^_@=+=rUZ0M+cAcEsRbLq60I{oT+d|Gu!N*VqFj1 zIjlBoE!OK6oCRl=Y{gJ#8AXFySK3_twWeKC3qo|#_{=xJS+Il0jMTWR%20vARmdSK@_&qx@mQ07yV|ez ze#)Zj8#}yRJy5{UevI`m-=okJZ}NsmGCOFQoByrXG22_ic(Y1m{kR%vxYLD48`(&x z1py&$q<5{vSpdJ?w#f#uL2RT=CohT2hy-ucr%fCVhN?o)MH!mMv+0@5+>n|+q5O{Cb zO{A^bY(gZma>&%?-e~dA`-`?EzLQ7hEuTxF1FoU?Z{L>MJSjqr`i#*BmR{sG;w})Rb9sP-&=xD49+pgL0BG9ke9^dg7qU4O&MbP z=BRsq>&oiq8S_w?lpu%em42|;)j|_#!4qb|Q+D7?RIIN!!N2dc#$z>v)$GOu{Qe^4 zW>gq`ArtZQ3z6~1pS2tJo1ZxE)Y(CDv*{v6Cs*dtG^h*|hrX}gz+%BPUS!k$l0 zk4nb0K?W4iMTpy2Gt}3A3s?EB6agim08QhqQEaSTrok?oADKhj{3zk)*HKtl2s?%j z|3818)x>_HgDOeqE?K&;)zQpRiqkY<#FX$=F5CP8CVt;Ez1wgQ}-U-%@#b7-rz zY|Lru!Q#c;{IjP>m-W|?K)R0+VnBv6FPW@h}7%TCeu=N)WCLg`4cNZVgN07nr z=TB)$atKO{KMf5Sy1Inb;*5R{ihWfH;X#LtSrBslj3Xs8$lRjo>4)bR)jH)3V6-et z;(vaOc|9^|4!QmzJPhox9QjRq8O1(S>XSHX-`X{;S7xsUxPE8ISn<>!c>QpexSTaB z3P(FvX-!f+DkZ1Kj*q|SSzS#kuzbCw))e2u`&1$*_XKUN#mEqUMLCKPyE&U{mrUm) z$WaO_CVUP} zKbpVIZ4Rsxp;rCL`k1c~Og+j>LOQbCV9+r`Q%)fg+*;LyjUgB!3V&d;OaFkFDxjH4 zzNIhX(ykN@d%?ssLIjn&vQFRb8)Q(mzN2^4L5|$ZVRu-fgcT)DC2Q*E){s-BBp%hD zATEBj9|9pf*0r)UzXA=xj%=nqT7%qMg%~2r+<11%dIe)A8e+5LHoB-!igw9vsnP_S zKlHW2C_MF}_*m6rGx-LAkR~NB?`V+9QX|djoXuV{c`6F~@+dLHa3&=ACCn$bDlG{L zom(q|0}ce{PMtAwM8}5U*$#sBxpRZ@pz*4$piM-;*&_773&xKY$2*9a&YOv>IzL~~ zg298%ulEhl9I=u$!eK>%KjW$AMcpdg_Hq96#|UShOq3I0osqx9%|>9-y8^z`P1$!R z5^vZTph+HOk5myShFxG}y%$Pg0lF>2ruF6^2axWij!^>}K)oF;rj{ z$^hQHR8k_9SjzyZ)q5iGKeO*8fDRbwYoonjIc4sIt5Xo3-JF|*-92{Z!fxG6ty=}3 zHTAWdKL`n@>(CU@h)OSVb$fUX-Tk(CT$@a?7=sg`*tS5L=zNgXI8seg9%iZ-q0zPG zSBb{ic{wcRK1VUCD!n!|{v;=aa=bQe0)1%;xn(gbgSMEXBin8Yxg@Laq&9R1d7^!P z83Cgm1Je~5eTgZ-t(4UuKR zxVmlnoLQqQg^E6j%Sz3_)3|3;KU$w{dy+}0J{d*?A|m3eo>IyE-=2VGg%E1yp;KAm zI>j($VcOt?ZUrsL^+)866EiX=_y@x!He0{4ICq+(A$rgZTdzujY`&$XB_N&5>Ely^ z_W%`ms?xLHHFng5WJI1>k!HxPtR>rsA*wGKx8(K14Aw0~BXYKWR+2@JSfHGMh{uP@ zY&FU+C7tok(7e9E@2u_i#>vr3GLb`#gw;enxWE!1roe3B^t76Q-EJ@e87XPk>vDyM z5f$i>7S=7t65}(9?hNCqlL%9i65(}>3E`D!`O?>GLf;-=jrN95(b}XkATExs3}5Ah zv`bSxV*49R6BeL=w&}DJsf6Xu*Yjyu3(e?XdA;~0igA+kfGBlYKvhY z2$<(bfGzL_HTLx8=3u$`0$_W9wJQYw`}gml1&oO|PtRI41L6-rx5)ZSU59dZDnI|S zt591)Q8D#;K@<=&m;^G)4&&3)IgCVIl$0K_vaT_y#f5xQ^tL7ev*%+f2OHB7nFQH6 z+cV_rnD?I5@3}dtn_f9E@kaA81r2MOjJBvZ7y*+wDek)_KAnW6LRkTAWGh^tXP0YA zyw%p5!0K+?X-dSBN&KQk3)8=?Mn!P7O3ST~)8hcXD=S(fdGxf0tU%CrYXo3Ens03HzV**8uVs2_Q)S z?K;J0FQB2Ka-0N?14+rZ5#iwf9Q z2(10rVZp@2{KRKKy(=mLGllDeaWnuf#}Cfv^z`%;6uB+=Fzu&SldVHwU|6*rHQC_E zs%M#QKNYW46e)XJ00v2uUD*6bQTj`ZWn4}jLc5}X zQZrvWL3-b{O7mb+gG#b~ghos6<#Ev+zi!_W7Luaw`2=G`Eze+i^4uvY>AF)1tWD!l zT1iZFbjqbOEC)4~M^f2Jlr%IKi0`9pmtxyFJxh{~H7cKl>Ql9=K0!i!MbQaPrMWVa z1xXMiS-WeULW$bUACTds1_%HN$^1IeAn<)WlX#$ z2DPy1&;8C41l(t}he{1cOPB@nnRNV`eRGYFG#fjW?|{Y1-N`AHE%z|19rV>o)rP?^ zY^6><3yOL^^;<(j5{SN<+h0?KI#TbzP_)HfY+=hx-W*uz(oL{1lppqqVPfCuOoBV% z6Eal1B%WcEeXOA}dV_9@h}=st1#<5$nA{bYXB;UQ91K@@cX`MTFT1J4=zsq}N2`2S zXVt$%78e?OPQuqSrzt6l;M~{u#O`CE*-p+*j5bme5)z_PJPkhKuuoJa7Sa}<@XUa3 z3DBtjs)Du0V{h*pgnTf=3iy7ri5OXJsnKH7YQ69VIk}VWv+xiZ0uSC=S|8lUe8I4$ z$N45*@8oG@9!)b&Ofu(vaR%OD)h84PBfa&Ny=LuIZtdYAx4O9mJzM8m};!NLLzqoTgPgPuhUj9CAdryC%dM1pC1Fe24q z(0*?S5D(9|8)8-7SU5Yy_vpTrf0^}+YfFY&<} zen-q_VSs1N8AW0VMJs?HQwzi&C{Own4PFZv#{k=t2~1>dX9I+vgd-&V&Zu`KCWxda7;*!MqhtHnMJM$?3_6QAk8bbiRG0L>n(n!EWA z0PG{=Kx$yf2@^!cid+kZ%js09UoNL6O&Jy9jl;|dYqyBgp@D_);Y>Svjqiy}oTGwnF z5fn({GJjKO-{D`!7n@FF#5=oS6~gum5+q*n{9u_Ds}TSKI68W^>1WK6G{E%(&ag3Q zxbn5~y@S8J{%rLWJ^*Mm*xNhRw+Ih2)$B;&2*!cs)42E?{(b_4`a2hUdu?zx0mfe@ z`EtAolVyAV*HjlvAcgAa(7Ve|e-;>iI=eYP2Wd$Fv;J3ga%u_?1)FT{^CsxOdl6PN zmmQA4V0`dR(Vjk+LPtY8-Tk&*pOu{KZe~_6n}SQ*<5XObjOV-)mUaFnI_v$QOAIbA z*WZTmnO;L4iS@U3y=mwPjm_V_A-cYFOG|a zBp8>*A?AHGhv41-Q`K|r-ZudKiULNSi`B+|u!s3WDi%T3)ciDTaiIfcPv0XTJS}wk zce0uSfcDYi9>Qk>GC+F=ds;&lY2c@HPHT-y5HR#`@?sC-b#yS7fjI{N2BlM+E_apf zlC!Y$uP`aBCb!~*m_epSU@Ns%2^9eI02Z@a%6EWP$G}ioQ4ytT_Bc~~Hayzbz!VL~ z@%VAztXmkYvf6^?RgHx5eNtSYFp8Au#iN{%o4FoBpKtTeZ)I53!b1Mx&>)NY^)~_k}5JkIH~~Z z_0toytgI{uMrroBO9oLcn|WY&7TM7{1*}9=;&Q@{KFem=Y1MioF|AQzsgZDJR zkPEsUdTixyc}LZ2NMt>}MG_2YWWG)JS`m#F#4poLvsAgbzTJB9JMKqav$;aU01SVd?llE3m5^ zEjJ&OR%-Y?o(TID<2{RWc+ydI~&LDJ9TUf~OL zz+0lASAT6*;PyO>wafw8zzm0v$8^2*3t*Hm@bLT^837;SIM6kopCR>#a|#GT`F;>4 z8=Rt>fK;0%fB#XyR=V!Tm4nREZ@p$?tA6xr*pJ7!?8#v0(I*Y|;6x$fWn??M2M}0r z01yyp2T-~?^9f=hA%6uOcB_pWLlIBw;6k;MyUvR89&>i%q|>`*CZo{z4l2$}@AN5| zbg%-&6VoU(*mcfo9tYkkc7NrtmQf8=hT0tFr?TtYDl;Dau<@EibiSjrxw8Z4o51EF z!H5H{t}cC|q?8mc78WS1-#`F1RD=DR0*++#*YDp|?kL`ZBjXJ~3j1Hp%&D&mKy~Yt zoE-9tVvA0H#$g#m4_o&3Hn4Al3we0(^bZ)GIJH91sXz)nma{f4zcMg98SxXWzMQ+% za`zS1>a6I5fv{Qg^V#QP-|9z%2|(MftpXyU?Lo24&LSl%m@v`YIp% z@@#W;j&<$Xgx&=BhT!iUB zTw@mG3|JM&`0wby+y6EH?0v}XoOhhglwtNaB_nko1+lw3x-yNa(EBdMuSJmxSjAKp zE3L=2PTPUq=5|?Gs~XXGJ*G@LehiCEa2$>(zhgzmMU=75P}!ou8^}{B&S;;?7@?6w zW?pQyPbvvmX>rp%jvqk%o&Z6bJfcpoj^ZBiKeP)-j*~T4TnJX?6Rw!cO*U8~DoL($ zOC~z4uTmr2EvfXCRTxoov2`1=mU2v`b*bpg?(nJ*9MIBBA)HGS&z2rBYhm zSeDCO&eyu!EvTMIYS*MHC zhVBA4KO2Cgjab?J$+>Iy_IgXhmSAW1Gx^JO7~QLErIh%UOrNGm(@LdeTEkJdk{>8Y zB1^U_S(>7j(-dR%5tvTx)RBSdED;PoiM_=LFnlTDOD+AZ$a2b?&Dxj@DdchNPQ-$S ziyW?){OvtvV$3sQ%eE4zp2JE1Fd_c}x+rKt1H5}FSihKjc?Pi6WYcee@`pLi&8f{0 zq(QabV;&d?uVW@s(1&gEhe8w{?2@kW)@gJ>oHT```Yb+19){z^8EY^_^@DLY`g2aZ z+%;YK?ldWOr`$$xV(4}7oRacsHJ+`M=^84P9<-tK}VEU+r_G5 zaHJR?9n}MvbzoArZZf$Fl!@L)Q zz1238n2kxR@J>)w#fR5IF5>zT(AG}&QAFCpmK0(%fhB(eXWjZA>>~62@=xZmDkgT# zTbq=)tPr$Q;$u8$^S~-(2sVi_nHa&RS19A{dKd`vuvu!smR{*Er{Sq5vOC!gXG@aJ z2l_JMLJG%Bn77FIu}NTR{%0tcNQ zISUm7S$$~gRIpCDL7jy%h~E=@x>RKj(RDS^PP(8a0B67WcuWXT#eV+vy^iCk7PmAQ zBx{)ggEcVUF9HnH#mE3bKJ`qmYP=2sW+X%jwQbk2EQ^Q}=%Qh2;^QhyL+@e)26Z$`PgVuhfJbHNZ0 zj6kf}6<|1C&^>+yI&HQR2qj35kL=$707wvRmc!dp?RxM^BWwlbaC0-5C3*lCQwKj! zWsmRVVg?=#xivR6>8Z7 zK?4AlL(FNlIS`WuU_BOIZ>)Hh8i;D$aN%K|KBi*XiO{{zv&PGz##Cl6!(N%q%^kaS zk2im~hI!T*u_ZeDW222DTNsCZrXpWf3T+^7W^0aFA|qVxtUCvVv^*AKMmu>$!D4=! z>d2?HbLfVd4+KW02Tt_S9)4BvY$dJPkD{VIpithP$Xo*~$KU2*tjM`)^n{#Nmji_M zjQTBVj5t#q?Ev#5=zE`H*E9UN20ZtgTU(JZYinviP;A$Y-VF|NIGQLe!$EU@qaL59 z^|_k0d!X=dI1`&{U3Q>-!zst_kw!Ko(W&U^l}(f{Py#XOm%f@h43o_VGzY5neRJ)L zoF|>-Qd!QyeFS|aJ-uj@qT(JL4^9N687E-Em4mU&U{DdHO{&1MOivhgQ$LdkE{siR zG>0H#AID|`()%`O0Avv8VDo@fP5>SPV@!xpe8Fptg9+rxBcLAL-Pp*{D78!lX=dj@ zuL3y+pN$zn&Y__HbK7h+C6I@ZkZo)=>;b43@KkXzF&{c#d@=Cmd4a%Owo#u>uZv5A zRuVK!!YvZ&f+7s6l3B#<5fW}AHa&hreO2)r-v-Cvc)yjK-)8c=C;{1zjG38pR!1aL zswLA{-CJ=i)2)q#J|f*Wkx{$$Z%rO)nPwbNo1GYoW=JszYf^5jM)IfKRP(q@hOmks zD>uYt%9x0FLVBW#MUNa>iqA= zJ0zg+>T7A?VPI?=9RXajBj7zV>2jScUNNjWuju~9pu>t>Y4z8y-}eTGY%rS#h^LKU zbl|m5_ICi`^#NFPaQY%!!w4N1NO3Cf}m(#Jv)iHLQ-by=od8nxa7J=!W@BbQ` z$+zdtw!Fg8Nr>1H_QQP@=9u*fCx0jgC=Wh4>2#XN`1CgGd4gv{%0Pk(J|G(Bpuopac zmiI zwGoYkIa1h3Xi>D0a85$sS7T?>)X}X>U1778@;FDqBN<1dB#WDNkO%7^#K)^wJ?f(^ z;C%kkvUEZOKoRKV!Y{jafjnvfeEG{R*{+l8FQ z_q7-KDwduUU`dzGAnU3moILN2nB^dG+pq9DQLY2xvi?(~7pKQ4Yc%XpN156nDYzxv zJZ^<4@WBZ_M*4Nto?_%8a6)s4a*(3$MA*ISV4N(=R8sQd6`#2-uk$n6QP^doI*dM@ zMp8}v7nQQ4&i>4a8zC*cxrksM_CeyK6aIT`muGP=pJ-N5&Esz-5(je}R!a?*ViPp+ zg*()RI@P7FA^Yzo3^unuKh-|}I{T4b$qy4(@imi>!^6g8do$X76$o4YmZ{9_qOwL< zutRiN>s=??ZBJft*Tl60HxG`z^xT?`A|iqPm^aCB`*<)w_}dIhLx*=IKt*+5L1h84 zBm^MW?9->xt}YGWDV33-b1(Q>pLd1wj~6PZV6huG2f+&Gx0wgo42F9kQS;H$xwht~ zvu=;FiH=4T_m%F1mDHrb~hbTig)mIgwu^dl1@cg zr2Zqx=dl7A$H#zs7J?7(zb-;;96Z{&1zA~dfwu0UB`9lPn#aN&>CG+tSx)Aiu=3%m zkgUtb-zlva&YlIbj=;dT@a#Mg5TpL8>tRLNf=2dp_|uD&WkR- ztx4%I=H~fY^ID0uf#I9tbM&uiY2NEScSA#SC2eL<+1tN{hiC5{_5j&1Ci)!)I=bWb z=)zRtL~vLbASV_S7V2v1p#GU02WgccSFB$yBGn23Y`d4&*Uvy5e15zz_VIZP`28D5 z7(yOj`&b!Adcb!B=Vw@07>UqNhr{_ZkYQI;R0IUKio;rS(@9V*qP)WsH0~Q39o>Of zhF9L(!w1Cx9tSNs+4|<$Kbq0+h(bP^t`d@hdg#&B+WAU6LNK*y&{cUnHa*|N8&ctd zfoP?B@OK-Ge_8pu%zW01*p@Z)vT3k9FIG9YmaV9kW&E*T!6y@?eNQHOyDuz*0c`F(Ujvt2PD02lj{ z^XcgOcZ@{Y{vYH4;)>rZ>+@$vbZ#J{19BjstKcbJ9Jg0YUYcCud<^LmHOA!UO#jFD znJ4Uz{s!B@)l`0UhNiy#nU_Khb`XNis`9(HHzRWr9bR2-zc+!}?>Q+WqmVN%26>vL zLu(&I8hT&96Wsd0_o3+3;=cm*ZalLy3jhw6=aMDmHTX6295IDP-kL6T2pBD1{_vW> z7J;wOYd$|4%mmrR@MvXv)yoSDmiL$VO_yqM;6cxjI1IEFsIExt5s(QB@=Fl%!fQ*x+Kr&)SQ z3!`{*sazXwim&IDx;>`b`1Wv#x!N1@6e~qdi7Ifzkd_CQYR;B$%f+VZX)$p`y`e@a zxj6Dn39gqFtlo51BdD8K{wSEveN8OLG>iwA)bDCWR&WPckU_@fe2eQRAm0JZ_Yw#W zGXPfdd~iDp3Zm%LTk(M8`e*f=u&@UZ2?<2e#hNV!@Rg>%&gYg7z~BseA^_zJlsWaI zBQ*HX4{=!f8r413| z5^HOn$=@?F9suPTB#OO;lOHq?VO$rNKG-T{KwsM{Q3af{Dwzky@ZBsmm+u(ZAHJv% zc^b%l@VRvW#r(<&r+0nf#~+6PdwGBP0|3dr4$2!t{I!$*5A88r-GBt#P0d6iOPaSC`MBHFR{5Fe8`~U1{8L%2ok(7R~hHZvlRu?w^LLdy=1yKbEOjw8SQD54$ zM<=fXfDYIX`dEw&_Qa&3u_0Znu*kyDO`@~De`cHPY8ve2Gj2*iPilc%swf;d8Y;A^ zgI?}|R7fU94#FHDNCEQ-pnh=yv^K8Opvl4L^XEnG2E*G!*oGK5&y6KuEG`t z-4l%WUQ1+oLjo+$p7S+l@df2beXCZV*jOPNP7hgRjIw(Meo4~ffLY?-92qyF-wchR zkMr$e@^*(sZvM^X8m8T9fbK_War{*}Xv<;xM;-G*5+YylM7g}6L3dYh1 zxGhJiTAG`2a9_X4bHd6~`CD2k!wtdO*i5|^v%3qucM4EXB#G)2 z%IY!*YGa}k1)mlZ2gm4=ZUYD|AIB<=CJ#^j@am9RJ^f<;$$Ir|AbE3Vt=KU4nvj#r zC1I)WDttHEjB8&updC!76eIQrgYb?7skm{XCY#=$$CKAqUnC`xpWT`-PmdHk!`)n6 zCE%5@B&IkZmOr-nU3URZ-cA+XPiSek+G{|UT?&-)slJLZQy^la7sT@f(}7bOAS^q- z;%B_Bh707={Ow;*!BFxHek2{5+V7$@*>pK@FmbVMedr~mpd5saxUH70&t!D5veA0zXx^u>$z%E zaQ>@RtH*Qns4$3>9BBcKY3kSRGz5OK5qZ7b{lB?zJNi#;MYpa$s4wu zw!EVFMVfT|T z>QX?73$hr%d{P(e#mslOH#bB=f-O>U$9{g#h#?z*zXw7wXJ*TnKF}%0_iz6HYqOPB zT_sPvg{;;1&!qTY8=p;$e#XA@2%pa_UBgRjz6+=^E(f!&qbYwFM@G}QD|<>-fr|v_ zmEz*a`@gfFKw3%YTOun;XCM%}9WU1d849!t-@Lg2K~L@$7Fzko!NRnrx2HwcbI)l! z&Ke_0fbbBKA?VA?#g*h90?a9Yy1#@Oo0xq0@&JA*0Z?&(VxN%1;*-AR)90<>N*qS5 ztQ!)woB|zDJ-tH!U_>FBUIDlG(}M|!bPyAJ6CC>X0}$#zeq`*-EWgi#VTvxb1ie-8 z$OcoIpvBb+go{i8Z#N)Xf?sAEv_NqvEdS)dQKbkMqzz>t6rz#!G! z{;{Kx$jsrTXzqo;`Y&9pS&unU7C=|5>b?Y@FN41Hxzszb#!rAQ{tVhrrET6YLCtDY z3!cFxAw|C!4GJjUBB(2<7s~`}hxaC*CwjV?bfbqg|0-6bR%~P%^?v^-U*6OXJXD9_ zMrKUE5o%8I_1HSw6f8v_ce?sX`+9V~ICAsi#;5-ch#^Pt5KBCTg7#B~cbOzm(*0X!A+3iGR5#+_NBDG+SCu zZe(PHqJ!Ku!3(=DREdQ2^7^~wlpF6P zrmgC=7`G)JVLNS%C0PwYqaHY@AYR}gA&K8!54=&U|h5&`JPxRc!h*xm9R=PNlSqOA2g$gT3P4%7{v76eUki1hNit z9Ft|uzW1E!B+GYOv&RzHVjsWV_v^+N>a-%k1aaY+d?Ep$8{|ELFGasx&?Iz6u;`eX z;jXJqO$%RDXEfEkmRH+0SwVO|9-9PxZh;ll>m+DEOOXZTtvyf499B2p;6TR9gA@Hu z4|qqG9I+g_eN7~9>5nopzO;uIOk3%dDJ@ASD2uhi!Esg2D$H{KUsYXoT+?6op9qSe zbV+Wx=AoZf#(xyG$jS7Ksf%*<_ct5i-v)24l((K#`msbd^jG z3)NP~4OVYOR1~%wSd3x87WmP!v9M=V6U5zndO*RJo_V2GU{K>csR~8$LL#VOToF`} zRH(be_jT`cl5sxw@HqOlQ4Poe{iPiBP*DSBfCOTvsCqr_-$4W#+((`ai0`laUGB9l zk7J81^;bf^ap4)C zKNKKJq2V`nvbQH3AJN$C|4k8P!K<7RRAY5^_8kXi9OEto^M{;_8XcM4A@Y1hZW1}f z7^6ZXsy!+pNHbzSW+QBJSqab3B<9g?&9E3A&KP-nPls(rL1!pso!9YgZN(GIvdn)m z;-K>VtG}zo)nm2DMwpE6*K&H@oN%;0kTyFybTApBd;38K*}+t@UsY`j_b}w6qbX4l zNI`T$E7iciOUpSz3PCI+71xoD`Fi3y2^4iF{$Bo-2<5O!HCHopbG`rfGjGrRi-&IA zHsZUV3xO@|_f72R&gTVaQy0)Yi(~us>#N`9eeJYZDufDj$C!49NaXMk7?5X^NVG&D z61JihsdhIdBk#79j&)shBHNs|x&OD5SPKdC^^SLDu%RF%ePas36d3*aLQ>>ih&3)9 z=o8)9Akw9W3ry1 zfibu6TO6DOWWkjGh*PkQYpYL=LZ~?DRlLHtIxl^iD&(YF^;-K|N17&3|7Su z1sbNIasN-?_s+&5TgatCh$E}(EUs^G<&7E1lkulmjRMsgLD)zbB#zt|n+fk#vP zT;AAN+t^@`%^BKAsvpW|JnqiM8!cqgkP>6O2{c&0AGEzkAP^A|#4ZQXIgF@6*;b$< zX>aR=T>_@&9{}P~HqH@liAXOEZ=AxWY4$P@Tm*S% z=p0u2>+;_ppU-e+Sx3UWmO^9xIgnRI`{D%l9@3;9&DDZLqg6C7eEde;`mU!8fzfC~rZrbJJX z%?G2hv&U(t4+2iT_p_+MI70zo5i51lLx2wZ{IB&7fGTC;4o8|+3LqXWyP*0Dph)!Z zos-Q4KVVinH<%g@X!26)LGxAK({R!g6_$6-VXurk#)6ZO zbq7(gp)*!*dTR1RtH7;@OIFSPm|B%ZKuo;2w6nN&A)uge@Q;4_+GiIVkH<&vXh^yQ zZlj!Hg>=zcu756GzfXAJ<})gH1=|Q$Drj56-zW0EXS_{) z8J*;1R$V2AUsg0f#8})0AZyM4B7i$Vr~;tKFvW5H zj0B4^2XhCwP!R6wx=DsTf`iGJRTvs|=6^IOuXxaxncaK=KbamI6^ktUIb zlLYmil$ytnwpi7Qx~{=kpt4h-y<%!$9>z_5IZO@O8<3@rR1r*Ir{jlVBlPL5wH1*VwT{1HwmOJL_X zXgw3J{ZwWusb4at*=&rP&EmL0KaKU43~h8=lq;L15UIp~{nGh`uWxeSD!2y+X#nm9OAjYE-Rdf@Z#ZUjX80^gskcM2sknO}#If4h3!z zQhtX_6~<6MZ$CjJUMFfI>v?nYVCEj+UuCMLA4XM`q-N#Ba3AOgAd!$nWFyxT1Py08 zI2ZtcQ|D4_{Y=g);QV+qBqYA(TejkW7cQHUu4ex45HU@P zZ64Ji&nMr9*L>UygfP40lZ@9ymMKB3ujCLbGyg43P#kNlo+$I32?)6$XDPXXqUy61 zhJPpx52q;rz>}F2znY|(S#?O5GM#k`1S(o)Brc&0vF4)Jblu*wY{+rcfHH_P0a#~; zZ8Vvg>-TNiX!k%PI3I&8)0{&<1>qv`D0;QK>n8c}BSQ)4<2G)wMN%L;1#z`CwEVJmzQXTf+e~K2Pe)Q9^Rrtrve*XR1`(xKg@r(CMh90nX=dy z%Td5sWL$3*;YB4mey!^b2i|nWI!%iK1Xh6nPFE1Rcpu<(%I1ZY?}0?6m!8B$cTzeX zhG-;BE_Fa5p2=S&yquTpwpMRdefqv;DJw^e9(S`45`N+1r%H$DK=qfN$F2L9U1pY< z(xAR2DoCVK=^SU$A}}n0awNMXGo{YlXP&)I*MmelrK21*xT#}QzP+P~VU#jRGsjf!$|(jZRZN(p)1_taKK{Ll93 z=3fYl%Drwm_`97sbyM&Jrgch?MD);bv(=ClyqjNh{%8BusM6DreGociZ;wpKvO(V0 z^kAlyn5dQXU+C)-K=$bA2`B-ZKtyeDx%LF$jZ#84AksI90aSgiS?P|VqN0S)eGnYw zVKhZ&N5{KhAM6cqNe_>pk@j(2+5Nfj4V#=B5Z(G?c@?Es5}WLtoZgxWyFWsQa^$8)x)#t-$FnQ+4e%yvsz9$iqlS$_b6`?; z(xH&w+tQjKk{EEKIGlyEudLFGT=)Lj@_A?e_3`zjI|*|QcJP%g4=_LA8*?H5JgR=2 zeUd~AP5|~t<&suHR`tHKmJr9u!(@f#i{YkV{-$50X|zo^_vP;FpsgR)@UyjzBSvkj z1Kb*dla`!}Z1#%_peCJ4oys#jItQ+s{s0yg1k4T-J0!V8guVdqK?0?2={&hI$!}n1 ziW}}b>1{Y%c3$3eUmj^`?Ox!$^)c9Xd*?hf@aTwZ(tq;B`B`w5w_jKN=gIFf^(8J} zbco7r<><%^9w-~!rlZ#7#M0|Us1y)U^CJ3G&o7nDkaJT#B_*3{B{{!L>YfNGL8~~S z3$-&MT+QWT;@R+199e1JS;CA%_Z$Y#XEH5zK~%sdE5^gYlapWljt4=5`!0uCBC(|& zuH~$9hZhGf(jMlaOV2n$gX~UD%P2kOt>nDD7RUaqod=EHTW?&mXUHG@$9*204Jw`N zB0=Wl$&3gq%#_ZBv3sc#H-bu@l zRTtr>W}D>2p_}?oFHW*AoX3)ZlgTkW^vq$rFF9F!;dCuKWb5O+uY?Jb4FdUrIPQ;J zH=1-8SmoI}n85#Yw!ZeE&;m6r-g@_&ds^}FSa!&-e)IJ7nBuj}^TydDrP{`n{PdUW zjnbmD$#WU#qrrQODjB2tMUMqDWQ3ptYv(gFwdCbTC+8lD_{q?HN~_=#I3r^>lM4|9 za;QUkhcBV%KqlYvxZ_jP?`wCyzvQNkgPI7f8!=>`|J;hoH&#m>%zvJ zM6XpN5LU8(R!->YCwup+9iHw4z4Usp(=j@BjlMhgTY7 zr-&ebKR(B(@t6nWHfK(w0(hVd;c7!UEbGCQm3M}`-tN@0W^?Dxe}(V1?(}-D^?#FY zy67dmcXX~oAoYbhtBDC%k_w(XOt77~M*Iv52ERX#HxKkwQrFuJ`W0HRIaY!wEt`Lw zq+;+eOKumYVwiQZQp7UwjPG4-oxG3A>P0j>^psWe>Q34?`~p4$gB;RWZKQeTD;E0k zcq>YZifZBnu%r$3rwIsR+FkpSsYlx9shdn5BoBNb5b|^a7T|M}i$6Q-!eL3eHJy`G zItQ+Yc42<1XF~d8chZ=XxSPbs?uH|8?;F%7BUhEutmIe6+-f)q;|q(chXeM`O|;WL zZc&yu9(7Hx7U^Uw?!VeMS)W<5U z?kbV4ZAiZnbUxRuoE1`p6ULwRD=ETvy@kuq|IE+Ab=b3i$PYZ~e%iFhLPP2+BY&(h z6p?o<8mT2gA2V9juPV6SXLaFwO^MesRit6rdh;Z8Gd!lZG-#S4h3fe8<4NMYo~0O{ zlge(ZfDH^>DJaxtaiy&-rn6Ijf1iA?j$1uw$&@nG#@$^<V zE0?X4g)d2ByjX6&03^#MY3BDXK_HM{&DT`l4&i2mLx3a8UP)25BsqLXUZk2zd0K;` zUu8TEq4wkjO?F%AivJzk?b$^whD?Qmeqt0>Ja`m( ze1h@l%8k`gQ8{N?FIc5aOVhVF&1AGPwG45E!iYg;`+o!ynyPg>v#jX|M0kT1wVv*% zFCYOzp&%|7ltil~6-)T^(ub3HciuIjdQ!L3@5~&?YY0RRg+`~ZFD7cgX?kr$y^A{y zaIoQ=zj#7O3*13kp@kRf%0v|od6!v1^r}5jV zd~u&i3RDlUzgh)uOH%uvZisg?t{oOS5(?@PM>;+CK=lBr3-AL~U%#GC%uYU%tg;S0 zKm3sO(T|!?&ZDa8n>EbwU7biqc)%N(hC;=j!X~@l3sYC!i@H?~F1)L!KDe_27W2az zB%x4wKKo%pSBa3!s=Vd?Q)c868XNxNxk*alvVbWiNMLmY3CXLSz;%4*v93shU!b?$ z$ykjhVVLC6Zm6E>r-KWCYp^Tcg_1*YE}O{ay+EIo6#E1A{#G3kNeVN?`z^@IT{wT_OG2Jz@+wwzO>qbh^RI-^m z3zza%{N3%<-yziM=M$tQtBo**xH2?i9@Z@JYo zywRJDZ`5-hlX9{zXK23TRG2_tjzz{LKvr}gMM>N-hwO!fg;1w&Xvi4q zS02l+0w(2?XAEsJ2Qvz#E%8s|72msP?~>3`)6ys1^pEcEU%K@Q)$)0JlGk3)@P@rT z9~9Mj&yGx-?GH?kem$t4b5O4ONn->;X1z)PIY4J3mA{{Sq{vS7QD#s6@zwO?Dgke< zrC4vFp?xOZu{s%{f*DOhr7Z>xla=FrJJcsVx`T2&{`5>2yY9Y=%t8P8AVCgA>vZ<_ z8)O!fTysWm_Jfi;ZBFp(2W~?QqZ02%f0fV}R*K*mr&^$OS>(cFshQ1Fq zchsj}^Y@8~?yHN*)Xd+D=bCv)`l7by2h5hIyvcj{dh?&h8V#Cpx3NlMgocY~k#_En zmR({=M?1^+UDO+2gvA zRAjWF(qFev`t-Y*N1gTSxJ2(v{q@a~Ts$^j$;#Sdm@L_Gsr;t!&Bsj3)quW|p)?BNUmjpL zUY|R&&Fe7ELffuB&7&Fcy|!#2(`NOZAX2KTVb;R4zupB`Q#r&On(c2@6J5M-ztqTY zB`d!F{Y|w-SF7$SzCGeUzpjjUsEtf7AI&1oWtO8V!92BjcAz${jCfpF=DPf3{Iq&E zcib|b5~!6_{}i{bpP}_WxBt!0s&bb);4}SozvgvRj6#{w&XS(&@Ai-s8@Tj*s|mWC zxk#w7eFF1AF|8ooleG10yL}Xo)F|{(v54b7qZCk^W->feW z8yZS(ZKTul{G&@v-fC;i8*ts^pkmH>;IiRtbV)INJ6lb2{nN*RT61}PcH-)3ma%zX z2gD8EqP>rD;ZNzCKC_+e{k+EgSxQ?Wa62w-gF=Ii@e^Wz@x{$p=SZ@3b9UuliS*4P ztG^!G+nQ?4jEP$rjSFLhQ~ICCJrr=rx>|%b)3NtWr0F>%EbyGZe82<4#v!1PEOo=b z9Qwe(qLlQj^If%HJO&LLAbl7=&z*-DORI7VETSZ2tFCT{nqprnIO} z2SzUHym~s*C0bjvm~U}9)P}Ufhw6Dp@Skbd(7P?pnrXegj#Jy)6O(kK`ZGJC<%;Qc zjt1X0{n`tmKlvAj6a38LVn<$CRUcMqMQwIyb;clG3frTZSstD$l7ABQLZD4uqiLy= ztlynxz1lFmjF4sQzv6|s(Xe`TvQ*;7b>{28=?QY=r(Px1UK3f7e*E|-O7CZeBkLoY z{NivI(p*;#k?LCyK*0ykQ#XZRT!^ikN0ylLzFK-={*+NB(JQmg1I%2QN!+E9X8&CH z`fp^M>6oobF1(`eil1Y!&a9xY%+#dYtls$9P`pXo#b~z-25%Q!6@hj`YpJ}(7&^jr zsrf$+YN<46kmf4NO-u+oj0jwLmk9$xo07vXec%GC2?SN{hdawgW2epxTxjM%BR6J$ z+-YKBV*_WHLPg!Q&gk1v!ziD3W+s+F4hIw5NP?LB@jLKnW_z`p@zFLL4J@nC>tgfc zF7Eh%<>SX~b%yI8N6TVO-E;^p{^)zq7OwBZV7#oVU?|*kt4nq3>{EG&=e}i;_%p7* zmmsO-0+fSAckbAi6n&uz1uZb$;s9f6b_IBB&D(HwwXICI&@eF2D;A1UKG* zYp+Cbq1%v!E(9SMFoJjw;zBf&*fTxd(_LL%Kj$15Gqe|wZ}aUQ-uHnQUhtypuRi_k z%ZKmYzWrgA+ukM#B7!Iu;2h3-l!|FrEvwC#{Pg1w4E_pT8$D35m5x z8FTmjk9qCp>x@H3??$pXMjMj>8Gr;ZMpZIa^6v3{?i?L63_Zbnl#~b&({?RdO2)zA z-9(n<3Z*K>5dn~ma7$u^_ob;WY*%{gtaLuG4-xOmX@WIiaawYqiEX=`%Obt z6}ZW<*=`5|>bk;B4r3HHNvrj8eg(+$Vow`QQ>R36Kx;{1H9`tRB*;fg1eBSj?FMX? zlBRjHt5EN~v>yqW%@&CWqn);F{Y^j**V-=~}hPXI(D0Ek6|hy_Y& zR4frV$}<07;^ad0?bqKhpPf array('posixAccount'), 'conflicts' => array()); + // managed object classes + $return['objectClasses'] = array('systemQuotas'); + // managed attributes + $return['attributes'] = array('quota'); + // help Entries + $return['help'] = array( + 'quota' => array( + "Headline" => _("Quota"), + "Text" => _("Please enter the quota settings for this user. The syntax is: {mount point},{soft block limit},{hard block limit},{soft inode limit},{hard inode limit}.") + . ' ' . _('Multiple values are separated by semicolon.') + ) + ); + // profile elements + $profileContainer = new htmlTable(); + $profileContainer->addElement(new htmlTableExtendedInputField(_('Quota'), 'systemQuotas_quota', null, 'quota')); + $return['profile_options'] = $profileContainer; + // upload fields + $return['upload_columns'] = array( + array( + 'name' => 'systemQuotas_quota', + 'description' => _('Quota'), + 'help' => 'quota', + 'example' => '/home/smiller,50000,60000,10000,12000', + ) + ); + // available PDF fields + $return['PDF_fields'] = array( + 'quota' => _('Quota') + ); + return $return; + } + + /** + * This function fills the $messages variable with output messages from this module. + */ + public function load_Messages() { + $this->messages['path'][0] = array('ERROR', _('Mountpoint'), _('Mountpoint contains invalid characters.')); + $this->messages['path'][1] = array('ERROR', _('Account %s:'), _('Mountpoint contains invalid characters.')); + $this->messages['softblock'][0] = array('ERROR', _('Block soft quota'), _('Block soft quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['softblock'][1] = array('ERROR', _('Account %s:'), _('Block soft quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['hardblock'][0] = array('ERROR', _('Block hard quota'), _('Block hard quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['hardblock'][1] = array('ERROR', _('Account %s:'), _('Block hard quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['softinode'][0] = array('ERROR', _('Inode soft quota'), _('Inode soft quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['softinode'][1] = array('ERROR', _('Account %s:'), _('Inode soft quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['hardinode'][0] = array('ERROR', _('Inode hard quota'), _('Inode hard quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['hardinode'][1] = array('ERROR', _('Account %s:'), _('Inode hard quota contains invalid characters. Only natural numbers are allowed.')); + $this->messages['block_cmp'][0] = array('ERROR', _('Block quota'), _('Block soft quota must be smaller than block hard quota.')); + $this->messages['block_cmp'][1] = array('ERROR', _('Account %s:'), _('Block soft quota must be smaller than block hard quota.')); + $this->messages['inode_cmp'][0] = array('ERROR', _('Inode quota'), _('Inode soft quota must be smaller than inode hard quota.')); + $this->messages['inode_cmp'][1] = array('ERROR', _('Account %s:'), _('Inode soft quota must be smaller than inode hard quota.')); + } + + /** + * Returns the HTML meta data for the main account page. + * + * @return htmlElement HTML meta data + */ + public function display_html_attributes() { + $container = new htmlTable(); + $spacer = new htmlSpacer('10px', null); + // caption + $container->addElement(new htmlOutputText(_('Mountpoint'))); + $container->addElement($spacer); + $container->addElement(new htmlOutputText(_('Soft block limit'))); + $container->addElement($spacer); + $container->addElement(new htmlOutputText(_('Hard block limit'))); + $container->addElement($spacer); + $container->addElement(new htmlOutputText(_('Soft inode limit'))); + $container->addElement($spacer); + $container->addElement(new htmlOutputText(_('Hard inode limit')), true); + // existing entries + if (isset($this->attributes['quota'][0])) { + natcasesort($this->attributes['quota']); + $this->attributes['quota'] = array_values($this->attributes['quota']); + for ($i = 0; $i < sizeof($this->attributes['quota']); $i++) { + $parts = explode(',', $this->attributes['quota'][$i]); + $container->addElement(new htmlInputField('path_' . $i, $parts[0], 20)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('softBlock_' . $i, $parts[1], 10)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('hardBlock_' . $i, $parts[2], 10)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('softInode_' . $i, $parts[3], 10)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('hardInode_' . $i, $parts[4], 10)); + $container->addElement(new htmlButton('del_' . $i, 'del.png', true), true); + } + } + // new entry + $container->addElement(new htmlInputField('path', null, 20)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('softBlock', 0, 10)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('hardBlock', 0, 10)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('softInode', 0, 10)); + $container->addElement($spacer); + $container->addElement(new htmlInputField('hardInode', 0, 10)); + $container->addElement(new htmlButton('add', 'add.png', true)); + return $container; + } + + /** + * Processes user input of the primary module page. + * It checks if all input values are correct and updates the associated LDAP attributes. + * + * @return array list of info/error messages + */ + public function process_attributes() { + $return = array(); + if (!isset($this->attributes['quota'][0])) { + $this->attributes['quota'] = array(); + } + // check existing entries + for ($i = 0; $i < sizeof($this->attributes['quota']); $i++) { + if (isset($_POST['del_' . $i])) { + unset($this->attributes['quota'][$i]); + $this->attributes['quota'] = array_values($this->attributes['quota']); + $i--; + continue; + } + $path = $_POST['path_' . $i]; + $softBlock = $_POST['softBlock_' . $i]; + if ($softBlock == '') $softBlock = '0'; + $hardBlock = $_POST['hardBlock_' . $i]; + if ($hardBlock == '') $hardBlock = '0'; + $softInode = $_POST['softInode_' . $i]; + if ($softInode == '') $softInode = '0'; + $hardInode = $_POST['hardInode_' . $i]; + if ($hardInode == '') $hardInode = '0'; + $this->attributes['quota'][$i] = $path . ',' . $softBlock . ',' . $hardBlock . ',' . + $softInode . ',' . $hardInode; + $return = array_merge($return, $this->checkQuota($path, $softBlock, $hardBlock, $softInode, $hardInode)); + } + // check for new entry + if (isset($_POST['add'])) { + $path = $_POST['path']; + $softBlock = $_POST['softBlock']; + if ($softBlock == '') $softBlock = '0'; + $hardBlock = $_POST['hardBlock']; + if ($hardBlock == '') $hardBlock = '0'; + $softInode = $_POST['softInode']; + if ($softInode == '') $softInode = '0'; + $hardInode = $_POST['hardInode']; + if ($hardInode == '') $hardInode = '0'; + $this->attributes['quota'][] = $path . ',' . $softBlock . ',' . $hardBlock . ',' . + $softInode . ',' . $hardInode; + $return = array_merge($return, $this->checkQuota($path, $softBlock, $hardBlock, $softInode, $hardInode)); + } + $this->attributes['quota'] = array_unique($this->attributes['quota']); + return $return; + } + + /** + * Checks if the quota parameters are valid. + * + * @param String $path mountpoint + * @param int $softBlock soft block limit + * @param int $hardBlock hard block limit + * @param int $softInode soft inode limit + * @param int $hardInode hard inode limit + * @param boolean $uploadIndex position is upload table + * @return array array where error messages are returned + */ + private function checkQuota($path, $softBlock, $hardBlock, $softInode, $hardInode, $uploadIndex = null) { + $return = array(); + if (!get_preg($path, 'filePath')) { + if ($uploadIndex == null) { + $return[] = $this->messages['path'][0]; + } + else { + $error = $this->messages['path'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + if (!get_preg($softBlock, 'digit')) { + if ($uploadIndex == null) { + $return[] = $this->messages['softblock'][0]; + } + else { + $error = $this->messages['softblock'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + if (!get_preg($hardBlock, 'digit')) { + if ($uploadIndex == null) { + $return[] = $this->messages['hardblock'][0]; + } + else { + $error = $this->messages['hardblock'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + if (!get_preg($softInode, 'digit')) { + if ($uploadIndex == null) { + $return[] = $this->messages['softinode'][0]; + } + else { + $error = $this->messages['softinode'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + if (!get_preg($hardInode, 'digit')) { + if ($uploadIndex == null) { + $return[] = $this->messages['hardinode'][0]; + } + else { + $error = $this->messages['hardinode'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + if ($softBlock > $hardBlock) { + if ($uploadIndex == null) { + $return[] = $this->messages['block_cmp'][0]; + } + else { + $error = $this->messages['block_cmp'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + if ($softInode > $hardInode) { + if ($uploadIndex == null) { + $return[] = $this->messages['inode_cmp'][0]; + } + else { + $error = $this->messages['inode_cmp'][1]; + $error[] = array($uploadIndex); + $return[] = $error; + } + } + return $return; + } + + /** + * Checks input values of account profiles. + * + * @param array $options a hash array (name => value) containing the options + * @return array list of error messages (array(type, title, text)) to generate StatusMessages, if any + */ + function check_profileOptions($options) { + $messages = parent::check_profileOptions($options); + $quotas = explode(';', $options['systemQuotas_quota'][0]); + for ($q = 0; $q < sizeof($quotas); $q++) { + $parts = explode(',', $quotas[$q]); + $messages = array_merge($messages, $this->checkQuota($parts[0], $parts[1], $parts[2], $parts[3], $parts[4])); + } + return $messages; + } + + /** + * Loads the values of an account profile into internal variables. + * + * @param array $profile hash array with profile values (identifier => value) + */ + function load_profile($profile) { + // profile mappings in meta data + parent::load_profile($profile); + if (isset($profile['systemQuotas_quota'][0]) && ($profile['systemQuotas_quota'][0] != '')) { + $this->attributes['quota'] = explode(';', $profile['systemQuotas_quota'][0]); + } + } + + /** + * In this function the LDAP account is built up. + * + * @param array $rawAccounts list of hash arrays (name => value) from user input + * @param array $partialAccounts list of hash arrays (name => value) which are later added to LDAP + * @param array $ids list of IDs for column position (e.g. "posixAccount_uid" => 5) + * @param array $selectedModules list of selected account modules + * @return array list of error messages if any + */ + public function build_uploadAccounts($rawAccounts, $ids, &$partialAccounts, $selectedModules) { + $messages = array(); + for ($i = 0; $i < sizeof($rawAccounts); $i++) { + // add object class + if (!in_array('systemQuotas', $partialAccounts[$i]['objectClass'])) $partialAccounts[$i]['objectClass'][] = 'systemQuotas'; + // add quota + if (isset($rawAccounts[$i][$ids['systemQuotas_quota']]) && ($rawAccounts[$i][$ids['systemQuotas_quota']] != '')) { + $quotas = explode(';', $rawAccounts[$i][$ids['systemQuotas_quota']]); + for ($q = 0; $q < sizeof($quotas); $q++) { + $parts = explode(',', $quotas[$q]); + $messages = array_merge($messages, $this->checkQuota($parts[0], $parts[1], $parts[2], $parts[3], $parts[4], $i)); + $partialAccounts[$i]['quota'][] = $quotas[$q]; + } + } + } + return $messages; + } + + /** + * Returns a list of PDF entries + */ + public function get_pdfEntries() { + $return = array(); + if (isset($this->attributes['quota'][0])) { + $quotas[] = '' . + '' . _('Mountpoint') . '' . + '' . _('Soft block') . '' . + '' . _('Hard block') . '' . + '' . _('Soft inode') . '' . + '' . _('Hard inode') . ''; + for ($i = 0; $i < sizeof($this->attributes['quota']); $i++) { + $parts = explode(',', $this->attributes['quota'][$i]); + $quotas[] = '' . + '' . $parts[0] . '' . + '' . $parts[1] . '' . + '' . $parts[2] . '' . + '' . $parts[3] . '' . + '' . $parts[4] . ''; + } + $return['systemQuotas_quota'] = $quotas; + } + return $return; + } + +} + + +?>