summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMuQun Yang <ymuqun@hdfgroup.org>2006-05-11 00:07:28 (GMT)
committerMuQun Yang <ymuqun@hdfgroup.org>2006-05-11 00:07:28 (GMT)
commitf857bb3d755e753409319c9b9ffa02c4bdc316b4 (patch)
treedb9018f9b793a9ef356b476ce47a185083c9a274
parentb415a49c9e0978f75abbe6e8916dbaa376d2f6c5 (diff)
downloadhdf5-f857bb3d755e753409319c9b9ffa02c4bdc316b4.zip
hdf5-f857bb3d755e753409319c9b9ffa02c4bdc316b4.tar.gz
hdf5-f857bb3d755e753409319c9b9ffa02c4bdc316b4.tar.bz2
[svn-r12343] Purpose:
Bug fix for collective chunk IO Description: Several options have been provided inside HDF5 library for obtaining chunk addresses when doing collective chunk IO. One option is to obtain chunk addresses for one process and broadcast to other processes. This option needs all processes to participate. If using link-chunked IO without any optimizations, sometimes this is not true due to the random initialization for one variable at mpich 1.2.7. This is a bug inside the collective chunk IO code. Solution: 1.Initalize all the variables to some safe numbers, 2. Avoid using MPI broadcast to obtain the chunk address if possible until more performance studies have been done. 3. Seems okay to obtain chunk addresses individually for each processor. This option may cover most cases. Platforms tested: h5committest(copper is not usable) NCSA teragrid (mpich 1.2.5) mir 64-bit linux (mpich 1.2.6) Misc. update:
-rw-r--r--src/H5Dmpio.c64
1 files changed, 48 insertions, 16 deletions
diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c
index 8c7778a..c290f9c 100644
--- a/src/H5Dmpio.c
+++ b/src/H5Dmpio.c
@@ -69,7 +69,9 @@
/* Macros to define the default ratio of obtaining all chunk addresses for one linked-chunk IO case */
#define H5D_ALL_CHUNK_ADDR_THRES_IND 10
+#define H5D_ALL_CHUNK_ADDR_THRES_IND_NUM 4
#define H5D_ALL_CHUNK_ADDR_THRES_COL 20
+#define H5D_ALL_CHUNK_ADDR_THRES_COL_NUM 10000
/***** Macros for multi-chunk collective IO case. *****/
/* The default value of the threshold to do collective IO for this chunk.
@@ -646,7 +648,7 @@ H5D_chunk_collective_io(H5D_io_info_t *io_info,fm_map *fm,const void *buf, hbool
{
int io_option = H5D_MULTI_CHUNK_IO_MORE_OPT;
- int sum_chunk,mpi_size;
+ int sum_chunk = 0,mpi_size;
unsigned one_link_chunk_io_threshold;
H5P_genplist_t *plist;
H5FD_mpio_chunk_opt_t chunk_opt_mode;
@@ -790,18 +792,18 @@ H5D_link_chunk_collective_io(H5D_io_info_t *io_info,fm_map *fm,const void *buf,
int mpi_size,mpi_code; /* MPI return code */
- int i,num_chunk,total_chunks;
+ int i,num_chunk=0,total_chunks;
size_t ori_num_chunk;
hsize_t ori_total_chunks;
haddr_t chunk_base_addr;
- haddr_t* total_chunk_addr_array;
- MPI_Datatype *chunk_mtype;
- MPI_Datatype *chunk_ftype;
+ haddr_t* total_chunk_addr_array=NULL;
+ MPI_Datatype *chunk_mtype=NULL;
+ MPI_Datatype *chunk_ftype=NULL;
MPI_Datatype chunk_final_mtype;
MPI_Datatype chunk_final_ftype;
- MPI_Aint *chunk_disp_array;
- MPI_Aint *chunk_mem_disp_array;
- int *blocklen;
+ MPI_Aint *chunk_disp_array=NULL;
+ MPI_Aint *chunk_mem_disp_array=NULL;
+ int *blocklen=NULL;
int blocklen_value;
int actual_bsearch_coll_chunk_threshold;
int bsearch_coll_chunk_threshold;
@@ -810,7 +812,7 @@ H5D_link_chunk_collective_io(H5D_io_info_t *io_info,fm_map *fm,const void *buf,
int many_chunk_opt = 0;
H5D_common_coll_info_t coll_info;
- H5D_chunk_addr_info_t* chunk_addr_info_array;
+ H5D_chunk_addr_info_t* chunk_addr_info_array=NULL;
#ifdef CC_PERF
char *bc_percent = NULL;
@@ -858,6 +860,9 @@ printf("before inter_collective_io for total chunk = 1 \n");
ori_num_chunk = H5SL_count(fm->fsel);
H5_ASSIGN_OVERFLOW(num_chunk,ori_num_chunk,size_t,int);
+#ifdef KENT
+printf("total_chunks = %d\n",(int)total_chunks);
+#endif
if(num_chunk == 0) total_chunk_addr_array = H5MM_malloc(sizeof(haddr_t)*total_chunks);
@@ -899,9 +904,14 @@ printf("before inter_collective_io for total chunk = 1 \n");
/* Calculate the actual threshold to obtain all chunk addresses collectively
The bigger this number is, the more possible the use of obtaining chunk address collectively. */
+ /* For non-optimization one-link IO,
+ actual bsearch threshold is always 0,
+ we would always want to obtain the chunk addresses individually
+ for each process. */
actual_bsearch_coll_chunk_threshold = sum_chunk*100/(total_chunks*mpi_size);
- if(actual_bsearch_coll_chunk_threshold >= bsearch_coll_chunk_threshold)
+ if((actual_bsearch_coll_chunk_threshold > bsearch_coll_chunk_threshold)
+ &&(sum_chunk/mpi_size >= H5D_ALL_CHUNK_ADDR_THRES_COL_NUM))
many_chunk_opt = H5D_OBTAIN_ALL_CHUNK_ADDR_COL;
else {
@@ -937,8 +947,12 @@ printf("before inter_collective_io for total chunk = 1 \n");
bsearch_chunk_threshold = 1 +(total_chunks*bsearch_chunk_ratio-99)/100;
if(num_chunk > bsearch_chunk_threshold) many_chunk_opt = H5D_OBTAIN_ALL_CHUNK_ADDR_IND;
+ if((sum_chunk == 0) && (total_chunks >= H5D_ALL_CHUNK_ADDR_THRES_IND_NUM))
+ many_chunk_opt = H5D_OBTAIN_ALL_CHUNK_ADDR_IND;
}
-
+#ifdef KENT
+printf("before sorting the chunk address \n");
+#endif
/* Sort the chunk address
when chunk optimization selection is either H5D_OBTAIN_*/
if(num_chunk == 0){ /* special case: this process doesn't select anything */
@@ -952,6 +966,9 @@ printf("before inter_collective_io for total chunk = 1 \n");
HGOTO_ERROR (H5E_DATASPACE, H5E_CANTSWAP, FAIL, "unable to sort chunk address");
chunk_base_addr = chunk_addr_info_array[0].chunk_addr;
}
+#ifdef KENT
+printf("after sorting the chunk address \n");
+#endif
/* Obtain MPI derived datatype from all individual chunks */
for ( i = 0; i < num_chunk; i++) {
@@ -1012,6 +1029,10 @@ printf("before inter_collective_io for total chunk = 1 \n");
coll_info.mpi_buf_count = 0;
coll_info.chunk_addr = chunk_base_addr;
}
+#ifdef KENT
+printf("before coming to final collective IO\n");
+#endif
+
if(H5D_final_collective_io(io_info,&chunk_final_ftype,&chunk_final_mtype,&coll_info,buf,do_write)<0)
HGOTO_ERROR(H5E_IO, H5E_CANTGET, FAIL,"couldn't finish MPI-IO");
@@ -1070,7 +1091,7 @@ H5D_multi_chunk_collective_io(H5D_io_info_t *io_info,fm_map *fm,const void *buf,
uint8_t *chunk_io_option;
H5SL_node_t *chunk_node; /* Current node in chunk skip list */
- H5D_chunk_info_t *chunk_info;
+ H5D_chunk_info_t *chunk_info=NULL;
haddr_t *chunk_addr;
H5D_storage_t store; /* union of EFL and chunk pointer in file space */
hbool_t select_chunk;
@@ -1469,7 +1490,7 @@ H5D_sort_chunk(H5D_io_info_t * io_info,
H5SL_node_t *chunk_node; /* Current node in chunk skip list */
H5D_chunk_info_t *chunk_info; /* Current chunking info. of this node. */
haddr_t chunk_addr; /* Current chunking address of this node */
- haddr_t *total_chunk_addr_array; /* The array of chunk address for the total number of chunk */
+ haddr_t *total_chunk_addr_array=NULL; /* The array of chunk address for the total number of chunk */
int i,mpi_code;
int total_chunks;
size_t num_chunks;
@@ -1483,6 +1504,10 @@ H5D_sort_chunk(H5D_io_info_t * io_info,
FUNC_ENTER_NOAPI_NOINIT(H5D_sort_chunk)
num_chunks = H5SL_count(fm->fsel);
+#ifdef KENT
+printf("many_chunk_opt= %d\n",many_chunk_opt);
+#endif
+
/* If we need to optimize the way to obtain the chunk address */
if(many_chunk_opt != H5D_OBTAIN_ONE_CHUNK_ADDR_IND){
@@ -1493,6 +1518,10 @@ H5D_sort_chunk(H5D_io_info_t * io_info,
if(many_chunk_opt == H5D_OBTAIN_ALL_CHUNK_ADDR_COL) {/* We will broadcast the array from the root process */
int mpi_rank, root;
+
+#ifdef KENT
+printf("Coming inside H5D_OBTAIN_ALL_CHUNK_ADDR_COL\n");
+#endif
root = 0;
if((mpi_rank = H5F_mpi_get_rank(io_info->dset->oloc.file))<0)
HGOTO_ERROR (H5E_IO, H5E_MPI, FAIL, "unable to obtain mpi rank");
@@ -1559,6 +1588,9 @@ H5D_sort_chunk(H5D_io_info_t * io_info,
i++;
chunk_node = H5SL_next(chunk_node);
}
+#ifdef KENT
+printf("before Qsort\n");
+#endif
if(do_sort)
HDqsort(chunk_addr_info_array,num_chunks,sizeof(chunk_addr_info_array),H5D_cmp_chunk_addr);
@@ -1624,9 +1656,9 @@ H5D_obtain_mpio_mode(H5D_io_info_t* io_info,
hsize_t ori_total_chunks;
unsigned percent_nproc_per_chunk,threshold_nproc_per_chunk;
H5FD_mpio_chunk_opt_t chunk_opt_mode;
- uint8_t* io_mode_info;
- uint8_t* recv_io_mode_info;
- uint8_t* mergebuf;
+ uint8_t* io_mode_info=NULL;
+ uint8_t* recv_io_mode_info=NULL;
+ uint8_t* mergebuf=NULL;
uint8_t* tempbuf;
H5SL_node_t* chunk_node;
S)Q؏2O#GbXBZAE(N}C'yl>UM`!؄o[g# ;*?8&9:K,@hQRCI SPV&@Yj ʚ"Qň:Xbx{݁){MvrA(1x>v%דmDE {TOQ+C?6T培?+>M:Y+tD-y? I&,k2-/ Nf]gR $%O-r1A0A_t:\MYYy;6LN@P7VWR\7 ~)A\>fnjzVC߬7߬-Vr,= LMQw ecDѴ*7 =93MdtԻ jfJ Ў6 !ez(8v/c3$Sqx5r R9"}6:{~>"3cU13Q%ʥT{ I01`YZ#5[|;'J'W <*bY N^8{'"7R*ޒfJ$+i|ntА{x67Y!X-ϣtoJYL >|Ȩ T]Jiq cɨ;ɪsTNy1.n5%&9H}MMi76Ylx,垒o"2`7B\Ce\Q`JM>hxS+LZm"Aa#*)Ž}DS0/jJyWX ZACh*4i 0=i.ZR>;χr7h^7ɲ8^\yjv rcb3`X`};\>"IuxIHV4h^ɷ+.տ<./W?WK_h>l^xR(/.T&J6*œ5ljrX/ `EcOx_PŖᮂ0Ҍxt#y460O:{z7/F;of]' FDN010Se!Q/q=\D5j|ѮWϏ9nXmϮ044\ȯ߾>~{8:)lE$"d͍fceyѬ5N~guOv:I҇嶒xiIQ1,TE7n!a>pʀ'%c<0{5S 7*r0{m)R~H̤!vG !rO-#JP`C@Mrvf:zrbнr mQ/9 ctIFK#4WH(LY>tӡمt&Sb((^9J^C<ylG^#yzt"Lg=ג24c 9@vٵG$-%WAy@؂'Tj K Y4"ٕaI;rŌ"**N޶ %U7ʹI %Nن\@,`˥a%pKP07$#x!+~A,h|'Jョ^UEɐݞǃlFc|"˵,?啕h.'3:k ӼI6'~bdMf4Og̊l^ڧa}4fn]nA O&7CqzX !em?$LMhd] 8niQzR.;J|ȖUr"dѤKRNs2KBTtÉ2$Yfh?OqPEaF%+Fk+ 4qi-W0 0T[DeU(ȧ'} N,}H񴜂*f#%lٕ7-:4VT=Ъ+ƍ+SMvY<7bg5_md"vg6a4xogM[ @ͱd |[`Ղe@G:܋Ulq'%՛VyH KCn/k+iCmqq~}OI?Jߓ[4Q3^`ϓ,(t{'Ok~ƪ'''@V&t&X,4?5?g `f fɓ;+O5O2OٹYh~ߨ0b'=%.?sv_ܿj9xV`uJuw޹aԫՕ;Dwl_Do/?])W!͝D~˻`5?lI-~abh GNl1mF^DYdʒI֏Ϟd4Vz?lI֏Kz.zC䳠2IV;@7AnAu5D˜}{<!8F(_7BLժKYS)hqѦ dx/hHaE8\dmz[.$R[&pR{OMJȆ>M6Ȕ|9ãLܰ&WY".=ssnv;: 2up8Bre ᯾׃PFZmym5QZHYf4a\7v7 ݞ?U2I,}{YcmX[2<ܼhE޾/;?n0~>ahӧQ,X_?/xPꈖވbaj5xg\`+0⩨.z 4bY#uA͸8 h=8=Q݂kK+6-ω6ON6+T_};7F%n )Cݵܛˉ"`VQrOf;x{߿y<3,p7#+dn;z沈:Ýdgb߳'K1YM*t8jrvN="e]m:Y̨$5.\Ŗ)td`CdhӫÊmL~?{vtDSC$ҷnoK@CZ,d>>,ו/Tѷ^֠g{b5_q"w^,Cx]tOya2Ҷ3J#2^)\5QiK7L<ǧvBy*jxxIX.W'Л4bO1?ƍ<@-HxA.ZwTr,m'<]o6N86.{09>:O%/T?}쑷0ˆ%ȏt޵[`<B͞zJA ΪZv8gT#G-<f(uE{)İ0 &5e+0`<(#0ݙB"jf$-aj]ĥipdЄD!dž]M* ѸB/I#U4]V:fB۲I$ )q1h/|ŎȥX:aSѬ s]#j?W BFݼAJATb b,%m[-^⊏p[pG঺䖵_JyDFZtFB)#2eiVl#;RR+&Tܲ^ݟn\K&ׂV vBt7zMU#D:&\r,}E6GbdmŀX[3=|ݽ0N+1\Eg>2fq3YhK&P7@U"9#Dd`M:W6kj`4F tL^Yl_â:q1oA!Q݀p0im1ٲZ%baFh"^m/mK2watg1Js\8QM3@N=ZE%!LC`Dh?7VACs}^Ѫx"YyHi_4Gjs'ʯ'elX$+QnU|R99%Qqn96|V "26S>X!R'GO]eѧ&(Zc-==b]ovU\Mak3ݰi.5Ωݙaaфwh\D*g`nsgzfO_J1 41K ynhH񋚝YYKPqNviU_(csp Cz?~ :d%{"= FcWl_yA|S%k!/rf\ #7#q"^(79EAxEһ\섙t P HL67썁:n!%v(hL`[{@`̲An//JuoqY}50m{L[c7 Vd/fp%RқBA찎H=veGC(]h<7 pD3l\n'0 mGti#-Ɲ#VNF I6HtpFgze:9Y袆[ڙы͞ dn> E>zӯj%x"oY, ̣Hd";:ts#sسQW+B!ӝOM k? v.7{hUFǿ@^wF-!CcbAyݸ;ow8oƋ[0]{.ҧdz];Ɣm*oU=YUw g;k%_ٽglk&WrpWƼA+ۗ&R0Sc&j%!@Z8$ Ô=zDHb`u=Zpe {' ewMѻq2 y HR,8D;+F>i6>Wp=k3@ ? ֚bN$FF _TTg9QGWOƮRM\Y ZD;Mr<=une 5v;1`7 ϣ ]Cc; ]".)@szᓀ<\E~/> g{4 SF^@ `G4ZD(q9: C~*r*n0x>BmG/Q67jM7%m%|J"K,sx,э"z`gɮ "IWB汊m):o)+/>牔4]x o~I _ > ~!WQW Q)[,AQ2|i4qh؏2ɽ!2z;G|!S<Ϋ\1 ):zbkNrFm&LfwIn eeu=z d *:p <4 ::7<$ȹ%oIؐWBk-F%\&6khIvٔAdf)6(*2AE~CϔwTNgM\rg'qټQCWLzWM7^E^%WtcMҧ$fK^"?neqh0HO^_7.eV!zyW`ۏP1XT%d\>e;XpVZ`"X]S{.=nR[S8Qcq8RUj:SVQQ[Fd>T/}!ӃE^FwI&wWK&=L=s%ZsT lҭ|^)S+gnrrΓDzFnz M\itL~By(W*Jq^)kL"(*%"r ݰs5oIgEDFK&6?jϣ%lQNw#G CڻqS@`nj5-K _ ¾TxH\E(Cb}qdMQ2F?hZ5%)~WQ)ov'I](Y\zISJtKpT|]bc Ka rŀcWרE*W-h?-&§qUDټTb#zr=k;FN8] ueɺol&  Zst\BKwfD}2c'pa?,Wk1NB. nV7> }r`/4d,b7PP#J_Kf 7jM6"J+~lyyM>_tӊd\As3stM EDl|#|@coj>yzFz(7kG.%2SIesÚ AAH ~3A͋dZ_\ض]C2iWb3G8|^ F<+?#!vqzQkxGF?Ұi_d~Eҏ- #UTKԢk|E=TsZ?c@K4u)qy8jxG #W*.(Y1Sr8YBs MeD0"[gɑ+򦎖wpyh>j'b.%-w6Rp%_ g&S l$blS' Bʞ?YAa|늘N#qI`rQo\Bz,Lp<%DBJ)Qo;&p"UQ\r)3%C.ўTMt肸Q@'յϬkaMYI|28&gㆼrJV$r~"6jڂ&671W+7 ä[Q$@TaGRftA).IgUl_dj}5{_hɒ.W̝;B<(@ࣈƌ)0a`~}+V q͖-HYDV\Pk)*7,~CM+g~qG 3Y2b /;E00H-@i F'':!ު QP#XJE-2p1x#o,!'/TRnTqYbWB /Rjc8hj(#kFK/8BY 4{9C>v3!izyn A3qcRγ{t.CEM]1.<~ 2Qv_Ph%n`Iܷ uBC'$|\׆7 jDF_mC7(BD(9r=SrN\=RpnūGS*BF7v̡TIe4(p6o&;(> FqFΩc [֭g5@TfJSL*7tTmZ`hxl& ^9Hv?/0Ip%VғDQ֑OT( Bz+)7rS@ m')`@'xc]%%mQdMnr:hEreD,FF1f{Pu'Tbd*Fs ?[MνS++V>N3NV;k;d*HJs.\ʕϦM;w3J%aC+Fab!ע^I{Cso [+ACWU(D?J:'3oM0'xgؒ|J/w#iy[(?=}4?o^fw5c'Vjz:(HB&)[k*qD6 NY70xk66aOZb,Ӊ?dQn h*OE g forZmzrjkEXD|Lf9X7`P= Ÿ'++[WSw6@;7ǭ\لQIkַ'L$Lɕ:.GQ q=DxDtE & oJ03Q¯yo0947b7YTzA tB颀s,~ḷP6a7n'O^8w.]$IGZZ LRn檎\%66^%·d\4b*(J>"\VqvAbDN{PIٮŀI+)?O0 * GIѓ8s40&;P/ @(8h*^ZeɳU$w|#{R &H dc^Q&QqC%9\G ndR)s=иVCQnr1n$P@ hFH+C shǥ 9_"n̮Zrzd m$[:<~Ѻmèqb4A G1uB\øf M-%*l0Vb&zk¬?KN0ܤ*n?Kd5Ye׏-ERDU%Q%A&mIc 5 -f~$fO[¨dbO@oӖ"#t <%5 bF0ޤu*2/rʬr-K4hȴzvnKOj==Iwzdݏ奖7 ^V$CUQģ+ʍ"#R2 .`gx|f$S8CJ^. CFmt|'-К0ܼ*Z~\L@߉S0ab 'ґy &V~(wѵj3ymh]kZ~G^fo'߶fpժfQvf14`LvwMk,l$=;0Ÿ_R>݊˸M=%8)a" |)P5Mnv1nΐ`n) fFT(SP 5Ժ?y,ePO(3jE;Hv|X7nK']?']@ɞku:t?+.N)Z?v \:rw,Rㄱ&8G@No׵zkյRR{?׫˕SoPA:|֩ imm>!%?KS--WVjk^֖z*O]>ٹHZerGE(Q֪bhK>C'zuJYe nag毄7 U EZzb \P8Up%oBƸP,,h o6^-}ﻣ EZmG.sQ]WbHׄ7N](F ^ݟ1**7+{m:nӉ)؎VPW2{?v;_Ñs/ŞqPTC\Bz[4`Wl .[Fg{sXɈJkD\pp&2Khge{D-z_F\n 5!續sGSe!ys_>N=S翶jj9h8topngmπ;e<ҽ}]ڃ) TC/M/]Ǵ󿶜:WVCj=&#58~}O7Elm{[Hl}%J(Ji4/N)*3LWX?ɔs&%%$*Knq?<&TDBp/ HL$<Hl$s֟,W0ZOg*yU[E})_<|.ޣ6:8g#Efo?A_cA= +9jͦQ~Mc ^Jcj鿹_Zυ4n'Λ5ۛ 5ýG7SioiFͅ}A4wv6m9n47VƏUuhz/)?WWg8'J硨_6D}nm"zE lAk\Z'5T`WzԇWr3"HQT`0@ЂhGȮ߀X|Hx\$ZڭTff~%GmgЮ.WP@Ǘ~=:Y¬Gzijbktvlj\uOU%sNE*&_na>%RCǡ_꺡KqC/,rCd˻{ߡ]Qi|8T~YF Bx^+1{_];vF%$9-ts%>r-oc ɢr xs+ )ʆ(U^CSɷډQ]KK35g# rś !^r!c.>~{xk׫+5HUWJ=osteVӽiL+ioy#Ed0N_-꘲WZ]i++O1Rq}S n;M<8gv}Twp ;yt `=n8=%pP ]=N;l%=| $EFɜV\Wza_RP|]g0>x{]xE9Jۧ=gK˗/iW ՘c=mF#.oj;/ /n?pCjEv  qy /?ۤO&F g=I3Q_Nw:}U#~{&o隲kϠZfB/LK_3~)5T+Ŀ#Q<7ETO93c_ن؍{^TD=hL`V`(ܰS^6<5=yjx 0i2=\0~Y{8/r-y[ǟ l٘8 j+lVPQ=:%jZ%/#xlYF9y, Y7u8G81}Eo K8깃<(~'۳7*݋gq/7OVWSU!wGxmrG,[;[o[[Gn:N;\ M]|`H.FVk4'HQ?A?bR-sԉuェ˺qrh=>|{qfQos֌\ fcը+BYv.6E,чX ?wr@ ydC䙷'⹈_{5KW_b<ts9Bz;1P|@[1vP-;uEߴn> xOo+\Yf~j_Gg*@S?KY?d^[ͷGǨzqt]c_L?*ԩ+dyN~H9=*o9CYn7g 1Wwsbq{W _r0W$sAӑV=p?* r+L u+g1l8X)q/jq-^#aJ4dpN|1 {2Vu=tyn؟UYl@=QLd%iB?h0`Pgm 6v@bͦOЄ.dfA9qޑ{&:gQoͰu5_zV?څWPy|S`#\/ l!E@h]+xl RƆJMp{bk|Z]&]b=pP%I^U YÎGLp^:Ȩ2 (]sumNƪa8CZ;Ho;{ k(p{g%< XC^^e4ruR%!6!R{]M( u./QHCK ޔUNU`4c2%k7& 8qg(X@,M?[;G/^_M&{ɨw+kVciOoWWSKc- Zt!@{jutw4\Kg)5gIvϛvhf2s `_[N[/Y?d[?q 7]@/Im (:wC楝y!{B >d/>]Rwm%j?璌_ͷ۰m ˃כDѹs o*0.4)Bزs8Ǎª v]6֜; ŚGM2E"ne>@P;uh/q, P.b .dnV9z#Q&9N'_w.QА^ ;@z`fq4P4'J[B*39 sD Z5F92=F5(bjr,9o a+W .McˊjY}xH0nr{x4ʚG#Sywo瓬3BM,RAaKwU]I]YϜ;nFO%áEZ tS(ޱ(A;e;պ7K݁9uap&iOop7MQ摬 Pχ3ـ!2ȷZԶ[^"X6~?8Kc -^mor;kXt(^.FHP?ׯ$Ge " VuAJ>e7TZ*RsHŸ Z -zN)=n|o'l?H3sciVOk6\ ӈSKG+zmV6u;gH3jd1U+Uk;~g`Vh> Dšs77/Z5A=E>Oo_琽Z((`n *3tu,ZT\-תL#'lZ':ݏ;E-0PIl< p _.W|aZ/o#m–?<<8:Fׇ{#4 Ԧ~uq:?Z hvzAIşth,EDR|^B/itv-kNx!h5 f%nzG۰lP 0Et2eUoo(6pX1Jλҹ^ K<,?ːM,kUk?Xpcn0x2 v4KHo) 4AZE)PRc>7y)Td9lj]Z@ l9\aNb"d (0B8=o0*-~G J<:< љOFg.)Iq#| (؝wN}3u&H"[Ho)&[I.U>YYY${}p|"9^LxW5[JA@䃟cT5i ߲GJ1NryX؊>z/-V<DT|PTQ) ~uK$ z hHzT:Ak/;&k0)2tG'Jҿ6*G\F?ґXR&nOнw\x[h3Z5ԃ̘\Pÿ|\g2{o^v<*k4oA+kOʯJofhQ2H ڵcT1zy,/}sfCʵi( "y4^xX,tn8<b.S埔I'f#` ?2?K!{cy?}sB^]YVKH$?'׍-6ǥi1`W<"J:2d[{6]"`fC߆_N+GIߑG}SXiu_O]׭y$[CxSxlmmlZnj G~R1 :<:8>>k}8j*3QSn]`qdU<Ӑ0`Vp1F ҬWRߖKVs큧{)FS)o+G2? O#2\Ҧg"A :@—tFܑaX^(IAf\pœqrؔBk̬nADRXSh#U#8;o_5Ъwx3vs7L%wHfyVLS]Ypoova ack  jb{G}B\;/굪\X~)D[F 6?[6OpnU3FX%;Z$aKGvXGO0 @Ehoxٽ]{#v6y?;owrjOm~-Mmǖwii (Ϸ"| >ac "|.wWs Ne\YZ?WV]zuU~.g-/k.,MxX@HlD&Imez}Bs_qsek_']f-f^]fCsDoJ'MMy@䷅mQ6^7XePAz'j0U b/i&Z5璌g-??tO܀ʚGow\^Ibg?}++$?DN~N?E7qYV^:ʛ ^7x@_^k؋1}*/ :>:(MgxCz?G?,c"*`EjtnfW5V٧{ {]e{iFEcij-o[Aga*Pk%;{Mqƃm& aՉsstijgqx{||vE'X,SWK,8n04PT0{a }E޼ sَVJK>eq/ ׾6_|xt6ۮBWՕj/Bѳlcѯx{)0ɶ.#=%[8.,u:V0Ŕ[P+&'J ׉/Y @oao1a<3>!|u:yO&fȕ›^^7GƆ㴷:>nX7w7M/jZ*/~ժjD>WE5AEj :~X ۋ&8" ]@_;T8u;mx{}'fs2'0]X9Ka_LFӞM|2`w[~lv;B WS?\ZyͿ=!/ju})PsG#>Oxג'Ya?x@Ely& dZYXOc#Shgiʰq%t2mXhƝ19:j YXA/. =;7?a4nBt{vW7ܙ犢J Y haHJ _ C477i߁_Z[Z?J/VWV,?dK[L5hÒ=؀WIθ5(T c~ Z"e}ş)#//"P*O9 xiSI?ߪG|\sϛcio~N'Yi2U/,K-o? l`hz b?6Lqc; j`ŀ>CX/w>ϺUb䶻-)spBt9z/ۓL9%F^FP6y T|9,.ϿaP`V_ݧJr _6c$N=x~rff8揘<`*T-}p)΄r4׍jG? 趝" p>ja$ xbB+ 8 !RnQ1,!Xh .O[] W1?obSGԈ+CYsLn@1DIr8jyUzprί}[Ĩgfg׻|t򺉗 #9Ac;KH/Zӧ5Li%{?dK[ |ꝵ}6 ;u_β){RV8rus"uc+w41K? zoyH7bS,,y][v?/s_W4 !d4<-o[k>Σ[~ks[߲P-Tî# m{ kkpSs˾Q0Z8|H߇-CߤַGU|t%7[sH1x/h^Of9̿rVH-o̚q˗ҽY/Z{[vTX@?T^.[J4B 1VokpBsƂC}W7 5M ./QbОoBDǎ*1בzۇ0^> n\Z M2ffKc#?[4J;}LcVK5ʩ7rw[圣Fl=nm̕NPQ?&Fol < ీG@_$qv0@2 A3ϑ=U->8 2'UUWƮ~qةȦSsUu)]+9]y>GsAr?)WN J<wbAzCQa;q6x2p# D]9t=_D)_):W~"4 gZg8`XNCvc~65M$/Mh>D?NSj_璬A?Ƚֶ[-(7~=]RxgxE,XIp" Rx$^P xD"? Vӥ7 &%l?#E_IǧLmȏZi&wfy$[nuL[{RL`C-|>@eNgJ,>WQ ͯuzz7t, WYwP&`O _Ww{{T ;!b :/.-Y?d[F^ivd}5MXoWXCQC1i5Cϻ.+5k;r9)ιA٣?nvG-Zkd瑬!Gٺ^-կ[am֠,+ a>B6z[_"AaGa|YBMw4#E"`umt >Gÿj<-o[Ah^ n6v*/0xߩ\;A8U p2ݰu>kݺ l鿺 I"?{pp)~w l66? :u)_K27ǭío7z#[~sNWÃ́h^hs>x?m.ԝG/ͅ%׻4XlqOZGD?s⹐KKF׹y뾯F5ts JjHU`SR ]޹uO7hu,wt{ x63ZqW50 c/JgS&5r!ºyI5]`;!B:] yu"6( csWqn!աBj4KFBA@b(eW^(Rk˿ W{1tV<[[?H?SVVWyH/;apa?-swO;nf0^Y5%Y$OߞW2#͊_-m\[H/; t?t=7(<Ҭ_ːLk+_լw- W{f7w/mjWmXA_Z/޾|ـHo9gSv=L뫩?%mM {@ӄ͚y*+5U_X"S=Q Mi5hTWJO[H.R׭y$[^}v⬝a@ _+W i߬{?קYuVf`ZK%!f+i+\-o[A={g⋮{x!uqԄk}qT>Wx&Wյjly h9>'70qoQ ǔr?mqH,WQ27iua2D<Ku Ѐu)!zT͡`zUЩikng/,gH䢠kkehsH?p]wT1stP:1ʩb:R:.^彳?f/} J4">³R9P%Jo/uD@ )7D?ĪP0P5]A\} ocqϟ>]yTM4t7sP˨+, ~\j~>AgSBuyt" ($;AF'N&pǐ8BNچ[{ӌ?ly?WZ-Zg~k?׿W~zҙ[M<|/C/:ߌɷM![H"at±_~R=/׭$CwvB?wG41RX@VBAjr, ;{.1WLwG q&ڭu( oyp~;@0rhrc2DoT̡,zC*f4sIӹU%-NυPCt%,(9oTs<>jr$NVBXZ=UѺX@rO{}d [O}ߥtG_+_+$,fuEJh2HjRo!BOgHj I7(rxg;1㳯K;xdW $-Z$cW{.QDmD=ki%qɐiս 7-?4$U$_]-ٌN0oρ/!aAVkpW9&G*cxw@#Nab-\@!50ml@ůBz&W8K -Ce,Y-wKߪG2D?,m杝lA==/'VYi&wQW0&>Y$'t2g%w@֖y?"fd9̿?Lw ׬y$[-oӄ4[n ojy$_ X`?)sS/n_knrG-o?Hv6 ejbn `[IJ=]RV_mor黁X@i]`#MxG}7G2V KoSVuG~+VŁ~w1>;빭W[ͷSiZV跠|`4/_ˠU:{isGp?}{]NruG-o?HgW^+跃w};Ŭ6fmVwU R:V='fiW,?4 4Z^YH-oWM^w3DgvB@NP@>5 ,L?xjumWDG}S׭<SVl׹$Cl.du3^˸Y]?HVgVgVvZ H?$d\GkDx( D a"Ih& !SA>"ะ=v:G(0~cm ^zCSX`Cd)n';GТmxT*"a[\`{n :"O s~v?>Н{F]/_v6~T߅| e]1h+MuI>~ IۨUXaK3`ÕX-^B@`}W<~w H*Xg#/|ONq8:d0GG{5 zg `:r,R1-8ƇOluqn'0>[#XoƓ.}ҍzȕa|kmIÑ/uǟ7g y0=3=_,헽B84rEhC]"HyLv]ϿvO'@ `ssR/S-= [A|Kze}on77޼-~d:>UxʨńgTX75lBܾ-+j #tSm5h|d>pJ G7gƏc0i& 0XYE#@ =QUggZN&f{_!j8hݚUQz\~\~xY=ƽ]X?oyiל_dKv 4׼dt=*wV-&2sP8@6uv#Y.%WEFY[أx j} ;\0ɱ'M\Tymr\vZȫְAtը.>%fR_zZvXz}^}=\ _{c pB`G/B~Gz]q[AQDtjY31a'z*OLYAM"+CU1RAV`uI^~Xo?JZj?<Clbwi:iV=j)掠G$WR,ǥ{T ]%k=4^JX$[hδ?tܙs4͎,WKkg<>3usmq::j[Z]Q9q=xجts+ 3Z14ݎ÷nF?s3\/( '@#:zH/UODT|Y@l@Wĵ=(WnNbdf{a>2b)#Tj#Xʸs_Nɩz;]y$]6oݠG" .w9u߹s/Z+pu-7hB-j!G/rɕ*sX AڛsP$>_pC9QjcU׫ eeQ7A͞"t?ۈ$]YZ 7KoKU{!YZZ7%RoM凂?~LVؼ| =ό9UmwPrڰ1Wںr]._- M +Gw@e<: T!'l,!J!ZXxzF ζ(^u-G؃xykӽ'f9Y?L6+Vo-3:h=|X^{=n~0at፦G8&$ ;Hby*c\nF ?睎X*WWd,9nYz\qbIr.5Ο>͉xׄWmoʛrGlr.lgN| Hsl &:;mIQBV 팞xN)?1piJ1%]m-Dr'w .Y)OrqNN0cv|%+wXE+u _@lxNA4A|Ş7aհ 38?+io;izZR<[[? eQ4}h1 |ĸ֚ >`s07bhhl&HsKEr01E| À&)ꅟ2͘˼*VVBRDO\EۦXң1c)L 5>]/~Ce6C {#~WТjw{T6oX6xf쎮J`//l?Uc_XQ;Z^$P9cPas},ae}w3UfЗ=7r'"Lg\j3ځMwp++wE PW؛mEMј=.:Hfǯhĉw΃P.H Ŧj^ć㷇>莂wQ: pxRtJVEMi):A٠=/ՕS^޲)xm %SW?߳l8mIJsoR,1_VJ?ۢnX3-J4Ǯ]0-GC_7Ў|#,OFsXJyלj2C&?^9V!`QIi(:ޜ6( MA 'Q7q"}vg>R?d<߭????'s[=Gy J^2RrvBBlT -1U h %N_'77-{GiMX>Li8IGL@KGˬkD} g/X{oR+ڔZQF@}oV޲;ŚHQD=-l C*`$ Z?J?4 !y