From: Michihiro NAKAJIMA Date: Tue, 29 Nov 2011 14:52:15 +0000 (-0500) Subject: Enable BCJ + LZMA1 in the 7-Zip reader. X-Git-Tag: v3.0.2~88 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4d265511053324bfaca4af86d25525b810705359;p=thirdparty%2Flibarchive.git Enable BCJ + LZMA1 in the 7-Zip reader. SVN-Revision: 3884 --- diff --git a/Makefile.am b/Makefile.am index e45103fed..dc7961e62 100644 --- a/Makefile.am +++ b/Makefile.am @@ -454,6 +454,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_fuzz.cab.uu \ libarchive/test/test_fuzz.lzh.uu \ libarchive/test/test_pax_filename_encoding.tar.uu \ + libarchive/test/test_read_format_7zip_bcj_lzma1.7z.uu \ libarchive/test/test_read_format_7zip_bcj_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_bzip2.7z.uu \ libarchive/test/test_read_format_7zip_copy.7z.uu \ diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index a7d79c7d1..d9a54ac0e 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -233,7 +233,9 @@ struct _7zip { unsigned char *uncompressed_buffer; size_t uncompressed_buffer_size; + unsigned long codec; + unsigned long codec2; #ifdef HAVE_LZMA_H lzma_stream lzstream; int lzstream_valid; @@ -261,6 +263,10 @@ struct _7zip { } ppstream; int ppmd7_valid; + uint32_t bcj_state; + size_t odd_bcj_size; + unsigned char odd_bcj[4]; + struct archive_string_conv *sconv; char format_name[64]; }; @@ -315,6 +321,7 @@ static int64_t skip_stream(struct archive_read *, size_t); static int skip_sfx(struct archive_read *, ssize_t); static int slurp_central_directory(struct archive_read *, struct _7zip *, struct _7z_header_info *); +static size_t x86_Convert(unsigned char *, size_t, uint32_t, uint32_t *); int @@ -775,6 +782,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, codec = decode_codec_id(folder->coders[0].codecId, folder->coders[0].codecIdSize); + zip->codec2 = -1; switch (zip->codec = codec) { case _7Z_COPY: @@ -803,26 +811,32 @@ init_decompression(struct archive_read *a, struct _7zip *zip, } /* - * NOTE: BCJ+LZMA2 is OK, but it seems BCJ+LZMA does not - * correctly work. With BCJ, liblzma did not return all - * bytes I expected; it was four or three bytes lost. + * NOTE: BCJ+LZMA does not correctly work with liblzma + * because that packed data made by 7-Zip does not have + * End-Of-Payload Marker(EOPM), and liblzma does not + * know the end of the stream without EOPM or the + * uncompressed size. So consequently liblzma will not + * return last three or four bytes because LZMA_FILTER_X86 + * filter does not handle input data if its data size is + * less than five bytes. And thereby we have to use our + * converting program in order to decode BCJ+LZMA. + * If we were able to tell the uncompressed size to liblzma + * when using lzma_raw_decoder(), but unfortunately there + * is no way to do that. */ if (folder->numCoders >= 2) { codec = decode_codec_id(folder->coders[1].codecId, folder->coders[1].codecIdSize); filters[fi].options = NULL; - switch (codec) { + switch (zip->codec2 = codec) { case _7Z_X86: -#if 1 - if (zip->codec == _7Z_LZMA) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "LZMA + BCJ is unsupported"); - return (ARCHIVE_FAILED); - } -#endif - filters[fi].id = LZMA_FILTER_X86; + if (zip->codec == _7Z_LZMA2) { + filters[fi].id = LZMA_FILTER_X86; + fi++; + } else + /* Use our filter. */ + zip->bcj_state = 0; break; case _7Z_DELTA: filters[fi].id = LZMA_FILTER_DELTA; @@ -830,22 +844,28 @@ init_decompression(struct archive_read *a, struct _7zip *zip, delta_opt.type = LZMA_DELTA_TYPE_BYTE; delta_opt.dist = 1; filters[fi].options = &delta_opt; + fi++; break; /* Following filters have not been tested yet. */ case _7Z_POWERPC: filters[fi].id = LZMA_FILTER_POWERPC; + fi++; break; case _7Z_IA64: filters[fi].id = LZMA_FILTER_IA64; + fi++; break; case _7Z_ARM: filters[fi].id = LZMA_FILTER_ARM; + fi++; break; case _7Z_ARMTHUMB: filters[fi].id = LZMA_FILTER_ARMTHUMB; + fi++; break; case _7Z_SPARC: filters[fi].id = LZMA_FILTER_SPARC; + fi++; break; default: archive_set_error(&a->archive, @@ -853,7 +873,6 @@ init_decompression(struct archive_read *a, struct _7zip *zip, "Unexpected codec ID: %lX", codec); return (ARCHIVE_FAILED); } - fi++; } if (zip->codec == _7Z_LZMA2) @@ -1042,10 +1061,27 @@ decompress(struct archive_read *a, struct _7zip *zip, switch (zip->codec) { #ifdef HAVE_LZMA_H case _7Z_LZMA: case _7Z_LZMA2: + { + int i; + zip->lzstream.next_in = b; zip->lzstream.avail_in = avail_in; zip->lzstream.next_out = buff; zip->lzstream.avail_out = avail_out; + + if (zip->codec == _7Z_LZMA && zip->codec2 == _7Z_X86) { + for (i = 0; zip->odd_bcj_size > 0 && + zip->lzstream.avail_out; i++) { + *zip->lzstream.next_out++ = zip->odd_bcj[i]; + zip->lzstream.avail_out--; + zip->odd_bcj_size--; + } + if (avail_in == 0 || zip->lzstream.avail_out == 0) { + *used = avail_in - zip->lzstream.avail_in; + *outbytes = avail_out - zip->lzstream.avail_out; + return (ARCHIVE_OK); + } + } r = lzma_code(&(zip->lzstream), LZMA_RUN); switch (r) { case LZMA_STREAM_END: /* Found end of stream. */ @@ -1064,7 +1100,21 @@ decompress(struct archive_read *a, struct _7zip *zip, } *used = avail_in - zip->lzstream.avail_in; *outbytes = avail_out - zip->lzstream.avail_out; + if (zip->codec == _7Z_LZMA && zip->codec2 == _7Z_X86) { + size_t l = x86_Convert(buff, *outbytes, 0, + &(zip->bcj_state)); + zip->odd_bcj_size = *outbytes - l; + if (zip->odd_bcj_size > 0 && zip->odd_bcj_size <= 4 && + avail_in) { + memcpy(zip->odd_bcj, + ((unsigned char *)buff) + l, + zip->odd_bcj_size); + *outbytes = l; + } else + zip->odd_bcj_size = 0; + } break; + } #endif #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) case _7Z_BZ2: @@ -2802,3 +2852,89 @@ skip_stream(struct archive_read *a, size_t skip_bytes) return (skip_bytes); } +/* + * Brought from LZMA SDK. + * + * Bra86.c -- Converter for x86 code (BCJ) + * 2008-10-04 : Igor Pavlov : Public domain + * + */ + +#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) + +static const unsigned char kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; +static const unsigned char kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; + +static size_t +x86_Convert(unsigned char *data, size_t size, uint32_t ip, uint32_t *state) +{ + size_t bufferPos = 0, prevPosT; + uint32_t prevMask = *state & 0x7; + if (size < 5) + return 0; + ip += 5; + prevPosT = (size_t)0 - 1; + + for (;;) { + unsigned char *p = data + bufferPos; + unsigned char *limit = data + size - 4; + + for (; p < limit; p++) + if ((*p & 0xFE) == 0xE8) + break; + bufferPos = (size_t)(p - data); + if (p >= limit) + break; + prevPosT = bufferPos - prevPosT; + if (prevPosT > 3) + prevMask = 0; + else { + prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7; + if (prevMask != 0) { + unsigned char b = + p[4 - kMaskToBitNumber[prevMask]]; + if (!kMaskToAllowedStatus[prevMask] || + Test86MSByte(b)) { + prevPosT = bufferPos; + prevMask = ((prevMask << 1) & 0x7) | 1; + bufferPos++; + continue; + } + } + } + prevPosT = bufferPos; + + if (Test86MSByte(p[4])) { + uint32_t src = ((UInt32)p[4] << 24) | + ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | + ((UInt32)p[1]); + uint32_t dest; + for (;;) { + unsigned char b; + int index; + + dest = src - (ip + (uint32_t)bufferPos); + if (prevMask == 0) + break; + index = kMaskToBitNumber[prevMask] * 8; + b = (unsigned char)(dest >> (24 - index)); + if (!Test86MSByte(b)) + break; + src = dest ^ ((1 << (32 - index)) - 1); + } + p[4] = (unsigned char)(~(((dest >> 24) & 1) - 1)); + p[3] = (unsigned char)(dest >> 16); + p[2] = (unsigned char)(dest >> 8); + p[1] = (unsigned char)dest; + bufferPos += 5; + } else { + prevMask = ((prevMask << 1) & 0x7) | 1; + bufferPos++; + } + } + prevPosT = bufferPos - prevPosT; + *state = ((prevPosT > 3) ? + 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7)); + return (bufferPos); +} + diff --git a/libarchive/test/test_fuzz.c b/libarchive/test/test_fuzz.c index f3a3d6ca9..1e25cb8fe 100644 --- a/libarchive/test/test_fuzz.c +++ b/libarchive/test/test_fuzz.c @@ -63,6 +63,7 @@ static struct { {0, "test_compat_xz_1.txz"}, /* Exercise xz decompressor. */ {0, "test_compat_zip_1.zip"}, {0, "test_read_format_7zip_bzip2.7z"}, + {0, "test_read_format_7zip_bcj_lzma1.7z"}, {0, "test_read_format_7zip_bcj_lzma2.7z"}, {0, "test_read_format_7zip_copy.7z"}, {0, "test_read_format_7zip_deflate.7z"}, diff --git a/libarchive/test/test_read_format_7zip.c b/libarchive/test/test_read_format_7zip.c index ef4496390..612170011 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -634,6 +634,7 @@ DEFINE_TEST(test_read_format_7zip) test_extract_last_file("test_read_format_7zip_copy_2.7z"); test_extract_last_file("test_read_format_7zip_lzma1_2.7z"); test_extract_all_files2("test_read_format_7zip_lzma1_lzma2.7z"); + test_bcj_lzma("test_read_format_7zip_bcj_lzma1.7z"); test_bcj_lzma("test_read_format_7zip_bcj_lzma2.7z"); test_delta_lzma("test_read_format_7zip_delta_lzma1.7z"); test_delta_lzma("test_read_format_7zip_delta_lzma2.7z"); diff --git a/libarchive/test/test_read_format_7zip_bcj_lzma1.7z.uu b/libarchive/test/test_read_format_7zip_bcj_lzma1.7z.uu new file mode 100644 index 000000000..fd6b4e067 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_bcj_lzma1.7z.uu @@ -0,0 +1,245 @@ +begin 644 test_read_format_7zip_bcj_lzma1.7z +M-WJ\KR<<``,I&RS\_RD```````!9`````````#FU5W,`/Y%%A&@[WP)!,(6+ +M]:YDCG/TF9,6Y4@I6&:W,\L.GXAK)SG^7$ASM;Y]KP;]Q:,S]93R>,&)>5<, +M&FZE"`#6^N9W.O9$'UE^T-50DI_AD]BN$0G/D?)@D^5S4+=>0I338+60+5WO +M?S\=&H#(CWK#P8A*.F39U-N85;*`7:QH4MPY]Z"R4@0-G[PN0P/I&4U*T@DV +M'"`CQ@7=GL@J7_2-A[.]&`<]D>$^(9=0(?Z*\Z.%M#RG1BD;5#6(4_PL?`47 +M!00BJ=5&HZ7@@B$C!NO::D+1C%8P).\)*UDX0P@<+::RMJNW=<@+:$ZER\IE^S3<>=HCZTG +MM[:O[2?'(:Q@840D]\]5Y73NXY[]$A&S9_<=T[^)S9E-I@,/"Z%N3%P8EQ8N +M.<>T1U:G?9*=LX1R,65>5\LCE.PG__FU`+L]UUEKFS13]3C4N`J/2*#MK;D6 +MR_YC0[KZK#6ZDVED3OA(WO_#+'G.!7!DNT&:A<:N8%2S1T,0<.CXWI?5110E +M(]/(V5U26WQEEBY"+^%%%QQ*$$LVGS;&M##OO=PE)#7IOV]4!T0>MCVFR7A^ +M)`*]D,D*8(TTY<\22+QK022#]K1P8Q>ZDOE"5%*XR1S_RD)#8:OFV8PM<:&: +MXO9&=U7J?O95W3V[0_>S$IA67];6D(/WJJ:Q>6%"L4.3$3?0E!!$%?%!2/7& +MXB4BNO1`#[FYN$MKM,TL^'./,4GY)NO_;YJ7P +M.<8Z"R!*LK]S`B1=P4X(^JK3]7X8N(%H?=H&K>KB'G7(0C'R=1Z0Z`IBTR?O +M>DKYV:WR$Q0MRO.CI2E[0;'KUGX`,?^8H_"$EOK=81Z5Z4VZQ'O;;O;-'3N/ +MM(@343API(#U5#X1=PK%4)/F?[I"DE\39HS<'P)7H49\16$$ES92A@%4O+Y4 +MAD=?Q`Q6L[^+YH+AJ-Z!]8./"Y'^Q"*$TJ#,%/ESOJCC)X:D@0R_?J)%YC&F +M):9`]N(:_,O,>0]$-QL,-?ZE@EH7Z=TEA\M7949(]"*65FN\?-CF(U?7P0?R&\DOWV5DVFK[.JXEP>WU1IL?6K&/CWJ(7%PM9 +MZI:B)8)Q$N-53QL+1O[;'7O/7/O^;3JY[WU7(!DWS`YXM'QL?+>("XZ7)FJ3 +M#T4640CH[0Q8U319C-]L^2259=A(C)[[!/*9P+!6MXIH$N)1*Z:&QIZ7]E*8 +M%(B.D'_@P=8!H(?*X?N@HB+MAKFN3F][.%W':*1!5I4=/"TFY>,\=4<$EI/) +M\S[27U*=0/;8!0P4W/=5+RC"*W]L[Z>GIXO;=$L;^CKMC. +MFK$GA0?W<=3^K@8Y^D_FAZ!W7WZ#.6HO6/_:M&X<5E:R +MAU)=J;SF.%&+0R;V*[FQB?;-D6E*-E9A9B[,4F',0KL8S]AZ3/3,AZ!6('R] +M)>:,3R!'4,\HCK1#'3_?PE4$NKGPX,R?.IK6$:/[E%8278\-K\&D4\:14"/( +MJ(V,!$2BJH@D@[TOT`^<-9#'>!Y!%G[3Q4L[4EU[56_:"*>E#X'=E='@D%RN4=E!\F6P+B>NF-E.')J;D/S +M>](@#H.CZB,"S;X1F.)O-8.%W0+\OBW-QVYBLHRW$*]^CP(Y/U\G<3B;CDT0 +M]"EG+*#EDEZI35$5+9SLPO#7YC4(/'^E+!1? +M^*3VBP3&G9$9CU2`[V+^+*?N^CKX/5VXN]BITG#,SZN85C91X7OQC*NK9_X/ +MLBT1D8WVS!OCD4C7_3>4N>6Y[.58AS6TD<_W-2HXTD?5O2$`?JW4#>E1DA(` +MHQ=#I"0OK1YBL'?/Y$@>3"0_Y+,WS'D:N2A4EH3`]F2 +MVFSKLME)Z,E9_,4[!'G+XCO\^^`Z\^_ +M!QY_7[O&*@MP8&R9/?%Q"XE@16@O\T+PU]?>]+QO%2RW(E +M^$A@,C_K8V6Q,(\<*T?3=QQ4D)]CL-8JTO%EV64)I,+2`_,\J._L2^N5B1N7 +MPJ])*IU6?/,23U8+;W*OE:A@V<`;](1`&8U>JD6(DW,D!F]^H:VF;L,-_%X> +M,)O/C?JM)C=5^AL,$UQR5IE^&Z1LE"T4OCT2A?W*V(0FZ=[^9O=[0L[DD:O6 +MTE:IM]=YK:4\#5<6Y>]VU@73]UZ689)7!_EKHD0T^P))9P%J]^#P><2"YV.% +M>U#Q<%/(S*4JZ+.0NU!_ZK^5M7!QAIZX:/Z32G6WM(_6?(8E9)/OGY..D_/. +M%.`#A_`A'J3"O.005L(]?6EP;FQH7HX1HF +MCAR1ZQM^6(:4S7GX!F9"T=U-C/O+M%,($IH< +MF+1P]=.-IA$C!(-S+&9]!:S%,;25N3YB'YX+%D?E-2=`D%!!Z27@>!`2&G1F +M-=33R'N8/38:0'UK8R-M.OE^?B@GK<]_L?9*.CSS19I'B[TRS5DPH]XZ*@=4 +M'N0J@P[$RZJX07]PA()D$BJ>JM2B14.HY/8P)=2E8[1@\';&"H3/)K\^2;9W +MJMT1I_^!-`'/V15^*=!%]QH43#I-"Y#'9@90N#0PDZ7ZG*X +M0/K*DSL[`\0HY64M4W(^[Q"I"\HMJ\:D/N7K3 +MYEO^MPZJPEH2V,*E=IMWQ8"E;5T[__9''NQO$.S;KOSY&Y?/G:5J#A\^T)?$ +M'+?-WQ$Z`'JWI3Y6^9:>JX)Q";!98%$S/HR**LS"4XW8"A%>9BDORAIC[W%M +MCJ#K];":3B4`,5HG,6OW`)L)@!N][4&Q\=V,!V`H=CUN$8->`C$7%9!.USIY +M%$TS2]-DLCFIJ/U,M32BDU!R@0)&:<1L7G:H>H#$GO#/7J>FABW=>4K(-;FM +M(PYL[]WV;8O,LY8:J2@V$53&XU`0`2]F/"[->8L@I4%MFH#ZVLDC/@T#HOKO +MQ3B_.`*!AW+0>7---V)6VLC%/Q8P(?K*&G7;RPF!6=-6/1=4MNA]7W<>H%2) +M6-5]EI]E8CK>-9?A/04EG"9L'E# +M\;IO)#E1-^C!(ZO0H&NE^W@N(3UFG?:I:3P,"#DQ41-K1@*#QE7;]W+$_3L5 +M:1$\.("#"CK--V!Q34.3GJ5-9SKJQRW^4W6SU*"-9<7U8=SX2)+KW'LG]DD> +M@FUA#W_-)WK%\.&\#-_?W.YZ6Y]/1;Q\5),6=LX8F\5?.%]X6<71?;:-^U4` +MM)T(J'EN".ZP>>ZX>;'B_*JQ3QJN?0<,D.5:AB.FA[E5-=-"@O4!(F^R\05T +M8`E-4F!NS5LV(VL-(M#[6!("]1#8;-@LE^V\4*!U:SXZ5@'PPWSI0M.I+($7 +MSJ._H<]-!AJ7>BW$J_#44W$;-7S9L/8*SBN=U[)6I$)(U6E&\8D6B7@5F\D) +M&:U?,]>Z'[6^8E&1Q91HLMEX-7SQM&/P4;ZH/\AF3]9;CL1[ZXSLI/3,Q,VT +MB6BM;E*X,404UJ]\M,L`_R!NT+M``JB>+=-*+;8++B:CLZTF%IME1)&SI`2A +M_;*=>Z[VZ)([-+/O<-8[!@QP"`(J#I3+6R9KMD;<`B&;;Z,TJ,(47QZEP5>B +MF,0.XPN@FLPW0,#7KZ"_`.7^R-JS#H@@6\3N_S-OWF=^J+!Z-'?M5*ZIA=F_ +M>\[088#:U,JEEAE6PM[PX2+CQS13SL/9X%LXF%Z@UB$T'(ZU?^`SO5Z7\0,%I[8@6GD8'03Z> +M:YJ:R>N%?0Y$_O[6LZ?BNRCA=37A,R/,$<>LH35**HTHR$&\Z]1&[TRX0#S1 +MFB"EU2??5S'ZP=^@VVD@,%Z/3C?/R&5PT(J.4;GTKD;]].XMT8G\F\QQ7:-/ +M`*V+!74(GVTBGJN/LYO[@/`Q8@X9N5DZ^;S[9'("+9I\$R&('_CI04"%BKKU +M$8;RDI/->GO2X-)JR/LL`;#\F[X/ILE)[S,7$=OI49NK*YZK_H[C;(U!AU0$ +M6+3;W"1A!/DY/X7G0J@FVI[_Z2[R?2-YS#=2.A9`\[";'@_BJ_8@ZS3*LW]: +M,0(83P2BHK#=<\)9>-J3&3V.R0MAB;Q=6Y_ON<`S-@Y6*H3UDD7B;-Q2?F:D +M--15N@/$^-]81!-&0-4@?-_7ZOP[4228AV`5VGVSOM'']2\Y?`%?^?![ +MKCTI]H[V7VAS[QX2;5XE["D^I\5[O0AN[!#6.P7H@4W:85X`7W8[ +M7=.^#]'OH0JBCP58C':P-3BIP4#OB?%4K2A;:$E8$C/CN!#!6DB.'ZX&HE5SIQ'V_<&HTDT=.P'>G[9U&,^;,3X:OO_!-[;UQ8*Y/G +MD2]*"H-R3*+B!%(L:9&<`5]0]6`KR/<2ATPN8A]/"#O*.O@;QDQ=:+&<.$@KK)K/PKZ90:#3X^\!S)474V8(Q/S0I%"A^O_ +M6M"EW9EC=(ET]FT[3E=A=OA=@T"KA@8@1@%D[B.60ONF^,$KDWGXGJ3UH-]X +MI=BWT5P*"`/+V$U.1B3$5GB_KM>W%?5S(3F=VO^R-%4K2!/M1[FX7D36Y&Y` +MU-N>@6D:>QJPZTL^/R10SZFD2NF`G*P[3]R(9JFF@KL(4&?!#`/H[O]9-9"L +M3:^?RYBI:*V1)-^@C./??0=5*_(QA_CD1M28HUI#&QI]ZEJUT/KD>I"*2]L! +M?Z4+V/`23D=D.(I+9OSG4D='N_ZD''(6034^793JDG'SP7R:CL_ZBH%@,>25 +MJ5=7-H5])9HT8(:!J;FP?90%OR_EX.&[K87] +MAY:`OJI"ICPI)&/6=._AI"AYHM8V/,87`C'O!0'$7OS +M@##S9B&,,KHM9@::[=#9;TVMYW(QO0T\@SMFFAN!=W/U?VPY41)+4CY[?_!< +MNW,W#U,GY_CN5XY>IV",=Y.8)[W]U8Y;3IBC/^N#/`M#(5#P%Q9L#[.ML0%' +M98I%"`G*I&"M`$`7.D,=)!=4]`>H8M9 +M(4I0A#O\]'3(PJ46Q)-;/K-/`5JN",&%"+Y,<-MWE#2-(%V&#>H\\.RHP.]S0-I#Y>E@%6*7Q6FY#*Q&JJ]UW@4WA+,%QE3PPE$8$AS?0O7E<./2QA"5TV%"1% +M(A'0&.[WUV%$,*3.B*:N"8VF*#AU5\Y^8P3WP#7MPTG)VPP#CY9/>N6R9>0] +M).7-KI?S&LC-D.R0!>&^ECY%Y:#?W#HK,#H:3NE5X;M(Q$^U;\%%EBMP@/MI +MS:[EF^7_SUQJ,Z1VF*;),:QLT]CG4C1\)#W\C'4SBJIEUX-)C!Y\6P +M(ZR)/5`:/6_"!UQPQD"^8):+>OG1JHV,3AV%-NN^6R<&LYDJNT3G3 +M\+,?-^B#/?U[/)WSW;&$JD0^I>"MST3DTA4,92>9$3W*HE3E=<`T^@J]\"\I_1@$8P?LYX2=&>TK(H[IDX%#;# +M/052%71UXW$ZM=B7/C./*XPJN8ZV1+&IG$`.V/A"1SL]X@]BN6$Z\L81365T +MRE8"[=YV)6H9BJD@6Y'F`5@R(N6WU+?]VP^US7$WD/&2?ZB:"W=0;ZN0D^>\ +M7`!WCK\DV`DLQ2Q/].IURR&!;Y6)0XVIZ[_3K%QH@_/$Y=U[T`A"[/A:#NNE +MY(59/4G6UVR]J1UV\>)UAD#/V*:1%61;[\F>802&'<-ICN^PP2FHR>6NZNWNAH27%QM4#+H'N] +M+1^%CG`[:[9>S=%M1$$KOK_]JL0+]6+-:]9>AY=+2U\NR4`C3@E,#WWFW1DV +MA*E'.T5\,EV+<:]-A=X!:+G!`F!(9I#4'T^GFR]6D^Q%CR)L`B!0O)0(OF>\ +M3#U@%O^#US4`_Q_@A8*Z1)7%(ZQ%J?6M-$8'\NG=)!4C`MPGVB3&2E[9$38( +M/3@US1,"70*H&87;S[!UC;\*'*>3B(?@G;I3FAPQHWIU-1Z0<22D_[R=_8I- +M;V5*Y;(S,-]<%<6I`?>M!6@.'?)8-U\$.QK9/5Z)QT[JDIIW?/5RJ9([\+W2 +MZ_3!GE7JO@]RBM/C]\_O?J.*]M2KMQB-5/.3<1`\H\RQ2O(7,09O0?X-9*[Q +M"B#HGK\B5.FYNX:5QE+7C!.:C]9,$[KPXR#I6LR2ID1EJR/,)OW%AE7[+>'N +MI%$H907$J5)49IXH#DNA! +MD--=$KY]0&N]Z'<,+_>A(YZ?YK'4`@,^:N?-3@A)

;`2,&](DA-\+6/.WM!X0,.T8[F'-?PAX# +M0L?`J#M!ALYFK*I_(_P^(Q^*W4MC((OYFP@Q7RI'W1*IR/8R(\7-A%IZ-S@\ +MXSB/G*3=?/Z5S;*RL7+@:#=0M/.;(5EFT4!R"M6A)YM3U(/+>OG_0)M[[CD' +MKM;*8UGWC!D5I7GPX"@?!$[RK_+AR7;=O/-/^T]&OE?RM_N%..M^T95Q0#0\ +MLX%LA(05LDBT2UJ5(0UFL[6_Z_F!KAW@2!A^I25>BAF8XNXG +M1V?8;M,'%TZRVV\0*!!4NFVG!A*@'_(WU'=8.7<%)XI3^8.N4#3-LW<(^ +M*PNNKKY&I/3Y69"B2=V.W0$BTD>3S$C1F]!T0QNDP8:;Q&S7*`?G+GU7=_HND#LS58$JQMGR`RT81!J8@XZ_.D1)<0IUO8.'@9I!6#.B. +M@\2WO'G4NP,5N?JT?0W.,UZ70[3%(UJ`O7%!5$22^4F[&9A=NZ6TBP+L9@9" +M"H[/I;A2*\Q1P/1T$NC@$PKB]0_9N<:]Y_5YF=&M@6/R>6/2MHA];6.[EQ*D +MK'7!P6?8PN@_(N5PRW4M[A=*#X?C&5;-3"82;2VM]46--D'^+$N0F$A"2OC'&8LCB[,0TY=SP11Y57AOOV^%I^QJK?+.UP8 +M6?:'9U*'*1*QYX?:[&[+X.[@RD*A6BUDW09G'33JZQ`BDN_F>DUYP9I,OPM5 +M(RBT/&BIEIJ4=,;#2^`:VZ#-,]NR[!KXDKC;3:7X8P"4(L15=&/WYL#*W>/V +MG'18))_@*80Z!3QR?DN05D#)$320O#Y)4\.0PME&.N1IZ2Z[0.6,!.E_O&L$ +MG!\UWULP8^IW_W*.O^UK'OW(!GTU@G!2HXZ0YR8\"5X4"9VB,\N_ +MOW&P,^];7*Y8BC#P&JV0`/>4<&2-$=^4F(\\3:!!$GN9 +M\NG!"),B+35?.J0@)Y*##"4/2%SV7__/,;8;Z8*ZER_S`T"%S]_1Y)V+]!Y_ +MYNOOV%+(QZ$;\V7^GU3T'%X7^G1LFW(5`")S?)"ZY"VV:08!;)=@B(-+SEYB +M>#7ZHN301+UFJMH#DYKTH[>)I9&`C=>KV_/B#7D:0-N\#.;BQ_"`/(V!RGSI +MR[40/"&/U'JB=^Z5#$^R7Y]0M$,C@IUI.^P9"M/E.!0:<+PB^_"HD[GI;X@0 +M!52M![84"KTU*3'MZ+]@[691I>:X,(S1@ +ML>4$U%7Q27("H2^J2/)`M#8JV-8RYP!>[=8*0']+B3"R`]S\$&'I[0&>VGJ/ +M/Z#RNQ[F8X:I?;P$W]IRSJK$>+\C);]&ZC\H)O`Z0%$147&IK..R.I$_2$F' +MO4Z&,&YMVP"L"NN@2A[A4@,<++T))G&/^,->Z=^M%4\?_XMNBLX)8[M[OCQ@ +M=T-BJ@TLP)[ +M;CV!F&@YN@:/VR=*&U%T#0?T&(IO2FJ\[Z4/$U_V.-/CWO:U%S$^H^'*,TT? +M@<.0:LH+MP*>KD;02H58$)9VW7P-"KF-1GE3;R>\O-OT,^*G\*"IZP2X**1: +MT0,F#J_QAF3-NEOTO8S'(<(O@7*?,K;)3:_.K")@Y[&;IR,@;[^!U%*\GK\E +M2C.G=3..B8KJC10CDI@>4&73_CW0]^&VUKU1[`&`HZ@FVZ;ND%:@.,-9#Y7< +M-.#4)^^EZV=?7$354;O:D0/>?3'&47!!571?:./5N/XE>@F.?7-[6!=B*`M=`Z$8%(-8-MW:$_2WB@12SV,!$P%(&!H8H]UNM>=5G_>GMN$W^Z"FG +M<0K1N@P[_@-TO/DJ\A%7@G4OM^Q$H?[WG%C:ELB$M2UE.U1TB-<2`$MI``@*- +M5,#;]1%S1$241WG.SBJ`BR#5(6DTF==42ZA2[68+0#VN]'1?9M,"GM\^H?YH +MC%GH&!'GZO1K+PXY$#[L'=6"?)X;W`*9`Y@,]D;/:Q!0=N5<#[GTIVWEJEC8 +M\[!OMKUNS,/N1"OO+W"";$9\Z;+12Y,R8K-!+T&2"WU>G:_7T06IGB@@_7DW +M!>A]`\3>"Q_TV&9=`==*MAY?RR@5EWM<:)>2FTKEV +ML3[GSW>S3=>[2EP!F?F5].N/*_(2^GWP`26*S=3`%0F`.WP5V0YD/1K:U"HC +M3ZII\^%@FE@I2)LKKWMW-YR+EB\H%MFF$Z3TL6= +M+K;Z>EJ=G'VZZXPR,<`K^]F89P%*8%S6#J`U836CGIU[P(?7^!3\ND`<4K(\ +M]:.KX3O\!W!IOYK"K0U9,D=!270*T)?GU?,L>)1T_C#3D:*Y!ZOJCF=HX[(" +M/=Q('%YX.:V!PQ;U2F-"BH2P6$G%6_(8MGO:)Q,+8HOM:<#%;JI +M:XVG-%^\G70`LFB5>24!<]N?^%?.W>?&FEGA+BVC%.6/"P'=<%K^(8BM723" +MY!&*Z)<>^ZY-6S?QB"43$Y)C'A@^B?`L!/@D0=H2\$*ALMV(&' +MFV6)=PC[[8>!84`9(:STD8TW:;/N"4IM]U'9FFL>I^J:4Z\H[#?Z^6N%/DU9 +M(7[NY"SF+V?$N@_G'(RLM'2%V423A3XFY/&WRNZN\;$068UBMF)8N:(UC]IVTWBM^BL*VR8D4QJW4$QD_U[52VC +M"%QYQ4[-K9V43U]?W:O=!2%]HR]6LK.PJW?1)P*GUO!"(`("4TT2J>0ATND +M>DE7.D9-SW.K1*E7"&6:.`L]6\VIH4\*X7^3`:8]QC*\!5D0!^J_ISZG0#N\ +MGQQ,IU?*50;I4)#T\'?YR@V1BQ=60^[1O,2+1H#8"=C#Y3LW7N@MW!SP*%J8 +M_@P5B)OD.V5P7.RZ%WV\H@]9%1V_`F"B&OJR[^HYP--,N?N;GQURPIU6.FOO\.I1(?[.E30]7RR-;7I!WDFM?A&%6/]XI^F-Y0WM[M'EK#-D&S`21RI +MQ7'A!P"94]4RS6L)AL,(7HDW4MV6`WI8::90W2_'8W3!]BN<$S/K.C41\9X'YTAYYA1FV;&*)%(TH:U6;@.Z +M<8OS'A4H`]7>7I!K&Y9ZHA)^,MAL^ +MH9N'U(G(ZWF-;_XY*SYGB,.Y>U$YY+Q(RAD1V7>6.^[".?8P/1(CWBCE?Y(> +MY,GU*$9P=9_V/$Z=-?VD3'O#F,=`8L-;(QJ&YM9O\J>)E(DC[J\"@;>0*'84 +MX\F2Z?,:(*3,Q'XET;J]O9N2A43DK +MBK`!N"+>+B2YC?G8OJ&,B19LT2$JA6T7*;$CKV,`:`4O$!RQ*%J\BKE9+1TN +M^:'"LO%,25X$Y]T.A\29P<3%IL!7&7$!3B!EPWTQJ8.WV,[9)FOF&9B."!^E +M;KJ*DR_G9F*(VN'K[\;%#\:RW60'%5-5;W@OFSL";N--CN[0J-M;O/@/0GS>MFP;N( +MTX785X)P#R%J$SN#YTE5K6CNQ8<84!T(/']&.P,<=I3^O86VP?ZA=Z<@\!L>]8]_/.DR4B!9X/&L&=]N1B5D_196!UGJ\]4%>:I_ +MJ@)>@LN+S]!-?QHT+]D5E_>#D:UYK6.WR(/>([$:3)<4.%I*-@A/IGNY:RS* +M3S2EDLW_2[LV2;LYCM&3\?.=84'RA +MUR=WVX:;A"2DFQ!E8S-I^1<$R`HZWV3?-G]8:Y#,.>A@=`^A;Q?C.V(S=_;( +M,[?6(:F[[");ZA>\H47?VSVG!PA;)3(/MIYZ>'#K`;$8/=OK*W7]Y)+=I-O& +MNZ\B+.&*/D=Z"$T:D^3DO%T1$$``(#(NTHB8(1)H( +MX;#B\$T[$X37,SL]?XDR'KO62?\%3>ST&[ME+XJ(\Y?T?PS9CZ5&,@$E'GCZ +M>3;7RUCFF[GPTS:A;AH>/&+EL;?#K#A^NGCWA>/$M").DS@4PZ3\;T96 +M@VW+?A-+_Q*=HL,2<+\R1G3.#(RC`Z&L]^227?>G]"A%\F]3B5WPD:I12I&V +M<,(N6,.',^$%^X;]L%NZ9H'Z!KU!@+E#R[K1(?M]><;/FQAPLS?>N=XKTYEL +MN-PIY&*VB$-%G-%6-XZNICMSXD6&,EV(J@@.-R`I`XR2`G^,^T,0G++HSITP.5B/&132Q\O0/2LH#C:;Y=.'<;S8>X:KKEX%(3( +M25#P.\@!K]%$*O$UII=CHST9VI[VNC=DB1Y^[X31T*GTG +MV/_Z9@%CORE;KG^;=;SZVXUT#:,W$=9:TO$H%I^!34,9%O3F&AET@#7+XV?Y +M)9$Q7;A@Z'%#;$CF]%6R28_.XCPCJGL@B+^[T@$$!@`!":G_``<+`0`"(P,! +M`05=```!``0#`P$#`0`,P,!JP,!J``@*`3U]DI4```4!$0\`>``X`#8`90!X +;`&4````4"@$``"U#*W&SG0$5!@$`(8!M@0`` +` +end