Messages in this thread | | | Subject | PPP is slow (and so is TCP!) [with fixes] | Date | Fri, 12 Apr 1996 02:52:07 -0400 | From | Eric Schenk <> |
| |
I've spent the last couple of days giving the Linux TCP stack a hard stare, and I believe I have fixed a number of problems that have existed for quite some time. While I was at it I implemented a basic version of the fast retransmit algorithm for single dropped packets.
For those who don't care about explanations, the patches are attached at the end of this message. They should result in improved performance for TCP in a variety of situations, including the notorious slow interactive PPP connections. On FTP gets from SOLARIS machines I see close to a factor of 2 increase in performance. On puts I see a smaller increase, but this is limited by the fact that both are now running pretty close to the maximum possible speed. There's still a bit of room for improvement, but I suspect that the remaining difficulty is just that Solaris has a lousy algorithm for estimating round trip times. FTP's to prep.ai.mit.edu now run full out for me.
The attached patches should be applied over top of the pp87 patch that Linus posted to linux-kernel on April 10th. Sorry, I'd make it over 1.3.86, but I wanted to make it easier for Linus to put these patches into the distribution. If people really want a patch against 1.3.86 ask me about it.
So, on with the explanations of the patches.
First, let me address the numerous complaints that since 1.3.73 Linux PPP has been had a very bad interactive response, particularly with Solaris boxes. (I have been one of those people plagued by this problem, which was why I started looking into this stuff in the first place.)
It turns out that the slow interactive performance is caused by the correct application of the Nagle algorithm on the senders side. The problem is that the Nagle algorithm requires that the send not send the next character until it gets the ack for the previous one. Since ACKs are delayed this really slows down the arrival of the response to interactively typed characters.
There are two possible fixes: (1) Every time a character gets taken out of the receive buffer send an ACK to the other side informing them that the receive window has changed. (2) Assume that packets with the PSH flag set are part of an interactive connection, and don't delay ACKs for these packets.
Fix (1) is what the pre 1.3.73 Linux stack did. It is also what the fix posted by Linus yesterday does. The problem with this fix is that it can result in multiple ACK packets for each packet we receive. It turns out that in order to get good aggregate performance we don't want to inform the other side about changes in the window unless we have received a packet or a zero window probe from the other side. Therefore, I followed the BSD lead and implemented fix (2) in these patches.
Now, on to the real bugs. For quite some time (over a year) I have noticed that FTP gets from Solaris boxes never achieve full throughput, although if I look at the number of bytes crossing my PPP link the modem is running full bore. When we still had some SUNOS boxes around here I was always able to get 1.5-1.6 KBps across an FTP. After looking at reams of tcpdump output I think I have found and fixed the problems.
First, I found that Solaris TCP was resending packets that it has already sent. Lots of them. In fact almost every packet is getting sent at least twice.
It seems that the way we are dealing with out of sequence TCP packets was triggering a fast retransmit on the Solaris host when we didn't want it. In particular, a duplicate of a packet we had seen some time ago was being treated the same as a packet that ended either at or beyond the currently acknowledged sequence number. This was resulting in situations where we were sending three ACKs for a packet, which was resulting in the remote TCP sending extra copies of the next packet, which was resulting in our sending three ACKs for the next packet, and so on. This ends up cutting your bandwidth in half. I've fixed things by ignoring duplicate packets (those that are to the left of the last acked sequence number). Note that we still send ACKs if we get a duplicate of the last packet we saw, since otherwise a dropped ACK frame would stall the TCP. We're only ignoring really old packets with this change.
Second, after I fixed the above problem I found that delayed ACKs where not being dealt with correctly. In particular we're violating RFC1122 in a couple of places:
o It is required that an ACK packet that is delayed be delayed by no more than 0.5 seconds. The implementation can be forced to violate this easily. The problem is that every time new data arrives we reset the timeout for the ACK. An ACK can get delayed for as long as we continue to received data packets in order.
o Second, an ACK SHOULD be sent every 2 full sized segments. We used to test for this, but somewhere along the line the test got dropped. This will mess up the RTT calculations for the remote side. I restored the test.
After fixing these problems I was still seeing slow throughput, although now the link was sitting idle rather than having packet retransmits. To fix this I found that it was necessary to rewrite the implementation of receiver side silly window avoidance. The original code was following the RFC1122 suggested algorithm closely. This seems to interact badly with TCP implementations descended from BSD code, which uses a completely different algorithm for receiver side silly window avoidance. I've changed things to follow the BSD lead here as well. Strictly speaking this does not violate RFC1122, and it leads to much better performance in the tests I've been able to perform so far.
While I was mucking around under the hood and trying to get better performance, I decided I should implement a "fast retransmit" algorithm as well. It turned out to be fairly straight forward, so I've included this in the patch as well. This isn't quite full blown fast retransmit, but it still makes quite a difference.
So, without further ado, here are the patches, uuencoded and gzipped.
-- eric
--------------------------------------------------------------------------- Eric Schenk www: http://www.cs.toronto.edu/~schenk Department of Computer Science email: schenk@cs.toronto.edu University of Toronto
begin 644 tcp_patch.1.3.p87.gz M'XL("&7Q;3$``W1C<%]P871C:"XQ+C,N<#@W`*1;>U?;2);_VWR*2N^98.,' M?@#AT:2;)-#-3$)R@&SZS.P<']DJVUK+DD<EX3#3V<^^OWMOE20_"-#-2<"6 MZI9NW?=+?C`:J6:FFHD*@RC[NAOI=#>8W^WMIL-Y:R@76[,@TBMWMIK-YD:0 MRD42J+-YHCI=U>X<[Q_BG^H<'1ULU>OUA_=;!>L=M]L"]O//JMDY/&P<J#K] MZ1ZIGW_>4FJG4OFD_216U_&_,ETYKKS1::H3=?OVDUH$D1\OU,2+?#QPW%"^ M#KU[[2MO.&T)[%]CG8S5M<X``^"K6,UB/Q@%0R\-XDC%(Q7&PRE`!MEHI!.C M@D@`\0.$^W[<3W2:>)&9!6FUME6G>^=),%0WPXF.IMCSPC.I*A:9UJ9%[^)H M.U5&1T`N4F=O_Z9&<:(\Y6?SD)#10$7@\(,5<>BK.8ZATY;ZE.@[':7&7E`F MC9.9R5>/DGBF1LM(J)D>@BR!F3ET\'-]\;;3Z7958%04IVH8:B]1($(ZP97` MF$PW\K6#+,5UK6B7L2:0N4ZP<:K]C>>["+Z"B.X)=T$<,H'-<;YCDT\]RX`G M/7V@<V[-XD3C85Z4KU6JW=H'M89QY)N&(!+[6BT\H[PPC,'X<6FQEPP"G#RY MERVQQH"MT1A_2ZLBO5"^EWJ\BTD3[4$^QV!X:P5'NB\HTGWP+%5@`';OJE$6 MAJ4M3?!OX&_T>$;\V4085;D)PO`>,CJ<JC06":"'),%XDBIOX=WG^RT`HC[= M_*I&H4?/!>MOB37>71SXQ4D,S@^L(=#>,`WN-'$&PC3SHJ%6WM@+(I/FBV\^ MOC^[OKQ1D]A`@*K0%#6/C0D&P"D&71-3V\C/M\QW'R(UU'A&@J."_H;/(FI7 M2"NA)P\/QW$2I),9G?3-S3M0^3[4Q4)WVY[+C[-!J`W8F\39>#+/"K3M,=3, M&TY@1(Q*LB@B;MQ`L)+`-$JZ0@S0,T//3+3)PA3$46,=@3X%KX+9/(GO-/&) M+0/]5[>Q@MP>B\*S&L^]=)*+&]!<Q*0=T=@HD$JKIAH%7_F^-3U#+QQF(NIB MP+K=+ENP[MY^XY`M6"48J6K53)NO34IZ?GI*MJO_]OW'F_.:^OUWM7[O]O+# M>?_+V>5MK0;X"M0Z2Z*3+;55Y\UHO:\'V1CF"$*HU#R!.$RK/UQKSX?T3G4V M_Y_HAQH@V(:1S/4A?P"D:]^PD>!Z]*KQ"KCV&&?"=4L1'I"#(()!U8HXJV@+ M[:5],QU4H3;9$!8(-E/MF&E#N0O3/AE0T!2K@/1_MIH50A-/[0_P*XS']3KA M@]LX[%2=8B%][].V_8P>1_@-&NHEP5FQZ\/D9YH/,ATE6@L.M.KB^OR\?WU^ M]@XW^3"][D%COT.GV6\W.ATA/1U5579W@`U8?''YVX?S8_E\EHK9F\<@G5I` MM"=Q%OJYA29U!:V)U7`7\`P:`BZ@0522@(8B`:3OWBS.L!4\BH&=9I,Y",9C MJ`Z;-@8EYGZYO'KW\4O_W>7%18OXMZ.^:)49Z!H$V(^=>V!YPY50BR%F9;5: MJ-E<I@(-W"=@>^(%O$>.64N=?X5E"-@T.;O`6NF42N!Q\`5O1[#WA,'5QUOZ M0_1IP77.XCO2/-J9#1?KF`4&+3QEL@'$)DH#+URR1:)S5N6P>G>K"3(D3)Y3 M$J&^?!:Y;$*VRZ+=K%2<7+-$"%5/U5_"#,+=4'*!`2V#K;6$80=%#'0S<Q29 MP?JI-&%[TU)8!P7/DH0L.P08FC>^EQT"-B,&F(=,"KB!"3N)48D))"+T@"2. M9[E-!SMX!SA5/*O'GL(Z;'BP@69L1%`@6NRS4QAEXA86>ED:-V6#&2F@1W8V MF_MD%,HL59>KB/BQ-A1:$)Y3V8$E`GYAE@TG5AA#/4J!19;F-QEYCD%2BW.' M';%L,8Q!`8V'VY"#1%@%]BF&-O'C!OUA[$M*8\DXFVD_`/+A/7#^2,@N`CJK M!5AXV"N;$_$*/T_"-/2,Q8!."8HED#</]TP\TXQ?BV^+*#F^7Z;;1F61!#3P MHDP<[$T4)]F9I9G"2?FC$5,N4G!OE1M14.@D8)7`$(F8UI`8>,[NFQDX9%5; MF#J&>?(IFOIP<R,[58F+%!Y8#.BQ-6(A0\2()^@9>IN"#1`\BO208]*!3A<: MD0!1578B$V,MHM@;0Y))E#$4OHF/FA9*O`W3,8Y9:>/2-HRTDTD@<A$G5CM( M1]7E]@P4<ZK.`0N,6:+];.@N@GJR%=%+0D<MW"?#U""\:!=X\I1`W*G+/",' M9G7YM;@R2](F$VIPGVK33X9WJNX(5R-;0`X%_%8W)?LL(51$>D&;2\!.XM(7 M'^CLRC?\UR$+EML&1R<#E1;J*UN:.([<;NP8/-.W4=8I!9?]%/8TJ5H?Y:)M MN<K/XO.]*('!P?\O9"S0ID[6'Q:4W;OZ46W:HZ6_S@-86#9_C*P]%*+!_M=\ M695<KT0)UY>WYPU5WEKPH$.[4R-*\OU'4?\FH8$-#H[V.AS(''7W$22P-V5F M(8"#&];_`CT(LR#"'OA:K9VX%<Q.NV0)Q*T`=RD<V;0$#SZ!9RFO&H(-IZKC M@'62X&O;??6SV>R^GTY:OC:TC@08`480]>=QDM*J1)-YP^ZQBX#\[R7#.!'$ M]^&4V-U_(#%VM]?SW+W]1]/C'/AVD@EP1W5[Q_M'Q[VC4I*\?X#0LBY_)$>& MEX:XD3![*L[29CQJ6JVB-!ETS2A\45$V&\!HD=.&-8]@Y$E+Q2#0-KOXM=6T M(2#'?@,HDX20LL6#`2`63?Q$[:23!D44"3F5J$%Z3S]V43SGG%#MX$,#!ML$ MXP@&DE,U`Q%-\NU\?1<`X1W\19#[IS'*>EVRY034L#&SVO@H!*X2L*<3"CG2 MI?B;B?]JO]$AO<#?[I[H11&@DPY5"L=4V6OU$&3$11H3QO&4O2X,)YS3%$PB M(PL.D(N3"&P(YB#TH(Q>=H'ICRG_I+0)7D;!U$8<(ZCM./2W!1K>VI!!FT8N MG(L1P(\2;T:V7,QV94!^):1@B+V(A+S(Q,F^($I3;_(PA2L"N#62W!Q^>Q*' M+@Z1S8`WI],4"I$5\4GT"`4Z0`H+S!CPTP0-Q(;.?RZ0!F*U;`3VAE2_::E_ MW.!X?_6&\8`<&U43>MU>0]VD5``Q),R[EY\4(HC,0!K"[C]Y`]GE"^6?H&%Q M*C./Q0^E28!HAD0GUP5*ULD1Y!'X&`D_X4_QN],7.IZ-T3FT)"X;7@5-PP.P M[W`*MMB@S,9*FF(9\<0"J_TQE7>6LH:4<GV$0Q\^W]RRYRDV:`A4G$=-GA"1 M@F_["*(P4XW!0)8BD_`UY(+(*TRD@(H4GE2&DZEJS:[]&)4"'2JA-5SL8Q\" MZ%&6N%@J/PV%D@^=!K$WB[C$2H672;4OP*ZD!8HM))T(."2E`XWIF1';,!.D MF13H2GD.!8Y(M=F`(28ANJQ6O4B5(CF1?5*)>_0,<O6(.Y'.$HKX-/'"$3B: M0#@B?Q'X\"0N5]F0.]=%:&X+RAK.EDPVG\<VA8-<>(/0$@O?)]Y\KA%4W)*# M(M4/TI_XYFXIG2=D?7&(I\Y247:?IT"7,UNVT1NEE+%IN:0_MT<NU3]HM\F9 M'[0/G2\';O0#R3"3+`436:!2+;>ZB,9X6\Y32@1F$9(R'%=-)3)%A@@&,^0> M(%V,/$DR1*4X\;.W8MH=TE:T(DI=:KS*\!:D.)=7BDD=\Q2;<2;MOXG^?DWH ML+]'M8'ZP4'/5CQ62@2?BY1+HDM2#'>@LAY3/<U%M>MA3_'EQ"4JA%?E4S!G M:ZST#*[0TFRWHJS3X4(0<3_U@I`DX>KS^_<40>8W)E3AL3=JPMM7[5>-3EO5 M7W4ZKFB^<BBD\)H=/R..8Y$D<@`M.84O6O+X.N91D94*U.-TLMN3<2(>#D11 M%W$RS:L<8"B>8^,3`H4_H31S^\X^Q9#G8HM&"ZW[P&:N/AV5>%9ZO@"[[)GU M5O)M*B(C6+2"-5HKX3L;H"Q[EV-6?!)CX+BV=)OOJY<OU:I<E`6#M/L_I.'@ M$GZ+\>:TR@F\A%'#S%:J8NAZ`Y%$=&_7PWH:?+^'XM*1$,UI2LFW\9GI'%$= M)E3N4!:J"#X(OB57R13Q6>KUM=#[5'TX^ZW_[C,G&#?U#INE"I>H?S]5AR=D M$/F;-#1633+O_0W_.1>Q9_ZNPMC[FRA>V9P9U"7N4KF>?2&C8,@@L^DAV23_ M'J1B:QK6T.`&J!?#GR&KB!,)\-H]MI6=]G[/&4M7Q*V^H(-*T98^O=RKU1R? M"_5\8?7VY4M"1GX`RP#=?'U)VFA#.ILL.>2O!>32YB`;N5K)C1,(R8\NNZP! M%4!1_.HLWU.@;"6X?=3H[5'9NM=K[-E34]!L&7#"]D0R%*.3M*C#;JS6U@M6 MJ'>(V6'%R;F#VE)-HTX,^?GA]"=GKRO+"6'N#T]LR>"%-THY[Z7R,:)XAQG3 MLW3/1?GY_1K7HBO+=6IA%&*9@)/&]4.<K,-@>:2_IGRG0#:/JVR0`))(E5T* M#?2;B!#G=3<2N:*Y9RP=\MH-8@<(I@6;>;Y6=P&[_9]4]9>8=&SA);XX4RZU M-RO64E4(.R8?R)!CNI@$"!FJ?`^"65T]4XUI8(G$E!9B$L`*I?E9E<H@T=[T M9./R=>(+R$/D(BA++UIG#R![R0F<C7V0_81YO8S)PU)`9FMWIQSA4NW7IPX4 M!8#.><%6B#U\OLRL`^5"4_\.&0JIJ5LD^<\?D1L+]Q3!D:5RTG71J5>>(SOU MRN/"4Z^4I&<CP`;Q$:`GR`\OW"1`%2J%K=+UXY2+UZ,X`[==7[CA0ILB&*?^ ML4!$X+0QU&)>[J%R\5"J^DA90K>\R-4XW2HHO1+L%P:64?RFR$M:@JZU^BI% M.G`&UA>C`S;7D?!?RAN53=E+I5RJX""Q;*2>093FLVC27"=)8;4>)`AY'/$B M+EE124;*2G$&]_DYR^2Z[;%U8WL'C>X^N;'#7F/?QL)4(%`NP.)1D7)+Q1W/ M!I"",?<<+%!>V%[8\(RU$=J'^!4GA]K928E1D%"3:1';F,K&6[<<XE+<*B5U M%_$6>3K7P28IMKXZ^^7]N873PTFLYDD,#9Z9EKKR9CJ\+U)T,Y&@"QL;*1G8 MS@_"GFRFG5UP99SEL@Y7__+Y`0M;=""DQU#T1)?+$Z7)A9;0:#>O>XNX@C5] MKDDA3J(ZVBB(2F9Z91%=MNMP*/MMN1/P6CH!WM=^%K&HE&"*O5?:A^OJ$L!: MIWF.O$E!N&Q>5RL_%%M*]*HJ$E]Q:X!2%.*]#5C26';EXJ&]]5K]^O?=+M<0 M\;A\/5TL'.@C9W6NN03?%N#*S$M@BB=5*OI?]]_\:MTHX[NY^[Y*)+5*)+:M M_@J1'NT^6-0$Y%NEPAGH4L1/=&3SRQ3=J7#]9YMZE`&'Z9ZK?96[,:UB_1E7 M]E(OH9R/D2AU;KC@4RPNH)Y9?BT`5^NPZI$2;`'YE%JLRLNP.9Q(VG.+LL5C MR]59]6AAMH![M$*K\N)L`?3\*NTZ:_Y`M=8]':!$5S>AL&'W7??)_K5F9V`] M3<U=9[LA"U9-1WFLAA1C3E*@15S(4:VX7%Z_T>-RIV%=%TL@CZK7+(BJUL8T MQ*+D;OZ;Y+ZEOAT-]5!WJ'=PF(_!4$HL`XBNMC#5>LXI,OO0X70;8D5FGB00 MTI5.6LK"5:GS3F+"<W#@*(D6W#`--<3<%&?1J:VZ`C+.V+&6FWUWX6G6F@ID M]]\UUG5KZ;XS&)2W9JKMFG1G9%3HH-OHT.#37N\@'WRJ%!5R&X]36=MF<JZ2 M]D2S)1-&3S!9KH"H7):[)*2V7;W13VT0J>83K?5&<6H6-4.NH%R1Y=*VP<!S M&(@'J-C$X0]/8W!WQ$K=8?N(1\D.7W57BB8OEIMUU)_+D[ARKM8D^3#W$8^\ M\;G7.WW,D@9W%A6W$&W3D%IW+!`/@FQZDH-[H@Q)S_G;(]UCF,SOMX_=@H?Z MQ^[^'VL@Y]"E#G+[X+BS=]SM%1WD5T?[7`;GO[W"1K#'\8L)$:?3].<!H5-% M$!/,"ZDCSX&4L1`[*M,0@C;*U'XQ]2B%*QM9/4F"?_V[S69V.466LC`EDMQ# MW;!#/B4EHW-8OIR.K9SH&U>PEMNZC_!=IC<>9KN]_Q#7[>TEMK6/VX?'W<>' MZC<"]X[;^\>]$L^[/%F/W]VV#`UL%=.=ZP1?[:GS+,SD?K5I3V5%;IIS6^R+ M;6?2[#1T=,Q=0;(?3B(D>;'I4$A)%A*H2+H]E!Y:+HP1@=H.(3MYZ2URW5X& MR\D9<:9B)QCMX-1>J]OJM;KDHNT@NFW_7<6IS8A*O"8D@FB8\$PPO0#@PBKN M[85AHY0)[-@$D*?74VJ+O%8=,>=I?L*DG`;BNWTX3YVVU(T$.MAD8*?J>:YP M16>8.A1&V?%*2P027=OIX(E4RI[R)N)R&S$_'C#$G;5J\_*<$5;92O`3UN95 MX[KPO5ZH".G+X^-1,K*S>N93DJP3:=A52:QJ7*W^4;5KZTH'CH69+PI`XMF: ME-5B_6Y)X=9OKJA;IW?<>[51W1X!W3ON0=DZI1&=@SWN(>"/]8;]?M;K2BG+ M%;:+B\-X'JQ?+35`R-KEFL=]H>+V,$I/V!(.\_EC"N4IFF/3[;8KMUB*J\B? M5R]ER5@N?9?X]#;/@[3GFP^0GN^M>[?>P:.4WP@)*[E7$%YZ-_AMR2ZO:5`8 M1GF93Z.]3,/.`74A9UXZ,2^83/_EZQ%-O'^XO+(3VI5N>^^P=./L-YZP>X-? M[S_^4NENU<NW7'\,UY?W(H_5O_ET]O9\9<.567![UX53C?TVA5,=UZ:V,4AZ MUTKO^HC'AG7YB$\[G3;_V'Y_DX)5EU%RQW.416(@91-3'E=GJV@','B$G//* M'#XS-,O@<L*!9V3&E0U=;%_$H<H15=+A(XQ`TN]*I\5SUOF+$I&*Z"T:3O7L M9$`D,YANPA9[5V&XU:NC7HVWZ+;(IX2!O-`THY'9.3MY'EBC%;T6C'MI$#8_ M@GONTC@O3\_S,!1`<;HP3@W/N-I![CG,*B>^+5K!\ZIV]*S?ES<B^GVUK(?B M/^FI?7GBJN_$22B:97<I42;-OIZX2P+$4P*<9Q#M"J]#8]A9ZL;&N33ISM72 MK>6U<>CW\U%:U['O2V4ICOK$:+I?)!UV\6FI30W(E7$4F<H-D?TNQ%+43BJ, M:G$6VF'3,+^JEM;`&[6[>]P/*EU]>:K^K_VU=W%QHG:I:S'53",[M.[!WX8I M%P/`)((OAHA+D\/]8>C-YJM;G^9Y3GE5H\2#VDD^D.PFPT]/R>G82)<ON"%D MK'5)FF,!')1"-EOA-INCI=3F;";[M_/KJ_Z[\S>??U$_W%Y_.29(!EN<_@4V MZ/0OF>KB%[_.P"5Q^2F0;BPW0QOKS+#CS0ZU,LG=($Y-O2Z(,:/$G0R6F!XD M?XH/;.U+=?,&NVYVOL9O^/!'H5Z1&S6!1_[^T/?UQ>@0(=N#"L-#F"L*LTG( M.*SM[37VZ+6?HPZ]_F-S><?390%1?T!`2M.<CVBC'8Q_FA9:)53/D;\_H;*Y MH*_([A-%]^:[HLM%YV?+;+UX<-DLEN:6*(A7%,4?2S#LOB*^N>?W2J6S@SL_ M\&L(&1('0Y'\/VZ^W/Q3K;V6.'.5W^*E1GG=AXIA=B3N^OSM?[>NSG^[575U MC8_0$GKE#YO"60;AL5N&6V\^7UR`UO3Q\\WYM?TH:N4TKK/;S=<VZ,V0V@^\ M@WW5A&RX!/>%WUH;8<H;582`NH\S\J4.Q&Z4TMZ*I4QH]="K7U3?LZ]0%E7Q MX@VPW*?;Z46NDDO7S;[VY1IE#VX&(TXQ`17+91.JXXXS;0QN2K>,'L?O)G&5 M.J^U<V4)VX]"(H%D3[+%)=#G5QM=U)&C$-)EC\NR]!I/_GX.GV8,'IO\)/RR MKJ.I>_NK\#8-!3,443O5ESEZYWMD`^>`F,;YQ*]3?[/T0I!`5!XVN3E.,C3K M@UB,7&E+SQ`]^/UCNM.FS)NJKIR?VH%8>6%QDLB[/SDH-2IM.$5J5\Y%.1PL M<1)/849X[F5<26;S]W'I!H=/D,H@XO8VO]T%LI!L\8AN,7+Y9WV0Q;]^^CPW M5-]@0NL;3:@=W\W?3%8P%(6=6*T5N)?9_W_@65]0F0,?`0#W(Q`[H1%&0)=N M9Y:`!YS``R%%J86EF46I\(8V;!<@HKA";(N&E&F(+CV\L,8=<F"O(A?A4#]" MSQM`3QQZ>GJX%AYK(^H&I-I%&Z/X1K$0GTIH183<XT79(@1?]@<;&$#6B[$, M3`'1"4(8`>[R:(/D]"$[NGU`BW-`Z^+!(XO@QGTB9`],/FP?(V0:+`FT/B:U 5'!3\H*EY)?BXI!(7`(.%M$PL0P`` ` end
| |