www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - 4x speedup of recursive rmdir in std.file

reply Jay Norwood <jayn prismnet.com> writes:
It would be good if the std.file operations used the D multi-
thread features, since you've done such a nice job of making them
easy.   I hacked up your std.file recursive remove and got a 4x
speed-up on a win7 system with corei7 using the examples from the
D programming language book.  Code is below with a hard-coded file
I was using for test.  I'm just learning this, so I know you can
do better ...

Delete time dropped from 1minute 5 secs to less than 15 secs.
This was on an ssd drive.

module main;

import std.stdio;
import std.file;
import std.datetime;
import std.concurrency;
const int THREADS = 16;
int main(string[] argv)
{
   writeln("removing H:/pa10_120130/xx8");
	auto st1 = Clock.currTime(); //Current time in local time.
	rmdirRecurse2("H:/pa10_120130/xx8");
 	auto st2 = Clock.currTime(); //Current time in local time.
	auto dif = st2  - st1 ;
	auto ts= dif.toString();
	writeln("time:");
	writeln(ts);
	writeln("finished !");
   return 0;
}
void rmdirRecurse2(in char[] pathname){
    DirEntry de = dirEntry(pathname);
    rmdirRecurse2(de);
}
void rmdirRecurse2(ref DirEntry de){
	if(!de.isDir)
		throw new FileException( de.name, " is not a
directory");
	if(de.isSymlink())
		remove(de.name);
	else    {
		Tid tid[THREADS];
		int i=0;
        for(;i<THREADS;i++){
			tid[i]= spawn(&fileRemover);
		}
		Tid tidd = spawn(&dirRemover);

		// all children, recursively depth-first
	    i=0;
		foreach(DirEntry e; dirEntries(de.name,
SpanMode.depth, false))        {
			string nm = e.name;
            attrIsDir(e.linkAttributes) ? tidd.send(nm)  : tid
[i].send(nm),i=(i+1)%THREADS;
		}

        // wait for the THREADS threads to complete their file
removes and acknowledge
		// receipt of the tid
		for (i=0;i<THREADS;i++){
			tid[i].send(thisTid);
			receiveOnly!Tid();
		}
		tidd.send(thisTid);
		receiveOnly!Tid();

		// the dir itself
		rmdir(de.name);
	}
}
	void fileRemover() {
		for(bool running=true;running;){
		receive(
				(string s) {
					remove(s);
				}, // remove the files
				(Tid x) {
					x.send(thisTid);
					running=false;

				} // this is the terminator
				);
		}
	}

	void dirRemover() {
		string[] dirs;
		for(bool running=true;running;){
			receive(
					(string s) {
						dirs~=s;
					},
					(Tid x) {
						foreach(string
d;dirs){
							rmdir(d);
						}
						x.send(thisTid);
						running = false;
					}
					);
		}
	}
Feb 04 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Jay Norwood" <jayn prismnet.com> wrote in message 
news:jgkfdf$qb5$1 digitalmars.com...
 It would be good if the std.file operations used the D multi-
 thread features, since you've done such a nice job of making them
 easy.   I hacked up your std.file recursive remove and got a 4x
 speed-up on a win7 system with corei7 using the examples from the
 D programming language book.  Code is below with a hard-coded file
 I was using for test.  I'm just learning this, so I know you can
 do better ...

 Delete time dropped from 1minute 5 secs to less than 15 secs.
 This was on an ssd drive.
Interesting. How does it perform when just running on one core?
Feb 04 2012
parent reply Jay Norwood <jayn prismnet.com> writes:
== Quote from Nick Sabalausky (a a.a)'s article
 Interesting. How does it perform when just running on one core?
The library without the threads is 1 min 5 secs for the 1.5GB directory structure with about 32k files. This is on an 510 series intel ssd. The win7 os removes it in almost exactly the same time, and you can see from their task manager it is also being done single core and only a small percentage of cpu. In contrast, all 8 threads in the task manager max out for a period when running this multi-thread remove. The regular file deletes are occurring in parallel. A single thread removes the directory structure after waiting for all the regular files to be deleted by the parallel threads. I attached a screen capture. I tried last night to do a similar thing with the unzip processing in std.zip, but the library code is written in such a way that the parallel threads would need to create the whole zip archive directory in order to process the elements. I would hope to be able to solve this problem and provide a similar 4x speedup to the unzip of, for example 7zip, which is currently also showing execution on a single thread. 7zip takes about 50 seconds to unzip this file. What is needed is probably a dumber archive element processing call that gets passed an archive element immutable structure read by the main thread. The parallel threads could then seek to the position and process just each assigned single element without loading the whole file. Also, the current design requires a memory buffer with the whole zip archive in it before it can create the archive directory. There should instead be some way of sequentially processing the file. begin 644 perf.png MB5!.1PT*& H````-24A$4 ``!+H```)'"`(````8)JC*`````7-21T(`KLX< MZ0````1G04U!``"QCPO\804```` 8TA230``>B8``("$``#Z```` . ``'4P M``#J8```.I ``!=PG+I1/```A?Y)1$%4>%[MW7O,=E]>U_>'^$<;(7(8RB%$ M'51&1D<&%)G?;V9^\_O-0(=1#G]XJN=38DF;Z-/]W/N9/?M>>^]UV,=U[?VZ M<C]7[N>ZUUY[[?=WK>_W^UG??5W71_SH*R\\\4```0000``!!!!```$$$$" M1^`+?M?O??+4`P$$$$```0000``!!!!``($> ?O[^[N[NR=-==$/` ``" M"""```((((```AT!<I%.1 `!!!!```$$$$```000&"'P2"[^S)_[._T ``" M"""```((((``` A<G$!;8"07*60$$$```0000``!!!!``(%'!-)R\7]X[>M_ MY/WO:W_>__Y7WO^^5UYYY;TOO_Q2\_/>][[GI9?>_9[WO.MW_?YON+CL=OD( M$+ X 4;(97ZL3GM3:&G[3BX6G:4]*E<NONI5K_K43_W4S_B,S_CLS_[LW_$[ M?L?G?_[G_];?^EM_\V_^S;_Q-_[&=[_[Q48ZKF[C5OZNWNWL#FL;S^P+<2`" M"""```((((``` C40Z!4_G7M(U\,V9=Y>\C%C_NXC_ND3_JD5[WQ$S_M=_Z< M+_JB+_H]O^?WO/:UK_WB+_[B+_B"+WCWNU[XGN]Y2S>(3N/U]57W>[[HRF^9 M;+E-5A=_]Q]X_?=___=_W3=^9_-^Q>8>U$_[M$_[F-_[<?_.__R)K_KSG_!Y M7_2;F +C;__MO[TM,[[K7>]L;D_-E(OYUMI.:\WK.7Y4)T2["QR^DG_M6B*` M``((((``` ,!%""R1BZ/WEW92L"_\ K/T]6& 'K/DXK=_QQL_YU?_VB_Y MDM___O>_[]N^[=M^YK_\Z)_UAH]M;DG]E%=_RB?^R*?\EM_R6S[O\S[OTU]\ MS4?^\X]IY.*;W_SF3+D8E!DC*FM8G(R7*^/M^U-M*/SZ5<>AWFOKI:-GCS?. M?5__:__EDR_[J__-^][W\G=^YW<V[UK\E$_YE(_^Z(_^A$_XA'__-_T'G_ZV MU_R"/_/O_M*O^0\_YW,^YX47_OJW?_NW!\*FKZ^2=Z6.WJJ:^>*P6;)X&&DP M>M)`"4_==]I=<J23))9165L*,$G II>3P2.```((((``` <"8"1\G%3C$& M)<HLN?C&[WSS^][WON_ZKN]JY.)W?=>;FS<N?O(G?_)'?=1'?>S'?NQK7O.: MS_RRSWKU=WQZHQ4_Z[,^ZYWO_*%GY<>'>UL#R32LVF6*P*2LBJC$T5+AJ`R; M&O-0^(V^$O09J,K^)0RQC/YU%.!4R_YEQ 7JF=:2:T$``0000``!!!!`X&0$ MCI*+BZJ+__L;W]3(Q>8NT^9;%INW)G[$1WS$S_ 9/Z-]_LB/_,A6/3;UQH__ MDZT?EX,`` ``""""`P(D)'"(7E[YWL9.++[_\TK.?][[TWO>^YZ67WOV> M][SKQ1??^>*+/]S\-$*Q^6FJB\WW,O;M%WF;WUH**B+SDMHIN%<S,MI1>1:Y M6B8_ZF:%3T9M;T9MJHO_XQ=_XP_^X`^\XQW?__:W_^6WO>W[WOK6[WW3F][T MQC>^\3N^XSO>\(8W-!^:VFC%S_^"KUI%+G;RK"L;MMV.WE\Z)?,VO1FU/Y[ MDH=S=#C"_G7EC+^K 9UU"&6MN6HE+WIQ6/P"""```((((``` B<F\`2N3CU MU8N;?^]B\\FH[WC'._J?8=,8Z9?^9__K7_I+;_OJK_[J/_HU?_SG_XK7GMML M=5X=05BG78P*`0000``!!!!``(%Y!&;?C#KZ+1I3GW%:>I;V6B:_=_%/OOX[ MOO[KO_Y_^?*O[Z[Y=_V!/_/BBR_\\`__4*,8W_SF-S5%Q5_UZ[]T'A%'E1)( M\Z6+S7-'L+D9M?GYWN_]"]_\S7^J^?FS?_;/!&]9K(&U,2"```((((``` M ``"-T2 48";/EH4I:=HCYJ4BS?$UU`10``!!!!```$$$$```016)T`N/O^Z MH'E?97,OZY.+7*W+1``!!!!```$$$$```000R"1`+KZ024HS!!!```$$$$`` M`0000.!2!,A%<A$!!!!```$$$$```0000&"$`+EH6B"```((((``` ``" M"*PG%Y\\\7;'K>83MI>J[[M8!!!```$$$$```02J)9"H+C;2I?]H+J,5,\LE M3==M!$W_+,O/6'2B+4X7]#EUBBU.7>W\,S`$$$```0000``!!!"HED!:+HX. M?:&DR=2!"\^2#SUS M87`!0YG4]1GTUO]O=]14FT#RM<TRV0WE8N1T;9_]!C/.$O30'^T4C<RS:(8` M'<K X*)&&Y1>>!]F_!KW*7 FC:4!` ``""""```((7)9`6BX&:`+1&(C) MP%*YF'..4<'9?W&M6F)0D2M26<GJ8E^Y3>FZ.(TIN1 1Y.3BC`GF$`000``! M`0000``!!!!``($=""R2BZUV:A^E8QT>.'I?:]=Y=XK P%&--WM(W55,G6YU M!HP`` ``""""`P,D(I*N+_:+?*AHFZ'"TJ+ SY>&0MAC`Z(5/G6 5U%M< M*OP ``""""```((((``` $!,A%6A$!!!!```$$$$```0000&"$`+EH6B"` M!!!```$$$$!`=3%/0WN'*P((((``` ``""""` .JB700$$$```0000``! M!!!```'51=5%!!!```$$$$```0000`"!/`*JBW81%A%X>MZ'>P\00``!!!!` M``$$$+ X`7)QD5BZ^.QII.*)"=S=W9WXZEP:` ``""""```))`KER\00U MI#Z+6[F<RL><G%XWW:!9&[<R3T;'>>SDN6G3&SP""""```((((!`2R!++IZC MS-)=Q0W5Q&H>\PUAG+?:V[4Q[] :CCIV\MPTNAK,9PP(((``` $`-!-)R M\32JH+W4V[J<FL=\6R1G++9;EXM==73&M2\_I#W[\G[T ``""""```((('` M`7*QZO<N7D0N/GEX'+ ,1D]]`KEXX/[(K=.K;38:#P((((``` <` !<I%< MG$E JG;4:K]\!5BA4&R7XJT+GF/W&FZ=WB'NV$D10``!!!!``(':".PJ%X\5 M!L=FS_,,7_.8(W*QN] <B^>TF4=OX5$'"IY5F!P[>0ZDM]#N#D<``0000``! M!!#H M]]R?2YDM ^DW/&I8X9QJ,V70H>`9GG3TV.5L Q[F=1B9\/UAS^L\N0K(Q20B M_Q2!!)J2B\$AF7(Q?O;AA!E=*:/S:FKN]5%$9OMP!R%GP >7$Y^TD<8Y]([U ME<GPZOKJ:)CH=^US;D:-"*WD502G'JJXR-ARJHO#L4V--G(5P;P:"K;XL*?D M8G*UC%87YYT]\ZC`7E/_'9V*"^5BSDP8G4Y3&%47DQ-,`P000``!!!!`H'X" M%<G%H )11$!.*9S\]R[&:U_#Q'HX\J"'X7_[9:)^22=3XHZJZPC`H<"8$E'Q M^[_T3S':_W`,H]?5$9BJ+ 8PAP:=FJA%<K%OP?PEUC=?3CE].-LSIU-GJ2D7 M0RXFG:\&"""```((((!`_01FRL7^A>7GLKO)Q:%8:E[)S)Z7R,5`.8S^-ZZ4 M ADS3R[F9/RC;8K&-B47ZY_TF2.,R,6^6)H2AZ,;"D.A.U3R4T(Q?J*A:LV< M\)FS=-C_Z"J+B.U,[)HA ``""""```((U$- 3;DX5;T)4N1A1:C%T1T>-`BR MV03FR,71DPV+#Z M` ``"MTM -;E8/X*:I5>\1%-G':_.4:TX#V]=\!P[X6^=WHH325<(((`` M` ,#M$B`7ZRTM-K/JV(P_/JW)Q<J7_;&3AURL?'H8' ((((``` D$, M!!!```$$$$```0000`"!)('(?6'D8M4WHR9-JP$""""```((((``` L(0` MN4 3(H``` ``""""```((C!` %TT+!!!```$$$$```0000``!<K'B[U%< M4B-V+`((((``` ``""""P. '51;L("""```((((``` ``"JHNJBP M ``""""```((((```GD$5!?M(B"```((((``` ``""* NYFGHU6_YU2$" M"""```((((``` <',$5!?M(B"```((((``` ``""* NJBXB ``""""` MML$ ``""""```((('`=`E7(Q:%(Z+_2_EZD#Z M` ``""""`0(4$=I*+S6F&CTA!:2VYV%7>NG.UKW26&"UC!FV:QJ/CG_?B MTZ=/B^;!K:.;DOJ=%?HVBMNKOW$PG"$MU7E&<10""""```((((```A<A4*1' M]I.+S;""Q]9R,5)C'%8LIUYI!SD<_+Q7&MQ%YFGUSTVC:^5B\. T9*3P.+IE MT!>9?<W?_3[/+HY"``$$$$```0000.`*!$KUR*YR<;2J-O4>MF&A*7+7XJCJ MFB=IT:%82KZR/[JD7.PL/K111"Z.SI.U+*4?!!!```$$$$```03.1Z!4CU0A M%]N\OW\+:.8=JGW[!3WT^^R:1=KTWQ0WO(MUK8E2:IZD7+P)=,F;40.5.&6+ MCM<`$$```0000``!!!!8BT"I'KFZ7-SN4VU&+5IJGIKEXL[HR,6U?(1^$$`` M`0000``!!"Y+H%2/7%TN[CQ12LU3LUS<&9W3(8``` ``""""`P$("I7J$ MI>:)R,7S0;N)*PHL>Q-C/M\ 6:$&F[("*]1`H(8Q6`NL4`.!&L9 +51HA57T M2!5R\>Y<C\8P^\C%<V&[ :L96K9=/QY[$F"%/6E/G8L56*$&`C6,P5I A1H( M<(XU68$5GAPT]W+FYYYMK`5KP5KHOG]N6%UL%)0<Z5B/1"ZFI=`A+<C%/1?& MGN>2%D +I`72 A&?<Y!PXI%X)!Z)1^*1GA,XR`_OF87FG"NB0?JZL?3-<;7< MC'J(KMOHI.1BSH2^Q3:2,\F9Y$QR)CF3G/7] + +H +XD+-<4%U<2.YM[1; M\<FH*IWZ*)>I3YZ-%#W MG?S+EY=S%2.YN*$+(Q?C6Q 7"'X"4IT!27*6V%W<8&U:"]8"T4ZT$^W/"6S M8S?,9MNN-QBS]R[.JO0=<1"YN-4":^]$;1[=+Q'[[K((I<A2Y'I"]5;KKNO7 MIP1/(=[`V^18DUPD%[=(-W/FWDB;=C-7=*[,2\RTYBPQPR/5Z9$N7UV\;Z5Y M]G-1X[;;60]R<2OW1"XF)^36:6L_%9`6')L62,[BRV'KM=">G14JL<*S^'Z7 M=)!;M)$B/\?>1 1QX=BXT)[=6CC6"I7%A<O+Q7GRK]6!^<_I^!.V(!?)Q4<$ M#G M7(R'AGV\1&5;)^1B,E\XI &YN(E0Z6];"DA'!21R<9] DPSYY&+2N^]CJ<K2 M BO>'M^98!^+DXNC2X]'JL0C)6-'-\X-UHNMD^=T*XL+EY>+^17"MF7SF'%( MT 4,&I"+Y.(C`ALXY:T()P-)WPD2[0>*]N[4K'"4%=KS5I867%<N]O<3(U%[ M`V\L17YT`RJ/=*Q'(A?C2?L&'F#DA)7%A<O+Q7GR;WO%N*M<;*;^17Z:Y=== M:?_W'2]_,BW8<0P'FYL5:K`U*]1 A68,G2%XI`,MP H'PF]/S2,=;H+6"OV? M"C58H5_.XI%XI%=>Z'*RR]5X>:0:/!(KU&"%*N/"Y>7BC#KAC$/*%2:YN,FM MDGU7V&[;["Z5W73DIJ.C/G'NT627%D +'B8$C\0C\4BM;[06K(4JU *Y&&C3 MIT^?CJK5J1>;S;:I0[+VX29W+A_^D"\"BQJWW98_R$5R\1&!2E+;;DQ+QD.H M+*'7GQ9+^F&%)?36LD*5:4%6/*V$'H^4S"YNQ5(\4 V68H4:K%!E7+A\=3'I M: ]J0"Z2B^3B<P(;N&^[R':1[2*KJ#SW MW 3WK()UEU8JA6TB&J2O&R-EO"EY>7=W%_G3,_,/?ZJH+K;5O_SGHL9MM[,> MY&)QL.D?,+HP E7G9M0IQ(5NI=A2TH*M"2?70C\:!;_O."ND!76F!:J+B:"] MP?JU%FQ ;9'TB\Z/"&RP<HL)YT1G<M'-J/G*D5Q<?Q&2B\\V.^[2DW#K-MY! MNC7AG(!$M+/"PSPA5`B5ZN)"-1456R>V3D8([!`[5!?[BK&*ZF(Z=SZF!;E( M+M[JKE W[BF72B[N$&SB5K!U4N'6B11YQ\KVHU/9.CG<([G?H0:/%+ 'NDH MCZ2Z6&-U\?YA.N0_%S5NNYWU(!?)Q7/*14*EPK3`C=E'I06$"J'R,/?4>-5X MN,'J+HL=4F1KX4,S1EQXM'94%X_:1B07:ZPN%JJXW9J3BV4A/VCMHVX.='/= MJ5F!%88$>K/BZLE9/R<(?M]QYES="N1BA7+1_0X[>H`/G\I:J'`M5"/:+_]% M$1?$!7&AG0/D8N9W>F1^OT=6DC&Y_![^D"\"BQJWW98_=I6+C6L^_4^SY(;7 M./KBQB FD[.-SUN+B8?,66%_T[/"_LQ'S] WQ!$+H7$+/-(CW\ *1RV- /P1 MAK`6PCR!%0Y9#E7&A<M7%\N%W#Y MS;'"AQ;LU>M:P<YQ-;O(6=NOAWN2P.W/'H\;\&KP2,%:4%V<+&_<I5/0M=8" M"P,D*SR:R-*"&M("5CC$"N0BN6 #JR6P,#JOM'ZO'IW)Q:$PK>5[%V?(OQF' M%"I&<K$ZN4BH]$U2*,\^?.C" ,0*-5A!6K"*%8*T %Q<:5Z5Q8Z%'FFE,4N1 M'VD5:V&E>64MA!NCR51\=FX3]+RDG[Y3JN:ND\M7%Y-3YZ`&Y&*9FTLNU.75 M14)EE11Y87+&"C588:541HHL179[?+N8K`5KP5JP%IZ'UGZ>4\W6R>7EXHPZ MX8Q#RC4GN;BF7!S5&.W>3WSGIK\_1*C4(%18H08KD(NK6"'P/]6D!9=^[R(K MYUH %U-)VT%_)Q?+1$C0.DBUR45R\;%(NWI`(A=K$.W-&%14-MT6B<>%]J_6 M K7PH7DB+CQ:,2KM*VV,%F>S5<:%R\O%^P<[YC\7-6Z[G?4 %XL76/\`<O$H M-Q>QPBK)F9M1DX23*?+H^WB3[Z??(*V_>G)&+M8 5,C%&JQ +=1 !6NA!BO4 MNA8N+Q?GR;]\>3E7,9*+=<G%QHT2*LN%2N`'6]=<)%188;D5R,66X08"N-AK M5;F+[&;4Q![O!C/GZELGA,KA'DE<$!=ZGBVB0?JZL0D615]RT0:7*>79_.G9 M?35O,]71U)C)Q<.M2: <+E26;R.6KKL)+WIIT;Y<+HK.RZ-SVT.5<>'RU<7[ M=ILY^[FH<=OMK`>YN%H"EW1A$<78I3+D8F"/V4G>PN0L:<W(<B/:AZ&H?:6T MQBLY.W5:<*$-K.4ILK6PREI8&!=88;D5EJ\%T7FY%88QNIKH?'FY.$_^Y<O+ MN8IQ5[G83,<3_S0N+'YUR0;M<NV>E[&:W+]<UNW-6'!(.X=_!Z>H\3322UMA ME.%*8(OFX:6M,.I/6&%G-V M[`Q\ZG0+X\)*5W%IC[1\+:SDOBYMA78F!R17 M`KLP.I.+LVI_VQ^TJUR,7\[L.M):]:B%_21WO%07%Q(NVME=N(N<M*;J8M*: MW".I+M;[WL49=<(9AR1=P*`!N3C)K-1=)ET8N9 4&$-CE%JAZV&8% SSYLAX MDM8D%Y/67)X6$"JKI`52Y!.DR-:"M3`[&B9]]8J1-WFNY7%!=%YE+009D9M1 M,S]U)_,3>++>:S'IUA_^D"\"BQJWW98_R,7]Y&)$KGCOXDK)T(>[(1?K3)&+ M1/M*LT)U\1'(:M*"K' J18Z']4(^UH*UH+K8SH&KKP5RT2>C%FE&<G%ON=C( M8E[ES+WG;507-UO=!5;H)YS=>.KP2)=_[^)]Z_VSGXL:M]W.>I"+Q0NL?T`_ M7JP%:^&VU\+HAOLL`7;UM=!`Z\?B:NXZN;Q<G"?_\N7E7,5(+A:DO\.FI7)Q MN*,3O$(NDHN'R[SX/,]/6\G%64G,:AZIZTAU\?`UM;RBDK_NHNOWZBFRM7#K M:X%<7"M'(A?=C%I492075TO.<JJ+Y&(?=^&^>(&EE N5?&M*SD9%4>2&:M7% MM01Y9C]2Y%M/D2-!O="+DHN/6%934;G*^WB7QP5R<2VY6&M<N'QU<4:=<,8A M14KQH3&Y6"!"XLE9OL`8MNP\H.KB*JZ07#R\KK4\+9`BK[(6 BWD5CC5\1Z5 MJZ3(0Q.PPGJKNRR"UYHB7V4M9,:%J0C>+:5(/_$TN+>]8NNDSJV3R\O%9^'A MP33YST6-VV[+'^1B6;"))'"SY6)S8)O`=3UPA1WGPKWSY\>M(A=988D5,M." MX?*;9_%H/]*".M."JZ3(Y.(23S(:H6=["7*QW:I(/C9JDQD7R,760!M9H>V\ MUK5`+B97YS$-R,4:Y>)4>I&<(W;.1OU YW;S;X.<NN.ET'U?5ZADI 7DXH73 M`G(QX=$+O4U.++NN1ZH[1;[*6LB)"Z/!UY>-32WOV5Z"7*STO8OW[59!]G-1 MX[;;60]R,2?$9K59L;I(+G;$Y[E"U<4=1$BP* )+Y:0%H^MJGL6CLE.*_`B/ MFU%73[SB:V'*G[LE>"\/\.'SU)HBDXN/[JY27=PA M>Z%E072[1B)__RY>5< MQ;BK7&S2E!/_M/>4YOP$+?LWHW:'Y_<V<<;)%#EGA+?>9HI>/M5V W,QA^M: M(4(O'VQ^RZBEKFN%%LL0XTI BQ;(I:TP"IP5%CO8HAEH+13C6MU`.7$A'GR[ MBLK4#ISJX Y[DSM4%XO6U/1X5!=5%[=]%]"\M:"ZJ+KXR MM<GR)ZF+<GW=_ M;>7BU)IJ_S3:56$.*2[4&1<N+Q=GU`EG'%(N+\G%U21E46K;;TPN1N9M80!X MWA.Y2"YZ'V^WK(+EX&;4M;8(,_N92FW)17*17&SF0'^[?$H->N]BIK?)7U.U MQH7+R\5G2^+!C/G/18W;;LL?Y.+!<K%=L:J+:[G">+")YV=]:3JZP=E9*K[0 M")6&3V3WM\ *^<$O:,D*Y&)_2LS;>!I.OQG]D(L=QAGTUO``'^ZCUA19=?'Y MA\.3B[MYK5K7`KE8KN1V.8)<K$ N]H<2N1DC,C&DR*W,6UA==+O+M/3*6B_) M1QJ-+X%I1BW5&2NR'6DS-W.3BUSTR:A%,I-<S`WYR<"63)%'U6"_ND N9KJY MB) A%W?;FXQ;(;Y>\N6BM&!VVDHNUK`6UI*+1?%E>FU>5*AT0,C%!L51-=ZB MC$C!'$LETP)R<2'A(BO4FA9<X 8\<K$2T=X. US<6H1$/%LR+O2/)1>WME2M M<<'-J.5*;I<CR$5R\81R<6C4X;M#I]IT*86Z5H=HGFA/$AY=>S[2($<*YK11 M7:Q$J$QYDJ*;48M2[>F4775Q)-YE;B-&4K)"#WE1*Q3-X;BP%YUG1^?N0'*Q MTNKB_8.)\I^+&K?=SGJ0B^O(Q<QJR7"ANADU/F\+P_#X)ZP\6TUWS\Z3F1:H M+DZGFUGK)9D6Y*P75EC+"K6F!:J+B:#M?;PYVR)%;507NVBX;N3-L4(R+O0[ M(1>WME2M<4%UL40K=O(O7U[.58SD8E;ZFW2%.>GOJ"LD%]<-6O&`1"X.:9<* M6XN0R"97T1PF%[>V%+E8:74QL8MXV)_)17+Q$8$#DZJX>( LD?P]>'*17+S MEV+7FA:H+B8"?[YGR]YTNZA<C&R=1+:W6JH;Q,2K6R$B*8?"OK^E/F7'69:Z MJ!4B6R?Q!&FOM7#YZN)]ZW>RGXL:M]W.>I"+1\K%;G$.`])PW18&K8NZ0M7% MY6+1.&^N<9Q;)M6D=;*QL,+DNDC: A6RI]DXY`; %,,D_(6G'CO\HFMA%3_? MF7*Q72YJA6["C\[\W9?#U:V0,XU'31:W8TZWO387M4)'8#CM=U\(3>2*:)"^ M1[)P#SYC1S9==8D4\4?W?H+*B>KB*E9([L''[[7HK*"NM7!-Y>PB)]NPPG(K M";S6:%>%EKJH%3K(P[403Y#V6 N7KR[.J!/..*1<=)*+:2D8H1H(C-&6Y.)* MZ6:6I>(!B5P<0BP,L2M8831OZ_HEVM=:+VU)2HJ\6=*?M1:FU$B1:"<7IZ57 MEA4"[1%XF\RXD),)Y+6YJ%"9(1>[F3]<+\/>"F/91:U`+M[?-X7')U57%V?( MKNZ1R,7;E8N![507!ZN[+)LE%RN5B_>MU\Y^+FK<=COK02Z6+;"I!(Y<7)C: M3IFA=.?,S: UI,C)RF$[2'*Q,U;I/,]9+^1B_6MA:J6H+L;SF=+UXF;4^M=" MZB8G_<UI0R[>5EH0"?FJB\&$+TT+6 \S13BRP[4D!9D>\]7K6J-DR,6A5R^= MYT5Q075QF]6=E4=E;B.V?9&+6UNJUK5P^8^Z*1=R^QQ!+F:YN61`*JTN)N5B M?>Q3SCS/::.Z6/]:&-JQ?W^$ZF+./"]J0RY66EV\;W."[.>BQFVWLQ[DXB2V MH 2.7`PX%M';4ZCD6*J_K[GLNHCV1_PBGQ+<M?,)>$4A/S(_R<7Z4V1R<3C; MMX =?>$QG!4J[3M8(2?R!L/HWQPQ/#RRU9B745PT.G=PR,5*Y>(\^9<O+^<J MO.3BPLA;9*EDY#UH+; 9-;+=<>2?R,5UTH)YKI!<3,[]H "98X7\-J,MB\8C M+< ,?GW4JHM%(3]">"VYF-R"B:QBG\D9I]?M3`6%%'(Q'AH*_?"'W\1;:XI, M+HX8O&\LU<6UXD)_6VJXH59!I?WR<O&^W2S,?BYJW'8[ZT$NDHN/")2&X=5= M6'Z;G)8I.*Q0L"[ZP*=^3P$?/=UUK="JD5%H^=,[OR6/-"00IQ<8J&W<?^[^ M%\N5W"Y'["H7XU<T>X\DZ/:0?E;?.9O:!\UF:/_R$:I GWX4H[W\5?;.9ZR% M[KQMK`HFOUWDED^19^LJ5%/T(F8*SC75LF \U[PQ>^C&NZD^6M=J54W[&*Z% M;F<]R,5);$5A>'57.,PSBL9SS>0LQPKY;21G06H;]S!% CS259O8]>%+"V:D M!7W5$=`N39')Q3[`0C^<^-BG "VY^"SSN4OG,J5MR,4E<YA</)Q>9$F4KH6N M/3^67"07L_W>.OY\Q>2L5&RK+L[S$G%?/=R$ZJ^I_$K[*L))=)Z*SD7K3ER8 M$1?ZA,G%>N5BD8S;JS&YN$YZD5.S*G*%0V%3&$0)E7&ADF,I<G%).,\A7+06 MI`4ST +5Q25SN&A^)H7*:&]3_IQ<+(QTZ0C>^?,I3T(N+MX8S;5"T5H8W<SM M7A079L0%<O&5%YY_"O'H/:_!]]N,MNF_V/0U=4C6AQV/KX>'5^^SGXL:M]W. M>I"+:3>7DSJLGB(W)U5=?+8*[M+SNN VR!Q+D8M+4NT<PCEK2EJPBA66I\BE MUD(RJE:P=7+Y]R[.DW^M#LQ_3F?680MRD5Q\1&">ZXD$B:(`L+"?'*&2WV:T M92&?*Z;(.82+9H6T8$9:H+I80XI,+M9 !7*Q'BN,>O["J/J\#W%A1EP %V^ MNE NY/8Y EPD%\G%YP1\,NK48B *Y^1B5<F9ZN*2I&KA!A:Y6,]::!;"\K6P MBH?TWL559 6YN,2S5;P6+E]=S*\0MBV;QXQ#RB4FN4 NDHOD8L)SD(LKI8GK M>)N(M8:W?BU/"T;S[&<1ZBX=<'IMKEAI)Q=7$08+1;OJ8CU6&'49A9[D>1_D M(KGXR M3[RYLWSDXI3R;/SVI][V+\^3?]HJ17%PG 5N]HC+,,PI=ZA63LQPK MY+=Q,VJW-HKF7 [A','3M9$6S$ +UKT9U5J8MQ;(Q7J$BNKB[#F M6DA&5>]=3'Z\S>8?=9/>ACVF!;E(+CXB4"0,BI+^A3O$.>?*"4A%;0B5)4)E M+8NSPA96R$\+5!?[,[G40TYQ3O;3'-BT"0ZW%F:O!7*17'Q6MKGK,%QQ2YU< M+JZUG1'OAUQ<(K:G'$61!TC>C-J<);E>LGU^3D9Q1:&R.F%;)S.V3LC%&Y"+ MS]*7!T/E/Q<U;KLM?^PJ%QL7?]:?=B=XW9]E?4X&I'4'655O.<2*VN0TCA) MA746Q3)#L M.2\VV16MT/&?HK>8:M%":!I'-$CF79^1-RC>['L7R[7<#D?L*A=7W9_+V</; ML:O,1-9+WG6IJ#SBE&/Q5N'T'SS2;(\TA/EL1_[N.=WD>EDU>[$6BM?"Z'H) MK):SIBY^[T_'?<J39,:%/)^?CE-CF:I/1GW =I_]7-2X[7;6 US,F=#I-EL$ M-CD!J: -N4 NQIWJ(8E7SGI)SG-R<8AQ=6LFK1"?7>3B*BER9X6(/U]HJ<*9 MH[KXR+"%]&PCKD!/=;'J+](HUW(['$$NDHLKN)X=$J]54N2FD\C-73[J9MWD M;,59H;K8P"Q*JI+I+[FXXOR<VE!+6H%<W-,*Y.*,[;^<R)O39N%:4%U<)3IW M*1"Y6*]<O'\P=?YS4>.VVUD/<I%<)!>?$R`75PE(TH(I\9"35*W5)FD%<G%/ MH3+O7*,VLG4R>^N$7"07O7=QZOT%+9G,N+!6G/+>Q7&2^5JQDW\S#BD4C>0B MN4 NDHL)M[%N72M^,KO(^XCVS+1 *K<H3=E]^-:,301R<=VU0"Z2B^1B>XN[ MZF*]U<5"%;=;<W*17+RZ7.S\INKBNLG9O(H*N;B/%<C%%>?GE!1,UGCCD9Y< M7'<MD(OD(KE(+M[?W]W=/:E7+LZH$\XXI%QEDHODXG7E8E`Y(1?73<Y63,?= M %=:S<L1*A$U$JR%T99%-6?51=7%TCD<R6>*YEXW>Y?+Q:EE530>:V'&6K"- MN$IT;CIQ,VKM<O&9HWRP=OYS4>.VV_('N4 NDHO/"9"+JP2D'*%2F B2BZ6I M=HX5R,6UTM:I?G*L8"WL9 5RL45=*&[E2.?)D<C%V_ BC7(MM\,1Y")7>!Y7 MF).<]=NH+FZ1.N1808J\6XH\1#W<%NFW:<VGNFCKI$_ $(%1ZB62HIU<)!?= MC!JOD&>^26&MM>FC;D9(WK<Q./NYJ'';[:P'N;B"7-QH :FHE(J9'*$RE(O- M6493Y.[U!6F3[]=ZM+YF)YW6PM9KH;53^[:6_KFF[EPJ'8\;\()(8RU,A=[9 M9*8(NQEUK;FWI)^<Z!Q)8MV,NM9Z(1?=C#I++3Y[M^?3IT]'W_-Y?W\_]:?1 MS(1EYKBB%7*<^3*JI9:-:)"^T"C5(ZWHF)(V=7_4S3PQM_U1N\K%^.6LOJ=8 MNE,U>^=,=7&(^A!KYNQ?JB[.GN<YZ]=:N-&UH+I87B^=7!#QVWW;PY9XR/XJ M$2+[N:AQV^VL![F8#OG)A2%%'B(J3&)6L$+318Z;(Q>G'?<*5K`6;G0MM,-N MJXO]%*0SZ-"RA6M<BOQH:A32>W0LN5A$KS0N1#QD MXQ&0AD8=NL*A;HRW:?MDA7B0V& M2`M*Y]Z\%)E<3,;0( ^08X7,)*_?3%Q8 M/B*0'P#BD_R0 M6!1?<JR0TZ9=':,MB\9SP>JBN'"[<6&V-,WS;)D:[4KO7;Q_()?_7-2X[7;6 M8C!1\ZU`+I*+$[&57!QS__E:L9-_,PXI%(WD8CKD1Y"V[G(C5QCTG.^:'P;L MW1'C,EAU<7;(SQ$J&ZT%-Z,V\(L\0$[Z.RH76[=CZZ14PHTF0SE62,:780-R M<>NU$+&FZF(')]\*X *Y2"X6JK/JFI.+Y.*XK)J1Q$RX Q4(YPB5N&Y/IK]2 MY%4L+BVXT;2 ;SAK896UD.F19IR+7,P7*IE6&'5<HS=FDXOD8C*1+YJ?,SS` MBT'>',P/5IA:,)M6VE47GT6$N[2/+_JX JFI3BZNE0SE)&<SSD4N;KH6.HN0 M[F`%PIE!*R<Y2]Z,2BX.:4L+XB(Y<W[NN:9660O]':MAA_FSXN'";6"MYFG) MQ:*Y5[06^D8B%]?R;.3BDJBZEA7Z_CPR'M7%_F>?QG^/?`*/3T:=ARZ+6U$` M9R9P.5:8<2YR<;NU0"ZV!(H()^>PN$`N] GT9I?JXF!JW+<K,/NYJ'';[:R' MZF(B_<U)"S9RA<VII07Y02O3"E-RL:.MNK DL&5:(9E>!`W(Q=($+D>H)+=. M^BY(=;&=D_$9WK8INB6X="V("YNNA;XY5!=S\I^<-N+"DJB:0SBS35%<B*R% M&5ZK?PBYF-!K]VT R7XN:MQV6_[852XV4^24/^UF_!8_"WJ>K"YN,<X:^LQD MU34;MF]?"5[/[':"`"NLLRY8H72)Y1";6 O]8R/KI7!()UD+.6!;,ODM"TDN MZ?PD5B BEF.(T3:CL2"GM]3P+F>%-:"-A))EW5[."IE.*6<MI&9X?MQ772S7 M;0<=L:M<S-S_6&_?8K*G_)I5SI WVCFSBURTBYQIA;;9:./1/P4M"V?.Y6X) M<;KH9Y; )!=7D)0;N4)RL< 5YEMA*N$C%Z<60^O<XXERUV:]0/+AGJ0%16N! M7!Q.PL*$?G(6DXMQ+Q'/0]:R0E$_L^5BNX[(Q>46SX_.1><2%S:-"WVY&*R% M]:*\ZN*`99'PZ]+6HJ/(Q99`42!99=)OY`K)Q2)KYEN!7.Q/^_SU,BJGNZ[( MQ:)$)VB<;X6<=#QS M"_H]YX_GX9).DISE7W6^%<A%<O'^_N[N+N%Q\^=>3L*T9YO,M3"E?,C%B+'( MQ7JV17+65-%:Z'<X3)$CIB_T%:+S(],5TOOPL>0BN?C*"Z/?U]!^'4/D3\]2 MY.'/TZ=/\[]%HVGIBS1:7!$.4SRG#O%%&C,34W(Q/Y!DI 7MYMEHX]%L0$!J M`])4)2K8F\RW0FG2:2VLOA:*Y.)PUSE_/*?9P.J$=,X\SVF3(WA&VZ N)K?7 M%T?GZ/[S?,7DC%PL]5KD8F3ZG6`MY%07A_LFI2F[>W]*U]T487*Q=.Y%='OP M7(QO(9<&ML#NJHOYZ7CF7GY2+EH+PTF8[VTRK3`O\5)=W"(ND(L= 7QOL^(& M)W68UT9:D+\V,X4*N5A:Y5!=K,KGYWB2S+70;B.2B^3BB=_3/ISDH_G8<,ET MD2(_!N6LS8<VJHO9JJVM9HQZM.#UY M)V SVM628$,NYM/+3)')Q=ER,2?QRK3"/`&FNIA,>/+KP&U7Y.*H>) W/P/9 MN=U:$!?RXT*.UQIM0RZ6?EY+^^DOZ<_32WJQKD%DP[[[T_"7_/XS6I*+2^5B M4L87+>;A:*0%R6D\(RV(U,=&DX8 ^,6'U+/X23X!+\ZDI4$N1L1VYAS.GE<) MKY6?G(UN5D[5T()N"SW;&=9"1R8G\<JWPHR9(RYDKJE\*Y"+&\G%37,D<K'( M#T=LX;V+F87.OG3<[Y-1\^5B<KTE7>=$`W)QDEP.\ZU3Y'Y24N04O)D^L&N? MWFB*W`D><C&R9]'^*2*VUQ(\\3%8"W&!490B#QN3BU-XR<7(`B]<E8DMC[4\ M2=%:Z)]T6%&)[-T77OL9MD[B.R8=R:US)'*Q:.[ER,6A98=K83T_D*G12K^I MX71?I!&1BZW!(NYIKCX,CMM5+C;3^H9^VLP ^9/9+-G/5(.Y_4\&I-DCJ?S` M?%#MRAJ]G.&?\KL=Z_`D5 1.AM-TD6&.(D5LAGF\]J="UTAV?:/6] 9[!" ML4+&E3[W(?F&V&;:C[HR<C%/S,7E8M='7S1&] ;RSGFD7%QKOW"??OIR/;*7 MG[1(T=Y/I*A2V,])]B_SKSIN"-7%>#TJOJ8"MJ.H[2(O(9P_SW.\W_*UT/80 MMWOAF,_ D=HLJGU$(+=M\JTP8^9TG5_0" VN_*O.M\)H/M99/)ZMY8_GP=9G M6`M!2>.H'*EOEVM:(?^JUUH+.3$HNPVYF"?=BN1B7S3F=9_3:M?J8O8$FFR8 MOS`6GJL-$CE2,*=-TA*1ZY(69-(K<H41P2-%' (G%V<D]-TANWFM+HU>OA;( MQ5&+Y\O%K>-")T<+9]=)A$K^51>MA<[H_71K*/Z'?>:/YS1RL9(<B5S,GWMK MK86%V?7C[1YR,9GA/C3(D8M#E9B,0WDG;UN1B^.T1O<4ATTS)672(N3B\G1\ MGBOLG[>UYK"?BP>D?HK<XHJ([54#R:/.+FZ%QR%V$G-I76MTPG<FMG42 "87 M(PL\/VW=SDL$_GS*677- KM.NM?)Q:0U*\F1Q(6DI;K8,2]'&JZ%5=<ON9C4 M<G$4"[EXD12Y?YFMVR$7R<66P-7BPG`KWUJ86 M)$9+,6I?,+G(QGU[24L/M MDB`*)$U9[BO(Q6RY>'1#U<5Q"P0I\M0B45V<FL#Y+FPM23G/%?;//E69N7A` MRI2+&P221U/CXE8H"L/+U\*H7`Q2A\(UOM-MD!%?/<QW U?B5]3VW+6)0-XA MJ\#L\Y.+67(QR)-&]V"V"Y!!FA(Q;L]Q2`L><9JZZ8A<3`:;H5P<70Z%:>OD M("YDQ05R,3D_,^5BX?P4%R;GY_(,DUQ\Y87&`3Z_SZ[_]8G=[T^?/AU]?>K% MR,4I%1>DOZ-Z^!;E8J$T)1?3<C%8/J-3)6B3%%?[B_:I'9_'(YGOM<C%*\2% MDZ']UT*_D%*8UDN1TRER,#T.K M8MRSS= ZR9DJ03Z0/TLG4N1%GRS0'W!PL_3HY1>.= 3P,"=IE^W^:V'TVO.$ MG+B0C OD8KS8J+K8\HEP*"W,SG&%H]YGU,WU6PZ/&LU[XOU$Y%G7VY1S'/JI M55QS<[K"?B[D"I-:,1#M4^U;PO&`MY85IB)K-Z_ZPYA:"Z.SO=]SFTK&SQ5/ M+Z;6POYI09<BQ]="MT)[UWZAM3`UA_M^*6?K9-1M;I<B#Z=]X&E+-XR".=_. MS0<666$J $U9:L&%)P)2T'-W%5W(GXKTR0P .?^'ZVMJQ8VF#J-,BJPP+T7N M9)[GQXYL<U +L10Y1T?ESY9IHZ3C0OY9(GZ[?ZG]B!"LA7B4F;J*B*0\:BWD M1*5>&VMA_EK(=CC)!/+,<K'H;9`WT7CJO9WK5A=O`L7)!AE8MC'HR2[P)BZ' M%6HP$RNP0 T$:AB#M<`*-1"H80S60H56&!U2J1YI;VF<ZJKYT[,W30Y_5ORH MFZ:K4SY6,4_3R91%3PGM)BZJ;]F;&/`I!\D*-9B5%5BA! (UC,%:8(4:"-0P M!FNA-BNLHD>.EXLU"/'=QE"JYB-R<;<Q.Q$""""```((((``` B< T"I'B$7 M1VJGVTV%4O.0B]O90L\(((``` ``""%R-0*D>(1?)Q5T)7&U!NEX$$$`` M`0000``!!.HA0"Y6+7Y*S:.Z6,_2,A($$$```0000``!!&Z=0*D>45W<55Z6 MFH=<O/4%:?P(((``` ``""-1#H%2/D(ODXJX$ZEDJ1H(`` ``""""` MP-4(U"L7FY%YE)JGK2YZ((``` ``""""```*K$"CZ3L2=JHLU?`E)/6,H MVL.H9]A& `""""```((((```B< D*]'=I*+^0/2$ $$$$```0000``!!!!` MH`8"Y*)W[B&```((((``` ``""(P0(!=-"P000``!!!!```$$$$```7+Q M%9,``0000``!!!!```$$$$` BX#J8A:F&NX;- 8$$$```0000``!!!!`8$\" MY"*YB``""""```((((``` X&94-Z,B ``""""```((((``` CD$5!=/-4N MPI,G3S:J36_7\T8#UBT""""```((((``` L)'"\7&QT2%^*!/]=>'GG/KQE M+ 8RNYDNVZD7<G%T-6X'?(?%[Q0(((``` ``"",0)["07F],,'^W(VH1[ M$#W*:E,CB<^6X`)'.?2-$J\N] E'INC4K*YD'NXPU9T"`0000``!!!!`H$(" M9E3']I5AUV!*+FYMM;APS1S_\(I&:Z>=%)S:?0 &,WKMP5RM9![N,-6=` $$ M$$```0000*!"`J5Z9%>Y&,GF^YEWEYV/YNNC+4=E3/S%HA+?6HU+S=/)Q2ET M2C\(((``` ``""&02*-4C5<O%X)J'A9JI,E&U:7JI>9)R<0I17%2W?RTJ MFDT)JDBE-Q!1.37AH2(-SAL(OZ$.S)D2PS81C-TI`I4X=:+^55<[#S.]B68( M((``` ``")R-0JD<JDHN=)9(9?ZGP&&J,HZQ>:IY5Y.+4Y:\B%_>W6GXE M<$JYQ97>E")-:K_,FNU1<\]Y$4```0000``!!!`HU2/URL4V:^^*8/TD?K3, M %YWHN[`FYB'AR\$`T```0000``!!!`XA$"I'CE>+NZ`:7A#XPXG'3U%J7GB M<C'S*NJY_,P!CVJVHF/CC8\"<M1Y5T2G*P000``!!!!``(&;)E"J1\C%7;]W ML=0\Y.**JW%8&%RQ\YRNR,4<2MH ``""""```((;$> 5(]<0BYNA[NTYU+S MK"(72P>I/0((((``` ``"")R20*D>(1?/7UT\Y41W40 ``""""```(( M(%!*X/;D8C/B\SV:;^0<M5RI>2+5Q?-!<T4(((``` ``""""P%H%125*J M1XZO+K8C.-.CT7C[R,4S07,M"""```((((``` L!:!*4ERJW*Q_]4(M_[[ MGG+Q&:O[NS0Q;>*,\,%GBH"Y86Z8&T,"UH5U85U8%WT"?$*5/H%<3$NDHUJ0 MBVGRW$J5;F5R4.S%7E)#J:'4L"7`'_*'_"%_>"/^D%Q,2Y*C6I"+:?+"K7`K M2&52^1$!L5OL%KMO*G:3B\T-(0\6RW\N:MQV.^M!+J:Q"3E"CI!S4R&';"`; MR(;G!,0O\4O\$K]N9+N37"S4BIW\RY>7<Q4CN4 NQ A(-:0:4 VIQHVD&K8) M;!/8)K!-X/VZB;2VXKR.7$Q+DJ-:D(MI\A4O+>F1]$AZ)#V2'MUN>L2'\^%\ ML4`L$`O$ LUB >IB6I(<U8)<3).7(D 1I`A2!"G"9BG"I(/A>_E>OI?OY7LO MXWO)Q9*B8E<GS*]#SBTM-C.07"078P2D:](UZ9IT3;IVF72-=!\A(`Z* ^+ M+G&07'S`/$/^S3 DK7X>M=A5+C8^UP\""""```((((``` T"-`+A9JN!V; M[RH7GVGFN_3%:6,GST[>+CMY* DJ"8\(\+U\+]_+][J;P-T$!\4"<K'2TF*S M(LA%\C5&X""70<:0,63,<P+6(`E'PI%P)!P)=X%80"X^3//[PN=YAZ35SZ,6 MY&(:V`66*'E&GI%GY)F[/Q+A0"P W4EWTIUTWTRZDXMI27)4"W(Q35Z*($60 M(D 1I`B;I0BVJVQ7V:ZR766[RG85N5AI:;&9FN0BN1 C0"J3RJ0RJ4PJD\IB M 5 %H %&\<"<O$!\'WA\[Q#TNKG40MR,0U,F!0FA4EA<N,PJ<*FPJ;"IL*F MPJ;"=N580"ZF)<E1+<C%-'ERD5PD%\E%<E&%32P0"\0"L4`LV"P6D(N5EA8; MBY.+Y&*, /1(>B0]DAY)CS9+CZY<27#M*NHJZBKJ_8HZN? P'^X+G^<=DE8_ M"%*$S5($5295)E4F52;OVTRDHQ?(1<G%2DN+S=0D%\G%&($+N">IJE15JBI5 M$. 1(!<+-=R.S7>5B\\$\%WZXK2),\('GRD"YH:Y86X,"5 7UH5U85WT"?`) MDHL//.\+G^<=DE8_CUJ0BVE A=-=&B&-D$9((Z01ZZ81_"J_RJ_RJ_SJN?TJ M(Q?)Q1 !+IZ+SW#Q*C\J/RH_*C\J/^>N_/#S_/S6?IY<?"!\7_ \[Y"T^GG4 M EQ,`R.92":2R4ZYG?*6`'_('_*'_"%_R!]N$`O(Q;0D.:H%N9 FO\&2L$MG MQ`*Q0"P0"\2"S6(!N9B6)$>U(!?3Y*4(4 0I A1!BK!9BJ`RIC*F,J8R=NN5 M,7YLN1\C%RLM+3:F)1?)Q1 !4IE4)I5)95*95!8+Q`*Q0"S8.!:0BP^`[PN? MYQV25C^/6NPJ%YMXXP<!!!!```$$$$```000Z!$ %PLUW([-=Y6+SP3P7?KB MM+&+:1?3+N;&NYAN'%I^XQ"&&#XB(':+W6*WV+T =I.+E986&YN2B^1KC(#P M+_P+_\+_ O!/4I*4).5S`N*I>"J>1N,IN?B`Y[[P>=XA:?7SJ`6YF`;&Q7/Q M7#S M]\OWDJ:D*6E*FEY&FI*+E986FQE(+I*+,0+2->F:=$VZ)EV[3+IF*]-6IJU, M %Q,2Y*C6I"+:?)2!"F"%$&*($78+$50T5+14M%2T3JJHL7_U.-_R,5*2XO- MPJ0P*4P*DQN'23O<]>QPLP5;/"( !Y`#R`%VR0'(Q;0D.:H%N9 F+U0(%4+% M+J%"FBY-EZ8_)R#NB#OBCKASL6U MMK!M8=O"MH7W4B;2XPWR0W+Q ?E]X?.\0]+JYU&+7>5B,[?\((``` ``" M0"P %RLM+3:KCUPD7V,$+N">)B_?M4O3I>G2=&FZ-%TL$`O$ EUB`;G8;A(7 M/L\[)*U^'K4 %]/`A`JA0JC8)520[B,$^!_^A__A?VQ;V+:X0"P %].2Y* 6 MBAU#A6T+VQ:V+9X3X'OY7K[7ELW%MFS(Q0>#WQ<^SSLDK7X>M2`7T\"$;6%; MV!:V+Q:V27?2G70GW7W45B)%E!^NFA^2BVE)<E0+<C%-GCM8U1U(0Z6ATE!I MM=A5+C8QP`\""""```((((``` T"-`+A9JN!V;[RH7GPG N_3%:6-GT<[B M)7<659E4F529GA,0!\5!<5`<O-B='>1BI:7%9AZ2B^1KC("41<HB99&R7"QE M$>F(=&3_=(3OY7OY7KZ7[ZW3]Y*+:4ER5`MR,4V>7(PSP >?*0+FAKEA; P) M6!?6A75A7?0)\`D/-,C%D IA6TML'NTO^<]IW3/2 EQ,8[.,A7:A76 7VI\' MICL^,T9`O!`OQ`OQ0KR8%2_(Q4+AMZ-B)!>E/E*?<0+2/FF?M$_:)^V;E?9- M8LD]I3N6%AN+DXODHNJBZF)(0%HL+9862XNEQ9NEQ:JO(P3$G<O''7+Q80JT MY[3N&6E!+J:Q6<92.BF=E$Y*)Z43"\0"L4`L$`LVBP7D8J'PVU$Q[BH7FUCK M!P$$$$```0000``!!!#H M.^E ^%Z^E^_E>_E>OO> 6$`NEMQ3NF-IL5D1Y"+Y&B-PD,N0SHX08`NIO%1> M*B^5E\J+!6+!26,!N>AFU/N[NX>Z(C?'S9W4S9&X).XC`GP=7\?7D??D/7DO M%F3'`G(Q7<$ZJH7J8IJ\I9Z]U$DFDHED>DZ`W^`WR$5RD5PD%\6"[%A`+KH9 M5751934ES+G4;)=*EI/E9#E9 M^+OJ8AJ8D"/D"#DW%7+(:7*:G":GR6ER6BRXK5A`+J8ER5$MR,4T>7*17"07 M92_V4J%5H24%56CWC`7D8KL!4_ \[Y"T^GG4 EQ,`R.92":2225!)4$E02P0 M"\0"L4`LV"P6D(MI27)4"W(Q35Z*($60(D 1I`B;I0A[[EX[UP !,4Z,$^/$ MN`IB'+E8:6FQF1OD(KD8(R"-D$9((Z01%:019!Z9]XB`V"0VB4VGBTWDXH-) M[PN?YQV25C^/6NPJ%QO_[ <!!!!```$$$$```000Z!$ %PLUW([-=Y6+SP3P M7?KBM+%K:-?P=+N&JD.J0ZI#SPF(<6*<&"?&N6NC)=#SA^1BI:7%QDSD(OD: M(R"MD=9(:Z0UTII!6F/[P_:'[0_;'TH B12Z,(<D%UL!7? \[Y"T^GG4 EQ, M`RN<[M((:80T0AHAC5 WC>!7^55^E5_E5\_M5\G%M"0YJ 6YF"9/+JJPJ;"I ML*FPJ;")!6*!6"`6B`6;Q0)RL=+28F-Q<I%<C!&0'DF/I$?2(^G19NF1JJFJ M"S:+!>1B6I(<U8)<3).7(D 1I`A2!"G"9BG"I(/A>_E>OI?OY7LOXWO)Q4I+ MB\T,)!?)Q1 !Z9IT3;HF79.N729=(]U'"(B#XJ`XN$L<)!<?,-\7/L\[)*U^ M+7W"%N1BFIF41<HB99&R2%DND[+8MK!M8=OB.0'YC_QGQ_R'7)RE_<C%R"KE MPKBP'5V8]%'Z*'V4/OKTPL3NJK L+HO+ME87;*V2B^D*UE$M=JTN-K'$#P(( M_K[KS:A"8-+04 0I A1!BG"Q%$&5X'Q5`C9E4W<!N`N =-N+7%1=5%VT6YS2 MRJ0RJ4PJD\JDLNJB6"`6B`67C`7D(KE(+I*+Y.(T`>F1]$AZ=,GT2!5.%4X5 M3A6NM`IW5K]!+J82Y>/^[F;4-'NIO%1>*B^55_52]1(+Q`*Q0"P0"S:+!>2B MZJ+JHNIB2IA+Q:1B4C&IF%1LLU3LK!4)UZ5"FZC0WC]],OHCYE86<\E%<I%< M)!?)Q6D"I+*P75G8EH)+P1,IN*T-6QLWL;4QI16[U_G>:M8RN9A*E(_[NYM1 M7"07R45RD5PD%\<(D,JDLC1K<9IE"\`60,$60*;^J;-9*I583P8?*G'C\$<\ M(<T\==-^M&4MIB$751=5%U474WLBJDRJ3)7M=*K8J- 45&S:IOP8/W:4'RLJ M!IJKJ92DZK4\]4&O4_XG:-]=>]&<V?[39<E%<I%<E$:D?+,T2YIU5)KUZ$:= MN]1,M993A*QE:_FVUO+RI/FV>K"U<0(?-:H`(]?UX?:/8UQ-4Y=<3`77X_Z^ MZ\VH=K.2ACZ!"QN]1M<E?;RM])&]V&M( !\[Z[JH*6-.?5QGWEO4S-6SSM7: MKFO5M4,N)E7"80W(Q31Z;K<V]V0\4GFIO(JH"HG8)!:(!6+!B6(!N9B6)$>U M(!?3Y(5D(5E(%I)/%)(G%S1?Q]?Q=7P=7V<KZJ!80"ZF)<E1+<C%-/F#EHV4 M;H0`6TAGI;/26>FL=%8L$`O$ M/%`G(Q+4F.:D$NILD+2\*2L'2ZL&0[QG;, M+ 67 DO!J_Y^.;[75IVMNLMLU5U;+ 8Z<+CR^PU:^=?7C4'[H'&R?4H,D8LI M0KYC+46(G":GI712.BG=95(ZVTRVF6PSV6;:8IOIVG*QOZKB8J]M&9&+P\/) MN^EVT^VFVTVO?C=]TE'QX7PX'\Z'7\R'7UXNCMY$VDZ"HG<JCK[+,?G>R*C/ MW;6ZV(Q$"!0"A4`A\&(AD"08(2`6B`5B 5 %MC2ZL6":\O%^!L.9]QZVJVN M[I-1 U?B0>CQ7\G%-"UIC;1&6B.MD=9(:\0"L4`L$`O$ LUBP>7E8O(-BJ-? M`]7%-'YA0! 0!A:'`>FU]%IZ_9R`F"*FB"EBBNV\P78>N9B6)$>U(!?3Y(5V MH5UH%]J%=I4ZL4`L$`O$`K% LUA`+J8ER5$MR,4T>2F"%$&*($60(FR6(J \ MJSRK/*L\^RC$1#IZ 5R47$Q+DJ-:D(MI\A=8HM(UZ9IT3;HF79.NB05B 5 M%AP5"\C%M"0YJ 6YF"9/+JHNJBZJ+JHNJBZ*!6*!6"`6B`6;Q0)R,2U)CFI! M+J;)2Q&D"%($*8(48;,4045+14M%2T7KJ(H6_U./_SF57&PNYF0_3Y\^';VB M]&3T;VMIGE;UGO*QM5P\)307A0`""""```((((```FL1&$J2VY.+:ZGGF^BG MU#S-1<TXY"90&"0""""```((((``` CL3*!47!Q?7=P9T+&G*S4/N7BLO9P= M'B$7R<5="1R[/)P=`0000``!!!!``($K$R`7JQ8_I>917;SR8G;M"""```(( M ``""""```(((%`) 7P]LI-<S!^0E ``""""```((((```C40(!=W?>]B M$$```0000``!!!!```%R\163``$$$$```0000``!!!!`((N`ZF(6IIS[>K5! M``$$$$```0000``!!,Y$ %PD%Q%```$$$$```0000``!!-R,ZF94!!!```$$ M+AU/:?MYHW(4` ``""""```(((-`0.+ZZV$B [M&:9(8HRCPD:-:>MYL' MAH_V:H/Z7OM*I-X8%.7:_XZ^V.]J>*[NJ'X/.?V,% /[!P8]1T[=_]-P&$,R M((``` D$E 5[DX.J;\6F(G\#KQ MRN%HB7)*\&0:^-AF13( L_$4I6'5MS\] FDV9=!C<5WV[)FFORP?%XX`` M ``""!Q%H`JY&%Q\1$KU_]07C9GUI>'A 1 ;[6>H)[M7(G7(?L_!>?L=%G4^ ME(Y'S9O,\Q;) ,S&$5$]G!)3Q,C%3`ONTRS3]/L,QED00``!!!!```$$. (W M(Q<#B=5=0%_ 3:G!474WVF&R9I L`,:583#LN) 9E<U3'.J<TT4R(+/Q%);1 M*3$D')AX]&;4.F&>>%29IC\Q`9>&``((((``` C42>!6Y6+PIKY^TM^_*7'J M%L2X3FLE6=!/<$CDC(&EAP)RJJNAX`F&<5M:L1EMD0R(-`[L.*6Z^R;KC-C1 MSC1HG0OUW*,JFB?G1N'J$$```0000`"!J <+Q<S<4R)KLS#CVH6&?:\*YIW MU%&77R0#BAK?G'(^R 0W<=Y2T]_$11DD` ``"""!P` +DXK,O\]CN)Z[N M+W )13* J/$%89[XDIG^Q,9U:0 ``"""!PTP3(Q0U+BS<],U89?)$,*&J\ M0``!!!`X$P%R<4.Q=*:),N]:BF1`4>-YXW%4G028ODZ[&!4""""```((('`& MN7AS'P!SG6E7)`.*&L] ./Q2S1F=.&0+`EN;?HLQZQ,!!!!```$$$+ " >/E M8O\K]9)?43AJ$G*Q:*8.<8U^7>%HL^Y$PR^$'!U#D0R(?^]BO_]Y%B<7\^?) M9)95UR)_B_U$M \"N=B_.G+Q%FUMS` ``""""`P&CYY^[N;I1,JR2?C/[M MJ(<3/F"2(QV;3H:"/,DVZ1_.NAA=%P((((``` 4#F!&JN+R52^KQSZZ6GE MXFR+YLD^E^\L"""```((((``` V!VY.+23')KG$"I7*Q+P_:WRN1B_&9D)2+ M4ZJ&:)S: IDB,UIV#O"2B_P2` ``"""!PBP3(Q<M][V)<+D:DX* J6%$& ME%87UY*+D5LN;W%)+Q]S4A;V3Q'1BAMM*RR_0#T ``""""```((9!*H42ZV MQ8WA36[]Q+3?0#DHT] 1L$%F'\`?+2J.M E&4G238:E<[%_.5"TQTB:88\,I MET_U9"T[%'T3QY=DP'FX5..(BN;)R6B['`000``!!!!`H&8"M<C%FAD9VVP" M-0&FWYJP_A%```$$$$`` 7D$R$5R<4,"13* J/&\Z>ZH. DP?9UV,2H$$$`` M`0000(!<W%`LF5Y%,J"H,;9G(L#T9 MQF=:A*Z%Z<T!!!!```$$$$" 3 +DXH9BJ4Z3[SFJ(AE0U'C/JW"NK0DP_=:$ M]8\`` ``"",PC<*MRL?3+,TK;SZ/IJ(!`D0PH:KRN0=?MS30H)5!D^M+. MFR-0A5R<D:R7'E+:_N8,.6_`?2S);[H/3M'_#O>ILQ?) &3CX6CG7?7P*-.C ME&1\YI023IJ^='C:(X``` ``""*Q"X'BY.)6IQZM>H]7(R"'T0'*Z1.1B M<^QHL3%)M4 &)!L'$F58W>J/,Z=J.IQ%PZ.2W*[9H$ NKCM/K G<52.```(( M-WW.A-F.]CEZ'I6+4V)[W7ER#H"N` $$$$```000N`D"]<K%H/(S6MUJ$7?9 M?^209,)Z$];:=)#YU<4^YSC8I`+L7U&R\90('!UYI'(8D8OF2?X<&Q(.!'Q_ M><:[39H^?U1:(H``` ``""*Q(H%*YF+S5+=F DY'Y.>N*6&^QJWRY.*H* M1B^Y2`8D&Q?)Q6`\\0D3_)5H+)K`0USQZNZP\Z3IB\:C,0((((``` ,!: M!(Z7BX&N&ZJ[H8P9E8+Y>F`M=B?H)Q_:J()*RJHB&9!L/$\N1FJ)4[HW>5TG M,/U:E]"Q&K5.)LFDZ=<:K7X00``!!!!```$$B A4(1=;^=<].L4X]<JH7.QW MTI<!02=%=*[0>, GYY6AJA]E520#DHWSY6 M``$$$$`` 74)D(O//BS'ST8$BF1`4>.-!JS;0P P_2'8G10!!!!```$$$$ 2 M`46-L3T3`:8_DS5="P((((``` B<B0"Y2"YN2*!(!A0U/M,B="U,;PX ``" M"-1,H!:Y./Q0_B2UT>]C[(XB%Z<`QK_\H/_=$OVOU`L,E/F=$T4R(-)X^#TK MR>FAP2$$=I GAUR7DR*```((((```M<D<,-RL368ZF+1Q!UF\X'`CLOLH42? MXM]VNZ)<C&P$%!'0>#L"PYV(3*L5S9/MQJ]G!!!```$$$$`` 8!`%7*Q7\4: MBL"I&E< 78)ZU[`>%:F576I:Q`7VK<C%N/7;?82^-A[]!OE( V3[2\V9G(N- MS507][&1LR"```((((```J4$*I6+HWE_D(].U9>&^7T %R-Y;2F^6VP?KR[V MKRA.LB_.IS 4R8"B]RY.R?XI-3B</$,]W)<W\?:W:/>MQQRW2/SL1?-DZPO1 M/P((((``` $!'X'BYV,_+AR6L9`4I7](H$\4%WFC5L=/M_6/S*[1%,B"S MNCB\BJE*<E_^C:[Y_GQKKS0^28+V_,AP<R&PSM3>1("N:)[`C `""""```(( M(+`; 2KD8C+IC(B6)7(Q,Y?=S1C[G"B_+I?/=FKD13) '[D8&'WTOQ$]?,TY M&;R^"L=;Z61X[6N],DJ 2`;,EHO]N=$-8VC]?FTP_M=AAU>>,_ES>XIJLBI; M-$_RQZ,E` ``""""`P$("Q\O%A1? \)H)%,F`HL8U7[6QE1) ^E)BVB.` MY"*YN"&!(AE0U'C>='=4G028ODZ[&!4""""```((('"\7.Q_FZ+O0-]_1B:_ MDRVXZ1,!!!!```$$$$! E$`5<I%MCB(0B(=F&/%7VG$.VTR-OT &K" 7A^,\ MBO">YTW:I15OW9#B$CIG; 17%^D_?JZB>;(G4N="``$$$$```00N3J!&N=AF M" [+?7&Y.&KN8$D&R[-_^5.SA5RL9)(8! ((((``` 4$2 "KD8Y/W]K#U' M0NS+R+YIUITG-V<7`T8``0000``!!&Z70!5R,<`WFIX&1:%AFGN[-CAVY$.M M'M% HX(D,OX;DHO)6N6Q9LHY>XYUYE7_\D7UO/Z+YDD."FT00``!!!!```$$ M5B%P`W(Q(B970:"3ED".).A7('.X%<F`&3>C1I1M=T6C5Q=<2++\E7.QA[<A M%P\W 0$ ``""""```(G(W!+<C%'SYS,/+M=SJ .G`*>+ZYN42[F7]UNULD\ MT8R;48=ZNV F!)I\5*+WY?K4A13-DTP:FB&```((((``` L)U"[7&P3T.'; MI8)7EH.X;`]#DDG _?LVX^*J2`;$&P]O%DW>/CJ43T,MU'_E!)-JU'9]39A< M2 &TU=N/+K2B>7+9I>K"$4```0000`"!_0D<+Q?WOV9GW(U`D0PH:AP4LG:[ M^D,&Z:0(((``` ,`%"9"+M.*&!(ID0%'C"Z[5$U\RTY_8N"X-`0000``! MZ$LUBAIG,JFYV8K76Z'I:R9O;` ``""""`P&X$=I*+C6;PN"R!S-F<U`S) M;\[(/%'7;/C%DOT>`CD4G'UT,"LJJ-)KV:+]\&LY(GP"JLU_-_K"E2VN5)\( MPZN8^N[*%;^?LWYT1H `` ``"")R&`+FXX3OW3C-+]KF0B%R,*+J^/NE7 MPS)?[Q?!DFHPI\%VLG8?*XR>97A14UIQ5$8FF20+RP=>NU,C ``""""```)7 MR<6;FQ4&C``""""```(7(4`NUB*6+C+A(I=9OUP,JI?=M22UY>T:-^=.W?;J MIMZIF*.?R<7;G2%&C `""""```+G)D`NDHNU$*A?+G:ZJ%5'IY>+$:67_R=R M\=PAQ-4A ``""""`P+D)D(NUB*5SS[.<JRO]J)O=;D8=%8>GEXMQF9<I%W.T MF'S'77#VX6 MUB*6, UVXF:U:8;,REC?(C,.N46#KGZ9M9G^%HUBS` ``""""`P!8$R$5R ML18"%6J&(EU4U'B+Q;Q;GZM?:86FWPVF$R&```((((```C43(!=K$4LUSY)] MQD8S[,.YPK,P?85&,20$$$```0000*`A0"Z2B[40H!DNZY*8_K*F=^$(((`` M` 4#F!<\K%U6^66VC%TO&4ME\XO$H.IQDJ,<3^PV#Z_9D[(P((((``` MD$/ >+DXXW,4DQ<6R*W^AV<VQP;_3?:VL$'_8SF#BVW_ M,Z8_GTU=$0((((``` B< T!%<G'%DMK-R<5N, V_\N$<\RSG*FB&'$JG;,/T M40'<U[3-[T-Z-_%*D0PH:GR.Y><J6 ),;R8 ``""""```)U$MA5+HXB"(IX MK4P*%%1?_ U_C[?OZZYA;7#J1*-5Q*'J"V1A(%,#R9>O1?LGJG/>9(ZJ2`;< M0')Q^=QJ>BB2BS=1+S7([0BL,N5T `""""```(((+`B 5KD8E\QCM8/(](Q MWC[0HGU9&#FP5"Z.GB53!L=KIRL:>_^NBN3B_L-S1 000``!!!!```$$$( 0 MJ$ N!HJQ?Y-J4E!U]Y3VU>"HP P:3!TX6I"<&M+H28=GG[I5=?2]B\/&MSB/ M`0000``!!/()D(O/1//RG[BZ*]5^I>V7CW^C'LC%C<#J% $$$$```0000`"! M'0B0BRMHQ1WL=*.G(!=OU'"&C0`""""```((((!`0X!<)!<W)$`N\C((((`` M` ``""-PN`7)Q0[%TN]-BK9&3BVN1U`\""""```((((```OL3(!?)Q0T) M``('$JA"+G;7OY;,6ZN?`PUSX*G[4K!/LOL]'R^Y>*`=G1H!!!!```$$$$`` M 84$*I6+PXK6L`B9TV8AG0L>WDK!4648_"D'#KF80TD;!!!```$$$$```03J M)%"I7`SJC<,:5\XK=1*O>51#E3C*>?3VU-'K(A=K-K>Q(8``` ``"""`0 M70)5R,4`7T[E<" (BV3,[1ILGY%GWHR:E.5%<C$0J_Y[-0+[S&UG00`!!!!` M``$$$, G<`:YJ+J8;^_,ED?)Q:<>ER1P=W>7W'K(G+J:(8``` ``""*Q( MH$:YV%Q>Y(-M^DJF;=;A&!ZU(JE+=35*=< YR:2TNMAHI62?&IR,0.N#R,63 MF=7E((``` ,`Y"!PO%TLY2BM+B1W8OAZY^,(/_94_]?IO?-WKOO9KO_9K MOOE/?=-[7OS!`[$X=9\`N6 ^((``` ``"U1*X&;F8_VF<U;*^X,"6R,7^ M/<9+?G_5Q[_V+=_]YE_WN?_EN][UKH_ZMS_F`Q_XP,_^Y">O_Z9O^FU?^M^^ M275QWAG[1_V1/_)5+[WTT <_^,&?\[H?_XRO>.7+7O GO^!K?^0GON=3_]^_ M_>KW_;E_[X??^.M>?OGEIL%7?N67+S^7'F83(!=GHW, ` ``""""P-0%R MD5S<D,!LN;A*=?&KONHK?_(G?_)G_[&_]WG?\_>^[,5_^E]_[S_^>5_^WK_U M\\!]FJDN[L/961!```$$$$`` =D$R,4-Q=)LJYSFP-ER<14"C5S\B9_XB8_[ M\K_Y>6_]1__I=__]7_BZG_BL+_KK?^?[/_/?_*/?\*___F_[U__WJW_H];]X M-P\VZGFV7%S%$%_]U<^JBXU<?,TW_,2G?=U/?M87O_09_],/_KV_]NG_^-T_ M?9C3U,?)M#HP.. M&4'_=(<DS0=>[^BI`YTSO#ES2M ,>YLM%U=A\D?_Z%?_U$_]U,_Z`R^]^LO> M_^K?]\Y/_]U_[>?^[A_^N^_X]+_[]M?\[;?__)]\ZVM>_.9?\F,_]F--LZDY M0``!!!!`8`<"Y*+J8D (EWBPF9%N;B*;O_FUW_#C_[HC[SA:W_!WWWG+_UG M'_R/FI]__C=^Q<=^R0=^YFM_[&.^Y(.OOO^;O_P+W_;**R^__AO_9"`7AWJX MKYD[Y9:484D!V6\PE.5]X=<G'U0IE\O%'1S-Z"E4%X\B[[P(((``` $`F M;W_[7W[3&]\0R,5`IP4B>: M1U5TO"`9Z.&(/!X6)$\C%UN2JHNKS':=((`` M` ``"6Q"H5"[FI-HYJF9Y/UM`K[S/`-I0M_>E>/Q:9M^,NDIU\9U_[>VO M?_J;7__B7__^4;DXNHLQE(ZEXFVH14?59 1RZ1GSJZ"1D:QBD6"VJ"Y6[ H, M#P$$$$```000J$4N=GEJ:2H<)-_!'7VC<C'9YN+38DH8],M<F<78V7)Q+1/\ ML==]S0<_^&/O?-/G_I,?_<__G[_U7_V+'_^5G_ '_\9GON%??=8?_X?_\9?^ MX`<^\']]TS?^B5$-,U1K4^7N?LMXU7I841RMG\?'$XC8H(= V(')NL4R==3. M<K$=C^KB6K-=/P ``""""`P.H$3B472VN) =0,<N756=]*ATFY.)124Y<V M6RZN5<MZ]SM_H/DZC:;`^)ZW_(8??\?G_L-W_8I/_8-_XY=]T<MW7_ 7FW<M M?O57?673X%;L<KYQJBZ>SZ:N"`$$$$```01.1J`BN=BJM275Q5*Y.'6ND]FX M]'+B]R[F:\6V</3TZ=/,`33GS6^<V6?3[/O>^I8O__(_W"C&O_J6K_ _O_R7 M_>+__GO_NS_Y]I=??F_S8O.G83_]XG-F$35_,%H.": NFA4(((``` $"U M1&R^9;'1C2^^^,*45LRY*&W6(J"ZN!9)_2"```((((```AL1.%XNSKZP4D51 MVG[VP!S8$9 M%UOEO^+SQ[WJ"__$U_^Q7_\;/O</_:$_]*M^S6]J/ 5GW?[U M"""```((%!&X8;E8=)T:'T) AEQL#O&X&H&[NSO%_T-6J),B ``""""```)Q M`N3BL_>V^=F(0*E<;&2#QS4)D(L;K4'=(H``` ``"2PB0B[3BA 1*Y>+H MIY)Z\2($EC RQR*```((((``` AL06`_N7BU^^M<;TM B^_&V&(EZ!,!!!!` M``$$$$```00"`CO)Q48S>%R6 %6'``((((``` ``"MTA )[EXBVB,&0$$ M$$```0000``!!!"X, %R<<-W[EUY8KEV!!!```$$$$```000N'4"Y"*YB``" M"""```((()!'0'71+ (""""```((((``` (#J8IZ&OO4WI!H_` ``" M"""```(((+"< .JB700$$$```0000``!!!!```'51=5%!!!```$$$$```000 M0`"!/`*JBW81$$```0000``!!!!```$$5!?S-/3R>WSU ``""""```((((`` M` C<. '51;L("""```((((``` ``"JHNJBP ``""""```((((```GD$ M5!?M(B"```((((``` ``""*Q:76R$I <""""```((((``` ,")"=S= MW8V^`[,M/#X9_5OS!P\$$$```0000``!!!!``('3$RB6B[?^"3_&CP`""""` M``((((``` ,)M`K+HXNU,'(H``` ``""""```((W#H!<M&[71%```$$ M ``""""```((((```JJ+>=]3.5M\.Q`!!!!```$$$$```000.`T!U46["` M ``""""```((((```JGJXHF_=W+32WOZ]&F[?[#I672>),`0240:7(J`%7$I M<[M8!!!```$$5B30SR*:+YQ\_E$WS0E.4S;=\T+Z-/<\KW,%!!C"E$" 3\"* M,!\00``!!!!`8!X!<G'-6K.<;-XL7/THAE =J0YOFH`5<=/F,W $$$```00. MYE9[P1%]E9GBKW5IPYQL-$$/TO$B?;CU%0V-WKTR_&4M;JOW,Y2+<>8K#J!: MN1 HPV"!]_][0X9>T7#G[HI</+=]71T""""```);$&CRA_X'H&;)Q3:/[&>3 M\;+>5)UJJH><] &+N'S:6EP% XFHE$"NM/\->/9?'&T? 1]!%[=7A.?0W$.- M%R,R>(ANZI51[1=13:-J=F?"F:?+D8N!3!I>>$3XC0XC,LF'<C%RNF")C;:, M1%H'C:>485]+'$(XTW9%[UV<DF?#Z3HEL*?(]]L/SS)<'0'VX;*:6F 1B= G M%E^_HRUSUF"F430[D`"Y>"!\IT8``0000."V"/2U8L%[%^-Z+)+%#NE,B<8I M>RB29\O%`&/$9*5R,3E)1K<>BI;;4?LO"Z>!PSL"Y*+) ``""""```))`D.M M3?RH),\IL5&SA%A%+ [G5:<>^_`#Z\1W1OK2+M)_L(\PU7+4-!'1&U^MMVCH MY6OV(CV0BQ<QM,M$``$$$$! -H&X5FRZ'7GOXNR37?;`.G.RFG7=1E-EGB%N M%-2-#GLCT^MVE,"\%0$F` ``""%R$P)163+QW\2)T5KS,JG*R86UVQ2NM MO*MYAKA1W76CPZY\"IUL>/-6Q,D N!P$$$```000F-I6[KXSH^R]BX"6$I"3 ME1+;J#U M)88PC$H(6!&5&,(P$$```000J(I`OE9LAOWHO8O-D1[S"+0S8-ZQCEJ1`$.L M"%-7)R! 19S`B"X!`0000`"!=0D4:=='<K'H2(T10``!!!!```$$$$```01. M3(!<?%85](,`` ``""""```(((!`0>"X7VW<T>B"```((((``` ``" '14Y$KD) `` ` end
Feb 05 2012
parent reply "Nick Sabalausky" <a a.a> writes:
"Jay Norwood" <jayn prismnet.com> wrote in message 
news:jgm5vh$hbe$1 digitalmars.com...
 == Quote from Nick Sabalausky (a a.a)'s article
 Interesting. How does it perform when just running on one core?
The library without the threads is 1 min 5 secs for the 1.5GB directory structure with about 32k files. This is on an 510 series intel ssd. The win7 os removes it in almost exactly the same time, and you can see from their task manager it is also being done single core and only a small percentage of cpu. In contrast, all 8 threads in the task manager max out for a period when running this multi-thread remove. The regular file deletes are occurring in parallel. A single thread removes the directory structure after waiting for all the regular files to be deleted by the parallel threads. I attached a screen capture.
What I'm wondering is this: Suppose all the cores but one are already preoccupied with other stuff, or maybe you're even running on a single-core. Does the threading add enough overhead that it would actually go slower than the original single-threaded version? If not, then this would indeed be a fantastic improvement to phobos. Otherwise, I wonder how such a situation could be mitigated?
 I tried last night to do a similar thing with the unzip processing
 in std.zip, but the library code is written in such a way that the
 parallel threads would need to create the whole zip archive
 directory in order to process the elements.   I would hope to be
 able to solve this problem and provide a similar 4x speedup to the
 unzip of, for example 7zip, which is currently also showing
 execution on a single thread.  7zip takes about 50 seconds to
 unzip this file.
That would be cool.
Feb 05 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/12 10:16 AM, Nick Sabalausky wrote:
 "Jay Norwood"<jayn prismnet.com>  wrote in message
 news:jgm5vh$hbe$1 digitalmars.com...
 == Quote from Nick Sabalausky (a a.a)'s article
 Interesting. How does it perform when just running on one core?
The library without the threads is 1 min 5 secs for the 1.5GB directory structure with about 32k files. This is on an 510 series intel ssd. The win7 os removes it in almost exactly the same time, and you can see from their task manager it is also being done single core and only a small percentage of cpu. In contrast, all 8 threads in the task manager max out for a period when running this multi-thread remove. The regular file deletes are occurring in parallel. A single thread removes the directory structure after waiting for all the regular files to be deleted by the parallel threads. I attached a screen capture.
What I'm wondering is this: Suppose all the cores but one are already preoccupied with other stuff, or maybe you're even running on a single-core. Does the threading add enough overhead that it would actually go slower than the original single-threaded version? If not, then this would indeed be a fantastic improvement to phobos. Otherwise, I wonder how such a situation could be mitigated?
There's a variety of ways, but the simplest approach is to pass a parameter to the function telling how many threads it's allowed to spawn. Jay? Andrei
Feb 05 2012
next sibling parent reply Jay Norwood <jayn prismnet.com> writes:
== Quote from Andrei Alexandrescu
 Suppose all the cores but one are already preoccupied with
other stuff, or
 maybe you're even running on a single-core. Does the threading
add enough
 overhead that it would actually go slower than the original
single-threaded
 version?

 If not, then this would indeed be a fantastic improvement to
phobos.
 Otherwise, I wonder how such a situation could be mitigated?
There's a variety of ways, but the simplest approach is to pass a parameter to the function telling how many threads it's allowed
to
 spawn. Jay?
 Andrei
I can tell you that there are a couple of seconds improvement in the execution time running 16 threads vs 8 on the i7 on the ssd drive, so we aren't keeping all the cores busy with 8 threads. I suppose they are all blocked waiting for file system operations for some portion of time even with 8 threads. I would guess that even on a single core it would be an advantage to have multiple threads available for the core to work on when it blocks waiting for the fs operations. The previous results were on an ssd drive. I tried again on a Seagate sata3 7200rpm hard drive it took 2 minutes 12 sec to delete the same layout using OS, and never used more than 10% cpu. The one thread configuration of the D program similarly used less than 10% cpu but took only 1 minute 50 seconds to delete the same layout. Anything above 1 thread configuration on the sata drive began degrading the D program performance when using the hard drive. I'll have to scratch my head on this a while. This is for an optiplex 790, win7-64, using the board's sata for both the ssd and the hd. The extract of the zip using 7zip takes 1:55 on the seagate disk drive, btw ... vs about 50 secs on the ssd.
Feb 05 2012
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/5/12 3:04 PM, Jay Norwood wrote:
 I can tell you that there are a couple of seconds improvement in
 the execution time running 16 threads vs 8 on the i7 on the ssd
 drive, so we aren't keeping all the cores busy with 8 threads. I
 suppose they are all blocked waiting for file system operations
 for some portion of time even with 8 threads.  I would guess that
 even on a single core it would be an advantage to have multiple
 threads available for the core to work on when it blocks waiting
 for the fs operations.
[snip] That's why I'm saying - let's leave the decision to the user. Take a uint parameter for the number of threads to be used, where 0 means leave it to phobos, and default to 0. Andrei
Feb 05 2012
parent Jay Norwood <jayn prismnet.com> writes:
Andrei Alexandrescu Wrote:
 That's why I'm saying - let's leave the decision to the user. Take a 
 uint parameter for the number of threads to be used, where 0 means leave 
 it to phobos, and default to 0.
 
 Andrei
 
ok, here is another version. I was reading about the std.parallelism library, and I see I can do the parallel removes more cleanly. Plus the library figures out the number of cores and limits the taskpool size accordingly. It is only a slight bit slower than the other code. It looks like they choose 7 threads in the taskPool when you have 8 cores. So, I do the regular files in parallel, then pass it back to the original library code which cleans up the directory-only tree non-parallel. I also added in code to get the directory names from argv. module main; import std.stdio; import std.file; import std.datetime; import std.parallelism; int main(string[] argv) { if (argv.length < 2){ writeln ("need to specify one or more directories to remove"); return 0; } foreach(string dir; argv[1..$]){ writeln("removing directory: "~ dir ); auto st1 = Clock.currTime(); //Current time in local time. rmdirRecurse2(dir); auto st2 = Clock.currTime(); //Current time in local time. auto dif = st2 - st1 ; auto ts= dif.toString(); writeln("time:"~ts); } writeln("finished !"); return 0; } void rmdirRecurse2(in char[] pathname){ DirEntry de = dirEntry(pathname); rmdirRecurse2(de); } void rmdirRecurse2(ref DirEntry de){ string[] files; if(!de.isDir) throw new FileException( de.name, " is not a directory"); if(de.isSymlink()) remove(de.name); else { // make an array of the regular files only foreach(DirEntry e; dirEntries(de.name, SpanMode.depth, false)){ if (!attrIsDir(e.linkAttributes)){ files ~= e.name ; } } // parallel foreach for regular files foreach(fn ; taskPool.parallel(files,1000)) { remove(fn); } // let the original code remove the directories only rmdirRecurse(de); } }
Feb 06 2012
prev sibling parent deadalnix <deadalnix gmail.com> writes:
Le 05/02/2012 18:38, Andrei Alexandrescu a écrit :
 On 2/5/12 10:16 AM, Nick Sabalausky wrote:
 "Jay Norwood"<jayn prismnet.com> wrote in message
 news:jgm5vh$hbe$1 digitalmars.com...
 == Quote from Nick Sabalausky (a a.a)'s article
 Interesting. How does it perform when just running on one core?
The library without the threads is 1 min 5 secs for the 1.5GB directory structure with about 32k files. This is on an 510 series intel ssd. The win7 os removes it in almost exactly the same time, and you can see from their task manager it is also being done single core and only a small percentage of cpu. In contrast, all 8 threads in the task manager max out for a period when running this multi-thread remove. The regular file deletes are occurring in parallel. A single thread removes the directory structure after waiting for all the regular files to be deleted by the parallel threads. I attached a screen capture.
What I'm wondering is this: Suppose all the cores but one are already preoccupied with other stuff, or maybe you're even running on a single-core. Does the threading add enough overhead that it would actually go slower than the original single-threaded version? If not, then this would indeed be a fantastic improvement to phobos. Otherwise, I wonder how such a situation could be mitigated?
There's a variety of ways, but the simplest approach is to pass a parameter to the function telling how many threads it's allowed to spawn. Jay? Andrei
That cold be a solution, but this is a bad separation of concerns IMO, and should be like that in phobos. The parameter should be a thread pool or something similar. This allow to not only choose the number of thread, but also to choose how the task is distributed over threads, eventually mix thoses task with other tasks (by using the same thread pool in other places). It allow to basically separate the problem of deleting and the problem of spreading the task over multiple threads and with which policy.
Feb 07 2012