diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/compat/compat22/Makefile | 10 | ||||
-rw-r--r-- | lib/compat/compat22/ld.so.gz.uu | 702 | ||||
-rw-r--r-- | lib/libc_r/test/mutex/Makefile | 8 | ||||
-rw-r--r-- | lib/libc_r/test/mutex/mutex.c | 1548 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_exit.c | 8 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_priority_queue.c | 192 | ||||
-rw-r--r-- | lib/libc_r/uthread/uthread_setschedparam.c | 16 | ||||
-rw-r--r-- | lib/libutil/login_class.c | 4 |
8 files changed, 731 insertions, 1757 deletions
diff --git a/lib/compat/compat22/Makefile b/lib/compat/compat22/Makefile index 5061805fd6e5..0cd693c132f9 100644 --- a/lib/compat/compat22/Makefile +++ b/lib/compat/compat22/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 1999/05/08 17:53:43 obrien Exp $ +# $Id: Makefile,v 1.3 1999/05/21 18:37:33 obrien Exp $ DISTRIBUTION= compat22 @@ -12,16 +12,18 @@ LIBS= libalias.so.2.4 libc.so.3.1 libc_r.so.3.0 libcalendar.so.2.0 \ libtelnet.so.2.0 libtermcap.so.2.1 libutil.so.2.2 libvgl.so.1.0 \ libxpg4.so.2.0 libz.so.2.0 -CLEANFILES+= ${LIBS} +CLEANFILES+= ${LIBS} ld.so -all: ${LIBS} +all: ${LIBS} ld.so -.for lib in ${LIBS} +.for lib in ${LIBS} ld.so ${lib}: ${lib}.gz.uu uudecode -p ${.CURDIR}/${lib}.gz.uu | gunzip > ${lib} .endfor beforeinstall: + ${INSTALL} ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} ld.so \ + ${DESTDIR}/usr/libexec ${INSTALL} ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} ${LIBS} \ ${DESTDIR}${LIBCOMPATDIR}/aout @${ECHO} "libcrypt.so.2.0 -> libscrypt.so.2.0" ; \ diff --git a/lib/compat/compat22/ld.so.gz.uu b/lib/compat/compat22/ld.so.gz.uu new file mode 100644 index 000000000000..a689daed330a --- /dev/null +++ b/lib/compat/compat22/ld.so.gz.uu @@ -0,0 +1,702 @@ +begin 555 ld.so.gz +M'XL("+G*_38"`VQD+G-O`.V]#7Q4Q=4X?/<CR28L[((K!(VZ:E`0A`016`1, +M`AL^RD*(;()?C8%L()@ODGN30-DD>!/-Y;*Z?8#6MK8/[8,M;:E2$8G*1X(T +M`8L:@2IHT$AIO>NF&FV$A:[L>\[,W/T(H#Y]GO?__G^_UX7)W/D^<^;,F3,S +M9V:.<H^W<7T<QUDY;BE'?U8N\G-*?[M/P8\'U[\V!>+)=J/,R8,T[8M#@C$D +M&'2B'@)#7>(AXX-'7H/8CZ2WR8*^6(X7/XW/R5.:((UXR"#9]85'7J/YR7:# +M[#2?RTC(X.-DAU&3=.2U687EY16\M=K%6Y=5N0H?K:PH*>>MHT=5C^%84)7K +MSLJJ"MZU_/(8F&=^7AC*'WZ&4!K$MDMB0%,S0G0;]/Q0^*OA![6&X.?;I^4X +MK^PPRYD&*%ZG@4\)/BLMZ$J7ZY)U-MNEZIN]7G$FQU\GQY-(.:'T/.5>2"YV +M&*"NMDM5'T&>NOHA\B8#E`MQY,P420M^VGHC<25+8I<.0DBX.(T3#![Q!'B0 +M2)#0(_;J2$(IT^HW89+%1NHG91EET<AR76R6S$HVU$D2S==RG#*+?%KP,X-\ +M)N/G#/*9`I^>75;XFWY,)M%M)*8P1";1;"0&'_>*!C*7ABO_O(64$5IM7,7A +MO]`NA%CIAR:5.N3LE%!&,OQMG)NB"0EFC)B.L6@U<I0W,-I!.8M$R\)H6O'0 +M:%*Y%$@F#]?EC).SD^4,@R['P"?F*EL_15K04_O5-`"%XTU*1R*X`B$A3CD* +MA)>GG$DBL:C7RU:,.HE$M4"5D-;2E$T`_RI.>>13AGBCG&.@@4";&0;`\*NI +MF,2TI6U4"&R@P^E&0H<TU^76<,)*O2Q:2$(IVR+6ZSE34PLZUUC6?\SUA4*K +M$E9RD'&^\J]_8`9&S&`$Q9-'O,T<"N6LTB@?0YC7Z_5DFW,(.BW*:?!9%<>2 +MMI&D%DQJ49-FLJ0[_L%`L4C91EH'<2K')W1F&["1E*>361,9E!]"U%:@7<[C +MZG_P^P5'7ELPNV!);N8L>\&"19FS[;,+%F7-M\]:<E]!3NZB.0LS'7:.NUJ, +M;,>2="[QSM)1%>-'E5EGS+2.JH2^5#<FZ>M23.021U6P:-@EBRN$\B)N5#4W +M"OY6TKXM]J9$=<7X7JSJ0]=`597WX5NR]T/+-K<)B9Y=;O"5A'Z/6$^"]Y+@ +M8#CX9R0XZ!%WDN"?D^!`./@-$AP`8H,&FP9(D06#7&.4A+[F<Z:F9/28+`F] +MZ)N=(M;I.7Z(G*&7<U)D3I<U3F,G(35Z25":SV%^[Y+\%-D=D(6^<]EZC:FI +M$_`ONX.^`QIL7/'"*%/36]@Z%Q[BL^1-R=@.54LEX6QH_B-K!LM9C]BR*ANN +M;;R0Q)MEX:P\O.5PBS84[UL/J4/"V<7*7_V$`'V5)#NO:;]).BQ>*.=O;#`W +M'S$UW0_>OOMHF!C@^;M\V<3!2LI:"L74#9&SEG9P2:&LI;[1$)JS*DG9"-GZ +MDFDZ%G<^QEUC8"`-D34=7&)(XSO'8:3%JQ*5I9CF+!<#AZGIU^#18!4O%/+5 +M#4/%"YG\(PVW(60'P-^?(@;*^%K_M0!;I:E)!J]U#XN!.E/31NPL5\'&-8B- +M(5'8\`M>@HMW/X$LB^$;FO\CP+Q_B5?M%\1I]T)8+W-,]4*3F`YD&W(\XEGT +MN)VZDU3WB)"@L+A&B&L(3?:('Q.JJ?V$X'P.5'(.5*5YRJ50B#2\01(,0"C- +M'5^%0A[72=*;!HXC\WS0A7.4>SY!9NBIMT*/Q!!93&'L8IR\"3\I30ZB?5>: +MZ!_F#4>I--!/*4UV6*0A2*W\$!@TE4\A;RE;[S=X.[/U'.7TTD(8-Y*EA<E2 +M?4KG',0HUSDGA0::I47ZSCD&ZF>E5BJU1J.5WB:Z+9QPC>A.YOC!D(UHTPEQ +MK<A^I#GCI#Z58Y`Z1JI8K-".LS!%7&/D!).\B?#0;."@_D%`3XN-^)UE$.L- +MG#"85A>8)H1B`/8F<&090S5Z)=6'O/M&'W*GP(/?/_+:<C:D\X6\]991U;=8 +MIUF!5514NLJMQ84EI:XBX!]542$K785%KBH8YPN+!D;@EH%?6>&*DN76<J%L +M&<0J*:<!966%E5?.KDR5%JX82O"POK<)/J)://]C:$UH(QPN"2+2?'_`7J*Z +MFL_QLX&=G,M(T0GC<*S@;Y/S]++;L"%!NN!/\F[09C6U\2,W:#*G:ODO3"\- +M,[V4&;(=Y!.`X(#-'$**JP+6Y+%OS4$J"'P<'I-29-%*QS8_>&*H1[PP`BAZ +M)?;K2/FCY;R4<UE0OEG.LMCLVZ#QLLPV^U:UC!XL8XB6H\,YE+$-LI.:UZ'@ +M0@>OV\(EK0^79$K&WO+&2"0D7Y`PDU56C[TQ)[0;4RHK/F9CGY4?01*,(0F> +M@02^EQD?V>-L]#QV`3H82EV%ZR\.@FSX^]=?/(I#]V+9WOAX3_MA\^,]Q3,2 +M-'QFM!LDL_1H]R`-?W.T^RC'#R6EVDFIMT&I_FQ2/P+=*NVJ.-G>I+.WZ.P; +M<T`L:/\[]ECQ4(IX*21,"%?W/_ZN5O?[))\/H(NQ^DWY.ZFY5A/V&04^JQ)" +M0HO4I[,WY2A?_0TQ8&YN`X%0S3`SG&$=9.C/\E(12@$^MG*8F:;?2-(#;#G* +M'7_'+%*P#2:&\\!\HX&:A\-]N#)Y)#R]S?^HE^2CJ33DY($H1D5O9<&_8-#J +M`(J`%%*65;:W2%FILGVCE#5:MF^5LLRR?9N490'1(RS+`:@:X?H\Q:T)"UF# +M5T'';=>1<G10CN?92L``81?34/J^'?I027F1%22#G%P[B@76ZI6%5="G2DN6 +M5156K:%=41W_#='C_UGDERCHP=`.\I&X[WJHI,<>S%'&0<6D3J#^YA#?D'ZN +MTQ[`-(WW<GSJJ@GYRK4$WP;`=Q+(3Y`-L$IOOE(^C(`M=0"I7YOO$0]@?HIE +M!(GL'PETB&T`?"@(F+$'\A3/6=)NHCL(,I5L#W9DA*:)[@!G:JZ`2I+Y@%^; +MWN9Q]9(*1U5W8!WA8U3U^&H0F(K@_RW<?;'AE87\2FN94$TX7A5OK2T!]RT3 +M;HDPL=K"JO*2\A41_B/V6J)P]=X9P)73(.>F2,Z@>-`@.0.RPP#3"!!H070! +MT:FYS=14@IT3HV6ER$FZN>.DP[*S7W-0<O9)';J)Z:%.>R_F=RY+K^%GFPYD +M)>7`'R`:9:F9XMO8'!(>8!*UX)`=,))F8J1,B.01GTM!?!ZZEB#-/QYED5>M +M1/@>T3AS`C\,HIPB47YY+47YH#SEEK_2G/70DLE`EB&A+U_Y^45L@-Y\Q?A7 +MU@"]''_K*H/22ZK9*YD[,]C`%Y`T8IN>"G?^.:JP/X(Q,,@-NO2R`/(OBW\T +MP#.:A$]09EIP:C"55,0,LD#2#0C8V3,$,-G9)^<:)6=_\S%3\U'D2NY^CA_O +MOQXRG:P<)Z.<7G8&87#+4U:2-##Z!N75R$3?CZ*+GBO*!G=^A+*A0;H$=9[O +MI6."%N8%@C%/^:F&D:X[@>:33EGS*1([!?DYBY^8IPAQA*!IC(_SE2-QV`_5 +MX7H\4&()5U!`+)CONJK*"TNMKJHJH*GT:4!NY9'QCQL(H]1#"6IM2FA1LJGY +M"22+.2D&/LLCSK@)4)6K],:%QY\[/>(L]$2V\I<XUIV0S4Q6?@UU`&1)<P!3 +M,S^BF*HE8XWH!J%AHCS'JIN3JILS.@=*"TU4YG^DUM_D$>??1*<Y?P)@O)CY +MNO,H<='JA7M$>46YM5*H<EF75Q2Y<'`?56T%L6%47<P20&%I:<7R0MYEK5Y3 +MMJRBU+J\</E*2&ZM@6$>$((=#;J6L[S(!?B"KLFBD5&?Y#D-@['?38U"T[(/ +M*9JJDN7Y*9+CI#Q,MWB<O-`@S[-H7L=.F`>=+7ELEB4UH+,'H!MBKQPJ.TZJ +MT5(P6A]FD20[3^KFC\,4N:,U;TN.WDZ[@O-X<69"?0)\,^E*GCMZ[-P4Z?!/ +MSKN5]AZ=9#\JVX^..22YS@+^SRIC>D@L;)FZ21QO#>U*)1U%909#=3EFJ2LG +M1S'T,+KMMSD")O&79%W#&1"GP9QHLY8F2=0E28YNA&XB5(/P$I`C!$,<RH;` +M[S5]-GNW28S7D*YX+C/!P#\4S5\<77)NLN0\(<\W2([#\N+1&F<71)17Z]?_ +M'0B#H&Z:KFZ<[#BL6Y,B.T^(TQ+JDZ2^]AZ])N!/\'KT-1[]$S*GL7>!=`YC +M@$PF?HXNM>O>)KXZG?3H&T)"%T`?F@A@AU;K/6**%3OT-1\2!@+EG,NR:(1% +MJQ)H/4*5:;(6!&\JY>8H#WX0GI^/#0^OOP#/'#6_.C+"?@RQ2;]$#I>$O+1Q +MOD63W@;<=>.."!9,33>"H],>).PT,\'*)R&YFYK&8AP@BRS]**R_Z7F[HK/W +M-=;I;Q#BH20)F(BS5V>6G#V(IDP:2W:>E:<?A.YOE&<?!%X7!&D!^(`CL"$S +MH4V)$WLT9%0,"3W*"EP`ZHPJ07:<E::WR[GZ]6>(TQZ49K^M)YS<U*1!:&H- +M9'P#*2BH2Z/P6W&>T9VG_.,T[<MUX`H)`>5OX-9T$`89.)<%DE@<P#PV'5R- +M:Q,X]RB2T4TRPE)KA+GR'$,.BC'="%FB%O-*]H]#QMR=YQ]););Q1EH0Y(9K +M9>`AGJ:,WQZ`LOIMSH#IL4=@M@41SF5:-'P5"&V9:CMJHMIQ4W>X'>>$V_&= +M;FQ'8"]5X7:\R<3:T3^&-C"=00*@'G$UH9ROA@"%=R.>H8V762XA7]W+V/D` +M7OGP^X2?LZ4@%+3)V%=O!JS:ZLW"2#D>6CA!&!JJ-(8J#:$:H_)["J=<HX?N +M])<PQP9.S0/')E;,7.OB>W2N17B_09C2.#<%^C=,"`=!ALJ=="+I$3]+!=#S +ME,5<F#4/]HA?4L_I7'AV%9OW+VC>9$HR"&=C'Q#ZU@/WK@LAOPVG$7OUX50K +MWR,+I4"-JS24^HR*#V>K!Y&XC@D&BM[!7B`'7#8QA+K2V^2'`U?`WPT4@/1C +MC3,Y_GJIJSTPQ*//,>T?GMXE'02ZO9?CLB%(^)O4];(-DOSD_`6/F(&KE=.] +M(LA\@[SRO6*G`3Z%<ZLL2O[[*,&O,BL+\2,>QXV][Y'%QGC)3!9DI;D&.7Z# +MP]PR5X_N9&FN$:?8.(5.D1::PW-U=6F/K?)):=*4R&R8X&-T5#7R3H6[/-!4 +M^KE&&[`E+\C$I#Z5IOU#H3X=P/B@/ID0"/7I.T#K$Y+>IC62)[4`^<P"J)P@ +MPYV4#60Z*(Q`.G2?W)`P1W*?A%GBM>B=P/?"D!&>*`KQ4A^9=Q-I8!_R)!!: +M.=^GV,G9\B;(22@'/D?D0+>1(`]ZKVV$J5DB"U8!>0YE\ZE,9*Q"[SE$XC`U +MN\"1?@2:"AO*1-9_XCW&N:1Q^M=_!.W=0,:E?NEMS*HA17)W(R\:ILL?AQZU +MR3A^P23BHN3L]1A?AP%3M`$?&LRXXC39V:U;.T[.2=&\*[G[,,D(V=V-J3-& +MHYRJ=-K/1@V)9\F"I_LD,-;7.3(0;QC6XNP!'-C/`KI,SR?(0I^F0W8JNN&2 +MLQM:)7,#<%9W]]01@@7*@BDW>`,^T^BLNQ>"3"_=2_#9R5\/V!770J=8+:_5 +M>_1?8</J[+V2_:3PGU@H?W]CO7Z0,`*SSP.6C5P1D"J-\)T$D=&+RQ[\9(BB +M$6XAWRF-]7%:WBR[@[9Z0TT*64<*^BVBVXQK!E!7IU&:!FV8@3PG(.>B$(\" +MZ'U$``7..@I99A!$6PU:&J7F).GF1.SZ'<Q99,ZO]WJ141UE\Y'24BM?85T& +M,Q(7B#A5%656H?S1\HK:<BL1ADHJRF%"<6M=TE7DGN60`:Y^8$(B`!&YZM8Z +MR@O,4;3_P#L1VJ>T-A7&J]L9-8T`F</F--08Y8Q)J0%-E\UNJ$J0&V#V)IP& +M0^?G,\=086_[NZ3_F/;,BY<<_;))KDW1+1R'M`.24=5HS><2C(P)\J(47>8X +M6>CWZ/ND=KG*(L\>PD:\*1BV>AS,A33O2$*?O"A9M"74&U"FZ(,QVZ//`*KP +MZ!]'L2*@,J^`,BY(5CE@,+D!9PZUX2$AX!%+&&Q&A*TN:L"<FD]F&0;E%4"` +M%/"XSA+,3Z@IK)I0)91/*"W"21\(FGQU>(YKC<+;+7_!:4CJ<-QN:/X0J?E5 +M`Y%G!M/=IC?I^@C=.&F]`P<F\SML+B:&0OP\7&GIR<E7M.^HBRS"A/7NGI*Y +MLQ<(MT$WF"L&-+4W8/K\51HDG`!,B$[_)6J-8T2^(H"[4\2"<=>`,N[\?.7[ +M&&T7`@>HUWPA;1J-GR)ZZ"K-TJYQ82<N!M3I-?56\54CD<M&2%_H<E)`SE1\ +M)S!O(\L;B?,$'46C]P:O/Q%&`S^29AFJ3,Y1IA/`B#_2U,-!-G:A;"H88<`` +M%GLCX"<R9@R-C!F,QY(@2PX*E09-7SH+E+ID`7++*BRREA>6X;2AR%7'.@-Z +MDAEYM"=MNZ*HMBL^CM1!UE)6`L9@?"$U^,GY!J/'D@OE]NAA6KUK-,&/P4NK +M)0^WY5@:!N5ZQ,)QN/KL5?WS]!@P#`)JQF$SWP\H\7DI5Y-E1+5N"%"OEZT3 +M#ANX3BA\#W@/,!9A%BX0RB))D:W/4;J.J\(`/_L5(KK6C];4Z^0\HVPWPX#X +M*HE9K\]7?G0<1TF_%667<2%^N)P]#CI+5#5\4R$Y-J$W=@8&O,%:5E(.4Z@: +M5U4U<!7KJ")K12DR'7YE8;G555<)LRS@)*.*QEF%:IQVE<",K'Q-;>&:R]=] +MAAQCXM0XNO1#UG<0<!C0LF+7@5*/4X'#T'R,OQVZB#T`_L:<_%QEU7%*XI:8 +MQ1L86]M@<)RJ5`<Q.V$8IH`VS%=NO(2K8=C_SPDCHW)2QK",S)#V%MEAALF2 +M^SIU^C%T,72H/(_XBSNQR7X-@*-\0%>#)G!7H)F);P^L&U1J:4R=<HY%ZC0S +MWR/N'4^FV[\]1G82[,^`*/?LL?"6X*`\Y6/(,_T<=L$!5?TM3M7RE0:2$@'S +M1LFO(,M%P?73KJB]"7L0)BM:T^8VTTL!=24XR1?&#W\KW=;5LP3.H,W,7YN? +MIPS_##DH$3OCT]O\B5ZO,@*7TJ#D/E+RO/*:PM*2(FMAU0JAS%7.X^!45+J\ +MM*+:%:LK,*B+TCT36P!'([VV+JA;A@%:[4MP)\(<$X02O6#QB&]-0.POT*FL +M:Q#PRUQEW&=(JX1GY"Y9,+M@H7WI$BO95!`J*RNJD!R7K0'Z+*D.4VU%L76" +M4%TUH;1DV83E57S:^(H!.@S5;U'M`.A+9L2+,4=I!K;F'XIS4W%.&EG_TB*; +M(^6RI8<B%^^J@O[AH@-JU>W5ZOI@Q;)5T#&XA176<E<='^M+EB3"D%\V0E_> +M;]YYDP`GN\T`GZEY<V0LQBG)-'DX2.5QK^`\21Z"8VBV.J$_(B2P";W.'K!= +MK-7;.JO8CL#K8)(\X@&HF7\MDRU!A*%+4+R.1DKTB!]CA/N]'G?0*Z%LDH_3 +M@??ZU1'U>S3B6?\XX-4=3%"`G(PT)SVO(ZG4><0OPPF'><1!Z8C5<@U98AX& +M,.1$C;]FJ4OM;[%SBB-O('-6U[J[HGKWC+0VX)3!EY%4OGA..GR^*R-'N?4M +M'%0[$@H@@6>.)D?)?8NDQ^%=^0^2.E^I?Y/V[[#\'R[MP3<0UWH]CE9Z??1H +M%4L_=T&\59JP)H+4"T(;1B-B@KH4%UGCC9K_'<7M364BH$+>A;M[ZSMV<KAG +M]@+`I*PF$S9<[QZ:`_.]B62^]_2;=(I)MU<?P^BA#:WPMVZH3%RX%TP^_(-P +M+[CQ#3).@)13_"8*'3'EK\7R@1\".E9RN`FU*VTX%C\+4;(+JZQ.$^G>&`[V +M4:UQ3W1R"/+LY@#D/$4/R=/:I//1K3$W)P]@^`*@\3S;?XGM)4`OR,_,75BP +M<-'"@AQGKKU@UJ+9]AFH;W"?,R<GUW[??21\WL(Y]Q'?K'D+H=\LRI]Q-94$ +M$C!OSL)%D)=CWGWW0<J8(+990;X7S,O*S<R]OR`G<\G<&9?SSN__&1O?J/). +M>:IH#^)R=HG7VWCO`N&^Q@;-;,'1V*`M$.;(NT:3Z0O'3U?7QN/)_N@HF'CG +MPXQ;2UH!2?\:.5O?.'TJQP^3LXTP/DM3_0:QPPQIA4/`<^5IXD&]Y`R"_/P3 +ME;]>SA,.OHYMM3,9Q2O\RPF"\INC1!M"$M&CE6M$D65FCE*G8[O1IJ9=6!=[ +M8.ZM8AJF;-./L0?6),HR)M`X`K@%`@S8'="\BN'IYUXA2DJD`$/-$."%FF/9 +MMDWHK/U2VO4B[DJ1M&)[$!B/S6&H'4:2D)$]&&)R$$D@D^C^!,R#'Y\-4)#I +M0NWGGE>G0H`$TR3C'LD1!*8U/$^9BH!.WR.Y$0TXYMP,?'C35*+U$I0UDOZ% +M#LUGTN<PY6I9I`%^`551V07%E3$*5S\Z0@8=\:"NE6@XO7V\!YH3\/$D:BS8 +M"+KJA\H$FU(?3'.#4J??Y`4Y4D?\4-4#"&$2?(XEB+-UU(_SD(I#K3&%#2;5 +MKR#"I2YPR(Y^3?MB!;N3=!`&^]'R)DREV85_/2*MA4&RM/@3`71-EZ25#BYJ +M#C5\X7$I5]Q7^,MALHX"?#7%4Q]LK`]^)EQC>FGA5PPC^@U2=E":OB&RG3\@ +M_19(GQZB>]C(AI_["F8@Q\D>M@"D%\25L+60:>(<TTM97_G'PKQ$DZ?LY=05 +M^^M`K"&,+4_Y3=@SKO5&Y#]S=?L1/<?_;B.XJHF#_/R)\(?B#KK+3&!?5L]< +M+4'^\1Z&[SBQ#>.U!77$;1.,M4DVN[$&N+_!/XWL@U^BJU4`\%<H;=#-)$$/ +MU'"=S6W@KY'M1EM?C5;JRR'</.T(G:GU7Q&'/^RD`AK,+H[`7/H8:P=]"T!G +M\=J^X$VV@*"7#ON'9:%<(OPC4[QP0_V[1/!0\RRKJ')5%JYP58<W6495JML0 +MZ"HLKRA?4U8A5%O+7!!WS4`8!C,8HDF)U-X]0R;$07&V4":>YT_>W$&CCND# +MMI]X6-W[-(-@^M)4'#SW43\:?Z[4<2O)A6CMA59J<;-9)P5,SY-@W`/?UXGZ +M@*3ODRUG_J9PL(YX2Z0\2JE2P#_$(_Z9%/30X>@-J('UNKL#Z=-H>EXPY"F+ +M_Q5N*SXA+U]9W1G;+.2G2F/<9;3J^Q/!4?HY/^Z)Y<MB&N&_H4D[E0\[50S, +MSP;$8-]-:SA-OT+`8-)H-R7QVWNT.<!U7\3"X_.5S0"AU,X"S6JFT@)O4`5L +M6NRXO.Q/5.F#GX*DY>P@DC9T%ER,_8]I*-([#;F*NR.\'YVC3$)^]X'7FZ>, +M[X@:-@?4+_%/C*&DGR,Z',CIL'+G*+5GVRZM^^1J>'[C$"9+#^$ZF+$11I"\ +MQJGC!5W(#C,^HVF_>?U%5&NL'2Z+N"8LMDW:,-NK:5>T8H_&K_/BPB'AI;=` +M_TZBH[91^6D'Y4;Z/V;#\#1'#"74_RHB"RTOJP3QM-:U9AJ(N"#7KRRLK'25 +M7];^A\)]ZYCM"_=-7J_-::E/EO4_QGF5_H<-4^$3['4CLVQ?K/NK3;`0.&[W +M8K]+@;A"`F$._FL]XO9[Z(K,VC^AK!+3_2[#Y;[7L%P+T,HHI)6P6!A--#\B +M#,L"51\<(9H3$5J>0,>+1Z+G_Z\AN_1G>E'?S.`1-TQ'Z2R<9ZMR[A"=LFV% +M;OG%(77*QN,Z;3)I?^*GG\/*F]K0BN5M)N4AT5=7C.<*J3RU5!LC3_D/<F16 +M9OP3ZN>T?D5H`D?N5"T*5`/DV[E2\UZ(TMF\$_YB#AW-/4!&:*&'9TL;6-*6 +M':C.YNB1/-OA`^JT&_-5_HB5:'XQ4D2CADR(.PR7"6[R%BQ&/!AGZZIJ7Z7S +MB!>G$TF4UA-EFM^'=F,40+],LVP;E*.8PL$;Y2WH*WLP4N.ZH8/&FYH%;-EU +M24;,[Q+FEZ]\\!I+8&I&2<4S1Y<3VHW0*_U!*N>C>E[3/;CU[#2+TT+\G7(S +MUM&F-37C&J'LL(BV$#]"O*0Q/6E!C^9#&*PQ/16/]=F-B`KM1CSDL9PG$@28 +M41KX*^H!,O`-.1Z"Q!SE9@#*H]^-Z,VA25G*-F@KB>0([>_[-2X->U'3SM3T +M4YQ77/*\JIT1"KV,JKG![=P_?VUJ?FQ@`9>P`,P'54"++F'6I&UN((C0-^XC +M[8AZ3SU084DK[L/B-/4&7`=W6"0-!=(_'&)BPPL)T*U0WX7ES6@7*2KK(,K= +MSWS%Y&XN]N<LCTR>JUSJ&K*UNF2M"V8M=3%SG3EMJKX_G0A%AXW%,"=;@(K, +MD_)PSN\PRH)Y0U9":GQC8<(%0V8"V6G4-\Y+T)SO0*F1?&><[S"KWXUX:$`M +M`V?`#C-D+AZ,/_]><2?G58JE'&W[)V:P],72W'@J^V%1=K/8=G&LW5C<J?7Z +MBJ4L;;L"L;+TQ9U9\1PW8(VR]@"IC]AV"?"4DZ,@SXF"'8,X;>,C"1<:YR;H +MP5C/V<T&'K\RHN*`TQP)4*.'83=&9=!(YIBXU`F8TDC:#LW1@0TR0/[;SW%$ +M.9^,2$.1#QC"'?3U\\=P"YJ_]C+VX%FB#>$F!`TR#PS*57#XQ<DQ6>;%K)%Y +MYBN_::,+BYBKD2RB;5%](+-$G#TK8EOTJ#ZK0B@MLL9H8Z@2T(#UG_V4OVT\ +MH&K(#O6(;V52EO_$`:JO?(7Y]?%]X279H6ULS!6&1)(N.!"9E^/OZX2RZ'Q_ +ML(\LK<2%3!PWBBCV1\M.*#)MV!_6SQON$1_)PAZ[\`#.]I41L?!&_\(%7`<% +M^(I)1$_<6/#[*08D<%6G7[MB_$]`ZO9-9O%'?G/\5S!^/(L_X9OC;\#X[^RG +M\9._.?X#&/_7+/[^;XY_!\:O8?'G?W/\BZ]"_&P6?]XWQW\=XP]G\?=^<_R? +M8OR_[Z/QX[\Y_BJ,_Q*+'_?-\:=A_,=9?-TWQT_"^'DLOOZJ\3UQFDC897+@ +MGUXA\\%037*>,@PI>&8G&=Z8UCC10W@55W&>)7_/[\7C)B6O1HZ(Q/*_5T@? +MP+5726S%2?HU[,S`^H.XBB1M0L_P'DTXW;TTG23N#0?'A-_T"JX-F7-8OQV, +M\TW<4.#@_ZCJI`%U^OQEE.6,5+=#3A-?;26K&DG0!1=1M059-)!)J$<,V'%0 +MVX4QE`VO4IDAQ*>293WJ:]R+,^VOHN(M(_$L><HO`2P8&+GL2%CVJU0IY56L +M"=7%ETFM\`";GLACK\36;=;+,75#0O$F7:[_\+(J%T=7I_'2UU3GU5=H=<[Q +MPZ`Z><QW!JVD1SP1!;7W%<J4&=3&_"B8\Y4'7F9K?6%HGFH-K]4IAMAUS"B8 +M2UK9'/7R=NC\ZFL`U[X2U0Y&M1V:7AG8#N^]S-IAY,N7M</^EZ-(-);_[[DJ +M[!'0G]M#]5VB0+9\'<B+7H["M5'%]=LO7P'7J2]'S^C8/HLQ7/(D!&]3&UF- +M:R.%3^ZT]R.[Z;0'$H@5Q*Y)MGOMP9S<55J/O3]'*7N9'G)C.C4),!]L(YVI +M;\"(<ME^T\&72%WI'*1C#QL23<U?0G"Q;-]>#*-9\0PN@Q]*6[*30T47WSL( +MA#Y/V;8'EPJ?H9LZ]#!/>H@>0'A&^;`UG%W+P.R&1&?G+UVE6:7%)"^VJNI9 +M_-)5*<H?]D24?^<JIE8\;V+^;0CX(Y_0.<?,`2Y"M6;E<8PVQT@$`=XJ.Y^1 +M1G3.T=,#+)@_<*WE)&VR%/!;59+,5]Y\":6!9Y0?(1*(KY06V;V\7'[:LIL@ +MB^ANZ3GA>D^V)2=48P8^&9JL)&()J%<)<X#ZJ7*VWI9M:!C$6*G_31C?%QIU +M"_7GVG7"=<7B&CW'7V/:DZF7\_3SY7KSF'>EB[:N>I2[AY+S#IEZ3;9>M''\ +M9NGPE6DY87=8EMFRAY$R60]95E(^C?Y!5S7Y(G\OX_\O4J4Q8)=.LVRWX,F> +MF0:DXI3%.;GY>8H=\O7-@R&D^0B>CZ0MAB.*;P([2Q:"&=,(5$E&-991S<?X +M.''JC36C.KF;<`/G&)^VZB:/:/X>V:$,`9K]-WG!URQ.U=4.:L4E<=\GR/,Z +ML2DAOI"4WN8[274:Y(5ZL?V2>&&8Z0F<-4DGQS;)`<@IU./U[H5YW3-@T'X1 +M#*Y(;V=^I6"\S._K3!V+VZE=CBWT>*<6SU;X?@`E>#NU6%=?!?WFH-?[EM/O +M<4DZSI?/_#'.]^@WZ1;WTF^<0_ONPF\59\-5M8D!ZU>7[15,!(!669077\0Y +M--F5>_40,F,1_TKU>J(\:P$ZD[/T4K91RC-+%\2/;O)L.LQ6<..E21LD5(U5 +MUSSZ8O9TH]?^.UZ@+-INE-K#>7@L&R1G4)X(95=ZO;9L/8SF0E">W'Q.^`+\ +M'I+SC+9\/1!-GL&6;^'O786Z']+;[1=N6IP;FJ+<NILH@TCY%M8#<3RL-W+U +MP[WYRN,O,FF=-\CY>EN>L<$O#Y<=06EHGI*U"SEC[Q77JVYX@;`5D<`WJ14W +M*F$NZS#8YIN%H;)6BL]5=+M0=0)U_/\JO2,/\Y_V>N>(H9OJ7X]%^`#Z_R-9 +ML_+H)8\^TZ/_DPGGYLI4R`IF!;@^/,F38VH\$^SDF,Z>-%<OY1A"#D/==5ZO +M]*YGUUP0K8,O8^O^\UGQX%((6:-$[?]%Z3]A46(&/7\KQ"E((O*NV63M'!H3 +MF$"=&6B^6*R#R=(HL6WI_#7_Q)T<\ZHD90XJC\13Q,7+DY&7`&R+BSLSC!J. +MPM:904_OT5,/G1EF:EFH14[[0?0A(-IEI%&_2=2:3:VY7$3Y,P;N7X'DIN3M +M4H$=FPU`U%]/SJXGRI.)L^$+\#+D*%MQM2(^9KTRLO\)V81V82G*T%V,5T6' +MW[,3T;.`G/;,P<YNILBBW"8R,XKA?SMC9*?"%V*G;MP5SPP=>SZBA[8):^2_ +M`W7IUAKD*OW"NI'%8H.1B$!.0^A8(CDP+'8N7;CF8Z*E2/3MA+=D>S!J3SDB +M_SX?EBUD,9DLG"[-45[_XP#X8^')>IZ*X&3)T70@;TBNLG0G#GK-H74W2A=) +MQX)B4>_;'M!DYT#90[.7H.J$MWA]L3'T&4Z>>R^GMT^>(_F>RQZLX:]9I46! +MP70@>TB.\M@?29^DB=5B,>"7.V/W:*/T?Y]C,%IPF'`8<Q=30*?\D4H=0\2+ +M(2&1YN@?#'`M-')F*3M'REL2I1L<SF[1<T3>-QW(@%*O?SZFU6+*O8V4:R2Z +MD=?E81N?!AB9\JTZL":I9UQQX%;I=WWO4GW,>NC[?R!;=\5RKK'QS%?%DO-% +MZ,W%<N:08LG^$EZM8#\D9XZ3["<\S=MQW\&^7;*W=MIWXK#4:=]+K38R*2(H +M\[BWYRO7ZZCF#TA^ZTSYRMR=R#?XN/W(=\_97\S@$XCZOS$#3[T]\R]UQ2R6 +M!V52R&2[61:2`;EB((F_MF&0&##PN;[UR!_$@)E?X5_C%2\FU@Z:UW@PK66H +MOQK:?_U%U*>ML<R3N@[@G"']V/GS-#3.*W5YO?.([T_.AX@G<+1/_=/GM72E +M)NC36C3MG^B$+_!4+S]Z>AJ?.J]#D^:_$=)(76*/:0.-H1=0'=*K(&&C#EVL +M'"+V)D=58^T.;%0S50WB:D>`"!$2DH%DB*B=B*J*OT<QP6U)XF]I,(-M,#4- +MP5/IJ%?L!;?9U(1GTGUKJ!LRF2C$BVY#8NT=(0<JM2:QCM[W',J<BN3LW>!4 +MH&XP@+0,]<TG`LEZMY$@95%LDGW/$:*7[/W0ES8X^]5445%^I4;!C&4G_%7P +M()FSUV\B9RD,DD-!S7!';SCKWI"@*%5?FS6)DG^UK$6WP@D[\?":\#N?A&T- +M>6]P&!H_2FAL3Y.=P98DNN!IVO&ZKMVGDYP`A9'LO[Y#3D=UD1/9N5!@HRV- +MGS\/V`0V9";F@SO59TRR(V6#,2DV*WV[3Q^5U7&2U1NH&NY5Y#]0V0M97#?3 +MR2KF%A8NY-+2)]XUZ>[)4Z;:"I<M+W(5<Z/+A=+2,5'^F5FS9MNSN30N;3PW +MGNEY;(W=E[CO=\AWE]`K2_A!B'CL`#BUPI,;1@,?+ZXQ<\($#)GP!U5<L$;2 +M$&7:&_[`Q"G?X1LIO+1O%XMG0+:^F"3,PNXMKAG"K;-%DB8N5L[N(%E&%'_> +M@F[I$TDFG<UZ7#G'7&^^D9QU,DI;DB_AOLBX2W1?I+.Y"]?-V:%YSU'<$''N +MD+88<>AS]L)<C<2R]]'(>I;,X^B5/(=QTT0F&4I;S/#7M#])\EC@`X1KW'<2 +M]Z%C%#\RU(R1:%33_F'2%A+IF/"!O!N]QN[&U/PR>0OFK_F"\@'3$]-QO9GD +M+'L(0$.EU2"4]XOM!HEXA.Q]HKLOH?Z6T.[#9)/%H&R\R!2#3,UWWH"`[J!1 +M-;LQ;PH19VKZ/`487S/%A2&,BYZOU"\N[!?\BJ*PH_DF]!M0"5:S9OP6VWK$ +MP%+3$T.'0G=^;^QF\01*U6>\WL._YKC1/Z9F1]3W0+,5PBJ?I=\-8!>Q[Z/_ +MQ7%MW\)<+=^!9MNO..[:7S+W+R\/GQ25UZ2?7SF/HS^-?#?]Y-N7K8>\?\[* +M)S"@87YJG!16?N4O..Y.*+_W9QQG9GZ-/Z/VGZ+*YZ'\QGVD>4S-#UY2V\KJ +M6T2VGKR-'FQBC2\#_J:?DSV$8CV48H=*9"^0[I:)![MP3+H5]XF,YSS\D"Y- +M1ZB9$"`C<*UG;I=X(;&FAWHT3DL5W/(^[$/B/M*GA%2/)XWDCT[/%OR;&]I] +ME.X!*E]>1Y8#I-U12?AK9!)9-OY1!G"0]/QFT6[6XZ[.O*#D01^)%$)+S:*] +MF.S#JGG<)'MH!)K3!C6G$.G@_N'4'IBKN(\0NLDS"@+/_QP=%%EZWS5D2]1+ +M43G6I__JL@Y,:5^\>(>I>3CJ*GX+S-[\W\#KZO\.7G\^\@IX-47PFHZ'*4GM +M0>"K"C)L$D@S)0*V_^XP+J^7M]!@DMKR0WDBP^(PKS<6CZN#TFYD$,WG3)XS +M_T)FHK(+W_%_$?P!5@BR&`(F>RQ0_^%=TFZ"F]T8I*/?'HK<1,I"&7+;"59> +MCY3RP]A2'L-2:),U^A[Y%](WT.Z_50;EC:G"C!@DFIJ3_H7X)K@G6/<0M"R. +MX/YFHC5C]'T$K-<K[48B\GUR,0R7P7?XHDI6&;Z]X6^S;V?XV^K;=A%+R0F/ +M)3(A#[5%;AY`W1N&MA#B8NV2/*!=-LP+MG@P?`.)U6+V_6H0C'^L7)E8Y]JM +M?(V:_YB!+0X#V5GTF`\S:252D#52#M[))L\/J/&"-)ZX#_]"A\)IWOF?8YBX +MA7B=_SE:OH]PJ-U"`#AHYFTJ`);+NJ]_EO?R/MN+63Q%YM@LCPS>KN9A'9"' +MZ0!TP=X(\`_$Y&<ZH&8X@(]<CHFH/*+Y"-0_-TA+$/?A7\X]^/S/\8,RC3M; +M45SWV1+)?5#[D&8Y(8D2+]FS)5XAU0L7A=6F,?"S5(!N&0#0^W><_GE_!*#[ +MO5%M;X1ZO5_23R/X9UZM3J>U,5D,CVG3TUD!%KH[0/[BM]+\7ZH^T_A3GW:3 +M\`][&L_:A0165\^FY4Z5=@_@=I?O'E+OF%SFA'-)]L@KG"JOI/$'D?CK"0:( +MQO`6*^5Q%L+P4M'AV3*6^AF(2D1P()A)-Z#J"NDYAZRT0Z_@$^G''&&&N`]S +M"=8/D;=@4AO)M#ZEU4Y:@\06XEI=N%Q!)!J0H#O)QXIP!%>#(^1)):43%K(; +MOSW.0*ZR@93=AXHUG;I]UDOT!AWRH3$]]=.HUM70:[!\CX=S+1;NH;!Q];?) +MY$.EET$JH6OX!V4/^GG6V33^13()%SNU_ME>N1E3V)JQJ(9A4F<DR6@_E4-) +MU@W7R!2L3NU8XH.+#M1K3N.^L50P;$Y`92'2I+XU"1&8K;Q#):>4@5U$RPCI +M&N_`\2$S2&5:NNIAEN;J?7_N)^."FJ\YTG__G7S-OA_$YI?Q;^973#,LAAS' +M8(Z1L7``8])<<2P$7I`5E#T$)H/OXW]&R5UFM3FL_`-JKG=>05HA?'2Q7MH2 +MX;>^`%DXC^J?`.OB@!HW2./ZCD715@Q/'<C*8GEJ%/]B//5R'%H'Y&':$\L/ +M'XC)S[1'S?`;9;.K\-0H/M^*JT*^?M11_Q_QYE9<.O7(CQ)V<P(C/(O5_)"V +MCI9V\#HLJ^4;RC)?^KJRZ'AM)L*:T2.O"[,WUI773:<,"^^A0F\E\Q=,J8VW +M2)UC24H;B6KR!/"F3_+M^X>.S(?3VF02(UJ[Q[,VY'L3@K^CL_\1G9%1>B.. +M.)M$,H8AD?B'X-TC$:*)(/=^M;AQWQ*YY\DZT/\_<6N.$O<T_!V(OVO%?6?) +MT'8M$Q8%HW^HETE0?`+KENIR`QGR)`^N3#0?69>TGO3=AA!;IJ%K(^H(M4C- +M>9B:<R+K>_SJT.Y(*XIG-+DYM!.&=I.&VHWIE,`G4!23'I+],U68(KF,O6HN +MO407U1=);Y$^&4O`\ZS=X;]+70N"`;9V$(HV$4%_`YF*M'C0AZA_AQ=:>HB. +M;C<**A?=\=(^_&+3?-X0:NXFHY!:>RV?(!(OK4SFO=*6DZ3-2?+7(;F'N,D@ +MIR-AZBK3.[V0GBP"-9F:7\+V(E.8L;N[Z93KR5^AF'+)7._T;!H]#*F4KD5U +M9NK)90SV?O/7+4C]Z^/P@M0ST-/"JVMB1Q]DVOX5(`-1*W))")GLIL9EI:96U7P>B(0+B;Q.CJDSI9OT9O$9R_<5& +M<@/`RU=`^+,,X4O)_4=3H]`#`(1Q_C4`//'W,`"C$Z-P%,;YIJE1#?G-BXI3 +M(OF=-$17:#?2Z)A+"/0V!G3^OPGS\;^%R^`-_PLPBY'\4F-@ID3P)XV02M<_ +MPJ2W5J]Q1TC/]V,]G;<1J=_TY`%PGOKT=#/.,][SX>1G=F-_AJGY7X3#$0&< +M3%@:1H;YG3#$(V^&$<0WCX[AGDT_<D;6<J'_A(GI:^KQZMEP/1Y*B,$]EK80 +M43\E_G](+_F1,@+QWQ+WOG(=Q0^96YB>PGNN/#*IX'^OM[SWUW#A/X@N7"93 +MJ_,?8`W_BQ%7GC<6E&_)@VHC123'7Y$'3?UO\:#;(_D=CHL&.8:@9$(/#-3% +M>NKTW:>G^QM1)&-Z"O>ZOD5BC?-K2=Y[)@Q6>MQEF!Q+".8R_O+OX//V2$&' +M]?\+^'SWHW!^=?IHP-6>9&JZ#V][EG_BO!)GC_19+:')@9A,C<5DZC=C,CL" +MT,>Z&(!(8CJP?Q,T5\CWTYYPOD_IOH%PQL;"?06(34_.T.(-M.'VC^2>KHMJ +M%M]P+=7MHHL1#::HA8@BI#PJB`QK(4,>79CN:+X!_H[W$*__)LLR1.#XK3:J +MEK'LT]X8S.`G#:BY!R&<)\T'2;1_OH[@08**-QO)0JK$],@BK._SB&SR;]!Q +MP8=A0,D1]W^+CE='\C-%\MNIB:JXWS&`)K\=M;1]$,ZN4!,%GL<94"LJ;R$+ +M3E<DC^BLA$A6PS57Z&%Z4],OKR")>")\-T9,^Y;C2NATN-2MW!7'E=&7C2MJ +M-M=&LFE5LQ$>EHGHJB%B++FB-2K:#\/1)K,-VW"!/N<97-/!!-=XG+VY&'U9 +M.'H"BT[NC#1F\$F1C>,!6]LU3]*;C]BD:"3=%["121'$V(VV,F\C9$5R\#R[ +M1#U61?0KQD5MG%\G4P4T1Z^'7!,*,!C(5C->M,^1H].K#*NX'.66)ZG:L:-/ +M<G1['/V2XR317^@U[1_:?,S4]$H\&8<OCN('A^R]JK_P*8;](AZ)#*\5I?IN +M&):)1:[M$4-+34_4Q%,US%<;!:J&Z=VV@>.2FZB)_AYH4J1(.-J'6B+?P2>^ +MV5PMWX%F'<3M>9Q^JW:T.1J5%_?XE?/(:(Y\MS5]^[*?@;SK6/FJ:6-^:IP7 +MV??3$!:$<AK!;&=^C[!RIP\H/_V8[.[U#_%Z],<\L[5=IOTC-`?GF/8GB&U= +M8B"Q1FF\-]6$"^Z<)/1([]B$O@83N37S9)[RVSAZQ8>]OT,?K\^V"6?=.DDX +M*PL]_E7>2/N23<D?<JPHTWX-6?/\FO*$*9)P8D!9,ZY6UHDYDKO7]QS9((U) +M,>BR%";/$\B?A+.^!KJ?ZLG",DU/K"5W>X;ID?C6?.I;CK'P'+-''_+,3NCR +M3-=>%NNL>!'P8\-\+_E&XZ38H1A\-]'\X3M#W;N%;[,O(?QM]?TK2+YC8,[7 +M1\/L6X3K:9!.=BBXI&"-B3LV.FZ2[U;R'H^""S:Q\731\1)\_]*R>!D#XKVO +MBXJG\1W7XG4'4>&OZF)@VZ7F8QB0SZ;H>$-\\L!\JJ/#!_L>5?,96+_O1<<S +M^F9IKU*_6Z/C)?JNOUK]_J6-BJ?S_5,S`*[WH\/C?<<U7X/[YZ/C#O+]1G,5 +MV)Z(CF?P-:CQ,DQ-2P>6_V!T7"UY3B4F_)[H<+/OKH'AUT>'FWS7?!W\GVEB +MX/^8NPK\G9H8^`]P$?B?Y@:4_S--#/R;N*NT:W5,V?YR,GY<H>SOQ93MSU;C +M#6S76V/*137#V#ZEBPZ/HWS@>Q<H'YAU@?1!O.9RZ@4<Q,\FU"?+CK,>O4=/ +MM+4W-%-E+`W1(3/+&JH03=;&;.ZSIHU/<.P]+@VJ[QE;H1C32Y8$\:*YUH6# +MV:8%Z^A@]H@(//A;F$IFU.^546&BW6C`M6"PC?YX8NOG(!B>M2$F@IAA`+?9 +M^U&1K5]9T(1*MX<C8W[T68#;1-3/QZ/*J'H<E$=X)CF)2OU%@W!CGN)M(F>D +M)6UH2DY(""IU3?1>?0O@*P\U#28TLPCX0EK?V(2<51SDH=]"[RDUYBCG(((T +M13TB<)EN\J\?0]0FBVYKL9#T"NZZXC4\(!=977P\_+7CE1'F5U#&/_5I]\,& +MNL5K/FTWG.HY_;"A0W,GHL#;H6&WY>'=72DAP9S+=.\:L/AVR&@%R6Z.,$@6 +M+.<[L.7XI;+3K'F=%#VZT98FW`BS`;LA:BHPF+3P6$"/D"+-A#^ZX5%1<+%% +M,$G.`-[!;0]T<&DAP+HS4/6%[`Z,>4L64J69J,\:==Y@?>\D<B<58&R#W2R[ +M#2T)LF#(;C[F'G+^O8XYFCO)'3=:O[XC?FRVY!,O)M:G>U7=6U7+5CH(_@T^ +MJJ5K\U5?A_<Q:EKB,[-MOJIS_D$=\6G9+5WZM);X;&@1N\'S["$0_&+.)XB] +M2R--<.MZIAUL)*=!=)[LT`RBX!J'ZH\-Q9WVET(A^/NB02LYMTO.5LF^4[+O +MQ9?`!""T[3G*?)'<'G2.CY?MV_'ZD2Z/:VOT^;.H!M_=J)XSE+.3I6S#N6RB +MD%EOYH3!><I643UK/5NZ8'KI@CQ\;)[9EF=I,.4I"\)AH]./A18:Y'CI0HLA +M%)\%X?P@R$?#)XNA).&:/.5FD:A))]*C:GJO=\!=.U'TWTB/)T4=FU@"B1$J +M82[\-:OGW59[P:7GT\3Z-%S1S<ZP9:?A3=5I2F\C@:LSFYQZ:"PVOJ^^B)1M +MEN(;%QH-I';Q>8J6YJSA+>KMSGF6\^])><GD/%9Z&X1I!9V<C6=OPJKF[/Q. +M!.3J!O4<`SZSII>Y4%>G/?@AOB/#>81@WBJ=\DOH5:OBE5\]AMQKVV/D,%^\ +M\E_D`\/7/X8@CP:_!A(%W:LTRK$&=@XSJKWB2&E+U=MT1P+_K=4OK,,[GF?O +M,82Z%JXY+]_;'!)\`T`B^LZ-++_8/O]"/;T=@+["16\M0]3?Z*]G5Y@Y`V/- +M>&>JEK`6J<^_@NI'XU6K@QIM,_AX<J_JEV/I;?7A>\\"Y);!J22NC/=Q\<D@ +M9\WD^,$;AF9NB,^>VB7H%L$\)"0D@&OZ#/XIT1[0X[F+B7C/8.05E<ONY;KD +M5F%^(@;FZ_QK59C[&<R2/0@0NZX*;R`";W\,O(%OAG<3S&]Q(2("KW+9%1FQ +M[6=WD_[FV=5X$WQ8]C<?XY-DK:3?C]>4><FD3KIP_.\>_6X+&>M^48]]65JK +MEZH,G5GTC$\6PDMZ]97."/YU'9DVDN-[F7K/)E*0_C%)`R[)^)AZ#B?VKN;G +MUE$VD&\&!NJIM4A"'SLRX\6'3[2F/8=-SSN,.H>Y73&;G@?>]&;[IV9-GW2P +M_1-(8F[O,9OV'-$<EH4^*5[LT$/ZD#V(UX@[@^OVD<L?YMOR#0U3Y#GZC!Q% +MP>F\O4^N-;/K4<0V@^SH$]N-GGQC3NYBY:D&(A_D*[?@%-O=A]N80D!:LL>2 +M+=6:(Y<JA\_31M7ES`_8$4<+N<S#`'3X<B*](AX^PPK;0:)A%=#4F[W>MUW! +M$+2^/6BS!QJ^P%$ZFT#8+]59H'D!\1CY0"*]4U]T&Q/K1XL=B7C7.4R1<K)1 +M[[]?^35-@W<AV=S&AC/9_E0<.SN2R'U4L7'71L<U-YP!$26*>.A=).EMY_%. +M'SSCBPW??L:,;BXD0$:&]C,&XNI#E[[]C)ZXVM"E;3^C;3ZV;E@&\<H0$EOQ +M1.*1U[Q>]4X1?'#DW,$$_G;<<XU/;\.P<P>U_*"W/Y&&DON4CKS6_HD6OK7D +M.[VMF%S?3\#XQ-QTC(+PB>'<01,M_Q/]N8,Z6O@G6MS9,&:\_8F0P$J6A@XX +MJS1S+6DC8'*G\7J>2DMG!D%QY#Q/[)LJ0]:&CZUFFVUSS/5X3[IT"9@*OKJ# +M-ZT'Y$5FR=%/GDZQY1G<&B"S]>31IB",T`<MDO,L4)C'N$%R]-A>KQX!='V6 +M'N<D=R9"('A7?2)V`.WW`.%Z+#^2G-UBIT5RGY0=_1[C4Y+CA(P/*4%67;:W +M3.(P]D:BXZ1I3Z+D4*#'K9:=/9B7NXL]FT3"SYKV:/!5#].>$9HN<EO\4:F] +MW0?@]N(S'EK:I139!'[8A7HU'10FZ0O2NWJ+I5IML>PX6BR9Q$[@-]TVY]FJ +MW\"T5S+)SI/R,!)+X2NA#I(CJG1Y"CDG`>5KHPI@$!QD>9-\%VF+I2DD[P@\ +MICVF*T(C.[IM#B@?$MA/ZD5[%Z0Z87.>-#WV.:X7.J"S!CWK-EB:C]2GBIU! +M?((A99[DZ`.W!62SD`.7[[AZ`PWC/Z,II/EF<@+E*N]I#*XC@JUX1L?C5<SB +MDF%X]QEY`&@".;V%;^BVNXU:_E%Y5]M->).L<,/*U=#`BHCK`"+Z21V=\?2` +MJA[;Q7BN7<./)*?,9**4AU]_Q'>FW)C;VVXC?Z,<CS?.YN4I)1@CGLXT4+CN +M\._',S.&Z'LQ8M_?>J"6G&5KOX0OHLCS]-#<>.VD0;?(G(G#Y!R#K;U^D#=D +M[]6TV>S!AG,AH5=Y\P)Y9TSJ))37E]X&L-KZW,,1WCZ<^>&-F9!57X:M;UTO +MN9K2@HR[`3CI/@S5="%;<1EOXF?B4[?<6'*`*?V<5]9"C8_W)/8!.Y42H*WQ +M-86)0$3'/X7VM3G[:T]+4_">2&#<Y.Y-+8UX4$_C8@P_=+A%^,#6&C/BJAF` +M!5%[P)M69/`TPE`B9YK'=`DVSVH+FX%X+&F>V5-ALB(>#(IM03G)9N`MY'8B +MFZ$FCEQ$+G7ANVRV+VJ[B<05S>.C[\B_))#QBMPP]`0FL_?0E=J;\=Z=`.GV +MC*4`;75FD5.QOL'TG%D/YQXN`><`((&)",9.>P^Y0L[@A2]RX*]6K]AI)MBA +M<XPP4.';L)T6CV4//LTD&`F?Z,5Y6JZ9U0Y&0^ACCJ#8;F'Y>$U[8$+1:]HS +M>4R?SMZ#X\G!]HOD)9\$Z&00)$^&871,GZ9+M/<2/+/P8BD3>KS07RRE0W/+ +M3L7F[*WZH\W=5W,/Y,GRZFB_9$9FA7EI^JZ:&E+5ON[7A1P!L3V(UPM\B1(6 +MU#R/]K@3T??$`HVL_PA&E8;U[3":!*'/FH!6V6-Z_H7`3\Z?:K]@$2]<TS"\ +ME>,,W/$`HIJ%XQLW3&X0VWO%"S<V7-N*MP*,.2RULSL\@;C]"1`?7:?M`<;K +MH\\5WL*3PZ*>'&"T_7(&R!9:SSIS4`9`^A8K'V&[=!#2'O,YRJ-)XJ6DAFDO +M#Z(>]K[C>%U,W[T`E<W=7QTGSPF2=]<67@N"S/$S+-YQ)?&@ST,8-,8:!+Q( +M'H$G_Y`&".\4.[[D'X$DTN?'SP!S)0/9F#X\Q-=^_!.IBY0QR*ZP8I+DAB#T +M$=27#6\5]`Y,VD>3DE0!_[5D;.A;?X1`2QYY@E'L-':G[AC9)AHW\=5D9K#] +M2RJ=M`.MX2CB-J[_.!0RX56XZUWD."2T8[L/POIPBG:$3UCO@!8RL]=Y8"[V +M,+E7ON\\O1M/#_W^)A5.=P#@_%@*#`+J!Y:E@6J4!?P&?+/'W2LE0(='[TP] +MZ;AX^I4L!\CN?@FE1P7O\\;)O[*)9,ZB:R"\<P[ID)UVA8A>'58B2_6A_AF, +MS$WI;_P+93VSE'#@;H3D/%Y39_.G43Q!^)MJN.Q0`)00_U10.7:.O+)@5]I[ +MXL9TD8OMB"C5'9DW1..O8[4ZW<7ZYRNXYGSZX3Z$-T^I(@X%&,98Z"!SS&.S +M@?;B-`>;C]4GX=,-%HV]WV\@7V/LO:?M?=V"$M58])=!K9Y[M]R]=7,H].&] +M=__M^;LC[K?N)>L.+;'OQ$Y8C6AII8+IB]3:2:T`DU8)30D@]NP@[_[LV#"B +M\>)8_KH&8],Q4]-F'72^&V&N<O%.800DI5N'.V1A!S[#,\/'XSJTL,/TTI#U +M%_#47LV0Q<HDGKY\>1#?8]KT$&8_3%ZR8=+Z,U@'W@#I_3^F937>FR;<#H!A +MMG,DZAZDYI\&_`2]8"[VVT&D&$G8WDD>B*6@;Z;67FH=0LNT?Z:T#Q^2$D,3 +MZI?AOC,Z;`WYHON0H6&D+&SV6,YIOI")MV?)B"[)N=E_*ZY#'3(U7"^3%U4' +MQMB"GB'[(0J7:?]D:3<IX=*$AJVR^Y#D;J.EC#<U6S4J>L+18$Z7+5Y*$Y)A +M/&[%,#>$W:L"F<;[Y"WD\^!;XD6#Z8D/.+6FLKM5X][+&@_7`6E$WTZBTVEO +M%9O1V65J>I(D:=4(>PDGA$%],LAF`.XAR+%AL.R&.H?PC:/-_A%03W/#T$@] +MWY'(9X;-WMKPYTBB9#613.J@.8^);R'K=9!^I+R/IH^.0+P8M`.J*5VD1[!, +MC]M)G"["!DF0BQ],/^RFYB'D3/<AF&N+[E9.L(CN%_&M(D*:OM\D4IG7O0-D +MJ$X[/M5+*,:T?XK:'&-Y@WCI3F%8R'YT```JB@D03VP-EYY&WKJZK%W3^-[H +M1JDMECW$U=XE`^DFJS1UJ\=R1/,Z18!GP?"NRQIW0@/(]3O&'$2,&M9?N&DA +MQ]4G0?7QPZ_WXLN"[J,</_+\PUVXT,H00^YCH+4FV+`B-DS-OS8@=EZ$KV<, +M]$5/]P[?#PWDONR]8X0N$,Y9N>XV3HB7A4.2T$;(\[`8,N,#5H>)1JRP.3TD +M?2%=6)S[X;A4$&U..P.B^W!B_9V>32FX(^X^W&V\>/KA`*61V+C=]@"$X#K; +MZ9.DQZP3W5W0/9,`C/H<^![><)UG4]$P,@`#0#0GGS^!M%TK7HDRUG[(DS/< +MYNQJR!AC[PI'[C8>/(VR`R3Y`I.T)F!MNSY9=YWLZ#I_*A)OTNL8_),$LGYP +M:*SSL(:V%*DZ9WH2-9YETC/$'A-OBBG@X8#X+(;TF9I.`JVM)VEPH;8^5=Y$ +M[M;1WD+N\G@$_R;AK3@.%$)\=Y`*M)/X>E/3S\C+9+1(3?V=E%6<)S(TEIAR +M#2L10<U\>U\$/DW#\?7(<'<&!\0"H6G]WU$XHMUQ_26.V[K.]$0Q^_:NJQD. +MG#H4^JR!O4[C&T'GB"2[')W/H%%IFC-Y4"_P_,\)X5\)$Y-B,(&//K&:?4V= +M9G]=G2#@M%.)B>0,G/KT]$?JZOGI4T+QJ?8/#IXZ`@$T.&II_9X!8U%44_AV +MQA$Y&V8&N8N572"<4!+$JVG+XO"N)YJ&B7U^_>F3IT^&A,TAX5!(:`L)VY4I +MGZ)`TX+/<@HM^-Y@1R]Z;)3KS1[+/CI+-XAM1MG1(K8;<Q?G*&5E5.G!V9?K +M<?;GADL_@@*!W0M"DOP9?C6)AY*1_->-2#\6&96`A"6A6Q).^D?*SJ[S[]'1 +MH]-^DH+934IT]W/K@"_W:PC3Q'D)R-1CA&[*5R7W"9`T=/:^N3.TT.;N0;*C +M?WW[77J<2+P\F<R\^C0>C*EQ=,ND9)N]VZV3[=TV^PFT3S2WU1O'D)`Q]NXQ +MX#Y6?WMN2&A2N,\)Z"'!BZY/$3D=X%`LB!7!BY=&$QBX>@M]7AP#?T`2><EE +MJR>Y^J$A`7"\47FQCV"2>'<3[V[T=GP>\3Y!O$]@69,_9TB#N=5&S'7]%^C1 +M*%<:*=_MS##2.U$`ND9ET!?L"F3W;'PGOA&W?<ECV#7P=1[[@@D<)3J./%#7 +MJ+Q+@&EDJ=_XG*5N>-AG1\4\U`-J#?-]CI\"S8J/E)HXU$4W<<(#D'M(6$*\ +MR2SE($JUDE.=@?@N$44V5K(P%H$11L&D+#*IZ0NM/T)D93*M(;WT""8Z!\1I +M:MJOC?30YC&H@J`25C=4M;LL@(SXD.'4IY%]*5/3&2C-UZ0-8Z7Y2Q0DMT(\ +MSZM//PG?"=T/;\7H<:9F3U3UDCOM6RG!;<-)P&G[5C8G(6`GLEKPZ>#4"$GX +MPHVIJ2:(=!J=K-/^-'4]`ZX#_L7`;TXIK$"[8(Z.W'.O_P[/KJT(4GRW8RO` +MZ+\NVNT$KZ<9=((!X,%=O:<C;$_8C'RNIT&HPBFD(PCB/DP_&+,,8^H%:-9N +MQ].4!X2;"K"!C?B?ZVK&K`?A'9@D5DD)F9INNXA5BN&;0V/XIK\&O]T@2&;H +M:A='*G?I**"_.L/SZE:*9(#7?59VG-UME!P]I\IZQ%[]^RFI#YPJ.YO[OAY& +M1OUI9Z1VI&I^'8R18<`O]$4!CH\CQ/)[F[!9^,%I6HCS[$M&F&FS0BRI]T,A +MB]]+)85`R[-"3+$-.<ZS:SO%-:L`G^MY=6<T@0`]:?@99&[HV=4:&_<V[([# +M%.SL&Y4D8C<I6F(W*A=A_N?;AV?*,5;OQS36V8]IK&YBMR@G/J:QC^+Y`[RC +M&:JX`]^GG`(#@NC>R?':4SV>9TM#T3IIJ5$3E<>+Z`7>&7CM#T@WMCEF-][? +M]R%;"\6[L"V27<'+:-S!]H^UDKM'`X/S6;*3:D$)M5?F,B1[#TRWN]*/G1=Z +M)'L?7B&_/WJVTZ^NG;H5>019?E),>PZ:GK?WD0=2<!WR7=/S[C[I=?C$ET.[ +M85:FX(T\ICTS37O>'O,N-*CF@G2X/6#&;:B9[9^937N<W7CEHN8@;@NA=[&4 +MIRV6AH@=>ME]UN96:@#^7MQ%NIM"*[8%)7NOK:\F!3V)#.H(BO;>H$WHK3'` +M#!27+WO)O-@@S5&OEPGTXC-RIHU'B(3=%ULGFG$83;'U"]?M+0#W?Z]6/U4+ +M#7KTCTNTAA/^FW63[7T>5Y=Z.1"^1;R&WA"D3GL#]Q;.JEC^FR>.W;OK\"/R +MZ`T=]_YKS7_F7#/[^+TT/)7-BU.8;0G/D^F=0;'SX9N6(:I2Q%?K</6(OU?> +MM`YWL61THH:VB$ZR_B"U'S^C^AM"N_!#^?0L\!.1)`UOV'!N4R<^2<ZQ]1%_ +M/%T*EIU&-I)<Q+^"4W8D=VI,M]/M16'X>;N1C"2#/9L:?XZJQDUX:9)'EM#A +M:!+=5H[/D9U-C6MUT)ND+K'-@'>QP@C:II,=5DGCGPBX1?V(3Z-DJ=ME9W*G +MEFQXR)ZHG.(S9:=52H+D/C\,LUZ/([#8XPRJVA/_^`>.GD_3M9WU'X42\!6A +M+AQ!C_#CZ%U/DK-/`CG$U4\&34<_#A#K[5T:,FH\0R8N%>0M61WPY8,305J1 +MG##?LM:GMF*+C.G")37`*;Z%V25V].";PY\?_R213'V\9(EHK+T+?4DDZ6#Z +MD?`4Y>&^]4CEYDM0(*[E0(&TBEZHXFG-:7O?!Q]Y-CV-#NT'1SSR5N+]0;MG +MTW;B]YZCZX/V4V[44$4.KIPJ4]YW[CU5UGOJTY.GZ&@V_'W[WBB-D,208R^= +MY[#5"=&]=WAMJBI$`T+V=J>\KC)603]/<NQE"RRR$!@K="VL,S)I#Z;R?N/Y +M#T`J[+1OI^+?7F[=,"82RLZ]DG.;QKG=/PSR'./H/G]*<IPD8RK&-"?6P,S- +M'-9"`I^X^GC1;@ZFA]AR#'J9GB`*6$ZS=&KLQDU=6X$0/_(F%W`<FL#W.>X$ +MF,_!O/%]<OD<N9C;?IA:7<,(&[&H"[%LA0@O=&N`PBUTK1LWIR1GF^0\[+\C +M'$=V6*`"G@5)&B`7R7$8T-"&,C&FZ\)T^U%!HI/T*IIG5W(-.0-/O#3G/'D6 +MF`O6]H5VH5L9\Q'NJ)!.9V\DTB)TL<-#3$_<J,-GFTQ-PW4(:I=ZA::CCURC +MUD^PV"H[#DN.0YWVHUIR_VO],NEM\2-UXJ-_'>;)[9?T["F'R>+?3=".W;NF +MXZ3E85Q2($I)-X*,1[6&3"'[43I-@RDH3%K>OA2R=S6?$WH@V0>?0Q+_`AQ' +M]I[_D)^%]Z:&9U@&,DLR2)>@-'YT.+]KP_D1^NFBL=1<W\.Y/3\911"F^W0' +MU!QFICB=-SV)9P1D@GT@3(^\DQ!XMP.ZA@&R?=]^]+2SASA[/)M:"<UWVT$, +MZ5F/.MUM0<Q*F-5IWTA'C!:R9R*WL=YC^."CTTY#M[.'%&QJDN,0QIY3/1^< +M8CZ/@H]O'5F?V0FBX@N8?--#PS"3PR030#U,S;M=6"9KGU,P(R1P:AF?BNE_ +M5(+Z/O1!",I3Y1N#]`6Y\ZZI!;5NFQ"7#_>HO<S4]"GPI5/MW:Y8WUZRZ`:L +MXS"0DLGS-EG_[SEY!$"!#-`V^,AZE?P0:1]@/8>[C6]32"D?H96(P.GL12'L +MZ^#\G%RJU]22E`6<&VIO<W0)65AL.Y;Y-H'N]"E3TR(HX-010`S#I6";#PD: +MI^$ZIZ-))I_\ER'@R]<FD'6]KMC6]:W"JW^].*^5G8VD+.##0#_]DL,H.ULE +MYU[9<0BZ'A'B-TXB;;1WB.FI.\BI<J1(X"M`_=B=W=.1$!HFQQ("^IDV/JXC +MUX4S'LJH,,[45$GN,=:1N3;!%N+HY.=7:\U3;7GO&1%)W66&R]J3-I&P"G-H +M`Y)C>.+OC#[5.!B&3]IE3$V:>'+S/XXKC39G$Y^*2H!DC@^9.9H:;3;^;X## +M2_BT>I/O>!R1[4)V0$DCWEUXUJN2("+3.6!R]:LX0C>^<>21GF[)`0(K<%XO +M1<U&BAJ07!\%#JMI&"6ZG\%[K7!TNXN.;OY[O&P^'@#VY[^3K-L=7F@[OTX_ +MYKP_:<PEC;!-(YQ,AZG>88C>?,R=-,:Y(\R^NF#ZKG%L7Z51IGW(ILS`[79P +M];>([NU<?8KLW`&I9,=VV^OU.BA`=G:-`9G,N6.,<SN9B"\BX$UM#M7?GH]" +M^:T?D6Q"PM/H&OHAG=P_K4SIQLG]TS"YEX638R[Q(_*(+B69QC^M_*.'C/WT +M-<Z='[#E$H!D&YF\;T/Q_D@/\S807*01$>96582Y#CY0QN&'ANS=(?MVF!AJ +MV$(FFR-B9OP$V=$BSS.W?Z25/#QY+JDEQ`\U*RM/T_OP'=O%=NL8O#T:L3D( +MVGQ[EGCF)A0C8$CA![%=YRZR;MJEK[]&M'?!W+!+X^S6.'?@$#H"YK==N@8S +M!*2H^-T!*(Y:GWA:^4.XO@3-X+T=J_BCJ"H")[:#'\86U>-X[KN`\]*+.)]6 +MKGV?Y6$D33",^F]4OGJ/-:21,FO2W>X#G&GK'?B];A3$C,/BCI.8+3F8VTVD +M#$MS6\-P*G/`L'K^;9`H?*_A^@'V_*8.;3K2.-"V[SFMRH?/D-Z^@U1B!Y;_ +MMDI(P"`V2@Y`QU:.SPRMUBMOG:++7DZOG&MN/Z.5MO!D@9NN?7G9VM?J!\C: +M%RZI;%2:U,R,:L]'FB%8F8&K,VUIDOT$64EZ6GFHAQ+;1JS;;P@J-^/Z6)V1 +M$ZXAE9Q&3^9)G;C<Y27"3$C8K/SL%'WK*X3KW&:@I7-V@P;7_D_8^,KF<_6Z +MD/W$!N<)_P^\WN9SZX8(N236`A(K&RA_$L+ZM'*2T.W3#+PW/Z3/_9F;0PU) +MPE#9>0+5D1(A*\AW&I^\`15N@'?[LG!V";F,QO($D,":.C0VY%2^!#KOA*(O +M'23\RX>OGZ![`#<S-6VCCR@0P@B>5`D#&L#F\`K#,62Q<I;X;R2K:$;_+5X: +MWZL</4D7%1G][#O)4)Z,C.DI>H>BBGU6N?8^%??1P&"3$WC<R2HLE6%8(#-_ +MNY=BZKG3T9C:]@'=IS4WGVL8(<R0'2=0=>5N<G\K,%&;HXE/5L<I&_\/*.Z2 +M!HO#O5CDL\Y&1IC^Z[TJ3TX3C-[8L0V)XH5W24.+[HT<?Z?H]N+=BP1%>+S- +MJVQZESVLN5%IH9]X[3SE]0`G_R[R"QP#A"$=VC0LD6W\D3;#,0YF.,E2$IGM +M`/4WL?E.H^?9):&KO"^&:Q`I49-#[1*.[6.SK78<=X(;AK4X`R%[T/32ZY$] +MSIQ\NL?9CGN<(MGCY.0%+9/6?X1[G,+A1G?@3@%D_#XB/-N#&[@6>\!O\H+_ +M6&%05*Y$@S$>_IJ%VR$P3;@98C=.K>/C&J<NQ4NR@QMR-1!5M`>U,!$P4X&? +M$RS@0&5QD@:G"/0$7S].0<G6=P)=&&B4[?VX&H(;Z##?QUD#T4(PO60GJR>. +ML[]MA#2FYL])?6D-:Y.C7FMLP=<:\5)_\E[C$9@1QC?:`UU^WO22(\`P8EZL +MS,Q3,4+N.([%B08'\Z=(L4)`^GS])8K'/,60=U4\-N)>,<I91V"T0ONW+8X` +MEFESF.NS\:+C=4:;N[\J01AB<RCN1*@84>`>"A]$>GC>;<9::CIC&_%\.ZEP +MTU"R5];+N6\Z$$9:W`&",O;0PBUT$",AVO,?DG4MX!$&3,7#>!6<A[KT!E0: +M/7D%`HO5,WMV,7TL,?)(VIOGW\E31MP7>95D2!YYZJQW"7GG5!O]MBG^(I<C +M,]J-/M.9O9@]8E^$6\#FFB'RJRL1F_H?^Y?AFI_C)([9;MWY][Q15WQ+'1LV +M7[?UN5`(F<@7S<>$OY)8^@[-G9D>L0[F*O,V#&W),7ERS![[25M[S6"/<'+> +M!DV+-LOV>>VY#BU'8ZG'3F+JG[K0Q6?=-WN:==GRBLHUX^\;5V--'S_9FFZS +M39Z0GCXA?:(U+6W:W6G3TB9;5_'+K?:Z2FLJ\MR\?)E/-<KK4LWR@E2+%!C3 +M9SM<-2S8[M/^\UGT$3_2_7-;P?=?T[RE>?,K<"Q:^,]MZ`\1Q$]UXF>Z?SY; +M\/W@:USJO"(H>ZVKJH*5/1'+OGM"6OJ$B7=9T]*G39PZ[>Z)UJ+"FI*B%:SX +M_/N@7"/D!A/L-O&"J?YZZ>+Y]\0S.NG/8XY+;__S=](IA./WTBF$XG</%D15 +MF917YBI;OK**%7CW%0J<&EL@>4]V7:I!GDV+;3X;_.(YP>"9$RIXC9P5B)3P +M/\`GUHF/P>?P`?C$\K\>IS1&\#7N_UIX&/ZK7?S5&MPV+6W2Y?@G;6YZ:38% +M*#^([9[:<D@ZV-YC3NSZ6@)8&D4!I/QJOFIYX=>5;[M*^R])->8#S3'FX%D4 +M\F[0MFB:VO@%&[(T+9GXE;4A2]N2J86OJ1NR="V9.O@:OR%+WY*IAZ_4#5EQ +M+9EQ\'7=AJSXELQX^,*G+5LR$U#,:S<TM0D[EA8,P!?"&Z;7*\";/O$R>.\# +MS!LV+$@UHGR4//44GY#1]+[P97K;@P/ZOYI_6>77Y']Y>T#V>D"'`67AC*P- +MAJ8C_-*I2<(2]KT`ON>R[PSXGLZ^)\%W&OL>#=^I[#L%OI/9MQF^C>Q;/S6) +MWVIZ"8:D86.Z7HN&-TS,5X)WRN7P+J#PXO[8_RMM]EHL/LLC"+WK<@`GI@\$ +MD+07`&D$(,W-Q\C<+R-S/M^P(;GI?;YLZDBA!)V5Q/E]<#Z`SD+B7`3.[Z$S +MES@SP#D=G;.(,QV<=Z)S$G'>`LX;T3F*.*\!IPF=PXE3/W4DWT+PG3CF\(.O +M(6][\/+W5?3Y>:A&EX!W(Z2W^5'/'.0QKVE_6H;L,'KQ.+;M"R$9ABI\4T?? +MD1$BNC`)(#7A^Q+@W^T_!N.=J__R\0CQM]Q5556ATOOD\1/'IR,*IR+#`M:0 +M-G7:I(G3TM*MO(J^'*7,P7'W/RC1XV%$E3BF/4I65%95+"\KK'Z493J)<L`T +M:):[K6E3IMT]>5JZS5KIXEU5+,_(^^_S.,YW^GNHR[(@U2!>P#MZ@?C)Y#E> +M3I3`TQ.7%O4@XY^P&2$>KY4TZ6V7RQOAG*?,P^E5^(V55?C`Z2IN)6J9*]L6 +M7.%QFP'IS\]%<<(J.U)HXF1Z"I!N%T!&?\*,'EPP\+V5</H]<]57T"(1(N]? +MSL7W+^?3]R;O_Q;O7V+\EUA\R[=X_Q+C/\[BC_H6[U]B_#P6O^.;X[\W!^+? +MQN*__LWQ?X?QS\VC\1_ZYOAK,7X'B[_OF^//Q_@_8O$/737^O/+"2J#5RJH2 +M?`NWN*349>775+JL%576XHJJLD*>RQ;*EY,WEO&=VI*RRE)7F:N<=Q5Q"RNL +MI17+'ZVV%M84EI06+BMU<5F%15:D?%>14.7"#-"UHJJPC,NAMK7&556-F=56 +M592OX')S9I$8X^F3O)@/\;L\%K`X83F47VU=5EC$+:FHL)85EJ^QEKIJ7*75 +MUHIB:Y6KK`)J4%)NK2SD5W+W\850E879]]$ZK2PL+P+X9I=4+[>N%BKX0JNK +M;KG+5>2*RDNHAE(C3E*/ZFI7-:2J<BWG*ZK6$"A=996X'5EAK:H0H$"^PKJR +MHIKGYL(?!*^HHK:<R\8RRPO+,!BQ!)6X`LC5:\J65926++>6EI0_6LW-JB@O +M=U%45[F*`9HB;E&EJXH^<,V7E+F*K%!B)".(Y*IRE0.0Y,W[VWEK=27DYL(W +MA='A*B^R%A8CAZF&9G*!STJ!)^#=1]T`+59H.2T7BHOX%Y96N0J+UD2%0867 +M"<7%F%MEX7)75*/'P`UREG49(,_EJH+LBOG:0B"$Y858&S4SC%BXK***YT!6 +MK*VH>M1:!`18&1M!S2P<!X`2R@&HY2M)H5'>I$JTSH75P'HQY6K!58U/A!<6 +M%4$VU5PFM</U`C(!D,+>Q85E):6T>2//BR\C-,!7+*\H91&0BJ/=L0FB6BO6 +MGZ&5]*O8D'!^7^,=0738FW0+FA_V,=J\G`-J4K@BBN1F`PY*RBE$#!$$-4#. +M8:`JPC`3L,OO9)E%ZA*%,M*9$9W1-:V-"<EU55<(54`?//23BJK"*D234!ZI +M!$002GD*9&'5"FA)H<Q55;*\L-0*3@%Y"Y(Y]H^BBK+"DG(NJZKB41<445+I +MBNI%I,OD`F1W5I1#$:275Z^!1B_CYI66NE9`?M4NUZ-(MY1@2UW%/%:RR%6# +MG81TT0@42UQU/,UDF5"]9@!;+*E8SI<25+/$83``?>4D6?65_!`S*DSE-86E +M)47A.G+S@!BM12IG`3#Y&/=5:`F)DL$PJZJBNOI.ZB#HH%5RU954\\"SJ#^I +M3!:R:98L0@#(J]7ND>.J*BNI)BRWR%5>`J'L7?*!KZ2'F[<(,$^R+:RI*"FB +M_&'YRI+2HBB^B240E!:YJI=7E51"Q3A[G6LY&UFL1.KB,M56+P7`HXF7@,L8 +M5'')"@&!GE=>*?`3@#[`8NGGP6!45254(G8HLH'?E):2AA>6KU3A";L)1-B4 +M5\%U)>*"QV[H+"]R%9>40[ZDI&E6D+IRKK1>F!Q9<D$-%#PZ:C>2.[1B=5A+ +M<5]Q88B=36K6XAI=$/>E/78E!]_9S5-29^$IEW60@4+6Q-D;FSWJA0I$OBRI +M+BDO'K\\(NV#9#D%Y];I4Z?=/6G:1)A;/[J2R944QO1CQ;)]2/&HOH;B&7T- +M@D7=I<'WSS@^CBJW=-%S6>G'`/I1N/PU@RBI#"(;.U%QKB8?OCN3+3=58LRL +MT;+(DX]Q=!$/GURL"S^YF-YVV1N-/YY)EEI!/B4/AEF:CX%(JPVO`&:D^0?C +MVZYQGKD:*0DF#5%O*^,I0*=1MEO(TNDP3-F2U-S&#\N2S)`*Y@!M/#M.R0X< +M1^#'`\FQ[1E]OEO+*N4PRH)9=EN:C[A'P-S_;>[\*?IL8J>]7T,/8X3=F+0Y +MY+X&U>19W$:A7X.3+/1:Q2W.#0G!D!!09F12S5\^X?Q)\1AW_KV!9_HO6X^N +MFJ'"`Y",#$.">CALC=./[WR&?:CVB9E<E&61!(5L^5Y#ZW+^`_%=[OR'$":Y +M%7PT(B0H(>%L2.@/"7W*+S.P.5"EDJQM1B`\^>"`^T0,,#_#X])F1O``G,T1 +M<-M>QI7I,1<`*5[9$3#ML2R4+AP_0SYG+]3*CN#Q0''B07`72Y:%F7@Y`DFX +M[AB)HL?8/214O]#CZHN<&^2C\+%L.EO\GH$U$Z;(FP(6W(A]AK0SKG(_(]E/ +M2/:3^)*=J:E%3ZZ<P>FA#541U^A]@IZ^Q69S6FJ3A/'X[*O#7',;>?ENB.Q. +M1O6C$:BHE*\G!UE>(:J_=GIO*KD`K\OC5B3W48^S6W(>)BHH)X@*RLEB0@RR +M^V3[9V;)_4RQ['RF6'*>*Y8A"*OK/A$3<!$"3A3CZ3RW&16^W>0XN/,D.0D- +MD1P0R?%),>17C)J-SA,Q`9]"`*1V]W7:6U'#IEAT?\*9FMOH7?J.5M'=JC$U +M_R=1W#EJVI.KEYR;94>7:4^F%M&T67JG6++O:/\[T,K3ICWS]%)?XN%(P'8: +M0!+,BX^$=;2?,5-/@]2E>CHW$^R-E)V;TX](3MQU)$C?B$CW`M(!Y!WM'Z$^ +MX?;$MP%1TN?$U>7[*^YCVH]J`<1B<:T66BP+.-'+>K++VRHY]LKNKF*Q0<L) +MPZ!.>T5[%T3M(E'YS_:CMLY886_=8"CN<'&G?C7'+5S3?X"D=N^5G8<]EK70 +M1*I2E@/0,$\K.3:OOQ!JX+C:H;A_]>+;KLWKW9O1H^9SW/:MORTDO"@[]^J< +MK=!!NI1$<K\C^+3.SP4PQ8/:7.5+HO%&U9_<1XOE!BTTQ"'3GG<EYS9:C%YR +M;"4ZICL17GG2VF)Y]EIML;Q@K1[:;G.Q33@D#"%/@&HXTYX^/-PJG6__V#P* +MCQ`D!A"OVZ1W)'N;;-]J>M[>!F@W[7%L3GS;=KCF-FS?-IVP;3UY)J]VN.R$ +M.,XVAE7[YL1VV^NUW>QPG"RT-I^KGXWZLSLU?8!/TY[I<PA)6*HPU9AWQ[HW +M2^[-0$Y('\72]$QH1R"UEQ&V,6^;]ER`T(7-YQKVR\Z=I.TMB\<ZL=6!CC=# +M#:$[KY$=F]M]9CX'`(LI-YW@0',>L`#IUA+DZ%?C.?*G-7;(P+$9\2,9U[:7 +M;39C(6\3/XHVC1'0YF@CKL,8:8Z$GWMM[YJ>_!6Y@A/[>!-'3T7Q.=([.J'5 +M]D[]3'*7Q%C[BUX"KG&U]);L>/%X2'(_3>!84G6):!AB7W(^73S(^0R2F62I +M76@3]J[[,V*!$!.@Y!RT"9!M(/%=Z)L`S$6"8G<P\0*YL2$9>K"4!/U;FH]$ +M_@$E\AY"Y.`^0]UGT7U"MD."DQY78RP_#;.V)Z;@'K+LM,@.<^YB'-\<AMS% +M2N(]40LHE/^&DRR9@O>R!G(O2W1BFLK,Y8?[8\<[=0Q5;3(>1KFCF.V7D\DI +ML^:08&*/+6^SP8"3@WM[2]@%0(GYRELVLH%W;HXQ61BN;ISA=2;DY5H\MNC- +M5W`CC9P&CB2-SR?Y27TQ=\U$E2],)H.?Z4"6<;N!QT>4Y;7FYA#OP*^)8RY) +MT[;KA&1\OSS+X)_$'L>E5SB-(V]X=F:1JY?\R7GD!>:J%#EK7*B+O'I2WS6F +M0],)!'<V>H_MLKMKOKB;C&_B&KP.Z'?DIL'H=T6O(?='3V6759F:-Y$81CD1 +MV7TBLG:PU^CQ;EP<[C"IEO^^WR)?(1@JIDB!]2%\'+@FKA4MO(<-4H56I\B9 +M`#A['-CTY"@H1B,$\12S4<XTC.F3,@W"`5\2.9]"BP'>_U>L^K7>JY6%0M1J +MB#I8RX^VG:_62I>@O^*-%:3(=&7E5'J-GL,P9K5!DRY=\M>1NXLTMDQS]1VV +M\S6W8=P<)2,<3Y.^6/F/*6%DX.6'^#X4EF.QG:^Z$>-?5I?[-53ETBM=BI3= +M.R6F[(%U-37?@P<YKB,*&K&OI(+L%Q*LJI;_U>J.0I@P(1^5)(+*E"EX#1*" +M<PPD`'MP[IB#($^1,YB>11K)T<=D/MG>9^L$/`4HYG2K+?)0VV)S]6VVOOI; +M$/9<9=*4:%P\/EF]Q:S6GZ'BH6_==5?`0[V3XJ`C@@-E<@P.Q@A]PG`DM[1P +MKC>S:EZ.G@"^M=GFQ\2-\UB?B+K6Z.KOF6OO8N]\&[7"*/6:O3P%IS)XA4E0 +M636)7+*':N'"M8T+C5I/]BPI7LHV=V83+6'_M-AWU]>_A2]-2$.DA7@AA)1M +MP5,K_%#Z1OC=D\DA?YWXEJ8XL=X8<W^>V/M(%%RK)JIW]!2+]4.X=<,\]JTY +M-)/#DS`3-[X^1^\P\5N],/W97CR*ZRN>P5E-F]M&A3CU5D=W#R<,[DS`WM7* +M`7?PI\GV'MP[Z)&R%ZC)7L$02-L(<K.X#G?3LT?#E`@3X<U8F\-X#,/W>CH( +MB<,GT?77\5==?Z5[]N%4F]-Q,GB"O&F=?C=Y_=RTA4'[<->`=\Y7I.-ZOG'E +M-?RX#'+/^=U<])PH5A=@6CH]2^,T;S?S%H_[A/1.D%Q/\<]G&QW=&H_S1.IG +M8D##7]>`[^$949];#&CY:_PW>W-76OAQC?XAN2NO13L^=^5PL+'$'T']_$-5 +M#C^<8X\F1^W\T_V;,!0OIA$H)'L0R6AE#:\G^2R<A)`'PO?=A>,WI2$^(&8M +MKR=U3)VDSH^#D?DQ34KF@3!]S!A-\R'?J>R;7G&8-1H'MRAWZ@#W:.;%TJ^W +M:DZ&0HT&C?B(_M+Z1XR%%P\4K'_$$.H-A=;/-7"`OHX,JZ8CXV8N3*.&",H[ +M)Q`2C:P"-%X7#P/ZRA_PG#5/>>`NTINAA?D[L%^MXN@_9=Y=..RO7$MB3;J+ +M$`&/^UY1ZP%][-ZJ<%D/3B")O@^)$$U?362D,`"?DR80_&/+WM"0@.V=Y!\G +M!G3\]?Y17G9+F7\"O5<%%R;P&@3\#M_->5E;^X=Y20.965.*$]6FI/A(BZ+! +ME\:K?=:3'Q(OZFK=Y'[4TK?I_:A-$%P'9B4S4)\*J`]NX7GANYP@Y%;(WY_G +MQ4Z2IWP:)/J#B*"9'OM9,:03XCWVS_UZK]AF1/6JX]-#_-!5&H_].,3&]1N, +M>@W@TG*ENGA<AP8RQ##L%^^$_HRW/&)_GOS-^R^O8_SA+/[#5XU?!&,4R*M+ +M5H(]$^Q2L+U@5X+]!-A\'YEP+JD#^P=@KP-[&]B-8/\*[":P'P2[!>R7P-X( +M-HA02[Q@`Y1+-H,-;&')TV##4+3D&;"KP=X*-@AP2[:!_2.PMX-="/8.L(>` +MO1/LY6"_V(=`<TM:P889T9*]8$-MEK2![0;[$-AY8!\&^UZPCX+]$-A=8,\& +M^P38UX-]$NS[P>X&>SW8:3!.Q4.4!6`#$YV=P^PES%[*[(>8_0BS5S*;[\?K +M@+C9=<S=Q-PMS+V9N9]F[FW,O9VY7V3N5N8^Q-R'F?L$<P>8.^U+4I_9D[XD +M]9G]D$9#X*\$&^-YP?X!E@OV`U@NV##.S7X&;*CO[*U@PR@X6V'Q>EF\/A:O +MG\4+L'@96AIOMI;&FZNE\19H:;P<+8VW3DOA:&+Q#7H-@=?(;#.S+<Q.9G8* +MLZW,3F7V:&:/8W8:LR<Q>RJSIS,[@]FSF3V7V0N8G</L)<Q>RNR'F/T(LXN8 +MO9+9I<RN9#;/[#IFKV-V([.;F-W"[(W,]C)[,[.?9O8SS-[*[&W,WL[L'<S> +MR>P7F=W*[+W,;F/V(68?9O919G<Q^P2S3S*[F]D]S#[+;(79O<SN8W8_LP/, +M#C*;BZ.VGMD&9AN9;6:VA=G)S$YAMI79J<P>S>QQS$YC]B1F3V7V=&9G,'LV +ML[GO?M_]OOO]VS\4P%#+.HNYD]@E7P\S=PJ8>\#<SA%Y@1O-D?&4PRT7?!AQ +M!!A\/AJ/;Q82@8/CIJ'B,TL?!P8D*!Q3N!I<G0<S(ZK\A6#JP1B9&V0!#J;S +MW"R.C/_<#0R6<<P/EU-P/I2..M)@\$PGR!G<4%8&B.O<]S@R9I)?(HN+,#U( +MGT@A/YPAS0.#FCGXX#4*GWC:"@7/"7@LA%VE8F8PXHRR`DPR*R.>Y8%+O;C) +M-);A$'&`.L_7@LD$<P<NC$?EAS,@5*8:S!%YB;L&#-YWC1I%('H3V1`7ND:" +MF0_F.H[(4]R->-44&)0@\=#YS1R1NXAZ>#Z86SDB%W&X`9<-YC:.[AV"5,BM +M8'7*967/9FVRF)7Y""O#P6!:P'!:PMKB(5:6D]$"QVCF"=:6RQAM/,I@6\1H +M:#G#014KLX#1RO<9C$M8G<I9G>]C;?(LJ_L>UI9E#+;5+._[6=U6L3H4L;K] +MF.6QB>7-,9C7,-QP#%<_8CBO9'G]@-$&S^KZ,H-18C`_R7#D9G456-VJ6=E/ +M,1JJ96U=RG#.,5IXAN%R+8/Y/QFN.!:78W7T,%QPC-9:69V;&0Y_S\I\CL'* +M,5A:6-]J8C"(C"9_RNJ^@97]0U97CO6AQUF=.-8''V-];BOK6[]A?7TS"WN: +MY<VQLF0&&\=HX0\,%H[A[C]8V1R+NX7UL5^PNGH9;CF&0X[Y;6.P<BP/CK7I +M'QDLNUA>/V=M^1-F?J;.>MCW;H;[[2SN+UG9'&N#7[.Z_I:%_1?C:<^S;X[! +M\@*C28ZEX1AN.)8WQ_+X'3,OL;;:P0S'<,.QMN-8&3N9X5C=.%;6BZR.'/OF +M6%TXEC?'^@;':.051K/AS4+V0U[,]47X>APPN9Y*ZA[*W&FL`48R]]3)U'TC +M<^OO9GJFS)W#"IK*W&W[(Q=#XG&U[5HBEQ&>B>&629%^2/)C"'N8N<_>1=TN +MYLYX@;JKF+MI8H1>2?D,42+C[:GDTDU*1QC>,I:&/\W<J7^,M#>ZE?^,M"/) +MCY6WD^'K$8:O3C5\'W4?9V[K'=3]/G,OJ:+NOZKX983B9^X76?W^J>;W#'7_ +MB[FW3Z5N?#*&X(?!<PUSMTUCXS!S6QM8>S!W'\/_!.;.8.V3P=Q+F?L^YE[" +MX'F(N6>W,3ZENEE[53%W(VO_-<Q]\E?4O9ZY<]B`L$&%]W;67YE;81WI9\R] +MF;7_L\S=PL+_P-R&="[\W`VZG][&VH.Y)S%X3Z#[E@@]GF'A12S_?S!W-^NP +M%YF[=QR3"[2,OA@^AFFIK"*P^"-9^$[&,&[64GH;S>@MC;G',3>^1(GTS^;O +MW'TL/(V%/\+"%1:^FN6_D=6GGKF3F5MF[AYVD\PFYO8R?/^,Y3^)Y?\;EC_. +MQ['M7U33LSML_L3<C2R_-YA[`>M?[V@I/E5Z^2L+;V/]YY\JO$QX^TI-S_K; +M$!UU][/^<9..PC>5P3>6A6]C]#J9N1L9`YS)W%-9_YG#W*69U+V8N5,9?K[/ +MW(\P>EG-W`KKKV[F-K+X&YC[F78VKC!W<"9U_T3-_[>,K^LH/N8R?+RBPO=+ +MZGX-W5"URIVT/=]@X6D5-/PD<R]@^,=G5+%]'M%0_O@E"S<PP3NDH_2WD/'N +MP7J*O^D,?R/T-/U#+#T^Q4;JQ_C9W7H*;[C_L_!M!ZE[+G/WL/!<YO:R_OT0 +M<P?9C4;%S)W#Z*6"N4^P@:^>N=/8>"(Q=Q'+SZOFS^K_2^;&?36"7^:>RO#_ +M"G,O9>WU)^;N8P-A%W.7,OKJ4?,?1=V*FI[QISZUO@R>2\Q]F+5??!R#]T[J +M'A['^L^7P"-A,G('"W^$#:B3F7OK`>K.9.YQK'X+F3O(X,]7XS-\/<K<R6Q\ +M7</<)[<R?LK*YW%]#^PG6'@/&P]^R,+GQI'U/^[G:OZ,WGX=1^DE@]'+3A9N +M9OWG9>9N9>Z#S&VU4?=;S*T*$N\Q]R%&CSW,O8V-#W]G[B8V?OV#E3^;E1]D +MX8V,?QCB&3P,7R.8V\KX\2W,/971QQCF7L#Z]SW,S3-ZSHJG_:7T+#M7P,*] +MK#ZY\12>N0R>!UEX$</W,N8>Q_+GF7OK:NIN4..S]FIF[L,,/CF>M@>NA^+< +M=7,\E9G4WYOQ=&ZM_MYCZ5]D_>OOS#V)T6<O<W>U4O=YYFYE^$I(H&Z5']W( +MW-V,?Z<RMY7QYSN9NY'5[V[F3F;TFY%`\;.`X6<."U=O,,MAX3DLO$#-G_'/ +ME<QM8?@H9^Z@G;KKF+N?C<<-S/T(ZP_-S)W#\"TS-\_H:Y.:?RIU/\/<@9%, +M+E?KQ^2-WZGPL?S_R-PG6'ZMS-W%ZO^:"@_#YY\3*/]4^^L)%CZ)P?]>`I4/ +M5\91?'R40-L?]P=PKN1G\0^Q^%\P]].,OK]B^%S*\*DU4/<2%;\%L^]?F.F8 +M-XLKH&<5"@H*BOB*0J[`557%%:".-W@5\U5K4`L:=8H+JGEA&5=04EW(\VLP +M>DDUOQ)5YUU%7$%I-5\(>:QP\94E1<06T(9?E5#N0DU^KJ`.(J.Z->914EZ, +MH<M+787E0B5)4.2J=:W!L/)"*)H<KR5`E=04E=P%7W,6+,K*7%"P*#O[/ON2 +M@B6960OL!1BANJSP4=<R`?);SK*'S%SE-1P`7%7MHIFO0&C`S5>4<@4UM855 +MY760MKRB'*I5*?`()%>`E2DJJ6(1(0&_'))"=:L0%0/P4%`LE`_PPG))0<N+ +MJUU\=:4+,5.&9RQ<RQ'!KKH2GF2^''&%VONDM#!:Z+%14J<UU<OY4NJS$J*4 +M%15@+0M606ZN<%Q$$"FJA)45W5QJ-J@J7A!U8`]BE907%926+"N@T1!J;"QZ +M2)#D7(1-4@X0%D+QT`)5U=P`!U]87E18513K6Y!3R*]<4`%%NL*U*JB&\%(D +M)GXYGMA9!OZ/(M@K(F!75I64\]!^:JT+"O"X!1XO(GY(D:@[3]"P#($'-%27 +M5B!*BVL+2R&[NC*&PJA&";<OE$3;-X+R:CX,.CE-50`-'^L!D8M*BO!J1H*] +M0G)JAWR6%]*&*5?;JK:JA'>QEJA06QVSXPM(;2LKH'HTYLI"GE(J5E^-RR\' +MVJHE$8I95RBI<I7S526NZAC"*P(R7P%YN\K**FH8;LI)=ZVI+E>1J)(*HY." +M@K)E!<N%*O"L(T4L+ZVHAK2(1U=5`1:#W0SJ!<F1SF<)55AX+F!,;4JH+*.- +MX@ARJUVEE*H!ZE*A&E!&<B;HC?3K8A4LK!6/!V2J2]92VJP%!&$4AKXH$J=M +M2WHIQ*QR+2\M+"DKX%VEI23WY<48L:J0H&PU\(<J5UE,"Y)8*D70L_&$K9$F +MH=#CC078?5@*[`T4\MFNXD*A-*;Z6,,:!B42,5^YHJJ2`$QP7$C]BZKP+`]$ +M)J@J$,HCS%$MFO9_>ED"R3:;M$]%$65P!27J7:`$/810"@H@>Y(,O#`_\D$. +M_A!F6[@BC%!!S:B*+R7,#ID,XW1X?`8P4EFPDF9!.@8E;J@&9(3H@]X)R"VK +M+&><N`;@KHLT#."+T10Y+@35`LAX.E00W`'/+:G"3D*NGX@D7%'!AXD1>0_A +MS36$;ED30Q\M%5P<NDK*5TRS\BM+JM63E7B.K=I:#"R!,I318\99:U>6+%^) +M1^.`[\)X,Q[H+!P>^ZVB3%"'$0"JN*0NFH/$=B_&RJN750&&(R1744YX-FE^ +M.B``_.45!':*QS"*>3SD23HUZ144B37ACE!,&Z8,HG(J10CEQ%6GQJ&=$^)6 +MN5PXMI+F9AV7C$F4`HM9$8SFN()'2Y#9NXH*>1C'@?67`S!0F>+EY=A>B/OJ +ME4#JV%1%2"<%](0FI8KO?M_]OOM]]_ON]]WON]]WO^]^W_V^^_U__<.U=W,? +MQXWN^_9I<$^Y!TS;08[K>IWCMG=1?]0?6MK-<18#W:>?JZ/V(;:OAVO7N)Z. +M:X2X+X!KL;A>BWM$N.Z(>XFX_XA[DKCOB'L7N-^&:]*XSX-[X[B?@WORN"^` +M>T>X?X![5KA/B'M+N+^'>\ZX+X5[`U[?1:*IY/4EC:'VIUG4?IS9SS$[F]D? +MV*@]?AJU[VBD]O!9U-;:J7U+!K6?9/[QZZD]OY[:CRVB]M]9O*P_,#@F4_LV +MENYQYE_#W+]@]L'=U'Z3P37Q16H?^R.U.[)9_.>H_<E,EO^]+#YS9S/[(BOG +MIW<Q^*=2>PBK3]X]#&Y6[V4LGT\SJ;U?]7^!VL,64GL:@_?,.I8?<[_'XKW" +MX'R`E?.+=&JO8O6XQ,HY^%L&)XM_RUQ6+U;_.W:R^MU-[3V[J+V!Q5OU/8;7 +M^ZC]`O,?\A*UWV'XO&,^B\?\'V?NQUGX+0R?6H;OYYB=ZV#I.UF\#H9/-ROO +M3]1>R^S'#C#X][-V8_ZO,#R]Q]RO[Z/VC_;%TLDK#(X-/Z5V^0)6WA%JW\CJ +M/Y/!5\SLW^UEY;)\'F#EO\#BE[-XOWZ=Q6-POL#<[S$[[TUJUQ.;W"2#^@+0 +M+R<(U5438)[OJG,MGU!:-+ZZ@NH#XN/!"ZP<=Q9,\!;HK[=RW,9;V/Y[*M4] +MQ-V!C=!GWTVENH/D$F9P[TVENH'H;@'W?Z52W43\;0;WCU(C.I5-X&Y,I3J) +M1#<&W"6I5->0[*W$:2[C6?J!/.R.6#<NR#D*5Y3@RM77\3Z5OWR%VH_:;V&R +MM%21,MIH_Y=,1CPTB/[?-\8X3@-&"T8'1@\F#DP\F`0P!C")8+XNCR0ICAL$ +MQ@AF,)@A8$Q@R`;Z_Z:Y6ODCH7PP1C"#P0P!8P+#C=3_[YJ!96N_DQV^^U%^ +MA:2@8SP&]_!1ESJ!R5:X)XJZBLCKD'^AGC3JA*,^.?)#U%M$77/4FT:=:>1I +MR,=0#QWY'VX/(U]$_6_474?]<=R71SUQ8+-$;QI9+.I+X]8RJH^@KC1N(Z-N +M.^JG(ZM#M2;<NKV3R6FH/XU;\;B=CEONJ#:&6\NX?8\J`K@-CJH0J'Z`*GNH +MIH4ZTK@=CRHNN.V/6^NH'XXZQ*@_C&N\R#Q19QCUA5%7&/6$44<8]8-1-QCU +M@G$@034/5+7![7)4.40]8-0!1OU?U/U%O5_4^45]7]3U17UFU&5&/4O4948] +MYD?^#Y:/>L:HLXGZQ:A;C&J+N$^.^L2H2XSZFZA#C/K#J(>,^L.H.XQZPZ@S +MC/K"J"N,>L*HVXGZP:@;C'K!J!.,^L"H"XQZP*@#C+K?J/.)>L"H`XSZOZAJ +MB7J_J,*':E*H^H'J/Z@BA&J'J%J(ZF:H\H?;_KAUK^KQJOJ[J+>+.KNJOBZJ +MLZ!*#JHEH6XNZN6B3B[JX[8R]1E4&7H5##X-@.IHJ/*&:@=M8%!]`E58\%`F +MROEXARG>]HGZIH?!X+MZ>)OGG\'@^])OH"X)F+?`X+0!'Q8ZQE%]U!-@_@+F +M'3#O@L&WO$ZAK@)']5/QY:_38/`Y[P_!]*#>`I@S'-571=69OZ$N"IB/P>!1 +M4A^83SBJOXIW.?T#S*=@/J-3$PYOZ/^"H_JL>/0?IAS<.=17`8/'CB^`N<A1 +M_5:\A>PK,)?`A+[K_Z3_9S*1!L^RX)D(5)?!LQ!X#@+/0.#Y!SS[@.<>\!P& +MGGO`^1Z>>\`S#WC>`<\ZX#D'/..`>M5XM@'/->"9!CS/\,#7]/__4^5_U_^_ +MZ_]7ZO]?N[;R9:S.'/9U+DGSM?,2HB^91?4<<?U"U1?^[Z_KQ)9S]'\IWZ0! +M@F^J]M_/=R7`I&-UM@[XI0WX#4P;QWBC.^S3-^#MTONIG?$4M5M>H_:J`+$; +MF\832+N&+2=VT[L_)K;KC3?0MA9LU2);46KF3D'[5YNO*P,[XV_/I/T*;.^- +MA_:^`_:DV[Y\U#B+:^R9LN:US%G<UI/-^9-J9G&'%ZXH:__]+&[&#Q\YN_2C +M61D;=]?=\/RULW,^._/.V>N^-_L__N*(?ZNO<;::;D1YW.[=K9NRO[QPKT^W +M:*ICX@UI%^;6/O;`]`/5#:<772OLE4[^^(5CSTR_ZS?;_W+KN7FV&;_IG_V5 +MZ=F)/__QQK<,KSPX:E;%CJ+1\8>3HO'C+'^TO**V7+UY\QO;XJ&=>%@;Q@HP +MUX'1@OD,F,0I,`?![`3S#!@)3`68I6"RP4P#DPHF&8P1S$5@+B?!'`;S,ICM +M8#:`J0&3#V8N&!N8F\%8P%P"AO09F+^".0CFCV"\8&K`+`5C`Y,"9A"87F!@ +M?P&S'\PV,!O!E(.9">9V,`8P`6!T'X'9!^89,"*8$C`.,'>#L8#Y`ACB!V#^ +M#.:W8'X$1@)3!Z8(S&(P66#&@TD&<PZ8Z%DPQ\#L![,=S)-@?@!F&9B,WX9I +EL.&[&=%WO^]^W_V^^WWW^^[WW>^[WW>__YM__P\[+-(F`!`!``!F +` +end diff --git a/lib/libc_r/test/mutex/Makefile b/lib/libc_r/test/mutex/Makefile deleted file mode 100644 index 334d2a7a86ae..000000000000 --- a/lib/libc_r/test/mutex/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# $Id:$ - -PROG= mutex -SRCS= mutex.c -NOMAN= 1 -LDFLAGS= -pthread - -.include <bsd.prog.mk> diff --git a/lib/libc_r/test/mutex/mutex.c b/lib/libc_r/test/mutex/mutex.c deleted file mode 100644 index 1fe45027b49b..000000000000 --- a/lib/libc_r/test/mutex/mutex.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* - * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Daniel M. Eischen. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ -#include <stdlib.h> -#include <unistd.h> - -#include <sys/ioctl.h> -#include <assert.h> -#include <errno.h> -#include "pthread.h" -#include <sched.h> -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <sysexits.h> - -#if defined(__FreeBSD__) -#include <pthread_np.h> -#endif - -#ifndef NELEMENTS -#define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0])) -#endif - -#ifndef NUM_THREADS -#define NUM_THREADS 10 -#endif - -#define MAX_THREAD_CMDS 10 - - -/*------------------------------------------------------------ - * Types - *----------------------------------------------------------*/ - -typedef enum { - STAT_INITIAL, /* initial state */ - STAT_WAITCONDVAR, /* waiting for condition variable signal */ - STAT_WAITMUTEX /* waiting for mutex lock */ -} thread_status_t; - -typedef enum { - FLAGS_REPORT_WAITCONDMUTEX = 0x01, - FLAGS_REPORT_WAITCONDVAR = 0x02, - FLAGS_REPORT_WAITMUTEX = 0x04, - FLAGS_REPORT_BUSY_LOOP = 0x08, - FLAGS_IS_BUSY = 0x10, - FLAGS_WAS_BUSY = 0x20 -} thread_flags_t; - -typedef enum { - CMD_NONE, - CMD_TAKE_MUTEX, - CMD_RELEASE_MUTEX, - CMD_WAIT_FOR_SIGNAL, - CMD_BUSY_LOOP, - CMD_PROTECTED_OP, - CMD_RELEASE_ALL -} thread_cmd_id_t; - -typedef struct { - thread_cmd_id_t cmd_id; - pthread_mutex_t *mutex; - pthread_cond_t *cond; -} thread_cmd_t; - -typedef struct { - pthread_cond_t cond_var; - thread_status_t status; - thread_cmd_t cmd; - int flags; - int priority; - int ret; - pthread_t tid; - u_int8_t id; -} thread_state_t; - -typedef enum { - M_POSIX, - M_SS2_DEFAULT, - M_SS2_ERRORCHECK, - M_SS2_NORMAL, - M_SS2_RECURSIVE -} mutex_kind_t; - - -/*------------------------------------------------------------ - * Constants - *----------------------------------------------------------*/ - -const char *protocol_strs[] = { - "PTHREAD_PRIO_NONE", - "PTHREAD_PRIO_INHERIT", - "PTHREAD_PRIO_PROTECT" -}; - -const int protocols[] = { - PTHREAD_PRIO_NONE, - PTHREAD_PRIO_INHERIT, - PTHREAD_PRIO_PROTECT -}; - -const char *mutextype_strs[] = { - "POSIX (type not specified)", - "SS2 PTHREAD_MUTEX_DEFAULT", - "SS2 PTHREAD_MUTEX_ERRORCHECK", - "SS2 PTHREAD_MUTEX_NORMAL", - "SS2 PTHREAD_MUTEX_RECURSIVE" -}; - -const int mutex_types[] = { - 0, /* M_POSIX */ - PTHREAD_MUTEX_DEFAULT, /* M_SS2_DEFAULT */ - PTHREAD_MUTEX_ERRORCHECK, /* M_SS2_ERRORCHECK */ - PTHREAD_MUTEX_NORMAL, /* M_SS2_NORMAL */ - PTHREAD_MUTEX_RECURSIVE /* M_SS2_RECURSIVE */ -}; - - -/*------------------------------------------------------------ - * Objects - *----------------------------------------------------------*/ - -static int done = 0; -static int trace_enabled = 0; -static int use_global_condvar = 0; -static thread_state_t states[NUM_THREADS]; -static int pipefd[2]; - -static pthread_mutex_t waiter_mutex; -static pthread_mutex_t cond_mutex; -static pthread_cond_t cond_var; - -static FILE *logfile = stdout; -static int error_count = 0, pass_count = 0, total = 0; - - -/*------------------------------------------------------------ - * Prototypes - *----------------------------------------------------------*/ -extern char *strtok_r(char *str, const char *sep, char **last); - - -/*------------------------------------------------------------ - * Functions - *----------------------------------------------------------*/ - -#ifdef DEBUG -static void -kern_switch (pthread_t pthread_out, pthread_t pthread_in) -{ - if (pthread_out != NULL) - printf ("Swapping out thread 0x%x, ", (int) pthread_out); - else - printf ("Swapping out kernel thread, "); - - if (pthread_in != NULL) - printf ("swapping in thread 0x%x\n", (int) pthread_in); - else - printf ("swapping in kernel thread.\n"); -} -#endif - - -static void -log_error (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - fprintf (logfile, "FAIL: "); - vfprintf (logfile, fmt, ap); - error_count = error_count + 1; - total = total + 1; -} - - -static void -log_pass (void) -{ - fprintf (logfile, "PASS\n"); - pass_count = pass_count + 1; - total = total + 1; -} - - -static void -log_trace (const char *fmt, ...) -{ - va_list ap; - - if (trace_enabled) { - va_start (ap, fmt); - vfprintf (logfile, fmt, ap); - } -} - - -static void -log (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - vfprintf (logfile, fmt, ap); -} - - -static void -check_result (int expected, int actual) -{ - if (expected != actual) - log_error ("expected %d, returned %d\n", expected, actual); - else - log_pass (); -} - - -/* - * Check to see that the threads ran in the specified order. - */ -static void -check_run_order (char *order) -{ - const char *sep = ":,"; - char *tok, *last, *idstr, *endptr; - int expected_id, bytes, count = 0, errors = 0; - u_int8_t id; - - assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL); - strcpy (tok, order); /* tok has to be larger than order */ - assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0); - log_trace ("%d bytes read from FIFO.\n", bytes); - - for (idstr = strtok_r (tok, sep, &last); - (idstr != NULL) && (count < bytes); - idstr = strtok_r (NULL, sep, &last)) { - - /* Get the expected id: */ - expected_id = (int) strtol (idstr, &endptr, 10); - assert ((endptr != NULL) && (*endptr == '\0')); - - /* Read the actual id from the pipe: */ - assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id)); - count = count + sizeof (id); - - if (id != expected_id) { - log_trace ("Thread %d ran out of order.\n", id); - errors = errors + 1; - } - else { - log_trace ("Thread %d at priority %d reporting.\n", - (int) id, states[id].priority); - } - } - - if (count < bytes) { - /* Clear the pipe: */ - while (count < bytes) { - read (pipefd[0], &id, sizeof (id)); - count = count + 1; - errors = errors + 1; - } - } - else if (bytes < count) - errors = errors + count - bytes; - - if (errors == 0) - log_pass (); - else - log_error ("%d threads ran out of order", errors); -} - - -static void * -waiter (void *arg) -{ - thread_state_t *statep = (thread_state_t *) arg; - pthread_mutex_t *held_mutex[MAX_THREAD_CMDS]; - int held_mutex_owned[MAX_THREAD_CMDS]; - sigset_t mask; - struct timeval tv1, tv2; - thread_cmd_t cmd; - int i, mutex_count = 0; - - statep->status = STAT_INITIAL; - - /* Block all signals except for interrupt.*/ - sigfillset (&mask); - sigdelset (&mask, SIGINT); - sigprocmask (SIG_BLOCK, &mask, NULL); - - while (done == 0) { - /* Wait for signal from the main thread to continue. */ - statep->status = STAT_WAITMUTEX; - log_trace ("Thread %d: locking cond_mutex.\n", - (int) statep->id); - pthread_mutex_lock (&cond_mutex); - - /* Do we report our status. */ - if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX) - write (pipefd[1], &statep->id, sizeof (statep->id)); - log_trace ("Thread %d: waiting for cond_var.\n", - (int) statep->id); - - /* Wait for a command. */ - statep->status = STAT_WAITCONDVAR; - - /* - * The threads are allowed commanded to wait either on - * their own unique condition variable (so they may be - * separately signaled) or on one global condition variable - * (so they may be signaled together). - */ - if (use_global_condvar != 0) - pthread_cond_wait (&cond_var, &cond_mutex); - else - pthread_cond_wait (&statep->cond_var, &cond_mutex); - - /* Do we report our status? */ - if (statep->flags & FLAGS_REPORT_WAITCONDVAR) { - write (pipefd[1], &statep->id, sizeof (statep->id)); - log_trace ("Thread %d: wrote %d to pipe.\n", - (int) statep->id); - } - log_trace ("Thread %d: received cond_var signal.\n", - (int) statep->id); - - /* Get a copy of the command before releasing the mutex. */ - cmd = statep->cmd; - - /* Clear the command after copying it. */ - statep->cmd.cmd_id = CMD_NONE; - - /* Unlock the condition variable mutex. */ - assert (pthread_mutex_unlock (&cond_mutex) == 0); - - /* Peform the command.*/ - switch (cmd.cmd_id) { - case CMD_TAKE_MUTEX: - statep->ret = pthread_mutex_lock (cmd.mutex); - if (statep->ret == 0) { - assert (mutex_count < sizeof (held_mutex)); - held_mutex[mutex_count] = cmd.mutex; - held_mutex_owned[mutex_count] = 1; - mutex_count++; - } - else { - held_mutex_owned[mutex_count] = 0; - log_trace ("Thread id %d unable to lock mutex, " - "error = %d\n", (int) statep->id, - statep->ret); - } - break; - - case CMD_RELEASE_MUTEX: - assert ((mutex_count <= sizeof (held_mutex)) && - (mutex_count > 0)); - mutex_count--; - if (held_mutex_owned[mutex_count] != 0) - assert (pthread_mutex_unlock - (held_mutex[mutex_count]) == 0); - break; - - case CMD_WAIT_FOR_SIGNAL: - assert (pthread_mutex_lock (cmd.mutex) == 0); - assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0); - assert (pthread_mutex_unlock (cmd.mutex) == 0); - break; - - case CMD_BUSY_LOOP: - log_trace ("Thread %d: Entering busy loop.\n", - (int) statep->id); - /* Spin for 15 seconds. */ - assert (gettimeofday (&tv2, NULL) == 0); - tv1.tv_sec = tv2.tv_sec + 5; - tv1.tv_usec = tv2.tv_usec; - statep->flags |= FLAGS_IS_BUSY; - while (timercmp (&tv2, &tv1,<)) { - assert (gettimeofday (&tv2, NULL) == 0); - } - statep->flags &= ~FLAGS_IS_BUSY; - statep->flags |= FLAGS_WAS_BUSY; - - /* Do we report our status? */ - if (statep->flags & FLAGS_REPORT_BUSY_LOOP) - write (pipefd[1], &statep->id, - sizeof (statep->id)); - - log_trace ("Thread %d: Leaving busy loop.\n", - (int) statep->id); - break; - - case CMD_PROTECTED_OP: - assert (pthread_mutex_lock (cmd.mutex) == 0); - statep->flags |= FLAGS_WAS_BUSY; - /* Do we report our status? */ - if (statep->flags & FLAGS_REPORT_BUSY_LOOP) - write (pipefd[1], &statep->id, - sizeof (statep->id)); - - assert (pthread_mutex_unlock (cmd.mutex) == 0); - break; - - case CMD_RELEASE_ALL: - assert ((mutex_count <= sizeof (held_mutex)) && - (mutex_count > 0)); - for (i = mutex_count - 1; i >= 0; i--) { - if (held_mutex_owned[i] != 0) - assert (pthread_mutex_unlock - (held_mutex[i]) == 0); - } - mutex_count = 0; - break; - - case CMD_NONE: - default: - break; - } - - /* Wait for the big giant waiter lock. */ - statep->status = STAT_WAITMUTEX; - log_trace ("Thread %d: waiting for big giant lock.\n", - (int) statep->id); - pthread_mutex_lock (&waiter_mutex); - if (statep->flags & FLAGS_REPORT_WAITMUTEX) - write (pipefd[1], &statep->id, sizeof (statep->id)); - log_trace ("Thread %d: got big giant lock.\n", - (int) statep->id); - statep->status = STAT_INITIAL; - pthread_mutex_unlock (&waiter_mutex); - } - - log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id, - (int) pthread_self()); - pthread_exit (arg); - return (NULL); -} - - -static void * -lock_twice (void *arg) -{ - thread_state_t *statep = (thread_state_t *) arg; - sigset_t mask; - - statep->status = STAT_INITIAL; - - /* Block all signals except for interrupt.*/ - sigfillset (&mask); - sigdelset (&mask, SIGINT); - sigprocmask (SIG_BLOCK, &mask, NULL); - - /* Wait for a signal to continue. */ - log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id); - pthread_mutex_lock (&cond_mutex); - - log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id); - statep->status = STAT_WAITCONDVAR; - pthread_cond_wait (&cond_var, &cond_mutex); - - log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id); - - /* Unlock the condition variable mutex. */ - assert (pthread_mutex_unlock (&cond_mutex) == 0); - - statep->status = STAT_WAITMUTEX; - /* Lock the mutex once. */ - assert (pthread_mutex_lock (statep->cmd.mutex) == 0); - - /* Lock it again and capture the error. */ - statep->ret = pthread_mutex_lock (statep->cmd.mutex); - statep->status = 0; - - assert (pthread_mutex_unlock (statep->cmd.mutex) == 0); - - /* Unlock it again if it is locked recursively. */ - if (statep->ret == 0) - pthread_mutex_unlock (statep->cmd.mutex); - - log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id, - (int) pthread_self()); - pthread_exit (arg); - return (NULL); -} - - -static void -sighandler (int signo) -{ - log ("Signal handler caught signal %d, thread id 0x%x\n", - signo, (int) pthread_self()); - - if (signo == SIGINT) - done = 1; -} - - -static void -send_cmd (int id, thread_cmd_id_t cmd) -{ - assert (pthread_mutex_lock (&cond_mutex) == 0); - assert (states[id].status == STAT_WAITCONDVAR); - states[id].cmd.cmd_id = cmd; - states[id].cmd.mutex = NULL; - states[id].cmd.cond = NULL; - /* Clear the busy flags. */ - states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); - assert (pthread_cond_signal (&states[id].cond_var) == 0); - assert (pthread_mutex_unlock (&cond_mutex) == 0); -} - - -static void -send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m) -{ - assert (pthread_mutex_lock (&cond_mutex) == 0); - assert (states[id].status == STAT_WAITCONDVAR); - states[id].cmd.cmd_id = cmd; - states[id].cmd.mutex = m; - states[id].cmd.cond = NULL; - /* Clear the busy flags. */ - states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); - assert (pthread_cond_signal (&states[id].cond_var) == 0); - assert (pthread_mutex_unlock (&cond_mutex) == 0); -} - - -static void -send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m, - pthread_cond_t *cv) -{ - assert (pthread_mutex_lock (&cond_mutex) == 0); - assert (states[id].status == STAT_WAITCONDVAR); - states[id].cmd.cmd_id = cmd; - states[id].cmd.mutex = m; - states[id].cmd.cond = cv; - /* Clear the busy flags. */ - states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); - assert (pthread_cond_signal (&states[id].cond_var) == 0); - assert (pthread_mutex_unlock (&cond_mutex) == 0); -} - - -static void -mutex_init_test (void) -{ - pthread_mutexattr_t mattr; - pthread_mutex_t mutex; - mutex_kind_t mkind; - int mproto, ret; - - /* - * Initialize a mutex attribute. - * - * pthread_mutexattr_init not tested for: ENOMEM - */ - assert (pthread_mutexattr_init (&mattr) == 0); - - /* - * Initialize a mutex. - * - * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY - */ - log ("Testing pthread_mutex_init\n"); - log ("--------------------------\n"); - - for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { - for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { - /* Initialize the mutex attribute. */ - assert (pthread_mutexattr_init (&mattr) == 0); - assert (pthread_mutexattr_setprotocol (&mattr, - protocols[mproto]) == 0); - - /* - * Ensure that the first mutex type is a POSIX - * compliant mutex. - */ - if (mkind != M_POSIX) { - assert (pthread_mutexattr_settype (&mattr, - mutex_types[mkind]) == 0); - } - - log (" Protocol %s, Type %s - ", - protocol_strs[mproto], mutextype_strs[mkind]); - ret = pthread_mutex_init (&mutex, &mattr); - check_result (/* expected */ 0, ret); - assert (pthread_mutex_destroy (&mutex) == 0); - - /* - * Destroy a mutex attribute. - * - * XXX - There should probably be a magic number - * associated with a mutex attribute so that - * destroy can be reasonably sure the attribute - * is valid. - * - * pthread_mutexattr_destroy not tested for: EINVAL - */ - assert (pthread_mutexattr_destroy (&mattr) == 0); - } - } -} - - -static void -mutex_destroy_test (void) -{ - pthread_mutexattr_t mattr; - pthread_mutex_t mutex; - pthread_condattr_t cattr; - pthread_cond_t cv; - pthread_attr_t pattr; - int mproto, ret; - mutex_kind_t mkind; - thread_state_t state; - - /* - * Destroy a mutex. - * - * XXX - There should probably be a magic number associated - * with a mutex so that destroy can be reasonably sure - * the mutex is valid. - * - * pthread_mutex_destroy not tested for: - */ - log ("Testing pthread_mutex_destroy\n"); - log ("-----------------------------\n"); - - assert (pthread_attr_init (&pattr) == 0); - assert (pthread_attr_setdetachstate (&pattr, - PTHREAD_CREATE_DETACHED) == 0); - state.flags = 0; /* No flags yet. */ - - for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { - for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { - /* Initialize the mutex attribute. */ - assert (pthread_mutexattr_init (&mattr) == 0); - assert (pthread_mutexattr_setprotocol (&mattr, - protocols[mproto]) == 0); - - /* - * Ensure that the first mutex type is a POSIX - * compliant mutex. - */ - if (mkind != M_POSIX) { - assert (pthread_mutexattr_settype (&mattr, - mutex_types[mkind]) == 0); - } - - /* Create the mutex. */ - assert (pthread_mutex_init (&mutex, &mattr) == 0); - - log (" Protocol %s, Type %s\n", - protocol_strs[mproto], mutextype_strs[mkind]); - - log (" Destruction of unused mutex - "); - assert (pthread_mutex_init (&mutex, &mattr) == 0); - ret = pthread_mutex_destroy (&mutex); - check_result (/* expected */ 0, ret); - - log (" Destruction of mutex locked by self - "); - assert (pthread_mutex_init (&mutex, &mattr) == 0); - assert (pthread_mutex_lock (&mutex) == 0); - ret = pthread_mutex_destroy (&mutex); - check_result (/* expected */ EBUSY, ret); - assert (pthread_mutex_unlock (&mutex) == 0); - assert (pthread_mutex_destroy (&mutex) == 0); - - log (" Destruction of mutex locked by another " - "thread - "); - assert (pthread_mutex_init (&mutex, &mattr) == 0); - send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex); - sleep (1); - ret = pthread_mutex_destroy (&mutex); - check_result (/* expected */ EBUSY, ret); - send_cmd (0, CMD_RELEASE_ALL); - sleep (1); - assert (pthread_mutex_destroy (&mutex) == 0); - - log (" Destruction of mutex while being used in " - "cond_wait - "); - assert (pthread_mutex_init (&mutex, &mattr) == 0); - assert (pthread_condattr_init (&cattr) == 0); - assert (pthread_cond_init (&cv, &cattr) == 0); - send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv); - sleep (1); - ret = pthread_mutex_destroy (&mutex); - check_result (/* expected */ EBUSY, ret); - pthread_cond_signal (&cv); - sleep (1); - assert (pthread_mutex_destroy (&mutex) == 0); - } - } -} - - -static void -mutex_lock_test (void) -{ - pthread_mutexattr_t mattr; - pthread_mutex_t mutex; - pthread_attr_t pattr; - int mproto, ret; - mutex_kind_t mkind; - thread_state_t state; - - /* - * Lock a mutex. - * - * pthread_lock not tested for: - */ - log ("Testing pthread_mutex_lock\n"); - log ("--------------------------\n"); - - assert (pthread_attr_init (&pattr) == 0); - assert (pthread_attr_setdetachstate (&pattr, - PTHREAD_CREATE_DETACHED) == 0); - state.flags = 0; /* No flags yet. */ - - for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { - for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { - /* Initialize the mutex attribute. */ - assert (pthread_mutexattr_init (&mattr) == 0); - assert (pthread_mutexattr_setprotocol (&mattr, - protocols[mproto]) == 0); - - /* - * Ensure that the first mutex type is a POSIX - * compliant mutex. - */ - if (mkind != M_POSIX) { - assert (pthread_mutexattr_settype (&mattr, - mutex_types[mkind]) == 0); - } - - /* Create the mutex. */ - assert (pthread_mutex_init (&mutex, &mattr) == 0); - - log (" Protocol %s, Type %s\n", - protocol_strs[mproto], mutextype_strs[mkind]); - - log (" Lock on unlocked mutex - "); - ret = pthread_mutex_lock (&mutex); - check_result (/* expected */ 0, ret); - pthread_mutex_unlock (&mutex); - - log (" Lock on invalid mutex - "); - ret = pthread_mutex_lock (NULL); - check_result (/* expected */ EINVAL, ret); - - log (" Lock on mutex held by self - "); - assert (pthread_create (&state.tid, &pattr, lock_twice, - (void *) &state) == 0); - /* Let the thread start. */ - sleep (1); - state.cmd.mutex = &mutex; - state.ret = 0xdeadbeef; - assert (pthread_mutex_lock (&cond_mutex) == 0); - assert (pthread_cond_signal (&cond_var) == 0); - assert (pthread_mutex_unlock (&cond_mutex) == 0); - /* Let the thread receive and process the command. */ - sleep (1); - - switch (mkind) { - case M_POSIX: - check_result (/* expected */ EDEADLK, - state.ret); - break; - case M_SS2_DEFAULT: - check_result (/* expected */ EDEADLK, - state.ret); - break; - case M_SS2_ERRORCHECK: - check_result (/* expected */ EDEADLK, - state.ret); - break; - case M_SS2_NORMAL: - check_result (/* expected */ 0xdeadbeef, - state.ret); - break; - case M_SS2_RECURSIVE: - check_result (/* expected */ 0, state.ret); - break; - } - pthread_mutex_destroy (&mutex); - pthread_mutexattr_destroy (&mattr); - } - } -} - - -static void -mutex_unlock_test (void) -{ - const int test_thread_id = 0; /* ID of test thread */ - pthread_mutexattr_t mattr; - pthread_mutex_t mutex; - int mproto, ret; - mutex_kind_t mkind; - - /* - * Unlock a mutex. - * - * pthread_unlock not tested for: - */ - log ("Testing pthread_mutex_unlock\n"); - log ("----------------------------\n"); - - for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { - for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { - /* Initialize the mutex attribute. */ - assert (pthread_mutexattr_init (&mattr) == 0); - assert (pthread_mutexattr_setprotocol (&mattr, - protocols[mproto]) == 0); - - /* - * Ensure that the first mutex type is a POSIX - * compliant mutex. - */ - if (mkind != M_POSIX) { - assert (pthread_mutexattr_settype (&mattr, - mutex_types[mkind]) == 0); - } - - /* Create the mutex. */ - assert (pthread_mutex_init (&mutex, &mattr) == 0); - - log (" Protocol %s, Type %s\n", - protocol_strs[mproto], mutextype_strs[mkind]); - - log (" Unlock on mutex held by self - "); - assert (pthread_mutex_lock (&mutex) == 0); - ret = pthread_mutex_unlock (&mutex); - check_result (/* expected */ 0, ret); - - log (" Unlock on invalid mutex - "); - ret = pthread_mutex_unlock (NULL); - check_result (/* expected */ EINVAL, ret); - - log (" Unlock on mutex locked by another thread - "); - send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex); - sleep (1); - ret = pthread_mutex_unlock (&mutex); - switch (mkind) { - case M_POSIX: - check_result (/* expected */ EPERM, ret); - break; - case M_SS2_DEFAULT: - check_result (/* expected */ EPERM, ret); - break; - case M_SS2_ERRORCHECK: - check_result (/* expected */ EPERM, ret); - break; - case M_SS2_NORMAL: - check_result (/* expected */ EPERM, ret); - break; - case M_SS2_RECURSIVE: - check_result (/* expected */ EPERM, ret); - break; - } - if (ret == 0) { - /* - * If for some reason we were able to unlock - * the mutex, relock it so that the test - * thread has no problems releasing the mutex. - */ - pthread_mutex_lock (&mutex); - } - send_cmd (test_thread_id, CMD_RELEASE_ALL); - sleep (1); - - pthread_mutex_destroy (&mutex); - pthread_mutexattr_destroy (&mattr); - } - } -} - - -static void -queueing_order_test (void) -{ - int i; - - log ("Testing queueing order\n"); - log ("----------------------\n"); - assert (pthread_mutex_lock (&waiter_mutex) == 0); - /* - * Tell the threads to report when they take the waiters mutex. - */ - assert (pthread_mutex_lock (&cond_mutex) == 0); - for (i = 0; i < NUM_THREADS; i++) { - states[i].flags = FLAGS_REPORT_WAITMUTEX; - assert (pthread_cond_signal (&states[i].cond_var) == 0); - } - assert (pthread_mutex_unlock (&cond_mutex) == 0); - - /* Signal the threads to continue. */ - sleep (1); - - /* Use the global condition variable next time. */ - use_global_condvar = 1; - - /* Release the waiting threads and allow them to run again. */ - assert (pthread_mutex_unlock (&waiter_mutex) == 0); - sleep (1); - - log (" Queueing order on a mutex - "); - check_run_order ("9,8,7,6,5,4,3,2,1,0"); - for (i = 0; i < NUM_THREADS; i = i + 1) { - /* Tell the threads to report when they've been signaled. */ - states[i].flags = FLAGS_REPORT_WAITCONDVAR; - } - - /* - * Prevent the threads from continuing their loop after we - * signal them. - */ - assert (pthread_mutex_lock (&waiter_mutex) == 0); - - - log (" Queueing order on a condition variable - "); - /* - * Signal one thread to run and see that the highest priority - * thread executes. - */ - assert (pthread_mutex_lock (&cond_mutex) == 0); - assert (pthread_cond_signal (&cond_var) == 0); - assert (pthread_mutex_unlock (&cond_mutex) == 0); - sleep (1); - if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX) - log_error ("highest priority thread does not run.\n"); - - /* Signal the remaining threads. */ - assert (pthread_mutex_lock (&cond_mutex) == 0); - assert (pthread_cond_broadcast (&cond_var) == 0); - assert (pthread_mutex_unlock (&cond_mutex) == 0); - sleep (1); - - check_run_order ("9,8,7,6,5,4,3,2,1,0"); - for (i = 0; i < NUM_THREADS; i = i + 1) { - /* Tell the threads not to report anything. */ - states[i].flags = 0; - } - - /* Use the thread unique condition variable next time. */ - use_global_condvar = 0; - - /* Allow the threads to continue their loop. */ - assert (pthread_mutex_unlock (&waiter_mutex) == 0); - sleep (1); -} - - -static void -mutex_prioceiling_test (void) -{ - const int test_thread_id = 0; /* ID of test thread */ - pthread_mutexattr_t mattr; - struct sched_param param; - pthread_mutex_t m[3]; - mutex_kind_t mkind; - int i, ret, policy, my_prio, old_ceiling; - - log ("Testing priority ceilings\n"); - log ("-------------------------\n"); - for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { - - log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n", - mutextype_strs[mkind]); - - /* - * Initialize and create a mutex. - */ - assert (pthread_mutexattr_init (&mattr) == 0); - - /* Get this threads current priority. */ - assert (pthread_getschedparam (pthread_self(), &policy, - ¶m) == 0); - my_prio = param.sched_priority; /* save for later use */ - log_trace ("Current scheduling policy %d, priority %d\n", - policy, my_prio); - - /* - * Initialize and create 3 priority protection mutexes with - * default (max priority) ceilings. - */ - assert (pthread_mutexattr_setprotocol(&mattr, - PTHREAD_PRIO_PROTECT) == 0); - - /* - * Ensure that the first mutex type is a POSIX - * compliant mutex. - */ - if (mkind != M_POSIX) { - assert (pthread_mutexattr_settype (&mattr, - mutex_types[mkind]) == 0); - } - - for (i = 0; i < 3; i++) - assert (pthread_mutex_init (&m[i], &mattr) == 0); - - /* - * Set the ceiling priorities for the 3 priority protection - * mutexes to, 5 less than, equal to, and 5 greater than, - * this threads current priority. - */ - for (i = 0; i < 3; i++) - assert (pthread_mutex_setprioceiling (&m[i], - my_prio - 5 + 5*i, &old_ceiling) == 0); - - /* - * Check that if we attempt to take a mutex whose priority - * ceiling is lower than our priority, we get an error. - */ - log (" Lock with ceiling priority < thread priority - "); - ret = pthread_mutex_lock (&m[0]); - check_result (/* expected */ EINVAL, ret); - if (ret == 0) - pthread_mutex_unlock (&m[0]); - - /* - * Check that we can take a mutex whose priority ceiling - * is equal to our priority. - */ - log (" Lock with ceiling priority = thread priority - "); - ret = pthread_mutex_lock (&m[1]); - check_result (/* expected */ 0, ret); - if (ret == 0) - pthread_mutex_unlock (&m[1]); - - /* - * Check that we can take a mutex whose priority ceiling - * is higher than our priority. - */ - log (" Lock with ceiling priority > thread priority - "); - ret = pthread_mutex_lock (&m[2]); - check_result (/* expected */ 0, ret); - if (ret == 0) - pthread_mutex_unlock (&m[2]); - - /* - * Have the test thread go into a busy loop for 5 seconds - * and see that it doesn't block this thread (since the - * priority ceiling of mutex 0 and the priority of the test - * thread are both less than the priority of this thread). - */ - log (" Preemption with ceiling priority < thread " - "priority - "); - /* Have the test thread take mutex 0. */ - send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]); - sleep (1); - - log_trace ("Sending busy command.\n"); - send_cmd (test_thread_id, CMD_BUSY_LOOP); - log_trace ("Busy sent, yielding\n"); - pthread_yield (); - log_trace ("Returned from yield.\n"); - if (states[test_thread_id].flags & - (FLAGS_IS_BUSY | FLAGS_WAS_BUSY)) - log_error ("test thread inproperly preempted us.\n"); - else { - /* Let the thread finish its busy loop. */ - sleep (6); - if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) - log_error ("test thread never finished.\n"); - else - log_pass (); - } - states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; - - /* Have the test thread release mutex 0. */ - send_cmd (test_thread_id, CMD_RELEASE_ALL); - sleep (1); - - /* - * Have the test thread go into a busy loop for 5 seconds - * and see that it preempts this thread (since the priority - * ceiling of mutex 1 is the same as the priority of this - * thread). The test thread should not run to completion - * as its time quantum should expire before the 5 seconds - * are up. - */ - log (" Preemption with ceiling priority = thread " - "priority - "); - - /* Have the test thread take mutex 1. */ - send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]); - sleep (1); - - log_trace ("Sending busy\n"); - send_cmd (test_thread_id, CMD_BUSY_LOOP); - log_trace ("Busy sent, yielding\n"); - pthread_yield (); - log_trace ("Returned from yield.\n"); - if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0) - log_error ("test thread did not switch in on yield.\n"); - else if (states[test_thread_id].flags & FLAGS_WAS_BUSY) - log_error ("test thread ran to completion.\n"); - else { - /* Let the thread finish its busy loop. */ - sleep (6); - if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) - log_error ("test thread never finished.\n"); - else - log_pass (); - } - states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; - - /* Have the test thread release mutex 1. */ - send_cmd (test_thread_id, CMD_RELEASE_ALL); - sleep (1); - - /* - * Set the scheduling policy of the test thread to SCHED_FIFO - * and have it go into a busy loop for 5 seconds. This - * thread is SCHED_RR, and since the priority ceiling of - * mutex 1 is the same as the priority of this thread, the - * test thread should run to completion once it is switched - * in. - */ - log (" SCHED_FIFO scheduling and ceiling priority = " - "thread priority - "); - param.sched_priority = states[test_thread_id].priority; - assert (pthread_setschedparam (states[test_thread_id].tid, - SCHED_FIFO, ¶m) == 0); - - /* Have the test thread take mutex 1. */ - send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]); - sleep (1); - - log_trace ("Sending busy\n"); - send_cmd (test_thread_id, CMD_BUSY_LOOP); - log_trace ("Busy sent, yielding\n"); - pthread_yield (); - log_trace ("Returned from yield.\n"); - if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) { - log_error ("test thread did not run to completion.\n"); - /* Let the thread finish it's busy loop. */ - sleep (6); - } - else - log_pass (); - states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; - - /* Restore the test thread scheduling parameters. */ - param.sched_priority = states[test_thread_id].priority; - assert (pthread_setschedparam (states[test_thread_id].tid, - SCHED_RR, ¶m) == 0); - - /* Have the test thread release mutex 1. */ - send_cmd (test_thread_id, CMD_RELEASE_ALL); - sleep (1); - - /* - * Have the test thread go into a busy loop for 5 seconds - * and see that it preempts this thread (since the priority - * ceiling of mutex 2 is the greater than the priority of - * this thread). The test thread should run to completion - * and block this thread because its active priority is - * higher. - */ - log (" SCHED_FIFO scheduling and ceiling priority > " - "thread priority - "); - /* Have the test thread take mutex 2. */ - send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]); - sleep (1); - - log_trace ("Sending busy\n"); - send_cmd (test_thread_id, CMD_BUSY_LOOP); - log_trace ("Busy sent, yielding\n"); - pthread_yield (); - log_trace ("Returned from yield.\n"); - if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) { - log_error ("test thread did not run to completion.\n"); - /* Let the thread finish it's busy loop. */ - sleep (6); - } - else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) - log_error ("test thread never finished.\n"); - else - log_pass (); - states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; - - /* Have the test thread release mutex 2. */ - send_cmd (test_thread_id, CMD_RELEASE_ALL); - sleep (1); - - /* Destroy the mutexes. */ - for (i = 0; i < 3; i++) - assert (pthread_mutex_destroy (&m[i]) == 0); - } -} - - -static void -mutex_prioinherit_test (void) -{ - pthread_mutexattr_t mattr; - struct sched_param param; - pthread_mutex_t m[3]; - mutex_kind_t mkind; - int i, policy, my_prio; - - /* Get this threads current priority. */ - assert (pthread_getschedparam (pthread_self(), &policy, - ¶m) == 0); - my_prio = param.sched_priority; /* save for later use */ - log_trace ("Current scheduling policy %d, priority %d\n", - policy, my_prio); - - log ("Testing priority inheritence\n"); - log ("----------------------------\n"); - for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { - - log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n", - mutextype_strs[mkind]); - - /* - * Initialize and create a mutex. - */ - assert (pthread_mutexattr_init (&mattr) == 0); - - /* - * Initialize and create 3 priority inheritence mutexes with - * default (max priority) ceilings. - */ - assert (pthread_mutexattr_setprotocol(&mattr, - PTHREAD_PRIO_INHERIT) == 0); - - /* - * Ensure that the first mutex type is a POSIX - * compliant mutex. - */ - if (mkind != M_POSIX) { - assert (pthread_mutexattr_settype (&mattr, - mutex_types[mkind]) == 0); - } - - for (i = 0; i < 3; i++) - assert (pthread_mutex_init (&m[i], &mattr) == 0); - - /* - * Test setup: - * Thread 4 - take mutex 0, 1 - * Thread 2 - enter protected busy loop with mutex 0 - * Thread 3 - enter protected busy loop with mutex 1 - * Thread 4 - enter protected busy loop with mutex 2 - * Thread 5 - enter busy loop - * Thread 6 - enter protected busy loop with mutex 0 - * Thread 4 - releases mutexes 1 and 0. - * - * Expected results: - * Threads complete in order 4, 6, 5, 3, 2 - */ - log (" Simple inheritence test - "); - - /* - * Command thread 4 to take mutexes 0 and 1. - */ - send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]); - sleep (1); /* Allow command to be received. */ - send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]); - sleep (1); - - /* - * Tell the threads to report themselves when they are - * at the bottom of their loop (waiting on wait_mutex). - */ - for (i = 0; i < NUM_THREADS; i++) - states[i].flags |= FLAGS_REPORT_WAITMUTEX; - - /* - * Command thread 2 to take mutex 0 and thread 3 to take - * mutex 1, both via a protected operation command. Since - * thread 4 owns mutexes 0 and 1, both threads 2 and 3 - * will block until the mutexes are released by thread 4. - */ - log_trace ("Commanding protected operation to thread 2.\n"); - send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]); - log_trace ("Commanding protected operation to thread 3.\n"); - send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]); - sleep (1); - - /* - * Command thread 4 to take mutex 2 via a protected operation - * and thread 5 to enter a busy loop for 5 seconds. Since - * thread 5 has higher priority than thread 4, thread 5 will - * enter the busy loop before thread 4 is activated. - */ - log_trace ("Commanding protected operation to thread 4.\n"); - send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]); - log_trace ("Commanding busy loop to thread 5.\n"); - send_cmd (5, CMD_BUSY_LOOP); - sleep (1); - if ((states[5].flags & FLAGS_IS_BUSY) == 0) - log_error ("thread 5 is not running.\n"); - log_trace ("Commanding protected operation thread 6.\n"); - send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]); - sleep (1); - if ((states[4].flags & FLAGS_WAS_BUSY) == 0) - log_error ("thread 4 failed to inherit priority.\n"); - states[4].flags = 0; - send_cmd (4, CMD_RELEASE_ALL); - sleep (5); - check_run_order ("4,6,5,3,2"); - - /* - * Clear the flags. - */ - for (i = 0; i < NUM_THREADS; i++) - states[i].flags = 0; - - /* - * Test setup: - * Thread 2 - enter busy loop (SCHED_FIFO) - * Thread 4 - take mutex 0 - * Thread 4 - priority change to same priority as thread 2 - * Thread 4 - release mutex 0 - * - * Expected results: - * Since thread 4 owns a priority mutex, it should be - * placed at the front of the run queue (for its new - * priority slot) when its priority is lowered to the - * same priority as thread 2. If thread 4 did not own - * a priority mutex, then it would have been added to - * the end of the run queue and thread 2 would have - * executed until it blocked (because it's scheduling - * policy is SCHED_FIFO). - * - */ - log (" Inheritence test with change of priority - "); - - /* - * Change threads 2 and 4 scheduling policies to be - * SCHED_FIFO. - */ - param.sched_priority = states[2].priority; - assert (pthread_setschedparam (states[2].tid, SCHED_FIFO, - ¶m) == 0); - param.sched_priority = states[4].priority; - assert (pthread_setschedparam (states[4].tid, SCHED_FIFO, - ¶m) == 0); - - /* - * Command thread 4 to take mutex 0. - */ - send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]); - sleep (1); - - /* - * Command thread 2 to enter busy loop. - */ - send_cmd (2, CMD_BUSY_LOOP); - sleep (1); /* Allow command to be received. */ - - /* - * Command thread 4 to enter busy loop. - */ - send_cmd (4, CMD_BUSY_LOOP); - sleep (1); /* Allow command to be received. */ - - /* Have threads 2 and 4 report themselves. */ - states[2].flags = FLAGS_REPORT_WAITMUTEX; - states[4].flags = FLAGS_REPORT_WAITMUTEX; - - /* Change the priority of thread 4. */ - param.sched_priority = states[2].priority; - assert (pthread_setschedparam (states[4].tid, SCHED_FIFO, - ¶m) == 0); - sleep (5); - check_run_order ("4,2"); - - /* Clear the flags */ - states[2].flags = 0; - states[4].flags = 0; - - /* Reset the policies. */ - param.sched_priority = states[2].priority; - assert (pthread_setschedparam (states[2].tid, SCHED_RR, - ¶m) == 0); - param.sched_priority = states[4].priority; - assert (pthread_setschedparam (states[4].tid, SCHED_RR, - ¶m) == 0); - - send_cmd (4, CMD_RELEASE_MUTEX); - sleep (1); - - /* Destroy the mutexes. */ - for (i = 0; i < 3; i++) - assert (pthread_mutex_destroy (&m[i]) == 0); - } -} - - -int main (int argc, char *argv[]) -{ - pthread_mutexattr_t mattr; - pthread_condattr_t cattr; - pthread_attr_t pattr; - int i, policy, main_prio; - void * exit_status; - sigset_t mask; - struct sigaction act; - struct sched_param param; - - assert (pthread_getschedparam (pthread_self (), &policy, ¶m) == 0); - main_prio = param.sched_priority; - - /* Setupt our signal mask. */ - sigfillset (&mask); - sigdelset (&mask, SIGINT); - sigprocmask (SIG_SETMASK, &mask, NULL); - - /* Install a signal handler for SIGINT */ - sigemptyset (&act.sa_mask); - sigaddset (&act.sa_mask, SIGINT); - act.sa_handler = sighandler; - act.sa_flags = SA_RESTART; - sigaction (SIGINT, &act, NULL); - - /* - * Initialize the thread attribute. - */ - assert (pthread_attr_init (&pattr) == 0); - assert (pthread_attr_setdetachstate (&pattr, - PTHREAD_CREATE_JOINABLE) == 0); - - /* - * Initialize and create the waiter and condvar mutexes. - */ - assert (pthread_mutexattr_init (&mattr) == 0); - assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0); - assert (pthread_mutex_init (&cond_mutex, &mattr) == 0); - - /* - * Initialize and create a condition variable. - */ - assert (pthread_condattr_init (&cattr) == 0); - assert (pthread_cond_init (&cond_var, &cattr) == 0); - - /* Create a pipe to catch the results of thread wakeups. */ - assert (pipe (pipefd) == 0); - -#ifdef DEBUG - assert (pthread_switch_add_np (kern_switch) == 0); -#endif - - /* - * Create the waiting threads. - */ - for (i = 0; i < NUM_THREADS; i++) { - assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0); - states[i].id = (u_int8_t) i; /* NUM_THREADS must be <= 256 */ - states[i].status = 0; - states[i].cmd.cmd_id = CMD_NONE; - states[i].flags = 0; /* No flags yet. */ - assert (pthread_create (&states[i].tid, &pattr, waiter, - (void *) &states[i]) == 0); - param.sched_priority = main_prio - 10 + i; - states[i].priority = param.sched_priority; - assert (pthread_setschedparam (states[i].tid, SCHED_OTHER, - ¶m) == 0); -#if defined(__FreeBSD__) - { - char buf[30]; - - snprintf (buf, sizeof(buf), "waiter_%d", i); - pthread_set_name_np (states[i].tid, buf); - } -#endif - } - - /* Allow the threads to start. */ - sleep (1); - log_trace ("Done creating threads.\n"); - - log ("\n"); - mutex_init_test (); - log ("\n"); - mutex_destroy_test (); - log ("\n"); - mutex_lock_test (); - log ("\n"); - mutex_unlock_test (); - log ("\n"); - queueing_order_test (); - log ("\n"); - mutex_prioinherit_test (); - log ("\n"); - mutex_prioceiling_test (); - log ("\n"); - - log ("Total tests %d, passed %d, failed %d\n", - total, pass_count, error_count); - - /* Set the done flag and signal the threads to exit. */ - log_trace ("Setting done flag.\n"); - done = 1; - - /* - * Wait for the threads to finish. - */ - log_trace ("Trying to join threads.\n"); - for (i = 0; i < NUM_THREADS; i++) { - send_cmd (i, CMD_NONE); - assert (pthread_join (states[i].tid, &exit_status) == 0); - } - - /* Clean up after ourselves. */ - close (pipefd[0]); - close (pipefd[1]); - - if (error_count != 0) - exit (EX_OSERR); /* any better ideas??? */ - else - exit (EX_OK); -} diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c index 93b8b8358494..c54dbda2fd90 100644 --- a/lib/libc_r/uthread/uthread_exit.c +++ b/lib/libc_r/uthread/uthread_exit.c @@ -164,12 +164,18 @@ pthread_exit(void *status) if (pthread_cond_signal(&_gc_cond) != 0) PANIC("Cannot signal gc cond"); + /* + * Mark the thread as dead so it will not return if it + * gets context switched out when the mutex is unlocked. + */ + PTHREAD_SET_STATE(_thread_run, PS_DEAD); + /* Unlock the garbage collector mutex: */ if (pthread_mutex_unlock(&_gc_mutex) != 0) PANIC("Cannot lock gc mutex"); /* This this thread will never be re-scheduled. */ - _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__); + _thread_kern_sched(NULL); /* This point should not be reached. */ PANIC("Dead thread has resumed"); diff --git a/lib/libc_r/uthread/uthread_priority_queue.c b/lib/libc_r/uthread/uthread_priority_queue.c index cc2b6e670a98..516a1e0a37b2 100644 --- a/lib/libc_r/uthread/uthread_priority_queue.c +++ b/lib/libc_r/uthread/uthread_priority_queue.c @@ -29,7 +29,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_priority_queue.c,v 1.2 1999/06/20 08:28:37 jb Exp $ */ #include <stdlib.h> #include <sys/queue.h> @@ -41,51 +40,9 @@ /* Prototypes: */ static void pq_insert_prio_list(pq_queue_t *pq, int prio); -#if defined(_PTHREADS_INVARIANTS) - -static int _pq_active = 0; - -#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ) - -#define _PQ_SET_ACTIVE() _pq_active = 1 -#define _PQ_CLEAR_ACTIVE() _pq_active = 0 -#define _PQ_ASSERT_ACTIVE(msg) do { \ - if (_pq_active == 0) \ - PANIC(msg); \ -} while (0) -#define _PQ_ASSERT_INACTIVE(msg) do { \ - if (_pq_active != 0) \ - PANIC(msg); \ -} while (0) -#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \ - if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \ - PANIC(msg); \ -} while (0) -#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \ - if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \ - PANIC(msg); \ -} while (0) -#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \ - if ((thrd)->flags & _PQ_IN_SCHEDQ) \ - PANIC(msg); \ -} while (0) - -#else - -#define _PQ_SET_ACTIVE() -#define _PQ_CLEAR_ACTIVE() -#define _PQ_ASSERT_ACTIVE(msg) -#define _PQ_ASSERT_INACTIVE(msg) -#define _PQ_ASSERT_IN_WAITQ(thrd, msg) -#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) -#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) -#define _PQ_CHECK_PRIO() - -#endif - int -_pq_alloc(pq_queue_t *pq, int minprio, int maxprio) +_pq_init(pq_queue_t *pq, int minprio, int maxprio) { int i, ret = 0; int prioslots = maxprio - minprio + 1; @@ -99,26 +56,8 @@ _pq_alloc(pq_queue_t *pq, int minprio, int maxprio) ret = -1; else { - /* Remember the queue size: */ - pq->pq_size = prioslots; - - ret = _pq_init(pq); - - } - return (ret); -} - -int -_pq_init(pq_queue_t *pq) -{ - int i, ret = 0; - - if ((pq == NULL) || (pq->pq_lists == NULL)) - ret = -1; - - else { /* Initialize the queue for each priority slot: */ - for (i = 0; i < pq->pq_size; i++) { + for (i = 0; i < prioslots; i++) { TAILQ_INIT(&pq->pq_lists[i].pl_head); pq->pq_lists[i].pl_prio = i; pq->pq_lists[i].pl_queued = 0; @@ -126,7 +65,9 @@ _pq_init(pq_queue_t *pq) /* Initialize the priority queue: */ TAILQ_INIT(&pq->pq_queue); - _PQ_CLEAR_ACTIVE(); + + /* Remember the queue size: */ + pq->pq_size = prioslots; } return (ret); } @@ -136,27 +77,7 @@ _pq_remove(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; - /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_INACTIVE("_pq_remove: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue"); - - /* - * Remove this thread from priority list. Note that if - * the priority list becomes empty, it is not removed - * from the priority queue because another thread may be - * added to the priority list (resulting in a needless - * removal/insertion). Priority lists are only removed - * from the priority queue when _pq_first is called. - */ TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe); - - /* This thread is now longer in the priority queue. */ - pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; - - _PQ_CLEAR_ACTIVE(); } @@ -165,23 +86,10 @@ _pq_insert_head(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; - /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_NOT_QUEUED(pthread, - "_pq_insert_head: Already in priority queue"); - TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); - - /* Mark this thread as being in the priority queue. */ - pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; - - _PQ_CLEAR_ACTIVE(); } @@ -190,23 +98,10 @@ _pq_insert_tail(pq_queue_t *pq, pthread_t pthread) { int prio = pthread->active_priority; - /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_NOT_QUEUED(pthread, - "_pq_insert_tail: Already in priority queue"); - TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); if (pq->pq_lists[prio].pl_queued == 0) /* Insert the list into the priority queue: */ pq_insert_prio_list(pq, prio); - - /* Mark this thread as being in the priority queue. */ - pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; - - _PQ_CLEAR_ACTIVE(); } @@ -216,12 +111,6 @@ _pq_first(pq_queue_t *pq) pq_list_t *pql; pthread_t pthread = NULL; - /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_INACTIVE("_pq_first: pq_active"); - _PQ_SET_ACTIVE(); - while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) && (pthread == NULL)) { if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) { @@ -235,8 +124,6 @@ _pq_first(pq_queue_t *pq) pql->pl_queued = 0; } } - - _PQ_CLEAR_ACTIVE(); return (pthread); } @@ -247,14 +134,9 @@ pq_insert_prio_list(pq_queue_t *pq, int prio) pq_list_t *pql; /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active"); - - /* * The priority queue is in descending priority order. Start at * the beginning of the queue and find the list before which the - * new list should be inserted. + * new list should to be inserted. */ pql = TAILQ_FIRST(&pq->pq_queue); while ((pql != NULL) && (pql->pl_prio > prio)) @@ -270,66 +152,4 @@ pq_insert_prio_list(pq_queue_t *pq, int prio) pq->pq_lists[prio].pl_queued = 1; } -#if defined(_PTHREADS_INVARIANTS) -void -_waitq_insert(pthread_t pthread) -{ - pthread_t tid; - - /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue"); - - if (pthread->wakeup_time.tv_sec == -1) - TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); - else { - tid = TAILQ_FIRST(&_waitingq); - while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && - ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) || - ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) && - (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec)))) - tid = TAILQ_NEXT(tid, pqe); - if (tid == NULL) - TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); - else - TAILQ_INSERT_BEFORE(tid, pthread, pqe); - } - pthread->flags |= PTHREAD_FLAGS_IN_WAITQ; - - _PQ_CLEAR_ACTIVE(); -} - -void -_waitq_remove(pthread_t pthread) -{ - /* - * Make some assertions when debugging is enabled: - */ - _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue"); - - TAILQ_REMOVE(&_waitingq, pthread, pqe); - pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ; - - _PQ_CLEAR_ACTIVE(); -} - -void -_waitq_setactive(void) -{ - _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active"); - _PQ_SET_ACTIVE(); -} - -void -_waitq_clearactive(void) -{ - _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active"); - _PQ_CLEAR_ACTIVE(); -} -#endif #endif diff --git a/lib/libc_r/uthread/uthread_setschedparam.c b/lib/libc_r/uthread/uthread_setschedparam.c index f1ce72ec3538..93635da449cd 100644 --- a/lib/libc_r/uthread/uthread_setschedparam.c +++ b/lib/libc_r/uthread/uthread_setschedparam.c @@ -29,7 +29,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: uthread_setschedparam.c,v 1.2 1999/06/20 08:28:44 jb Exp $ */ #include <errno.h> #include <sys/param.h> @@ -51,10 +50,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param) /* Find the thread in the list of active threads: */ else if ((ret = _find_thread(pthread)) == 0) { /* - * Defer signals to protect the scheduling queues from - * access by the signal handler: + * Guard against being preempted by a scheduling + * signal: */ - _thread_kern_sig_defer(); + _thread_kern_sched_defer(); if (param->sched_priority != pthread->base_priority) { /* @@ -62,7 +61,8 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param) * queue before any adjustments are made to its * active priority: */ - if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { + if ((pthread != _thread_run) && + (pthread->state == PS_RUNNING)) { in_readyq = 1; old_prio = pthread->active_priority; PTHREAD_PRIOQ_REMOVE(pthread); @@ -103,10 +103,10 @@ pthread_setschedparam(pthread_t pthread, int policy, struct sched_param *param) pthread->attr.sched_policy = policy; /* - * Undefer and handle pending signals, yielding if - * necessary: + * Renable preemption and yield if a scheduling signal + * arrived while in the critical region: */ - _thread_kern_sig_undefer(); + _thread_kern_sched_undefer(); } return(ret); } diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c index 15b16d384d83..3887541a409e 100644 --- a/lib/libutil/login_class.c +++ b/lib/libutil/login_class.c @@ -21,7 +21,7 @@ * * High-level routines relating to use of the user capabilities database * - * $Id$ + * $Id: login_class.c,v 1.9 1998/07/28 01:30:16 ache Exp $ */ #include <stdio.h> @@ -163,7 +163,7 @@ substvar(char * var, const struct passwd * pwd, int hlen, int pch, int nlen) while (*(p += strcspn(p, "~$")) != '\0') { int l = strlen(p); - if (p > np && *(p-1) == '\\') /* Escaped: */ + if (p > var && *(p-1) == '\\') /* Escaped: */ memmove(p - 1, p, l + 1); /* Slide-out the backslash */ else if (*p == '~') { int v = pch && *(p+1) != '/'; /* Avoid double // */ |