pdfrenderer-0.9.0/0000755000175000017500000000000011622545450013762 5ustar twernertwernerpdfrenderer-0.9.0/swinglabs-build-impl.xml0000644000175000017500000002365110733156512020537 0ustar twernertwerner ${build.branch} ${RELEASE_DSTAMP_LONG} ${projectname} Using custom javadoc target: core src: ${javadoc.core.src} core external: ${javadoc.core.linkexternal} core packagelist: ${javadoc.core.packagelist} pdfrenderer-0.9.0/manifest.mf0000644000175000017500000000012210725114532016103 0ustar twernertwernerManifest-Version: 1.0 X-COMMENT: Main-Class will be added automatically by build pdfrenderer-0.9.0/tests/0000755000175000017500000000000011622545105015121 5ustar twernertwernerpdfrenderer-0.9.0/tests/samples/0000755000175000017500000000000011622545106016566 5ustar twernertwernerpdfrenderer-0.9.0/tests/samples/issue_19_b.pdf0000644000175000017500000000674411126606130021230 0ustar twernertwerner%PDF-1.4 % 3 0 obj <>stream x; mJOMIsr 2| @ܪ<_m}= M=uٺEf~- 1]쭙LfW+vϜde-0{fB\M y89lf͘]5}F%/+ ɍٱL>8$.}”)S&7I̝&% r0arl> endstream endobj 4 0 obj <>stream xTMo0 W[i> (ŷb vq7HٖUd0xޔLYȹbKv$|p|k e>5;yU~#_:۠O}̗+ \aR8om3k)9y7saZ O'.((+JNphWxF`WַbE\j:.| c4>&O͘mi}[^Eplw]]פRÓ{ptʜˌe ߰?:ӹepmos:7F::쒡#>sKMw ]5ŘI1xuO{9:*їLJH(`-wI<3\xt9Z\837𶾹=ns6s %}VvӫE+-QO/x[C}zW!5B.Y!",kD4&^(:I(A6A*W@P& RCFk2H"ӉI(&Ф :P̤bb7P)uNa (2#q$iB6NL'8@ endstream endobj 1 0 obj<>/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]/Font<>>>/MediaBox[0 0 595 842]>> endobj 6 0 obj[1 0 R/XYZ 0 852 0] endobj 2 0 obj<>/Subtype/Type1/Widths[278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 556 556 556 0 0 0 0 0 0 0 0 0 0 0 556 0 0 0 722 0 0 0 0 0 0 0 667 0 0 722 0 0 0 0 667 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 556 556 0 0 0 222 0 500 222 833 556 0 0 0 333 500 278 0 500 0 0 0 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 0 0 0 0 333]/FirstChar 32>> endobj 5 0 obj<> endobj 7 0 obj<> endobj 8 0 obj<> endobj 9 0 obj<> endobj 10 0 obj<> endobj xref 0 11 0000000000 65535 f 0000001846 00000 n 0000002059 00000 n 0000000015 00000 n 0000001167 00000 n 0000002830 00000 n 0000002025 00000 n 0000002880 00000 n 0000002933 00000 n 0000002964 00000 n 0000003020 00000 n trailer <<2d1638b9e71ee96bd9ffcebbba2dcff1>]/Info 10 0 R/Size 11>> startxref 3187 %%EOF pdfrenderer-0.9.0/tests/samples/issue_19_a.pdf0000644000175000017500000030411011126606130021213 0ustar twernertwerner%PDF-1.3 % 9 0 obj << /Type /XObject /Subtype /Image /Name /I1 /Width 606 /Height 194 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Mask [ 0 0 255 255 0 0 ] /Length 17533 /Filter [ /ASCII85Decode /FlateDecode ] >> stream Gb"/ld<-]bcGqGf$,NhB4omWp4e%/SE#]P1%H3$rn!h*\E)1mus%hsEJJ(9^e^\O8*p._6.KgG."@DI%OsEV^,Y=.E8Wk>jOsEV^,Y=.E8Wk>jOsEV^,Y=.E8Wk>jOsEV^,Y=.E8Wk>jOsEV^,Y=.E8Wk>jOsEV^,Y=.MjO^SBT:_b_Q^u=iqtG#)r?TLco(V$kj+fiXp^]seltkEW#(Q717Br-m!qUIRW/m8Hrq4lMqA7>2nb2\M j2[4i)aA5u#9$:1-lFPg.uEkI+g1b@n,N;9)3Y1LV:s,.4/HnQcPq15:m$4/!V72O6:m!5ROp)5CRadXmo\Gs$\CDLTCBo9M,if_CkViZTDcO$'LdG:InR,L?8'&B^ZS=cjM1Xkjd5UWBrItunum)rK.Pti^@5%B6F-(Kml[6(JL]DR\onO<1<. '14^W6dej*Gj8>l@ug#I%F=CL6_j0p52R!=@WVqMgTJ=f[eUq]!i1]NJq[-gY/RC:O2)aC.V;Z9Su`ga/WB8*\t*rXpGK=!r6/fXgV%$6c1&@$#"^qp'C>"Q(9VM"2lE`X@k7t@k:;C6^"&(l."N.,'(J)f)$6QK+)gDKmdi8WGK4ZYCMOG:D>lXe')Vsqj`qtsbpO&!f4g:smAjPYAKnNs#,4nT(RA-7B'C#:d=oPDZ@!OCk<15NNQurl3Gmq$f2G<'K!MPTWb4B\>D$f&Wejfa3Y&%MhET2R!J9n%C[=03t(%!SKDf;8[*V;L`W!`_EuS>6adXGg19DN-55^S)b+hqu&V7?*T!Pp4+8K>]"Z86Oae>Aq:B1*fm!74(m"gK15ka$Z*#rJ5:$ M*N:^[].Brd+W)^-:MeC6cG4S6![?V1cSE3J1jH24e$H":n4O![EXXccSZqq1-Emj#qfj%Vi:^59Y;0R_W;#Kh>$^JrXFDp-6\j5*uF,?p"NB^(Rg[c!Kh[j&/:(4QV^VNOJ--FXnq$dJB<0;DOTrMHT.0J#H[=13IB,[1I6$Ro&D&L1(_8U]GSE@<9mMrb;AdV[7M6UdYq[[UW(C)AS7jrQ 0f2\0"eXV*R.7[j5d1n**6`ce0^kmoX]qcDLECsteEi\i#b:-6'<^Z5jgaKF-)d#?b%g=U-icQr=\TK&3\+8+F[,-@\/0(Q?RI>=f]cr])l1K%b1].%!f_6FG89qBVr-kDPH4EK#eGjVn8C/[kJ2W0.:/bO5oYh,S5(D@i(H*t/*_l1`%<*T$J('V%,#'9!jC3n!CfFAgIY.i_=1tk_e`'Gbg\m69?<\uRuGKV?Ym9G+tg+r:GqD(4HIGLlr+ 1U]'@#-/SL`/P(Bdb4\%B]jRdu;.YCA5K-H2&jsAG]mi$C,5!0bESW:>XOBe<)o;K5LK2QU6(Jg0^ekR,g(gD[m^'=6ZiqYkqMHGdJekT<'T-h@OELOG%dr4@.]-BoiD+]4.UAO+1/G$]g/]WjdNfT'&Xj]&n&0D<>Sp%GA[8GImB4`JXP92od7Q2%U:Flh1F.9$GBKSG2B#aVRW38S3-VebaGkluRuqXdOp05o*Gp"5J>5`fYk9j5G+Y;3*DM_Ejd$^KJ*UtV\pl#>_SAr@d!/;9'j])*ZV..)Nstda?&Z7DNQkcfAi"K+?LknpS5hk`]/HQo;Q ,.E3a+8r$i_??@9J?-E"885j2RE&\*8(e2?2EK#3U2lp!e'D1?4NZ#4s^C0ObUAhqQYHS:$&-<]:)q!AlN^[*+:dioIiod\nf8j/\HM^3&JMAg64DSrq.L6%3qjNG1Eam;DZtn^9YNB-oD9Y)Ep],<`=\c.,?^o!jg_7PM:"QI0dPW3E7I/Mi(L0gO2^5 8Pt)86tgEK"sDd!"a4conO3H3^OXMS`qB\r0"B`F/^jR,+"3VLLZ;Z(18$D3YF;_bF-\RJ0(me5*iAl8%A7`T0RrubVMj\Pi:'r#jR#^C+J>g`5(CMAgdcsJ>Ulh)T%oT(3gpi8LhAi\O4IXjG?pC;CFQm*RL7DEGUMeQOD)?SbE9]2A%X(-#LeVr<-RP1N*4j@+-"s:*2=&)u)i:l WkLq+IJrFRc10XlEb&%T!H'FGXHMr[monl(P(1s%VD.V-&XlM&*I^[<[k#MTKN8<\5On*:2=^4I#tkQUa/F=qfJ$U3,;"/X+(%>@er)s7c+NHf(Z>mqfYd_F:,O@^?EBdQZYMcR"4X.^+*)\=BQqo(Nhm]V?Y/2'%2]QB`d%M\nu)CkAGV(^3C1omT;>>Cl16)G`R7cSJV41!^9TY@l/em\=b8rlu%iWE[J;"1;2NQk"@3l@pcjafcuo*W!Zn G9=n/,*WnQCiK(C?arI=gjnn7DlEV:AEij&rN.#E&AB)X2BcVDkmO#)/;Ui!o)C6eWB\M3;\,&L=2E@/R1C^inN;>LOMVaXR+M\oK`eng;`528HPR&EE0KeaRJd:H%X[Vn>G\h.fW5N^!;+!.m0;=f*3!Y2+BlW+oSRg89=5l^NWIjOD6;\K[M4i77rI2(AY^-frjbGb!L_4$u,k>Ud=ma3Gh8=%3&LWWhu?S0BoUbqse"=7#l<"h4`>s6Je* %UbZ(P3$0!ljTR+V9r6_7;(I?deu#u8-Ipst:nTB#i^LW#mq7n%O"eAu8+rNiM$[0]jdBpSq%-T]>cYV#"#M=G$8Af'HTe@4C*a>#P!98648LU;[ld8ZC"gI%[^%NrX(ir,^\(WL1d5CSjFfdV5Em:4+.iO@MZhATp^&D\U=R&o3`910j9OENU_`J&[h.H2DX-1>Dtbs#gl6kXCa\)plcH]OJb;1UjSnlNJ+I9HK,7A71;Y4@]e'H/cQ*Ur^#'b+p@8t_oYL5/fbj[!<9K_)b15N1(EjtoYm,Y>]d[!4pD5!CKTPssQ3PWiGA=F/8qPt:p\-aYDlm2j_0[_.u.Lq8I68BP:*2aN1D4cP3f.c^GjL#`LS8GEXpn+P7F`J>pS3C2G4pXl0aE%:7S/^>B`43JW.meCBLhVO%Pk00hIP(A\7i<$sb&+Y-M]5L+H&,LFOLK+/C61]&Gu^Z]#n&>oR@9-bX010\K`/L3%KUC,sE<&L0^E$U?lS(;OgPfKn3Uk#]=5 .bKTART:&f\.@o6,Cj76PTJJ&R.F]s*+D,k"cCUQm;+HrFWD,/i9cKW$68%2jAA0@VJ]S8V&rkCpFVl_6Y:_&U4SGEbNWfeED;abrG(\[P'V1PaYrYEhqaV^15WNk$^cgqrDsS# JK:2.K1rDC90g:Zr4JB&$);`LLP5c)BZ#4,L2E@<1`fpcEs/YIY05n-Ef?0.&^>"?@Rgi^5%/"LWc$/Q^i@X@A^)VR,?s2jo-;Ih")UN(rFMR"bK6nX;pUYB`XciaR?Mo<4\]mDRh8=Ca!dVtd>UF]2OiWDEC95$O/gqJCe"H!MEKVNC/fc;Br?5*FUtktQ'GjN<1D(pch!7AC.;XrUO;p9:lF8U9(VO'RW4foN_pFmi0t'_ o/Yj.!MUbZmW>q\O?,U@1UG\eo[A^ZB\saO[%Dd!5DEE2iKW"2-YcQ@%;m'on5r0\jkEJDi"5UDB=_oA6QN;;I35;='7((i;O%p5W=_.>@nf$WR'L>to1Cf2AUBj'e&(i'RFcL&rqMp #o1%9@Xi@m,O]>:P]NL<^nTOC_b:-qu[V^gjU2'Xc=-QZ$fJ.O"u.2UR!=kn4o<0:KO3pRG[A5pk9XAV7XRXf5]@]18(p!taMd(a+/?g!6l$28ZWZA4qI/miMUWtlF:`B#m:XBI.igGT%8/fQkK%G*fHOYrmr#]"7rfq.t,RM#Lh3d&sel1[h<_dRhPLqS/p)cAj8/:+>Bb=;3s2#&g/l/r.9)d.Xg3gQG1OH;XujICJOe_ni6;md=I_]F%>9 h*E_he&B1a:i8W>FJ+rK"l;kBpE_amp,C@.IakN/eWI[B6D1>1o%@,AZd'kj\fCliAtgF6^CV+-AdJm`i65(KN7m-]AB8GK&Pt)&;H'PFiBed`fSUd39Rm^ZQ\(^Z=:3^2u&u5Z#t2A@o^$7Be^o;6*KRag9&dcnW m>u,q*?UgMse;WdQ2X&K?!Zq1>R;GE7/FIGQ)2GUciD9F(_$EpklX]!Cn@eRs/K,U`f55>aX,@,AQ=EJ4*%t9?lPVj)J6X]kRPPOr$N;e5dYpit!*=(>CVG^01R`CXns]+/`4Ip8^W6^Fn!%.2VEX[."e:,[b3'$m6mKl1,cGFCL7CB0ArO;gj9SK3P>gt;d@_@7l^:Cu/[%@MTc%?WRaH2%e&uMrF3SZ3M&b2pL^B_r+h2d4E$nSAm&2D2l; QiPk\r'#g^\-$q3C-nN1O16##3^5;cm>FY%AY[%-l0(N;c)ONHL];A*p.*4Ho*$X^9%^#GVk)#;p):+Y@\d*#!_t<,/:2V7fF*4%%;0<-iR?[):n3?mip@f=,RNWP<;a>Aiu(9*O;Pu\iha#Meg>kqI-j[b-+dhX>6#t!J936F7!H36%sMMDR8o3+CdC=+d_L7G(gjZ2Y&)X5)]&lo@@k%(bZR$(TAX!^\Dg0o@)kJ]8V`ajhSnko/bBZ:WF$4_&lD=AN2et4(gfi g[Hrm*+:.ENn()mV"A$UU0956rQjdf."jhiP?,L.OtD+".PE5hH[nd+(](JQP[$[\;ta\dI:Vt+#KclBeeSgN=AhDct6NA)90BB;>t@3_!V86TV^>l5(Q@bqa$jFeO3sm5n8\3LJe5@h2R\hS0s&tSFZ%YF1 c==D33qNGA)ePOW"\m\?8_GIguQaS=aj]'2)XE5?.)Qa oaQ`SG1Z_bfU:Im(Y/r3O[BV7M!jHCY;K'O+0)l:+/.8Ls[.GIWOEYZ50<7gM^Kf`;;o=s4"K"pO%LpX]minYfC]iKsH5Xt`mTam[S0+p=!F@079dQ1ZA+KHY/,O#6hc6b`3*YdP:79JtP9*HtOTNP3ndI)GW]icokF?_DImofq`r"$RA^gj[#fj7f,0Q,'0AEo*Z?(n(c8cnU<`'N*Z+1T[=!_&citC+Y2;))W;d677=>_jh.-0f2asbpY4_V.PC1No@.#K#%tnLsoIR_qAOBE"E!.,UWO;*"gB?o&9XNL!]hTo_BXr8t>mG$SL$b1-]!2Rrq.6c2N;936FE;XH*hJ%4LTIctGR`*?MJs@a0Ad8gj!>Q;og9T_s>68 )"Ff\Mh14AosX=.6R:+chk5,??>8@K0Wl9P`+9Egklj1PUO',';Fk-`Om3I>CQN^1un"n3nhGBa_CTEj>kDbpLd^a#5i@]L5TaSX/XB$;_pV!7CHD.T0-1mA'3bVaI+E9++dbqlT;`g5^hP&mcoX&A^cUEX/VP^))PjXQ,r]P4@A1gn[BnY$=?a2mH.Z;-?f`h`2d3og"UFLj@LKf/iI/g29q6YQ7R,dWi&*FpB50oioMN?7h4(@fZa%/3G+!Ds7/<,@!W:]4g&2KL`e6A15=m]4XcaQ*G#n<,=M?\57qgt0ct>=1i_r7gYncY(Rm`bpc+$:=ms4bc 9qjYb^Kr_]5Q*Gsj&3FmGAZQqB!G1V?e5]MEX"@@odR6U#]8g0[4(L!$>osr)Jo4%YjsW)g2@neZY*@r%J4a"B4K$L0HMP7.5[f:6.J*[bK9U='71CtTk6W+Bt$.^QqpTD`C6X!OuB(!'`Sjnce*64-ouH/`6nKW1\f&&HapjQ'sWbuT(:+-\ZS<-H(lgB:PAB=mNtG(\gmi>l8^G6WYpG3j.,HJfAC3DZfUb2GE>bsQR1!j"dK=-^7,MsUEKOk?0f3+)SOJjiRnDGHd&le2d:,W/N+?ZG(>)g-G:J=^sd'6l2Se4Sr_l%1R9fmFVF67gH@s?D!dK -)KJ_j]>uc";`WO+\)aAbra[mo6`V?eTd(#@[n2A5.qn72@1FYb8f->=!KOnb]1DDnS#aq$HFH;5g).=E)q.f[MCoq3e7Jd=Z45Q*@Ao43-Q.6f?j;*ptEGRIXt#c0m]$aCA+TWdfeIOV]'I\YY/](mu]]A,_d"JBabs%>)UX!d`%qV`>;J!VA9:n!V3.Lq-[c]jH2?3EnhA')SS1^fJSnBkH\QF[UUhB Jpfr2+hEEVSN(7G?EaLD*&AX><3T,Y=/H>D`V1]cXY:Z]B3)f3)R+#EW_q<\*^GOItfql]p4&OO`Ae/P2*NGpNSNeCBKrY>i6`#p4nsqkq$;:0el4/?FaT8Wk>:/WEd8R_/`Y4d!m_Xj5b3.W>>*&9"ru?'6I)P/mn@A%'BiBi](:99KfZf+Ol8%[o)X\V6@q8b+XPYmnEmjQAm*9!P\3F.hZ@=W-`Woj4UZgGdVANT8.>nM)0iiic_(IbkBi >e8hl7/Rs#`*fR]<#YX8Ao]:UX4mBTZ%eC,RlS]JY&?IDoJ28Wk>PKCa3Ge31mWAVAQf_mRo[N>Zm2+Q*&:L!EaTR/N#Jm!kepL^b0-SW-0CRW_nWdbf.)k u"/"]P@VS=OT2d8WmTfFRbu>8/;Rf._rRil94+)qill9J?rp2_.'l/q(L]B'H"/>8KPtAL($b<]FqG:5&[Nd@T^pH]tr0j(0A41Oer21=c0Ncs'AS+R6Q,OiBB$RWNCc*G;eabG/5:-o7?1%An*&#C-Ms:'"Jl:B?T:4$]m$Kg*o/s&-Fk(j0`m(a-CaC*V8!lGd@bsN8^hPY>8'[K10a)1agXlg;S$0Io^EOk@[56n?o6h`!<1(%%]-1\,)lj-KddGGBP2Pa@D6D1dd/2V/f6Fdl'3+<5a&@r$umD@d1tg/qPNUH;,[kVBUN0e'g>>dg^U8_\B>U7EBUUPVVN)a;\s5,9r#IBS8YYERcl(RW3Qte$'R&Y'H&b,*T8L>V#@ljCEGq;hLUu3mH;O4@u84)r#<*8'$$`^[D2-S,mR_g']DqIr6C7[qn2V=2mAO 94afWCsnJ68/E`k2dQ8=^[POeds*,JeR!9SLVon)%81-V`H$R!bs#dZl7pf@$;:(`eke.@f%B'egBJEpb5X2%h+=mbK2Z,JoU?VUB[;'4=j0.oQI^!rQL6f]Ce?k3\Xh9icEd_miu#&F[^:1CCj0VNS@?^#j'hCi?\p;ms2[(JjF[=/)YOhs(_('O@;%AUd<$I+qARVgU3j`k&u8HZgMkP8@aApO;]C1tE:ceNk1sGT7l-7Z;iS\2be?u7+W; uc"d7s*BGOR<,)5@FIKsMab?u#o%hr[Ni%@Z/[J7H%/.H.Ad&!a47T3/-@JL)_)S\8Vc@Vq%PJdk>)Ui4fn8cl*fkohT?e_[?cP\:;/(iG!igK;][he;u(i\KnS7DLZ7CMRVLplngJU%$iuC&ZfNckM61[=>I06C-0L3[BVr)oi@"e'X"'oeZEM[FFcH7%j[#;a-V&;p$QLG8ap$<@*)Fc0:XolfX;*F7\qpgDmjME,8AQIr1k1\T2,@Zn3U9g70-S+2/T"/N!rZ^)]&^TiR`,`b\P6S[ XsuA>Nm30#^dKES`lTMFel5TsE;+#">;E+<;DTk438g8?aM&9aE*tW7p=P*jHSpZE&ZgjYH"mqat[,ooN(maK);>)3YF0/$c!7TTg9A6RtT-V2@\ue44.G@^Th7(4U!,Ks)cgV@+s9=(X62Y;CE0=fiRZK]jlU`0U"/X0Eof@N,@/3uPYt4^(oTi)pLO57N=;3lsp+VX[rXhU(5lX)XMJ_cp'-IsK<&\Z8SVdF2<>3-VAW5Mb7Z49`BWnS9n9:#&Dk@rfruAVfY5gV@:`^;pEFPTa !DLBeE9MR`!)Or-GtMCWd`W_]'/aQ8-+>RK5s\^J;`+Tt+(Vs^HfH:3(h3$>;sb:glLeKrd:V+P"$\Yer.0@PlsX@[m2rV_/Q#fG]K!`#Zf,jBp3V)`gVNZ!E0q72U.%ckB+"EPbqd't)OM1DB?3O[k1dm6>V+;VQ,r1uRB<;28WrBn42dCuJGd()B6&/Q[0f(HL*?EW;>o?P-WBi r*B)q3-`pZ4>j>ApAt7[4i8j.Aj@mY,&tY_/\ts3#pOD!)&QFKKUt52>i7SAJpMd(D?#NW@hC*;H8e(f04gY&Z^[WD9S3e:Yg9Gi]0UcRT/EIkVq-7Pg[Q6rc"AnA7:Vcd26qtr-2]""#_m$gcT!O\'Jb+31?3#c)kD^4/],L@3.F+-HE7WR_3bOLop/L'+kCP8VM^NS.IE(6XQl,GXjVh0[%!!O^XLfAt8Qor4']?@S:]t76aJ2%JriRd;qR ^S!;NiOE1;&fj-r)`VWo4*B3.%Z&ITVm^^\]ETXd1K-B@Q!QCJHb0%kF-5S-Xl[iQg"GOuVFf&C-n]hUj[$&)^!dd/h8X!:2caTgC^HnuHTqj1nELd+LuqCJ17/"LW9LUdkcS7g,sN'c^%q@HgaA=qINRJZ,XlbM!+)0N\qJNh23n.qVD@eRLY=>[Vg!lO\;6I&rXVmC@?C$jk0mPq)j:`lj3Hcg@fP5]DEtNm.-TD5YQPXf1f95W."l3IXb1$#?1gZs:O?)9&Wq;JF.*'aki@AJd?.LccbW&N?DJB\f=Aq"&08A7YO&2EY,[eBS6UKb]hRZ;b#GGaGKe7r$Pi7R>@D3J&=WQ"[P]IIX,(NMdpY$B2W iR+:#V>4hMIuKc[5h61]nXM3\an])RAJY%l!U8K?>6K3ffX'q:WiDrQG4o9Yk1^$dDt4>;k-?Hi"ZV)e>)To.RmRD/.5diSG&B"N(6Z/0X++'Phjq#=CG=b#V>3]Tc&WCc[!f8TA*(Qb>Yb!b>"-K[_'Ria9ML&WAAXbR6N`TH*TLK3\"`32TprY^3GkMdY+8^.lbK]HmVN$4Y;;cg:]5j.E`X`R/*XXM@q;IZ7fK<,#7#-`=!`KHc3k%rMF*3-r1e3@B[#%P@+UE(_Di-MkB2b%Na"l396S>/0BE.G%X%>k#Qm-XPqkJ%G?84?@kH>(/bdT"J:A7D4fssgnH)!4VDQ9Gah!/sp>'c>;R+p]OV=99CA!U,$\(Rn]&n1`C'LYB>P*(BIlCJa' .B=?;W(kY7_/O"a7^7/;HZ"*miW[U`.[+W;cWZm^d4%4MN^*[k^W3+h-D*USItb-0X0DLpEC%4_@jF9BLOlM=0\Rc:$`).aoKu3Y47uUVG9$k(.UBQAH:gNobG"2c)W\0QH1Y."9*&+>@?6-WEb+R[iZEJnOE[c)4N4$+4n%k.If!"+/48K_B2]2fN;LgZd&:Xn*6sg9SY\sl,re%Hqn0$KDmuEB^KLpCcOfi-.Cm_Z&ieF?hh^gD/Ro1,l"+ 9eUO57kU$YmOs;kRfVn1$]64\$;r\_(N1=ptaga1+&:s$Y^H'dcJJ[o&d*si=bQsSJ&A%_O=W$Vo*50!QlH#F&.VH0E^=O`@O6W#f"6XT^Z"/n6<1(IbmCT=cTC*r.Pm]XYOL+)Ri32X[tQe_hPP\G+p7:Or.c*&U+T$#, Y=.E8Wk>jOs^<+O$e,;4Q]ne,6pkE(@KJ(?&9k/d]M]1$I;TU%6W_W=46%S.BY64\[cs0=(B:jE!5t'Qm5jOsEV>54G^#a3Ku!6%Aq52b>1=J,%_m"V41(.cfoEi1Jh\@H-pC'Bk?:D^JbYsKmOsF*2.uKjnp'>J+>&9uVQHCd.s8,%\WoD01H$5`;b(N@PU&h`,Y=.E8R_e!b1%3&!IfV5s"5&\E9K,)etUceTEK@S1s[j&8Wjq+WQ)F0?6hQX=+25HN,qe?G1V]9_(Vj@Q\BdVo)*UC:H`*lOrSMBnri48p"5F&f/o>&3TiuR,Y8W"J,e \=C=eXK#KFiLTV>H2Ni'>\crNDbesZ4,UcTH26?+Wqi4Xc[cH?*.HjQ[/m6Zm[8Wq]&4(+5_PkCn/>YI`M84OA"8SA!4B31H_;sIJH9DKD'3`SXY)!$J?+8HW>%FN7N2(FN:`Y>"9Vq*+bOpW+_\'b/23&`!"?feIYj/'iFN5kG]`rMDGKaAdRUr*jnYV(^BL3:/Ot0II8]8VOIF\M9:uZhdasc%?4r[6.$G$&9eE;W\OsEV^,Y=.E8Wk>jOsEV^,Y=.E8Wk>jOsEV^,Y=.E8Wk>jOsEV^,Y=.E8](9fj endstream endobj 10 0 obj << /Type /XObject /Subtype /Image /Name /I2 /Width 100 /Height 100 /BitsPerComponent 8 /ColorSpace /DeviceGray /Mask [ 150 150 ] /Length 863 /Filter [ /ASCII85Decode /FlateDecode ] >> stream Gb"/g?($?g'Sa't&I:Z&,1qJc-N_nq0EMFE?j%[XU8oMX(_/=I>jT@PjZ)0+S6tr-'>ZY>K:`.AV$7"G!$NiqUg`d19:9d8bl<4XUCAaWCO(1RU&`0"TN0V\5lG(\r8B`]&OLhU5G,=m_*KB)2LrAY#^K%bRD.>Q^cC!;sEK6qO L_5);Ze;#iiR^O%Datd[dieO@nM32FG=a63dh8N0f?_X5o%M]8L"MnmEoF%:2."-#Rco^F!kT@I1.^ZKVj`f+-u>9eW+RE:A_r()LF5)!agB2LR,+KhD8afB]E$p3I=.t,q/%0-d"&IP2Eht*_Z#@-K!%&n+&]RZ8rGEJ#!UYd8tts3D8bZBT57/uQp7SJc^c3obeY;#jLKG.B&%0jfE3C35jW*@(?^bqj+r[f&``Z*-Es[u?]9m/&S,P,V!Y bn>(It.)%TL\9NCq\=l%l&9dXhLM9kH=K55ZNJ-^jEuk;I#_\$'L#0+(b/<]@J!h,Ld,r8RIPAH+'i*dN>GbjUf?,qoi^+>#LLhEC>9W`0.ju&QfjoS:ii/qar/>R8)//_I_:,7r<=ULuV>@A\31KZ.-Vb;`fVF/PW8>s);E>H\WPNUu`Qds?'!R*&=DOG@)mqYR^&3Ja>$:6g,@XgWX@#+X4N>,]n endstream endobj 11 0 obj << /Type /XObject /Subtype /Image /Name /I3 /Width 755 /Height 1181 /BitsPerComponent 8 /ColorSpace /DeviceGray /Length 55837 /Filter [ /ASCII85Decode /FlateDecode ] >> stream Gb"-6Mdb@$e0[`A!lf/OP4KN:M-o5XFN[r2reBC>Ic0H>5ufZPGeRus2F68W3l=ZoDkM5ICZoLnQS\mDq dVpTG)dL&9/\'q:DDs@S9!@CD+.VQ74CS>E7dIGTN7O2GZd7?"ZB.7^*n7r7Pnc."FYbha@l3C6`s<)OL%%^Pa@MUZBTV<;g)%e]$^m!(eKIh9(7p5"[;*qls(9l#h5nmm7//j0toeMLp46c`Mgc_o1_c>@EMe<^E#;@!3-)S=Y;o>-)^*GkA$J^k<81,JI0(fIPHmHZ=2^`cuP\nWJ,e69/CABg6ppbU>CC+N6Q:M@>1tquijWOt-MKF'"cH>$nPg1CG&Y%"@Lf`H?Mb'g6V6+!e1ta!.ao`--Pd=2iei;+N)H,56SmRMk3dMZ:U.adPcQ4CohW!RTT]'bpM"6nXP2oSeKN&<-d`gO!iJcBR<#^Yl^C1\qo8G,q]9Nh57>_p"29PORV.hjJh2]q;D$sG5AM<#sgc'gU]-W Rp;PMU25&N,U@&29Yq3a5V(,]cP8_u?+2?,>?%>N,)+M4i"7GOsQj4tu.8!Jjoo7,bKFIhdbihY<"=dH-PmAf8d\0N"`J>FUaA9p&Zf^%Pp>dJ#hBfaWKh\gP[CL3k8TE.p*&>Z&)Y;^$TB5+1#K-Sc1dqil.2-ZB-mIe%Aj<,#I+7D2i=,OA.M_@\%g@!st<18,2ctS26b-/2P$8Y.QQpRphU/MMDOXb5)h[Q4Y>Q-%T;nes/o C`35riQa`2tcI"C6"dl/0/FQUb+r_Yn9QFpK*8@Bb)Wk^"5pS8_b,g@O!<:/>[X6&;;e0rF2>tu9uhHbL#i/Ss2"ZJN$KabN?m_7TUs9A47qF%p5o< 1L.s15.:6b<`7;"1Fi)m"oUsMD@A5FM=O#r.+4bb&#,A6j+9@]k$ETI>:[$c"r_f!qBC1?<_%hqA:Z4Xp\Wa48XM$*&+[^D.i*C=Z_Zl%2SWlcIphl[[7Vcoh1-E0u/Ol[>V?9UC4#fOZJFZ3];p,h6hn@nN?`/2mN+[_gL^[oEL69o/a?)SG,&RD*"5.s=<%YjS9'r#;DRnu\'TF_l+U0_eo9Ai,enaUZd0YEQTGhpSaA-GBD0%\W_sYUegVc>DZ_$[5ZmCCs*f4D3>1lth1sFC0YlVHi'YR,M)1ja034Ea^9D\N6',,qA975DXF]1e(El!L,eUG,IIskG!S`o[/LmB64kfgZ7cSHhn#ehQUmN%%B$H,N7%V7JHO#0=YuY`Jg895\]HQPV1$^dH=kj7!6sWoAksFdD'blK,TW/+7Ib/C=@l%fgd'GKTZ8"S:kNQgJ+#+1\41Xk;UWl8mNER*215.D/"DcHI&oWVLWOEj$7Z=YSorl&Y77tt[1ZlD4k6i;,/&=8:+s'(/_2PdAI$@"&j&t)I7=O(VcY4PoS[)OCt(r2'9#@WFW;tTU--o7_?it:`,EqG3Y#qK6ug,1A9CJ.MEq)>=6`5>nY?h]J !^isIh_6;Gr]E;Xeo8n(00Ga0S_B$3\:G_N"UZY96iXQnjrd4f#k)4NNK60[>:3Vlu99FfjpOu`J`Vne2Xpn4q)/ pC('\Mu++(M]@ldkUN/O%X!h1Ln@n%L`>m=t6krk+0e@36H$@+lO\k$0972CL-fo#JXW,0(_-Luc]=CsP[3%/4cfh?u<`mNqXE)n[BMpj,I&[2qIh[j9I/Q3b1b`8fqUh\)nsWo,!m\>i-T@M_G>Gt#:?>$=RRb c\Y`#cl?d[feoe+$4ndhPoj!Ea`V6S1o8pQ^V/$aFj$\XK&r!N!a'Aa1i5X>,i+[gUe[91c>r2T,OECY:E:;TJjDUFOf:.B\Ymi0]bLC]RRIc7Ct(Ntm$=Qet-'2,j'Z4?Z[?]<=Kq;^"F%Dpk69g+/W='i2gL\'!NIpuErtjZG<[)sS6hjeQU-#Na'@,;6E:. ]P`*Z53+D-E'1ibBj9kjc9O/jYKYQl%bXkh&U(.L?!1(K/=`\*LH>;c7;r?Go,SIlJ_'IO'[sF4J)AYS6%4;rWI1gR,=f]POgYJld^(QF@4QF6h:*sk]bF2j-S"ba1`dpO=;s$?ZkJC!BAG^?.A#TE@-9I@V>PTEAISmk*o&?q4o+VS;'e:!(cs2s!tUd+t(5,Xe7A@IA;YV>.nhjH(L(,5mP%geSg=7-WZoW[+EgE d.DUgf_%HUdD;qjt0F"2IKRc6`&N1AP=Jar;i]SYL*jQ$cMeL4t5K=P>HLkM_XYl,[!XYZ%-iN'bE3]S_pU?lsW5`47*"kTn.]5BtZ+`RSK$ar_8AC;#mbPI\?kV6Sf=Hh\'U949nfN,V4L(e/eu!,LO%\fj/mqb@a&75lP(AWEMR+s4@ZA`8Ndp9I*S[?";1"6GRFB=1?%@K,t3+)YNpND5aW%q>#rc"71heact4'dk7_kO"N&675HZ]-S,' _P4FhXf+5VH>dXW\+5CaPWoKpeVaB_`tAnImQfIUA"Xd;4LJRi.?Cm?*KF)1",'s2Q%ab%ODJ[VZeODs]A"L*V^$p_':8?#hiGRI(nge(i2Y?MgoNg5iV&!g=6"%G0i(,`j\EJkp[mZ$4W-t>hC]D2*YmciHNAU'bO/GA08r`k;an?:]<\RcD#<\>mSCe";.kbnT"HY(!9K7C=1&N["4Nq&@;q"C`DlcVnG/4r :/RJ#;fq/a_`X0MahDB??0#5Vf$_tYZKrm=irPo"uA7tIF=nNnYj&]Zkn(#LQG'%6:jjFmKI/Lfcs+tW]?PfM9.L(6UsD0^EPESgc\!ds+pS=Z+b2>.9HjL&7pl&/No;J!Ts;#WukC\]^F-rhP*ciOpL;QVR*5JtIU*([`BP^ebGnqnN/ks$4`NiWph6O.j8l'i&eejNHfKkU32Rs"HV,jq5De)G#jLqJ9/7tFmfmm;<1oc38c-D73m4`&Np$ _Oc#@YrO=@9a[?Gq.7cKFNl8jDJOWb%!K]eD3i`fE,O4#ogkE\"@0uWF>50f=_E"bn_&q5=X<>`\9#p7(B8iLG1`g1!*GDc$8BE4MA_SnQY&3np-$7`&b(ik-WpkY\DVGW:0b`^@b(g2F^h*e4I421lrY4RE.<=8kH^?iqe#c8qg>Ze8:+AO&-ONp".I!VM?e;?"uVm"J)g/G*2oJtbdU@a;gQ-W"p @hZkt#'bl)$jOe/IFHLe#!Tf@DB=5b#G/G:r1K?66Y9]/:7na[rGit*TX_ji1h=n78;OK`'l;4PP6N&[etMgrNEi1uGmbM3-]UWF#nQ&OK-uSpnj]68*0R8A.b@m(fW+88oSJ^l(hfcdQ,h=L;j?QRJ$[/`]49c"@D)LT\T1a;8*m.dE&VZ;5CF0@0;MUc4j(-6h+o@C0MQ&V<4PkqehUR!p1fD+W`*nB\OfD7Q,f^W^Np[K)':"LF\/r>/\QmF&'$5m6$f4%!J(Dm;@DHl(Yg+f_L)F*hK;rm:]'j@NmK65?>NN-1>6="Vhp4g]FL^[\6fA:CYePGX8(Mo0%UhkW/5nPBM1NB6;g@Fq#JE$fbAmMd lQc.Qbdi+7:,Rd`Na-^'Vk[###>j>.;n8kifcbB%I5[NK(]'nV75W]K>6.^Ld4[^W?"eZYn:W;L;?iY?#4#RaiThDLV1]L*GDYpc['AQ< s_MoSS]HIphC<&VA-g5l:`"qIj,BoZ%NkMkNf,nGIHq@E42AUBTBazzzzzzzzzzzzzzzzzzzz!!!!8%Wb*+mo6,H'/U1X)4-0BN5%ZHmX1NB*1(W1i(qfEPNU"-G>c,$P,J0t#KA&hrZ?FjT@)eUd(aeAb"`BTE3AD=Fe-#L74]g=ob57.:P7t[SVu!mh6=82p>l*XR>P@9]jFBeM%)EIlu\QVHaQhObC#nYjAaUh-Cs8;Uls)rJ`B+4=a;H6jNj<4gUo4gf'AYp:'.^);Q=iB,)Nrq@(\jp@/?Ek<h$Xuhk8#`<+;O\@f,.7Oh(T'aZn+aLZjtbAj'@D7e!unA`%(,rs@52R(<_.S[;EIOWj8g2ZO/!aQ$RqP27"DZg7u+POK[>U&B9e7"AA4h[DjBIbPlTVMPZd'J%ZCBI*ZS@4V)+_ATpla[g-bZ&`*emG'F=P_Xd/Frd1U6C-#7-Sr)tGDO:@TURQ*<7:D=bhb]m/I6Y*Z-1>jF^;4]neR .3JO_"FlA0BS(Okg^GgT3"Rh:&LCV;)95G%>sq13XG[P?UWUAiap%iTZHmEi;Cf4>P]GJ61P->cNl.-53%^5UXo)pSYg*^0qS.#`KBFP`hkI;=oNi_=m#>*i+ZGVmDD-D0Ch6=\M>_r"';L6l0NSO^H^6E('ch=%mPj=XWLrcYENQOL8!.t`KFGU4DP?HQFD[" d1sQD[;SEo!n&(;ltG]^9<;l&D/+:"t`/T>gDuGZB1ih`MC:T_fiNciA,.."=_M;]\l0Pu^h5.Wtakris,#A*m(W_ku#_P+"b&.[+^&H:tdEZdeT&j?/UsWqi>G_<=DHOeHQt\R9UY7r_5LIge6YTA*K#\!\:qc0#GA4.!4Kr["psLo$QTX@A,M0l6N4.\&/noQuggs)0-AQFra[V3sh"P.fKdj$>=):N/R_"j3GLm$,QQ(Y2lqA1ZOT+R8D^0s1m?4.4#f):Rhm#mN\modhsX[B30P#%uqEhFhK3$Ib1`'>mjDQB8a\MYBU?m9fuDIn"BlGrM+]_!#N.>g]H[+kj,Umd>dqmW3: h8BqODQa/dPru@Y3YTnm*Y1O31VsWdmrUQKD9u80WE@GS"W?2SJ!?'7c/RUaAM!2DO1eN^;Ae7$Q5o2";s*J^:O9CYB\9.-954'0+gHUhB7sP=c[*&oR4B*.s/q$?:[E>@Zdpe/k#:-Kh3mlAJ'mALS&.(?:W][6]%5U("n.[L/V;qn`lC5PYiT4(G+sB]KRX?,JWa@a+,-*?6kcE7l:=?I'[b7_g!8E*A7CgD?Wuc=s08]Qk"A^1T;)-F=G? W$OtC([k4N+@at%m(D3tE4b=VYLLr-[$'?"/eY%ddcJbC;1;YVs`QFCO2.'e.6Y]gcVpK>0^PeTkL$cfg%HEi03<$SE,(*ORP(:#b^DsMh/+(eP$,N3+M3)oZY"MkSeLp9J'\b8^cJ"3R5JG1?)m&LoY>/uS>FHSqs/3,^"hank!_Gr"(2W$#+D.^Q/!L,enN2Jf#e!Z"f[q"R@dX:+Z*dnBl6;tbG=%4+fi=['f;+9]_bX"s.E3625;_^#9BZ"jdP@cr6KtJb$JWnFT1LF,nQp1etT+Q6'D!DDB[&MO;P^Be\S7>O EK&:Sg^E,jhF[mF"R&BnsA-/DjM/gA`F3X(iZkr0k]qp.2H!+<\a5-o[d?+8(d/bYF7bD_!k$H:/,a*Pte<4a0TTW!tf`l7to7%6e-HqYK]t@,IVXp<0U;cmXHdAXoR9DT#kDnVBZOr2)jHon&9.P&c.tJo(QCQjq!%<=dfT#I-o1Fe6.3W^d-m*W>&t"T.r5J0Y=57WBKdJB8(K)sdc7k04f(MD'QI!;j^&h!0"'LQ$L8@h/[;["+LEQZ?T+ Q8;Yp#>.r*_,'VLef++fS<3X[GeGE5kfuH0MS*&Ei*aocn>`)*-E\$5F./.gB^^kEa\/`d8>,Ej*8Dq(ol?PV4[9dlOBA7b!+WCYGU*L.]fN1nQ!hcQXm\-3sR'9/[U&(H_e1hgD_FBq4_W$br3Q,p.ET,2D\dN>s?r7bE:_;Z3;,l:*HoP0^TfN![4*T#2M?O"K7;5nSbJaMfc)MXUGUi2%gKKZ=`a=XMSj6k_S1nH8p9T,$.Gf?=[!lTpVb 5TRUd&m#>(CP$XB+)phEY85`Pamo_2k<'mXW,!PFlFp^n4n:;kCqJ;]ZGU_uQ#d,PV]eXSmCdYOk"gr(#<;CJI=hr.fXBgiM0Z=W<'ei^a[>,$U?9H$7kNJ&+QE,;q1ClQ6N&:3ouhCeb'BCCEK(1Vt9PL3u3=-cQ]h[l]=r%4Ag3>'mH5+Me+IiDE!A4?:i%o2RS7PlP@`/s]7210KFKJ[Q`oU\Upo]]83)'-BB!6H^;);rCd@)?k$pU*A.bmCS@bLc]dpU+C=54kcS>lqVkM^jc-DsS=EFu;>;(Qei?;sV@mq)%A,qrDOJ< ;7Ia=1iA;d[hY4+9nM:)'Lsl^\u7KXt"_-S\&dl#k!^<+d1,Z`JQ",T>k*i3d.6qE@7s7JU1SrHY6I25M^)_VVfB.#-DttT0h`8jdIKDU0ScF24]rY/[(V;X=Jf!1$RXYH4G749PU^n=*e]Q;s2ZL[$Z]$7Jb!FW+6=l%#NT6n*KY$rgdDS8$p'];d7A/q\oCpc*WG@H/usE'M]CKEF:EI!)ju8(+A'Moq%_Qr[ekcAT#7=:K`5[BT_o\D6["!>VpQPS:ZS!DHJ($uq'A5eMDT6K*Q"r"\aKb,;#ZF3VS'dbp2s`1&M58i$MNf4m-0NLZr-cD@9L.3jk8fGjYFo*#rjT5YKg5rVmfo7;MtafE(9^JU6T',Jb!FV2ruj3'YZU\A>%,Qm(8f,TR57>@AH2pitt67gEj TN@O$pii9%tcK(-)=.?CHC[$7S(,ZRurf#d0]WsigdkE**n:P =6)Z5mMGsS;\l/@3&i_r+H9=_(cdJX9lT+Pmo:%sm*0ed;GEOWgoEQsk.JO+I*?SS0R,3qMbO_0(+;UZ*TPa=l6.9=3pHC8,ngm+%oGgX(qQ_0,f?qh2-HK!?^PWpPJ.?Bal6oF6@DdZ6tV4i-ML9qZb/jXKmO=,7=Hs-rl\,orUo$3Ktf+Hb4:trHT8N>\4!Gu$75q)8g/K3=FO^#Nr!/G7ekeKI?RfGVhP8DR]Y&4lOp&\D%1kMu1njn4G*SD$,+.(Sm^l<@k[ZGbIR$?^:1$."=^j;I4U/FHdl0)O?-e\-EXXBYMQEYd"g$]>HQ@DTl<*HEjbAG4_N)L)5H3V(JG.W`RpI%*@fNa\pO#/G@LMR`h`sq(mVDOOBf7@G!QaoICM,W>d4=fk!1B)*Dbm`[ZW`F"+8k?h-mGR21jU,Jke+oPnrrHeic S"9hSqV9CKEQ;sj;2)NZ8MCrsfIf\ZW#^4A"%l`TG46;gi9oh'l@ipLIL"#Yqb1kRI7&dc3?.4WC0=ijg(jldchJT!u7k+Kq!mb,%Wk_,*Xk3+"mjg9$\!)=!dLlLE7mQ'^<2sI%YBtn$o?a_NH,CIZ#M&d3itn?S*Ujh?khej^D0NY[RZo#e)0mcA*@6jOrV&0V_?S&K8n?Q(qK3 /;(t(5)=$6D]%SUU[s%geXmn(U4TqhVC7j^?1a?hHo[4W(`?0eFP@jqlWV4uRB2c7L(Otn%sR*d7OJ>2i<8S0<*>hGmL!jP#Mohu>M.H$S4\s98nZUc*HVPoF&=HB?gTR9_1G*K.'7TXfn-ML4O"I`(;7nQ r1Zi!#5ZqJCo6'6Mk`Cof*)CZsX@T^[:Z:J]GP;H(a8Gj?&f-%\u%nWRN"Nm>?Yh3F/nha6u&5cJ-r-DZ2oW_a_m#bI]=-Upoh\M"l0#J1nI@X"'or&9P[l1E@KP@7J:X1NgDL+WSbg!mM?pgUus@I,[*46W.;cQ;LWKQ.]?9G,O3%bQi2RW3^PSViojoC*IT8Vr:Ag.XN1*]&Sn3*Eo#;?!,I1rH2OHRJ@FUXdbH]ZWW'K(nNLi=d=YiSZAmSO.+6fZPPX?5M!:-iiM8aV.fD#W5WPpU#tUIC70t=THmaHDlbLIuhhL>TgcS0i.$3SDG45kccGbus+.5o,dG0A+pVR'm?OsTG4R\`Y1gB&&j7#Q/]O-PDf#>=jcLN&g"546(eke5.TQ`@B.0/:bYocEFnR8qD!N%Nb3P[VI.;6L#`!Tsf\Si\]-lWXGF!G;pSJ8[qn*b0oo^j3^uK+CWD@b(,!!R-he)nq0=2r&nGYCrSWuMP8Wq2)eW_pD_[+`aesrqt7.9LYWm>(9t5QX:uK2Z&Qb1(Voif!`kr"n\FuqTGQ:DR,';3C&pWQB;kqZ1=4b)_n[IX X(IUF8a3BtCf-T:BZ)]2@^_-W,Y@p3dln-BchE4"I<^B#/3..)+O,e4=AbcPQ>6q`N2sba;tu?-i->`T"-U9:61C=!!LGkCs=pR)JClPAdiqXFd7RB`H7s#Nq`A=-5n?^h's;)*CJnS>+Ba=AEDoFcs\rd)Dn\Hj9GAREjJ9!Y9p0,>XTP@G[K\!75]neN4aeoKAdC'f+daTM"M/u0m7:]4:;]]grG7+'7_]StF95#B!P!Il,$b13o\]CtTSV=D"oI\AN&dIu$@%?S^O^$Ke$ePL")0Y9K(*h1Z@J?q=p\4Xf@\=VE;=N,Rf,/'eJ.Epk4?HX(^k=CXc1&Z_nR<\d>R/h^?e]dTc$s` &>2U`Lp[(e$FACO1(6UQhD^9)SbkBa2Y3/8j)*4lt&D3Y(c.IgJ+EVrZ\l$VQ:>9HK]iUPsaFM$_V5icbbg1t89R:n#IjLaOk>@JPAD,*5dpA'H;I25$C.:\kFbI]:bG#@kh^<,&R7nA7ol^5/DUauA=;]rgFRr%KC$B!3l=q)l1]W]ho?\ie3!+%tcdX=SP$\&`1s,ejVStfX#tlq[AGO@?S5$]b9R3W"IpX*,EgoO/916dZ]K4T+@ JM#j's6Qe[OL;YX'sN;:(m\Ch_aX*iHQ]5*q=UX#7#^H=Oa_Sgt?&a:7ti@UjCRU]_n3\/%!QJ\aEnY0G/d*E>g-=,^L^%YG19g1^fJ7h;g=H$#aST\1V;Xm?GYZ;/I^:q+ola.D++/&*&m%"TEHc+13de"dtJI^6%C5s#s_%.^_'DDPiUgL6&(TW?flcQgGiK%38%9'/L5^b'VAq6X;oRdF,Rf;Oo5l?(+AH]h(*0:VM\hdF;?PGQ!Jg<,s* (MXLDuH,/<)(&'O(q+/pDM7fA$M:q;3/K.*3Y.jq5](^D'l`3[#=NYgh2"ecu\4-<;GBlBe8`XFs`H5_rWT.fE`Q;I3H8U1H'59Y.6r6mg=O*N/Vr)q9+_[#;/k?-sZ3*/UIW`t15S1f.@hn:Gqd#g\TP0*8R(S`HXfbA%p9M)!ADI+s&`]iSW=6-.%0-^q%KeG"Na@Zn/rl*PdSk-1s;f r4_V=]gc70-]-l^T99+.^FOCK4Z<;nlR7t_qCn]O'6:M`hqQ*P^I-,iCl<"8SC*TpiAEmE]?A\lM57+9"^,-]lGKdKpR1_;Q@p!=g1UC.ep4DWi86K6^;WmumIU2Td@#SJsF'nX)i0E?f$h,te1Ht1d:Gc&iRH[,7+1@0`ND'%dD:LUi[U;aSK!\B*NBTg%V=pQ-=SDKcN3G@QQ2e,YOG<9XL&-?C8F5I&a%as0`Z%1sqX#HMM[*j6p_i^m7H"G'0&E@X:@T<>iR%X1eC$$.q-Kf:3 W7Qlpf?NB53MNRP)$I\k1sAr7&`_([`q7'Nt`fKNJF1T];JVo&jW/[3m*jmSIDb^1Y6KrSWHn'I-Q1nl<.D)Mlf&9gi=0p7(XVZ;":CX'sD'iqu26>XI"7Nk[_ZY[(`L2X(L#*_=UE:\oN!:hhpPjgu]P9@bDl)fuoI;SSBScFQTK_pK&cMc$^b$rn@3$M"$s0X2HniGB@Ba^W i$`5=Ye@#UH564r^d"b%3gOroS&5fc,*TJFt9!sl;]=Y\@h^YCL/QDls59\"n1=pD\A25QG7I+Fs7Fig7ie,Zk5.P!C!\$tFe0q/1M5"Ip5':U6!AYF-O'4$>1hH.DmZ^f/CV!YB^RA4OMfS2[XX)sGQWL2d:O.)3WGkX:1Yg0N"-c"ZQE'+akd@LbAXLn_lNV[::\oQd8\I4I\YgbdI278dboDr__`@@,jbg7OgDfZA&QKY'9;H;hI3H#c!9 I".47ORnoV(fbesO7d;%.6IooTZPRn/tt9.GuuDKVs=f?9kjoZlg.]40E]%-HAqH8>lqiJ1EC*[lLNW2&\Yc`k,6a%E&QKk"=7XI;@bn+Q16kKO^_><]k>%P?Kb;[97BZE^=5EQ6*6FjepK>*%6:tW.W6.Ea]+6'.*(BG1lH,UccTrHV@_^OW4$mEm-h5ZDt12,aehF'?DZltk4g@^bS;#C`C_W]%`M4T>bM"1^`(=K$QhjW,^+[H/4hafc]u"s's8OoPHn/2&t'5kek'!g-J@C/KBuuBb$.S:bH"jV<_XDrq%H-_QAp7nK_)ss!$11ECh895epK^6"&kf_^&8eRd_\^]dQ"_&,.[,'/SZn&$WGbLCg*bY"9Sc-b+BSmEYNX+2M8jdK$"YcPI;Sd4_nBp_7UJV/'`)@+hj9h@*7aY)Ab98fNuPL^!sAYIT,OQsS4=MV*U/(>CW1!sS0.$*U-hjc=S)Df^+7:uKBsV7NFa>ORn\8-9BG"16%JMR#*qnAL/CI!9YY=bA/_E]2c9:3fVeU-b#QE]jh$,o@Tsn-nWBq5HMgaQ1W3](.">u"E ]N7lHV@7'GEp8.'@iD6*8YE.Z78DH;2mD^f]["tcqM0-`Z=!%J='B\&NUekN'/%.BWlt?]G?MGYcTbb[WgoTG<_hNoa2b(Kiaf5(F;5Qe>mHNs`L#Jjhmq020m4o[:,_M,?U 6tM0PjLE<7,1HE:/[AV)OW"'S`o&7Q(gNr$g"HU(N"4h#0W>$3uInCudS&"*Xk.K >^)d-6smU=;fD60S(Q3PL('WM7-'R`(dk=aK$Yg2Y(7="9j"4*)(/XLu2+'jgq2$(&Xg8J5i[7KZWLZS6K#Uk1CA=D-.UiJPS"H=J(rkRfM$?Jl,]dPNr\radSR0@dTa@n7rgb(Nd^9f_9o1(+\hW0:4C7qbbH1_I,,I*"CJ1=:@Ig0G'%,b+.`Ku._2[_o_t$I7Dn-H^I^tP!@4LQ\&/8uqBZcE$Q6]2&s#F)Nj]q-0FZUl0Y32Qph`C;%cf"p<5I2>d?`Y:X)1ePT$(lf h-4VMSu+j@>r?PZt0H;B@1X1!Ii:JQ1C=g.IoL06BhKn*e; q@oup4`qj'^8^XoZs-(t\uP.fdmRMPh72j@&u\%+Kr%#nD.'nuh2A0[Hi=bKQsTJ'/q1&i12RaE;#Um-,`;RCj,#4G&/hD.eX?,i25<_!EDMORddf$9CWe>(a]kU4Cn3X-n@nU$lOXoGji5u5rQkfRV)BDHI2mK`6sV2AJFY&jk5RYYAd>b7U_iFK?D^mbd84`Ao?ul:2+#J2Zu2rl7;(GX';T9@atP'O3OC/FFXu,?O0-cpBK!NIoEp\W*U- C^%7M"?`7,'>Q`-@'[#@gF29b876THe=dnMFF]"%LL!:0DgIP@kEuf)L37$mMErjU4d\CSNpjr\@BR)VsqNJ:0U^jp(6I#GIcmkgg,SH3H(Z.D3q-dP-9Yd5](9G9?QmBD[qbc#k&o>Xd9bDl3G>U$nqnmKj&^<91H+2Y/]aofol@+YJ9)1n);Ll-,$npket!%n5Kgm$@G)8.-7kP9ODa.iO93*>Y5kYSZm?'^t3PX-a&YmF+GT-q95n.@2b8rh/f)8.-7VuGcfe_)]!pO@)3Gs4lTlO1#nrPe$GrGm>MEtOFgJnth<_K(2^haGi[7$iS1K1?jFR694D%IXBj5sA6l1g,$CLO#qKr)cT;nst\Tf@Q$2k8i`i&>I]X\e7G:[1)?hIXrQ$h6?ETMo15 DWbbNL%>`Ci[gQVJY2LicBZq;s$piUYdR4;j^u1t*&p.WTfhmCEU$I]40*BY\'H*kWlCj(@[!_iB29Q'S>S"Ime7=*WQdT(Z4@?><*'<7][EuH7m.r7364,C08ocIm/*J=Xej N?MX*'-!YZmS#Ws#7(F&V)O=*D'*uhp);G9gj)77M@$h&lAD#YoeDjftuh@jC=8A=ZrH5&N4\m.D.-ni4Yg95Ah-bPF4#k*T?<&^UZ>1a<14Vd1U4d_P%L.sVY>b/HN-H<-E!k5Hif_Cl:gPG0d_;H*1cOCp+JFtp>RF)sD_6?)XB?!o9$!'];%QWcUJ\`MOjhd6k'_;'>+P^uL7#p&:j9,0h=`Uqh#F6g3dD51]1[6@]H@K\+30Rt%bg\+_)9FsDuoR43]3'NV!X8>$q[7>:&8j[3R#CY[s@5so/`KYE6"1EZVS3j4J1CjQgGMi9pd^,U%LCYc&;6q%?.?.3WG`m<9Y`WFD`>/poff$bM=brL%NFZl1TC;[<+A ]=2R4#UM9F=ds8`cLSf*gIe_u*nH+&_SK@l7C8Ks&K6c"?Y2UKKsE*W2:jqhrfn8oTh7le]QnkG>]&4Y;jro0HLq45?lNu_.sk\R_J!ZW*Z^\JAsS(Fk,M>W'#c$'uq;i:qV9*kF>dtQ\_Sauuh>]&&iIJt!S#RFn$ hgAC^*"+tud.o*eP&Q:6m!<_Ad+"[+f2H,+D3Yi^jBbBFfQ4tV7:9>COW$%BYb;f:XV;ni3W]doPtAa3D8R/0\e$=NUN42d&pOTl;MYh$e_$jPR;`UNcL5E'a:4W+*bRN=Bl&[3E:h(?Oiq-C@TDiq&&97,8/[f=lRf*l?;(:4%j3$-,i1KYiG4GKiTF#+Zh[=e(O7k(m^i03SRsp,C2#&-Mj>:/#g%3XVYC2HZLR'#3)[f`Lnl[Gd#UF+Z52U;XCOb*9>PYnTDO<4.hlA#nh>_e;A-mnAQiY8<)W@jIS)c[`PXj!Ij!p(PnNl$5\>e)LP!N@=l);mAeCCjONI$Cc][>_Go>G<9I '5@`anIi"\W+1+VBSTQA&>:YU@&uo%e\W?r1NuF,._7Zebm[Sb)UJ,4)n'q^G!8,PfrkZ;4M8)ajRh`Nfg?sZY8ia9sJYpAL>+8@[VRRr#iNG?L:u`e^A8-)T[okKAd$B>]b,?_kOj@6P%ld_-R)!]\$BTEsH;,cr742Z1;5t=rMrRkA>*V!p/])[Hqsu&(:#S=4F[d2hRPCDLSB:>GV3sq4G2jiBqbB-1[*jgffI!^ `4dmB7a%f9&I(?\Hm`H<%Lth4G^fDK-b=[i(N!='CcN+Mj\0;g%_spI#QX[a7Zd&cO:$#Hbjdu?[lK.#"p!$Yu'Q3"tb_GCBR9';7W?#fmql6dcIXb)\#(U;3NCa)7p*_?Sla(Nt6mW;Bkn#"?(?fh9N@Y7D[#BF^`Ou].8jr:Te?U2PpsMB]U,s05KQ,I[G;8+Y&(g0)4lr@Q7BK#B9X$#4)\5]SDb<$K?+Rr2(nu<Qo4L6l=hB;4L1je8d"[O:bbOYcBY&k1ZB\GRSb6fJ-U[R=,"+b]YOu.Idd-C)QKWelVgJ,F9$gjB.*<#WVPmrCHEOppgWAcq2aH@:\dL8*4)oTkRJF?kASG_.3Q]u%q20lsk-)knYjGphnm%>r?-9n&8ga1]VOj%@K7^g)Qu.?U&;#BGlb\;r8G,)_LFl_;]T)_AC,4]!AC%4pec.Zc8/q3$g+LIDDZg8!/`1VQQJTf\@jT8+-=/1Oc^e+G>.$'GdKSZ(Mh"fIe/ IMbTWJS4J8Q!NKRj9)5[0<'I8ObI:!]sH\2Og.>1:[kS;L'Q-rmA6EtiQ_(r3=]dts8i;A,OqHS%#HW7,95O`IV.\OkK/0)cT5K6XIVs`;CdG!IcchlYb_Js@aKHKQ,Sk1UB-5FV!E;*L3e9ce];q(=?53qf.^i0512;f>YUo8rS\7>I)Ui0bGlmIImql7[_q/A-`-)K5VAH7++fMIW8)tgRM(iQV6&_1=p$MkelhZWl>0BiKY#=B9"aCc(t^ TaE#SOcPcnqd;SE[.7Q2%+V!pT;:&jc4Z*EZQ[&k'a^W>T57>b>*`ZSalfrq8He:3q*YD,P6WML/k.\nYG@&f6hi5pm%8Q\X-.ghb=3NVH/`RYENoLg6oBM%uS:G\Wh@C]ntT.jb&$RXdVIfL9&,NA_`(F&9BSM\!q5%A)5tQmli396--9MVNkhY5C,);-`8Shqt36+%J;Q):NUN@?F-]^T/c7^EH<9fkjpu*"T@Hpho=n7\-os_1GMHJ],:E !5)MH9=f#:4D78bYnelrs982\V(Omr9;G+eRD",$Fbb4EpHZ2p8$QANVeFiY\jZ:2II`Z>1IW2O9j&!('3W+W]k;6EA7ku0Ri \Ol\aGLhZ[>oAA0GbQT?-)K(tnr4(mc=0H'/"P;e&nC4s>uVo:0@"!E1Wq%`l'AG[`;lO$jf*QYi]9P$)aALS"Fg3ueD$k.Af*UXf+a\MQ1AXNBZ5#e*D;P`#[7n.C%V(oU2e/=m4(7og d0.AiZolV5VDU1/D)Cf]+l"X09d+HIGb2=Rm.+$j;JLP`cc?aP:be)IT(DV)Z7J/;q7TdQrT7h-C^r-U:K$uKI5o.WN!@4A(Lrl2p7C"/g1i.(gXQ6o32TjKUog(+U)YYg:&Y\^kc*Nj7eZc[']g<%Q&'bE-)**s(]cIR"%;"YaHai31b/..$s+;m&qk+(8+u][!!tj6$0=O%cZgUOaa.9JDOdf[ieoT(5Pg.JFQ,h7"DWQnO&2FcBj19tQb\Tl-0*#Tgu)E5"]4qhG,T7EBD]g>AUP\!7*l&6Of0M@RR(3$rM#(rnnfr24.1G =eFUK/rZ4-gNjUr'i;m/PhZ`S0#&gF$SIW%;h?>6&d:udE`p]Lr=>l4,'UsV?LCk> Yg_DL!%oVc0g+2?10n%UQcEXoD0@Ujn8p)I+KQh.m="qW.(@'>u`"%*Oo`h6ArjPeOGbJO.[m:j*kZLegWIOn[ksU/X9,h?DdC0V*ggi,6Te>_1f-.3]\ALYsonai00$p@l@RX]j);Ma6FCgl:@SaF'2mjY;Ru2p6`FO6)b74#ao$mI-?Pl!>SMNI@Arn9'EaZR<8\TJua0QFmtAn=.1*!I)AfIo8CCU^+%iL(rjjtE>Q01TIjq%(O@:>9$?qR%^+fED\$&efD'(*@mDNZC,>;".)`A^0f;G$;CL"6"$)2_H\#Q1(9BG[A""^\LFn_\ul4hW)5BcC[Cum'HQ3Oh&))IF(*`PfOpf$.Emjp9cdCUkc49VJ&qHfR$_"h`S*P,Sl?\pJ&G3jjDemfQlrQ`*(!t6c$L#%Hug(;5Er'69XHB,r?^sc4a8GOa't'L?1r!,4QaN0rP!>:9V.3!sENBhYlU$9"c7P] R/s+MF&YJ]dloLkO!CElZn>t90V(I0XFZ7%cjj^m*m96k^aCCe$a'1'fcN)`c`Q_!5,'B]nPA!!;D$!c8]f[FW@)W4/(IX^doL'O@:#S8YOQ@lu@pHKaj:#k>F.5@8]m_O`hF5CqsF06f\T6Nd&A5q82GVDdSFeGrkRu@*M3=-/gY2L9rZU1J`%&^[07+6n`?VStU)ZM+HI113,j_XV9#jlgIZ$h1O*ge6qWIJDY8d?!3qUYS%[cX(1]Q`I'3 BH\Y==kZbUoFi$pJ`Jm5W>?F+/j0TdMrj#-Z"\m%OcWn@PaBEANh9PS81G1?>GnSrTgM2FqT*qu@Hk+th*3LHTpGo]kT&a;3[4S['2Q9p+?J#gZfWH7"EiOYr!_r^ufdhY7O!e5?2FD_mhaIr(N`D/mK:=%:KG]m>A0k)o2Rh)[Z#oI%k33^S]=J8Fr0k@:hcO`(-Adr9db/W]l%Tt/L]K??-UAUE"G+FPV(MQ,'V6g/r4q&t4YV&%o,<*$U$eO*c$OEm!-[(1`o*kUS&KZVKc$b)pC5A`W4$Nt._h@7%dQd_@cD;6je#M-?>IlH$TSqT)FM]X.X^K:KSl7lYX51c!=>X?HK>J%ktc1(/& d7>IkRMl?8ZL2!U1V.QrmKZV_!dd\hde58?5B-ME,IrdI*Bd!L(/#L_VX?%Ip8s5+@F08b(9b2M_@ej1L'qg<3+qR$1-PK^YBfspquVho-TVK]m;Hu-f`O1od^rT;e3Z8uf"mn*>b5FLgD4kB:Z,]4RnUbY`ji2(JC#X2Gdq%b.%@Vh S/d1/o0p?>Y*T>`U+ohQ::ZgMVMDk>mQ#%Oh-RHMs%J]p:GYhS-'i*qJ^@H@Qrd`V05\K>F1Y:G1a=M2n(iE6+f9!r#&R.m+>-u4N@@>A)f$c\QFg6q5qH/mlEUn2+$E`@H3SI,T;g/Dh%ep)6<`PmaTJ=c6]MgoOU_`d?Q>%gk>XK8 ;5om]?+"s.@TjD,&`Zs@nhK?2A;W#(jId@AHY!JGr2PKDY&V"`jY8lCkdIfcQ?/*W#Bhlj'_7n'Cf2R'@NGa2;F$D(C7&G5CNIG'Rs8l-=KgV0-#*N\bJEF4j*IBj@qO4ASql5ViM3r8laX5eEr^t@H#CBTcj(Db6n=J1OqSX2AeB5&PGWjJOEBWIJ(* DXr?F+VU7J+-X(%^Q"*^dR;0,fk*S;oGf3B"QSV&)7C1"nY[_r/g)=7Y]sj6i.jbO^Xie0t1X#nU^(Z1tk/gh/)$1X::<=-WCm`#"GTor'4q2^6\WLa,gqA=57f.A)Grc_9Zedi&0S[l(H.9dG;,#lm.:"FlDU!A]^i)CPS$J3<`"UR)[CJ)?caKR(m,g56+n&k$l$AAe/]Wsg4%)Zc 4(a=pFTk[gcO.Rh\0Kb66;OH]M&H<+@,lSVpM-OL*6gX-ZuY;6qrZn[H,F-`LHD?hdUnQ\D`O]WHp/4De+.RQNo\9K^VJZIYL?jpCub_?+`-[>]qu!>WkhAF36t)Y54!ei(9e1ZKnY,MRZRTI4sg(pO(fF64IcLVaUI3PsSp(Q_Lo0eBT\?EF'dUa*Z8P:Xn>n:66 !p0YD$QOc-%E*'2=trnfi_@-516GToJo1c3pJ2J/Im+?a%=,>1ZK>].#20QlfiZ>"O)Y^7T!N9j`>T=-l./Qo^Jhpgq:-uG*(&)&Z,!,nX<8'iCE>)CRb.q4M6LMHE%1!#`\8l>@E>7fS@/0n5qTJo']7OP4X3uZ+!7 >4e1.OC4*DGnl\9smlC.V`Au2Nb>&&)(m4$WC2f10JOaRum@IM6?:,hklW]pbkLm(oEF6$VMZ,O(%ju2>Cu^oKs"$<_`I8jrS5)5o8&^Y"(dU/8#&D]D%>nRNi\Fa!*?L0Ar7*EMH#u]#$\3ec(I7-Db("W@++(AL7NV,ifj+N>_+H^i%CQbqBV-[T"\:D<>d3[^L]p')8UYpPsi8!ftAV9n'_M:(G@M6D?hA(Leo,OQUqm1h+7qu7pD_%"$"oPqe>Ba^@hu)T%oOQ,1fBI;'cbt[`a=rr)pkpM6h>$9tCB!P&7Xj+[eU/f&Q@V*]tMig*p:R+H4;]8>TRca81IT^R2,%"kp@SWi73V`R89k.:ZB0VjCnaO'Q]F?Y2fgod]SLc94WA.P3]giD_bk+\=UkYZ'sn2n,?Xt.Pf7g,`qR7mGc"]8jM\joi-TW"+K\Ws+b$.f+TM6O(`B"-q[t>5"7I_o^/%(\o^[>%HbU_"?a$@cl=k2<\KDk!eFa,.pb2l[q80;Bni>Z_RZ>Tm%d493?)A+iF'_OFWo=S=HaOEqthQ24hGrfrir)<7aUmHYH"3^9s]jL[g94I -JQL4QuFsTM$Q+UVWGjTi&.a/Q?-TC9ag>]!-J*eX'>rRbintpl6+6A##pcCR85B>KeUnHjq8?7HGq;25gn`k<0$'nX,&.hJQA;QQ#Var@MF;WG/unH`NiWI58WumI9Dp`h(u[L7)8Wa4B2OOOM@W<7ocG7+QoEk'+LW>lboA6\"!t\*WLc>3mR9uiF=*p+abhCT'kO[Y)^?s(6#gCnA$$dI%+Qrn%8T[F5m^?Ub->8_jf(=N%#q6i.Q@mL/%SSuNFF

fiO5?;8.[E]t;G'S!L9F$-q5/i5sg2?QGDdUUJeU5up\R8i6/L6oX'jLe''B5HFK0?3L+698,j/rkZ1;sct`FR_^@!iotRW]'.r-cY+iY]:$#.Nao,-&`q@t\]T-^@tr65hW]_O=$)I3SKD=,;@q9Lj'a@>k)hjdAuL_+LZu8IW[p'c(-B\Noo/>Nj[l)]QZ:^MfRI]#b3-.o,IqMQ*C`islII#lpK_N+)o]"=Wrp$()4O5],Nk3_4!ibs^206M39N_I'0I)q^:"KF?&A:@1ENOWS*&=V47BJ#j,Bn?N4"S1n$Q?u?bW H-]OP5UFX^.4J>k!g`lXOXQH.kLfu>>pr]f.]m814_D9+P'(1Uo@JF[O09Bo3Vgp:Cl"7@U?;Pf'[1@s#YCesH6kAm/P+Y/D>nm80eKl(%V!uX"MV?pIuW/EjN]J$<:fgCoJrLE&OZ8+0WU?,Sn/s!a@ZGDN5@kFKm_XH.t*h`]0Hg2g8,==pb&'8-ZcVR2GH-n\s:VaFIbtMrdLZAuhBHm70R>:P$),\hSMeT8*(\urX8XeN!X**MrE?OAtS s/S]_uD](iQ`+lW(:/6GU31UfXkEjHsdVl.Pfa^5G\[*JT&t^^=r4,,><>m-b7LNQmO;PPfeXhPBl\=fM^-TOlaLZkF3tJ,P+3o1n?8ija+&!X6/VWqMmQboq4N5,HYP+UOV-Q,u0]t9Z-rE-5%@9FEJ_^Vl)<.0js[PDpZkq8D+s.`:iZ[E^J$PT8!/Wpl`:DXl2rln$de$'J#frPFrl)_VQ#,dJ"5cpP+CLrka[<)C$gC`JEV$Hs8d'F(0b'W]b>9.eJX-EYE5"`6 (;GE\?CtISFE8G+RZ8_pL@/g;1-(;>GqZWoc"#'d/gE8VGST$fRt1[+=9k<1[n:#DXjN^[M>)J3Cle'sgKHIEcZ&/$@?iO-i_OD^jMdT>=WLm*+<>9onqWlQ,LSGd([!6S4Zjn9<>a[DD)d+0ieU=.V.-Ju3P5[?k&#mk"D6;p,A)!O1BuSko;a`/2pu-MgA,c4>*@G8Rt-$/f[:X6).^4A,U5-#q5[EDW5`A96-@i4U7QF#nVhSqN>mS^s\bR*aCjcTFN/APJFcdTn:ii24@#MbjFfWLe9?)au&/KAF0,ZIb.h_:Xa(09DdN\.mG!o2^A7WT_?!C:T;RYN^J6BP0\CU5URWu5/KE[O(uR>ka5sAKn]l 3<&Q&J_,4%7,B?^;/LMA7(k9;-3J,JHLIA`$p*I$s'rpPoe6GKb4gddhn0-iDThd`ctRdW7YLT:V$!5#5)2`b]T"9Q:X/35]Pk`#n@8gT[u!CcSkiJ5cJNE)_5ZNns83&94$tbobu:n^BC8G?iA5;cHhdQVm5Nqc#mk_;D>B1tVdT[2rdD]O2fIg$h.n1Hcf%-\%g7-\)!#D[WVQ,7U(2tQ8AJ.3#<4;_q p"H:IPk^H:`eO`0k=r=]rj^h]p+"1elH=3F,07S8(!D#i2]f"3tsY>q2tm_]N[Ls`sOfrM?Z+t-`(JEWUeS50*%#dn=WKKT].hKjF2WFInf#**"#BoO&JbaZH'.hMa]zzzzzzzzzzzzzzzzzzzzJ6.^2LFL#a$\2:hh"u3b)?].'Y8l3imf1:d4>%!DklIt/SC=" Zs*DT)huLQ.#$-4^j-KNc!58Ql%^ZL*^`X0GW9B?SA!M02V>P=_o:`A6G=.OBaYssZc8)bf)[qZ1*#I8(EEd7:H$UplH2teiUtN6%ZcEeq6T`)-_""+$1u64KHT!l0`t\l$5P^O^C70QI&-1W:^m [t`XS--&5n`f3`mR4NSTSa[s-E/'[OdgHEg@(M%lc=tG5qMh(.Ti!&S:6Y)6a"p,0a1B\hF-"n\AE4[`_HdO/BT6aFcfr=s)nA'TiBGj5R?-[(FIpF;0lWHoKbY]%DaK"T\88C7ZE+fOGM+%pbOQ2j+:D%"[C2bIWXT0tTD&bBoU-6.lA67Sdf/gf2IXKOIA-?:KRjP0CE6a]Qp`J?_pANu?j$(Wi".RaaTI^c5_enC9JW/]1TRTuJ5d!^rpf 3jcJ)9Zpo'4CC:MNDLE?jd,[(,K?e0R,m.I?=>j4!!%rXA'WC^D+7(nI3oMbOg`:@%lM]SYTk4P=!k9!'M/4:IqG0Kf,W^k^eg'@TG^!QA7"c\*SY]4Te/k0EOE0U1BHkR0S&6te7p$8@OEu"XWaO]%>s/7BfaERH+s(,Xo.3]Dsk`Q^au%R$.P@Q"!m297GModNkL2gGN%CBA7Ho\K3NnZ!'L9nF1b_B]I>Kt$#'+&73^tNhIU1[ZCWgR_/BkGf*F8HGaOA)cqI$S>J?sB.cP#`M+W0bLAioW<=bL=OQ^,9j%IQ#7ChFSX\d@nnfuIBRN)5`S%I=E*k_&Au]]%Rab`l$F/=nH9B-ej?,jbBN+pBlRMj:H7DcssK)p\0f8HHM+J<#X!X&NAY0 p#Qe9!Y13-Q9_cB;//OH8SKR8S/*^F4_Jq]q\*),4SQ&2l235,GG"let-HU/M/'s1?8:8/N0R*GD=s6ooC@dR3&]o):@lMTh\>6WHdR@9^s@$l,D!`Yl9&:0V1E'+rP2=1HYVH^-1kD)Rt&tcI>pUIoM]i\m.?J"%U0&pB5@2U.g=RSU\'I>4jLk#s0#AB_N`MG$##jSda-3C378'!nZu(9p"ioU#K:bTuMot"(P+jgha`1#M:ZJ-\8EA:*DO RjPY]pAcjt>TR>(7p=J&i6@+%kFP@`-!N0Q*RR0lWJX'1&(3RX\:'hSArTBGXadgX%f9Pgkl#03(3#*];Si^7HL]a8':rf$$ndX'adTruSstFo=1<0Yq#CFS5V.VT^Fk:h8r1\LA%d!aaNbZ!r8hW"<8!$j724=lC#):%pk'm=`nJ9%gh%@/a;s&RdKeA @Jg)6pGRbCo$G-9FFfOc5fj.Orr_%)GCd=5r'D`d]0PigEUEn%'@`QqA:hB#gl_t1(3mb>M)W,!H'&*eo6HoS[UUP%oX-Xu*D%W'=T`Ce2#mE_+f2hrr@XPM])%9^$iWh2,G_M*e0QjM-V)aBnYY[5`"oPJ0<9lS+K(k*oZ(iWm+e?@`@h3PNc\C&S",mDA7%!0n^:[Z*tQo4er3:*(JiL\(!qeE27.U:0:pXGg#.Xo]?"dQjg,npouH TT!V7Y%E.k_R?IdMS%][&9dPP<)U\]c23r.26:,mB-JY-8#2#0U3F[=036(gFY4UXpWgb^XB)g7BlC/8Q*"KgQs,k"u\NCOS&FI\Y&n43PXetcc@G++`"Aj:6"-%07rTj3jT"Bn_qK&Ep;')2cJNcG@"lAEO+?-O&_rN@p:mAca-X3,MnE.),=I+TK>./F4%XFJ b*u4rE+&L)QqQthislO0J%?ei8hFtVDI=\>Uo`#P[COS(3pQM>m4GXrY;FeGLj)]mO?pc3jol).K33jQ$dK*_n3a%O%sA_X`/mF=JtQOQbmNlnk(Hh#>aie$:L1LEJbB@X_or_>r+s1@Jm?c":,$h`:5c&Z_XQi=lIl7QU3JE*<^++i4*C3kMR9:BDg2Yqcb>"nkS64ci4cTL4*`fc\;%./JUUcnf"5#%BS:!'ad?N9[OLNeC1,"?[U"o4=C31O3@SYIrmRm9 6f8!`h@H.SQ.H!cQ7@["c,9`WZ-ud+Z_-10K4lhW9)9(L4W'`7ogu--b?F"OY0\L6:hi0ulXT 4[SK2p?ondO=9(@#%"@D[J\?26Go,39ka(80Y#P*l5P_o^Qi2Q?Toe!sM-j&rT`8f,#Pm/"M(DqlI#pVghkf]&=gs.B3^mFre"dGWWU.oS4T"+iJ0p.2\Zp1e3F[(9gPeCj&3PC=PPc0TnQIA9H+6g"B W")-":T/bRS0OKj9&5j#muU5=f]+&@39H0PgKRZ0Q4c]#GpA-IpiCaN>XLdEa<2L4,CqH"_SmQ,!&E<]>=-:fW"ejPcr2Y@!/e`@XKV[O0C)!7CXFhpSL[AP@A7trF]IS0m-="=tP]]A.6A8ca;]K$Q]96+U$M=]HP4]$3_SD?9;skhQD[RjdTDOE%6NKi XAUft9.Z!H.aP#G&LcC,1NJ"NJ6^ksQK,&pO=2H*]>!LCD$$)Sh2=fTkC(4T[C@Pf;##U5EAF!Xuq\if@n[d]"3.K.9,5e/Pl=RMCD_MI]ks [qXRVHr2fH\#q:kn9h1$:YBkO#VrBB7FB5Yb%3aflNKD?6#;cdbn:IhRhhF@aMR/l3)@\,HnNjX62KEYlp[3s:lOs6h9:_794]PoCa>6n8oS`s^(#Y%OBroVpa2,&#jnRJdjnC"[&i,q-JHFGXWX2^;s7k:Pq3:,J,A:7q6>PICP6bEeJ?hLjO/ZB=Ng>P>4%%1[8_[F<^$\<+ BbC?+IF!BQr]`FDo8&q#!'Zo2XO#[?`g70hq`4qPMMXj!mjK2bhmWAY]#`NeGIYeJ"t`Nin\eFc/99p1UqWUT"8nAjd2?=j?ID F%aD;gLBaFn5*lc@-ik@cH$jhHSCF\7D#^XA9IF*.[05i@3Ku-6jMdmYYBmRr7k7/OdCSSW-,?D0`JK9qcChGL*&'pS6q`!VA7RUN.<+Sjtk4Yh[@TF=M9K,1YhDbNGO9h:n:i!*Tg$07>SM7g]%pZ!mS3i'Dak1<=(k-nW\*N]'W-CYcZeOhFmQh3b=BFjfZJkB5hWWB2#)Z@hV.j1e2F->GP1#2;Y'iNZ%G@u:^G+I?rYhcf!`IG'YdfKLE7i"B#$X3d-SH'F/LU,M54Bgq/X81]S)*BBV`>05FC ?Wi!k@D\N#Jb2=YL!5Jk4Frg+E'Fj'''E,^XpkC9G4BrFj/s\4o'_>k=Sf__DB9?r?%2(H,gXZp6GfD3@0QKEH7nIs9\]hYd%Q7UbLFgKJIfEH*baC"8hpQ>q$!XY8sXEsGiJ[311b2V&8OF:l[3U%K3m[A`"Y$"E,s;PXa$Y:Y)B&g_b_()rb9+EE,@>O\,"@,H[TeM^tfuhI-6@F,QDh)p;t+nl%eOlquiGe_In3;pD6VpJDHoK8RDeBaqf?4qnS0'>j=>0`T6jDIP0XIIN0Jg\(K/4j-DOJ_k=rl)S=2HRbWL,]/C>-mh3`4&iTq^G%o`o2(fTt#('bb\Sh-qVaS^(k5=sHa9 _tX='InI>[T6S0K8Z".'F16/o4\93+Ss#uIUPu,0Om[8!edBdG3Go^Jp;Oia^6c;HIg>aco&1@>ub8PIQSg3)d'WWT/^CK*n-'"o<*PFTOMW7sMLkC[N1fBG%IE7Ct8XaZ=:`JKE-C&)"FnfN8;7a]0^rR@J83)V'e&b?'9^(fCdc8:XeH]+s-2V7(FO0@TV_!J3IKmVi T2JcHZ)F&^qnh/Q1W]*K=[d_bSgs&#S=GMW(MoiH!`(^-^0*(lU9]%st_JjOr(sT[^W&F7$[*L["Gfqc>3'hu8a#Mk%<=3mtFuA94G),-CVJ&Q,jjQR6#/3m1ZngESrJ0e/0T<#m.]bOk+mJhETD2?uK]P@A86^I4C9Y"&U^9)`[)et?bnV)aDm*9Blh"o*B%*6lZBCqT:T>o&\!OnF6XPk?]=PQG+((f&_i0p<:>dWS"Y"1(N)9:@O]kAb;9 j%P[n/&K4Y-^Lm5HOroL!.r,aNqjs37]n_=Z+92uW4%s1[JjhCQVZp,O/,>p4^lo"fThL,(5G][2shE:O`B"P4t7$mC-Huh#WA_M^.NB(-sk+q>42sCW)q0%U4ta+]RVI[s"JSl)Si?A"92S\ AW`qfd!'s]EedLS4RCXcor8cQ0"jiAI[nR[naC/"a_kL?HE>+:r\VEnU@k8>LGdVmPrFCVH$e6A%mR5EFV1F2*UXY/)h7T#.LmZRoFG5LUO<]\fFYO2]:JVYR<^,7.n/hq)+Qn7r[OB#qp^n2Kak%9@?uS$&:%TlO3'RIPN%2oATD_YeE^Yk`KHU^>aoa!l(cF?]=5^<30:n-p;VKj-Nm1&EYIbBcd64C`q\LdW.k13AhOGO)jt]Br!i2QF)+ 2!XEIh@B%so.7R%slkL]377#.Z#?2@=MQ4(u#$[+,)h.S^?"qqj`8;hd19''B@`^dR`+*Q8tq(i(9.XGb-mr0krH+BDk?pDGUVpJGe]%2E;o(1pN]T^ZhT!N4?ne/I'VOHY4RE("5Z]F,.;W4^>.0RuhR9RG57\31.t00rS8b;L\QUnm6Hl0[fB=tdg :m1"muW3GfVn?G3bmOESdnEpisrNKP:^o"S/$9,'\YAK771k'_+1Q(W"?o2;G]FJaa5/6Nn8mJE^1TLf6_t9lTO2mY'?6X3;L%'C9l;iNC.FH&le0.=B[hD[4W8PkO/9?)%>/\ZhuCfU)_H)mA;TW>.1ZC7\?'ea8NlP$=.<#HCc`_XnjDq1NM`l0*2&1F/9-i8XjaI&P$)Y-CquX3Alfe m1ISU6-3a%gq^u@HL?Bt0d\qX0Vm/mlEA$FpUZ(0G7+5k.ON861NeeH\6t8*jHSO+$=7ijq=?k-l?G$HEHk'rB#kV9*QJ5JV5R[+=.-V8L/J8)C2F)QWYfO1iRl[=m]X?J4Gkm^nFsY+!kbFk[:@K9J/TL`ur.*"rk6e1+4-qu-^>"!RC^>9hkkJJ,)?s>lhc`0LH&nZ-@Uu2r1M_0TX:j\kW9 ,P-7M1@)1ST?p86V26Ia\kh"cq=^ZQtCO@_S-.\u=3h!n,>0?]MOkq&S>04)q4A&E1$6daQqYTb>%(QC73r`35s@)A.H.1`atB-h9Ml1_$.!G!`*E!+-h.jEEj`FC7lR^U\3Ir#r0%J#(UlW3C]] +?R`tnf/+7.(!ju$4q4$XG=Ug;3X:_OQ]Zsac_?la&;j67`k6ChQcf7f=l2i8]jc+q;eG!$PT8uP=Ta:cLk!m)aI?:5fg"*uao9aLjLS4FjO48D(5OQ9I_3QT-@!2u#DE;UA!TjfRF!=8#>YfCSM`r,=[>A`C_'YSNj9[^OO6[BZZVTeg6Ps]hruU!Xm4WD +s89"6b;R.H5K$h?-;$U*KI:U%jnS!SbaW/OGP&>?s14!*dr9*.0[7>/`hER!4Z_pOf''F7Hl3?lm"`r")cYPSN\]#\nM`JYBKJL;k/1N>Tf8'WKT$5H0D)>!RWf2#VI^d>]G:$@G.sUnk!_5EI-8*7WP&&/I-TUdWQInZO:i88/lS'g1l>9HlYH1f[%X9(@l<=j%C//:;qGBUd">V*fZS&a-)jh]!tpY7UOMMVJRb$Eg.;,Z6"Nn!CPb#b0?ER*Uo?oF,<%Aaq4p9fIGOA>?(o/L!_FbK[Li4)jr9t^>S@P-TIfN!D=P0neji=VUpsAXim:oI_;u]#gCXnRACb#RTt0ga^N=MeB''[EhtCJ'Qk$r,b$#8i+4Bq)4PI4%lZ&b4:sH:4UXFL:+dfkTjXpCX)-oupW*9hXB.c/jkK(QCl.`e-]3T[9NV@1ONnuSZb1Z\RTsM'na)Q[(@o[leA,[g'W%lP?;55(7]oI!\B$[nRJC-+>;n;+rC7 d6di6@-BY8d_5;'I]U)q/*be\+YO[-If7Q78jb9bhTNCusoM_C^EPECIZ%Lq(3]f\&YG9kjhI(UlDPs6LajQip1%]r1l/*-O*r["X;er.C!h"gpre8P#35d$?$Q>R-lB8&&]9U(6QBW!L_\>Vl:H-:t%4n[(TjGN!$aEuQpmk`E^!/Qg%d*a[Xj:`:bOgR$#QH9r20o]N(._2!Md59)5Gm-!kY<1t@hh.E+`u^6-b-m5u,U,`7mDdOV!l;X-j1b0EBE*L6l$G')'5jI10D-qbhqhm4WQVP>M-ho`>:VleJpd.bQqZg^;a:4;P8.:8^7S"Igq?%\ke]:HN.;h1,f8i%F++h8^?0K6,'J)].eO/$j>$ATge$[8HFS.@SjijC`]@ZBD_JI#+qs9,[mFrN>dlGai]Q4#`B!Yp*T^EF35Sg2q*rK5"LaI&#GT5_H!:T1h4eSYcCf>Wd-kD^_QZGl*S[dCC!XQP<4@nuO;WVIu"1Mtm)oP:+bb?n5II,rpO&CBr&MM9PTtW1UZ4?sE&Z:R7);JiN:KF(t2#SB\em!u]],1b[@P\NO)1p7.d-p*L_fD5I>2:Q9M4$i0CX:,pq=jF%,BIuqKO bkLQR!EKBdrT&&q5S#-jWQ#L+?<`M$+]^S9"P9a)*P`EutPM2M]qGE?3ilg817=K&Tt`moDGn^U.>4J-%)\VX%>^"2@jKq[tmU 9rZnUO09_9c-NYY2V3o!k_rn\#fI/..'DgRGq@2TCV7=L6I!sO/]-G(,-*nPg)&uf_B!d]ftbum.t6dZHL[hqJFNsgBbWLRiBuMM,%?Q$,EP$=V'2WfFIRX.6R;>C1?&jd`\OsqE[&&?6EjUc6QEt"15R\rCuf)T4pF>YGWh&1!r,5]pcAr=F$BlL#9"m2'>YXIJY[Aa%K8XRr4D5%hL"C./<>/k0&D60BXYV%.Unnnb<7=,:_TtY*$f;Sh>c Yd\QngnW@]l9##/E>l?A0./:)*_QiD\#K2A*VNcIFZ5+JRm,f^ODKSRBj\EltY\]W&ngd#o8U,p;P.iC*+N:*m\rXWeOc;\#P.6po;Mi6okgVLM>5&e[7_X0%d>LW-=pTsII7K+ng/L$;H0Ho*1nhkK?N/EsFL@MH=VJ,4]YLNpmH'KY`V4!a+"o?E\G76L$r3*P_1m8\b+,+>np_]ASW#1K\SC*eQ'_SmCX5?LT)St2Jsqt>bonIZg97EB,rZ6$HV[qDcL=nd8.g>h8Z##P7=BDe*V"TbC)$D>0%[^f>_lLB4qr;%BBe'iAlqi7V64d461:9ai[Zf\dbbj&.76)0R:'>/J#nP%&&\5:'TJBjUQGDSnNplEf_DAS;IQD!r-[0bMX1\OhFGh]6Q)DNT@XSMdD:4em%l4hM(aCrZ$AH!^IIYQD1Ch#Feri\E)fHQ[QcbcuR #,EY>rZo*7%>YI4MIsqR_oMnCI>4BbDOtYM>:2<)qX^0SM"IVrq+R3hb3Qi^^g?!P4I@[QN9Z*%[d:t/J"*Xt 5Z57ZN.DSG3UOtUU]ONb3-58klDE[X8(^>]9R)"_N]S#%5MeTmRWLTqZ.YD"&+"Hn"oA?FMd)E[o>/QgAD.`BZWbbN]`c@`W.)F/,70iTq3fniZHAX4/&*g$I"[T=G9OA+>F(aT_3XkY`OO0k;oU_K:lY5em+B+aHc@jBTA[6+csJV+IKA:AXV!iBK"?L 2?!V;E#[m0fs/cpi\e4?TodKAqSg.F)!8lHWYc:9VS,Y%ul2bPPNXPf\tNJ4lIZY08suSP/k307s]E/&tqIsDe$k'MRfoDk;X1;o%(7ISd+3#t%%-AC59AYYNhb,6X3Ei(T3)?`<:ob3Cb$t!j!/'TQq/dK[`4_q2)C>-L!8O'1ANt0Lpf`K2fmKOSarqmatB#@"EaSOK^D1dl?9I'2`^4?*E@DQG`$+m($*]](2UWWQ%E")Gu:nr gBOM,]E:4km(bC-LN7B.j,U>YD509@C:UP9gA,gri*5>]#N^opmVPO>Q"n9o:%>8dbaD4SD:m3a6?)M\,H65rO%.gWVuJAe Z:.Nh,H6^K^?fWA[m1%-N&o.J*ZNQ$Z"s\l\XW0UT,7JcfV$DskUE86+-s+kh7W^J`o"JJbV=ABKfa`0qX@+l@L$D_Wj3"JTB.gd%F_$ueU0q.melP;U/J_P^TZ"Dn,F`H"CfA4a#0Vd64%23^_tt:(76iA<\ESEB8DY(QOWJ1#(s,ZQ1`?#`NLqAhga:A*TP![5NhAfDfm-_B,.L%EGGcir_a5I/DY63U.[lVEp+5$uR(3,d?a:"r+nZ8Fui>M0]t-6@Rm7so*u1(qoCjOCY:1 %sHp61Y=3E_I5tpD!Y5bW29"ilt##%a30H970]X6D>:/!6>_j1/uSj7GHpBNa[j,D#Vu$(bpXe82[.[T-KL[0V4YPDD*F4U2nUIUpFQD0)qG^Z_5u[3*V-Od&JG;$S1N+e[u2E.#-WfdM2I4!9YT Sir,4MO=2De"L%>:;d++u"FPJj0'6DKPc6'9fc!@mNh-[SbnF)l5kUt/UC$1+G5G%d\0"3b\Ur/r`Wm0*lF're'ZpY5t3"Z:;p_W-S>r:^([\0TWNXQ`nV/g'\dn3tVN*iOZc2q1sB;SCKRuf5'1Wn6bt#7;h/E>,'n,38uPXoW%!;0'7h3Q5eq8FI0hi9@\H,/3KXe-*,*/= .j0&N<3Rq5Uh&Y4jg0h:(CS&+39%1Q.'jr:'L+:%;ei^I,cib,Y>eZN7*t4,DPP\[-L2,3!"-+JZ9FWWU"\gkn%=Y_rTC?F^CW/`8kD$&E5ZbPk-`pMP2a#)n1Z\J*7H?penp((#+)5EGglVRlQf.RLdKh]3j48e^:Cebt&AaVmqT.iu^VG7J]([ck.q,&IWUl>nraWT?I0m'mWqgNq@Q!:9rPqbu469P4su?i5;hT#C]cgQoH#omW^bbRFpA (5AQ9gNT")9B4EM1'h:2OTu6E-=0RgSqS,3!!9aE<;76U,kT*I.=kEMTm>3%e7iiVp.WS5-5HId?ot$T[C^=641N/"O`,7"a]S]nX&;&5'X&WpQHuOm`<(mrk7M'1%t8kn#qTnYNKHCSSY/'1/rVV%me?5Yupj3&Kop9\kLm,b@=gkNI&B'CJEpeB&>d,8B!jdOkIIF@L5'B_YQ$=)K^9t9mhVgAA_s]cZ4GCZg5DNgfoiHg!WC4O]C o5/L.E!,^T0@<+!DVX]RJIkg]I,/b54?,8Zmd9:"q?#;%nfI^W(k)`SI,XL(K:1]eL[@%=D?$Uh:&R-6r?f40a6`iepj]uS49Vct'<]:!`]ijrnjLpp^B-DqGd$cL/:D]4E+A^B"q_mRqs/SA"EIPN+dED:F3/J\/CFcTlj:'#?f<\^pRftI:\osD[OB>>Gc<^&?*Af6>>,Au+/bRt#*(jei4,nh?3g&gH;aal>0!Le>L-Z8@H[r1\N5XQ=.)IsSqDdAV8'k?6'+ln%Ce6+b`pK#gS>(ZTSj\p7gO_-JLfkLo8UepD`!aV9g#?C[N224(P5Dj&_oUh;k!,/GZq'mjp/F;W)pQJ7Q-6f$qaac SX*7ijA;SZli0XT]u,,A$EW=8o99:T]'l.>+LaC.p'EL=P'#2dd;AVPL9qhD*lHhBH:&o=)Q$-[5u0A:IaH0;!9u:UGS92%`p#I@?1`TAb3A:q!!?kBHc4P?M?ICP.Yo/^1K):oNc7FL*V]H>Q0JNMi.9!)\#NRh(38oQko+TTGGk9HHRXaa%s!j,DmeWDgBg8,n';=QZNY&l'CIkR?$GYC=QSZB%hY1-##HoLsD!P\,(qnV06W:ec7lS\c`$ n7/(KfdNDu\bU0\+r,>mH[.dI`2`32Xk25F@3dt_1,^/>54Q.qD1/;AXE8`UdqJ$[[d-fe%::W+AJTM'7M1*Q94g`N:WEg 178>PK.fG]I.Qg@eP]^*OQ:HV_OLr1gTNIp/nB+E4RVW>.\.H?Fp8Wb8srkT`%Qa=E,_`=2N0a9A_narrNjO\5(=+=GrV5RCV'&HK4"TL"C@+ppe`otgW`7Hhho"C24#_lKk.Wb5Ko,`A6Jq`IGYj40>(P5J$41!0cVJ!-FnsWF-5XNrb%\N0O,@,)pmij93q*OWiD78CHiV*]p(*K"Z9]J!>2eE:B&[!,T@Y#9_):6DBY(E&.p$g"No9l*CX[2[I;T#[3>t3u<=,-[oe?/Xh$Dtr?qT[nfidKu`+sL,o)iZt:k[,[>fj*/Y,l"J"\=E"\HGq<%gu1SdZ+p'`o'_ppVV)?4i3q@oK6LO9S,3i&0A>dIXNH0q%WSiNGn>k%!RghU2@R92jF)"4g">((M<(AU[67& (jmq`:lj#-Z/@;7cq%`MqQ<_7:IH#1*ihDUJ07orFX.OZ?\eo&*Y.+9f.H``dNbTQ6fIUMR24O[s%7[o:@;MLG(e?CFgRZmnrhHn9_VoM%0Uh)\)UZru-O+`^e6t)3g0?niTS3Aoq7:gm*)20KBYAq)Dd?jEQOh#NIlVi0OD!MK"K9tjobV *5X1#p%J8oYu[OM\_Jp.UGm#[XCige/eFqoj7^OMNGM@s0T"A#QN>:jEcSnpNPC<:-#%IL2Q\FLr"!s2WY]IR(L=]luK>fJtS9b^M#:Q"SV'hT[XlEXE]6,GM^*a[5TrDK_9AV<6c^,pWCnZ4q'T)>uc*DjDI[\r$Q$0ahi.?EIU*D0ML_5H 4:dadclj2%Br\<#qn1r8$D%Zq2YM@d3Nr6+B`r,qKNKQ.o^=\^P_cA5L,2+YAe!"tPCh-cDt9A#J)hj>pYb-,r=r[d+dHG7Qnn-IUSjt,?`J`qh'PI?`7^>X6a[[%BZgH*>=3kEUNHiQ^+WWFVsOO%(,jEY\6S7k=O;8D@WQ2Gkc_gSsM8!XfP!5c+4#iJ$8_R/7(9(+->i@*hoi+%n?Xpi64QPCc#j]Bl+P+^Y=PF!gR8'F+(:Q?S eEgI]r:c!rMi&aJp&Pm^5S]2c*>k.'hP+7*g'Do9sASGZ:6\ATU(P`@@m,r7dDpL;53QY#Hjl[h1b2;kr'pIbkj^Q5W!Ni=s*"#1he!A'Z[:L#ZNa/lP1kbC.Bfk=qDV2qV4cmja4PR OROo_/e,>4fd\4?[YpX^HHM5L*@tcRG35_VlFuOV4Bf$fK;PpDd&'t)`p4VW>GTgS0H"on]M%8]tM+Z;p`7&oocg-(AbrgbStL1k3n`QUT$6QWLUtp]:[K"UN,;O*$@D$ZP,^/6aU3J2RK7dSX/q(i4qtjD](nW%kju+^\T#FB]lNhHDch]k^5[c*Pc"boPE=75upuh(eFmB2m5IeOenH!l1[Bsn`H(N%J`pB5&\iF`C;&c,W/7l?BI+6R6,L,q6Bb3SW^'b2eCRa/6k)Y3%7B%1+N1jc2ETsLS,aq1aLH>@k!g6F'k?JP9cs7b&%lkC6M$Nc_`ApY*pr).Z(t/sdL:'VWA"^-8`V7@F%A+n50l)_PbC%q[Qo;bX$Msj7H\j95Cfg>_0/ZGdR7GI^c&G=B3pj"B&./\n=maUWtCOUYoh&k@MSr)'_^uS$:6qOm,V%$7QV]r1.bt@cmAe8[pkOQ-SZb*;3bs1LQG5RK[`+g>Fn-849(,6=Q,EU'FuJ9!9aI=6$'iZQ!*HN=#^\hCKrT[S%Yp H8jM[J]gWh_NcnC4_#.b+I?ZdZb_f@16e"\*:u8J)3T@<;F2\p*OJ+B.H]^Udo_h>BqE%-@e0BD1`$S.;!\HJ/MtQqk\E=etJ_n'd`)*J,9g0WK"(YXd9;,^6iC!+!QXD8hMq)&;6OK#0mR6"1]u(mF"fG&=I)7FL,p`DoV52LSNB@s!c).2]oE6&UT7s_-]_6K24(PK5nEO7jnN`M7M)gZ84UR\[b*%t?$G5GpOW*qni6>]LtJ)iEuX*56Ij2iOCliW@P9cD6o&G:WSbe,<0flFAl:7hDo4&hS]NpL4A[IPgN6fC(7Eds6Ki7>?cp8kQ `UP#-I]VR_;B[mK->jk=Vb9pX%j(S!+gXHjfQq\HcIsPA6(&cU.aO.##Ob2jEGBNJAnki/NU1-5<:.:,P,)A#T]DtQ_I-Y/U-WPp!0".EScH&faZfT\TQpbXTcD->2CeM=F?'OD74q6+McCul\Zq%LjVWLTDGFTM^O[%a`5Vd _)@";4:amn#`XdY(An&6T-e#2>nJKXZ@T`mUN9Vo.D]K%`*=ClgbBo+dRh!'p+QH@&$HI!dllN'")7DG?gB;3LLS?T0Z_a2GJ^!Ci5od3V/nT(/f3SXtEeXfdQTK/O4&B7rdl4YDNZtej=V.^)jh(B\@G,>0+@=Uh&K7Wb2u=O3Qc`2cCg''XR_U:4Jb*3V\Fc1P8VJ/ulA&?eZ]r'fWOd/1hdDe,t?-ZF4A$4hiEKDrm+d](g[Ah5\ed#$YYgnl0q5JHR[5DR,6'Kje*SU`jpm>!Wg551>.S aA%0`T"'@[,uj'qfgiN)"m*4kc;r^U/%k)ps#4=pr=GGJpHZ1X;-7Cc%!Jo>"E(MIqWd$+=r3MhCDSK*3g$heFcGO9Be+BCi,[?d8b$>8([+uF:pX%r't+.%OQlT>X4j\\@7^QRe.%%,bsP!2'RZZP4R)Ap;qGj=ltSAlMIF$L/GMtWH!&#&2!QCG/F+h1a"`E[/)JLRYqA55V_LjB7CA;3H-E/Yt>#^t_klV>-Y:?T*k)Jt6fT:,SG,PL?AT\5Dj!HW34Z6Yk/"OSa58P(Pm)*_r^)n^b *)'VnRfW!Dm)Y#i7hr*Y9Wj"3NFX+#o#T:\7p4,n85P*N5nl&n0Eg<4L0lZ>dKraTQt4&YfE:Rfo`a#iOK'XMnfOX#kJ!?D"%HY8j_t<(oh2dZtMu+d(mJ,$<]Ku."DBO&l^%fFES0cM.L3o^&a=Vk>okgcFm&f-*4,$I oP:m@MEh<\Jq$,)N^r4IjPU^PVrZ5DT&MQl/9$cTWpTiq6ia$LHDM%EYE26mt:7\j=j2Zcq-`(c6Rl'R:ja2O_%]UCC"o/EiRe$SXM[M;cU710rM4"_L)d+gS(a448Ke$+-6/%\;<8+=g[>+A5-'_p&ngjG!^M,p<$s3h>_0eKZL3ip;Z?b[B7lI8b[QEa\92N^MhY^\+@J-ZntOj`&Vs M"\)(B!NiO1mPDXpq2bGuB^"R,?g\<6]&d'lH?=)(8aj*A?rrlITP1*T*2tJ(2D-?_Se]pi/\Sk]3fH'5Cm&fGjgj(.[&>V4[@rDhM(eSu)pbTOo/3]i]D0m8&&_6DZ\3+aI(ht]m*WSSD+q\f9ph$eWW>isjuTTr+I:b_c10 +9<;Gg:QTThAbe+l7Ro:MI%S9dR.SS,So;02l,*NI;^[+VO:Kgh-&2^f#B)UKn005_^Z'a=TqPr'g.MLL$o/_"WJO)ENI'ZF^IGku\?+B1al%O"lkFN2pr1A5mG$$p]Q[+M?Y3t?dZ('j<#H"6]ROt87f,b]ELGOK@2g(#(0BafhHE`R&grBqZ"fb=h(rHe!DMR>;q<3l^\ZqD-HP\9FV9(:1dYV%DMb\`'irl7+/;(jlL+m`3`S1udc"&93`>q0,HE:$k(OY9=e(HM`."3m)To-G9=AJK]$S,eu/O0WDC9f>Ia#F?;T+INU>^AERI)YD9mIUgtcPjh_'=h]pf\e60Z;AolF`H[#70-Wu4_A]l8a.Fj84QhKJ=^i\T-2P631`CNHDO^:[`f@4LaZ_>4+N_f/;W-'E+jrsBL 2WY"0lPF[kBn')IDpY2[=+j^@pg_Al"&Y&B/ZC'JIKE[D]mikiE>mOg%cdA^7-[Lrk1!49Uo.9&sqO`!%M997fA:Z6gmk&`3![qarY:OY*8G_iRW913p2sEEufG?S]"_kj:!RX=o37F6cTE".&.'F+:e@St^Qb-bbj20]aGab;B_"_%-bCcY3c[mA+8A(GhEqlV2,]p`a-VbbiOU829-tWFlq>8?a_/IJ-R: ^LqJ2)#jd/QqSDOu;)^'@5L#n.g?$,7SJkjtd7R(Yfd91=`F#?OD8S)P2B>F5!Mf0g@WKCnUs>h2'=cR[)_AG_sH&>Xc@U^b(U>+1qK/"ZL-%diRp_r9H`]60UD[#3UODDriVkeqoX0:3F'3f"DG1M.B?L#1"Ip7C$9apd8h")ru+rKO$p"oW'2J+kVXa4WiEm6Z`i!%)'I GVOMLo/19c1Ne,s&T%7G'\R(/Q^)rY3Q(LXT.K0[mZ6QFCV(`(^,jJW=ScAEG])c`*7MN*$9k6j!6#'90`?W&7QZWE^;@Pmr\+T!*apXKI8+D=I=K!E.WXnDq\/dRqj&6:HMOnFP/'/%Dq`:'cU)j,]27%i&*m#rfYaWers>asR$I]*l3S_=M1B08TbtpJ]4=Ot2mm<2L,ru_l_YI%Gpik=q!iJ@RMlLAT)?=Fp$f='rD=&o6bK`R9s0MBNf1Q"!TI(t6#t'2hO".-<03.gCB+mku!J!GsJqkD6Y&Ye/V+HTq-_23@EkUunY/r38[B#hBCA)MrK$m7l*W40'I QjEMTUDf-/gf)U$%K!%fOgq8EQj>b\'9^C%oc9i:-3\`K*/pK&Ua#!GJS$tM['!-@SM*p.Rbi%V8m-ns4k)UO:2Z,KSK"Nq^`')2:98#i[Z*O?I:.NEL>6_]gdAbmq6rGebr-NHse%3Xac7(_!3)6tHDT"OIko$C:rP]nS(nKbg6)A!"rO];!2C*&N&EZffS>jiK-)pljE-Xj$Vbr@@nJhrj 'r;Gu[]/bDs!PK2)MLU(*(H7nZ]B:B,)/+3o#6rNc,H@*TMN;!8LnSV#[][98mn=/k5U2enrWV0A;Kk%fAJeHn`Hl`A8DX@I*KZY:(:X;sq6sS?X;aAr5@7qHTSKbQdq%#0Q44UM_WZV#n@m'$Y?B+WY'4;S'4r3b!-FrU+L25lkTaZEYlW4+/glf9pD2:R#,iR[O_F3IF@\j1P"EYmV:Sg,?P_lpoHX,moiV>]"\lZ=+#iD8M;_EkAq_la+U DEhiEk19o$%[i=I9)U.6)S`"+Q endstream endobj 12 0 obj << /Type /XObject /Subtype /Image /Name /I4 /Width 266 /Height 222 /BitsPerComponent 8 /ColorSpace /DeviceGray /Length 4750 /Filter [ /ASCII85Decode /FlateDecode ] >> stream Gb"/,$b<>]&3^i-5QrZ?_$X5IJeb@p"Y3Ec$<5Y.+>CT]\3=$hmXNN1I-Y;$GF00k]O!fNr;@bCa[Fsn,C_bo[]L&p5oV`REGXmgd>lE!S/UrF'/a:K:sgjI*s,UT'4V?jLbV3mC$r`i"V!MsWK.?TKSb#H2[@nY;9unlO.]1r'5K4;:J!D7LiS&$dD+D9Ro:$WX$]'>R$cP!N@>5jO5Yip'/^kp`o\d:L0$&qHmWS\7n2%RkC[&Zcb68Y#24S7 NsS6C23n^QXofc2Dp\>=`+;7J6)N)4]bZ!WII0-H*$u@3F6TQ.NenlX3(sT%g="6Y"k%8Sjqncl@U!O12VnSiiG$)qkh%(9?`Yau8DfqTLD*`:P.=%0/7>qCuN4$MEq=W(R;*3+hG360+.'IKO>iH53d47*Cq3.UK]32hD_'3B0]kie&TH(>6I%5N(/ld=3Hk\$*r*)Ah5f1-pUbr!cjHpK]WOoi[r9\(R0,8[1%FR2D b19ra$V95f27aM:[o>0VeFY7qY'8PPX]@Z"^r4re]sMj9-F;ZA3n.]#G+9K\Pp"f-uqYqkgXH<5u\6%'Y]U+arOZOdKeZr=rnn5)f[1EndlO3dR0\1uB)1eJ0%'9jl3R%HVCKDS5dF>U"QP)4M0An+Lsc=3H^7Yh@2AuPsCR.q.8(:BOM7),b?OGPV-)@B$H6'%&@5sB2.`4R#1J;LHQ6KDgT180GUA3s(h#>BNgfFS5#cWR_koubci2>sdk_Z6/%"5ng/q:1EO`!28"os(>l3o=;MiEaQ9LQR1'Dgl$+#H&_+I;QOOY7@]H92/%:Z:cL@)[M?\V`>lRBItN&)7FZC%LLauu2FHK,F0$Z6`;pLGK(74T' jpdnM+%,3/%#tJQ=l\UUV^!D)E/k2iAYCrZ+ZYdaK+)"Du,BBsp0nINdQCc`Tf$.fFl:,3m4)&=[Iob!#jP$JpBig?;KZUO`78G#3U@dKVr%+^&L)FV+;>:f+lk+8Mc!-gEmCK7dG]XD#D(k^5pf8=&f$%#gQ"KX,`I!CmAVSrA^i[QbfbuH'2hI4]kqNVG.a60`Z6RgoZrBfe6[(g5QMP2[RV2jF\H!-V3P39$4qFRI#Ej)D9!`]X2ck@EdCPUm'5YZAI:]RZI+JU9-oT-bN59TM/Y=J.%W,0`1h&S\,-@m&^'nJ.rQgd\M@f/i!!IL-Ga+;qdNgu:Iqu ^Z/ZQ[X_mNmM2V"Z-PUpm,.*6<>:(tY4'"V?fJBmXjlqib#(Jr>#fWt+.r>O+7Sc:CfMtgN8gZ0I3u!WMm&S/OWpY\`lblT:/cLF9AZP=*91n':-Q[e"if7[0*e3/U\4obH4Dp!;*eCs$M9j4<:MAMtG<>jiImW1n-T(7K4$F`NImW1n-T$9lLW7Z4d.li3NF1J7nae+bIf>#?:JY[%r!A@T5G@W=-T$9u6K@6)B`.c7NLufh.%/,Wl8l=`7! 7r8/ET`iC(SSL:Gk=[?<-@b@Vi,`>8"0-ShL<_'=(4I=InK\`LI:S*H3aId];n2osM8,1A5:iE"cT(&be]c,na4o2a&2iJr#8$Hg3CI3Cq_S&P5:Y21.;A"C&.,9$#@aEn'I/C=K9U*m;a9sCm./%ORG]Y+0'd[Z$_?>7sDu[O]V_!F+_Oj)\!1aE3B$(+Z!mGPHYT4Po$Pd]pPIs&UI%7E1?BM`Bet'NNDF9Z*n\m=XfFCk- %cY"qKMo.s^l2aroChO+MUI2I13F'm8,%i3hR*FqLiKb(6"uK[PZCQoK>>Q&k45;^OOI^P;e%%Qr*fU.,km9kr"m3[eFS'Fs&4^r<.M6k9Io-%2%f2_?%>'_?0A;=>r^>jtn4om]G:ncJLn7^;U?V>o9(&GKX2!?\)ZbY^`]-sogcANnW&q$?K@;3A6n6a3oU=MnaMdas9H.q+nM$Zb'L@D/_Kb@H:1^0H**<;]kAFuq;Kj)H3U/$&p@X Po_I#Gngod2YbVAd>UZ1.*F5#RmG`eM]D_'?6(o1I\ro_5$g8TG))YcqS%ug"YOtFq'2"rZlPYn4A+]iR0aP2NT>Z2R$5QQA ]MbVre0;3K[YFt^IIoi%WI0m.&85\V?]+cG?#Pt9t]DAPC:[0nsE`Wjl\As8)+Uu]PF)WGBcoF^6>(`DY!5b*,uQRTq[LGW[eg=HYQF'm"o5q$)u\'B\VE5Yrj@=VZBd0U;OnnEHJMdO5C"FKPrWR"/YRU?k-#C7W<`+&U%a#/`eNCK;qU_qlnUk-:`"W*+A3FOR3K]5@l`<_@0jestnShAS(IppRPOb(ohS532pRD.?^8)hAKXYBIlA9LOk-Cn4h0F2"p5O>k;0sd9O)?3>;G:Rjs%)ODPsoZ)4DQU5skf-(PZW%75Zbk^gfs2CFJGUVZLm& Wmo"n1]4@nB$#bjr(N@)?VF[dD/hLG+4OVlnT5j'APL9/:/W'=Vd:F!pm0g%4mT3@0cZ"$_^6*I#.kWp'6qq#:76R7Q[?q)ecn$TmuK.0o&LKG+aGka9r21G"MJ,sUr4#U^CH9XOA?P)4Lm&g7qO Ul%>9aSXbI#rNtdQoJ_-ORg1n-S_@u19j;Q=Q+4]nG-mne$*"&.(;l`j+3LmIfU;Z$V$QkANDX].dk65anaC;88OGt4krCO)HGQ(/$!:nN^-,Sl]mcmeLDsoW1%FY^L2$+.l[2IfZuUC$*kJ'27T#a1*ZCk`UlDJipm([U0IY'R:p-^1B#YC1ls)1hh7k>A2P$H3b)`Q9Ob5BY;8&kZY&0)<..//!iSC^CW38?mnke2hMPN5KjnL04=7!80m9 _CpLpMA;46]&PE(c_j6aFM#=>stPK@%``0;r&aC7g"$KX3G[S#%)d>GT\s!&4U,RAWH%jW[Gmd5nZk<[@8p)oFs9MjS7IIs^q'T!;hQS endstream endobj 13 0 obj << /Type /XObject /Subtype /Image /Name /I5 /Width 494 /Height 285 /BitsPerComponent 8 /ColorSpace /DeviceRGB /Length 9696 /Filter [ /ASCII85Decode /FlateDecode ] >> stream Gb"/lNIn42%Rt^kSi0C1hA$ZTD5Vk5+D[NpB6QD=9iXAD#[pj9zzzzzzzzzzzzzzzzzzzzzzzzzzz!!!",;FH"lXH02?QM#/n`.$5A;I6O[o+(g$i-2KlY/H]WY5aFR1W1-Im?.DG:CO^^rKI%iIPs@LT+'tnlKcXf2E]]7#..`XVc^r1g4Ji5b\U[L4M*mJ=.W&apK_'ZW:3r)6q^-ens9J!kd*m(dt%fe55PiTXH5 &.C[mHN3Q?&GBARN$/G.V;?Ti!Y^D<4Uf;CJ+5_gObsuXWL/L7"3c<2$*dY]oT`V2`&"qMjEbi'=X7*]pc@r!L-m;Cd.@%6[5@sRJ=ITc$A4,b(.""GU0ZtC5\J$"+0PX+PQEKl3@BFcTEE[Y&!>C*n0.+$d9IQk[4MCMOuIbq,:YN>p^Y]nn^`Ep9S`%4+)$;r3uU1.e,jS1S!?1>c%/N\1ZjKR^sSt#='!q;2@'+g]+hY2"Q6T(*)XOlJcjDf*B+hNcJ6uenOn=7gB'0oP$N&N!5:hC`"Om9/Wm^71L^j`)?1Y8:2^=T&2Ycb_rXVrGTX]BAntTNDV2BrXUP:JK4l3@,3*W)l`P34mNm#Q?dQ3uH/%aEG9q!4+'ji6#$Qhk!'HrS(WZ?&]b/At/TFd/gToK6H0R`[m[q>`7f+'\WnW`6e2\t9!3s%$a>iO:A7n!7#LU07_*:[LE%s3[[M)++=4W"gm4!p7(X4ld `6#W%>+Z%Me"@Zrm)%$;G1G-[*EMY`C[A(-mu)&2o?B'?etR^6qt*^*YC\B#7b6P0"L8Kq2k9d4r8KRE4=qu9b;km$FkhmbARR5=`VZfK#AX=N_8`D.g[HY;];Xr2)Wh_RirR=*\,6[sF+!,q8CH#H$8BF*?][D,9uL7inb>np'm'9OG"n".6uP0OHTFkjPI-Je%H7T]-h tF(^T;!EQ>p(>jch"Tn#M!b1tkVd0P-FQ6_7rIA=8$R4@]X<.;mcpXfu8U44LU+Q0'cjeuXiGg[n\Zl!ao=AnVM/ADY-!&rVZK!$7`qhBJPJcEkA@bVCNCP<<1Nk^l=p=?3Aa*--XHu3+h)/[9b$Q>Wiq8BV[lNa+f;-dmg4U3P1O]l5hub!E1>G.FH%HpL`O!Uo F4F^SE3.X/fGdDJr],=H#FaVuR6S+$Sn0f1h99F3ciA*X)FS*CMR/4;O$/jgf^kUqrnMlW535-[l3:r2r@1o/IU;H_&c]=rLWJ*30,P`17jFXZAc&e9pQC/7ld?qGaRC'74(,9;=qYW#Rpj7fpd9-n\XT+u[cK7(TAut\]6(G="Br*+ETXAIA=TH-n$An%SdWVa_Sht@*UjtA;;c>[*%d%*N'mL"8oO+9A3?!m]V!nbcn4:\h1 NBP>M)$%N16g4)TfMW0KY$Z+/*.=^`8qT23C`+R42igK?1P=Cl)Z"WOr=YAahXh,SG=B`:uJ?>2/V"9g9kCc%sM0#27H,:.@jTLYeLS*(62n)bhX,h)j#d9:dh"6-Et_Dp4-i<#J6HDgNs(RBTe+c7g%Q/6%S6OY.VAeC`J?pOKj7F(om]s*%7c^s)WIi=YE%3'!9:0oCq58mL!,\$i+N@T<\I[BL:Ok&bB+TE-D"UFZXC8QJF,>MIRC&^&rs @J.X9gP*F^.%3:_J4&bA.B$=&!"1'ZoQ9Q((lk98rBqn_dW@*cdW#-RHZ\P:dkX!1+3mRDDl2:?Up')@D`)5FQ#SqVLCb@-=_q@kNFY*@0!5)sFLuok>k-G$`\5h6RN%*X>C*\8"jSD_eRF$_!2X*jXr,NRD;B5J_ORZ`ac30q_)7`M.PoUZ^5A-Em^edW&aJ2t:!hNbCI@#ZXM.:SNa)p`fTZhlaF9#B7G=9:.:JRPC!h6Qm2^3^nE>$'c%R BuNPCOMA_OY);j-^<\GEO/P!b\LE48d\[D]Cd4"H=U-<3:jUeQY',*[I-R]kpK$ggmj,i%@%`^,hQ+I-BoUeQZQ(U!^!M!jVQraekO`3!4a]f2O+.8#Ng)(L)$o5PO&+ZX/upf*cUGH+N)>k9H-_>oig*o6*,Yt^-O1@R?g[WaD;e3BIe;qL/iea!mN?KbYa(q(C`Uc7+%!!O)$$eS*c6DC=jF4o_"Fl+Q_bE,-H$=9]^kK:>b92/*67#8!n: O?rHhml4b8Gpnj6MoJ+Kjmq! tssT(2a'#W&&R`.Hk#S@9^&)HTM6Ci/YD;G#VWj*mI7f,%Q'ke;f-J'..J;LdWOc[nAHafiP7TV;g?LD'QOid4m;A^fdPoD%bil2GGB,#H4eo^>LZ^L1&j0Q=Bh@U!63![\dm\=`%,o,jKmA!0u\Yc)SYZeO&7FS,.L`>&@!^9<6 1>a+W/Gd0j?jgT.&tU[h`hmIpMa3AW#!FW$N*Zt(^ifAT`Zb.WF"'iC,?l=/E(`tVjrr9YZeYB\h.nctod`sZ^d,^QSr_Bhs4bMBKNCN;"rqY7o(*h6HJhl;Sar\m']GjkX"((p,Z+&EF.(,(Ef]*iLI)XO(IR'hH7HdZ(o)T##-Ji^k!nSR0n>`0EuO/bbE:S*$7X:J`q7Uaa=T!bb/ol+Z=MWAD=hh3,P(e`98,3.3 2M7Sb&T4Q;lKjI*pk>33g[rlDh*ngG:nLh*ZWWT)Mf\P]0?SO1&T)+)g#%NbN_C9Q>DE'<8k%<[_?ln2?H+q=Y0'tYPYRd7k5>SQ[oo_@Y]MiYH*Aq3*GDlFg\j"GsRNAP6sl2L'M5Z2F:ELW)4?S1Qt2&`GXm]q+@eQ_9`>-*Vjf!"3*HdP1gN;nCUX\cQc#jA"'l=O,G5qhJtHV^+uS(4Z7q%'aiCn01=*c&ihT%:@Y8"0G(Q4^DB/imPh@[ff`mO="<3bUBn.RVagVrWT;VJl-lettH/,MCndghZ90gV4L=hcTI=ac/%KjmW1LrO-ic=1_'U8@pDPb1r32rJ0G?a%H!HTA6fGs/U&6Q?CiOZjuZ(:UOEqHHk5VH3p_MEcl%gZGL5?d>h\mT<.5@p!H[h[uY)S!_5X[/<^s'2-] FrF=%kFK.0WBIe1-F35pIjqHJ'u[>M9i"qQC:bo9(\J2f-d5f_l6DJ&ET_Z'6rc\Y@DmhCZ^]6#Pee&D;<2G:s:p^G9$b+g5GkDd>_)q$V.Apa6L5REH2aHM[^7I:FJ8'A(D715S47CkVEi.E;s:,btJ8KH5LO7S< p^b^q47ssmZ,gYZAQEr$9-:YgcLs*q6Z&JJ:Uuu&rW.p)F,Sm2.F4O=E0@Do;rV+8If01DoWp)sfS)MTZ66%*/!``8fqp-siLK1Nj9XHFhh!QNqqM]gP0:\p]0,3a-SKRE,;&(h2'aa_3K*dR)KU7AH&mkj%pg$100-Yaf%\_JDsUOYe6]gI&buHTf$>dbndudb%K qc!C3)5X8!aOd\oTXt%8\W@$q8As\Sbb*TgMafb'dq6ZJ+JdO*K"(BlUO-kT9K8X\d'Nc.V(OgV'_b:*$.,aY.jjefS:so;G=*j?7_PghYQS^6oqCIT+RR5RAunXL"mNq7Cfro"'fIuKN0sh)l,ZCM-&29??G%j*3&7Y<+>/n[k<"QdEO)*:Jk][XFp8% [6.duP'Y@'MXEM9\Q\Uh9>f.h:E[]U\j+fDjK/k/M)mUfBOtME-3RXq^(2"Panp#=2E#>faC(r&``Qhf1q/%ojCN]4$enrCMs)im'-:U4":c_k^.<$,i"1>GTUgh&)/Jf_3CJVYDXTW/E.EsgXt5AOUtS]M=q=c!2m4JYWk#\db9 d!N"QAY)_0/22:/=Yq:1:"j'1EqJPFM13<0j[e4*TL2;6>_'?N@aX?QTi``>(eqT-7(*<%mgnp%b=TlDLb7YGt'NQ0Nk=]U0gfbXP!1'og5Io`9@qmG-aPE'_5SG (S6eIJbJ(6-t7Z+^1)'cTq-6>`n"hJ!!LRbMW]gD8DkH`[0k3^nPfNV#2rcc3TVi#R/>N!kBV[`&dPY>KPRnjpCMFn(.uDFCccoe_aZ*#'nQY8NF3-AGjK9Jm?hAi"]s_i8fmc13Bfo84@@O"_a(.lh^9XT]GT+H1I.fr8WuVdC4#j\h%OO.@>7EN?,U[rs+Y:nfg@$EoV5QPc`R,>1@H8gF;<=m;WH\ZI%Ki"-[-1@;_R^ M7VuQTab_hl'ss57s,=!3El#V)2uNq,0i&K>2'*Cd=1(B[si+)5U1_\!VGH'/.7&jOg6&i2p]9Aq;PF!+A4VcaeuTlrgn+3PB,(F3Z:[\e?'mJH7U;);j&'`5UR5KB6$E))sOFR)N9@`Eu5Y`MOR/QCi_3IRG>@9+pAR-`&p(CJoS%:Gr`FlV8h^GM6;MroQ>]F&gW6>&Tb"MnZ/gJ/epVH)Ti1TT(Q)a)*c>d`Z^+CYV@nB4t(!Ejgg^3X9F #)01<@?4Jnmd>ru42lp6[2Z%prPBJkNCYM_]dj*n4\gl@;A#b`!cO7eMBC`+o\aXqEC@la/@cGU(?*r6m+JI&k$[)sH!eqg-Yq#>ghQMump<.!QV,a02X,1troC-Eca?gkiaou>m?L'C-k0$g&7Cd=/H'.*Moq/$eS:HiK$8Iuk6N4Pu)6bh$1P*F%qqj:TQg9^_b[JPoXdo>a"m[Of>afugADRn`I`O,uh^.4W;P S5SAZU,bZ6j3V[DELr1P;NEF8W2\+SpVfC*)=LGVimT1*#]lVj<["-2#QE])qP@a?k]2hq,f=lrJ]g31s#h6\akV-kT!<1$)mYbUqd!kV&R]_q")NrF#BU67EcVgNe>p7_DBN.QSJIFNDjUZ#^ckAFTLiY`k\#AfOrNA[iRO*qaWaIpU"b846/`CZMF*o/"IFHo;1J%q">`J7abb24+J!cTZC``h]76f++b12/\0&s: .Eu5MPS9(G8^eN&9QiN,f&T=f1$Si3E?u*[5h0BE>\T[/*,1='`Vn%bMY6#s-,NmjirDOnMXY&4mj8eq[4XMoo@q%HUaEdfMT(`lL.]o9.`"c'%b6d3ldf`3W)$*sK5'kPEe@UL7\:HRKj-)DJ&*IjD$m-Z>Cd)CUgZP(ghDebqrt;"Sbh\5%iA#3jkXa=)2a;\hJip/0!S@oe>PDLQ]4u>i+[oRFOC#ElRa#JUDnI`u!;=7O((KI"9gs)BgD 2/^8Q6p]Z]Ki-R":L`Rs#o`m+F0YdaHZGC0gu-&'j'W#bWK,pTg4!T$m\(H,L3R.9E/,_NkH!3CX!.)S_5e]dCA1(/$P:]4H&P2kB;5.6C^h"OI4B5DFgI/cIMrluoQ/h66's?/?P:Z#=Ib5R0:K]YWa?n-7/u5:LS6q75=!-Z,i;I=gb1b+Y?4-f7$r%&%kOjV;YO9K`-uJm0(K"65[bkl`MjuRt")o7FTU53l]rJs!A@GT>h3E%aH<]?l_Vht__$L?+(Fb3!74"TW2D`rVfPPHTfXB;3Zs38-!1kb+DG],Xf/FMO`%nl#WFM@eW;>E:Q,f l'bEK123+G""c;6M,[F[o14Uok3H"254Z\ma*FuRJtGo(gU=taIuQMQ/sB.Os>);l\4ni:lSHis#e`prYP!';C5U.7*=a28Yd]Gb<\$=?$4Gu-YlYIc,OEXMl+9&8c8T=5W"bMHj]>ujN]nAEhLq*,HM8ZbgK'hcJjF01=LoU9e7Wr[T2TQTWp1m! Itc$q/FGS%s`>8\a[$];AM1emsiIJ$32k+/p5F)TDP'#A*KO1CqC0Mgm>Q`k]Z?!Z0(C= endstream endobj 8 0 obj << /Type /Page /Resources << /Font 5 0 R /ProcSet [ /PDF /Text /ImageB /ImageC ] /XObject 4 0 R /Shading 7 0 R >> /MediaBox [0 0 595.28 841.89] /Contents 14 0 R /Parent 15 0 R >> endobj 14 0 obj << /Length 2163 /Filter [ /ASCII85Decode /FlateDecode ] >> stream Gasaq95iQE&AACjJ!a^Q\;WtlF)r@7i?Ck"NV?Bd$V$j2"g[>_Ems`#p(ufB6P#+3p9ZW%bFuNW&=]KX`Hcq'n^/S#f4)StMcj*Zn_+T!(#W:In0&@5q%c@;3*gJ_fC7rXnV#-[L+M,R"5d^!!5?JkDcfEFdZ[]Rq>0mMbn:)5q8e8YODPlQl%R).%N^``=)]oVKk[PC3<>V%AQtH2e'#^HHG,h)\<*=+oYBPi]F]bj$C22V?Od6dJq^X)0GshU .fI*0R6F!K/tbdE#aX#_%6\=PmI1;iE$6&/n`'9?+b'=DVuNI63"MDDJhKHFDXNMS>JC!?gn((.5!;%`\_bFP<\dAnR?`Z/U6G3TG/+0+QlDD&JHZN1LE2EGa_m9:dOpo+_/gHJZrZT'!qtS`T"urL2VNQlm5E ]Ufd&$tFa"\'DOJXbH)\N"lZ`1$3CAG2"7DcO0FT6`D1F'(SF^]SMPPK9!Wk=[nncG"=m?OJ1FcrkK^6'A@XN+V]/p>27jkE7U_P<0rI+tPa'a-I'_An4SMpblDf:oK/:/ofHdWW%C+,g>kcB>_mKubShntU]"Uk\>q2o@3cOYdq8TIQF]QSq3^`CI8u:4Bj7_tWLP_X>Z!P2fpuUOM;ob)65MqP5A]pTk/nOonH8V7#[@9^a]jC!QbrY`Gdl7=d2J::7DVttLe&FIH3bqdmmQm+aho#uWLXGSSWu`s6LV]C=_ZI/#f9d]fg7&2AbogB)'TgNa&3Cgi$bWRa::r,Sd2/_u'I^)-7B,9a\(,Ktgp88OZEEXtmFu*I2&6Y ?'2@&GlAr]%/+oS+8=>lUQ)j-*Cn-G."K!jnj7WLB%-8n-In!`reKC]RMt+Ec@NQU]Dhrg4 G^:YE0[JJ/YYF(9HIh:[!JU'DmH%HO.>GJ]e**4BIW?!S4J9!8$lBc>K7Q$$h=a*4pe*TaS'o&V>=>=K7Y;K&PZOohqHJH:[G8XN.gQX]S-phkJhX>Ll+.^W*@GgnRicMW=0JXZu27jaRgXn"gnf4OAdpMKL$&Vou$E62,7g>N`D/="`Q,j(L)OIMccVMD>H%Z+mZ_&H!q^SBiYI[Ck5NucuXc%bkd<.G-I`p0?O)T6fBJ:N.ELZ)TaKp6TM*G\uh\uo65eOJhLa>LF!#*Xo&E$!L6^_Q4n&PU@]orXs>0XK.aJMjp!.?DA2Y&^>*hD@?_m/dSPs@Yuh^q9*B@9L.6G<^ M;C`Inhn%H#jAQ*thpbdSqDgVJA%c8<2E3'bJk#?04-oRsnm]cPdbH%dg5n!\nnYI(HOU)AD=9K\%l+7sMsn7_bDa5`#9+L%SEQ'Z)u(>sfdEJjTJ endstream endobj 16 0 obj << /Type /Font /Subtype /TrueType /BaseFont /Arial /FirstChar 32 /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 552 400 549 333 333 333 576 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 549 611 556 556 556 556 500 556 500 ] /Encoding /WinAnsiEncoding /FontDescriptor 17 0 R /Name /F0101 >> endobj 17 0 obj << /Type /FontDescriptor /FontName /Arial /FontBBox [-665 -325 2000 1006] /Ascent 905 /Descent -212 /CapHeight 660 /StemV 110 /ItalicAngle 0 /MissingWidth 278 /Flags 32 /Style << /Panose <080502110604020202020204> >> >> endobj 18 0 obj << /Type /Font /Subtype /TrueType /BaseFont /TimesNewRoman /FirstChar 32 /LastChar 255 /Widths [ 250 333 408 500 500 833 778 180 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 250 333 500 500 500 500 200 500 333 760 276 500 564 333 760 500 400 549 300 300 333 576 453 250 333 300 310 500 750 750 750 444 722 722 722 722 722 722 889 667 611 611 611 611 333 333 333 333 722 722 722 722 722 722 722 564 722 722 722 722 722 722 556 500 444 444 444 444 444 444 667 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 549 500 500 500 500 500 500 500 500 ] /Encoding /WinAnsiEncoding /FontDescriptor 19 0 R /Name /F0201 >> endobj 19 0 obj << /Type /FontDescriptor /FontName /TimesNewRoman /FontBBox [-568 -307 2000 1007] /Ascent 891 /Descent -216 /CapHeight 660 /StemV 110 /ItalicAngle 0 /MissingWidth 250 /Flags 32 /Style << /Panose <010502020603050405020304> >> >> endobj 20 0 obj << /Type /Font /Subtype /TrueType /BaseFont /TimesNewRoman,Bold /FirstChar 32 /LastChar 255 /Widths [ 250 333 555 500 500 1000 833 278 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 394 220 394 520 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 250 333 500 500 500 500 220 500 333 747 300 500 570 333 747 500 400 549 300 300 333 576 540 250 333 300 330 500 750 750 750 500 722 722 722 722 722 722 1000 722 667 667 667 667 389 389 389 389 722 722 778 778 778 778 778 570 778 722 722 722 722 722 611 556 500 500 500 500 500 500 722 444 444 444 444 444 278 278 278 278 500 556 500 500 500 500 500 549 500 556 556 556 556 500 556 500 ] /Encoding /WinAnsiEncoding /FontDescriptor 21 0 R /Name /F0301 >> endobj 21 0 obj << /Type /FontDescriptor /FontName /TimesNewRoman,Bold /FontBBox [-558 -307 2000 1026] /Ascent 891 /Descent -216 /CapHeight 660 /StemV 110 /ItalicAngle 0 /MissingWidth 250 /Flags 32 /Style << /Panose <010502020803070505020304> >> >> endobj 22 0 obj << /Type /Font /Subtype /TrueType /BaseFont /Arial,Italic /FirstChar 32 /LastChar 255 /Widths [ 278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 556 556 333 500 278 556 500 722 500 500 500 334 260 334 584 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 278 333 556 556 556 556 260 556 333 737 370 556 584 333 737 552 400 549 333 333 333 576 537 278 333 333 365 556 834 834 834 611 667 667 667 667 667 667 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 500 556 556 556 556 278 278 278 278 556 556 556 556 556 556 556 549 611 556 556 556 556 500 556 500 ] /Encoding /WinAnsiEncoding /FontDescriptor 23 0 R /Name /F0401 >> endobj 23 0 obj << /Type /FontDescriptor /FontName /Arial,Italic /FontBBox [-517 -325 1082 998] /Ascent 905 /Descent -212 /CapHeight 660 /StemV 110 /ItalicAngle -11 /MissingWidth 278 /Flags 96 /Style << /Panose <080502110604020202090204> >> >> endobj 24 0 obj << /Type /Font /Subtype /TrueType /BaseFont /Arial,Bold /FirstChar 32 /LastChar 255 /Widths [ 278 333 474 556 556 889 722 238 333 333 389 584 278 333 278 278 556 556 556 556 556 556 556 556 556 556 333 333 584 584 584 611 975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 667 778 722 667 611 722 667 944 667 667 611 333 278 333 584 556 333 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556 333 611 556 778 556 556 500 389 280 389 584 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 750 278 333 556 556 556 556 280 556 333 737 370 556 584 333 737 552 400 549 333 333 333 576 556 278 333 333 365 556 834 834 834 611 722 722 722 722 722 722 1000 722 667 667 667 667 278 278 278 278 722 722 778 778 778 778 778 584 778 722 722 722 722 667 667 611 556 556 556 556 556 556 889 556 556 556 556 556 278 278 278 278 611 611 611 611 611 611 611 549 611 611 611 611 611 556 611 556 ] /Encoding /WinAnsiEncoding /FontDescriptor 25 0 R /Name /F0501 >> endobj 25 0 obj << /Type /FontDescriptor /FontName /Arial,Bold /FontBBox [-628 -376 2000 1010] /Ascent 905 /Descent -212 /CapHeight 660 /StemV 110 /ItalicAngle 0 /MissingWidth 278 /Flags 32 /Style << /Panose <080502110704020202020204> >> >> endobj 15 0 obj << /Type /Pages /Kids [ 8 0 R ] /Count 1 >> endobj 1 0 obj << /Producer (StreamServe Communication Server 5.1.0 GA Build 91) /CreationDate (D:20080123124225) >> endobj 2 0 obj << /Type /Catalog /StructTreeRoot 26 0 R /MarkInfo <> /Pages 15 0 R /Outlines 3 0 R >> endobj 3 0 obj << /Type /Outlines /Count 0 >> endobj 4 0 obj << /I1 9 0 R /I2 10 0 R /I3 11 0 R /I4 12 0 R /I5 13 0 R >> endobj 5 0 obj << /F0101 16 0 R /F0201 18 0 R /F0301 20 0 R /F0401 22 0 R /F0501 24 0 R >> endobj 6 0 obj << >> endobj 7 0 obj << >> endobj xref 0 27 0000000000 65535 f 0000099170 00000 n 0000099295 00000 n 0000099422 00000 n 0000099476 00000 n 0000099562 00000 n 0000099664 00000 n 0000099691 00000 n 0000089823 00000 n 0000000019 00000 n 0000017794 00000 n 0000018891 00000 n 0000074946 00000 n 0000079912 00000 n 0000090037 00000 n 0000099101 00000 n 0000092301 00000 n 0000093397 00000 n 0000093648 00000 n 0000094750 00000 n 0000095009 00000 n 0000096119 00000 n 0000096383 00000 n 0000097486 00000 n 0000097745 00000 n 0000098845 00000 n 0000000000 00000 n trailer << /Info 1 0 R /Root 2 0 R /ID[<58cb41a85829e16d76b9fd01219618b9><58cb41a85829e16d76b9fd01219618b9>] /Size 27 >> startxref 99718 %%EOF pdfrenderer-0.9.0/demos/0000755000175000017500000000000011622545441015071 5ustar twernertwernerpdfrenderer-0.9.0/demos/viewer/0000755000175000017500000000000011622545441016372 5ustar twernertwernerpdfrenderer-0.9.0/demos/viewer/com/0000755000175000017500000000000011622545441017150 5ustar twernertwernerpdfrenderer-0.9.0/demos/viewer/com/sun/0000755000175000017500000000000011622545441017755 5ustar twernertwernerpdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/0000755000175000017500000000000011622545441021421 5ustar twernertwernerpdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/PageChangeListener.java0000644000175000017500000000233610732532577025767 0ustar twernertwerner/* * $Id: PageChangeListener.java,v 1.2 2007-12-20 18:33:33 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; /** * A listener to indicate that some control has asked for a particular * page to be displayed. */ public interface PageChangeListener { /** * Notifies the listener that it should go to a particular page number. */ public void gotoPage(int page); } pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/ThumbPanel.java0000644000175000017500000003071611137242555024333 0ustar twernertwerner/* * $Id: ThumbPanel.java,v 1.5 2009-01-26 05:09:01 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import javax.swing.JPanel; import javax.swing.JViewport; import javax.swing.Scrollable; import javax.swing.SwingUtilities; /** * A panel of thumbnails, one for each page of a PDFFile. You can add * a PageChangeListener to be informed of when the user clicks one of the * pages. */ public class ThumbPanel extends JPanel implements Runnable, Scrollable, ImageObserver { /** The PDFFile being displayed */ PDFFile file; /** Array of images, one per page in the file */ Image images[]; /** Size of the border between images*/ int border = 2; /** * Height of each line. Thumbnails will be scaled to this height * (minus the border). */ int lineheight = 96 + border; /** * Guesstimate of the width of a thumbnail that hasn't been processed * yet. */ int defaultWidth = (lineheight - border) * 4 / 3; /** * Array of the x locations of each of the thumbnails. Every 0 stored * in this array indicates the start of a new line of thumbnails. */ int xloc[]; /** Thread that renders each thumbnail in turn */ Thread anim; /** Which thumbnail is selected, or -1 if no thumbnail selected. */ int showing = -1; /** * Which thumbnail needs to be drawn next, or -1 if the previous * needy thumbnail is being processed. */ int needdrawn = -1; /** * Whether the default width has been guesstimated for this PDFFile * yet. */ boolean defaultNotSet = true; /** The PageChangeListener that is listening for page changes */ PageChangeListener listener; // Flag flag= new Flag(); /** * Creates a new ThumbPanel based on a PDFFile. The file may be null. * Automatically starts rendering thumbnails for that file. */ public ThumbPanel(PDFFile file) { super(); this.file = file; if (file != null) { int count = file.getNumPages(); images = new Image[count]; xloc = new int[count]; setPreferredSize(new Dimension(defaultWidth, 200)); addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { handleClick(evt.getX(), evt.getY()); } }); anim = new Thread(this); anim.setName(getClass().getName()); anim.start(); } else { images = new Image[0]; setPreferredSize(new Dimension(defaultWidth, 200)); } } /** * Renders each of the pages in the PDFFile into a thumbnail. * Preferentially works on the needdrawn thumbnail, otherwise, go in * order. */ public void run() { int workingon = 0; // the thumbnail we'll be rendering next. while (anim == Thread.currentThread()) { if (needdrawn >= 0) { workingon = needdrawn; needdrawn = -1; } // find an unfinished page int loop; for (loop = images.length; loop > 0; loop--) { if (images[workingon] == null) { break; } workingon++; if (workingon >= images.length) { workingon = 0; } } if (loop == 0) { // done all pages. break; } // build the page try { int pagetoread = workingon + 1; // int pagetoread= 1; // System.out.println("Read page: " + pagetoread); PDFPage p = file.getPage(pagetoread, true); int wid = (int) Math.ceil((lineheight - border) * p.getAspectRatio()); // if (!p.isFinished()) { // System.out.println("Page not finished!"); // p.waitForFinish(); // } // flag.clear(); // int pagetowrite= 0; int pagetowrite = workingon; Image i = p.getImage(wid, (lineheight - border), null, this, true, true); // images[0] = i; images[pagetowrite] = i; // flag.waitForFlag(); if (defaultNotSet) { defaultNotSet = false; setDefaultWidth(wid); } repaint(); } catch (Exception e) { e.printStackTrace(); int size = lineheight - border; images[workingon] = new BufferedImage(size, size, BufferedImage.TYPE_BYTE_BINARY); } } } /** * Adds a PageChangeListener to receive notification of page clicks. */ public void addPageChangeListener(PageChangeListener pl) { // [[MW: should be an array list instead of only one]] listener = pl; } /** * Removes a PageChangeListener from the notification list. */ public void removePageChangeListener(PageChangeListener pl) { // [[MW: should be an array list instead of only one]] listener = null; } /** * Stops the render thread. Be sure to call this before dropping * a ThumbPanel. */ public void stop() { anim = null; } /** * Sets the default width of an un-processed thumbnail. * @param width the width of an unknown thumbnail, in pixels. */ public void setDefaultWidth(int width) { defaultWidth = width; // setPreferredSize(new Dimension(width, lineheight)); } /** * Handles a mouse click in the panel. Figures out which page was * clicked, and calls showPage. * @param x the x coordinate of the mouse click * @param y the y coordinate of the mouse click */ public void handleClick(int x, int y) { int linecount = -1; int line = y / lineheight; // run through the thumbnail locations, counting new lines // until the appropriate line is reached. for (int i = 0; i < xloc.length; i++) { if (xloc[i] == 0) { linecount++; } if (line == linecount && xloc[i] + (images[i] != null ? images[i].getWidth(null) : defaultWidth) > x) { showPage(i); break; } } } /** * Sets the currently viewed page, indicates it with a highlight * border, and makes sure the thumbnail is visible. */ public void pageShown(int pagenum) { if (showing != pagenum) { // FIND THE SELECTION RECTANGLE // getViewPort.scrollRectToVisible(r); if (pagenum >= 0 && getParent() instanceof JViewport) { int y = -lineheight; for (int i = 0; i <= pagenum; i++) { if (xloc[i] == 0) { y += lineheight; } } Rectangle r = new Rectangle(xloc[pagenum], y, (images[pagenum] == null ? defaultWidth : images[pagenum].getWidth(null)), lineheight); scrollRectToVisible(r); } showing = pagenum; repaint(); } } /** * Notifies the listeners that a page has been selected. Performs * the notification in the AWT thread. * Also highlights the selected page. Does this first so that feedback * is immediate. */ public void showPage(int pagenum) { pageShown(pagenum); SwingUtilities.invokeLater(new GotoLater(pagenum)); } /** * Simple runnable to tell listeners that the page has changed. */ class GotoLater implements Runnable { int page; public GotoLater(int pagenum) { page = pagenum; } public void run() { if (listener != null) { listener.gotoPage(page); } } } /** * Updates the positions of the thumbnails, and draws them to the * screen. */ public void paint(Graphics g) { int x = 0; int y = 0; int maxwidth = 0; Rectangle clip = g.getClipBounds(); g.setColor(Color.gray); int width = getWidth(); g.fillRect(0, 0, width, getHeight()); for (int i = 0; i < images.length; i++) { // calculate the x location of the thumbnail, based on its width int w = defaultWidth + 2; if (images[i] != null) { w = (int) images[i].getWidth(null) + 2; } // need a new line? if (x + w > width && x != 0) { x = 0; y += lineheight; } // if the thumbnail is visible, draw it. if (clip.intersects(new Rectangle(x, y, w, lineheight))) { if (images[i] != null) { // thumbnail is ready. g.drawImage(images[i], x + 1, y + 1, this); } else { // thumbnail isn't ready. Remember that we need it... if (needdrawn == -1) { needdrawn = i; } // ... and draw a blank thumbnail. g.setColor(Color.lightGray); g.fillRect(x + 1, y + 1, w - border, lineheight - border); g.setColor(Color.darkGray); g.drawRect(x + 1, y + 1, w - border - 1, lineheight - border - 1); } // draw the selection highlight if needed. if (i == showing) { g.setColor(Color.red); g.drawRect(x, y, w - 1, lineheight - 1); g.drawRect(x + 1, y + 1, w - 3, lineheight - 3); } } // save the x location of this thumbnail. xloc[i] = x; x += w; // remember the longest line if (x > maxwidth) { maxwidth = x; } } // if there weren't any thumbnails, make a default line width if (maxwidth == 0) { maxwidth = defaultWidth; } Dimension d = getPreferredSize(); if (d.height != y + lineheight || d.width != maxwidth) { setPreferredSize(new Dimension(maxwidth, y + lineheight)); revalidate(); } } /** * Handles notification of any image updates. Not used any more. */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { // if ((infoflags & ALLBITS)!=0) { // flag.set(); // } return ((infoflags & (ALLBITS | ERROR | ABORT)) == 0); } public Dimension getPreferredScrollableViewportSize() { return getPreferredSize(); } public int getScrollableBlockIncrement(Rectangle visrect, int orientation, int direction) { return Math.max(lineheight, (visrect.height / lineheight) * lineheight); } public boolean getScrollableTracksViewportHeight() { return false; } public boolean getScrollableTracksViewportWidth() { return true; } public int getScrollableUnitIncrement(Rectangle visrect, int orientation, int direction) { return lineheight; } } pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/PDFPrintPage.java0000644000175000017500000002025711137242642024513 0ustar twernertwerner/* * $Id: PDFPrintPage.java,v 1.4 2009-01-26 05:09:54 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.print.*; import javax.swing.*; import java.nio.channels.FileChannel; import java.io.IOException; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.io.File; /** * A class representing a print job for a particular PDFFile. The class * maintains a status dialog as it prints, allowing the user to cancel * the print job. */ public class PDFPrintPage implements Printable { /** The PDFFile to be printed */ private PDFFile file; /** The PrinterJob for this print job */ private PrinterJob pjob; /** A dialog box indicating printing status, with cancel button */ private JDialog pd; /** The text in the progress dialog indicating the current page */ private JLabel pagenumlabel; /** The cancel button in the progress dialog */ private JButton cancel; /** * Create a new PDFPrintPage object for a particular PDFFile. * @param file the PDFFile to be printed. */ public PDFPrintPage(PDFFile file) { this.file = file; } /** * An example method to print a file. * * @param filename The path of the PDF file to print. * @param setupPaper true to post a page setup dialog * @throws java.io.IOException */ public void printFile(String filename, boolean setupPaper) throws IOException { File file = new File(filename); FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); PDFFile pdfFile = new PDFFile(bb); // Create PDF Print Page PDFPrintPage pages = new PDFPrintPage(pdfFile); // Create Print Job. // We set the margins to 0, on the default 8.5 x 11 paper PrinterJob pjob = PrinterJob.getPrinterJob(); PageFormat pfDefault = PrinterJob.getPrinterJob().defaultPage(); Paper defaultPaper = new Paper(); defaultPaper.setImageableArea(0, 0, defaultPaper.getWidth(), defaultPaper.getHeight()); pfDefault.setPaper(defaultPaper); if (setupPaper) { pfDefault = PrinterJob.getPrinterJob().pageDialog(pfDefault); } pjob.setJobName(file.getName()); if (pjob.printDialog()) { // validate the page against the chosen printer to correct // paper settings and margins pfDefault = pjob.validatePage(pfDefault); Book book = new Book(); book.append(pages, pfDefault, pdfFile.getNumPages()); pjob.setPageable(book); try { pjob.print(); } catch (PrinterException exc) { System.out.println(exc); } } } /** * Generates the status dialog with cancel button. */ private void createPrintDialog() { pd = new JDialog((Frame) null, "Printing...", false); Container top = pd.getContentPane(); Box lines = Box.createVerticalBox(); Box line = Box.createHorizontalBox(); line.add(new JLabel("Now printing: ")); JLabel title = new JLabel("file.pdf"); line.add(title); lines.add(line); line = Box.createHorizontalBox(); line.add(Box.createHorizontalStrut(10)); line.add(new JLabel("page ")); pagenumlabel = new JLabel("1"); line.add(pagenumlabel); line.add(new JLabel(" of ")); JLabel totalpages = new JLabel(String.valueOf(file.getNumPages())); line.add(totalpages); lines.add(line); top.add(lines, BorderLayout.CENTER); Box cancelbox = Box.createHorizontalBox(); cancelbox.add(Box.createHorizontalGlue()); cancel = new JButton(new AbstractAction("Cancel") { public void actionPerformed(ActionEvent evt) { doCancel(); } }); cancelbox.add(cancel); top.add(cancelbox, BorderLayout.SOUTH); } /** * Show the progress dialog for this print job * @param pjob the PrinterJob representing the print job */ public void show(PrinterJob pjob) { this.pjob = pjob; if (pd == null) { createPrintDialog(); } pd.pack(); pd.setVisible(true); } /** * Close the progress dialog. Don't use this method to cancel * the print job; use {@link #doCancel doCancel} instead. */ public void hide() { pd.dispose(); } /** * Cancel the print job. Disables the cancel button, as it might * take a while for the cancel to take effect. */ public void doCancel() { cancel.setEnabled(false); pjob.cancel(); } // from Printable interface: prints a single page, given a Graphics // to draw into, the page format, and the page number. public int print(Graphics g, PageFormat format, int index) throws PrinterException { int pagenum = index + 1; // don't bother if the page number is out of range. if ((pagenum >= 1) && (pagenum <= file.getNumPages())) { // update the page number in the progress dialog if (pagenumlabel != null) { pagenumlabel.setText(String.valueOf(pagenum)); } // fit the PDFPage into the printing area Graphics2D g2 = (Graphics2D) g; PDFPage page = file.getPage(pagenum); double pwidth = format.getImageableWidth(); double pheight = format.getImageableHeight(); double aspect = page.getAspectRatio(); // handle page orientation matching double paperaspect = pwidth / pheight; if (paperaspect < 1.0) { switch (format.getOrientation()) { case PageFormat.REVERSE_LANDSCAPE: case PageFormat.LANDSCAPE: format.setOrientation(PageFormat.PORTRAIT); break; case PageFormat.PORTRAIT: format.setOrientation(PageFormat.LANDSCAPE); break; } pwidth = format.getImageableWidth(); pheight = format.getImageableHeight(); paperaspect = pwidth / pheight; } Rectangle imgbounds; int width; int height; if (aspect > paperaspect) { // paper is too tall / pdfpage is too wide height = (int) (pwidth / aspect); width = (int) pwidth; } else { // paper is too wide / pdfpage is too tall width = (int) (pheight * aspect); height = (int) pheight; } imgbounds = new Rectangle((int) format.getImageableX(), (int) format.getImageableY(), width, height); // render the page PDFRenderer pgs = new PDFRenderer(page, g2, imgbounds, null, null); try { page.waitForFinish(); pgs.run(); } catch (InterruptedException ie) { } return PAGE_EXISTS; } else { return NO_SUCH_PAGE; } } } pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/PagePanel.java0000644000175000017500000002774511137242555024140 0ustar twernertwerner/* * $Id: PagePanel.java,v 1.3 2009-01-26 05:09:01 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Rectangle2D; import java.awt.image.ImageObserver; import javax.swing.JPanel; /** * A Swing-based panel that displays a PDF page image. If the zoom tool * is in use, allows the user to select a particular region of the image to * be zoomed. */ public class PagePanel extends JPanel implements ImageObserver, MouseListener, MouseMotionListener { /** The image of the rendered PDF page being displayed */ Image currentImage; /** The current PDFPage that was rendered into currentImage */ PDFPage currentPage; /* the current transform from device space to page space */ AffineTransform currentXform; /** The horizontal offset of the image from the left edge of the panel */ int offx; /** The vertical offset of the image from the top of the panel */ int offy; /** the current clip, in device space */ Rectangle2D clip; /** the clipping region used for the image */ Rectangle2D prevClip; /** the size of the image */ Dimension prevSize; /** the zooming marquee */ Rectangle zoomRect; /** whether the zoom tool is enabled */ boolean useZoom = false; // /** a listener for page changes */ // PageChangeListener listener; /** a flag indicating whether the current page is done or not. */ Flag flag = new Flag(); // Color boxcolor= new Color(255,200,200); /** * Create a new PagePanel, with a default size of 800 by 600 pixels. */ public PagePanel() { super(); setPreferredSize(new Dimension(800, 600)); setFocusable(true); addMouseListener(this); addMouseMotionListener(this); } /** * Stop the generation of any previous page, and draw the new one. * @param page the PDFPage to draw. */ public synchronized void showPage(PDFPage page) { // stop drawing the previous page if (currentPage != null && prevSize != null) { currentPage.stop(prevSize.width, prevSize.height, prevClip); } // set up the new page currentPage = page; if (page == null) { // no page currentImage = null; clip = null; currentXform = null; repaint(); } else { // start drawing -- clear the flag to indicate we're in progress. flag.clear(); // System.out.println(" flag cleared"); Dimension sz = getSize(); if (sz.width + sz.height == 0) { // no image to draw. return; } // System.out.println("Ratios: scrn="+((float)sz.width/sz.height)+ // ", clip="+(clip==null ? 0 : clip.getWidth()/clip.getHeight())); // calculate the clipping rectangle in page space from the // desired clip in screen space. Rectangle2D useClip = clip; if (clip != null && currentXform != null) { useClip = currentXform.createTransformedShape(clip).getBounds2D(); } Dimension pageSize = page.getUnstretchedSize(sz.width, sz.height, useClip); // get the new image currentImage = page.getImage(pageSize.width, pageSize.height, useClip, this); // calculate the transform from screen to page space currentXform = page.getInitialTransform(pageSize.width, pageSize.height, useClip); try { currentXform = currentXform.createInverse(); } catch (NoninvertibleTransformException nte) { System.out.println("Error inverting page transform!"); nte.printStackTrace(); } prevClip = useClip; prevSize = pageSize; repaint(); } } /** * @deprecated */ public synchronized void flush() { // images.clear(); // lruPages.clear(); // nextPage= null; // nextImage= null; } /** * Draw the image. */ public void paint(Graphics g) { Dimension sz = getSize(); g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); if (currentImage == null) { // No image -- draw an empty box // [[MW: remove the scary red X]] // g.setColor(Color.red); // g.drawLine(0, 0, getWidth(), getHeight()); // g.drawLine(0, getHeight(), getWidth(), 0); g.setColor(Color.black); g.drawString("No page selected", getWidth() / 2 - 30, getHeight() / 2); } else { // draw the image int imwid = currentImage.getWidth(null); int imhgt = currentImage.getHeight(null); // draw it centered within the panel offx = (sz.width - imwid) / 2; offy = (sz.height - imhgt) / 2; if ((imwid == sz.width && imhgt <= sz.height) || (imhgt == sz.height && imwid <= sz.width)) { g.drawImage(currentImage, offx, offy, this); } else { // the image is bogus. try again, or give up. flush(); if (currentPage != null) { showPage(currentPage); } g.setColor(Color.red); g.drawLine(0, 0, getWidth(), getHeight()); g.drawLine(0, getHeight(), getWidth(), 0); } } // draw the zoomrect if there is one. if (zoomRect != null) { g.setColor(Color.red); g.drawRect(zoomRect.x, zoomRect.y, zoomRect.width, zoomRect.height); } // debugging: draw a rectangle around the portion that just changed. // g.setColor(boxColor); // Rectangle r= g.getClipBounds(); // g.drawRect(r.x, r.y, r.width-1, r.height-1); } /** * Gets the page currently being displayed */ public PDFPage getPage() { return currentPage; } /** * Gets the size of the image currently being displayed */ public Dimension getCurSize() { return prevSize; } /** * Gets the clipping rectangle in page space currently being displayed */ public Rectangle2D getCurClip() { return prevClip; } /** * Waits until the page is either complete or had an error. */ public void waitForCurrentPage() { flag.waitForFlag(); } /** * Handles notification of the fact that some part of the image * changed. Repaints that portion. * @return true if more updates are desired. */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { // System.out.println("Image update: " + (infoflags & ALLBITS)); Dimension sz = getSize(); if ((infoflags & (SOMEBITS | ALLBITS)) != 0) { // [[MW: dink this rectangle by 1 to handle antialias issues]] repaint(x + offx, y + offy, width, height); } if ((infoflags & (ALLBITS | ERROR | ABORT)) != 0) { flag.set(); // System.out.println(" flag set"); return false; } else { return true; } } // public void addPageChangeListener(PageChangeListener pl) { // listener= pl; // } // public void removePageChangeListener(PageChangeListener pl) { // listener= null; // } /** * Turns the zoom tool on or off. If on, mouse drags will draw the * zooming marquee. If off, mouse drags are ignored. */ public void useZoomTool(boolean use) { useZoom = use; } /** * Set the desired clipping region (in screen coordinates), and redraw * the image. */ public void setClip(Rectangle2D clip) { this.clip = clip; showPage(currentPage); } /** x location of the mouse-down event */ int downx; /** y location of the mouse-down event */ int downy; /** Handles a mousePressed event */ public void mousePressed(MouseEvent evt) { downx = evt.getX(); downy = evt.getY(); } /** * Handles a mouseReleased event. If zooming is turned on and there's * a valid zoom rectangle, set the image clip to the zoom rect. */ public void mouseReleased(MouseEvent evt) { // calculate new clip if (!useZoom || zoomRect == null || zoomRect.width == 0 || zoomRect.height == 0) { zoomRect = null; return; } setClip(new Rectangle2D.Double(zoomRect.x - offx, zoomRect.y - offy, zoomRect.width, zoomRect.height)); zoomRect = null; } public void mouseClicked(MouseEvent evt) { } public void mouseEntered(MouseEvent evt) { } public void mouseExited(MouseEvent evt) { } public void mouseMoved(MouseEvent evt) { } /** * Handles a mouseDragged event. Constrains the zoom rect to the * aspect ratio of the panel unless the shift key is down. */ public void mouseDragged(MouseEvent evt) { if (useZoom) { int x = evt.getX(); int y = evt.getY(); int dx = Math.abs(x - downx); int dy = Math.abs(y - downy); // constrain to the aspect ratio of the panel if ((evt.getModifiers() & evt.SHIFT_MASK) == 0) { float aspect = (float) dx / (float) dy; float waspect = (float) getWidth() / (float) getHeight(); if (aspect > waspect) { dy = (int) (dx / waspect); } else { dx = (int) (dy * waspect); } } if (x < downx) { x = downx - dx; } if (y < downy) { y = downy - dy; } Rectangle old = zoomRect; // ignore small rectangles if (dx < 5 || dy < 5) { zoomRect = null; } else { zoomRect = new Rectangle(Math.min(downx, x), Math.min(downy, y), dx, dy); } // calculate the repaint region. Should be the union of the // old zoom rect and the new one, with an extra pixel on the // bottom and right because of the way rectangles are drawn. if (zoomRect != null) { if (old != null) { old.add(zoomRect); } else { old = new Rectangle(zoomRect); } } if (old != null) { old.width++; old.height++; } if (old != null) { repaint(old); } } } } pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/PDFViewer.java0000644000175000017500000010557511237133111024061 0ustar twernertwerner/* * $Id: PDFViewer.java,v 1.10 2009-08-07 23:18:33 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Rectangle2D; import java.awt.print.Book; import java.awt.print.PageFormat; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.awt.Toolkit; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; import java.io.IOException; import java.io.RandomAccessFile; import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Box; import javax.swing.ButtonGroup; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.JTree; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.filechooser.FileFilter; import javax.swing.SwingUtilities; import com.sun.pdfview.action.GoToAction; import com.sun.pdfview.action.PDFAction; import java.lang.reflect.InvocationTargetException; /** * A demo PDF Viewer application. */ public class PDFViewer extends JFrame implements KeyListener, TreeSelectionListener, PageChangeListener { public final static String TITLE = "SwingLabs PDF Viewer"; /** The current PDFFile */ PDFFile curFile; /** the name of the current document */ String docName; /** The split between thumbs and page */ JSplitPane split; /** The thumbnail scroll pane */ JScrollPane thumbscroll; /** The thumbnail display */ ThumbPanel thumbs; /** The page display */ PagePanel page; /** The full screen page display, or null if not in full screen mode */ PagePanel fspp; // Thread anim; /** The current page number (starts at 0), or -1 if no page */ int curpage = -1; /** the full screen button */ JToggleButton fullScreenButton; /** the current page number text field */ JTextField pageField; /** the full screen window, or null if not in full screen mode */ FullScreenWindow fullScreen; /** the root of the outline, or null if there is no outline */ OutlineNode outline = null; /** The page format for printing */ PageFormat pformat = PrinterJob.getPrinterJob().defaultPage(); /** true if the thumb panel should exist at all */ boolean doThumb = true; /** flag to indicate when a newly added document has been announced */ Flag docWaiter; /** a thread that pre-loads the next page for faster response */ PagePreparer pagePrep; /** the window containing the pdf outline, or null if one doesn't exist */ JDialog olf; /** the document menu */ JMenu docMenu; /** * utility method to get an icon from the resources of this class * @param name the name of the icon * @return the icon, or null if the icon wasn't found. */ public Icon getIcon(String name) { Icon icon = null; URL url = null; try { url = getClass().getResource(name); icon = new ImageIcon(url); if (icon == null) { System.out.println("Couldn't find " + url); } } catch (Exception e) { System.out.println("Couldn't find " + getClass().getName() + "/" + name); e.printStackTrace(); } return icon; } /// FILE MENU Action openAction = new AbstractAction("Open...") { public void actionPerformed(ActionEvent evt) { doOpen(); } }; Action pageSetupAction = new AbstractAction("Page setup...") { public void actionPerformed(ActionEvent evt) { doPageSetup(); } }; Action printAction = new AbstractAction("Print...", getIcon("gfx/print.gif")) { public void actionPerformed(ActionEvent evt) { doPrint(); } }; Action closeAction = new AbstractAction("Close") { public void actionPerformed(ActionEvent evt) { doClose(); } }; Action quitAction = new AbstractAction("Quit") { public void actionPerformed(ActionEvent evt) { doQuit(); } }; class ZoomAction extends AbstractAction { double zoomfactor = 1.0; public ZoomAction(String name, double factor) { super(name); zoomfactor = factor; } public ZoomAction(String name, Icon icon, double factor) { super(name, icon); zoomfactor = factor; } public void actionPerformed(ActionEvent evt) { doZoom(zoomfactor); } } ZoomAction zoomInAction = new ZoomAction("Zoom in", getIcon("gfx/zoomin.gif"), 2.0); ZoomAction zoomOutAction = new ZoomAction("Zoom out", getIcon("gfx/zoomout.gif"), 0.5); Action zoomToolAction = new AbstractAction("", getIcon("gfx/zoom.gif")) { public void actionPerformed(ActionEvent evt) { doZoomTool(); } }; Action fitInWindowAction = new AbstractAction("Fit in window", getIcon("gfx/fit.gif")) { public void actionPerformed(ActionEvent evt) { doFitInWindow(); } }; class ThumbAction extends AbstractAction implements PropertyChangeListener { boolean isOpen = true; public ThumbAction() { super("Hide thumbnails"); } public void propertyChange(PropertyChangeEvent evt) { int v = ((Integer) evt.getNewValue()).intValue(); if (v <= 1) { isOpen = false; putValue(ACTION_COMMAND_KEY, "Show thumbnails"); putValue(NAME, "Show thumbnails"); } else { isOpen = true; putValue(ACTION_COMMAND_KEY, "Hide thumbnails"); putValue(NAME, "Hide thumbnails"); } } public void actionPerformed(ActionEvent evt) { doThumbs(!isOpen); } } ThumbAction thumbAction = new ThumbAction(); Action fullScreenAction = new AbstractAction("Full screen", getIcon("gfx/fullscrn.gif")) { public void actionPerformed(ActionEvent evt) { doFullScreen((evt.getModifiers() & evt.SHIFT_MASK) != 0); } }; Action nextAction = new AbstractAction("Next", getIcon("gfx/next.gif")) { public void actionPerformed(ActionEvent evt) { doNext(); } }; Action firstAction = new AbstractAction("First", getIcon("gfx/first.gif")) { public void actionPerformed(ActionEvent evt) { doFirst(); } }; Action lastAction = new AbstractAction("Last", getIcon("gfx/last.gif")) { public void actionPerformed(ActionEvent evt) { doLast(); } }; Action prevAction = new AbstractAction("Prev", getIcon("gfx/prev.gif")) { public void actionPerformed(ActionEvent evt) { doPrev(); } }; /** * Create a new PDFViewer based on a user, with or without a thumbnail * panel. * @param useThumbs true if the thumb panel should exist, false if not. */ public PDFViewer(boolean useThumbs) { super(TITLE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { doQuit(); } }); doThumb = useThumbs; init(); } /** * Initialize this PDFViewer by creating the GUI. */ protected void init() { page = new PagePanel(); page.addKeyListener(this); if (doThumb) { split = new JSplitPane(split.HORIZONTAL_SPLIT); split.addPropertyChangeListener(split.DIVIDER_LOCATION_PROPERTY, thumbAction); split.setOneTouchExpandable(true); thumbs = new ThumbPanel(null); thumbscroll = new JScrollPane(thumbs, thumbscroll.VERTICAL_SCROLLBAR_ALWAYS, thumbscroll.HORIZONTAL_SCROLLBAR_NEVER); split.setLeftComponent(thumbscroll); split.setRightComponent(page); getContentPane().add(split, BorderLayout.CENTER); } else { getContentPane().add(page, BorderLayout.CENTER); } JToolBar toolbar = new JToolBar(); toolbar.setFloatable(false); JButton jb; jb = new JButton(firstAction); jb.setText(""); toolbar.add(jb); jb = new JButton(prevAction); jb.setText(""); toolbar.add(jb); pageField = new JTextField("-", 3); // pageField.setEnabled(false); pageField.setMaximumSize(new Dimension(45, 32)); pageField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { doPageTyped(); } }); toolbar.add(pageField); jb = new JButton(nextAction); jb.setText(""); toolbar.add(jb); jb = new JButton(lastAction); jb.setText(""); toolbar.add(jb); toolbar.add(Box.createHorizontalGlue()); fullScreenButton = new JToggleButton(fullScreenAction); fullScreenButton.setText(""); toolbar.add(fullScreenButton); fullScreenButton.setEnabled(true); toolbar.add(Box.createHorizontalGlue()); JToggleButton jtb; ButtonGroup bg = new ButtonGroup(); jtb = new JToggleButton(zoomToolAction); jtb.setText(""); bg.add(jtb); toolbar.add(jtb); jtb = new JToggleButton(fitInWindowAction); jtb.setText(""); bg.add(jtb); jtb.setSelected(true); toolbar.add(jtb); toolbar.add(Box.createHorizontalGlue()); jb = new JButton(printAction); jb.setText(""); toolbar.add(jb); getContentPane().add(toolbar, BorderLayout.NORTH); JMenuBar mb = new JMenuBar(); JMenu file = new JMenu("File"); file.add(openAction); file.add(closeAction); file.addSeparator(); file.add(pageSetupAction); file.add(printAction); file.addSeparator(); file.add(quitAction); mb.add(file); JMenu view = new JMenu("View"); JMenu zoom = new JMenu("Zoom"); zoom.add(zoomInAction); zoom.add(zoomOutAction); zoom.add(fitInWindowAction); zoom.setEnabled(false); view.add(zoom); view.add(fullScreenAction); if (doThumb) { view.addSeparator(); view.add(thumbAction); } mb.add(view); setJMenuBar(mb); setEnabling(); pack(); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); int x = (screen.width - getWidth()) / 2; int y = (screen.height - getHeight()) / 2; setLocation(x, y); if (SwingUtilities.isEventDispatchThread()) { setVisible(true); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { setVisible(true); } }); } catch (InvocationTargetException ie) { // ignore } catch (InterruptedException ie) { // ignore } } } /** * Changes the displayed page, desyncing if we're not on the * same page as a presenter. * @param pagenum the page to display */ public void gotoPage(int pagenum) { if (pagenum < 0) { pagenum = 0; } else if (pagenum >= curFile.getNumPages()) { pagenum = curFile.getNumPages() - 1; } forceGotoPage(pagenum); } /** * Changes the displayed page. * @param pagenum the page to display */ public void forceGotoPage(int pagenum) { if (pagenum <= 0) { pagenum = 0; } else if (pagenum >= curFile.getNumPages()) { pagenum = curFile.getNumPages() - 1; } // System.out.println("Going to page " + pagenum); curpage = pagenum; // update the page text field pageField.setText(String.valueOf(curpage + 1)); // fetch the page and show it in the appropriate place PDFPage pg = curFile.getPage(pagenum + 1); if (fspp != null) { fspp.showPage(pg); fspp.requestFocus(); } else { page.showPage(pg); page.requestFocus(); } // update the thumb panel if (doThumb) { thumbs.pageShown(pagenum); } // stop any previous page prepper, and start a new one if (pagePrep != null) { pagePrep.quit(); } pagePrep = new PagePreparer(pagenum); pagePrep.start(); setEnabling(); } /** * A class to pre-cache the next page for better UI response */ class PagePreparer extends Thread { int waitforPage; int prepPage; /** * Creates a new PagePreparer to prepare the page after the current * one. * @param waitforPage the current page number, 0 based */ public PagePreparer(int waitforPage) { setDaemon(true); setName(getClass().getName()); this.waitforPage = waitforPage; this.prepPage = waitforPage + 1; } public void quit() { waitforPage = -1; } public void run() { Dimension size = null; Rectangle2D clip = null; // wait for the current page // System.out.println("Preparer waiting for page " + (waitforPage + 1)); if (fspp != null) { fspp.waitForCurrentPage(); size = fspp.getCurSize(); clip = fspp.getCurClip(); } else if (page != null) { page.waitForCurrentPage(); size = page.getCurSize(); clip = page.getCurClip(); } if (waitforPage == curpage) { // don't go any further if the user changed pages. // System.out.println("Preparer generating page " + (prepPage + 2)); PDFPage pdfPage = curFile.getPage(prepPage + 1, true); if (pdfPage != null && waitforPage == curpage) { // don't go any further if the user changed pages // System.out.println("Generating image for page " + (prepPage + 2)); pdfPage.getImage(size.width, size.height, clip, null, true, true); // System.out.println("Generated image for page "+ (prepPage+2)); } } } } /** * Enable or disable all of the actions based on the current state. */ public void setEnabling() { boolean fileavailable = curFile != null; boolean pageshown = ((fspp != null) ? fspp.getPage() != null : page.getPage() != null); boolean printable = fileavailable && curFile.isPrintable(); pageField.setEnabled(fileavailable); printAction.setEnabled(printable); closeAction.setEnabled(fileavailable); fullScreenAction.setEnabled(pageshown); prevAction.setEnabled(pageshown); nextAction.setEnabled(pageshown); firstAction.setEnabled(fileavailable); lastAction.setEnabled(fileavailable); zoomToolAction.setEnabled(pageshown); fitInWindowAction.setEnabled(pageshown); zoomInAction.setEnabled(pageshown); zoomOutAction.setEnabled(pageshown); } /** * open a URL to a PDF file. The file is read in and processed * with an in-memory buffer. * * @param url * @throws java.io.IOException */ public void openFile(URL url) throws IOException { URLConnection urlConnection = url.openConnection(); int contentLength = urlConnection.getContentLength(); InputStream istr = urlConnection.getInputStream(); byte[] byteBuf = new byte[contentLength]; int offset = 0; int read = 0; while (read >= 0) { read = istr.read(byteBuf, offset, contentLength - offset); if (read > 0) { offset += read; } } if (offset != contentLength) { throw new IOException("Could not read all of URL file."); } ByteBuffer buf = ByteBuffer.allocate(contentLength); buf.put(byteBuf); openPDFByteBuffer(buf, url.toString(), url.getFile()); } /** *

Open a specific pdf file. Creates a DocumentInfo from the file, * and opens that.

* *

Note: Mapping the file locks the file until the PDFFile * is closed.

* * @param file the file to open * @throws IOException */ public void openFile(File file) throws IOException { // first open the file for random access RandomAccessFile raf = new RandomAccessFile(file, "r"); // extract a file channel FileChannel channel = raf.getChannel(); // now memory-map a byte-buffer ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); openPDFByteBuffer(buf, file.getPath(), file.getName()); } /** *

Open a specific pdf file. Creates a DocumentInfo from the file, * and opens that.

* *

Note: By not memory mapping the file its contents are * not locked down while PDFFile is open.

* * @param file the file to open */ public void openFileUnMapped(File file) throws IOException { DataInputStream istr = null; try { //load a pdf from a byte buffer // avoid using a RandomAccessFile but fill a ByteBuffer directly istr = new DataInputStream(new FileInputStream(file)); long len = file.length(); if (len > Integer.MAX_VALUE) { throw new IOException("File too long to decode: " + file.getName()); } int contentLength = (int) len; byte[] byteBuf = new byte[contentLength]; int offset = 0; int read = 0; while (read >= 0) { read = istr.read(byteBuf, offset, contentLength - offset); if (read > 0) { offset += read; } } ByteBuffer buf = ByteBuffer.allocate(contentLength); buf.put(byteBuf); openPDFByteBuffer(buf, file.getPath(), file.getName()); } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { if (istr != null) { try { istr.close(); } catch (Exception e) { // ignore error on close } } } } /** * open the ByteBuffer data as a PDFFile and start to process it. * * @param buf * @param path */ private void openPDFByteBuffer(ByteBuffer buf, String path, String name) { // create a PDFFile from the data PDFFile newfile = null; try { newfile = new PDFFile(buf); } catch (IOException ioe) { openError(path + " doesn't appear to be a PDF file." + "\n: " + ioe.getMessage ()); return; } // Now that we're reasonably sure this document is real, close the // old one. doClose(); // set up our document this.curFile = newfile; docName = name; setTitle(TITLE + ": " + docName); // set up the thumbnails if (doThumb) { thumbs = new ThumbPanel(curFile); thumbs.addPageChangeListener(this); thumbscroll.getViewport().setView(thumbs); thumbscroll.getViewport().setBackground(Color.gray); } setEnabling(); // display page 1. forceGotoPage(0); // if the PDF has an outline, display it. try { outline = curFile.getOutline(); } catch (IOException ioe) { } if (outline != null) { if (outline.getChildCount() > 0) { olf = new JDialog(this, "Outline"); olf.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); olf.setLocation(this.getLocation()); JTree jt = new JTree(outline); jt.setRootVisible(false); jt.addTreeSelectionListener(this); JScrollPane jsp = new JScrollPane(jt); olf.getContentPane().add(jsp); olf.pack(); olf.setVisible(true); } else { if (olf != null) { olf.setVisible(false); olf = null; } } } } /** * Display a dialog indicating an error. */ public void openError(String message) { JOptionPane.showMessageDialog(split, message, "Error opening file", JOptionPane.ERROR_MESSAGE); } /** * A file filter for PDF files. */ FileFilter pdfFilter = new FileFilter() { public boolean accept(File f) { return f.isDirectory() || f.getName().endsWith(".pdf"); } public String getDescription() { return "Choose a PDF file"; } }; private File prevDirChoice; /** * Ask the user for a PDF file to open from the local file system */ public void doOpen() { try { JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(prevDirChoice); fc.setFileFilter(pdfFilter); fc.setMultiSelectionEnabled(false); int returnVal = fc.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { try { prevDirChoice = fc.getSelectedFile(); openFile(fc.getSelectedFile()); } catch (IOException ioe) { ioe.printStackTrace(); } } } catch (Exception e) { JOptionPane.showMessageDialog(split, "Opening files from your local " + "disk is not available\nfrom the " + "Java Web Start version of this " + "program.\n", "Error opening directory", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } /** * Open a local file, given a string filename * @param name the name of the file to open */ public void doOpen(String name) { try { URL url = new URL(name); openFile(new URL(name)); } catch (IOException ioe) { try { openFile(new File(name)); } catch (IOException ex) { Logger.getLogger(PDFViewer.class.getName()).log(Level.SEVERE, null, ex); } } } /** * Posts the Page Setup dialog */ public void doPageSetup() { PrinterJob pjob = PrinterJob.getPrinterJob(); pformat = pjob.pageDialog(pformat); } /** * A thread for printing in. */ class PrintThread extends Thread { PDFPrintPage ptPages; PrinterJob ptPjob; public PrintThread(PDFPrintPage pages, PrinterJob pjob) { ptPages = pages; ptPjob = pjob; setName(getClass().getName()); } public void run() { try { ptPages.show(ptPjob); ptPjob.print(); } catch (PrinterException pe) { JOptionPane.showMessageDialog(PDFViewer.this, "Printing Error: " + pe.getMessage(), "Print Aborted", JOptionPane.ERROR_MESSAGE); } ptPages.hide(); } } /** * Print the current document. */ public void doPrint() { PrinterJob pjob = PrinterJob.getPrinterJob(); pjob.setJobName(docName); Book book = new Book(); PDFPrintPage pages = new PDFPrintPage(curFile); book.append(pages, pformat, curFile.getNumPages()); pjob.setPageable(book); if (pjob.printDialog()) { new PrintThread(pages, pjob).start(); } } /** * Close the current document. */ public void doClose() { if (thumbs != null) { thumbs.stop(); } if (olf != null) { olf.setVisible(false); olf = null; } if (doThumb) { thumbs = new ThumbPanel(null); thumbscroll.getViewport().setView(thumbs); } setFullScreenMode(false, false); page.showPage(null); curFile = null; setTitle(TITLE); setEnabling(); } /** * Shuts down all known threads. This ought to cause the JVM to quit * if the PDFViewer is the only application running. */ public void doQuit() { // if (thumbs != null) { // thumbs.stop(); // } doClose(); dispose(); System.exit(0); } /** * Turns on zooming */ public void doZoomTool() { if (fspp == null) { page.useZoomTool(true); } } /** * Turns off zooming; makes the page fit in the window */ public void doFitInWindow() { if (fspp == null) { page.useZoomTool(false); page.setClip(null); } } /** * Shows or hides the thumbnails by moving the split pane divider */ public void doThumbs(boolean show) { if (show) { split.setDividerLocation((int) thumbs.getPreferredSize().width + (int) thumbscroll.getVerticalScrollBar(). getWidth() + 4); } else { split.setDividerLocation(0); } } /** * Enter full screen mode * @param force true if the user should be prompted for a screen to * use in a multiple-monitor setup. If false, the user will only be * prompted once. */ public void doFullScreen(boolean force) { setFullScreenMode(fullScreen == null, force); } public void doZoom(double factor) { } // public void doOpenMeetingDoc(DocumentInfo doc) { // } /** * Goes to the next page */ public void doNext() { gotoPage(curpage + 1); } /** * Goes to the previous page */ public void doPrev() { gotoPage(curpage - 1); } /** * Goes to the first page */ public void doFirst() { gotoPage(0); } /** * Goes to the last page */ public void doLast() { gotoPage(curFile.getNumPages() - 1); } /** * Goes to the page that was typed in the page number text field */ public void doPageTyped() { int pagenum = -1; try { pagenum = Integer.parseInt(pageField.getText()) - 1; } catch (NumberFormatException nfe) { } if (pagenum >= curFile.getNumPages()) { pagenum = curFile.getNumPages() - 1; } if (pagenum >= 0) { if (pagenum != curpage) { gotoPage(pagenum); } } else { pageField.setText(String.valueOf(curpage)); } } /** * Runs the FullScreenMode change in another thread */ class PerformFullScreenMode implements Runnable { boolean force; public PerformFullScreenMode(boolean forcechoice) { force = forcechoice; } public void run() { fspp = new PagePanel(); fspp.setBackground(Color.black); page.showPage(null); fullScreen = new FullScreenWindow(fspp, force); fspp.addKeyListener(PDFViewer.this); gotoPage(curpage); fullScreenAction.setEnabled(true); } } /** * Starts or ends full screen mode. * @param full true to enter full screen mode, false to leave * @param force true if the user should be prompted for a screen * to use the second time full screen mode is entered. */ public void setFullScreenMode(boolean full, boolean force) { // curpage= -1; if (full && fullScreen == null) { fullScreenAction.setEnabled(false); new Thread(new PerformFullScreenMode(force), getClass().getName() + ".setFullScreenMode").start(); fullScreenButton.setSelected(true); } else if (!full && fullScreen != null) { fullScreen.close(); fspp = null; fullScreen = null; gotoPage(curpage); fullScreenButton.setSelected(false); } } public static void main(String args[]) { String fileName = null; boolean useThumbs = true; for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("-noThumb")) { useThumbs = false; } else if (args[i].equalsIgnoreCase("-help") || args[i].equalsIgnoreCase("-h") || args[i].equalsIgnoreCase("-?")) { System.out.println("java com.sun.awc.PDFViewer [flags] [file]"); System.out.println("flags: [-noThumb] [-help or -h or -?]"); System.exit(0); } else { fileName = args[i]; } } // start the viewer PDFViewer viewer; viewer = new PDFViewer(useThumbs); if (fileName != null) { viewer.doOpen(fileName); } } /** * Handle a key press for navigation */ public void keyPressed(KeyEvent evt) { int code = evt.getKeyCode(); if (code == evt.VK_LEFT) { doPrev(); } else if (code == evt.VK_RIGHT) { doNext(); } else if (code == evt.VK_UP) { doPrev(); } else if (code == evt.VK_DOWN) { doNext(); } else if (code == evt.VK_HOME) { doFirst(); } else if (code == evt.VK_END) { doLast(); } else if (code == evt.VK_PAGE_UP) { doPrev(); } else if (code == evt.VK_PAGE_DOWN) { doNext(); } else if (code == evt.VK_SPACE) { doNext(); } else if (code == evt.VK_ESCAPE) { setFullScreenMode(false, false); } } /** * Combines numeric key presses to build a multi-digit page number. */ class PageBuilder implements Runnable { int value = 0; long timeout; Thread anim; static final long TIMEOUT = 500; /** add the digit to the page number and start the timeout thread */ public synchronized void keyTyped(int keyval) { value = value * 10 + keyval; timeout = System.currentTimeMillis() + TIMEOUT; if (anim == null) { anim = new Thread(this); anim.setName(getClass().getName()); anim.start(); } } /** * waits for the timeout, and if time expires, go to the specified * page number */ public void run() { long now, then; synchronized (this) { now = System.currentTimeMillis(); then = timeout; } while (now < then) { try { Thread.sleep(timeout - now); } catch (InterruptedException ie) { } synchronized (this) { now = System.currentTimeMillis(); then = timeout; } } synchronized (this) { gotoPage(value - 1); anim = null; value = 0; } } } PageBuilder pb = new PageBuilder(); public void keyReleased(KeyEvent evt) { } /** * gets key presses and tries to build a page if they're numeric */ public void keyTyped(KeyEvent evt) { char key = evt.getKeyChar(); if (key >= '0' && key <= '9') { int val = key - '0'; pb.keyTyped(val); } } /** * Someone changed the selection of the outline tree. Go to the new * page. */ public void valueChanged(TreeSelectionEvent e) { if (e.isAddedPath()) { OutlineNode node = (OutlineNode) e.getPath().getLastPathComponent(); if (node == null) { return; } try { PDFAction action = node.getAction(); if (action == null) { return; } if (action instanceof GoToAction) { PDFDestination dest = ((GoToAction) action).getDestination(); if (dest == null) { return; } PDFObject page = dest.getPage(); if (page == null) { return; } int pageNum = curFile.getPageNumber(page); if (pageNum >= 0) { gotoPage(pageNum); } } } catch (IOException ioe) { ioe.printStackTrace(); } } } } pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/Flag.java0000644000175000017500000000363510732532577023153 0ustar twernertwerner/* * $Id: Flag.java,v 1.2 2007-12-20 18:33:33 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; /** * A generic synchronized flag, because Java doesn't have one. */ public class Flag { private boolean isSet; /** * Sets the flag. Any pending waitForFlag calls will now return. */ public synchronized void set() { isSet= true; notifyAll(); } /** * Clears the flag. Do this before calling waitForFlag. */ public synchronized void clear() { isSet= false; } /** * Waits for the flag to be set, if it is not set already. * This method catches InterruptedExceptions, so if you want * notification of interruptions, use interruptibleWaitForFlag * instead. */ public synchronized void waitForFlag() { if (!isSet) { try { wait(); } catch (InterruptedException ie) {} } } /** * Waits for the flag to be set, if it is not set already. */ public synchronized void interruptibleWaitForFlag() throws InterruptedException { if (!isSet) { wait(); } } } pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/0000755000175000017500000000000011622545441022205 5ustar twernertwernerpdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/open.gif0000644000175000017500000000034410730014314023623 0ustar twernertwernerGIF89a̴̳̽{f33! ,@>Id k "cqIڨR)!r;_ & R"!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/next.gif0000644000175000017500000000026710730014314023644 0ustar twernertwernerGIF89a!,)HN\T{ޝ2|5jtfo89@B!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/prev.gif0000644000175000017500000000026710730014314023642 0ustar twernertwernerGIF89a!,)H\T+7]]ʠmlryN@V!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/fit.gif0000644000175000017500000000046010730014314023443 0ustar twernertwernerGIF89a00a==n}}丸󋌢n= q !,W%dYZei=V$4k-0X B;= A&ki55*ޗ5P(y]tpf%!;!!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/zoomin.gif0000644000175000017500000000046010730014314024174 0ustar twernertwernerGIF89a00a==nĿ昙a0—~ !,W %dY`i0@L$kE XMa;1 ki55@*ޔudRM"y]tpf%!;!!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/first.gif0000644000175000017500000000031010730014314024002 0ustar twernertwernerGIF89a==nnn!,8P6`L a H ع&9 3 ?.`ͨ5#(#;!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/zoom.gif0000644000175000017500000000045710730014314023653 0ustar twernertwernerGIF89a00a==n󋌢n= q !,Y %dYN$6L3 l;5&E] !OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/fullscrn.gif0000644000175000017500000000063210730014314024512 0ustar twernertwernerGIF89aڴڳڳڳٱװկխӬҪЧͣɡǝÚ}}zzttssff33f!+,@dpH,SR"$@4mL"RQX<=ϩbuCJL 1|o,VqS(eBHW nMz+J[OHuw&oVB~DA!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/gfx/last.gif0000644000175000017500000000031010730014314023616 0ustar twernertwernerGIF89a==nnn!,8N4 `~@1 '@T3&Nc4!(4;!OCopyright 2000 by Sun Microsystems, Inc. All Rights Reserved. JLF GR Ver 1.0 ;pdfrenderer-0.9.0/demos/viewer/com/sun/pdfview/FullScreenWindow.java0000644000175000017500000001504611237133111025511 0ustar twernertwerner/* * $Id: FullScreenWindow.java,v 1.4 2009-08-07 23:18:33 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.Color; import java.awt.Dimension; import java.awt.DisplayMode; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; /** * A window that takes over the full screen. You can put exactly one * JComponent into the window. If there are multiple screens attached * to the computer, this class will display buttons on each screen so * that the user can select which one receives the full-screen window. */ public class FullScreenWindow { /** * The screen that the user last chose for displaying a * FullScreenWindow */ private static GraphicsDevice defaultScreen; /** The current screen for the FullScreenWindow */ private GraphicsDevice screen; /** The JFrame filling the screen */ private JFrame jf; /** * Whether this FullScreenWindow has been used. Each FullScreenWindow * can only be displayed once. */ private boolean dead= false; /** * Create a full screen window containing a JComponent, and ask the * user which screen they'd like to use if more than one is present. * @param part the JComponent to display * @param forcechoice true if you want force the display of the screen * choice buttons. If false, buttons will only display if the user * hasn't previously picked a screen. */ public FullScreenWindow(JComponent part, boolean forcechoice) { // super(); init(part, forcechoice); } /** * Create a full screen window containing a JComponent. The user * will only be asked which screen to display on if there are multiple * monitors attached and the user hasn't already made a choice. * @param part the JComponent to display */ public FullScreenWindow(JComponent part) { // super(); init(part, false); } /** * Close the full screen window. This particular FullScreenWindow * object cannot be used again. */ public void close() { dead= true; flag.set(); screen.setFullScreenWindow(null); if (jf!=null) { jf.dispose(); } } /** * Create the window, asking for which screen to use if there are * multiple monitors and either forcechoice is true, or the user * hasn't already picked a screen. * @param part the JComponent to display * @param forcechoice false if user shouldn't be asked twice which * of several monitors to use. */ private void init(JComponent part, boolean forcechoice) { if (forcechoice) { defaultScreen= null; } screen= null; GraphicsEnvironment ge= GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice screens[]= ge.getScreenDevices(); if (defaultScreen!=null) { for (int i=0; i 100% Java PDF viewer. pdfrenderer-0.9.0/src/test/TestType1CFont.java0000644000175000017500000013001611237133111021155 0ustar twernertwerner/* * $Id: TestType1CFont.java,v 1.5 2009-08-07 23:18:32 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package test; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.awt.geom.*; import com.sun.pdfview.font.*; public class TestType1CFont extends JPanel implements KeyListener { int encoding[] = new int[256]; // glyph at position i has code encoding[i] int glyphnames[]; // glyph at position i has name SID glyphnames[i] String names[]; // extra names for this font (others in FontSupport) // String safenames[]; // names without high-bit characters HashMap charset = new HashMap(); ArrayList charnames = new ArrayList(); int charcounter = -1; byte[] data; int pos; byte[] subrs[]; float[] stack = new float[100]; int stackptr = 0; AffineTransform at = new AffineTransform(0.001f, 0, 0, 0.001f, 0, 0); int num; float fnum; int type; static int CMD = 0; static int NUM = 1; static int FLT = 2; public boolean isRequestFocusEnabled() { return true; } public TestType1CFont(InputStream is) throws IOException { super(); setPreferredSize(new Dimension(800, 800)); addKeyListener(this); BufferedInputStream bis = new BufferedInputStream(is); int count = 0; ArrayList al = new ArrayList(); byte b[] = new byte[32000]; int len; while ((len = bis.read(b, 0, b.length)) >= 0) { byte[] c = new byte[len]; System.arraycopy(b, 0, c, 0, len); al.add(c); count += len; b = new byte[32000]; } data = new byte[count]; len = 0; for (int i = 0; i < al.size(); i++) { byte from[] = al.get(i); System.arraycopy(from, 0, data, len, from.length); len += from.length; } pos = 0; // printData(); parse(); // TODO: free up (set to null) unused structures (data, subrs, stack) } GlyphData showing; String showname; Font gfont = new Font("Sans-serif", Font.PLAIN, 24).deriveFont(AffineTransform.getScaleInstance(1, -1)); Color fillColor = new Color(0xe0, 0xff, 0xff); public void keyTyped(KeyEvent evt) { } public void keyReleased(KeyEvent evt) { } public void keyPressed(KeyEvent evt) { if (evt.getKeyCode() == evt.VK_RIGHT) { charcounter++; if (charcounter >= charnames.size()) { charcounter = 0; } showing = readGlyph((String) charnames.get(charcounter)); } else if (evt.getKeyCode() == evt.VK_LEFT) { charcounter--; if (charcounter < 0) { charcounter = charnames.size() - 1; } showing = readGlyph((String) charnames.get(charcounter)); } else { char c = evt.getKeyChar(); // System.out.println("Got char: "+name); showing = readGlyph(FontSupport.stdNames[FontSupport.standardEncoding[(int) c & 0xff]]); } repaint(); } public void paint(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.white); g2.fillRect(0, 0, getWidth(), getHeight()); AffineTransform at = new AffineTransform(0.5, 0, 0, -0.5, 30, getHeight() * 3 / 4); g2.transform(at); g2.setColor(Color.black); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // System.out.println("Showing="+showing); if (showing != null) { showing.draw(g2); } } private void printData() { char[] parts = new char[17]; int partsloc = 0; for (int i = 0; i < data.length; i++) { int d = ((int) data[i]) & 0xff; if (d == 0) { parts[partsloc++] = '.'; } else if (d < 32 || d >= 127) { parts[partsloc++] = '?'; } else { parts[partsloc++] = (char) d; } if (d < 16) { System.out.print("0" + Integer.toHexString(d)); } else { System.out.print(Integer.toHexString(d)); } if ((i & 15) == 15) { System.out.println(" " + new String(parts)); partsloc = 0; } else if ((i & 7) == 7) { System.out.print(" "); parts[partsloc++] = ' '; } else if ((i & 1) == 1) { System.out.print(" "); } } System.out.println(); } private int readNext(boolean charstring) { num = (int) (data[pos++]) & 0xff; if (num == 30 && !charstring) { // goofy floatingpoint rep readFNum(); return type = FLT; } else if (num == 28) { num = (((int) data[pos]) << 8) + (((int) data[pos + 1]) & 0xff); pos += 2; return type = NUM; } else if (num == 29 && !charstring) { num = (((int) data[pos] & 0xff) << 24) | (((int) data[pos + 1] & 0xff) << 16) | (((int) data[pos + 2] & 0xff) << 8) | (((int) data[pos + 3] & 0xff)); pos += 4; return type = NUM; } else if (num == 12) { // two-byte command num = 1000 + ((int) (data[pos++]) & 0xff); return type = CMD; } else if (num < 32) { return type = CMD; } else if (num < 247) { num -= 139; return type = NUM; } else if (num < 251) { num = (num - 247) * 256 + (((int) data[pos++]) & 0xff) + 108; return type = NUM; } else if (num < 255) { num = -(num - 251) * 256 - (((int) data[pos++]) & 0xff) - 108; return type = NUM; } else if (!charstring) { // dict shouldn't have a 255 code printData(); throw new RuntimeException("Got a 255 code while reading dict"); } else { // num was 255 fnum = ((((int) data[pos] & 0xff) << 24) | (((int) data[pos + 1] & 0xff) << 16) | (((int) data[pos + 2] & 0xff) << 8) | (((int) data[pos + 3] & 0xff))) / 65536f; pos += 4; return type = FLT; } } public void readFNum() { // work in nybbles: 0-9=0-9, a=. b=E, c=E-, d=rsvd e=neg f=end float f = 0; boolean neg = false; int exp = 0; int eval = 0; float mul = 1; byte work = data[pos++]; while (true) { if (work == (byte) 0xdd) { work = data[pos++]; } int nyb = (work >> 4) & 0xf; work = (byte) ((work << 4) | 0xd); if (nyb < 10) { if (exp != 0) { // working on the exponent eval = eval * 10 + nyb; } else if (mul == 1) { // working on an int f = f * 10 + nyb; } else { // working on decimal part f += nyb * mul; mul /= 10f; } } else if (nyb == 0xa) { // decimal mul = 0.1f; } else if (nyb == 0xb) { // E+ exp = 1; } else if (nyb == 0xc) { // E- exp = -1; } else if (nyb == 0xe) { // neg neg = true; } else { break; } } fnum = (neg ? -1 : 1) * f * (float) Math.pow(10, eval * exp); } private int readInt(int len) { int n = 0; for (int i = 0; i < len; i++) { n = (n << 8) | (((int) data[pos++]) & 0xff); } return n; } private int readByte() { return ((int) data[pos++]) & 0xff; } // DICT structure: // operand operator operand operator ... // INDEX structure: // count(2) offsize [offset offset ... offset] data // offset array has count+1 entries // data starts at 3+(count+1)*offsize // offset for data is offset+2+(count+1)*offsize public int getIndexSize(int loc) { // System.out.println("Getting size of index at "+loc); int hold = pos; pos = loc; int count = readInt(2); if (count == 0) { return 2; } int encsz = readByte(); // pos is now at the first offset. last offset is at count*encsz pos += count * encsz; int end = readInt(encsz); pos = hold; return 2 + (count + 1) * encsz + end; } class Range { private int start; private int len; public Range(int start, int len) { this.start = start; this.len = len; } public final int getStart() { return start; } public final int getLen() { return len; } public final int getEnd() { return start + len; } } public Range getIndexEntry(int index, int id) { int hold = pos; pos = index; int count = readInt(2); int encsz = readByte(); pos += encsz * id; int from = readInt(encsz); Range r = new Range(from + 2 + index + encsz * (count + 1), readInt(encsz) - from); pos = hold; return r; } // Top DICT: NAME CODE DEFAULT // charstringtype 12 6 2 // fontmatrix 12 7 0.001 0 0 0.001 // charset 15 - (offset) names of glyphs (ref to name idx) // encoding 16 - (offset) array of codes // CharStrings 17 - (offset) // Private 18 - (size, offset) // glyph at position i in CharStrings has name charset[i] // and code encoding[i] int charstringtype = 2; float temps[] = new float[32]; int charsetbase = 0; int encodingbase = 0; int charstringbase = 0; int privatebase = 0; int privatesize = 0; int gsubrbase = 0; int lsubrbase = 0; int gsubrsoffset = 0; int lsubrsoffset = 0; int defaultWidthX = 0; int nominalWidthX = 0; int nglyphs = 1; private void readDict(Range r) { // System.out.println("reading dictionary from "+r.getStart()+" to "+r.getEnd()); pos = r.getStart(); while (pos < r.getEnd()) { int cmd = readCommand(false); if (cmd == 1006) { // charstringtype, default=2 charstringtype = (int) stack[0]; } else if (cmd == 1007) { // fontmatrix if (stackptr == 4) { at = new AffineTransform((float) stack[0], (float) stack[1], (float) stack[2], (float) stack[3], 0, 0); } else { at = new AffineTransform((float) stack[0], (float) stack[1], (float) stack[2], (float) stack[3], (float) stack[4], (float) stack[5]); } } else if (cmd == 15) { // charset charsetbase = (int) stack[0]; } else if (cmd == 16) { // encoding encodingbase = (int) stack[0]; } else if (cmd == 17) { // charstrings charstringbase = (int) stack[0]; } else if (cmd == 18) { // private privatesize = (int) stack[0]; privatebase = (int) stack[1]; } else if (cmd == 19) { // subrs (in Private dict) lsubrbase = (int) stack[0]; lsubrsoffset = calcoffset(lsubrbase); } else if (cmd == 20) { // defaultWidthX (in Private dict) defaultWidthX = (int) stack[0]; } else if (cmd == 21) { // nominalWidthX (in Private dict) nominalWidthX = (int) stack[0]; } stackptr = 0; } } private int readCommand(boolean charstring) { while (true) { int type = readNext(charstring); if (type == CMD) { System.out.print("CMD= " + num + ", args="); for (int i = 0; i < stackptr; i++) { System.out.print(" " + stack[i]); } System.out.println(); return num; } else { stack[stackptr++] = (type == NUM) ? (float) num : (float) fnum; } } } private void readEncodingData(int base) { if (base == 0) { // this is the StandardEncoding System.out.println("**** STANDARD ENCODING!"); // TODO: copy standard encoding } else if (base == 1) { // this is the expert encoding System.out.println("**** EXPERT ENCODING!"); // TODO: copy ExpertEncoding } else { pos = base; int encodingtype = readByte(); if ((encodingtype & 127) == 0) { System.out.println("**** Type 0 Encoding:"); int ncodes = readByte(); for (int i = 1; i < ncodes + 1; i++) { encoding[i] = readByte(); System.out.println("Encoding[" + i + "] = " + encoding[i]); } } else if ((encodingtype & 127) == 1) { System.out.println("**** Type 1 Encoding:"); int nranges = readByte(); int pos = 0; for (int i = 0; i < nranges; i++) { int start = readByte(); int more = readByte(); for (int j = start; j < start + more + 1; j++) { System.out.println("Encoding[" + pos + "] = " + j); encoding[pos++] = j; } } } else { System.out.println("Bad encoding type: " + encodingtype); } // TODO: now check for supplemental encoding data } } private void readGlyphNames(int base) { if (base == 0) { System.out.println("**** Identity glyphNames"); glyphnames = new int[229]; for (int i = 0; i < glyphnames.length; i++) { glyphnames[i] = i; } return; } else if (base == 1) { System.out.println("**** Type1CExpertCharset glyphNames"); glyphnames = FontSupport.type1CExpertCharset; return; } else if (base == 2) { System.out.println("**** Type1CExpertSubCharset glyphNames"); glyphnames = FontSupport.type1CExpertSubCharset; return; } System.out.print("**** Custom glyphNames Type "); // nglyphs has already been set. glyphnames = new int[nglyphs]; glyphnames[0] = 0; pos = base; int type = readByte(); if (type == 0) { System.out.println("0"); for (int i = 1; i < nglyphs; i++) { glyphnames[i] = readInt(2); System.out.println("glyphnames[" + i + "] = " + glyphnames[i]); } } else if (type == 1) { System.out.println("1"); int n = 1; while (n < nglyphs) { int sid = readInt(2); int range = readByte() + 1; for (int i = 0; i < range; i++) { System.out.println("glyphnames[" + n + "] = " + sid); glyphnames[n++] = sid++; } } } else if (type == 2) { System.out.println("2"); int n = 1; while (n < nglyphs) { int sid = readInt(2); int range = readInt(2) + 1; for (int i = 0; i < range; i++) { System.out.println("glyphnames[" + n + "] = " + sid); glyphnames[n++] = sid++; } } } } private void readNames(int base) { pos = base; int nextra = readInt(2); names = new String[nextra]; // safenames= new String[nextra]; for (int i = 0; i < nextra; i++) { Range r = getIndexEntry(base, i); names[i] = new String(data, r.getStart(), r.getLen()); System.out.println("Read name: " + i + " from " + r.getStart() + " to " + r.getEnd() + ": " + safe(names[i])); } } private void parse() { int majorVersion = readByte(); int minorVersion = readByte(); int hdrsz = readByte(); int offsize = readByte(); // jump over rest of header: base of font names index int fnames = hdrsz; // offset in the file of the array of font dicts int topdicts = fnames + getIndexSize(fnames); // offset in the file of local names int names = topdicts + getIndexSize(topdicts); // offset in the file of the array of global subroutines gsubrbase = names + getIndexSize(names); gsubrsoffset = calcoffset(gsubrbase); // read extra names readNames(names); // does this file have more than one font? pos = topdicts; if (readInt(2) != 1) { printData(); throw new RuntimeException("More than one font in this file!"); } // read first dict System.out.println("TOPDICT[0]:"); readDict(getIndexEntry(topdicts, 0)); // read the private dictionary System.out.println("PRIVATE DICT:"); readDict(new Range(privatebase, privatesize)); // calculate the number of glyphs pos = charstringbase; nglyphs = readInt(2); // now get the glyph names System.out.println("GLYPHNAMES:"); readGlyphNames(charsetbase); // now figure out the encoding System.out.println("ENCODING:"); readEncodingData(encodingbase); // now get the glyphs System.out.println("GLYPHS:"); readGlyphs(charstringbase); } private String safe(String src) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < src.length(); i++) { char c = src.charAt(i); if (c >= 32 && c < 128) { sb.append(c); } else { sb.append("<" + (int) c + ">"); } } return sb.toString(); } class GlyphPoint { float x, y; boolean curvecontrol; GeneralPath gp; public GlyphPoint(float x, float y, boolean curvectrl) { this.x = x; this.y = y; this.curvecontrol = curvectrl; gp = new GeneralPath(); if (curvectrl) { gp.moveTo(x - 4, y - 4); gp.lineTo(x + 4, y + 4); gp.moveTo(x - 4, y + 4); gp.lineTo(x + 4, y - 4); } else { gp.moveTo(x - 4, y - 4); gp.lineTo(x - 4, y + 4); gp.lineTo(x + 4, y + 4); gp.lineTo(x + 4, y - 4); gp.closePath(); } } } class GlyphData { GeneralPath gp; GeneralPath advp; ArrayList points; float x, y; float advance; String name; public GlyphData() { gp = new GeneralPath(); // advp= new GeneralPath(); points = new ArrayList (); x = y = 0; } public void setName(String name) { this.name = name; } public void lineTo(float x, float y) { gp.lineTo(x, y); this.x = x; this.y = y; points.add(new GlyphPoint(x, y, false)); } public void moveTo(float x, float y) { gp.moveTo(x, y); this.x = x; this.y = y; points.add(new GlyphPoint(x, y, false)); } public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) { gp.curveTo(x1, y1, x2, y2, x3, y3); this.x = x3; this.y = y3; points.add(new GlyphPoint(x1, y1, true)); points.add(new GlyphPoint(x2, y2, true)); points.add(new GlyphPoint(x3, y3, false)); } public void closePath() { gp.closePath(); } public void addGlyph(GlyphData gv, float x, float y) { AffineTransform at = AffineTransform.getTranslateInstance(x, y); PathIterator pi = gv.gp.getPathIterator(at); float[] coords = new float[6]; while (!pi.isDone()) { int type = pi.currentSegment(coords); switch (type) { case PathIterator.SEG_MOVETO: moveTo(coords[0], coords[1]); break; case PathIterator.SEG_LINETO: lineTo(coords[0], coords[1]); break; case PathIterator.SEG_CUBICTO: curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); break; case PathIterator.SEG_CLOSE: closePath(); break; default: System.out.println("Unknown path type: " + type); break; } pi.next(); } } public void setAdvance(float adv) { advance = adv; advp = new GeneralPath(); advp.moveTo(-2, -2); advp.lineTo(2, 2); advp.moveTo(-2, 2); advp.lineTo(2, -2); advp.moveTo(adv - 2, -2); advp.lineTo(adv, 0); advp.lineTo(adv + 2, -2); advp.moveTo(adv, 0); advp.lineTo(adv, -8); } public void draw(Graphics2D g) { g.setColor(fillColor); g.fill(gp); g.setColor(Color.black); g.draw(gp); for (int i = 0; i < points.size(); i++) { GlyphPoint p = points.get(i); g.setColor(Color.red); g.draw(p.gp); g.setColor(Color.blue); g.setFont(gfont); g.drawString(String.valueOf(i), p.x + 3, p.y + 3); } g.setColor(Color.black); // System.out.println("Advance: "+advance); g.draw(advp); if (name != null) { g.setFont(gfont); g.drawString(name, 0, -40); } } } private void readGlyphs(int base) { for (int i = 1; i < nglyphs; i++) { System.out.println("Reading glyph " + safe(getSID(glyphnames[i]))); charnames.add(getSID(glyphnames[i])); } } /** * Read a single glyph, given its offset */ public GlyphData readGlyph(String sid) { int index = getNameIndex(sid); // now find the glyph with that name for (int i = 0; i < glyphnames.length; i++) { if (glyphnames[i] == index) { return readGlyph(i); } } // not found -- return the unknown glyph return readGlyph(0); } /** * Read a glyph, given an index */ public GlyphData readGlyph(int index) { String sid = getSID(index); if (charset.containsKey(sid)) { return (GlyphData) charset.get(sid); } Range r = getIndexEntry(charstringbase, index); FlPoint pt = new FlPoint(); GlyphData gd = new GlyphData(); parseGlyph(r, gd, pt); gd.setName(sid); charset.put(sid, gd); return gd; } /** * build an accented character out of two pre-defined glyphs. * @param x the x offset of the accent * @param y the y offset of the accent * @param a the index of the base glyph * @param b the index of the accent glyph * @param gp the GeneralPath into which the combined glyph will be * written. */ private void buildAccentChar(float x, float y, float a, float b, GlyphData gv) { System.out.println("Building accent character!!!!!!"); for (int i = 0; i < nglyphs; i++) { if (encoding[i] == (int) a) { gv.addGlyph(readGlyph(i + 1), x, y); } else if (encoding[i] == (int) b) { gv.addGlyph(readGlyph(i + 1), 0, 0); } } /* if (shapes[b]!=null) { gp.append(shapes[b], false); } if (shapes[a]!=null) { gp.append(shapes[a], false); }*/ } public int calcoffset(int base) { int len = getIndexSize(base); if (len < 1240) { return -107; } else if (len < 33900) { return -1131; } else { return -32768; } } public String getSID(int id) { if (id < FontSupport.stdNames.length) { return FontSupport.stdNames[id]; } else { id -= FontSupport.stdNames.length; return names[id]; } } /** * get the index of a particular name. The name table starts with * the standard names in FontSupport.stdNames, and is appended by * any names in the name table from this font's dictionary. */ private int getNameIndex(String name) { int val = FontSupport.findName(name, FontSupport.stdNames); if (val == -1) { val = FontSupport.findName(name, names) + FontSupport.stdNames.length; } if (val == -1) { val = 0; } return val; } public void parseGlyph(Range r, GlyphData gp, FlPoint pt) { pos = r.getStart(); int i; float x1, y1, x2, y2, x3, y3, ybase; int hold; int stemhints = 0; gp.setAdvance(defaultWidthX); while (pos < r.getEnd()) { int cmd = readCommand(true); hold = 0; switch (cmd) { case 1: // hstem case 3: // vstem if ((stackptr & 1) == 1) { gp.setAdvance(nominalWidthX + stack[0]); } stackptr = 0; break; case 4: // vmoveto if (stackptr > 1) { // this is the first call, arg1 is width gp.setAdvance(nominalWidthX + stack[0]); stack[0] = stack[1]; } pt.y += stack[0]; if (pt.open) { gp.closePath(); } pt.open = false; gp.moveTo(pt.x, pt.y); stackptr = 0; break; case 5: // rlineto for (i = 0; i < stackptr;) { pt.x += stack[i++]; pt.y += stack[i++]; gp.lineTo(pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 6: // hlineto for (i = 0; i < stackptr;) { if ((i & 1) == 0) { pt.x += stack[i++]; } else { pt.y += stack[i++]; } gp.lineTo(pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 7: // vlineto for (i = 0; i < stackptr;) { if ((i & 1) == 0) { pt.y += stack[i++]; } else { pt.x += stack[i++]; } gp.lineTo(pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 8: // rrcurveto for (i = 0; i < stackptr;) { x1 = pt.x + stack[i++]; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2 + stack[i++]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 10: // callsubr hold = pos; i = (int) stack[--stackptr] + lsubrsoffset; Range lsubr = getIndexEntry(lsubrbase, i); parseGlyph(lsubr, gp, pt); pos = hold; break; case 11: // return return; case 14: // endchar if (stackptr == 5) { buildAccentChar(stack[1], stack[2], stack[3], stack[4], gp); } if (pt.open) { gp.closePath(); } pt.open = false; stackptr = 0; return; case 18: // hstemhm if ((stackptr & 1) == 1) { gp.setAdvance(nominalWidthX + stack[0]); } stemhints += stackptr / 2; stackptr = 0; break; case 19: // hintmask case 20: // cntrmask if ((stackptr & 1) == 1) { gp.setAdvance(nominalWidthX + stack[0]); } stemhints += stackptr / 2; System.out.println("Added " + stackptr + " extra bits; skipping " + ((stemhints - 1) / 8 + 1) + " from " + stemhints); pos += (stemhints - 1) / 8 + 1; stackptr = 0; break; case 21: // rmoveto if (stackptr > 2) { gp.setAdvance(nominalWidthX + stack[0]); stack[0] = stack[1]; stack[1] = stack[2]; } pt.x += stack[0]; pt.y += stack[1]; if (pt.open) { gp.closePath(); } gp.moveTo(pt.x, pt.y); pt.open = false; stackptr = 0; break; case 22: // hmoveto if (stackptr > 1) { gp.setAdvance(nominalWidthX + stack[0]); stack[0] = stack[1]; } pt.x += stack[0]; if (pt.open) { gp.closePath(); } gp.moveTo(pt.x, pt.y); pt.open = false; stackptr = 0; break; case 23: // vstemhm if ((stackptr & 1) == 1) { gp.setAdvance(nominalWidthX + stack[0]); } stemhints += stackptr / 2; stackptr = 0; break; case 24: // rcurveline for (i = 0; i < stackptr - 2;) { x1 = pt.x + stack[i++]; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2 + stack[i++]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); } pt.x += stack[i++]; pt.y += stack[i++]; gp.lineTo(pt.x, pt.y); pt.open = true; stackptr = 0; break; case 25: // rlinecurve for (i = 0; i < stackptr - 6;) { pt.x += stack[i++]; pt.y += stack[i++]; gp.lineTo(pt.x, pt.y); } x1 = pt.x + stack[i++]; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2 + stack[i++]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 26: // vvcurveto i = 0; if ((stackptr & 1) == 1) { // odd number of arguments pt.x += stack[i++]; } while (i < stackptr) { x1 = pt.x; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2; pt.y = y2 + stack[i++]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 27: // hhcurveto i = 0; if ((stackptr & 1) == 1) { // odd number of arguments pt.y += stack[i++]; } while (i < stackptr) { x1 = pt.x + stack[i++]; y1 = pt.y; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 29: // callgsubr hold = pos; i = (int) stack[--stackptr] + gsubrsoffset; Range gsubr = getIndexEntry(gsubrbase, i); parseGlyph(gsubr, gp, pt); pos = hold; break; case 30: // vhcurveto hold = 4; case 31: // hvcurveto for (i = 0; i < stackptr;) { boolean hv = (((i + hold) & 4) == 0); x1 = pt.x + (hv ? stack[i++] : 0); y1 = pt.y + (hv ? 0 : stack[i++]); x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + (hv ? 0 : stack[i++]); pt.y = y2 + (hv ? stack[i++] : 0); if (i == stackptr - 1) { if (hv) { pt.x += stack[i++]; } else { pt.y += stack[i++]; } } gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 1003: // and x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = ((x1 != 0) && (y1 != 0)) ? 1 : 0; break; case 1004: // or x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = ((x1 != 0) || (y1 != 0)) ? 1 : 0; break; case 1005: // not x1 = stack[--stackptr]; stack[stackptr++] = (x1 == 0) ? 1 : 0; break; case 1009: // abs stack[stackptr - 1] = Math.abs(stack[stackptr - 1]); break; case 1010: // add x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = x1 + y1; break; case 1011: // sub x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = y1 - x1; break; case 1012: // div x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = y1 / x1; break; case 1014: // neg stack[stackptr - 1] = -stack[stackptr - 1]; break; case 1015: // eq x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = (x1 == y1) ? 1 : 0; break; case 1018: // drop stackptr--; break; case 1020: // put i = (int) stack[--stackptr]; x1 = stack[--stackptr]; temps[i] = x1; break; case 1021: // get i = (int) stack[--stackptr]; stack[stackptr++] = temps[i]; break; case 1022: // ifelse if (stack[stackptr - 2] > stack[stackptr - 1]) { stack[stackptr - 4] = stack[stackptr - 3]; } stackptr -= 3; break; case 1023: // random stack[stackptr++] = (float) Math.random(); break; case 1024: // mul x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = y1 * x1; break; case 1026: // sqrt stack[stackptr - 1] = (float) Math.sqrt(stack[stackptr - 1]); break; case 1027: // dup x1 = stack[stackptr - 1]; stack[stackptr++] = x1; break; case 1028: // exch x1 = stack[stackptr - 1]; stack[stackptr - 1] = stack[stackptr - 2]; stack[stackptr - 2] = x1; break; case 1029: // index i = (int) stack[stackptr - 1]; if (i < 0) { i = 0; } stack[stackptr - 1] = stack[stackptr - 2 - i]; break; case 1030: // roll i = (int) stack[--stackptr]; int n = (int) stack[--stackptr]; // roll n number by i (+ = upward) if (i > 0) { i = i % n; } else { i = n - (-i % n); } // x x x x i y y y -> y y y x x x x i (where i=3) if (i > 0) { float roll[] = new float[n]; System.arraycopy(stack, stackptr - 1 - i, roll, 0, i); System.arraycopy(stack, stackptr - 1 - n, roll, i, n - i); System.arraycopy(roll, 0, stack, stackptr - 1 - n, n); } break; case 1034: // hflex x1 = pt.x + stack[0]; y1 = ybase = pt.y; x2 = x1 + stack[1]; y2 = y1 + stack[2]; pt.x = x2 + stack[3]; pt.y = y2; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[4]; y1 = pt.y; x2 = x1 + stack[5]; y2 = ybase; pt.x = x2 + stack[6]; pt.y = y2; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 1035: // flex x1 = pt.x + stack[0]; y1 = pt.y + stack[1]; x2 = x1 + stack[2]; y2 = y1 + stack[3]; pt.x = x2 + stack[4]; pt.y = y2 + stack[5]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[6]; y1 = pt.y + stack[7]; x2 = x1 + stack[8]; y2 = y1 + stack[9]; pt.x = x2 + stack[10]; pt.y = y2 + stack[11]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 1036: // hflex1 ybase = pt.y; x1 = pt.x + stack[0]; y1 = pt.y + stack[1]; x2 = x1 + stack[2]; y2 = y1 + stack[3]; pt.x = x2 + stack[4]; pt.y = y2; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[5]; y1 = pt.y; x2 = x1 + stack[6]; y2 = y1 + stack[7]; pt.x = x2 + stack[8]; pt.y = ybase; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 1037: // flex1 ybase = pt.y; float xbase = pt.x; x1 = pt.x + stack[0]; y1 = pt.y + stack[1]; x2 = x1 + stack[2]; y2 = y1 + stack[3]; pt.x = x2 + stack[4]; pt.y = y2 + stack[5]; gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[6]; y1 = pt.y + stack[7]; x2 = x1 + stack[8]; y2 = y1 + stack[9]; if (Math.abs(x2 - xbase) > Math.abs(y2 - ybase)) { pt.x = x2 + stack[10]; pt.y = ybase; } else { pt.x = xbase; pt.y = y2 + stack[10]; } gp.curveTo(x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; default: System.out.println("ERROR! TYPE1C CHARSTRING CMD IS " + cmd); break; } } } public static void main(String args[]) { if (args.length != 1) { System.out.println("Need the name of a cff font."); System.exit(0); } JFrame jf = new JFrame("Font test: " + args[0]); try { FileInputStream fis = new FileInputStream(args[0]); TestType1CFont panel = new TestType1CFont(fis); jf.getContentPane().add(panel); jf.pack(); jf.setVisible(true); panel.requestFocus(); } catch (IOException ioe) { } } } pdfrenderer-0.9.0/src/test/Type1Decode.java0000644000175000017500000001314310732532577020512 0ustar twernertwerner/* * $Id: Type1Decode.java,v 1.2 2007-12-20 18:33:32 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package test; /* * Type1Decode.java * * Created on August 28, 2003, 11:54 AM */ import com.sun.pdfview.HexDump; import java.io.*; /** * * @author jkaplan */ public class Type1Decode { private static byte[] decrypt(byte[]d, int start, int end, int key, int skip) { if (end-start-skip<0) { skip= 0; } byte[] o= new byte[end-start-skip]; int r= key; int ipos; int c1= 52845; int c2= 22719; for(ipos= start; ipos>8))&0xff; if (ipos - start < 16) { System.out.println("c = " + Integer.toHexString(c) + ", p = " + Integer.toHexString(p) + ", r = " + Integer.toHexString(r)); } r= ((c+r)*c1+c2)&0xffff; if (ipos-start-skip>=0) { o[ipos-start-skip]= (byte)p; } } return o; } private static byte[] readASCII(byte[] data, int start, int end) { // each byte of output is derived from one character (two bytes) of // input byte[] o = new byte[(end - start) / 2]; int count = 0; int bit = 0; for (int loc = start; loc < end ; loc ++) { char c = (char) (data[loc] & 0xff); byte b = (byte) 0; if (c >= '0' && c <= '9') { b = (byte) (c - '0'); } else if (c >= 'a' && c <= 'f') { b = (byte) (10 + (c - 'a')); } else if (c >= 'A' && c <= 'F') { b = (byte) (10 + (c - 'A')); } else { // linefeed or something. Skip. continue; } // which half of the byte are we? if ((bit++ % 2) == 0) { o[count] = (byte) (b << 4); } else { o[count++] |= b; } } return o; } private static boolean isASCII(byte[] data, int start) { // look at the first 4 bytes for (int i = start; i < start + 4; i++) { // get the byte as a character char c = (char) (data[i] & 0xff); if (c >= '0' && c <= '9') { continue; } else if (c >= 'a' && c <= 'f') { continue; } else if (c >= 'A' && c <= 'F') { continue; } else { // out of range return false; } } // all were in range, so it is ASCII return true; } /** * @param args the command line arguments */ public static void main(String[] args) { if (args.length < 1) { System.out.println("Usage:"); System.out.println(" Type1Decode "); System.exit(-1); } try { File file = new File(args[0]); if (!file.exists() || !file.canRead()) { System.out.println("Can't read file: " + args[0]); System.exit(-1); } FileInputStream fis = new FileInputStream(file); byte[] data = new byte[(int) file.length()]; int cur = 0; while (cur < file.length()) { cur += fis.read(data, cur, data.length - cur); } int start = 0; if ((data[0] & 0xff)== 0x80) { start = (data[2] & 0xff); start |= (data[3] & 0xff) << 8; start |= (data[4] & 0xff) << 16; start |= (data[5] & 0xff) << 24; start += 6; } else if (args.length > 1) { start = Integer.parseInt(args[1]); } else { System.out.println("Unable to read size"); System.exit(-1); } int size = data.length - start; if (isASCII(data, start)) { data = readASCII(data, start, size); start = 0; size = data.length; } else if((data[start] & 0xff) == 0x80) { size = (data[start + 2] & 0xff); size |= (data[start + 3] & 0xff) << 8; size |= (data[start + 4] & 0xff) << 16; size |= (data[start + 5] & 0xff) << 24; start += 6; } byte[] outData = decrypt(data, start, start + size, 55665, 4); HexDump.printData(outData); } catch (Exception ex) { ex.printStackTrace(); } } } pdfrenderer-0.9.0/src/test/README0000644000175000017500000000072310725114532016406 0ustar twernertwernerTo test on a file, cd to this directory and type: % java SlideIndex or % java Presenter Note that there are many, many pdf files that either won't render correctly, throw exceptions, or render mostly correctly except for some odd characters. Please note those files, and let us know about what went wrong, or dig into the code and fix it yourself. I don't suggest the latter until we get around to documenting the code. :) pdfrenderer-0.9.0/src/test/FontToy.java0000644000175000017500000004467511145024767020020 0ustar twernertwerner/* * $Id: FontToy.java,v 1.5 2009-02-12 13:53:55 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package test; /* * FontToy.java * * Created on September 15, 2003, 7:38 AM */ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Dimension; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Image; import java.awt.Font; import java.awt.event.*; import java.awt.geom.*; import java.io.*; import java.util.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.*; import javax.swing.event.*; import javax.swing.filechooser.FileFilter; import com.sun.pdfview.*; import com.sun.pdfview.font.*; /** * */ public class FontToy extends JPanel { /** the combo box supplying glyph information. */ JComboBox comboBox; /** exit from the application. */ private JMenuItem exitMenuItem = new JMenuItem("Exit"); /** file chooser for PDF files. */ private JFileChooser openFileChooser = null; /** the File menu items. */ private JMenu fileMenu = new JMenu("File"); /** the fonts */ private Set fonts; /** the current font */ private PDFFont font; /** the frame holding the app. */ private JFrame jf = new JFrame("Font Toy"); /** the font to draw glyphs in */ private Font gfont; /** the current glyph */ private PDFGlyph glyph; /** the list of glyphs in the current font */ private JComboBox glyphBox; /** a spinner list model to let a spinner choose the glyphs. */ private SpinnerListModel glyphModel = new SpinnerListModel(); /** the name of the current glyph. */ private JLabel glyphName = new JLabel (); /** a spinner to choose the glyphs. */ private JSpinner glyphSpinner = new JSpinner(glyphModel); /** the input file we are processing. */ private File inputFile = null; /** the menu bar to let users supply information. */ private JMenuBar menuBar = new JMenuBar(); /** open a new PDF file to examine its use of fonts. */ private JMenuItem openMenuItem = new JMenuItem("Open"); /** the PDF file we are processing. */ private PDFFile pdf = null; /** Creates a new instance of FontToy */ public FontToy(String[] args) throws IOException { Box controlPanel = Box.createHorizontalBox(); glyphBox = new JComboBox(); glyphBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ie) { if (ie.getStateChange() == ItemEvent.SELECTED) { Integer value = (Integer) ie.getItem(); glyphSelected(value); glyphSpinner.setValue(value); } } }); comboBox = new JComboBox(); comboBox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent ie) { if (ie.getStateChange() == ItemEvent.SELECTED) { fontSelected((PDFFont) ie.getItem()); } } }); comboBox.setMaximumSize(new Dimension(200, 50)); controlPanel.add(new JLabel("Fonts:")); controlPanel.add(comboBox); controlPanel.add(Box.createHorizontalStrut(15)); controlPanel.add(new JLabel("Glyphs:")); controlPanel.add(glyphBox); controlPanel.add(glyphName); controlPanel.add(glyphSpinner); JPanel ftPanel = new JPanel(); ftPanel.setLayout(new BorderLayout()); ftPanel.add(controlPanel, BorderLayout.NORTH); ftPanel.add(this, BorderLayout.CENTER); ftPanel.setFocusable(true); ftPanel.requestFocus(); ftPanel.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent k) { keyPressed(k); } }); jf.setContentPane(ftPanel); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(-1); } }); jf.setSize(640, 480); jf.setVisible(true); jf.setJMenuBar(menuBar); menuBar.add(fileMenu); fileMenu.add(openMenuItem); fileMenu.addSeparator(); fileMenu.add(exitMenuItem); openMenuItem.addActionListener(new ActionListener () { public void actionPerformed(ActionEvent e) { openPDF (); } }); glyphSpinner.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { Integer value = (Integer) glyphSpinner.getValue(); glyphSelected(value); glyphBox.setSelectedItem(value); } }); if (args.length > 0) { initialize(args[0]); } } /** * Draw a shape in fancy outline form */ private void drawShape(Graphics2D g2, GeneralPath gp, int w, int h) { // System.out.println("Drawing shape in: " + w + " x " + h); float curX = 0; float curY = 0; float startX = 0; float startY = 0; Rectangle2D border = gp.getBounds2D(); double scaleX = (w - 20) / border.getWidth(); double scaleY = (h - 20) / border.getHeight(); if (scaleX < scaleY) { scaleY = scaleX; } else { scaleX = scaleY; } double transX = 10 - (border.getX() * scaleX); double transY = h - 10 + (border.getY() * scaleY); AffineTransform at = new AffineTransform(scaleX, 0, 0, -scaleY, transX, transY); Rectangle2D borderTrans = gp.createTransformedShape(at).getBounds2D(); g2.setColor(Color.CYAN); g2.fill(gp.createTransformedShape(at)); g2.setColor(Color.BLACK); int num = 0; PathIterator pi = gp.getPathIterator(at); while (!pi.isDone()) { float[] coords = new float[6]; switch (pi.currentSegment(coords)) { case PathIterator.SEG_MOVETO: curX = coords[0]; curY = coords[1]; drawPoint(g2, num++, curX, curY, false); startX = curX; startY = curY; break; case PathIterator.SEG_LINETO: Line2D line = new Line2D.Float(curX, curY, coords[0], coords[1]); g2.draw(line); drawPoint(g2, num++, coords[0], coords[1], false); curX = coords[0]; curY = coords[1]; break; case PathIterator.SEG_CUBICTO: CubicCurve2D curve = new CubicCurve2D.Float(curX, curY, coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); g2.draw(curve); drawPoint(g2, num++, coords[0], coords[1], true); drawPoint(g2, num++, coords[2], coords[3], true); drawPoint(g2, num++, coords[4], coords[5], false); curX = coords[4]; curY = coords[5]; break; case PathIterator.SEG_QUADTO: QuadCurve2D curveQ = new QuadCurve2D.Float(curX, curY, coords[0], coords[1], coords[2], coords[3]); g2.draw(curveQ); drawPoint(g2, num++, coords[0], coords[1], true); drawPoint(g2, num++, coords[2], coords[3], false); curX = coords[2]; curY = coords[3]; break; case PathIterator.SEG_CLOSE: Line2D.Float line2 = new Line2D.Float(curX, curY, startX, startY); g2.draw(line2); curX = startX; curY = startY; break; } pi.next(); } } /** * Draw and label a point */ public void drawPoint(Graphics2D g, int num, float x, float y, boolean curvectl) { GeneralPath gp = new GeneralPath(); if (curvectl) { gp.moveTo(x - 1, y - 1); gp.lineTo(x + 1, y + 1); gp.moveTo(x - 1, y + 1); gp.lineTo(x + 1, y - 1); } else { gp.moveTo(x - 1, y - 1); gp.lineTo(x - 1, y + 1); gp.lineTo(x + 1, y + 1); gp.lineTo(x + 1, y - 1); gp.closePath(); } g.setColor(Color.red); g.draw(gp); g.setColor(Color.blue); g.setFont(gfont); g.drawString(String.valueOf(num), x + 3, y + 3); } /** * Draw a page */ private void drawPage(Graphics2D g2, PDFPage page, int w, int h) { // System.out.println("Drawing page in: " + w + " x " + h); Dimension pageSize = page.getUnstretchedSize(w - 20, h - 20, null); Image image = page.getImage(pageSize.width, pageSize.height, null, null, true, true); g2.drawImage(image, 0, 0, null); } /** * Walk the PDF Tree looking for fonts * * @param pagedict the top of the pages tree * @param resources a HashMap that will be filled with any resource * definitions encountered on the search for the page */ private Set findFonts(PDFObject pagedict, Map resources) throws IOException { Set outSet = new HashSet(); PDFObject rsrcObj = pagedict.getDictRef("Resources"); if (rsrcObj != null) { // copy the resources so we don't overwrite them in // children HashMap rsrcMap = new HashMap(); rsrcMap.putAll(resources); Map rsrc = rsrcObj.getDictionary(); rsrcMap.putAll(rsrc); if (rsrc.containsKey("Font")) { PDFObject fontsObj = (PDFObject) rsrc.get("Font"); for (Iterator i = fontsObj.getDictKeys(); i.hasNext();) { String key = (String) i.next(); PDFObject fontObj = (PDFObject) fontsObj.getDictRef(key); try { PDFFont font = PDFFont.getFont(fontObj, rsrcMap); // System.out.println("Found font: " + font.getBaseFont()); outSet.add(font); } catch (Exception ex) { // oh well System.out.println("Error finding font from " + fontObj); ex.printStackTrace(); } } } // look at XObjects for fonts as well if (rsrc.containsKey("XObject")) { PDFObject xobjsObj = (PDFObject) rsrc.get("XObject"); for (Iterator i = xobjsObj.getDictKeys(); i.hasNext();) { String key = (String) i.next(); PDFObject xobj = (PDFObject) xobjsObj.getDictRef(key); outSet.addAll(findFonts(xobj, new HashMap())); } } resources = rsrcMap; } PDFObject kidsObj = pagedict.getDictRef("Kids"); if (kidsObj != null) { PDFObject[] kids = kidsObj.getArray(); for (int i = 0; i < kids.length; i++) { outSet.addAll(findFonts(kids[i], resources)); } } return outSet; } /** * Called when a new font is selected */ private void fontSelected(PDFFont font) { // System.out.println("Font " + font + " selected."); setCurrentFont(font); int start = 0; int end = 255; if (font instanceof OutlineFont) { start = ((OutlineFont) font).getFirstChar(); end = ((OutlineFont) font).getLastChar(); } else if (font instanceof Type3Font) { start = ((Type3Font) font).getFirstChar(); end = ((Type3Font) font).getLastChar(); } if (start < 0) { start = 0; } if (end < 0) { end = 255; } Vector objs = new Vector(end - start + 1); for (int i = start; i <= end; i++) { objs.add(new Integer(i)); } glyphBox.setModel(new DefaultComboBoxModel(objs)); glyphModel = new SpinnerListModel(objs); glyphSpinner.setModel(glyphModel); Integer select = new Integer(start); glyphSelected(select); } /** get the set of associated fonts */ public Set getFonts() { return fonts; } /** get the current font */ public PDFFont getCurrentFont() { return font; } /** * Called when a new glyph is selected */ private void glyphSelected(Integer glyphID) { // System.out.println("Glyph " + glyphID + " selected."); char glyphChar = (char) (glyphID.intValue()); String s = String.valueOf(glyphChar); PDFFont font = getCurrentFont(); List l = font.getGlyphs(s); PDFGlyph glyph = (PDFGlyph) l.get(0); setCurrentGlyph(glyph); repaint(); } private void initialize(String fileName) throws IOException { jf.setTitle("PDFRenderer Font Toy - " + fileName); try { inputFile = new File(fileName); FileInputStream istr = new FileInputStream(inputFile); byte [] buf = new byte[(int) inputFile.length()]; int read = 0; int offset = 0; while (read >= 0) { read = istr.read(buf, offset, buf.length-offset); } istr.close(); ByteBuffer byteBuf = ByteBuffer.allocate(buf.length); byteBuf.put(buf); pdf = new PDFFile(byteBuf); } catch (Exception ex) { ex.printStackTrace(); } PDFObject root = pdf.getRoot(); PDFObject pagesObj = (PDFObject) root.getDictRef("Pages"); fonts = findFonts(pagesObj, new HashMap()); gfont = new Font("Sans-serif", Font.PLAIN, 10); Object[] fontObjs = getFonts().toArray(); comboBox.setModel(new DefaultComboBoxModel(fontObjs)); fontSelected((PDFFont) fontObjs[0]); this.validate(); } /** get the current glyph */ public PDFGlyph getCurrentGlyph() { return glyph; } /** * Called when a key is typed */ private void keyPressed(KeyEvent k) { int curIndex = glyphBox.getSelectedIndex(); int nextIndex = curIndex; if (k.getKeyCode() == KeyEvent.VK_LEFT) { nextIndex--; if (nextIndex < 0) { nextIndex = glyphBox.getItemCount() - 1; } } else if (k.getKeyCode() == KeyEvent.VK_RIGHT) { nextIndex++; if (nextIndex >= glyphBox.getItemCount()) { nextIndex = 0; } } if (nextIndex != curIndex) { glyphBox.setSelectedIndex(nextIndex); } } /** * @param args the command line arguments */ public static void main(String[] args) { try { FontToy toy = new FontToy(args); } catch (IOException ex) { Logger.getLogger(FontToy.class.getName()).log(Level.SEVERE, null, ex); } } /** * find and open a new PDF file. */ private void openPDF () { if (openFileChooser == null) { openFileChooser = new JFileChooser(inputFile); openFileChooser.setAcceptAllFileFilterUsed(false); openFileChooser.addChoosableFileFilter(new FileFilter () { public boolean accept (File file) { return file.isDirectory() || file.getName().toLowerCase().endsWith(".pdf"); } public String getDescription () { return "PDF Files (*.pdf)"; } }); } switch (openFileChooser.showOpenDialog(this)) { case JFileChooser.APPROVE_OPTION: try { initialize(openFileChooser.getSelectedFile().getPath()); } catch (IOException ex) { Logger.getLogger(FontToy.class.getName()).log(Level.SEVERE, null, ex); } break; default: break; } } /** * paint the current glyph on the screen */ public void paint(Graphics g) { // System.out.println("Repaint!"); Graphics2D g2 = (Graphics2D) g; int width = getWidth(); int height = getHeight(); g2.setColor(Color.WHITE); g2.fillRect(0, 0, width, height); g2.setColor(Color.BLACK); if (glyph == null) { return; } GeneralPath gp = glyph.getShape(); PDFPage page = glyph.getPage(); if (gp != null) { drawShape(g2, gp, width, height); } else if (page != null) { drawPage(g2, page, width, height); } } /** set the current font */ public void setCurrentFont(PDFFont font) { this.font = font; } /** set the current glyph */ public void setCurrentGlyph(PDFGlyph glyph) { this.glyph = glyph; glyphName.setText(glyph.getName()); } } pdfrenderer-0.9.0/src/test/TTFTest.java0000644000175000017500000002016411237133111017660 0ustar twernertwerner/* * $Id: TTFTest.java,v 1.3 2009-08-07 23:18:33 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package test; /* * TTFTest.java * * Created on August 9, 2003, 5:57 PM */ import com.sun.pdfview.font.ttf.*; import java.util.*; import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.awt.font.*; /** * * @author jon */ public class TTFTest { /** * @param args the command line arguments */ public static void main(String[] args) { if (args.length < 1) { System.out.println("Usage: "); System.out.println(" TTFTest "); System.exit(-1); } try { RandomAccessFile raf = new RandomAccessFile(args[0], "r"); int size = (int) raf.length(); byte[] data = new byte[size]; raf.readFully(data); TrueTypeFont ttf = TrueTypeFont.parseFont(data); MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); int nglyphs = maxp.getNumGlyphs(); if (ttf.getTable("cmap") == null) { byte[] map = new byte[256]; for (int i = 0; i < map.length; i++) { if (i < nglyphs) { map[i] = (byte) (i); } else { map[i] = 0; } } CMapFormat0 newMap = (CMapFormat0) CMap.createMap((short) 0, (short) 0); newMap.setMap(map); CMapFormat4 newMap4 = (CMapFormat4) CMap.createMap((short) 4, (short) 0); newMap4.addSegment((short) 1, (short) (nglyphs + 0), (short) 0); CmapTable cmap = (CmapTable) TrueTypeTable.createTable(ttf, "cmap"); cmap.addCMap((short) 1, (short) 0, newMap); cmap.addCMap((short) 3, (short) 1, newMap4); ttf.addTable("cmap", cmap); } if (ttf.getTable("name") == null) { NameTable name = (NameTable) TrueTypeTable.createTable(ttf, "name"); short platID = NameTable.PLATFORMID_MACINTOSH; short encID = NameTable.ENCODINGID_MAC_ROMAN; short langID = NameTable.LANGUAGEID_MAC_ENGLISH; /* name.addRecord(platID, encID, langID, NameTable.NAMEID_COPYRIGHT, "Copyright (c) 2000 Bigelow & Holmes Inc. Pat. Des 289,421."); name.addRecord(platID, encID, langID, NameTable.NAMEID_FAMILY, "Lucida Bright"); name.addRecord(platID, encID, langID, NameTable.NAMEID_SUBFAMILY, "Regular"); name.addRecord(platID, encID, langID, NameTable.NAMEID_SUBFAMILY_UNIQUE, "Lucida Bright Regular: B&H:2000"); name.addRecord(platID, encID, langID, NameTable.NAMEID_FULL_NAME, "Lucida Bright Regular"); name.addRecord(platID, encID, langID, NameTable.NAMEID_VERSION, "January 28, 2000; 1.10 (JAVA)"); name.addRecord(platID, encID, langID, NameTable.NAMEID_POSTSCRIPT_NAME, "LucidaBright"); name.addRecord(platID, encID, langID, NameTable.NAMEID_TRADEMARK, "Lucida is a registered trademark of Bigelow & Holmes Inc."); */ platID = NameTable.PLATFORMID_MICROSOFT; encID = 1; langID = 1033; name.addRecord(platID, encID, langID, NameTable.NAMEID_COPYRIGHT, "Copyright (c) 2000 Bigelow & Holmes Inc. Pat. Des 289,421."); name.addRecord(platID, encID, langID, NameTable.NAMEID_FAMILY, "Lucida Bright"); name.addRecord(platID, encID, langID, NameTable.NAMEID_SUBFAMILY, "Regular"); name.addRecord(platID, encID, langID, NameTable.NAMEID_SUBFAMILY_UNIQUE, "Lucida Bright Regular: B&H:2000"); name.addRecord(platID, encID, langID, NameTable.NAMEID_FULL_NAME, "Lucida Bright Regular"); name.addRecord(platID, encID, langID, NameTable.NAMEID_VERSION, "January 28, 2000; 1.10 (JAVA)"); name.addRecord(platID, encID, langID, NameTable.NAMEID_POSTSCRIPT_NAME, "LucidaBright"); name.addRecord(platID, encID, langID, NameTable.NAMEID_TRADEMARK, "Lucida is a registered trademark of Bigelow & Holmes Inc."); ttf.addTable("name", name); } ttf.getTable("head"); ttf.getTable("hhea"); System.out.println(ttf); if (args.length == 2) { FileOutputStream fis = new FileOutputStream(args[1]); fis.write(ttf.writeFont()); fis.close(); } InputStream fontStream = new ByteArrayInputStream(ttf.writeFont()); Font f = Font.createFont(Font.TRUETYPE_FONT, fontStream); System.out.println("Attributes of font " + f.getFontName() + "(" + f.getNumGlyphs() + "):"); Map m = f.getAttributes(); for (Iterator i = m.keySet().iterator(); i.hasNext();) { Object key = i.next(); Object value = m.get(key); System.out.println(key + " = " + value); } System.out.println(); Font f2 = f.deriveFont((float) 18.0); JFrame jf = new JFrame(); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(1); } }); JPanel thePanel = new JPanel(); thePanel.setLayout(new GridLayout(0,32)); for (int i = 0; i < nglyphs; i++) { JLabel lbl = new JLabel(Integer.toHexString(i) + ": "); JLabel val = new JLabel(String.valueOf((char) i)); val.setFont(f2); thePanel.add(lbl); thePanel.add(val); } JScrollPane jsp = new JScrollPane(thePanel); jf.getContentPane().add(jsp); jf.pack(); jf.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } } pdfrenderer-0.9.0/src/com/0000755000175000017500000000000011622545441015327 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/0000755000175000017500000000000011622545441016134 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/0000755000175000017500000000000011622545450017600 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/BaseWatchable.java0000644000175000017500000002631311144062623023130 0ustar twernertwerner/* * $Id: BaseWatchable.java,v 1.5 2009-02-09 17:14:32 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; /** * An abstract implementation of the watchable interface, that is extended * by the parser and renderer to do their thing. */ public abstract class BaseWatchable implements Watchable, Runnable { /** the current status, from the list in Watchable */ private int status = Watchable.UNKNOWN; /** a lock for status-related operations */ private Object statusLock = new Object(); /** a lock for parsing operations */ private Object parserLock = new Object(); /** when to stop */ private Gate gate; /** suppress local stack trace on setError. */ private static boolean SuppressSetErrorStackTrace = false; /** the thread we are running in */ private Thread thread; /** * Creates a new instance of BaseWatchable */ protected BaseWatchable() { setStatus(Watchable.NOT_STARTED); } /** * Perform a single iteration of this watchable. This is the minimum * granularity which the go() commands operate over. * * @return one of three values:
    *
  • Watchable.RUNNING if there is still data to be processed *
  • Watchable.NEEDS_DATA if there is no data to be processed but * the execution is not yet complete *
  • Watchable.COMPLETED if the execution is complete *
*/ protected abstract int iterate() throws Exception; /** * Prepare for a set of iterations. Called before the first iterate() call * in a sequence. Subclasses should extend this method if they need to do * anything to setup. */ protected void setup() { // do nothing } /** * Clean up after a set of iterations. Called after iteration has stopped * due to completion, manual stopping, or error. */ protected void cleanup() { // do nothing } public void run() { // System.out.println(Thread.currentThread().getName() + " starting"); // call setup once we started if (getStatus() == Watchable.NOT_STARTED) { setup(); } setStatus(Watchable.PAUSED); synchronized (parserLock) { while (!isFinished() && getStatus() != Watchable.STOPPED) { if (isExecutable()) { // set the status to running setStatus(Watchable.RUNNING); try { // keep going until the status is no longer running, // our gate tells us to stop, or no-one is watching while ((getStatus() == Watchable.RUNNING) && (gate == null || !gate.iterate())) { // update the status based on this iteration setStatus(iterate()); } // make sure we are paused if (getStatus() == Watchable.RUNNING) { setStatus(Watchable.PAUSED); } } catch (Exception ex) { setError(ex); } } else { // System.out.println(getName() + " waiting: status = " + getStatusString()); // wait for our status to change synchronized (statusLock) { if (!isExecutable()) { try { statusLock.wait(); } catch (InterruptedException ie) { // ignore } } } } } } // System.out.println(Thread.currentThread().getName() + " exiting: status = " + getStatusString()); // call cleanup when we are done if (getStatus() == Watchable.COMPLETED || getStatus() == Watchable.ERROR) { cleanup(); } // notify that we are no longer running thread = null; } /** * Get the status of this watchable * * @return one of the well-known statuses */ public int getStatus() { return status; } /** * Return whether this watchable has finished. A watchable is finished * when its status is either COMPLETED, STOPPED or ERROR */ public boolean isFinished() { int s = getStatus(); return (s == Watchable.COMPLETED || s == Watchable.ERROR); } /** * return true if this watchable is ready to be executed */ public boolean isExecutable() { return ((status == Watchable.PAUSED || status == Watchable.RUNNING) && (gate == null || !gate.stop())); } /** * Stop this watchable. Stop will cause all processing to cease, * and the watchable to be destroyed. */ public void stop() { setStatus(Watchable.STOPPED); } /** * Start this watchable and run in a new thread until it is finished or * stopped. * Note the watchable may be stopped if go() with a * different time is called during execution. */ public synchronized void go() { gate = null; execute(false); } /** * Start this watchable and run until it is finished or stopped. * Note the watchable may be stopped if go() with a * different time is called during execution. * * @param synchronous if true, run in this thread */ public synchronized void go(boolean synchronous) { gate = null; execute(synchronous); } /** * Start this watchable and run for the given number of steps or until * finished or stopped. * * @param steps the number of steps to run for */ public synchronized void go(int steps) { gate = new Gate(); gate.setStopIterations(steps); execute(false); } /** * Start this watchable and run for the given amount of time, or until * finished or stopped. * * @param millis the number of milliseconds to run for */ public synchronized void go(long millis) { gate = new Gate(); gate.setStopTime(millis); execute(false); } /** * Wait for this watchable to finish */ public void waitForFinish() { synchronized (statusLock) { while (!isFinished() && getStatus() != Watchable.STOPPED) { try { statusLock.wait(); } catch (InterruptedException ex) { // ignore } } } } /** * Start executing this watchable * * @param synchronous if true, run in this thread */ protected synchronized void execute(boolean synchronous) { // see if we're already running if (thread != null) { // we're already running. Make sure we wake up on any change. synchronized (statusLock) { statusLock.notifyAll(); } return; } else if (isFinished()) { // we're all finished return; } // we'return not running. Start up if (synchronous) { thread = Thread.currentThread(); run(); } else { thread = new Thread(this); thread.setName(getClass().getName()); thread.start(); } } /** * Set the status of this watchable */ protected void setStatus(int status) { synchronized (statusLock) { this.status = status; // System.out.println(getName() + " status set to " + getStatusString()); statusLock.notifyAll(); } } /** * return true if we would be suppressing setError stack traces. * * @return boolean */ public static boolean isSuppressSetErrorStackTrace () { return SuppressSetErrorStackTrace; } /** * set suppression of stack traces from setError. * * @param suppressTrace */ public static void setSuppressSetErrorStackTrace(boolean suppressTrace) { SuppressSetErrorStackTrace = suppressTrace; } /** * Set an error on this watchable */ protected void setError(Exception error) { if (!SuppressSetErrorStackTrace) { error.printStackTrace(); } setStatus(Watchable.ERROR); } private String getStatusString() { switch (getStatus()) { case Watchable.NOT_STARTED: return "Not started"; case Watchable.RUNNING: return "Running"; case Watchable.NEEDS_DATA: return "Needs Data"; case Watchable.PAUSED: return "Paused"; case Watchable.STOPPED: return "Stopped"; case Watchable.COMPLETED: return "Completed"; case Watchable.ERROR: return "Error"; default: return "Unknown"; } } /** A class that lets us give it a target time or number of steps, * and will tell us to stop after that much time or that many steps */ class Gate { /** whether this is a time-based (true) or step-based (false) gate */ private boolean timeBased; /** the next gate, whether time or iterations */ private long nextGate; /** set the stop time */ public void setStopTime(long millisFromNow) { timeBased = true; nextGate = System.currentTimeMillis() + millisFromNow; } /** set the number of iterations until we stop */ public void setStopIterations(int iterations) { timeBased = false; nextGate = iterations; } /** check whether we should stop. */ public boolean stop() { if (timeBased) { return (System.currentTimeMillis() >= nextGate); } else { return (nextGate < 0); } } /** Notify the gate of one iteration. Returns true if we should * stop or false if not */ public boolean iterate() { if (!timeBased) { nextGate--; } return stop(); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFObject.java0000644000175000017500000006273011526563523022217 0ustar twernertwerner/* * $Id: PDFObject.java,v 1.9 2010-06-14 17:32:09 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.IOException; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.util.*; import com.sun.pdfview.decode.PDFDecoder; import com.sun.pdfview.decrypt.PDFDecrypter; import com.sun.pdfview.decrypt.IdentityDecrypter; /** * a class encapsulating all the possibilities of content for * an object in a PDF file. *

* A PDF object can be a simple type, like a Boolean, a Number, * a String, or the Null value. It can also be a NAME, which * looks like a string, but is a special type in PDF files, like * "/Name". *

* A PDF object can also be complex types, including Array; * Dictionary; Stream, which is a Dictionary plus an array of * bytes; or Indirect, which is a reference to some other * PDF object. Indirect references will always be dereferenced * by the time any data is returned from one of the methods * in this class. * * @author Mike Wessler */ public class PDFObject { /** an indirect reference*/ public static final int INDIRECT = 0; // PDFXref /** a Boolean */ public static final int BOOLEAN = 1; // Boolean /** a Number, represented as a double */ public static final int NUMBER = 2; // Double /** a String */ public static final int STRING = 3; // String /** a special string, seen in PDF files as /Name */ public static final int NAME = 4; // String /** an array of PDFObjects */ public static final int ARRAY = 5; // Array of PDFObject /** a Hashmap that maps String names to PDFObjects */ public static final int DICTIONARY = 6; // HashMap(String->PDFObject) /** a Stream: a Hashmap with a byte array */ public static final int STREAM = 7; // HashMap + byte[] /** the NULL object (there is only one) */ public static final int NULL = 8; // null /** a special PDF bare word, like R, obj, true, false, etc */ public static final int KEYWORD = 9; // String /** * When a value of {@link #getObjGen objNum} or {@link #getObjGen objGen}, * indicates that the object is not top-level, and is embedded in another * object */ public static final int OBJ_NUM_EMBEDDED = -2; /** * When a value of {@link #getObjGen objNum} or {@link #getObjGen objGen}, * indicates that the object is not top-level, and is embedded directly * in the trailer. */ public static final int OBJ_NUM_TRAILER = -1; /** the NULL PDFObject */ public static final PDFObject nullObj = new PDFObject(null, NULL, null); /** the type of this object */ private int type; /** the value of this object. It can be a wide number of things, defined by type */ private Object value; /** the encoded stream, if this is a STREAM object */ private ByteBuffer stream; /** a cached version of the decoded stream */ private SoftReference decodedStream; /** The filter limits used to generate the cached decoded stream */ private Set decodedStreamFilterLimits = null; /** * the PDFFile from which this object came, used for * dereferences */ private PDFFile owner; /** * a cache of translated data. This data can be * garbage collected at any time, after which it will * have to be rebuilt. */ private SoftReference cache; /** @see #getObjNum() */ private int objNum = OBJ_NUM_EMBEDDED; /** @see #getObjGen() */ private int objGen = OBJ_NUM_EMBEDDED; /** * create a new simple PDFObject with a type and a value * @param owner the PDFFile in which this object resides, used * for dereferencing. This may be null. * @param type the type of object * @param value the value. For DICTIONARY, this is a HashMap. * for ARRAY it's an ArrayList. For NUMBER, it's a Double. * for BOOLEAN, it's Boolean.TRUE or Boolean.FALSE. For * everything else, it's a String. */ public PDFObject(PDFFile owner, int type, Object value) { this.type = type; if (type == NAME) { value = ((String) value).intern(); } else if (type == KEYWORD && value.equals("true")) { this.type = BOOLEAN; value = Boolean.TRUE; } else if (type == KEYWORD && value.equals("false")) { this.type = BOOLEAN; value = Boolean.FALSE; } this.value = value; this.owner = owner; } /** * create a new PDFObject that is the closest match to a * given Java object. Possibilities include Double, String, * PDFObject[], HashMap, Boolean, or PDFParser.Tok, * which should be "true" or "false" to turn into a BOOLEAN. * * @param obj the sample Java object to convert to a PDFObject. * @throws PDFParseException if the object isn't one of the * above examples, and can't be turned into a PDFObject. */ public PDFObject(Object obj) throws PDFParseException { this.owner = null; this.value = obj; if ((obj instanceof Double) || (obj instanceof Integer)) { this.type = NUMBER; } else if (obj instanceof String) { this.type = NAME; } else if (obj instanceof PDFObject[]) { this.type = ARRAY; } else if (obj instanceof Object[]) { Object[] srcary = (Object[]) obj; PDFObject[] dstary = new PDFObject[srcary.length]; for (int i = 0; i < srcary.length; i++) { dstary[i] = new PDFObject(srcary[i]); } value = dstary; this.type = ARRAY; } else if (obj instanceof HashMap) { this.type = DICTIONARY; } else if (obj instanceof Boolean) { this.type = BOOLEAN; } else if (obj instanceof PDFParser.Tok) { PDFParser.Tok tok = (PDFParser.Tok) obj; if (tok.name.equals("true")) { this.value = Boolean.TRUE; this.type = BOOLEAN; } else if (tok.name.equals("false")) { this.value = Boolean.FALSE; this.type = BOOLEAN; } else { this.value = tok.name; this.type = NAME; } } else { throw new PDFParseException("Bad type for raw PDFObject: " + obj); } } /** * create a new PDFObject based on a PDFXref * @param owner the PDFFile from which the PDFXref was drawn * @param xref the PDFXref to turn into a PDFObject */ public PDFObject(PDFFile owner, PDFXref xref) { this.type = INDIRECT; this.value = xref; this.owner = owner; } /** * get the type of this object. The object will be * dereferenced, so INDIRECT will never be returned. * @return the type of the object */ public int getType() throws IOException { if (type == INDIRECT) { return dereference().getType(); } return type; } /** * set the stream of this object. It should have been * a DICTIONARY before the call. * @param data the data, as a ByteBuffer. */ public void setStream(ByteBuffer data) { this.type = STREAM; this.stream = data; } /** * get the value in the cache. May become null at any time. * @return the cached value, or null if the value has been * garbage collected. */ public Object getCache() throws IOException { if (type == INDIRECT) { return dereference().getCache(); } else if (cache != null) { return cache.get(); } else { return null; } } /** * set the cached value. The object may be garbage collected * if no other reference exists to it. * @param obj the object to be cached */ public void setCache(Object obj) throws IOException { if (type == INDIRECT) { dereference().setCache(obj); return; } else { cache = new SoftReference(obj); } } public byte[] getStream(Set filterLimits) throws IOException { if (type == INDIRECT) { return dereference().getStream(filterLimits); } else if (type == STREAM && stream != null) { byte[] data = null; synchronized (stream) { // decode ByteBuffer streamBuf = decodeStream(filterLimits); // ByteBuffer streamBuf = stream; // First try to use the array with no copying. This can only // be done if the buffer has a backing array, and is not a slice if (streamBuf.hasArray() && streamBuf.arrayOffset() == 0) { byte[] ary = streamBuf.array(); // make sure there is no extra data in the buffer if (ary.length == streamBuf.remaining()) { return ary; } } // Can't use the direct buffer, so copy the data (bad) data = new byte[streamBuf.remaining()]; streamBuf.get(data); // return the stream to its starting position streamBuf.flip(); } return data; } else if (type == STRING) { return PDFStringUtil.asBytes(getStringValue()); } else { // wrong type return null; } } /** * get the stream from this object. Will return null if this * object isn't a STREAM. * @return the stream, or null, if this isn't a STREAM. */ public byte[] getStream() throws IOException { return getStream(Collections.emptySet()); } /** * get the stream from this object as a byte buffer. Will return null if * this object isn't a STREAM. * @return the buffer, or null, if this isn't a STREAM. */ public ByteBuffer getStreamBuffer() throws IOException { return getStreamBuffer(Collections.emptySet()); } /** * get the stream from this object as a byte buffer. Will return null if * this object isn't a STREAM. * @return the buffer, or null, if this isn't a STREAM. */ public ByteBuffer getStreamBuffer(Set filterLimits) throws IOException { if (type == INDIRECT) { return dereference().getStreamBuffer(filterLimits); } else if (type == STREAM && stream != null) { synchronized (stream) { ByteBuffer streamBuf = decodeStream(filterLimits); // ByteBuffer streamBuf = stream; return streamBuf.duplicate(); } } else if (type == STRING) { String src = getStringValue(); return ByteBuffer.wrap(src.getBytes()); } // wrong type return null; } /** * Get the decoded stream value */ private ByteBuffer decodeStream(Set filterLimits) throws IOException { ByteBuffer outStream = null; // first try the cache if (decodedStream != null && filterLimits.equals(decodedStreamFilterLimits)) { outStream = (ByteBuffer) decodedStream.get(); } // no luck in the cache, do the actual decoding if (outStream == null) { stream.rewind(); outStream = PDFDecoder.decodeStream(this, stream, filterLimits); decodedStreamFilterLimits = new HashSet(filterLimits); decodedStream = new SoftReference(outStream); } return outStream; } /** * get the value as an int. Will return 0 if this object * isn't a NUMBER. */ public int getIntValue() throws IOException { if (type == INDIRECT) { return dereference().getIntValue(); } else if (type == NUMBER) { return ((Number) value).intValue(); } // wrong type return 0; } /** * get the value as a float. Will return 0 if this object * isn't a NUMBER */ public float getFloatValue() throws IOException { if (type == INDIRECT) { return dereference().getFloatValue(); } else if (type == NUMBER) { return ((Double) value).floatValue(); } // wrong type return 0; } /** * get the value as a double. Will return 0 if this object * isn't a NUMBER. */ public double getDoubleValue() throws IOException { if (type == INDIRECT) { return dereference().getDoubleValue(); } else if (type == NUMBER) { return ((Number) value).doubleValue(); } // wrong type return 0; } /** * get the value as a String. Will return null if the object * isn't a STRING, NAME, or KEYWORD. This method will NOT * convert a NUMBER to a String. If the string is actually * a text string (i.e., may be encoded in UTF16-BE or PdfDocEncoding), * then one should use {@link #getTextStringValue()} or use one * of the {@link PDFStringUtil} methods on the result from this * method. The string value represents exactly the sequence of 8 bit * characters present in the file, decrypted and decoded as appropriate, * into a string containing only 8 bit character values - that is, each * char will be between 0 and 255. */ public String getStringValue() throws IOException { if (type == INDIRECT) { return dereference().getStringValue(); } else if (type == STRING || type == NAME || type == KEYWORD) { return (String) value; } // wrong type return null; } /** * Get the value as a text string; i.e., a string encoded in UTF-16BE * or PDFDocEncoding. Simple latin alpha-numeric characters are preserved in * both these encodings. * @return the text string value * @throws IOException */ public String getTextStringValue() throws IOException { return PDFStringUtil.asTextString(getStringValue()); } /** * get the value as a PDFObject[]. If this object is an ARRAY, * will return the array. Otherwise, will return an array * of one element with this object as the element. */ public PDFObject[] getArray() throws IOException { if (type == INDIRECT) { return dereference().getArray(); } else if (type == ARRAY) { PDFObject[] ary = (PDFObject[]) value; return ary; } else { PDFObject[] ary = new PDFObject[1]; ary[0] = this; return ary; } } /** * get the value as a boolean. Will return false if this * object is not a BOOLEAN */ public boolean getBooleanValue() throws IOException { if (type == INDIRECT) { return dereference().getBooleanValue(); } else if (type == BOOLEAN) { return value == Boolean.TRUE; } // wrong type return false; } /** * if this object is an ARRAY, get the PDFObject at some * position in the array. If this is not an ARRAY, returns * null. */ public PDFObject getAt(int idx) throws IOException { if (type == INDIRECT) { return dereference().getAt(idx); } else if (type == ARRAY) { PDFObject[] ary = (PDFObject[]) value; return ary[idx]; } // wrong type return null; } /** * get an Iterator over all the keys in the dictionary. If * this object is not a DICTIONARY or a STREAM, returns an * Iterator over the empty list. */ public Iterator getDictKeys() throws IOException { if (type == INDIRECT) { return dereference().getDictKeys(); } else if (type == DICTIONARY || type == STREAM) { return ((HashMap) value).keySet().iterator(); } // wrong type return new ArrayList().iterator(); } /** * get the dictionary as a HashMap. If this isn't a DICTIONARY * or a STREAM, returns null */ public HashMap getDictionary() throws IOException { if (type == INDIRECT) { return dereference().getDictionary(); } else if (type == DICTIONARY || type == STREAM) { return (HashMap) value; } // wrong type return new HashMap(); } /** * get the value associated with a particular key in the * dictionary. If this isn't a DICTIONARY or a STREAM, * or there is no such key, returns null. */ public PDFObject getDictRef(String key) throws IOException { if (type == INDIRECT) { return dereference().getDictRef(key); } else if (type == DICTIONARY || type == STREAM) { key = key.intern(); HashMap h = (HashMap) value; PDFObject obj = (PDFObject) h.get(key.intern()); return obj; } // wrong type return null; } /** * returns true only if this object is a DICTIONARY or a * STREAM, and the "Type" entry in the dictionary matches a * given value. * @param match the expected value for the "Type" key in the * dictionary * @return whether the dictionary is of the expected type */ public boolean isDictType(String match) throws IOException { if (type == INDIRECT) { return dereference().isDictType(match); } else if (type != DICTIONARY && type != STREAM) { return false; } PDFObject obj = getDictRef("Type"); return obj != null && obj.getStringValue().equals(match); } public PDFDecrypter getDecrypter() { // PDFObjects without owners are always created as part of // content instructions. Such an object will never have encryption // applied to it, as the stream that contains it is the // unit of encryption, with no further encryption being applied // within. So if someone asks for the decrypter for // one of these in-stream objects, no decryption should // ever be applied. This can be seen with inline images. return owner != null ? owner.getDefaultDecrypter() : IdentityDecrypter.getInstance(); } /** * Set the object identifiers * @param objNum the object number * @param objGen the object generation number */ public void setObjectId(int objNum, int objGen) { assert objNum >= OBJ_NUM_TRAILER; assert objGen >= OBJ_NUM_TRAILER; this.objNum = objNum; this.objGen = objGen; } /** * Get the object number of this object; a negative value indicates that * the object is not numbered, as it's not a top-level object: if the value * is {@link #OBJ_NUM_EMBEDDED}, it is because it's embedded within * another object. If the value is {@link #OBJ_NUM_TRAILER}, it's because * it's an object from the trailer. * @return the object number, if positive */ public int getObjNum() { return objNum; } /** * Get the object generation number of this object; a negative value * indicates that the object is not numbered, as it's not a top-level * object: if the value is {@link #OBJ_NUM_EMBEDDED}, it is because it's * embedded within another object. If the value is {@link * #OBJ_NUM_TRAILER}, it's because it's an object from the trailer. * @return the object generation number, if positive */ public int getObjGen() { return objGen; } /** * return a representation of this PDFObject as a String. * Does NOT dereference anything: this is the only method * that allows you to distinguish an INDIRECT PDFObject. */ @Override public String toString() { try { if (type == INDIRECT) { StringBuffer str = new StringBuffer (); str.append("Indirect to #" + ((PDFXref) value).getObjectNumber()); try { str.append("\n" + dereference().toString()); } catch (Throwable t) { str.append(t.toString()); } return str.toString(); } else if (type == BOOLEAN) { return "Boolean: " + (getBooleanValue() ? "true" : "false"); } else if (type == NUMBER) { return "Number: " + getDoubleValue(); } else if (type == STRING) { return "String: " + getStringValue(); } else if (type == NAME) { return "Name: /" + getStringValue(); } else if (type == ARRAY) { return "Array, length=" + ((PDFObject[]) value).length; } else if (type == DICTIONARY) { StringBuffer sb = new StringBuffer(); PDFObject obj = getDictRef("Type"); if (obj != null) { sb.append(obj.getStringValue()); obj = getDictRef("Subtype"); if (obj == null) { obj = getDictRef("S"); } if (obj != null) { sb.append("/" + obj.getStringValue()); } } else { sb.append("Untyped"); } sb.append(" dictionary. Keys:"); HashMap hm = (HashMap) value; Iterator it = hm.entrySet().iterator(); Map.Entry entry; while (it.hasNext()) { entry = (Map.Entry) it.next(); sb.append("\n " + entry.getKey() + " " + entry.getValue()); } return sb.toString(); } else if (type == STREAM) { byte[] st = getStream(); if (st == null) { return "Broken stream"; } return "Stream: [[" + new String(st, 0, st.length > 30 ? 30 : st.length) + "]]"; } else if (type == NULL) { return "Null"; } else if (type == KEYWORD) { return "Keyword: " + getStringValue(); /* } else if (type==IMAGE) { StringBuffer sb= new StringBuffer(); java.awt.Image im= (java.awt.Image)stream; sb.append("Image ("+im.getWidth(null)+"x"+im.getHeight(null)+", with keys:"); HashMap hm= (HashMap)value; Iterator it= hm.keySet().iterator(); while(it.hasNext()) { sb.append(" "+(String)it.next()); } return sb.toString();*/ } else { return "Whoops! big error! Unknown type"; } } catch (IOException ioe) { return "Caught an error: " + ioe; } } /** * Make sure that this object is dereferenced. Use the cache of * an indirect object to cache the dereferenced value, if possible. */ public PDFObject dereference() throws IOException { if (type == INDIRECT) { PDFObject obj = null; if (cache != null) { obj = (PDFObject) cache.get(); } if (obj == null || obj.value == null) { if (owner == null) { System.out.println("Bad seed (owner==null)! Object=" + this); } obj = owner.dereference((PDFXref)value, getDecrypter()); cache = new SoftReference(obj); } return obj; } else { // not indirect, no need to dereference return this; } } /** * Identify whether the object is currently an indirect/cross-reference * @return whether currently indirect */ public boolean isIndirect() { return (type == INDIRECT); } /** * Test whether two PDFObject are equal. Objects are equal IFF they * are the same reference OR they are both indirect objects with the * same id and generation number in their xref */ @Override public boolean equals(Object o) { if (super.equals(o)) { // they are the same object return true; } else if (type == INDIRECT && o instanceof PDFObject) { // they are both PDFObjects. Check type and xref. PDFObject obj = (PDFObject) o; if (obj.type == INDIRECT) { PDFXref lXref = (PDFXref) value; PDFXref rXref = (PDFXref) obj.value; return ((lXref.getObjectNumber() == rXref.getObjectNumber()) && (lXref.getGeneration() == rXref.getGeneration())); } } return false; } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFCmd.java0000644000175000017500000000375611134132451021502 0ustar twernertwerner/* * $Id: PDFCmd.java,v 1.3 2009-01-16 16:26:13 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.geom.Rectangle2D; /** * The abstract superclass of all drawing commands for a PDFPage. * @author Mike Wessler */ public abstract class PDFCmd { /** * mark the page or change the graphics state * @param state the current graphics state; may be modified during * execution. * @return the region of the page made dirty by executing this command * or null if no region was touched. Note this value should be * in the coordinates of the image touched, not the page. */ public abstract Rectangle2D execute(PDFRenderer state); /** * a human readable representation of this command */ @Override public String toString() { String name = getClass().getName(); int lastDot = name.lastIndexOf('.'); if (lastDot >= 0) { return name.substring(lastDot + 1); } else { return name; } } /** * the details of this command */ public String getDetails() { return super.toString(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFXref.java0000644000175000017500000000355211526563523021712 0ustar twernertwerner/* * $Id: PDFXref.java,v 1.4 2009-02-12 13:53:56 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; /** * An indirect reference to some object in the PDFFile * */ public class PDFXref { private int objectNumber; private int generation; /** * create a new PDFXref, given a parsed id and generation. */ public PDFXref(int objectNumber, int gen) { this.objectNumber = objectNumber; this.generation = gen; } /** * get the generation of this object */ public int getGeneration() { return generation; } /** * get the object number of this object */ public int getObjectNumber() { return objectNumber; } @Override public boolean equals(Object obj) { return (obj instanceof PDFXref) && ((PDFXref)obj).objectNumber == objectNumber && ((PDFXref)obj).generation == generation; } @Override public int hashCode() { return objectNumber ^ (generation << 8); } } pdfrenderer-0.9.0/src/com/sun/pdfview/NameTree.java0000644000175000017500000001046211134132451022135 0ustar twernertwerner/* * $Id: NameTree.java,v 1.3 2009-01-16 16:26:09 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.IOException; /** * A PDF name tree consists of three kinds of nodes: *
    *
  • The root node contains only a kids entry, pointing to many * other objects *
  • An intermediate node contains the limits of all the children in * its subtree, and a kids entry for each child *
  • A leaf node contains a set of name-to-object mappings in a dictionary, * as well as the limits of the data contained in that child. *
* A PDF name tree is sorted in accordance with the String.compareTo() method. */ public class NameTree { /** the root object */ private PDFObject root; /** Creates a new instance of NameTree */ public NameTree(PDFObject root) { this.root = root; } /** * Find the PDF object corresponding to the given String in a name tree * * @param key the key we are looking for in the name tree * @return the object associated with str, if found, or null if not */ public PDFObject find(String key) throws IOException { return find(root, key); } /** * Recursively walk the name tree looking for a given value */ private PDFObject find(PDFObject root, String key) throws IOException { // first, look for a Names entry, meaning this is a leaf PDFObject names = root.getDictRef("Names"); if (names != null) { return findInArray(names.getArray(), key); } // no names given, look for kids PDFObject kidsObj = root.getDictRef("Kids"); if (kidsObj != null) { PDFObject[] kids = kidsObj.getArray(); for (int i = 0; i < kids.length; i++) { // find the limits of this kid PDFObject limitsObj = kids[i].getDictRef("Limits"); if (limitsObj != null) { String lowerLimit = limitsObj.getAt(0).getStringValue(); String upperLimit = limitsObj.getAt(1).getStringValue(); // are we in range? if ((key.compareTo(lowerLimit) >= 0) && (key.compareTo(upperLimit) <= 0)) { // we are, so find in this child return find(kids[i], key); } } } } // no luck return null; } /** * Find an object in a (key,value) array. Do this by splitting in half * repeatedly. */ private PDFObject findInArray(PDFObject[] array, String key) throws IOException { int start = 0; int end = array.length / 2; while (end >= start && start >= 0 && end < array.length) { // find the key at the midpoint int pos = start + ((end - start) / 2); String posKey = array[pos * 2].getStringValue(); // compare the key to the key we are looking for int comp = key.compareTo(posKey); if (comp == 0) { // they match. Return the value return array[(pos * 2) + 1]; } else if (comp > 0) { // too big, search the top half of the tree start = pos + 1; } else if (comp < 0) { // too small, search the bottom half of the tree end = pos - 1; } } // not found return null; } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFDestination.java0000644000175000017500000002140711134132451023251 0ustar twernertwerner/* * $Id: PDFDestination.java,v 1.3 2009-01-16 16:26:09 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.IOException; /** * Represents a destination in a PDF file. Destinations take 3 forms: *
    *
  • An explicit destination, which contains a reference to a page * as well as some stuff about how to fit it into the window. *
  • A named destination, which uses the PDF file's Dests entry * in the document catalog to map a name to an explicit destination *
  • A string destintation, which uses the PDF file's Dests entry. * in the name directory to map a string to an explicit destination. *
* * All three of these cases are handled by the getDestination() method. */ public class PDFDestination { /** The known types of destination */ public static final int XYZ = 0; public static final int FIT = 1; public static final int FITH = 2; public static final int FITV = 3; public static final int FITR = 4; public static final int FITB = 5; public static final int FITBH = 6; public static final int FITBV = 7; /** the type of this destination (from the list above) */ private int type; /** the page we refer to */ private PDFObject pageObj; /** the left coordinate of the fit area, if applicable */ private float left; /** the right coordinate of the fit area, if applicable */ private float right; /** the top coordinate of the fit area, if applicable */ private float top; /** the bottom coordinate of the fit area, if applicable */ private float bottom; /** the zoom, if applicable */ private float zoom; /** * Creates a new instance of PDFDestination * * @param pageObj the page object this destination refers to * @param type the type of page this object refers to */ protected PDFDestination(PDFObject pageObj, int type) { this.pageObj = pageObj; this.type = type; } /** * Get a destination from either an array (explicit destination), a * name (named destination) or a string (name tree destination). * * @param obj the PDFObject representing this destination * @param root the root of the PDF object tree */ public static PDFDestination getDestination(PDFObject obj, PDFObject root) throws IOException { // resolve string and name issues if (obj.getType() == PDFObject.NAME) { obj = getDestFromName(obj, root); } else if (obj.getType() == PDFObject.STRING) { obj = getDestFromString(obj, root); } // make sure we have the right kind of object if (obj == null || obj.getType() != PDFObject.ARRAY) { throw new PDFParseException("Can't create destination from: " + obj); } // the array is in the form [page type args ... ] PDFObject[] destArray = obj.getArray(); // create the destination based on the type PDFDestination dest = null; String type = destArray[1].getStringValue(); if (type.equals("XYZ")) { dest = new PDFDestination(destArray[0], XYZ); } else if (type.equals("Fit")) { dest = new PDFDestination(destArray[0], FIT); } else if (type.equals("FitH")) { dest = new PDFDestination(destArray[0], FITH); } else if (type.equals("FitV")) { dest = new PDFDestination(destArray[0], FITV); } else if (type.equals("FitR")) { dest = new PDFDestination(destArray[0], FITR); } else if (type.equals("FitB")) { dest = new PDFDestination(destArray[0], FITB); } else if (type.equals("FitBH")) { dest = new PDFDestination(destArray[0], FITBH); } else if (type.equals("FitBV")) { dest = new PDFDestination(destArray[0], FITBV); } else { throw new PDFParseException("Unknown destination type: " + type); } // now fill in the arguments based on the type switch (dest.getType()) { case XYZ: dest.setLeft(destArray[2].getFloatValue()); dest.setTop(destArray[3].getFloatValue()); dest.setZoom(destArray[4].getFloatValue()); break; case FITH: dest.setTop(destArray[2].getFloatValue()); break; case FITV: dest.setLeft(destArray[2].getFloatValue()); break; case FITR: dest.setLeft(destArray[2].getFloatValue()); dest.setBottom(destArray[3].getFloatValue()); dest.setRight(destArray[4].getFloatValue()); dest.setTop(destArray[5].getFloatValue()); break; case FITBH: dest.setTop(destArray[2].getFloatValue()); break; case FITBV: dest.setLeft(destArray[2].getFloatValue()); break; } return dest; } /** * Get the type of this destination */ public int getType() { return type; } /** * Get the PDF Page object associated with this destination */ public PDFObject getPage() { return pageObj; } /** * Get the left coordinate value */ public float getLeft() { return left; } /** * Set the left coordinate value */ public void setLeft(float left) { this.left = left; } /** * Get the right coordinate value */ public float getRight() { return right; } /** * Set the right coordinate value */ public void setRight(float right) { this.right = right; } /** * Get the top coordinate value */ public float getTop() { return top; } /** * Set the top coordinate value */ public void setTop(float top) { this.top = top; } /** * Get the bottom coordinate value */ public float getBottom() { return bottom; } /** * Set the bottom coordinate value */ public void setBottom(float bottom) { this.bottom = bottom; } /** * Get the zoom value */ public float getZoom() { return zoom; } /** * Set the zoom value */ public void setZoom(float zoom) { this.zoom = zoom; } /** * Get a destination, given a name. This means the destination is in * the root node's dests dictionary. */ private static PDFObject getDestFromName(PDFObject name, PDFObject root) throws IOException { // find the dests object in the root node PDFObject dests = root.getDictRef("Dests"); if (dests != null) { // find this name in the dests dictionary return dests.getDictRef(name.getStringValue()); } // not found return null; } /** * Get a destination, given a string. This means the destination is in * the root node's names dictionary. */ private static PDFObject getDestFromString(PDFObject str, PDFObject root) throws IOException { // find the names object in the root node PDFObject names = root.getDictRef("Names"); if (names != null) { // find the dests entry in the names dictionary PDFObject dests = names.getDictRef("Dests"); if (dests != null) { // create a name tree object NameTree tree = new NameTree(dests); // find the value we're looking for PDFObject obj = tree.find(str.getStringValue()); // if we get back a dictionary, look for the /D value if (obj != null && obj.getType() == PDFObject.DICTIONARY) { obj = obj.getDictRef("D"); } // found it return obj; } } // not found return null; } } pdfrenderer-0.9.0/src/com/sun/pdfview/ImageInfo.java0000644000175000017500000000444711134132451022301 0ustar twernertwerner/* * $Id: ImageInfo.java,v 1.3 2009-01-16 16:26:11 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.geom.Rectangle2D; import java.awt.Color; public class ImageInfo { int width; int height; Rectangle2D clip; Color bgColor; public ImageInfo(int width, int height, Rectangle2D clip) { this(width, height, clip, Color.WHITE); } public ImageInfo(int width, int height, Rectangle2D clip, Color bgColor) { this.width = width; this.height = height; this.clip = clip; this.bgColor = bgColor; } // a hashcode that uses width, height and clip to generate its number @Override public int hashCode() { int code = (width ^ height << 16); if (clip != null) { code ^= ((int) clip.getWidth() | (int) clip.getHeight()) << 8; code ^= ((int) clip.getMinX() | (int) clip.getMinY()); } return code; } // an equals method that compares values @Override public boolean equals(Object o) { if (!(o instanceof ImageInfo)) { return false; } ImageInfo ii = (ImageInfo) o; if (width != ii.width || height != ii.height) { return false; } else if (clip != null && ii.clip != null) { return clip.equals(ii.clip); } else if (clip == null && ii.clip == null) { return true; } else { return false; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/action/0000755000175000017500000000000011622545450021055 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/action/PDFAction.java0000644000175000017500000000561310732532577023503 0ustar twernertwerner/* * $Id: PDFAction.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.action; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * The common super-class of all PDF actions. */ public class PDFAction { /** the type of this action */ private String type; /** the next action or array of actions */ private PDFObject next; /** Creates a new instance of PDFAction */ public PDFAction(String type) { this.type = type; } /** * Get an action of the appropriate type from a PDFObject * * @param obj the PDF object containing the action to parse * @param root the root of the PDF object tree */ public static PDFAction getAction(PDFObject obj, PDFObject root) throws IOException { // figure out the action type PDFObject typeObj = obj.getDictRef("S"); if (typeObj == null) { throw new PDFParseException("No action type in object: " + obj); } // create the action based on the type PDFAction action = null; String type = typeObj.getStringValue(); if (type.equals("GoTo")) { action = new GoToAction(obj, root); } else { /** [JK FIXME: Implement other action types! ] */ throw new PDFParseException("Unknown Action type: " + type); } // figure out if there is a next action PDFObject nextObj = obj.getDictRef("Next"); if (nextObj != null) { action.setNext(nextObj); } // return the action return action; } /** * Get the type of this action */ public String getType() { return type; } /** * Get the next action or array of actions */ public PDFObject getNext() { return next; } /** * Set the next action or array of actions */ public void setNext(PDFObject next) { this.next = next; } } pdfrenderer-0.9.0/src/com/sun/pdfview/action/GoToAction.java0000644000175000017500000000420110732532577023732 0ustar twernertwerner/* * $Id: GoToAction.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.action; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFDestination; import com.sun.pdfview.PDFParseException; /** * An action which specifies going to a particular destination */ public class GoToAction extends PDFAction { /** the destination to go to */ private PDFDestination dest; /** * Creates a new instance of GoToAction from an object * * @param obj the PDFObject with the action information */ public GoToAction(PDFObject obj, PDFObject root) throws IOException { super("GoTo"); // find the destination PDFObject destObj = obj.getDictRef("D"); if (destObj == null) { throw new PDFParseException("No destination in GoTo action " + obj); } // parse it dest = PDFDestination.getDestination(destObj, root); } /** * Create a new GoToAction from a destination */ public GoToAction(PDFDestination dest) { super("GoTo"); this.dest = dest; } /** * Get the destination this action refers to */ public PDFDestination getDestination() { return dest; } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFXrefEntry.java0000644000175000017500000001642311526563523022735 0ustar twernertwerner/* * $Id$ * * Copyright 2011 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.lang.ref.SoftReference; /** * An entry found in a PDFFile's xref table or xref streams, identifying * the position of an object within the structure of a PDF, and the latest * generation number for a given object. May also indicate that * a given object number has been freed, and that references to objects * with that object number should be treated as references to the null * object. * * @author Luke Kirby, Pirion Systems */ public class PDFXrefEntry { private static final PDFXrefEntry FREED_OBJECT = new PDFXrefEntry(Type.FREE, -1, -1, null); static PDFXrefEntry toBodyObject(int generation, int offset) { return new PDFXrefEntry(Type.OBJ_IN_BODY, generation, offset, null); } static PDFXrefEntry toStreamObject(PDFXref stream, int index) { // stream objects will always have generation 0 return new PDFXrefEntry(Type.OBJ_IN_STREAM, 0, index, stream); } static PDFXrefEntry forFreedObject() { return FREED_OBJECT; } public boolean resolves(PDFXref ref) { // it's expected that the object number is relevant return type != Type.FREE && generation == ref.getGeneration(); } enum Type { /** * Identifies a deleted object. A Type 0 reference in an xref stream, * or an 'f' entry in an xref table. */ FREE, /** * Identifies a reference to an (uncompressed) object that isn't * part of a (compressed) stream, like one might see in pre-1.5 * PDFs. * Identifies a deleted object. A Type 1 reference in an * xref stream or an 'n' entry in an xref table. */ OBJ_IN_BODY, /** * Identifies a reference to an object that's in a (probably compressed) * stream. A Type 2 reference in an xref stream. */ OBJ_IN_STREAM; public static Type forTypeField(int i) { if (i > 0 && i < 3) { return values()[i]; } else { // if the type field is illegal then it should be treated // as a null object, and returning a free field will // do the job quite nicely! return FREE; } } /** * Make an entry for a given type based on the values of field 2 * and field 3 in an xref stream * @param field2 the value of field 2 * @param field3 the value of field 3 * @return a corresponding entry */ public PDFXrefEntry makeXrefStreamEntry(int field2, int field3) { switch (this) { case FREE: return forFreedObject(); case OBJ_IN_BODY: return toBodyObject(field3, field2); case OBJ_IN_STREAM: return toStreamObject(new PDFXref(field2, 0), field3); default: throw new UnsupportedOperationException( "Unhandled xref entry type " + this); } } }; /** The type of cross-ref entry*/ private Type type; /** * The generation number for the entry; note that there's no need for us * to actually store the object number itself here due to the manner * in which this object is stored, but we require the generation number * to ensure that dereferences to previous generations of this object number * result in the null object being returned */ private int generation; /** * The offset into the file for in-body references, or the index of * the object within the given stream for in-stream references. */ private int offset; /** The reference to the stream for in-stream references */ private PDFXref stream; /** * For entries that point to an object stream, we cache the index offsets * here rather than parsing each time or * placing another field on PDFObject */ private int[] objectIndexOffsets = null; /** A cached reference of the resolved object */ private SoftReference target = null; /** * Class constructor * @param type the type of entry * @param generation the generation number of the object the entry is for * @param offset the offset of the object for in-body references, or the * index of an object for in-stream references; ignored for freed entries * @param stream a reference to the stream for in-stream references */ private PDFXrefEntry(Type type, int generation, int offset, PDFXref stream) { this.type = type; this.generation = generation; this.offset = offset; this.stream = stream; } /** * @return the offset into the file for in-body references, or the index of * the object within the given stream for in-stream references. */ public int getOffset() { return offset; } /** * @return the stream of the object for in-stream references; * null for other entry types */ public PDFXref getStream() { return stream; } /** * @return the type of entry */ public Type getType() { return type; } /** * @return the generation number of the object this entry is for */ public int getGeneration() { return generation; } /** * @return any cached reference to the object that his entry refers to; * null if this entry has yet to be looked at, or its * target has been garbage collected */ public PDFObject getObject() { if (target != null) { return (PDFObject) target.get(); } return null; } /** * Cache a reference to the target object of this entry * @param obj the object to cache */ public void setObject(PDFObject obj) { this.target = new SoftReference(obj); } /** * @return for entries for object streams, the offsets of each object * in the stream, arranged by index number */ public int[] getObjectIndexOffsets() { return objectIndexOffsets; } /** * For entries for object streams, set the offsets of each object * in the stream, arranged by index number * @param objectIndexOffsets the object index offsets */ public void setObjectIndexOffsets(int[] objectIndexOffsets) { this.objectIndexOffsets = objectIndexOffsets; } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFRenderer.java0000644000175000017500000006276511376325030022557 0ustar twernertwerner/* * $Id: PDFRenderer.java,v 1.9 2010-05-23 22:20:08 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Stack; /** * This class turns a set of PDF Commands from a PDF page into an image. It * encapsulates the state of drawing in terms of stroke, fill, transform, * etc., as well as pushing and popping these states. * * When the run method is called, this class goes through all remaining commands * in the PDF Page and draws them to its buffered image. It then updates any * ImageConsumers with the drawn data. */ public class PDFRenderer extends BaseWatchable implements Runnable { /** the page we were generate from */ private PDFPage page; /** where we are in the page's command list */ private int currentCommand; /** a weak reference to the image we render into. For the image * to remain available, some other code must retain a strong reference to it. */ private WeakReference imageRef; /** the graphics object for use within an iteration. Note this must be * set to null at the end of each iteration, or the image will not be * collected */ private Graphics2D g; /** the current graphics state */ private GraphicsState state; /** the stack of push()ed graphics states */ private Stack stack; /** the total region of this image that has been written to */ private Rectangle2D globalDirtyRegion; /** the image observers that will be updated when this image changes */ private List observers; /** the last shape we drew (to check for overlaps) */ private GeneralPath lastShape; /** the info about the image, if we need to recreate it */ private ImageInfo imageinfo; /** the next time the image should be notified about updates */ private long then = 0; /** the sum of all the individual dirty regions since the last update */ private Rectangle2D unupdatedRegion; /** how long (in milliseconds) to wait between image updates */ public static final long UPDATE_DURATION = 200; public static final float NOPHASE = -1000; public static final float NOWIDTH = -1000; public static final float NOLIMIT = -1000; public static final int NOCAP = -1000; public static final float[] NODASH = null; public static final int NOJOIN = -1000; /** * create a new PDFGraphics state * @param page the current page * @param imageinfo the paramters of the image to render */ public PDFRenderer(PDFPage page, ImageInfo imageinfo, BufferedImage bi) { super(); this.page = page; this.imageinfo = imageinfo; this.imageRef = new WeakReference(bi); // initialize the list of observers observers = new ArrayList(); } /** * create a new PDFGraphics state, given a Graphics2D. This version * will not create an image, and you will get a NullPointerException * if you attempt to call getImage(). * @param page the current page * @param g the Graphics2D object to use for drawing * @param imgbounds the bounds of the image into which to fit the page * @param clip the portion of the page to draw, in page space, or null * if the whole page should be drawn * @param bgColor the color to draw the background of the image, or * null for no color (0 alpha value) */ public PDFRenderer(PDFPage page, Graphics2D g, Rectangle imgbounds, Rectangle2D clip, Color bgColor) { super(); this.page = page; this.g = g; this.imageinfo = new ImageInfo(imgbounds.width, imgbounds.height, clip, bgColor); g.translate(imgbounds.x, imgbounds.y); // System.out.println("Translating by "+imgbounds.x+","+imgbounds.y); // initialize the list of observers observers = new ArrayList(); } /** * Set up the graphics transform to match the clip region * to the image size. */ private void setupRendering(Graphics2D g) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); if (imageinfo.bgColor != null) { g.setColor(imageinfo.bgColor); g.fillRect(0, 0, imageinfo.width, imageinfo.height); } g.setColor(Color.BLACK); // set the initial clip and transform on the graphics AffineTransform at = getInitialTransform(); g.transform(at); // set up the initial graphics state state = new GraphicsState(); state.cliprgn = null; state.stroke = new BasicStroke(); state.strokePaint = PDFPaint.getColorPaint(Color.black); state.fillPaint = state.strokePaint; state.fillAlpha = AlphaComposite.getInstance(AlphaComposite.SRC); state.strokeAlpha = AlphaComposite.getInstance(AlphaComposite.SRC); state.xform = g.getTransform(); // initialize the stack stack = new Stack(); // initialize the current command currentCommand = 0; } /** * push the current graphics state onto the stack. Continue working * with the current object; calling pop() restores the state of this * object to its state when push() was called. */ public void push() { state.cliprgn = g.getClip(); stack.push(state); state = (GraphicsState) state.clone(); } /** * restore the state of this object to what it was when the previous * push() was called. */ public void pop() { state = (GraphicsState) stack.pop(); setTransform(state.xform); setClip(state.cliprgn); } /** * draw an outline using the current stroke and draw paint * @param s the path to stroke * @return a Rectangle2D to which the current region being * drawn will be added. May also be null, in which case no dirty * region will be recorded. */ public Rectangle2D stroke(GeneralPath s) { g.setComposite(state.strokeAlpha); s = new GeneralPath(autoAdjustStrokeWidth(g, state.stroke).createStrokedShape(s)); return state.strokePaint.fill(this, g, s); } /** * auto adjust the stroke width, according to 6.5.4, which presumes that * the device characteristics (an image) require a single pixel wide * line, even if the width is set to less. We determine the scaling to * see if we would produce a line that was too small, and if so, scale * it up to produce a graphics line of 1 pixel, or so. This matches our * output with Adobe Reader. * * @param g * @param bs * @return */ private BasicStroke autoAdjustStrokeWidth(Graphics2D g, BasicStroke bs) { AffineTransform bt = new AffineTransform(g.getTransform()); float width = bs.getLineWidth() * (float) bt.getScaleX(); BasicStroke stroke = bs; if (width < 1f) { if (bt.getScaleX() > 0.01) { width = 1.0f / (float) bt.getScaleX(); } else { // prevent division by a really small number width = 1.0f; } stroke = new BasicStroke(width, bs.getEndCap(), bs.getLineJoin(), bs.getMiterLimit(), bs.getDashArray(), bs.getDashPhase()); } return stroke; } /** * draw an outline. * @param p the path to draw * @param bs the stroke with which to draw the path */ public void draw(GeneralPath p, BasicStroke bs) { g.setComposite(state.fillAlpha); g.setPaint(state.fillPaint.getPaint()); g.setStroke(autoAdjustStrokeWidth(g, bs)); g.draw(p); } /** * fill an outline using the current fill paint * @param s the path to fill */ public Rectangle2D fill(GeneralPath s) { g.setComposite(state.fillAlpha); return state.fillPaint.fill(this, g, s); } /** * draw an image. * @param image the image to draw */ public Rectangle2D drawImage(PDFImage image) { AffineTransform at = new AffineTransform(1f / image.getWidth(), 0, 0, -1f / image.getHeight(), 0, 1); BufferedImage bi = image.getImage(); if (image.isImageMask()) { bi = getMaskedImage(bi); } /* javax.swing.JFrame frame = new javax.swing.JFrame("Original Image"); frame.getContentPane().add(new javax.swing.JLabel(new javax.swing.ImageIcon(bi))); frame.pack(); frame.show(); */ g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); if (!g.drawImage(bi, at, null)) { System.out.println("Image not completed!"); } // get the total transform that was executed AffineTransform bt = new AffineTransform(g.getTransform()); bt.concatenate(at); double minx = bi.getMinX(); double miny = bi.getMinY(); double[] points = new double[]{ minx, miny, minx + bi.getWidth(), miny + bi.getHeight() }; bt.transform(points, 0, points, 0, 2); return new Rectangle2D.Double(points[0], points[1], points[2] - points[0], points[3] - points[1]); } /** * add the path to the current clip. The new clip will be the intersection * of the old clip and given path. */ public void clip(GeneralPath s) { g.clip(s); } /** * set the clip to be the given shape. The current clip is not taken * into account. */ private void setClip(Shape s) { state.cliprgn = s; g.setClip(null); g.clip(s); } /** * get the current affinetransform */ public AffineTransform getTransform() { return state.xform; } /** * concatenate the given transform with the current transform */ public void transform(AffineTransform at) { state.xform.concatenate(at); g.setTransform(state.xform); } /** * replace the current transform with the given one. */ public void setTransform(AffineTransform at) { state.xform = at; g.setTransform(state.xform); } /** * get the initial transform from page space to Java space */ public AffineTransform getInitialTransform() { return page.getInitialTransform(imageinfo.width, imageinfo.height, imageinfo.clip); } /** * Set some or all aspects of the current stroke. * @param w the width of the stroke, or NOWIDTH to leave it unchanged * @param cap the end cap style, or NOCAP to leave it unchanged * @param join the join style, or NOJOIN to leave it unchanged * @param limit the miter limit, or NOLIMIT to leave it unchanged * @param phase the phase of the dash array, or NOPHASE to leave it * unchanged * @param ary the dash array, or null to leave it unchanged. phase * and ary must both be valid, or phase must be NOPHASE while ary is null. */ public void setStrokeParts(float w, int cap, int join, float limit, float[] ary, float phase) { if (w == NOWIDTH) { w = state.stroke.getLineWidth(); } if (cap == NOCAP) { cap = state.stroke.getEndCap(); } if (join == NOJOIN) { join = state.stroke.getLineJoin(); } if (limit == NOLIMIT) { limit = state.stroke.getMiterLimit(); } if (phase == NOPHASE) { ary = state.stroke.getDashArray(); phase = state.stroke.getDashPhase(); } if (ary != null && ary.length == 0) { ary = null; } if (phase == NOPHASE) { state.stroke = new BasicStroke(w, cap, join, limit); } else { state.stroke = new BasicStroke(w, cap, join, limit, ary, phase); } } /** * get the current stroke as a BasicStroke */ public BasicStroke getStroke() { return state.stroke; } /** * set the current stroke as a BasicStroke */ public void setStroke(BasicStroke bs) { state.stroke = bs; } /** * set the stroke color */ public void setStrokePaint(PDFPaint paint) { state.strokePaint = paint; } /** * set the fill color */ public void setFillPaint(PDFPaint paint) { state.fillPaint = paint; } /** * set the stroke alpha */ public void setStrokeAlpha(float alpha) { state.strokeAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha); } /** * set the stroke alpha */ public void setFillAlpha(float alpha) { state.fillAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha); } /** * Add an image observer */ public void addObserver(ImageObserver observer) { if (observer == null) { return; } // update the new observer to the current state Image i = (Image) imageRef.get(); if (rendererFinished()) { // if we're finished, just send a finished notification, don't // add to the list of observers // System.out.println("Late notify"); observer.imageUpdate(i, ImageObserver.ALLBITS, 0, 0, imageinfo.width, imageinfo.height); return; } else { // if we're not yet finished, add to the list of observers and // notify of the current dirty region synchronized (observers) { observers.add(observer); } if (globalDirtyRegion != null) { observer.imageUpdate(i, ImageObserver.SOMEBITS, (int) globalDirtyRegion.getMinX(), (int) globalDirtyRegion.getMinY(), (int) globalDirtyRegion.getWidth(), (int) globalDirtyRegion.getHeight()); } } } /** * Remove an image observer */ public void removeObserver(ImageObserver observer) { synchronized (observers) { observers.remove(observer); } } /** * Set the last shape drawn */ public void setLastShape(GeneralPath shape) { this.lastShape = shape; } /** * Get the last shape drawn */ public GeneralPath getLastShape() { return lastShape; } /** * Setup rendering. Called before iteration begins */ @Override public void setup() { Graphics2D graphics = null; if (imageRef != null) { BufferedImage bi = (BufferedImage) imageRef.get(); if (bi != null) { graphics = bi.createGraphics(); } } else { graphics = g; } if (graphics != null) { setupRendering(graphics); } } /** * Draws the next command in the PDFPage to the buffered image. * The image will be notified about changes no less than every * UPDATE_DURATION milliseconds. * * @return
  • Watchable.RUNNING when there are commands to be processed *
  • Watchable.NEEDS_DATA when there are no commands to be * processed, but the page is not yet complete *
  • Watchable.COMPLETED when the page is done and all * the commands have been processed *
  • Watchable.STOPPED if the image we are rendering into * has gone away *
*/ public int iterate() throws Exception { // make sure we have a page to render if (page == null) { return Watchable.COMPLETED; } // check if this renderer is based on a weak reference to a graphics // object. If it is, and the graphics is no longer valid, then just quit BufferedImage bi = null; if (imageRef != null) { bi = (BufferedImage) imageRef.get(); if (bi == null) { System.out.println("Image went away. Stopping"); return Watchable.STOPPED; } g = (Graphics2D) bi.createGraphics(); } // check if there are any commands to parse. If there aren't, // just return, but check if we'return really finished or not if (currentCommand >= page.getCommandCount()) { if (page.isFinished()) { return Watchable.COMPLETED; } else { return Watchable.NEEDS_DATA; } } // find the current command PDFCmd cmd = page.getCommand(currentCommand++); if (cmd == null) { // uh oh. Synchronization problem! throw new PDFParseException("Command not found!"); } // execute the command Rectangle2D dirtyRegion = cmd.execute(this); // append to the global dirty region globalDirtyRegion = addDirtyRegion(dirtyRegion, globalDirtyRegion); unupdatedRegion = addDirtyRegion(dirtyRegion, unupdatedRegion); long now = System.currentTimeMillis(); if (now > then || rendererFinished()) { // now tell any observers, so they can repaint notifyObservers(bi, unupdatedRegion); unupdatedRegion = null; then = now + UPDATE_DURATION; } // if we are based on a reference to a graphics, don't hold on to it // since that will prevent the image from being collected. if (imageRef != null) { g = null; } // if we need to stop, it will be caught at the start of the next // iteration. return Watchable.RUNNING; } /** * Called when iteration has stopped */ @Override public void cleanup() { page = null; state = null; stack = null; globalDirtyRegion = null; lastShape = null; observers.clear(); // keep around the image ref and image info for use in // late addObserver() call } /** * Append a rectangle to the total dirty region of this shape */ private Rectangle2D addDirtyRegion(Rectangle2D region, Rectangle2D glob) { if (region == null) { return glob; } else if (glob == null) { return region; } else { Rectangle2D.union(glob, region, glob); return glob; } } /** * Determine if we are finished */ private boolean rendererFinished() { if (page == null) { return true; } return (page.isFinished() && currentCommand == page.getCommandCount()); } /** * Notify the observer that a region of the image has changed */ private void notifyObservers(BufferedImage bi, Rectangle2D region) { if (bi == null) { return; } int startx, starty, width, height; int flags = 0; // don't do anything if nothing is there or no one is listening if ((region == null && !rendererFinished()) || observers == null || observers.size() == 0) { return; } if (region != null) { // get the image data for the total dirty region startx = (int) Math.floor(region.getMinX()); starty = (int) Math.floor(region.getMinY()); width = (int) Math.ceil(region.getWidth()); height = (int) Math.ceil(region.getHeight()); // sometimes width or height is negative. Grrr... if (width < 0) { startx += width; width = -width; } if (height < 0) { starty += height; height = -height; } flags = 0; } else { startx = 0; starty = 0; width = imageinfo.width; height = imageinfo.height; } if (rendererFinished()) { flags |= ImageObserver.ALLBITS; // forget about the Graphics -- allows the image to be // garbage collected. g = null; } else { flags |= ImageObserver.SOMEBITS; } synchronized (observers) { for (Iterator i = observers.iterator(); i.hasNext();) { ImageObserver observer = (ImageObserver) i.next(); boolean result = observer.imageUpdate(bi, flags, startx, starty, width, height); // if result is false, the observer no longer wants to // be notified of changes if (!result) { i.remove(); } } } } /** * Convert an image mask into an image by painting over any pixels * that have a value in the image with the current paint */ private BufferedImage getMaskedImage(BufferedImage bi) { // get the color of the current paint Color col = (Color) state.fillPaint.getPaint(); // format as 8 bits each of ARGB int paintColor = col.getAlpha() << 24; paintColor |= col.getRed() << 16; paintColor |= col.getGreen() << 8; paintColor |= col.getBlue(); // transparent (alpha = 1) int noColor = 0; // get the coordinates of the source image int startX = bi.getMinX(); int startY = bi.getMinY(); int width = bi.getWidth(); int height = bi.getHeight(); // create a destion image of the same size BufferedImage dstImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // copy the pixels row by row for (int i = 0; i < height; i++) { int[] srcPixels = new int[width]; int[] dstPixels = new int[srcPixels.length]; // read a row of pixels from the source bi.getRGB(startX, startY + i, width, 1, srcPixels, 0, height); // figure out which ones should get painted for (int j = 0; j < srcPixels.length; j++) { if (srcPixels[j] == 0xff000000) { dstPixels[j] = paintColor; } else { dstPixels[j] = noColor; } } // write the destination image dstImage.setRGB(startX, startY + i, width, 1, dstPixels, 0, height); } return dstImage; } class GraphicsState implements Cloneable { /** the clip region */ Shape cliprgn; /** the current stroke */ BasicStroke stroke; /** the current paint for drawing strokes */ PDFPaint strokePaint; /** the current paint for filling shapes */ PDFPaint fillPaint; /** the current compositing alpha for stroking */ AlphaComposite strokeAlpha; /** the current compositing alpha for filling */ AlphaComposite fillAlpha; /** the current transform */ AffineTransform xform; /** Clone this Graphics state. * * Note that cliprgn is not cloned. It must be set manually from * the current graphics object's clip */ @Override public Object clone() { GraphicsState cState = new GraphicsState(); cState.cliprgn = null; // copy immutable fields cState.strokePaint = strokePaint; cState.fillPaint = fillPaint; cState.strokeAlpha = strokeAlpha; cState.fillAlpha = fillAlpha; // clone mutable fields cState.stroke = new BasicStroke(stroke.getLineWidth(), stroke.getEndCap(), stroke.getLineJoin(), stroke.getMiterLimit(), stroke.getDashArray(), stroke.getDashPhase()); cState.xform = (AffineTransform) xform.clone(); return cState; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/Cache.java0000644000175000017500000002313111145024767021451 0ustar twernertwerner/* * $Id: Cache.java,v 1.4 2009-02-12 13:53:56 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.image.BufferedImage; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * A cache of PDF pages and images. */ public class Cache { /** the pages in the cache, mapped by page number */ private Map pages; /** Creates a new instance of a Cache */ public Cache() { pages = Collections.synchronizedMap(new HashMap()); } /** * Add a page to the cache. This method should be used for * pages which have already been completely rendered. * * @param pageNumber the page number of this page * @param page the page to add */ public void addPage(Integer pageNumber, PDFPage page) { addPageRecord(pageNumber, page, null); } /** * Add a page to the cache. This method should be used for * pages which are still in the process of being rendered. * * @param pageNumber the page number of this page * @param page the page to add * @param parser the parser which is parsing this page */ public void addPage(Integer pageNumber, PDFPage page, PDFParser parser) { addPageRecord(pageNumber, page, parser); } /** * Add an image to the cache. This method should be used for images * which have already been completely rendered * * @param page page this image is associated with * @param info the image info associated with this image * @param image the image to add */ public void addImage(PDFPage page, ImageInfo info, BufferedImage image) { addImageRecord(page, info, image, null); } /** * Add an image to the cache. This method should be used for images * which are still in the process of being rendered. * * @param page the page this image is associated with * @param info the image info associated with this image * @param image the image to add * @param renderer the renderer which is rendering this page */ public void addImage(PDFPage page, ImageInfo info, BufferedImage image, PDFRenderer renderer) { addImageRecord(page, info, image, renderer); } /** * Get a page from the cache * * @param pageNumber the number of the page to get * @return the page, if it is in the cache, or null if not */ public PDFPage getPage(Integer pageNumber) { PageRecord rec = getPageRecord(pageNumber); if (rec != null) { return (PDFPage) rec.value; } // not found return null; } /** * Get a page's parser from the cache * * @param pageNumber the number of the page to get the parser for * @return the parser, or null if it is not in the cache */ public PDFParser getPageParser(Integer pageNumber) { PageRecord rec = getPageRecord(pageNumber); if (rec != null) { return (PDFParser) rec.generator; } // not found return null; } /** * Get an image from the cache * * @param page the page the image is associated with * @param info the image info that describes the image * * @return the image if it is in the cache, or null if not */ public BufferedImage getImage(PDFPage page, ImageInfo info) { Record rec = getImageRecord(page, info); if (rec != null) { return (BufferedImage) rec.value; } // not found return null; } /** * Get an image's renderer from the cache * * @param page the page this image was generated from * @param info the image info describing the image * @return the renderer, or null if it is not in the cache */ public PDFRenderer getImageRenderer(PDFPage page, ImageInfo info) { Record rec = getImageRecord(page, info); if (rec != null) { return (PDFRenderer) rec.generator; } // not found return null; } /** * Remove a page and all its associated images, as well as its parser * and renderers, from the cache * * @param pageNumber the number of the page to remove */ public void removePage(Integer pageNumber) { removePageRecord(pageNumber); } /** * Remove an image and its associated renderer from the cache * * @param page the page the image is generated from * @param info the image info of the image to remove */ public void removeImage(PDFPage page, ImageInfo info) { removeImageRecord(page, info); } /** * The internal routine to add a page to the cache, and return the * page record which was generated */ PageRecord addPageRecord(Integer pageNumber, PDFPage page, PDFParser parser) { PageRecord rec = new PageRecord(); rec.value = page; rec.generator = parser; pages.put(pageNumber, new SoftReference(rec)); return rec; } /** * Get a page's record from the cache * * @return the record, or null if it's not in the cache */ PageRecord getPageRecord(Integer pageNumber) { // System.out.println("Request for page " + pageNumber); SoftReference ref = pages.get(pageNumber); if (ref != null) { String val = (ref.get() == null) ? " not in " : " in "; // System.out.println("Page " + pageNumber + val + "cache"); return (PageRecord) ref.get(); } // System.out.println("Page " + pageNumber + " not in cache"); // not in cache return null; } /** * Remove a page's record from the cache */ PageRecord removePageRecord(Integer pageNumber) { SoftReference ref = pages.remove(pageNumber); if (ref != null) { return (PageRecord) ref.get(); } // not in cache return null; } /** * The internal routine to add an image to the cache and return the * record that was generated. */ Record addImageRecord(PDFPage page, ImageInfo info, BufferedImage image, PDFRenderer renderer) { // first, find or create the relevant page record Integer pageNumber = new Integer(page.getPageNumber()); PageRecord pageRec = getPageRecord(pageNumber); if (pageRec == null) { pageRec = addPageRecord(pageNumber, page, null); } // next, create the image record Record rec = new Record(); rec.value = image; rec.generator = renderer; // add it to the cache pageRec.images.put(info, new SoftReference(rec)); return rec; } /** * Get an image's record from the cache * * @return the record, or null if it's not in the cache */ Record getImageRecord(PDFPage page, ImageInfo info) { // first find the relevant page record Integer pageNumber = new Integer(page.getPageNumber()); // System.out.println("Request for image on page " + pageNumber); PageRecord pageRec = getPageRecord(pageNumber); if (pageRec != null) { SoftReference ref = pageRec.images.get(info); if (ref != null) { String val = (ref.get() == null) ? " not in " : " in "; // System.out.println("Image on page " + pageNumber + val + " cache"); return (Record) ref.get(); } } // System.out.println("Image on page " + pageNumber + " not in cache"); // not found return null; } /** * Remove an image's record from the cache */ Record removeImageRecord(PDFPage page, ImageInfo info) { // first find the relevant page record Integer pageNumber = new Integer(page.getPageNumber()); PageRecord pageRec = getPageRecord(pageNumber); if (pageRec != null) { SoftReference ref = pageRec.images.remove(info); if (ref != null) { return (Record) ref.get(); } } return null; } /** the basic information about a page or image */ class Record { /** the page or image itself */ Object value; /** the thing generating the page, or null if done/not provided */ BaseWatchable generator; } /** the record stored for each page in the cache */ class PageRecord extends Record { /** any images associated with the page */ Map> images; /** create a new page record */ public PageRecord() { images = Collections.synchronizedMap(new HashMap>()); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFParser.java0000644000175000017500000014157511376323412022244 0ustar twernertwerner/* * $Id: PDFParser.java,v 1.14 2010-05-23 22:07:05 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import static java.awt.geom.GeneralPath.WIND_EVEN_ODD; import static java.awt.geom.GeneralPath.WIND_NON_ZERO; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.Stack; import com.sun.pdfview.colorspace.PDFColorSpace; import com.sun.pdfview.colorspace.PatternSpace; import com.sun.pdfview.decode.PDFDecoder; import com.sun.pdfview.font.PDFFont; import com.sun.pdfview.pattern.PDFShader; /** * PDFParser is the class that parses a PDF content stream and * produces PDFCmds for a PDFPage. You should never ever see it run: * it gets created by a PDFPage only if needed, and may even run in * its own thread. * * @author Mike Wessler */ public class PDFParser extends BaseWatchable { /** emit a file of DCT stream data. */ public final static String DEBUG_DCTDECODE_DATA = "debugdctdecode"; // ---- parsing variables private Stack stack; // stack of Object private Stack parserStates; // stack of RenderState // the current render state private ParserState state; private GeneralPath path; private int clip; private int loc; private boolean resend = false; private Tok tok; private boolean catchexceptions; // Indicates state of BX...EX /** a weak reference to the page we render into. For the page * to remain available, some other code must retain a strong reference to it. */ private WeakReference pageRef; /** the actual command, for use within a singe iteration. Note that * this must be released at the end of each iteration to assure the * page can be collected if not in use */ private PDFPage cmds; // ---- result variables byte[] stream; HashMap resources; public static int debuglevel = 4000; public static void debug(String msg, int level) { if (level > debuglevel) { System.out.println(escape(msg)); } } public static String escape(String msg) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < msg.length(); i++) { char c = msg.charAt(i); if (c != '\n' && (c < 32 || c >= 127)) { c = '?'; } sb.append(c); } return sb.toString(); } public static void setDebugLevel(int level) { debuglevel = level; } /** * Don't call this constructor directly. Instead, use * PDFFile.getPage(int pagenum) to get a PDFPage. There should * never be any reason for a user to create, access, or hold * on to a PDFParser. */ public PDFParser(PDFPage cmds, byte[] stream, HashMap resources) { super(); this.pageRef = new WeakReference(cmds); this.resources = resources; if (resources == null) { this.resources = new HashMap(); } this.stream = stream; } ///////////////////////////////////////////////////////////////// // B E G I N R E A D E R S E C T I O N ///////////////////////////////////////////////////////////////// /** * a token from a PDF Stream */ class Tok { /** begin bracket < */ public static final int BRKB = 11; /** end bracket > */ public static final int BRKE = 10; /** begin array [ */ public static final int ARYB = 9; /** end array ] */ public static final int ARYE = 8; /** String (, readString looks for trailing ) */ public static final int STR = 7; /** begin brace { */ public static final int BRCB = 5; /** end brace } */ public static final int BRCE = 4; /** number */ public static final int NUM = 3; /** keyword */ public static final int CMD = 2; /** name (begins with /) */ public static final int NAME = 1; /** unknown token */ public static final int UNK = 0; /** end of stream */ public static final int EOF = -1; /** the string value of a STR, NAME, or CMD token */ public String name; /** the value of a NUM token */ public double value; /** the type of the token */ public int type; /** a printable representation of the token */ @Override public String toString() { if (type == NUM) { return "NUM: " + value; } else if (type == CMD) { return "CMD: " + name; } else if (type == UNK) { return "UNK"; } else if (type == EOF) { return "EOF"; } else if (type == NAME) { return "NAME: " + name; } else if (type == CMD) { return "CMD: " + name; } else if (type == STR) { return "STR: (" + name; } else if (type == ARYB) { return "ARY ["; } else if (type == ARYE) { return "ARY ]"; } else { return "some kind of brace (" + type + ")"; } } } /** * put the current token back so that it is returned again by * nextToken(). */ private void throwback() { resend = true; } /** * get the next token. * TODO: this creates a new token each time. Is this strictly * necessary? */ private Tok nextToken() { if (resend) { resend = false; return tok; } tok = new Tok(); // skip whitespace while (loc < stream.length && PDFFile.isWhiteSpace(stream[loc])) { loc++; } if (loc >= stream.length) { tok.type = Tok.EOF; return tok; } int c = stream[loc++]; // examine the character: while (c == '%') { // skip comments StringBuffer comment = new StringBuffer(); while (loc < stream.length && c != '\n') { comment.append((char) c); c = stream[loc++]; } if (loc < stream.length) { c = stream[loc++]; // eat the newline if (c == '\r') { c = stream[loc++]; // eat a following return } } debug("Read comment: " + comment.toString(), -1); } if (c == '[') { tok.type = Tok.ARYB; } else if (c == ']') { tok.type = Tok.ARYE; } else if (c == '(') { // read a string tok.type = Tok.STR; tok.name = readString(); } else if (c == '{') { tok.type = Tok.BRCB; } else if (c == '}') { tok.type = Tok.BRCE; } else if (c == '<' && stream[loc++] == '<') { tok.type = Tok.BRKB; } else if (c == '>' && stream[loc++] == '>') { tok.type = Tok.BRKE; } else if (c == '<') { loc--; tok.type = Tok.STR; tok.name = readByteArray(); } else if (c == '/') { tok.type = Tok.NAME; tok.name = readName(); } else if (c == '.' || c == '-' || (c >= '0' && c <= '9')) { loc--; tok.type = Tok.NUM; tok.value = readNum(); } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '\'' || c == '"') { loc--; tok.type = Tok.CMD; tok.name = readName(); } else { System.out.println("Encountered character: " + c + " (" + (char) c + ")"); tok.type = Tok.UNK; } debug("Read token: " + tok, -1); return tok; } /** * read a name (sequence of non-PDF-delimiting characters) from the * stream. */ private String readName() { int start = loc; while (loc < stream.length && PDFFile.isRegularCharacter(stream[loc])) { loc++; } return new String(stream, start, loc - start); } /** * read a floating point number from the stream */ private double readNum() { int c = stream[loc++]; boolean neg = c == '-'; boolean sawdot = c == '.'; double dotmult = sawdot ? 0.1 : 1; double value = (c >= '0' && c <= '9') ? c - '0' : 0; while (true) { c = stream[loc++]; if (c == '.') { if (sawdot) { loc--; break; } sawdot = true; dotmult = 0.1; } else if (c >= '0' && c <= '9') { int val = c - '0'; if (sawdot) { value += val * dotmult; dotmult *= 0.1; } else { value = value * 10 + val; } } else { loc--; break; } } if (neg) { value = -value; } return value; } /** *

read a String from the stream. Strings begin with a '(' * character, which has already been read, and end with a balanced ')' * character. A '\' character starts an escape sequence of up * to three octal digits.

* *

Parenthesis must be enclosed by a balanced set of parenthesis, * so a string may enclose balanced parenthesis.

* * @return the string with escape sequences replaced with their * values */ private String readString() { int parenLevel = 0; StringBuffer sb = new StringBuffer(); while (loc < stream.length) { int c = stream[loc++]; if (c == ')') { if (parenLevel-- == 0) { break; } } else if (c == '(') { parenLevel++; } else if (c == '\\') { // escape sequences c = stream[loc++]; if (c >= '0' && c < '8') { int count = 0; int val = 0; while (c >= '0' && c < '8' && count < 3) { val = val * 8 + c - '0'; c = stream[loc++]; count++; } loc--; c = val; } else if (c == 'n') { c = '\n'; } else if (c == 'r') { c = '\r'; } else if (c == 't') { c = '\t'; } else if (c == 'b') { c = '\b'; } else if (c == 'f') { c = '\f'; } } sb.append((char) c); } return sb.toString(); } /** * read a byte array from the stream. Byte arrays begin with a '<' * character, which has already been read, and end with a '>' * character. Each byte in the array is made up of two hex characters, * the first being the high-order bit. * * We translate the byte arrays into char arrays by combining two bytes * into a character, and then translate the character array into a string. * [JK FIXME this is probably a really bad idea!] * * @return the byte array */ private String readByteArray() { StringBuffer buf = new StringBuffer(); int count = 0; char w = (char) 0; // read individual bytes and format into a character array while ((loc < stream.length) && (stream[loc] != '>')) { char c = (char) stream[loc]; byte b = (byte) 0; if (c >= '0' && c <= '9') { b = (byte) (c - '0'); } else if (c >= 'a' && c <= 'f') { b = (byte) (10 + (c - 'a')); } else if (c >= 'A' && c <= 'F') { b = (byte) (10 + (c - 'A')); } else { loc++; continue; } // calculate where in the current byte this character goes int offset = 1 - (count % 2); w |= (0xf & b) << (offset * 4); // increment to the next char if we've written four bytes if (offset == 0) { buf.append(w); w = (char) 0; } count++; loc++; } // ignore trailing '>' loc++; return buf.toString(); } ///////////////////////////////////////////////////////////////// // B E G I N P A R S E R S E C T I O N ///////////////////////////////////////////////////////////////// /** * Called to prepare for some iterations */ @Override public void setup() { stack = new Stack(); parserStates = new Stack(); state = new ParserState(); path = new GeneralPath(); loc = 0; clip = 0; //initialize the ParserState state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); state.textFormat = new PDFTextFormat(); // HexDump.printData(stream); // System.out.println(dumpStream()); } /** * parse the stream. commands are added to the PDFPage initialized * in the constructor as they are encountered. *

* Page numbers in comments refer to the Adobe PDF specification.
* commands are listed in PDF spec 32000-1:2008 in Table A.1 * * @return

  • Watchable.RUNNING when there are commands to be processed *
  • Watchable.COMPLETED when the page is done and all * the commands have been processed *
  • Watchable.STOPPED if the page we are rendering into is * no longer available *
*/ public int iterate() throws Exception { // make sure the page is still available, and create the reference // to it for use within this iteration cmds = (PDFPage) pageRef.get(); if (cmds == null) { System.out.println("Page gone. Stopping"); return Watchable.STOPPED; } Object obj = parseObject(); // if there's nothing left to parse, we're done if (obj == null) { return Watchable.COMPLETED; } if (obj instanceof Tok) { // it's a command. figure out what to do. // (if not, the token will be "pushed" onto the stack) String cmd = ((Tok) obj).name; debug("Command: " + cmd + " (stack size is " + stack.size() + ")", 0); if (cmd.equals("q")) { // push the parser state parserStates.push((ParserState) state.clone()); // push graphics state cmds.addPush(); } else if (cmd.equals("Q")) { processQCmd(); } else if (cmd.equals("cm")) { // set transform to array of values float[] elts = popFloat(6); AffineTransform xform = new AffineTransform(elts); cmds.addXform(xform); } else if (cmd.equals("w")) { // set stroke width cmds.addStrokeWidth(popFloat()); } else if (cmd.equals("J")) { // set end cap style cmds.addEndCap(popInt()); } else if (cmd.equals("j")) { // set line join style cmds.addLineJoin(popInt()); } else if (cmd.equals("M")) { // set miter limit cmds.addMiterLimit(popInt()); } else if (cmd.equals("d")) { // set dash style and phase float phase = popFloat(); float[] dashary = popFloatArray(); cmds.addDash(dashary, phase); } else if (cmd.equals("ri")) { // TODO: do something with rendering intent (page 197) } else if (cmd.equals("i")) { popFloat(); // TODO: do something with flatness tolerance } else if (cmd.equals("gs")) { // set graphics state to values in a named dictionary setGSState(popString()); } else if (cmd.equals("m")) { // path move to float y = popFloat(); float x = popFloat(); path.moveTo(x, y); } else if (cmd.equals("l")) { // path line to float y = popFloat(); float x = popFloat(); path.lineTo(x, y); } else if (cmd.equals("c")) { // path curve to float a[] = popFloat(6); path.curveTo(a[0], a[1], a[2], a[3], a[4], a[5]); } else if (cmd.equals("v")) { // path curve; first control point= start float a[] = popFloat(4); Point2D cp = path.getCurrentPoint(); path.curveTo((float) cp.getX(), (float) cp.getY(), a[0], a[1], a[2], a[3]); } else if (cmd.equals("y")) { // path curve; last control point= end float a[] = popFloat(4); path.curveTo(a[0], a[1], a[2], a[3], a[2], a[3]); } else if (cmd.equals("h")) { // path close path.closePath(); } else if (cmd.equals("re")) { // path add rectangle float a[] = popFloat(4); path.moveTo(a[0], a[1]); path.lineTo(a[0] + a[2], a[1]); path.lineTo(a[0] + a[2], a[1] + a[3]); path.lineTo(a[0], a[1] + a[3]); path.closePath(); } else if (cmd.equals("S")) { // stroke the path cmds.addPath(path, PDFShapeCmd.STROKE | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("s")) { // close and stroke the path path.closePath(); cmds.addPath(path, PDFShapeCmd.STROKE | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("f") || cmd.equals("F")) { // fill the path (close/not close identical) cmds.addPath(path, PDFShapeCmd.FILL | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("f*")) { // fill the path using even/odd rule path.setWindingRule(WIND_EVEN_ODD); cmds.addPath(path, PDFShapeCmd.FILL | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("B")) { // fill and stroke the path cmds.addPath(path, PDFShapeCmd.BOTH | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("B*")) { // fill path using even/odd rule and stroke it path.setWindingRule(WIND_EVEN_ODD); cmds.addPath(path, PDFShapeCmd.BOTH | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("b")) { // close the path, then fill and stroke it path.closePath(); cmds.addPath(path, PDFShapeCmd.BOTH | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("b*")) { // close path, fill using even/odd rule, then stroke it path.closePath(); path.setWindingRule(WIND_EVEN_ODD); cmds.addPath(path, PDFShapeCmd.BOTH | clip); clip = 0; path = new GeneralPath(); } else if (cmd.equals("n")) { // clip with the path and discard it if (clip != 0) { cmds.addPath(path, clip); } clip = 0; path = new GeneralPath(); } else if (cmd.equals("W")) { // mark this path for clipping! clip = PDFShapeCmd.CLIP; } else if (cmd.equals("W*")) { // mark this path using even/odd rule for clipping path.setWindingRule(WIND_EVEN_ODD); clip = PDFShapeCmd.CLIP; } else if (cmd.equals("sh")) { // shade a region that is defined by the shader itself. // shading the current space from a dictionary // should only be used for limited-dimension shadings String gdictname = popString(); // set up the pen to do a gradient fill according // to the dictionary PDFObject shobj = findResource(gdictname, "Shading"); doShader(shobj); } else if (cmd.equals("CS")) { // set the stroke color space state.strokeCS = parseColorSpace(new PDFObject(stack.pop())); } else if (cmd.equals("cs")) { // set the fill color space state.fillCS = parseColorSpace(new PDFObject(stack.pop())); } else if (cmd.equals("SC")) { // set the stroke color int n = state.strokeCS.getNumComponents(); cmds.addStrokePaint(state.strokeCS.getPaint(popFloat(n))); } else if (cmd.equals("SCN")) { if (state.strokeCS instanceof PatternSpace) { cmds.addFillPaint(doPattern((PatternSpace) state.strokeCS)); } else { int n = state.strokeCS.getNumComponents(); cmds.addStrokePaint(state.strokeCS.getPaint(popFloat(n))); } } else if (cmd.equals("sc")) { // set the fill color int n = state.fillCS.getNumComponents(); cmds.addFillPaint(state.fillCS.getPaint(popFloat(n))); } else if (cmd.equals("scn")) { if (state.fillCS instanceof PatternSpace) { cmds.addFillPaint(doPattern((PatternSpace) state.fillCS)); } else { int n = state.fillCS.getNumComponents(); cmds.addFillPaint(state.fillCS.getPaint(popFloat(n))); } } else if (cmd.equals("G")) { // set the stroke color to a Gray value state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); cmds.addStrokePaint(state.strokeCS.getPaint(popFloat(1))); } else if (cmd.equals("g")) { // set the fill color to a Gray value state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY); cmds.addFillPaint(state.fillCS.getPaint(popFloat(1))); } else if (cmd.equals("RG")) { // set the stroke color to an RGB value state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_RGB); cmds.addStrokePaint(state.strokeCS.getPaint(popFloat(3))); } else if (cmd.equals("rg")) { // set the fill color to an RGB value state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_RGB); cmds.addFillPaint(state.fillCS.getPaint(popFloat(3))); } else if (cmd.equals("K")) { // set the stroke color to a CMYK value state.strokeCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_CMYK); cmds.addStrokePaint(state.strokeCS.getPaint(popFloat(4))); } else if (cmd.equals("k")) { // set the fill color to a CMYK value state.fillCS = PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_CMYK); cmds.addFillPaint(state.fillCS.getPaint(popFloat(4))); } else if (cmd.equals("Do")) { // make a do call on the referenced object PDFObject xobj = findResource(popString(), "XObject"); doXObject(xobj); } else if (cmd.equals("BT")) { processBTCmd(); } else if (cmd.equals("ET")) { // end of text. noop state.textFormat.end(); } else if (cmd.equals("Tc")) { // set character spacing state.textFormat.setCharSpacing(popFloat()); } else if (cmd.equals("Tw")) { // set word spacing state.textFormat.setWordSpacing(popFloat()); } else if (cmd.equals("Tz")) { // set horizontal scaling state.textFormat.setHorizontalScale(popFloat()); } else if (cmd.equals("TL")) { // set leading state.textFormat.setLeading(popFloat()); } else if (cmd.equals("Tf")) { // set text font float sz = popFloat(); String fontref = popString(); state.textFormat.setFont(getFontFrom(fontref), sz); } else if (cmd.equals("Tr")) { // set text rendering mode state.textFormat.setMode(popInt()); } else if (cmd.equals("Ts")) { // set text rise state.textFormat.setRise(popFloat()); } else if (cmd.equals("Td")) { // set text matrix location float y = popFloat(); float x = popFloat(); state.textFormat.carriageReturn(x, y); } else if (cmd.equals("TD")) { // set leading and matrix: -y TL x y Td float y = popFloat(); float x = popFloat(); state.textFormat.setLeading(-y); state.textFormat.carriageReturn(x, y); } else if (cmd.equals("Tm")) { // set text matrix state.textFormat.setMatrix(popFloat(6)); } else if (cmd.equals("T*")) { // go to next line state.textFormat.carriageReturn(); } else if (cmd.equals("Tj")) { // show text state.textFormat.doText(cmds, popString()); } else if (cmd.equals("\'")) { // next line and show text: T* string Tj state.textFormat.carriageReturn(); state.textFormat.doText(cmds, popString()); } else if (cmd.equals("\"")) { // draw string on new line with char & word spacing: // aw Tw ac Tc string ' String string = popString(); float ac = popFloat(); float aw = popFloat(); state.textFormat.setWordSpacing(aw); state.textFormat.setCharSpacing(ac); state.textFormat.doText(cmds, string); } else if (cmd.equals("TJ")) { // show kerned string state.textFormat.doText(cmds, popArray()); } else if (cmd.equals("BI")) { // parse inline image parseInlineImage(); } else if (cmd.equals("BX")) { catchexceptions = true; // ignore errors } else if (cmd.equals("EX")) { catchexceptions = false; // stop ignoring errors } else if (cmd.equals("MP")) { // mark point (role= mark role name) popString(); } else if (cmd.equals("DP")) { // mark point with dictionary (role, ref) // ref is either inline dict or name in "Properties" rsrc Object ref = stack.pop(); popString(); } else if (cmd.equals("BMC")) { // begin marked content (role) popString(); } else if (cmd.equals("BDC")) { // begin marked content with dict (role, ref) // ref is either inline dict or name in "Properties" rsrc Object ref = stack.pop(); popString(); } else if (cmd.equals("EMC")) { // end marked content } else if (cmd.equals("d0")) { // character width in type3 fonts popFloat(2); } else if (cmd.equals("d1")) { // character width in type3 fonts popFloat(6); } else if (cmd.equals("QBT")) {// 'Q' & 'BT' mushed together! processQCmd(); processBTCmd(); } else { if (catchexceptions) { debug("**** WARNING: Unknown command: " + cmd + " **************************", 10); } else { throw new PDFParseException("Unknown command: " + cmd); } } if (stack.size() != 0) { debug("**** WARNING! Stack not zero! (cmd=" + cmd + ", size=" + stack.size() + ") *************************", 4); stack.setSize(0); } } else { stack.push(obj); } // release or reference to the page object, so that it can be // gc'd if it is no longer in use cmds = null; return Watchable.RUNNING; } /** * abstracted command processing for Q command. Used directly and as * part of processing of mushed QBT command. */ private void processQCmd() { // pop graphics state ('Q') cmds.addPop(); // pop the parser state state = (ParserState) parserStates.pop(); } /** * abstracted command processing for BT command. Used directly and as * part of processing of mushed QBT command. */ private void processBTCmd() { // begin text block: reset everything. state.textFormat.reset(); } /** * Cleanup when iteration is done */ @Override public void cleanup() { if (state != null && state.textFormat != null) { state.textFormat.flush(); } if (cmds != null) { cmds.finish(); } stack = null; parserStates = null; state = null; path = null; cmds = null; } boolean errorwritten = false; public void dumpStreamToError() { if (errorwritten) { return; } errorwritten = true; try { File oops = File.createTempFile("PDFError", ".err"); FileOutputStream fos = new FileOutputStream(oops); fos.write(stream); fos.close(); } catch (IOException ioe) { /* Do nothing */ } ; } public String dumpStream() { return escape(new String(stream).replace('\r', '\n')); } /** * take a byte array and write a temporary file with it's data. * This is intended to capture data for analysis, like after decoders. * * @param ary * @param name */ public static void emitDataFile (byte [] ary, String name) { FileOutputStream ostr; try { File file = File.createTempFile ("DateFile", name); ostr = new FileOutputStream (file); System.out.println ("Write: " + file.getPath ()); ostr.write (ary); ostr.close (); } catch (IOException ex) { // ignore } } ///////////////////////////////////////////////////////////////// // H E L P E R S ///////////////////////////////////////////////////////////////// /** * get a property from a named dictionary in the resources of this * content stream. * @param name the name of the property in the dictionary * @param inDict the name of the dictionary in the resources * @return the value of the property in the dictionary */ private PDFObject findResource(String name, String inDict) throws IOException { if (inDict != null) { PDFObject in = resources.get(inDict); if (in == null || in.getType() != PDFObject.DICTIONARY) { throw new PDFParseException("No dictionary called " + inDict + " found in the resources"); } return in.getDictRef(name); } else { return resources.get(name); } } /** * Insert a PDF object into the command stream. The object must * either be an Image or a Form, which is a set of PDF commands * in a stream. * @param obj the object to insert, an Image or a Form. */ private void doXObject(PDFObject obj) throws IOException { String type = obj.getDictRef("Subtype").getStringValue(); if (type == null) { type = obj.getDictRef ("S").getStringValue (); } if (type.equals("Image")) { doImage(obj); } else if (type.equals("Form")) { doForm(obj); } else { throw new PDFParseException("Unknown XObject subtype: " + type); } } /** * Parse image data into a Java BufferedImage and add the image * command to the page. * @param obj contains the image data, and a dictionary describing * the width, height and color space of the image. */ private void doImage(PDFObject obj) throws IOException { cmds.addImage(PDFImage.createImage(obj, resources)); } /** * Inject a stream of PDF commands onto the page. Optimized to cache * a parsed stream of commands, so that each Form object only needs * to be parsed once. * @param obj a stream containing the PDF commands, a transformation * matrix, bounding box, and resources. */ private void doForm(PDFObject obj) throws IOException { // check to see if we've already parsed this sucker PDFPage formCmds = (PDFPage) obj.getCache(); if (formCmds == null) { // rats. parse it. AffineTransform at; Rectangle2D bbox; PDFObject matrix = obj.getDictRef("Matrix"); if (matrix == null) { at = new AffineTransform(); } else { float elts[] = new float[6]; for (int i = 0; i < elts.length; i++) { elts[i] = ((PDFObject) matrix.getAt(i)).getFloatValue(); } at = new AffineTransform(elts); } PDFObject bobj = obj.getDictRef("BBox"); bbox = PDFFile.parseNormalisedRectangle(bobj); formCmds = new PDFPage(bbox, 0); formCmds.addXform(at); HashMap r = new HashMap(resources); PDFObject rsrc = obj.getDictRef("Resources"); if (rsrc != null) { r.putAll(rsrc.getDictionary()); } PDFParser form = new PDFParser(formCmds, obj.getStream(), r); form.go(true); obj.setCache(formCmds); } cmds.addPush(); cmds.addCommands(formCmds); cmds.addPop(); } /** * Set the values into a PatternSpace */ private PDFPaint doPattern(PatternSpace patternSpace) throws IOException { float[] components = null; String patternName = popString(); PDFObject pattern = findResource(patternName, "Pattern"); if (pattern == null) { throw new PDFParseException("Unknown pattern : " + patternName); } if (stack.size() > 0) { components = popFloat(stack.size()); } return patternSpace.getPaint(pattern, components, resources); } /** * Parse the next object out of the PDF stream. This could be a * Double, a String, a HashMap (dictionary), Object[] array, or * a Tok containing a PDF command. */ private Object parseObject() throws PDFParseException { Tok t = nextToken(); if (t.type == Tok.NUM) { return new Double(tok.value); } else if (t.type == Tok.STR) { return tok.name; } else if (t.type == Tok.NAME) { return tok.name; } else if (t.type == Tok.BRKB) { HashMap hm = new HashMap(); String name = null; Object obj; while ((obj = parseObject()) != null) { if (name == null) { name = (String) obj; } else { hm.put(name, new PDFObject(obj)); name = null; } } if (tok.type != Tok.BRKE) { throw new PDFParseException("Inline dict should have ended with '>>'"); } return hm; } else if (t.type == Tok.ARYB) { // build an array ArrayList ary = new ArrayList(); Object obj; while ((obj = parseObject()) != null) { ary.add(obj); } if (tok.type != Tok.ARYE) { throw new PDFParseException("Expected ']'"); } return ary.toArray(); } else if (t.type == Tok.CMD) { return t; } debug("**** WARNING! parseObject unknown token! (t.type=" + t.type + ") *************************", 4); return null; } /** * Parse an inline image. An inline image starts with BI (already * read, contains a dictionary until ID, and then image data until * EI. */ private void parseInlineImage() throws IOException { // build dictionary until ID, then read image until EI HashMap hm = new HashMap(); while (true) { Tok t = nextToken(); if (t.type == Tok.CMD && t.name.equals("ID")) { break; } // it should be a name; String name = t.name; debug("ParseInlineImage, token: " + name, 1000); if (name.equals("BPC")) { name = "BitsPerComponent"; } else if (name.equals("CS")) { name = "ColorSpace"; } else if (name.equals("D")) { name = "Decode"; } else if (name.equals("DP")) { name = "DecodeParms"; } else if (name.equals("F")) { name = "Filter"; } else if (name.equals("H")) { name = "Height"; } else if (name.equals("IM")) { name = "ImageMask"; } else if (name.equals("W")) { name = "Width"; } else if (name.equals("I")) { name = "Interpolate"; } Object vobj = parseObject(); hm.put(name, new PDFObject(vobj)); } if (stream[loc] == '\r') { loc++; } if (stream[loc] == '\n' || stream[loc] == ' ') { loc++; } PDFObject imObj = (PDFObject) hm.get("ImageMask"); if (imObj != null && imObj.getBooleanValue()) { // [PATCHED by michal.busta@gmail.com] - default value according to PDF spec. is [0, 1] // there is no need to swap array - PDF image should handle this values Double[] decode = {new Double(0), new Double(1)}; PDFObject decodeObj = (PDFObject) hm.get("Decode"); if (decodeObj != null) { decode[0] = new Double(decodeObj.getAt(0).getDoubleValue()); decode[1] = new Double(decodeObj.getAt(1).getDoubleValue()); } hm.put("Decode", new PDFObject(decode)); } PDFObject obj = new PDFObject(null, PDFObject.DICTIONARY, hm); int dstart = loc; // now skip data until a whitespace followed by EI while (!PDFFile.isWhiteSpace(stream[loc]) || stream[loc + 1] != 'E' || stream[loc + 2] != 'I') { loc++; } // data runs from dstart to loc byte[] data = new byte[loc - dstart]; System.arraycopy(stream, dstart, data, 0, loc - dstart); obj.setStream(ByteBuffer.wrap(data)); loc += 3; doImage(obj); } /** * build a shader from a dictionary. */ private void doShader(PDFObject shaderObj) throws IOException { PDFShader shader = PDFShader.getShader(shaderObj, resources); cmds.addPush(); Rectangle2D bbox = shader.getBBox(); if (bbox != null) { cmds.addFillPaint(shader.getPaint()); cmds.addPath(new GeneralPath(bbox), PDFShapeCmd.FILL); } cmds.addPop(); } /** * get a PDFFont from the resources, given the resource name of the * font. * * @param fontref the resource key for the font */ private PDFFont getFontFrom(String fontref) throws IOException { PDFObject obj = findResource(fontref, "Font"); return PDFFont.getFont(obj, resources); } /** * add graphics state commands contained within a dictionary. * @param name the resource name of the graphics state dictionary */ private void setGSState(String name) throws IOException { // obj must be a string that is a key to the "ExtGState" dict PDFObject gsobj = findResource(name, "ExtGState"); // get LW, LC, LJ, Font, SM, CA, ML, D, RI, FL, BM, ca // out of the reference, which is a dictionary PDFObject d; if ((d = gsobj.getDictRef("LW")) != null) { cmds.addStrokeWidth(d.getFloatValue()); } if ((d = gsobj.getDictRef("LC")) != null) { cmds.addEndCap(d.getIntValue()); } if ((d = gsobj.getDictRef("LJ")) != null) { cmds.addLineJoin(d.getIntValue()); } if ((d = gsobj.getDictRef("Font")) != null) { state.textFormat.setFont(getFontFrom(d.getAt(0).getStringValue()), d.getAt(1).getFloatValue()); } if ((d = gsobj.getDictRef("ML")) != null) { cmds.addMiterLimit(d.getFloatValue()); } if ((d = gsobj.getDictRef("D")) != null) { PDFObject pdash[] = d.getAt(0).getArray(); float dash[] = new float[pdash.length]; for (int i = 0; i < pdash.length; i++) { dash[i] = pdash[i].getFloatValue(); } cmds.addDash(dash, d.getAt(1).getFloatValue()); } if ((d = gsobj.getDictRef("CA")) != null) { cmds.addStrokeAlpha(d.getFloatValue()); } if ((d = gsobj.getDictRef("ca")) != null) { cmds.addFillAlpha(d.getFloatValue()); } // others: BM=blend mode } /** * generate a PDFColorSpace description based on a PDFObject. The * object could be a standard name, or the name of a resource in * the ColorSpace dictionary, or a color space name with a defining * dictionary or stream. */ private PDFColorSpace parseColorSpace(PDFObject csobj) throws IOException { if (csobj == null) { return state.fillCS; } return PDFColorSpace.getColorSpace(csobj, resources); } /** * pop a single float value off the stack. * @return the float value of the top of the stack * @throws PDFParseException if the value on the top of the stack * isn't a number */ private float popFloat() throws PDFParseException { Object obj = stack.pop(); if (obj instanceof Double) { return ((Double) obj).floatValue(); } else { throw new PDFParseException("Expected a number here."); } } /** * pop an array of float values off the stack. This is equivalent * to filling an array from end to front by popping values off the * stack. * @param count the number of numbers to pop off the stack * @return an array of length count * @throws PDFParseException if any of the values popped off the * stack are not numbers. */ private float[] popFloat(int count) throws PDFParseException { float[] ary = new float[count]; for (int i = count - 1; i >= 0; i--) { ary[i] = popFloat(); } return ary; } /** * pop a single integer value off the stack. * @return the integer value of the top of the stack * @throws PDFParseException if the top of the stack isn't a number. */ private int popInt() throws PDFParseException { Object obj = stack.pop(); if (obj instanceof Double) { return ((Double) obj).intValue(); } else { throw new PDFParseException("Expected a number here."); } } /** * pop an array of integer values off the stack. This is equivalent * to filling an array from end to front by popping values off the * stack. * @param count the number of numbers to pop off the stack * @return an array of length count * @throws PDFParseException if any of the values popped off the * stack are not numbers. */ private float[] popFloatArray() throws PDFParseException { Object obj = stack.pop(); if (!(obj instanceof Object[])) { throw new PDFParseException("Expected an [array] here."); } Object[] source = (Object[]) obj; float[] ary = new float[source.length]; for (int i = 0; i < ary.length; i++) { if (source[i] instanceof Double) { ary[i] = ((Double) source[i]).floatValue(); } else { throw new PDFParseException("This array doesn't consist only of floats."); } } return ary; } /** * pop a String off the stack. * @return the String from the top of the stack * @throws PDFParseException if the top of the stack is not a NAME * or STR. */ private String popString() throws PDFParseException { Object obj = stack.pop(); if (!(obj instanceof String)) { throw new PDFParseException("Expected string here: " + obj.toString()); } else { return (String) obj; } } /** * pop a PDFObject off the stack. * @return the PDFObject from the top of the stack * @throws PDFParseException if the top of the stack does not contain * a PDFObject. */ private PDFObject popObject() throws PDFParseException { Object obj = stack.pop(); if (!(obj instanceof PDFObject)) { throw new PDFParseException("Expected a reference here: " + obj.toString()); } return (PDFObject) obj; } /** * pop an array off the stack * @return the array of objects that is the top element of the stack * @throws PDFParseException if the top element of the stack does not * contain an array. */ private Object[] popArray() throws PDFParseException { Object obj = stack.pop(); if (!(obj instanceof Object[])) { throw new PDFParseException("Expected an [array] here: " + obj.toString()); } return (Object[]) obj; } /** * A class to store state needed whiel rendering. This includes the * stroke and fill color spaces, as well as the text formatting * parameters. */ class ParserState implements Cloneable { /** the fill color space */ PDFColorSpace fillCS; /** the stroke color space */ PDFColorSpace strokeCS; /** the text paramters */ PDFTextFormat textFormat; /** * Clone the render state. */ @Override public Object clone() { ParserState newState = new ParserState(); // no need to clone color spaces, since they are immutable newState.fillCS = fillCS; newState.strokeCS = strokeCS; // we do need to clone the textFormat newState.textFormat = (PDFTextFormat) textFormat.clone(); return newState; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFStringUtil.java0000644000175000017500000002556511156177553023125 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.*; import java.util.Map; import java.util.HashMap; import java.nio.CharBuffer; import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; /** *

Utility methods for dealing with PDF Strings, such as: *

    *
  • {@link #asTextString(String) converting to text strings} *
  • {@link #asPDFDocEncoded(String) converting to PDFDocEncoded strings} *
  • {@link #asUTF16BEEncoded converting to UTF-16BE strings} *
  • converting basic strings between {@link #asBytes(String) byte} and * {@link #asBasicString(byte[], int, int) string} representations *

* *

We refer to basic strings as those corresponding to the PDF 'string' type. * PDFRenderer represents these as {@link String}s, though this is somewhat * deceiving, as they are, effectively, just sequences of bytes, although byte * values <= 127 do correspond to the ASCII character set. Outside of this, * the 'string' type, as repesented by basic strings do not possess any * character set or encoding, and byte values >= 128 are entirely acceptable. * For a basic string as represented by a String, each character has a value * less than 256 and is represented in the String as if the bytes represented as * it were in ISO-8859-1 encoding. This, however, is merely for convenience. For * strings that are user visible, and that don't merely represent some * identifying token, the PDF standard employs a 'text string' type that offers * the basic string as an encoding of in either UTF-16BE (with a byte order * marking) or a specific 8-byte encoding, PDFDocEncoding. Using a basic string * without conversion when the actual type is a 'text string' is erroneous * (though without consequence if the string consists only of ASCII * alphanumeric values). Care must be taken to either convert basic strings to * text strings (also expressed as a String) when appropriate, using either the * methods in this class, or {@link PDFObject#getTextStringValue()}}. For * strings that are 'byte strings', {@link #asBytes(String)} or {@link * PDFObject#getStream()} should be used.

. * * @author Luke Kirby */ public class PDFStringUtil { /** *

Take a basic PDF string and determine if it is in UTF-16BE encoding * by looking at the lead characters for a byte order marking (BOM). If it * appears to be UTF-16BE, we return the string representation of the * UTF-16BE encoding of those bytes. If the BOM is not present, the bytes * from the input string are decoded using the PDFDocEncoding charset.

* *

From the PDF Reference 1.7, p158: * *

The text string type is used for character strings that are * encoded in either PDFDocEncoding or the UTF-16BE Unicode character * encoding scheme. PDFDocEncoding can encode all of the ISO Latin 1 * character set and is documented in Appendix D. UTF-16BE can encode all * Unicode characters. UTF-16BE and Unicode character encoding are * described in the Unicode Standard by the Unicode Consortium (see the * Bibliography). Note that PDFDocEncoding does not support all Unicode * characters whereas UTF-16BE does.
*

* * @param basicString the basic PDF string, as offered by {@link * PDFObject#getStringValue()} * @return either the original input, or the input decoded as UTF-16 */ public static String asTextString(String basicString) { if (basicString == null) { return null; } if (basicString.length() >= 2) { if ((basicString.charAt(0) == (char) 0xFE && basicString.charAt(1) == (char) 0xFF)) { // found the BOM! return asUTF16BEEncoded(basicString); } } // it's not UTF16-BE encoded, so it must be return asPDFDocEncoded(basicString); } /** * Take a basic PDF string and produce a string of its bytes as encoded in * PDFDocEncoding. The PDFDocEncoding is described in the PDF Reference. * * @param basicString the basic PDF string, as offered by {@link * PDFObject#getStringValue()} * @return the decoding of the string's bytes in PDFDocEncoding */ public static String asPDFDocEncoded(String basicString) { final StringBuilder buf = new StringBuilder(basicString.length()); for (int i = 0; i < basicString.length(); ++i) { final char c = PDF_DOC_ENCODING_MAP[basicString.charAt(i) & 0xFF]; buf.append(c); } return buf.toString(); } public byte[] toPDFDocEncoded(String string) throws CharacterCodingException { // we can just grab array since we know that if charset completes // without error then there's the output buffer will be exactly // correct in size, since there's only ever 1 byte for one char. return new PDFDocCharsetEncoder().encode(CharBuffer.wrap(string)). array(); } /** * Take a basic PDF string and produce a string from its bytes as an * UTF16-BE encoding. The first 2 bytes are presumed to be the big-endian * byte markers, 0xFE and 0xFF; that is not checked by this method. * * @param basicString the basic PDF string, as offered by {@link * PDFObject#getStringValue()} * @return the decoding of the string's bytes in UTF16-BE */ public static String asUTF16BEEncoded(String basicString) { try { return new String(asBytes(basicString), 2, basicString.length() - 2, "UTF-16BE"); } catch (UnsupportedEncodingException e) { // UTF-16BE should always be available throw new RuntimeException("No UTF-16BE charset!"); } } /** * Get the corresponding byte array for a basic string. This is effectively * the char[] array cast to bytes[], as chars in basic strings only use the * least significant byte. * * @param basicString the basic PDF string, as offered by {@link * PDFObject#getStringValue()} * @return the bytes corresponding to its characters */ public static byte[] asBytes(String basicString) { final byte[] b = new byte[basicString.length()]; for (int i = 0; i < b.length; ++i) { b[i] = (byte) basicString.charAt(i); } return b; } /** * Create a basic string from bytes. This is effectively the byte array * cast to a char array and turned into a String. * @param bytes the source of the bytes for the basic string * @param offset the offset into butes where the string starts * @param length the number of bytes to turn into a string * @return the corresponding string */ public static String asBasicString( byte[] bytes, int offset, int length) { final char[] c = new char[length]; for (int i = 0; i < c.length; ++i) { c[i] = (char) bytes[i + offset]; } return new String(c); } /** * Create a basic string from bytes. This is effectively the byte array * cast to a char array and turned into a String. * @param bytes the bytes, all of which are used * @return the corresponding string */ public static String asBasicString(byte[] bytes) { return asBasicString(bytes, 0, bytes.length); } /** * Maps from PDFDocEncoding bytes to unicode characters. Table generated * by PDFDocEncodingMapGenerator. */ final static char[] PDF_DOC_ENCODING_MAP = new char[] { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, //00-07 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, //08-0F 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, //10-17 0x02D8, 0x02C7, 0x02C6, 0x02D9, 0x02DD, 0x02DB, 0x02DA, 0x02DC, //18-1F 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, //20-27 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, //28-2F 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, //30-37 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, //38-3F 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, //40-47 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, //48-4F 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, //50-57 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, //58-5F 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, //60-67 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, //68-6F 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, //70-77 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0xFFFD, //78-7F 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, //80-87 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, //88-8F 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x0141, 0x0152, 0x0160, //90-97 0x0178, 0x017D, 0x0131, 0x0142, 0x0153, 0x0161, 0x017E, 0xFFFD, //98-9F 0x20AC, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, //A0-A7 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0xFFFD, 0x00AE, 0x00AF, //A8-AF 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, //B0-B7 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, //B8-BF 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, //C0-C7 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, //C8-CF 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, //D0-D7 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, //D8-DF 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, //E0-E7 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, //E8-EF 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, //F0-F7 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, //F8-FF }; } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/0000755000175000017500000000000011622545441021023 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/decode/CCITTCodes0000644000175000017500000000751410732532577022610 0ustar twernertwerner # $Id: CCITTCodes,v 1.2 2007-12-20 18:33:33 rbair Exp $ # # Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, # Santa Clara, California 95054, U.S.A. All rights reserved. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # WHITE CODES 00110101 0 000111 1 0111 2 1000 3 1011 4 1100 5 1110 6 1111 7 10011 8 10100 9 00111 10 01000 11 001000 12 000011 13 110100 14 110101 15 101010 16 101011 17 0100111 18 0001100 19 0001000 20 0010111 21 0000011 22 0000100 23 0101000 24 0101011 25 0010011 26 0100100 27 0011000 28 00000010 29 00000011 30 00011010 31 00011011 32 00010010 33 00010011 34 00010100 35 00010101 36 00010110 37 00010111 38 00101000 39 00101001 40 00101010 41 00101011 42 00101100 43 00101101 44 00000100 45 00000101 46 00001010 47 00001011 48 01010010 49 01010011 50 01010100 51 01010101 52 00100100 53 00100101 54 01011000 55 01011001 56 01011010 57 01011011 58 01001010 59 01001011 60 00110010 61 00110011 62 00110100 63 11011 64 10010 128 010111 192 0110111 256 00110110 320 00110111 384 01100100 448 01100101 512 01101000 576 01100111 640 011001100 704 011001101 768 011010010 832 011010011 896 011010100 960 011010101 1024 011010110 1088 011010111 1152 011011000 1216 011011001 1280 011011010 1344 011011011 1408 010011000 1472 010011001 1536 010011010 1600 011000 1664 010011011 1728 00000001000 1792 00000001100 1856 00000001101 1920 000000010010 1984 000000010011 2048 000000010100 2112 000000010101 2176 000000010110 2240 000000010111 2304 000000011100 2368 000000011101 2432 000000011110 2496 000000011111 2560 000000001111 -2 0000000000 -1 # BLACK CODES 0000110111 0 010 1 11 2 10 3 011 4 0011 5 0010 6 00011 7 000101 8 000100 9 0000100 10 0000101 11 0000111 12 00000100 13 00000111 14 000011000 15 0000010111 16 0000011000 17 0000001000 18 00001100111 19 00001101000 20 00001101100 21 00000110111 22 00000101000 23 00000010111 24 00000011000 25 000011001010 26 000011001011 27 000011001100 28 000011001101 29 000001101000 30 000001101001 31 000001101010 32 000001101011 33 000011010010 34 000011010011 35 000011010100 36 000011010101 37 000011010110 38 000011010111 39 000001101100 40 000001101101 41 000011011010 42 000011011011 43 000001010100 44 000001010101 45 000001010110 46 000001010111 47 000001100100 48 000001100101 49 000001010010 50 000001010011 51 000000100100 52 000000110111 53 000000111000 54 000000100111 55 000000101000 56 000001011000 57 000001011001 58 000000101011 59 000000101100 60 000001011010 61 000001100110 62 000001100111 63 0000001111 64 000011001000 128 000011001001 192 000001011011 256 000000110011 320 000000110100 384 000000110101 448 0000001101100 512 0000001101101 576 0000001001010 640 0000001001011 704 0000001001100 768 0000001001101 832 0000001110010 896 0000001110011 960 0000001110100 1024 0000001110101 1088 0000001110110 1152 0000001110111 1216 0000001010010 1280 0000001010011 1344 0000001010100 1408 0000001010101 1472 0000001011010 1536 0000001011011 1600 0000001100100 1664 0000001100101 1728 00000001000 1792 00000001100 1856 00000001101 1920 000000010010 1984 000000010011 2048 000000010100 2112 000000010101 2176 000000010110 2240 000000010111 2304 000000011100 2368 000000011101 2432 000000011110 2496 000000011111 2560 000000001111 -2 00000000000 -1 pdfrenderer-0.9.0/src/com/sun/pdfview/decode/TIFFPredictor.java0000644000175000017500000001131611376323412024272 0ustar twernertwerner/* * $Id: TIFFPredictor.java,v 1.1 2010-05-23 22:07:04 lujke Exp $ * * Copyright 2010 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.IOException; import java.nio.ByteBuffer; /** * Undo prediction based on the TIFF Predictor 2 algorithm */ public class TIFFPredictor extends Predictor { public TIFFPredictor() { super (TIFF); } /** * Undo data based on the png algorithm */ public ByteBuffer unpredict(ByteBuffer imageData) throws IOException { ByteBuffer out = ByteBuffer.allocate(imageData.limit()); final int numComponents = getColors(); final int pixelBits = numComponents * getBitsPerComponent(); int bytePerRow = (getColumns() * pixelBits + 7) / 8; final byte[] row = new byte[bytePerRow]; while(imageData.remaining() > 0) { imageData.get(row); if (getBitsPerComponent() == 8) { for (int i = numComponents; i < row.length; i += numComponents) { for (int c = 0; c < numComponents; ++c) { final int pos = i + c; row[pos] += row[pos - numComponents]; } } } else if (getBitsPerComponent() == 16) { final short[] prev = new short[numComponents]; for (int c = 0; c < numComponents; c += 1) { final int pos = c * 2; prev[c] = (short) ((row[pos] << 8 | (row[pos + 1]) & 0xFFFF)); } for (int i = numComponents * 2; i < row.length; i += numComponents * 2) { for (int c = 0; c < numComponents; c += 1) { final int pos = i + c * 2; short cur = (short) ((row[pos] << 8 | (row[pos + 1]) & 0xFFFF)); cur += prev[c]; row[pos] = (byte) (cur >>> 8 & 0xFF); row[pos + 1] = (byte) (cur & 0xFF); prev[c] = cur; } } } else { assert getBitsPerComponent() == 1 || getBitsPerComponent() == 2 || getBitsPerComponent() == 4 : "we don't want to grab components across pixel boundaries"; int bitsOnRow = pixelBits * getColumns(); // may be less than bytesOnRow * 8 byte prev[] = new byte[numComponents]; final int shiftWhenAligned = 8 - getBitsPerComponent(); final int mask = (1 << getBitsPerComponent()) - 1; for (int c = 0; c < numComponents; ++c) { prev[c] = getbits(row, c * getBitsPerComponent(), shiftWhenAligned, mask); } for (int i = pixelBits; i < bitsOnRow; i += pixelBits) { for (int c = 0; c < numComponents; ++c) { byte cur = getbits(row, i + c * getBitsPerComponent(), shiftWhenAligned, mask); cur += prev[c]; prev[c] = cur; setbits(row, i + c * getBitsPerComponent(), shiftWhenAligned, mask, cur); } } } out.put(row); } // reset start pointer out.flip(); // return return out; } private static byte getbits(byte[] data, int bitIndex, int shiftWhenByteAligned, int mask) { final int b = data[(bitIndex >> 3)]; final int bitIndexInB = bitIndex & 7; final int shift = shiftWhenByteAligned - bitIndexInB; return (byte) ((b >>> shift) & mask); } private static void setbits(byte[] data, int bitIndex, int shiftWhenByteAligned, int mask, byte bits) { final int b = data[(bitIndex >> 3)]; final int bitIndexInB = bitIndex & 7; final int shift = shiftWhenByteAligned - bitIndexInB; data[bitIndex >> 3] = (byte) ((b & ~(mask << shift)) | (bits << shift)); } }pdfrenderer-0.9.0/src/com/sun/pdfview/decode/CCITTFaxDecode.java0000644000175000017500000000464611145104376024307 0ustar twernertwernerpackage com.sun.pdfview.decode; import java.io.IOException; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; public class CCITTFaxDecode { protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws IOException { byte[] bytes = new byte[buf.remaining()]; buf.get(bytes, 0, bytes.length); return ByteBuffer.wrap(decode(dict, bytes)); } protected static byte[] decode(PDFObject dict, byte[] source) throws IOException { int width = 1728; PDFObject widthDef = dict.getDictRef("Width"); if (widthDef == null) { widthDef = dict.getDictRef("W"); } if (widthDef != null) { width = widthDef.getIntValue(); } int height = 0; PDFObject heightDef = dict.getDictRef("Height"); if (heightDef == null) { heightDef = dict.getDictRef("H"); } if (heightDef != null) { height = heightDef.getIntValue(); } // int columns = getOptionFieldInt(dict, "Columns", width); int rows = getOptionFieldInt(dict, "Rows", height); int k = getOptionFieldInt(dict, "K", 0); int size = rows * ((columns + 7) >> 3); byte[] destination = new byte[size]; boolean align = getOptionFieldBoolean(dict, "EncodedByteAlign", false); CCITTFaxDecoder decoder = new CCITTFaxDecoder(1, columns, rows); decoder.setAlign(align); if (k == 0) { decoder.decodeT41D(destination, source, 0, rows); } else if (k > 0) { decoder.decodeT42D(destination, source, 0, rows); } else if (k < 0) { decoder.decodeT6(destination, source, 0, rows); } if (!getOptionFieldBoolean(dict, "BlackIs1", false)) { for (int i = 0; i < destination.length; i++) { // bitwise not destination[i] = (byte) ~destination[i]; } } return destination; } public static int getOptionFieldInt(PDFObject dict, String name, int defaultValue) throws IOException { PDFObject dictParams = dict.getDictRef("DecodeParms"); if (dictParams == null) { return defaultValue; } PDFObject value = dictParams.getDictRef(name); if (value == null) { return defaultValue; } return value.getIntValue(); } public static boolean getOptionFieldBoolean(PDFObject dict, String name, boolean defaultValue) throws IOException { PDFObject dictParams = dict.getDictRef("DecodeParms"); if (dictParams == null) { return defaultValue; } PDFObject value = dictParams.getDictRef(name); if (value == null) { return defaultValue; } return value.getBooleanValue(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/PDFDecoder.java0000644000175000017500000002045511526563523023577 0ustar twernertwerner/* * $Id: PDFDecoder.java,v 1.6 2010-06-14 17:32:08 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.decrypt.PDFDecrypterFactory; /** * A PDF Decoder encapsulates all the methods of decoding a stream of bytes * based on all the various encoding methods. *

* You should use the decodeStream() method of this object rather than using * any of the decoders directly. */ public class PDFDecoder { private static final String FILTER_DCT = "DCT"; private static final String FILTER_DCTDECODE = "DCTDecode"; public final static Set DCT_FILTERS = new HashSet(Arrays.asList(FILTER_DCT, FILTER_DCTDECODE)); /** Creates a new instance of PDFDecoder */ private PDFDecoder() { } public static boolean isLastFilter(PDFObject dict, Set filters) throws IOException { PDFObject filter = dict.getDictRef("Filter"); if (filter == null) { return false; } else if (filter.getType() == PDFObject.NAME) { return filters.contains(filter.getStringValue()); } else { final PDFObject[] ary = filter.getArray(); return filters.contains(ary[ary.length - 1].getStringValue()); } } /** * Utility class for reading and storing the specification of * Filters on a stream */ private static class FilterSpec { PDFObject ary[]; PDFObject params[]; private FilterSpec(PDFObject dict, PDFObject filter) throws IOException { if (filter.getType() == PDFObject.NAME) { ary = new PDFObject[1]; ary[0] = filter; params = new PDFObject[1]; params[0] = dict.getDictRef("DecodeParms"); } else { ary = filter.getArray(); PDFObject parmsobj = dict.getDictRef("DecodeParms"); if (parmsobj != null) { params = parmsobj.getArray(); } else { params = new PDFObject[ary.length]; } } } } /** * decode a byte[] stream using the filters specified in the object's * dictionary (passed as argument 1). * @param dict the dictionary associated with the stream * @param streamBuf the data in the stream, as a byte buffer */ public static ByteBuffer decodeStream(PDFObject dict, ByteBuffer streamBuf, Set filterLimits) throws IOException { PDFObject filter = dict.getDictRef("Filter"); if (filter == null) { // just apply default decryption return dict.getDecrypter().decryptBuffer(null, dict, streamBuf); } else { // apply filters FilterSpec spec = new FilterSpec(dict, filter); // determine whether default encryption applies or if there's a // specific Crypt filter; it must be the first filter according to // the errata for PDF1.7 boolean specificCryptFilter = spec.ary.length != 0 && spec.ary[0].getStringValue().equals("Crypt"); if (!specificCryptFilter) { // No Crypt filter, so should apply default decryption (if // present!) streamBuf = dict.getDecrypter().decryptBuffer( null, dict, streamBuf); } for (int i = 0; i < spec.ary.length; i++) { String enctype = spec.ary[i].getStringValue(); if (filterLimits.contains(enctype)) { break; } if (enctype == null) { } else if (enctype.equals("FlateDecode") || enctype.equals("Fl")) { streamBuf = FlateDecode.decode(dict, streamBuf, spec.params[i]); } else if (enctype.equals("LZWDecode") || enctype.equals("LZW")) { streamBuf = LZWDecode.decode(streamBuf, spec.params[i]); } else if (enctype.equals("ASCII85Decode") || enctype.equals("A85")) { streamBuf = ASCII85Decode.decode(streamBuf, spec.params[i]); } else if (enctype.equals("ASCIIHexDecode") || enctype.equals("AHx")) { streamBuf = ASCIIHexDecode.decode(streamBuf, spec.params[i]); } else if (enctype.equals("RunLengthDecode") || enctype.equals("RL")) { streamBuf = RunLengthDecode.decode(streamBuf, spec.params[i]); } else if (enctype.equals(FILTER_DCTDECODE) || enctype.equals(FILTER_DCT)) { streamBuf = DCTDecode.decode(dict, streamBuf, spec.params[i]); } else if (enctype.equals("CCITTFaxDecode") || enctype.equals("CCF")) { streamBuf = CCITTFaxDecode.decode(dict, streamBuf, spec.params[i]); } else if (enctype.equals("Crypt")) { String cfName = getCryptFilterName(spec.params[i]); streamBuf = dict.getDecrypter().decryptBuffer(cfName, null, streamBuf); } else { throw new PDFParseException("Unknown coding method:" + spec.ary[i].getStringValue()); } } } return streamBuf; } /** * The name of the Crypt filter to apply * @param param the parameters to the Crypt filter * @return the name of the crypt filter to apply * @throws IOException if there's a problem reading the objects */ private static String getCryptFilterName(PDFObject param) throws IOException { String cfName = PDFDecrypterFactory.CF_IDENTITY; if (param != null) { final PDFObject nameObj = param.getDictRef("Name"); if (nameObj != null && nameObj.getType() == PDFObject.NAME) { cfName = nameObj.getStringValue(); } } return cfName; } /** * Determines whether a stream is encrypted or not; note that encodings * (e.g., Flate, LZW) are not considered encryptions. * @param dict the stream dictionary * @return whether the stream is encrypted * @throws IOException if the stream dictionary can't be read */ public static boolean isEncrypted(PDFObject dict) throws IOException { PDFObject filter = dict.getDictRef("Filter"); if (filter == null) { // just apply default decryption return dict.getDecrypter().isEncryptionPresent(); } else { // apply filters FilterSpec spec = new FilterSpec(dict, filter); // determine whether default encryption applies or if there's a // specific Crypt filter; it must be the first filter according to // the errata for PDF1.7 boolean specificCryptFilter = spec.ary.length != 0 && spec.ary[0].getStringValue().equals("Crypt"); if (!specificCryptFilter) { // No Crypt filter, so we just need to refer to // the default decrypter return dict.getDecrypter().isEncryptionPresent(); } else { String cfName = getCryptFilterName(spec.params[0]); // see whether the specified crypt filter really decrypts return dict.getDecrypter().isEncryptionPresent(cfName); } } } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/ASCII85Decode.java0000644000175000017500000001113211150120723023761 0ustar twernertwerner/* * $Id: ASCII85Decode.java,v 1.3 2009-02-22 00:52:35 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * decode ASCII85 text into a byte array. * * @author Mike Wessler */ public class ASCII85Decode { private ByteBuffer buf; /** * initialize the decoder with byte buffer in ASCII85 format */ private ASCII85Decode(ByteBuffer buf) { this.buf = buf; } /** * get the next character from the input. * @return the next character, or -1 if at end of stream */ private int nextChar() { // skip whitespace // returns next character, or -1 if end of stream while (buf.remaining() > 0) { char c = (char) buf.get(); if (!PDFFile.isWhiteSpace(c)) { return c; } } // EOF reached return -1; } /** * decode the next five ASCII85 characters into up to four decoded * bytes. Return false when finished, or true otherwise. * * @param baos the ByteArrayOutputStream to write output to, set to the * correct position * @return false when finished, or true otherwise. */ private boolean decode5(ByteArrayOutputStream baos) throws PDFParseException { // stream ends in ~> int[] five = new int[5]; int i; for (i = 0; i < 5; i++) { five[i] = nextChar(); if (five[i] == '~') { if (nextChar() == '>') { break; } else { throw new PDFParseException("Bad character in ASCII85Decode: not ~>"); } } else if (five[i] >= '!' && five[i] <= 'u') { five[i] -= '!'; } else if (five[i] == 'z') { if (i == 0) { five[i] = 0; i = 4; } else { throw new PDFParseException("Inappropriate 'z' in ASCII85Decode"); } } else { throw new PDFParseException("Bad character in ASCII85Decode: " + five[i] + " (" + (char) five[i] + ")"); } } if (i > 0) { i -= 1; } int value = five[0] * 85 * 85 * 85 * 85 + five[1] * 85 * 85 * 85 + five[2] * 85 * 85 + five[3] * 85 + five[4]; for (int j = 0; j < i; j++) { int shift = 8 * (3 - j); baos.write((byte) ((value >> shift) & 0xff)); } return (i == 4); } /** * decode the bytes * @return the decoded bytes */ private ByteBuffer decode() throws PDFParseException { // start from the beginning of the data buf.rewind(); // allocate the output buffer ByteArrayOutputStream baos = new ByteArrayOutputStream(); // decode the bytes while (decode5(baos)) { } return ByteBuffer.wrap(baos.toByteArray()); } /** * decode an array of bytes in ASCII85 format. *

* In ASCII85 format, every 5 characters represents 4 decoded * bytes in base 85. The entire stream can contain whitespace, * and ends in the characters '~>'. * * @param buf the encoded ASCII85 characters in a byte buffer * @param params parameters to the decoder (ignored) * @return the decoded bytes */ public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws PDFParseException { ASCII85Decode me = new ASCII85Decode(buf); return me.decode(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/ASCIIHexDecode.java0000644000175000017500000000760310732532577024304 0ustar twernertwerner/* * $Id: ASCIIHexDecode.java,v 1.2 2007-12-20 18:33:32 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.PDFFile; /** * decode an array of hex nybbles into a byte array * * @author Mike Wessler */ public class ASCIIHexDecode { private ByteBuffer buf; /** * initialize the decoder with an array of bytes in ASCIIHex format */ private ASCIIHexDecode(ByteBuffer buf) { this.buf = buf; } /** * get the next character from the input * @return a number from 0-15, or -1 for the end character */ private int readHexDigit() throws PDFParseException { // read until we hit a non-whitespace character or the // end of the stream while (buf.remaining() > 0) { int c = (int) buf.get(); // see if we found a useful character if (!PDFFile.isWhiteSpace((char) c)) { if (c >= '0' && c <= '9') { c -= '0'; } else if (c >= 'a' && c <= 'f') { c -= 'a' - 10; } else if (c >= 'A' && c <= 'F') { c -= 'A' - 10; } else if (c == '>') { c = -1; } else { // unknown character throw new PDFParseException("Bad character " + c + "in ASCIIHex decode"); } // return the useful character return c; } } // end of stream reached throw new PDFParseException("Short stream in ASCIIHex decode"); } /** * decode the array * @return the decoded bytes */ private ByteBuffer decode() throws PDFParseException { // start at the beginning of the buffer buf.rewind(); // allocate the output buffer ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { int first = readHexDigit(); int second = readHexDigit(); if (first == -1) { break; } else if (second == -1) { baos.write((byte) (first << 4)); break; } else { baos.write((byte) ((first << 4) + second)); } } return ByteBuffer.wrap(baos.toByteArray()); } /** * decode an array of bytes in ASCIIHex format. *

* ASCIIHex format consists of a sequence of Hexidecimal * digits, with possible whitespace, ending with the * '>' character. * * @param buf the encoded ASCII85 characters in a byte * buffer * @param params parameters to the decoder (ignored) * @return the decoded bytes */ public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws PDFParseException { ASCIIHexDecode me = new ASCIIHexDecode(buf); return me.decode(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/DCTDecode.java0000644000175000017500000001654111405463631023412 0ustar twernertwerner/* * $Id: DCTDecode.java,v 1.3 2010-06-14 17:32:08 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.ImageObserver; import java.io.IOException; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.colorspace.PDFColorSpace; /** * decode a DCT encoded array into a byte array. This class uses Java's * built-in JPEG image class to do the decoding. * * @author Mike Wessler */ public class DCTDecode { /** * decode an array of bytes in DCT format. *

* DCT is the format used by JPEG images, so this class simply * loads the DCT-format bytes as an image, then reads the bytes out * of the image to create the array. If this were to be used * against image objects we'd end up wasting a lot of work, because * we'd be generating a buffered image here, writing out the bytes, * and then generating a buffered image again from those bytes in the * PDFImage class. *

* Luckily, the image processing has been optimised to detect * DCT decodes at the end of filters, in which case it avoids * running the stream through this filter, and just directly * generates a BufferedImage from the DCT encoded byte stream. * As such, this decode will be invoked only if there's been * some very unusual employment of filters in the PDF - e.g., * DCTDecode applied to non-image data, or if DCTDecode is not at * the end of a Filter dictionary entry. This is permissible but * unlikely to occur in practice. *

* The DCT-encoded stream may have 1, 3 or 4 samples per pixel, depending * on the colorspace of the image. In decoding, we look for the colorspace * in the stream object's dictionary to decide how to decode this image. * If no colorspace is present, we guess 3 samples per pixel. * * @param dict the stream dictionary * @param buf the DCT-encoded buffer * @param params the parameters to the decoder (ignored) * @return the decoded buffer */ protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws PDFParseException { // System.out.println("DCTDecode image info: "+params); buf.rewind(); // copy the data into a byte array required by createimage byte[] ary = new byte[buf.remaining()]; buf.get(ary); // wait for the image to get drawn Image img= Toolkit.getDefaultToolkit().createImage(ary); MyTracker mt= new MyTracker(img); mt.waitForAll(); // the default components per pixel is 3 int numComponents = 3; // see if we have a colorspace try { PDFObject csObj = dict.getDictRef("ColorSpace"); if (csObj != null) { // we do, so get the number of components PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, null); numComponents = cs.getNumComponents(); } } catch (IOException ioe) { // oh well } // figure out the type int type = BufferedImage.TYPE_INT_RGB; if (numComponents == 1) { type = BufferedImage.TYPE_BYTE_GRAY; } else if (numComponents == 4) { type = BufferedImage.TYPE_INT_ARGB; } // create a buffered image BufferedImage bimg = new BufferedImage(img.getWidth(null), img.getHeight(null), type); Graphics bg= bimg.getGraphics(); // draw the image onto it bg.drawImage(img, 0, 0, null); byte[] output = null; // incidentally, there's a bit of an optimisation we could apply here, // if we weren't pretty confident that this isn't actually going to // be called, anyway. Namely, if we just use JAI to read in the data // the underlying data buffer seems to typically be byte[] based, // and probably already in the desired arrangement (and if not, that // could be engineered by supplying our own sample model). As it is, // we won't bother, since this code is most likely not going // to be used. if (type == BufferedImage.TYPE_INT_RGB) { // read back the data DataBufferInt db = (DataBufferInt) bimg.getData().getDataBuffer(); int[] data = db.getData(); output = new byte[data.length*3]; for (int i=0; i>16); output[i*3+1]= (byte)(data[i]>>8); output[i*3+2]= (byte)(data[i]); } } else if (type == BufferedImage.TYPE_BYTE_GRAY) { DataBufferByte db = (DataBufferByte) bimg.getData().getDataBuffer(); output = db.getData(); } else if (type == BufferedImage.TYPE_INT_ARGB) { // read back the data DataBufferInt db = (DataBufferInt) bimg.getData().getDataBuffer(); int[] data = db.getData(); output = new byte[data.length*4]; for (int i=0; i>24); output[i*4+1]= (byte)(data[i]>>16); output[i*4+2]= (byte)(data[i]>>8); output[i*4+3]= (byte)(data[i]); } } // System.out.println("Translated data"); return ByteBuffer.wrap(output); } } /** * Image tracker. I'm not sure why I'm not using the default Java * image tracker for this one. */ class MyTracker implements ImageObserver { boolean done= false; /** * create a new MyTracker that watches this image. The image * will start loading immediately. */ public MyTracker(Image img) { img.getWidth(this); } /** * More information has come in about the image. */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { if ((infoflags & (ALLBITS | ERROR | ABORT))!=0) { synchronized(this) { done= true; notifyAll(); } return false; } return true; } /** * Wait until the image is done, then return. */ public synchronized void waitForAll() { if (!done) { try { wait(); } catch (InterruptedException ie) {} } } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/RunLengthDecode.java0000644000175000017500000000661611150057144024703 0ustar twernertwerner/* * $Id: RunLengthDecode.java,v 1.1 2009-02-21 20:04:52 tomoke Exp $ * * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * decode an array of Run Length encoded bytes into a byte array * * @author Mike Wessler */ public class RunLengthDecode { /** the end of data in the RunLength encoding. */ private static final int RUN_LENGTH_EOD = 128; private ByteBuffer buf; /** * initialize the decoder with an array of bytes in RunLength format */ private RunLengthDecode(ByteBuffer buf) { this.buf = buf; } /** * decode the array * @return the decoded bytes */ private ByteBuffer decode() throws PDFParseException { // start at the beginning of the buffer buf.rewind(); // allocate the output buffer ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte dupAmount = -1; byte[] buffer = new byte[128]; while ((dupAmount = buf.get()) != -1 && dupAmount != RUN_LENGTH_EOD) { if (dupAmount <= 127) { int amountToCopy = dupAmount + 1; while (amountToCopy > 0) { buf.get(buffer, 0, amountToCopy); baos.write(buffer, 0, amountToCopy); } } else { byte dupByte = buf.get(); for (int i = 0; i < 257 - (int) (dupAmount & 0xFF); i++) { baos.write(dupByte); } } } return ByteBuffer.wrap(baos.toByteArray()); } /** * decode an array of bytes in RunLength format. *

* RunLength format consists of a sequence of a byte-oriented format * based on run length. There are a series of "runs", where * a run is a length byte followed by 1 to 128 bytes of data. * If the length is 0-127, the following length+1 (1 to 128) bytes are * to be copied. If the length is 129 through 255, the following * single byte is copied 257-length (2 to 128) times. * A length value of 128 means and End of Data (EOD). * * @param buf the RUnLEngth encoded bytes in a byte buffer * * @param params parameters to the decoder (ignored) * @return the decoded bytes */ public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws PDFParseException { RunLengthDecode me = new RunLengthDecode(buf); return me.decode(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/Predictor.java0000644000175000017500000001132611376323412023622 0ustar twernertwerner/* * $Id: Predictor.java,v 1.3 2010-05-23 22:07:04 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.nio.ByteBuffer; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * The abstract superclass of various predictor objects that undo well-known * prediction algorithms. */ public abstract class Predictor { /** well known algorithms */ public static final int TIFF = 0; public static final int PNG = 1; /** the algorithm to use */ private int algorithm; /** the number of colors per sample */ private int colors = 1; /** the number of bits per color component */ private int bpc = 8; /** the number of columns per row */ private int columns = 1; /** * Create an instance of a predictor. Use getPredictor() * instead of this. */ protected Predictor(int algorithm) { this.algorithm = algorithm; } /** * Actually perform this algorithm on decoded image data. * Subclasses must implement this method */ public abstract ByteBuffer unpredict(ByteBuffer imageData) throws IOException; /** * Get an instance of a predictor * * @param params the filter parameters */ public static Predictor getPredictor(PDFObject params) throws IOException { // get the algorithm (required) PDFObject algorithmObj = params.getDictRef("Predictor"); if (algorithmObj == null) { // no predictor return null; } int algorithm = algorithmObj.getIntValue(); // create the predictor object Predictor predictor = null; switch (algorithm) { case 1: // no predictor return null; case 2: predictor = new TIFFPredictor(); break; case 10: case 11: case 12: case 13: case 14: case 15: predictor = new PNGPredictor(); break; default: throw new PDFParseException("Unknown predictor: " + algorithm); } // read the colors (optional) PDFObject colorsObj = params.getDictRef("Colors"); if (colorsObj != null) { predictor.setColors(colorsObj.getIntValue()); } // read the bits per component (optional) PDFObject bpcObj = params.getDictRef("BitsPerComponent"); if (bpcObj != null) { predictor.setBitsPerComponent(bpcObj.getIntValue()); } // read the columns (optional) PDFObject columnsObj = params.getDictRef("Columns"); if (columnsObj != null) { predictor.setColumns(columnsObj.getIntValue()); } // all set return predictor; } /** * Get the algorithm in use * * @return one of the known algorithm types */ public int getAlgorithm() { return algorithm; } /** * Get the number of colors per sample */ public int getColors() { return colors; } /** * Set the number of colors per sample */ protected void setColors(int colors) { this.colors = colors; } /** * Get the number of bits per color component */ public int getBitsPerComponent() { return bpc; } /** * Set the number of bits per color component */ public void setBitsPerComponent(int bpc) { this.bpc = bpc; } /** * Get the number of columns */ public int getColumns() { return columns; } /** * Set the number of columns */ public void setColumns(int columns) { this.columns = columns; } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/FlateDecode.java0000644000175000017500000000710611127717423024032 0ustar twernertwerner/* * $Id: FlateDecode.java,v 1.4 2009-01-03 17:23:30 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.zip.DataFormatException; import java.util.zip.Inflater; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * decode a deFlated byte array * @author Mike Wessler */ public class FlateDecode { /** * decode a byte buffer in Flate format. *

* Flate is a built-in Java algorithm. It's part of the java.util.zip * package. * * @param buf the deflated input buffer * @param params parameters to the decoder (unused) * @return the decoded (inflated) bytes */ public static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws IOException { Inflater inf = new Inflater(false); int bufSize = buf.remaining(); // copy the data, since the array() method is not supported // on raf-based ByteBuffers byte[] data = new byte[bufSize]; buf.get(data); // set the input to the inflater inf.setInput(data); // output to a byte-array output stream, since we don't // know how big the output will be ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] decomp = new byte[bufSize]; int loc = 0; int read = 0; try { while (!inf.finished()) { read = inf.inflate(decomp); if (read <= 0) { // System.out.println("Read = " + read + "! Params: " + params); if (inf.needsDictionary()) { throw new PDFParseException("Don't know how to ask for a dictionary in FlateDecode"); } else { // System.out.println("Inflate data length=" + buf.remaining()); return ByteBuffer.allocate(0); // throw new PDFParseException("Inflater wants more data... but it's already here!"); } } baos.write(decomp, 0, read); } } catch (DataFormatException dfe) { throw new PDFParseException("Data format exception:" + dfe.getMessage()); } // return the output as a byte buffer ByteBuffer outBytes = ByteBuffer.wrap(baos.toByteArray()); // undo a predictor algorithm, if any was used if (params != null && params.getDictionary().containsKey("Predictor")) { Predictor predictor = Predictor.getPredictor(params); if (predictor != null) { outBytes = predictor.unpredict(outBytes); } } return outBytes; } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/LZWDecode.java0000644000175000017500000001617311150120054023437 0ustar twernertwerner/* * $Id: LZWDecode.java,v 1.4 2009-02-22 00:45:32 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * decode an LZW-encoded array of bytes. LZW is a patented algorithm. * *

Feb 21, 2009 Legal statement on Intellectual Property from Unisys

 * LZW Patent Information (http://www.unisys.com/about__unisys/lzw)
 * License Information on GIF and Other LZW-based Technologies
 * 

* Unisys U.S. LZW Patent No. 4,558,302 expired on June 20, 2003, * the counterpart patents in the United Kingdom, France, Germany and * Italy expired on June 18, 2004, the Japanese counterpart patents * expired on June 20, 2004 and the counterpart Canadian patent * expired on July 7, 2004. *

* Unisys Corporation holds and has patents pending on a number of * improvements on the inventions claimed in the above-expired patents. * Information on these improvement patents and terms under which they * may be licensed can be obtained by contacting the following: *

* Unisys Corporation * Welch Patent Licensing Department * Mail Stop E8-114 * Unisys Way * Blue Bell, PA 19424 *

* Via the Internet, send email to Robert.Marley@unisys.com. *

* Via facsimile, send inquiries to Welch Patent Licensing Department at * 215-986-3090. *

* The above is presented for information purposes only, and is subject * to change by Unisys. Additionally, this information should not be * considered as legally obligating Unisys in any way with regard to license * availability, or as to the terms and conditions offered for a license, * or with regard to the interpretation of any license agreements. * You should consult with your own legal counsel regarding your * particular situation. *

* * @author Mike Wessler */ public class LZWDecode { ByteBuffer buf; int bytepos; int bitpos; byte[] dict[] = new byte[4096][]; int dictlen = 0; int bitspercode = 9; static int STOP = 257; static int CLEARDICT = 256; /** * initialize this decoder with an array of encoded bytes * @param buf the buffer of bytes */ private LZWDecode(ByteBuffer buf) throws PDFParseException { for (int i = 0; i < 256; i++) { dict[i] = new byte[1]; dict[i][0] = (byte) i; } dictlen = 258; bitspercode = 9; this.buf = buf; bytepos = 0; bitpos = 0; } /** * reset the dictionary to the initial 258 entries */ private void resetDict() { dictlen = 258; bitspercode = 9; } /** * get the next code from the input stream */ private int nextCode() { int fillbits = bitspercode; int value = 0; if (bytepos >= buf.limit() - 1) { return -1; } while (fillbits > 0) { int nextbits = buf.get(bytepos); // bitsource int bitsfromhere = 8 - bitpos; // how many bits can we take? if (bitsfromhere > fillbits) { // don't take more than we need bitsfromhere = fillbits; } value |= ((nextbits >> (8 - bitpos - bitsfromhere)) & (0xff >> (8 - bitsfromhere))) << (fillbits - bitsfromhere); fillbits -= bitsfromhere; bitpos += bitsfromhere; if (bitpos >= 8) { bitpos = 0; bytepos++; } } return value; } /** * decode the array. * @return the uncompressed byte array */ private ByteBuffer decode() throws PDFParseException { // algorithm derived from: // http://www.rasip.fer.hr/research/compress/algorithms/fund/lz/lzw.html // and the PDFReference int cW = CLEARDICT; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { int pW = cW; cW = nextCode(); if (cW == -1) { throw new PDFParseException("Missed the stop code in LZWDecode!"); } if (cW == STOP) { break; } else if (cW == CLEARDICT) { resetDict(); // pW= -1; } else if (pW == CLEARDICT) { baos.write(dict[cW], 0, dict[cW].length); } else { if (cW < dictlen) { // it's a code in the dictionary baos.write(dict[cW], 0, dict[cW].length); byte[] p = new byte[dict[pW].length + 1]; System.arraycopy(dict[pW], 0, p, 0, dict[pW].length); p[dict[pW].length] = dict[cW][0]; dict[dictlen++] = p; } else { // not in the dictionary (should==dictlen) // if (cW!=dictlen) { // System.out.println("Got a bouncy code: "+cW+" (dictlen="+dictlen+")"); // } byte[] p = new byte[dict[pW].length + 1]; System.arraycopy(dict[pW], 0, p, 0, dict[pW].length); p[dict[pW].length] = p[0]; baos.write(p, 0, p.length); dict[dictlen++] = p; } if (dictlen >= (1 << bitspercode) - 1 && bitspercode < 12) { bitspercode++; } } } return ByteBuffer.wrap(baos.toByteArray()); } /** * decode an array of LZW-encoded bytes to a byte array. * * @param buf the buffer of encoded bytes * @param params parameters for the decoder (unused) * @return the decoded uncompressed bytes */ public static ByteBuffer decode(ByteBuffer buf, PDFObject params) throws IOException { // decode the array LZWDecode me = new LZWDecode(buf); ByteBuffer outBytes = me.decode(); // undo a predictor algorithm, if any was used if (params != null && params.getDictionary().containsKey("Predictor")) { Predictor predictor = Predictor.getPredictor(params); if (predictor != null) { outBytes = predictor.unpredict(outBytes); } } return outBytes; } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/PNGPredictor.java0000644000175000017500000001475011145024767024200 0ustar twernertwerner/* * $Id: PNGPredictor.java,v 1.3 2009-02-12 13:53:58 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decode; import java.nio.ByteBuffer; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * Undo prediction based on the PNG algorithm. */ public class PNGPredictor extends Predictor { /** Creates a new instance of PNGPredictor */ public PNGPredictor() { super (PNG); } /** * Undo data based on the png algorithm */ public ByteBuffer unpredict(ByteBuffer imageData) throws IOException { List rows = new ArrayList(); byte[] curLine = null; byte[] prevLine = null; // get the number of bytes per row int rowSize = getColumns() * getColors() * getBitsPerComponent(); rowSize = (int) Math.ceil(rowSize / 8.0); while(imageData.remaining() >= rowSize + 1) { // the first byte determines the algorithm int algorithm = (int) (imageData.get() & 0xff); // read the rest of the line curLine = new byte[rowSize]; imageData.get(curLine); // use the algorithm, Luke switch (algorithm) { case 0: // none break; case 1: doSubLine(curLine); break; case 2: doUpLine(curLine, prevLine); break; case 3: doAverageLine(curLine, prevLine); break; case 4: doPaethLine(curLine, prevLine); break; } rows.add(curLine); prevLine = curLine; } // turn into byte array ByteBuffer outBuf = ByteBuffer.allocate(rows.size() * rowSize); for (Iterator i = rows.iterator(); i.hasNext();) { outBuf.put((byte[]) i.next()); } // reset start pointer outBuf.flip(); // return return outBuf; } /** * Return the value of the Sub algorithm on the line (compare bytes to * the previous byte of the same color on this line). */ protected void doSubLine(byte[] curLine) { // get the number of bytes per sample int sub = (int) Math.ceil((getBitsPerComponent() * getColors()) / 8.0); for (int i = 0; i < curLine.length; i++) { int prevIdx = i - sub; if (prevIdx >= 0) { curLine[i] += curLine[prevIdx]; } } } /** * Return the value of the up algorithm on the line (compare bytes to * the same byte in the previous line) */ protected void doUpLine(byte[] curLine, byte[] prevLine) { if (prevLine == null) { // do nothing if this is the first line return; } for (int i = 0; i < curLine.length; i++) { curLine[i] += prevLine[i]; } } /** * Return the value of the average algorithm on the line (compare * bytes to the average of the previous byte of the same color and * the same byte on the previous line) */ protected void doAverageLine(byte[] curLine, byte[] prevLine) { // get the number of bytes per sample int sub = (int) Math.ceil((getBitsPerComponent() * getColors()) / 8.0); for (int i = 0; i < curLine.length; i++) { int raw = 0; int prior = 0; // get the last value of this color int prevIdx = i - sub; if (prevIdx >= 0) { raw = curLine[prevIdx] & 0xff; } // get the value on the previous line if (prevLine != null) { prior = prevLine[i] & 0xff; } // add the average curLine[i] += (byte) Math.floor((raw + prior) / 2); } } /** * Return the value of the average algorithm on the line (compare * bytes to the average of the previous byte of the same color and * the same byte on the previous line) */ protected void doPaethLine(byte[] curLine, byte[] prevLine) { // get the number of bytes per sample int sub = (int) Math.ceil((getBitsPerComponent() * getColors()) / 8.0); for (int i = 0; i < curLine.length; i++) { int left = 0; int up = 0; int upLeft = 0; // get the last value of this color int prevIdx = i - sub; if (prevIdx >= 0) { left = curLine[prevIdx] & 0xff; } // get the value on the previous line if (prevLine != null) { up = prevLine[i] & 0xff; } if (prevIdx > 0 && prevLine != null) { upLeft = prevLine[prevIdx] & 0xff; } // add the average curLine[i] += (byte) paeth(left, up, upLeft); } } /** * The paeth algorithm */ protected int paeth(int left, int up, int upLeft) { int p = left + up - upLeft; int pa = Math.abs(p - left); int pb = Math.abs(p - up); int pc = Math.abs(p - upLeft); if ((pa <= pb) && (pa <= pc)) { return left; } else if (pb <= pc) { return up; } else { return upLeft; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/decode/CCITTFaxDecoder.java0000644000175000017500000012706711145104376024474 0ustar twernertwerner/* * Based on the SUN code (see license beyond) changes are made to handle CCITTFax encoded * data in a PDF image. This may or may not apply to real world CCITT documents. * * Copyright (c) 2007, intarsys consulting GmbH * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - 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. * * - Neither the name of intarsys nor the names of its contributors may be used * to endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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. */ /* * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduct the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that Software is not designed,licensed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ package com.sun.pdfview.decode; public class CCITTFaxDecoder { static int[] table1 = { 0x00, // 0 bits are left in first byte - SHOULD // NOT HAPPEN 0x01, // 1 bits are left in first byte 0x03, // 2 bits are left in first byte 0x07, // 3 bits are left in first byte 0x0f, // 4 bits are left in first byte 0x1f, // 5 bits are left in first byte 0x3f, // 6 bits are left in first byte 0x7f, // 7 bits are left in first byte 0xff // 8 bits are left in first byte }; static int[] table2 = { 0x00, // 0 0x80, // 1 0xc0, // 2 0xe0, // 3 0xf0, // 4 0xf8, // 5 0xfc, // 6 0xfe, // 7 0xff // 8 }; // Table to be used when fillOrder = 2, for flipping bytes. static byte[] flipTable = { 0, -128, 64, -64, 32, -96, 96, -32, 16, -112, 80, -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, 24, -104, 88, -40, 56, -72, 120, -8, 4, -124, 68, -60, 36, -92, 100, -28, 20, -108, 84, -44, 52, -76, 116, -12, 12, -116, 76, -52, 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, -126, 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, 10, -118, 74, -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, 122, -6, 6, -122, 70, -58, 38, -90, 102, -26, 22, -106, 86, -42, 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, 30, -98, 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, -111, 81, -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, -23, 25, -103, 89, -39, 57, -71, 121, -7, 5, -123, 69, -59, 37, -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, -11, 13, -115, 77, -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, -125, 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, -13, 11, -117, 75, -53, 43, -85, 107, -21, 27, -101, 91, -37, 59, -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, -25, 23, -105, 87, -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, -97, 95, -33, 63, -65, 127, -1, }; // The main 10 bit white runs lookup table static short white[] = { // 0 - 7 6430, 6400, 6400, 6400, 3225, 3225, 3225, 3225, // 8 - 15 944, 944, 944, 944, 976, 976, 976, 976, // 16 - 23 1456, 1456, 1456, 1456, 1488, 1488, 1488, 1488, // 24 - 31 718, 718, 718, 718, 718, 718, 718, 718, // 32 - 39 750, 750, 750, 750, 750, 750, 750, 750, // 40 - 47 1520, 1520, 1520, 1520, 1552, 1552, 1552, 1552, // 48 - 55 428, 428, 428, 428, 428, 428, 428, 428, // 56 - 63 428, 428, 428, 428, 428, 428, 428, 428, // 64 - 71 654, 654, 654, 654, 654, 654, 654, 654, // 72 - 79 1072, 1072, 1072, 1072, 1104, 1104, 1104, 1104, // 80 - 87 1136, 1136, 1136, 1136, 1168, 1168, 1168, 1168, // 88 - 95 1200, 1200, 1200, 1200, 1232, 1232, 1232, 1232, // 96 - 103 622, 622, 622, 622, 622, 622, 622, 622, // 104 - 111 1008, 1008, 1008, 1008, 1040, 1040, 1040, 1040, // 112 - 119 44, 44, 44, 44, 44, 44, 44, 44, // 120 - 127 44, 44, 44, 44, 44, 44, 44, 44, // 128 - 135 396, 396, 396, 396, 396, 396, 396, 396, // 136 - 143 396, 396, 396, 396, 396, 396, 396, 396, // 144 - 151 1712, 1712, 1712, 1712, 1744, 1744, 1744, 1744, // 152 - 159 846, 846, 846, 846, 846, 846, 846, 846, // 160 - 167 1264, 1264, 1264, 1264, 1296, 1296, 1296, 1296, // 168 - 175 1328, 1328, 1328, 1328, 1360, 1360, 1360, 1360, // 176 - 183 1392, 1392, 1392, 1392, 1424, 1424, 1424, 1424, // 184 - 191 686, 686, 686, 686, 686, 686, 686, 686, // 192 - 199 910, 910, 910, 910, 910, 910, 910, 910, // 200 - 207 1968, 1968, 1968, 1968, 2000, 2000, 2000, 2000, // 208 - 215 2032, 2032, 2032, 2032, 16, 16, 16, 16, // 216 - 223 10257, 10257, 10257, 10257, 12305, 12305, 12305, 12305, // 224 - 231 330, 330, 330, 330, 330, 330, 330, 330, // 232 - 239 330, 330, 330, 330, 330, 330, 330, 330, // 240 - 247 330, 330, 330, 330, 330, 330, 330, 330, // 248 - 255 330, 330, 330, 330, 330, 330, 330, 330, // 256 - 263 362, 362, 362, 362, 362, 362, 362, 362, // 264 - 271 362, 362, 362, 362, 362, 362, 362, 362, // 272 - 279 362, 362, 362, 362, 362, 362, 362, 362, // 280 - 287 362, 362, 362, 362, 362, 362, 362, 362, // 288 - 295 878, 878, 878, 878, 878, 878, 878, 878, // 296 - 303 1904, 1904, 1904, 1904, 1936, 1936, 1936, 1936, // 304 - 311 -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, // 312 - 319 590, 590, 590, 590, 590, 590, 590, 590, // 320 - 327 782, 782, 782, 782, 782, 782, 782, 782, // 328 - 335 1584, 1584, 1584, 1584, 1616, 1616, 1616, 1616, // 336 - 343 1648, 1648, 1648, 1648, 1680, 1680, 1680, 1680, // 344 - 351 814, 814, 814, 814, 814, 814, 814, 814, // 352 - 359 1776, 1776, 1776, 1776, 1808, 1808, 1808, 1808, // 360 - 367 1840, 1840, 1840, 1840, 1872, 1872, 1872, 1872, // 368 - 375 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, // 376 - 383 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, // 384 - 391 -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, // 392 - 399 -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, // 400 - 407 14353, 14353, 14353, 14353, 16401, 16401, 16401, 16401, // 408 - 415 22547, 22547, 24595, 24595, 20497, 20497, 20497, 20497, // 416 - 423 18449, 18449, 18449, 18449, 26643, 26643, 28691, 28691, // 424 - 431 30739, 30739, -32749, -32749, -30701, -30701, -28653, -28653, // 432 - 439 -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, // 440 - 447 8207, 8207, 8207, 8207, 8207, 8207, 8207, 8207, // 448 - 455 72, 72, 72, 72, 72, 72, 72, 72, // 456 - 463 72, 72, 72, 72, 72, 72, 72, 72, // 464 - 471 72, 72, 72, 72, 72, 72, 72, 72, // 472 - 479 72, 72, 72, 72, 72, 72, 72, 72, // 480 - 487 72, 72, 72, 72, 72, 72, 72, 72, // 488 - 495 72, 72, 72, 72, 72, 72, 72, 72, // 496 - 503 72, 72, 72, 72, 72, 72, 72, 72, // 504 - 511 72, 72, 72, 72, 72, 72, 72, 72, // 512 - 519 104, 104, 104, 104, 104, 104, 104, 104, // 520 - 527 104, 104, 104, 104, 104, 104, 104, 104, // 528 - 535 104, 104, 104, 104, 104, 104, 104, 104, // 536 - 543 104, 104, 104, 104, 104, 104, 104, 104, // 544 - 551 104, 104, 104, 104, 104, 104, 104, 104, // 552 - 559 104, 104, 104, 104, 104, 104, 104, 104, // 560 - 567 104, 104, 104, 104, 104, 104, 104, 104, // 568 - 575 104, 104, 104, 104, 104, 104, 104, 104, // 576 - 583 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, // 584 - 591 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, // 592 - 599 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, // 600 - 607 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, // 608 - 615 266, 266, 266, 266, 266, 266, 266, 266, // 616 - 623 266, 266, 266, 266, 266, 266, 266, 266, // 624 - 631 266, 266, 266, 266, 266, 266, 266, 266, // 632 - 639 266, 266, 266, 266, 266, 266, 266, 266, // 640 - 647 298, 298, 298, 298, 298, 298, 298, 298, // 648 - 655 298, 298, 298, 298, 298, 298, 298, 298, // 656 - 663 298, 298, 298, 298, 298, 298, 298, 298, // 664 - 671 298, 298, 298, 298, 298, 298, 298, 298, // 672 - 679 524, 524, 524, 524, 524, 524, 524, 524, // 680 - 687 524, 524, 524, 524, 524, 524, 524, 524, // 688 - 695 556, 556, 556, 556, 556, 556, 556, 556, // 696 - 703 556, 556, 556, 556, 556, 556, 556, 556, // 704 - 711 136, 136, 136, 136, 136, 136, 136, 136, // 712 - 719 136, 136, 136, 136, 136, 136, 136, 136, // 720 - 727 136, 136, 136, 136, 136, 136, 136, 136, // 728 - 735 136, 136, 136, 136, 136, 136, 136, 136, // 736 - 743 136, 136, 136, 136, 136, 136, 136, 136, // 744 - 751 136, 136, 136, 136, 136, 136, 136, 136, // 752 - 759 136, 136, 136, 136, 136, 136, 136, 136, // 760 - 767 136, 136, 136, 136, 136, 136, 136, 136, // 768 - 775 168, 168, 168, 168, 168, 168, 168, 168, // 776 - 783 168, 168, 168, 168, 168, 168, 168, 168, // 784 - 791 168, 168, 168, 168, 168, 168, 168, 168, // 792 - 799 168, 168, 168, 168, 168, 168, 168, 168, // 800 - 807 168, 168, 168, 168, 168, 168, 168, 168, // 808 - 815 168, 168, 168, 168, 168, 168, 168, 168, // 816 - 823 168, 168, 168, 168, 168, 168, 168, 168, // 824 - 831 168, 168, 168, 168, 168, 168, 168, 168, // 832 - 839 460, 460, 460, 460, 460, 460, 460, 460, // 840 - 847 460, 460, 460, 460, 460, 460, 460, 460, // 848 - 855 492, 492, 492, 492, 492, 492, 492, 492, // 856 - 863 492, 492, 492, 492, 492, 492, 492, 492, // 864 - 871 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, // 872 - 879 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, // 880 - 887 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, // 888 - 895 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, // 896 - 903 200, 200, 200, 200, 200, 200, 200, 200, // 904 - 911 200, 200, 200, 200, 200, 200, 200, 200, // 912 - 919 200, 200, 200, 200, 200, 200, 200, 200, // 920 - 927 200, 200, 200, 200, 200, 200, 200, 200, // 928 - 935 200, 200, 200, 200, 200, 200, 200, 200, // 936 - 943 200, 200, 200, 200, 200, 200, 200, 200, // 944 - 951 200, 200, 200, 200, 200, 200, 200, 200, // 952 - 959 200, 200, 200, 200, 200, 200, 200, 200, // 960 - 967 232, 232, 232, 232, 232, 232, 232, 232, // 968 - 975 232, 232, 232, 232, 232, 232, 232, 232, // 976 - 983 232, 232, 232, 232, 232, 232, 232, 232, // 984 - 991 232, 232, 232, 232, 232, 232, 232, 232, // 992 - 999 232, 232, 232, 232, 232, 232, 232, 232, // 1000 - 1007 232, 232, 232, 232, 232, 232, 232, 232, // 1008 - 1015 232, 232, 232, 232, 232, 232, 232, 232, // 1016 - 1023 232, 232, 232, 232, 232, 232, 232, 232, }; // Additional make up codes for both White and Black runs static short[] additionalMakeup = { 28679, 28679, 31752, (short) 32777, (short) 33801, (short) 34825, (short) 35849, (short) 36873, (short) 29703, (short) 29703, (short) 30727, (short) 30727, (short) 37897, (short) 38921, (short) 39945, (short) 40969 }; // Initial black run look up table, uses the first 4 bits of a code static short[] initBlack = { // 0 - 7 3226, 6412, 200, 168, 38, 38, 134, 134, // 8 - 15 100, 100, 100, 100, 68, 68, 68, 68 }; // static short[] twoBitBlack = { 292, 260, 226, 226 }; // 0 - 3 // Main black run table, using the last 9 bits of possible 13 bit code static short black[] = { // 0 - 7 62, 62, 30, 30, 0, 0, 0, 0, // 8 - 15 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 23 0, 0, 0, 0, 0, 0, 0, 0, // 24 - 31 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 39 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, // 40 - 47 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, // 48 - 55 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, // 56 - 63 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, // 64 - 71 588, 588, 588, 588, 588, 588, 588, 588, // 72 - 79 1680, 1680, 20499, 22547, 24595, 26643, 1776, 1776, // 80 - 87 1808, 1808, -24557, -22509, -20461, -18413, 1904, 1904, // 88 - 95 1936, 1936, -16365, -14317, 782, 782, 782, 782, // 96 - 103 814, 814, 814, 814, -12269, -10221, 10257, 10257, // 104 - 111 12305, 12305, 14353, 14353, 16403, 18451, 1712, 1712, // 112 - 119 1744, 1744, 28691, 30739, -32749, -30701, -28653, -26605, // 120 - 127 2061, 2061, 2061, 2061, 2061, 2061, 2061, 2061, // 128 - 135 424, 424, 424, 424, 424, 424, 424, 424, // 136 - 143 424, 424, 424, 424, 424, 424, 424, 424, // 144 - 151 424, 424, 424, 424, 424, 424, 424, 424, // 152 - 159 424, 424, 424, 424, 424, 424, 424, 424, // 160 - 167 750, 750, 750, 750, 1616, 1616, 1648, 1648, // 168 - 175 1424, 1424, 1456, 1456, 1488, 1488, 1520, 1520, // 176 - 183 1840, 1840, 1872, 1872, 1968, 1968, 8209, 8209, // 184 - 191 524, 524, 524, 524, 524, 524, 524, 524, // 192 - 199 556, 556, 556, 556, 556, 556, 556, 556, // 200 - 207 1552, 1552, 1584, 1584, 2000, 2000, 2032, 2032, // 208 - 215 976, 976, 1008, 1008, 1040, 1040, 1072, 1072, // 216 - 223 1296, 1296, 1328, 1328, 718, 718, 718, 718, // 224 - 231 456, 456, 456, 456, 456, 456, 456, 456, // 232 - 239 456, 456, 456, 456, 456, 456, 456, 456, // 240 - 247 456, 456, 456, 456, 456, 456, 456, 456, // 248 - 255 456, 456, 456, 456, 456, 456, 456, 456, // 256 - 263 326, 326, 326, 326, 326, 326, 326, 326, // 264 - 271 326, 326, 326, 326, 326, 326, 326, 326, // 272 - 279 326, 326, 326, 326, 326, 326, 326, 326, // 280 - 287 326, 326, 326, 326, 326, 326, 326, 326, // 288 - 295 326, 326, 326, 326, 326, 326, 326, 326, // 296 - 303 326, 326, 326, 326, 326, 326, 326, 326, // 304 - 311 326, 326, 326, 326, 326, 326, 326, 326, // 312 - 319 326, 326, 326, 326, 326, 326, 326, 326, // 320 - 327 358, 358, 358, 358, 358, 358, 358, 358, // 328 - 335 358, 358, 358, 358, 358, 358, 358, 358, // 336 - 343 358, 358, 358, 358, 358, 358, 358, 358, // 344 - 351 358, 358, 358, 358, 358, 358, 358, 358, // 352 - 359 358, 358, 358, 358, 358, 358, 358, 358, // 360 - 367 358, 358, 358, 358, 358, 358, 358, 358, // 368 - 375 358, 358, 358, 358, 358, 358, 358, 358, // 376 - 383 358, 358, 358, 358, 358, 358, 358, 358, // 384 - 391 490, 490, 490, 490, 490, 490, 490, 490, // 392 - 399 490, 490, 490, 490, 490, 490, 490, 490, // 400 - 407 4113, 4113, 6161, 6161, 848, 848, 880, 880, // 408 - 415 912, 912, 944, 944, 622, 622, 622, 622, // 416 - 423 654, 654, 654, 654, 1104, 1104, 1136, 1136, // 424 - 431 1168, 1168, 1200, 1200, 1232, 1232, 1264, 1264, // 432 - 439 686, 686, 686, 686, 1360, 1360, 1392, 1392, // 440 - 447 12, 12, 12, 12, 12, 12, 12, 12, // 448 - 455 390, 390, 390, 390, 390, 390, 390, 390, // 456 - 463 390, 390, 390, 390, 390, 390, 390, 390, // 464 - 471 390, 390, 390, 390, 390, 390, 390, 390, // 472 - 479 390, 390, 390, 390, 390, 390, 390, 390, // 480 - 487 390, 390, 390, 390, 390, 390, 390, 390, // 488 - 495 390, 390, 390, 390, 390, 390, 390, 390, // 496 - 503 390, 390, 390, 390, 390, 390, 390, 390, // 504 - 511 390, 390, 390, 390, 390, 390, 390, 390, }; static byte[] twoDCodes = { // 0 - 7 80, 88, 23, 71, 30, 30, 62, 62, // 8 - 15 4, 4, 4, 4, 4, 4, 4, 4, // 16 - 23 11, 11, 11, 11, 11, 11, 11, 11, // 24 - 31 11, 11, 11, 11, 11, 11, 11, 11, // 32 - 39 35, 35, 35, 35, 35, 35, 35, 35, // 40 - 47 35, 35, 35, 35, 35, 35, 35, 35, // 48 - 55 51, 51, 51, 51, 51, 51, 51, 51, // 56 - 63 51, 51, 51, 51, 51, 51, 51, 51, // 64 - 71 41, 41, 41, 41, 41, 41, 41, 41, // 72 - 79 41, 41, 41, 41, 41, 41, 41, 41, // 80 - 87 41, 41, 41, 41, 41, 41, 41, 41, // 88 - 95 41, 41, 41, 41, 41, 41, 41, 41, // 96 - 103 41, 41, 41, 41, 41, 41, 41, 41, // 104 - 111 41, 41, 41, 41, 41, 41, 41, 41, // 112 - 119 41, 41, 41, 41, 41, 41, 41, 41, // 120 - 127 41, 41, 41, 41, 41, 41, 41, 41, }; private int bitPointer; private int bytePointer; private byte[] data; private int w; private boolean align = false; private int fillOrder; // Data structures needed to store changing elements for the previous // and the current scanline private int changingElemSize = 0; private int[] prevChangingElems; private int[] currChangingElems; // Element at which to start search in getNextChangingElement private int lastChangingElement = 0; private boolean fillBits = false; /** * @param fillOrder * The fill order of the compressed data bytes. * @param w * @param h */ public CCITTFaxDecoder(int fillOrder, int w, int h) { this.fillOrder = fillOrder; this.w = w; this.bitPointer = 0; this.bytePointer = 0; this.prevChangingElems = new int[w]; this.currChangingElems = new int[w]; } private boolean align() { if (align && bitPointer != 0) { bytePointer++; bitPointer = 0; return true; } return false; } protected boolean consumeEOL() { // Get the next 12 bits. int next12Bits = nextNBits(12); if (next12Bits == 1) { // EOL found & consumed return true; } // no EOL - unread and return updatePointer(12); return false; } // Returns run length private int decodeBlackCodeWord() { int current; int entry; int bits; int isT; int code = -1; int runLength = 0; boolean isWhite = false; while (!isWhite) { current = nextLesserThan8Bits(4); entry = initBlack[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x000f; code = (entry >>> 5) & 0x07ff; if (code == 100) { current = nextNBits(9); entry = black[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x000f; code = (entry >>> 5) & 0x07ff; if (bits == 12) { // Additional makeup codes updatePointer(5); current = nextLesserThan8Bits(4); entry = additionalMakeup[current]; bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 code = (entry >>> 4) & 0x0fff; // 12 bits runLength += code; updatePointer(4 - bits); } else if (bits == 15) { // EOL code throw new RuntimeException( "EOL code word encountered in Black run."); //$NON-NLS-1$ } else { runLength += code; updatePointer(9 - bits); if (isT == 0) { isWhite = true; } } } else if (code == 200) { // Is a Terminating code current = nextLesserThan8Bits(2); entry = twoBitBlack[current]; code = (entry >>> 5) & 0x07ff; runLength += code; bits = (entry >>> 1) & 0x0f; updatePointer(2 - bits); isWhite = true; } else { // Is a Terminating code runLength += code; updatePointer(4 - bits); isWhite = true; } } return runLength; } protected void decodeNextScanline(byte[] buffer, int lineOffset, int bitOffset) { int bits = 0; int code = 0; int isT = 0; int current; int entry; int twoBits; boolean isWhite = true; // Initialize starting of the changing elements array changingElemSize = 0; // While scanline not complete while (bitOffset < w) { while (isWhite) { // White run current = nextNBits(10); entry = white[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x0f; if (bits == 12) { // Additional Make up code // Get the next 2 bits twoBits = nextLesserThan8Bits(2); // Consolidate the 2 new bits and last 2 bits into 4 bits current = ((current << 2) & 0x000c) | twoBits; entry = additionalMakeup[current]; bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 code = (entry >>> 4) & 0x0fff; // 12 bits bitOffset += code; // Skip white run updatePointer(4 - bits); } else if (bits == 0) { // ERROR throw new RuntimeException("Invalid code encountered."); } else if (bits == 15) { // EOL recover // move bits back... updatePointer(10); return; } else { // 11 bits - 0000 0111 1111 1111 = 0x07ff code = (entry >>> 5) & 0x07ff; bitOffset += code; updatePointer(10 - bits); if (isT == 0) { isWhite = false; currChangingElems[changingElemSize++] = bitOffset; } } } // Check whether this run completed one width, if so // advance to next byte boundary for compression = 2. if (bitOffset == w) { align(); break; } while (isWhite == false) { // Black run current = nextLesserThan8Bits(4); entry = initBlack[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x000f; code = (entry >>> 5) & 0x07ff; if (code == 100) { current = nextNBits(9); entry = black[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x000f; code = (entry >>> 5) & 0x07ff; if (bits == 12) { // Additional makeup codes updatePointer(5); current = nextLesserThan8Bits(4); entry = additionalMakeup[current]; bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 code = (entry >>> 4) & 0x0fff; // 12 bits setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(4 - bits); } else if (bits == 15) { // EOL recover // unread bits ??? updatePointer(9); return; } else { setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(9 - bits); if (isT == 0) { isWhite = true; currChangingElems[changingElemSize++] = bitOffset; } } } else if (code == 200) { // Is a Terminating code current = nextLesserThan8Bits(2); entry = twoBitBlack[current]; code = (entry >>> 5) & 0x07ff; bits = (entry >>> 1) & 0x0f; setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(2 - bits); isWhite = true; currChangingElems[changingElemSize++] = bitOffset; } else { // Is a Terminating code setToBlack(buffer, lineOffset, bitOffset, code); bitOffset += code; updatePointer(4 - bits); isWhite = true; currChangingElems[changingElemSize++] = bitOffset; } } // Check whether this run completed one width if (bitOffset == w) { align(); break; } } currChangingElems[changingElemSize++] = bitOffset; } // One-dimensional decoding methods public void decodeT41D(byte[] buffer, byte[] compData, int startX, int height) { this.data = compData; int scanlineStride = (w + 7) / 8; bitPointer = 0; bytePointer = 0; int lineOffset = 0; for (int i = 0; i < height; i++) { consumeEOL(); decodeNextScanline(buffer, lineOffset, startX); lineOffset += scanlineStride; } } // Two-dimensional decoding methods public void decodeT42D(byte[] buffer, byte[] compData, int startX, int height) { this.data = compData; int scanlineStride = (w + 7) / 8; bitPointer = 0; bytePointer = 0; int a0; int a1; int b1; int b2; int[] b = new int[2]; int entry; int code; int bits; boolean isWhite; int currIndex = 0; int[] temp; // The data must start with an EOL code if (readEOL(true) != 1) { throw new RuntimeException("First scanline must be 1D encoded."); //$NON-NLS-1$ } int lineOffset = 0; int bitOffset; // Then the 1D encoded scanline data will occur, changing elements // array gets set. decodeNextScanline(buffer, lineOffset, startX); lineOffset += scanlineStride; for (int lines = 1; lines < height; lines++) { // Every line must begin with an EOL followed by a bit which // indicates whether the following scanline is 1D or 2D encoded. if (readEOL(false) == 0) { // 2D encoded scanline follows // Initialize previous scanlines changing elements, and // initialize current scanline's changing elements array temp = prevChangingElems; prevChangingElems = currChangingElems; currChangingElems = temp; currIndex = 0; // a0 has to be set just before the start of this scanline. a0 = -1; isWhite = true; bitOffset = startX; lastChangingElement = 0; while (bitOffset < w) { // Get the next changing element getNextChangingElement(a0, isWhite, b); b1 = b[0]; b2 = b[1]; // Get the next seven bits entry = nextLesserThan8Bits(7); // Run these through the 2DCodes table entry = (twoDCodes[entry] & 0xff); // Get the code and the number of bits used up code = (entry & 0x78) >>> 3; bits = entry & 0x07; if (code == 0) { if (!isWhite) { setToBlack(buffer, lineOffset, bitOffset, b2 - bitOffset); } bitOffset = a0 = b2; // Set pointer to consume the correct number of bits. updatePointer(7 - bits); } else if (code == 1) { // Horizontal updatePointer(7 - bits); // identify the next 2 codes. int number; if (isWhite) { number = decodeWhiteCodeWord(); bitOffset += number; currChangingElems[currIndex++] = bitOffset; number = decodeBlackCodeWord(); setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; currChangingElems[currIndex++] = bitOffset; } else { number = decodeBlackCodeWord(); setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; currChangingElems[currIndex++] = bitOffset; number = decodeWhiteCodeWord(); bitOffset += number; currChangingElems[currIndex++] = bitOffset; } a0 = bitOffset; } else if (code <= 8) { // Vertical a1 = b1 + (code - 5); currChangingElems[currIndex++] = a1; // We write the current color till a1 - 1 pos, // since a1 is where the next color starts if (!isWhite) { setToBlack(buffer, lineOffset, bitOffset, a1 - bitOffset); } bitOffset = a0 = a1; isWhite = !isWhite; updatePointer(7 - bits); } else { throw new RuntimeException( "Invalid code encountered while decoding 2D group 3 compressed data."); //$NON-NLS-1$ } } // Add the changing element beyond the current scanline for the // other color too currChangingElems[currIndex++] = bitOffset; changingElemSize = currIndex; } else { // 1D encoded scanline follows decodeNextScanline(buffer, lineOffset, startX); } lineOffset += scanlineStride; } } public synchronized void decodeT6(byte[] buffer, byte[] compData, int startX, int height) { this.data = compData; int scanlineStride = (w + 7) / 8; bitPointer = 0; bytePointer = 0; int a0; int a1; int b1; int b2; int entry; int code; int bits; boolean isWhite; int currIndex; int[] temp; // Return values from getNextChangingElement int[] b = new int[2]; // uncompressedMode - have written some code for this, but this // has not been tested due to lack of test images using this optional // Local cached reference int[] cce = currChangingElems; // Assume invisible preceding row of all white pixels and insert // both black and white changing elements beyond the end of this // imaginary scanline. changingElemSize = 0; cce[changingElemSize++] = w; cce[changingElemSize++] = w; int lineOffset = 0; int bitOffset; for (int lines = 0; lines < height; lines++) { // a0 has to be set just before the start of the scanline. a0 = -1; isWhite = true; // Assign the changing elements of the previous scanline to // prevChangingElems and start putting this new scanline's // changing elements into the currChangingElems. temp = prevChangingElems; prevChangingElems = currChangingElems; cce = currChangingElems = temp; currIndex = 0; // Start decoding the scanline at startX in the raster bitOffset = startX; // Reset search start position for getNextChangingElement lastChangingElement = 0; // Till one whole scanline is decoded while (bitOffset < w) { // Get the next changing element getNextChangingElement(a0, isWhite, b); b1 = b[0]; b2 = b[1]; // Get the next seven bits entry = nextLesserThan8Bits(7); // Run these through the 2DCodes table entry = (twoDCodes[entry] & 0xff); // Get the code and the number of bits used up code = (entry & 0x78) >>> 3; bits = entry & 0x07; if (code == 0) { // Pass // We always assume WhiteIsZero format for fax. if (!isWhite) { if (b2 > w) { b2 = w; } setToBlack(buffer, lineOffset, bitOffset, b2 - bitOffset); } bitOffset = a0 = b2; // Set pointer to only consume the correct number of bits. updatePointer(7 - bits); } else if (code == 1) { // Horizontal // Set pointer to only consume the correct number of bits. updatePointer(7 - bits); // identify the next 2 alternating color codes. int number; if (isWhite) { // Following are white and black runs number = decodeWhiteCodeWord(); bitOffset += number; cce[currIndex++] = bitOffset; number = decodeBlackCodeWord(); if (number > w - bitOffset) { number = w - bitOffset; } setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; cce[currIndex++] = bitOffset; } else { // First a black run and then a white run follows number = decodeBlackCodeWord(); if (number > w - bitOffset) { number = w - bitOffset; } setToBlack(buffer, lineOffset, bitOffset, number); bitOffset += number; cce[currIndex++] = bitOffset; number = decodeWhiteCodeWord(); bitOffset += number; cce[currIndex++] = bitOffset; } a0 = bitOffset; } else if (code <= 8) { // Vertical a1 = b1 + (code - 5); cce[currIndex++] = a1; // We write the current color till a1 - 1 pos, // since a1 is where the next color starts if (!isWhite) { if (a1 > w) { a1 = w; } setToBlack(buffer, lineOffset, bitOffset, a1 - bitOffset); } bitOffset = a0 = a1; isWhite = !isWhite; updatePointer(7 - bits); } else if (code == 11) { if (nextLesserThan8Bits(3) != 7) { throw new RuntimeException( "Invalid code encountered while decoding 2D group 4 compressed data."); //$NON-NLS-1$ } int zeros = 0; boolean exit = false; while (!exit) { while (nextLesserThan8Bits(1) != 1) { zeros++; } if (zeros > 5) { // Exit code // Zeros before exit code zeros = zeros - 6; if (!isWhite && (zeros > 0)) { cce[currIndex++] = bitOffset; } // Zeros before the exit code bitOffset += zeros; if (zeros > 0) { // Some zeros have been written isWhite = true; } // Read in the bit which specifies the color of // the following run if (nextLesserThan8Bits(1) == 0) { if (!isWhite) { cce[currIndex++] = bitOffset; } isWhite = true; } else { if (isWhite) { cce[currIndex++] = bitOffset; } isWhite = false; } exit = true; } if (zeros == 5) { if (!isWhite) { cce[currIndex++] = bitOffset; } bitOffset += zeros; // Last thing written was white isWhite = true; } else { bitOffset += zeros; cce[currIndex++] = bitOffset; setToBlack(buffer, lineOffset, bitOffset, 1); ++bitOffset; // Last thing written was black isWhite = false; } } } else { // break line - seems to be a common failure // unread updatePointer(7 - bits); // and mark lines as complete bitOffset = w; // throw new RuntimeException( // "Invalid code encountered while decoding 2D group 4 // compressed data."); //$NON-NLS-1$ } } align(); // Add the changing element beyond the current scanline for the // other color too // make sure that the index does not exceed the bounds of the array if (currIndex <= w) { cce[currIndex++] = bitOffset; } // Number of changing elements in this scanline. changingElemSize = currIndex; lineOffset += scanlineStride; } } // Returns run length private int decodeWhiteCodeWord() { int current; int entry; int bits; int isT; int twoBits; int code = -1; int runLength = 0; boolean isWhite = true; while (isWhite) { current = nextNBits(10); entry = white[current]; // Get the 3 fields from the entry isT = entry & 0x0001; bits = (entry >>> 1) & 0x0f; if (bits == 12) { // Additional Make up code // Get the next 2 bits twoBits = nextLesserThan8Bits(2); // Consolidate the 2 new bits and last 2 bits into 4 bits current = ((current << 2) & 0x000c) | twoBits; entry = additionalMakeup[current]; bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 code = (entry >>> 4) & 0x0fff; // 12 bits runLength += code; updatePointer(4 - bits); } else if (bits == 0) { // ERROR throw new RuntimeException("Invalid code encountered."); //$NON-NLS-1$ } else if (bits == 15) { // EOL throw new RuntimeException( "EOL code word encountered in White run."); //$NON-NLS-1$ } else { // 11 bits - 0000 0111 1111 1111 = 0x07ff code = (entry >>> 5) & 0x07ff; runLength += code; updatePointer(10 - bits); if (isT == 0) { isWhite = false; } } } return runLength; } private void getNextChangingElement(int a0, boolean isWhite, int[] ret) { // Local copies of instance variables int[] pce = this.prevChangingElems; int ces = this.changingElemSize; // If the previous match was at an odd element, we still // have to search the preceeding element. // int start = lastChangingElement & ~0x1; int start = (lastChangingElement > 0) ? (lastChangingElement - 1) : 0; if (isWhite) { start &= ~0x1; // Search even numbered elements } else { start |= 0x1; // Search odd numbered elements } int i = start; for (; i < ces; i += 2) { int temp = pce[i]; if (temp > a0) { lastChangingElement = i; ret[0] = temp; break; } } if ((i + 1) < ces) { ret[1] = pce[i + 1]; } } public boolean isAlign() { return align; } public boolean isFillBits() { return fillBits; } private int nextLesserThan8Bits(int bitsToGet) { byte b; byte next; int l = data.length - 1; int bp = this.bytePointer; if (fillOrder == 1) { b = data[bp]; if (bp == l) { next = 0x00; } else { next = data[bp + 1]; } } else if (fillOrder == 2) { b = flipTable[data[bp] & 0xff]; if (bp == l) { next = 0x00; } else { next = flipTable[data[bp + 1] & 0xff]; } } else { throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ } int bitsLeft = 8 - bitPointer; int bitsFromNextByte = bitsToGet - bitsLeft; int shift = bitsLeft - bitsToGet; int i1; int i2; if (shift >= 0) { i1 = (b & table1[bitsLeft]) >>> shift; bitPointer += bitsToGet; if (bitPointer == 8) { bitPointer = 0; bytePointer++; } } else { i1 = (b & table1[bitsLeft]) << (-shift); i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); i1 |= i2; bytePointer++; bitPointer = bitsFromNextByte; } return i1; } private int nextNBits(int bitsToGet) { byte b; byte next; byte next2next; int l = data.length - 1; int bp = this.bytePointer; if (fillOrder == 1) { b = data[bp]; if (bp == l) { next = 0x00; next2next = 0x00; } else if ((bp + 1) == l) { next = data[bp + 1]; next2next = 0x00; } else { next = data[bp + 1]; next2next = data[bp + 2]; } } else if (fillOrder == 2) { b = flipTable[data[bp] & 0xff]; if (bp == l) { next = 0x00; next2next = 0x00; } else if ((bp + 1) == l) { next = flipTable[data[bp + 1] & 0xff]; next2next = 0x00; } else { next = flipTable[data[bp + 1] & 0xff]; next2next = flipTable[data[bp + 2] & 0xff]; } } else { throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ } int bitsLeft = 8 - bitPointer; int bitsFromNextByte = bitsToGet - bitsLeft; int bitsFromNext2NextByte = 0; if (bitsFromNextByte > 8) { bitsFromNext2NextByte = bitsFromNextByte - 8; bitsFromNextByte = 8; } bytePointer++; int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft); int i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); int i3 = 0; if (bitsFromNext2NextByte != 0) { i2 <<= bitsFromNext2NextByte; i3 = (next2next & table2[bitsFromNext2NextByte]) >>> (8 - bitsFromNext2NextByte); i2 |= i3; bytePointer++; bitPointer = bitsFromNext2NextByte; } else { if (bitsFromNextByte == 8) { bitPointer = 0; bytePointer++; } else { bitPointer = bitsFromNextByte; } } int i = i1 | i2; return i; } private int readEOL(boolean isFirstEOL) { // Seek to the next EOL. if (!seekEOL()) { throw new RuntimeException("EOL not found"); } if (!fillBits) { int next12Bits = nextNBits(12); if (isFirstEOL && (next12Bits == 0)) { // Might have the case of EOL padding being used even // though it was not flagged. // This was observed to be the case in TIFFs produced // by a well known vendor who shall remain nameless. if (nextNBits(4) == 1) { // EOL must be padded: reset the fillBits flag. fillBits = true; return 1; } } if (next12Bits != 1) { throw new RuntimeException( "Scanline must begin with EOL code word."); //$NON-NLS-1$ } } else { // First EOL code word xxxx 0000 0000 0001 will occur // As many fill bits will be present as required to make // the EOL code of 12 bits end on a byte boundary. int bitsLeft = 8 - bitPointer; if (nextNBits(bitsLeft) != 0) { throw new RuntimeException( "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ } // If the number of bitsLeft is less than 8, then to have a 12 // bit EOL sequence, two more bytes are certainly going to be // required. The first of them has to be all zeros, so ensure // that. if (bitsLeft < 4) { if (nextNBits(8) != 0) { throw new RuntimeException( "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ } } // // Some encoders under Group 3 Fax compression 1D writes TIFF // files without the fill bits, but say otherwise. // Need to check for this here. // int next8 = nextNBits(8); if (isFirstEOL && (next8 & 0xf0) == 0x10) { // // Fill bits are not actually used despite what the flag // says. So switch fillBits off and then rewind so that // only 12 bits have effectively been read. // fillBits = false; updatePointer(4); } else { // // This is the normal case. // There might be a random number of fill bytes with 0s, so // loop till the EOL of 0000 0001 is found, as long as all // the bytes preceding it are 0's. // while (next8 != 1) { // If not all zeros if (next8 != 0) { throw new RuntimeException("0 bits expected before EOL"); } next8 = nextNBits(8); } } } // The next one bit signifies 1D/2D encoding of next line. return nextLesserThan8Bits(1); } // Seeks to the next EOL in the compressed bitstream. // Returns 'true' if and only if an EOL is found; if 'false' // is returned it may be inferred that the EOF was reached first. private boolean seekEOL() { // Set maximum and current bit index into the compressed data. int bitIndexMax = data.length * 8 - 1; int bitIndex = bytePointer * 8 + bitPointer; // Loop while at least 12 bits are available. while (bitIndex <= bitIndexMax - 12) { // Get the next 12 bits. int next12Bits = nextNBits(12); bitIndex += 12; // Loop while the 12 bits are not unity, i.e., while the EOL // has not been reached, and there is at least one bit left. while (next12Bits != 1 && bitIndex < bitIndexMax) { next12Bits = ((next12Bits & 0x000007ff) << 1) | (nextLesserThan8Bits(1) & 0x00000001); bitIndex++; } // If EOL reached, rewind the pointers and return 'true'. if (next12Bits == 1) { updatePointer(12); return true; } } // EOL not found: return 'false'. return false; } public void setAlign(boolean align) { this.align = align; } public void setFillBits(boolean fillBits) { this.fillBits = fillBits; } private void setToBlack(byte[] buffer, int lineOffset, int bitOffset, int numBits) { int bitNum = (8 * lineOffset) + bitOffset; int lastBit = bitNum + numBits; int byteNum = bitNum >> 3; // Handle bits in first byte int shift = bitNum & 0x7; if (shift > 0) { int maskVal = 1 << (7 - shift); byte val = buffer[byteNum]; while ((maskVal > 0) && (bitNum < lastBit)) { val |= maskVal; maskVal >>= 1; ++bitNum; } buffer[byteNum] = val; } // Fill in 8 bits at a time byteNum = bitNum >> 3; while (bitNum < (lastBit - 7)) { buffer[byteNum++] = (byte) 255; bitNum += 8; } // Fill in remaining bits while (bitNum < lastBit) { byteNum = bitNum >> 3; buffer[byteNum] |= (1 << (7 - (bitNum & 0x7))); ++bitNum; } } // Move pointer backwards by given amount of bits private void updatePointer(int bitsToMoveBack) { if (bitsToMoveBack > 8) { bytePointer -= bitsToMoveBack / 8; bitsToMoveBack %= 8; } int i = bitPointer - bitsToMoveBack; if (i < 0) { bytePointer--; bitPointer = 8 + i; } else { bitPointer = i; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFTextFormat.java0000644000175000017500000002141711134132451023066 0ustar twernertwerner/* * $Id: PDFTextFormat.java,v 1.3 2009-01-16 16:26:11 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.Iterator; import java.util.List; import com.sun.pdfview.font.PDFFont; import com.sun.pdfview.font.PDFGlyph; /** * a class encapsulating the text state * @author Mike Wessler */ public class PDFTextFormat implements Cloneable { /** character spacing */ private float tc = 0; /** word spacing */ private float tw = 0; /** horizontal scaling */ private float th = 1; /** leading */ private float tl = 0; /** rise amount */ private float tr = 0; /** text mode */ private int tm = PDFShapeCmd.FILL; /** text knockout */ private float tk = 0; /** current matrix transform */ private AffineTransform cur; /** matrix transform at start of line */ private AffineTransform line; /** font */ private PDFFont font; /** font size */ private float fsize = 1; /** are we between BT and ET? */ private boolean inuse = false; // private Object array[]= new Object[1]; /** build text rep of word */ private StringBuffer word = new StringBuffer(); // this is where we build and keep the word list for this page. /** start location of the hunk of text */ private Point2D.Float wordStart; /** location of the end of the previous hunk of text */ private Point2D.Float prevEnd; /** * create a new PDFTextFormat, with initial values */ public PDFTextFormat() { cur = new AffineTransform(); line = new AffineTransform(); wordStart = new Point2D.Float(-100, -100); prevEnd = new Point2D.Float(-100, -100); tc = tw = tr = tk = 0; tm = PDFShapeCmd.FILL; th = 1; } /** * reset the PDFTextFormat for a new run */ public void reset() { cur.setToIdentity(); line.setToIdentity(); inuse = true; word.setLength(0); } /** * end a span of text */ public void end() { inuse = false; } /** get the char spacing */ public float getCharSpacing() { return tc; } /** set the character spacing */ public void setCharSpacing(float spc) { this.tc = spc; } /** get the word spacing */ public float getWordSpacing() { return tw; } /** set the word spacing */ public void setWordSpacing(float spc) { this.tw = spc; } /** * Get the horizontal scale * @return the horizontal scale, in percent */ public float getHorizontalScale() { return th * 100; } /** * set the horizontal scale. * @param scl the horizontal scale, in percent (100=normal) */ public void setHorizontalScale(float scl) { this.th = scl / 100; } /** get the leading */ public float getLeading() { return tl; } /** set the leading */ public void setLeading(float spc) { this.tl = spc; } /** get the font */ public PDFFont getFont() { return font; } /** get the font size */ public float getFontSize() { return fsize; } /** set the font and size */ public void setFont(PDFFont f, float size) { this.font = f; this.fsize = size; } /** * Get the mode of the text */ public int getMode() { return tm; } /** * set the mode of the text. The correspondence of m to mode is * show in the following table. m is a value from 0-7 in binary: * * 000 Fill * 001 Stroke * 010 Fill + Stroke * 011 Nothing * 100 Fill + Clip * 101 Stroke + Clip * 110 Fill + Stroke + Clip * 111 Clip * * Therefore: Fill corresponds to the low bit being 0; Clip * corresponds to the hight bit being 1; and Stroke corresponds * to the middle xor low bit being 1. */ public void setMode(int m) { int mode = 0; if ((m & 0x1) == 0) { mode |= PDFShapeCmd.FILL; } if ((m & 0x4) != 0) { mode |= PDFShapeCmd.CLIP; } if (((m & 0x1) ^ ((m & 0x2) >> 1)) != 0) { mode |= PDFShapeCmd.STROKE; } this.tm = mode; } /** * Set the mode from another text format mode * * @param mode the text render mode using the * codes from PDFShapeCmd and not the wacky PDF codes */ public void setTextFormatMode(int mode) { this.tm = mode; } /** * Get the rise */ public float getRise() { return tr; } /** * set the rise */ public void setRise(float spc) { this.tr = spc; } /** * perform a carriage return */ public void carriageReturn() { carriageReturn(0, -tl); } /** * perform a carriage return by translating by x and y. The next * carriage return will be relative to the new location. */ public void carriageReturn(float x, float y) { line.concatenate(AffineTransform.getTranslateInstance(x, y)); cur.setTransform(line); } /** * Get the current transform */ public AffineTransform getTransform() { return cur; } /** * set the transform matrix directly */ public void setMatrix(float[] matrix) { line = new AffineTransform(matrix); cur.setTransform(line); } /** * add some text to the page. * @param cmds the PDFPage to add the commands to * @param text the text to add */ public void doText(PDFPage cmds, String text) { Point2D.Float zero = new Point2D.Float(); AffineTransform scale = new AffineTransform(fsize, 0, 0, fsize * th, 0, tr); AffineTransform at = new AffineTransform(); List l = font.getGlyphs(text); for (Iterator i = l.iterator(); i.hasNext();) { PDFGlyph glyph = (PDFGlyph) i.next(); at.setTransform(cur); at.concatenate(scale); Point2D advance = glyph.addCommands(cmds, at, tm); double advanceX = (advance.getX() * fsize) + tc; if (glyph.getChar() == ' ') { advanceX += tw; } advanceX *= th; cur.translate(advanceX, advance.getY()); } cur.transform(zero, prevEnd); } /** * add some text to the page. * @param cmds the PDFPage to add the commands to * @param ary an array of Strings and Doubles, where the Strings * represent text to be added, and the Doubles represent kerning * amounts. */ public void doText(PDFPage cmds, Object ary[]) throws PDFParseException { for (int i = 0; i < ary.length; i++) { if (ary[i] instanceof String) { doText(cmds, (String) ary[i]); } else if (ary[i] instanceof Double) { float val = ((Double) ary[i]).floatValue() / 1000f; cur.translate(-val * fsize * th, 0); } else { throw new PDFParseException("Bad element in TJ array"); } } } /** * finish any unfinished words. TODO: write this! */ public void flush() { // TODO: finish any unfinished words } /** * Clone the text format */ @Override public Object clone() { PDFTextFormat newFormat = new PDFTextFormat(); // copy values newFormat.setCharSpacing(getCharSpacing()); newFormat.setWordSpacing(getWordSpacing()); newFormat.setHorizontalScale(getHorizontalScale()); newFormat.setLeading(getLeading()); newFormat.setTextFormatMode(getMode()); newFormat.setRise(getRise()); // copy immutable fields newFormat.setFont(getFont(), getFontSize()); // clone transform (mutable) // newFormat.getTransform().setTransform(getTransform()); return newFormat; } } pdfrenderer-0.9.0/src/com/sun/pdfview/pattern/0000755000175000017500000000000011622545441021255 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/pattern/PDFPattern.java0000644000175000017500000000756010732532577024106 0ustar twernertwerner/* * $Id: PDFPattern.java,v 1.3 2007-12-20 18:33:30 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.pattern; import java.awt.geom.AffineTransform; import java.io.IOException; import java.util.Map; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.PDFParseException; /** * The abstract superclass of all PDF Pattern types * */ public abstract class PDFPattern { /** the pattern type (1 or 2) */ private int type; /** the matrix to transform from pattern space to PDF space */ private AffineTransform xform; /** Creates a new instance of PDFPattern */ protected PDFPattern(int type) { this.type = type; } /** * Read a pattern from the given pattern stream */ public static PDFPattern getPattern(PDFObject patternObj, Map resources) throws IOException { // see if the pattern is already cached PDFPattern pattern = (PDFPattern) patternObj.getCache(); if (pattern != null) { return pattern; } // get the pattern type int type = patternObj.getDictRef("PatternType").getIntValue(); // read the pattern transform matrix PDFObject matrix = patternObj.getDictRef("Matrix"); AffineTransform xform = null; if (matrix == null) { xform = new AffineTransform(); } else { float elts[]= new float[6]; for (int i = 0; i < elts.length; i++) { elts[i] = ((PDFObject) matrix.getAt(i)).getFloatValue(); } xform = new AffineTransform(elts); } switch (type) { case 1: pattern = new PatternType1(); break; default: throw new PDFParseException("Unknown pattern type " + type); } // set the transform pattern.setTransform(xform); // parse the pattern-specific data pattern.parse(patternObj, resources); // set the cache patternObj.setCache(pattern); return pattern; } /** * Get the type of this pattern */ public int getPatternType() { return type; } /** * Get the transform associated with this pattern */ public AffineTransform getTransform() { return xform; } /** * Set the transform associated with this pattern */ protected void setTransform(AffineTransform xform) { this.xform = xform; } /** * Parse the pattern-specific information from the pdf object * * @param patternObj the pdfobject with data for this pattern */ protected abstract void parse(PDFObject patternObj, Map resources) throws IOException; /** * Returns paint that represents the selected pattern * * @param basePaint the background paint color, or null for none */ public abstract PDFPaint getPaint(PDFPaint basePaint); } pdfrenderer-0.9.0/src/com/sun/pdfview/pattern/PatternType1.java0000644000175000017500000003244111376323412024462 0ustar twernertwerner/* * $Id: PatternType1.java,v 1.4 2010-05-23 22:07:06 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.pattern; import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.PaintContext; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.sun.pdfview.*; /** * A type 1 (tiling) pattern */ public class PatternType1 extends PDFPattern { /** paint types */ public static final int PAINT_COLORED = 1; public static final int PAINT_UNCOLORED = 2; /** tiling types */ public static final int TILE_CONSTANT = 1; public static final int TILE_NODISTORT = 2; public static final int TILE_FASTER = 3; /** the resources used by the image we will tile */ private HashMap resources; /** the paint type (colored or uncolored) */ private int paintType; /** the tiling type (constant, no distort or faster) */ private int tilingType; /** the bounding box of the tile, in tile space */ private Rectangle2D bbox; /** the horiztonal tile spacing, in tile space */ private int xStep; /** the vertical spacing, in tile space */ private int yStep; /** the stream data */ private byte[] data; /** Creates a new instance of PatternType1 */ public PatternType1() { super(1); } /** * Parse the pattern from the PDFObject * * Note the resources passed in are ignored... */ protected void parse(PDFObject patternObj, Map rsrc) throws IOException { data = patternObj.getStream(); resources = patternObj.getDictRef("Resources").getDictionary(); paintType = patternObj.getDictRef("PaintType").getIntValue(); tilingType = patternObj.getDictRef("TilingType").getIntValue(); bbox = PDFFile.parseNormalisedRectangle(patternObj.getDictRef("BBox")); xStep = patternObj.getDictRef("XStep").getIntValue(); yStep = patternObj.getDictRef("YStep").getIntValue(); } /** * Create a PDFPaint from this pattern and set of components. * This creates a buffered image of this pattern using * the given paint, then uses that image to create the correct * TexturePaint to use in the PDFPaint. * * @param basePaint the base paint to use, or null if not needed */ public PDFPaint getPaint(PDFPaint basePaint) { // create the outline of the pattern in user space by creating // a box with width xstep and height ystep. Transform that // box using the pattern's matrix to get the user space // bounding box Rectangle2D anchor = new Rectangle2D.Double(getBBox().getMinX(), getBBox().getMinY(), getXStep(), getYStep()); //anchor = getTransform().createTransformedShape(anchor).getBounds2D(); // now create a page bounded by the pattern's user space size final PDFPage page = new PDFPage(getBBox(), 0); // set the base paint if there is one if (basePaint != null) { page.addFillPaint(basePaint); page.addStrokePaint(basePaint); } // undo the page's transform to user space /* AffineTransform xform = new AffineTransform(1, 0, 0, -1, 0, getYStep()); //new AffineTransform(1, 0, 0, -1, 0, getBBox().getHeight()); page.addXform(xform); */ // now parse the pattern contents PDFParser prc = new PDFParser(page, data, getResources()); prc.go(true); int width = (int) getBBox().getWidth(); int height = (int) getBBox().getHeight(); // get actual image Paint paint = new Paint() { public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) { ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); ColorModel model = new ComponentColorModel(cs, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); Rectangle2D devBBox = xform.createTransformedShape(getBBox()).getBounds2D(); double[] steps = new double[] { getXStep(), getYStep() }; xform.deltaTransform(steps, 0, steps, 0, 1); int width = (int) Math.ceil(devBBox.getWidth()); int height = (int) Math.ceil(devBBox.getHeight()); BufferedImage img = (BufferedImage) page.getImage(width, height, null, null, false, true); return new Type1PaintContext(model, devBBox, (float) steps[0], (float) steps[1], img.getData()); } public int getTransparency() { return Transparency.TRANSLUCENT; } }; return new TilingPatternPaint(paint, this); } /** get the associated resources */ public HashMap getResources() { return resources; } /** get the paint type */ public int getPaintType() { return paintType; } /** get the tiling type */ public int getTilingType() { return tilingType; } /** get the bounding box */ public Rectangle2D getBBox() { return bbox; } /** get the x step */ public int getXStep() { return xStep; } /** get the y step */ public int getYStep() { return yStep; } /** * This class overrides PDFPaint to paint in the pattern coordinate space */ class TilingPatternPaint extends PDFPaint { /** the pattern to paint */ private PatternType1 pattern; /** Create a tiling pattern paint */ public TilingPatternPaint(Paint paint, PatternType1 pattern) { super (paint); this.pattern = pattern; } /** * fill a path with the paint, and record the dirty area. * @param state the current graphics state * @param g the graphics into which to draw * @param s the path to fill * @param drawn a Rectangle2D into which the dirty area (area drawn) * will be added. */ public Rectangle2D fill(PDFRenderer state, Graphics2D g, GeneralPath s) { // first transform s into device space AffineTransform at = g.getTransform(); Shape xformed = s.createTransformedShape(at); // push the graphics state so we can restore it state.push(); // set the transform to be the inital transform concatentated // with the pattern matrix state.setTransform(state.getInitialTransform()); state.transform(pattern.getTransform()); // now figure out where the shape should be try { at = state.getTransform().createInverse(); } catch (NoninvertibleTransformException nte) { // oh well (?) } xformed = at.createTransformedShape(xformed); // set the paint and draw the xformed shape g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); g.setPaint(getPaint()); g.fill(xformed); // restore the graphics state state.pop(); // return the area changed return s.createTransformedShape(g.getTransform()).getBounds2D(); } } /** * A simple paint context that uses an existing raster in device * space to generate pixels */ class Type1PaintContext implements PaintContext { /** the color model */ private ColorModel colorModel; /** the anchor box */ private Rectangle2D bbox; /** the x offset */ private float xstep; /** the y offset */ private float ystep; /** the image data, as a raster in device coordinates */ private Raster data; /** * Create a paint context */ Type1PaintContext(ColorModel colorModel, Rectangle2D bbox, float xstep, float ystep, Raster data) { this.colorModel = colorModel; this.bbox = bbox; this.xstep = xstep; this.ystep = ystep; this.data = data; } public void dispose() { colorModel = null; bbox = null; data = null; } public ColorModel getColorModel() { return colorModel; } public Raster getRaster(int x, int y, int w, int h) { ColorSpace cs = getColorModel().getColorSpace(); int numComponents = cs.getNumComponents(); // all the data, plus alpha channel int[] imgData = new int[w * h * (numComponents + 1)]; // the x and y step, as ints int useXStep = (int) Math.ceil(Math.abs(xstep)); int useYStep = (int) Math.ceil(Math.abs(ystep)); // a completely transparent pixel (alpha of 0) int[] emptyPixel = new int[numComponents + 1]; int[] usePixel = new int[numComponents + 1]; // for each device coordinate for (int j = 0; j < h; j++) { for (int i = 0; i < w; i ++) { // figure out what pixel we are at relative to the image int xloc = (x + i) - (int) Math.ceil(bbox.getX()); int yloc = (y + j) - (int) Math.ceil(bbox.getY()); xloc %= useXStep; yloc %= useYStep; if (xloc < 0) { xloc = useXStep + xloc; } if (yloc < 0) { yloc = useYStep + yloc; } int[] pixel = emptyPixel; // check if we are inside the image if (xloc < data.getWidth() && yloc < data.getHeight()) { pixel = data.getPixel(xloc, yloc, usePixel); } int base = (j * w + i) * (numComponents + 1); for (int c = 0; c < pixel.length; c++) { imgData[base + c] = pixel[c]; } } } WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h); raster.setPixels(0, 0, w, h, imgData); Raster child = raster.createTranslatedChild(x, y); return child; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/pattern/PDFShader.java0000644000175000017500000001674711376323412023675 0ustar twernertwerner/* * $Id: PDFShader.java,v 1.4 2010-05-23 22:07:06 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.pattern; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.Map; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.colorspace.PDFColorSpace; /** *

A PDFShader fills a given region with a shading, such as a gradient.

* *

* Shading Dictionaries (section 4.6)
* A shading dictionary specifies details of a particular gradient fill, * including the type of shading to be used, the geometry of the area to * be shaded, and the geometry of the gradient fill. Various shading types * are available, depending on the value of the dictionary’s ShadingType entry: * *

  • Function-based shadings (type 1) define the color of every point in the * domain using a mathematical function (not necessarily smooth or continuous).
  • * *
  • Axial shadings (type 2) define a color blend along a line between two * points, optionally extended beyond the boundary points by continuing * the boundary colors.
  • * *
  • Radial shadings (type 3) define a blend between two circles, * optionally extended beyond the boundary circles by continuing the * boundary colors. This type of shading is commonly used to represent * three-dimensional spheres and cones.
  • * *
  • Free-form Gouraud-shaded triangle meshes (type 4) define a * common construct used by many three-dimensional applications to * represent complex colored and shaded shapes. Vertices are specified * in free-form geometry.
  • * *
  • Lattice-form Gouraud-shaded triangle meshes (type 5) are based on * the same geometrical construct as type 4 but with vertices specified * as a pseudorectangular lattice.
  • * *
  • Coons patch meshes (type 6) construct a shading from one or more * color patches, each bounded by four cubic Bézier curves.
  • * *
  • Tensor-product patch meshes (type 7) are similar to type 6 but * with additional control points in each patch, affording greater * control over color mapping.
  • * * Table 4.28 shows the entries that all shading dictionaries share * in common; entries specific to particular shading types are * described in the relevant sections below.

    */ public abstract class PDFShader { public final static int FUNCTION_SHADING = 1; public final static int AXIAL_SHADING = 2; public final static int RADIAL_SHADING = 3; public final static int FREE_FORM_SHADING = 4; public final static int LATTICE_SHADING = 5; public final static int COONS_PATCH_MESH_SHADING = 6; public final static int TENSOR_PRODUCTS_MESH_SHADING = 7; /** the type of the shading (1 through 7)*/ private int type; /** the colorspace */ private PDFColorSpace colorSpace; /** the background color */ private PDFPaint background; /** the bounding box of the pattern */ private Rectangle2D bbox; /** Creates a new instance of PDFShader */ protected PDFShader(int type) { this.type = type; } /** * Parse a pdf shader into a shader object */ public static PDFShader getShader(PDFObject shaderObj, Map resources) throws IOException { // first see if the shader is already cached PDFShader shader = (PDFShader) shaderObj.getCache(); if (shader != null) { return shader; } // read the type (required) PDFObject typeObj = shaderObj.getDictRef("ShadingType"); if (typeObj == null) { throw new PDFParseException("No shader type defined!"); } int type = typeObj.getIntValue(); // create the shader switch (type) { case AXIAL_SHADING: shader = new ShaderType2(); break; case FUNCTION_SHADING: case RADIAL_SHADING: case FREE_FORM_SHADING: case LATTICE_SHADING: case COONS_PATCH_MESH_SHADING: case TENSOR_PRODUCTS_MESH_SHADING: default: throw new PDFParseException("Unsupported shader type: " + type); } // read the color space (required) PDFObject csObj = shaderObj.getDictRef("ColorSpace"); if (csObj == null) { throw new PDFParseException("No colorspace defined!"); } PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); shader.setColorSpace(cs); // read the background color (optional) PDFObject bgObj = shaderObj.getDictRef("Background"); if (bgObj != null) { PDFObject[] bgObjs = bgObj.getArray(); float[] bgArray = new float[bgObjs.length]; for (int i = 0; i < bgArray.length; i++) { bgArray[i] = bgObjs[i].getFloatValue(); } PDFPaint paint = cs.getPaint(bgArray); shader.setBackground(paint); } // read the bounding box (optional) PDFObject bboxObj = shaderObj.getDictRef("BBox"); if (bboxObj != null) { shader.setBBox(PDFFile.parseNormalisedRectangle(bboxObj)); } // parse the shader-specific attributes shader.parse(shaderObj); // set the cache shaderObj.setCache(shader); return shader; } /** * Get the type */ public int getType() { return type; } /** * Get the color space */ public PDFColorSpace getColorSpace() { return colorSpace; } /** * Set the color space */ protected void setColorSpace(PDFColorSpace colorSpace) { this.colorSpace = colorSpace; } /** * Get the background color */ public PDFPaint getBackground() { return background; } /** * Set the background color */ protected void setBackground(PDFPaint background) { this.background = background; } /** * Get the bounding box */ public Rectangle2D getBBox() { return bbox; } /** * Set the bounding box */ protected void setBBox(Rectangle2D bbox) { this.bbox = bbox; } /** * Parse the shader-specific data */ public abstract void parse(PDFObject shareObj) throws IOException; /** * Returns paint that represents the selected shader */ public abstract PDFPaint getPaint(); } pdfrenderer-0.9.0/src/com/sun/pdfview/pattern/ShaderType2.java0000644000175000017500000002656110732532577024273 0ustar twernertwerner/* * $Id: ShaderType2.java,v 1.2 2007-12-20 18:33:30 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.pattern; import java.awt.Paint; import java.awt.PaintContext; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.function.PDFFunction; /** * A shader that performs axial shader based on a function. */ public class ShaderType2 extends PDFShader { /** the start of the axis */ private Point2D axisStart; /** the end of the axis */ private Point2D axisEnd; /** the domain minimum */ private float minT = 0f; /** the domain maximum */ private float maxT = 1f; /** whether to extend the start of the axis */ private boolean extendStart = false; /** whether to extend the end of the axis */ private boolean extendEnd = false; /** functions, as an array of either 1 or n functions */ private PDFFunction[] functions; /** Creates a new instance of ShaderType2 */ public ShaderType2() { super(2); } /** * Parse the shader-specific data */ public void parse(PDFObject shaderObj) throws IOException { // read the axis coordinates (required) PDFObject coordsObj = shaderObj.getDictRef("Coords"); if (coordsObj == null) { throw new PDFParseException("No coordinates found!"); } PDFObject[] coords = coordsObj.getArray(); Point2D start = new Point2D.Float(coords[0].getFloatValue(), coords[1].getFloatValue()); Point2D end = new Point2D.Float(coords[2].getFloatValue(), coords[3].getFloatValue()); setAxisStart(start); setAxisEnd(end); // read the domain (optional) PDFObject domainObj = shaderObj.getDictRef("Domain"); if (domainObj != null) { PDFObject[] domain = domainObj.getArray(); setMinT(domain[0].getFloatValue()); setMaxT(domain[1].getFloatValue()); } // read the functions (required) PDFObject functionObj = shaderObj.getDictRef("Function"); if (functionObj == null) { throw new PDFParseException("No function defined for shader!"); } PDFObject[] functionArray = functionObj.getArray(); PDFFunction[] functions = new PDFFunction[functionArray.length]; for (int i = 0; i < functions.length; i++) { functions[i] = PDFFunction.getFunction(functionArray[i]); } setFunctions(functions); // read the extend array (optional) PDFObject extendObj = shaderObj.getDictRef("Extend"); if (extendObj != null) { PDFObject[] extendArray = extendObj.getArray(); setExtendStart(extendArray[0].getBooleanValue()); setExtendEnd(extendArray[1].getBooleanValue()); } } /** * Create a paint that paints this pattern */ public PDFPaint getPaint() { return PDFPaint.getPaint(new Type2Paint()); } /** * Get the start of the axis */ public Point2D getAxisStart() { return axisStart; } /** * Set the start of the axis */ protected void setAxisStart(Point2D axisStart) { this.axisStart = axisStart; } /** * Get the end of the axis */ public Point2D getAxisEnd() { return axisEnd; } /** * Set the start of the axis */ protected void setAxisEnd(Point2D axisEnd) { this.axisEnd = axisEnd; } /** * Get the domain minimum */ public float getMinT() { return minT; } /** * Set the domain minimum */ protected void setMinT(float minT) { this.minT = minT; } /** * Get the domain maximum */ public float getMaxT() { return maxT; } /** * Set the domain maximum */ protected void setMaxT(float maxT) { this.maxT = maxT; } /** * Get whether to extend the start of the axis */ public boolean getExtendStart() { return extendStart; } /** * Set whether to extend the start of the axis */ protected void setExtendStart(boolean extendStart) { this.extendStart = extendStart; } /** * Get whether to extend the end of the axis */ public boolean getExtendEnd() { return extendEnd; } /** * Set whether to extend the end of the axis */ protected void setExtendEnd(boolean extendEnd) { this.extendEnd = extendEnd; } /** * Get the functions associated with this shader */ public PDFFunction[] getFunctions() { return functions; } /** * Set the functions associated with this shader */ protected void setFunctions(PDFFunction[] functions) { this.functions = functions; } /** * A subclass of paint that uses this shader to generate a paint */ class Type2Paint implements Paint { public Type2Paint() { } /** create a paint context */ public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) { ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); ColorModel model = new ComponentColorModel(cs, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); Point2D devStart = xform.transform(getAxisStart(), null); Point2D devEnd = xform.transform(getAxisEnd(), null); return new Type2PaintContext(model, devStart, devEnd); } public int getTransparency() { return Transparency.TRANSLUCENT; } } /** * A simple paint context that uses an existing raster in device * space to generate pixels */ class Type2PaintContext implements PaintContext { /** the color model */ private ColorModel colorModel; /** the start of the axis */ private Point2D start; /** the end of the axis */ private Point2D end; /** * Create a paint context */ Type2PaintContext(ColorModel colorModel, Point2D start, Point2D end) { this.colorModel = colorModel; this.start = start; this.end = end; } public void dispose() { colorModel = null; } public ColorModel getColorModel() { return colorModel; } public Raster getRaster(int x, int y, int w, int h) { ColorSpace cs = getColorModel().getColorSpace(); PDFFunction functions[] = getFunctions(); int numComponents = cs.getNumComponents(); float x0 = (float) start.getX(); float x1 = (float) end.getX(); float y0 = (float) start.getY(); float y1 = (float) end.getY(); float[] inputs = new float[1]; float[] outputs = new float[numComponents]; // all the data, plus alpha channel int[] data = new int[w * h * (numComponents + 1)]; // for each device coordinate for (int j = 0; j < h; j++) { for (int i = 0; i < w + 8; i += 8) { // find t for that user coordinate float xp = getXPrime(i + x, j + y, x0, y0, x1, y1); float t = getT(xp); // calculate the pixel values at t inputs[0] = t; if (functions.length == 1) { functions[0].calculate(inputs, 0, outputs, 0); } else { for (int c = 0; c < functions.length; c++) { functions[c].calculate(inputs, 0, outputs, c); } } for (int q = i; q < i + 8 && q < w; q++) { int base = (j * w + q) * (numComponents + 1); for (int c = 0; c < numComponents; c++) { data[base + c] = (int) (outputs[c] * 255); } data[base + numComponents] = 255; } } } WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h); raster.setPixels(0, 0, w, h, data); Raster child = raster.createTranslatedChild(x, y); return child; } /** * x' = (x1 - x0) * (x - x0) + (y1 - y0) * (y - y0) * ------------------------------------------- * (x1 - x0)^2 + (y1 - y0)^2 */ private float getXPrime(float x, float y, float x0, float y0, float x1, float y1) { double tp = (((x1 - x0) * (x - x0)) + ((y1 - y0) * (y - y0))) / (Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)); return (float) tp; } /** * t = t0 + (t1 - t0) x x' */ private float getT(float xp) { float t0 = getMinT(); float t1 = getMaxT(); if (xp < 0) { return t0; } else if (xp > 1) { return t1; } else { return t0 + ((t1 - t0) * xp); } } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFImage.java0000644000175000017500000010233311576205374022027 0ustar twernertwerner/* * $Id: PDFImage.java,v 1.12 2010-06-14 17:32:09 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.Color; import java.awt.Point; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.color.ICC_ColorSpace; import java.awt.image.*; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import com.sun.pdfview.colorspace.IndexedColor; import com.sun.pdfview.colorspace.PDFColorSpace; import com.sun.pdfview.decode.PDFDecoder; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; import javax.imageio.metadata.IIOMetadata; /** * Encapsulates a PDF Image */ public class PDFImage { public static void dump(PDFObject obj) throws IOException { p("dumping PDF object: " + obj); if (obj == null) { return; } HashMap dict = obj.getDictionary(); p(" dict = " + dict); for (Object key : dict.keySet()) { p("key = " + key + " value = " + dict.get(key)); } } public static void p(String string) { System.out.println(string); } private static int[][] GREY_TO_ARGB = new int[8][]; private static int[] getGreyToArgbMap(int numBits) { assert numBits <= 8; int[] argbVals = GREY_TO_ARGB[numBits - 1]; if (argbVals == null) { argbVals = createGreyToArgbMap(numBits); } return argbVals; } /** * Create a map from all bit-patterns of a certain depth greyscale to the * corresponding sRGB values via the ICC colorr converter. * @param numBits the number of greyscale bits * @return a 2^bits array of standard 32-bit ARGB fits for each greyscale value * at that bitdepth */ private static int[] createGreyToArgbMap(int numBits) { final ColorSpace greyCs = PDFColorSpace.getColorSpace( PDFColorSpace.COLORSPACE_GRAY).getColorSpace(); byte[] greyVals = new byte[1 << numBits]; for (int i = 0; i < greyVals.length; ++i) { greyVals[i] = (byte) (i & 0xFF); } final int[] argbVals = new int[greyVals.length]; final int mask = (1 << numBits) - 1; final WritableRaster inRaster = Raster.createPackedRaster( new DataBufferByte( greyVals, greyVals.length), greyVals.length, 1, greyVals.length, new int[] {mask}, null); final BufferedImage greyImage = new BufferedImage( new PdfComponentColorModel( greyCs, new int[] {numBits}), inRaster, false, null); final ColorModel ccm = ColorModel.getRGBdefault(); final WritableRaster outRaster = Raster.createPackedRaster( new DataBufferInt( argbVals, argbVals.length), argbVals.length, 1, argbVals.length, ((PackedColorModel)ccm).getMasks(), null); final BufferedImage srgbImage = new BufferedImage( ccm, outRaster, false, null); final ColorConvertOp op = new ColorConvertOp( greyCs, ColorSpace.getInstance(ColorSpace.CS_sRGB), null); op.filter(greyImage, srgbImage); GREY_TO_ARGB[numBits - 1] = argbVals; return argbVals; } /** color key mask. Array of start/end pairs of ranges of color components to * mask out. If a component falls within any of the ranges it is clear. */ private int[] colorKeyMask = null; /** the width of this image in pixels */ private int width; /** the height of this image in pixels */ private int height; /** the colorspace to interpret the samples in */ private PDFColorSpace colorSpace; /** the number of bits per sample component */ private int bpc; /** whether this image is a mask or not */ private boolean imageMask = false; /** the SMask image, if any */ private PDFImage sMask; /** the decode array */ private float[] decode; private float[] decodeMins; private float[] decodeCoefficients; /** the actual image data */ private PDFObject imageObj; /** * Create an instance of a PDFImage */ protected PDFImage(PDFObject imageObj) { this.imageObj = imageObj; } /** * Read a PDFImage from an image dictionary and stream * * @param obj the PDFObject containing the image's dictionary and stream * @param resources the current resources */ public static PDFImage createImage(PDFObject obj, Map resources) throws IOException { // create the image PDFImage image = new PDFImage(obj); // get the width (required) PDFObject widthObj = obj.getDictRef("Width"); if (widthObj == null) { throw new PDFParseException("Unable to read image width: " + obj); } image.setWidth(widthObj.getIntValue()); // get the height (required) PDFObject heightObj = obj.getDictRef("Height"); if (heightObj == null) { throw new PDFParseException("Unable to get image height: " + obj); } image.setHeight(heightObj.getIntValue()); // figure out if we are an image mask (optional) PDFObject imageMaskObj = obj.getDictRef("ImageMask"); if (imageMaskObj != null) { image.setImageMask(imageMaskObj.getBooleanValue()); } // read the bpc and colorspace (required except for masks) if (image.isImageMask()) { image.setBitsPerComponent(1); // create the indexed color space for the mask // [PATCHED by michal.busta@gmail.com] - default value od Decode according to PDF spec. is [0, 1] // so the color arry should be: Color[] colors = {Color.BLACK, Color.WHITE}; PDFObject imageMaskDecode = obj.getDictRef("Decode"); if (imageMaskDecode != null) { PDFObject[] array = imageMaskDecode.getArray(); float decode0 = array[0].getFloatValue(); if (decode0 == 1.0f) { colors = new Color[]{Color.WHITE, Color.BLACK}; } } image.setColorSpace(new IndexedColor(colors)); } else { // get the bits per component (required) PDFObject bpcObj = obj.getDictRef("BitsPerComponent"); if (bpcObj == null) { throw new PDFParseException("Unable to get bits per component: " + obj); } image.setBitsPerComponent(bpcObj.getIntValue()); // get the color space (required) PDFObject csObj = obj.getDictRef("ColorSpace"); if (csObj == null) { throw new PDFParseException("No ColorSpace for image: " + obj); } PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj, resources); image.setColorSpace(cs); } // read the decode array PDFObject decodeObj = obj.getDictRef("Decode"); if (decodeObj != null) { PDFObject[] decodeArray = decodeObj.getArray(); float[] decode = new float[decodeArray.length]; for (int i = 0; i < decodeArray.length; i++) { decode[i] = decodeArray[i].getFloatValue(); } image.setDecode(decode); } // read the soft mask. // If ImageMask is true, this entry must not be present. // (See implementation note 52 in Appendix H.) if (imageMaskObj == null) { PDFObject sMaskObj = obj.getDictRef("SMask"); if (sMaskObj == null) { // try the explicit mask, if there is no SoftMask sMaskObj = obj.getDictRef("Mask"); } if (sMaskObj != null) { if (sMaskObj.getType() == PDFObject.STREAM) { try { PDFImage sMaskImage = PDFImage.createImage(sMaskObj, resources); image.setSMask(sMaskImage); } catch (IOException ex) { p("ERROR: there was a problem parsing the mask for this object"); dump(obj); ex.printStackTrace(System.out); } } else if (sMaskObj.getType() == PDFObject.ARRAY) { // retrieve the range of the ColorKeyMask // colors outside this range will not be painted. try { image.setColorKeyMask(sMaskObj); } catch (IOException ex) { p("ERROR: there was a problem parsing the color mask for this object"); dump(obj); ex.printStackTrace(System.out); } } } } return image; } /** * Get the image that this PDFImage generates. * * @return a buffered image containing the decoded image data */ public BufferedImage getImage() { try { BufferedImage bi = (BufferedImage) imageObj.getCache(); if (bi == null) { byte[] data = null; ByteBuffer jpegBytes = null; final boolean jpegDecode = PDFDecoder.isLastFilter(imageObj, PDFDecoder.DCT_FILTERS); if (jpegDecode) { // if we're lucky, the stream will have just the DCT // filter applied to it, and we'll have a reference to // an underlying mapped file, so we'll manage to avoid // a copy of the encoded JPEG bytes jpegBytes = imageObj.getStreamBuffer(PDFDecoder.DCT_FILTERS); } else { data = imageObj.getStream(); } // parse the stream data into an actual image bi = parseData(data, jpegBytes); imageObj.setCache(bi); } // if(bi != null) // ImageIO.write(bi, "png", new File("/tmp/test/" + System.identityHashCode(this) + ".png")); return bi; } catch (IOException ioe) { System.out.println("Error reading image"); ioe.printStackTrace(); return null; } } /** *

    Parse the image stream into a buffered image. Note that this is * guaranteed to be called after all the other setXXX methods have been * called.

    * *

    NOTE: the color convolving is extremely slow on large images. * It would be good to see if it could be moved out into the rendering * phases, where we might be able to scale the image down first.

    RGB // transformation when reading JPEGs does not adhere to the spec. // We're just going to let JAI read this in - as it is, JAI looks // for the specific Adobe marker header so that it may apply // the transform, so that's good. If that marker isn't present, // then it also applies a number of other heuristics to determine // whether the transform should be applied. // (http://java.sun.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html) // In practice, it probably almost always does the right thing here, // though note that the present or default value of the ColorTransform // dictionary entry is not being observed, so there is scope for // error final ImageReader jpegReader = ImageIO.getImageReadersByFormatName("jpeg").next(); jpegReader.setInput(ImageIO.createImageInputStream( new ByteBufferInputStream(jpegData)), true, false); if (getDecode() != null) { // we have to allocate our own buffered image so that we can // install our colour model which will do the desired decode ImageReadParam param = new ImageReadParam(); SampleModel sm = cm.createCompatibleSampleModel (getWidth (), getHeight ()); final WritableRaster raster = Raster.createWritableRaster(sm, new Point(0, 0)); param.setDestination(new BufferedImage(cm, raster, true, null)); bi = jpegReader.read(0, param); // since jpegData may be quite a substantial array, and we might // need to create another substantial array later, we'll try // and make it unreachable as quickly as possible jpegData = null; } else { // if we don't need to decode samples then this is much // faster, though I couldn't say why. bi = new BufferedImage( cm, jpegReader.read(0).getRaster(), true, null); } } else { DataBuffer db = new DataBufferByte(data, data.length); // create a compatible raster SampleModel sm = cm.createCompatibleSampleModel (getWidth (), getHeight ()); WritableRaster raster; try { raster = Raster.createWritableRaster (sm, db, new Point (0, 0)); } catch (RasterFormatException e) { // this here seems a bit on the odd side. Is this really required, // or was it compensating for an old bug? int calculatedLineBits = getWidth() * getColorSpace().getNumComponents() * getBitsPerComponent(); int calculatedLineBytes = (calculatedLineBits + 7 / 8); int calculatedBytes = calculatedLineBytes * getHeight(); if (calculatedBytes > data.length) { byte[] tempLargerData = new byte[calculatedBytes]; System.arraycopy (data, 0, tempLargerData, 0, data.length); db = new DataBufferByte (tempLargerData, calculatedBytes); raster = Raster.createWritableRaster(sm, db, new Point(0, 0)); } else { throw e; } } /* * Workaround for a bug on the Mac -- a class cast exception in * drawImage() due to the wrong data buffer type (?) */ if (cm instanceof IndexColorModel) { IndexColorModel icm = (IndexColorModel) cm; // choose the image type based on the size int type = BufferedImage.TYPE_BYTE_BINARY; if (getBitsPerComponent() == 8) { type = BufferedImage.TYPE_BYTE_INDEXED; } // create the image with an explicit indexed color model. bi = new BufferedImage(getWidth(), getHeight(), type, icm); // set the data explicitly as well bi.setData(raster); } else { bi = new BufferedImage(cm, raster, true, null); } } ColorSpace cs = cm.getColorSpace(); ColorSpace rgbCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); if (isGreyscale(cs) && bpc <= 8 && getDecode() == null && jpegData == null) { bi = convertGreyscaleToArgb(data, bi); } else if (!isImageMask() && cs instanceof ICC_ColorSpace && !cs.equals(rgbCS)) { // hack to avoid *very* slow conversion // - this speeds things up? It's still pretty slow. ColorConvertOp op = new ColorConvertOp(cs, rgbCS, null); BufferedImage converted = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); bi = op.filter(bi, converted); } // add in the alpha data supplied by the SMask, if any PDFImage sMaskImage = getSMask(); if (sMaskImage != null) { BufferedImage si = sMaskImage.getImage(); BufferedImage outImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); int[] srcArray = new int[width]; int[] maskArray = new int[width]; for (int i = 0; i < height; i++) { bi.getRGB(0, i, width, 1, srcArray, 0, width); si.getRGB(0, i, width, 1, maskArray, 0, width); for (int j = 0; j < width; j++) { int ac = 0xff000000; maskArray[j] = ((maskArray[j] & 0xff) << 24) | (srcArray[j] & ~ac); } outImage.setRGB(0, i, width, 1, maskArray, 0, width); } bi = outImage; } return (bi); } private boolean isGreyscale(ColorSpace aCs) { return aCs == PDFColorSpace.getColorSpace(PDFColorSpace.COLORSPACE_GRAY). getColorSpace(); } private BufferedImage convertGreyscaleToArgb(byte[] data, BufferedImage bi) { // we use an optimised greyscale colour conversion, as with scanned // greyscale/mono documents consisting of nothing but page-size // images, using the ICC converter is perhaps 15 times slower than this // method. Using an example scanned, mainly monochrome document, on this // developer's machine pages took an average of 3s to render using the // ICC converter filter, and around 115ms using this method. We use // pre-calculated tables generated using the ICC converter to map between // each possible greyscale value and its desired value in sRGB. // We also try to avoid going through SampleModels, WritableRasters or // BufferedImages as that takes about 3 times as long. final int[] convertedPixels = new int[getWidth() * getHeight()]; final WritableRaster r = bi.getRaster(); int i = 0; final int[] greyToArgbMap = getGreyToArgbMap(bpc); if (bpc == 1) { int calculatedLineBytes = (getWidth() + 7) / 8; int rowStartByteIndex; // avoid hitting the WritableRaster for the common 1 bpc case if (greyToArgbMap[0] == 0 && greyToArgbMap[1] == 0xFFFFFFFF) { // optimisation for common case of a direct map to full white // and black, using bit twiddling instead of consulting the // greyToArgb map for (int y = 0; y < getHeight(); ++y) { // each row is byte-aligned rowStartByteIndex = y * calculatedLineBytes; for (int x = 0; x < getWidth(); ++x) { final byte b = data[rowStartByteIndex + x / 8]; final int white = b >> (7 - (x & 7)) & 1; // if white == 0, white - 1 will be 0xFFFFFFFF, // which when xored with 0xFFFFFF will produce 0 // if white == 1, white - 1 will be 0, // which when xored with 0xFFFFFF will produce 0xFFFFFF // (ignoring the top two bytes, which are always set high anyway) convertedPixels[i] = 0xFF000000 | ((white - 1) ^ 0xFFFFFF); ++i; } } } else { // 1 bpc case where we can't bit-twiddle and need to consult // the map for (int y = 0; y < getHeight(); ++y) { rowStartByteIndex = y * calculatedLineBytes; for (int x = 0; x < getWidth(); ++x) { final byte b = data[rowStartByteIndex + x / 8]; final int val = b >> (7 - (x & 7)) & 1; convertedPixels[i] = greyToArgbMap[val]; ++i; } } } } else { for (int y = 0; y < getHeight(); ++y) { for (int x = 0; x < getWidth(); ++x) { final int greyscale = r.getSample(x, y, 0); convertedPixels[i] = greyToArgbMap[greyscale]; ++i; } } } final ColorModel ccm = ColorModel.getRGBdefault(); return new BufferedImage( ccm, Raster.createPackedRaster( new DataBufferInt( convertedPixels, convertedPixels.length), getWidth(), getHeight(), getWidth(), ((PackedColorModel)ccm).getMasks(), null), false, null); } /** * Get the image's width */ public int getWidth() { return width; } /** * Set the image's width */ protected void setWidth(int width) { this.width = width; } /** * Get the image's height */ public int getHeight() { return height; } /** * Set the image's height */ protected void setHeight(int height) { this.height = height; } /** * set the color key mask. It is an array of start/end entries * to indicate ranges of color indicies that should be masked out. * * @param maskArrayObject */ private void setColorKeyMask(PDFObject maskArrayObject) throws IOException { PDFObject[] maskObjects = maskArrayObject.getArray(); colorKeyMask = null; int[] masks = new int[maskObjects.length]; for (int i = 0; i < masks.length; i++) { masks[i] = maskObjects[i].getIntValue(); } colorKeyMask = masks; } /** * Get the colorspace associated with this image, or null if there * isn't one */ protected PDFColorSpace getColorSpace() { return colorSpace; } /** * Set the colorspace associated with this image */ protected void setColorSpace(PDFColorSpace colorSpace) { this.colorSpace = colorSpace; } /** * Get the number of bits per component sample */ protected int getBitsPerComponent() { return bpc; } /** * Set the number of bits per component sample */ protected void setBitsPerComponent(int bpc) { this.bpc = bpc; } /** * Return whether or not this is an image mask */ public boolean isImageMask() { return imageMask; } /** * Set whether or not this is an image mask */ public void setImageMask(boolean imageMask) { this.imageMask = imageMask; } /** * Return the soft mask associated with this image */ public PDFImage getSMask() { return sMask; } /** * Set the soft mask image */ protected void setSMask(PDFImage sMask) { this.sMask = sMask; } /** * Get the decode array */ protected float[] getDecode() { return decode; } /** * Set the decode array */ protected void setDecode(float[] decode) { float max = (1 << getBitsPerComponent()) - 1; this.decode = decode; this.decodeCoefficients = new float[decode.length / 2]; this.decodeMins = new float[decode.length / 2]; for (int i = 0; i < decode.length; i += 2) { decodeMins[i/2] = decode[i]; decodeCoefficients[i/2] = (decode[i + 1] - decode[i]) / max; } } /** * get a Java ColorModel consistent with the current color space, * number of bits per component and decode array * * @param bpc the number of bits per component */ private ColorModel getColorModel() { PDFColorSpace cs = getColorSpace(); if (cs instanceof IndexedColor) { IndexedColor ics = (IndexedColor) cs; byte[] components = ics.getColorComponents(); int num = ics.getCount(); // process the decode array if (decode != null) { byte[] normComps = new byte[components.length]; // move the components array around for (int i = 0; i < num; i++) { byte[] orig = new byte[1]; orig[0] = (byte) i; float[] res = normalize(orig, null, 0); int idx = (int) res[0]; normComps[i * 3] = components[idx * 3]; normComps[(i * 3) + 1] = components[(idx * 3) + 1]; normComps[(i * 3) + 2] = components[(idx * 3) + 2]; } components = normComps; } // make sure the size of the components array is 2 ^ numBits // since if it's not, Java will complain int correctCount = 1 << getBitsPerComponent(); if (correctCount < num) { byte[] fewerComps = new byte[correctCount * 3]; System.arraycopy(components, 0, fewerComps, 0, correctCount * 3); components = fewerComps; num = correctCount; } if (colorKeyMask == null || colorKeyMask.length == 0) { return new IndexColorModel(getBitsPerComponent(), num, components, 0, false); } else { byte[] aComps = new byte[num * 4]; int idx = 0; for (int i = 0; i < num; i++) { aComps[idx++] = components[(i * 3)]; aComps[idx++] = components[(i * 3) + 1]; aComps[idx++] = components[(i * 3) + 2]; aComps[idx++] = (byte) 0xFF; } for (int i = 0; i < colorKeyMask.length; i += 2) { for (int j = colorKeyMask[i]; j <= colorKeyMask[i + 1]; j++) { aComps[(j * 4) + 3] = 0; // make transparent } } return new IndexColorModel(getBitsPerComponent(), num, aComps, 0, true); } } else { int[] bits = new int[cs.getNumComponents()]; for (int i = 0; i < bits.length; i++) { bits[i] = getBitsPerComponent(); } return decode != null ? new DecodeComponentColorModel(cs.getColorSpace(), bits) : new PdfComponentColorModel(cs.getColorSpace(), bits); } } /** * Normalize an array of values to match the decode array */ private float[] normalize(byte[] pixels, float[] normComponents, int normOffset) { if (normComponents == null) { normComponents = new float[normOffset + pixels.length]; } // trivial loop unroll - saves a little time switch (pixels.length) { case 4: normComponents[normOffset + 3] = decodeMins[3] + (float)(pixels[3] & 0xFF) * decodeCoefficients[3]; case 3: normComponents[normOffset + 2] = decodeMins[2] + (float)(pixels[2] & 0xFF) * decodeCoefficients[2]; case 2: normComponents[normOffset + 1] = decodeMins[1] + (float)(pixels[1] & 0xFF) * decodeCoefficients[1]; case 1: normComponents[normOffset ] = decodeMins[0] + (float)(pixels[0] & 0xFF) * decodeCoefficients[0]; break; default: throw new IllegalArgumentException("Someone needs to add support for more than 4 components"); } return normComponents; } /** * A wrapper for ComponentColorSpace which normalizes based on the * decode array. */ static class PdfComponentColorModel extends ComponentColorModel { int bitsPerComponent; public PdfComponentColorModel(ColorSpace cs, int[] bpc) { super(cs, bpc, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); pixel_bits = bpc.length * bpc[0]; this.bitsPerComponent = bpc[0]; } @Override public SampleModel createCompatibleSampleModel(int width, int height) { if (bitsPerComponent >= 8) { assert bitsPerComponent == 8 || bitsPerComponent == 16; final int numComponents = getNumComponents(); int[] bandOffsets = new int[numComponents]; for (int i=0; i < numComponents; i++) { bandOffsets[i] = i; } return new PixelInterleavedSampleModel( getTransferType(), width, height, numComponents, width * numComponents, bandOffsets); } else { switch (getPixelSize()) { case 1: case 2: case 4: // pixels don't span byte boundaries, so we can use the standard multi pixel // packing, which offers a slight performance advantage over the other sample // model, which must consider such cases. Given that sample model interactions // can dominate processing, this small distinction is worthwhile return new MultiPixelPackedSampleModel(getTransferType(), width, height, getPixelSize()); default: // pixels will cross byte boundaries assert getTransferType() == DataBuffer.TYPE_BYTE; return new PdfSubByteSampleModel(width, height, getNumComponents(), bitsPerComponent); } } } @Override public boolean isCompatibleRaster(Raster raster) { if (bitsPerComponent < 8 || getNumComponents() == 1) { SampleModel sm = raster.getSampleModel(); return sm.getSampleSize(0) == bitsPerComponent; } return super.isCompatibleRaster(raster); } } class DecodeComponentColorModel extends PdfComponentColorModel { DecodeComponentColorModel(ColorSpace cs, int[] bpc) { super(cs, bpc); } public int getRGB(Object inData) { float[] norm = getNormalizedComponents(inData, null, 0); // super-class wants to do a (VERY expensive!) colorspace conversion // here, but we'll ignore it - I think we'll already have the // colour space converted. float[] rgb = norm;//this.colorSpace.toRGB(norm); // Note that getNormalizedComponents returns non-premult values return (this.getAlpha(inData) << 24) | (((int) (rgb[0] * 255.0f + 0.5f)) << 16) | (((int) (rgb[1] * 255.0f + 0.5f)) << 8) | (((int) (rgb[2] * 255.0f + 0.5f))); } @Override public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) { return normalize((byte[]) pixel, normComponents, normOffset); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/Watchable.java0000644000175000017500000000451511134132451022331 0ustar twernertwerner/* * $Id: Watchable.java,v 1.3 2009-01-16 16:26:15 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; /** * An interface for rendering or parsing, which can be stopped and started. */ public interface Watchable { /** the possible statuses */ public static final int UNKNOWN = 0; public static final int NOT_STARTED = 1; public static final int PAUSED = 2; public static final int NEEDS_DATA = 3; public static final int RUNNING = 4; public static final int STOPPED = 5; public static final int COMPLETED = 6; public static final int ERROR = 7; /** * Get the status of this watchable * * @return one of the well-known statuses */ public int getStatus(); /** * Stop this watchable. Stop will cause all processing to cease, * and the watchable to be destroyed. */ public void stop(); /** * Start this watchable and run until it is finished or stopped. * Note the watchable may be stopped if go() with a * different time is called during execution. */ public void go(); /** * Start this watchable and run for the given number of steps or until * finished or stopped. * * @param steps the number of steps to run for */ public void go(int steps); /** * Start this watchable and run for the given amount of time, or until * finished or stopped. * * @param millis the number of milliseconds to run for */ public void go(long millis); } pdfrenderer-0.9.0/src/com/sun/pdfview/PdfSubByteSampleModel.java0000644000175000017500000001163711376323412024603 0ustar twernertwerner/* * $Id: PdfSubByteSampleModel.java,v 1.1 2010-05-23 22:07:05 lujke Exp $ * * Copyright 2010 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.image.DataBuffer; import java.awt.image.SampleModel; /** * Provides a read-only sample-model where components are less than a byte in * width while allowing for pixels to cross byte-boundaries. For example, this * allows 2 pixels made of 3 4-bit-bands (p[pixel,band]) * to be stored in 3 bytes as p[0,1] p[0,2] | p[0,3] p[1,0] | p[1,1] p[1,2]. * {@link java.awt.image.MultiPixelPackedSampleModel}, which allows for sub-byte * components, does not allow for such byte spanning, while the PDF * specification does permit it -- hence the existence of this class. * * @author Luke Kirby, Pirion Systems */ public class PdfSubByteSampleModel extends SampleModel { private final int transferBytesPerPixel; private final int storageBitsPerPixel; private final int bitsPerLine; private final int bitsPerBand; private final int componentMask; private final int[] sampleSize; private final int ignoredBitsPerComponentPerByte; public PdfSubByteSampleModel(int w, int h, int numComponents, int bitsPerComponent) { super(DataBuffer.TYPE_BYTE, w, h, numComponents); assert bitsPerComponent < 8 : "This is designed just for use with per-component sizes of less than 8 bits; " + "you should probably use PixelInterleavedSampleModel"; assert bitsPerComponent == 1 || bitsPerComponent == 2 || bitsPerComponent == 4 : "we don't want to grab components across byte boundaries"; transferBytesPerPixel = (numComponents * bitsPerComponent + 7) / 8; storageBitsPerPixel = numComponents * bitsPerComponent; // account for possible bits of padding on the end bitsPerLine = 8 * ((storageBitsPerPixel * w + 7) / 8); this.bitsPerBand = bitsPerComponent; componentMask = (1 << this.bitsPerBand) - 1; sampleSize = new int[numComponents]; for (int i = 0; i < sampleSize.length; ++i) { sampleSize[i] = bitsPerComponent; } ignoredBitsPerComponentPerByte = 8 - bitsPerBand; } @Override public int getNumDataElements() { return transferBytesPerPixel; } @Override public Object getDataElements(int x, int y, Object obj, DataBuffer data) { byte[] elements = obj != null ? (byte[])obj : new byte[numBands]; int bitIndex = y * bitsPerLine + storageBitsPerPixel * x; for (int i = 0; i < elements.length; ++i) { elements[i] = (byte) getComponent(data, bitIndex); bitIndex += bitsPerBand; } return elements; } private int getComponent(DataBuffer data, int aBitIndex) { final int boffset = aBitIndex >> 3; // == aBitIndex / 8 final int b = data.getElem(boffset); final int bitIndexInB = aBitIndex & 7; final int shift = ignoredBitsPerComponentPerByte - bitIndexInB; return (b >>> shift) & componentMask; } @Override public void setDataElements(int x, int y, Object obj, DataBuffer data) { throw new UnsupportedOperationException("read only"); } @Override public int getSample(int x, int y, int b, DataBuffer data) { return getComponent(data, y * bitsPerLine + storageBitsPerPixel * x + bitsPerBand * b); } @Override public void setSample(int x, int y, int b, int s, DataBuffer data) { throw new UnsupportedOperationException("read only"); } @Override public SampleModel createCompatibleSampleModel(int w, int h) { throw new UnsupportedOperationException("Not required"); } @Override public SampleModel createSubsetSampleModel(int[] bands) { throw new UnsupportedOperationException("Not required"); } @Override public DataBuffer createDataBuffer() { throw new UnsupportedOperationException("Not required"); } @Override public int[] getSampleSize() { return sampleSize; } @Override public int getSampleSize(int band) { return bitsPerBand; } } pdfrenderer-0.9.0/src/com/sun/pdfview/HexDump.java0000644000175000017500000000564111134132451022012 0ustar twernertwerner/* * $Id: HexDump.java,v 1.3 2009-01-16 16:26:12 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.IOException; import java.io.RandomAccessFile; public class HexDump { public static void printData(byte[] data) { char[] parts = new char[17]; int partsloc = 0; for (int i = 0; i < data.length; i++) { int d = ((int) data[i]) & 0xff; if (d == 0) { parts[partsloc++] = '.'; } else if (d < 32 || d >= 127) { parts[partsloc++] = '?'; } else { parts[partsloc++] = (char) d; } if (i % 16 == 0) { int start = Integer.toHexString(data.length).length(); int end = Integer.toHexString(i).length(); for (int j = start; j > end; j--) { System.out.print("0"); } System.out.print(Integer.toHexString(i) + ": "); } if (d < 16) { System.out.print("0" + Integer.toHexString(d)); } else { System.out.print(Integer.toHexString(d)); } if ((i & 15) == 15 || i == data.length - 1) { System.out.println(" " + new String(parts)); partsloc = 0; } else if ((i & 7) == 7) { System.out.print(" "); parts[partsloc++] = ' '; } else if ((i & 1) == 1) { System.out.print(" "); } } System.out.println(); } public static void main(String args[]) { if (args.length != 1) { System.out.println("Usage: "); System.out.println(" HexDump "); System.exit(-1); } try { RandomAccessFile raf = new RandomAccessFile(args[0], "r"); int size = (int) raf.length(); byte[] data = new byte[size]; raf.readFully(data); printData(data); } catch (IOException ioe) { ioe.printStackTrace(); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFPaint.java0000644000175000017500000000451511134132451022044 0ustar twernertwerner/* * $Id: PDFPaint.java,v 1.4 2009-01-16 16:26:09 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; /** * PDFPaint is some kind of shader that knows how to fill a path. * At the moment, only a solid color is implemented, but gradients * and textures should be possible, too. * @author Mike Wessler */ public class PDFPaint { private Paint mainPaint; /** * create a new PDFPaint based on a solid color */ protected PDFPaint(Paint p) { this.mainPaint = p; } /** * get the PDFPaint representing a solid color */ public static PDFPaint getColorPaint(Color c) { return getPaint(c); } /** * get the PDFPaint representing a generic paint */ public static PDFPaint getPaint(Paint p) { return new PDFPaint(p); } /** * fill a path with the paint, and record the dirty area. * @param state the current graphics state * @param g the graphics into which to draw * @param s the path to fill */ public Rectangle2D fill(PDFRenderer state, Graphics2D g, GeneralPath s) { g.setPaint(mainPaint); g.fill(s); return s.createTransformedShape(g.getTransform()).getBounds2D(); } /** * get the primary color associated with this PDFPaint. */ public Paint getPaint() { return mainPaint; } } pdfrenderer-0.9.0/src/com/sun/pdfview/ByteBufferInputStream.java0000644000175000017500000000557611405464114024705 0ustar twernertwerner/* * Copyright 2010 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; /** * Exposes a {@link ByteBuffer} as an {@link InputStream}. * * @author Luke Kirby */ public class ByteBufferInputStream extends InputStream { /** The underlying byte buffer */ private ByteBuffer buffer; /** * Class constructor * @param buffer the buffer to present as an input stream, positioned * at the current read position of the byte buffer */ public ByteBufferInputStream(ByteBuffer buffer) { this.buffer = buffer; } @Override public int read(byte[] b, int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } final int remaining = buffer.remaining(); if (remaining == 0) { return -1; } else if (remaining < len) { buffer.get(b, off, remaining); return remaining; } else { buffer.get(b, off, len); return len; } } @Override public long skip(long n) throws IOException { if (n <= 0) { return 0; } else { final int remaining = buffer.remaining(); if (n < remaining) { buffer.position(buffer.position() + remaining); return remaining; } else { buffer.position((int) (buffer.position() + n)); return n; } } } @Override public int read() throws IOException { return buffer.get(); } @Override public int available() throws IOException { return buffer.remaining(); } @Override public void mark(int readlimit) { buffer.mark(); } @Override public boolean markSupported() { return true; } @Override public void reset() throws IOException { buffer.reset(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFShapeCmd.java0000644000175000017500000001614311134132451022455 0ustar twernertwerner/* * $Id: PDFShapeCmd.java,v 1.3 2009-01-16 16:26:15 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.BasicStroke; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; /** * Encapsulates a path. Also contains extra fields and logic to check * for consecutive abutting anti-aliased regions. We stroke the shared * line between these regions again with a 1-pixel wide line so that * the background doesn't show through between them. * * @author Mike Wessler */ public class PDFShapeCmd extends PDFCmd { /** stroke the outline of the path with the stroke paint */ public static final int STROKE = 1; /** fill the path with the fill paint */ public static final int FILL = 2; /** perform both stroke and fill */ public static final int BOTH = 3; /** set the clip region to the path */ public static final int CLIP = 4; /** base path */ private GeneralPath gp; /** the style */ private int style; /** the bounding box of the path */ private Rectangle2D bounds; /** the stroke style for the anti-antialias stroke */ BasicStroke againstroke = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); /** * create a new PDFShapeCmd and check it against the previous one * to find any shared edges. * @param gp the path * @param style the style: an OR of STROKE, FILL, or CLIP. As a * convenience, BOTH = STROKE | FILL. */ public PDFShapeCmd(GeneralPath gp, int style) { this.gp = new GeneralPath(gp); this.style = style; bounds = gp.getBounds2D(); } /** * perform the stroke and record the dirty region */ public Rectangle2D execute(PDFRenderer state) { Rectangle2D rect = null; if ((style & FILL) != 0) { rect = state.fill(gp); GeneralPath strokeagain = checkOverlap(state); if (strokeagain != null) { state.draw(strokeagain, againstroke); } if (gp != null) { state.setLastShape(gp); } } if ((style & STROKE) != 0) { Rectangle2D strokeRect = state.stroke(gp); if (rect == null) { rect = strokeRect; } else { rect = rect.createUnion(strokeRect); } } if ((style & CLIP) != 0) { state.clip(gp); } return rect; } /** * Check for overlap with the previous shape to make anti-aliased shapes * that are near each other look good */ private GeneralPath checkOverlap(PDFRenderer state) { if (style == FILL && gp != null && state.getLastShape() != null) { float mypoints[] = new float[16]; float prevpoints[] = new float[16]; int mycount = getPoints(gp, mypoints); int prevcount = getPoints(state.getLastShape(), prevpoints); // now check mypoints against prevpoints for opposite pairs: if (mypoints != null && prevpoints != null) { for (int i = 0; i < prevcount; i += 4) { for (int j = 0; j < mycount; j += 4) { if ((Math.abs(mypoints[j + 2] - prevpoints[i]) < 0.01 && Math.abs(mypoints[j + 3] - prevpoints[i + 1]) < 0.01 && Math.abs(mypoints[j] - prevpoints[i + 2]) < 0.01 && Math.abs(mypoints[j + 1] - prevpoints[i + 3]) < 0.01)) { GeneralPath strokeagain = new GeneralPath(); strokeagain.moveTo(mypoints[j], mypoints[j + 1]); strokeagain.lineTo(mypoints[j + 2], mypoints[j + 3]); return strokeagain; } } } } } // no issues return null; } /** * Get an array of 16 points from a path * @return the number of points we actually got */ private int getPoints(GeneralPath path, float[] mypoints) { int count = 0; float x = 0; float y = 0; float startx = 0; float starty = 0; float[] coords = new float[6]; PathIterator pi = path.getPathIterator(new AffineTransform()); while (!pi.isDone()) { if (count >= mypoints.length) { mypoints = null; break; } int pathtype = pi.currentSegment(coords); switch (pathtype) { case PathIterator.SEG_MOVETO: startx = x = coords[0]; starty = y = coords[1]; break; case PathIterator.SEG_LINETO: mypoints[count++] = x; mypoints[count++] = y; x = mypoints[count++] = coords[0]; y = mypoints[count++] = coords[1]; break; case PathIterator.SEG_QUADTO: x = coords[2]; y = coords[3]; break; case PathIterator.SEG_CUBICTO: x = mypoints[4]; y = mypoints[5]; break; case PathIterator.SEG_CLOSE: mypoints[count++] = x; mypoints[count++] = y; x = mypoints[count++] = startx; y = mypoints[count++] = starty; break; } pi.next(); } return count; } /** Get detailed information about this shape */ @Override public String getDetails() { StringBuffer sb = new StringBuffer(); Rectangle2D b = gp.getBounds2D(); sb.append("ShapeCommand at: " + b.getX() + ", " + b.getY() + "\n"); sb.append("Size: " + b.getWidth() + " x " + b.getHeight() + "\n"); sb.append("Mode: "); if ((style & FILL) != 0) { sb.append("FILL "); } if ((style & STROKE) != 0) { sb.append("STROKE "); } if ((style & CLIP) != 0) { sb.append("CLIP"); } return sb.toString(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/OutlineNode.java0000644000175000017500000000341711134132451022664 0ustar twernertwerner/* * $Id: OutlineNode.java,v 1.3 2009-01-16 16:26:10 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import javax.swing.tree.DefaultMutableTreeNode; import com.sun.pdfview.action.PDFAction; public class OutlineNode extends DefaultMutableTreeNode { // the name of this node private String title; /** * Create a new outline node * * @param title the node's visible name in the tree */ public OutlineNode(String title) { this.title = title; } /** * Get the PDF action associated with this node */ public PDFAction getAction() { return (PDFAction) getUserObject(); } /** * Set the PDF action associated with this node */ public void setAction(PDFAction action) { setUserObject(action); } /** * Return the node's visible name in the tree */ @Override public String toString() { return title; } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFParseException.java0000644000175000017500000000246711156177553023746 0ustar twernertwerner/* * $Id: PDFParseException.java,v 1.4 2009-03-12 12:25:25 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.io.IOException; /** * an exception class for recording parse errors in the PDF file * @author Mike Wessler */ public class PDFParseException extends IOException { public PDFParseException(String msg) { super(msg); } public PDFParseException(String msg, Throwable cause) { this(msg); initCause(cause); } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/0000755000175000017500000000000011622545441021732 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/PDFColorSpace.java0000644000175000017500000001705611155027230025162 0ustar twernertwerner/* * $Id: PDFColorSpace.java,v 1.5 2009-03-08 20:46:16 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.function.PDFFunction; import java.awt.Color; import java.awt.color.ColorSpace; import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Map; /** * A color space that can convert a set of color components into * PDFPaint. * @author Mike Wessler */ public class PDFColorSpace { /** the name of the device-dependent gray color space */ public static final int COLORSPACE_GRAY = 0; /** the name of the device-dependent RGB color space */ public static final int COLORSPACE_RGB = 1; /** the name of the device-dependent CMYK color space */ public static final int COLORSPACE_CMYK = 2; /** the name of the pattern color space */ public static final int COLORSPACE_PATTERN = 3; /** the device-dependent color spaces */ // private static PDFColorSpace graySpace = // new PDFColorSpace(ColorSpace.getInstance(ColorSpace.CS_GRAY)); private static PDFColorSpace rgbSpace = new PDFColorSpace(ColorSpace.getInstance( ColorSpace.CS_sRGB)); private static PDFColorSpace cmykSpace = new PDFColorSpace(new CMYKColorSpace()); /** the pattern space */ private static PDFColorSpace patternSpace = new PatternSpace(); /** graySpace and the gamma correction for it. */ private static PDFColorSpace graySpace; static { boolean useSGray = true; try { graySpace = new PDFColorSpace((!useSGray) ? ColorSpace.getInstance(ColorSpace.CS_GRAY) : new ICC_ColorSpace(ICC_Profile.getInstance( PDFColorSpace.class.getResourceAsStream( ("sGray.icc"))))); } catch (Exception e) { throw new RuntimeException(e); } } /** the color space */ ColorSpace cs; /** * create a PDFColorSpace based on a Java ColorSpace * @param cs the Java ColorSpace */ protected PDFColorSpace(ColorSpace cs) { this.cs = cs; } /** * Get a color space by name * * @param name the name of one of the device-dependent color spaces */ public static PDFColorSpace getColorSpace(int name) { switch (name) { case COLORSPACE_GRAY: return graySpace; case COLORSPACE_RGB: return rgbSpace; case COLORSPACE_CMYK: return cmykSpace; case COLORSPACE_PATTERN: return patternSpace; default: throw new IllegalArgumentException("Unknown Color Space name: " + name); } } /** * Get a color space specified in a PDFObject * * @param csobj the PDFObject with the colorspace information */ public static PDFColorSpace getColorSpace(PDFObject csobj, Map resources) throws IOException { String name; PDFObject colorSpaces = null; if (resources != null) { colorSpaces = (PDFObject) resources.get("ColorSpace"); } if (csobj.getType() == PDFObject.NAME) { name = csobj.getStringValue(); if (name.equals("DeviceGray") || name.equals("G")) { return getColorSpace(COLORSPACE_GRAY); } else if (name.equals("DeviceRGB") || name.equals("RGB")) { return getColorSpace(COLORSPACE_RGB); } else if (name.equals("DeviceCMYK") || name.equals("CMYK")) { return getColorSpace(COLORSPACE_CMYK); } else if (name.equals("Pattern")) { return getColorSpace(COLORSPACE_PATTERN); } else if (colorSpaces != null) { csobj = (PDFObject) colorSpaces.getDictRef(name); } } if (csobj == null) { return null; } else if (csobj.getCache() != null) { return (PDFColorSpace) csobj.getCache(); } PDFColorSpace value = null; // csobj is [/name <>] PDFObject[] ary = csobj.getArray(); name = ary[0].getStringValue(); if (name.equals("CalGray")) { value = new PDFColorSpace(new CalGrayColor(ary[1])); } else if (name.equals("CalRGB")) { value = new PDFColorSpace(new CalRGBColor(ary[1])); } else if (name.equals("Lab")) { value = new PDFColorSpace(new LabColor(ary[1])); } else if (name.equals("ICCBased")) { ByteArrayInputStream bais = new ByteArrayInputStream(ary[1].getStream()); ICC_Profile profile = ICC_Profile.getInstance(bais); value = new PDFColorSpace(new ICC_ColorSpace(profile)); } else if (name.equals("Separation") || name.equals("DeviceN")) { PDFColorSpace alternate = getColorSpace(ary[2], resources); PDFFunction function = PDFFunction.getFunction(ary[3]); value = new AlternateColorSpace(alternate, function); } else if (name.equals("Indexed") || name.equals("I")) { /** * 4.5.5 [/Indexed baseColor hival lookup] */ PDFColorSpace refspace = getColorSpace(ary[1], resources); // number of indices= ary[2], data is in ary[3]; int count = ary[2].getIntValue(); value = new IndexedColor(refspace, count, ary[3]); } else if (name.equals("Pattern")) { if (ary.length == 1) { return getColorSpace(COLORSPACE_PATTERN); } PDFColorSpace base = getColorSpace(ary[1], resources); return new PatternSpace(base); } else { throw new PDFParseException("Unknown color space: " + name + " with " + ary[1]); } csobj.setCache(value); return value; } /** * get the number of components expected in the getPaint command */ public int getNumComponents() { return cs.getNumComponents(); } /** * get the PDFPaint representing the color described by the * given color components * @param components the color components corresponding to the given * colorspace * @return a PDFPaint object representing the closest Color to the * given components. */ public PDFPaint getPaint(float[] components) { float[] rgb = cs.toRGB(components); return PDFPaint.getColorPaint(new Color(rgb[0], rgb[1], rgb[2])); } /** * get the original Java ColorSpace. */ public ColorSpace getColorSpace() { return cs; } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/CalGrayColor.java0000644000175000017500000000666310732532577025140 0ustar twernertwerner/* * $Id: CalGrayColor.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.color.ColorSpace; import java.io.IOException; import com.sun.pdfview.PDFObject; /** * A ColorSpace for calibrated gray * @author Mike Wessler */ public class CalGrayColor extends ColorSpace { float white[]= {1f, 1f, 1f}; float black[]= {0, 0, 0}; float gamma= 1; static ColorSpace cie= ColorSpace.getInstance(ColorSpace.CS_sRGB); /** * Create a new Calibrated Gray color space object, given * the description in a PDF dictionary. * @param obj a dictionary that contains an Array of 3 Numbers * for "WhitePoint" and "BlackPoint", and a Number for "Gamma" */ public CalGrayColor(PDFObject obj) throws IOException { // obj is a dictionary that has the following parts: // WhitePoint [a b c] // BlackPoint [a b c] // Gamma a super(TYPE_GRAY, 1); PDFObject ary= obj.getDictRef("WhitePoint"); if (ary!=null) { for(int i=0; i<3; i++) { white[i]= ary.getAt(i).getFloatValue(); } } ary= obj.getDictRef("BlackPoint"); if (ary!=null) { for(int i=0; i<3; i++) { black[i]= ary.getAt(i).getFloatValue(); } } PDFObject g= obj.getDictRef("Gamma"); if (g!=null) { gamma= g.getFloatValue(); } } /** * Create a new calibrated gray color space object, with the * default values for black point, white point and gamma */ public CalGrayColor() { super(TYPE_GRAY, 1); } /** * get the number of components (1). */ @Override public int getNumComponents() { return 1; } /** * convert from Calibrated Gray to RGB. * @param comp the gray value (0-1) * @return the RGB values (0-1) */ public float[] toRGB(float comp[]) { if (comp.length==1) { float mul= (float)Math.pow(comp[0], gamma); float xyz[] = { white[0]*mul, 0, 0}; float rgb[]= cie.fromCIEXYZ(xyz); return rgb; } else { return black; } } /** * convert from RGB to Calibrated Gray. NOT IMPLEMENTED */ public float[] fromRGB(float[] rgbvalue) { return new float[1]; } /** * convert from CIEXYZ to Calibrated Gray. NOT IMPLEMENTED */ public float[] fromCIEXYZ(float[] colorvalue) { return new float[1]; } /** * get the type of this ColorSpace (TYPE_GRAY) */ @Override public int getType() { return TYPE_GRAY; } /** * convert from Calibrated Gray to CIEXYZ. NOT IMPLEMENTED */ public float[] toCIEXYZ(float[] colorvalue) { return new float[3]; } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/sGray.icc0000644000175000017500000000464011155027230023473 0ustar twernertwerner ADBE@mntrGRAYXYZ acspAPPL-ADBEcprt2desc`wtptTchadh,kTRC textCopyright 2002 Adobe Systems IncorporateddescsGrayXYZ -sf32 ?&qcurv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmpdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/MaskColorSpace.java0000644000175000017500000000600410732532577025452 0ustar twernertwerner/* * $Id: MaskColorSpace.java,v 1.3 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.Color; import java.awt.color.ColorSpace; import com.sun.pdfview.PDFPaint; /** * A color space used to implement masks. For now, the only type of mask * supported is one where the image pixels specify where to paint, and the * painting itself is done in a pre-specified PDF Paint. */ public class MaskColorSpace extends ColorSpace { /** The paint to paint in. Note this cannot be a pattern or gradient. */ private PDFPaint paint; /** Creates a new instance of PaintColorSpace */ public MaskColorSpace(PDFPaint paint) { super (TYPE_RGB, 1); this.paint = paint; } public float[] fromCIEXYZ(float[] colorvalue) { float x = colorvalue[0]; float y = colorvalue[1]; float z = colorvalue[2]; float[] mask = new float[1]; if (Math.round(x) > 0 || Math.round(y) > 0 || Math.round(z) > 0) { mask[0] = 1; } else { mask[0] = 0; } return mask; } public float[] fromRGB(float[] rgbvalue) { float r = rgbvalue[0]; float g = rgbvalue[1]; float b = rgbvalue[2]; float[] mask = new float[1]; if (Math.round(r) > 0 || Math.round(g) > 0 || Math.round(b) > 0) { mask[0] = 1; } else { mask[0] = 0; } return mask; } ColorSpace cie = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); float[] prev1= cie.fromRGB(toRGB(new float[] {1.0f})); float[] prev0= cie.fromRGB(toRGB(new float[] {0.0f})); public float[] toCIEXYZ(float[] colorvalue) { if (colorvalue[0]==1) { return prev1; } else if (colorvalue[0]==0) { return prev0; } else { // System.out.println("MaskColorSpace converting: "+colorvalue[0]); return cie.fromRGB(toRGB(colorvalue)); } } public float[] toRGB(float[] colorvalue) { return ((Color) paint.getPaint()).getRGBColorComponents(null); } @Override public int getNumComponents() { return 1; } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/AlternateColorSpace.java0000644000175000017500000000525410732532577026504 0ustar twernertwerner/* * $Id: AlternateColorSpace.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.color.ColorSpace; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.function.PDFFunction; /** * A color space that uses another color space to return values, and a * function to map between values in the input and input values to the * alternate color space */ public class AlternateColorSpace extends PDFColorSpace { /** The alternate color space */ private PDFColorSpace alternate; /** The function */ private PDFFunction function; /** Creates a new instance of AlternateColorSpace */ public AlternateColorSpace(PDFColorSpace alternate, PDFFunction function) { super(null); this.alternate = alternate; this.function = function; } /** * get the number of components expected in the getPaint command */ @Override public int getNumComponents() { if (function != null) { return function.getNumInputs(); } else { return alternate.getNumComponents(); } } /** * get the PDFPaint representing the color described by the * given color components * @param components the color components corresponding to the given * colorspace * @return a PDFPaint object representing the closest Color to the * given components. */ @Override public PDFPaint getPaint(float[] components) { if (function != null) { // translate values using function components = function.calculate(components); } return alternate.getPaint(components); } /** * get the original Java ColorSpace. */ @Override public ColorSpace getColorSpace() { return alternate.getColorSpace(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/IndexedColor.java0000644000175000017500000001065211137246332025156 0ustar twernertwerner/* * $Id: IndexedColor.java,v 1.4 2009-01-26 05:40:42 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.Color; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; /** * A PDFColorSpace for an IndexedColor model * * @author Mike Wessler */ public class IndexedColor extends PDFColorSpace { /** * r,g,and b components of the color table as a single array, for * Java's IndexColorModel */ protected byte[] finalcolors; /** the color table */ Color table[]; /** size of the color table */ int count; /** number of channels in the base Color Space (unused) */ int nchannels = 1; /** * create a new IndexColor PDFColorSpace based on another PDFColorSpace, * a count of colors, and a stream of values. Every consecutive n bytes * of the stream is interpreted as a color in the base ColorSpace, where * n is the number of components in that color space. * * @param base the color space in which the data is interpreted * @param count the number of colors in the table * @param stream a stream of bytes. The number of bytes must be count*n, * where n is the number of components in the base colorspace. */ public IndexedColor(PDFColorSpace base, int count, PDFObject stream) throws IOException { super(null); count++; this.count = count; byte[] data = stream.getStream(); nchannels = base.getNumComponents(); boolean offSized = (data.length / nchannels) < count; finalcolors = new byte[3 * count]; table = new Color[count]; float comps[] = new float[nchannels]; int loc = 0; int finalloc = 0; for (int i = 0; i < count; i++) { for (int j = 0; j < comps.length; j++) { if (loc < data.length) { comps[j] = (((int) data[loc++]) & 0xff) / 255f; } else { comps[j] = 1.0f; } } table[i] = (Color) base.getPaint(comps).getPaint(); finalcolors[finalloc++] = (byte) table[i].getRed(); finalcolors[finalloc++] = (byte) table[i].getGreen(); finalcolors[finalloc++] = (byte) table[i].getBlue(); } } /** * create a new IndexColor PDFColorSpace based on a table of colors. * * @param table an array of colors */ public IndexedColor(Color[] table) throws IOException { super(null); this.count = table.length; this.table = table; finalcolors = new byte[3 * count]; nchannels = 3; int loc = 0; for (int i = 0; i < count; i++) { finalcolors[loc++] = (byte) table[i].getRed(); finalcolors[loc++] = (byte) table[i].getGreen(); finalcolors[loc++] = (byte) table[i].getBlue(); } } /** * Get the number of indices */ public int getCount() { return count; } /** * Get the table of color components */ public byte[] getColorComponents() { return finalcolors; } /** * get the number of components of this colorspace (1) */ @Override public int getNumComponents() { return 1; } /** * get the color represented by the index. * @param components an array of exactly one integer number whose * value is between 0 and the size of the color table - 1. */ @Override public PDFPaint getPaint(float components[]) { return PDFPaint.getPaint(table[(int) components[0]]); } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/CalRGBColor.java0000644000175000017500000002023510732532577024637 0ustar twernertwerner/* * $Id: CalRGBColor.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.color.ColorSpace; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.function.FunctionType0; /** * A ColorSpace for calibrated RGB * @author Mike Wessler */ public class CalRGBColor extends ColorSpace { private static final float[] vonKriesM = { 0.40024f, -0.22630f, 0.00000f, 0.70760f, 1.16532f, 0.00000f, -0.08081f, 0.04570f, 0.91822f }; private static final float[] vonKriesMinv = { 1.859936f, 0.361191f, 0.000000f, -1.129382f, 0.638812f, 0.000000f, 0.219897f, -0.000006f, 1.089064f }; private static final float[] xyzToSRGB = { 3.24071f, -0.969258f, 0.0556352f, -1.53726f, 1.87599f, -0.203996f, -0.498571f, 0.0415557f, 1.05707f }; private static final float[] xyzToRGB = { 2.04148f, -0.969258f, 0.0134455f, -0.564977f, 1.87599f, -0.118373f, -0.344713f, 0.0415557f, 1.01527f }; float[] scale; float[] max; float white[]= {1f, 1f, 1f}; float black[]= {0, 0, 0}; float matrix[]= {1f, 0, 0, 0, 1f, 0, 0, 0, 1f}; float gamma[]= {1f, 1f, 1f}; static ColorSpace rgbCS= ColorSpace.getInstance(ColorSpace.CS_sRGB); static ColorSpace cieCS= ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); /** * Create a new Calibrated RGB color space object, given the * description in a PDF dictionary. * @param obj a dictionary that contains an array of 3 Numbers * for "WhitePoint" and "BlackPoint", a Number for "Gamma", and * an array of 9 Numbers for "Matrix". */ public CalRGBColor(PDFObject obj) throws IOException { // obj is a dictionary that has the following parts: // WhitePoint [a b c] // BlackPoint [a b c] // Gamma a super(CS_sRGB, 3); // find out what what is according to the CIE color space // note that this is not reflexive (i.e. passing this value // into toRGB does not get you (1.0, 1.0, 1.0) back) // cieWhite = cieCS.fromRGB(new float[] { 1.0f, 1.0f, 1.0f } ); PDFObject ary= obj.getDictRef("WhitePoint"); if (ary!=null) { for(int i=0; i<3; i++) { white[i]= ary.getAt(i).getFloatValue(); } } ary= obj.getDictRef("BlackPoint"); if (ary!=null) { for(int i=0; i<3; i++) { black[i]= ary.getAt(i).getFloatValue(); } } ary= obj.getDictRef("Gamma"); if (ary!=null) { for (int i=0; i<3; i++) { gamma[i]= ary.getAt(i).getFloatValue(); } } ary= obj.getDictRef("Matrix"); if (ary!=null) { for (int i=0; i<9; i++) { matrix[i]= ary.getAt(i).getFloatValue(); } } // create a scale matrix relative to the 50 CIE color space. // see http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html // we use the Von Kries cone response domain float[] cieWhite = rgbCS.toCIEXYZ(new float[] { 1f, 1f, 1f }); float[] sourceWhite = matrixMult(white, vonKriesM, 3); float[] destWhite = matrixMult(cieWhite, vonKriesM, 3); scale = new float[] { destWhite[0] / sourceWhite[0], 0, 0, 0, destWhite[1] / sourceWhite[1], 0, 0, 0, destWhite[2] / sourceWhite[2] }; scale = matrixMult(vonKriesM, scale, 3); scale = matrixMult(scale, vonKriesMinv, 3); max = matrixMult(white, scale, 3); max = ciexyzToSRGB(max); } /** * get the number of components (3) */ @Override public int getNumComponents() { return 3; } /** * convert from Calibrated RGB to standard RGB * @param comp the Calibrated RGB values (0-1) * @return the RGB values (0-1) */ public float[] toRGB(float comp[]) { if (comp.length==3) { // compute r', g' and b' by raising the given values to the // correct gamma float a = (float)Math.pow(comp[0], gamma[0]); float b = (float)Math.pow(comp[1], gamma[1]); float c = (float)Math.pow(comp[2], gamma[2]); // now multiply by the matrix to get X, Y and Z values float[] xyz = new float[] { matrix[0]*a + matrix[3]*b + matrix[6]*c, matrix[1]*a + matrix[4]*b + matrix[7]*c, matrix[2]*a + matrix[5]*b + matrix[8]*c}; // now scale the xyz values xyz = matrixMult(xyz, scale, 3); // convert to RGB float[] rgb = ciexyzToSRGB(xyz); // cheat -- scale based on max for (int i = 0; i < rgb.length; i++) { rgb[i] = FunctionType0.interpolate(rgb[i], 0, max[i], 0, 1); // sometimes we get off a little bit due to precision loss if (rgb[i] > 1.0) { rgb[i] = 1.0f; } } return rgb; } else { return black; } } /** * Convert from CIEXYZ, with scale and gamma calculated to sRGB */ private float[] ciexyzToSRGB(float[] xyz) { float[] rgb = matrixMult(xyz, xyzToSRGB, 3); for (int i = 0; i < rgb.length; i++) { if (rgb[i] < 0.0) { rgb[i] = 0f; } else if (rgb[i] > 1.0) { rgb[i] = 1f; } if (rgb[i] < 0.003928) { rgb[i] *= 12.92; } else { rgb[i] = (float) ((Math.pow(rgb[i], 1.0 / 2.4) * 1.055) - 0.055); } } //float[] rgb = cieCS.toRGB(xyz); return rgb; } /** * convert from RGB to Calibrated RGB. NOT IMPLEMENTED */ public float[] fromRGB(float[] rgbvalue) { return new float[3]; } /** * convert from CIEXYZ to Calibrated RGB. NOT IMPLEMENTED */ public float[] fromCIEXYZ(float[] colorvalue) { return new float[3]; } /** * get the type of this color space (TYPE_RGB) */ @Override public int getType() { return TYPE_RGB; } /** * convert from Calibrated RGB to CIEXYZ. NOT IMPLEMENTED */ public float[] toCIEXYZ(float[] colorvalue) { return new float[3]; } /** * Slowly multiply two matrices * * @param a the first matrix * @param b the second matrix * @param len the size of each row. All matrix lengths must be a * multiple of len. */ float[] matrixMult(float[] a, float[] b, int len) { int rows = a.length / len; int cols = b.length / len; float[] out = new float[rows * cols]; for (int i = 0; i < rows; i++) { for (int k = 0; k < cols; k++) { for (int j = 0; j < len; j++) { out[(i * cols) + k] += a[(i * len) + j] * b[(j * cols) + k]; } } } return out; } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/LabColor.java0000644000175000017500000000711510732532577024305 0ustar twernertwerner/* * $Id: LabColor.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.color.ColorSpace; import java.io.IOException; import com.sun.pdfview.PDFObject; /** * A ColorSpace for Lab color * @author Mike Wessler */ public class LabColor extends ColorSpace { float white[]= {1f, 1f, 1f}; float black[]= {0, 0, 0}; float range[]= {-100f, 100f, -100f, 100f}; static ColorSpace cie= ColorSpace.getInstance(ColorSpace.CS_sRGB); /** * Create a new Lab color space object, given the description in * a PDF dictionary. * @param obj a dictionary that contains an Array of 3 Numbers for * "WhitePoint" and "BlackPoint", and an array of 4 Numbers for * "Range". */ public LabColor(PDFObject obj) throws IOException { // obj is a dictionary that has the following parts: // WhitePoint [a b c] // BlackPoint [a b c] // Gamma a super(TYPE_Lab, 3); PDFObject ary= obj.getDictRef("WhitePoint"); if (ary!=null) { for(int i=0; i<3; i++) { white[i]= ary.getAt(i).getFloatValue(); } } ary= obj.getDictRef("BlackPoint"); if (ary!=null) { for(int i=0; i<3; i++) { black[i]= ary.getAt(i).getFloatValue(); } } ary= obj.getDictRef("Range"); if (ary!=null) { for (int i=0; i<4; i++) { range[i]= ary.getAt(i).getFloatValue(); } } } /** * get the number of components for this color space (3) */ @Override public int getNumComponents() { return 3; } /** * Stage 2 of the conversion algorithm. Pulled out because * it gets invoked for each component */ public final float stage2(float s1) { return (s1>=6f/29f)?s1*s1*s1:108f/841f*(s1-4f/29f); } /** * convert from Lab to RGB * @param comp the Lab values (0-1) * @return the RGB values (0-1) */ public float[] toRGB(float comp[]) { if (comp.length==3) { float l= (comp[0]+16)/116+comp[1]/500; float m= (comp[0]+16)/116; float n= (comp[0]+16)/116-comp[2]/200; float xyz[]= { white[0]*stage2(l), white[0]*stage2(m), white[0]*stage2(n)}; float rgb[]= cie.fromCIEXYZ(xyz); return rgb; } else { return black; } } /** * convert from RGB to Lab. NOT IMPLEMENTED */ public float[] fromRGB(float[] rgbvalue) { return new float[3]; } /** * convert from CIEXYZ to Lab. NOT IMPLEMENTED */ public float[] fromCIEXYZ(float[] colorvalue) { return new float[3]; } /** * get the type of this colorspace (TYPE_Lab) */ @Override public int getType() { return TYPE_Lab; } /** * convert from Lab to CIEXYZ. NOT IMPLEMENTED */ public float[] toCIEXYZ(float[] colorvalue) { return new float[3]; } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/PatternSpace.java0000644000175000017500000000642210732532577025201 0ustar twernertwerner/* * $Id: PatternSpace.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.io.IOException; import java.util.Map; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPaint; import com.sun.pdfview.pattern.PDFPattern; /** * A PatternSpace fills with a pattern, the name of which is * specified in the call to getPaint(). This pattern is * read from the resources of the current page. The pattern space * may also have a base color space which the pattern is defined in. */ public class PatternSpace extends PDFColorSpace { private PDFColorSpace base; public PatternSpace() { super(null); } /** * Create a pattern space with the given color space as a base */ public PatternSpace(PDFColorSpace base) { super(null); this.base = base; } /** * Get the base color space */ public PDFColorSpace getBase() { return base; } /** * Get the number of components we want */ @Override public int getNumComponents() { if (base == null) { return 0; } else { return base.getNumComponents(); } } /** * get the PDFPaint representing the color described by the * given color components * @param components the color components corresponding to the given * colorspace * @return a PDFPaint object representing the closest Color to the * given components. */ @Override public PDFPaint getPaint(float[] components) { throw new IllegalArgumentException("Pattern spaces require a pattern " + "name!"); } /** * Get the paint representing a pattern, optionally with the given * base paint. * * @param patternObj the pattern to render * @param components the components of the base paint */ public PDFPaint getPaint(PDFObject patternObj, float[] components, Map resources) throws IOException { PDFPaint basePaint = null; if (getBase() != null) { basePaint = getBase().getPaint(components); } PDFPattern pattern = (PDFPattern) patternObj.getCache(); if (pattern == null) { pattern = PDFPattern.getPattern(patternObj, resources); patternObj.setCache(pattern); } return pattern.getPaint(basePaint); } } pdfrenderer-0.9.0/src/com/sun/pdfview/colorspace/CMYKColorSpace.java0000644000175000017500000000564310732532577025332 0ustar twernertwerner/* * $Id: CMYKColorSpace.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.colorspace; import java.awt.color.ColorSpace; /** * A ColorSpace for the CMYK color space. * * @author Mike Wessler */ public class CMYKColorSpace extends ColorSpace { /** * create a new CMYK color space: a ColorSpace with 4 components */ public CMYKColorSpace() { super(TYPE_CMYK, 4); } /** * Convert from CIEXYZ to RGB. NOT IMPLEMENTED */ public float[] fromCIEXYZ(float[] colorvalue) { return new float[3]; } /** * Convert from RGB to CMYK. * @param rgbvalue the red, green, and blue values (0-1) * @return the CMYK values (0-1) */ public float[] fromRGB(float[] rgbvalue) { float color[]= new float[4]; float c= 1-rgbvalue[0]; float m= 1-rgbvalue[1]; float y= 1-rgbvalue[2]; float k= Math.min(c, Math.min(m, y)); float ik= 1-k; if (ik==0) { c= 1; m= 1; y= 1; } else { c= (c-k)/ik; m= (m-k)/ik; y= (y-k)/ik; } color[0]= c; color[1]= m; color[2]= y; color[3]= k; return color; } /** * the number of components */ @Override public int getNumComponents() { return 4; } /** * the name of this color space */ @Override public String getName(int idx) { return "CMYK"; } /** * the type of this color space (TYPE_CMYK) */ @Override public int getType() { return TYPE_CMYK; } /** * Convert from CMYK to CIEXYZ. NOT IMPLEMENTED */ public float[] toCIEXYZ(float[] colorvalue) { return new float[3]; } /** * Convert from CMYK to RGB. * @param colorvalue the CMYK values (0-1) * @return the RGB values (0-1) */ public float[] toRGB(float[] colorvalue) { if (colorvalue.length==4) { float[] color= new float[3]; float k= colorvalue[3]; float ik= 1-k; color[0]= (1-(colorvalue[0]*ik+k)); color[1]= (1-(colorvalue[1]*ik+k)); color[2]= (1-(colorvalue[2]*ik+k)); return color; } else { return new float[3]; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFPage.java0000644000175000017500000005722311376573573021677 0ustar twernertwerner/* * $Id: PDFPage.java,v 1.7 2010-05-24 22:02:35 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Image; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * A PDFPage encapsulates the parsed commands required to render a * single page from a PDFFile. The PDFPage is not itself drawable; * instead, create a PDFImage to display something on the screen. *

    * This file also contains all of the PDFCmd commands that might * be a part of the command stream in a PDFPage. They probably * should be inner classes of PDFPage instead of separate non-public * classes. * * @author Mike Wessler */ public class PDFPage { /** the array of commands. The length of this array will always * be greater than or equal to the actual number of commands. */ private List commands; /** whether this page has been finished. If true, there will be no * more commands added to the cmds list. */ private boolean finished = false; /** the page number used to find this page */ private int pageNumber; /** * the bounding box of the page, in page coordinates, straight from the page dictionary */ private Rectangle2D pageDictBbox; /** the post-rotation bounding box in page points with the x,y co-ordinates at 0,0 */ private Rectangle2D targetBbox; /** the rotation of this page, in degrees */ private int rotation; /** a map from image info (width, height, clip) to a soft reference to the rendered image */ private Cache cache; /** a map from image info to weak references to parsers that are active */ private Map renderers; /** * create a PDFPage with dimensions in bbox and rotation. */ public PDFPage(Rectangle2D bbox, int rotation) { this(-1, bbox, rotation, null); } /** * create a PDFPage * @param pageNumber the page number * @param bbox the bounding box, specified in pre-rotation page co-ordinates * @param rotation the rotation to apply to the page; must be 0/90/180/270 * @param cache a cache to use */ public PDFPage(int pageNumber, Rectangle2D bbox, int rotation, Cache cache) { this.pageNumber = pageNumber; this.cache = cache; if (bbox == null) { bbox = new Rectangle2D.Double(0, 0, 1, 1); } this.pageDictBbox = bbox; if (rotation < 0) { rotation += 360; } this.rotation = rotation; if (rotation == 0 || rotation == 180) { this.targetBbox = new Rectangle2D.Double( 0, 0, pageDictBbox.getWidth(), pageDictBbox.getHeight()); } else { this.targetBbox = new Rectangle2D.Double( 0, 0, pageDictBbox.getHeight(), pageDictBbox.getWidth()); } // initialize the cache of images and parsers renderers = Collections.synchronizedMap(new HashMap()); // initialize the list of commands commands = Collections.synchronizedList(new ArrayList(250)); } /** * Get the width and height of this image in the correct aspect ratio. * The image returned will have at least one of the width and * height values identical to those requested. The other * dimension may be smaller, so as to keep the aspect ratio * the same as in the original page. * * @param width the maximum width of the image * @param height the maximum height of the image * @param clip the region in page space co-ordinates of the page to * display. It may be null, in which the page crop/media box is used. */ public Dimension getUnstretchedSize(int width, int height, Rectangle2D clip) { if (clip == null) { clip = pageDictBbox; } final boolean swapDimensions = doesRotationSwapDimensions(); final double srcHeight = swapDimensions ? clip.getWidth() : clip.getHeight(); final double srcWidth = swapDimensions ? clip.getHeight() : clip.getWidth(); double ratio = srcHeight / srcWidth; double askratio = (double) height / (double) width; if (askratio > ratio) { // asked for something too high height = (int) (width * ratio + 0.5); } else { // asked for something too wide width = (int) (height / ratio + 0.5); } return new Dimension(width, height); } private boolean doesRotationSwapDimensions() { return getRotation() == 90 || getRotation() == 270; } /** * Get an image producer which can be used to draw the image * represented by this PDFPage. The ImageProducer is guaranteed to * stay in sync with the PDFPage as commands are added to it. * * The image will contain the section of the page specified by the clip, * scaled to fit in the area given by width and height. * * @param width the width of the image to be produced * @param height the height of the image to be produced * @param clip the region in page space of the entire page to * display * @param observer an image observer who will be notified when the * image changes, or null * @return an Image that contains the PDF data */ public Image getImage(int width, int height, Rectangle2D clip, ImageObserver observer) { return getImage(width, height, clip, observer, true, false); } /** * Get an image producer which can be used to draw the image * represented by this PDFPage. The ImageProducer is guaranteed to * stay in sync with the PDFPage as commands are added to it. * * The image will contain the section of the page specified by the clip, * scaled to fit in the area given by width and height. * * @param width the width of the image to be produced * @param height the height of the image to be produced * @param clip the region in page space of the entire page to * display * @param observer an image observer who will be notified when the * image changes, or null * @param drawbg if true, put a white background on the image. If not, * draw no color (alpha 0) for the background. * @param wait if true, do not return until this image is fully rendered. * @return an Image that contains the PDF data */ public Image getImage(int width, int height, Rectangle2D clip, ImageObserver observer, boolean drawbg, boolean wait) { // see if we already have this image BufferedImage image = null; PDFRenderer renderer = null; ImageInfo info = new ImageInfo(width, height, clip, null); if (cache != null) { image = cache.getImage(this, info); renderer = cache.getImageRenderer(this, info); } // not in the cache, so create it if (image == null) { if (drawbg) { info.bgColor = Color.WHITE; } image = new RefImage(info.width, info.height, BufferedImage.TYPE_INT_ARGB); renderer = new PDFRenderer(this, info, image); if (cache != null) { cache.addImage(this, info, image, renderer); } renderers.put(info, new WeakReference(renderer)); } // the renderer may be null if we are getting this image from the // cache and rendering has completed. if (renderer != null) { if (observer != null) { renderer.addObserver(observer); } if (!renderer.isFinished()) { renderer.go(wait); } } // return the image return image; } /** * get the page number used to lookup this page * @return the page number */ public int getPageNumber() { return pageNumber; } /** * get the aspect ratio of the correctly oriented page. * @return the width/height aspect ratio of the page */ public float getAspectRatio() { return getWidth() / getHeight(); } /** * Get the original crop/media box of the page, in page units, before * any rotation and with clipping co-ordinates * @return the page box */ public Rectangle2D getPageBox() { return pageDictBbox; } /** * get the post-rotation box placed at 0, 0 in page units */ public Rectangle2D getBBox() { return targetBbox; } /** * get the width of this page, in page points, after rotation */ public float getWidth() { return (float) targetBbox.getWidth(); } /** * get the height of this page, in page points, after rotation */ public float getHeight() { return (float) targetBbox.getHeight(); } /** * get the rotation of this image */ public int getRotation() { return rotation; } /** * Get the initial transform to map from a specified clip rectangle in * pdf coordinates to an image of the specfied width and * height in device coordinates * * @param width the width of the target image * @param height the height of the target image * @param clip the desired clip rectangle to use in page co-ordinates; * use null to draw the page crop/media box */ public AffineTransform getInitialTransform(int width, int height, Rectangle2D clip) { if (clip == null) { clip = pageDictBbox; } AffineTransform at; switch (getRotation()) { case 0: at = new AffineTransform(1, 0, 0, -1, 0, height); break; case 90: at = new AffineTransform(0, 1, 1, 0, 0, 0); break; case 180: at = new AffineTransform(-1, 0, 0, 1, width, 0); break; case 270: at = new AffineTransform(0, -1, -1, 0, width, height); break; default: throw new IllegalArgumentException("Non-quadrant rotation: " + getRotation()); } // now scale the image to be the size of the clip double scaleX = (doesRotationSwapDimensions() ? height : width) / clip.getWidth(); double scaleY = (doesRotationSwapDimensions() ? width: height) / clip.getHeight(); at.scale(scaleX, scaleY); // create a transform that moves the top left corner of the clip region // (minX, minY) to (0,0) in the image at.translate(-clip.getMinX(), -clip.getMinY()); return at; } /** * get the current number of commands for this page */ public int getCommandCount() { return commands.size(); } /** * get the command at a given index */ public PDFCmd getCommand(int index) { return commands.get(index); } /** * get all the commands in the current page */ public List getCommands() { return commands; } /** * get all the commands in the current page starting at the given index */ public List getCommands(int startIndex) { return getCommands(startIndex, getCommandCount()); } /* * get the commands in the page within the given start and end indices */ public List getCommands(int startIndex, int endIndex) { return commands.subList(startIndex, endIndex); } /** * Add a single command to the page list. */ public void addCommand(PDFCmd cmd) { synchronized (commands) { commands.add(cmd); } // notify any outstanding images updateImages(); } /** * add a collection of commands to the page list. This is probably * invoked as the result of an XObject 'do' command, or through a * type 3 font. */ public void addCommands(PDFPage page) { addCommands(page, null); } /** * add a collection of commands to the page list. This is probably * invoked as the result of an XObject 'do' command, or through a * type 3 font. * @param page the source of other commands. It MUST be finished. * @param extra a transform to perform before adding the commands. * If null, no extra transform will be added. */ public void addCommands(PDFPage page, AffineTransform extra) { synchronized (commands) { addPush(); if (extra != null) { addXform(extra); } //addXform(page.getTransform()); commands.addAll(page.getCommands()); addPop(); } // notify any outstanding images updateImages(); } /** * Clear all commands off the current page */ public void clearCommands() { synchronized (commands) { commands.clear(); } // notify any outstanding images updateImages(); } /** * get whether parsing for this PDFPage has been completed and all * commands are in place. */ public boolean isFinished() { return finished; } /** * wait for finish */ public synchronized void waitForFinish() throws InterruptedException { if (!finished) { wait(); } } /** * Stop the rendering of a particular image on this page */ public void stop(int width, int height, Rectangle2D clip) { ImageInfo info = new ImageInfo(width, height, clip); synchronized (renderers) { // find our renderer WeakReference rendererRef = renderers.get(info); if (rendererRef != null) { PDFRenderer renderer = (PDFRenderer) rendererRef.get(); if (renderer != null) { // stop it renderer.stop(); } } } } /** * The entire page is done. This must only be invoked once. All * observers will be notified. */ public synchronized void finish() { // System.out.println("Page finished!"); finished = true; notifyAll(); // notify any outstanding images updateImages(); } /** push the graphics state */ public void addPush() { addCommand(new PDFPushCmd()); } /** pop the graphics state */ public void addPop() { addCommand(new PDFPopCmd()); } /** concatenate a transform to the graphics state */ public void addXform(AffineTransform at) { // PDFXformCmd xc= lastXformCmd(); // xc.at.concatenate(at); addCommand(new PDFXformCmd(new AffineTransform(at))); } /** * set the stroke width * @param w the width of the stroke */ public void addStrokeWidth(float w) { PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); // if (w == 0) { // w = 0.1f; // } sc.setWidth(w); addCommand(sc); } /** * set the end cap style * @param capstyle the cap style: 0 = BUTT, 1 = ROUND, 2 = SQUARE */ public void addEndCap(int capstyle) { PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); int cap = BasicStroke.CAP_BUTT; switch (capstyle) { case 0: cap = BasicStroke.CAP_BUTT; break; case 1: cap = BasicStroke.CAP_ROUND; break; case 2: cap = BasicStroke.CAP_SQUARE; break; } sc.setEndCap(cap); addCommand(sc); } /** * set the line join style * @param joinstyle the join style: 0 = MITER, 1 = ROUND, 2 = BEVEL */ public void addLineJoin(int joinstyle) { PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); int join = BasicStroke.JOIN_MITER; switch (joinstyle) { case 0: join = BasicStroke.JOIN_MITER; break; case 1: join = BasicStroke.JOIN_ROUND; break; case 2: join = BasicStroke.JOIN_BEVEL; break; } sc.setLineJoin(join); addCommand(sc); } /** * set the miter limit */ public void addMiterLimit(float limit) { PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); sc.setMiterLimit(limit); addCommand(sc); } /** * set the dash style * @param dashary the array of on-off lengths * @param phase offset of the array at the start of the line drawing */ public void addDash(float[] dashary, float phase) { PDFChangeStrokeCmd sc = new PDFChangeStrokeCmd(); sc.setDash(dashary, phase); addCommand(sc); } /** * set the current path * @param path the path * @param style the style: PDFShapeCmd.STROKE, PDFShapeCmd.FILL, * PDFShapeCmd.BOTH, PDFShapeCmd.CLIP, or some combination. */ public void addPath(GeneralPath path, int style) { addCommand(new PDFShapeCmd(path, style)); } /** * set the fill paint */ public void addFillPaint(PDFPaint p) { addCommand(new PDFFillPaintCmd(p)); } /** set the stroke paint */ public void addStrokePaint(PDFPaint p) { addCommand(new PDFStrokePaintCmd(p)); } /** * set the fill alpha */ public void addFillAlpha(float a) { addCommand(new PDFFillAlphaCmd(a)); } /** set the stroke alpha */ public void addStrokeAlpha(float a) { addCommand(new PDFStrokeAlphaCmd(a)); } /** * draw an image * @param image the image to draw */ public void addImage(PDFImage image) { addCommand(new PDFImageCmd(image)); } /** * Notify all images we know about that a command has been added */ public void updateImages() { for (Iterator i = renderers.values().iterator(); i.hasNext();) { WeakReference ref = (WeakReference) i.next(); PDFRenderer renderer = (PDFRenderer) ref.get(); if (renderer != null) { if (renderer.getStatus() == Watchable.NEEDS_DATA) { // there are watchers. Set the state to paused and // let the watcher decide when to start. renderer.setStatus(Watchable.PAUSED); } } } } } /** * draw an image */ class PDFImageCmd extends PDFCmd { PDFImage image; public PDFImageCmd(PDFImage image) { this.image = image; } public Rectangle2D execute(PDFRenderer state) { return state.drawImage(image); } } /** * set the fill paint */ class PDFFillPaintCmd extends PDFCmd { PDFPaint p; public PDFFillPaintCmd(PDFPaint p) { this.p = p; } public Rectangle2D execute(PDFRenderer state) { state.setFillPaint(p); return null; } } /** * set the stroke paint */ class PDFStrokePaintCmd extends PDFCmd { PDFPaint p; public PDFStrokePaintCmd(PDFPaint p) { this.p = p; } public Rectangle2D execute(PDFRenderer state) { state.setStrokePaint(p); return null; } } /** * set the fill paint */ class PDFFillAlphaCmd extends PDFCmd { float a; public PDFFillAlphaCmd(float a) { this.a = a; } public Rectangle2D execute(PDFRenderer state) { state.setFillAlpha(a); return null; } } /** * set the stroke paint */ class PDFStrokeAlphaCmd extends PDFCmd { float a; public PDFStrokeAlphaCmd(float a) { this.a = a; } public Rectangle2D execute(PDFRenderer state) { state.setStrokeAlpha(a); return null; } } /** * push the graphics state */ class PDFPushCmd extends PDFCmd { public Rectangle2D execute(PDFRenderer state) { state.push(); return null; } } /** * pop the graphics state */ class PDFPopCmd extends PDFCmd { public Rectangle2D execute(PDFRenderer state) { state.pop(); return null; } } /** * concatenate a transform to the graphics state */ class PDFXformCmd extends PDFCmd { AffineTransform at; public PDFXformCmd(AffineTransform at) { if (at == null) { throw new RuntimeException("Null transform in PDFXformCmd"); } this.at = at; } public Rectangle2D execute(PDFRenderer state) { state.transform(at); return null; } public String toString(PDFRenderer state) { return "PDFXformCmd: " + at; } @Override public String getDetails() { StringBuffer buf = new StringBuffer(); buf.append("PDFXformCommand: \n"); buf.append(at.toString()); return buf.toString(); } } /** * change the stroke style */ class PDFChangeStrokeCmd extends PDFCmd { float w, limit, phase; int cap, join; float[] ary; public PDFChangeStrokeCmd() { this.w = PDFRenderer.NOWIDTH; this.cap = PDFRenderer.NOCAP; this.join = PDFRenderer.NOJOIN; this.limit = PDFRenderer.NOLIMIT; this.ary = PDFRenderer.NODASH; this.phase = PDFRenderer.NOPHASE; } /** * set the width of the stroke. Rendering needs to account for a minimum * stroke width in creating the output. * * @param w float */ public void setWidth(float w) { this.w = w; } public void setEndCap(int cap) { this.cap = cap; } public void setLineJoin(int join) { this.join = join; } public void setMiterLimit(float limit) { this.limit = limit; } public void setDash(float[] ary, float phase) { if (ary != null) { // make sure no pairs start with 0, since having no opaque // region doesn't make any sense. for (int i = 0; i < ary.length - 1; i += 2) { if (ary[i] == 0) { /* Give a very small value, since 0 messes java up */ ary[i] = 0.00001f; break; } } } this.ary = ary; this.phase = phase; } public Rectangle2D execute(PDFRenderer state) { state.setStrokeParts(w, cap, join, limit, ary, phase); return null; } public String toString(PDFRenderer state) { return "STROKE: w=" + w + " cap=" + cap + " join=" + join + " limit=" + limit + " ary=" + ary + " phase=" + phase; } } pdfrenderer-0.9.0/src/com/sun/pdfview/PDFDocCharsetEncoder.java0000644000175000017500000000715611156177553024334 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.util.HashMap; import java.util.Map; /** * Encodes into a PDFDocEncoding representation. Note that only 256 characters * (if that) are represented in the PDFDocEncoding, so users should be * prepared to deal with unmappable character exceptions. * * @see "PDF Reference version 1.7, Appendix D" * * @author Luke Kirby */ public class PDFDocCharsetEncoder extends CharsetEncoder { /** * Identify whether a particular character preserves the same byte value * upon encoding in PDFDocEncoding * @param ch the character * @return whether the character is identity encoded */ public static boolean isIdentityEncoding(char ch) { return ch >= 0 && ch <= 255 && IDENT_PDF_DOC_ENCODING_MAP[ch]; } /** * For each character that exists in PDFDocEncoding, identifies whether * the byte value in UTF-16BE is the same as it is in PDFDocEncoding */ final static boolean[] IDENT_PDF_DOC_ENCODING_MAP = new boolean[256]; /** * For non-identity encoded characters, maps from the character to * the byte value in PDFDocEncoding. If an entry for a non-identity * coded character is absent from this map, that character is unmappable * in the PDFDocEncoding. */ final static Map EXTENDED_TO_PDF_DOC_ENCODING_MAP = new HashMap(); static { for (byte i = 0; i < PDFStringUtil.PDF_DOC_ENCODING_MAP.length; ++i) { final char c = PDFStringUtil.PDF_DOC_ENCODING_MAP[i]; final boolean identical = (c == i); IDENT_PDF_DOC_ENCODING_MAP[i] = identical; if (!identical) { EXTENDED_TO_PDF_DOC_ENCODING_MAP.put(c, i); } } } public PDFDocCharsetEncoder() { super(null, 1, 1); } protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { while (in.remaining() > 0) { if (out.remaining() < 1) { return CoderResult.OVERFLOW; } final char c = in.get(); if (c >= 0 && c < 256 && IDENT_PDF_DOC_ENCODING_MAP[c]) { out.put((byte) c); } else { final Byte mapped = EXTENDED_TO_PDF_DOC_ENCODING_MAP.get(c); if (mapped != null) { out.put(mapped); } else { return CoderResult.unmappableForLength(1); } } } return CoderResult.UNDERFLOW; } @Override public boolean isLegalReplacement(byte[] repl) { // avoid referencing the non-existent character set return true; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/0000755000175000017500000000000011622545450020546 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/font/BuiltinFont.java0000644000175000017500000001737011157264553023663 0ustar twernertwerner/* * $Id: BuiltinFont.java,v 1.4 2009-03-15 20:47:38 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.Font; import java.io.IOException; import java.io.InputStream; import java.util.Map; import java.util.Properties; import com.sun.pdfview.PDFObject; /** * This class represents the 14 built-in fonts. It reads these fonts * from files in the "res" directory, as specified in * BaseNames.properties. */ public class BuiltinFont extends Type1Font { /** the properties file */ private static Properties props; /** the fonts themselves */ private static Map fonts; /** the names of the 14 base fonts */ private static final String[] baseFonts = { "Courier", "Courier-Bold", "Courier-BoldOblique", "Courier-Oblique", "Helvetica", "Helvetica-Bold", "Helvetica-BoldOblique", "Helvetica-Oblique", "Times-Roman", "Times-Bold", "Times-BoldItalic", "Times-Italic", "Symbol", "ZapfDingbats" }; /** fonts others (e.g. Acrobad PDFWriter 3.02 for Windows) assume * are there, even though they're not in the spec. Grrr... * * the format is */ private static final String[] mappedFonts = { // map arial to helvetica "Arial", "Helvetica", "Arial,Bold", "Helvetica-Bold", "Arial,BoldItalic", "Helvetica-BoldOblique", "Arial,Italic", "Helvetica-Oblique", // map TimesNewRoman to Times "TimesNewRoman", "Times-Roman", "TimesNewRoman,Bold", "Times-Bold", "TimesNewRoman,BoldItalic", "Times-BoldItalic", "TimesNewRoman,Italic", "Times-Italic",}; /** * Create a new Builtin object based on the name of a built-in font * * This must be the name of one of the 14 built-in fonts! * * @param baseFont the name of the font, from the PDF file * @param fontObj the object containing font information */ public BuiltinFont(String baseFont, PDFObject fontObj) throws IOException { super(baseFont, fontObj, null); parseFont(baseFont); } /** * create a new BuiltingFont object based on a description of the * font from the PDF file. Parse the description for key information * and use that to generate an appropriate font. */ public BuiltinFont(String baseFont, PDFObject fontObj, PDFFontDescriptor descriptor) throws IOException { super(baseFont, fontObj, descriptor); String fontName = descriptor.getFontName(); // check if it's one of the 14 base fonts for (int i = 0; i < baseFonts.length; i++) { if (fontName.equalsIgnoreCase(baseFonts[i])) { parseFont(fontName); return; } } // check if it's a mapped font for (int i = 0; i < mappedFonts.length; i += 2) { if (fontName.equalsIgnoreCase(mappedFonts[i])) { parseFont(mappedFonts[i + 1]); return; } } int flags = descriptor.getFlags(); int style = ((flags & PDFFontDescriptor.FORCEBOLD) != 0) ? Font.BOLD : Font.PLAIN; if (fontName.indexOf("Bold") > 0) { style |= Font.BOLD; } if ((descriptor.getItalicAngle() != 0) || ((flags & PDFFontDescriptor.NONSYMBOLIC) != 0)) { style |= Font.ITALIC; } String name = null; if ((flags & PDFFontDescriptor.FIXED_PITCH) != 0) { // fixed width if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0)) { name = "Courier-BoldOblique"; } else if ((style & Font.BOLD) > 0) { name = "Courier-Bold"; } else if ((style & Font.ITALIC) > 0) { name = "Courier-Oblique"; } else { name = "Courier"; } } else if ((flags & PDFFontDescriptor.SERIF) != 0) { // serif font if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0)) { name = "Times-BoldItalic"; } else if ((style & Font.BOLD) > 0) { name = "Times-Bold"; } else if ((style & Font.ITALIC) > 0) { name = "Times-Italic"; } else { name = "Times-Roman"; } } else { if (((style & Font.BOLD) > 0) && ((style & Font.ITALIC) > 0)) { name = "Helvetica-BoldOblique"; } else if ((style & Font.BOLD) > 0) { name = "Helvetica-Bold"; } else if ((style & Font.ITALIC) > 0) { name = "Helvetica-Oblique"; } else { name = "Helvetica"; } } parseFont(name); } /** * Parse a font given only the name of a builtin font */ private void parseFont(String baseFont) throws IOException { // load the base fonts properties files, if it isn't already loaded if (props == null) { props = new Properties(); props.load(BuiltinFont.class.getResourceAsStream("res/BaseFonts.properties")); } // make sure we're a known font if (!props.containsKey(baseFont + ".file")) { throw new IllegalArgumentException("Unknown Base Font: " + baseFont); } // get the font information from the properties file String file = props.getProperty(baseFont + ".file"); // the size of the file int length = Integer.parseInt(props.getProperty(baseFont + ".length")); // the size of the unencrypted portion int length1 = 0; // the size of the encrypted portion int length2 = 0; // read the data from the file byte[] data = new byte[length]; InputStream fontStream = NativeFont.class.getResourceAsStream("res/" + file); int cur = 0; while (cur < length) { cur += fontStream.read(data, cur, length - cur); } fontStream.close(); // are we a pfb file? if ((data[0] & 0xff) == 0x80) { // read lengths from the file length1 = (data[2] & 0xff); length1 |= (data[3] & 0xff) << 8; length1 |= (data[4] & 0xff) << 16; length1 |= (data[5] & 0xff) << 24; length1 += 6; length2 = (data[length1 + 2] & 0xff); length2 |= (data[length1 + 3] & 0xff) << 8; length2 |= (data[length1 + 4] & 0xff) << 16; length2 |= (data[length1 + 5] & 0xff) << 24; length1 += 6; } else { // get the values from the properties file length1 = Integer.parseInt(props.getProperty(baseFont + ".length1")); if (props.containsKey(baseFont + ".length2")) { length2 = Integer.parseInt(props.getProperty(baseFont + ".lenth2")); } else { length2 = length - length1; } } parseFont(data, length1, length2); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/PDFFontDescriptor.java0000644000175000017500000003411211376323412024707 0ustar twernertwerner/* * $Id: PDFFontDescriptor.java,v 1.5 2010-05-23 22:07:05 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.Rectangle2D; import java.io.IOException; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFObject; /** * * @author jkaplan */ public class PDFFontDescriptor { /** All glyphs have the same width. */ public final static int FIXED_PITCH = 1 << (1-1); /** Glyphs have serifs. */ public final static int SERIF = 1 << (2-1); /** Font contains glyphs outside the Adobe standard Latin. */ public final static int SYMBOLIC = 1 << (3-1); /** Glyphs resemble cursive handwriting. */ public final static int SCRIPT = 1 << (4-1); /** Font uses the Adobe standard Latic character set. */ public final static int NONSYMBOLIC = 1 << (6-1); /** Glyphs have dominant vertical strokes that are slanted. */ public final static int ITALIC = 1 << (7-1); /** Font contains no lowercase letters. */ public final static int ALLCAP = 1 << (17-1); /** Font contains both uppercase and lowercase letters.. */ public final static int SMALLCAP = 1 << (18-1); /** Determines whether bold glyphs shall be painted with * extra pixels even at very small text sizes. */ public final static int FORCEBOLD = 1 << (19-1); /** Holds value of property ascent. */ private int ascent; /** Holds value of property capHeight. */ private int capHeight; /** Holds value of property descent. */ private int descent; /** Holds value of property flags. */ private int flags; /** Holds the optional FontFamily (PDF 1.5) */ private String fontFamily; /** Holds value of property fontName. */ private String fontName; /** Holds the optional FontStretch (PDF 1.5) */ private String fontStretch; /** Holds the optional FontWeight (PDF 1.5) */ private int fontWeight; /** Holds value of property italicAngle. */ private int italicAngle; /** Holds value of property stemV. */ private int stemV; /** Holds value of property avgWidth. */ private int avgWidth = 0; /** Holds value of property fontFile. */ private PDFObject fontFile; /** Holds value of property fontFile2. */ private PDFObject fontFile2; /** Holds value of property fontFile3. */ private PDFObject fontFile3; /** Holds value of property leading. */ private int leading = 0; /** Holds value of property maxWidth. */ private int maxWidth = 0; /** Holds value of property misingWidth. */ private int missingWidth = 0; /** Holds value of property stemH. */ private int stemH = 0; /** Holds value of property xHeight. */ private int xHeight = 0; /** Holds value of property charSet. */ private PDFObject charSet; /** Holds value of property fontBBox. */ private Rectangle2D fontBBox; /** Creates a new instance of PDFFontDescriptor */ public PDFFontDescriptor(String basefont) { setFontName(basefont); // [[MW TODO: find basefont info and fill in the rest of the // descriptor?]] } /** Creates a new instance of PDFFontDescriptor */ public PDFFontDescriptor(PDFObject obj) throws IOException { // required parameters setAscent(obj.getDictRef("Ascent").getIntValue()); setCapHeight(obj.getDictRef("CapHeight").getIntValue()); setDescent(obj.getDictRef("Descent").getIntValue()); setFlags(obj.getDictRef("Flags").getIntValue()); setFontName(obj.getDictRef("FontName").getStringValue()); setItalicAngle(obj.getDictRef("ItalicAngle").getIntValue()); setStemV(obj.getDictRef("StemV").getIntValue()); // font bounding box setFontBBox(PDFFile.parseNormalisedRectangle(obj.getDictRef("FontBBox"))); // optional parameters if (obj.getDictionary().containsKey("AvgWidth")) { setAvgWidth(obj.getDictRef("AvgWidth").getIntValue()); } if (obj.getDictionary().containsKey("FontFile")) { setFontFile(obj.getDictRef("FontFile")); } if (obj.getDictionary().containsKey("FontFile2")) { setFontFile2(obj.getDictRef("FontFile2")); } if (obj.getDictionary().containsKey("FontFile3")) { setFontFile3(obj.getDictRef("FontFile3")); } if (obj.getDictionary().containsKey("Leading")) { setLeading(obj.getDictRef("Leading").getIntValue()); } if (obj.getDictionary().containsKey("MaxWidth")) { setMaxWidth(obj.getDictRef("MaxWidth").getIntValue()); } if (obj.getDictionary().containsKey("MissingWidth")) { setMissingWidth(obj.getDictRef("MissingWidth").getIntValue()); } if (obj.getDictionary().containsKey("StemH")) { setStemH(obj.getDictRef("StemH").getIntValue()); } if (obj.getDictionary().containsKey("XHeight")) { setXHeight(obj.getDictRef("XHeight").getIntValue()); } if (obj.getDictionary().containsKey("CharSet")) { setCharSet(obj.getDictRef("CharSet")); } if (obj.getDictionary().containsKey("FontFamily")) { setFontFamily(obj.getDictRef("FontFamily").getStringValue()); } if (obj.getDictionary().containsKey("FontWeight")) { setFontWeight(obj.getDictRef("FontWeight").getIntValue()); } if (obj.getDictionary().containsKey("FontStretch")) { setFontStretch(obj.getDictRef("FontStretch").getStringValue()); } } /** Getter for property ascent. * @return Value of property ascent. * */ public int getAscent() { return this.ascent; } /** Setter for property ascent. * @param ascent New value of property ascent. * */ public void setAscent(int ascent) { this.ascent = ascent; } /** Getter for property capHeight. * @return Value of property capHeight. * */ public int getCapHeight() { return this.capHeight; } /** Setter for property capHeight. * @param capHeight New value of property capHeight. * */ public void setCapHeight(int capHeight) { this.capHeight = capHeight; } /** Getter for property descent. * @return Value of property descent. * */ public int getDescent() { return this.descent; } /** Setter for property descent. * @param descent New value of property descent. * */ public void setDescent(int descent) { this.descent = descent; } /** Getter for property flags. * @return Value of property flags. * */ public int getFlags() { return this.flags; } /** Setter for property flags. * @param flags New value of property flags. * */ public void setFlags(int flags) { this.flags = flags; } /** Getter for property fontFamily. Option (PDF 1.5) * @return Value of the property fontFamily */ public String getFontFamily() { return this.fontFamily; } /** Setter for property fontFamily. * @param fontFamily New value of property fontFamily. * */ public void setFontFamily(String fontFamily) { this.fontFamily = fontFamily; } /** Getter for property fontName. * @return Value of property fontName. * */ public String getFontName() { return this.fontName; } /** Setter for property fontName. * @param fontName New value of property fontName. * */ public void setFontName(String fontName) { this.fontName = fontName; } /** Getter for property fontStretch. Option (PDF 1.5) * * @return Value of the property fontStretch */ public String getFontStretch() { return this.fontStretch; } /** Setter for property fontStretch. Possible values are: * UltraCondensed, ExtraCondensed, Condensed, SemiCondensed, * Normal, SemiExpanded, Expanded, ExtraExpanded or UltraExpanded * We do not check at this time. * * @param fontStretch New value of property fontStretch. * */ public void setFontStretch(String fontStretch) { this.fontStretch = fontStretch; } /** Getter for property fontWeight. Option (PDF 1.5) * * @return Value of the property fontWeight */ public int getFontWeight() { return this.fontWeight; } /** Setter for property fontWeight. Possible values are: * 100, 200, 300, 400, 500, 600, 700, 800, 900 * We do not check at this time. * * @param fontWeight New value of property fontWeight. * */ public void setFontWeight(int fontWeight) { this.fontWeight = fontWeight; } /** Getter for property italicAngle. * @return Value of property italicAngle. * */ public int getItalicAngle() { return this.italicAngle; } /** Setter for property italicAngle. * @param italicAngle New value of property italicAngle. * */ public void setItalicAngle(int italicAngle) { this.italicAngle = italicAngle; } /** Getter for property stemV. * @return Value of property stemV. * */ public int getStemV() { return this.stemV; } /** Setter for property stemV. * @param stemV New value of property stemV. * */ public void setStemV(int stemV) { this.stemV = stemV; } /** Getter for property avgWidth. * @return Value of property avgWidth. * */ public int getAvgWidth() { return this.avgWidth; } /** Setter for property avgWidth. * @param avgWidth New value of property avgWidth. * */ public void setAvgWidth(int avgWidth) { this.avgWidth = avgWidth; } /** Getter for property fontFile. * @return Value of property fontFile. * */ public PDFObject getFontFile() { return this.fontFile; } /** Setter for property fontFile. * @param fontFile New value of property fontFile. * */ public void setFontFile(PDFObject fontFile) { this.fontFile = fontFile; } /** Getter for property fontFile2. * @return Value of property fontFile2. * */ public PDFObject getFontFile2() { return this.fontFile2; } /** Setter for property fontFile2. * @param fontFile2 New value of property fontFile2. * */ public void setFontFile2(PDFObject fontFile2) { this.fontFile2 = fontFile2; } /** Getter for property fontFile3. * @return Value of property fontFile3. * */ public PDFObject getFontFile3() { return this.fontFile3; } /** Setter for property fontFile3. * @param fontFile3 New value of property fontFile3. * */ public void setFontFile3(PDFObject fontFile3) { this.fontFile3 = fontFile3; } /** Getter for property leading. * @return Value of property leading. * */ public int getLeading() { return this.leading; } /** Setter for property leading. * @param leading New value of property leading. * */ public void setLeading(int leading) { this.leading = leading; } /** Getter for property maxWidth. * @return Value of property maxWidth. * */ public int getMaxWidth() { return this.maxWidth; } /** Setter for property maxWidth. * @param maxWidth New value of property maxWidth. * */ public void setMaxWidth(int maxWidth) { this.maxWidth = maxWidth; } /** Getter for property misingWidth. * @return Value of property misingWidth. * */ public int getMissingWidth() { return this.missingWidth; } /** Setter for property misingWidth. * @param missingWidth New value of property misingWidth. */ public void setMissingWidth(int missingWidth) { this.missingWidth = missingWidth; } /** Getter for property stemH. * @return Value of property stemH. * */ public int getStemH() { return this.stemH; } /** Setter for property stemH. * @param stemH New value of property stemH. * */ public void setStemH(int stemH) { this.stemH = stemH; } /** Getter for property xHeight. * @return Value of property xHeight. * */ public int getXHeight() { return this.xHeight; } /** Setter for property xHeight. * @param xHeight New value of property xHeight. * */ public void setXHeight(int xHeight) { this.xHeight = xHeight; } /** Getter for property charSet. * @return Value of property charSet. * */ public PDFObject getCharSet() { return this.charSet; } /** Setter for property charSet. * @param charSet New value of property charSet. * */ public void setCharSet(PDFObject charSet) { this.charSet = charSet; } /** Getter for property fontBBox. * @return Value of property fontBBox. * */ public Rectangle2D getFontBBox() { return this.fontBBox; } /** Setter for property fontBBox. * @param fontBBox New value of property fontBBox. * */ public void setFontBBox(Rectangle2D fontBBox) { this.fontBBox = fontBBox; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/0000755000175000017500000000000011622545450021343 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/HmtxTable.java0000644000175000017500000001041611131135415024067 0ustar twernertwerner/* * $Id: HmtxTable.java,v 1.3 2009-01-07 14:24:13 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.util.Arrays; /** * Model the TrueType Post table * * @author jkaplan */ public class HmtxTable extends TrueTypeTable { /** advance widths for any glyphs that have one */ short advanceWidths[]; /** left side bearings for each glyph */ short leftSideBearings[]; /** Creates a new instance of HmtxTable */ protected HmtxTable(TrueTypeFont ttf) { super (TrueTypeTable.HMTX_TABLE); // the number of glyphs stored in the maxp table may be incorrect // in the case of subsetted fonts produced by some pdf generators MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); int numGlyphs = maxp.getNumGlyphs(); HheaTable hhea = (HheaTable) ttf.getTable("hhea"); int numOfLongHorMetrics = hhea.getNumOfLongHorMetrics(); advanceWidths = new short[numOfLongHorMetrics]; leftSideBearings = new short[numGlyphs]; } /** get the advance of a given glyph */ public short getAdvance(int glyphID) { if (glyphID < advanceWidths.length) { return advanceWidths[glyphID]; } else { return advanceWidths[advanceWidths.length - 1]; } } /** get the left side bearing of a given glyph */ public short getLeftSideBearing(int glyphID) { return leftSideBearings[glyphID]; } /** get the data in this map as a ByteBuffer */ public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); // write the metrics for (int i = 0; i < leftSideBearings.length; i++) { if (i < advanceWidths.length) { buf.putShort(advanceWidths[i]); } buf.putShort(leftSideBearings[i]); } // reset the start pointer buf.flip(); return buf; } /** Initialize this structure from a ByteBuffer */ public void setData(ByteBuffer data) { // some PDF writers subset the font but don't update the number of glyphs in the maxp table, // this would appear to break the TTF spec. // A better solution might be to try and override the numGlyphs in the maxp table based // on the number of entries in the cmap table or by parsing the glyf table, but this // appears to be the only place that gets affected by the discrepancy... so far!... // so updating this allows it to work. int i; // only read as much data as is available for (i = 0; i < leftSideBearings.length && data.hasRemaining(); i++) { if (i < advanceWidths.length) { advanceWidths[i] = data.getShort(); } leftSideBearings[i] = data.getShort(); } // initialise the remaining advanceWidths and leftSideBearings to 0 if (i < advanceWidths.length) { Arrays.fill(advanceWidths, i, advanceWidths.length-1, (short) 0); } if (i < leftSideBearings.length) { Arrays.fill(leftSideBearings, i, leftSideBearings.length-1, (short) 0); } } /** * Get the length of this table */ public int getLength() { return (advanceWidths.length * 2) + (leftSideBearings.length * 2); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/AdobeGlyphList.java0000644000175000017500000001551511150540317025060 0ustar twernertwernerpackage com.sun.pdfview.font.ttf; import java.io.*; import java.util.*; /** * Build an object which provides access to all the Adobe glyph names, using * a unicode value, and which can translate a glyph name to one or more * unicode values. * # ################################################################################### # Copyright (c) 1997,1998,2002,2007 Adobe Systems Incorporated # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this documentation file to use, copy, publish, distribute, # sublicense, and/or sell copies of the documentation, and to permit # others to do the same, provided that: # - No modification, editing or other alteration of this document is # allowed; and # - The above copyright notice and this permission notice shall be # included in all copies of the documentation. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this documentation file, to create their own derivative works # from the content of this document to use, copy, publish, distribute, # sublicense, and/or sell the derivative works, and to permit others to do # the same, provided that the derived work is not represented as being a # copy or version of this document. # # Adobe shall not be liable to any party for any loss of revenue or profit # or for indirect, incidental, special, consequential, or other similar # damages, whether based on tort (including without limitation negligence # or strict liability), contract or other legal or equitable grounds even # if Adobe has been advised or had reason to know of the possibility of # such damages. The Adobe materials are provided on an "AS IS" basis. # Adobe specifically disclaims all express, statutory, or implied # warranties relating to the Adobe materials, including but not limited to # those concerning merchantability or fitness for a particular purpose or # non-infringement of any third party rights regarding the Adobe # materials. # ################################################################################### # Name: Adobe Glyph List # Table version: 2.0 # Date: September 20, 2002 # # See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html # # Format: Semicolon-delimited fields: # (1) glyph name # (2) Unicode scalar value * * @author tomoke */ public class AdobeGlyphList { /** provide a translation from a glyph name to the possible unicode values. */ static private HashMap glyphToUnicodes; /** provide a translation from a unicode value to a glyph name. */ static private HashMap unicodeToGlyph; /** the loader thread we are reading through. */ static Thread glyphLoaderThread = null; static { new AdobeGlyphList(); } /** *

    private constructor to restrict creation to a singleton.

    * *

    We initialize by creating the storage and parsing the glyphlist * into the tables.

    */ private AdobeGlyphList() { glyphToUnicodes = new HashMap(4500); unicodeToGlyph = new HashMap(4500); glyphLoaderThread = new Thread(new Runnable() { public void run() { int[] codes; StringTokenizer codeTokens; String glyphName; StringTokenizer tokens; ArrayList unicodes = new ArrayList(); InputStream istr = getClass().getResourceAsStream("/com/sun/pdfview/font/ttf/resource/glyphlist.txt"); BufferedReader reader = new BufferedReader(new InputStreamReader(istr)); String line = ""; while (line != null) { try { unicodes.clear(); line = reader.readLine(); if (line == null) { break; } line = line.trim(); if (line.length() > 0 && !line.startsWith("#")) { // ignore comment lines tokens = new StringTokenizer(line, ";"); glyphName = tokens.nextToken(); codeTokens = new StringTokenizer(tokens.nextToken(), " "); while (codeTokens.hasMoreTokens()) { unicodes.add(codeTokens.nextToken()); } codes = new int[unicodes.size()]; for (int i = 0; i < unicodes.size(); i++) { codes[i] = Integer.parseInt(unicodes.get(i), 16); unicodeToGlyph.put(new Integer(codes[i]), glyphName); } glyphToUnicodes.put(glyphName, codes); } } catch (IOException ex) { break; } } } }, "Adobe Glyph Loader Thread"); glyphLoaderThread.setDaemon(true); glyphLoaderThread.setPriority(Thread.MIN_PRIORITY); glyphLoaderThread.start(); } /** * translate a glyph name into the possible unicode values that it * might represent. It is possible to have more than one unicode * value for a single glyph name. * * @param glyphName * @return int[] */ public static int[] getUnicodeValues(String glyphName) { while (glyphLoaderThread != null && glyphLoaderThread.isAlive()) { synchronized (glyphToUnicodes) { try { glyphToUnicodes.wait(250); } catch (InterruptedException ex) { // ignore } } } return glyphToUnicodes.get(glyphName); } /** * return a single index for a glyph, though there may be multiples. * * @param glyphName * @return Integer */ public static Integer getGlyphNameIndex(String glyphName) { int [] unicodes = getUnicodeValues(glyphName); if (unicodes == null) { return null; } else { return new Integer(unicodes[0]); } } /** * translate a unicode value into a glyph name. It is possible for * different unicode values to translate into the same glyph name. * * @param unicode * @return String */ public static String getGlyphName(int unicode) { while (glyphLoaderThread != null && glyphLoaderThread.isAlive()) { synchronized (glyphToUnicodes) { try { glyphToUnicodes.wait(250); } catch (InterruptedException ex) { // ignore } } } return unicodeToGlyph.get(new Integer(unicode)); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/CMap.java0000644000175000017500000001270611157264553023041 0ustar twernertwerner/* * $Id: CMap.java,v 1.4 2009-03-15 20:47:38 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * * @author jkaplan */ public abstract class CMap { /** * The format of this map */ private short format; /** * The language of this map, or 0 for language-independent */ private short language; /** Creates a new instance of CMap * Don't use this directly, use CMap.createMap() */ protected CMap (short format, short language) { this.format = format; this.language = language; } /** * Create a map for the given format and language *

    The Macintosh standard character to glyph mapping is supported * by format 0.

    * *

    Format 2 supports a mixed 8/16 bit mapping useful for Japanese, * Chinese and Korean.

    * *

    Format 4 is used for 16 bit mappings.

    * *

    Format 6 is used for dense 16 bit mappings.

    * *

    Formats 8, 10, and 12 (properly 8.0, 10.0, and 12.0) are used * for mixed 16/32-bit and pure 32-bit mappings.
    * This supports text encoded with surrogates in Unicode 2.0 and later.

    * *

    Reference:
    * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6cmap.html

    */ public static CMap createMap (short format, short language) { CMap outMap = null; switch (format) { case 0: // CMap format 0 - single byte codes outMap = new CMapFormat0 (language); break; case 4: // CMap format 4 - two byte encoding outMap = new CMapFormat4 (language); break; case 6: // CMap format 6 - 16-bit, two byte encoding outMap = new CMapFormat6 (language); break; // case 8: // CMap format 8 - Mixed 16-bit and 32-bit coverage // outMap = new CMapFormat_8(language); // break; // // CMap format 10 - Format 10.0 is a bit like format 6, in that it // // defines a trimmed array for a tight range of 32-bit character codes: // case 10: // outMap = new CMapFormat_10(language); // break; // // Format 12.0 is a bit like format 4, in that it defines // // segments for sparse representation in 4-byte character space. // case 12: // CMap format 12 - // outMap = new CMapFormat_12(language); // break; default: System.out.println ("Unsupport CMap format: " + format); return null; } return outMap; } /** * Get a map from the given data * * This method reads the format, data and length variables of * the map. */ public static CMap getMap (ByteBuffer data) { short format = data.getShort (); short lengthShort = data.getShort (); int length = 0xFFFF & (int) lengthShort; // System.out.println ( // "CMAP, length: " + length + ", short: " + lengthShort); // make sure our slice of the data only contains up to the length // of this table data.limit (Math.min (length, data.limit ())); short language = data.getShort (); CMap outMap = createMap (format, language); if (outMap == null) { return null; } outMap.setData (data.limit (), data); return outMap; } /** * Get the format of this map */ public short getFormat () { return format; } /** * Get the language of this map */ public short getLanguage () { return language; } /** * Set the data for this map */ public abstract void setData (int length, ByteBuffer data); /** * Get the data in this map as a byte buffer */ public abstract ByteBuffer getData (); /** * Get the length of this map */ public abstract short getLength (); /** * Map an 8 bit value to another 8 bit value */ public abstract byte map (byte src); /** * Map a 16 bit value to another 16 but value */ public abstract char map (char src); /** * Get the src code which maps to the given glyphID */ public abstract char reverseMap (short glyphID); /** Print a pretty string */ @Override public String toString () { String indent = " "; return indent + " format: " + getFormat () + " length: " + getLength () + " language: " + getLanguage () + "\n"; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/NameTable.java0000644000175000017500000003120311145024767024040 0ustar twernertwerner/* * $Id: NameTable.java,v 1.4 2009-02-12 13:53:57 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Collections; import java.util.Iterator; import java.util.SortedMap; import java.util.TreeMap; /** * * @author jon */ public class NameTable extends TrueTypeTable { /** * Values for platformID */ public static final short PLATFORMID_UNICODE = 0; public static final short PLATFORMID_MACINTOSH = 1; public static final short PLATFORMID_MICROSOFT = 3; /** * Values for platformSpecificID if platform is Mac */ public static final short ENCODINGID_MAC_ROMAN = 0; /** * Values for platformSpecificID if platform is Unicode */ public static final short ENCODINGID_UNICODE_DEFAULT = 0; public static final short ENCODINGID_UNICODE_V11 = 1; public static final short ENCODINGID_UNICODE_V2 = 3; /** * Values for language ID if platform is Mac */ public static final short LANGUAGEID_MAC_ENGLISH = 0; /** * Values for nameID */ public static final short NAMEID_COPYRIGHT = 0; public static final short NAMEID_FAMILY = 1; public static final short NAMEID_SUBFAMILY = 2; public static final short NAMEID_SUBFAMILY_UNIQUE = 3; public static final short NAMEID_FULL_NAME = 4; public static final short NAMEID_VERSION = 5; public static final short NAMEID_POSTSCRIPT_NAME = 6; public static final short NAMEID_TRADEMARK = 7; /** * The format of this table */ private short format; /** * The actual name records */ private SortedMap records; /** Creates a new instance of NameTable */ protected NameTable() { super (TrueTypeTable.NAME_TABLE); records = Collections.synchronizedSortedMap(new TreeMap()); } /** * Add a record to the table */ public void addRecord(short platformID, short platformSpecificID, short languageID, short nameID, String value) { NameRecord rec = new NameRecord(platformID, platformSpecificID, languageID, nameID); records.put(rec, value); } /** * Get a record from the table */ public String getRecord(short platformID, short platformSpecificID, short languageID, short nameID) { NameRecord rec = new NameRecord(platformID, platformSpecificID, languageID, nameID); return (String) records.get(rec); } /** * Remove a record from the table */ public void removeRecord(short platformID, short platformSpecificID, short languageID, short nameID) { NameRecord rec = new NameRecord(platformID, platformSpecificID, languageID, nameID); records.remove(rec); } /** * Determine if we have any records with a given platform ID */ public boolean hasRecords(short platformID) { for (Iterator i = records.keySet().iterator(); i.hasNext(); ) { NameRecord rec = (NameRecord) i.next(); if (rec.platformID == platformID) { return true; } } return false; } /** * Determine if we have any records with a given platform ID and * platform-specific ID */ public boolean hasRecords(short platformID, short platformSpecificID) { for (Iterator i = records.keySet().iterator(); i.hasNext(); ) { NameRecord rec = (NameRecord) i.next(); if (rec.platformID == platformID && rec.platformSpecificID == platformSpecificID) { return true; } } return false; } /** * Read the table from data */ public void setData(ByteBuffer data) { //read table header setFormat(data.getShort()); int count = data.getShort(); int stringOffset = data.getShort(); // read the records for (int i = 0; i < count; i++) { short platformID = data.getShort(); short platformSpecificID = data.getShort(); short languageID = data.getShort(); short nameID = data.getShort(); int length = data.getShort() & 0xFFFF; int offset = data.getShort() & 0xFFFF; // read the String data data.mark(); data.position(stringOffset + offset); ByteBuffer stringBuf = data.slice(); stringBuf.limit(length); data.reset(); // choose the character set String charsetName = getCharsetName(platformID, platformSpecificID); Charset charset = Charset.forName(charsetName); // parse the data as a string String value = charset.decode(stringBuf).toString(); // add to the mix addRecord(platformID, platformSpecificID, languageID, nameID, value); } } /** * Get the data in this table as a buffer */ public ByteBuffer getData() { // alocate the output buffer ByteBuffer buf = ByteBuffer.allocate(getLength()); // the start of string data short headerLength = (short) (6 + (12 * getCount())); // write the header buf.putShort(getFormat()); buf.putShort(getCount()); buf.putShort(headerLength); // the offset from the start of the strings table short curOffset = 0; // add the size of each record for (Iterator i = records.keySet().iterator(); i.hasNext();) { NameRecord rec = (NameRecord) i.next(); String value = (String) records.get(rec); // choose the charset String charsetName = getCharsetName(rec.platformID, rec.platformSpecificID); Charset charset = Charset.forName(charsetName); // encode ByteBuffer strBuf = charset.encode(value); short strLen = (short) (strBuf.remaining() & 0xFFFF); // write the IDs buf.putShort(rec.platformID); buf.putShort(rec.platformSpecificID); buf.putShort(rec.languageID); buf.putShort(rec.nameID); // write the size and offset buf.putShort(strLen); buf.putShort(curOffset); // remember or current position buf.mark(); // move to the current offset and write the data buf.position(headerLength + curOffset); buf.put(strBuf); // reset stuff buf.reset(); // increment offset curOffset += strLen; } // reset the pointer on the buffer buf.position(headerLength + curOffset); buf.flip(); return buf; } /** * Get the length of this table */ public int getLength() { // start with the size of the fixed header plus the size of the // records int length = 6 + (12 * getCount()); // add the size of each record for (Iterator i = records.keySet().iterator(); i.hasNext();) { NameRecord rec = (NameRecord) i.next(); String value = (String) records.get(rec); // choose the charset String charsetName = getCharsetName(rec.platformID, rec.platformSpecificID); Charset charset = Charset.forName(charsetName); // encode ByteBuffer buf = charset.encode(value); // add the size of the coded buffer length += buf.remaining(); } return length; } /** * Get the format of this table */ public short getFormat() { return format; } /** * Set the format of this table */ public void setFormat(short format) { this.format = format; } /** * Get the number of records in the table */ public short getCount() { return (short) records.size(); } /** * Get the charset name for a given platform, encoding and language */ public static String getCharsetName(int platformID, int encodingID) { String charset = "US-ASCII"; switch (platformID) { case PLATFORMID_UNICODE: charset = "UTF-16"; break; case PLATFORMID_MICROSOFT: charset = "UTF-16"; break; } return charset; } /** Get a pretty string */ public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Format: " + getFormat() + "\n"); buf.append(indent + "Count : " + getCount() + "\n"); for (Iterator i = records.keySet().iterator(); i.hasNext();) { NameRecord rec = (NameRecord) i.next(); buf.append(indent + " platformID: " + rec.platformID); buf.append(" platformSpecificID: " + rec.platformSpecificID); buf.append(" languageID: " + rec.languageID); buf.append(" nameID: " + rec.nameID + "\n"); buf.append(indent + " " + records.get(rec) + "\n"); } return buf.toString(); } /** * A class to hold the data associated with each record */ class NameRecord implements Comparable { /** * Platform ID */ short platformID; /** * Platform Specific ID (Encoding) */ short platformSpecificID; /** * Language ID */ short languageID; /** * Name ID */ short nameID; /** * Create a new record */ NameRecord(short platformID, short platformSpecificID, short languageID, short nameID) { this.platformID = platformID; this.platformSpecificID = platformSpecificID; this.languageID = languageID; this.nameID = nameID; } /** * Compare two records */ public boolean equals(Object o) { return (compareTo(o) == 0); } /** * Compare two records */ public int compareTo(Object obj) { if (!(obj instanceof NameRecord)) { return -1; } NameRecord rec = (NameRecord) obj; if (platformID > rec.platformID) { return 1; } else if (platformID < rec.platformID) { return -1; } else if (platformSpecificID > rec.platformSpecificID) { return 1; } else if (platformSpecificID < rec.platformSpecificID) { return -1; } else if (languageID > rec.languageID) { return 1; } else if (languageID < rec.languageID) { return -1; } else if (nameID > rec.nameID) { return 1; } else if (nameID < rec.nameID) { return -1; } else { return 0; } } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/HheaTable.java0000644000175000017500000002566511133763517024044 0ustar twernertwerner/* * $Id: HheaTable.java,v 1.4 2009-01-16 01:47:59 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * * @author jkaplan */ public class HheaTable extends TrueTypeTable { /** Holds value of property version. */ private int version; /** Holds value of property ascent. */ private short ascent; /** Holds value of property descent. */ private short descent; /** Holds value of property lineGap. */ private short lineGap; /** Holds value of property advanceWidthMax. */ private short advanceWidthMax; /** Holds value of property minLeftSideBearing. */ private short minLeftSideBearing; /** Holds value of property minRightSideBearing. */ private short minRightSideBearing; /** Holds value of property xMaxExtent. */ private short xMaxExtent; /** Holds value of property caretSlopeRise. */ private short caretSlopeRise; /** Holds value of property caretSlopeRun. */ private short caretSlopeRun; /** Holds value of property caretOffset. */ private short caretOffset; /** Holds value of property metricDataFormat. */ private short metricDataFormat; /** Holds value of property numOfLongHorMetrics. */ private short numOfLongHorMetrics; /** Creates a new instance of HeadTable * Makes up reasonable(?) defaults for all values */ protected HheaTable() { super(TrueTypeTable.HEAD_TABLE); setVersion(0x10000); } /** * Parse the data before it is set */ public void setData(ByteBuffer data) { if (data.remaining() != 36) { throw new IllegalArgumentException("Bad Head table size"); } setVersion(data.getInt()); setAscent(data.getShort()); setDescent(data.getShort()); setLineGap(data.getShort()); setAdvanceWidthMax(data.getShort()); setMinLeftSideBearing(data.getShort()); setMinRightSideBearing(data.getShort()); setXMaxExtent(data.getShort()); setCaretSlopeRise(data.getShort()); setCaretSlopeRun(data.getShort()); setCaretOffset(data.getShort()); // padding data.getShort(); data.getShort(); data.getShort(); data.getShort(); setMetricDataFormat(data.getShort()); setNumOfLongHorMetrics(data.getShort()); } /** * Get the data we have stored */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putInt(getVersion()); buf.putShort(getAscent()); buf.putShort(getDescent()); buf.putShort(getLineGap()); buf.putShort(getAdvanceWidthMax()); buf.putShort(getMinLeftSideBearing()); buf.putShort(getMinRightSideBearing()); buf.putShort(getXMaxExtent()); buf.putShort(getCaretSlopeRise()); buf.putShort(getCaretSlopeRun()); buf.putShort(getCaretOffset()); // padding buf.putShort((short) 0); buf.putShort((short) 0); buf.putShort((short) 0); buf.putShort((short) 0); buf.putShort(getMetricDataFormat()); buf.putShort((short) getNumOfLongHorMetrics()); // reset the position to the start of the buffer buf.flip(); return buf; } /** * Get the length of this table */ public int getLength() { return 36; } /** Getter for property version. * @return Value of property version. * */ public int getVersion() { return version; } /** Setter for property version. * @param version New value of property version. * */ public void setVersion(int version) { this.version = version; } /** * Create a pretty string */ public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Version : " + Integer.toHexString(getVersion()) + "\n"); buf.append(indent + "Ascent : " + getAscent() + "\n"); buf.append(indent + "Descent : " + getDescent() + "\n"); buf.append(indent + "LineGap : " + getLineGap() + "\n"); buf.append(indent + "AdvanceWidthMax : " + getAdvanceWidthMax() + "\n"); buf.append(indent + "MinLSB : " + getMinLeftSideBearing() + "\n"); buf.append(indent + "MinRSB : " + getMinRightSideBearing() + "\n"); buf.append(indent + "MaxExtent : " + getXMaxExtent() + "\n"); buf.append(indent + "CaretSlopeRise : " + getCaretSlopeRise() + "\n"); buf.append(indent + "CaretSlopeRun : " + getCaretSlopeRun() + "\n"); buf.append(indent + "CaretOffset : " + getCaretOffset() + "\n"); buf.append(indent + "MetricDataFormat : " + getMetricDataFormat() + "\n"); buf.append(indent + "NumOfLongHorMetrics : " + getNumOfLongHorMetrics() + "\n"); return buf.toString(); } /** Getter for property ascent. * @return Value of property ascent. * */ public short getAscent() { return this.ascent; } /** Setter for property ascent. * @param ascent New value of property ascent. * */ public void setAscent(short ascent) { this.ascent = ascent; } /** Getter for property descent. * @return Value of property descent. * */ public short getDescent() { return this.descent; } /** Setter for property descent. * @param descent New value of property descent. * */ public void setDescent(short descent) { this.descent = descent; } /** Getter for property lineGap. * @return Value of property lineGap. * */ public short getLineGap() { return this.lineGap; } /** Setter for property lineGap. * @param lineGap New value of property lineGap. * */ public void setLineGap(short lineGap) { this.lineGap = lineGap; } /** Getter for property advanceWidthMax. * @return Value of property advanceWidthMax. * */ public short getAdvanceWidthMax() { return this.advanceWidthMax; } /** Setter for property advanceWidthMax. * @param advanceWidthMax New value of property advanceWidthMax. * */ public void setAdvanceWidthMax(short advanceWidthMax) { this.advanceWidthMax = advanceWidthMax; } /** Getter for property minLeftSideBearing. * @return Value of property minLeftSideBearing. * */ public short getMinLeftSideBearing() { return this.minLeftSideBearing; } /** Setter for property minLeftSideBearing. * @param minLeftSideBearing New value of property minLeftSideBearing. * */ public void setMinLeftSideBearing(short minLeftSideBearing) { this.minLeftSideBearing = minLeftSideBearing; } /** Getter for property minRIghtSideBearing. * @return Value of property minRIghtSideBearing. * */ public short getMinRightSideBearing() { return this.minRightSideBearing; } /** Setter for property minRIghtSideBearing. * @param minRightSideBearing New value of property minRIghtSideBearing. * */ public void setMinRightSideBearing(short minRightSideBearing) { this.minRightSideBearing = minRightSideBearing; } /** Getter for property xMaxExtent. * @return Value of property xMaxExtent. * */ public short getXMaxExtent() { return this.xMaxExtent; } /** Setter for property xMaxExtent. * @param xMaxExtent New value of property xMaxExtent. * */ public void setXMaxExtent(short xMaxExtent) { this.xMaxExtent = xMaxExtent; } /** Getter for property caretSlopeRise. * @return Value of property caretSlopeRise. * */ public short getCaretSlopeRise() { return this.caretSlopeRise; } /** Setter for property caretSlopeRise. * @param caretSlopeRise New value of property caretSlopeRise. * */ public void setCaretSlopeRise(short caretSlopeRise) { this.caretSlopeRise = caretSlopeRise; } /** Getter for property caretSlopeRun. * @return Value of property caretSlopeRun. * */ public short getCaretSlopeRun() { return this.caretSlopeRun; } /** Setter for property caretSlopeRun. * @param caretSlopeRun New value of property caretSlopeRun. * */ public void setCaretSlopeRun(short caretSlopeRun) { this.caretSlopeRun = caretSlopeRun; } /** Getter for property caretOffset. * @return Value of property caretOffset. * */ public short getCaretOffset() { return this.caretOffset; } /** Setter for property caretOffset. * @param caretOffset New value of property caretOffset. * */ public void setCaretOffset(short caretOffset) { this.caretOffset = caretOffset; } /** Getter for property metricDataFormat. * @return Value of property metricDataFormat. * */ public short getMetricDataFormat() { return this.metricDataFormat; } /** Setter for property metricDataFormat. * @param metricDataFormat New value of property metricDataFormat. * */ public void setMetricDataFormat(short metricDataFormat) { this.metricDataFormat = metricDataFormat; } /** Getter for property numOfLongHorMetrics. * @return Value of property numOfLongHorMetrics. * */ public int getNumOfLongHorMetrics() { return this.numOfLongHorMetrics & 0xFFFF; } /** Setter for property numOfLongHorMetrics. * @param numOfLongHorMetrics New value of property numOfLongHorMetrics. * */ public void setNumOfLongHorMetrics(short numOfLongHorMetrics) { this.numOfLongHorMetrics = numOfLongHorMetrics; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/LocaTable.java0000644000175000017500000000650511157172615024044 0ustar twernertwerner/* * $Id: LocaTable.java,v 1.3 2009-03-15 12:33:17 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * Model the TrueType Loca table */ public class LocaTable extends TrueTypeTable { /** if true, the table stores glyphs in long format */ private boolean isLong; /** the offsets themselves */ private int offsets[]; /** Creates a new instance of HmtxTable */ protected LocaTable(TrueTypeFont ttf) { super (TrueTypeTable.LOCA_TABLE); MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); int numGlyphs = maxp.getNumGlyphs(); HeadTable head = (HeadTable) ttf.getTable("head"); short format = head.getIndexToLocFormat(); isLong = (format == 1); offsets = new int[numGlyphs + 1]; } /** * get the offset, in bytes, of a given glyph from the start of * the glyph table */ public int getOffset(int glyphID) { return offsets[glyphID]; } /** * get the size, in bytes, of the given glyph */ public int getSize(int glyphID) { return offsets[glyphID + 1] - offsets[glyphID]; } /** * Return true if the glyphs arte in long (int) format, or * false if they are in short (short) format */ public boolean isLongFormat() { return isLong; } /** get the data in this map as a ByteBuffer */ public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); // write the offsets for (int i = 0; i < offsets.length; i++) { if (isLongFormat()) { buf.putInt(offsets[i]); } else { buf.putShort((short) (offsets[i] / 2)); } } // reset the start pointer buf.flip(); return buf; } /** Initialize this structure from a ByteBuffer */ public void setData(ByteBuffer data) { for (int i = 0; i < offsets.length; i++) { if (isLongFormat()) { offsets[i] = data.getInt(); } else { offsets[i] = 2 * ( 0xFFFF & (int) data.getShort()); } } } /** * Get the length of this table */ public int getLength() { if (isLongFormat()) { return offsets.length * 4; } else { return offsets.length * 2; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/HeadTable.java0000644000175000017500000003217110732532577024032 0ustar twernertwerner/* * $Id: HeadTable.java,v 1.3 2007-12-20 18:33:30 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.util.Date; /** * * @author jkaplan */ public class HeadTable extends TrueTypeTable { /** Holds value of property version. */ private int version; /** Holds value of property fontRevision. */ private int fontRevision; /** Holds value of property checksumAdjustment. */ private int checksumAdjustment; /** Holds value of property magicNumber. */ private int magicNumber; /** Holds value of property flags. */ private short flags; /** Holds value of property unitsPerEm. */ private short unitsPerEm; /** Holds value of property created. */ private long created; /** Holds value of property modified. */ private long modified; /** Holds value of property xMin. */ private short xMin; /** Holds value of property yMin. */ private short yMin; /** Holds value of property xMax. */ private short xMax; /** Holds value of property yMax. */ private short yMax; /** Holds value of property macStyle. */ private short macStyle; /** Holds value of property lowestRecPPem. */ private short lowestRecPPem; /** Holds value of property fontDirectionHint. */ private short fontDirectionHint; /** Holds value of property indexToLocFormat. */ private short indexToLocFormat; /** Holds value of property glyphDataFormat. */ private short glyphDataFormat; /** Creates a new instance of HeadTable * Makes up reasonable(?) defaults for all values */ protected HeadTable() { super(TrueTypeTable.HEAD_TABLE); setVersion(0x10000); setFontRevision(0x10000); setChecksumAdjustment(0); setMagicNumber(0x5f0f3cf5); setFlags((short) 0x0); setUnitsPerEm((short) 64); setCreated(System.currentTimeMillis()); setModified(System.currentTimeMillis()); setXMin((short) 0); setXMax((short) Short.MAX_VALUE); setYMin((short) 0); setYMax((short) Short.MAX_VALUE); setMacStyle((short) 0x0); setLowestRecPPem((short) 0); setFontDirectionHint((short) 0); setIndexToLocFormat((short) 0); setGlyphDataFormat((short) 0); } /** * Parse the data before it is set */ public void setData(ByteBuffer data) { if (data.remaining() != 54) { throw new IllegalArgumentException("Bad Head table size"); } setVersion(data.getInt()); setFontRevision(data.getInt()); setChecksumAdjustment(data.getInt()); setMagicNumber(data.getInt()); setFlags(data.getShort()); setUnitsPerEm(data.getShort()); setCreated(data.getLong()); setModified(data.getLong()); setXMin(data.getShort()); setXMax(data.getShort()); setYMin(data.getShort()); setYMax(data.getShort()); setMacStyle(data.getShort()); setLowestRecPPem(data.getShort()); setFontDirectionHint(data.getShort()); setIndexToLocFormat(data.getShort()); setGlyphDataFormat(data.getShort()); } /** * Get the data we have stored */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putInt(getVersion()); buf.putInt(getFontRevision()); buf.putInt(getChecksumAdjustment()); buf.putInt(getMagicNumber()); buf.putShort(getFlags()); buf.putShort(getUnitsPerEm()); buf.putLong(getCreated()); buf.putLong(getModified()); buf.putShort(getXMin()); buf.putShort(getXMax()); buf.putShort(getYMin()); buf.putShort(getYMax()); buf.putShort(getMacStyle()); buf.putShort(getLowestRecPPem()); buf.putShort(getFontDirectionHint()); buf.putShort(getIndexToLocFormat()); buf.putShort(getGlyphDataFormat()); // reset the position to the start of the buffer buf.flip(); return buf; } /** * Get the length of this table */ public int getLength() { return 54; } /** Getter for property version. * @return Value of property version. * */ public int getVersion() { return version; } /** Getter for property fontRevision. * @return Value of property fontRevision. * */ public int getFontRevision() { return this.fontRevision; } /** Getter for property checksumAdjustment. * @return Value of property checksumAdjustment. * */ public int getChecksumAdjustment() { return this.checksumAdjustment; } /** Getter for property magicNumber. * @return Value of property magicNumber. * */ public int getMagicNumber() { return this.magicNumber; } /** Getter for property flags. * @return Value of property flags. * */ public short getFlags() { return this.flags; } /** Getter for property unitsPerEm. * @return Value of property unitsPerEm. * */ public short getUnitsPerEm() { return this.unitsPerEm; } /** Getter for property created. * @return Value of property created. * */ public long getCreated() { return this.created; } /** Getter for property modified. * @return Value of property modified. * */ public long getModified() { return this.modified; } /** Getter for property xMin. * @return Value of property xMin. * */ public short getXMin() { return this.xMin; } /** Getter for property yMin. * @return Value of property yMin. * */ public short getYMin() { return this.yMin; } /** Getter for property xMax. * @return Value of property xMax. * */ public short getXMax() { return this.xMax; } /** Getter for property yMax. * @return Value of property yMax. * */ public short getYMax() { return this.yMax; } /** Getter for property macStyle. * @return Value of property macStyle. * */ public short getMacStyle() { return this.macStyle; } /** Getter for property lowestRecPPem. * @return Value of property lowestRecPPem. * */ public short getLowestRecPPem() { return this.lowestRecPPem; } /** Getter for property fontDirectionHint. * @return Value of property fontDirectionHint. * */ public short getFontDirectionHint() { return this.fontDirectionHint; } /** Getter for property indexToLocFormat. * @return Value of property indexToLocFormat. * */ public short getIndexToLocFormat() { return this.indexToLocFormat; } /** Getter for property glyphDataFormat. * @return Value of property glyphDataFormat. * */ public short getGlyphDataFormat() { return this.glyphDataFormat; } /** Setter for property XMax. * @param xMax New value of property XMax. * */ public void setXMax(short xMax) { this.xMax = xMax; } /** Setter for property XMin. * @param xMin New value of property XMin. * */ public void setXMin(short xMin) { this.xMin = xMin; } /** Setter for property YMax. * @param yMax New value of property YMax. * */ public void setYMax(short yMax) { this.yMax = yMax; } /** Setter for property YMin. * @param yMin New value of property YMin. * */ public void setYMin(short yMin) { this.yMin = yMin; } /** Setter for property checksumAdjustment. * @param checksumAdjustment New value of property checksumAdjustment. * */ public void setChecksumAdjustment(int checksumAdjustment) { this.checksumAdjustment = checksumAdjustment; } /** Setter for property created. * @param created New value of property created. * */ public void setCreated(long created) { this.created = created; } /** Setter for property flags. * @param flags New value of property flags. * */ public void setFlags(short flags) { this.flags = flags; } /** Setter for property fontDirectionHint. * @param fontDirectionHint New value of property fontDirectionHint. * */ public void setFontDirectionHint(short fontDirectionHint) { this.fontDirectionHint = fontDirectionHint; } /** Setter for property fontRevision. * @param fontRevision New value of property fontRevision. * */ public void setFontRevision(int fontRevision) { this.fontRevision = fontRevision; } /** Setter for property glyphDataFormat. * @param glyphDataFormat New value of property glyphDataFormat. * */ public void setGlyphDataFormat(short glyphDataFormat) { this.glyphDataFormat = glyphDataFormat; } /** Setter for property indexToLocFormat. * @param indexToLocFormat New value of property indexToLocFormat. * */ public void setIndexToLocFormat(short indexToLocFormat) { this.indexToLocFormat = indexToLocFormat; } /** Setter for property lowestRecPPem. * @param lowestRecPPem New value of property lowestRecPPem. * */ public void setLowestRecPPem(short lowestRecPPem) { this.lowestRecPPem = lowestRecPPem; } /** Setter for property macStyle. * @param macStyle New value of property macStyle. * */ public void setMacStyle(short macStyle) { this.macStyle = macStyle; } /** Setter for property magicNumber. * @param magicNumber New value of property magicNumber. * */ public void setMagicNumber(int magicNumber) { this.magicNumber = magicNumber; } /** Setter for property modified. * @param modified New value of property modified. * */ public void setModified(long modified) { this.modified = modified; } /** Setter for property unitsPerEm. * @param unitsPerEm New value of property unitsPerEm. * */ public void setUnitsPerEm(short unitsPerEm) { this.unitsPerEm = unitsPerEm; } /** Setter for property version. * @param version New value of property version. * */ public void setVersion(int version) { this.version = version; } /** * Create a pretty string */ public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Version : " + Integer.toHexString(getVersion()) + "\n"); buf.append(indent + "Revision : " + Integer.toHexString(getFontRevision()) + "\n"); buf.append(indent + "ChecksumAdj : " + Integer.toHexString(getChecksumAdjustment()) + "\n"); buf.append(indent + "MagicNumber : " + Integer.toHexString(getMagicNumber()) + "\n"); buf.append(indent + "Flags : " + Integer.toBinaryString(getFlags()) + "\n"); buf.append(indent + "UnitsPerEm : " + getUnitsPerEm() + "\n"); buf.append(indent + "Created : " + new Date(getCreated()) + "\n"); buf.append(indent + "Modified : " + new Date(getModified()) + "\n"); buf.append(indent + "XMin : " + getXMin() + "\n"); buf.append(indent + "XMax : " + getXMax() + "\n"); buf.append(indent + "YMin : " + getYMin() + "\n"); buf.append(indent + "YMax : " + getYMax() + "\n"); buf.append(indent + "MacStyle : " + Integer.toBinaryString(getMacStyle()) + "\n"); buf.append(indent + "LowestPPem : " + getLowestRecPPem() + "\n"); buf.append(indent + "FontDirectionHint: " + getFontDirectionHint() + "\n"); buf.append(indent + "IndexToLocFormat : " + getIndexToLocFormat() + "\n"); buf.append(indent + "GlyphDataFormat : " + getGlyphDataFormat() + "\n"); return buf.toString(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/TrueTypeTable.java0000644000175000017500000001270711144055133024737 0ustar twernertwerner/* * $Id: TrueTypeTable.java,v 1.3 2009-02-09 16:31:23 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * The base class for TrueType tables. Specific tables can extend this * to add more functionality */ public class TrueTypeTable { /** * Well known tables */ public static final int CMAP_TABLE = 0x636d6170; public static final int GLYF_TABLE = 0x676c7966; public static final int HEAD_TABLE = 0x68656164; public static final int HHEA_TABLE = 0x68686561; public static final int HMTX_TABLE = 0x686d7478; public static final int MAXP_TABLE = 0x6d617870; public static final int NAME_TABLE = 0x6e616d65; public static final int POST_TABLE = 0x706f7374; public static final int LOCA_TABLE = 0x6c6f6361; /** * This table's tag */ private int tag; /** * The data in this table, in ByteBuffer form */ private ByteBuffer data; /** * Creates a new instance of TrueTypeTable. * * This method is protected. Use the getTable() methods * to get new instances. * * @param tag the tag for this table */ protected TrueTypeTable(int tag) { this.tag = tag; } /** * Get a new instance of an empty table by tag string * * @param ttf the font that contains this table * @param tagString the tag for this table, as a 4 character string * (e.g. head or cmap) */ public static TrueTypeTable createTable(TrueTypeFont ttf, String tagString) { return createTable(ttf, tagString, null); } /** * Get a new instance of a table with provided data * * @param ttf the font that contains this table * @param tagString the tag for this table, as a 4 character string * (e.g. head or cmap) * @param data the table data */ public static TrueTypeTable createTable(TrueTypeFont ttf, String tagString, ByteBuffer data) { TrueTypeTable outTable = null; int tag = stringToTag(tagString); switch (tag) { case CMAP_TABLE: // cmap table outTable = new CmapTable(); break; case GLYF_TABLE: outTable = new GlyfTable(ttf); break; case HEAD_TABLE: // head table outTable = new HeadTable(); break; case HHEA_TABLE: // hhea table outTable = new HheaTable(); break; case HMTX_TABLE: outTable = new HmtxTable(ttf); break; case LOCA_TABLE: outTable = new LocaTable(ttf); break; case MAXP_TABLE: // maxp table outTable = new MaxpTable(); break; case NAME_TABLE: // name table outTable = new NameTable(); break; case POST_TABLE: // post table outTable = new PostTable(); break; default: outTable = new TrueTypeTable(tag); break; } if (data != null) { outTable.setData(data); } return outTable; } /** * Get the table's tag */ public int getTag() { return tag; } /** * Get the data in the table */ public ByteBuffer getData() { return data; } /** * Set the data in the table */ public void setData(ByteBuffer data) { this.data = data; } /** * Get the size of the table, in bytes */ public int getLength() { return getData().remaining(); } /** * Get the tag as a string */ public static String tagToString(int tag) { char[] c = new char[4]; c[0] = (char) (0xff & (tag >> 24)); c[1] = (char) (0xff & (tag >> 16)); c[2] = (char) (0xff & (tag >> 8)); c[3] = (char) (0xff & (tag)); return new String(c); } /** * Turn a string into a tag */ public static int stringToTag(String tag) { char[] c = tag.toCharArray(); if (c.length != 4) { throw new IllegalArgumentException("Bad tag length: " + tag); } return c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; } /** * Put into a nice string */ public String toString() { String out = " " + tagToString(getTag()) + " Table. Data is: "; if (getData() == null) { out += "not set"; } else { out += "set"; } return out; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/resource/0000755000175000017500000000000011622545447023200 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/resource/glyphlist.txt0000644000175000017500000023057111146024321025750 0ustar twernertwerner# ################################################################################### # Copyright (c) 1997,1998,2002,2007 Adobe Systems Incorporated # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this documentation file to use, copy, publish, distribute, # sublicense, and/or sell copies of the documentation, and to permit # others to do the same, provided that: # - No modification, editing or other alteration of this document is # allowed; and # - The above copyright notice and this permission notice shall be # included in all copies of the documentation. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this documentation file, to create their own derivative works # from the content of this document to use, copy, publish, distribute, # sublicense, and/or sell the derivative works, and to permit others to do # the same, provided that the derived work is not represented as being a # copy or version of this document. # # Adobe shall not be liable to any party for any loss of revenue or profit # or for indirect, incidental, special, consequential, or other similar # damages, whether based on tort (including without limitation negligence # or strict liability), contract or other legal or equitable grounds even # if Adobe has been advised or had reason to know of the possibility of # such damages. The Adobe materials are provided on an "AS IS" basis. # Adobe specifically disclaims all express, statutory, or implied # warranties relating to the Adobe materials, including but not limited to # those concerning merchantability or fitness for a particular purpose or # non-infringement of any third party rights regarding the Adobe # materials. # ################################################################################### # Name: Adobe Glyph List # Table version: 2.0 # Date: September 20, 2002 # # See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html # # Format: Semicolon-delimited fields: # (1) glyph name # (2) Unicode scalar value A;0041 AE;00C6 AEacute;01FC AEmacron;01E2 AEsmall;F7E6 Aacute;00C1 Aacutesmall;F7E1 Abreve;0102 Abreveacute;1EAE Abrevecyrillic;04D0 Abrevedotbelow;1EB6 Abrevegrave;1EB0 Abrevehookabove;1EB2 Abrevetilde;1EB4 Acaron;01CD Acircle;24B6 Acircumflex;00C2 Acircumflexacute;1EA4 Acircumflexdotbelow;1EAC Acircumflexgrave;1EA6 Acircumflexhookabove;1EA8 Acircumflexsmall;F7E2 Acircumflextilde;1EAA Acute;F6C9 Acutesmall;F7B4 Acyrillic;0410 Adblgrave;0200 Adieresis;00C4 Adieresiscyrillic;04D2 Adieresismacron;01DE Adieresissmall;F7E4 Adotbelow;1EA0 Adotmacron;01E0 Agrave;00C0 Agravesmall;F7E0 Ahookabove;1EA2 Aiecyrillic;04D4 Ainvertedbreve;0202 Alpha;0391 Alphatonos;0386 Amacron;0100 Amonospace;FF21 Aogonek;0104 Aring;00C5 Aringacute;01FA Aringbelow;1E00 Aringsmall;F7E5 Asmall;F761 Atilde;00C3 Atildesmall;F7E3 Aybarmenian;0531 B;0042 Bcircle;24B7 Bdotaccent;1E02 Bdotbelow;1E04 Becyrillic;0411 Benarmenian;0532 Beta;0392 Bhook;0181 Blinebelow;1E06 Bmonospace;FF22 Brevesmall;F6F4 Bsmall;F762 Btopbar;0182 C;0043 Caarmenian;053E Cacute;0106 Caron;F6CA Caronsmall;F6F5 Ccaron;010C Ccedilla;00C7 Ccedillaacute;1E08 Ccedillasmall;F7E7 Ccircle;24B8 Ccircumflex;0108 Cdot;010A Cdotaccent;010A Cedillasmall;F7B8 Chaarmenian;0549 Cheabkhasiancyrillic;04BC Checyrillic;0427 Chedescenderabkhasiancyrillic;04BE Chedescendercyrillic;04B6 Chedieresiscyrillic;04F4 Cheharmenian;0543 Chekhakassiancyrillic;04CB Cheverticalstrokecyrillic;04B8 Chi;03A7 Chook;0187 Circumflexsmall;F6F6 Cmonospace;FF23 Coarmenian;0551 Csmall;F763 D;0044 DZ;01F1 DZcaron;01C4 Daarmenian;0534 Dafrican;0189 Dcaron;010E Dcedilla;1E10 Dcircle;24B9 Dcircumflexbelow;1E12 Dcroat;0110 Ddotaccent;1E0A Ddotbelow;1E0C Decyrillic;0414 Deicoptic;03EE Delta;2206 Deltagreek;0394 Dhook;018A Dieresis;F6CB DieresisAcute;F6CC DieresisGrave;F6CD Dieresissmall;F7A8 Digammagreek;03DC Djecyrillic;0402 Dlinebelow;1E0E Dmonospace;FF24 Dotaccentsmall;F6F7 Dslash;0110 Dsmall;F764 Dtopbar;018B Dz;01F2 Dzcaron;01C5 Dzeabkhasiancyrillic;04E0 Dzecyrillic;0405 Dzhecyrillic;040F E;0045 Eacute;00C9 Eacutesmall;F7E9 Ebreve;0114 Ecaron;011A Ecedillabreve;1E1C Echarmenian;0535 Ecircle;24BA Ecircumflex;00CA Ecircumflexacute;1EBE Ecircumflexbelow;1E18 Ecircumflexdotbelow;1EC6 Ecircumflexgrave;1EC0 Ecircumflexhookabove;1EC2 Ecircumflexsmall;F7EA Ecircumflextilde;1EC4 Ecyrillic;0404 Edblgrave;0204 Edieresis;00CB Edieresissmall;F7EB Edot;0116 Edotaccent;0116 Edotbelow;1EB8 Efcyrillic;0424 Egrave;00C8 Egravesmall;F7E8 Eharmenian;0537 Ehookabove;1EBA Eightroman;2167 Einvertedbreve;0206 Eiotifiedcyrillic;0464 Elcyrillic;041B Elevenroman;216A Emacron;0112 Emacronacute;1E16 Emacrongrave;1E14 Emcyrillic;041C Emonospace;FF25 Encyrillic;041D Endescendercyrillic;04A2 Eng;014A Enghecyrillic;04A4 Enhookcyrillic;04C7 Eogonek;0118 Eopen;0190 Epsilon;0395 Epsilontonos;0388 Ercyrillic;0420 Ereversed;018E Ereversedcyrillic;042D Escyrillic;0421 Esdescendercyrillic;04AA Esh;01A9 Esmall;F765 Eta;0397 Etarmenian;0538 Etatonos;0389 Eth;00D0 Ethsmall;F7F0 Etilde;1EBC Etildebelow;1E1A Euro;20AC Ezh;01B7 Ezhcaron;01EE Ezhreversed;01B8 F;0046 Fcircle;24BB Fdotaccent;1E1E Feharmenian;0556 Feicoptic;03E4 Fhook;0191 Fitacyrillic;0472 Fiveroman;2164 Fmonospace;FF26 Fourroman;2163 Fsmall;F766 G;0047 GBsquare;3387 Gacute;01F4 Gamma;0393 Gammaafrican;0194 Gangiacoptic;03EA Gbreve;011E Gcaron;01E6 Gcedilla;0122 Gcircle;24BC Gcircumflex;011C Gcommaaccent;0122 Gdot;0120 Gdotaccent;0120 Gecyrillic;0413 Ghadarmenian;0542 Ghemiddlehookcyrillic;0494 Ghestrokecyrillic;0492 Gheupturncyrillic;0490 Ghook;0193 Gimarmenian;0533 Gjecyrillic;0403 Gmacron;1E20 Gmonospace;FF27 Grave;F6CE Gravesmall;F760 Gsmall;F767 Gsmallhook;029B Gstroke;01E4 H;0048 H18533;25CF H18543;25AA H18551;25AB H22073;25A1 HPsquare;33CB Haabkhasiancyrillic;04A8 Hadescendercyrillic;04B2 Hardsigncyrillic;042A Hbar;0126 Hbrevebelow;1E2A Hcedilla;1E28 Hcircle;24BD Hcircumflex;0124 Hdieresis;1E26 Hdotaccent;1E22 Hdotbelow;1E24 Hmonospace;FF28 Hoarmenian;0540 Horicoptic;03E8 Hsmall;F768 Hungarumlaut;F6CF Hungarumlautsmall;F6F8 Hzsquare;3390 I;0049 IAcyrillic;042F IJ;0132 IUcyrillic;042E Iacute;00CD Iacutesmall;F7ED Ibreve;012C Icaron;01CF Icircle;24BE Icircumflex;00CE Icircumflexsmall;F7EE Icyrillic;0406 Idblgrave;0208 Idieresis;00CF Idieresisacute;1E2E Idieresiscyrillic;04E4 Idieresissmall;F7EF Idot;0130 Idotaccent;0130 Idotbelow;1ECA Iebrevecyrillic;04D6 Iecyrillic;0415 Ifraktur;2111 Igrave;00CC Igravesmall;F7EC Ihookabove;1EC8 Iicyrillic;0418 Iinvertedbreve;020A Iishortcyrillic;0419 Imacron;012A Imacroncyrillic;04E2 Imonospace;FF29 Iniarmenian;053B Iocyrillic;0401 Iogonek;012E Iota;0399 Iotaafrican;0196 Iotadieresis;03AA Iotatonos;038A Ismall;F769 Istroke;0197 Itilde;0128 Itildebelow;1E2C Izhitsacyrillic;0474 Izhitsadblgravecyrillic;0476 J;004A Jaarmenian;0541 Jcircle;24BF Jcircumflex;0134 Jecyrillic;0408 Jheharmenian;054B Jmonospace;FF2A Jsmall;F76A K;004B KBsquare;3385 KKsquare;33CD Kabashkircyrillic;04A0 Kacute;1E30 Kacyrillic;041A Kadescendercyrillic;049A Kahookcyrillic;04C3 Kappa;039A Kastrokecyrillic;049E Kaverticalstrokecyrillic;049C Kcaron;01E8 Kcedilla;0136 Kcircle;24C0 Kcommaaccent;0136 Kdotbelow;1E32 Keharmenian;0554 Kenarmenian;053F Khacyrillic;0425 Kheicoptic;03E6 Khook;0198 Kjecyrillic;040C Klinebelow;1E34 Kmonospace;FF2B Koppacyrillic;0480 Koppagreek;03DE Ksicyrillic;046E Ksmall;F76B L;004C LJ;01C7 LL;F6BF Lacute;0139 Lambda;039B Lcaron;013D Lcedilla;013B Lcircle;24C1 Lcircumflexbelow;1E3C Lcommaaccent;013B Ldot;013F Ldotaccent;013F Ldotbelow;1E36 Ldotbelowmacron;1E38 Liwnarmenian;053C Lj;01C8 Ljecyrillic;0409 Llinebelow;1E3A Lmonospace;FF2C Lslash;0141 Lslashsmall;F6F9 Lsmall;F76C M;004D MBsquare;3386 Macron;F6D0 Macronsmall;F7AF Macute;1E3E Mcircle;24C2 Mdotaccent;1E40 Mdotbelow;1E42 Menarmenian;0544 Mmonospace;FF2D Msmall;F76D Mturned;019C Mu;039C N;004E NJ;01CA Nacute;0143 Ncaron;0147 Ncedilla;0145 Ncircle;24C3 Ncircumflexbelow;1E4A Ncommaaccent;0145 Ndotaccent;1E44 Ndotbelow;1E46 Nhookleft;019D Nineroman;2168 Nj;01CB Njecyrillic;040A Nlinebelow;1E48 Nmonospace;FF2E Nowarmenian;0546 Nsmall;F76E Ntilde;00D1 Ntildesmall;F7F1 Nu;039D O;004F OE;0152 OEsmall;F6FA Oacute;00D3 Oacutesmall;F7F3 Obarredcyrillic;04E8 Obarreddieresiscyrillic;04EA Obreve;014E Ocaron;01D1 Ocenteredtilde;019F Ocircle;24C4 Ocircumflex;00D4 Ocircumflexacute;1ED0 Ocircumflexdotbelow;1ED8 Ocircumflexgrave;1ED2 Ocircumflexhookabove;1ED4 Ocircumflexsmall;F7F4 Ocircumflextilde;1ED6 Ocyrillic;041E Odblacute;0150 Odblgrave;020C Odieresis;00D6 Odieresiscyrillic;04E6 Odieresissmall;F7F6 Odotbelow;1ECC Ogoneksmall;F6FB Ograve;00D2 Ogravesmall;F7F2 Oharmenian;0555 Ohm;2126 Ohookabove;1ECE Ohorn;01A0 Ohornacute;1EDA Ohorndotbelow;1EE2 Ohorngrave;1EDC Ohornhookabove;1EDE Ohorntilde;1EE0 Ohungarumlaut;0150 Oi;01A2 Oinvertedbreve;020E Omacron;014C Omacronacute;1E52 Omacrongrave;1E50 Omega;2126 Omegacyrillic;0460 Omegagreek;03A9 Omegaroundcyrillic;047A Omegatitlocyrillic;047C Omegatonos;038F Omicron;039F Omicrontonos;038C Omonospace;FF2F Oneroman;2160 Oogonek;01EA Oogonekmacron;01EC Oopen;0186 Oslash;00D8 Oslashacute;01FE Oslashsmall;F7F8 Osmall;F76F Ostrokeacute;01FE Otcyrillic;047E Otilde;00D5 Otildeacute;1E4C Otildedieresis;1E4E Otildesmall;F7F5 P;0050 Pacute;1E54 Pcircle;24C5 Pdotaccent;1E56 Pecyrillic;041F Peharmenian;054A Pemiddlehookcyrillic;04A6 Phi;03A6 Phook;01A4 Pi;03A0 Piwrarmenian;0553 Pmonospace;FF30 Psi;03A8 Psicyrillic;0470 Psmall;F770 Q;0051 Qcircle;24C6 Qmonospace;FF31 Qsmall;F771 R;0052 Raarmenian;054C Racute;0154 Rcaron;0158 Rcedilla;0156 Rcircle;24C7 Rcommaaccent;0156 Rdblgrave;0210 Rdotaccent;1E58 Rdotbelow;1E5A Rdotbelowmacron;1E5C Reharmenian;0550 Rfraktur;211C Rho;03A1 Ringsmall;F6FC Rinvertedbreve;0212 Rlinebelow;1E5E Rmonospace;FF32 Rsmall;F772 Rsmallinverted;0281 Rsmallinvertedsuperior;02B6 S;0053 SF010000;250C SF020000;2514 SF030000;2510 SF040000;2518 SF050000;253C SF060000;252C SF070000;2534 SF080000;251C SF090000;2524 SF100000;2500 SF110000;2502 SF190000;2561 SF200000;2562 SF210000;2556 SF220000;2555 SF230000;2563 SF240000;2551 SF250000;2557 SF260000;255D SF270000;255C SF280000;255B SF360000;255E SF370000;255F SF380000;255A SF390000;2554 SF400000;2569 SF410000;2566 SF420000;2560 SF430000;2550 SF440000;256C SF450000;2567 SF460000;2568 SF470000;2564 SF480000;2565 SF490000;2559 SF500000;2558 SF510000;2552 SF520000;2553 SF530000;256B SF540000;256A Sacute;015A Sacutedotaccent;1E64 Sampigreek;03E0 Scaron;0160 Scarondotaccent;1E66 Scaronsmall;F6FD Scedilla;015E Schwa;018F Schwacyrillic;04D8 Schwadieresiscyrillic;04DA Scircle;24C8 Scircumflex;015C Scommaaccent;0218 Sdotaccent;1E60 Sdotbelow;1E62 Sdotbelowdotaccent;1E68 Seharmenian;054D Sevenroman;2166 Shaarmenian;0547 Shacyrillic;0428 Shchacyrillic;0429 Sheicoptic;03E2 Shhacyrillic;04BA Shimacoptic;03EC Sigma;03A3 Sixroman;2165 Smonospace;FF33 Softsigncyrillic;042C Ssmall;F773 Stigmagreek;03DA T;0054 Tau;03A4 Tbar;0166 Tcaron;0164 Tcedilla;0162 Tcircle;24C9 Tcircumflexbelow;1E70 Tcommaaccent;0162 Tdotaccent;1E6A Tdotbelow;1E6C Tecyrillic;0422 Tedescendercyrillic;04AC Tenroman;2169 Tetsecyrillic;04B4 Theta;0398 Thook;01AC Thorn;00DE Thornsmall;F7FE Threeroman;2162 Tildesmall;F6FE Tiwnarmenian;054F Tlinebelow;1E6E Tmonospace;FF34 Toarmenian;0539 Tonefive;01BC Tonesix;0184 Tonetwo;01A7 Tretroflexhook;01AE Tsecyrillic;0426 Tshecyrillic;040B Tsmall;F774 Twelveroman;216B Tworoman;2161 U;0055 Uacute;00DA Uacutesmall;F7FA Ubreve;016C Ucaron;01D3 Ucircle;24CA Ucircumflex;00DB Ucircumflexbelow;1E76 Ucircumflexsmall;F7FB Ucyrillic;0423 Udblacute;0170 Udblgrave;0214 Udieresis;00DC Udieresisacute;01D7 Udieresisbelow;1E72 Udieresiscaron;01D9 Udieresiscyrillic;04F0 Udieresisgrave;01DB Udieresismacron;01D5 Udieresissmall;F7FC Udotbelow;1EE4 Ugrave;00D9 Ugravesmall;F7F9 Uhookabove;1EE6 Uhorn;01AF Uhornacute;1EE8 Uhorndotbelow;1EF0 Uhorngrave;1EEA Uhornhookabove;1EEC Uhorntilde;1EEE Uhungarumlaut;0170 Uhungarumlautcyrillic;04F2 Uinvertedbreve;0216 Ukcyrillic;0478 Umacron;016A Umacroncyrillic;04EE Umacrondieresis;1E7A Umonospace;FF35 Uogonek;0172 Upsilon;03A5 Upsilon1;03D2 Upsilonacutehooksymbolgreek;03D3 Upsilonafrican;01B1 Upsilondieresis;03AB Upsilondieresishooksymbolgreek;03D4 Upsilonhooksymbol;03D2 Upsilontonos;038E Uring;016E Ushortcyrillic;040E Usmall;F775 Ustraightcyrillic;04AE Ustraightstrokecyrillic;04B0 Utilde;0168 Utildeacute;1E78 Utildebelow;1E74 V;0056 Vcircle;24CB Vdotbelow;1E7E Vecyrillic;0412 Vewarmenian;054E Vhook;01B2 Vmonospace;FF36 Voarmenian;0548 Vsmall;F776 Vtilde;1E7C W;0057 Wacute;1E82 Wcircle;24CC Wcircumflex;0174 Wdieresis;1E84 Wdotaccent;1E86 Wdotbelow;1E88 Wgrave;1E80 Wmonospace;FF37 Wsmall;F777 X;0058 Xcircle;24CD Xdieresis;1E8C Xdotaccent;1E8A Xeharmenian;053D Xi;039E Xmonospace;FF38 Xsmall;F778 Y;0059 Yacute;00DD Yacutesmall;F7FD Yatcyrillic;0462 Ycircle;24CE Ycircumflex;0176 Ydieresis;0178 Ydieresissmall;F7FF Ydotaccent;1E8E Ydotbelow;1EF4 Yericyrillic;042B Yerudieresiscyrillic;04F8 Ygrave;1EF2 Yhook;01B3 Yhookabove;1EF6 Yiarmenian;0545 Yicyrillic;0407 Yiwnarmenian;0552 Ymonospace;FF39 Ysmall;F779 Ytilde;1EF8 Yusbigcyrillic;046A Yusbigiotifiedcyrillic;046C Yuslittlecyrillic;0466 Yuslittleiotifiedcyrillic;0468 Z;005A Zaarmenian;0536 Zacute;0179 Zcaron;017D Zcaronsmall;F6FF Zcircle;24CF Zcircumflex;1E90 Zdot;017B Zdotaccent;017B Zdotbelow;1E92 Zecyrillic;0417 Zedescendercyrillic;0498 Zedieresiscyrillic;04DE Zeta;0396 Zhearmenian;053A Zhebrevecyrillic;04C1 Zhecyrillic;0416 Zhedescendercyrillic;0496 Zhedieresiscyrillic;04DC Zlinebelow;1E94 Zmonospace;FF3A Zsmall;F77A Zstroke;01B5 a;0061 aabengali;0986 aacute;00E1 aadeva;0906 aagujarati;0A86 aagurmukhi;0A06 aamatragurmukhi;0A3E aarusquare;3303 aavowelsignbengali;09BE aavowelsigndeva;093E aavowelsigngujarati;0ABE abbreviationmarkarmenian;055F abbreviationsigndeva;0970 abengali;0985 abopomofo;311A abreve;0103 abreveacute;1EAF abrevecyrillic;04D1 abrevedotbelow;1EB7 abrevegrave;1EB1 abrevehookabove;1EB3 abrevetilde;1EB5 acaron;01CE acircle;24D0 acircumflex;00E2 acircumflexacute;1EA5 acircumflexdotbelow;1EAD acircumflexgrave;1EA7 acircumflexhookabove;1EA9 acircumflextilde;1EAB acute;00B4 acutebelowcmb;0317 acutecmb;0301 acutecomb;0301 acutedeva;0954 acutelowmod;02CF acutetonecmb;0341 acyrillic;0430 adblgrave;0201 addakgurmukhi;0A71 adeva;0905 adieresis;00E4 adieresiscyrillic;04D3 adieresismacron;01DF adotbelow;1EA1 adotmacron;01E1 ae;00E6 aeacute;01FD aekorean;3150 aemacron;01E3 afii00208;2015 afii08941;20A4 afii10017;0410 afii10018;0411 afii10019;0412 afii10020;0413 afii10021;0414 afii10022;0415 afii10023;0401 afii10024;0416 afii10025;0417 afii10026;0418 afii10027;0419 afii10028;041A afii10029;041B afii10030;041C afii10031;041D afii10032;041E afii10033;041F afii10034;0420 afii10035;0421 afii10036;0422 afii10037;0423 afii10038;0424 afii10039;0425 afii10040;0426 afii10041;0427 afii10042;0428 afii10043;0429 afii10044;042A afii10045;042B afii10046;042C afii10047;042D afii10048;042E afii10049;042F afii10050;0490 afii10051;0402 afii10052;0403 afii10053;0404 afii10054;0405 afii10055;0406 afii10056;0407 afii10057;0408 afii10058;0409 afii10059;040A afii10060;040B afii10061;040C afii10062;040E afii10063;F6C4 afii10064;F6C5 afii10065;0430 afii10066;0431 afii10067;0432 afii10068;0433 afii10069;0434 afii10070;0435 afii10071;0451 afii10072;0436 afii10073;0437 afii10074;0438 afii10075;0439 afii10076;043A afii10077;043B afii10078;043C afii10079;043D afii10080;043E afii10081;043F afii10082;0440 afii10083;0441 afii10084;0442 afii10085;0443 afii10086;0444 afii10087;0445 afii10088;0446 afii10089;0447 afii10090;0448 afii10091;0449 afii10092;044A afii10093;044B afii10094;044C afii10095;044D afii10096;044E afii10097;044F afii10098;0491 afii10099;0452 afii10100;0453 afii10101;0454 afii10102;0455 afii10103;0456 afii10104;0457 afii10105;0458 afii10106;0459 afii10107;045A afii10108;045B afii10109;045C afii10110;045E afii10145;040F afii10146;0462 afii10147;0472 afii10148;0474 afii10192;F6C6 afii10193;045F afii10194;0463 afii10195;0473 afii10196;0475 afii10831;F6C7 afii10832;F6C8 afii10846;04D9 afii299;200E afii300;200F afii301;200D afii57381;066A afii57388;060C afii57392;0660 afii57393;0661 afii57394;0662 afii57395;0663 afii57396;0664 afii57397;0665 afii57398;0666 afii57399;0667 afii57400;0668 afii57401;0669 afii57403;061B afii57407;061F afii57409;0621 afii57410;0622 afii57411;0623 afii57412;0624 afii57413;0625 afii57414;0626 afii57415;0627 afii57416;0628 afii57417;0629 afii57418;062A afii57419;062B afii57420;062C afii57421;062D afii57422;062E afii57423;062F afii57424;0630 afii57425;0631 afii57426;0632 afii57427;0633 afii57428;0634 afii57429;0635 afii57430;0636 afii57431;0637 afii57432;0638 afii57433;0639 afii57434;063A afii57440;0640 afii57441;0641 afii57442;0642 afii57443;0643 afii57444;0644 afii57445;0645 afii57446;0646 afii57448;0648 afii57449;0649 afii57450;064A afii57451;064B afii57452;064C afii57453;064D afii57454;064E afii57455;064F afii57456;0650 afii57457;0651 afii57458;0652 afii57470;0647 afii57505;06A4 afii57506;067E afii57507;0686 afii57508;0698 afii57509;06AF afii57511;0679 afii57512;0688 afii57513;0691 afii57514;06BA afii57519;06D2 afii57534;06D5 afii57636;20AA afii57645;05BE afii57658;05C3 afii57664;05D0 afii57665;05D1 afii57666;05D2 afii57667;05D3 afii57668;05D4 afii57669;05D5 afii57670;05D6 afii57671;05D7 afii57672;05D8 afii57673;05D9 afii57674;05DA afii57675;05DB afii57676;05DC afii57677;05DD afii57678;05DE afii57679;05DF afii57680;05E0 afii57681;05E1 afii57682;05E2 afii57683;05E3 afii57684;05E4 afii57685;05E5 afii57686;05E6 afii57687;05E7 afii57688;05E8 afii57689;05E9 afii57690;05EA afii57694;FB2A afii57695;FB2B afii57700;FB4B afii57705;FB1F afii57716;05F0 afii57717;05F1 afii57718;05F2 afii57723;FB35 afii57793;05B4 afii57794;05B5 afii57795;05B6 afii57796;05BB afii57797;05B8 afii57798;05B7 afii57799;05B0 afii57800;05B2 afii57801;05B1 afii57802;05B3 afii57803;05C2 afii57804;05C1 afii57806;05B9 afii57807;05BC afii57839;05BD afii57841;05BF afii57842;05C0 afii57929;02BC afii61248;2105 afii61289;2113 afii61352;2116 afii61573;202C afii61574;202D afii61575;202E afii61664;200C afii63167;066D afii64937;02BD agrave;00E0 agujarati;0A85 agurmukhi;0A05 ahiragana;3042 ahookabove;1EA3 aibengali;0990 aibopomofo;311E aideva;0910 aiecyrillic;04D5 aigujarati;0A90 aigurmukhi;0A10 aimatragurmukhi;0A48 ainarabic;0639 ainfinalarabic;FECA aininitialarabic;FECB ainmedialarabic;FECC ainvertedbreve;0203 aivowelsignbengali;09C8 aivowelsigndeva;0948 aivowelsigngujarati;0AC8 akatakana;30A2 akatakanahalfwidth;FF71 akorean;314F alef;05D0 alefarabic;0627 alefdageshhebrew;FB30 aleffinalarabic;FE8E alefhamzaabovearabic;0623 alefhamzaabovefinalarabic;FE84 alefhamzabelowarabic;0625 alefhamzabelowfinalarabic;FE88 alefhebrew;05D0 aleflamedhebrew;FB4F alefmaddaabovearabic;0622 alefmaddaabovefinalarabic;FE82 alefmaksuraarabic;0649 alefmaksurafinalarabic;FEF0 alefmaksurainitialarabic;FEF3 alefmaksuramedialarabic;FEF4 alefpatahhebrew;FB2E alefqamatshebrew;FB2F aleph;2135 allequal;224C alpha;03B1 alphatonos;03AC amacron;0101 amonospace;FF41 ampersand;0026 ampersandmonospace;FF06 ampersandsmall;F726 amsquare;33C2 anbopomofo;3122 angbopomofo;3124 angkhankhuthai;0E5A angle;2220 anglebracketleft;3008 anglebracketleftvertical;FE3F anglebracketright;3009 anglebracketrightvertical;FE40 angleleft;2329 angleright;232A angstrom;212B anoteleia;0387 anudattadeva;0952 anusvarabengali;0982 anusvaradeva;0902 anusvaragujarati;0A82 aogonek;0105 apaatosquare;3300 aparen;249C apostrophearmenian;055A apostrophemod;02BC apple;F8FF approaches;2250 approxequal;2248 approxequalorimage;2252 approximatelyequal;2245 araeaekorean;318E araeakorean;318D arc;2312 arighthalfring;1E9A aring;00E5 aringacute;01FB aringbelow;1E01 arrowboth;2194 arrowdashdown;21E3 arrowdashleft;21E0 arrowdashright;21E2 arrowdashup;21E1 arrowdblboth;21D4 arrowdbldown;21D3 arrowdblleft;21D0 arrowdblright;21D2 arrowdblup;21D1 arrowdown;2193 arrowdownleft;2199 arrowdownright;2198 arrowdownwhite;21E9 arrowheaddownmod;02C5 arrowheadleftmod;02C2 arrowheadrightmod;02C3 arrowheadupmod;02C4 arrowhorizex;F8E7 arrowleft;2190 arrowleftdbl;21D0 arrowleftdblstroke;21CD arrowleftoverright;21C6 arrowleftwhite;21E6 arrowright;2192 arrowrightdblstroke;21CF arrowrightheavy;279E arrowrightoverleft;21C4 arrowrightwhite;21E8 arrowtableft;21E4 arrowtabright;21E5 arrowup;2191 arrowupdn;2195 arrowupdnbse;21A8 arrowupdownbase;21A8 arrowupleft;2196 arrowupleftofdown;21C5 arrowupright;2197 arrowupwhite;21E7 arrowvertex;F8E6 asciicircum;005E asciicircummonospace;FF3E asciitilde;007E asciitildemonospace;FF5E ascript;0251 ascriptturned;0252 asmallhiragana;3041 asmallkatakana;30A1 asmallkatakanahalfwidth;FF67 asterisk;002A asteriskaltonearabic;066D asteriskarabic;066D asteriskmath;2217 asteriskmonospace;FF0A asterisksmall;FE61 asterism;2042 asuperior;F6E9 asymptoticallyequal;2243 at;0040 atilde;00E3 atmonospace;FF20 atsmall;FE6B aturned;0250 aubengali;0994 aubopomofo;3120 audeva;0914 augujarati;0A94 augurmukhi;0A14 aulengthmarkbengali;09D7 aumatragurmukhi;0A4C auvowelsignbengali;09CC auvowelsigndeva;094C auvowelsigngujarati;0ACC avagrahadeva;093D aybarmenian;0561 ayin;05E2 ayinaltonehebrew;FB20 ayinhebrew;05E2 b;0062 babengali;09AC backslash;005C backslashmonospace;FF3C badeva;092C bagujarati;0AAC bagurmukhi;0A2C bahiragana;3070 bahtthai;0E3F bakatakana;30D0 bar;007C barmonospace;FF5C bbopomofo;3105 bcircle;24D1 bdotaccent;1E03 bdotbelow;1E05 beamedsixteenthnotes;266C because;2235 becyrillic;0431 beharabic;0628 behfinalarabic;FE90 behinitialarabic;FE91 behiragana;3079 behmedialarabic;FE92 behmeeminitialarabic;FC9F behmeemisolatedarabic;FC08 behnoonfinalarabic;FC6D bekatakana;30D9 benarmenian;0562 bet;05D1 beta;03B2 betasymbolgreek;03D0 betdagesh;FB31 betdageshhebrew;FB31 bethebrew;05D1 betrafehebrew;FB4C bhabengali;09AD bhadeva;092D bhagujarati;0AAD bhagurmukhi;0A2D bhook;0253 bihiragana;3073 bikatakana;30D3 bilabialclick;0298 bindigurmukhi;0A02 birusquare;3331 blackcircle;25CF blackdiamond;25C6 blackdownpointingtriangle;25BC blackleftpointingpointer;25C4 blackleftpointingtriangle;25C0 blacklenticularbracketleft;3010 blacklenticularbracketleftvertical;FE3B blacklenticularbracketright;3011 blacklenticularbracketrightvertical;FE3C blacklowerlefttriangle;25E3 blacklowerrighttriangle;25E2 blackrectangle;25AC blackrightpointingpointer;25BA blackrightpointingtriangle;25B6 blacksmallsquare;25AA blacksmilingface;263B blacksquare;25A0 blackstar;2605 blackupperlefttriangle;25E4 blackupperrighttriangle;25E5 blackuppointingsmalltriangle;25B4 blackuppointingtriangle;25B2 blank;2423 blinebelow;1E07 block;2588 bmonospace;FF42 bobaimaithai;0E1A bohiragana;307C bokatakana;30DC bparen;249D bqsquare;33C3 braceex;F8F4 braceleft;007B braceleftbt;F8F3 braceleftmid;F8F2 braceleftmonospace;FF5B braceleftsmall;FE5B bracelefttp;F8F1 braceleftvertical;FE37 braceright;007D bracerightbt;F8FE bracerightmid;F8FD bracerightmonospace;FF5D bracerightsmall;FE5C bracerighttp;F8FC bracerightvertical;FE38 bracketleft;005B bracketleftbt;F8F0 bracketleftex;F8EF bracketleftmonospace;FF3B bracketlefttp;F8EE bracketright;005D bracketrightbt;F8FB bracketrightex;F8FA bracketrightmonospace;FF3D bracketrighttp;F8F9 breve;02D8 brevebelowcmb;032E brevecmb;0306 breveinvertedbelowcmb;032F breveinvertedcmb;0311 breveinverteddoublecmb;0361 bridgebelowcmb;032A bridgeinvertedbelowcmb;033A brokenbar;00A6 bstroke;0180 bsuperior;F6EA btopbar;0183 buhiragana;3076 bukatakana;30D6 bullet;2022 bulletinverse;25D8 bulletoperator;2219 bullseye;25CE c;0063 caarmenian;056E cabengali;099A cacute;0107 cadeva;091A cagujarati;0A9A cagurmukhi;0A1A calsquare;3388 candrabindubengali;0981 candrabinducmb;0310 candrabindudeva;0901 candrabindugujarati;0A81 capslock;21EA careof;2105 caron;02C7 caronbelowcmb;032C caroncmb;030C carriagereturn;21B5 cbopomofo;3118 ccaron;010D ccedilla;00E7 ccedillaacute;1E09 ccircle;24D2 ccircumflex;0109 ccurl;0255 cdot;010B cdotaccent;010B cdsquare;33C5 cedilla;00B8 cedillacmb;0327 cent;00A2 centigrade;2103 centinferior;F6DF centmonospace;FFE0 centoldstyle;F7A2 centsuperior;F6E0 chaarmenian;0579 chabengali;099B chadeva;091B chagujarati;0A9B chagurmukhi;0A1B chbopomofo;3114 cheabkhasiancyrillic;04BD checkmark;2713 checyrillic;0447 chedescenderabkhasiancyrillic;04BF chedescendercyrillic;04B7 chedieresiscyrillic;04F5 cheharmenian;0573 chekhakassiancyrillic;04CC cheverticalstrokecyrillic;04B9 chi;03C7 chieuchacirclekorean;3277 chieuchaparenkorean;3217 chieuchcirclekorean;3269 chieuchkorean;314A chieuchparenkorean;3209 chochangthai;0E0A chochanthai;0E08 chochingthai;0E09 chochoethai;0E0C chook;0188 cieucacirclekorean;3276 cieucaparenkorean;3216 cieuccirclekorean;3268 cieuckorean;3148 cieucparenkorean;3208 cieucuparenkorean;321C circle;25CB circlemultiply;2297 circleot;2299 circleplus;2295 circlepostalmark;3036 circlewithlefthalfblack;25D0 circlewithrighthalfblack;25D1 circumflex;02C6 circumflexbelowcmb;032D circumflexcmb;0302 clear;2327 clickalveolar;01C2 clickdental;01C0 clicklateral;01C1 clickretroflex;01C3 club;2663 clubsuitblack;2663 clubsuitwhite;2667 cmcubedsquare;33A4 cmonospace;FF43 cmsquaredsquare;33A0 coarmenian;0581 colon;003A colonmonetary;20A1 colonmonospace;FF1A colonsign;20A1 colonsmall;FE55 colontriangularhalfmod;02D1 colontriangularmod;02D0 comma;002C commaabovecmb;0313 commaaboverightcmb;0315 commaaccent;F6C3 commaarabic;060C commaarmenian;055D commainferior;F6E1 commamonospace;FF0C commareversedabovecmb;0314 commareversedmod;02BD commasmall;FE50 commasuperior;F6E2 commaturnedabovecmb;0312 commaturnedmod;02BB compass;263C congruent;2245 contourintegral;222E control;2303 controlACK;0006 controlBEL;0007 controlBS;0008 controlCAN;0018 controlCR;000D controlDC1;0011 controlDC2;0012 controlDC3;0013 controlDC4;0014 controlDEL;007F controlDLE;0010 controlEM;0019 controlENQ;0005 controlEOT;0004 controlESC;001B controlETB;0017 controlETX;0003 controlFF;000C controlFS;001C controlGS;001D controlHT;0009 controlLF;000A controlNAK;0015 controlRS;001E controlSI;000F controlSO;000E controlSOT;0002 controlSTX;0001 controlSUB;001A controlSYN;0016 controlUS;001F controlVT;000B copyright;00A9 copyrightsans;F8E9 copyrightserif;F6D9 cornerbracketleft;300C cornerbracketlefthalfwidth;FF62 cornerbracketleftvertical;FE41 cornerbracketright;300D cornerbracketrighthalfwidth;FF63 cornerbracketrightvertical;FE42 corporationsquare;337F cosquare;33C7 coverkgsquare;33C6 cparen;249E cruzeiro;20A2 cstretched;0297 curlyand;22CF curlyor;22CE currency;00A4 cyrBreve;F6D1 cyrFlex;F6D2 cyrbreve;F6D4 cyrflex;F6D5 d;0064 daarmenian;0564 dabengali;09A6 dadarabic;0636 dadeva;0926 dadfinalarabic;FEBE dadinitialarabic;FEBF dadmedialarabic;FEC0 dagesh;05BC dageshhebrew;05BC dagger;2020 daggerdbl;2021 dagujarati;0AA6 dagurmukhi;0A26 dahiragana;3060 dakatakana;30C0 dalarabic;062F dalet;05D3 daletdagesh;FB33 daletdageshhebrew;FB33 dalethatafpatah;05D3 05B2 dalethatafpatahhebrew;05D3 05B2 dalethatafsegol;05D3 05B1 dalethatafsegolhebrew;05D3 05B1 dalethebrew;05D3 dalethiriq;05D3 05B4 dalethiriqhebrew;05D3 05B4 daletholam;05D3 05B9 daletholamhebrew;05D3 05B9 daletpatah;05D3 05B7 daletpatahhebrew;05D3 05B7 daletqamats;05D3 05B8 daletqamatshebrew;05D3 05B8 daletqubuts;05D3 05BB daletqubutshebrew;05D3 05BB daletsegol;05D3 05B6 daletsegolhebrew;05D3 05B6 daletsheva;05D3 05B0 daletshevahebrew;05D3 05B0 dalettsere;05D3 05B5 dalettserehebrew;05D3 05B5 dalfinalarabic;FEAA dammaarabic;064F dammalowarabic;064F dammatanaltonearabic;064C dammatanarabic;064C danda;0964 dargahebrew;05A7 dargalefthebrew;05A7 dasiapneumatacyrilliccmb;0485 dblGrave;F6D3 dblanglebracketleft;300A dblanglebracketleftvertical;FE3D dblanglebracketright;300B dblanglebracketrightvertical;FE3E dblarchinvertedbelowcmb;032B dblarrowleft;21D4 dblarrowright;21D2 dbldanda;0965 dblgrave;F6D6 dblgravecmb;030F dblintegral;222C dbllowline;2017 dbllowlinecmb;0333 dbloverlinecmb;033F dblprimemod;02BA dblverticalbar;2016 dblverticallineabovecmb;030E dbopomofo;3109 dbsquare;33C8 dcaron;010F dcedilla;1E11 dcircle;24D3 dcircumflexbelow;1E13 dcroat;0111 ddabengali;09A1 ddadeva;0921 ddagujarati;0AA1 ddagurmukhi;0A21 ddalarabic;0688 ddalfinalarabic;FB89 dddhadeva;095C ddhabengali;09A2 ddhadeva;0922 ddhagujarati;0AA2 ddhagurmukhi;0A22 ddotaccent;1E0B ddotbelow;1E0D decimalseparatorarabic;066B decimalseparatorpersian;066B decyrillic;0434 degree;00B0 dehihebrew;05AD dehiragana;3067 deicoptic;03EF dekatakana;30C7 deleteleft;232B deleteright;2326 delta;03B4 deltaturned;018D denominatorminusonenumeratorbengali;09F8 dezh;02A4 dhabengali;09A7 dhadeva;0927 dhagujarati;0AA7 dhagurmukhi;0A27 dhook;0257 dialytikatonos;0385 dialytikatonoscmb;0344 diamond;2666 diamondsuitwhite;2662 dieresis;00A8 dieresisacute;F6D7 dieresisbelowcmb;0324 dieresiscmb;0308 dieresisgrave;F6D8 dieresistonos;0385 dihiragana;3062 dikatakana;30C2 dittomark;3003 divide;00F7 divides;2223 divisionslash;2215 djecyrillic;0452 dkshade;2593 dlinebelow;1E0F dlsquare;3397 dmacron;0111 dmonospace;FF44 dnblock;2584 dochadathai;0E0E dodekthai;0E14 dohiragana;3069 dokatakana;30C9 dollar;0024 dollarinferior;F6E3 dollarmonospace;FF04 dollaroldstyle;F724 dollarsmall;FE69 dollarsuperior;F6E4 dong;20AB dorusquare;3326 dotaccent;02D9 dotaccentcmb;0307 dotbelowcmb;0323 dotbelowcomb;0323 dotkatakana;30FB dotlessi;0131 dotlessj;F6BE dotlessjstrokehook;0284 dotmath;22C5 dottedcircle;25CC doubleyodpatah;FB1F doubleyodpatahhebrew;FB1F downtackbelowcmb;031E downtackmod;02D5 dparen;249F dsuperior;F6EB dtail;0256 dtopbar;018C duhiragana;3065 dukatakana;30C5 dz;01F3 dzaltone;02A3 dzcaron;01C6 dzcurl;02A5 dzeabkhasiancyrillic;04E1 dzecyrillic;0455 dzhecyrillic;045F e;0065 eacute;00E9 earth;2641 ebengali;098F ebopomofo;311C ebreve;0115 ecandradeva;090D ecandragujarati;0A8D ecandravowelsigndeva;0945 ecandravowelsigngujarati;0AC5 ecaron;011B ecedillabreve;1E1D echarmenian;0565 echyiwnarmenian;0587 ecircle;24D4 ecircumflex;00EA ecircumflexacute;1EBF ecircumflexbelow;1E19 ecircumflexdotbelow;1EC7 ecircumflexgrave;1EC1 ecircumflexhookabove;1EC3 ecircumflextilde;1EC5 ecyrillic;0454 edblgrave;0205 edeva;090F edieresis;00EB edot;0117 edotaccent;0117 edotbelow;1EB9 eegurmukhi;0A0F eematragurmukhi;0A47 efcyrillic;0444 egrave;00E8 egujarati;0A8F eharmenian;0567 ehbopomofo;311D ehiragana;3048 ehookabove;1EBB eibopomofo;311F eight;0038 eightarabic;0668 eightbengali;09EE eightcircle;2467 eightcircleinversesansserif;2791 eightdeva;096E eighteencircle;2471 eighteenparen;2485 eighteenperiod;2499 eightgujarati;0AEE eightgurmukhi;0A6E eighthackarabic;0668 eighthangzhou;3028 eighthnotebeamed;266B eightideographicparen;3227 eightinferior;2088 eightmonospace;FF18 eightoldstyle;F738 eightparen;247B eightperiod;248F eightpersian;06F8 eightroman;2177 eightsuperior;2078 eightthai;0E58 einvertedbreve;0207 eiotifiedcyrillic;0465 ekatakana;30A8 ekatakanahalfwidth;FF74 ekonkargurmukhi;0A74 ekorean;3154 elcyrillic;043B element;2208 elevencircle;246A elevenparen;247E elevenperiod;2492 elevenroman;217A ellipsis;2026 ellipsisvertical;22EE emacron;0113 emacronacute;1E17 emacrongrave;1E15 emcyrillic;043C emdash;2014 emdashvertical;FE31 emonospace;FF45 emphasismarkarmenian;055B emptyset;2205 enbopomofo;3123 encyrillic;043D endash;2013 endashvertical;FE32 endescendercyrillic;04A3 eng;014B engbopomofo;3125 enghecyrillic;04A5 enhookcyrillic;04C8 enspace;2002 eogonek;0119 eokorean;3153 eopen;025B eopenclosed;029A eopenreversed;025C eopenreversedclosed;025E eopenreversedhook;025D eparen;24A0 epsilon;03B5 epsilontonos;03AD equal;003D equalmonospace;FF1D equalsmall;FE66 equalsuperior;207C equivalence;2261 erbopomofo;3126 ercyrillic;0440 ereversed;0258 ereversedcyrillic;044D escyrillic;0441 esdescendercyrillic;04AB esh;0283 eshcurl;0286 eshortdeva;090E eshortvowelsigndeva;0946 eshreversedloop;01AA eshsquatreversed;0285 esmallhiragana;3047 esmallkatakana;30A7 esmallkatakanahalfwidth;FF6A estimated;212E esuperior;F6EC eta;03B7 etarmenian;0568 etatonos;03AE eth;00F0 etilde;1EBD etildebelow;1E1B etnahtafoukhhebrew;0591 etnahtafoukhlefthebrew;0591 etnahtahebrew;0591 etnahtalefthebrew;0591 eturned;01DD eukorean;3161 euro;20AC evowelsignbengali;09C7 evowelsigndeva;0947 evowelsigngujarati;0AC7 exclam;0021 exclamarmenian;055C exclamdbl;203C exclamdown;00A1 exclamdownsmall;F7A1 exclammonospace;FF01 exclamsmall;F721 existential;2203 ezh;0292 ezhcaron;01EF ezhcurl;0293 ezhreversed;01B9 ezhtail;01BA f;0066 fadeva;095E fagurmukhi;0A5E fahrenheit;2109 fathaarabic;064E fathalowarabic;064E fathatanarabic;064B fbopomofo;3108 fcircle;24D5 fdotaccent;1E1F feharabic;0641 feharmenian;0586 fehfinalarabic;FED2 fehinitialarabic;FED3 fehmedialarabic;FED4 feicoptic;03E5 female;2640 ff;FB00 ffi;FB03 ffl;FB04 fi;FB01 fifteencircle;246E fifteenparen;2482 fifteenperiod;2496 figuredash;2012 filledbox;25A0 filledrect;25AC finalkaf;05DA finalkafdagesh;FB3A finalkafdageshhebrew;FB3A finalkafhebrew;05DA finalkafqamats;05DA 05B8 finalkafqamatshebrew;05DA 05B8 finalkafsheva;05DA 05B0 finalkafshevahebrew;05DA 05B0 finalmem;05DD finalmemhebrew;05DD finalnun;05DF finalnunhebrew;05DF finalpe;05E3 finalpehebrew;05E3 finaltsadi;05E5 finaltsadihebrew;05E5 firsttonechinese;02C9 fisheye;25C9 fitacyrillic;0473 five;0035 fivearabic;0665 fivebengali;09EB fivecircle;2464 fivecircleinversesansserif;278E fivedeva;096B fiveeighths;215D fivegujarati;0AEB fivegurmukhi;0A6B fivehackarabic;0665 fivehangzhou;3025 fiveideographicparen;3224 fiveinferior;2085 fivemonospace;FF15 fiveoldstyle;F735 fiveparen;2478 fiveperiod;248C fivepersian;06F5 fiveroman;2174 fivesuperior;2075 fivethai;0E55 fl;FB02 florin;0192 fmonospace;FF46 fmsquare;3399 fofanthai;0E1F fofathai;0E1D fongmanthai;0E4F forall;2200 four;0034 fourarabic;0664 fourbengali;09EA fourcircle;2463 fourcircleinversesansserif;278D fourdeva;096A fourgujarati;0AEA fourgurmukhi;0A6A fourhackarabic;0664 fourhangzhou;3024 fourideographicparen;3223 fourinferior;2084 fourmonospace;FF14 fournumeratorbengali;09F7 fouroldstyle;F734 fourparen;2477 fourperiod;248B fourpersian;06F4 fourroman;2173 foursuperior;2074 fourteencircle;246D fourteenparen;2481 fourteenperiod;2495 fourthai;0E54 fourthtonechinese;02CB fparen;24A1 fraction;2044 franc;20A3 g;0067 gabengali;0997 gacute;01F5 gadeva;0917 gafarabic;06AF gaffinalarabic;FB93 gafinitialarabic;FB94 gafmedialarabic;FB95 gagujarati;0A97 gagurmukhi;0A17 gahiragana;304C gakatakana;30AC gamma;03B3 gammalatinsmall;0263 gammasuperior;02E0 gangiacoptic;03EB gbopomofo;310D gbreve;011F gcaron;01E7 gcedilla;0123 gcircle;24D6 gcircumflex;011D gcommaaccent;0123 gdot;0121 gdotaccent;0121 gecyrillic;0433 gehiragana;3052 gekatakana;30B2 geometricallyequal;2251 gereshaccenthebrew;059C gereshhebrew;05F3 gereshmuqdamhebrew;059D germandbls;00DF gershayimaccenthebrew;059E gershayimhebrew;05F4 getamark;3013 ghabengali;0998 ghadarmenian;0572 ghadeva;0918 ghagujarati;0A98 ghagurmukhi;0A18 ghainarabic;063A ghainfinalarabic;FECE ghaininitialarabic;FECF ghainmedialarabic;FED0 ghemiddlehookcyrillic;0495 ghestrokecyrillic;0493 gheupturncyrillic;0491 ghhadeva;095A ghhagurmukhi;0A5A ghook;0260 ghzsquare;3393 gihiragana;304E gikatakana;30AE gimarmenian;0563 gimel;05D2 gimeldagesh;FB32 gimeldageshhebrew;FB32 gimelhebrew;05D2 gjecyrillic;0453 glottalinvertedstroke;01BE glottalstop;0294 glottalstopinverted;0296 glottalstopmod;02C0 glottalstopreversed;0295 glottalstopreversedmod;02C1 glottalstopreversedsuperior;02E4 glottalstopstroke;02A1 glottalstopstrokereversed;02A2 gmacron;1E21 gmonospace;FF47 gohiragana;3054 gokatakana;30B4 gparen;24A2 gpasquare;33AC gradient;2207 grave;0060 gravebelowcmb;0316 gravecmb;0300 gravecomb;0300 gravedeva;0953 gravelowmod;02CE gravemonospace;FF40 gravetonecmb;0340 greater;003E greaterequal;2265 greaterequalorless;22DB greatermonospace;FF1E greaterorequivalent;2273 greaterorless;2277 greateroverequal;2267 greatersmall;FE65 gscript;0261 gstroke;01E5 guhiragana;3050 guillemotleft;00AB guillemotright;00BB guilsinglleft;2039 guilsinglright;203A gukatakana;30B0 guramusquare;3318 gysquare;33C9 h;0068 haabkhasiancyrillic;04A9 haaltonearabic;06C1 habengali;09B9 hadescendercyrillic;04B3 hadeva;0939 hagujarati;0AB9 hagurmukhi;0A39 haharabic;062D hahfinalarabic;FEA2 hahinitialarabic;FEA3 hahiragana;306F hahmedialarabic;FEA4 haitusquare;332A hakatakana;30CF hakatakanahalfwidth;FF8A halantgurmukhi;0A4D hamzaarabic;0621 hamzadammaarabic;0621 064F hamzadammatanarabic;0621 064C hamzafathaarabic;0621 064E hamzafathatanarabic;0621 064B hamzalowarabic;0621 hamzalowkasraarabic;0621 0650 hamzalowkasratanarabic;0621 064D hamzasukunarabic;0621 0652 hangulfiller;3164 hardsigncyrillic;044A harpoonleftbarbup;21BC harpoonrightbarbup;21C0 hasquare;33CA hatafpatah;05B2 hatafpatah16;05B2 hatafpatah23;05B2 hatafpatah2f;05B2 hatafpatahhebrew;05B2 hatafpatahnarrowhebrew;05B2 hatafpatahquarterhebrew;05B2 hatafpatahwidehebrew;05B2 hatafqamats;05B3 hatafqamats1b;05B3 hatafqamats28;05B3 hatafqamats34;05B3 hatafqamatshebrew;05B3 hatafqamatsnarrowhebrew;05B3 hatafqamatsquarterhebrew;05B3 hatafqamatswidehebrew;05B3 hatafsegol;05B1 hatafsegol17;05B1 hatafsegol24;05B1 hatafsegol30;05B1 hatafsegolhebrew;05B1 hatafsegolnarrowhebrew;05B1 hatafsegolquarterhebrew;05B1 hatafsegolwidehebrew;05B1 hbar;0127 hbopomofo;310F hbrevebelow;1E2B hcedilla;1E29 hcircle;24D7 hcircumflex;0125 hdieresis;1E27 hdotaccent;1E23 hdotbelow;1E25 he;05D4 heart;2665 heartsuitblack;2665 heartsuitwhite;2661 hedagesh;FB34 hedageshhebrew;FB34 hehaltonearabic;06C1 heharabic;0647 hehebrew;05D4 hehfinalaltonearabic;FBA7 hehfinalalttwoarabic;FEEA hehfinalarabic;FEEA hehhamzaabovefinalarabic;FBA5 hehhamzaaboveisolatedarabic;FBA4 hehinitialaltonearabic;FBA8 hehinitialarabic;FEEB hehiragana;3078 hehmedialaltonearabic;FBA9 hehmedialarabic;FEEC heiseierasquare;337B hekatakana;30D8 hekatakanahalfwidth;FF8D hekutaarusquare;3336 henghook;0267 herutusquare;3339 het;05D7 hethebrew;05D7 hhook;0266 hhooksuperior;02B1 hieuhacirclekorean;327B hieuhaparenkorean;321B hieuhcirclekorean;326D hieuhkorean;314E hieuhparenkorean;320D hihiragana;3072 hikatakana;30D2 hikatakanahalfwidth;FF8B hiriq;05B4 hiriq14;05B4 hiriq21;05B4 hiriq2d;05B4 hiriqhebrew;05B4 hiriqnarrowhebrew;05B4 hiriqquarterhebrew;05B4 hiriqwidehebrew;05B4 hlinebelow;1E96 hmonospace;FF48 hoarmenian;0570 hohipthai;0E2B hohiragana;307B hokatakana;30DB hokatakanahalfwidth;FF8E holam;05B9 holam19;05B9 holam26;05B9 holam32;05B9 holamhebrew;05B9 holamnarrowhebrew;05B9 holamquarterhebrew;05B9 holamwidehebrew;05B9 honokhukthai;0E2E hookabovecomb;0309 hookcmb;0309 hookpalatalizedbelowcmb;0321 hookretroflexbelowcmb;0322 hoonsquare;3342 horicoptic;03E9 horizontalbar;2015 horncmb;031B hotsprings;2668 house;2302 hparen;24A3 hsuperior;02B0 hturned;0265 huhiragana;3075 huiitosquare;3333 hukatakana;30D5 hukatakanahalfwidth;FF8C hungarumlaut;02DD hungarumlautcmb;030B hv;0195 hyphen;002D hypheninferior;F6E5 hyphenmonospace;FF0D hyphensmall;FE63 hyphensuperior;F6E6 hyphentwo;2010 i;0069 iacute;00ED iacyrillic;044F ibengali;0987 ibopomofo;3127 ibreve;012D icaron;01D0 icircle;24D8 icircumflex;00EE icyrillic;0456 idblgrave;0209 ideographearthcircle;328F ideographfirecircle;328B ideographicallianceparen;323F ideographiccallparen;323A ideographiccentrecircle;32A5 ideographicclose;3006 ideographiccomma;3001 ideographiccommaleft;FF64 ideographiccongratulationparen;3237 ideographiccorrectcircle;32A3 ideographicearthparen;322F ideographicenterpriseparen;323D ideographicexcellentcircle;329D ideographicfestivalparen;3240 ideographicfinancialcircle;3296 ideographicfinancialparen;3236 ideographicfireparen;322B ideographichaveparen;3232 ideographichighcircle;32A4 ideographiciterationmark;3005 ideographiclaborcircle;3298 ideographiclaborparen;3238 ideographicleftcircle;32A7 ideographiclowcircle;32A6 ideographicmedicinecircle;32A9 ideographicmetalparen;322E ideographicmoonparen;322A ideographicnameparen;3234 ideographicperiod;3002 ideographicprintcircle;329E ideographicreachparen;3243 ideographicrepresentparen;3239 ideographicresourceparen;323E ideographicrightcircle;32A8 ideographicsecretcircle;3299 ideographicselfparen;3242 ideographicsocietyparen;3233 ideographicspace;3000 ideographicspecialparen;3235 ideographicstockparen;3231 ideographicstudyparen;323B ideographicsunparen;3230 ideographicsuperviseparen;323C ideographicwaterparen;322C ideographicwoodparen;322D ideographiczero;3007 ideographmetalcircle;328E ideographmooncircle;328A ideographnamecircle;3294 ideographsuncircle;3290 ideographwatercircle;328C ideographwoodcircle;328D ideva;0907 idieresis;00EF idieresisacute;1E2F idieresiscyrillic;04E5 idotbelow;1ECB iebrevecyrillic;04D7 iecyrillic;0435 ieungacirclekorean;3275 ieungaparenkorean;3215 ieungcirclekorean;3267 ieungkorean;3147 ieungparenkorean;3207 igrave;00EC igujarati;0A87 igurmukhi;0A07 ihiragana;3044 ihookabove;1EC9 iibengali;0988 iicyrillic;0438 iideva;0908 iigujarati;0A88 iigurmukhi;0A08 iimatragurmukhi;0A40 iinvertedbreve;020B iishortcyrillic;0439 iivowelsignbengali;09C0 iivowelsigndeva;0940 iivowelsigngujarati;0AC0 ij;0133 ikatakana;30A4 ikatakanahalfwidth;FF72 ikorean;3163 ilde;02DC iluyhebrew;05AC imacron;012B imacroncyrillic;04E3 imageorapproximatelyequal;2253 imatragurmukhi;0A3F imonospace;FF49 increment;2206 infinity;221E iniarmenian;056B integral;222B integralbottom;2321 integralbt;2321 integralex;F8F5 integraltop;2320 integraltp;2320 intersection;2229 intisquare;3305 invbullet;25D8 invcircle;25D9 invsmileface;263B iocyrillic;0451 iogonek;012F iota;03B9 iotadieresis;03CA iotadieresistonos;0390 iotalatin;0269 iotatonos;03AF iparen;24A4 irigurmukhi;0A72 ismallhiragana;3043 ismallkatakana;30A3 ismallkatakanahalfwidth;FF68 issharbengali;09FA istroke;0268 isuperior;F6ED iterationhiragana;309D iterationkatakana;30FD itilde;0129 itildebelow;1E2D iubopomofo;3129 iucyrillic;044E ivowelsignbengali;09BF ivowelsigndeva;093F ivowelsigngujarati;0ABF izhitsacyrillic;0475 izhitsadblgravecyrillic;0477 j;006A jaarmenian;0571 jabengali;099C jadeva;091C jagujarati;0A9C jagurmukhi;0A1C jbopomofo;3110 jcaron;01F0 jcircle;24D9 jcircumflex;0135 jcrossedtail;029D jdotlessstroke;025F jecyrillic;0458 jeemarabic;062C jeemfinalarabic;FE9E jeeminitialarabic;FE9F jeemmedialarabic;FEA0 jeharabic;0698 jehfinalarabic;FB8B jhabengali;099D jhadeva;091D jhagujarati;0A9D jhagurmukhi;0A1D jheharmenian;057B jis;3004 jmonospace;FF4A jparen;24A5 jsuperior;02B2 k;006B kabashkircyrillic;04A1 kabengali;0995 kacute;1E31 kacyrillic;043A kadescendercyrillic;049B kadeva;0915 kaf;05DB kafarabic;0643 kafdagesh;FB3B kafdageshhebrew;FB3B kaffinalarabic;FEDA kafhebrew;05DB kafinitialarabic;FEDB kafmedialarabic;FEDC kafrafehebrew;FB4D kagujarati;0A95 kagurmukhi;0A15 kahiragana;304B kahookcyrillic;04C4 kakatakana;30AB kakatakanahalfwidth;FF76 kappa;03BA kappasymbolgreek;03F0 kapyeounmieumkorean;3171 kapyeounphieuphkorean;3184 kapyeounpieupkorean;3178 kapyeounssangpieupkorean;3179 karoriisquare;330D kashidaautoarabic;0640 kashidaautonosidebearingarabic;0640 kasmallkatakana;30F5 kasquare;3384 kasraarabic;0650 kasratanarabic;064D kastrokecyrillic;049F katahiraprolongmarkhalfwidth;FF70 kaverticalstrokecyrillic;049D kbopomofo;310E kcalsquare;3389 kcaron;01E9 kcedilla;0137 kcircle;24DA kcommaaccent;0137 kdotbelow;1E33 keharmenian;0584 kehiragana;3051 kekatakana;30B1 kekatakanahalfwidth;FF79 kenarmenian;056F kesmallkatakana;30F6 kgreenlandic;0138 khabengali;0996 khacyrillic;0445 khadeva;0916 khagujarati;0A96 khagurmukhi;0A16 khaharabic;062E khahfinalarabic;FEA6 khahinitialarabic;FEA7 khahmedialarabic;FEA8 kheicoptic;03E7 khhadeva;0959 khhagurmukhi;0A59 khieukhacirclekorean;3278 khieukhaparenkorean;3218 khieukhcirclekorean;326A khieukhkorean;314B khieukhparenkorean;320A khokhaithai;0E02 khokhonthai;0E05 khokhuatthai;0E03 khokhwaithai;0E04 khomutthai;0E5B khook;0199 khorakhangthai;0E06 khzsquare;3391 kihiragana;304D kikatakana;30AD kikatakanahalfwidth;FF77 kiroguramusquare;3315 kiromeetorusquare;3316 kirosquare;3314 kiyeokacirclekorean;326E kiyeokaparenkorean;320E kiyeokcirclekorean;3260 kiyeokkorean;3131 kiyeokparenkorean;3200 kiyeoksioskorean;3133 kjecyrillic;045C klinebelow;1E35 klsquare;3398 kmcubedsquare;33A6 kmonospace;FF4B kmsquaredsquare;33A2 kohiragana;3053 kohmsquare;33C0 kokaithai;0E01 kokatakana;30B3 kokatakanahalfwidth;FF7A kooposquare;331E koppacyrillic;0481 koreanstandardsymbol;327F koroniscmb;0343 kparen;24A6 kpasquare;33AA ksicyrillic;046F ktsquare;33CF kturned;029E kuhiragana;304F kukatakana;30AF kukatakanahalfwidth;FF78 kvsquare;33B8 kwsquare;33BE l;006C labengali;09B2 lacute;013A ladeva;0932 lagujarati;0AB2 lagurmukhi;0A32 lakkhangyaothai;0E45 lamaleffinalarabic;FEFC lamalefhamzaabovefinalarabic;FEF8 lamalefhamzaaboveisolatedarabic;FEF7 lamalefhamzabelowfinalarabic;FEFA lamalefhamzabelowisolatedarabic;FEF9 lamalefisolatedarabic;FEFB lamalefmaddaabovefinalarabic;FEF6 lamalefmaddaaboveisolatedarabic;FEF5 lamarabic;0644 lambda;03BB lambdastroke;019B lamed;05DC lameddagesh;FB3C lameddageshhebrew;FB3C lamedhebrew;05DC lamedholam;05DC 05B9 lamedholamdagesh;05DC 05B9 05BC lamedholamdageshhebrew;05DC 05B9 05BC lamedholamhebrew;05DC 05B9 lamfinalarabic;FEDE lamhahinitialarabic;FCCA laminitialarabic;FEDF lamjeeminitialarabic;FCC9 lamkhahinitialarabic;FCCB lamlamhehisolatedarabic;FDF2 lammedialarabic;FEE0 lammeemhahinitialarabic;FD88 lammeeminitialarabic;FCCC lammeemjeeminitialarabic;FEDF FEE4 FEA0 lammeemkhahinitialarabic;FEDF FEE4 FEA8 largecircle;25EF lbar;019A lbelt;026C lbopomofo;310C lcaron;013E lcedilla;013C lcircle;24DB lcircumflexbelow;1E3D lcommaaccent;013C ldot;0140 ldotaccent;0140 ldotbelow;1E37 ldotbelowmacron;1E39 leftangleabovecmb;031A lefttackbelowcmb;0318 less;003C lessequal;2264 lessequalorgreater;22DA lessmonospace;FF1C lessorequivalent;2272 lessorgreater;2276 lessoverequal;2266 lesssmall;FE64 lezh;026E lfblock;258C lhookretroflex;026D lira;20A4 liwnarmenian;056C lj;01C9 ljecyrillic;0459 ll;F6C0 lladeva;0933 llagujarati;0AB3 llinebelow;1E3B llladeva;0934 llvocalicbengali;09E1 llvocalicdeva;0961 llvocalicvowelsignbengali;09E3 llvocalicvowelsigndeva;0963 lmiddletilde;026B lmonospace;FF4C lmsquare;33D0 lochulathai;0E2C logicaland;2227 logicalnot;00AC logicalnotreversed;2310 logicalor;2228 lolingthai;0E25 longs;017F lowlinecenterline;FE4E lowlinecmb;0332 lowlinedashed;FE4D lozenge;25CA lparen;24A7 lslash;0142 lsquare;2113 lsuperior;F6EE ltshade;2591 luthai;0E26 lvocalicbengali;098C lvocalicdeva;090C lvocalicvowelsignbengali;09E2 lvocalicvowelsigndeva;0962 lxsquare;33D3 m;006D mabengali;09AE macron;00AF macronbelowcmb;0331 macroncmb;0304 macronlowmod;02CD macronmonospace;FFE3 macute;1E3F madeva;092E magujarati;0AAE magurmukhi;0A2E mahapakhhebrew;05A4 mahapakhlefthebrew;05A4 mahiragana;307E maichattawalowleftthai;F895 maichattawalowrightthai;F894 maichattawathai;0E4B maichattawaupperleftthai;F893 maieklowleftthai;F88C maieklowrightthai;F88B maiekthai;0E48 maiekupperleftthai;F88A maihanakatleftthai;F884 maihanakatthai;0E31 maitaikhuleftthai;F889 maitaikhuthai;0E47 maitholowleftthai;F88F maitholowrightthai;F88E maithothai;0E49 maithoupperleftthai;F88D maitrilowleftthai;F892 maitrilowrightthai;F891 maitrithai;0E4A maitriupperleftthai;F890 maiyamokthai;0E46 makatakana;30DE makatakanahalfwidth;FF8F male;2642 mansyonsquare;3347 maqafhebrew;05BE mars;2642 masoracirclehebrew;05AF masquare;3383 mbopomofo;3107 mbsquare;33D4 mcircle;24DC mcubedsquare;33A5 mdotaccent;1E41 mdotbelow;1E43 meemarabic;0645 meemfinalarabic;FEE2 meeminitialarabic;FEE3 meemmedialarabic;FEE4 meemmeeminitialarabic;FCD1 meemmeemisolatedarabic;FC48 meetorusquare;334D mehiragana;3081 meizierasquare;337E mekatakana;30E1 mekatakanahalfwidth;FF92 mem;05DE memdagesh;FB3E memdageshhebrew;FB3E memhebrew;05DE menarmenian;0574 merkhahebrew;05A5 merkhakefulahebrew;05A6 merkhakefulalefthebrew;05A6 merkhalefthebrew;05A5 mhook;0271 mhzsquare;3392 middledotkatakanahalfwidth;FF65 middot;00B7 mieumacirclekorean;3272 mieumaparenkorean;3212 mieumcirclekorean;3264 mieumkorean;3141 mieumpansioskorean;3170 mieumparenkorean;3204 mieumpieupkorean;316E mieumsioskorean;316F mihiragana;307F mikatakana;30DF mikatakanahalfwidth;FF90 minus;2212 minusbelowcmb;0320 minuscircle;2296 minusmod;02D7 minusplus;2213 minute;2032 miribaarusquare;334A mirisquare;3349 mlonglegturned;0270 mlsquare;3396 mmcubedsquare;33A3 mmonospace;FF4D mmsquaredsquare;339F mohiragana;3082 mohmsquare;33C1 mokatakana;30E2 mokatakanahalfwidth;FF93 molsquare;33D6 momathai;0E21 moverssquare;33A7 moverssquaredsquare;33A8 mparen;24A8 mpasquare;33AB mssquare;33B3 msuperior;F6EF mturned;026F mu;00B5 mu1;00B5 muasquare;3382 muchgreater;226B muchless;226A mufsquare;338C mugreek;03BC mugsquare;338D muhiragana;3080 mukatakana;30E0 mukatakanahalfwidth;FF91 mulsquare;3395 multiply;00D7 mumsquare;339B munahhebrew;05A3 munahlefthebrew;05A3 musicalnote;266A musicalnotedbl;266B musicflatsign;266D musicsharpsign;266F mussquare;33B2 muvsquare;33B6 muwsquare;33BC mvmegasquare;33B9 mvsquare;33B7 mwmegasquare;33BF mwsquare;33BD n;006E nabengali;09A8 nabla;2207 nacute;0144 nadeva;0928 nagujarati;0AA8 nagurmukhi;0A28 nahiragana;306A nakatakana;30CA nakatakanahalfwidth;FF85 napostrophe;0149 nasquare;3381 nbopomofo;310B nbspace;00A0 ncaron;0148 ncedilla;0146 ncircle;24DD ncircumflexbelow;1E4B ncommaaccent;0146 ndotaccent;1E45 ndotbelow;1E47 nehiragana;306D nekatakana;30CD nekatakanahalfwidth;FF88 newsheqelsign;20AA nfsquare;338B ngabengali;0999 ngadeva;0919 ngagujarati;0A99 ngagurmukhi;0A19 ngonguthai;0E07 nhiragana;3093 nhookleft;0272 nhookretroflex;0273 nieunacirclekorean;326F nieunaparenkorean;320F nieuncieuckorean;3135 nieuncirclekorean;3261 nieunhieuhkorean;3136 nieunkorean;3134 nieunpansioskorean;3168 nieunparenkorean;3201 nieunsioskorean;3167 nieuntikeutkorean;3166 nihiragana;306B nikatakana;30CB nikatakanahalfwidth;FF86 nikhahitleftthai;F899 nikhahitthai;0E4D nine;0039 ninearabic;0669 ninebengali;09EF ninecircle;2468 ninecircleinversesansserif;2792 ninedeva;096F ninegujarati;0AEF ninegurmukhi;0A6F ninehackarabic;0669 ninehangzhou;3029 nineideographicparen;3228 nineinferior;2089 ninemonospace;FF19 nineoldstyle;F739 nineparen;247C nineperiod;2490 ninepersian;06F9 nineroman;2178 ninesuperior;2079 nineteencircle;2472 nineteenparen;2486 nineteenperiod;249A ninethai;0E59 nj;01CC njecyrillic;045A nkatakana;30F3 nkatakanahalfwidth;FF9D nlegrightlong;019E nlinebelow;1E49 nmonospace;FF4E nmsquare;339A nnabengali;09A3 nnadeva;0923 nnagujarati;0AA3 nnagurmukhi;0A23 nnnadeva;0929 nohiragana;306E nokatakana;30CE nokatakanahalfwidth;FF89 nonbreakingspace;00A0 nonenthai;0E13 nonuthai;0E19 noonarabic;0646 noonfinalarabic;FEE6 noonghunnaarabic;06BA noonghunnafinalarabic;FB9F noonhehinitialarabic;FEE7 FEEC nooninitialarabic;FEE7 noonjeeminitialarabic;FCD2 noonjeemisolatedarabic;FC4B noonmedialarabic;FEE8 noonmeeminitialarabic;FCD5 noonmeemisolatedarabic;FC4E noonnoonfinalarabic;FC8D notcontains;220C notelement;2209 notelementof;2209 notequal;2260 notgreater;226F notgreaternorequal;2271 notgreaternorless;2279 notidentical;2262 notless;226E notlessnorequal;2270 notparallel;2226 notprecedes;2280 notsubset;2284 notsucceeds;2281 notsuperset;2285 nowarmenian;0576 nparen;24A9 nssquare;33B1 nsuperior;207F ntilde;00F1 nu;03BD nuhiragana;306C nukatakana;30CC nukatakanahalfwidth;FF87 nuktabengali;09BC nuktadeva;093C nuktagujarati;0ABC nuktagurmukhi;0A3C numbersign;0023 numbersignmonospace;FF03 numbersignsmall;FE5F numeralsigngreek;0374 numeralsignlowergreek;0375 numero;2116 nun;05E0 nundagesh;FB40 nundageshhebrew;FB40 nunhebrew;05E0 nvsquare;33B5 nwsquare;33BB nyabengali;099E nyadeva;091E nyagujarati;0A9E nyagurmukhi;0A1E o;006F oacute;00F3 oangthai;0E2D obarred;0275 obarredcyrillic;04E9 obarreddieresiscyrillic;04EB obengali;0993 obopomofo;311B obreve;014F ocandradeva;0911 ocandragujarati;0A91 ocandravowelsigndeva;0949 ocandravowelsigngujarati;0AC9 ocaron;01D2 ocircle;24DE ocircumflex;00F4 ocircumflexacute;1ED1 ocircumflexdotbelow;1ED9 ocircumflexgrave;1ED3 ocircumflexhookabove;1ED5 ocircumflextilde;1ED7 ocyrillic;043E odblacute;0151 odblgrave;020D odeva;0913 odieresis;00F6 odieresiscyrillic;04E7 odotbelow;1ECD oe;0153 oekorean;315A ogonek;02DB ogonekcmb;0328 ograve;00F2 ogujarati;0A93 oharmenian;0585 ohiragana;304A ohookabove;1ECF ohorn;01A1 ohornacute;1EDB ohorndotbelow;1EE3 ohorngrave;1EDD ohornhookabove;1EDF ohorntilde;1EE1 ohungarumlaut;0151 oi;01A3 oinvertedbreve;020F okatakana;30AA okatakanahalfwidth;FF75 okorean;3157 olehebrew;05AB omacron;014D omacronacute;1E53 omacrongrave;1E51 omdeva;0950 omega;03C9 omega1;03D6 omegacyrillic;0461 omegalatinclosed;0277 omegaroundcyrillic;047B omegatitlocyrillic;047D omegatonos;03CE omgujarati;0AD0 omicron;03BF omicrontonos;03CC omonospace;FF4F one;0031 onearabic;0661 onebengali;09E7 onecircle;2460 onecircleinversesansserif;278A onedeva;0967 onedotenleader;2024 oneeighth;215B onefitted;F6DC onegujarati;0AE7 onegurmukhi;0A67 onehackarabic;0661 onehalf;00BD onehangzhou;3021 oneideographicparen;3220 oneinferior;2081 onemonospace;FF11 onenumeratorbengali;09F4 oneoldstyle;F731 oneparen;2474 oneperiod;2488 onepersian;06F1 onequarter;00BC oneroman;2170 onesuperior;00B9 onethai;0E51 onethird;2153 oogonek;01EB oogonekmacron;01ED oogurmukhi;0A13 oomatragurmukhi;0A4B oopen;0254 oparen;24AA openbullet;25E6 option;2325 ordfeminine;00AA ordmasculine;00BA orthogonal;221F oshortdeva;0912 oshortvowelsigndeva;094A oslash;00F8 oslashacute;01FF osmallhiragana;3049 osmallkatakana;30A9 osmallkatakanahalfwidth;FF6B ostrokeacute;01FF osuperior;F6F0 otcyrillic;047F otilde;00F5 otildeacute;1E4D otildedieresis;1E4F oubopomofo;3121 overline;203E overlinecenterline;FE4A overlinecmb;0305 overlinedashed;FE49 overlinedblwavy;FE4C overlinewavy;FE4B overscore;00AF ovowelsignbengali;09CB ovowelsigndeva;094B ovowelsigngujarati;0ACB p;0070 paampssquare;3380 paasentosquare;332B pabengali;09AA pacute;1E55 padeva;092A pagedown;21DF pageup;21DE pagujarati;0AAA pagurmukhi;0A2A pahiragana;3071 paiyannoithai;0E2F pakatakana;30D1 palatalizationcyrilliccmb;0484 palochkacyrillic;04C0 pansioskorean;317F paragraph;00B6 parallel;2225 parenleft;0028 parenleftaltonearabic;FD3E parenleftbt;F8ED parenleftex;F8EC parenleftinferior;208D parenleftmonospace;FF08 parenleftsmall;FE59 parenleftsuperior;207D parenlefttp;F8EB parenleftvertical;FE35 parenright;0029 parenrightaltonearabic;FD3F parenrightbt;F8F8 parenrightex;F8F7 parenrightinferior;208E parenrightmonospace;FF09 parenrightsmall;FE5A parenrightsuperior;207E parenrighttp;F8F6 parenrightvertical;FE36 partialdiff;2202 paseqhebrew;05C0 pashtahebrew;0599 pasquare;33A9 patah;05B7 patah11;05B7 patah1d;05B7 patah2a;05B7 patahhebrew;05B7 patahnarrowhebrew;05B7 patahquarterhebrew;05B7 patahwidehebrew;05B7 pazerhebrew;05A1 pbopomofo;3106 pcircle;24DF pdotaccent;1E57 pe;05E4 pecyrillic;043F pedagesh;FB44 pedageshhebrew;FB44 peezisquare;333B pefinaldageshhebrew;FB43 peharabic;067E peharmenian;057A pehebrew;05E4 pehfinalarabic;FB57 pehinitialarabic;FB58 pehiragana;307A pehmedialarabic;FB59 pekatakana;30DA pemiddlehookcyrillic;04A7 perafehebrew;FB4E percent;0025 percentarabic;066A percentmonospace;FF05 percentsmall;FE6A period;002E periodarmenian;0589 periodcentered;00B7 periodhalfwidth;FF61 periodinferior;F6E7 periodmonospace;FF0E periodsmall;FE52 periodsuperior;F6E8 perispomenigreekcmb;0342 perpendicular;22A5 perthousand;2030 peseta;20A7 pfsquare;338A phabengali;09AB phadeva;092B phagujarati;0AAB phagurmukhi;0A2B phi;03C6 phi1;03D5 phieuphacirclekorean;327A phieuphaparenkorean;321A phieuphcirclekorean;326C phieuphkorean;314D phieuphparenkorean;320C philatin;0278 phinthuthai;0E3A phisymbolgreek;03D5 phook;01A5 phophanthai;0E1E phophungthai;0E1C phosamphaothai;0E20 pi;03C0 pieupacirclekorean;3273 pieupaparenkorean;3213 pieupcieuckorean;3176 pieupcirclekorean;3265 pieupkiyeokkorean;3172 pieupkorean;3142 pieupparenkorean;3205 pieupsioskiyeokkorean;3174 pieupsioskorean;3144 pieupsiostikeutkorean;3175 pieupthieuthkorean;3177 pieuptikeutkorean;3173 pihiragana;3074 pikatakana;30D4 pisymbolgreek;03D6 piwrarmenian;0583 plus;002B plusbelowcmb;031F pluscircle;2295 plusminus;00B1 plusmod;02D6 plusmonospace;FF0B plussmall;FE62 plussuperior;207A pmonospace;FF50 pmsquare;33D8 pohiragana;307D pointingindexdownwhite;261F pointingindexleftwhite;261C pointingindexrightwhite;261E pointingindexupwhite;261D pokatakana;30DD poplathai;0E1B postalmark;3012 postalmarkface;3020 pparen;24AB precedes;227A prescription;211E primemod;02B9 primereversed;2035 product;220F projective;2305 prolongedkana;30FC propellor;2318 propersubset;2282 propersuperset;2283 proportion;2237 proportional;221D psi;03C8 psicyrillic;0471 psilipneumatacyrilliccmb;0486 pssquare;33B0 puhiragana;3077 pukatakana;30D7 pvsquare;33B4 pwsquare;33BA q;0071 qadeva;0958 qadmahebrew;05A8 qafarabic;0642 qaffinalarabic;FED6 qafinitialarabic;FED7 qafmedialarabic;FED8 qamats;05B8 qamats10;05B8 qamats1a;05B8 qamats1c;05B8 qamats27;05B8 qamats29;05B8 qamats33;05B8 qamatsde;05B8 qamatshebrew;05B8 qamatsnarrowhebrew;05B8 qamatsqatanhebrew;05B8 qamatsqatannarrowhebrew;05B8 qamatsqatanquarterhebrew;05B8 qamatsqatanwidehebrew;05B8 qamatsquarterhebrew;05B8 qamatswidehebrew;05B8 qarneyparahebrew;059F qbopomofo;3111 qcircle;24E0 qhook;02A0 qmonospace;FF51 qof;05E7 qofdagesh;FB47 qofdageshhebrew;FB47 qofhatafpatah;05E7 05B2 qofhatafpatahhebrew;05E7 05B2 qofhatafsegol;05E7 05B1 qofhatafsegolhebrew;05E7 05B1 qofhebrew;05E7 qofhiriq;05E7 05B4 qofhiriqhebrew;05E7 05B4 qofholam;05E7 05B9 qofholamhebrew;05E7 05B9 qofpatah;05E7 05B7 qofpatahhebrew;05E7 05B7 qofqamats;05E7 05B8 qofqamatshebrew;05E7 05B8 qofqubuts;05E7 05BB qofqubutshebrew;05E7 05BB qofsegol;05E7 05B6 qofsegolhebrew;05E7 05B6 qofsheva;05E7 05B0 qofshevahebrew;05E7 05B0 qoftsere;05E7 05B5 qoftserehebrew;05E7 05B5 qparen;24AC quarternote;2669 qubuts;05BB qubuts18;05BB qubuts25;05BB qubuts31;05BB qubutshebrew;05BB qubutsnarrowhebrew;05BB qubutsquarterhebrew;05BB qubutswidehebrew;05BB question;003F questionarabic;061F questionarmenian;055E questiondown;00BF questiondownsmall;F7BF questiongreek;037E questionmonospace;FF1F questionsmall;F73F quotedbl;0022 quotedblbase;201E quotedblleft;201C quotedblmonospace;FF02 quotedblprime;301E quotedblprimereversed;301D quotedblright;201D quoteleft;2018 quoteleftreversed;201B quotereversed;201B quoteright;2019 quoterightn;0149 quotesinglbase;201A quotesingle;0027 quotesinglemonospace;FF07 r;0072 raarmenian;057C rabengali;09B0 racute;0155 radeva;0930 radical;221A radicalex;F8E5 radoverssquare;33AE radoverssquaredsquare;33AF radsquare;33AD rafe;05BF rafehebrew;05BF ragujarati;0AB0 ragurmukhi;0A30 rahiragana;3089 rakatakana;30E9 rakatakanahalfwidth;FF97 ralowerdiagonalbengali;09F1 ramiddlediagonalbengali;09F0 ramshorn;0264 ratio;2236 rbopomofo;3116 rcaron;0159 rcedilla;0157 rcircle;24E1 rcommaaccent;0157 rdblgrave;0211 rdotaccent;1E59 rdotbelow;1E5B rdotbelowmacron;1E5D referencemark;203B reflexsubset;2286 reflexsuperset;2287 registered;00AE registersans;F8E8 registerserif;F6DA reharabic;0631 reharmenian;0580 rehfinalarabic;FEAE rehiragana;308C rehyehaleflamarabic;0631 FEF3 FE8E 0644 rekatakana;30EC rekatakanahalfwidth;FF9A resh;05E8 reshdageshhebrew;FB48 reshhatafpatah;05E8 05B2 reshhatafpatahhebrew;05E8 05B2 reshhatafsegol;05E8 05B1 reshhatafsegolhebrew;05E8 05B1 reshhebrew;05E8 reshhiriq;05E8 05B4 reshhiriqhebrew;05E8 05B4 reshholam;05E8 05B9 reshholamhebrew;05E8 05B9 reshpatah;05E8 05B7 reshpatahhebrew;05E8 05B7 reshqamats;05E8 05B8 reshqamatshebrew;05E8 05B8 reshqubuts;05E8 05BB reshqubutshebrew;05E8 05BB reshsegol;05E8 05B6 reshsegolhebrew;05E8 05B6 reshsheva;05E8 05B0 reshshevahebrew;05E8 05B0 reshtsere;05E8 05B5 reshtserehebrew;05E8 05B5 reversedtilde;223D reviahebrew;0597 reviamugrashhebrew;0597 revlogicalnot;2310 rfishhook;027E rfishhookreversed;027F rhabengali;09DD rhadeva;095D rho;03C1 rhook;027D rhookturned;027B rhookturnedsuperior;02B5 rhosymbolgreek;03F1 rhotichookmod;02DE rieulacirclekorean;3271 rieulaparenkorean;3211 rieulcirclekorean;3263 rieulhieuhkorean;3140 rieulkiyeokkorean;313A rieulkiyeoksioskorean;3169 rieulkorean;3139 rieulmieumkorean;313B rieulpansioskorean;316C rieulparenkorean;3203 rieulphieuphkorean;313F rieulpieupkorean;313C rieulpieupsioskorean;316B rieulsioskorean;313D rieulthieuthkorean;313E rieultikeutkorean;316A rieulyeorinhieuhkorean;316D rightangle;221F righttackbelowcmb;0319 righttriangle;22BF rihiragana;308A rikatakana;30EA rikatakanahalfwidth;FF98 ring;02DA ringbelowcmb;0325 ringcmb;030A ringhalfleft;02BF ringhalfleftarmenian;0559 ringhalfleftbelowcmb;031C ringhalfleftcentered;02D3 ringhalfright;02BE ringhalfrightbelowcmb;0339 ringhalfrightcentered;02D2 rinvertedbreve;0213 rittorusquare;3351 rlinebelow;1E5F rlongleg;027C rlonglegturned;027A rmonospace;FF52 rohiragana;308D rokatakana;30ED rokatakanahalfwidth;FF9B roruathai;0E23 rparen;24AD rrabengali;09DC rradeva;0931 rragurmukhi;0A5C rreharabic;0691 rrehfinalarabic;FB8D rrvocalicbengali;09E0 rrvocalicdeva;0960 rrvocalicgujarati;0AE0 rrvocalicvowelsignbengali;09C4 rrvocalicvowelsigndeva;0944 rrvocalicvowelsigngujarati;0AC4 rsuperior;F6F1 rtblock;2590 rturned;0279 rturnedsuperior;02B4 ruhiragana;308B rukatakana;30EB rukatakanahalfwidth;FF99 rupeemarkbengali;09F2 rupeesignbengali;09F3 rupiah;F6DD ruthai;0E24 rvocalicbengali;098B rvocalicdeva;090B rvocalicgujarati;0A8B rvocalicvowelsignbengali;09C3 rvocalicvowelsigndeva;0943 rvocalicvowelsigngujarati;0AC3 s;0073 sabengali;09B8 sacute;015B sacutedotaccent;1E65 sadarabic;0635 sadeva;0938 sadfinalarabic;FEBA sadinitialarabic;FEBB sadmedialarabic;FEBC sagujarati;0AB8 sagurmukhi;0A38 sahiragana;3055 sakatakana;30B5 sakatakanahalfwidth;FF7B sallallahoualayhewasallamarabic;FDFA samekh;05E1 samekhdagesh;FB41 samekhdageshhebrew;FB41 samekhhebrew;05E1 saraaathai;0E32 saraaethai;0E41 saraaimaimalaithai;0E44 saraaimaimuanthai;0E43 saraamthai;0E33 saraathai;0E30 saraethai;0E40 saraiileftthai;F886 saraiithai;0E35 saraileftthai;F885 saraithai;0E34 saraothai;0E42 saraueeleftthai;F888 saraueethai;0E37 saraueleftthai;F887 sarauethai;0E36 sarauthai;0E38 sarauuthai;0E39 sbopomofo;3119 scaron;0161 scarondotaccent;1E67 scedilla;015F schwa;0259 schwacyrillic;04D9 schwadieresiscyrillic;04DB schwahook;025A scircle;24E2 scircumflex;015D scommaaccent;0219 sdotaccent;1E61 sdotbelow;1E63 sdotbelowdotaccent;1E69 seagullbelowcmb;033C second;2033 secondtonechinese;02CA section;00A7 seenarabic;0633 seenfinalarabic;FEB2 seeninitialarabic;FEB3 seenmedialarabic;FEB4 segol;05B6 segol13;05B6 segol1f;05B6 segol2c;05B6 segolhebrew;05B6 segolnarrowhebrew;05B6 segolquarterhebrew;05B6 segoltahebrew;0592 segolwidehebrew;05B6 seharmenian;057D sehiragana;305B sekatakana;30BB sekatakanahalfwidth;FF7E semicolon;003B semicolonarabic;061B semicolonmonospace;FF1B semicolonsmall;FE54 semivoicedmarkkana;309C semivoicedmarkkanahalfwidth;FF9F sentisquare;3322 sentosquare;3323 seven;0037 sevenarabic;0667 sevenbengali;09ED sevencircle;2466 sevencircleinversesansserif;2790 sevendeva;096D seveneighths;215E sevengujarati;0AED sevengurmukhi;0A6D sevenhackarabic;0667 sevenhangzhou;3027 sevenideographicparen;3226 seveninferior;2087 sevenmonospace;FF17 sevenoldstyle;F737 sevenparen;247A sevenperiod;248E sevenpersian;06F7 sevenroman;2176 sevensuperior;2077 seventeencircle;2470 seventeenparen;2484 seventeenperiod;2498 seventhai;0E57 sfthyphen;00AD shaarmenian;0577 shabengali;09B6 shacyrillic;0448 shaddaarabic;0651 shaddadammaarabic;FC61 shaddadammatanarabic;FC5E shaddafathaarabic;FC60 shaddafathatanarabic;0651 064B shaddakasraarabic;FC62 shaddakasratanarabic;FC5F shade;2592 shadedark;2593 shadelight;2591 shademedium;2592 shadeva;0936 shagujarati;0AB6 shagurmukhi;0A36 shalshelethebrew;0593 shbopomofo;3115 shchacyrillic;0449 sheenarabic;0634 sheenfinalarabic;FEB6 sheeninitialarabic;FEB7 sheenmedialarabic;FEB8 sheicoptic;03E3 sheqel;20AA sheqelhebrew;20AA sheva;05B0 sheva115;05B0 sheva15;05B0 sheva22;05B0 sheva2e;05B0 shevahebrew;05B0 shevanarrowhebrew;05B0 shevaquarterhebrew;05B0 shevawidehebrew;05B0 shhacyrillic;04BB shimacoptic;03ED shin;05E9 shindagesh;FB49 shindageshhebrew;FB49 shindageshshindot;FB2C shindageshshindothebrew;FB2C shindageshsindot;FB2D shindageshsindothebrew;FB2D shindothebrew;05C1 shinhebrew;05E9 shinshindot;FB2A shinshindothebrew;FB2A shinsindot;FB2B shinsindothebrew;FB2B shook;0282 sigma;03C3 sigma1;03C2 sigmafinal;03C2 sigmalunatesymbolgreek;03F2 sihiragana;3057 sikatakana;30B7 sikatakanahalfwidth;FF7C siluqhebrew;05BD siluqlefthebrew;05BD similar;223C sindothebrew;05C2 siosacirclekorean;3274 siosaparenkorean;3214 sioscieuckorean;317E sioscirclekorean;3266 sioskiyeokkorean;317A sioskorean;3145 siosnieunkorean;317B siosparenkorean;3206 siospieupkorean;317D siostikeutkorean;317C six;0036 sixarabic;0666 sixbengali;09EC sixcircle;2465 sixcircleinversesansserif;278F sixdeva;096C sixgujarati;0AEC sixgurmukhi;0A6C sixhackarabic;0666 sixhangzhou;3026 sixideographicparen;3225 sixinferior;2086 sixmonospace;FF16 sixoldstyle;F736 sixparen;2479 sixperiod;248D sixpersian;06F6 sixroman;2175 sixsuperior;2076 sixteencircle;246F sixteencurrencydenominatorbengali;09F9 sixteenparen;2483 sixteenperiod;2497 sixthai;0E56 slash;002F slashmonospace;FF0F slong;017F slongdotaccent;1E9B smileface;263A smonospace;FF53 sofpasuqhebrew;05C3 softhyphen;00AD softsigncyrillic;044C sohiragana;305D sokatakana;30BD sokatakanahalfwidth;FF7F soliduslongoverlaycmb;0338 solidusshortoverlaycmb;0337 sorusithai;0E29 sosalathai;0E28 sosothai;0E0B sosuathai;0E2A space;0020 spacehackarabic;0020 spade;2660 spadesuitblack;2660 spadesuitwhite;2664 sparen;24AE squarebelowcmb;033B squarecc;33C4 squarecm;339D squarediagonalcrosshatchfill;25A9 squarehorizontalfill;25A4 squarekg;338F squarekm;339E squarekmcapital;33CE squareln;33D1 squarelog;33D2 squaremg;338E squaremil;33D5 squaremm;339C squaremsquared;33A1 squareorthogonalcrosshatchfill;25A6 squareupperlefttolowerrightfill;25A7 squareupperrighttolowerleftfill;25A8 squareverticalfill;25A5 squarewhitewithsmallblack;25A3 srsquare;33DB ssabengali;09B7 ssadeva;0937 ssagujarati;0AB7 ssangcieuckorean;3149 ssanghieuhkorean;3185 ssangieungkorean;3180 ssangkiyeokkorean;3132 ssangnieunkorean;3165 ssangpieupkorean;3143 ssangsioskorean;3146 ssangtikeutkorean;3138 ssuperior;F6F2 sterling;00A3 sterlingmonospace;FFE1 strokelongoverlaycmb;0336 strokeshortoverlaycmb;0335 subset;2282 subsetnotequal;228A subsetorequal;2286 succeeds;227B suchthat;220B suhiragana;3059 sukatakana;30B9 sukatakanahalfwidth;FF7D sukunarabic;0652 summation;2211 sun;263C superset;2283 supersetnotequal;228B supersetorequal;2287 svsquare;33DC syouwaerasquare;337C t;0074 tabengali;09A4 tackdown;22A4 tackleft;22A3 tadeva;0924 tagujarati;0AA4 tagurmukhi;0A24 taharabic;0637 tahfinalarabic;FEC2 tahinitialarabic;FEC3 tahiragana;305F tahmedialarabic;FEC4 taisyouerasquare;337D takatakana;30BF takatakanahalfwidth;FF80 tatweelarabic;0640 tau;03C4 tav;05EA tavdages;FB4A tavdagesh;FB4A tavdageshhebrew;FB4A tavhebrew;05EA tbar;0167 tbopomofo;310A tcaron;0165 tccurl;02A8 tcedilla;0163 tcheharabic;0686 tchehfinalarabic;FB7B tchehinitialarabic;FB7C tchehmedialarabic;FB7D tchehmeeminitialarabic;FB7C FEE4 tcircle;24E3 tcircumflexbelow;1E71 tcommaaccent;0163 tdieresis;1E97 tdotaccent;1E6B tdotbelow;1E6D tecyrillic;0442 tedescendercyrillic;04AD teharabic;062A tehfinalarabic;FE96 tehhahinitialarabic;FCA2 tehhahisolatedarabic;FC0C tehinitialarabic;FE97 tehiragana;3066 tehjeeminitialarabic;FCA1 tehjeemisolatedarabic;FC0B tehmarbutaarabic;0629 tehmarbutafinalarabic;FE94 tehmedialarabic;FE98 tehmeeminitialarabic;FCA4 tehmeemisolatedarabic;FC0E tehnoonfinalarabic;FC73 tekatakana;30C6 tekatakanahalfwidth;FF83 telephone;2121 telephoneblack;260E telishagedolahebrew;05A0 telishaqetanahebrew;05A9 tencircle;2469 tenideographicparen;3229 tenparen;247D tenperiod;2491 tenroman;2179 tesh;02A7 tet;05D8 tetdagesh;FB38 tetdageshhebrew;FB38 tethebrew;05D8 tetsecyrillic;04B5 tevirhebrew;059B tevirlefthebrew;059B thabengali;09A5 thadeva;0925 thagujarati;0AA5 thagurmukhi;0A25 thalarabic;0630 thalfinalarabic;FEAC thanthakhatlowleftthai;F898 thanthakhatlowrightthai;F897 thanthakhatthai;0E4C thanthakhatupperleftthai;F896 theharabic;062B thehfinalarabic;FE9A thehinitialarabic;FE9B thehmedialarabic;FE9C thereexists;2203 therefore;2234 theta;03B8 theta1;03D1 thetasymbolgreek;03D1 thieuthacirclekorean;3279 thieuthaparenkorean;3219 thieuthcirclekorean;326B thieuthkorean;314C thieuthparenkorean;320B thirteencircle;246C thirteenparen;2480 thirteenperiod;2494 thonangmonthothai;0E11 thook;01AD thophuthaothai;0E12 thorn;00FE thothahanthai;0E17 thothanthai;0E10 thothongthai;0E18 thothungthai;0E16 thousandcyrillic;0482 thousandsseparatorarabic;066C thousandsseparatorpersian;066C three;0033 threearabic;0663 threebengali;09E9 threecircle;2462 threecircleinversesansserif;278C threedeva;0969 threeeighths;215C threegujarati;0AE9 threegurmukhi;0A69 threehackarabic;0663 threehangzhou;3023 threeideographicparen;3222 threeinferior;2083 threemonospace;FF13 threenumeratorbengali;09F6 threeoldstyle;F733 threeparen;2476 threeperiod;248A threepersian;06F3 threequarters;00BE threequartersemdash;F6DE threeroman;2172 threesuperior;00B3 threethai;0E53 thzsquare;3394 tihiragana;3061 tikatakana;30C1 tikatakanahalfwidth;FF81 tikeutacirclekorean;3270 tikeutaparenkorean;3210 tikeutcirclekorean;3262 tikeutkorean;3137 tikeutparenkorean;3202 tilde;02DC tildebelowcmb;0330 tildecmb;0303 tildecomb;0303 tildedoublecmb;0360 tildeoperator;223C tildeoverlaycmb;0334 tildeverticalcmb;033E timescircle;2297 tipehahebrew;0596 tipehalefthebrew;0596 tippigurmukhi;0A70 titlocyrilliccmb;0483 tiwnarmenian;057F tlinebelow;1E6F tmonospace;FF54 toarmenian;0569 tohiragana;3068 tokatakana;30C8 tokatakanahalfwidth;FF84 tonebarextrahighmod;02E5 tonebarextralowmod;02E9 tonebarhighmod;02E6 tonebarlowmod;02E8 tonebarmidmod;02E7 tonefive;01BD tonesix;0185 tonetwo;01A8 tonos;0384 tonsquare;3327 topatakthai;0E0F tortoiseshellbracketleft;3014 tortoiseshellbracketleftsmall;FE5D tortoiseshellbracketleftvertical;FE39 tortoiseshellbracketright;3015 tortoiseshellbracketrightsmall;FE5E tortoiseshellbracketrightvertical;FE3A totaothai;0E15 tpalatalhook;01AB tparen;24AF trademark;2122 trademarksans;F8EA trademarkserif;F6DB tretroflexhook;0288 triagdn;25BC triaglf;25C4 triagrt;25BA triagup;25B2 ts;02A6 tsadi;05E6 tsadidagesh;FB46 tsadidageshhebrew;FB46 tsadihebrew;05E6 tsecyrillic;0446 tsere;05B5 tsere12;05B5 tsere1e;05B5 tsere2b;05B5 tserehebrew;05B5 tserenarrowhebrew;05B5 tserequarterhebrew;05B5 tserewidehebrew;05B5 tshecyrillic;045B tsuperior;F6F3 ttabengali;099F ttadeva;091F ttagujarati;0A9F ttagurmukhi;0A1F tteharabic;0679 ttehfinalarabic;FB67 ttehinitialarabic;FB68 ttehmedialarabic;FB69 tthabengali;09A0 tthadeva;0920 tthagujarati;0AA0 tthagurmukhi;0A20 tturned;0287 tuhiragana;3064 tukatakana;30C4 tukatakanahalfwidth;FF82 tusmallhiragana;3063 tusmallkatakana;30C3 tusmallkatakanahalfwidth;FF6F twelvecircle;246B twelveparen;247F twelveperiod;2493 twelveroman;217B twentycircle;2473 twentyhangzhou;5344 twentyparen;2487 twentyperiod;249B two;0032 twoarabic;0662 twobengali;09E8 twocircle;2461 twocircleinversesansserif;278B twodeva;0968 twodotenleader;2025 twodotleader;2025 twodotleadervertical;FE30 twogujarati;0AE8 twogurmukhi;0A68 twohackarabic;0662 twohangzhou;3022 twoideographicparen;3221 twoinferior;2082 twomonospace;FF12 twonumeratorbengali;09F5 twooldstyle;F732 twoparen;2475 twoperiod;2489 twopersian;06F2 tworoman;2171 twostroke;01BB twosuperior;00B2 twothai;0E52 twothirds;2154 u;0075 uacute;00FA ubar;0289 ubengali;0989 ubopomofo;3128 ubreve;016D ucaron;01D4 ucircle;24E4 ucircumflex;00FB ucircumflexbelow;1E77 ucyrillic;0443 udattadeva;0951 udblacute;0171 udblgrave;0215 udeva;0909 udieresis;00FC udieresisacute;01D8 udieresisbelow;1E73 udieresiscaron;01DA udieresiscyrillic;04F1 udieresisgrave;01DC udieresismacron;01D6 udotbelow;1EE5 ugrave;00F9 ugujarati;0A89 ugurmukhi;0A09 uhiragana;3046 uhookabove;1EE7 uhorn;01B0 uhornacute;1EE9 uhorndotbelow;1EF1 uhorngrave;1EEB uhornhookabove;1EED uhorntilde;1EEF uhungarumlaut;0171 uhungarumlautcyrillic;04F3 uinvertedbreve;0217 ukatakana;30A6 ukatakanahalfwidth;FF73 ukcyrillic;0479 ukorean;315C umacron;016B umacroncyrillic;04EF umacrondieresis;1E7B umatragurmukhi;0A41 umonospace;FF55 underscore;005F underscoredbl;2017 underscoremonospace;FF3F underscorevertical;FE33 underscorewavy;FE4F union;222A universal;2200 uogonek;0173 uparen;24B0 upblock;2580 upperdothebrew;05C4 upsilon;03C5 upsilondieresis;03CB upsilondieresistonos;03B0 upsilonlatin;028A upsilontonos;03CD uptackbelowcmb;031D uptackmod;02D4 uragurmukhi;0A73 uring;016F ushortcyrillic;045E usmallhiragana;3045 usmallkatakana;30A5 usmallkatakanahalfwidth;FF69 ustraightcyrillic;04AF ustraightstrokecyrillic;04B1 utilde;0169 utildeacute;1E79 utildebelow;1E75 uubengali;098A uudeva;090A uugujarati;0A8A uugurmukhi;0A0A uumatragurmukhi;0A42 uuvowelsignbengali;09C2 uuvowelsigndeva;0942 uuvowelsigngujarati;0AC2 uvowelsignbengali;09C1 uvowelsigndeva;0941 uvowelsigngujarati;0AC1 v;0076 vadeva;0935 vagujarati;0AB5 vagurmukhi;0A35 vakatakana;30F7 vav;05D5 vavdagesh;FB35 vavdagesh65;FB35 vavdageshhebrew;FB35 vavhebrew;05D5 vavholam;FB4B vavholamhebrew;FB4B vavvavhebrew;05F0 vavyodhebrew;05F1 vcircle;24E5 vdotbelow;1E7F vecyrillic;0432 veharabic;06A4 vehfinalarabic;FB6B vehinitialarabic;FB6C vehmedialarabic;FB6D vekatakana;30F9 venus;2640 verticalbar;007C verticallineabovecmb;030D verticallinebelowcmb;0329 verticallinelowmod;02CC verticallinemod;02C8 vewarmenian;057E vhook;028B vikatakana;30F8 viramabengali;09CD viramadeva;094D viramagujarati;0ACD visargabengali;0983 visargadeva;0903 visargagujarati;0A83 vmonospace;FF56 voarmenian;0578 voicediterationhiragana;309E voicediterationkatakana;30FE voicedmarkkana;309B voicedmarkkanahalfwidth;FF9E vokatakana;30FA vparen;24B1 vtilde;1E7D vturned;028C vuhiragana;3094 vukatakana;30F4 w;0077 wacute;1E83 waekorean;3159 wahiragana;308F wakatakana;30EF wakatakanahalfwidth;FF9C wakorean;3158 wasmallhiragana;308E wasmallkatakana;30EE wattosquare;3357 wavedash;301C wavyunderscorevertical;FE34 wawarabic;0648 wawfinalarabic;FEEE wawhamzaabovearabic;0624 wawhamzaabovefinalarabic;FE86 wbsquare;33DD wcircle;24E6 wcircumflex;0175 wdieresis;1E85 wdotaccent;1E87 wdotbelow;1E89 wehiragana;3091 weierstrass;2118 wekatakana;30F1 wekorean;315E weokorean;315D wgrave;1E81 whitebullet;25E6 whitecircle;25CB whitecircleinverse;25D9 whitecornerbracketleft;300E whitecornerbracketleftvertical;FE43 whitecornerbracketright;300F whitecornerbracketrightvertical;FE44 whitediamond;25C7 whitediamondcontainingblacksmalldiamond;25C8 whitedownpointingsmalltriangle;25BF whitedownpointingtriangle;25BD whiteleftpointingsmalltriangle;25C3 whiteleftpointingtriangle;25C1 whitelenticularbracketleft;3016 whitelenticularbracketright;3017 whiterightpointingsmalltriangle;25B9 whiterightpointingtriangle;25B7 whitesmallsquare;25AB whitesmilingface;263A whitesquare;25A1 whitestar;2606 whitetelephone;260F whitetortoiseshellbracketleft;3018 whitetortoiseshellbracketright;3019 whiteuppointingsmalltriangle;25B5 whiteuppointingtriangle;25B3 wihiragana;3090 wikatakana;30F0 wikorean;315F wmonospace;FF57 wohiragana;3092 wokatakana;30F2 wokatakanahalfwidth;FF66 won;20A9 wonmonospace;FFE6 wowaenthai;0E27 wparen;24B2 wring;1E98 wsuperior;02B7 wturned;028D wynn;01BF x;0078 xabovecmb;033D xbopomofo;3112 xcircle;24E7 xdieresis;1E8D xdotaccent;1E8B xeharmenian;056D xi;03BE xmonospace;FF58 xparen;24B3 xsuperior;02E3 y;0079 yaadosquare;334E yabengali;09AF yacute;00FD yadeva;092F yaekorean;3152 yagujarati;0AAF yagurmukhi;0A2F yahiragana;3084 yakatakana;30E4 yakatakanahalfwidth;FF94 yakorean;3151 yamakkanthai;0E4E yasmallhiragana;3083 yasmallkatakana;30E3 yasmallkatakanahalfwidth;FF6C yatcyrillic;0463 ycircle;24E8 ycircumflex;0177 ydieresis;00FF ydotaccent;1E8F ydotbelow;1EF5 yeharabic;064A yehbarreearabic;06D2 yehbarreefinalarabic;FBAF yehfinalarabic;FEF2 yehhamzaabovearabic;0626 yehhamzaabovefinalarabic;FE8A yehhamzaaboveinitialarabic;FE8B yehhamzaabovemedialarabic;FE8C yehinitialarabic;FEF3 yehmedialarabic;FEF4 yehmeeminitialarabic;FCDD yehmeemisolatedarabic;FC58 yehnoonfinalarabic;FC94 yehthreedotsbelowarabic;06D1 yekorean;3156 yen;00A5 yenmonospace;FFE5 yeokorean;3155 yeorinhieuhkorean;3186 yerahbenyomohebrew;05AA yerahbenyomolefthebrew;05AA yericyrillic;044B yerudieresiscyrillic;04F9 yesieungkorean;3181 yesieungpansioskorean;3183 yesieungsioskorean;3182 yetivhebrew;059A ygrave;1EF3 yhook;01B4 yhookabove;1EF7 yiarmenian;0575 yicyrillic;0457 yikorean;3162 yinyang;262F yiwnarmenian;0582 ymonospace;FF59 yod;05D9 yoddagesh;FB39 yoddageshhebrew;FB39 yodhebrew;05D9 yodyodhebrew;05F2 yodyodpatahhebrew;FB1F yohiragana;3088 yoikorean;3189 yokatakana;30E8 yokatakanahalfwidth;FF96 yokorean;315B yosmallhiragana;3087 yosmallkatakana;30E7 yosmallkatakanahalfwidth;FF6E yotgreek;03F3 yoyaekorean;3188 yoyakorean;3187 yoyakthai;0E22 yoyingthai;0E0D yparen;24B4 ypogegrammeni;037A ypogegrammenigreekcmb;0345 yr;01A6 yring;1E99 ysuperior;02B8 ytilde;1EF9 yturned;028E yuhiragana;3086 yuikorean;318C yukatakana;30E6 yukatakanahalfwidth;FF95 yukorean;3160 yusbigcyrillic;046B yusbigiotifiedcyrillic;046D yuslittlecyrillic;0467 yuslittleiotifiedcyrillic;0469 yusmallhiragana;3085 yusmallkatakana;30E5 yusmallkatakanahalfwidth;FF6D yuyekorean;318B yuyeokorean;318A yyabengali;09DF yyadeva;095F z;007A zaarmenian;0566 zacute;017A zadeva;095B zagurmukhi;0A5B zaharabic;0638 zahfinalarabic;FEC6 zahinitialarabic;FEC7 zahiragana;3056 zahmedialarabic;FEC8 zainarabic;0632 zainfinalarabic;FEB0 zakatakana;30B6 zaqefgadolhebrew;0595 zaqefqatanhebrew;0594 zarqahebrew;0598 zayin;05D6 zayindagesh;FB36 zayindageshhebrew;FB36 zayinhebrew;05D6 zbopomofo;3117 zcaron;017E zcircle;24E9 zcircumflex;1E91 zcurl;0291 zdot;017C zdotaccent;017C zdotbelow;1E93 zecyrillic;0437 zedescendercyrillic;0499 zedieresiscyrillic;04DF zehiragana;305C zekatakana;30BC zero;0030 zeroarabic;0660 zerobengali;09E6 zerodeva;0966 zerogujarati;0AE6 zerogurmukhi;0A66 zerohackarabic;0660 zeroinferior;2080 zeromonospace;FF10 zerooldstyle;F730 zeropersian;06F0 zerosuperior;2070 zerothai;0E50 zerowidthjoiner;FEFF zerowidthnonjoiner;200C zerowidthspace;200B zeta;03B6 zhbopomofo;3113 zhearmenian;056A zhebrevecyrillic;04C2 zhecyrillic;0436 zhedescendercyrillic;0497 zhedieresiscyrillic;04DD zihiragana;3058 zikatakana;30B8 zinorhebrew;05AE zlinebelow;1E95 zmonospace;FF5A zohiragana;305E zokatakana;30BE zparen;24B5 zretroflexhook;0290 zstroke;01B6 zuhiragana;305A zukatakana;30BA #--end pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/GlyfSimple.java0000644000175000017500000002376210732532577024302 0ustar twernertwerner/* * $Id: GlyfSimple.java,v 1.2 2007-12-20 18:33:31 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * A single simple glyph in a pdf font. */ public class GlyfSimple extends Glyf { /** the end points of the various contours */ private short[] contourEndPts; /** the instructions */ private byte[] instructions; /** the flags */ private byte[] flags; /** the x coordinates */ private short[] xCoords; /** the y coordinates */ private short[] yCoords; /** * Creates a new instance of a simple glyf */ protected GlyfSimple() { } /** * Set the data for this glyf. */ public void setData(ByteBuffer data) { // int pos = data.position(); // byte[] prdata = new byte[data.remaining()]; // data.get(prdata); // HexDump.printData(prdata); // data.position(pos); // read the contour end points short[] contourEndPts = new short[getNumContours()]; for (int i = 0; i < contourEndPts.length; i++) { contourEndPts[i] = data.getShort(); } setContourEndPoints(contourEndPts); // the number of points in the glyf is the number of the end // point in the last contour int numPoints = getContourEndPoint(getNumContours() - 1) + 1; // read the instructions short numInstructions = data.getShort(); byte[] instructions = new byte[numInstructions]; for (int i = 0; i < instructions.length; i++) { instructions[i] = data.get(); } setInstructions(instructions); // read the flags byte[] flags = new byte[numPoints]; for (int i = 0; i < flags.length; i++) { flags[i] = data.get(); // check for repeats if ((flags[i] & 0x8) != 0) { byte f = flags[i]; int n = (int) (data.get() & 0xff); for (int c = 0; c < n; c++) { flags[++i] = f; } } } setFlags(flags); // read the x coordinates short[] xCoords = new short[numPoints]; for (int i = 0; i < xCoords.length; i++) { if (i > 0) { xCoords[i] = xCoords[i - 1]; } // read this value if (xIsByte(i)) { int val = (int) (data.get() & 0xff); if (!xIsSame(i)) { // the xIsSame bit controls the sign val = -val; } xCoords[i] += val; } else if (!xIsSame(i)) { xCoords[i] += data.getShort(); } } setXCoords(xCoords); // read the y coordinates short[] yCoords = new short[numPoints]; for (int i = 0; i < yCoords.length; i++) { if (i > 0) { yCoords[i] = yCoords[i - 1]; } // read this value if (yIsByte(i)) { int val = (int) (data.get() & 0xff); if (!yIsSame(i)) { // the xIsSame bit controls the sign val = -val; } yCoords[i] += val; } else if (!yIsSame(i)) { yCoords[i] += data.getShort(); } } setYCoords(yCoords); } /** * Get the data in this glyf as a byte buffer. Return the basic * glyf data only, since there is no specific data. This method returns * the data un-flipped, so subclasses can simply append to the allocated * buffer. */ public ByteBuffer getData() { ByteBuffer buf = super.getData(); // write the contour end points for (int i = 0; i < getNumContours(); i++) { buf.putShort(getContourEndPoint(i)); } // write the instructions buf.putShort(getNumInstructions()); for (int i = 0; i < getNumInstructions(); i++) { buf.put(getInstruction(i)); } // write the flags for (int i = 0; i < getNumPoints(); i++) { // check for repeats byte r = 0; while (i > 0 && (getFlag(i) == getFlag(i - 1))) { r++; i++; } if (r > 0) { buf.put(r); } else { buf.put(getFlag(i)); } } // write the x coordinates for (int i = 0; i < getNumPoints(); i++) { if (xIsByte(i)) { buf.put((byte) getXCoord(i)); } else if (!xIsSame(i)) { buf.putShort(getXCoord(i)); } } // write the y coordinates for (int i = 0; i < getNumPoints(); i++) { if (yIsByte(i)) { buf.put((byte) getYCoord(i)); } else if (!yIsSame(i)) { buf.putShort(getYCoord(i)); } } // don't flip the buffer, since it may be used by subclasses return buf; } /** * Get the length of this glyf. */ public short getLength() { // start with the length of the superclass short length = super.getLength(); // add the length of the end points length += getNumContours() * 2; // add the length of the instructions length += 2 + getNumInstructions(); // add the length of the flags, avoiding repeats for (int i = 0; i < getNumPoints(); i++) { // check for repeats while (i > 0 && (getFlag(i) == getFlag(i - 1))); length++; } // add the length of the xCoordinates for (int i = 0; i < getNumPoints(); i++) { if (xIsByte(i)) { length++; } else if (!xIsSame(i)) { length += 2; } if (yIsByte(i)) { length++; } else if (!yIsSame(i)) { length += 2; } } return length; } /** * Get the end point of a given contour */ public short getContourEndPoint(int index) { return contourEndPts[index]; } /** * Set the number of contours in this glyf */ protected void setContourEndPoints(short[] contourEndPts) { this.contourEndPts = contourEndPts; } /** * Get the number of instructions */ public short getNumInstructions() { return (short) instructions.length; } /** * Get a given instruction */ public byte getInstruction(int index) { return instructions[index]; } /** * Set the instructions */ protected void setInstructions(byte[] instructions) { this.instructions = instructions; } /** * Get the number of points in the glyf */ public short getNumPoints() { return (short) flags.length; } /** * Get a given flag */ public byte getFlag(int pointIndex) { return flags[pointIndex]; } /** * Determine whether the given point is on the curve */ public boolean onCurve(int pointIndex) { return ((getFlag(pointIndex) & 0x1) != 0); } /** * Determine whether the x value for the given point is byte or short. * If true, it is a byte, if false it is a short */ protected boolean xIsByte(int pointIndex) { return ((getFlag(pointIndex) & 0x2) != 0); } /** * Determine whether the x value for the given point is byte or short. * If true, it is a byte, if false it is a short */ protected boolean yIsByte(int pointIndex) { return ((getFlag(pointIndex) & 0x4) != 0); } /** * Determine whether this flag repeats */ protected boolean repeat(int pointIndex) { return ((getFlag(pointIndex) & 0x8) != 0); } /** * Determine whether the x value for the given point is the same as * the previous value. */ protected boolean xIsSame(int pointIndex) { return ((getFlag(pointIndex) & 0x10) != 0); } /** * Determine whether the y value for the given point is the same as * the previous value. */ protected boolean yIsSame(int pointIndex) { return ((getFlag(pointIndex) & 0x20) != 0); } /** * Set the flags */ protected void setFlags(byte[] flags) { this.flags = flags; } /** * Get a given x coordinate */ public short getXCoord(int pointIndex) { return xCoords[pointIndex]; } /** * Set the x coordinates */ protected void setXCoords(short[] xCoords) { this.xCoords = xCoords; } /** * Get a given y coordinate */ public short getYCoord(int pointIndex) { return yCoords[pointIndex]; } /** * Set the x coordinates */ protected void setYCoords(short[] yCoords) { this.yCoords = yCoords; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/GlyfCompound.java0000644000175000017500000002370711145024767024630 0ustar twernertwerner/* * $Id: GlyfCompound.java,v 1.3 2009-02-12 13:53:57 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; /** * A single simple glyph in a pdf font. */ public class GlyfCompound extends Glyf { /** flags */ private static final int ARG_1_AND_2_ARE_WORDS = 0x1; private static final int ARGS_ARE_XY_VALUES = 0x2; private static final int ROUND_XY_TO_GRID = 0x4; private static final int WE_HAVE_A_SCALE = 0x8; private static final int MORE_COMPONENTS = 0x20; private static final int WE_HAVE_AN_X_AND_Y_SCALE = 0x40; private static final int WE_HAVE_A_TWO_BY_TWO = 0x80; private static final int WE_HAVE_INSTRUCTIONS = 0x100; private static final int USE_MY_METRICS = 0x200; private static final int OVERLAP_COMPOUND = 0x400; /** the flags for each compound glyph */ private GlyfComponent[] components; /** the instructions for the compound as a whole */ private byte[] instructions; /** * Creates a new instance of a simple glyf */ protected GlyfCompound() { } /** * Set the data for this glyf. */ @Override public void setData(ByteBuffer data) { // int pos = data.position(); // byte[] prdata = new byte[data.remaining()]; // data.get(prdata); // HexDump.printData(prdata); // data.position(pos); // read the contour end points List comps = new ArrayList(); GlyfComponent cur = null; boolean hasInstructions = false; do { cur = new GlyfComponent(); cur.flags = data.getShort(); cur.glyphIndex = data.getShort(); // read either e/f or matching points, as shorts or bytes... if (((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) && ((cur.flags & ARGS_ARE_XY_VALUES) != 0)) { cur.e = data.getShort(); cur.f = data.getShort(); } else if (!((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) && ((cur.flags & ARGS_ARE_XY_VALUES) != 0)) { cur.e = (float) data.get(); cur.f = (float) data.get(); } else if ( ((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) && !((cur.flags & ARGS_ARE_XY_VALUES) != 0)) { cur.compoundPoint = data.getShort(); cur.componentPoint = data.getShort(); } else { cur.compoundPoint = data.get(); cur.componentPoint = data.get(); } // read the linear transform if ((cur.flags & WE_HAVE_A_SCALE) != 0) { cur.a = (float) data.getShort() / (float) (1 << 14); cur.d = cur.a; } else if ((cur.flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) { cur.a = (float) data.getShort() / (float) (1 << 14); cur.d = (float) data.getShort() / (float) (1 << 14); } else if ((cur.flags & WE_HAVE_A_TWO_BY_TWO) != 0) { cur.a = (float) data.getShort() / (float) (1 << 14); cur.b = (float) data.getShort() / (float) (1 << 14); cur.c = (float) data.getShort() / (float) (1 << 14); cur.d = (float) data.getShort() / (float) (1 << 14); } if ((cur.flags & WE_HAVE_INSTRUCTIONS) != 0) { hasInstructions = true; } comps.add(cur); } while ((cur.flags & MORE_COMPONENTS) != 0); GlyfComponent[] componentArray = new GlyfComponent[comps.size()]; comps.toArray(componentArray); setComponents(componentArray); byte[] instr = null; if (hasInstructions) { // read the instructions short numInstructions = data.getShort(); instr = new byte[numInstructions]; for (int i = 0; i < instr.length; i++) { instr[i] = data.get(); } } else { instr = new byte[0]; } setInstructions(instr); } /** * Get the data in this glyf as a byte buffer. Not implemented. */ @Override public ByteBuffer getData() { ByteBuffer buf = super.getData(); // don't flip the buffer, since it may be used by subclasses return buf; } /** * Get the length of this glyf. Not implemented. */ @Override public short getLength() { // start with the length of the superclass short length = super.getLength(); return length; } /** * Get the number of components in this compound */ public int getNumComponents() { return components.length; } /** * Get a given flag */ public short getFlag(int index) { return components[index].flags; } /** * Get the glyf index for a given glyf */ public short getGlyphIndex(int index) { return components[index].glyphIndex; } /** * Get the base affine transform. This is based on a whacy formula * defined in the true type font spec. */ public double[] getTransform(int index) { GlyfComponent gc = components[index]; float m = (float) Math.max(Math.abs(gc.a), Math.abs(gc.b)); if (Math.abs(Math.abs(gc.a) - Math.abs(gc.c)) < (33 / 65536)) { m *= 2; } float n = (float) Math.max(Math.abs(gc.c), Math.abs(gc.d)); if (Math.abs(Math.abs(gc.c) - Math.abs(gc.d)) < (33 / 65536)) { n *= 2; } float e = m * gc.e; float f = n * gc.f; return new double[] { gc.a, gc.b, gc.c, gc.d, e, f }; } /** * Get the point in the compound glyph to match */ public int getCompoundPoint(int index) { return components[index].compoundPoint; } /** * Get the point in the component glyph to match */ public int getComponentPoint(int index) { return components[index].componentPoint; } /** * Determine whether args 1 and 2 are words or bytes */ public boolean argsAreWords(int index) { return ((getFlag(index) & ARG_1_AND_2_ARE_WORDS) != 0); } /** * Determine whether args 1 and 2 are xy values or point indices */ public boolean argsAreXYValues(int index) { return ((getFlag(index) & ARGS_ARE_XY_VALUES) != 0); } /** * Determine whether to round XY values to the grid */ public boolean roundXYToGrid(int index) { return ((getFlag(index) & ROUND_XY_TO_GRID) != 0); } /** * Determine whether there is a simple scale */ public boolean hasAScale(int index) { return ((getFlag(index) & WE_HAVE_A_SCALE) != 0); } /** * Determine whether there are more components left to read */ protected boolean moreComponents(int index) { return ((getFlag(index) & MORE_COMPONENTS) != 0); } /** * Determine whether there are separate scales on X and Y */ protected boolean hasXYScale(int index) { return ((getFlag(index) & WE_HAVE_AN_X_AND_Y_SCALE) != 0); } /** * Determine whether there is a 2x2 transform */ protected boolean hasTwoByTwo(int index) { return ((getFlag(index) & WE_HAVE_A_TWO_BY_TWO) != 0); } /** * Determine whether there are instructions */ protected boolean hasInstructions(int index) { return ((getFlag(index) & WE_HAVE_INSTRUCTIONS) != 0); } /** * Use the metrics of this component for the compound */ public boolean useMetrics(int index) { return ((getFlag(index) & USE_MY_METRICS) != 0); } /** * This component overlaps the existing compound */ public boolean overlapCompound(int index) { return ((getFlag(index) & OVERLAP_COMPOUND) != 0); } /** * Set the components */ void setComponents(GlyfComponent[] components) { this.components = components; } /** * Get the number of instructions */ public short getNumInstructions() { return (short) instructions.length; } /** * Get a given instruction */ public byte getInstruction(int index) { return instructions[index]; } /** * Set the instructions */ protected void setInstructions(byte[] instructions) { this.instructions = instructions; } /** * The record for a single component of this compound glyph */ class GlyfComponent { /** flags */ short flags; /** the index of the component glyf */ short glyphIndex; /** the points to match */ int compoundPoint; int componentPoint; /** affine transform of this component */ float a = 1.0f; float b = 0.0f; float c = 0.0f; float d = 1.0f; float e = 0.0f; float f = 0.0f; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/CMapFormat0.java0000644000175000017500000000733610732532577024277 0ustar twernertwerner/* * $Id: CMapFormat0.java,v 1.2 2007-12-20 18:33:30 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * * @author jkaplan */ public class CMapFormat0 extends CMap { /** * The glyph index array */ private byte[] glyphIndex; /** Creates a new instance of CMapFormat0 */ protected CMapFormat0(short language) { super((short) 0, language); byte[] initialIndex = new byte[256]; for (int i = 0; i < initialIndex.length; i++) { initialIndex[i] = (byte) i; } setMap(initialIndex); } /** * Get the length of this table */ public short getLength() { return (short) 262; } /** * Map from a byte */ public byte map(byte src) { int i = 0xff & src; return glyphIndex[i]; } /** * Cannot map from short */ public char map(char src) { if (src < 0 || src > 255) { // out of range return (char) 0; } return (char) (map((byte) src) & 0xff); } /** * Get the src code which maps to the given glyphID */ public char reverseMap(short glyphID) { for (int i = 0; i < glyphIndex.length; i++) { if ((glyphIndex[i] & 0xff) == glyphID) { return (char) i; } } return (char) 0; } /** * Set the entire map */ public void setMap(byte[] glyphIndex) { if (glyphIndex.length != 256) { throw new IllegalArgumentException("Glyph map must be size 256!"); } this.glyphIndex = glyphIndex; } /** * Set a single mapping entry */ public void setMap(byte src, byte dest) { int i = 0xff & src; glyphIndex[i] = dest; } /** * Get the whole map */ protected byte[] getMap() { return glyphIndex; } /** * Get the data in this map as a ByteBuffer */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(262); buf.putShort(getFormat()); buf.putShort(getLength()); buf.putShort(getLanguage()); buf.put(getMap()); // reset the position to the beginning of the buffer buf.flip(); return buf; } /** * Read the map in from a byte buffer */ public void setData(int length, ByteBuffer data) { if (length != 262) { throw new IllegalArgumentException("Bad length for CMap format 0"); } if (data.remaining() != 256) { throw new IllegalArgumentException("Wrong amount of data for CMap format 0"); } byte[] map = new byte[256]; data.get(map); setMap(map); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/CMapFormat4.java0000644000175000017500000003456311145024767024301 0ustar twernertwerner/* * $Id: CMapFormat4.java,v 1.3 2009-02-12 13:53:57 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.util.Collections; import java.util.Iterator; import java.util.SortedMap; import java.util.TreeMap; /** * * @author jkaplan */ public class CMapFormat4 extends CMap { /** * The segments and associated data can be a char[] or an Integer */ public SortedMap segments; /** Creates a new instance of CMapFormat0 */ protected CMapFormat4(short language) { super((short) 4, language); segments = Collections.synchronizedSortedMap(new TreeMap()); char[] map = new char[1]; map[0] = (char) 0; addSegment((short) 0xffff, (short) 0xffff, map); } /** * Add a segment with a map */ public void addSegment(short startCode, short endCode, char[] map) { if (map.length != (endCode - startCode) + 1) { throw new IllegalArgumentException("Wrong number of entries in map"); } Segment s = new Segment(startCode, endCode, true); // make sure we remove any old entries segments.remove(s); segments.put(s, map); } /** * Add a segment with an idDelta */ public void addSegment(short startCode, short endCode, short idDelta) { Segment s = new Segment(startCode, endCode, false); // make sure we remove any old entries segments.remove(s); segments.put(s, new Integer(idDelta)); } /** * Remove a segment */ public void removeSegment(short startCode, short endCode) { Segment s = new Segment(startCode, endCode, true); segments.remove(s); } /** * Get the length of this table */ public short getLength() { // start with the size of the fixed header short size = 16; // add the size of each segment header size += segments.size() * 8; // add the total number of mappings times the size of a mapping for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); // see if there's a map if (s.hasMap) { // if there is, add its size char[] map = (char[]) segments.get(s); size += map.length * 2; } } return size; } /** * Cannot map from a byte */ public byte map(byte src) { char c = map((char) src); if (c < Byte.MIN_VALUE || c > Byte.MAX_VALUE) { // out of range return 0; } return (byte) c; } /** * Map from char */ public char map(char src) { // find first segment with endcode > src for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); if (s.endCode >= src) { // are we within range? if (s.startCode <= src) { if (s.hasMap) { // return the index of this character in // the segment's map char[] map = (char[]) segments.get(s); return map[src - s.startCode]; } else { // return the character code + idDelta Integer idDelta = (Integer) segments.get(s); return (char) (src + idDelta.intValue()); } } else { // undefined character return (char) 0; } } } // shouldn't get here! return (char) 0; } /** * Get the src code which maps to the given glyphID */ public char reverseMap(short glyphID) { // look at each segment for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); // see if we have a map or a delta if (s.hasMap) { char[] map = (char[]) segments.get(s); // if we have a map, we have to iterate through it for (int c = 0; c < map.length; c++) { if (map[c] == glyphID) { return (char) (s.startCode + c); } } } else { Integer idDelta = (Integer) segments.get(s); // we can do the math to see if we're in range int start = s.startCode + idDelta.intValue(); int end = s.endCode + idDelta.intValue(); if (glyphID >= start && glyphID <= end) { // we're in the range return (char) (glyphID - idDelta.intValue()); } } } // not found! return (char) 0; } /** * Get the data in this map as a ByteBuffer */ public void setData(int length, ByteBuffer data) { // read the table size values short segCount = (short) (data.getShort() / 2); short searchRange = data.getShort(); short entrySelector = data.getShort(); short rangeShift = data.getShort(); // create arrays to store segment info short[] endCodes = new short[segCount]; short[] startCodes = new short[segCount]; short[] idDeltas = new short[segCount]; short[] idRangeOffsets = new short[segCount]; // the start of the glyph array int glyphArrayPos = 16 + (8 * segCount); // read the endCodes for (int i = 0; i < segCount; i++) { endCodes[i] = data.getShort(); } // read the pad data.getShort(); // read the start codes for (int i = 0; i < segCount; i++) { startCodes[i] = data.getShort(); } // read the idDeltas for (int i = 0; i < segCount; i++) { idDeltas[i] = data.getShort(); } // read the id range offsets for (int i = 0; i < segCount; i++) { idRangeOffsets[i] = data.getShort(); // calculate the actual offset if (idRangeOffsets[i] <= 0) { // the easy way addSegment(startCodes[i], endCodes[i], idDeltas[i]); } else { // find the start of the data segment int offset = (data.position() - 2) + idRangeOffsets[i]; // get the number of entries in the map int size = (endCodes[i] - startCodes[i]) + 1; // allocate the actual map char[] map = new char[size]; // remember our offset data.mark(); // read the mappings for (int c = 0; c < size; c++) { data.position(offset + (c * 2)); map[c] = data.getChar(); } // reset the position data.reset(); addSegment(startCodes[i], endCodes[i], map); } } } /** * Get the data in the map as a byte buffer */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); // write the header buf.putShort(getFormat()); buf.putShort((short) getLength()); buf.putShort(getLanguage()); // write the various values buf.putShort((short) (getSegmentCount() * 2)); buf.putShort(getSearchRange()); buf.putShort(getEntrySelector()); buf.putShort(getRangeShift()); // write the endCodes for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); buf.putShort((short) s.endCode); } // write the pad buf.putShort((short) 0); // write the startCodes for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); buf.putShort((short) s.startCode); } // write the idDeltas for segments using deltas for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); if (!s.hasMap) { Integer idDelta = (Integer) segments.get(s); buf.putShort(idDelta.shortValue()); } else { buf.putShort((short) 0); } } // the start of the glyph array int glyphArrayOffset = 16 + (8 * getSegmentCount()); // write the idRangeOffsets and maps for segments using maps for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); if (s.hasMap) { // first set the offset, which is the number of bytes from the // current position to the current offset buf.putShort((short) (glyphArrayOffset - buf.position())); // remember the current position buf.mark(); // move the position to the offset buf.position(glyphArrayOffset); // now write the map char[] map = (char[]) segments.get(s); for (int c = 0; c < map.length; c++) { buf.putChar(map[c]); } // reset the data pointer buf.reset(); // update the offset glyphArrayOffset += map.length * 2; } else { buf.putShort((short) 0); } } // make sure we are at the end of the buffer before we flip buf.position(glyphArrayOffset); // reset the data pointer buf.flip(); return buf; } /** * Get the segment count */ public short getSegmentCount() { return (short) segments.size(); } /** * Get the search range */ public short getSearchRange() { double pow = Math.floor(Math.log(getSegmentCount()) / Math.log(2)); double pow2 = Math.pow(2, pow); return (short) (2 * pow2); } /** * Get the entry selector */ public short getEntrySelector() { int sr2 = getSearchRange() / 2; return (short) (Math.log(sr2) / Math.log(2)); } /** * Get the rangeShift() */ public short getRangeShift() { return (short) ((2 * getSegmentCount()) - getSearchRange()); } /** Get a pretty string */ @Override public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(super.toString()); buf.append(indent + "SegmentCount : " + getSegmentCount() + "\n"); buf.append(indent + "SearchRange : " + getSearchRange() + "\n"); buf.append(indent + "EntrySelector: " + getEntrySelector() + "\n"); buf.append(indent + "RangeShift : " + getRangeShift() + "\n"); for (Iterator i = segments.keySet().iterator(); i.hasNext();) { Segment s = (Segment) i.next(); buf.append(indent); buf.append("Segment: " + Integer.toHexString(s.startCode)); buf.append("-" + Integer.toHexString(s.endCode) + " "); buf.append("hasMap: " + s.hasMap + " "); if (!s.hasMap) { buf.append("delta: " + segments.get(s)); } buf.append("\n"); } return buf.toString(); } class Segment implements Comparable { /** the end code (highest code in this segment) */ int endCode; /** the start code (lowest code in this segment) */ int startCode; /** whether it is a map or a delta */ boolean hasMap; /** Create a new segment */ public Segment(short startCode, short endCode, boolean hasMap) { // convert from unsigned short this.endCode = (0xffff & endCode); this.startCode = (0xffff & startCode); this.hasMap = hasMap; } /** Equals based on compareTo (only compares endCode) */ @Override public boolean equals(Object o) { return (compareTo(o) == 0); } /** Segments sort by increasing endCode */ public int compareTo(Object o) { if (!(o instanceof Segment)) { return -1; } Segment s = (Segment) o; // if regions overlap at all, declare the segments equal, // to avoid overlap in the segment list if (((s.endCode >= startCode) && (s.endCode <= endCode)) || ((s.startCode >= startCode) && (s.startCode <= endCode))) { return 0; } if (endCode > s.endCode) { return 1; } else if (endCode < s.endCode) { return -1; } else { return 0; } } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/TrueTypeFont.java0000644000175000017500000003170311157264553024627 0ustar twernertwerner/* * $Id: TrueTypeFont.java,v 1.6 2009-03-15 20:47:39 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.awt.Font; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; /** * * @author jkaplan */ public class TrueTypeFont { private int type; // could be a ByteBuffer or a TrueTypeTable private SortedMap tables; /** Creates a new instance of TrueTypeParser */ public TrueTypeFont (int type) { this.type = type; tables = Collections.synchronizedSortedMap ( new TreeMap ()); } /** * Parses a TrueType font from a byte array */ public static TrueTypeFont parseFont (byte[] orig) { ByteBuffer inBuf = ByteBuffer.wrap (orig); return parseFont (inBuf); } /** * Parses a TrueType font from a byte buffer */ public static TrueTypeFont parseFont (ByteBuffer inBuf) { int type = inBuf.getInt (); short numTables = inBuf.getShort (); short searchRange = inBuf.getShort (); short entrySelector = inBuf.getShort (); short rangeShift = inBuf.getShort (); TrueTypeFont font = new TrueTypeFont (type); parseDirectories (inBuf, numTables, font); return font; } /** * Get the type of this font */ public int getType () { return type; } /** * Add a table to the font * * @param tagString the name of this table, as a 4 character string * (i.e. cmap or head) * @param data the data for this table, as a byte buffer */ public void addTable (String tagString, ByteBuffer data) { tables.put (tagString, data); } /** * Add a table to the font * * @param tagString the name of this table, as a 4 character string * (i.e. cmap or head) * @param table the table */ public void addTable (String tagString, TrueTypeTable table) { tables.put (tagString, table); } /** * Get a table by name. This command causes the table in question * to be parsed, if it has not already been parsed. * * @param tagString the name of this table, as a 4 character string * (i.e. cmap or head) */ public TrueTypeTable getTable (String tagString) { Object tableObj = tables.get (tagString); TrueTypeTable table = null; if (tableObj instanceof ByteBuffer) { // the table has not yet been parsed. Parse it, and add the // parsed version to the map of tables. ByteBuffer data = (ByteBuffer) tableObj; table = TrueTypeTable.createTable (this, tagString, data); addTable (tagString, table); } else { table = (TrueTypeTable) tableObj; } return table; } /** * Remove a table by name * * @param tagString the name of this table, as a 4 character string * (i.e. cmap or head) */ public void removeTable (String tagString) { tables.remove (tagString); } /** * Get the number of tables */ public short getNumTables () { return (short) tables.size (); } /** * Get the search range */ public short getSearchRange () { double pow2 = Math.floor (Math.log (getNumTables ()) / Math.log (2)); double maxPower = Math.pow (2, pow2); return (short) (16 * maxPower); } /** * Get the entry selector */ public short getEntrySelector () { double pow2 = Math.floor (Math.log (getNumTables ()) / Math.log (2)); double maxPower = Math.pow (2, pow2); return (short) (Math.log (maxPower) / Math.log (2)); } /** * Get the range shift */ public short getRangeShift () { double pow2 = Math.floor (Math.log (getNumTables ()) / Math.log (2)); double maxPower = Math.pow (2, pow2); return (short) ((maxPower * 16) - getSearchRange ()); } /** * Write a font given the type and an array of Table Directory Entries */ public byte[] writeFont () { // allocate a buffer to hold the font ByteBuffer buf = ByteBuffer.allocate (getLength ()); // write the font header buf.putInt (getType ()); buf.putShort (getNumTables ()); buf.putShort (getSearchRange ()); buf.putShort (getEntrySelector ()); buf.putShort (getRangeShift ()); // first offset is the end of the table directory entries int curOffset = 12 + (getNumTables () * 16); // write the tables for (Iterator i = tables.keySet ().iterator (); i.hasNext ();) { String tagString = (String) i.next (); int tag = TrueTypeTable.stringToTag (tagString); ByteBuffer data = null; Object tableObj = tables.get (tagString); if (tableObj instanceof TrueTypeTable) { data = ((TrueTypeTable) tableObj).getData (); } else { data = (ByteBuffer) tableObj; } int dataLen = data.remaining (); // write the table directory entry buf.putInt (tag); buf.putInt (calculateChecksum (tagString, data)); buf.putInt (curOffset); buf.putInt (dataLen); // save the current position buf.mark (); // move to the current offset and write the data buf.position (curOffset); buf.put (data); // reset the data start pointer data.flip (); // return to the table directory entry buf.reset (); // udate the offset curOffset += dataLen; // don't forget the padding while ((curOffset % 4) > 0) { curOffset++; } } buf.position (curOffset); buf.flip (); // adjust the checksum updateChecksumAdj (buf); return buf.array (); } /** * Calculate the checksum for a given table * * @param tagString the name of the data * @param data the data in the table */ private static int calculateChecksum (String tagString, ByteBuffer data) { int sum = 0; data.mark (); // special adjustment for head table if (tagString.equals ("head")) { data.putInt (8, 0); } int nlongs = (data.remaining () + 3) / 4; while (nlongs-- > 0) { if (data.remaining () > 3) { sum += data.getInt (); } else { byte b0 = (data.remaining () > 0) ? data.get () : 0; byte b1 = (data.remaining () > 0) ? data.get () : 0; byte b2 = (data.remaining () > 0) ? data.get () : 0; sum += ((0xff & b0) << 24) | ((0xff & b1) << 16) | ((0xff & b2) << 8); } } data.reset (); return sum; } /** * Get directory entries from a font */ private static void parseDirectories (ByteBuffer data, int numTables, TrueTypeFont ttf) { for (int i = 0; i < numTables; i++) { int tag = data.getInt (); String tagString = TrueTypeTable.tagToString (tag); // System.out.println ("TTFFont.parseDirectories: " + tagString); int checksum = data.getInt (); int offset = data.getInt (); int length = data.getInt (); // read the data // System.out.println ("TTFFont.parseDirectories: checksum: " + // checksum + ", offset: " + offset + ", length: " + length); data.mark (); data.position (offset); ByteBuffer tableData = data.slice (); tableData.limit (length); int calcChecksum = calculateChecksum (tagString, tableData); if (calcChecksum == checksum) { ttf.addTable (tagString, tableData); } else { /* System.out.println("Mismatched checksums on table " + tagString + ": " + calcChecksum + " != " + checksum);*/ ttf.addTable (tagString, tableData); } data.reset (); } } /** * Get the length of the font * * @return the length of the entire font, in bytes */ private int getLength () { // the size of all the table directory entries int length = 12 + (getNumTables () * 16); // for each directory entry, get the size, // and don't forget the padding! for (Iterator i = tables.values ().iterator (); i.hasNext ();) { Object tableObj = i.next (); // add the length of the entry if (tableObj instanceof TrueTypeTable) { length += ((TrueTypeTable) tableObj).getLength (); } else { length += ((ByteBuffer) tableObj).remaining (); } // pad if ((length % 4) != 0) { length += (4 - (length % 4)); } } return length; } /** * Update the checksumAdj field in the head table */ private void updateChecksumAdj (ByteBuffer fontData) { int checksum = calculateChecksum ("", fontData); int checksumAdj = 0xb1b0afba - checksum; // find the head table int offset = 12 + (getNumTables () * 16); // find the head table for (Iterator i = tables.keySet ().iterator (); i.hasNext ();) { String tagString = (String) i.next (); // adjust the checksum if (tagString.equals ("head")) { fontData.putInt (offset + 8, checksumAdj); return; } // add the length of the entry Object tableObj = tables.get (tagString); if (tableObj instanceof TrueTypeTable) { offset += ((TrueTypeTable) tableObj).getLength (); } else { offset += ((ByteBuffer) tableObj).remaining (); } // pad if ((offset % 4) != 0) { offset += (4 - (offset % 4)); } } } /** * Write the font to a pretty string */ public String toString () { StringBuffer buf = new StringBuffer (); System.out.println ("Type : " + getType ()); System.out.println ("NumTables : " + getNumTables ()); System.out.println ("SearchRange : " + getSearchRange ()); System.out.println ("EntrySelector: " + getEntrySelector ()); System.out.println ("RangeShift : " + getRangeShift ()); for (Iterator i = tables.entrySet ().iterator (); i.hasNext ();) { Map.Entry e = (Map.Entry) i.next (); TrueTypeTable table = null; if (e.getValue () instanceof ByteBuffer) { table = getTable ((String) e.getKey ()); } else { table = (TrueTypeTable) e.getValue (); } System.out.println (table); } return buf.toString (); } /** * @param args the command line arguments */ public static void main (String[] args) { if (args.length != 1) { System.out.println ("Usage: "); System.out.println (" TrueTypeParser "); System.exit (-1); } try { RandomAccessFile raf = new RandomAccessFile (args[0], "r"); int size = (int) raf.length (); byte[] data = new byte[size]; raf.readFully (data); TrueTypeFont ttp = TrueTypeFont.parseFont (data); System.out.println (ttp); InputStream fontStream = new ByteArrayInputStream (ttp.writeFont ()); Font f = Font.createFont (Font.TRUETYPE_FONT, fontStream); } catch (Exception e) { e.printStackTrace (); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/GlyfTable.java0000644000175000017500000001033410732532577024067 0ustar twernertwerner/* * $Id: GlyfTable.java,v 1.2 2007-12-20 18:33:30 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * Model the TrueType Glyf table */ public class GlyfTable extends TrueTypeTable { /** * the glyph data, as either a byte buffer (unparsed) or a * glyph object (parsed) */ private Object[] glyphs; /** * The glyph location table */ private LocaTable loca; /** Creates a new instance of HmtxTable */ protected GlyfTable(TrueTypeFont ttf) { super (TrueTypeTable.GLYF_TABLE); loca = (LocaTable) ttf.getTable("loca"); MaxpTable maxp = (MaxpTable) ttf.getTable("maxp"); int numGlyphs = maxp.getNumGlyphs(); glyphs = new Object[numGlyphs]; } /** * Get the glyph at a given index, parsing it as needed */ public Glyf getGlyph(int index) { Object o = glyphs[index]; if (o == null) { return null; } if (o instanceof ByteBuffer) { Glyf g = Glyf.getGlyf((ByteBuffer) o); glyphs[index] = g; return g; } else { return (Glyf) o; } } /** get the data in this map as a ByteBuffer */ public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); // write the offsets for (int i = 0; i < glyphs.length; i++) { Object o = glyphs[i]; if (o == null) { continue; } ByteBuffer glyfData = null; if (o instanceof ByteBuffer) { glyfData = (ByteBuffer) o; } else { glyfData = ((Glyf) o).getData(); } glyfData.rewind(); buf.put(glyfData); glyfData.flip(); } // reset the start pointer buf.flip(); return buf; } /** Initialize this structure from a ByteBuffer */ public void setData(ByteBuffer data) { for (int i = 0; i < glyphs.length; i++) { int location = loca.getOffset(i); int length = loca.getSize(i); if (length == 0) { // undefined glyph continue; } data.position(location); ByteBuffer glyfData = data.slice(); glyfData.limit(length); glyphs[i] = glyfData; } } /** * Get the length of this table */ public int getLength() { int length = 0; for (int i = 0; i < glyphs.length; i++) { Object o = glyphs[i]; if (o == null) { continue; } if (o instanceof ByteBuffer) { length += ((ByteBuffer) o).remaining(); } else { length += ((Glyf) o).getLength(); } } return length; } /** * Create a pretty String */ public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Glyf Table: (" + glyphs.length + " glyphs)\n"); buf.append(indent + " Glyf 0: " + getGlyph(0)); return buf.toString(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/PostTable.java0000644000175000017500000004221510732532577024116 0ustar twernertwerner/* * $Id: PostTable.java,v 1.2 2007-12-20 18:33:31 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * Model the TrueType Post table * * @author jkaplan */ public class PostTable extends TrueTypeTable { /** Holds value of property format. */ private int format; /** Holds value of property italicAngle. */ private int italicAngle; /** Holds value of property underlinePosition. */ private short underlinePosition; /** Holds value of property underlineThickness. */ private short underlineThickness; /** Holds value of property isFixedPitch. */ private short isFixedPitch; /** Holds value of property minMemType42. */ private int minMemType42; /** Holds value of property maxMemType42. */ private int maxMemType42; /** Holds value of property minMemType1. */ private int minMemType1; /** Holds value of property maxMemType1. */ private int maxMemType1; /** A map which character values to names and vice versa */ private PostMap nameMap; /** Creates a new instance of PostTable */ protected PostTable() { super (TrueTypeTable.POST_TABLE); nameMap = new PostMap(); } /** * Map a character name to a glyphNameIndex */ public short getGlyphNameIndex(String name) { return nameMap.getCharIndex(name); } /** * Map a character code to a glyphIndex name */ public String getGlyphName(char c) { return nameMap.getCharName(c); } /** get the data in this map as a ByteBuffer */ public ByteBuffer getData() { int size = getLength(); ByteBuffer buf = ByteBuffer.allocate(size); // write the header buf.putInt(getFormat()); buf.putInt(getItalicAngle()); buf.putShort(getUnderlinePosition()); buf.putShort(getUnderlineThickness()); buf.putShort(getIsFixedPitch()); buf.putShort((short) 0); buf.putInt(getMinMemType42()); buf.putInt(getMaxMemType42()); buf.putInt(getMinMemType1()); buf.putInt(getMaxMemType1()); // now write the table buf.put(nameMap.getData()); // reset the start pointer buf.flip(); return buf; } /** Initialize this structure from a ByteBuffer */ public void setData(ByteBuffer data) { setFormat(data.getInt()); setItalicAngle(data.getInt()); setUnderlinePosition(data.getShort()); setUnderlineThickness(data.getShort()); setIsFixedPitch(data.getShort()); data.getShort(); setMinMemType42(data.getInt()); setMaxMemType42(data.getInt()); setMinMemType1(data.getInt()); setMaxMemType1(data.getInt()); // create the map, based on the type switch (format) { case 0x10000: nameMap = new PostMapFormat0(); break; case 0x20000: nameMap = new PostMapFormat2(); break; case 0x30000: // empty post map. nameMap = new PostMap(); break; default: nameMap = new PostMap(); System.out.println("Unknown post map type: " + Integer.toHexString(format)); break; } // fill in the data in the map nameMap.setData(data); } /** * Get the length of this table */ public int getLength() { int size = 32; if (nameMap != null) { size += nameMap.getLength(); } return size; } /** Getter for property format. * @return Value of property format. * */ public int getFormat() { return this.format; } /** Setter for property format. * @param format New value of property format. * */ public void setFormat(int format) { this.format = format; } /** Getter for property italicAngle. * @return Value of property italicAngle. * */ public int getItalicAngle() { return this.italicAngle; } /** Setter for property italicAngle. * @param italicAngle New value of property italicAngle. * */ public void setItalicAngle(int italicAngle) { this.italicAngle = italicAngle; } /** Getter for property underlinePosition. * @return Value of property underlinePosition. * */ public short getUnderlinePosition() { return this.underlinePosition; } /** Setter for property underlinePosition. * @param underlinePosition New value of property underlinePosition. * */ public void setUnderlinePosition(short underlinePosition) { this.underlinePosition = underlinePosition; } /** Getter for property underlineThickness. * @return Value of property underlineThickness. * */ public short getUnderlineThickness() { return this.underlineThickness; } /** Setter for property underlineThickness. * @param underlineThickness New value of property underlineThickness. * */ public void setUnderlineThickness(short underlineThickness) { this.underlineThickness = underlineThickness; } /** Getter for property isFixedPitch. * @return Value of property isFixedPitch. * */ public short getIsFixedPitch() { return this.isFixedPitch; } /** Setter for property isFixedPitch. * @param isFixedPitch New value of property isFixedPitch. * */ public void setIsFixedPitch(short isFixedPitch) { this.isFixedPitch = isFixedPitch; } /** Getter for property minMemType42. * @return Value of property minMemType42. * */ public int getMinMemType42() { return this.minMemType42; } /** Setter for property minMemType42. * @param minMemType42 New value of property minMemType42. * */ public void setMinMemType42(int minMemType42) { this.minMemType42 = minMemType42; } /** Getter for property maxMemType42. * @return Value of property maxMemType42. * */ public int getMaxMemType42() { return this.maxMemType42; } /** Setter for property maxMemType42. * @param maxMemType42 New value of property maxMemType42. * */ public void setMaxMemType42(int maxMemType42) { this.maxMemType42 = maxMemType42; } /** Getter for property minMemType1. * @return Value of property minMemType1. * */ public int getMinMemType1() { return this.minMemType1; } /** Setter for property minMemType1. * @param minMemType1 New value of property minMemType1. * */ public void setMinMemType1(int minMemType1) { this.minMemType1 = minMemType1; } /** Getter for property maxMemType1. * @return Value of property maxMemType1. * */ public int getMaxMemType1() { return this.maxMemType1; } /** Setter for property maxMemType1. * @param maxMemType1 New value of property maxMemType1. * */ public void setMaxMemType1(int maxMemType1) { this.maxMemType1 = maxMemType1; } /** An empty post map */ class PostMap { /** map a name to a character index */ short getCharIndex(String charName) { return (short) 0; } /** name a character index to a name */ String getCharName(char charIndex) { return null; } /** get the length of the data in this map */ int getLength() { return 0; } /** get the data in this map as a ByteBuffer */ ByteBuffer getData() { return ByteBuffer.allocate(0); } /** set the data in this map from a ByteBuffer */ void setData(ByteBuffer data) { // do nothing return; } } /** A Format 0 post map */ class PostMapFormat0 extends PostMap { /** the glyph names in standard Macintosh ordering */ protected final String stdNames[] = { /* 0 */ ".notdef", ".null", "nonmarkingreturn", "space", "exclam", "quotedbl", "numbersign", "dollar", /* 8 */ "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", /* 16 */ "hyphen", "period", "slash", "zero", "one", "two", "three", "four", /* 24 */ "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", /* 32 */ "equal", "greater", "question", "at", "A", "B", "C", "D", /* 40 */ "E", "F", "G", "H", "I", "J", "K", "L", /* 48 */ "M", "N", "O", "P", "Q", "R", "S", "T", /* 56 */ "U", "V", "W", "X", "Y", "Z", "bracketleft", "ackslash", /* 64 */ "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", /* 72 */ "e", "f", "g", "h", "i", "j", "k", "l", /* 80 */ "m", "n", "o", "p", "q", "r", "s", "t", /* 88 */ "u", "v", "w", "x", "y", "z", "braceleft", "bar", /* 96 */ "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", /* 104 */ "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", /* 112 */ "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", /* 120 */ "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", /* 128 */ "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", /* 136 */ "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", /* 144 */ "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", /* 152 */ "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", /* 160 */ "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", /* 168 */ "Delta", "guillemotleft", "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", "Otilde", /* 176 */ "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", /* 184 */ "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", /* 192 */ "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", /* 200 */ "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", /* 208 */ "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", /* 216 */ "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", /* 224 */ "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", /* 232 */ "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", /* 240 */ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", /* 248 */ "Gbreve", "gbreve", "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", /* 256 */ "ccaron", "dcroat" }; /** map a name to a character index */ short getCharIndex(String charName) { for (int i = 0; i < stdNames.length; i++) { if (charName.equals(stdNames[i])) { return (short) i; } } return (short) 0; } /** name a character index to a name */ String getCharName(char charIndex) { return stdNames[charIndex]; } /** get the length of the data in this map */ int getLength() { return 0; } /** get the data in this map as a ByteBuffer */ ByteBuffer getData() { return ByteBuffer.allocate(0); } /** set the data in this map from a ByteBuffer */ void setData(ByteBuffer data) { // do nothing return; } } /** an extension to handle format 2 post maps */ class PostMapFormat2 extends PostMapFormat0 { /** the glyph name index */ short[] glyphNameIndex; /** the glyph names */ String[] glyphNames; /** Map a character name to an index */ short getCharIndex(String charName) { // find the index of this character name short idx = -1; // first try the local names map for (int i = 0; i < glyphNames.length; i++) { if (charName.equals(glyphNames[i])) { // this is the value from the glyph name index idx = (short) (stdNames.length + i); break; } } // if that doesn't work, try the standard names if (idx == -1) { idx = super.getCharIndex(charName); } // now get the entry in the index for (int c = 0; c < glyphNameIndex.length; c++) { if (glyphNameIndex[c] == idx) { return (short) c; } } // not found return (short) 0; } /** Map an index to a character name */ String getCharName(char charIndex) { if (charIndex >= stdNames.length) { return glyphNames[charIndex - stdNames.length]; } return super.getCharName(charIndex); } /** get the length of this class's data */ int getLength() { // the size of the header plus the table of mappings int size = 2 + (2 * glyphNameIndex.length); // the size of each string -- note the extra byte for a pascal // string for (int i = 0; i < glyphNames.length; i++) { size += glyphNames[i].length() + 1; } return size; } /** get the data in this map as a byte array */ ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); // write the number of glyphs buf.putShort((short) glyphNameIndex.length); // write the name indices for (int i = 0; i < glyphNameIndex.length; i++) { buf.putShort(glyphNameIndex[i]); } // write the names as pascal strings for (int i = 0; i < glyphNames.length; i++) { buf.put((byte) glyphNames[i].length()); buf.put(glyphNames[i].getBytes()); } // reset the start pointer buf.flip(); return buf; } /** set the contents of this map from a ByteBuffer */ void setData(ByteBuffer data) { short numGlyphs = data.getShort(); glyphNameIndex = new short[numGlyphs]; // the highest glyph index seen so far int maxGlyph = 257; for (int i = 0; i < numGlyphs; i++) { glyphNameIndex[i] = data.getShort(); // see if this is the highest glyph if (glyphNameIndex[i] > maxGlyph) { maxGlyph = glyphNameIndex[i]; } } // subtract off the default glyphs maxGlyph -= 257; // read in any additional names glyphNames = new String[maxGlyph]; // read each name from a pascal string // the length is stored in the first byte, followed by // the data for (int i = 0; i < maxGlyph; i++) { // size in the first byte byte size = data.get(); // then the data byte[] stringData = new byte[size]; data.get(stringData); glyphNames[i] = new String(stringData); } } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/CmapTable.java0000644000175000017500000002012011145024767024034 0ustar twernertwerner/* * $Id: CmapTable.java,v 1.3 2009-02-12 13:53:57 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.SortedMap; import java.util.TreeMap; /** * Represents the TTF "cmap" table * * @author jkaplan */ public class CmapTable extends TrueTypeTable { /** Holds value of property version. */ private short version; /** * Holds the CMap subtables, sorted properly */ private SortedMap subtables; /** Creates a new instance of CmapTable */ protected CmapTable() { super(TrueTypeTable.CMAP_TABLE); setVersion((short) 0x0); subtables = Collections.synchronizedSortedMap(new TreeMap()); } /** * Add a CMap */ public void addCMap(short platformID, short platformSpecificID, CMap cMap) { CmapSubtable key = new CmapSubtable(platformID, platformSpecificID); subtables.put(key, cMap); } /** * Get a CMap by platform and specific ID */ public CMap getCMap(short platformID, short platformSpecificID) { CmapSubtable key = new CmapSubtable(platformID, platformSpecificID); return (CMap) subtables.get(key); } /** * Get all CMaps */ public CMap[] getCMaps() { Collection c = subtables.values(); CMap[] maps = new CMap[c.size()]; c.toArray(maps); return maps; } /** * Remove a CMap */ public void removeCMap(short platformID, short platformSpecificID) { CmapSubtable key = new CmapSubtable(platformID, platformSpecificID); subtables.remove(key); } @Override public void setData(ByteBuffer data) { setVersion(data.getShort()); short numberSubtables = data.getShort(); for (int i = 0; i < numberSubtables; i++) { short platformID = data.getShort(); short platformSpecificID = data.getShort(); int offset = data.getInt(); data.mark(); // get the position from the start of this buffer data.position(offset); ByteBuffer mapData = data.slice(); data.reset(); try { CMap cMap = CMap.getMap(mapData); if (cMap != null) { addCMap(platformID, platformSpecificID, cMap); } } catch (Exception ex) { System.out.println("Error reading map. PlatformID=" + platformID + ", PlatformSpecificID=" + platformSpecificID); System.out.println("Reason: " + ex); } } } @Override public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); // write the table header buf.putShort(getVersion()); buf.putShort((short) subtables.size()); // the current offset to write to, starts at the end of the // subtables int curOffset = 4 + (subtables.size() * 8); // write the subtables for (Iterator i = subtables.keySet().iterator(); i.hasNext();) { CmapSubtable cms = (CmapSubtable) i.next(); CMap map = (CMap) subtables.get(cms); buf.putShort(cms.platformID); buf.putShort(cms.platformSpecificID); buf.putInt(curOffset); curOffset += map.getLength(); } // write the tables for (Iterator i = subtables.values().iterator(); i.hasNext();) { CMap map = (CMap) i.next(); buf.put(map.getData()); } // reset the position to the start of the buffer buf.flip(); return buf; } /** * Get the size of the table, in bytes */ @Override public int getLength() { // start with the size of the fixed data int length = 4; // add the size of the subtables length += subtables.size() * 8; // add the size of the dynamic data for (Iterator i = subtables.values().iterator(); i.hasNext();) { // add the size of the subtable data CMap map = (CMap) i.next(); length += map.getLength(); } return length; } /** Getter for property version. * @return Value of property version. * */ public short getVersion() { return this.version; } /** Setter for property version. * @param version New value of property version. * */ public void setVersion(short version) { this.version = version; } /** * Get the number of tables */ public short getNumberSubtables() { return (short) subtables.size(); } /** Print a pretty string */ @Override public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Version: " + this.getVersion() + "\n"); buf.append(indent + "NumMaps: " + this.getNumberSubtables() + "\n"); for (Iterator i = subtables.keySet().iterator(); i.hasNext();) { CmapSubtable key = (CmapSubtable) i.next(); buf.append(indent + "Map: platformID: " + key.platformID + " PlatformSpecificID: " + key.platformSpecificID + "\n"); CMap map = (CMap) subtables.get(key); buf.append(map.toString()); } return buf.toString(); } class CmapSubtable implements Comparable { /** * The platformID for this subtable */ short platformID; /** * The platform-specific id */ short platformSpecificID; /** * Create a Cmap subtable */ protected CmapSubtable(short platformID, short platformSpecificID) { this.platformID = platformID; this.platformSpecificID = platformSpecificID; } /** * Compare two subtables */ @Override public boolean equals(Object obj) { return (compareTo(obj) == 0); } /** * Sort ascending by platform ID and then specific ID */ public int compareTo(Object obj) { if (!(obj instanceof CmapSubtable)) { return -1; } CmapSubtable cms = (CmapSubtable) obj; if (platformID < cms.platformID) { return -1; } else if (platformID > cms.platformID) { return 1; } else { if (platformSpecificID < cms.platformSpecificID) { return -1; } else if (platformSpecificID > cms.platformSpecificID) { return 1; } else { return 0; } } } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/Glyf.java0000644000175000017500000001224510732532577023122 0ustar twernertwerner/* * $Id: Glyf.java,v 1.2 2007-12-20 18:33:31 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * A single glyph in a pdf font. May be simple or compound via subclasses */ public class Glyf { /** If true, the glyf is compound */ private boolean isCompound; /** the number of contours */ private short numContours; /** the minimum x value */ private short minX; /** the minimum y value */ private short minY; /** the maximum x value */ private short maxX; /** the maximum y value */ private short maxY; /** * Creates a new instance of glyf * Don't use this directly, use Glyf.getGlyf() */ protected Glyf() { } /** * Get a map from the given data * * This method reads the format, data and length variables of * the map. */ public static Glyf getGlyf(ByteBuffer data) { short numContours = data.getShort(); Glyf g = null; if (numContours == 0) { // no glyph data g = new Glyf(); } else if (numContours == -1) { // compound glyf g = new GlyfCompound(); } else if (numContours > 0) { // simple glyf g = new GlyfSimple(); } else { throw new IllegalArgumentException("Unknown glyf type: " + numContours); } g.setNumContours(numContours); g.setMinX(data.getShort()); g.setMinY(data.getShort()); g.setMaxX(data.getShort()); g.setMaxY(data.getShort()); // do glyphtype-specific parsing g.setData(data); return g; } /** * Set the data for this glyf. Do nothing, since a glyf with * no contours has no glyf data. */ public void setData(ByteBuffer data) { return; } /** * Get the data in this glyf as a byte buffer. Return the basic * glyf data only, since there is no specific data. This method returns * the data un-flipped, so subclasses can simply append to the allocated * buffer. */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putShort(getNumContours()); buf.putShort(getMinX()); buf.putShort(getMinY()); buf.putShort(getMaxX()); buf.putShort(getMaxY()); // don't flip the buffer, since it may be used by subclasses return buf; } /** * Get the length of this glyf. A glyf with no data has a length * of 10 (2 bytes each for 5 short values) */ public short getLength() { return 10; } /** * Get whether this is a simple or compound glyf */ public boolean isCompound() { return isCompound; } /** * Set whether this is a simple or compound glyf */ protected void setCompound(boolean isCompound) { this.isCompound = isCompound; } /** * Get the number of contours in this glyf */ public short getNumContours() { return numContours; } /** * Set the number of contours in this glyf */ protected void setNumContours(short numContours) { this.numContours = numContours; } /** * Get the minimum x in this glyf */ public short getMinX() { return minX; } /** * Set the minimum X in this glyf */ protected void setMinX(short minX) { this.minX = minX; } /** * Get the minimum y in this glyf */ public short getMinY() { return minY; } /** * Set the minimum Y in this glyf */ protected void setMinY(short minY) { this.minY = minY; } /** * Get the maximum x in this glyf */ public short getMaxX() { return maxX; } /** * Set the maximum X in this glyf */ protected void setMaxX(short maxX) { this.maxX = maxX; } /** * Get the maximum y in this glyf */ public short getMaxY() { return maxY; } /** * Set the maximum Y in this glyf */ protected void setMaxY(short maxY) { this.maxY = maxY; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/CMapFormat6.java0000644000175000017500000000766711146131260024274 0ustar twernertwerner/* * $Id: CMapFormat6.java,v 1.1 2009-02-16 00:26:24 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; import java.util.*; /** * * @author jkaplan */ public class CMapFormat6 extends CMap { /** First character code of subrange. */ private short firstCode; /** Number of character codes in subrange. */ private short entryCount; /** Array of glyph index values for character codes in the range. */ private short [] glyphIndexArray; /** a reverse lookup from glyph id to index. */ private HashMap glyphLookup = new HashMap(); /** Creates a new instance of CMapFormat0 */ protected CMapFormat6(short language) { super((short) 6, language); } /** * Get the length of this table */ public short getLength() { // start with the size of the fixed header short size = 5 * 2; // add the size of each segment header size += entryCount * 2; return size; } /** * Cannot map from a byte */ public byte map(byte src) { char c = map((char) src); if (c < Byte.MIN_VALUE || c > Byte.MAX_VALUE) { // out of range return 0; } return (byte) c; } /** * Map from char */ public char map(char src) { // find first segment with endcode > src if (src < firstCode || src > (firstCode + entryCount)) { // Codes outside of the range are assumed to be missing and are // mapped to the glyph with index 0 return '\000'; } return (char) glyphIndexArray[src - firstCode]; } /** * Get the src code which maps to the given glyphID */ public char reverseMap(short glyphID) { Short result = glyphLookup.get(new Short(glyphID)); if (result == null) { return '\000'; } return (char) result.shortValue(); } /** * Get the data in this map as a ByteBuffer */ public void setData(int length, ByteBuffer data) { // read the table size values firstCode = data.getShort(); entryCount = data.getShort(); glyphIndexArray = new short [entryCount]; for (int i = 0; i < glyphIndexArray.length; i++) { glyphIndexArray[i] = data.getShort(); glyphLookup.put(new Short(glyphIndexArray[i]), new Short((short) (i + firstCode))); } } /** * Get the data in the map as a byte buffer */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); // write the header buf.putShort(getFormat()); buf.putShort((short) getLength()); buf.putShort(getLanguage()); // write the various values buf.putShort(firstCode); buf.putShort(entryCount); // write the endCodes for (int i = 0; i < glyphIndexArray.length; i++) { buf.putShort(glyphIndexArray[i]); } // reset the data pointer buf.flip(); return buf; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/ttf/MaxpTable.java0000644000175000017500000003200311133763517024064 0ustar twernertwerner/* * $Id: MaxpTable.java,v 1.3 2009-01-16 01:47:59 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font.ttf; import java.nio.ByteBuffer; /** * * @author jkaplan */ public class MaxpTable extends TrueTypeTable { /** Holds value of property version. */ private int version; // the following are supposed to be USHORT, but will be Int to enclose the sign // (http://www.microsoft.com/typography/OTSpec/maxp.htm) /** Holds value of property numGlyphs. */ private int numGlyphs; /** Holds value of property maxPoints. */ private int maxPoints; /** Holds value of property maxContours. */ private int maxContours; /** Holds value of property maxComponentPoints. */ private int maxComponentPoints; /** Holds value of property maxComponentContours. */ private int maxComponentContours; /** Holds value of property maxZones. */ private int maxZones; /** Holds value of property maxTwilightPoints. */ private int maxTwilightPoints; /** Holds value of property maxStorage. */ private int maxStorage; /** Holds value of property maxFunctionDefs. */ private int maxFunctionDefs; /** Holds value of property maxInstructionDefs. */ private int maxInstructionDefs; /** Holds value of property maxStackElements. */ private int maxStackElements; /** Holds value of property maxSizeOfInstructions. */ private int maxSizeOfInstructions; /** Holds value of property maxComponentElements. */ private int maxComponentElements; /** Holds value of property maxComponentDepth. */ private int maxComponentDepth; /** Creates a new instance of MaxpTable */ protected MaxpTable() { super (TrueTypeTable.MAXP_TABLE); setVersion(0x10000); setNumGlyphs(0); setMaxPoints(0); setMaxContours(0); setMaxComponentPoints(0); setMaxComponentContours(0); setMaxZones(2); setMaxTwilightPoints(0); setMaxStorage(0); setMaxFunctionDefs(0); setMaxInstructionDefs(0); setMaxStackElements(0); setMaxSizeOfInstructions(0); setMaxComponentElements(0); setMaxComponentDepth(0); } /** * Set the values from data */ public void setData(ByteBuffer data) { if (data.remaining() != 32) { throw new IllegalArgumentException("Bad size for Maxp table"); } setVersion(data.getInt()); setNumGlyphs(data.getShort()); setMaxPoints(data.getShort()); setMaxContours(data.getShort()); setMaxComponentPoints(data.getShort()); setMaxComponentContours(data.getShort()); setMaxZones(data.getShort()); setMaxTwilightPoints(data.getShort()); setMaxStorage(data.getShort()); setMaxFunctionDefs(data.getShort()); setMaxInstructionDefs(data.getShort()); setMaxStackElements(data.getShort()); setMaxSizeOfInstructions(data.getShort()); setMaxComponentElements(data.getShort()); setMaxComponentDepth(data.getShort()); } /** * Get a buffer from the data */ public ByteBuffer getData() { ByteBuffer buf = ByteBuffer.allocate(getLength()); buf.putInt(getVersion()); buf.putShort((short) getNumGlyphs()); buf.putShort((short) getMaxPoints()); buf.putShort((short) getMaxContours()); buf.putShort((short) getMaxComponentPoints()); buf.putShort((short) getMaxComponentContours()); buf.putShort((short) getMaxZones()); buf.putShort((short) getMaxTwilightPoints()); buf.putShort((short) getMaxStorage()); buf.putShort((short) getMaxFunctionDefs()); buf.putShort((short) getMaxInstructionDefs()); buf.putShort((short) getMaxStackElements()); buf.putShort((short) getMaxSizeOfInstructions()); buf.putShort((short) getMaxComponentElements()); buf.putShort((short) getMaxComponentDepth()); // reset the position to the beginning of the buffer buf.flip(); return buf; } /** * Get the length of this table */ public int getLength() { return 32; } /** Getter for property version. * @return Value of property version. * */ public int getVersion() { return this.version; } /** Setter for property version. * @param version New value of property version. * */ public void setVersion(int version) { this.version = version; } /** Getter for property numGlyphs. * @return Value of property numGlyphs. * */ public int getNumGlyphs() { return this.numGlyphs & 0xFFFF; } /** Setter for property numGlyphs. * @param numGlyphs New value of property numGlyphs. * */ public void setNumGlyphs(int numGlyphs) { this.numGlyphs = numGlyphs; } /** Getter for property maxPoints. * @return Value of property maxPoints. * */ public int getMaxPoints() { return this.maxPoints & 0xFFFF; } /** Setter for property maxPoints. * @param maxPoints New value of property maxPoints. * */ public void setMaxPoints(int maxPoints) { this.maxPoints = maxPoints; } /** Getter for property maxContours. * @return Value of property maxContours. * */ public int getMaxContours() { return this.maxContours & 0xFFFF; } /** Setter for property maxContours. * @param maxContours New value of property maxContours. * */ public void setMaxContours(int maxContours) { this.maxContours = maxContours; } /** Getter for property maxComponentPoints. * @return Value of property maxComponentPoints. * */ public int getMaxComponentPoints() { return this.maxComponentPoints & 0xFFFF; } /** Setter for property maxComponentPoints. * @param maxComponentPoints New value of property maxComponentPoints. * */ public void setMaxComponentPoints(int maxComponentPoints) { this.maxComponentPoints = maxComponentPoints; } /** Getter for property maxComponentContours. * @return Value of property maxComponentContours. * */ public int getMaxComponentContours() { return this.maxComponentContours & 0xFFFF; } /** Setter for property maxComponentContours. * @param maxComponentContours New value of property maxComponentContours. * */ public void setMaxComponentContours(int maxComponentContours) { this.maxComponentContours = maxComponentContours; } /** Getter for property maxZones. * @return Value of property maxZones. * */ public int getMaxZones() { return this.maxZones & 0xFFFF; } /** Setter for property maxZones. * @param maxZones New value of property maxZones. * */ public void setMaxZones(int maxZones) { this.maxZones = maxZones; } /** Getter for property maxTwilightPoints. * @return Value of property maxTwilightPoints. * */ public int getMaxTwilightPoints() { return this.maxTwilightPoints & 0xFFFF; } /** Setter for property maxTwilightPoints. * @param maxTwilightPoints New value of property maxTwilightPoints. * */ public void setMaxTwilightPoints(int maxTwilightPoints) { this.maxTwilightPoints = maxTwilightPoints; } /** Getter for property maxStorage. * @return Value of property maxStorage. * */ public int getMaxStorage() { return this.maxStorage & 0xFFFF; } /** Setter for property maxStorage. * @param maxStorage New value of property maxStorage. * */ public void setMaxStorage(int maxStorage) { this.maxStorage = maxStorage; } /** Getter for property maxFunctionDefs. * @return Value of property maxFunctionDefs. * */ public int getMaxFunctionDefs() { return this.maxFunctionDefs & 0xFFFF; } /** Setter for property maxFunctionDefs. * @param maxFunctionDefs New value of property maxFunctionDefs. * */ public void setMaxFunctionDefs(int maxFunctionDefs) { this.maxFunctionDefs = maxFunctionDefs; } /** Getter for property maxInstructionDefs. * @return Value of property maxInstructionDefs. * */ public int getMaxInstructionDefs() { return this.maxInstructionDefs & 0xFFFF; } /** Setter for property maxInstructionDefs. * @param maxInstructionDefs New value of property maxInstructionDefs. * */ public void setMaxInstructionDefs(int maxInstructionDefs) { this.maxInstructionDefs = maxInstructionDefs; } /** Getter for property maxStackElements. * @return Value of property maxStackElements. * */ public int getMaxStackElements() { return this.maxStackElements & 0xFFFF; } /** Setter for property maxStackElements. * @param maxStackElements New value of property maxStackElements. * */ public void setMaxStackElements(int maxStackElements) { this.maxStackElements = maxStackElements; } /** Getter for property maxSizeOfInstructions. * @return Value of property maxSizeOfInstructions. * */ public int getMaxSizeOfInstructions() { return this.maxSizeOfInstructions & 0xFFFF; } /** Setter for property maxSizeOfInstructions. * @param maxSizeOfInstructions New value of property maxSizeOfInstructions. * */ public void setMaxSizeOfInstructions(int maxSizeOfInstructions) { this.maxSizeOfInstructions = maxSizeOfInstructions; } /** Getter for property maxComponentElements. * @return Value of property maxComponentElements. * */ public int getMaxComponentElements() { return this.maxComponentElements & 0xFFFF; } /** Setter for property maxComponentElements. * @param maxComponentElements New value of property maxComponentElements. * */ public void setMaxComponentElements(int maxComponentElements) { this.maxComponentElements = maxComponentElements; } /** Getter for property maxComponentDepth. * @return Value of property maxComponentDepth. * */ public int getMaxComponentDepth() { return this.maxComponentDepth & 0xFFFF; } /** Setter for property maxComponentDepth. * @param maxComponentDepth New value of property maxComponentDepth. * */ public void setMaxComponentDepth(int maxComponentDepth) { this.maxComponentDepth = maxComponentDepth; } /** * Create a pretty String */ public String toString() { StringBuffer buf = new StringBuffer(); String indent = " "; buf.append(indent + "Version : " + Integer.toHexString(getVersion()) + "\n"); buf.append(indent + "NumGlyphs : " + getNumGlyphs() + "\n"); buf.append(indent + "MaxPoints : " + getMaxPoints() + "\n"); buf.append(indent + "MaxContours : " + getMaxContours() + "\n"); buf.append(indent + "MaxCompPoints : " + getMaxComponentPoints() + "\n"); buf.append(indent + "MaxCompContours : " + getMaxComponentContours() + "\n"); buf.append(indent + "MaxZones : " + getMaxZones() + "\n"); buf.append(indent + "MaxTwilightPoints: " + getMaxTwilightPoints() + "\n"); buf.append(indent + "MaxStorage : " + getMaxStorage() + "\n"); buf.append(indent + "MaxFuncDefs : " + getMaxFunctionDefs() + "\n"); buf.append(indent + "MaxInstDefs : " + getMaxInstructionDefs() + "\n"); buf.append(indent + "MaxStackElements : " + getMaxStackElements() + "\n"); buf.append(indent + "MaxSizeInst : " + getMaxSizeOfInstructions() + "\n"); buf.append(indent + "MaxCompElements : " + getMaxComponentElements() + "\n"); buf.append(indent + "MaxCompDepth : " + getMaxComponentDepth() + "\n"); return buf.toString(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/PDFGlyph.java0000644000175000017500000000627711144055465023043 0ustar twernertwerner/* * $Id: PDFGlyph.java,v 1.3 2009-02-09 16:35:01 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import com.sun.pdfview.PDFPage; import com.sun.pdfview.PDFShapeCmd; /** * A single glyph in a stream of PDF text, which knows how to write itself * onto a PDF command stream */ public class PDFGlyph { /** the character code of this glyph */ private char src; /** the name of this glyph */ private String name; /** the advance from this glyph */ private Point2D advance; /** the shape represented by this glyph (for all fonts but type 3) */ private GeneralPath shape; /** the PDFPage storing this glyph's commands (for type 3 fonts) */ private PDFPage page; /** Creates a new instance of PDFGlyph based on a shape */ public PDFGlyph(char src, String name, GeneralPath shape, Point2D.Float advance) { this.shape = shape; this.advance = advance; this.src = src; this.name = name; } /** Creates a new instance of PDFGlyph based on a page */ public PDFGlyph(char src, String name, PDFPage page, Point2D advance) { this.page = page; this.advance = advance; this.src = src; this.name = name; } /** Get the character code of this glyph */ public char getChar() { return src; } /** Get the name of this glyph */ public String getName() { return name; } /** Get the shape of this glyph */ public GeneralPath getShape() { return shape; } /** Get the PDFPage for a type3 font glyph */ public PDFPage getPage() { return page; } /** Add commands for this glyph to a page */ public Point2D addCommands(PDFPage cmds, AffineTransform transform, int mode) { if (shape != null) { GeneralPath outline= (GeneralPath) shape.createTransformedShape(transform); cmds.addCommand(new PDFShapeCmd(outline, mode)); } else if (page != null) { cmds.addCommands(page, transform); } return advance; } public String toString () { StringBuffer str = new StringBuffer (); str.append(name); return str.toString(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/NativeFont.java0000644000175000017500000003744711157264553023512 0ustar twernertwerner/* * $Id: NativeFont.java,v 1.4 2009-03-15 20:47:38 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.Font; import java.awt.FontFormatException; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.font.OpenType; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.font.ttf.CMap; import com.sun.pdfview.font.ttf.CMapFormat0; import com.sun.pdfview.font.ttf.CMapFormat4; import com.sun.pdfview.font.ttf.CmapTable; import com.sun.pdfview.font.ttf.HeadTable; import com.sun.pdfview.font.ttf.HmtxTable; import com.sun.pdfview.font.ttf.NameTable; import com.sun.pdfview.font.ttf.PostTable; import com.sun.pdfview.font.ttf.TrueTypeFont; import com.sun.pdfview.font.ttf.TrueTypeTable; /** * a font object derived from a true type font. * * @author Mike Wessler */ public class NativeFont extends OutlineFont { /** Control characters to filter out of the underlying font */ protected static final char[] controlChars = {0x9, 0xa, 0xd}; /** the ids of our favorite CMaps */ protected static final short[] mapIDs = { 3, 1, /* Microsoft Unicode */ 0, 0, /* unicode default */ 0, 3, /* unicode 2.0 map */ 1, 0 /* macintosh */}; /** the actual font in use */ private Font f; /** the font render context */ private FontRenderContext basecontext = new FontRenderContext (new AffineTransform (), true, true); /** the cmap table from a TrueType font */ private CmapTable cmapTable; /** the post table from a TrueType font */ private PostTable postTable; /** the number of font units in one em */ private int unitsPerEm; /** the hmtx table from the TrueType font */ private HmtxTable hmtxTable; /** * create a new NativeFont object based on a description of the * font from the PDF file. If the description happens to contain * an in-line true-type font file (under key "FontFile2"), use the * true type font. Otherwise, parse the description for key information * and use that to generate an appropriate font. */ public NativeFont (String baseFont, PDFObject fontObj, PDFFontDescriptor descriptor) throws IOException { super (baseFont, fontObj, descriptor); String fontName = descriptor.getFontName (); PDFObject ttf = descriptor.getFontFile2 (); if (ttf != null) { byte[] fontdata = ttf.getStream (); try { setFont (fontdata); } catch (FontFormatException ffe) { throw new PDFParseException ("Font format exception: " + ffe); } } else { int flags = descriptor.getFlags (); int style = ((flags & PDFFontDescriptor.FORCEBOLD) != 0) ? Font.BOLD : Font.PLAIN; if (fontName.indexOf ("Bold") > 0) { style |= Font.BOLD; } if (descriptor.getItalicAngle () != 0) { style |= Font.ITALIC; } if ((flags & PDFFontDescriptor.FIXED_PITCH) != 0) { // fixed width setFont (new Font ("Monospaced", style, 1)); } else if ((flags & PDFFontDescriptor.SERIF) != 0) { // serif font setFont (new Font ("Serif", style, 1)); } else { setFont (new Font ("Sans-serif", style, 1)); } } } /** * Get a glyph outline by name * * @param name the name of the desired glyph * @return the glyph outline, or null if unavailable */ protected GeneralPath getOutline (String name, float width) { if (postTable != null && cmapTable != null) { // map this character name to a glyph ID short glyphID = postTable.getGlyphNameIndex (name); if (glyphID == 0) { // no glyph -- try by index return null; } // the mapped character char mappedChar = 0; for (int i = 0; i < mapIDs.length; i += 2) { CMap map = cmapTable.getCMap (mapIDs[i], mapIDs[i + 1]); if (map != null) { mappedChar = map.reverseMap (glyphID); // we found a character if (mappedChar != 0) { break; } } } return getOutline (mappedChar, width); } // no maps found, hope the font can deal return null; } /** * Get a glyph outline by character code * * Note this method must always return an outline * * @param src the character code of the desired glyph * @return the glyph outline */ protected GeneralPath getOutline (char src, float width) { // some true type fonts put characters in the undefined // region of Unicode instead of as normal characters. if (!f.canDisplay (src) && f.canDisplay ((char) (src + 0xf000))) { src += 0xf000; } // filter out control characters for (int i = 0; i < controlChars.length; i++) { if (controlChars[i] == src) { src = (char) (0xf000 | src); break; } } char[] glyph = new char[1]; glyph[0] = src; GlyphVector gv = f.createGlyphVector (basecontext, glyph); GeneralPath gp = new GeneralPath (gv.getGlyphOutline (0)); // this should be gv.getGlyphMetrics(0).getAdvance(), but that is // broken on the Mac, so we need to read the advance from the // hmtx table in the font CMap map = cmapTable.getCMap (mapIDs[0], mapIDs[1]); int glyphID = map.map (src); float advance = (float) hmtxTable.getAdvance (glyphID) / (float) unitsPerEm; float widthfactor = width / advance; gp.transform (AffineTransform.getScaleInstance (widthfactor, -1)); return gp; } /** * Set the font * * @param f the font to use */ protected void setFont (Font f) { this.f = f; // if it's an OpenType font, parse the relevant tables to get // glyph name to code mappings if (f instanceof OpenType) { OpenType ot = (OpenType) f; byte[] cmapData = ot.getFontTable (OpenType.TAG_CMAP); byte[] postData = ot.getFontTable (OpenType.TAG_POST); TrueTypeFont ttf = new TrueTypeFont (0x10000); cmapTable = (CmapTable) TrueTypeTable.createTable (ttf, "cmap", ByteBuffer.wrap (cmapData)); ttf.addTable ("cmap", cmapTable); postTable = (PostTable) TrueTypeTable.createTable (ttf, "post", ByteBuffer.wrap (postData)); ttf.addTable ("post", postTable); } } /** * Set the font * * @param fontdata the font data as a byte array */ protected void setFont (byte[] fontdata) throws FontFormatException, IOException { // System.out.println("Loading " + getBaseFont()); // FileOutputStream fos = new FileOutputStream("/tmp/" + getBaseFont() + ".ttf"); // fos.write(fontdata); // fos.close(); try { // read the true type information TrueTypeFont ttf = TrueTypeFont.parseFont (fontdata); // System.out.println(ttf.toString()); // get the cmap, post, and hmtx tables for later use cmapTable = (CmapTable) ttf.getTable ("cmap"); postTable = (PostTable) ttf.getTable ("post"); hmtxTable = (HmtxTable) ttf.getTable ("hmtx"); // read the units per em from the head table HeadTable headTable = (HeadTable) ttf.getTable ("head"); unitsPerEm = headTable.getUnitsPerEm (); /* Find out if we have the right info in our name table. * This is a hack because Java can only deal with fonts that * have a Microsoft encoded name in their name table (PlatformID 3). * We'll 'adjust' the font to add it if not, and take our chances * with our parsing, since it wasn't going to work anyway. */ NameTable nameTable = null; try { nameTable = (NameTable) ttf.getTable ("name"); } catch (Exception ex) { System.out.println ("Error reading name table for font " + getBaseFont () + ". Repairing!"); } boolean nameFixed = fixNameTable (ttf, nameTable); /* Figure out if we need to hack the CMap table. This might * be the case if we use characters that Java considers control * characters (0x9, 0xa and 0xd), that have to be re-mapped */ boolean cmapFixed = fixCMapTable (ttf, cmapTable); // use the parsed font instead of the original if (nameFixed || cmapFixed) { // System.out.println("Using fixed font!"); // System.out.println(ttf.toString()); fontdata = ttf.writeFont (); // FileOutputStream fos2 = new FileOutputStream("/tmp/" + getBaseFont() + ".fix"); // fos2.write(fontdata); // fos2.close(); } } catch (Exception ex) { System.out.println ("Error parsing font : " + getBaseFont ()); ex.printStackTrace (); } ByteArrayInputStream bais = new ByteArrayInputStream (fontdata); f = Font.createFont (Font.TRUETYPE_FONT, bais); bais.close (); } /** * Fix a broken font name table for a TrueType font. Some fonts do not * have Microsoft-specific name information, but Java won't work without * it (grrr.). This method takes a font and adds the Microsoft data into * it. * * @param ttf the font * @param name the font's name table * @return true if the table was fixed, or false if it was left as is */ private boolean fixNameTable (TrueTypeFont ttf, NameTable name) { // if we didn't find the table, or there was an exception, // just create a new one if (name == null) { name = (NameTable) TrueTypeTable.createTable (ttf, "name"); ttf.addTable ("name", name); } // first, figure out some info about the font String fName = this.getBaseFont (); String style = "Regular"; if (fName.indexOf ("Italic") > -1 || fName.indexOf ("italic") > -1) { style = "Italic"; } else if (fName.indexOf ("Bold") > -1 || fName.indexOf ("bold") > -1) { style = "Bold"; } if (fName.indexOf ('-') > -1) { fName = fName.substring (0, fName.indexOf ('-')); } short platID = NameTable.PLATFORMID_MICROSOFT; short encID = 1; short langID = 1033; short[] nameIDs = { NameTable.NAMEID_COPYRIGHT, NameTable.NAMEID_FAMILY, NameTable.NAMEID_SUBFAMILY, NameTable.NAMEID_SUBFAMILY_UNIQUE, NameTable.NAMEID_FULL_NAME, NameTable.NAMEID_VERSION, NameTable.NAMEID_POSTSCRIPT_NAME, NameTable.NAMEID_TRADEMARK }; String[] defaultValues = { "No copyright", fName, style, fName + " " + style, fName + " " + style, "1.0 (Fake)", fName, "No Trademark" }; boolean changed = false; for (int i = 0; i < nameIDs.length; i++) { if (name.getRecord (platID, encID, langID, nameIDs[i]) == null) { name.addRecord (platID, encID, langID, nameIDs[i], defaultValues[i]); changed = true; } } return changed; } /** * Fix the CMap table. This can be necessary if characters are mapped to * control characters (0x9, 0xa, 0xd) Java will not render them, even * though they are valid. * * Also, Java tends to not like it when there is only a Format 0 CMap, * which happens frequently when included Format 4 CMaps are broken. * Since PDF prefers the Format 0 map, while Java prefers the Format 4 map, * it is generally necessary to re-write the Format 0 map as a Format 4 map * to make most PDFs work. * * @param ttf the font * @param cmap the CMap table * @return true if the font was changed, or false if it was left as-is */ private boolean fixCMapTable (TrueTypeFont ttf, CmapTable cmap) { CMapFormat4 fourMap = null; CMapFormat0 zeroMap = null; for (int i = 0; i < mapIDs.length; i += 2) { CMap map = cmapTable.getCMap (mapIDs[i], mapIDs[i + 1]); if (map != null) { if (fourMap == null && map instanceof CMapFormat4) { fourMap = (CMapFormat4) map; } else if (zeroMap == null && map instanceof CMapFormat0) { zeroMap = (CMapFormat0) map; } } } // if there were no maps, we could have problems. Just try creating // an identity map if (zeroMap == null && fourMap == null) { fourMap = (CMapFormat4) CMap.createMap ((short) 4, (short) 0); fourMap.addSegment ((short) getFirstChar (), (short) getLastChar (), (short) 0); } // create our map based on the type 0 map, since PDF seems // to prefer a type 0 map (Java prefers a unicode map) if (zeroMap != null) { fourMap = (CMapFormat4) CMap.createMap ((short) 4, (short) 0); // add the mappings from 0 to null and 1 to notdef fourMap.addSegment ((short) 0, (short) 1, (short) 0); for (int i = getFirstChar (); i <= getLastChar (); i++) { short value = (short) (zeroMap.map ((byte) i) & 0xff); if (value != 0) { fourMap.addSegment ((short) i, (short) i, (short) (value - i)); } } } // now that we have a type four map, remap control characters for (int i = 0; i < controlChars.length; i++) { short idx = (short) (0xf000 | controlChars[i]); short value = (short) fourMap.map (controlChars[i]); fourMap.addSegment (idx, idx, (short) (value - idx)); } // create a whole new table with just our map cmap = (CmapTable) TrueTypeTable.createTable (ttf, "cmap"); cmap.addCMap ((short) 3, (short) 1, fourMap); // replace the table in the font ttf.addTable ("cmap", cmap); // change the stored table cmapTable = cmap; return true; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/Type3Font.java0000644000175000017500000001326511376323412023251 0ustar twernertwerner/* * $Id: Type3Font.java,v 1.4 2010-05-23 22:07:05 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFPage; import com.sun.pdfview.PDFParser; /** * A Type 3 Font, in which each glyph consists of a sequence of PDF * commands. * * @author Mike Wessler */ public class Type3Font extends PDFFont { /** resources for the character definitions */ HashMap rsrc; /** the character processes, mapped by name */ Map charProcs; /** bounding box for the font characters */ Rectangle2D bbox; /** affine transform for the font characters */ AffineTransform at; /** the widths */ float[] widths; /** the start code */ int firstChar; /** the end code */ int lastChar; /** * Generate a Type 3 font. * @param baseFont the postscript name of this font * @param fontObj a dictionary containing references to the character * definitions and font information * @param resources a set of resources used by the character definitions * @param descriptor the descriptor for this font */ public Type3Font(String baseFont, PDFObject fontObj, HashMap resources, PDFFontDescriptor descriptor) throws IOException { super(baseFont, descriptor); rsrc = new HashMap(); if (resources != null) { rsrc.putAll(resources); } // get the transform matrix PDFObject matrix = fontObj.getDictRef("FontMatrix"); float matrixAry[] = new float[6]; for (int i = 0; i < 6; i++) { matrixAry[i] = matrix.getAt(i).getFloatValue(); } at = new AffineTransform(matrixAry); // get the scale from the matrix float scale = matrixAry[0] + matrixAry[2]; // put all the resources in a Hash PDFObject rsrcObj = fontObj.getDictRef("Resources"); if (rsrcObj != null) { rsrc.putAll(rsrcObj.getDictionary()); } // get the character processes, indexed by name charProcs = fontObj.getDictRef("CharProcs").getDictionary(); // get the font bounding box bbox = PDFFile.parseNormalisedRectangle(fontObj.getDictRef("FontBBox")); if (bbox.isEmpty()) { bbox = null; } // get the widths PDFObject[] widthArray = fontObj.getDictRef("Widths").getArray(); widths = new float[widthArray.length]; for (int i = 0; i < widthArray.length; i++) { widths[i] = widthArray[i].getFloatValue(); } // get first and last chars firstChar = fontObj.getDictRef("FirstChar").getIntValue(); lastChar = fontObj.getDictRef("LastChar").getIntValue(); } /** * Get the first character code */ public int getFirstChar() { return firstChar; } /** * Get the last character code */ public int getLastChar() { return lastChar; } /** * Get the glyph for a given character code and name * * The preferred method of getting the glyph should be by name. If the * name is null or not valid, then the character code should be used. * If the both the code and the name are invalid, the undefined glyph * should be returned. * * Note this method must *always* return a glyph. * * @param src the character code of this glyph * @param name the name of this glyph or null if unknown * @return a glyph for this character */ protected PDFGlyph getGlyph(char src, String name) { if (name == null) { throw new IllegalArgumentException("Glyph name required for Type3 font!" + "Source character: " + (int) src); } PDFObject pageObj = (PDFObject) charProcs.get(name); if (pageObj == null) { // glyph not found. Return an empty glyph... return new PDFGlyph(src, name, new GeneralPath(), new Point2D.Float(0, 0)); } try { PDFPage page = new PDFPage(bbox, 0); page.addXform(at); PDFParser prc = new PDFParser(page, pageObj.getStream(), rsrc); prc.go(true); float width = widths[src - firstChar]; Point2D advance = new Point2D.Float(width, 0); advance = at.transform(advance, null); return new PDFGlyph(src, name, page, advance); } catch (IOException ioe) { // help! System.out.println("IOException in Type3 font: " + ioe); ioe.printStackTrace(); return null; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/res/0000755000175000017500000000000011622545447021345 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n022024l.pfb0000644000175000017500000033706410725114532023124 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusMonL-BoldObli 1.06 %%Title: NimbusMonL-BoldObli %%CreationDate: Wed Dec 25 23:40:33 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusMonL-BoldObli % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusMonL-BoldObli known{/NimbusMonL-BoldObli findfont dup/UniqueID known{dup /UniqueID get 4077138 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusMonL-BoldObli def /FontBBox [-160 -278 914 1029 ]readonly def /UniqueID 4077138 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Mono L Bold Oblique) readonly def /FamilyName (Nimbus Mono L) readonly def /Weight (Bold) readonly def /FSType 0 def /ItalicAngle -12 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec `*eɨ0qb w*MqXxίI2  Ii2>ZVpXۍe/IT )I/ۯNzV54tUDKj2GƆd2 j?zaa0Zљ ?:G?ץ ХSlqH+ܨf76޷~8I/Ñ!@bz ,rW^m~!"Β3{*^.Tp9,({o)_[?oCC3 db0krZ´#FM7϶t2kːuQ~x<\3v HIxPLES7">i\ɤjU9{"Rj XNmS?EG/R˸@ocx-ݤi&jn"*qH}BΌ鴽.zDȢf?|]m|oĦlއ`D =g?JC=}jmG~ G?ߡU݁ %.Qf@7$\)QqK{_GTJ"}bO_r %flQ/5ayFc xu(`Zd'$ }^cШ?yrENvawKОWLdhHi =QlD4P>_‹d`;d[8M%Bj\US6T5- y/̲[Rۆ iup[!~La8FIns.b:S_)Ѱ0Mc;˾_\sԉWZ d>pl";Vs3#k`OR[rz^zp_:kbck={ 'EKV9TT 엏+|tӈ>7kfeTU1G!jހ;HzJٳgdB3M* b>r4V<'vn @@ [1Wחx>"ce,P@ui\j1qSj7S )\:\ufIPQ4`+

    t(bhjlX!}_ 6EW>LvG;^FSI_觝 +5? 0^ʱ\xxu pA6Og^>}ccہUt6(D.E}]@"_\VC|{3ZwN*nSr60Nv~Ae7iH})/:Wo:Ll#(e .*Vhp* e&`8Gȏ4h6d33@z7"G:[uv@zpd!2}EoF*UNruĕg>m(qm|qA!0[3@pGJDdvw L^ښ` GN(.f8NxZzb+*d B 9e@qm=ˤ]3!GjqC| Bk+YRtbV&0sϏ\7ƒ^21FE8S)tȴUj0a3)zj.޳Ox>:OJ s /i]|݆z]g3:3I`>C|5Hy(~Pv#MvdJH+_ه{Z29V]~@kuM/`,%Cr\ bF_xWʵVDv` 蒤NUwbnGLJ%9N=d/), |_gm_XLCXP9Hvqs[V]tѨi6 >-ZEK"&vLgT|Un7,psaBBs5Iz},y+2hƂ^<{U(yZ{E '/kK\br͵< ~ϥ2E.3{::sjfGpȐٵbQ6&T|t!{"NSȂa- u2sXϨ~;og ҩDL(R3H?X84w!v RQ?û&6U-Lq;揰nvLj!8\{o=@ӹEšjۦ_Lɟ^@DG'*4Qqx黵s!SaRQq36GI;ϭJm"3C+#+>ǭ̐cK;'?mރ"^w*V^W?&Ooa,m7`K7P[ͺ7w${ȖG4JPUApjjmM Ҕ`~u9tzXg^TQ2g|^M!RapLq}|{Ot?rUi<9(Ɣڬ֍G o$'^.7Q-ޚgZ(f+d\Q'y!k@&8TWsj |uE 7&V`޺ͺN< eJ<)|I>5FgL+!7 5ݯ=u˄ [*oVۭaL{ e!!߅?xͅ1o6Z.J6cKItT2m>W˜kHŒ4dB$[kw={#gnh-~ ɜ{nQ=--/vlU^;by;ˌS$6i.\NR+ʿ5k8:B@?`accbiƺ=t\bC뼙'+8_|ܓc{@2(Q^fȂp]Snj &C뤵yX2zzLzE]/>ɪ/PB]%@QfY)(8q3p#EmC,e]Rx0sKLYޞ)h udA_xD*4g"?;lЧoN!O=)'/H$sU12:J!}xGWePg7shF#G["M(G~j'0/b<~xBZe2y=}1)gM`5/KX>scA |%g(N>Ex@\ ``صVrBuh ؏wG*/ܶQ"]NXU_Y\tfQٜv)ĪBR{*qM:Tvڭp"tR9V8Ѱ3{9סAR -ՎQj[&V;EH|k l.V"$n>qr5- Z!&W N bZ$5#P`1ҶX5qUd9FZX_iG@cPGi6R[ D$`ENY F 7as.bQYbWly-qdU|WtU* T?siBN_ aD8#i=hk H(:Jn@2<=tc8G;""/GGvXu&rw=%Cv;dn{ʋ3^sc GH&uv^ᆔ0W"GK Si1TЧ#U&Nvi_AO<>1z_(샢5+B폃Qm|M0,q^@Ŝߕ裌n2F A=:2У޺x;F@쪡7eV̤~K P5`7 {O3a f\Uk(.?}mև }ly9 DYdžt|,y0µ?|aб7rWqɃe07Ӑ<Й:L)O 0s]|Rv8wxk:!D\pLq?r_7]0(?̷s ,LhiDP]e=CLL a#ȰGPL}n&-0h{8!8I8jRz8}:=Lʇi?@Ɖ-BR2F4` 3N^HF +s h?zL8VMyFRI/CsNkKf3'*9q GyT[ -6aIJb88ҍdUj ?i{>\tLv=Xz%}xɽ^+!w1E)л/ 5eDUO [buHK][H!GW Ѹ)YpBEiCZf W߀u?J篦bobT0-M:5dϦKs/Fsi| մ_6'=q98E( ,WGG%y$%L}VGk+0Ҩ =Y' |KNzFM9_䦭XQFg^ZIe"Lb8_u Sە"uQ(lt%.0ՑUxK7}C;bD$t%i SU /&B#CYq b3S0V1An#sQ{yzrzvR!X1@Do m'H*yzH$%rǵ9|>Q6ʝZ@p*7 RӅ`)0IK7?+z.ѳ鐒k xg\=i@~ffYt*4)UdT-̏ՠ .aa- 7FfRsξ4U;^W[;teԒ.7Ar*. C9τraV ʥ8e8|2_ks\ Ӈ'(6xqf%Kמ~[.}eiE={z>md(X/b-\ }cʕ tydBL 'BtOr%Zt&ޞpۨ*;\ S8;.OC\Hr+qڱj:~}F.T#.Q`䭨--1~J8!};ɵ=IV,NP3V(I㸠,YJËjW"Ax:1/ҙx~-FߌxoQd'B}T~}ψ?8}|?N<;u"]_4sfPxXy 9w4ty1CzwQusoY _dMtRR5ߛ܍ڒrs>A\G_$Gi /)L$A4=tcAﹺRnqyc?GM٦E~GZIl?l/! Y>Ŵe_Q3xv%Y>6")  ,g8PHE5msNkEg#q<Ȥ>(oX _0hA^ H"ɂ7Su*RI$E~?@#)xX7E6~`dG٤w-s鯛w$Bs؄cz%BbܱQ,)|beQyO* ϥLJ7e*{Jg2{}K(1p)N0*kXĘ*m,M!$}'{o[TU@O8U.yXFE0{j#K5|JƳO߯lYeAeJo0h>Y9/L~0|juW/-1Y&/:DꋄӇ .໺ "KVlנXb)CI] B~Ѹn3? ;eYv3 "M'65t^pֺ، oCG(|wGGɇHMɅ^V$]+\b5%{o?$;/$5E,'Z__EQx'Nzل1x2bb(8u#}&NFȅ<$ ѝ4tӮGwag}G UͿZɫBu^,=AJr&j@{AW9ʋ)n3malbTcqt2Ö9e߷Q%_E42~xS"h/5 >ګ[8+nS)`ePm, SPjduLpϿq0C芸b%`ޤi=M:mU:dC%~'\Xޚj{f!'XdELԴG˓)g?7`b:t1ھ~Fz)"y[T/10GKZaԅbB7?˴zsQ_LvL| 8 }r}Ẍvx0Q#ʕPv+N>[8X K!V%=<ϙP唼YS#P'Cd6 ;܈Ξnmlz O<ʣV]{P;rI,zdsWD naK2&Qd(.P8 3 ͠g&R BG7j/0\>x1)`fm.r_$IPTJ"-˥pu@7R'B\VGkmìVifvS Q`~s]>$~Jq2KttKf2~MuWt y&ߒH.._: :k"T}?,iQ*<0JxcV{Iw/ysK%ӚMvm c"F.ufe~F>vB_>'Lx7)p,BV{GJ2V7/j 'YiR ΐ=EIXQBu [ SEʞQP,vKvyW&=IOj318O&#iS>5&GwUK!Fb:iR/*w5h~Œ[y&'Ja Sd/lg 5qkE`7&.rҊDoC86x ? Ce ^V1t-7 DhALo: @/VBO 8m~cs5.AӞ"yȼw˾)1 dY3h) ءŁS,p|h´52o[]?5KƞE"L9#S@@H"[pFwƤ_'*W&%:dj3"9 #Vd\77W|[AKJ(%)뜁@ӝ&R i~*c9AtG D9ȇORJHE4FͿ6蚫vކvύ$آahpJ|dE*ZO 9|aSo\St99#˒ckz~m+_/yeD܎&_n#~]T\KErN hiF?Twh]f]Kڃq)}ɝh76W?ꚋK{l ƼO\{&V}͍ҹ1j>b&.ro:45ђ]H//ok7b_DUH{.@iqeԄN܎4N6s*-mºL( 9;'`ԱgU.OK`ȰRN;*[+~وꎈ*e$%:/(^_S P9WoL =SZZ3#L"a C', NK>Q_F>}j'.CL?5693`fVTϵ)=oo-0N-7 \rIz}ߗbTU{e )y5Xk^_\!rJ1fc=)pL*gQ&JYYJtQl^N]} w^e&?8lmVQGt6o "cgّۙ |~tjWvNUTp ǵ3Ee^JZN8eaؔrRW1]%SsM܈>] #wg0"&(} 0 D&%+gs2h*]M'f:mS!"8r s>V}7z5m2g.^3%:$o2 *a$<߽OEEGXRYKv]Y$sC Jө#-B.=xq"KkM8(+5`拴JIh=rD;.X㠠8&B;#lp.!%q?*R ԛv6Ěn\-~ZHuBQ}-c9lWl8x1={ Z?Suuӈ) |CPYr&k'۾R!-f$ @ډo+nXD6MpFOŘtj&,ḑIbV0n_1o4FQhSIgv Y ʰQ#`dd'S; L'F0 kQZib*h?^lRUI:cq[ifC?˜#QЄ-^yMʾ|AHf &S{@w+[s/ƜQ_}&F-%s0b7pIk̋~f:87m퇨j l91vJ2ƏR5Qq;T{:F}!9%Pxϧi~ݝv7T \Sq7q[2G"8fL>U; `[3+ovdQݔL!xk,Le/sЦԀM䥶ȜuGݒg_6-: ?b@C[(=̒*e 1.A. (8lN /ѽ$2XEF>јQD Z"JkT>T`|C[ AA~Gəf9@}0(S{<{BDQG&m8/pc?..^S<c|_и7[Rx ƿQ='ޙ 㤦Z0lJj擄Y% (-K@`3U٫|uk0) ؞aBͩn? Z^z|wN04D7ym {l rL5P _ٓȥ"g:chc3ĦxgN+2oMjMH6d6Igf R>;:l`ᯒb /O$4 PM(DLkb=*ўL2k=tb{ OvKnIJnbAC9H֤^ VƑJwCYA'G-pdCGҡ{2, a1A?tȭ93nl_Ph  k-dIޏL:CZ6" [E,hE! z>\ tn5S>rԽy6WT2 f|zY;9vF)ܩ#u"%#"i Ra{ρXr<X -&*<]7VdyToDd(HM-Y@sAl/Vo}?.noV3D!>?Oެ\޻:Rhh,/9}1x&^}ЈtZYg.[XUCgSijB B2m& pp2a&0AgXcTtxN @R$쌼+՗0+%)?;D s;GNƺibs 6Sd%N`8fĔX+0!sGG/QkKwwKsDs]LNH1_{O-( vfƊW\۩(}yPKnޚ[Ѿ}Hmp/+bKM\Tj2DwۿYNtD d$vNi)/0IOz"fHvY ${"!'iQqhKŊ/xs+|?^`Ι5"vT=-O5iKW4co-͠2uL:JtqUR\v*0U$(?Hd fgU$UC6QAD~N ZL3ARq[W g$p*Qy6nCϙ4q-1یw!AԿNL!"Ϥ= -!vrh=v9ۺD "a/kFBPf{;&W 0^uPۚ\i=jć1 a] ˢ[Dle}D{޻&7"sq2^?Z%[]B.^ !%-S~ҐjgЃ~D A+9y@ 1O/9ⶒ '#m#͵řua!{u9Nm8+gL*E.MC GԹsK,͟|óIy>\5%M0Jw H&jvt0Icm}48E Dt.b)fwt"Cv:*gM `4սlhDeUfZ9M,"=T"PK=z) Ot&HvL+'Nv~ߠAEW-4H8̶_TTR˟?J0s ~?Xa0{gix¤X!T*Qg|Qs!SsRݔ;(+l5m5峭eC*]D1;-[5:eb௘*䚱Mۜ]͸EXDCJQH\7F!4~̿Ա+A57ك"Dy~6LY9/.ܗخ֥gG>9L* P OOKaKMM_>?%I#flf=_6φ,TٽzOy,Gby~f(NFRH>!;FD¿Bx˹ђລvi~9 VkC7itkQU.Ϫk5:*^P[nb_98$A W\} /  (ɼ#2˝vOt0w]27iEwZ= 3qĿ?tLĪ"oD Xt}<8=1cUREgkM]Ksڧ>} Ď|qwecp=6;6啾T|_bC: z+g'/?1Qx/ Md "܃eS1°B+dž:`5Ogqѐ280 C!35-/0GUxE ^@WҺ`3|d pp]1PF'^h%&"F۳OlMعt`f"d-[hݟ}I!kRɋ%K&'LAxPsnS%P7T]HԳL 2&|G^SެK:ͱU cKhoyOpLP_l?d/]]ܾ CqAi؅ԅY?O,xݡnF,~!-Ttéۚ]4fE ء Y@0_ ްgzm-t<˾jCvXB K,| e7-̕u!8!,"&T| ߤ`CrȥyqB.Wڮ&z?Me\2( \O#ȋ71+eP 2Y2Q1 xIc\n\ݔlL)CN +Y~vMX$-=>֝dcvJ};Od,0~Ȏ#MėL)i_VOrr2x-үhs:Ln:z`X^C#PXA*p;t/{ޡğq4=j$zƉYfn imION5`!ŗnK8Ij1L+}.EYi\uk.qR3 rRJF+`2r s;ƍ_6f܌uA _W.w-I (Թl]91ZQ2 A~i(N=)1hA-R4\8eAPyGS =C䎶BĞԾg cNRŏ* XN$$SM;\DJI[ C6B'褬:6sJNs\xzh{4 ~}ocZ8w$Vx ù=uu,ve tQ׋f?s~<0 >]`iq .,1ew۳O܇3Q` @CuY (]p#JoC~uSy˥eeFݏϡh'+Ap~0?_BwPJe ꣬v,?7XZցQbr8 nv42| ޭ׏SVI!cgz BKS6}iMbܰ' k}Mlq}Uyu(@[Ĵ`F偘#J8r Kۑt/ 8T(%P;h *+G#h_b8tObqc`Ŧ;|T=<7,jZOυ=Pp-:(Xw-1%QHMY߈%4b_2lzRAC zb6y^xN;&T1\B ޻Bq%YߕrÉ19?v{GgG5O0 `N8?YE=IոD mLȳJJl{ISːA~C:Oyl_9p?]8e)ZPH 4qRޥB*O'fA ]ZKC:`}% >\LpEQȮyz[o*odQ eG;KuW/h.cLE UlfHNh݂rSbţPwjeS<#5X-EpQ $IiF/jy2>'(ͳDZ[8s%yVր͉/q ߎQ7/I ٥t*Ѡp gv~>~hK&Wb9%:#K,tǤ@ g,Jgޣki .1 BHf+[& _, qE2JhSeO֎`閆 ىRʌdgxݗݛE(Zq ]XTé"c7^ጙ5GObqn<1trO6KS|OK}4*suM1~gxÆ =䠝EN]z:_6P^c:U(c>@+ Ŷ*s9ur}KP)C~0%m~Si G0H"[䩝У]o@c Tn3[h*|/@^.Sl+a,vo; p[!T> t! -~tvB⠁$a0l}Z J3^Tm+<lI|H\{t's ޘ9mQ~_0cnd9pp:S78@R;>χI4Ώ?R5T}:RKa]ɉuA#oO%L[F&C Q3xJ"Ee8ILlE\P>6n!t(?8i]j8_z^[-sxB#0+`J/{?.=1zר=}d̐瘲ERՆ]yXV\uHr*<#Šh28 c.A R@=, -_?Ia.3$pbO7D"ԙ4(M솒5hN7Ohl(k[[o# ~jp ID:$Ǣ &x>z`zXcPt3+@gvx)DLLwRHDa25 Ȃc2Bj!]]Fi+t=oJ?cVUMyl>}M[M%4~FCɍ.hTTFG벜{9@PbSEl:g!.9oQ^<֐VB$F'$gZa;:*5bq4(ukE.s%߂~ju$=֗P'hrryېըfbi'wGhD5  wx5h# d̴ RM1YcܾrZ+F#}9u˜SGOw]~i9c^.u Xk/mcC=wp"(H20_b:?E/(BRל&/O#AԹd?dF *.HC XҥZZ`.!9p x'ISͿ!5p#2Ĭ,x=jijIA?ritW?M?Sk y0فC D-XC9d+Hv A- I6$8{e;? ?I^WHz3PHh *@t8j]ۆ:`@oga46z`)Sns,f x H6A I S"%G?E&lfu9NN*=(oٍ::fЍ3h ɗ8˃cj#쩈\d L##~-L\J+H0YLMVF]=883=9,<|sٟۮw_^ӊ(;r18MB:ѢҚ^<(b*2b?Gf(R['<:[\T SUN$4OR6EX}^!?c#DC-|U1Őg}N|l`3@YKgG3F3؈ےs9Hw*RG& >\bև/GȱX7r1.]Kʪ=DCo6 AvHޑ1:C361)7lP: M2m'h}Na0 ʠ[˧E*x7lMCMGy~lF4-,ѵw-/b)1P~B=`.қ$R}~ԳC+C6 jN{@,$M"x.:gr;9~ց5h3x6T`N.fӕDe XHTg#Hfl:!:躷8/˝.̄2 ut}wF3eT *s 3 thM;qFns5KduӛL:X/#@H(8I鸯߂H[+Z.L^.D;UbS7'^p?ƺƌ\Ԅ vibWЭ"fz`3^~I I wP$yK8.<k!=n' NGFe3CMJFVUnT%g]5(%WT *APCMX>pkɼMZ#0L?-5O$xAi%7jr ;0ǀ3sAi, \@t&lf.SC s(Emv%6pГ/ cr.Q2irgv#O&~F9y~CPǑa-WC Goxeկ9@a)pf YQ_6ME[_+b+:FKPjJ葈:Xq4 iOK,I&5g1ޣnuAutLg.{m Gyߢmw xuV70i?7fɳ~W;ļ,ƾ,J#%zVfmV5n\+no(^_X@vus HQBgL@ALxcJ}V ؜Xo뭾}} ( 0_Bp1 +IbůFS=26X7Xȧ9M% wZY&{5rNabҫ 5bAh5Sp.b)0Afv0r)Lvw.俙-Bv܊{46jom9 VF+鐿#hmŨh|ZURpgc}LL+=ꬁXH,v/} {. ~\YJp|u_֞?'m-__/55Dzs9ecasܥ/9vQ O7R 5;Wq~ˆh-T2G#g׉M'1)g,xP >0KDXlgKM"xܟ^J[`PZߑr nO|t5ȇd _ b}9ڞ(xOE㫇7^ L2Y,30"M'܉nN93 \ub69 )b z~ 25xVS F$`a#[81x~m^dv,zҞjs4EMh/&DJ̐rvS+ɩ$E1Ó:oajglri8|Q>I߳}L( 51P\H)I_tP>5b!> ݙ+i)_7?qJd'zs z mdST RڥWMO*qy5jK!JڞI<;rot%.a!@m,FgG^2ڢ9tƕCB &v Yߩv* i {GZ5 ,P'vSzؼ(vtg6 HHQgF5_iֱ~9 "@n^?3cP}G|U O[xY>[1\BSxk1uɳ3W}6!?/g,s+<D0QaJSF-לw/b ^ xޏ084?G*Oxw˜p]J3rdj;M$eځql r DIOӀlsp 'B+<''*7P͘~JuRνγX ;:c[aI( !9v I$4/5&D:0CGC7n W|lƛP?yx`[E;CF$ZrFXFV#$ ynuO`1 Lht;)7p|o~ml8|WKL9i:Ǧ*Eg \p6j#.bJHr46V|5; qyv7{̐2Z /ִ`. t!U:QeҥbxצUΤZP&E۠ (N[-*|zϦa x#+ZPn?(BFKAO컋l@ٽB2por7w ]3)G~(`C V;Uw5A@s6 ])ذ씕 e\hJFׅ#ټp=RL{N7㹵DTpF)(iym XK cљ"j 3LRQ&$"}w0Kbl<}S|@rx:K9MŀW jSeaCAʳ[-dӤ-,~13c1lJ;"khBhzj~ˇJgkN0w$kY8FLJ (ݤU觶;g[@p5|]Β cgՂw@^ 1+>| W9H `}Fʽ. )O 9{GcWTJ8}#կtzu tru46A|/IDzqYyS1.L߄;WWrSgHGQ3zhfCiO[BLrlذjwjw V#F vIGEѣF\%+܃ܸroӘO雽blqƪfE>!@$ޞcR>6 3B)+e/+QߧB΀|5q"*-$1WSb9dZԿ07M$84۩<9rr&}.]dYZnd"IUy $򼾰*(0%+VN,#e"ri p…KR _m'`~vW10 R.,Bu)PF ٨~8Og"oYn_dd䆒q?.6f_0xeU A}d:dT┃Cabn݉,ŖH>2T[pzPuh!1D.b-h`XjYHVVs^js07iΝ r:Sĝ>uQ &]L|VY4{DAEk><gu d6%@58QB &7?[j5ß.#+ xp*ǖ=ϡnpVA84B]lf/ U?bSg%gPXg(:$U YگN ƚFјET.bf-d/t qN!Ѓ;{J]fu+ geHt@D `u *RRR|8ʨP"Aߒ==1Z-JMQFIBM6 )U32bq 9l%B.zL{ B{]6\pW!NCᓲ ݆D1[ȪƛvӝȨdIR2& G8Y2? !C򪍣"V iPeIϯS+ٺT#m`E=3'ʐc΀gHjpVNV@ 9kD <{FQ3FCsh%ޡ0<و`o$6Bk;bVM5*1DyשwoB-XF6,I;B*6e")|Ÿ_#\& 2)tbc=bWe!WNْwwtN'JSu*J:fͶg2fG֊qoD1*D9#BvIPnyni9Q~zLYq [P\148>e [Ec; (eJ=pGkkLp˓?s+|FʃycwL>k^f&  Dž'AK;`p,EbJJIa͸gTV!JnP=Л6Zn`S ~lMiVNA@HDi*I1ɿPa)Ev ?@*3\dH*y(~g/7A'2fv[yzͩǍpk6^ebRsS$Bf+ Px|?ikW7N=c+ZAp5 5h$`rjN[ѪoCP~7* :Sb~{~ Rˁʄj׼d,ð(YsD],(/Ko|B%gpf}"|VW{Ae61$dCL]-`GxHhg@2*r릡F#8ի- Qeij՚b:O.ⰧdNo0ٳDU' ;L@mH֏h&u ;ыsZeʶT©ykfFvk_ƂJY(GU!ramrV3s (^sa O[@;Q@cÇO>XdKާ-% -J'4NK% GK70YVĻ &{ Aw%*!|gFŸ HbydaVZ}} fg=ml? ӫ 8uy }hbb[ll FDxX#{Q"9$xSF2$zQ!}Xs>ב|8dHo)Z3d۬; ٪{ )ϖv_|Zt}T"K_(ipK14c39x)Ų63P/f~z &:r'Rbkb^D9I9Yck?s6/B{1](ũ>ԇ.+AMm*7aZ >iZR)PǽGju&EgR3]vP! 'F h\H;߫T{qOIRY!MXoNa+mwC3g+DOR͆@Bx_rP1 k0RX'jtF⋠>uE 3P2:v~IyzlD̀L>,'lD!ܛ{21@>Y⒤PЫܐV ZdSbNTW |.t74?3I3nj!a=5@wP# +bK`OB'/[Kc  w4H ~EО:5)H7Qx4O3,4*\30՛.x04K]q {5| >,dfL_ytav\85Ol?k}+nV x*[ L~|rBQ;]pDR/aW 8;<ΟSmQ2QAhBϛ c֕HƋѓ N獾Zl#q)$ JY`˜ϰpg``tH:!a A/P.YPtp&*dVNж~u(=sd{t¢%E$_~W۽xv敯w2{ 3GK1U[MMm|f~lVS@gve6hukn"snЈ? 'D:TX&3WGQrgY? 4d&|2E  `'Cna7UBmhi ^Pu=B mzջE7iČhV'0ȶy'J^H{BoxBt0}qq~qiⶖF|%6qJot$h#d޲65UWL)DLxrpPr?q vk;1qo@`i`7j0#>);Α C}B1RUXi?2V4.ԙ5Lh0KB4v1jX4@#cl}8fQ?p[,ȇ$PZ QOJXʎ$ؼ[;kqhǖb" ͓LAt/Hg1ܐ)IIv}|Ѻl~m5:agZ3^J4N2TdCᤋ -2Յb?OEh@=P ɫ<+K*1绗e 9d@kV_rŬ®~,;oK1.g 'ЊXC* l31obnѐ79^x:wCW4|%DsvaNep!-1aOJ i_fZt/])Ro%H)4ἧ!i"&`1VJC?0q~>)aTw=3$^r,>bxmAT -+ƁPv:6 iCT#d[ ,T0'n#5@-ȥK_!3cO+INqc7lġwpOJ6j.y8V+|{0{H@vNq+gN 3w N+x%'$/Y@ԞKyn_&7DNH:Z^0CK"B8zV6O:ⴽ{c/oK/F6B ''so4''|79BIy8k;&7wf>q]L-!|JpG ӐWQT;3vvCĊ$N t^eҲ(PxߚJ&Pe$ooљO7@930U E}L] A668:xfd$w|1^gH]&)EnmYkb͸fJZI gb}L*8Lhz: ^jٞ ߪ`ä+ 9}ۜ, Qi$PB*DMbt,!};vdb:o\CZ=>. kg Q BTl\v-+~OCV/U8VMiH!*W)](Wڊf #> UV!ƥ[-2ZvwRYC$kf`Xhx_r#)l*&tF w? _<[nMm&LfN!UA#u׋myQ~s R'xХ[_70}Zt jf1a4GR! KU('W,z8Z]QhL}U`q[(;pʚLc(aY VTlЁ'Q@H=vb}eY&E{`Ђxⶕ-EBvsV8qD PK7`lq`|(8)μ%H|DP6 u;z|ZgYvi C@J9kgFѵ`g\?_)^OSLg\,TSCf:@v'xC>BJ[}(Pz-Uqa\t7>b%FC^4gf[E$Xr)X̡۬ ֿmc=n?ѿi"79.m STnXnnaI ܌W=uj[󏝫N#{ڰ*}T: =/ŃDx jW i1JL%{} 4` } ABHr-Di=2׉C x=a]gRCʟN}`#xO}k;U 7gzA:]g7H_fTLJ6'R +G%QNc ȺO_؟jʂ@%) S\E/2GTk ƎcNvQHh `$Q=d8ra]V$\hw 麿p2\#(= ,#΁NQԘBH9[vk#'?d'ǠZ -b'B(/(QPTϏ!K{=,}].V8~7<>[K*+uļ"L<'"ּoi^oV:HS56Dm5bzbȄ;Al: 1BvvW:Ц2oIޱY X2#]<}G)/6^/ 87}߇r'DmP.~h Gc mB&ºDŽs\E0; *u߰GC~0B-έAjÈoyHk;f 1NM@Y~bS~qcxيKcܡ@KXO)Zlkxz겎ͳW ̃;gPp?-sԣ vt}Zi}r*u˩M1n whNdlB\,-V%ƚR(V5p1 _6Mz p3d@puvO@>Yx$Bh/NW_&H؁d SrͪqTLfSM' 1+lK2ɫ loU6̂QJ*+T:o?y̐]$l^ *v.:CgFn9dº#^f Du3#cYKFUDh ^Nz[ u.a"&%K`#rf9Soەrd{P3]%зEf9EʳbyxMB{3.E 2>Jt}g65],~)& >FFF\y#pϋOh7Lr3`>4tmQ q-g׺Y$$Q dž`ӟk3">!6ENwI hz!spDC:fA'K{ J11UBloGuaqm6_=c2gm,T0(mɊN3^KV̍Wj(JBXG(=f, VVfhSNTG=|aպ iAeu`3CPa _{l t|2ksζh#ႏ+LY_I\4/K J8SXtgi՚kjGHZznvIC b;W˳*-Z_@DYnOv5糙 XD78 .P\c.?4$$ E_ DR ʁf&s+~k,-cJ^B) gT7:J )aO2ˬS׵pNA^#̙CX7,.l|OХ-n7;iOBJl8=(!/w Nh /ZnVsfՖgyP&LQw:B .zt46fAK@DuhL3#6L~ӑXch9G 9*I. S v?xUNs=J3:zcNa\ho\OCOmPevC2QaY$|WIrYm"9\,j4.`31OFpJ)2=U8cT@_)&3Eb!N >Dp QvP86dtΖpzk{NJe tu `h_F pSU.,cG "wײL:ݖ)w3z0enZ/~ ߨaQO.Z +x7N bw.y .gV0G y3HbY|IPV|͙5%(Źsϱd .NTqMXTis)\Hj@$B[ݩf"~%=? `&jnCSl!}^;giOّ黅+7pSyx˺2 Fð qphJD-cmdx0I"؉+H_YU0DI` T潳 V>huoݲN@XNs& Ș^ ]XE:eI,$hϮ!ecTh@AKW)1/O2#熳 "$[1txdדdX +x.ˎ(EvHU6 /:aXM3Bm=h?ˡQS2ANK]∬jʚ"Q^xxF|=7 Tmp͸SumpE iɝE lG/1알nVt3db; W e#UU%.1]m;Q ]:qg#;d_lMhP3ސ;,{Yw" My_5UV5_yU. M&ÓӉmiШ3Б&~\ޕdj#͟Ev B5꤆0)m`W ahz~6?I0D_%Bx/VOQ sYcHQKgxNbjr`I8f=Yd!f9ӫERVk`.U\'v Wr֍yR&-ORx?;Z KٓzN76:SSO'-*]0'l0JSo(0{4an*̝F&q4`X)=& aOnB0Vt:6as߽B?`V'Iij(APY,oU=@,9txK6;FA)pj;r*5U-io|w ^󋏈7!, Q eJ wش3\6kWb `XcCF"wPEoPǚ $8HsJ,9,It(E@:FNZ ؛8̇ @ƀH0zx{.T:l7,2h؞:fF ? խL7Eqzn*Ԥ4Z9X, 7]|Z` SY>h(NC M*7+{<Œ ѥQWQnN#,=3"}Z_ I~!w@,ٖ["uejP(w0Y;E-xI_x#\ޗxiJix L1vEmV&Q = sDL9|EXPk"-G=Ͱ%m#a!@21LYBpn9Aqd$V~+RAࣽuVR3 S~bSOO=jٿ{O[0zSO 6JNM_b GE3[:lǃ]yJOUKi_t)k_"nT꺹I.>Z8t~H Bua"2LT2jOر YPMTE*$w8Of1# xJf`ur kN1bs IȽ ݅]Uvqc.8MQ_迠7@Zl!_h?[<\ u?JoKӓr#^CU-20Ƌ m" )׻{~Q4 k\PZn"qQP-{F&Y i(f KLm:RTw%dW?X B.UAWe;jqI5]BaZ@좸{1`@쑺 SC H*aEO!|nmu kz^)0!!b gs5&C]$#yʺب_2mZu_OvT%KUWq4l=T*LX fpL3821G.$WoPݕC=QP0c#]P:S1C*I\V7';#NcJ߸H ruӄkAs $͝';WłH稈`j7%& Z(%Xx+Z7pI@3GdU >1&wTIgYn_ߺ_T4Xӕ+qZ Nim!Щ32r+ȏdT M3ԢN -{1]bBX &n״̃?*=M:bĉ46k5KDaUf`D9'3ymyizxM46̲RRC+UVpȔ9~@"HFӍAB\WEU寭E5/ eCЪSpm*!w l :{6~6Y7.eNR&LCT4S'i&[q'ҬGQ`Ɲv#$4O9Ahw"׭~k2Ļ1}%ll>\Ir3>`Ѡ7uJ7N VWѕ%#="\c@*%DŽL՘wMurXx%4]k!Ӆ(.@B(6I1 IU%\%~rkP3T?2̦ss_twlz*u2ڨ;m e.*~T)ׄf!_;S([s3ӵi-S8o朄AY& cbY14꥾6K Q T͛*]&@^WU'˧_jQf q&|dH!>Gq6ھbs)p<2 '!$8Ѫ #voL+&|ř7,pv"]!lipPo*fo[Xo@H1$Û`"R>:Cw%; )Awv M UlͶp XljuA0<"ĝΦ[8f2. Z7zi o[ ‘;p5N@hYP8%\f< -tФmjpB}nq͹#?$o%+!?iT;uM9dJ ݊Oa`DfVeʭ33sXh-y=#n,b8CX;{K5A[H3PܸR$+5e9v\S֟@3] euOo?&g<&_CD9Nrbl|szH$PMZ6JʹES]˛}U$SYwWpZ3Y|o@V9O{yo3?+3vDz,vJFrâ؞u C@K?vc?ۡO`ltS>?V7N[U~nHƎ׮w=, f%*Q֝՟N}5iQbQ]SЙ iSw<%SZ":5j1Y0}tZ6b9߈%#t ѢD^ tԧPC?͘ P8Cq*D:Yqj?BEĨg#`Px$_ڥ2ҋsB_:]z+#//(p#&eW~%thjK3xywe]YΕgbޞjkhY֍P]t z4ɥNeWp-w69)k~,z/v&;ςb Uh+vE 2EmqWSU/kX鍸=1i tynd5găaG1qyHgXހѡ@kx*o~ɟnt7bB[z<q|oqpR;G"tCœ1&T )&Y,q}ȃ:j.qp^VHj}BUva}GE c:ݎDQ& VRb4 [HKt%lPySN$ߐ)m81 uhZ Q<8Om%;E&H '/dOTaSM_sQs#՛5eN:c* !-Zqg~?:Yj@B}n>Rhn{7?p7q@$=hGHw%-Tk> L; $e)ũk/5LFsZL FL j7{U `eͮޟ!MYFIO:v tr_ZI-rn?v5Wv‰jӗtalKiN̑XfWk{~lPPڜ!O/uKWϗ"R|zÀv:5 ZLT-;;|կE,J'Yr'52SBx9{<߇{9p3C0L#w.twVYwֻ$D9@{"Nod$hǴ x˛kmܖC[x%MיNC~Sx5bKh$DV@e00CGD Nx<3.,)l9ݓbKM{yk6v-eaC2"Xx@0P'N3RB`<-<.h;d>> 9IA6\ESdnu^tMkrCLl@ƑR_^#1i{<;h"8mYXyErĉZ򄨛|wn>CrNo__o8O*>ْhR-E]XpC.qp.-/|;aK'L=])lY}HtC[:+N48Gt{|9-ob!2ȚJD72:r0L'up0iQc] L!:OQ'qOFU |C1@|kEw닧V~Sq܂ϟ.&u )+2@ ׯ;/ah j '(ĪH҉~ۆo7/aPSɖȉ[ ;$ "(WaR QZ.;mVxɼ/QS7Gs*lŋ+/im^oWЭ,[Hl60B3Ï]Wn([5,;vq m~a#K(!Sv n3(j )h*#d5-ROͱܹ c Z pe {d Hn5׼VcRoH ଂ949xN]b;#L 9J $jd袁26/^ p12T@N)cH 3[q" X̎Ow3U](ovw#96F]m5uĭ`JJG\4JXP+S pFG%@sEYQjvHG YiD'auX4K @VcX3XE:晣ޘ0M; [R'ܻ'b37N<KYО]`# \GOi~63r^4 4u-%4)Mej6;[dj(aGCU/s=CA%żTK!L ,NzKd 1EA{ %p67,z[BslPktpNz{Tgumjlh.&ZLc o "o62s6GO(-XiC1bZ+[v=xd]- ݁OԨ s┱zWi7Bǽ1*6JMJc!nߙ>z" /( u'&T?䀿:8p-ݕ (Xٔ"~"s?Lր)Y7P`[ëNtŊ` 6pp^`qA-'' Bګ"2iL)6)AH U1},Pߎ;0]sdvNLz>(QI3 >6)}́nx?p) :|>푺TTwFzwAb9z/~ޑ36K1T%64Zt%2-a8/oCɥ(eiQ:_Cs Z9FYٳa4hJrlٍ$pE ?u:iRxN+CȾ0UuYExBzjh1(Pj Aq`f~ |it:[묋IP)%rTCH3ЂVȕ(m^c,'ac^ w2ꯪ쟏MR "c7$dv<}X"IPZApd$Ԕeg"Rvվ̊/mfy\o^/`#xiTq]OuAQRhqSɺ\Un`UZp@ESzS3c 9+QEIW C\N)&|/I0a\CW>q<^ycYY3O- ^?!2>67js4>\J. Ϟ{ b}KGwNԯ՜JV ejUr !8P^auw#욑?Yb2 v/Hl qy*ʦOFDffY9a@{F-Y$P9H*0\gY v<{SBr`3;'c)9:rTnk$_mGtwb{a)WLa*.mzϙHqi5H&FHz~ ԫE QuM&dM :~j_ ^#lTdG)PZI烙֐(܅DbBrUR6\\p}n˱Ʌz @/Ev5'9abs/1JJq3 ѓJVKo7 ڮQ]nV œ^gC HL +¬Ǔݳ~0VYՃAKrZMTw١k{2;kDɐ\`d mXLL  ŠdZ܎::䳱5M(9HI> 9w$j̩t)zyٌ̗gɏk?*c4*H9vsupeYuFDҷL\r!H g=8 N 킒]''+7%qw%~ϘP`UJᒰoe{{3'yEyB9"?WzN6v?-iuѠ*ªZ5Qs q ύPI6;|ճYQL컇iel!+zidf!rd©[Ƀ#:Z ][8lo>[4ѫ;Oa`P(FF E`cqlCw\vEj9n,EUɞӉȃ3xlrmPR&p#/nV @OݽĬQڼ(^Fo&Ƒ b;W힇+G<"T?2G=+6#fн s+xuY,/v} Snmz"dxy-r1$Hk"<9drY4ik-1%XgY.V{\O !3eZ:+6Nr}^v @n(=-3TR,%2k'5?OV:66 '=C|(.[@Vtl|;yFbJ2o|\w~b ̟&kE\`:PY}x]J1~pZGwTrFm(&·6ʅ\KÛ ( VkePO 9(CʬNˠ7Vj\^~"=T (mL͞aQbt#v|a(/čv{KWqz1Dzҿhr Gڹ((WӔvZ-B)d{%U*%Hk@j/Eq1M]F^~KP󶯰bWCψ3~.Bj*m^EV·c]l,44Q}g}kCc?cLe8NZJ^,5eR^0paE%:4H_HItoexL;)խbл\x8xN|XylQ?y50*z!%J"~Ltu1 /kzt02 ёW4,X J[}Z&f5sqЕ.^߈=/D[_:l!!8XޖI>?#.[ {X)ꃲ m(O֒@wXeN:!W,߲rte&1]_V$k`g\"o/k).(zt笤65ZUML(o&ud3[ o'[}j 2g6MiwsV8(gʨ Nd'}]gJKoX,3A7wr>*&}ߴ;A$ׅCx,o0 Zfr-륢w\qK˭ 2Ҝ ʿ s Y$9v$#ң nFx6eԉ~"bTά9쪁ܬy6 C\P N~N\~P#ىa9ye-ssV?p!rI!);+3j냮_@ie#S[s\klHUY ZKgr1IO$JM\Gyg=S JxR24ޢQ"gÀf6)^y_ZBRo^x:<1fK1aO5UV[)_cA! B\ `~}rvՐ|͒9kՇCqyZ|0q`N,[@)Ȁ9g5^x.s)0h/=E㸋' Ķeɹ͐>R:xR4k'EkUti3_50uOOQMU}@$it58W gqn]l5[ԐVPoTkYZ$2SMqYc-Gl ;iFp_Z6ᣫgHyhiE d.{aZhrg\:d~Mumn?6]%V, os X'd73D߃Oӛ:\28"T%K'Q%=i||GW? ^0p;.Ӣ@LeXXi \ +60 ]*̌d<99PSrݦOUTݎ #C2_grL7]~"{JC4etT| )4M ټ/Lzr d-|OH0z~T>'NxeX@10*T؈V<%[=23H'qyjE#$-"Ä%/0}Ͻ`S\x]`Wޙֱayqa[ZZubls/;UoXk Q>tլ#o>r%c0urn`/P't9U<;(s7gp m1nd]Ԧr4_ԩ:W=ճb( +Q.;վWXqt;߅}2Ei^ ͪR(/߱CÐA'b@_̍ FrM|+űzx $Nѷan2`)}7=Jр̥GAe^*+%_O-q:G6)iSp2+:h~/edGz( rh!at&XڶfîWNi֘Y4'*.1FjekhBC /0_{nXf]jqwXLM]#,'ⰷ\Ra 3|jPe7N|x4jΟH'7KmL]{K.X,_׍& 9֯ δrD*%ܵf W;Bf ˡ޽2F3 [zw|Aι`mb̌C#!6MI6LtDPv]A 6Ibs+h׶*wj祕GeNF05΋QALL\!{2Z*6k=&e}LYA.DVdP-: JSo~ű':!ɩ'|nr(vZnoKJC-{f\&7I?TA ?WCm+F:η(]`P/}B43m9Xp"o*4 I.cB~FO;cvZ4z`'>ļ`^ HOQ2:Y=vEbc Sj{7EmָVmWe"vX,BK?[&M\P.1F-eL]çty+>@T^F"m ivO"?Ġ[TtSɾ=ו"8N3 #gi!30^O3cr(8S_Ӽ8VgmRўI$Z,\I`'cXQXS!˷'i4-c[Pu ]= TqfIo{mW Ejs^>,wMIļ ꁼGcsG[Mq%>U} ,/+6zAu-E˙Ǝs<]_ 4aq^"mh; nT-_U/ƭG*rbRb?~-A$a'"\Mqv2ii&?vdRrOxl.ad#wP3Lh{1ёjOb,//d x_BN:p7Ga#RӶcNE1D9RYIqTTHe$|2Xp/Qoc4D26 9rצ"M|SAUgE,PN/'qG/Rz:QCAȼC4P*_d#9췚qPQuq0eDNx Ky+C6[8ήy{>u*i=VisಛNv5^;R (zuK,vPy/J[;ezQqGp 6)t<.I.IdLx5WܫurgKMOz㵺UiU?X?\Y^#Gצpy`@[X#uXJBQDALhggT ,nYO6fшkjf'$VcrYZ;d@8cC+U{u %Q.Әg'Dޗv{2;[䄨 +|&[趕 I`Y-~)DO #'HK؄>Raԭ,}У,szJ 򧾩7W̐ _joAo{ۄaUҧCflxNJN{kRi%DQ/G66SYoiMbg,DFv{yDfL]үu >ta8'9V>w!-L -PYO꼊6bņSMStEVP, 8ᵎPx.#k$i..EL$ *F@o~,w-y,q*0vgD}Ŷml 6 +vY=M3H6bq컷K@7Hᔿ^A̖U"ʧjk7b9[Iț"ady bGFC3\%+#%,LF<BY@Y}r G|,@֥_J 7!ov" 5LB`U\{Z$A:8FZtm]=0~^? J\n^3Bs38tZ~3qU]--)=kEMstao}ȸB'.^FB§ vR*3ގ ~q X{ 1Gqo.,;r L]BWAΧ֣AҷzK%_i+~_05 9:TȸP IM}BD;!lb Eq{ʀ7qo_b胊X&Khm;?0B ^F Pna8ɪnyvC,.'^''0 a1nG>蛕hj& BYf (taRfGr"XղG LTqgɺՏ%-)\deUaWJLA[DK^р,g,YlYsxNGD}忿E>uh;oB$8}UezTj*Q8#k:Y b<TppWᶄlʥ&ek&LAnxfL"W:7C>Sb4h,;!}$LMORuvͭ!P^Qe\ *] Y[D5G_@eG:uk}430~y ϙKFב.J0sd|p-2~̀ \ڡO32 5_>!KP"DgRBL քH "~&@P km F/Kn#-}}y>ET{tD2KUOl_̋Ţy:o3d<>\1~nt0.r"buqj0MB!ɕFQb 껔S@陃*d0:YO;hTd*;g׻b&3S(_ ,H@cn8bX n''gOc(蓊04g [EKUگ<46*P$,4FWN9 b*ӎT2\KvAO e>Z+o)c$TXle3X6%W!AV M 6=rxT}(s#T{H.' FRj&<4}!AJaod] ZOMƠsѦbz^ 2r>jr'c@_Z eEo9P4vgKUS.'5\cS=J{Ge2o#p-]ʚ~ڳ9f։ _5ۖUچR!:ϕKï~4[x;n5 w|8 92+ = ɜœ'NPst#;9h%gӇb 4zAZmBTo@j+]ft-o9<(E?NR>s<\0Qx0n5RW~0Fmu`JaF R_v\Heθ=۽,?}sx_z0v*T`ڣhX>ifMOsBj7 j=Pt 6Θ觚ޑ3#ؚ&w͜ ꔪG>qr.^ߓ(%[=xP:x~zL`/9保* ֹCdQ3=6/E↑-HQbsp{G U=uеG80Y-Mf."e\B9+PQ?LocX6dΰ +TI5:l3Pr'[DQǿE,<|}I_tR[D#~TM_OQZ8:d$pM%[w DF$Ǖ'Djvba@ӫV-j!%hgMȘÂ汓N^w8AvDk B9ֹľV^\48~D񕊱A|z@o\kꑁC7M ]盲$jlyb|ECB\m|1B3vȆ-cwZR@^3LtɯQ*ق.9:Y-_ǹg8j|)Pd.-<[(~OҜCƒLWaj< pKmη0}dM~jl|X6wJ̆:٘4|]Z2G g=F%K6;LJY[qňRsn!9a29onIn9 SE}U܇];ւr֩/ؕWeqOBʃ%&hkZ)Ee˒=#Ғ^τ fILT˝l&aժZ.J53~KP I+*<<+ҫJPơ2 9N_y~ݷ%R֔&Z}Z_.-j9eO1$>SSX|=fiQh;X|p"#w?#g"ˁ~z/ %]:$c Bbo}gPlnrCT~m؁jOYc~uc`0l?1LڕhE3tw7g[/Zܖ]jt}3a42m=/ YgwWnN*񷽄mqxֶVE*֡+'?.tXϴ0#tpG")IRm)}X3p]<@ϹitZq o!v~|4:Qyl68.YY õNl8'DAjm?k鐈_X~Ioijyfǎ>}Q$(%Z_z ;*z=So,^AbZ#<)LQM0Bx⛹WB%\d}?JR06ϲ.~naχ @%0`T >.?sHLԤ5 /%88EgeaecNINu`!h&"D/Q-807#$Tl=nT[\LSca ,"oG 惱7dxy K?v)֋ktlj`-87?N8XeRB\xV(ت:me1ymzXBHLw)unAc ;.b4V  s/ M*j/j%A'jT\b"S)ѓ2rUQvNoЄOhҦRhlsl4p}Y$)xopDeK4 /BKví5@,ИߴRnNjR~ OV rz>Lmr;[%,jNuϾFfsc.XUڙy?îhxPjҴ)~qU/*ym<\S*Ka-)J?^_ݾL:Mfa ==v]e0(Pp=Y,(F]rȃ`ob/b I{3=QWrC<>E3 G@6e8ͦM?qM@Ai1r`W<ʬڈORn~w<8QU( yo i ]i,E?b!g7:mS/wO?Rxŵ"O]K=/l\ u$sQ y;=mUݬ+L \9\^$ZHGD'J̢~WJr Cb}lx$A#m1=[GFdV;u9ҶpbS9P"/`܈0'ӗb6 cSJ1iڈ ѲU sNsLf|xJBmW PϬJMH<ߐ';[Ծ e@^(0SXmn^..3_څc7Qsc`Jh))N?r,DQE7nك"'m%VBnşZ3F҅4+jP#NTŮڎn:hfӬX)Y\.}tjU0EȤPxUf~ÖM*"~|W$QƷf!0S`l` !4@ax9 ?Х{N1+=jAp+AD|ݍѧFKH@P,9ЎpvT/"idr!H 63 -&YRZUMi֢]B|Zi֡̾@bt K'] \/`s 00%,̸Q!Q/BN@LY|F>E|C _k3%j d˪2b薲1 Zk>|Û"/:;p^)0h(wsW˻gynW"qz Єh &oC}a24w)=ڦ,p64T1'ʪn+wSCuƀX4.! 0'ȿL{ ̎tD'\mN@![<9m 6/}# ?߬{uymÜurp]`3!" *j[,\W0yEQR;u(vսu<ɲnM͖u_`4ǚD-,=rB.85 ݪ}rGX3 kt² n@u܍-1*T %Gʟ8ťyɜ$ׂoGoclUs:-x7CeRNP mRkԗRS-a z:vk$&2$PdmĽצEI}o _ lQqwS;cQ.TwdDރI45k߂/w]~Yxo{Nc'z~{iPx U|R= d+%v?X;ꄅd[ J2 @9)]LnrE⠑l@{[MtsJo͏]|}8p+Bi'a:a3'4e8o갵#Hq-8o%rߑ`9.(%1E3OT[-b?DFī"dnfFRGET T}QbS^.+?& ۚZ(!}%\3EDN P G?xDnqd-kxI_0h+EbWAʺ2WBTd=`JDP%0݇#ZNٻ1[Ljg\+;:f韔o6*-Y7w][.o:'MDߖ 3h2Y. w@>y"52;;1PKs6ܣ˳i}19魡'};SBI2_`,S󕎑 -<%q#wapbt>3=;8 cnb j·Gg K|"728E4H!k)e}90 l 3_[4"nxy+b:EB ދ ,ݏz#oeWVK,l؈tƤݰfGA.㠐pq bsw/wn?]`j{[/Z~U@KF'O!ѹBOǕ 4,ϝUkHS?"#iby!5 zB4h>ģK:jqY ϻv%EnT:NtcåOG [j@^^CgjZDEBEyPT ]d<'9Q5#8ⴇz7Z-sz˥(^p<N1SW8%.G-5wajQU6h2B,+9YbK.7; dzLC}ꏲ{_Q_ٸE;|DC! ._a'*;T9RVA6'Fʵ6wA'V1X@hDtU. BFw4CjpިK$^sdiwx6b ܴ O7e1(;uʫ(`H`'#|ء4HVn e]\}TM!놛X)\LY_"zlق[IgME}f] j+c7oL[lMs|'e~c^ E r!+!JF馁ݤ&˶X+eJ-=mkS9 ;"Xxy)NlEiV%i 'V`xayϼ`XZK jE5=Tݨ`MFv^р&恹 C/T|Y8\RKXBiwÓLXePn.ﷂPLq-, ˚b.ŲMg=ljWqHrCx-PIjH5&p; #v%N'\{}4sK撩LNI1E').*=> 5;ݞ ݉(>N|]tB'o|ڶx&.A)߲5TYEy6Ε#dc8P>b#[eW0RD ^_  yF?O(b+Y3jn^#6N!ufs]\?j\ N}ͺhFtD_E=!,Wqhcԉb1"E[=H$o ^Ld30!*yZ-ouRQ%e0g?C ~G;:h!6,[svxI>(D;] Կ_Lz:{'OrK,ϝ8$v*$Gբ-ǰKg ^eoȘ|b/ ,R"Y̿(Tx]Ic04yH I~dSMfnXuV,%2Xyw #?<$eMIL 4J?@;߇ Rv]{a1JZeݴU-=u*ࣛ/g.ӏ"VފYOBkom|'$,(#oD"=QL|n8@tq`-Ija3$wSdmG6ϚOsU߉ ԞAÆ2]Kp=APUw %WFJ]kĒy/ HR;rm-m:EWBo{Uվ+WPP[ }=GMD(\vpcQ +ŠYIfIGoGme*_C|0in3_"Olܝ\^0dvD{.]nR*=$WcͻYn-.V:Q" a|tցx1$&|1pjFߔ֙28kv4EoHB 4̔FW +Jv&np$7°dzi ڎ}J`xj F,qkл}[`m;oUujRk3.PrrqI0mh?iW D39km ?fb&< {BY5/.cto͸R#UoUz2ض&:Lk~1E^q|"6c v;UMAM%,*Y= r>GȒ(0lޒ&ARQed+cT{I"ǹ= kF[%n_KՖ|sjP 剙:Db\ܰ.XHWx>AǏ?OCA-PŻ@Q9].l,DMyh#,O/R@CTtXjÚbD_YI>}+$e8&៣ *8@S8L]C!G =|ܱ1&h*\I&,Vz>AjN`{PWt02qYVƵiUmqk@:aL8'>gCdf޾.jTTKyJ=~f[ȐBȱXļ5L 5t\.&sc g]wԝ[LXEQ*/t):޴b,vː*8AX78/ZbmdYtBk5:?ȼpM*L`qnbkJ2Z.^7 ,o|4 vK6*wuPYwo?[F$by(-F^n'j{Ac;͒)?'> ˣS|E*Mx17+9D\6^C%ٕ`)`ͣBΖil.ti=3fw:o*t {E]@<;lt20f29|08s?pML45!oRt{(S&QZzC4E㸑}“Q"ZRÜaRGvV˦1A 9T*\s .}6G\&3piLS;33:Lp b(hX# y:}>~">5jwLƥp k5|rV0B_3we:dqDΛd."K5X4:22c$=uenOjW8s:hrNX]X0pk1{܇.^vͱ2?X8<qQa xAq2IuEay);^~ߠ6KroSvD|bXgFG~>PbPw]8|4 z:Bf|hC|hi&XK~Pkuʢ<@"4E]ʩ S*`,ɿȱ@bDĺ/戲 tΠee]8]yOE}d8b}*Z,w<EelF?;DE9^~1TԻ[m$ɩ,8v/ o)4Q{ ;-:.D6~(iAM#x1eEjj)#\5]JULc BP,ޒOE2N uy3={{wBL;NVN6tZiRY2gx.:-|svֲmX4;e|?|ĪG#fC/ hsjA6/_8Gqr:(YNFStl1mN1 .]}w(L\e; K}~؇85RCB(RTABr|0BlYʫmDŽ-%r?f#]]b:Qyб$F^;,ҟa7>{Rde,%bދCѨ| qpzӉ ם xk%BCP )eB@<CgҶN|36IBeKAڋbp)c`˧1l eEHo^S)<켜~.{9n"ě4XST\>w pE\ b47W}ܮQ,lY&jp's\ѕ?%!%xH+T;@ujfV:SٰD!L=9k>^3C Sgv( 1uP@|+)*ɘ4Ԅ8>N~hoPơKo.t]'Aǹ]iO^P5[s`yp/Հ%<:B/4R'=V(&St!1-fZ6AЃ[6aҧ,=cQhme2 t'ېN)v7T9la$Mz){IIt ބt ¿U[{Cf0̸'zٟZCky~@jGߡ\#ko NY bkH0ޫcoZQ-)Z/V2a!WЄHwÒ?woc@$lA6(!F!VwZNu;,5=αܟCt3Aί;e?yH4 ӕf0vҰapc}W5!AjlPuţΏl,db7G&)^2fAbA1~5|%$XCd n/~ jK8ˏ«V'ʡ,kK QvQV8u&+ %Q,@Aj-T-& n[ʄ[Md~$XIs]+E^EŬtM jYֱo '"67m=> qr,kJD!icV800[A5!BJ$u$ͷ*Bޏ(Y^Yuwԓ]j mޝ1R{N2|/o_tIU.{gZ8$ ëd-AzFJz\Qxxz\}k, ÓIq YTbMc T4y0"N6Rk=<\ q*Zc'x_ѠZAh5aӿaX0W 3 ȘTg"M_vZ`]tI>YAO|E;ZPL7p6`Bg$SٲgduFa{%7+g;-qDcaj)y4^|j}Ը5Pe&ݹda|#? u%w0m ɽѶe%g'>xX-**_i#Wa<2dhYTavDj1<$G!e52~N`5i;x|,96bą%vL3wKҖ%feSe buP\v_?Q`ÚZCQ|#aa=ԣmaM@xD#*X5zxF-Y~NZTȬqD٭B Ǜ˒?6 ds2)_Ϻ|hȍӍ(`И#l.d7Q1ef.oYљ}Vަj<EIK-t}N}`I[>YҮSOmr]R xIJ͘VDMF|?p|د5ﻐ5H$z* Xmv P)S[:e7E†H ȅ/ ZfJ{IYe<>OjT|X'ȩ`RU7Z2eh%tpV`8bo@})+hNNY@ e}mt$T(2U%˔# qX)2fBܨas wa'I*^g+üY8KUty*Q#ZaV v=Z|wו*$gv.y^&o?7O?qpF) ;,!'V쩧riI77xG :y[o5ߏ#PF\YZ*cO <np&6l`*ϗ4['֠'gP7uk&)*{ )O("JwH#6*61'c.ź7E$ yP9̜@QiVbqF4޸!CUZǯ8"'l~LM-BbMDC;-XSvD-k~ܯ.7}ڔ B)Ig~xJhq3ݝrG+h@ sD^ 6dU1Wq Qv6@iv=Kҍ#!\^Uɏkp.TsGvV Uu=*dFl?ͣT,65ڣQhh s H :ڶ2ϴHT;d[ˇj6,)Pf(j V[! nX-2fM#}%:ƓKLEp )M׹n]_o1e?L}W5&'1)(3 DZؖzY5k 51y(|1ދܯJ- POd.I}iO#R b^ #WWf'Vy3CwNJxt=FW=f iVztŞ/vԽ=39KѿBupqps1%AEO@/L٥Jw5/Sp騕K0w%uBZ-AQhxbd!0757`#鷜f7~J0i8 Qg_<KMR/G=O ~n{y4!>Ͻ!򪋡3uEccfpm϶C\=Ѭ2M’8 \Q\U+5WIs(OA eB$?ܿU / R qCI!_&1v/_^9 K+H~7}g%j4A *a,t=CܔcgUBV j]3T٦<{Ʒ‚t>i_bj}Np_K\=ke;ʫ[zÄ\A#؋}NY R/|.7s2y 2E{˜腈=AF!GC?s~a%X}=3J#LF!@TK|1ŕ`Ge( J#Dl$9CwiCCTD |*}xt!1 WJIIjxR[ ~J5>.8{ kʱ ⨮Kb;;ۇF nN%l`t` {URjNw8砰Q\)"/ pP !~%B2WHFsKEӭ`63pLִDd~ .7$~c3S;/yO7^ + =O @oU#c`%?lEEU;CgT {Ttp]UĺDgHiL?v%ЂBwFMP}a^( lz j"[.v??$O=yy͓sXW9)B3\YmumpNzv1,ڊUJqiPP:Qati(AB)+{Av9ZQ heL `7D^ѽEKP4MTw$P.)*”`.pA-oM*u Yer;s虾ɢ|rLC=r_[]vݸ^M#r{1jmsַ9K1jɜcD@1%p+> IĚ+_*-CDB%FXc<̄n' K1h+[ ᅒ|EM6U7=!fzȔ1}CD h7}o,[8Q|2ʆL6ueRY5 mH@cÂgi(gzp ׫Y9 ZU@l )Љ@7X*N#=j _b/e$ٺ>432&ck4u"MMI] 8V&#>Ү2b DIW-E .ȗ_-".¨àbb0K䓧zZ F('}(0#L_BuYq#$\CA sn}=q?g)C2A $A@;.Qs(mpu2Ce GsAHpc\+!5[I^`7H.~O"[ `O/L3ŊA.9pmF %"hVekLC[Ȓw)@wN̵P (&|f[`C}\ML7V3: ,t] I)X9JBU<#I>licbWEXjM"ܷ? x2jxݺ3/8Cz|3l'&鯿_2^4y)-e6 B~;E]ǻ'/8vFdpgz@*5[qLroyShf6iM) eG= @uq)h:2BR[ s  DٸPN^g;YJ cQB›[C.9 pJ D9'Ro;C>s/=P9nbj$-b2p6mesVpNBՈ[k}ޔ)½N#݊d6YcKմln#KE*ߗL"/h-dG̝)v0|>PA͆mbsDIĎR)e h5[nB,5q 2^fwu{\u&$΢,Q mKb wn*58.dX\ʙQ3SPb;(׊+[;O"񺱿2W n" RJѮF,*i8&k)Qܾ`A:7@AM'Am٥,Cn)4j-'X[ziEUY(1(eW =:ݹ>5~fn![e+ǧ,tt/KnH gdx̆&aӡ&k'& _hC3L=v GY;ɥU?`DMN5 hS> Зx3"w7v~kJ]9Vi͔ӂ6> p;jQHSUNBsE-]_sv6$AmvRQ s[aPr)5yIי@YTf1 $I0J/(J@Ph g!`{"z\شaP+_EM(x\ cz_\Z&&|tmGq|"lϗxDyߪn=YEx7E;D^É)`l2厼V][6Bsvi`c? 2 =Aũ$Y>&)ێ7G#5R:_= %ʋ!Z@؛MkLkni*|ZbWyE0 xQ%'G,!/ 5UȖy 梑fYbmU[;|L+rsGLUMu]3+J') {@\,uQ|'^Q670@Ηi|HEZqJ_M~o 0|.A`ֶk%)!ZbZ Z'sjFizM<G&9geTݯDٻ괾wk4ݖ(8 dRXS0^I|6Ie@Y`$a0"ccO!|_ z͂{&㶳ԾǪ v*OÝ FVA^DXg~]RxUȱI|C9%|M};PJش}h%y,OLkM4a(=W[4ֻ^y[Yo8݁Rۡ&!Y:zCyR  J] T / hms:l\n 0(T/@azq cD<&b#^#C'WƑSOP;L}D W6OD ]HU҄N{6@s<:|:Ś%ZBV@CZӨ3i/~gM |jޘ`P'g,RL\٢ßk*ޱ$rZDƁO(3*iww8B\Zf%$1Ymm;dHNjJKg`:|% #{9’}| ז{niڱLcą14Dh;6 R:5:ݬY&BA CUZ[cƓ8k.AM*wt懠 >v4 w\_0Z x/'2%Ґ)O%s/[5Dy =WaO-J98CB{u(;*7M53Q};MmQgCIp,W+C. âш-apcY|+x*}MZx=%7!e:Pfc[TDwX3Hχ#m#.fB ԩxcLʑӆE8}'D(eꁗu4} TRprsNuV>whWjsB󞈺`B.d)jv]3/,Om٨-DODNCw]t%))Py2Tap{,]9Pu~U.4XBQ's{U("@Xą# E&ǧo :i6mϋ)/W|C0Rz\J%}.2 $5P >XS<D-ޑ9}{W,?Q{ C5Opf~-LVw&z!iALRuvA ,)_-8 ՙ̋1TD񹈞2qh`t=7n-)SMׄwcyߤ KWpDvo`(ɼ3 pPPgݯ*& H`f?r`1 c҂,I.nP;=RQ;}wE"aMYd]d.;Aؒ]n t)GO~5=B'Eo"$ey=v%OF.e$y<Ɋp \B̅E5i-?(SF2kў8t8JD0B'̨TN6;HOv|CՍK6դ=x]o|*^wlvex^B*L4z^DC6 Cd_OR Md@#u(!H_4"P\^HŇ ݷ`2Z+wꧥMK섾] z2< [k#&DQWBŪO @YFeٟ429 x֘(ec~>F9<0?y~9R=10KD$iZpo! 3oNߠW[F{k4'ƧpԖ`k k"Pq̻]?ЙV=PPNZ'dI~b1D)9:1,.L|6έ~"\MFݬ4|)#].j.'hˬ<_؀݃j/u IU)ɅpG axwi ,\JM$ǕHl>l&Qr%@~櫧v-2Θg[pE4/Vlkgs >dw˟txH!:! yG3'O>@xr-nj:)ZDEmcjrZdg~~v29=tMX\)'Kh-|IN]CdܮsNx~d(qQ{5P*,~Cwz뤳&X;hY᣼Uڹa&3D }bo&ё5;5;ݷ30ehW%@=NB ?VKG ߏDXρP\ѧ1~8} EYjq"be2uq4ԹX1 >̏\z #p% {-ő 澢Imf Yʓ nje[;u8-\ [3(s-rq:̕zL1nLTT ͉dމVWU 9~fTIB,L)vJIc<2+j&$Vvc8EӠjnxR%rjP-$VIu}V%{IB9PMANL_"^sbC;DǃeEJn۪KZ1 ` ~` +BRNkyB2oU ǏPz巵9g -mΩ\HF,$h::O.'PJ"K]q` }'֓AbISwE;4ݠ•Qј6d- s , h4Q]5ߛ28JڮS5;@pg$Ұ>g4jm/i7:$Tx]nh!"{C~!Y SpM wgG~U48A (k-nXo o- h&e2&k5f~ajHIbRCSin6y5qBh{;vd{w MIN- viGZ Blc[/@]c,J3S6(|VSt 0G#pE(`jkhB^^%29#*5LBImш-=nwCo#~&8h|J@,f;P9aval<%QTpRe?P mE*`(F};,ir?>~hSQYmP>:h8] d:^ĘP@P}f Ԟ&Bj!x尚2> ȜkhQP$`ɳU%P4W 3ˤ v`~FPluHf` 0ղOFur (qzuZ߫F aOKS˂Hɳv9|>w!kŠ1v?Y7F+QJ,)5!FYkӻ_<7pcW JO= @ixw߽VT=J4Sm;mGiqRt~ 1hj[2p9?8T&K[+Fa ՞ßt #^ )c):]O_5+c9y̾vpoگM(yνVU0u{856ķ4*n*i^fm'nxtTÜXOa\j]T͙3xu'%8K&eJxllb)lybΉU-GT z1C]pb?GVA# C"Dbq= r`}B&iA4d4er[Gy%H BKz9޵'B"A:*o^C J|YW᭏Hgs(ѬyM&jSt7Cݔ#=;\4Bt$Ll`3 '5XR4ulrZH|U_!"hӒMiuO%PE/d"[n0q=\#]CWBQfNݔF2坜z]Iy!c5T9)>S`Kܑ}M[h8٦ F#5}:eYC3~Ksϓ}D p`*߃vY/ ZUZ*,c\jvFqml"[x %`!W3.Ppni}?= F)i fW.F\l:+[RieӺƪn.~$Q{Hpk?ØlnLB?QîL#Gk(դ y.s6u ꩡ vT=Ylj[ T{M[ hʝac% "f萢ۋpp vQ(sz%w^Մd ޳4=[VOB]Nm}B=֤ X$&wPyiP@]#,q^{'Sϵw!^>AFZ].cc*&E>EA9ҜST+wԌmX8IcfM5lu4f;Ekbo /R[=sH,Ԡ~P&cYz/.؉璒Iq e,JYw"˥ۿ3fL !;sҿn )$$=AuGw,U&##uFT B)v"<2%6zfԘ 'i(wnhxpOI'chϚ'q';?Sw\BF -#5֞0T!݇"5j3Ȇ^#V l-JbamLTm}wYyȣK6v؇W}.'NjӋT(< C,eI"uɤ0I_:2bZ'"3VU+PkY?Z0[inc-tE h&bT6~J C3Q X?M쐑cB z ;}s >]6Q diTp$+I H]|x/^,FgA;o@40g&w\+偋M?NpϴLj6^wʔA[+[)z[m]27*)/}gCxhN*/)8 8 kev\ڸfkueWIoČW:W.@~sed Ac쮡Ne0vh7g\bcc xSެ&n7p"Qo¬fYVHZ\Ш:e7ñ:!LP,b䊎˖Z ?Zg /#aDO t`&%!֜ U|?v۠u-^&K22/[BԐ.8}Dr>3;YϥhP1w-q59L{zV3IːݍD(;ƥpLGFi$}b>ճϿݬ;W!Ѯ(͋x"lbMiG$pO9S׀o N1s>pF&4!GNu%>5LciWuV4z~ҁ]ե-ng+hN‰U=6fcVfayzj,!\Хƕ k8.U3eTbnJDžxS;%!Jϒ DJ ֝T,jn䧓LV)íвRbLqsx*6RR.QzMbEЕcsOzvUQM:F>Br}$V'[P% | }bHN$4CB_O]iյtv tt& t$v U[#Hb;0ųbRq!oDFYP_x_TK\ Q,MfǤdozA-m?[dߘxb&{ B% 1dct84Y$fey]~zR8=vLSL`WV HMF)Ctψ)ԒSpE*mm2߶?Z 3vIu"Jn ˔B$e푒2)z9f /y^ M,KG!?gN!29Puo%'zi-T[#4OcVMeKY \U7}Ayc|&wk0m00qS,YzC®"^E`#ԃk]4@qۭevP.z,g8_KgrVm]0ۨk\sX*1{!F8`rpzn}*Įc.'r;jDrcKIIҤ;1~S jeN*Ƅd؍A럐`0MR`p[vZ pRuARiI\D1)Xk;Oh{USI1QO ,)1~;N7][m&mYcu}O0YZ^ t}~'bfXG^h͔UǸ`pZ!CǵKFܸ{봙$Ag?Pw!*=-Y0%uP֢5:}D|kďmxG1R"2S?b?O. Z5fOڨwr}$mytE;1V PM#y4E[Ms&ΩG:3$h?i)Ӻ̀uF`qqa.I,v7c0X[](|^n@C;HQW2F0\64 ֤ <ƊфD\m%R(mH!0fi ,g])M̩G4!bDAK^+ê^Ijg.ūFc5svWυUg8ϦI4CsZcxwKsl62ޥO1nw ;ScWz(65IgD;Ȇ0T-h S3^}ȏ B6 xEEFmv #=$b Kw8tL{Q%z*ʣAUuس] dǚ\fRr;y>i23`H# A-`+%P#9_,95B7a6ٱ)N<_)^V%h|> H3Tmct:w[V u߂I(AFAlI!@c~K+eA9Tq( hj5Crr/=RGjL"uȁ+CnEp,ai/>pE c*,69ݔ2W6+-$ML*#sngOWN i}8 I)F3'hN9&X"{VP4.Ŋq ޺Wl}z/RPBȗSYIԡ021c+nvp[j7hܢ=4B'ܫ,}_'Eە*zRhUi3ua@hdy¬;XD}^w㭍$ѡ=&+>=l8^<(Ysv=FsI?NYiE~0a ܠuO| EPx`pmIFeܮ4X=+)pbFy8Q>`UIEx@Mߒ^AwBlEbʦ*_u?.A-}v٨8YaQ+*78B@bYHd>ruٯQWɊwJm7Oh%_$(fD qXVlsKkm𝽃QZJ0C@fBFkW)vVޚԑuM6|P᳃_.>Gf+Vq䭃t1/o Pߩu`5z6F 0_*OG]Z? C.;C1*Ld\Z8K|uuN-¨} ܥ\*ö*`8c}vQ  n7RRy|?Cl;~kAQLEư. r%\8BQLmC;t1 oh<CfkK r EVop7ut_;?QRO+t@GhOT2poNk<.ְt5ZXY>_"cjg Пh7eJAj1'T!  &iCOwQ$}ɺy2WJ_K8BEGrխ:,g?{{7 E>;2AF+; PCe mϭXe PBRXc#цOELWMĘw:e8s Gj ) :n8Yyy"5BW[.wYiX C?7VO#yY_eӚXц}7 WC&\P :¢bP&\jo.h@ߜ0HS4Bޡ0uxK#Hcl.A>0hA)V%fX"vJcb_{\@o#/;䛸xA 3!lU R)$X+ִIj.kClv-b3`PxIF QRP~&oOfGx1SCt;x> m:$oxNP9h:T1\ˉu$D\DF, v;)(*P ½9Y/oC;٨9 e2i=d@m[a+]>?JPqS\TcC3cD w$4cO{󍶸3Eפn"<hLE^t[ШIɶx@0PYh˪12`s( ʅ۸ş94Z"8a[ u LK =4>~= 4#vQJ,-'(!K\H|]v3=;,™Ŭ=^^oq*A TV&lpF@n4GrXv1g}$-x>އ(o;n4CfmkIeQv'z'Vk`ثTP͍(lȲ'us =O0 \ۂY2Ah9yG^FQDZ;xJIUb<%ϻcT#>?$+z_1`nM)%QSW3Պ F}l7% -ݬ̢ǂ^鋺AjB)ZE 笄K?PI0U!ŷvZ˵d'N! Te@v]̈IR[>r]l6j "Kj"$-k9DKS704lq,hc[,eY4±UvI"~c?uIQqs.׷anՠz8 Ք6Zc^ZrèZA2Ak[M~?R\o3蟱fF f_<$Y&fo^JF h8,95W&A$|ӵ0S2sфǫ^퉗VYn9贴\Wj\2rd2 yl'9(m⇮;^H -j!ߖȭ9t.3snMfkGڣ"`?0ULsu?4 $dC4o2)9B~%H.o!B-&4Lj /w,fo Ar [EOK1Ss9l>x5LY f|C@{$zxs^gZ0My7]=KafD:"ͶqMQ02M 1z{+ {S@~US*>OR=畍S@@yIcpt>O_U9Q̎^Bv?9Ҍ$.]Sfsc;M"ד}jigtp ʔrp'k5g&u>;%_%߷F4?}ᦑݩكi Y #+RYކ`^ߎ|LLeγcGE 镹nBj &@iXh 7uV fFkJk+}%"QaXgU8CUL |4ЭY+j۟zӐ XnOg R_ GA0y4E~գʠ}p*\3ݎQC|k]'uTf{9pT-;(e]Ht c VPiYg&o3"&gB8xݭ!jKدm:"k*(iBG2jocNӚ Ez[Y+)ZSBkȸhg"y@##íkatvc=+q]@ u!y_ӪEadܖY&PPZ7̾L?ـN%zs$BnE]?%'i5Yu]Af(:_p.StG{,[p|?*/X[~ws1{bJg>S P-khnG?dE 9]>لg7M#7-dT8| <S_?Ap5 Z٥"¹ :n;W`|.?5>r+WS97i38L*&Ȭp6(6 eufW0CAaR G3풐؀ -G%1zN~l1wTHbIzF Q s[pٱnTQ7 ۷=3HECSN 4xIr$?4ِ=.2 _i#v;I $UbN;:Z[ ?i.M VDoi!y]ُx'sqOkL|{ԡO S$vu}k.wZ~$0]?4`OAZAGG 0xgu&GN7`T;̖~#ƣQQBʐ*"xœB!wݿtG#*2'M>0F垓˾Ll? k(Vqad &<j}7oBoƕ/?>i)Yyw^KP= %Pp+q\-G7ҥƷef(A@^NJsZ-s9~?`|vfRy 9 \ZvMjIx@I^tXM\[-;U=˞2le؝<gҙzY$\?ACs=>s-=)ka}>̹20lϩӽb6l ߪBMٟ j>=;4p߿AUh2 D<)}8)U&^9ߏ=Xˋ?lsR'NE%$IjNp)qs&hOg(2t/ 7K->!kҠzL<ϟab].?je@j4|>̚R%Ǯ8Ae )W.48$P bZ LZn2nJ( SsN4 Q!::}u'/Y16s$G1 ?]Izb;h' `XV'zRC ٤P<ǚR7F~#?jJG͛*Eu XYr3-4X0CFEXJMV1~YB7!oNߕQg<7Tg9AToaY}-EI9r1Z%8>蠉v}1e|4oN/q̠ܺXGZKh'0֡n3 8GZmFPl.Ѩ0|#Ù3}$x i4Ip"ȏ$4Ƒ~ˈa]gΆ>+%Q=t5%%M6YcMr錌 c3+"t3siXtt06Ex޷}}Lfً@14d-yڼ԰}7QڔWw4q\M<: *ޱMy_o)cԅ6Xτ欄͞nf&+JMc(~H'rn+SF_ `,pVdS,ZћB)+.9fMKIOˆG, M3Fꢏo+._{v7ŞS3$a l/^z,6Ӭ&Q!Kx!1ωB\=b~O:щ1\T S?lA}3nԞ% ,lbBhooa<..* KAp!e +(yBҚrH.bue *c{Ƈ y&#s1" 9PS=q7 !:aN4>39 kV[o+n婇_*ȥ2yנf_H4Q'0L]< uUb vG5Gnq׌ &:Uv*– 96mV;Pd:˳y$kQ˜U]y'+ plvf8PKi Yc ~@ gCG@G+XߧIf7mߞ(gQEa{^cJc_XP!/D6W^E<7I.)zvFuprAi.gGV#<@g"܇C$3 ˮP}ܝeRu #it8Ms5P'Ό"dq7[G爨+jK e>2At4$f"!EeÏP/9{zof 9\ L$DPdĪ!lʻ1*. j=xz7]_85Bu{o23Yu>&s0Mna@QC%/O?`{A!#zֹ6ڒ> ڜJ0憤,FiqڋގM@͍fh,Z-ybvW>!ށ4#wF/, ~H&o2akvM  W/)VSdM;y t'붸t=PυF=#Z$QݪOQֱٍ<f/oJ5 VLIֲ8cV0H7e"ӟ_xA VeහIw➏Ha7ՠ{v;,'"$fOTA&s5X* DGU3W>zOc@ex?H c; ''N GC8&1j0grGg`5xêÑY? Unj34i#Rytה$BJCϖ!ICs>2ll{%5n}#Ϛzj?Q/vXif N{v oza֍Rz}1~i`?KBȁUJT-&$>bB))Xah\l,kn}&dJb3IřJaL@aJ H *hbZ {5adYg[;QnFcn?:f|s.)'6C!T*C}nФA]9dJ L,UJ+9ڙ $]pJ`߄{O"-HVc1fhJ!iÔ{Bb|&7*ȓo<*`ВCn1ՠŊ솪J(#t;%=R %7QѾ^cn-  s :\*6]p k\wA*ځuY|ǴK3vQ(YY3?!@s}%RgW@pNP,jd&G yO1+ҮS6]0 L:neny=o{bϭ# c+m#>8RKуF6iS[`'Eضp̖xmØ 7&ӍKe^1P#u8\ӇCtWw;}F_\=P)p =H0PW=j.=\  @bf(|H'#N'KsHD%dbtIJ\}ijQXǯd oip>RMjP)4B9F:,+uXc~7 _84Px2!yʊ!OBF.+䫟gh VێzLd'=0{hT% \j Gnp.t>0 rO4|xV%]@p)2SR~:S f4^+mȐuĤtWj,f.%^ۉ/ck|U`@q@QeQxXbBiy"D© d)׊{K2{1u}Ȕs<򴊪DI;h@57]:'FPlZ`l^)FXDiįqAaQn$@ D"?bq\tq3k[ѵxCzVTxgӢ˯#q%Ȇek鮝0Љ@=ri2,sy2].:XfH!Of oi+Ѣ*rjoC)rrKTQ ^ctw/ nefN;hw]c`¢R8o;,uM㶫Il$0'Dfb _%!>9 \2^[*baGP7 =#O@h=134VVL7HvI% >ȸ<,(O_*9)a;94rHÛkO =@VjX͂{9VZߢJ҂”-upFbp%QDeꅋWKr/}a #'D<7TW4Xx普lhs+zUu>I73'M+s,Ә֟QHzi:<+Itj. QΛ.y*(g334HDox7ssg?["NV8]eG/K͍&ﺑ _W +6=F?ʄkkcGI]Z)]9prB۵>Z]Ze'鴥*ӳ*?)|)KѺ>GL#A9oV`=H)eԇ>`VJAExf .vE%^՜lP̈́gxNoCF(*AIuxFiѣe==M, I3 ,-lR 2Q~#bm=y.F3YV?̧/!Y 5\7(允?c(' &Vkq RNmi,xXr_"8טo}8H/LHiđ=̺kM0d2Rf e;~:H7dȄE.ƗJEX:} P4Ҿ_h!e Mvݿ{-̲rtOH@SVUnǴNb$a0L\Ŵ;T& s;2M&ُx߲0%%[V$P_/#0? ̮W Vy5_>SoG5ObA )Q&P\t cM0pj7UD, Gδ^cfԔ}xT agT~Dss.UGlSˊ}dࠒ؛EP4|A|-eu\);eU{$;W 1 Es'AŠYUp y *]9G==닧AqL1$%A FDxzh)/yU/[!{-vԾ)' _hE^7wb==+4፧v0}_D?b[Q쮇D3W&R>wb8\Bɜe6f"4dIhb)OqXӧr$~nެtt\&!(w3Cs"2C-@vS:IPI(M _ȋ ={Q[lǠ" Jw?~PfDZ3KS$,&*{ )I(0 MeʬyP| a~6TǤ+I؆4f:A+9 g s9r|< )T }- 8mh0'ps\~vƫ'p_?my(O!뛑0=i7ß3! <Z;qHK넱\G`^ k[ؤ!P+-b5>/rqUzyc7]-VAG™eo΢JȀ)Տm]QsmZ3%N9"8,1[k? .✸KdQ-yFl#ۏ8( `5).9ygP_ .zS=/fC$_U⃂_uuFA/H2nj|šy:gg~c#Ih)@Ow(kB fe ҰZ&v_- xNej=8^.p1[:r=?*T; &9tn +!%FŶ̱ld/|J^O3(F\Ϋ]åŶW`qO(j.YZ)Ӗxm0?`rj)!:+ %DB([;y=BxW&H­V ^%H(y:[Ћ?/0 #ޝ IG\g^(UWW >q|On}[%b&ov@k| .{4 j CO.H%"ABui+}GWYgc1uqož'?g^,dQY?-&qė s½Sׂj܈ImBn5IE\XπР~ /x`j5!\ꄱQfdRoa-OЗY"^|-}ϹqW|x&0IIo0c:nqaɟe $ -| xtғ^˸ 6B I-JBD؛"w6"2lɸwd7~;Z z@0Sg I[+ @i>#?`Q:tRrᱬF=b h*w;J Ґ&+:=j uu _#1/`3nNErGV/;jn"Ajr_`dou+˼% ]kb[CaoE<ۃn%5Ty\3)g>$.o F;6_|zMUz#y9=n["Ϊ"oproT$^Nl[+pB,i*v }lc~%ϼ_`^w%[${RD镪a~! ˁ`Iܒ9moæ'L23ֆH;&q_óxHKU(ܮ:HȖ‡Y#eT|`79hݎ/ߏwu(^ۦ֧a!CD2='(2bdrVЈ?sTn5"G VS^%3VM<&7}Y3kB=hyq|5ByUL J:R{µ Ǚ]al dWZˠ ńh-I[ ( @Fx؅&?eR#Gh .Mkmێl7Sl&_iF^h42?-  R_phNp, `k7 ψFMTDGu ${^ >뎁!PV@&ƴZwuw%)4e*ԛWDĝ۠~o0B\$|o29هw=*ŕm95WH\p9^݊}Dҭ% _o>.g ċۯt UR0V!!3TaeT[6KF Ge'ղ1]|vi:r$9zǒkV-;RUxR&4';\g;5^Fjg>$KQ8(cܦ(*+r \(&o/ݳWj}YQbvS![umFLojc%1ex_ͪ9]Ƅ-]< 1 AƜ)$ ݐAmb!ﰓ V\B=7'yB2nR~Iݱrʞn&'uQ w` 2>Q IEZauIgJ;:xz3hM qeێ.ʅO]ٕCD{N=Qx3JHICCYHT#ߩJ[m"l@m|M}+Z4/{pr@#+DKرYaxL 6S)x7!QTĭB_S8'leN d!2|X6ASP`rRmwˠHa=y`lh’ w|oU#?ěᏉ#dy:.Fpࣈx9!Z/65IdQ܋p|6蟨`&d;SO}$=qF ~`jXj'#)6@3\mȒJJH#+-'EI!wEܱkW 4*Ç++DZGcB+9' \_)c }ZE8LW<<5+( a"\ gD&9 ̥aKFU:)K*@UDqwعjFwڣMޗ>a]Z3WHTjB<|-{G\(kRp6Gϴ< u_"qrtgrHԭ (vVXx<ձYx1a v`d&0,{O%5)ԭ"zsoiS ɢG%G4ᶃLBd@$m3-@M@|m OOkYDIO/2': {~ƒ 2A U9}$Y\5ց.E3J92Z$7+S|7*BqB@6V&f$/]|>,^YW&%1߾j@p?r, Ϫɝh'/x4:<8&|h9rë3rιϡUiZbd);,2+^S*N*SĚ# BpBUZ4mF@3}L R{m{j㡺1S鈿 * σ>uktq2Q/ŲKՈ{!XqD82^Qv WIEЀ]by\y<؂HdCޓAщDmu(A o̫OI{zK֌{ bx_:W5*'F}Bl^w]߫@ Œwd.-5ٻ+w05%~B3}9c;3+mb]޳x,@9\S']{Yb6+lLa1%?5^0f>Uڑ ~>aq״aO&;9ba@T(: ڹOɹZ ;/ѥwۑP/T !Eem鏜TWZ摲y')е )OԷW/ UX$N25j=Qɥuv]u!(cwisi@={y8`|H~;;jAkH Nfmv#Et՘9nW +i>Zhp4bY/lBs' O΋RW1^Ld(sSDdm %]wɀ<Z&o.8O_yb%~UXs)PYѤ5u$WW|Fq*Pt Jz_E3٧;18H1Ks>ycWfnw74|l#X2{ĒNk,޸`A„Mb<@F|7"}!cQj^߇Yr?_SY8 š:x/8˝mIGF6QNď/u. `XtOXy<ߥoovL&WE]D,Īc3 Xw^g`8KTl5)YhN-眎^ Ytܪ=d[UkzjgIHX{yYz&( P<s l ss\, eAcOVcSde[b?h.65-WF>;wL'eWWУf90RUo?׍ n2̼8?Hj *yFo[`o7dN`\) XǕk܂@Bf^ s.rXT\b,ֵi#€!*fܗQ.GiHVlFtb &?:2 LB#¨XdTw$`R9P)\jbC{~:m|~P @ > Xϴ:n3T1|(ٲW l'i]GYXVqؘugc2YΉialoysΐLagXz.EiZ*Bkt:qIܑn)v[%s&A*y^ir`!.6<+G iA^m|gApT}nƜ/YnK3ޘ[_~hjp)yh' JGƮ r%U*[| ŨجyS PCh~3Zֵ~7oMRJ%hKwZ!-+̆0 f fwqX3eHBKEZҶ~:rl!JmR09#x=6?櫺L+.1u[_SD4Z\ AJnT#| 4g%`= Y}:}EfQKr8uF RdOY 1 pLkc OvDgƺFRQ X($DgwZgcel <% :x85tp{ovʻ@"f_vaic졲YYZQc1Fѩ!pz&?MONN CܓTdOM˰7]L.G^JY#l!/$rف*VU)0_Yץ9_'Yv`&ٽ '3>@TSysqkG^jiu@RYi܄99pӅ%fڪ`߇a /'AU\ ؕeNՙ ,"?:kC2\M90S(Ҵ4'zg*ֳ2=%V yV\Ү#P鳦2Svhɽ 5_&"v';ԊQF-;Wg.Hxu,JSB.PsvʓIkc#AXaHN4͹OfJ8!"s~1mft_ioj#0 Hx-Y 𲰚{1:ÔU ɂBL  Vh}(r鐀AϷϷHOdR\cRW86En&|zЁ (߼x#,Vء E0L`0nj.ު,ږ2ǩfE =&߷bR{Fݛ)Ia)u,.5+H?uO/@tO4rrW^RðeЛi'c(PZ}8(Uu[Qi,ڮT(Ne:C(1,@Jdi =濄P5Vt(,~mҪZ90|62Iu8f=á|M賍*[,(h~xfEiDŽ?T F _: (B[rL56:s=Ĭj c؃)hİ. (C޳;=Ӡ@ttjMgZDFDbλbSxJaee U,]5! 6|GU} Nj^&P;5!9ϋmTI~sgM& W{ Πf~#ni~Uī ^IȬhH%j*R5ak=Z$*";S 7p=f,c슾ō;x8"NТTbhisG9|dLaQr)O#Ro,t}]h+V$#m;k3 {80 s8]d7Ն"D~zzkY,CRqy2'ЎO[w;AL<z8>}N.D.CG.)Idꌺ8y=Dﰗ2 }鶀eM^9\'9X(Y<& >0)#oK`%ןKuL7!{,R%QU[- fMxd+Q`GvD=|`)b0YI2zVޯ7Gx.AX i9ӊ{S1eDܻpG) :޺:ᥖdwBFd+;<jx w{ N:آiIiU=B,0&?*aêC{+@`0?@ "={ӻ:I Wn Iyu5 BiFU,:B'k?'S3(E9 CJM={}AҗP|RKdǿH qLSe8t,x$&0]|+%tNJWB_%>&ɦ g; 1fuUf[d#6 I1ːHFP˓ lG޷Ű)9ރ*Qywp3 E)'nZhm&}Rh(L.)u)S"G#2YH-\ӛC{ܝ,UԵHx(> 10 'Rvں] +˱|zf3BNԃ~JsyP&1G?ޭNÈtw9ޜ>,p dp4B F{ б>?Vƫ?4rw+z殺LIxpkÜĄ.Zd! >YK!,#@YkiC6]\-6 ;/ZOwDz[B)$CA٠+W¡,,!it7dDr o~ó8kiAc/HfVHXe )ѷA" 4GS] tRzGstՉCd7϶['+׬8AD}"} .f߂dZ8D':Eo7>,n]s6vEpu F~L2ZWהAQIja0ӈ6H^.+0ԓ=mcC}iR"/M/]SC<0B :~6\4uN/ֱS)+~[/"0 #ucRmqopA1j뱒@Ҫuʌ3$o]KKq7sk: H=z|Py'DUtz]~]bSopMɾ>vY?⋖eJ훶Z$]*SnZ0S7r5`e:g L3SÑ~3M#ܣY|<6'J*{1h-&L_r ζm ‰mȽ_\'j@GE<t`O9 AlMy빥%Jlٽ ,p*a$KLr  d H6c/[5klF˧yM tH%07^#/⢗Ba8{.9%sC6x:>t/_ .*Sbkw## *4=mUo J(} ZFj?Hr51FEn6bTr! t:0zwXleoA@g8ksݔ Q#w Ls"m:wQHZCZҸH4MXot=e <3P`LW֘{~yR2 Am~؟?s$j>7.<|#,a޴6ݝP{n͛S?Jo3ry[jS\ dͭE{ w-bBH< Vs`͈D&Lt|Ӻ 5+&b\:1UpH32Xs< =/4 @ $2N)8k-f /jmY<Ƚל;xdw,бB\){3D~a {P2{.1bhO?1ߢ2qǿd%\$š FR`M4xAaBBQx&jIw'hHLf"3}0T6|Y:KRhGbd%v)b<_,BU@0Lbn@Fѵ\ɜEXi@[prGj5y$~;X RA\-]@YleA?>Hv,UEr7 (5p<̜!RǀT?~"* d&tYWÎZo^jjڜt@aA(-8zlЊ>T90Z|_2VƁ9@CV5W=Ϻf9XLH oogVG9Gs(#SLLZ)y*E8/6iQAZ"<2am"Hޘ϶U^G'OdX}6H"RT"P۽W 2>kC6 /gݢoRM!."X2j8Euk򚛍ȃ[xm5{D/1)-s}6jjJdY!eW<r`Ɖg`~\\;~?l bS>)8s}oryX$d|]$Ng(ݡ"Z]I7q4R_Bѵ^^Vp?.f3n *=Bd!9JDgE|+xni~(,S]urRe_cD\)X2͘EB}AZuI"1܈WJ+ܹHRbV>{w7 DjIfnK(Z:s&?*bJTca? =BN+aU g7NӨ>7/)%½$x]ypnf%T pιbH\kg $i3mtU(CpԎzr"PhV6_rrz_l&$_4`zo_yՂnskGB0F(BȤi){m+SJ5vx jJܠ8خ:pN.zзm[_ _foB+$)OHQc« ޝ=ޟ;8#X$Pw2qWt]5*+شp~U{fo{(%WC;2d<M=cfݪ*l.=B;9hB7% M>f:Ōq3>,NwlDdV*g=}&ͲX@E?GʥNNeU/4- z1d7Y4?#TiDbZrtx&g@!$~Pzd );+q[B[魙d9g [;n]c)7 e7>֮%qJE $RJ[+v1ΨvԽ:@EPFf&\9v[N_;ƼT7 }A!dwqaw}^jYK>iL9jZI5jh*ijWQ`ӅCmTcX&" 1MR9`Q4zYU{:Sl6Q])Xh8d@]HUB'MOE罌s%)0>@n(f{;먎T3_dq:$_oۤS:4,V̸ oP_!ClPN _gr :w+`>)trRd(i:EZ 缴W;jr*j$rZ hvGGMYc^+/0HR;"*,"%rwMwn{\zw-e0'>HZmXgͭe\ۢPlՈm@s7~fls>[eG` z'EHC Dn[N-;SNϝ lӼr*Vlhޤ`@6Fezxm$/}]#ި{ĥ{+5'N=GD;vUDe]NÙHe~nu]x9sWKs{ň/P$c֤C(cb,#DC \8Yf% espsUOyW,"JQT6U#0;p ,jrW>ٶ$_H}DzW~eȆyCi+AU }k_+}V/,A[JUd5 dLH&GԼh䥌hG+ᎬZ$-C"d|+ faBISc4H]|! |g3%箄<= - Abώ%ϯk/b&a3^Ce擙%ݛ͏S܈cVgmAiY $ڑ+?ڢQMVNf< 6xtaY#W%=x4u:%\-S_DHWg7Y]1V;EbW;\ ,gpBHXrr<I9m:-^ (;8%Fjk>NC NP[mSkE&5e.kbDO/A&zj[ IKzJkGѢ9(5a7h1|^[_gi<4@'H# iM4ǰf@Z,݁Td1%eN*#$BH|FnS]XEYa״ý\ji0myi]}৚T;IΦ&τ s VC嗵vr|]QHnf(dK{ ȪY58AtJlΧȻ\">a[WB/#ZFZel2_W/ے?y]$2f   0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n021004l.pfb0000644000175000017500000032442610725114532023117 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusRomNo9L-Medi 1.06 %%Title: NimbusRomNo9L-Medi %%CreationDate: Tue Dec 31 16:49:24 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusRomNo9L-Medi % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusRomNo9L-Medi known{/NimbusRomNo9L-Medi findfont dup/UniqueID known{dup /UniqueID get 5020933 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusRomNo9L-Medi def /FontBBox [-168 -341 1093 960 ]readonly def /UniqueID 5020933 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Roman No9 L Medium) readonly def /FamilyName (Nimbus Roman No9 L) readonly def /Weight (Medium) readonly def /FSType 0 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec j0(]J͝H5~^ J,+ȺYu=PoT= e-@!isvb;U_^XOi{i_B6?oH6\[+4v Е)UݪE;ӀjݳW!m T;?%9~xoQ~R"JjWMnFIߩ2mc4Dp4c ;pG8m5t?V[o ;PxˈɿV?ǸsgZ{KǫFP͙&O?:Xڧ@sɛEOA-_<'JRupq|G_HϚ})4UZBy1!爙[+; (1C? -$Sfb˼nP)Jp~)^6OU]VX%eѐG Y;䂀7,o̴Z8 ^^%SDdDxW^U ?ev x) B'kתpC/XcvY)VK6(g7| 7$8= Au\=0lM͜\8]| sA ٰXc2^L f 黙^$3>wFo=!Z8,ik i8*ZIZ.ģYY6#vœIH`tT, NXz+ν+ vfL8y sM7bRq1udw;Ψހ( Al)canzD_`[P`D2#Ԧ)Yz<2!;þhR˼긼 SoH J%aU:G??%핦g;ah(K &jC'ʯɶ:Х0ItH nNb;$)!/0wݡ!tt/цٌ. .αrWˉgT< 7A@l'BrqgdZhr1 "XHH_X1ݓ# qTӫ׹ <*f<*?',dȮ0 [bBH7ICj2OgXsEEhkWf+oIX(҂5,RYznzX:ξNr9#8|A>{5?>PV7,?' )9Xm ۽7[4 74#l̶:+ʤU,{9h+/R~ iйJB $V2!AaҮZ L{m#-g8SiPDL+[ltrh8%FB A2OuRN+=bE <vܲzQ|a,p|ʫDGo h}\1"ąQyQB0mACX<*xhiTQrn<)Jr(N:E;s .N9 *ೂgkt{A\vpyPT#b_{X-Wlqd0&"e#>vU0VC&Geuߡ/].\:H؎IiYbZEyiH%N:Wׂ )*(YWڊ_KʱBr(Ŭl{RxSYWOG,+ӿ=I[~kz%LE:Kx}6fUËy{PZL±4.v8>ȿ>®$ #4`eSp%׬;f].^ы*0yf!b@bky%|y0 #E>` -'#W(EsJ@,γ=y?Uj$0w KKvu y~ bG69m*Ї4vI#ݏ'#RAfSCgb4_8>u~ۄT?rוt|*[/~7IJ*آ_ L|l$2Iゕ:Om\cx-ELtޅA$  dJO@М j#!P-y  2#Yu*:+i稻u%qGPUqۻ]a`Q6%}9!2Cu@62s- X%g%Z aPAz^ϗ7O+ac;xm ~4?W/=cw.!7[Eې@eYp3B-jk|Se8YWY#7+ YDicWtdn2B¹΄zztivG `B|?f&mK]N'_lZAw؆ 1&5MI0R͗5Nyn?kˁ|S*:1^  녉|n6 cB\mSlUC:hV"%V 2 yWLM1hh( B=CD޴/RDOcge k̞CQ S m{@]]tle~ڔ_z3>vҟOniuGcwO_tq9RY\Lq?AI$5E\29a.*'=WٞI|~8dUʮ6NU&̣&F?&«nK̽+IJ!:?=G$26Ëq@JU`t~ @d9"ws<2;p̏^~[W!@G\, w Jor?  i~8Dӭ& <3ٸ堪+ $(Q3<5 ϹC}N1VKaۮlOb+}Ж1w^]6HSJ9H[@) s}WT>F(l)ofVOc[1̕E" .+*|`YoZ^*v.ʏ+X[;IPoNz\ciyX)CtⓃ 3aCչĞkp9tS%D6U2^] \Z@ソUCT [4?yE5+ҫ9\Z}ƞGh,/rj¦( ÅDQ).!UiKtQ-L=x瞄hQ @dbZ3sn-h#/^NB@k; qMʯc]t#0fіƼL|v0-H71T!Dd3`sQˇRpjccIVי4J \ڭ,P|dU8 pAųAQ>ESC+64NJer~yۑj/Y'ef0 =&;`<^oAB_mh!h͘H=d fNL~eyW?}MǤ sD/6K3t84>U5%BOEJt83:=R36\l$k:y^`si9xHQ'&٬-Cp,UZR!|re ڰ0o O~s!7_:1`7zN5Z9=mhϪ_26UdcD:P`Ii0zYq5?j^سcl{J1R  R%@i͆e9ysM s66-:vWFXI *?U:z٬4ɣ,({\fKO8i`#2nzH%ێn^J+VHN2o }*`W/,@U&Ar'^1~䁌ʝbkМXqAP7 {eh[le6у$x(E}Y )G:H]TNe=,5(诺i0Au- \XiBzzsrvouz? A,@Je!5 ҭCsqZ "R=RW(^<_BVƘ(oJ-6Z[:!v ssgmqUK#̬oB? iC6B$fUW?qY8ܗM4&\K,:dq#@&/*7tFp*TGԟ }rwsTD`DY 酩#==P-zN蘔 1x+nt߳1O #{1fIo#f̤^8QC锬 rjk)(UJQy!zI >93U?j='Bk  bbJk'ϱe}3_ٯ wl-trd X h>Z#(9Hٛ6䆚3c -UV ޴@,%q ?Ӝ/מwT ;[phj-"pa>Xc*$ِ84`V c+ ;.*XaE>;%>AZEAj2Gmؼ&nϩl)zlR%"f (37XYCbF#r? gvفN. eVvTߝioD+ |Oe.Tlݴ]g@.?rqGsڙ09(ݨa@>Xy&lm]̄WЕ{X M欿sۅ 5U|+# x^Y6""EVվQ/SIDyؙICRYm>ŰnvfnL"Q9=GǡӲ nbQ,GX-:R6kkؼA V#+80=a*,*jV)LJA\(;RDQ"Ф0@d29B}d)(Gz̓;n6Q: go\Ȝ> [S1%8RzRL W٫u7;@lA>ZFO34_&[g-Yh:W?s a OYb(2{|8UN{AˏfrMBVПvigNə-A[zl!Q Y0 +O9ܫ8+keoI!UpS`ΌV34>yɴV@OW:6@J8QH #}*Fd)Rw2ͧ𫀯SEN4%:r6י8qֳ % ޔ7 W j3{LX~~d9>9/7J/vLWAzz$,"4^89d.7^g#1Qtuxɯѯ:%b2R/COt"AJ먂j"9=X&vʫ=hM5l{e-/]ǎTfuͲλDu|sjf a+3nt`\Hz( LkD@vYOf 3' މ&fxQ`yՇkVN1L?R1CUq b:C l<L)Yr$f,nc9Ҟ{VtJ^|X~{[\rib۴fgp4 90ͯ2D!Uc0'gbT*;+%acSݼbSEN)ck0&|P33ݢkJyv/- DL}CSSi%e3 lJТՁ4gUV,-6x/T??!SEwU[@ћVP e>w!  z]}(8 +1{ḭ_'+% P60Ƈ.̅x-/fyŞ۰<1 htnO6V7O5C7q<HMj?I#0S7#g5!~Q(ˬoJKGmC5A*p 4O^aVgE ىnТDGхV M(k%/?B-(J>h;6 iEV]LC< d.t=ͮhǭ䋘p9vۛ=򝧖<&::,y: %+<\-ʙD2Ϫ-}{kOo%nױwjzmc-Ozf}zp'w,A`(P4*DC̯Vt݆9)=ߎ[Zo 2sǀWۋcO~Gm0_g.fd@b0 Z*Ȗ, ]g \,AXCcP[s3x֤_z5$iDb4q8CNG8E?'!rXbwQNZbyE$SW/}vӳ#XZ!7o \BWPȯl¢ `ٸ,M7sEV XF0c ĞV ]&|0w"n&l4[紁1\pjchTԿo^՘Z8v!1'-OUW&͛vh+mi@r"$uavwP-[|`~WʪAV>L\Ce.{ŊY@i8x- .ۼBM Ē{<9 : Q,4;p7%c,.V{/elSX)GG?_i̻&eJas0d}Ol3r,E*J4 NoBfCOXI0|vW-QSDh2Wp \٥|}NAY|1f@:]f~ f*f3֮O8GjmTLreo$M7s^$Oco.Ōrê0Jz,QPpj%ƗLqph߰4U؋ŦX-df!Rp)mrFQΟf15`|m˜yY( gmh<&>My2\.9]sWi/XqꔥQ 1%ydq݂H^O`螀G}sk 7V0o& N)Z10B :0oL>J똩+dqQC&U#Yҽz}b$C&N> &X9)}Ӷi{DVijS$]JqBFR~+'rQt6_z.$vDyCzړ_O{#u'Uk$#_F}{yMl7SLӃK:=]ˀUD !O 4&+NJwW@E5m<-lP6g.cN.Xra^Vlr"?Dq:-_jWw8, g݌KmxKud.~c*m DT|j) R1w8Y4|"1Y>켙qb9WF瓞 >y"k 9xgFt (eQHelO4;La'^քVv}v(FһdnW+3ŀWC}_x>Sx H[*u[`Fe? -+za,#0P@{*"{ArZ59Z+XU\KjJٜ vgz1# vo&tS(n ^{;>V,`s/Il"3AޒY3 ew ?z߉2i!lz.c8q_clX1)[");lɑ 8{/f$kSK3"&S^7>+e/^BRx:Zx?Ƙ kb{`AK]: *c=C^}>>!J|:)y 9i] h%+ kdj΄uḼk'LbH@vZ^M1= ֤ ]$lFܲ ߏF(?4vNJ^%ކLũ-Z6ptG95evXaoo ybvEq0E /=ԗHL]ݗsWy~=ߗ S=d:t iPM&d9ۺ}5 AzihEn.5- ̱m{,?ʊr`!y[uTKcҁ֋ۗ%4D8_Ӯ#vy{=>amxHO%ךiֹ^p"?4AENP %<|>^wׅ2nd SI @g*G~T^E~n^=&0[El19Zi# h]Ce9g3q8~|-9`*?l(A_D _B;D/7y8 FT2ʹ6h:{LGZS[teJ E`:ѧ1 >.C_T!/l j%3iٙN:.nV!QA~;,)iQ6nCۉ;ч$I};EqN9K*"Ԑ>҃m;HpƉI03ׁ0zoo*XgQNCeó~w?tЁxj&]Keܛ.LJK(ylr'  4N~/09~^ƺ4Q_ 'aM"dy:to.2א T!x"}ٰZqEl R00R0y#ʢL ۉngbY h0K`NէAGrsy?\ Lx\We{)ǟ*_2d ԉh'bP"m\\3_4EcDĉ,+s^s8`T {m=A:&&zrGu[z#s"hb{k0NOV-sa oG`9V>osL;?ʾ5c"S02f.?ܺo~7NA\\.eGP [I[s5\<,'1XwuR/)n6ܓuAq>L yRjD.j᷺bO@S=@¯A]V^.>1Y1ӠkFqTdӽXĬԿ+3❖.j5t},\<͆$(bM.Q-\T2Gf~tPpd4mm;$$P˗cz2cuKIkw' =3 +GZxBJ/攉v0n^]6FrרT7jBj*)zf@`1 wn*eolzʺTQ7qy񋢽 uqau-əWvʊy6+.hK<82<Ž8>Bܠ}squLVwa;ꔺzW+SRTÝ$i/s f3^Z-?քx񬼨51/Fԍs=WAt'+_^ Wv N?q.ωL/䋷D+& RZ0s|B[}^ {6 nbCq.)E\պQWLlh1O< 񉹷xj]4z^j@H^ղ05Od Prid/ ˖8(3cEm$jsyn\!D|zU `8Fg4+]DȰkJK4yﻖym^Q;kQF!0/bf.XRW97~n>&%)Q pN 0CKf ?W{9/ll&it6Fi4o$߹\RҦ*~.}2!J(fS9hgpIU!!04Kbz1A139Շ(QBm+sSWz^EN.؞2Eoc7?;R.I, a,Gacgc7Эr,qlItJ>SÈrh?xеCp0 )ϢcSKZm2B L9 jl;]('H׍鐑N,;.08Row+S [bUNHr!eU ;$7H`6ՎhL]D>QȇE;@Qs ::XFuHYdx11ݮHI;AowUՇ1 Dؘ% {$tWڴTaHsJ5O'i#yvWy:w5M>.6r+BWl-& G;\*(ewDucioeI 7hNgH{0!*ݴ>4571@=:[ʛЇGi$q +0Sc裾Zr儸KB}ytuAm퀀6:V߫/K0@o?Keό.׳j>0L:j<{'nW~"E!*cә^&m^yEӿ\3>^Z,%8nT5xv IL?۰˱ _6Z)}.hvJ(@i`SgYa֙AN7@pLxŭd- 1YC@ LhᏔm9푹 :ɪCʱիc%Z ࠣNw%2k7uqUYi /=܋ޝ#PF?ZT|E ; ahj r9$@;Ti*.7Ņ$h4NeP\J5W)ڀh:߬Ygm(2- ) ^__4yHĉŤǏ/G+m/p%^B~]Z*ZpW 7ey&(՛΢Ff0G0"R ,﮺ ~;;zBq)R?{ɔo L,8R5U}Ul1䘤A* "&t7i-Т¶eܴ-SYƒc/iAL (])^|,[Otvo HLJw)2rۈ˘ͮXNQL ooV(ORshJ_LXr|Zc%Q9*%-5)JgH1h- Ajq)y3Y =ld'hQf@Oؤ;KqgyhԜ/*|3l3/}xQd#v.,$WLWi|pً\I!9ރ}A~뗌yU,УGkjF),^€"9?A#zfniKH}574,UCe '꒙ǽG4^8/.'e>zz1%Pe{@q0G}E\}%/$@WrTL2YUJh/Dcvݜyk܊ǂf̀eQ ZsDl(|Ν`PزUE*8ӂ=o}}Rmfܟ9ѬAono*dqQqioueܾ r&w ]cȳ{hVq9 Ù`ɣr2@Gz‘A̼$y?qXH 3j 4C(xT]p"72(AjjTơQhD^;+7k~qH7 'JWLTy4VUgE 7J3;i!Qw?] zʪ`?3+%G7ҠP%tV0z1 crrT֙ _%?2h"' &L\M[/'XqvTkP9)+QІH5C9vjq?_U8؂%7>86,T7,࣯"9pT).vjU@&2@ŢWЄoAU8CAgkf>.zmt~K@m=6=T' UT*,O6yk)ɪIDrB Bzax)1ZtbSk)t9%|hA&:h%`!J`D,W3Cx%]h7\}~{ 2iT2[$P?%@BC΃ذ@!4F)BR,k 7z·E:`RmU9??'xޖr~C_ Hn@h`FS.M\D:ER3J\d$@x`wH;W9d[<טݩ&F9NͱGZ *h`ч(}gh¡f5efY!ݭ3+u7mԐ=*hSvN,"pn#~F[1Nl+ ?à>{fI6߸P% Ԯ_bQE #Df+^_2<5ӈ6{؏4Ch>DBm"AM&[?cu'x֬Z1ȓ`}J+yYq^`{"jw!k,gΌ4 o=I=_ᅖ}ShY; `BXЈrp}X5E,HʣMѴ'po+yd"pq˶S9qqiOV+\ .eopX[^ Øx{?ﱄ2w]vilуN[AèúJ ZEVKeآ+eM F.lLЯ߱r{kDT _oh07ZPFa/2}]+'4 `Q3!K6Ḿ n{̓)4"|ۭ`܏"*,֩(IVAOx-7o`* "nX.::-K;kC2m){qHJ9/ϝ3?UWQ_L+Ϭ=K_80"%)޵BdHٟIy8^=[ʅrJoIe~.umSHiZl"SI0ň~:!i؞^|=HHCBYے2UbPޑ趡ۆ2S߫ayn>1fc޿~z!F"ZN1\rC:A*GKGJ-|;'ccL޶Ņ`"k,4[~#>]Er(4݃iI0JV #SDG6ZDΓYEN˜@w3୊Pg?cN:q`ǒZ_ЃKs_f79yri7Kjc}Bcao5M< nVU!OD 4y㖊.gRu*_/J[MK#0El^fSL"*vI%-E㩗p +&{"GQbIoh7r"c\"dN $.i (zQVD"48 !DZ㵬ՊYn4D p`A>i _4&~]5sPP.$4SKJ{UBMi~!ҟ:BDX*+{_^E uYt!on<ӏ,A<0va9, Pi#lޑAT5\ԄQ3>K(AuXt}u+]0JRdlo{.b1@CVwSIT^ll~S CFBc;Q#N} +F YVet>B+9:6KQ`'ߜox?I$.gj5=}(p۳;$a_JK ͥ7-z.4l@ =K$u_j^ `Bxd1me` vކ+zaL.cJQe(I:HW]ѐTexCk'/L3~Y+ME&r^4vl#K !j)~ 2xȯֆD.zlrFZW;>h 3P&~޹0@_aܫv!,yМ?a!d\+ a$tB'}Ud.1*S\d'U|N3Wȕw*{tꌐ̢(phʥ%3?htz*:ZI<"namqMS<niU/ 7iy !ep7.vV{{S"Ո,򀙄QHҶI[Tt*y(Mr'G_+$(0ۙ:f\`Z$e tr%` 7#\I]WT@5^fi52$O2aАdӓL aԊh<8vȂ ^D#1l@38dv0O%Tj":q"y\$YCs!H׻'zl 9>tx$/$ڊYyScJ.W*976T+:`IiiըzWQ.myzh%cxmQ-m(r 0n)ݐ`o%u-BcLď/9@mJbb 8ÜuZז姜`%H'DX؞@&_}FNRtDWzۍs=>Ya菤`,p_nŹ=̻M:[st 85P {9xtS9vF38|yϨL"8>?`^|'S%vD!gj#k90q%ټd6Ի0#mZ5EUU:*͍VY?ɩdUvٙɎ;ӟ^z,=H 嘭ZYoH fXQ,:gȸM-㋙>95K3^Hj)|OPЦs5ݖ)HZX_i԰\a8賺$:jB}c3>ocOTCU=a#嘵Q 䫇|Mm  6mvS‚0P2Q:;'SEL'2Dϳ _ƌf` \W+n=c){I 1ÿv?TKxՆxv4|0@b u 4AN ff I /xҸOBD~}%a#P;jح.i6 JRrHsSg)TZet\cn{MЫϼZBS?PB^Jpfr$7ð9L}8"L`PG[ojрzhy+=cd$(tY '[6=3LԴmBB6+A:k-1*1s|j^llW# 󠭭OX_.JvwaT{B31`X֎8Tms+[KRzAVNb%aOC3&K=Nن!E <*ܖJXS-,DM5F+WcRDnKFO[D*ɟVpCxL]TEQx57if^<-k""ym Ć.}x]|VKؙppG=liG?6}!=^L֓|Oe;MaA޽/)u'S+[#7* E@>u_g=ylRZ~پdyx\T$-Lu DFm1pQW-4eAv/ƃڠC| vjV8 &qLYMGM;&t뇻D[AV}2]D ֿD2O?_,CS~lE9')C \Cƭ)::N12IWz9unS(n蒁L_v$D?3}G,0X,Cl)6YH| 1g-@boCk.'U3F^>L Os 0)5(5B`=&ssH]V<`p^C.Agvrﴅ YtX*DH ?zj50~˂fP6S6' ^YxrrT9@Qz0kNa0BZdz2Gmp\ R:F?m=*;A\v`< \di-mG ћgXwꈤ~+_Inྺ'b&Q6N QK0}q YŸ.[Q>Z8d,mԱ7I&Y6G%bK3f Ug{ ĤQFpQZA۳%tJ]DY "f#ŸXq2O͆:Tc-X*`1*ʧAFVg-%IMvst#"ƭh\Qt1vтz yS\pE DM۹. ߈:/&<]>@;)s!B&-.lK?`ߙ<Ō_u6 _eaFG3 < TcA:IX{"㵘+H#CMvB?w61/FK""8h:!f,&Y`.b;Ey2:^=8Eؿdzx\`=C=C4J`(^ڰN&7{)qp#j4? 9~У 1/eO \Qa[٧v\M둣0):u:ˠxTk6;v'Ñy_wz17b}CX#$]ڭ9x~ HژSU `8SDyR.ծ5 u~ \huI%UXۈJ>kon[ZoΨMܺjNEh[ԧ{겯,e^a$/(iFh2buGzbi˟ћx?ט)̫I DdDuNv8ŗ~S! >k kBFz'3{wh#ahNicvUV雋 0JA5 e 3.}=@e=Z[.th, +A<  1Cvc&XӕKsvf-Ng!M.-3 foܠ\ϩtO 3haBĝR<ךUJ~h$eqi*`E`'yF5K'J+QE$S%0~2҄=f3q1G  n`F}w5DM m3;u>J^( ][1/\6AJr?3a7jjjc\~ (>)F<9bKu 21Jyhn6IyF҉Hl{ *>Id ?qMutp%.kI"MB>ۨheű~(l?DD$ 󫗁gglwK|HwZD i?NpzzWߚ"X.e.#YڕPC7{VO}%O_SW^s?AMFxO<7Tv}^睫K2#Sݩh݈_w`0P\dm it0w)uր2o. mS:$ ~yNUs!Ѳ MN3AwTC;W9d((.~ dީYcn;!P)#i eɦNqB, ]B|xAppƶS LAieջ PT2ܬd~P"gv% %n!b!2 w;iPk ]'HK.gs8Xad>BbBFlc.BˁX ޢsh3;7t/{ݦ,Z\X|kFJg ~ 󊜂eB||Nz]_O5/2v1[ƒ-^ Rr#~"37_6A P)eyFFtGU$QD[gd˙͑âG楾GG6~vGz^f\2Nb;3I UYHwsoPJ 6t&YXXPW.l w?pN6 GsF>ܮ֦ȜaZV*(Cf}`KHNJԯ{m;3,ǿ7nz3|BF7\<큘W+5@SNf3i*# j/:)Vi^B)t$ kSèƱCDBci{:4); cnAb`we8434F) bP[A/q\{KR:ԍ=$,w Q駡ܠ۴Oc M)7A.z'yRnvc}XRs 5Qg I]y!eȓGI_Hb}%MY&4,ҢˎЛ_]WagB@9E:~Yin7^)9ߤe*ylYb(-:IRη:~d2{##Llt"܆P[_7cFݭ oX HtUϪCdΛ|$D6d ؾsz ^꫄knD+qh,惧V ;1_RBm<ѷrz|ML7<>o/Z+A_%1nM`0z},A-NuL%q~+_qA 3ʔ&Lŝ3.@UYE7nmqձ^aL1تvCnŌBbOk'0PA֕tb^Ҿ0eSGGB1RP]DwD L';844b~oD9λH.]PvU-[H۱e*#oe@6pwũ$3g2Ajc5!G6UǺZh vc^y׈631_Pq؎w+KU*0Vs''?Cam Ĕ0,yp"@#350*I t[o  <."gE##LZN t;l_ Mѽȴk?=i8{SR(Y( Y'X 5%KΘOKRYdch1*QD)Ot(߇4aq^2E !.(4GgÿMw8i ]e\0"RCh!4g8q_s`w%y67y "'l$TPEhYa5ʻ ^R]/xf,uAgĈJ08)frg|yg؇%:K= @hiҜ8g8[Gi,i0D?w/whJE x _AŠ4 ĢI\K#hR?|*n]eeo׌ CubzxO_-0>UhZk ~tyZr{ |Ko5k#/U%|^i᭖ \Y\۴1L?Wū3WT5=WX;178"Q 9 j^TyjLf^_Yo}ΨHSDQk3lkZF )'b2tY$EݑIL8u\p{ÄM=+Q 6j!ѐĽ ߔIgAm^p6+OuG솤|wD42xyM<-\BO<Ќ'l ROyS k:O0^*K$h8EGº%kY)郔læËKd DFdX3? Eo ׾DJ5.^ڐܭci LL2nm/F+ j` F' $ ׺oYS f?f!CdnĂ.03ToG vJUvjղ0使!Q}L&KDIM:jm&Dpmf Ye{IXjI}!gN0Nu}~HWxF}FS7$##<:l#+t:SI)UR٫ٟ9Kqsj eYH,Dq8c GXd]~eg_b)Zmu@qJqtĸ  SR0M~~mpkq f KeŽ9PHv[z%{7}Kqg72" o#i݂}m%YS"jT`/Jۜ7[EƩ:"CEvA`!qA47tE=PNZ9鋤֧=6yOb9s٤@>Pc >Q'wn $BcL%ǼR=ZVsȆziIWmPMv$:;G#+\T˦>[RZNl2Gk]~]n9ӡȨ'Gަ ݉&t9wj\x?CY e;A|yb,a823{鐔>e`4Ii( 0ȼi~9,)*ɘkk;A"kz]}ŕ:LƮR=` ސ%9ӛa$/Ny -P@^+) HBѹ`);uPhLn8gA'^# $}LVX-{0EN^2]GZbCC*yrLMR ^[I/+gVf?⊫j v%)EyhMS`Zr~C^?k)hQT82DhI? lfCA_RۃC|!Y2U5EMN b8Uqr0Uؒ &*cܼfD~N^k֤Fۊ'Yd@F2U7/2/&+y`˖JY ~:,Čy2Qm8y< {-װ \ڤ`u\w08ćT}rX.xEg ԙ*.bʼZ8HcqViPְ/+9߃<.чܩY|@Bֹ.&L۴郂Yc50-w`X:1-ש&-B %}e2,OZ!WD%?ŠM/$F2޺菔Fx$Z3Sgyx6ͧr=hsA1Nsw/|+C,1dy0|ئnLVuzss Tٸ|'Ms @[janr<z(5 %:c(} jťо==B_Ӛ_ֵIR<dkz]H Lyo.)z5\ehQ| r.uv%V)A<43s/͚#@C1XH|cw`!Tsfj {pysZ-™5{.PǏxDFޖs+*a*M\<A!S#ċ͘ "0t%v*Kےf=xãM@+},#K:CsuKD (vEv]:o[IPBrzvK" 76sPv?d Y;}7x7F4p2ߪyILn vDgDWu=Y§&6ޏs\2{|4>uf/'$p2Qx;M5λUPn2R7xIJDo`w8ZF{$õwǏuGmN a8jO7vdžb7L%7-5x1bYVQvjN욌ՃS-gM m"!QdGPȈQÒrYƎ[îȥ2ҼR̰-ZLQh CAQdx bƸMtTkB0 u$pCm_?ǴQhRxTŬl9KrTGnŗ#.u$m#3Uj56Ar wCR3\Tۚ(XqѶ=B2kɄD9<_;#-kz~٧0~\,Y9vp3PQy3X20t`ѳ5 F[zKٺe Y+ϟMa2y@9'\U6Ik'_@mŤPqEYV{y9g.\|[k&,sdcOv/4APdPSML6+\V} ucwL0]:sἄ"pGX&_$1rS-R~8zrN_Az4ӊ"vu?E#JClb!o y>Zd'@!D[0FS{ۄ4ih4꽉7~F" 2^%? )?2ʌd"ӹэ O|c,膌XCLuCc2a˷(TYVS.d8<bHۂX̬ .eWC%Qj]GTO6U~W]RRE2Rz0?&b ]u2jScSZ\]S7TX!8A#k*:>@@dH>$>ͱo`@T %>6B^Hѱ4NL󶁤O- Ck_inz%'[BHshAM q4M&]=J]Enb6I"m{$^2Tqw`%{Zߞ>O!ʠf dO.rs Ggnޏv8k$Lr n+6F~ւ{.2]&מmhi iǑy xNuW1Mg1uG U$nn [UG}_{v/B]"Epu%S׻`I w߳k-|k]l+꒔IB.c"Byr|^ɔM Tk_cwzs7|?C<풛p=Nr(c"H'Z 1k[k y]ň޽ شM+[Aşg7=)x0O` !R/I5$ [R`B`1 4b#EsYgRJF?kS=r3~Yl,0 2g=lM&Gwӊq%s~lZS,7$jD]cb,{Hhߌl+o[K*C쩥c|*,P+BԠqYNc !lLg:ςQѥzuD<2)!7uXb5],F1G,tsMaMu bn,B'q(Z dC)3A} 0? o(o'܊xM=U|^$.sbv4Ut47NL@T5=e7ďJpDu]sړ(6zÔiN^_DqryG7=-'wEggww=o3^f"yX~^,H@z(+ O%D> ¦,}wiz_nhPF'z]#FhMHvUJYI\W8U2Zg}vm)\@d ,.S>$KԌhSLcX;.m+xQquKǗ1nYS?M"YnwR VCM ~}/ƴ8O_Yî {S+=`[j+-J/U^c0,(g:Pz?hCLJ`azAd X_#dt| ,*Uσ[-Ϫ>5>#B#㓘OF955`t ﷟ڌmVVj0=)e8g8& ^s4fWHĨS*cU<߿!f14#c#13-Z6DM[G4xy^C,c7 b`2R} ݜy $'WN`Pjϟh y2-O>t.~[!vR\ Vhye7cFP,*S4I33tC]kf"s v ~9S}DP#.f/ I-'dZA]l5]CvQ~&8q!dsn?MqzOlFM)s*xa040J&iQ:DdnުRUJ;Ƥ% o5%Lǫ}ngscx%$G}WwtUw PXW{82qXqh e-X4NJb>7V<hviaNk5|<2(v A0z^\]#U6\k$Cɖ0MuT+mfmsnh[†c ԩgV때;46,"E!%+m)@|ѲwKҹ#T9#ckDM %NT[ϢtͧЌ'c7C2Yz ݾ<╊E$-|_9EEVY3PG76+6mRסwMB*hn_/9*%0Lg-DpI Q"5|z"AP @3?x7Ds ezaL$#Z npriX ؽ:]S\ua^/ޥKCr?6ػMB7\](6Z[5j,}"0ˑ6m:Ǘ$]RR6L}v\C-s44œh͛ENQyh܍+cl ztVDWn(RUH'[ܯh6PqUҊ} a+Խ0s,sӞ&°/1rozd-3{15gB-+L P4c̅NPH$&*50.iaPQkD;Quu$rn3%3F43bQ UJ[>)5<2H4at{vͩBU|N&  (X z4=PRUaj"Ьd^ǔ:U{jEB D=⎏h@ =-f l(san*km^ ,i w{*E,'DDƲ|aCx%u>}4ߐQ%YI5WBa+7Ik PYcy^9,"-]+0lZQzZǙdrw[Uf5!|0jfᗁ#_jnr ѱi)a(WƱ6l aP629͖4/!ぷgAP D漚7ƻ|.1?״fPmvu q/\pN 8ѬGu[&+%P$:O.$2^2%g)!c[QۋuU&*nb 4Pnq1!]2S6^Hȿ"DN NJUEOnUQ$n82ދ:,>pa^v8ilLfoPj= {F  nА r]G.mOR,cƲoYWeOgY K_y(d=Q]wΝDWj"̎/Mcad[YLAB0-3&x\|q ۷ xŮBNn cLjC=VN_;6EԲDzlk^QшB_9Y K4 ãkcW2Bl]^Z">^e:3Q"ME3\[S}U>CzHbxe'&*;wIfW>xalWh!ozq U Ŧ-%\Avyy=kݩV( u];7BcCR2YR-DO7cElzB8nQQ8ʔ@3?2EqE傈 Vw:A}E=IP7xbD9wi u|qaC`rxEaThP~7Rr wO,r=},1)t\mƄ䙩|fٸ J*iHf[:A7Sx@%^8(4ޚu0چ]ѤxNjmyO:@22jhge͋_/EIOP?)CI[$idL_f*BQO,*gRŴpxg Q#K'*(9#۪R&PAyûC4csM_$C@¿|đHPv@z=%[|J/rqTyF3}ACY/CZmN<E>y#dQ6o 'Ϗ& z\Kʐ?r8j'fs *6-ŐjnpC%Q=i-%)D<.A*rY}y[ C%F-*;&4?Dస[Gpcvc/!`[X | vU}psFǯHK2o)!-B%Fu]Zb6m8 sBcy/њf1}\\r6uK{**?G_We\q^Ϧ2`k{4[6~;Ё9#͙/Ȧ/ۢ^M H*8 x}lY9Zuk-Y)3q-U qaDolI" ̨3orيÒo=s3 Y"fTpԴ^FC@^p/5YI,4x"=1ɼAʻaiɦb,]@<(\',}P\KVx{QLOH L&Q|j\-AAb\z &EōJs$A(QZjc$cxs M}8-%DGXbTd$]bԈ,X,ו&_p`h!0JP=aSK#7}"v 2HDfseI2:^r,yO`"lj2fdiOD_C}uhܸ,Hyi|]&70,Gmeg3>㆚7q&sm@wNNvW \xivW1}{hha%͸3QX=j aR5ƋB"Zcn-G-yZO=+<8Xu#ﭽH@NXORlI]3(rIXq{Px)XҏZ.螷zl14KΊ6&b#̦ޯc4k|qAqҢt زU# ه}k KP@ܓ 3hהką;]p@^mwSwyfk݋IhՈ^Q( ]f{Bڝ@\7 ]6L`*{ (,yc^ [4tH6M%י#zd>8}#7,܈e#?!&~C6*_tLGvmQC5wdeCsWK  t#F<7߮ 4eKm}/8#+mFW7^IٗM2Sy^W,K:c>}'T!<о{'3HmjiI*qk=ݜx\>>1)bƖ6æxjyBS? {]c&@Ŧm 9{L"vv-3͌R0Q+3MQc oBuD Oq˙O1 H^ r0aVQWVs\C={\ -f`ZnmFC3׷H#Vbm M X<5T"k+ 7-G1voE(2|m?M[1+Ԫk{ᖌg$%џ4Oc(~t#k(yp-䓾J 䪥+;qңa>E^>ڋQ /}XGF5%ܹjv{C,#9Z bh(k2ӧoZoq+%"jeв@p=]-bk9ON4=a} y+GK=_ YTh?hFor3JM0EI)imy_?cݬ؋d@+`_JЎ92v5;׶ )P/Bٛ ?X^g_GCWJ pY8Ճ_mMƹ>v·>^W& 1G9k m [R2iK? ё?V᧷내΂4]7WEi;>Ԙ3q6mZ]qFڇnh76q '.d p.2Lv:f#5ÁQMtdw8e]fc"cON}Y/lBsnKxkiHK Z*w9T%lNpA @d>)3U< m>4ihvi 't\akY-}4Q4kj(Uq%=+t $,%)g|=Xk;H-Ntn9$I߾+mNJ} |(9v%ȉ3=`u>AZT EAv`,@T Hy26pF*{` >8fLHnp0X;)ʻCq%P;<k<s֡/:t' &!ɍ>7.F~̕: ]qy#=hC(QɄO%(50m9hPRQٗsVVU4p6W H|[RDӤ ʧs)ɋ/< @Bh{hq`ѵDt{*2cjEPMOe)۷{?Wp hH6w aҕGrkrx[9E1/ T~~s+i"v GS{lVZCa8ZG[M›"` N i/rA,{~pSeEUJeqY]TYwF\5 ߂2D*k=-cA`LŁ|CRlz{;y҄aR3oso5Ae6ZsCW.OA&/ HA`LGSFS9>͢ 7I?loT+ጚH'";df j$$0:j-%eTfHffQ [\AO2?)D5uH#j?Y&-a-9ocfE`(0u&bdiE Ox8ʅ}@c.<4֗>Z85TQaQ;]CUoA&Unw.fmLv&$F珝tZWYS8~otF`m.ܐȶsU }.">,sdiPɈZiiZV@n}Vjo2ePkmUVV4Nh]v 6|ƬE c{g"Ս ? RYA%l$@T54=2 D6:] P)IQ0G,_'ř\Mf&{N,ό0/" >Eq-7uØx L1O.p(KLEؖq p:#l/ W_m^.%(t/$RGTfz|񼸈{A/n,{@uRl}kwF1V2_u:;j;yW'M(\@KxU.:&8r(C yn5[H3w͘Ѫ( xq?휼ni4wqhו8"IOb/AM/.T?H, r[/XM'=qS'i VG+ZPN= ϓNԐ ; cjo)t&5D-ipoqb.3AyIcsN Л_L;e]W"bm=üUW˙gSBZ|:§,ho$۸ 6 d!qd(R2o `?ux+CP_*,Z9ܶE8.k;=L.K$[``=7H9;~LT89ƫL}e8 D="v^N6EʅPn"ךpAIţ 6$Љ@_(>KYŴX-Vth736e^&qVx1s|^ /nF.`ح'&ief1?Md >ȧs&b@ǁIEncU}EY# $bS_z RM0>Fܾk/"wݷՉ;L 2w1hBɡI{ u!--;ϝrs(]mh_hȃLl{6![\+DψeK3.BY`Р$OLϽŇ H(f9M# J; Y3`,]ʆ,N ?lnp[ԴK>c?_<?o/ISH=aOȈXr!`C gU״5ZLl.F]Z,TSuw0{n(KM2"`_CH%L7Fv3QHfg7UḦK_[IM;wz10vh~~C$ڕSl(3D]pQW|=YKGu*K2Rp_{2 }b="(Aҫ31̍s\`-0zt(]aV-ۛLjDiPd >`]5b@ؙTf^K7 ZTaD5C}ϒά]||ٛ/1Rxx.* x06_틳3pe7McW=t$[mf`H"s4F7)whPO;1jVO#Lt+E=)x8yFkmS;Sr 6v5Bޣz{L5t\6 h9"Yi/C9dsH"45mjz;մč=B9^BaYIhnjL?m'f`Hs ;W rX,c8 9|ass%ruhhwQ[VLFf-$wkbY+wvlFWP+Las8p_qX.<@~%9r&xk}~F?ǵ/;%>BgU@mx4'˵ES?ahK-{am+aIĞg?cwCM(ϲAA-6C 1j\f匿pf'NF8>@/T5B۵0HߧfZw'ٜH<9"),)?Z@I3W]BzBܳvdSx qpUgÞԜp~g7$1]'gG^/İFq1ʻnv`@>;Eq<tHР }JK!yr2[xD?|{3QAJC0}~(MU4<:(V7XKg!MgZè#Jv:JX65tɌ nVSpG ׇ:/EPP`ãxFFBI)NLqeoN>K@xVs$Z^`NwXbt|%FBm' ߎJk,p_Ü!/ YQ ]9|t،W(u0hFf LH>`C~?bY:S9&g$"Pd$CzWqP--X;StB1(}r7Й\^ӭ;,cD+%ĪDe r8iʨ17jurFr خ"{|XN#S:pp:XCMaJy[(!@KsV=-y?z~R&j'sԳU&V;DP>tGS_n ʥ/լK0tطͼu1!xQt#L. Jὧ1?İ~ T|g·r\c&tC:,k~Iq20,>[~~$)uVur(ԧ~P$ޗgd)F܌:5F}QCɘirJ\S%^]d\"|B$(эdPf}%9I=1 .mɾPAO4R<)30~Oπ/6Srź/Klj_aT`H'E6JTڬ(g&#@db*#r+kv߭VFrsME0ʬ~P}rjBDQWJ(9) wRz@n_Q/+,vK{z 7aLX@VBa o@EGfvtkZ,L)+a/E_Veɔ*`m 蘫.kҖভ\0z-[`(賷acJݥ)VQ" d\ Z1ם|54>b:ȽEJd㟰2-Li7_(ؤ_JJ|uF0>bї*Rvme򻙂GBђzTc~#7K5 5(6^Մ?;G8$Kbprf!KP(yf_B'jg]ϼ M{@?5ZXmxQ؆NV,\K*~<'m5YdGB6b]q]e 5p  l5$NadZrazvlqļcnt}1ez$5gOъ('%^se~j|@IP0Omy;+T\A?Z`Zd}s{L 5 0M;ļH)рP֕ 84ޡ^nr_-}KkL UoZ̻e m#0' bp67ScX)yįMa_(`(D?~:¹sX EOwaA2bPax bB|-K1=&qlEAKfLÒmV'&3"HAFLR=t)n*%[y{3R}4Gp-Ho{ RO3nz0ӟz;y/ %bB=\N$P$qB9|~_Bv.L;F(/3SVYiMN(k";f ʑpy6D,*>0,ɡط,$`s=o,8{:A粡Jt>֧Sخvߖ>]bTXߦU8H `vhlk/dX‹A̖%#_o OЌJ[*jZANh''ޡT٨YuD$TWw&h"he.[%yS9K3Otl#J zXH2J)a$A0.m>^W㟒޺s=GGuٯq"'C졏bkÔNL%iY4UE4UUԿB %zyݍuHkh WՎ毹)q)VNXt-fapzP H/I3^f?i$Z:#(ˣ Tq4jA]R@ݽ^ 203$7AvrlF2ʐ9s|Ҥ% cg)F so@F2v9J8x%uFK箰^$ /떱^0,C|NLXPзFDG¿ l@u[ZmI4:/RtLj<Զi *N'Q#w#Zj|-~_]vlaZܽHVk?Xͣg cJ+;ap !#^1is3Y!aI-Ƙ#9=l% (d{pSn< ╇}lW mj]WtPC=- K'gPlgQIabgaeFb^B7@f˯`M)Dm f/qZaSǧ2݈eo >mV1܃.:1ȓXP>6mV&/zT,;hy2?x!=r9~ܟt-;ڕC|cS]N~VB/p\ڑ؜?BP`d} \09R 7/QJ>sFS챼 @޸OViPq~Ē Ň X? ϲh2cA;Auҍxde475 V863n>BPj"SB $D B>cymK)0Ӥnr 7ī]|yGx(lYYJ\mje6Ir-¡wNBaY1t9I."z=>eǫIiZ;e|bnpx8yfԛK 6HP-Rg=si{xb[bE;5r2> {!􍓁Ϛ5i$=q4= $ZYz)^v4xej;BO|RL 2n*׊6- OxU H=51PP7e&2*}e>1nzwyb\b95I-mQEG/>9%^jMyY܀`+-GN.D3'ao7Fv'Rʳ',LRC[:S> j)BC-.T[P\m璹y.ͅ*x7y /P #UD5-R˪ߵp8Rڃ9}RDYPx¦ClyWs^*?g*u8gXLҜD#bRmc2 đp8*.udX~nυ~IIA8~82@XQ۟-oQ8;Z"D[;*K;N ZoQ)Mh{P"zLt3ˋ[,DbY׬_ VagT _@rrխdD/1 9l`ibA mLqS_rb1V>zKgHA"KH_mxY0IȮ$܈G*g\0Q45,g~J- ύgcB*?>: 5Ӽabe&}K?LZ2l.9vIQ6 DAȖKJ";QŐ.NNxtx\xAl/lAzͪqʁ񟰙~@=*8e~b wyz{ȲDn$O(Il֋ea2RVg\6wKӞgUF͝}Xwa6 0r>?d/Bu!Zl}I2*juc@wdbP*P#"-#HKa: LbmSlpo]o,2l?ry͟ڶgJbA139vӘP *䐰şb swbN]C.1$³k<#>i1{U]V%n,ӱCK@Cfi`"q4/]y~ ziN$RaA]M_g;uѵv\a𵡓0ǰ~G }R=Qeg^QWZp%-s}"[>R׮tY,F04/!>UE`zĘL}awJ$!OY1@(d?2w%SD:߲,YFе鿓1iN"K en7Wj/dw ZI  Zo_ɿ;>aߒ OՆSe(_Xw7)R/loq^F ~+#Hg_ /.-i5(`?F,KJt*[sWl\nl?M=<> `蔫C+!hlX^!9G%02az"yZ>"* pT>eh*I02[{FnZ=ji=AD D1Uw48r_&!V~ESR=ݕEp{K4HY{W&Gԫ7g4-ZYuy}G8y5 !p&}͍P\-zٹdzˠw)8g ,_H yy;Tm`5K.C BdWŞqnD4i0*;moܷ[)OzXAĖ\h B[noQݴ2nV>Cj~GyjLH(gw:kT7#vMuS\͌7%[UHc\%L5-2Sv7_4x%}?`0WŲz#@mj9ih8қ-ȶ)m/i$'ܰ4cMo"eR' UzdxR+ۓ>1kW%;C9ƠŔ]vB2@W\*Pn7e쎮0¢PWqd+՘:e@hǎ·g Rm2ϝ최?a͌(tj^ Ehh- j͊8,8oՋUc;>P'-qa3Us~+9̄"3Ed3NauC8뢝Lo: N(&hDmGG*T`Dd }qn4h-db-Ҽ䋧Iqv'4U?=>C UcC|6 ay}?EKZ!*J7s)Tj&M~-p<x.cuIݮ3yPG 8C&$UkaM9f lOw  9ݑE>\l95r0!%D^ƯδgZ-eIX̹h?Av6꽑(dwEyɝsy~թѺy raqb}( /n027WHws7C>Va >b1NIm@RaJ4ܨ?g 7^V I)P v_ +3Vs?qF+?}O +c7e}3I )ɲx[) {κ gx#0WѹP=41%.Ϫn:#qN!r9^ kEV]z-٘|/Hn̗&#bZ2wQ&`dϜ%s)“ٕen JLW'n9:$ (=$dRۃߣkN<_ŝ]GؗYm8HfדeO`" Ʀn^boRZnV`dXG?k+ڤCFJ{S^r ȸatc _'iOU#b{0~^E_UW.VW[TA3=+-)ĩF2FC8U㔾NSTWO&pB $geU8Q.*.>Kd6.eZ}kADyS0+!M{U9H ^n]NAOTe93B!eAحkud)M1AQ<[Ɩzu N!=%GHڝ>1{ j2(LuB͇2,|;?0|LU°NW3熦ɼx"q]iqܼtd{949SP8s[wU``ۗ=m{6ͮ=O^}N-^$SwzXK4?f-լ+;;ⵎ[Ws>G)LA*GސɎj- %bاt]4PIB% e( ‚8/$ܝVU~\|W_ iaUy:Q^(YA Njޤ&[ˬr/p뗗hdn,o|݀oE6}O!_qZW/$E`F̟'=e\T6=6dqY ( ^ozoҵJ %fKB9"`?=Ekˬz/^s&Z&USW`^{(7ND(%C=z5;.N90$vSpIolO0&^B&vxnP5 ¡~)S&be|Ǘge.eW-'+nZ1GxAV&n8j#yCkd{ZIcZ%[%V!c4 b(ܸý 6-ʀ:`ַ;x+"IpP$I;ơ|B D5tҩzyzg-j]^oHEOR32D>q_[A!*!؉$=XeRՓkd=q9E*pQ2hgR]fk[X[xWC3=P>y~PA% T*ԫ8ԭx5\zzԆﵵgRT<.F<CI !s|m>b-~RyFZwڱ0͝'o2Bƈ濜~YG,w]u!#ku]jh;B+nt)F/3o 6V=h^?*D]+)p_j+BG՝l0 X4n=ПVbC׮@@k 7nsd>n&iV*6? ݑ}ay?! R.{_ƎKy hS׷dӬ" Ե'a&~BQrbto9FyCw\\ƅGji ^6FCNL }}qCVC(b/ Ɖ'bMΦ:䳇hhtْ 99 RY`| 9׈+բz]@|N/;IyئEhSefC:$p;#-lJp&7f.aI\|Bޞpetve-NƅS{Ѐr\xu"NkE2.n.._ط><%je6i sd _SQYϩj՚{Pﭱ7H6+6⾞)-ƫ*ZkHJ^.{|(O3rFIwʚ%#_׻<*}B{@D2y#t':kmYp&@\H|\B OF~\"m訥A-B**PNDQkHn.̠V+čcQ@ZcGªɞ86J̋ug>9+^qV 0V{#Sl౐,ܔ~u#EJVϳV,I>l?^GqN_L@L[M8BLk~#JRͳbNzGZ3Gp.fs ?Mgg$έ/ǣdϡd-0iKxoY 3P8ࠩbeFRFKS{!]U&;z+z4Z\s *5w_€r{ ,)c\MXN@lN&&>T].cmʨ5Ø/Q4Kշ^׍;0҆Zψ':*bu9cTYIV =j |zFDT~ߑSw\xu9Q8O'A]*JȊ/U НSI#"=[}t|O+FyQIS,a $,Wb "@də#"iRnEkAjߊZboξYy\m$H{Or"$S*Czݓ\s06?+z]oK&=e$_FdpAˠ`&A)O(Ff㑓lbڢ斕 D$wa?#t)lIG¾ c4t6:VX.0 |KAC*?'s6;J2-`jF_b6f(TPT`B!Lwݥ&.'%gߕk4񓮆|u\IiS68Oss}\K!6,w=wԎn翏ᙇ&ۧ=SXMk٧l Oҫ줶'h(cOh:Z%1N2 uCh:$$uWSv!}z8Ak\p|%GRxG8wNAKj\ڈdzBGdw=A]cgy&Aċi5 BPE{GUTX',Td$ w@hChVƮ4eS^}v8<'D)u'xc\cn FPD<4UCnpT{C@ å~xs >-RhJLJK96LJd`¤sUܦg^^au]7{kVp輌퓒iD܊OzAtqwӸ$l|MdytpxdUi,6THkUT,S꫙ҽ {/uQR+pv[:Ӄc*FB[ԝ-z\gf>!@fl 6ۆ{2(@^gɭYQkW4e;q J5*EJ̺GFoJSw}6$:O$VzpSߪKoINpӖ @jKZZXb]4̂%ֹz؅UE"P ?/J˶bإHA;ͦV >{9PΐZ!,PrWr'Ӳ̹ea?]I m_!ڵS2i\2'b!kHp)ȓD 6 \]hD捐xuO~ۭ=%lӰvSxKϵ(SvDn _NS7/`p_gS)LÄ ]eǞǼڜY g3 Nym)jtz#לY=ѺDYu]U<,dux?V}jJ,,O,=/帐Pk^T<Y~}sEN4xGk+4c،QV^(I{oNRNBC,ULlԬm>El\/5 {ff-}({P>\^ ` Z26{ѦM8Ɍf#q /l3AgFfL+V\Y'^͛ɮ$"+ϐ^R(LV@Y0[&HoTgs+Syرn3WWSh0Q>#SR) f؆b"nx>/TPI=2_p|nN//ސIZJb*`!0c3eT8fUb:Z\oB]Ð O e1kBǡ&2Sv|/TkfVv,VTӞDS-&_;AϤXb.,)5Ȯ2C3yg-7G! Ҫ\Wiހ~CFj j"IΙYDދՈqd‚SoL|_Rb*a: _}Kk}rdWq=R"dqve ӿ:L䜨^SZɼ(խ+YORXܲ'vr59Wqf3_m0< >!`&-Y-+ElohJ+ 3ae vf7f[b'Ϳ%FH]y8ZHPMa(,*G\^TJd{Y s(Vq?5~Zr,1FEv|}Ïy Qf鉡 N"O^ZyU#|mx;rLǠp6A-~ 8<1twWˎwcFsY&t|~Q8_γEg} 4Qwpx_U?{>$ڴ2xe}}O=I'Z^DAH}~{pNv+Orr gd c\96 ,6ѽ @H0p#LB>$5.Ebjb-NC/ƃ2eM. ТE>`(fqS_~ 3s !S2Dp}Z;b sY9elPKrCY& _~u1u.IմVs7zDWo|s{]! Mlm/GA+.EfJd#$+(Z-)  ~4G?C6{Z$KΔ+xzx0>S4p?;lxx_*q{\m{/9Wb1L%CWH]_ocf_k,TDf9x %Fc.)T\8t΁)KCry 9U䤾:Tj<.[|gԒULd On?$<w0qlz|!Oya@G˼vشv{>ǰeqO w ǜVАʷțadY%eI:t7p U"zH _I屢ɨyWо@fA4EW]N> i;BaT&'|`/ Ug܄ç7jh>ɬDhh)xx\ncAMwtZf66E[)zϠ7D֢v&zE5TAIt7 @d K!*TX-.°@Csi(5g/}RÚ)yDYr{ eku=AҠgc LJ1~2:> }DuBxw!SQt ܢª_Ιg若XDi֗|a=d3AhF滝z?ív^WP[\RsYm^߬N$Q*v Vj "kT]U]qa·^ ^"ފ-e:aX2w53s57{XvlNnG g/_%c J!P:uf(}ȣ< 4?]z(GKxb:WߌwI菥hR:_,D K'NaNl2 @WG bZ/];.d^yfF9Y/;Az1p~πGߒ&cP?>1Fk=NTI5Z-񽏖q}w*HaҼ5 Fm/͙)|DyvU+noӗBq~pT7(81:-y] t xvfN|oK&XrKTY5;'7,5zt$|IkQ喧g$?OGڝ^傚oKؤt'X{ CIqcuQ3Z84hPW#U!ML_RmV+}_6] GA e鵠mzg8][HIBs;!okxn|ّ/@" A];2C1>xw9W Dn7}VIFt> Xml8K\~ݨ1+a8.vX{jT@v7fC֞eAA¦},H\[ .8ru](-B'f3ջ.wٲՓNl񝿹TL(O_W&;]zBU+,+u2D|s.":h+m*agE2n K,sr_i_B؍Sv` sz"9BNU4搕.B:2G!m]olcQ?~׃S!v.Bvmfg!uE, pZ*`Ǐu~^>6#5EF5cRt *$R,[<+Ěd_h=thقyK988ar>S7rP!RL?&ib׸S^U`:Ko琢سC@o,+8!Wر1/ne|91@ixY&΋Oj^%a7~B\&q$3v }k4xzSzJɽfSr[1t@J  +QEl z'S@oUqHy]{=݊ݼcoDs.1=-J40T9F܆BgdVO ZB ]C@P"ͯ%B$"D)֩RF1:X/k[{e<-}9,-A=>㓌$Qә^ JC3@M2RZYr hm _hE1܈ BlN7zKl\Ѝˌ\KIߨ֠DL %M}Tho$f;=A,7}}_1c$ Qj rf+`/IO)u{nix-w+ߴoa,Hub5$/^՜xp?i8AMG}>Za nW7!=`F r}v_HfЍl%_Jm_E3:HNq8Qу 1M+c*NDXI lF%R_3YyUO[v?R/gqƖ$ x1%`h.+΂ b#'~$VH-@^a͚-Ya>}!fb~ X&pr&8hЕ_ s!2}/H8/ǂ2B('u[+1WWj}X[nnT`ЭpkсJH#CJRM K5pږ;_}VCO~9ޕ%<1 ÜpĮpmNB5KU4^F# ¸qϧ ;V6!X3Γ8nSl&Nv*6o]z.QC7=sxgyZb0I{OݑWw{m:C-`)4>-޻tdEm^xL 2nvхtՔn'9݉<<_mtV´:=E qr,n|بUAuJMU\P>Gijɩ)E[  2O'J86.5F])38Z8f śjn<Xd5*GЂgjۀvz.A1~doqd=u_+rTD]4|uOA7_4M n#MXx;hF{)hh t~FKT{ӹ3 JcB۵L o(h+,5!ZZ}|y;WOi^?*vs" cCEP &ϮH*Ԑw>? Z2<>Dyf(v5a 5.2xc|h5sEPe}Wg,rt/{ل\0K*|bTMg$X{ƥSf0oۜ!4#T-\|"$a c9'xJ0;#? B BK^܊|_W$MaGZ4rfѼUt.GC?U֯ȕk)h鉩x1Ҷ%LO !%_IoUzO$ =nL4ao5#|t6k ,#!u8f9-`G8[[kCQ̝}bF3ۿyƃD"U(ͥQNN_\ޔB4if1H>d x:FKiG'+g2N($Hvy}7=MY1e㹄Bx llzѣLmJsxcROn]zp?J%|4GնDuC F3$̌'AmteS.CIFf^ȋ,y*9@GOg)a[(4.R=PZj]Z| (,s9#*x%vA!]vUԌ%c *NQ!EPT眂兩@+ЎI9 Erft*:up@ ]g ϶~^"zM0KH!h>IVK_x Z 2rp;=' 駃 @>q58aZԐMڳ߿φ:[M4z֛zftiZUxeg-NTgg?'>nXϝ2y/Liqt)j$͏/ɽXz_(u1^ 1pAKX2.JËSQqqqm*7J-#5ã^HO`V ;tdDB+Y{ vsa=2(P'"dX8ofGSx'(Ȕ 1;?尽fҍQ/ 4}쳛d&V_ӊnEXa'zdhY&ՌIT I[\-|8k:a"PuF˨1.܇F/4a9fhSdŗru{zS2mAlpI8Wa󛸕f/ +n]d8H*P (nVן5O$G(F9)XA+x*uimOEfA/DTilJsYj 7s@Eu m4ҡ2S_K_9&o:3] ZgzP?5AW1k  uH [Į倗g2`!} /xr~nxA&LRVCV \ҌSAdx=qښ5F{kfWDa2 45@HL-l6*czՕ\3a ChFiPcYzcϾ]D\F=kow7VNsq,xъ櫜 dD>ky/ G JK9q7/`=58+ ;lqG#*Ҭ6aI,៤-mvY;.h7=dǘ S]ݦ`(w>c긲'҉} h+fd0)f_^w`ȽtON*[%<4k'NC*d(1Uhˆ'&>=I5 <Ũ0|[hJi"L{_M9a݈1'N(D Ez/!{=O.Mp猧lܼB'CR(j˜Hvͼ{Y$1\Kh Nැz o YI=>}ƍ^T"ЩI=`  |Gx}XB&.f2)uiK_C8Ec/TAB(g9/mQJ7&g8ux,g,9CV[`z)uNJT"DGTn~R0Q.Z#?P֦+=aCA@*&L+8Kft}h D 9VFM7$ $qJA.AUgEa CPkPu"Nh}E0KfE!_I6p ȿs&-ʆ(K^֎iV.5yپɷ7[pYBv'QLЕQ';BEH.#%z3J -'.+ɇL}?+mҷƱ_P.@s cfkuu!]x3 k^V7!0Vw'$ gHB1%{BL703DWiv/bL*כᐵyy(PGO3MuLo_3l ^dG<'~I8CM}lL2]*gw#PbUb9,ʃIaB/8uԷjs6GG^ 8?>Jd5uSid]tϐ!&@vޘS7_LRۤ:B/ pu(د)U_z.8U )x$5t5#N,yXO.ɛipiYc?(}$1Lſmc/0hdO_!gd$fh+beN2ORH9{uGV0>H7Wze3~/Xpp3FpOFY";V0|b!Qz'U@ϙKEhZ3^_oi*, 20 $ Rgg"5OkӮ )/2=q=q;OJ{\m}Jx2kZiC ]o[cW|4w E /Sj]-ȿM"Bw0M %]6\ LpMRiCIy:P U׀Bc5:OPiQ&h |Vz9% Rg(]#Foq2$yȱRLoVW^7#yGz /:-.3:B ~ˆE#A-n(P!>w$Is47M~Z{(B&AgυYLJ85GDK2v.QDo p$|ĈHOλމܛ;U\u!<"9H%}PE{&-}ahՃY/ihIoK g +RJʾ\YZ,W+jq(r[-̇a y2h᧼c+ƌ07͟tH('8hTPڿ7/<(~E*UlX/U"ObˬM}_Q;ҙi-ݽU]a v[,1 ?5S2$uQfPb8-1D/ᬕ|K/C2 =!Ť;?2xu\pP{ψ4 ekWX>XB|d yIw+B]*J0Q嬓 8'`87S**u$"6/5fɴV~H&kޏ}# 0|GP}idPQUbZ6CC+1:z q=٨dehC;tfD 7S:Om1W> >$/B+t 馘gfy6 d5+ p|i:ݽTm%%hXKkל :s.5DD~*Ȓu ^ߋº-kw֭CWll"j~e ?$䂈|wK=AAELI :8H Bvmk k>vci]xRjf&>e'Js[Z{lqe܃FdZjZ@1߂Jר)=FbԁUF)M^Xy?[J Sw~#ɃR4 PpU}po"590_ C+U Ud`VO6R>#sIT|רuDh](?0-x*Z7Yf?-˯V+ݦΟ&$-QۃQUptvۼ7 ֡3@bIo/oCŅU[>ԅ= ¥'<#oa`x%\_E>V0[0{ a|!mt~miև^A1Nݎ$//Ks`TS }Zy9P6y6ilEe!s#^Ĝ}*[_A_:VTxx ̫uj0+u5nY<kQE8S)UH` ^-%r0_4?U/HA&:֠|۴ PPA հ4S*g99I5(C'36;N*:Y~*`Y&};gy"JAVwƖLT/ɓxB>LD}88V!~VE lQ[AI%GR#No@7+C+!Q:6-vS;Pmz:TQ`Yh;-@P5\*FEc++ dCVۋ]'d7R4uÿV_ӻ<'/5:WL^s鷀P^NfkVN+&xĦ2d@_GJӸg̕nJo}V\U02 dSMܟPYoAylNZpaߢI4$B.&OD"./'08#g:BO,)/,n.|BF5Dw |1%R?YR1Y :͖q&-Yqe6ZP-9@_T {2Y{DD^h|q?g쳈[ڡ/w0O}9[yT2lЊIZ Č 庤uZ[,ؖ9j8:@?i `b/6oQ$ջZM1 !Z66nĤg,"q('QȠR$b i1x?7r#1SV*.]Vp)9/I%'JؚmhA<fD;N C{9\\/VL=g.ѿ4ܱmVY 9M^r[ѕrXPH$ʚw-'),`u[D=unf$Sۢ7LW2`v >R?(/ =zYR"EV|6a_ȕLZ&yȐK چ2FO$iH$(C?SaH#ۃ zN]qͷۺixO7Umd6B{xPHS+gfNVr7>FBɮ's@3SBI] C}$|@"0pTt?nҺguxqy(FCrx$C@C<ɔm4ih[Wj!$Tcg`G}p$f6> 09:>B5}Zh::7Or"+3.#?\h- ?AL j5Y RPc Cy-Z&I\ZN3&l>)obhnE9$s' He )@;vi+7ʓi H_d⋨WL#hIT#VI2X@omb%$5cI'd8QU>xFYJfgֵT"u 4?v0Ѡbk{;{hDG.r#җ1A/b_HDUm0'I"QTc2m `ceN@zuqC]=(O%h[TԬHC`9e18ŋ.}ZavCDNf/D݄xA3<db]&~\>e]F]mazryY %'F0NUao']gkw^C.q{yuvL2w1!\`1`p!FWuML1f=?',ժDF7_veߑ`>^+`٢44dn El`,̔)G?9|;qR P揔g.(;`)#h]Zv4sZZOjЯœwyaF}{jsn8*-;oN@MbO0-z(O[mm /"tG)/:43S-Q=?8 w`,Τf0nҜ4 Cp1y0g<7SUg'!CX~m}9rA i@|*L2;TEtTb&:NdQr<pdTe;, a5Rq{~5]ftPQPU$sX+(x!aB̡:,yҫ,[N%YBa)\>8lQ+,&&9ݯd6x.w)O$$$#oQ?\]‚$'#/յutPQ&,x,ˌ 1:.Uބʴ<s΃g>O}Y@=2f4?uFku[8Kpӥڬ n[W8ˑHv&9?0m'C铳SǤP A֍n`d;WGwdUV3jI$Mw<ΙY%EP9z]W6c&.)#B !GnW˥֜Ʃ"ǣbF Ҕ 0ʷ%͆u ᡊ]BOAp : lh4Њoj  5UteE]`0ZFfgt_KWXTfT- B4(A'BO\xblE 䝭\xͣ$}nn̞OWM\ʧkXh`xf3+,bʯċwVYP{Uph\:( 'B7ԓJgsQYti(^.;Y8:H~7z'x-.[ N^` =~Q'mwbܧ8pAs~fMrUX؝ĕR/$ϧ<]IK^V|lZ_/Ig-Kpߋ*.o8"q,8n<6:P+I˝(UOiq.uS wۭuCw P&XOeOT`+H9c]Ά1 ߬qR'L;b"1 6T0H_V"6 tufJe~QVɝȺc<7w*z Mt=^xܼ 3R^\# N4J)f'\8NQ rZ1 \n0{,"{[e!g1V/+^f滕zEZ s/S4 h;A]}l[_Zv %x:(:ZF)ֱBh}q? 8y]x$!M5j94G] jj>,H?&Wx%1*;H4yK5-H\k˓6 h$ϳ4:Ļ"bL[AMs G rgNh:A>>g޾1d"f1?$P(6F<>8? ;!V$A )thGԿ7M1Y5l\X;+OqCOY G J{Q&;͞V4bC%F:3h87_7¸2>Zt/+*gPֹnݤoJi-g4 eP@ M I%M-5sTc?F(9%#1_T&p{Y}:@uA+f`^jвeSF@oeҒ"ھ :[tV CtxcG

    !#4^y銫&ا!C<{vVj +nM==Ae|!j d1XTj|vlJpCQiŻeؓ*z0t&#)W:4o3xw%G<6Fq>B'c+>8=3\DD0_3D@t۷q`$gn4%f* x?Ba5?IcnG(J&8Q,TMU):b)3PՉ򴱚nߙ3@FIl7Jx5+dqcc =7OCT_I˖0g_vOzr"LN 3|1,d*J!wGa`'f`3*/!Psev r]OGͬ+07R8R&i?."NM 504WM`( &>x(w}bM`tg$ >n{{$ ldgT?) Pax2ä+!>6{c]VBBfSQ3~Xk]Sgc2Ewҽ?[ 8)-]B`;ᾏU[Xcl̽ 8׊Љ+kn"@FWkхg~+@d6I/зpƷspc7:> yt^m C7`>ru+x?LK#PJ*dw 7yȧxVjjW-2A%s@MSIOvWx!taF={-/R;sCREz6Cm]iffԸ,Pb̒0V@_ǔݾ5M=[I|0_ߘ "'D@ jdyg(s7sgBesj(Hvwku/8mH%nk@RϼBUb\Θ=nlBypb%< W`} Z29#C,^25?0g619, Ex& *#m6u6}C\Gٯeo05Io XҌhG>_\$Ҫn~ڗB6\̟jQ;ɛCM;K"pEw~o B`IIT1p1Cʲ ]/9S!ne˩\)V1XRDCw 9ISU1~6"m;|gmѹ7 jym w 8GzkUHq@\]{іY(GK] dk*gH^~_ {kqg;f,9Eh;u"{|It{bLwrd'z=N-bp@?8yeb, M:%(-]N,zyD|"-ИF$f=2:G\,hW$m!&3`5#ZS*lu7bXBZrL^0/`b~ۻ~\ %,PJQ|w׺tg@ͷR}ʐry sP[T A"N/6-Ft.rUZAnQn]ɷZg%$حSomfK6#-E*(e7ש#cP&& }9~soh5JŇIt x Qs) }"4l=#g:&!ɤ砓zϒ[U1 ):S2у+$LOt1x /?у2@Uy0׃0#9 '4DQ Iv.^fZ%$y✏|,.9h֩BlSq/@ɐiFt{t| b秼1Z h۝ k{I 2-zla@ɯQd܋/`fz3ttXB>Gg%TX%)Wc فX4"<\uZU:Zu|mG5ULD`I CZiemUr1QpLF Av֞)'{$F6zW$tǾ[5TB'RR\eiA8X ".a;AjB{(l Q o\=mW:Nto`DX$ u>3#{ä5(\TxF0YǓuOSd @)KztܼY!{YzVqb/2 30xUc8 C ;0ˬ+Ac'"Iwӌ^zcjqؿ^}[HwD]i@ ed!̀o<{C0 $K "\ W +gMiR|EWR-J?l|:z4[|pG'a"5JHζ66ll㭈j-!+SGͽ#ݤG{g}ذVc hͅ0+E#嬝OV  ݃@.C*Xi1N𣏕J/58UGlm?<%xLIor;.b+4seqR1J] Eݖz뀕t~Js jx /I_co3>Y6 +YvxƸּX#>yr |R$K-0(T:D64ix>g_粈Xm3*bNuD`e?ݞrDy wS8sxh j$"5Ҧw;PK/Y"hr_tGhz5,T){k|^賘Nn]3f]cf >H9&X+'2ɲ搶ε0Q`bqg[n&SԘĖxok]q٣T.oCe h)URRzvu3znr9!J k7Yk9 w CzQ/5vgCQO `kGmD.Ie៼"褫ScE,c3{U '`6W3xSvƻA:C~>ړ 36Ԇ/ރ^(C&1dϾԱտK ⤃FCJX5[AZMO;5;x.R@@"F}Jg<T3Xoзo=ׁv #E7)@CkD8M[Pá,]p/5lb=$pq(f')0E8j"q7,l*S6T8a@ ,9ghޭ]F΂%ϰ" ʪl3z0UӃRB&Gmշ0"q(DH?)O 7+H/Y Z6*>pe}K 'xrN3 *8Dm h]2=j_97KS S\>1k4(uoteO͈aY5bȣ3Jα1hy"ŰΤpnhDvgkQ^7 @gwD&<9h~l[stKE>6m6ǜ='nr"Gy}Y )"Iڦt~?.u<M~n2gj&a+\ ˦܂KzC&%Gq/fE]f]XT"(-wZm*Q)s kj^cbAfǎP]]hY9?K ~v]bJe9G<QSYM> p']ܑugv=. (a Vԉ^Ya߳cn0.q5Qe3/*DC:/rkݛ=fb`/t#wW82vX8UٟMjR_Ɨ<-|5>eXȕBIOcl8a\s)*82eh ( U~~/ ܡ<|d+"͏WKoѽ8eXSRNa9هA5H\͚dLZXiBs *vF {$ A/vH9tĔ_bV/2h ; Nr ӕ䄮05~2?Te)@.*TӖ ۀȴs]镣imژiw~zX]@1Ğb8HէU@SJc'%P $Om2i8ľ˗$Pĸٜ MM?8I^cRC^1RXl3Q"8nxr W9ٷf#"!{|qT~S]V4mqr̡=-_M$}whmB# @A2T+ 2;O͒d#rGbt7fD;F5XsPnQYFo'ss\ cjyС0.O2p^c2ٺ,T5 /%s_412dcS %9P,˓*w+HiG f=!Y93M$ϘWx8)1C>/׭%V@]M|aYOa'GȞz |[e*^;,x'i_ .(p)paDB(7$_=ghMQڕ:Ll~˘ɿcj4wI[܈=/\[(z/c?ճ0阉98UdsL #ڄRN8ۢJ) \E_,Ċe`@TAxje}Xf+>Xn[wD.?"|r,S;R48lx!h/A8Hfw#۠Ԍ%q(r%@Egy֬1z<X>gr@()BI v:T[CX&W+m@^CI_$M0Q+-[ *0ZauTIԛZ4?# ѝrev:Є8@(Yڿ̊YCWc*HQ sBqhzd]u ,M5b)ao*},<~P}-bo@˒Ռ+d1~%t4u T&B:3Uo2׌}>ªd<->}BflEp 6"b& /-RZT%!oZvd^l)eňܔb;~Iw")^͊H\j\ڵ{U:~i/Ie7.\k %W9%'Vhޭ9nH'W8 U: /8MyQX^mb# ji!/9o1 sH'y,AyjvE+̀r*!*'m6ݳa~ʹD="2:'+ߣqݜc`de}$K[t>j؞ =K@Rn'`/q*2u(1.?=LɯKr)vMWu2N[SIJᗍԝ5GBy6qͤcbY.j{Z *R1*v.Zcdj>veJ52Sz i`Oo֪Ց۱3Ryݰ{@lґ٩|NnQ_48?,`oq_< ?]j*\)CNCɈ--J'[)/ jy`# TJܢ4>4b0-bA?lcc{~:(2:gfI;X` CqgPNeJloq m DKw pM^cE-aQ?~@J}-J-."US YtNfyM"$`+";WaO>mZ5FW/<(/[mo3{o?A%*,JIx欶6Fձ JZ k9=1xԺ\8Bľ֔AZ;48ͮCDZ뗼 TGa^V"]\/D\<@b/ӭ_p%H|k#JمHb "T_}L&̫ꅑMV2E NoK  ^|1SGb gp'ݮ.ExY\Ցᱯ;!7jv O">?Ӛߛ ()28۱+5`#ZbW7b[  /REKmڜ?RN;cS]QGkH˂R)@|Ә2uz6UEeeE9bJ<ża6p5hqDC6AUpDN(uAs]E{^GυGGZDX}\L4t9cJwV@2膆J;ɭy -]b\x9zZ ܑ/nqI6#N$-hv>0]dI|Z74吐r IH0gi  lp>>yd֑*LJ֜TT_>V\kցKN!H&l!G,/cnQKԣ_T5>}H4={,9>Go] I<VԍfVlcluu-1=:"jZ xB +&09mДRݟ`c{ZQyl,Ym^ AοZY}b +e|3*XNWL҄Ž/UL ຫg/\'LW/૊R : "!u:=L,qE}7]zWs~P䜿DHa|yq^QsYз-c6" D)k r0 j VX w q>ǂiHZ6Ms 9QgBZ*?-/ʟ-I3]P.o6@JoAó$J)(ag]=ߝWA5үr!W=n'n~b>zeՋ.PRKݥ9^WM20 G!l_7#f|vcUiGRN= cԶg45BFxw^Z+Lˏo] ,Wq.ΡaI'׃P'<2psJlV򓎏H/{nmNV6qGo "^̞Ĺ ,(%K7"B4XהTqKGƾt= gνA-DS72gLv9_waY6O!~A,P{ڻt%y뽙'["k5O2?}hmmG^A얫6fޝʦß)] "W=}3 ˊ^=N<g][BG<(^ 'rz9JJfMx#g11Q >@"nޅE:Fw޺N=$*9`~dIkQR=M!#ķ8܀oj o0j16jYRB[DE UٜTCq^FΑ*& =s7\6wx3EÎHT7D2<=j=0wRl@+JGyi\΍P;1'0e>^-g32pXM_a+F;lw'Ӌ+>Ʌ|ĺ5=!f女".rL?erե`XVm==NCxQm *cuxrjL))I-b4.l(!sҋk*%6o8 RWȻtS.GE%1SC6w1r*zH"8U=p4V h-I㐮'%DN߈zf Z9 Si X1R:Ǯ; __uA찆f?~qY? 84ٴ0'G"5N !:Ad΁u '>F[T=AlY'KKn=Aōl݉9"1$Sm!>;80b@Z|Ó+}u"*t5>uСQ0U4@-M7-yi- e_3Qfc$kiN쌃QnH+KF?Iߑdz2q +십AғZg(FYNB /0$bAB9ӚAGCӕoٜnt2zM}hf!u^~{#mo1TZ4JȳWn,'#f -"͉qjC^'1SpRz}~gi)]0#Noz;]'mNmSu]UkZқ|Ar⶚C8 Pەt)ϊ"B*;EI)'h_teUnp%0*>=s1A`f%fbD|@_d΅AE<sWDU՜5[/)}D+!D࿧O~t< zCypty 16Fw*4ٕV#ЋP(w7_ L4ӂH碔' h}E)A5YF˟*$p v4oN ņ{@Zؚ.KzN#vwYPT듏- p# Y hod+V,3b04e˺$V[aU6tLvDoZ}ե*Q㧰r_JGh#}K_css5xVj>?݉Qa_"zV&0m+s`p#eTva ̗LFk<~ke><2jݕWbG,O@ǔ@kaQ6wEN?.8Qy8콁yUv7SDTt8'Pɿٜ99! m؞fgeο.{- #ѱ-Э뼮Xco;&r<^jZs͋pQ L:UëEԉ̢%* \b 8, 㔊$F+GufH6Ov:( G*htlmkrM TfV+UƋ He|zK:MZhW[^Q>m7Ҏ鎜FwjQ'qb6(W @$ T,VFd0jpۇҸ/x@k|)JC.T d!n  %5K*scV,(@J) K}DP_ъtbSѿFR&8=v8n O@ّʇ r_٭ ZϘAE'oA|em{Ɠ\k=3hET)_L -5YfPuJTyQ<_4+qkZP *?,gfZsnKE:z֞E^]Zu4+jjߚe#sF)̤V6Rk?cz6S[0:EFvAo8Tow$WpUMa-#ޛo SIO˖\2&U?lڷ>C9OUt%5O*Y,u_6Gʇ}:A4 2œa![~rˉhb =$x):ހ} B#4D m':EL)ҭJDZM.N?hw 2%y\9Co=U*'5d' FQe⊿=mh\mN swC"(R9c5/lد,5z %P @?P{4s;s-3"32M,B3 8mr@h6#`e'J1W}z)G5l6= B4ԑ+0 9䐯:lEE#,g?R@lE2Py7UgJo^֝cÕȸ{NW,SY$%b' +P\p]Iʳb7|_ 4P2en4jNPntQ- '#/pB2֫v]Rٰ"nvě+;p,YA?;f]JDfi=%^͏{boWP3 kաi"yؕ+:vC ߐ`o2~WWQ`9XZ˂lFr8~t(M/_0jK6lїHP2}\3-z$:%ۙKތWYQ]It˸(p ?́0(*Õ5;jlt6[G,E,5$To8؛ZRm a+!TyݔH eaF%-4_T>/sv9*~=u01R->ZG fkZiݍ׹llP WqGhdGɍ;am?`,)d 21uM 7|vGF vFpk'ձg*E(w7"WxZ,X7qquYiZ/n8 VդtN݉`J?9.ϻX1~&d4#CvXbے^ș AZNtSE+*(0`' VS#9.e~80@J#c~d 3D"uh'`C2ICBuIy"MhsSKHìIY{\'/ L{lj6hPW@r)wteg6l"@jU#;6?0kc#…`GBeUZR^;['ڏN CvuA">֊`] ` \dM2i!AU F6*U$IthQ?s(1Bī䴕;)suW~XLs):7˜zgG{:t ڦ>ƙ#.ƝE &cI/@6:e' 5S(henK'}}dt!r*Vv57Չ<6F`٠-*::dG3^G,5brbFjzaa牰hVc8nT;t̀;2V7 Q}twnXO,4E ~9|t mK\T{an5?n[2PB- Q+XzEy%s{(t;kʪ]0?{=fItBfΉb[3e6w\hC.By[KCSV0Q[gi/pL6sުiMz>'Na'`'-ÖcoT%~kc{,%gE%o٩$"%3_7dj^ФI 0%G;t+䏮gv!gCm$c0&-:5A/wrr1ڝx4k 6Fp1KE&E@; ms *Θ"I_3k\@\Eq+,haH$d2׃uet [#`NjۮYY $W<|eut~ Nt#ȜRt 1^b`i Jy:%uyLX ‘*B{R-ػgvqRO)핝Y;9Ƴ;)›j!LxJ$^K~ )ΤN=\}tO.n|I]5[ŅTcSwcd1 &phә.݅[XĊW,ijtt+޾%&EEM=XH%fP :>Gw\EO%./dY$xb%p/ƶ>A6 r~NJyK4#5i( )0fnkl'KV3fj(6PUplDy؀^ɲ9iX\< ay9Akuvk}9J&*x8M[Jfʹ?R",TLy!$5nw]BfnBVsc_$fPЏ2֚8J GHu'% JzʗT}1̳FM?aQ?u4=; 8n2˔~A6%m#睽Qg[WT?OGbB^>6.Č *ADhXG V ݻHn6` E5*%e-CcHf'Ðv'7(3uj ˳\) <M*CxXMtjaxSAm&z$VQ=t|w{C O}C#X?\Cfꉤca>˺b,KSf6q|k4&|VMY̳e#H9k;qfe5Mw{GYW=YcvɓCaaYO$Ӹu/lm/aXue aV9Rd!ToiYU`QG⬶ƋTFi2Rhf#Ig0S uxIQW=@}k Wo_V<${;^-AT d%^4Lى[e0M vg7a0 E^kߏ T4Y=i|*_9ԗ%N@#9LMϋ ܣ6&m1ѝzZNܐD_le]4Obߔ/I\th5!b;Ln9} y|s ny,[A*5b[13QXHU}A,:Hզ/XvР-#y XWM)`Y?.-PJ ѣVt}Woq*3]~ϯ?kbY#h춘#?ͥbc{gL.1;9Qz1ٴ++Nq %\6AW>ێj܃i[Q_&Q{y4p=E\i;(ipP%T1WPc+{7tE /f$ oɰ0OZ% c|gtR5gβ&D 6C4k:3X*yG7!Ĉv*>x0'>p[L!U 'urAH\@ VlR==7xbkQ7T L JEyvGT!q~s-21m^TRsZiʶ`~*85sWS*0?Zc]ljXW`Wf(6B~hSfckuE(Ԟ "꭯"JW@D}Ͷ1^\T]B!\m2=@<a-$̙V0l\_]DTi:SN휐lC"!ӛy-p8˶ 0!ˀhW`BZPGv?rqœXψh- #U[n! Q̓ eP;"c/XZqb =n ܳ Ĉt(q.tG dmڭ49d fUڭ1I,:FzYD[HPem{ iKBJ ϗ&[?iL^?+%<]%qP;{ B6`&Y)OWf{$0T#/\Hͺ!Z9E]Jy=:̒ : WnYlGP2!1v}2@5£f;5Z˦Œۮw|, t]Z֞\qW,M՚rQCB.=D#q맔2S6E88azp.e|\ͧV„]CxQ -4bQIˊNfEPqt1-39q)Lz5ĮwZoT54fa3*‘i 4r\$Y }M:s)6I75C£g!vJfk.:ީޯF-*۲|U ̣}-଼5&$4^m 쾩sQ LƨsA,Y4tJ[PV#eܲ%f Ȫ<0LMRˇ^帟mZ~H ІG!hxf,HHĉg%.Ni{l3o{䑚3|߷Y r^3U#4[l7YG$ yÃ?E'􇅘P 㠑Pе5L ::?nB]痑_!BQNĉFb͗ ;>WXkM)'zM8Wl5tniCbxP4c<:UʼnnP SЬ~<@vIœw|PUuʯH$>7I?3=t7fEǗ 9z8`%٤jVP1PneS:VQR\oS^BgSR&w"-.hY j2 r6n^՟cx2o=98zٲO\=_?8较&;~u9ٴ.5drقrIjrGk22Q(/\*\YqQ%wD|ԹO(&Yng_2=Ĉ!  U^)n :\RPICq7cTeS:rX?s7B\Z#z,"j$W& @# N{U좕+c L?nT00mk}{ȐgI FTo&\J^Z-7й8: ȷmale^V=h+F!;K9!@𖂡$ɻPS/\&0ؿc]eQq>F8XOYL@!cb~&#>=SNS^5% j^C%3aĽH708s`'@I\ԯ><>y %1"غXS:Ϟhp|T]W5\N L)KNQ,bu@Gr[( Ӗ\ V`:T"She')/+kКxCt ],Z?,3m+ͼ(CJﴁ-.C_׀-хeWk.!:1G#MKtkldkF@%ELCȄSVϫ`~E7`(7Z,a\Ր&8(qoˡ@m"\3?TEO`Q:8wywF ?s kdcYd%|~ eTC-X}!N.Md!CSijn>Q>Zc~{M\:R066 v0MV!O{4܁:i6Bp" ?a" 7/Ӵnxf_&;R)V|I^f"L#jLí]eѮڡ8>6 DZM'Cӳڪ u *G s'6[,,@KTC D$eP`Zn x,(8zfW L9B ?H|k C,rȠ![3wHb pA\bs:7K L+ծ.Ņ9E\8m:U&jyn$kOٻrJS+!4QuiyU]q+̯2Q0H~oZp N 3IJ>Jdfls3/ߟ!sm*5aZ\ b>c83Y%, }yɿ{|,3)WM!&#c+8Q['D0Ҫ1?&vCh6AcٍpRuB8Gp 9s~ֲB#2Z֬ 4Y4xzHP/zjd Iɹ1m޼Ιw[-Pv//`/dA{72'>mѫ.=}W~F+N䯙3 4w\"./4md)wD@k)&4kTnv؜+ -M2u%F=ˣ eM% 2[|463ceWcf '%V%lcB#~| ?aˠu! P!75U̸ dY/XD5+ Ux֍3B Դ]=6%G2ZUA z\}@:|nfgio|SJ1ao>k5֏,0!XSr3k jim/8"<$6lZ)^Q1")biK647zX|uovدYf1WXPko`dߊ@9! ''؍=\DOjZ4!޶[HJM3,FiJfondž ;5a /|ͶTr{ ՈK9{ զ` XlgZϓ$a3~)[`N#{#NOSWvDus#{#\\Sf,Ӛ,:p3`kUm@('HԴ@`?CCZS `U)Ұug"l`3J|&}:qt0nuOC盆JmQayn7 vą細]L"-ܺ1'ȥH+PUg`1!M'vsB]UU i'p*bY|4K&MR"Av51hZu_ѐ^ ͍,Y4|1SYr6ɵ=EEBtY;mcF3%:e v1醍!$uI+vf0q*H/7jnm4 A=—tr@[= 4K/A`=@Y/P"Gb7B}f'ELӺ4TVvPFx(Y>sFrzwyU6%vJf5Ԥ)Y}} a-e߁{-FMBQF׹xNxOxS"?-$ǿH34A/Ba#}+!c iN_^EC7Hs'a{< NU0u5r?j;6G?UzN ݛxOmT~Sn#\ t(<6%J`"Ըu-;8WS%SV?eiC c VǓPaʷCmP&/^.x/Mmй1w6hq1kT@:^+JVS Tءw=`#{vpRsWWvozAWfBQP@Nбf稏"9lVDgz"5S.oiD2U2/F־MPcy[ZEbĸyx|R::CI,mhgv'9UdzQVQZL"o͡KZR_ҁ:o2/HDn5H#7rtʜt \Lf,1 r8|]JXE]jeL(@Ѝs蓟8?q 9-b}ùAag+Hfx[* iJLj\jӽ/Swa n=wY,COVm;h.b:1bYɀﭙhy&Mİw_##l1akh^V#aʂg[ *pB s3s')UK1|7j :1 r4LV5]"%ʵKY}iBH 6`mϾѱ36Xܷ7j `mFJhPA(k 0- qrUŷ?.\H1:1x1MkEvW0ynJx6€:2Pz`]|J 8 MQa)EeĻ~#Bxk}L5l\] =megIG `bz}l]S.-"cYsF%΂{ ~V.FӀu Ĺ/yܣ![fo4*[Wńߴw))ĞfYaZ.3줕%kQJ[Hy6_Lp!Q IY͠J';ן;Qշ8 FËYv1N1ՅXx\!B '6IpeR g{v4'X7cjD10$VzC -c5?Xʺ6vU?Z\8 kP7C  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/BaseFonts.properties0000644000175000017500000000160210755336245025346 0ustar twernertwerner# Sample ResourceBundle properties file Courier.file=n022003l.pfb Courier.length=96263 Courier-Bold.file=n022004l.pfb Courier-Bold.length=120373 Courier-BoldOblique.file=n022024l.pfb Courier-BoldOblique.length=114228 Courier-Oblique.file=n022023l.pfb Courier-Oblique.length=101133 Helvetica.file=n019003l.pfb Helvetica.length=68590 Helvetica-Bold.file=n019004l.pfb Helvetica-Bold.length=72400 Helvetica-BoldOblique.file=n019024l.pfb Helvetica-BoldOblique.length=73879 Helvetica-Oblique.file=n019023l.pfb Helvetica-Oblique.length=71719 Times-Roman.file=n021003l.pfb Times-Roman.length=113206 Times-Bold.file=n021004l.pfb Times-Bold.length=108822 Times-BoldItalic.file=n021024l.pfb Times-BoldItalic.length=96211 Times-Italic.file=n021023l.pfb Times-Italic.length=108217 Symbol.file=s050000l.pfb Symbol.length=32213 ZapfDingbats.file=d050000l.pfb ZapfDingbats.length=45955 pdfrenderer-0.9.0/src/com/sun/pdfview/font/res/s050000l.pfb0000644000175000017500000007672510725114532023130 0ustar twernertwernerw%!PS-AdobeFont-1.0: StandardSymL 001.005 %%CreationDate: Wed Aug 3 1994 % Copyright URW Software, Copyright 1994 by URW % URW Software, Copyright 1994 by URW % See the file PUBLIC (Aladdin Free Public License) for license conditions. 11 dict begin /FontInfo 10 dict dup begin /version (001.005) readonly def /Notice (URW Software, Copyright 1994 by URW) readonly def /Copyright (Copyright URW Software, Copyright 1994 by URW) readonly def /FullName (Standard Symbols L) readonly def /FamilyName (Standard Symbols L) readonly def /Weight (Regular) readonly def /ItalicAngle 0.0 def /isFixedPitch false def /UnderlinePosition -229 def /UnderlineThickness 46 def end readonly def /FontName /StandardSymL def /PaintType 0 def /FontBBox {-180 -293 1090 1010} readonly def /FontType 1 def /FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 32 /space put dup 33 /exclam put dup 34 /universal put dup 35 /numbersign put dup 36 /existential put dup 37 /percent put dup 38 /ampersand put dup 39 /suchthat put dup 40 /parenleft put dup 41 /parenright put dup 42 /asteriskmath put dup 43 /plus put dup 44 /comma put dup 45 /minus put dup 46 /period put dup 47 /slash put dup 48 /zero put dup 49 /one put dup 50 /two put dup 51 /three put dup 52 /four put dup 53 /five put dup 54 /six put dup 55 /seven put dup 56 /eight put dup 57 /nine put dup 58 /colon put dup 59 /semicolon put dup 60 /less put dup 61 /equal put dup 62 /greater put dup 63 /question put dup 64 /congruent put dup 65 /Alpha put dup 66 /Beta put dup 67 /Chi put dup 68 /Delta put dup 69 /Epsilon put dup 70 /Phi put dup 71 /Gamma put dup 72 /Eta put dup 73 /Iota put dup 74 /theta1 put dup 75 /Kappa put dup 76 /Lambda put dup 77 /Mu put dup 78 /Nu put dup 79 /Omicron put dup 80 /Pi put dup 81 /Theta put dup 82 /Rho put dup 83 /Sigma put dup 84 /Tau put dup 85 /Upsilon put dup 86 /sigma1 put dup 87 /Omega put dup 88 /Xi put dup 89 /Psi put dup 90 /Zeta put dup 91 /bracketleft put dup 92 /therefore put dup 93 /bracketright put dup 94 /perpendicular put dup 95 /underscore put dup 96 /radicalex put dup 97 /alpha put dup 98 /beta put dup 99 /chi put dup 100 /delta put dup 101 /epsilon put dup 102 /phi put dup 103 /gamma put dup 104 /eta put dup 105 /iota put dup 106 /phi1 put dup 107 /kappa put dup 108 /lambda put dup 109 /mu put dup 110 /nu put dup 111 /omicron put dup 112 /pi put dup 113 /theta put dup 114 /rho put dup 115 /sigma put dup 116 /tau put dup 117 /upsilon put dup 118 /omega1 put dup 119 /omega put dup 120 /xi put dup 121 /psi put dup 122 /zeta put dup 123 /braceleft put dup 124 /bar put dup 125 /braceright put dup 126 /similar put dup 161 /Upsilon1 put dup 162 /minute put dup 163 /lessequal put dup 164 /fraction put dup 165 /infinity put dup 166 /florin put dup 167 /club put dup 168 /diamond put dup 169 /heart put dup 170 /spade put dup 171 /arrowboth put dup 172 /arrowleft put dup 173 /arrowup put dup 174 /arrowright put dup 175 /arrowdown put dup 176 /degree put dup 177 /plusminus put dup 178 /second put dup 179 /greaterequal put dup 180 /multiply put dup 181 /proportional put dup 182 /partialdiff put dup 183 /bullet put dup 184 /divide put dup 185 /notequal put dup 186 /equivalence put dup 187 /approxequal put dup 188 /ellipsis put dup 189 /arrowvertex put dup 190 /arrowhorizex put dup 191 /carriagereturn put dup 192 /aleph put dup 193 /Ifraktur put dup 194 /Rfraktur put dup 195 /weierstrass put dup 196 /circlemultiply put dup 197 /circleplus put dup 198 /emptyset put dup 199 /intersection put dup 200 /union put dup 201 /propersuperset put dup 202 /reflexsuperset put dup 203 /notsubset put dup 204 /propersubset put dup 205 /reflexsubset put dup 206 /element put dup 207 /notelement put dup 208 /angle put dup 209 /gradient put dup 210 /registeredserif put dup 211 /copyrightserif put dup 212 /trademarkserif put dup 213 /product put dup 214 /radical put dup 215 /dotmath put dup 216 /logicalnot put dup 217 /logicaland put dup 218 /logicalor put dup 219 /arrowdblboth put dup 220 /arrowdblleft put dup 221 /arrowdblup put dup 222 /arrowdblright put dup 223 /arrowdbldown put dup 224 /lozenge put dup 225 /angleleft put dup 226 /registeredsans put dup 227 /copyrightsans put dup 228 /trademarksans put dup 229 /summation put dup 230 /parenlefttp put dup 231 /parenleftex put dup 232 /parenleftbt put dup 233 /bracketlefttp put dup 234 /bracketleftex put dup 235 /bracketleftbt put dup 236 /bracelefttp put dup 237 /braceleftmid put dup 238 /bracelefttbt put dup 239 /braceex put dup 241 /angleright put dup 242 /integral put dup 243 /integraltp put dup 244 /integralex put dup 245 /integralbt put dup 246 /parenrighttp put dup 247 /parenrightex put dup 248 /parenrightbt put dup 249 /bracketrighttp put dup 250 /bracketrightex put dup 251 /bracketrightbt put dup 252 /bracerighttp put dup 253 /bracerightmid put dup 254 /bracerightbt put readonly def /UniqueID 5021339 def currentdict end currentfile eexec 6h `,i"[[5j5mTʻ^+݄fKitrޟm%9۩*++`[&NfA-O!J"|UY+; <Ԟ2?.P2QhnDtw=y0)n*[ Y]~ ΁RzYi[AXmv$zq }V]- l8 QЇ ʜ5R+ rMMdjM x0}"UC¡u#vL"BX=̆PNhX&B`î$+a!c$7^EyQ&be@Dm?f_f0D-A)+E@fklR3Z*qhy4! c-97)ʟ!ԛȪ-ZdJ4/&EhU^{.c9B`W{ZXE7fiBDH7/2?}W%^R & 뱘|D1UNXXŮح㘼Fѽg`|h]TAߡ[btFOUmk"ʖ&E* Y:Aaw 5:pk=P&\X]Vےss&S'B4fI@l͚T(|$܍Ǘ[FJZP &Nwh֋'"Lhp(kpr>|v$YYlSZxRŶ%l򁱺?#dg *U\jP]lbq%Z okژIza'hl_I=TZRZtm1[@Sf'ÿ*da~iCt bɉl߈W+1]4p[Ո j[:}pPHM%!/~D{ұSZŎnhwR8k szosJ@wBA3-z=XJeO =Պ11=ՎPIJ4TGrz>PKYLJ4@Ly>&y$tnCu~xĠm*۱ VxWnA(9f*Mljiyci^q^Ԛ44ھO\s\6 ęq|_믑g7ɕhԕM.6~DO3% l!iߛ=T{ߕ(G2/!na1Wt4]`c=ێ#9i5dZU8`<ʸS79n:s77uϖx;ӳw;A$~v.o?"ҏmD@Hɵx8{6``A^) ʽ02|6͟=ۓe%Q+^* ;p6xߚ:l-AaL vBm8_RhouTӵ xfh3 eEbَfʾo>r͉׀m*L{'¢J#Q^X;]Opߥ"t2z*0M~ :&V4@Շwyz2Wy{%mk.)1d &-c ~4)c& :a?> abM \xVO-́GXq:<Џ$jW)Thk.FtyJ#:i$ r2!l'H0͟ ow>a{zA fs72b ?4S>l,3~LU?dϾ٩=dމmڪ_z%;AI§tn>̑3NQ(`t6͂,%^m糟j v9GN:\t_9XE=T~]IPr%`E/{.^Vsx^L^ ѧ#J_%زݖ\v^Z"3-r,]°e8 (O7TJRݜ̓q;x/`B Ø\%n^Y,aON>rS}J׌w5k:%&LDG%P|%ݒQ`_MD4h$y`g$QW3sF#CVba@?lBт-'"G@M~j`[FDE+rTWWFuM;NaZ G^4ߍtUnG,ٗV0y7s$yyGR{b_HKWjYճ{l:c8 3\C-ڀ6ZthCܶG64 E4!+B)0JGa \ao鱒Ȼ0?Ʃd(zRrbW#Q7^{OK;`*@A ^ȘcKqDL~f>feAp dB`wyVbc?/J:LIT="~Z)x~IucUEyؾ`qM"]&s+DLohFv_Q6UxT{̐;rIU/a ڜ 𞯪9d?lg= 0ꚕGaqެ b] SC+vxeuea)bhP(ݍ*t4?/250H#j*`G?׭ƍXwt1L?ۏ.Cq&#Z^}({N|qW*(LאkdLk'GM-oC;L-qљr@u+J"9*=Gt&ZhnѦ A W}1.TY($uz½ diK4znu!d^8,[:! |wLS.,kK*b$_𙰠^3&)>ɓ%7uBE~&L8l}G1<0=fwD ݭ:.Ú/CU-I+*pqXfMNղjF)347Ȣ'WAF"j-3ƇAv5{mB1 liؔe{D̥ U"k= |;>I0mM;N5bhW2%}y)W/ ,H zI tAb6uI|Qp|X3=ȓRV CO'c'/!a4<]ѕX"wz/*7푵K%M%@70w"p˳k>&؅ $֪>t@-] :녱ӍӋװLjmC_qTR"M]wtd6U#=πz,܎Av~±7|2믊>Qc=1@kU I_3T_#gJ"!UU(l^8`+NJx;V7 qX>F:|oIj n *r*"y]>6Iwˍ2r6s<5cs5DhRZ 1H~Nl7,a6Q<IGF5 :'f%v8@fB4`aC {_\eHw~݂fga*~P|+eُ@U5&#+'A ޚ<߆yCA+|kK$ԯ3g,xkZh*qa'^ଐ!Ph+~՝K/HGo*f "ko Zϕ9;ET#fR xLKֻP.c! N $Q[򈲔1EL ^vw-P3ӦdD{o#<d M%0ԝ& zqB oϬrѠ;߰|>g 9xXkfYiyLnزKV9-3UR1Po1(oRYpb `e)"cgf ~ R>{zޙkbB̥s")/{=]@o']]2 qD{])L"./t 7Uc&.Ts^i@oф7Il6v]>9%Y'l#\:X%_yM:V6.zMYD4i俆ٍ۩!e2}kZFu?`5tLF!NK$V$}궘 WJךAAtWK *bL#& Ƈ͟U )ׂ& omf9(USfG! =IRoP\Y?+8. {:2ue#;B[1- =c6ð/1F&6D0}+T^ޥk LHHu^(PwO;J&6J7G~}X$+RO~ȭѠH11umۮti`M1PS.}NL.8m3(qUkt#J a321=AS=I9q:$qfj-t^8E2}+#*NMd\jp2-ݳmB$EUi=Wƙ$:aGL wٽZT$ɒ &;7BwMƚ ۟Tw s(OL:3,^oloΓtm#zO5[ڢcV0Bh3X8d2ytyﭕA3lJiGr|VX"~ګsFZ}"ُ>KKDn w`=fN.`QQ4Dh>n:iK!{з>ͷdKW,!M_k_eQK|gC.-. à)fiqb^L$; ygkmbXcJA%f΋i-~t0e&13 a,?E7|=hP=rϖbLSLS&Ff5\@V{#h_F)O:_Xrf4Z{xvL;xqsj>I\,b1L P?*+ÜWPW\:Č3ϋђ" @2)߁*?_,k]s1CَWދäU6Z=m\# k)lLLcM5M¨ė|CQQ{nǓ?P $|#k֜,Vd&:!^۰/MAGs?\3CJ)J}R֫yNƟe NitTA8^C=ߴ@߭!Ǣ!rHYґjf&l7jP8ut 9)Q$ Q4Xz9G<h e΄ ߰ :SU>: 4Oܘ*jAPN7Gc Zޥ1n2b%8rţ._qPgػ9+:ArF:}YUeXƩ"-P/eER:9VȘ99Ѽ}2:уHޮwY:H =Xeru=\%.Bd \ UV%)W./TMWS9+g ,9]WϿF$1b6*:>+GྏA8Qqsq2z-Y`MDGMFt7/)rX Am6:VHN$2]){^(JD8fƓkQX;<s9CO~zP޻5 Sc`®5N(ǐ=`X {tLvJ[^djV,~<ìy68q=|>מEUlfɠ$tÛJUp \A!÷GOxi k{cIDS"-; HZbzn;x/aH _6s3Hʹj[pu@E/]Yn_ (-X,i/X~ χRBλ837z2jl{ةTX=Kߺi`lűUmU_S1wcOͣ e1ö7NO-g?rP%T?PȃT,ζ y eh@ŵn"@rq :\\11r(bij2,2ъVVVѴ6:%}pIuUըdB:@.#+'&E~6vR[- qr&cP.8 ^!$ Z&U͖" .;h![c bwOT !ek4c<<_ɗfvO ._*p?aIR^X.6(TMf^h.=-<}S{5LX`.F?{=ToMϟOGw_9 tc:R@k܁\BZ#\P ϛ80 #ha?p#T+ietާ]I( ^]o_gjcTC_\3z x'tu<}0(ľFiFZw/\)M(TlmѪIqUYW!|M;`oE-;hI_CӉB?mV} UDIH"'\75e)9ӇKѰ’Sd^T>28^T2*+iL 43_Ɍ -xlѩKDq"iJlm&\ލmp{6Hj/; j4HW)pᓬ_?jc>w`[&/P"'1&9uRm&Tҷ{c=hE\-NĐ'6$LuSZ iv-y^9)qbaޣ瀭YnMb6Q;2|M`5پ z:_㫐{!OZȌ rB咘^s;ğ_+k΋FcV4_+yR_ʔ4\0ѵ̷yž}~0kw0k= KVC\ntI-YB+ wg9umGuv7,JLf3+Y#HtfA'xmţY; 0ԀDiV=,CgU3jveYO鮈~<2l`o Ex.!S>@ Cn{$.z I}i[8i2;z]eĄnOHKMΊ&>Ցo8 `^9A U?_ L۬; 뮜`Ksj -m'!!|2\)yOͶPI:oG=5jKݸlXcR2S:(9A+ĞzD+[)J}8C,6`?Gp}N,Dͳ<^*wnب x{8*ƈYʕ5\X#d:97eeIړG:'vյ^2ifh";=q3Ͻso1s<[CR$>Q~>$] >򺐼 T+OD$flGDټ!2(beRO`GuuȆ0r[ȁUe-&kǒHV@j/J(r͸f_ EN]FbveϋYl;i$L"x^#e.\!M$TБCwۀrC ֋)j+]DՉgЍ=|( .pʍZ##hB$!MMztBsMoJn-1rmPXFs*UAӈ}`b*ԃ *bF@ ʦj,ۙ䨵!K8Bjґx2$DTtr@u&q%QA: wj"DKޘdoyb3s(7ccLҵ%|+p"%V,vU%,ӊy[;]s8/(*2>c3ʱ9É`H45P5:YBGn'6BgSc3=a9(#I7y@Qbqbq,Cë r̛pCCzTܬzQ-F̿O%قR Vh瑽@Wgq*nJi}`ڰzFɡk+] a uU$ -|2icfD;\S&J0c GYiUt~VWTA;,M9 Nh9Kelo`F-;Z "Fa5d_ReQ0DAf; /emƒt-)ec%%,zEsr%[0A)ւdDg;g* 3|| 6fYEFXT_ebӈ:6e +ObFOϿG07U\m1~蓃P(Phi_P{%RV Z;/i1(N/0 X{q\%FpIdT>k?.`=H}W e \a,c /u!!UQ0 \iY .8(mvxQ{GA72M]Iឝ#J'6.t8<bix*C\UI !b r'7;[4WUYV#wL ӌoM^( 9fEEhpg{vĕ3&ßv{2iJ J|RR}R(0T@)V>{Cheb6:'#f n%7-$D_ jf9`dW3-)Ӏ.]B5 ) 2*мz@R↞ Ƭ;h=s_wnsᖥ@DZp$C ˁ3h Ƕ  aRJ\e;M0=1k)g &|z](sFS!bQOﱠĬbVM *_4,UE ߇؁ʉR?[?i x)Dq1HYU=5:~L-T~k6r&Ě}xQhwvPɕ\Qb%O\O^,$wVQIb5NTVqzZnu1ܩ[!b߹`ė 1 ߾pn^~ WS"OP( Ug2MUlӁihh3C_Tҍ"A3H߮qjW-Qѧ ୐Eo4˜󜶾ԫ5cޘN˥7~я_7K9T,j…C)& aδ`ʴX@n {#t[{t5'j&2L iEbýEq~$]v<,`ه8L"ƜOxRcl - q".=t ߮ =3`FnNS0+4|@ơy)@kuǁ-X6o؄ЯYn]fB޶u@Mg ! ]c*Ҋ!2xBo&ВHU3$l =/8⇴NbVWPoE~d΄W2Ɇ_=ln빀u* h.OGyu_z[?]kgw˼6~[]E{l*ۯn}Zk03ըCenZ*6T2%`0 B]xI{@-q_a@1:NQ`:ϯH_q1/.ߔeu([kW.Yx3^fTx0(dU<6O!S}I6|<\/oU]Cnnsgv pϑb[Z}%ܒsJ9>9UT(8w7c@D: ѩ:>@#39St$~a,3/mB\2?ѵWn(fJ|b  @L*ŊڧB& S&*/Va۶_Δy#M(H@ &cZ0d%I lj0.>9ӣjW7u~S*,^L.SWam5z95;iۊ1Q}'6c/z63r&}Ҁ&[ho$& wT143e]VQCT ?heYVbBFL( 9xLdKʊ7h]ERK}z8l1 Xhqk<a(6`YUtw.'$gy'M؛`y<,J$xqxSz^K:ԁoʄeL,H>:1t p&<ӏo4w8D7P:}MEG#fm5Olvx򷇴ȔW~dtqs-W]ˣ/0=*p,y Ŕe:Hw L+lCM(}O10FZv*{tLzh"\|1Z{[^< ^}.֨*Ż#Jx^}d >gbWû) BcXwlkw4~*_%Y &$s2ծT[MM -+0j[m~zXcoޠ2tpc;<"d~1lm@v=:ZĘ*8& H˒}( [f-8TvI@Wi_U/ 9yFZe <@Fss4ƨiae3NfI"/lmֶh(f\?~Bqy E/Vq~R/S Qbr$O).J昪-o;'Զ)Lu9)+ZH/e1dGbOЕ 1#d(=q\_ 6H{IEp-Cs(c|o?Džhz]!BѼ$ 1?ۡ'ΫC,Z( 1g٢u`n+w{,1D]zco0xR>Bū=_ 2>ݬv WGi *|Bh0Q- F0}JEzo+uD *0*!ZmG_uTo8=(\|`J" TU|I_@3uoXEeY$FuKdPI6sRl~T3?R(R-h UO'IV%b1\w__W`qɼwo!,$d8e}yiβ#dbR'VrF^(*R0KYnde+6qMY7 >sXɜf:$ש;'aþ,?M9<.0}qęu[3YtX^drMH[h}F9Jm 5붿u`IO.{6HJ(QjRh98nTMHhga-xta FBcu y]-8y04{Vcn`Ҕu}^2}BKܻn*ƉBW-w {cNltmuB1vH7Bܞd0-$%X3ɕ߹7hw*T ~+dS3ʌY!za5oi-E5h d szz<=rFk:ڪĉRNv4lw2 T0ػEuAdn]%1iǖ]g6hdž {ʳYqI'61S.7RTe=P''iH+#DAcI< _JU 漜D_Vٺ^3G1z,(z \awwʅ녱|U#?0`e0b"1ZD8pY# Ņ5XgG8 2'u|k5n$$J^k`Mk<뾿\wImdqnװ( jR- `P,W$0cq7zQܿIa s~FKudB+㇆Tdd[Bw*Vf?tA(d]:8&3$%:Rm(=ZmP/nUAs.oK+gr{zG?cBf΀saKRQJw?̙H)][l,dnp ^6D&^AMn |aÛi97/ˑ&p"o8!l|[~Z$Sj_eRUJa|{ [zXu _#l8(O >֭_pt?.01;݃̋4~&,DޅC,ɩt{b)J<6>rt ?/цhh:dpܵ<EkDW%s&.:[ 6X߸U8_ bZ7Sȧ2tHNg'µ48ܩ=X¤1.652#&?tؽH'&lD D)Xl8%&ZddMZX!rZ ,Í1puae[};'̲NCNy8H#U¢O7Nכ0?IeY=ˋYI0#cM)TkʁW5#T$ʜIP 1Y։ (q7vtJ2#B1Vd㨏|yfE/~(7h~jN[: w%.:VB:$(Fz6 1Nv]<`V;jL,NmT`az*»bH!..ҩx7WI"끎CTsV|3:>FJaJ+{{?ap/xSXk8Gz*,k+ okdS;KGkIp5B$|5&ߏD3uUԟCJmFKrA2ńu xQ7804Dk b P0ᖋWDђ㰯$E|O}2 @VW}1`1w%/ldY؞􊁸H>y2.P}걢ɑ]DXtLs/yn{ mZM2[פ/2-) h^P0l5tڣ1]Y rF 3tJo]yߙU,l,452䈣RBPS$wG[d^48S8H٨DG#s(k(ٴs(#ߒ]NS?R‰Yn#{?p0lZY$;ate~|su˲ncS[ޠm|<Л vS). z"`EȣIEMݿ>Wo]yӤbV4JbP"<+@70 >'r~\]Q,>7ʈ䚍S,8s.4׳c%xyg+j|P]TB_sT{cꇹw9r<)cŅ!i5?xS -oV'A9-wuKDB?(+ d7̧3I@ś8du6yD\l ZT򟅭(,}x\o)Nr#KDjXH,&UysoCJU_)K] ywIYZ\/@ڨ'vBOyBpƺ~DɎQ OY~ Q\Ta5sR~D&V19#}9Dz==('Kȅf|8(`1y+M^f5o70dFHCHr9 笇3b?hŢ%S_tC8@Ae" i~<%&񖢤'%,zrhy]#ɒ4ISǎ@} UϮƒ7Cqä^1٢s>^Z氄E cյFs uyR%&o5π9Kǝ ^Ę~̨ sfE>HSÏNI7j}BDv>S: l޵hȟAU5 {毗ִB.EU)YPN:x-4 `%[׌=tPRoF8nwZ|864u,GՖzB+ gz|H u1iJ ĺYCm1 R~_XM0f jHWSyX+Boq=IeJXU adn&˖2 ,tTOߕ_$#W47{|8s<]rڞFy< "aЦ~@8i 0NJfĉ;GĜ_`aC_*IgZ'Xg+}_Hz'Bݙ/"'U0h8;SwG`_q} 뻠0nkrPfbsOW'X-ViD n6sm,,a&"yjVȂ0ni`MR #5#Gp=C (3?Z")9xV[l 5TtwdXvM *wȜa$ZG+PPJ`> }eR99G=n{ӞLI N=~YNx枎eh5q_cN,h{~d}HmV-IWLgږ)V7뀬܎G@R=`vGkhOJyE0FɎS T33΍湏/ {.)6 rʪ\^s&uHqzuH%Dlx*sD R`LD9"[>w+?8&1 $` .NEF轷*&AJ;"7[^1/" &cyh>tWϞ{F~^y$#:7&iT,0o ;Ic֕qh6x瘉J ٗv0I&WK̖߲\X?I!8!M4Ȭ4CPml,Ʋ^s?ω')c 98xSM_;]qM^%r:,gg ~Q2@8x:+_FgV߼n3B}2;Hb𡑚}^|{!Fwe= 0`JMF[ly&_d5_(#,/]"ώە%*/JY?4"t?Es.<*pRlAm" V (P3諥S.ޝs+;IQoĜR5\ 2p&- Jֻ^/? rL:GgI!3XGPQ&È~gԻ== lJa9OX`bdY;{pHӍp2&1^rgJ%}>,`BYe"G#EWEmyӱ<|`τ&̴q(b[V;!~_ӭ7wA~))PߕR8X.$#~%2llT<4qZ2p>r2F j`O` Pڭ~c"i>$G֖=2? +YF |٩!HXIg8q*C?)VZjv8 l^su5q`1X "("`*`A'WDm% L*J':ioT @j>޽f1-!(1{W[amA?x 2$N[s^.6R WJf|H\<%'F;WYVt'ĵQa}v{ݵuxM6/Z"ݤ"(ye^:ߋ󚣌moUJ RlܬEdxz`+YyHUPg烜yF}]8v-q|e(֋R\ց;磥 (9h?Kuf74&킝͛k=%-)^?7BF_d$e88GZ@̾jH@U?R<@PbμsT䃸bA[=[R:w^@bD3Kі_QKa$Y_!GO?PfG3:x)}*CVOTaځDO8DIEٜy" <#$5(h2Kj" Za/}sCPm](zVۨ#T満!FׇW$: lB#'FE8{ff-k":FJFN,x(TLH71 p8RxGkGi /F -z>6 3ڲd\[.;ugdٮ"7ETR4D+x-VP媁ӚOņ}d @8T"/u٩JSfK_m"2ۤ{8`|{R,l}W…?C~3*: ,x z b(:3npfjm?(( rWj$kZ?Wž-)k nL3T?5K2ޞ)Oekrq&9@/4FZAN;SSb +sQ*N,*ϧ+L@Dxٱvhks+y./Q DI΁!djR7IU]enw1Pp'Vgv2bX,% ygU%‰}RVV! /o:bڣ$#K5ie\4]ڿJ,7c&•n@9v烿UwۑQ,D7ꕝ߾H͠btmXIF` N0]dwr[6Qa>DV7mHOyhJpW?29k)rS3xCKU[3uWQUR*d7\+Yι3'p PXϦ UY+ٵFmOqTab4s̺ dC&wث+7XSI}_f&X7ed[HN.y>41d*-~eg6,\Smh86291!Ⱦx[y$:e7,<PGA;1}9>dn!ɵX ͘?EU Sgh=c\ b'qk5of#bUHXחu-$yCKa ZLJGẄ́~ 0}3G ' /]I.:\(?uwuV1Bugm+Թz6ÅKMY^J|\?lѨԠ@~lSK ]r]!1!ppį āLybm Bi OtehH i))k|[c>fWO~\c֗X)PȪ>{&V 4H V&Ӫ lc$hvC$==;z3Xj>\}D[AH buMebZ_Aۮk~^̅bRY,dPu>†*:'$aqtx’ŻAK4`:_Q_l=>lx4I; % nD)-4ȪXsAV/ Կ].>;T #'Z֡J~*  f6. gr9аZT1,tXSa3M;*j(lSD0y%l&]FS<p&\BcVshM9 ^< 3!T g-WjJ9KjO4ݴqL2}{kV*iqO~|p&5˕ L8P .$؝-GG%C`V6ҼK-ӷ|pQi@m`Dͥ :q4,S3rҾ0`IL3''\GSDb[L/2K UѸЯ 6+][eZMrMoeҗ2FG\iWI0-᭫ڎ59_ ~I9][/aUǯr ݫWlƇl-Y.^b8cpvN tf> -7#z-7ꯓVz 'ߋIH//Jm`©U\&ǟfJ \c9?hUQ1Qc]Ax9m{  1渿v]I~P?R`4&H||΢x:5(r /, yqq/j NK .ZSn@ F~4bgxom&,4ºp,Z*5=Es ;jZ*x< |ټyPP>,gģ" +xY})%ŧ$֌$4':UС8ag' sBh _߶zgl툖^18 '{~N&=͐ПYw)uǩwimx{\ojaԵPNAjH& ,nU{u>akH/s75'渽NX@A#W“5<(I%0so7\q߁ū5*ITbA| b}_PCY` H(ƨom^l\6qD!jp{sDZZ6,VSaB3{{c)K!)#,IOSp?TEfHJ0 n|[(U`Yû 3`٫qK!V_m)( vkn&P_wQ4  +Jdƅڸ.>麾u"Jq07`> m?AM-9W1~Uϱ-bTna.Yyп.os 6#lVNc|Z7{B69&6òMMHmTʝnP¾ovw)1,̈"W :zH|hvYʳ5Jf|tSpaph9dMG[By wuN[O"tâ&l 0Oq$[A,ސ\oa g@}U#'tkR"Š,O<T!  VYi;/,\bQ'>_3 |^M'xhl^Ws}wDh#]6E`x\ZݵgDW,ճ{ ɁN&ް0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark pdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n019004l.pfb0000644000175000017500000021532010725114532023116 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusSanL-Bold 1.06 %%Title: NimbusSanL-Bold %%CreationDate: Tue Dec 31 16:51:23 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusSanL-Bold % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusSanL-Bold known{/NimbusSanL-Bold findfont dup/UniqueID known{dup /UniqueID get 5020904 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusSanL-Bold def /FontBBox [-173 -307 1097 979 ]readonly def /UniqueID 5020904 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Sans L Bold) readonly def /FamilyName (Nimbus Sans L) readonly def /Weight (Bold) readonly def /FSType 0 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -155 def /UnderlineThickness 69 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec fc8bA)5$%q/0\=CAFܣ,W)yڲWJ&{ZL`>!Wd SpԲėAG$|f>97&zIɆkG['EJ5q2=]LHلYUz%ٖ!H)!H<^7E#lbbJ~}:ߢE T?*b(:8)wyA0 ; o.тF$x5s{2(vf:xzC\ӛ_Ɋ25s *JJz67Jmkf,M8͜ `;w V=\Tl"WA}} 9j^VY|JV?Zhknq(#p|k_arQŇmMLK Y g sB%[(}Kɦ n$v)5n-k@J{ V`!ʊ[iQO @j8a ]ۚ8v_R![27fN!q6}s/-}@Yvr7TE)mk$vR-)O4A&sُ !4ܧAڂvمW6[*ls3/|Y.b1Od*JPT:,[T_s ӯȖP-_)ީTrt4I(y3$ k%˼u%-ɭM LMu+Tqo WwON_H]Qizہ *u]/a@->fEN%#D8QtSe;9:w.aL&g R>NT5K̄?&H{YћDZ/6!ȆHz/o_0Qu#ce;9d8/Q`aMN!Ǵ8OJ5M`^Xz1q3e*6XmHPGڥv!1.CUG8 vjh՞6Z~=48X0VOJN{SH%XzMKjMQ37!34?"`F edz) ͢Ȅ鎫ֵfZ4֙N`S[ܷ-KX*ÃOȮl1{GB5F'U9ڬ(VS^ DMzmU+34Q"j?Aj6+Z(oU~#i]:3k=_9,t,АRTMMKɰstskw+_4-Enajr[Ѿy"kC=F7wD9?UIAFASF8-J/Xb|e[hͬ ηV;-MK6\θf#BfD Yiasz4嘾>|;`Q#mrS/g]MpCw"!g,A 0>,SJA sHq9U'B#߹ ZβRݏxG :+:ƕ >9 `0a8<^Qb>$Bnw+p$+l$ ŀJX.>}}DgV=*)Q 1M"8 z!4Cfwy 3bN|XUT:Z:b3߈ǵ\M$LG YDO;~KD,=O*-n;m'*iMB~5+gUa^TdyQz&zRa`&RY^IvfΤnƝx?&1eê wwOS~Jk";{Ub~<-et~޼FW1m,])Σ1͓>TCNՠo4"C'fƶmO ~YKC7;IQqOEsD<)Q7cO1?w'ޔ;@dO/_kθFc70$t ba^sqI6݆ pur$㢄Bߗqj"1đ 1hlpsK9/a`o$Bh[TPWHYz'iv:lJԯRz$^,ʜRg6n-vf* /%xy 1jQPzeǭ秤wM3Nf!1 ԋvWˢP|`: XOE{E8ji)m6]Q|3Y N !c}Ij|Jru ?)CЍtzkz, :N`%>4"-(p#pmB\d7ѲL}mߞCe JK'#AL!W%/PlzF dф`=iU% 3lE.5,z[ef$2;Bk)OԏmFBVYl2n_I Y>tM#Bz\t[ iN]ڋ!R ~ D3xچ$F8Sc+Svh #?X~1Y¾X@{ r _O+6y!b-GqBd;]j춟]n@k(QGMW;h$^T8p<Bl)t"rWg{]roMJ8 _\n8T]9]#@ff;sL;|x  bwʏ7c;l*s EԤ:!CD6 DNM\ ]1Psc:=. '-HX)dDy5]/j G*{v+iV檇ZBta*Er2:F|%{R܃Ƌ5^<*s[R ΰ6c)9}9+vW@Lg (? OCE/$ț?d&rxH`࣒D2? Xn(aF$JRe mLqƆrpf3e%اGUJG):ߨO]4CtGZ-Jg.R&"ec]%F5&[ Sd;]GdN}*`Kx/ĥpd 2y=j{Vs&B">BM}42j_Rxx`sۀv nÆm)/1Lz;!VOv9]( $msuFQĶꁷJh37=ˑn[𳢮ӠRZ w9Ek++KTd[+,ADàhi7 P\$;ts=tG7}2Rm 6T)62rEDEVcqHB/Yي@v3 r 9D}L]v%fSVHp;>]͂&R; mVKKfܝ1^ɷ7]YZJJHra19?V悕 "Cv9+ SC!$gh*foR$7RWyoB#lo} =_u!\.R0|m|/R $߻AHF؈NVIo`sE=3.(Sbysv(kȐ>d`,ҿ3|@8U>-4<>mvTϓg~E-aASoupF}.[ `Y׳x-U39Cm@ |07dX*_sLҪ-K\s6Q.>FI} PF?O[t'lLpg.%f l)83biÎTT!i`e)CTO~WqgJ+e5Zԓ-"@G:)X9(NHpM6d,I ?}>0MWez%@ӹua =mL(PSpk Bǭn"m")|EODXs&#_gT0 wtahU #n̹dZSCեxAD r|y!aO8vu)Sם׻8hvE8KS]8CБA;^W2{ppz0XEώz,4[J%/oɰ]ߚ[_%uzzefK<% ݕJO^n ƄheKdb(n_eyчD:Y8BM?LEN7w͉6joi!-98 y~8yn7iI!U{ar`,#StlM9qa4sOWesnC#G6B3>-LdQti2I ڧ G⼪k:ElrSSԘt)OPQm^56 NtՇِ*܌[FÚZۼ 9^iBR)aOSXH *j <6ep] n3uݮ hn& > om͙>QY|!uLধĞ -<2g-xk~^[-ɹ-lҡKt42նѣjʎٶܭTX)Rfś<)UQ䟘M sF$ jآ|j.v>ce@}>bY;|F?LH5ML.Z]HgtzCm݈+m%}=bW ~ډ)w#}1\Wމ$tX VJV4KVlk/r[Nځtfk2g0-: 箔jd akSW2j;l^AWE%d*.rȒR֣L}q*C97 L-\cop]#Zno{mpf} 3 io 9BNSG8+(Hoo1MS)৓IӪF1}eC|ܿMo 9uA Q"Y}eK⌾yxqш\(s}+*nf}Hq;ikdMǠءN)AT&𙚶\-o,ćeݲܝ'l8S5!¢Y1))3#9?ne.:KnȸoF 8Qf΢Nhϼ-ϐ(-F*RutnͰAiPxE_"~a>#q]7\F=h@N-*aΨD#߳[.И4& qF[#凤eq%O6bB"387VJO6o H#=ݔ!xRhmbN*t]ԓV?Q@ǽ# _C/1Ë<?\*1!YZX[K+?W.j7r.0F8wlhNĀ$j>cA5 RM+.q5dߺߎ^ґoAy^G{,Q%{"ow3gIH8v3˦1 %rMl"씖_tU (`kXx~ʓ@qnpH".4d兴Ʃ(0'6Yf, Jd|EPOC*9[(w{huakL*mZIκfO)7X$FâE~`dtEte}yP~ S;:M!RX7#脭xJM 'G *?v}4ZUZFf\_ k݉7el<.Ĥ> Վ<S.N:v.Bfbg)A\T^Lk.eЦw[bX(^₩ ͋H 7m |N $Rx<6P+9a]6 h#)xA]8&.7kY>9!I["MúF׆I? | ^PcJKl&][yzs/u(:,qJ@XÆ)4A%b(Lוs"e'hƪ+хڸR!e^Z 诌\gR]@ M@ir/2CK並KhAY> 5 +'Rbe`` ][/5J*UzCe$z1@?5X=S;ٟxo yC|qe[z9^x5= 麺Ζ"mcߵ(MtmOxL,CDV X~g<^w0&$@ 72ߒIyI~OH>k.6Q/zEÞtH/>åUQ]x?Yba+ {vs˃-91->3Lˆ^SgmOxg#oS~Et܆$U)s M^ oĠ},jHcW\XY%?fɦ Z³E;y^Z07{231;m8O/x#?.YCvEL~l(f*Judljx@E(Δ "Dtn6$JyrM+ GbW @8a ǏU% pbQQBn Wc[ԣ:8LC6l/q1Rsզ{o^Q*읔UV7iӶcs3tD9HFuC+A_RS"T>X65AqtNaa4 ћ<5J_ɢwz |WM^ TnGeN:buh[?-bE]gQ!֫wvsZ4gqӯ(uhf=g!%c` ) G[4ns?ST|coWeGREfk\=Tz^^s-"p:! Yzs lA)093nrf( d% Aq3㊮FMWŔ HC}s\HObІe Wu@A!um̀S=,KsYS+TsEQɴX;׫TJFA)kU.QʞGBFC(vl {9E{8[bK*o&͸if+L u|@~7%0zAϽQBβ'ÿxs +|h]ʺ JHwLhvCfۺvp-dU:jF2 FRe&FCo,m !Kv-d5) ؕ&Pq6%Fr ĭU:0>8َNNNCϲPb.@A"՛׫EL-x}G,?Gho m9 IzHLM:+G5JHq;HtY1E~,&&Cmqbu̼6i9*T]^DE4B2kR LYJ(dJ](Q#NJ'\=2݊)]{ NzYd1Z<.j>{82$,( z*PXAc3*\*'4*;9|:^Kn鞳GJ|wA}9N Jα#Chϰ>X%:#8(@ hCf=Xe1|:,L XqG.}&mX w;2Rz:[C^;!DE:x=PDy'} sa]eդ9i]DD-x}IF-|lzKN3RA(Z x]c*cwL@)|unUԹePq-@4eC|QMɦ^qj;#Kb"S7%s!fʋVK.+5"4L춞 Kh3~ľ^bk#%e˫5"5|E7Z`7H\t-ϺMvYq  b,W5ܖbv2،6Ac^IY)df7?TmY֢]܂O(f[x>mDԲ%,˂ $׭"`ehYBp#(h^pؼqs8[V閏5vEv U 3"$M"F9uKpg~{kwqDf b ?{°Ez\,K*NLo&^ߒHmUဲaB "@#sX]A3R3_|/hgxeε]aUy*g!?…*hTRzAw(h s[f ֕ܬLi_sPiy^VHvxV}dž(+ol;SlQfnr??W;L3dDEє'jÔw@w{F=<ѳ^80C%ꈧ6+pi[~ɢqjrpg(qҒ[[b9z6AJ`Dj \T D9.ڨxI+ۇQewD[> $]qZ~B,m_88&Ң3(,Vezr-SVC |Ut-B^En\VSj U[5ީO.WHL <-&m\UphˇpNuCCoAUiIc K˕/8LE;\;NszrE\~Cs)Yu%/[BYq !-v)Tk4x30h2F෯9Qn<5DVՊ_03>40>Ԭ} {&er߂Q}ZvK9$-%6[@mYٌr9p@B߁d>V7 R^"<[Z8 ]4>+sZ߹ +FK#KV{r,eIE'H؈PQ_ <"LNbž;gi QGyvZS,mQÑA2W\ݽ$3 ;x:ϒ'@Lf%;P&glK\P*Q8B\i'K g[fҷ^.W Dx+*aGެnyL_֊Nӫtdߋ7VuޙKɐ'!ǹqc>ޱ: uC e]ד17O/k+9!Bg9MF=-Gr~-$=ގ5p\T)A¯Dr= =:t~%oǮMc |3?6C/gˤ/hGHvjA T*s3F8:?x>FS|afz{j?V#-F~fF4C(h+C5yg0O]蘖~4A Mi.}3Zä=#WnA.3ZL,OSIW\T-\Ҏvp)˗eҋFgpV;' џ?.g#@ا?αسѥҕܞ _aJЉHt0I I'Hd-}@EfKW[(J>1o BtR丵Bz.ߛCgb d2 *Ӧ&GY֕lcKUbդI&mgIA5!%0 `u]?39+Nng,6юe15z#vraTl~ZjoעjL#Gx (;%;g d#C*uh>A ʹzaZ{+! Nl"xĮ"Á&/w'|CMt6qXg/$qlS k(߻<=ibu2Q,mXkIX2ɒGdͥ.V49in8fM7Ӳ:d:3@\v #2HU9ӼJi ^!/}h4CD@c#W d&T:qtOr⧈d|.UOX͛_^MԾ4$6.WY>7̾؆a!쀯ZY2u|=A/2P (gҮVt &7|8pXzmiX2H!|W cѭ}0=UwՈdl7 y|4[-0!l :ъl Pz}QO,Ltb]pZD|#*7K:/|@j,hhk.*A;p uy1Z;~IMpL gΓ51_y"gVbp {*lȬ'Acm ^ATj0gBrW5R ţ:~ &wDn9L$6#O2/XNul)DK3.`M*A=D]qD%by~/T x>4^! CԈ1<xZʚ2wqbnhseݐb2hO%“Ⱦ_^M=\ Z/r76)uB"|ՌPPf>>SIv7"c>;L;p+ F]TvA*M:rOs 5B~9] qTu~Sg?Q@(X3Zfzi}1Lm[FbSLJ8B0RMV{]ꩼ%ҾzJHˠZ`#qyEh2a{Z|-ϖd0ݾ$ʘ+IVHlib Pc`nPZ:Yxcoo _J vj;WRvYRQk[LJ;GByrVqwÕ[bE_XF fPyϫ~AnB[ܜڊξnjWmϕ 1Q>ZjJqaNk+MDwK=S#-;ˋ}P0>+&~QpɳM]d庪qE4˦YDOAtJf}u1@bGGyc鞍p#ŵ]| '_#j!ךxeѝ-{%u\<7M0@f@Ja^AJ|L ,XsGcʬ\ZeLNЙ,̜WVZܓ.-9,lFd ^|t}9DPVVϲ\:8MkM.[_RlAf˹~|@  K_ MRN 8`hzEfR+qd-'WXڻumә1W3͆עN\n,Z>m4HFfseݶS*0[mk-uN"LCa%gOߛ[K%JݺrޯKr_J !Gl$`Tpayؖa  ܠK?muVwd](03H11&AwU.%( d]cF`OڪR%lEjM .mte@nݐ1ѳOg4Lh =b}#0M&皓AXRnZ׻a=:K đ&ߩ ?goQހ mnaAlHer)j gy:k0' `t-*HxVNw&=ɖ02Lb]՝#Y/ JO-SZBc~' QJ7-YM]x>/ hi)epo!_?c1{6 條:cEOf^"W2c2^`fZDO7SeLocy?9r Mn["ۅ|m܎e[C}>/YOS){KɬLbbic<-ͶaY_okaԻ]`Bĺ[J?b1dR@g?1%oيtPq*a8qp/݂eu`v3WKZy8_i=1he}e'?# ZyClzn_ bw {jUWHF*39"Z n,SX 8$7yGT,Dj|PtZL0r<⼦ B`B"X:Y^g|\eU41~dVM0Uoq83- *]cva&yCiV ѬY⳪& >id ,)we68AԠ禡u(˷qek¤N:J g׊2%c{1X݄듍uk$?۸ڼ9 GZn;HХ4]pr&yNB nV*Y~T9'ҀIozG0lmu~.kX~z}Vmn|ID9Ql YCy3M!ySv{ӣRWˠMu 3Qx+,o4Pnޠ`)$>k`VGD)Hw }g&O(&,ȋNMc&+6ͩQxN^A h㙝<䑕 jalQH b \ EIGJR~p]֦/]Hf%Q vZ-|xnkCx:`TQmVj$M/ JjBΑm(_^-؎!|WtPmްcE>g86JA4ɷd.[)eED{P1o b$⣋2*> #3΃LU)RYey-wY\bɡ.<)ю,^[x Wipj %l*,EvIǖGtgG4:jZy&' | B=/;!rŚ5r$Kʳaк p*&k"xy_dl*5&N}OowIn\Aς?] r9?KKEJ.SzU-؉fdh0\ xU%VPYԐ"gAq%2TJ۝:b"׳ru#uWUM8WD r3IdB~!Șq#q}NKu:ˁힵ6Jt%_8AD<"Yv lrMmPd"׫*ޒ- T7BS;OZơl`wH67 V 68,J-Ws{L~68W<:Kffj~<|2gt_BR2d[Ec?*kbl: !T"8ΪhA@28$#$lTS@ȭj5]mFk] hm_8<ЧA~1׌=ݿ (w(L&}BߣSd%[:s]dՃF@ @L]Ox0_7@eǜ]~K0ٱ;3M5KD']<'}y-:Qt ž+xbKCo'u35ן{j^( 5?Z>I){ɁJ>Tw6eV`Œ :5`  ,՛05S7<-HR>Z"d+_Z(ɉwé,lU Pi0sF1)JՍre7B/[px$ᦕI1b# $:8$73r8I,TW=P'hJѦ\ι {{NTu϶!y|`\+,w}z"E[1aJT22ogOvhy>ܤ .qg$;J[F,5EhtoIMӐ;SID}Nt=rEvIި6k?Z΀'&r!$楻Yz}E` X^?i%~ N6D㎢і|}ޔ5 ѓ(B_Av|G?RQf {t9M:j_I^FxyqX'BͿaI}B7dK@ݛ:z%!tHl,l!ʒăCυ2h{ ``"K>ՉCtqhAvT1dAߨ2Ϝ_uHx Gz0xjn-S*TqP btL3E",IJH-4RfW33_3|v=*ttl;ޞ(5qpҌI2f%؍-) 8*y""ä鴀X\,+3SCy2ď$q4M](p^%lkz[t\2)dV7qfJ\RknP9QIcZeUAVhn!$![T9Nŀ $Y 7\z( ~&;ǻI#jKr (f1PkZ"-ԛ s[~ 0ʍ%bzhϔ@ WDrΟPNėep˩f=+v)7\t f7z!.:^~OH_h[^Q\Cz%ctw=c)Ȧ O_qI'|LDsky<7C% # ]"kz ".7JZg:g>j}I#^c6ydP]AI&0"{ZveCP19䵗Vq旘USFtQ; 0)1vkwPDsvE.pѼj WBDM`K+>4YJ#-ɿR`fp<*KݭNJmʉ +>RTIS1g%WMrv&`o MULj@SG+߯U2WT Ҽ[zrb :"ү4)b'`k>')b,_#L5~sj-Pw}̛ϲVNcf4WBdW#dӴwDf/J'@&R(k;GZM?'Z=zdxQ7?Hn] bt˾}uP'*jV۰#S9|QiP9! N=#@G78m47էv^3H"^Տi 6y"{`'+SBiL4s$gkL?&cR\̺k7nYH$flO!'~~j7A`'sS)j~ЉX-PsÖ5|j6aXl%G\W²v!mxc_a aLl9#"t5TTi,i<_V .+3pNF"J> `r.m^|/> zlU@+tttd`vICXp:^ ![78F =s.ZtٜUoR>e茇T1-y涵Wh0j/% P)#}gS O #vne$]U1v ( %v=ǝ?`?8sd|ߢe<0rK3g! 6* a(KOE!wsK$bNz t}>^c-H'CJff[Rg{,tsаRNvvב~Bn5jЙJӨfGo L5 5-+›G@gV8 s \eHa)}?*- ߬vRs4c<,hL=KSIj}{H q86B4%Nm*rEN']YZDyf|t#+MC:#*Z"F/m@C,h)${y]\qU'mCJ284":E9/5@'?FN|Zk H'u"&īlvqr%)ܴ{"6W) 8{!ƮTwTU!J2p*ᘺ{/VC]//Z?Uu.hpq@DQ\1}Z`{ɨj׎}B`xf*yn `{Pq܌FsVXN'LJD^wҷD\ulc\]EvOYE]QI. E͞ƻmX Т"6=?uw؍p3Wp\o!U?K%SxHWkh(*P.w&WL8Փ f#k$hfx,$_#@M DZtu~E =ӆmwe4)jmݼAR"}>ffs(iH"ۜfgWbzenjj UYnVNp -Aʥ9mqZNh"d.ILuEttuڻ/8ʔc(q m &:~f F>Mb3 UBIf ctޱF7㾤ҐB;4|E á> @ѓAҚO{R)J0^\K3yʉdOͲ_-%mnY"UQ 3; _>U/,uT>רkء{:c$S.2_yzw'+X22!y8YsW(+k+HMjFvdP ΖxlN8i瘭hx&GFɆQ9md!!g4P,PLÙM4 359: s.1) e]/fwbGD(y!LuRy =c |ˣ;K0_4VP33F=b$Rm'"۫+l@ ry^oq0~xmtNϩ&,I;!?-55̨6Rv&.N\!q7l}+(>=o8ۇQȶo!@n`*Y*b-cU7/~YZBEt_d(QS~u'Y*z@qB`J*hcM ]P24we"@p xʞ7IO=ۤq@i{\yҴVިPyV @hHjS pPwmh<:s$ըX 2̴C#.F=g̛cź࿀[>p>S+@3-KHxˢOnEP.ʕ5pv9Ş~bqdL7$T\@_la0Tv/XNJ#֘l(Yn\̷Eϱ`q/G ׮l-Ӷ<+ u3BT,¡߼VDŽ} ,Z$RDڃfI~E5YX1(pjZ>kЏRw?q4tОj߄0%wC3^p8l[j"bQɴbh =.*d;E7p/m, w4Fbd'\刌:(I[FK^A1kJPBpdŇk. ]5r=oyc׮n_!zB &DRŠ1 Ƽca".Tb^Kldw y%>!KOd!Y(3 )4 KcH-"n1 N0S h'Wp{{4+εiKՒ\ Xma[AFN[b,;@U+2K?#+D8VNXعg8EM\myS3Q~6RoB@s8HS.韑8XI50N3 !MFmQljzߒnTʟyKa j@P4p:xvfXkEҋ|CI2}X2^iW\6øwSJwd(oG'^ F5~rʆU8DŽv68I : %/:"PuÂjdhY4z9sys>םa#Ny6.?!gF6؆#)J'V9BhR6E8rxlKo&vLQTCvntIњt[$NO/`hQܤ{T5hNפ`Q1au`y|b={aRLѰS!ҡa&m/fr麱(E!hn)`x1/3xOA/z,S̩3a Kׇ[?/OAzK4FM<{>\`<66CB6 bbS cri7nHeq12%%}F/=͟ZcC7,P(Y , 'rW7P/p?&? jĘ"ldi]m w1%L יF\YѺ}:| pZJq0h ^rO4g `b9jՔ+g$pRt$CDDW{m7_۷/ a8 fe ]lcݗh.83;Œc"%m~-Bh0oO(C! I1A51 r= U+D͈l#/c^BCY˥OX0[ZLO#c0o>(8C+].Mlj⎍b[ Z?]#&| 9bk&0ߝ4` HbmjX90&317YP{!6į*h7BB烌}}:\<.=*H^J2E.J`X'"jnQX"C>oupq{0gF!e:"Y6njE7eH CWG#G ew}սdvЅ{] рWwHR%Bk~VV'>]r4a.MawVU爔,e0h&G^T[|G`tP{sax`h"aP|SQ=Ԭ)1j]Z>!)YwمMhnaL7ORy`E2i76_me qVlOpT$v"o@%2tMM_WcU:vս@tatԊFڶUD{`J "oX^f:T=%GnZN T}=-3ˈRپGJx6lCNj!QL ȁ!@e4iY$+MF#.GT1n}=3`M+m ?iYzeu._[Fs3=+B"&o+@T~Ϗ{ˎ"ţL YB~s8.ǴQʒƹ0s9,,GeQvwՌ4J5n28IW`6BM2C$u˼Gڙ#<Yo+-N=LOLTca^MVt=:dorϷ%_̏ʶaLLvL$`oOO!Ak[ ǘzTm<W": `̲u(8?:Ԯ̾*!t53}!/m=]TheZ5M} ߈a[G4F)/_X铉Z7~ªA1H{aO а Éy#J[؃hr> #ؽ*CnPV#r\bZSNՑ zӷ x`B ֚0Yһ=Of |e+oE!n=J@ qS0u>J-5&SA'_<&XJ6gY\s`Q0!l Fq13sSDS!.K^W{br`~vb&o4slݴ] xuOiWs?t !9TM1vd\%FݣCxаh2Q :z(iݔؚuqiDvLl0VFr iIF=Ƣ-^k/@&*S %ixvfr#P,I% ``;:f-(;E"U! +1jdM CѵMvA` 5$v4Z,H:dK}8ӻ`퇄/ H pÍv!™c~xfmf+wDThES~@:H)&qHԩvwkW+$4o()qr?gw*?HPXSD*NBsO#[h]lw@S PAA x`4Ͱ 4v|)\O?MY=6J~=p+7@)6ΟERbeu5cKK;s~k($8Fh#÷W? +. J֚ z9e>} Pu(:>AV$ oB~화a MƑO{ϲC5_ՎLP={µ^' aY!'w2i$@j,e3VA-ʶ9 2 LA F\xOa@'V1)\~}~~=}c|IԜ]yk?UZ$g#9 .g+ok~ e)ֺUFd P?s^Z᫃H%2i 2x_-}ըy0k Z6KԼ<,۱)p65 YͶ;C~)q QI}M"h΢],1`:[Wds tגUqЈ#Sxl,Vpn YtcE\dSB u4&kD}u0ׂ"K%[=+fފ~]XgѮF0ӦvqyRyxkӟ p@Zs/uIfAocNc!ϟt+~&BKzl\RP) ̈́"K HIkO-A.?E=]3=65􇜝  bs4zE؀B9DFz,S<[/wwb- QLgR}a+ QQ yJ1pԡCVȂUAХ Ks֮+mp@Nj=y?`Re6QtWJ@ERvʔYmd^^'=4f$%rQIb jk \#f-ꂵ0]B+la;&;8x46e {r5fM >N?$I"x;QX7C{{q *,~J8M(*Kcd2"ɹU_NKZc>RXnIA3-,yzoaL>k#BcPhA@뱝l7S)(8^?N<f&W"d>QYY \W6/ނ ;^`k F> <ؠ2N뼂66Z6tk4q -쇓l%nQ7A#Jjs KC4yD' vqF0mW°;~lgx]bZޞs+x#ͷU0bcqI?k}%Z,˕N|j2$Uj`b^pTp!7jlyFKa GMJj^#Ip?/5́{RolB¢ Xkєb"NTu, 5,N>p_ @:iDwOY";)*XvD?1k뮺4?ߔ"[RHS &34 qJWdK7|Y^:HIc3LZRdqe'NHG~+);&/)XXcf[aY5q6'ScO%*o%" V_[0Y5#CM##^ nKՉe ~ӏ9rt!}%Ʋ9deӶ3ɧ D&,E6ul\ܲPB%vn8Фp.h*gv~m +gagrIcU.'>` ,:ϡVmNB f*I+-"a,nǝ[.4E*$qROKVpnOMcOZc<* SayE5sm >ߐ[| t 9Soh|MfaaF~ (hS{ȓ]S6YTJ7!eh0뼕OPr$CgS}A6kd* mj'xkW+fnˆxTOkX_z('mT"4D_hV7oO^V>ZКF<2.fLO(99u>ЂÁJYi7\PIJ:h=˾:n J5dY mԑ>'k6<>g豸#Q7ə<X}9f%H ;p,tsކ_ɒ$9Ɔ+ƃv:{h1DND3ؒ& {<*j~dk" :(hq0 'Q.GB/KJƳTG,IpN=R 7deI@8CidRs)@m"J(zA;q7M;:G˾/rjV'AW_MԡVzo7ȄEV0Y]>7KEǃY &Z-YHe>Xd\&Y{Su6Ǽ ~ d^xɼx.tbJqerm?@]#|ͅ.?ʱB",{:D/灇YfBaA4 ڧ,\'VYv.̃z)eNZ4c)/JaY2ԌBKDd?(ً;DwGgYΐl׀]k=rd@pJAm68f؉j%mR:/wn\0Z]<0'H>Kڱ P@Ѯ:.@p%nPܟw#*4(9#h|ehʓ5(:N>}c\}7ȹA矾-y_+9u33ok`g+O򐞙K)"V@ks4Jrq?Hr/4; ]b61F#STU+VO͌:xܳ)k}ͭ@nL}َ 臿rU35F ̂Fg^Iɹ}w/r?3d)$8̪.dbrَ3uTdyrpg 3u揗:r' l| B0e 7w 4BmLD12eh֣-|o䝘I>G%e(L9j+Qī ukWik^37チ6^1PT=e>Uyc(O{nė"ϒB&,Rf.^2HD & ,HNӦe_w#EF./fm F"u~"4NCy 2YPksaeU[|^ 㜔Dʼn|ZF OWGtᩈ~p&N_;،.4uߪےNNG(_L4Np^Kn6a@ ܡyn(<=Kw4<~=Hr]Ӭ\qh4ſ8O$tzUDJ SeX Em'>4>h\9j+*K]R8V hBHg)HmÕ:|P/I~JEj?K-jNiCADPvbpCPqPs>{00#.TB}lIʐ>JL3=t~M=gȣ9ܘ@?9Vaq::K"#Qa@=%ϒc*$Z=ذ#Wb^ѢR#}97B{a$6b[{.}~~wP+5.OÙv4idԵS1u 8,~eK-(VjB9YvZ{;j^ɌiM}nqV{ll z 3ǝq͆^Oߠ·SœHUQe^k1tK`X%-3IrwqYFdžIhGm#`F:W"rwHcǁ=+d^RƗ83q޸!p@CZ} V#|3??#RpF E&RZ+˹Nup:^R5eHJ<\XPwgHB,G pӘ hIx'@.LSC?K?nx]!$`Bꎊ5 's#{1O +Aeo#IFPuyA5n.*vW㕒b@ 2[G5X^ry>KeIwfG] +wQښ޽^mokGl)u5=D-67%YmCS- sՓҨrlϡb+/x`F@+^!RGΐL(F>?||AHVLa1o & T2]+j ny˼Pk RU|"A8?U ƩC%uX.S9706mbQ?9dɢO5Wvjqo If1\lAo2Z_R*Sx߽[SG,4iˉDHLmi6mh<ͦ%)MwwHYTaRwU`q ue _ٺ|q];ﲒ3܏ EӆWJA~4?Cv?G}`xG`^BÁ@5 Dޞ`dpI^o)mI Q5mh̘n2/I$[~'mUQ[цa-8yFP\BY-_DL71] -spD'j"+܆SGNذ7>;Q]4s܂]8{(p0E0$^ֻ2}WɰR&SwOH6&uAKLԘU͜4w偧 xτmpɯ+TA%ܗV0ձ9=ьyDkﷴ`X?F5.\W)o_+Ӝ ;\);asN#~9~-T[ocfaHp9g]rHӼt/Z9.7Hbo}6}NՖK$8T3L#Jy08n^TƲ 0zLdm xVDo%n$>jbml%C?Hx.p6MЦڮipŽ(Cl ~Fx5ƖKk}MEjc1X|݅/!@VLTw#(| >J0NQtFԫBKH&sm4g T룤Tn$!lu`W> "-MfSs(<|(U%hT%S@BP)р ~ XE +ڨ<6lrņe2jU`m UaKᠬ$_x 3b+cw"nlL*t|"́p:d(bk;!!;H?{:HoL,W͒jZ365nhW@PIwg6Tw/󮖘Sɚ6hWWc= P !_BJ'P3a ˬ ^tsUPthsi9pUmfrjK5a#E3umW6%bE΁ lޥQ]re՗[XDbMnLÃ$gwi 28%4][IۥIDܮ<5[,$4 C0s}{SM62~=︂4slk8"%9%M &ydi1މ_ B̢|(y|s_?^6Z^|wyUo,w5 /g* JOעF 7cQTh\wOLW 8o":ʐ̒lKZyoƜ!IW8O90P<"%'g%sSgP)KIAemMeo!IaR.fv,C] yӂhb`F {H@is 5{H|RANJmNg\沼SA*Fw %ӕ+p0[#*=YIShީZNf;U,tTRO rsH9sU 8~e.8Dwšs<;#iz]{bܖ⒈Ж`q}VVĘ0,~/PW(ojB| QBc#PqW6B3\Z>ݰUjdqFM0™ZV<ĝQTr]'m(E/7͓w%Mk^Mi؆ `ci6,;@!{Ʊ?Fk$2@m&P. |>3* ){)5F Byɻ&\D9 [4x8eP+쨐؃Z渕aA[\7w; q%E(ܮ;J=n8p+Gwb 49CDԣ7F !5\ \[eakGߪoDQZ *ksn=n/h/tISqh/(T+yTW ~I'-k@ e VEW5Q~pfU lcz霺Ci4[ʷo&G]h*Ja-Y_Oj5k^ꪡϰuHrmT2D6:" Fj__d,-jwoqIܘMɚ=lcOÑGB~XI{cXn|+Rw;5rIG 1'nǘtg :?Xpn"4w{rFOGHivY#'tk'XL4"D/i>\#v[c U8 WßV~^:3zxޤS|?_6m;m䝰r; $.X(9>Ӽ(=hP&&4LhH 0(hVyCwD'RM] DڦyxRddqY!djRؽ.K>KVV!,/aрBNtƶ.k(%t߫4.n]1ȷA9Cg ~nˑnH3~p5!a0U9F\ }q{N;qּCA?0:MK^떚@ W+":B7۴:h脐M d}6WH {xᘝcir,*_A8r.6y dL1_.ok!ܩhg uRoW Jy01Ct fH()Z6خl>>F,~L|z8qdE[uO>;!F+nx->iF2'Am&A:A5t3StH5AvpT*F4֯%d ɌQPZRRe><滍}΃nTOWJPHy0(Jkp<}{Xk1c%bFc38 *,Aܨ-koG$ ʯ ˡ-ak^`w~A¯e\'a"͓a0zS}Vxp%+~T4kWP%ۇ~> ^Lv`&J asLxPA 0M[]e`ԛk-,7Nd8[FÇ֫fF&3WL%=eg;)_y_R*nۯ#c !{"xs~zt!/+Zf YIKTY4>ըB?h=bڰ_CNҌ^9f B8/-ιYa4XLޏjؿ'7S<#ZL( P*5$a 5? Ԑz@ 8)[ j+aTm>V[0>d7?"(C Tyowkm ɸX *Cb=A*!&X>}[ dQXW׫j4H _9$3E`nm${ 򗡀DTsc7pC Sۛy=NS̤ ʹPuKn(nAk['w9PJ|kEbc{[);}6湔7)nk;s͜_C(iE *Y (f30*? 4& u}'==BGtQߕ/wz:-F/XCAdwp!?E"XsٓWR\fjr~e Eb@ ?>~,glpaSR :̵ۊ( ufpE+T m\Rc}?OEк91,8A` Ѡ?&A; aɊQ۾s}=# 2X@ZSU-cO j_吩AȽqb&4*p^8gB+yKkHGI)RӒgZ&]p:[4Tq^gޠ2Z๪BDf$K=fj >l0aDIA%zzvw&𳵓/-L?Bw a- u!ܒs҈2Scn6@<)%kU4UL0s;xcJOS4z /$|c͈8ǡx¶(ʉdJ*,W }i)G놠lW鿇_ 3RWW3gLgc7y9G+M knb_4Ȭ3pGJU>y3o5#N$S H{Φ칒b䂞ϷrFG:R̮4B DOl*?ۓ)660m s뀶vmtDHu"Of Y?ba"$&Nݬp, xT`E9L4\+C[d߫ZOƴ()0bdLEVx_+~46iw5Z#G'Ü,Pj {DRb+:[ddƎjќ"y%("8 0.X⚊Og$ig ~FC,{e5dI79gr ~_9WܚwoO к{5ӆ@ιh Q7=\<ۈ1# v/w~|s/e%9.=+#L[KY90\c 0\q?S>Cmvj9UmT]A_kUt7<'[  63!VB_iS!S"H&s/0.:͜s*.8~L?a Og^p?ߠ(t:Ԇ|Zqhj),8R/3ABZ(+AS|϶|k(ǝt{-aFWKe9 ۫R^`o\`` #YJf'hӆb~cMqvX?jh[P.LNC3yrnq2 M2.DjD!nM 51m#q?W6V(7GPx0& U2YЫmh~ =;TNFLXy]I|fj1@,voT` P胉+yglKg?DϔgɄQ?9)0턝r_&oJ0GCqyͭp%=\GLbd)e:i& "ʭl03BVUUu&˱[HĢ+eԥM^+66aq#A5wg]3~tʵQ2.$@ )cֽlDB<ZҪ? ߌQ7te]jZk'cO轸7,uy R2\ij«|2T ʕ?&_] (7͠luwGШXIףsrt_-7*B7rq?K"Gl~k*F%*@2@'p_?ʡnJ_cDx3 |l7M7W%&ȿ(Ɍ6Ni2Lyr\u9LنLlnUX]@Ur=, i ˑeStZ>$ ߾Ih5;]lEȆ]U`rR?ZnJ>Fa>BQ\kGbjAK8'v~+W8N*tB:0_Uh'LnWz.i–H TNBmBDO|xgnyBCdy8 +j'r4J&׊vhfշbWlja1V"%Lp˄TR#Q}г7/w 8'̝BM!/dO鬵xQ5c/v>_O*g|sE'ӟ}\eA[ Voߝʏ% `#_U,*0R8CLv;35~Lej\hЂ.Ota^ lҀbJOʯ@\4NJBD<,RC45yL)\A+T'XYͲ2¹_CuZGYNw]^ulc[Bij?:V%{9Aje|NXDEJco%+;ܽCrNK xoP`i`lі!Kf7y ] Ɔ3 3QtmT-C1aDPS9 wcO8ݚgH^9do-FĢ_/Ľ1s]^"[+d$a<ŀj+oYiUw?mߠ4̂g]\Z]ϥt|!Mw6uU^u(5*7<[r:ڝ!jhEцϭSZw0p8&x%cTLGOMז*՚X3;;޼c\!6g{=DfhkyS_Bcy1c<_AuC9QkfP {l#-[I^@/\4ԽͽuqC_3KL ϫD7~oTMz- ?7wg<}s<3k36\Mk3]f,(G\3T.]t [AѢTxB;{϶GO[xn$Ǡ(SS u Y4;<œ@S2&4$EA\! ;JC<&7u6!mĬ/8&쟎0+ F /9IlIJ1J*Pq 2\VsTdKJim%^]p kg<*u25rjZD/FJ_ʜ)hWhO:pbrij딏v+Ȕy-+)4+IFIJ=tzC`pxdP ;-}帲)G=Wwj}7Xw d;Q<`'4ԀHՆU*MC{Yjg E]ɋ8 Pg013Bje"cJ]=eA2tݱKjϧ]yBQ0mW$&]"1[S/  eNeQ!ª |3-u%j"]q$7sOWVGIt_BV5AV%$u/nV b qnscX% _(\%t5o XvU$5T6$2V8"vi1quIǰmmnHP|_mX'a:mf(0p6S=t(Jq*:!3^D_cK$c b4Z༈za0z j_b;_NϘ!֤^D&(ImD?Ms*8%sU!ѫ;sRP z۳^cB#3&Tn:s g)xP;9?]cwzR&5 ᥦvd$^\1$PIr*n@2ׄB͞Ӈ yFDi~K^  '<K~$w Q흱ݲ:F\ֻ*`vgUK`b y+zcF4?gPUȂ +t$I~X =jU+bZOE8`MYZ0.aw5P}V\@-OJq<7..hb:U\/fa/Ϡ`pJį*|9Ds*6B9jq~닞7ZDӷ~Z-Y]ngM,Q⦶7hD:.3 ęsiCS0#e\rj }IVQ:mn }##۠1xa]]#FnhIh^QH:;$UYxZ֔TQ/8.bh@RnTo>/L ""3PJQ Elo&^W0jALdq|е?~8PNSq#30ɨvF"1V !\և,9S\߰^ 'mD&ڴo 2 -q_z&m wn?td2vHfmKDDQE~7-~9ُT&~۬oGC l\lgE l C{$}I z8deM~2;|[ٳT'`'t=m<]\(4bW]G.9#1F 1Wrz6 } V`U[`n`P|Q&ntJ+AsOl_92lE P0%DaRqtEv4n0\-r)E*`pWlqڳɿT)W" 3IӁ+f%*a?wmU02KɓˏQm09AlCY*z: *l'9?cH"%g7DI hK^˄w\~5 +P=ATݽr @5`y"`цe$n'3Q,1}5}j]:mN9ԔȶwrK(.|PXa}i=(\.bCl38k0BQ3 O_$${\TM`n5">\oy }*4m͜F ) m4CRo,d]C9#*%/t;ۂ~Lk`zT1hWmf?";ki̠jj x%X({mu&l;{S6asO-16\uKn26{ގ[uuJw1 ,REBV'U/k$|p;E? L2gO>$A+( 2axX?oxZܻ6AwPIA\;a ❍11pάmD&f#y?p8d'c0/vC{=3h(|#f&}|!$2e c0ZDKQξm9T~Οj 0GaYњZR.U JR#VhM11tUd- K6NgYmhY2\@ TZg pZbI"Y"詼+ydڕO``B#ܼ1"TPzet͊9JubԨ%s;F1xZ {e7]@;@AN|\OHADPެUGN5Lq]׾7#DQVvpkWcb/ا4̉`I &­0cw"mwOU`Q#2m_ofEns4}34e lwMkeL32i9bޞ<_xo磛[ԛMd\Z7ijF ̕J5ٸ Wأ&i3~o!TZ7PfD5x!BYRtYc0Q04FW&8HÁXePYRp%a;eЈ &jDU d<(Mvi,pFu4$nzx6g(1Brt\镲ºUCB>iJWcӛQ~$ _޶a *˗Эrcz+2_|TyXP5 `ǨLMF,,vH/Hݯj̗IH$`5%.ߏ AHwVN:ߙTC>;o/Ec PTn}n{[@eSN+Z-(>'# 2? $"]*-0Y=ʋ41iZ#YAvm{[!@Pp8N 4$_(09q H#B~& [u Pw.|}xfvfY͇G0yOUq㓱}`dGȐ 8?(_+$zzd}HOjs*lJy|y`4ȗ %ǧ$fI>G6G8 a_{!'r|rJ ?_Z|r9Po5&&bMRP, MԐ:Q hz}$I܅^_&:\#a>%~Ck̢&a~9ՙ'=JASVNWᲛ_hf((\,ފyp:1u|컪x? 3ʩ$W֨e_(,_0͜sj|=3J.Y!*gIN6e ]4{5D䒽h4 \+`cf:t1Oڒ"'qdjZP`CL R46BAδ ?mz=<0ġpaՑ f(QPiN}s}#q~Dl D8Ƶ:U4CuGb=AKU屹u Z6mPzw RXgC > iu#.-m|ZqOS~ګsܭbzXv%ׄۈ-a'B&ç*+NG:YSv; o&-2=r.@Bӵ Io9…Bw_g)s>6:ilUn F `v;ĕWy\7(t;Cm d2FUBnIx!haԺG/)Zm:DPl%Ҝ!}@ QG߸(FXU P-9;R^B5ۉI MQ: W~e9dB>>cTꍢ^zN$\8"Vu71cu}%zZ 1YZ,J`+8ޢBFMU2+R3AE f{R!C̜?:S7,K]|_`G\Hg;~d|(E>tkYqW"eO4e -a.X \_f 0JmpYQ'8,whhA+d;HY a?9ݡ_+ HgDے/.zF_}-pqm~ُtlfv{^lAE v Z ? h~'{p9|ˬjlmP*re;F(25P̆XZGIu.;?y5^&7k]ۯZT"'[paߚ c^6/PPS'[BAP}4\̭=p˟ft=`hc T /}zKAIɮ3,?|q*S=. I*cֵ]"XP`_"#̪u_E ؘi޲FF]5HX*lQVoz*&I`„xwqPv+$>d݁#..VszJKs%0+2!ߑG$0._M,hV1=HЉ5I?VcSqq3iiI`nwCqt=B^!f-SȺcډhV).i!ic z"o0t)ّTr ifýH(p"9k%Z-DʛՈT6C3}P`pidj)岀&t[-$Qd|5gul n*jՅRϋ=1$o['_:t:;N M:#pP]>wDJoE\2p7l F4L IVyݞ'%tjI KAJNX}&CF"vŞYT kP IvR0D.| Ǘ3/6J 0p?PiŌgD|BFnw4}W8Tg"VBhhKmq`/Ŕ!€3r ƌܲ@_AF`+Q 6ܢIaB!$Zf#57\I["MrLEP>$fH5;RA0i& {⯩n:Ur2 P_O~h5}85(t a-b6~m;lNQ܋MeeN/CH i^4m-WNdl@, ߟO$`Ey=ܡ+~Ұ?*#sD^e?Pe.O~, Vlf6:~Adkz]V@uӐ:Bօ:N yyD0Ƙa>Mg1[Z"%~39K4\r ) (lT{%L7ʉ䨲.x*YO> ǒ@xKM+gU%Q?s_ NL؊:5;Pd* _t5j^6D,i.'lnD_ծ#=Q%]uy]{$-֔gKf-[M![a2g,;󎥯ߘo%0-I{)ىVKj6joeCԍ_'\:4LS% %{6IY-H-Kɺ.Yk +O )inZ)<~{ФmZ.2 JM/Xд4yC>:|g.[X$0hF,k} 9Q1 @JeP{)yT-7o $3.RAޜUFn)5]7iȞ<O/QgpU=@9n!旣ఉ{@eXE ,ʐ6eӲyz&!k -Kq6W.4.p4t\6 ͪH-醍>~CE/ZK#|?>dbV48J!vڦ|1k "eʈXPݞ1Z0l=jZgP<}qN(ije TatƳ M-%YJ*zk` \%wSz]]T坖)]~RJ@ Y \$? E~B\yT eW_ǚx(t|Ru`Q )3ю(nWWGՖϖ Ko,6!>s#2QUxP׊p&YrQW^fqM;H3Im4{d'ـWCz%o&Jl7 DN/r_lb{Ii9:g{@oh=6GbK=MHT}O0`-|beu}N ]# ~ 2\Xs16熸H%3Hk9R7P`a;iБa{ /)~/Yw%3 {_p430+|킱֙EKUrxJ6&lܩpbN)h-|n<yGǝJv-VBk؜5~!Q˜p*&alr]k/N^U23z|xdȬm%NhCpI:6!ss/Gsܥ7^誒{抎3sD6>q险;3ѹ!ȉZ׋&+Mݐ]ti}oFY]T×3SGd'?:FXADQfapvs=;0vO~ۨ~6aFK![HS֞)L׏(cȓY!1m.2H%B%+k}< \{jIj{cM_h(~VV° 8AnBk'wgYnyiPP&xtyaͰOLM%08cl$}^cQw3o&uֺ)s&Th 4 O2\܈':+a3ZlP 0}b$aKI;4lVu-Dde/A+& H/Z6V˯N5`8PλC0+46:/Nͤ^7!7)[NcKos\GWmp3Z#ͮ*uRE>wR!IIe0Dk +›v|H--\gޫm)cb.ߨD$$׻Bhw>=,׏&c.I:w>Z6ҚQ~PhA>"BèJL奞[+w mf]%^ŚR2RX+z!3jI]wQwI à**r!R7+e}Q)$I37z`dy_3 7ªHU bZ':ѕn凗vHYa0 .9bF2fYf4ϺM+gQ0sChKE- ~3l. a]n9i~6/ /ܻ)EaBl U_99궫|x:T84^4FAjG; ~h݅abB%|OM.ޢUϛtB [!E|R4 X"bC+Yy7J8; ej.;V/?5ڸ&M&LM8Y?% 4^>\cE!XPvL@]uh~nmq^_Z3^MOy(acRoLHtGgizCB.kԯb- $r4A5TzK,2ds#8Z|*S.7#`WCU][nc5 l[h[,q3^ :q/8rl01}6 9 %c[S{˰~&vfV,on-|™2 c?CM'Am!q!@ J=GS6NU3|OJlsD:\~ 1E'MrJrg.|nv43q=\uFmaemߟ+j|~?KvCL )it!ֿnL ^}JsMq~8ƉñYSN'R"v큋Y TU0rK")gx+yEWSKTzunuq")/>j2o xQTFOـ Vb6Jdg[K9i3:.aZd7P-X.{ pzsC^8Ƨba"jRiZaI.AUYe` s+rV;!}_ޮvQ_l!hbRFע>&J#-/QLbX_sKo `aƋ g,Z{-E&&CygvKbE@\7㠧D6ӬȌ ԥ#Zq.Zp1gk!+ү%:h+wc= g |r';>*S[aquϝ(rwFfjQBKy.氎fۍ@ʲ6 Zf)6u? iys 0^ {AtNOԖ39пDN=BAL҈wd F\XPwEawD:VaE}t܃545.D侉h8lpD-iQS&B|oǩ>X1WPPe} )~q9&!&aA)K56R!JU'(pjhސ ֨ ;ю5ܗ5c"l@ʤ _mq,*R-\Ǡ:^ʜLOϖVa% XF ӂ*&^]eHx~6흁6Kt7iqgn}K $! ~'jpv(6RyOb4*[A$/cA.*lkXqNXdl"*6꾔\;w$xn ]Ikw9*y;ˋ"QtsvU6x3Qq\ی }Eq(PLTdY[9S.\)BLtQQh*[|?)x !CE\]$pX3fPH;N<($pj{ f8]9~]A5+C@K>4*!K {v K߻pLCxTb">iw7A@qa; t_[UӧI;֒Stj ń`\ͮmy֝FI6M{ȎS?ºXΖi$g> /?{Z!uJ!/ Tn6Mxp 0Լ^&aŠnzJ#3DC"_/# Dtl ٥/<&PS.zq|c :2>-xF]lܚ$N'T|udԪwI+gi P2v;bBA1b2ϧ͍=A#$aU2F# ?sApG]BQ{r_WN%EA+/E9bzzzq2(& 2$MŔ 3~KHfw͉?bABA&T>`AΒu-K:4G>Wb'8DWi_0`d y@Qv l#Zbs{_rʔD( VN?Ӯ˶pcݴfXZ!}mF~~nq4nƚ@՛"B 8,eH߾FM[(٨IQ`sĀ)ĩzɸ5Bgx+!PQX(R=`SEG@ F-Ia%3h&8AޏP$B&◶K+Ij$1Pb3p|R 7)~|hFYUkEox,?6(TgeO$Yڭ 9 >dj}rL#⽨=L鱊œݥOPY0;ox! ;=1%#ef-xquhsg\rDYrEZmEZQ=mqJGGS̹?VW@CG2,ШBL9{se:&Gpٯ|-+MY'@]^Zl!+"y|/=mB/3ߨT P])&>0P"G~yfϠԼ[ QW14ˢ'[CUT- p8ror;!#UHYFЁm7wՂ<vK#Xp5q7\' @J2",SI!ė*Hjz_Q=r\#tih|fjHӹaW_ةq]g6Uv{,35$b3.-2aA]hlѠwr;ņɬJ2ٿ[}pv|,/O?`3۱꒯jp"q}& #cecՏ! c-z=Ƞ1 3 @tmcw}! O$61L!6if-N/@{{AQb ,5t `{8'릶l,Fn H\h 6-(:"|R%yT3hqZePL 9<SA6Bmk)ސ=(09`HPzuVTVrũ6e5FfJg%uҿ̓g&Z=&nF F>EVؐN,/*-24 ۜ4u@K'٪<9a߃zNm xӆ Y"G m ֤,hM?7/ZKO5".VCTgRO[nƍ29ck:!Ń:[6DJjs$Q"nj30NβO:@ e K\ & Sk+g{d$-.|STWRD}2+`؋$H䷲ЊHD5R?,ɹ~4K24Q+1pe\*[*sDu!+B_jՙ} p9k׾ְS1VF2G7MEs1 ep|t>ߞv_/51)w;BsͪlY0AVBn\҇6Mgl&ƍ~Bާ9Ou [GmB/*$|ZN5 LB`@;z@v\C{Jejo9R%;w?6TJIʭf)qMDK*z:u;{5USGhݢ,Ako@{(~2݄'ᩄ&JfE~4 .]'crՏiv+Πzm\f"+r7fׯ"1Gl6?KSw5</ 8P?S;]<>/9s VvIPF-E/Id 4b 嚶&ikm>ϯD!OFRLpx\D2Yq*Beۀ%3Y3po>*7K%Tף#hzal3b4/wM$m|/9ළ Xvu#0:V?fMP1vt˔FRߏLLJV}"/VtƆwiYK6VsP1*-@JE_GHq/+Pk;jP IoxׯgL#T̶ z_,Nq+(gFᱢ.ӒOBA~m稷3]¼LsX KFhl!N_+nIw 1 ԇ5#׊ҝݍ^R;ŚYO0s6qEyM >%dM|o,7K+5K?4yay3墸+ǟbZq`N*بR&WԹKN7ȫ( <5R\P}J2Ҍeoy3.EڎL[4*"XGS^i/ԓqyU=0ZTIga:vYhØ4i"rE(on_ߪNcQc6|+i1%X@'_|BEy)}`@A`?Jӧ38 wUEJbӟ@g W/Ő#N'Aynv'+ y(l{ɹՋbU)6 4YYhaf۷ +Fv}:f.Ԓ,):F*_C{ZQ]c A?ޗio 'H[XQnʦ'^_Kw1%N=`J|zڵ$ۻc9d kQT(sYAtWhݙ:[f#^uNYfm+f%z X^CA~=w? U[+.mdCr9/dEw>>{M3u~D̫!+Zj6f_cL1MnS(Y`h#r cuTtͨay8 `̼neN,h1PXtL]v,׊/%oI9 YϩO }h<h%"=iJ`9 ,w"9zTjc;@ cUTأL Wn +U+);Su45&dƒzMN}_4(Aދ#s:9X ˓+;E7i3YGTh:*+G Džo}XQ319k=MI飵jO--6fP[;66ҘKs<`2Nw]yk,i A꧖apW~ mY&! 3"0Lc\" ;K0Q$minv~t9VclETesyzm#tloHA%9HCP_W)݆+ vS]g@kv榊&o/Y=k)S"ם-n/-T%?AvّiDA&vˢ r]RbH xޜZ5Z;[C~,C%(LJ&;yn𒳁 zaPyuRw'}{_ | Rd[]_OXջZc{%s;2|Ё:oҤgfw>nj~ch:t.>0+h&3њ'tyʷ{稏0-cZY,tZ 3{̅{w[2 P>A XY ,̦4MΩm"p!G]gIfЇ|&n,w>eHQLI#;֑%+%<ozXSv> ;&5HRs9EU̹֊=錻Pw,^%RI'i:)/t}}(FL&%#k\"!㿷'Ca ep;bڛ,^ e ô׋U?"!苚!dƝv==# Ơ/Ei^NP^f2n@CcN(FEIR$P=jB=]?nazYnу9-t" {)=Tl™׀oM_+_ÏL\KVxe!䜆؍7?a eꯎ.LRc 0QJ(Še6(0{cw ]*RE{?TФ8ѮN!C4NUaHV4Ɍ9`$ΐ,>CkDK վ&]MӋ}%Б#Hޅdjv$ G<>,#$`02c! s!HBk-BLwZeWĮ[H uZkR c n~D0bn+6(̜ĨZC%H .Uz5C̻#Pa#)zVXSDLN4b^gܭY]:Ì038*3&jT ox^(ܚ4Я\{'t%Ic'k%G?|b, wrKzo+'2zUsDݳ>s$sӍq]7.L&1K_/Ji< )Jj؃&!],1ϫ+M^բ3}nLP} gkAS*|6CY3=iRD$(vY{8Pw#<mԻ`Л$iLYc6Ș@ 2= ,/S?ӧ&&j"R ܙ(ZL2dɗggFs9skYC D%\6jxrG tp}Zv. IIb#Ea["j]p\L*=Vwx⢁v4my|uKǫ(gUS]L,/YrHq?3ֺHEtr,߮MMs's_dlp/2q(!ֶOgg5.>prPZf8cꢥuNUzVJl,sH}Gh9:z=:"Cm,eמV3oqL?=};yVj_$I{p%ަ{T%*Q%8%5aWSS7D9?ڣYNuJC'sљ @?T{ףl0d`i-NϩQwO,L$ɑcT+J s:`j$;ڮgNp[ 蘄9^Bܒ-UƈK4=QhޫFRɍr 2AQC<$E҂twR7^n߹  YA 8FL3C -1f ´.:V9jQKhlҩCW Of=; k:e@yENr]Br.+ZD|}Mm7}K:m8x ۱-@ z"AF+y %T:D}}~8H_tsiyR`xkg 98gUI[V kOiI&nֵ2sg~7Tx2_Մvy"ĹuLnæz{q+TW Cf O7@Z׻RyaǴP_NJ*gΞ^_Y&j;E|SRFiۦ'|B (.Q*{؍rt<>~#GVqafD 0<2K}]2b[ĺ6ʪ4R|t -Qۮ;n=ʃbMQ}l[ǚķDi^f2$3Sh7{~M9;vྙQc+˜/n:EZx6#ءco圥z]d"!)hF1`4񥐓q! mއ.ѭɒx[!0H}uIE5`Z5xbêxωw;g;_n2g˷o."܃ɫl HB&UP'G#80 wXܗ'X%|Y$"/=֓ Am m?%+Xr |pU$#9[48Y "sLr\ amh  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n021024l.pfb0000644000175000017500000027372310725114532023124 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusRomNo9L-MediItal 1.06 %%Title: NimbusRomNo9L-MediItal %%CreationDate: Tue Dec 31 16:48:20 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusRomNo9L-MediItal % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusRomNo9L-MediItal known{/NimbusRomNo9L-MediItal findfont dup/UniqueID known{dup /UniqueID get 5020939 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusRomNo9L-MediItal def /FontBBox [-200 -324 1230 964 ]readonly def /UniqueID 5020939 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Roman No9 L Medium Italic) readonly def /FamilyName (Nimbus Roman No9 L) readonly def /Weight (Medium) readonly def /FSType 0 def /ItalicAngle -15.3 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec pt?clZP'0*X \}<+}-˕~gj3u(zSw}ϰPQwa o&R_iKWH2()ȓͦ嶑;UKI=:'23'EtGa72w h V 4*ƽ2*heb]-??]9_q<>q,hr^l`,9{VܑQdGl#/8X.]E ]6 mA4 [3ᶁnʎJG>oGē8L$ ř8JΔ3,{,; uUBq-v{VLkqPֆ\a0EIT йeml)xfƂ~➵JVcWX *fim qPх{FV,et&&:q $Hm$埄+>̋`5˲~rTN`AO7:Up♌ƒ?OO8L2>xm)NAh'0؛bh+r 8G (vNfm/qn,\Mr>.ؿW9Eʶtv[.+hLh6̟y%gg8^Űy ܷ5N(X-BHQ`wZD:e{QTHr "^mu7 ݰV-@cI %4h[ Fzw8*!2,4+$\﫯P0hIȡ*Ō75Ɔ&S#U'fHhPʃIo8u%3Ppct=GύD+?rF]j6H\yjNd/Wg\iq1>Gz{=_$ˎo u#I&Q}0V^7[n >5},/d9/6a9j#F(&ʢ&SB )7v= ٪K oPc㏥aҁ}O ؃%P{|~m< zBGU>bTu@L1|S-iĄ=ZJ~AnΈ fxWӷӼ7U)څ:wcBj6$&K *Vc=%_xx#j @W~ê6UtZD<} eڐꨘ o1:FG0/ 4k7p͖rFﳪ>NyЧ G77RetWjW+MJ 25PEU`H^ 8/bM*@""vܖ N` ( {E&nXxdÁxgsuPX)#JFw)vi5/(^),Ӿ10oMW_7 {u ]I=',^Ho6^ۻBrDϯq̐Vsm\3^},M7WW$ NJV3%w[Yh4i|3β-`<6-vfGw~˸MƱh xF!%+̎MJJk1m1>]WSL?Vؒ>hhܪMԂ<\IvӁdq}v_)Af w1¬"&Ʀ}#߱78qa"Ⓙn@?!Dw)BʚJy*╟9&:8$XjstPz bAWn^m^pGrw9Moٕ:tCUw2Ʃ_T%[ zWF2Ma;KCXȹ,X*d2ba*w(E@:{Ork kuܲv8:5$3 !dl9bU E쵖 T,/],'[5FRDfnfڧh0RnʄO!J:,4"8NJjx;ս!UwLhRDC\.7gg8Ju #oF{͉b]t/ƒ "}u|C {yGʢ9$ %sJk0fthe)n&w*1׮ _lmDM/f%G; &ƣU2^pW]3|VYa Y 2]%bORV)Bske|򥨧D)䜎EU]nIϿa~ܹ 0.dU3\ۇ)E'x%ȣSQCjA_[ ใ$(Ʈ7(Ov9AW=Q \iIo҉2|(Iy7 :>K=nT ɍ[i1K| GEX'58q'$`;039d8Csj7C%'cj뤞@]GQ eBD]+b.M'`` D3?VV]=d,`bU\8SUЂ N,l}-r (uiC}R.ob3`QϱI+JBSJU'$ rvں4g+m/SN';sĸgůXqij0Ws}0Xb,bZU$y=o0 + [mNPmEB{HZyԞaS>AS[xY.0.X ڏ/%gM7 aOP[5iݮ")u_Od//7Tz:;M;MLІn_9]{q΢WTˀ nV'/s} +sn+W¬c]q S.RaRÈW|ۙ#fOX19Rzc &**{$NzR5kv}'kum ;ٸA1'zjs H*),[[.@PLZrD6h-L`R]5Pb@kiVByֳqK6'/ﯰMF$]QZ66Ѣ[d]x C (̿bΪOHL6SHa2yʞ,o{_ÄLX5俸F~9ɾH^M2,NqȾYpbN4%͎U~[ |4Zz3k4º*w*4_`I8oyޢd}6bdV)%BBǷYӯIyc8\ }1>?<[s{j<OnC8]0LwM`g,-*kUDo<8EPU>rnxݼ Af-.)^LRW\k)Ev ;ASڵBko\aR] *_z^x/˜j1Msm~LujPd$B@dS?# na h'Z)Ed:ɬΛFr|m*gGR~EWwlCM +)Opi>}tnc2vcЗ1)i֪Xa\Hy~ܨϑC8T}̤Dϓ">iouP:eet֚a2"uM; gTktvGN֜CjÀ"_ X?l%j{f!z wAC˾A39R˜X~b&<{(Yh{}WGSƸ"M}ɶpr^mtKz/v'LSp(]lϑVSlq_LTg\xbuDQh +5@JgB1.l, Y7@)?u#}yDOLOwu*8ܷ R/55'dB]޹9) +UGW *F]= Ӱ)q>q0\5Sh6Q΂TlJ:t贈o5_YvlI7^vm ^p=71l HL,_= X1 ]= xbVQ3 Jaʊp6[:ͅ|@#:n @ţ Ŧ1UOOq&۫v='~MG&ή39V0ʪUbxUZaCͰtw| ?Gq'q3>Lg%ޣ=[= 3z -9 TnM#zU;{`ih[WdhNY~8;‚95cfv̓|-ymKy']*%azWM 1>z3iURZwz n/>R׈vmN40uҢI~~X,伌)\aF o, 'FYQe '2SS͌,Α#+s%C\ r,q6Cn$F)Z>KyX,]yݏ EDb_N|8]=cGM+/:Վ)+tď5amڲ @V d]`qX9 =3ѳ !ܨul3#qY+(Cy+ؒi{L Rȋ@`dη ~AK?3VD`yŵ7F:ԋ%lr.Yxd+X0eHH3AP%y_fi[,Wg^` .%:i2)ˢnF Ŀ9WFN7K4űFë-FD 8;]'6йN w5DxC-"jC~k ЁԘ)*+v*h dl]DVQ];ʹEVSJW"di4n>:Oۧӌ$|&ΠX6NJvG0(-m4 :66㏲$Vwnv7\k PbIӚMn&|16@_sU~&ͬ A"S5aHO&K(y4UeVj!ð)4y=[ۣL ij;X$R!ُِ` Q8@Nʄ@Niyn*'eUțF*:'`(5d*rZ +9U5|nQ'm!eHo9tfkK-zJ#4Xvb>QrT؟䑬uuuiM=3.#z*ؐlvN[r(̶yCo\ CAbWz/+\^+;䍏5[+!c$￲/͒,BZxym /L :I]qpc=yuy7ܜR9Ml^ΩhB€)ّH6Mφ I*Zƾ)䐡53uTGpjg]}aY!Ǧ ezj;G4^8j{tpr8 랳:@58Vp D1iZiV:nn2 ['Y{0dP(/L"Qf:ZH_ҋ~:]ƥ ,PL%gB۱ѳMu?LpB'@^D "[X5'SrtL8sJ'-0t==ezdk &/w# ҍm@geBZ?i :IŕTL0"ڌؙ'cG.Ke_ pqpVi}QQ$CAm3*)/:Wo:X$|{ rTkgQ\rQPψBLVi[>d+3w:C~!o>; 魋 h Т$bm8hz`s_XU*zMQ8tcs x{3!=6 IMBBwJ^{ŽעGt%ҮlՇܹX*p!{(GEI&TPeUDpiVo`,LkcɽրACz ~uu¥b蚣 ņqj"n*0S2Ep'hRd$^pq(ĨR%wf1ͬ8Erwб|}-;)+mPFk{Gͭ2*MM(sY|̱M`͘V#P˖XL;&/BKg}B -μ]Lc\_rrp"]kiN2yW4omR4 3; aybzbD [Nt\,b`(v~)(u BXW'btZ3n妢""Nz@T~\~H{b _SnX#B-E}$y]wٱH03H"#vc!FTu"c!p0z.ĄݾLlt"@JT{<s´7k9}[&B0y3_'WԈlCX2y iwhǾf _#E%Wt ka[<"1ud+Ϙ/gz,aegWmPK)¬L\U]:z`͋~\O< ~ŤHJK !,QUrG@mB9|T ߶GވTd 9ėKb;qI`ϭsxWIu 6$׾bF-9-- (TE@Vw,V^W lvnߤ?.7z ֭(MV̛%-H0 _(g\?GF x*=y:MXz-83頼YQk\{}c/m~C>dv7k3ݠw3> eFheDS!21WM (8Z\׈73޳Ƶ o_h^p:4Xa> VmeAAot4.RUWb MiF=O]/%I\R_dWxL2TC%sshfIPbXתX]Xj=&#{稇8 tI^ SԴձ C4`}FHэh۰dM!UoJ")ɾ 1{&n.b)iހ}gA2A\:o44`o&}CJW.4;ws 6z`Ju겾MQԅ_Dv;HXK-uNnnw.Ζ8F]hH,<5sk`cf"}2zWA$t%uwvwKBdf9H p5&EĞj{J:o=1oH0rTd}>LC\exb#9lǼ S &Ɗ^ o۹uiVrO}׌; \sedIe4=NݬFK bseUM +Ӧc< c@` + HtꠜNDR3;˂(E{Y>5ȗH .LgÁTt* :hBC$@g/'H-/'9%}ĘUpͶ !$Xaif{t+@j?˫ɎP2N!'n]q@u7۩](Y ]&z:xFamZ_& DK%d +Zf5:3dS@RJ$.Nqohq(~-aN-xE#ɦTu(41R5e-$C Be(.I˱Jx^p_|5Z<ᐨz汾BHJo,[J|ud GZxs NHEJ7Pν Ѽn pc*U +/FrtQ.>x ?Ynqhq]*.0-}y$=l :d2p]e҉eٟ2 6>6#m(;-b=njuL i??1>I4lw5FMVtrm|3ƻ d+:G9 m +oNjvڏŘYy޺E>1HB!9\QRF yzK݉nA;̉,ЃT͟˝D9&ȍ&j cDnGr) 13 g|W?z7V٧`n{g# kj9iat&sO|ADrA-&Cf?\HxjK<~8'wy0E S"<,y |dbpVX?; Gfx(u )2c9 mFhMgFꏏCE<}GMvH  G5&ت}gs&oL~Q K|˽>NhʬʯTa$ʤe7O w,tN DY>3|av5l; dI05d=$&^xJb~sK%Z O/dr4~yuc7+Bm(`wJ?`0!v=ĸC/zt6PFQ0*"'>P=q)=sZr,Gzi]'s3R촠v/wz7 i(ihBS"?)כ6tH ꎀGKD2!D-_Ͳm-2->I#5),dS'|z+XZx R6xvit ɴ=g+JЏh&U/dG&oTsnu7f}z ^f~<u׍ yRq9ΦP^JJ#SBi; i7sbW'9,69H+bҸP"'*-Sh,:&xdͨ#Nl"횳 ucDm++-r89IwAX)5osgwD=o5SN_F&zo @uiv!tm|4 h[Hй .#;;qiGV1ҹTL ޸dIFRJX~pj`4td#u wYTW^O/>U) 7 SsHSI9tQOj PrQҟt [h2j_k3{7qQ)sbs pL&mtTe?E|ꀈ !X] JòB]:mY!B}pdZH:'ЈX"U$>`ΤvD=:?N9l;MI 8g3\[EG`V, >:ͧ)b:A@-6.Z ~%x= ~'?Uݱk=GS-j2T'S8T((Nw |+WyVA8r[G ގ:6vƋJIk;Rļ1.&=ԄPFU5+Ӡuqlnݳ:\JM&G."J&&iʵ0{+ >v?[f_HAˬh;l씉(\]/q$فzء4({2=1u:~'/{*nnwUm=7+H:m>=Тg Ϣ5oN?l: SO[Hi$ebʮT,# vhdЛhWځɹ+69u W5FI%6 ,ޏVjm% `A#jyt⏉ph6n!HUg`ϊ14 ~^(ݛ)r=UQV%Ju<9iZU]X$?#QmJ~?O8LLm%GK6-L|f0l&V}`7C0k~1,u1kH>46tJz̬,l[PG5j'la*'Mu{Wi6SiѝKD2-h7CJ#j.ȎdkJzP7~5(jP.JY$6_Xq WӗAf!O.\hX@_ z}+ jcJ p F³]@^Aյ _M $2Y<@]u&N%veyOljmJL[uM*sb=?sS;ĕK%A 3R2N,̗|eҰ kS S=L(ZӺ¾Lԉe1~w F9PFS4rKfp(zۗSSJ6̝1@;؜G#80P] (K a C{K*jt>+c?BE½Jx/v`!ㆍgsb MƢ PP/1='uA/iu#/eƳMtoxt2fgKvv`~;gʁ(gsVJjP$|^K&"|jkɗۢB?S҈lhO \a94G Z긱!!EIBl9N}f2@Z`S惣Y_eQRH;ѻ)9 Tķ0$kD>t_ fڇ۝#ralD m8[tK0jiFOMlte 1g 5m&l'!T/VFT-?H7atdUkQv%Cu?ˑJ$Xc(6ݿ'< ].A\> Qڢ(&@ywgh"lA9T3bT4GuUJ=B;jՕY7yNl[qIͱ ?igf\lDsJe])ox+ >Pwe *_s:*"V s:};7l0iUµ:X HAVD=@"u Hhu LMMDSNwjt)# BoP8;2@Mc]"HWλ Z2=Z0c"R>0ޖ VP-dKmL ~~0j#vQW+LJ+.8lpi%A=Ѐ{ЬUD6CKk{TC-PkĂI?ED~:STnϮ8GgW57ВRLxs^*(rtF1^Mߘb}K@NA-94_X;v1[-?^ugR@A'3űik,f9kY>T E./ĤXgo{8ގ(ph(:QV𡯝}eщǹہ8 |ȾI>/T{rRӁ8Hc])DadCTgK"Tgg "HYIK)7CSBOX `^M#} \j @B\jIsB|RF~tk=e,fb`v}t$\}h=_6C52}0iK O7k]B97;0Y/cyŅ+:cCt]$fjno1u ^ɨBJ;;`fEBS?[JN׃OKEZ" 3)$q7e ŀOxŠ^zO.N>b @[=Whkv ͳ\+%bc8YSkF\ujvcmN{SyFE#cl *.z@ľ &$LyPsqd$8CDHg5wA&+UY9~d:.!QW|HsQ/%?ɚDkq &@c1 (1" P{mXT"dvo h5N#)Կ*{6 g>0UAM%vzm,'뗍X vyf ܌%9L#bHtJ85dDɪ|D' js.>5YofsênHDS:4cÝ()Ui,qd^-[?%+od*DeTn!`O-Phal5&w!h,0O g GOCjo+3)ȏ6uuA fkvK|U{m U)~$G%;4'o{"9 2%ڸ Ȟ\sa?{W{=tYvWz'O>&=_m’` g(.@L#T)Qٵ;i=zw#5&],M5|^d6M`f CI4hl{)S| `G-֋{,)HZ \{," O&2I?A{/L浝1KgW}-J,~v¿͵;RҦM]vvUSxW=b y^>hZjh1Ax++FT!e8*^F#|_ߔY͡+ j=<$Tq/Bq)OmR7?n4/ =19|w fd]Է.4)OCq8[F5f \F .(km{fHя ԬQ %Z|Ur|H" ơ O gϡ; nEZNV4'Pr :F2V;je c98Sel;I rU> AYqb0ɛj 5FuqlI=B%]Z\:,9INeOVb#EtH]Cp'(0`jQ:lGx۫=CЫDY lwFk%waJŸ^N_oR/Bw2G6K-9K,w*uKɳ>ͩSjIn$LUr*P<orQ<^< VtQ~hxs'sĻ:*dV~f@VX9wH4@A;N'p-NZ"FaCz*\db`ursOn=C#lu8nwi CE Xڥ)MّGcy2w#TǷ|'1/ _S lK)LQ\!HV!y_.w_1Ha:a"'^/Xr: I˖%v2iһ#`ێz:Ih(WQnyg ]D ^/.h.:,/$bjA=ha&FAQyDk%Nϟvye|a"0 < snϮ1=XhfZP~(x}a2%3ԛsjآi,Ѧxh5ϷaxRW}p-0W?{׸ v,q@RNpəBXn@Y`gLa rC2\^&3 ~*m"D\31*fB 9ٱ* JB;Pzl920i nSERcAd~{i≵:5vݟi^m?doSHKd JTQ4t0=ȮMxF^O߼O}'d(JLt _t(v:ksOj|Ŵz\ߍ1qn:JPkmܩm˵Sڎ‘[IWo$)2P].Ug"ǜ(9?'-YRN+0UI0{N\{™;I`U)8e#Un–aplѤg =N+El W{qRW!נd&]Ms8oy k h6Wކie#H#gg9M V6'f3:W,D0.oFyVpg7VU‰߂ 6+XɡM^[/ Eh4\\\ҵI B̦W=haEłhho%Y)r7y[ՠ^u?-FO]TH˒+IM94zF-V*?>ˤ%$듦J6AWb6 3=}k3m,#pmવ< .CPߥ6.TI<Ұ3V }?4#SUxKR$d Q 6ufLRt9?'RerjKϟoz0^XK4ĭ-C}|DPD)_OU+p]%e$K+pE~5Kmt`h(**g޹Nv4\ ;ۜ0X_?kD4Amr{41}a)p$M9&MtPyR6"w9ޏZ3 3`2=VcT$D?AL8˚`X;,8rrRnGV 5nkf%*u> {nq->]+"7 ddzqt̹BzlA:Q#be;2o*A_-  Ϸt EGׯOzKnʜ;cg˙_M,{kWBla*r: 1{&g!NI,3ŜxG?AIҰ y}bEgϽW$'r6y66fNuaԓMpabty'ޡeW`HQ|.~(6N}ŝ7 <}nP0]Pew9] sguz :=" yʈMsas}?@28C7΍bw%oI*nd\uշBoT~!rzl@wdhiRNT<8VT&4* R6*:RRUfsDFXts{Zc8\ɓ>’VL:0AnDQ P.jfF?>;_UtE_/8븧ElQUFQaf9xcPk 5l/L]!D0_ȉk70Ag^[pClJ nvJ0wKܫ$EL6nB'o$,dĻ\`^yEtQt{y Le=4L$X(%ic_AQ1v:^;>R> [$}t{Ĵ "- wl*toMӆ(w̋)pxTJWRv׀]A!>ʫgL. 5[It뵧ĩ'd͟ ̣bI0=*(V_ğlj"(@a,5F`Jd$|vzӈ$cP#&z %-L0*ג%}xhT݄f*c7\JU?[s8Xm==.rCq n.j`r]8[ ׅWQ{lCl@:t \$.Ƕ:JiM|2HSrpv{1ЎP,U@(6Ѹ\oo >#E, 21 GJwdHHks͇{A7By}uXgv!2 ?]*zs`(ϿKɥ4#;H*W衚~^11iA9,/A[p,x#P7XHYhqp=0JIEe֤V[ gj6jrf& ےkw[8?f8CxոctKS]j7zE7$ 2ZZp)LZ; dT$} o5 ^*"`$`#3RG]C!Xֻ,faKx#-%*dJ"Ι`:>f1.X xݱM;qT#dj)Ee(GEX_ͳi0N򃊘hB-q騁uO u Wui(vTdinU[ 0ʳ6?Q׫׺ џ23D"E<b{4 UXZGtpu H&˪l_ F$OAq@C?klA:-t.U>ICݠV.) _xY f/ڂi .oP7ZC*>Ӽ z\qRltaTJ\'s-EvC{^ H+ly3RؕcoRfLgy28j2ET"- %jg ?>_!@:vETR0Sz60"M=(|I|6[ʓ+yߠlOpLίDNư/~>S,M$p Goj J]V6vK(΁>7ĭ X qZLzʝm!e @t~L%YFgS]@N1z$Hxg%Qp!0OOO#,_үKlim5pt`?J5݃5͇csߜF ޵'v8K A6y_+Yha›it$M$kn1~:ݧFƬC=-qBt-MӦRe6BO *a_צ~g trqH>ҋt>ͺIvTML:%[9. w-Au. ȰF,> cJs}ꠟ'jpt)?@쩣xf]+/4Uhhҩђ\zMtY>x ^#Q,wygh:M NuI:vاHZs(z@RYъ^/r0D/ԔRuRU5JOfM2lq_n@?ҍ(X V嗥].Ɂ¸KE] ۸?c˷%ǵ7-O i䃍B|ʦt˔_N-QsgxCf>V%jr ʇE+tZ"F!,|G:p/fQ? `>>ưoHG7~ n|+DQ^ y HVâ%oOX=pų UP)Έ T^CWbDP|k{|Hlp)M yEti?qJԁWRQ^fRJDox"qىyXE8׈2*5pᩱ2Y9GBd  ,8ϓJxwtsMkw3}>|^((]FŌڭ2? " g,!;$B,NaֆQ^ =~H+ATki  FnǃoJD⛣(&K&H}}*u=i" 閺nmh>PE R%-'[x9jb>gUƉDMUH }{1E )d)t 0?[!D;\f 0ZECG`zj8';5GڨlŠ>prinՓc51>n4?L1#PDEݗ wmf2[ BfS7eu!1d6a4+?p^X*=c̹#SbK#"1BR@ّZ4mXk5~ZٙfPz,j.[Cq(t35xQEJp9k/Ayqgte\^M%>cݝ``-V _*h_eYD ?)5  lYI}+Zb̅0 З3JH< =o{tg=Hw`c?\j ?ޣ9S↊k?Fȓoޯ*yIc-bth`\Ž* %ۇ6r7Ոfj͔rȅ^#*eN+lR>;;T2DໂPRc t@tCmX+Hں=^Y -bߏċ ULdv҅du0+yzr\Ĉg>h3:W91/[U˷Jw6G~bK؍,@Ozi:&h d:Q1h[a::Hew'w+nx'{A`  GHC`(F%^n=6hq_+r %T6 GkvE][v %>4֓ SZɰ*&z9L}Os yt՞% A޹o|_Fd>F`tܓTBaN{τl];af>)3vY[LUeBȎ+q6"E{qN=R^z7eCش<;>_'L%2bOS&qP>WoHC7aBab^z) tb〘Ţ{m=bG2hW $ 힭vWŠcd&Nz`re]_y[);qfقA/w&du}1tl-1p݋2| H+褜X,irǁx X&,ge?Jw޻Y.Ns8f1eL h2QrL}Zw\It <{$`db[D$bC+;gs\?ՙ1NCeW8Ќ S0lK?֋i Ǘ*+ &W/ |@7$u"mKj׃,u'D!/Z{*l={2!zXd&g yBQ=WWAVc<B9]b3PKJQTEA'3mvl~:R(kg6&gPnj:"^C%7S@Q ؠ} K2c3 {n] [ܫzjh\{xwNDZ.os֯J}G7P5 KjO^7wהqB| H&}S9XV2ɡJU̖:(ٌ8i!,d|,"洞iDbU3E<$r@!(3̤uGұ* !v} 86>tCCI\$b5bZ"FeS )C}a=9;&ĹhICՃSi#I@(LV.0eHA.x鸞M(Б_^6,@\f:xb10&Urի(nD1YƤmRJ=\I(IԕpӡT{muOXţp M5ħ;ˣM2sPv '@-!LR`\z ݜf"V,2 R k;8z0^5`';ʳ>2E&|O.7F/ME"2/#IB܎櫃)q='j>/%0[R,.!_95Z0_a>ܒ,H co+ݸ[y1 Pȏq| ó v)[S[.-nl)z;!wo1ڕT R9(/D.X(RZ]oc7Y}_ [FΎ# ,*tqtGk `ЫNݵ@Ƹ8l0d_F r ژ OM6#5I2jONlm2,/ +$h "H/49x]Ǟ }1G|B) U1ߍe" fc4&~oP <ǫtyYΑ 6fTx%}ÐX6iF!l2Utʺne%hZucpm.!O װavlxYjAW3n o"/MUCkNEHiU2ˑ%8ڣ'&`̇܅21 xv5&PR߳va9+Fb\yg4 wb6(Ghe}' Žn,+N-M$f$%;Ji !ES}֢uPȞƮ徤My% /nM</cNa!i?ں.faZ4etvPG!L"ڌ* r`PFdA=ʼnSNQ1_) ZS\b7?c)HX YSۭYk'?CzQQku!VK{0 E$%@*R->e5} p}DcdG>'&Z)3݊T~!f˻vVP_DIO40L?Z4n|*\,hc602s\IcjJL[gR63=Bڂ!=-Go:W?׵|,@\!=]ÚE @.cf?@Ԅ׭z6ڐ|<0yrce'wpR+@;Ij`AdF4>Dfmܒ3bwGjCO Q:'ǾF^*̛ի[G:(s͡/HKl)o#sL1"IŎۊ7iGaDxWuF[4*a(MGm%;_Jtp,Ƚ퀾`S< k8w~h)كHO+C¼hRFV d +M;;=lVPϑN=*+]mjn+vUEB'&'Wy= 9R!-Sj7] -%KOhJɻo.2@Mw'xjF& !=/}{%r=ȕHп2=~;u2HNsWߞsZ7҇x}x|*v?-v#Z Bv]yo|sU0Npz[fB!wY{v;KaHàt/Ә_l5EvRFzUGzS_1g|ԏĊ.D2"JSZ?rCbE"6zs͊]_087zHSރ8 p,<2mhmX%=0%`@8:|>sd`6D:B]!g" J' K"LMŸ8{~T )fCg[𡌄ؘ=OwG.NJ ˭Aߘ0W -Z ,i)~[ VUX淖_'>akξCٿFE|탼\IMվQz`g&DBU7nH+2%{2y4<*cX)9 X( .(ǣ>7xi":ȳcK9M M i66:-r/.7U'BޤW6Kv;hRvW26.H{ ح٩ %qmg?cc{.k Ptns!O R>ǹ`GXy%;f5/}t(bE3B|AYT9(#ޜ\"IGNVOCf-6Z{+nu7 .)G?rJtA:68{>v7Svh}Zf3 IqФm[g=fFڼbf62:~ѫ'_!=Mg8'\[;9L$<7>|"7Kޕv]eOp1't99R`y΃oAXJ"zT)#KK o0IO`37aR{P4R-Uc iEtUOa߂xBvi$$F@4sܩ\<[y-jy^Qة[,3%lsH`&+? vh钤:gL5axb,Ě\Ό2)M0"~JlYWSӣQ3s!؂5,EJޗ:MflŘ6Pj5qX}&5MS}H\GmFu|b)Xp[RpCC5/aq:U |-!P682yݺYn%ܷ;`dJ#\O&+y2-MJOėT2[֖^4F"4[1s m$hd.%]E}r@H+`FnJ&6l]%I<ΜH[5U%K{7h1Uk$O@bR'8/DTn58 <X]GTVg#kѼTLqdeVJԬ&%1N⢁9XKua[%Ը[_݆ƪ7j}Ҁxvc{<"ksBa/\o:/LsRi<% DouʻU@U Da$CL}7o`@sӒ*;vP!`EJC2d-DQ6Ʋ&az`=dRH".er5I>Ȳ~⡷Ҕ"'X56Y%lz05w{ezXJDoj) ZKnU އ (*/iRGLH7ic. Ժki_ʗΘy@JEϥWMVHRzK9h+x]QoۈpO I =#&4Jh2Xَ-Oy%p0+2>o'7)X"0h@v{h[㻑96;7fw '+&qAx-`.bM&<>WxYZǪgj_ 'TYB#$=<`EgQ)Է?tvWv.BhY =Yݸ^c*,0ӳ1 E-H"/WLa[Ʉn>.؇Z~Mvt˯^&tpϹpL鱼3b˵;\V!/@Χ-b<<Ъ?@1/ItnD}!M1<w؆)"KhC@s1u=a>+t'F7}_1h7 N^I1=[Cy0S$>~6$ 侸5[pҤ&X`JWu `/DUJB.\,9(&\w5JAftAw؍|(QqW -5UPb)A^%0v`!45왴:k>Ug cKyοL%/gNK%wNv0o86@FuBXskdңc_<`57_^Q=?qi*֦:yU1V <^B{onBG%>H1ZxJeVmM  mG}WgYuSܝ_9DN"T<c^lYn4"\ҍ`Vypg&1js<8\tiI\8~N~SY&{FFCF4Ad1\Ͼ L@fWu{w0mXkݗ mu0+mDG%ЧduU (&"nzmj*Qr Bw½Cdy./vՑvDk ́uG&7Kt9XV[K2ﶇ BeE  18U0w(.]٬K a~z>.}0mW%3G˲o"%0 EkX[l<'K`zr(_%t>HgZan锰; wBp gE;XzkwoP=囧d<.?̑(Bzb} /RMw.tOWڤ/6x{fBܡ^c9zqm& ,~ 3a:jRcTogUFu e_HlQr<@ A ~nEm5XV/U{l)yI[/ S_bw1뗑clte)=sw먎5kLWmbq4 0;SASmyJhZԳi!U .[ߋ'Y}RÃ)* hOlUN0W sc`(S,`,[q@u R9Z}BaK?G‚K0Zp ?KI@ cvX<wܤk$5G߃@ *~1%Q+u)(~6KT&Z 𢲝OkFƓ'r5A_:'𭓩6|Hm_j^LYV\~ԟ@g8uBKGWHb{r/6KTFbQ:q/\8vx*qϔ=OH%+ []ggd<uZށ(ܯVM,6BC/2GHw*?i(*ڿIFZ4yR*?JϏ*{:8 ^4š<~pIn|'Ht=AOaaүoKU4!oe r\0ms΃g/nLd5=uGSY_N|8x5WWQ@؜E!!oBgkaL^T;OkJ(&ֽg*79;*RȰ/!WнqZ1s&p5SrdT?e*^[+ \T ŧR%E]I.#` YO!y^MU.n4f̝\q$0cgzT 4tl @-H+pFXAH D& SNXvfҰU>0z`/>mjrV(#'׽ J ïo0 ڳQN~_D40r]j nGYZ.\6uR[Ki$Uxy,L\1FʵB20(ưzm-N{V4>BDUk:RZ"ɚqv  l}vxT`x ~2ykKW֧emTVErEѰ18J{IZV.Pbz9l:% |-vloBQu2GNEk2Vf2=*ЀuN |ĥ5ͪxAaئO{ ;y?٤\=#WаCMDiBw/;F0h}8OOjcy8ewM#]=C0 XΡ7xP xh p&-*O>E^2>)ta\29=WZI2g.GǮ 8YNhAK>%ۡRE?]8{(h\:TY#26~+ OR۰vA3!So`艍"+L'◿Kgg4bMZ?ߘtϐBX:bDءg?%[-&ɖ0]-ăuοh NcHaP@4%JF?Q@1̯(~Q0dpĢF1&/~IV Ws gԞ:QbP.Cǎ۾e9-ED ncqỌur /_h5TMʊ rjO*۫* y_JBiҒG8q b1)AD k.@OԑqkIbYVw 4W[u[\+%qE? !) q^;If3N,<ˈTGw~ b4k! EڮuzkTB) fUdPQ~\uķ]o4\;+)dR;;<QOp_1rG.,gcOyOFcfN'pIѦa0?.W]eK U֫UftL[+F "jc <$Vl0{q0sdvXl/( C`]ҒӔ]ALIn,qm,l1>Zl}s\w/=?ԯnapzĹP:7ۉ_B qc,ԸRcvu9ɜrze;܏9S:jx2P5(x?zɔY8MPNtRdk1pP7H[p?K nH}sӦTS[V_񑱺j^z>Xc-~eXPWbTBFo>yGU5HDZ(Inr8o ` ǟZdq?H._'"AT[܆K0 $'׵꾡-MuXL"2?o}MM?"jw(lRҋ`M(I[NGfWh0K\OZɼ8WH8ʔj*N ^ v:}v ?!l49AB?  oT Ed dF@ehK 5tJMTAE!* x?݊HAו* j^ Ak&᚞tkA*. ߥPtt=sϟxߕ/pꢣ dOFl[Rb! +&7& RHjmTZu\qVT4x,)z1QROd5\.aHC7]Y, qs76NNjͯ+&tա~ VWlI^rs݌܍m=SL拿|z$^ p~ܐ :qE2y,\Ў+ {A:2fL=E[Zb?zӣjduZ,8{/(Z+ԨUO5!+rªh<ŐX U'kT!X{[#n 7P7A7qmnfGS^+_BAjD(=*4pVc;8}`b^d&:JO%Q-/% nW N]T*A~!n]-l]qJzG~07L ->4yKe_dQPFk *CoZ_wvaXƷ{NŰ-MUAz`g{&\ǾU{k*lfYzf3MYЪ8m\H;1Gk'YB֮7QK꽁oeRh+*QKA0$j||d&9aVfcK옶a.KLN-;)ҶA)3Q;뭌W&3Kc؝HO =gxcJE/Ͻ!j B]}6Vj,^ʳI+5/^/A**ڑ)2TAmd r:~> ;El)3$ ALT]6}7vR% RM c$[%;Y ^lƏ帲d b+'oCY%Ihq}_U:#b2L-Br X.jw?0L̞zN}m y`e'Y'-XE Z7 4|K3|]p,3OE@~^:&$ZU$}DaU[m,5!}RIc\Ǽ@ӸCS|1Kin9Y7ː5/1-vMBx6D@NxNvE# QL29Pz@z6TgQNIDL<ݢ89r%#RJ1Y+=qDjl5pGCvij(IYTj͍80յD#hj0=%< WQ(׀N|B81ʶJc7T*]]Ji:n?{mBR8}D! (qI'+ 5oYQ%yNG] )6>iqZQ$w?|6KMcaY3ѳܞ)ܫg:r xTn#f o“hzMwp2$;xqFb8F34#"qZAOS: 'އ L)z 9yS?)lL+n^Lӡr,LB2sq#N9 #u8&܍ 8UR/lP3R~uVN>"5n,􁤍gJF˨@ "r1>נl_)J+6_eF:']ϗ2"A, \7LgCVv6ˬQoJ7ۇZmziTp/Nރ(^ZBZ}ˤw}\U\Ԉz$'m2!v̕w%&jW*- J\>LmzJ`@}Lqlgط7˻{"@r࠲Jtq;.]nkak؆^\)Wf9_{IJV1xr9!V}L8Ɋ 0t.1Uf+"%i\f !`6Io\<0,:$*aN˹Ot.۾QbQ+iƀjJ6nz7AIp5 gS'#EK *ڎWNu9!c[4 {:h.xp$ungF{ ?gt\RqD#1W6۹_~*V74|ʡD-,U64(e;H}}wx `{|iQȥ|H )7IIԬ/N})<2Gg% Tl1w7"|l+LU+$bSZNvʕ<KS"p8Ⱥ|Eg=Ow C3 2hOeA[*r*“$SH\L\+QT,?6\;@A{,si،g&:8QS[eZU:U4 ̴uF@M?9f6~2ш_'mѭ'G*y5-1r* -gf;]#Ȁ誳ަrgUIrTL~nj{`pX=-¢1IlgX+dc@4`+#[dӘ+[(zRϪם)^a`0uSZtj%::r*q2w0> -Лui:g y8U/; EWSvă!1"k DNS!nI8C޺7f-R*BsQ(dG.ڒI! ui}㿻~fe#&/A IqCZDj3 aĕgVk)S4="dbn'`DI{Ťn*~Z :W.Xغﭾ,|ri 8#ԟL݅Bo'VpW`J츛 V!}뽽@>O5F̥ vtv5Jx2+DeC}i3$FE k[<=EAK4xَR0Sϗ\7㭡,LFr[JVT;t& AB];{a ͔ }OZZkP{A8Q0b%`SY?e,lkőA(XNu0Ɯ`[؂0f*u}a+!P}Sk*xۘCM{Ji&i,}]Q=Ņqi:t/TH @pc0h{'rRLR?(׻~ExQh1n=a'##F)Uj5籓בF\ی \6!~'^}H5GQ-Yx /.;o# ]OSy{2'OE󆂟7O>_S5#x, Yq K R@.]e4/N-|,5ߠ9C{ł.qٚ<#l_GŜ^uG©FMAZ e2;- m]<rp;ӒZ*a 45%!3j'Slo:ibY1sĂIֵێ֓sytbkƐ,eg],>*6 yI ic#0Sd D5VTRb/F 0+`=E.8X2MMkg?|nCm⛧mc˨Ԁ>o_}VQc=hήbfld!$Oc6s`='iwϪ\vF({"J<^NY8j<,2[ "Dj 8TGO<aJ+IPHn!3WiflycL܃; 4K OoUy DGH ;j蛎]"<3ϮA?!R #G?8/-PB荛) tJ$ A^~2[Wf$yD60 ZUHIi>e=Cuv>,_2 W=ʉ;Ɇ{q1vH4y0° wMIaO cizPg$CCΦ@ y Xe-'H9 vEK,r}'&UCH |fH ;ZPpzkpVmΜ, VFb㖃nXbx(q!Xi ɲhOE)s-'Q.PfC3a*.`Yk7 .E[('}jI# LB:{[ig}ꚆC0:T F(D3ޘP7cϮ&\M~"TO~Lo$l6Hk"PF1S[M[@;udfezt#Vzs4=oeĕ- DLAx#Fj;Q##}cX9pv9̠h} щ{_w9+2k*kmSXw'&d)Mgqz;҅=Ȗ rv4Y+>Q$8o*⌷'?!V*~j8w˭2$kQ%fd͛lcDJG,Xi9vϲ=U& 8 Eq3z&d[&g7ƺ:}dq2uImzFk*mrgnCuk+%#-s*Vg07/kux)tdkDFq% ǵ֊R͂FFdwl]ch척sC3y{l?TN R,nT)E LmTJy%]㚳Š8Dw+.A?yd [ K9ٸ|28 4dn1 +&;;):y/P_r vyWcሸ-WE;WEm3n}rNjA;X(p Te?r!/QB=R]#T'1@;/pU} %l6BY\XjO xb*;eLvSѵ~Ax:U[0Bwl'`#ҥB)/_ifaX> (Ӽ_ui| 8r(kC#?Ιty G׼hl, NnUy"{Cp6 'o*j uۤFj٤}^ I"TvXD!C{҆,Jf.@6-{:FWHNN"j72`}|'#j5ezhÔl@J-V浄n?â^yTf®DV͚YSKQHU~VޝJ8T-}ef8ʶPt'ooSg~O5p"qlv12p#el rEb:<WIeBMzsڼ0njM|@:f^v":=x)#ŮL~:ڊ$!@tMVl mwsGbUE&<\dlMMwdBb8V9㽆)LZSLѯ1znYHzJW^b/9o]_kr|2R\Hry3{ >u0ZEDp3.ԋ[,~?LI2oX'8wk, K/~q#J ƒ'.܀5ŜaPoLFM"c4:]K] xh#5dpGCgbXic]{Hr [!F :y%29 ճ(ݦP.z" c.<FטYH5ybE]VMMBÒCLVN}5%*(VωǢ>Ghd3H*?O>!Wn S!$Nrc@LTjXvL\0cA?Z@g&dQ2-xcyM3yxn'_dX\7Aԣ|D.mb@@XbE,SDXVE\Jے+!:{HC`^p1yk pj>)ХX*I.PSgawb4kL'wy>d:w >Ey$FS[ ol$WV&beldxerZmEbS]u9Ȕp=)Kz8Ir -(Q=JϺVă%38U<̓cֱ8p0|ݳŅ`N)#JZs3J. -yN)EɊ-\!t'ӿ X}cz4j;pknt;yJ#f sPH8ò 1F'E9n_+k&N|賉8\^aߩ5q bb?ybl"9j)"Omɞyd?s.\X͜9g}:p8nI3|1PFǤyAcf&P'hmw |Y>)Js:^N6m R*׹zT0~ g\kTYN6CʩH5CݺE2'ꥭ1BQc3ufI$pl_0[aK@O#u?)M۬EB.%]9JJ]g!Θӝ/}}8?EdH7Kht)&">QS{:Hnw"?e,#dGx$(*۲ܦp& Nc.S0jؕ r0=pܔT칫m~Gcp57nT1v?!#:IA;3Ds6[tAmȠpT5]w%vG4i +.d庄B:u=yk`::ya:23zO Uem]w_q$j]^Rզ(b.>SuEGʪ?J|\H_[mQ.~'XddϿ *mS0mk=@)@l)<7xdEڱ?D>K1>`҇B⻲tC]4<p J@O;rнSI ;ȋ- .1rrHG}ng@cGr.[UV촆F䨝l>O~+I۪oӍO ?a Rz!')3|}B4NPlJx.elqR2Qbv[xc:/as͜`RERd dg N-DM*.L[VޚF\I 9#0ghr~A\& IӚN>N54Y al"!m7x'*F[?V<ڡ&Tz՞ec D LKOKQ+^Ѣ ;H@KWR2{lRk>W'OK_ŹP% P&5M_*>X$͢$Z 5tFxn'^Q |G=W 0ƬlEd:~wG-ߏHi](A[=S?`pFGkuʟAqͥT>f6(3OŔ0g\BRtB7hKђ˜Ơ-QM^nn lן1@vT*YHw.I ]խ9z>/#奵M6Vaؽ흈Y<ľkI *<6͌ 3_G  KE'?^W00A%)SS(pgQbk9 SH.6u期"z}@]TO,T86-& }  ൫p"iE ?qV A+2Egk La7$Hgx1M1.#EP1rZ8(1o" 8| ]XۊGJSoZzSo#OQ3!3:z;XuWXQI Lh^fvEib`Hn.jBǡ@*{ϚXl&4@2*9zPs0 K[)\C>g|Xm;CQs> Q{h{zF"0$яF|kvP/^O17\+oF.;yt\$ڝ L1`I9R !CٔW!>O*UQ_m@ rV$stzFwqX!h9XU"-u#C{u=h,{x66T4=:R[@V]- $vD KMhiRʅs) %7kdL|O*=╄z\"9!48?E]# Vt2ugVtAi3>8&zBc筇4m nխC-\F sd\ 9!k)[^DW'*\|3`1;u4BS[cpU(R#ƴȔ[Oi/oF=뽕s٢[֡S=ֆ:uF9wIh&"ո[m[KT}ѩ E8RL۳sQN'!aԷzRd&9g,FH}+5! Dnj@gaջz~w= Ώ|*yTYNĤĬɫM%'# 0wF~REI3Vr'#@Եooe,fcPj{-N_*l؂}U({eO|2>y 5B~ܭ;98冲c}{BV5z܆_M+=7D{_A=1V\C24B ,itphF&!X]-M.@QI˟V%`!y$\F 25!y< w|EMw-uFj^t뎇U\S4 k Wwtϩ {Jthΐr*$ gHZ)D](MI楙zHdj=#Z 19 Qсh iɰ+u9TX.b:܍zH\_mơ&Y}hH4+[Xc:hZbZcrޱ>@G3Q]kzhw-0wQOJBIJzMko([Sʭ7fyцbl$0WA:ixrSOլtY6H\.'h4J`-8@ |rWu-R[:9x,DwQҕw F"j5րfBP?^>^2~0݅'nyBD ~K`:J8@$K-TuCGZWi94(/>:Դuc"@t0} @u@HDR:C.W J]8yU l CZL[.MqWLl޲rƼE?Њ`X45h4嬾q36%f 1(p/ۆпDeAXsF9ЯL@z4̘itE7^+o8myz8f-c8D0] flv&KhA,_vy3s 梪Ğ\HBRO$yWjSJJ<T$7Ǵ$4mQJA-y_Y[vQ0NɆARTBxDkR (Pzےt?6u I샍 )U$"987ΎoͅRmAw׃li.Ӥ{gCJf&c$}ZS;cfiG:rpE1&p7iC՘K,'6MW2<xK ,1 DlRIPFc5} &M+b(^oM%#Y AV |Ly3tml"#aOL\Yk/,gvFqIVt'5XDE(wz Qv4$}c,uUV^ZLL w#j۴ER6=R\9nT5XP ΄z@x-)FE}Y Waq2tSa.b=0HW0Am>N-p]tFK;>Fvδ._H ӗvбߙB؝eMwM; 6I[[Vv6ܑ8MCI4 D ^ĩa'6@T4j9t;`@{s 0*gL+( p,8`Zx,rs)9]@' i̙C]l ֮8 '*c]d*H>>R<׃j^J,)BnQ: q7rFk*# c hm^5 E7|{3 %$JU`N' lu . !q+3|VSed۩UL1LpGAJ%r> U Gf|$0`1boX=e&ei 9!m^3tkXg(hq9-^թ-$5黸(X4GI݈e1)ܭ|BU:7:pe6 ;k7:dϦ $ET^=vC,"cS&B(}_w °O) o?ޟ܎P 9\}(t|9æR8^Ph`(3!8P#eV;c pߵQV= M$i\Xd9][x& ,bٌUg0x4z™6w<@:li% 0m6G[QD< C G=N/aʄ+_asU%&skdi!1j)ȷT`w8rZ |[-QŢ>Sk]CvÕ"Y" 4 D|τ|Wr(Vj_x&%ϯqb2V~4:hHF X3?)zXqK Q㑇3p!0bFx/"~ ]>k~.|Ȩ?8˦DypˍqɞTy_QA#z]TQQQkDGT*2O5o&JPԔG 31ݡanq$K',;0ؙ"P!΂cu7 zjS{f aLЭep0j ђ}ad[-C|R9;s*1\aͲZhKw%J 9Jmjkh;7BYjm2)9O_GwLtt FtFӀf{oe~al(gO5b N{XD̶3$Nt沪[@S"T)jcfr㙑^+g/'CNXzȑWm+ZKsj2]J׶[k !fbІˤg Yv\uo9*@f+19|:2Tiۉ%.5 bv 3^  amx!MB>MߠT- fӎ. ^ĦhOV2LSdB,'5XxK<{' \*&? z[s~$TP)iA0asDrd~`ʱ H4jϨv2fJ $2^CC\y8j%S\.NɚD.S^p@uXs74zVM;@ q^$Sj˗!dTHe_BX5>P$] =ՒM$ٌB3JHja #WkWzsM⏈%/KyA,B ϫ;V;6yYbЮTOZ?7j$ۀv*@OhE @j ;4Z`e*֪{:(!6h=Ȇ IGe]'2፛#߇ 2j(C[`8E!YۨIѹ_-epW$uD _5阜|6L8.ۣ6d҃M}ts+_2 .A2u KD" Vx&1Ҩi/ciE&X>"ulUUlm͞uxB9˱y$W,a;g=M[.o/oQOG.BP누C-O"}-tiiO*DAv1cSCz :Zg8_piI͊ ]?`"A!S4C:Jl,2ik~btb{uG Eh )h hu%̝Y[_sj+tg+p.9'q 94I_Z3J^\[-IRF20 sÿKkdjk/0Ic?Ye Tu h G)wrf3DSj;;}-X@5(zw{ie˜UVhKkDjizbsE+MP뇅ΈpßV*C>B.cwn b"k~䶗>Qv&hfKa7N.u=A,%NZHRBg'חJd6U4+n޵P |1ÚY t/e*@ҪuJ$~9r:H 2yǐm4G8oRBVk!en_h@tYaD Wx{;TNP{suvL_W.Pȿ6[ZYNo:'N$Nv(TuJ|+6p[>mXʴ旈FNV?>ff`X-en&v Z8@r.ƙ;8,#mY0) {h(pmn 1I% vf(CtАM("R)¢Do 66J8t\#t~(C!I"fTc $)pg y-zZr$BW;yQ"EѲ^x۬J+Pz 0V+XU'|K^@X=!v/lDPantlMu}3:bu&uv9\/'@; a;*89u}Rd_L 'A|2b6ocG&#yBw!$9-3;G8[h[K!C 75B[ dv D30iHng|ܼT'#cߦfȆVHJ2"ʂE ;\:p! ˑ/laif蚕=gpAr{vt_x(1N Np=ZE[ᑢ'Tq3%3}Z*Z0;y\yxIG%n 8) $udzr z4sJ6l !Nn,ܭء3Ls˯S0Trb-sQHA U0Kϩ 3H]zYN鋨a7$x!/V y(rݙ+sϐ\"Lcm+8ni:  ވ Vu;Ԅk=>7& lq~Cqyy?>J@H uCmYGE'Un\E>NS(E;x%##5ehP QwxxK_q?zy#_y>U6%$:L"3!?3ւQcWRvY{9G身 +n{bؗ?Ɲ4acxXXU8{U80 //h?bǝUUDY_nt|: 0rH>w^6 w@:mz+?Mv |6#$=Gro\nkkaL%~ y ?wI "xa+YK[J bƋ a`#GpˎwY;QӖsJE^/v> "%rUD@WY+[>㑏A=ř]= k&GnD,0lҠ3|}gF3>ϣN; ,F#-+b p-Ƌ#{f dЪx7Sɴ~3[ M z/cmZQ-GcVJVE_D@jw֥1|h a( thϰaMlR+9Rٌ0fj6sq1!*ޞMC݇6Nq%.!fɶ$P vM0cXm|C`26rn fmT[NVd z<cbugɃ鳛5/t~_iu~xrN-gb&Qߢ=9Aԭݒh{ig7pL=883 U/-\HtMEuz4e豣͟?3Lb~ZE=dܦӗ\|Y|pЉ|"'DT$kSLh$Fҿ'WS&i;[,ze A&\O.Wbj/bs "$v>!Nw>ь:UUuwZ#t虥Q DžuDsHEp**C͂|swf*loSq.P31T[*1bpNLp Nrp1:"D!~p!*݃5V:]Ԋ#~{ o 7S l>17zw)pBH" v2.X.d=rٞrFS/^1#'Qhka:B?x5%.)iL$-c&yHtvIb23l2> >K{ۃ|h| ,lP uv} $.;'>ҽ(؏(JzZh,Jn=&G 6-ס`@ 9!UQ鄗vD4dB>R]WSuymAUf?pt ddcir-kʜ:_|}3Zu{?O0F5MLcB p[ߌc[|$;nM@ySN3^%y2꙲LFt\Ix$[|쭬Tֆ'y ̌fQHBd */i,lP D|A;c*@HʽqڋTšUo1:8 : ,G+k1yd:2uvd9%,N4m 0U:YQdDlj8 uh{[,9 A0MQH wƂ6/zTYxAO6X"zY 0դ`n'VK* M؞7 uJ15&-fv%LN?x'ƱBxRѠ.AHُ1>'oՕʩ oπ6`LvjFSω]F@+-9"*;YiI>P=>*ʒn}u0In MֺHC-C&r 7 AmD)Vkۦ73+¾!sI[b%Z2],t r!y]/춖^HT1}5 RybҸ7=U-bCsT $3gj9.e˧hlJZlZU6*O(k,chemg+=VG阌ԇ0.&q{̵߼Ϩ>H4 Br+0MS' qعXQ+#gB?n 8[ %~W̤yG<\$˂%Ru u'HF;%rkʯYRޑ<kV]30Ld 0-]ؕɡ)ͣ+HX'j ,O:b[O `&Yk ?e$%R>{5Ai2z^Hq?s'4*w`Ӈ.B_- 㮗e%#f1 _ ZV,#<4# #o8~K{#ʥ$}sN_OU;5{n F-(Gg1vD.GqB]SC ͆Y (n^E{+նJ͒=M퉌0/Wfŀ$j;OxcfVQKs )gYeX~K]b&`Ee'=u]9 砙Q/wm:ɴs&D\,RS7#6{ij؋u$/dB|wp9coa{0C`9'^Zd:j9T6S9˳ܧf T׬Eɚu%nHɕKTIm7H+< թ{rT OifƭW7 Y#OP\l>c~8 [fڡb3w3zzJԡm6[~>624Rgv'RaP#'Ak55uzLjR_SaWrRabZ]KH$+- _B>)V/UzеbD mGi(Y[ vGNx6._h/ -(sl 5BbDZ -śŞ0xo -uz2q/i4W"u\]=6}/v-unż%)v6Qhj4d o^j?i" >rě9ŭ%ZiiBׯkJEc9f)o9tZ?Bi3`Q_yrP^ѫ'_"UOC_0 v, 臠EΞ=}`/ʵ^Z!9*Ӊs8*dj  !!c˩ mbQ`-ơۣLXxA_t' S$tBY5~_vPvhݰsS+?既i{q31΢I%Ax!hu."3~')ǃ׎BR\mX*8 r4./"n(ї1?2Tn54To>;|?XPJ# > >\9;|MU%HŹ0<7_HR[*V!XUox;q8:a2;-uC9E;hY!@d}]' +D]XOlkGG#- g )+UV&v PJ'~Ͼ֑ A}EIg?amEgO"¯|E"E.2P{Rجm3ޱ.MK3*j!\V{STL%k(y|sfy*Ӊ.w@IJ M?fˍ7Y}.X~{bs(6!FG3iZ*B#USxt;Cm5F ;{>꘢Yߨs/8CHzD.qt!%4q:t2`-V(S(>NM?/J%,^7m.:dp(!sPP']݊h翄u\c+܆/IVWI1λi`_X$>_"`HeE#,GNJ,3D6Ǧ9bLg"Pַ@Oz1 g'-ȗK~GYvM`f4Q 55<4>#(uI(">`?Ho1y 0|՛ c哽;|~e. 46`O1N:0ݍ~Opft@;% -Ia=Pދ8`e9wnY97=qׄ0bwtY1n#P=\$.ÿ¡aW51m ˥^]k*]J_ۚ9Ǖ~JEJ\ˠ G\?Pu)C͆]"n`VY5tvm%t->¬ZʴhvwEgZr-bRB# 3Ř#r"-ﮊ@=_8Lu:P,؝I-v*O͌EԾמiF}&X|#_ZDDHa,Ruz;v3~^tA8vfCwLej:+~1nC5[ZM1>D; `¤yMiF@c؏e}#_J1 ݐߨ}5}+d׭*tO#>[~=G33i֋BWoePV]*qԭc%59.> 1u"`wT3Iu¼GN[>$ZNpB"@?f["ƙ T]"U4k"MR%ͤ! d쁮4YY`?d=륖zn3"#\u|^GIC6\aJC3L X]@8=6̽aB7'G7ӝq0r\Q&hGdEny;M'S8(ڀ%= wJG )W{ LJ 85z|6ik=WJ caƇccVp}*@%U)Q=8`ľ?kKq,ȴ /Jf3-&HT `F|[$ce26nOB}Wx+'\][W4YVj-u-G/ A KPbҷ֡N&B $Fbx5D>WL(@ogde5P/̡,}c궒jtbuz6W{ !$m*ts)J<&Ku.;LӒ|Oc0.Y$@ C2Rޣ@ *%6.i @IFNlw9/ "u gf * C"w;I`A`L)?:|qIx؊c'9&5:/&}Xxޮ* (͞FL)h1SGݠGM F_ "Ӓ5;AaIO! B.]9kzĕ$(x)>TzNZfj ZUxfs6vQtuXA}e";'f"WsM8׈ׄG;ΠEC AxȤޔ[Goͮiby}A5)r[Oʀoix*m U mӛ!T~^*vOŰwȷ9vt/KRk?]Êp~K$CNc1;ܫ'V{M: fU:}d7{h(,xZpF=3$g;i? ~aYTaڢs ջj6f' a>stK''ܦZ¡tu='v/w 8uڒ엖Vw>fIWybfzM ?G?qymwSa=*2 3DA`{>/)x`|e.(P휰}3c9 ?yzB%S* za.ǎzBG7Vvr>|捤*Nt^ߜԃ?9r,# $O`f^ c(swq^WCgM>Fhw#o|Hli3?mG˝bȘԢ;4l_< f LWjlcr`sx BǬ͚^s`+r{ fUZJZLnN":pe.ա-9JײfYC.3=8dK*OH."5kkMLӝr /<{{{*gƅ[lhRDR--bnV'[hsYX6td?B  xFcR#j,u%*j2/.Ae@!1t}7 3[B=;[QHW~KyBhA4wY'-Y|q0kTu+[ZΤ.<`OV5ڋ(OXl040ϟKqt$6ʛ_75j.\qQBdߪeh-gXBjpvC 0x6SͩQ"'A>{Rx݀唶@a=JCn#?nUF%5:m'QӫhC0W;Dbk5A .Z=o$QVi{B9byΜ<ЄG#3 S| 6sxH]B6Kj1D7GH].unE`.U]u֝H$ 9F'eU8z2dJi>5n3B,P͊H 3Hqk2cA "< 9phS'ywC]TH.1P+!2Jhu/6| ޶f "uرp8$pCcT//7F*5V]Rȋ80w ԥ"$u~yh5 ;q8:a8N 9Op"1Xu\5䌾1ZwU4gpmyfl?0fjnbM㬂Ajxa}>aOk>h\x.2X|6,/&$814GYZ"n}@oÎS&=ppFdCovx"U3HB @׎OwgLaxx:B7rgs{L<$[@(az vQ VžT"x,AbE!rfiŹq\)aV5RAϣdFJ5zل;3kw!u:f ?ur)?LSo}y̺(ܮ .dga 0!{vugѕG%VUrtN0Vcu Q^HXvY}OoFpQ]k=F^KxXʠwŒwZ;0\?:sPS@nw3fT#%w S'7ҳ TpWM6N]xkJY^GxXJG~_1o(5[~D|Hś:L{,"0u6D6.F!"{{85"@e f(Zw\=7O ߰*tUX:JTeCڐ޼>l_Aabȸ)>>̯$&J+S- x[rES*3c"a JʿfP3`f1@Lmw b%$ز`! ;/Uq:RHrm ͓ mT$d'X#9ePK\w "| ]׵yT(\S&{/w%SaZQ=]$mW;Z}yoZ$@r%CݳlBs|mdӤ^]x]`\L6"{=3|}(s䪄w.:!N%e48#>U#ltYݰ\C㷒0rŮMtZqtvl˦8#E+H\B{tvEԲ6#=7.j1g=)LRC q%k)]b႔<<Ux µ)//vstcogSwbR[ڴ=n ?5_e?'ӜCA 8"U4Bx ӴEjiIYq<]ȈȨ"j%_mNwW7bl'z)M*j!8cl!.:Y}G/Œ4y!&lYEYR/E6 sR|g/T:0sjX ӞgUnz5V.Vᵛ>sɓBprpb-ewB1G,l!É ,,`S!gabHz`ͥgD>岯 ͡rp_l04˰=EZ BZ9\>]FU,"bߪ'A >S@BAs[؍ %e:".B{R "q\|~H-4wꑸfL8p-TuExfs^*wpێRf% ʾ/ lhR/ ^(`{IM).Slˡ%&O Frzi1lLIW~D!,+<5d„@L]]KܱpɠleN h akyp KYonTLRhT%hB | b3jC1ryRk5&qȠV$f s TZ<2Yb-7&%xf wqdjDZ aG,MvM s,)6Meg"hG݂~g Y>\;WO-t*m[^G*l^D@ҭs_q(73E-HR/Y$n7J4|5֡>d /'Xorsh{/y Eg_cokH|(eT~{;S`wq&~q#2v7[^!~8lbs8oܵ"q.@+(91q$0.4]1Y- j½Gl<ObQqS1Qs5#ҹ4^YvAh΋jE; >qc[n A Kq1|jc9O m:f3QFM{5pKez K _?jML_BYqrp?EdXu9SUdKt~}k$uR Ы Ṣ^wF+ܢQv}nNTgyɇef:Pť Q[<2ɰS>z0~AxZ<ԓS āk5~ҏxfWA2y1ߙSKW{JdV6ei.r-^O^z¨LTgӢ TLya*L͕a4-Rs=Jsj2x,wr"4,{VG?ظDyQ^o4p6eA=/1S ]dİtbҘc魑;:vVUUm?b&1rA¯"xۿO<m+-b]3\OO`;n/jUyÛ@b(?4Y@{quUhz2W.!|2svT~~}w-7,7:HAIhD}d>KA@Q%rKФG(%tuU9Kja~]DQ<&|[Ĺ2/S)+=Y#DZ3'zֻ @@;AܓRlYL[ےC aXCOaX/oFg}1NΒlt}]3BV Bdw~]/\0܉GD; ,s7)0t!WS*q3.B1]Eۓ[&*+1>j(Jԏw h̅i}3kiأpLǷ\E&92uSXD͋hs 2ީĆBC%i#mz|S{#}GUۢ'if)ЋS}3;nHyt1ߔml-"mؔ :YafQZ回@}Lbvx~J$z7N!P7-5u(!l']]G@Gٛ5!pE(ay/vdA#v\ ( ?J?Ļ 88@ Z,@ъ:~Bbƶa2ZS5r> ~OIӞ|,vUz7>T1.tVs>\KIю7HAa=љm!@j`>Jx,E&VLhdN&̽4f4ΞyeK t`6'0HJksN' 5 Rr0+PWv4E=(<#պ[vH0fdD'PD:-32i[:(%TޞJO3!Ic#Jã+btH1م JK ORD*y{=4SaAyS:5 J!Ө[BNxl%T}=Is VA /:9:V?'WmfWS|̯z.)L/қƿQ7R$ AiۻI{G5e:lZ4H(|igQt޺~[IȳIf {ۡ]Bj%y<.<怼U q$5F¡:qB@pWy9VAmY+Gr&7~|Yn}u'hE//6Qq&3Ro}TKߗߐ:}? Pr)wlZ,u/Ez,ipvA#C?BSϘ>X<|eYb-!T ?0^># h#,JV_?_h]y^ʝp Qn]R)v=<'l'#کbZ/ fj\>r-~R>}%#K+d&tIsƯ-!rIZz[v!<'ɿW+N1K p4┄fq)"O{) mw Hv_ &F[DR# ao?a;v=v}Dnl~ݲ EetpA#28Gv-M0 qgG=7~ I} (!?3I^wױFYS|Iwg埇e"k4B C[\}Ą.@,Ţ&9&+pJWOc/Kry.sW2CD}|ȻŸ]$MNBQ̂IeiDUyY!OUx@盾{WS- k0DIX;X-%3TE m 2s{3?JacWk|n%@Tf`l@.?f>Ŝ2o[[ ~"ML{3fE_zT̚}y b1m:;FAkQ:F !r'R#mz@W6&n8/ "q΅>GMb1]].5 e""}pΓFdp7v2Z&MуboF;_Pj+FЕ'E.sՕQRſ4w#bTn73pX׮Qb“3ҝ)G|daQYNS@ɿߡW~BD4HmY֨Cy$;TVGDg4|SVrR'[Kxt5AԹþ,-a+v l" *}r_8Q2˷tl6N 1껬)/Q>VPrg"+uYlݒ bϮLRi)БVaTi.ao_Xd=lZh+9|){3*(z nZs7QlȻ!dOj-鰲s>W'xjc]T;'g5]Q_BX 7@9 @=2.dQuxւum#mI*P7|lE27Jti!kcH78-׃]Sir.x6Ҕk#Ä/t"S\Q%x$}n}Aw(ڄj8z2Cscti]#$ԈL ;6cPσrl,~ !t˲=nfEbʗ j3!!q߮*L GBQ tJW'6ѾY u#顬8C,^}K*hsw *Z3 \fy)uLpdL%3HW?-0&= u`ܮC BNn O/Cn2&Z ( @O1Wz- QQ.^+ ] (36o)iTXW(]z:=7LM>%=M_ƿWH2-S%gڴW hur'#1Da۴+<0 ) ;$ɸLwyw|Y`{ Ԗ}}h1=|@䪥i%lk Oχ?X_>~8Z_":aE$A* q݂E-i!bp( MF:D$Sy =7i!@Eykrme|̯|ŏgIhl&AyĠ͈iI ՅM(i`&& x0"?'fE8" hrGߞЖ 4|Ȇ|T\۸Ӡ ? ;.ZU&h r>N=vېH+omJKUq &I~b)^@b!rr0oE|,-s0 0v3 kȎK΅-7'`_ړ} mr+Faݗ|y;d=*&[*IsŐ:& ee=/&JJʑm f}%Qa:-"ŹYr)^Q!I( ;M.2'i8OZ} Vx$G-!#KccHU78P LD6 *48!8 ^ ]:"x r"[rlP y\j)vVM@KȖyq/Z +/>ߌ}l&5C4L،A< 0տ將"/kqRzgUE )qȟ+Yxgzhf %X8vrn/wO+MgYnU--7u$x7WOV7g0ųF/5Um>,i*1K%F>6MS[/;"U:Ё#C3gjIt7R8١?lM/ʵIiMOg$:JR-_)}q}?KܽX[Z|Ñ>vg"X'|6ݑ ҭ{US+)ipiRvX:/u+.Q˶tzjm| /֌'K)XNgsY4Y!U):LxȒՌ H(ܨsPǖ5f:xд10 ';P8'|=T.8p؍,G~50cC6(@5941x,=a -o4U$ GKɘ">B<0DvTx<%hݯPe2ʒc,>H U4ZaM^^Z- K+<͇5U?Hd!r*kH+Gb[Jlֲͤ4[@ѸY]qn~&S c%x$).M5 $زV tЁ?wRzk!vJ'J39 x<̞'TW3}aXY.=IICi-$16{UHg7V@ lȨc}O<5ˊ0#$\/JDE?4#-]5h*z&5h?X噹h+,rU1 -+uL2^(C!Bq^SLzס%bC쟃k{^\`mLD`U%eͲ?D~ĤhUjq4yqO]wgb3P2 xyI!ehC8x;+nye)Z&22HbAs1#F1 `x:}x'Κ@p9 脑Qy@X[Hqx ,8gp/w!ʁL d$RB3ː~#~E.÷}e{^ՒzY+dVځ~5ΣfiJg=Oq8}.C"~QN(>>/e+]wWAk3Ԇ#,oyY@JYapVyYz<ژ.BDGY96[w7kʃ N&ǣ=L3&4'mM(y0S{~3J!WSgCyx^Ί{&Y׶JY"^S%e ZDI">Z8l-uz ˺*ȃuktްJ4}ݏiwEϙt5Yew3*np? øA?R֓ɃpAX8X^/îT`v3:c`-hLN@"#8/,duq>5.4dыxjx\{ -;AHUڞq֐? u2B[',Ćj`ZUtUn7V=&F)S _w@!z`-Shxs=j·:@T3Bm8bzъ5K@a36 BdRjC |6B? :*<@xBA7GTmmhG{]0yG8,aq<r橖TVM !x9+gTh9q#^*MԂ,<&!P䵍QfREAdxx@PWɈ঑%5+K|hAUFϘ4]GlawV/z"w'P Qs6_6_2᧽%Բq2Cw'(ۼ[e*_&EE=+O}  N&sfzĦX{e~g'(k=%q 1Y lr%xnilΚ|Оff29@="Gދ"GG ..zgtY1n :qo 4v:8EI<84sL"ߥQG>GJ] E/CGhQ"\G~X㽢Z@lY2mvIPl܄*ik  EΠ >2\32c?,C+7C^""L `Y5I-\"LqqPlW͋l" P쏾9ޥ#jHA՜JQcSBvnJ" B.?*Wb,Yejc?.gݏ|Dhg<{ iW"|ZYlD1w=M#kto|v(X*E]_wɳq 3C/bpYP\pH-] S˭2psn Q yC1&׏7AK6ttP6?\sB ?9XݎLXp`横'+% . 3h6\ɖ)g -4c@ teB,9b GppBQ]s&B #&L)uSipP8üċxsKVy6! ^;Z5O GRzX4K7P24qy,5Xb4cUdZ(?5ӧǟ Fݍ2mgI:\Rs=Jgxq9NI[;!9rG2:amEkH1 տ<4re=׉ahо76]G)&$i=rM;Jj3&Us 408Meu`Hk}wlyz+[GIWډΣ=oWm-kVo$k89 S5-2&oFw{,~o)1v|A2zfW ҺNl=AsC^q߱[18xo/3@kN(cCdiaX~p5LBOG/b?^]c¨@9&Dj56$8/Z̓kёuU,iDc%D%YPb6 f"@^~_V:\2ѓ"[|G\h}u 7jwQ3C-w%Os#8x7T]ꋬyrgP%9F.$uf^QY;^qPd @"Z @n%zDy}^W߸ HܰgYP]AbevD!z΄T՘ aJH셈FK<3-zt"yЫKLWm  5"mqf;9dJ*,żIt/C.gWwsƸ a#sxlg< 16? bT vב? 0W.pV3{r (҉=/LJ}D:g.U #;2ua&I[H(P]hΧz-<}H*X.+=#H0PtKj^zrQcJg+$V7xXVJɞw32w8AY{﷟K~Tp yU`2ݸCŕSq(͢:hHܣ GN% c>аr=t? /" vEilaԠ9i_"cR*uNgXx[茿qiTQȣ,0Lb mLF5yThv#M;7"1Gh HY lW1 Q1I,*qJʳDN6(2,̟3!Fq݊VTd)GR6@9_2eöPO'x 0٤.tq-Em&-Ϙ $fM)ݩw: @[GC13$:JiG8SٯCaCea`j;wE   V |krڐէ]bD-`cX+ [ q,?%#uXB2z%$ ¸zG/$\P3Sxs<Ӕ3W6cjR<8|X%7ۃM0F ΋M>s7Alw_HO*툜.GD>;JGz"vqOIOk#[XLx]+ xf#Wfu%fNq? =[_6dU#0P-Q1=XSB_kfrT Y]b o>7ߺ|8#{EzaըG:ӌ۔7Mw‡&rbGDxLzvx/4CW:ܲngT>-es5e̟vm1]tz1={7w}M 0Fs r׭$ _gBhZW4 S^WCZPPHE&4Y,NDrR?! R6H3w<=ZDo pɵW10߲v?;A; zd "DZ…jbK ]COX,CoRyWuRM՛Z8groWcL4+jC郦%9CLK5.ԟ8PlRo8]| a(ݢSc=ҼALyft+O2>`D^r(ZF1&-i_ *<LO.ArWѪ7Ȼ/aMɭJ+/N?0l^Hz ue`U˥@Rύ:l&ҰEew$|qd'S 4%l֤WNRLzE|>Йr}V$'ӅEi' JP@@^5A[(0Ttҷ{/)'h _쨞 o+MP1(EW[ZnRt7fDXLH6_6nګȂg=촚F%r1sY8떨 `va_LOA QW}Q 7Wg#14 >V SΩMf᭰ٶwݎnBzͬq~}`EXx7?9ҚP3!>bPd%: #8) (&<,=IhTw [(V /ƶ;A!g\PQ Ē&_8TS/~?ٺ}ch+?u^>_wV~^b <^gBW$ӻR2-ld9 q(7V_XГ~yLFq{g,ɜ?ȃE7*62:OEbM:e*cm"G1Pr?Pf]ϥȷ|vkd8<PjςoLu*y]r Z@ycˆ֣oGxivgxq@q[bbNCg W?ƂSU"2{4&}`>W: Bm1-t|ȝ\iFK#Q0RyX;DZ{k(;H#ǝ 11n&S@|+ p gs.|c־^aʐw(2iQbKM58tD,܊t)30knO=nd(/IRi*p_:+uz Ȑopbm"LEm@ (&+ǿqeD]*WNne'Y;Vgaf/ZudRV66 A؏HOCUx=%@&H]BR'|abIsqX ߙx!ڞP5E07Mg|)A ><%Xi0Ry󨬚']=or ՙxYeL;y]]A4'a;*/OGZ *}˰xB<g2IOBZʹDծ5ҡh|->.(B񒖦*_^maM]Uv}@ʙ±Ŕ>rkY> @<dKs (̶$@ NbUQۉ_D[J4́E}FY2:WhEYbfSJVdrE/tma"<ag^#Y{Ljؐ@,]\xTsiZPV\\DEuD}w9Y{p6Mfس}+o&)9S^6{$Z΂D~“)4xu{;IsZ0W@N'3w1ZV ]2(h ΅a)UM֧-սl{Blda r ̺)[E0y*㦺[ΆS_fYN\ɶ}Js]Db 1"=X95 {<*5f( ~yч [M "-ʱ:X%+'7-έҭ bCh v6I M~@ M$KuY+3ٝN>q4J +1FdprF#x6 d8耐秝zc*Ж>isCIk_ivHxL0ycY_?Lԓ*Xg[,b_Jzѣ}Yu5O0_o9PϖO4!3`_,d#+өQ1 fȳg^'1SvqJƔ **8вuʹb˱(a;OaLC჏%{nHqVsnFR+?-sqKP Mm]CwePla{Gʣ`t`E $?\SۆUwD<Ék3>]WZ$:LۤA/|!Dh_)sV$-scʼrSutSK+}p+ҚɯLPI,-YuFݼ*T!:>S<8C@ =41 JQ#uHկV]~u{_..wM@Ew޾"檕}$XQߎiTZP;^":%`Qtc6n}CH >[h'f `1STLu*,}i ՙҸ\})ۅZ;O-(Gbt"򺴃ԉ)U!nt l(>hԪuJa7;^salЯ,j 4TyۡI1XbFE/?8zI@hE-Ch7/HWاK:;wעeLoHC4C}GNK9s(Z+v1tSu~E b]B^ J&/M,gk  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n019023l.pfb0000644000175000017500000021404710725114532023124 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusSanL-ReguItal 1.06 %%Title: NimbusSanL-ReguItal %%CreationDate: Tue Dec 31 16:51:42 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusSanL-ReguItal % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusSanL-ReguItal known{/NimbusSanL-ReguItal findfont dup/UniqueID known{dup /UniqueID get 5020908 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusSanL-ReguItal def /FontBBox [-178 -284 1130 979 ]readonly def /UniqueID 5020908 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Sans L Regular Italic) readonly def /FamilyName (Nimbus Sans L) readonly def /Weight (Regular) readonly def /FSType 0 def /ItalicAngle -12 def /isFixedPitch false def /UnderlinePosition -151 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec ڞD5bHhrL9bdV :o\Mu_lKqXк=_$ W)}:lRѴl&pU~m V#Hr~2ۗzʇ74LMSn ;5rk1*fޤ*+mF:A}+#p3 ꣠H*I$ 悌vql ta+U{QeGT>'JKQӝIYKOn&^ ؾRPBYP(SJʐ)|KJJz67Kd%M~U{;ժk^,{*: a7665qpv^EDxy8gfb-l( >kj҅k@,>ZHGߵ.UWd&7/\Yک&'{f@'_TCӋ- A,3 xQ=6csU z.R8Zv]f}e[AV,&9d[g6x{@:A`Y5؄5Ed4]ƖYA35p4$%+ŊA, y7Xt7tۡ~wo5d7{CZ~ݑ@/`'[oW[U7.'ȦH<\I, iN^bV|Wyqc[zچ/NpjtS# >#L9t_d/oMȍH9qv?#`p^"e2+F~@>HgxPxAW$`E7y&R_~9di`7z+oTë ەLSkvsևթ 8yVJSRO"ԉWB"Wuhs;`Hjod u">x8> T'mΡ]4V9،.Л6vbƉ|k%@G )^hޫ*앒|ל-%Mi}1WfZlu +hj1ow*'opq&|V>UA!f<|1(~5l]ѧlXnIɆ$RgBIЮ'dzh0.do\W.:%MU/MPrĩJ2+kh+ظDs c8q2'Lc-::b& cQߠ17/שa˚bvrx؎9J#77SGBv8泷[^-i. 'C'S(Nӵtj2_rRj"0PuU;>P1OvR-ENzmP'EcZ ߎSq"/+"˴P!:MGe V#@VިQ*L#х*ee(1| `5' 3KXSi({ދ.OEoY⑶kxUڹ< 66R3引'HFT:=(G0-P̜8\}[͸30qf/C]bj+ g|y4/wJJ 0_<7j˖YK }4_R<䋸BL*7# A`VliZCv^xdʔEM Eh^E@R]= Q Ex>qW0f*ɇ RGˮ ["0eǠrlF[SṱiDxD\kxw﫜5S-U4~YE[ X,`Mc= puGߚ ;w9rÝz1lG|Zq7bCj/ASmY"}z6Ou?l,7`+Ɲewn{[mV67 J}''ޓ. s0>$%5s.8M?kP0CyNqv%Nmϗam*a2~A{_eXDFB1DSk&bQʊpRČ7K(Yr ;UFDZnXUsyT5 Evſ^8Ɋ|am홰[li2g`!`/ۻUmq2ag5eL&<[ߣ~lt {~r%f!3:rB=CBM:ddRLUMM]Y7WGxT){8oKٿbW_q!H61SDa,w=4U47V͕<ω-1$m_dc;h{5VSOZs(N9^*mީ^',|/5W~,`WI>ƎGm5@4He"ӎ=℞ÉEsD4`{/Ip@Gz(1F6˚jA{ltg0dr iwH"sVWd7vD l U `bԮ,sً9T,Jw-qn g/ѷY}6V50%{#GR"H)Y]ۑG"e $/88>W4*iGƉ r " C@>J +B2㼨!2" qKkPv-K`ݼ0$feYb>_pWɇnO쑧X_Zr/B6VJʍ+E;9`e[=yj*3c"@D${G5Ըy?*\d_ʞܬp xlДӦkRS?_ ^+> 5)GV|"h}34>PS8/ӑH-gAJt{zO2`Bx=sd|zA2~ܠ۴Oh!ޫ7k]&ՀSyLGZ p0 ʧD7o,2ia:>boǡ:-Ÿ^QqyS!3XLHطqSCU8}zM-rbq59M䵺@ML+#Gn?OSj7UN#qmtCoI;BC*% Ntr7!>IpBHVHws!t&Wu{,)8NRB}dæ=1~ղ,OmFV9vQřL5lŝZdt4UMKu>$XTjRh9Aψ= saN>ȓ)ƙ T^eIce#ja ˿)gF" t>hVIhi > FEՈK /hlJ^3%5 D?R]4ϯvD+U%-?):[\$7:-h!pV"Z7{w1%>lwX% lel{݅;݁zmE=ﳀ$#,p ϢP+hU#4$_x?88:܈d] |BB0@!#LjBW,k^3rZDj %&_<)lJ k/}dp䈘}0{4O5~ﻼuiI}VvT ch!@c;[NHiZMmDKХXp#~J8awH{%S,:QC[`bm1Rq  ƶw3pVdſ|Q_68P`Z#<~ (!~o,.Rt0@&ncuD;\dl`jKyPe+FƁ43֍ge0ZBbI)Ck;36L9J:0I~Rbr@]ɣ{C$1I[sn߮"=!NX0"?s>{2-]M%` otralV˛}Pߔn=wfs̢Y/M"(jMա KhK\:|dt;L "IVb!϶_A-n*Ȅ#-qא#%W}R5~KZݑ+А:K}6uefa=)k˖[cfy/"4^%; WB.`eyd^b"wFЁ$aK,+Xi(E꾲ޠ̴Tjs'dH5ϥ?ӆǸD"@891wlGyG nXQ:s%X x]jCZ Vx^_M[$%:)8;;.N]r~~?[5(p.6ҝ:-#_`υ2ƍA pۻIG0kL jߒQ؁\<`c(:TAIz"P2 ʗ AHDOʟ1ˣjNf܅\jx;4o')(ɛ5f(it[`YPajӚup;cΖ`3K7x#Q5Ʒ tp.88NLN#DI[(@abm"c-L\SݿGKFφtfl}Ps^;Q1 ?g${D |S8+zgf%QomTi4@"P\XqoŇ챉g._f87*d!̴ξ uk\Kn$b!JܚB Nc zר!psl za /BL-*yblbK_Wrjq2\{ΊDf֚TVX|5-LVoةШp)jhh 7%[k/ۣ~ R&` } Fuq&@ eHRKX2MWKBg/z ±C90p>!]: DkXk]5*`pokɯ0D_fvys#Nϥ*&XSq@$!RgBbRAjfg.ϑn>R]i?W< t&k:E"~JiϳwSRq${e=K>)Y$f3SӲ7 W!#=_ =Rs\_NV-V3NyݑLZF=&GnpJ Z@یU'PO"FRUe*Ҋ[%˄2Nz+5,1aLOɌC#ݑ~1M\}Nqv\x `nJYH4b]Z6a}:ӁsQ.jЇl9=ڝ5", \"hړ4R-}%G %{s#a%SZ%@]m m"y%Ov#ZE3ͱzRW"z͇,x;P(#nd%;tY߰WpFc#0A$ ;Fo8:{U{k1$g lFU؝@ ؓ@ ,Wta<68b0M!3V=)ٴ~hуrkU]WFx<=K=iL 1BEQ&7=^Tї|BY-ٺL< Pu^+؂ ZHD·>>՜ M2kf};ݣ/~C.=kBxȚvhcood!JڧF`޵1KkWk4e`VeM$Cm,[bKKE gFak&9&x< shEөyC3\Ǻ^cd{W[#Uf+.C4D&)?t joU5.$Wu8:̡wh䉔Z-.ψ KE2Sv$xa5Ц60F'ַ͊"ޏAr Adr4&Z:T>b;[/i_9ݼX^=Q67q6Q{f0Gx3eMY2aW%mƵUze>, 'D P`\Sw÷J2I#L? 5\mxrˤNX(,33S|tYQi],㖟dOJ:m/W"+2u<@!LzrG9Voy2/J%_3~3iuc[$[RpOMIn 񄒾2NĠzYP W@*9ƁB$1y`b %9h`Kuu>̣ViuaEs n+a%cY+/WakFTY8LW[݀mTub8^ZN ux7<:eK[Du7 /#C<byټXS*n>_w#+oC]Av,xktz3m:`%\49 3a*+YWg5?_:!CԨq5:miEH7 )"UD0uU80 ׼/uo"r[aXaeAfeŇ>{G\n$л\1@W~BHfv!f3a蓚<wܬrȋJbR$%<EP?~,SJbٕb渻[ #s .u g')M ]ee֭,o{QcJd7u\aT (#ܦc}嗀vȤI K0em>wʤ~Vsas$/ޤ>OQ,7k8k"t(ԣBqO-Qckkah:5F.:~%gWl0zKmAG(p7U^!/NNF aid8ڋ1d0X z{>M?dzhr Fɇ; v1mҶ$$NO6q{w;\0+~Iə$|u N*`X֫nD[s)0Ρ%|m0z#7T=h~TN᝜K?ʼ*3eQrgsLpPie܄8+JQV4-JĉDykc5{h:Ѥ.u; M S*HڇOJg0ie_j!,o;ţ6rK6;< I=ؖ!غoLCoR;"V )9Q^+dKK^AeBOٿ]ZB4nL96 C񖪯13K4O(o˩AidaB_)(&RzrUlx6JNhĈQ,xiݾ9#Ƽx\/{in6܀5w]tL.2V_^c{i6;seypiIndPzaI@* G[a_L#1*@"~ HJ%؇uөK}ߖD=汨WZ`~ hˈkd~I1p*\T (0 䉕.D>Х eզo|˄YҥF*BhU'̔պvܡW͞?[ $n _rPڟ]jc]SPPuބ}3&[]\EhAq QbYZ6 >*:2 t|&*fP陦&8DX`^˿p|*;5@dverC%(W?:4)+eJ%6%Fb/1mr{؛S|&GCcq#.,I"9m;Ν=UݾM~2&WAs0A-Z)a*<$\'~u>H- W@l"q0Lcbӭncy;C Uj b[0D N: 1! CUf#s}C~\tіQ7.Y֑[_[&dCCdT)F| ./R@{WC?f-H(ȃ޼(v=:OYhNx: =x#XnU-C=pF#iSՙybŷFf;!᮲[,C#?o~#ʵ_j ؙ?S[ b> jCpBIp#k 0@Bj w#r=ē#i:tLܖKW>x6.d=:cӥ//Pl)wCt vn{nXOςrO+%{5V+c~z3( dIl$᤹Vu8O\ۀMh3cuϓ#gjQI3ԔmJڴõtr=5s6ޢR ^LzV!!eS}GI3䬊`iT'X^8iYb8?!@'u".4i&nӃsTӟNWɗǵR2EpO|D)>Ev@5`I~YHbP uɺя__eN>%]Z6n/)>*0~}AF*us R?v?*1MS&tZد?hq)lKqJ߹+@dZ.K]bh_`5;[;`A>%b 7jPkqDLڋ%Ԑ5;- ݬs|yfw=K1N)A&jPq%8kv~np|M yʟ%͓HxS - hSH[:N[ Q!ZaiaW8J!On%xD""`;]l(nQ!S-3Ux8WSf'Agpxh01# 8QW=2Ǹ@l^1,֧[@vvZqFx4}:({ZTgL8>LDHt6B%A k;Gp6y[I-9cp̫]N҂؎P)s{BVЈ{eqmx#K&2a_URHk6|}@8<]1UN2~h'2,oNn21+ Pdq &uP-;'φỦ[ W*7 !b52R(rP oWJ1t;׌Gkx \PL#ف3d(OY:@P"1rٮP1;$nFWJUZʮMyz`~0.rvK¥hN Ul;YgP.U] 7U/g= 4,y-쀌+R4ӣY|uG:& #[ cҏ=<}S_A)z7t$D0jw5զ\\búA)y+P|8tX>,>4aԠNUQk~w-Fe $pÇO@J`0] 'Sr^l6|lnlL#)Gؽ ,w#!jEZVvrjmoe3;H,&9Wt=Un7?xRY͛KC""Vb6)"Y7oZ!&`!zM6WB L)`K`=p^HTS#U;e8V5:6Hn=X4nӰcDͭ \ÓD3)M<2c^g8VagZ3{OWj=%)]M\@Ǩzd88SO=>>,fL!DX9/Ui\dL^rCzįᾲCylHE BB9ڳ8gU?s9A]P)Fe \zd(?!4X& aK>UDXoGB7wxt[](A7^#+uAUI?CJ\9e-$!bڢYɥ ٞ+qwثl|4%QQѐ/nTp(]b5#ʲ S ʐhDqAN&'$9o/6wښ$&GăTn 0rlsj<ɡ<,65XVMM=L@%b?޷і ; g4!B3-+pFvLsd1č4ٚ1 RF '5hBSR ]@aF[nG,N2͕djogYhFWGh@=uJ%d(,$jPH?r^_\E״aSułQyxSx|ՎN>nFL\M_SĀN_[U f #gxl>-g ?!6߲J;) AJflЬ6GSxrJM| >gtz;AWr*[._\s]Fw,rw'FuCQiNj!` ~GOh(,j~s/5|l&ձނSNͱCB58̈ W@%H|8~ C2ӕa 5p<]+;dxCEX`:lJWrW̺$2y5\Z 6lzMBZ "F>>v3e8XЭf:3uj _2^{"H=T.$s}(╏HHZ4P>"}9W0@m +x9/"1m\TSJ7PtvA#322#&+]S Ӆ7ʚ+M9sgrsY-[JXT1dkOwJ[:lnᔤw:9[IA^G:]MJqL=Hm.28YhE8Qk n`΅#ڷe=唐@-Ғ:+|X NB 䰔"ٿ(FFslמt{qUG4^wCSX ׋Ҹ+e٩_\\r9QKˀzk4;Qd so9nV8ip8&{Ԛש E#RhtނX'9Y]]!!OP>T ;_'gw1 nksf'OY {x~ MۚI8QR3@~cru" ^R"gЋ4zTzݛw# 0(܉zj%,V+V6_\ҵyT3+Dȍ6te!M2&dH]K $ *3VQ܈x;fc|2po?\κ Dǰ$(Ptko##On8>yicjy!#~zRnȿ'U_b3Zzrsa^cEFRhX1co5 arȉp~GZ.w7('m..}1K< {k7\o;22f{鳓5GD~C6-JGW$7`{S_hLAų> ~[qp f.OH2|',E:GW ?* fC#WWWlB骜Y|6˵1nE(iƄřۺZi'fC > DRmy9æc/CofCG&U6l0l0si{ދ[7׊-uBW %:Yh}*lgNjGv?+}ρNۛLtv{ i౑+5\E-?MhJ\:IA)00}D]i94.7$y @}g>mLN@ :>>KQ[-Oce=) 0өgi#LUï@lU]dO6j4P;/]O6P'Þ? tELY@_֚6NH`tW; "f4m !1q[>dc,$~!0bMR/)g: h<5*Zۘy߽|&ܲzAFay?` "BApE# @sEX+(󓌞Bq@X|[v Z"n.1<~*?_&E>S/U,|\|o32SI4T~( P7(aKr26Uwj&'{4v;,pfrV eOOi:xG PP^_[H97?/NmXfbE 4$m8rǘ"T}tc\''f]$$M!]psDut*НY?x֒O]9 "Syּ$a~iit[(KOb|5Kg'-v@Q&3EZݤAE*vo)_8;ۻ[*R5(YcZ^ݴ&c3v$35AA]ɰPӣd-n (N\jcޟC;eɟ41a"a:| ʉr09"o8G*kXIAd#s 4󆃈,K @4Tʁba \qWuX2A,s;|[vj"b:EHbwΊAF yt㇁c S*xWU}]7PUCERF1\")>rχ @Zm%T7yAz{8Myxz ɠɵt%=ĝwBlPBO,&p!Ns% &6֎33}:NB#N).[.NŊ/:x n덴P.QAF*T&ddM,nnJb^ m PN+qBxi(_DmȄx+^Y2H(B\ [̴,t_DiŌH5HS0O@@bYxEEQ%V@ %2X8 vJ~۝=Vu"|%1:3\)t3鱒~&9/X£#}h`Ǻݦ,x"U6Vq!?lɜ耒Qp Lr4:RN!п'm&f?p䍽.TauGǮ «Q ]PϫCvNAk5i4١ROt贫w6V9L݌F<)Ҙ}~/);4?i-5 Kn/]* >ȧjm ڴ(=~m[a{g0b%9RG"NC/P,2:hK$+ym:}B^7 uv0Њ -N^O!7z.'7}Dhp[HʒaqN%hB*ڞs+uzP)/!IsI>r$p5װԤcX#6ș8Zy$j,]4CX'19xU J[ˆ) |"`&u/[Q}ԢߞˈQՈ "eA 3V 9Hܘ (Ձp6u'ijJ}"\3!T-;1%h]MA eV P*YI_SY,&ĭǘ3zc}Gc[D-EDžbgvk{4$ ݘXuO~:0ny-`̛p紭hS Mqdt~=_FW%%cߥOޜVu-}o0..(:/-r4/77@4A6Iݗ[ i(:{Q1(.%xh]M]ЗUM`QJ]9H2&BƝ!8-^D⓮|z.љP KGvw%t%1) 1.z!GjwWd@as)RR߅J<,$֐;Ҿ%҃>XMN*do !W&dS"{Ekj^[j4nT@U ;-v~6~nb-wO6P 3Akop [>ik/h5*:1Nkã9\k*_>'kRWx]F-fQ,O` 6׫MCMr~sJNg~$a^k69AI$@C;ǿHr`xd_[w:"c. aF 񭋤[ N0J)t ܓHj7]2f$v!|vl4PZs/;"dp2 H&F-aZ`1o`Bbq5o4 ( C(Z6_SӠ)]W9}m5z03vtfD,+sAD9ٌKӼk񳳺TBZ,֨nSNhٶkAXMjq8r]((މAp*.kv$0&MR>Lc=~|ZZt4'T(Ÿ4ԕK(d2lGԔ%|u$nҵs)|>\mx`[Fj8&)Q&MnpvʈN?(>z&PU 6\h[Mi(Mjc C3x?*(4h0B,VҫT))hn `KG]MB?F6[ Yq|Z hPڏhBW3|OG`q9f}ļz^TZ9]Wt/dz*K(:7)!3IAV8<(;LG|& oH`;ttƗ Q!j~ϒ,63=Ck\kڳn&4Z2X, P:eh +19a*L?( ,AA- dhD2[ s^֯KUG]0e徔#BrD 37ق&9^ ?\v 4+yD-Į5&s2q 4'aNŭ^K}ʥ]H3YPX\o hu#9nW~G>m5n \JRy6D>Mpf`> KޜWvW1%6dD?Z%k}VX_ӣҊ ]=ܘ,K)aNX\khdXEO=PzcsNU>-}Oc"3I5`"MBz-2n-?n@yxcjV@(W7;sabW$ l:ZR%kh_Ht! 2;8B-G'ZL0lв/;}k;4CW;e8[)-䃯iºԝ}t^ET/Zh .>d9$Qm} ɔzPC'bG9k[',{Uz]^! UFc*/d*,.ߧe^r.Ϝp۷. o7xO;~޸[ī5f]A9Ci*sX+me :$DkχnU5NUne~-I$3M]R";zm0;}⪰_B> HY9eG奐#77#Ds4WK%P1_ЋQc_今 .qí؊?.|GOWlPe S tXx`dOj\0,P2)WyLIt[tIۗ{Bƛ-cYIy BH5+(XJKʊ?NaF~WbHvS!5E&ED6atZb8^2Kd5YbA m!IL,7П8xaiKߑ:G.!?T\1aϺ+} @7Ddƒ)w:]%q+g c9ΞczZG#gڥElA̅r }e!]LrYJ*z1 b&9@@A6^ fN=a r_։?PYyDrуC^^&aƩ_ 0rI¤yx,BftRv)mx2l|do4~i_JCACv>sЭTRNCd)=[^'mK50H;' kg5h\0ZXq]h gpT=e,tBQ&`H-w(JG_1-eqU&쑛&t[UXw_UE_+l}co`(у$5ZI_f&ICϺmM4 Hcw.F{T!jDФE#qGک$X?I1~.5ZIWu&yM ۀH7'.3 q =qJYbzZ_8m"`ca=^-r~6tf19%gDs ׄy6$u'@#=Gb@Ы\Ӄ+D3R?rk\T<ʐ/|عY[Bϛl7e\9 j"oYۿqU|ұr*ӫzf\63= HOf_d-ꅫpPQ$gd 3.%+[_ z4Zg 05:p㪕Qm-c ̙.upM(߇Z,t6/T0~nt7 K28 k7ݼ1xMgL„4PZAL'} Gx>D!A7ZH?+m{K($@:X igTПp` O*$hJ^Faid` ndWockJ1yHI~10bl`0p$A$[֛T>E=Td=A[%j`Μmȭ kMO7 9fuh/eξw)Xٺ8 Ge̬7ȷ(h6$XX~Gߙ./'anb^3N92h1SvAeU99Όb$@;*KVʯu ڊtg~%T^IiִzC靫K}.:0;~33~m$O!puVެ]ON-7M$AXGfJZ*_dNzĂ>C((u_-ͿuoLf8 i7I7{SzPO}wd 9LC','n:=BZkؼ--Vt?9:[Tפ7jK s Aa~,x]eSZ?+`ͯl}A؛T@{G̻Y[*ؙQ2ElЛX';gZׯ$쮝Y,͋4#(r$#194rOW]fP,]'ÿOĨ;uDzR%L {yL)277J dvWWҋ23NXspu}z8K[+㖴b|OfjGlb &G4瘚dGw xJ'0Sއ Vo3’M粵|ڟD8G$s~:(wzAr-lJ8!S;[4h2ET{Z~[#-qz[D\XJp2NιU5O!hEn2<<5uK O뷪qb4YuqoCt1IM7%VRg}- l "(_\Q07njh Kpz q ’&S\Ma@>Ɲ]4X\{RѕzQ f9x:JL 5>tTujPx&%ޑ,isklY` r'ΊeXw֪cn_mrh~ȁn/"փk $'0J}" 5/ U!R*R>(rYq)gՁjNq܋R- ~`n?;ːRcm״?~9j#x3'Kt}Upx_ك.|91Z ك+(pWsaM]:vK恞j CAh]a$^KݏOy\oY{+4> >.V z7C[$R!iPۊgm{(H )d@X;sV6+)NKW$XTd+))TR*-GcYY+Ȝiّ h;;ȹF-#Џ 0|79193&C3S8QH냐{5<1BE2!6԰fmw$1gGF4O Ȋ$jBݱ;bf|:d2_H-#(5wK#PB:J#WBHR,c%ThJFí^% :% o| &Nۺv7>&D\T64o+RJa茬!TP**ۊ'C`c#%Ib=\c-rVs呴na.y;0K)^`܊[qoԲvc4+OrWw<^H dHl GX3Ge-3~UJr#8o 49#Ve3#rpkY4m gFddS!аtnH#v DY Q:OÂ9\K)艭NR5Q23.ٙ=$gN.iŚa-Xbt PLzrX9v=aO[u2Qfrv";[S14QvFLU{s $odQݗN"賤Z=$WZwxۄA76fvd6wדM7au+#ne_q&gVQҀ!ٮx=UpuUGY.VIpݫ&~nJp{BN(6縴SzhR2uE][3vL MO盬͸ EϗDO]65mMf".;dA>'I]E\v} *"JOWW*0d%k ''#8g*^AUr,Yp\,}X|brwS2'̄)>ǒ\Gqj)Զ;aXA} sPըJ3#@t4̀߂9nOa +j܃Xjijԕ3"Vx2@cnNb%&5Q+3߸666r[d_N?Tg`Ϸv՞{ٿeͲ#t ԖIٷ9M 6  bC#،JIS5X8r3_$@}|I6b*MwM ICTAr zU/޴>;x{O <Ƥ ׈LbHdKЋI_lq24{ʼn:Z+M~_+TFյN<֨pə%71fZ札)ss%qcGw9M:nU)7KZ6ߑl\B"u` ;9ub5ZxD?D2 TA Bϡ~;Iv61*d~jʋ%"?bG #,(+ }xLE:CLwkT+Eha$h3et@IScymS3b#B6*3Q$1s-8ӭk5s]p{zG9(!'׹O _]5[Fo 8󌈝F*1w7 |gų/%"d#j|7 8mxk7 P#x &^ .ԍnDAj!*߭' 9:>vp/qPIBeN jCbt[[qA.f#sw@Ӑvtۚ]g'4ٗӫA]oߋn歿炪L&CÈޱzB` ؤS$eA f(d \^1KYzhѿ{c1!QngG7V~b_LLj(%Wp&5 J m^CsUukkj<șE~|~$ *`ak  5B cc eSE5՟}NWS{Z^$ ~o7Rf\.8v\|`-~._2pʩ 5B~( xe |;„<=b)C d)QhusxUJ)wYC|X-Nq G%j`XDXW,\&%uCM'^Td#}9LE#AI9$`5e-dz"'ḬYS1GB'|Zi9m$ Q5ծBlǖ~9ʺ-hHQdƽVPa^[vc5f.mAAyN/YL0n7S,z)eQ n0z٢+Ƚթڍ~YMkҎ ;A I vV8kg 4xbwըoYCw V9otlc~)G! W :OW&[9!ESwV! ]œpC}D4 ݓz7LX5u9ŪckÎgy[A;Qe?U2.a v6Gڗg$Ll)fA `"{J TN0H#W8p[[X6$?L=ҰJA TU'w/=( \\1(bs;/?s%%PlQ{/"8x a.t06H2dcp 3f5*8dr*y=a^Q1̧ŐM\߼G0$8xL]Fyn )Rr*6z8Ow '@gfpK5v(+ri ͤ4.QHS޸-Ϻw JA.S(K~F+ʢlzZ=輍Cn\b WhBsfeME;Kx,х+2P؋*u1`Cv( n/X)Gr.c0>Kt<$@H# ߠۇ>dI}tx+74a0J(!S~}%*Di&Ǥ- xPnO~v /?1ƍJ1' TՃs 4/M7dm9\ӝRh򨐅fx{\d!Gj? e[4};5@21[BñDIIVd DQm (n;<=/ƒ6:C)]iEUUXI|-S L}l oONSn2,M@ _ԡْe䊜lxmVtE1/:Dr_|6'ߩG<^) MFNMAp֧B2w(Ou )@M 䋑g/d(n[¹`Oqs?Cl޸Rno;M|5_lnD^DLՔm\ .ƓE]тm4KEZUDK͟ Gydncs* @Ì&ֳ3CPWBBdӆ?i`;\`l=*2?vD"fFJf~UR U@XWZRLg{NXqtr0l}XNQ)î6xmPpQm7ѐ1#rC,8'SZԦ{.fppCI$-BbFzD=5{#ZoBHN;EZܛsGca2 @{kX8% )ۺ.b7 wq 5+~`]=^zEayN $>++X6,)HΕX+gK KnVmw<9|sx '!&jh)K t[;RRK {6u ^5 ,MF{oVveMn0~VRQ{#&keTj^ ziVwM[mG[4 ӁEZN ZB,B MJ[{7޹j:Ct5iotOj0Dž1_ݒFOd$#"r/ᕝ%!VCcN-Hxs/b,ӛۢ˙Ka,!!wy$52En٨.6H:PO%p$>gBH?/l`BY 酬Wb#˽-ȦPsQ) >悘{$C>GiVp6B=&()Qv>} me'E bXVqICSvatُ\zC#,xMN"~#0bV`[1.v`:۪)aCs qoy_3tK"u-mW" Bg!>'ww}TrwgahB/c76)̲se4g >C-Y0 , X W~Dpv&9#Z (\3?|c"0dUQ1,A~zdџԐI2&}W&|ehj$ge u{c=R3?xAd+ж @C:Q%/Cz[hɎ*kQNc$n!0ZXi">(JGC> w Gf`'#_ZӐpotT#45TFD*_ﶬmY_c1ۮiOyhCy𬀫:% q3*y^fUUFoyK.ڂpTtwb 0SC} ٭%6LJ`LOyFFm:1̤5G  7 ^0.nVgM}jgc2}H610;4YYlH2PT:i@CzgWf^ar̉4_7_4*>hVG@7'_MX (s "i-rΰ7QboMG*Su;oNu|Y ht5S"nl/- /` 3h1Dt I9zi6!d,/#%mj,,Kw8()fZϾe:Ur)j:b#t KV8hwAz qW0%d>0=ba^ѹ͑?P;Z plYB`je;cv)~f DSs7V^4[49FnZ&m3Aؤ?"ShxY/kloٶ"n.Eԙ69Mt!łB3 q)JT)uL]tBRe;)kQG<]Xr&l @ b*W')XϨ HI6 BStGZ̅{ }du>́3Y%aGGMwL?.=̆Ov$W9PoR2B_\>[Cq+gKE ۧ(^pֈ([^<XE͡P|p3puVqu9Oetw\2bz`r}kiv2@@ ~I}XSRӦɟl2dAvtaӟ8cQ?#0 T'O}65 NjMѺF;O;gChhMS=JBE㨜jCxV44G-w XN|Ix }NyP9W(T/ -R'ٹ(eYrSC!Pv|'g -$'4:bD4wS62z-B&Č~;iaGNM~[ /.;njًpK˫ M'yI8)Mu)A%"iZZe`)x`-FTPPZ?>UdxQ+M{-gW{%NmM=(Df{ õpc+a)1~^ Q4rj.0wN0鹋{ϩɶ xǔo8 tƣ'"v}GU|J%q{-Y}#9rkU.A4 A^ZhV(og_9nG(4`r&sRq7 % 0kM7Q\5`[WCL Wd :f+=ʉid 8)[^1 #)`|tfJFjuiQ,)ɇx$\mh;K &L-dr7FJfSX:W)X#9;w m~x$pgnߕ?9F 823flȇl.bEGc'rxp@90fx!28e+wPYC绒?F4)bǢ"Mܼ@Ԝ K(Vkh~7'd!ƌ5N42I1_< O+M= SO@P-878tlcW}P(S^p&uSmW2\`ebvM814mn*x)ۍ,5.D[?+3[6%zW5UM\5` Dej1i\v'Zu#.2Qɦp癱H ;o^S[DVp5rv$ِ.5սǬ V6 iqWDZI Qpx=D|,.ujJ$ȥU?gq%4}JxXRtʽYokk5-ַ ./\;$9 oǂ77?e6bF7{lpOQY R4Dl_)V"y/>)ӄElRhO46k T*:_ 114ep9&4MjeNBV5qg(# ⨪vcwr4iFǛOᳰh(27)4  JkY [se+\v6 Qh.pOC"(;2B*a{LcS|Yf VvI:+ֵ #)qʘ"5s{՟ ߜW+rC=f6e.pD"e2kz+kVK}}eЁZԢqZʊ|ʐ`^l1VWκý9Dem3|I7i2~OlEk8r䷮ 99@g3S/U:cQ ړf9dAxv0׾8G8u^~5a(2,\fuV?QΞ)JVu)l>B]~&skAb~{OևJqV \'eyꉽj-qT҅]Q-(K n ͢C[GBh_ӜN0?!Ta:bC׎Y+`*a9@]oȖ-}g6WOǻiB2<FfZNXDF[DžݙmF/& |㕁(˚ Tak PspyAV .JiE,93,Z~Apa #A[֤4:OϲsOJ)&2ʥNmkv)gY*w^vYp k&-'p ֺ@#+"tꌥ,PĜE z H3kܚ y`a/ڝy>AQqL8;X퟈BtBRV[3; n\`CDޢi+wÙY{'CXbϑ=#dJ%+Bׯ1tP΢0%Im0цYzێ\} ] P ȰY卲HK_&V\ t ČٿuJA;z^Ӻ0l6_ #4YLcư>6Ŵ`ʾ#hQ7o>>dxe[I?FOI KvFJTy;]R\u.Ca '`s?)hU|9XtVY^&M1k&9* /Qg#rwvƍ.|9Öl̋(wND X1?꽘\X P/8~Ѐ4[~ I7=|N?tid;CfVh;K~pi͜+f8,$%$RujP 5\Xz,r>~eevVx5q&ɔh 66mR?ðX$PII>g e@34WU12Ki76+m![_NNgXOH-b "%[: .v/t@$@˅HİŪJP;yldY7G_ 'f y98_ e{u/romlj3[Oq_zP&Xz]=7;mVCT 1އ&x z f^i+ID:rYp}ʰ={dq9hWbc)a%,WQ|[bv6kk?`<@<^3U"T DyNnbҡ"z'Ow r5{\̞T»{TNPorD"-'RSy0+Ѐ`La7V}R_8{JFh.j X Ԓɦ D1h/m 8'++9趔ΊvT9A=Cyǘ?YTK뢗pr:dlOR+'ʮp!wFdA/DX*yȬ43 sNP;y$\4 VmțߓVUa>o#M߰$=/ <KU4i@ 37+d3dXec]ZᅳHTQEf': y<)~8Kaذ{SyTPedS!τG# wHX'{e,9u>HJ"Jʳ)֜l/F[+f|쫔מO'U2sv^λr42o^2Gᗪ2!)uj&1s%SxST\T2&CtmڼZfgaGEJbF)P<$3xնdO; CbHhD͟t&DVY`^$ì)J|ĦT^<)qx|nh\f:N;(@|3dM0/j|ZJ@62їRK)hRܣjl|zXk@m穮p b-^FCkߚ7>OdTSY>i[vP굌$˻&ڒ'i`Og\rSEeЙi᳃ Ð @̘;16PVaW c?vnͫʥfDɳIl+a"a`ԉZ ڂ :N)Mn\> yi}zrF2XJlGqN~R% ?'!Fۉ m` ]Ή0jHŬ@iEhh h+͡L»74[趻w4O3I%!/^'- Z( bVw Q~\4",w܋絵ո#a HK 6JQ́h% 8K&>àۼkN  ޢ/+B4aEIM;d;>lJr~)bjs*Je)"vJ)dUxu1(b ^?&M&O/5-ֻa[kz,+!#G>`tYQׁpBpvF86 N)uyڷ@JIoޯ*$^.fhG貖l1%K+}U@ k\ ͌JPbrxbҳ""Ii^ʏM&2Κ@M_隌*Z^[^^Z5yӥE)3bcY/"EmS5u0dђHR;Ko<"jX%ydD(ɦ<dޣOdv"8@Ka]EA#bҥC.o:$QL t{`k{oAEuwȲ-/W1\m%.JIW<5EnGNb'^=pځj(OӖ$Iҧȭ5\  e`m@gHydЌ`=i!;4{~^M.gN,{L &>g8x ഈOB{; fw; +lio8=f7G.`ʚ-)IGeeD֪Uqͮim 4Wn~vxF}1Z1M P_ӚQ'29Plb>cX B׉jAGM %E) jˈ?30C1ͤҸ[O5l: }Ӥi\& P+3ew׸CqU$ )a `8PÑr{JɒvrZ,f(vtlj`'+5'f;ef 4$t]T,ǟBkZtf?YbzaΒļ6c_tjZSz ^VZ{ 򩗒%dJx.f fQZ)^0$7~]e;1sÌجͥzqZM 7o]R̿Y)qZD#dFe5 y^[y<g z# jv՘n5a:=6YDqbxBcML`c-}[OeޛCETe&Eog1>*>g&,%Amֆx]*# DGhSY6vg@bt>W)cPwhNnb<sP?EDz]D(,•9E HF+W{Ciz*nSJ|{:ҡy˚}sޔtYYCV{VS?Fl泯#70yI#d^zG<$gDgV/L6lzHV-m Tq@Aa.SE֤"6)xbDC$1 ؏huL+OӲtV+-χïh7]Vp1s4xcf %$J<,(+ +ӲGݧ@%Wݒ<[2WiC!Kݨ?wϛ`a)_unMQ]2U=\i*Ur?pfL %Л_W5p; /h5?#@iqfg.o7 `σ]~b&8k:X%- >D,UtOH/Cw,gY1()=08]hMKkYŨ)I͝_QRZ6uş'檯n-MH5kTBR0Msx90k>(fWk AXA,b dHYkt+19g򿅙BGfT8!^y"' w̻|MN eMBRh7٤ ^5vt N+゙IΞ"e7V6P._bw%5zú);UTF1I> Nes ;[$ME{a  Y= |/U9]ozs_?yZ1n_V!sKCh` q8gvjryGzōw Vc ko DYMDE,}Vv 59 4_?s`o/FS(7ԢjN1M$|(߇" 1`ˬˁAs_&S]/e,L2dU{袉1"6L#0:uW.crK7%2!duܟa>©q5rE$/Tl2*H >U d}@qڲhb Tvo@U+`z:J TEH')U+P1Pr8с ]ڊM $K}'yg6;3*GI^c1qex *Tt-oGz` <L uK)m_NA*?whI0E7x~B 8yx҃ÜNcI[F;gF 8d6< 5^y\ë܏FC&\s]AѸGN¹5?%tqW1~L8[e{Qsy+"IXTHaw?0/)m[r/utفI݀ewRCI?`LG:.ՏO5<O{e1x6 q:ѽiӄw;,p14h'CԈ?Q/LSOlg[l#~D"#,ax"LVD }$n Iٶerxq}j 9A/(6<Ɗԗob1\H28̕UF=LTsse;lxfRյ'2@cui9vb]tmh\hݘMC rXe2,x.)|GNyɀ]Xu}0g%4"Fadq.eBL^muTI`ߒQ* Dx(E+T۬tpBV&S: n:oxk+HGۥ" ,G : eE$4@awvD!Fne&Hwゲ[2cqq?QC|9 9QM:D|[U 5,7Cǒ= 8#/G{b9 VFDLrF6g؉7aae2V-0Xa}Ԃ>522EɆ6q{D.<>*TUDSsQf&ҴUܴh~"!JxFyGA'VR~V;!~y>& wb㰮Sn!  ˀh}54?D뮄-g#(&?S)d4v~A=Fvq1\6?~SL1+ ')0%xl|^ce0jOIw4Ȉ~a 6u<vWr5O}[ʕ[,-dEOk;CSef+Oh!1Ft*ז6wj) l K`!J VT7Fޱ|MjFcR0u+Fw(0Ctg!-P^&:˼ռZ'o !GR'Dgӏƣ+@3x2Z}s ]-=v쏠?Y:Xb$ Hϵ0%'vK%TgXαh 74J3֩B~3 !dtDB [>X\ p53#Ҹ;9A6h%k߿5 K5޽Sb_}-Sd4nMzp JxĞ7P0(wp1T[cK&'`΋JNFw5rLx>'1垫 e4buYOهO%UӇa2"%8oKGl; kv[s:@Q 3c==6k^٨,c-fƼ^c@ TOQ,J2a&T7)DZ3{Ļ-)ؔ<\׉qQ gW"fcϏOz=4AVh=#xV5`T :e i>lGsH|"x]4mr!`k˟19ְkRqUmN=,ӂV1K@XY;+qG%4sSVә!]V|G{NZbS>!W#86$H`V+MY={{z h`'?Zd{ ; S={-?ؠt{}M wWeV#<ZL5͚Wr]?H)5o^{ Ls_jzyF؍o_-CTQ%l:YZ\jGLݹ7W7ֲx:Tvi}@I$ )?%CJ]BGל`X`Ur\!}?-ն)kc_؃'kmR&QX˶A}=9H1j_P#je,f;:))vJx8%UX?Bpa4q6SVs3Q1ۧN;<\R(mX3t.Aӹ#iHD PF aXo/c._vvͯw3剕HIK;͝RG!a|4u_MX/0~ׄ`9˲SS.KKHq" {o-$n[V0w| 8iE~dYmaa^(Pm,\wb(;p-W`o:Nvn Z(+`wp`ZzLhlߌ|0iW'f0{;G9sh! k^6&y|^1i}F\fB|^fi\BBVh/>s`Aɛ Kp&BC [>1F#X| 2u ]jǟ>en&0sT#A!75{ٱo;FO?ABu'l=?NGebWؔ ^bͰpC m64-’h'w-~|sv*ɇ f+[zP,ZoW@/V'{q CU# j%#K\ ^cU\fT s[ð+XqC/^ɟGj}]\tA{-eIOUsx5s{Ǒ.[IxPڿV$ vymmf/]ѓVyv?bi{-'u2Wa1kL>N# lA>koÙ0Åp.BDy0H*0GnlU#v5+9z4iGܕ%rU;7tO(E Eؘjr@$Pq^|@vѥHuMt56^ -u)WWRY 7E L6 O2N M^nd=9=P<8Hz11$p+e˴pz]'t c%`Nc&Dvo"D+>DzP^R9|Y, f))X"`!G,Oyh&o4%́$!Pne)G~˝j]K^,@`5T?.wɋztyҿFkX+r;@SAyf9Uz)jS.֠g &NcHˊ_>Q,K8437Ɉ.u4|@wm$x~i@$EBBϘެR}[!cT î Jأ'C- NFH:C7%;F%Z3`KN5 :y4-fPS9嵰-@1zHш 7A߫ XO** 2Hĕ2PjYh7FVUEu)Aѭ o6>v/Lϭ,AK{}No=/+^X?a-#D)~lkV(a킙Cbrr8_o# 8t'm蚖rkj4Q%<Q@r1!-krߐJR^3f6ak^]YpQl{"ud=${]p~+C0TՂ?%ۛ\b_ny~Nˈd^a/6*E^ѐzO uk)ݣZ}:i5q3@@ Kk#EZ!:ݍ&GAojݕ`>Ey48(\X)/dˢKE^I08xYћf= j/$'SL/ȇğ!&1D"Aϰ`MXG8^ѷG-w494/yUwzֈf]ـ܌íubVܘ7a7oW@ _Ä?pP*}7Y6!"3.E_UF@ k݈xC.  gnD~\ %fZ!n/DG#";Ь SzcH`Z{ 5\-oLa ;lz5~-#60<2 _ m{=`$zt{#QgiRBSNۊ\a)|l'5vuL1D/.GC83υ{K@2{> '[!7g4xGFl%AF([J>sNcRGbgؗ;0cQ2h߉Ia phĐD[OU]vE#|r$Cl A졂B@I }ȟV8QӰm={q!e*dl$(!iW Zț0| z 8'ü* M~+%a\ |c8 } GBy.KKK:J"ZlWmBr`sSSԚzGҚRx?Px= e'+ M8P2?.Qclw\F750`}'e]qU>(6/+fi}c C='J=ZލWX إ 1An(&6 IR9tϘ:.(?yrSD`Po=[8#JTv$ 4ofU6:>c9'Yjv~"ϫTț8Y[<<͜x< <8i P7lA P {s G8L"]zxmՠ[֙_2^,γ5Z{H=c3*@#<\ uqr rܠgFmq sDőg$+Mby\E /|JաccgnP1HEAF3bND*yGꋥf~Yl9Ʉ%][W!mL_0:&|Q-, wX:g*']!P/xBAK#oIRV]J6Av ԐI-p*J(D8B#.qi4Cl+T*c"XaG1^o7>^Ms3cz5[w wz1\=dp.͆ء Ld}u6ATH^'(:*4naUgOLД < [:wFs$pC4ʛV+aEt<~!|VIz{ٴR^-'S(h7pFmF4$kM07oҍ"~/: :݂؛pbrXe}OQ0hU;!N\mp) _+Vr?7LPr]U",Qv&$7ժfH$,ld[tUNg,#H%ݒ*RZQW5H%=2on7xu-%gN n8bLQ.p3D6m5~ОC} "be?};H/Wv哓Y[@DYP.-njg2 @{_̚5V ƴ`sC{Ws/Ha^6&mkZqhC74sF0%BRL!ҋe-X,C܏sh?)%pPA{ ٌcbaˏ%[p:fGcG WW|yX A3vqpbQJ@ W5 @7!ke_*&YV _k4'?"Sh7INNpn+tD #HmY I>"h8} ;={ʒL/2}qMOd}:Dk4h'Į>* v๸r@C|&pKd| v'),H{8_f@[j wX}RqefM^88NEhڟqi!1Yi{%.~".5ɕ ^0~K3 pe w$ʑeʤ˸Ƨ9 n.̟0J\Lܺ: ;-XmjXa$y 87#$|Z?>Gh@g M]5wXI[f5e_i]n$/_#)gƏªonMyCfE` όCRj<(D_awt2v[HcVqk/ue pEu(EtMӟiF/?9i֓W*Is-K# b9L3Q"=RbG;~o&Mr+cǾ͞+6k8^k%[3\0}>?O<kdTե(Ps$9ޕ])y(^:M0[tg#)Krd.KKum 02,_2 }9 Yn퍢f6N7=*J6RLtdjq7K q2ӀSi>ȅ3@[nF &STBAGz4u[ E O.j)5Zx|\5f\;S\y3# p6Q~} (UD ~7/Z4 UOi We0ɄoAA0nߐnɡ'\2Q+/` EY>F#=V{"Ar˃h@tm}L4.TJcK^)pcY4C8`(T"Eђ -٥jf5;TeYc?Fu ol<_6W~k+-5[<vG\ȣoĆҊ qŽ󼈣RI|"ۧ|:cXX~?ME>lqQcVbGqHQm!tn%.slHG(~c}5S{ɓNcuoAA0`I ~1>( #O4rNP怊c\xC!~Ch+mT94ŜVҖX-OGr D^]zNsyN 5)"l#P@;B[sI hc!˟m➈Aӆ omv=ZT$:!\ r")+A-3(D:QN@Ȥ#-&¼bf:e>S۶m_/+ )H9m "ͫF u j?xE'ؕBsumr/ӹ/JlОجg~Qug g5crid[BT璌{p\0e~v yhN_2ÉzkA^F"xߟĸx/E #Y3 Kq~xO-yPRB>CT8 jA1\]6^XX!ˊKXcC'\UqFl 7(hFo&y]v(>v@[+ *iͿyp(I8xN)4㐚ɯru)\=bFx) 7v(\AV#}_>7@XԐ*< y7 4Ve5^FqOs{ixEbdU-N p c\oZi>a(~CWaA B臢V%T;>z2XJ]ĀΣ5ǹ|5n>:åV~#iHx.bG@1Uݭ&Fr[< Ldj/3;>IpV5FLQ( zXY!<#cxNe-+ڃ|YP8:6;I%!"؃;nk3 bCAN QORM?̙2P' 52Rl_cNq\&gO\ʝ쯃;aƌy 1`xäc^u DJ Hxr!m8~wtC-rȿ9Y0UUۘ$[B"P;\5,9}H*/S[AB9ErL(=@?Q3F9٥ B4!nc7}ټ4/V43#?u2>Ud) nDbSSՉYVnn}ܝ'ɓ<]k[2HsPdJԫ~'vȡ|Z7rvPl~qbkاn=5'rھXO<f0 LJ޻"@.b<kػObg%jB4cGP]x+U;3g`fzZ V$ yoX6U@t=8ƙzl'$Rc;t8f/w48R?rр-hX(m%1#F$)4(# $>],FW9}5ny; sPI6 kJOĔϽ3nʗsܥ9VD' E1 Lb`BxN%.x,B\yqpkq^JiRqNk'vHWG 5g?p\K-(@ &j\M&mƓ3ljrnC{oAV``{Ah-B 3k# =BKDf鯪x5R&FWXnQA`Ӄ ăH ,]lβpT0[W7O^2:/>Kݒ ,ϔX¹NlqknTB!糆u)P)|X0<ĮdL}yq!}7pkyX6),J;!P̈́U#$gYWVsXϠ=mkSiH9 ڍc |Si‡BnU,*Q Ҵ鰉c@JutX.'"sVS[ &^z5K`QNX'g9vq;5ao`^; hpbѧkl52(^-|[@CO{hfH҇G; cYd'TQLTh dV[}EaXIƓc~\ӣ~^H3O[˳M^l<,')R r<tJpǟ־|tbfy12B.Ifg9Ç1b^c̈́N1vI۔h&B Xkˊ5 +g&OIj\Sᗻ(!1*FjzEti\v&<.>9G E;8m7 O˲ =UʚML/&[n?I|p1NoRA1J8)%NΔQ†(]w?^]čK4RȓX_%*޸ }-V?xq.Î/֫wpC>paͮ@3 xAiьG4mju L KR-`2gyKvNauW ڕH!!6n5׊ iF*,Ke>YjQ͸gpѷI승>/IAOO$Dݐ-wz (vp Ъsf(7£Uڊ#9ߓG[>'yA8k=^3U/r%H4cګtCp@r`PЦ4(tPxAÒMI{,b|qVnƶh LI{+tCy#hR9ﵹ+E bdk[)yD%Hneو 8]i̔$B  n|/~bYa̜6o^Kdt1!+AG)۽p1+dEB>J]qyS4-7\E:&0R*;CV`;Èq F?XVI^M٭(YN.M0025; -^4 G%o-3 9T4eS0G0BLTɇ3" 2P` o H@_Wfbr=8:_J`5ƽ:LPcg\&d#1G8?Jt{]E|:F C]" !ߐwH`~:TGuBOw,kz/MIv3@nnKM2dyϢfT_'˔!00ujM %¸?wI@]q*GlCܥ܊*{Oջ'K<Д誔U^!˙4̺h}*qDmkQ7_`j_Pa~烬/OIu%%y 6Ა x̝ff(f/QЖ}ga0A@fj6t^?'VgNIno}ߺ?? {_aXJmȽv-sLɠ~ ֟p"ғϺ2s1}lN͜Cu# xT@,5(_+)w[OVn ɏb: E<\SC0'CU rEP;tZ<_a 4/F]l^9ʊILF4j+T)WU=C=cIX81u NL780 BOQ 7"- rZ*o!4ҼyC4/ uc`!% }|g0ZT׆Y~&S/HfØ2ǜC)JchC5 @xB諢5wȰLjO:^,hv 7B } nSr2WQر]ݡx >4[ ![ D" q6W4{5P+~_;veQ]1eu!a+Tw"Mk3@S!@$0B̩QXcEzae HFmOj[:?NzΟܵ,ζnHR|Nru8%l~ m@>ed(#_,zfFk\N VlN$dTr~DG2QO9L<_uw8PQv3HVg7~dF*5l^jPP ui˥NS3-K tjt+KYq9D"dG㞧rj/);|fC-zG(<7jwJ;VMtL|ZI oя̰KhEpTՙzH R`[9A{|r[(e;lչO`**ijW:S!,}6A4ظ}俖EKDZN 8J9(G%'_J_=|e]ם?HwTg3Mj IɹߦshaHU:i/J O5~8 updo=R5>^ p.c^aڞJ2hfPyae; $ N?Ŧ1bݫ{:=4yLמ;& KH1_iXq%tMUɭHݑ*ȏM~ih捱Vv~Ӱ.0ǻ<_i}=Rx07 1I-_qEe&ɢ*- y{%b]?<~H<ӂsQ pBx1\qa̾IMc2vt^ԙtJE,#; K4h$`KsKɸ6xܡgϣ\qTHtl6Zs[kf u1҅՝( ov9;0܈XRCa[V OmZ[4bG2r0=tx7Ai Ai.~t-fA[]R@5@ $5I,_A,DCK9%9:`pTY$wkc*Hy uaH}2jVzL۲H .F**BU73s6V/MATsd^-DtN$1,&^6x ik_fk]V/u\bӳY%]s(V=>uh+#kA_'Z{#ϑ#]ݸS\iR:G]C03J7XI#׎EPV3r2;ƷgCoi 1]:QH,&;_,=Yb̾u6Ҭi=Ƃ[&jOVwMPN`#CI$?;0Do}b,xWZ\t/ %5104] ֥)27߸ݡOӎ֋n@}52` uJY5(Z.'4*="|+"j%s'Wp{O&x @{g#ό>[+䒖{uG_"hGCQQJfU}䭢SRufmӢ]H0[ut! L䂇Vj60,6a.*37d^=&KDJja*nj5Zq< J^*J6dB8*y7$JaHnj%YeMY!wjթm/:9SvP-Pɘk6x'fE$ _*2:9A  K5%CU34ʶvƽo==g C y;AD>O͢(*ysi5뺻ۢO45)L!K?m'A:O# t]ˬWuR0۬'EjaWRTUY+2 J\UlG+Ҝ A\(L}cdMzXઆL^UMK1TJR3F|syFap].#Ba@j6[Uݰ[ؾ]'T6_0bnw;O%K=ZF 2jp>Dծ ݾX=XR(p]RvaG"kmm)*6ݧ'`z%$T2Y{X*G79SM7}4ٌ@ɠN٩W6¨\Z hltIG5;Hmf#bgi)5"@8G7Kkdcf9+ڿCR0n-yaȵ;'ç2G^aaXKq ).a-TuL$#L&i(E{nii(لys_>1f ̹ba&hͰV}4;z#n>bud܃vXy1dTP]+f`$UtHŠ<#.uwǹ =ԗk_/z0[Vӿ6[x YU?fK` *a_B 1)Sm?ܧyȈa  ŊxLKEZ},^k.[ YZw,Πl/kT)9  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n021023l.pfb0000644000175000017500000032327110725114532023115 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusRomNo9L-ReguItal 1.06 %%Title: NimbusRomNo9L-ReguItal %%CreationDate: Tue Dec 31 16:48:49 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusRomNo9L-ReguItal % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusRomNo9L-ReguItal known{/NimbusRomNo9L-ReguItal findfont dup/UniqueID known{dup /UniqueID get 5020937 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusRomNo9L-ReguItal def /FontBBox [-169 -270 1112 924 ]readonly def /UniqueID 5020937 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Roman No9 L Regular Italic) readonly def /FamilyName (Nimbus Roman No9 L) readonly def /Weight (Regular) readonly def /FSType 0 def /ItalicAngle -15.5 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec piAD4=sdSlC 3uE&v`j[B v*![Hr±.l}XT{K@5(Hٞj *\w}^oVI[3^~~$IjSVѹ2qO:8Cׯ|ug܅ُ$pJS"<)vfsid=;)DHltC# O c:r;a6L$_ȥ fل  ۼ 8419b N~NCzhtZGޚޝ@uW݆ojHQaRQ` #$iV6_b&xnnXǣj?cB۬᠘4Nw7?סO}@ *o' OwI|nZmmmHkk(F%,BKS֠p0&w)BIL'% rq-ڲ@ M%_aXKN:q^ADUօ-Zsz_MZS(@|cw*SRs癖Yᩬ1^{WfMRhco,epj2#`uɿ+KLjcEb y]=4Hbk?>*KtwV23uH`Dx Hs6 `e~:I7E5K~PfḶJd _+ΎtE3J?Rb Szӌ}bG44 > K:s`StKG͓VΟr34e5_?UĆ:~=WD{\=݊M [0l=FZ(V,l꟣pЙ uO3Yߺ? p!P U8#C9Me6 Cv[}<ЖME!FdC+ v46݊N]31rNChMOf&tbsz«g9Bf*k eNOs ߍ$yfXȻ3ʸnvTq;”7'4A;_͛^"i^$e9qA87y@Mqp\U?zzLH]}Ͳ'߈;qя1i؏}(42P 'o9Y-mgf |v  ]b[M9ĥ M7һgӠI MD΁&C:HSؖ**hZ!}%S#.o*ք>‘9#ꌪh^*dqޤoiY9wjy;/w#p< [^6QvgkSTWhC/5٪jG)b*W`Na-uxS t1\\ВԮ`&{E!CsDY]~z%g2I+3U-kl[).n؋'u f~, ]o~G7ǣRzqyMT.·9)53ɥASK u sW9l!i +[g>6TX_2δ_L">538GYD^3XR;{wC'I\d~[{ѻ1Ԋ BHB^vxu X߾WZ eO.{7Uj'{@L$Ll<89yy<FdV,d7Lm%ɶ6)j3s"r ޮ~2 lI6 n㲽v: H^d1uaZo?k=Qo'`|y,bɴ2hVAME{f2OB [fq/#S:l%rVRkHŖ/:{ i8B3U@l{ut:,̏(ÈkYv URyLPN AYsD&՝^"qF9e}N@]X>,66}A/rbyиR\aje<3D\߽a1Z3WLJ#?ʄ:GxקrvpO\ӫzxcc˔`C@ʡqU I_A\]eFX87E6q4h'[:"Bmx.6 "AѨc",OөÊ]{[C<*nZ *K/E77r8*"wS͏Zj6PPg5Z <b #u1?P巷5R !gFkLMU4iFm$,)0zL;m;+Cj,+<yB!7anByq;Wckn.ul?#Tkw̡͇t.E^V2}ۈ }XMwV/L M%y0} [" #-!Nm1bҔO~ :-6Xw}vL$\ISw*$aMN;maM \g9B3O@ō>xNPJp&)67xkaxĕXQ25 ɛKšhkCh.\>!>"XVT r[IJ;֡Z1A$}Fi=_qy8OK{̊2c~_T#;3嘃f[UwX0Z$-8- d{;[  f~oߩ Wj5 mE*4*7yvE˫֭44l֌v %\Øݡ&eRŇ/wûمDA%sFa/<εSZChlDm] 3|+ +^(lum+>M4*$rG;|6ayF 3Q (6\ ox_e̋P*8,T:\/Uoo׼/[5NrM"Z Xu50|ؽW$~kKދj,<@Q<1A/G`3**đpsM V[ӫDn"F?LUb?\mc-n"Jߘ?fY7[Y' x!ppO!Ӣ_DD CfuԻZi6Tc\8*FSؗX 9'1&NL^ [.|F&CT_ ^L/X<66lix" O`n+Ɵq:$N]E# L_-3YX Tb`DCTx5e^lH }edǹ ?#1_1Bj`+dw$?wt7O侨ltA S\ ՝'ՔGcѬ׫IEIeNK(X'Oωe¡`P$3x a<&D]zm_D^Jو],4E҆?B%Ƌ!s(0(WjC8˗B(KZ63`ۏjryʼp:zN4\"ٲ00ڪWxyMDUsAU> =ybS+jڎͻ~%=JOIeL~^>e? 7%[UWʴObvo!쏗4@3cpscNt{%Am"S#2cb}άY6`~c7MBf9,ub1hLJkIwg#ih"׉==\Xx!U"Ҕ?fth=Ri% >3)2$ W:GHDyl:` 3W, }&a xB;j@a:q 6:M@OEZ4)=UqeF2/ ԮN f,M jQa.}mqA?zFBNbǿ.(Fx^'AcBc%Kݽ˨Cw?聴<2Oq<^`WJ.z.륜h$ AV=Cq_i˽@c3eNfK@t/l6|_Mǹj1k|U+q |Uz` ?k8xNC̙ijYsTT[J#{}m*e M+H


    d\Ƕ ^2^v2nQťVYLy)}gOʶjN-L"4G oc>bdCt†Wu6E?ZrЇs0jÑLkR5 ;H6pz-3Z?b&&fU(@XUA ʶ ;jW*,3R׾a{j3X~mN^ԝS~aUytL;0p."<ig}1ՠ];1sY!B}p߈$[OX$fZW(W%yyY~L1xp+֔Z"Yla&wC(\LNvi|i͵ū^+;D ]VoOyjW+s)/r2M F0+= Y],Sr2M[f8 jH#fd s<OI l.>G"c|h<_#W{_B΅Lb.;&1$;6'PrT2ky_sSg/f zd}}ico]lWPGnRFΡI }P h6N_~EGI')~VH$4u$LNa: `)Me5{}aC^p4!yWjwto'Sa}_j'Ia¼?P8 ·E{ P lF?x]A8 I opД9nuN]o:~ QWD_]ATܤfr\g+ +pUcr~ǷHݵ *rт"i{t΁r0Νc|q+Zy*e&}uK.Vbj.ZrS|q.u<*¶! Uf܎Vmyxcg3lO Ae$ 0j?ضPKzǪsC)N~nA3/\Dc!1ĐV% ~;B¬D+zbSfgs1̌e-pfY&gDÀڔ~ ̀> YA:CfdwNTp`ɍz^PkXUt%Lm[JDU7?JѮZ֌8<[G=0H#yNBsC5g H C)hW\ZXQ?EXJV_$%ъ2_$}zH`ưk@OYPnMuH #kV[;J!Sh$c1 FO.zh6$|o\[R VE%Xpy&L/3{rxQME IˌzhHCr3<Ž#t49e1uX#'d"0**ETM S`YS&U>#I @=M.~Yg<ls<B`H0 S2Zp&d;,CkB-"Wz\o^N`"AD}{(\"/PdN|+r}(Qۂo|>qwXAB"Ĉr}Gد+RJ!o>È+SM(kx]Dp\Ї$˸~I)gT&Wh r`Z0s|uAc(qCZX_ݦ:4=W[I$J7g->} pK =1{nwcp~jBL20T8J8Nvpd;iC=ʴJ/&= t nǜC. KI aй( 4]2m%n6?oQ<>G8_T؃ռ\Y\cBB9F֢Q1.= gk Ln+!WR+T;h>I$-I7F؋hU6Yyewkz  C0Iڞ R5z!v=kN\0@eng=?zΫWŮBxz T/miP"A 5!q~[72a 'R.F9۬MIkO][n{ɂHgF{;y]w쳹w@u8㣒ٿnو] I?YDb&՗>8d/s%As#ȕWpBv倧mtDF'XDP& y63;c4b$%2J5'hqHVpܣ&E+3^R\kŠ }Nwp]ˈΣ؋t /4Ba:篿ol'ׁR{ߪ6*3l)4[<$W>q#o'q{jvs@0bVWܟNy6~ʝb1f^o]hx u)UgdoPK`፮ւmTޗDjRd.A.U>A<`pO66)Gt8^Q ‡Z>5 {Fܘ7f* +,/0?#EshU%+)o](rCK\-,/PC:  ][ewxvPZ _\J]$S˟`a#׉LJ\9 @@$R،BQOͥOod_:DH-]Lђn5g(a֏Fo~}g_#.+*)EIKs%O0,dE:gp_Vp*սW4L.j])D)s ۉxԨN}A7MTJ}к$9EN}6]'4 K!]~j9?=oᔕU (&`= PfpSzpܐ4wsQ$._Ml$Yel xiEc ܃?;9j]Vٰz~J!ސgS ^07^QzrkVoE8`q(E gl;mzLQ\vBAZ"p@j=9]TPN5:Ym:(FW(*wwaL n-^z$KĊ,~C!At# }:fz]7 +j3rDt \2]Wpⷸ2S6ò+Ր5@}(m~zS 'm?MG͉[r t0spZm>n< }G0 Ў4)'%~PqS1L> ?o8ʰD Ԅf%Թ}dP#}z8:㏁)J/bZ2p@Co+qaLogpN 0Kz'uu7y2r[x wζa҅qSD-\,,|/V 8U:So$ (\'~o/ 5$::7QnW{W$4~6FPM-v2R\0B_x!_}esZDp7vI0V;{ }gYkFM5 Ɇ#`EODXs&^#|\4;SBHԇ{ Y3,YwJYf=GW@/lCgqV؎J?ӏu0Q$iRscyj`S'`u +eݥa "E= |˗ATVV|03yh[* b,/töqe=U%@V(C+=3 A%Rp>;ywz*kLgl̜LUJj8oҹ5˸E٤e^ iWCJ\AjCk;KB1"[JЫ~Ś(/tHZH(k *E.P=s:kOHcɮV2pUbB`]B `t`77ZYa=HG+Lu +5m e"-?IkC?Thpz,/2RC7By^H_YEzM#0c7GyM;$Wݗ۲mb>\F2c&(Ssɪ?oٖ1t8Gһ$NsKPH[ЎO搋SҀ-mVqL7832{>?(*~vu+6`Jue-5Yg$nmGbgeٮ|pT/[9Q-*əeeH`|VLD6`,IϹḲ#A//=3ƶd~zT,I>5C9zq MKSc"'}][f; ơ^]wo]o. 3:;z5Ea*ۃA ]. & ]4{m4H?AyӞe fA 38o0TP.pH3lUVܡJwȋaM"ӟ1i#n~zd?"R$mK*60*zA|MP!17sAN eb`tG͕!߃|WWYܑj[Džg0|8/NxN?\u(DT@߫s_OL.׸ÓhƭըgժTz<}*bcގn5W` Q$6(RJŎ r:~9f=+jcA+Iw6 UkJq`Q4]{sYq<gZ_\9(3/:+և#iC3mlyP+Gs֌W[L~/>=t)Wn=+ʸM`bvB2U~k-1 3Zn?))2;u YrIK=+6TNhsF0]w ܆J7~dܵtai\Ddcm#0E⌦$- Ow l1|'/r,n"!S@mlqD]KU;͘αsQS'_I;K0nIT |v], =7pzBtI UoSsVcヲ/!P\uoK)zl"ƞye E~tc(go;mْ"i/#+~aHХc7 0k"\(ߪ `:39p[BќD )S޽A? U`%ϔفd(\{,Bb"+&ɶG0~Yr|JAm i#s'2ίCu,oYhȲMןQ֑ 7*٘Mk}.+LẌ́oجb!M7bQd5.,Sءu Ypwޚ~n(i# 0=?} '3hG,½;p# "+뼡ei0vNKWE3!12gLb_m9qaޘ֒(uk/`ykpatIʡ +]_|/,P^`& uk?t}sۏq%3o6 _u|`?҅r=]e& 928![!ΓN+d>x(A" DS3LH")dG?n+Q懨_OL~,qo;@ .c4I F8]' u։ǥ %uo'ubp C9d@kzeXu'.K7C$ӷ\v^g*l%ۗF;N0ԯ{mr8QKvtg4G@>PKܻPQviWdS` 9 Y XU~B7D|jE#&#ËAb}?FKY|Y{gZu zg>C?/l,[kJp%E5 U-G`߾F4;Œ!6竭/Y?1"<"dO9=R:7yƊEr&UJF'5kI4{d}d!D7|5r F̡5;,'H@Er1S\^Z]/V1's\E?q@+<0x?D\K50b&?{46zƆ;+Br"LAY[T^[3%@Nbά{`؅"Y:q'vzM+ReQ̵b !XްbQ5t%ؒ2 }LS*;aVkrD/> @",|vVcY9hy6A&4SG D=(&;NHΪOHJQgoĈƎ[E"ACД4„}K)aj&G)ƽ.kAc*;p8Ҭx,|  KCo+؋ Ъ$ | 2ҫj8Á {1دا+TN7U#uQA1Vy@l:x?oJKkec6ZIdEǎuMSh{ekTُxB(wKa3MlX)`:32^MO2meLTЊSe2'j.0H̱y0DqbEQ񱳋i 2 Ia3wTAg* _o4{܂D%kywxwZGr` JvQ՜n6rWɇ3D/,1AL͈m}̂H@R܎ hm`b[_?uܒnyQ@vH/#o)l`5GSD`LB x2ڛ)e_yTt;L) > SFe{P5!n3 ?·AwK)hLt,쯺kޥlIx-BfHzqC|B M`ms-,-C *#et b](e lApwt7ӜQV oGؙ"v1XϟS"%#GhKol)Cf!lOiaS,ngiн8c/ZwTyb[$aEw)@Jci W1`` %|/gi]'|@ʴ&O1'9'FQ?X/,{]pF/#p y9:}je/;wPq$ҾԈ_+`*1:VG񋡽۾U/[ʥ9Ud=)Ts4'ֱ^pȦ!P*eրâ{i}OkB QAV̸pYzTk, $6I_e WnRXWǹ 7$ h~$-uZ‰ܔ=XV0G7L3m6T}8ߧ_AG?77:e2&+tsC܎@/uH@:)wPf%=X{hFQT<^BD-ʇMVhkPcDhp_syEˍ5:ĨbLTCRD2w!u$VJEF*.7x}OϚ_:ڝ(g<}I68[d1`ޖ^pNu;QT&.rԔg$".rO2Y"|5SOȧD[u?*ϰKP͡ۂj`GV5)f-E~vfbvB1' ^w0Vx_3BwD̄5ې2c~uCQ.N>l1D#}4Z5F]օM+_T-&La)#6'9]hl~<?s6OBG.@gsqaQYR{`eUL~WgG=_–ղ$Sd9'8ɴ 6 /,U# A]ꏭ<78CY%zSxgWX{ \8joHT$)w:[gk?py/Yy8ʚYᗪs^Na:5]2(kYp-Ig?Q%&R_$8}6Oϖ+3{fn%Ij8c,04Խ=CԲ`<4|ED.=ۣ;½O9&|[,yy7G&ztdz@w,3R-'sO&~;$o N["O/b5j~r^Ǩ<z!'P:E/z.d?B@Ɠ+dױ(f1VI y)ABSsLk,5qLWX2Yu5ub\Wp?$2GDמS )2t*PK<:Yn[%S«2xMiB/XQ&oQlp©`N ](rUJU8[Qbr Gi,? K\岗)4Ef~njuX_P596q*iKp{/ %bc0mL }7'zLTڡ"g~LZoI!UΞަcIȷڊjmg [ZbYE+;NL͇qFPr~(>-:GnIkFWBt`5u7u?1HϿͭkuήY )\y%l]Try :Y.6РH 5J5|Rh9@$p)](vDu5jfƭZWM\V@ft6+E AEՂ,KBT,ffqYJQ#Oէd=xg @T`<5uϱ ' k!נk?&O)MD/$%jH-OqəW*mm M˒v9}m9‰MbZLg!5PikF D9Gk&NʴhPj-hgo?n\hx̭.-(# y(քa6mՐQ&; 0(KI &87{:$_=Lw(zL{RZC%ֲ/b+F/<=7/Q3ſFP222g"׬Lw_.V,n#Bj;ҹnOcºQ/,8d.Z az2|C8ƝCAQ-SU!>F:$`RJvuץi}sQڱR,Jf*z>Hs[ޤl *`IXG&;p kXĠ. Jө#-B/mDooQCYVDE-6ifchL9]Xƛ虜F2x\M$+02o+_mN8mcvK X͆`B'e}_=m*Y i.7'Ǒt%~0A<ָ߇Ւ 0&;&aG,g- ;/) 7VP&3rs:t7zkOB;8?tn-s!= ѩj11ZwPK蝔Oם*+wW~N{t,Bd$ڒPp@#GMCoJbb$ظ௨Y,ˉJeyE^ jͺz̈́x9}C~3DA#:% 5F OU>ƧzW_59 NLiLO8)ml >WkȹhtGȁ>NGs L#lO[ѪOFHhEq L_c]N3o-&ل'=ޙgM8CP}LC4#7.@9rh!:}H=^ɥx~وNB͠;nY 2gpkY;[L7PVCE+0RtW +PUnџ}^wa3a٬&0won+n}V #b[Piml%i] i' g'R){M#Lk,[l.RT_CH^.p ߄y>{Ih#*ucm=y r`u;Sp+m'HP/1u9ݿ'x0dA{T3:vo3I{<}ďck[%!{.K%G=%# @U&&:n>Rc'7QUb_}wy ǰcgreq_Dz7򫸏05 ]$#lWm;X%[+(USj]-NU B_`e}W1@;XW98*P X]Lc]^e$= q4_eBk?̽6u>B?<Әiu0^2vvdKQmݸ~L,HV+a_ $MRq̃p$%vnP;_zM/tPilL&&_x x":39* 0xv vhF砪k<@)og[}&&ʂ: F5‡H/i-gux%x| kN\Y*y|c(J٥o#;Ox _E ꞼEv< &Q1$z/2>:fIs`W FG1d{]voS7gEE?Fe.<`'Tl`@Z7 _CŢY D2'Ӻٛh RNs# 鵭9fq[aRwt9xtd0 ·(-pEw~-M1%"/NA9UnYK}ѷp=*f0({vL8Y4ئ{󟆳䏺lg(eY5<@96dDbʺ0~m_º`yvXz²Y?J˵~Us$X ~[zmL ;x-70e($1k  Tࠣ;F]48 nB'DK cJ>֒s0cKx-wCS*7A8(Q~O +' GD-ZM}K5 ee7$Qؙ+ia@.ʚ GJL 2&P+xfMЀعr<ɒqG&[v|,^yIuC}:bzsA! [{$(#u5kG$mỉwRu쥷Kh0Q/kY%:Q=Ӓ`^' zRá9IhK Vrvgmw; P$QDُɏ`kj.srJ3! \{Lm@[VWspF "j~C 8g<]Fr y6.6}AKV8BP?)*]<x(r~>xS#*A&ѝފLt nV~4#Q[BWKz$UV>p`QG U~H|]&D%n´g2@Q:*[(#9]U0XT/t:. Ks HTHCϵkW^Z=|6eP<6L N@vNIߝ8h,IbnSwo~`xԝ hlTex/ޔVK)|Sb< Y搹 l~x&abv[2٨7J<BE91TةK`IHbS\5berd s8O_sqjl{#8R>O58F!ѕ6]75ivX? EWm]To^^Մ-rm]=-PDh$L|*Sd$Ig[ֺmAңX,M F%'?wY uuaCC61/5\_lhVRi+.8LV7+[q*\]eR>䧽辮I^u{b KjmrD;L嚋6J뉛JzSD~cUJM9Q#龶b· IoWIssu);64Io .Ð77wOc \d4}&3yI5@uˋ͇CBG<^\yz_9ByiJx\LuԙLps3ȓ$W2tzj%8"Wc0i|K|G_j lWW, ]l[7W)@[P b =/$nDV&&"d~FeY O3y"hƯߴskw*beJ11x5$ `8*M6U(P!մ2,gmZ7`9,)w@8Ny#\5Fs YbiJ)T92j`pl?֚GH\օUOm  MU =*',"J. ۺО<6k?Ε9b޴`i^6y&,X@^ҝe6͉J ],80܄~ Ӫ\zؔ7R^ݍ{ip϶#2ηbOTgdM^TK:SW0MgbF5{fL;ƹ$* irh& l=gTPi (sq F4H7;Zei giDJ4aQR:݄`A@wlߕ} ENz::P(g٨Hˠ;8S2HV\\hk0ev@Ql(StXDRBSE?QrCkC" Fţ*JV.'@ Yn*'&lbSn0~NG9["F7ilq4CM&},lcl[0k9Q($Bgxj&pԐ|q}Vxҝҟq8 ?8`q7tB)$Tޤ#@2fӟnvb>b(E,p sr%CV#Mi|/7yF]?x$+r W~#Xo-R.nsm/Qӥx#(қL:eRە/:p4#mؕܔ7.`^]s*+XYX)6vRUY* 2 |1/3C5l,ûX ee=$POZ6c3$@{yfB5:`*z=OFE_8xV߮Cre >SN'B]Izdʢi#8y\oks ȖI*`Z1TpߵoWA35iT%!//IuY^,X C/Nۊ\$Mr̈́Dk%]h@A.9-|8O؊x8$V8T6 %-vSSN`԰U.2d R5$$Zunu#c-ܡJ-YGA:6_ŠF%{,[ ¦w| ש~+o;bn[092@Аs͊c ^!-f{ ; !HuUGS8`YF!ٯiNN9O'e cڕa'܀ $MП V&ȑ/,/hg1*d<&: sa 4EFH>qsP y\ `Pq ɶ7nntƴ>ب ԃJ>Ay~O aU_\1qڷm\kEK:X.mA?R {g6F 5WKcMMO]̣ǼqK$Sf5.,شp#=Y3b8-l;)W1pz]Li+UE,P|spUo׊P?VK99c:b$7Az5C'3rlBmEì*t= Gn6ϛa/|4#Gl%%\t/*R*l!$_¼2*Ha+!{_{4}>mIYdǾ6G;7R:"kqmquEZﻑ"2M] A9vn`@bUPpkm=)WA|Ji*E\lPμ9$4H9*/Adr5b GTkj +-Ȑ9oY.a9"pNЪ |D4]ZoSxB3$XOX ;6T'ҳTtx[pXqQ AVErbsL, Z[Ζz(ia:U~H"\[~@ffb%$Xf2Oh$KCrx+!`}n׷<ݩBiBw[-Calx9Hkjiza“vCʘPd?C0a|FNLPy|h4m_†z {rVZ<;_ y;M"Ed4 PD_E"a& `ý,-nh lշ+3 /&X:o]c ioǜ%;Z$VJ f\ 9x^+ʘ _ǝ'xf.br2^v]Wi (Ǘ*0E\5:BST JY5b;FF^D$mG( rU_eVb괃[pnٺJ3]hFI4#jy fSrOckHjgpH94r 4 P!W | 8O G_tm]HpT r9<7F˶쵐l¥NYdZ{ mzqK w []qI;2cL9VCs (B1ڞ\m(8MDsKl>8ѡ2ZdfPg̳>HzrgURɡ_޿g*q<3T/zW/dOOíX*#z~m8 m,7h}MMgyhF_Kրd Ġ4S& S_sm+e5 ~擰0R} EGcgdž.C3W>.nZegbβf!1&-G,A:D @=iEoNBd kP gjöIqbgY*D#iiJ8 #^F|hg F^4y]zٕl[tRhfe脳%ԲYoNQOf߹pVd%%VqOUV4J?M`%T{N_bFA۞( Sp74.? da> HABM9<䝗!S0ّ It~jⳣHG݆ȏי$0nڊHռS7͂DplJ;ފ4uZ G;wx? O{6F>n[C5IVNNCҦf8q, 2'WZm OC+B>zNI_K?u8*z&9Z\$nv!eD~[BesbyPyKENܵO.U7Jz6G20+M[Ạr8.Kmk[t8്j4U"rnSd(gS)J,їO.5V; ~xyILuɐC3q<5{wq^h !MJ0RJ|jnI.bmcXZ0zzz^d0|wGڣ5x-IpmhfA"ȱbOz#)e.:8Iybl$ʦ2}FDU@l2ZX'TPR̶ -0U7'ab}ь7#; S2t Att #Pz>:׸O`nˎlaT[ AKiO/]tQK5.AiܛH( fNtWgvrhƏԃVQ$Ya_UpL]ea@'u H3P0L3rrjVI=ƻ䡏 jD"<#?9ʹQJ7% 䶏qnu"뽆&4~>AmW~3๟,ZX}w'»t@2L$F ~b*;[K([g4 Ts`#޿sX>EH~E*f࿋sWB))Жkڃ,֪*g½{pK8ɧ>@RTkǞ`}ÀmH'm0VۘY4U:W3{]0xCez dN gg7]i3̾G*5Xom"~Bp7) 0p , ĥ$DY9l }5\Dճ)x.(BPF`Iq<S(4h_gxV;*D}9R ~7$kJ>z%!jrAG!5Q`!>Pf_膸 l9R0yA!p%l@E?n͹2YGEHčU;]\ /9,2+ǥp ^6!Hv! =Y1!YnZluwf)czBʤJƀu,Ru@M;G]IftCy2+hR*3Cرnz&-vX@5P˽t[@RJ(Y,K-hkz0Ư*/K˹_x x6~@P5$ҷ5Y< T'`dyXՄ>u^v^/dG;j˘QeIn&߰~C{S7˭bZ,悇x _+ aM8%䶖yEq龘,طzI,/^0(Xfo|  0]A4lv5c"yz}l$2?0asstѫ`V6 v`pQCY-ۃ8n1|`qAφG-\D9nav䇌Qy SD8b$=Ԏ(k"K$B6ވ%ݾOjYYF>H4 Axm&²d!~e({QrD8͖X %)^X^̕kxIl?Tۃ6DG&.F)e:cG V=s Ň DgWƽOy/; \$'B= ?VdܩHr aρyۃ6JiU[ @8u>j~51zvΕG ةVx"spn)ʘ>n[A܋Z%:i1ʠס*t* -|S/3zT}Jb*yzmYӣp r}iL"(ा&X({O.֐S ;cԏ T P T*sԮGa5u~9Hc\~})OZbܑry|z>дqL7HhJQNGG .թ.ӾC*Kᯐd*zf.OˮN/jh!ʑޏ$w{L,/Q.ڂbP8#Gl<-]vڙ/\ny& o´-QC!TB/)[䔨|܌k7 r.`A'ˣ#ptg'Վ$/M/]ua:`puȩem<n"n$]!HϙqB6EK )Lu}VRI eJ|Pe3t+Hkf+*\9,A{7Y+4l¸v#OJ;e֡y{5 Cqu螺XܿG50SbBhT~wOXjޗ'PYȫueTDlY>sl8n5 RfSo'\(eO7erc-G{JG~4x@:@d?*\MC3&CJE􀀒3}U6$۰xi$ͯvy*}}Ñ46]!w. !Cp,)+A?4B6>)XW;$S3t] ꋷn E|w':E/(Ĵvx#Hx(qȺT',@dQ]lgQs0(7 ʉ.&}\OI{j7۞ ҲE{A8KםoЧ/kr,<=(,՞YAQ"QLZ|\laT )- .50-c΍҃w脈ÏbA/vX-2Xԕs5oQkR YZ45J3zVΗDFL659˘O:B2ɲ5:!;ǁa"d" yą,;.Guض'ff Z׉,%]´mVU::a홷ƇH>yM@2Ε !$Gb\Mg?l*؋-ORB#[|O~9F>rW1Z,Cv3j}wLl yתq(lFU-{@Y)kC 㮕F$z儼_C!1U;>[&IBp&4V+ ¾@>w`d al,5N /%Ae%=M}P)o7PAW?%f It.2 Hp◖^x_M[74嵉qJ_FoM`lhS(~4q7=mgjt/kQӄ,h8!V9.zܭ {lFn]pDm>463&"yhQ0 KtH6l0ѵw/ F)h2(`B9R}̢!С0dK>9+m5p~6q4 Z^1P}]ףh Wt/z tT3H_zFȷ,D).rQ H+fA *AfUϊrdR CԎ{H.nWdHI0V(0YF_:: Yb`e˵ 3C|^mϝ8O~Ɉ3i`מּAGC ya{z퀤X_Cuo$$/mʔ<]jL*Vmy)$maLFb)@ҍ@CCFc,K#92Sǚcv_$8G ޗ_ ^r nzGɺ\Oܟ-G,\R17ӡz\)L9z,Eǘ6KgW޲:j78++tEP* =9G_j^X܁hu D\*I jF^yἇ3-HGb>Ey)h<B!5lY%g2/!3߇U_F?GP3/}}{6y>s.B *M 8Q1(s9KP&wZ"6%%*=Tzໄ{#ƄKE+k[ Ɓ. 6`nto^DBC:1Sz.K>Ȇ &# ه#,KՒ9jW&\xv(ݱdjOq/u8znSM7D.[.whThhߌtVoSEU U̓Z`W hoXgZ:hYOA e_2X=Ճ'lIz37`)?z/WD\X&yaQu&Ų㼹hÍZ{}EM˄~*Pv"\Z"P>w Sy [T6g aQ{N_Kgya3Rp0f㡻P׸5'f,'ch8!ou-p|f1RX>BRR#jCiRb.Þ)Va3SQ+'PQ5 !dIbasߍcx02 wXvWc@2$][|li6;% 3B3:^=-eFg>1|;(J^: pnFq=/͙(ns}Gp^9") UFcN Yo9O9.l>@Y5=]_N-h/rp~KiRP@à{(܏U)ԋaʂ(V/ZC*dm?4k)!4ww!U;I-.u:a A0HWԎqlxc߰/Br{4Zu}Υ\8嵞C&+j j`*_˴v̱Tωq[&gEqm47̧@{1Q"*W;䧁6>􇈆:Ӈ C+HhXȪ ~5: ȕ~P{_=;9d!;jyr˴ Yx q;jR-Ayo̬IK?Sr # 0 OZFri*m Iq&ӆ}wpȚJ+;Hsڑx њ lPZ}RDwT\^h8@ݞB: 4>O/ Cד<"0:^}<ŌG{ ޶Y=1?6]=u:+N' b-$h(!Q;1H)eTTe;^Kd:$4 @`jw\7\krzOdّ$5NHI8~Hhw)yN)"ͩ\,Nd_<2TUPraHe>۳5V,T6Wtt~DAMF0^&^gK0r͵.4m n^Ϭ;̚Rߏ 1jK6SᆃWzU=Y0#N WVlg IʹҠ;hR8^|8tQBj# L"N 5D/n3ߍt۰>\:'ם!%z=7D"~C;u49 yxj .AC%R:>&ۧ*>jj{Md \!l08`-)zT6-ţ(j|Ld鈍syNk9T3cNF_U@YDQ\x;YZX--* @vVvH`LS?mªԣJ۵AE8U{e@Nw4(6{ۖa~"&7sRx%faJy{0" 1aYƣ6T5ӘsZߣ]D)+ex _E׸QvNk"9Ğr w/K$xJ>TÝ.0˔bWqXfjDnuh/v5S"]_©V=3| ?90i1H{Qsv h!u -@idVtv;^#n&i4lՌ 8?Wk>#>S?x0 `?T>sK=vu,Xn[刵aȬ .VU_GċIF>~3lu$_K?.7oU26½OC! '3ηhn\dx ޥra.K0L'T {_ %~Xn6 _%$ M 6%,rMu%@<ѬX1Q ZmwR盗ϛ4wP{`_nIqpVX҅ lDN ew-ffқqZi`#FX$17T>g?w NHlU]-fH>v(ĥ'VӰܴTkwqR4`P1|CEƶ_>́g@ OSΤO⯊,p|ۮÊc2 :$qU8HI<~`dwz?T’ݜ>ƀq .ϘBV8X"HgEmt͐+!eTHFK# gЍGL{e+`̩he08jYk }lNs˛ ]Died;"CӎrLS(p=H" % .0A DU~Eܡfrq l䞀TߕF-D7#,zwSűeza_}ϟEdNq*̈6a%n3c )_WDD3b>Ru! }8iV;7NHc|=rtYAd4O5:oƴ'* uBrk7I" !hJ|-7+KeܮSӇA $:8.}TQ%M@SGK+*fq7!tsAl{'4d85% 7$+#J\M dNn#X"1]vNpayW8E^2@-6C -"uq}?zu`XKVC\Aj!W&L IeC>bi|ČP]袆+ Fw!eڸ=`,rdOJǐO2O[293j tPm㑛- }b "Ou3Vz-?0 : _$E: >' t Pll L$ O=6g=1+%Ft FQ?l_yo6>nȒ$ CrdV-QAElAisjjMaX/hx_;/?"@2#wQu$JW_̧>scY\f 0su23{_ی}S5I1eXatū&a8Q/>x-=b»'ugf3M9R;J(G9nNr|RjeuUSlȝhQœvCF ;Ɍs WdÁM7r~C(8ܵ󪢢NJ,15;!cXEdl+ '})*.tEvq᥊IIDkt9'E?\gm u:րjT(:>9U_#,x $Koq ܖ5nY]d{ay&o!߳M @a]>]D'uQ6j)n}(SwTM2?us@荶!Ydq\{TbT6ҝ-D+&>?#|dE5dHswztf'VjVWdNg0uXJd;>L|fi'D:+,DM},Wu|Fބ D."{6V9gUT+qM"~ћnRFM=C>;lkހ YL$Eƈal Ӳ14 AC.]ïl>x;#[;UP9m02¡o&(h3: iG<~ +)^r1 :p:bq$[; .R~/уp^Q,_Db@ \ZI!Vd4JCBuWY֏RI;:q7'/ ˽8NƼfRO\3s@*b.o΄D%K57JQó(j{e/·YD'z\6$BT樉Œ^S8U+ث[.%gHY 6c6ǘD [^M V~2|;I!|iijY5!޿ ܯ w7VCZLJQژo1an/R FG/ИmVY C6~:6/~{wx?4ٲT ; +! sJ%(ZSY+%`iJN W~w%@9F,$Cb(fA[bD";e7Ma .R7T U=fQ.s.R.R4tl䟮*(jRp6@9?F|ITZ%z|*`+qDM?NBHJFqO,kQ ~F#q?iD̏(ujkp(0<xM%D@XLLWΫ:oϢRr{7A9|SMZ3Sgqf/`y =kr56?6^vQ .U  @ F`fnw0א=h"IqI4 `cq;==G$` 6gMȏiO99c9,LBkMG"uS~i9匜`b&M/Rr AiRjv{j=6QT^ZA@nL!EK<: [<5äH3,,!K ZK,bѩ(yMe핚R{!G/Y Aﰷpm^K%hWaAJvpp!#}6N97)}S pv~nvPic}T6N*/H\P4r3_unLӰh",9 b\V1ɫXDI}XqQJJ{"I}3mw4COD+qIaϒE 6 h׍p ݦIFEw:\G%a%\Bova#[,4 U'D+2Ώsi !x^O^yK-(|uD!WuɆw)Jr|!D;4#ER#ud؋VK՟ A0{׹xE0MiRqE\>Q"iËEɔsx8ѿYB'VS43ys{M1g*TҡQVH>Tdts%LT9^eP3ja尦T*t-D"5oK L> >jpr\Hjs=薔mvqW$g+oO~CWE-ЇF&a#@Η\ | ݭ a hTMoEmscܒ5q!iӫ%2n1VQts1Njwg}Ĺp. !6\F;NτxKqs+:ĹZ7gť$`i81FSt9+̈́trOSε5|_pa!&oy5Qz5_ ؁>o90{IJ6' (K;8ڤn͆owҷE ɿ/˚|Q >}}Ev]F.%QTF: ^*gdR<0ݨǩOWVBö$&2oS&{ۭ-TY+ijfL~Zp炰4$},߾)l3\Qi !@k [ MeYH-L>Gv{W ۿN)$36#8F2kfOl+Y0 剠' P| #b%5\Ma4=0yb[!щ  M<G*C;Gw;2\M6-a#`cTҝ^iKMeӊݝ)3Q# ڇ# x\`%fȒQvn!f*=[Z' c1cg`ffa.\N vTߢ-ւ|MqQy^ X# N>%7аmߍ?D8~9 ѪltgG{.kT7;֌ϪdͼAOetI<4|P؇5obOY΁fBd#yUH[4S߽:RPGLKSdR9`EbdRH%~{Ǹ"10h@G)}vz~iBUdۥ&;耶z B'=ϰL?tڕReؽ^A`ݹu$ i)I?YΫ -9Z值\ Icbs_7qC]/U?V8(i-bR_\ Z"$հ=mAS%k" DINbN)i\o/LYJG~~)yi!N nU]#gGť= {WS=şQ7sC5j͂I=WSm2gK$8d* W+2;Ž5SNIeF:@i#Qnh8R;TP^ O/+p/ BwpPc7iQwSbag&ӐþtS?Tyh9ד98SC-{TZLJ΄h+ږ9ǔB 0o#OT70ŸmA%T<ʙqZl(-Đ|856gDoVlqN;b@{ܚW3=͠zók}R} 5۽k3n;x5^,(5=I8%_h=syUiN$@Y~z'T1f;#FcaόWpy+ EU3yjcyز9?C -\HE**3 -G %S,e5ZlA/Q$Ž'vEIUWp&p3"H\gBn|a S&\v 'kM]!b:U.ZuXZ#X4lJEǨi[ջOY49IH]MNM ;+ʝguWhw<*ݒS-|Cnb(j-xm0mi%ԺE- "_C~]u+o$ZDhBx,yywc/- ) CMo ^Ŋ.m`.%<3,L걄j?[IxA=%oѿ v*DžD "yaUb6g ȈVtyTH8ִZvdB@+y "ҮqӲOY:wqGG=Aע kSLiӅ g5i( N35E!MڠpIK-cM[tOD!Q=n5JK4ii&sSۑd'(l.K|S h,FuO2C`$Y1׮CTjl7Qg5fqǗgn]VCnP˝؞?>|Fy-VQr̳ 25b&yXl+Ks&dη$l׬ Yg/^zNpXtN/T9F1s؆Mg{,n.(gek / AV}M5N+>WfLih/lDY R893Xj47o,`)ogsBmT"a@F▿<#d dE1 fq֊íh6"'tؗB,c=X nw=wߞnľt/%l>6FԶ$nEd/_X*s.Whۛ #.lc O銅3&dQRÌs3~]<+)5!oݰ1`18~F`ˣF֍4@29 QU-k3?C7nTqg(~ !e-(xU l=`?)ɇMSZډ2 Klםe<`&`BVN׵*G\3OBuK#u]T_Kul;m"ag睴'ըns?F|f;` zm_;KBud"'?aV@mܕڊ(;z$zyV5 y F1U:PWPޙ9OuYc8.7,RhFn։*5O@I_D޲/$YczyiMѸ0j׉@-Nu"]FΩ'ʒ@X]JHbkuݝN_VO{XP@?hugYɒC:ÎKNA2@'OJis/G&@.U-['Xw6z 0gѾr׶/-]MnOg"5nK0;*H93c5LJ\eoc .bvhZaOi4b?K*m޼2}~*v&=N ݩGo gYpE;AG^hQ^BԛzdhYpq8gxE՛WCStԥCҢ.xcj~ڂ^lUn~pc beMX#}pi SЉnxkeq"ʈQN6,E1)6V=m|.j~jm(?4 [3?ۮ|# ?w$d$gmM鄆{(w1}SAX;:b<RЗd2HxR"5pE*Oς4 xo۳;IsnN=vDf2 JQNkh02ϱ ]C疨ǙR^x?֚#Ue('=!Uϑ#Y>=2i+6ㆰ=ÎF5!٧g,=ү a pgSRxo<}[Bj9u'&cIa}ŸT8(+GL3n=ElRW@nS/Ow:&!ٽ&Y] YhHkm*k2lߌEuug]8"R&CIKxO9z~U1HL4MGF_B>ݍyqL !Q2ǘg&/ӆ9aG^ hM-CS~ 2uO`AF[mly96@+óaR`(W%k Gt.:"VXgCߦ|2zaA*'fGRByw«n4N .[\<^>OP> ?P #go? ש딨xC;ź4?@Y5.ArF!uT}7P#6޼[!H`8y~Nꦨ~;= 5.>` a,,cs haC4cX^xjݫ΢7kZǙpMBAsǙvNoLo>8 V rQJeXw axy-nA}fo\qS+/O)}k-OD _YΞÁcsɚzs& (!Y:hAxۏ`KNO-1>f斺`gW「*,iMd!V6|J^DR łո ŋ{L & #(N &[Ik*3k   {ԠYT',E5`wt4c[ u*I9D[Y`{xMi4 &AE$E!|'s@xo7&D/iX% D-*nل ᠊Oj*JW>5)᏿1qqT?>#Mgj6L)$^@>nD(3]ύ# u.,  6Kr6ȉcFzDRAZOQ ]0w96ns<`ad|g;S-iSla|;;=|f[X5ЗFԜ%=ӇZ/loءh9)egs*Xv Ir,􊽗yCc DED]yN:[׾f]L,d~ mĖ;[4O߅1<4ypYRF9[XL"KQY/jfxr>RB:W琙spiTZv6)f%Uskmvգ7Wswh{g]D"S'pG[mu#\!J'Mg&'ceY+ی9|--$SU?t_+L[N8kR6}WJdɉ2.4[Aq[u:k}a)@ʁ`,X%ӀrId.1Me^6)a2H ĩ\W[(1&< 26/k+Kg4ڜJ{ јЇUĈ;ڧfA-6ʠ5AÉ,:ؤs:d0nּ WNBHx9W8(wҪxgcd6@ъ*oNKH8{f^mҘl\5چoF鮅$S5iz9X%F |N~hf2+s06rSwZ_{MeV4K:n\T.WC3]ТD)9/sDmկ,">]:zL{v2-D 2DD9U9sn5]Sz7Z,v{9'AB't4P PpBfwmW7!$hj~;ug|#)2QGغ?S"ڒ]'i7Hʰ_jo0!ǣmу\sҤHsOA1,4x }HaTZ2U벆j8dt[$ P>`Sոɲ V{g.YRQ:q[eة2wNkL]*o'"=p'tl%5:D;zqm:lҴ9ـ_{o-lSn/OӞdּlSKPTL-aS~R\ _aw}qjFIZ4fL}J)6]%vVBpqvEs}6x h,Ǔ` Z?F Sc}S(bHgA/c eʃJ/Lܺ)יK#;\෢~*nEU+ .n9F̨b3uy/lX!t(&#Y||nZ𳪌mZZa!,\t^Ks>gb"OTK43=îh_-Cjv]k懆9֋~q>3ZLYܪ$sYz#R#EZ4^nb͐t|+t/Ƀ[0+Ȃ_~[ Rbfɓ"{X#PqʾMyp]U\m''UKYBOJ).BPCk`=Վx(3f.Ou%khloe/{*5m99AHR.@R‚ZJr:-v ;3}|#4|'b 7K^hq[t@ Al8F |6(h{:YHM[%mzT^6YL'0mum}FӢ&\*ITYƊv( W LR\hpk~95`rmj tB01jb$r3 _8]2^zP4OXnecX,~\hXs*> CdJL.Bp]cky3V\b]GU{CKK]o+2חv Z: a`Y'eJkqT-/t>tmdM$'5pߗ,oN7NIkfVV D5 Uƀ f$g)YOl>3dkgC*Yb)5ϛ4&?ϣQaINz'@=h+njAmfoYIO-y,mT#O'*|: M8u3Kj3g,v=uvRsB~,JE'Q l߫UEu`bV@tקO3Cvgmx>sϕ|`jcʎk0D~{Z+Sh }\ ,S(t!8G ?=|r24V!vt׽X q yiLw]b&Qj!ľT}GڲƷC?ן'׋iik?pN/I iQ|!"w?vQYIh"i @Up!Kd\89: !{ۄlM{[(eâܣv"LD%\fdD)d#bxyrS`oLrw2lسTi g"G-_8_4/Za9Sér\mVjφT VH#@K*hz a<UnQA28}EY|4zC Xwͣ]/T={߃_y&=>H줴g,%o`e4(EA|2Cc`KWQ)#BUY05:m8@XKؽqP\:]k& y1_ǓA mȎ Rnڍ:\Ը/fpyKu7HrIPO/ɨRČ8N~諩3*U08Yz8D^n ~FOȇ@Bދ,, +lL2U& fRtA×Ci 1]\58)pTlvA9 c)O5o ~ V:Gt W (a {[y *io>9+֨&@ܷy5%@ۻQz5EuMʀ)~<S wK3Hv߂:Ws\.xɞA64-" /c↨"v W*q!:]Z I¦)& }1AIT9R1aRAiyP iV)mU! 2&Z`̓v Gi}M Ǩa{F/[|7x.pП^boqyǍG*882fS9xUM]@.]Zm~ީ V}fh>-y8[ !7hw +~zipQwyVc7yJ~јØ_.>vqP [zZ4%-R/]R/b <.y"ja2|T7V6?Jc<^ *\؜7ѷUyn'srSS/@ɵs^N0|Mi`QY{T>[ҫuYY-{"#%שcP_~7*{'L "BErϑh$0͗}p vnߩ ,/s+Bk2F}L tɍA>u\Vzi|1߳zVܣXEˉIҕ{IH ȿI@ħQ@vO[l*Lwo.mj8Z褪HH:kl˱=aC` ;<"D |lЬ؎c{[6%[u>EdP횅[9pRk\)#X떳TUr'T =#ĥp(מ:?P܍]5z%#Йꟲ$\߮##Bȧ$iy$>U+5&}7}b=pX gB`tejά4W$C/x:.J*dJ|K %4؈E(V !~;}x!-Db:T| 5KhtPH4͜gW p# AnGZtOJ4Zh+,*mOx*m(eQ|ZO6P' ' a`¹p8RրnyZ H.@kiW@\_>Ti N$CR^t5|Ds߫^sO葴#^;,Q r6 Rr)<@Ob=hxPvf[~&qSep@Z!2^x|bo{T@^Шw)#Aj,3W%g "f.UWAݫr h|$/D!1l(i lz%|lCP9m ( ,Hb"#ִ`Pu=?8?I"8!wob[% K<̰OC2 4'zX뽫n߱LjhƮ> G Y/nQ*^q;눔. H$5+AR,RB4ؿaq~R? q9 d]R2J[>H8SYUƽk@)̘<%9d[;9?2'x"U^x}\&@lYYp#Pᝁ P:]mr*V{{ӳt/{ ֒S  DK#w>8D6ҡIyLcgg\ʣR?(_ .]o7[ TP?zNc, ZE kԸ?٪ߕ'ʈƵ 3țaMonQ~ Ľ%sm͟ kX~gˇ8 dYr8}UX? 2'hn;^ ȌKԄFO 7/gg"Nb;HM秲)]FCk͏=Mjz)ɓ>’UV@ iy ٕa ,2WXeՃ{K_FPiMף>Gm(FT$ȫ_-/ZmOS]C'̥?fPU^6ႋoa#!88Qgd+P ͎aDwZ[,K'z$R۱'q}r"0Zߊ> 2}՞d0@!;CHb|" ܚ1/>})kP2ޏ̝^讒*i*ҎKइ⭨>}ƦaC^s~ŅyJ?(9+f}} b!x `I"?V;MS{V3kP Jp6P#,9%kc!6\=Dk|%Ro4Q6m_W`(s<_EN*xC0bҴmwMl"LW(=I94*=5yOwSsNg Zc:X]oZЦ7/=i O[ s4 ެ݃ajId9ʷ+"QHF*#%E6V) 9GʉH2 \Q4W!~ ysڶzK/$GXb8R9|I?!Cfy7N-L&enĔ'QT'dpW~Ku )#inL"GHZ4.5k=rn'6xS[:*,bA'ûpYݱ"(ZFuzGp h_$jʌ-5 AOO>HfyjJCu{2Y*-[mGqp!$Yr7*b|xa坰?ųwV" &uǥhoj\CS v7ANR ?p; G(Ulg{GȆ>(R {p̠L>U #|rtG^.U|fRzVm*Cy=,E$I"ksn!6:2Udtew kk\# ;hJ7깍\e:qq#bf蔵@nPm`­5 9ȳ$3&fϸ ܒl4Oֆx@C&![#ن@_E: ?#,$g5d'o`xd,A"lh:#(d?NYfney:md%UOo7.na&湗JP,5"&N E.;*Z LR.OD&`/S}PyfSEX* ř4q ZtIȄsZ׼\}uO'h1]37bK0W Ÿ {Q ʯ$*ҳ ٦4 1[~phF}>B4lc^[rjxӯ>6a RB8Oc_-]0 .;.=ʝf!GMRSikf ,I߰S=pq kCQ?a?fTWv]QeCb:9iQ"n2pXHANIN8: "M-XhTV{ߎ1mM1Տ]1؋H%})vW]-N"ȸ"lD( ݆b([VYCA7=\I2D0R8]z#E{Z>4xGg,|whYѴSe`nǾarn :pU_܉9tj4?;sz&ȸ"Fdz2KM? 4\L؏rn+'0%_D24 Y 󸅣8 a=!yi<@,>{7G'V˲3%$>52뛚 ) ؍̏IKJ[߸Pv@\Qt(vObQ8 FK V +C)Oqɋ.]Tn6 94t~l#3UUf}wXT}e=A@/VIr Y?Ry-~sXl&!3ݳ d:3};y6 sכJm&Lj- b `'9#FwgpA q|Jܔ7!J>b{~b h1O$k"o@qD45Ҧ/-jأ@:IɛMdk3FDBl{Ȃ#J pLc?g{ ݏ\ \I|L08W]B^_L<~\~6epKƈ2s"4Xjy0Xq\s_LͷO(% x=)l:Lojm:Y? }j]㛴qG1 }'II܊{K`-}+g"s ؎2V}ђƟ(][%ܞw}^'k!ߜ#( F}ü=zy$ :#ӉaiAфp%#+Ihg'?vpƲƪc" Gf%IHG4>6Yx@N{~h!d0'y"SrL$ 'ZC+[WJ ݴDDlLQx,GǙmdC9K7PB܃s-bǍ}J7m͵eykzmY9亚w^1tׯҸv b?V*XobFg uZ2޾-^73Jg~ȑ7,M6kv0̬Y9)EDz` ߔE^krL9 ^l4 (`)7GGrVSaġL]ө8iYW^eNjJ Q 6"Sc^"`zeZN+ճ{ WRa-MiRQ"ȱ M 8_#1%(i8" =)o<x~tWt3%p>x #~f*=a=g,!qaH[k k󥼞pI0iK8燯\}A]YͷVF tXaGpAIkl~(OL?t|f@8 $s+q6NM5}/a Nb٨\8SToOzBg`/˖ G ʃ"+I"o- H2fE\Z(UAYg΋暑o Ao â< 7т8d;MwFQ2O"ІBY8qv&oݫ/ONoXq[68X>cգxT 2d"m2ݐB7űCt'Xig0mFPx P^͆J9¸'a7D2τjjif}ZR!NlZ $ԚY3&jZk&ѨjIiX<:;'lɵ|Āx/?T pV NoMQ+ObӃJu`Qy B-P# 1/1I=k^VΙ(nO{_r\q2ς09=`mBHέVM^cdi<$MHIr]!4;9t)- Oak}7×$v 1e5d PQ]zSf.ښ)~Tc` Yj.5nG5rx]g]Z87 OE) wă~!wCϴ?Ӝ0_~8 @ M4hQpb؇gI y4?骃L2`N))K__ dznK,n ]3V @{[,n"CwL̚s*q[qo:1tD)˯Λn<#Q?rDrШ̥hQ gPnf&IU )3?f`gw@M֎"/MmpC0&Zl'w(k2N&:)hg)'MFVdDA_ϳ4*5o2rdTb}yy9ʘFo@w04qw6d&QtoHPĸ/QϺ;1AG>_}3\fL \YClG6 d9ε !?2UL{ /0N O9 g"!xdGUV'E)jW#' ħJ<61-Q±aӪ`H+ad+:b+_l ʼ]p%d#|M9EX\Я8j$+56"\dDD귺4`CYWtf~z(DȐ86XxBeخ N;!VA?]_¨.k"l0 F$4C-Zv32{MqóXS?R?ٜ;c2fŀ *t[;F5ǑlT;]klh~=_~yYKxup s ޣ P1̵V~"U(O99y#% pmfq_p*6!u쭉s8.;yLx(:P~Mx_RM ֒$1Dgڼ0L{@*!;0YaȐi?_=skЙp31)r<5.ȗ] k<ڣi- >|9u|̸Apb)n@+a6gpݪ*{g`-y6@;s&VF^ o\Uxyo2<2>I7n҇p0ԄkOVLЋՍ]ώ7`BmZҼ [ϼ%OVSƢ "[?k9a== L F4wEʿK%knZ+$p\:Np{!*Š24 !û $`Pە$<$} 5q&_`3Kck| ɠj+Aּ#r85V^EqL?2&jߥ ؝6868detc&IBՓV8XG]2k]֭?- @%DC!3DfK J9yQn\cCݦͶxN6JK:Ce¥T&F`:* fX=I1pl^{10%lzU: L#A+Q N6P}R?={yTu?Y1G [o 4o%|NW' ;W RʦyL\fY SN,s/;A1 zII1^$L >q;y;u`4 S)Jv<B#"KbpF:FYj&~ӥY\;(<` p&0yW$̚rj4j[7QƎ]/eE) ZX~鑲5AqֹgHJK>+]R#< q AݝSӧ ~v#0lRޚv(aI*|qrCPpb1 C=!@`^bKu{h2R*2l7BRDuwۏM%*w\瓽a3S HZ&EY*gr:*MӇ]Ꭶ[wtgX ;c#ࢃϼr92F|tsoDu[z0dM8芖}\ELd@|>[$KxUjDjG0Jt6̎ ZZ?4/ַ c%;~p ã |&\w+wk[ô0}>nm,ZnSܛ25=?&^(o\ڱ`*.$]vaܔ^=3Ҩȸ0Wd;fӬ|{" 7@hkty/46B2idLzSl8 ].!'*SLAݳתoA\PMЍ_tB\z nkJX:`;q^-7n'U`39!$“+] oZ?\19|gA,=F.K2%9|.N$[Uhc_TDp4"(1hj1I|Hm/a>yn%bۛg,X^MYr0qEǠ9=i΅$ ē 5Ɓ5|KE<'?!9@=#'Ĉ'  ^j>=s8*/SuX8n^#p)\.cKϹm~ΞTC>v8:mJΙRir+64bj\wq(NxyOP+9{*3f[ m^O#G= [ ( | 4Цcr ўm I[FbGI?\ǻSrSSEFԮH :lϟoV-pc 1)Wi5zouO2bkf{_c nd]Bcd^+$*Y=i$jݽGt5pX{%#q?h~s&.AK]GF r4bGٟ0?>nbkkHu;"%'61Hq,Ԑ a$/ˢ/Ąŷ,%S/&E.VYN\*]C^zcy 9^ ke"˩x+ CI 螳{)65 vk٪L}%SHRWq먦;nLK- pWz>=ʅ!ORΰ$?&9&.5L_F!fܺeG XҀ,imdb̘,* dJ1ø~&G3sg`0M!wsƳ4Kr{/oU.z꿷7l)Aμ<\tȁ\~/i4TgfM0ˮ_\e@9x6zaa8\+%- 08 2`-#j]X*E.4&U7ݓ"OE<%=UEchi'`Vx 5L)F bO }O_ fVTɬwҤ!ᛮ!HZ)&>mxoH9ƝXvGw.lڼ>J@Ap.m̡hDPm ])R,SWHK_2Q@TMhؗbQ% ?;1x8|O$rb >pV颋nY̒h㣛{QeSa7M^˿ !9D( i'$y:c%Mr_L ̑mlnPkob.3•W }ˀ;!jYd5D&P$]"TmQ?#U;bBCx8ML/Kz-Q4CvSJRH wZ~G)bYaC^'yTO0cK~  [X16+j%67@eL\R(BI_G~/ևn^|Yؔ':̿tj=S`bdi<0|o5*G A%; ~jVWE͌DZLT$2Hn[o '3Ɗ#[GZܭXanF.Vj 78EQa45Z'Yqb2oe}|`p;ܒtD1^8Zy̟0㭽i)?, F!+ߩKNdNL)$R.t D*RۢҒ[|TblS,&Y#ѱqFyS P@Rw)2jy(\M)MBN+(+]CJzff H$B?QWthz1Pm`i.E~9T;+3'x;sVQvj#/r쬢nLY!Sv1r/e\71Su[&ӿEdaBX{g~Wv ~@\Ϭ_tWc[ K"W3yxg'~Jdߒٸjjyoi *YI׉I/`e9sZA5ʁ׫.e=6Fk"h2onD `ar%[9+:;;@t, 6m >˯aMJͧx#ږSJt~$hH策Q|kxR9 `!qzX~%mt{>Ƌ<\'3TΝy<!-^Pw- Qf"bԲ@66ivֵ]oh+vz[%C|?H]EADTotbXgJO[v2(`y;3,YltN;6FRBY|͚sAFNT`|+vAk$P@ʘVZI+Rqp2߫rB Đ_uT$sD;ۢ!"tGMBtc3pMR!^! D 0m$:xۯ $գy$L:sD4`BKJ܀@-dT+~1K\|.}47su{7x'U{ީfo7LE !s з 2m@s'A[S'؅(`ue0 ˔e-^z|1}c0|x;xyx'e|VNNc-p5{t K*qi7pwXA"g"]6t}Ww}粰%FS4{3*iu‡a>Fz&BH1l56/$=o@B,+m;'ig&fZb(y|nTp7eL K,)QuenXj #Ab+x (/cR&^}ILpm\"J$orM4< `|Z E?UHuUlՍ6ū{hw܊Mڠg( 3>u8i+ZӏQ S乞`Y,r^5Fα5et 69^&q RƑ}u5ЧHrs_ul`AKSnHsSӫ 5lJ).=$ .jRuP2:FkE,:~qG}<5ulF=L{U˨^?9E@ )#4̍j-S?vӪbDDg|(xZp.XgTn^nD D-؆dB,}cRLؘp{s60VprYyy*s"Wk&:CxA Mz0S _c8CmΥ=ϋ aW%vNTY-C"9S! xAQ' _@/J&3,B87NycvE ŕ1Iq_ Uy@q<fht;U9]o١@Yw(VJ^H W3ȁL^nù&nIJF4bNv1R'/hu'U ݥB%.i6klN>$sWVL])#3pgf "񍤰R}u W6[6*~`OBeeqF$ wHl|B-yhQg‰ht&SfxefU5Iͣ523 )l~?lva8\7L>W;aChڌ!r̋9ԧR6`ehcĄ.O1 ؄lVc7(y] t3eb1USw7?> &j&5y) Uv:F*F`->Q (2MѡgqIs<"O>`{K6%g @ڰ"5p`R\{]T )}nS g*Ɯ-~d.N{J,pe}6gQ ;0x\'`+N)X/qynZ吝2YhQ%}Ӥ@m*QV 4BkH!r~!I˵9p8L&،*,Z ,NN.xΪ`u5vLf^~Bry6 P{®Fd֗EWq`^AmLA%>AOd$^ͰG~hӣ!3 NT_QFm.Vvлxko UK8$QOWVtɚaHݢ0(1P$ y8Wt>6T{Osd%/M88ƖJ <\{2\ϧN%Ȁ[SRaU-Wm4w-mX8% \c/ *}t< i'Q_OT/-u_Y/hWJJZ~8DGT5h vr;~cPȢ^`-}m^qlQz;?B\P @aIW\|;x4M@bfԯwaKt9潡w4%UPmI)EHChVY 1Fb`/tKPdKsl!w'DSVjs9/AJWɧZaC5ςѪZL &/A8c<(LQ2'!zy;=\. `>á3ΐV0SfkީGrzY] h쾺_jzMe 8~XK-3A}t*O=7^ֳM9'>]p{ I˙- va̱r1 Eji 9#>zS^kꗖ//=N&-?JK;MW2=u8iv?uD2,RNGv3C1e}BnVLz`-mKך܁ɆYޜH阘^7m+2}`U BdJ 8a$oHrC9)9!8<*tdh@>Wa g?3w,#bCxٞښO>X""\s ;2Qcc$X!I.) ذ\*Aj-]E1:@O}njpf Tj3\[.z jy2@pTWcޛjRr4<]0EqHBc%_ڄy-1߃xw pgOAey 묒#b3?4Uѩ07Ӡz42PfS,%E[t^]܂LO{,k#%5Sdۚ$3%i" W "iTi7TrWS0~#"tLl )+KAeD6BDԄI~&U<*[> N": ¶ jhKTNuζj9,}U6%Jf{ЊեW3ꥻ~e-4q""qvN#9ƛs9&CˏԀAY;e@y#z $|S> 9a+*B.,o Xpap?bà=l;ʝJX? 1ᑞ9< $&_:xڝogHTBZ'zy hS&sb,hbʒaXpٺgw!>,ɯ!Z!V (TjKJ?Of2}+t!YkETJ*VI%<_nL4_^=32$Ijk%F{( ? 2D -R޲I3R@'r|po龎!^8pɗF\IoڥSjCi˔w$%qS^0=tqj|KbIH=̍-\E`uҚ&{@ U@jȻ4O96g.֊^(~Ǚ{&DpX-" }k;XKFBs^c~9U He{5-|>έ`-VнT/mIZ=&O χy%X\}[3kk=Y$8p$)'H'=u?d?𨭝,{B(k )˩ż]PC5DjrE9?J+8,'Ӹ3zvܨrŠć/7J_WȮ9@3>t‘TC$ǨZA9dF*N5;v"Hijش/Uh ϑZD% \fk1*uBG`_R̷ }g5Xq-9/g=r:@ܣg8vaGv&//HWm5!vNY26uacIo:`qӣ\V~D⥢}پp3X@ tC^.CqGW9r>Ut3RaFU\rb}DqR|$sf=Fu{}%uRHCܰ~aDc駨v|岅$LoE$Nd$;s?ƿ? fZnj|?Mc2hBv#3Zyo{%<r~dL`\;l@}4ϊ(5}`5Dp\80r>Rg?B8H!\'mulCC ,կ7Zh.nR,hd޻7$ڶc3)cλlG!]ƟNhמW8aS_aoStb?mLUj̰|6џFlhgHϏ*rR.k|]Swձ{:eUV殚-n%ŽG' _vCiy5;g/Ԫ{6eN椒9!)Rާ#K%&%KKTHgܠhYVObGE`t:ݡf)K lLKwIҖ@ o:b+QnBr]Mک_Qk$S-Sw2&lE0s7ҋ^f xÏysV EceUO}KTj&Ⱞҵ:Hb{I'LjJ&w[r`]MZpvN);v&F^gz|i v [3V.pcZҴo>0^Oflooxg6WԺ:?"iJXo2g>Vٿq?s{M-^#UPk(vaKJr=9/bJ*WVK װfIz ̾xݺ lZ·^tm!#Stx01P<w&QR(0͸< 5uU2lR&5p[v<-5\i=')˦ҁu#ؘ'apZ9+Ϗھqf`~0(>a rmtGb(Z9~@e!7I4}40ih^gCPd/qxǪtG5*6evDa5X=!/_.R/+$ӹg qP+} ~MHAv˰|E$&FCCH< UM'!T z*BD(y"2dFqujc.VV,LhKWw1E(:}' WJc8V%@8 xej|;#EC]-3##$TNKb!&6 ;Lj3'D$XrMuv[)Y98a{6wOᄔê!:1!{Mc~DcOuwBKI{!ov9~ t2N Bq:'k@zoֻ[#@V= >"J;X/njHZX0L;G[&d0/xbYrؓApS*{J[DU ڛQtl2;,yD"r6 *\u#v%/K$zj%AZLmWo;N Y +4u-Gޏav>*wяvrlA$! 4F^10QT9~sUp*J%;42,q%;-Q~B^XRBk̖DV/k>ګ8Uv6B7W=д^kj&s1t=C6 xyj^@paľSڅj2z 6p9ڷ,s81~ K'ViFrgq npG+Z+K6-3zn^:Y ً Մӧk9vTLAQyw^A|AM2SzZj#'F?ԊD[jjky7 BM~F5LKJb3>_]~Skl љC_F|dzБ-e@ZwK:A9@q~ Taz=B?>#{{eOZ骐Y/b:(w=| m̃oqrh\GlgIûF]D<;hyJ薦y]\sZ [#i?azڇ kŷI?1@m)7=qѓHp.lpÉH~R~2w89RC*8<ڣD:}AE E/L ' p  zkr xZ/@=wCgg m%N혒hR;'6ȹ (pYh:ڄǪ2PϦ ]&=J֍-JReU .R!ӨLgS:Fhw<D-uұG-R?eiV¸!*j0 ePENF*sr$;TOjN.ơw<;g6/Y! +e#[F^]hSnvyE;QPxKve~>f`P6< ҶT.|62K(E4ǘE>RD۬ˉ\zZIAe1U;xN_ !ֽL AMøkǗM&2:Yڪ$hVa.W>'k<- Rbz`h=_XhvZ#T? >%f0ܰW윑rz::MHǗTx\3cfPRl<]r⁧.@c*IT#nKc 278q,r9fk/v\} gE P5&M'2a'X߽*KH3M8Vy.YXӈ6GI9(ԡ *52-i"c3l26ǥdDUM6Mc(r |6R%}%T suZ/%W^͍;J*=7]үuKcd ֈ\⇊?w@hpó1h ~pu+HW"1ol`ۺ㒴PRyĺۡ+FV ~|.*qboJ)BJ@Pk_3R Y\Nkf8Fʔp;h":uj啡%>SWtehMhl<47xwV 0&+4UϬE :Q7r_'/%heFB]Lckqԍ0fxKI5v U;w+6H ^޸T|Q/4Dh.abbc= ]kVWkS^XnNA:At.C9/3K-1:z\fWukL.VWkyB|5oC Ig@@>_?`FfkJ!}qӪAŨ1uIQC%lA rCWseK;9#; aBٸe~Z"B+{yy AatշeQ'0ez0HJ O?:9i-&D+Qm4pG ::>Wm\=a͖\3t]r^*pl-c$ _IVueL/&!|+SœȌ1v;zz (<W\F{-itۙ'E= pwq)^L٩IRfxl](Xg3 tB/ Y\ cdfN^,\ިHQڔW#_\XO0[C0H\s\HTBw:e3qt/KN?ם[AoTUE23i_F*4%2,6K̋}Tt G\,Iiy[A?!X]J-{ q x(9a#DS3DZdvT=V{&>m{Ą1fVƫJJ&?ʌlEN2AUwhiɇ0|],?l_ط6"p-}Ӄ!?!a e G6+ h5J tupG ovKW1L<ܼtM˞;ߵSpukbf5yO3>yϡ܇c(8DN9 Go0R8>vNxoɓ`PCr6<+/e/ZpkaڦٙODDȯj'$T'ܟ1ŁC#?%&HpDg]*boG+="׵@de=R3K|_Q@<'̔u/;]^|L5+rfdѢ i)qe#J%Y۬MKPH"Zw=^$FYaI5&GڳlZAc4+]Y_-Kt'.^"F|h/:hv/ Y{CEc>|쿧Z8,BǮSNDavsS'o7m9,0՝lŲHma'G^Xr0r$ }2Z/~8i!_鎦R%4卐!?p`f}1TAnO Q8&YlԱi}>zgsl O;1Ɍ҅"'VRV\owх;]aA ;?} C6A368_SSΝȂCG^`>:ͷBژH*ɷhj',ta~d>.>v Fy-m+l* GWuG$cof)5Lԫ6}Fqs6fOw:-5y?y؄wExiZ&f]@{>5g;J@Oh5AFo.cȀ'j8,m*eVչ2 %|].rSY{ !qm-loUW!Zu1V)v@%!6 ' N{1RǨsp'%؝UXgIo7fku5%`?lS y]C}WW-I t]҆v9Zu+9#VD0-#cPJW`F %0FwDMB/3z7MW?lwejℜ!x,1K*;vrj]߸֜~^@rHc(<)~yA:)t)e4cBW:PdlwP oa 3BcKƯh}14~6a" 8&#?[_G+Dh Hy瞯nI4u/-i -Pa 3 s9D݃p5 ٪YGU Hxޓ|W:w^{J_+'j]! 4НLὪ(rVK !:G"K46KzH;pTK+DlLLg\DηбWkާϪPyp&Pi@3fp}8O!.l@eMPMngȇ*EaZgCtr Lf͖ʺ$O"ʹQR`*mv˞#ʟ#d:CsjM~d`;=uیbӘFt+tb5$KW&[SI|%g.>_Q/;}B Fe7w"7@}ǣS7.) `jb9.c :JC[.2*'۸Rh ?{|8f2kNiG_Z$+r'=va%gև=k7[~G%Rn-C?9Z>nNMK}9-(:e].Y>yg90M$-s^XP-Ks;]f!X#A|Wg*{!Wvsu{{4¯dAQ{LeNpTd06 AN/HF"ѓ8rqK3H0@rrl"{ &V)ztVn\0=aE>8L:P??ZKwЕo I'Cr{ȝ`@KDR.dΡcse7zϩy4.yRGG1ײw-&Wo$̻~m|k6 !%۴ h;Թ3Psa~>xupRu@c-%|{dlb,yAzAB!{4|HOx+ .׎)O] zto,f8 J.{ma=IɐG4Gp?M8Gr49uoŁ͂fjwARpl4 dQuz1mC}[($;)o2^hrgsHTZS/vKXܳ6,䇭9r %0yZ@ѭ`w@ʠ/ګ tn$AYzs$.ɛ~Q3E4t݌t,"0D 44n+n#OZ!Bִ: it6(56"[W\?8$JNv':5@#33{ |?,g_$f  tuR0a6]ʂ@?`>h.PK\5lhov%gCYaNؘ`FQpkʺ(o=ƼMU4>w#s~`x*VP*4 ?)&T$1GW@2%GHQs:\¶#cjŎEi"=ˀ%i5S[89V|h6BR|Omk[=p^LT}'hB<>_Ӿ^ 6g]dmQhCSFAySek7f}D|Dm3sʝ/dZ$j" E -rK5@9]\`=v񢘾dva[8zqyi:bScxȓ [u\eƎF3 HQRWt,?f1Ѧo29LQ΂ .^XG5d#@ȷU.`~()Q%d4ܫ5j?iT< L'T%wT7ry`3њl'5y{e< Aj8ziOuP~=G.( 1 lU$ =y?^a6jڈ"v8}-6WO6ڇn 6EwX^w@삣Q9O; x /V]8 oQTcgUqڙLNnldaڌhtǽQh) Eȟ6Lq~s˚3R13ln6'V ~H\>RA_a4ҏ2]Tey-<SFwawxH!ͫ~ & ,΍mOT3ša`wN_nYwP}ѓ vh{-?+ ~ _OSnk~$&֦;j]Ce@{0Yw ti'lڿ9'L_N:38 (V/( 6Қr6̒@$5Tf}}.ӽ74[~zBAʗ3 š:o0ƭrGuN^q6JbGRG0=ryum~"!k%:Lkɕt`n%v͋1T-<μ-%zK ڷohDJwqJ2=Õ`0.+VIRc::R?j\>Wʖ.b>%,AU {v/밐)iӹSU33ec .`0`%(v6xˁS?Y=@.wK/YdNP*ADFJ0EiioQmA⋄$ܶ+3o|pU|7ٷMwʠ&*fk``Ȣ m8ŝ47 0o˙(u Vn49\ĺZpy[1آ@F_Ynn4K|%+Uq P;bP0O! `Ӄ{- #<}, cK8vRM*7/JK[m{Z9^'a;˱ȚDVCS ء-R^>tvhΐ rS'/t3I&ԢX>;TԠ ^ *_ qX>.|nY-P *ysz$s680YՎhb7r3`P(u-|Y]n^Sؾ`x6L?7ƹ?DY~Z^a &nc*V䭫RgoiZEW$ao-&`R/{IoD;&$A䀼YXOn堣/a8!-J(;VetY8^XL&*Ggd C@TLZJYh ea{lS7KNj~&$p=kTN/J9c|xKc  E>FU *^WWBrh˚U?i6Ļy#T/aro`D½)klE 4:{H:DL)<$7OfZy' 1-dσ3rr쫥3[EMUi;)Eۀ99!ZYb/BF.sJq!H֫Om|[Mu<޷S%7Ya)3fxZSӮYɘo58zh8›yOqM> iPP7+\_lS \c@ФIdFEj&kw`Þ#E|V*_Azz?g0^t7GvIz=ĈwbsRr PɛFS7{>cSʁuWnkUr*&ucZI=EByxDWgap-ecbk '&Aȓ/iėpbhSOROyb.Gptz$s ĸ'~nO㹼Vyƿ>'F B=weɀRIM xS/ 7F1G'[o V ϥl<-nP` ~5&6AxY+Ӧ.r2khyP׳h#Q;sK o\SwKt̘ecW .X0q*r L8:"`]v QV e#iYlhPU$1J, V[R%DAYfųz3o^WZQ_ՊY"Cō`l8lD;r(AпŔr",n79 UVFY=qP0E! )99q.q-}tڢ>tT?/q2,*w̟#^I}PyX9״%UtU9cmp|)∢Gmb@G$Σ8S:}UoPme~a+iލ*^xѝZF;KZDLE +'(͕y58Tm,\p(BHh40+,.e\-LzDQ=h][rF0Q7Nm|Ttqűrٰ XIW99ͼ/*fɄDp9l(U:JX3վsCɰly:-/X놭 Wj>'ޒvOmzޝrG pXg|3]Her#Mꕖ]=|7$5 ɞtɚxAw 3yzPUؙ:_t9tLF7/2rw;9m\6lw;?i3?X ,(m/|W&LP%_auiPssۘʆũ[ɬXӾ@#/(@|>ŊB 2uv\e">bX*- )j {wB.D޴(4RK>m%v Qm$Fh 7hn?$o\99&M! |桳f_5*iJE{BU/P-ҡGA !%kVQW-27? @Y_{3]~,_Re3Gc*5 HM&\/ܤ>I֜v ?F3!roV]lvlZu!=*]q>;64{%! @P-8~br7μإX[4o>uDMWkk>{ z`Td ?U ߫c6+sƜDf <9;-҅c}*-:Ao8M퍐7g~a{f|iޢEzXEd۳:0߾~eqr{OHrtS7+2pQX4g "T;}eDʤ1eP@۳adM\ԿW!bE"&@:eq1}i[㦧Htֲ,ݦ ;X:J…'.bW6T *:S :A\g.#>uww/7ο/r(s0ҺΈFHkHwkm93T;N1m,eYZ./Tފtñf*MT7l44dXi}IΩf%ZN;1uډ,,JW}%%'< r{nLC*O eX`E;-(nPSzH!l0FF]6E0 [ s\,n-P;8qe`%۫Xx! Ɍv4>I!& =Yտc;׆C&1a[׌9ng cbUhzǣq(v ĕz$Xl4+͉JO0n$N,m"1 $4EJi Lj >>_aL]o&Ãy](5|#ԛakPʕUB 04]D4.hMxO H)\nt0_k:coM&, ~ H 1Ԡnŷ~ u-NuyK6ޯ'PH:Sh~5ӓg0+!H`gTxҧ'vJ a6`>5͑Hl'4ZgHl4EBvA¨ bޅNno1y5lc6((TRoyDތ(,x`xLLG6 X˃xDEcjh>gj2R)Aԉ?3D;Nych7BA)TM"5%P޿pn+Z ga+ htĪ;jyt[d^ ;˦VAGBAE*=;9Νt:!# G"U)|]~0K.r&|PYz1[m~̞?ɅIh LyPe,?q-jXky*ʬ[=uԎL.V*fkQ4e ڻpU; >xfOnS0@-姹˚s  YEɨ8iT= ]殌5U}!0͖.u7Д}z9_wIk*Ad0KYa_]Ĥ^oHAJO[xϙ*ҡB/֑v>=µo(3~2FO)gI.gت#RQhXqY*!e$ O&&9 |Ai}YBL66Fr t .cKk+fp 2u/iH^vmtfbaW,4M8lg]]?>Gi^ y U:v,8c\tU#(>.rTXuq2, /|g7TVۓ ( :,0} @y^w95@ޣW.0N U`*&h":L`cB\4HX NHZFM%!PRX +'g_|;v5偱b&c t_xBN]JR!0M>6˺]" r=[zfU,r6=cR[P>ZS3c,-ɺwF1m`܊H?Қ^Ķ1H5k[Tɨ˚Gy/~ѥ4snKMt*>\IHا9X7?z1HEjTb!`TGA<+ !-m*9Q9WT@zgN%R;*<"Fҫ_8/ǥK4we $w}EҎDMvh9I@A!`fS&RFGxZ3v(6y>)Z݈ &'5&e!p?U݉d˗Th|fal M{Si3*%Wy-Vxs h7V~h r%'Ri+Z}CC4YǼ%Jk,/Pf^C@tX !Y [>Zҩg&$)Ik{+PDYym ۡ˂&;(.Ǟ؛ eU1۾?uTJϳ)o+N^ִaTibC;2%ڵ˸2THX~RԇbCNu]L k(x^<942+X~*eAQkQ{32k %djO~؈EQS3!t(a}ͪxzv%mc|BS'$\Xq4A<ٜШLi Fe>̒Y;ɯ߹S>x/!T+Ohc[vYgE6{7ϧQ}/SAE*-IҎJ⤾+'eBWudw'޼'^'48qH.A f 5xA hN4a" SV^}b?ڝOKbet v6{M@P*HcpaQe0u9@T@ ;IxLmwJ]M =ǞmתK`61M0 ~4X~^ tADl/p5'by; ׯ_҉LKԙJzJ$)?⒀!ʶ ^$| mkڮ6~IQ~yRsHG+ߟ)VH/x_n%ȋW/%,ț)-ُtS [샯|;С >D=OdqS6 )y<=8U+JIC `󩮺͛]Wu?R/M#A9ӴŏS"u2s]?]/P[4v {O։s񗶷lP\Zh:pTdZ+},)Y>d5dc*7UqCcs%k_GeR{2e1>e `߁ςOzGrlyӣRמ1YV:E $ܢw-σU7"2lz9aw &KfXf-mg1x,̅`{oQy9NÕ5[}h9ü_TjC_2[f11_[ h*Нt}9u(EiIT2c"45 2lD}ܜIV#SI,p[LQLkeᣮ>= նφUXމ$ECGֿ\U؜ޕ8;[m?k PEq_추KH&0z P3yӺیӽ eĉ _sxY$P_DEҔ|c"O-RkQQ6Qyڱ:if2g܃r\Y.;oJq~-KJc:m̀lZ͝ x%kEri]Op΂`+!b֪a)DVYFt%%nTt~}۱gJc+G#&W[C.=l t垑)<PI`5}ߢUʴ;G25`ȼ>ɷU5Q | ë!ЏuY=|l, %iDyOAאuM K)wkz&Vz,"S"h4мlQC[_Cɝuf_N$zIl(.*-[$SVf)Uκ8`Ѫ:A#Ft$q-r%__4B(Ot6#59(Tq*/ŚC&[#3P12o^*Zpd/TҸw$QQsrV.Z'(qY$a1Kc GV싇@QG8@?45SVT-JW8W13 l&M*R<`>fs3 iu?YYb*#Y%j(r!oq[(+ۢx2M.c B){N]тSM*VՍ&8?Ah+ S#g.!dI̕jhņRK! <%tݥqQŤ]N5`R-ez̿߼-_LYat6,(r5n?fW#E4t:š7nu*x5I sz-lBXF<kT:+&ste =1{T( À=:F7Md0e^uhCF*GIvO`KЛ]H(1252Y3"[ι3`+xɈI8};K5ʡzIZs%x\pƈL@k8M0mw$AKvk4,;;= "?˭4KiG8j2C=@b蛴y[J=Jt.!'%9w“y,B]:ؙD*E u8d̢Rſ\C;Ȯ(ܴԴ1 Z :7J1=[[p;We7ux`])`TW' Do 3!wc^'Ac&".6qDf:t;S1Ht)WYi7S'Q#ֆ`5=R.x'(ʚ,6E:.W_bOpĖCevqH^cH9I+x$LJ|MdٯDȃ1괈o2r0ڡ\FjC[NHp# ojXMCLjR Xm󠵐#u3vs٠gW$n2<,* /L?CՊ)ͩU d|ΥoHYpȬwcT a a- h=j9/]\"?oGD*s dW'|ڰ#.rm_sk0ɟm4CTVLWO]#UXx@lw0Qhh),۬F4ŵsz Fqk l)I -+iÃlai~Gx6@BJwt.:hBh>bv /qh8LoK,vnkŪ!yQaSrPvk Vʸ }MAfN%m) vtOPܫNq!CJ0]]TКxݓw1@q8 v3YQa0g6.ypSHa20hf".7GjE!*7WɅZ/ePnH/[>iwnܟu7AUU>8@S!jp5 !U.&q.B׃MSx_a/_ژ^a]DpɄBax̕|jEma Td"^P+&r%Ljvgu7PgLoU,_OG[z_BmV=l&sz6(ӝ#w9Кp>1~F5ɇ2߹9*Cp_gߕ)].&S;v~zL[6M2E'.r21,` VEr۔* ;Dk}bk9#ޱJ'1vsẌ́|k}7L%ERFy1zcvn:q]«^ցl`EZ%?².uP]ƃG@I FT*^c l fC Gهӡgΰ RV$g 8cϮ[嶦s 6"Ћ6M0~xDҦdHW2YVX D_^F#qg$UоhJ4v@W l><%utfHV h]lT}0![{T` Usc?bJ`-c8pr<Tj )Bx6IH0s8Mݙ6jTy7AlWƦ8E,:Wq2[_]&A &nG"EALz3hzw81zuR"$Teid:M劚"|n "Oִ]n(0tx?PS<oiYY|~*~Q PK+=lW4OE4 rXZoaT1=)(‹ESJ=@\@n4H}u@$9X IKAQ%2nWD.<"ԻMx9Q2D/ᜃ!T+&5<3 Gr:~6O0eEc3?%%ې U*8Eޮyұ|+bŜ{^p٥ ;vc_7Uȳʐ*G7Mrkse{sK|*. dIc(ihJQ;GR(.fo6G6#Wi`V-#F[[!* hmMGpP8N<ݣ]uʚx@nz~~Ǘ7ӟ?ORA_&J3^It-XbY{9ه7tT\`zE.Ύ.#cYJEXhV|`dM]H<)lQAaH3s\s)T7a.ĊKPe {BL}uu43#cTӒڱt22V:tS5? ;xq?UpFA>bj:Oj؎} SYѰ;n9wE۠~~uQ 7@Q`CB0nb&-{U|+Ǒ789DK- ʟ-m1‘]_ɬOf0" 9JF`"6gw'IXNoK2),~jǢ 2y0%ws ע|@EG ހ Ge`vb4owμW-~363y묻}-DƆ .>zLњC= 7ht>0*ˑ,fe,zq7/ȈW ^\M1r6\3i]&YhiR+`ϿbOiKUEAXfCi(y Z"hƈGsVώ!]B_#M…F%1bQ&Ey'ɁqrTSF L/=Պς޹%e(BObߛ>TQ@ j =i"[0͞3z}Bbp=^).^>%\e ~;>@^Lo2(XaZ:Xr{'*pa#%ɸm[1 kMpU4?V0IOTJ4CD#08C*~S>/SIFݩ_p_Z~0ap6{PXWTdY'Wy$S&qW}}%@0쬭>1RTJ!|XNH9.j-6HoI8% hqub.h>Iʱy[.5# ۝^F%3RwD)He(fEܵ1^N17iN=IoNj6KTH ڋ8s҇pa|FHDu+zL!ԩT*Ŷ ;zz(vJ9b5aQLة8E7HR7~D% AE,@mS4t+A4،)Z5zllD|$ YgaY#zkjs!ĥcݜf8T >-0/zhڛL>T}&d,9SJ"gZ,=0tĥأu~`F61jT;$ρ"kqFSZˊjY;Lu9βຜ,I"uC` "Xm52fpVT%ܤ|\Bh6ąy?a=LB&ZAZCv`HrNghyMƻ:i0t?Rp >ja a危{= oO\u᳋)7BFٰ{Hz4:HX37* E& \ yu!oWo,CCUU7 ;ϒd܆ ~(2[11? Qn A_~1*wN6\X3.l^£cf靤wz m\=,oa DL=H+`2>x|x]Oض'0% kX$kPf]J0i՝,ZS~n(5lm:i:^3Kҳ~G<ۏBlq,.&f}1dMSv&8F,tuǢ81nZd>Jv*Dݏ,fɚBeY*#@z}X۔fdNJNrDZai=lui֎^i. ,W⃏dc87{n:7;0z9{3$yi|6d?DPjF>jj=uh#ۙz xmZ)G·OeEM65 bLi,̶b<p/qP-z)v'zl\ gJ/k=]E'B|$!yOMEj͢bMX6K1+ö8رF٤1e"!"f/'\w^ntx ͕8kb e?EjSmK9 y*wg~யnf Λ0 a%37$ i4ARes^XY< dys4n] KXC1x^ft1GNT+ŏנ(M`A{hZX{<d'+DO/I]HQfOIpv3'ƱBxQ*iӕcUgվm9Pç(wzks+ W@a3a[*uc[w-DU01[Y{h_-ns ,`y-YUr~IOV|~UTelKB5=ױ}[K鸭K eBx\$ygz0ҩH.6B6*` ]l6i_xx(jMLMP}J@  ]MJ ra\\𳽡0bJA0PLO7$C $i0C0֑@ oy=5F]v}ve%h`lt鲌wW^Qx?M}WP[Ew;4rzW,aMR7!Si~瀚g&v| }gFf63~jT2%3U~F^6Ua*  lڙ " lq Ԏ&es>@xϠTY# z3Sh 翍KOPZՂD T">GYX8]kW%~ϓ}u|LGv&Q9~5 2詛Xw0oD~~ύiXM@&[Ձfm}ZS_ĵeJGʡV\E9qNIg8VK?HI޾(Nʶʗ#ƭO2/ fd[OџbY1}sܨ[:os%Ssa:1Rد?lQ@?ﳫM=L /ab?z2cap80EԮn¶ .2][2£szF * ibG7WV?$U(YurN1hG rFBI(q2-CF Z8a.lIܖ&%ӟLǮh[ՈT#A̮扩NhV}FLL+~FO߄iC0$a ɋB>&%KfLD ѓx4i{?փߐ%-Iۡȃ(AO(l*?5^ƎqZhALd nOsa`yA^5 ~<+l'ځDg 4bԾ34Mx`TVY"~!r&tvλ?r6j֙K tW5c,ZMlszg@kVn7RרⰘ_8StBT5Dה^ɧr5˛7 5V;d} zF< Gs>xI5)g{RF BF!DM ) '[Z`}QfB!3O"8e2OJT\9s>IX Cp[V}YB]D_)!T)zY&%ڏa~>ʙ#d !Ŏ_̖o-3؜[:G@ʥ/h!>QrO?UKwFՏuD9a WGX]K[݃P`:2,I^.=6?kчy!ڟb;*R8OOrrVDYS_IĽ l0bɶ~Y[7Ao*"dx#H1tDQ ;F1-/1#!HFi8s{:!D~^(BFg"F";GpigXvl=qM|#`t6k{QAuKCnV8ʜ/olk_r/e4V:rRHZ}xpz$ѕ46=`V8B}|YL+ʴ)_E^׻c|8mvRa]ë |) ; @Z F?6#iM/ɺhQ;z'h0gEm*A_7T  Qي MK_iH/x3U" ~ 6w$/q> NGtgx:.ƭ^T>tYRLY]S~j [qݵ5[`BJ8[˦܈=o=z~1gCZG Ǧ~j׉$мh (n9*3>N?:3ՒKmh ޴nSnaOMYlɞ@ aP]3̭ԬaXeX7IaKT $HUqLS{4 I,V6 >e[%niDIO)!Z 4pfKk`" |$ߤ+kByGl4mLï|tDHnsTS[%a$$\-͉.)Fx:fVk$Na1lp;3GέVQOB߁i,j0t!m6 F]J Y%*ju쥑M6St8l4`3A#:]ܰy"ݸڴtr{CYܔ 'ÈBϔ+7RBy>\#MSjh  z+(d;`qKvOZHg A&OAN G/貫lqXKy bF' gb+ ]Cq"eRIMNW"dk,ؠl:0EA=G^kBV+ݬ; x|P#-WzR!EXR?7y13z0=qa%ɧYj\{6V\7 0Ej%EUNɲ 9a\!~(aut4_eI?V*d^aៃ?WY<[[d4U Gk̜bHWg' 4?khIj۵e[M]ѼF#fuf^)*PGXwްH[C+ZHrt=:8M%dK6zc͡~|CimiȈ w#ǜ)[_zIU(2c?k]S\Kv[+QqΡ8'Vg*ؘO ?{)k|!ܨk_Tk<ٮ‹<ܶؗd'.uQCs+z494+#j3wظ$NL {1S)ncmNt}etjqyҕ ͛y@):sK`-pD,ψd9{¨W\Op?f8q”6rř%lij}7}/1xaٿ),L͡h OYpWW}HgFoue͹[ "SO6`hi_dά,'!\ވ^A={Q ĉ^qB4wy0m=Jm,ُRCZ{\Nl}+`eFUiY)uAtz?WM{7)θ-2Tf|1Һ&<a5xr\a>ܩVߤ‰H,elb{%h&- (2J޺g5 MX꬘r+m⼵[   0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n019003l.pfb0000644000175000017500000020575610725114532023131 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusSanL-Regu 1.06 %%Title: NimbusSanL-Regu %%CreationDate: Tue Dec 31 16:51:01 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusSanL-Regu % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusSanL-Regu known{/NimbusSanL-Regu findfont dup/UniqueID known{dup /UniqueID get 5020902 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusSanL-Regu def /FontBBox [-174 -285 1028 953 ]readonly def /UniqueID 5020902 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Sans L Regular) readonly def /FamilyName (Nimbus Sans L) readonly def /Weight (Regular) readonly def /FSType 0 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -151 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec e?BޒWG#6qE$)bсƍ'wmٺ/v O# v32cͽLntcMZVA,; q{ޟz`GZgD6"1rL]Aٲ.3 8(j 17K ksܪG\0J$tIC0He tqMaRܶD4OaA冤.x>-BzѺL\Yb,6,dۙ owlSYk[c]r&;/S ?jb6,Ż:4 Lz?%Ubj}NR5U 7ܥMEfjzYYRz1`& s2wDP_KoYS]M5%1D/M 1˻vKgM׹dӬzæZ& ( }K-xXٛzU齧*wE)迧%WIFhOA&c陦fX"ઢojs{,$iozAyIƼP@|^朇ye|ɂ [Oi7%$i`-xQR9̣C\ջ`#7=RC2Tbeg1$G,@ 1Yح6I ityhg@M`ܬDF=N"a͘! g'Ѓv1A[=ϩ`1468X~3 AP`vfOzgZ`5F:ѻ(^,Hu4مZy00 u |?z*.:zhS>+RDU#ֻ=[ԶKt۹ hn>s,sz̀;LPʫ}} ŏ_  Nv 95{V3VPA_F Ow>Kb-*J"]վV6S)1'FĆ1; lgN0e;)q7F0}J_$W]fk7iB7MS%2ą*iBg90oq]̉m0dT﹗8/F@Y3t uj"~T;}}AxIXcFVn{@Yf<܂IxG\ h@7ѭ^O~~0qs!R;/sN0fpgf 謝Wad]Sݒ:15dmCH7lXwZ-޵ܤm} \w\5 8l PR9/{ִD9K N]GwFlʘӺ2jbn5zQ اh|Ys1 %Cqni#qUQ۩@&D$bXNb=k0t֮3VrhAV7}C)45 no Pxl&Y^I)]ȼ}n >錒Q&%Y.kU.:(HA($}@!^nnԳM>E9V0l%nFt끣sE, {oAZrHM ˘GbM!wNlez  Ezn૝v<*f8y\fX*i?`mBLYX4" ulo,E]jH]쑐#zѫɤͬ1 DQSB &g+e\=&̀%H]6%U58JN(i R9_YAa-?&OF.EpW"U8ʨTGQ4~R W~#ɀ.m%w X78ހYtgxyRU;ALf\ ]36 >7׀m}A71۞RhrZ.oj,aRoorJD8!8<>X4M5W;+fo" IB w#(@C-lW廟__060]-~o (3L5U5*аr)e=l1F鷿TdDdv3 T"[} '!'\$M*Cx B',m4 ہM |:Hb#ݫEʡ6. yC=*1̾RhI ԗ~pRWiXaZ։++ sށۖD`K{B⠀Ro)5]fe:!'OZmm_4t~j;Lg 0ÅpZfm('[\=ӗƻ7Kl}ܱbOC,,VG"*M%G!\a0֮s;@#ahyO3ٲ].7ALB m?*[3/bc͍"-m i+ַ 򉱠 eqGaɪ3ǐ뛙`Zk)Ys.Ȭ'Sn=؛o lZKN%~fnjõ|PHu<tLt2e*ę >a2e'yʂKznd=zjD ¨m~#[n,7lOKfYy5Ԩ< ʄT޴S,]xMf,6`=p'2^ޤבZ<_咚@D9#w-(#&_{jWl7Z9'kû+g๑Rfewuu)`$$LLU:g:EJz຅yusR?Nt3~Նb yeQ0!U*#.۞L_yNEsGr @6ZLVOk8'E={COXYTyC~ Z䪃轉# D)v@$j^zd zr\:FEZn 3y[gV8ܼr{1qJ@e׈}b /Of,_v*dž` .AX6u>OOo.`zh>צ!'Rl:~Amq`ZLȮ|hjRmŭ!>>.-4ch6 !(yjcH >}g8pT\, ~^]ĭ)MiUoGϔ!菳ٺ9'E3ј_w{=!3cHSZ2ʦE)xɊ:3}TLO d~N!x:U&Kc2Xg` dW50Gȕ1pQb'Ǫ+F^YWK ?QV9(@;l@™xL](y /t@@+S(1R5pJ :Wm_]1h3$lB1j (>tKN/N+pU K CH%yq F_JUH>"T j|L[͝!1Ń:/T4FcYKmz>jYK)'/_ȑnP;7r@WAj g+:Z,[@9&r)4Jn_y䰽%h'b%У).i<\u,#-a+l%?W#9U?qQdltw8kf+>3jј[wF1$Y,eU<3*^ 2 0|Y*pIZ5Q;" P!_DBtfeܚ90 _-YfH(i*Zpi;88h]I 1Xy&͛ǯ{ HJ̊Oxpڽ o~G6ӉX6Zۘ4B^_! O;uQL Ȯt9Mž6z/~l.]XKv`gX f-JgjM 춉-Nm\vA)W+A>oLf ^Խh+SgL &> +X` .nS76$z'o:X Ž(i:Ij?ٝMtQѮ?sRkh]L"϶3M{@Y&-m-Dh:_xxq̲[H4 夤# ܮ܍  ˉ{)Cߡx10A~P:k3U痁ŬYkJXAIj@Qm.|BHPQDPhټ(엊BlL)FS7B oz2+{>VԆI=^*ょJqHqk|ݗj̻R[Z84.$ >֦םK) %rnsbv8 V֤D=Nja㦋gc܏?݅b=16MA45"Yk~z2\3~e0B*NSi$݊=ýIgjzVxtn^֋1q#^}1}!vl&!iik.Jl0y<<} ҶG ALL=(a_J{r,*YBx_uð-_U! +ǁ !ZfoGMI2h ouULLm9pj` 1}9$M đ~&:5󖘂0!\}lSCqcKHRvuNQlֱk %zi2rԤ_^Z:.W@vݸ /QgU-:zPA/9W]2Rn|koYVI[WAE|X AU~q Va⿣Ug`U4rt r.GPF:%6I (-1ߦ%wXVVjsXDW|6I,mC<#_9Ԣe*l뭅Cj9rs#[,ĞWB)3s :y`LSuH[To9 rnJ;M= 9!_ˆCRJ)+|ԛrw\~?ok7a;3A.>~ɨ~[cᯠMe@o m>p$g1mDx?pi͔Hֱ6 Dֽ'BaUtZȫO"j;pҡA6NU=i(%'C=v h|x;\xbοPz#|L Eݖr| M?{X7E zّ*(X!,k?W2'+L_wd3<7fծ<&[*Ol70oO@Gl`ca<ɈmBInx>U10ZIy9mB'y2 O)]dV{G81ϯ1:ZBD֑&¬zv)A BR'la+1ɧnr=Gհ܄#Mq 4-U=TTĹ+ =,V~W> CPi4c"CQ>şPt,Zk];jA1 VH;cx){%ƍ/?[ֺ1?GMw'JKjA?]P*ب$q6f^^jp`%H>Hx0QRlD35OmOc~j&G~|IF1̐;Mݠ57gm !HIDJz<l4v8޴>? د)XƩ;S^f߷Np  xݴx^'rLUi ~2H‰+Ufٱn#=}%–lT8r6* ="²f[%b[$G_$?;nax\8}83t:3K>5\;UQ"t]f-]cc<S>Xg}g x sD " }~UзYep]QPuc]jZ =y#}aP`^pR̳.K[iF^|Pr5,!R_ܟ{v%ZP:劦$7ˈ{Z81b+"bkSolQ%fkb2 ~bҾ䡳_s5H5 |=$+F5ftSQB/`F⃟ՁcE|B>/=`Λ#\0ERZ oaenbMɽjh== 8{`Đl]+R=>rlxQ| #]](}"+qccWI+ Za?/. Pkzi@`}Ej[`پ @Wۊ?rK0==;ȢId^Hte4{-`$Yw4j5fk,t}쩟e(mG8*=[Ʉܽ/xss#o=J~IBߕ?r%K aDۇ7$"M"j8 "< {^.?at&<<6ΒP}PldthF!3|g b݃(Ԭ\]A?v{A9sLₖ nV e|Deqszlv }~d<>ʞg+7s|S fA`g) ;&2IU`[wDZCg 8yvh,uA'^Wi}Ȳ 9Z!HgxELmZ Cgo yK9gUZ[y` 4,̤X'@ g|oAE)qA̫)o!ѽ ]W<㹑ܜzeLuWc`j=d{wIHVѦvk|& M{EYƮ,ԀGX ܏v+qH,D{2ТU]v P+hi#++E#sΡVX;4 [t~=diזh"W0 %˂JL t8LpPα%P `dswXS[ 䓌터1҄S\q>$ҮdߤInD$Dn |ȐqTJr v1nLP|Q Mx0իҷs~K^=( =ϼ| @PD5yVK[ H;jAԱL|1'O~S _wxu-[B-Q8(Uɾ`ơ[R=TϫHk3NTXOJ{~ݻL_Um|=ED~cDŰ();i65JwJz\Qc]kIXMO^ ubI.!5@5AϘqі[ߧJi$X L]?S^^ /;l>;w\-3N门L!. W.HexS asݗ#sƢZ#Y}6%2rY${A lH38. ^\hhe%1iş8#"h☥Ap4Co݃;Lx 4tW.j+;E:Q孭28Lqپ:E̿~U]Zh|m"6&003߾V|*J3.XysaFR}=: K24T7JG^o@ba εD@LjPL dUF.]`r΅\>[zIl8eؘ|nѾ<&q `\ JO<]J$Ǥ uK ᅳD,r BbYUM{b+F6,Ń;5JkLį,R7fIx/Wl^['$`4H}+! [8mdș/O9btnkz+$A|Ònjч瓫kaY-i~,ؿ:\ahKJpG<ѐX&`x2_10>j 2$޴e.{CV)$Hܨp)>I8(2˿$瘵0)J4];(ɝ0Ra!Jrޘ}Q ~vOVGzD`19@~}C\<<=n*%~6Ӿ y/ė7>aiQnn%u# -otE~Q:}3A>3C r +`_5߮6@b1 g.Enŝ5K{/$jyIXMyLސ h8ڶ 5\Y/&4բ1'nlR9^;)_ etpI]^g)p]vxVw =hbZz*VAbj2/gT <rFd9CS #}^eRIMMHjf cxޏaZӑs ?G;kjpoP2$/e<4c|dߪĜ; LPZo=Qt>-dxwk Q &\ [[lT`2퉐0^d짤9Nn)h|p KN[ӐėNۏ2pQ8ueM}y҇>A)V6tٞfEˌ/!Ц=(N.eo2jKTt8A#Y]ow"r$=PA&U{*d'uFϨ 2 yĻZx2{P'>%Ζ\Xz>7sHN <zNO<79,kn4|̕!u U9?PHBc*6J;*ʶR[!m兞g)Xp뗿 3*/nSKMB8ZPIB67sޠ)) {wO~)_eU.z$xizΗFq֡| K1D<gKJ~HfN+d %2M*YܘDnVvIRHQ\ {[<& `,q:Dau]ӌ#LDk Z7s5B 1dos.rYK-}fȶNܞ\Ԅ^YZGqcqQ6.z  L~7E3Yihl|l{6QZ,U[ iUNPB4btn2[OT:3-{؎L:sfb/Nӏ#e>0IBO1'iv8O,VbK:漄?HNkh1 @JؓxTPWU-xYzkƫRruKJ|}oW&+ ho|g;2m/J>CS8J9*caJJ G(ITL߱ t:+':?ˍa1RfUiE+7eSĝ~kC KTan d鈞_^r~ 蹱,枦xf!lR%rfX-ΑnH=U]%eǀC&l I*onpEpݤϐJHk}1*ͷC$r񱭍BɎpaŅi;!g%v]iX8}qIAvËC^{zp/EN'U>[/dNuV'znCFuGMg6Dzxs2DC?Y? YeF :;0j& 髑%φg3Ae&#/rF|_ALߓ˼`?@Ky#Zv-\ }u'{;j] m#Y40IP: :QP!uFʷt-Ux\p>89mg@2r؞%.ţXm)\Z 'oy]p0zJ M\&w2ڙVO<ےSɺm{5#{B?Vڀiϻ=˹.cd"Q>Gmg5CqAo i͂z 3OтT傃v7f&ƍu-2FPذwޥ)]B%Rar7CՅǚ(0{@t|F%`eLWQ{}(;"ʥKWP2jGFػhzk>/K*ިs,_]W`)"3傲"^1!UY Gx1ʜϬJ?hW—ùzk쯇w$dQ`9[YcsF{N(WX. 2{te,BHlq֬MOFW .$I@3֪\ rN !:cwei ERE|rP%uׁ(ja)&ǖƾQmAVajFKw'+J¦ģkNZB/' 1FYzՙ\VNC}aۋ@ϼ4 #T>(?J_ޠ T2")Df ƹ/qdpqlrAˊ5 k$X}j2e=5p!ѱN^@,+b8M*qdE9[G)wr9?ӌ-!1*$aV1l&vܰ)Q E9wwɘ&G9GQ1qYypM'"U [exa,Xͭ{0Gr2`j\?=J:sFHDDD_l CNط[?N-P!g9Khlu?kr%/e`(gH9FݟKgH8AO~ay~eVR:1H&aj CpyuDz{P߸:seG8 H3w|EW4˘^&")j賈L^537hBtPɪB/f=o(a={!\ݮrqM'fxvz-_Љpt pK_A#0‚E +S+:$Xhl(CfFg(R*qUÐf^.4/fFq՝Q̴,GkYPr/QA"Ꙋ l҈KMXynΌ?E;Nw;*~ h  1 c4>eik{*gF-w@t&@âR-'2?PEtKj|BH#:;wf1@G0d9 &-l9NC/vOHaqC+EwBd&pJlQX9k AX1#7%5_%3?H3 EGJ3ᦙt.*:v}dٟl ʮkPP-b_-Dz+lK!h\7,#%*dh=˥y[q9Kb`$dm%: U|_BvIOu,Vg~v&i]Y-(UsAޝ 5߃Bπ.ͤS vj[WI 8^FTxKR{}-odD\k;BaSfDD/~m ^kRG֎Ht߃g.'Of1MaGzj3ig&̆cq JTzYAY`znZf! aGWN/*3TNŏ#q:)i/z7b}1|}34=‘W<)2It]' lS"of}cdYw6H҇W,>ܤ-f$fde%f ۆ`9sQbm%G?_aQ?rh{ق >ծ^Hʞ:.dIS!M"m% 1[;2ip~^ +E>j`s><Cm|d~^rA(ȱ. =g3d'}itOrX>HA#= Vke55d$~uyJ؈L1vR%85Vxldck{l^e͛P%Pk06kly#OTV7q$On[U_Eoݳ`˭B9`z1x guQ"Y+{NRȠJ|a# J+z_sp쉿2s~>eS[1EA(FJ),_*d'hGPIJF!LR70tKT-ֿb5?K6_*HW?,N:|: iڍ5 +oT^4lF+},^[ ma."M F0#xg2ZXό0Ͱ8)TR >!At:HeZ;yy# 9gѻ@Na8ٷvBi`D3E/"m֗5uiXK "h@żB8F9ȼ1 i;\ں'r9L _' #tuIR\iĆ!w6?p`ݧs/5Aw_pC[ӘJU3BC6x'}:#B+a]gj Ww΋?V1#JCBn}AZe0 v_Rm"!uÃ:W2Xd缂rz2U_%a\(@MƅԌ3l$z.ShQEo)0>oTyKJLl]I˶<QolxdlY8$6+j с(pk#=>" 숎E`.#c5[xmS1xf> ciCnB@Ihaʸ:]*`K0=5uXgvb@żI:g铚G0Y:Lm{7ywҤ}uPL~ZK!:b G`D9ϳLlbuU|15[Wnkcxd1}tޱyI|P2>p?U17\3?ۈl*=bB QXPT#n9ӥoo8Gx|YE\39}6GsXπv>`m'\Rbb#X WJ/TG9El% D w"qQ[mH.,h،gZ;1ʂOn :(h[#f1%M2_]. %P4\ \e=lY KM):X<[|BJQoJcLG!vO:Z}Zj7:UE:pVWT-Ǹ j+u+cd ]uhx|IaSPG+cHoHss3lhQ9Q8;kڊyfbmƗEa?,AֿZQF+SCӖھxI%'4PDďLL;Qkfp[ӆ3R0>W_ЧR(qg$ەmZ7hRz$b2jMyƤ7G wrHS H4]o!K#4?qKǗvve**/hR@Ovmu'تn"g#[cy;U1rCNC784Z\RRIɔ Outp@f+Ţ"n?Tm6:̷>x8c8D 3]\$S#sH*T!P Qy!: V\&7Z]^WHv27>G K41&C`KQ@Hp_fq5m0;B@,%,5SÝ7G/MnjQ}Ib'.ٙ}솉AoQ@' }ܢyQ D}I48?6B~H suʘ/Y0G1f> Vf :2y4\7!J%eSyUǑHH];c8Ago_f`0 ]i2@E]y\C}H7pbuGC1qɸ!t/ & $)fWn'szn5yZI=3T𷏙yslȁHFlPׯX?z[b@n3'C%4DˠagxZy Sv:m6Vf/+{bȐۀf| |,DRCiPu8Lh\E˚;?#ZV4-0gҰ6u+qRP Ȗ_8 &&LetjwF1(]hxX@갊+vm: 'pæOye¨Ddnq 9 +[]/X qtMd뭌C˖+@Mc|a|F}NS=fhkty9T%w6]r$_ߟCLY/SN{8Y]$'IBۀmOÇ{Q[{U1NKuCJ<^fg`e"gGX#Q4/0!'<5E+B9%K Fzve ϡIsmAFs݇ Q#>J$D_SI@F59i| 0 "#{~8 jJ/#vfuJ?h8Ntq}ޫ$ #imWo"c0&7m'2D1@Bv-7,yUΗ/2]BIDU?ith;RSw0r-$A$D@D+hj~Huhbd'?W3W@MeAxVYU50inBl,ȣԁ$0R- -zz)=81vtYta-6&{G;6pm| ct4 ]geVKm~Q~=lQj5!ݞg5 2kv4G>&+ɾ8MxUۤH/)dumJDmIE.7u"z)_ imh~۱Ff q fHn\# @-@Q48=DOe-HF7# 6]g?"PAB^ R-Fb" 3:O+Ti})>V B֭eBUB,sb@m s]Jt<yz7!)D~..lIJC7%c[]s^eF2nI3?b<@)PShBAs._"pކ8&? XAv꺱@"мn;DTI8-5'/8e~3;*G֪A= tHTwjS `I%>vo39\ ނ,+i7cdY @=mYA&R`?Óbbrb h_u(d|}ug=2Kz nӺ;}':ͧqi;ڃC 0̱fP8hJt3iT_7yjUK7HpqzHv+vbz̳#)y* |*R@1f9Z`N8k@[>^lnzF7I4 kGi r>r!{0Hpa6:䬒?BmE F"3*cɖ#%GP]&1/+qeu$ [@-jqŽ fO(Iu_ {HvړB!gb]<5l{4*xj7P[p{:kzH.\Tj.PA>"n`޵5vpϸRb 3'e6N!z#ɮ~Kj{S#;6&Z/j|2ePR:,'&asNa 5:{@Sٱ%I>6O9[Zcb1UHѐ-%Sba!*޳5# 6щ ]7uWj±J(ׇ[Cuθ'NLMNB 1ܹ {Cf 10w]H$s,Z?:g=nm/\*%;vhw^0 \s}r/ɟ5ۏ׎]xMhm O-aД _6`59zPpG 5ad'sPêT =* UPJ( )D@CTIb3(zU}5>%"{ uN|+/65Y N`,}rOBƤ86މ a^/#"7Aø51 놚n6x`[X3uYV5-ֿ;1ts-_D@wȎ"bV슶9䩙O0/w=ҔҼo.*mjOwbeD[ce =ia >ÁOhq\E?go;z @_3|_*vS|z:Dh諲_ʿ: q̾ ̏-}@d$`+Q< $/u,M%LOQUc6( 4Q^ +ٷ`di'ek&'<( 5}Shx25|(]@:5+[6gnNq(hɉ_*U\]U c-, g{^^ll(+>E\5i(er3D߁˕")[ai^}*!"< }hQӳ&q2>"!" 4@\d1e/0ڍ`ne 67;`"ZBMX|"%2R)!ʯ F_Ho*͋L g2N9>}ixFڂMz(m ?kв;7ͺ-2ݺk߃`rVW J5h]",IQ^ 7ک{a53cXl¸deÓ(فDOr~]q@@S/ڀ4^Q; t&:Kw:@ZG)NDqkS֦XI/s_t%QV^3;v%QyaH+K[BG@eٵ,@, &,ILEfLn90 R)Ax'3Pfㆂ} : D?k;*RKg{ M|+[Kn /Z1a"`{}#Ρ"=Mc[풕 o #inM/b7zҹ3)\P y~K͘WAlHGEE (QQr!.n%3QB^Ү"߱;o0k65j|6v2TM+ ]56trCGI ]pfE%{Y+u~j;tز?^NNJO["I=?Ac͌o|Iri=ԯm"7%0b ""sx6dC!jPqv&l 1r1EJƔ U{wbqLWXqmkyZdF@C5$fNEД[μH#^¿8| ?0 X#FD @^߫q$IV dj̙UdZN~Blǰ[1:-E[b@,r4jF tFbk:E iݧ]ZC5@KAfa MD8|e[";h(&[M*&!~GLVITHAtn7p/qiƑ('zqEwcث D[-!8ufb,mq \űK$I 'feߌ&GyF&sUl+ETKg+p7eڏ!~Pw W93f2˥#2Iox XOX5*qRRY% SQ`FOwdLkTwiWl .aȏ0e_oY=w\' Xtsת=KH5/PMȠ3^Lu_gvvdyؚ TN٭˫\]F2ft>i>%^r3Kc$\h #>MZl6l'A;uIeJvgF/rH-U?8( s՟gBi:-+-kuCDaN*!)8P+/Wy~wlЕ&Txm.*ҽB8 iž Oy t(=Opzیv2x+i;J1kQxdD91FF/Ɋ'@3̺ݖ7׊FY;@]t=ŜJQ߃54ѿVk_`Ϻ;|<57Kv.^{8<Ҵ .}Vї 2đ}Tb+nhE}/1]M-Mĕǻz^iUЋ'mHIWTQO_A0pkhOQl:Uâ6ʷmEol1= [!L'v9Ol Kwkɞ@c"b+R9`3X:i\E+-Bkm>~16VS 7jZ5E j1]Ӗ#i%獫a{3h m gb1nhYUaK5Zv2&|8=v\y0n?VIz5W>'ў S8̅!4@Gxig2Z)*c$wa cӦc7{ZA7t(-IWIOX3j>J2$ N@/b(Q!pn,h{0T:~?υb]ߵޞ}F(4yy ңzɩA`g fې7mNb*ƞ I O8=OU0 {1k}nŽgyp^s%`18}Q!*o~,{n~x~Nݐ6"1mXA}>m1l E>Rka=u#4呣05oL4n PLB>I֌Q2ւEh&M&fۨb2[RlO } Yҧ |eӧ]Lk%,^tA8!bCb[ 6ZQKet\8x5z5a%* GR( 1UUk:`\&5l0 ]FnAt;h J4|'voҳ>H=Ґ nL%XLX9Ϧs<9Rf| Ҝ\0Zt."0XiQ4dgep!0{i!1M=^{ 9$]!u[(?+󝩩?R_uk?%,cA':胉G6#:pX2 Aⅱ A/Y r;l9f֤$T\ŻEUV#W8 ωS!l[y Qx ӪNT22*ko¥ޞMߋEQ1A1|=+6ǖj7!naN6(?͇DȾ:$DLVK.NqBDK^d'ga-2kɌJױg@wkê•UG^J3jcD*Z7i\AOB(^fga? ~ ۣWRU NYzpc' 4.|g%8eQfk: CA.(e' %D;Qd$DE =.>9@[. >y³J 3+@xJޏ3l^e=n$-U?l?q4j 7c=į5Ď|jM] ZE!Ęh3N>n;Nhnu 陨^|8"al|=-+rvt#0 "@ Z\B"7+!Z+h9@GztKa9P*i#M p4q^ /OO]hy&M%Dc!jntfHVaasPwzνD9[c]  -f*f=qOu,&\^nX ^>zL}'*~ޓxcqټX^X%飏^f_Z[-Ģ'y~/; h*;+quq̌.L=x] ke5G0ƌHuKӂU׿.ٿm,]f X+ 0AeG{ǧ͓jqpk{1˭rH{@W'@/4`2_G0 jK{Jau_NFTOplD3x ޢ+,I7ϫr])GPd3QźE=9*U5t1S/(}2_ &2p0<)A[2NClRK?0X΂N H9JhHQDm}*1v?'p( f:>OCt|ʤ%&Π.(pTzkKmks 23*r%A -@!v,gk36qu~Bva.bs %KO"|`$vg]Cb\l\꟭zgO\Wң]O|u /=sh$v vq!R`C.8jiP!95`T8>~A!C*="PߎŠSh?i ]_=zAez4+^7qJ:J"A8hpeBc4DTP!@)*]=1)7Z04,X+I=cʹv3n} 8S~~,B4QwnL0r?Յn1;*񑠀zfhI=%)kHO# j49F9H!md.G}C[BI{ ߗec:gKN̦uF+e/2?Q@s>Lّj?~<&IK*>v1-~>qI|`53戀N;U4/e' ǮI׽@$_nM,ܛLce)k5m&D ~"<Hnhc1hN0c~0"W&mρ9wyH"0+_COyCNI-*Yj}8ڻEJF1?%a{8I7pn+$߶U; rIT2C5'cOPڟt }rNMb_.2VyN'!i0zQ=t;YY@J/-{eՇ6ZJ5lǕ>o;3XwE:7*̺ĖC?_Rmf%:D(@-CaMOͻqij*7V77C?@ Tl;TaDû 6>r?ʽp]$” G]~bu,*<#C/ae םa%";pm3IvPbXُ0[՞DWcBXS*d D m$OG- 4 s;ƍ~IyJ-_pڐvd{\$2 ,K} <9l=9'bN,D=qښk<>jnIY >6bVC ; ?ӆXu_aztmfW]1sH.ZUx ՚-b"޲##Gy,"'TjF#x3y^m^Ro&q >&^nz׵I\Fdr"FI]]J6ɂZ.Sc͙eܤ qCt.Ҽ#VSO+vNi(Rz>f>۷G Xߞ)kqN}| >侾fI=ޏ7)w̆dirăD6atATHgq|t~?5; ΛH!^ErbA/CQa ~f$QOf8ȻЩ5pR0s/11{U`kquDz,0TUxrOwۚ݃r "|Y^M 2$8ap_wPyc}{`tκ-;1+]nj-GR~JpL>`$#U l5N")M-NᴅY+w3hzOJ #]R UYN'Qc(`"c&fKgT{p%KnKؙK`'M1 lꈘ/5 φ .H|O3S-DN2YA6'ƹ C sۃDkA|`CtWNgiį/^\͢MXD[aGzўtnƬͯ\ =|U 1&d\{Lv70c7LM۲d7HИ݀C%8md?L\ un:r3%{dו 7VXoHlyCD?7h$~ OOl} g@ +$X||RM@WnoNvmH(+'W9, +N U;@z7kO}R);8C{y b"ez /ٚ7q8m눇KjpUV+N*, z3F,ٯ_qa9Xx& S$M"Ƹbc`;V/&e,؆_揆>1R =ƮGS'jTM?[ofattmJ3ݢ/rc$wc$p,*S̏ihܮqRM "B4ǕCj .C'e{ ':h:4{#ߍa+߳'9$&&ocyrcr$.y?W˓ yQzH pyqV;&Vg*N|1Mvj΁X]ǂ9&tIX[.c[І^ '<997v'ٌGӲzKU>NH s}t(s'ш'\ >ysV\or\!W!£Ӻ0.դK##J# `o1!`t=;Φ"<=6[=C7cE=cLfL1 X*B;SIUL:cMwaHMqzuVTx]կ^'cr%U,^_\9a'KbdB:rW3Auqu^F X^VFѻ{#K! rqgI z!8Q10e,;TYJlvF'_NDP_ 1 p*/"G~luTŕ4*8*X]N~ SzNtHO9͊ bFSYpntɟ0nvqf}A٭@PYAhInI5B$o 9"R뢍uW+eL'yRR !R6 +^ ׳Jh'?Sgob{bݴSӧKTr%rjzQ5Ԑ ~IsGg$c}򩯵; 4S<5p-+Dnuޯ|;g k]Py:0K#nΦt۔U}c0sq٫B)9PA|=,W o,֨]@6G~yoȭ3QQH&@ ר>:}Z6@eZ+hdwAz| }#z2q`z?R>hPK.(vG,>Eyv u*zA4g`"=ĀQs6]s C8NdS5R"=lqjrbmS8e||z\eem I5y@Ѐ&T:kG6xi#X@DIw8捨JI‡Чt_̘kLvگJ"q ԆV2U֣, qd:5tMgx;MRB18 LB$eߕă#DSվ0rOmʽW R?vu t~ ev1fFI;Dj{܆&$&TEխi&:;N6zȜ7"9Jn6U62vcwڨGDvlj0/(sH[Ԏ} ^xZY8҅IABL'Ū5Gsn<%j+wjsyRݨ\rr7uL&gaKp:`«G<`ӭ{ftE*dU׋BsVL̎$aF2AOj&kDFƠYp#c^;s]뗦r@m6OA ^wKQ&FY蹴E4'zjTP(J׼zyqQ*EzleI,b7؅]ʞ9{ q_itN$yn N(Fک]0hW:;keʚ4Q^IkG4M0p։&6dsVlPiHg 0f0*xh~/0x|3ë Ñ 1d|V,0Ց^17_A y2lKKMGg~-!#uJp#C[2n$MNlߣڛ@JvM+4/jzOC9r߇q=@l~L iEBuF:uvŸ{`:vA y`\۟k_9Ei{H6g<[0Z T`ɭBYhZ 6_&oCY_TǼSmr}(d^3c9 fED-8I ]_E,{ٛ WЁS:&aqa&C Pp :AH>%spş1K= OFQܝHImv%޷bnje[EtUخO\]EdtI\~ y,mLJV0eMK&Sq @0͛*+$4%ޭcb!b> L}XbVXdBٸv t@198S6?ZX ,aa>;~$ BX󯕰\"(i&\lLm~W;LV#_ǝ⊉x[  xfae3:d"o9<q'ΣcHͼ>c5UwJ4T=IlOVzLc*-wD1g'Fݟ6̩I~Ky](n$2b!N vU*iȖP~ob[ɫ7kmalYK"c| e;ikJ305F/IS:/֍Z++aP@[ Hswf 'iDؼOQiLc\GX(k6D@%GqM͙I\"bddFgvWxtX, jW+SQ%{mG7:OZA 6 ET+!6kicZd]˥Y/mNgkir<q]1L5Eؗ.p7>}/z-+`\Y;[v|E+ 0ODw!'WWZTkk&C,9۠?b}y^5AmctZ/Wp? 5Ep0+3{CwysPM8u=:̩4)+5LͯoNڙlzь}\?0  xIT3M&ɑ2=]gG[f.~\U\y߿e.^3fϰ^d0q?!o `Ʃg\ϓ^ qRS/ds4AF͵kpZo`u!0y6M{3#?$+4Bp i eNKϱ-VQO3.8c8ǀxڞѼKthJz\ySM ..\&^uſYݥAV^-[)K/',dgWd$w2>'/w4soG^ ;B_uSE-QەA3~Dpb[oN xC?`BӗXo$U5 g%[H",xd}`.VA UΕe,,D=9mPX>D\ʳ|ׁ<.3H_}e Ó 8nr,Ɠ>|/N\B:]v ţ$] (90O4g nW] x ZΫz!GQ?2xu#07`T_WJW)hb^e*4Ug٨ F֒N֎uBםq2ƞuWSx%Ҡa]Bz}OWU\;vVDLz@\ɖ'=g6ﴕAp@&NpxS]"NP ˰mP=(e=.b|ѱѱTfwZn#'%G=Dj5E"&wzP+U$pQ Ems [Q~ &JԗzZA.`Js~QV{sq_a1x|"3 WLc8o=dt*.afx?_Čn* he^Sײ'F_ҿDɵ)x差39HgXJ(-Dđc_뷰%w$%ĹjDVŽk12/׳܎tVDw)] gKIlha52.l[eǣ?GΔ0D'nT}Mt }E먀W@PRC3-v26DytFZʳQpWg´QROGpOa ]BJ.krEgócZg vvF ,n%6 g7ƺ;OI1;aa0}EORe* _9H9ޮ?A2W<0Y: ,Û,}ިӟ!2-mKJo6.pvbfQ_3c$E"k0i+5Q7k/ìFL]Q2g=fXxBHVbDiѯp\rMiFcȨSi3k@lOF؂'%t>(ZN{{,Zuh`VEh˷Ms:1|QJuDIutjv\1ޣdVdM~d=}"UVW:ҡ<.:t/8{*O+8r V>$2ƍܘ Mܞbˣ@Y5k7bZ^:jqZ4|fL.ɥq,nF C'WJêg8q^qn%%+ݝK-UbvO_3[ EcY:e]ㆊKx~*Q6hvT82l*b!דs͚AypIA4ơꦺrzd>&v'.V d,%; '.!!pq5eN D4; '야 \ e=9 ENyHټR6|Zc&CY=L,]ř.>[!uY z:mu&_n`liXee2/lUͱU_u ~x9y.{Pbt\=Hp{dPNY'/\~Ί zBsSpCn'iZslMn15Ţ$h1yVqJ{]oyt*"磰#oE?&򄶽Q K̕|LCzA=oAۋB3H T%DRn2K-bW#xq+]%IeKqĬ>~/Yc $8sd}?՚onrGOiG'MvMQQ:9[Mr( 2B C'WXD|:*4H;|37YJU kWv2ۨ}+<5BM00iwa|"]pH̷;6=tt{-IDA)0.Q '%ޫL]cNYXI\0,2e佥ll<KuMs`gSNl2e-kbNǁ'&s|UČ}gKNXSs<#--Ic<&%fvpXHU6 ikQ$j]{_`~^p3z U5T1LK;UN&&ه1=Aܿ?r ŁvE"o5. -W W9 vYPXۜ-ZFwgBp.V7nLR}0_ŽT͚ڲLE8Q:knkƈQ|^(JI)K. ܦ^hPj}an,!=ڲ jU=kڱA(ـWh M._S&-/ŵ;>^R5+iu9ߏj*N[C*Μ[gBU'MCDc-/E vPa%IsGn} Yr! =eN)4(s<ܞBm߲P>ډfFLj6 Cbv@oH\M0.[]r6U TlD+l$L=>Ͳ|->@w`zrv{},\)b R@ Th2_EfeNMě l.HpGǤPrL؀ZS,ؚ]b$Q) J` "ɓbسbOz+;zfG4QZaOd;8S3֍Z\AacHbhF,[ L_> }H`}&ROPrгiʇ<#bq_9NGrU?}aYQP青"ɨ!w?,;BK[n z 7(6[vm"gpϠɆKə0t"j uK qE}i'@D3ח  4ϭęC7EY합5f̣L?}[L/s`u|/_H]𷫙^7M\ A`$_wso%-9g:LKىSJW֊1%^{>DXiv"NV(Rs3} (-{få]ACvh m,[t:@vzFo%m=nuOC[JUEZXغ3p`R1B ew5Fe8"kovZH]Rʺv 3WK\݀;-)H 2Q@CM_7X[IN%͏۵% 5 C̶B͟U>Ag$4CK5@ɷx$4]`H%c)yPGe jH`륽w> 5tD}/ OWge6!S-Ѓ5C+tW|sCހ^Pj-9gP yX.o{I0Xd&G"މE Q;-P]nvOHv1n{s{.K;X_oS䜸GCL\|IźyJ(o 9@ʂ=_cK9ʒ2Z% Z,Ɂx>zU7lhƃ4NG,<(hz$ iejk| 1< |AKvdlqLӉp=g 0>{ْÈ]lcUvdfT&㬇(2mC%n}Ū#Ur(;#䑤?~rl6j(YO03YlL,߽g+gҐÁ)z=P0rТjgC +Z4< gaY8κ3?է {g*17 m"Bw_2oS_qV>͡Lhʘjes3f. 2ޒm_Cn z j؅uAy;ڄ3TaNj(f?`\|#<ީ%X|uY t0-ڙ_F9ƺS"~{Иh2 "MbCi՗t;W@u+ 6M$^v٭G^c"#ebֿ ˆCNoCJNɒ#aא`e^Sv xThOtTa|}EOԵ5v$.om(F'_g ̣Qx v8>wr&њUDT4zZTu4IbM+sũ2AòTaZ/rwbag`qUdN۷Xn]H`ىe`ڠ 5SxrUV}/vZi!e}]CI.fޔES$<T*e?UTEZ]G+2,1 w#-gSq\prϗ} _E @XYATFL(* {~SGz1M O$'CJ&4`J5F N6#t5HX'װBC0 kI&afޅvVH/KMhHC^ B~UOn1:rP` {HqTGjb AmfVCǽPc22)$6'Wر-'qƒ510~[YŔ\b [MY4ݯy|mHo cZH QZXf{N$1L|C Q+Ϫ-v]r:r[ M'bXL ބ۶cX -Nbۧӳu;^j\Z+y`(nbP| *OUv O+"L<6 ~E-[w6挀Vfc:krAFo4Gq$DmD6|cʲ݈I3 xT5h9)N5h, TA)>y%8Kl2nEY*k#k\9BYԭĉ${qߓܞ3QBk*It(Wչ2@a~\tHLZ:"g\=Gjvjdka\ eaW_Us\ | Y/8y@^[,,?|p)`Vm@*(IGBozz7,l luz32r(R&y󢵫-4gi8rCSu/0nwto`ɢ~`0kFxk+Ap``fE5ӱ'ؓvs)@*2v6PB;gnC&h2>[sNQN6'ǥ2ѐF7vev5I\,%ztYelUMrJW.#xo?m7ŲRӣUa_~yo'}GŁb܄I!o#Ե^T?JЀ՚ &Gz'j! wX֧r9~ :9o@y _e{bMW&'R8?V.ָeU$q倈_4avŒl7DD+?IQtx3o[URIa8Qꩥ kp: X'\Z.Bdt'ُMqڋl4ovo0tQcqjiKamR.I)xvv "RωՆus2ZȬp)۵VM6gjElsw(M,交>YJEjn/"nQ^k Qu;[l(DDzȫdk+4* 1p\z"-TkO"g*m aq3 ]ix!o!OǕ9rz)Ћx@ ^g'*O`(!_N' \Zq-,HrY!٣IXs,  ҩVǚ&,G1/Ux|fFf1`miPcOhyp_{&2|^2@ 39co) FqZoMC"+.`t5UNQ꛼9 oiݚc D`4YȬ4 dcQH|X Q쬍VɚF: ђB~EMnx?v6;yVػY>*ե xpcT6kppP=!m)O7L2VMS2^_R\Pg`Dꭹ5)mc _LPֹB(ӢfgyP=0a&ٶF :'goA,igE ;7|l_}h@I~DC^sBH~Rt~s&5I$}?sWU{X %j1LDXV.J|rbE%6H`k|pEgpXH +sZ ]i^05,[|T@BJVQ+A_olѰOFb; (O['E s)8(Pb}wRͲX/h ƭGޫc)3&+6u;>Z+abOyi,b['y >C]0 }gEg9nW?/;S~ꙬY=.H*Kȋ'#pb1U7OzS }̩Qی}sǝk(TMO.2T]7wj/xԴ4]=[Y|lSq[iZMԛlW -4/bͩ=NE)oz7ZpWƹ2/4!rBz?/6_^QbMY1dPZ6I5m,[+l7C+-EҔ\AVܠj _;YSum Wuҋf^'61 .8P'z*Ύ#,%,_myͪjr $&Ҕ^/87{A@4–4@U|k^D15;Qs<[cةgQ8tDl!P>y ߼tH[@CO{hdʓ%K2u"z >Sb P{Jf 1A9X 8*)~EVCYȧ`ljݗ~ 6oÇbIw8CoA'UMwڅ8[p/E^5}뺈jiUAxDU%P f} -XFD ؅4=Gsez;鹓h[#?q2u/J,FB- 2F[H;1M:ڃ|S@7H4!wH ::rsMi  m჏+6N\S3@mDXě,g*gܾOB>$J䥋AңU(C[1 dbdztM^3!'(i)<_ >鲫,`*]v|Z8an <:ݬ' yP:Vi{E7I5au < KZqێ *" %|yn=$#WL|,whPj+$܄" 6Q%#g GN%. ?z5_H4Fe^E^.^@[BBȢ0-1V0[A4} ocTiS!'лucѸ I1ˋ. 2L .9$t_y>.(oAn|i?t*GJf6_]JUvGJ~4ɾuj9O*H=Eq/L3^܋q짐D~Eug~/e9/WB`~_uT 7[D9pUSThGND'IQ>CQTTLmrϒ*^`eCBaN=kLmA쟎b0.I&"N ī„`:/ys]w*Y1 56_ִwC2Y#]@[bq۞1]뚉g=RE3ItDMxR'$]L9PN`ZqVL5ss@&+_Lhi۲8 ^@Mںļ&V{g=1}U(-NRV-?֞=|5?~Cb',e0s=BI5;1Z ” 2hHȄ&d/O9FU9sDR gx. A_[xKx'h? cC,=}ݼ`Q *&lXd`ucz%-j'HLi\V ) íؑsE)B,K~d&u(Wnj>:VНXxQ;y\)-Qn)͇;^Z.&J'v^Dj1s+;@ zM eU7.  ]~CXޜvYQ7mÁ~DAU>ZvVB4`v*Hݭ uČp?3 %? ,Ku#/d'#>#=k; &Z0XY6Fz`pd['KƳh'›0.{a1t|]Ț3R;O(boYiv)I.Ծw 1Hu'+X| 2QzX^?$_د &<3PxST M7[Jb4AͧrN ҭW@>Y+M0>썵;$m0@Y5B`S#ڔÒ>v  c,gr؋ڳ$DT19'aˮ"#tx4Lu)Ϫ3VDu3D~Eg%`'=}YNܱg2ؙ PfW'Cp^lJ&,mA~2{ N8T,ڮfY5%4 ud+6~;L:IEǔ|NO156A`Oqe{Qn6^?\'weF67z㎱Ǥ`]x~I/@|u뇛1n@c-6`VNlÓ(tNjT #U5`t5(eHMnyFQָG92 _"ͤg'F8T c8,%s^MQEh2%[9l ;XItNa"U"`SoK.i^^ 6)!rhHCatk|KФt1'/Bȗ!N[}Fu&>-"CpfCuۗ#EtymzG^*s>a@7JR~h60Ÿ"*Mx|!]qHZ-bi}Mia*03|,<ɏH&^&EqiEg0Gt(~ J#Sv-?oC 30L&LvsV{>v[e=_bk69^P^h#i8;>(&&>G*%rQ&vTuõ7$8vk朂4a;_?>9)aX[7b..1 }uk}r X{2kг5roB:Q&EIhCJIr_v:hY5kܐ9W*qa~;70=~Z ;vx/iO9$k'<\ /NqmPqj\Z#|XL8[ _<7tJ{y<<}@7tdƣWpeic.+ñۆ[N =_$p[6-tZڌhݐnU,Kt5RWGDΡ\(4QCLPD$y4꼣 LI/X>}W6!wލ4qy8#bWo/ ? HWD !_tB~Vt3ޚe"SRW}fBcŕ_rXH3V>Oq؆MgYơK[`ێ6k@ &y "?`Ibr\׌R s_دf?6z~'_<#vxjP?^X NL"#8ޝ(ȕgz$9."tp10}]g: wX߯ܯiٚd24e  ke֦j XB$ͫQo$N;?ǹɩFw3n^ZaZZ{gQ|oUpoAi^h2d8zݫo #GC$L *VJ6P_ez%_q40l4){h֠v;$#uktUh:;tP-m\t3/htz2a& h鐨ގ+m4Vty#Vy nQ"r"ZtA#/wi t5G=2 2V1W7K()?#/"߳ȰJUbqDm;/w(vp^OF߄R#3ZݢouH3-NJ.SfB767J!LͯGC.8J,v.Չ'C65~%4T&]~zMsjKյ>N7 aɰe݁j 2k,@0B ,p\D֚6>Қ|?UA8oU4= {+/핳ъ|JcX޻w@BRFw?O{mK$ݫ,VEkqs˞P_ A.W,$ u=V?H(< "<pOzotzNZߕ Km*t "0, LSf]{Ddw8Lӂ)X QDҁb&hԑ0zt|&6;n*BQn]{x ?SԲ&OؽѦi=/ &x]}oCt @#^=- 22t iDjQAˮat,Tn~Yl1XG7wp}}E< oeg]}z&hwlf?-BOdPB T C qYLMf吭3F8hY-D)9z* EjO;V62n*j׼Ce]jۂ@I=٦#:F2_k_z gOb.UJc/pxW-NR@%Rj%0+"d6 ?UbgES ?MFsHc9f3 ;iPvU\RO_"V.ņdMl;9XI_h8A?h؋ / FpfQH1 t>vahF=A:K9ĘPɠ4JY- @Q{C*Wx}ӗ(*qJ> [&!cijJ o֏a wWv E؝#oIãg% 'yl7J|nրh#&`8)b+c=XWhu& Z'R<ߒa~k$NOu_2lwhlvlZ7cf}-)&iȂyq "lID?0/fN`Y4AN- qv!1Mw߬2/#Yw>ԟ6g)[)wΚYn4_*YyH:ӝ- c&?OkMGqݖ\y!l򽖮D!1D_ +xoƋ},Wı"Ȝ!F8պ*"}9ku)=ܰ*Ӻ9] ;͉ZF"A<[CxaЌڳ.X׵+n,䴐ږ5Q(}F?9oFc=r/bmkht]5I1V0!~ 2%۽]~]f]UwwbkUo%E6;ѹѼ{'br7ʝgUBLʆTe &\%gufDKT*4Q6bfD%sIrB!!GDs,N/}cߥj~qUu6sΧ1$X8_Bdvu!)U+TVβNS `Lqu|dz](F".M'_ɰѰVdf`Dד5B5EM|Zx>1RsU =FS"n?D !Gs%ٟb%- DkWYdnQVwW$&SU@@;}7v㈝}ݲ܂2ld}X [7IcdHˡv;|o~:̌Ӎ.K32g]Z]^-5^^klf(C%q=QvmNO;vvpþBu=X@ WGx^FA/O Kt#@P}uָt!j1(4ٯK8ʔڧʌ^ī:c9MZ :֛M~Pz+qlgC:^RM ̙A WT4hcMesVXT&xZwܟ9A} `St*-&UuO/nvE*u=kGJ9EIDHڽM=7KQ+]p2B!o&ՉPd춅fǃaRb_˒ SQG_W!+yHzo"Gv$ޞn߬%ϸY򷯌Vc1oD\ŤB4VG QT5f0'Cȁ]^uw韺0hp9]juhƻK#4-"̡9v\rǩ]G@i'/RN']i$Բ\"bLeel|iYHkT3o, DlP|!CP 6mJ=FÂ&ʆ@aԇQ&=y=_%N!,rDN2&띲lDvl4Yߟa41Bsw9}Ĥx[y˘׬fHo?TV:<ǘUPkԴ2cVELuܚ!kC=6iM.=?? a|96c+cs(:aG a!@cY@R=M<>ZW*5AS^V"wa̭'Si@͝*Mh_(1 }čSxE!Y%Yd#cr.V-Z 8t>2.`OQ|:[0 nlbTOe7dOTh8]},}R-!ג͐=V)  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/d050000l.pfb0000644000175000017500000013160310725114532023074 0ustar twernertwerner%!PS-AdobeFont-1.0: Dingbats 001.005 %%CreationDate: Tue Oct 19 1999 % Copyright URW Software, Copyright 1997 by URW % URW Software, Copyright 1997 by URW % See the file COPYING (GNU General Public License) for license conditions. % As a special exception, permission is granted to include this font % program in a Postscript or PDF file that consists of a document that % contains text to be displayed or printed using this font, regardless % of the conditions or license applying to the document itself. 12 dict begin /FontInfo 10 dict dup begin /version (001.005) readonly def /Notice (URW Software, Copyright 1997 by URW. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def /Copyright (Copyright URW Software, Copyright 1997 by URW) readonly def /FullName (Dingbats ) readonly def /FamilyName (Dingbats) readonly def /Weight (Regular) readonly def /ItalicAngle 0.0 def /isFixedPitch false def /UnderlinePosition -72 def /UnderlineThickness 36 def end readonly def /FontName /Dingbats def /PaintType 0 def /WMode 0 def /FontBBox {-1 -143 981 819} readonly def /FontType 1 def /FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 32 /space put dup 33 /a1 put dup 34 /a2 put dup 35 /a202 put dup 36 /a3 put dup 37 /a4 put dup 38 /a5 put dup 39 /a119 put dup 40 /a118 put dup 41 /a117 put dup 42 /a11 put dup 43 /a12 put dup 44 /a13 put dup 45 /a14 put dup 46 /a15 put dup 47 /a16 put dup 48 /a105 put dup 49 /a17 put dup 50 /a18 put dup 51 /a19 put dup 52 /a20 put dup 53 /a21 put dup 54 /a22 put dup 55 /a23 put dup 56 /a24 put dup 57 /a25 put dup 58 /a26 put dup 59 /a27 put dup 60 /a28 put dup 61 /a6 put dup 62 /a7 put dup 63 /a8 put dup 64 /a9 put dup 65 /a10 put dup 66 /a29 put dup 67 /a30 put dup 68 /a31 put dup 69 /a32 put dup 70 /a33 put dup 71 /a34 put dup 72 /a35 put dup 73 /a36 put dup 74 /a37 put dup 75 /a38 put dup 76 /a39 put dup 77 /a40 put dup 78 /a41 put dup 79 /a42 put dup 80 /a43 put dup 81 /a44 put dup 82 /a45 put dup 83 /a46 put dup 84 /a47 put dup 85 /a48 put dup 86 /a49 put dup 87 /a50 put dup 88 /a51 put dup 89 /a52 put dup 90 /a53 put dup 91 /a54 put dup 92 /a55 put dup 93 /a56 put dup 94 /a57 put dup 95 /a58 put dup 96 /a59 put dup 97 /a60 put dup 98 /a61 put dup 99 /a62 put dup 100 /a63 put dup 101 /a64 put dup 102 /a65 put dup 103 /a66 put dup 104 /a67 put dup 105 /a68 put dup 106 /a69 put dup 107 /a70 put dup 108 /a71 put dup 109 /a72 put dup 110 /a73 put dup 111 /a74 put dup 112 /a203 put dup 113 /a75 put dup 114 /a204 put dup 115 /a76 put dup 116 /a77 put dup 117 /a78 put dup 118 /a79 put dup 119 /a81 put dup 120 /a82 put dup 121 /a83 put dup 122 /a84 put dup 123 /a97 put dup 124 /a98 put dup 125 /a99 put dup 126 /a100 put dup 161 /a101 put dup 162 /a102 put dup 163 /a103 put dup 164 /a104 put dup 165 /a106 put dup 166 /a107 put dup 167 /a108 put dup 168 /a112 put dup 169 /a111 put dup 170 /a110 put dup 171 /a109 put dup 172 /a120 put dup 173 /a121 put dup 174 /a122 put dup 175 /a123 put dup 176 /a124 put dup 177 /a125 put dup 178 /a126 put dup 179 /a127 put dup 180 /a128 put dup 181 /a129 put dup 182 /a130 put dup 183 /a131 put dup 184 /a132 put dup 185 /a133 put dup 186 /a134 put dup 187 /a135 put dup 188 /a136 put dup 189 /a137 put dup 190 /a138 put dup 191 /a139 put dup 192 /a140 put dup 193 /a141 put dup 194 /a142 put dup 195 /a143 put dup 196 /a144 put dup 197 /a145 put dup 198 /a146 put dup 199 /a147 put dup 200 /a148 put dup 201 /a149 put dup 202 /a150 put dup 203 /a151 put dup 204 /a152 put dup 205 /a153 put dup 206 /a154 put dup 207 /a155 put dup 208 /a156 put dup 209 /a157 put dup 210 /a158 put dup 211 /a159 put dup 212 /a160 put dup 213 /a161 put dup 214 /a163 put dup 215 /a164 put dup 216 /a196 put dup 217 /a165 put dup 218 /a192 put dup 219 /a166 put dup 220 /a167 put dup 221 /a168 put dup 222 /a169 put dup 223 /a170 put dup 224 /a171 put dup 225 /a172 put dup 226 /a173 put dup 227 /a162 put dup 228 /a174 put dup 229 /a175 put dup 230 /a176 put dup 231 /a177 put dup 232 /a178 put dup 233 /a179 put dup 234 /a193 put dup 235 /a180 put dup 236 /a199 put dup 237 /a181 put dup 238 /a200 put dup 239 /a182 put dup 241 /a201 put dup 242 /a183 put dup 243 /a184 put dup 244 /a197 put dup 245 /a185 put dup 246 /a194 put dup 247 /a198 put dup 248 /a186 put dup 249 /a195 put dup 250 /a187 put dup 251 /a188 put dup 252 /a189 put dup 253 /a190 put dup 254 /a191 put readonly def /UniqueID 5020164 def currentdict end currentfile eexec  `,i"[[5j5mTʻ^+݄fKitrޟm%9۩*++`[&NfA-O!J"|UY+; <Ԟ2?.P2QhnDtw=y0)n*[ Y]~ ΁RzYi[AXm6,5rm`o!VUt0-Y3y81\V #uL&~D:gYn1D"O2UC I'KAD m uˢpi4܂a۞D/1Ky 0s=ğgR|ZbD\pt! ͜+Ж3]ou5egS:ʱ喿F, 1RZxvqvMed>CW܇nKY8ےɑ~|m>EHbX6tb3 %yW0U&3ތytNM`hJ3ahKƎw0nu /ΦIA#Vx5OGhwy;l4h G@Ҩ*'aZ36 6=2AƩ.Ю A\\o!m:3_ ?Y Ձ]'-]O]i 5'xzBW1uxB57G^K #Iig%ng2.Z/5 ɤ_o˶짩saD P"|% !(+0&A58-ly֘N/$` K\N6YMp3D)2_" KL?u7 @ ||:U h)P~2fK5@X689$~.BM;(0Ou2.&6 Rq.¦,IPZ0ȰA^[(1=+ 8h" S\l*ȼj2nw`|e̝1v"xMd AW҆fR'pgZ>8 MuG~UA. wue` 3=,T:9#e>0ޯelmrV" z9-;Z$ԍi/ X#k*[>_DE ޗ5y*Q /|[\Ad< j>6q]x9&I媠W" w5EH34cG<MkVS7 D7 L/]YvہvqQ%뤩0+cSmp|ډKԔzD"*qEZpI`kF RבvŌʭ ZMd6itǹcY2R%bkcUݨA|l22*4~ъdN2= :*_ IksmS8C$GFnVh?qX Fm=[GFrn,FxPSà;Co,GOyjRЍ-ǿ(5bG 6*da\p'd!]P/٬>9˸Z!ե01X 3Vmڵ?kʬuDŠG~+Πvø8kqH+B5_j,OȗhsEq+X`w8TM5 [ĸ`9؎Mb+D<H,<5b8E:ãfcSjA*:֭o'nm3oBY#^$Ez<9g1n\JRǐ:5mPDzFQܝ Zy'f CzNq ?32(P Q$ j y!TәAu~[895ñ#ˢ/%'c)|?O2Pq ixncxeYF}70#&^D(al}Բ)@Ùstq[D7r`Ȇ%pY=$h"M`~ݕV~DKf:icgT&f0ѡ} yp-"O0V/EAQBK|vMRkn՚fj5iYadFP8G~Ģފ]Kpw~^S2dTLsJM'5ce/t["1wHjnΗ?⃫v0' xΉޤraJdg-nS35|.(9*?% -"dn9=[m,kŦP$\Om)"y` ss: VK(khX \· >0 ~9G:RBl/?0qE6ۦp@H- nsGcHM>Z!Q擟,Wi&X{A zKPLxI6X#00~f^Wlg/Gnw':!9 3sNRo7ON(&"jLY5G}bJ>+s9I#'쳞w- J8[lX8EQ3N3X?nT+E@SM!f¾9 =}9]==f  }49O0T =сk\"4LS: 9*LוYp&00-R`rNTJSS&VR9*s{W Ma1fҸ`-mgPUi3Җ4w3\PlҴ 6I@y8 =cյȓ2'p"1M1kCIM!ux}nSxO><)bI:K;K骠gnudϊX &HvFS`]e&/y[5? QKd/x[*]LO.5"N)&T@onhlUN YZSGErLrCͱۭEv $؆,bW-rA$"]ݔz`p\uU"!C9dw g3lI¡#z6_to!1M.{]"1]')agd Wswԝ>}_$|tqQEg>x\jY8ɝR&dvLӎNFhH&[ݲ.1HzEvNI!K( 'Go&QiS"Mל,5meMG3d ]U}2ic:R?rD ܵ#{x%ݚaK"1bs1$@fC7!0=6B},!=½CW.V;Je2Z6ti2jQ.~Gr܉M!ی?~˽i: ,JImPrHElH_߅bg.ID#X^']xlOU.މŜ.pG͜@/x{OV~OFgKF*_Bzo˯DmQ%s`ňb!شTh}He4PB ѝllB0I<̳>];$$Γ w#qQO.y4*&dw W7qISA90@AC:כ^ NI_7 &&ۘM*BE4\Z7+7G𜚒 z5ƘVw~9^w;x_pQ*HJwM l•P큸^q6\09UGZEm+A&<q`IBcj!obRB7=7 \Ot<j6XG^"]dOһ"1qiɕR0P6;l(q]U Pa硼_|Ǹ>I(V`/+y]r7_ jn-2uD< _t&g0<:r=Lao4 i18:h<3R9`|?Hߴ"]䯆^P^",'uc0jc %@6P%1r]_u=A>'^9DCηQys%R˸{N  BCy'&=Me"X_϶*G &&a;;Adxq 2 z%O5ա+"ĻTI-"%a|uwxn6g(%=e-t7 qe Ek障{B'K9숺ɎH,^):I%W]V_r7XJrz~{W IJGltPcSؽRAr;F *КPJeZ(bg>/_-U7&`$3fu pjruDW9\ryO޾AVbG8fFx|zLWpvCɷL宝s\{&RsqVz)c7ϩzg]DmrYr) _b ?Ol CE1Q'F1`,mzĪC?3+<ٻ61A#47Q/*wQ x#wohY_~@'} E0 xPtRQ؃+üU[n~#{DA  M81wTsqZDN3N8+Q0.mVBl:D4c(d>^|VH]922l YJ07*-eёcǜWQ?.>USU*rJDO%| [?_6;A 4K>jԓyQIu7=JW=Q[2a%n!)_ sL,Lv`GQz8=t\wWE(_1j Y>ЈaJI)K~/8i)PZq.T EqLYB0Ėg{Vҵ"-׫6@~~ W{PTEqQioRTbn o+M?sgKToR@m9k>ۈk[#34mKN$s{'פ|/9FK=l}0µ u_^3,6͓ 8Ccu t(^ #Tr0Pi(Q)ްKWRm& 1RY5[ `l8/"GQ%q֕`EFF|vb J=┋E~uqSTTsBk!'3:1BHK/H’pFxs&dJ:g4l2 P\TVW<K\m!K3f /1̧e\{e⦆x c{UZ2,n.w2-+b~'?( *ʾQ%}qr7䬼*naWpxmlHdY#GN27WB} ʭ2ԟ+ڣ( c:[7Uv>K #6 y#02BXM1)3ȪJ3afkcM~)Mdu3/ 5QWT$ёuϧd#HΛc*i׎UJL}Kxx'Ζ2u-R,ZG@KľPwzl0*Cr>k /Dj~U}45گ}O=%<@P_ޔc&L1bfPh.. [7U*ODcvyr++KE&3pݖ#/:)G).%ŽO$YP9ը9wA#V>[nnJ6$ 5ư8Η//=eapLpA_݆s1& >dMf(.]Q~LR \tғ`_&&zX0zkXivgq8Ydx2^ /y|0|ӝ% G Z]64NH:~ {X[\v:&G~62@GdW3K"+Hm,+nKI$rfKEcjcbD@A4 +t'179DTqRDXҗ93X|pA~74}OߣB0$u岁NM_*⑀ZfHA]5sgtˑ< ϡSvӦ/*&r5ܞ"Cz^u!fP>ה"B| d%ƓEWL'^ ht5m1Yzˤ&FlM߉#p%6XFQN&Ldbv81[ب /cL2 fWsW' l OL׍. LNܚY'>jT)$}|۞HTya,e`\Gk:!]?.D)xi˜}AMPAhVe1tMA^%ƶzO*,<SYMa $&*Ug93>2qX'oPl1DO9j#RZ˼f@U4Rcʷ>?y6JjYҐV}:[17G|HS0='C/N6E+5d/ (ӣѩ7N, /,}(.ݜGVݵ{@{SV*xI@t`sü! tddrm {X4?F?(+_j?96)xtos/:hUFV%ĉX^`[>Ts&B5/0L]YK Mm zĒ>Q|`>S"< )$c# z^ 0kY@?B*+O0EwCM˘ް@_&~Zqʔx~Y/h5Y^ނ탲 3EϤFA|;(%e 5^ B"j.{ҒpMma*4gǑhŝ7-9У޺ } QmjWP60Mgt)x `%4g.dBR1L t&Z<YsWon)lºs(GL4ǐ_KUKO K!< ҫj'8M U}|O?.'lm`m3(%!T0 XY$m/ `eA3\Zf?n nqOD3K{lcq Q1č(bUi3F!_2PF`1HI2Gs~,atx-OIhTZel)]vv6aK1;/RlʓbsV"c@Jmxꍍ|F]Lx/:.f #OlPK:-庥D*u ŮDP›ulqВ1N0ZBo7kM[^Z#h &fGÖpA/yR7:F7`#C" 8PÀa$n|+dڮ8&28TЬ [mLΰzpb’\'E *tRܟ('%{8DBAY+h""+?nr \E[te5\Wa&OP>wmţ7}'X l΋͏dFE]F-?3ݱR r(X[N"}40!6`T-$dj|^|'{H,dRMU߫2982|t)rOjRK%א1m 웦;v&`R&Z]`)w )"R: nRήJٔei`EVҽ!Uҕqc9wi4Ps$TG)cX5 *48l?IN7GX O6JSoZP%fvye ZovvYϕŇԲ $ 7SH5 w$W\$j<oZ3.iI^u􏛃9.7l.,9HЫqxL J8gC Xi_y E|k1cOzZK9Ķ)?H7 AƎyJv>O gZMpβÜU 28'n9(S0FY.(*BJhp8WY 9>87W]eSl_PDs||LT p|,]?5(Z Rj|Y4]0E  A) /nN)xS>$( J(~]}2bYoߕĺ!+}e_aЙ5v?y>a[lQ~_GX|d5ɴLo؆n ,q&߇5J;1F$ C_xb9 OANg›ՕX+ndԉM:\{7kcݕ#IxIcdP%v F6ݵhϛ%vzh[S(,BaMӹ&2Г핐A3L:g I9=(z1Sjd",v )CH({utܓL2[_"pp*v{ulȺ`P))7DA1~]2DKCM5`<䤡P  +jm̟1ޫx ac?[sރF:ȃxb͚ju Y"R6w#nC\PUF-+ƈǫn҄ncNGO҃KC3?%-eGWGz ReLOcyev!.J#=uB|} ~]=KD`31)&ތ>0j_Zv.0f9#$_q;ڶ8Іn5]4H&:L:)(NSm9˾;^VxoH; ooNXf(oE.~|\ɿu/TM-(?ԙ/r-V^۫Zl zW,ZR|rӠ>M(SuNkao2A79yiPDnxߍK6ᐉRi c!fܩc=CQ)7XFMtRaV5dUiuX7"IPa]86"lLUJc\ѧpNb.:eD'F1Bk9iĪ0A*zH8ޭylkP.v2(M?J;7s <>#`qN16wOՙY_}T]=?3+gJﯓJK#Zo3/RFg#:g䳰@$Qb&pdOG ŷ!D1ԁTz@834|Ju_x\jP $8 CU!N\?P\9G1B̠㎙;;n5Q;9D'`8JEb&ab[MY1˸;Xoxs0ZJ1U`-LE {Ƭ ą"YOYyڻ:њd8o#t_};9uEc/۬L?m{Ks8!L%m]})~7P$ kٜ 夾qQ>By&Vn|IsaF.VDThB.۹_x]Gvgw4jKS쌙+,FG՘IdB׶Hpj3w>h; zhH& $?b 4.\.1\3mPp3kqqQ?kjN{0$0ש0YU&0r:TAZjjm6Lgxq35~]R24:AK78l%scU-?C[HgF"cv0 >=iŻc]G(v9,Ѷ8?F./D\gh OHPh)#|4KzfE4h6@NeP09Y胼]԰ON?Eeimr"E =ռb#oe>] UGBViu-R=Zp -k8RtKLW}i\TI]zi@];W终a1 Jwu_(eCzq7#@lj#nk=,g=y剅,#pJ(CZS`m-zZ2W"Rڑqh a9u'G/`)yv*}Q%i&C|'nGh v|+.%TH_oյ 19~_S]<L K8$ ~\5uMvn߄gN,@?ɹoOpL.p`L\QfnLG Aѿ8Q 8OGeh&˝SNm -}f2Cպ' k7 %S+9GFY BlD[4 ,lgai (晃ihg-%<c'5ɜqoF蹵>l4|eFNHONPg9PzkTU Bx08՘W}`,`7b6ı6h(N|8ذe|c(QqWۿcy8RLH筁l0B\O+`H&GX3d2<1vru\;BX-tc!{a$r7hgsuѶ7eT} t#Tz}S67t沁=!Z>ahrviTſ#NM؛}~LET>1qƚTLnL\|s#rwsWUM˖N[8xWrO?,rbTNԙK7K&XǦ)]#i ߁&YYu^).ժU֗ Tai^$Jy1#[ +ՙTia nZ&Q,8.Ra|] tr**[j#W+;wId!}P8W_L{<|^So1[Ț k\*+MtXʚ 2bhR[qU*Vi?"b;rP5PDϲdN6N:vې4f>Y^z qbpNNO9qAܺ4S$6`[hF(DfHoXv$~ߔDwk"Nw,ANsM tQb3ig:}:bpuAH28X={/%<Jҫ-+};ػeP}\3 > /[jo&xstTiOg8ed~$NQG<;L&!38]kawO_.95LJ®7_?,0jP9tmDᬁΖX>V35vpe.K"/N/K\>DPbCh> M_H>n̒)s̵q]pj^*d銋pa| Glbk|\Lb)rz冫^PajY{J}\$7HjyE0R_F]w/3vWWªaWR}\JIF\ 'Sm-mG&.j_aj|8pu1Yq\q*GW`};2>'QdA3렢)v0Zា#ݻ۽8VԂ>Gyn]U}?cEжxIťQJ}3ro"{͕Xip=vAtխ fk–ǀR8r;;7/V"El|. eH/h+}ޤvLVS Em*V!k1Q: Z8CvL6iqv".~f\" 1/V6#=vKKuG,>4d5:A7 ->rFqHݗ NW83(3 D-|i֯F]~0-e1Rp}7ޕUP$!_-NwiNΔpʹ;5ܺ=w0"W~ $x!hj|d|d1 Є唝]~$p x"[Fp]'JJĘ #19ߝΌ\IՄō>D 6CD8 f=)+xdR]M+Dgp@5YȢhxJ#GBI7TutZ=(K㽱XDsh>h:uZ]!P5,Ga\eGTexOৗD/ڗP;POB &~./08] )Bmoc,^8Q8](U!%CK~܁Hݏя4 U(=H;GU1DvWW|:%8Cp8#Ry`T6 j-nv"`eEJ6YfP:˕Bx/kL_T>{! ]N HKУdh*9a]ej/ #j$ "iXjd5*V^` Yv \Y]_8a 5GRmk\*/kOyy_B}AR!Zduy]Y˾MXSc^LG|٣gPDyR#;!=˫!k$ 4=R7M:ӹlW$=r/\ d*3gDSv{sՑ/,PtN˻6zٱ'zyB9Ƶ/D#K-B&JikfT {W-)5;.xiji`#Arj=k:%͵Z 提R#Bօ!<\%vt-_BIZ#t75>36C yʪ7Ẇπ#^1/AǤz  5[Q ښ)9(j&b}qC4õ P7hSG8WvƳ=|- őݠSA5vV[oN}\營R%aZ:&2m?rtav=D|2W]")r)TAeR0s{,Bg NTq.d[_ B[7iaL볁A! |2zդUƺ cK+a`^,.iO|uW4@q=i[ItY+O koMg dUOʨ5Y#mK"ɜܩ|1ػh1G!J{5rsUZ`v um^/QΙsz%t2K磮b|.xuXZZ=[:k|ϐ:Lh2^^rstۡfh:vk&29tX16LT4VsNJ9"yWXٛ^zGA6w)4xfq{19ᱮ#鸾uPHJ"׀!@+c"nZއ jW !V$eN/FA2 =Mb 2\O_:Q=LӚ 5!` G ;*|k%Mާ#8]j*ioo =ZUQ6̴S(Vj;chyBK/6 HE娆ɜ+9Phߣ(́L5#䂷8GZ֊FY_ ϲpa[BnawvM b?`Z -,tꜝIic"Ӝ2{R0 9wBަPW.V꒟ڰee/n*Ҥ9M/'.|9?#ƺxDMC>I]-L\3\qI@׈N"2 #M8oN[:޸&6ElBrcC}`TK՜<Vl`w$703|؊+,q^ݎζ%"Xuڰ)jmCljNHhay$3PL a2K9\5-Fn|"ӇNo܌ 6+^Nvv k;fAٷw'q&X|/f9sƉ#%+韯kPq)sk ~~=O "cJ,'&tU;=#;}T܍kWhȱգnC2曱zZQzGnR$!(^O$Q;VNY3[z.Nbƽ?oa0 :fN #+\Id?K^rzK*SYO_7ڂK&Sǐp}gҽ;Vͳɜ}xr+,0|hN!8 6CbQD?KA>Il,\ PeRcY:a?u.xZ `Ñfeid >e^!sN쏉G}2?)lwRz#\F=`ޛ:{0#+O?R{tT,Z._򘒶eRg=` tgRq$~N[zag\y;;9Am?FǢ% ʉz)㔎b a@(6NY&;E┼f.iwl~'ׇCW`m;m`xRAAni<|{y !Y .=yOY_/]I[; ^b)I$kcrO1 2GTH|%CyDSL»SZ\? 4 ^bۃ#/T7?}s=Wu=Sbr^=KϜ'yn竪 a37 JjMK109Qş> "MI>*[ΓN13{S%@1)~niGI4dF!`Ye l}qu}qqSݝ5t,ڐD;fR'3y7Zx6x·J9t* /74-D JwzJSӎRFP;jYꯧ`ω%K&nB;*{|?G.Q ? k)nϹIe$yIMv--̻ /Yd{UĸG(@Qu$pF Ƨbn<(+ϰ.Bwpx}8J.kU$HE:B6~l8ܳs~m)(70n_\+i[Y#m:,i`Av=hm μ+e@MzdIQV hS!3/l‡,"U?@NBC.շ_hIq$X*PkCuuC?U3Fi,7J2.TkSuLjsz[gj[[EOHE{uKbVm`B\&x9;IhE,늞z;ʭl4m?B*(4 ]XAOIY+=iڶ8G恚2 Pf(YCHҟ$,δFy g4$)Ϻѝ]R!^4loF䁟$r'H~׉MKY ^$>yJ rí_J4xt$H~&si$,ҏ)R5 <_o>J?%SąR5D7Ft8aʤ4ZDJ!Vp Mcajc<;W`VV\6fFqCfbr 7BYP\AۖUh@mwŚH{h;w*m׺X0 z6 Vbw/m*-0-x54t;nŋ/5Ete;Ι/V}r0YM'AkQqڵd asN,fyC$6"} `[灉/Rx;i8ךYZ`+jH;IY"U(ޛ]$3`*zҎvT| D5)F1dX*,Ө 7%vBM :b+-/9{r/x[{)V̭c 1Ktjhm# o ,椢p|Ǔ; ;ǓK: Elٹ4̶&PLJ6|׻1)XP!́!^Pս'^$=a9%杹n8!̞ K, ⃛2o{Eq*;u}tfm}~):4ٯ6q\Ť77kg;j={l9Jvzw܅a$1hu@/Oh1ѓPT]9l=惼+;1qzuZӱ$ܕ>5v3ھ6T9.[ة4>N,b[)b[ XʕWq(/B*697u9*@b@6E$JSX#V BhZ~BS7{![w LAZ Z8PdY`N4+-'@R[ a*,Y?L-3URqddZxJ\b_ q`),Gf:>XE(Ε74ۣz)#͸TOZs=AqZis\%~U[;mמf@?|R}ʑk xKO>F=75c˜'X\нN>>V$ d,i^kgkR+ dk Nčv,"bR;_KRdL/ IƥLTaRUT?r@(OZ`k";߃k. 4OedBz:i+-DO;a`AFތLS "u=Al%5ccrf &"t;N ab/i3ȼ/ww-ňokkNuS{9hA|_|et逰7h6 L"ԛ_f󃔶PE%!iIv'K Hʮywʻ7>riY 6) `pYްh {b$pe$uKJ>YV!u&qG}A8pʣ* :|kғ>Wpa2)o I l 1:oSݽv,L3^A'IVN&]腰)gyq襏z:~/K\ͣAݵka;d 3*qg7G72FO\ rϱ%3sxX4&B?b>/L3f&Ak LPT?3 3@j =\ٰMD\iL[D&xbhPJ[XZ TB^lC0mu&3p +inR_z4 3.u@w64af2p9D L *dVxWNgM8Sx_QLhI@c ϒYsN 8'L{8_E"\Ivu\uJ{Xܯ,HYr+/`} ײii+x- 1tb9|aѸXk*Nwe1Fe|VW7Ho"a)C)BfX=';> <š(y Ukۄ+#w=|YT״9fڄY}Zj[lG]?*捤Ӯ=(䃆pI7zǬy,^i2oFC ùR(#xW >?,)9\]{,i" aJOu'vWPHR8'Լ {ӔXxq7tQA96㚎Vutw\>,.\uX 14\|?c)DbӆmΦ Ґi;}*pbsd@o$D$\ Qh@.nRR(<{WwG~ZGJܙ}hf6E[o6\MzM (3 H.ib&6$ck 7<#Nf ~(h}LJ1:}A32f 4tm9^ UχG|6&V>R{>^E`)PKt4nZ3PP3 }AZHn&%zC<5 k_II^ vSʺ~ 5Bw;4ю2"v53!jAG'7 ,~M@#^ 6A:Jf2{~gZĥ s I?%<DA]' 8P`̈́ͦ\eza'F3)LSX񴢦+3^*p͎8\1|#F0-2,({]kdF b ?gͧOZ\PfQOѯ3$e;0KO = QR5V8}4=Lk U]?vhnQN/'" k?^5Yo'tep&f7NݞڸJTXDcGYVxev<}}hR3`i]Ck5E6Сϡ֜!,]g~ >2Xo7}^<j 1z{M%m˖!:q&bۉV;;acu[kp߬ȻGi`/0p̶U! PGheo¢$yyesZ{&i\GSi;Eme"ǢO &o)^}tMRX^!o 9+3k-AA +-0J?R&6(sړA_bMwzpA mF =ބI2 {vQ a9J0+"D' ŦC )X)h\jҒ}^3,VOaj d|S;ӠHHhj:dQc8(x&8Ļ8&]s$s` qm=.riF~rB-յAjI$`8&E:9R+΃jsczŽ"r m:E'ed.C۱b:]rmV͈ں^.YgܴMEuy\"~ҘM.õjOxl#imJbbnӟ|[I_f\OJң7Mu5!j _XL-D!$#)P4fΎ\%g碻{sd ˧)-H#K HeT4𔅪4O.(*Jhn}HH Wh,oN`HtCcc~B4J5j.>yz(l;#48ۥU ~%qTI?Ȗ5<3l`׻Q\Q/`m-3d.}?֔ˑRFE*o[9}'Tx`ke&goܺvnR#)Ú- C46 >.K|BsHCѢM}M53g=W:␃X6:=TWٽN*L!}Gpp|L'M մD䠥G(/F=gBsь@om?BM'J-5$Čp5S[ {w9ads8sH%um V11#-n2Sjq҉QRr!^WwZ*Ɠk"!U* Iq$tFFbz &%!*i4!H4MmmIb/Yg~ G4=6ĵP L92!][߶Nk\QMu/Qlyk[JD/ųdxUD@=GPKpG қe7 1_n"z,0^.^oZe s\wd:j]{7G a|?QMڅ0d$k8KD[^2589E_(-&[ZgXøGRBD"9s%ϩ55rS="_ի3M9dFJ7en89#ϻ:/M<{)KV >.9M5 (YWn~;|G sX4.ʹ/BSOYq&FQA#q˺Ղ:c$x|LtsFpC'sğ( dY).Ḍ2SxmϨ:B6%^!y"[ |L^ѧBhazI*Ku? w#_\&@P0< 5σ0A%ᄏ͍ 99VkzR`N6"0K_Y"Hߝڄ*m6G+ 4rIQ>҅etDzoq4&gBMK8"Ŋ_L6ộgt-oubjH֖(sNh9H2ܪzo*(iH{ j%+W Ϲm2fb֕? 7Ho八4b|fOvM6!6o Yc]?vj%?9%C.kr-FĄ2{U_y+vEdJzmL\`}|t,L QAǫѸHE6߸S/:fm$uʴmAxcv90˪z41RYTh6@Azrm'HgF`H(K@#N"̫c MY/Bp2(:]Jli Z^D, ˜f9~jߪ*[+A-%M@$./v4.[n: `P1*Ō^- 4*2VlkW J1Pm "Mw"e OMjNhI,oMELhd!'U5Mhoͧ vƳ=0Lj2JQڢ2r:O&juY TE`Hv=(4 d|Ӭw)de.|B؞,;ѠxDqʿiR,jS}1RKO@;>Xf eVԻ3۬fEXbҾbxR l݀s ?V夌=cg(ӭÏx=\ im!gmjOZ(Iǐvp U0p)M"ΗE*]e/odѩbUVa &s8Yx6(qg Ї9]fRA<5дsfwE`i1BбĪ!+ :| $[accCڐQMf [o,)>_U?(w}@c\҈fih#1սWBKzSi?,F)*v,'?8rjK ĵɥ!gabIdPJ^7+aQ!'oÖȺ{$Jv<ychC.[\s|fP~"vL췮eq3|:LPoOJZ7]+ _lXΰ1/te $o8fB59>-))6?~ Z =r{ g砭%GW,hږP@u$nc<%N+Z8hߟBdG~!6D3J د ~;:1~gzHixV% /K 6YY4RT&k4DцyE8T@$d͎@w n w:} y-ئA<zyp$:n.xYG/NJxTz|.&t34ꔿ𹺞~qٳYo CUئ(Cʥ?Ig^զDF6 6`OmbbWVd9,*ti쓠ʆs}XLP3Nޓ}umY}9g'Հ>|XM.@7+Ǭ] <'`q}'VَehDݽI_{| 5lցF#5%,)鿆;#[H|*VMд{ 7sZPj4;ѿaLMDXn4o~R{RaFC=x|&U1CQ@&< U ֜'ؽ&!AR]q"/}G^/IK׳]XVgDUge666+kfS=-%H <p\۫JtMsҩ"^`/ж3ea9ZNX8d]7+=#4BA L? vwI ,Ve%cHg|z/0,Y"$/GŌ5 MUz53,HhkJ"ZMG@ U&n$G21h5׋9H '-B.[,ϪR ěAi/H. %Jd=t%fHԤ8`ovW%(6yV(yOG \.t0PjP?#b9 /IN?)PΑ]Ýex];+'|Y-L fxcgʧ $1nOwID9)JGw)t)G*4ra xN;:^AgN̠@A\l!s='o8ߖz\ڗ. 7p:sDg-BNjCQj]1;E#0gLn />׏ݩ FK3,FڹC<4ҩ&w]U?JĻYCt L_5K*j}|פx成y=*(UM|MØՓ^(P>-Yqp`ȏhlü=NYa 8[)?g9%(w/o|H*xy VXh;)61V#`!Q#vVkZIIG8:u$Z}}Tm4}CPJ d@JF!mv<1k'tkNKf|,06]*^&iR.KQ,aYO!ObV./Hڳq;NzI}@9 .fbŴPZ l yp0}x{ba]hZ'Ӯ..QzvSi3ą6b)@w~>ٖM>D_ >{.˃yAd>ȁK@K|P_̶, \gh 5W(Oܨm\"(kA|tjGD!zbTm.qT5(4IC8DPI 6ejw:\BekH"VCY>8OmKך~cOzѿ 5kD"{e^CR!1IG&m7JC T7Hg[<3Ǹ;* C?[m3kI =S C Pj)#DN&ſreJb#d~K`&`kCwU#~Ҙl6PT`ȑIf9}/HEUt$WVX8T1/L:ѹW$ivR~wmo/4,v~ \x+gQn2#!owۄ/^Ne˥towڪgt UI~~og?܉X`_GSzaf$%RLڞ>`;e [?TFhfpPȾc /(@m£y mFL?_!7hRc艙_7ߘ|Omk9Ȩcf7 ڙawC1զ}5M e\SVL V$q;4Y WFmR.%^ .N7LmX2ɐDy@693Ȱ6$`5V5u3C¡ўuz>nӅ -NFG'>!2>2e?HzwOcSv W4zDDJ Д43|% o`x`Qj$zIΌ6ՑS_0` q+\wc׳e?쨸~9h%#t^@}I,:^ssx,'(r&|}#= UoRfEVXe}1S:C $"[֒F U6V3I)>bHJߘn,XX>Àuo%-{8ũ؂KЁsW'@2;e"{fǡ %PNΦ ^eBDmo2IMA2x*LppV1hi& 4*k;ş(š30i# O5NBgvPlW}zȖl( fMlkd3/'jK2I}NtM4Ǐyq DH}%wNlTJ1'&Ǜ)1} hhqß 'Dy[X_ܘWɌMnYkF:7 Qd __#:M$ (,74 ,GU2y%0_ YMz؅FYzŠ>5BӍ~ gӎD`_7w}o_0WՉ~*|V/T@zS}ry&> \ )5٠ԕCq9*͹trx]/qIrgxBf_0yK8Lr]#jGtF7Cf @{Y񞢁5.m6ۊOr EN3TɪUϪB.vt2Q^P0X:I|:~] fJ4rĘ}Gº,&I01! =|Yʠ6Z삜jMǶHz#/ `"hF\POo ! M^ z._.eZ K/ H_jX{-Uj N$7s!ߞkt'bVY(砋hw\טSYr9 ฒA)AE(tIП]yT{1?f !G 1Qj XhVDT_s(?41ЊC;C)=vÑHÚ *_)@F'@=ؘ*Ec-8 3s]-E !z.2d-PX4 GPb3DΪŘ31ME, %e5KIqw@n\*eg,:C\Lc×#h&ߜtmWHÒQt½gl`;^T%K6XT[b˱d?aj^LCt1qN,H]?83:?wȞĴEvI;:'סZS}lE}!SБeMn#^ q _JM^RK#I+ EvǛMN `ݨF"1ݾפEs$f@UOE{w\:xV~ZU٤Yp&0 = @^; AUV7O5.@Cqni*ݷ&f" h:A;2Yt+U- g̨(pGL-.vb0(NJd5R%ìƟ 9x|0Vn)r;L7T}KU1gy)=oV|wJ)Nq}-Czl,>0H%;b_WJ"S6u@Qh ֞Σ *?:׮'fMNBP[ LdG4a3=9td |/bp'NvNW=1ap8p%+ںd JhLk ya*.{<{@syĠ&\&4Q%=f+PA05N\,!}XަHu--vt)be %M]7տ[Ȉ*O_LJ@uԳ>dz$nt tCqflz}Vm%B$UD LbaۅStZ&VŎ!Bڃl r 䰏< o0 2 7ՌbA-5ňxB[9Ox/g!AMiQEڄތWb+ h{~,X' ݴօn Ve0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark pdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n019024l.pfb0000644000175000017500000022022710725114532023122 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusSanL-BoldItal 1.06 %%Title: NimbusSanL-BoldItal %%CreationDate: Tue Dec 31 16:52:06 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusSanL-BoldItal % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusSanL-BoldItal known{/NimbusSanL-BoldItal findfont dup/UniqueID known{dup /UniqueID get 5020910 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusSanL-BoldItal def /FontBBox [-177 -309 1199 979 ]readonly def /UniqueID 5020910 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Sans L Bold Italic) readonly def /FamilyName (Nimbus Sans L) readonly def /Weight (Bold) readonly def /FSType 0 def /ItalicAngle -12 def /isFixedPitch false def /UnderlinePosition -111 def /UnderlineThickness 69 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec rMB/v/P$س/)Uo\w23VkH&wTPi+-LdGGGBXTPT ʡ^&\Tq{/r1y-n5Mq %i?`"1Dנ+f82.ҭu~Bl?U cՒa51#hϲ?x#fۯrbwF[^|SOPG3Ow eQ0=*w'VCREʮ*@z9I]Qsẇe  QPhgY8A%3@wǾgq%G:{!OvgO9#PCEXuJ ffR-,}Ma>x'ZDvwthk卞pc|o\~ um+Bխo84"C',4<\ CSivDĨ?{4rKnq*1hKnz; 'Pڷ}px]*VW9ղBD4D4%$3 Fa1 ^^k>vk@{풖 k#~/.U\lr,͖E=EL \(<*5sƫ ?v |Pi⸭BoEa]Ƙ k,ql܌#꼬nXzo9ЃU󟰥}@OβAp?ѐu'g;)j":eUY%kνZO{a=.V SU\D|z[{6jeZVcQ?֓Mg;6a4Y _sWj'R+ƹU5~>`.8 dJ7bsVj>HAej1&PI4]D$qE%{' YXlݙo{Yn/CRNVbɌ3o_Nig7ngZHYF`)7|%,4u ZMi?)skHp{CuHA%wLvD=lfc> cN}oRH!\J<tc.C`R줔hf=[ݲ,4CZ %|g2~2dl,l˳b*NɾtnQ0KTjHy6 So^Xa+ 5A}4he&+>A C BaЯߒIyBvJ'ͻگNcY͉XPV{I2xqYCr7yQatOVԯKNDmhl9Պzk%C?}{5~f%F8]' =h9:౼tHRdjW\Fd~ :χ%yD`jWx q2s`|>^rvRmSp[:K' }ADk6%mFpv:?wN 4DF6 뀼}lƀxߡ'|GvZ!'pJ]ܣ2p/Ŧ+H[T =m||?QnΚY!Y}KL@u(bb˕й.CK"cҖn!ȍKB~ 0[4JAO Kl@䋳 [>><CURG0&ܺn(wjޏ #O[kkigs 4A41qΧ#?+CײZiw]OvX廧~9° bS$ٝX U&DVnLs' j\:bh(P-  6ds8 F˧,?߃.^C68}~tj‹= س'-ӢnO !O( JnBr-lc9. >lI +M J#% +Tsd'$f! :zDžtX*32H$E΍dH_Å祭ˬF/F$۟ӴD|jG:[ b?z}qmGUUn#?MénUsVD${}+m?\t^.Ҷf{%tje52L6 󗦷ز'me{P5!owwuhK+CH4ݍ"J6%rCUݜBҲjB Ī [6Zd{qIVOoPp9+71_ߩw flA>z_}|[dce_A>tx6PybrF:1FA6hOD*^>*;pfnն*{~ey;[fx  mz3uTx2Y{cl(-xP,>zZgy\_Q%hSh>9쇓lB e*ن>K ~|2W&k;ar`XAc`rkB׽ Kx-At %(s˕.֦Dp 0|wl$__‹+L.3f2+0ceRDjcDyk|r`^*P0B4Td/  DK=g'*_>sit*t +n)\=Ie$,mH~x}j܍KC5љ̤%uMG\4]uI&֎Hx#܀Y֥wF˴aũٯDOXrD0 W[d&܎XW) p;[»ATsPE;W'0[E9GĆi\]k#[kZ _j8D澤atBCu0NdzoYDDl-=n6VP)\87zt%*̉<hՆ PK6BN:KsI@EI5I5E(RtEa'tE xcV"-wA&7~8Oߩ re^C?=C:fq܀RK\|$ZK^"vdewg]A'0f3sugIߑG8*~3 sj6;xBb47X%rH&P?oh:d0<"nH@wD.W94"z]M=Ÿ޳AlL6zuCxn) *wexSNp\N%ĐԄbelͦ]3_Y N'J{db)[ވ?>7i\xGrup`zz<, &ӗ0XZOhe0N PϗHz}2ι>O`nBA12gI6gkt=<}(S=^"QY/c\X9X]WSL4q#w W\Dbގϫ)ygl2.xOmy\ߤ}>=x237MK)Dy-xId ?=oz`s.j{~pBJ9a7+`q|9aLUXԭ֣{CCgř|$|u)#t4tKB^=f\X[\u;t9DU5ffFz{64=M'׌Mm(r.* Wtp6scGIҲ[8 T@`Pr1~ǓJiXPc ͿR${,K>'@Mu<ϸzp頵-dlTWl  fO4| O*, ƃ+u?M!.[e`i. ep]+M e !wwFjIZ=7ɱuG1mEf:$} ZA U02Q^JJ+cdr)pnA r#NiPFgX?1 h@j$-ų^WG dJӖհv{CuV>?A[yȰ9ǣVc":nw 7gӰ7(BD9.O3%:rKԌ ojoP4<1Iq kTFMH5XɇSq]TyΕzHXR\'G˯$+N4I IK4 .෢2V퇙ۄ儑w̲/:bi1QWsxnʨj꽁AV̉-NGCgcF`--ȳU\q)͠3N{_=1LeBԨtXafqzJIKa: fin0l[Pa^j[(U3t-:h}i0( 6\W&$ $5Qy 9إU ‡04ti; FT2Ɇ| {d)/Lռ'$S/' hVicPsOcYί%=*ڼ }|th/mClnf7~_lђ/|x#-[zC`&MnC{N7{_xWK .Gqj\ @ͯ R;#J #Pb0Nyh*/gvV` 6Jwu-厧?7h_;nu:j_0pusr^Kֱ-@^ݦ(=IrmWG/nO~'˒ !l>D Eae9+LSa@N򱀠߉iMK0ّdC.Ѵ,dmTUĝ?Xu92 mT`lιaP1 *xSv~2}Hy͟'-  ;&/>`^mPc_:8*9뒸q Mp{J^w5dl44UVYz!ĔaefnVm)Jv)Pt%DN߅Ri<0 B._1T{]VDw PWOl-1ڦRO^.}2Ek\%Msd݀T?B9;t#Sk-$o я@xGI:70N%LLMنQ,O6<է7|O!ZN7:(:=] 5}:I=d?||W%bu{Bu9u*Gv 0cPS=9oq026yEhfX8]tnH`lW,w^H#7PUiLe^XUOxNkT0a\!&}h(,t Zx>jx/jSq92 LJCR<f'z Y0LF}9#}9s%\P2g=XM$ c^sQ>lzt;U1T[Af)b2/~oo:t aLqZ*8uvV~ڣVfp!Cڕ(8F>3 NRςdGX{%B1RH*CM;0=Vٝy~9{{suô-r~ /~Qt(~گKwlj. p-d`!?i&ìh lo;:2p +Lڔ d(!DS:.wQNMXj&*И&s.M>Hfh63nfLA|kRB]Q&3] $GGuo2!fTj"(Ea?^ 4% 7Y$qR8{Z$ n T>^|@T}J¸I-*-`86TYb>CWn-ApG6`u;P(9EyMQ']ha6 (ܫo;邂KH̅ 4d%՚V[/9hE#jJali8~l~NJ+q+9AiQXuJGEPM@_/i*mP!U&W}|[c~ `ë0^^[( l &~{omߢ;O[6D㠝UYЂ9[н+[L-KtoDkt$D<ή_#q^f}lkCQ~ETOPR͚̉hJc= V4P]j;Ҭ`!2f&F:62[5J7{ۍׂy!l99 ΣU:jeHo熔KЬR녝$۟_>>Gl F -Oߖ--@0-o> U4jg(8ek`ނi#j:~Ix'1 y=ȝZ^;<2 1d8יs֫rjɹ3x$ d(R5>*}49F՘ W0.(G;Q;}L 2=AuF(k廹}ZKP3d֘|fNGJ !ʟqr=LC6|OCDrm 䛲}:̕x!d*j{/gq ? /hVC9 w|B ~}P u˙PGg],"XM803(Y9Hy E( Cv4ՀO6VW<<]ٮ^Shښn :/EEilQi,Q!s׽ gȕdvAgxSj9"X ̈"2,7S&ƨ|ڋgMvBQWS} Uz:?~uuG1O#׬>hK[|۷Bzi )Ք&$K'?-8hiT,@3 -^>/GrH)Cs/P<&xεm>BN0+lGqӮDuUh4:zD^_2GA)TyZ t>߂ ,PwyALѡimgfɒNI>@>.f[Deّ;4g܋ݳITkJJW[2͋0ƒ:X}t?c0ԩ~Sd|ɥɞiW/!UhYM?F1 SӞYv͢I ^/\FH6! h?᪵i(U7$?}^A]Yoǎ Tx9>eDS. {6'$R$O[ v!9gV)P2'W%0)®lghOEs ߚ`act.G%_ U*`dc9M4ɑwg=^MA )=dC\ ,UK1zxJvft=[$o y A\jnUx3e@Z "T"-UzJ%e;_nfl=$+J5_eH٨[Z+ xW:aΔ)R_9ݧ,w*4|q䯑֏ؠ1#lra[Ƽν+:»r&cCf28P5(J-K$ѫ6uu|m;ύ{H^@!oYg2UQKbG6B7i`CY)l=wkyfox_S4BR8lE+wՏ>A[b*ιt[}o+PƮCQis[Bi! 4vJ]!kBዳҏCCmt#BRFzLa?>m*ϋ@t85[y*>+VB`̂JUԩb![ ;kϸo zjEdp'7\sf6( A~{Π;IBycXm"*> !oAt[/8JAoZRC`&,g]@(Nzc,AP s["O̵OS^RcoO:vǽhkvvw$h{:7@ݰU7a^nfV$}r%׊U..|mz8&T$?Yw4䣙Fā7)<ҩ+Vxʶ4W`Η<]N|^:DmPV 5`lbQ W-CpRl|VlbBhg̢0F\-QCjv 1.ӝ9٦ iy@CivyHѻj0qθ$!o3\w-)p 5"S . wڶ\[)p|ADI}W@q^ lq]0V7H=଒K}IY.rA)$mN'%2GHv1 RZL[a M/DrbKL;uR&YZͳmɓ 9 5/ZJ@SkQI^h2΂ݝ\g]z2߲~ܛPR20HcKR>={\*IbR^s&8(]~3=/*İ*D%\/O!w@ ,>ߴ.s(0x<#ܫI9yr8tusٙ zN6>GC ;msm 6\V?͈JfҾiU5ez߲VhU#r M15@#\k@P o -(L$@iazj-{1Ej]"0`MݿM'Śė[th\‹IH5C<6G_ %$6y${ͬ},4Jzx'/R?J_[ xNvfF"y!4q$S*f}?W8|M.J#a=*g<)ɒيCO#MF3&zB}ݛeX%LiВI47=sη|<5PuT_WgG,iGF0/9=e-jpLfLƣV展؉4=)j+U'm,Cl" 9V Ĥx(Y>Ҧkh12o+%Sz=()Mώ>yq,gȐZߧs_U׮:V嶕:)&)(/!R+ ߁em>v6˛~n?'cG{x(̫-#bz?MSgBϷbZH͠gLqwvӦg-lW[ѳ:ci r1VKm˴y#d%'[u)7&[7dn\غLbI5t.p3~s'KѓنVi7P;DddOc&nɐ݄7Ⱦ!X:)#:+Y(p\Ω*X>Ʊ . qIq.DxZu =Eeb3QsN>bR=J8\(Hp_\ D1j6CYٍHR L _8~j-o!ݭ_VG3ӕWQ"hC$ vEizKICƇm'U33߿Ő1az&HV7v('&l C*F"8KhEVE]DjQ#1$"]2pC4^ o&w*(6ETY `捘~B! ' * ֻ<$2ShUY%0_gT#/m{"d3H;܏ N0/}0>S0:-[ ޚo+rt|ӏ}<_2̍HczQ;p `|Z%^.+d~ >&G—8wNfi_sj}Dҭ?T*֖4e,#=!ɪ.i0cm~@ʗO̗X!K } cUe.jpՅpJ`O=y(z/z"~e`qPg.ָgߺ_G ִ t D؎9Xe3&@Ybѣd}-dZ!MމN|W\n{tkbLe_WSۢqBW |j;yCrj+#?!|UU3Z|k՗VűUKe,0BwZg\C(yG6 ?s]3`Lܝf5+}a~0AH*w{%'$H8Џ#^'~c Dc mb;1 /lQX$ճ#2{N~oJg#n-eW7y|Dԣ;%r;5ZRz{R z%jf]f?%5@_>iжuL?\2(U͢jq`w_N3 wWp>v &!Syo5kDOn2we.q+B*nG Ta"_4LBU19nyFQ4 IRt)x(5ƇU wUD=sVFKp|i*Sb tTGҬxeU&iae4"PV0KR !· 9J ͅ>Vұ;Ogl~kE@UsK7Lz ;H^tpb D|Z:"ၞ@[nC?kѢ8_7«fzkM&>[}[IT"NI6>Txx4/Q͌iѸ`Kx/~jޗs4~t(Ŀ"z5RK5Md46l01b?Kjh̐w%4cw58ɸCf !a6Pfh"aY]i"4`}=\dKlsm>:H垢J8@5";j2` t.U"JK./+#\(aá6úiК-}*Gs?Ⱦ#D`;aZbBX]jŲZ<_)҅3 xo=QEP3tuU. ,G}-E'AaA#lF+G.ضu96?!*E" p+q{r?ۙw=`8%qI"EEރr_|>[SK_JW APK 8n67TSY^녒7Dӹ"p|$%"<u0aQ{FѦrbvmA*Ƴ'ȕG?^YN^nc^3IV 18Y긬Pte G9˞Pv.Uض.MQh4X - #f6ɕnS;WBdz\2w0?`!~\ܡ-:X—Y1JGر)xGm#FKM@O!Z1y\90"ujP`8XFo{0?t =Sʓ4%!8g1Ncˢ6%@M }_{K#u#_9ulĨq%i x":fJHs$g y20ǎSQ=˚~.2CxVӝEW+5SD-\o05d߃rw!p{"2GW ˜ !j.͟.JR˾(\tŎ\8$(>ͫݥtKh[`r]Pu%VKB'yd4p"haO"U@*{U,=ۃxUL 6 x4͍^+\eKW8et䪦4bG}@G|Aj@"/1NIwچu6/HyV)8_,`i>e]i~.R75٠͞6,4W+x+M4#65P ._ ѫfXe`8(mڶWu0y׭0C3_ OZz̥ausбj&\ۆ $ {)9HY*^UC#*Yg) -vϧ|l*C-xBK ӱZy]C$\zjiq"YΌ%sm׽k_FYq>aJ#1fUt0RJJ?H d?N,>|eHS8,ý{ iM6x=z~'J>coju{"9+N_̚NAszASfCF =#m5]e_g gK_3P]G9ɾ TsR})''Vdʡl.rrDǚFʥ+"PNPҜ-KڛTɱyVPg+8Pߩ~)~) 0Ha0u$_Eo/qy!y.`3ǧd; +ADܶ eMbne*vh"+Xm"=8%iqTPgW͆Rd+ѱ1ę6p fs&KMmlEWG2GW~` ‡Z9< %xAj:;h ([߮pW Hscv竖 l"L,>"qvTh:שּ~/*;_XDdlts3i3~E$) J>mJڀ%Liy?m2DrfTwǼ&1+ZN:o pKx ?7jT7V*=O9,(Ew8W>h]yG Kj!qP8ݞ1H~;.  C<:34Jf]#4L)aCԇlϚl9j> Mor&N{$1V+*M+t8bӮM0 ֩GD=wm,|>zJjRsF*fREυخO؅@JaqV"w9YIY"Pl%"\w `Ԭymp\64. Nޫ_XEaꈟ7H FXE-Ahj mJݏБhuwFnFB,\\#g{@7*Wf vjتDcf'5SFD! Kp c+6ax1sMrld~%cD,Jy~ b#LVP]ɣ޵6>! BS8C=oqXdk-D@´r)nw렾r{2Y71 IFx)H|FA@Gb%y=YR.C&),1U.A*A3|+616wGff}qoEmntA)cF /vJӮFT>0. ̼VM#HLou0&1lb/%px c8%/jH9hYId闉 {R>mVGWjF5'9mG4!gU6lLT^!3_l%Z8hj[!aĚO&"hRf;QUjRr3Yz6}gwn8vϢOMxhRj>7<3<я$o`VI3%Cȟ^;W{}2lFe uP3f^jk5 gy8eBݖaVWFi (s>f"J"ŷ1PN#q u;ħ,L}0ׂc)>m8fz+(g#7TOctS20^εlBFT4 g}?gq8'@Y8Lr3P1*goAL.9"ٌ)&jk>(mrvhc*']*fij]mNBp,8)t?"P*~rtxԉw9r89IpaFmɞRj៹|nv& 7:GiBX h6ݡ ed_l_;M5 :0O{Z@uimtQ^X7\?+O]9uG*jmx)W#֪ܨLۖ aY,8eګWէ#:eJ:~Z'f?ŐeS@ hGq^f@&whaVs/ߙRKj.yk>CaϞpd.ş(RHB>V2 {ja{;LHv!I8qA( 2D kB8\Z(X4h|68@G$)>veʝ ˎl3S0Zjn^aAdLAن, F Qi9ljs-:th7~o&'2fnsjQ`WX;!_nH>tli#-S5 u)UAfqp*(3zrNऄYn2| Gbol*9x:R1ʲ\xRW^\u7߫x 4xû쮅A'ɮ j6C.{o>Fvh*{;Լ4*m2_pF?8K: K5}exV7҄1 J L}Vnת#^Xh ȸ&׽X P#G^%AnO3!LVIC3պߞSAN}8޷Qd{Dist4G6.P^1\ k oV̳xtPLwgA{s1K^-\S]Vcs R==mM |㿄˂Zy.ʨ& p]/f '%g!3ފ|n:9mMJ1Y>C[#OVTv2*~1I-!Y{[%a8$|onApf̽6xt*8pc ,7 XU^ AÊ_SJhY?\CMve]s3<=JVyIbJ%r`-QeQf8+,豔v r5M`f-( _k9ՔR. `Ʊօc@R>_ B*]h9au_`*UxjdF!Gk~BAog7/d_e]Q@tDg<e9Eui"08*yhp-c4F0 LnT%gD5CDw,!%Aj 'PH3GY/gfUZ ԗ"is5SJs.@-aGM\_?% q+;3W#jp :G|,}zрiO@3<Ŕ.YKEttP$&dWhN|6KTQ~ rx ᝐ'(x@0?fX#͏h%h?83~$gx*K=]ZV+^+ YߧƟNaw_a-o+E"BW 9j 5r!5̍@ΚRuńO16tv/hchpȱ<͞xB VA%7OnLXfOsߔYqe 7,4VhA<&,:C# \.fW"|p? Ksv֙Z6͖mWj'\{insI|ZwF. *[Q$*yNVQbM.Bݏ_ހ,@-ŢYdKl^~ ㋌1{5R)VӴsE`*VݘQ]Duȕfk3ܼZ( ^ Y_ZSՌ(dsz`|Wd<ՓiX"ߔbOtxţ'1鎟B:ɫ1):6}Xe-z_ڦ3Ͷ5q0p~-@* ̲XY56.Y|>"JֹnD r׌ަ(Aj|oRAy▔ ߷>H]Z,1%iyIqk'rԑRc:KmoY;SpA*th:{/iX5 S!g_M>~&UM=REjŰ$-LBF>eݍHͼD*h-MunhQ\O _G7 VY@?psqTKU\xFK}nfI 3|7 ҟXd\8dt(}}biO:$9#!w֣fx61襁a(l^ sK{z",SE 5-262Y~X8]zJQ EdF@`1GXGUcӈE|%%k.%gm^or uV%}*L,/~ ! ,5PZ[4Ly'NͨQ`JApKw:- 3M96I\ cJoi1sL> rmS p0ZLH~ h %ipnx:o7 cfBvf]Imrg'Km3Cmս'bk\Nh瑃4B`ԯ GyF MN.%#ȇqN[lfb^bsƫԾgjK+ZjLtU<6r0- (#_uc(-[`4n8`f8iL!SE{\MCOfύ&P7LܮPId݉>Qn"%{Ԧձ G;!9 +O>ڱr }*׬p4Y<ϼG>Jj x /aF`O: S,n9qW*y>nlDp el=a Ďk[IdBcR7O 40W_.{&Ru)\|)ΫmΉ@x37A1VAgK6cR<՜R>Ȧ96BNOM{xԠ4CO!:gi(M?{EN'^-ԇPv!Jcf [4JUx|M@4jХXMjس;EG1ӧ.ش-fۆͲ}i6!ky&2 1 [G(o2ZfB@{a擨 MUXT5{NaNQu X :%BwgksX"Z\#@IڳmUyh“ Jς3V$cXmDpC>R|M>/ * 2kQM*$ 6nQ<?a .HSߞ(:@ JrDR ƏoaU ;/bA}BڢTG|cTU)ZaI8wH[J3p>Q>o甽9cۡK׿RCr5ad큛^~ݢY~}5 ?\v7\' Y0> j%φ4d e&?'t,:Tٛ/Y'f)ݲ 'zhKfۿb} ~mE ڴ/>!VilTZ_0S^dܣڍ.RmίaC9Lk)5KD섛ت|h'w^}!B⬧po. 7F_iGHl;8լh{xכ~Lt!m"AJ7QMM%A*q2!+ '}-Iu%-#t,J9첖#J/U R/)0(Qln^-?oRT2DCĘdy|]D_& /'djuAr!2c3U cS:8*@nRE0ꔥK-qK3U݀kDsKhE9jҵyN9Y4xЪЉvV/WW!8@?CC ,-ܤ-_ ˳ޥN[iϷt"?^x#fe$N*3r딍]jV _t%r~ԐLt 9xz<%5ScJ#T6J0%{ /tsdu̜JBVb9Ʀ*^'E6禮`Dq:N9Bs|gT7hXIHxM^R -ԚἝڠ3W5>Z5sٖcM;Cx`o ?U|5= jQ>7]&cm_ Nþ4?C>=*iNy]ET@$1[X ҰOA8ۣfvgFaaP4#P,$\PIiX rxZ T>N-UoO>|%8P# .0Km Yr FTa>VWF)Y&+ 8D~(fXИQ0!YD; 0a.^.ƍ3}N7@j b6,wW lDuUCǭU|8ī[Uâ0ScCo BE%XDC] srDд`E<_fZٷK1q/ $> c@aF<|~Ή2蛏I齟}41EN~`IYs`[B$p .̗GoGJH^pP`'e~btHoèb'j"> n`"lP8!x!x~,-clHQ9m^]p1; `@,5\/0`W=Q۠u4FG /e?! N^qDKnTKA*I[ߎ.M">D]ˏ[iaxTws bi END2X}T7-11?psBFavk(e޻eKpkC`W dodMZ$7gU̐t_E4AE>oǢ/7RP2!u *X偅  8~_<h^ʼn;L?9B팤Ǣ1w{[ӛ* x֔utzUzX3Dmw6P$Sc|/z _LIV`kݩ.Bl7$C@9Q6T/ ΐK`׼ E OT-,Ȕ0t^ѾI9n4 ֪ n(jN\^g]$¦5T Ȋa,{rfr){; bCEN ZGJ`DCGLL}YV0B#M$D7!&F<mAT,/8G:v)8,$ѶB*)x~}UOR?Uhc_XTi`$yNz^N'p3IBJ_@0 叻')DicfXV[퀋YxOdo]_0;QYJP0w@iY8JLr|r$([VCm{)}oR+F>{"BAZ'm 16Ɛ(D#\Vhft 1@K.}:c%8h;81`oe45Q4w$eK)Yٶ.ш5mL]YOoxɦOX2Ф$IHr@ZL VYwf; X](5v D6eMQVC:%J\/1L!&sd2m^4HzAy+8ȚNމae$\7Bj@??2ع"Ad*-KD ه$c4z*>}a=! Os\ⳛ̔M.3zGƒ.5jQz;]Md#WS\Њn`m̷'u;yl=' :%wVc޵Y&&ۅy{)IżL'xZ ey `@ n+o)9C3c? imNacUBrƌNhn;n0T{7LHl.4tʛ"lJ YƎe}Hbƍ7H3r[t [ t3< 4FX\yOzYGRm0:HEjSdSek#r OUPAFri- w[.vUo Tɢ :;s<~j2X %{q:8f<_wlT6@u5 =U{ȆbbN$lvXS-ύ k(o3sXOs Y׋t1rԤ-ٲFºĩa B &/w|gPb枨+,rzƊ9OqW/snD=(~]%T5)'Uq 2-/$‹*8.@ 2c[_0tewTʼz`q0evqmq`-:Ѭq;>лBTFt#T V(K$1*MQZ 9 =2'aoFvZFM.[܉tp GxULomt /Ti2| gg5m>$n" ϣDKS/n I gFp3\ι_@:"iIPO4-$ݽ T,{m.t]ǠV'<#?tbRɲLyM0Qp4J AG"`k!_{[z.`حhagj[ن/9N<v5A?n' %H&!@%`Lt5BD @o5@$ c@I%j%>qlCnw6]fwHAL5W-yM؃W\ÞS$"rB5 Z# svz99fT.Azxa#o4RڛKgoEqL=a0OJkgfE/ъ>*ji.I5;X%4X]!u1j P#9<-{] ?1 /9^SFXU|YFT򹳁`YM,Y+=go<]pQ/G̀M~f7-QcmGxb8ЬLd~:dD̈́9*z]BܲHRib^d1Ƅ!-q\kS=֙M_xetW u{צ{za+0 7#q$,1:N:еemhwFh2J)k+.Zi >~W@7$Mѳ:}¤j@)[vdt!%p)oXZXOE:з- ύc&f = f C7c&Tt(C|pWJ1)QT9ChV˹wBIy627 7-FUR郑+ Tk`^zQĜX.N /mQh'lq8K[N>96zXH"rKh]nkf]eO}};>1<<<(qQs mFj 6a|Hϣ 8W0SQgZ !Áy R diEs.™ ͕Ôb$'׸9@'9IeF%!&L0Bx`U*KX} ENލ)gIvg1޺x,|*) ejhoKԂ7f*XNJ}_ tPzoݻtJH1F t[6wQlJn;Q73۾~ dhEC7F^dt:}8,#Qܑ5L ;&a6-Xfld5֗[Kmd)*:%/meB`!;?/dvH&Ρ̑p.878@#ȐX/aFsqs2&P!]P6 $$ '^R P* !^goIyN[AhgbEy0:ҴJ-ֲM0=dқ>Km(';+a *SI_C1 S+iIpzt2|IB$I'LhcQ71QuskS>a9|(<(О !U7Ǖp>fܕSu&RCXkB1p6o/J<eE0P5^[p-(sD}%- ai()^.r b癤yrd"ӒLVH+NhHɔ/Bee$TǧF{RܣO5U'pӻRTC@Sأ}i TW碳pv w[|gokC(ӭ?c(eU,dh緭F4MmQ23 hL-dgE&xÏ "c[uyh,0)8h.& P-,t@/s˩~'4'NE`2~u7mK6ƏGޟKŋ݁G&I(HB%<AkqE*ҘH(ְ31_HYh<s.6'*C LïH`}KeMij*(̡ "X[Q͎)r*.΁> :BۀPB5:k)p3ߚCwTH\ ڿ`ۋj;'<^fXJ;iH-&!h &~b&g][nYP\D4:E2yd6H&߬ 3h16+gifD_*B0N EV6LBXĂbcVtJU!+/~5_ō3lR2) Lip,.8wuuH M+`{~s?=.NZRR1hT-ɪ|t)7RNj憭 ɣƞOR6X˗{y``T7$y l%^)2$b{ec='>cn/>:T|Y=Qde`8%x, _1X:lj](/7$ۓ$0ҊXK6`ˤSy܃<qTmEJLu5eAnє 3q]Dǰv4>OSz -*-3.5K _Yat"/'{l ht=Gp y8 " ۦ\wU-"̏Tae+B7Y5@7 %u go7x((uD:?F\Է=1-fvw݀ yy蹛_!>ɇi,1L?QbARkVNzmz56M9\Wr)v҅T3J6 OhlAnW(A`@m!*4: w.ϮzP)G3=n3إ;66b ;:>]sџiW͖μ_H85e˫X~{'Dy8p C%-14L`q&믽"ddSrDʽ R&& M~fm烂3*BuԵI u)ۯGnLLA׸>҃JКf͠1RC80fuQԀA޾TSƞ{/#T_;̾خ8Rg[Z=:mJ)@ !b2iݞKN;,rUjr|W-]&Ed? (e>hJMàźW"ScEOfSE΍'aidfԩJ<8%/'ԗݰ'h~wM ??v31.}fNx!|4-8ߞ)\87ui>pKr8d\=ۼPxݓVc*. Ҋ_xn)tM۝nhe+) Of ޹9PB:Vt3~R4uUh8v Mno ]XyB<)sVZR l>A& 7g[_!Xz>B&s wFuo-qa^$(8̃{԰zx! ' IYAdrHSp4E };Fj %rMℍn U[tukWFn6ҠɄI'uV :^1^*O[3aLdZ,%WT8I7M^`PFs^ ~Db4[+-$(CIl#8x1ldBƚu=~|bGIӟP g$a>MHf9b|f!(-N]`y2UTxHQé5α;sf?=hHc,r2nUF3dX%8M#f(܅ɪfZG]_(aoY}Dp$gq|RqyNȍpT1ay /5c|:%9޶є?Lƈ/l|㱡8w$C=QuyegEtZL߳ya,C➏ L o܅ĒYDkn7 7\1{{_A Y$D/vNr_ƒ"1~#%%5@F/:ھmCRCx_='_M|d V)pb|:r кm=U)"Nt?^0ԟ ͇+|C8g(HJ$n3U?=!f:f(54HnLR1m۰ `#G]mu}w|*zCFizCE-M觛,U $!\w)ɻO$ P=!:  3!|r<gQJ{fШ,K7#};3W+]F-OӜEA!AI2m+LBSOJ+w醨 6 \ؖswi*4,!?ۡ"nqunX @P AK S< r\{KPa}*.'{$ŵ196aKbu~N!9dde;^$ʥ/tZxxȲ6ԅ8͚,kcIf1Vbb#>1l.Hx_աB!ode~6*jr[jab- 9ڲ$#2ؘ+'d&ڵK:Jgw\}MSI@ |u3CHq5P cbڸ,(uv'̦F׷-v'-TEt(h,q cҦͽ b!Hx {'J8G xwwL3ن3{zgM/ HR9Z4Ŋ(WD>چM"ǝ⯖"߉NӦק#}9SJɑq0\FJLXN qq5,BgIآg3vz>D k]i{h?CGnn+ЗOG@1-9%WK9F;8>=[W>F;$r\ؖ7,*ƢV%mÌsO׮wDO`} [a3:!<ς#xQc\'* D<㖻K ޞ<ɎvqV_O,35$@c"z)f9oNX_ģB{+'I sȂ[{7T~V:&"ݰ(jKsR~KV˯tJE6UIMm343r”D@^%--"ZIv0 oN^Le-^8\z8)Frhb6_JA#>M %_(")QcXG31x<{[xSt\Omy-T gɨ*5HQQh{äY.:Viᙕve :Kύ`E4KMZ_jadH4{@N$JCX@PaIZYZ{h3rR2v3(-GP#^U5 z-ǡa#[dTcj?R>dكJA@n98{ACqLXᢨ 1 ~{y9̫DaA^U76:6}%=rhYxD5Ln)y[?prh4| R$4Y8d$ .A/JyjKE߇ #®.zӎUZoZhVKH}Q`'{92DauTa7r8RI$Lz83&ݒ?߿s[n5FESl{IuO>)w?Ys5û<5;7Y*ώ6f% Ar9n LwH'pnR|'ABoQD|nR+v٢o5,1']Vr*? %ԲӓRڰ,޸o.*|NTBHKޭC g| &߼(Nl7' 9՞XȏGbfDv7*SNo3Pn?(e`2 nGscH["v`<ʻ ~o[{O!Wٖ-0C2M3"7UISO4DK Tiۧ%+$%U6,?x#GŧuLƢ+LLfv[ԀskJOۘTvne~Efp愸wSxsI}N]+L"`N)oFi4Up}z0ӪTQv\b#P=Lg \: bUVR|пe!$] vS$W泣@(@ABW U_9fыf*ϥdӊU9j,zTOԻuyҩ!xx";[`[)Dp%@\iR0Ԍ>M c]d*بo='-De;x 7H\c 6;<AE==65 NGuGBxgQX{.[ njsq$Sr9h}@llAyfk.yL+Z\?ze#m;g*P[YM^Ba(a {L1Y cmGPL%K''PO ݄eCsbH c R]ޒA\?ɩ 3%Q8"@Σ_\tCrɜE\S f[mq VwY.YQ@[Lo!5DŢFU铀{!S,t,{ Scthu5=6Ԇ:Dܬ ^X[ev=\.d!]s'#@J XT!oKN 71WbB4DOOw/J~/x{0RM}D^ȏ'$<ý3T\榦Պ]"/uiQC\FBYtT}V\e왹X%tCI}EѠdg31X9)3uGOGz)še}aFKnCr'ݡk\UA{7A+iΨ'HV Yw~Gpiohfg`e\LmHC>9NkC\fEpΠ GbP!#;gf __r#:aԴ ca"3Q긕QxIݠ|4ӭ Jt|sm!)Ks\%I{?ʉ^# ShrONp{hO}מ=;1y_nx6g%A͖=ߙFmN&>@onX%ȵ {LƀOaԷ(Nu9U 9Bu[0T/98"ҝӠOe,5tVABY`&Qj;u,&`5yTi``%Z6kd, L5ȼON- MաϡAOk*ÚE5nt#~WwHǷ/03g}|f" OukH3kI's̫EqPVn\jŤH]D 8ԺI- Dͫ2QJF1㚐lWHxF>gg-(+hơx 68ټ{GAIRo!Z# syG+lwn,țyfKy~2@e!~F`p^>B|ՕO~zw.z﮸#GY 4 A"U7r 7@ >8"|t6d|zgi K;i7p)jng͋6-r- {ϿkgB\H.:Wcby~Dꣳh/Ԛ)/< /j!WdnuKwbe] f* TYpWv%`")f *旎@p5&]'Ji;p#7usAqdQޜs h?As` AWE2MP<HP˛``:$3̯vi)6uI+ˆ]rI''+f$Ðq&/e-: Z·K$8 5 1-|np#T ð#IJ %UnǏhVkçXw H̨Vi L]a{+Ӗ3ꕵ"@PtI2°.rBx Q^tIpi9KM '#%Xݚ9 Mx/+iښΉ8=p}dapQGcizKȂrchތhn8 ߊlpNJix,+C*woޥƭ7G(ԶYtq >O9{yO&(k>vIGXE$1U;C Γ(޼{7:YcWCM>T]~ eJ?*y e 2a1o9)R*YigT Ǔa]ŒdR2h,:ZS ELGF7]^Ka|aRkL2bދz[ %a J#nj-.?@ n$1bOi: Sp5+&d-ܧU%#]G6 n †8;cŋ5㍕^?U:2Ujpd1|]|*F>bw<5f) ]yr^Ms'مyq;{\EpӦ+F^Bx ~5zK^BkRVtCG{|2T2owH[ Q'-]9zJهo{vE&o'G͙K9HЈMlG+D-[ܘAl4MVS5l}8{ }@RЯQsXUɸ(2Z \B}4 DsXm2纋3yPLƀTCj;]Oh L:nu9pҦp&{Xtx`Duunb(*34ih@W)T?(1ꊛE,),G.xu6-ϲy?i ]lm2 s?a!<ܕxdrlcw $󶝫ݪy7(هm^BRI+ǍaG?]deZ&{$B܌}Cށ9o/kÀ $카`LԈ#2 IѺAɎ0hA˺ŘODdS[ ;uR0\Di^'zUznW)Nxx_؃C,u#lҸt$#w _WLOl lxERb r<4[U}l,rz33a33O3} H5 q<,qH6BKIlf!j˯ ae Y"-@majp`;b^TxPИk^3 _21p.>]p3ދi~k>n kU{Vm9 !U#egh1N ]U mWKu.GY~&K23r?nOul8LQ"(j7I7cZœSHN~J_Z뾜᝖mg: )W-c[QF~ SxCjE/sd @eMI)5QpL]}oִzmTɴW;6x@Yݤܪg !@xnydT 1!7 >!/[O /-}/ ]y"u!ʂ?Ax/PVP \ ]սXb Su'RX_?\n?@vYnbdޣ{s6pH%&(L 9pAӁkw1FId*We}ŝHjd (beCvAT9)M1xv}#gTլG.j9i"6mFSwf*|:CE*~uNX}YMn'[Va?\N8'/Wj L-LQիrBK0퓄aN w |_d(@f`?n/TILE=R뢥涚ayW2ɻ\#TE(KOŗ  }_]MYdVVkb%i$IaxuGQb2~ Ո gǛߵVXr|="Zwʷ_^V)U}|eQrf2]G(Vy,EOȉF3 \9IvfN|H-Àm ,>^ kn;e. ׀ NOp4F w"`95w?pB$>È,u<4Nj9§rr~<0J9c=ʓeHHÎBy( B9j"9C2c~u{q,3^_Wُt:N}{G#0NAr `%Fމ0>NzJɶxΊtgMgK?Sv%D^T(rA)v-1|Ƿj'nX(17HJvDidaӼdtrGw+\4S孬؜ضs5L H伙-`MV1܏Y'%TX+$J*E}C~v 5yRx'? d (VjYwPG0Eyj~Rݿ\ٱ­Ohb8ߧEmw dV!טmS/wO+ΐS"N+\gz3xrA|Wy[E cZ2b:k9n8Y)A*:}GRY8$›?YY 75P()t _Y V>&r̈́XE%BvrHnb 1Ձ(\ܛ`fp98] :so/,H-4(}])ɰ/Yy,oVQy†r^-zJI7HhЏ3d/Mp4a(J;x8m]dO̸*J☪vyDK (Yzٛ#Ylptd0Q{8ۮ Bq[vl̘6҉ DJa}r/-*  UԁڸV8ʜAiUGc/ՕlJrD3pxr-nj: L2Z8d4! C >`S46͇#i-X:u5u(f;ty8cgcjM,1jOɭۦ)0 ?v %^ \Ǿ\sYIT TZ^$b&Mpѫ,˶_=eϗdՑ4E=huS d32HwMnVsK_5 `~U]y u^vӏѰLu7#%oH2J[=/i4DafLꐈhK>/ө$ȭpI\*Ŀ$ڦ rQHXJixc?_Y45V h8ɀq :") %3͌wU1Q=zKf5b]߆5͐<{mKWwsaD-f}ٽdէ\ibs5h09jb2&w^AX7,'ʬ$M">fDk2z  3k7{aS75'\q .GQpD+8M I.Uq2s2X򉩮AзWE%?Uߎr:bU:"zITť= 9K&W*41})ƳR%֞f|Om%QddQ=qt37|P^V.n/ؕBv\x䵂SP׿'TFQ?l%WKu_Evė2p$dh=$ ^wP6(>YgRdI~vk#9륐&E˭ƈ`3@nz(,!Mx3.>zh7̒u|[F xZL0Q;#\`up[Vy?Į60;!Xd+fK/Oro=nc -["ẌG9|ugDsv{<ڼ#Yʜ ñN$a+ {A7j(vdt3xn*6lΣ2j`Nƈ( ^ ^&%p5UDdrM܎,Y?2}ڱ5"9OguQ.H&VithD@P) `߽I'*'Tdى:BeY8K^reu"8EKIh*E >[\{-!΍ʨ!_e($ 4Z2~6S n:BQ)/?mW:F[b4(0Pᢆv< ˊS"^2 k|їT> =?O,uX+GqKF_xɛ G-QjKSÀڃDSYUێh|{O FI ;uΧ=C ɟM~c@a(7eYc򩚄>kפIO\z. "N%^{hhG7cWuYiUq djf7! _kv=iHWr8SQi{X5b*`L%n&/k$hq(kf._m`2T B ~1)(òF'cLָXD쯦˭t l7HOUVt4gyV+ ]z5!YVJmV^Qm㬲Z-3\o4`uVBt5kׅ%q*䩥A:Fgěw#2M~bѴ~N"@P#w%=2_)ĸo$|^:kR(UJs9|FBq âlئhf~;ϓsHn!S*SPg[2c 1=peT;,za7RE)qWHkV^F$o֕zJfZa&,ԚW+ŐI*k~GזaY" M2G.0DpAÕ&ʉy֤ !kzC>j&ec޲=mf<-AI:Қ7<^i&@8n;oeD[S@ ii2XoXĮ,)֧48$ ydXhME-)1 Ifz~4)Jj[}m puE?RYuDz۴ [3 }^^̼xAe ^ *{e<7᲻14@G$nYԬ^÷Č_szQej\JwM"0aKUкJa2Z3Iu7nO'=a ]GF}/LcKٲEXh7tw? 5}ZԒdx겘x4g 2Kr/>XH|( ѐ ?M9^sOs0L¹p󆘓iXrd@!+yH"@H-D*d/a'fӹb U%h&tpį,$⃭c(KeìS \2klwpU:v̱T(C2I[ w U#h?QcSvr{1RFZr[׶`%@HJ_~o`3ej|Qu֟.9O1KƊ`hRﶊHtO²\*1n5^œ9w+Bw1"e炰Zo^hJ,ngךAǶyY^`u^4X.c](I53hË\ msmw YP)pȴ)-EwsTy"'SʨjBM=`}ӥaH-)(&e۩7oV'gtXxMdyo)xzMPnBiD,3E:p_L'8lūλbߋcұ+' َΈM"ϭ+c)LeƘAN 6,䷗Nl-: iv0)U0~U"iK]nQoHNFjBO֭So=Lbv0"ձ%+?՜9iYs>_$N{%T'4΅6;oS,ːǾ1ڜ~&=Ta(1#C {.IAU Ai7CzQg1;B('OΤίݢ JaK86uلi: n֍jYg&yL s<."TdupG4 0ʩaq%\~ 8c6>#v[6n;?,μ\E3gs*@k;v  C=}]mhcGR0)H~G2l.M9AF5O g8T`dWlXg(y{cܲr !/'+!WK` 9[Pa$ѡyS}U!)^+i<ҞYD!-˜Bdf]Ic^ˮO%Ka^__Ɨ 0;@i >eyŏrˑ;㤓 l{ov '6}7xg̓EŽNF½?L~Ӌ[*eT{~0uSa^ǘ]5&1SnD w|+dricSk<I8;. \R:Ij22k!m>BBaY2.h_EHEѩZ<ő]T8ocXj\֣>=Wbƹ=x$} i>&7CPD/v\> C%I3͌mTFpd7Yey8eNmUM:ΖwOr庶n|[A{pBg\$8S$;"?p<+:/Qv2d(ixke5Y]Q컶Q*Jǂ?pY]ߑe>L{}S%{+T4ѦgcfbA"ߘ>f+/p-tŔh.06"Ys.=>wHw||oP zQ.P6K%:q (;v:or4it&v8u jSEǙPƫ6~{ ۬olEF&h-ى2vjAP^-ProaA#%ՠQ}2C!w_:e]vg=á&z+/[({9\,G{'ϐ%7|XN•⁂CO(}QaxADu4YX^oLՖJOrc\1X7ܘ|lܑ;?AO[.Pűkdb8$@}z 67S߮M4B$pI}wM2k= QMӔubAs_r e祥_#uZ&'x2E5'W٧{7R)+;޳: OeO^?-#cuCpH]#$Xhڳsv=;kVt F}*ۻ b.7}aC͒BwSP\ij ߚͩϦ©MFw{(IdI'KYrvгtU~}߫ W:4W]o׆!G2_geRay`~?-U5eic@]\_ؽ(|8#QJ/ / |etIt=(‰B$ḏ@ A2,=gX9(J]! dbH(Y+-E`uhhgVCQvr0bؕ"toF^w?j+^gǫw'v%>YӀgjzlM)kJ,69%[/ѭF)Q9gH%]dt1tvVhFpql).ȼ,6v,eA:W+2zq3I/zeA,t.EGWL[Xc-˧`"$*}LɲwŊ&"3_IFg8c_ E')% Y erAeEm.rM^Z*Z N8 ޴(ԥ\3;!zb82s+pMx< U|WX; ʋZIuBc%S;(n.1jfvZ.C"҃7K9;P,mz?! {dd NE,g(W K=  N~ywjC*ӡl~r#Yv6AHM<m8^f}ʙy.c^), ԶI(@ d0z\9lgi|HMjkQxMѡ?UAkd?\9= ‡y_;a?RN0 )< =4э}E8WCBG !׶ #p ְiJƱ=QTnv%>qˍd HQC+ͅdܾ"Aᓕ&Ր b(])ZR%z"84 OY o)Z]`0  Ta#'_ *ֺFrWP}҄YPpqixw&kf=Aʋ.1Grh"7>>6-e6Pz$!dHIТޟgָ,,)LGב_.f:ιVbPmrl[5,̄F]ieh8l59M 2‘vD)Lb8xUJ=RQA,[̈@{vp/FIF zDE/h2JzhL&\2VCc"-s(x-pE([:kjhL]?y7H+ ᢂ1qxw[yQy\f.jKLwқ0sפR.Hn KzCuļT`W2"z,3p'>ꮣ:P iruYhqUW$X wkİ%Ne[{i\ᅊS2ceX%dPd->v޹ztf.-WKy?d_Mz5P_]5K)VY?!&]H9U[(Q'eIeRnVRYU,ԘsyۡˡmU zL~~;̱JoҴtRQOmWH2l*Wi%ՍP٦/V2MӂGRRZ"{/gßf3Uo2׌3mՈ$!-n]/ȅ߀>N7>מP:,Vt%?4Ȧd4|3[s'f=%]CQ^cuvfGiL\ݕ܂INzatv".Ue8^"k]sis&N[gAݳgWh=NqIy#?Rϣ<Z"Wij~G㼸ytQ{Ul,,4@|v5q|l1V|G f]Չ1SFK/SZPmjX^e6S<Ƣ3BoOKd>1'B,κf|h˲б`47`eӘ}(vEҜBh)9cQŒ:GvbKMoQN2Ge7y9e ~|79-n8<[U.~C_c_-&Lpxuu:T+qW6fc7RP.c0j "ȷzRTc$_#_!K ?隯inܐMN=pCmLdp]T,{A。 I@"M01TP1cJC1F1u¤Y-lI{g,]B`JVDh9'e= nݑe[5F;Y%NZ,⢳n-ݟ8",Pr᪚2&qM_` t'-l_%2bX-HԋD-7-XF'i :Q9Rǘz=18TQ~ߞxOlm1 a}LW]/XY:S .PքɹQ79"Mlb}n_ i4Gԑ ]qoKǾ*Qlq8јz*HKO5Hv9Fkwe斜R+Ɵ>U wn|LbGg3TCp*K{ޭj+E!بL%>#RO DA߸m؍jd)^{)O:kn!*fuT V\cKMC̃7=bɮsYѤAZT9 3TsQ4AkyxHU!.]\EoaJ]JHH!+CʏW=d {hfV)_ɊAP/k3  @G- oyKBz){O*~.ySUt~xߛ {eg51\*<3Hv<}d>0kah8fup=(,N5p9fe(W>] ŪC60> ~^"]7MVgޡN|q 6"9r `IwGu`y;8O(ӰKMZq:(1G@3<#ARŇ Q"^%D-P5 ^AIQ}cQZN4?r 0o K;ӕvJtsj 'C^%@vۜ$!ӂ |cs؝K (g'ئW~GGSRrƅhv(Bj,! r ^?e,Y9БY%wsX Cy lz쁏=hM_}xUxF\t:?FY}%z WUIRiuo!WflaYbz5wEW I78n[Iv5,pۦU iTZɪ 10aF_8l`;%=yB;sfGjOp%/n ))81K<]adҁma{癀m]9-jp!X%UN,,#$oRt19{ca7˦o0%凖xLhS .ڊA3븘kƴEPҚ 5S*iqy4ob_g-LxE(=#6 2.U24$ ҫg4~1ų[L,M5ȑD]7b@ "OM4>JwI)j#pRhhAc;8م7FE-NC-;!+g fAD,I⧊\s67'S9!vcVy ˿!UXȟS{OBJVSu™MBgç_ DgP$o}PH0+9M+/zwH-׸RP{ɚi;H:a"I}[&r 90 ,#@S7cn"%*%"h6bҾvT@!vCj# ^Rph;gv LsQ,Wy"+OSp d8ొt; 0H CX9!Nsm P1ă]{W0iN܈ѩ?)3& X̞&̃Z7ZUkUW8seڡ=(]tm318;Usqk?p<*kg-fYkiG ǼOaȭ.wuth_*k`IHP]~p 7 vղ(^k,}u~tX[fd1@d@9 7:Ju?Ԍ/N4,5@T jtNI3Uݟ@S.k;v᫏7PH 5 r&9 +^G's/49 :{$15\푟0Z2rXG-i#Fe_QV3*h4g59EΒ/yEH)Bp.}inj^ȵãQBg&  yN-j5}ƔgAd5N:OL鞱 N/p,=3r %=dg0_ 39c@Z6Z*0E*?P DsnAʁ?d8H /+a#xm!-gZ2JxWm] UxU KiP P ZijWf(:9NzisDy]ۥI+r˭\ ti%Ю@y6hmfk{aO $.vb*:@Mr4DzbU2@J×='W9V &hJT ԙ!Ʀg5ܼ8o@Bp DSѲ`}3Y}7OV(ܝ,|TΦMqs.[J;c5S"~j( ⋾n7h:dՌEFD9!ˁ$:m.V?r~?@ I"@L%[6No%1Cʂ2҉,oL E]9u 'x$Ã7=%N~}ٳT0۟<MNRprp̮Փ#딽0NQg M pv.//?L?{y FEC3ށU&&>s`hnJ3uڛӺP0ZcώpaƺTg[;)2 _ڣU3x<5w+HvJۮo>Tc)(ȚA% v`?%?0^80Ҏh|?QMZ^uR],"u!*HI?wT;*ݑDs Yozx7;``7&A.]<ccF#ۿ 2DNܦjV$KrVW~̈́}n}1kC7X>l$ʔf,Kk3Q8Dd.<9` ϣE&w(],PlKսD}9CT>|j]_3!WiL[or=$jkk)MZ*N3WIR!xbxpawܒ"ݖ,Su;vI&~W'\ P򌜂"pe_h!!D-z5!1vUqz@ G¨Kr \BZq#η m5Xud2R+͕CVz5؄7vKz+S"]3e-94h)1;[jm4EQƙXgJ+٘1*H@Oc0OP 8™Uu@"09_!9 $+GLV->I.!v!To Ҍ)븗g&.9D+>aͻ[ȴ!fӧ\IQA9n.U9qMSq".rgzb|?n]AcǝԩˎxUROG# x~;'JsݍCpב2!.i /S3*eyYqY-ʺߕĪP=)m:)oƤEnEibk*95zqie;CFA(5rł|lm'POc*%=<|Xn ]'q\7.F U9m5,2A?tK$7/hc8אsjWy&RJ*"v<.uM[_vdkOamv&>b9AS"Zx.RЖ/| DO 5szLͫ/\956; mp,"f7zRw=\O68-i$=1;a$ .8ߨI,k,S~F#mN%w<~;q'a#)xp3|4<;O cNv8w˛rXY)\Pi" ~.1m_G(=:tyAثăa &̛uˬ56j- Fp !H璑 y ns70Qh 1jB+j&ɨT THT.oUb7q1e q__@`57OIee$c1be Mƪk'/RwS"}pCB`CPAKn U7Ohj訶ϔD>j$,P` "ca1yD×G\7԰>z]PL>4V{/JYahJWxkC8莈8+54Xn"c zv %r_&mܙ13 ASֹK߽ X^~B6iUk<b S}_gbpV EJ7sJuw`:'3h OMh҄U,`ziKo#de+EbxBM)0Մ)KیkKN4,xk!ZȨ THjiWәV)"鱰/ﳳ ;FEm18M~ݦ~¤ 4C1+}B|sXrpyf8KiwmK.Z^kmd'%= @CyoXak #Аe+*o@_"B{"ZmD(uF/ R+qGFF"ke=RA_kbpYݝF(? ڏy!2tYE5@4T- OцqǢCq:-"v)tm#ġ !Y-E q :zl`I괳+~+TW RZp:f专L5?:/Tnږ è=,۵L  h:[Ԫ+p0!Jx.RSNG8`~Bg"~t+3 d\S;ȧ&n+Y;dqEHr DAL?&lWֱD|xu){0r{<ȏUt@dle #o8փk/* ?}oc[dl/Lu;=4殭vW52I1FBra:6 P"A-S:kR3lʗܨ3ܪC;2[XM(U&٢.VUl-wP=HnhKB{iLvN4mR O/Ar u#ׄ*k7p~d` O,jM 7UaAB&{.{U {4˔y[:Fb]YlI=(q>4qUm9qye6=!I=XO_+nSk9F5y>|+~)\l%4 FMmojènJ@\d3!oF%r$1f^جbjW0/^/V_}=7GbW.k|xRvA͢ 7:>5Okpc9bO4F9ӯuꂉs-"*te~e_3W1q:9'hܓ4Z : we6MfU> x%yĝ(N~YcfJwF}nHmaY}_$e*(Qx PhzWz$,^:O@ E+E`K?~tb)<)$*&Ac̷\-#6vU]ؐ]t4e;ᝑxzy"l 3ۘ;~6h ,Ƈ x@Oe% 5 QضZgDtp*IاRRFHAܰS1 ]/ WI!Ssgo1JU vT/z4GwwS_RޮU}? ^]@;!vDOelքb"fHM2YuQ #@mljq0u#ڬAн ukl;  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n022004l.pfb0000644000175000017500000035306510725114532023121 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusMonL-Bold 1.06 %%Title: NimbusMonL-Bold %%CreationDate: Wed Dec 25 23:40:09 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusMonL-Bold % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusMonL-Bold known{/NimbusMonL-Bold findfont dup/UniqueID known{dup /UniqueID get 4095674 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusMonL-Bold def /FontBBox [-138 -278 888 1029 ]readonly def /UniqueID 4095674 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs aded by Valek Filippov \050C\051 2001-2002) readonly def /FullName (Nimbus Mono L Bold) readonly def /FamilyName (Nimbus Mono L) readonly def /Weight (Bold) readonly def /FSType 0 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec 2o4>ì`0CWk Z_J\7T?PHSyo܌K8AGy+#Shq(=g<IˤuUb`Gu &J:+n.6|kSot懪ToIpL%p1M?nj{& ٸR<@dR/i$+Q WF!3|K+۞5^( 3C$XLFh@l Ȇ{qȿA:RmTդ{]bC(3%n ^ܗWE?#28pȨ?#QSRV)N/>$zȳWcoK82c1p>ڐyf26o'V9`n(0fԖu&UO؅CCkAHS `σ XwPICU\|/sVArXUɫl݈>P3[LfiC )UCF?M_۹%],*v}*қؔ R0J]k?L`a(}0ؾ##Ww*q C1Ofǐ*<8ynɪ1GDj D&-C 4-W]0Hڷ}ڈ:Y#(Bi1 6Uft5h[뎑$ ƺ.pgu5ʂbV]jodl5f{{%M>FD+zc@S҂uP hTfmp+l6ug1Ss;؏lJ~t 2CB%dQµ)nY݈ޗ 7#{}pyωXms P5+!%6W%_r Rʩ<B}^׵謚=,_c o˱j+ 't8tu.Y:2_Yޡe&{/\ :0IL/׵]9ћTz1cfHX2kVvz7GA$|7]1Rf}߷.~(~3<` !K" H*ޢ2O($xJun4 nwad[qJxj$ |CP8v:~ߓ Z=GG/2wYnIܑN%ͪoij_DBYROCEQz0sFº7@p'!ufh;fV+j$O Uh@'.z<)<9:XEʘjmڋAܝ=`:IwɼWFK1KdzNT5 w8o%DYn7",#u~@ijo.$ᄈHM߉UCMf z_[Dy $oNw%c{f#:D>.,}I`aղ?ȞS[+A9ǐ,CV ٛZ7GE j16hEbĝxW<׏*,O~N'N.;ZSޢ* AS$,IqSO|%rRCf'`[+o݄?i<6$v(}V5b g>F8]'r8 ?h%(PR;׳T%l>q@ZCK@U&>  Mm?l\s l_S §jU&XZ)Q)C5;[xya Td<ӑ^}ͅ|F#"8ozy̜7f(F,1f yɑ' ""7I~􀋃J^ʳ4l(Npc=tm=ű)oI16yqW2fȤ< "~6*M>ɣƕ#9%H2BA"&s_,%oTSr%)Ad7mm C+ vN Z׻^b<dXhJ1j?Y"TLq]YD3[`RIzfPNiL :eE`Ě^ ZQÒ`Yo֕ҾF=Z.KIZm1I~X!X鱌# VJD=ǮΖ6 ƀ|y_'X*/CZTzNI9cA&ol|MZ UMlDpD_V|nwM&+AK, Ĺ]:D!AAaφ n`d_>-jmEjPUJ>2n[MיLFZ}?ux 40w?0EqLiwj!ckY*y?p yNUxgk(ӀT_eóN흇h;Α[6<+`/ý$.HNB;S6K!٦&CMɬ*=|I;̘uE_ܿCq+Ǹ~nE7@ 튰yw+Y!i^Uҋ<zuwi&P$ڍ& Rɦ&C< 芓Nlu) lsbw&!Wq#q@>AT:/'1|$G0> *y Ā6clS``ĆxrʃШ=˝@HG1FIGl&A@&& ~Vz4$9tcd$$^m=_fɦfnt |K锎_IWn-}ݩc?[d sя:?u_y>NP\^?4u$lB2#x/ y2})`:o(ZA7VT\YQP`ɱG'㫻HdԶt@1$ٞ.BNn8 T$y:]ufנZ`G!Nd%j,0nY2)5 VD2a M-b_z4HY)%҉`< y S9sQ>iL(!ރt~Qm+"3z2H'T%,h"OU] jBz :_"P7J;g/j<@_bX'qL;I3P$t3N`lX㜵9Q!\۷}Թt]i3qpsvt~~&_&MԺ߅OHKKmh'zeHh >z84& E[j8]QK4Quֵn qp)h[V w4 J  GjltO ډ}1rꥥcΟYJ4m68jnB}'Iҍ3wq5s)LăAB4>sx[b r _sIMx{'wZ10qu('ҶN߀gX(6E%Yzۉ2oĒ{nSZG=lGM"AnsQ5dDA4ߨ'֑)Io)GwX(2ir,gWtY!yW0[MnsIjX8.=#ON6&RŢ:#-&E sن/ AU=NssZ>Ej::s>;AAh֟KGw:G&v YT84wzI@qnOATk]aX2Ճ*g\EVjuYh1 T\Hz2&pG )E&ڑE3r.x~JVvYPaH<ћgOjb|1ͅ B&qɤhЋ^^8r%[zwQT3L apvhDjf5q9-JC`ơ JɌgb`y0[((!~p񯥚Qɬ#/4t! ~A]_Isj)0(V:t΄~Da,2iJDI.aTUiX14oG`PRZڕK)QkzbakEz fKn0CuJry\!^JR̢cJz>H)HVQ_|-2(D^ yQ P@*i1y5WfY޹ǤWCJH%i/Ms0c{{᜴ځ']050 fsH t<fè\\fb/ eK n.I~r&g6F&5V'[饓F6BUChX^WU;@0{5.3͍uAk_}7O+5K97J5Rz̴'[),Gń5Cڋ9yo/Y@ M裯|Ss#m[gk+܁pY[2?l%rkM.,칸iS?)Ey %M\d] e:)4LpN1r;(Is7+NO?Keg{<9`ސ$2"q\ԝ<"FYӔʫ|.Wd(bq ݢLDL9P#sU˘ɱ51.hOTȴsJ%R; OnrZApԩs$$/gDYuLH#[$m>CY DUl1iW3ez9}${1zk7ot4j0 0(`(F̓ Sp96O[|hȟy@8P-R&ÑY2wg2,lyZU~7(xO$5^e[<~\6]%XȪ1h3'p@+xA+No(ިÚQQ,$5ٵ+f$f!zHLKxDESf2\pxަ芘Ï:f߅~r1 {O/pTء~;R4)C`]m!(J(;tO*579i[;,=~Zj-ChGMVz;xG6wCg%;@BḊ=heܰmvAY 9A쀒EFb[Ŧ[V:IvZFQ}JherBш/V)#=h~)?IԯymIת``!kHf "1!֠B\inp0o&%!-WDPn M`4e)< ]]Nd_G0S;t̅ ڛQmݐR_PEfg?e k 14!+Ma6ϥE0jheI!3 *k)V` X7(fw˱2W`dz騝l~yv P#CRVxj71leRR%LbP9[ 1+vgx_i[]q>oQ8ʮ!+dV86輶J\{qDkly0NKjTxkПx!~QjG`QxbVO*|"ʦ\i1ηZ=m)r9M GMOZq-gO3Uc#S4Icp,o^^_,|emt;)ԔI|#M§NHul*O }S1Ld3\-8EUPgԼh2zqH[ ge:dl|n*Rf7{ǭ8r<'~TUs 9j/Hw3Z'5!5+0Kͥ76^d3jW8w#֝o>)ۄ9^(A0Qq{8vrouMF~Tɰo*sF|.9&yY†s_@ hD2Dέˁ%, QY"q΋y=ĺeg hή Ā:! {C9EYel x Ml_dnyb_^vU~ ti(bxg⧤D VJ-v9 D@#.f8K40sZNwpo Ym dOtC~\։MN[[w "=Z]MKx?I52_ҷ0^.q‰(qEQ7Rl ;Տ]%LaҶnMGq(Sfg{C(ϴGw5vܔűZfU ;2O9d<Ѫ$_+}S:8`Қ˅?8,[3>H^Y1_r:*8͕H}%Jٱot"4@JYG2VjeM:UZ[H)|ڜ$`Ϊc0A0z ,o`(bk#J Kd8Lr'.VtT% ŬO$6>h0/~`&ە>ҒX뷵^M`h6)F[<%4N#YuB.َ9x(L{8s&LP'ybFqWA[MPs%Sj^icͿ-w/ Srb~Eؕ]j0ee(fsU))lQ}_%CaFqN2]Sі.96U$l6#=2:B24@61-[G1{YwN-,F`PTc\0 7|uW_r˰%Ff`C%"Z6v2*0tM$5Bƺ>^Lr˙r Bz|AV<0hM_u[P=nl4w|f~]O(4=6O(kUO"+D4=|bo-do WB -]`Z64?.;79 KYZٻ.3ozXb^I (2@H+Y.):ɛ)b VhlpqАc&V߾LbA/Vo-~U*,HS+/Bn\U.?hd|EXTlnzNsz/8W-:m|+^2^B}r F(=+K+q\qJqb}wO[8כ<輳VGi kCV J'֓ndQy@& X]U,ܞw'͏!&$!MJA]cg/ "Vg,Ĩmbz0Xl> ޹I祫uՁrٚ6!8`:.384Ϟ-x4B̼7nNQuDgrYTIX5f:" a1Q8rkxO/0_%Ub R-%OvT+ube'4,L]>)~N3R쿲mXV T#F1_㓪)XֲTmIҵ֍frs;!Z 1Yt+*Tőދ> S} O5~f챓a\H6Yz#T_ÂNikj3g5R e(INC2~LI"gld(y&T$'bseD? FثzLCıp,yB1aݧlqʣQ2/lؔC?9v5;M>EPT䐆{9hcqZˋN>nEWf!]e(iR]iE2X(,` }"A&ZOTkJdJ}b5|ǝ7.ޟn%P`#QՎI5heFD7PDw\b$(ȯmfI93M*$"?QL_2f񺋞Z77jK" ߬3ȸ ?f9マM /,vYp]3Rvucq#Cq"o]c׌پ`o: bH)a˳)gDl$T[M DpP@T5gЁCpd歹iTYDIsGr;aV hQMw M{u(%'*G}h+t[9ύ]qo_&4,lۇW"KBd/%:&}a#5i _Y6N&ߤ[&IuӃֳTVQZpbjЙ2zӿcl|M@9.yczuS9i/l|u^NGc\*p(| *jwoHF} *D'>MӧhEgcu.ۼOqd4IGRj$kI<-ZjZX灅pf6aLϷ1=IRR{Xۅ)K͉o"Lg3p<mYƼpp*m]q/S?soZ9( qZ; 0\+6ߑ&Y/Q/w.)0T6vɶ mqֹ+be=lj9DE{;y!|nFhfx &v#h掳-QK7*`ܨIX2>q+W%QyJ7+u mv!wc{+İm|w)*/ncvʧ4ٝBZ4D/;XʄVġ 2sBr<̩ٔHKusp:xI+@SEe[<ԆBA/ڲXM%~9÷D =mZQ.*R ^ȧRzqȣ6dnCz0 mTӤ,ܗ@P%A>S&.M_f6x$Z~0__KpJ]T}vy/|JѶ>d"﩮/hʺvOm!!t|٧c50F>.ˇ^gǯLJ2dcpo"b !|96;UA)(qJhpMx.mbpG 8]l o.f=NxT#tl3CyGRQ].8sdТϹx䠑 ZaCnD wS(S8~P·?xG9Ԭx+IEecf1D%5&}iAd$-.Xh>s#Oϑx@u}PX8{l_!ԚwBwZDVpE!˪9H·CX#_ruP vd0bF.gW%BI ?e¥k`ȍ;=<`O2iiWg͋GgPrЮQʜ;qĊ E]~V1!@R;@*>uS"ֹo~chc7sRfG:\T Hm_2vl".118S[I <=z$٢L,trY3gX*了V0=3Abe#}LEԾ9X #s5~t:߬W7Zq2C՚G$h ^_QI]-WCfDϞԣedlTLowg|CzzUm*J]C~̧/+ v:n8n\qg1uJ;?.{B,&zf^2K!N Wd^z?J8@bv13Y–?N^\;$DV5ՋI%YJ%L@m{O< 񉹷x$FO}SagI6v;7BaX:KƔI%+K q CF.j5/)3zro]UGUg;}*1Y2D'B M?ۮ̒^Gڹ~qo2"wiH]ջ۾_=Z5*Wwj^rh^"4ʊ"n EjZ [}ZgD1%{e"(":+awQ⛒8$ "ui@D~Eˣ s a}w'-?4^271nk(nt$FݵPL]ڕ<d.ʦNm +1$H8ɕO:6vT`_z/ƚQO=yN">GJrmgrAs:cQqWkmR&/&=54AtgKNb-xң/#B~e/X#^ĞV _u8|MKRcj',*!RE;m~n\Yy٬Nv_)k\/ Pt kh^.ˇJIG.WuDgl_42'Krۄ9^([(BsՔr!"\NKKA7c:xd]UKzQĄ7H>?:{Il~NZҸ:%bbЖTwvzCn[Fy`Gs[6g)?F<ﳭc\%%p}ۢmOCBD4t껺vց;P:PϽIcINsC߆{$o<(]aIsTEHHow ֌ Kž.#<,ԙRrN˳l4V3MAL,6/U|w3ԍ![T{]9(|ش}-ILѰy(4mߊ xDl,&o۹i#L:DL㯐xe~X-4u 3xߪʨnʨAq޻&+YlkBWWx>jt;Zy rdhrÙ0'I45on6UgM3L`¬c.d[#U7tֵ.ILtIC~񎐷kՅh:nrQ_ a<bg[r*{vofqdsIGuJ0ms`M!g7<m"ED{pWn#~N|ԧӃ^R0Ȓj PȽvIc`ҽY-+Pr=jцS1|dvqc~-W*4O>=+xUgP\wPv?wI ۓi,'Z<];0U[`Z\%e^ iWA%vܨB M=*e?EEU#DV~IKђR `|yJY͕F )!J`[E* Y@,/ghaOZt/r~#6.Lٚ7.XeCjRV*BH)>͕ʭ^ qvi1>/o؈*cٔI9+ʌo >CoJ-|ٍ=D;LS̫1>#QOaeD*$L/nA-V'f@& f J ٲ̣D.܏ޯac[,6ΙE>Ƭǹն)z^D|kv^Aފ0E#ܫfÊ0+r UDGRBLjJQ=4N7":L\W[*PgeT?{T8"+u {19X}s^ͣ~In^~LOtVť w.Y Iꮌy LqGѿ@`-ۥt+ ϫS3E%U&=C^_Hf"(!9o-&pZ y!S9Z6U{$뿆n\YY_ *ȆyT`5gQ6TgjmG@6]YGO}^S|2WώQC6 ^&{sG~^:YF4Oh{M5 礖O o 8_|:A>jRl0DkyچL6R'ޙXtCDbOvSԆu&Y Ҳsw9NscbS z2DqҊbE^GSͅ ~z `anDYxnjs# #鶁).hUg䬮/s#U9hfPEUw8N8Ûvl0zGцIbJw.diQAT9HVÔ+f6@1QeQk;,xy"6Q ؃aZơIwC]w d"$,)Wi~V8zsɶ-Ҙ=j%M#DpP[oE;ΣNh+2}Bpꌔp!Y]z:K$1uᩍLJD5\N ۧ4 Zp긔r5&DYSݴN饇^ӡ5"ȩy;$%+-[%rPcEl!(tu:s9B K_ϓ(4LzqN\5Gmi^n>tZ!*aKO\مjRR,d+- RX_ 2ᅘ $}v,ϯEj ~ҍ?[4ů3*T7mvy|x`װsϸezhXLZ娬$2bTGP`UB3#o#뉆a}0UnI"i؛Қq9k+c4;?"T&,)PP>&l\v!#&SȚո &Nv~׫~~4s}vYv7#T}XL)B]{Kc(Zv7Ūc2i^g_QSt7/ӆf-SntLުba$XԃS`/Yn)巺W"AMf"s0 Sh\;T&t714ͬjL J"ܫ3&om+eÎA䨂&Ƅl_Gixӯ޴)Ӧba˧qh']y grU K,K&yQ=b}`1n (_Ea&c^0IڢXJ{}l{CVZ N޴MgQh2|lM*v-K%"znknd7h4YP#΢k3>~ EIGscb6r<w4LimOh]☲؝v;q쥨,zMLٗ^γ:j{1ɸGlzqZ:^fmVvCΜ};=,5P ?(˅=0AnB4.ӱ]V^hS=@U y#de ^+ɻ2?.VT];cC(L@+kv[JYG$V/5+@μU||E9nT4a&zY dz&o7 Y*fHm='ܾ8i $ӹPqUt! "xQi9o/'6"&+Jܐμ a?ZqqeŚ9Z-tBw-H 㬹H9z{N]P'y83hq5lͼͺٳl0}U. |4J-lN n"YTZumy ے'nG>KU[ Ԋ0:D>-.h0΅3 W`Tը:w,؞/Zs Mێz!b8m%>Hgtw ==aXC 78U:kanzP˴ O\0?;gjgQ=Tӊud"/f)KS&:K.?Bi|Rt<#dU"f)\l)͢JydM/Q8Z$ e; Y2 ~~U"`27FH&3@ė! >o Q du*Chۊi'I`kҬEPXD2wSC7;n }Tu\x9k=2JT3h3`honY2K&Еqf*.׏,e X{^lhʥ|ڈA)š¸$:= Rkߟp_FBQ+rDgT-)QY‘CbqlTQVi?fXԖ'H5 'kݭryEfd}/wx U"} Q;cZmZ5ת7)W͵ڮw{ySO/TN _H .O͢İgB7Z V}HJ,iB5+0Ĩ!/dpG+YQFن08MoDjP*Ux[ [)&b}6 # Qfk}O*>nO,%&9PQyY/%{@@<@p7䪥Ǒ\JgbK)R%HL&NV!F]3o"V:ӓql0< >5glC\4#tS+S(VyքQ:s+ >>8i! 'v,_4H0|[cTʪ.s1+:=rpNhxЇ*m5U0Ȝv[p( eBN|ȝF_ bBD:iì@ q,,1p AFrK<hdb|Wz4~C]Ke `H[sINm70=k[L{T1½bUtӡ]r`F[]V6B 5rA~ 5Pޟ xp; ֱ 8 D< I!^~&?;s1٪"r*|Xag<۟gDy_ ZZ{,?N-|GcIRtktf.`Q.tn֦Oprg2t$͞񪥿b(rF`OLtFܱ7 Eҭ@Z6G #2oBfJ\xQXR2;$jO0Þ bu,=}C쎂[Z6 qEVYbZOx~Yk/?!-֨=Av3l$ pNgl:iu*k_U LR<5q2 qU؎ b=iH;'Jd1$$Qvf|:.tϨ_aSQue?]wm*tIΦS ]0f; sꩀx;hnTe6-ŀ"wKav0L3Y+e 5!Sn3D"-P[oiީ*\U )^~&8ږ z6Կ^+Y4B+(‡+6]nHlW(nzԔpHc9Fc_6Zoe·3aa(EnFRg6_r$Ow@œ{V.] ZiޛMa>ņ{K n%W9N7Q2ǩ9ƈ!xi @eI}EB UZE;lgWh0cZ@-X}0Yq9aNU+{EQXd< ~PܵIZŸV=K F{i0 K9tuUp wY"GN3Q3 Mgv[!I9+]@9D`{Ut!v`?pn _|fv=X xL Ҧ\U=ϛz( l Oq]tR[#r\kf]8ä49T9KyKܸĻb!Qݰ.}ț x37KI?fRkU{Xɡ07d>LJ+ɩZX"$[bS]( tfȚ u& %&{B(D̐@-[hQx8=N5/ gdj~_B@Wp.~ׅ}K=9H \EaVeJqA> GX-TU"#3dpKj( 2,Q0#s(d3󖷗.emr`O>ʛ8ښIঃ \9jnJGQ"ƟQgf+34+,\!C RW 0|֮9 4W~ࣔZs"*BB<כmuJ tHyd"p*D1) H2!x$J,5Y!^A~q{s8N2^דY?1H6魖 [)z^#^O}uq 虽zuzܥ^|']ΟQgX *XN$(SejEmz]*l̖BDfOdoh% 2?B'u>/؊ojTiwo#зaĘV>nY'#2e3 o H~3TD]/3Yc;D*Z4)z}}ŞXcL -vHi Mo]5+k 8E8_(F: f[,v/oW62iXH'8_T <J$ kI#3l+V(p8;o8l~e#e 0O4kFqC2{|r5&tC.Oȕ&%taƱJJD./aF(.@c1?,]&x$^,:K6t"+GzD: lxky ?_'#c~v]R.yjٛLjxGh*@}f ^@R?=m(t(0URhѐ3Vr53:-3v=?wrTMX2E>c)R{iێai{k. ~@2!SU^rD* fqc5f9㪯xd6W92 ɢs_(D]10TMH Db 0r3?8E])IUXYEIَc_oĔ\2"pړe+yˑlmyRTٝGO'Z}*yVHU aqprͧ3?׌D {dVt@oLS)o); V 70diq9ypj*P"ʦ=0fz&M1c_ /=XmPE(A VI1L 9hcƄs=zXxKج G+`0F )<tXcջ$ F*P]*#]Z1%r0̅a> 1-/ F;2ÜuW:qÞ>o 4Q/3Ji[.aGy~TN @塤, ״< Jrg>`~ }xum$s)(xkq@VeXsΏxAm׵Po826RE%2?UXDS݇n߀ }(eA'vQ6(=ܳb2L+OƮ/+X ҩ23x]ѧSz.^K?^U)$O6=eh@ 0JTz(xǝ ۵Y˸rBF'bbIL_ۚRf 7Cg+.ۙꄁ 5dd*:IDϖSK"4@hp;H +y7͇$!;N\-UvT45)O/+Y>'\6ߞ5 ^w C _ msHϹ!DEmc|W,(낏HsXLjSJ%С&?T78Lbw|U7i*Q{6*`/,dXqsv{p& SUXN5BgorxgBvO (b!#k ]5)Kq4S]U=#PyӠcPyl2 Apv)5? ImrUO&|\щ@xlIh[M&55wG'&a< UsQּ^]cSeMwc zNxż`cIĐ >i|{OjA܀{G8_k^TM8hie[Ͳ}]*E9bDHLy]>-^['[Xt*~Sb|! eW19ƛ}ȅrA[؁D*q K]a:j%+ȣbsٷu>tV=r 1z#݅eIAS3hszdë#Oju)v$QT#4d{(=@OW/ز aS5h!9{%XiFߺ`&wGȆ>L{}|Q1V#AہL^FIxS| ٘$6*B"7*XA:$LXߪ ƿe0, HMw*`"๒Ggd tyg \H2,]9} e^8ՇE,4K(V- 97p.w ~13xV?v'$vOf珝EfGVPWS;~a``L&'f ^iTV{O\ns %UmꩲΊKNc΂rr GC6 ~!}h^޾l~sIύ’-6 RX)89rt ~tB~l/l>wJ- h/.]`- r=CSSk9!tTr~iT\k {DFPwL?9l YE;jA۞BkQM:מ!.-5@s|3[~Eo'Y>!^&ˑ Ȯ:'ZR4qp0e;_K.5WHH[lOͽP.ϟe:H3 R$N-.%cE)KLM`Z57`nuLnkuPH["wGҨUm|AJ?A2Zd?x0ˆFsV1v挥ra01ZEY"ϓmyG"}8Dq\ِʉϓZMj4S`-a8z-k>{EYe*8\I6&ɛu6^5jk+@d(M% ˠGc4Zs1?NF,#|kLU9͐5e*ʛ`N╩‹^}v}6:^Ѻq z -[lMȺ*c}^mW@vEGZ#NYhE Z lO7@"J)nAJ.g@$J9ߖ٩6- ˬE uȔK[r; 46GPw[|2kW29C*:w=Yq5hU@cر[V< U.V[pŲ"@w̹]X݃'=T%ťTJ>4olk,.z zSԥ9"n4? gg,SCw2ۼ:vt? *\Jϧ^r\iTlJ1x_<^D2c>f\GdA$va8#nrus,G@ʖS=6إxDlZ(of+CaϿᄚ=ɘ4F::aì[Z%&e=bLʥﲲ-c4~1s Q ~|lRCRcf ,1af>\͋ Qpx2X(bj:6 O-%6;?. {Dy5 S ?!&-1ҭHh"N5a9X] 058=!P Qlgna87KGqT0##^ Y0wN!SG[r7d-U= .w>-q!acb7oGjzsBjњZf"VlY6gת8:TpjÈ@ qbq:bsڼ 2]>r~eC@ 6tWQ";R5EXEe^Uv / *gΛ^djqպ]6fy" &LKRH=\GrB=3CV{/kFXnhϰk;tXi 9f1_q̢ JdDJa,f|GG% h|Om03X 2za$ g|;k%R`Ŷo@ 2"5!2ժ.9K_oa:QYҠ=됝daR=V%ny} 0f\ pVzpΨnltݳX[2lm-E>9ӄ&MϮ BkhAͥ^j\W3csӱV]Q>_ꍜ).bR.(0uQv#9w'oBs<)CD:l_ghVUSNeK=yK^{JdQ9:d,@@zҥO;"vJ?E m =qLI[{'<gT5ie03VVC=V=Xp$hcV]{f i$CnaUZyX#l!5nf߈%8&R^knE!D!<ެiqhO٨-ɡ l:5' P {v%K+` Gr}+ ZGs*5Ȣ?T=',Io` c:6MŵߌCw!b19IFU<ބ>o}Uu(M yY4~"\ c!<_Lm@fqaM}N*Z^sqXl30; 0y3ުZe*eN=KdW7non[iܮ J>V'pb'ZM[^znu.քcפ4zʚ r4rcLc0%>f\D(pqݤzsg9 :ؙ'X̬}G'kD"@zb%n :;ԩ?ُ,X/~9?v#LmyDwʩN=uOa# a7 L6F1 I_T DR~12}U܋K 2m| @֟ދ? $U͑Nh-ޫVI{nhW|ћ1 $y~-/H 8!dꬁmD'H8IZ=FbG F2 ||Tf*un׺CJRٻ0U&n4xgVptDC.Rjv2 {%{8D60iSъ1z#P5ACez0:lWjSxt(X`75(h"y0->ːxxK#{#׶}Z??+(VLb6?P&0RugFܳ1j;tLltDXrKe0 scy˜rJJA^qX։?P5eC%_ȦfSXHMbXNDvڪU>ETVSa~z^6^Å0!ѣOgv ζrnyY,JkCXFUay_|ci@!7$#.S0N4w'dj@3y OPC9@v* B(PIbzXKɇkJsH6M$2|,IۖBuSW(k4^ n3S Ͱdr%f,hńW4T I7.(ύNf!!C9듍AZ̓g'?U˶+V~ooS_pSdn= K̺r2:oluCu"as>t=Q{J}[ #ɀw#5ݜ7-zg膁$A,NmM<}ѡy&ؼ&,.w) l6|+&9R jუ6O mq_bb/7zavO1(ثFc@=qt _{C?iNgRul0`zyެwPi3*Z,[(3q^u3aB.|j 1|3RJ[igء~4k.@(,Foe?>1κn̩zeN#)2>f4D\p FQ)Gsl ^ʺ7SOҳ[g< Vu&@gpne3wHP\L\.{ˎF.K8 ޕsN41K X%StuU[VIwB-fAV.}EJw//OEG#0ŕOq:ӒcTj2m=|˭q΂1;kJU-vEB\i (2*Ē_{? i,],$ 6Y*WYȇc|6j[OԢB@/*(l~s=AR8SQ٬bF=Ūϝ9FbZO6gdGڇ&=L^I"YƹEi730Fm+A+'BJ U>FJ~W;0 _)ZDmqj~.`>-5#s1vn Z =c?ߔ7uJjUk\'A`daJb1^ > 8~ZBXۊGǮOTY4r50Rbw<:䡸Sd#vm:Xv.X܎7Y1ca?`Dd<'G][q虗 V)|4d]'jlB_ߴ@ ƶ3: Ș'ѣ>V3\Q#kVc5*g?UPfq0_GeϚ]FXqsWO:f039vxaL^G!Ёp~ְBU9c';=AKp>-*kaoS^ɍxHOaIXrms!_)gx' Xi۾c y\́{Vrȣs/H+?!;jkd ~;-a/sխߵq Ĭ? )ݻD@=4 n:iY61j]}Yås;AK䜥Iéܳ;%>$>S,kfюvvio+s7WV q41:d+ ˉv.|(*-bf+r`vf 1sCe OўR=X6֟IY~T4 Oբ&mױuPYkٞ$䓵kӹg.%)~VF|Zvt TUb bmC m7R!4(J@^Th#?k]1 zہiEXɣV RSdFψ`c:>Uݘll(+7-զӀA °x^+5pk)V.0~1AM3/bg:/"<'@V=rL2&$惐\+S/_RbcCjӑ6EYKzXZ 2x.2щ֧:_|9˒qbi݌If'B5H^n%q9(Uwzd(Ga,Ց/.W@ai;+it,|>LK@94 DpEޡe B[w>d\nl-W[fS rAF2l[Y^Wgl(֨MB[|)o]M "RʞxVV\– i@/حYުVrGnN  wX(5Uk`UtlXOayyk_Y<j6 $뇮) V^l aU[j=IoMOpөvY µ^ܽ.󎑷D3{s+גZTS57j=i,q+( JՈn5Z"=):j&Mڦ\ O3i^}(Ɏ>xs%Mq&n^ ups]SZ.Nɮyh;Ղ[|Yjg.(@!u-(ʿ5q^Q)]7ޖeTNH:(7S$#4!9?[/ĀR8%9 i gEyOoϊKӄ^iOU)r \ݙ0k[l8ٲ)Ny*Z5P zy][O ΰt! ЌRMIcg\ UJ\@#fexPRm$mzѹY(KڊuGEBMQا/%I-Q_˴ Lv>ٰGDu?E.@ZF01LdS %Q*&૘yKQ/XێW'^RLT|j#?2U$7<u ۻ ys ͼW Z8$ɏVjg [4 PԠf^ [nwl(!1Do۠ K0q;r㩋s¯7yc/$D$*YI4,'&]^5ծH:rɸzR L+9X/aǿ_-U9RiXW)L p1uafH6\P89Ti$;t;s5R%p9\i*8p84F̂ К^G⑿hS'0 bz3" Ҏ'~ @ِLO6zqOD&Ü]&IMYNpxS0$+$ /ܩA4Aυ:yKY]ρZ'qrNt.ÍsU~1'gMJO$31 3{.I*o%)F߀2@3gOcHIA$.D||37nrN82RWId  sk\>HҦ2YM*DľRӊBOb"Il_˰%^U]/ݽ44G#Td P7EGi4"y!6<[s)l%b8]57Gݹ<Nn"&ZHpNH s7\J.2c 727#ͯ02`#[ӊ[@Nr H=о$͙ظ@ 63Lά,Z}v$T@J"dm[znmo;V@$ M e^{Ʈ=?.l>؃66h_[.d%T aILllE'۰{߲N̝4^Ytn+79zqձd|Ůrw8 /4\†t#oGRP麡zXJǾ׏e9PvTuHgz{N<#O0Fk^Gc԰e 3x"+:qHƚ'"EZWð[oa r7>c:<{hpfAݗiK3[d[ {.~υ/KJK )_1:\.Λpd嘖,ܟۓ-\|сITbsqh2w ;\[Ac:GS< ]'Vq2bՉ3UޑbGX&؃iz@"9S9m^<3 VŰ og}R2$wS)ԹrԼdRdoA{ԽqF=}H1m&EQ> .1x%"U}-urVwmƆ:/ּy(nލM [.b< k{Akɼ.}r>y198|x"0(mFWKubxG J4s?kxZ~0&F>^'}QICXgf Y2aĮM<T9 3ϏCm+)Ec~?gPD:huuv 81݀)")hWF`9f+ |oK |27tGZ1M&X0kY%c&;jyzo# m1egs!e9?‚*?p+QƷ-/H |BS>c!lF ,k㞧ѧKԞ2#Qb ZAACLG(%ƅB7.h.?σcT29IB6DfL͓o tyu*eka> h lgO(У i2Pcq;Dﰯ3 fz5WU L8[xp|YwO*_ AjX>2,r+ctyrGw*D&D__Pn;2Dm'vuc3˰,2+ kr-V'q^C7ҫ\гGk{G۰"BŬY0i@rp6hGc毋r&*9+)AzLrƕ}JbⵅҰ[xA"!+f6*ݮJT~w0NW+sЌUDBTͲ_%D*ǯy˒nɫ[L" gX%P[s u'f$?1U`A~ \ ,撥Z%0cp,h>_M\XT ]pͨ)l~"T,l/TD%Cex v0P4sZXЍg2, #nKOrf7۷yZ[O8 7Qϟjz QFuc抷@Jt.{֫I% kqt¤ JST:mjнYa8^{yEJȢOŮF$nxH#,CTϞ-W'I3 gmqnLpn̎nrG ޲qm$OXL!PZ/[UAX !0{&iƁD"7JS1xJAm:ZR*#d\Ͷ{rgv+;u`U7?)8m}̘%v5s68NO&+lHY\fVFlGzZ(HO| /S)aR\P8i,F6 }/JZc֑#阁j kЖeV!ȶ*'G״㉝=]!WpU P [LUiϫ2"EXk88҅bv$oʇ!*-䯁?il͉66lN1DS`7L`u r4ż$hlX9lM9˲c1ᖪ)u߇ `iS4!ZW[?uTR[$_+)O6П7")B>Dh NxVd,M&1L榁l-{/łϣXk.GʾEu2 ~)mZ2ݚd̿O {k^ D~(+QQ@w|{J7IE=3 ]*; %_ɰ?Qg)~x -/X7ⷫG<!Y 5xJzy#DLɟ2H܂G~,uTYc {PH,=~ۥZs (j~uo}p!HзrcF(SFF3AbSJEèa@ojeɋasQf{Aed,Y|4~ a>A1jt)qnN0贱ʵOꇴI6rhJcۇN=`ꠙ S{'"fl`{Dg+s* {\s BH͐Dit|"Y$1S{}bnR[ O2ۆeE*+6 85yq9Z;>r|G9)f$'\%f#Uӣp J3βiҁGGW W{P&}'TaȆn;] mN۱%FއricYAĞ1D_iAU/^9'Hu]JKAm1B@+Ds滢EnWq"dg\u2Ih:DdǪr̼H<YA~ynnx롼BFUmA&jD->?aL.HMAiH,+zIHә _r`rȜ_`\%2.Ec@`աX.#S`I?w+}䎤(SN 6gOŶK3a[3H#ܨ =a>{ϪLT-ky,rB# HD]dY^f_tc9SjZֱO'㾻Fc/9e }݂_x6D|I! stǮa}Z'1T>#YwdfkYղV{ZB)F{\HX3Tq%r柦LYΑjbUCֺƍRp_DPN'ZrpAÊfI@67k5 [usqwwlXe6أ.X+|m%y Hm^%gnc* ^5 As#4E'\c=gu`8椐7D`k@v:^1S(=C[L@@Y K{vd9wV гz6'mpKJ9 >VdWn!:Qrb2Z@<;/ߛ~}1zfYIR411Bh*.E;b5%m.e6DXRq )/ AwkFd17)\'"cHr0'1&pl meit`6ǘciǠ ψq&K콧``V2pW(\^m~-wQX*&bc󰡂lg;eHKp콜5(л{zq-*!(GiYb6t\` 3#qjS_Tz%y`ˣm,hJL~ #a;zHmԓ#PiO1z8[$DQ3rX5D,h}84")"žUWC YEx]枬L'EḦm?!'Y />5oohR^^!Zۖ1^pEmErV]wʀ(iJ#Fʾ q*D;UX Λ|˞Irii,B od\Qy^.:ǥЊ)3*D65Tc1UxۭB*4bnU0)vK7l= &6t]}>N?W̮fؕJGp[8o0r" 7 oP!Q,6G-mT} @O.xo㶛J,9GVMbD[ 1&*0( ;@$pg$$]$b)~++0Zt<_- !ϕ$pfgA#]`'YÕ%2}=Wp~ʳӤg,gC~{J3_ 4HêcGvͻ 2ZdBnHȆ_G0 ,d+,71 @`VV(^+`SQa0r ٹu2H+<3Vv8 F>aI @!s2%Ií3 #27׹y"6N`T_w@\? 2[T|n5ĀzRy>glp(#zd,U $N| .MAp6QͳTՁ;6'O7[ tB#/5KP*nG(s$ha,D8\X!^zpɲzy0̆CU v:dYLs('׶l 91 _54"`Z="qaMaܿb 8oHޣ)`ys*݊t3fjHn o0+$0fH*w:qx;kpenkNA 2EuX!w$xIwU&.ie)iUkɫ+P]1^yL54fqfu`1"$v 0oce6Svwe(UoN^_6`MEhr~}y~{#c!ͭKWuָZT|J.er ȚdB@jLl3w3Xbʣrs^rׂ5US^hlXQQJHn݇ƈEV^4:?X;StNށC;Bm}8U"pЯT!D>[/sju_ZrCg`2&~ JG|RR(QK.7500@HԥAj:mdW=5ErGnwC?|ג\LjhQBHU᮸5@kv^wJD dBOf#^y1V$$%jJ>nuZ;DfuWt`2صHw3 rZ 2Q)a&8|3^鮇 = I]7լDȸ7 }o\M#K`j\Wܷ"A6$pl@һcblPy1DN^SIjuxq?ڡڮhV!iImB =͝vtq@1.Fu26`*Zu 6͠a 𹩑Mx?(iFT=t#~I#v=6 .uˤ\xU{8j}GvXq { lw"1`\yr8G٪~)H:OkCԚt d/oU*J;=t+V[HSSP%p<\4KYfnX 8p?G CLgJfd4`ÆTQP ?%r1R ( N[-1Dntfq/RH'ۥ QB^Y&c鮣T8B# ԕFna-PP25aҚBi^%>ι5 xyiGH+E"GH.皹A]^VT=ob: Aԏ].oA 4H ;=@VUv%w;pd]0P0rʦeQ3ޙmi S붺nFEp׀Jm,s9FԪvyJ~@~bK|6c%E'E >ڦ 1>3*;N\WdŨe?ǿ)X@lp)e;e)JCLyIлp֟Oy Sۇը3쨂jSa4A;?;ȤF΅)Xܑ!n> W4l)mh) 6T%" OikKn-zm]r{2*u,>jIrT}nx?ywA[6` hǦ<㓸 #6֧Fͬə^2:H.لixS/a@0)qbWr:/-y,A e814R0Æ-OF?En6^B8 Nn45 zȋWG@xGCxirB_׭C`XiCey3*>ia1Mb|D>#BOA񟂚9 w)_/X%@0::k|[Gws|ɿ~哎z6O![@j_ c8!<|)8@2௺=+81DT@ag#aU ZmIICHEV{pO8jZ@܃?DĢab.db&ԒGf.SbbEVS& ρ!,sA0"np[]3ZJ^ϣB/mVMw\m8m'(WYAF~ʽ!fInn@-RY/I'dr(BE9}ЎȬAO7p/YZMJND#'׃ vD'Aqpa&7d< KЁjUYD,B7 Чpi\ʔGcs3 Nn+tq͇g!XsگjKw2# \M1~Yr'P";@|lQ+pÞt fz&U]}nE$jp^R:L$Qsl?4tནepAtMZnIvS^E 0^hTX;l9܊!:C'Mb%q*Τ|Cѐ]Ӳ7f :O{#SeKBuYڎ!$O3m)dTmQc8`ĠϘš0ϲB*?@4M`^T~y"׽2A1&f$gٚGbGc5Ҳ䯠s) vhˣJ75-w Vy9#5ǩ!LL6 U[߫`44'i.|sjr RnEHe( 9xx[uJNwIPnt( 4[(*I"HPDL I"G3l[f04.݌vO(VL^JI}+b~2/}&]u8d?bT#d^12Yzg{* vc^yv򠰕C\ dF%cl,_b.OƆMI֋@g%uSg4aPby;?$fE5t܄TXpDWcIYQ71`]粅'l+vf,%|Z?5BQj^Qq jJw9a8Rl3i,a+Opm@1ASS_$JVC 4n-rA";u{3I” u?I,#!n\)WzgJtٖw;'<'m0< \ܬ |NW(Xat-5ߟhCf嫇B:c.7mBdO;9dx결0eg9q~U^b(.tQd1L=y}w.KƗB.cñ@ƱOpɏ%^4PȨkbG1,%r4rV%)_俒򙝩Ǟx ؛ ;&UI̲aK -1Wt4aGdukK $c Z tw !7,P]})̨3:#ɖUo\{dU@.uTCх.G<ˑ{bhuSmA-G'_YKk`rfm UX04>fs`qPa$wٻ"7U;_yoZ|"ߘi eRMJfΓZ(tp B< =|~@rm^ĩ+9K(cf@*fϾ]zO5]-a熡m|tE0G[S4dz_#}S䳯ǍzXE|۷_╺g:}5w`ݸ\s'440'6&*g/MM92e^>*/Y_6m@WckjѺ9_:_$~ _f 9h '\nY`\~]@z颤G)cm>v*'|I*=Lnÿ,|0) ^2v$.䌐NON=;I>"钫v'PtlԳsV~ѕ!0Z j<={BAV-i J׸>cC![ ){|;]RtWC煺sg)(ITOK*,]Yr♅8Z-4շʅ`=_ =v1dc<r>G>a`̎;Yb6 Oп˱s|8^y.j=z{vIRiqaAFܚ8z$z tW~_Ƹ'1Z8t_uqYj6fL]\ӳο?΂<;q7j5'=ocDC5S1H)[NZ$ f8H e1sxx-{"~-~;SL#)ָ/cR:8C:..^5lb_O~pM*,pOuTXC YcԡJCA?1/zWʭTC5`Baڑq\, g*6/lLj#-!be)fl"հ.Ct>2$KnD8K gD_yFpC )/7֊d^4qސˆdt$=Z6@6( &Z..jyfl'.ֹ6t6páh_w\?50=ӗ&{j%Q̛Adl LTzh+TQ?A@ `YVC?C#v^y^hv?*_E. Y HGFgɣGe|9K#JުH4[i oWGF,8VPy{
    6|V;0 *P=s> "&k"p30@5 sAE~e.c"C~!`bRj8Զ\¬5'XCW&WY_tUF ,Z,i'Kytg ,ig͉+uJT~5։>SthVJ13!cv0:FE%m:(+i5Q94ĜsX06}>VZjLBDPe?*؎S=8>_]1Zpn$KlEqJL,_?1T!tsϿٮ q4 N^kX B\_NC:&*7<ُleL=^QH\DUUN͒TՆZ3l:N{GQԐdHmPPX= Ў.@N{:)`96MM t-ՈP5Kr qm˰N)2DF'avs> 2Q:h֢R?ƹ"Bظ#Qؔ'ōݗ idI$Xic'4E0oQ9n܂Gf*n\6.+ϰtS(y*MUn|OE&R2@Ϝ9\5>o˝_/*S# {uZr@̥m?A{8 #]F,W|$2#7 #k7Ir@Z%4::ܥ7cE;DUOhbۢHngԒPqZʭ xºyw%$hoK(x 7 M:poʠmDN}fV؀|l.!lom+,9 T²4eDw e1؟4&pI} c_h6?bژ$MUJʒu(|  TL.c.Il=3dw.9c8fCyE&\ izJE>ʄyG 1&.xbDn-ilp!Ƶr;mwuS$lV]4ӣ(FM.fs%!E`\6%MtT- wMQիh#u8]>P?yP6y%^uP*F!eM_/.FeA- .}YqjAHzVc!nt{~·8f*q/?v*`+ )4q<{UǤdD32^JTH0%:3Ĉ lpx =Xp.YN?<)=?c5j sµūLyIM~sLu0$[:9&P=Xb9L:A0T) &m%o\]Ь(air] ~%-ϸ㫄W:FM ~ۢZ5GVh+xmrGū )6 Ԧ!.`5(.,Cp }U̗Ye);yFh`**5O Q*VѬLydjܢF%`{J7wK`xbp@``}<7[WAPlJ |0z/xIAve֧t&ש-bŰq14)p e}ڷmsJ[3ce{-CT7״A |I%v#@rۄQ|xԬ`tZ֚X=q636$'|"č|51.knZ%uɰCb^'(ZiN9ܫWUs$PiqEzk׼x|7m/Qd O}. ^ZxJngZ4o6Ɇf[A⨝KdCg,m0lǘ⬏`F 7_~,sEN Ȋt'ZpQ1pBW뾾|'xQ.-D=,P+nSbVk]tt+vҰ!O^Ro6uUT )ic# WȊ^g>;8EH- ,vy)~`A6qkIUڳUFY2a2"29кU F]umuJ8+j|(W C4$0jMQb>2ՍQAYM{轥wÐ匎:&ƾP@aaL4o$w 5GqןgKk}ۺ̻luA~rF5jٯx@ꬨvCA3ډ{ziaL)+~T9j HoQ|/8v<ʴsލt 3Zsf/~ʱ6ź02Leb sB%\\k:ǔ"aN;kt5UZs%RD x}d,v69J-%b MR(ӾiRK`Gp-9:'ҁϤ⤕Wo }=Vy@쐳90ܬOڜ`m,7~~!h޹/Z"BVs#"#rxNJʎ]#e"Y5ۿd&7^>F^Y 1/F &b38ͨ8`0f%;zWdւr7XFMy/c\-ϳ!C5/FlJwx> Ja#q[[[ 1΂%p?|r5%Q|8C"/ZQ}?*MLWV<^`p2F0H$;Ղ/2<;~EO4eђ>2iůzd^X DnpA@=4cpr3bDa&E G;&G{ؙ,=J @tG8_,]M7iN:.w*< 4-(ݐmR4*iUo ^3KȠO~bG~X! S*TtBy~hY]WZzyI^{.Ga%%x%EzLm+;G)ޛNנ wY0-Wi~җ#s_ۍA'lTh8vl1ܣ>w\PHWMhHG8+ > )WE%6o5M0X]L۰Ћ*uC A g~zo1Y,:ME$ld+ƨ c|_9}*ӈؓL [zOSp: q%mݺr b?b8KAq[?sNYk_]Tb|>jq×je\z}eOI![+&TtdQ&AzFi-Z'VrI Pbߌt͕`Aķ6kyJ NWɜy쑎-8rh[Z-++bU#ysSHD.}lX+ x?2n=ۍR;RqSCfSXcRͨP@dHgR&XΠ^vʠ]EIn"{3施zQad\rLx HV9۸,nxEr O-F/Cw6i4]'u)N^6IK^&OHoHj'[ O" 9b~/ V\~zgs-rg8V/V)k pj9پ\ *A::fzqJ)B)EΖ|@@-?Mvlwlx~A dRa}V5 s*Zz^`||Gг}>6W!xjmn7"UbC<\󮢡u%^z M;!/AF$ z3>8 T٧oNaLy+j Af2FQ=rba0mZ:Y_YxQ1:z8R\(QhC2َzjd+0 bثwVzwxEnGT7Ҽ"uCrH0Uw-~",Xe"F4L !]I|KU"cpסil44⦲Ǩ5%|ĚqԘ:4^r `V+!Pb @L^Nn+{\xȏq>YhQgV0/5.Y|e!uF_ͺՅ=^rda  E4T_dG\܎+o[$͊&Z .dSL_$W?L=={Y)Ȗ .@=lkj?G}&g("%rcHWvl$%3cbuэq?nղkބ 4/֤^  E~[4_l\aLtY^+' Dyxe>ǃ6LN'=M4;:ů; kYw~$5H4}'SQ iЂյiܾ ҧ`(҂.̇9#㴔J4in1#VlHw  וEek0c+6 `^R(^Laeg˟kOe.kH!`*tRnM+ K^'SG0#m^LըMQ7sZ6?yD>VƇ$u1YB ]u`2Yqʩm]!st$ʩ) BImF![r DAڎFl#{g AS{|ρWزw݅緥I*9_fBJ9Sqazr{>f/) IVS׺`6= %=4nr._o2 ɴ2|ghM'am" #86a%Yxlq:Y 9+{`ڸK4G[pH{ʵPlʓq+p$ᬮ10߿%ku-lU3紷Z.14ε-K [miuEYfY1܅>4ӊ*X?lq@Md[Iq_'l&o%_!5BB׈bs/(1- z8@+xIC46 y̬O?٬rAӠ?|uUf )#nQALҰBEѱIŜk*l}+r"\oTAV1U+^X+4 qR],%e)YJl5ܗK/ˇV[KZ `PWqܘBοvq]'Qgvk{tҙa,`tg1Mv+Q:v-z=RIƟ=_9(MZFX,vYmݪk_ŏ*MzU䶩kKgpZJ հ˭}rIA-ϠvkS];7@ZxǞZ@B:*)%BvWYRKb]^Ze  vkZHmls<Hkv,VaLo Cߓ=E1 >KWWkAnX*yeBcoܳ,6o5åE>:h_6`"+v> HBWyW,HȺ T«T dү:`*w H^J23EJ&N#/FYc}"ݧUWmC`SvxqA k3t3mV!o NJ}!ue؂68)A~vO)sjJlh^y3K/õ2%.z4"  ;0X,ٱ"d? M4 12P)]=d>9@Ytn /u5P Q=9?1V:YCa>PF*Lda;w@M1Mh>ׅG*ftkYNjUa1oն_ y#ᰴ}5t`C՘EY4䶣:(i?]X@Pw$ݏsYH`e_]􇊡E= vv0i m c-|axWy<_pmDS e\*(Q2{9,,JĜf`39fƃi)-<)4<,8a߄hY>"L zӅ 1 3nB^IʨDA3q,dz }>X8A>_2$>ۻ$U'FC=U*Ma]sKNfbsV[Q5 WoyS =Sd|xt[Z| 0š C2;Uˡ|lЀKb8J;BzBVm:"FlLZs-:tԦ)'br5ijwR@ri!3-_Eɸ`X~9Z71%qk®kFrqk<WH3tQBPG׳EGYlN+Wdr3#KaYoH{Q{`n qTi01ڽܚQxf!$-'WC@ )L;[=nFky7g`47$#aI{/d]u Oa{ %oUӴ|HV~-=7/Y]V?-=z~ RϝBVaJ@}@dpO񵻎]]JIȄ,=,7tggٍjTU:P/{!2Q+e-K?&AJ[< '$a=m[OoÀ}mTvLW2(~ FsHq&d ?'s'K[$AGz)@yyD`R^:n2 )^ռ}?wawˢ)}URїGvC[:сdA\ rjO_wuõ (G9%jb%Aݗ-I#Q\ho[:q#Obͷt5KR, BQ&)]u(.!q-9Cӳ/ۘ ΋Uw&!P6SFY>3? $^"NSdRWncpz$x7O:3Yv|_QHc] Y]ղy-{ǂh#ZJ:i_?F<0܄&]z,$Di0d[`qņcyZe7HSJ7T)Pu?,kU^J3ҥnG6-8]䱯H+uoC/O$)8Rwǩ,5?˼#~=C~X\ XcNtj#^{,tk\H MI^}VHfظS]1|>ւNpdtddBd&IƫD7udpai3)mw5Wj6zo;^^afBb6*Qp=Q9㞅l QC<ʈGaV?n5 @ܦvw)~1 )E>x ,"Dc$Id+_9hؤ(+4z_0ebW`*8s<\8&ߝ%|@u{Q@$<{ݝ&lo~lur&C _<v?)o/1t NZqM CUz1I(SVEHcAfc"HQkAծtIR6Ca  aMn.@7ȯpFN꼆Ukb܅s3Н9+qe_5u$ waH;XtH+.=Ol#. |NNG<΁u=5;Ej͹.u{Ve (Ȁ"Vs"fz-܁ӹgw_2Y- ; Bzg04"^aE:V!ӣL!} IrOư|Z\rG8jޞ?ҏW*9M襦אOV$hƯ쓹4YSS5Q3q{=A)][a ʹ.\;)Ń:U*Į9OjA=+SL)he2*Cq<l1?NnzAKl*֤ 9ӊ\b; Jh,QlY(4Qt)i0-{H_70jE|1lx[ 0'n3SChE eٲPyq/>2gZ=\k,RpT.?7sis{fO6IX7%4"ӟaW{}M)4,N0ȇprW s*јtiFuCn{@M e*#`l'>" Sn(kBy3lW Cm[oIc ԭpy2<3Ŋbe!|.e) ;ڎ!`"â{|cKk%ÿ5Hk}HHnN#7WKrAͥ*V~úb1äD4^HbfY1%;Fn$+6]2/wsx?~^.("ݎ4ɲd.6ֲzsSB unbUt(3/P}`C0G)eN%|W_b+~Vfesk/GF5ʺ9noA衡]M,%I} Γ7Yu)µƩWǘ5~MJGBd*M,E|ʨmm\w;1*Mu%~Ko᪋![.3Wku`֞ ^evp r:P)P)Y&xIzwH\cWVDoSH(Ц˄?0+c)bu0Yb-%"ɨp6j)jsݳрm).q|gureV<-b& q =4Qd}Χ;7hCU{ P*Ud$Ǿa_؆j VwL2")ᮀ(_fl1Ja=R&*n>Im+Z(IH<2e@%#{!,++NKgՋi u<(fsM2#H뢤~4HcD$5*-,J\ OJaNf`@%H?B\'b4YvvQa9;Rr<#źoǮn{QѬu/~uyb28T}iz[Vy؊<6c+DqDFow e _EyT͊)| 3`Cֺ"[K5l4<^@/&<霊2Gu$)Be[W_?]AC?N1a?sGe"i]߶lI]7%?H̫FFYaW 6Try o&FrٝrղXq6n.dQkuJ%XкN !=߼_净iÕw2f|L> OXසjdAJ1#r|rW:t-ެkn*#xToQb}DS'@LXN#sPd 4Ѐey'eAa 4fQ*nU%i|E3\L^?/ƘrԌYkDve~x]mNADkaBEyI}" Ywhqj!) ܸm϶;42%c?GC)xh.kt{@/(W?F]$7*.g7+PDjouf /.46yR@k +-0{O ;`Jh-Cеwz "['%}J變]> X!"4%ݒxxݶ?bJd/nCC;{o"B=vO7Y[$d*MB+}! 'R[5SZ>`QW1t+.ۊp v)V35/)"[ƪזq btڒZ eF6nu/U+Ge^iHDcA!-k&=@ꄑ%N^}miͅp&иwoC]{ue;9m!rg"tj(ylP+?Y2PJRE2xKo|~{~Ŷ~Ξ_16i#;~]NT5!n ( I’#_@xцS OO_Y{pG?GbU1}Z_of"u+v= X3 )fhh< sL+PyU ]2h1F"m+T+?)S+O2OoI<Ϗ<ƚ6.r${mIC3#Nc϶) Ny"֜INP;7P9J^;Z 6)(|/И Z}ۏ|(߈Tq k-1KxVR|E(%遴  r~VT`jGv! ,,s#;5I+yx(Oڕ܌cDHk+%\>;语T䮗k1s7 ]G7ElHV|°H80F|Q5B]*+lhI"_"]6@NJ;З4D)ꑰ&Z;8,˞hY'w7 "b0lhRg^.4?7q;vAH]Tއz=9JQ;}"l XHi;@V }EϬrZ.UqzOX[I~&7?~)=ˆfJЀ2ZrǦ>tJW̨ D&\9+3=\.qS6GaB*1Yu$%Ces΀O +]Z&H޿ *%x5 [UaZ=fW=-6yx$p,hETVYy8͎ᓼ=Ʊ?ƍ«c"]${1h-? +4gH#јU'$Qz}[5kw,KaVr!GMTzKRr<bq* fN"a2MKʄ*E1~uAdAQcj y%Gq)v>STwƃ&E9ؖڱFct_E v9kMʤb!-9!$dOzڵ{FҖZh=^1JGj^"E5s ~u ,z.m\gIAQ5n#[IQvڶӮ]*Ih/vJݵ$LHIf5T}Hx0{hDWΰ7YW{_m,Iӱc.Q3fS=Wɶ̥o y5sD6Ld<=.0#*kKh]#yh:PHU/RB 綰ȮaQeآzDqROs̽F7,L^{O! K< Y[ QB45[h0wful(I1bУQIJisFF?HFI*KHWT{DA i`1_NZ8H~3H[e'Rl=MH5/2 X&0̀:HQ1"=tHDCo~w7)?Ns"&8C {@*.usٚBFFyE<<+`+ڤ0ZUt৯.ANz*]//\!5]$ QrGu?D˼!7B{} w~&6 iF jU Y}0@!h祑GHrהxHU53Ԝ pK/,g4&8]F};{}_y}2?i޻z~l Z{2_1廟%t{A[r)/r(({ɜ+! GEqF ~0k Sw=l=#Cݪ+@Q%l -6RTt/-&_2݇+H1-5fcľ6Bpp{ߒMf:$}ծ$ X!'>˖d9/^Œ5|DWEyF ?1* aN~A @U`!ϒD:"!SMUV)+_ ;Ќlcս^!bCAON lnOmagfY9{O{Um_ Mtil 'g"ZİVh>7hcZ/)YIїtQW1?0>R_NB+oi \\~D8KhUcN=%IFPl- 3k`am|jh5h1űI:5Q\a|fsVU˨o 4Ќ hfZD5.j4y7S-@i|VF7 `KKG`FU !gXd]<gVY;@ m['H$OwYi2Fdްjq]kkR/SFv%Cxj@‡ 9i)r]㮈*GYeXb% Mo(B21mTvfxRR]N;HB'{-Pgp]< `LRJ5 ^x-JXmnX57ێ3=CӝIJ5eZa-XG^"[ʮy+]*D3.BNjkXwM luG({*v}ekc2>30 = n#ۆ΅YO,=Dz`m 9}&.\j-ZC?->\!CVy %DXva+y:)f\݀RtԪ=8x:][:S'QS yћVAp'|BcA !θ5FgG Tym?L(TjfC){rP?=*xZhn'N{%_&җ>| 4B|^{saZ@'IRnwoggC#㴑Pه/TPMv #F"Uk {ir~*n[%^e4N2Ӵ_mّ| H=L1Y3#*٘W3L:F) 8֦ ed1F!9P8=M/rܘ;?hN;7e߂]#9cYHD]6 Pqٟ4"Y};3r҃-HBH3Hmʼ[1GgI<Aׯm!۱MEZHZx@DlF){q6d7 q.2_Ux"PSZT!]jQQWA«nމ<L]"lbf6{vX*!&iZ O#0l 3WU|ᝡL 6/'!gPf8' d-d-%SDz!@7="#i(=:jk׾!?~h3%c0xc??Z a^HpYukazKc d6DggE- RJ0 sIAga7~8`L?Jkߣ`5!Yxk]@+@92ylN=$A>Tx' 3v mJudM5 #Sh5oSMWJ7G9O! z–'!X+q]h\1+b B,p~[݄k?Û rymU+{:(W4X)(~#eT&.t~8wJR3LpV51ۢ-t-=5$fu`dYN*[|g1aS Noc{o-豩gb/2_GM 1IaاFl9uwʟkwD1ג/tg'jLo)"z)= \.p(˙BF]*aI3cc = &N]Y1y=]Tz.Az=Ǣںx5ĤF .~ hԺV2Bʴہ"Bqsnw\Ba47'`Txދ|L+\}$[N=k:(QJp߷Z+;w3qb<%eD؜j;M2gFW0no x=gȼk:{.ARj56jyڌ7pe&qGPy709̻O#Mz-.bNku0:wO|hBX8(2u¶, CH~ ɒΕfѸ㮗]HlɇkkgÉq FbmF"ͽ$M0Myj$PPEFtF஍:o=WH8Mv;-1`@-F4[c#738 ظށ (J}K`iKvȡ>3eI=u.}n2d!^vdYy<[{a[ӫ|-Cb@-fC.-Q,߀7 .*wSwP;tUJP 0$$4ZБ3ž~uܹ{MlD&hb^dN#s3ev'|݂g_q.J"$_%qE^ YWOJl  TM(MԊGIiw0<@A>\k")GK&NogxR^C]?*W;W]äK# 8Z$+b 6 R2@={ҙ90"njxėsP) ʹ,[aŷ.tnD! trXUo#$t2yo{,k+K>_b2Jh])T5aR#Y)en*7E9^[cWRjOx OğKnp_bgź3KV[hG'].hGFf ׬|]MN(G!yX c>,4A>?Kx" LbR%<|cD ̫%a˳KX d0j !l]"@_:<&#^'3WoRi뮿eANx86j T1>}grDc)dʴl` {E|%^ d6i ^G tp݆jn6Y\Q3gp ҈X蘅-gz> 7芬$)mjy+[}AN}GThG>`: L#E ܊hp.p򡃶*~nXO;(Yq8(%ثdjt|¦TCGuh2h-J՜OK)A]9 jQDwud&zpeSֵL׊V^a闠O%2JdTOffYw\\[9~lu;*`9E)T AOҡx:(9Fb7IeW[0iR)gB`kԟt$Fa|AX֡<4ygPZhQ /g+-n̡?oI_-9 8#ҷ %bY_;=Ba)ӏi)UB[F;P##k2_BW2ġ(GH]W-KM]t{c&`.w휗׾]9 "TYJ4eGR|??{Rg*YwbO\ywct;5^fisV=Y|7EdY ΪCt /Zcn/g{NT Jh#O FX ccv5hjNxMYThGj ܸI5eFFk^´dp"%|8^,&Ip}w!f:փ/^ JLD1S~i;I_g l0`ko|HWsMϱrnKe,hK"feXsv@7wOtr }$ԀV E#3|TF:G#vn; [}^mS\TNT@P'aӭmm{O$&`^G5^ ?M簞jC@y2,ˎFl(9+iQ3-gt6h}l+ϫ[@~L|AV"秇-ꉠeFbM&cbx.cxy~r3V5|@^nbv7 U؜0HuJ v?bzӺhfHET= Dǀ¶z}v{+Wb%Z8C:I[r=Pj(@܂F167>N-B7SDEYɤl³V3b[%~u~='7izP"<6 [_e<2M[+, B_l2 v}!qz583e{&:Ye?7fIp¦5 meMdHwaU=u)z.M1dŌ8CF(ucZ \7]f`GU0˗R;˴kRL!|~%]G5Omv @cZnR]G|%+W{ ~`"9 Y4W2[Cs Nbڗ0h""[|ɓ2(e'6 '4HOrɘ|Bym3*Mÿ폅7"`\Wg=YqXD ]vi)v U硱T)]9VYQz@%k<^^4::egS@c2[@vy*qɓTh*կ7`ӿXٖQRp5r ظ&Uxe_(_d~XOKe#=0ǵUXlbiJV2tlg!.F#ܬu<)4RjB$*kȦI3sLHyG/a^EM`eJH)!]+v[ 5%=CڷZID\0Z C7ϮaUqi(}0>`^gt"!cq`N=Fׇy|Mp(9 Ep:-/ՋpEݝoW0y[u1[~~&'YGIv|!&2IDj8 |@NPQ^\,݃\L-ŜX`L8*-߆`@N_: Qg +W)xe] ->ePua n`00#؝@Ș2* Y**B{υ_е=B6xDhڼiZB65h(4{% $Օv>db^0Пf!(yZX5& >O'F / ./xCÊ-O.0(svkC,Lr<6!h}c +.zX gۺE'9#P_U|w"`lT>wXU=;+0C <%ͷAV$3Ta^`h˛=`'‚]B tt+v ZSCX͉GzH :YR0a`k"Ȕe8BTlIlaJP.@ʔUl=DzH]{G7ErD8;R"N .Ƌ{!T6 NDw3rٟ쪯A]vg1cY!S "N@&[xpzm,ڍ<,ϧ]:P' #DG2 ,"RH~R'?6.4kyF4Gt q(~!OGD4nNph1Rj[k}Vo]kH"INVmG^u-$&i924l¸nS% i hZ%3qYG 7^n/𣮹 mU͓Y?'#^>!'ND57<:{ĕ#;wjZHYˠ7P]>}i-?ǰoFU$L! m 餳! 8`4 {Ya?V]h0 ?I [kW,3?a^MF9*|o/<+7זCh&d<!&&R4 uțTaU)jÖ(1z̥:o(E,G~-ɸr %RqbCujCЂǛ& ϻg-I7,M,E!J叡TʘHZ{RqÐYs f@}2>cf3`PEP8Ašu *n"oߐL)ݟJb Hli6šS_t32ƒX2L'-Q[.PpY҅-(}|t>]3N}Z'Y Kn c== h@ˠz<m)\a[B({f;0hw'3@ 䎀k]WȲ&rG9HRw5[L|ensb/qFcZԫ\g> d9Ri7t,<ǯV>Ex\ao'6+{2Pͨ_us'UU?d H#h4Dv)?V/sT!: H@"9ZNT8JQh)ǧ!\zm.d G[)V)m-M .<#`WX#%ڝC?ںnl lHP1}m Mؑ;A.Nz+J%i)yN&Y'!k(мla7byn]7`;曳>T*Ua ߎ6>s?41*q6As4*C)*6.4JSv,+yN)-טc-IgpnϕW;ȔMvO1; p>BU6Vetբzme_&Z^#q^YDcFSNܶbSsZ R7YGJ3_=KơqJ Ct?3+vb."VjS wKi`T2ˡ 2e:^FT f~2yKh"p^0^`&;Ź&hfq4Z5<`Wi~d:[V6V)n4cjSeB8꽂17[΀7 XH5l Na:TRw E]#C3Z3;6t-UNt-U`K_ z(KC(<MJ4RF89K6v%K<`yƗ-xRoV KCBϞTU K'SGUfˀ* liwS4+7t]Z8ƷA 0g.V%Ph6ܼX\og @g@ʊ]}Ip՟!3A^n'\ sEMfH ,fS5o!g'Sxo&qK\!)qD^D`A1O蹫SG8鴱<=iCum+( 4^M&LaNii;sk˪DG4l0(6/5_=2b!iGtbſ2mr1@JϷ38m%YN#@}?g-w0QƖby9ǫYJV}w6ET R <٥ *Nߛls?˕LWn[ !+Ov]|ܙ/\?NQx7d}o׆k:*s_,l@ng<7dӷkqR]bSnm~@bc֜ tRԋM^S C4?w GFTio8Db>;'tAb 岗8,Tol)ؕVvΟ,}iNǗ&&3A#l]-Yf'> ()}jǼaO[xlgscєHkeM(Fxt׺ܲgHoꓼb̷בRVkbz{pΈtj?Y*˚}F`sWN^~XG]F vfn8hJx~Z0l=MkUT)wV|.Y6b}]kSf|\9")5/$ngԂIޔ( : wt lifN(8D vyy?*pp7$ӖBVk>і[;>?)"I 7# h;I}N y(KTDSsKm ҇~z&A]-eK\癝N_6NL SCs8*W܋}U ʑ?>?=J5RH9>O@aF3T4]#B y\Gx\hx|+e~&#\~MQH#q 0wv]]WQrxw /9I#"%mWoZc(;|و%) K-uf TZ@*duMο Q#+/I0Vq+;(>m#<~*޺dR\uԌ\7Rّt 9+{FFBUy)NƥtiPf$R'c.CR_5a3 =!Q.ێ?~Vº67d|Pp EyÙcUz`5i%]d I+0#_}H^/=M3F[cg $Ex[pݑg$Y%I %wcR1d($K<3D4Rzs<ҫYItLYKfuQA<$yĵȚlE4}ɖҠ"T{ ?z?^aa^M[Kj]|Hڔ=T"CP\-l@ v SK:%]S'\+j>f5KiB[#U1yG8 dj8ɀgq)*ѾɠUxv}SgOcq\VȀJ|oÓ7V_Ȼga"2(ԥԲIjuzP89 V0'Qr1_/3c;j6Mb3'33*u+WuBT#(Znxan% \$ ;I)u2Ʌ,(E/oj|9V@bƙk`Dkf&FdP 2 $C!@ G a ϙ_2s0,cݪ7S^$GsJj! /3ٖs(h* `\ӑ"]1e:3X6 kk09I\ S]a>qQ컿p!gVYa,oϋE.ԾM.6خw4$t--=},j @s2>d"qN/efH~C 3hxMfjR+C۶$X$ϓ5X;(CiFUnG3Q'Ad}-}i48& #dzkrZVՐukҢ}щZQSB,ee,N%~h?/y N#D6g=?>2ey_I9.ހw@@k}uOtFF^yܧ] $6j N՞q8fڙ a'kK 4kн0pNΊ] !=hF҅cpG9T;h H#wMwr%&-qφzs=2Kd.YGDxH la_6~LjtEH\PW̚;uP}U4~NEkJ9M=Ӂ8 A}tm eOJe4 /\8A/zzpJZHdѰz*bGP3kWOfc.F6'+OS2 bIږLv;z$P㩒v݄(@߳}gVBJ@5ܳf}jXOeJx-6 ,eqOB@I >yi()g0+(넬E>xmKz8ɫz͏, Γ!#<ֱ0@~ٹϸw eX'WS-fFS4ӂ8ѧ'qe'LV4ŝKFMˉo08ہ*|(yXs*޺hIq|ak㱋tJ&l6^wW͒5AbUGm$)@gdADlzz2e9)z7q*va Jv͚\CWo>}Wes ̲w48[~B{lp `,sQܕI<4'0صyc8٩ɏzA̛zT}d)/^¦ $aFo1J  l5[Կ I"-! ھ DrP)IUsl:pLI^+ Q%eZ!KB ϩC;Em1 X.տ'ZH#N}J%kƔ 0cacނO+;?>3hW.ܕBNЈT9-wcP:U~>0I)>VZÀLf4^n#嵘YeW("~.˺'M 7į25S7;oԩoeڱFAz/GߟDթ(#H̚^;Be?`d{MI7[ k4`+ f=CZ WL0K*ܞgOD&#QgJ}8w0ڇd AREWl$(K (I͠ڥjL1xQ HZ9KPM/-7J:7Hc%$ʬ:MTdP^dm._U3")l0Wwr+uE 4b ,oiRH۝=$ٲŞ@_-<hւLˮTvHh3<Ḭrqf'7&N+ @oܧ@цG>3a|Ҟ+|se_K.ݱe:2L>]u!v8S qBAu::jOފ6σG@fQ\LfWLLSe4 lo>_F@Z =V 'qֹV̻6)Ta.63ȂJAk()aGFQKO52[+z]|ljNȷtŊ!>RB)Ѫ aǹ)IsG|{ ˑݝ`]uL|VNnH)%7Bcz΀o{|bvN"s7$lĞǀQr6C 5-*'NMK,3Gc-[VREF=kK97&T=)_`=KG^ք9|0\bUO„ǻp|mT;0 ·r|ٍ,9Wc#,ye"]dJ\Qoǎ ӓGZH-|(_)\8d-pa V8ISL,vmA|CwQ2-S<JLL[l =ʴaʄkVvRtC.JMsّ mҮ|cCB EJAŃ܋@ [+;t{LvW* v֪ 7405\]㮗 L{j?J_oyW o;rQr!-="`u <]Q-ib7*iQn)fz$$ Ew1urVvv=1|;`5eVs0Ŧ T ]8UB.T%;E%'+_pqE.=tPxë]"}+ZE?lCHcfzE۩ 1x!tJ't:1k cmbYzI3KH%hc枡P bˋS9bո j 0vba>9LaAOc^w6? 6y֌荆V:dhx[M&RN)>A̡B*t9-A.^>ɉH/>+S+MR0S.;Eąh* m،,,R3s_I٭J\fLAZKEuK!ywE?{7=DyI3*T?BZ2YTuNj5]nDv57۽TZdo|29:0n_y! k7eswǿRxpN.J ؙjx^Aݥ֭3Ԩpu&hn/*0 7V?\CA8,vXmfz JIkk6 ,`#ͣLÃEHck&mwIfoоȉ|PdnincPkmR*ItuzT%;q;ݛ mZ_u3(nTxb /dW~~Q>w:▴}*߅Hv5Ed"B Xe[:ݮ!Z {eq\Q/5']>V䏂K{V99T˧+,$P߃0p܆ՠՁI^QY @>^WSwx`X]xZ;3_wP ;psGKOhb\G4]UQBܲD{Ԇl<}T֓=5(K-gt̩0i ٝSЉΚi1QwQiZh;h9).=wQadA%[AB"VP>)I\w`!΂nȈ\&fY(6W+}Z4䝑+9H*GrōN匍 ɗ%ļTp$^2 ˕%@^,;.#a ,L(҉Mp26%־ص=ufOt,S xdxRXA^R?cqCMJQƅ-RrR9eE;F9Xgo`@MؐI) }| a[2!p"X}K 9윩QJ;8QKe}̮3bVtjUx=^^2LvS,qI2V$crJj# tm,R]qxj0|C8uWX63b,pgٸ{t\:*dsJAQ?uDLJjoRz3V > 힪o2̕8%>cA)dߦ 럢[$fѝ) )&>6i>촨 A&CD\~B _MKe顏pEёD#i $Ct0lN·T%vgf5^|I7V{؛HKvYV$0tn`TG-YLh{BȨDB(VWϠjm|226Nh„! X}P2'ME hJ{&#Qh'\A1nVWCIU(x^NGC.b@2z? 9za> \b(U ݋)?EZ?55vRhfx+% 6/|}59@mhKco*}ͣcxws!}?}h8UkXb+i$2h+!5FE7a5*0cCuKq?1B6Mܹ 1$̊+*tCW0 kr'>X*x#yV 4=f8;dK2ۂ1Z}z 0/=;ߦb.xԎq Dv"pF)D%̶ft{S9TGz3 HK׾>k)m}rh⹑e_ V*;´Zn[@EZQ:Otl݇EA3@&Z}!yх1Gn;,{=gJsC"O_)@f( v~D9u\7C\҄"S[ rS&Y{N5<Аq"283vY2v?7?'*(^ >j#WkHu3U7;} g)~+&pנ$:^tu,,הwu xX)NSnze__bK~%8xL)-W5a$\``d{{P6Bx#i8_F`ޛ6'ibWL2pB"sz(ƹPLIe%m/J5Z<* $EKUdJ v  sCѹd=@3<_d~#ZpQ tQzӷ "mˏWBn\_BbjLiGN->\=LW:p.s\ ?.Y?6\w+1l籼g11$" F).({sDqG1` %z@=6q E4U*oe7cPDek<1sf`{NZ0 {,x$ޡܖ!oW?U81 ]ʑJ*} .0֊{y-[+l2=y 4ܬ]1=ڣW NrW;YBP!Z˒Cd܌]= wdXm8չWIJ!5(K߉ I_-gsA&}\=2$ Ytui'rVPth I 5KUC cm_76.KoVnݼLOR U2h̎g:(R738dqOZH[ŢBQ0Oӌ^$H$;Cx ,R 0a>U `6 -2rߺQ>^  hǣeSJ!nZu(ڞ<]Nb,&+x]0R*N'ErTW}g<hW mβO_?הgHUe(;`U~* T EPI ϰ?Qq,L{heaL6`]N<79fK!Խ& Ġ\*(I˥DG=h nztG_{_JGmU @|QiW(cC*PRn9ˣ$vrB&EpyNheH%Na:X;{˶!6(<YAdmPY$| k(m2n} :iͦݘ v?)z @[ErxzR.4V\mbfGb5 +ǜ^6taqRcaVDo:ѝŕBZAolm+s{!۴S`{ek%e{`.2W !o6߬)`U{e !S Ej# y+$qգ/f٥kiuҩGfu"NH/gzqotj*gDZvZu4kč$ ٬Αb~SFۣ^)6f7v FLN7x+ 1WBp8W9xVuxr,DLrK-9cZ7;Zs Hipc/ar ivER Q2jit2L^)/̬Nz7 6a^${JKr1% oER} f4]X;RQKּo@d^GFF(Q䁨 dZ : R(9^jKSlאU?xE?9ߞ{Mf'Fr*i>fƭWs ڞM~Bb,z39GI|!{:p[BTmytF= fBkg< uIi)X~L֬ZcوېmXISWh)O/g3+t0Ml4-Xx0#&5!uȸ0̪x]Øs7˓k=x2=C\"#%mÆIpܹӔ)&"kϘC7liQX],Q/MWh[(^c򆄸ؔAӻ:Uތ/zą+(+WV-L敹4kg~ 84nڪt%_2-$.34Z슁(7)K>0̀z?kP68j"oZaP Qhvjagʲx4lRf "͕`lr:`W,+Ob1wv%D:@=4rK{>ߜ}^n-x;7N Vht{ۍ t!F9j%l(Hȩ'[BӼaQ\Hw7ڦ5݋ͦ u.[PNP;GԻ2$/70W6#m`i'YɠsR=0k6;o}#3JR,?}p`i ~+ĝ-P+ ?`=};uvsT$^k8!daU$5@HvniK,Oo}DO0.A鱒=aĒϘC G)Q>>@cz%_X'Rt0MɩDM;״P_Xt ݐ!ӫ ғ"̌9C%'=ێ=")[cKTdC+<{7 *aq[8RN]Pn!x, aYWv*v8hle@skw8_^Tkae" Ij߱v^+Eb%ޔab$ ."hi =Ƭs!7AY&&Dv;ƴ'+W۹ Z^ZF*⳪>%Pָ5AdEś*oBgT@`",UWQg,#a1 ܡkMUerm#hDGN/rv0a ;a~{Ym1lޣQKPG؝.NYUB#Xx}h2Wl"vbJ*5fsϩRҹL]m=-gOo օ+K} c7^[ J c[UI~~Fi~H/ m'UxŔ|Gчc˘%R-XE 7ޮ0b,-"y%R=Mv]?WX0hrj3n~MFYV0Uyj\:?ko[]ypQ<=9Qd7WP3{/ndpPEsERtup駥ǹ1BKLK79m7/t|.V&z`-x'_}yq &jZ*, ߖ= 䇎{F(w ~ p` :Ћ֚5#u5Jdh99c$3D;E&c7m:hFn6>ƴ~t)SFiLJygfdP-- 54k9deHh<hQyu_~ Q<ܯp-MeG(;t~H/E)$P(gLU_ ,!.83#Zߋ nȓQACrJ)j3/ 1JW. dԆePEs6F?ue |30?kQPK\ ?*#*f9X#quNX[JFZEvp͕XbOJ|W:'.; rħ}i-D(ԇ{ϱ1 "Зp8MHtᏈu5GWAۃ>frdNw%K=#>_xG*;XN_> L@맖# ,K!:ٹY|'IH} wy4_&֠O]BTs<]dv>֦{!_kSqvQ\̍w{ |Nh>A6;4g.*4ZO`Zѽ0=!?-\.^vD"&brlMy, @06y bcu2Fѓ+O_R2D G5`yғb$ӝHHCLTvmD@ViM@Mgf='Z  G(B'KSdi@Rڣ\SOE֠>idѳd; p330$ WUX.. ج8/qqd ٓmfQ܅VsIX!zy\pݒ+\+K!R nɣn pܪ9O~Գ"N@&0焽̆fǿq?l+o8I68 %^9tQ%wd696[[Qx/՟ _puI!B;Uy_8 OVC"o5Qhzww~`ڛu{Cܸ n_N丝H@A"Yj &zOW;3|}ocVn{K;AI*>c*yG,e}J3g$ &`kd qhuyυaT&@ UUsPVƚhѭ|ՠ;Fڟ̗5EY8fSДI/Ko2wLg"@LΖ^Xi%ɗq<׺?&E)]}(7(7~@fsI{|e-$$tp rgmR[ B\%,K 8N:o-,ѤMKv*^tfQ%~F|C>GQlĝ—ixg- =G@4xc!zfm(NN,dhπJ2Mqπ8lV3˛⒭3s^ *;g\ve;lRX!:$r.~3 :1!Gv[b^?Tl>:jŶ; P-!Xt:$E N%h t]5#d#Ok~<7'Δ|%ršxZBhHlNEPRR \-7EP rrFbApwC+v9M+i<!]&)Ǘu=PMʅ>("q9υ`7/.f*Z-@S Ρ,1 o;R^!Ya&Մ4ז2mm@pGw Vpb\pe\fA%y4.q_^ 5yݱN/RZE= '@p/]{k']zaùָ- GD\_ڊ{ٛ[6- d8C \}6 Ryޓ$~UQBXl/1]̳>m ˆ N.fV}S vo\ WͲOhEgPt4;6R?t4X.uP reS&"!8x Y2 \Q[>O1dZ U4PPjaiS#ĹF3 #UDXr -c˘ͨL>GNЖZ5FǼl㽜=m@r3I aN]Q5@}=o>P+3+OeIKrPe5MyW$G2Ӕrw k`&ۦO4(sG\r4 ܪWJoY'.s!wѨb4_%n>'>j4MTnuA`6z;4Cg%6]/S4Cj+_"~ *VF0xuJaZIXj Um;ڬ1z˚(jy홈\p|j::G1Ǽ-/qqn9AH]FKf(9`3 @ @+*O.wM'D>ѵ*?)hHnf)Ӷ)g@NK jZO딶AS84w'ji8x$Bm2iͳm%zόo~ K} R˦$۬(gW^=sa _=CK6?]Y=5+08 )g % }:Y-1;*.q_"aCH\!,&>J҅"Nܒ{(VC[4|c BLxҟ`"gj r.CkCwSF0GoR$ْٜm#HCnr5a\z5oեYW Ü)?vl1ٓbu`䓙{Ar.Q `M !K=_*T"3 cƘ,eB9Y8tk4^v՟k֥3顽kwY[2tr y+m)Dn,~3Nɷu(MmpiccViFLn ;3A J95(ύ٫o&>e22_F@[QLFM8gn81)S>R܅&HtiOd8iQu{֮$ȗed7 ^gg%X]`L,uÁ &eQpw5;_`f:u uoX϶[>Zcut.,#+4+h+̔tQvKoVܻ Η䔞N5?^y]㏗ $lG@NMR˸$ڠB*3y-&f :7_>j2O)~eX0Y5.<"즈fKPn ){c P)DqAzR,O?Imփ!*RMmc|Iwm GtjJt#QɠJTb5lmHo>G|ls'44cK&F(@aXxSX`!j}AkT?f 1E XTz 9%Ko9wؐny:$pix{+p#ĞDwmnLciw0_E0-cPwv.x&A[ho~dWm\-Zp]qw! RdHfA|wBt\$X ^1>OZFUB&)_Xod#A+rʲWvQ@ JSw& ֒CC8=o]T-Y`{JEh C/`LXϛ!.v } z1qO͆0u-|#@H3$PEi7DA0ѻˇ ֍ $0B)~vqnX@e0p7Gξ_A>t?64ivV :*,+xnB=?E0U 2_tMGX:Toс/WPkOz(zmb@CS.nSPLcd\ӶWs|i6J 783Lh|]GN"~T$,uEq31Ji`y#1>l+]Sjfj:rz/ի-[2e8 5‡deh.Qsuv'Qhp\ 2_*+) D[&\nfn^|ȇ,#@yR8Ö,|jن+i&8"r.1h vY6.)aVG*uޔץԘ52*q *gO =iO$ p]2wi>Dx=35>aƹ7\/Y{q%%|QXQw8V5U+\t=h2y +, eakh/"~Kկ?GYp1X`boIVx?z=Ga,vSij%T42 (Pwܕ/iSk:zF2HFA2Ƭ;AMaˤ ^+@ 3-m_|\7ZaB`F@e - }ᒉД,YH=wA>mOBHʽ?fmio)CF%{{^F[OiI#9*M,aDŪ%̈Joi=J~5ŨA?5;!BQAl3gnWoƿ""v #oC8< 3Neg2*wn: E%5O߭!x}6q&F$lN}Y@bQq]rNz(K4e(:7 8Lׂ⽋RAY;W݁;߯ Nsy}VSA+E--՚!Il=MZ%!sv4/~"t0e2VdUe8;K>eQ縷{'T%︚qFڅs9#CPkY&n*#`_~aωaPc'p%Y% PƥFf0ZNeq\@/\c(_Тޣس8\XkF\%K1£G6g(OQ%þl˸QPIƬnlı`x*Q\1B`| :f9}U] sG&.݅TV.W|3`K 7 ߘ?I;*5$m~GsæB!j8ma %$|AV|8e}.3>Rg3;AOߒU$&Ucŵ W>ND=BEgkqo#dVjtxIqb?E#e# dQCBk8!aF&GwwyjAeЧD (=Z)AKkS\H+ԗe.2^sғ3Ji8hK\uG^ T,"]sBϪ |ͦ?pcw8GfZHd~{+ usd-g{\m! H{ǽ9M> )MJz1m'lJ6ӁUJCy~ ES_*GӃ6*)<:36ЭNN9VLBZ,aQ7z$ځ:Kcfa,|"Sd7+V[[ˇ>Q}^XQmp?}v=/!]C}Ҽ#U8 ]؄Cj,#Tml|7}D2nJvo%Vgٿwz-FjR}4lWѦDH!,aÅ/J-4=A#4ՠlڃ&m }3_0(gFn> s_B l8'0McEĬ偝1 S~s|jc\7F/d {WE;yUNri9b{K4n9sh1PX2UG5d^^Ws2PsZ X_@&}0{u%UH%G"[[Z@@{Qʄm O21rs}f(k{惻f6Ɗ T3s&a{-):C/Alma (*~%mtbZƎݾX> M )8$'FTgg;<،^s7T ^0HЍ/HgsCV`@ ߍx~GU1-AFהџb]q:̌ٲH̆49Β[S? ȻGўJC2Њ{^k꽌{7iUi!䠞1Ra2`[OLh@dP<&@c,/` < MAGL_?̸S;Hʹ]LC#2bɃo0VݍH0v(6xߘuƵJɋq߫aP $L /#SN?.h*j14sYtp ;I>efI'ɝ8%x=&>x(Ic~KI?Ud'- &"{Qf#˒QǦҗj uh>b VVCՊ%"葬}44y*sƏ@fT!Gh NٸviY&y>XD Op>0< yj]P慧%Bbg$7s^!N+D@K_g.gK8`0jGr 嶬_.u(lJԿr%BwSjGӕnJʕ7gwQ5#_/84 bwV-rkÁX@r&(v:`Hz,2ɰ>f'exӨ'Fįv`ڊ쎬{B[ ެl.[)hgcJՋʍj@zNlή4FKu\wFїm phj$ w(P,IhkđbIqUUd_l_XJx! D.eY㯚q`0;ie*S[Qh088;vZx]M`8-#s,H%UHۑhRFMiN̻ 9R޵wǼaEkwGۥl9oݍT?8qOG{e1kƮqCTVaߟ(Zt/FZy 9BUCc5gHnK=J29(IÿcGƒV%799UEv] )R'o5y̴&ywHX-F7IDGJ67[BT>T`9򹹵{4Y(͜f t(6ӉUnaHO='m^'ZI!󌦔!*{;ʇnh C8+pg6[<ý$Ll?x@KNh~CUqܣ4 !?ryUp&A_YvE2dr׃,1zI{'a,yLT,>X`4Bf  d<͜Y%W'.\t?l}˼gZ>dm{@v'F'e>+Bʔ^xa@d@d1. nDbr}p֧3nY̧)TҢkg'1headH1/{%֨geЫBd/HY7oX hԝmFӽX\ c_  H4arEZscZv aC78gFmEG8bbΟ 5ȗ;hBɮ63q8N۵*:DA-}κBBn.9'&A,lޣV7`\f6{S,:آyӹe\')y~ߪo\MZvCFdQKR(Sj$u?;_&\kDA[] 4fY$)~iȃ-*eS*>Xy &]b3kf-h'+RL:4Yn}ニ%7`Wel o9̄U | =>rU)DT\ oB-%_FJ:C\ ЕڡMIjtِ^ܺ3„+OdPlEU蓆&w@ ,K}ehmjsU36 `k]o9< QDO-.+T*JoB8 c- &j[9h^)MT&vp4k D嵎_ E1%LBLFQd΍bhvY1ڙd Dk ~oZ9<a0(hb17j+CaTJ5ʙ_|g8yPۯ.Kz"aB~jH802cp:%[M)I m`GE9ƻde2oI}߆E#1`3i-G] H@kKqܖ5S[3 ZOG*8PQǶsc΅J͑ǚIc%z2}+QsYLTt^YveI6.Hhv[3ŋRby1 )(n |D5K.DHC!hϠA~$A67wIF^NC c-[E>/TёmlmשzdbÇx ;2=+6}bVo@[ 8 &#V@feu=A>̛A6@:-qYEҎ!.CYL.uJ|xˁ[IZs*p_;Gc&ZQn8>8?kݧuOxp nppNJ/|HV}'Cj 8DV L52(nXz5m{ކN>]7\("1Jh>Cq}EwbzxVl"jLW*p;r89O-,u>[3jUQ8ֺ؃@Kx'!]#`Wt'+,'L&9ea_ƚ/'U+%IE\]CéJr a<+{}e(@Wb;ⷧM`8R-C5 4}`Y/0rȏ> 7sYJ~VvaV5}'sxHtz;hZ0UO沸vlq,*F,~bBf*u CR(Gqrn`x-xP}#<ӷwNp h*BS >I:IoޚMs ||PyKw ?s^iɓ<迪EC!`3{hZohVA60{%@Al0D4%81R\PBQ^Jge@O_OҾ+lג| ӟT/& ?Ps3@-IO[CSI+ \A.ĕ>KBX(=ʒ0O\YڱA`W=Et[Ne"2ܹRd1 \F9K-Pn5J]O)gek%Ő߿(t*z'`{ I nFwwPQcI94t'(a3G-EM!--m33IJRwɟ4U~R8.?8F#4 '5[u&qſř%1=IxYNZZ2xdr~:*Q&_|ِBDU37P|8t;$E+$ ) Pm/ =¡&zñC5!~mnQbOǎhk"E7xC2ٖ rZEXb1onͰ[᪗U1ju_n#Ӄ)o&Y7J#ׄVd kM *<ԟbI5\#:EӊL^f T6_+{n!]p }D4 1{VRMl6>ڂ `ct[X J5p9jz)~J! ]NY 0ntȺ}›R^)Yc95 C]nn?Lcw :a۵Gg 7"B43\TH)[aHPM>QICBJ e>CmH:K}N($K0֥ub"a[*xt'gpє[KWUCLhXCz(CW/0$ɩg^gmY~'/ٝ+ʪfўdz˜7kL[!֞LϚ6@,stk%eqAU%|s^M dZ^ɍqKAD Y._*Tt&lƑ$ox K/oteG.z85DL8lm! ;ڸ3=Hfбֺp`PG  ȵXП*iaTNd?^ A@=66f7-QLelCL3۹_(]WlY2?W1n5ODžLp+0~]k>A.kR3%%[kShΗ[c8SCvIJ]XoIŢ-@=˼D[ג|qbEL#LsS3+~ iRlǯ![}NҨS mQv`8޵vzf<=yB8j!:(L' HO#HJ4CMYsFGUn'"_1;/&͂s{ygc"M9a~WYN Ђ}ԫeO#KRdեxP)K:sU1clLu@S2NFx8'cVzis 9xCZ(4GCӬ`hbc0F `0H&v9dy+CQw_ѳxDn^!?KG$ BtCC5d93o2~0P ު,;uXUph6 x΍nJ MX` ]P%N5%HO\D#1W^L ) YͥQ @=g$ro?Wŕq G#: gH !{aYf١'Sp3K)xK@]@;T#CZ e~snΑsKPQ8+"G->&f,2U*C U]CȒYu7(Lx]a?K+[Uzns^@A4!)n5RP,#^??Gт _h%Lf-̎E?€8w':R49R,*kSQҙrsU*5䈻lUtt;B $ ԃWLU1NO7&gT鉡?eM1]k-0|8us@f^M]mqy- IDu0`[#IXf+ve%i nz`v>j?Zjm؅fjC}C<=znp]1PtxZ dj%3[wxX]?[^!Q1hgW?H&Ki=~[->$%f k֜e \u&jn&q]yeۊg001BNyI82{ drE>'~-x88'~@HX%)J, q⣝ڡSP[vC|g )R|Û-N_PhbKٷCICD!diplWVϜNEH1bm=_Oܺ>={3p'H'gDZ;.@+P6Lc? O_>LڸެIjjvf}!dfkJB=8ď}qǫ&ff_:bLJ}e pLnԬg)CF*zA]-Fjυ38zmGjVF\H@E }a=ꅦio4G`DNj`z<`!993G#y,2bsacMJCTȋ?/q_ô+˫3N1@L/wp rM!O]u8hUS-7&UVlBFurV& zpR٩ejZozqϤKt 52z3\91AwWos@8R+^l)̀:~lG(KT`[ܙQ^i6\5|M2Ӓ.X5[O&PY'b^GM@*$ض T=B2|'_plExũ8(m#~:% |4kw-Kr7lM˄Z~PeW8ep}hrTDbM$̤k{GUCYD7'7뇮?]a˖Vs&[Y^`_Rn@p@M>Z[)2>EhW9-0cy06bac'$)y1*m{` c9iNV owPP=KLi,9qu7(:{qT46-a>ɀ|Xb[qj43YE'fLWtT=j侗B鴺x@Gqa#{1SƹUgv͋Nz߭B@!> @ThBqIb>UѤRl0i@a[*qÒ{{3I#6vj (K.)cL?MQyp\ kF7PmT_І) d}C2蒻i NhZ5mQ /1Oy`K`i,7Sxh,o%^$a5ָU9SțX+dQݽY e_n{obZO P7 %e ^ 6(e+N1~"=1lس h|J/ulq!ŘӰ7.*V߻k!y-Ziz{ƁxTr]3_^,&l{ӇҶ(uo/&(^{hE,U;qqD# nK9QR7D6눇l.b}3:>  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n022023l.pfb0000644000175000017500000030541510725114532023116 0ustar twernertwerner%!PS-AdobeFont-1.0: NimbusMonL-ReguObli 1.06 %%Title: NimbusMonL-ReguObli %%CreationDate: Wed Dec 25 23:38:57 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusMonL-ReguObli % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusMonL-ReguObli known{/NimbusMonL-ReguObli findfont dup/UniqueID known{dup /UniqueID get 4225180 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusMonL-ReguObli def /FontBBox [-126 -240 902 970 ]readonly def /UniqueID 4225180 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001) readonly def /FullName (Nimbus Mono L Regular Oblique) readonly def /FamilyName (Nimbus Mono L) readonly def /Weight (Regular) readonly def /FSType 0 def /ItalicAngle -12 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec t?clZP'0*X \}<+}-˕~gj3u(zSw}ϰPQwa o&R_iKWH2()ȓͦ嶑;U}^ ?V.f\\HI%Kw}ϰX]@Mܭ|2 - s4RZV 'SpF/uGW*O]B6&)[黠l <[a߽Y*U}b(BV_NU-Wz&}zE<&nmHc}L`嘫mFC-'"{NysMCLQpw/@VMzomj8EECVЩ۔|vX,[wa"MyhP6l2A!&1'9 ) 9OW'0+|YKztKmqNwh֋'/o< _"X{pT.t Y_V/1(gsisYCB|/`; `JrMҎ.(mϚ5NP\fJg3Vx9>^곂2"+^Z ybš䇎f{ z9Bq#&J*&D`20wʍ)0$hX^ua; >Jk7k!qo1@j9ѵwͤAxfU;ma${V72N1jE>E(ɧNt`gy.F~4\KФcPۄoJ ͫqW3y.Xu}wkILO0m~JIб>`={Wf6; + hy}q}T0'Xy,~OYA)3o^'K/HԑbKb6P5v7Oayŷ4k oT8@e۠>?nJU&$ڮ (-(PkE*xPjp2> Dr{g=k-0<9w ^;ƴY}:R6(d9N0ى`SG>2Z~-^R1K]gCنB3@PoLVb}r2j!&` j*\ӇD)kQڇnӿxuOUQ' u( cPp@_A"'! O|4BF”_@ݎ I$~'0֛ʔ)Uh(^Ղ1T9Ɯ .F,9"< FA~2cW-WЬP(!7 pjSUK>>]wkD5?g}G? B^Ȥ|T?b_ՙP-H%9 Lu+qن#\JP#58"dtxȿeǺU!3;]<Vpxzd'結U[#@_ߞg\hus `X-3`Ntsxưbձ?a5-88egfB71#dNôV% gGXg7L> HOMS;T܇'E6Iw@BFjD!fzҩIIXbԊAiWO>xRZI F 0`_-o.5Q;p VBu=ph,ؽiqGHkT=[G-%-GDܩV@m\̸)0F4FY㤕2/:PR&C154 kK/'H.Ĺ؟;ԼmdwAlDVoYAl70o-RF 7ȑ^~8A;ȹ +>ǷSpb9n\xI S=<wc[M4.cC1E%h>QJ% v͔3 vʖ!gj6IS_|.@ƹXR9 Gqb!scԨʈR{.6݆Ҕ:]l~R_\<~^*+V95{jxc)b.tMajj:. &XY@~"RGYo6y jlj&P"7UȷJeDdd4aDqS dgP85$, a+m_$iЕ2R$pO-h_m|Z8cZ y?ћ6*k LmAR1V\ ּ;E} (Ǩv\J |&%R8=wv'cv6QDj؞+~+,0*b]-X/ᚊlSIC Ȥt`ǁrJͼӢOξcLGjǟnZT A<Ś++E{JK{erIz]dCD:ηlf)l)_2Oi Zx~='ʈN֝p~V&609EUw&3 67m&Jz#A\6*SXd¬A[ |Yg~-=, "QJW#g jvI)w5Z+u|E? +Bv3/ i_~e>'Yٙz*n+!iOؓMkDvu&k>H@tjqS%˶9N(j1~bVVщ4UN4LR):m_OPFꚚҥ6HH.W{)*eڗOf84GдR-@ gLͯAKt=XT0iOB˟tdY;;$vr7~ྴ y wL̽;I!9~ޙXNʃMҍQLxƛZY {Ql:}nL21tb xúi)% j פ:čuޗ.#4b,~22(3Y@:+'=۵aOr;x +5 -o-nߴpS-n:3P.U"22Yl!ӽڼfO +T Tz @w%0#J"JpE7Hf  1ݿGМ6Q4աy>C i%PD%sj]u>a3ʫO4>%W^L_^c3{ 'zm8+^lFaTA~9;}=[®$\ 3ga| _ϭM TMѾ:/Q@ 㺳6ѕ]`$}8)>yS erH^WH/iW]q&ԀljK$ #YQ]]gL&;պOyA宊\Fcnvn$)5.pnC]kXXBK=o+NaWLDXz=/DΊzWf]2+ 3G^ML7_ۗMi5~C}fe]9H睿7_A,Nz B|NGPGէhYЅzqj?$+MkUqFO*HS0PJ`QI27SrF4*<|ӷ?iQ8qX/O "Z\J zGЦʁx%QL*jwlo1 %NT F톼 ޠzBl/0}KpJȏo렯ka\]^~4rШnu[~S0Ec :7zQP0"/D"cWK?H,7? dSq"ٹ1Жpu?Wh /,%c)/=8C c<pV,_wR`LzBmn۔ċp7 M_N0v Np839*(|FN2傛pC;_%_gM*狆rB{ӆMd 2 jSw]Cj#۳膻g> KVlUAh ʓ} (KTqfhS|B!QtB5!KS)*y/!xߗuCҗ.H#f< wcwXxcqZL@c?z kެ ;Da>%[SSjOIG #2u -,=j[S_\xǬG:̙F*FE?zoɔM [ad GJ tzr2󃇬^A1+ֵļz/|`3Y̶|g,2_MJ37sR̩Oe5G uc@ x'vqjHӘ8'JZb^.|]r1[#|MCAiñr!O/&P\<k3z>|S#h7 j)Rki8}Y"_w,o%\S9ٽ>q^0_O(٩SKQ@VB?Λng\b9?T 8F-!q;#Iܙ@مN6O;glN=u67/Td0Jc~2\3̈́ 0Kι$FC0p0"xלX1lbLx: z~<NוKy )1|8rbM0~}=uDC4(B%̈́q$B2:"׽! l8DP Oۡa?kp)&1W/!0fPV's P@A- eIhW6) KߴI`y 軙ԟ?h6%3~VhI ސpsTᶻRDMeJ滀K২4B^)J}B Rl l^O:hmKs Q5*U&nϽ?֣@_zq|8RUϊ-NBZJ:F'q5l{,/;lp5aX%sSً,.WbeqBom81v5=zu[lU(h[)2TGKBđ_B_Z{bs Ȫ س秞pͺna%@jؗLs/1٥sn R>OCI2m:6 mƾm{W'a"jޥ\8K䦜KN|w6>^7` IHjjf<-71,\ δau=˿&cݚN2]7⸦-qpKwcu96W|E]V #FS Hjz#ٳgМVvЩl9]zHV|ߟ%)۱>ŴHZ\Qw= uB5U٪YXotdc‡e:Э7Anwǖ(xL˦D2?ݑP Z=-Zdp!vh]DO@aIڰ???Iv-ܱfTnbh:V6g:;9ˆIK^mHI3>p0琊k#\T.4dc?40vsc=n\Լگ /#4m(iVyRݳ(f^`f|0PiH=dO4e^L JΛtcٱ PU3Q %~Maƶ&SJw!,qOBWSmxcހŀrEY4S-+g9sӮ/0"wfzPqyHQoVGt  Ӌjզv0cۛF>J Ь>&-ߢFncT(Bv9Gd1X^byu ez!mtEDz-ݶKZWx/~wV X%/_4l /#K)δ洩Oplc CO܏4pE1K~%4T|VGFE{H+U#Xf{s UIB8ՊӜ:)Ѓ3?$trA18cq$vXȣfIJV{^T=;1^tNiO=onY g P/'x7U:t;ri /sۑw?wW+HV_OFP[˺"u~ៜХ`})Oxݻ`xG=i{껭#tEVD1-EPhJaۘSC~/k1-Ts|"/Pb'h?b;TZ ʇyOU*rMHs/5V^ M|HY&NS<&cAƆY69mr`6A)0iQ{RMkEh,8k7P2"\_rPi|N7HDؙR#6d'I4kCX`EFu$G~cH 9@V=xuϟpvX/!d{G)xU}@μыX=Rԓbw/w=^8acڑz2ESqDgj_ E2>V{n®´B; gEr%n;Ê\N>4 =VCM[6x^w E=ÈP !'WIf*sK5\& O9yj_6eeԎ:kD`5,?hr]qo3:x'"4[Ysì4] CY%9#5Bxe )HU)i`qE}J;~ywI]ղp,fhX{Qym{drI $Iծk; +_7+A\VIoP5JQn~EJ )Z@d G^q+38@Hښ~!: ;WSet0oc[ƈ `GLZū9{ٲ.8.@Z7Vd7KK೸oz/Ȱ}FApVrA6^AY˺fMOZ~/ ߅vK0E08B;ݗpî䟷uH>"a«/!0☘ pos}ƴɇWdJ,|3.J&TM- b@51ͽ@Uk1# -sߋ_C305z iBnb1%o d4#$5 p#َ~8ZXW`f*S9DkX1o? ,-$CBBK^^B+_ɵdtvXJ W!UA #$H&\ݛxqF0bgDhp"uDzR"Xk Kmb}X!J-k%OŎ=Y=̐U5J^ 6=]5 Upm7KyNrd|U $a|ai>NʉW7& =z>ceg}QSIYqXa/Z@K=wʳ!q1[fC~q>H1BWl [޵qT\DB޿mUjD/I=D}lSP~{{TT¢x<[uG:5)- '36p=6*\d&%~\`> d -h䷳/UZaW-/,!濄9q/nƋ MTEe{0PTMWS0 7 ML\0E~.Ém!JGM&>A4v^7cz&x={X8Kr&Tf(=߁v/TѴwɠuN emh1n)x&A2VGjc!RN 9s78\:PLMpHtUEj/ dJ/dz׽&+6NAbA9@<rjlfVjY4P)GRj2 MRdI\0l?1Jdǽ׏-h8j3ͦ{ ,R"As@D-.:&ܜe 1;x8CDojD" #{ȅ *G\K*:H B*VPB~ذKo\*F؋o2+b\Mtv#,ySQ2YfQdaT;N}4 ҟW&&Fۓtuğ_g*"rRjO]d}ak:oO4hH#v1Ljğʍa1@-WxTYa ׍d!4mHK=} 4*Bl݌Jj0kEp2iˎ<.ˆpJ[;lG ]m,c``a>,YW"k Vz2ny)^7&=G Q"!K%ձוFY$h@fZhDAR\N"z*^1y -Hp45x:w3nj[k=J+U72,ʼ Znnq P}6uՑ^HDPR6{?d:T w̽z't7 '`0$UAX2!ˎ+4IV-e1X5u~Y%es(Y>JxR=KYH7ʴi LbR ^s2v!2N2s`҃?PxIBIV*Ԕ* T2>c!7Dg(̓<(%_tCMݐՔeӐ-ihHQO~Y-ZNH}/pG/™aY逘?(ۨ 6oc pT!hj<,,7`L(3iQ߲}"r,ƅuOF;VyЃP0\K-ؽc0vDD|Sh>[-8u,-⟷(Z [Ǫ+&vP*[ bUohǁ e쳾Y`~݈*з _ժ4ZDԤF¶Kπoe$ER9Feq>ԆO2AGԻ<1 3eӻ |.L Sҵ`6f)],.)B`1ApĈ xͯ>c˫\ J͖( ‽!=Dg|phMTO$}YZ6@x?^IAЬ N!:Nbq\5$iy\?:BWp⋄VRR UA sa D*+XDޣ{G s nW6G(_JeRPHS?h&eWzB?B} }Tc}+?cz}Q&X=n 04(.k $] "d ]b'+ۮgF6:XgS!|_[-'+ܸV.S}[Jt~lwd62VhԯGj^D$lT.ry}h||a(0TA'b1 CU[0 m4pvUw-26xPD.~Y;} >?:J-V˘ dnnv`mX-)icSn*{E[+S,C?ByxP#0Eb/@nǤlH̢"*?.|&xW5u|LUBx:W'W ߪ:+ Ɉs8/Zäw `=92'rd|j⑵D?dMJ_XD?s{FO z';KZ2[UM Ձ; k4hn#5=n݀÷?;OZCD}|0UV yиC}nJ*@fkp;b">ÿOFtۜ9Eztvk֍g+gȫ@J´!q,g9`gMpbɠb&<`Z10EuSP( Q S27Ve1igV#[.B;훺ͣ^ڋ8<ʵn\UqDr֩][[Y]BE}1W Kֹw=gZk 9j!Y?C7$G]»[†؝[Dk%S+OJr-!ލ0D0i&]j@@otB,K.z?cB.'hq3HX{ QzmkS.4C U.q?Xz&Zb7Ь@lmϠ@?@͹^2G}^+ |7uMM+2Os^Tn~`ЊWuY>Qh7"ѿNJZ~̘ sIu,LdOnV0,Ąٸ Ȯ0 F#=iZ9獖)c%P16פz|[(NpիMIi,Lo+ j\^WN}/oYybQwJ4?|"H%9E1Eyl#0+K^5,fA5}Q&r'#/_z_y4qgzzܯ0H̭|YQ$c '<~\YO)7㗒 k;z[n$T_Tdi?[NTM4měUqڃmaGw-rTP&,Ś3U#%aġs^'o~Dt͟G+QHU$|\.m&:GKFktg5% ¿򇚴4AʝaQeF8)7Ej"Ԇ7mސC)?Vň3+x .DU?m|G2=g;Q,50~zxoLyfd:oؗ35EGb}/ySNf5r-tct"菃Gts*L/&k!QoS)0bۡY~elBJ/%oƙ؉p0|W`՘#xu~E1H@7[Q6Xԧ難(QȂC='tWk6QPB؊\@sCUq{t/x8.cx30 ݄c? (Cf}lk46q.&&Ju!Ҝf[+i Lu ;ȞŎSINcٺ8{Xe'-X#ą}w D^Y<LAw*O1BBӻ -wVFiTCK7<`I!b)O5iJ-a[m|lg6 c#6 bH?y [V#QiYI. ^]_<3v%^nGpءQ)dh/ְ;D3'~ 6If W윌z؅Č S.G3{IBq I Ϊ͘\' */=G+%VUM|~>cd^>|s0@2F)pp0*BY/3,$tt\ԎI Nqs~}&DMNWPønH;ȈMNf%VпonT͗2]xU 'u(v[L\aY{٫M#3$mW~xWl<F3r"L{'J{6SO9v RX \TXvvFݴlriw6%cn&L46D |ɒˈbQdQ n$b#z,n(ڻ1~Ԋ/5Nc =xy~fh,S|>Ǔ9J op *_UsQ$h{ήTS|TT ӱ*8qJ4zXSHq%Mp uZ9uaeLZQO j3xcUN90O {non1 /Z1Y>r<k+vҗ(T=tä-#*le}.Rn }zpǵ=y;We4 ڹ˔2RX3 ?j\8)r+_@#=E Ca& ]h7c6 V8PY&Xr׀Ljyo.:;i ݟ OlMgf ,Y=Zo"y0dMYG# Mt8z26hftB͔>ˆ ~ G'½7nt,1.uH@ [*ur4yX5:6;*=,/e_%}ҽ#2g  a&#G p$[:rȗȽY~qxXE/0$q@6'! ob(*2X\Ey&yyr`!`.o8{lF#?:dҞhíEk/' Hb-]=HzsTzk"*]Rp wr/ QUG9]_Sկ⭴ B!)X ^w2EHٯOyZhs6{ Qۏ{zC%w% vH-Sq7ӴW|Շ!VDR3{QleG>ʵpsSb:h2<0U7knKd&Յ@[+q R1`U׭(҉+O:qIXsskc-h3w~H$PzO,128b<ڝojk,Ge"8]}798Ȏp.A 2 S3H=#&,p.yCc[Bf~V;yvY#4؎׭-4*Թ#*-swcDwP~eVa2H=?,Sz,M_&t?1^at8.PXjL(@"%pp&ԑzeX4,} 7fC|jR[I0ap )§y5ҪPnsV(WѵM)`y\ 1KQ8L6b=ҥd<с-2o@|ߢe&2xqq%jN[ضgY8p_DL2{ֶtx>n'fcxQLNj1|6Pm꫚Q6db&#!vRt̒$l:SE ܶ2gTq g{ @`yUD4I F]s}j&61*W 5\[e5b!i Ӵޚ:3GgKg-{yMr㩡A+!C&dy稂E>R:֕Yt딣>:[ZrV╛ɑ4R0&-U@%P0+GQh@AVLQ]rZepvXܖ8ɛGLYD=r|QdCXUs*yhª' ϣ!T |qX-m/ {co!%%p?fݱ%H/I,{t9NL ܇2δjV$ӚUgP{>f`in2뿛RT cA;݃vG]]=e=w{9 ]BwuDl-K9GzX z .J|<a,bEp$Z2Vl6BU#٫eїl"|XEd#tlCMta`g$ n15 )5urxX_/jQa?$;VoVjMHZ3yN $3]I>nuS}Kqnϳw{#iLCn]3V;`&[UXUN2Z2¡Ni5d6\$ni4_~>|1"ޣ Fxd g,pI\Xa15tVT0rIC@`Ɏ+A7t=rUv8S |M餇Bʋ*YQ`WT^,k.W =TвZa87m {3f/jS, ߡ؃YBc$pV.ܝXۛ4zMY9B6őкCOKh'hU B fⶶv9$Ul)wr\7`S.x>ª.MHNݲgڳ8Ʌ @'g3Ŷ".CQōPN&rOmƗ7.F0wG6,mHKÑZݾ?J HM="Rzԗ;QQ vj_31 {dL 4CHAH~",b l 2SamfLTyi Nն3G._L1Ck`bʛCʣQB \!D ] @M ~{<ҔaRuy[(f\Y~Ζ7\Sx9Q/VvAxMF^7x?l_ݖJGԗubqv:Z YˣcCt$%o?xk^|YCD8Bo!b(_&/|Ic Ψt |x?]CB 'M9G'`c9BG`#:Lv[;K`o9sRk9}NLԜ B%k %AqVB%ӊ@J!z8xE|$i3k͟ڼQ_-;ҐaV{GʕSMлwa%ZǏ~օHx3-:yg@:Ս1Ek+=;9b+3&,1UGe/ }eo<ǜ0@tQVzz%rxE35Fxeb|v,a_t0v ޙaFl2mWԛMz8ٯZ4FDVeFNUumHfGK|g/j,B!z#vIJ:JwA5C+TO[ ;TE$=15PT\_{a2ŏ‰$#d9qۊ%+x!: k]C|o>i)9g }Fo u0GEv= 0Ip ~=UTz?V)4#kyƝdwiR/gȅsCx@;l16I1 r wyɰm; -]k5JYNu~fv|XR8yĮmoWݢ-: 䫤%|ы#msHGSҕB⛩C}R:LxAuMzC9fГ HƹְG )eUʦG)Y"sd06ysa Tmepgw&Fzѳi۹'OQ9԰a2j2Z|DzZD4~pWA(X=9X>0$5m/Uj+9UhZJ>=WhS^SCo7lxj sޑg:lFpSr(J52vt@c6r[#MmUQ _ZUM7N,$-6E*$[r]KIua9!UIߡʅ~|M ekqZ"2^Mz'ܣI5G lR4%Hxg )9at |UM]D%#+R~ L%DɌ ҇sR8nƚJ@'T՜ @Av[XT 4R@M6~7N$fcޱ> I H`7@45EMڢzSVxLZ'$'Fu*QZU7 G@tb$)+h?ֻyǠNEI_+NL?++C_SA~y&!ej_zeTլM9o0B]:s) ٯp}y\G֧}X ̅ dF);ԿGڋ_!:{>i⟛0аNQ}ΗCuHQ P'~G֩y@oug.sO+vus&u)(L UI-(" E9ko6x-x2ٗJ inDsrwHhݻh;HǙ?_'?cԴg$|r7.uGޯ P TGrh KM1&w.lr3:ei/KM()auy|*4:u[BGȊ<k(n?Xc}GJ!g/$0'ohS2p=d7|3Al* -%a% ;dkߦߊuBYc'J\)hzqX#_>&FQLvi=2:# )i4m ϋƒs3YTk^12 |ȺU7NA>_4FT@~^ĭ/O+,Y~|J4Ӫ""o;eLa,%;]\: 35A GIr\B_1~ҏ+Ip=6x>3BBAƲ+_zj%A+j`Kiu_!W[ _uCbk{-#db`iJnbpkW| r_vHK'}{Q-s埾Z-ZMCY|hxBvMߚf2{_F^v>}KĢtBLa_TzYo)81F/z&,|:=MIͫYL>uh"^+[;ԅ1}"^l0fɪtUJBô7=o\$ KDe$EFx'k|57VJ[QS~xbJS)sP϶d. o%:6S3V!0์@8 _AEe&x"PPp@l`TJ!+Ŷ4tgԋ*Q~X׆ v;_6ϻdH6k/R^g vvo*$s}\aMy]!!(In8[ŧs+"zj%\61Ka K^+sS^60DE9@'_~74Y]8 U>%}bܫrk}u)A_Vxu\L\nqGfM2*,3'}4ә$5!Wn[6_,G1Qjj%j7QSd◾ [F?Rg@:ֽ#!2AH q)Ŝ }F[N? Lug;9U Ct)om!Sb`J 6Iui@M2Ma0ӀL}+;ˉQ A֋rه^2U,ŹWPg5 YkV5?ЂC;SF?C )Gl 0:~t^%?0[a % =yaZ%di`ي<|;:bvX>%BU70nل=2'÷@DՕQdPJ%%Q{uը.9_-L_8a_MZh`wF0[jHqzLbN!s)%QfxqK͖I轟 5'tB p06k\wNMjB Ou2\$ƩyoJ{i&U<${?"6ѯJK^Vs}=O d",t}̾-Ayd>f' T=H|#҆*(b)\onUi%~>%hH@:t@e +Mh`$ }݋ZEX F1qf4Dݑe*%75*fZ~A5)UqdG="@KLa?qfTU\—b @}fi:: m7-mgr vJe+'(h1?_=\L`+:L)MOREbCž Xh$^3+z8i h~rjU=<]\% fe:Ȍ(])k~JIL| *p0Uզ?%-Ȁ*ɉmPB:sb#柩2[AMs}5+0yG˱ޖWaj9u. @ځT)0ZI_K#ʋnOk'G Aqɘ2S8X,\[D 31x{%}'NuPz/Ϗu[[(bEV .3\mdEq{`_tԎ@8\@ۃNB=]+* T@xv,һL[4F ;/N!0lS>EG 1 ]}Tj6TDniɧV/K/OüIT r iUA~֯ p'xFkĄZ4#$.%t5F.U-2L<.bB2oƇ3UӦ5p6,q 1ڇ- #,xwqo D x r0-QjO8MRn0ԾHk!S]']Fi2^V/F1)Iٲݺ8MWW]̞ɕ^P$3RJCmlqp`Noĝ7.u@s91,0qYkGNڿ)OM*݀޴;F9 'IUZ#-rёiO< @X|@ԩo! vV֥t  #F? 05dG #;>*in.3i I(== u?9¬{C n6| vjg:;nikWy[YKaU~mP97lot ,3.se&JKQ6&ucj4gqI6l|m LRYDfCJy dRLo n,5vA%̊>Ikbx`K,`0,qnEP侧6*P؋jseBVKYk͝tNR$Ju_2%kd9qõYrͱԕ2A&?gjnPL?0O# R)iphd:/K8 ϵL&=WR뷵C*˙%IN^niY0E_"tI4EIZ"^k#Ly'V-mUSľyo'q<>U^;gr`Da@3'YP7ZDWBvk֡i8=!=\2՜ -m hp\GEC ϱ©9$Ʉ|vA쐏䰅(QO9!c`% Ի +@6ȘYw{ENiS*G0'_ 'o=sw ?w _/BΔU Z=صfE4<(lUƈWsЂVj2gyQ圐P_)J_\8fA3c }Z>8(kf3stIJK7vŋR~Q-as&cY|P@ nL)b#TPu ''< ؝r ;ZH3M{S= yEK78N>cM!Q!Of\vTS4QîhXRU81x>kZ*&xn+ d2IC}Gđ,o6#tqzGQ"$Xۢ$IèrC 0'}u7EJf^g=u]8|H3V׭ؚ"QN˯;U^ݣTzX')4/, #nU'*冯G[;l7yh/6~\Ejń*0 wiBdnR+#:֚$ä֤t'jio&f G2=M6ȵ|h^W+\W ({1< ~ TW>CT30&q-!1~8-\Pv]YShT`?ޖž>S3C-4#cF o=ĞCÖ6J #Ns-=-k˿KQQlam^jjU'鹫sAn,CHH[ۀ#4>{:m6ZrXFe5X-*QhaS *ׇL( 5gJ|QFtD--:\y\U:l_)H6|NfeFP̻ p-GHA{Jfޯu; \!MP|Ҹr&ʵ]pyixͽiR AVI11kaU O'Y}Ǭգ2${/tuM + `2!4aǘnL*8/I8̘*O%4)xid9O M#Qe5N.zuvwq|ީZM"̷M%7x$eغJO[oz̛o0/XI-Uڀ'#sE;!׃l`DLA4g* f9 b PTXol]@0 i|$+$D Fk^yXǚu`f.q#_9ځdhkN,ǘfI5"$z`>QkuŖ{O6)홱v^UD[t;] i4EfٟqrR/gNSPt98  Rg?;{ ߖG-Zwރ pUh)܎q8$Ϝv]I^b{0 w}_RܢP! ,r5 S-D%t,I#RmD>90H~ٺ'cޯ<Yٻ]8OU&~ѡ˝f,^ćn͖ 9m+fFޭ ;you [aHZ'BV*CoH̙\ʂ>~Hahdޥta M~FV h}q+(zֺ"vP4 :*[~V]._/aR(}:Qi3 ]CHz$ Rx>3iUʦczN==`l_"' 5A(T ]p 5e7BJz2dQU$Yd ]Y'=3!/+Jh< <W#^i{H_0^i͉I{^FGN>,zҩ6rS-0t }97\Pb-1Yy1G+!vW;(,|p!O|`Fv ¡w!K#uē\J{%@qvCd[_6RC$2Qg-^E7s3cf3hE',a)HE*E֩+q)pߛũ. d<2}e(.oǒ)"3{ '`o64}QYiU}h٦f﷗ŊwZdqwc 3<3rg1e[%$AַBaXvCH b+ROb~|R]d`;۞CX˶T3ʮSl,2HXt L'y+ Hρw]9yeK>ɐVuCUoya`IWCH";a'gjXDtՌ>4\?g11$4iv< Pd4 YGhi5`,'( \-o@רRsr-EM܆o04]|d'F\Ml< -d8''0 o_)WW p9!= ;H>.:(|02eͪ?C;% `-9uUqjT7"!Zۦr%u'ʉ-*Ro/N=wm&MsJr0۵HŗT5qB 63u?kTwV ˿hhҾR4!naVTh,/S-pvىAu 7%\1=P sLkIfI!bpbuOc۵$WL2fEISj&T}a'&(>;mNv"SHtO+]kITmZ pv޷M`Ml|ȖB'дj M˝ݼS]HrNF&O(1P0mC to#F[:&4HVʵ$݀=0*/@u)1PWSY~*02xǮE`I P!dnȒ> U2pby*?wʡ:*L4QfV!=:§&.h\.\h('٫M%@*i2?Lv%ʝT=@|N*ꖑTj+Z-lVjצgJ뙣"Aϸ]DtiO>v(e@4,o{uk Jcyvד!v\@5AµŘ/jaX! 8 6ilr{bl 6DQyr P械\}P/C"h6g GKCkM xH΄ؗi},?`jm0ziGfcҝ5Dxۄ7Bc{NFKQf1`h3x7xT}b{֕)\RoغF]W\¯z j3tݵL9Uqsp܂M]QF5;=Xu > 6e0M;F'?iUM/(㧰c'v+ǔu;{ nиmb hR XYCl:9s;Mrh W7`=}xk niey&p1dp:$I*i<R-dNDN#1M(Eʽǃ :Ι m6%a}`eq VaԷSC?)oo9Sbm͑b4M4G5&[_~v5(b5`_p]N\afn?}E wӸ::MXR-$V1[56֑>Z[p`;R˭H> CkiM,< ȵ :5EYVK|Lç~$H9x$?YMB* $n)}羑ؖ>CxdAHb/fZB١ז$:|݇+z̳>Fd&@ 8s'æYdžv&^-\"ViϚ]ߊ=Ei[5׹*-Grq`nxi謉Ŋ"r /guo0Iz1,)CkYOޠbРRbSJԮWX?qզ\ziWO!J=fLOfV7k܂:"g~'"o:2!`+`C9SّD>9_0aE* 6&LEk~d`Z§:fu H"i}[Od V7Iy(:34d4LWyVo C#IdTH`TO|QOh0)˩n^HQ9rOfB JAΡQk-к3/X tCTV" an"]i4x^Zaؙ #oCX!Ʀvv vdMSr(?"+ [X:S"E)np8Ķsx׃"18\> RO2;\KK(cy7wo׶.-y u73ܴqq8}h ɸߚ%QO/?&@&ӳĒ~B;?RVeB7J:Oufl%m"-Zjf{Ŕd{8k?;Pa|U~Z;m8VY$y;vC]iȄe!yw줡2C YGYMKuGxmWsTH4waƺB* ?s{SyEIB}!@b"紕pxN'81> Ţ\tH}t]rG9%%HIFKV6j?2xH4$~Twp+v.Tgj^'!Bpۙ9pf˙4ImVtiưVmָre!*EU<0sRM+ qr#,d,NզTDM^g3@)I3L&HdBtԡРZ%c(mxJX}2mb 1R?B- ];Ȕ-52KJ,K২4Sh7PrjoXw4O=ܩۢ(Z9{o䮷ܗuv3am`@9P0nҚ<qL# D8d鄀phG7x0M6ugCz]tOOg*bbiŲ穦n+fh7v- I QјfW|SI}A*%:IXUzܼuIJ(E͕,0QKx%COk[ -?>^GAi\q"&cMKz<9FpPcb6 ?M1P׭c"` 8~EagՈPMH$!s1SX#l3D L|tSg6V^ :B5C~:mf":{(T&o\Ʈ.+s6 /˝<zb?MwDep.G.BmM"y=9|+*b֣GU 1#.{ ͡tq gS |Qz۟+M|x|jfyIv 6ƥW酜zf%qh/1|:™?~\B6% p 0烁BKahSI?2 +(ڲrX]hRՔ{Mqv-QK(8bY4KǪ8mAߢv#ǏU±U';rŅ3W{Y Ȁ0]'O }k} Ǽkc!;F\ʎcI֬L@%l4zJB!ržq^$/O$e&;v(06صtHCjӌZՕ,d## @|A]< %^ JrV(RB{`;<:pwZ s58 7$SI;k~X O@PDxOjuf+ӟ]Օ50(Bt_;>oI>Oy+wM|Q%?xLSG&uI@ &(lg–2WoUjPQá)l_'!&h>]eU|SnlK(*"ᯩo`}O۴-X##R<2LMѶӰ!tQ(#5-Y-LݓKGzY?(S&]jK@MAamJnfS:=@^e{A/E$щ{#-5X9WH_'ysG*ļ $kFťc'X#Zb1;فbWiзv!zǏ(eB 廀0,ua LYH˯ų[#8 ~nV7 m wÜz!d# 6˰lAt,o֧9׫$;$Ԭ\dl"z)%>p:WIy095jWҺ SK+z WP"K@4>i LTNÛĚzT着<5J '/n-q%rLQEIt6 N$V QB[{T#;2tъi M#^BKy])iig4t3RC^ oIlRGO+"$ʷ ITAQc?@i]֣3FSl9e$`i?tȏ5C%E;$qΚ_(BG(bVV S&*CMgyf UFv;ˣs*!Yke&}Cme2Xf=+DH;Y@NU&ƃg\{tpѭۑ[ ^> G0rkf~)lvʎ (WX^|y 679Ŗfz 8m8V P(E:CҊA^ԩR)0'JGǭůAp uBhנ:Z?n45󶦚+*@E?E9MW&-cP@;2ui>x!!o7ۅiRQy㱭Jb p0U܃2[|C~Bƌzޑǹt/O8U"urُNP瞀{ x9^y֫E4ch'ͲԩZՔBd\P6j;b*feNY]xe$6d*kjd[-OCE¯Z?!\1;uy/J/ec>B8ƌN‰hu-&2 A60`h84˹SٙtH,)ǀczG :gU(Quh(՚E = LՓ5^ݯ_PRV),I:eb'~/֤.onwj͂ihf| @ \:?1:|ҏl䠈[R a$"%ugQ ULlk/dJJh+oCz?n|"'-| \Bc.gR+Mkᴬv^jWPe_4$NsSAjL\xG^t<jT"oSz.b瓷UIlr2#ýh)%L"i%chI Ѿbǔֿme=\=̵8f 2W)j4Cnt`ʲt/bIm//MZ B(:m(uwe$UNH}},~u݅_ʶBʸ#z%"ؚ5*8BiTˌD" 4] fkǬvl`7^2+U~:R=6W"'*B h!fPq ;{P%)"[籤ƾșU}CWF3lb&FV\S.}xcxRcpZ%`wG=}K'f.T&|8m qq1%"F^t cka|h~+XpvuiQEE{n걁HG= &sԷn,c"?:]ԍ :z_)(O},g6|sZ'oPs‘Z}8:K{X)fxSn!" );`, vӛ7  yJ2$Nֻc pI/16/pm*6FG ͐_bU!}ٯ%0}n/jLTZ ] .E~sFh]:cS~X%azH!\'"e Wwi9T $/&ø[x<x-F+^qEI?sn'Bxfu@!3q IG@4zNŖldd!\B*,Ӄ9eF#ݩp2|ϓ.Dcd⅏P}ʱlacmѽJ3"۩}ק."կݩpߩ}u5Cix/ eՔE=j}zV?mSBIM$RMI"ғ7&$[|ƑezMM TVZ.g5MY#;d}g,hɨ+ЖNKGFsi$PVpStu;h_CF.ԸMr0cK"ɄAL[^CXgl`b{*t'qZO>AAc5u&{AcH:A̼.vC5 5pM(f 3̱,t$z&jo (w<]m2M6+P"~^]eտLy G T_fCL-F|pեPPUS"p3.8R_(~ Y|1u<a2EEҢ~$#L߳:=`ԗc"+;)k 6GOzVO>@6ˈ,.(du$QU؆} pF$?40yaKL*Jٶw.#AIQ;;Spte/K^%اrDKc%x`)LTmocMgXgc"Zu跽hpӨK?z"%Y̙K7P2Я p M!΀N vy0)RwjMgڧu䞫i˴KP|Z4~#bWZ)}Yh6]MT5G( 1X Z%Vn! M|M88~Bz6pb\splvvNr;p c!6J!#OH,Ek$ϫttW8v HX  ؀n3@> (^οՔ*/vA6TK H?JbEkөj~"DL!:rI)*/\f/:r)r䅻 ]^gz_ۥk @j>MWh\CۗմҸB"١nj ),jӏX#Bk{ cS]:guCj\7]bSqArܞj0f]LӓR[={hJ2 Cm0+L{=:M3Ou!|=m *;Ug:CDMGWW'{fֿKzt@R.3D.v ][d!/\N*1@ڽTv.B PӜ4q_PjzúsxI2Wп`X:$p?vE3 MO$,t"etrA ޱCh%*K?Kfq͚\raXi*qp,u׭e20<گ~y#6t9/ Ll2uF̭3"> gm/Q^C85vx(GYAOgyGj~>^,>5}be߃@/8#TUz:xWOs'oh v ngN~`7d䛷&w77H;[wIKxSKf!(Oo׃?_43q>=TӤqb+| 4[$qx|S1ÎR4e0 &*k2.nH}ڒ%˽Ab (|YU QTw%,|^d\Ē5 R?<X{A`HEim^|ߙN czR|$z`[UG,XlXkʟd1?қcp,pw[?&cF 723(55WE%T\ƟYԁnWB%ǴU\W%]oNoi&ۡdQ1ֆX9yedo\V 'i[}CX}oX$ԈԽqupm3)wJJ S[.OݴFK{V~S"s%po[J]A>:eO`7pPŜ[QhDe`7#o= V-iuTļZMIO}bGW?$|UN_PFQKۊ+ߩ@ | RzQ\eq]EmJ+غSEp,m?J:(ـg#wndM TA1oZa]!^%)G!{K`Kޟ)?`֑=v]QGL>IK} ~҈n隷@=#\ّfeu\:oZeIr LW6l[H'_# C@#^,AqL'MF=+nɜP_R mbї"I4>ch_5b%q{!;CԴϧ*ɳr~ɨ`TKH&0P{뺖L6)[-͠Xx"l46KIT ~Q/o˚5k# fQ`r< CC-Ψ);/2b*⹗D 2H |`x8($PSU*eSj5į yYkK0?dH–l4ydG.Ϩ>Md 6A@Ug+Nqj,뉢X'ǖ)0j X4HSldщ'`p[֤akrYY&?Pv"8u'P‰1P+8?E~g0N/hr=4(Is{p$#cPX@G7 *yךu!/,GUE?x Px7CpW:f`%iBCjolh7(61ȅY&K vӝ?bT4ES/) ݄o +4$ l"6|Wb_VnḮ=f%G >?hzVRKN)s M91*Dz8A$mqG6+*m!@^1DcjuK.MH9;$;]FLߜY-kN-kZ2/+PW>yMO $EY<ײܲ\xMY0FXbOQ,ƱnYY!r rOE"(70Jpjy*ܾ20AX(FLؐ Sa03@+p`±+W u?`rgsK?H?cغnE9&A! ~ΈRu`YdejZ`='Kf+ 4o"?SEmfn'xn!UNL|@@oC^UuoI8+|+"6l^W#dQ5\o mY鲹!xxc{3߭O@*.mdr[N|"ڊQL5$礦pEzr'00)bbFY8VH{nBW^4v.TFLdrvh(2q.F̩d!鎮 fqτ 8'n±&5=0J4A[2q/b3hdރ:W\NV=UNC$X+3Иgb% wu-5+b[HIe:M.m)ԋmQDԬ R0`xO,_:jKEzEhu88-xa[s mFSi6.dרiNo;HqNFİ&$. QרPTPM0N r77)M-;|f(8ߖ<6 =0)iI!*@j%QO9QD{6כ;$ە?0+d7([!SqFtӉBJyLR rq#dǜ2 NR U7E \e!ڳ5eQm5 NmP;4݆1g_\|!ybOO t׃3.63/\Hu h}1I'6(h-Ǣ>!}0c㍈ɸVG:O؇th 0gO.6K$+̣WA݁~NGOp1J.b<+nvIbPUYYթ#=RALzԂƅTƱ (: y>i-''k'_΋| MCVW pw7H(3bTzN8LձAi4%mLn+*`f)RiAVi~:+OV.5|wWN 9Nޠ#/j~f.֧-U&a]Œm|-gD.F )ΤPA@R/v:bfCd܀p3Mĝ^J>.㔋o/6Rx%o8M ոʧcoaN!?F6;nQ FJ#I DAv<+fWWuyqI|oxW0YNKd@`uJ{t'B ZSܬ;k5\L#G2W-#zct. PԏhCTpOAJK(XnhP*:zdPYɏpb-`;Ww^Q_c3[6ۋ=rgse'ږwjJKQRȸjMw-R<ܿ9Q&j&EC~|ZTԍfgCOL!pt1w/+L O.!+ q=v\TUi~߾ܩg8Zv>=\$}3lч /M\Z".D T}1H[6Ɨ:_gpTmfRF5AGrE~JPHVWVHGjP0ؗh@ SNV?o*yC2i?l*-p)9Fytݷs(2vf93=@OabD!GbHr˽-ˊt+4m>^KnAEg:(t^$*6`M"g8U; ةJP5S-ҿ89FMdjEɋaTC6Җ:GUD W.fsג7$͑:<{TNfg[=iNoynqNwtKƼvEmS(n(|D|GljmzDګ|Qfr҂bmS~]K;K=Ŧ<-?B ԁVݲFĦ0j%V`nk0jU.:6 ]iAm"W"uXۗ' J?` F*4~Zv+4Il7] x!Ӣ·ō<^ RP!@<\=@אh8Tg$CV'>98}7U $8i’H~'oH?׹I%^QSZA:`SY( unO)ukā^,VY$6coV߰'w^R8)? OIY^!J$֫ĐVP@W?[J ?OB׆h!s#qJ,j\ +IG / vYJ ڐ8@SQt ʎ$X6^˘P{/5&hC$D9'[o7ۆ,jKE(vCu ꜤwNAH꿤Is9lV&W,zt~Zcfji3ȹMN|++q^.G[e;ޑ|6ɶnj>V}<{uk92oټ{9B-IąB.5|< C{ tƸi{0|O_&oF3j&* `ɵWն@Ri?6}5!A×PtS\;T!TΟt4[9QddqV8C0 ڢ"_~:m\(V?~93-0 ]^ҠvEi viUimK)O;_q$7iPL Kw"3 N]'-8Ɲ m/NCKA5;2Cu&5Mr8oXZOn>Bfl:oɘNzO4_)L&u.rq]ȐٔYh~]ݦDPv la"Qc_Iu\)qUj7YV1~!5a߲|?q{1'0qDK3A;`(A9˵r_s0:L&i~ 8_%oq95Mov/Xt-}7ơi`!-SS*R"E*^1GW ["T3r, fc׻.VYs,(*<„k&:o=25!+Ar>a Fbk30Ne;([j;4zP~% G7G} }:n)mm]DϤ<۶# hg8$(N_ȝ/45X7?%P`m89OX髈\P4]K*aJ c񑆷">Y Dt 6'EK&z4u+ڷ1mopӧt{v@nrx~dϴ{W29;o4 d{6[-S׽:AgF- cƵ qS(>j<8:-~}m>f5"͆|(a2Y,zcciJ8ǟ'r~$'wWy;9/găĨY88:MC3`«ɋ<@$vm+ֶ'0d;MF`N֦*]2 r+u?j''P&|2vYUb^| ^'sջv$RBAa6N?:`zFE0~фH3܌Y=n$lA8hӥF3WbZ#VUϛZSK&Hjh_e}ň $Җ, PTV.a"k7*jHe5gS0ֈO,Q%( ^ɷqE X/*/I"*̄hE``9Dwի%xV.ȷ'!H5:Z3x7+ܖ'}*BԷkCqp[ uw8`v> c|r֝RRhǩk˙64-L>,8#ZS$-*v-K!!%֦y ]}Y2޻#˗#C ~?h-\J#!(Kkmg#P Em)O+ `^'])4ն+B71!08g?D\Lz@NڨX:`''w'-M=!D{Fˋ.@osunj`W!UYFמ 79M*?U;g@@=-5<(;}ŃUCl UJ>΍eJ )QWf.\j_U7&\Ek'[k&/W0f Y<1TU ٹ6dx.#RIJ ?;4ʓyŻu2u \Hf%v25ypc9>O""H9;VZ8Lrz{ܭ zڟ)g""D[kaK@ VX٬綫fp32k5pE_}%io?^7v݃^CCθHGK2n\Đ5Ȇ֕1%DHf1', lX j!k+-}V3^itVWU2i ]W܇`dOJs裳:͈3EXD~`3Rn-h,-ZlB~wB0PMT> c.,l$H{#h'<DLf5Avs— lf1YHsQ,{Azm[q0n.?$صRuʙ.\~,J=aɚjMv7',ߋ󵩙\:EEj1s#2 7iJyRdj=f:m2T׭os&ͳQfRnXkr @Z#\3<ON#0U՘?|yj߱"CiP͇/U@*%%-@ς 8EnLOy]>G-2?K3{u"+QijCe#/sE&vS''(9r}칠ƋdA˚k`= Q<_:=ⷣ!~EVEƉb"B9V5 +Fʶ癧t8~&Q%C" Tafv7*R|LgL9fQBQGIaF_>.+In^9]`k &Zqs裣cʑ?N1G "b}+ԫ6!##nD!qk_g-M[Պ&g#QJCb-./zcBd|$iVǩ4f9Ӯe45El#SHOqNuG#uXz{{- u}'eژ&WT~ʡk-XIhs7uU*CG;S|EPP,s8\+zyzi#nؚ{T7 YyU_gg 2JJJ- x{E߉`k~3c[mi V1p=;I8#^N9:0KF{ *zg{Lr*EGK%|DMkƶU#sa #:/pmUk롄{vo) ]/%nb;zFWYoyni&zdSO*m5}"J)ۅIEjhrmVWdp?eKgw~ϒӠ@-U@s**ϕ.`m Y3KV#/͙5Q#hu >ѬdyA筃JUVJ411 tR5@^fbჃ'.7SW1AU #?bv7\c 'Wdj[v RN}Cc & v2A2FB.y"Ude'q!k4x ܩ5Iӟ֜l"M.r*UczMaކ_q햛=7"3yW,0[ƿy:ࣽ޺MU Wi۹IX hVR1ucK;ůҎv쟥J4aHFacDz?c Q1~YBg\IӥOgSEwi|y̙y!r$w;;챆 kJ:;*[x^4+ 9mӢhCP!˦:Er+Ny+sf6ؠj=!~3h 0ו. $$!y eq7W=a(?xnu3rߚٻ15$ LeeZ8La?3!?Đ}i2N^ƭ\x,Jñ0h\kc)A{6:q'k,Sb87tSaK< ~0grnQnV4 B|d(AfğNŬwTߘhˍMKUkKBje_Q`KXB]~$`WT8ۛVo sQ3Ki^<#(^Ļ[ <zw"nyFH0u#bMKḁo %]iΑgs/\^vww;L 549ݵ<oO,Ry6@aDTs^ Be֛/] nn}2N:P|-O @iQh˽3?؃qƎ^9#Mi`B8 ~Ⱥ /8ZgD&Κ9CbXN6"V U*hZ(ԑr, 0>QF Nm#)#Gr8[w% g坧Ƥ3 } !IO^:1,aNٗu=drb$ [ Xަ+;!jLr-XŭJKjJ@H@0:ɢCkToyׅ0][;@ft(5.Or~^fT~s,kKf[)xZV<ı-u37~A t(#\1 kگ[)?G.,"y5Z?Q Ɗ\[(U-Wgiƻ BKʄ!ب{+w~݉]h6}axx2٢.\5<"ܴ4GtD &q0! I6HgCdlwDfǠa$-( "D S(&"\:'!#ę]?=L 4Tȋe6$\ˠӹg_"6L\]ͷѸSQ؂'E er$y?<77T{<;k-ع/]DvO@Z-~ijjZߥ"q/ J+}]2x|j 4;RέZ(ݏz1: 9X 53HVZcgCj~ <{̒KD!Q,,KA4)ǴeAm%rn r ,&ABp]s3WOl sp 295\5eo jnS$\n ޯ\O}w͌Kh/£  Ui;SU@-Tfz%hUGWD0s C㥁]xW[j hN?{qSØ>9Rn"]y{7 %i^Oϴ"(^(G˰W5LpRĄgdHh5Ь1Q^ҡM>{۸1 $B.}d ~)SvGOon- eT z)+^ .k zXz^gg7ZeЊhԴ}^`3筟ZTj |{P'ZjMS#4 3~uHrzBdo2̟R`DCJ4T;}깅T זw;sbn|;Qjڀ;w9{߱3\ dC#dzo~q3s'@K~i/+p>^wΖxEGY9GqØJk qYW1zqX27 gZ&|ǣ#0'B=g8@W:#cI?4VlᶝJ G;#rN>\oi>ꢵ5rݬK/__\ةԲq{/ [+:8AKDX9u A(=mNqtlq6Z> Z6I0c)ۺGT/iW^=bfUz 0DXnm";W͙p'o͋=rZi! 4'xB h;yIl^k* k)L9¨;N 2hG{lOWp86ܤeZ*ĒN30s։^t(6'JwiNjp=1mB*g'_h(cxm-$I9=}4?b1(!"\c@A3 F ^԰ 6E@yP/bvO1U|_DB[_vnesҙHuAG)`IaM\po6tF} _= M'ݲDb!).Gsf@ÿ/^Z F+F DJjڭP9k(˜.T ~2Ukp;+VA kBTQ<ّ󾦡S"O2TYƕM/{t,5 {GBHE 4G0njpqSEO۸];?@0sͷ P0j3mzE<'wX6_/'"\*4{8Al8I9?*<-/Cc(<_`]_iiy$usscFvlVB;j+9粂g׎z} T N /Næ,05"t`tCd "}i:S-'a# _NN=;qB"ڎc=VXhyҲ;LYmMcxšIBcQk}{־2R74hQ;1K4֜JaP|5<0kHrkt$h^[_l78>3o逌pn7J$፟f)bjv@ET19X2r'! ڑf26Bh=Fxz u#ʖ@wS9wʼn|N} C[d)ц=6;KN4ȁr!xhY.B^9W?xЕ\ٲfJ3)/= yBݧ6XDѧfPB_F6Hcr5J e}=uтRl9y<8%SmqwKoCr3ʑW eutsxmU@/Ĭݬ℆3kyf/O} -Q įتi8q͢ws53R(q"<"tEeOhM vdss5:,G8[Z,AIx]MW7G':pxObGZT^_)uD`YD cyC2?SOL!D3,ꔢe;M7HY(fztAP "ߘ?wg(B?{GKgw8|G:>fM8}O'^K˜q qn*A>E|zT:e1e'5c2rR3a>ƎAC2(M<4YN Dqʮ6:A5LCG,ȹt6W!ះƌ,S^fx $ɱzצ9ŰF-A*$$Sy:r*?zC S􄓯=9cc3w,MPhKjM3aTMFFmGʤ-3(iVAuBsZJW 3h|Q߈'4xNX@0%UDb#y/BHtGks7u_тv1m I]ȯ F=ǜڃb0v1*$0dFAX;7@#&iq@k ;~c&f#8ŸU}~+i/6:oI4i5GgnrNG:Uޥ3arKxO M* !xáE=Z0ys~ @R FAs JV^8jvMz;Gb陛+!\0\]og=q 9(܎{g`XFP3U ٖ([0~ diWc듽2N ;J*/}I舤$]%dkί)xݚ vH!P+#Ϊf#6Y%Q16@,2j=+w8'*UjF^,9mo#uvڏg?lˈ .7 ]JM%+!Iй6%PX#Yns~gkڦ9xe瑓21j(Dg{psʳQk/-lj"%7r Rv1Ns]2}a5)|m%(VȜ]N%O+c]MF9zl#i9 f*͠~ o<`mG rѠnȍXCIe3H\Ɯ5뎠}5J6ZfN4uD:cԩcs;&*} JڿrKl2߽oM`:FK3l;wʆ$j3kDºuv .##Ux=W[3QP3ƐRpVӣ`D٪zy!'/FF: AbwWpޏU⊠SjPԑԨm!lc˷ܻ6\ 7DΗI,7e-Ve_vn <, [x%ݡ"gK> vVl|V;9bWjlY!0ڶO㲸9zt?!)rMZӳE/.ރɆAn-MB;2ZS ,* !άs^Q kwe}Om>`8QlP'd<0y >'@H|n>bL0J3)fC$/\D3F+;5daVw ri6\iL,&jy5Bc8Ź?OH-L K D\7]R˄δ u^V6 vo eأ̤P|gU{}:HB雕F{\RONL9g<{M -k۷ YkW}%y/fgKDzK $1 Q4R F{y%44'UEn;dTPgsno]) Xf5Pg78&pQ\P1*H s,57(X%{3 LeTW17&â?H%en=>l8q nf)9\*[G5IH^e_iPviv"tZMI@!Z| PJ*<@.ը,9 8貤p|6YK9' Ʌ'-ƋˊXcb?j##{bZ(c!$mr c[^ 8qq*R@Ѡ>iL8f. UOwKh 49"%QK%!} +<ʛV<ޣR fw ʳ%$}/^[~%!ne_%!ŭ wC}@`zI\|/%a>ڰE Y4k='d9T"}kl 5uI"Ċ,2[L<^*E2 N52B`•:|,~9Wf]. Fe'5{S.5I ɱ] !̀0){p!0aEHHEmROp*03;$ȯRݷ2ÉZjѬ*ޘ 1w㺄Jt3orB!ٕa4bxYs|b'j7m=xu'62q~O` =鈛*aQÞk@S\yFL}OKOFn'tMq pb|DXkfx<}JD[l J ~VcHMcw65T,vgaE)U9DѦwl]?u @&KԾvg$پ4ӑ_ 0o?)ʤ'OzpD,uδ/׈ *]S+!|η]Ј |_̖~q [Nz0x?L!Pp%^d[fD'*1fs ~'oNIewYĦ=핐lߞU`{}c\ 8DyI3ODT *~YzV1kYc"ٙ6ub8 5WiI,ʋ2@߇tW Ӷ:fMdQlI*o:Lcc|4}0HԒX-uǖy`Vg+d_,l ~d[֪=R%4q>> $0CO"p#E,V~[;➫QC9x\ \܄emp[ۖ\@}/xWP%5},16uԸHFzGn[jK2\!Df}i} AӍxsХP^\/排[[[!x% oyſ b+:Z[럩cXWH3Kr aDq6bHTPӂW qQb8 |ȇ饔;QiڷBiF8T⎭I 7X.(;QQ<^&`v[ҿdJ\0FŦ !Gs:ܬ ڏfN4Z^Ғ(h$2q̧+mK%]>{#܀sPX`ucԋ?.sk͛GѨⰘ_>al<$JWnI|:\!`mQJfd]E`g\%!?pdV-5xJ f`~͉MNDF9 |k@\9KK{sw]KjsPa'Κ)1%̈R"YQptrv@Њie8X˂$x<:Ry低2 /5!KEl_C1A/=~p[t%KvC6qV Eϖy>uCβ|rPS[`7χ h{m815雯 !Axh-A6ĮtfQ:**!wS F?l~0_[J?3$ne"uT(ËEiWÎU5 H%3ΊA1W0 Ge8 [s QcK۷X.cRkJZh=Lv}ˮ_IP-S QkHAk7^`ric<\QVe&%S5 ͍]b ^ք}&1x:VZ gZ# M͡0'I6%煄·/g1ڦHSGAsx$G%yT9o7^newdu`b+L >N$} %TܭQ|&CF*"^6Zx{cdJv7MvJ`Xq\oMI6fM~.:u=ۏ9ލvo|<ޅSJ eq{Dkq$J [J]fҳ6YUAPxpڞzE{K[Bɾ P Nur,RӨ3LECf:[AyޗyO9 МF\$ELPg)5C+ _`Q,TV-;ǕӞQpy(_3dS80/g%gɟ߼#U?Iܾ2N0D,_FiLʧln1RMx**UP˶`60tҟD̍ij.Rhʵ)j _$PJ_l!m2誔KMfb$f71m]5 jWc7K>%R#_DJKԡW>a|?bB@4 'VaL} zA }UсT)96BM =x;h;a1{ \jU ͜4A :"6]?&;TZ{}BYӵޟ}K_,?c=2@<7, ;NOgdHzM(+ ,2 {{ۋDR]Doh~&@$TioBMqA;&NR5x[ 2x"[k9?/ /E} Ɣ; |2jSIclsog=ZdS]ԖoE1޻jsY_BM!'F%tӎU3xUu~|&FJ\NYw9ӻ8!^lγ~i3 KC fZs?#f 6IYq!KޘAvXѤ#xĞ?}6%Nn  p뇇i8e5Q9agP\&{ uv;*`Gw8'?QӋ~meS6¦›Ern6T+hmҁrzx~t379Zcn5sB壶 !Yl3g_ȹƚt8 ~_L(*JAQ'/}G13$fO7*~GwT%PuY0UAdV(yҡ[e,/3jOjd_ܧ! I&uNPN1q :k4MVͬe+|Y,P֯_ ! {v.;wn#>ޓfl ({ m):ZT 1y{DĴ7VI-stg `\q75:B42J JQ9Y~ɏ},$~ d/8naΝz8fɣ-Z5sKxB[=1y$D4 ,-!9zZ%SN57g5K_CiFե=07vvG׮zZhHm7dmz4Ѓ`ztd3j〳eF Ҫv̇Il`/`T;dxyj jAI!h{O-AW'Q#&FHs>bI9Ge Kg&V@2$  (%bYc<·& xwnpcF2H'%}u"Nﮔ7ok,hM.9da ;W6^"^ 3]d>4 зczN06ی<ö0CȭK=tDSa|i,:}=T*_4xNy iggF< $e6 j 7,WfZ 'F6\pnE!ʧ>o)c[Ym&H5oӮ̒ݾ 0[ JsgPc.B:>BM֭\C ^I["qwJZ̎['Dice*t(HGp) ."v>LЅ;Ό>(}re+6 /]Χvzo:򛏥azΗ7ݞ ~XQP7(=z ;#xB;g V,Srs15D):]XxT(  {Z,a爀(Ѹ#_-82lqղlxnJL<v;J x#do>|$P0sэKltbRt f(3?1x$|8Qڦ2ppV`?f,YA 71ٌ0\Z֭VG:͈Ԯr}S.WL7Űxdm9V>7f2B߫+rhAy.{m  ׶A7 8aIwKb QzE=@"Ec*q Gs۠G{ uo-+xaۆ>< |b5lm&3+e` VoKzSW\(fNt[+oz%mirb}sD/kLYB ]Rњ)g/,`e@RpODJZv'X3 > VQjT|J}cw2'9us9cMV ֿt/lũ _ތ(?àx(cC=7r6\,e㱞z`y@YW(V`f}pE0Hqil;)HOi5;ZFO?CUYѻ{] 3έuov`}{y  uÄ# 6]7G#P$wȠ=.24OΥ\tWPZnvHMt^2wD󰉎T28ףܓ9]*m`Ԡ%knG߇J%Ga3]nց ڙ:d;'`w$>:}}.'yVYR]:IHN/wOKR1&Uu_ougtr.Ϭ9%LOιEd =S0e^RҒΡI3 I`&0!1[SxBhǵKT!yjU Da">O֐'B,t/(hNZ~;K"/e.0HJNRގNT9vr bFWE_~-` -Z(G5T?ȑO &,`yfl.Um38Vچ^;ܢipmUK5uQ{Iec0 4 !Gèc +~ur\Vh=&Kr8?::H afIgJ~TuY&9An $4@HF!/pO͘=B"vwHK0A?:A)#H"jkrRVIc1+X#G,nPs)Hp8cݴ ZBBjd6ke}m,Z*pTg60z}.9 _ӵwGS!󸳢,3lVWtJ,An>ffg5Xwb⶿_f|@ǣ 1l mI1!&k\: CC:WAn0ݪMǕw0i/j[]b 7>- DAw"Mp@+(%TҷARL,c%TT=Qn'C97"^K(Z5)uK𨍖0U 2F1۽! !MjTOkc=ֳ'gV9@>tډAjlruEGB0̾\S/!di\JM&Ь PM;a/Ei֡VF~J5I9VAlUbfѪ q{w=6)=es %Zsl`O+AdA# Oy;3KZL0$,jp9~s-b-@ˬX+on7'bKSw5!#B "k^_ yX"ɇri9;$!';}QOMJ:%RO-^, bPZ#t?%g9aZp׳)[vӺؔ;,.bMLuG !M+δdt,}%@#}V): i[&r c?}%$9 BoNJ+IXytbGcr:L[e&g{St_6`h/ ~Xд ٞs5UщU,rtt$OOY|B}Fc B*'Uyjsa>|iUiM{T<̽CCP@': Ȗ.uUq;$]`7h/G#zcR%ION:o8_pS(PO[\Ein&'',ż$' 30 $_:;C`mt]7}I"s/ #Kr4صnk\n͐ N?RIҳj":5FY濆~SWiteVi轚YF;.׷1=(w;6XW,8 WM1ZbX7E#J)I"Q t;UJqx9yN5 5KLSy5Jcߦ xDqdo2wVݚIJ;?+Cug+DO!ABHa@[Npm>DCBk f+Ѕ0C?" ( Sf}Rk''Z'muhqu+{̉4wXgJq3g|`N v=iܑ`}~r JpHփ }M|G VLO}ZRK.:q5:~AI -宣)3YLSƺR 6CSJ:ԛovd1n_ j<3z-bp7sX>B-:_sDzPx|E 1E.'!$RK&=,bq(!ˣ%qL FՓ ^d #wid"IP{ "ܹ%'7zcod׌>tkI.R5]6|jsW]g-`F1:](9;Y"^Qw.*ʖSֹR|SEC[BS4] zQ뇆R,p9 xdN=%`byR:8DSOeO5ܾN Ap+'KN)p vx*0ze%%/g~ ـU>FɯJi%Z! ^M~bC4τV3$J>'3Z1Ew,:LlSs9V’Sfʼn1e"tLİ.cbJ4Ӗ{a|7 KO\ ~m}gl5"5]d66$3]qt30ETn<:,2A]3i(չ1M̘Z'^CX1eύL[B~wʇgnQQD6Ci](R$7!;4L׊yDiQH&ejSPļ1S򱇆xѥp}ԥ͑r[U;F'B׍⫇9jYIBi_\,Ըg{5xCIixbiYJUOm@7CdjLE22/eN"P4w.a4⠉)d+7,{#X,O-Kqjcs5$jb✀"Csg+q`\G?k_:~A<ވ>]Fx6h: Kئ尨_U U8?#V|m%(ȴޚ+=12',#u?Itcү1. {Z !B)\|ZvfiN%2"cv4IvTA{vI#Ye{.-\N}[NkM?Û؞ PqL8n; BxWϧ*LD%0W3IGzs3`Ug;zƠPS[bڼUchnĐA"oFp mv|Wq.e爔^[oW#@̷q<aw+V6d eO'I ZW.$f ɿ(nJ:m99.v{USCYuufcQLuה>ʧ%%+FgEQh[Y;i Git*B8pV+ɛ>6cp%u$Wlѭ|A {e&&>{fJP4MR@ʡV&8atfW%NʙbI,TT&ԓujؘ87y?^!O_wZ2qCWڭ<4lz?MZl)8IYrVsPyE)AV^mNΩFw<'ϩv&a"12:Q6hzm򂽺(>>ͣ l$Xa*/n6 Z.Q'&v:!*;P^U <$_ kQDYcœ?n]mPcMt,G85xiAq/) ;5Vw0">k.'LĽxOK !A3yvc`8IpF{9d5fT7j|HN4Yޟ|#>AqN_%7caLlQ ˦'&2>ھIR%x O.%i'S)מ:tjA[5|ń1.nwS0[\ =:8*X. .9I^g>3I EI*<,eL_57FCit,>`+l`d L&3H#֢Ddf*ݩި=➕!>vxҐF@QٟId^&mnEy)/{:||$hwb7,,ҫ Kwm n=XYljWb7\ZjoGJ47O7PCsZS:p'BzZq[+$F `%Oz?) 4}{y3 qJ_ xwŀ'B\'"η@&[|IǍfQlr}tEf]QBZڤ(vyxH*'#_3 9Oz<4kz,>5hjdƥծPbwIqEyXmAl s{-L)*Qb;@̫Dm=x8' l Yi}3+!FIb!gjS7,yPms{iG9L]%2lq.~zTiveHW! {UteUwHP_{(wŜU~m:>$2l-~մ+¤lxqn,f̼ #gBX~@>:|LO O?V(3f<1J^Kҡa;2N nZP˭LDəz!Y컾5=~\4supOok7}$bEBshrF7Z^d[_А|´QdaYҞ--( ػUaaǮNZ`AeԓT,z򐂦_ xْ] b&s^r(J$ZAz#ln@qB|2JM C;K2}^.A/TVJ(uU';z;NPMe?;mN;}Kr*;GI9nѕU^7h{adaJc&ʼw_)o?1hA>;g"uF>>%#Ww݃%¨SFIqzhgLmF*evjtb]] jW-c\g 'C\6uWCO~q 0@󋗙M3 %$A=nk 1ߜ?Bߞ:[o5Fej6| @x)2C[(Զ5_M4( oaE.y='oNM C6T_$1+"]-ySC%F?,RIR1> [ט[?O݉֓bSe6rcl髃V;j.4zC2"G=]friM[LmLd Ed)y9zv"^ڄ VE)tsXA@v񦛕gʠ\3"~Y9t))0ȼI7T=ڑ&d6=.*A߰=ʨL`3qaAkIy&|l` hʼn\%@8{%=m9{JLNNlsm0xӨK䃣uãǜ+*wWKd; r$(>0zĵjԷjI)?V,8ifլeG:3L}?:Qᔉ/F1 91_Ѻז+QTRdG=Qc4|(C֙Q{Aϴ}$DU(qhN/V/' dž]DVYH1 lSl;ڜJyj YcZ{&d+gSq[Z߉,TMkjDBF5pg ; nYl+92>r%#ah:D%PRAO,cѬ913bwzhf8VYI*7]L {. e}>+3lOvm-J,Eycl}d'$=N3*XsEƳK:++DDl9e ,6mQ dFkt6,g{C1&Ohhȳa4.{ @M3DЦ>4V-ޗFrlջn̻HtXe8ڬ@gNҰWy޴G{b$Qʫt5W~zs-Ȥx ZB=j c؃ίE5( }X_D[DaV@7N,Iґ=Jya,*3PɱE{#鉾9 <_1_ HX=Z41f5ܚza~Tr Al?EAnQӠLs"1 Sh@u]͈Hmg2NݞmJ$] 1c[FIW 7uTz_wܧ6* c$źQgD4Bh?N bQ;0NcyHdmSg 0:U<1LJyXf;뼒λ|Z(m9,loA5tGYe3Ճ#7V#2>f׌UsLsT5ZCn9Ѱ-P%lŦ Z~X5fk'Y<Uo\ ؀*nmGW]óâpt![e﹬ChHRƫ('%bG*wc#9bCl C{@[EP-qSPݸTڠ2C#f4z>AtǏGho ;% 醃+E xx8<:jֹ7t 8H H[&'Ti. virwrJC_B8N M.oUNB4ͼWG#l; 1UjQymBE^B7崦t4T\OE!_4,m|c=gf%cq|eGV9e knܗvVc A{xcƢN$5lC9.PՇf-Hɩlq[t[lRhi"&cdv79[TēzI?AY J}l8f ;B;|dMR:CG}D3҆0ЪŠ%xo*/3.GZ|v&"ȾcQo bʮX ?~7UcQ0|"l6RYY9+EE,uffrx_yŤ]̓ :+Y5 '=S#cTB"W 0f 9AsZm3'zz 2C#h'4Dz-|48+`6:-SBP|rumxj!zލ} ʬb3R$-_aElcZ HלOO߭ C+%ȕ ~RN(Jj?.v"@3fVW 9FHӝ(5xc;xDi9a (zL q ,a7~K@\2b*q7/&kMv /p,K_Ĺ3b&ҁ:͘)Dbc9_z "J"0 T>pq+Ŵ@ \}F Jͮʛĩܔ) 'IުiɆ f&`[N "e >#XLFZAeRK|u#j%CK&W7V7f uyyF^u'fW=WHj[<ʅݻRTS y{Z+G癎g]Βpv{uō7/&CXslhmg?ċ;ԚC'2ωNv@UM ^D7[7)A x|&E>o˿chh/d6 Fl̵WL11oCuShntu/xSʦ,uݪ5‡-#۫DR5@TNy4K}@&XQDAi%qBV8<ժǬ>rxWv24;8Q QQgrdz;d6kgX(?4n*v8ti͂%M dpnWizD8N"ԃP',lEx,JN*+^_Ps aCV hVX,N'ε0a})Ery:]L KĦxkOVI58`Q!ޜu`oT N”će$-x]i<"V0X~JIF*9#[_־#,TNxgoLhD&䗢I{Dz\ Ga1=󝤆\-6Tٸu힟-Jb 2=DŭEBl/Om(nfRҤZ[ ke 6lY?>: MS?!=`1 aym֟n3RZ8A~8#apt~`p: h/ջzjlOEٶoH.Zl [`4C|Zݰd3 ҔyHyAGbЕaĥ}8>6g7^mxΧBLƒ8POZ?>&1F5~ORy؍qz*9-`fdfr WBюfJ .}Fb"0h# d-`Rba$MK@|,~]r08[RL9 g+rLx5v欂y=^Vb#yդt76qũʹ]蝃!)23j^.u׫ 69Q^$\jRGUNsst H9;fQ͔R^{WIkx,ݸ?9,y0p'a _9g‚ԙ`;ǪܬMTʫ9<&*8!rϋw !c3GVOsf.52qfχ|> ۛՍ~xrq(s̩ HYO؛/G<ҕ*l  "ngǃvY\9ȋ('ya"q$,n/ˆ@A~Set?oz5c~:ގ;#Qۊ)aI߂ZiؠxDxn9mD-}g U S@KUu w9˺tEVDL&x$eF+oӷȖ4+;|Y )Yu:ҧdX6yc@iFOgV2~Q! aX<#,}(f8jU˩D*[ G٘{t8kv |I"P2=X^fg,^<¨| gSI1{^di ت_!rU*Hg*큅1P œ{\guߩ{@\IwE,J vj4ǚc[\pwpMi|@^g*?MGx,'rMe]s,Nvtw G 9^y_ƨ]3Ƭ} )T:J\o`}-'_b"!dZhpWPG/iy9<$Q]d@$hsq&FQ/1SN)bՆߐ!H~ᵀCqZ/+)%n^ŰeM6o"R'G%)l /glK5QHf1+V:$B(^PDoNt3.XkŪYdӆ?yq50~xJCK'[n0%N߿ 5vY D/F8j06#Vc _rgC$>v3ܑKvf  tq>n^5~N81U{64WG /v0w PXeVxx׆r=W"s~PAr, yU,4LX OB%7:igpj|!*PqiOy`Ka%bbm\;t1?Tv!v0o qlf Go3SgUi?yѯ40%8CW&![ӗfDj;>WՉUefnP73m,i?ĥO;hK6DZ:|pGnxRJ!p_cd`g83:*)N6"k` 0)4ś؈ljO^ XWo ?cu3pSUvr>:* %Ni!퇃=í)Ua IDe.'|dhy[vt)'^+v=vЄԨ8/L!K),up<|l bB+UaȎxrWy@Cg8v7[װxjJ3n'X7&T>v(R9$KlRzY c_he| Q&X`kVz)}㘡t ri1pC̃J%=IϴZWb$BA@HB!0eAxFP]+K+,wjqkaHKEQl&Tm C*ӹ\nzC1V :DZ;Dd0&"1s{sO\ΥB&%rnz/(g1T"X'B/aNLqh> ..$_,G*'6fp~i,- ҆(^cyy@/|jI #/&%׭ɞ#e:UVUv]pEFN%nWQE0ͺ׏[ǚL\X';Naeܞ0N~pHV\iC7m} /Ց&]C})JaiDgď1O~S2·H݂rQ?3-~ecS)y"kǏA|([I^FUj$>ۣU$ߴ1zM,;a浕ƂqvtlI3e[`ʟY:_[7MX,7)p,,NfOuj@Swt2`@e+a{۝T'gg?GU6KW.3HOË!cdwܕw~oF B]>5G X8xU.κ/:$OQ͊Klՙ.5B禧)gKڛ3-849OMh;(H/00)7x ͔cA!gZhC\X˖ DnCV㟣4hso,M@԰$6B@B$90[%+"iexPIF(eAX<srnȈzhحbsa8*ґ# D_"ا1 .9l c sdֳ$DޛV]i.Q$Pn"om0u"Ҹ*DS* KU|IkhQZÎ84܉!dPqPE9h`ߚܾ<2PhV;?# ܌&`4/%J=˒BUșhXZ*̪c3\N}smB?.qÃj'mN拣BFHěg3fPN]fo2-p}GOmݠ<#ͪ- w;"ѯf&"ڮ"zl6W9wZbn ْI#7&!ȃJ.`n0%${+9ZBx䃇;o. *d,R wfY40 Wd8jl2#HK꿸/zs{܃bANXD5m{OZ 䍜̍І@|YM!]ϐݠ=2!7̅^S`*H2! Z9f͸c8PR5v51.U_$4r7P^= QjSg׋ | Yb.p3{o]c{\ss)!xMl~zu֙W1Fuy@5Oe1IjW1z\ͰS;O~Ӱ`<1}x5AU2/^hm$V=(\O©ʝ,/3b* -3TһD@V3ܝ%4(Ѐz@oC_]ٱlV3پ-d XQ =};#@3@+b<~'80mdXVFQKEkei?\ft<yz 8,˭ %uSUquWĘ+paa0'+li[I#Є_R_x _% f|&\Å[{.RA{l5luĚjrY7V}#đm}id-7:x%08|BDDb@M]+`AÇ/%%n`#\K! QF5<>?\yWmG'(dG&&p%[Q_/jbW)J}Eƒ/tqUu-RWضFJ92{||_4]$Qr'0j3ƟOM*m h>._?:ڄBezATa r\{5pۚj8P/FzIz)NJv$uW2Q׊1YT=1:{e0E&2օ[9ۢ1VfG-, O!D+)΀Z)5æɄ~1N.0e=b* H_W10!}щW;njvLYt* *x lɗbG=GrzL "*ZuۅLYͻk>l)w0i9KD~PS״V]r˲zG7\'kh77ClR|m-bG(Bbl6i,z.hT #UjcxĢ$P- m%6s˟"XtZ Ԧ IJā>ɐw% * $X@1>7KYbyJbÀ{bvo*f~pr=;>F^JƳR:]=\ ''GU)| ~gT\D_̏cz OІ4s!h;F ТHN >gї%*jSWB8]bX|ٍ>~.eG%Ӟb$`D{U RsN~f>(r8&Y:v9L=9L-7Èܪ͑H?G]8w!U=Yw^KY# QX(rZ}?  }ѱ^x־ W:dv B1(^)(5S>P>XO»O/"Z;f,PP0Ϭޡ7ٯMl4^YRL~wty(=v2!Yk[-;Y er]\Z> 7*%8y97%y?')[\#avKt:!=fT"$h0#w 6MmjI_d$us/x _alƖkךo۠ a3b<24 ̏A#ފDȗD;MjF>%SP.xF*;0 sY%ZU)Cx|.yeg5 %V1rZ3ɥ݂?F%/X6TU.T:uNNZX`[=8|P2tHeoF<ԺV )0iDdA.Vôa ;F76_7v ̫ؿ*l#bBѪV7 u Sl nx*|//IY {tlER- A\ޅrvb- Dz-U/ lcQYC7k T^3 kշF BH( =}eRF`KJc`ȹ}dܤ{Gd^WMDc qg%~r {wQJw NkO&ӂL_`{"WmΧ\'$-,YDh &XM~=guAL9p0Iu҈e ATa.g8| jdv|vy8:~ o)`^g8E4+|S[b+t`Ld$x(ƩvoI!7bSP% dxLHAk-*ԕ_UTw,O ?PE:` >݁N,}G@t{GW/ɘQZ'RFAx{~Jf<͹ڋ։Mubo3BKwO\E3]S, Bu1\{EgB\0&y댓wDqOK7N ꦀ7@>rg4 PÈ-Rbc#2}XHs JCJeĝ߳XMxj|`!m j'hu|,2^ԛÿV()FZl =#ܴ=9hzw^amZ|Ċ]@α[N$@T){o\bQ3'8yc <96O{ b1 JuHm&VLxd?Z_~xäa܀lKX8 _''}Hbh^Ǻ.S#l5a]@P:,Ew$bCj+/=Eqr^;}W4)ڇHBRGB #`\* \S POlLIH;Ϩ!Se"@'ܠV32qs#K:ǿETsNIMV0FrOCWWjsFϦ] w I1HTo}WeLH.+k4|̲CV/EY7A128G2D]?z겤Z=H Ymn1FT7]D.?2_`{GNvL Ӷ߱5tǨ`,&6XgkqҢ3mò~m44iMrQl6~gH5νNeyPb)^a&W%O-u~$r&Ii/fpsfƈ>pj.NA9S _s>N*ωD1i5~~GUnb=p1/EGH \Q)-7i$qlX8?Q9:\ •v\۝H nxu* {)W7`iLDG"r99\5; BBv^ZWOޏZ"X_&ҺXe(ͫԾUu!r}aqueld#)ΠuPL4X`ҝOm[^g r=l[QvZ;}:axf8JW@{3RkR])bNocB-^ 97aI9=C *OE,ykqvX]16M$a^܎)Ɯ"#YgYyrWvFGH,ѤrSz,s&=tȊSm#eߎ+#'?dp8O&^SXY>yqW=5#h@roTPVq)Ö&zXԘ$.#_'oӠQ"xtsHxuޫź[yܱ^LL*n^(pMXU_ @#+kZ,kc9Ã㌪Spa-?f., * A_;;[ E^q4*a)"),5Yt9l s'̪T͊=OP#^T 3藥*ɈrK-! ?oq@g@D0L0Q+aQvYbUO>voh[Z|3z̡O=d /v8B8 _irzw#TbzxLZu*)D6ފ#!dHIТ#BwQR &򔽊ƞ7|$ă(Kr͙У֌ko:Rl,-Zh(FF3ONp>@6oIagkeG:)6-`jPvSLEEaUwv Ԣ_r+y7Nc{YҸ}ca2V4ѤR F?pi `nb ?R/Y/~JkS*E>Wûmm }x_Ykr|9Q/cbXk6p:zU0';IK^ztp^ JN V20[&Gͨ[jn(tHc%1 Jh鐻 :9&l3t Ռj\SQ$(xI [yTNm0Xu<I1Z5.ɾz#/ٳA<2Dl;[Ji3Oi'i!kV2/5y Οt[̝X\ܰ 4ӊF*.{\PmR﻾;G!TףapqAx $Q<{I@qڏ]> z]TRIm~\({%7"Շ%wqn)5TIV&>QS;~ib <(lxx^dp:_eyټ{|-VE!'6[ʕl H^0X.!t 2x ?V)`؛gZK M'}3Sy c"37m!MAV'o!*hZ(ܫu^լruroh$EcrΜL^c; s/GY ;P/Ll욟>ExB\9UQj[@i #h11sQ " K5#[,ykVsߊJ吤 8xY1+pa9G9y 6r%}8& Ma,;GXa۟ &XC-vd66Re6 xVSExvl#ݔz<0M+PӢp5st W Mxl1 ޹$іUdB-:wjbsu!Nj׿齩^ۖX]BPX P.ڣ؋%E*>#[`j22|`R־iv)*a>B@KK 3?ML?%(* se:\Ozu^Dە#J(̅E0qytR?+B4;3t͌X]͛:\9`Lota>+cac02˸7MX)HbvV*6RZ}| worIW' 9 o$sB`d5*96W}|0[=p3A(Br VpV'e%oDļ' Up\42 !0Fn+08pџxOd0#C} Oب[]>&nXJ鄍ʡ.j`ĎsK>[@/b̳fCcAfcVNN>B*c!<$E-[L:<#ɷN- \z%AypD't""+p*ݥPxb1{brH.mN`lcNv &gUԒGSEED)͒guѬv)@OoT㾯蘾Xr4g J)9>erC&SWRĊQ D,GA(3ԓZu^V\ Re0m1dJʴ\~T@[sB7e8 (kkF֬_n[Ǔm}&Kl|U,&vs']A1Be;{8Jp<E(@P\Hѝ3mĥ_'|c4`yXvB+GR@X#>r_grϽy.3J“xFxC2ѝc3)!'D'~bX nlAjpsgq+h[.*''Vh.|E6PQϻFs"fJ υ0IMPr/e胉?n$5M~3пYFa>wsd|EgzYl~MnÐS|l;95=dm}TҜE5:d^79Dֱf G uZQlyD,Lc/am.Ti.%#3p=;GT+&ZM ~. !)3U|DxUc?qz0i8*4M#u@0^V=f1cGW%Re%}8%Ȫ!qq<rYG {耰1+1 ,a-p-xZc*ӧ"m}NoE[YV;~> TWQ$4`WP%# C4%tT#(61лUB'5;Qxr֭>>c碒d*;BVcGM,W+-#NXgk'N*P|N, Q|34޳YnZ7X*?}9gOw9"HKSwT=ms?ݧXqko'|v on@1ޠL/ǷN)ՋR+ +ULbo},XFSU锍kNoӖaIF-2vݠT7=쮉N1#E :tWIS h rL,8ϘtAS-6s.dV4'yLYy 6;yCpH9l_t@)z9wCRQZYO(>S>ҨQrd"#6 Kjv,V_팓+H'=@F2HЋˎWO|Ǘֺ$p^ejL;`VO@:Q6Hvӆ2B&,61C7?pKAޙ~Sk-"j`E*(T˶<Nw05̫3FŽSl~!A+$-R< JTՅTw6~N[7oRroHZB)sEuxJ4v@L`wȷK+r3ƯV%sx Z"\ٌ^ dƵ`pAĂKч5EǜiO(kAHeJul\t3n92Ά euq`V+ W˜wJ3LJpPGyK։,7!kX*>@Yf=ڑkیJAǞo evoI/w݈q|SJAkkALnwhK  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/res/n021003l.pfb0000644000175000017500000033506610725114532023120 0ustar twernertwerner1%!PS-AdobeFont-1.0: NimbusRomNo9L-Regu 1.06 %%Title: NimbusRomNo9L-Regu %%CreationDate: Tue Dec 31 16:49:50 2002 %%Creator: frob %%DocumentSuppliedResources: font NimbusRomNo9L-Regu % Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development; Cyri % Generated by PfaEdit 1.0 (http://pfaedit.sf.net/) %%EndComments FontDirectory/NimbusRomNo9L-Regu known{/NimbusRomNo9L-Regu findfont dup/UniqueID known{dup /UniqueID get 5020931 eq exch/FontType get 1 eq and}{pop false}ifelse {save true}{false}ifelse}{false}ifelse 11 dict begin /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def /FontName /NimbusRomNo9L-Regu def /FontBBox [-168 -281 1031 924 ]readonly def /UniqueID 5020931 def /PaintType 0 def /FontInfo 10 dict dup begin /version (1.06) readonly def /Notice (Copyright \050URW\051++,Copyright 1999 by \050URW\051++ Design & Development; Cyrillic glyphs added by Valek Filippov \050C\051 2001-2002; Numero, infinity and Omega made by Dmitry 40in \050C\051 2001) readonly def /FullName (Nimbus Roman No9 L Regular) readonly def /FamilyName (Nimbus Roman No9 L) readonly def /Weight (Regular) readonly def /FSType 0 def /ItalicAngle 0 def /isFixedPitch false def /UnderlinePosition -100 def /UnderlineThickness 50 def end readonly def /Encoding StandardEncoding def currentdict end currentfile eexec Ѳo4>ì`0CWk Z_J\7T?PHSyo܌K8AGy+#Shq(=g<IˤuUb`Gu &J:+n.6|kSot懪ToIpL%p1M?nj{& ٸR<@dR/i$+Q WF!3|J.iZB@^pNF()9`ԋ.Va|Vv홫,V&!X ii@X4 g./ d*LMP 5c˯w[2ԗ8{b)c]w`\(=Wk|wMm!K=Nn,uTsЌ(oۿ{G5QV.{|2kO_Y-|8$YΔW=8qKAQJ  n'r%VnA8=@tV?tRYa7_݇ݏ@* `D$aa ofL0_Ћ-&[ L72c[;Gtn;C<.l1zAwNlPeG̺w \˱AkH)B~=,eK aecO-WuMoF\!ؚc\tiCaɹ~ݚ)岐KLja] w]˳jgsS_u%TtLr\LW4e]rmE+㾋?q"|j*sZYzgSC+Ԝp=}o R#iދawƆFX1eQj t,4 3س6U.[$zX9|mך󑡈Pl#gr 0A/|X31*ZBTvM욶zfq($ _,Tg bB: mt[K#ЖAu6<fp\94hܛ{Cy-JvWMsJ ?l=q]c"gT;Y4.|+4:<WJ=YYGPߝpu0ZQgZgHnuڹ,I~P+bPդXec<+,ۉ}Eؠ3 Yӣ {X:=KD jnIp'śR!W9dNڭ/trXy v@0vi]OPX}4g9 E|We(eSCL ˑ1*)?:D_p(  J׍L .:_#Nz-ُf n],%[/ѲǼ{lxF{Ui ż i$z>LTt/in͂ҷ\pH,oR2{RwyAYi5I7pצ~0<.̫&TE} m:,OD@0$w2x0-PN 80Rw[R [󀋇ӅtS)ۼmdyveK Y#%c@pN;]MFHVad\Q=zx\,+ѬqG]/:=1phSo޸Bh)QJzPs81Ai%mR J#-q(C#Rm{lEo S=pl(* 'l!>ȳ0iXA-E:+hU 8S\z1^7Ylu3;TkE3[:ovA=J/8_/v20M%5\ѿf.?su 7LʦC]IZ<$/&,OftQ<~ǩnyɠt_խa?yۈ}(bHg2GH8pt4AwÍI/2^/(2?{Uy#K"g>PA3FRs۩DB@>޴x+rܕ{wϥ+@r N$Wfu}}_ť PcG"&0zpoi'ЖHZFv9KyCgmH}f he='P ej%$$4ݜ8 薞I | n{6;eY2{a> ȔB%)o%uN:nwoSy! P0|+(MU 4=1;99MlAi&#hΆB$¾*3Vc$80PR Xg"u [w`OλsDe}9!ukebuˍ6g>.=X/P&QU(t^N+j)^&pN ޚraQfLV0yX`xbts8nk̘ȗQ ^l d+X̼Lqp}=MCESRKȎS?-Ka^>+XgFar)R|hb9rhnrY47q̪N37Ds^pɦ!D~cT?vXq@U~ & sRwA}2 >cEKT^)`=_q W4T,4QOs}Q*&:vTZ-] sS8~VAo֘6AZDCqwWMjwC|Y)n'6=68$} P#5[-q: xn'6͍ţRįZoq.Ψ KR_-a%`sbm|nocMۢJC"iu:vVIIikFʘ^ *-Q/L{_[.j238S"IRC]xo h0"į>n_<0 𲦯ZX*iM.QDdpR5ݜP`(6]v>eZ%fZCѦ;Y}kҾR};մ[ef[Jc pgyk叡w݂&dEL>=(  ݄lHM.z=#J9;eJi#ÒZ7Wq.`ic'&'F3F o[>}WN6|GN-+kQX0Z%x P ;ͽz]F CukV?ӁlUّ)h4 'x?q_=CtmD"sX "X7Ԅ j˽kؾ$弥?a|j~2=j c! Z,_N{ޘ6'Xqsߴ;%)eLyRZBuf_[,fD BE+T@oaw²д٠CKQ?=:)A\_lhuQ:@#U};M?Q|h`l g/,;6SPBB:Ǵj?!T&!P.i;0t|]jdoX(Sf*JmWy**Ǿ꾞bF"ޯs*71+Թ1އ%s1ӌHx5ʜL,Fo"A@'}¹ݙ2]giU_b2 >>}`#-]H5,0H W ZpXk~TRȋO6@!{$0{ԉ-*_In&(ZV0{ noa#i!kΛX@?GV˩rz %MqWm*C6gBPGs)S,S7yAXA,3MoL3,.G\{z \Ӈ>bQ\˥jXt-$Wlslo~K|~Q.YST>AdnU" pT5C)dQY .:R$BwGx͛LҞwkqjCY?^iĊXA&H)҅h^ɖ`Qfשć݃i|MDs+{!%%5vKCP[Dl0 X~7wܶswwZ5ળD5oZ9\EqbLM?|ue!RTdqiU#,鉠>6*|GL6^Z,)twɘucI(~LtT|6$p6MWyP0@}㷽+N*ln tߩrb̩u_G=Bh~T &^w9iiM!ut 8ho%%'͉C4&p$,|t+M1\iB$Uȹ<.JAUd@4T KZI7 a[)ErrWI F`CmrZpݧ)X-㒽[ve>0fxf9 lozmYлR99w8 oa5vI8l)( ͑h.bW߅e%; &HɩDwWӻSW34P',ϓr0'/!3}~e!^"eV^xuq'<}~`rǭMUh+DuN9? 3p3<z>!/c}i=+f`H0H,ڿhzZ\cl![9q@%Z͙o!eP]t:i=hMBr܌z1fM;mƓ;.djR{㐁gWȭȈ[MYVp,c *a'cnK۠jWZMk-1C#:5u{j{ݶ9HO`s~lEx9“5^qL8j, PF?hw.&mSΏˆT1G@8doK=Op~^Q_κE]يL iHa~Fcvd' #bbԉdVWV,eEj>ǶZav6˄ ܳbj܈{iX[NuJe|\sXGR[]e[^}YNSt#Imx1c6A\'etfA|v&94E8sc_Ÿ=rl0R[HCW 7p1G)ozoP(_W]%8gPhd 9ŶhESkuʀ{y#6Y[-WiExJP#+/JWBrL7hhܼbwz3}!X( LXD=Nbzq( +ۛ~̮nIJR$[)( K!hG] ͨ,v^VwjQn+b .q[F7 jXlh#ЩM&8RԎ6;%ꁨJME3A&MqTL%E?xK)D^$! ]&P6" ? ubdbZ4ٚb$jǗkZݤ;nFۋbla_sO]h,#Gm1n_wo(GE"sGSNEOU< & %Ju;nX{aSvhg=#s{è*>rT˗!s/qCO/kZ/ ;mYŕpxJ "ɄjKZd+ eҢ-o&S?R`-]Гپ72Ƹ!d<f54Kk{Z~f9lukU0?A>N0_:DBAwkI[3T3w\_9]ccߕIB[o}-n=Frwg;oWl6mYĀU?gm`b^6m<:c,C(_@_)Ziʩ1{xQWxWڰa݇fCdn1TÔgM j؟ 3^B_Ug gӟy"JBe@]`_ [ޟUj_2W;-/$Sv/R[LM.*NSJEv1iE\ /2& xW!M>gSwoBΛ2{\I_Y囷ᑖͱy󯍾rg[i_h &^Zd ˰HcjUeݏr! ?9+75"3eRFr%Jz@ęipuNeSa#ZK^ۚչ{KXmځ1j++؝N8YBR&,B="=_pwuB`(qx>WX%J|PNX.ل]3,3C?%@GdYJߩH[DpO{qpRl:3>z+Mq r u)e ӹןl*Sx.v,kuoʁ>HwHUA}+ %+8I|lXQ]_ƷB*j$ (ZY3sz0-H*45HM8 Z2Aވ')pMw+a<WPkE*"DCjvELXNDa^spf4Ɨ2g ` ` EÚQd)ZOY m`F)Dh:7vFw@[;s5:w֦,#x] p_F@ƕ:aTggڬ*,,AF±zUk1VmN7i[Y !͚h X)Cu-jXZA1O4 x>U cbjРK&?Λ`-O,!I/ڢGJa#q>iR\XuKR j j+?4HS#fW$Sz3r}ֵ2F+gE:rC:Gp ?N3N*aЁV[SڃKG!TԤa=ZK%}6pfm^]'j-fT_lY!VyNpA/?61+%!S R6m%& mS{F;h[9ik->pD'u3Ẋ'h hV0w'47Q\J* YY WQKCje /RNq53Os-)>ޏJ̩/GD%O;5nTRXМ!cMQW_lcˬmHkevS{k@KCR.v9!me4Hp%. c9GHG?h˜ rh{|.<郁dѢ)U+ɭ/`힚C1kUu8숥u/ LEy_A iջ N+]Lx|j+2*Rcn%(~-#&IbvS[1'7_x|4UT~ L(J*qgƚ;шf:z&ᾜ=Z[{~r@Q~4f.%{tNS=3ȝ-b"FXxMURwO2y;fYwz)VyOjS4jf1v>I)0(.i+?"K(ɘ=Z99bwЖ~ pVT сJU@DjCY:c}9σЃ׋EhWRE.eL)Ur[=vb\l0B/YXkp 8G.+Kw@Kcj.p~w1z:v,`!9ڔWWETy8!}Xf]Kڃzirl٤*!3?Ҍq"OiqboRƪB[uJ!%f Äk|NTqElr^Dߏ^9qVmZQ0zl-|uYA鷑⌵K7eV>=,Td?.p:QAKt*+`Y,}3̀ghcHb4 |ڷ~gPmF1g~FfNM5'fnov\Kۏsc|`@¸Z Gܗ'nh҈;cV:6♟IhF\-Nw3W~t vk;CxDOn_:*Kʒ9ns_]m_"LrHYS͌dYBMoJYG7(*_hJKvИeTlR!P J,g4r5HW=)ʄi;Fp.4fή3?rn+77I`xf|bT7Rw/J< 0%MQ^+*+ڳ6dɏX.(+|쥱ᩕ*]$}h XI~ҧ"Ё/j9Hޙ iuv!_9eo[z*3(bE ȩ:,lO@8T$-Gh+޺? hlag`^<AMQb\'JAn)B#3rW MjRf]^SF{뷟4oyЏ!Pk̒v\7J,VT{>  kHԷ(a.FOSzGJi*bߺ}"v2Yu5ubޥ;=G\!*Pe1*y>M@7]"h3 Ƙ;s!6 lO#hKl \xn٩$HgeA ?rђקC{Ŭ@,wGV wmeMDޯ4$V';əS2qo\(㚹>)˺֏+VX@CZ[Ӿv&ۭav5+JIcȫ7&XIXczYrArR>9?65<׸dR[V#64FL*5w:m2:Oc"m|(oC>oN(%X.G@h)V5#kq =NHkk%xcE+?LZ86E!N<'st:[Tib<vuP9$Wkk-]tI:efOu`"/&fzg bL8aj~+D&̪vcA A80݀ E@:Sl+,2YyCFP:}_{KI}HȠhCЗ|{03{s$wgT6L~Uuk{S\K)'U8D|_|:ps.DL{:ǗxBD 8w~ I6)l(1,SlWmX) e 19'Y1iН8oo% ef~,o!pkD+ Ups: E#fo_`5k>o`FRlNѹߊ ?>'(phw7gSk+׉[?uVyc#` !?\1%7XDФtCa 'wk7Y2~:QdErq-Aq.PtOAVΩ,$, ~nb&$s4bl߷ԣFÙMdU.V;e؅YkN B jFv3Y4ST{j@%oD\v' ؓt:yhKqQ0>th8=,֛γ~ut%d+6h@z&J|82H3AG2FN8s"(#x\L'<^l0!#8"Hǔ(<&Ja܁d <80A9޼^Aʯ0 4g_`~.oBy|`xbhHYiԑe kV-_g|['6s fko=pSePjdLzyPK TNrQj+ya)1ѵ Z6ǡ旵uBK/َP=)H͐s \9Yl`%`::pH!(>zஔ(a/[%aA]uˢ0N| %~Ê*oӸX9 " ‡fz⼭/ƭfCes>hRs4{ݘGrG' vr3ߎbZ>KJ`N$MXrXuRšf>LJڠ|_=+@zaPR/jΉ× 7+pO,,9ǯBv>Y3m,L&ԹD\9%zɰ [U/HtN ' NgUބC}gŀzC•af獒2CS'BYaPֽe hԗư.Z}j1CV J o oGa(9E D4t,ys;"$RRw?S]@XWxA*=m !S>L/YF)o1-0n#5|ٙ<-}M. WatBZ$$}x4OVVn9֧@7WtwEQ},B=X`djHPy/t*Of*/[{$Xͯ x_sy"I`U g0dv7ZEw .EކP cBhh~b4 `@x eu2B I`U=F'(e!ڙ:]^v#tlňa0(69F}|[zD^EގM=Vm[/Me\Ք0ϦQ׿+ővFnj Y% U~f&S{CEaEi<MaxpJ@CFT0r۝ϭ/|PTD4ahy=X_ަ3eUB=R!S=aa; xȷGu|݆=cS VٍՖTrSHh2wԱj'RR/ GǼpfp]vy8 >|o&+zZ SȄ=hFuqtj9cL Weq2!* sX8,t0&u!rYp:C <c`GpltoMKzCxMz bXB8Rry=wېOUCAs3봿td]jdzʥ8LBw${.6rX'SJwv 2XYE ;|[ښa]\2C5HsK)fc;^}ꤤsPx#) a[u2#}ȫ^ 3Å57f&DnFo1M-/8q3Q4dưB$Wo(g.s瘃vQ'i->|+Q B>_wF}CE ێw>;hU&l@SVf( e<89{0IPYK_[kqD̂s[ 2b#ȗ+x??w/N"Yk`#9kJl"_\yH[H̝(Q*;gAg.5|-(-YNCqYJX7 8*!9hSʊlzB g5jhV u5y x{Σv"'BV.6h!X rş\И$`b.ߨؗOW&4A=JY!J}7K=libg C;Rv@#VNWS1gnw ":S3[3@{O7M~mvWsbc@ΦUqS4{Ew%lm-#gsqOՙghX&0Ki e>PiږycY GItE6 "ܬB&&=iYCHԷm!>[=Jv"rHԯ>enb;h-]YB| #sXCmYݜ9F/Q$s1G}&UfEmBK_jꃞgN^gjhD#U O|wȋGW w0p"耓5ZDaaciBEZ3Mibm='eY.] R? }-3 jM! ?ǒíqfU~hw&,k}FC a7qN=l!i߀!SMOlg/txWǁ;3lnVodt_r&nŐd&X-<`!~R"U* ǕEC$Z2u2iYF"Grض`ozdn[Bťcv+X G(U J"GN3^ %^tm]<)],SF+ml6:LB$wUf:sFrE|ɡj1/x.p!+W*t7SpQ2`Gݕ%\qyD R 8D+%ܐU=ODC^"5CZhJk4X\O[>'T#.\JޜdY-c,&PEa?AUԇݭy&5]Ѕ'_L^ov?tIxc蜪4qҶ Brs ٮy竷^CEbywjY˶Wc\ !-!D6!<H*g^rhSLgvjդ@ 2o S0r^֓Sd^E( y $*w/ w;FyDp+7[<;UwiH7p?U&S* 6ha󋄭&jŲ%0|kcIwС74-HJIǣ6T՟&R ʱ,ϒ^s,rf4+GO$wnJ!iVth7J:m=Zs_Z5*1*/}ׯaIۢB1@7ȸ^$DS]~ъdCbvőRims RI?3ic:K^}X5>Z9N8 1l5:o.[DsJ/ ɥ%e;Iߍ\n17C🲯)vrWݽx՘D,dK{@$iPR܃܎-FZ)F7c-Rff]-uuq=&3c"I |, i[DFu<5f ܳϧ{Wt[< @"cy pJ) ㄗL{I90 Œ@ޫ*rD?"L>{aWX+9OXPv (J"`Z5a?x#?k7Q.6(=|Nˉ\""tqQ#kɝk8BJ <_oO !`枚g.8̇$jMNĿ-@cYB9lsd񋝧vJu>˥/PU9nXhΧǾD ix^]cNcSM!~ʚ̅QFt0uH-2Dv.ty5Eg ]>slHQ[toQ2!{ɍ]E%* 33QRa |Ln -Z3c<*_̫7)/~w$,'Ј6Ȱ9MÒa#N贅[6#qlh@( s@9SIDB WA_ aB4`vۅKbŮ<'h\ʪca2'ƔĘAEQPC3n$Qߨ8-9YD~0/$fD/j{rc^/yU3FK(] B#az1Ӥq2Bm/2*feTGYCf0E] o9C+ezn |<% sJTצj(ϼ_7d VX}z^F"Yma఩=̦>z87=rüc`yT3U{l\$;Ac@rG:- l>&Dnk랸IHy VS9>vQqk[yMɋ=1&148Dg%K{Aٜ G]:Q{o)?m{ކBF{ᤒ7sAŖKZsa(?S% (/nϰoӦeDѬ4<1A&PKMϝҺ-k;vəDŽjYe׳ɤ"`-.=x-DpH0_jlUdTXr@$ojG&׫*QǑlŚ_e2$A\S\'Q%)4yPD_*S,;Eh/X8v}*'s=/@"'O\CBޡww%Q$n==xq?Bd?\V8ڦkۯ^>'C2>|֮N5@:ͩ*~ѭ?ZnB YjY4:rsv|cD`‹Gέ-G} ǚ⌖ ?xsd¬)Xqylݯd{]Duq_B7~.H{p,}ċ J/ack* K[/QnV}?oۑgD'>̲{]VSnNNdцxYK"{{W!]-[/sQ5u,3B@N`MlGb_^+>WJK<1$7EL'as.l>298p38< [bc.HNRZ%ϛG9t= Fci cJ>_$O]i[0^/GcUI6;A]w k_G Oޒ4`s|;{¨`RL p(;A$c'YpuF֖ ^m?"LVz~J]Z@8mI"Y o8Uځ&3'7ɉ: ZlL*/ccf絳:H\y^8MGk& G!R+{&y.@XM$ %ƛacT$_P65_o+<SCb)QyUJ5麰x.aˠkT)nz4 !CYgGs:V"D@kO,/$Նɍ;-ՄSFGV&g%+9>Kz}oJ%dtO4 kw8nxH/jO"YՋ]<jy&jB& ١HH@L !8bq?s~ԨD$8eZ~У&~z-5WnH/"r]]\¢37B5ۭɎ`K!7(*I$ AɶɃZ> 4-rE-/;Q`Q6r 8+-a>{)(vّ>(FpsAk(nkIEhԸ2Q+oL[åt>(^lR>+i0i ̶%)60KdJ,ae$4vhr7P(vcAJYϏ/{Prlu$Z9R|)Qh'zf!H7"d)r8{ 3⮅al6k.-??\N{Ũ?Wt+~E{G2ƅ]g}UTR mQ8ԛ\_Xg"gQiQr ³#Tǣa^eqTym1apz â S:U?Ysm OEW.@$V|c7XߺO80&J!aaWa$ܡUjy?SL[)㎸T-.jq^VicPsJ/;㷡Poz7ȗ١'zRTL[˾xLTS) 9@lB3L`-I\ AtorO&NyuUYz}bz\ @u-C H$-k 3R:g\(eF@nK:ydDA5dX״_IՋe7iD]\t0l6v.yX,Nbe3f4A"Lr&3virM{lYy4 7ѫ#|LH}Uhi~ƒy]@%^`zq`J]*"&pf<$7ç庣,2v!~hUyK(~p0vuZפSyS#x,2S`XtpBzPАOM{XX,ʐ؟C|$+[-J67$5ԂT+;rfLyYVѶ:~ˌa;cwbssC2u$UQ?n7VٗV=62Yqt/|wK6}MoxO/塅M, vx Q 1>{-LY>cL[ߤs1_XƤ5(5#ÝOy3]] *~ (7̥?V]#Pә{(6IGW7PhX[,%KUgHMAmUf gM;}.0!‘{E(rDYƑh`Nƭ#E6A{q BE<MQJ@v PV' SyUE?=˟먩u0zA$t/aqALW++di6X$U%C rtQQDCHʉ 6!_n1[jwWVv@n>! t_M*Pv^q }Y {#xTEbiv I naVBEBfB],gH缉98^_S#&Q`Ծ* )˗ebٮt8'! kNU<iT{I)CԍQ_[N杊ӱ97i/R zol;b@H ,X}N _yU؁`)xK!7符jy7F+d _.4^")K_ v#_s ~(ǀP&ШL*Y77)^c[/dYg)Z1hU](XH_Wֳ%<͞2%1&o gojF|jOW'-qCV~ J=Wo&y̾!!Y39 NxJLʿ0 1 &.e_K}3 d \uzl]BX:̸SL|9xSXjm4[}]{.)JdKn=>d-SˆgP7X},H '>ߒxvB˵'̆&`=jՄ{\?(D$ x1Sqe^hFH5!\p'Nc|gNOr≱r0vm\NW:ZJ% zїt{"rZJYaڇl9Ax[oGX +u>Oǿ?nlP#~Kp9f_KHv3+I0n=bAO4R7ȩOd꣜Ң#(eٱt #Դ$&pm.W].Y Hu6^/× ‚hJq"f7cJ!=[Q5ا )`+18C0J)L|:/l2oyS- NT\|fEK=rR`#ɐKyJo,ݧSf"vbKWN-3vx1aH34Λ7~6`;p-ᣝMkC ζ`0*JxQҍ:\x3sp|{>%yP n'f}Fuή\pZT  ̍o#WBj.[iǪ2 ɏ8Jws^ aڷMBV90me,:Ic 僬&=l9Z \)~[c*VPpKzcJPka\lhcgCwW_Rw)!L=?GuI~U-bwMic"]yJ ^m4MH3\+y&ҷۼbs1f!˛(5FTmfn[UGӦE'jkz6*ޅ`KAh\uLMB@$5VܩyEGy:\TEsi'~$ed(8oVQ@lȋj _A2TA sr1<d |G2\YVg+թ6䋏A "gFQ#'g%Ýi=Sb]#ǟBu =р𩬽_b^e\3-;3ך޲JLUDJKEbNs?jfUdž-}!G,JN| bdjWgbz{g5W60l>`Ӕ+(ys[(tM%(ծSH&c@6@\{~V_"*MT-!"oT /gR3zip$%qΝ@0H_HIq6ifpI3D8~d.AOLop3Rz$)-jNHY}H:BMY"*?CE"!mQgl]I խv/ `ҎXjy"cg"jSSh%X6&t^TMK0U-R/ˬ Ts=#Zz|`S:}b %5Sw?hl-`3X޸n- 9?VK;gv6ds[`h4 H+'HogNefOx{)r JINsL"޲׸{ a'lyI y5IDٶk-;ײGW |qEA>0**!!mZsRg5.[睘C`Pݣ6J꠷U׬J@2ϔPG`osվ8¾؟sE0Rc:ψBxJrbb1'Ni־v*%pw:`Rq짹ѣ(Z= .пP5Jp^~ fz)~CP}"5l}%@>g(!ȋWL5Zvy-@P`UI8#(1Y|H5cx$m%cqxL'z#)&^$fy,F!-xud]}}Cmnծ*G)H!@@Jዪ 2,OѣԿܿGh[[,{oAvPzPZD=Y Y\^{Y)clc^F%$rXNQTD[5H)@ҕ!4JrAX\ ɗdIeHK@`*HFR4+[+A'p cLKtl"y"?gL| f4q$WbaId E hhP4DV9f0g)zD_Q 4Ỡ7d!Is~beWێ; JC mL(x z鷨QZ;MI_go<&$bc+RfSXcbbrϜ0.?Gj}:NKb$Te Wd\d-ʢ$%"?4/>Qkџ,b(bhݝ7(=i]ڇ/ 7#+bv  / `>< IO$$s}NJĺ2 Cef4T\|@NW4uZpōyYZNobxB/h_c yz>[ʡsFנ%%E\V1D(aI 9S_J2I/Hȁͅ %ؠ7zLlI_9=B(ܩG}.:鰐#q<#K`94 VT֜o*8MߙԃBf ZY=!LȖNH<(>Li` lR-Qn֕,E_5q\e0}lD܎ B l032X۳FUxwT_i.>{+j+-V: $ۆ{}AҴSбM wZ&4)@|u$ǪekZ`o͂/6#| 9x)(, b]%}ڲa˗SrӃ2bbOUO/ O 2pܛ=I,- EPaw杪wC,KbMO%(< { 0ir`Z# < #}.vpbr}'ijUc.+->Gy'/ ֫7XSyN(NjM;).p2Ly@ [ I]by6gCAX+斱Zomf+!xQ4սY3 ?:X+ D\3Wߙ]D,.)i]^)H3 v&Yea2L#,,I?Ǯ[/C7LZlNo0Up4`~_t2&"#-̈\an]~NVf(ob= (goha|_DKc>%Zl,~Smk܉ tk/&n] s`I~:B(V܉)@y!cP覩&~ѵMrRYl}eu1<IG#!3xe9WI$JzȎ}+>}י.M9s^7R<$NOjm7r׮1 {Py*'>'fd-/~]w 7*پdcM||'U\ܺF.m4;떽RU;/U?"I9D`- z.^Ҽߕ ;$p' ]qR5~m¤Qo*!e*R T3,JRiR|M7u6dw{ ZI %ll[Ӕ| Y{vx„ܝu!jmL_&T+ϫ>C: O(Jt^21,g:Z*04ewx): 3=w 1LP閽?}!.B`z&8t;*W)K%o-7{Hܔ 29 kQS: =3RxxUP;0Ez"Qz@mRw'uGewr3G~G&&3G#hX4wBAB&5"(]9ϐ{0c=^l5Q7㢋VM3"]L5=tH%lq T&:A'q ,ˍ]hyQ6e Os9F8ն<{Dp(LtL?pI,·.`Rα;t\̻*pƮʼi9[ }vuͽ3Hᵕ}ǑFO#n=MixVPhn62&W.VX6fU^qJF"qKe<$ 4$ i, ߑ:GocWc٨❍@OѤ|s7G]Z9\ _V'09|H1@{LJ}/-܏Ǜ5E2e4\g2ِs؜/+ 0/͕zhb]mDT*?̲~"w ,!L;m3Y;1ӇX<<]q6^j@h }vgki*AkSsX{T+c(' @tRB("1?]_գR Ӂjg\AA C!R~ih_S撬=H+rAӷW(糍 HT\9?"Gsf-Ʈ<=UWߴgUp(^]ȣ [9bW 1-" %e5 @;=k[塓_5ԕw<vopC (mon~p#a/@;-EL5yQݠw@@pK`Y/z?k-8qaQab ͂ɓmZ 3<`ƍz@+w?t~h$a.f-FPobsB<]iz#l=&[FX 9itώj©IvIbmq.ZFԠP;KzNġַ_oW)͝z7蕇08'{Pg+6/y[7jul,UtO~aA;6Ro0Z> ;b!q-6Kv [_ "O\;5Xȳh7('=3e.ŀTмUNUv)XIֈwlZ $ڹT:ag=5u)WO w2"yo x;Q2-F٥79q?hńͧ{8[ɤbr7xiFb/6zK$İ!ƚUɪ0q`d SK'Q2RA̓(\c)5rn]Ry ͍ݳdiR.wJxȝf{8V018ѹV81n{U#'fb# U=[\7eܚni̳AO6a*[kΈof []z@fZ{/2uNSZqm\ep/|]Ujѵg1ҼVkf-v'=5 ge6<ml_2C>Yl ObT3d TOshĴv@>+I͢LJd u0EYq¥'YclwRsBEo2>`,=ſ8ɒP|qHTQ$[{-sϠ6_Xmt  6Q[dRӹ6rE‘pkqNRI.9ڶ 5޹nfn#\q^O19I; [V,ט g?X#Re@=fGaC.4"fXReR58Oaf*_8Ֆ"o$f S̎kk3/x_=g ߇gu[wCR}?i1' ("uObXTX*J12o|Ԋ %OAt?6+ۆ;w ;mE :JOwsVp!Semmb`!>G:y?磉p;7t=!E^Oh@ܕ|d77mז=]W $Feo &ל" c> a|²o?zPց0CDg |eB`gQWpN8T;A2칔riU@µNsC<=Ċxq)}mlGSx(KU/F6/#Cch!քI)8f-JOmeXXq`)DA l겼F6aE~u%cm9.VoR9 3M''="T\z:"ϡe&PgON3~RyH0q\ݩw|QL{$MڰB3-Gϸ[˺ybTC.W.? ᱕a?% HM?:DD?vxida*Sb8v ~\5B{pxfLT۷+Q M[2T(?bl'yH* "!,ZK80C2U0a>J3Ù젦!ʯ Ĺ7vIT S2r})[}H[E~R;^+/CPf\lɂ/[Ub9qE.Rz/`'6[7շsqxm-fb|s(O!*H2>NxqE-?Xyrko|3~,Ғl9Ѹ]mLx8s- J\8zٽhpD.9eY]z)@j_rQ)_PeKD58p`] "NZ&oZxEю*8͔erc2޼{]~{cm28cHJ{Rp8Rs*2<d !PD|iiM0(>8)h':XMk94in̡`IJXCÂBc?H7сQiԒǂ4yHt==퐸l|GIK=Ipi^3~8nDڸ'yH,!횷t.ASA]],a~l<@`ü,S%|W@ l[b01ٟIiVp ,"M f b'؍DWlR̗Դ _48ɱ+skj9)9Io/P`[ihN~Nʏ 9g{MfZd_։+=g۸Y3>Pe׺0}h-qT)GsxJxJ x Q5:[sSsHCTÂyAs jIl{;mYeO;shQ:703@Eb_뭵ְL:ͷBkqDS' 7~˟RKMgT^4^OD8Z?w4RFV\2GS .搗^rotLfcX\! w4yr !@Q@||p {(зFf]ime : R: :ÏV_bw+^’'5Ř8IT8#IX]mD} |RU;҅X *rfL nd7foϦctwP:`hu{峆85/>DXz­V8]?V=<<6.O ˕Jg=8Sv]8*MdG'_6:Q<3DF#G8MvSYR %OT𠭂g<%D/P7PC:`JSo9%U@P  "֥3D? hdQڪT@miŒ} iYq$|h"):Ab_\G Nj;YhkH&\~ܱ͘fek᫽^;@#U씬f놎/HyRx㖯Ga[@dN/Fc`ϭlp߈pʛo3v\X;^#Nj^>UۿC%O,8dQc Og9@ !d޷EYf{2K7b,(3+ć6xuaSu|o՗<} xQJ=J|D֋m\50"\$#h1u`j :ίb;gSexqfH ;.@?Aj`-8^OOBҎ(ȯGlK u>6Yl_A)g{G7;Fn@exy ٱ܄PV|/zonz6'_A [ h@m갳0&?-{[eU֑A#;[WB^Ze>hUY*`- z; اUBH^E9qi WFDbeΥۄx> _W_``:Nxn&QsURf#$u;bgF/p|vda5CkV>3'pRގr 7Fo#pf DH wfu KUt<^HxbY&Q('gٲ}ioyrgk#c\xkvH8+VRTpU{}7=xB^{*0)pS]ZdjG[ jǓtG=F\n8X6X4Ԉ M/tM?AvdfUqS8nxN`c"sK\vΧxG7KV@0 PB󮑇4w'8ɝfuTpkv N`GSGEy(h5N퇠p6e o .؁ rC_?aC;)rRB"ޑG oj[2O2w]c`'Cg^13hwLզ#45Ln'y.PFwro|@PҀ@Hra 05/j8ۏC5:# ^\LN*JF TЃ"ˣ𢡄d" U73cEtZ+W1q\͟ctp]~eV1azqJO v 5ICӁ+&&%GAsۡmQ@)7D}'r-Y렮vb\x>%5ZmO)f&Ql55-6A) ʚz8_, pX?h~HeM$'@oFPMb=$מؾYepKb׊?l)0sՎ}Uڅ._o:/&J*_zoʨt.MdE~~ 9?y 0zǚշ3(ɱYx r4œ&vH|D;dDtp!ϕ${Eݍ(WP8H ~s2o4ǫs(cKw`Y6&]2-,!`J܅׈a YG<̜v=3X}l hQIxLj6n|t7QJ ppր~W-NrC7hChoI6CvkX^'u%b:RTٹ>=,}٘c&WNAb(F^$ {& ɔ6."^ŅGۧ4Q,rRYc{<d&GW $SQĺoq`]ަܢ{$[;|;~|`[m",;؅;Lc}LmuBp^:G*g^ A ky$G.D"+61IG'g_to: X#;l8%~TD㫰m\&f;flڈhk*?(T+CpIU^lpS .ϓЩtIOPBK~,xR] 0Xp7w*zk{QڲDϓ_ۇKQZV^)cSUT]м O-|v}dUxƭ` V:p69> Z۸n =+Itsk AFـMQ!yiz9 j"(*jXȭy}4scysv+y=Y>7]{NJnHgWi[ HN-G9R6m)ROr6:m6`G.,te%z@XL+aΘXA +/F2K{a3y!5ϒo]'A #C+-QtYdh$3e#= "c! Ϲr-_ܠDմ}󔷧gНD%촘0+.fi:{XqǍ%hnl\ξN:1x8*g.6R92nˬEIJz@oln{<;30tt\g>k_8k{YP H%}AnI NA5źV\긁OC~Mz#9b*Z?νLy1-}b?c_ PG^wb(paXbfrKU[]xSf&gMΤ-NĹ"HXlɏLgZJ4XeG'T-0eE̦#oUΧ%P%yObei!xr^7W0 QrO bc9UyxuoFx[1t&$MS!bQCեp #ZSRtÔY9D Db4vnǞw0i`@EpbI<'_"2;$,f <{:f4iIl|Q!y96B5ojEB*'c5c uډmL^/Ķ9hxR7՜%D5jaJ7Ė?GU1gK)|i5p_Q cN.D O;ٓ8B$cec@jC,Xlk_g]*)H4ɒegub\-sxloHDB;K*.cze$ >e UX>6ʊ/f$\SM"z|wr_A\ ͽ3K$:dq$:ǃn%Ȥl/'dxj(d_txڜ^`"FsDWs8_whnaފ۠f;=0!0\ D:f\mz tet%hϧTkE\&NB2BCB AsJ=s ηE5V:S0= :wpS֯KU"s;gW R3krNsJv?xэl,'|_D1TE%کZtԞ@ 0Ρ\# \| ϩ"'29`1Pg82†}}bjݖFN O sA|5H7}\P*keG)H|԰, _34r>9i)MκhCZƕD[ȝ58il[ԉQ^dYh5ZX|J߉Elx1SbYk\y,Grg< n0C_VWiݪ(IBE1QpH4lhY)IDtdcM䃏}o")B0_WZkDBexX,=U8ba1eyP(Ovb,4uZGu͵Lȼ˘05[9Ey+.?nNa:M}Ewֆ7LhKf ) <,dW#; uqaD+K8Ft?UEUߗc3u0,u+3D&hh3!He t~ Gz.?Yo XBجW}!4SQ?8PI۪ Ogftwe#) CpD1qulf W:J*)X餫6\MݜaTP޳Mσ)||APY:dy@G.܄3l[d_uCSN銦R:pt4O轃TG]m7FP|L dq>`,ulhرU$esӟK4օ#=34:nC.gq:J]iEVus ]]IՂ yA ;Eroi*A訲 5X㤔qoOxp0ܰD>E"%OGa~nDp ~`ik?+I8AP \OɯnкiUph \@7/3c+=[cOЂ`áG)P 3*A}IcJXK7H=O1f,ɗl}7,,v CZ-j'wv&{#مo.+ 6hӑ].hF0cOdc~ťEwl9g{2WnL">3uGPfo Ќ\қv%@(4stUbKKèHuPes$n:|=2+DžQd䑌H=剌䇸NW@x&q1$%A6yQZ]Yϸzwl V9!޹! Ȝ6u=F="Yg.8Oufc<#Ǝzws¤Da7N[ k)L^9h}H!iCZn4!8;]N?VO(?R=w)J/4W*~$2lJ#K7|t=|E^ōCq~δ';l):~w<]eݪsHcJu5xgq M[Nvۡ-N5 wqZwmb_0ad-`0*BJx K6Ώ_~\c6'kR]?4ۦQh.0Dmcl B#Q2&C¡T{^ZT|[X\ƒ$#beSH#el0#XmhsRe[&asvc =>F!Ys\H'@O?T+QO"r$%h _&ˈZS! " 6x) .=YYC|V%5Ɯaiu̼ MδM9)KD|ɠ4;Pƙ*,JNmMD$;S ~=n|k4%d.mދ1 :å4sb 14e(+0HNLA5٨iԧ <è4+3a<Ԅލ6R4aD>iR@b 0zUjeԩY3]͓}~TҊ$\T\cXuug/)+7H`,LkidAI`q 8>W~=uɸDO-lq[x$fnb omJ t?5sl`nۭU@o&Dwpi=_ &噊mIsr&d%bҼT"AҸNb.$!f\!*JB,Y.cYbM1 ,>~lEAQw}2ͣ}@p]oӮ[:~#eBo;(n -p5{L=w Im-ZojB<,5}B@ETWjjGYG'mQ27zIgGO%;;<'h k 2AWY=2)iW)γs4(3r0x:k5'b2*~)H mNaOa9FC{:neB+~1RejVAǯ6xpN!@5f -2$͉O:1qa)!ԯ>cu=eǽx[T=RϿpF<۬zBwXq¼|.YwsGpXUlEγ-Z>Y(2Ȋ<:7co͢mc֣$ѦsuLqMXENaDעt+6L=eogFڃ_:*x7!9k}؉Is`YVNJB/f% ۩k{FU#!Ci.'sEƵ2{H"M> -;:f7R^XwpK˔ ['Оj/kk: u$V` X~")ӜNm}P EyBIKX ,8.wCzGgmE x c(ӊЩ{oq`-m-=lHJ#J?([)&4z.*q,FM$$y1H!rUq"[a+(a6iܥ7tkN-sS^x;r/ggZ ^5Ek5j{3{V1٥(.o<p|dR6@ I>o!?!ld:ݖ.[*<(|.%ԟ :*4iC+\kgpa>ʹN9\ -zw>R]r}C؟ށ-+`3z˒4/o'"(L'K5>̖0 'l}MV/4M ϊkP'w"ȢyJ.hvs*X|2Z&cpP_4/L}n0ihv'tҞs!y`f0[]r;8䀡ԩxN#x`[zjߩ0sIjcԔ!0!gϳՎcGgՄ!ǫPФO^Щ ֦fYdINf{hQM)'x2ːac 5 #nVIլ&@9/EP0e#GbsT'~b$jl PaƂ܈_ʟAS*#l8zv Y1j'"LRp>>Z ԑs8VZ&[/:8A$Rk9x.JYg,ΠuEa5_Lڑ)棑\ $@mu"`B1֘fv&ԠL&*38kVnJONIdƞlBBO^є=Wir^2į:hwv" Yyr5frVZkb?s riet#L`ZEV-~f-Ƀ^uFY73Cާ(5jI )ҕ-qU  G6Vj{PF^]SE|khdD$/m.)`Y}\i=uf>_Of …"w&QWcw<~3\ ۫ѡ` nA谬:8(sl(i #?5B?n;HUȀ@pҭg_ClcΪ!B$JT6r4巜M3di ]W*m5EQzL:Bo2#RDMA(5 2R\aw=|b>p ӓjф"Q0hf6Oȝ '?D 11*Fai$ *_(;xU&{y8j TNb6ٍͽ+#Bf..JBɺ-M8fh kԍw[DmI4Bs󀲓?la5,| g. ް!tU \e(} /oҧ[R:=]f {5Z[ߨhȓMWb(_&51 zO=@üܩ^ -SX hܢ "`3̑M{W)<# #b֚V~üy!c.i #Uߏ3[z{/ᖣ|NC5 $&,+)6j=/0Yf6Isw?Z g"*ǒM絖ji ,u]N' FJ%$Z+XȹJ,U C%3tHKA+ߦ`wاvx(ϐE ..^٪jLk HĦuԙڏ ӟYmAjhϲ0N6tH3]y.>*ڥlRr״N *BfX ajѓ%PI Z4, Tc!zuȊ}U@WIt~ GPj]8tb#-Ϣ:lK?yf#CZNžA| .\jkQ|r~\/1t\ee}.5՝\Rz\: e]*y|cZAޱ@\|TaRm``[1ZEipBudyVEZ)D+Rq1,x8Hė#6D  ` }NJ B`-E7rlx)$|0QHMmw˨k`騜[|u;5ư7O!*a>*y}3^]Dln'LkfɅ>Qscñk8#zw[ TlufVTGj}Xkꥑ@g>wr܍'`mP=`(O;CJPdZ"W)ibe]gwX(d#X/\%"Y)D?fv?3Qh|p.1eU;`xε!$pQ bmtE&n"nc*)x+k:9:z7c~~jK3ot_VUd |^ W/OM?繁G @G<> $}'E 4nc~, 1+ut@IÀHs1͞g{ VtŮ$ Z*%׍Y >FF}jsH$YC_9cSQ;vuV#8W{nR@.&bzxA-7lؔ107ط#\ďm<[cPP#O' K2֝: }= $`st\,YoGxȺE+ll(/Z5 MGQZQCL*'. ۔΁!w& IG& BwoU#@X\oGt=)NUi_R(VF5gV ةp:bB{(n̰gz*raM?7N%Iq|!ꍫfa _<8BԠO·FcG,QaA%MB(VGm~u=vLqCE1D^RK #-Oۭ 1Yy߯\Z0D -}+ riQӕ=<} 2ȡ_mK #OB㲂Ǣs*X S \6Wis8尡!q(&CRB_{+44ݧÅж˜떏. #:̋Qiϵ+e|tpTe;&ƒֿA?,D -ԡ`\c@ʤ]P>^ `S hEdp&ho?'Q{#bsg`e7=:+ߏ>\ۇ?v|=m8k0X~wkw!čj f&')g Kt"$8<1B똶X75EcQ2S NC.?_t[#Ph9(\*"vZgےUQ b30\zl!`^UAkM˝i)=Dd!3Xh|ڙĒoz+`E xj|?q RUooKbQCRC VT3}9fg-jlm >c,R  x> |3315D12"=\H)ǧh>Wfs̑HZ -߁+/ʨǺnJrƑ}6}sDA򅨏(<1mai^tHǣTU{Ϭ 'NᛤԤETLd>MzObM^iB;:*sUx0Q+LuXyxX+'$ LTu'rt5RXR ?XQ2p:,kH2AJVČzlskoy tSD^0gK¶(ИpTJ# ݵBqtD|@G|VAgMq\;OLvSH(D;lCg 'H-d:j ]"Mذe]ҷH1O[stT|w;Ƈɣ.F3ӂ(ky + xF&Elw֮9dTBer]=I$αH9aJK.W̙JhDٲv9.a*m4sy!9\E׫f>9\ '} zJYF?lg+5?4KzK ?`afuqp{|39As'K""C_4-l ]SwCiburneP5^ LR%fx,WNL1yVb,%A<͏ZǙ RWoB_:Κ֎+V1}ljd$ZS}8@Fxy8"~XC -bsF S9&[x_~Und(Z4Rۊ$:޵m7j,jF/9q؞ŋFXi$Y}Qxөs;b64a[3⡧FY)ae`{Hj&1GVf^#Kz,>siqChЍDp5}$t70H2-S3adV|LŪ9LyBOVa-wĜ姿YW!C:Y;pם? hV@PMճƺq{h.8x( C{{'̮^~CGC[bDдO-Qc5ƧE$jv`(F2))3ip~܀ bn #٠m2rƫƪ5>9UZJǂGz+A'vڭ9j=cu-QqWc֒ # ٽKWNP]YC7} ڡd&%v‚\f.:afBj6UbN -OsAax,+Of4.n TfN,-2L4m$,6< =jg*TiJ_4sxS[]Wje, -}~x p OXX zzSJq Y$ާwRص`ض8L)V:|v Ni.7o V i C>qm!BxGEΔeE]+,`3&rF tsO@$-I¿5j6)c!`5E,4&%Y6#E@6XnJ ܈Dm.=$kH‚7q;"{N`!'t< c;9N9ܳ:KXE 8!1N2pu-YNƋulV !b> HWϲp w )taJY-3wl">.m’z8U^x"HQ5.xOw!1`[wrdjnMA!I;Ɵ|@u 5'rpj|NE[J{(@" r NVorm6)ZKl .B9hJWmmwSvaf&Q9.n DaB|,VEƂz5w?~& pO Yu2d~Ʀ$> 0 P"0ۼ܌eK E{`ɫlUrbו\^hB>o x Ҭ!3ї4M\*7Շ\" %\6 3QpCRھvem_GZOkVSc[nyq_$NG(hye+Y; u崅S59IY^ ٢2vU2%Z(_@y%]yL0V)ʶ!NH"K͌3~Ր6Ekil6oy^a;bB\ r}p6]ҋ{6^3H"-Ff*'u]͙иDj:rѯ2,^_paDۨdz$:,첑 &mC 7j_x.s=[>eWML0_=h񷖪,4+Z9ZyB7 E."{/;vUW$G6&S(#7"̓?2DZlr7u,{)=խAFa"Nsi@j9̨F^P)} G #At"c-o}%E~jO{!FL;;VQ(lB#-.N*d)4)S!bgZdb 5*n;0ݍ}L"orEX @]:ʖmfVN@1Jk]h]U[{d"|7ڊ hi1uNuV.Vks"!mc3 3wEB- o2 }g|oY`)3B&Ir;"$?Ɵ4XԚi[V!v7Eb7/I“z+ CD.L\:T9jJ xnY6O >Kײ T;ͮ׌ [9€aETi 3K H=I"0"ܐo^9I: I鄯zX(v, l{O퍩m2&<1dmYAkS:]V4>SӃ}YdB#d Q\ XVfNlt٢y'W]uDEw=;a3&#{;ٴ9fl)R,X:sm~P)'׽)Au]9+&%A?MܪDR| 1!ѥ.aq"0523|O}0<QΗCKà=%\e\kLSșZG~yuz\ Sb`#SaFdwqO@Hz4g)F{ƻya@ciەjSx3YPUXJm+DA ln|woߎkrt{ Ň\V%8f!Z/|`|WFд(sV WU- ~5`+.Ţ1n $_/$_˰LYkF5+>*#(1Y gm87.3}%IЛL>1剨EeJ (-95ݭ}h=6jCz<SĎabu=9K^MV$stpNQ'ޙB (W9{!G.+雫0HUUISQ;a%zAp!@asJJ%7걩Ce@ 1qZh [0Rrfڠ[g "rD1d?I=_j >(ѴF"ܚl*"o%F6 "GŒhg+ٷ Hp @7vK %ۏi Q^&chty )]5'uf,P/?0dMBFZK!W0265Ș eyyq1+Y!co H;4Bռi~Ѩ_;2jyeo!/UX [_+~>q©|pLN.< HJ/NX☡ޭCޓ_Q`*vJx\a.ֲ5,S cXaV<^̳-{$ yQ{sɁv ;^{Q:)L[q+ ?jrv *E9_;O}R _Q(φڑ1%%Gt=2|.̗wN5mW*Wa10娲Qwlʴ7M*L\}6V @6p-7L~` z5HV-nZs} ʋ,,ײ,D+g3${ 6quh(:7C1O (F~<ŷ|qLw-IWě%k=LL*RH=nE>Ov}?Qk{|]1+Z3'w J% ~bGڥi𐍏 8;w v6+5y_BnQZm򰉂^+Hq1;MN\"d)2e`y\Θgta:.3<~܌3&~7hΕWaS vFi%.a^L;y=Y!8lE-ҩicF<˫W}(Xt$̕vy6`q}~*HTpAKT ߼K%L]^%{k{T|yM-QB$|01D7/ݺ JX~FM ![?мzz Acq rj!sɚ fʮ@[jϢSH4|"/yΰ$~C'*ȘSlLQO?&}t qp!\^ \l3{}Vr޾e6u36&"*NVMde}\{.$&Gk ( EZ_JZJfW UyhK/ǩJYQ,v6NGV:Y\u:i/l.Ff԰`rLy1>? >_ nߏ7[P# #F$"wTo7vyp4,tP>0ѿ# g~;X/eb<ߠeۖVjNO\4"Hwj_P|,fUv`;-!Y *Nbl5#rO -eyBo>U輦|T0 'kE2:U!^]9181NƦ~7F4BJteE pDv--c좓'OQ{ ?.l1?<ܳ Dӵ@6Da **oӀ*ϬZ@ ?HV)NQðG"D&jKձ/)SP=a2gW72Ai^P~AM 4z,yJC\#̲D){L0>q* gS؎Fu5քV_WН,:&m0z<pERT]oFR #lsFd@"~ط}kl;'9 Erj ; 6E6ʦ.NG`1bm)Bc=nQ37*7;ap#+dphy\nU2%`?j+v0b tiL5]mC0BIEg3UASk@Bh>0vwc ƈAh<{P B&t7QX%W*v0'E!w&pږăuq{G퇝娦ZpR2cmƂXW ݙLFz~6ubS⒰[E+ly1'S 0G:Ll#r9K#M0d';L36'37u"! YFʫF߈oDZeAK36u*0N{|])ڀzp\dYOh7[L; 9|ߦ |5%JX5.r/Z !σ@+6G4oaT0$;_ jGAu&u.=46]hzs>BUP.;kAx~n1=a$HB؛Rsr׏G7m;.%m55_/`|C;ܠ_zicq] n;ߢh(ad`| > 8Xw([Wo*cWZw-P0 CWAᣨhGSBÞC8ԭa%yHQqZL `ࠔLsJY:NX9Y #ECǭ3C.&@?>[=KfJJ$>V}e4vGǻ$⼏⹒O <?a"n;t: MUrAwF6ꆛ|ޱE CPb6rK٥ໍfځ6"0q`oQ$ȱ3ȎRzP8m`kŬ߉zAv IEx piEcaQ"e$&9Z5톅cˊ}&3MZګ%@԰0M-,_!b(w_b% ;<clT3KbF JUuL3s% ˏ6zf3 ȄVXmARtnJಋ&@C4@OK[!C~?=W~h>#dP ?kh2?M|_A&g&Gfs3;[k :^8AszA/" [J,6 BcULa%'ʈO-}}k7t 7EW hMocM<ʂo D&޽ysSj?nbAtz'Q)?A+? €֐j{->6vvٌЧۈ ijhN쩦5p d}`2?vUcJ=YVNI^D̤^0Gm wv ' 6)'=S*`m оf< njCϲN_wSܢDYYO; lݖanT֛O%7kz)qixStJj`Rs0}ST#ѿI)v5>!ZCjo޼P]le֝ WߎV2tTsoHt>aΌ\X)Rf&9(??K0 C]p>-@c +x(grxeUvH3`YhH$ )+zh09t5,v[uA?@zH怂ҏF%S7\46ttcȵy,˘ռ\^v=1'KH&"xŖ|hN\%LH7q%!aR'GBD̓ HrV¿f H-hb﫵B'@ nWL},tBQ55ɮ %Jf#ՠS󑜕2fθ"?o%?10̓Ly$F'i?3l;p:_;WbYs4iJJ Rǒ>B]oVaϟL`KkŖm Z[RBJO-DZLqח0LW;\#ojB1t0Q3Wr`J-I,OX@Wa\YGSCczFмOWc^4O:UD1]ff2LWz qcNcJ~CRi a4=nx8:P仦nE@eg9c*pued~nE\5c/P5e)40_2<(XW>ç!ڍS7kR|u1V6g0Yzqbo,}XeK`o>K`wc-XpO#EC%膧W Xfve*WΕs,E42Cgk;"鳃< w= ag` Y&L8[ ygAw1MbkD] t-2FemId#oat 1W\b Nnm9&zchQY"*ЧmVtɉvچZ1]ܺf:mA8c}nV!W;@>I|UPY&8O;% ֮̌FNOU}v.7WʹeAJGɕ~h9`G< K | ʍ܆ ny흧C_})6 Nl\*n8E{hbyX ˝z9oB]_jc aշ)D2O> V!qBW[s^w mfx51%лDzµl9(H̚*_,1hg6t1Uo^_k"I63i +J)D9ȫS(d,zB^ҁ*٪=!"Xdzb%H)9GJ Nv;¬8eZf+O5xǂ.Φ~3;%Xs[_IL KWꉹKU׫# ^çV0<q25I<(.N\vm67Fsc6rvQ{"0:WAlx<檾߃]VG*%zd#S~QKH%Ek*bΕLg{Ik)κ`^wZ@wdm2Xd{Ks>Ή%|}x UUi)vu#wY lk|+a3Z̙pV>ֹ*Z\6ƥWXVl?P~bXV?7/xX%Y{_…sl q0fU*Tj @>"6}="X,`d:l+dNr92_gj|$ssYjIl Bn 0.ݨ&7<7>fT _DAx[k0cܽ q@ZH\(nmtũ.Vr/=Ftxߚo]t)tz HDtl? l~[bk%N,!߃J&.F͟\Z'(~Z_^_etK4.{ 8,~egsgWo6"׸MNRT"{Uf m3|qM{e˞nsVjfڢ_`ߙ08GwqULx _99T$[6A|Isay|G̻4=ZSF%_m]|Kd=ebE&1'V3y˱I?k/@g-7st<7#bLnZW ^DL-SyYo¹hO3t~|7u1RRsj^g|5 d&Ux1Ovw1fxj]u!v$!WUz`U E{Z~L;߫!蘏ė7 ]%9pYϒ9FfdfTɼ!;hM2.'~lvWbH3!-B߂c `jB.\m?i^m8O4>'* `iQUStĄm"|_/~,֤xE5>*|p_c\ia{n]+wi.qoɧp]s@dcE6T0Ī:{K1yӱSn1 H+-`hEрk[a6B -ք~oӻC.T-КWJWq"} Qa[J>77?P11r f~.blmXuB 7j1x^ J z~${W[ȆX.%93N +y~ϢOsuG@zU0nZ)r+4-I~]'Mё@[kav 'fj!0 [5[CϘ򙡠1GOmmh|V圮0\#t;B:>n S# }y@>Trgdz$eO#}1Wq(T9Z3Dq R~5wN,Gی|Վ 37pA$1-YryV iV@aƅ$⊕w5doCȒN08 :rnߤ/{{ ǀU6n xV_s&BHӄ"t2}`v?W?Qi`Nr=*sl)IܰhJ{C}{2,p_0%=T Y#BܑJ2YZ4yq*љqʰ2Tlxi"T+S&W%{+Ff3ʳ 7g(aFQŗZ5: 4SNaD^rGX"vJB- T4'kt`e@ ;:ҐR 8P׷-,_UE' t9is/A;X~i*Ql#C(gE$w̛'UBq$E)*-nd6(^Bx,59D(.BQ $Y:-n", IPĥMf7zQ߹| ALv3P Sy_M护UY 2HS!+eI!t4Nӷ8kHfp݌nߥ+䰋Ts aRRtO,]~$gPvGyMLOh/p4lkqZ]&**i;he*%HR߉yX'0꓈*HNz9jaG7Wdџ޲_I= xdq49t:kșNA5zd|Q^A۵΋wj竣BrA@* UX XYYyuZZ#lg6r?QVlQ{VVe2.bWK> a԰?c qyΛ\PSvxتzAä:'( -qhRS?y؈..0뗗Y&ZX)$` "ʰێx&W~t#3RtDs#c>6">  ?MMfvyu+{Yp>?`J|E2j [ &Vb2؅.Nf tl9}1nc:L,_H^WR'Ja` O]m-[3#;D{PCbK6=\x%8I/1:S l%yk8rTY?|UMRhK%l#JK[zLNU;f|g(j7,f9; c$G<8SNYAC$2UoDWÖ< ϿvhX"uE8LDzz\%+PFT1x?~?:k6`V;Јލ, /QB|!&g'L;a5{o35 [rtl ⡫ فeѠ$kB/WHx)0Ox}LEO&YSsKu|{{= IbL{9n aNjxքL#~nmgO%;lf,%T #eވ5-/ s|3a *QFx@i$\;UmNKyjbN*nC|i]W]iֲ$+1* 8#BKys;wͣέzAܾ -QaOd]{BTEFl̀j io`Tݙ+w"+~:Mp-P.=cJ=s-Hh;C.`L``8Bڽ6-T!]i,]ݭ\^{=Y"4n$5Ӟ]dFOFZ.]n|8Xu"=[Xoo;Cc( 7J\H"]gm؟{:mjT!ϒJ$*'kpu@"o)IgƟA@6nd^$}WΘxgMS + YԦgqqrɧL=?z]0nI@ExU!|P|9gb48~nRhRWRMp8xF K\Naqm5h/tw>J)I)xتE|Н(N^?CE$-Nkӽdg4Fz`lD6I9ۢ=ނ=nL^)c=lX۔/rF3SanmCoC@ j'zD?1DHsy]~KX<"yj, U~-K#o. gwe >7,6cΣM^TAlc:LΏOsYid(VeR&J)M,f8v"EQQ[To6._x!=ba 5,Wlb"`\Yä b3j#-`bAZp#Pl^Jea;odQvENګبFk@VZ* ze^LD1)7J"=]2-q,G=(9f30N[ Թ.jSbYF^[S" qgRDVDzٻ" [jřo=%QtEpe*Ơ7PyELλ{s2d`4Lx^S,>AI""+{iڥw<+v v>p=c?f0p ؕ_ sSfs+!H de%,|T) \>:cIx 2٭Wl/Bfۥ?Mңtц*Na37dFDxeʿP&qx迋̰J2c&,Y5dX=Qep!"&1C`8xv{Kh҃qLr%v ,SxI}Tĺ39hŔLQF m|T-9;^߫뒅;QFb5myF1z~?0MV9%`za]MMJSAw1j(@ʨx}| Y!a#á yJB46/C- CaL2!!w(&NU =;.ck^ AiF3[G.KdL-eaM0bh>7u'+S,C5$b U&)/~t _ֽeB,ԓHqI%[&L6zAkX;fzrz4DF^w#`k) FG~2?mxƀ.J0=95tGݬUK{HjQ'Up.ff?I!" z? Z]ŽCAapIRWѫ:Vy9jv8q)AԞf'5䷱ {xԣ*kuӃ"_eH+g y؞U\T?P GT䃞m MXsZo[\fdpo{\jkQD5b~!~spZM/lb$s*mr 6DI}*?斷˾pɞ0xO^JKgưlp^%Yi3;8qiƶᮿG6)@p̙#;CAJƥO R׃C GZߜVm (NE!ji&zT;!Z#SX8b(\Y缂֧~ m$瞶XIWR]vI ưKGQ )L6ӫDh"vfҩR֡F@G9Bț)^v$Փp{aVER2yqZdŲ'%}2 ]A|bD&yvgյ!wdhTM^ {RItyh}c`?e"$s]%_ [8z a$kNDg 0c̅Xr\pH ̊.V0 >Ce [Eǩ=x)(h=Q$vOQAf1WMU-el5;!'@uW:|oCF֘恰r#) Yx<~zF $(_%Iy _Mh>1K=te]BiNm]4id~{/|[mtЙsڌeRkUq-(mG;A$]D7,;ՋuǛ!TGeJ:!׿Jx.;0ׯpG= ]m> ޔp"h hUpN5bCoҥS/Ls%Vg? D7~ ,, ̒ v3c*hV1tz)z|ŅVĵc 22cX} zH-9 (+۷fw_ue'?9iWP˱;۪C7%TUޭaUI0YiubTnˎkkȏ}[hw}d# g3@> J/Ɋ[R"+GIo2Kj(>/.1\ 8r.9S|PDD  A :^ǎyȸ˼rr Q4(t͎OcY0BSEd"a=3(/C.mD_F/gҏz ơۻJmv=E*׺bAׯ/+g|:Iꏀ]Z# Y~)^\pv67gțgŇ|Ks$LţQR;2l"iw$FCh +ױue%,Yvoi̺ g+|U P)v)pK5 $P!&6kj΢@,xQ:ys|KK FH9-`xb%]KkҭK^!<&!09 l9ēKme(l+xB\NuUV7&H>Nh2ۘc*˳އ 7CB  1295pP2Vu`ƕw!l D?jFm'AE<&uF5LP]]gb5^z׽{^/=_oOw#!gw+SMu<1p Ɠ~_܊̱Uv3&$BmsmRgm2}cTzުVӻ#L0BTyy#S:KAݦ|vDɥe ډ߾YFp6\Gd[F5b&s>tq'7E~ǙF-Y뉗1u0u%e:\uR-lͫeÙ1mezD&C. mva_[qvTN_!]jQ~W][pW08U~C 7 ̇Wwc`!y\d46> ].7vcO4$e؛=@ztFy)CQكKٸjx"}n5t\%Fw fr)޾}:H/s$t ]j=||0R8].qwB1@##,Ϻ>mnIc$4dpE uTNG/m\oHvUۯhҟ?QjIK.Kʂ#@vlVP9f= ۦlT5@[)x2_)$^A(M p-rp'ұ^LP>lM($GXTKo vK>ٴRiH1&.b欲(U6ٶ $Eezyz:(\2 vi(xn~ESmNd3yZvM %QIM|j.ҷ#3h;՛.dK%~3e k桾],9`j -6MMأӌӠwʕ%!Vt:4AgKc9rgWnR58۬\SlG>A zI*1Y$uu5 T^ )RNhm(VW"dLT'ĹCQ꟩qPBvGq4O ;^^e  –񄺷a~Whu*I,|Ha9ISgcV/p& v,뤾Y&~Z;qp]N`qʍ-~~\ ! TUҎ}zJr|tHw`(&sCμf3Q%3T2'9ueRNuk7[nh(ѧtc}H -wgf؎Soqz>8߰VԴ9Ǩ 0ge9DDT2]K2gj I X5\i$j};$3dSYH82<iL)%綛M45X׵«Tםqt8g&zz q,\d3w;l5+-'IdG?3ޤWE/#(zkz(O?i~z`obdeS-ӧoش`gEU [̡QCC,#r 1%"c35 }DGTNR%JA1A<ߧz+*2}4~^68_H >qɘ=Wj,8qK!DxFX& E>FGTn{}~ee)Xaȩ#٦8? 7Wru ɼ͒ISzMǔQ]pp$,3mǿ:n".ȡ~dVmj/ 402st8 _1"6xߨwN\5K_ P5doKax6j3DX l-L#QcHՅj@1jGc o$I(ֳ>ˁzi*Znn\;o,q6{=xU~mT_!t9$-f[U@JB phsP(P0S}eRJڜIn{/Nu Hܘyn)-6R8b$+A=Axr-!79"mnԯP #α @: qH8Aͭ҂N1Gj9a W׈!/%SпcZ;gҜ:`,]5;@r-JB424c/ ?Ž/DĹf#A\[!P-[hUP&`M~Sia{5ͅ-ɭ,fF6TzAQNY0d[&!_npˬ56~mk D\/뼮*$N8t&dְABߘ#/,xxV߁D*&%x(-Pل  R5 lǀjt%ls<FRLx sׂ |[sYfbWX&>K{#`:C3y%_ #><KNIl).\gYw-D'Q}exA ܅W_ -~!؍\_j0MSxD#L?ȟs.ԞmGp8 ~ivX){0^[[F3jyZoI-XQls)ģzqMOo.h P!U-L9z{7rَG;*=v"ȷ|]/G稰ѭ- P }U;\~wyJKGT$kq1C(6}h鮹"| oҥ~[Gf@O9QDKA-OC~kN7-="q "ղ)30`HZ AJwi9 _V=R|lѭW7GVKݮgbpjAQZ rE2Պ{bY> g􆼾 1vY;N7Jv! TR&۔|u3o*U(XIJՙCXkn(okqOdsuA,^gv>tp2$VR$w*'hR?np$E6z/@roK IY'j ]_Dp)#`ËGϋ x;0Sb)SLANz0ͳQaԺq=9a/cÒ:䣌@|9 hJ 43ɦ[Ѕ\NuNrOl@}%EP%ilAʙ!Ȥ!ק.#ptXG7q?7AԳ.F۾y@{m(llndK+M (5)uZv,>7jyݳL |Y(+ Άݥ)<{wDN/ߏ>+^7qJ &ȨiO8A8l+oa~LRͫZRgU^s2ߢɛS@k1S]~Т_8.qM q!Jm8hJ-? !59+eTӐ+^oݐӇֲLI0A$vwD-+ {[HUZ;USq<S9qh Nj:һ2]M n,pk?Rc$Rf2 1}ޤ=bI\>K.%j!=?YV65\o}#+K0fLR\rM!I=!|}wq~P8QGP-)9&G>9z%އȊS xr챭 ? lnrY07/7B0B5/'d^d pee˖䏒 n9۪!'(8Ji"]h 9p FA%~ uMah{iM\TPCpXz|+v5Q|Nx#\)j፯I-})2}P{mV-:>6D~?\]#LيV+Yw#Wʩz4+~½I/?A@5샣C_M6G_= m+ {ƿnvuCy}7Xd#O0,`uiC@\]^2MsLXH)f7sQjDu::Dd&l\0ႃ^4i09|?9~,Ȝ@]$.j{k<)\NmPOl.QѡIV"lx|r W$+Q53g.c&!( y `kZC.}VJ7gz*&F5~[D3RX2!N\qwts "짙&8nͺ'Mݦ0wni}.DA0لh|~MHўG  $ܱd a %19sRc\ϙٓ7-H|NWY sMfO_Ҧwv(qp1\HK˽Zr8 ؅R/+\a-2%vC0Jia_}gg-U2'\"zҶ&N/A [9ܮ_pScq|}S#*ZO29Hֹ*34@pYTQє$H0Z&ڢԯTk@c~Ruώg&ndjwNC+*o߹E SPs $ZKA6Sןf2Or=n}ܫwqiޫ@ތIOZ $t6J9I^M@66 "C1ͪ[l F.H :MZJ>-~k"N8\4:_-/Z-`eer7D Sdk\ 5uOb2c_: g9:hBFWv!7yzgP ^;#;wta Tr)Ko$|w3\.<&v2~n"I6؆M]>5 +jAiGȜ5uH"D&r];{C*M]^ A!A'{]~aJ3zT H a3cPIJBa=]$9|9[h:U 86`h>ٰIeFTht `` r*Ȃ`îL4c<@Yh $=Ie?5|Ȝ]vCDaux0anqD݆ݘ&ХgOuTc>ۀ+nd BUƹ̪]KIW~tdͶ>{ .i4\ 7SWhΆ= /U(48`UTiTd3\hݩ LsQHPa3K|8*rhUW^5eJuVɐ* yJq? 8s_0P\@G50o-6}cA;0&u`}[Sm_Fd Ky\2-?Gv.ԮN%=_uP^Cm$HO,sMwC,c&:lFp4+Q{r݉L,8obDS BNHIwHHׄR@H*wa廲+&S(oL/&YXE&3E~c3u"e >>|9)fRŽ utPSFk7 d_=Z:Lwd 4i GguCPM``9?zE[M:gw,'@1 j԰}ʹJڔ Okf"бV@p"b۫3 v͢|n1XZ{c#_`A3=I5$/V3AMqN rw]FSp3A{`S:CrrO!fzGt~fԧmAģN<>'" n֙,%iꂧ"FQIy0=ȔQA)4 Nm"J;+qr\6m~iZ*!4HY(! q6{MD6|І V>M)5H9L9gs`o0b d~M(]sNWDY8žC~B'$2f{؂v&#]7}0}jN`p?2I'\G-n5 (I4Z&Aܾtiuܞ$;Cr@}ae¬?ܨ# ’)sa%RWǕv2ͷ$9϶ MHT %n[zƻ]呷Övˍ ֭<hhA͗bį]b?.z6ѹiWKw\ 8 >,.OomVE¹Gnaﱮ04lJ=I bMkw22׍ب@YF_~򩉯zp_̤\;,nRmQˁM"f2Okrf(Qj+i ]1+6$!BY橣 ΂~O)8 F`YQ]lMդ&Ih{e0T[nse6G)|eS*<(d1%2I`DG4M %p&Ë9AR"ƫVkV5RdOD8O$'7?賐 U%5C7K\a/*DS$Yր|4|͓iNDhc"0`][.}2 دjV\ :2<+ύrb} q|[lϫ'f0 ,5Ci M k[SyqCq~TWIjXOR }&Yxh:r"UG H=ql ͭ2wTFy0`%LtS89 =c,9;BL pמ(]Ϡ^ a4T;53u<7@JMwٚAT}I01Q~LMj#oSRɌڋmx0m7hu*(r(v0;N*(P}\ɸ>!0=QJԅ|.^5Pn k_[}aJI~qSۈ:lYu}\tBZOCa>l@eDG}E\^U7q`3q=;f…jbkɧ0k'kzF>^g[<7oz/hTe0w]y%|!vTh@d/uN6;=R8Z6:e3&$m$m]b_nT;DGs4K~M3&bk?S@=9aJ:H"Oz[$˕+%9+aVjإg i}2 2Dw(wYXN#ixڽX-zV[yosn+*v}L|Fl'GW[._Qy&]ueVoDM.NDSR> bM!]3%/XCIlzx H/՜SIUK"}J!W|0>z"?ual'ډOqf@k%QffѰPvp$u;RAY7M&IX*(%BEǜ<-ֱQ7h`j}J^T`n8h`5VwŃx~lèpsfL0K\){}V:< Cf2dׄTGhBbP,Z0;*=Z 'o4!kI0vK;+)f}MS9fǗa/G[WPjNk!B6E*.} $-$i5m_jM ._=G.P g!1s5Ҝ~#rl93`mRo: Rx<q,ѽ-m ؚ;-0?w\H{-3u\zC-JVخ?!/D&n@N`Qv{\v|W:I'#5 \ҥf$[KM F A~N ΀Wy"a}ڰf c{]ɲsE;sɩaq쁈Tb0GB|>/eLIZ3$>5Gpw*G>Vk=A%<599YRWEeƸ .Xg/ThH%R*{zv\)^~uI|yW%Щ׏({xP3fqpWe>;вG||%7:wyJƣqaw _9HEa-}"5X3Q$];eۿP.UuGr8JCI|.obGgFA#f_k ` P,a^؞dpBlƈ,*PeQcr=eYφG$|c3 SQ49;?Ν 2e D"n )(;8G[)&s?jFL"s=jo-wt;|Ķhg2[7z 3Svsܫ>#J*aƆX jǁ?FGg&*n0Ig=ob<-#<߼<jcl[us -)6ДWi3ex9_>P6ocn3DEZ@Mht>d;̖󦡆tĵ«nucNNt+~gUx*x҄d菝ʸ S;l>D>~ѿE3h[|m//oPvrC]2T-V67VnE;h{~X ҘW9|J%k50$k%nl%UBAi娔ɚ]` zkZϠ\ȿ"^Rͨ:vd18oBә#v0U@J\<D c %I}+1&uϷna#(r fH>g2u]/}0-SU//f!WAWܿFEKLdeDBJ`ԁs3Ǎ:H ;yO3x6z61r].;۽t}'T,3E^Z.ƥP?;[xcTgeʡn+9'>e VF&O*Z[N*/!B:Aw?!kJh7]hFw[uW4!I2X'JLѨEMW,+$`<"r!-hzj[BZKh{8鶜/Vkt]CKp5pFƴ2.h 5U3-2qrB^5 ^ ]^[ێEB.-؂$yNlITokBoT>X1bDHRtZ{;FctVm۳o<UW&b {7#GޝjSI>x9} A֏g&q?u[S*Lx4">Z"iu29HS8?ꁋrO6Rs(EاFVzu0Td}yu P;aM R_wE VBRwcWRS{޽5/AJ҃=1D{l%*y ZPϡ"<`c%l"icX14F|H|;n/+0߼Lehu]Ewua0 59> [f3^^ L{ƌpY` _MWv{V7Lh7du!pi9NT,uV&F|(B jnEmJCfOi 3ڄnш36U5JBḯ#G K'FrAnfso3il~/Y:TװTi$$J ބuw™FS%U8ݻ,ƑDޕ}GTC! mgóU"jIixsZ0ߑ͊`;Xcَd)E^%`6Cv\N@R7 ڝ#`5v/ωGi5\nȃif¤<_]Vg.x'kx;78AP6ɇsroW2AUbIYr:?Vp@u:ą33{HZJUzK)gbСR$ ~ǗɨUt]OB%9O\gm}_eq]KtdMhŌz,r&`fCyH$R/s`#N%uQOz;χΧT$EQ ~w?l Eg:Qv&C5Ѫ_R|WT[$>83Y΋10{PQTZ MoqHڏMa,C7Hh@}_,iNkxtڅoe;lnkoaV05\ \&#nU} R2$M=%X;'"Q/K%wAiwrڧ,rf'OrB3NC8k-1}?GJ{8P4bP*c. pҚ^ϪLmHsgƾ2gehNtd<4ɜ#eTp䨈mi=W 2^R{Wn6aJK<*!CkbU"N%_ѢoS-~k/ eX[<`Hk}* W43iW}FoD1` :o"`.,r,xs dnS8-S ͹C.* PW*1Џ{|rdbu|,_@r]~~* + FdH{6DG IlRt tpadRChadj3n)/!\CҘ{ZL/O<*{yxjۨ)%{H)|b+Fd)1pI(Rߡ_#w/< ];AVHn³-(ԅ}K4h`Ce Lm?_,Fdyza%UVj!fR͞'[˥ROOS*Lb1U*uqfSMȵNQ'x$¤]#-xQ${ #R,JæEns$: $3.b#)t'*38?' }a,V 3VQCqZE+qZ ZO">M'Q?e?D@S)F/{Rx_Ce5tHiXR ;H_VeRgi^K+L*x F{5pS'G53Zօ쾋X_LڒAU ZUlՁ^G{Tk*/Z=]-ϰ_QCN||-B&!i qR/dޛ(Yڐ1~ל8n1)WN.0:co+2hy P+7bA8& *R0NvhXsVEL + >PG{B Sۉj ls|OL`08,etv`u*ZNaHC]m?$1)q[ZTA|vFIgY@ 66ur`.ōq] ovu[x:}'&qt8aֱSo7&j~]ta2L濯L5CD](g }Yg$w F*s( nKlpl,ؼ`Ӳkjr oSCES$Fz15PV9wk0kG0v@M}~ǐUAL4ݒ >0# %͋z\+z HWU|~d!NL?C2`9Ɛ@E20[EyxP&XG:_MFVёH X'ux9u.h=>w;QZ\f;:1q2+O%_TFǷISK/'<â]UO,Ւ_oDy(s:,C"{/|zGgR?e9p(5 2MIaY6s},Iն ;BD>BZnd,e/bdNK!I8't~ƛ栏tr[U 3s7N۹[SDO&II=v+%IU;N1},נY CV3jB65F@$YI8,x 80"!22=Ex"4짟1Btآo<@vM8kJ/IĞclEi >i^#ŕm"Zsw5ULSoVq CfjfIU~~-աkU+7ԓjF{!ۼ*]%6*7wBMfnthN4|R귏 0S0T{M.m-u@{_۷_?fiu[0rH uH4hzW<߶즓ϥQ`1I0+,-ۣX ֵ'#n|wE{b:q!1ws(VlFݰK;MuCgԀW s; p ED2% 9G'*W]hW>旯<O+56 Z# 'v'S\+jZ4w5 :~,VTq>Mr7] Y){lC\IYvhJgFۛkcF4șskvv_Q'#4+.+*m&_w@$ +gBhӪ2\-d7k^Q%P_^Rh ï0$ o>F|dCc=AπQzo@I$VMQuŃzѧ})"Ծd KGQDޯ$JWl$PފmS/w[4 v#"T_xA 2bHR HhN=ۘZl4Q 詹 [<2xUװ)[]H]{8Tf~0"ⶖMzM9bb9g8eBXiAg; E[UG7Ɠ)=.P>JCvIg|čAWPTӣ.ؗ5$bȍ\a8Mƒ:%GlT;VՇ :47>6:xwO}C>w ݃綒QF=tc1+),f,Ȧ3򁍔WΆ'D2صg%noN3:&Cy)vl"f<a ƃuy_ Ԯ.3h;Org@ {®Y+C;)K ^.I/H[8݀S]噊a5sdJbG3_jB 9XT 3E3:,WXe(pås/}Oxanp՗͗Ea9c8w2v 3%U8Bn|&0!-Ӽɏ UXmWQ'59J]GAx!\|. Ho]j2"K(M jp8L{ZWt5I,yC(9t ZA /\S"mGZKCaGik{4q[p6^ai;ov nQq 0NCG1lCd^Z-b-p(([boinSZ}uީMI{ M!KLVY ^&?EA438@wӒ#EkXF Y?B-;8C'x X3 G_=Gq(w{:ڻhkb &Y*.^p*caL7ʨ}v0[tDHO)gºLYlCE|O &Evd DkvΉyu6{JOyBbl tߞ|qbIw62:e%eahyZ Q/L/KMgBRzkHu#09}g#Է,绚\S$]_ BL߮PB֮l+6UPԚǔ:cO`p%Y,8A58ON>I0 Ę] 7f՟,}H+.?oCm*6.N -hZ0ZUDke$3[""Zb1M0QFKT&.,Q8T+BNZ NDv|r1G`NcUqJ$~cz;&x"/1cgXq>֒X-f%ضq-lSt啑{K4O4!X&'}iG_WP?omﻜ%Xb1n][Q5z? Kx3tQۄw6pygQoST^QA إTqAJϘi_65rS~n|׍]"_O[$е+wT+~&l4S42ϯCBj~ilHg?c{o>n_E0SLFff:Ј`:pq3SP3ߑp&i 4b:ǑӃJp %[-1lODQu:ex tXd%و8H8Oc Lx(pF2oy ,X+-\m" PZn)N-zuEaP9F6Ƶ:CEd"vJNJD2 .$f̮HJE`w nJ}9H)ʌvHV5gKW ]72ysA g"ZZ m顡 9|LI!P5P@"dZm5c"ܻ9Q@—u z:`Z;(2d˗%ĈX"r5"? ˵rę!sMHi`@}z,yz)JA޿%D]56PZ!K~]誉F⹝a2ZM5G.Cd<'/wy5U2TY/kzL*: Myb;[~i}w(8ѫ+UzN{S^-v0yOTQ#**NYjr\x6V?LT aέ[^L/cŁpg!|(1/%h&q*ssaws8݅c=>-6VcKMi;h`GHPQ=Lj}uaO߮:xQ.ٮ#JqBDn6*75k~FzeԪ8NZ2Td@ W05紤{f쀠?\un}~c!% d4kO$t3F5QeJ+rѦ$M$G2kLyys:gfrAKA;"Ss}m"^4ȥ/V6mHU'}?0~\:$ 7`;›Eul:eDY>DQCNyhIVGuq/iFVkkr;,ԏ*L#"AvIanٞhe&Oʫi27ׯiQ0OXYT{ޓwjZ\.5m= *KjUpX535E nL: ׏|Fe;G?.YTz*'~!E-1`=qu؇+tO-s\ibo!3Vidhe6̄@.s6䀋P{,(*{ Bg%gdpz]=g#g=x]H`t.o?)8'g 2/e[ObAr;Vʹ1"9椡T22A<Xtn H.g=P#V˄fDi2ᣖqVL!|d"ggbV 1at m!\) o ݋́;##6niG_fzq-Ȉ /_ QZ_`;9I0+IUfHCYȥ?se} &J_[X:``2wOPHhNEas 1qGϖ*u%o?nKYKas`/m[*t0Q)vGQJ̙/3 '0~&4i@sjQLwAfc}/-$)H& $V&&@A%nL2v?4j bwiF T[G= -'0Q+q)I=Jf&r#FO;Uvw!'YSG~bGǓStck Q7?&𶴓% S(*|K`:rd-*lB $wjmzY+)ˆA=p>1j#?*Ԏ "]T0 YeڭsIf"_)}h1ʋY5đg/iYy^#/ǹG*JT!Z<ξ|RIvui^FhL8KrԢ„+x&O~!݅2JyND+#r GArOn8?5D_ dI{ Dl?)?OYFB`ە pPghH7>!j# hZs?k yyvGD_SbzL]9HmYրV+-z+/qpP%Ix[/3 ๋8(fS PޠfP>)#O5C=R6l& -ų 6j WI=u\ 8 ,ArV[ zk_& ]o46b"MO&[^;b U ˜y?Dupm5]z 5 I7H0KI0vSSL2Ja/Ҳ^4#}vo.C}8" InhB'sƇR$gN9f>=)$-8û9u*"p2\:5CU0y8 x펗kw8'ckGǀd!+ 7G.VC"enىZ#F7]þh?Ⱥ?c&ZR&mhx[,0r%D;Z12&O˞WZR%0۷mGhq:&WJձz<ŏƥ^N&5Uhjd^Z\c@ 5tI)GWM1xM@M؉~ft$x`'I=CYJ' .=Nl|s1 jC+2}OYQ[rE{# #*j’FmttwKo@XP_icGtuSR)s!:Q5OZ|%ee_ά[,)p7ߑ)aV.Nspf؆Nj+affAl+ϽwR|\^Aw\"s)Ȣ Ʊhʕr?FPNQ3靇_j 8ps\uZ4, -OEEPa/ k?ȯ.4ohkSbCBK7jp*Q"o2`G)SbήMkOC٧5G s2a}o~ P-# &Q (/,O TGɒ387]\N"ո'I'\:R*2(Et%8M&['EOdIњ?AxV 94~܎Jι,O,[UuR.">q}m|Jf`W ت&#Y1l7X˝2@9&ufMr0do 5wUlu; $Qp_ p#PʻN;}VL9i@CI.!JLa-<\!{̒z6I;8-E;ߘ\=I!"  d =K,l&df )q|R-#,OowSgO8=ԁxJSxo=Ԇp E"v0` Oٲ/3V#[, #:цkmUq6J@aBL)$cݭHDq do9Y .韕9hh-I\0UAJƊ.v 3ձ#bUk}ت3GP[Olc`eC .sh)Va ʂ>[ӟuS|a<A*wm2gj5L̐t1<kgHo}Ű1?k)MMaxvN#RaH5}6En,1h@ԹV= w :63ÄgsWJ,0C߷Pre'OEIZVX7? ;s_Ž;RCM )v+oju]&?9bBzV5_;Figʹυ|GP`5,?eR;zQ:&ؽ2 ]riPr(??rVhIxgv$0C'Bh6h u`U)GcS!֫.DEKui>M/܅WF.Q;VK >ɵmÁ5wN1,A\1V-_R (=橍߫[jh#P,YŹ22zW*[w'j47e,i_F<+պyL&D/(>٩gTC*7ڼǻ2/aIblHMVMSk?<~hd{z?0Ȁ ְ|uWUoի0bKC(fg+9;5*X]nFɆSpvC*Am%Q֥"dӱ=5=%`܂J<ںz7F@5*.rnF^HVo]Q:z 4 R;n? E #Pxl?mB {۶?@QJsF zYj!\[ )W5-?mo6ݣ իL3TJw$!78k|O)S8BL(oϞҼsܴNjLqc9maZ̢O? }^iF<+V"Y =$^[-ƽ5Amś{No@G+KQi˥vSk \5{C] 48JOsݫ9!x.^1[#dzlBtƘ.MZ;4 a4, ^vPA"I]هY['Zyܔgw:a?¨!"Nrm7]HdkBzPDz}q2SQo8@&aؐS@rHdOlVo#a`3x >N\xf氝X_źҐK rB϶If n({# y$L6葙U3GXkQ #¸4ĩk۵$HSTk<|IL!k8Az"-4ӷs+z5ڐ,(jm#:䖐lgS{f0W `O QA r#TQxvi,کie˜`I5^3s w`6BIiBg.K[l5IvyyXx!8+7VJpoV>G%1V쯐x !,fUQoTz)ISNϼ꼅=/0Z Z=iyVo&驍z$p<1%$_K? 7,Op1iҖ/8!=577])Q{.g_4W%M "CݴBǥk8AEȥ=p~BDLnL#\5J J~rN'.[o;sRbЬY?Ȉ{ݢ ɏY{E}V45 VMjYx>K.}&GDi4KFtt8ʭo`qϗk=dK7 i0N,U(82=N9Irjp9v0>GsvA WҪhuS~YXJSBY;e$jns wa>njnU`'!XN.nzMRJ%8,5j'; J'h4hkNa0BdypBR1ɸݍvg(BP3ddcٌRQ3(Atz ZZE;: !k {]/#jN,Џ1o c,_%"VkiJ(,yiͪ۽= &q-Ό`Jt窲+Tje 7+[Xu{UoBˎzƓ\"U?·km-& 9H貎66?: d0 %>EvcAs9c/ȮqD OTxKr 0PkZsp9,jk$<(w/Y6-]"uv1eD4g1=Iq\ Jo9r-7*[8"J{t7bQߜB2eq<~-%ļjH<ˮ'lr"Cui9Ёfc4:dJ %}wYo<;1w3oI4u P0ک<8 C^a>1 g fܰvY0 c4nvdyK]ğjrM|͚:iQ3"{AV` AUEN?U7 4 ȍ6{ŞC}ȏa v V+˳ۿdƓ${^ ,Yt-LO.S$rÉlsc֢]MQiJJH^z5/9&; \Oʺ[vV$5f.eFVAӂoa'!@|TWaw5P[!5ۄ CkbSk# !1!qx51ǴUs1Cnd8?2 !4Hދ@bV~7 n-6ݾ]7<p!p t H2ȧ!8v %مv+;+q哈F2@TRD': N\E>&|_CK]wb"@ Qi@mh/ﳾooTzCG3>Ϥs/CB4{ 姜uI*t2|sT `Ka+y|C e 7䥛YOGqqU=۠dF=N?."KH)vvr(~I r&q[,PK`#h֑W֏ܔp^ jNQ`h[A@o}H n_]-d{(7yk X*3qf*iH1L7e24T(S s&RT]4=?ڄIEGZ 텍g,{MmnF=~OR5< _\ g튯Bڵ]#$Ǫ`\4\İmvNn"#yhkbׯqW`|*}G֩^ep7\jOR/"&|{b&upRPѣJ&ESb~&>\_6Pa {&$u}l'RrCgсB5$RT28|E4ޠVWM+1 0Qg"$RFHHdg- BUOs + <9PRd0 epj&b3q77z[:O'%!4 8ߡvw ؘp^mvHB ;MD5|ld2t\-wdgb,bkI<ז6R i|m)17=W q>mȳ\鳸2Ͼ|"282qшv=?7!dF{E K&TǪ}Y\aіkh!5-q'kULW%\>*=bTeshm' /n8;9AI|+Į}&`N } ?DSv<V(iQ_1g>#a<*'l%s'#ttFoxMr%2]~5]2>?LZ8u[b^; :55 3fnD}2P.ST5ҧ&#-KOy|yΧBɱbk/'m'8`y˼vbQU1w8HnV 3]UnX])l?a hdMZʚ軿U:. tёktr=gqjrq.H>9JoC:7gxD#2eJe4}xltxڹ9[7w˛;jۂ+LwK`']n-Ň?m8ІuxcBfq?~Bo^/Ceʳ~_f*=Y&+؉ A@O#]y<*!>^*$xaS 4% Ǹ᳇. h;KPR1-Br ? NӋ`-'hga-SΣr@ FR+{^ܰUBr5Z|g[MP` UL i߰!³/? q%gî-#0X8ghH֣sR_egG+8mп.d`E|gCI|`mL :qtu \Be}RYƃzgFN C jWVC|Dw"#z4eBiǒ+[:k?Zor 8;? x=SWKڱS( j+S],5ι{+'?yZP=n`WDS12/Uu=*X͂adVGꤨ.8ڭ#Ihw[]z!^OV oj]yk./hJc 84r)C 5rFNk8}(C q[= JU} e)䦞SP^ )D"cȈH/$^r#s QHA2MAߋTPc- q8 xƊut݃:>FSIt-}s]mA;cZinHq?'9:gh81g"81a~"ԤRվ43kX V"]d Md.\i`X!&]rٺ*B~=M !9}v)S$:|`|y@5O;/\2F YX\% w=^I 򏰤^UMN14d1C2Lq7`eH,$\[i-Q`Do3刈\#H&Tijj: xNMCV]o7+m@2$=^gS4:g MɿGp462|'nNoc8zNR/Z;FCAX]s(XL}3\5;i0|f(N6S;! ?NMU0R;3kV(g'hY{,ėwEА:d1uVfAX>[{eR_g֯C ʛJyX}YY64ޗ"Yk H^?]! MF NRt8HfxecN/8\bλ$0TP,yV~=eYo`L#|%Ρؓ˟dӔ]A$ Ccp vK^Q sE}ejCC`vŪ&+ބy #=PSr0NϦ][ j'Ǣ'Bj 2HH~~hT7@tyэAb94ȋ:?kV=ib[1 %~(y(NXD(Տw֠堼ϪVDuw7 НHQ!#Z<ƮT9e\J#Т~e>=Kӧ[/!g>(`nan1˼&rd5ђL9)ɲƾ6,cW]`&JMZ'.}u4J9f7۹|/oW_n.NbsѳK(D.9b7,)m&T z+Q[$pJSm7gsTsI*}OBxw#_`.ǟQ:9՛s[z`aCT"xߛj꬀B*'2Txt1Hn1y// I{(~bSK9;< ƫY v#wi.?*rWQ>^ޔHV0G^m,*Eqv/FykO-AdW?u.c0K3qcǣl{&ܧ*Ҩy0ް^y:P"(Z]yRH?sJ{j ?RpT LɱǙsu7]:G=lϽ"9_Op^X z(ZmR`QVf2v<D~^FESi3{CaJ0"\{Xq4# /2Y8v4wfXWמɁήYZD& Ռwb)Dz@=Az_KR+wukC!Qꕁ@JŖfOr]i:3=Q e) f^AJ4F#6WWw$6_h5Y9.Yw{e1pFUuhRr ܞ‡2r OoޜR=3 :IN<)Nۈg̬`g_%^ T_}(y+wM >оH;(Fa_x {ehxR_o]o!Ȕ+ntdXxQ% F"Uԏ{ě|t tdXmrȁk~`BG_A8DI;W*MΙZ@&!̽vd􃣇LE\mcE짾j'gtC)xsBQ;W, h)jhh !IX}Ajgs\tBP_;ŸdR)oFƜkn7]N%K5.O=8TO+7v'h"Fup#|f-zNna4]vuGyt"O||0b35Z5ϺVgz6Kؔyʽi=wK$LȊM\k8ԹRn=p$KMd4|ՎR:'U|t *3ztP2lMC|dkKIJO"8D}7Z4_H\5y|C{ۢpeX^$ߢacgI#RfܮWd0"~\j}Ti<.zE -6ƀ&ԑu@l*IǟךC׫$ /. y5Q>QRG5VPa%C^No5W u85a>Dqri ug'׽V4U]#"n)oQ`8ﱳ.i?h冀M1ɒqL*EcU^~08sªA7xdh-նo i+ 5J(S_YoNy7$ԃUڴ*s&O6vIIgal'!V. yVTރ&J]a3֤ўPNlC$=4>c-&vi*4>̝jX-snT'|rv\ oB8@lέp. 8?C Y[G&c.KRʠ ?ϝj6`V҉`#5!al^gkB=)N~ &F"iv.E)HjA+RDoZnY38z_*~\[᝘SS4Ywb`AUjLdL{FNXV.[py2}awgg`Tx7Jx%mU@ktUHոAD8ch#°Vx5<Ò&}^X-y5;LGQJ$W,SńC?DZ~e?Pt"" LdVgRBh1/pUf=].M^{DuqPZ / lصذbIMU%|b03n0l,ه+Cs}y;];K8?P]Ph  TN>rϠ `]*fݓ /SvV{7Gj4<0B2$xoO\[n Ǿ^WdQ j)%Qm6 `7DP/'~g4&NH]|K%6tzzTo#jACz nCRʮf#Mb5^|ŞDқkC)K0 O<: :,k~+:EFTFy5ފ\A\OmQ >=}̭LDۅۗY-tg)v =@QlCR"0O ?}9F+.,6}.mJ.dq I ,j9yjHdxWFZgӷb8n @UӜo n--uELF-, t 19_\v<#3V^7jcכ3x>Y;Vn󈨧D%ŗV.QUR]H[?e_Rdw(K,Ktl`n>=]"N뮁i3`}{jYu>Z `ilY((Grs"6pr( 0U)sJBg}!ow#b^c1*4vO1a`ԛmk\)j 7_ꆬ0p9D)-e1g{Čh$le@/<,q|1xɲ3c[*W \9`{[Mf${tGIA$]--VZ`Lp\*7rSN[CF;w{WOGcgPf~} ӵrMG{EH#)(HЪk\VoTk"dNG=Nl~*IWV}g2} :3RjBt54&߲/ 6]h%!8S-s+ mә ߜ=obfC#*"^*Că2-2=.,W/f& öba<9;REe03\$\|5ˇԂl ]\q*ۼj} ԓ׎r:OoDVɩv2h3;^3PśTr`CS{z }ܸdD 寐S ,DY߆l!)\H[kG~y ['7Ҫ5[tԫzZUO@EߍĻÁۆ|87:"J'Lt{koL#|><0oSkFW ;qKCkddMPQN@;3*[pqaDEn=p=!K?artwuP#]gT si <_]Lâ(m5^Bx ./4h g$rܚyiJQҤ9'9ի5zkw0Hq!+, 9 6gaYf|DF,-:dVݰ\z,!`&1yIjl,c s= *}v2 U=")=b8(&5CMܗDZY"#~Fdp$M-^:7ιZ[D6Skru>0|QbD_f+I;e#ǷLj-1 ~ߣo>I\CVa=emʴNkU^͗mX %•C$=GfiṰ|f@*cؔ%(]O`0 3<4 kw:TK;f [!t"VWS}&!;-QN(b+?ڈXuyfr$2yt"vi\97_C8 d#ٻs:jϣB[J)xlejt[Ws3c4H0q;=,Ia'[y)3,G`ducX}Mqa|YP0??O7<#$>%wq6 F '_Q(/R^ ҲEs忯b;c1ݘ>yZ6fd+7A3}膇ݪw~e?T:Z Q0gJq/妗\._F!Q<ֺk5/?݈U6\&  κnad$J|GdW-OݫrHy FMy/Gwݮ.e1581H@Td)`-:geɵ2I䢐2lT\ ,M>Oj+yo{oV-5'ڼWPˤίa֕ bmޘ@w8_Y0wxGcj^I A8pjğL|~*;r9*$T  \kW]N q=`RHh>aa=nsJOP3ail0J cw{HdkE䳒rVK;2o|e4~Q:%a7;v"f`u$`C̐J`P7?.ufbD]93RK5j ^\|o< ]5bMׇP vĈɈ Xp~rx-Df9a<]5=byٯxɘI7'u9][),N[B `qzGZIr৏nVF"9njrC *;J!_vLm'fl_Mu3=[^0%<)A4`VuȊ `*x/s)f3cDf DN!RĿǝuv5 )w3_˞wrSD,.gF{մr)\9zS y\CjTRHE|eP!ҏ)Tڎ&&B#N׫O܃Ǭ@ѕט!Rnv@x ._+fqM-HӪmI0xlb4ۂG?d/ϹU:*&.9S/.K,8& T].cg.MxeYWԡꐶ_ +R^ӬmZ/r9=-mao+E#KsWZ ;Z3̈́nG׎̱y/(y6(̛R] ϖ|WS )0;Ḿ"i(IW *FWᒝ]c9L8jֆlM}Ep-P?(`, ]B^\F8@wVѯOSsXJ#14)aAyy:OӍk';C.udBj=E1bs#^GmIt3\,K(\{B  d&D ߶?dTTXx*U &l:shS7V9Kc CbbN[@ڀ0FTg*;TIQ<@mzѰ]Ngi2{IV!R> N@~uϙCMr}j] S8;NQRڃ_E;Kް@yq,>~h봃=نGهB8EI#>eߣQʀ{^UU.Mfrz%\*@AXu*F7o(UeJ]$~6xw8A=Q4@2(%!\F?8X$_2.8TD*s5`fP) 볝d,E]Rm{mYi|!qYE%xq3 4_ w0N'|C_%d%kwFEȂ .NN[7"ewf,XR17J{nbXTxW,&Ѭ{M&Ќ⨤wGvS֭gelMC#Ձ)< jqIdsn)qOY&ޖ{, iLv X5m=E'Q~b$V>" ܡonj v >3MRIư䥕?>ՍaĢ x]b; 1|t"Yt龍 |@:zϷNM6vYEUK#xx]'3iN$ҐSr`6y»(ߞI9 \Z#Su ZE7cnٻ3E,e^!㬎:$7Nr6sI@Ӏ W-wR}hny_QrE8{}VxV}Oe~1ZH R"olX  V=OkOhOMzA9%m`S)Y4{Bd!)ǻvX횗Ƭ O '=Us%.0 z]ő\Vq18:O.#,ڳULdBZB4X7X)m>vH0} <7Ll9*Q2d\3t^oVXs"^ ц܎MygŞhKgU1YnV>OuTqj?kyhh`¬WUv! u(Ghv~HMU IV [ILWpBʨ -@1zIa}l SJsL+Zp$z1Ɔ|37Hd3K@v]ևW;qX3^ʪ KӠk8]_g)6(buZ*fd״isuR6NhRjoSk)Bg}ٰ{oX/`] ?7FtkJ~|uL2s~tuv_?gFanWwVy#Z<3il6E$ih ?{>KkUHmβEcܝN=>h3b/H-L @%b,:օx?Ye(GT)wG恈tR8Xo c β?K>Xel4wɽ<⳦~ z]Hv04~p|M)dD]^N@chDGgz1NZ4_Pk:ULDt}`Tk, Se@A:黸 nĈщ.+Iᕙвl$)ȢI2uњ+0ԀҔ38i_5\Zf>KdtppJLTNJ9C?hA:9\&`]Q+V~F2kjBF]:.szA;ciNi@fʰY QBsjl3yB3)cɲ+=l(B#V'ErƓs̤,^7شsZ9|JVlk`$L\q~ՄJApHqkVH,1Oq9]Xb k*Yks}[tcߦ/cMZ|1`?n" SZ)q)H'>yYC5 ^/IrȅrNRd0w~  OBv!N\&«W5" ^_{E3U1N0qe%+`:V[gfK(㡘;5I`zReDϺ)՚_Y퍸x!*d0I{y8DPϬq\37)"W@'e67;K&x*D2sh7g/_ZY)/>GtoUOȄP+|+>cP㎐"ɁchDfG'cYt50MuMH|!vPZ:qmȭ2*!(Ŷ۳`2xJ}r0^)"%<#UAk%FWТ S嶇ҶS7tŬ^tl%"n ODs Z369exP5 jc 1+=U*?, Boq%CX?F +pׅ>.;&w9 a4 yc*ORWTc; juYx3ˑŤhyD j=.3e9*ݮ ů qt#1s|t2y1m,bȇ:i4IݡSű2^hpr^,,L8|9 VKQZwh3N}\9O`" ,3>fD Fk{hĞIN)=e3yi_Aw ZPe99}|Fa bI6*S~* Zɻ8G&kop&zb]ln\sgR a'Yxr+iK gAF 4ƺ.P3O6!o:lizՄ]X<5VBpNt]t,&>OaX*ȅ녱aQ=!9;Vk 'uH1yxgךU C"c FZ4j[ڏ >EkFmú>}9Nh^;H 'Z/qR'tuˑ-D0=.u/]]ps 2Y=x PqXw$f5V#Gr6DܠDž5sI>5Út D從 xj&ީa<8yÌ~|9ie'j\TM!WWT@^[KORpFRtq}68"@W7rr[SaĨb;[]xBdz=-fR9{9br1$,ÿ"ML'i\ZG/=GW!/(H[H*#I Tp)ȰfrgiՀ"61N+}ZOrE p|]liC:z >XZU*} 6{F|L}Oſf:tKa#ebԙF|WWYcHH1^6MڑɀK/cK^DwpV\@8z> L1ҷo ꑈ7QE)oQPnlefRlZpQALmrX ȬmaU!ܦ9+w/ѣ00]ܲ`m U\xh"@OQ٥Y: ] t`󲗭k0f2^K%|SY/P竸*"i Rz۹br6=(t 3qjGU|@̶4g7V`X e|'d\o?0u2qOǿ$rT*iZL 6WBӕXp=,žl¸1X<t!D~q^9P~n_ vdRȉ*7Őbij QSrwڈ|_eL`Iu6vlxlTCv$.]@NYRy`sߍc/c1Qh]}}؁y.3Ej(s cg2&C~pյ vw);WT| QW%߸Z VKiU9g-;okqEYv69ON2|/\j(qFS@_m6o= ǧi?hmIߕ ҈Nfq1fdM >,gyv"9:pwQԾXx3"0Xsdc<1R&D:?x[7%Sv‹S¡ RrDG-}24tPd3cB{DD-g@DɆpUumpuEZfPH|yۈb ';Q{z"# Ͱa ?cdz^O=eUV~ Oo@gal #9S!tv{/`Aj*}h{X[g K /2;?2 `,ϰҊF+G B!H%u^ EbRDfH1bל}0jq(=0+F lDURiZ zHG1Y.xRJas[ZʸgϪ94MB;]J+Hl-=y燢|P= ,ag4F!gg@>^5]1TK~0-M͂D_TS9˜JȐ?c1Ejl+j\Y^t ' d7ۚ_SIy=~bTk ؂u53+-QQCs-/yЊiKf[:ɟiðE+$ά5,tMl7zr}>(X @`R7L=bBz/.0]lQ0opGMMpp|HEqx ) cJe/{Dt"pcxH rp-`ޣvsp 1JhS KJ|FFҽ ؗ/4jkS.JҷHD(nB*+~Վ;l? 8s+/;ꮖήx a N7lSO,PчލMփTX^2Җ0U/;4%p #]E9Mz>z&,RdS,/eMm[XZۙ= F#G6{xośpj-1Qe@& I< OJ^F{(R+`єV̸pX bW洁R#M*B3Gb#1/'E>2ESy~]/I@A<.o0UzR?6'M2'v99 Su4+eӁ+uy(.'`Hˈ%XGL(׽kRecFN6EnA0Ou0'*ܱCҀzyYrf]kLl5ÁUԫq;Y^V@3k})rA1 ަOBn`¹svlif`t !GsmN PdB;{\wÑdl ":6tJj\-J(l2!>*wPz1i[}^T$,*TUp-U>z.Ӷ3@ƛ+C B,VWK߬X,4gw{rމΎ&W#V\CX9]I_8Zg삨=V/R'"鐉t` ]UMӊE'B,mw؝(>≶Qźe5;|4Vl+Ia:E.t3+j̬ 7\:m5pUݜT!ˇ#>#Ca< V cxD0@0 KƫWKW`&l#;7VnuÜmN jsv0@9{MԄ4\ >֐#O.k,?̽܅ lcEhNus5*\xŴWvh:sW-]$sop[_,Ji2_ 'w=  O 7c}%weqfSt߆tZ(%A %d|,y1cWُ N'D~v92O PA!le㋜!WT0-w0b쾽*~A<]C `ڏCzU602[!vNCgk=Z"̔x$ud`{|Ȋp%-qO.hC}NHG2tc4R̘ڍLKkH~Bqp ֍"6Y9 4N_]^i?K8N 3ڱ۠؆7tI=9lN3V=QA.Aw&LQPkЎX77Zc 6]1?}9| &}=B {kK0?f|vj[W v`!Kt~gRӛ)Vު}Ϊ$k]^q<{3/ :|ua^"#M*;`pjNZG=&(x_Qlc7 t~=1GKr{ԔQ{5V9ZFyȗњי[6ci-jw %I+4K^m[Y:_P<;!Lê „6/gSfǟF /g溢wG] 3t`BM/|*&a{%I #3o?LR݁L&R/Rg^#JՋ.<y/<宷ur /~)/c)@}&=d8]T'ޝ8[ؖ퍏^Щ(VmIIw/4͎ÔLG_MfCXyX=/J|熠|)VuZH)9[A};7sNZȋpFXC0ua0'SZG].xyrdzvf¶rŞbl2ț/}/zk(0a[Q%C`#~Z :HMkCW7z>_pR0)兰9}=Yc2 P"=yxKC# [qFVk51m>θd[*$!&[wAW1NIEDէƙ2.a\PfMp=p^ ~$Ϟgn[rD\Xft$ .o/Kb2˨¦gw^P/( ;Nnuu!TֳP@=uVss/Σ˚ӷuȁ$-1 (ߛ5QOroU-ZjmCfNG\ltA^y WEw{|i{1pI vm GL+L%g-KGF\GI47zV74R93Z]) g 6,@+r]ap@PWNX̡E8Yr5 P~,(<ι8|(iKPIPb@qLA 23 v5tVLɑ'9A>V`)[!tC?y39*x-OF辴zV %l vр[ӟs#I²csN3غyaapV!1xQ8@džAL/wK&k/Rї>bB1>T^^; Z0&Ggx?@ru@'EI%讻TKX@fz-fNâ{| Gpͩ,a#z}sGL(/=sd|Y˩mNp3 >{opEAjs(LFpehl)sZÏB`#yr#8G1pֹFr͉ Y]Iff9Z_e;⅛ &1Im]4蓤ժЙu6AM,pomy%AjY|aP oMĀ<\Vy'vᯉ22{0c:SS݅$/ooyNrٞ `֕3}]ގaRUzcykq؝ZAGzvrEZw|ʂyĸwX|K\_߻ ovy9} &nM*m"m/Z..zjXAdtcS"Izԇ'⃒byz~`f+p#.])[y4%y=;}rU?8&/oW>]`jn UVW!x]H@QleWBt-z}XҟcĞ״zM'Hx6}/m* ގ AFS⺬2'd.@]Ц-4Pvqor;TYO "5ʛ!B''mIXOr2S_pqcDbW0z%ڏЁ83P}+Lzr^0{ i Γ#K%ބX<,AIWPq473,m0ApHfM6uYT =ukKs^ 9b+L&&ZSɏd}yőbP6N_c=1V߿;( WxhEf'HQ;(NJ RgѼ5E& T cвCSEva 6~DLXk`Wg/i |6ٺ:hGG$ KAIA ~N uM K8uU&::<# ,'أb_ s4MOsW7 U>[Gye%AN*f]Jp`r=Γnǡ{E\z锧fPaQ.wTCn 2 R|z0Y!uQamJXBoaӯ>$e=0h1,nsj`e1;cXv]/a佱f,C~lYCγ\I }I$ŏ!2t9Z}Y1շW~U详we$eaF[`OJsQfW@dӤᗯ uF6A|DŽ߿3o7nI!`y૞ROTXZ?"+cBeQfPA+D+ {DOdt@練l6O[m%orhPwv7m׭H{=!ώ4V6EbkÇ\rr>t& ܻ<*ث|lS7pP/ٿNyl' 櫭oB?Vsx_"`wvVEjUsgmP% sΕ Kr`3[g"B(2 % {يRuD;tZMC)YFտmT!|Aܐ휺Y'*̨̊[p;eBG}Ee,w'~s2{TLӵSRXAo#ܲxF[Wۭ2q ͇RN)f]76 XCtOs- m;>[wVri뷹F`C)-#)`h(ܲ BygTܯvEe^Th{ .Wţ`}77{M4J; E/0z5ᙑ$,Is5,<z9^ѥګ[DW}2m҈ :Q4]-# zbZ^d96jB}$aΜskQ"I]b]O*inX@SGguG՜@H\Zk)/e-&?! mOmteQ'mPUɴKAa%zYHy3,$}jyUqMy fBm/J۽>c˽VW+L5}O 6, l~ڣfiE8 fP!h%|׸8><Sp]pQstb!v;%gx5y HbnYo IՑ.[e _a|D5K{?|Ŷ;ӂX'A3mk'n 3`F5"3h`?/"HlĊ[ b"sBM VQ1> л'nyZZsiܽ7|J7,r훱i݆!0;YBH)^lL'-:IiE `ӂ p( j^$4O M;1b'v+qߜHݚi꘬bjkHC1ɽY*!/?o{^ %z )Kz ˈ Z VN]Tk+}󴼲YJE-+i]{w$&9N?u(xwXyC'Ui, ̖-L; OW)LWߊ>U"=G<`eG).l{K8-s[T'礔شWoO6tE,sKŖ}Ϝ  屇` qKXE ;<5^ލN_C<I!OԨ0f&PD(q1 ?*\8!I2䰳|jLxJ"ޣs0gd|/}*nc+*ާڙ3pR҈9\5"h7r%lͧ)w 4!GURvY5Ŷ~7]RE$#"gwO7t)k@0cxZ&&hR!]m[bl:~d&}h8ũoǏ)l{7->g=1ژjC++Zk n!Yq9hMɁ̇U? [屠:E߹f`y$r$ֈ", ]sjJ_x(H:nCrYEe16E(y,[@T鶻nf &Pvp! K2b XV| BnZQW)Dο F/.HMZ 7e~֫p|c}s$qmH1b8h/x;nZOKb#zYp̜q BAaJsYp{Ģ 46BM (g'f!jt>;D f+.Dʵt'LJÁuz5|oQZ}jS 'w U (D::!ir ¬!JN*|Tx6Aqxjo߆:X?He?/#^YK겒s+EggՅfl xR!y>JeaUMS<Ѩ9g^r-- |<:'VnsVn]PYmeC.OiJ,e-Ĉ^mi]y J ,ntOJFh[r?Qd=!0<ӫVQpN,ꗓzpZrL-4FOh^mS岣,9oJ `j yeYl(t;z""*wzVrtNlX'*A*P:!DYHÒA6;.&LiܔtZQC= = FR48M p0ߣ{QfEy8I*-NUBۼ pk HD/:1q#%ف ЉyRzsGJu-)RU)5v)XXoS7o>`E*De݆)xRΖt9y )8"Jcf.@)#Ej\Eo<žMK>O!Cp,7MUhVrxaU՝+nJY&oUprTm|V܂IAq4^H0B)6Z}ϧf„z9* h \1"p}C: |i|D 8/= 0|G*鴆S٦qm.54wikiW>t[j,sdyʧHB/)%yܑ2̞<)@|2w@ՂRVk˳rٻtG r"%5ч,6IB.2_XJ c\_Y"1oW9x(,Y|^-\00˄7+L>SX90TLg8)['!}^W}TPa/rly&4q*KHCf_&vvJ:_j>Ħg9=f**nMcg(HOxx؎MIZ,- C ֟w;+c߹_C&{nHI홟fSq$'jÿƛ)vI4EKyH%ų.#Ӝ+tz wZ_#8wYaN2ZwST @S}\.oszM \/#J08) g'hmf\Yw':Wᵆ]U2Vsł>ubr)xmЫg{z 7[u{@ m%x°`F[Zj7E+00~(; /y,M<`ECٟڞ3ZJ0tl:7ŋ^+ }WtDŸ0gYoƨYm6/7\fM^ׇ<Bpy نhD)ڸf 0>!Duk_IÛo=w:r`|P~6RA0٢lOtFܸ`r4d<j9da*h#2)EaFQxFPȱ"1]8Nq{$9& KR $ᢑ& 8$=Wџ"^tb!3^N"ҏ2Y,D Mc!LroREy>g샮Zi8t!Slh s_kwZ;I2_-,GLG JЬXM*Utk}_E5w&N8'w7 f#*bND3>0;Ha!5σCP5C J~T>h:$R!$+A۩PCy<7ʢ3Gi3G|~Kt1[:ÿ~ &(#bJD6!-}i, yRB&t=vWԜwJ67^k@D+bP,ursk1Zߨ-jv;P i".e-HpIEv;f6 m8T]d6Qn8b\z^u&%w@K㾻M޻\LTEn7Њqg<@fų{ynR!M\-hqwv%Ys$>:nG>zS |h$ʾ-;^؛c;W_4͖^RFY,Ku {\ZEkjHlGi+|ͻ_jދ[JF)M837-ET dƄA\2%^3;]+▾,9`Oupt;J^&A:($}&R BSH 8,!6|;$)o*4V&ķ{Π>^4&eo֕B&nY 'ɣPI}-zN OasV|Wr`{97cy c'4@PK-\k0r0usrO=w-1VvMk2ɑSD˙=zQh,kWb6/,6ie3ɣ$"8 7 ٧+۟kOw< 7M}4OIi]ϗ^Hdg{2~qpl/*E_6g:\Q $'ǐ*;;bj0#k/J,y+n۷9al"c0gkq-8臇ie ~nj T#@7@`3+~͐pZ^.} !5HguEA$g |K~gVo0NvS+bnѪ%eE1&/.<KS>S=i#vkFÈ0&JjW+h%V^%]d 8jUID^w^;R%var5ׅa3dpX&`FJ[h.tx8@YQ:9?$y8\=Ǡ%}}0M]-F5CGV#f%>6)4/eQm) R1ʶA}`, +"Z:c$?鍟%-֥bH `FOb?10W2 bJL%AZ/k0nhVmr(-1;PA 31g=| ntd^Wd!iw$} iS|K}9.^X=MvuJ@*V <<kh'Jnj2@'lb6U!CHpMʦ&2ڜCޠ BhPw9?1{X~wcC!ӅlalFiNZL6Ѷ j~-cRjoC01TvcRJ+Ee]\&dU0[{*K]SuJ9dPK&LzDaZYo&/tZH;އ " t $9$%uI4D?]+ø/P7`EHgJ 7!:hV%]^ë# tIiƜ~ٵPZ)*Z`+gos#eBԃѽIZߚep[Mcڭ]hpsE3gQ"K0F꺡ֆ8Nr=q0|FgYOHz/[=S2t+ lWC+N zIrXr 殈ku߻7f,XHEi d-QWKZ]xt{X`8V$tHlSd{>qjZTv 2!H!Se'߼*.:O O}9[l ԋs10Ki&YcnXx>$ ?ճ%H?;~S:Ci nd`^1o@>ǜy5H43h^ЇM"4!%}|!inRwl!EX&K^+0Z 7cuDSo޽qCFnӺ6 QH 0#zjS}7= ջe=O,;/ADTF\7-CuLQVpv(n26E@Zt+pRͿ9.)hz>hq/7qV ?#|T㕉s,C;S4tL PuTZF _.~p}a6M!74`_7ppc̻0phL m:h>ڏ>!",O.tUor@u\h"XB.=h4u_7EZ⑊1ªX F,W; %~أɒͰ 1!zsA?p>_"KW2_/+@ ĸ߼+/'T>U?) *h2]*<%A1o{:&Vt\Đ.W̟ ]Wh61֎aRI/OWUoNYv`N?csCW.w&1d ${ bKH-ې1V-Sh'ˌug1 &ncuc{dh#ՉI\0w54 jt3i~Ñ@`g*\=Y%: [Ͻ-_mx(Om [ e! 0o "@֠㑿+^axPz]R,K$'50߅K 4X3a\{B9Gė>_zFpI^$wG7I+6OcO`V@߀h/78fcE K?pC.o>dAÈۆ*>&BnmqP4HMvظ$J\G f|K:Åb39:nZyv}0"j̵\vGߧyVX ;K%;Rp|!Fg\2?HпY|oVCj;f !xzG^U9aThM#j &|'ɘYr ?ѥ2DO0 n]pcxz&Nttru,aMXM{];cvɴ{IۢnF`V\$lVe߈$T,_c*l ZkYɃQlk${A7嵿- 9vbwmMU$` (oڀLGD~ P99(+ qS8E%v?`G,4DXY&ux75W7HK0iYU8!"Lpƨbؾ%6.tY.L@h\P鞱"Hk'k<: [=V~SD&d})fI5#1f?IUrY.# |ꯔCg)x#=7$Š/"76" 1v9W&M~ p䭊0C;c-MXد}scٴp~et:1#q$O p,0Dr\"mUWw1{SkZ_$UXQC*ꇎh/A6]i]Bfj9X$,DLly/=Ζ%'AЅVL7S,5>w=Z?Mb=\xeP-Wo.-z[JOGR=U̦""y w3&m pgQa.sܰ!& }cԙ/|%^Ș?$~+Ud`mR0T{bM%yzhQ0jȄ8MrnOK͔mY5ptƏϻA.^䫻TÜ+f.'g_21ԋatJJa`*jw n $lUUYa<ͨ=()E2S |mK;VTɼ W!p[ uAЩfx&"P}!#k Kpjjo~R~1ƒd6Fm%x=;옼7'ch6R<8hHzO{j%մ e9aT_c)]_9/"&2.ʛUu#dhI909Y(vHB\XKK&z#sP;XXƣ% L{1=f'+pGI ,3/F;1.G*#7JŴ.j1湊K83߉Tj:iͰ7ߢ$֦QZi,KP0Rg=jpI/.Z'?>&I6n[7Iv.Bu dJ:* Z9mLο@ Wn<]]">_1`^_vaboͿv{4}k @q8pǗҤ5%f%8k0k4@YTsGdO0_=Ocy#;[EnԦn;`t!ή0wNB/$XG/#Ο2oM+7Cr(uQ ՑJ70")ڦs;*zÒ E(-T zlgi3 T #VQն\(˥셻PqgQ9(K{NZde5F ;NxXE@~}4La4yYq 3>W[Z)6amYE:I٤yQ $jG60?vFIFzwl2._J<Ŭ ;,|"ؚM1l[+$tUuY̙ U/ܻw o/7_LI@#1`&έDoZBd~XOp0@d𪲲K{\@u  bw_xtD;͕+<ğ; D+zi,;8VM`iRxutka`4YiPDQTrt^ IE ?[1^)vMMыWZ@)wAֲ4Ï"zG'hHaz֥eJQFY)诇 =ly?`Ic`BBN{=ǧH{A";[)tU^oᛗf\\Cq 0B y}K xX^3B/YuZWdU "-ܛf$0tO}Y 0B\ITa Ǜa˃?;FE(dZ<}k6T;]O#q,k`%~;;z"_[OpFS&[$mMVl#"IXN҂HERFa_wgSA{/ r{'|\jN [0%KJΫ>^;,3&y4Q~f44_]zBYLY-bA ?W,xį-HCxKXoD0w'ٽҙfRHCBlšR-\OypgFʃFChQ{ 7 EHCZ捯US 1N_v5MKFa;RN81祙7>n؉`FH&7;J;n$|$yF>2^F_pnqsh[fJ "VI?\g\)(gmz'a/g?lΤ.{.i81uBfUU:BO&a]ƞ?# UH㫠emri*+-fdm<l@G%.B#ȚE`n2:E5γf:nD/E`+YBf`$'o,v5~ vaNh9ZUk:TsJ݇qb'nP\K,Fe _jMɆiE:cf^܃#m,oFREŠ8qH }ABJ}[/6UQ7Q'X( î9Шb.%C3qdKͶʖEf)4Qg9Pu'Xt|pLe5ɏWʞd#BPL sHs{ȮyKw)^͞C>'e0Im?Il~mS̄+M#< jpxo  jB)exÁhv"P8Ey\z AFT ""g_03]1FEE;Օ01)ExA*gTw l@ʙ sx@t^tZ_x0&X(Av>y3:99t QCmhӿJ1Uy n-(ӤQ 螳8 ߟſ,9;жX&%5MMjEgoחEF۾ 2"+ilg84Cg|jJ~fl9-wWsNkJvŸ!.lЗE㴺%ѪRsV E'dAiI{44T) ;&JC c4+zUpl97 mn7PW3KB[)b4&{i]KZoX`fBQ%#S'g.wRhydHK FFJL,J$mc/ɹ´t~ڢhC*[,xoQqr%_;}aJ > +Bsh^)ډ+y;u^B1h86¼jzE ,5䧹KVk# ELi0ݠ<V1k#ѿ-R{pM./Q#PWVZdå iLtT$`ވB ᗯH+kW\Κb MDE:jSwR:%?W,(0|ӢڈlFˑtp'jDƇ8,8 /^UyPI_$FNfezM.d^XfPŹZio}9}~7;ddO؍IJ eٕA O 贪g! @Klʆ3SJLcPPYg вSOoh:ks,A,LdNXgZ:Geg"\ ('gV?/:G:]., n-ѿϕY&:7oX|q7M?U2`\gUpU)EdU @-wMsҝhJ=0Yt<;Q'5\8\{)uy/s\|o7$Hmrs;ҩ/INr€k*=˾G'S:nlX 3ND0G}QHLu  8|5aE^#Gw{u 'jOk^Cc5Z p'xR)<{kl?bODux3;Da֪xF)X=F<՛/LֹJh.'b| AY5?u 0T=kXcʱܸ2^>$H7w~5Shay ZbN0Py' 0CdbcY9}rzlDc&o@e&*tڟF TgzxiV:`=<0UF y2o=\bA[cfq_=[;J0ep}[u2nE]# '^J31a(wTE1.svzQxuab~ \F2&e.Ӗ'ދ V'fa,tYmΌoZAfoؕ1M7ѻ1aHxԑpo|C>M/߱vk<J[мVeA羉k;5`h5˖' دTlWi:1g"ax+`*yu:V IЫ2NxɤL?wq^ƋSTdj(@ʷ|'isF!9"f;Sa '?YǗF'|~$McݫMGzM8 -ҙD.U俓$3Wwճ7Djj]~]c6l*CnI~p{Bvgss;Túu~sETBU|n4\ot +%K(,(oz6 ˍ/kiES+pRgƆ3=պ_\ϚzQt̫js"9u_Nlq xvma; +'Ǿu R҆Iɦb}9%l`A@,6%0O2.?oxwU@z bv&#~ gI:D60lvIcd3k2y4Z EpQ t^?3@rYfJ^CU8f󟌎I7tzSiE|[Ez`Uaz - ZIp e=g(+R!<7ws}7 /HnL}RòD12|CzأCN]$WNb)zLS^:NjhR"HÐ 0('}nqd8USb1) IuR6 /g<]4ڏDjX,*; PsuXUEh`::KfEGV,Ƨj:`y+_|I vχ\#ȃO#5Yl߷ NT۲FC[Kz.z2i^oLC0xωv'ASgPCP6K[V03:&.ftچ 8ooý40x̜.خK GѦy7kgP_R|4Pg8-gY*x| =z=٦lV°ހF\e~(bd[1AD-wMt;\B}vrxMsdb{ՉqreEf]*wR/@ϵ@=A2ua NS 9&ĥN^ȳ[Tߒu g= bemODס0J^ha-so)nlP:GQG#ըERttwC-nV5\8˕"y<0iy:mY9}b)*Wt<[2WIM|mަDUӭ'%0?hEqM)];G7:!_=a*R.u#HG0ٯ]1(E\XTR)cԗa=24j816J Eb`u{gS\TװpI2/F5&*ƣThX΋4nj-bD@s"XPp@pZ!͚}'{sep߂$6A:^ҵy7+ͥ9䎱')Vq4b;VnP4#S .V+ji6 *'E3m~A\7]I2fXr%'/4 [v~]M5Me{{ N ,Hf8)ֆ>JZ'|ܑ.ꁹ5.X"cVX1IVN頚;)IH00mks;]ukm>:o8INMJ{~n;=uà2N[G׵"dT/`6lXdrG5z$Ԫ(_'҅& tSx0WhT>J|0H^ElU!SS PlG{hwƛ*'Y,ʧ4JXԨ 7˟sО_UަzNj+9*W/ SB{oO"ժ=g*D:>>b.:bxByD!5k)3.wm7=%?"?FQw1v؁Rk/?DRMO ]AmqkS? ׆n|ywoKgeǦ m؜cI7_Βw7lEi`Es$v Np6p$l3Lïm(z5w+WG:"S~Iz#F6v d(]G8+ޭT('Jo34$\3 LwK:^r)%4 dZC ^mg-2+h EEnSOV3ާ̽'B[·h jLsy9"-ژFEWNI1z0S\|~xL9+t.jĄڟSȌEԾJ[L4vs72<֩zc;y}Ҳoŷl{k-Ѐcq.{#]mƤf]&b"^ 9E%;i#b`yT0Cx@]WnjiٳJ.ҶREd*$ˀt*< w>MB>gK:kU4qfm >Ƌ),b:&!>(?}{El0t|ZnSDN`,',"Z~`/" ][}AHD Q6%^]lޤψ/'QBi/<Y`xz00Ck:}=Bt"6 hKlEPL4q 8`ɻJlc9{u{춹0:5ebFk薪aUٿVղa%pA٥*\D/..W,R卨G;Yljyɨ\'}Cyb>6OsIIћVϋz,}o o7`22$bQG2l|]ȺQfzu+K.=Z$7N]26stl(S*l J0{Gt@<>A>ΠX5+Né`lYvnH6HOGPcW̓*bO $:͕XӉ.cGjB?_ZhǒzA >珺&UZ-\4 Ir@H!TŔ +G0@R34/櫟U)U.f{7;oF%TQO.n(y3ҕo/,,믝QXؒu(<kg2Yސ;͊I[ Q p ڇjUx/9 RGdUh4QΑLf`m:[ȝMf~LB;1S, AQM2IЂܾ#z&ԗ- n9^ꗙ@PfiVYq^!3x.{hCzQ+ߧHFH34x7mngv6v)x=BMtl{pMŀ.ڴX0Lf]1Rޢ <:[0|Nf{~gTcM6e0 Ael{Pnʓy$Ko+5 +scN .]̢7 wE‚o2Z ejq.^T~aVcDz\8'gࢶfn='-h@6HaI{cy(zHC|“68i?.uk3r0vv(qn'|-A*{o%}U [ 8⻖ {!P0E4ׇu)Dkf]:8MژضZܲ6KGvYUV}\Keb{ztbTzhg@b㚗q@i "\:WgyssvbU?J*.mt]D;ߓ|Ru(z*K'p 9lZiI mA,T(hT\f`*F +B94y7sU.$Ko[kFYO՚Ω{?o"E8$͕ŐKl]@{L5 ErKXBlGdmp6Pa Ӣi}Z=%KMDRL?V@}|)gv-VB¡tlcή }CEݜU^z?6mPjɨލʨ\cV#Q HJv^PvU&T̑S-gwHh$=$9Bh5Ve(̂>/Bq>);7[넖ݡE~T k[J3ӒkйrD'ㅼ@5HH|B/CڬhM_/.Ebɷ Fl'S(*ѲQ7D]SJZg:[' W|Aq 8] xtJ(eRSoG"r!iQc?p}J"wrpՎo?:CM✁} ֲ;"}uԬ@ B€I!B@ i˱ЌV`kH^Z"~eC|C'%EЌV3W9p fr]5*[J5n&Yzq= ʼ,<0 s6ܫTIq(pN{ G+8Ѿk"nZ6|̀_j'-Ui!=pʣFݍ Y4(NLXOKDխAB̢OVt 9WwqC3@n<)B~+yvA0،db,;q,;/rJ,◵Sh>md,'W5.n}V mׇ,̝Ѱb2xP!ZjwwyL~%bS QiAP3'|4nQ!LVmO8p:j[ 9Wv_}0O`lK/zÚ;iiY(#}&_W9w~RnhŚ"nc=Ydf=|p.7* Òz?1qUиz1ns|ݔЧQe{@2Yg^o[)?'oaPH"fN v>2[#TLBbu9LGr. .hEQMlF[u1mɘh'g؆Xdrq>yCZT=ֆ4D߶ȏOPj?hPC-0cDZa$@0X'? "d t-I~(UHvZ^F7) :";r'xqW69q KI$t}{um]02dxUv_2CFonlv],HlOec7(Kexѳߵ/Ǥ?o+yOI,.QwHg`VW_,[蹫f#Qjlx*Oy<+k~,lb%Tgk΀7 +"҈&<bf@ 6vp٣ԟ<; ]p~ =Wj$_|Zg0%1O}y:1Dp>'E&%9τ*3G-JDi ܾ$߇?49TP/ZݤsaM‘@kwSEG4; ]b1R'|gd' ֶ$5̧?oH#*ikBxT˘DʻD~LI3i7B<CZKb_7wwmU4¦ܙ9ԳO?tiLhDcsk&a/aܘrqp۫]H0sU=/awL͌ MKmu! XWDr/96m,OFBPmv7q j53쒼PHzVL>MdL0%#<-8IDEՑڢH@]6MAyUqksJ, _G>$.NwUuZ#轎+8']T'c CN-=xf&:Fׇw&hy\]cvMR+xJy2:2cfKÃ2~sH0: &nKX㥷k> S:bZ΀xǓXc`M CWve(͓ǘH(f>}%DI ۤR2,,b/2v6./lޜEuD yq(UO]f( ]v>6uu2p jN&̹!ȃf ݝM^nn^0%ਖ4F?=\u3 l5 D0ҡU!5_SPŨ[n<8U`L0Ĥk0$='JSڠF vМ>he jͻG{|HӔgM~U.IEvI]W}Xw'[f>cbJ19]F&d@ @(㚪Z47?L͚ZzI/K8{02CM׼%gۙe4>ap酜w#;利n /J2u).^?5V <֬5 vOC@h_$QO*ԝéggr3>;Z#t B67J-foML,SXWnI=[mF> [f&i- _g斜B9f=Ȫ7䧑Itu`O*w]tY[V6ة"J/?7=—c-aC(M KdZz!a] ʿ׈'9~PHbw45Za1T7xlf/>w#f>ʈþd9_TdiuTUh*eGQ\x;&aI X9Ȩl94tn!`%  O@a|AWV ?\&ՙٓ 3h+Ki5P17@M,?㚬xrrYS`""i  zY_ X) ERE1. ,CmFZbLSpuD2](dPN}s$)uV4 k?JN=Z}W{*Kٔs`0 8cݙT6W,]{0أ𨶷ʷLa[vƎs8RZVְ/تz{njSp}jBm]N\ W7XVLRa7#,D>axΞY 4=nrJkFeW-z i|-u_:S *pa3$-YYe)loEpTK/{0"2k@9RM,ط՝Յ@ M Q;?<_xjOq- %Fd ? ueBZ>Fb=kS>G0DOBLzO+>cRg\?7|mg ;iؿ맾)y<$`JEG|#ը}h3H>GxU16'=Dk7c͝`D`2P"򒐶 Ojgo[W?6'ʎAbq>X]=O;fȌoe>Wpvcqs^p8e??!'g$kq _66C}7F?&+ 67g:`oQϫ/5n$Yןs,q5"1IpK 0D&\ /\[Y[xJn24|r7L쒢ArB[ui[s/[X\V3U2(f5SiNiQ> 7TF?8j? '+ԏtqw\&gnj 񭵛NQp.c9t= Hŵ1 /xP~cI}h0@\GK+aB]ƥdZo#>{aȺ};T~!+Wӄ&|O'$ocjp^сb_[;e:}$;mm!^8 ˎ[ _^1%e&Y&%0#*wȢbDTX0&jC᡹ nkT` |^rOg% b] j-̩R8E= 1n7 $nuSŸu# N7@Є=Vid> o }҉zgqyk!ߊRq[BU<Ś:`Ñz0Ft-$.dQV6ngw;`iHulq Bu|+z{v<|S 9d1Nf)G#g'K>R y/"4Δl؋Qq8 /?[lܓ39ȩ#(S8hΣeq&B?W%*-Hb_"Ƥm+mt3w$n\G.ta|[syK> z s;?lh$1RD]ol~2 HFv"9Ӓ [˜IՌUn,%{LFRs=J}Ww9[8[-4\b G'_ t:?39VV;Q^Άe9hq-AFc,4#o]շB25^:@bI+`\,%/|NFĹυ7pT5?GRT+gn { O$˔X6dߍzZ6ua4awGݢ~TN]Cw ײzND^{( Ջ&gflN`XD CN'pw(xZ |;YMbmWPx]NMzA23'Ch6׆tIK1lxa_"agh}e% k1.@abY:ɘH*/lސfX6,K5he.|ܤ3~U]3mQR)ǝՎ7aIh usn]e"Z|N4E8^QY#\-.vT}]?_y3;Іobp8fWUO*4}%oX,»6ÀQ1z[-=z_8yOF/uWv64ڀ2WNu+"وVD\tSZp2mٞt{vo!)qf[1 >~?:fR,O)@ d5ԙ&`ܞvb >'`6*[s2hSμSH%]%iG$P<dzdOp8!PP*ͻdpu0D6l#RGI)8YVd~|~b?vTRe7_yB" Оf--ݚ ޟ9F%Ymqɇh)5.HT>/5ə5 \A*Q8Sl؈6HjpCB1@|qZ[1 zHz=e̒7WxNZ8 x)2#2JHo׃zF6Q:HrxqY=ϱMWઽdʍd.CT. 7!m @Y/,&zhni6+0KpK^_86מyQωfw#0]{֠⯚M3%oAv6kK 9gCeDc!y *TO*Rat_0Z5OJ_h5t#XA$%t3JLM\ql?hXrΈR9慬W今"Ś ;D`\J8:̡|{W9wl۪(#%Q- ئbGZàV:DZ;PnX"+rpPL 3iQbQ>YZN7…B!S:\,oOH*k;rhPKDy;| kfnv2^_ۤ0%A1(a.ǻ־uQ/G7j1TXc._(\ϼ/g:C$>3XRη _uY8w۫6715ޯ|6N.FtL¡F(,VO侚ObZ`[$BmlH3T2>VU|CpS8]!Lۺ ɚ% lC#4C fRkY SʯB&V|Tkï);MnrUC$1 JV461Wk\3Zj!I*D;96L{vM=A2~eڥY9bXz%ȓ7}tP' yzlqLdbdXcyo^HsB訉V:%z8PҟF}VIE]o(y*hT9 /52 e.\-&po=g #' p|gsI%T771bչTՄǠ dl(uϴ;A"{H:U1ipMq0}sPJvqeFI؞ YLsCDjRX;Fa~9{h51W !n_/IkP\Vo^wʤ0(x% l3rKX6j Ў| T`|J˥Ѿ {?+d7'zne!jx|tz;_e#bqȢu5+ k\m;Pwh~X:3H?c2F'QDA!KHѐ5hTk#;C0C4{{n$qG~_~枺d?Fa/i>lw ї=|a*[|(6uԵ8ԩ6MK0Rd8@tuk9]' tYI-Tnjyפz¯oa0:PńQUa5w 3J}*L3&v0laZ359'I8O ޹nʗXN/v\SD$o[556@Hesló=GJQf@;1K"@r͈ 4rqCgc;M^R@(~6yVx^.=-d؛&LwBw:8t +_d;sHSYK癤r?X)iĒuh1B@(y;N .y|;@m U 7^G%y1SsK-).'eQu m{)XIDΑE4gn}8T bGZW(PS˾2p3oPG<擕%: u'adB=0X֏D_ @ܙpJTq;Ӵce!$5g:|]>h3=F,a*ypr}dGG1zen$~ Di6U֗š}~$n^!CǩP٧l0{hĉv PR+hf$.x @^`JA.Sn.5GiЌBKMbٌ~ѧJwN]A~?NN)c(Be[!{aGҴ3+uƆR , 0h Orcj a=u,x=ڍIV0' +@òO,<.)PkbS)y28rP4o~qt&{1؂$ZGKè[} 7DD +gJ1oÄ9d*D?Qࣀjq.Lsoʽ;܃atEgw;ĥ6IlXY[G[ ”SOba,G+xoKK?qZ<6T0f9x] ڟ!\WwS?^Kl&map #15<:%6"qdDPk|\( ac] > ,Rp-8(7箺1MZZGOZ Z`˜To cSSsDT|ɫTN08Z&\l@^eEmH=X4C~ z^hG3fh٠ORGjG=V^6 9 XVvU-mX,uBYME9;eLOpu}Ut=f87%SܿM`vvm~WI $3HAgw Aۇg 2\#E>uDTَ@gש['~" v&sq|y`4.h{kC9<9WfL(o4;YCZS0P JQM/Gsd!i>?a(-4&eg-׽oBPQz6)`X[j_uOUgz35ٻ+.Bi<ےg[;s#N Ho1ʞqD> 1TޮviuzqRTrs*@րKhwBv_Lbc-0 ,O@qcokIVYE .A|.yzX9ޯZɨ J{їGjn n/kHdK uؓж}lpݞw@4^kdhwZi!4nwz14{{!; mQ^tv6 `:Qͼ c9]4,["m짥4j=zcoL޺>dmEBji_V$L67&ã0/q2=XʃϙOmY]SvOjs\΁`m5eJhf _ yIӅ@I⍇OC6 $|ˡ7D%6 RtUc51вϓ`E\&6:+d&-P׶0ZZ ]<~jowωVSfŠQG<8RC0V019ʢ#x;o͉]%v+zg-q Obtj\J71"=MUp\EV5jEԯ? 7%'͖},xu ݅#6Vn6j>[1bk29T[M0q̯R̮(#Lp -ϑh`D6;i5F3 @?:/|oT6x>f8j6Rla>àxYf $=H? I5eCn+)#B/쇗dBJ[0vWz7#cT] ;T Z+ϩ_RW1躤RO*mVQjrB~,P5|֣#~h!WʵޏPP A3(J(Щ(N[Gf~CMҐn(cÅZr&;/;+V!'9qm+ vz=W:o8RBQ0bfF龐ìMb[LB&R%80gλva6fUMP5Bk}#(kANV1"(9!~?*7MWpTɜgUFWU~KMUZ \eƷzK 7cpV)S(%|ԂаC9YfޱW]z;IT{q5f~]7WeuN؎A`2jR[&r꛵swi5rd9; ۺ2œi)A9QA@"ڇar?;.T5vwFvdFCWw2YyV^$eCuA9d<< 702u`P 78M$jmj8nw^r\j!T$K;tڪ{*/Kr.ڣ {ŲKRzZ ؂V~B\Zbx]-V?µDžĥWfjRVq,hqS/Dٗ08J7[ϋ CCAW}CONfAUxjŕ?p 魱ޖFXo|-^}#fI.c4CKOT?i-s9 xDo?LvѓPbӻ१C+eϡcx& 4iycv[1 ûӭ)[7 c E_X@^LW$!=Š5$2yƎshh@H,︯j){$=-IƄ0j;!]$<% D6It)u.F-]1+S ;%céuĕT b׍c-l,ҝs3Rhf7j#yyE;AEӑV?2N*c985t nxϯ+80,PbgYw/92SSL3';InXp-I<.$$|0<[@^2i $E _j4V'_0Sy^eCqd-H$|7` KLޕkͬѷ$~!w>mB̧eC>Nr$/Y->t*DԴHCE$i[D=|Gr19 FJT0}7xx>b41*ˍg>ZΧe+U|Fm?03ڊkhެl,K?}z[4)m벱Ͷ\3f[@*ugOݏ]{4χFM8?*\X#{C\9㡪>aW |hnpN@C1^hމL¼k>GF[oFE9ר0޻VWIdt'zYӣp2daכ|' :$*K l(ָ #* ,u6|]_"=U,v %}d.G=,D B*nG/ gB7Z!YTHctCӟt+aG <F  zaI9k͝ij^%XdXNHGke޸ 5Wbg^3lXl$qWRχ!/,: Tpg gë"pKiTAHM ii-Քf Y c&D- 3a_ׅ96CGĚuq̵UQݩ4_#Xa##' -M#ϡ`.C[B߁&jgVO{nfGjї kB蛘a~"v>NIT[dx\-?凒䒭ҞN ndjhHK8cLυ2i@^YQbèa18a68>;М+,9^a6k7vV$_ˏz"fƄ-xqO s9:CIv7*HǿOok޽=4 ;(^ҌEG9j1lizԄ>Cnm~D0z)[?(ʞd6ُGO` ;ZAdT!9#cetĴM.b)OGk|4넮'q]XUg&@*J2:1qЈ;U6UI ̳dJ"tzJ7qYriwwjC,޸O?i :vl$2Fs tᒃa\I& 49ZggدV#=iqНNRzԎBY$([z_ V+hQĉC2M2 ʎHʜ u&Q_ L~ -{my StH҂SXۡ+^S,&Y)FZ90eWfN%욦()QC$U2N;"r6\dȣu#X(q9_6tQgߺt'@5H(?Z콏ە6q">Rv;0{+ހWMܖڡF#I qޖ8ɛK(<>lSCl*5l@W:Bk+9` `u/ZMI{Hp hGeJm!6ܖmշiQ\Ϟ|{7GPװ5JN˾i=X,ʂ!(xyl+fF@66鯚0ጧ4`!s>n|6;Hלߝgi#lW'z=CGyAŲ+3n:yXT6^W9*̊Q^V 辔Us&.㒅)A rC6ϭΖ{2&dDHh7 "O: o j&vOխMӓ%M(|#~1@Ӟ&?SLMjRuTq8FOG199]"8煸ޢia[R|F,OӋI$;O]d*M`9Fy0h:F_Љ@3Q~確{}*Ƿm*,6_%rm~3nל̓#;:!?K{YҥZF`7!rDOK,׺%yiޱtZ?o,RƩڃ>2 筡MrqjT=Fv#mCήp[2)o=Ap`XF%R惦IBN(ƣEjvoc[L}-7CeN̟QYmӔw9PhJԉ+Q*= DEH.`0lW6f$ x tQްKa^Euë‹sSM ]ѫL٬CaqK0rmz4fh_hBl#PFάp _j֫n)?R;4uUoTy*W´ sn[BM#76gvH=h!v9M IӈGЯucg}?i*}V>om“q:l(r-5rxHڭß˹}}yu (EÑ29o tX &t7լ^ JܓH>Y?ƥ:2E"wIi}R7yn 6GpbE5ã}4ЇL|=/+Jb;K"=!k' ?1;Rt)jZ.AH# \8=HT Kyn AG8ks\c!/A՚k\R1Ͽ ېXvv5˃0`&9bI(;]:1n 0pLZ8{Pg-eAlH~tdˎP>Qv%42*i, UTO=YV.rg|`6Aș 86 6-|t%L Z99=Λs%'/FCJ𘥔H] pBfp*4ӧ3j9`poAo]8d]#<$}d7S݄,*4(Jmew\lSN*}Iӊ5=Ҟp{QWsbB`{x[źD/_ZsDv{l KBEcTw}O3ㆽL`{ݹ^o|EnJ1Y*&<$C*V Uړ/ܳo>!,23yF^lI0u.|dMm!,C=aU1X_Eծ{B7Ӧq Afޓ8]'Q}Hi%Fm变īXACqpLGStO'UT ([t[r|C񣉅ÈZ:\w7#3V&RGԇ?:IG* O' @Cqh l3,w3.>A\fm٭Œ&hWBIIT >~kނ!F,D{EZ}\<*=rC|fFf_ #Ǐar"l\n_hVje࠾ZoaWˆ`(eom |33^n Lɜ/_ FB6I>j @>z&5K 04? i9,0pQܕlJ#`øpdzH {02_/+*PZx<,ȯcr&ߥQ?|tgA- Tl)q!2g#WŜqn?b"W GV)*TaA-2|mSmz^յ:hmTKDr{2[GO$ݝ:1$  M]m0П#K7 Wr-A3Q#BqHw׋n*i!\ː*1XpB8Rk)Zq٦YcX:X-sqfh?׻̣Ǐfg`jx3agHI~52A…[ =3՝ZyE$WsL>1<1U߻XoaVy@Ьz4ܙ$SBTB-Lǒ9/b=.q?8||%8s,0Ԓ * \>`%Ȩ? }|zby6Bw3I %0o3pM"ϰPʝ{+aш=u\1eKr/UD=pH7+4y$H2+'K,-rlBڧg kLk: xCO'S?QDipP-U,cARwXVЋ%=^gxOK<[1`6B0ըԤsr&§oumQ)]֯;D?g𼚷 Kۮ%# z@+9wB'6%P-$}bMHo$ҀxGf!k +Y9rڦӐp#;eGࡓNbVJ3ng8vtƘHjNcHv$'h'px|G(LlUNt/P**eڍN'/61x],&s`yt;ed5PkgBOCa&vE`P D&aS0R.Cـ û_7 u3䩦S #KKHځo-ʈ` 60t7` ? e)RוJ$8*UpaSLhqw!cԎkӈ*+e'B\>K,nv1ے"ܣ=jǐ[RCљ2JNdfG2.}þ݂a(QgD˘ pQ do>?bMrMzr.G(oEd \b&>O)@VpJDjs+\\3ث} H("%ŋSTMGIV"Xlw=xt2t֡hl4W9xUu) ,立_g׉ōeߨ@k&4zc`I]? ??4m$^^vIŋ2+ [:E,>#u-sh+o>h!#-Ӽs46`f*aaYnp "<Hc8Y/Y=itҾョyܺ2Z7dT;!%3d6:Qz<6zܰ]9Qܟ班xA$3 S?Y$ҟIx:b(yNF%ScVphd1ݝ4 6}C٣@l%bB\Q=ᠯiկ-*6?d/69 m=J6c%b2EE{;eEy_MJ0vW٭3Cb{WOc%/Yo`1Pvd#Es&FϿ@ߑ tY9WbD/r•@뿧=h?}+ M7nluϡLBb 1AʰÜ4_pG,[WCy0rd1,KKk9aA4z7-.nqӰr~}a|k31J:d؁i*Neu\>LLb1!|HdR=iQ{UY(ߠNWe# Xu³ I>^ P݇q$gr"$]w] bG5ؗ:Ja?ܿ0ᬉ7gwLvmQ$pGS+>2e<$ӿvӖl‹;eD֪E.}B5wyc+= Խz*COZfH423 a!`DO+iZp:Q1jrƂ{4p]?T zUuK {q[8?> ʹ1PjA irGt֛py#ip]/e  L. ]EfݍL9K8S#7nlOHA&B<Μ2ʔ3/rI(.Io# bXy^* ق,:`ctRS5KQ$}>ѕ}5pmYzTv/B8(wr ,/3hs.'L3j\#*ֈMI1F^1a  /C[fsg̃DJ 4 _:nP3pŦ1zp&gWAaE@(I^d5tDV}Sw躛aT3תDW },0ꬸ>=흊jF[K+69R_@napTZ!§Nt|5"CBtpRRPc5?}.XS7=2g+fɃw! Q=;k n)6UħA1MZ .b k6#7yEDI -V_6E9!sbaUc!#$xp+,Y]e⚌> /4tj^Σ}P A581Уg|cH27m‡)ƀwȲ8Lh^ĥAYÙ;%im^Ѽ 7y"_"S`6S`tzMPU=%HwdCZVXa`Zbsv8O3lg+GWu΢}|V8Jב8a  +H]Zֿ 3ubAJiwrWM,3/2?6)%}"ڈR?\7oQL0"Pס..U*+v㪵PRFFI]^"> VCSFu|8| ^ji{xw^W$5 ue%>Xw}LݞsD'|>i¬3w9EIi_s8Ԅ#%У|N@k9"%>z?Qkbdìl=csm˔Bt!xgNC!Ӫ;sxfئrvJAB(1yFU2_n02 Ke5(\rRl $EiY;buiVֽ={2~ii!E8 j0>x= /܍W $3'qM]'=WgI_ȐE:1:-жZ^ѦTaS/Յ E`iQBJK;l]oی9>g%8tJ ܾdUHgW*Hs ̦y'<~%o 0oja׎!ᄑXH3 aaG0.l):9]1&gmn8;FBK@@#;0LBmu򪿧&A 9ބ.xz9PGeVp <p,kɄ+N CF%L)R8vf ;!M7!m2P~ 0HǦuPc?#OdS,zQmTz }z6J`4_ѽx/'rݠg w^7"[ E=H?'Aɖk٦E`v m R7j.neXM3S?-Q6a5BDQJaf>B.@&<QJ81,FR=<[¶) UQMnVqj ?y+HZu {ק}wи-L |.B70<HLH$ 8j-WnK:sӀM0^%@]FW U2xɑ$yw}^??14ZV0K1s䐣H?hG "1 1mb[61u2޽8lV˩h !9{[t2 F%,E}`ⲴG?&ş] (%1؀[NlyN IWQB. ZнPnk,~Qg?s=>zʎ+L۰[(-a6b!Z]-Q[[k"dc }R}6̣k3m3.^\*qDP|g8&;z -88-W e&3!]0N&_5?keWh_ϨV$fj!N\1vvYة{ǜf⚴ GQj Rir};!Z|Nm ,D`̤)zai %4v61%,>Km. ޚ>h( ȭFrKd%7(+bk-#Cw kQ>iOUs'xVt' ' с [gT@:l$8VS^ &4kIz(1>9Hst,1PYhq PwmtcmP?/MIZB>nWwb whd=Z,>ITs C<[R{2^h(U[y%?ה8+rs8̲8zĜ=[ =͑mA0aMC]Cw%ʄpE=²ذ٪\|dWYs~gS!f0K&~L8Q@Lϥ|Ca%ɢ( s$s>E-qm[PL#P4k/ng@lVn@^:a?^yt(8$[KFtq#"11+$=J2iۅ*ږ>a漣yƕ{]TT&K2gU^xP_!g,b:h?@]GG391\>eJ&u,h;%{3gGf<'?j(Qxʲ! T9]Ee*i_w/7pk)r'd A$yb NmβE4XN}MVp3ſr8^loB3g !g$;`o8my="Y˅ĔXb֯Y2OenR='Zd:^L.Q> 䟢n#r@t(3OOhˋv3=ҝ~]7S&I`ET~'| VT@ҌY2JU6Pt=c"WiMK33ƕ+(E|c玙ְ4!h7g z~:R[QmGsjr~ A;ȟ@țK$IdIn6cՉf{ؑfߒ2: =<|1&BM0mռI^09S?xIgB?eD|_]T*:bSG:Egh T0)B =O&5fBv}QGJFgE/ ԯ;[GPX$k77LN\eȂg=@>"Rɋ_ ^MoZne}G5XS۷m{"N~H'&MPveV1ˈƦ+1^<'gAb:.ǝj\:ܟ$k .=]{j`Q[JTRUvr81./  b[.^Te YîGS)~c(q+Ax,nYquq<X=BgGQ^UqF1v=fza2ȩ9[C60 T`[.(B-WasS _ay@(sAA='V%Taoag&`YH 'j.MnZc5EN]$;<& v3pk{"D<6a|kT,F~RdM4^anD-;(Z'gfF,NAƛ,پ@ou>HV ~[;V%wV3݅A*mS)He0}JM %Z uW(F90 mqtZ=+qo q'$y9?G [9l׭l-I7& RńR[1*ڡW?yM3`E2X?eW*Hrx̹C䬒FTWqL=p뭩>f:R ZhjYU LEsm<(H͹N"c^=.eԬC!MYwp|@L. n' ԰@xy;Qv =H/3,/w\>y"+\rdU4o#I貳7*myzu;}mrŬ:wα]AX So[ϼ|ϽQ/{/h6 |\U1ѕjL(Fj6JQmEQ}aB\! z.ݨ·ȨkQ#5C%R1ى&D"a} \Mm*Ԕ _3fvp]̮VM_QIF,\bZE*sl?h.pDBQ t,[q)7ΈVb6Vb`.qVYV 1cZjI8VŧA8A61$tg f77|K< ǿwalǕb.gi4cаxkiIuecvU*GOn$DIvj Pֶy4"!Xi!PhXNǹ~_/JubOUjm1!ݹJ#m/џN_E]L DT}oG$V\ΜMG trWY.7* j}*[ P Ed/S֛UHW:@+S)%DLȕEMD7$&$EL= y(K6, $y9 '싴SԿD;qp|8A;q5p'tա|W ybb"Q(tͦtgJ:u6 L1^K''>1]G&icYS{8uȐ!>{bߗVf#&)FAHs)R&8=]s jd%cPo&`j ? 1K c4/*uFf<:Ke*"$&Ӵ3V=\=O2:\gt\c}iO:cExc}ܡudAo}f<8֨s ev{!Z %tn]} Ae$IUm]sסū| Ѧ2KY0JpΗ7jIA% v[mG_=Cs-ڱa69">Ѯr\i,"^-2LJA5vL5'G)Zv2/E#nmxBݟm9l9(_S.1",71?$bbO]H-37'R!i\[/BV 5q 堸ƛI&$䨿iM0W_lgZkBQs87vK#CTqOAldܘ\GkΞeweUAk= gWp3x{iD@yТܤ(|R-T}c3aD?+a+Ti (s_ eZz^JL.5WECA[(鹳 lqޠ% = #8ŽəAAt=-h+D*˺I&3: ]GLcX 4c )j;%ƣnrV3Ƣ(zTNbyW/4Lh'*جKǖ`ot: cU4#HAe9Md2$&E% M̙VE.ǵl._E`:|Ϳܲ~kU5F}ش7{uls㛺oԝi7!yO sU|nR3LK8p_zurx܌ӭ56ӎ#nHͤRl'qpF$gs$\ҿ=BLdEEo}X  NqЖYT'V"O.ސjvu[`W6RUL'D$ E(;\IC &ݙG8G58DF@:oO=}LwfA5όP8iLTl1'+ }i)TZ"ɚ%߀ WxfΣ%F_RIbkPY_n# )/sPIŝ)65NZtg2צ,vSoь iVmvx_w &4.,ZLWe"IcgW.]5 򊻣Bm̘lҵrf:(,IGJmvLjT}_5YOxLv8Mn[ǝt in|*"c4]bR׎$ d;7${ w4x>|t_^'eoiíX2J9P%I^;"j0 c) VӬ`>GLlsZ6М;A@ܐ!6E\IƮrKcXUC7lh;^ SU~Uo^/$ Rs#8? ht4oOr@ Ls۹e).@=Γw6)zlJFfN/N5rs^.k @y ɼ; nzpNӧEúmАGdQaV t0My;0}^|`K1qϒ'ب fg1lAw`юN.Hz$ϒz ,#E(r`ۥDpdWc "$b{؃PmM_֢RC u"l& A uMQV OvЀgPw&dY`Nl4qX \$ ESԶ%>VbR="~-l}Ґ*LfP3mR~6Fx^;ap ۍ3~kߑaTs@)ARoG؋r$ml9jwX)wmތsL'9.ƳɲR {uPd츓9q@["{O[?bOK៧Ns?_J4 5u,zU~?tKw4|˯Ւդwct8A2S8Ű橛bↅ[U= I ܪ:pp nߖ-<` ʝyn%=J kzQl8᎒:& <\pz$0a}gRܽ-J^v -ٌPȭwa_0+Vs:b8>gAaz$ k-'X$ꃐ ߝ5+QFksN㦯?V&3 5KΑnpl #BKz,LԺe1UG}Y贖yFC 2q&3+4?aCYՌ%Tlqp=EC ҡPk>8urn L~9:j$1tƞ;> s+2JOLL>$*I910-1%M[C%O4BQ]m>PN{W̡^>2-z{s?X&mPOs L BpvEYL$B>c3ك-25!t' 8WSsk?N[ גT _%,E:`W|N@PAF ,tȨʪZNņpZ":|\ CE_el(˸𺐩Mc`i >`5bISÆqgV|;yX7'=g)ql5k ǭӀ}h TvޫJe OxVDY $Eo3WbKvKT[Q!Nj)p0Alf"(؋J&LTibСSF^h+QT8poL*Tgd ,FvV\9+˭&}BY̗,DfyD&oUZ!^rH6UĘwmڸdb>T+? 'lCZ h;X0RSʉڈјCo"08Z4M'C-@ t\̄|Ƅ"vފ2kx^*@j(wFkYk FG\S7¯0ms3T~Hwf:.'~ ԤE"iS^\_- RV·FT/Q{!X~W$D;29 + pLk/umW|ɩx}J\tI!{:軦:"n{Y`~@NIs<%{2IJdýv+'xQ9IEv)ʜB<@H٥ڽK@kT9F'4a"._-.MkH"amU]ٷs< @TVoz ҫm~EyC^0W͝48ϗIᠳ9| V7^bU9bk꒎~ONZ"V˧\uN 1Wo}kF:U #_r3Wٷ H"<fbņNRE7wD$}`W @&Y4}T yhb;L(\Eyޔ`6iJ"XP68M|BIf.ujN2Ez^R``noͷ Dڐ0GC}rRR9*΢G!N.ipuf'bIbgpDnMX68PMI oL$: ,+8渁p\.UK3i^mjtR|d`'X+|^.~~)9' 2ػъ/0]STn! 'vgt! "ysWCUm頻A3z)!*l@dQ7/:.F0^Xu؄_gMӻ,4aN?G4pRRĽJ?fE/ŮdУJ!X"W|"L(PwrՇ>AYtY1*־2{V/}"BS炝jx_FxXfpp3X(bF! ]`5IiܖOq 㮗򊻣DȢeRr3Jz5uMg +&PMZ"%j_&/2Ldž5O8e{'7$8^A3}{N~3Gcz5C7&AW]j ڰ.e?f9C;g hXq 715%g=3LcbeivUY`xT"vDr!\YoP]bw V-?~電 3BzbkJN߲LN17gdWGwi(~Z G !stCvT3ku-j܆co}FF|qWD7N_T; m Y|W딪_y+~,lh1RV2 *\XqBvDHԡUQȑ?ymF3(: tJC~Sh[i൤s&.RﳮxX+h!}grRmʸyNJplgAIFL0yOW?[Wź̪)RVYz]AԈ+~{pCR|)H\ {2*KMNT4tA$]G< f&a;A>.?ʓn#58&I|v I ϡ H6u:zs{O7HsIuA%g'ŀP 58Ox;[g 9,]dlɌ)׈X偵} kKrz _L_y 8cdry ~/)GpqNDݼ olrTsj2G'&F]XV}N#Bsͅ"*T ) xLޱe`\|?X9!\DGتnst6trۿm2O .%>𘟷 ͈o=uS! zܻgNS%?;ل/nV p #8GO}&1hOWSƎ]Ձf(v9"OV0W7iaM iz}<}a}Oa Lb }ț ZZ߿O[/TbBo7ӇL&)>7. JՖ5Czj{OԚ.\R)g0%^<R2W24i5tc F'v7/\kӋOXrh bRڔ}op>g@F4גǮ,,ʎ/ 稼/xdVIn A+6"E Dz?d2`[*n F4F4 FB7?i˿ R5ѻ2(꠳Lfo/~Q}Gle:qkEjΒ}y5ֶ밽>l\ui nl9q^JYVG,~kbo 8oS}L ׬9w?dpg*sD(c1Nױɸ`$¯%_y{qm/WEfйI=)̸1?b6@a~뀆/&8_. ٲ8-&^)+ ?nKnYp`Oʇ,t1ۃ'҉! AܟW)60z:6qۇRqs6fаE{>։K+ĹMktxNL㩨-´I2lP%B(!W=,Lp5g ΄( @~''pnz,1[RmiSw1J 021$H-B<*I (yIP2t pÿPh2aՔ!},"!rG @&80O-vTƦE V3Rٹwkfl&D=;ߵ盧Wg) Asq?oJOp`m{,]yà9;VZCխAN=(W}a~+ FX L1hޕfDĭolYPn)JHZqy(2p\LwݴGkM%qEXaR8 AO模ϺWRd<l5Ǣ6;i=.$R}_ sg+&\?#MuK MD m#KV`*ఌɘ?X iߠ8Hyp1&>&8j' 5EEĿOd.Н5I 3nwx~bw@q(Rv]p;{ڕZQ!5޲W߭ڥ=umh~r0;^ڳ0D+:p[!"Ӯɫf30x*)ͻFqˉ8s"O>"eY1?uf[Mm([4]D}H#L Ju7a'4D4Z\K`umuIl: i.Gd+k>Ьw^W@M<; *s7`2@2=Hs<ӊLٖ $1 m&Gco%" a`av;HA2h}%P ϟcD#E tM$FVF>IbjP#ۉC ;RUfAc ON qoET[oPepR)GH?)[ZZt-K'OHpV5"nlqbfD/23*vBxP )(0jlF.b_5gO1`S) F@sNӄ@ r\W>KeSXRSr.6A/l'dh|q9:sT_ѡfmYWr OAUp`n@٭fǟӶ(F6uO'w匊G~x&]Ay+)tĮ?|) Jv~4;t7 /hBQ5GBN& [:'OjQ.Ao}mQ4015Űv㨸W6VMU 66/4i,$(AR2b5ݾ\u#4ZhA*uԳ2˙ (z=\f;"=qŪ^-DMgeʤY;߶6='ACA:$rZf`m{ '}?JcbdIpRycw7s]LZ t_tCt2jY%\vˆ+`fO7Na7Q`V% Wlv"0ޒե Yd"o8wawO4Ŋxx>[ǢN+rs&k5xcM,jo{^C. ^i\Ũf]h'.-3CB.UB;7hpZ(1}׮1J "$ɸRdzQ\Os[vlE ;=kT#DS?%L!ˆQ;LBpI4}7K#D]\i Ou-Kjug[m0|ꨜva9,OqhROPmoq|:F2 P!f",BA =HFQ+ qXZkL%<\ @L\Vn#ƓF]*Cɹ{X$Ca 7MVw8C0٦(,.u^5{qb.;zT?D=?%z'd oKc)AƝ. oĺ!~3U?p,/[[bZOA*UP\5 iN#!dNPr_ed#FNZ`U-{cʿzVCuCR;Y`([ ']; Z?ƿaE \TRSȭ@~"RgJwU@V##45Ֆ=Lt&gBpQ(ԥN)8&Mv:Yrj ފrvCwh͵*%K=GvH;8o'jdw UbGtpy2Amz̘ [}B?Twﻕ\*r$)Ui-V ȼS ,iďqs&9yi?&yL& k_8jJgޛz8A˽}L~s bFYU۶\F8~{@eր$Y|]): 0SfٯB?+K0f05q ixfI9+]и비`Br> \%g@wqJr#xR臩QѧcLWJzK1UagjvWllnد}aVCZ)Qu 1-&Lj};E8RGsD8@ lQ'/p@[.]GVι%l6ɒ O0OEGW90x6/Q4 _%?+Ng79:+/ +ˉU8 JOg<Ȁ"vזƑơ5}Υ̘?~y)} %kR9Cԩ/KT(#FCZ\(a :PfBDS4,Gá\;uxc 6kz-%fF0DӖJi$J-)Y.AI'Op'? ߉)Y΀N۔3ڣSvB~:Y\':ɶc}Év'Tщl4j}@PDsjr7P?¬čg OBpQǨ<8Ss~Ֆ}bT;)߯WI4!nMC۽ϚYKi#p7R!(+gzc j+MMh^)֝=ɷՑ?,yDsI${pf/O/1rK*n|~NHKZpȝ?4qsZyGw+ȮH~whn*&"0E@ z݃]qX KYe EXS"B Y l]^2I BBAQlF~|:.젩T0Ko$v?:<~ƑdrZ^ZD)/9z߿hxt *m"V]OA6ZMޅ[GQlܫl):U |8c YDq ӏw56"%L\<qYm; l*Nu'b}We45 `qld ^?cLNqx#Ug^Րm]=T\)\Nrjϒ)zɒc,xdo`,R/`L[yBK,5s+Ȣh*' 0~d6BFRc Yk9|E.⺬o"f((ӱDR+ [}),8,A +zxc7*髦Z1$ fr cZZ=3a_Ɨyq% `|,mR8*EI6aE+ҠM@wˍe=~$ c]0KcԤ́Mh0Eq2@kBC0%  -8ztVw詻0ЦmA 3ʩ(/ =]\& IqjB9{u>>cP?r ["mf8!DQC?B9ߠ_RBK J\#Ԋ@T t~| <uH {H1}ղF ];hܖCgp+\=/Gb(mܥ҅&. f{Ap|R,*uʢyhVrU&fIY|d0B4!\MjXJ}yOW8H8OZ8F$fLh9tKɺ媾5m1u0QShi9e⣍G,`C)CXp"?Ohʝ< z~zZڇvDWȫ]SיIf7 >Kx|N#'74E{0 H7]5 x#~Jj=c-e =_G(#Ԁ2> 2qH:dYL ɰK]XhJM]*k ٓuS=vۥP7oJ]hw S9Π ÊZZ_:6}q*u0kWd / V36Joӥ~x*~!o(/BH('hm\R+ŊND>?xI莱A^j1 hc \k &Z_jL6EP*|4J dn?ZCTp[$|ܟ@&vNV ;{6cnHXY%hBN~E0Q%|c.34n< \b/y.mMےq3,]Hru EP>斶c5,[d( ! xYȴKVp,4x~ݏF_e+zs9O!֫wyO\T!ٲ'~Ci:rkgtp6/vf%ܺܳZx6/Ou:)bIQ F먌+kN2C\,ɉʈmzXKHEzeXS[@jwCC [uYRS4)]F$&V5ҏ5bOp,DV8XgOhtaiS-t'[}8ifS9z#$$x[[m똙%D$hf3h:BQ* 5 #Qd */*f ͊Ow6u\"O% 6pk!)?¼IZkĂc(y8ߢ1>T/ <=>%M;w>Fb*]!8ÚW=r"* 2a:yUD~ΐ;|d_Qb)w!(S`eF PAnEI8.N-nfg[j:g#<_}itp]XvI<.. Z, dL3/9t¹SG9|-1bn xW|B>hh @;*P{*:NP-'ul:|?7 4K }v#LxjrqS:Vt9}/5SQٟ[YJZ(j4 l}7n" ENMZ¬O6!5*J:o'&ѻJ3(vޯ5t.sܣH`t1ff~GIWkB[~.я>.Jmu&Ŕ&fiat` tƔ_(-czv|b2sDJڹn6e.Tx퇷pG!َOZ.Vځ +xG8@鎾)7J*UJLr XjЋ@$,k\sa<-sa;<5AfjYci Se qeb<`& GJu?ꅈTm*m^~^u{ SU*V^'KpH /OW*o餪 [}#YFlZ l}z0˴/ a+;C7 s?zaߌ/Ș :#W  0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark {restore}ifpdfrenderer-0.9.0/src/com/sun/pdfview/font/CIDFontType2.java0000644000175000017500000002220711157264553023573 0ustar twernertwerner/* * $Id: CIDFontType2.java,v 1.5 2009-03-15 20:47:38 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.GeneralPath; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import com.sun.pdfview.PDFObject; /** * a font object derived from a CID font. * * @author Jonathan Kaplan */ public class CIDFontType2 extends TTFFont { /** * The width of each glyph from the DW and W arrays */ private Map widths = null; /** * The vertical width of each glyph from the DW2 and W2 arrays */ private Map widthsVertical = null; /* * the default width */ private int defaultWidth = 1000; /* * the default vertical width */ private int defaultWidthVertical = 1000; /** the CIDtoGID map, if any */ private ByteBuffer cidToGidMap; /** * create a new CIDFontType2 object based on the name of a built-in font * and the font descriptor * @param baseName the name of the font, from the PDF file * @param fontObj a dictionary that contains the DW (defaultWidth) and * W (width) parameters * @param descriptor a descriptor for the font */ public CIDFontType2(String baseName, PDFObject fontObj, PDFFontDescriptor descriptor) throws IOException { super(baseName, fontObj, descriptor); parseWidths(fontObj); // read the CIDSystemInfo dictionary (required) PDFObject systemInfoObj = fontObj.getDictRef("CIDSystemInfo"); // read the cid to gid map (optional) PDFObject mapObj = fontObj.getDictRef("CIDToGIDMap"); // only read the map if it is a stream (if it is a name, it // is "Identity" and can be ignored if (mapObj != null && (mapObj.getType() == PDFObject.STREAM)) { cidToGidMap = mapObj.getStreamBuffer(); } } /** Parse the Widths array and DW object */ private void parseWidths(PDFObject fontObj) throws IOException { // read the default width (otpional) PDFObject defaultWidthObj = fontObj.getDictRef("DW"); if (defaultWidthObj != null) { defaultWidth = defaultWidthObj.getIntValue(); } int entryIdx = 0; int first = 0; int last = 0; PDFObject[] widthArray; // read the widths table PDFObject widthObj = fontObj.getDictRef("W"); if (widthObj != null) { // initialize the widths array widths = new HashMap(); // parse the width array widthArray = widthObj.getArray(); /* an entry can be in one of two forms: * or * [ array of values ] * we use the entryIdx to differentitate between them */ for (int i = 0; i < widthArray.length; i++) { if (entryIdx == 0) { // first value in an entry. Just store it first = widthArray[i].getIntValue(); } else if (entryIdx == 1) { // second value -- is it an int or array? if (widthArray[i].getType() == PDFObject.ARRAY) { // add all the entries in the array to the width array PDFObject[] entries = widthArray[i].getArray(); for (int c = 0; c < entries.length; c++) { Character key = new Character((char) (c + first)); // value is width / default width float value = entries[c].getIntValue(); widths.put(key, new Float(value)); } // all done entryIdx = -1; } else { last = widthArray[i].getIntValue(); } } else { // third value. Set a range int value = widthArray[i].getIntValue(); // set the range for (int c = first; c <= last; c++) { widths.put(new Character((char) c), new Float(value)); } // all done entryIdx = -1; } entryIdx++; } } // read the optional vertical default width defaultWidthObj = fontObj.getDictRef("DW2"); if (defaultWidthObj != null) { defaultWidthVertical = defaultWidthObj.getIntValue(); } // read the vertical widths table widthObj = fontObj.getDictRef("W2"); if (widthObj != null) { // initialize the widths array widthsVertical = new HashMap(); // parse the width2 array widthArray = widthObj.getArray(); /* an entry can be in one of two forms: * or * [ array of values ] * we use the entryIdx to differentitate between them */ entryIdx = 0; first = 0; last = 0; for (int i = 0; i < widthArray.length; i++) { if (entryIdx == 0) { // first value in an entry. Just store it first = widthArray[i].getIntValue(); } else if (entryIdx == 1) { // second value -- is it an int or array? if (widthArray[i].getType() == PDFObject.ARRAY) { // add all the entries in the array to the width array PDFObject[] entries = widthArray[i].getArray(); for (int c = 0; c < entries.length; c++) { Character key = new Character((char) (c + first)); // value is width / default width float value = entries[c].getIntValue(); widthsVertical.put(key, new Float(value)); } // all done entryIdx = -1; } else { last = widthArray[i].getIntValue(); } } else { // third value. Set a range int value = widthArray[i].getIntValue(); // set the range for (int c = first; c <= last; c++) { widthsVertical.put(new Character((char) c), new Float(value)); } // all done entryIdx = -1; } entryIdx++; } } } /** Get the default width in text space */ @Override public int getDefaultWidth() { return defaultWidth; } /** Get the width of a given character */ @Override public float getWidth(char code, String name) { if (widths == null) { return 1f; } Float w = widths.get(new Character(code)); if (w == null) { return 1f; } return w.floatValue() / getDefaultWidth(); } /** Get the default vertical width in text space */ public int getDefaultWidthVertical() { return defaultWidthVertical; } /** Get the vertical width of a given character */ public float getWidthVertical(char code, String name) { if (widthsVertical == null) { return 1f; } Float w = widthsVertical.get(new Character(code)); if (w == null) { return 1f; } return w.floatValue() / getDefaultWidth(); } /** * Get the outline of a character given the character code. We * interpose here in order to avoid using the CMap of the font in * a CID mapped font. */ @Override protected synchronized GeneralPath getOutline(char src, float width) { int glyphId = (int) (src & 0xffff); // check if there is a cidToGidMap if (cidToGidMap != null) { // read the map glyphId = cidToGidMap.getChar(glyphId * 2); } // call getOutline on the glyphId return getOutline(glyphId, width); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/FontSupport.java0000644000175000017500000005353311157264553023732 0ustar twernertwerner/* * $Id: FontSupport.java,v 1.3 2009-03-15 20:47:38 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; /** * some constants and utility functions for font support. * @author Mike Wessler */ public class FontSupport { /** * names for glyphs in the standard Adobe order. This is the ordering * of the glyphs in a font, not the mapping of character number to * character. */ public static final String stdNames[] = { ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" }; /** * characters for glyphs in the standard order. These are string "values" * to go with the names in stdNames. Not all glyphs have been translated * to their unicode values. In many cases, the name of the glyph has * been appended to an ASCII approximation of the glyph. Strings longer * than 3 characters have this characteristic. To get the character, * use the string if it contains 3 or fewer characters; otherwise, * grab the first character off the string and use that. */ static final String stdValues[] = { "", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\u00a1", "\u00a2", "\u00a3", "/fraction", "\u00a5", "Fflorin", "\u00a7", "\u00a4", "\u00b4quotesingle", "\u201c", "?guillemotleft", "\u2039", "\u203a", "fi", "fl", "--", "\u2020", "\u2021", "\u00b7", "\u00b6", "\u2022", "'quotesinglbase", "\"quotedblbase", "\"quotedblright", "?guillemotright", "...ellipsis", "%perthousand", "?questiondown", "`grave", "'acute", "^circumflex", "~tilde", "-macron", "?breve", "?dotaccent", "?dieresis", "oring", "ccedilla", ":hungarumlaut", "?ogonek", ",caron", "---emdash", "AE", "aordfeminine", "LLslash", "OOslash", "OE", "oordmasculine", "ae", "idotlessi", "llslash", "ooslash", "oe", "Bgermandbls", "1onesuperior", "~logicalnot", "?mu", "(TM)trademark", "?Eth", "1/2", "+/-", "?Thorn", "1/4", "/divide", "|brokenbar", "*degree", "?thorn", "3/4", "2twosuperior", "(R)", "-minus", "?eth", "*multiply", "3threesuperior", "(C)", "AAacute", "AAcircumflex", "AAdieresis", "AAgrave", "AAring", "AAtilde", "CCcedilla", "EEacute", "EEcircumflex", "EEdieresis", "EEgrave", "IIacute", "IIcircumflex", "IIdieresis", "IIgrave", "NNtilde", "OOacute", "OOcircumflex", "OOdieresis", "OOgrave", "OOtilde", "SScaron", "UUacute", "UUcircumflex", "UUdieresis", "UUgrave", "YYacute", "YYdieresis", "ZZcaron", "aaacute", "aacircumflex", "aadieresis", "aagrave", "aaring", "aatilde", "cccedilla", "eeacute", "eecircumflex", "eedieresis", "eegrave", "iiacute", "iicircumflex", "iidieresis", "iigrave", "nntilde", "ooacute", "oocircumflex", "oodieresis", "oograve", "ootilde", "sscaron", "uuacute", "uucircumflex", "uudieresis", "uugrave", "yyacute", "yydieresis", "zzcaron", "!exclamsmall", "?Hungarumlautsmall", "$dollaroldstyle", "$dollarsuperior", "&ersandsmall", "'Acutesmall", "/parenleftsuperior", "\\parenrightsuperior", "?twodotenleader", "?onedotenleader", "0zerooldstyle", "1oneoldstyle", "2twooldstyle", "3threeoldstyle", "4fouroldstyle", "5fiveoldstyle", "6sixoldstyle", "7sevenoldstyle", "8eightoldstyle", "9nineoldstyle", "'commasuperior", "--threequartersemdash", ".periodsuperior", "?questionsmall", "aasuperior", "bbsuperior", "ccentsuperior", "ddsuperior", "eesuperior", "iisuperior", "llsuperior", "mmsuperior", "nnsuperior", "oosuperior", "rrsuperior", "sssuperior", "ttsuperior", "ff", "ffi", "ffl", "\\parenleftinferior", "/parenrightinferior", "^Circumflexsmall", "-hyphensuperior", "`Gravesmall", "AAsmall", "BBsmall", "CCsmall", "DDsmall", "EEsmall", "FFsmall", "GGsmall", "HHsmall", "IIsmall", "JJsmall", "KKsmall", "LLsmall", "MMsmall", "NNsmall", "OOsmall", "PPsmall", "QQsmall", "RRsmall", "SSsmall", "TTsmall", "UUsmall", "VVsmall", "WWsmall", "XXsmall", "YYsmall", "ZZsmall", ":colonmonetary", "1onefitted", "?rupiah", "~Tildesmall", "!exclamdownsmall", "ccentoldstyle", "LLslashsmall", "SScaronsmall", "ZZcaronsmall", "?Dieresissmall", "?Brevesmall", "^Caronsmall", "?Dotaccentsmall", "?Macronsmall", "--figuredash", "-hypheninferior", "?Ogoneksmall", "oRingsmall", ",Cedillasmall", "?questiondownsmall", "1/8oneeighth", "3/8threeeighths", "5/8fiveeighths", "7/8seveneighths", "1/3onethird", "2/3twothirds", "0zerosuperior", "4foursuperior", "5fivesuperior", "6sixsuperior", "7sevensuperior", "8eightsuperior", "9ninesuperior", "0zeroinferior", "1oneinferior", "2twoinferior", "3threeinferior", "4fourinferior", "5fiveinferior", "6sixinferior", "7seveninferior", "8eightinferior", "9nineinferior", "ccentinferior", "$dollarinferior", ".periodinferior", ",commainferior", "AAgravesmall", "AAacutesmall", "AAcircumflexsmall", "AAtildesmall", "AAdieresissmall", "AAringsmall", "AEAEsmall", "CCcedillasmall", "EEgravesmall", "EEacutesmall", "EEcircumflexsmall", "EEdieresissmall", "IIgravesmall", "IIacutesmall", "IIcircumflexsmall", "IIdieresissmall", "EthEthsmall", "NNtildesmall", "OOgravesmall", "OOacutesmall", "OOcircumflexsmall", "OOtildesmall", "OOdieresissmall", "OEOEsmall", "OOslashsmall", "UUgravesmall", "UUacutesmall", "UUcircumflexsmall", "UUdieresissmall", "YYacutesmall", "?Thornsmall", "YYdieresissmall", "?001.000", "?001.001", "?001.002", "?001.003", " Black", " Bold", " Book", " Light", " Medium", " Regular", " Roman", " Semibold", /* extra mac stuff */ "?NUL", "?HT", " LF", " CR", "?DLE", "?DC1", "?DC2", "?DC3", "?DC4", "?RS", "?US", "!=", "?DEL", "?infinity", "<=", ">=", "?partialdiff", "?summation", "xproduct", "?pi", "?integral", "?Omega", "?radical", "~=", "?Delta", " nbspace", "?lozenge", "?apple" }; /** * glyph order of the glyphs for the Type1C Expert character set. These * are indices into the glyph name array. */ public static final int type1CExpertCharset[] = { 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378 }; /** * glyph order of the glyphs for the Type1C Expert Sub character set. * These are indices into the glyph name array. */ public static final int type1CExpertSubCharset[] = { 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346 }; /** * extra names for the Macintosh glyph set. This array should be * considered to be appended to the stdNames array. The stdValues array * already contains values for this set. */ public static final String macExtras[] = { // index starts at 391=NUL "NUL", "HT", "LF", "CR", "DLE", "DC1", "DC2", "DC3", "DC4", "RS", "US", "notequal", "DEL", "infinity", "lessequal", "greaterequal", "partialdiff", "summation", "product", "pi", "integral", "Omega", "radical", "approxequal", "Delta", "nbspace", "lozenge", "apple" }; /** * character mapping from values to glyphs for the Macintosh MacRoman * encoding */ public static final int macRomanEncoding[] = { 391, 154, 167, 140, 146, 192, 221, 197, 226, 392, 393, 157, 162, 394, 199, 228, 395, 396, 397, 398, 399, 155, 158, 150, 163, 169, 164, 160, 166, 168, 400, 401, 1, 2, 3, 4, 5, 6, 7, 104, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 124, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 403, 173, 175, 177, 178, 186, 189, 195, 200, 203, 201, 202, 205, 204, 206, 207, 210, 208, 209, 211, 214, 212, 213, 215, 216, 219, 217, 218, 220, 222, 225, 223, 224, 112, 161, 97, 98, 102, 116, 115, 149, 165, 170, 153, 125, 131, 402, 138, 141, 404, 156, 405, 406, 100, 152, 407, 408, 409, 410, 411, 139, 143, 412, 144, 147, 123, 96, 151, 413, 101, 414, 415, 106, 120, 121, 416, 174, 176, 191, 142, 148, 111, 137, 105, 119, 65, 8, 159, 417, 227, 198, 99, 103, 107, 108, 109, 110, 113, 114, 117, 118, 122, 172, 179, 171, 180, 181, 182, 183, 184, 185, 187, 188, 418, 190, 193, 194, 196, 145, 126, 127, 128, 129, 130, 132, 133, 134, 135, 136 }; /** * character mapping from values to glyphs for the isoLatin1Encoding */ public static final int isoLatin1Encoding[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 166, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, 1, 96, 97, 98, 103, 100, 160, 102, 131, 170, 139, 106, 151, 14, 165, 128, 161, 156, 164, 169, 125, 152, 115, 114, 133, 150, 143, 120, 158, 155, 163, 123, 174, 171, 172, 176, 173, 175, 138, 177, 181, 178, 179, 180, 185, 182, 183, 184, 154, 186, 190, 187, 188, 191, 189, 168, 141, 196, 193, 194, 195, 197, 157, 149, 203, 200, 201, 205, 202, 204, 144, 206, 210, 207, 208, 209, 214, 211, 212, 213, 167, 215, 219, 216, 217, 220, 218, 159, 147, 225, 222, 223, 224, 226, 162, 227 }; /** * character mapping from values to glyphs for the Windows winAnsi * character encoding */ public static final int winAnsiEncoding[] = { 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 117, 101, 118, 121, 112, 113, 0, 122, 192, 107, 142, 0, 0, 0, 0, 65, 8, 105, 119, 116, 111, 137, 0, 153, 221, 108, 148, 0, 0, 198, 1, 96, 97, 98, 103, 100, 160, 102, 131, 170, 139, 106, 151, 14, 165, 128, 161, 156, 164, 169, 125, 152, 115, 114, 133, 150, 143, 120, 158, 155, 163, 123, 174, 171, 172, 176, 173, 175, 138, 177, 181, 178, 179, 180, 185, 182, 183, 184, 154, 186, 190, 187, 188, 191, 189, 168, 141, 196, 193, 194, 195, 197, 157, 149, 203, 200, 201, 205, 202, 204, 144, 206, 210, 207, 208, 209, 214, 211, 212, 213, 167, 215, 219, 216, 217, 220, 218, 159, 147, 225, 222, 223, 224, 226, 162, 227 }; /** * character mapping from values to glyphs for Adobe's standard * character encoding */ public static final int standardEncoding[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0 }; /** * get the name of a glyph from its encoding value (NOT the character * value), using the standard encoding. */ public static String getName (int i) { if (i < stdNames.length) { return stdNames[i]; } else { i -= stdNames.length; if (i < macExtras.length) { return macExtras[i]; } } return ".notdef"; } /** * get the encoding value a glyph given its name and a name table. * @param name the name of the glyph * @param table the charset as an array of names * @return the index of the name in the table, or -1 if the name * cannot be found in the table */ public static int findName (String name, String[] table) { for (int i = 0; i < table.length; i++) { if (name.equals (table[i])) { return i; } } return -1; } /** * get the encoding value of a glyph given its name and a charset. * @param name the name of the glyph * @param table the charset table * @return the index of the name in the charset. */ public static int findName (String name, int[] table) { for (int i = 0; i < table.length; i++) { if (name.equals (getName (table[i]))) { return i; } } return -1; } /** * get the encoding value of a glyph given its name, in the standard * charset. This is equivalent to findName(name, FontSupport.stdNames). * @param name the name of the glyph * @return the index of the name in stdNames, or -1 if the name doesn't * appear in stdNames. */ public static int getStrIndex (String name) { for (int i = 0; i < stdNames.length; i++) { if (name.equals (stdNames[i])) { return i; } } return -1; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/PDFFont.java0000644000175000017500000002751311157264553022666 0ustar twernertwerner/* * $Id: PDFFont.java,v 1.6 2009-03-15 20:47:38 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * a Font definition for PDF files * @author Mike Wessler */ public abstract class PDFFont { /** the font SubType of this font */ private String subtype; /** the postscript name of this font */ private String baseFont; /** the font encoding (maps character ids to glyphs) */ private PDFFontEncoding encoding; /** the font descriptor */ private PDFFontDescriptor descriptor; /** the CMap that maps this font to unicode values */ private PDFCMap unicodeMap; /** a cache of glyphs indexed by character */ private Map charCache; /** * get the PDFFont corresponding to the font described in a PDFObject. * The object is actually a dictionary containing the following keys:
    * Type = "Font"
    * Subtype = (Type1 | TrueType | Type3 | Type0 | MMType1 | CIDFontType0 | * CIDFontType2)
    * FirstChar = #
    * LastChar = #
    * Widths = array of #
    * Encoding = (some name representing a dictionary in the resources | an * inline dictionary) *

    * For Type1 and TrueType fonts, the dictionary also contains:
    * BaseFont = (some name, or XXXXXX+Name as a subset of font Name) *

    * For Type3 font, the dictionary contains:
    * FontBBox = (rectangle)
    * FontMatrix = (array, typically [0.001, 0, 0, 0.001, 0, 0])
    * CharProcs = (dictionary) * Resources = (dictionary) */ public synchronized static PDFFont getFont(PDFObject obj, HashMap resources) throws IOException { // the obj is actually a dictionary containing: // Type (=Font) // Subtype (Type1, TrueType, Type3, Type0, MMType1, CIDFontType0,2) // FirstChar (int) // LastChar (int) // Widths (array) // Encoding (name or dict) : assumes StandardEncoding // and........ // Type1 and TrueType fonts: // BaseFont (name) // may be XXXXXX+Fontname as a subset. // FontDescriptor (dict) // Type3 fonts: // FontBBox (rectangle) // FontMatrix (array) // e.g. [0.001 0 0 0.001 0 0] // CharProcs (dict) // Resources (dict) // // Font descriptor (Type1 and TrueType fonts): // FontName (name) // Flags (1=monospace, 2=serif, 4=script, 7=italic, 19=bold) // FontBBox (rectangle) // ItalicAngle (float) // Ascent (float) // Descent (float) // CapHeight (float) // StemV (float) // FontFile (stream for Type1 fonts) // FontFile2 (stream for TrueType fonts) // FontFile3 (stream for CFF/Type1C fonts) // // Font data can be Type1, TrueType(native), or Type1C PDFFont font = (PDFFont) obj.getCache(); if (font != null) { return font; } String baseFont = null; PDFFontEncoding encoding = null; PDFFontDescriptor descriptor = null; String subType = obj.getDictRef("Subtype").getStringValue(); if (subType == null) { subType = obj.getDictRef("S").getStringValue(); } PDFObject baseFontObj = obj.getDictRef("BaseFont"); PDFObject encodingObj = obj.getDictRef("Encoding"); PDFObject descObj = obj.getDictRef("FontDescriptor"); if (baseFontObj != null) { baseFont = baseFontObj.getStringValue(); } else { baseFontObj = obj.getDictRef("Name"); if (baseFontObj != null) { baseFont = baseFontObj.getStringValue(); } } if (encodingObj != null) { encoding = new PDFFontEncoding(subType, encodingObj); } if (descObj != null) { descriptor = new PDFFontDescriptor(descObj); } else { descriptor = new PDFFontDescriptor(baseFont); } if (subType.equals("Type0")) { font = new Type0Font(baseFont, obj, descriptor); } else if (subType.equals("Type1")) { // load a type1 font if (descriptor == null) { // it's one of the built-in fonts font = new BuiltinFont(baseFont, obj); } else if (descriptor.getFontFile() != null) { // it's a Type1 font, included. font = new Type1Font(baseFont, obj, descriptor); } else if (descriptor.getFontFile3() != null) { // it's a CFF (Type1C) font font = new Type1CFont(baseFont, obj, descriptor); } else { // no font info. Fake it based on the FontDescriptor // System.out.println("Fakeout native font"); font = new BuiltinFont(baseFont, obj, descriptor); } } else if (subType.equals("TrueType")) { if (descriptor.getFontFile2() != null) { // load a TrueType font font = new TTFFont(baseFont, obj, descriptor); } else { // fake it with a built-in font font = new BuiltinFont(baseFont, obj, descriptor); } } else if (subType.equals("Type3")) { // load a type 3 font font = new Type3Font(baseFont, obj, resources, descriptor); } else if (subType.equals("CIDFontType2")) { font = new CIDFontType2(baseFont, obj, descriptor); } else if (subType.equals("CIDFontType0")) { font = new CIDFontType2(baseFont, obj, descriptor); // font = new CIDFontType0(baseFont, obj, descriptor); // throw new IOException ("CIDFontType0 is unimplemented. " + obj); } else { throw new PDFParseException("Don't know how to handle a '" + subType + "' font"); } font.setSubtype(subType); font.setEncoding(encoding); obj.setCache(font); return font; } /** * Get the subtype of this font. * @return the subtype, one of: Type0, Type1, TrueType or Type3 */ public String getSubtype() { return subtype; } /** * Set the font subtype */ public void setSubtype(String subtype) { this.subtype = subtype; } /** * Get the postscript name of this font * @return the postscript name of this font */ public String getBaseFont() { return baseFont; } /** * Set the postscript name of this font * @param baseFont the postscript name of the font */ public void setBaseFont(String baseFont) { this.baseFont = baseFont; } /** * Get the encoding for this font * @return the encoding which maps from this font to actual characters */ public PDFFontEncoding getEncoding() { return encoding; } /** * Set the encoding for this font */ public void setEncoding(PDFFontEncoding encoding) { this.encoding = encoding; } /** * Get the descriptor for this font * @return the font descriptor */ public PDFFontDescriptor getDescriptor() { return descriptor; } /** * Set the descriptor font descriptor */ public void setDescriptor(PDFFontDescriptor descriptor) { this.descriptor = descriptor; } /** * Get the CMap which maps the characters in this font to unicode names */ public PDFCMap getUnicodeMap() { return unicodeMap; } /** * Set the CMap which maps the characters in this font to unicode names */ public void setUnicodeMap(PDFCMap unicodeMap) { this.unicodeMap = unicodeMap; } /** * Get the glyphs associated with a given String in this font * * @param text the text to translate into glyphs */ public List getGlyphs(String text) { List outList = null; // if we have an encoding, use it to get the commands if (encoding != null) { outList = encoding.getGlyphs(this, text); } else { // use the default mapping char[] arry = text.toCharArray(); outList = new ArrayList(arry.length); for (int i = 0; i < arry.length; i++) { // only look at 2 bytes when there is no encoding char src = (char) (arry[i] & 0xff); outList.add(getCachedGlyph(src, null)); } } return outList; } /** * Get a glyph for a given character code. The glyph is returned * from the cache if available, or added to the cache if not * * @param src the character code of this glyph * @param name the name of the glyph, or null if the name is unknown * @return a glyph for this character */ public PDFGlyph getCachedGlyph(char src, String name) { if (charCache == null) { charCache = new HashMap(); } // try the cache PDFGlyph glyph = (PDFGlyph) charCache.get(new Character(src)); // if it's not there, add it to the cache if (glyph == null) { glyph = getGlyph(src, name); charCache.put(new Character(src), glyph); } return glyph; } /** * Create a PDFFont given the base font name and the font descriptor * @param baseFont the postscript name of this font * @param descriptor the descriptor for the font */ protected PDFFont(String baseFont, PDFFontDescriptor descriptor) { setBaseFont(baseFont); setDescriptor(descriptor); } /** * Get the glyph for a given character code and name * * The preferred method of getting the glyph should be by name. If the * name is null or not valid, then the character code should be used. * If the both the code and the name are invalid, the undefined glyph * should be returned. * * Note this method must *always* return a glyph. * * @param src the character code of this glyph * @param name the name of this glyph or null if unknown * @return a glyph for this character */ protected abstract PDFGlyph getGlyph(char src, String name); /** * Turn this font into a pretty String */ @Override public String toString() { return getBaseFont(); } /** * Compare two fonts base on the baseFont */ @Override public boolean equals(Object o) { if (!(o instanceof PDFFont)) { return false; } return ((PDFFont) o).getBaseFont().equals(getBaseFont()); } /** * Hash a font based on its base font */ @Override public int hashCode() { return getBaseFont().hashCode(); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/PDFCMap.java0000644000175000017500000000613011145024767022566 0ustar twernertwerner/* * $Id: PDFCMap.java,v 1.3 2009-02-12 13:53:54 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.io.IOException; import java.util.HashMap; import com.sun.pdfview.PDFObject; /** * A CMap maps from a character in a composite font to a font/glyph number * pair in a CID font. * * @author jkaplan */ public abstract class PDFCMap { /** * A cache of known CMaps by name */ private static HashMap cache; /** Creates a new instance of CMap */ protected PDFCMap() {} /** * Get a CMap, given a PDF object containing one of the following: * a string name of a known CMap * a stream containing a CMap definition */ public static PDFCMap getCMap(PDFObject map) throws IOException { if (map.getType() == PDFObject.NAME) { return getCMap(map.getStringValue()); } else if (map.getType() == PDFObject.STREAM) { return parseCMap(map); } else { throw new IOException("CMap type not Name or Stream!"); } } /** * Get a CMap, given a string name */ public static PDFCMap getCMap(String mapName) throws IOException { if (cache == null) { populateCache(); } if (!cache.containsKey(mapName)) { throw new IOException("Unknown CMap: " + mapName); } return (PDFCMap) cache.get(mapName); } /** * Populate the cache with well-known types */ protected static void populateCache() { cache = new HashMap(); // add the Identity-H map cache.put("Identity-H", new PDFCMap() { public char map(char src) { return src; } }); } /** * Parse a CMap from a CMap stream */ protected static PDFCMap parseCMap(PDFObject map) throws IOException { throw new IOException("Parsing CMap Files Unsupported!"); } /** * Map a given source character to a destination character */ public abstract char map(char src); /** * Get the font number assoicated with a given source character */ public int getFontID(char src) { return 0; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/FlPoint.java0000644000175000017500000000305510732532577022776 0ustar twernertwerner/* * $Id: FlPoint.java,v 1.2 2007-12-20 18:33:31 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; /** * A floating-point Point, with public fields. Also contains a flag * for "open" to indicate that the path this point is a member of has * or hasn't been closed. * * @author Mike Wessler */ public class FlPoint { /** x coordinate of the point */ public float x= 0; /** y coordinate of the point */ public float y= 0; /** * whether the path this point is a part of is open or closed. * used in Type1CFont.java. */ public boolean open= false; /** reset the values to (0,0) and closed */ public final void reset() { x= 0; y= 0; open= false; } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/Type0Font.java0000644000175000017500000000433110732532577023251 0ustar twernertwerner/* * $Id: Type0Font.java,v 1.2 2007-12-20 18:33:32 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.io.IOException; import com.sun.pdfview.PDFObject; /** * Type 0 fonts are composite fonts with a CMAP to map between * source character codes and destination fonts/codes * * @author Jonathan Kaplan */ public class Type0Font extends PDFFont { /** * The decendant fonts, indexed by font number from the CMAP */ PDFFont[] fonts; /** Creates a new instance of Type0Font */ public Type0Font(String baseFont, PDFObject fontObj, PDFFontDescriptor descriptor) throws IOException { super (baseFont, descriptor); PDFObject[] descendantFonts = fontObj.getDictRef("DescendantFonts").getArray(); fonts = new PDFFont[descendantFonts.length]; for (int i = 0; i < descendantFonts.length; i++) { fonts[i] = PDFFont.getFont(descendantFonts[i], null); } } /** * Get a descendant font of this font by fontId */ public PDFFont getDescendantFont(int fontID) { return fonts[fontID]; } /** * Get a character from the first font in the descendant fonts array */ protected PDFGlyph getGlyph(char src, String name) { return (getDescendantFont(0).getGlyph(src, name)); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/Type1Font.java0000644000175000017500000007741511237133224023252 0ustar twernertwerner/* * $Id: Type1Font.java,v 1.8 2009-08-07 23:19:48 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFObject; /** * A representation, with parser, of an Adobe Type 1 font. * @author Mike Wessler * * @todo * The parsing of the encrypted section needs work. A fix has just gone into * readArray, but it is very heuristic (as is all of readArray) and simply * stops the read at any invalid input. */ public class Type1Font extends OutlineFont { String chr2name[]; int password; byte[] subrs[]; int lenIV; Map name2outline; Map name2width; AffineTransform at; /** the Type1 stack of command values */ float stack[] = new float[100]; /** the current position in the Type1 stack */ int sloc = 0; /** the stack of postscript commands (used by callothersubr) */ float psStack[] = new float[3]; /** the current position in the postscript stack */ int psLoc = 0; /** * create a new Type1Font based on a font data stream and an encoding. * @param baseName the postscript name of this font * @param src the Font object as a stream with a dictionary * @param descriptor the descriptor for this font */ public Type1Font(String baseName, PDFObject src, PDFFontDescriptor descriptor) throws IOException { super(baseName, src, descriptor); if (descriptor != null && descriptor.getFontFile() != null) { // parse that file, filling name2outline and chr2name int start = descriptor.getFontFile().getDictRef("Length1").getIntValue(); int len = descriptor.getFontFile().getDictRef("Length2").getIntValue(); byte font[] = descriptor.getFontFile().getStream(); parseFont(font, start, len); } } /** Read a font from it's data, start position and length */ protected void parseFont(byte[] font, int start, int len) { name2width = new HashMap(); byte data[] = null; if (isASCII(font, start)) { byte[] bData = readASCII(font, start, start + len); data = decrypt(bData, 0, bData.length, 55665, 4); } else { data = decrypt(font, start, start + len, 55665, 4); } // encoding is in cleartext area chr2name = readEncoding(font); int lenIVLoc = findSlashName(data, "lenIV"); PSParser psp = new PSParser(data, 0); if (lenIVLoc < 0) { lenIV = 4; } else { psp.setLoc(lenIVLoc + 6); lenIV = Integer.parseInt(psp.readThing()); } password = 4330; int matrixloc = findSlashName(font, "FontMatrix"); if (matrixloc < 0) { System.out.println("No FontMatrix!"); at = new AffineTransform(0.001f, 0, 0, 0.001f, 0, 0); } else { PSParser psp2 = new PSParser(font, matrixloc + 11); // read [num num num num num num] float xf[] = psp2.readArray(6); // System.out.println("FONT MATRIX: "+xf); at = new AffineTransform(xf); } subrs = readSubrs(data); name2outline = new TreeMap(readChars(data)); // at this point, name2outline holds name -> byte[]. } /** * parse the encoding portion of the font definition * @param d the font definition stream * @return an array of the glyphs corresponding to each byte */ private String[] readEncoding(byte[] d) { byte[][] ary = readArray(d, "Encoding", "def"); String res[] = new String[256]; for (int i = 0; i < ary.length; i++) { if (ary[i] != null) { if (ary[i][0] == '/') { res[i] = new String(ary[i]).substring(1); } else { res[i] = new String(ary[i]); } } else { res[i] = null; } } return res; } /** * read the subroutines out of the font definition * @param d the font definition stream * @return an array of the subroutines, each as a byte array. */ private byte[][] readSubrs(byte[] d) { return readArray(d, "Subrs", "index"); } /** * read a named array out of the font definition. *

    * this function attempts to parse an array out of a postscript * definition without doing any postscript. It's actually looking * for things that look like "dup id elt put", and * placing the elt at the ith position in the array. * @param d the font definition stream * @param key the name of the array * @param end a string that appears at the end of the array * @return an array consisting of a byte array for each entry */ private byte[][] readArray(byte[] d, String key, String end) { int i = findSlashName(d, key); if (i < 0) { // not found. return new byte[0][]; } // now find things that look like "dup id elt put" // end at "def" PSParser psp = new PSParser(d, i); String type = psp.readThing(); // read the key (i is the start of the key) double val; type = psp.readThing(); if (type.equals("StandardEncoding")) { byte[] stdenc[] = new byte[FontSupport.standardEncoding.length][]; for (i = 0; i < stdenc.length; i++) { stdenc[i] = FontSupport.getName(FontSupport.standardEncoding[i]).getBytes(); } return stdenc; } int len = Integer.parseInt(type); byte[] out[] = new byte[len][]; byte[] line; while (true) { String s = psp.readThing(); if (s.equals("dup")) { String thing = psp.readThing(); int id = 0; try { id = Integer.parseInt(thing); } catch (Exception e) { break; } String elt = psp.readThing(); line = elt.getBytes(); if (Character.isDigit(elt.charAt(0))) { int hold = Integer.parseInt(elt); String special = psp.readThing(); if (special.equals("-|") || special.equals("RD")) { psp.setLoc(psp.getLoc() + 1); line = psp.getNEncodedBytes(hold, password, lenIV); } } out[id] = line; } else if (s.equals(end)) { break; } } return out; } /** * decrypt an array using the Adobe Type 1 Font decryption algorithm. * @param d the input array of bytes * @param start where in the array to start decoding * @param end where in the array to stop decoding * @param key the decryption key * @param skip how many bytes to skip initially * @return the decrypted bytes. The length of this array will be * (start-end-skip) bytes long */ private byte[] decrypt(byte[] d, int start, int end, int key, int skip) { if (end - start - skip < 0) { skip = 0; } byte[] o = new byte[end - start - skip]; int r = key; int ipos; int c1 = 52845; int c2 = 22719; for (ipos = start; ipos < end; ipos++) { int c = d[ipos] & 0xff; int p = (c ^ (r >> 8)) & 0xff; r = ((c + r) * c1 + c2) & 0xffff; if (ipos - start - skip >= 0) { o[ipos - start - skip] = (byte) p; } } return o; } /** * Read data formatted as ASCII strings as binary data * * @param data the data, formatted as ASCII strings * @param start where in the array to start decrypting * @param end where in the array to stop decrypting */ private byte[] readASCII(byte[] data, int start, int end) { // each byte of output is derived from one character (two bytes) of // input byte[] o = new byte[(end - start) / 2]; int count = 0; int bit = 0; for (int loc = start; loc < end; loc++) { char c = (char) (data[loc] & 0xff); byte b = (byte) 0; if (c >= '0' && c <= '9') { b = (byte) (c - '0'); } else if (c >= 'a' && c <= 'f') { b = (byte) (10 + (c - 'a')); } else if (c >= 'A' && c <= 'F') { b = (byte) (10 + (c - 'A')); } else { // linefeed or something. Skip. continue; } // which half of the byte are we? if ((bit++ % 2) == 0) { o[count] = (byte) (b << 4); } else { o[count++] |= b; } } return o; } /** * Determine if data is in ASCII or binary format. According to the spec, * if any of the first 4 bytes are not character codes ('0' - '9' or * 'A' - 'F' or 'a' - 'f'), then the data is binary. Otherwise it is * ASCII */ private boolean isASCII(byte[] data, int start) { // look at the first 4 bytes for (int i = start; i < start + 4; i++) { // get the byte as a character char c = (char) (data[i] & 0xff); if (c >= '0' && c <= '9') { continue; } else if (c >= 'a' && c <= 'f') { continue; } else if (c >= 'A' && c <= 'F') { continue; } else { // out of range return false; } } // all were in range, so it is ASCII return true; } /** * PostScript reader (not a parser, as the name would seem to indicate). */ class PSParser { byte[] data; int loc; /** * create a PostScript reader given some data and an initial offset * into that data. * @param data the bytes of the postscript information * @param start an initial offset into the data */ public PSParser(byte[] data, int start) { this.data = data; this.loc = start; // System.out.println("PSParser.constructor: start: " + start + // ", Length: " + data.length); // System.out.print (new String(data, loc, data.length - loc)); // System.out.println(" - end -\n"); } /** * get the next postscript "word". This is basically the next * non-whitespace block between two whitespace delimiters. * This means that something like " [2 4 53]" will produce * three items, while " [2 4 56 ]" will produce four. */ public String readThing() { // skip whitespace // System.out.println("PAParser: whitespace: \""); while (PDFFile.isWhiteSpace(data[loc])) { // System.out.print (new String(data, loc, 1)); loc++; } // System.out.print("\": thing: "); // read thing int start = loc; while (!PDFFile.isWhiteSpace(data[loc])) { loc++; if (!PDFFile.isRegularCharacter(data[loc])) { break; // leave with the delimiter included } } String s = new String(data, start, loc - start); // System.out.println(": Read: "+s); return s; } /** * read a set of numbers from the input. This method doesn't * pay any attention to "[" or "]" delimiters, and reads any * non-numeric items as the number 0. * @param count the number of items to read * @return an array of count floats */ public float[] readArray(int count) { float[] ary = new float[count]; int idx = 0; while (idx < count) { String thing = readThing(); if (thing.charAt(0) == '[') { thing = thing.substring(1); } if (thing.endsWith("]")) { thing = thing.substring(0, thing.length() - 1); } if (thing.length() > 0) { ary[idx++] = Float.valueOf(thing).floatValue(); } } return ary; } /** * get the current location within the input stream */ public int getLoc() { return loc; } /** * set the current location within the input stream */ public void setLoc(int loc) { this.loc = loc; } /** * treat the next n bytes of the input stream as encoded * information to be decrypted. * @param n the number of bytes to decrypt * @param key the decryption key * @param skip the number of bytes to skip at the beginning of the * decryption * @return an array of decrypted bytes. The length of the array * will be n-skip. */ public byte[] getNEncodedBytes(int n, int key, int skip) { byte[] result = decrypt(data, loc, loc + n, key, skip); loc += n; return result; } } /** * get the index into the byte array of a slashed name, like "/name". * @param d the search array * @param name the name to look for, without the initial / * @return the index of the first occurance of /name in the array. */ private int findSlashName(byte[] d, String name) { int i; for (i = 0; i < d.length; i++) { if (d[i] == '/') { // check for key boolean found = true; for (int j = 0; j < name.length(); j++) { if (d[i + j + 1] != name.charAt(j)) { found = false; break; } } if (found) { return i; } } } return -1; } /** * get the character definitions of the font. * @param d the font data * @return a HashMap that maps string glyph names to byte arrays of * decoded font data. */ private HashMap readChars(byte[] d) { // skip thru data until we find "/"+key HashMap hm = new HashMap(); int i = findSlashName(d, "CharStrings"); if (i < 0) { // not found return hm; } PSParser psp = new PSParser(d, i); // read /name len -| [len bytes] |- // until "end" while (true) { String s = psp.readThing(); char c = s.charAt(0); if (c == '/') { int len = Integer.parseInt(psp.readThing()); String go = psp.readThing(); // it's -| or RD if (go.equals("-|") || go.equals("RD")) { psp.setLoc(psp.getLoc() + 1); byte[] line = psp.getNEncodedBytes(len, password, lenIV); hm.put(s.substring(1), line); } } else if (s.equals("end")) { break; } } return hm; } /** * pop the next item off the stack */ private float pop() { float val = 0; if (sloc > 0) { val = stack[--sloc]; } return val; } int callcount = 0; /** * parse glyph data into a GeneralPath, and return the advance width. * The working point is passed in as a parameter in order to allow * recursion. * @param cs the decrypted glyph data * @param gp a GeneralPath into which the glyph shape will be stored * @param pt a FlPoint object that will be used to generate the path * @param wid a FlPoint into which the advance width will be placed. */ private void parse(byte[] cs, GeneralPath gp, FlPoint pt, FlPoint wid) { // System.out.println("--- cmd length is "+cs.length); int loc = 0; float x1, x2, x3, y1, y2, y3; while (loc < cs.length) { int v = ((int) cs[loc++]) & 0xff; if (v == 255) { stack[sloc++] = ((((int) cs[loc]) & 0xff) << 24) + ((((int) cs[loc + 1]) & 0xff) << 16) + ((((int) cs[loc + 2]) & 0xff) << 8) + ((((int) cs[loc + 3]) & 0xff)); loc += 4; // System.out.println("Pushed long "+stack[sloc-1]); } else if (v >= 251) { stack[sloc++] = -((v - 251) << 8) - (((int) cs[loc]) & 0xff) - 108; loc++; // System.out.println("Pushed lo "+stack[sloc-1]); } else if (v >= 247) { stack[sloc++] = ((v - 247) << 8) + (((int) cs[loc]) & 0xff) + 108; loc++; // System.out.println("Pushed hi "+stack[sloc-1]); } else if (v >= 32) { stack[sloc++] = v - 139; // System.out.println("Pushed "+stack[sloc-1]); } else { // System.out.println("CMD: "+v+" (stack is size "+sloc+")"); switch (v) { case 0: // x throw new RuntimeException("Bad command (" + v + ")"); case 1: // hstem sloc = 0; break; case 2: // x throw new RuntimeException("Bad command (" + v + ")"); case 3: // vstem sloc = 0; break; case 4: // y vmoveto pt.y += pop(); gp.moveTo(pt.x, pt.y); sloc = 0; break; case 5: // x y rlineto pt.y += pop(); pt.x += pop(); gp.lineTo(pt.x, pt.y); sloc = 0; break; case 6: // x hlineto pt.x += pop(); gp.lineTo(pt.x, pt.y); sloc = 0; break; case 7: // y vlineto pt.y += pop(); gp.lineTo(pt.x, pt.y); sloc = 0; break; case 8: // x1 y1 x2 y2 x3 y3 rcurveto y3 = pop(); x3 = pop(); y2 = pop(); x2 = pop(); y1 = pop(); x1 = pop(); gp.curveTo(pt.x + x1, pt.y + y1, pt.x + x1 + x2, pt.y + y1 + y2, pt.x + x1 + x2 + x3, pt.y + y1 + y2 + y3); pt.x += x1 + x2 + x3; pt.y += y1 + y2 + y3; sloc = 0; break; case 9: // closepath gp.closePath(); sloc = 0; break; case 10: // n callsubr int n = (int) pop(); if (subrs[n] == null) { System.out.println("No subroutine #" + n); } else { callcount++; if (callcount > 10) { System.out.println("Call stack too large"); // throw new RuntimeException("Call stack too large"); } else { parse(subrs[n], gp, pt, wid); } callcount--; } break; case 11: // return return; case 12: // ext... v = ((int) cs[loc++]) & 0xff; if (v == 6) { // s x y b a seac char a = (char) pop(); char b = (char) pop(); float y = pop(); float x = pop(); buildAccentChar(x, y, a, b, gp); sloc = 0; } else if (v == 7) { // x y w h sbw wid.y = pop(); wid.x = pop(); pt.y = pop(); pt.x = pop(); sloc = 0; } else if (v == 12) { // a b div -> a/b float b = pop(); float a = pop(); stack[sloc++] = a / b; } else if (v == 33) { // a b setcurrentpoint pt.y = pop(); pt.x = pop(); gp.moveTo(pt.x, pt.y); sloc = 0; } else if (v == 0) { // dotsection sloc = 0; } else if (v == 1) { // vstem3 sloc = 0; } else if (v == 2) { // hstem3 sloc = 0; } else if (v == 16) { // n callothersubr int cn = (int) pop(); int countargs = (int) pop(); // System.out.println("Called othersubr with index "+cn); switch (cn) { case 0: // push args2 and args3 onto stack psStack[psLoc++] = pop(); psStack[psLoc++] = pop(); pop(); break; case 3: // push 3 onto the postscript stack psStack[psLoc++] = 3; break; default: // push arguments onto the postscript stack for (int i = 0; i > countargs; i--) { psStack[psLoc++] = pop(); } break; } } else if (v == 17) { // pop // pop from the postscript stack onto the type1 stack stack[sloc++] = psStack[psLoc - 1]; psLoc--; } else { throw new RuntimeException("Bad command (" + v + ")"); } break; case 13: // s w hsbw wid.x = pop(); wid.y = 0; pt.x = pop(); pt.y = 0; // gp.moveTo(pt.x, pt.y); sloc = 0; break; case 14: // endchar // return; break; case 15: // x case 16: // x case 17: // x case 18: // x case 19: // x case 20: // x throw new RuntimeException("Bad command (" + v + ")"); case 21: // x y rmoveto pt.y += pop(); pt.x += pop(); gp.moveTo(pt.x, pt.y); sloc = 0; break; case 22: // x hmoveto pt.x += pop(); gp.moveTo(pt.x, pt.y); sloc = 0; break; case 23: // x case 24: // x case 25: // x case 26: // x case 27: // x case 28: // x case 29: // x throw new RuntimeException("Bad command (" + v + ")"); case 30: // y1 x2 y2 x3 vhcurveto x3 = pop(); y2 = pop(); x2 = pop(); y1 = pop(); x1 = y3 = 0; gp.curveTo(pt.x, pt.y + y1, pt.x + x2, pt.y + y1 + y2, pt.x + x2 + x3, pt.y + y1 + y2); pt.x += x2 + x3; pt.y += y1 + y2; sloc = 0; break; case 31: // x1 x2 y2 y3 hvcurveto y3 = pop(); y2 = pop(); x2 = pop(); x1 = pop(); y1 = x3 = 0; gp.curveTo(pt.x + x1, pt.y, pt.x + x1 + x2, pt.y + y2, pt.x + x1 + x2, pt.y + y2 + y3); pt.x += x1 + x2; pt.y += y2 + y3; sloc = 0; break; } } } } /** * build an accented character out of two pre-defined glyphs. * @param x the x offset of the accent relativ to the sidebearing of the base char * @param y the y offset of the accent relativ to the sidebearing of the base char * @param a the index of the accent glyph * @param b the index of the base glyph * @param gp the GeneralPath into which the combined glyph will be * written. */ private void buildAccentChar(float x, float y, char a, char b, GeneralPath gp) { // get the outline of the accent GeneralPath pathA = getOutline(a, getWidth(a, null)); // don't manipulate the original glyph pathA = (GeneralPath) pathA.clone(); try { // undo the effect of the transform applied in read final AffineTransform xformA = at.createInverse(); pathA.transform(xformA); // Best x can�t be calcualted cause we don�t know the left sidebearing of the base character. // Leaving x=0 gives the best results. // see Chapter 6 of http://partners.adobe.com/public/developer/en/font/5015.Type1_Supp.pdf // and the definition of the seac-Command in http://partners.adobe.com/public/developer/en/font/T1_SPEC.PDF final AffineTransform xformA2 = AffineTransform.getTranslateInstance(0, y); pathA.transform(xformA2); //<-- goht net fürs 'ä' } catch (NoninvertibleTransformException nte) { pathA.transform(AffineTransform.getTranslateInstance(0, y)); } GeneralPath pathB = getOutline(b, getWidth(b, null)); // don't manipulate the original glyph pathB = (GeneralPath) pathB.clone(); try { AffineTransform xformB = at.createInverse(); pathB.transform(xformB); } catch (NoninvertibleTransformException nte) { // ignore } gp.append(pathB, false); gp.append(pathA, false); } /** * Get the width of a given character * * This method is overridden to work if the width array hasn't been * populated (as for one of the 14 base fonts) */ @Override public float getWidth(char code, String name) { // we don't have first and last chars, so therefore no width array if (getFirstChar() == -1 || getLastChar() == -1) { String key = chr2name[code & 0xff]; // use a name if one is provided if (name != null) { key = name; } if (key != null && name2outline.containsKey(key)) { if (!name2width.containsKey(key)) { // glyph has not yet been parsed // getting the outline will force it to get read getOutline(key, 0); } FlPoint width = name2width.get(key); if (width != null) { return width.x / getDefaultWidth(); } } return 0; } // return the width that has been specified return super.getWidth(code, name); } /** * Decrypt a glyph stored in byte form */ private synchronized GeneralPath parseGlyph(byte[] cs, FlPoint advance, AffineTransform at) { GeneralPath gp = new GeneralPath(); FlPoint curpoint = new FlPoint(); sloc = 0; parse(cs, gp, curpoint, advance); gp.transform(at); return gp; } /** * Get a glyph outline by name * * @param name the name of the desired glyph * @return the glyph outline, or null if unavailable */ protected GeneralPath getOutline(String name, float width) { // make sure we have a valid name if (name == null || !name2outline.containsKey(name)) { name = ".notdef"; } // get whatever is stored in name. Could be a GeneralPath, could be byte[] Object obj = name2outline.get(name); // if it's a byte array, it needs to be parsed // otherwise, just return the path if (obj instanceof GeneralPath) { return (GeneralPath) obj; } else { byte[] cs = (byte[]) obj; FlPoint advance = new FlPoint(); GeneralPath gp = parseGlyph(cs, advance, at); if (width != 0 && advance.x != 0) { // scale the glyph to fit in the width Point2D p = new Point2D.Float(advance.x, advance.y); at.transform(p, p); double scale = width / p.getX(); AffineTransform xform = AffineTransform.getScaleInstance(scale, 1.0); gp.transform(xform); } // put the parsed object in the cache name2outline.put(name, gp); name2width.put(name, advance); return gp; } } /** * Get a glyph outline by character code * * Note this method must always return an outline * * @param src the character code of the desired glyph * @return the glyph outline */ protected GeneralPath getOutline(char src, float width) { return getOutline(chr2name[src & 0xff], width); } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/TTFFont.java0000644000175000017500000002451511160342052022672 0ustar twernertwerner/* * $Id: TTFFont.java,v 1.11 2009-03-19 04:03:54 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.font.ttf.AdobeGlyphList; import com.sun.pdfview.font.ttf.CMap; import com.sun.pdfview.font.ttf.CmapTable; import com.sun.pdfview.font.ttf.Glyf; import com.sun.pdfview.font.ttf.GlyfCompound; import com.sun.pdfview.font.ttf.GlyfSimple; import com.sun.pdfview.font.ttf.GlyfTable; import com.sun.pdfview.font.ttf.HeadTable; import com.sun.pdfview.font.ttf.HmtxTable; import com.sun.pdfview.font.ttf.PostTable; import com.sun.pdfview.font.ttf.TrueTypeFont; /** * A true-type font */ public class TTFFont extends OutlineFont { /** the truetype font itself */ private TrueTypeFont font; /** the number of units per em in the font */ private float unitsPerEm; /** * create a new TrueTypeFont object based on a description of the * font from the PDF file. If the description happens to contain * an in-line true-type font file (under key "FontFile2"), use the * true type font. Otherwise, parse the description for key information * and use that to generate an appropriate font. */ public TTFFont (String baseFont, PDFObject fontObj, PDFFontDescriptor descriptor) throws IOException { super (baseFont, fontObj, descriptor); String fontName = descriptor.getFontName (); PDFObject ttfObj = descriptor.getFontFile2 (); // try { // byte[] fontData = ttfObj.getStream(); // java.io.FileOutputStream fis = new java.io.FileOutputStream("/tmp/" + fontName + ".ttf"); // fis.write(fontData); // fis.flush(); // fis.close(); // } catch (Exception ex) { // ex.printStackTrace(); // } if (ttfObj != null) { font = TrueTypeFont.parseFont (ttfObj.getStreamBuffer ()); // read the units per em from the head table HeadTable head = (HeadTable) font.getTable ("head"); unitsPerEm = head.getUnitsPerEm (); } else { font = null; } // System.out.println ("TTFFont: ttfObj: " + ttfObj + ", fontName: " + fontName); } /** * Get the outline of a character given the character code */ protected synchronized GeneralPath getOutline (char src, float width) { // find the cmaps CmapTable cmap = (CmapTable) font.getTable ("cmap"); // if there are no cmaps, this is (hopefully) a cid-mapped font, // so just trust the value we were given for src if (cmap == null) { return getOutline ((int) src, width); } CMap[] maps = cmap.getCMaps (); // try the maps in order for (int i = 0; i < maps.length; i++) { int idx = maps[i].map (src); if (idx != 0) { return getOutline (idx, width); } } // not found, return the empty glyph return getOutline (0, width); } /** * lookup the outline using the CMAPs, as specified in 32000-1:2008, * 9.6.6.4, when an Encoding is specified. * * @param val * @param width * @return GeneralPath */ protected synchronized GeneralPath getOutlineFromCMaps (char val, float width) { // find the cmaps CmapTable cmap = (CmapTable) font.getTable ("cmap"); if (cmap == null) { return null; } // try maps in required order of (3, 1), (1, 0) CMap map = cmap.getCMap ((short) 3, (short) 1); if (map == null) { map = cmap.getCMap ((short) 1, (short) 0); } int idx = map.map (val); if (idx != 0) { return getOutline (idx, width); } return null; } /** * Get the outline of a character given the character name */ protected synchronized GeneralPath getOutline (String name, float width) { int idx; PostTable post = (PostTable) font.getTable ("post"); if (post != null) { idx = post.getGlyphNameIndex (name); if (idx != 0) { return getOutline (idx, width); } return null; } Integer res = AdobeGlyphList.getGlyphNameIndex (name); if (res != null) { idx = res; return getOutlineFromCMaps ((char) idx, width); } return null; } /** * Get the outline of a character given the glyph id */ protected synchronized GeneralPath getOutline (int glyphId, float width) { // find the glyph itself GlyfTable glyf = (GlyfTable) font.getTable ("glyf"); Glyf g = glyf.getGlyph (glyphId); GeneralPath gp = null; if (g instanceof GlyfSimple) { gp = renderSimpleGlyph ((GlyfSimple) g); } else if (g instanceof GlyfCompound) { gp = renderCompoundGlyph (glyf, (GlyfCompound) g); } else { gp = new GeneralPath (); } // calculate the advance HmtxTable hmtx = (HmtxTable) font.getTable ("hmtx"); float advance = (float) hmtx.getAdvance (glyphId) / (float) unitsPerEm; // scale the glyph to match the desired advance float widthfactor = width / advance; // the base transform scales the glyph to 1x1 AffineTransform at = AffineTransform.getScaleInstance (1 / unitsPerEm, 1 / unitsPerEm); at.concatenate (AffineTransform.getScaleInstance (widthfactor, 1)); gp.transform (at); return gp; } /** * Render a simple glyf */ protected GeneralPath renderSimpleGlyph (GlyfSimple g) { // the current contour int curContour = 0; // the render state RenderState rs = new RenderState (); rs.gp = new GeneralPath (); for (int i = 0; i < g.getNumPoints (); i++) { PointRec rec = new PointRec (g, i); if (rec.onCurve) { addOnCurvePoint (rec, rs); } else { addOffCurvePoint (rec, rs); } // see if we just ended a contour if (i == g.getContourEndPoint (curContour)) { curContour++; if (rs.firstOff != null) { addOffCurvePoint (rs.firstOff, rs); } if (rs.firstOn != null) { addOnCurvePoint (rs.firstOn, rs); } rs.firstOn = null; rs.firstOff = null; rs.prevOff = null; } } return rs.gp; } /** * Render a compound glyf */ protected GeneralPath renderCompoundGlyph (GlyfTable glyf, GlyfCompound g) { GeneralPath gp = new GeneralPath (); for (int i = 0; i < g.getNumComponents (); i++) { // find and render the component glyf Glyf gl = glyf.getGlyph (g.getGlyphIndex (i)); GeneralPath path = null; if (gl instanceof GlyfSimple) { path = renderSimpleGlyph ((GlyfSimple) gl); } else if (gl instanceof GlyfCompound) { path = renderCompoundGlyph (glyf, (GlyfCompound) gl); } else { throw new RuntimeException ( "Unsupported glyph type " + gl.getClass ().getCanonicalName ()); } // multiply the translations by units per em double[] matrix = g.getTransform (i); // transform the path path.transform (new AffineTransform (matrix)); // add it to the global path gp.append (path, false); } return gp; } /** add a point on the curve */ private void addOnCurvePoint (PointRec rec, RenderState rs) { // if the point is on the curve, either move to it, // or draw a line from the previous point if (rs.firstOn == null) { rs.firstOn = rec; rs.gp.moveTo (rec.x, rec.y); } else if (rs.prevOff != null) { rs.gp.quadTo (rs.prevOff.x, rs.prevOff.y, rec.x, rec.y); rs.prevOff = null; } else { rs.gp.lineTo (rec.x, rec.y); } } /** add a point off the curve */ private void addOffCurvePoint (PointRec rec, RenderState rs) { if (rs.prevOff != null) { PointRec oc = new PointRec ((rec.x + rs.prevOff.x) / 2, (rec.y + rs.prevOff.y) / 2, true); addOnCurvePoint (oc, rs); } else if (rs.firstOn == null) { rs.firstOff = rec; } rs.prevOff = rec; } class RenderState { // the shape itself GeneralPath gp; // the first off and on-curve points in the current segment PointRec firstOn; PointRec firstOff; // the previous off and on-curve points in the current segment PointRec prevOff; } /** a point on the stack of points */ class PointRec { int x; int y; boolean onCurve; public PointRec (int x, int y, boolean onCurve) { this.x = x; this.y = y; this.onCurve = onCurve; } public PointRec (GlyfSimple g, int idx) { x = g.getXCoord (idx); y = g.getYCoord (idx); onCurve = g.onCurve (idx); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/PDFFontEncoding.java0000644000175000017500000001662711145024767024337 0ustar twernertwerner/* * $Id: PDFFontEncoding.java,v 1.4 2009-02-12 13:53:54 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.sun.pdfview.PDFObject; /** * The PDFFont encoding encapsulates the mapping from character codes * in the PDF document to glyphs of the font. * * Encodings take two basic forms. For Type1, TrueType, and Type3 fonts, * the encoding maps from character codes to Strings, which represent the * glyphs of the font. For Type0 fonts, the mapping is a CMap which maps * character codes to characters in one of many descendant fonts. * * Note that the data in the PDF might be ASCII characters (bytes) or it might * be a multi-byte format such as unicode. For now we will assume all * glyph ids fit into at most the two bytes of a character. */ public class PDFFontEncoding { /** Encoding types */ private static final int TYPE_ENCODING = 0; private static final int TYPE_CMAP = 1; /** * the base encoding (an array of integers which can be mapped to names * using the methods on FontSupport */ private int[] baseEncoding; /** any differences from the base encoding */ private Map differences; /** * a CMap for fonts encoded by CMap */ private PDFCMap cmap; /** * the type of this encoding (encoding or CMap) */ private int type; /** Creates a new instance of PDFFontEncoding */ public PDFFontEncoding(String fontType, PDFObject encoding) throws IOException { if (encoding.getType() == PDFObject.NAME) { // if the encoding is a String, it is the name of an encoding // or the name of a CMap, depending on the type of the font if (fontType.equals("Type0")) { type = TYPE_CMAP; cmap = PDFCMap.getCMap(encoding.getStringValue()); } else { type = TYPE_ENCODING; differences = new HashMap(); baseEncoding = this.getBaseEncoding(encoding.getStringValue()); } } else { // loook at the "Type" entry of the encoding to determine the type String typeStr = encoding.getDictRef("Type").getStringValue(); if (typeStr.equals("Encoding")) { // it is an encoding type = TYPE_ENCODING; parseEncoding(encoding); } else if (typeStr.equals("CMap")) { // it is a CMap type = TYPE_CMAP; cmap = PDFCMap.getCMap(encoding); } else { throw new IllegalArgumentException("Uknown encoding type: " + type); } } } /** Get the glyphs associated with a given String */ public List getGlyphs(PDFFont font, String text) { List outList = new ArrayList(text.length()); // go character by character through the text char[] arry = text.toCharArray(); for (int i = 0; i < arry.length; i++) { switch (type) { case TYPE_ENCODING: outList.add(getGlyphFromEncoding(font, arry[i])); break; case TYPE_CMAP: // 2 bytes -> 1 character in a CMap char c = (char) ((arry[i] & 0xff) << 8); if (i < arry.length - 1) { c |= (char) (arry[++i] & 0xff); } outList.add(getGlyphFromCMap(font, c)); break; } } return outList; } /** * Get a glyph from an encoding, given a font and character */ private PDFGlyph getGlyphFromEncoding(PDFFont font, char src) { String charName = null; // only deal with one byte of source src &= 0xff; // see if this character is in the differences list if (differences.containsKey(new Character(src))) { charName = (String) differences.get(new Character(src)); } else if (baseEncoding != null) { // get the character name from the base encoding int charID = baseEncoding[src]; charName = FontSupport.getName(charID); } return font.getCachedGlyph(src, charName); } /** * Get a glyph from a CMap, given a Type0 font and a character */ private PDFGlyph getGlyphFromCMap(PDFFont font, char src) { int fontID = cmap.getFontID(src); char charID = cmap.map(src); if (font instanceof Type0Font) { font = ((Type0Font) font).getDescendantFont(fontID); } return font.getCachedGlyph(charID, null); } /** * Parse a PDF encoding object for the actual encoding */ public void parseEncoding(PDFObject encoding) throws IOException { differences = new HashMap(); // figure out the base encoding, if one exists PDFObject baseEncObj = encoding.getDictRef("BaseEncoding"); if (baseEncObj != null) { baseEncoding = getBaseEncoding(baseEncObj.getStringValue()); } // parse the differences array PDFObject diffArrayObj = encoding.getDictRef("Differences"); if (diffArrayObj != null) { PDFObject[] diffArray = diffArrayObj.getArray(); int curPosition = -1; for (int i = 0; i < diffArray.length; i++) { if (diffArray[i].getType() == PDFObject.NUMBER) { curPosition = diffArray[i].getIntValue(); } else if (diffArray[i].getType() == PDFObject.NAME) { Character key = new Character((char) curPosition); differences.put(key, diffArray[i].getStringValue()); curPosition++; } else { throw new IllegalArgumentException("Unexpected type in diff array: " + diffArray[i]); } } } } /** Get the base encoding for a given name */ private int[] getBaseEncoding(String encodingName) { if (encodingName.equals("MacRomanEncoding")) { return FontSupport.macRomanEncoding; } else if (encodingName.equals("MacExpertEncoding")) { return FontSupport.type1CExpertCharset; } else if (encodingName.equals("WinAnsiEncoding")) { return FontSupport.winAnsiEncoding; } else { throw new IllegalArgumentException("Unknown encoding: " + encodingName); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/font/OutlineFont.java0000644000175000017500000001157011144055133023654 0ustar twernertwerner/* * $Id: OutlineFont.java,v 1.3 2009-02-09 16:29:58 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.io.IOException; import com.sun.pdfview.PDFObject; /** * Supports width operations for Type1, Type1C, TrueType and Type3 fonts */ public abstract class OutlineFont extends PDFFont { /** the first character code */ private int firstChar = -1; /** the last character code */ private int lastChar = -1; /** the widths for each character code */ private float[] widths; /** Creates a new instance of OutlineFont */ public OutlineFont(String baseFont, PDFObject fontObj, PDFFontDescriptor descriptor) throws IOException { super(baseFont, descriptor); PDFObject firstCharObj = fontObj.getDictRef("FirstChar"); PDFObject lastCharObj = fontObj.getDictRef("LastChar"); PDFObject widthArrayObj = fontObj.getDictRef("Widths"); if (firstCharObj != null) { firstChar = firstCharObj.getIntValue(); } if (lastCharObj != null) { lastChar = lastCharObj.getIntValue(); } if (widthArrayObj != null) { PDFObject[] widthArray = widthArrayObj.getArray(); widths = new float[widthArray.length]; for (int i = 0; i < widthArray.length; i++) { widths[i] = widthArray[i].getFloatValue() / getDefaultWidth(); } } } /** Get the first character code */ public int getFirstChar() { return firstChar; } /** Get the last character code */ public int getLastChar() { return lastChar; } /** Get the default width in text space */ public int getDefaultWidth() { return 1000; } /** Get the number of characters */ public int getCharCount() { return (getLastChar() - getFirstChar()) + 1; } /** Get the width of a given character */ public float getWidth(char code, String name) { int idx = (code & 0xff) - getFirstChar(); // make sure we're in range if (idx < 0 || widths == null || idx >= widths.length) { // try to get the missing width from the font descriptor if (getDescriptor() != null) { return getDescriptor().getMissingWidth(); } else { return 0; } } return widths[idx]; } /** * Get the glyph for a given character code and name * * The preferred method of getting the glyph should be by name. If the * name is null or not valid, then the character code should be used. * If the both the code and the name are invalid, the undefined glyph * should be returned. * * Note this method must *always* return a glyph. * * @param src the character code of this glyph * @param name the name of this glyph or null if unknown * @return a glyph for this character */ protected PDFGlyph getGlyph(char src, String name) { GeneralPath outline = null; float width = getWidth(src, name); // first try by name if (name != null) { outline = getOutline(name, width); } // now try by character code (guaranteed to return) if (outline == null) { outline = getOutline(src, width); } // calculate the advance Point2D.Float advance = new Point2D.Float(width, 0); return new PDFGlyph(src, name, outline, advance); } /** * Get a glyph outline by name * * @param name the name of the desired glyph * @return the glyph outline, or null if unavailable */ protected abstract GeneralPath getOutline(String name, float width); /** * Get a glyph outline by character code * * Note this method must always return an outline * * @param src the character code of the desired glyph * @return the glyph outline */ protected abstract GeneralPath getOutline(char src, float width); } pdfrenderer-0.9.0/src/com/sun/pdfview/font/Type1CFont.java0000644000175000017500000012140111155166333023344 0ustar twernertwerner/* * $Id: Type1CFont.java,v 1.3 2009-03-09 10:18:03 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.font; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.io.IOException; import com.sun.pdfview.PDFObject; /** * A representation, with parser, of an Adobe Type 1C font. * @author Mike Wessler */ public class Type1CFont extends OutlineFont { String chr2name[] = new String[256]; byte[] data; int pos; byte[] subrs; float[] stack = new float[100]; int stackptr = 0; String names[]; int glyphnames[]; int encoding[] = new int[256]; String fontname; AffineTransform at = new AffineTransform (0.001f, 0, 0, 0.001f, 0, 0); int num; float fnum; int type; static int CMD = 0; static int NUM = 1; static int FLT = 2; /** * create a new Type1CFont based on a font data stream and a descriptor * @param baseFont the postscript name of this font * @param src a stream containing the font * @param descriptor the descriptor for this font */ public Type1CFont (String baseFont, PDFObject src, PDFFontDescriptor descriptor) throws IOException { super (baseFont, src, descriptor); PDFObject dataObj = descriptor.getFontFile3 (); data = dataObj.getStream (); pos = 0; parse (); // TODO: free up (set to null) unused structures (data, subrs, stack) } /** * a debug method for printing the data */ private void printData () { char[] parts = new char[17]; int partsloc = 0; for (int i = 0; i < data.length; i++) { int d = ((int) data[i]) & 0xff; if (d == 0) { parts[partsloc++] = '.'; } else if (d < 32 || d >= 127) { parts[partsloc++] = '?'; } else { parts[partsloc++] = (char) d; } if (d < 16) { System.out.print ("0" + Integer.toHexString (d)); } else { System.out.print (Integer.toHexString (d)); } if ((i & 15) == 15) { System.out.println (" " + new String (parts)); partsloc = 0; } else if ((i & 7) == 7) { System.out.print (" "); parts[partsloc++] = ' '; } else if ((i & 1) == 1) { System.out.print (" "); } } System.out.println (); } /** * read the next decoded value from the stream * @param charstring ???? */ private int readNext (boolean charstring) { num = (int) (data[pos++]) & 0xff; if (num == 30 && !charstring) { // goofy floatingpoint rep readFNum (); return type = FLT; } else if (num == 28) { num = (((int) data[pos]) << 8) + (((int) data[pos + 1]) & 0xff); pos += 2; return type = NUM; } else if (num == 29 && !charstring) { num = (((int) data[pos] & 0xff) << 24) | (((int) data[pos + 1] & 0xff) << 16) | (((int) data[pos + 2] & 0xff) << 8) | (((int) data[pos + 3] & 0xff)); pos += 4; return type = NUM; } else if (num == 12) { // two-byte command num = 1000 + ((int) (data[pos++]) & 0xff); return type = CMD; } else if (num < 32) { return type = CMD; } else if (num < 247) { num -= 139; return type = NUM; } else if (num < 251) { num = (num - 247) * 256 + (((int) data[pos++]) & 0xff) + 108; return type = NUM; } else if (num < 255) { num = -(num - 251) * 256 - (((int) data[pos++]) & 0xff) - 108; return type = NUM; } else if (!charstring) { // dict shouldn't have a 255 code printData (); throw new RuntimeException ("Got a 255 code while reading dict"); } else { // num was 255 fnum = ((((int) data[pos] & 0xff) << 24) | (((int) data[pos + 1] & 0xff) << 16) | (((int) data[pos + 2] & 0xff) << 8) | (((int) data[pos + 3] & 0xff))) / 65536f; pos += 4; return type = FLT; } } /** * read the next funky floating point number from the input stream. * value gets put into the fnum field. */ public void readFNum () { // work in nybbles: 0-9=0-9, a=. b=E, c=E-, d=rsvd e=neg f=end float f = 0; boolean neg = false; int exp = 0; int eval = 0; float mul = 1; byte work = data[pos++]; while (true) { if (work == (byte) 0xdd) { work = data[pos++]; } int nyb = (work >> 4) & 0xf; work = (byte) ((work << 4) | 0xd); if (nyb < 10) { if (exp != 0) { // working on the exponent eval = eval * 10 + nyb; } else if (mul == 1) { // working on an int f = f * 10 + nyb; } else { // working on decimal part f += nyb * mul; mul /= 10f; } } else if (nyb == 0xa) { // decimal mul = 0.1f; } else if (nyb == 0xb) { // E+ exp = 1; } else if (nyb == 0xc) { // E- exp = -1; } else if (nyb == 0xe) { // neg neg = true; } else { break; } } fnum = (neg ? -1 : 1) * f * (float) Math.pow (10, eval * exp); } /** * read an integer from the input stream * @param len the number of bytes in the integer * @return the integer */ private int readInt (int len) { int n = 0; for (int i = 0; i < len; i++) { n = (n << 8) | (((int) data[pos++]) & 0xff); } return n; } /** * read the next byte from the stream * @return the byte */ private int readByte () { return ((int) data[pos++]) & 0xff; } // DICT structure: // operand operator operand operator ... // INDEX structure: // count(2) offsize [offset offset ... offset] data // offset array has count+1 entries // data starts at 3+(count+1)*offsize // offset for data is offset+2+(count+1)*offsize /** * get the size of the dictionary located within the stream at * some offset. * @param loc the index of the start of the dictionary * @return the size of the dictionary, in bytes. */ public int getIndexSize (int loc) { // System.out.println("Getting size of index at "+loc); int hold = pos; pos = loc; int count = readInt (2); if (count <= 0) { return 2; } int encsz = readByte (); if (encsz < 1 || encsz > 4) { throw new RuntimeException ("Offsize: " + encsz + ", must be in range 1-4."); } // pos is now at the first offset. last offset is at count*encsz pos += count * encsz; int end = readInt (encsz); pos = hold; return 2 + (count + 1) * encsz + end; } /** * return the number of entries in an Index table. * * @param loc * @return */ public int getTableLength (int loc) { int hold = pos; pos = loc; int count = readInt (2); if (count <= 0) { return 2; } pos = hold; return count; } /** * A range. There's probably a version of this class floating around * somewhere already in Java. */ class Range { private int start; private int len; public Range (int start, int len) { this.start = start; this.len = len; } public final int getStart () { return start; } public final int getLen () { return len; } public final int getEnd () { return start + len; } public String toString () { return "Range: start: " + start + ", len: " + len; } } /** * Get the range of a particular index in a dictionary. * @param index the start of the dictionary. * @param id the index of the entry in the dictionary * @return a range describing the offsets of the start and end of * the entry from the start of the file, not the dictionary */ Range getIndexEntry (int index, int id) { int hold = pos; pos = index; int count = readInt (2); int encsz = readByte (); if (encsz < 1 || encsz > 4) { throw new RuntimeException ("Offsize: " + encsz + ", must be in range 1-4."); } pos += encsz * id; int from = readInt (encsz); Range r = new Range (from + 2 + index + encsz * (count + 1), readInt ( encsz) - from); pos = hold; return r; } // Top DICT: NAME CODE DEFAULT // charstringtype 12 6 2 // fontmatrix 12 7 0.001 0 0 0.001 // charset 15 - (offset) names of glyphs (ref to name idx) // encoding 16 - (offset) array of codes // CharStrings 17 - (offset) // Private 18 - (size, offset) // glyph at position i in CharStrings has name charset[i] // and code encoding[i] int charstringtype = 2; float temps[] = new float[32]; int charsetbase = 0; int encodingbase = 0; int charstringbase = 0; int privatebase = 0; int privatesize = 0; int gsubrbase = 0; int lsubrbase = 0; int gsubrsoffset = 0; int lsubrsoffset = 0; int nglyphs = 1; /** * read a dictionary that exists within some range, parsing the entries * within the dictionary. */ private void readDict (Range r) { // System.out.println("reading dictionary from "+r.getStart()+" to "+r.getEnd()); pos = r.getStart (); while (pos < r.getEnd ()) { int cmd = readCommand (false); if (cmd == 1006) { // charstringtype, default=2 charstringtype = (int) stack[0]; } else if (cmd == 1007) { // fontmatrix if (stackptr == 4) { at = new AffineTransform ((float) stack[0], (float) stack[1], (float) stack[2], (float) stack[3], 0, 0); } else { at = new AffineTransform ((float) stack[0], (float) stack[1], (float) stack[2], (float) stack[3], (float) stack[4], (float) stack[5]); } } else if (cmd == 15) { // charset charsetbase = (int) stack[0]; } else if (cmd == 16) { // encoding encodingbase = (int) stack[0]; } else if (cmd == 17) { // charstrings charstringbase = (int) stack[0]; } else if (cmd == 18) { // private privatesize = (int) stack[0]; privatebase = (int) stack[1]; } else if (cmd == 19) { // subrs (in Private dict) lsubrbase = privatebase + (int) stack[0]; lsubrsoffset = calcoffset (lsubrbase); } stackptr = 0; } } /** * read a complete command. this may involve several numbers * which go onto a stack before an actual command is read. * @param charstring ???? * @return the command. Some numbers may also be on the stack. */ private int readCommand (boolean charstring) { while (true) { int t = readNext (charstring); if (t == CMD) { /* System.out.print("CMD= "+num+", args="); for (int i=0; i" where ## is the value of the byte. */ private String safe (String src) { StringBuffer sb = new StringBuffer (); for (int i = 0; i < src.length (); i++) { char c = src.charAt (i); if (c >= 32 && c < 128) { sb.append (c); } else { sb.append ("<" + (int) c + ">"); } } return sb.toString (); } /** * Read the data for a glyph from the glyph table, and transform * it based on the current transform. * * @param base the start of the glyph table * @param offset the index of this glyph in the glyph table */ private synchronized GeneralPath readGlyph (int base, int offset) { FlPoint pt = new FlPoint (); // find this entry Range r = getIndexEntry (base, offset); // create a path GeneralPath gp = new GeneralPath (); // rember the start position (for recursive calls due to seac) int hold = pos; // read the glyph itself stackptr = 0; parseGlyph (r, gp, pt); // restore the start position pos = hold; gp.transform (at); return gp; } /** * calculate an offset code for a dictionary. Uses the count of entries * to determine what the offset should be. * * @param base the index of the start of the dictionary */ public int calcoffset (int base) { int len = getTableLength (base); if (len < 1240) { return 107; } else if (len < 33900) { return 1131; } else { return 32768; } } /** * get the name associated with an ID. * @param id the index of the name * @return the name from the FontSupport.stdNames table augmented * by the local name table */ public String getSID (int id) { if (id < FontSupport.stdNames.length) { return FontSupport.stdNames[id]; } else { id -= FontSupport.stdNames.length; return names[id]; } } /** * build an accented character out of two pre-defined glyphs. * @param x the x offset of the accent * @param y the y offset of the accent * @param b the index of the base glyph * @param a the index of the accent glyph * @param gp the GeneralPath into which the combined glyph will be * written. */ private void buildAccentChar (float x, float y, char b, char a, GeneralPath gp) { // get the outline of the accent GeneralPath pathA = getOutline (a, getWidth (a, null)); // undo the effect of the transform applied in read AffineTransform xformA = AffineTransform.getTranslateInstance (x, y); try { xformA.concatenate (at.createInverse ()); } catch (NoninvertibleTransformException nte) { // oh well ... } pathA.transform (xformA); GeneralPath pathB = getOutline (b, getWidth (b, null)); try { AffineTransform xformB = at.createInverse (); pathB.transform (xformB); } catch (NoninvertibleTransformException nte) { // ignore } gp.append (pathB, false); gp.append (pathA, false); } /** * parse a glyph defined in a particular range * @param r the range of the glyph definition * @param gp a GeneralPath in which to store the glyph outline * @param pt a FlPoint representing the end of the current path */ void parseGlyph (Range r, GeneralPath gp, FlPoint pt) { pos = r.getStart (); int i; float x1, y1, x2, y2, x3, y3, ybase; int hold; int stemhints = 0; while (pos < r.getEnd ()) { int cmd = readCommand (true); hold = 0; switch (cmd) { case 1: // hstem case 3: // vstem stackptr = 0; break; case 4: // vmoveto if (stackptr > 1) { // this is the first call, arg1 is width stack[0] = stack[1]; } pt.y += stack[0]; if (pt.open) { gp.closePath (); } pt.open = false; gp.moveTo (pt.x, pt.y); stackptr = 0; break; case 5: // rlineto for (i = 0; i < stackptr;) { pt.x += stack[i++]; pt.y += stack[i++]; gp.lineTo (pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 6: // hlineto for (i = 0; i < stackptr;) { if ((i & 1) == 0) { pt.x += stack[i++]; } else { pt.y += stack[i++]; } gp.lineTo (pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 7: // vlineto for (i = 0; i < stackptr;) { if ((i & 1) == 0) { pt.y += stack[i++]; } else { pt.x += stack[i++]; } gp.lineTo (pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 8: // rrcurveto for (i = 0; i < stackptr;) { x1 = pt.x + stack[i++]; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2 + stack[i++]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 10: // callsubr hold = pos; i = (int) stack[--stackptr] + lsubrsoffset; Range lsubr = getIndexEntry (lsubrbase, i); parseGlyph (lsubr, gp, pt); pos = hold; break; case 11: // return return; case 14: // endchar // width x y achar bchar endchar == x y achar bchar seac if (stackptr == 5) { buildAccentChar (stack[1], stack[2], (char) stack[3], (char) stack[4], gp); } if (pt.open) { gp.closePath (); } pt.open = false; stackptr = 0; break; case 18: // hstemhm stemhints += stackptr / 2; stackptr = 0; break; case 19: // hintmask case 20: // cntrmask stemhints += stackptr / 2; pos += (stemhints - 1) / 8 + 1; stackptr = 0; break; case 21: // rmoveto if (stackptr > 2) { stack[0] = stack[1]; stack[1] = stack[2]; } pt.x += stack[0]; pt.y += stack[1]; if (pt.open) { gp.closePath (); } gp.moveTo (pt.x, pt.y); pt.open = false; stackptr = 0; break; case 22: // hmoveto if (stackptr > 1) { stack[0] = stack[1]; } pt.x += stack[0]; if (pt.open) { gp.closePath (); } gp.moveTo (pt.x, pt.y); pt.open = false; stackptr = 0; break; case 23: // vstemhm stemhints += stackptr / 2; stackptr = 0; break; case 24: // rcurveline for (i = 0; i < stackptr - 2;) { x1 = pt.x + stack[i++]; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2 + stack[i++]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); } pt.x += stack[i++]; pt.y += stack[i++]; gp.lineTo (pt.x, pt.y); pt.open = true; stackptr = 0; break; case 25: // rlinecurve for (i = 0; i < stackptr - 6;) { pt.x += stack[i++]; pt.y += stack[i++]; gp.lineTo (pt.x, pt.y); } x1 = pt.x + stack[i++]; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2 + stack[i++]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 26: // vvcurveto i = 0; if ((stackptr & 1) == 1) { // odd number of arguments pt.x += stack[i++]; } while (i < stackptr) { x1 = pt.x; y1 = pt.y + stack[i++]; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2; pt.y = y2 + stack[i++]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 27: // hhcurveto i = 0; if ((stackptr & 1) == 1) { // odd number of arguments pt.y += stack[i++]; } while (i < stackptr) { x1 = pt.x + stack[i++]; y1 = pt.y; x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + stack[i++]; pt.y = y2; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 29: // callgsubr hold = pos; i = (int) stack[--stackptr] + gsubrsoffset; Range gsubr = getIndexEntry (gsubrbase, i); parseGlyph (gsubr, gp, pt); pos = hold; break; case 30: // vhcurveto hold = 4; case 31: // hvcurveto for (i = 0; i < stackptr;) { boolean hv = (((i + hold) & 4) == 0); x1 = pt.x + (hv ? stack[i++] : 0); y1 = pt.y + (hv ? 0 : stack[i++]); x2 = x1 + stack[i++]; y2 = y1 + stack[i++]; pt.x = x2 + (hv ? 0 : stack[i++]); pt.y = y2 + (hv ? stack[i++] : 0); if (i == stackptr - 1) { if (hv) { pt.x += stack[i++]; } else { pt.y += stack[i++]; } } gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); } pt.open = true; stackptr = 0; break; case 1000: // old dotsection command. ignore. stackptr = 0; break; case 1003: // and x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = ((x1 != 0) && (y1 != 0)) ? 1 : 0; break; case 1004: // or x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = ((x1 != 0) || (y1 != 0)) ? 1 : 0; break; case 1005: // not x1 = stack[--stackptr]; stack[stackptr++] = (x1 == 0) ? 1 : 0; break; case 1009: // abs stack[stackptr - 1] = Math.abs (stack[stackptr - 1]); break; case 1010: // add x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = x1 + y1; break; case 1011: // sub x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = y1 - x1; break; case 1012: // div x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = y1 / x1; break; case 1014: // neg stack[stackptr - 1] = -stack[stackptr - 1]; break; case 1015: // eq x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = (x1 == y1) ? 1 : 0; break; case 1018: // drop stackptr--; break; case 1020: // put i = (int) stack[--stackptr]; x1 = stack[--stackptr]; temps[i] = x1; break; case 1021: // get i = (int) stack[--stackptr]; stack[stackptr++] = temps[i]; break; case 1022: // ifelse if (stack[stackptr - 2] > stack[stackptr - 1]) { stack[stackptr - 4] = stack[stackptr - 3]; } stackptr -= 3; break; case 1023: // random stack[stackptr++] = (float) Math.random (); break; case 1024: // mul x1 = stack[--stackptr]; y1 = stack[--stackptr]; stack[stackptr++] = y1 * x1; break; case 1026: // sqrt stack[stackptr - 1] = (float) Math.sqrt (stack[stackptr - 1]); break; case 1027: // dup x1 = stack[stackptr - 1]; stack[stackptr++] = x1; break; case 1028: // exch x1 = stack[stackptr - 1]; stack[stackptr - 1] = stack[stackptr - 2]; stack[stackptr - 2] = x1; break; case 1029: // index i = (int) stack[stackptr - 1]; if (i < 0) { i = 0; } stack[stackptr - 1] = stack[stackptr - 2 - i]; break; case 1030: // roll i = (int) stack[--stackptr]; int n = (int) stack[--stackptr]; // roll n number by i (+ = upward) if (i > 0) { i = i % n; } else { i = n - (-i % n); } // x x x x i y y y -> y y y x x x x i (where i=3) if (i > 0) { float roll[] = new float[n]; System.arraycopy (stack, stackptr - 1 - i, roll, 0, i); System.arraycopy (stack, stackptr - 1 - n, roll, i, n - i); System.arraycopy (roll, 0, stack, stackptr - 1 - n, n); } break; case 1034: // hflex x1 = pt.x + stack[0]; y1 = ybase = pt.y; x2 = x1 + stack[1]; y2 = y1 + stack[2]; pt.x = x2 + stack[3]; pt.y = y2; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[4]; y1 = pt.y; x2 = x1 + stack[5]; y2 = ybase; pt.x = x2 + stack[6]; pt.y = y2; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 1035: // flex x1 = pt.x + stack[0]; y1 = pt.y + stack[1]; x2 = x1 + stack[2]; y2 = y1 + stack[3]; pt.x = x2 + stack[4]; pt.y = y2 + stack[5]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[6]; y1 = pt.y + stack[7]; x2 = x1 + stack[8]; y2 = y1 + stack[9]; pt.x = x2 + stack[10]; pt.y = y2 + stack[11]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 1036: // hflex1 ybase = pt.y; x1 = pt.x + stack[0]; y1 = pt.y + stack[1]; x2 = x1 + stack[2]; y2 = y1 + stack[3]; pt.x = x2 + stack[4]; pt.y = y2; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[5]; y1 = pt.y; x2 = x1 + stack[6]; y2 = y1 + stack[7]; pt.x = x2 + stack[8]; pt.y = ybase; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; case 1037: // flex1 ybase = pt.y; float xbase = pt.x; x1 = pt.x + stack[0]; y1 = pt.y + stack[1]; x2 = x1 + stack[2]; y2 = y1 + stack[3]; pt.x = x2 + stack[4]; pt.y = y2 + stack[5]; gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); x1 = pt.x + stack[6]; y1 = pt.y + stack[7]; x2 = x1 + stack[8]; y2 = y1 + stack[9]; if (Math.abs (x2 - xbase) > Math.abs (y2 - ybase)) { pt.x = x2 + stack[10]; pt.y = ybase; } else { pt.x = xbase; pt.y = y2 + stack[10]; } gp.curveTo (x1, y1, x2, y2, pt.x, pt.y); pt.open = true; stackptr = 0; break; default: System.out.println ("ERROR! TYPE1C CHARSTRING CMD IS " + cmd); break; } } } /** * Get a glyph outline by name * * @param name the name of the desired glyph * @return the glyph outline, or null if unavailable */ protected GeneralPath getOutline (String name, float width) { // first find the index of this name int index = getNameIndex (name); // now find the glyph with that name for (int i = 0; i < glyphnames.length; i++) { if (glyphnames[i] == index) { return readGlyph (charstringbase, i); } } // not found -- return the unknown glyph return readGlyph (charstringbase, 0); } /** * Get a glyph outline by character code * * Note this method must always return an outline * * @param src the character code of the desired glyph * @return the glyph outline */ protected GeneralPath getOutline (char src, float width) { // ignore high bits int index = (int) (src & 0xff); // if we use a standard encoding, the mapping is from glyph to SID // therefore we must find the glyph index in the name table if (encodingbase == 0 || encodingbase == 1) { for (int i = 0; i < glyphnames.length; i++) { if (glyphnames[i] == encoding[index]) { return readGlyph (charstringbase, i); } } } else { // for a custom encoding, the mapping is from glyph to GID, so // we can just map the glyph directly if (index > 0 && index < encoding.length) { return readGlyph (charstringbase, encoding[index]); } } // for some reason the glyph was not found, return the empty glyph return readGlyph (charstringbase, 0); } } pdfrenderer-0.9.0/src/com/sun/pdfview/RefImage.java0000644000175000017500000000356311134132451022120 0ustar twernertwerner/* * $Id: RefImage.java,v 1.3 2009-01-16 16:26:10 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.Graphics2D; import java.awt.image.BufferedImage; /** * A BufferedImage subclass that holds a strong reference to its graphics * object. This means that the graphics will never go away as long as * someone holds a reference to this image, and createGraphics() and * getGraphics() can be called multiple times safely, and will always return * the same graphics object. */ public class RefImage extends BufferedImage { /** a strong reference to the graphics object */ private Graphics2D g; /** Creates a new instance of RefImage */ public RefImage(int width, int height, int type) { super(width, height, type); } /** * Create a graphics object only if it is currently null, otherwise * return the existing graphics object. */ public Graphics2D createGraphics() { if (g == null) { g = super.createGraphics(); } return g; } } pdfrenderer-0.9.0/src/com/sun/pdfview/function/0000755000175000017500000000000011622545441021425 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/function/FunctionType2.java0000644000175000017500000001006210732532577025007 0ustar twernertwerner/* * $Id: FunctionType2.java,v 1.2 2007-12-20 18:33:34 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.function; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * A type 2 function is an exponential interpolation function, which maps * from one input value to n output values using a simple exponential * formula. */ public class FunctionType2 extends PDFFunction { /** the function's value at zero for the n outputs */ private float[] c0 = new float[] { 0f }; /** the function's value at one for the n outputs */ private float[] c1 = new float[] { 1f }; /** the exponent */ private float n; /** Creates a new instance of FunctionType2 */ public FunctionType2() { super(TYPE_2); } /** * Read the zeros, ones and exponent */ protected void parse(PDFObject obj) throws IOException { // read the exponent (required) PDFObject nObj = obj.getDictRef("N"); if (nObj == null) { throw new PDFParseException("Exponent required for function type 2!"); } setN(nObj.getFloatValue()); // read the zeros array (optional) PDFObject cZeroObj = obj.getDictRef("C0"); if (cZeroObj != null) { PDFObject[] cZeroAry = cZeroObj.getArray(); float[] cZero = new float[cZeroAry.length]; for (int i = 0; i < cZeroAry.length; i++) { cZero[i] = cZeroAry[i].getFloatValue(); } setC0(cZero); } // read the ones array (optional) PDFObject cOneObj = obj.getDictRef("C1"); if (cOneObj != null) { PDFObject[] cOneAry = cOneObj.getArray(); float[] cOne = new float[cOneAry.length]; for (int i = 0; i < cOneAry.length; i++) { cOne[i] = cOneAry[i].getFloatValue(); } setC1(cOne); } } /** * Calculate the function value for the input. For each output (j), * the function value is: * C0(j) + x^N * (C1(j) - C0(j)) */ protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { // read the input value float input = inputs[inputOffset]; // calculate the output values for (int i = 0; i < getNumOutputs(); i++) { outputs[i + outputOffset] = getC0(i) + (float) (Math.pow(input, getN()) * (getC1(i) - getC0(i))); } } /** * Get the exponent */ public float getN() { return n; } /** * Set the exponent */ protected void setN(float n) { this.n = n; } /** * Get the values at zero */ public float getC0(int index) { return c0[index]; } /** * Set the values at zero */ protected void setC0(float[] c0) { this.c0 = c0; } /** * Get the values at one */ public float getC1(int index) { return c1[index]; } /** * Set the values at one */ protected void setC1(float[] c1) { this.c1 = c1; } } pdfrenderer-0.9.0/src/com/sun/pdfview/function/FunctionType4.java0000644000175000017500000011333411145024767025013 0ustar twernertwerner/* * $Id: FunctionType4.java,v 1.3 2009-02-12 13:53:59 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.function; import java.io.IOException; import java.nio.ByteBuffer; import java.util.*; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** *

    A PostScript function is represented as a stream containing code * written in a small subset of the PostScript language. * This reference is taken from the (3200-1:2008:7.10.5)

    * * http://www.adobe.com/devnet/acrobat/pdfs/adobe_supplement_iso32000.pdf *

    */ public class FunctionType4 extends PDFFunction { /** the set of all Operations we support. These operations are defined * in Appendix B - Operators.*/ private static HashSet operationSet = null; /** the list of tokens and sub-expressions. */ private LinkedList tokens = new LinkedList(); /** the stack of operations. The stack contents should all be Comparable. */ private LinkedList stack = new LinkedList(); /** Creates a new instance of FunctionType4 */ protected FunctionType4() { super(TYPE_4); if (operationSet == null) { initOperations(); } } /** * Initialize the operations that we can perform. */ private void initOperations() { /** these operators consider the left hand arguments as deeper in * the stack than the right hand arguments, thus the right-hand is * is the top of the stack and is popped first. * * Operation details in PostScript Language Reference Manual: * http://www.adobe.com/products/postscript/pdfs/PLRM.pdf * Chapter 8 - Operator Details */ if (operationSet == null) { operationSet = new HashSet(); // Arithmetic Operators operationSet.add(new Operation("abs") { /** * num1 abs num2

    * * The type of the result is the same as the type of num1, * unless num1 is the smallest (most negative) integer, * in which case the result is a real number.

    * * errors: stackunderflow, typecheck */ void eval() { pushDouble(Math.abs(popDouble())); } }); operationSet.add(new Operation("add") { /** * num1 num2 add sum

    * * If both operands are integers and the result is * within integer range, the result is an integer; * otherwise, the result is a real number.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { pushDouble(popDouble() + popDouble()); } }); operationSet.add(new Operation("atan") { /** * num den atan angle

    * * returns the angle (in degress between * 0 and 360) whose tangent is num divided by den. * Either num or den may be 0, but not both. The signs * of num and den determine the quadrant in which the * result will lie: positive num yeilds a result in the * positive y plane, while a positive den yeilds a result in * the positive x plane. The result is a real number.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { double den = popDouble(); double num = popDouble(); if (den == 0.0) { pushDouble(90.0); } else { pushDouble(Math.toDegrees(Math.atan(num / den))); } } }); operationSet.add(new Operation("ceiling") { /** * num1 ceiling num2

    * * returns the least integer value greater than or equal * to num1. The type of the result is the same as the type * of the operand.

    * * errors: stackunderflow, typecheck */ void eval() { pushDouble(Math.ceil(popDouble())); } }); operationSet.add(new Operation("cvi") { /** * num cvi int or string cvi int

    * * takes an integer, real, or string and produces an * integer result. If the operand is an integer, cvi * simply returns it. If the operand is a real number, * it truncates any fractional part (that is, rounds * it toward 0) and converts it to an integer. * If the operand is a string, cvi invokes the equivalent * of the token operator to interpret the characters * of the string as a number according to the PostScript * syntax rules. If that number is a real number, cvi converts * it to an integer. * A rangecheck error occurs if a real number is too * large to convert to an integer.

    * * errors: invalidaccess, rangecheck, stackunderflow, * syntaxError, typecheck, */ void eval() { pushDouble((double) ((int) popDouble())); } }); operationSet.add(new Operation("cvr") { /** * num cvr real or string cvr real

    * * (convert to real) takes an integer, real, or string * object and produces a real result. If the operand * is an integer, cvr converts it to a real number. * If the operand is a real number, cvr simply returns it. * If the operand is a string, cvr invokes the equivalent * of the token operator to interpret the characters of * the string as a number according to the PostScript * syntax rules. If that number is an integer, cvr converts * it to a real number.

    * * errors: invalidaccess, limitcheck, stackunderflow, * syntaxerror, typecheck, undefinedresult */ void eval() { // YOUR CODE IN THIS SPACE } }); operationSet.add(new Operation("div") { /** * num1 num2 div quotient

    * * divides num1 by num2, producing a result that is * always a real number even if both operands are integers. * Use idiv instead if the operands are integers and an * integer result is desired.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { double num2 = popDouble(); double num1 = popDouble(); pushDouble(num1 / num2); } }); operationSet.add(new Operation("exp") { /** * base exponent exp real

    * * raises base to the exponent power. The operands may be * either integers or real numbers. If the exponent has a * fractional part, the result is meaningful only if the * base is nonnegative. The result is always a real number.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { double exponent = popDouble(); double base = popDouble(); pushDouble(Math.pow(exponent, base)); } }); operationSet.add(new Operation("floor") { /** * num1 floor num2

    * * returns the greatest integer value less than or equal * to num1. The type of the result is the same as the type * of the operand.

    * * errors: stackunderflow, typecheck */ void eval() { pushDouble(Math.floor(popDouble())); } }); operationSet.add(new Operation("idiv") { /** * int1 int2 idiv quotient

    * * divides int1 by int2 and returns the integer part * of the quotient, with any fractional part discarded. * Both operands of idiv must be integers and the result * is an integer.

    * * stackunderflow, typecheck, undefinedresult */ void eval() { long int2 = popLong(); long int1 = popLong(); pushLong(int1 / int2); } }); operationSet.add(new Operation("ln") { /** * num ln real

    * * returns the natural logarithm (base e) of num. * The result is a real number.

    * * errors: rangecheck, stackunderflow, typecheck */ void eval() { pushDouble(Math.log(popDouble())); } }); operationSet.add(new Operation("log") { /** * num log real

    * * returns the common logarithm (base 10) of num. * The result is a real number.

    * * errors: rangecheck, stackunderflow, typecheck */ void eval() { pushDouble(Math.log10(popDouble())); } }); operationSet.add(new Operation("mod") { /** * int1 int2 mod remainder

    * * returns the remainder that results from * dividing int1 by int2. The sign of the result * is the same as the sign of the dividend int1. * Both operands must be integers and the result * is an integer.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { long int2 = popLong(); long int1 = popLong(); pushLong(int1 % int2); } }); operationSet.add(new Operation("mul") { /** * num1 num2 mul product

    * * returns the product of num1 and num2. * If both operands are integers and the result * is within integer range, the result is an integer; * otherwise, the result is a real number.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { pushDouble(popDouble() * popDouble()); } }); operationSet.add(new Operation("neg") { /** * num1 neg num2

    * * returns the negative of num1. The type of the result * is the same as the type of num1 unless num1 is the * smallest (most negative) integer, in which case the * result is a real number.

    * * errors: stackunderflow, typecheck */ void eval() { pushDouble(-popDouble()); } }); operationSet.add(new Operation("round") { /** * num1 round num2

    * * returns the integer value nearest to num1. * If num1 is equally close to its two nearest * integers, round returns the greater of the two. * The type of the result is the same as * the type of the operand.

    * * errors: stackunderflow, typecheck */ void eval() { pushLong(Math.round(popDouble())); } }); operationSet.add(new Operation("sin") { /** * angle sin real

    * * returns the sine of angle, which is interpreted as an * angle in degrees. The result is a real number.

    * * errors: stackunderflow, typecheck */ void eval() { double radians = Math.toRadians(popDouble()); pushDouble(Math.toDegrees(Math.sin(radians))); } }); operationSet.add(new Operation("sqrt") { /** * num sqrt real

    * * returns the square root of num, which must be a * nonnegative number. The result is a real number.

    * * errors: rangecheck, stackunderflow, typecheck */ void eval() { pushDouble(Math.sqrt(popDouble())); } }); operationSet.add(new Operation("sub") { /** * num1 num2 sub difference

    * * returns the result of subtracting num2 from num1. * If both operands are integers and the result is within * integer range, the result is an integer; otherwise, * the result is a real number.

    * * errors: stackunderflow, typecheck, undefinedresult */ void eval() { double num2 = popDouble(); double num1 = popDouble(); pushDouble(num1 - num2); } }); operationSet.add(new Operation("truncate") { /** * num1 truncate num2

    * * truncates num1 toward 0 by removing its fractional part. * The type of the result is the same as the type of the * operand.

    * * errors: stackunderflow, typecheck */ void eval() { double num1 = popDouble(); pushDouble(((double) ((long) num1) - num1)); } }); // Relational, boolean, and bitwise operators operationSet.add(new Operation("and") { /** * bool1|int1 bool2|int2 and bool3|int3

    * * returns the logical conjunction of the operands * if they are boolean. If the operands are integers, * and returns the bitwise "and" of their binary * representations.

    * * errors: stackunderflow, typecheck */ void eval() { pushLong(popLong() & popLong()); } }); operationSet.add(new Operation("bitshift") { /** * int1 shift bitshift int2

    * * shifts the binary representation of int1 left by * shift bits and returns the result. Bits shifted out * are lost; bits shifted in are 0. If shift is negative, * a right shift by –shift bits is performed. * This operation produces an arithmetically correct * result only for positive values of int1. * Both int1 and shift must be integers.

    * * errors: stackunderflow, typecheck */ void eval() { long shift = popLong(); long int1 = popLong(); pushLong(int1 << shift); } }); operationSet.add(new Operation("eq") { /** * any1 any2 eq bool

    * * pops two objects from the operand stack and pushes\ * true if they are equal, or false if not. * The definition of equality depends on the types of * the objects being compared. * Simple objects are equal if their types and values * are the same. Strings are equal if their lengths and * individual elements are equal. Other composite objects * (arrays and dictionaries) are equal only if they share * the same value. Separate values are considered unequal, * even if all the components of those values are the * same. * This operator performs some type conversions. * Integers and real numbers can be compared freely: * an integer and a real number representing the same * mathematical value are considered equal by eq. * Strings and names can likewise be compared freely: * a name defined by some sequence of characters is equal * to a string whose elements are the same sequence of * characters. * The literal/executable and access attributes of * objects are not considered in comparisons * between objects.

    * * errors: invalidaccess, stackunderflow */ void eval() { pushBoolean(popObject().equals(popObject())); } }); operationSet.add(new Operation("false") { /** * false false

    * * pushes a boolean object whose value is false on the * operand stack. false is not an operator; it is a name in * systemdict associated with the boolean value false.

    * * errors: stackoverflow */ void eval() { pushBoolean(false); } }); operationSet.add(new Operation("ge") { /** * num1 num2 ge bool

    * * pops two objects from the operand stack and pushes true * if the first operand is greater than or equal to the second, * or false otherwise. If both operands are numbers, * ge compares their mathematical values. If both operands * are strings, ge compares them element by element, treating * the elements as integers in the range 0 to 255, to determine * whether the first string is lexically greater than or equal * to the second. If the operands are of other types or one * is a string and the other is a number, a typecheck * error occurs.

    * * errors: invalidaccess, stackunderflow, typecheck */ void eval() { double num2 = popDouble(); double num1 = popDouble(); pushBoolean(num1 >= num2); } }); operationSet.add(new Operation("gt") { /** * num1 num2 gt bool

    * * pops two objects from the operand stack and pushes true * if the first operand is greater than the second, or * false otherwise. If both operands are numbers, gt compares * their mathematical values. If both operands are strings, * gt compares them element by element, treating the elements * as integers in the range 0 to 255, to determine whether * the first string is lexically greater than the second. * If the operands are of other types or one is a string * and the other is a number, a typecheck error occurs.

    * * errors: invalidaccess, stackunderflow, typecheck */ void eval() { double num2 = popDouble(); double num1 = popDouble(); pushBoolean(num1 > num2); } }); operationSet.add(new Operation("le") { /** * num1 num2 le bool

    * * pops two objects from the operand stack and pushes true * if the first operand is less than or equal to the second, * or false otherwise. If both operands are numbers, le * compares their mathematical values. If both operands are * strings, le compares them element by element, treating * the elements as integers in the range 0 to 255, * to determine whether the first string is lexically less * than or equal to the second. If the operands are of other * types or one is a string and the other is a number, a * typecheck error occurs.

    * * errors: invalidaccess, stackunderflow, typecheck */ void eval() { double num2 = popDouble(); double num1 = popDouble(); pushBoolean(num1 <= num2); } }); operationSet.add(new Operation("lt") { /** * num1 num2 lt bool

    * * pops two objects from the operand stack and pushes true * if the first operand is less than the second, or false * otherwise. If both operands are numbers, lt compares * their mathematical values. If both operands are strings, * lt compares them element by element, treating the elements * as integers in the range 0 to 255, to determine whether * the first string is lexically less than the second. * If the operands are of other types or one is a string * and the other is a number, a typecheck error occurs.

    * * errors: invalidaccess, stackunderflow, typecheck */ void eval() { double num2 = popDouble(); double num1 = popDouble(); pushBoolean(num1 < num2); } }); operationSet.add(new Operation("ne") { /** * any1 any2 ne bool

    * * pops two objects from the operand stack and pushes false * if they are equal, or true if not. What it means for objects * to be equal is presented in the description of the * eq operator.

    * * errors: invalidaccess, stackunderflow */ void eval() { pushBoolean(!popObject().equals(popObject())); } }); operationSet.add(new Operation("not") { /** * bool1|int1 not bool2|int2

    * * returns the logical negation of the operand if it is * boolean. If the operand is an integer, not returns the * bitwise complement (ones complement) of its binary * representation.

    * * errors: stackunderflow, typecheck */ void eval() { pushLong(~popLong()); } }); operationSet.add(new Operation("or") { /** * bool1|int1 bool2|int2 or bool3|int3

    * * returns the logical disjunction of the operands if they * are boolean. If the operands are integers, or returns * the bitwise "inclusive or" of their binary representations.

    * * errors: stackunderflow, typecheck */ void eval() { pushLong(popLong() | popLong()); } }); operationSet.add(new Operation("true") { /** * true true

    * * pushes a boolean object whose value is true on the operand * stack. true is not an operator; it is a name in systemdict * associated with the boolean value true.

    * * errors: stackoverflow */ void eval() { pushBoolean(true); } }); operationSet.add(new Operation("xor") { /** * bool1|int1 bool2|int2 xor bool3|int3

    * * returns the logical "exclusive or" of the operands if they * are boolean. If the operands are integers, xor returns the * bitwise "exclusive or" of their binary representations.

    * * errors: stackunderflow, typecheck */ void eval() { pushLong(popLong() ^ popLong()); } }); // Conditional Operators operationSet.add(new Operation("if") { /** * bool {proc} if -

    * * removes both operands from the stack, then executes proc * if bool is true. The if operator pushes no results of * its own on the operand stack, but proc may do so (see * Section 3.5, "Execution").

    * * Examples

    * 3 4 lt {(3 is less than 4)} if

    * * errors: stackunderflow, typecheck */ void eval() { if (popBoolean()) { stack.addFirst(popExpression()); } else { popExpression(); } } }); operationSet.add(new Operation("ifelse") { /** * bool {expr1} {expr2} ifelse -

    * * removes all three operands from the stack, then * executes proc1 if bool is true or proc2 if bool is false. * The ifelse operator pushes no results of its own on the * operand stack, but the procedure it executes may do so * (see Section 3.5, "Execution").

    * * Examples

    * 4 3 lt {(TruePart)} {(FalsePart)} ifelse
    * results in FalsePart, since 4 is not less than 3

    * * errors: stackunderflow, typecheck */ void eval() { // execute expr1 if bool is true, expr2 if false if (popBoolean()) { // expression.push(popExpression()); popExpression(); } else { popExpression(); // expression.push(popExpression()); } } }); // Stack Operators operationSet.add(new Operation("copy") { /** * any1 ... anyn n copy any1 ... anyn any1 ... anyn * array1 array2 copy subarray2
    * string1 string2 copy substring2

    * * performs two entirely different functions, depending on the * type of the topmost operand. * In the first form, where the top element on the operand * stack is a nonnegative integer n, copy pops n from the * stack and duplicates the top n elements on the stack * as shown above. This form of copy operates only on the * objects themselves, not on the values of composite objects.

    * * Examples
    * (a) (b) (c) 2 copy Þ (a) (b) (c) (b) (c)
    * (a) (b) (c) 0 copy Þ (a) (b) (c)

    * * In the other forms, copy copies all the elements of the * first composite object into the second. The composite * object operands must be of the same type, except that * a packed array can be copied into an array (and only into * an array—copy cannot copy into packed arrays, because * they are read-only). This form of copy copies the value of * a composite object. This is quite different from dup and * other operators that copy only the objects themselves * (see Section 3.3.1, "Simple and Composite Objects"). * However, copy performs only one level of copying. * It does not apply recursively to elements that are * themselves composite objects; instead, the values * of those elements become shared. In the case of arrays or * strings, the length of the second object must be at least as * great as the first; copy returns the initial subarray or * substring of the second operand into which the elements * were copied. Any remaining elements of array2 or * string2 are unaffected.

    * * Example:
    * /a1 [1 2 3] def
    * a1 dup length array copy Þ [1 2 3]

    * * errors: invalidaccess, rangecheck, stackoverflow, * stackunderflow, typecheck */ void eval() { long count = popLong(); // ???? Object obj = stack.removeFirst(); stack.addFirst(obj); stack.addFirst(obj); } }); operationSet.add(new Operation("dup") { /** * any dup any any

    * * duplicates the top element on the operand stack. * dup copies only the object; the value of a composite * object is not copied but is shared. * See Section 3.3, "Data Types and Objects."

    * * errors: stackoverflow, stackunderflow */ void eval() { Object obj = popObject(); pushObject(obj); pushObject(obj); } }); operationSet.add(new Operation("exch") { void eval() { // any1 any2 exch any2 any1 - exchange top of stack Object any1 = popObject(); Object any2 = popObject(); pushObject(any2); pushObject(any1); } }); operationSet.add(new Operation("index") { void eval() { // anyn ... any0 n index anyn ... any0 anyn Object obj = stack.removeFirst(); stack.addFirst(obj); stack.addFirst(obj); } }); operationSet.add(new Operation("pop") { void eval() { // discard top element stack.removeFirst(); } }); operationSet.add(new Operation("roll") { void eval() { // anyn-1 ... any0 n j roll any(j-1)mod n ... anyn-1 ... any // Roll n elements up j times Object obj = stack.removeFirst(); stack.addFirst(obj); stack.addFirst(obj); } }); } } /** Read the function information from a PDF Object */ protected void parse(PDFObject obj) throws IOException { // read the postscript from the stream readPS(obj.getStreamBuffer()); throw new PDFParseException("Unsupported function type 4."); } /** * Map from m input values to n output values. * The number of inputs m must be exactly one half the size of the * domain. The number of outputs should match one half the size of the * range. * * @param inputs an array of m input values * @param outputs an array of size n which will be filled * with the output values, or null to return a new array */ protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { } private boolean popBoolean() { return false; } private void pushBoolean(boolean arg) { } private double popDouble() { return 0; } private void pushDouble(double arg) { } private Expression popExpression() { return null; } private void pushExpression(Expression expresson) { } private long popLong() { return 0L; } private void pushLong(long arg) { } private Object popObject() { return stack.removeFirst(); } private void pushObject(Object obj) { stack.addFirst(obj); } /** *

    parse the postscript operators and aguments from the stream.

    * *

    Syntax is to read a set of tokens, including expressions and * to queue them as they come including other expressions. Expressions are * enclosed in curly brackets and constitute a reference to the * expression body.

    * * @param buf the stream of postscript tokens */ private void readPS(ByteBuffer buf) { } class Expression extends LinkedList { public boolean equals(Object obj) { if (obj instanceof Expression) { // actually validate the list contents are the same expressions return true; } return false; } } abstract class Operation { private String operatorName; public Operation(String operatorName) { if (operatorName == null) { throw new RuntimeException("Cannot have a null operator name"); } this.operatorName = operatorName; } public String getOperatorName() { return operatorName; } /** * evaluate the function, popping the stack as needed and pushing results. */ abstract void eval(); /** * return true if our operator is the same as the supplied one. * * @param obj * @return */ public boolean equals(Object obj) { if (obj instanceof Operation) { return ((Operation) obj).operatorName.equals(operatorName); } else if (obj instanceof String) { return operatorName.equals(obj); } return false; } } } pdfrenderer-0.9.0/src/com/sun/pdfview/function/FunctionType3.java0000644000175000017500000001666211405463631025014 0ustar twernertwerner/* * $Id: FunctionType3.java,v 1.3 2010-06-14 17:32:09 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.function; import java.io.IOException; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * 3.9.3 - A stitching function define a stitching of the subdomains of * several 1-input functions to produce a single new 1-input function. * Since the resulting stitching function is a 1-input function, the * domain is given by a two-element array, [ Domain0 Domain1 ]. * *
     * Example 4.25
     * 5 0 obj                          % Shading dictionary
     *  << /ShadingType 3
     *      /ColorSpace /DeviceCMYK
     *      /Coords [ 0.0 0.0 0.096 0.0 0.0 1.0 00]% Concentric circles
     *      /Function 10 0 R
     *      /Extend [ true true ]
     *  >>
     * endobj
     *
     * 10 0 obj                         % Color function
     *  << /FunctionType 3
     *      /Domain [ 0.0 1.0 ]
     *      /Functions [ 11 0 R 12 0 R ]
     *      /Bounds [ 0.708 ]
     *      /Encode [ 1.0 0.0 0.0 1.0 ]
     *  >>
     * endobj
     *
     * 11 0 obj                         % First subfunction
     *  << /FunctionType 2
     *      /Domain [ 0.0 1.0 ]
     *      /C0 [ 0.929 0.357 1.000 0.298 ]
     *      /C1 [ 0.631 0.278 1.000 0.027 ]
     *      /N 1.048
     *  >>
     * endobj
     *
     * 12 0 obj                         % Second subfunction
     *  << /FunctionType 2
     *      /Domain [ 0.0 1.0 ]
     *      /C0 [ 0.929 0.357 1.000 0.298 ]
     *      /C1 [ 0.941 0.400 1.000 0.102 ]
     *      /N 1.374
     *  >>
     * endobj
     * 
    */ public class FunctionType3 extends PDFFunction { private PDFFunction[] functions; private float[] bounds; private float[] encode; /** Creates a new instance of FunctionType3 */ protected FunctionType3() { super(TYPE_3); } /** *

    Read the function information from a PDF Object.

    *

    Required entries ( Table 3.38) (3200-1:2008:7.10.4, table: 41) * are:

  • * * Functions array (Required) An array of k 1-input functions making up * the stitching function. The output dimensionality of all functions * must be the same, and compatible with the value of Range * if Range is present.
  • * * Domainarray (Required) A 2 element array where * Domain0 is less than Domain1. This is read by the * PDFFunction superclass.
  • * * Bounds array (Required) An array of k-1 numbers that, * in combination with Domain, define the intervals to which each * function from the Functions array applies. Bounds elements * must be in order of increasing value, and each value must be within * the domain defined by >b>Domain.
  • * * Encode array (Required) An array of 2 * k numbers that, * taken in pairs, map each subset of the domain defined by * and the Bounds array to the domain of the corresponding function. *
  • */ protected void parse(PDFObject obj) throws IOException { if (getNumInputs() != 1) { throw new PDFParseException("Type 3 function only accepts a " + "single input, so Domain should have just 2 elements"); } // read the Functions array (required) PDFObject functionsObj = obj.getDictRef("Functions"); if (functionsObj == null) { throw new PDFParseException("Functions required for function type 3!"); } PDFObject[] functionsAry = functionsObj.getArray(); functions = new PDFFunction[functionsAry.length]; for (int i = 0; i < functionsAry.length; i++) { functions[i] = PDFFunction.getFunction(functionsAry[i]); } int k = functions.length; PDFObject domainObj = obj.getDictRef("Domain"); if (domainObj == null) { throw new PDFParseException("domain required for function type 3!"); } // read the Bounds array (required) PDFObject boundsObj = obj.getDictRef("Bounds"); if (boundsObj == null) { throw new PDFParseException("Bounds required for function type 3!"); } PDFObject[] boundsAry = boundsObj.getArray(); if (boundsAry.length != k - 1) { throw new PDFParseException("Bounds array length " + boundsAry.length + " should be " + (k - 1) + " with functions array length " + functions.length); } bounds = new float[boundsAry.length]; for (int i = 0; i < boundsAry.length; i++) { bounds[i] = boundsAry[i].getFloatValue(); } // read the encode array (required) PDFObject encodeObj = obj.getDictRef("Encode"); if (encodeObj == null) { throw new PDFParseException("Encode required for function type 3!"); } PDFObject[] encodeAry = encodeObj.getArray(); if (encodeAry.length != 2 * k) { throw new PDFParseException("There should be " + (2 * k) + " values in Encode for the given number of functions."); } encode = new float[encodeAry.length]; for (int i = 0; i < encodeAry.length; i++) { encode[i] = encodeAry[i].getFloatValue(); } } /** * Map from m input values to n output values. * The number of inputs m must be exactly one half the size of the * domain. The number of outputs should match one half the size of the * range. * * @param inputs an array of m input values * @param outputs an array of size n which will be filled * with the output values, or null to return a new array */ protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { // calculate the encoded values for each input float input = inputs[inputOffset]; int subdomain = 0; while (subdomain < bounds.length && input >= bounds[subdomain]) { ++subdomain; } final float boundMin = subdomain == 0 ? getDomain(0) : bounds[subdomain - 1]; final float boundMax = subdomain == bounds.length ? getDomain(1) : bounds[subdomain]; final float encodedInput = FunctionType0.interpolate( input, boundMin, boundMax, encode[subdomain * 2], encode[subdomain * 2 + 1]); final float[] subfuncInputArr = new float[] { encodedInput }; functions[subdomain].calculate(subfuncInputArr, 0, outputs, outputOffset); } } pdfrenderer-0.9.0/src/com/sun/pdfview/function/FunctionType0.java0000644000175000017500000003707210732532577025017 0ustar twernertwerner/* * $Id: FunctionType0.java,v 1.3 2007-12-20 18:33:35 rbair Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.function; import java.io.IOException; import java.nio.ByteBuffer; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; /** * A sampled function maps input values to output values by interpolating * along a line or cubic between two known values. */ public class FunctionType0 extends PDFFunction { /** the valid interpolation methods */ protected static final int LINEAR_INTERPOLATION = 1; protected static final int CUBIC_INTERPOLATION = 3; /** the size of each input dimension, as an array of m integers */ private int[] size; /** the number of bits in each sample */ private int bitsPerSample; /** the interpolation type, from the list above */ private int order = 1; /** the optional encoding array, tells how to map input parameters to values */ private float[] encode; /** the optional decoding array, tells how to map output parameters to values */ private float[] decode; /** * the actual samples, converted to integers. The first index is * input values (from 0 to size[m - 1] * size[m - 2] * ... * size[0]), * and the second is the output dimension within the sample (from 0 to n) */ private int[][] samples; /** Creates a new instance of FunctionType0 */ protected FunctionType0() { super (TYPE_0); } /** Read the function information from a PDF Object */ protected void parse(PDFObject obj) throws IOException { // read the size array (required) PDFObject sizeObj = obj.getDictRef("Size"); if (sizeObj == null) { throw new PDFParseException("Size required for function type 0!"); } PDFObject[] sizeAry = sizeObj.getArray(); int[] size = new int[sizeAry.length]; for (int i = 0; i < sizeAry.length; i++) { size[i] = sizeAry[i].getIntValue(); } setSize(size); // read the # bits per sample (required) PDFObject bpsObj = obj.getDictRef("BitsPerSample"); if (bpsObj == null) { throw new PDFParseException("BitsPerSample required for function type 0!"); } setBitsPerSample(bpsObj.getIntValue()); // read the order (optional) PDFObject orderObj = obj.getDictRef("Order"); if (orderObj != null) { setOrder(orderObj.getIntValue()); } // read the encode array (optional) PDFObject encodeObj = obj.getDictRef("Encode"); if (encodeObj != null) { PDFObject[] encodeAry = encodeObj.getArray(); float[] encode = new float[encodeAry.length]; for (int i = 0; i < encodeAry.length; i++) { encode[i] = encodeAry[i].getFloatValue(); } setEncode(encode); } // read the decode array (optional) PDFObject decodeObj = obj.getDictRef("Decode"); if (decodeObj != null) { PDFObject[] decodeAry = decodeObj.getArray(); float[] decode = new float[decodeAry.length]; for (int i = 0; i < decodeAry.length; i++) { decode[i] = decodeAry[i].getFloatValue(); } setDecode(decode); } // finally, read the samples setSamples(readSamples(obj.getStreamBuffer())); } /** * Map from m input values to n output values. * The number of inputs m must be exactly one half the size of the * domain. The number of outputs should match one half the size of the * range. * * @param inputs an array of m input values * @param outputs an array of size n which will be filled * with the output values, or null to return a new array */ protected void doFunction(float[] inputs, int inputOffset, float[] outputs, int outputOffset) { // calculate the encoded values for each input float[] encoded = new float[getNumInputs()]; for (int i = 0; i < getNumInputs(); i++) { // encode -- interpolate(x, domain<2i>, domain<2i + 1>, // encode<2i>, encode<2i + 1>) encoded[i] = interpolate(inputs[i + inputOffset], getDomain(2 * i), getDomain((2 * i) + 1), getEncode(2 * i), getEncode((2 * i) + 1)); // clip to size of sample table -- min(max(e, 0), size - 1) encoded[i] = Math.max(encoded[i], 0); encoded[i] = Math.min(encoded[i], size[i] - 1); } // do some magic for (int i = 0; i < getNumOutputs(); i++) { if (getOrder() == 1) { outputs[i + outputOffset] = multilinearInterpolate(encoded, i); } else { outputs[i + outputOffset] = multicubicInterpolate(encoded, i); } } // now adjust the output to be within range for (int i = 0; i < outputs.length; i++) { // decode -- interpolate(r, 0, 2^bps - 1, // decode<2i>, decode<2i + 1>) outputs[i + outputOffset] = interpolate(outputs[i + outputOffset], 0, (float) Math.pow(2, getBitsPerSample()) - 1, getDecode(2 * i), getDecode((2 * i) + 1)); } } /** * Get the size of a given input dimension * * @param dimension the input dimension to get the size of * @return the number of samples in the given dimension */ protected int getSize(int dimension) { return size[dimension]; } /** * Set the size of all input dimensions */ protected void setSize(int[] size) { this.size = size; } /** * Get the number of bits per sample */ protected int getBitsPerSample() { return bitsPerSample; } /** * Set the number of bits per sample */ protected void setBitsPerSample(int bits) { this.bitsPerSample = bits; } /** * Get the interpolation type */ protected int getOrder() { return order; } /** * Set the interpolation type */ protected void setOrder(int order) { this.order = order; } /** * Get the encoding for a particular input parameter * * @param i the index into the encoding array, which has size 2 * m. * the ith entry in the array has index 2i, * 2i + 1 * @return the encoding value if the encoding array is set, or the default */ protected float getEncode(int i) { if (encode != null) { return encode[i]; } else if ((i % 2) == 0) { return 0f; } else { return (getSize(i / 2) - 1); } } /** * Set the encode array */ protected void setEncode(float[] encode) { this.encode = encode; } /** * Get the decoding for a particular input parameter * * @param i the index into the decoding array, which has size 2 * n. * the ith entry in the array has index 2i, * 2i + 1 * @return the decoding value if the decoding array is set, or the default */ protected float getDecode(int i) { if (decode != null) { return decode[i]; } else { return getRange(i); } } /** * Set the decode array */ protected void setDecode(float[] decode) { this.decode = decode; } /** * Get a component for a sample given m indices and output * dimension. * * @param values an array of m values determining which sample * to select * @param od the output dimension (0 - n) to get the sample in * @return the sample for the given values and index */ protected int getSample(int[] values, int od) { int mult = 1; int index = 0; for (int i = 0; i < values.length; i++) { index += mult * values[i]; mult *= getSize(i); } return samples[index][od]; } /** * Set the table of samples */ protected void setSamples(int[][] samples) { this.samples = samples; } /** * Read the samples from the input stream. Each sample is made up * of n components, each of which has length bitsPerSample * bits. The samples are arranged by dimension, then range */ private int[][] readSamples(ByteBuffer buf) { // calculate the number of samples in the table int size = 1; for (int i = 0; i < getNumInputs(); i++) { size *= getSize(i); } // create the samples table int[][] samples = new int[size][getNumOutputs()]; // the current location in the buffer, in bits from byteLoc int bitLoc = 0; // the current location in the buffer, in bytes int byteLoc = 0; // the current index in the samples array int index = 0; for (int i = 0; i < getNumInputs(); i++) { for (int j = 0; j < getSize(i); j++) { for (int k = 0; k < getNumOutputs(); k++) { /** [JK FIXME one bit at a time is really inefficient */ int value = 0; int toRead = getBitsPerSample(); byte curByte = buf.get(byteLoc); while (toRead > 0) { int nextBit = ((curByte >> (7 - bitLoc)) & 0x1); value |= nextBit << (toRead - 1); if (++bitLoc == 8) { bitLoc = 0; byteLoc++; if (toRead > 1) { curByte = buf.get(byteLoc); } } toRead--; } samples[index][k] = value; } index++; } } return samples; } /** * Perform a piecewise multilinear interpolation. The provides a * close approximation to the standard linear interpolation, at * a far lower cost, since every element is not evaluated at every * iteration. Instead, a walk of the most significant axes is performed, * following the algorithm desribed at: * http://osl.iu.edu/~tveldhui/papers/MAScThesis/node33.html * * @param encoded the encoded input values * @param od the output dimension */ private float multilinearInterpolate(float[] encoded, int od) { // first calculate the distances -- the differences between // each encoded value and the integer below it. float[] dists = new float[encoded.length]; for (int i = 0; i < dists.length; i++) { dists[i] = (float) (encoded[i] - Math.floor(encoded[i])); } // initialize the map of axes. Each bit in this map represents // whether the control value in that dimension should be the integer // above or below encoded[i] int map = 0; // the initial values float val = getSample(encoded, map, od); float prev = val; // walk the axes for (int i = 0; i < dists.length; i++) { // find the largest value of dist remaining int idx = 0; float largest = -1; for (int c = 0; c < dists.length; c++) { if (dists[c] > largest) { largest = dists[c]; idx = c; } } // now find the sample with that axis set to 1 map |= (0x1 << idx); float cur = getSample(encoded, map, od); // calculate the value and remember it val += dists[idx] * (cur - prev); prev = val; // make sure we won't find this distance again dists[idx] = -1; } // voila return val; } /** * Perform a multicubic interpolation * * @param encoded the encoded input values * @param od the output dimension */ private float multicubicInterpolate(float[] encoded, int od) { System.out.println("Cubic interpolation not supported!"); return multilinearInterpolate(encoded, od); } /** * Perform a linear interpolation. Given a value x, and two points, * (xmin, ymin), (xmax, ymax), where xmin <= x <= xmax, calculate a value * y on the line from (xmin, ymin) to (xmax, ymax). * * @param x the x value of the input * @param xmin the minimum x value * @param ymin the minimum y value * @param xmax the maximum x value * @param ymax the maximum y value * @return the y value interpolated from the given x */ public static float interpolate(float x, float xmin, float xmax, float ymin, float ymax) { float value = (ymax - ymin) / (xmax - xmin); value *= x - xmin; value += ymin; return value; } /** * Get a sample based on an array of encoded values and a control * map. For each bit in the map, if that bit is 0 the integer below * the encoded value is selected, or if the bit is 1, the interger * above is selected. * * @param encoded the encoded values * @param map the bit map of control values * @param od the output dimension to read the sample for */ private float getSample(float[] encoded, int map, int od) { int[] controls = new int[encoded.length]; // fill in the controls array with appropriate ints for (int i = 0; i < controls.length; i++) { if ((map & (0x1 << i)) == 0) { controls[i] = (int) Math.floor(encoded[i]); } else { controls[i] = (int) Math.ceil(encoded[i]); } } // now return the actual sample return getSample(controls, od); } } pdfrenderer-0.9.0/src/com/sun/pdfview/function/PDFFunction.java0000644000175000017500000002702411157172615024416 0ustar twernertwerner/* * $Id: PDFFunction.java,v 1.6 2009-03-15 12:33:17 tomoke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.function; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import java.io.IOException; /** *

    PDF Functions are defined in the reference as Section 3.9.

    * *

    A PDF function maps some set of m inputs into some set * of n outputs. There are 4 types of functions: *

    • Type 0: Sampled functions. (PDF 1.2)
      * A sampled function (type 0) uses a table of sample values * to define the function. Various techniques are used to * interpolate values between the sample values * (see Section 3.9.1, "Type 0 (Sampled) Functions").
    • *
    • Type 2: Exponential Interpolation. (PDF 1.3)
      * An exponential interpolation function (type 2) * defines a set of coefficients for an exponential function * (see Section 3.9.2, * "Type 2 (Exponential Interpolation) Functions").
    • *
    • Type 3: Stitching functions. (PDF 1.3)
      * A stitching function (type 3) is a combination of * other functions, partitioned across a domain * (see Section 3.9.3, "Type 3 (Stitching) Functions").
    • *
    • Type 4: Postscript calculations. (PDF 1.3)
      * A PostScript calculator function (type 4) uses operators * from the PostScript language to describe an arithmetic * expression (see Section 3.9.4, * "Type 4 (PostScript Calculator) Functions").
    • *
    *

    * *

    * The function interface contains a single method, calculate which * takes an array of m floats an interprets them into an array of * n floats. *

    * PDFFunctions do not have accessible constructors. Instead, use the * static getFunction() method to read a functions from a PDF Object. * */ public abstract class PDFFunction { /** Sampled function */ public static final int TYPE_0 = 0; /** Exponential interpolation function */ public static final int TYPE_2 = 2; /** Stitching function. */ public static final int TYPE_3 = 3; /** PostScript calculator function. */ public static final int TYPE_4 = 4; /** the type of this function from the list of known types */ private int type; /** the input domain of this function, an array of 2 * m floats */ private float[] domain; /** the output range of this functions, and array of 2 * n floats. * required for type 0 and 4 functions */ private float[] range; /** Creates a new instance of PDFFunction */ protected PDFFunction (int type) { this.type = type; } /** * Get a PDFFunction from a PDFObject */ public static PDFFunction getFunction (PDFObject obj) throws IOException { PDFFunction function; int type; float[] domain = null; float[] range = null; // read the function type (required) PDFObject typeObj = obj.getDictRef ("FunctionType"); if (typeObj == null) { throw new PDFParseException ( "No FunctionType specified in function!"); } type = typeObj.getIntValue (); // read the function's domain (required) PDFObject domainObj = obj.getDictRef ("Domain"); if (domainObj == null) { throw new PDFParseException ("No Domain specified in function!"); } PDFObject[] domainAry = domainObj.getArray (); domain = new float[domainAry.length]; for (int i = 0; i < domainAry.length; i++) { domain[i] = domainAry[i].getFloatValue (); } // read the function's range (optional) PDFObject rangeObj = obj.getDictRef ("Range"); if (rangeObj != null) { PDFObject[] rangeAry = rangeObj.getArray (); range = new float[rangeAry.length]; for (int i = 0; i < rangeAry.length; i++) { range[i] = rangeAry[i].getFloatValue (); } } // now create the acual function object switch (type) { case TYPE_0: if (rangeObj == null) { throw new PDFParseException ( "No Range specified in Type 0 Function!"); } function = new FunctionType0 (); break; case TYPE_2: function = new FunctionType2 (); break; case TYPE_3: function = new FunctionType3 (); break; case TYPE_4: if (rangeObj == null) { throw new PDFParseException ( "No Range specified in Type 4 Function!"); } function = new FunctionType4 (); break; default: throw new PDFParseException ( "Unsupported function type: " + type); } // fill in the domain and optionally the range function.setDomain (domain); if (range != null) { function.setRange (range); } // now initialize the function function.parse (obj); return function; } /** * Get the type of this function * * @return one of the types of function (0-4) */ public int getType () { return type; } /** * Get the number of inputs, m, required by this function * * @return the number of input values expected by this function */ public int getNumInputs () { return (domain.length / 2); } /** * Get the number of outputs, n, returned by this function * * @return the number of output values this function will return */ public int getNumOutputs () { if (range == null) { return 0; } return (range.length / 2); } /** * Get a component of the domain of this function * * @param i the index into the domain array, which has size 2 * m. * the ith entry in the array has index 2i, * 2i + 1 * @return the ith entry in the domain array */ protected float getDomain (int i) { return domain[i]; } /** * Set the domain of this function */ protected void setDomain (float[] domain) { this.domain = domain; } /** * Get a component of the range of this function * * @param i the index into the range array, which has size 2 * n. * the ith entry in the array has index 2i, * 2i + 1 * @return the ith entry in the range array */ protected float getRange (int i) { if (range == null) { if ((i % 2) == 0) { return Float.MIN_VALUE; } else { return Float.MAX_VALUE; } } return range[i]; } /** * Set the range of this function */ protected void setRange (float[] range) { this.range = range; } /** * Map from m input values to n output values. * The number of inputs m must be exactly one half the size of the * domain. The number of outputs should match one half the size of the * range. * * @param inputs an array of >= m input values * @return the array of n output values */ public float[] calculate (float[] inputs) { float[] outputs = new float[getNumOutputs ()]; calculate (inputs, 0, outputs, 0); return outputs; } /** * Map from m input values to n output values. * The number of inputs m must be exactly one half the size of the * domain. The number of outputs should match one half the size of the * range. * * @param inputs an array of >= m input values * @param inputOffset the offset into the input array to read from * @param outputs an array of size >= n which will be filled * with the output values * @param outputOffset the offset into the output array to write to * @return the array of n output values */ public float[] calculate (float[] inputs, int inputOffset, float[] outputs, int outputOffset) { // check the inputs if (inputs.length - inputOffset < getNumInputs ()) { throw new IllegalArgumentException ( "Wrong number of inputs to function!"); } // check the outputs if (range != null && outputs.length - outputOffset < getNumOutputs ()) { throw new IllegalArgumentException ( "Wrong number of outputs for function!"); } // clip the inputs to domain for (int i = 0; i < inputs.length; i++) { // clip to the domain -- min(max(x, domain<2i>), domain<2i+1>) inputs[i] = Math.max (inputs[i], getDomain (2 * i)); inputs[i] = Math.min (inputs[i], getDomain ((2 * i) + 1)); } // do the actual calculation doFunction (inputs, inputOffset, outputs, outputOffset); // clip the outputs to range for (int i = 0; range != null && i < outputs.length; i++) { // clip to range -- min(max(r, range<2i>), range<2i + 1>) outputs[i] = Math.max (outputs[i], getRange (2 * i)); outputs[i] = Math.min (outputs[i], getRange ((2 * i) + 1)); } return outputs; } /** * Subclasses must implement this method to perform the actual function * on the given set of data. Note that the inputs are guaranteed to be * clipped to the domain, while the outputs will be automatically clipped * to the range after being returned from this function. * * @param inputs guaranteed to be at least as big as * getNumInputs() and all values within range * @param inputOffset the offset into the inputs array to read from * @param outputs guaranteed to be at least as big as * getNumOutputs(), but not yet clipped to domain * @param outputOffset the offset into the output array to write to */ protected abstract void doFunction (float[] inputs, int inputOffset, float[] outputs, int outputOffset); /** Read the function information from a PDF Object */ protected abstract void parse (PDFObject obj) throws IOException; } pdfrenderer-0.9.0/src/com/sun/pdfview/Identity8BitCharsetEncoder.java0000644000175000017500000000403211156177553025603 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import com.sun.pdfview.PDFStringUtil; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.Charset; import java.nio.CharBuffer; import java.nio.ByteBuffer; import java.util.Map; import java.util.HashMap; /** * A {@link CharsetEncoder} that attempts to write out the lower 8 bits * of any character. Characters >= 256 in value are regarded * as unmappable. * * @author Luke Kirby */ public class Identity8BitCharsetEncoder extends CharsetEncoder { public Identity8BitCharsetEncoder() { super(null, 1, 1); } protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { while (in.remaining() > 0) { if (out.remaining() < 1) { return CoderResult.OVERFLOW; } final char c = in.get(); if (c >= 0 && c < 256) { out.put((byte) c); } else { return CoderResult.unmappableForLength(1); } } return CoderResult.UNDERFLOW; } @Override public boolean isLegalReplacement(byte[] repl) { // avoid referencing the non-existent character set return true; } }pdfrenderer-0.9.0/src/com/sun/pdfview/PDFFile.java0000644000175000017500000021515711526563523021673 0ustar twernertwerner/* * $Id: PDFFile.java,v 1.19 2010-05-23 22:07:05 lujke Exp $ * * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview; import java.awt.geom.Rectangle2D; import java.io.*; import java.nio.ByteBuffer; import java.util.*; import com.sun.pdfview.action.*; import com.sun.pdfview.decode.PDFDecoder; import com.sun.pdfview.decrypt.*; /** * An encapsulation of a .pdf file. The methods of this class * can parse the contents of a PDF file, but those methods are * hidden. Instead, the public methods of this class allow * access to the pages in the PDF file. Typically, you create * a new PDFFile, ask it for the number of pages, and then * request one or more PDFPages. * @author Mike Wessler */ public class PDFFile { public final static int NUL_CHAR = 0; public final static int FF_CHAR = 12; private String versionString = "1.1"; private int majorVersion = 1; private int minorVersion = 1; /** the end of line character */ /** the comment text to begin the file to determine it's version */ private final static String VERSION_COMMENT = "%PDF-"; /** * A ByteBuffer containing the file data */ ByteBuffer fileBuf; /** * the cross reference table mapping object numbers to locations * in the PDF file */ PDFXrefEntry[] xrefEntries; /** the root PDFObject, as specified in the PDF file */ PDFObject root = null; /** the Encrypt PDFObject, from the trailer */ PDFObject encrypt = null; /** The Info PDFPbject, from the trailer, for simple metadata */ PDFObject info = null; /** a mapping of page numbers to parsed PDF commands */ Cache cache; /** * whether the file is printable or not (trailer -> Encrypt -> P & 0x4) */ private boolean printable = true; /** * whether the file is saveable or not (trailer -> Encrypt -> P & 0x10) */ private boolean saveable = true; /** * The default decrypter for streams and strings. By default, no * encryption is expected, and thus the IdentityDecrypter is used. */ private PDFDecrypter defaultDecrypter = IdentityDecrypter.getInstance(); /** * The file identifier, as found in a trailer/xref stream dictionary, * and as used for encryption */ private PDFObject fileIdentifier = null; /** * get a PDFFile from a .pdf file. The file must me a random access file * at the moment. It should really be a file mapping from the nio package. *

    * Use the getPage(...) methods to get a page from the PDF file. * @param buf the RandomAccessFile containing the PDF. * @throws IOException if there's a problem reading from the buffer * @throws PDFParseException if the document appears to be malformed, or * its features are unsupported. If the file is encrypted in a manner that * the product or platform does not support then the exception's {@link * PDFParseException#getCause() cause} will be an instance of {@link * UnsupportedEncryptionException}. * @throws PDFAuthenticationFailureException if the file is password * protected and requires a password */ public PDFFile(ByteBuffer buf) throws IOException { this(buf, null); } /** * get a PDFFile from a .pdf file. The file must me a random access file * at the moment. It should really be a file mapping from the nio package. *

    * Use the getPage(...) methods to get a page from the PDF file. * @param buf the RandomAccessFile containing the PDF. * @param password the user or owner password * @throws IOException if there's a problem reading from the buffer * @throws PDFParseException if the document appears to be malformed, or * its features are unsupported. If the file is encrypted in a manner that * the product or platform does not support then the exception's {@link * PDFParseException#getCause() cause} will be an instance of {@link * UnsupportedEncryptionException}. * @throws PDFAuthenticationFailureException if the file is password * protected and the supplied password does not decrypt the document */ public PDFFile(ByteBuffer buf, PDFPassword password) throws IOException { this.fileBuf = buf; cache = new Cache(); parseFile(password); } /** * Gets whether the owner of the file has given permission to print * the file. * @return true if it is okay to print the file */ public boolean isPrintable() { return printable; } /** * Gets whether the owner of the file has given permission to save * a copy of the file. * @return true if it is okay to save the file */ public boolean isSaveable() { return saveable; } /** * get the root PDFObject of this PDFFile. You generally shouldn't need * this, but we've left it open in case you want to go spelunking. */ public PDFObject getRoot() { return root; } /** * return the number of pages in this PDFFile. The pages will be * numbered from 1 to getNumPages(), inclusive. */ public int getNumPages() { try { return root.getDictRef("Pages").getDictRef("Count").getIntValue(); } catch (Exception ioe) { return 0; } } /** * Get metadata (e.g., Author, Title, Creator) from the Info dictionary * as a string. * @param name the name of the metadata key (e.g., Author) * @return the info * @throws IOException if the metadata cannot be read */ public String getStringMetadata(String name) throws IOException { if (info != null) { final PDFObject meta = info.getDictRef(name); return meta != null ? meta.getTextStringValue() : null; } else { return null; } } /** * Get the keys into the Info metadata, for use with * {@link #getStringMetadata(String)} * @return the keys present into the Info dictionary * @throws IOException if the keys cannot be read */ public Iterator getMetadataKeys() throws IOException { if (info != null) { return info.getDictKeys(); } else { return Collections.emptyList().iterator(); } } /** * Used internally to track down PDFObject references. You should never * need to call this. *

    * Since this is the only public method for tracking down PDF objects, * it is synchronized. This means that the PDFFile can only hunt down * one object at a time, preventing the file's location from getting * messed around. *

    * This call stores the current buffer position before any changes are made * and restores it afterwards, so callers need not know that the position * has changed. * */ public synchronized PDFObject dereference(PDFXref ref, PDFDecrypter decrypter) throws IOException { int id = ref.getObjectNumber(); // make sure the id is valid and has been read if (id >= xrefEntries.length || id < 0) { return PDFObject.nullObj; } // if there is an entry, make sure that it can resolve to the // requested generation number and that it's not a free entry; if // so, we should return the null object final PDFXrefEntry entry = xrefEntries[id]; if (entry == null || !entry.resolves(ref)) { return PDFObject.nullObj; } // check to see if this is already dereferenced PDFObject obj = entry.getObject(); if (obj != null) { return obj; } switch (entry.getType()) { case OBJ_IN_BODY: int loc = entry.getOffset(); if (loc < 0) { return PDFObject.nullObj; } // store the current position in the buffer int startPos = fileBuf.position(); // move to where this object is fileBuf.position(loc); // read the object and cache the reference obj= readObject(fileBuf, ref.getObjectNumber(), ref.getGeneration(), decrypter); if (obj == null) { obj = PDFObject.nullObj; } entry.setObject(obj); // reset to the previous position fileBuf.position(startPos); return obj; case OBJ_IN_STREAM: final PDFObject stream = dereference(entry.getStream(), getDefaultDecrypter()); if (stream == null || stream.getType() != PDFObject.STREAM || !"ObjStm".equals(stream.getDictRef("Type").getStringValue())) { throw new PDFParseException(entry.getStream().getObjectNumber() + " is not an object stream, but was referenced in " + "the xref stream as one"); } final ByteBuffer streamBuf = stream.getStreamBuffer(); final PDFXrefEntry streamSourceEntry = xrefEntries[entry.getStream().getObjectNumber()]; int[] offsets = streamSourceEntry.getObjectIndexOffsets(); if (offsets == null) { offsets = new int[stream.getDictionary().get("N").getIntValue()]; int first = stream.getDictionary().get("First").getIntValue(); for (int i = 0; i < offsets.length; ++i) { // we don't need the object number final PDFObject objNum = readObject(streamBuf, -1, -1, IdentityDecrypter.getInstance()); // add in the initial offset represented by First here offsets[i] = first + readObject(streamBuf, -1, -1, IdentityDecrypter.getInstance()). getIntValue(); } streamSourceEntry.setObjectIndexOffsets(offsets); } if (entry.getOffset() < 0 || entry.getOffset() >= offsets.length) { throw new PDFParseException("Xref references index that does not exist in stream"); } streamBuf.position(offsets[entry.getOffset()]); // According to the PDF spec: // "Any strings that are inside streams such as content streams // and compressed object streams, which themselves are // encrypted" // So, we figure out whether the containing stream was // encrypted or not; unfortunately, we don't have this // cached anywhere. If the stream was encrypted, we make // sure we don't attempt to decrypt any strings within. obj= readObject(streamBuf, ref.getObjectNumber(), ref.getGeneration(), PDFDecoder.isEncrypted(stream) ? IdentityDecrypter.getInstance() : getDefaultDecrypter()); if (obj == null) { obj = PDFObject.nullObj; } entry.setObject(obj); return obj; case FREE: // this case should in practice be covered by the // call to entry.resolves() above return PDFObject.nullObj; default: throw new UnsupportedOperationException( "Don't know how to handle xref type " + entry.getType()); } } /** * Is the argument a white space character according to the PDF spec?. * ISO Spec 32000-1:2008 - Table 1 */ public static boolean isWhiteSpace(int c) { switch (c) { case NUL_CHAR: // Null (NULL) case '\t': // Horizontal Tab (HT) case '\n': // Line Feed (LF) case FF_CHAR: // Form Feed (FF) case '\r': // Carriage Return (CR) case ' ': // Space (SP) return true; default: return false; } } /** * Is the argument a delimiter according to the PDF spec?

    * * ISO 32000-1:2008 - Table 2 * * @param c the character to test */ public static boolean isDelimiter(int c) { switch (c) { case '(': // LEFT PARENTHESIS case ')': // RIGHT PARENTHESIS case '<': // LESS-THAN-SIGN case '>': // GREATER-THAN-SIGN case '[': // LEFT SQUARE BRACKET case ']': // RIGHT SQUARE BRACKET case '{': // LEFT CURLY BRACKET case '}': // RIGHT CURLY BRACKET case '/': // SOLIDUS case '%': // PERCENT SIGN return true; default: return false; } } /** * return true if the character is neither a whitespace or a delimiter. * * @param c the character to test * @return boolean */ public static boolean isRegularCharacter (int c) { return !(isWhiteSpace(c) || isDelimiter(c)); } /** * read the next object from the file * @param buf the buffer to read from * @param objNum the object number of the object containing the object * being read; negative only if the object number is unavailable (e.g., if * reading from the trailer, or reading at the top level, in which * case we can expect to be reading an object description) * @param objGen the object generation of the object containing the object * being read; negative only if the objNum is unavailable * @param decrypter the decrypter to use */ private PDFObject readObject( ByteBuffer buf, int objNum, int objGen, PDFDecrypter decrypter) throws IOException { return readObject(buf, objNum, objGen, false, decrypter); } /** * read the next object with a special catch for numbers * @param buf the buffer to read from * @param objNum the object number of the object containing the object * being read; negative only if the object number is unavailable (e.g., if * reading from the trailer, or reading at the top level, in which * case we can expect to be reading an object description) * @param objGen the object generation of the object containing the object * being read; negative only if the objNum is unavailable * @param numscan if true, don't bother trying to see if a number is * an object reference (used when already in the middle of testing for * an object reference, and not otherwise) * @param decrypter the decrypter to use */ private PDFObject readObject( ByteBuffer buf, int objNum, int objGen, boolean numscan, PDFDecrypter decrypter) throws IOException { // skip whitespace int c; PDFObject obj = null; while (obj == null) { c = nextNonWhitespaceChar(buf); // check character for special punctuation: if (c == '<') { // could be start of , or start of <> c = buf.get(); if (c == '<') { // it's a dictionary obj= readDictionary(buf, objNum, objGen, decrypter); } else { buf.position(buf.position() - 1); obj= readHexString(buf, objNum, objGen, decrypter); } } else if (c == '(') { obj= readLiteralString(buf, objNum, objGen, decrypter); } else if (c == '[') { // it's an array obj= readArray(buf, objNum, objGen, decrypter); } else if (c == '/') { // it's a name obj = readName(buf); } else if (c == '%') { // it's a comment readLine(buf); } else if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.') { // it's a number obj = readNumber(buf, (char) c); if (!numscan) { // It could be the start of a reference. // Check to see if there's another number, then "R". // // We can't use mark/reset, since this could be called // from dereference, which already is using a mark int startPos = buf.position(); PDFObject testnum= readObject(buf, -1, -1, true, decrypter); if (testnum != null && testnum.getType() == PDFObject.NUMBER) { PDFObject testR= readObject(buf, -1, -1, true, decrypter); if (testR != null && testR.getType() == PDFObject.KEYWORD && testR.getStringValue().equals("R")) { // yup. it's a reference. PDFXref xref = new PDFXref(obj.getIntValue(), testnum.getIntValue()); // Create a placeholder that will be dereferenced // as needed obj = new PDFObject(this, xref); } else if (testR != null && testR.getType() == PDFObject.KEYWORD && testR.getStringValue().equals("obj")) { // it's an object description obj= readObjectDescription( buf, obj.getIntValue(), testnum.getIntValue(), decrypter); } else { buf.position(startPos); } } else { buf.position(startPos); } } } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { // it's a keyword obj = readKeyword(buf, (char) c); } else { // it's probably a closing character. // throwback buf.position(buf.position() - 1); break; } } return obj; } /** * Get the next non-white space character * @param buf the buffer to read from * @return the next non-whitespace character */ private int nextNonWhitespaceChar(ByteBuffer buf) { int c; while (isWhiteSpace(c = buf.get())) { // nothing } return c; } /** * Consume all sequential whitespace from the current buffer position, * leaving the buffer positioned at non-whitespace * @param buf the buffer to read from */ private void consumeWhitespace(ByteBuffer buf) { nextNonWhitespaceChar(buf); buf.position(buf.position() - 1); } /** * requires the next few characters (after whitespace) to match the * argument. * @param buf the buffer to read from * @param match the next few characters after any whitespace that * must be in the file * @return true if the next characters match; false otherwise. */ private boolean nextItemIs(ByteBuffer buf, String match) throws IOException { // skip whitespace int c = nextNonWhitespaceChar(buf); for (int i = 0; i < match.length(); i++) { if (i > 0) { c = buf.get(); } if (c != match.charAt(i)) { return false; } } return true; } /** * process a version string, to determine the major and minor versions * of the file. * * @param versionString */ private void processVersion(String versionString) { try { StringTokenizer tokens = new StringTokenizer(versionString, "."); majorVersion = Integer.parseInt(tokens.nextToken()); minorVersion = Integer.parseInt(tokens.nextToken()); this.versionString = versionString; } catch (Exception e) { // ignore } } /** * return the major version of the PDF header. * * @return int */ public int getMajorVersion() { return majorVersion; } /** * return the minor version of the PDF header. * * @return int */ public int getMinorVersion() { return minorVersion; } /** * return the version string from the PDF header. * * @return String */ public String getVersionString() { return versionString; } /** * read an entire << dictionary >>. The initial * << has already been read. * @param buf the buffer to read from * @param objNum the object number of the object containing the dictionary * being read; negative only if the object number is unavailable, which * should only happen if we're reading a dictionary placed directly * in the trailer * @param objGen the object generation of the object containing the object * being read; negative only if the objNum is unavailable * @param decrypter the decrypter to use * @return the Dictionary as a PDFObject. */ private PDFObject readDictionary( ByteBuffer buf, int objNum, int objGen, PDFDecrypter decrypter) throws IOException { HashMap hm = new HashMap(); // we've already read the <<. Now get /Name obj pairs until >> PDFObject name; while ((name= readObject(buf, objNum, objGen, decrypter))!=null) { // make sure first item is a NAME if (name.getType() != PDFObject.NAME) { throw new PDFParseException("First item in dictionary must be a /Name. (Was " + name + ")"); } PDFObject value= readObject(buf, objNum, objGen, decrypter); if (value != null) { hm.put(name.getStringValue(), value); } } // System.out.println("End of dictionary at location "+raf.getFilePointer()); if (!nextItemIs(buf, ">>")) { throw new PDFParseException("End of dictionary wasn't '>>'"); } // System.out.println("Dictionary closed at location "+raf.getFilePointer()); return new PDFObject(this, PDFObject.DICTIONARY, hm); } /** * read a character, and return its value as if it were a hexidecimal * digit. * @return a number between 0 and 15 whose value matches the next * hexidecimal character. Returns -1 if the next character isn't in * [0-9a-fA-F] * @param buf the buffer to read from */ private int readHexDigit(ByteBuffer buf) throws IOException { int a = nextNonWhitespaceChar(buf); switch (a) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': a -= '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': a -= 'a' - 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': a -= 'A' - 10; break; default: a = -1; break; } return a; } /** * return the 8-bit value represented by the next two hex characters. * If the next two characters don't represent a hex value, return -1 * and reset the read head. If there is only one hex character, * return its value as if there were an implicit 0 after it. * @param buf */ private int readHexPair(ByteBuffer buf) throws IOException { int first = readHexDigit(buf); if (first < 0) { buf.position(buf.position() - 1); return -1; } int second = readHexDigit(buf); if (second < 0) { buf.position(buf.position() - 1); return (first << 4); } else { return (first << 4) + second; } } /** * read a < hex string >. The initial < has already been read. * @param buf the buffer to read from * @param objNum the object number of the object containing the dictionary * being read; negative only if the object number is unavailable, which * should only happen if we're reading a string placed directly * in the trailer * @param objGen the object generation of the object containing the object * being read; negative only if the objNum is unavailable * @param decrypter the decrypter to use */ private PDFObject readHexString( ByteBuffer buf, int objNum, int objGen, PDFDecrypter decrypter) throws IOException { // we've already read the <. Now get the hex bytes until > int val; StringBuffer sb = new StringBuffer(); while ((val = readHexPair(buf)) >= 0) { sb.append((char) val); } if (buf.get() != '>') { throw new PDFParseException("Bad character in Hex String"); } return new PDFObject(this, PDFObject.STRING, decrypter.decryptString(objNum, objGen, sb.toString())); } /** *

    read a ( character string ). The initial ( has already been read. * Read until a *balanced* ) appears.

    * *

    Section 3.2.3 of PDF Refernce version 1.7 defines the format of * String objects. Regarding literal strings:

    * *
    Within a literal string, the backslash (\) is used as an * escape character for various purposes, such as to include newline * characters, nonprinting ASCII characters, unbalanced parentheses, or * the backslash character itself in the string. The character * immediately following the backslash determines its precise * interpretation (see Table 3.2). If the character following the * backslash is not one of those shown in the table, the backslash * is ignored.
    * * *

    This only reads 8 bit basic character 'strings' so as to avoid a * text string interpretation when one is not desired (e.g., for byte * strings, as used by the decryption mechanism). For an interpretation of * a string returned from this method, where the object type is defined * as a 'text string' as per Section 3.8.1, Table 3.31 "PDF Data Types", * {@link PDFStringUtil#asTextString} ()} or * {@link PDFObject#getTextStringValue()} must be employed.

    * * @param buf the buffer to read from * @param objNum the object number of the object containing the dictionary * being read; negative only if the object number is unavailable, which * should only happen if we're reading a dictionary placed directly * in the trailer * @param objGen the object generation of the object containing the object * being read; negative only if the objNum is unavailable * @param decrypter the decrypter to use */ private PDFObject readLiteralString( ByteBuffer buf, int objNum, int objGen, PDFDecrypter decrypter) throws IOException { int c; // we've already read the (. now get the characters until a // *balanced* ) appears. Translate \r \n \t \b \f \( \) \\ \ddd // if a cr/lf follows a backslash, ignore the cr/lf int parencount = 1; StringBuffer sb = new StringBuffer(); while (parencount > 0) { c = buf.get() & 0xFF; // process unescaped parenthesis if (c == '(') { parencount++; } else if (c == ')') { parencount--; if (parencount == 0) { c = -1; break; } } else if (c == '\\') { // From the spec: // Within a literal string, the backslash (\) is used as an // escape character for various purposes, such as to include // newline characters, nonprinting ASCII characters, // unbalanced parentheses, or the backslash character itself // in the string. The character immediately following the // backslash determines its precise interpretation (see // Table 3.2). If the character following the backslash is not // one of those shown in the table, the backslash is ignored. // // summary of rules: // // \n \r \t \b \f 2-char sequences are used to represent their // 1-char counterparts // // \( and \) are used to escape parenthesis // // \\ for a literal backslash // // \ddd (1-3 octal digits) for a character code // // \ is used to put formatting newlines into the // file, but aren't actually part of the string; EOL may be // CR, LF or CRLF // // any other sequence should see the backslash ignored // grab the next character to see what we're dealing with c = buf.get() & 0xFF; if (c >= '0' && c < '8') { // \ddd form - one to three OCTAL digits int count = 0; int val = 0; while (c >= '0' && c < '8' && count < 3) { val = val * 8 + c - '0'; c = buf.get() & 0xFF; count++; } // we'll have read one character too many buf.position(buf.position() - 1); c = val; } else if (c == 'n') { c = '\n'; } else if (c == 'r') { c = '\r'; } else if (c == 't') { c = '\t'; } else if (c == 'b') { c = '\b'; } else if (c == 'f') { c = '\f'; } else if (c == '\r') { // escaped CR to be ignored; look for a following LF c = buf.get() & 0xFF; if (c != '\n') { // not an LF, we'll consume this character on // the next iteration buf.position(buf.position() - 1); } c = -1; } else if (c == '\n') { // escaped LF to be ignored c = -1; } // any other c should be used as is, as it's either // one of ()\ in which case it should be used literally, // or the backslash should just be ignored } if (c >= 0) { sb.append((char) c); } } return new PDFObject(this, PDFObject.STRING, decrypter.decryptString(objNum, objGen, sb.toString())); } /** * Read a line of text. This follows the semantics of readLine() in * DataInput -- it reads character by character until a '\n' is * encountered. If a '\r' is encountered, it is discarded. * @param buf the buffer to read from */ private String readLine(ByteBuffer buf) { StringBuffer sb = new StringBuffer(); while (buf.remaining() > 0) { char c = (char) buf.get(); if (c == '\r') { if (buf.remaining() > 0) { char n = (char) buf.get(buf.position()); if (n == '\n') { buf.get(); } } break; } else if (c == '\n') { break; } sb.append(c); } return sb.toString(); } /** * read an [ array ]. The initial [ has already been read. PDFObjects * are read until ]. * @param buf the buffer to read from * @param objNum the object number of the object containing the dictionary * being read; negative only if the object number is unavailable, which * should only happen if we're reading an array placed directly * in the trailer * @param objGen the object generation of the object containing the object * being read; negative only if the objNum is unavailable * @param decrypter the decrypter to use */ private PDFObject readArray( ByteBuffer buf, int objNum, int objGen, PDFDecrypter decrypter) throws IOException { // we've already read the [. Now read objects until ] ArrayList ary = new ArrayList(); PDFObject obj; while((obj= readObject(buf, objNum, objGen, decrypter))!=null) { ary.add(obj); } if (buf.get() != ']') { throw new PDFParseException("Array should end with ']'"); } PDFObject[] objlist = new PDFObject[ary.size()]; for (int i = 0; i < objlist.length; i++) { objlist[i] = (PDFObject) ary.get(i); } return new PDFObject(this, PDFObject.ARRAY, objlist); } /** * read a /name. The / has already been read. * @param buf the buffer to read from */ private PDFObject readName(ByteBuffer buf) throws IOException { // we've already read the / that begins the name. // all we have to check for is #hh hex notations. StringBuffer sb = new StringBuffer(); int c; while (isRegularCharacter(c = buf.get())) { if (c < '!' && c > '~') { break; // out-of-range, should have been hex } // H.3.2.4 indicates version 1.1 did not do hex escapes if (c == '#' && (majorVersion != 1 && minorVersion != 1)) { int hex = readHexPair(buf); if (hex >= 0) { c = hex; } else { throw new PDFParseException("Bad #hex in /Name"); } } sb.append((char) c); } buf.position(buf.position() - 1); return new PDFObject(this, PDFObject.NAME, sb.toString()); } /** * read a number. The initial digit or . or - is passed in as the * argument. */ private PDFObject readNumber(ByteBuffer buf, char start) throws IOException { // we've read the first digit (it's passed in as the argument) boolean neg = start == '-'; boolean sawdot = start == '.'; double dotmult = sawdot ? 0.1 : 1; double value = (start >= '0' && start <= '9') ? start - '0' : 0; while (true) { int c = buf.get(); if (c == '.') { if (sawdot) { throw new PDFParseException("Can't have two '.' in a number"); } sawdot = true; dotmult = 0.1; } else if (c >= '0' && c <= '9') { int val = c - '0'; if (sawdot) { value += val * dotmult; dotmult *= 0.1; } else { value = value * 10 + val; } } else { buf.position(buf.position() - 1); break; } } if (neg) { value = -value; } return new PDFObject(this, PDFObject.NUMBER, new Double(value)); } /** * read a bare keyword. The initial character is passed in as the * argument. */ private PDFObject readKeyword(ByteBuffer buf, char start) throws IOException { // we've read the first character (it's passed in as the argument) StringBuffer sb = new StringBuffer(String.valueOf(start)); int c; while (isRegularCharacter(c = buf.get())) { sb.append((char) c); } buf.position(buf.position() - 1); return new PDFObject(this, PDFObject.KEYWORD, sb.toString()); } /** * read an entire PDFObject. The intro line, which looks something * like "4 0 obj" has already been read. * @param buf the buffer to read from * @param objNum the object number of the object being read, being * the first number in the intro line (4 in "4 0 obj") * @param objGen the object generation of the object being read, being * the second number in the intro line (0 in "4 0 obj"). * @param decrypter the decrypter to use */ private PDFObject readObjectDescription( ByteBuffer buf, int objNum, int objGen, PDFDecrypter decrypter) throws IOException { // we've already read the 4 0 obj bit. Next thing up is the object. // object descriptions end with the keyword endobj long debugpos = buf.position(); PDFObject obj= readObject(buf, objNum, objGen, decrypter); // see if it's a dictionary. If so, this could be a stream. PDFObject endkey= readObject(buf, objNum, objGen, decrypter); if (endkey.getType() != PDFObject.KEYWORD) { throw new PDFParseException("Expected 'stream' or 'endobj'"); } if (obj.getType() == PDFObject.DICTIONARY && endkey.getStringValue().equals("stream")) { // skip until we see \n readLine(buf); ByteBuffer data = readStream(buf, obj); if (data == null) { data = ByteBuffer.allocate(0); } obj.setStream(data); endkey= readObject(buf, objNum, objGen, decrypter); } // at this point, obj is the object, keyword should be "endobj" String endcheck = endkey.getStringValue(); if (endcheck == null || !endcheck.equals("endobj")) { System.out.println("WARNING: object at " + debugpos + " didn't end with 'endobj'"); //throw new PDFParseException("Object musst end with 'endobj'"); } obj.setObjectId(objNum, objGen); return obj; } /** * read the stream portion of a PDFObject. Calls decodeStream to * un-filter the stream as necessary. * * @param buf the buffer to read from * @param dict the dictionary associated with this stream. * @return a ByteBuffer with the encoded stream data */ private ByteBuffer readStream(ByteBuffer buf, PDFObject dict) throws IOException { // pointer is at the start of a stream. read the stream and // decode, based on the entries in the dictionary PDFObject lengthObj = dict.getDictRef("Length"); int length = -1; if (lengthObj != null) { length = lengthObj.getIntValue(); } if (length < 0) { throw new PDFParseException("Unknown length for stream"); } // slice the data int start = buf.position(); ByteBuffer streamBuf = buf.slice(); streamBuf.limit(length); // move the current position to the end of the data buf.position(buf.position() + length); int ending = buf.position(); if (!nextItemIs(buf, "endstream")) { System.out.println("read " + length + " chars from " + start + " to " + ending); throw new PDFParseException("Stream ended inappropriately"); } return streamBuf; // now decode stream // return PDFDecoder.decodeStream(dict, streamBuf); } /** * read the cross reference table from a PDF file. When this method * is called, the file pointer must point to the start of an xref table * (i.e., to the start of the "xref" keyword) or an xref stream object. * Reads the xref entries and populate xrefEntries. Also reads the * trailer/xref stream dictionary to set root, fileIdentifier and encryption * parameters. If /Prev entries are present, proceeds to read previous * trailers and xrefs, too. * @param password the password to use for decryption */ private void readTrailersAndXrefs(PDFPassword password) throws IOException, PDFAuthenticationFailureException, EncryptionUnsupportedByProductException, EncryptionUnsupportedByPlatformException { // the table of xrefs // read a bunch of nested trailer tables boolean furtherCrossrefsToRead = true; while (furtherCrossrefsToRead) { PDFObject header = readObject(fileBuf, -1, -1, IdentityDecrypter.getInstance()); if (header.getType() == PDFObject.KEYWORD && "xref".equals(header.getStringValue())) { furtherCrossrefsToRead = readCrossrefTableAndTrailer(password); } else if (isXrefStream(header)) { furtherCrossrefsToRead = readCrossrefStream(header, true); } else { throw new PDFParseException( "Expected xref table or xref stream, but found " + header); } } // make sure we found a root if (root == null) { throw new PDFParseException("No /Root key found in trailer dictionary"); } if (root.getDictRef("Version") != null) { processVersion(root.getDictRef("Version").getStringValue()); } // check what permissions are relevant if (encrypt != null) { defaultDecrypter = PDFDecrypterFactory.createDecryptor( encrypt, fileIdentifier, password); PDFObject permissions = encrypt.getDictRef("P"); if (permissions!=null && !defaultDecrypter.isOwnerAuthorised()) { int perms= permissions != null ? permissions.getIntValue() : 0; if (permissions!=null) { printable = (perms & 4) != 0; saveable = (perms & 16) != 0; } } } // dereference the root object root.dereference(); } /** * Identify whether a given PDFObject identifies itself as a crossreference * stream * @param header the object to test * @return whether the object is an xref stream * @throws IOException if there's a problem reading the header */ private boolean isXrefStream(PDFObject header) throws IOException { return header.getType() == PDFObject.STREAM && "XRef".equals(header.getDictRef("Type").getStringValue()); } /** * Read entries from a xref table, and its trailer dictionary, which * is expected to follow it * @param password the password * @return whether a previous crossref table/stream should be read; the * buffer will have been positioned at its start point * @throws IOException in case of a bad format, or IO problems */ private boolean readCrossrefTableAndTrailer(PDFPassword password) throws IOException { // we're positioned at the start of a cross reference table PDFObject headerObject; while (true) { // read until the word "trailer" headerObject = readObject(fileBuf, -1, -1, IdentityDecrypter.getInstance()); if (headerObject.getType() != PDFObject.NUMBER) { // we must be out of the cross-ref table! break; } // each subsection will start with // // // read them now: int objNumStart = headerObject.getIntValue(); // read the size of the reference table PDFObject sizeObj = readObject(fileBuf, -1, -1, IdentityDecrypter.getInstance()); if (sizeObj.getType() != PDFObject.NUMBER) { throw new PDFParseException("Expected number for length of xref table"); } int numEntries = sizeObj.getIntValue(); final int lastObjNum = objNumStart + numEntries; ensureXrefEntriesCapacity(lastObjNum + 1); consumeWhitespace(fileBuf); // read entry lines final byte[] refline = new byte[20]; for (int objNum = objNumStart; objNum < lastObjNum; objNum++) { // each reference line is 20 bytes long fileBuf.get(refline); // if xrefEntries already contains an entry for this // object number then we've earlier read a xref // for this object number from a later incremental // upgrade if (xrefEntries[objNum] == null) { PDFXrefEntry entry; final byte entryType = refline[17]; if (entryType == 'n') { // active entry int offset = Integer.parseInt(new String(refline, 0, 10)); int generation = Integer.parseInt(new String(refline, 11, 5)); final PDFXref ref = new PDFXref(objNum, generation); entry = PDFXrefEntry.toBodyObject(generation, offset); } else if (entryType == 'f') { // freed entry entry = PDFXrefEntry.forFreedObject(); } else { throw new PDFParseException("Unknown xref entry type: " + entryType); } xrefEntries[objNum] = entry; } } } // at this point, the "trailer" word (not EOL) has been read, hopefully! if (headerObject.getType() != PDFObject.KEYWORD || !"trailer".equals(headerObject.getStringValue())) { throw new PDFParseException( "Expected to find trailer immediately after xref table, " + "but found " + headerObject + " instead"); } PDFObject trailerdict = readObject(fileBuf, -1, -1, IdentityDecrypter.getInstance()); if (trailerdict.getType() != PDFObject.DICTIONARY) { throw new PDFParseException("Expected dictionary after \"trailer\""); } return processTrailerDict(trailerdict, false, true); } /** * Process a trailer or xref stream dictionary, recording root, info, * encrypt and fileIdentifier members as appropriate. If a Prev entry * is found, and followPrev is true, the buffer position is set to the * location of a further xref table/stream to read * @param trailerdict the trailer/xref-stream dictionary * @param xrefStreamSource if the trailer comes from an xref stream, as * opposed to an xref table * @param followPrev whether Prev entries should be followed * @return whether followPrev was set and a Prev entry was found, indicating * that the buffer is now positioned to have another xref stream/table read * @throws IOException if the file is badly formed, or in case of IO * difficulties */ private boolean processTrailerDict( PDFObject trailerdict, boolean xrefStreamSource, boolean followPrev) throws IOException { // read the root object location if (root == null) { root = trailerdict.getDictRef("Root"); if (root != null) { root.setObjectId(PDFObject.OBJ_NUM_TRAILER, PDFObject.OBJ_NUM_TRAILER); } } if (fileIdentifier == null) { fileIdentifier = trailerdict.getDictRef("ID"); } // read the encryption information if (encrypt == null) { encrypt = trailerdict.getDictRef("Encrypt"); if (encrypt != null) { encrypt.setObjectId(PDFObject.OBJ_NUM_TRAILER, PDFObject.OBJ_NUM_TRAILER); } } if (info == null) { info = trailerdict.getDictRef("Info"); if (info != null) { if (!info.isIndirect()) { throw new PDFParseException( "Info in trailer must be an indirect reference"); } info.setObjectId(PDFObject.OBJ_NUM_TRAILER, PDFObject.OBJ_NUM_TRAILER); } } if (!xrefStreamSource) { PDFObject xrefStm = trailerdict.getDictRef("XRefStm"); if (xrefStm != null) { // this is a hybrid reference file, read the // cross-reference stream before any Prevs fileBuf.position(xrefStm.getIntValue()); readCrossrefStream(null, false); } } PDFObject prevloc = null; if (followPrev) { // read the location of the previous xref table prevloc = trailerdict.getDictRef("Prev"); if (prevloc != null) { fileBuf.position(prevloc.getIntValue()); } } return prevloc != null; } /** * Read a Cross Reference Stream from the document * @param xrefStream the xrefStream; if null, the stream * will be read from the current fileBuf position * @param followPrev if the Prev entry from the dictionary should be * followed to read a previous xref stream * @return whether a Prev reference has been found and should be followed, * in which case fileBuf will have been positioned to the start of the * prev xref table/stream * @throws IOException if the PDF is poorly formed */ private boolean readCrossrefStream(PDFObject xrefStream, boolean followPrev) throws IOException { // the xref stream will have an object number but since there's no // decryption involved, it doesn't matter if (xrefStream == null) { xrefStream = readObject(fileBuf, -1, -1, IdentityDecrypter.getInstance()); if (!isXrefStream(xrefStream)) { throw new PDFParseException("Object found at offset for cross" + " reference stream is not a cross reference stream"); } } final int size = xrefStream.getDictRef("Size").getIntValue(); ensureXrefEntriesCapacity(size); final PDFObject[] wObjs = xrefStream.getDictRef("W").getArray(); final int[] fieldLengths = new int[3]; int entryLength = 0; for (int i = 0; i < 3; ++i) { fieldLengths[i] = wObjs[i].getIntValue(); entryLength += fieldLengths[i]; } final PDFObject[] index; final PDFObject indexObj = xrefStream.getDictRef("Index"); if (indexObj != null) { index = indexObj.getArray(); } else { index = new PDFObject[] { new PDFObject(0), new PDFObject(size) }; } final ByteBuffer table = xrefStream.getStreamBuffer(); for (int i = 0; i < index.length; i += 2) { final int start = index[i].getIntValue(); final int end = start + index[i + 1].getIntValue(); for (int objNum = start; objNum < end; ++objNum) { if (xrefEntries[objNum] == null) { PDFXrefEntry.Type type; if (fieldLengths[0] == 0) { type = PDFXrefEntry.Type.OBJ_IN_BODY; } else { type = PDFXrefEntry.Type.forTypeField( readInt(table, fieldLengths[0])); } int field2 = readInt(table, fieldLengths[1]); // note that this is supposed to default to 0 if field 3 // length is 0 for type 1 entries, and that will work just fine int field3 = readInt(table, fieldLengths[2]); xrefEntries[objNum] = type.makeXrefStreamEntry(field2, field3); } else { table.position(table.position() + entryLength); } } } return processTrailerDict(xrefStream, true, followPrev); } /** * Read an numBytes-bytes big-endian unsigned int from a table * @param table the table to read from * @param numBytes the number of bytes to read * @return the integer read; 0 if numBytes is 0 */ private int readInt(ByteBuffer table, int numBytes) { int val = 0; while (numBytes-- > 0) { final int b = table.get() & 0xFF; val = (val << 8) | b; } return val; } /** * Ensure that the xrefEntries table will support a given number of * objects from 0-size. If we were to read the Size entry from a * cross reference table before processing cross reference tables * then we could immediately set it to the correct size, but until we * do so, we'll just have to resize every now and then, though for * most documents, no resizes should be required. * @param size the required size of the xref table (i.e., the maximum * object number plus 1) */ private void ensureXrefEntriesCapacity(int size) { if (xrefEntries == null || xrefEntries.length < size) { final PDFXrefEntry[] newXrefEntries = new PDFXrefEntry[size]; if (xrefEntries != null) { System.arraycopy(xrefEntries, 0, newXrefEntries, 0, xrefEntries.length); } xrefEntries = newXrefEntries; } } /** * build the PDFFile reference table. Nothing in the PDFFile actually * gets parsed, despite the name of this function. Things only get * read and parsed when they're needed. * @param password */ private void parseFile(PDFPassword password) throws IOException { // start at the begining of the file fileBuf.rewind(); String versionLine = readLine(fileBuf); if (versionLine.startsWith(VERSION_COMMENT)) { processVersion(versionLine.substring(VERSION_COMMENT.length())); } fileBuf.rewind(); fileBuf.position(fileBuf.limit() - 1); if (!backscan(fileBuf, "startxref")) { throw new PDFParseException("This may not be a PDF File"); } int postStartXrefPos = fileBuf.position(); // ensure that we've got at least one piece of whitespace here, which // should be a carriage return if (!isWhiteSpace(fileBuf.get())) { throw new PDFParseException("Found suspicious startxref without " + "trialing whitespace"); } final StringBuilder xrefBuf = new StringBuilder(); char c = (char) nextNonWhitespaceChar(fileBuf); while (c >= '0' && c <= '9') { xrefBuf.append(c); c = (char) fileBuf.get(); } int xrefpos = Integer.parseInt(xrefBuf.toString()); fileBuf.position(xrefpos); try { readTrailersAndXrefs(password); } catch (UnsupportedEncryptionException e) { throw new PDFParseException(e.getMessage(), e); } } /** * Scans backwards from the current buffer position, looking for * the given scan token, which must exist in its entirety before * the current buffer position. When successful, the buffer position is * at the point immediately after the token. If not found, the buffer * position will be at 0. * @param buf the buffer to scan, positioned appropriately * @param scanToken the token to scan for * @return whether the token was found */ private boolean backscan(ByteBuffer buf, String scanToken) { byte[] scanbuf = new byte[32]; if (scanToken.length() * 2 > scanbuf.length) { // should be fine, though less than optimal, for current usages throw new IllegalArgumentException("scanToken is too long - " + "adjust buffer length"); } int scanPos = buf.position() - scanbuf.length; if (scanPos < 0) { // use a shorter scanbuf to do a single, most likely failing, scan scanbuf = new byte[buf.position()]; scanPos = 0; } while (scanPos >= 0) { buf.position(scanPos); buf.get(scanbuf); // find startxref in scan String scans = new String(scanbuf); int loc = scans.lastIndexOf(scanToken); if (loc > 0) { buf.position(scanPos + loc + scanToken.length()); return true; } int newScanPos = scanPos - scanbuf.length + scanToken.length() - 1; if (newScanPos < 0) { scanPos = scanPos == 0 ? -1 : newScanPos; } else { scanPos = newScanPos; } } return false; } /** * Gets the outline tree as a tree of OutlineNode, which is a subclass * of DefaultMutableTreeNode. If there is no outline tree, this method * returns null. */ public OutlineNode getOutline() throws IOException { // find the outlines entry in the root object PDFObject oroot = root.getDictRef("Outlines"); OutlineNode work = null; OutlineNode outline = null; if (oroot != null) { // find the first child of the outline root PDFObject scan = oroot.getDictRef("First"); outline = work = new OutlineNode(""); // scan each sibling in turn while (scan != null) { // add the new node with it's name String title = scan.getDictRef("Title").getTextStringValue(); OutlineNode build = new OutlineNode(title); work.add(build); // find the action PDFAction action = null; PDFObject actionObj = scan.getDictRef("A"); if (actionObj != null) { action = PDFAction.getAction(actionObj, getRoot()); } else { // try to create an action from a destination PDFObject destObj = scan.getDictRef("Dest"); if (destObj != null) { try { PDFDestination dest = PDFDestination.getDestination(destObj, getRoot()); action = new GoToAction(dest); } catch (IOException ioe) { // oh well } } } // did we find an action? If so, add it if (action != null) { build.setAction(action); } // find the first child of this node PDFObject kid = scan.getDictRef("First"); if (kid != null) { work = build; scan = kid; } else { // no child. Process the next sibling PDFObject next = scan.getDictRef("Next"); while (next == null) { scan = scan.getDictRef("Parent"); next = scan.getDictRef("Next"); work = (OutlineNode) work.getParent(); if (work == null) { break; } } scan = next; } } } return outline; } /** * Gets the page number (starting from 1) of the page represented by * a particular PDFObject. The PDFObject must be a Page dictionary or * a destination description (or an action). * @return a number between 1 and the number of pages indicating the * page number, or 0 if the PDFObject is not in the page tree. */ public int getPageNumber(PDFObject page) throws IOException { if (page.getType() == PDFObject.ARRAY) { page = page.getAt(0); } // now we've got a page. Make sure. PDFObject typeObj = page.getDictRef("Type"); if (typeObj == null || !typeObj.getStringValue().equals("Page")) { return 0; } int count = 0; while (true) { PDFObject parent = page.getDictRef("Parent"); if (parent == null) { break; } PDFObject kids[] = parent.getDictRef("Kids").getArray(); for (int i = 0; i < kids.length; i++) { if (kids[i].equals(page)) { break; } else { PDFObject kcount = kids[i].getDictRef("Count"); if (kcount != null) { count += kcount.getIntValue(); } else { count += 1; } } } page = parent; } return count; } /** * Get the page commands for a given page in a separate thread. * * @param pagenum the number of the page to get commands for */ public PDFPage getPage(int pagenum) { return getPage(pagenum, false); } /** * Get the page commands for a given page. * * @param pagenum the number of the page to get commands for * @param wait if true, do not exit until the page is complete. */ public PDFPage getPage(int pagenum, boolean wait) { Integer key = new Integer(pagenum); HashMap resources = null; PDFObject pageObj = null; boolean needread = false; PDFPage page = cache.getPage(key); PDFParser parser = cache.getPageParser(key); if (page == null) { try { // hunt down the page! resources = new HashMap(); PDFObject topPagesObj = root.getDictRef("Pages"); pageObj = findPage(topPagesObj, 0, pagenum, resources); if (pageObj == null) { return null; } page = createPage(pagenum, pageObj); byte[] stream = getContents(pageObj); parser = new PDFParser(page, stream, resources); cache.addPage(key, page, parser); } catch (IOException ioe) { System.out.println("GetPage inner loop:"); ioe.printStackTrace(); return null; } } if (parser != null && !parser.isFinished()) { parser.go(wait); } return page; } /** * Stop the rendering of a particular image on this page */ public void stop(int pageNum) { PDFParser parser = cache.getPageParser(new Integer(pageNum)); if (parser != null) { // stop it parser.stop(); } } /** * get the stream representing the content of a particular page. * * @param pageObj the page object to get the contents of * @return a concatenation of any content streams for the requested * page. */ private byte[] getContents(PDFObject pageObj) throws IOException { // concatenate all the streams PDFObject contentsObj = pageObj.getDictRef("Contents"); if (contentsObj == null) { throw new IOException("No page contents!"); } PDFObject contents[] = contentsObj.getArray(); // see if we have only one stream (the easy case) if (contents.length == 1) { return contents[0].getStream(); } // first get the total length of all the streams int len = 0; for (int i = 0; i < contents.length; i++) { byte[] data = contents[i].getStream(); if (data == null) { throw new PDFParseException("No stream on content " + i + ": " + contents[i]); } len += data.length; } // now assemble them all into one object byte[] stream = new byte[len]; len = 0; for (int i = 0; i < contents.length; i++) { byte data[] = contents[i].getStream(); System.arraycopy(data, 0, stream, len, data.length); len += data.length; } return stream; } /** * Create a PDF Page object by finding the relevant inherited * properties * * @param pageObj the PDF object for the page to be created */ private PDFPage createPage(int pagenum, PDFObject pageObj) throws IOException { int rotation = 0; Rectangle2D mediabox = null; // second choice, if no crop Rectangle2D cropbox = null; // first choice PDFObject mediaboxObj = getInheritedValue(pageObj, "MediaBox"); if (mediaboxObj != null) { mediabox = parseNormalisedRectangle(mediaboxObj); } PDFObject cropboxObj = getInheritedValue(pageObj, "CropBox"); if (cropboxObj != null) { cropbox = parseNormalisedRectangle(cropboxObj); } PDFObject rotateObj = getInheritedValue(pageObj, "Rotate"); if (rotateObj != null) { rotation = rotateObj.getIntValue(); } Rectangle2D bbox = ((cropbox == null) ? mediabox : cropbox); return new PDFPage(pagenum, bbox, rotation, cache); } /** * Get the PDFObject representing the content of a particular page. Note * that the number of the page need not have anything to do with the * label on that page. If there are two blank pages, and then roman * numerals for the page number, then passing in 6 will get page (iv). * * @param pagedict the top of the pages tree * @param start the page number of the first page in this dictionary * @param getPage the number of the page to find; NOT the page's label. * @param resources a HashMap that will be filled with any resource * definitions encountered on the search for the page */ private PDFObject findPage(PDFObject pagedict, int start, int getPage, Map resources) throws IOException { PDFObject rsrcObj = pagedict.getDictRef("Resources"); if (rsrcObj != null) { resources.putAll(rsrcObj.getDictionary()); } PDFObject typeObj = pagedict.getDictRef("Type"); if (typeObj != null && typeObj.getStringValue().equals("Page")) { // we found our page! return pagedict; } // find the first child for which (start + count) > getPage PDFObject kidsObj = pagedict.getDictRef("Kids"); if (kidsObj != null) { PDFObject[] kids = kidsObj.getArray(); for (int i = 0; i < kids.length; i++) { int count = 1; // BUG: some PDFs (T1Format.pdf) don't have the Type tag. // use the Count tag to indicate a Pages dictionary instead. PDFObject countItem = kids[i].getDictRef("Count"); // if (kids[i].getDictRef("Type").getStringValue().equals("Pages")) { if (countItem != null) { count = countItem.getIntValue(); } if (start + count >= getPage) { return findPage(kids[i], start, getPage, resources); } start += count; } } return null; } /** * Find a property value in a page that may be inherited. If the value * is not defined in the page itself, follow the page's "parent" links * until the value is found or the top of the tree is reached. * * @param pageObj the object representing the page * @param propName the name of the property we are looking for */ private PDFObject getInheritedValue(PDFObject pageObj, String propName) throws IOException { // see if we have the property PDFObject propObj = pageObj.getDictRef(propName); if (propObj != null) { return propObj; } // recursively see if any of our parent have it PDFObject parentObj = pageObj.getDictRef("Parent"); if (parentObj != null) { return getInheritedValue(parentObj, propName); } // no luck return null; } public static Rectangle2D parseNormalisedRectangle(PDFObject obj) throws IOException { if (obj != null) { if (obj.getType() == PDFObject.ARRAY) { PDFObject bounds[] = obj.getArray(); if (bounds.length == 4) { final double x0 = bounds[0].getDoubleValue(); final double y0 = bounds[1].getDoubleValue(); final double x1 = bounds[2].getDoubleValue(); final double y1 = bounds[3].getDoubleValue(); final double minX; final double maxY; final double maxX; final double minY; if (x0 < x1) { minX = x0; maxX = x1; } else { minX = x1; maxX = x0; } if (y0 < y1) { minY = y0; maxY = y1; } else { minY = y1; maxY = y0; } return new Rectangle2D.Double(minX, minY, Math.abs(maxX - minX), Math.abs(maxY - minY)); } else { throw new PDFParseException("Rectangle definition didn't have 4 elements"); } } else { throw new PDFParseException("Rectangle definition not an array"); } } else { throw new PDFParseException("Rectangle not present"); } } /** * Get the default decrypter for the document * @return the default decrypter; never null, even for documents that * aren't encrypted */ public PDFDecrypter getDefaultDecrypter() { return defaultDecrypter; } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/0000755000175000017500000000000011622545441021252 5ustar twernertwernerpdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/PDFPassword.java0000644000175000017500000002476311156177553024274 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFDocCharsetEncoder; import com.sun.pdfview.Identity8BitCharsetEncoder; import com.sun.pdfview.PDFStringUtil; import java.util.*; import java.nio.charset.CodingErrorAction; import java.nio.charset.CharacterCodingException; import java.nio.charset.CharsetEncoder; import java.nio.CharBuffer; import java.nio.ByteBuffer; /** *

    Identifies a PDF Password, expressible either as a string or a * byte sequence.

    * *

    In revisions up to version 1.e Expansion 3, the mapping between a string * and the bytes corresponding to the password was poorly specified, meaning * that the safest manner in which to specify a password was via a byte array. * With 1.7 expansion 3, a still slightly problematic mapping was given for the * Standard encryption algorithms through to version 4, and a very well * specified mapping for the new version 5 encryption.

    * *

    So, for passwords specified in versions up to and including 4, a byte[] * representation is the most accurate, but not necessarily the most convenient * manner to provide passwords. For version 5, allowing passwords to be * specified as Strings will be the preferred mechanism. Rather than specify two * interfaces whenever a password can be provided - one for byte[] and one for * String - we express the password as a class. This class can also offer a best * guess at a String representation for a password for encryption versions up to * and including 4.

    * * @author Luke Kirby */ public class PDFPassword { /** The empty password */ public static final PDFPassword EMPTY_PASSWORD = new PDFPassword(new byte[0]); /** * Ensure a non-null PDFPassword by substituting the empty password * for a null password * @param password the password, may be null * @return a non-null password */ public static PDFPassword nonNullPassword(PDFPassword password) { return password != null ? password : EMPTY_PASSWORD; } /** the password in bytes, if specified as such */ private byte[] passwordBytes = null; /** the passwird as a string, if specified as such */ private String passwordString = null; /** * Construct a byte-based password * @param passwordBytes the password bytes */ public PDFPassword(byte[] passwordBytes) { this.passwordBytes = passwordBytes != null ? passwordBytes : new byte[0]; } /** * Construct a string-based password * @param passwordString the password */ public PDFPassword(String passwordString) { this.passwordString = passwordString != null ? passwordString : ""; } /** * Get the password bytes. * * @param unicodeConversion whether the specific conversion from a unicode * String, as present for version 5 encryption, should be used * @return a list of possible password bytes */ List getPasswordBytes(boolean unicodeConversion) { // TODO - handle unicodeConversion when we support version 5 if (this.passwordBytes != null || this.passwordString == null) { return Collections.singletonList(this.passwordBytes); } else { if (isAlphaNum7BitString(this.passwordString)) { // there's no reasonthat this string would get encoded // in any other way return Collections.singletonList( PDFStringUtil.asBytes(passwordString)); } else { return generatePossiblePasswordBytes(passwordString); } } } /** * An array of password byte generators that attempts to enumerate the * possible strategies that an encrypting application might take to convert * a string to an array of bytes */ private final static PasswordByteGenerator[] PASSWORD_BYTE_GENERATORS = new PasswordByteGenerator[]{ // The best option, and that recommended by the spec, is // straight PDFDocEncoding of the string but its not // mentioned what to do with undefined characters // (presumably, an encryption generating app should not // allow them, but there are no guarantees!). Plus, that // hasn't always been the case. There's also a possiblity // that we'll be presented with the byte encoding from // whatever code page is default on the system that // generated the password. I don't think we're going to try // all different code pages, though. Here are // a few ideas, anyway! // skip undefined chars new PDFDocEncodingByteGenerator(null), // replace undefined chars with 0 new PDFDocEncodingByteGenerator(Byte.valueOf((byte) 0)), // replace undefined chars with ? new PDFDocEncodingByteGenerator(Byte.valueOf((byte) '?')), // just strip the higher 8 bits! new PasswordByteGenerator() { public byte[] generateBytes(String password) { return PDFStringUtil.asBytes(password); } }, // skip 2-byte chars new IdentityEncodingByteGenerator(null), // replace 2-byte chars with 0 new IdentityEncodingByteGenerator(Byte.valueOf((byte) 0)), // replace 2-byte chars with ? new IdentityEncodingByteGenerator(Byte.valueOf((byte) '?')) }; /** * Generate some possible byte representations of a string password * * @param passwordString the string password * @return a list of unique possible byte representations */ private static List generatePossiblePasswordBytes( String passwordString) { final List possibilties = new ArrayList(); for (final PasswordByteGenerator generator : PASSWORD_BYTE_GENERATORS) { byte[] generated = generator.generateBytes(passwordString); // avoid duplicates boolean alreadyGenerated = false; for (int i = 0; !alreadyGenerated && i < possibilties.size(); ++i) { if (Arrays.equals(possibilties.get(i), generated)) { alreadyGenerated = true; } } if (!alreadyGenerated) { possibilties.add(generated); } } return possibilties; } private boolean isAlphaNum7BitString(String string) { for (int i = 0; i < string.length(); ++i) { final char c = string.charAt(i); if (c >= 127 || !Character.isLetterOrDigit(c)) { return false; } } return true; } /** * Converts a string password to a byte[] representation */ private static interface PasswordByteGenerator { byte[] generateBytes(String password); } /** * Converts strings to byte by employing a {@link CharsetEncoder} and a * configurable mechanism to replace or ignore characters that are * unrepresentable according to the encoder. */ private static abstract class CharsetEncoderGenerator implements PasswordByteGenerator { private Byte replacementByte; /** * Class constructor * * @param replacementByte the byte to replace to use to represent any * unrepresentable character, or null if unrepresentable characters * should just be ignored */ protected CharsetEncoderGenerator(Byte replacementByte) { this.replacementByte = replacementByte; } public byte[] generateBytes(String password) { final CharsetEncoder encoder = createCharsetEncoder(); if (replacementByte != null) { encoder.replaceWith(new byte[]{replacementByte}); encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); } else { encoder.onUnmappableCharacter(CodingErrorAction.IGNORE); } try { final ByteBuffer b = encoder.encode(CharBuffer.wrap(password)); final byte[] bytes = new byte[b.remaining()]; b.get(bytes); return bytes; } catch (CharacterCodingException e) { // shouldn't happen: unmappable characters should be the only // problem, and we're not handling them with a report return null; } } protected abstract CharsetEncoder createCharsetEncoder(); } /** * Generate byte[] representations based on the PDFDocEncoding */ private static class PDFDocEncodingByteGenerator extends CharsetEncoderGenerator { private PDFDocEncodingByteGenerator(Byte replacementByte) { super(replacementByte); } protected CharsetEncoder createCharsetEncoder() { return new PDFDocCharsetEncoder(); } } /** * Generate byte[] representations based on a Unicode code point identity * encoding; characters over 255 in value are considered unrepresentable */ private static class IdentityEncodingByteGenerator extends CharsetEncoderGenerator { private IdentityEncodingByteGenerator(Byte replacementByte) { super(replacementByte); } protected CharsetEncoder createCharsetEncoder() { return new Identity8BitCharsetEncoder(); } } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/PDFAuthenticationFailureException.java0000644000175000017500000000244711156177553030633 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFParseException; /** * Identifies that the supplied password was incorrect or non-existent * and required. * @author Luke Kirby */ // TODO - consider having this not extend PDFParseException so that // it will be handled more explicitly? public class PDFAuthenticationFailureException extends PDFParseException { public PDFAuthenticationFailureException(String message) { super(message); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/UnsupportedEncryptionException.java0000644000175000017500000000257111156177553030413 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; /** * Identifies that the specified encryption mechanism is not * supported by this product or platform. * * @see EncryptionUnsupportedByPlatformException * @see EncryptionUnsupportedByProductException * @author Luke Kirby */ public abstract class UnsupportedEncryptionException extends Exception { protected UnsupportedEncryptionException(String message) { super(message); } protected UnsupportedEncryptionException(String message, Throwable cause) { super(message, cause); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/EncryptionUnsupportedByPlatformException.java0000644000175000017500000000277311156177553032417 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; /** * Identifies that the specified encryption mechanism, though supported by the * product, is not supported by the platform that it is running on; i.e., that * either the JCE does not support a required cipher or that its policy is * such that a key of a given length can not be used. * * @author Luke Kirby */ public class EncryptionUnsupportedByPlatformException extends UnsupportedEncryptionException { public EncryptionUnsupportedByPlatformException(String message) { super(message); } public EncryptionUnsupportedByPlatformException(String message, Throwable cause) { super(message, cause); } }pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/EncryptionUnsupportedByProductException.java0000644000175000017500000000246211156177553032246 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; /** * Identifies that the specified encryption mechanism is not * supported by this product, that is, PDFRenderer, as opposed to * a {@link EncryptionUnsupportedByPlatformException limitation in * the platform}. * * @author Luke Kirby */ public class EncryptionUnsupportedByProductException extends UnsupportedEncryptionException { public EncryptionUnsupportedByProductException(String message) { super(message); } }pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/CryptFilterDecrypter.java0000644000175000017500000001230711526563523026255 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import java.nio.ByteBuffer; import java.util.Map; /** * Implements Version 4 standard decryption, whereby the Encrypt dictionary * contains a list of named 'crypt filters', each of which is the equivalent * of a {@link PDFDecrypter}. In addition to this list of crypt filters, * the name of the filter to use for streams and the default filter to use * for strings is specified. Requests to decode a stream with a named * decrypter (typically Identity) instead of the default decrypter * are honoured. * * @author Luke Kirby */ public class CryptFilterDecrypter implements PDFDecrypter { /** Maps from crypt filter names to their corresponding decrypters */ private Map decrypters; /** The default decrypter for stream content */ private PDFDecrypter defaultStreamDecrypter; /** The default decrypter for string content */ private PDFDecrypter defaultStringDecrypter; /** * Class constructor * @param decrypters a map of crypt filter names to their corresponding * decrypters. Must already contain the Identity filter. * @param defaultStreamCryptName the crypt filter name of the default * stream decrypter * @param defaultStringCryptName the crypt filter name of the default * string decrypter * @throws PDFParseException if one of the named defaults is not * present in decrypters */ public CryptFilterDecrypter( Map decrypters, String defaultStreamCryptName, String defaultStringCryptName) throws PDFParseException { this.decrypters = decrypters; assert this.decrypters.containsKey("Identity") : "Crypt Filter map does not contain required Identity filter"; defaultStreamDecrypter = this.decrypters.get(defaultStreamCryptName); if (defaultStreamDecrypter == null) { throw new PDFParseException( "Unknown crypt filter specified as default for streams: " + defaultStreamCryptName); } defaultStringDecrypter = this.decrypters.get(defaultStringCryptName); if (defaultStringDecrypter == null) { throw new PDFParseException( "Unknown crypt filter specified as default for strings: " + defaultStringCryptName); } } public ByteBuffer decryptBuffer( String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) throws PDFParseException { final PDFDecrypter decrypter; if (cryptFilterName == null) { decrypter = defaultStreamDecrypter; } else { decrypter = decrypters.get(cryptFilterName); if (decrypter == null) { throw new PDFParseException("Unknown CryptFilter: " + cryptFilterName); } } return decrypter.decryptBuffer( // elide the filter name to prevent V2 decrypters from // complaining about a crypt filter name null, // if there's a specific crypt filter being used then objNum // and objGen shouldn't contribute to the key, so we // should make sure that no streamObj makes its way through cryptFilterName != null ? null : streamObj, streamBuf); } public String decryptString(int objNum, int objGen, String inputBasicString) throws PDFParseException { return defaultStringDecrypter.decryptString(objNum, objGen, inputBasicString); } public boolean isEncryptionPresent() { for (final PDFDecrypter decrypter : decrypters.values()) { if (decrypter.isEncryptionPresent()) { return true; } } return false; } public boolean isEncryptionPresent(String cryptFilterName) { PDFDecrypter decrypter = decrypters.get(cryptFilterName); return decrypter != null && decrypter.isEncryptionPresent(cryptFilterName); } public boolean isOwnerAuthorised() { for (final PDFDecrypter decrypter : decrypters.values()) { if (decrypter.isOwnerAuthorised()) { return true; } } return false; } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/StandardDecrypter.java0000644000175000017500000013311311526563523025545 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.PDFStringUtil; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.nio.ByteBuffer; import java.security.*; import java.util.List; import java.util.Arrays; /** * Standard simple decrypter for versions 1, 2 and 4 of the Standard * password-based decryption mechanisms, as described in section 3.5 of * the PDF Reference version 1.7. * * @author Luke Kirby */ public class StandardDecrypter implements PDFDecrypter { /** * Extra salt to add to AES-based decryption keys, as per PDF Reference 1.7 */ private static final byte[] AESV2_SALT = {'s', 'A', 'l', 'T'}; /** * Describes an encryption algorithm to be used, declaring not only the * cipher type, but also key generation techniques */ public enum EncryptionAlgorithm { RC4, AESV2; boolean isRC4() { return this == RC4; } boolean isAES() { return this == AESV2; } } /** * Padding used to bring passwords up to 32 bytes, as specified by the * first step of Algorithm 3.2 in the PDF Reference version 1.7. */ private final static byte[] PW_PADDING = new byte[]{ 0x28, (byte) 0xBF, 0x4E, 0x5E, 0x4E, 0x75, (byte) 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, (byte) 0xFF, (byte) 0xFA, 0x01, 0x08, 0x2E, 0x2E, 0x00, (byte) 0xB6, (byte) 0xD0, 0x68, 0x3E, (byte) 0x80, 0x2F, 0x0C, (byte) 0xA9, (byte) 0xFE, 0x64, 0x53, 0x69, 0x7A }; /** * The specification of the RC4 cipher for JCE interactions */ private static final String CIPHER_RC4 = "RC4"; /** * The key type for RC4 keys */ private static final String KEY_RC4 = "RC4"; /** * The specification of the AES cipher for JCE interactions. As per the * spec, cipher-block chanining (CBC) mode and PKCS5 padding are used */ private static final String CIPHER_AES = "AES/CBC/PKCS5Padding"; /** * The key type for AES keys */ private static final String KEY_AES = "AES"; /** * Whether the owner password was specified */ private boolean ownerAuthorised = false; /** * The general encryption key; may be mutated to form individual * stream/string encryption keys */ private byte[] generalKeyBytes; /** * The encryption algorithm being employed */ private EncryptionAlgorithm encryptionAlgorithm; /** * Class constructor * * @param encryptionAlgorithm the algorithm used for encryption * @param documentId the contents of the ID entry of the document's trailer * dictionary; can be null, but according to the spec, shouldn't be. Is * expected to be an array of two byte sequences. * @param keyBitLength the length of the key in bits; should be a multiple * of 8 between 40 and 128 * @param revision the revision of the Standard encryption security handler * being employed. Should be 2, 3 or 4. * @param oValue the value of the O entry from the Encrypt dictionary * @param uValue the value of the U entry from the Encrypt dictionary * @param pValue the value of the P entry from the Encrypt dictionary * @param encryptMetadata whether metadata is being encrypted, as identified * by the Encrypt dict (with default true if not explicitly identified) * @param password the password; not null * @throws IOException if there's a problem reading the file * @throws EncryptionUnsupportedByPlatformException if the encryption is not * supported by the environment in which the code is executing * @throws EncryptionUnsupportedByProductException if PDFRenderer does not * currently support the specified encryption */ public StandardDecrypter( EncryptionAlgorithm encryptionAlgorithm, PDFObject documentId, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata, PDFPassword password) throws IOException, EncryptionUnsupportedByProductException, EncryptionUnsupportedByPlatformException { this.encryptionAlgorithm = encryptionAlgorithm; // The spec (sensibly) demands that the documentId be present, // but we'll play it safe final byte[] firstDocIdValue; if (documentId == null) { firstDocIdValue = null; } else { firstDocIdValue = documentId.getAt(0).getStream(); } testJceAvailability(keyBitLength); try { final List passwordBytePossibilities = password.getPasswordBytes(false); for (int i = 0; generalKeyBytes == null && i < passwordBytePossibilities.size(); ++i) { final byte[] passwordBytes = passwordBytePossibilities.get(i); generalKeyBytes = checkOwnerPassword( passwordBytes, firstDocIdValue, keyBitLength, revision, oValue, uValue, pValue, encryptMetadata); if (generalKeyBytes != null) { // looks like the password was the owner password! ownerAuthorised = true; } else { // try it as the user password generalKeyBytes = checkUserPassword( passwordBytes, firstDocIdValue, keyBitLength, revision, oValue, uValue, pValue, encryptMetadata); } } } catch (GeneralSecurityException e) { // Unexpected, as our test of JCE availability should have caught // problems with cipher availability. // It may well be a problem with document content? throw new PDFParseException("Unable to check passwords: " + e.getMessage(), e); } if (generalKeyBytes == null) { throw new PDFAuthenticationFailureException( "Password failed authentication for both " + "owner and user password"); } } public ByteBuffer decryptBuffer( String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) throws PDFParseException { if (cryptFilterName != null) { throw new PDFParseException( "This encryption version does not support Crypt filters"); } if (streamObj != null) { checkNums(streamObj.getObjNum(), streamObj.getObjGen()); } final byte[] decryptionKeyBytes; if (streamObj == null) { // lack of a stream object indicates the unsalted key should be // used decryptionKeyBytes = getUnsaltedDecryptionKey(); } else { decryptionKeyBytes = getObjectSaltedDecryptionKey( streamObj.getObjNum(), streamObj.getObjGen()); } return decryptBuffer(streamBuf, decryptionKeyBytes); } public String decryptString(int objNum, int objGen, String inputBasicString) throws PDFParseException { final byte[] crypted = PDFStringUtil.asBytes(inputBasicString); final byte[] decryptionKey = getObjectSaltedDecryptionKey(objNum, objGen); final ByteBuffer decrypted = decryptBuffer(ByteBuffer.wrap(crypted), decryptionKey); return PDFStringUtil.asBasicString(decrypted.array(), decrypted.arrayOffset(), decrypted.limit()); } public boolean isOwnerAuthorised() { return ownerAuthorised; } public boolean isEncryptionPresent() { return true; } public boolean isEncryptionPresent(String cryptFilterName) { return true; } /** * Test that the platform (i.e., the JCE) can offer us all of the ciphers at * the key length we need for content decryption. This shouldn't be a * problem on the Java 5 platform unless a particularly restrictive policy * file is in place. Calling this on construction should avoid problems like * these being exposed as PDFParseExceptions as they're used during * decryption and key establishment. * * @param keyBitLength the length of the content key, in bits * @throws EncryptionUnsupportedByPlatformException if the platform does not * support the required ciphers and key lengths * @throws PDFParseException if there's an internal error while testing * cipher availability */ private void testJceAvailability(int keyBitLength) throws EncryptionUnsupportedByPlatformException, PDFParseException { // we need to supply a little buffer for AES, which will look // for an initialisation vector of 16 bytes final byte[] junkBuffer = new byte[16]; Arrays.fill(junkBuffer, (byte) 0xAE); // test using the longer key length for salted content so that // we can check for maximum key length problems final byte[] junkKey = new byte[getSaltedContentKeyByteLength(keyBitLength / 8)]; Arrays.fill(junkKey, (byte) 0xAE); try { createAndInitialiseContentCipher( ByteBuffer.wrap(junkBuffer), junkKey); } catch (PDFParseException e) { throw new PDFParseException("Internal error; " + "failed to produce test cipher: " + e.getMessage()); } catch (NoSuchAlgorithmException e) { throw new EncryptionUnsupportedByPlatformException( "JCE does not offer required cipher", e); } catch (NoSuchPaddingException e) { throw new EncryptionUnsupportedByPlatformException( "JCE does not offer required padding", e); } catch (InvalidKeyException e) { throw new EncryptionUnsupportedByPlatformException( "JCE does accept key size of " + (getSaltedContentKeyByteLength() * 8) + " bits- could it be a policy restriction?", e); } catch (InvalidAlgorithmParameterException e) { throw new EncryptionUnsupportedByPlatformException( "JCE did not accept cipher parameter", e); } try { createMD5Digest(); } catch (NoSuchAlgorithmException e) { throw new EncryptionUnsupportedByPlatformException( "No MD5 digest available from JCE", e); } if (encryptionAlgorithm != EncryptionAlgorithm.RC4) { // we still need RC4 for U and O value checks. Check again! final Cipher rc4; try { rc4 = createRC4Cipher(); } catch (GeneralSecurityException e) { throw new EncryptionUnsupportedByPlatformException( "JCE did not offer RC4 cipher", e); } // 40 byte key is used for base U and O ciphers final byte[] rc4JunkKey = new byte[5]; Arrays.fill(junkKey, (byte) 0xAE); try { initDecryption(rc4, createRC4Key(rc4JunkKey)); } catch (InvalidKeyException ex) { throw new EncryptionUnsupportedByPlatformException( "JCE did not accept 40-bit RC4 key; " + "policy problem?", ex); } } } /** * Decrypt a buffer * * @param encrypted the encrypted content * @param decryptionKeyBytes the key to use for decryption * @return a freshly allocated buffer containing the decrypted content * @throws PDFParseException if there's a problem decrypting the content */ private ByteBuffer decryptBuffer( ByteBuffer encrypted, byte[] decryptionKeyBytes) throws PDFParseException { final Cipher cipher; try { cipher = createAndInitialiseContentCipher( encrypted, decryptionKeyBytes); } catch (GeneralSecurityException e) { // we should have caught this earlier in testCipherAvailability throw new PDFParseException( "Unable to create cipher due to platform limitation: " + e.getMessage(), e); } try { // the decrypted content will never be more than the encrypted // content. Thanks to padding, this buffer will be at most 16 // bytes bigger than the encrypted content final ByteBuffer decryptedBuf = ByteBuffer.allocate(encrypted.remaining()); cipher.doFinal(encrypted, decryptedBuf); decryptedBuf.flip(); return decryptedBuf; } catch (GeneralSecurityException e) { throw new PDFParseException( "Could not decrypt: " + e.getMessage(), e); } } /** * Setup the cipher for decryption * * @param encrypted the encrypted content; required by AES encryption so * that the initialisation vector can be established * @param decryptionKeyBytes the bytes for the decryption key * @return a content decryption cypher, ready to accept input * @throws PDFParseException if the encrypted buffer is malformed or on an * internal error * @throws NoSuchAlgorithmException if the cipher algorithm is not supported * by the platform * @throws NoSuchPaddingException if the cipher padding is not supported by * the platform * @throws InvalidKeyException if the key is invalid according to the * cipher, or too long * @throws InvalidAlgorithmParameterException if the cipher parameters are * bad */ private Cipher createAndInitialiseContentCipher( ByteBuffer encrypted, byte[] decryptionKeyBytes) throws PDFParseException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { final Cipher cipher; if (encryptionAlgorithm.isRC4()) { cipher = Cipher.getInstance(CIPHER_RC4); cipher.init(Cipher.DECRYPT_MODE, createRC4Key(decryptionKeyBytes)); } else if (encryptionAlgorithm.isAES()) { cipher = createAESCipher(); final byte[] initialisationVector = new byte[16]; if (encrypted.remaining() >= initialisationVector.length) { encrypted.get(initialisationVector); } else { throw new PDFParseException( "AES encrypted stream too short - " + "no room for initialisation vector"); } final SecretKeySpec aesKey = new SecretKeySpec(decryptionKeyBytes, KEY_AES); final IvParameterSpec aesIv = new IvParameterSpec(initialisationVector); cipher.init(Cipher.DECRYPT_MODE, aesKey, aesIv); } else { throw new PDFParseException( "Internal error - unhandled cipher type: " + encryptionAlgorithm); } return cipher; } /** * Get the unsalted content decryption key, used for streams with specific * crypt filters, which aren't specific to particular objects * * @return the general key */ private byte[] getUnsaltedDecryptionKey() { return generalKeyBytes; } /** * Get a decryption key salted with an object number and object generation, * for use when decrypting a string or stream within an object numbered so * * @param objNum the object number * @param objGen the object generation * @return the key to be used for decrypting data associated with the object * numbered so * @throws PDFParseException if the MD5 digest is not available */ private byte[] getObjectSaltedDecryptionKey(int objNum, int objGen) throws PDFParseException { byte[] decryptionKeyBytes; final MessageDigest md5; try { md5 = createMD5Digest(); } catch (NoSuchAlgorithmException e) { // unexpected, as we will already have tested availability throw new PDFParseException("Unable to get MD5 digester", e); } md5.update(this.generalKeyBytes); md5.update((byte) objNum); md5.update((byte) (objNum >> 8)); md5.update((byte) (objNum >> 16)); md5.update((byte) objGen); md5.update((byte) (objGen >> 8)); if (encryptionAlgorithm == EncryptionAlgorithm.AESV2) { md5.update(AESV2_SALT); } final byte[] hash = md5.digest(); final int keyLen = getSaltedContentKeyByteLength(); decryptionKeyBytes = new byte[keyLen]; System.arraycopy(hash, 0, decryptionKeyBytes, 0, keyLen); return decryptionKeyBytes; } /** * Get the length of a salted key * * @return length in bytes */ private int getSaltedContentKeyByteLength() { return getSaltedContentKeyByteLength(generalKeyBytes.length); } /** * Get the length of salted keys, in bytes. Unsalted keys will be the same * length as {@link #generalKeyBytes} * * @param generalKeyByteLength the length of the general key, in bytes * @return byte length of salted keys */ private int getSaltedContentKeyByteLength(int generalKeyByteLength) { return Math.min(generalKeyByteLength + 5, 16); } /** * Check that object number and object generations are well-formed. It is * possible for some {@link PDFObject}s to have uninitialised object numbers * and generations, but such objects should not required decryption * * @param objNum the object number * @param objGen the object generation * @throws PDFParseException if the object numbering indicates that they * aren't true object numbers */ private void checkNums(int objNum, int objGen) throws PDFParseException { if (objNum < 0) { throw new PDFParseException( "Internal error: Object has bogus object number"); } else if (objGen < 0) { throw new PDFParseException( "Internal error: Object has bogus generation number"); } } /** * Calculate what the U value should consist of given a particular key and * document configuration. Correponds to Algorithms 3.4 and 3.5 of the * PDF Reference version 1.7 * * @param generalKey the general encryption key * @param firstDocIdValue the value of the first element in the document's * ID entry in the trailer dictionary * @param revision the revision of the security handler * @return the U value for the given configuration * @throws GeneralSecurityException if there's an error getting required * ciphers, etc. (unexpected, since a check for algorithm availability is * performed on construction) * @throws EncryptionUnsupportedByProductException if the revision is not * supported */ private byte[] calculateUValue( byte[] generalKey, byte[] firstDocIdValue, int revision) throws GeneralSecurityException, EncryptionUnsupportedByProductException { if (revision == 2) { // Algorithm 3.4: Computing the encryption dictionary’s U (user // password) value (Revision 2) // Step 1 is provided to us as the parameter generalKey: // Create an encryption key based on the user password string, as // described in Algorithm 3.2 // Step 2: Encrypt the 32-byte padding string shown in step 1 of // Algorithm 3.2, using an RC4 encryption function with the // encryption key from the preceding step. Cipher rc4 = createRC4Cipher(); SecretKey key = createRC4Key(generalKey); initEncryption(rc4, key); return crypt(rc4, PW_PADDING); } else if (revision >= 3) { // Algorithm 3.5: Computing the encryption dictionary’s U (user // password) value (Revision 3 or greater) // Step 1 is provided to us as the parameter generalKey: // Create an encryption key based on the user password string, as // described in Algorithm 3.2 // Step 2: Initialize the MD5 hash function and pass the 32-byte // padding string shown in step 1 of Algorithm 3.2 as input to this // function MessageDigest md5 = createMD5Digest(); md5.update(PW_PADDING); // Step 3: Pass the first element of the file’s file identifier // array (the value of the ID entry in the document’s trailer // dictionary; see Table 3.13 on page 97) to the hash function and // finish the hash. (See implementation note 26 in Appendix H.) if (firstDocIdValue != null) { md5.update(firstDocIdValue); } final byte[] hash = md5.digest(); // Step 4: Encrypt the 16-byte result of the hash, using an RC4 // encryption function with the encryption key from step 1. Cipher rc4 = createRC4Cipher(); SecretKey key = createRC4Key(generalKey); initEncryption(rc4, key); final byte[] v = crypt(rc4, hash); // Step 5: Do the following 19 times: Take the output from the // previous invocation of the RC4 function and pass it as input to // a new invocation of the function; use an encryption key generated // by taking each byte of the original encryption key (obtained in // step 1) and performing an XOR (exclusive or) operation between // that byte and the single-byte value of the iteration counter // (from 1 to 19). rc4shuffle(v, generalKey, rc4); // Step 6: Append 16 bytes of arbitrary padding to the output from // the final invocation of the RC4 function and store the 32-byte // result as the value of the U entry in the encryption dictionary. assert v.length == 16; final byte[] entryValue = new byte[32]; System.arraycopy(v, 0, entryValue, 0, v.length); System.arraycopy(v, 0, entryValue, 16, v.length); return entryValue; } else { throw new EncryptionUnsupportedByProductException( "Unsupported standard security handler revision " + revision); } } /** * Calculate what the O value of the Encrypt dict should look like given a * particular configuration. Not used, but useful for reference; this * process is reversed to determine whether a given password is the * owner password. Corresponds to Algorithm 3.3 of the PDF Reference * version 1.7. * * @see #checkOwnerPassword * @param ownerPassword the owner password * @param userPassword the user password * @param keyBitLength the key length in bits (40-128) * @param revision the security handler revision * @return the O value entry * @throws GeneralSecurityException if ciphers are unavailable or * inappropriately used */ private byte[] calculuateOValue( byte[] ownerPassword, byte[] userPassword, int keyBitLength, int revision) throws GeneralSecurityException { // Steps 1-4 final byte[] rc4KeyBytes = getInitialOwnerPasswordKeyBytes( ownerPassword, keyBitLength, revision); final Cipher rc4 = createRC4Cipher(); initEncryption(rc4, createRC4Key(rc4KeyBytes)); // Step 5: Pad or truncate the user password string as described in step // 1 of Algorithm 3.2. // Step 6: Encrypt the result of step 5, using an RC4 encryption // function with the encryption key obtained in step 4. byte[] pwvalue = crypt(rc4, padPassword(userPassword)); // Step 7: (Revision 3 or greater) Do the following 19 times: Take the // output from the previous invocation of the RC4 function and pass it // as input to a new invocation of the function; use an encryption key // generated by taking each byte of the encryption key obtained in step // 4 and performing an XOR (exclusive or) operation between if (revision >= 3) { rc4shuffle(pwvalue, rc4KeyBytes, rc4); } assert pwvalue.length == 32; return pwvalue; } /** * Check to see whether a given password is the owner password. Corresponds * to algorithm 3.6 of PDF Reference version 1.7. * * @param ownerPassword the suggested owner password (may be null or * empty) * @param firstDocIdValue the byte stream from the first element of the * value of the ID entry in the trailer dictionary * @param keyBitLength the key length in bits * @param revision the security handler revision * @param oValue the O value from the Encrypt dictionary * @param uValue the U value from the Encrypt dictionary * @param pValue the P value from the Encrypt dictionary * @param encryptMetadata the EncryptMetadata entry from the Encrypt dictionary * (or false if not present or revision <= 3) * @return the general/user key bytes if the owner password is currect, * null otherwise * @throws GeneralSecurityException if there's a problem with * cipher or digest usage; unexpected * @throws EncryptionUnsupportedByProductException if PDFRenderer doesn't * support the security handler revision * @throws PDFParseException if the document is malformed */ private byte[] checkOwnerPassword( byte[] ownerPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata) throws GeneralSecurityException, EncryptionUnsupportedByProductException, PDFParseException { // Step 1: Compute an encryption key from the supplied password string, // as described in steps 1 to 4 of Algorithm 3.3. final byte[] rc4KeyBytes = getInitialOwnerPasswordKeyBytes(ownerPassword, keyBitLength, revision); final Cipher rc4 = createRC4Cipher(); initDecryption(rc4, createRC4Key(rc4KeyBytes)); // Step 2: final byte[] possibleUserPassword; if (revision == 2) { // (Revision 2 only) Decrypt the value of the encryption // dictionary’s O entry, using an RC4 encryption function with the // encryption key computed in step 1. possibleUserPassword = crypt(rc4, oValue); } else if (revision >= 3) { // (Revision 3 or greater) Do the following 20 times: Decrypt the // value of the encryption dictionary’s O entry (first iteration) or // the output from the previous iteration (all subsequent // iterations), using an RC4 encryption function with a different // encryption key at each iteration. The key is generated by taking // the original key (obtained in step 1) and performing an XOR // (exclusive or) operation between each byte of the key and the // single-byte value of the iteration counter (from 19 to 0). // unshuffle the O entry; the unshuffle operation also // contains the final decryption with the original key possibleUserPassword = new byte[32]; System.arraycopy(oValue, 0, possibleUserPassword, 0, possibleUserPassword.length); rc4unshuffle(rc4, possibleUserPassword, rc4KeyBytes); } else { throw new EncryptionUnsupportedByProductException( "Unsupported revision: " + revision); } // Step 3: The result of step 2 purports to be the user password. // Authenticate this user password using Algorithm 3.6. If it is // correct, the password supplied is the correct owner password. return checkUserPassword( possibleUserPassword, firstDocIdValue, keyBitLength, revision, oValue, uValue, pValue, encryptMetadata); } /** * Establish the key to be used for the generation and validation * of the user password via the O entry. Corresponds to steps 1-4 in * Algorithm 3.3 of the PDF Reference version 1.7. * @param ownerPassword the owner password * @param keyBitLength the length of the key in bits * @param revision the security handler revision * @return the key bytes to use for generation/validation of the O entry * @throws GeneralSecurityException if there's a problem wranling ciphers */ private byte[] getInitialOwnerPasswordKeyBytes( byte[] ownerPassword, int keyBitLength, int revision) throws GeneralSecurityException { final MessageDigest md5 = createMD5Digest(); // Step 1: Pad or truncate the owner password string as described in // step 1 of Algorithm 3.2. If there is no owner password, use the user // password instead. (See implementation note 27 in Appendix H.) // Step 2: Initialize the MD5 hash function and pass the result of step 1 as // input to this function. md5.update(padPassword(ownerPassword)); // Step 3.(Revision 3 or greater) Do the following 50 times: Take the // output from the previous MD5 hash and pass it as input into a new MD5 // hash final byte[] hash = md5.digest(); if (revision >= 3) { for (int i = 0; i < 50; ++i) { md5.update(hash); digestTo(md5, hash); } } // Step 4: Create an RC4 encryption key using the first n bytes of // the output from the final MD5 hash, where n is always 5 for revision // 2 but, for revision 3 or greater, depends on the value of the // encryption dictionary’s Length entry final byte[] rc4KeyBytes = new byte[keyBitLength / 8]; System.arraycopy(hash, 0, rc4KeyBytes, 0, rc4KeyBytes.length); return rc4KeyBytes; } /** * Check to see whether a provided user password is correct with respect * to an Encrypt dict configuration. Corresponds to algorithm 3.6 of * the PDF Reference version 1.7 * @param userPassword the user password to test; may be null or empty * @param firstDocIdValue the byte stream from the first element of the * value of the ID entry in the trailer dictionary * @param keyBitLength the length of the key in bits * @param revision the security handler revision * @param oValue the O value from the Encrypt dictionary * @param uValue the U value from the Encrypt dictionary * @param pValue the P value from the Encrypt dictionary * @param encryptMetadata the EncryptMetadata entry from the Encrypt dictionary * (or false if not present or revision <= 3) * @return the general/user encryption key if the user password is correct, * or null if incorrect * @throws GeneralSecurityException if there's a problem with * cipher or digest usage; unexpected * @throws EncryptionUnsupportedByProductException if PDFRenderer doesn't * support the security handler revision * @throws PDFParseException if the document is improperly constructed */ private byte[] checkUserPassword( byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, byte[] uValue, int pValue, boolean encryptMetadata) throws GeneralSecurityException, EncryptionUnsupportedByProductException, PDFParseException { // Algorithm 3.6: Authenticating the user password // Step 1: Perform all but the last step of Algorithm 3.4 (Revision 2) // or Algorithm 3.5 (Revision 3 or greater) using the supplied password // string // // I.e., figure out what the general key would be with the // given password // Algorithm 3.4/5,Step1: // Determine general key based on user password, as per Algorithm 3.2 final byte[] generalKey = calculateGeneralEncryptionKey( userPassword, firstDocIdValue, keyBitLength, revision, oValue, pValue, encryptMetadata); // Algorithm 3.4/5,RemainingSteps: final byte[] calculatedUValue = calculateUValue(generalKey, firstDocIdValue, revision); // Step 2: If the result of step 1 is equal to the value of the // encryption dictionary’s U entry (comparing on the first 16 bytes in // the case of Revision 3 or greater), the password supplied is the // correct user password. The key obtained in step 1 (that is, in the // first step of Algorithm 3.4 or 3.5) can be used to decrypt the // document using Algorithm 3.1 on page 119. assert calculatedUValue.length == 32; if (uValue.length != calculatedUValue.length) { throw new PDFParseException("Improper U entry length; " + "expected 32, is " + uValue.length); } // Only the first 16 bytes are significant if using revision > 2 final int numSignificantBytes = revision == 2 ? 32 : 16; for (int i = 0; i < numSignificantBytes; ++i) { if (uValue[i] != calculatedUValue[i]) { return null; } } return generalKey; } /** * Determine what the general encryption key is, given a configuration. This * corresponds to Algorithm 3.2 of PDF Reference version 1.7. * * @param userPassword the desired user password; may be null or empty * @param firstDocIdValue the byte stream from the first element of the * value of the ID entry in the trailer dictionary * @param keyBitLength the length of the key in bits * @param revision the security handler revision * @param oValue the O value from the Encrypt dictionary * @param pValue the P value from the Encrypt dictionary * @param encryptMetadata the EncryptMetadata entry from the Encrypt * dictionary (or false if not present or revision <= 3) * @return the general encryption key * @throws GeneralSecurityException if an error occurs when obtaining * and operating ciphers/digests */ private byte[] calculateGeneralEncryptionKey( byte[] userPassword, byte[] firstDocIdValue, int keyBitLength, int revision, byte[] oValue, int pValue, boolean encryptMetadata) throws GeneralSecurityException { // Algorithm 3.2: Computing an encryption key // Step 1: Pad or truncate the password string to exactly 32 bytes... final byte[] paddedPassword = padPassword(userPassword); // Step 2: Initialize the MD5 hash function and pass the result of step // 1 as input to this function. MessageDigest md5 = createMD5Digest(); md5.reset(); md5.update(paddedPassword); // Step 3: Pass the value of the encryption dictionary’s O entry to the // MD5 hash function. (Algorithm 3.3 shows how the O value is computed.) md5.update(oValue); // Step 4: Treat the value of the P entry as an unsigned 4-byte integer // and pass these bytes to the MD5 hash function, low-order byte first md5.update((byte) (pValue & 0xFF)); md5.update((byte) ((pValue >> 8) & 0xFF)); md5.update((byte) ((pValue >> 16) & 0xFF)); md5.update((byte) (pValue >> 24)); // Step 5: Pass the first element of the file’s file identifier array // (the value of the ID entry in the document’s trailer dictionary; see // Table 3.13 on page 97) to the MD5 hash function. (See implementation // note 26 in Appendix H.) if (firstDocIdValue != null) { md5.update(firstDocIdValue); } // Step 6: (Revision 4 or greater) If document metadata is not being // encrypted, pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash // function if (revision >= 4 && !encryptMetadata) { for (int i = 0; i < 4; ++i) { md5.update((byte) 0xFF); } } // Step 7: finish the hash byte[] hash = md5.digest(); final int keyLen = revision == 2 ? 5 : (keyBitLength / 8); final byte[] key = new byte[keyLen]; // Step 8: (Revision 3 or greater) Do the following 50 times: Take the // output from the previous MD5 hash and pass the first n bytes of the // output as input into a new MD5 hash, where n is the number of bytes // of the encryption key as defined by the value of the encryption // dictionary’s Length entry if (revision >= 3) { for (int i = 0; i < 50; ++i) { md5.update(hash, 0, key.length); digestTo(md5, hash); } } // Set the encryption key to the first n bytes of the output from the // final MD5 hash, where n is always 5 for revision 2 but, for revision // 3 or greater, depends on the value of the encryption dictionary’s // Length entry. System.arraycopy(hash, 0, key, 0, key.length); return key; } /** * Pad a password as per step 1 of Algorithm 3.2 of the PDF Reference * version 1.7 * @param password the password, may be null or empty * @return the padded password, always 32 bytes long */ private byte[] padPassword(byte[] password) { if (password == null) { password = new byte[0]; } // Step 1: Pad or truncate the password string to exactly 32 bytes. If // the password string is more than 32 bytes long, use only its first 32 // bytes; if it is less than 32 bytes long, pad it by appending the // required number of additional bytes from the beginning of the // following padding string: // < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 // 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A > // That is, if the password string is n bytes long, append the first 32 // − n bytes of the padding string to the end of the password string. If // the password string is empty (zero-length), meaning there is no user // password, substitute the entire padding string in its place. byte[] padded = new byte[32]; // limit password to 32 bytes final int numContributingPasswordBytes = password.length > padded.length ? padded.length : password.length; System.arraycopy(password, 0, padded, 0, numContributingPasswordBytes); // Copy padding if (password.length < padded.length) { System.arraycopy(PW_PADDING, 0, padded, password.length, padded.length - password.length); } return padded; } /** * Encrypt some bytes * * @param cipher the cipher * @param input the plaintext * @return the crypt text * @throws BadPaddingException if there's bad padding * @throws IllegalBlockSizeException if the block size is bad */ private byte[] crypt(Cipher cipher, byte[] input) throws IllegalBlockSizeException, BadPaddingException { return cipher.doFinal(input); } /** * Initialise a cipher for encryption * * @param cipher the cipher * @param key the encryption key * @throws InvalidKeyException if the key is invalid for the cipher */ private void initEncryption(Cipher cipher, SecretKey key) throws InvalidKeyException { cipher.init(Cipher.ENCRYPT_MODE, key); } /** * Shuffle some input using a series of RC4 encryptions with slight * mutations of an given key per iteration. Shuffling happens in place. * Refer to the documentation of the algorithm steps where this is called. * * @param shuffle the bytes to be shuffled * @param key the original key * @param rc4 the cipher to use * @throws GeneralSecurityException if there's a problem with cipher * operation */ private void rc4shuffle(byte[] shuffle, byte[] key, Cipher rc4) throws GeneralSecurityException { final byte[] shuffleKey = new byte[key.length]; for (int i = 1; i <= 19; ++i) { for (int j = 0; j < shuffleKey.length; ++j) { shuffleKey[j] = (byte) (key[j] ^ i); } initEncryption(rc4, createRC4Key(shuffleKey)); cryptInPlace(rc4, shuffle); } } /** * Reverse the {@link #rc4shuffle} operation, and the operation * that invariable preceeds it, thereby obtaining an original message * @param rc4 the RC4 cipher to use * @param shuffle the bytes in which shuffling will take place; unshuffling * happens in place * @param key the encryption key * @throws GeneralSecurityException if there's a problem with cipher * operation */ private void rc4unshuffle(Cipher rc4, byte[] shuffle, byte[] key) throws GeneralSecurityException { // there's an extra unshuffle at the end with the original key - // this is why we end with i == 0, where the shuffle key will be the key final byte[] shuffleKeyBytes = new byte[key.length]; for (int i = 19; i >= 0; --i) { for (int j = 0; j < shuffleKeyBytes.length; ++j) { shuffleKeyBytes[j] = (byte) (key[j] ^ i); } initDecryption(rc4, createRC4Key(shuffleKeyBytes)); cryptInPlace(rc4, shuffle); } } /** * Encrypt/decrypt something in place * @param rc4 the cipher to use; must be a stream cipher producing * identical output length to input (e.g., RC4) * @param buffer the buffer to read input from and write output to * @throws IllegalBlockSizeException if an inappropriate cipher is used * @throws ShortBufferException if an inappropriate cipher is used * @throws BadPaddingException if an inappropriate cipher is used */ private void cryptInPlace(Cipher rc4, byte[] buffer) throws IllegalBlockSizeException, ShortBufferException, BadPaddingException { rc4.doFinal(buffer, 0, buffer.length, buffer); } /** * Setup a cipher for decryption * @param cipher the cipher * @param aKey the cipher key * @throws InvalidKeyException if the key is of an unacceptable size or * doesn't belong to the cipher */ private void initDecryption(Cipher cipher, Key aKey) throws InvalidKeyException { cipher.init(Cipher.DECRYPT_MODE, aKey); } /** * Create a new RC4 cipher. Should always be available for supported * platforms. * @return the cipher * @throws NoSuchAlgorithmException if the RC4 cipher is unavailable * @throws NoSuchPaddingException should not happen, as no padding * is specified */ private Cipher createRC4Cipher() throws NoSuchAlgorithmException, NoSuchPaddingException { return Cipher.getInstance(CIPHER_RC4); } /** * Create a new AES cipher. Should always be available for supported * platforms. * @return the new cipher * @throws NoSuchAlgorithmException if the AES cipher is unavailable * @throws NoSuchPaddingException if the required padding is unavailable */ private Cipher createAESCipher() throws NoSuchAlgorithmException, NoSuchPaddingException { return Cipher.getInstance(CIPHER_AES); } /** * Create an MD5 digest. Should always be available for supported * platforms. * @return the MD5 digest * @throws NoSuchAlgorithmException if the digest is not available */ private MessageDigest createMD5Digest() throws NoSuchAlgorithmException { return MessageDigest.getInstance("MD5"); } /** * Create an RC4 key * * @param keyBytes the bytes for the key * @return the key */ private SecretKeySpec createRC4Key(byte[] keyBytes) { return new SecretKeySpec(keyBytes, KEY_RC4); } /** * Hash into an existing byte array * @param md5 the MD5 digest * @param hash the hash destination * @throws GeneralSecurityException if there's a problem hashing; e.g., * if the buffer is too small */ private void digestTo(MessageDigest md5, byte[] hash) throws GeneralSecurityException { md5.digest(hash, 0, hash.length); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/PDFDecrypterFactory.java0000644000175000017500000003367511156177553025765 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Produces a {@link PDFDecrypter} for documents given a (possibly non-existent) * Encrypt dictionary. Supports decryption of versions 1, 2 and 4 of the * password-based encryption mechanisms as described in PDF Reference version * 1.7. This means that it supports RC4 and AES encryption with keys of * 40-128 bits; esentially, password-protected documents with compatibility * up to Acrobat 8. * * @See "PDF Reference version 1.7, section 3.5: Encryption" * @author Luke Kirby */ public class PDFDecrypterFactory { /** The name of the standard Identity CryptFilter */ public static final String CF_IDENTITY = "Identity"; /** Default key length for versions where key length is optional */ private static final int DEFAULT_KEY_LENGTH = 40; /** * Create a decryptor for a given encryption dictionary. A check is * immediately performed that the supplied password decrypts content * described by the encryption specification. * * @param encryptDict the Encrypt dict as found in the document's trailer. * May be null, in which case the {@link IdentityDecrypter} will * be returned. * @param documentId the object with key "ID" in the trailer's dictionary. * Should always be present if Encrypt is. * @param password the password to use; may be null * @return The decryptor that should be used for all encrypted data in the * PDF * @throws IOException will typically be a {@link * com.sun.pdfview.PDFParseException}, indicating an IO problem, an error * in the structure of the document, or a failure to obtain various ciphers * from the installed JCE providers * @throws EncryptionUnsupportedByPlatformException if the encryption * is not supported by the environment in which the code is executing * @throws EncryptionUnsupportedByProductException if PDFRenderer does * not currently support the specified encryption * @throws PDFAuthenticationFailureException if the supplied password * was not able to */ public static PDFDecrypter createDecryptor (PDFObject encryptDict, PDFObject documentId, PDFPassword password) throws IOException, EncryptionUnsupportedByPlatformException, EncryptionUnsupportedByProductException, PDFAuthenticationFailureException { // none of the classes beyond us want to see a null PDFPassword password = PDFPassword.nonNullPassword(password); if (encryptDict == null) { // No encryption specified return IdentityDecrypter.getInstance(); } else { PDFObject filter = encryptDict.getDictRef("Filter"); // this means that we'll fail if, for example, public key // encryption is employed if (filter != null && "Standard".equals(filter.getStringValue())) { final PDFObject vObj = encryptDict.getDictRef("V"); int v = vObj != null ? vObj.getIntValue() : 0; if (v == 1 || v == 2) { final PDFObject lengthObj = encryptDict.getDictRef("Length"); final Integer length = lengthObj != null ? lengthObj.getIntValue() : null; return createStandardDecrypter( encryptDict, documentId, password, length, false, StandardDecrypter.EncryptionAlgorithm.RC4); } else if (v == 4) { return createCryptFilterDecrypter( encryptDict, documentId, password, v); } else { throw new EncryptionUnsupportedByPlatformException( "Unsupported encryption version: " + v); } } else if (filter == null) { throw new PDFParseException( "No Filter specified in Encrypt dictionary"); } else { throw new EncryptionUnsupportedByPlatformException( "Unsupported encryption Filter: " + filter + "; only Standard is supported."); } } } /** * Create a decrypter working from a crypt filter dictionary, as in * version 4 encryption * * @param encryptDict the Encrypt dictionary * @param documentId the document ID * @param password the provided password * @param v the version of encryption being used; must be at least 4 * @return the decrypter corresponding to the scheme expressed in * encryptDict * @throws PDFAuthenticationFailureException if the provided password * does not decrypt this document * @throws IOException if there is a problem reading the PDF, an invalid * document structure, or an inability to obtain the required ciphers * from the platform's JCE * @throws EncryptionUnsupportedByPlatformException if the encryption * is not supported by the environment in which the code is executing * @throws EncryptionUnsupportedByProductException if PDFRenderer does * not currently support the specified encryption */ private static PDFDecrypter createCryptFilterDecrypter( PDFObject encryptDict, PDFObject documentId, PDFPassword password, int v) throws PDFAuthenticationFailureException, IOException, EncryptionUnsupportedByPlatformException, EncryptionUnsupportedByProductException { assert v >= 4 : "crypt filter decrypter not supported for " + "standard encryption prior to version 4"; // encryptMetadata is true if not present. Note that we don't actually // use this to change our reading of metadata streams (that's all done // internally by the document specifying a Crypt filter of None if // appropriate), but it does affect the encryption key. boolean encryptMetadata = true; final PDFObject encryptMetadataObj = encryptDict.getDictRef("EncryptMetadata"); if (encryptMetadataObj != null && encryptMetadataObj.getType() == PDFObject.BOOLEAN) { encryptMetadata = encryptMetadataObj.getBooleanValue(); } // Assemble decrypters for each filter in the // crypt filter (CF) dictionary final Map cfDecrypters = new HashMap(); final PDFObject cfDict = encryptDict.getDictRef("CF"); if (cfDict == null) { throw new PDFParseException( "No CF value present in Encrypt dict for V4 encryption"); } final Iterator cfNameIt = cfDict.getDictKeys(); while (cfNameIt.hasNext()) { final String cfName = cfNameIt.next(); final PDFObject cryptFilter = cfDict.getDictRef(cfName); final PDFObject lengthObj = cryptFilter.getDictRef("Length"); // The Errata for PDF 1.7 explains that the value of // Length in CF dictionaries is in bytes final Integer length = lengthObj != null ? lengthObj.getIntValue() * 8 : null; // CFM is the crypt filter method, describing whether RC4, // AES, or None (i.e., identity) is the encryption mechanism // used for the name crypt filter final PDFObject cfmObj = cryptFilter.getDictRef("CFM"); final String cfm = cfmObj != null ? cfmObj.getStringValue() : "None"; final PDFDecrypter cfDecrypter; if ("None".equals(cfm)) { cfDecrypter = IdentityDecrypter.getInstance(); } else if ("V2".equals(cfm)) { cfDecrypter = createStandardDecrypter( encryptDict, documentId, password, length, encryptMetadata, StandardDecrypter.EncryptionAlgorithm.RC4); } else if ("AESV2".equals(cfm)) { cfDecrypter = createStandardDecrypter( encryptDict, documentId, password, length, encryptMetadata, StandardDecrypter.EncryptionAlgorithm.AESV2); } else { throw new UnsupportedOperationException( "Unknown CryptFilter method: " + cfm); } cfDecrypters.put(cfName, cfDecrypter); } // always put Identity in last so that it will override any // Identity filter sneakily declared in the CF entry cfDecrypters.put(CF_IDENTITY, IdentityDecrypter.getInstance()); PDFObject stmFObj = encryptDict.getDictRef("StmF"); final String defaultStreamFilter = stmFObj != null ? stmFObj.getStringValue() : CF_IDENTITY; PDFObject strFObj = encryptDict.getDictRef("StrF"); final String defaultStringFilter = strFObj != null ? strFObj.getStringValue() : CF_IDENTITY; return new CryptFilterDecrypter( cfDecrypters, defaultStreamFilter, defaultStringFilter); } /** * Create a standard single-algorithm AES or RC4 decrypter. The Encrypt * dictionary is used where possible, but where different encryption * versions employ different mechanisms of specifying configuration or may * be specified via a CF entry (e.g. key length), the value is specified as * a parameter. * * @param encryptDict the Encrypt dictionary * @param documentId the document ID * @param password the password * @param keyLength the key length, in bits; may be null * to use a {@link #DEFAULT_KEY_LENGTH default} * @param encryptMetadata whether metadata is being encrypted * @param encryptionAlgorithm, the encryption algorithm * @return the decrypter * @throws PDFAuthenticationFailureException if the provided password * is not the one expressed by the encryption dictionary * @throws IOException if there is a problem reading the PDF content, * if the content does not comply with the PDF specification * @throws EncryptionUnsupportedByPlatformException if the encryption * is not supported by the environment in which the code is executing * @throws EncryptionUnsupportedByProductException if PDFRenderer does * not currently support the specified encryption * */ private static PDFDecrypter createStandardDecrypter( PDFObject encryptDict, PDFObject documentId, PDFPassword password, Integer keyLength, boolean encryptMetadata, StandardDecrypter.EncryptionAlgorithm encryptionAlgorithm) throws PDFAuthenticationFailureException, IOException, EncryptionUnsupportedByPlatformException, EncryptionUnsupportedByProductException { if (keyLength == null) { keyLength = DEFAULT_KEY_LENGTH; } // R describes the revision of the security handler final PDFObject rObj = encryptDict.getDictRef("R"); if (rObj == null) { throw new PDFParseException( "No R entry present in Encrypt dictionary"); } final int revision = rObj.getIntValue(); if (revision < 2 || revision > 4) { throw new EncryptionUnsupportedByPlatformException( "Unsupported Standard security handler revision; R=" + revision); } // O describes validation details for the owner key final PDFObject oObj = encryptDict.getDictRef("O"); if (oObj == null) { throw new PDFParseException( "No O entry present in Encrypt dictionary"); } final byte[] o = oObj.getStream(); if (o.length != 32) { throw new PDFParseException("Expected owner key O " + "value of 32 bytes; found " + o.length); } // U describes validation details for the user key final PDFObject uObj = encryptDict.getDictRef("U"); if (uObj == null) { throw new PDFParseException( "No U entry present in Encrypt dictionary"); } final byte[] u = uObj.getStream(); if (u.length != 32) { throw new PDFParseException( "Expected user key U value of 32 bytes; found " + o.length); } // P describes the permissions regarding document usage final PDFObject pObj = encryptDict.getDictRef("P"); if (pObj == null) { throw new PDFParseException( "Required P entry in Encrypt dictionary not found"); } return new StandardDecrypter( encryptionAlgorithm, documentId, keyLength, revision, o, u, pObj.getIntValue(), encryptMetadata, password); } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/IdentityDecrypter.java0000644000175000017500000000375711526563523025610 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import java.nio.ByteBuffer; /** * Performs identity decryption; that is, inputs aren't encrypted and * are returned right back. * * @author Luke Kirby */ public class IdentityDecrypter implements PDFDecrypter { private static IdentityDecrypter INSTANCE = new IdentityDecrypter(); public ByteBuffer decryptBuffer(String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) throws PDFParseException { if (cryptFilterName != null) { throw new PDFParseException("This Encryption version does not support Crypt filters"); } return streamBuf; } public String decryptString(int objNum, int objGen, String inputBasicString) { return inputBasicString; } public static IdentityDecrypter getInstance() { return INSTANCE; } public boolean isEncryptionPresent() { return false; } public boolean isEncryptionPresent(String cryptFilterName) { return false; } public boolean isOwnerAuthorised() { return false; } } pdfrenderer-0.9.0/src/com/sun/pdfview/decrypt/PDFDecrypter.java0000644000175000017500000001072011526563523024414 0ustar twernertwerner/* * Copyright 2008 Pirion Systems Pty Ltd, 139 Warry St, * Fortitude Valley, Queensland, Australia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package com.sun.pdfview.decrypt; import com.sun.pdfview.PDFObject; import com.sun.pdfview.PDFParseException; import com.sun.pdfview.PDFStringUtil; import java.nio.ByteBuffer; /** * A decrypter decrypts streams and strings in a PDF document. {@link * #decryptBuffer(String, PDFObject, ByteBuffer)} } should be used for decoding * streams, and {@link #decryptString(int, int, String)} for string values in * the PDF. It is possible for strings and streams to be encrypted with * different mechanisms, so the appropriate method must alwayus be used. * * @see "PDFReference 1.7, Section 3.5 Encryption" * @author Luke Kirby */ public interface PDFDecrypter { /** * Decrypt a buffer of data * @param cryptFilterName the name of the crypt filter, if V4 * encryption is being used, where individual crypt filters may * be specified for individual streams. If encryption is not using * V4 encryption (indicated by V=4 in the Encrypt dictionary) then * this must be null. Null may also be specified with V4 encryption * to indicate that the default filter should be used. * @param streamObj the object whose stream is being decrypted. The * containing object's number and generation contribute to the key used for * stream encrypted with the document's default encryption, so this is * typically required. Should be null only if a cryptFilterName is * specified, as objects with specific stream filters use the general * document key, rather than a stream-specific key. * @param streamBuf the buffer to decrypt * @return a buffer containing the decrypted stream, positioned at its * beginning; will only be the same buffer as streamBuf if the identity * decrypter is being used * @throws PDFParseException if the named crypt filter does not exist, or * if a crypt filter is named when named crypt filters are not supported. * Problems due to incorrect passwords are revealed prior to this point. */ public ByteBuffer decryptBuffer( String cryptFilterName, PDFObject streamObj, ByteBuffer streamBuf) throws PDFParseException; /** * Decrypt a {@link PDFStringUtil basic string}. * @param objNum the object number of the containing object * @param objGen the generation number of the containing object * @param inputBasicString the string to be decrypted * @return the decrypted string * @throws PDFParseException if the named crypt filter does not exist, or * if a crypt filter is named when named crypt filters are not supported. * Problems due to incorrect passwords are revealed prior to this point. */ public String decryptString(int objNum, int objGen, String inputBasicString) throws PDFParseException; /** * Determine whether the password known by the decrypter indicates that * the user is the owner of the document. Can be used, in conjunction * with {@link #isEncryptionPresent()} to determine whether any * permissions apply. * @return whether owner authentication is being used to decrypt the * document */ public boolean isOwnerAuthorised(); /** * Determine whether this actually applies a decryption other than * identity decryption. * @return whether encryption is present */ public boolean isEncryptionPresent(); /** * Determines whether decryption applies for a given crypt filter name * @param cryptFilterName the crypt filter name * @return whether the given crypt filter decrypts or not */ boolean isEncryptionPresent(String cryptFilterName); } pdfrenderer-0.9.0/build.xml0000644000175000017500000001075211137251732015606 0ustar twernertwerner Builds, tests, and runs the project PDFRenderer. pdfrenderer-0.9.0/lib/0000755000175000017500000000000011622545441014530 5ustar twernertwernerpdfrenderer-0.9.0/lib/readme.txt0000644000175000017500000000022410733542027016523 0ustar twernertwernerDirectory for 3rd party libraries required by the project. Such libraries, if any, will be picked up autmoatically and added to the weekly bundles.pdfrenderer-0.9.0/nbproject/0000755000175000017500000000000011622545441015750 5ustar twernertwernerpdfrenderer-0.9.0/nbproject/project.properties0000644000175000017500000000444611137251577021551 0ustar twernertwernerant.customtasks.libs=JWSAntTasks application.title=PDFRenderer auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80 auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=default jnlp.descriptor=application projectname=${application.title} application.vendor=joshy build.bundles.dir=${build.dir}/bundles build.classes.dir=${build.dir}/classes build.classes.excludes=**/*.java,**/*.form # This directory is removed when the project is cleaned: build.dir=build build.generated.dir=${build.dir}/generated # Only compile against the classpath explicitly listed here: build.sysclasspath=ignore build.test.classes.dir=${build.dir}/test/classes build.test.results.dir=${build.dir}/test/results debug.classpath=\ ${run.classpath} debug.test.classpath=\ ${run.test.classpath} # This directory is removed when the project is cleaned: dist.dir=dist dist.bundles.dir=${dist.dir}/bundles dist.jar=${dist.dir}/PDFRenderer.jar dist.javadoc.dir=${dist.dir}/javadoc excludes= file.reference.demos-viewer=demos/viewer file.reference.document.jar=lib/document.jar file.reference.pdf-renderer-src=src includes=** jar.compress=false java.dir=src javac.classpath= # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false javac.source=1.5 javac.target=1.5 javac.test.classpath=\ ${javac.classpath}:\ ${build.classes.dir}:\ ${libs.junit.classpath}:\ ${libs.junit_4.classpath} javadoc.additionalparam= javadoc.author=false javadoc.encoding=${source.encoding} javadoc.noindex=false javadoc.nonavbar=false javadoc.notree=false javadoc.private=false javadoc.splitindex=true javadoc.use=true javadoc.version=false javadoc.windowtitle= jnlp.codebase.type=user jnlp.codebase.user=https://pdf-renderer.dev.java.net/demos/latest/ jnlp.enabled=false jnlp.offline-allowed=true jnlp.signed=true main.class=com.sun.pdfview.PDFViewer manifest.file=manifest.mf meta.inf.dir=${src.dir}/META-INF PDFRenderer2.dir=${file.reference.pdf-renderer-src} platform.active=default_platform run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} run.jvmargs=-Xmx512M run.test.classpath=\ ${javac.test.classpath}:\ ${build.test.classes.dir} source.encoding=UTF-8 src.dir=${file.reference.demos-viewer} pdfrenderer-0.9.0/nbproject/management-build-impl.xml0000644000175000017500000002616611137251577022662 0ustar twernertwerner Must set platform.home Must set platform.bootcp Must set platform.java Must set platform.javac Platform is not correctly set up Must set src.dir Must set test.src.dir Must set build.dir Must set dist.dir Must set build.classes.dir Must set dist.javadoc.dir Must set build.test.classes.dir Must set build.test.results.dir Must set build.classes.excludes Must set dist.jar Must select one file in the IDE or set manage.class pdfrenderer-0.9.0/nbproject/jnlp-impl.xml0000644000175000017500000005267710725114532020411 0ustar twernertwerner $${APPLICATION.TITLE} $${APPLICATION.VENDOR} $${APPLICATION.DESC} $${APPLICATION.DESC.SHORT} ]]> Test page for launching the application via JNLP

    Test page for launching the application via JNLP

    Launch the application ]]>
    pdfrenderer-0.9.0/nbproject/configs/0000755000175000017500000000000011622545441017400 5ustar twernertwernerpdfrenderer-0.9.0/nbproject/configs/JWS_generated.properties0000644000175000017500000000021111137251577024176 0ustar twernertwerner#Wed Dec 31 11:31:54 MST 2008 $label=Web Start $target.debug=jws-debug compile.on.save.unsupported.javawebstart=true $target.run=jws-run pdfrenderer-0.9.0/nbproject/build-impl.xml0000644000175000017500000010071511137251577020541 0ustar twernertwerner Must set PDFRenderer2.dir Must set src.dir Must set build.dir Must set dist.dir Must set build.classes.dir Must set dist.javadoc.dir Must set build.test.classes.dir Must set build.test.results.dir Must set build.classes.excludes Must set dist.jar Must set javac.includes Must select some files in the IDE or set javac.includes To run this application from the command line without Ant, try: java -cp "${run.classpath.with.dist.jar}" ${main.class} To run this application from the command line without Ant, try: java -jar "${dist.jar.resolved}" Must select one file in the IDE or set run.class Must select one file in the IDE or set debug.class Must set fix.includes Must select some files in the IDE or set javac.includes Some tests failed; see details above. Must select some files in the IDE or set test.includes Some tests failed; see details above. Must select one file in the IDE or set test.class Must select one file in the IDE or set applet.url Must select one file in the IDE or set applet.url pdfrenderer-0.9.0/nbproject/profiler-build-impl.xml0000644000175000017500000001254611137251577022365 0ustar twernertwerner Must set JVM to use for profiling in profiler.info.jvm Must set profiler agent JVM arguments in profiler.info.jvmargs.agent Must select one file in the IDE or set profile.class pdfrenderer-0.9.0/nbproject/genfiles.properties0000644000175000017500000000143111137251577021666 0ustar twernertwernerbuild.xml.data.CRC32=c609d584 build.xml.script.CRC32=f5024d7f build.xml.stylesheet.CRC32=958a1d3e # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=f1f6bc0c nbproject/build-impl.xml.script.CRC32=bc9a6587 nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5 nbproject/management-build-impl.xml.data.CRC32=5edc89b4 nbproject/management-build-impl.xml.script.CRC32=c6fec217 nbproject/management-build-impl.xml.stylesheet.CRC32=4ab55f8d nbproject/profiler-build-impl.xml.data.CRC32=c609d584 nbproject/profiler-build-impl.xml.script.CRC32=abda56ed nbproject/profiler-build-impl.xml.stylesheet.CRC32=42cb6bcf pdfrenderer-0.9.0/nbproject/project.xml0000644000175000017500000000161111137251577020144 0ustar twernertwerner org.netbeans.modules.java.j2seproject PDFRenderer 1.6.5 pdfrenderer-0.9.0/www/0000755000175000017500000000000011622545441014606 5ustar twernertwernerpdfrenderer-0.9.0/www/index.html0000644000175000017500000001302410741515526016605 0ustar twernertwerner PDFRenderer Home Page

    PDF Renderer: a 100% Java PDF renderer and viewer

    demo | screenshots | download binary jar | download source zip | javadocs | examples

    Screenshots


    The demo viewer app (click for bigger image)


    Experimental Project Wonderland support (click for bigger image)

    What is it?

    The PDF Renderer is just what the name implies: an open source, all Java library which renders PDF documents to the screen using Java2D. Typically this means drawing into a Swing panel, but it could also draw to other Graphics2D implementations. We hope you will come up with cool things to do with it that we never thought of.

    PDF is one of the core file formats of the Internet, so it is very important for Java programmers to be able to both read and write PDFs. Great open source libraries like iText have long handled the writing half, but until now there has not been a good way to read PDFs using open source Java libraries. It could be used to draw on top of PDFs, share them over a network, convert PDFs to PNG images, or maybe even project PDFs into a 3D scene.

    Note, the PDFRenderer does not generate PDF documents, instead it views them. To generate PDFs you should try iText or one of many other great Java libraries.

    What can I use it for?

    Some ideas to get you started:

    • view PDFs in your own app
    • print-preview before exporting PDF files
    • render PDFs to PNGs in a server-side web application
    • view PDFs in a 3D scene
    • draw on top of PDFs and annotate them in a networked viewer

    What are the runtime requirements?

    The PDF Renderer requires Java 5 (Java SE 1.5). It has no other dependencies

    Getting Started

    Since this is the first release we don't have much content yet. You can download the code using CVS, read the javadocs, or try out the viewer demo. Also, please join the dev or user's mailing list.

    Our examples page has some sample code to opening PDFs in Swing, as an image, and other basic usages.

    Contributing back to the project

    There are several areas that need work. The PDF Renderer currently supports a subset 1.4 of the PDF specification. It does not support transparency, various font encodings or fill-in forms. These are the first features we hope the community will tackle.

    Since the PDF Render is part of SwingLabs it follows the same rules. First, SwingLabs projects require the use of the SCA (Sun Contributor Agreement) for any code contributions greater than 20 lines in length. This agreement gives Sun joint copyright on the code (so we can do things like change the license and indemnify customers). In addition, by signing this agreement you certify that the code you submit to the project is code you own the copyright to and code you have the right to submit.

    In short, you must sign the SCA and return it to us in order to get commit rights to CVS. However, you do not have to sign anything to download the code and use it in your own programs. The SwingLabs PDF Renderer is licensed under the LGPL

    You can find out more about signing the SCA at the SCA project or download the SCA itself .

    Where did this renderer come from?

    In 2003, researchers at Sun Labs developed the PDF Renderer as part of an audio collaboration tool, Sun(TM) Labs Meeting Suite, which is used extensively at Sun for distributed meetings. Meeting Suite was designed to allow people to give presentations created with OpenOffice Now, Sun is excited to release this code under the LGPL as part of SwingLabs. This release will benefit the Java ecosystem and also let the open source community improve the implementation to support the latest PDF features.

    pdfrenderer-0.9.0/www/screenshots/0000755000175000017500000000000011622545107017145 5ustar twernertwernerpdfrenderer-0.9.0/www/screenshots/PDF-Renderer-in-Wonderland.thumb.jpg0000644000175000017500000006405210727131710025644 0ustar twernertwernerJFIFPhotoshop 3.08BIMC     C  ," }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4P[~;UxіEo02bFl cEgeF|FΊ7w%%/ v?-Q Ş(g Q&[]10EB6Ҹ'A eU5X5o}i ˜*K.8Үϗ}^V]y"$B 03=o+ i~~1<5}[XX>OϹFNT$_PRx htX_[[Xvq[BM&\v-sȈ2ؿg%?ns>}}o+/~o.GΟx'k7.)Xr=z΋3AVk31&$m zK+}I;\qov(eq}[?'W:^Cվ#(->]rvH$ohKM>% .#kdM27IoR1g.G?l}[d >q>I_W RE)U;s `.p s x]$#],o <@w>rKs#\Ͼlman|Mtm~/LCiΡ$7*/ːw<g$Xo໻񞣉wͦ&鮻$_)mU"%ĽJ{9vd}}ˏտOw$Ǿ|ru?VVl4tmb$bC&>ln9,ssŞ.pm/&>8ˑ2H|e 'QˏտOn5]HV=[ n]Q#*3!* )ہ=2I-|}aaav.}pK%DȪʼuvyhr>t}+?m-Cn}4|,Lc[nHq\\|L7}9-acq㏗wu־eu W~"Kcx. n@H9'9'u{o4FB9?WYy G0 ٲceTd@Jj} {9m6m##rrF@45? )^?UԿ2?&g.1d+j.Tܭǘb +Yx<c].?熭x46BB+j?M]ˏ4G.?熭x4&Bh-/mG˰s/\ [ >q<5o+ǿt O&>?emC˰sq<5o(eտO"4`u?<1rLn5as}Z-w31Y}xj 'Qˏ4_}7z55#t\ͮ|UcR ר=[If/524?L!ī,BTUi$I=0kIpE]$0]>eտOVi?¾,B'~.?!5oqxzHs6uKW?BL3ӷ!axj 'Tױǵ"@?_o[ߊ:k2]І-WwڴC7hdkΌ/丙QOw?UK(!8)-)\'f澃s"D5I,{h zdү%/OÖZwڑ0R&c 5 mj:_'neo}r *oE_o5Ɲ 9nR^x[bks9S\rH5e|9'O_< w)~|?,16FҬEIl~aڵ`/x':n!I_K˘T h#//dsl*nhWՆs:|k1𞎊2Xqqۚ Q~%gC,ωm n'r;cq/A\I/?⿋ ~8댁{/ig~_̙ܶwhCg^en#>,5SSy@+wVb?xWɸW]z |AGך?mXugᮡb.$:oV/.Hbp㑐sL>g|4f&x~A8'+TO[e/]+zNw#!-{F+h- gmoh`cl՘M>Yw ;I >O6ֿ@x^{}Hfo ѷC5+s7|uϭ}sS9<# _ߋ"hj?ou0DlUX䌕# } OwMgGGz7ٷm[UJ]bAi +?垥/ :wïxqu:tI򫆑Id $f/zkxU{O&}23`Z֟a$F kq:C4ZV'o`s_d X,%3rmhmOxZ>tկn\QI":b2>^Xd ci2/x-flӠUL`l "X*m-W~\>դwkYKxůhϔMȵ>udyO!|KG} ~yMOI.+VEr̬7Iv?K$}>+᷆cĭne'wcZgHmo 5L$ƾvzgĭ^J H.WdhI$sӞAJ|"%jJ4Zt]4zo#0I>Kd&vp%.AwSO&az&2%+e zs]+?}[GQڷ&߯_x^$>Kd^whbͭZɯ'G% kR~n53y$!0zsK=},C;9;~~y#VQnUټ>p䛍'CmFBF35f_A ~ɞ0 ).;k2.}r3Кa DV⫼U{ :m)tҋN'};o|id6R.,c`[$O7i Nn҉-~Ʋ#1#pp=M} ]<-FJ $}M&/=h1&P3ӖSW %:\Ͽ3_97.>xQDp"Xv6Cc ^5Swឡqqx0ϯO/ VU8_AuY#|19gP*2 9'i5ыuTKcc@y@̪N0ŮhxyLǕ@3POr ev䦿}#v Xz}=ؤ{>X|oeXվ_:W>*k%ZFs3T+e)) n(sWWxCIoiᮆo<֚Wç]Vq||c{6o=FK4C F '#5Ŕsyae* +k}$IG=|}&:K?1"uR_1-էol?lfɻ}"EDRդ %s-[ţ_xe} o6YPpU8xkV2G>qUcײtl ?J+#3ikK)7r, {.pooh_>j4{ܾ "]b:& O\YU{C/n_RcWzԢ*Y.>* "Fg^EIAC%ƒ3޼:-SR.q2ϓ1=kmGeӵ춒WW7;CCgS9G+5ᆗu7epqPMB7R0(UKO|NE]&c];^IKXվ~>ؖ6VVv Ԩl:Oqkc+ENI7%dݯ͙ L[Ԣ>ZsҽwvySKq4#?<񾽠^L+$JOͅ;r ~>?Ťs)DV7nu0nnބ֍+˙|Ebk.(0tpRz[\VyRZ٩}Ϛns[*_[Ż֕דG%KXN+9ݴ8 {?fsF{m>m 0@8$&@[_K81ŠI6wƘYާ .b%.UtՕ^˦t6GxI5/E7頶 v>L8A8OśߊѨIc]>)FڊNC8;8q_2?tK%mo0,GUX‚:$B6=k g^5fSz3g,7Ԝxiֵ։[_NHw4m[\ɻ0I$#(:S[\&;LdBXA*> 5+DVd (!l1Qߥdx <ql)~Kx+0TBd潊aϳih)<+~팂y9K]mdݨT3+aY\:߄6R12ץxnj<{B\)/e 1ӦT2:spVFI ŹBkF9.jTP6{+FE+E#;P4C>ă1К\-fG!m+̓mY R%c+Ga:r9Zj;]I ]TY#׊&s3DglQksχ|iZE]WFSiALVv¶#'$q|GFfA<{{|?ikxzOjڃI+(ʬ2z8=+/g~~/߅:.hm,2o]و%^RONSMGū^ܽ8H20EAb;ֳ<[,o Uqm6/{gGmBVRf%}Z=pXWzιھ.phcMҥ5e)Iw?Xab+ᵷXKtʃ.#>Vu5GYtncc.Q"BFF{״xwgD'<x8H6W?0}+Zx#zՎI{bΐ͎ s~>&i|?w>=-Χb$Ԓ+Sp`H&cO RUc=ߡ3kB)JiKE;Ğ7v_eF/ 葅,O$ks^e֙-sswiL*>.دfJOEĭщ5Z[k,0\ۏ\tb΋$ڷ2կ5wc/2Xm't_'h V]Դa/%đ!F;yԖ^Լu#E5CprcRrTOj?>KO wL7RܥYb||vO Em97N,˰8lER' %}U㋣%WKEbJC^ˎiO]Ouψ6 r7'~(k!>&>tIcDeiNN9bVL <}oc[Ei_\$Qɜ2s*(NNkpp`߬4B⾐\o90ʭb>r_&(jm?c狯TP?UmOWcZۧwq.ѺK0*TH$ o_ZT;GF;(^?}~R)8IixKNl+&zsll&SD\,vj| Mѧ6,7WR&qͼ¯nSзDW̎6seBXA3&{-/p41pZI+e@m&e\8<~[iof) {jyв#n9U!0tsQ!ohdF1_hE"ǘ>%IDZG -/+-lVc=\wߙ~uh/u >8&x4Jypn*H Hl iΞ=OIF(5u͕CĮVq2>^FH*zUzTLi`)Ziӡ?d lK H#3t="+udx-5 N)Cd`Eze?賬~A7(ǹ玵CCgߊ 4Z˱0v=_;^3eJ̬齬tS~ԡvI}Nc\-"tHm8Qq{|-%׆^C4*sHXd8dzMt{d_hQF:_z:|w}ku~ZΣ*]6 Jex/c : NH9&?ξsNq]gR+̄^Wj׌R3n? ~Xj"Wƛωi@ບ)4ey6\nFMp<_'_xP|U +T^[DK5!jqcu'fwo.W 8\ϱ~HT1,gs ksz. G[y X̱2BwqNj| umU}9el;I2>lr+O>"dW'X?F Dž@ ˀrs}n}FKDnt]L֙ouC-H%I$Aܶ5kZh#Լ?fy>ucEBp|݃\JxI}ZHaҮ{o*3Α:.ݻc8Py3ޗ>*Mn-̖r]%hfMT,ۣܡ'dg|m ĺ "iB+9 Y+!p% W$`zhMfIe?t *Bƫd"y|U  xJӦĺ6wvVͧMD I+`$|m=:G:whk{ ;B4h;c<4vG?zOKѯhI-2\D]Id?g韷' >Y m($FW5 ʹI70O,G*H@?/4~?G/,I2d\تʛ5>U&gOį ڟcAGlž c0]UR\j0Yep +'shYhhh#ĺl U"B@K.CSNUjSSRu*7A^N_57|g#oDp _Q_]_ǻN&O;Nтb?ωRO':uoc[Ysk7͒@=}W_W'faK#/ڒWڹ1u8)b!+^g=}4ťpZ&1uknei9P)' ߷ř4}[Ö֖v(^ FXAq 9e+^4Q2l}/s$s(`R?oR/j3֬-^z͙2_F)OmB0'xJ%RT Y}/۷o5ꟲ挵տKe8¥8=mKs7]Ik3k6v˼O«v2rx |9,Rsgz\g?u@B>??uAG\W3z ?ϦZf#T$ ^SNZO+?9lw4k([xC_X&WwIqkJ^X&u: rp23bRtM5oهU;]O [ZOyp99OtI]_߱qᯯR&K9/F\[+88ʏʾ_B*q"]Yߓ?>+6(c~WRO$8:zTp9M~ʾ>-4 WjZՔXj6&؅)g\ ޹9 sf%ݕ rG㶺M/Rs-^2ٳIȶ>WQȨƥ9=/T*V(N)^y`Zx[< oj߇~M tEٽ½J|55ү")&賣33O;րZ'z5O mvTU.@SPC܍u#YEIo I4Y@db(۴KAӾ#iQ8`[JbVu2"ڄ'!O +ߥo.?0dB#g+sOԾ$|t;:/ƺdx:="VB ,NN*u7[Kώ Mfݒga3I9bA+^_ &m-uo^2E *ơX# Win8"I2ԕ9٭Q|5g]BOռqv .@3s_ Ɵ2se5K&U3 +%86r+{^*%\7=+=S÷~)Ǣiĺ<̭7!i[ EU "&䠟I FTU|3dVjY6^=­ W&Ds[]}O[_9evPۀPMC.Ꚋ^ ծ-ҝADWu /nZ7Ra Y5HݕOy)n@ϥwW:G? %+yj^%dUp{ci:QѸV#4%,wSHoDosm)8VIYhI$ CumtϺҖo+#<ҺۿZ\k+  ."bvE'{uEpCIG S+,K}=ƍƽj?,:pS#KuTqy -#24~3s_^yV_CAkyH=:KN)$zyςgo ?~9I{OV,2oceҹqʍExsZR9;++6]UxR`r|#&S_RFxV,l sqӥ|&kfX?5dN%g\~$d#񗋳9밭]ֻK[KK5 H"8Vk@&c֠ƫ|W1.t~bqW$ Z>?_Ik\xWV λ\B$ PF+IZB(Jƪ4-?q:xw@NZWG/Y714= 2Lz6e 'GF~d{jπ0[|-՘0;c}i0_eë$2 Aൻ ݴWPch%:#f~õa 4'R|רY&}.x~.๎ ſ)2PN^3Z?|]}1|h9 Kxß 冩3K$j,IneLּeGS߷}lrNlފ}ڟP|@O* zj lx}3QWc[6T9bf~/~?KijxOb=:F#ٿj1M~=5EmBK5‘ 7e 61|3Pw/i?3̫)ۑEMíZþ.ƥױUmnW;df )GEqNm{߳oś omm]L(e'_AP|Nk^^d-V>#Bq|6YR?E(|whY2䳨2 oYw0l |,U~N|W7Nh$a;g\a ޾u<[cMi<&bYW%r>`\ n$gM޴S۬> |1EЁI rrI` ϩ~]ꗷӦ|w 8-` cZޥzS\xzS!k|NZ?t7!ʂO)}I4_|1UH.#h.\Vq`S^|-ëO\ê[A܀"NAbI"Xxr7;@BX6К+Zo JЄ͐|2JcjǺRUW<KH+2I$g1#*ɟ52{Tڕ?9!uӬtFnC.1U$d:t>w_λW5:]PZ/#XU@[:U3C/MOMg^y'"Yjze~6ԅSZnV[l3S忴kcTmdqs0?Z8_i?8O__%wVw[,L[S=7I{*n+n>k^I6O<.*v>*ri/'O5""Αǹ>i543c6cwKSN-szWT7Gamujm"=#1J Ax zU%`[1~vB5aw_k_>n$Qׯ4 dlJ |8Oa܄}w:_ OapTNKryzuv:K3ycҭ?! 碰+.QV1<)7 vx,2ZqL; kCNiQd/ [15x;˥@@mA/,ZQW'Hi̤||:Y N,+J!#?ŀ"y܇d#?JTO/|EP2 @ѿoJ5o>rzn~mQRf?qV蘯Roiu Ϡ)Uւ}W1u W?  |`Smkx'R_U&kwwm5 #gS_Vrg| &#G_|7lj.%ѭ4J$? qa_`R~f=>뿲tyG6o1GNҮ1L'~.]ៈ8tY/oJWok?< krk;"P<3.&ֱco&ȠHۂ1=y }RX\kXI ZjklF9kxMlTWš%ƛqkX4ET+ly ԡIީzS҃imoÿ~ l42-CKGYG.I257,Nkşh)x7SJiy兹em 3'/sKm_ZN-Mq&J.p 3JSةn$.υ 9*ZJ1l3mXM}KW#w u{;/OfbF#*̡'y"5A)V p3x)^a|Z?s`r(mUV*@dW':|Bߎ J ݤڬ-6k_U$ϨYEvU9q8=_<;omjezv>|̍L9|2]1fȺ|REhu#GWcp; ѧiWs{\iV 1{Vy@Bz7~*tf+ xWQw&S Rs3?˄Zj ߌ-3E YQ<1&Bb2@ׯ&R28b/i&ɷ6,@a!s1~KF>55yv&Jws\"IjI188;^m}a-t܇fHyn Yߛ{{iՄV;"VIH+^..ℝΪ&he6K̊wpG|?u9>0jHLm/&T}7W_?/CR3g}k[<8CYv`w p&:QuJ{dDuv=*X룽R6w!QFX0CM,Mmi0;wlYwX+%~c? j6aI  9b} Sp0%'R:wjK|v\UxSwܯ=MLٚsM!VbNg/‘Ɖ>~N¿/z@6DǜP_?RwaQ?!hzsgy/W͆/m]Xžbqv*wc9sնy4}&9-n)` F?w<`Eݲ*_+Ɋ@r!u:ͨjw(dSrA>/9㠯~?|LϏ]zhscA]#)} e_N]J[+uj ^_'/x::[s <Wk&F5OjsUɮu:{xU2T9:?/j۲Dҝ:qJa[|XuOg+>?LùDj8$8Lsw/׳QKlXGSaKE~{!8S j[3na]ޒ:qkfVh7q:cvBS^FNMW/Tm gQF=^^1|OQ+Xou{M(3A_;$bq4Ƭ:5^Ϲ2eioރkGf["yiҩi%f ߽Qំƛm[]g=>˧zO|3O>ϋ|1]-k"Y%w~ԲT<_x-%/xzF^F 2(8;9+_=BA K"iw%≉?=:|;f,xtNU^) ;vvluq=Ld C v=E}uZ V)t t`q*{ ` |wxE<75ͬu[H"lS$#<\o! yC&40@ۭsp%ak(AEV;v>wd<)фc'xG^][\Lԧiv8r1_μ7<)xڍ⸷D9$úDž-j*?Imߦ+еޟxC]a_lo5n7FH`+ໟsǵ~{"Lͩ>4 /nK~br OQr`J>OJ'NXo]9#Z-deiV3(x[žYL4\$ ^wYjZX^ ,qʲ)韘q_T.DK)*BRʸ%dy~39vZ\@Xg3 biSFq?׭eouV~/l/cr9$BGH?βew|TS~CZ6c3ЦI {H?4:$ k$t{&?,M9RW?;xA['/ `JN? t>"Z}edm<9R+/Jr_r;fmV_{=N>' z %`\һ+_ /)~Ge}iW,l|GjẅSVnv$`p`jG~1 Udc B:W4W4 #fݧ觅hYҴM?I^h ,ZK7^1k:57hn9 zXxt4vG1n gq  FG:#Nx!b9hץ|"#*:o|:T?0O>ݎ8`#ȍmWɌZQj [Xm QpD0]<k ~h>%x?tgMogW%2¿_wf7^M +}0?? #c߀ AI y?WSBE ?^M (}71 ‚=BP^u+Щ"|Bh?1 ‚A{|B½? /QdGǿ?@ .c߀ [A}|B½? /QdGǿ?@‚>BP_u+Щ"|Bq_{#A} }?WSBE ?^M (}_G1 ‚~AxGBdopFJ8z}c *h_G+Щ"p*厈'9ݾO.?c7'3x ?G7\9J7TпWSBE d, T 5('mr`R #2 FqޓS>"յ/wNdv9'=WSBE ?^M +ZUR4$ӵooKa_ F9*AI^jlcd/  6?OWSBE ?^M +K?e>#>JAB OdGd(/TпWSBE ?_{F|_|cd (/Oc?WSBE ?^M )h?~]_C}|B½? /QdGȟ_C} s>? .{4/_TпW'>c>C8O?8?_^½? /Q *h_G+~Ka1W!~ϟO‚|]}y *h_G+Щ"8/N|_| q>? .s;9?⬏oX־{4/_ [=6RPĻU<ܓG+~Ka1WgW?뤮CW0xuyHؚ?t XBq~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Jh%a 4~Ou? oJk#[դD6l20 P4t]OMk3wӌ6ӚW E}?G^D*?MP"&xG4Q@ڼ#@?T>AEj QhW E}?G^D*?MP"&xG4Q@ڼ#@?T>AEj QhW E}?G^D*?MP"&xG4Q@ڼ#@?T>AEj QhW E}?G^D*?MP"&xG4Q@ڼ#@?T>AEj QhW E}?G^D*?MP"&-ŸmjEA1y sEpdfrenderer-0.9.0/www/screenshots/PDF-Renderer.png0000644000175000017500000036774610727576075022074 0ustar twernertwernerPNG  IHDR-:0gAMABO pHYs  "tEXtSoftwareQuickTime 7.3 (Mac OS X)#mtIME u IDATx`Ewr\z!{+6_}}-kZ JAB~rI.>2;;Lٹ:pTWWI@  zja4###CBBVՠ7MaAA< T 5&RvFA+@4>_^^.eee bCAvV2L$00 k-;;{۶m:{,즥 w/xjzmۖ_,ݼg_6`=RiQ[_=e}9E! 6wݻw{Ȑ!4u֚]t-&&[^믓&M jgm<Pm`69⦦fh}9s&7Çm?[onѣG!`}MKK\qqq+V6l;OC[n䆃Lw3Lp `XvvƕDE %eJ!ٻB]6\գ{wu&~bplx!Q!avv ejŽ|"{w7!ʕ+#E #)dtXM pf#wxZ=uԳgϞ>}z4'@o=ɓ' ,Y}6нtJ ǎV#QXu<_|}'Vȑy>3 9YP3>z~N믿~444%w'xT@ ]رfC*k7pa_ݶoW_M2Ng}{!}Qh`ookBC}Asr-JFfͬep/"Wصhtp/Ep)wdّÇkGDNUYݫͯ3DN[є<8jɼse '6Mg6J,TF[p1:MA'ڵ zV@gԨQ?! ~ֿiQzj̘1 :|QևoN]&}ӧ.-tRѰo߾?.p+>a„ϝ;7%%b  QϟOt@-3f̼{;=?_mAM`\(vIWIJBGQ)/J BYeihmUTvzמqdCIؘ'2牌RIlDx]j]M3=G!L,y u<5Ok;k ki=w,\P;vH~O? ?曏>hРA ?>S;!!… >{۶mϟg4πqA6XO۬YQ__Km?cX޽{=)))EX[[ n8vX;Sb p@ 2󫮮&G^xQB*6ͭ>φ,s!U=8x`ա~a'׮] 8p`ԩmXO 2p@ uU{^+6З?C`t۷~KB:x ㌌;=eprسg'|h͵z mܸbC)~q1M6_{5JAxh`p^ P3קHҤ'H̙3XUUմ~9gJ%T)믿:T$y8Z#$\g뀛 hnLr HZ$,j#??GA[ cxL J<(0 8X QEg910LZ(4Lh P*!AJU@{D6:',<1.PcV*HAA!%f ¿P\9{1D=5= <=4!C9r+ wH۷ *8/q nIC\Бoʂ yd1c1XTTg= nbP9X@vJ4 ,l8 -| ښ _ J*e*TJlVOmRM]y}놭itU#8RKpJpΉ.eJD>2 }!?<GPaC_B߻woO'L#7;Ha@ d!<\ ` ҂ `[PPj{***H/+_TBE;wz,H]]V Iƾ0àA tI\PdO?C`5m4H4~~~L3f nݺ 7@݂4tL8CS 59o<@p샂[Wh޽t$yT eA]K'`H$lB?Y8_ A`47|Cq~#,N1ܟA/\ 9ǃfC%Ѭ U@Bɗ:}* |' գiJPT%Q*@B1EӔL<tbZ9zF|W"?DTHUr?R-vX|ٙGi$⪴nE|:_p~=@IZV6q;bKEyɚ%o 8qi!Eeq.AEɣjprq "=&4k,hKxʕƍ#O[$KN"AI'@8u^=z4ߧz DRs\"FNf I=u> Rohhj#@={l- Q?~VY=tnBS Z&u.ya4y&h8أez8h'2O3pˇhn7{> e2 _PJ4C~Y0 $ş.3л+ГL;u?iQ;C\lkCqUS2%%%9<5oWXeذa\H x7(9`Nlٲq޽[n%Ságe5{⦆7eʔ,n\Oty۴J@ oٲ`0Ja6X^^h29+O+1;܅[IĐDŽ >A7B"7ϟ #gdmUEƅm#33Rܹs<@IsE2 `]]]MM y91d9sfݺudbdž\MC S RL}:)Tڿ/Y Ag'N*Z~=d$᤻PWP @{o.|AH[@f{Ϟ=P?3fwJJ yRpY3gk |PP40n{Lz, ͅ5ak˖q w9灑aa"T Q4Yzfn^}'$KH,c  >_N1ϷRZn2qz!(ȗ[n駟AG: I&L #"">3kB!6nش={ЏGx[oAB[o;w.DJK/~1c,ZD' n݊6WPgϞR4(x}](̙3ǍYbY8444S=M5Y1niҥw[4!*//GPPcPP^aһᄏ궮ZT̃b\sXh"dK.p {Ŏ;@dz]M4,Aܶm[ee?Lv=*aPKpk֬q+] ,.lsu=ۓشԐp_]VYw^U;i F-oMɠSC#"h,?$>c┙ޣoڼDźn0OPQ]s89#`ޢ# IbzSGmj( W3HMME[4 7O ܖu5,gtt2 LT  ={,[ $݇~\Bʕ+A[ ;@@|JDDO[ 4m\\@ p;B NH6^@humjƹpR^Vg6_P$9p/EX4.VFєT%7`\+駟~yyyܧ˗/N>MAA䯊a4M1b˖-no i>-{Arرcɬ+.MAAJ-YdMA3꫉-j!C,[)((8p0<3g_|A۷o۷oVV} AA0?|Eqq` ^p? ¨'HOO:uj ?~ee%|ŁMnBGFFC=~3gl۶{w}G(  ?Ȯ]7͟|Ƀ>8f̘nmȐ!5k,@j*bŊ;Saȑ#zܿIW2srr@15@A\<իק~Jv cŠV^m6֚] ~ᇧzÅ~{+9v!Vtt40Ͽ[y'o  \xx_={lM| qƥXL4iRVVJ2l;w 5h ~M6͛7# t.mƝƺFؐ5tИ%K//fcرcW^Rx lժU ƏA!hzd޼y+W-eX CNNN+4=woTw3fӧ?>j(؅kh  Hy~l=7Fַl}vGg  7 4FDRiiiTT@yukAASu:]gAAH{!  a~  r 0AAA/s#   ]SSy@A;" AA:"?n.Y֕|ݦirB! [icZ&""R'O=Tʀ tԯ[ -\:w[va׬_q-s~Xmml$ bp@|Q$GYd2uNp&3Υ 4E7;-) [2ƵPD"[`|!"> 藍\`  "KG@ñˏr';K̕t\k >d#X m4}m؉,--nzKYH:NZst.[`׮]Z?\Ka[^^ޚk)^ >#b' "="dgƵ 4SزO7;xgYopc#zCaxxxf&EWTTp6s=,l։pv[kּĭ֧E;8u+o:@b0 IDATc@l:t( o=qJk {)^uNnnvfΌa0 H"* k \>hǎ- Yo>n?)hĐP0ǎL)2Ԏѣw~' o6Ǐ /<݋ %ͅ_d_7@7@"#Wu х殥 ,ūX;htx-,KAhVZa |nrP X!iģ2̊0~$gdd͎[Fcdd,Xn_V=zÆ  X7nZ']BS<WPFԭ;X4oH9WQ}~[siٓY+*Γ_(@pk \k1:tb5x'vtΈΧFZ9A-="22t,l $sX`~%`k˗nIv-iUŋf̘ ِ\劰$ +XqSS;dT544Gq+6p'f|wuUa͕ ( IXseijMԳskAZIs-0V]]ED*HFtn-_mjji_`9a}j}|…_#vRg^lxTĉrrNC\"Zӛ7M{MrϦ"۸=!o7VْNXB2f̘씔>gϞmXo4- HI(;*nie>>6f4 >",,,llHGm|:z2f6[[iB/یnvBAAkgޏ+d@2%[23.iƍ3MF~-qSBo7@ `B)gswCh4 `x97(Wi2hytt3VQQj놯.{r;mZ܇ ~c!σcLv^x-s]}I5+9*![2 DGv"##[))),Oggg'%%ǃcXHH*E8frͷ\뢱a>i=M[%K..2Y_7~P^+&M+P/4k ',<+P mĖ۴]B vf3w[S;,lhhh//_VWW>w9V,\;, Y9s\;8ixb{nlH{/\wRO 7.̣{g;uN5{IcKFےnQ@hs- B~-jro) 7X77^-d vZIj%͕дN˭R!-Ah?.u#o/]%i ] p[,1Z?> O%#%)0^#s~Y\p[C\\Wust.mmvk)8 # --Lj%Ӎr-%8}Rع:A` D:r?&0F[c!U^1?۾>8piOwuNB[ ҹtԵv%#H_Kz{\Q2߫ͅ\u m[ ҹt`0f"ҵ(Z|ysC7y?C/-??_PTh [!7:%c D|d7ҵ  rrAAN~ E.C  xjj4A޽ccc]_@AAP޽{^xGn,~;;# L&nC8_A}/)@ͿmxE pDI\AAn\ pg\.WՠƄB!i*m5J v?.7hq}/[nI{!=ؑnr)3PR2nbCA: D8D2YPdxmA\Ny< [6.Jv C:NѐX狡 <:G $l4,,{EJ") A@ZZҜ9Ip0_e(ټ8X|oyYAfK6>[-B*m(:k6Y@uU8\_[cUUԸq >j61ϯa)nlV+qa6$77W]d2J۳gO??-  g& $%2YpP_SXTi<u}ꩆg% Ŕ >'n2E)[Huy/ P`999@rCf9;;l\  7.uX'(۱æ BѲh*eeUݑcV=oRa͟[Z `l[>Eӥ۶k% 2yi+,,&`+2 cqa2N8ѷo_CAuX13+ݱa4M %%rrdF$hϳʐLJvy<^yy9h,\ցK*1٬ Wuj MMCA[d(/7n^q𠥾6A3|DeĠ޽aa)CUw:0@@n%ad0 qbat`t%%}}I|ȉP`1W Ÿh -t" _K6v~  :ӂ:(-"0Q#$#u vߧO}͉0@,$ ]`(E6AƦpݺ={cCYYDvADy Id%0V_HY?nTǺ!C겳e2#43GAÑ`G՗Q#aF"d[ՙƌj4CZ%šizpqAoIo=[W\N;î/@x)2`ieڋNƴ4OѼ~SJ rCSuбW^1ԴHjhNRR5B^d=;$u}I;lq$(u|tjw*Aԩq3g|}Nլ +ؿ^m\S⢈\" v **&\?|>sšb S~P%eV5hm 80o^HEovXdzU?b?p0 |9Y]U\d÷E_Vv0 %K`EJ!3nAo|n{;}p~>k6}u?_Օvm (O,-.6vf8y6-\GWӬ)V3yY9IUVR|!#RDV ]Kw,GOپjH ŋ;6c! K ?pmFA:>0VUZq+? `ta#`W,V58$jdti&SbrCU˗Fu 7mX0N=>yR8|pO !G]cXxjHgrssNG䔴]۷4tࡾgJn^ ;bytvb1 m7UBAˤXLU)Z9ut7/r(p=P>XK$`N= zK6?$ t99VFC+BQC}'M<}ZF&[-V!5[UehEi+ˢcbjjB"T`ggtp0mvG^}O8#d/Xv=[O\Y^[>k^NT;ڳ9ʃ}IϣASB!O"$~OE @B&,$1Ӧ^4ե>o uuG{.O:*W^Hq@X w޹I# E-ޚ۟XetewCJK OȜ2m&褽%'&Y^}_ .]̛=ޣGft޳;6uq'@.1grN ,';f 0g< )VV :|]c'L WўW֒},;V\_KLcc(ƠyBX a7vcĒUm$nm5bj?CVFA%vɷ^uWyЧ@PMye_׷/SӜ-!! #G&MA110MQQ]#22:s̸I'lOڪu4EET{}IiaWmR"%2< j3b`DkWjFK|2a[믵'NKQ7& M3?j23'|pHTwo1VV0B4_\vU={F/I Fvmɖ-p4_{ED芊r,Q;MNpm}JX}~rk=eqPHZNHnO=eQ!?Lt]aC r}YYц Ē̬:r .벳~U \ |^1YG7vlAARYQ캎eBdt!zcXO\/;CLv 6CjEP@ 1ϋT9^kwkvxQs钮8bȀg0o_䓠=@#[o3G?}ˆU*v 2v E'(}G o /A00x*0n0rsO3g<;; ،]?B78TL0}Cs)Oa4YGv> *O sa=#Mr8Lc.E6㠟lY Q,Zt'S*TVgIxiXo]7/U(GD|r!L_uGtprKčA{eAA?FEJN.߳'vƌa_| 'l9<*pRIBAJxaN}ua&n̗Aq7.>u݇l\uhiQ!,/-YY捩ip@.;e%8ѭ{ŋfqpFaK-&St۶]Y| =B#Xn7`8h>Ϗ i bX“JC$&I,+_"I2W">-mwBPñu̪CP^< <؋}]a7VT@k8w>:dsK=+Lգ ֬:/,ڰ͟ c7*vDOvt(\u$}nmuM׮38y:*VJ[k)燵 $0<'ٜ Z(!Tr<.7 VGy-KkX…‡}t)7pGm3^pNWT qMbW(Ws3"t>[Ya{.\}.&59C?K@гO?sDj(h TYd~3SdX %PEw) BɩcƊ)M#X6kDX^ZWSG+y()'ϥ}MݢC޼#v?h2VQW <8j8Pl 闅Q3R nD~qml"  [Ah.E"qRR q6441?O HyyP(UGHˠ:ֈeU6o:UWj}{tZ*ju_V,f*(,&6/&c3 +f z=[u}Lg!0LLNӤ6Cv>4:R((ga za esRyrfkPkޟNt=g;Gg>V̷.'_)z/^:2qb_^a5okA%o%O҃"\pVՕdg̦39ٌ T4d2+J'JK&N3nyf)&.BT<؉69k4 $Dw%ɇ;.SĆùna4QV n"L]OY̠zhp>t M;E HoQ˻tQ_P}Hӣ!L|ݾe7F#l;R9صV>3<$6l{BÇk 7o:yGA.BB(35C"KOnhP>h Fy|>Aǎ :g#G1$ = 9$awlv;K>~Mψ Pڻ+b=v|VwhAy| aմl5DwEP&80Blwti y̧5>soA- z}4ٳ/:Zbr+t)b[ 0qT8۽^xaW4=qE9gɼ1A ۥaamC/^tpt33eA9+عABC/gT8wnd>>w8ZcB1ϟKh)nʳ[:}Yi>RN)ajiTjQ;$W Hg8{ŋōCQG@?޺ s*~xBd2W;/d?VX(/OHLp![%0x7WWUb@ʊ hL(\:qZ&P."#P̜cO>!Ɉ1(':Jܚ N&3R?Z$!2Q}AA: XzyKs+X#NNWmZ=6 `cwt1E)Օ2T,ذZ8,,| >"bb6&==5"@fEBbYJn$# aaaR:ɵoX @AxWUA@ytQrE% ݢbLdaa}_ݢ^b`ȭX,vߐx%R85]%Ƙ`>{^ZبC/ R&`F^OQ U&+MKy4`hT ¤{]]]Ϙ̌ QF@djaBV3r F>qn--"-?R$ Ih1ltbjZh,).JIMSʖ^8NP],RQalcb܂9VW1h-;U5W8k 2cٜ]=&rcUWjENdJub"#󟑣G}Aͅ  zJ w}-GE<`fc0v;Sv;_砘Ҋ`)&|NGAtzyy|z-jM'uNOz z&ԅXyP! 9ؤN3GMdK4##~rF[ZZ r}m-H%P[w2븺!)9e/kSRdgsmmMHpÇ&MzSDȿp!@Z3g:tf5Uzj$~߼)(88'dUe^ Tۆdo\d6W41}@k8ytБBCCD%N/EE3-Yw ۓ/2B3@>[D9tZ=C eɫ4-3. vnۥ2~rJ#&?Z,vh4lLާs  2_"Ӽkaf$֭ky|^L|\uUUiY1- h|3Nn8th_}j bbbbc%RiFFCGDbD&91v!_^VE*hq-.FDEvZ@_hNMە0eKˢ?@:dX}n T]aMY]3|AxXի7#9)0%6e!)Aw͹?;ibгg/7kn]usۣ{{\`=g5]E&%EԋłV%닝  u+Z?3+,>ur؈eC ?}lOLp^/O8jj4MdT P~P*!aa:o>WHk`EYQ\JCBrs.iuȨ ! oB_&wDxDFFS'H*/-9zЀjFcN@sgT'TUƁH hݱu+Dx0aRө) )gx6tO?9'at:VӐb> /]44ͲҒoQ-?a;vhI_ߚ+fAkyMsZq仯wxFTZ<>ZDAZ$բ:HL gG0iF>}j֭w6?x´n;$&&Ⲳ)f۳k1O4y}{g<KR*]O:#E"Q^9aN:&NWXaٕsٛ{B6b->}rá߿//Rq6?~D": Z sI}2e]BR%9W?Ń|G.]IK )BzK[(Jh)PBq;$$HB.r޻1|n77;;3;d;;x4NܰAX``&0tfUE"фI XZNO+OYW'jVLc긡>C Ő'eJ{+/.).d QԉRzOMI~(hh8s:1rpt{DҘ7[1L&B(}AX!F=bM@q:w#pZǭQ78u}+ܹuQ,i>8oԸh4L %վH@M!>i}r9Dkh3akcb֎BC4eY]]ҳI< C %5LC0x $@c1DR؊P?pp 4NL&?JGD6@ ^@r[kA#q-,,K-*@ 9cȟ)$%D>}5+?zL!;$'[&&ij=*+*||}3,JQ**Դ>//[pHB|_vfgFkaaijjX)F7~-),,RiPr2L"e2+kw|}rsr+*x&&&B@Pމ=u3"Cevu|2"@:9::ueE"EHS3Z>{/xyԬVqqM-_0PZ@Ѐ25i׮8)UC}=Naee}+f>vخVsDRvvx`{zzZFz Mg0lJ%H\I "AuRZ (?^SFx-1?I'Df L*).Mv`^O4WT,*,g;VUUT.nnJ X,&S(nB@9999bH$s\LV33BCC𲳳'H $6Q,ۛFYi=TWwRrﺘ;*$;w7r8ԝPb> @ x{AؠAX Phy4|a @ C.4=@0Q}3(iqݚ-mH短gΜZիVBdTԍFH,+WU 5 +W.UUUB&RT(@8$vA+]"`G+"lj:[:s5i0O(~uְ 1^ (B @ KGUrEʗ_Mf1` QiL&Bۋq&PTDka8qXݻ}J%eFnnnׯ]P666vVظW>OEx(i Y]]U[[dCDIs_$ )O8v9Y 6],[{4kg\"0@ ^^ ,#(}ODP-̱ʊ=zak!O0j@ Waxy~C6ֶi]:uڌ-X$c%~PP Θ`azZZhF1kZTPh59{8pЙ3 TTϜ3w^ݻA(N./R]]5dpKK̬F'K:8::gge BAmNTه!򂏊OII ;@MPPPO"zpnB@ ee%66vmIYft*4-L&t:JR4@$ E]n-gcNw@ !4@?ު>6Ƿ׊퍌ϋٿ?Z&?vϯIMI>q.--SV2iV+ׅO0^KJ&i,6==}ᥥIɣnj),,gW׺Zggg;{%'Awvvٶu HR.;'.%9yG"NJee ,< Gek&L673NHHpvqի7A.yㆯ<))Nj44C IDATVVVPoWi]-ڕ}vs_~'V@ ؈.[䍃BPSNhN@ cxAL[aTثUT*P(:(DB:RF]Rܹ]̰‡5pZ?NIӇZ,!@ 9V-T0UVV[TT(<=@U899s8 D*%%NJLԥqD"**Baccy\p>[f1ǂ|''gݡx (]LaAX,?`h2YcibH$fk@4K\uJ?zM??DL&"_b"8$8))QP܎|bCC}PPJyF)//v*N#/Ie߭\dll`2cܺnmm RF)ZZwܴIRIeҾ>_MuͥKjABzJ9fX KK/pEEvUt-%%rk# &˧gOCv`@ qF҂r"W(P7RA" ]S@Z׈K.Vp٤^t ~:okOl6@dX z '6 @f@ -zԕD"x i0/8'JR2 G͛f\xR.^f8^={@VعB1c-D"65iany{< O l C Őkf7Q7]Zl6  d2Ioɀ=\L?M  P)S4_ fM&?/:7@ N>td-,,Bw?t? 2lǏp ̙ox⩈a#98<U*Mq+&w) }.sI jd@ ˓Ʒ[^^Nl뫫rAvqܹ ӧ"ti/]hjjV__ԍD";:::99=r1c#oܰ۳{7֭[IIIqEo̴wpHIN&|> 2Y\\ɓ'D"e|*JT($;;{7wK/QiZ3{   =r@( kVvvu!!4---ٳeRLwoy$"10(ʪhڌuuu-F2So_YGP^V>qd8=v ~~V66P:F(((XpQA~B  MV/@ ˋ0?amV]]u/!{>}n7B>|xYiix V1t.WV^z]tގF' +*zmll,(N$&&Pav흚 ? B&Z>JXYYAd2dR7͂Gwn??B?QxG@xyiU  < x@ĵ @  0ji1"@R{A~xyiטϲ*jtva8 @ 3<'8DRFEa@Xg$=jL,W R@ ╠LgLK+jEE l&%>`XnO> !]A:YS˯y7!)KT3)$ O C t3EPTo?tTy26 ҙ> @ [lk2T* @ ҨjJERcUqo$*㜅=|裡x/oߐҊ:s.VOG{}#xcva  4U]UeieE"|wmm-h2g'O~qrYcnf֊JjK e2)Ϸy> aH!1.[%`̙P(d4CJF=JZ EY O"HRw@ASRGWOoJro?B`[rAxB m[êRЫW֗|2ّ(T1Lfk@;}g~$a8t *io#)T*Uё~}.و‚\ܑ{DuU_QcJ<A: xi@NN3H$ʤW/Q|؉S]x)lY\~#ƌt N_˦&s+)k݈>~-\z9f7.1;caCF"p\8 uw?tܩq 18&?~W*;87 G0)(8=@є3+Mٕ+xk]Fw֋N7aK`좋L%I#ptt&HyI qX2@зYZYC->؉ w?_ y_H?pP2! R;ZX1n'-,|Uetе) ~[p h9sN bdd}g.9DӖ@Uۿ?+88:3yIqᙓǧΜsprX_~&vlڊKd-{oH z.y_?C7q Gll!ZDJz#4.8ˆ?iӡ1&c͸W.]ŒrV. Y-\>&A I cʌM4nƖ8:9 u}uKꓥWF_3fe}.o߲i˰dE"{g`VAqҴp[+ 08W@)U*Wn?ea{vlptvF\7 y=1oWǚTT߽kحǀg@$~ m6 2fU~/lDĩ3!Ox++x5Es[w-_q{%Ps&ѮR=ݕrwtRɚ%qD\$6~)Q4DPϻ / vA!p){E &3|]$Rob0Pi>b,V}𰑡={O&@hRm TF𧮋ljSX:s}VЮ6YA7!9n!W[Hc&.il۵?+Ls,2c[1a8m3Bn6E/t`OC}@<;8b" % :u6M@%wn2pL@oݼASZnN畕&& 7lFOZӵD"414ޝKpE:s|/^9,,@?$ZfyجzNVvݤ<4@hQ: dPJaho ٛ6VT,ZHѝ ?ioVumcRSct.28ۉ{;A!S3m-I+ifn맟2{/K+kXu.򼶬ǑI$ lrc,%~F߸jGGgdݠ|ba*uԏ/kj&4ދO9 ,\?YP-1f&9Ϝ=҃,-*aYhTy5*?'N$פ>VA[.1.I*=w5nielk#J ښ<=[k)uu _ye V'& ŕgui.ռ!dllL ǁ.:|TFk=+ 8}bC5 VvPxO[th8ͤ-w_ShCroeW(D"l6`UUTcJe E%RD8XҽNH\8`R2'; 6u- a?e9$V֏yMLD ef>.*U.,STÿa&-12j&P)4sZ8`9P=L(< ACnZµV[Pd5tDG^b)?۞[9X˯LmmwKoQcEh[nelN9T[&593JH|+\ͳ!V+,ha66BiɍKs1v&^q`ӏ1 Nu?tؕK>+|f}^yfBGh5b7a-?5(841!:)ga_egB`-"!l-Hؗt͔cWG׺'<#ilic}ZAT;Z֠\cj3;eV6-1z'\ ~~Jҝwn@boD}HZni 7ؙϝZ{h>1z+:h+w?vQ]sw@t+K??z{fgݽs?M5v@kmgs"RD7gIn\4n[7#$Ұ-|^\/]e?4';+<6f̳>6Zy5TWAJo/ Κ8*d)nHArvqk@~臢39F &t\.o^P {rT"/.~r$;qPk: k|RSeYQ>x<@]tͅKqݗ6%ym* [}>&&JҾUn IDATl^K/C9hCn4O" ڨ‡ص}?3 qdv6fr;&J,~l 2DѺmĠPjPMӎqs4 q=ٯ^X i2^ 0/eX9>@LB/!D+y)uG ;֐M}o~3s lQ,Qsj 뱏3t \5Fs- 7/7C|_@'=*!{EUWUݎiG?oÛP?m| MoG&&h H(Za*3bX2u f2niU*H/q5v2|kF@giO8hGXnz8Ù& a?]\ "R6;aP7,j%bNE[>jzEIq.>9޶?o.$Hܼ‚|+k!Fboh]83 A&K 6Q T W%Gû3s|u{v(5+Jf={`hkW.&y n]AWDg߼gɹ1{<, Xt] 4ף2ҶY-`ࠡX;<VyMrh9C\#Vֺ@ ioj!1260pK޲sp <)3ʘ7krؠ!d2%+3=US33GJ^L1P9&&} x mӯj8wk2)V=<,sBvP( X'쳯33Cs?p5tQסϞIzFsgL4d nl hGJdwnCϽ/9$4`e0+Vo2G5h1C=vr9t_[6,pTH$ Hc3}=z'$ߞ׫o''X|v kj6w TݥOMM̉2ֶ%Ņ7#ޫϢfm;j섭.TaMh?[pNYiay-Z;"Nqwnٱ >ˎ- rR؇=%Mu5~RSwa ?F})3fA|lssO") Dn16dg_ZR}6P8>x p 49󛷤U~aMÇVmrxۮ۶l<}.7c'L~u*w33*35׺4oc@$4IO%>znx7DgGEE~Æ |v@*W4v'jC#:֟ͦө˗.Ҵ0L!+mpr-Zk9iHP*y R v`dERױ9G+ש㆕>xx̟5%#-ubSZ-ccody9YJխv O$[XXY6㇇AjLd^\TXYY2e%U FK9FƴnԭWshh:ag+P 031x@M@^ }ɥ rkjTbwTS{&:xŖI»Px}RPWS*( x'[a85^{bB0Oo.aY_ks2qmu,b˧C׶.D,,,-n?D"սcX. 5p]Kg&񺡵k{Q:L"k=_:"/.ݳ'׃z&U^V~J9mƜ.S..nsiIqG?tH&4KB_@K-))=Wt/Jy#+3*!t3ZEEyyy)\\PV{Ec /(NΘ 󆿺5?{Fݸ N:cCN.51:9q3UCAтfմ>m+LH|vF:b qw৑1Jgvn=-D"$%[ܸz(?dDt7kRrf"&#=@ \p'غya{vl%HM̴~Ў?v@БE":G9f+xW*t 暚۹wVʛFɉ CG9v@eo{wlFL2b"f @ :\̃nsپi_AsB!h4Tém> tjkͫ+mmmlTфqVVU؊,ΠK%Zme4HUId[;{!Zbؓnͮ8;EMMN1ͭaff.J}| Fkmy`## H+/KoaaD3r2H$RfzQ=~jXlh- ';"Ɔ  JK*܊oETWWWWƒeba;(d/oP$Fy*..gBa22>KIN=~bH^^nVaA_jJR h022.+-{kԸ gOH]\OGRwnG?v.tІ6 mh{շD>6,lb0iΝ>dF) :2)/-% ؄F1!'!gg75?`2^:d2 [UYRUYdDHrA" Hlbb Ns 򂺅qs3A2.r;:T ?5ssH@&lH(hD\ /--vtr6 @kdڇaB@ ^u 'NK>ƄӰȱ;(//ںVosܤ)MR64YبTA/ ĄP33[6ZYzHX;w^:3/@ ŀ?}͜(65up,|GCBLl173Z_@ V{qnxhр@ O44B ݸRq"]KO? 253?T`(C͜.2YÊAyeCG*ޣ~uuP d>N i %͏6ōD255726"P*RiT&s_Fv}]zBTJ fd(H"Lp$6Rxp8$2Y@ xH;fRN 4ij#cn!&ϙ$Pbkk<_WTܵo[;B_xa]\{w?% >#ʊZ+k&)2ٴfn|՟+㙰{v&@L3DG"=$Xg"‡_k_|A|j 1<|򼣞Ma/G6sΧ_}s_cu֖/&%ť%E=z~xG @LBڳ(5N3> ϟnodFO?{=rċ@~+mA㽟>d+1cdDPrD"ќoQ)a%En'N9FGޠP9ِxw􊊼N&Srrts4tӧ=HCt/*=z=&@c" {wq{[^VtԔï_ԕpgM]Y2q)Iϻ"*ЎyI;UUVO}Ցyn2@": G߹#HuBf0@i`O{PiTc㚚8ZW[K5sF;/ ?u%jn|{)L&KNL7`[Z \ѲҒ ^9z0/+p&7S5vaq^>.=X{ ~ E~-4)-x0h4/~G dr~pZs#`i@hs1J9H$]dRG@(f'm]u/&8;|o&LLzocݷbl7*zvLҽ:,&Z3K.Y  F''Mصn="^(vڌӂROpΠR)dBdb1LNt1FzCңh, vK {, #D׎έ]eGϪgt/ %91.'%jܜ,:*61!kfX5!d17odef5~=@&S ׳ Nk, #_)., S(A=zF2ӳ20~A4ڣei)zNP8_(v-&;cCdٺv?E,[y嫫*oFëm}-,CPyhj~M5J\S3W7Tt"C.';+JOIJW$  7r[lip[;{hz/o&x[ ӻO-#x u [YYfieZ<^yUU&n-n"lx{' R*\lr\Rc* uL< ͞s##!-pZCC8 yp3W@ ^@fosfw|guԆ~tqb&biЍ:1@G z:(}aؤ$p/.fBEsx.>pTwnfFGDcg-.n߿{k?Wʡ.Ot)_7m eӆoirZ=uSr55+ dRCWU$D"! w>X+ O?q| *[6)摉D~9]s:y  ,C;Ϳu}mˍF|qu1p] ?[އZ%ys]M7@XXa[`d`GF"͚;$]? 0y5)צ B@D:Y]n>nh>8 ~~;zvsݚϝ?ktO2Gng`=v促GO>̌tX@<_:ՋV}(|P8`+3Lw/xͽ{֬9]=}X. ?LV3{ % fD" n(U_bZ]Ml߷8Oo_45az10۪ʊ"q5"`x:+@1Dݧ~V,sA~޿{vBn_:V_"eA_`\ijJґߪH)3fA 0 qaX|͙E-xJL{k}Nrt,__^nΰc >+3}R${Ifؽck#?w'p{^޾r<.ֿ{wmbOMohP5+Θ\_Wwy?\ڠa~P=>uh :v 3g ,ݙt =ag`vLԲ}9pQc&䤽ٱ Z~a/ mC{ 5L&G]zňG=|z(COi\ALHhO g1GgO #J?|oQJR"q "bIA6o&Tʷ7ۃ%+F8ḛjsRmUu= >r钅qڙٶR^zρC{{^Bܝo F!+hyX={7s ȸc~T(@6}wXJPK+s)G|9CDj>qxn݌. T{#&v {zoo7w{3SB''"ڣ6,,ҪoAETgI%uyNn'ދ~f^M HS3u{qMJ9D3*-)@n ~Wni8m_]])ЭF;}/%!w~'?92J$y_0[XZ1w>Nɤ8W~nfٹ0^hviLE=5opeeX̹S'AEw>aL^MF޸ Ä}ݥ'8'ҏ'H}~ᢛH$Sf\N==Z~J(i]K(r¶v-^щ;2%:0YkWL_֓J%8]cU ^ns iP0l k#ذp߰kW. 9No&HQhО=}up@ZZ]?j8gicelbkblP%>Jt+3Uw*_+0#lq/%5z4 ^Os5ǒ=;ü|YDq|/ɣ;;U@ |vgw볻Q:s9Ju>o77;;3|w7\x^IIuQ!5JĎ2 JKK`GGGd?KKbc-m6vhpj`h/*PRBIWW H47vo_:swIEԞLJ\` wh4 o#uC"4kqqhPH3 ,͚gp?9Hb6C|5v"9*!,$0)=p{o`j)!vVs+7oǐ])92ЫCgmA%()YH7F MZ'!\>}W3cPdt,wo|hz&Z[sV ';()B/Oy"؇5yhi뤧of`H{e}hzA ?*((ZU_ K%EEqR A-dff;v)NvV&**",bctpNYYqQmFGF=w;<4}*%hJƲcUJ]5PCS .}v6.:|&rEBaIKIo\ JLH:?t؃)$(t^._Pb:*^. uE$(%8mܶ{pc 4=8XJD#SOV @ak셝ܮyR, / M9yVe%>aCaVÒz"3cv?I7kUUBedtk`h)!$EV~.EԔ*!ERd  cB)q ePp*yf .Ĩ%T`061jܣw^z'|ɁmܤifRIKAD_AeJJ%LVNh4z8DMB6nU4ZٮRRP`VKܴw4jr7~/ن5u _a!ABK2U"G zN#BB!9 &;>z7~E>~3F&E  1o)dkvRuVYY ^X$'o߸ѩ3*]Ix߻ӣW<Ϯ23X,7\\p/:uѭU! Ul'k<؜}Oզk{{P{Ҹg aӓ!鍘+B!wsn%, Z>aA))A75D 7n^kPRݼk[6{̌W/_t.<4ء}]{215 9gfWaȁ\@LjX;6{^I$'~"DX~NڌO{@|уՔ8[ Ү%F sLwl7Kdز~ׁcu@ ~6.IPŽ_QޫO(S3^pz|^^v~\W.99xKYIYVNǏqX^^}YY@ ܿkglFz'oO|!A&fMKMUVQ׈oS8ڟN+So*Lcdg#3a|S5da?> MLD^ĤqC=sE!.= 0𫬬,8П'ǁik8XA|"ࠀb 'Hz͚ k$$W|\Du ;w٧g"gakDo2-]BC^>krx\lt&W턅HFGC>m0YޭW޿E"%هoL,jX->^ 4 !qmcQA;hTzvvֻ7~}Wkem^Ͻ젡1wlUK#CPufSQkסk]Jo˥ SBėeJIꥧ1LxvXXX)(*CIIA*qDN6wP*)ڷro^Ͻ1 Gܸz[)y gh:!j?h(ՋϞ<s_<}MjޝΣK8G.~HOOt4⢭ל>~$(CM*y9kD7 VC#- p-ŀt&_<{ lߡK ;MݱyR_pQ%EE)7((_#"ӿj3aw'ϻyWGf۲23fN0 ߾ۻk:`@75F ٹF!A E% 7,+~z9\P hރGLbUEO3N(YO0iS/"c\A:^jE|O]p3h~#Mf?4Ϟm\ܪ J#tk#qo%%Żo {/}}U4wljfk% n"itx]2c jw@Iqέ {q8H5^=~rllwwl8=#;wp$4[6֐"O:ɑ{ygoٹa‚v3~2Ղ!k M0n4N9 akhBLMjf\ւCFp܄I(EC,,6_&9Tڥ[-הnS๱ȩyO>i8 †U}O Ni_#aGQaITTTlz=.-- a!ݭ{{woQK߷ehhY^^o8fyyNNNNA)އwY ՙJnSw[@΃(Tʳ#JRNꡝÇ5F{Uu(>? ؇Qi:pr` Vы&ZB p"ɠJ[[ܕ[nQUS//0RD0ܳxfni]K:t骫o9DjUfU(w|%rYY񈪓ܻof{![+ qɉx4:y޿{;"pӞ'pÄuts-@ ~ ___;;ܹse3 9o^;++SFzh[j12..Y *CCp Mxi(;{TbJr <4 _ [äW HyҼ녒$DSU%'##irrr (g2@ILk7o'ZMggoF'/HHqyҟo) HMIe}?U1_?a@ $6f 7A=#֛Fт 0h0<{gv[$45 V300 ;))+ uFc;bDx.'+! &Ȥ!/f̷5 By;Ҁq?j}IoF\LڕzlN ZXZ#@ ~{j/{eT*mȰ/,:ڰN,1ۢYܚ"é 6Y{J~_;AL[h/1acME ~ytY=kCyxdkv ;Q?}NA!՘R1ɷe5_F ӥKIIK_ VwquXhԷmP+.* PHNJzؤ|~>2_|aaia!,VUgM7~W[n=u!~;FULyt"#oL:֭f鮨$9)u҅.]?>z2mLC"#"Z:9y?{JјLs+__==}==Pܺޛ~ޤ$G{v;UPݷw> CH j"^y SM:mڷi)*b> :IAQa^PЩsppNVVwoׯ_C|.a^'Zڈ\wXsk!oGaQ[FgEGG#222N511~岣ch)iEϽ[h}@ny:<!5MMMj# DNDCWg6$\_[zA}:5a#Ϝ5Z:9C\ZUpغMSYt̲LmN&!1IM' ىUCC%\[ɻ7ss!whB*ľ d@R @iԺd=``hXOA JGXL_˕۲WL uou!_赭-Z33ҵ[RfFppl&&finaIaNNg7JCn#k sUb0j^Tϗ劋րe<_bbhD@ԳQպ觺SPUfx=UV=BOEE4,mZX5fU*:zTbMFa+ڵ{Vfʵ(өwnݴvӶ~ SU>g=nܻ]uriUwl^ZXZ TWPd-Xw;{--?CM-mޢbƙ@ (g? kw\W\RRѨ> gw ӳիWTUT-tۗuRRRTv}2`2&Lk9;T &zÄB! plXFCCOB ~"̕>_3SϿ@-Wءvly߫N"LC72=u|ˆ5n%t؏Nq,髬,nj[PPabltONNWSSS,:$u KQܴ~>2_@55yN0.dkFZ3aȱt͆?i*)_QV#Bٳ۠ MIF ߑ1uKK99)iix:S54ڵNmBv\lﵵu<<:HC\x/,,׈).1DC)JOoH }}ݼ~oAG1Qy&9<.OVNN DEƦju /).RRRlvaLT$[ZתY8: &-/#99yS3sYYON !rs{ IDATmlLI%F#rܜ2ҖV6!Ғ J[ZȈu#w>+r雚VʹO i,s :GKKKccCU0Rp.+) JZ\QQAGWO8ms K8KA 85ϗ5clľ+[:SDӷ[׍Mm {{WK^^+nݓ)ԟ6#!5 T u͆Cܲ~k6Z5ż{-*/]Nl5nwn<~RS>.[/\'ٽs'ZunڱɁraX]٫o!wn]߾yCnN:[{( $ή/?*5z_ϛ4e5+-(#ܻs.\4栀\~ =C}y%(rV/[ I&NN=}h+m~ w=hnA~>Q6b8c!kU1FQIiUm݂xڴ~5\AHoJh>O8=|<Ż "WÇaUmb39F3'ɞ1{>4??y7q֜u]vAy}v_lcSSh#FU<ќ\ELD6%?/DpQ#ciܺѽNTIO˖of`inР=;N?ȩ [QA̚2C'NJKJuU +ՕOgŎ[7ihjv++3CW|ެ:|T~^Mk6] w?|F1#4W86wJKK4׮SVƖ.C=0LPvoߴn⥫Ξ:kep+_|ick?y,u 7_سܕ>4ں-h;;ޡG.5_}Q?K5z!KZ6`odֈ3񃗾>7]7`į[6D 501u]ED=Fjjf>o}jaQX[iW\\|x7~/ RVV}zeՃ(+@ Kk]]i@Wr7_104H3C@FHK/7+((JYi騱.sUf߸E7 RC[C&A@8X/_8RrAG1CCIcASK,[d9&e:ޱWmPCϺV6N.z{޹w߁9 g!&T bgBmAAn}}BZfge9 Q737k dcνDySCQYYiB: @D޹(K kʊ1<{USO!"<,==f2֔ߪWF^ɔںaMFzį!Ay9 ^à |=۲7!,,q. .??ϳ[Bn2 3"  :KJ'ҵ{2femK6D#Kal B 6K(}ϽŁ<:U5}&4$PPP 4_dxhׯ^["L/~/$ҁ:ycAq.p,>\n!:u骣:Dګ@ Mf+oh,*b?]OXu uhȈH%e׮5o" c\-ŃSStuuqҤX,$Ҽy}4n)~0;dָL{-V-[IO)I޿%B޽KMN[Uvd2+ ,6&zÚnF /Bp;3rhy\ &X~^s?$%}[\\GA[GlH"QL.#& 62 O$Ւ!:U9$+'̬IX%.6G?}!{䨋d715<%9''[|ɮ:j~E⏥uPQMͩKRRIY86wurPQx[lΝKJJ䴵?e뵟_ZZZJJ <۵kP`-srrxh4ᶷr L{Dr}s U:U5zDyԘ O+?Qupn$&~c95*.bx)+dV]~}ӑ-@iĴM˂8)xIiȩ녪zRbœKfv233WSDɴu~~DX 'q]EPW'C)$zNZ_ Tu@JJF)EE{.ZȽ=Fr>6 Uܹ|jky.(+5'Xߘݟ~RM*3? R Mf̞}Oulђ`>~x9b'9_PUS7*IFYxU3]J`-\\@5>gʌYb?XY}ws8|lxx&2u2#JJVC,}uquI%lXs [vmߡ4^ 9疗{?}lcg*((3]AUvD7*kQPaŖ*x|^EEÝ]@ݽ9p"DGGE98JIڪ?o @|Mi ȟHV|^ z4=G2rx{| FLdOO*-->k.gHiMM''%pyO-).>yz gO=uݖ|oD Qc'l߼#V^:IyyV+ֵ'g6–`y)) 'MI%=G(,\tqDXh~E'*'zVqnWRRo׎aZŔ9Q޻ qyΞ߾ٴnBDxYSa~ @Ա$zTdh\.\ 3aPg!zF]f޸z,q`ҕ%y𞼼 lʝ'.;-++ U-#+v67&";مΝ;.UPT*#EmjDcP1JR<~$%%z T49 )M24 Wfe%Hɗ >e@ܲW/\a!YYV6d%h9/,(ؙApe M{t ۶@ш2m_96o o/}}mRc#m445ŵJgYXIqszS3v^*23B-#eK]pW^^.dꌄ̌^7mfdc\BB|NJJQӈ0 bnaնpH8*û722:waW5W޿)+-Щ * 8[^s Mk[@fPEW 4dX]x:LN ~C*tB0-LI/}5ISؖ*l7U3@II wA#0C_l RiUJV8ӨWB0_pHg\eLI(bpdch0G 1F=F*!ASRJ?.E*DSTcJQtlLP1vIC QuS@V? _Ґt4CQFAD,SAMi)C/#ǎڣxI-ُ+Y\@T k+)1قr KNZNNFfgۦ>+, _c3~v.|IP2H]i+  e];kulBRʄy,)Ey%E)yYΠ-[?^ZZ؇5z@T]'H@oiy%4 MGMJ "!ʈ C 0&IKc20)mR.!˃t؏Xn'#81%Ld]u RXt*b4:FWyzf0/EiD4}hEQ!@ ķQ6M^n9|Pۻ`bcBL PT+wQ0P>\@ w LO|U5B_b&qF o4FB @ .v+N#d$VRl6F)((@bl"*?  (#O  )V6-S2U51Y:&SpaŘ!Ê@ oïî\̔Bu t[YYZZt:=77*//4܂▗E ttu) 1y[h/Q8|*x7]'FFA%hiGm6쯿EEExRYYpSC(255P(8 6_\F/DR r1 ʹ|^9/q1w^"@ Qo귲ѯ" h" lAdXhVǍx|ѸBj9rQWdp@K{+J, L 4nQmW#Fc0XX'TMu@ ~'쟆/STc|-G56vwv$oNVƝۻm\ggPҭW_Gg9s DÅۼqHmL?w=EDxw~zZ*nEH]&bBhx) FQt*TCK6#njg@bܜ>gN :u TG:ҪO {G6'zΣѓNP(ZVtJ}Ǯ)/&|Ng:.sISOtʕ?)+/%RAIT\AKKbja^BSS$54G/9eee!El_x{um @F$ϧ8}jG| YQ3,UnSs؟:8vwM?/?mu@~KGzUjrPT Wc04 tƯlÀҜ"@TCkF8d֍B:円䨫kٓ J445a'(NgX**)I Z**2"5%YN^ޡyU!> MLr'D씗gfdx\u pYYYaA2  IOKԲL MOOֱ))..**RQUN/}VnD8ee~LtTFzC,  ,))LP3BAVedećÁ!AźzVY :CAQ?:آ%QϐBXh0_GW'UUՠh+k[M--JZZRbk!𗧬 ĉ())VTT'DҔ Z<#Ԫ8d* Jege/4Tuvv!yy22u'.\za½ΖVPPrCC!\UM΁ܓ WD]Cn<ȒRI=*jdlB _C5m/@\ulN[rF* `i&Q;B!|wj΀Oh?=wݪe_utnں uˆ7]ٺsϿkKKKO1{i4A-^0'6& Rlμo8­WAO@c #^z9mXm6.3gϟ2}ִc"#b0kysAa&{D|;wThJ-\CuK_-/[֯ҕk._!)yhvs8q&7mm :5+ᐫXZ}Q|ⅵ۴߀θwv 7mO, *7F[MW=u\Wf>~׳w:oִISf^h "_#Fbv[7PD33w%3Us`e,~DwŐ7 1שK׭׃܁Ў΀OmXL"?l)7o?}XDx(jfҕyFr;pnhMgNY)Cl覵o^!6#oTn} ܰe*sӺU[ d٪_ѓBposPlv93y#nm;^?J̗v%߻*D#Ae28RwBP%"EҩT tƭlþN!ϼ115[q+|FGE22aKml8{FYj94JJ_?:fVgVv Π޼~ds ur:q6CnGN0fݼE76+-g.; ڕK?<ƎVXPmڶOES"z;nqݰv%4jj=m;w{vSgVSSrƵcF ~rC@ݹun޸"++٭'&jZ@d̘=OSS[6bKz8oW/@m_/}Fa[عK7 / pW.[wZM@ z"ÔUIHV IDAT1F *UOpT// n9n8DHRiT*FƄt|nѤ aMC=()Z "//?S'̚7l|J ?p0T`~~=;}Ocz͔UO:c?ˉ>pc+. 5bҥ+֊;edeҗaPኊGO*&O[knze9D?#=}P]bwz5]4Ջt.!QE%ϙ9we+%8Gݺs/;,Q uƦĽG2${]oimۧ[tNшN]ݰ8ڶks47~: Ιz jU{B===MUiQ 9}};aed$,`f`j K\ZMjTVh22J $߿_;J4: >)4~(4ɇf~d~>DDEBc[c'LvISqщ\[!Dֶvo^5R/'/߹kw>ᡠzASJ0))Ξrs5W!DAjj%:Yo11xD=}8*qdM-:2Ir>b֫o&m9yEAe߾#~%m8>_Շly"'|i!J.;cB5¥Sˠ9ĈgQÝ\Dإ+! ^e-(Q@GC=HIfה, +>]\[] jik'*7=~'kZ$JNKM؅a+==-2"LH4ex(**0--u޽!zn&mۨa\h[ΠR ,rF(ZX +nNP^lk+/Uhfbg5jTizGC՞G咿 1|P +hI!7 8 KfggmX۩))b{) Q=Okg{%|>?#=M)B> ܾ$'kji(--HhGSR^hϟ9 gL.韕lkG9rɉ fV __nNBhiH h\(&ov߹u](޾yY3P,<}sɇ$`=ٛׯ`h or5m䉤۲$Ld^F } @&|"$%%yd',r^*jPUSX_;SE I&n^ .AB|gUf0$[UzD4QWW߲cW^nwdeemFDɥ1&y~:*>YŬd'R)D hz[5h(W/fN h`naծ}'V}.%JGV9_W!'" 9Z"yC;b1t:f`hֆ$'͚3iVGdy`)^Ջ'%C]]RZ ju j!'TFF2?Ξ0#J:㗤>G~ȠKBTg¨nlai[@CW"qםϓ)SDR4j"2`jfv'O=өcvįJ=u^^b:ؾl3=VzbFf\>?ln?% #VH?)CM(2DOAL̷wDɕB &h|a?}|er&-$?7jo7n٧{W/mOL(#ӵutf[H\ሻ@"232.#Pxq-),g9y3Ia!"ydgi о@qoӮDEs-Z33 y>>/{oADh$i3k9*eee۴k-[%=Ԝs\jL4!';n\֩{Ǐ;ᤤ$Cyut\JWb0ÈC%‰Mͯ?`n˖|xVT3],L:Lc>)^^Y"&+9pgw! l?8+4))nݔ,,ȁ*^)T@ ikrNZϲeK_~%%%k[Eg^YY9}EE=ZX {Ń{GH엖z=~iec Z˛ׯ^$[O3"$8jjj)I&dEY!*:0uLgnAW/_BZj** 4}>D~:_4bTxX蠾= ]*+=\jw^nw%y #bAnбӒ1l`ؗop ؅S3sC^23.^8[^}ׇ|NkC, * a52@N.9yy+J:c[W Kpp;7 ", @B؊FMB|oB>zܡSϲ˥ڐlddGLL͌MU#\pJѓ{6/ _ȇU f] ¹.QSh,Aֽ  SܸvyYY"<,d9' QI۶ r ,Iun-Vk:&.Y:}QÇ̜=4j97r鼛{199ٻwlI+"gO;.:Sv{w2PLđgepchihD>)gm\jm1nſnHq[} 7qYaϜb0n6~_J=kԛ0>>K|`>zp8ξdΞj:"#!VbW2wÖ׭? siM[;9@ł cȓ F ӳbQQ [A8%qltl#+.Al%+ .sD %0+"Wy11QZM2h>"Ʒo^s8 ۶d;8JKN@ԯ_prVRT B&Iܽy9muP&y255ږW# O,&*2)^ @aZҤR.v&ÖLR֒)E7\MYAY UAS8EX/: ZMFdW/_Vu"aa]ag/h :o-}ܼHg^M7yLYQÐ}CUGB%y|!n_8$@|wղ%b9qgH>rE%3'<[t4َ @ ~>!R1*T4wiʠ\Cԋ8{긯7BRG7iꌟuMn ؈55=6َLRpyl4{"*Oadd>w`Ru$B|}I*EȤa *FbLԃل2}aõ2BYb߿{.,PVQunJ6Cofpcb(EYV3RHcd:cR:P u:BR?2ɠ1h4:JŻ#aM =fz58mRsRNέjX@ ~ 5e.̟ HD(@0 1!Fa2%&iiP@ ~ Pp)r"$t)"htHxѨt*Fãi{#d@ įK]FM(>ZA| n],#REUÿ~{'S|Iiq},-+62"!g[NG!EH@Q1!1ه!PsO7SG᫽c˫fedpnu⹤Vnё,sKO qb(~3.[XP0tsK|▗JuB㌌͢ 4"BL@Ri{gΜ8 ͚QT koL97/';$(@QQ1SM]CRtxs'S3K)i4*4: >)4.)4> @ _%St5zD &ں0t7,$08𽙅UYiY6k^n#\82={þ9{Ͼo\ڣsR-lJ+YY8!-geXp^6⽽9x{=slQZR殢BQ 54L̔UT޿shquhyo!&Ap4|E3(YM@4y&ZZu) ңWi :CGGO[[WWWRpi;zz͸ JJV\.;jߡKfF.x[]{B[[|6Ss@hs-m&SJSK[KS161 كJrk#'JNdmm W *¾Uxs +J=j!1Ƞ5F <'e@x<[ydۇ5*B ~h: sڦi}}?P]|IKTRK] |p8]T mM6 !MͿξg{T%PWG7잽4Oo۶Cb0w$"ؾD'o 88C)=`&ND$tS:Zwqu_ "l( HCc<Ē>EXͨ (`xBAEA~޻wlKK[^OY^^uX~uu5Uz۹NEeRkDEd2YUU5t+++UThT*QPAF(*q=  oΝ:(ۘ MlaAAIQP  x|xZ °CE/D#aCCҹh$*h.!o" \.&DhHrdB@#AQ!{)?K0ZuY!}=LS!c 2!ǽ9w ޵fAD-N8J 綒|P(W.>~p!etcUzzBg~7^A."oj5LfuUըכ/2R]B!6"$ `'qIðu }yuVVL$o`Ʈ^< m#=~ҘB9w԰?]ЌaIZwTѢ^m TVV"о ӱK־ lѪ M,{ya)q,ޱH055q5=CCG+\WQU55%ee6eemP׀ /(ȷnc^Z\Li* YA~nXCKKkHifa#Fb&d TTs8l#qNvFqRfTЦ T#D>B|>_ " 0!W1XL&%I5vW^/M0d@KaLIqg\F t ޼~U\TH$,,l۴*-))+/344O~֌t:AO;%%e/oҗ/1M]\xLq$Ͽ1 ϛ65%j躸Kx<^ffF۸***^>@B0--UYI13sʊpn9)64ZքrzZjbBw:H.))ٹ]Ь9 o=A[ `Gh df=m>|{-^pyPCCc뗋KKMhlσ\o_{CTT6MPdBím{ڍ[,B0[niP -\ ggg͟3 K2L2C^F `bjvaXؓGsfN[&`jǎ@6l&h3}8:]/ ~ `h X%&̘2!@.6V6( AZ/o9w7dEVQ#8Fq>^!)K(bcb`ѐs KSЮo۲qKo{t Μ {={]ہ\~7.l 6HXAC<ѫ/<9 O0D=| ,Yɬ^w @KKJ8 c VM͒q8zeZ`ٿ]`` ~) *2?(@@1ѯW=zٖvQ)Կ6ʄOAM?||g[fD !{ǏZwn?z'̬Pnw]rMP O,@ <#Yϟ$[ZYK(/1.oB2 S::ia)"Y X˃_!x"82$&~F1RZR {]ObAC1'KK%6iܳz@LDX(ώ=,ME= yGOEGˬ^p.>.  K{%?={(L?V.).>}򘓳˦P9ZOY|Qh"޿w77;@$;y!\EG߸~]BK"qj)SπCkkϟ=ݧ`hq&m޸mlCn>xFvvHimkcNvcGll};zm78|MfۡS0ϝ,2?:;:صm LNCCyP@2S4Պ߻[^V3|42ɘ>1??$@l%ТeJReffZFzZ~ %ė ^rsu 򠓭B RQ^ ̌t^EYM(EaQ y<[5l~u !'`p +iF< N]I[ KLEcv;  2M)-9:ZͬO>x#?a۵SVQy!f%&i(p^}q$8xð?>dELt |,*ˑ\ASff)WD Qo`dAJbt3jX5cie"Z:EHL)վzk(xdq⧺2"<*q8_`;44Lf5ĨTtu![[^.P3?0~j3##;+O5w4ǰ1oN<޿W7x<}&M9F&DE? {d:qlDC322:|dfFSK5}2'htS>gV.|ewlіX/,طg'd 2=q(TC2TX"8r"ĴXZjʜJg@UN}ߓdJOK24P>,Zژ <~%%׮\{綅W@$ a_XS#-RP͚Պ~QVVmn6x t$'y氀s(+TVsvGWF45021rnNyyY/70Nu|~G'$0:(B~ baq8lrkIH B|8<BԠd!a-U\oz+mV^gI$d }e!z_K6a) khЗ̪+h؏>_Z+Vp@ =&ᯭ>_h:׮!Lۂ [[s,̩է_\LIJ:{&J]a/# :lԃ'|=y<ƌѫ'C1m Cܺg0:\ۉYC 殽fLrbV6+ ~J< ޽#5%I]>~٬=y`33)lXjIqƏz޸~e܄rq8:t{ ܵ{ffƮ[{{4u1aH̜ ީH(B3ֳ3 JK5%S)fffeЉx8\]RA>Tp-|pxa[Z%aq\^`X=x 4Tiл8dK< ]ɥa.iA{Rce$O$`$,cE"!aKTYVP :4z܄/_df#^GӋNהNqV+ :;; 󇆄dxz{SJ;@+V7q2T }?فnMA3g|񼢢#o?Տ>>"%&M}%F_b.}VHDxXVf<5j-LWҐ2A| lTVVK;~#u@h.AU;m?wUWoޓ(3$"mtؐ Q TL֬ g,Vs~xH\ig(giXZZ9+Q ~mnW7S'~Єx-pzGy]]U-MpHF=4 =T/+--]Oa 6uttI$Xv9{C!9V,@I-Y uv1u9jؠ| $NW é3e iOVPPXث#MJ+1u ,2)4м B FfeBD?4zJ*C^=%}kIL9|[ iiTwFW V dUQFP8rn pM(=WkH icf|02(>Wy0fĐÆ?=^VV۩O䋘Kl!sfNvVzZZ4z^`EE7xwhċOCy\^Hmqi3f%=ILxڡSuf\w^4d DҲO;|?]mlM a Ǐ©>snpy:hN3~$x+YsM h379ILL޽s5aOc z(`ZgϜHKl]Fڱ cMl߭Q@HHwF=$S" ~ڞ" CAžDSHL&wuU%cM߰x?!#4zo=+I&*C={{JuȿoHHrX06ҹԜ\Vs*)ifWL*{"?ihqbSl?Gr֩s,j"Lf_v}w0xg"_v&' CJIEhW*6cC w_"ZkZLV sǶ-@pe#FN?.0p;7ܾuu6߻'=-NkhL6*#9}x=}fCLxxWn~o@-m-Y7@A-l XX7&}?~1ȡhdݽYVH4ldTG!kl& ȵx1bhx~(kj^֮ZxJ-mmA"ٝ:C =Ąx 7wψGUWW7ų(aĥ7bU$YXZA xL1qqCٶi.1 jl1fK! u DD"^Db!Zk@Hy[˃UIEEybZ9eɁ3? wp>^8~֣W~~=iWbc;8 (^}C@ yA i-7l**U61uҝ71bPc=}>r!a|d:$ P}359_ӘtZuk͚ ]o]! Z*ccL]t+ ]z @@!T X m-m^0xp&Ȱ @"4)---,BԄBO:yjbtM-_Sx45U ]ҒbS/_WUVffejkTUi4Z]jq7.t!bj;6* 1pb44ߌꁝ={֭[zzAAAɒ (3ay=tݧiA,lN"ƍ444 ^VfN4ɣP^]8tC=%6]/3oS0 X]||Ⅿ^ ְAQPm{[I[w|V#gQfع$fuƍ602q .r@`YiH$2Le+W6g RSRm ^zo}|"a[iI zqغeӁCǘj 'KJfƈכInobKJKK[c2VQQ: p7.=\.G1/.^8gff& wYT=;>͆P Рprv/7V_ZZzܙq&a~i*++_ޤ}#-rxϣ"6jITᐬG>pw,sJDuamm-7awheMhU@-d}ڭߴb)}Ԉo$]Z4w-uBUvՊ+/y|`Q_wf]zeo0{oƎN@R-]Ѫ5'3jB?&2*@V RNR@"09%SS O/ .pv;D0rM ` k^sD޴~-.nu EL\HBPxU>&6&bRމ%d5vlA're9} _ɬ<ͩҢ<1d-,. ldl,#D4/~%vx<ޗ91T@P75&rچ<;aą3x<~t6mXy?;% PUWg OxTlg !w =;-h gΞY3F^>!ǧPfgd@iH涉ȰO bX+FT ?* 4ihˎ:ۘÍ;ڣdžܽrUk7||"$*KZiL^nb rj1,z8u~%:::X//\⢢Ǧ)))3ikĎf`u#66:?//##./?ɡR ߿/kw^>|m[uuzZZj0~,Q(9xw_YTmgHF$ěa-+5A#gTHD$}{a* (@Sxgz̅+ ׬66_:˗P?{ʊ3'澏*|=ŁLbL?C#S<̉`:ݏ|2g|E|4A;Lzɢ*.G.dV;)++֮aqxg>),Տ/f =vwO^k18,VahiHaY/Hs=&j LWSd~~~Jr򈑣%FE QQ`q3{eYFuF.] `0"PI֣ ڵ# ~jj&&DQ$"N<.O[GϏ@_A$'e2 32 Bפ[؀LIHwspvqkj&'Ze@ q6JxDMsˢ}9ooTd8TyAfK[Z"DMMM;tl_Dȗ}Ey9*=ζPхUa͞{N]M4HW߰CE͆t?̽(uk( e|wZ%feVq-SL_}?8ןP4SGVM?0,S3!N?e||MCsaMc1zȒI 4cQ&ƦS)EV77^2M|C~~h@|.oJޛGNኊ;OhCb__?&==-xWLNWn41042ӣ~2utt;uZ7}akbfak)irU(zHMMٺyK?x֮o X 8xTikI$:a=́V vx0SCg!gXHNm|D䀌"h-zUA 3Q۰Sw8>d<АkO)"v;p9%eefu5/D徉~Ac$I <~s)&<JB䞝;BLKKUVVa2A \|L@o0ȹ{v]T@ZEy90\LO_½DbTDjAV$c2?K>>^aDX\qE!1mb6D印 [7߃$ vs"r3(< Ϟ9Z_`gg]?+)-166Nz^({iddD!>tr.sOLNuUUrVVfqQ pAC۶iҫW6dg_pN1+ڶ)*.TQV)++zrOnλWc=8>d/yxblڭǖY&l`hxU+Gl }b"`3  \iBE ]<5hsm\!}Vݰb!4`ģY3f͞8etN*[lPIIiPO3SM}>=oXtҸ1%@~s,;!y7)zlşv ~5f\.Z5ؾ;54{woE'NCeE-]8w 0J=Oϔ57I ^Pr}T^B-*a^@ (#a?qo pX,Dž6ʺ BytԅfEE?ypVǎrpt242y&''{Պef;vB//))6h0!h}PW׈~Cj-!<у/?{֮}4nMPCH0|q$Kn V.[S'(**4H_6TcGcO\t JJKvjLkHx&wn ƒ;!ah\ vha?aGH{Z02yTL}?`$X:{-mxܟk)Fw?BmIp\߽v`^ aN`!V~ͪWfYiiuw]`'jNuwx浣_tȟ7칿IR^tqf@6Kcmc+r `pxӧ? 3x_>Ї3b賨ȳgNIx vqtsg̛lBwwOS3] cd4q0 {> lߞLA>|@ :cQ}AȽqusvOkeTD9}Z@"iT$sv\Maaa!?YAALRW (隀L@@&#Egq~ *^ȫErVh<!@UMD&˜P??ZT~XsBs;ldN+srv!S>alNmXi L@M KUM=&:BvAHƧd8AyX^4󊵩>v^krs:Ojkg/RGWxP%dbX=ڔ]anخл/^@=^SSC ̍MLZ(uQZ+UQHPu1&2>W<Ǐ\9hׂ!|jj"C8z/Cq@D Xwr5rVn5Vs_:b22;dExԤV"8aZ*!5%WN2 nSt&aP~~^!DFwYTt|5و̠$p]VfI ,}wbRel"d276:zƴI6m>&|eW߸HJ%%g/^B ( (+xؽOYYY%ut5L/]@TJS_NHR%=n-n(J=}y<MK (E 5x~ho݂*":E%efCxAW\^Հ`YĄx y5<1@$ѫ <8aҤ#YC$<&-?< CJn =\]O/v12olYD$}a8"\pD7UA"ֳֺ~c*'#+%%Y{ّ?$L#v7lĨ{wn(m0rKUg2u͈P/.K"ڵg<~̛m54E< 0IIDxeBARX&e8ʱ1vēǏ޻{҅s2J&(tr5'/u. PeuOIqBzZ1#8lCQZ]~5[sxx?$2<4~bN"@zե[‘QʊWV">T4vӂfk?W,;,>yfN{߁Īꟑ?kμVmC@挽vS $DHIQOpLræB , GDӳnU5𑟖U,2IٶKt0>ilF"h/ga?쇛#mvX jչJ.NNena~Lͫ Il7,'fiiu5Q"1㇄DZuZ:ϣbd=lIkÞ<~N%z.Ydgv'X-EoDEJJ2^O AvԬso޸~v5fuّ;o}gDobgMrrv9p7\*F֦5 [J XfjkXm2yy /457ΖIJJ7,sXlvEee}lNF&d񅅅Ξn mLݹ}5!aI߅>y$sj+)Ȉp"(鞡CbkW#5c=$}|(di4>42]#Plb^<4$7̦ jQV6K@)>6n X†. 6įaE={9}뮚@TB!PP_p$>HKKͅ~ffS;vU!v$9b i΀x>xM2]~^4g֌n*|~7_͖\urvA{yP?VLXw1IAԲ ;eǑCAxѲylO{0 r_@@]gWט HE'Ro_ݸvE[G7}{GGg :'$'śׯJ%/0KZ|- °LGVIvaئ86266.))SCC`>6Ǎ ffBwV;/]jK LЫ?-0_!HtJ޿KLMI&ڍd||Đ::)IEbZfԥ.ݺ< Cm[ƌf`襤$@=pRFp{wnC1_ A^M1k ǎ:sd^nnKbY55= e'O4eZCBa Y[#a:<-6 2ٶ˗/{0Lty1c^x ,::;{JUܥx*Mg{{]]@ D5NڵklmcuaYY٫W<<Iߥ O?&-5Z}A+(m.rUx0s\i޸RQ^SW!ӂf˸x9$|mڴ"1Ҝb5׸P$ a3@bccaUj ![ul!D>]@ga- PX( h'WkӦMC5 1ganP h1Gi;mڲ5f ŢHʖj+O+A&(k>r蠇d2RMM-22S**oYEq|NREEQ0ۿ-v'(EwKwq>w I 3f:tp; ì{-K@@5z#FݾeQSgNvRe 6,N= F18kkIJB i^Z  ??)iiIIIHXFFgfd@#TPP ֳ'?XUY W`-)//'H3Ka݂m;vE:Pvиg.\6㕤2N%[,,,LLL@ PZBC$d2777ε O0oFAQE@+_HVRVej4u{lvNg{i{NwI&hi 2DE}i' DbwZ{^ =G{S: B&@Bq2t'`2*=*Jc888888"x؟BcWe |#)x  4U/-#UTTV\\ ęCZK TJuR\tyIi/yyy^0;35B4Ri *+< h?~Qu/)ԆL(vU6}"!_|S>|p70ron@nŝ !!VL5%<,bB+cG+xYYsL[ǏEFܻ %2un"@d7]PKKKfY[I(xI?ܜDX"5miiB m߫/Gp7H$؎K;k7,7o\ iL1 zle 85BiIvhk,$:caAzOIe>Eeצ{KaDEEaŏ;Yq=vȡ/|fΞ[Bt+/7OR`ɝ[7PvUa.޾s7z vmZ/*0P}!;kXRRңGYy08J*yNk=fgOQalLW.mݼ ߩo:O xxx޿ D5AA~>P]P-O3v r]|V6542F-GGW %$$ kxX؉gm6v UH+Wurq$'nݾs⥠\~f׮0bǨC~?p Fٔ%W7oy}|X"zG/fN z^/T5Z#]ra3۷ skߒԊڹaP 6qdTC G}!M]>e*h雕>|ps,y \3^cq0HU$vؾ 9" +'WR\™XTa kp-+3#F`"]3O.0mm ߾zNP@%xe2܃wak5֯Yу+VƣLQU r3.B%4U-z֬0y'`: 쟷` $'9zz?$83Y++˘͓A>}p ?s K5F;ݦWhjcap(""2m_ ]>??#.@%'Zme);w IL; 덫W,Ζ12i^St$jQk*|=59) ODx_F=f:*8٩FmFzzlLt_>#s7_;~h [M :b贊6z"D|^KjH$HTRk(,6$D[ RąuV@s ?'T7)"dMTUU篗`ӷOeL–M<>Y~fz9x[g*,H^9d9#l‚=222U5M"#':N24bɈu effa !rr .,v^P(>~{֣'%.""y 깺 $$Nޱ[ |  .-#^R{6  7έ1Q>|pDE+ؔMyöpp,;3\W#**mng_|qUU;Tcn5=wt!A4F)w1mAup0`*;77E wA>~Mq6C=#׬\8ii#k?h"MuΦE C#}.-H lRQBEDnʼ#\'8LLO~m۱vf,B=Pe~63];_be3zyiÎf8L kjDGX@4yK #NX[2 [А>{[9!OA7p GXSSRS`":t$~P2:: D(S ` qHݸ$hC/^\@P>RRGu_>zdrݻ{dƬ=LKRS/\BtD~>^" U3S5Q3d&$ݗ@~hR.[077aŰ|z4h=h/4 奐{2e~mw7odeeb*h1BbF;\fvuKg&&Ļ?*$$d050`Ū5"n}N;iJSxyki2wm )5-$'Agj`yy-TB޹5QXXcIIkE"`GE_5Ӎ?ﱱ[HjN{B? 1j)a!QQL:+ X)ܗ-Ҷpp: &L/pg IDAT7n>t`0^zdKH(6?H$3/]8omajaiJK .--^lNowgjjjq߾)**X’@ TTTBCF4PV?^43Xh HzÌGUUU"̹ ؋-t߻;n$Z8o(qq W/JJJ8ջO~xon[K[۱Po@BRdL^'M>_;w O_b<q^i©woG[YZRWIY4qV&[hw451e*",0q+8Lzh;\s!= ٳgKKK6((7-_Ԯ8AAya7LX;Lt˄bԔyEĆHrKѐb\~Ԣ75% L6 {Innؒw+{f9pdeeMuLfYD pfQC6\OSSީ, ͑ -?)4Y P)ʊ#F0ՌM`X))),\EG衞 +=$M?|7'!;+KUUʺ=á,Z?3';;..BLt| )))֩&T*z N-?p 4aw :tȐp(""2YHHKJJ4Iqqq,_A!!HVAQqtaa!+*)Ϟ3W^Q:qq1`'N 65d2e쒲RAASS3111{0PTȨ^On^a!8,//kAis灀)s+g%gff' }y1116'NP Rz }:''ĩ_>$q4ћk;f,ӌxnn 0sUIwu׮k45n 4o|idr|LMAx[쀤Pj'jhhDDDյ |z!H^" ^T2͏P! Q.Ճ %e&{lƄ Ha <HPt$eT5KUCCU9 <\ bĒ_~cPk:q >6 [~~~^^^"lA`:Ne]k*5!茌Ȇw v&HDRSH* dJAE%KҘDDI4n7IGt"VQPU\]WYYM3\$ 0:pp~fނO̝5cTrrRTd:q8;[ĄR#cN`22ܮjjiwm8]PUQ_g_QNB4a'/5tP"RQpq!`cq&LE+>!*"56 pS($ D$ʪL2Jgr WQ H'rYZ5 I,!WT!'.94/ H""įL*}())zv/_M:iTlp9Fڲm{ó<<<iޝ-Gk;[x!Nv6uZqB RQEhx3,&vHt S:XABg:efF _&F 4čP2ZEnx@Y™IAš/E e* rsn]]*:[wt8Ū5VtKHDbȖ6AFFBZjP:dGѶ: 4L(ɨ=V?"|a0ըb*+$`%eJA) &N@a 2,DD왮pppprdk`4B]Txz{薉Ls72 W[HH҂LSs_?Ka#PkJ<_l|}mrT?ފ"jgi4j`ݟvIloئU:{uv¢I6o=fi.pcۖԔk7ncd2yLm]ݵ64aR\>t=)~Kn`ɽ;w6l2x&J5co)+=~X뭭I EDDN2MRJ d2fLӧ-!-Yj`h&c]z/==`((*7k\^1ݽ d.SPݶ}g2j 8PVۋvL3"<|wTNgB 럔$%%%{yy䞘~%Uf?!Ц"y˗>555ho/O##- 1ѯ^)W/ F +.*D <~XZn7{j !9% $$Ľ=oAVV3%9ǻ5BD={l1~~>#9t 7'gȐÆedڱn5g=KV@[gUk>Qf&a iц$[{v{i+xXPRRv󶂂B'p%L$4$Oܟ jz;9OoEO=AR vTNpt=?r1}{:z@H1wcr-$7@Ur/pg&:kґMݹ}kg]9DQIG/!) V5x}Fbbv]tHDbBbXVVREm1%։a88] ++А;f#Ff"a!j͍: PmZ)LA µYmva: @=w.Ţ!f}[TjTT$h@ZdDyĺA<|W^O<.,,̌|-Z%%%>}2n3P)e=8wP8aZbs #rҺZOte0[שΓU26qy-,*\vAjRjgΘyyl\s>Tĉ4: =5m[7?g$$X]|s( v}eT)-Y #33}0`ڃA`uk 9#$CFpBoiS{0aScn/5_Ӿ 7WSq>Bʏ=DCBB@**+]8Ҭ,3#"|>˒M̎94D{0T9VWAͽV4< X}bْ㰳ewv]۸ameez DBֆ';:@mCDMU©K-9)^W:9O(j@GE ;MEݱ}PMA$ݳRMKOpw7e*<mݲ }h 4::SRۍyJ3^^!W|qCx%NaݛC| )1 WmmϽ&Mv;OXlЋ7rrlŪU˗޹}k̘q6 Y"#WYaf#̝tpvJj>~Y-[rkW-^ "B@Z͝p Hh,w?&ifaqEta#W,]rpc7mݒvgr4>(Nvl߆ٵLp3O}7 R(AE`4+Qwܙ>cVSW!>>~]NIKK[h#DCYYsB|}箁XeP@tln%+VFI_YQ)($ԟ=9(k74/6&V}<=Ր!;s Kv}bcjjj~i7[ Pkuv6/郪όC#c[+ P'Mnh<7<+(z3##dX+wJ1XS EUh#,(TlL VBPEIIᵫn)OFjH0;ւԾw6h,P`匉fE`<3\TVVT8h+a(.*XϞ$1!SZhz}:_Vr'd OHdD8HC KzaSP7Jv۶XC̗,[1`Cv#tZnܷry(VpOSn"""?"# 8b)ٽ.]|aXh(|N?~TgzMi !`WZR] g"LY. gZnnG202n*C!,edE@m$sfԨHkq衃0&;#a"f!hGq7tF45QTСK e2X#g15W]]Y^u Z9X_zHPA>Ի_J*ޯؘh&f` d9s^`buǎ>&Lwx;D!*&(??DqqnD-xaݛ?).*Qq:Of{T"||K.O~~7߻:/^F/Y(c,擅픖ֻ))efkԶr`0P}Z&\ɚ<[L O)Z8 qB,,/?qXqq%k$bCIsD!ÑkW |CC#"[灄$p$7$ZjPi(6j *"#"}{vyyyxYIIV[ZZ ? @8P{PW~/j԰ f+0dv$6#ccO;#aW5 NB>~xgA#x\qZI[P| o8?atV~j䲳Mq:w |7e*: Dǻ':5j9= 9'oaZܴٗ4L&Y@vjj>_fUUU**>W;hYkj~Zϧ}^inUC":έCÄJ'1:{x9+kCæ SUU4$-P0)A8cK.]yunB2N; D ?ߔz<=k7>>>M/NZJKylb%%%#7g%+=Һ1Fsɓ'ӗkvVݸ.ٳLLMz1L.;o4g?ng#z}XTTt1Թ5HJI%;dHttTbB,Dn߹+*2WT} ?qh5Q?__?)ВS/SSS%%- 8PN?:xY$Mwً-`ee fi`발)8]RTDx8?x B⚷`6mX;Bvv0==}-gjSZL+VHOy㺥(EEII.]E'늉fM9 IDAT3 ܟ>|.N?qt*WuC ~># _߮ݹwo3i/t򽻇Iҍ ::ӏo־{HDx<σ))r={4|mPPoZc6m/QآsDd}k&i q & p5U ޘvҾںmǘqMLF&;d57n–k7OUYYYk`*9M"  LWwȡGGyhhFg-0bA?Ҳ2 ۝Z-۶c3\433Xz4D99f Ѡ]UWEN"h!l/rcQbڨ5E5 k zwHJL6\=_QY ?`@jJ2?yy4}ݸ5ΝrR$'8iR×FJFF*J$xg!qGtqM" Ǝ)SSSь'ń&p dG Yx.OŪ$!Cѳ';AY257w=y ~`\S(EiSe'N(0djvf@`{~JJjd KϨ7S8qCu._% xkSB{ppppyEEIg$o`` YY֯=~+]fD'%|-݇]Z9sh{ܵaMCRVX]\DEEO:5qD+++"%-p?0KuUζ_+ $KV\NuН-6DG=~=:Lo߃FGGlٲ;((# [YZkjjcOxʕظN-οA~4AlCZd<|plN"}N\OvI!^|ׄݸiͮC: %K`kkk+%Z'֭[}ɸ߾y(**jfn~}{aaKt0 /#"< iq_Rdջ>142޸y˰;j>ݲQxyy) xDGGG;L#8R%=***:fZM{;ۊ6pԚζM-]K*C"H?7PHPPFFv``0zw˗]\\8;wIG6.ʀ$&K^^zg "iZw1RWu.Z뫪6Ν;?NMM3v,|tuu>~LLLx͛7=<<@-Zpѳg*)o1JKKۻ`^/Yi9i!ZkWJIIlZ ?Y3\JAݶesfFz--+-?CHm#ҠOuK[X`?DS*VB&>|ph3OvcfggcN$%%!!KfffYYVZzc2jĕ[7o߽g2ʴ l &::wCϞnW[ZYuqq?}qTdd||uMmN޽ᰚL2w\@qq1X5~}S!U8I{pL~S(d?cܝmފt{>N/س~\{a[m_z ٳ-Uiysf?qo_,˗.?wvЗo0đǫ;.ȈLW^O=q)*+ l+~ݍ']ZOV%q%>!<_LLSO?>??w /j&"l ,D8E`0qm׮^ix!F ']ee%Lv`sV)7d6l0kiihS5;Z,5 ```R/j{ q L=C4o0܅[SdAp^94Z O>NunMsqqAkZXXX/|uWPSDEFN[Nl?%m[@MMM3kb+W,LsNe$eF {#>JI{j3]ܺc//oó]f_=t=~lؘmM ~􉍕%Է~X" ͝1}ꧠ cÑpU/Yid,/%9y$9iI@<ݛ1D332!-2e`E0e S4vc8#̙5| ۡاX`| *P4 /|!M 3L Sξ{=v@yyyi߿Cf͘B 塖2ӱ'\B8<-xfvy!Z'P ~3gϠfHpEl7OcF[5#3#͛T)E651za3&t$"1';9!!ÿ;Ԩ8L͠m]%e H }&8LFjҥV6(:|hEq[Wޯ^2Ӯ^g7ʲ~|<4$$$0a~}xY39#&_ Oh$\zmE;p5/v!֊1偃Ӿl۾4QW@*# F [fԚ2m3--+?i`7429oG!EEE\\\OBYlGPc=<o7n?|T&-.$$ dN??N PMiВb3͎ Isy,Y s.֕KwْX;0=}O=EH/Yx{w|dfnFKHH8},Z A2 ,} SoCP/zS|Q7 8!K-8i2By򅽃ٜ\μVXVUU9v-,OuhOYvvv6V~DVVVz?mk 88L?a).m9j'ж./FwQ5!?saHUxoJ @]Ӣ'%%Ƶk=jemdA|tT CٶcXq2-315l|_G:r_p1obbz#EE%LC @jTV F0@8OvDnF薇!aYP^}}Ƙkj)-Lv-ؾgTiTdK-ejfJn| q Oo_q qΕkj+P=zpV1&0{@uP;Qh DrWRjj0h.+EZPH^mNN֟:{<~ a zz pJjؖ5 2!6­7IP5k'Mt@؄ },KܟiU}Ei:_a}ܳ(~_QrW̓D  : AS}Ç O804b>:P]UUZRm3H:4w>YA!ֺNJLP(URHOc@`C=1z JBìKR߼~WV:~ܠf9 B Q.02@sR'''GEE>`ϑi^.BH:@U`|^LiDQjSHVKKN...6%%VVx"zC>}pF7a?<{/|FDGG݈X Wi&U448#hqDXd ֖p7GYZYYXZ:`P|Pmic|:¤߄F>vq- {~u4l:pֽ.n77^ 7wj"++KFZZD hNA}Ξ9 )D` * g<|hT*U7{nDR@$6'ϟ >$>)3xz>{ i:Phkj9N|2g2^>.竂<?͟y_Q~~"wx w܆h'Nٍqqv\VyQ^MRov>x+n;;nnܰ/wjƌҠBz@XzrVNuuubBڎ 4grÎC޽wps[XZ|z9!Q=Ο;޵7DeaL&#ꄓ&pdQ\M=H~~;wlWWW?p!t8y•82mhv4땮8C gLw%S33t/,4tSÞ=Yw0?A.̴a 4Z'A?nXVYYaÆ ^wɮIIIV c-*(l@~i,YԴi_hԪ;q%KOpq v!ݘa<Ƣ?ƶ4?€gH1 >o[˗Nd[%E%,l<ث/ Ν=C$_v1ik^YYdЧOA?/|SKX}kU'v؎.i_khΛ?a[6'''!X'Ϡl304o%;>TTT89O8 s -u嫗pmzЦ]nݨQCXu2 *gMyջw!{@';Nq:1r䁃WUUeeDBZZT6CJNJ cC ajΟ=z44')fbbҧo$^^ϟ?Ott |L&!C>|@GG#0XSfho/6V[l526 -6—˼  Z..pФ9N$!!ao۷޳D"1r2[4̙3#+W.?{իWn޸M&&`m{675Yb%XVO?włz`z c(_|>ZlWsuk׀.ܹsw+jL?BCCFڢ!1Rx`1܈pP]etTJ5@Uo|ԧDM 8[6oJ}PE`(䌆xyz­Gتag0XO_23r.–g8REDEiK/vvQ~?99|}&OB؎h??S?~ϟ .//?zUAA:r$99=pWUUKHLGD[i twZz}|sO5kmrCZn}SZ[ 0ĥ=55t2˗.S( DQeƌV3ft|CNJJ;o O4HC}7lfNnMA`?v>^o `:tÇ޿J33sf)gϜy;{3۹L _o,s,{ޘ];߻{[VVӧ m>k͛6Յۨ; 7Μ=ה#N{?dmg[ѱ0Y]X-m]׈4{lii鼼<؂yMG1̙3u@o<88~{ޏR=*6X?ƞD%&DcTjAz;ݭ^NtEogμaϞ=jEP@5P( ϟߟfɂ\+H"._O}*0rДdXd耓&Iݵ@jeTDCBIl[]qҡCGkk+k KKOGzmv@֌ %B!WmZiQ-hOx#F&X)ԣ}JͤVtɰ}f۶,ʃ*J(, v:[k'Linnann޺M)SyM5jkm6iȐ 7APJR5uim֝2<==];E3fwCT*رaB۶m_lAP Y@$MB֭K5itA!s߂EBr\[o/%۴kרQ#84 IDAT "{w߇κeVP,p8MjV!21r$\bTy4|~Fvvqбa".Y&p < 7l#G 6bSss(70`? k,ea"ddX7+xx;ꅣw%b-]~5:w.B}.w ]a 3JBX"22?::W^di]YsFEE X,\fFFHj ԣLlּa,?~OvIx.*HxÝdJp|}}ͼĈSRkRs 9 1S]ܿ/3'm R?hȈxCX$zxV :Ս@Fӽ֍{De>5#lA3o^1110  H]ECA ɘq23JA>71N 5m RD=a}  aMRg6BAwu(! *ݚB4^73!oDAKصh۞fF☟H}ܚb5۶!ܲ$IϘI-f~M5@iiiU}ΝluBѯm̨>hQQQB|!V!h社]}gl/yF<3s3dLa6ްl^=WFGK%Z:\ff&/Uұj"IX[XLJݪp6kCrX$"Jx)c8HKݽh-,JD"\naii8+9ŲH$r җE*1R/ M7zpT*ɓ テp\\, ןv[7WG @c<߿/8 ǎ4Мٳܜ`{[n!ݸ~TچǏG~XMMM: v=j.2lɢzc:msin?NerpXmԦw<( jSzt gnvp,?_o7;F`c<3g0lಎ~ĉmZyفK,V( iڔp \] e^ PWmVǏ3=7'gٞNPpC?NmNy |>ﳰao ]j=zѣ^xax{.+ lC&8}*PV`-$+ aXp=0x󳴱hYޘ?N`ea1= Sg|dD uU6j_nʂ@3\[T*1cZXXnϟb=mߞsvvZk-gn1#Fбi={;xcN%m!*=t><ޗ(-7/[ j###ۣg/p <͛  5{6mΜ5:ybxkފk@d4nU&&ׯ]_"^\.@eRbc{dى:-_:1Cxel6NO_TH`s MrM[lyb]ڍr8ř3A{Ap/Ϟ>x9iӦGڵ=tÇt 1Gl~e:@-^tܹTVÆ n|֧޽w_߫Uk`w*e=tx:?AM8iO?Q;ֶuysh={5,,g e$EEe`r`>X?1bB$9Sorde YǍ;|`'/A?y7aIS#t=sss谺~/? ZZ*'' .Qg7|Ĉ|awAr߰%,lTvm@};z.֌3 `Ҥ۶w^Nv-u+W@bmm :M6{d"w?e4X }Y;W$I~:ɓ5@L4oᒝ1CJpvqoe0cgr ԚϞ=36660d٨Eb<*WUTLlL S'zӴѣG}1kS',^|ҠnذE>~޴W5mQHH>}An$a~|VǏIobx.V6o ^ˁZuׯ{Rwu] du߼ ̤iE<133 n ɓIZܿO],RCmWFM_p^^'IU{{UOTdI@zxzA?>.66%%Qܣ(j׍]J+ A~0Y#c'Oqc#Xd)Ԅ3cXe*.ukY‹M)vvmڶ* lp82xP\vv4GӧMݷo/HFP>{􄳾z.rx򸐭Z.ҝYO}I:KӦLNMM&MfΚ⛯x\A;XkaZepM&%&>~0_3!!*9[˗/&X=ݸqa#J;:9 _ ;Q7skg u7III[^nyNpiTz)ݫSk Ǐ斘б}+Wu1S ~ݸG### |9Hٓ'O :lbMɢr.矮nnϟ=رSYeP,Ŭ}*0y')֯oҸ`\xֿr(ܱk'Oʕ660bO>2tHWu{J^~iܹ-Cq)JP`\.wگ2~6 c&;wp90-[;5  Ǐ8:o#FԎpU߆^^^pQD"oiߡ=˺^X]vLHH)ܥkׅAMA?v4''ۣƌtBJJ2uh??m_;xp׏>o^?Wz RTInggׯ_| ;`X&F<+6-W$%&ƞN{t(o(j0jn6 K({X2tPui'FVVnlRGC"IsYWڵuvv jۮC7W퍴>;vIbСATp˖U_CuxJ׻R[BM ;Q`0M۶[lٿcBaii9xȐu76jr@ 5n EfΚ'[ڵkc-K/p̝d2ӭ,-w@ BJ*NW7~2`@F:up1cǮ\»aC( RBڂap}ߺM˗O8 BI 4oV!}e2FZ~= -87h fn8}8dbA.^.D"iպ8pa=Nl?`mYt=Pn^xnժ&@x7k֬UVԩ5 Z%FPSԪPȡ'"##W^t.NgpvʧaL4H$24d+SSRbRáie9u$WTðހO 2JcZp|~[>_YԚy&ÌK" }+8XuARPattV@l>{͚ys2&D-@שyr"!j1V~*w3>W&T.QL3Pl5C~&&_L,K>,wL6m u h:ӳ?77wgڡ *]\\P!;I%K?§|ssv|q0s&|nDڔ/U E 4mաӅ'j !~x9%bbtrr :u\7ߌ;vg9 60׮} 3^"}&Ur* ͎,R9sNlf2-,ML:=u7k=ޡΎնm{wW^jN5͉y;T»#Ia#O6SF/ѵ#Xry.Ǟǵ0X8[tq|<<$%*5;deFH2L6.ѴM.oA}ԲHq666eⅆ;觵.RH77011b4MZ oeeU2BZA# ju2UjUI 9,Kf.HYL@P!X,v9 &(,,KLOirss%"RMD"!li6A A# 5CsA͛85򵷳ٽ[VGwo/Ooo'ǯ,VH֬Y۰n `Hлgy>W'/¾{{_Y36m<=Q`˗w!g ҵ֦|y%:wlG{dִS ~׮- p`>mTK.uhnIII܆-$sߔɓ232`NL2Ev ڵk ;LسgHTx{W Ք)He9wLewAjm_lll }z_nwP&Ի1c>[^~@u!CK50--ʿ[.<-ZLŋxvErRҟټylgV#>֍߬X nu_@ӵ;{êB =}L&SL$ 8~ذaCw77onܸs#"4h&$Ϙ>=0@qEb3VXPX wWA^={p8e˗7pop|''.EQY19vR\;*Tl{-ڶmwa۷?v%y 0~Ν;oB$5AAW^ O>w゙Lz*/gW_Q1C iެ9szT;3ߒKXa͚=w2lР'Lرctyƌׯ_6id H?ڻo*>}?wa۶n6s~K%h׾}pPqϞ@B4]Y3A]xR] hݺuhy 9}=V$Ihh/S͛пÇ)Ղr3[:::XM.4 ȻI:LV?\6 FC#qlA>'Uê%,׭Ύr]>l A?ۿo^y{{S" prr633 J0ḻ?~LUKgΚ$,,VFDDt֭,Snj߷f24lԩ߹nuz\.HL>|5nÎ%sy)Fѧo&M9sF(r=zLYgD1v8}U+m1d2??… )Fg R(]9o| 3RY3?O0>o*}z[?2dȦ_78~~.!!>`ٴiS]@TJHH899&e'L$_i\\aC&HOOeB||Y: ~56.k֬s}R2)5kkk g޿/9)xd2 kHLL)[|dK|>d(4ã8<ӟzHJL>FCô-a$ĕf+_ffOKh\yޒzduX/!mcK; 6<|䈳T&4<>Xp\BN{5y-@+AJ#SFFFw{AYڎM*0vL^5jȔ:Re~y-d29ҳ9vv`eeBd1[5Ht bte؉ VגeKR+,:ېi[,6N.S@:љL.;he* w? T*Ld ֭]{˗4]c'W__ߊBfAI?x:6[ [hQ֭+$1F=}tM r9:+++Hh džy(f͊e/bi:0k`UmC^֦Vp@ AJ[9Ts|g7Wgs##ŲI:maH]]޶ e% p~K/n痛a.QHȖ[0ly͚_^/^HJJ =f _u~-[%z5}5j:Љ3hm߱c D/DkQz9,+. ?w.@$2?*I:otn4K&eֱ3GO.!f Xt~511t&3nӦ={ROL;CO;*k F'm+>\llmA|>oT*b޶ -Afh#@U|7Ο>x`O?g~o8mʔėfZfMff&d`u^$'Ӹ-,LG^R1S&MՉO2ERi@-]8qAtMhq#]\] x R0|H4ϪgW_ FGG8qbĉ53 ;B]|qF*{zLh|cAC>A4?ՇH`p8ݻ7lXj?CbI'߹cc32[\ɤŮ={ ҧW/6 Bde FtE&M|}}EEO<:pŪ`&`{ 4rpD&Ə=:Y ccy߷+VA5o^T)7_H$|>?00p/̚1OF222> b|~C/ _A;?lqvv|LF !t'OVɓwl^֔ 2kq&M,_;޳A>4>vÇ##"rss[jվ}k6mD A  OrG777B[d֭ fƌ999j=ٓÇ,{z֬Y`[ݻvݽ{W*{С .3vl|jDžD;yDAAO?' ";y99F..f;vܵsgrrrPp0H~N:ZCgΞ=v  C>xAbL6_fAqy{yQnjiۮH} i/GEDDd2-[LLM?AzI|HhX^;{AufY,$tjU+[ܢrng*&=bZqf ]f|>ǁ#Fch H:FroPcb奏 =m& z3kw) &՝__r޽z 0@ ϞEMCG% }{>2`oom H:~K"7p A,Sɕ*HBD79abqoAAIܬaB$yZEHy#o7Ǫ0CAKL ^%>o[߁r&_} REJ$ךBkZF+I C0AWl}y)FgSwVc|ؠEAuQ|XAffBX(,LNJ3~JB:8:$&2=zgf[}.!bhRPA2&C;u$}qLƀ  h羡9+|=Ĕɲ{Μ,rF߳v%bvrق|'.dgI$EfxF#CzFO$ASڼ\zDlN]BlӮ@WE~M23mdR nŜ>9~d#+o{H%ds j? e! T U#A9;N`jQ666={6zy[XX#G[ZXBA\t~@{91; Rw=| je.l=]\[@-=t889׀Yu,? AA/_[a訏  UdEF0kz5 CAKaG(R3jA~M>؎ޫn\p6kQ,H( 3kmn! c}fM#nRNpٙIbZyϵ+ :uH.>q(Todg;:9./RwrYX$ɭ3ڶV'A?ARΘ Ύec_y*w''% zjdh''Cё@lج{wo:qD.w$"pṹ9X[xBN6fFM:#!q?/-bX;e #T.-ϻN'266T HN7f`ff KGGX;8>ghfnFAVkh_RX=AN4Z FVP[(1۲C%bIrGA*TtͪĪb$RDEUsIj?$ij@$V)A@U \aJKjrm$C*rӶnq=/?=Nw$yn*ZaBVmmjd[! H}$Q1ϩ^}/YL3w՜F4EVml5?LF WÆ_Me   S*_+8LSf(=;9NΙ{v2MMFe (, K*~䘚CxCAN(?N*5`[Ysv5cׇDu%ARJSh}#AA>H{7Tx!%? AA/巇F?rTcG$9i4bFs\OD77]A)o܊brcoyIIItǏ #Fۻ铔}L&h{ma !*RY ݀$IJxtJK{zx x>yW~Qwo9F߿Gj4~MxxxzzzD'e/CA\WKSc#\޽uZ|x7>>sv,1gW7w\n'n蓗SFgq{AyW ofZ)FjȜBYvzyyA-prvF5a{O_SuG}CAD,QJ"OG3N &m,h :" ȻAVƸHA5D$55ty) ya P$Sژ4 Ti rPcEk -x9pJ^Ay8̨l/gsjU ŬޫrP%uh^o0 ! Hnz\NJd"\6jpe/IhC1Vڡ+ ,@xQJEAJf2XL)ܘMEJ.,M_K,,RYt.!卧)}/YRV1*>ZE0A"\XF>! WT|Vn.87?\sKcn&4{ .E)-+tcD+f- 7 Emʥ2Sk'ix̧"R[S2%t,#¹ؔ<3h,a* VJ%0I1Tr4CA hYbO Rek]JDe3 r'qORhme+l̵)<XQ+2D䅨 AҔʵR[$ 2KHI1B~Qt[5AAFF|Lz..چ>~*AkgɕT֦J)1 #H,U !`lTJօ$IMHN#H60~OVY{(E~Q1%@)   obXMb lI~i8-[h˜#L ~bNvs~/!Δ$4֊cnĕ)EREP :WU7k:!uߦʙdJ$NX,JtNcT;H1au DA"#H*S}l1ُ͌ts# #I :ao͇ wxJݯ%7)Mx'6ӘҨ h:#(5K_$ʣ/t:L*RQ T\.\.̌AHdʜBAɕf<>O>|W{;s~CL$E |6hac xwg^Jff&aɠISW٤ryTӧO L&322bf0*4DAJR$S[Cz/!nBH$S4#W&m,dJCӐk c-6bZJN&|P1-2`0X/ J%͎),,ƁA\.H$,**? AA*(/=#ʦ$&:ȤڡZZlP 6RjTj"5R Ag4g<4U%R*e___8PjL*|g P{! HQ*Ubqѵ^:wԼ6' Ar~GEBg0 l{C:ܘ`^xK62ImyH-r!dl.Aa Rx[7n2 RT*޼ۛPզ榤) N]?eQy|uX*,K bPh  H^46/Y͛;w?M3`njⰒR\+iWJoQ㇙B@?ح} Rl@5ލ z l‡1*闳A5vtnw @rR`0  f+==c_eRYHV$koyzuqszxHg*E8έ[ڶmKmգA> 7F.oc'vtPWML8:;>}˯P&UZeXChG+JoܸƦqI AA*i(3;˽FCw@(UQbBMpWVǶƭ d` Ċ,o_S? AA*wCoP`J&e˾}"MSy)F'L&k7_nӊ`Tǰr {+j0}?>>>O<@0A2 \}}~*;5$Nշ_׶iۺxRyjy#$K"ܹSk׮ Tl_CACQ VQ_[BsD7Clz|fZ5$M`)'My:<4ÇӈݻwO6έCNyP(  Ȱ;v f |!hȡW>Hyܖ=>63sr 䫤njڲmǮ)j I;׳p5>OlMy>|#T*Uvv6aX,)aQ6l *0"Fy'IDAT7wQE6޽G8ŻJ$i Dd9K9uA#ܲ%..b8??ҥ~b۷{.OK,ɑdG龌{6*tFlٲ0x%{َul;nܸS{}|9vIIIcǎ 6رcz@ dǏÁBCC#""`6t)S233߭\ 99pyUY"Ha\6#)!>'+fO,,r9 R}M:e79\ڵᗖ~cG'$P1ݻuGIٙT~O2^H|~G[ϗZW? 4XYT9OAÇAW8~d͙ӧ8/Ġ(ϣGZZX;{622tЎ;Gɴi-lc<#!yٵkש-\a,ٸW=qI>tdWK=o[,6k/ؾbΜ:+<A'|KwϾ+WGm;wD}7ݿٳgW.:}իnJ}C Ҵm=y(Jj*z=iҤ3fPX9cѢEOtMh \TJC,&&d CCQҴ#OBQ6ݻrFݎ|:b,,-bcb66ݺMHLLb&7wW.Ok=UfBʂ\L+ OCx^!СCAjҽ{={|+k: aasQ~e9^9r{ Ak+k՚E}ܦG } W}Lx<F:h/{2;Eu6NY[-G9ܹs޽Mѳg7/ٷoڱAA aY9'%&T07[[[l;yK4LR~MR" ׯ߅ /i:>lذA]K"T}FʀR(e׮])A֡CJb8$ Gh /uǙGO9|z'L˰0Am*gCAz{OqT*UVFzܽ'u}4*LمԩSa ^a!ؾ}{hhh  U#11q߾} ԕJ%VtH$b0 ߠ1 u }Dmݸ>7z͛77a.9ȡC_w  H%ы0[[[Z}aes8Z*m'0̼<__|d  vqTHNJ dxPȍzEI1%Ê8q@AwP",))ã~aXL &Sـ(%Np؆It2a )a~8CP! ȻɣG:a{/3D?B)hFw) uEu)tH$t:v3%2jÞpb b(>gJLL˓J6mŦZX," #A(6OQ5)UhѢ:$RWB?lС%Eš2 AA{ȑ" ^^^/uD"IIIy@AL@l% XHH5AA= 33 ^%ÈӧOC! TJUy} iDIENDB`pdfrenderer-0.9.0/www/screenshots/PDF-Renderer-in-Wonderland.png0000644000175000017500000202731410727131710024534 0ustar twernertwernerPNG  IHDR5KuOiCCPICC ProfilexMkQ )XBB*!iЅԴ46 a23MdE~]r'Tpх_PFʸ'1s8=B8`w[tQJd(aqnEM+0v!әOZD7}Vx2% čn$r) k5|bC)AlɮBh8gZ}B*}ÆcmLKj-^ X+< ?&+p8JLb;@)ġ 8v*9 {[k@;5Ͼ}>ˀT5#x8ph*UBtp)2mϾ;a ږ2ޯ+Հ8 ؑV 6 r7{q-{msL})?@2Tp†7~^=nKlϹ㶛-,:NR=HM(q& oU( IDATxyչ?W`pfA(PLEc4{shFo"QWohrk4も (WdgzfꪮY`|g|SgSN YBS!ʝa BP( BP(&)RʵRʿƇƑyyy űX )e{P( BP( Ba #h-hhh i'T BP( BP( B|>W[@b`1a BP( BP(5B/H)B, +DSS<8PieƖ-[ظq#6mbǎ0f&Mȑ#vlĩP( BP( bb4M;]444.ɚ5k(--2ٱcr!̜9ӳ3%NBP(h4jO>jT)%X@ q+ BH`}EӴ_~L:cǎeɌ;[w^ 96lX7^XnP"@`Xv-XkR[['K,aر <8'mFCCtP/{o6r 'pBǭP( MI UѣG3zh***3SQQѣci' J BP6/Hlž={O~ɓs+Vp1h@8.+:vilݺz|;tI|\ٳgG:|>~?tj@ BP( 0/@U6mZ ]]]hfRF v`ĩP( E_p衇rp뭷+<1bOr 7?蠃~)B6md{9{BP( E:,?rRFio޼j|+;w\9ؼy3{쀏SP(F4bO <7F{1bwfÆ \K/j*Z[[a=m۶qwsW Rsϱf({,rioc~fΜɓyhkk㗿%&L`6ǍO?MKK ||?& `ƍzDQi^~=oy晫<<쳬^7Mb->}Q3f -vn&,X3]th.y ۙ8q"?B{l5^}U93M[[[Yl9L0|P( kww7O^^PXXHAAyJ"W"NBP(ݻwox穬/'//W_}suqAq _]]ԥ^OS^yv@cc#v\~\s5}p'RZZ~3&:zh }RJ6o̼yhoog׮]k.<@~wtti&y(?Ϲ [qB 0_g`)W( B?dScРAtvvƄ`nƩiB:;;4hPwJJ BP6QYYɨQluRon4;wr!FFQQQhF)--FJJJlU1vXq|Mf̘A4eȑ+a͛g3l{PXF:t(uuu6>!`ɒ% #n%}yկ~E~~>mˆ32h bӮSCP('555as  uK8C~N0_8 Bq|ڵ MXn]]])-eƌ|'H)4ON0'h4j1dͰn9|>ƍ{!PSSN>`6nȶmM9L6./_NWWᕖ*++ l޼={yd#Fj*/xg=V( B{dS{m6sNc"c***@SP(B3& o 7@QQq0l0=5̙C8EEEDQf̘駟NUU^x!w6lsG:I&qu1k,ϟٱcC `ԨQ3iҤ!Lj3f;tR Yp!֭3󮪪/x+VPXXH^^^{3;g jkk5k?~HP( < 82Qcl(q* B?G2|p?V)( BP t<~*y^qfĩP( BP( bߓnV}1I0PT( BP( B }BP( BP(pX-eP( BP( B1M3 BP( BP DBP( BP( ~Fk BP( BP(FP( BP( B1 Q{j( BP( BR'ێ|>jkkػw/RJ kokٳ!C$D"ڵZm UTTDee|_@+j*ǏgСW8 8 >awI~~>Ynܹh4|^^UUUf/~|>J 1=϶mFyy9汽{Fmu={P[['J6/GӴJss3Æ >) BP|Hŋyg(((0_pec=_|AGGG~>쳤x~nF&/Xx1>,`.K꫁ɟHmM7Duu5~7K/1mڴ~!}=،lٲ'2uT֬YOe)bX,FWW|kf'5{}q=Y`/Bf ~͟?;o$Gy$Æ cɒ%XVshnI&QUUϛoug)38?Ϭ_,^ȯk[ׯ裏+gfg׮]b1^{5?pJJJ6+WrqǙue3]R2?t3SL:ԟSO?'۷og֭)'஻bҥ|Cyc=ӦMcر][[k[Ob _:u-[p3pI'qWfꪫ8sXv-z7Sn߾_|k%Kp)D"nv>Cl߾˗s|[JJK/ĕW^UW]EII z+uuu,[#8"|2d ,cɒ%OK?> .WL䚾LytR^ y~mvؑ1]=ݜqs9S۟/:/uVP( B᝔{j!Xf 555汇z9s{]]]~\s5̛7|G}|;Y9}.G}/،kɒ%9>뮻줨^xO<իWsw^̙;BvŝwO?ի9s9ꨣ\?>|87p[ncg?'NB:;;Y|9L6??ܬnŊ]֓?F\ҶQ-[h"nffΜi=z4Ǐg„ w͈#Xt)+WCPWW/̄ oW^9}:pwprE?+W-?{/s?[nS~~>O?4EEE,Z/^z'500e.`ڴi :n[oS#Mֺ !L 6]vF^3<._~o}[twwc?)y6h &O+YgڵkYd P~ϋ/ܹsHtKlׯ_ϔ)S\y%SU( BPx'Jɓ'|rӾ/v~aN9N9eCII 7b[-[pgdc'~!q饗vZ(O?4ַr8p֭E6ncHē?~mBà38O?Ƕs]t>({lΛa !kxfټ03g4oB%%%tuu(}z۶m455O7nl۶ csRQFQTTd_])Lo\L!}1}:O=TR^9}O~ªUXh㮻B4[JKKN[w-5]!ߦ6X?>G+N믷Ȇ3ffM=cN.˔---TVVN^4McƌI>Sƌ2O8F4|0y `Dqqxqq1;w$y ߺ?FKƌnuY,Y6xke٬Y[x'6lL:)%?87ndܹg~x?^ߗm:$_[̥=Rg BP(铟7n@6sf͚ň#y'>xG/6ŏ>( 䣏>bٲe<wqI+&ƎK 3_0O&ʸ{={6-G-2e >,/[K%2tPNG}Yk2Lee%g ݝ2NMӸo~c{դӧs}_:~Æ 3&J0y =z4B^uʅu1w\aRWqA.\HEEEƺu'ss}|rڜmyv1Xt)Gy$f̘1,]C9\ ^6c/ZP( BN=5 (**b̜9SN9h4͛9Crrt…7SN9W?x9̙3믿3f0hР& ؽ{7 u])..߸Yr%<6m'fLڸӟ?nq:5rHsg?~;?0f͢`0ȸq̍7yfN:$~!WK.Q2%uQr5ט_|z?|lϟϲe˸k !ذa*fbYw0=<5fM_YYg}6_94iwu{__¸]_A4h4ʦM w 6 c*--SO嗿%v'j2m4^{5.R3#<|O}懑gn^|Tg BP(铕^{-H;('|r;'//G'O̠A:uy;{ljN=ԜˆѣGsEqXx1?я+?~_=/Z?wݟu5Wk6k}6+>V̘nn2tSaol.ko7\S#R{J~CF\Hn]q}.dKU?вP aphIsI )g c4'5t^N\>ѹ oNW짙LgI΄Hd;Hakҧ?vǥ3.w}wΉ4Kzdr,Gy\"ھޗ.}n/^лi͹fէ%+z쿋X%=?hV.]OO=oYf29>)]Z{~f#e\qכXO'޻^p"[yhBRvk.߾ʃ~6 %p!?Kt¡|6&7 #Sܵ*>ah|O@jm5n>وw}ټ5!RZI cX;֯uJr300W}˸\6a_'gL8OLGzM~tzEqgi'`ߘ8Ol)?>=#D5oF6he՛QKMk=.Ӥ?Mfk[L~Xw]a9#2U _7wJYqbv_7~|21>'7~Gkd.o"Dn!_6'^x9b|$ )=zz:1H$,uڡ&_\KGk 0"6)n]_ppo} %q*a獕1}p16}WUM~r}Oխo ?0`Ϫ8j7M#_O%R u*Z؎l쓍%56:Aoo?Ib;igVVz%!yzz~=ٗ_W?qgKdTPZI7IoYٗɓt6{=Mq'G2zDuZe Gcmn!ǵ>ї=o+BXVҧߔQ/ qP*/?δ@BF`81x?gmu@br@K6A;gܮ~mQY;Mg;x) cb#Y/)6v5:`)5saGhe O_S8 XSvJsY;q8M۟ҟ}'n|z`yrZ9؎o*O6܇D/}]o6#ڞ/MrrԧH٧2id}O5}*w`roӧR=ھ,_Kl7c8mE^Y7fן} O8^ӟsz<$[^/gYsjx5{-.C_uxO<~zOCuļx; _?Yˏ#?^gOU'މ7Z/emz9>aј6-96W0I8'8^ꝃ\Vo *'ñ`DzXu_I30?Dsێ5vM{F"v =nF>ӱ\ >z1eIa<,'qeOKwyr6ͮMi|NjtmS{b?NLg"͹o\= JKQr{/ZD|.@q\zKQ~s?x)ew%y(]ɠ~fҸӧ)U]p kLjȗ$bNB㖮t8moz;?pR&~ C=th$~WsH B}'ˏYM[K*9z!Uĸ0K&}zMC"I kn`w+'6q3:;rCgMWl薾=Gfl'85{o$MI>$Lf&7ݍmialjXpcKn8Lur;;T|S=71 _xk}ؾmyo/ȃ^:'ꜛ޹_rf蝚%=<P GBٷߩO?gOB/-mFY1ozoP4篼_Hm?g?$8ްpEX=}l?Y˭}ao+XWX$ԷzIw,JwHBB2k$-mZ9^vȦ5tՃ0͍@L;o~m$.'*VZx[ӟ&]d}۩xcgO(T:s(@RĆHF)B\hpFHfHupv̈;]~[}3}s<,pj?Ƙ[F?o|isΰ蝝Gss[}zXs&=6MF@zz)S饫>>=z-=خk6'ۗ)<}E\wa_Ǧ77gH~XZ䟵nraI|CsH{$X*XWWo$z|஗)5:#|cZ:zEe_j=x4 X7H iu{ZZmwR\P)tFc[3hP0D͠jBA wNLaݏzOM_WF]kNl$HYj4n[n+q oIOQ鎥}Cr;oKUʾan&mGup]oY꽕_wGl3S޶o_;y'*e>g ޶K ?&v2NՄEf1!A]rVeT{X vS״p>!(),$/˷uBi@Jy/~ʡ )HJ 9b0w颳"hFwO}N]cX JjUݪI+,\/z@߫>/x*5ubüǏo39C@V/twuv:.7C΃Y]~6زO$Ki?A;ӕ&@ԋ,ž\[ݟ7Jw؞ӟh c*8=}.7ƽً}嘔wg">iU~/ӕeuANܘ61}{q{Gpկ/er$O=LAW=MsiCZ"(t3K.ɯK)%#ňbtuwFj%>6er)),FJIa^Ϸ$ňD#A‡O&5#Qv7~ @ҢR b4wR׸A%mhRRRT̠J,_L'k}|O b7`n-$W>δ9o:a@:: =E &{٬Gl&8ms Nf3OG5"+eyN1`T: ۟ p~,i[Ƀ6\~5:9`omASF$1jaf٦:%u(qM}=M~wCc/zHNoطM1fo1t JwGXpIӧ]CEY!`]a >vW=v>WjRù"Hc,7 XO}ޖF"1E<ʊ>KJEe>y! BtG#46SQZN^0X,Jck3Mttu |>bhERJbFK{ wnE(+ OLӢܻ;ѤF[{+mmHO[M()(Qc).( J\:ѧ{~>}$7p-'+6u?8.%NcF<&c5t$xܰ59_a1a?g͎9j S*'K  {\;kgKwpn8'g/#H,m t4@`&67znk1U;WkH) OpHs/2=vWkXFv\?Co=iz>^"X\8EwAFFYNRb?1~ϔNkV|3~.D&&V0%"DQO'%L۷~9^[PfwOv/)!ɯg0;U곥D_eP1:+oQ>Sω5M/E|~C&v63ޖ>EtE1^)L,ztwv] {vSQRΘFRϴ!v&n#\[;{C u;(SQ\NQAGDihrhhF*0_VwP,Z>v7QZTUTTg;6~7}H# .!h4O#!L7 40a`6R1ڟLazS\4]P?7wdw+:C$#O? '9765 9E:!LN{[D5[PDJo|Y  5>(gJ z_/h'LzhL}uqO\*F4@: ɾ-?z">7RoHY|ȤOe;:j?իX^d=$~6=;d)55h? /^d:z6wi\ ]û>a{ʄi.OMߡ)0GWM:yNēޔz!%ٗ X,& T1lHyE|g4Cv|A|09]aʊJ\^ɮl޵*SǴsT)hgvS]VΈ!C駽s/-{| RMhjmeҐB~IݑnFW\wwAe>46-]!( A띭w}OޜpKf̬X[+WQ\7hKO[i֪sȄ7CsKw7uF*>KȾWft?^8R 4S}^׿+}*}ztr_a\~L,NaN{G~ ગ6sRj#E')lS'Lwzc`>;O~\ܿ;Oo۷5Vl}k ^d~r}5Ғ'ҕTwmorW^8b"Fz ; C4?SD/ Q ^InDgtvw!u+?#$#__=#6;d"*K*!?"-;@K{+ŅE3z 614Ls[39V΁wl3L?:zjLRZVZ~y$Y_%?6=Nb:w5:3o%I! P] ^oLYq@E%Naώ6-D#ncJWg G?L]s&vܸ]40?h,F6ťǔsr5^,uu]m]U8¡׫]Ĵ@eR,ʎB弹]uwv@_=Dh;N1VY?ZQOg2$3jl/fɌ =;r ; e +կ$WΐqBS\;2gd)s&)4ƫp/}Kx(Szq;Yy!oHN~&*=ԟ/7'֟!?zCة7Y}xP/[$&¥kjӥy_+zW 0q u66mΡCnRfi33Ɣ1I #|qH;Z/~9g Q(B'8n4z_1u%QI4CCGSm˺/h5P3Gs[1Ԕ8 ?+lD'O-sA?%oi]nwYCI5M|S::I.=)%*e[K'*9jpՔAJ$2v6GIU΅) J8.v7h49Syᣢ>( ʋт~ch."/QUv>ZhecvoQA U'az\Fn5)y\`TA'hߦÐBj+``Sw~QP/ǍtnAs`x)7~ nAKԖHΛ"ja+ XO| _x$-P]q{OtoT@x1U%ĆMo3(LĆy0M@i ayN\.y!ie͉R:FR^Ğvҡ_L[YhᙎAF$E/yJ5Rng=kW#L^f;ž z="ov߇0z=:]xԧ/1!S~g8z\zV\u}~+C$—z~wUzuCJiv?M(?op I6˫-n{]營#XU!c~(c$Xi"QvW !%4tt:*mCSxs@cLy'6fxIC˩Tů6ޫ>aeCЯcGml\6c/HhLa(/m]a~WpqlcV{>?(2D4~K()(bXƁ$yQcʡT#P ZDreyՕA|@0P {{8% /lmcMpt@HEI1;H =tqp8`5V'?G/MWhtֿUOh-V0*V  VF=jpk0ܶk\;i道TLlttF $WY)O5pfJ{z>nw˞+-7OV>1*ϩ2:N"-Oj֕h&G7$7{?Fo9t.eͱS'&+չtz#X/&;G񵛰ȄiB',4V n-l(gK{}fT #xc4⅏|!|l/d̐2& ?laz^\csUYRkm447F Ƹ*twArHg$ƲeE>:c~bZEb?qlkM,8?̊i|W_ |s|G ' ptD_쀀Gmb3H#?G(;BwrٜbJ  s!ݬOiQ y}>6-"*b[c] dV in /.D ]AZ,͏?ApP??Bߐs-]1h-EI&2I[uevl&a{|ׁ]ݸJI kn=> 72fgͿmIOps{^W̠ F `{ {b-1ZfF44ƀI6hRI5zsNfF'Ͻ %nzuD7y;ޠRUgD=fYc;W9"DA?_ހG.k/'?~V3.4Oo-rG@P\˙a6jMm)BxҴJWeЮ8VVc : ƌKo"Zo ωUB髪KQ>S)%7 >UfU%B \k03PBEŋVUZsOm)FY_Q\e)s i?\?95}nwB4u7E:r˯D8X® >c'n;8 PT~7L)(r@ױT[ eš uö\B Izn4Vy!I ] D֋œ|YIt[n^K/@1\I-21:&{\}P]:CMLHU]!ʭ"pCR@oBd@ ($U;tC}|}?J{ٵxcmi)%/ܼ:_pK?x6|EŁBxV;O{s7 v1 meoi%=?og![`n?xqW+-߶3KO=8CV1{]CT#kgB702bΠ2DE^okjv#@`6Bl;iҺ;t _R&\Z_AJ 7V TG[5&^r±fw?ş_BxuL:gVg昈 ^)iu~6Nk[]vͦVϹ2"*}} *`,}ͳXΟU(QK? _Vlv;4_0lj#ѷDG?s^T;5}|'9|Of>| J_(d6MɄ+Ƥ(&2kϱ2Zf6SEg{cK̢l<8M':s8}6w6y%^Wa׌x*~/<$I]+ȹ5$ŭhF3|mp޺$]L=|!`} nLfSєA(i4e25N2vxlC.%>Hmyrv+CqA2ZBQ+קMyKGKtwq~uAw(X,q~uc_9M'{_&$J}C%d6-n`lnᝯ;ߝ<7^14?t6ee…s3bk{, LfS>ytaXH)e(:dso/<D1> L;p^7ǟ|Cv&6\݅|VF=nNB*:݂v6ïxxـgvǷ#nao+/>oxP&9֖V}H:ES  ȺWy( {t\W/gA"O [۰1'xO_JG?V|VL 7C>[-7̃U/ >s|ǫ?zVffFSѪy `^ z!hkL ~|~vSү;oƣn/o?Fx~G[(=#S&Q~ڡVs7]S.]Q~(5Q⊡uZUبY(|$=s+W-Yx(xŕ[iJ#};R=P̹@Xe-s(/)q˾3Ʒ͇rOڜT觖EN,t,/Bzd֕lTIJI є͝mwPx*fswיF36owg{wgnU7np}{fskt.Tơ B.e2zH(Aȃg`d]CChy H9##~SG1Ӎgj&*k/WGB?y5W nOuy~v+<]9^+k/t?17݌)4 4U8t7?#x7o\?Wwl|Unȃ{XB_m)ƿq?`?&UA7L?׬è#G4 wxNql=)ݮ9Iʦߪ|៼V0Mg]垶RyvKJWM;7|)Vn #W_; ~_^hjW\<['Qb>޾ίҖ3t:t2(yuv!E^Sǿ}.$)&\zn? nmsy}0&&mAVe¿/+]nY(?œy/O>Uq zus9XSZ_Gb-o*qJUEVW;>SwxhCEoQőo?9 ~7R {p%G}B}T2}sijWמ%c@KnmLeD&LIi OG/pv Dh_^g>KĀ`4qa,_O}0~s\ B^}/] x_YC(Wy,3nnK]>5ln_#_<䳷Ƽ񑇸5鰵"K1?u^v<O_0%;{p*;<ЫGln7|s zMvv K1npz&O]yOx:=K e'aP(f+RKz|~,aܞԧIS5 xOķ> Ôbڮq^׳6wJe\kiWg^< xp n+bk}8>3na{B;ཾ ?>l^洟j(C[@}LUo?q1di\c_^&>_W=3(%y!Xͬ.Wk5Fa-OCȰ8s< 7SqF,UQ2oCek_y:*z2srZ5KMw⽲Cz.|z,5Ϋuƻi-FOogulnC.psz:tR _Hg.:^A*_`EA'R*&lɄ`6w& J)$&BcuB%1|oR\|9@(uk7 | +%`L'ҜtpBCjq#]A .OAE#\I?ث8"[A{({;1n5,XGdش qKw'YVx IDAT>(R ;'Bd>5/RԧFׂ*(6\džM<']xM(+6t?^Kg)%ǹqR)Uq"tmH;Wh)!Q ܼt 7`܍+qQHtJuɄ2фiEDy>$!)zlG'0 wz$RLf8&}.9x09vb6cn'xB{ni4 n!WIOc4ti:RE/ JKf-`AQwҺ7M=,G*T&SmmnaAIk١fL@!TdnlveZjՅ ⊍ReƼB p(|5-ɷM`(8^]>N^+̒IJݙ[U1:!N vT6xN:QP$YZ&庩_B]xEYٚ|HB5?B9CKD"d :()Idͭ[L)p5& ǹu<#J"8Kt!'u*o놭r~@k[$A<(p0/?77ά=zO o }1g8N n30AbZMQܾ2 ?{&n}2i mp}LI!6€0 }AƣoHw*@_RJ8a6G忯s>џ^p2 \ M1n|66C.Vl|[ߙSm ag,_Z)N ]çl_!T)^ (+C p,aqy|6«c_-P+P֤ /[B sdan<!XWG?*)&~y_+W ʋd34>; ѿrCwzAo}YCߴ<|K id#L~R7 =JGު"M>xi1~P?m~~7B?Q7ۓh41c}7!D.n`楯'2`6!1=y>N/>u\?g8;>C7n?/ ˣ%VFzw{MT}]o{̫SeM0$>M09deIse4eyBM!=eybH3[譜9!{IB74XBhYa vQoHln$"}GI#Gt<@*}d6aGO}xW2xU(Mi݊uLƛ=RK¢Lt]HSh~w.O6'd]~0e36 i^§IҪuxuLEm'ζp՟ZCL?5 ]S)Po 4h 31c>\#_ٶ[Ӵ~W4d1s~$_ˊ3#JN9;\+||W)#r@xw er-_7 ݢ<]~"_4/㧆^w}w9韆'|W~M}G`Qydі L@hǔ0Lyoo3vz(a4\b`Y4%!̕[/rm:;c#VˌGc%=2?J0lmK!}{>pvl5OdqeEˊ:e`yGx,/WV(`ww !͢얖LY :˹SN[9anU3}e qۿ*S۰H \P!SjeϾDIMGQR|l贚HAaf @kK˜&) #Fo=)vkE1PY΋8ş(}k#\3 hD_Twd tPN_)Qr[_XrZ%;B÷oBÉ7Dse#Mx2H߉ۿ;ǻ]=*}\ocˡm_ /~ȿRt.8UWBi)"UL<<|/ ~ 6vM,`mBg4Zbuy'_xxUzasr{gR.:^cooami35 QU(~t҂</jm,+6tedMGkKHez_ RX2UWݹt\Cۻ( $ID& ~di~7(4^ׄ Q {+n '4DJlW.w€}8n5b\0@ s'R:ɨiɫcU>WD*}; u_US|Ƥ57ndEO)/Uo+_VFr{aonesIMˍhʯb3m:*>OF b9k[|>4j^ۓ_j{O!iK8^hGШ灅O- 7/B_6(\/EƿwgƢ߄CyTa' _7O)']ZqagH)yʗY-qc硲zc' k׾qή3^ױ[]Ng?oo?Yi6*ƿt+)>ahYycI涐8ND+3|LhH,&Q*2Pdɟ)DMJI&$ɞ$!ILB)1 £ߝƻrȸ1d*};=D\ ɏXIozG6}wVé8MOs؇y[[QBpƱ=*!J Gw /B#ݎ~Ϗf)8677Y]uAv Sw~?| K+Py.{̱4~(2Qq殲3cvR|INVy肓"EJaNomlv:ah:+(*Tt=׊JBe6y/M[ڪBi%D$Zi(2eEǼ⋺nTlY&H)˄8өlpmBß@;WCOն mr]~Y{i9="_^Tr^~eɒ|>d_JSr+KoҦ|ax5aH)аs0_bMn1 {@QQ~6.AWTyA~"ceIsϲE񸇫.EDS\g0eG\ۯٺur?ոÿDwblG?:GiN~9)&]ƶg~ 4HwN/#(0NBNqg5<o;~ ^Y&eU73QWCS,󃉳xU~w0ORS<s0*dI)%WpmKAOgeOBdw.&9iQh,y 򙱘e*[_?' /59WD(EiUu]?ݦXkjT+N7'~6|1o[SZY_>PVy(v&O^A)XpD>ẔfYa!ƍY4X{|ge@ŧ cGUV^#]_<'}xEfR)\gp\ؙdk2+jvv,kM 8:nrVḷ?0owfQX fᲂwC3mcm-A>_^'Ԋ4RV躯lyS{+g:i_MͿQhˊ/|PTlMC>@zKhl[ޚ4v\9{]gEչVhݍNz+/ 苼"JV^m.2ʎ鱐-/}Pc^pyi=:OeםUiTꀷzQ[̛ﭭ/9\yx5;~]WS/kxahVV lolv&>GTH}%qz(RS!t6ʽ\տէ:Ң.}C*LD֭[(;i5csYlMC6dP!%(r?!B} <ˬf<>量Yv^ xAe'RP}Z|__Vj4M(U$vf& ъs+,~%mQ2Oy÷~;lݛ7!b.MJ-^U3& Vyy pY+,8vdbG:]*[P*XF1 7}+o+[x h* !R/z %A^)۶]ZE|9Ivc?&676ӍPg^糳W5[')Jņ݁Licd#Jٜᕥ}{IJ )3Ip| 5B:T\7J!4'[ȰY[T%) z. _\8W5_xd+*Z|||s5/E%-$<򻁾ZM/W〲HzEOBY$u(*uJjFǐG-"aj (ָ&>Kdr@lj{rH v Њ$`:c(H"fq$H4a`x*=z di<;b}YfD*!trp8}¥>ӊcM\E i:yM~TFa*;[&F?^\#0-Km:fVtTn 7-'e?*>Z\bY5Br5x?(Y[T&ԪBLhzg̖PC=}WJan@>O"KL&lo#vp)eL"aIf;t<`4dr8`$~'`np0 C";azLf Bxan]ae"SyJA, B?gBNL!$vHpHwn:nwj?sPj$ID+2 ?0 k?wp%:!|f c?{^.EJ|:d8A+EEAnF~X$2Ro.tҳ^Gʍ[ % 4?xZFܜ$?=q}=!q~IiQ=JeӘ7c+͌06m[~=Tjx>qW(o:S_!6Od#5$GOPw!Z¢lVYCy;xJF"ST;F[jeq˺Ni`Wyڄnx鿮o- Wyd̼2х-}x U8lmnrK<:.J EFYWoZU$QJ;2q19<z ,H" =|? t"ٌ(W>^n/Dv1ZI(jHr U[ QϷ?"!~D 쓈r9G̐)1RD,//gd29IRˎ4/i),L`h"v{9yCݼ{?_~'/NტFW2%u*ĥi-S㪂bB6}tY.Użs!ؼ/֖`+^9BmSP@I=gJ2NS'D1Ey7o+vN{ܤQ7/YPe|Yݜ`@'M ER,eư~~7V+usZr1R0a,+(i.e*- n,Qj?c?Px()L&f3ww~ ;ܦ}lpς<ew&HfԲ[zl%Wti TR(+77dEj mQ%қ!VL (|B~R~H*'롨$0-|䛗U7EBdy\nYUeƼN _~?_:cՓ(?F_9vo+ul:1񥹵-^8/?&&ul(ȭ3ÛEĿ+ SŽ M+d6W#ezkT}Y{W<Pw^(׿Mڵ5H*^4CJ*0p2p7O=#TQaa6׮^Eu!pב{T|W][< dp< ,ieHJDіZi`~۵@L9fLSL8<mYȶÐ(Rql6|~I+N);ڷ~k94Y_+O~޽ %(gS<7JMam`5&EGe*J6WoOxwZ|v @;GR0yXk4\BYmm > ;%|WaulOk%c1Nxe/p~"',,~mO:RW-ŐK!;qqˋF;9}+ ^w M|x75b( Is3:_n&Z!%NUG 5NT*\h։8n(ߊqڰ㿮~w#T?V5<~(FE_l~'2UJ(djuX_F/_E)_DRmƥs6AbeEyWHo={"쨇>k1l1NN&&S) }Ot#: "hr@>0P$|:a7!X#KJbFYa=t|T)0(ZQ2Ͳ5QAOʰn !NwEXUt7 ҟA)/B_qRå#O[/44ۆJ5Cæo +F4-aX}7] P^M=Kk*mA.My(v6x;~}z Şu^u Wo&`-kL*-yE/+-%g2ZwyW!(T<"PۿVsNouT|rhīU9ۗߦ`6_D6xQ{e \!OXh7/҇rQfXB*UL9'^6^^ >:\s\րRUt?)w{|,|KOZ~DRVDԆ\Q!8HT~)RK+JA(QJepLmyG>5H},|Ao B>A>B :cIELͦDQQیE17nD& JN=:.ppD#:V_[@WFjLN2QEy6`欼ržyqWq1m,R`"⇀Y}#" 4(-gnUa|黭_Z{JW};?Ɠ|'(mV8 :|9T[}dE韻E_9)q/wsN.b})U̗_bxU05y[f gpRWw?1kPsKΏTi1xJc20' VY? g[Rk7n'_;42zc0 IrE,fg"}Y~znzvI ٳ‚ } m|u_Uj~m@-/mg)dHx'G_(ג"^_WE5×K16xSW'@JGped`8[,)U;AtE,6\N}yA)ڙ3$G^;7_+xdr*}ހGxV57 >o*|: ͷq@or\ EQ6{}NH72SHYBp8d0xm}ߧrs=*+k8Plu:g&,-jİAI rZאJIG*yQWwfC/6^t*FQIsqpp2^!t:eٌ}.\>yf346J+20 #e~jc?iS80?FcϾ`k&Yȍ7}|QE/eYŷb~% @Ʒ\y#4+j.~ɦ/PyW/ι1akN6H;KdX{o{.q(>,aU{1 7ſ7;1 s=}-vrAp/lUji?7PɈv9nisoX5x5A_k-٫oqAw o&Ⱦ}ueզ'~{7h͓5ܲMnU/?p__xyJyǸzxe\Zl־%b|^0f/CW_Ot5T⑐d~ 0Ԋ 7͈Nŋa ߾}z^&.ׯ_'IA72}|2 QJ1c"!w#FU:AB'DqL$oJ)KQ0¾6}vwwC0D-{%@ܺu۷oŋpBnߧKKKy La+,88]DRrpp.RJz'~m{[? /'7珣qq(M0|1&iPR#K_װ_z .p+4lR6o)6%:6rJ mP:xmo4#LĻ軴uO0r/9 Ԓ8J$!N ohc-Gq8x\bt'/ϭ wSaQzOpv'^~р~;^(&NͲ?JcECk᥉?nWe; B~;&}syNjt} k x=m|[BuasDaH3i2_>ChL6lok˗Y]]e{{(yNN6;wL&ܸq?>;`KKK&ǻ(&鑇~Y+I@[&L'CRK&Eg6"IzAJׯ_':Nx<ڵkvF,--XZZb4ee8s BwHF9Q0 #K0mzRm㎿b8qT|iOXWzZJvG%:27纤.Fǁo ΅lѱ(EߕJ< r2gƅ#YF(&d^ {Gs.Iq_}K 4>s)v7:+вirrk6L7 Qo[ ?&m] \_#MUy-D9j3 H#,Tֻ{5{8pM!N$ A?—yoWk_xȰ+4L߈i0!I$ˣ!^)^Ο_qG_vN8dDZ}Ʒ, si\>ik!e.~U Ҫ+oiG-vΫ3e fp q4|qeҋ HӋ^Hd®L&i$X޻%$sv}UWיwz3#>loLd$*WF^b[|; "4|bn'8~}}{x/#_D}Km=cd[W!C6. VJ~YKiMX>=dE׶XA>i!jsm䯾 'NRLN,ܣǙ^%rr!ܸ̋2Z.r2q/̑̇ol7,>ݙ,ydsMiK|Zo!G'U?`jFڍ IDATTbtt?eam,..1P^eee_zlKR,bBb <#jZH%YtDE=}n#kw]jNJa4MJbxw~zmeY听1MB@XR p)˲ 9Md8NS[SP_ w,QS٭ׂ$/d [$b{dj%&#Ah՟? _~wk-yg_? ?T*v%\Dob+9epՈ<#V?YLxq 'Kg FE'Uj/<~O~YN:a ^y+g/q{)_'O^)`O SFܮm[n8LNNazP xK@:NH-Z<qqzۆ,e XWORF;y p eY *H o߾L"}di{ّ}[5NJWe0' {n b{5˷V.6?U="}24w6d3::\fʪ̼D͍a-FsAi"7Ig9 O7EOzdQi>$'xvZ,۾uV{˒q[+W=!at/Ȋu^|MWy '4/xَzm*bUQx l ܼ+.ū{`~zK7h6;Ԛ-/ΩCs6-6d(9jyi6-^y"cXXs3כ8"c \uB稷|oɅ9>i_o0!'u爏Ə-CL7wv~L~Emu]jF#K)-L}ۓz^# ?X.*z\8CBJ8R0eY(^CAX$χ=0+ }~dЌ{U<$*oRTrdl j =I;iWex;ʭվS肱(G~Atdu$|3uhkn-|N>9>0QF O''"(T /eZylvOѬx%;vX|m?@AfM27SPqUlfϟ ##o ||B#?O?cӴWE=w7 z߼@Ƕ9}}yL]qmu4.^[45fc_-]}Og/^}g9ʡ)\ʋESU--&o|bo*zl[8ˣGp2'ԡta p+g٘[gބ_5|{&ϫnFqy;,PwOMw7yޖ(J0fC I &qu]lۦja&a ?CBcuupV۶{ R.@ą$1z1;xmIۓF!6OId|ciSWhև˃dh7?8Immz9ȫCj9Yikc>J^V~B|8?ܙ&#,|2i3|_=e'mmp8xBO B/`۩t>l`y+b뷻6k\[uNzr%۵iv:ea_L2*9ȏi/ͭ;+X5x:£x|ϾE>gavWx< &Ǹwx &Ǫz" Cy|ce}>"o]wUfg4t^{22y˟дLCcnrF? ]`:iGM]vz_}Μ='sl~2dAzz+gh8)zz|B!Q|9a;/ɴ¦x@''.3H\Zazʿx)%,0;E1oGb> ?VgB=z~h<87u FF{DA\Yl?H</?NgğdD6/ PU%qp#a@3Q 333! $913NP/aɺFFAp2:ZEQTTώ:&os"Q7y駙#oYI@w ~1Xv(t]vlex.Oxýg[R#+eyuD ":Ix켫Y^,N~9 M.e%(x9#$9ౣ Z4 r(|=dBᒐ~?;_?d̟,]tM껯0Q-c'Xv\lg=r杫|'yaguHO=|Xw_}0;cGR))!D5Mag175e,#'Q)P N 8@2Y\Y-O&/9GϦZ.ձe/i:8L|3?՗/]&gXE^q?? ?5=ɬ8G~~POcz >A#;D,+$"DE܃"xel5i|rvmu|>w8rɱ|@Ɖ ?}LJ?J^%pvMThl$߇cٟIM_l? ܟ[_+7>F7ht0 t⺾L2tmku6xUQǙ ט06RBUN=CyKnfߺ+.rhv9 OZ.3?A!g2oe^o^ v~rO;sgvVi XOUƋ%OSYXIҍ4[ŜŇ~fWM9r8 1S,XNM(BcA twgnrm`ƕH|j#`7+T# O_NyW)#x~A?,u:_14Zoy:]'MݩWj?2ǎah:?|-0=^ᩓG8{*/V4g?5];خÉL'=n-::]޺| >SNFQUw㝫7<1:Cs O8<}U;/sgm+78}xO}}JvG_`rmvPj~+~ y{B|.iY'ڏGڳ"m Z#-w!]Q"koy_)Cq"jxC6ǯw~S<(Q alZkt]T4ʅcd4ĩ ?և{eʏ~G)NP ǩ<'h1)& `GPZDt5: (XlRۑl4T mV:)rE53RT(Bc"6SKa4YYyĄE k%~ ?WK_ h ф2 I*a].#+iwlj5VsvM15fAT!0MTJAfy)ΆKuDDzTE`i-S8V%7& +RvJHZ]IW$,"23gHu߬,\x^>]e(?XNWn+G!eD dYq::ڤ)0ڒk?CML^)аxv)!|cgxe#/]l')A@,;(T~ZɓF.̧>ô7+pgoǟs`e>CYyq2u9r)%Džk`&GfgxY^chb±]$#u\ܲN9|ܖ+}G>/~_̌#2}KLeoF %A~^|5I߀zѡ^t^w@{)|RXϖ/%ħh4x~˿m)jr"k.u$3R=4y]fhY̷oyxGFə9ӌVTfxdb|qSI֩SOs ǣRP(i:~Wz & "(q)A\vMݦj%vIAX cRiiv+Q5OLtmfA(*B8Rn8tZM8=x JQˋ 4<PRwm 'SJX2{h㸊wu\+Mn/aM(Me|d9V(Fl蜴M5Ão{4y5>觻Ja:ێ~蟽пC~"zqcPg]^si++Et@؆/71bkJ^73Tze"(GW~7]=< k^:ML+Oms2}fxc}nbf|U(|-8۸Ϝӵ9}h?+u:]g؁YtMctӧRXZ]ϣgDO rHeb S|Gz۾.J'O#o[߆K^=޲0)r2B|j>ɩx6rZy2V5?M|C3%/I㧏mZ+ٶ=kdyyr̿ƣMyoIAxewG}Afⅸ;ߑJ`zv;gϟ7Y__%o,!mљMzc ~܌fã3G(G7t!T-rfm4McllŃ "oQ|^Qq"UĤu=Gt-z,8IAߥ+ Ce@04&P4zrkRJXfK ys3e/XFɜD vh6t)69ǘ"=&L9ţUo02V`l1Vs$Db kю]Nj~gNOm᳖SngG)pờ J`r杵DqO7͖*nQv_Ne$+Rpl2q}/Lm-TxEL0fDr WK:P򚂟0>}wc>H7,zɷGtx n~fo',NJIkc;3 t]cu:y-8y-k(7̤cB>grpfn9~`e2^-1=1}ch=(TE8ypTe{Xd'MO"^! KJɵWrJETUJFu/Ǿ}xu<\3֥ 2e_I1o$,X6*'yԃIVtݾ5Ɏ;w: ~?Ui:?~o@1#ć}UDIf,P45:8s GOR*r BAYDyZĒ NEi|ֶ322xbw`cH*H:]VC]lp4mo3Rh_&ht,A3oRBrLjgaR4MEU4]Eczǣvh؊Gi]plm\ۡ#AFV^Gu:NE<ףx!ׄbzOضٕCet.Y {w#؏ ;s{7 {Ёg(?3~|F8$ͧ_o578iq#S^ `DCYOCb)NV@k$ԇc2GKEdXa鼭gO`LĎJ<'1;5NsT(/VOxe,|s+|"C4N|'^s }&{BdlEĥǤ{SwX,222|>O.4̐u'Ic(BPm4U ݎ:64Zwnhv\ZsE`4:xdaXICEaS(h(DHl!J4Cav~ו#)zu鴺h z6ݖCҘ-tJJk,/7贺xFuY:B(誊eTj xUS1Mw/_7 xxDKA1LB4ҟ`o(;l?o/Go/п}B̐~f??' [)B#KG~ }buXo\3I4Nan7-J1sI|:n{۽g n߿`sv+iIu\ز1a]~RO4Y?>o%~P  ! Me#h;\ȓ?9{lG19jbF5/̲o_h7MV{&%9Nz oŀ+r\bяnGN}T}fY,Dewoy#U1}K9svRsg7Kۿ{ٓ f/aXƖ O|Og[3?|E&']bżEu]ʅ<6T()Z_ ! 9׋c E]vĔ v hBKH\axo_fvvB`bq"'&&)D/půG(Le;y7qV@ёQWzdGzK|YD` p~֭_~{^#Njۭ?%0p/O8җS[)]1Hdme-65Oŧ';§Q+Fcz*fg~A$+~*Zo3hz8~,!:YyYNh7@SUv-7 /q/]L>4D57a|/F-?BI=OFԱ۫">EXe)}`B?yYſgmET|1M˲z( Fuuuvn~Næ/"/_b6of^oO~PX\\d}}="S%"'%" ,zp%3Ri Sel̈-nh463 FJ&ŢB`qp6+!(XBޑ,7X֠v7<L׮S_k3?cv4 #$**rJ&|@3T\,}v˝kJ&f)ǥu, @a4 IDATctl8*yUBҍFF,ffFTZ6(,ryE)蚊;Yd~aTr/v6)-?ݬش63IC3_~A;DݾAǦc|LJ o?15$ %Iύ`B H/9JwO~H" PyLk޽dH8hOoEZM?pIȎR]`#U'c[DW'xcVd*'vg&y3r9rgp$D0tM J2`RMߑ'!xGgϞ ='/Ȋ,"!Uav;OYDA$E:/s"kGІU0Uv7hios >UUe||܏R.-_0=HA?DvҹқFK$>s_=˿o/:o g|sY / tdl`S)%Ǐgll]7P !TUе=m8؎OZgKz!@冺xOxx@(.PP{~ QKyҐ#R#Ʋl(iFnߦZPa`9ZCfāV{;} )^uSU$gn0lN]X6R(=׳9{q28I 4u[-V`&q#At]H!Q6fk jƄFc)+}ae84AJťZbk=$jaeeQPT )H t6+>1hk D)+e2ڰ "YWA63Č#$Xb5<^_6YQYrR+8|x;&eC9Q9%tǶkhK W7{5ONh/{g{Vwܵ: X$1GuO 4/>@4|w7R~*"/FsE)yp]wLܬިuNt̯G=hp/<Ä3㇓'vZFH1Qi:8J!Vû $] Z}z E%ZM\\,._Vhk<qȵ&UQ$ajelۚFcA@hq {Ja._w=&*,!qW/?F&wE!'l,ǿMo7Øp:1 Rd8&Oi'ӣOpR]hEp6طFcb* m%)ݨN{0L-ײdąJeG0D Z-w  ¶1[ıɍuaHDQJ֟$JZ,I5`Ԁ(!u-ɩK vDn' J4_\feѧ`. mPJ5:Dc`0ήUP*#,337Iv#v4[8 !%R^FjhvBQmTJ6PԫCaD\F*G MF`XY,VX9 :++ωMB y2뇉 f7GOO^>#Y8柌t G3홓lc:H(Rܘ̅xvEB#_wW?$iRa9_35ItD gYK||bLoN|mY{LFN TE_wy9X>-ݷE˿ 9޻:.rνl5 ąqP#Pp^44Y15dpIWq֭1)'Ð iińqa*% "S,!IҘoml|*XOu}*穗rt™%ʎ 2ӈG!UAVSZ(b,\mcZ7hQ" c\iSVA͛ Ô84 N2 !adP[( -vF 0v'8}sk\0A̓Gɍb&4d677RR(J3ꤠ=#njڿ;sx^ʢcKw_B#2O{?jU2(J !4BlQ#IO02[2*'5# L9y b4? 4J@RGΈ|u A۰G8A6ze(y6U!**<,O-rF)X0QFضj߳|tɃMj>gbKUFͦ*AH9 RJeR8%$)}L RHC~vH#-IZSEpЏ"#R,Kr h 10a( D &=t74.cbHU*ugQM\BӐl4#o,$F&FDbo$լmTy5lbr~jFQ+S;OgO7^<#x~.?5&5ɣbOE0^Nh}T)T<2|5(B#ǯ-zc1k]Po?կߟ{}:Beg PGTqx؄`75g9XWGOV8=`eU"^;g{3`vPʏģG'&O.??u\")rnly|pm}z}L:$IzH6#l i>oh'W۷ZBvFPL"L3SNV3 ]ii50mBe{HBV)Jccۻ{|c dqiZ HMNl,~_*TK ja8sx*?-Ƒ}`=AG:l4 B~*Ld|#Nh0H0igOQR:^3=3D=wOhbҤ* !0m%)1-* ΝZ"OQSض21u9ymӈ)wf4*~t)vR4G)&/?oGyrYHQؤV9՜L( k(  i`[6㎈ {IaJwt:DAbS6R&IL^$|pG XFu.^|Ryi 0pAgO$#SDm AH3$(! b(eDz}Μ[PBJRZɢTu(Wl*%1"#6,VHi0 TŨ4!$贇DQBĠ!(A? Rb!RCEِ\ ҏb!X\p<׵؎B$qJ0F0\ZZD)N lu1*U%%ۻ=vALQthI&(qkKUSbZ뱜4vت'ۯ`eΗfxs=?^?w?MoX11=.ۍNχݴT+}83}g_$~)2/䱶Ti@bϜω -6_~7VqAӍc/DOI$aqŽ|p9lw>t5OU4tBrjy!DaVa&n.aJ}X4~r'W_8$-Ӳ8njzؖPE蟢x>_s'Y"_& ERDqLǸCjelb"$QQԫe^xsRfmjJ?2* +eU6%l;ۙ<2wIVB0Nq, ױ-s*zm[yKix qr7{jy,B FL=wPv}1> haďuz\+\ 2Bd.i5EaQJޭ+|>~3:ir5zƝ{vKݹ|Y/>ֹ~>;&mbG'i|˶w.67/2zLҢVE>c&%QS"UfWoPvC ڡ0u mՒC1.,S50-4vǔRt! aШ3i^#3Ӳp $ie~*"1#$l{XiZZ-#|Ϝ A )Ij!B!R&$¶$Ibj*vpZ%T2@'T)f}ǡZC)I IR9I0dV8dQV)iS:hL015-~J#4o,_FV+g_cY15OcSb\cO??5 !F@:}s Pq3°$iҐzS^^cVII҈NIp 41 #rzq^T&PhTze$Z" mKNe8ff*i6edZ~(l|ڊ4Mv{J0!bg pLTjqO0XRç%M5:|nG}X 4%咃4$RBM3_)p$~wrTy2xMᚧ_/瓏=o{zlDC&{ʄZi.(?M9~1l,;;..030i[U5!d~'6X/quƒ-|=4Ƴ]Z;]^8y6(\Uۙk?c^-2tV3+(W߲,Ksq+WL/LG1 c\n-żIpjcfeQl,0wQjӲA4Lhm#̋b&J%aaUp [  PWi=nr~_a^'M>ab$}gn^8\iI4k*5W֩QP*= /c9+4r y]QZ>2#yG.I;J8=ΦK>KΔvFHxW^o]/{}> }Wh4 Hs 8ܽso} }4n{ҋ.QKO"ϱ)Y(jI:mJB')($JS\[_8 |װLKilb}[$R!^r2] C#H$׳-Wq i(aҨW1L$QS(Vh-CB1#!ALsvzãZwi'ӌѠ,LI,+>YYYY!-I!R|΢,BbTC$čހ{,x M0ךk$AM#"(&E\~. 07m-z9 >`d)5e5,-&6o&0e{oAkcKvd!NSJFQ1x2~0k|ƟCGvgi{iM:VŞ<?nSEl7~׾B /ubW9fؽ݄ x2!s> irhRL:|R i筏g2a\v6{q-wѡ3@q!&8ɕ7cs$U6VX_\ceJačzxW}N,uy8Iկ6=> /Xbeao]_?C/s!~DĔB}6=O/b>BƏY~0|_mya|B#oDQ4=OӄDHBz;:ޗm؎bcLNL( I7s&% [wMm꧸`]ynwlP(\soOX$3Dȟ[ rfb]/d|?[[Uh3Yēť/v++H),kN]WisY'Ke>KgI?x} |(ɛ|7@u.ebLl='?Qf?Z;RVY,Iԙ۝7G70B {h7|=Zb0?q6%ZC4[Mn߹Ʒ/i@;.afayȝ]6V1M4II^Ͱ'8%7D۷o nP_Up]SKe JIc6aJ)8L)qqLHqNܾ~@!l!R;&v0%2cbȔ{)8qRAܯϸ&pqhvZ8Vx& t1݃!tiw#B];+e}L۠ڂz_vY\.c0R42ghH4k7v8UM(0%cA\m{J 0Hixs> BFjfٱGZ#z42&f3wqGP?~ǎ/㈇ɼ&_~>tZd>4l!FV#\rb6*l7sQ$6d8K1Il̾3:XO:-8c+jO !F4VIRh1jܹjj|>h4>amb$^"w4ԋX12a0 <Ǚ,`Y&jV4F׶d~6@ac|>2 SF\dc2]soyǭ +qUN&'W7扂FF{/^zk\>xaA3=f'GR%@HҐ{<ܺCm@\fei}p|`w_"IAHka/VQ׈CAHĄƌ#! LpZ`6jR68 Kx%j֊nCCg7O˔>Jk0f{^~'a BfόJŦ*Im> ,eJ bicI"aPQFkŽ͐8јZvmt:-(i8XA#xqj٥^5qsq] l^^QZg;'(-) CNk@m 9D)57 H<ǢQu IʕCJ6T>i,V}dsFD/$I#eI&Jm |!l؀D_x瓄l, g/'iο2#?8 =7x٘^\$3uL~ݣ44rbPHlؘ̦٢;6V1I51XޓwguEhg~>}ZiDdVKfܨ *_8ʝkTKUTB67׸r*[Ο80r~,aru.`g^ĵ]$ڽ\7j*i὏y,\Q0\8y+';Wǻ7?_7X."ڽ6N;e#ip0 U0y$kvEVYԀv۸g.4汬eMpǏ㓎?x$~šV~J8ecmp %o~`ЧR…C<# )i+4iVʬZ)p@ĸ)% ʾm,/-Rd;fJ),˚А 5zJB$IB*Ø~?~puj*4 Sضy Ko^_Gզ?#*>K43 &bzsc׿o_bf{ܤFqc~vn皔6~!Vuh4<U4%ܬZgDeJ J Ibۖ5AFݡ ÄJɦ[}::!A0 XUIҔA"j6QRxm"M߷T'a i ;C^ lvlt9ie?Zx6^1b2&hHR0hz5Ekg? ?? _8'??ut> ?(t:E+ aϽ@ i9Q8Chk &'kwr&󟯿1\ɒ 6楼y|[|*/[| !皗d_#G*jd.٠wAWνrm)lumZ;L@%$I1A0ĬTiBm{Zqu{-b&r-Bzmt Dqo%C׸kmڼ `@qF! zDQ_O4* ^>]‰3J8V۰LZ*rI;.asm _YڃA0 9qNoK_syq"UbiL򙿈9z2x"IS_=sHVPggBZ.]E _x5:9-+?IZh xaUNOʝтˑ>HPL~G~e:Zr<3(&2̼[w`(B\O #L#uRfD$(c0Gc4 dyrʚi"'!Lq+UΞhUlE`I"3)/\87֐:[ϣ&c(k$RNrd?B ",¢SkWVanNߢ7P 7Y_)W/EAHK?K)qј >.]RKP=<lju~AYZYPDiPx܈p;7&b4)M4R.D%1ѰIj.  ba&mæ0B*Ahb-y|Pf0`I)tյ Ej;a7C&E%vF±lʾ >Ygf )2Ց8%UjMDAV0Cؙϊ۷[YY!MH˜0fTJe20- sl +' L<Ʋ3 x:Uqm(Nt :!9ŋT;; l1*agsb"g781|f?GӅ&+@~~)%O ݘyiBX^vLg>~Qa3[~H!]hƓf:yҸyL7gWfg ?m #U)3Pno]nmw=.lE3bko~^itY,I C 9vPX,/`o_;(C"Jc;3eL?_敳/Ͼ/0dH=h l7wY9.9ɵ98wbXE?\_ûO+M4 ӫX[Xsg_!u%/r%JnzFצY4x9tT+Vˬ-6zusnиmt?n6|\<x?e{nt'U]t{ř>Ir 0Q{#+D!GBz=vsiifVH!Ð]wvHEV#JRhClF&IPHE)$"%ڔ}_K+Ke8z*Ah0A6a{%5R'xnC(in{pN2 H a#0$A`ЙPq(GaLs{e\v,+4j.ipX $K>q\aAg>5-$ ސ8 E*:$Ih,TvlowR!4[qB HlS2LT|`:dzht zo!DFX(HFçV4 c8%Ia}k ~}:b~CT6 A6m8&E5r 2X\gdو\*HCO'OF2(1yRzG<ljy_\zx5/{4G q[È;O?\`^a(GORk 7ac_N7wbܘo2m{jIw8MDZ=Juopg>pbin' no~]~FCmc7{7yK^K%l0m[iVs۴ΕS+Wq-‰ؖo}w orϟRyL >7쳹vqpA{}4% )e>}Ke.<ϝ{45Vx/Bկ`[.Zk6WN./%[\Z.ePidBo4SA.kss&+Od#T?YO?*֙ UzشP gH|4b `aPu6h9L4L\םp9"uB" ÐCVb^2lwvp֖1](j d.A!;{ )CZm%Nڤyj8!,,eIX@;ֈ˨`.c!)gaY& QW\s=*ZcFR6I4޽[ l%Q镉EQHTGȔaI>*0"<|pnSΝc v;\u0M$QL$r m0` }b4nS a]*eZex5d;6K ԗ9*l; ;Z" 0RDj@ i5>-TOH`aeZ;Dtz!i`ﰶ*]ϑ|{4,Hé (N( C2GVLׯ# a&"dډc|SvHSmJ$N ju^BEZaq'H4mfQbLF@H1&PiV$M}qp4C(%ZPZ4kϥ XsވmZO~1b ??^5xw:|.wO*Syˋ 31EG1Gъ~bzTyilr22*X|Lk + m͚ؠ\TmM'?qM7{^?[1Z, \gu%'5a4Y/> ~9ւ=~x]^=2~wn9\ٗhq@-xDqP8wva6i`x+/so(1ZXiPQLuZJ((i v0 8tc1 IDAT;lv2Ywyq_|K?œ$I/]_yKXl?rr^il&cxEUpa[l_w\":&>N[1~$gT#ǟgs5( REr%t&B 4`f@ eѨa&` ۶ɝ[f&Ƙ,Z&m G*"thxA:l?op(/`0d{MF<X?A3B)v(\Μ:IEJ$BlN %M3-&d[o,R$,DaTv3ogGa 1p]6qkj'CkM&"| Ґc<)ެٲe|PsU0E"p (ꁢ)rȎpXR8B~уЛaQIJV$A2e,ƌF[U{泧>p:Ϲ?Wܹ3Zr-L?'7^,ڣw@R[1TU\!cr w F +Ǟ#uP)Ό5C]:ubX s]:ɒ"?6 ƠE!IQ%T\xjLQ $:)a~Ck[Uv;[Q4s|㟡rp;"P9#e 42Rp  y0tBaQU%iL3 8[9~Jʑ*] (E.u}#t0}OA}J^=]]Bu/ǧ"뇱%HFZC n/OHw+ YĵXnkSE KjӣT[&m7e_'1_}z_F9,:.[^'_(apjZ1ȏ&˺2ɩVro籈\j].Y(BF-A9X?X$l?0h9 ^gQ 5I1 #!?i }HRqa .ejX+|Jkl(mWmdW+.AZe(xpwTf$p\z93y 6}NtNڸ~έ_/Q3ƒkM't|!R {~i2C)7_GIVc6(J@H|~m&KHS_nbŊe8i \T\JƦ CzIJB Ja s<jIy6h,$Gk$QQ.yTJ_*y#9HZJڥ ;gI8G8S/=L(QF/HsK`(1 <4ۅT)TBɰzС^ VkDwiKrb˗k,C$+XX8a {)r䐤vLirm )ISyQ_}NZɣ=fÃ>~LQƚq,aF ?tU>qS>MS58K19Pr]A(қ27ɯ'}NgϿ' ~,'^ǵ߮#w+$oTzc34{m6?b1M?acnk-X5x{?7ohX R(0~FJ_g:8𙟧3٪61(BިOT;or=u]B7 ,wOT%|cX,W/bBm繫O3Gt>' \m-? c4O_~nfI\?q*kAIrg?J8b'_Ha֭/>gq__|dW[u77=#^"ǟY#tB{'?^\1ZFyF&ךjBT.vc${eѳ/:|:<ا!*#j8!Nvw<~ORr#,%x/7o Je\g6=8(~\P %rgRP<\G!+ҲfYIL|!}9PJN:d^Nz[T&6^'ea)FCQAo~ .ׯ\! G+~xЄǺ Dl)\P$ aV)$Q96(!jp9.rw[{8Jeޡ7]}8O8wȵkO%:sm21_q٪6FII\bn>ENq$ K5 {ŵݫ\پ .o_.ҵ" jT?|rwhηjX`:Ɲ:|QZ_by3OQansIv)h7FG V3rvvd0@DaFFk$cWՈ"B*q3&Ik)Y ?T oldB ػ/i޾uvrDVő[o \|p/y#9CȬ@"%^V̓?0E9.'8s:sZ]/ofN%K2:MX AkC5ښbT)B,y!ErGU:..AI4=Ut3JbG<ЁJR]#8&J8[H(p/R $:OHRA.F)yޝ=Z16B(%͈VB5dpJARi6#asMVD(\ н!9H)vJ^B$&M2!P(UBpxgwLTV j>W^n)f._ TJ7qE>6X,/b= Rmn! r8/;2ggLQ0^4#Ѥ^Q "! c3{S&l# r-)*?Ə$21pL MO^/?]1h,7brq S&C>_Zl|SX&6n^N6&]W:t6Rٸ;1uoҼd),.BscOv\Ԫ9;q/-_|Am]z>z^@0…x ;<}I^!6|%JAD9,7#'g݋q^,fZ;{Pp1 䭷=+q߱9cxΏ1y9#b ~b|T?r9Ycy;۔^s/B C؈#g/rrzuJ#Ə4ձBIEzCn nDgt9ov`kj4f= DE4l(vA>z=,T*E|+_?3 /ȟW}[;S?`UP2p ` |`Ϗ9ҠEH9N\R-ïOT?i{kmDz'ZCCBdE| =Nɪm`!Vϝ67nHfM{M?puQcnƒ#/~6QVvʸя/X&<&x`/,@N`s=r{.k5_&>*R>}IF)ȗˆO \E\$KhVD~H|tW+"㡭@X0<+q$g3{{<r=Vn;Ә8KɴEXIxdznhI0f|LaK +(2;1 [ ܻaOȵ%іQ:,PP ]\!U.E f \܎KR.{8\r~‡>t ws349B㌟ z V\*E8T>!>WTpQT!('*|DyL5vJ.zO6: /(g5ZK@@j"0^7iXc#X#ȴE٘G6 ǡ.V #v0(\<4/62R}n'?1b9v#d9ı#@$f\TaBnf-Cs }Iٗ@9pB(,dycؾH|TYh RX|DQ+9\{s:R6P}G8s#:LL`B5vyeb6gˁv%m ?rS ,||쳿X&V_ڮuw.D.p!Ww f/̝ٮXky^M4Uxʳ_aN%:_JE)օ񎲥ZR++X𜘎)k')k75}UsM<_OG MG0uHֹ#ǿfQ,4N}J)< 4# ɐwޠRߢZI<ɵa.kMeB,1cT$q=8$IpV*qFB~^w~#tts:szċQ[R"Exk'xКz.dc뽵E8N#"eFjk$W9JRכR4O՛Hckl1t(KAL?dݧI,*a n;h Ry"C8$~E`pB j/˸ X<#˝ 5УVm}ACzxd&Mrn;yQLtG;~B;iYjt=5i2p;ΫoIn%Q`,)E=ˁ6ǚI<m VXFphH'G8j-}t0Α2C*E9>[sEqTَZ5YRQ[0,0aH"{1:~N2J4h}\,i0y45R %•h)x򉀝QB?6F9XK+|4y^ 6meˇX2щaAAIh4B#ڐ|I?8ƒ%qyr'pQɣZXz %b⨉@ .xE0UץR wD'1-&[ uQXuѳk{~ވ4Q@43_ɑ)Iv୅zesE> }}EbZ_603h~ /o]-8QF4eA[r?~(|3oF:+$G_mf.#`x?k?fxJwxm+t~4=O 1{܅1חda<.Uj"&,>YkIs{WA(/^G9 g9?>۵w+?xso\qFS{Ez֏u3{\ʈg!ӺK+tZqwng1FX!0EfyDZ &+RyJ txGT"x`8D`I4"$3d80a H}0L^d`G܊pJPHUܟ1fAR!}HUJRut -B/t"r(9X";5N?54"aش׉s8`M6)iwbR(&,RZ6ԪJ ,eB"K!H%!vk5BzETm(\QC8ৎS()e025Wo4tCSn/͌!,Z:IgMxfϊFydqO?u#Y#r=G).[uXo+B! &\EFgZ`?6 _oȟ;Snmrڸ7-\gWQ8ïog]_3qva<N,Ćs:szA 1l^7αFOx̻X/{Ql>+xCQݰ&˄|= _b~#(0WZ!xn7ӗy.ȧ3\cAk3mqR&w Ɛe9ވ(p1ة M BalY!cǠhc^XILBE +R]CH%Y$#}P.)P ,y^J,bnT !qN!]\+ !~P +aĠs:dT3U"IHD9AB4wns,G~9c's2~Yp+M~_?mŸύtNWa 1(v؂W@5B4E,Ml,Ͽe;Nizihq|&>Ւ~wȥFq/ &Vvw{]~*xu(.O]7oEkv \{|os}m,(9]^yOOtd& ? Ǚ񡣙LxZB9  )u ,̰w<aJG.UGF)4*>/W)Ek3Ѵe4nn#lrӨԷwT O?TXd'80w`ZDe=ZeϻU񻰌7g?91~^~v]hNy^hZdV#b&,չn/{K | }ηucC}ڕw:O}*vz! ?]7(xgi+Ig迵xLf/>govX__62c>=Ga؋bl0T;hg@y_\/;<=8@S 1[e<7|]{o;QF]79yJj㻷smNBy?WP/qm*W^?ŗ:[2wߺGOp+D=coNR: O;! 08 Z*e2#&' 2:.F"#TEU'*ETe0,cpH^ǭoc&4%ϊVk y*n1 e^R.KT |4ˊZc臘)+! dkɳ.Z \eÃ!rHWg883b,R9rM=?QV#QVTK.wn$. A(W! CFH T2Cx H1rt'Ǩ@)Q4VM}/G3-v,bSI<+HO9l=-~vmyls{y"xf8X4ٯ){NtNu'FEvM;,p?V %Ytuo`>r&{! _e)7M}g^5ʡ7޸o\K[åfZ9]}i^VZM{w^~>~P|1x쏿E5q8J<+=s3EtJu7Mca@-W@R) G}z G9ĐjA?$FR5I 4U-<$0"KDQTa-~<ɕkWj8íޤg)k!4y 9Q~@T|@ 2(Htu11$rZ 8$&38 a?e epaB=^G9zS.TKW$ *4]S\ |BP*{T!BHSʰX~f,BP(7}]0N5W瀫6!qRT~'?tg_^n<~:j+43h1QXgP~&E&<1BԇaR\}y:0rqj_3hLBh 16f\-XpCB,✯{58[//;M#oψsFںlŸp{Ou3&~QqN ̋ [dfaf*de87{}t|NC|]9PB2Sm)Z) ך+o7bJ)x owW_?lWKF(x.GFwg.ҍw^:~έ=> $t'6"@<',~%RIIa F<qR %p dyF#IGw)UCʹo:Oq3NZ_B(S.U/@(I),Q+x Q_dIStEpOĂWhpFg,Bd FwȌ%`O% ݉*(!1Z3G>ȱWrl8K3MP1*%E5dؾ[h{V|c+G矹:3 LTa e')m9bYy\38Ư_ڮ_5ƉY?_Ņ _L 1}UjgcKe33oψ_;bq@aқ΂ۿ++9ӻON Vq#1 9M?:a㲠fZV 9qM}iaǟ}m;"NtG1??kwZH!qUۮ%SJ8Xk)>?Ӵ{1_M~x;qeVV\Ioݤ{'_k? Vx|kGmߦ%.)Cn0'14?i #Bf9Ҁ',N+|?0:=Sٓe}lw޳c FHBLY6`e8,~p8dPp Q~B2C&%۲Il$f^k5yι޺]= s\~o)$1 HB8t;m¨MD(#hi|IJ IDAT_WJ,DyV'43ɒ8IӜH!-~'4s$Qd6!J!(Gaue2v ? t:].nnKeeBקQRbLTNEksADM tudO8RZ+Tn 9@- Cdi5'SnO/^h*߀H)@7tm ?ܽwE7Ɵ/Ϟ-\^n43 ܾ.^p8, ǘ/i= XMf avOx#M{٤iMol :θUWe_ukD:&js`vOel H?wlFx?HgKHcmH,`a~3݅]x1#'(>V)|&g)9ܤg>;5o|/~tcфn҉s$i }ܕ5}[~g˫na(˓O.}06^JXz8IF_HqswoJŕ>ǩZ.' xo :TP20.GJJlcS’琥(c<B&5eQJF! n kkt{=GN=VVYYYn{ݟ,/("AFZHsp~iu0 {{x$yh:\ 2L?)Qm&$'/,VV'`9t.Ed܂W:QF0t[MT:Xk) SZۊ1KTյ0Tē)QdO3ԊA?AZCdYF(L{b IJ/&HiQ IcNmS$ү~ժ1^<?=5nީwHYN9~{ʹL[[x`0 +;n~(,l N6'du%;󱉷! ou@D8x',X9~34 ӟIV̓>[O8r?[WFG?jg,ʊŽ` ]QYߞYo5 IK/?|6tO%%cOhK׷')6C&IFa {GS>/>Kkq=nn <~t.O]\\᏿2_櫟yQqq%Is~qck_!B@OpeOty'*yL;Ң=K=[B=m~pp RJFƴ<TZL&1INoe/l!B(z;lv"n |M+j!`| 0!Q蔮^_Ea! dMj?UB4k#}8Oxb5AÚdx\˞?-ޞSWD[æ_3̉xfRο9uF4[InãOB_ǎw]:Ǚ&-O0p+\vvG3+?7.Dp?/1], 0?4 Y$C&1~*' !mqn=sC?7`Ў?g?&rI :(!R> H c,/<~SLӌV?P$;o0?Xkֺk)$EIJ(a9:%2(yi +(%i# @kRM=q c)aSM$8ȍs*$i)Q; | ic0=JȓÄ4/G)q#_ GgeŰS BIn)HZ+IMI\9<geBg?x(PonlWy3׸0?bu'XH~; %IiZo}-{-~o'N3ͽvU. <}y.s_cM( |@HӜ#s-6|:VY9`4>@".=4?ZQFcOi)iH( ;mvɒ)Z ϝg2b:Mhu}F,{w - >' g!#&no @mpj;#' x2DIZINPaшQ+ є`E=T?ZQCYZ:'Cg1sDw)Id{rgkBuC<{ܺq .uB:umѽ-qHg青_w/[T䄨oxZFGzBwePi.^Ry4weȚ*eY_^ʏp]62sFYjx$98؝+8ak7% ^mqjgCHnv+V*.]FWuDMXkiZS$&+egyO G)Gq4Έ8@+=dݖ@(/~6sҟҸ뺣|[rGTi%?I N£VEx\)/T ppZ<K*Q:+itB&ٱ{Й;b=Vw\iJw< %?|}=Æ? GNLq}l|6/I ״0.,f9ßx B.SZ)?;wc$4/00ȋ)=MaM#i>t爒N=@E4Ɏ7=}J|V)`EQV^%I3<'y-R$>66L -xZ{rvxEq)Ak q;Q{%̸~]յfqMs&>sņED xD-߷KKҷL#{11p?0Pus;xX ["q-,şV"ߛZovWH;/:}oY8 w~S~Qloﰳ{ȭ} 5k<zi"+ -<t;mIc"'l hZdi?,XXw,tLV iNL+GSD8<2%$iV(7)@yvmuq˽ [7ȓ]] ~k$s$GMtx]߯x-*/;Vb;õׯyAõ;[=ŕWwx<ⳟ? ?1a1Lvml:(Ri ZϪ4ݧ0g}ٿh x`K `^*r ן:ճs.Mi3x'J!F Ny,c2ӌ<ψGGLGnhJIܼ09K'E&|Z6 XuI㘖i]zz=z.Hv=R0J;S<;3'_?pA0R< nC"`Ag$iҎ$1ƒdI! "Ո_ބաDVhxJL.x 5YN}ʉS;ȝqs FOa-i=AQ mAnUSLitTʳCqhrk㐰}||TfMW8PGLxeRj֒y3}&%Yfmsb?YT̛͗=&GkR`aHS7MS$!2$q>xi-wvG5X`ҿw%>#J!ٹ=qWsQ|?sN|G[_yhfGڂC\'1<\ R3ɍA2]g Ϲx4Or>5{WvI],og1Aޏqßח+Xly}Aku6RJT)پ[i1յu|qhDyO4<FyL, /~dy,`` Ha ?taah4&IrFㄭkAX$FEIL63|O͝Pc,ynߛ %h`D>u"nD؎eyNZ:!{ BiZ>Y,⥰9g] @XRJ*b2Ir0 ҊVIerrx)RXpUXº$IAJm$ecwB8J=h$6+xb8k_!&k-7n s[6W==[%Zׅa:QZXn3)g/kSBi6@-br2>Ҿ#$K/DdYFe51i-Wf?g2=Z_5w,}I,O;~iᤉJ_g_ GMo_'c>٢ٸ۟Z#wVke}\mL64qyW^Xo4IOƵ)eY8m? ^pV38Y $)6,8/{K% B`OR^Idz'ǽ_H߼~5?/KnŢ9ySAPK)d0/ْyKI >*C.JstN,>9Fu3|O[7fRȆ}r-K9#uom=tm(rl#3IYQ,*>s6$/3 ?,1 PB#U>RX!uս tGV)2X=ƒ>^wWfrl\voHn")v(LZ$JOG*!v?z%vv(("'9fdʅu.]Jo<}V>n,M$=::b &'C*ELGGdƒ!xpʰG' r&h"`2ɓ$8܏} X?FϹ6y>w~w}Rl9$M2P+IitБza |M QDC+Z"r]YX3Nr2k10dNKK.A.șGxREEf>'ﲾ\ѝGQ_-Yky^G!$]VEQԤDuWD*ܼyٓJv?"c1TהR /yxҠMF%9`,qwKmew F!St Yx~>2Z%,U1Y:5 Ǟ|[7^(\YpUPU375VK_OQufq^u7Ҳfou=+d• y:=_:a綼[ )o2~xX<?56wuWebLN^VHUatAv 2"6"cPPrb>½yjZ}ڭkm~#(PRSX8꓏ £yt:0Y?wxDH À RK4%BqR`~:iLc!xBH6x QM6)OiaBigmx0:FdKl=ԒYBhWO:?T_c5ZpN<[ D VA;v%YQ$9b='#%Gc[-OTJCLF Q4q3pڿ+asܺ`UQMUَm}T1{pm,$Mh6ƌeƇ O?4BT?\بQ -## >^ZkZ_|硕.xW =$nvnun^eg<$D',/W'_zwgcxg^˯|IU2C*vo\3meiB^<'P'#N  2£(%27 Nu+3C=/Q;)xZu,{1컄gipџ|?awsGPz9r"OHK_ո߬ŰL]v ?ÿr;GiB7H cThCP̺B{%Ѕ 3$h:pCl@ rY-U٥= CN+< )k-U/>XCE|y湌"g$e<0\]!"#x> }p-vvv"x Cdr8k3?:t{w))kyv.! k򤳲k}0sJi@!@*I:\-` S;S=$I$#1x?PZ5b2Nr(elaIsCn,4i\jqt0%N2=n'׍XX_|JўBGAKL,-ΡB2o؋ z*ά8ޯVׯ_/}w.Sf$aw_Z9A5墬~$h9#7>-Y_[W"s{j幊ܖ܃hZk&'1߭XƄ-^'ozLm9݇l3D`P?|x[t57 ??2&%-H+=䂥#*c[<^3%1QdPZRm -r+bak(ǜӅ姇/Ri1dixtxs=>U+m$p{a&8,ܠ X!Ov8 ڬt5$>$\<H% |IV,R 4͜0 IrnE RR8KTxI>ekvsssyn X$M FpLP,{ff *lί9vM "L-2huuj\Z.*X q4 ??$~c-B6<@nۅCxՄvR5!BA]d؛~.2h#V#C3tKE5S!2/jY "?_=ha-Ldgw4wO>qw؛fD!vH;h[a<\vRb':OO)aVa0U/Jgƚ_ yn( -9M( &)w7ƌ)X˹a(Y_؟dVzil==\\T/)$%']~X:hTwb<d(,GU<7yd" CܦQE|f#BF"K$ڴ;-@P{N mUFQD"sΟ?[op8d[]59(O;8$EAy8^3x∝f7"Q>T~{/8x~~|jee"wo6p"j_Pb[YW\sȒi^WE5XFY^~Կ1o}Rǣr9Z. i%ޤ!.//R"'r`Φca.=Tw;8aZ;V0RY:{qB'PCǞ=MX?Qzv}wfEAM|_-'*rbtlaggģf]$*Vcm ;,?s5v7 ǎwO[Đ& {K㲍g\?{Dz?^g3CTrP +tZ#*Qo@nkGAE92*}P~a5eTc{9͆41{⒂u8t{|Xh| +TxO2Ί"2$۾6IQxK\4 \}sv|Lv6'<Ú-oWh*X |9 L % m8֎pn! O Ȩ3GDݰ99(eY -Ouh_4i3H)`啗_^0Xc M&-`6IbZ =<페WR=MEzڝBj<%k4tT(پڰnQG BvJI3Cf,HIFG G1./N +m$9`d4r$)}SHG{MY;\#7[o\c.I.d1n@=^AJNCuvZS\? +YKuJQi:Zۛ`r%:}۸OE E4㗵8>%4EohO~oX[B̧̔kn$6rs53}{ @8KUV.?(l(9UlEjbǧHϽBv/ƅA@S k ,=6ex(ae%ZDbɨxcys6dye=?M *_FFF }!eQ% 3.gE|"wH&!2ݤ@ݞ]WoF>\'?o/Iˁ +I1*M R$u}$&j-dN{JFhe~6KdY(˜''st!5шL#Xw9I4٤%, t2O J "HcM,A{$F(u,i Xʲ8爵pNVSehpJs>Y />55GވYe(KC7"U+ /q"%hMc 'jb6 BVAйc!4M[7 /MӰ˝;wZKHG>?^hy~^{[c 1a iӃwyS.TTy^&y;U =:%5AD=K~!K{*g^`2u䜳'gBP$iR]MSqvstx5gHض*6Tl.k:v4E|>9nG.}56܆^Ȥwox/u)Zí[Bk7/<"kmUi*O&$4M m$TBWv鴷y!h_Ooc(I8;nw0m8R+ 6n3v=/=fsG_xŮ[>q(8LjV/w |BGbgY.,BAn*IG}!/=|{uGOKn IDATLԇb"+x]g3ˬ0B]2B--BHÃnkc:s|<&N*c;NQ[S 8%yl{۞ٶMVʿ?777Ry0Bxvy!.esMI5t2@Nr6 <铧|G<}(uA#'31ᐝ)l@:HI ftD $Y Qc`Z[`9:ɀ 4SaQ4D3d?:#ҒHN:CU50'^ gKCIwgDiҠ"EFXq(-Z{%D TRZ+At\'q$999wCqQ%gggs]nݺ1'''e>L fh2_yw899^, .Zknݺnns"ֲuA{w g0qJ!ڟh" k1uю_ Rt6\*o\tn_oӁAo5o|L㾻yȷ1c]36i)+o\5n%?7  Xk)“6 *U{/wYZ$;-eu޵FM3~tߡwҗJrqnb6a6vsބLJ>>d,"BpXc c-81HhL9q wp)iGU{!I-HPqf%,4FfzyӃKzwb6, +^Z>ƒ_4YF!]9t@cFkBFwh-&H= usY}cXUL-&{1+ǯ-]v| P=\\)2'8\k2!2^|54Ak+wE= Ev@JXpzч8'e>K拊Y΀Eixp.*9Wٌsqk899%4EQno~-/E!N7_kӓS$GJɻ˓'O: us֭6j`0( @t:Ν|GJS$bg'+_y!Ix 2]߶m"7rބ2m`u5CM!"Ije>S$»뗢(tC4My饗-ʶ~ú_4MyaG=}f'9]n\~//w {{wBpp]HLYrԵ? tRd4ByMJ\orJ—B 1?;ɠg8hMlp[UxZ= ͅ{xma_Տw=}<.RJ^yNi8FuTp|aҿ.YR)bػ}e2-p(CPJu"Bh-@mA(`SV,eH)VHfy(#f2ϱ2Ldp[W.sfwwtJGTUM pRQUUSj¼8E]|}dz\ixN֯H H닎AH8`B#~'2dkG!w鈇lCP>wR{.NFn/\g:j;wc?)PB1,e~?ҿJaSȃ'$egK9[HcMhTS5J+,=3aXK‡vmjKX.+uԍeY2H$GKȃQyp{ĭi$HCԵ(fo7#ۮqxG__W^!/r~{F5k-y1Lg8IS?ShU%۷o_.i%M׬^BZegi"wybp8^<;ˊ`q cHӴB>eYp8$˲n8Wx/^C]C &$Ix_/!I[rkgvQg>?Lpil@;_Zۅ>bD Bd٘:}J* c` '8%1G<qzrNb ),N(NHx]i{yNYVTUI՞X,{k(euYkAϿ7a]P悛E R+@E>:GTk9-^wxÅcHmsJ{cӏngU׳ϣRs X l:ag-,¸aSUEQPUU ˽{f~m"*RDYCʲ'#"*"*->KPܹ;%MYcZK"\CT Itd8!N4t$Lg)RI ~:x8 |҄۷'|.uSW^E)EQy++H)s4Mò~Yx)O<&_CzD_UU^hSx߬?k/m9jrCF|CNOOQJ˭[FzG7rXpxxHZ$ %K@da8v]=ܻi6Xvo~v\(㜣( NOO=o^x:-/^&/6h{T7Ȗ#}?~o{ݽ>p@S(K %Ñr!x+DhraYroLٶp`__]y_]#'G`qK˿_+kewRo] lӗ#j=??C~1|R';ܹ<2# IY=ن6tl!DBtH#Щ[,K84U;O>Svf{?|a4Cp0`:_d4`8}[h)cbA$ US}e.lm"@N_ƹ1`@rtXm6ʫWuZb"6?ޅC)X(T :F%LN(N'+tG-01B.֚"x+4\;ZxѮ2%Ѝȍ|zTwsNպ~z#}bo R-;EQtt,>#x ~_~|ќs[M?s-i,g9'4)+ĚenbaLØEaCKNF)f=hw2,>}Zm6Zg-'o !,y}Wkθ}6k-}пMӐyE>r$˲޽{1O>yItDp K vww:Ν;ﯽ'{L{r%kUm&o"dI߶@cKq_6Rw*׫oTϑgl(QSL'4Tqj\3tXkPQV_VRsvvvL&k<_rvvFesRF#uRi[6.O_>I.o;wWT_\ʅuh-IRuSePTnx^!9/T3Lg)EG NKT${k@X f,D&$I,ZX䋊0fE$Z2Im U`X,֬Y6NG5~ڽ[e ¾n(elup8DJr>쌣#AWp`0b \]kt:e4eYRH!W_}_~XNXkL&ku@7oB[q J)1=,&^4e,:ǟDbB8]%H|p|}Mӭ9vmx}KbH+fkqxs4RU_7 =_^Ÿҗ&Z-'Gg,4\O_@GԯׇO;܀ZWjSJskB'ӗmrP?_WZȆDس8+:驏y=-sQX?99Qy9bI@:`!u]w(髯Fd?0b~v"ˢ`vOYP*ǏSUٌt?fX$ шS?~L3N ۘ8A4.NS&)ˢ$֍Kvp^"$g޿g9?:w~R@J)ƒć Bqϫؓa+t  sCg% DB#H!|>˜&7V7r#):O;rL"7|<~$nVV Ƕ >Xm=(6,b؁ωqmJx"/9'%F dS3<>8:^+'H _ۼEs,$ pc^;"R`E)R/4bXA%:҂p4 }K~C[N7cʲU,K9oS!Ѩ]ӕh{WF#fYpih4:D 4tGi6I^y啵՟mn FJFȎwŷ`!"֞SkEI^WU͢(8kfXRU5yUsUsxe~K?G+'um>ˊ_)/mrK_HxxvnBd:MwͭW>3lv]]$HZG4MA\6rtֶv g wg FthsmA`ݖlo6 4 WC.>͟N%`1wߧ+!Z+!eU!f2a2$)JK_xâ(9kIEm1ΑW%UW fΖ ˆe(k?f~Wn+WXk}-dz wu$!.oY^lF/@*O,-[ $":N tچ >(G@'d҆@6B"ZM6R#Z+ 'D -Aϟ7<MӰX,x)~7fzXݷ>ݯYۆ}p$& M]SydiLSd'iQľdJޝ2Ib!Ҋ4LgXЎqE3k,Ӝ)+H``D:2\c;ĩ=a6e-ܦO}^ ^xs?I4B.v[͘TUfqCoۗ ׮&]φEx6S_+XiEeɰ%里 .I3bwo$Y.Xc|%m]6v. } "H#5Nرf)1_ Mudr&YҴ(-3ݻë? yE]i c,)A5(kJG1|IBqZA2hydyEv8kf[#0D{#o 5ʌHKØMlYa,l^̔RD(xRܿg\:qD%IB}TM.`p產6 @DZHWeY8SVUDuż,)Dk8&n]>H,ɢ4xaw,(S!Nڹ[չ6 @XՌDG(?Cp픽HIi=G[?IՋ~;)o[q&^ ƶyw.hS?>wft77;{|n?\#K?7[硗o6@c8Z.e3,wܟ*d긤\Vo/oP IDAT+V$Bi"MU,:<׸":6υ`=#‡z1٬ x;l0DqLc A:0OZè k dVziNY&/`Y5eònX+C^5TMCc Uch̊H'D%@3jƉ"J$&KiJKY[y߅:e,*x97)Ig-  _joFnFn#ߏ(?b􁖾E悻_-ILH9qwĐ'''[|>, Rc*MӰy<*Ӄxg Ͳ* l`%I#f\DSYNO ǧ%p oZ!$&wv 4cV]Ե0Nk 8GUU{~a$ Ru8@c 8 zDa1jtC}Mz뗐vc #oT"jRDi{!XG ш4$1i|!|)'? -pkmYkƪ9o#[k,魛ے_qt}bb~~x^ H6}_{  ?Z?GCn2Fir-ܿP]=͍t5/_G]`}#Isw񦫖G|>!ofs3f}BJ4%Lvv}Z5H8hq,rüh aQի*W75M ?abMiQvZ$A 4f2LFf)Dkj!$R5H j#iqhJx4ڳZ&[stwbv/ҝK "P‘xBgPmRE8B 2"DCd6DD!`5#R1'n0oFn/]=~x+ҏ2kH)޾AMmiӟm~[bXk)(:@~[T^PJa5/rx1EIA8^xql^c8 1C/H2ғJrYqt#pđd4JYiǧ9K0:;+8?+Y.kq,J8Ґc,x ( $_=8PRO>7E@Vcqnٶ.|X[z>4#BUI DXe™(ᲵLO9鏪__-yV_ώbs6t>uC/Z_apt=@0zϋQ3Yؠ -_hDQ(MUMEFIr֮':: Vu*u-͎臨^ 1|ޝ DEQPE_5O>e6uQNcqijtB3Ipٮ $QBP'5NiP +#PX!Bc,X'06L08m,,X4KK㨭b# VVX5» <Œ$V`5"È$b8P REAIPԖeaЪ!0hq%qR(cgg=m(z۸=O޷tb4ZK8 hÃ(0i#q]ta-1id2?: vo): Z?+K?,n6p.XKL&qBp֭n` D$ QkB%m1PKi ukYamkc[ c?aЙJ!Z[9o|u;c1 kkVk֠( J HNJ8$"Ku(SL1aZ#]((JK{C)lJB#D+IMT7o<54^|qt45/K:t)ųm1~??z@0ĸjihcY.wi7!YcO2BG8g !"}ٶ.֍["}Ķwu͆ Y-o_ck l<`=^tByBPټ|u8vٛ^/wϡРo燥߿7٬#" D3)?sK^Ԁ Nx0֣ցl\ĠBRcyt_+q[pPK1 BFJi#Z+hH{"I% &5JHb(òTDڢe/N:!4jw~[wu&>Sf} "^*B*,T-%"C:Щb{G@˫^{0rK~ !9,5yKUNp'XBtP@;OX51M-51AbYLSSw<Ꮤ LL&hi~4c u]Su~y{` cLGj,KP/S'91_̗P/̐Ʋ<: 0E*;c8q­ 5Y$Ox_w ˊiJEm;j4Ƶֿt<ֱ\TJ"o(˕6n~3LϒO1$|5ο;g;m眷<k,4LdI_]vE}_vT1سyӏ=H)MYϿ}یDj>{.g{1%x)ЮבvF=1&PpEO:uIGGkiCJ n5&ͽe^fp/tۊ^m%_]ZAk?;'7r#9GIѺ5ee?~g_#.FPZrӎ[5fzᳪ*x1u]^~epla8>o;W,ָ7.(GGG]| |y!9y4 ɤIBZ7-Ct ' N8VH۾AtB00RWӃ9KSqMcI"xsyM7,9IugrYrYs|Zpވ4 Ⱦ= cB0Olq'g4j NĘ!e d"C&6p(KБf/9\yzzLU&Z"pئ^|ѻ2gd'g!ɭ):κ f'nDl?4q#z㰽Oìx׫M,Ep{6ZB4X!k/7:ֱ3>/Ϧ \v{NhhQSv"S{sqڋ\ PU.BE.չ>wRn'i(ꚏ9[.䘗o nfvb1tn|$)(nR2_.8b21d$I|iGk!@KPn %kZ vDR("!< ",ќ-z[.je0"$%QBc,EƐ%Qtp(x|l^NcY6!1 Tnj TIeI^5,eY9 J#hĴy!(%{>6~濄/}:¨DBuBYȍ[߿yIi~]O yY8]<:9CKŢiVeMbmiǿcq_h8(˒o~<|7|wZ_E/[o;pppg,>ܿ/| |k_^x/}K|{QitRvh-J)(cEM)vRr,s68cБbFF)YOIR` i!% 4GKN50co'OD=Vd$M4Q<){ِ/*ڑf((jʲ[o3k!1ڶMb;C lx0uk!Hu5DPW5<ǜsoxo G$&1 Yj^<H4rزyd7?;_I֒H D&nq4e0AGwq¦1ukeߏQ4vOi޴*ˣq\ |-ǻ/PRpggd͝eJyAU70&ϋ8wjn@s/zqnUV[mb_h}t-zʳg-/kLlѓd77kYQEYQ[)$4kǧg<'"vg3R2_,҄ƀE~!pBDIVIR,T8my$$VT!U<ԭaD$$ ڧ!ˇGKPV y#(Xp8UkioI:McU5Dg$AU;sYX,-FP5 Fr}oY`'˫{Ә˒WUg> g8$;)RT$ˆ#Yؖc /|8A>(N")@DCrᐳOOwg|s{t g(21ӷ=u:UOK=;EIQ[s7.oY)'=Q|Ls|js=>jCe⻊Ub16{C~p6Wv)cx1[u<?E{_mS*?bt8s gΜa8ꫯ"֚[nkA/u)@Y?N,˘Ck vކ/ipA$NƼ}ύC|aGj gaQ1P  YѨ(ϝ ,Z:˖G(mU42My,IֈW{UHRRО[70I`|V$ IDATqؿg/ntgv fWq!6kPsN+"O B z`,q#dG“,IGXC2M: 1\h̝$NT$àXELhmVC3Ydڐe45ĩ&ӆ4dk xġXmR&_xU/6XU<%I|JRsàF;Am=L%"[\ĩD 5DpbL 2 qlIRKip&ݦ໑ޟ#?>+&ٕ<4ƐdchN0-z'1q,]>RԘAbmvэ` `F$Տg6bi.-2U2cHVm^Y3BVVXՠlfqKCGQL5K^9d4|Dx v^%+˰hqZvsB+nLn+ #d\e͋u~V ЪW_ G!|"!?YVl8 (>qgw1>Ti>aE,StߏO!; f)^}?:qw0a C^Ѿ"f)Iŗ%%R(!rTSR j 7(e{18Z,t/X+˝ePNX6&g9dIDv6$3y7Ԡui>g:Jj{zV)~-$%NBFdJ90!80(gIlG8cYĒej|T>R9g>q[qwh{3k-I ObBB3gzqk(fV3j9Zv#~$ЬT\8TnG;^rVZ%$0̍-GE8zQBځ 1Q֖V-Bjjw~^[g7$)|O?v>Ex1?櫼5(#m~tum痟}N y&׾(NҕkDIv7&54tg+L{2O{ؽ%T( c yJ˜ͦaΝ# òjR,CNqb?ǏnhCǼ J^'2$J)Re)<)hhsmdl RHa4itj,Z INSmw{l FsV8A/a<v'įd&YZjjx)TJg4NN8ܠݪGD[G|+54QN:S1><<,.? j}fY8H F2&7YK'8EVDQqt8$Z旙Ƽx2ˋKOVP~.h3>fU~a92<|LcӟzG.VƸGw /z_@fj1?T5+;O3-go?ߝSj/-z?S3p{gN~5P$Iy5*IGqƕ30Za%NR0ݬA e]H*$nA"uZLj!ad/uurDf9&hH˭CJT'HJ"RKt! 38ˋH.RIGe@Nϣ#'|{> G+ bb.C<ԝg{{5 l}qe#{&j߽MdTiV+#m6Rٕy![=FQB ͩwc)&Řq7nǼEddrVG)\:[lxdࣗN'iTgnh_/]nous_`41fN;[b ! ?/^Bj:u._`QvWag0[]RV( (EI.o|IZu.n7Y7op~eO){`ͧ]d!!>iQuzef]* j%T*sQ  REE!̙3L&(*1LB)mr=f&|*Ej:f1!<%x<N;ͭ$% $#tAEJZBC)p0%޹K 'R 1MLRȬ;f;ʗ_ %E tZB02TH+af? T bslsct$#4WME[AIK8=_g{wtv =ih9׼GtU6}Fhu8pݢ ,}⿠׏ٞl#&PU#j֭ ~3P$igA8z}7塿{oMEH8ik Br` x)'NDV^,sS]6v\Esarƕ,yUw>rkXݔ"w3.S((!T{hbt#wE Z8I NN.Ԑ-oָe%eS4Ӽ}{3Ҝ#۷6G.Z0SЪ,FC&ƁƗz5t;pc`1jGΟ^[^ =b)>ˢc?ywpn#B0I)gx*Ww7ֲqsKf4γS{σ=?zT1|s5\_e7`7ʝN,4~:65O>Χ9C)Vwo .ަDIJj-vc4kg N8A\0( ,K+ őxQ3>nmt\+9UP %CkCse^GSMl"(D1ٝ?Hi'`}h77({fsm mhj &T+,77=$f2p4E?V* 6-n։ ̵ZwuY> ) X -%hxۼֳK* V 2aB2V瓃JJ$R(AI% O |%t"{"ʖ{dEJv} YXJHdFWe @[CkUNs%M]?;VN=?pwki: R2lG ' aqz.obd|I*2ӆqTB^8DgC%$s{ֆ+wvyIL┫wvjers;0)6I$'Zs0$V_[ 1Xly=rӋ- wO'γ1DI˼|u }S43\^:ɳ$2wrg$^~?΅c+PҲirlIjΗb=#c\9wnm3$( O;'>B`qϣU \]%tI˻k;$i$IM4I׏X> soj_0\EHe3e].RJ/㏓eYixŗz4IH$N}W8Qܺ5$&^X' ,yY M9QRi~>R J 5Dt8ӿs {`Z༇/[ٸN!%hW;H9hL[h~S;vvX ?@N |tSpT=,qZCSgvþk}*e .j/>Xǟ) `ݦS=C+AH2pnps6X8n:VLXt2cHƳZPyyPCXP)OJB)ē%W %E@Jf)QcZ> C8!Ӛ(Gj!c-K H`iq󈓔4Ov* g8sdX))RI:-i'm&5A?VJ炕~,25nHS>ɓg _ѻ|wI/>usM^1rzw;~ M~K<}8Ew?{o z;fR .X75\^u,W±.$׮G~$+vkg1Gיad$dQU i*o Tw^o@k6SOepn|>YO=r84^nހwv8q/mRH?—Hn`/fA L՝;P^lQ=81cǽ;tc I}GeD<ӚT[DiJ[T~n>H w{~ euu4MɲZFc0 (1}Ep`0`2aɦjvt]14Ry畠J$DQD3ZSW,[hѨT!A5@q )'n46?$%{(c4> uͭ1ap8! =I)'d AsX Z8!d(#$qƅg+e^/q/-{;pK~FW#,T;HUq[{=]J%DIIX=~88cMObdpZj5_ k@vr _t)3B+ω ^{?;3|3~yfɘq/-rZƢ'=41Dfh#Sg|Eԧ?SZϲ^G( frMEm hnwX[J\<>VSp"j!ʹ7GfH[iӾ''VVX^wA6 aHZEy,jU"Ը:qOk!Jl'dIJj&qJh&I(N IM?Ps;u?kZ&I7PR,vn| `u_zBQq}sqR |nmNb.XS zzQhU$IB:qvuɊDzO23>~y?u,E!>5R]h?SE?]t3 h쵟dᮯQ=-66, lcKW앩#@Lx:n'])^ G>uӏV}8k IDAT^>~s폺(>s&G5z+p<6P䑖6ՐdL+S)cS.a5 Bd1ZGMNR7WiBPT!QkI4aݡVhi5);hiT+!:|0<7>fTgʏSd$N)8egLQ>L&J22II2MmɌ{oYYVCۻVbRG_9O\!݄{Jcᘯ6vYl; jH)y wHҌ׮;<(6%` b-B 'c%c6Eqbaw8ݵmUZ5z#nlvSͩ6gW:y!xwu}8os}$I1V篐O~6W>cvr`Bf\ءY@=%y1ڵ jp« foHo#`]gVoğ|m4Q g.gUwl'ϭ͋DI߹ů~._p㺵,ӗcgKZ[ɴCSK>|JQ&=:*R25{, HAQ3+rm}x "drl Zc [177B|JhA_(J3O, `U^Cjos0j0"1qSK ~qaK=L;fcpu0,$+@%T)RI:NqY4ess<0 L&dYd2!,͵4T! 0!gAu*QMKZ3Jv;s*mBRIi+$^VjU%ESpn?N0P$!M,qF'$4G?^+[DP?)) qqQ`q@ Iǯl|^@3'!}:wxsSy 'kM>:_ҩ3(2oa[aWϝF)3$̀dD& PੀdwlH"R@$]9ٜ^/=J a&b!H +%0f4:g1Y ȣ%wkwpR_:"'Dd&? <i;E@y"C]Nz dPi0DSl9wl R!t/?}^Y_zT~ه9*Ax I`?ƿވY2D k; #8i 2mÉ6;-U'Ϭi|`.!ر9;zy:)ί̣17v)5! Pfp[[=ZITro~cgGy^z&$aeysg.|v{C~?+x On_6ݻt|Ns-S3<fpiJEjmEQx<뱾N$cI021Im,R~Y f^裏riqڵ2ئgR3<$Jy\K;MdE(__ XΘP6MiNF=4qJfKX\idpF9E31`G)Kd $~Ǧ˿Wt޸`ute;d0c #,:N҆NO{qTY:,uj%~hA*5!c矡\AJx)0! 4g} Β)oy/7Hط{q;Z?5M1SM;8ph8@cjA9-vx:ȴ Ln0(%Vp\elW!p6[H6} dm\A/}hútɋvhnS];ïjwy?ݳ!V0{dmSLJ)4HXFk)EIBe8I '1Yi"2:6'"OmC2vV<RK,f y,-~y `ݿܕ6ƐaIsN-XrDġKJ,=G'hXKl55" q&Zg WtJJHcE #`B"e% CýmlIk :9nsFv)ށedcQލFN7@k?x|k]uk] +,Y!?\aB!%)UQT#w׿KYK!çH{oc'˜ezSKT/O[t$O>ymUN/y:1˝&}|q92mNbw(?Ux_N{cR:+Do^g{0G/\D[ˋo}Q;3)PR:RTw׶y2! X4X40ƲتmA9,sNgV糺=til R C?`p>hR5r,AYY 9.iykf{}hȲњޟ֚50dqqLI)RA #I$A)EVCJITsiHSp U$+,..rM8n!SYXX`2KFic4S0MRH4 TV=6 X Š(P {K10/-UWuNSoPw\A ge!-Є &ֺ=qDxx+dSz~^+cud 0UCgŊ{#@8֭c{80es4ZLkF5uT?b#(8Bynw)k 2ܢPotwj|r?~Z`G7.Ǘpvq۽xGL{Ajr9i[;u]4e0rpAk9ZJVZRT\<^`MF)tyRJQ @<6!BC5h,,ZJR B& LFQXĉl^X 'ܢM"EuL|-qw|mbWEk0RHc.. c.%B8AZW 0c)6;(\x?oGDG)._p=SaaaeH)9&4O?F2'+Xk!3{E<)Yj5h=nl!'*-e;r~-ο̬Z6ԵX@?/;+':7r%K,q^J(|` ,? w^6`2H5Bm4B[yͫ Z{`-O>PܫaX,sϺd5<,a]B TNZkxB0߬R۷.kQLQQ\F$f0x^-O_8MWznm!2O/vW]OH2 $e0irlҔk]B;gwb !Xç8o|Iyaz:O &$_y,c+sמ{ %\7K\Y.v#wAa#˅nƭ[xv!sͰB,i$ŹM۴FRhL3t0, T3)*R4iSK+aҕc_) }"*ʸ4\n9N?b0cQB7'D,D5 n\f.̯lUHc3ƴvq3 >8N?Yۢ^(^V]h?y\ }_%:4dyʓVuh4ig/qss?~]n4k7fJ q?J~$r'-3U.b%m^IT ^?_έ}e2P>ꛯY}6~Ke%;y~jWo|VW_z3Yg쓗3VܬlAR,OWy6]?Hl5=|sg6€Y3 vw !L׸6~CFX`K`% aL?*:toD|(mfiz=YYMn ,F9j~YJ 4`b .P,V֖.&M3,.."m]ٲ, ȒcA IDAT!nw(Frq̝; !1Hdu!zbbaBDqL" qD_A3?]dn c m>cē]H]R-L\}Ziq(ٰ) K~l>}aHOCP0x[fCExAxA@?0FA!~QX $#%4XO][ׯc[RT 6zb,/]d~z:һl`2޼74ҠpW`@?PDjDDI2߂%y XIqN\q)>6޽}d,NQO6o _K?~$1*&x up7l0U0X/}3;sC%}B{{"tۦi`a&bLGHӢ65GOYFhYdtJT~68C|R@c<PS҃'^CO_`^޼ŋoO64('+A z}Hn7y^8QDƽzD :^Qt^REO 11,JѡT-qͲ);E$aS+̥lA޻ꝩ(Nr֝mn?rj0i<>^NΛl(l~ɋ<{4!8l{|;xA~s1[-޸W-e}λvo+ғvvkx>޺ϯ>(49x{췺^HI8y l钢GçcP0[}wNP 9}~ctVOgã,Tom6\ճK:ͱ☽VY5f%pvics~yji8 OB ST\v{{MTKOMO-'lpVNE* {4!__ JyWN-C~^`박]}n?OfZ4 |"X'}hy;eZdyfi . ЅYʴ>_7it8<=wjIYcz0LֿzQMHS[";3rn:qBZri4[_o0R255ܘ8T*N:ܿ]-w.i255UXQIG٧ܣ)(N?B ۠^s,i"- )BJi!:G+s`J<^Hݧ~G4`m~ CY(aBv[BҠ#-J (Xho(C;bZ-k6;`)^mI$}]5xB$ ouhp^,tB0t.!R yC*UZày=Z>e)1f"ܒ  ss@ ʵ SRPr +Ne_iz~w>`iu밳DžK,-b!UwD}Lt =1IGO*drԘ>3"_7jO?9?o;?ԄLۣq鹣ojr/~c2 ^X3O< XQ(Ff| oo NE:cil Q2;آ3rQ!MVst^7re72_χWחI;].5aE,ӤpJX7:t=- 148"IhZ)7 3\R.% CcRbAR*2_-P)ҶYIϢ[ZrQBPtmDJH Th$ٴt)0L hT1) R7ma (J*ш:Im2!D \&mS? f Ƥ11yGϟMahڭ(wC/cK(Vl췸uȐX'T#(˧Y Mfov`޽=3t no}޼.+)Q?`V]AWN/Cn; z^4橗]z~l&.͞tO_yM><-c%p~osza:80T*uDJRy/XEYXx+Mz/^;cK\navcK ,/ xhyKT 6dgX*:l^.9Z/݄sOРiI_++Q䡃c}?_zVcVoӜ]0 } ҥr;N%94M. 剑ɅY^z^ 6&4S-럽Gq{琻*0+?Y~ؖ" qFhIBpzq !`eF`>ũ*NrXuXHS'.pwAuיjiȍג&az.>vvI{d~el&B $gZcIׯt]?^}yyzsRiZzT*Cc4iTUׯ_ϾOAbH^Cҡju,hYxIZ\zg"<ܹoK/y~DQDP`jj*KzHˤ6Ubii Ln7Jĭ i*va&7~LG4}!cEPҠwyD`K)ZeDZp\#/*2#]Ao٦TXWx<19װa!%td" %T<5%U8No8:\\هOsoGPX౳˼Dz>EG<C@z<7c{@)(’I$O+ڝ>}?ı$~^ 逝~@ -I=rZ=HJ8^mbxGwvG44BDz84=t#aȩM(ɧC;Airy}}MO|K] LW.0T\~Y ݆^4ŧt4K2[-emK\Y+(EJ)IźΙߔPNlH ٞ?Z9#^G_9!@t+1ΟFA:u )%077Gӡ鰷GXm<4R@BG2',4mYN[Ȃblm2-H֦1^bE hu}f.ve\0iI%rɦVw),=$4l<urЃHJo $[gs/ݤKD_{ àt=:QQTL(v=lKbZMqxqL0>;8:^č9r84}AKgx3dN߼K0_s9{wnvZM{2)![{`H`e3U;v$SҦVqq,bAqjqi17=i*e0q-c[XĶ$>vr<Ԑ`O}Hܕ'uCZ,^+<(u8?q'?(WFH}lаdVR i0Dk=F'0,Rlqޤ/vP.Jj:3se̿o*$2ݫ4,RoP;ii_yS?8-0.現ۃE?,'EyȖ:A/o2W+B*[߮%)N&.}_ǖy)7O_yvgi/} ;tRAP`A»w ˜İ☾p,3PgJŬ/Lae[)޺݆#;vfE^_7%x(c'}~y,QW$T:Bx!ebKECaD1N b0& :f&l04!w:ҙ3=S8RCJRPSB PH Ϧi%Uy,&N2qE N =/$N}XduyZ~L$vAM6~BŒ<[qAb&)a8V8Rj#JiC>pB(.ͳ~E!${O|$YdzO~9#듢_" ;JiyH`'*8ARD\\.gQJ)p3R\{O9 ,GF fqeyΞ=ycg LOOaYJtS%<)`YXAՊLf(>o\b{gVwgK5W)^x>g]=.,8}LwX[Rv[%[psGF Z%pTrTaeY¤ MR`I^Bi&@t:SYu8:%qMOF TeN9p/T䗼̷Dr稡_P I71q;1;tGSƮ4ߚ{ .. LQIOtq{)? F7td(g,?35WF+Z[Mb0,0{iy6$IXi _68}Ǩ$Թ&D2=yoER!hKn0uB0ٽNkxIyY=$@)8*OyHLU)JVǴ 4DDq5]ʹ>(u!vGϟq2>d"ͮ[Q=/`ZRtIlh<57ce[Bgs{p3b6|l {GR!{7}x3:$%wf| gC4׆!l,zAH!'eZ t̵s˼#fwx"EOCY^>j?358fyk#_u;vo?C]Q#B 9B]F1 0QR:$Bwj4u KgP:45%Tt#_9AR% IDATp6iK !j**2LLOL*ך8RR>,׮]… ,,,d['ާ$.Vt]=H?"xGvx1?IG'@Pe>bE1*Wa#ULSGl9c/ٙޥpI6P:FqhdL]TJ]B6aNХH'~n8I6S"Q " B[R,1Ҷ)K8!t&ilSR,u}ZRJDd.??D ; dV(h'P.+9!}?`cIF\\ӹ{&Nt,ulʹ w/(Xx7>JʏZR  ! ߻78O$gil,~8%.s9W+~f~)>i\Ǣ`IlipqmN7 ٱWt>ݾO\.mXj?YL;RN}6|alWY%Z=!s92 BLZt~2W-S%MiVkO_ATՀe! Si`85WG# qҴ,sKӬ׉b@רl V絘{=hhƉO8IA֗H=6򗍆ޤ(ub($5FID'c|? H@# @~@YYtB!/|e\TƑ1N"l "yP֊#8՟aa G:-IQ$[(uBht5c8bjxhp`yiKzk.HCP4=BfeBl) `4+kU 4t;>fy):r'i |^sRmʮX@ZޭB i\vSr,O_\7W_x?;ы4Uae!&.25.N#CEt<_=:d%u@XЊ\dmɱ:S-e4uk%,N#~-~% ,!t==^`Z}6: l<cB )Yi]ᛯ!O^ĖPE%]~SWX>arvKؖəi*c %ԅU-M#M*Vf³8te\Yw,չ:㹫j0-ҀS:dN8$mE0ڜkq+MBLOF=dr#;60l0H{ASp0)+ J {C a SO=ER<@RPeRKڿX *Jq'k̝4ZK U cJy}V8R#nT&;{6v%pϖ, \x|v[=/FH0"57*b))x~Drۊn bdsoڏu1 k,'<>ooߠ8 ?+ûڙ?(b%0@JbBNm挦$)gP d).Tl9Z< GC\`qn /T.aQ-uq!pA[(eCZzNj@/a&4 F[ߧ(Lq+tN fx.ܸGQvmVfjl?Vfu8Hu!ʽ?Se7(+g}H߿ŕY/^~7l1/ BXqjΥ9Z|w!mT^9l7s\=賭]%=6K~TIi0U.?q334y*^Xj,g{ve\;lLlmTO ψ70[-G3ږ6r\+PvB#G?T[?N~x(aC04QL0.8SՄYs#.ή 0Vr:LDOuIN;dUͅXI8({9(hߍp۠~k$jH)TfmS~MCMRt]:xGϾO*M(XT*L:lWh:cT8R#.mbߋ=/v fH1#t4~Gs #AR`qBpC@5-8lttt.Ki&<8MU?$q`_^rMtgke(h:n0"$_r2AlЫ(}X%e 96Ol`Tca0& wױkoR|拿0v)^ 6£ {;7[{ c|1=?a2dc?RtWEs L>Np~NLj' kPppGGia&ICa(C^?@(Jq,a*!Ib|WaX貈JaۦQz=60p G^"baXTe.˿aj"ŒcخC,M= -{8’DZq#>a##Eۣz>l5,)grJI(_VA-vÃڑ,+).*`Vb^J\i]IdʨX\95i` ~o)/s\CX| <2\]=Wp8_3Y(""cMWy[4}jnSu>uqjVI0K3/>[w!Å9irB@`#aNG(:6[#+èI?hϹ~%"yAA@0 Ð( EQ"?RuB D./DB`"='}C<*Vo$ɅUvNޫDֆcy^O4/Gn bц@MڃL~ucE1j<=3KA7ʟ@ޤK BGR`# -I}Y<y71, uY__SW^eqqiJRʉ- tI%:|ߧjO٤n8Rzb$MmM@J~zضߤĩ˶u׵ AOߏW,.Whj;vbqp聊<C`H3f&$se*%iPEt/&K?K"Pa*b=ݻ.лa *W;P: GGKy`C ,Ce\CZ38 %oFb'#4~]7._op)qK@ҶӗY A5ȖtT_q#Ky%2Fv2&'$?;kY%Iq$:_m?ϟ'SFyʮ{7Q~”ۖ4X:}?@&un}x0z3?nߧxM^yvc2nW Kn]_E|x^@x>|tZ矾LEY<a !M2q-kl4 %.<'L9b[&ja4Lx@1 S&OI'FxIyH I>|(0_3hAz_DKK-kχ=[R@m>Ќ@<%]"q[*`Eƈ>`؇rODC> Ay:wFqD "xTltk>~cJril$ZH[Qok8.7VFzVCx_W?/;8 IDAT卻<>fݥi!jbkK s2]+MCDh b!Ie㚾ʠ.i(0,K\{xTA^.n| d':1䅦2!l^0-4Um9Rsѥ6}Z^㥈??x2mXz&`%qvtElsHedenҎ,!񉴄p5,!Pnq<5d>!k|l9WG֝.xj^Y4Έ~'҄4&QWN$^XF/+Xk9\pRzm#8aq5`Q}Qa->&5k `QUUm)^!_2$z0QkQ-$W4J+- ұA}6E0|6K:xN8I{ZCi_F~7 =KãhBQ[~G-ĒB eVir^ D5CV#Bc!(p.B*uևjs1Zucd}{4Z\jڶtHWn?cO+&e:3yiӔask]1D){w8<:rS9eQ$*իL3 + "g22(.sᬰL<`{cSO`x:e6_)A|rHEYڸՑ3>P܊g%B-#Ɠ$M$W/p|:#/4A&t:͌QJ7x~CGC)p7ߥ^ @'! C<2#_w!C j}FlF"@KkxWe9=X}e%\إqN߿tu x㟿P@ z]wN? n/ ΖC`1wҍk+RO]ɤҚsR"i _f尿xZQ-lYw z,J()KNyQ?{1ڰhm {GoS7"TU_ٿLGr%Uu5ˍf8xWJh[@+ý=!\lA$^498:cĕ. " s$ҥ=l ޭߞc_ؿ+ɭm~fQ7#?|=Y _Z#q}w4V.nr}g~eqo^9v!NwÊ]'|BO!!|`YV];&( sk^Ѿ !|VR5,q@$< ,mDp&D -i}y56@='zbj@߬NFMϧs`] ծtmt H&uxIn+ʁUUʅ U+_[VT/][hPiw*<6Dty$@{4}4\>j,Wd6_3>b4\~ѨC1r2DNؒlMzBi$. 7t(AkL I'Ra,n=*ZMU89g,;Bg]Ea2u)}({cfƐ_xŢ`>ͩ[2]&aWEE$A[TFŒ(HSE*8DB)BTcl/<]Rp㽤H(3"dO&h2S {D "@TnLA ht!B3֞1Wti#@*0JcuEw\3gsNNfxjlowc遝G׏!D~ D8/t >q)|QiJγгFA+jԀ-w $k,o>1gş!$@} jܽ-K/jblu14Xx:A/9/xܖh|7~{$.B?)RJZkxެ_U/x `Eo/\<֘ϲxaWo gRk1)z:?O]iE.C;:olu4Ϸ[0矮O~Wx<bl>/8vv<<33\N^T9>9|>evRe>F%DqcEvJ E[fiyfJ$1I1Tܸ|y ]" 9)MxJ =c2uo&ZHJA"ԹRZгXIX~x~f{AqWGZ۲Z,H4rLW[0WZB:όJWe z>Vථo\"DklKxo)ƀ*A1னP4ml#JDq ᶕ7x>0us "L ~ҐP=59ԛjwnȃm m1nm-/ܛZӀ)'S )C>ȍ\oz =qnZ߽t|t EIdYdd2aQ8a63_,%Y"%,9*d%`+{xłt,"yxƝ'A'뗙NO tfׯ]!K(%ׂ,.o"DQLDq_s1=,頵!"|у1ySi[H) 0R*vzovܹ6O, W~V_fR--=ZV'#jN!)YzRo6|Ά ^dќr;|3 M7ԸҢ's^B/*[_%ݼ\r5_?ßaN BJ˺DwzgeXJ9ŰKjxrNj/o"e}t|"!R98=6 _QT&Y<'׮ 3wPJ2r6*f ^QOfU$=r H6$qLD\rcH Vw5S) 漋>_O ^' =` MZW SX˪kX% W`,Z*j+T]ݔ֢+%7w!Pl׼Еƶ >%jR_N˫@HeW 1 r5,e}RλVy/[y2c蟵Ήc|3bB6,pFF As?ƀB>2]CqSˈab)|:R2rR]_) iElms~e3 B㷖{oŽ`n4ig*c^j]ʠ7$$Bg.12) e i0t;$+\޻1sUZđr9%SiMiJNN9,Ⱥ=7b-qAeE!g1󅫚˂|LUw3>0(KF:Ad6 E7.ᶵO_F*I+I%jo,/Q!zKWCtN`jfN/-l˃A}H%$JA$J[wEJ_ۚ2VF6;hNV߽N_K+YKqn0ON…tcR Qrik!h_[`Ek_Xg?HOe`5ʻ(Bm*ݸIs&.6 >\{i?nw?S? @-R|o>',XKyG>wCp8J!q"VDE_DQeY ZkF{{{N[;CzY+YJG)X\B`JJvwT8DJ='˥D,f+7_VO =Eu~x:+# 6L#3+,zu_/)mƹ$EƐbq4Vٟ*qy=\{qRH>W'?ʗed!IE즤>g)oݾp )G)ld:a!6@)Ҭ+1UEYlnt 9)ɘ|M8!tIΚ?:#d*l5'%Ihk4u^JY/aʦ[sq|a =tè=0W+k<3(T] {Dɀk}L=- { pQJ?NVt!}E/ΞqA/B*JtU!&LgsD Ty^!M0(NsN-vFtԏ+7A-ea)$8>./8y<}/_ޱaw&nܱ_^k:Wq7#~q^7~kúĪO kZ! @pr|"_PiKAU^(bw_%$v]Ε}w_|E,ڹyr‘"c 'DIQ@PqD$[`_'Y䪪r9WKQ['Y,h׮mFeyeG >I!08Բwt EÄPxBO #59<V~eA"XC&dYVW1Rv:p9lP%q%j*kim(+MUY_>pFJ-5j 0$҅5C[?+xQ+d)C-7+YKDsk'*lBYUY,܋0.1 ̵2SiBS$o|v(Ekyȉq9Ԕ7oIn=u^xܿ^-gi|M1ϊŷk /llrxpoDR1JTu_<={dV;o_ "NRl\r?»r#v;$qB$ɴvUJ"-)Bl?'rEH8HӬ8&2LbEDqs",#}^D֡R 2!b2bvc EC(a'#\eEӥ7\(ݲ[a(raI x,k-Dm+G m ̅bUO[PezW ]۾Y pbE>tz(rײQjtؕ"re(xX.bQ)TԳP,I)3f1>ny΢ ye`QEb>g1_ y|> /X9(|eg'V2rDd`|r T*Y%ן(yI"iJ]rvrbQybz />8>|cg-rF1U 9:9 3ƭ[߽)_ʗdžQK71QAp@q;޹q!Qmd RlmAW"de6D` Wakgՙ=^Ɛ8N 6Oz IDAT-Fd"BD ȗUG u>w"NsYN ,٫NO'[ol:* [UNFi FT}KRRy΃XT_/kIcfl@WEx%tǜ$(Jz#CٽNB$Vυ1B8KXJEN%ne| z׺^?IpW^u֢ɔf'U@Y V.ncBO '$[ϲ{=9wn |@DL&S@e Iİ$V3hR"^}$I؁Q(r| !•CZRER,'TK@WJ)X`{Ωԁފ(\. a6Du pa*mYƕf ~o!½-/ެ<+MgWF _mU͞V^۾ȅ!.s<SQtk R9D TF<(!5IQUgg z YPjxl^1tzlmqU1,̋R [q۷wl\>]ino'UFMFM2f826GC7v2@ggs&2bQXNr66:l2,wcgs&-\r{%]P;IQ#25QJr6Sn\2RLrson8,B[ FIIl@v3,O}f 80#L3\YkLHjPSkX"_0)HX_OfIGv{|_bwo&ݞYwqvu:v‹/=l;w"( _;ܻ};;g)-מx>iD^!B~`w{7;I30i5f>qx2/((܁YJdy񹌜쉎 K{$qDw/uŸ~!\QMG}UI;"eI^AeJ.B.Ap'};cdz~ڛX vP}^;~| hۊEyXL(N8|4*,K~~';?CQl2JhmJ--8 qAr4/ 2k,{~.)o?9ƪc:[s~{aَ%7׈5.Re!κ iY")#ΎCUOVH"eB.qF&H4HU)z.E,3)oSΊګcaz,<BigDE E)A`6w1X.}QzBO%!qȿ"/\H%=ߓJ"z xw:X\`Nk7y!A,@Bj  XBtdrrW 7ZNH1G_ F Q+%-F E6@맯.RV_Q}84Sؖ<Dqw.۟Ø'4s!=~/hՊGo9g9/x)$Di+`b$acgݴ6Y'dt-J,AE)*)-7 )Xt:#n*S7/g.âBX^|ylb:ͷqDe\BE ]Um{= ,sɢb{Gp,S(gee$*r媝!y_ iXe&g3AlHUMh48w驶[|Ebb"{9 ł|rsQ0`5ɺF0)\a!C%;Kfm V`Kt!DD ^A7 T q nq2_܉DF[ޕ]QT%Y?)H4Cϐ(4KH:]J$~&Du2п RI$Fln N>XiCQLc$bks@HE̦yI5y0̿YFYv"dRj; |/)gSNҍ-/>w'GwH W_aey^Sya(!/$_K0Z=O_2J:צm!k-'ׯ?#`kԚ:JUɢXվEqتgZ}k׿sr\+Zy-/Z&ui[^jGo"e,'D^]HHt(DP 1\q¢Z27 ΐ ݌e(&Z*JuBaQ1Z72CkMge(H3L-2_'g\lmo1DN\J:CnW3TyUU\D泞K!n}dUrL%B5z}8=gO =8bk22r1T1IV\if\*BM%-P*\Q 6}]ٟA{h E}5FU{7tkBtw侕3\źlB VD_ჸqJӍW|t<"m1l#Q??( "1apKOSK R#w>XE4Zҫ,MvũŠ#o6ֲ.w3OWe(7NktIQ!*"T/*rPfS& V({&Ƭudlj>ąYH(l]O2zݮ[K{yyn [;z*I]ux7\pŵt2M< aG5 97{HË:1c+Cˌa|ynWYx\Cc-Xg<!fss{u:^hmyk eU |el3N Gh;8O1*3@x|6f8pyɏKCe 锷yggǕ7g%E1=Ea6lle}~+_s}+~8% Ogosr6Ed:%#FÍmr`lzɊRHN`@?H cI Ϛ?wmϞφrNyxs—~O|ӥ*KܿO )[#m?Uh0o?u- <ˬqV@HmyX{x{>_>ͷ}eu¹K6P׺: 2*ȫ^}`BTn0ı "P:I3ḊRIƐ%< ID"I^jdaل$QLcnߡ)ml2ӣlU9ظt`LΠGNKKWZd#^GDTD&g|| bNp8lrk<&￐s'Bz PX!<)D S 96XGWoco@D}Bz%=K FFZY)j "ɻXVQAӾaudhY[ɦ֞@ |4Džs76Z/gk X+ 3#@VԊr [-JԱGE'ìΩn@y5YmW_<ˠ,9UUQ9k,i.\:_EX7+N^j?_>K:[9Yi kPV1EXͱ\:@O%:})].{GFM.K[F/=0у5/u$B߱jl4# Q1qa4[<3x&;[ }(T0;+xw7o L',S`\Y{({wDw&o}b|xS.ؼQƤN`M6w%t`e;7?& +|zd6Ae=NFGU g9Wn(ż1o5McRLXkFd݌ziL$ȫ+ĚHEXW?N `$zw  4׮?J'Mu:n^wE >@N.Z뫤dc_΁V 'w^J% v1#RQLk_ ^K@Nϵm^^ψ.P{ֹKwmͩ]׾`,Xc5i9\?0w۾}N}n(٥pvvF!. ˂g_xm g'LOis=u##: b&sob(rBsnoSƨ)(1j)%eYQ.nhck7jcw|B5s.zBO轢Z6zAQǢAl)/ABd풵/Z,s>DŞ+BF"< `/g81ey(7\%80ƓgyKPVʀ5w,y*N֛w#lrcxD"HM4^ʝUmB(V u/ P՞$mik]N ]2⪹=\/K4ʄ5׈7oorRwN&s85v<=ӼlX7w; %%*rRLqs4|RlpK1`0w|tiMUhmuhѕ9s3w!Yei!Ls1GgO}jeY#o|e bKv #Ed\|ɺ#S**:;%>cXh^|_|o|7}5 K:$q VlGnt{=nݺ[;7y7I픝Q Oc‡Ōbk{Wyi6ŢRGۛl {$ - 6t ?% =(k;ܺ4:jRMcz)K:͸~}(9L҄$n(ٌ1QY"UF leLgyi4$I֦.0, Κs5d8xXRf &5nG/ҵ+l^\=!O#zMd9,iCmma, Π-<"-͇끏8}#*W6ViSit9TQF]SVI 㧯51= bX!HÎ[h'Y kPbɈ ,fօm}T- < I5*zMj\3ߏTzikB5AT ~O O/D{MPZ:[p-ђLoMࣞSs1&_zEYFtz`>V7j|0%|Nb]Ŵ akqVI!R}ՇP:˥Tci<9>S T$=?/<?|wA'ü'lxsG^G>/|~Wyo -M7 d0N=qyj/=EıKT!$5ٜnCĭƭ)XU Ų3ʲ&1'#-'s7EmlbNG̉}loal=62M4!O.7.UqɆ;FI{aR+$pxtRr. kocn-YD\6\s{_:d-:Rwu:X'.j_%Vگt= /\uCϾ9J;}iNG _g2L[V=8V'!,c6簞oFm᷋ƺکUvǫʕIͲ`q-hE|:Xo4;"SJٴh!(gÅ*rBSp  1F9*Q! 2$z``ɄS4uǢs{(I%lll0Hĝ(G# 6w~׵BO"YkɽKwaXP~o%舲,d.I6^[ =@,HXkKP9'!iz RKDc k5v7i e tjii䅔 ?^a IR%@H0 al ha@S'N7C@K smj OzOX,H-0QY\%и!YWi=:l-Z3OE4kwm~+aQ1D~$#ﭠ Q!?"V < ۄI;wq (Jv*M(t]U?ך61]0([U@j7ٲhUrnΫCy&\Ф)*(,kOa9 zߚ稪1eEK>>_?~鳴6%CPa7lyy /fڢ8?0g+"#1hS%ٔQ/fR8I99=* Pkq'sW+_o/(f\N?g @gskd.s:%֠Pɔ|1w9"ټwAܹ{ 67d@!q0c" x0t [׮/3Cf}-6%Q.2}*|3l]4btzݫ vw]ޢIue`2igͣ,>ﭱARKm$˒'ɖeجG!cۄ1ŏ`<;dK&kV'XUug{?9w[ݭv~ku׽쳇Ca &Ø[ T\Ri9l4YUl4^ pl6p-A.|Y?fJ{E/peկ|;@{ ? p1eͿ߲2)(N}T!{?Z`& E篕\z ??IakԻ5q,YZma g:(DmM"5Q`:9l^ǚ IDATj+ClC; C&+++=|3M0UCM!|R:7,_*,\Mf/"o;wjyH)Y]]jtviJYϣ^#⸿Ru4j5\ץ^m[5O:#$fbjb__nRJhR-ӹ2"]ǥP\I+YDtC|~Uo;\fq1+RSEt]LLӱ96&5ApwP׹2:PCkSO=_g|cnn~Ei羢N^9Uj_ ϠޚG\vEt 3{AAd ڧDxHKrddɁyR ⁤Mf$@TJ!X:u9kN^Ndt]( I$VxbI{.F/yS**KCz-=EN*u*>&J(H LO**Nf/5ioT( i,20e]6_^FcAgNRPj4V8I(˩F&!LNP2UZuHyhHyTRfeΛQ\I.wz,ח;r-?%{gsqDDqLQ5{2IvHbI}egV/ϟ$ Z)9@grYq7Lo?e1K |폃1!Ri S$Ly"s}@Zfguo|ibmt4WSfm4&Djb8ޱrRA|͕LNS“O?ɓGPi`go|g-sGAҡT8*fqëQk,I0{fe?Mh}V<tJk   ~$P]FYԈ:udɢԘH'HѦMhjY,u=,f7韹$@+7LblM5QZt[ Rck k݀8)A`!XȠ 2-q=?4(H"fo-5z:p1z?ExAgk=dngcpֵv=w+`Ak #mI@X fz@xF0-{QoD z߶EjE)R # 8MXk&BbسXk6) 8C̙3DQ:T*Q.WVkOZ\lR_AJyLMM[mX{bo]#$",ۦX(`; FBt T*LLLp:!7;cN>B^< !5vK]^}|?w Ø >n@AH.aEM=v-eXI(q I]r!]aa~}? |(#2!.fcֈ }Ԕ"Q}66GYE_2(7\~>~'yAZ^Wsl6[v5z׼ځ) KN r/ Ӏ$W|6 Ho@0=;W]=2-& k\ÃL?5"!z:0]( h)SZ*tI RC(S3j2Gs l޼9S4J%h)jD[% :I%BDkxEv㯵Bg L5KE7.|񛹖_C'2#i( L _E{J:ߘI&@ԬDZss 6K]Z}/K@^\$=pAQRJ!a| "˲qW2m4b)0 JsR,Z XH;0cM>v ?nMFJ8"|(^oC}v&Ƥ7ΩjmT*8DO΂ zf٤&NIôL5Dfiti!7U3Lئg|YY]VDb*Fa`;^ję?jٺe k݀ӫ]jexaXQڸM'ˆk({$1<ǍVMv.4ysqF2 s_Tȳ_L@$IWʟٟE1Ї˿Kn.d/vKVg;vMMkw-III ؞ 9 SY<%K'R椗\m@#ti ىr^ۿUv_S-:)z'y tO!R>ߴR,Iʸד@+b)2!Tq9huVzs;?VWb+[ ird[zPV@=ys4 hS'iZLMM# Ry?q$^H8"ά Ti @꫈gHٳȭ87,MZ"]Y:(3M ô0*Ӵ`c>c{_uyub/0HӄHN@b1WB{MwslinzMַby x,gO/[.T(8`~,eYC@R(X<{5RZkFlor;]M"e?BKf[(aVE,L(@ JjTR1Zi"MTJ͵UZI;iZLo4«MsANAMw^A+4ַGL;7)J5\b"JF*.feXZ^!<,e SF`+ &=ujLyV04,i8hcjaVVUj&ʔ]Nk7)RUS̏\t,1e@Y?~YҕB#|2> qxp僺S>`% @XxBIoЀtW{q+,Frң QJMFg&}mW݀^U5ph@{}Ruj=w !R4Mt皬ksA$1QlԙشJ}SNVXN <8\3V[]ЌtUC-E";$I$Id@"}"e*D(bJPZR,FZޯ>8Kg MQ)VǶfݡjعeX %°lg08׎ -%mXiP+{V C6*XxU(cfzr$Ę1 LJL^{PZzɉeMTʿw5\XhECt۝7)r }\G&g82)%3kY=?ՑC,C_KR8@jѐ('+[wծsZbԌw?)tR+V1!#Pa :u7*Op7$f)7XoHW/~֚;Q*!Id!4L`2Sˇ$A/e-~5'p]>?䇱:CJG _ :*CdA~ϻ5]Nں&'Ns(ٚ0\@LsPJQTYFʳ"q׾5/!dmm[oC RJ[ny;Ͽ:k/Hp6({_m<~sڵ{qL)CΜY`eeRĦM(Jړ߫ۿ ?8;vlo;_bǎ\}՘ɉ'oOsN;wr- ͏ų>weQuya>O?<\y嫘[on~#G0 ct:޺bIIIpaƫQE[mR4>yH#>b~ ~I ^ 0iM D]{(wžȏ95aq/Bz)]' )``Й<5?ÒAߕ8'?]$`w.?Ju6S4OP.) x 4"G6vAAsi$rF$X懔gkt8a%!aszmHjvH ' !Y4i/, Gݚj886 ^T14]2 v,<΄Z!s]I8m-ƌ1ktiN>%\2T_ aȧ>)*??t:_57|3ZOJIdqq=O7FO}S`mYc!zẇYJs$鰰R)&''iZyگ+ ۿč7X^>ǝw5\͛y8sD)}?9~W~o|䣽w!QCя~wϿ~5u|9vgغu+GOOAF'ZY=X< _lffk2^~zc MN.7|=f`Hh+")z, rٹRnz*e(L]ΦFM D:xN/!6ITL c^1╦[BSb S7ϩ-Щ[]pif۷8N*o9ĵfI,,~G&![-WK!:kHiIu="9~r xXKR)Ν[ae$,vchq4UcIgOs ngrvRcV'3S6qZSi$!(D48~8g7&S8< NgF,^ҒLxE۠G$qW2=3M2dn,(W'(,?t6~6I3 \y!oSjYtLayߜvKv4|A5G X yuu !KLLLHɇNxC<ֺ'zq_ڏ.İ+,(A" b]{#pѤ56 %\"lZh-5KH Қ!Eے4BԁZTTdJmMT!;hA.Jap*q ZJLa-hXq1dMHS  2[Xn􅑤 B 'X`R0 ʞ}!˧W9qpvK%D.ajATVRrl+g9qiK\r,,ۤXpa[6FvcK*񍎷x;W IDATE ~/g?ˇ?y^ν|up0̱qaaկ~uz}w!Q<ǣSE|k_Uzh/z(},^ ,h.L X5 Ɋ^FTxJYt~?p|cf7/6(|cn/ ׯ >Q֭l:r¹c͞L,]mEdkXF%](̐([,VYt48gꢘ6ʂ`m!33l^±IX4kk8qC$ FvGEmLBjLlA'}u&h̳ffv~fqałܩ݄7zzrťeu}L5LXw^69ȑBnʙG# VzAT/ġV 7~Ɲ.'ޢxoĭ;w]9K1} 4j8 ]ƳF8t6υQth% 2usI#ئXJ)ZC Q q 29T.gݕYl@y/w*_&HB%md *BXh}gD$[w0&t@bQF>S z- cTפ^qq HӤBd{uqKE>tZ4mS3Q07=k\IRIJkmN-pqp%Jt4GBۺ/RV,=a]7hmm~DZ{8pؘy#L߳d0 U6v5Rgxaa!333ѣGyY]]e~~n]kMEm8X,{.~_~9QO+o<->Y"Mk>n˭ʽ~lO$???#v!ɡgy("};Nz0U>S1^x/y !)ˍ?˹楦s{|E۟c{MR`#Z%S `ƍʚk6RJ-`;ٵ{'~;nn6i7pJ۵YbQHv vIK!P¶=laAF~n'$CVb˥{8q>˿̛4̻n. FYi4j52*N'|׼ZPTG?BT{W_MСtiƤ~x/BaE6mɓ'Ū8IE,}ϖ-[z@ZֳOkdC'$08r`%Mr|P=eTdvfp}* {^:XfQ,17=FE1Ea&J0Njm m?@%1JImhLa #<#NO>Q(c9רUAG)'Jݹ5K´manw<ǤU8ųs*$-]Dv\`^d׾KY -;“Od,\[EWT@uiT8u$+K욫Qq;m#{~z54`[RCЃY~M'֟:uy; )zi^? 0 B"DY1:ȶd%i%+.3-ӬwYH3k SdA+E:ɪyՠI,]+('tD@$F:u~F,)Op'JV!6Jz _kCP 4 6۠bXcz␊[H\[0QLR ϬNb! F0\kп?-&"vmv˶BIlEg0NekgSϞgp9Z XD %nZ$hИ Zy4;J+?WFzc_4DZi0A%b7䦛nsf)7 Ro?̯055ř3gO ?FIn6R)kkka%\ ɓ8qcǎqwݻ>K 6T{ei$ISyѾ-GCRn?HaP(k|_'I^gyV| 2eqy"_lɟswl{ 7xql48u&w !XLt4&Cڑj*-Ln} n[lA)Er!Ξ8Dgm,*tˬ-$+k:V0 ]veX<;2 Sl߱CG i%-Un0 ,j뺜[0㱊0D4-Elh6@,25xT 6ItW ebhZI(0!Jl,0ԗ@"@aecUaQpm 3A("$3|bBbqZa`Nș5DiBdm<{(Vm`9hG1Ns3D4Op"+&kDLʲm@Mle DZ*X1cc NV( J Nf.gQ_=;{HKSL(@ӽ;ꪫؾ};zg=Ȯ];Œشi{'OQTx衇,9DQ*ػwʦMXZZ⮻xv{}e˖yn߿^j}Q(ܰ,bbbٟ;䡇GͯʯۿLL4g!zrq2 `%3)ϏԲ;]+e2}'ڟs_+3h!l͜&-+biPaT y謉k\ݣm7r‚bjFREV2Y(YY>˱ЂFu͸"Q{raV>v}R2(CД%J2Z*DR؉g蹋eϭ{aJvȥ7S9H-8Ҩԉ $3Xm9$g CQT,enE*cx"nF@īH$ld~,2 fҴ1L!s= jƴl׃=[>Li2=3fi#LM~TF|M̵M5 ЩIJc1ߖB,Go4ǞwlgؑAxwkK˅ )-wl6=7^Ͻ/= 6^8 ?4 G7Í+'}$Q6ἂ>~rV܅&Fe-ƀRJ8q?C?yկ}k@ kX[[ĉܹxky.oxyի^E,bPY9;|I+>mϬԪZn7ͬ/>1NKndv4(Bk2naJ%l̙3=V'> 8͛o}+z$I;iڽ &"lbY6Ǐg(K=zNi|byyyOi/n6Jw_\z~"_l__y k{ :?۰N9, &4VJkCȄX*̤)abmacɝB fm™VOӨT\,"&]DA3[-{ v^z9B)a0ZJ3( i6!q,7(A%m_ d׾B^$iPP,Wp=a۴li! YL[ia\w#Eڧ2DoKݘzXsU*פkC",q>&Ay&cb/=)եTἡ6x*=/~t&`/,96"ŵ}=BBG*IZw>xq'QdTB8#ׇhw w(=`;FSz)/DM5QFA4}8@1I.-ˠյYs420P" 㸀HmT@ : Jg,k4:L Fb0ʀµ= @d@S2@`@HtL'b*Z(0%+URضE&2mgQfQpM6%sZޛ[<=wy^[WwU^E-5H-`&a0A&Faal1ƒ "!y&`ՋZݭޫ%3swV[P"޹r~cb&K xddtm|W8.>Յ9ȰKe><@ZR)1-W B/ΗKpwmlu~V{}ɂNIz^Cz-ɦNGIvM<̳XkWgQD Wƒ ;ٳ\?ϏutŅu!G'o3<ç>hY\\ȑÜ:uj,$?/| <?~ <4/^`{Fа,/!K_/_faa$I7^ AdQC̴wI)(J,,,| sɓᡇ_^;ogxy≿7ߞS_x|u9y$Qq뭷}[n9BK_J<|C+B\G׾5ݿu*n'cm}hfaaal{ɓ!صk?s?'gΜ;qVhҰ͇W~?2j$c&1`xQLSygz;%bh[ [͟ 5[ŁC'h9Yn!Д|\ {+ hcϾf IDATG %dh`mul4=;l9bBqgX̮gXk^&]D`M$27B"̌Rz_x^z(Y/ {1/"aM[k?\_:1h>a-2jPn6@^-~'-DmJsH 3,ۦ:,7}Byb()UXiH=֕b@s#ˆm;82¸H!Uaȕ3kcwkA|tM /qD\?SZn>zOtNn˳>x NxL;34?cXYYw~w8zV?0H7 BȁNyY${/'N[OǏ^`]|d /|ow2??QJO??yy>я믳|СCc=F(طo_s_~j:>(ۿO<wBaP'@)O?o?Ek|_ZjvN[xFy󿉿bvp6dځ^}9U"n74$?f 7w񌥜0j>ɯP0V"j!& /2gՕ5f*eeFыaȒfA<*2bWanD!2?h^ p\ R[2qRr$MHuHT0X2q`&/\"ЫH%,}y3/TOW8a݋ynjY,a]g<g])p@)1b>ijui{:Mt![l6ydg"O`$O>$Ǐ'~qa4~җS;#X'x'?  x׸{8~ؠǎ'?)Ν;nS*( |?( o ٵk vۻw/{EAP M opmǸ#j5Oٷo566MZ?ܟ&o(6\ގ;o\`lߛ﯅ }I (j1KUȣYXD.ί6kbho $iF7"!'z[Tx~@<*M)piIu +EMS#'7(뎅 fȲ—RğٗYXXW^_殻X̕g}ロ^xz )i8A 帕X,C?C?Oɲ ᡇދ<|OĮ](7( A(Vzcǎ7e{y<uםxG$|ѣH)9vFED Gxv,,,k׮￟;k\|a1JapI?Σ>Amm ycfff2CRzQ줯w}TU?9t.]T*׊,`hFVEZqs1ǏQM~wSiEf5+n⿝}"i "㍺ p5ښ|zAq@efqq \G62^!To RiŸ^Xiu=/+,Q`=ERynmzͱo~<5a_*}cgl>^!@3Űo 4+mZ)$I.nu6ط#̯O#ƞmry[{ei7w'Oz?L1F2pl3d1)΋/fcsuߠ1 Ux4Mn݉`VcI0! L9RӡkDHqPkk,WK8!t(-$ŷ).92 հAfhӡ,"ڤX+Ht"ȴaZi_+7+4MҔ8Ř!2$C]$!Kbc 1՚4[]v/.r>q~7JT"d"#1)J4H5=O;c&X#xUfYn腊R{wnVkA94h,ڢչ{F"qݾBdxW_ɿ[,ŚNCW:nFHdm"Bha/X^ZVp{n@22mhg+$qP Q)5jޝ!Fk7m6Y# S$ O=5> zQzm=ZkQ,bϞ jvv__ŋ:tg(*piN8A:ex >Ld,..CS,Fˉ'({gϞ|~`t,J<#<#Sۤ\.ȷ\lDl(!Q⻙0ɓJcƌފ49ntl+_m7o/{-wZ^! .[_^;nN2b 7=z` i) _,bdZeȻRA';Nb:>ߣXY:oMRsQFKc`QX3I%kkbLJ$=-U 9" n+y~͕mGN' Ƙ<P+x"%omHЕD 2mɒ,AbNn4TC&鴱iBmr2c Ur%Nk!}(&$D~z=Tq]*"u9і=K3dA`:}d2C|?`8vߦÝ?~Dk,+<.܃췲OwwJ9΀`2AZ#dPXɲ.!ͺVS0u9/3)%(U4#qB!/YMBHKTqWvڈ n > zu_>+uִI)h{eW@l%3 N_壄W@FcL%)0_ F"Hv.$)qm]emV 'miCn$ &qA5dr0.#u&y.cs8FfK[_])nB=1 PTɟ 1S|ロj:x t>BH>y>oXx`a3JI4ߦ0*^nhX;TIy=ߖ*=߈4,&噊r%i?~'k$H>L|a-[QMZY% f n$mJQʄQf8+rNXB GY{ڠiXH[8Bii&#[Nb,!+Jsdd]ɶmVsY2Ww *s  !(Ş8c˩NyE|4r|6kXntRM-vXP(I3ST&Qm8I۩!CAÈ8Xe4w/y$ڠEYt(/aqlbCkf2f$iz&ݤkE`cT\'FMl> ?$k!{˿S>N!?A2Et#f6vkʶǿT}.@D-Plhٖ$ $2ɢHW!D )AC!5 B^<7"\N'Vn%$aG(s:YZ} X[[^_CkB`m~~S\q[6ZHǡ}{0iL%XE\reutJs`,e<8VF>'oOĝhc "Pܞ*,adƖ,\s5*9q-VMU`dX.'R9T.-P7H %%Zk.s3` d2a!d~aVj4., 2&K)CjU˸JpPe3jM12+$Bw=pn+5:u\{&_\kQo.1[V8/$-$A)+`-Ba2Mi P nBAg] Tn} !,AQZYxGZśYs̗ ~xWN,VkoөPuRyX?  .^{g/.VNi\:*{NsC& Ř7:{D jǰQV6c/SPߺ[edwmwcN6& 뮧(Ә$4 bʸ  $uFX`tql%B Iⓤ!iE2S.Q(V"%\vy{uyٌobfqV(`(#5.|uZ?c:6KKHe&"Nbjk(W-8ƫj-"'{(C{fqD I|E*͗87 |"siJTFA[j]n՚qbv%367ZH)DTgʔb 51'w:&ݤtiw5@(]|?h$ތ C >&M_oG\ogt}I<#FsnW?B !H9ՈvHLT&ƌ15?x,&/ui<)@9fa-mZP┐agYk%3+)gHH,=C|k5z гNX:g55 ‹H.I7&*X*Qܬ~D$y'~ȌrTk?!_O79z>Ъ]xU-wxsp%Ow2V"a\H//U4/_]fffń~EDOWbuF&"MҶn̿lL}k~u*ߤUMA{'/>0^l&^3jxZc$zV4QYF{ 6q $q$dKLjVV x$D b"k,t T ۰zFТjǛ%˚X^h͕sK) h78J1Wp$-@(AgNƂl, 3|Gw.bqqS7mJq:L%1a9.^iR+HR` 'h7AYuL,3T7qʧqƀ6Y[ϛCC4CMI7h3Nuu#r:^ډ߃tyJjxøqb4|`#wg}1uB͵9]=>>M?ݻQGR=0QYK0'H)zFTkM8=I1,B2%n[]ӏ  ^w\vKg_BxAu?Y hqeJ{('vVN :W /,5V(J2NL&*f*+j68.̔s!bB!8g$Nhe])re չ*fLF'eRXfmк36u3v:nGۥޞ>mxz( "qIaJ:&86 7H|R ra*^Z^7+unQygL.!ssW-GwRr)OG`sC uFM_ia;W<ڼkSCӍnnGԇP=%2d8J cso[#rNÅswZAH!Btd *y Ę󈤅N(1Yc2C4j穿9FnJ]k%@&7yԛ$I57& ,$u$hZ6p=C))$i-Hi@wG20//-ѮM[07>r>Ak9} ^÷].s12 MΜȞ{fÅsY6pCuq.^\k2鳺֦X!k.!\.q݀Ni4;kMjbj3I-̠& ˮG\E1JR)wM ?vcȩS23| ~ÕiMI{賛?A5Æq ab#?7nhѝftkF}achOCabm61Y&Ij*IBx8A1IkS tcQnVKcm4t FZKJ rcvtq據"yLdYX1i%!Ճh\vHk-^!HR[nRľJ@ -]Y)k1kGy i#AWj7xX4:~PsH 0|"/0~($Z`tj$s!%v&K,eZf~H9Pb&`]ݤo]G¸Q,x<ܳ|w~'juGx5<韾N|wѴ6r:2`;Orwc<vZV`ڔ[C177J,$IL+*+KXZD)X@ 2kPB2W*3S+wʥ9JU(7ط?3BkW4D37S p`"69P*(T8XE}BH5`5RHr)BҳYv!gtgX|Ga_gto{NEq$nW=CaAź0unlM&#!ʾh~O~v -Qoj{L Bu!\J]T \BQF/ kY&)fh2b⤅4[S !MV8d A[.PJ:BdnTtcY4'ۅ^֥>:ƋZ-8DJւt[fU!}$"DoRqhNqRK ZixK<evHUBrP*1;.(CP^l7 덷#Q#?Fb #8~DZ)bo{x&桭o'Ҿt濛))zȸL yizw[NE_gkkgȰ`tۉ5:Ez? qɈFFr 3v Fe+Ke,VBEH x~SW^Y!,=gaX`ٷs"QB\QJ>d^DCH1\$~};8/BQC ffP(*ʷ߆PBT&Ҍރ:dVf?,0{a`t%\cqqɣ$IsGh8AJEfeiATO0:H5tܢZ=}(-mȋmGd)MHtIE;w2)nv$ fo!~]R;`ѓBL<٧lnmnF~v1y7hML4[Β$^Du-K\cu,;KT%` .|D8p*BahVk[$Wcim5YA*E?մmr ./v eW0 yKnɴ!ղOiqRo@bY:hQvJTa2[B[;]ZcTS ^*H[qMm&W$<*7k1f8Z w3]B9syu(8eYƹsX\\ŋ??qnnKec:1)qT֧,ˈ8S+$AࣔBA=h4Htpx汛$ns9 `~~(z{yqYDL* ジB˩s/&翝/Ӯó򋫯2mf\7iG/2#?E*;5W\&~/?2VĨ;SEhKeRF˼+Ny'󻘙E{ARqBǂ N.^fV k}^XӆXCĬ./S_^JF^i ]-XV)nAԺz'[[A"3uhw;}-]][d `e~~ߕ\<VX*M ܋P8&[[{xˊ[Uk=}fld8DWsMb&@$hxhhn3=g}>͜O^kճjXOU=ϯz;3D"Ul{眷y#va#-! ]~=èd?}K4ʄGL1JFjO#AB09Jw"@熨i_-{թAa75Gܛb 5331fs)Y)mL|官-ʟSx;kms/e %r7׵ޢs sbd]AڋIZiWKX# ѾK V ?V6E4!7CIv!J`j` $VT[ !kk qtCVwR"؄6<P[{"d3u)vI$4gLtrHX)Q!,K!b.*s+ w"h z{#GO&(lPRD!V ۢI#rם05K79dmo-i~[V:;; lUT79^Τi>O|e˖A<#|+l hX!}5 DuuV\.\d2eYA"FGGIRwAHeXE2l0 jݻCݍ-ZkFGGytuurYgzj,b (ʜvi_{%7<3|b֭(t:}ܼBq/ߋ}9l}^ ޾,>f>"v8^|Ho<tS5*MQ/o=1dz+x/s7l4M3sj}}į#  C`׎GI)vuX3běVu cкn`h@8*K €(xG%~4~bD/ٵ{?wN*򔼐4N,pK<Qz!We5|vAYaX%Qc;9$" BT +$!d&a ew1jt4Q$p=N L2F1+?6n /f?07-PM*_ >'dEL<9C:yAǘפRё5Z-&&&D)Igg'L˲} _೟j+|3G;_t۶ƲNz!t#$ah\d.BGcCP-5-TKs)e02>)H$MUMyrÇP$ɔMOH՗N!kd,gnFrxiŤnt!js"ffk=ۚ|EL`tZ#18pc {ET#TJeХtbR9p<Y:9̡]Ie;!K i[2˘gj4O=؁ݘ8t)e6J.X®wQ?S1\diajt=;v12y#}2|"9<:#ӈ1S,[>Lg)Nqxl$ʶI!',B5,i)Xd=@ڎ{Posk&r$R)Kw86lexv}`f6̹1BLJ\9TNVSs">;>G߮Lϣ5-fk,T5fh)~mxf>M1k%oED(D۳9&*s)Íd'p<"Z4($ c?FňIe[KaD| j&m2q~1䝻̼s};n.ڝO~16K~ <x5V `%r~{/}?# A1P.~.]?LLLefo>1:L"woR__iLNN!^z)v*>>'Lr9kx衇x;IWW7wT*2yBofeo\.thyꩧWnÇ/N:t:gAGGG*X|Y4an:|INH)y_wŏcV^M:-o!|Gz׻5'NMMqaN?teQH+2&6d6^]pC8xvЌM$jZ5_ڈL!$ºG'0 -4KVR;;D"I²d,?Fǧp=,^ɣ2p&W$LS̑r,<ϥbT:I'Ą.*d#V":[>l; Ig.˒>143O!AhRLY=,[p!V8TBcbwT~5҉P>eMDn hXZk:;;@JTZctH=}8ݘ}?hgܸ26xܚ/Bi1̗} aV!Il$bF.k[0Ppו> F4/p"m<7@\B h!m׼s~lkЎ@z"0(R$Pvpi°%mh L 5w/'G1z $Š΍4U|6F86HKP LdYT)'V&} @~h}֞^/nmAp!@ρ[(R-F2]R]H̯>\p! uVV^=+yرSO=kyjk1m=zt#G8t?{T*qwqo/}'ػw;wy{ٱ#:bHDV'd5k֐JX|9[Gì_)%ox?{<1\.֬Y7-<øu]z{{DƶG)\'|N"+V,gΧ9x [no;va卣%==$)ǪUPJ188vz,,{y[IFēlvH$"XizO__6p "Lr),U_4ځߟo?k[巀x0IzN7s-/f礗bEhD2wMC1ω^4"۲yֿvkG4ŽοA/f/A?Ӑ[~3L*e9QV(^ِ͚(ϨR_|ᔍIOK"E,|Hܭ:k2pt}#[ L )A@GAG#!80+5t~ ʁ eI>ΪUp:{.h/~%W& C6m:{n#߲eKЇgÆ LOO3::RjFq.Rz{{~{( eqa,bǎyĘJ2TOLL~z4ZkfsٳQ/c xrxHȼDzT#b#|`_oo/}}}<_lڴ/~&|'j56l;QP[:~7~o||_CzJRr1۶qR³8\f{[DB?`bb'xY}ظ٦Ybi^EE^6|!ڕ߈G}rkv"ZͱUU{h403ʚ1>iij~!АȤ9|s9I~ <,[2HHϥIRܷL¢.8iWctt%j@|$\5jПD&tsk.Z-'ЊnapǑ2$I;FDRR<~16znJAP8D;ϮSL֦:>}KH:QDIͦTBj>ssi۬K[3Y[9ѐ3=ρ2Ԛf-9~i\uچjٕ$$Յf3݈֬cLafR"%\ʖ[5RڠG $S`%Q2),Ur#(d3I40p;fAw@ (ؑAZFkvڍF3I2hbC-l,mK:ۛ## q1F򗁽v1U1L={;$#3Fctgw pB:ZBe+,Cjp@>?< CCC-#:Oww7!K.ebb2ޅQȏ9~@ݻwcRP-V}}}LMM155}ݻm1ԭS?e'"^?6Q< ||Kk3'X[vQ~w[\g6Qڙ]|-6D06s] .."%j&F9tR6|UkG Zu _Jjn V"S2[>tdOH$ؼy3K,ᦛnhVdY `޽RW]uT0 (ʜtYYu8B~lzz׭=c9 X2<֑V#_==\pX0 yy衇9}auB.]Ʈ]p .\.8<#Mo²,֮]K2{<JN;׭|kUկ~{3DPh8 MӬYo|[<,_)%W\q7p#7| {{_W]uU# \!BD%|+׿>Ǽ322·}+]tqe: IDAThIm9mZ%q~!Dth@DFHAc kPHB1!#e1!Η8a%JJA$lP( HRKF絥`JlPR eR(Be-l([!DۊƎPVWF篅ؖRb6* C(D) +؄~﹇ P(+e!3W-lR!#:R}񵔑0/Mī#G`m0Z#}`R`LC#b08rdk4B` 5f64F<7\z%˗xnufdNfIBU2R#CGh?7ilmda24nhaT+.cݿeEr*٤a4l|@6#N`tdm[[oZ)S"eO1fla`/0 v,Eʶc@CQʨB*/Y$RH{{9WD ^6:׆۲lEOww DjǪIK]͒%eJّge<,&c /\ff?7~i.m]G L @=oB:Kmc `h1٢菻-XMѱM!]"5E(xi#\q;`L:) /]JD"DRQj˱Q>F tHXRD B[P(-2)a ~bt<ԂThёq5PHJd:EhB>3MBeKl)`_喎_-? j7`oZ<.NBHUZ@zV[Oosi5³}'N\&ɴL%rqBk͓Onѣ~mg/ DdNٵk\ZWU9r3үg6LBN7OvBFs Nڸ_u}-Ƅ g֕JG%w%HX|ZjyY~}dRiR N",,eaaْAj p1,V !f\ϒ@:tt3n*2LR ぅe'$q L.-p}ME& T=4 wC*J֟9Ϙc"4m^m5.D/\9Vx1mEU(f4)3[cHYsտNxaBgg[I5,D? }~|0 |F}>xia9) ,MN8:{ٷ`,]6$EzD6ЄڐEbs4"5TTt=Q@Z6Qh!L`[6v*MBkr,Db1G!qvj &T3Hxk~0Z>Gš sLNH0069IJe @)(RtSAt鲋DzI'$hNhQ1: ;M xqQwrhuKp,˜m1/x."aHVcϞ= o` %5y5#8pZ g?9k֬azzG;x"rT*g^~m4z r˗x{T*qmsST7ɷ-֬Yc=Ɲw~=ZkM\_:}kxի._Izzz2]v}-J)_#C>%N366`ٲe\s5|sc=TA2dٲe wYfc~9g R!sEk)8w_my睸͛x/\֭[OP  @)ٳk׶aɒaOׯ3>>Ɔ ($Itvvr3NgddnN:$zzzRyltsmۜz|Sdrr۶I-u^)>aIN>\2(;2q, [ XV2Hi!%=l}^N)|/V&< cGwF̹^\'!V$I<?{8 |rIB$1*%g"cX8L lX0;<;G>U"0UD:Vy&P~sQ*r)'amSpl`\Q]ݤz(ZONF"o_PVs ,:B2ji`HW$ ʥ .!ٺ^|YNtXɤk.Jd04|9ߐcgK;^\֧sQs2f[D& , 95u})%Ba "|'Ǐ"HDZdOw ; OVa4&Z6Q&Q;008@2_&(3&r1$6}]E:2)8TBII6_$+`,+}i' hc|gƬ[I:ò#AcmXtHǶ(l6q,EOmn z&x]ifԨ+ | DkUX g a(A?WZ}6`fYL}Q*-n$,5I?*.7_9e֜XI BzBJ*OŝIȆX)eҩ ^el随HF^I tH?zrI|p?4tG;$ZXqAi/2Ub@>"CLIVEsVD1XswhMcؿwcǎػ!- .V>GMQ좐MЙOÓ5RcLt uI3uR UG8ah8:VcӑIQNL!$0AH&مxFZE A@Ҳ*rLCT8J^i4+-5ӿ 'k t2.|Z]x+^Ono+W!+o+Vя~~d2>1s>t{l6˹羂\wu}ٔJezzYntzVe2}d2I>mo{]v7ڜ1|_eɒaZ~hׇm(xk_\QҺ%>Q۶hBŎmJ)r\%r5|iC ZSՁڜRRyKRĞEÄyltD&EڶMNgXbL";2 ,ܿ_԰6PPG7yPoؒD\g5" =˱$ޛGunt pW!Y,jsl˙b{<|acos^Dg4mI٢"[,s $ڍ޻z?u@T޻Wۭ[}[HP`-nTqAcjc_?#?Rəϳpae*v횦5IVWWA>sfgyыo1Rϭ2#q1 ,,BGD=VS8vRÇ M?HV{j@ hm\Ϧ>on?(k;w}3-0[w~\п?l] ` L2 c-2YOֱHGP̪OQ'8^ 2"1F+Q"ݵ%@c $$TQ}^iS3795ho/+en `BBqvMP( Lu"/e;c{r ^5f,.Mvћ6y?d\g 10}HLhj3y@,a6>Dzϥoҧϴrh`p/VVHVjxpR`16AҠasA(E;4;]zX$S p1"T+$[+rƺ%|n`}x|9vq;(h %5I?x `R\)8v;BHdYD:OX7/s"NO,46%^ҥ)$K+y.R0nHIP򭛌`\(\#wg+w-YпP@)5 ,y[ޒJ&=z[o!cccy&7͹ ѣ?7ވ:u2x9r$ yjʭފ:wuxG"`dc:(W?<pR?e"N~O'' @h %IV6'ei\csIf^?{D#Љ5.(1y:M ΅UP'^ 8PA]EpÑwJ+K,/' B:6APdr^8{n8E/x>t3g89 (h]4Xpi=Zk+$I0Z1R,追#q@Þߣ?{_@BlPȅsk GF Fv]7ZR R* r1 ayq+Oow< 4cS̢bVYS 4RJiLNN~~!Fl|n=2;'Ǚk0.[Q''(Y$;$`pTZE#&;u-Zѧȅ״S鵍ٹ(-Ǡ4 + JE \GpٓLNNPUHA D*:Q xc^X)}(8(:Ҩٳ{7V lfeemڵ8 C̮i$fݣRjbN~ǎ=$ IDAT^jJ-D(ͅY;;{sOslf+k5<~b1LԓOYj֢Z+۷&0BȲ,|l|@/>&g8wn$Qu]&vq9:ty)G1(Ry^ƞEVW.f+) J'}BP \sog=ˡ)&5Kbli:ҰٿD*EQHE0L!H4R#5ʸ^BiPI8Ijc0 WTbj]b& %`=_kM(bXm,n3ik)5X6֊$UfrА(M'֚3M*~iiB z>BHVZ\XZP,R)\ EBϳ1 Kk RwqbNp=wvzh*2A@c]r).;{39E}YmYS(U..>5߶qm&N7ro 6tGYTYˀl6M1Zo0[ۆ ^_mK>~}vP1$V R:iKm vYdh\$a,>On;b~m +牍‰ Zj"(^lӁ"QZGc@9eiٹIњ" q"cxFF醬w\Өz۳"9' uof<,;ض[r|{jN8QJ>q/5.!{~Gy$Wq{qsi.{e~~9nᆁ,3Ϸc8w###e>kkӂƘ"Bsۜ>{vob9h7vGX^]9 EdL8E aHgVsB8hYov˶{Ćgffz8rUɗaBM{Ǚ9VWy/aeap Ѹ4Ȧw=Sx,[E2Va 5Jiy1כ%Ju,zZZ=$h頄$҆N7fn~W5 JXOsTecfz''>A$Q,6utM e40D{.܂k,3L6|֕]6f# h=ٓ126Ǝ](ߥ:6•3\s 1oK_±i2]0Jֽ1(EclmynN(EOƊť5t+E 6*;&bz;̷|nǟ>GQhVٹ Dwxl d,ٽo Xablz5lP ͘,o]}0ƘaO0fCgis.:> Rϧ}̱cǸ;+892;QR|_'o;ǎ=Χ?io$I8u~y[XXXĉg=+l`T0T#z8t H0R3165W_tKKJ5 nS `ӓH_ߗFcD!LjlibÊàpMD 4h#) 3h$H"cx<ƎI''h` RSh!YkO8<;}ݻw2W$V0ޙ]8Dc$$>Iץ\F11>IQgiz 5nj{=h;jx#=(2Ţ8rveau'֊JIUJf/P,qEo4@ MF%%O/i/\y-][k7JJh٧+=Q﹌6j]њL]1E$,7*K%HaK{N`|DЌLhT<\4jщ1*׋ط:X^k<%?t Ki{l0>Tp'9uߗRvh=D?,E0YtIhT-/-_MJbz5V/„k$q'IJD *I,$DIR1qFkE[SRelPOc?\G.Q.}GJJtڰ-6j 璠xT\m,6 I(fL(R 4ZH$hI"2d07Ƥ@I?؁jc[ݡrޯB%F07c7ƦSs2 }T_crرcO4o\<3]E/z|cttYRZm.ZkϏȏM;V\ll$qR\p'|u8Uzv@I=-%ed }9mAp/byd2~P,0>=Na#B⮤^ ڏ36#U\HI^׋8Am1Y4s \$Pv Tx ƚKpIhT2'^)JA\HM\z\15IR(S*;u:x{M~~auo%B`Bp uijǏ?zS d$B8HyE\C)]to\>wG*/x Vv-V !l\2sK3G@VbrZ!.JKS#ćX|r\ yp$y #жY^Cزw^r\s$)7`i(\S{T pHQ'UiQڰ9yubѧ\.&bD ɕW>՚ѴwO;Ft HEkÄ1( v 2uS\&3 ^Q <g'l\xE &z<+ d:V$IN@V\.&ws_4~]!(C:'`$b֮m_|~ⱸ< Ɛ.b귳ț^x}6ы 9xp{6Uk#F6Oa3l]}>EJӈa czQDDQL'$ I" "ZY3̏of!uMq]bP.tlh"#;GѥǗn@0]y_S^L Dj",cAd^Ab4-W[d =}>fcϯڀ6Raͪ> "2}n[ *0vgpΩmZ!lTvIarJ/pvᮻbbb=V0 ?o<'>?iDqQ~~{KLD 2R3ϱp8'Op')*\)qȏ5bߑr/&w((% H%7Hh\phwQ {ve}ɾqJ%|;p*rBhgSphطϷXZ  \kqBk,㇁JDP1}م,@\+/VgG?tкM+IfE]SSأ%eLleMj}Ğ_j*&X9Hyd9co7m̄ڳa_o޳hUΗonEЀKˋ=۾1fC0!Mn,>-׶G74[mW8KeG7QtmZ͖MQnf#q&$eN-5Sl{V!|1ĉ܋ .Rj~`94R9ϱkf ed@Xfpߘ/̓Ɇ4<0X6J4sq+aU_K dnR*ZVufT*P! :Z.q]NbjjT*tvċ_bg$ gΜ3 'NAӡ0>>6Z>ɿaqq_*n{7x#Ο?ϯٳgٹs'K___Rp7)֔eN>#<q>z!xߏ1翩X ҧAbcoGgN~a^cVq\C^̉۹ R,Vp}d/nJ Yd;eµ$QWLq[tr|'M!&;͕ reamA4Ln1b *0B'8C?=STH -DDb56CX@& j'I^$N-z$ Z[>m a1R.BLdyF[@ZH&cۥS?5k-886_F\?!XbDDU%7!`LdAR,6O1;(Jp\J4B B"asJW> fNߧaojVf" ȳeuX2ݝbMi!RCP,(YʁfSR+VX@qD^Xt2H魬G1*}dg_/"DjFYZeыQ8Oras,/QԾ!O==Ǎ4F(H݄Z8.RtCͅ.NB[Hu0,ϜWA౼֣ b"-h%GV`%ĎG"lC+(fjPV!WNЋc_XF-T(YY[)TQhQfV".q[9355+II؀46L˯ ӡ xc=nZ]elЙ05>G \M_ɠ l`< r&y{y-K~ 6e q(L8ʪꬓ^Xee~U @!N-Yk la.|4j{\_8Q8AS2EC:e16J Eϧ[b'_7R¦,z;iPp5G~r3A!֓_Uj/iOͯ0^R-z8bps(7B(Zk/j5ѣ8{9{\]wEP C~a>e}}n׽ur}_ܹ,,,vy'y[‰'xG(J_}J¿;~;IO|y9BZeϞݼٳ|#~-}no~3ry~J=ǏQ'>&?l+_w,..gnx\u|fmmq<3;;˯9s,y衇뙜OWUdnǜ:u}QZ.a7_e}j5Oo^;y_Nx:t7r9տoÜ={6#r-w}ԧ~#N3g5xǘUz"BH>/x?Ǵk0V"D9HT )qIP%I%V %$~"(SYxSKmh=,R"іpKq]FР6Ҙ\ * 6ˆ6eSZ=Bƚ2k*VҺl+UMmϽTFA JcPis[+ SGB xgؘ0هŠmJIFF-j lk0~ψ1)jRz67쿞` BF{D+.̟ѱ Jh ]-ɷ> o>?SR# /2 Cd e> IDATGD ڢ;(ҽ@S() ~Ags`$lHYGֽ&mccƺJg d;Y3 l gMZ1GP@*x-VZ؎*ZS`a طLG…ڣ(x6C㺬U T+Eڭ.<8|:(QJ%b$pm7͖FjѥR.P(yё=T*9.QB4buKъ8Αq| C 0{D)Ô>łRgE*ӐW&n<. mtftd@-7i+5ȗEgm\e(@p zZr)unHD eK_&̳4ϧ :1J"=IXa*Ha/)IBhTfwL1cV%A@qaqu@8TKEFke2B'E6z_t ƨͼ"΂cd>ӷA {6@G4[mJHڝϓ8C't:]~@X|2koNoJ{+/ E<_8do6lJmFK nE)s=;wX__cyyoV?ժq§>Br]wq_w~wq_2w}7_g>KP`޽?<|^q7[>!y{u{-_(O? 'N{<\w6B__czzOOӾ[n~-xR _җ8z6(i6[ꪫx^O=ug~~Z6wy'K(ػw/W\q8i%c 2y/4<=vICh*̂'()iް[N~ #ilOcCcpu): p);B&Jct̆8J{.a{iKx6M@&Hӣ8R"1A* ߥۋbeE M3D*n=F W8B%1*j3Yt#zXyV;G%T;'QHV; GSOX,p}8Ym8;9 -ZݘFHchG6+hN5)3m374R-?e߆͋_7[BƆl}nCUp.T)/&olz-xq7߮[oG6=wa98dl6b`\\ږuG?bY>$s3$JTH1NvGݣՉF5K4TQԩL4ZIY Es}8XKTE"zZLXH7΋;d)3*,2 Df 3923gp4y^;wZ->wg*ɱcc Zcqmk%nzo{8pJc]( [;NΜ9Cayy__kᦛnsh7?Gew j _"7t|!஻^>9|!幵F9rRDXDJJm 7܀yq|Ck_<fzz$I8z(gvݗO~cq'8|0RaFdnnY?޽W`]JjVVV;(8CTt]4#+#cwqsw}7wu{-o|/Q.rN WgUMx<{s"bU|?Ћ@%kf!96wtMtP6(*"!Pxk!%aPR#t7r"d6bC $RMa ci\*rBVHXI:ggQ /(9Sln=&_F9`61YF+ڀ!$&]yAK6n:p :DKnns<@t#N:poYfx1+Hi%qIS@nE# |ο@fbTd H`,hll2wSHRBVEH@k"d76Lw$.kY>\6L)%itԡRb=\@եq,.ԄU>&QDgmviu0IT'O\2QGi k(ujec5bLr8snf3|"asL[|vyv%f4PL6LNbVO.ij+rē_{z5&.[ `WOy ]Z̎[ 5U=$gPf?Ǟ㫏aʼn5gt&0Brx47^71&Λ;iF``@S!hbNqxKbCl@ۉm*3gZR_ i]3Ȧoi ~[(l/i^ e}ŊVE/,s9?;G+M"| $ʳ JYN$ZUVIjQS C I!u%bj@1< &b&d8a;$-[O;"kR` .\M7yfRDÙ8H)8x G\uٹ{=4ë<]ߔ3&aRTrAlHEt/xZM(̈́˧/*0>_.wĩ}kf~~b5;nGK^r|$I]wصkqh?ý{ z'xxֻw0115\4M/311W_w榛nhSJΝez)*N/})V .I8uԀp.drr%>rqΞ=RAT8tllr;RgϞ<8i^6RpgsRhG|ϳa'?I>O0;;nE]҆DQDVMq(˄a &<Z++>(?0>{x7X^ow [6˖yh:x%:Ih5WhUr Wa|t7;wca &]ND)H-]Qom QvIug Zc1 W+$ZZa\4 `a`FMݚ) i2cJX j IV1/ LLn )gH۾00 BdAViPPnD q}#$Қ0KG;TJ%8p2> Hc,Nס5wb'91`zG ƟqDZОފˎ}RkL:ZQ 4yU?[oC H߾O?80` ȍ s3c6t(\q`\R7mH!Mzu\GJ=B脨#TdNsV "Vh;wԸ ǞYb3Cn-f hTj"-]++͎DRcX Ġj:Z;)ZaB/R4>hGQL O㹒ݣuF*EJWL06VvJÓ;J@!p88=j"`%,H.ofY\̛QiU7 iCv2!F l?@q1HO@$o?~ߜN ÆrYf* 0 F*fXo`(ވcRc oӾl`6y>(fiř!eGP,z>BX2Z[ F$tL#Lh`tSќ_u5IFHǕ$ZqjsWYiOfLT+cň#-FF< YNV(af$H)u]7{x[C=?A>pqnT[I_3f{YsA0~gdtMJ+jl߶ZPG c\=k- 3mBk_"0Iƙsgi׉ K|kIL0Ynur@:W$q|d"tI O:ޢ^e(QT"jB`E+0iHI@uQhSAF<]Tyܹ$R2~#}VE "1IJ?N=>p%fb'Ox^24Fj4KDuΏ0?z='ٶC,/)t&*hNy~ !>/]vPG(CH\QISPU,5x-|2)w,s,syo֐jvBm&QNcnaF)U;]#mBCnݓWAj7C+fg9+ytᘞZ+۫  zt xB#y |ιf<7_6WNs^=j: kmjlI`7(n~Lf/OF߰m/&oFh_Uk>Rj)Vگ>V@\kG5#O1w&ōܱIDQNl1cNd [(ٲPL3H4+1j B DI!s@ayfuQJbu $$4t}4hf[xZGd)%r/τijQ_斲Lk gVVE٤6R:䥴(| )x?Q,H^ni!DvI!h$e}FH)ˊ3SS41B13bC[Xft Jf Ŭn6/|Zƻ.sw'xɟ@J锁]ՁNG?ơCWxE8MZFfe,t7IBWVc߾}|䦛^6ٍ w!%o;}xq>,X]]+y,,,jɓ'ʪ+u }gqqcǎ1Yɺ'hy:~$ː^iuog~~oZ{8t課$vW_}׾ݻ[o/|P#JΌ{n<$Dl"TIbΝ] ssXCIuT`uzȍ7l-ZXRd1bŏڽo|]Ps۷_j=|سw?++h. 8}ϯ O~)ܹlFz2;g5Iy~o}FD1E><G>c &FgI cUȎ;zm<# (/`y*֦ 6d@SSS-,rYUw9OmˆC}VҺe}% U}; % 0 ln̩H6\W͔tJOu_#y/Y$}:$eOXzN70VE:AaX'C<,3$&_XlYYJU 2\ +KtG$VԵ#*"nƿs2/K߄3FˢKWmN3վa"R Fph'82~2_Vo$lǰZeIƆxTf*g]d7 $b[@Sùo]'V91='_:d&)Q}yY!Ԣ!,Yrat z묷X(q (0dSQ…Hc/jTY԰a FkMe}$L$( b#i塼\傡^Rjݟ;V.L|EPs7eai\"Zs}AXs|,"*czz?g87~õW++Aࡇfcvuř3g<5oW1~%p|oA;yHZc=~~~n1ӧO{n bke9ZpLuN8,w}7kkk/[IO};w o濲r 4ӭESD+Adl/wGc~|=zY8yԧ8pO?Oddyy,KY^ ٩:A}1::27b~n+{m &:C()C4#Qޤ9Ӥn`mJr [1BF{ XYw;{a1qPﻁ6zn3~!MpۍF ĀVHS&)+'uj{WtiS+9:v}} [)~k+Kt3hStU!:V=vWWΗ[&Ʈ+oKݢb]3jy“(r:EnzkXę`8۩l#X@g~ŰQG}:o-E!DJ?q{'%S JI.2 P1ig)&)_8v-a]Yby?O#^YN2p5U#e{z>w4E̎E굡!{.+lXK;v1K [.?3 b!:N++a/򋞤\DIԪP0PԘ˙Q]HEr9)Gŕq28,PjOkRaR*d*P} $ #T!?U|SGᕯc-Bρ8vopW5|#n;3caٟ}||C |7^{~5f׮]?~c,K[ߺߠ^E./jK_R~oANxm۶׾;w;;q^)s޽??E 0 y;ӧ/>e~~WyWHV/הRj5ZLַ{w__,fd,b%i\UD待'Hql3ϐ,yc- :zc(䩳\8sgMDtnkefvTsax|.X`{ǕJ<;AHtq́E#O<MVT@Zd!՚{H5V;Haqބ;02FY˷Zu@CgIY__Ϥ_x%ZmxM io@*-,!$$5.Dj */q+%9q|uhXb&I\8i35]1H)Hy"1`R51!"ւxF`W9/=05Q:4wHg;ݤdCq֩sؓYM_#k+gIH ia~ډ̐jKj YQ3Z_f(ϗHZhvn^?H- h6\uZTCy/ G)K ^QL@ 8oSR?P|;>+g+w"1r.{ۿ,D0U,(?fA nc(M e`ஒI2fse/~9Jb'4m/1mFFD,>QLJ!DI=@GϗϹ[ :$Ż #I}I棶jDN՘jjDQ#+.֫Y$iZ&I$)n`0V!a}vh6$IVUX__'20Va媫bii<~{)E0@ϟlOIR*]^\ P+܌) R Gby./Hq!&;sGB(h6DQĎ;xƇ>9~x0i3xl255E!啯Ço~ɟ -o>Uyȗei7qGi6[yM7Ĺs{x񋿟0 w׽k-~ۈ뮻۷EW_}Ozf?{a=Ν;i__*7tSSbϾ}x{}ǣ>M7ġC&MS~~OV /x x׾59rÇcUfa(∛ތ;_z; 7=OmP|H y& c KX]m^ Oy!By=3W_M g,ֲZhXo֙۵5Ejq2HDn=e$&n6jL-NX4.wE]xAk2 iAH=vEإE 1vજdsSXf'@bm^VV>p$}6N" MR$MeՑH!GBuWp`eFj,-cmgϯc1b=IP9ؿu$_SO?Fm᭟z^"%Cz`"E!Í*q9ƚg w'?vWo80!=~c40!>6A⛮_Q*M]-"> 9:'7hdHz>Bӌ4Ӹ0^OM4Qo+VU)~@+O_<_.*<"ͷ f0훼I~ᎉ#ͅTA1!?ґJxI FT:jΌ ՊZf.NNx>H҉ DHPKk .RXvh\mkYfR2_`/fGDQ(\1Q'B87{tHJEHXO*~Wc'u,qV!عs\~-w/SA <~zb# #n(fc>i^}Pȝs=۷__`qqkfYy_Ύ|c[y_ΓO>Q/#Gwfɑ#G/4_ W]uaҗCqVt,..Ry{"w׿;w, LA&^y bY =[K! &^%,m x27`Ɍ{!{Ï!? ?4 0Hi训ҘvIpY^^ ,[{m=, ) sm kpu4=$cyf/<qw?OyU޾#" Hc4X+*X/rx&+ .Qgp>U"sdjY0x(8!czLt<vRpY 9YUc֤YƏ(!$Y&\#g =S4>$D^2MMy6c%]/Ar65GU"7Sg+[$gEf!zm䕜 #%ulb1yQ\<"0.$p 8nqk["\o{ p'K@OFDGP(rO^At}wq.fZ*L ı)<_E.CN ЪK%ho~sXmܜ V;~l8o~4Ykt: z# \gnu%a!zի l۶^;ڔ5\}믿}$ V+WFK^/o>0\uӼ/FJɱcwpQ>Μ9wm۶m۶}Ϗc*)nҸ$:vQh)X\؁ӧN6ک=̎{ط{/%xjs*Qk,܁\>~9cw;֐]0=W,V=Abug:-bU-^Ez.1Yd!K9]qa&h (<%12ֻd4C Vo _6_\#z%O6fHw7s)9k6j;mQn墒osQM [^y;kÖN Ҍe󢸺x'oyg(VƴʿS RTǑ#Ww=XH116pLm,Y?E KCBH!"3>"lp8x>gz?cKӷ}V#E˞Pº-J ::E%]hRJFxs٠gs?8ZZKPJRnVTitR_(1Yx!PidгB+keBrtX-&7ɷa77G*7UAr _@,Z:Zn-"Zkɕty(]5yvc5q/wp KfYƠe 'h5% 7C'k ]8A*+BX}xYF=>cALh‹ %\i,hyV19;y,jxAn*(l62E7\J2&0}?݆Sx}DQTx) cGN>ֺ*Jy94D7^!oxxի^{7`@)MٳgS{0s6ۑc+mKz'A%o[M7iBv4d$:.ހWPjHQR玨`#~C&渰XaE;vs _҅|aYtQQðQKUf&G/:#F.HY=7%QH!pVYOK#aK ܻg~%$_$Ӝ[jLz/vcX9"VD)J~cYh<7^%b;wUpGʌ%3y9)=SGad)8!SP1fرsOO~Su UGg~v|?$ `mix0*cn1UH<-2l.Yj]8NGg^!Am(iGM[>ΌgϞ-Y'>a&)M)QRl0qW }뭽h ͨlH6KwMMa⒄j4pny1}$)207@}0l`Y] )<{=S(>kT=l!K~84 "M/&p]`-wѨEW #~dlԙ O 6l\3+"w5 R vA^=Plh5:҅tWϹfDd%^p{cS m.Lb HR˸tW IK[G|Si deU*~e'ItJ$@p\|QdwĿQF?5Hʼna(Θ)RXѬR`M>PD?ܿbqcߖ@b :k%6uH+Yva+Q"h) ;kC =4kQcl1=7Kot+64Ud)/MɍJF2AZ"Iʙu׻rd~“W }ۦXt1vbNYbtmSuίvXL7BZ>'QBy(`[zwof$<rzC`!hBBERMX,_BPJ4Y qK\Vf :7L;/,b| /P“B?n|5Rgԥ&e z!4{݆'3 6GC A"tqڐfP4vѰY7ChPLmǹ+))d "Neya EĚL[zAesaJrH%6ylyntBW{Fx )<3FM6n˶ +Nt}U32m83>^:CjSK~%R&.9LW cf%<NP?)I{~Z#rίvy gW9cm g; ֺ1;Mqné m1[D*7=}Z^s+`B. /GYJ-neD~Г! cfB$v:%.Bc!˜#B z7ԙWVIi0,񅧆K>;4#A-HOJ>T3.r'ɲI=rAa):62- ZLF RRdp8+7+:碭_fXccJ^N#-SfȶTKD<ὓFnm>&}OBmUa]L |EpB+U,ևh}~*%RX1]kSk"KPJH_ľ  Q#bff%̓d([|bBX]ms߃rb D"E@`rkQI (C!R-RyKzyJC@b- |$_ D:'X&@4t r1i%SK4-Q*vLWWsE*[K' p߅zTnҕi%VN.,RE]1pCֵ AF *&G@֦ËB9m6;7YvXwܓқ8>ɭ-J@E-osQ}|S_5gJ WQN45}o5h|>s!Z1v4q᪑BI?&ޛQߪ^>4# I,@8 6`I 7{xK~uY_:M|!xxy1c0b51bB i$f=9]Uݧϙ3X$z]OWuuuYtfQo(ǣih̢"rlu/VV0 "<׺[zJĆ%TQHԘbj|f) (U(Uz AܜhCh e]k/dU k`|݅ڀĬ"2C>ѱcqm>Y]lοPy1dvar͢v $1 kCӒwC+~'E3ZRBmqCO1Oh|a4J"Y#4_*jM&'f^klafH-AH mHe#;681Tyy XY:Aӿww̥DZuPVyy/2vʺ IZ !]p`EǺD#@ "B*RM"$`zfe4@$an:~_ :1B$J6!q<,,4;qwNsΉwKv~Bg 3nAЙ5a,$[sn NFi9J@%G2!}TMX,}4M} ē!nQo4==͏~#{1~222۶m?> @J>Y|)w8̈RJ+YbEβAr>gkQks<\xDQZ}td; q9ŹؗO 0Г/8ppSq$%i#Ya\Z^R'#D8HX$@ӞM-m\[$;[8G2Xؿs{=jQU;C\[taH* h J~@xZk '$S3|"x>qCK+C6pM)n. `sfg(<ē9axB_ ¦ǧ`M+)Nep' Nn!=Vk($z~/|J x2@x m,ҝ:DȾW<\O73:-ŜMH+=?&;i17EmRŻ[GSE,˟ s\['#CsoA6"Eyv8sv_"?#6 4H 3uM#Є+K_;z20lPk*̀,I4)Uϳ4DF7. IDAT5Dabr P*vY -b fA4 _B:H頔؀q) EGUI:tL_KmޅgY vÙg=E]4ǪA)E뢵VQ(p]cLEf%J% Qq%*Jϳ0d߾ڵ|r14 BO\WU}Yyw띔4D.cjjZ0R 1033(333a* ֚f###Ŵ]clle˖14b@\exx%K橧"ϳj** z JvZ "Aǟ`%\|>OVcbb8RaR2:322yH)9S ?)j72<b/rxRBEO'X O>f/3(ɱƍh[MVgh#CȺSosFQИ.!\0 ¾3bk'Xa=384H#jk¦HpPHDhOFI.o!i:>b!*c(]zYY#\s ??CZi&>ƺu˿K>Ph 8g 0.D䢐Χw[0MjAQTOPq@ 1RIfDm"LG@(=jKyY#ֿZ:? ]&HDBJCFA{ VkCT {xUHTEGk+qA0 ner[f1H%G~X#NF|vfB@ڂogŊ~i89_j\܏|<8x KW2`7)cm_*{.|+_T*מ˝wIOO%KE?ѿc4qRQqgv=ozi6xM!x׻fU0,_5wq;z;i4vmy睜}T*=| ._2} s _B-b%>ڵk_ 7UVOq 'e]7 >rM7tR{1y..R>o'}/ַ?."پqo~BE^󚭼7M>qYg133î]RpFkjz[o=r9,w9gVk4 j_ C . iJJH(Z(L'%$*nO<.^I`h^?[/*sx._SV9q66Ӳ_mv]tq[bps[hc-:,!B<9~]:oԺ>Wqea1?sE՟'Jlk=oi/PW `rHr/nRXpFN0Q3Dxui@$2e.M0 6*Eʗ2*Cjhaӻ5BkQ֮]Ƕm8S@ q85vmLOOSVyя.c{{/_v.LMMמ˹9V˿SN9%G[ne۶m$nv.~~0 馛ַ\j_[ϡVw)%ZJ)&&&x{><,Z[o3WWٰa| ={pmWOI'ć?p 'x?ٳ}{~k.>yxW~ nJkbɒ!0ƤJ)|/+.Î;ؽ{7jUj!199~rw>aq(x/~7388?]<gy&wq7oG1_Eh M'2Š1uR.^{m r4 `Uo^H Xq߮uHWpp=o@;<`06N-&\'s- БbbG!@Cժtq(9$N7=颟@+PHuoRI)3n1F V=1R !5 2!Fgd4@L ª(.gN$jU<#F0@$QӶeN+c}Hcs8`]g-zEctc CqqL X)Ef,tXyh]?Y@# jcFJle"vs##EZU[9t(-&Bm+ѶI̤Y1K^q)xj6Y &M!DuGDN?F/ɚNZW;ߡg%JfV;E2 R?nEa?Q~FϿhgZlVWoz1lǟLFU1h +&fB9 N5&h OS:R q$|G0Cs+k]W!M'} ҋC5_\ZQۂ;") {G ӣ0!h|ABvZJT*qgPTÐUVwhVזZOf.?so`Ӧ+.Gsq}166FHë~EF"CD" ]ʂ_FL!4iþ)b5v"uvLJБ_eDZaϞ9fT qp|%þ={x},_6q˗{nT&B <‘LMĎYCx'ʔ**T*E %@4;MXu=߽;|`[w K" 2w/WGJf ORUYO7@Hrނps]aȶm3>>΍7ķm}v'O=۷oOLzǪU0ư{nv\WUzi>=Ho`Ϟ=<8ƾ}Yv-ph4xضm'|r #!!d*MNNy== )˥;Yj)s[RJdH:驤|K,I}.4(; 'u]E֯_Z޴mzjy'A)r9B+uK3d'8fH]9OAJH)۞3O'`J!aWnA033'Xs+*m7@c,EG2V)܋FشiW]% S*(˄Fќ3P2TVN&Vǟ]MFo;:Q<4HǦ2Z#˜Ȏmdj GG( Q|D4+Y@ dL %t˒Mm2\Rڵ1F8F"F R9m56Lsɻyʥ" t4I.jQ&=;*NU40}n2JD:$ OoR)"R !z|C/w7%wu.PQ b16^#eVC䊜nBaO>WDȜK. Ԙլ|Z{J1QW`4 ry jKTJ9"F"ș"Gj?>ͳ;v2o7)KV {359@/#Tz9VafP)3_}kXpvg UɡKC~cwb z>V(vQ;ee7L{]~k+&S0=ץ|Icf?&[k푔Շ!u}_OOY]aױi "il $FkzyJywA: R)k*c v\ܜ !ܡgwڍ0s Oz^#N¡xUkb0mBxE `۶m /gj?^xae>gdd={OqG};?Qq7}^Wsyg`ʕ qCf .G.߅7;A=4gi4C{NnY7)HYZ1-@ɖ>h/Q9I Iex)N;fZ/xH jp+&Ƙ|qQD2Q"tHkIa-(R ]S$4Q&%o#%i[]QCzyl/Ij``NbDX NO[~:+ZLgh6..O sbR ƴ74[~]cL/7sfe_Zso5[sw Ӎ<&]FmADHP*< T#M._ as5Jc YrWB,z "E.C>231fB w5~_`)ce7~ c az*p$uhLБFz+D>߉w[{q.?~^{G@l6yg>æMJ>qv$H)9OgժUlx >(fuֱc~Gk92;;_:زe CI֦ IDATޭT3\y啇 ÈtcXx$DdOa||<]$GV]m@2 i4011__jjzzzٻwQ9&x"\!سgO+0s|Zz5Adtt7'&\r W_'> \駟+hvBEvLr= %Gxr=NPbQCӍ:R+lJ% !Z hӑ;-:B2y5+׳wlb.O\ScgA>9x&ʌכVR>nT,%%Iap i 嗸B2IRU,FK4& 9BqpK4 r[01m-r|ЯY-;~hg91HHH3]шRl پZ4/0OOR}jF AuI-]px5?k:1ʟO8M5vN^f5ǭZ3xv.&k3(}~UZkha@&фe2ưI7V'iҊ4Ni#2K *>ΆƘ R ֟zfA!9ЯyM*;1Pb(e'ɺ{(Y,&A`DntJۿ\թgyڵL2B9``eL[Vm7}.h@kA2g,!\tAuV/ 1XV/F&6T=̆Pk**@J*Rz{xMS)Sk'BJ .#$hEoA£Z+MObTq\mu0 Vs&}֘zv"zױ;hEƀq#q+qZt*[Z`$eWнT#Nұ É'@ooo֟ovۛRJ6nȷm˖-3䮻NX,9:<}ݩJ>^ˍ7Ȋ+8ӻ\YyN>dw˚5kÐoN:6;~\e駟Noo_7Vkc#lݺ-j>59믿x38x;3~cwk;8眭Z{w!W^><7_1R|7[lfǎ<Z+Bի;SN!x'?]vQVt @YbŔIcR`|:v? Td_]lmltu%8DDRJqɶp* CP`r&'&hԚOopTd'ʈBiEMh6}rǷmlũHM;5b%6~?03Sh'o-JB:^UN|pf1[yy90==6ں3~~L#"sL#)8JmzJ#h21+}61ieHE"Gd }uA({9|逊lj"@,Fmuff&1٠i.uq~] k?=ݱoQ$<^KOt>m𺮋DXLb8ǥ<|?Ǜf:>яzMŚO)wW rMok_'ƍؼy3֭X,r}Ї>ęg>H\o;|><\Mws$ˇy\OwqӘ#'p"+W'{nV^|~1dm0`D_HƎ/-a6 g](~[X?ɵq7:?C"Bj1z(-JRJzzzRY^7{uQ&A[5R[mXtVxE(rb_$Ų]_=ww ݳtA"[Y.XRDTz=vp"A@0;CšZDDYJ|ǦqSZxRD̀|ъ0 Faȹ4!3*bPeru]q 7g^~O?4㸬_s9-k6loorwy_|B[o\o~3φ p]7R\~" öL+׽ϳ`ǖ-[_W"ŧ>)y/_A.c޽k_xџppUҥKkn`x^?A/_N,]BaJR+.epp.]L*ox,0n:뺬^q_vN=u#O?4zjw000('tR bFFFFr\tEc׿(\s W\q9}}}|ӟ?q<,69npMv]_K,sqQ8,?ua2Oa+,P!Z VQ)8BZe Edm3ӄQHOB_HÒ2T$9}jTq}gl&*|(N$;=3Wa B!mƍO hme]j8sYg͛Wm\rI pgpSc\hS ׿ϺukYiRJ6o̖-[RRTxߟwmhɿ8wy\,-+92ѐmYrl/733CERW'ع4)ku -=ߦFՃ4RS) )p0OޓEXwYbwOQӊjʅ3M_d^aDѰ[LJP$t5 O(fkG'3w}խZHB$!1'6 lal0D&Ž;03a^`cgl&0by%! uKnVKf?N:qV/_~fDݣ~$ӏWǭT~ؔe/UȍMӢj^υ6,E B #qJˈTGvvjh8=U/?/Z=iE۳gOna2+CƘ`٩Wq|+gF_-Do fV}~cHM h.Tj4HlVG/qϑ$Ư R` k,3YH!\O<&R..OYaQGgtfZ$! C* z=WF)uYUNK%P0J5$ !"bw$&" l4rbi?1_ *N<u,wC3.a۶)I>utyLGHDHÙ>SJ?#e`V B* qs7FYg56( fIJI@M̄p8i;s@(+[Hy9(r6oT_+_ҋc$IRZ9眓.tfp;C!]fGEtG‚7DD_D 2zŲi_|P@;4%k"Qn@&0rcbv$I-Z jȏ( m$JXmc/DJօn>&V7ƮK#`{T'&h_=LԎx=c1HPh4PU2b PNЂ8 ~!%$ԶID#\[gIlAaF 6Bzg~x'>nW%LV*xOֱ+<1=SSMza;"R'(j6ƭy}9kItDvEa.t.ʲHXXy&掝FZNB"Zwj=IЬu:^=0FbV$mR X I"4Pʡ?MGl}Ëa?+[+2e[#FϬ3!P=Yy"@0uUF]R{?(cZY\wkzFoښY)=} B.)l)'dJ~9D<33?[p3nyGt|۶m;ֺ^dJB7XVZk666T*Xv]x{=gA 4ȀZK 3x=J:]>l5lNX&Šq$njwQҍzT*<\ XAvD RU EXK[C'-j,5&6j~K{UW;pgݣ tj $OXj?HP=α5PRcDXyU$N7E=J8?[p.TnM]]Z5,[l0wtd1&d ~=&JZ'X?֥"q 6AX1A:!NTs5:;GZaK+[*9E!$pl("1/yB auNCj$6G' QR1+дghcK"J>AcDžܔަP5Dw}Gk=^fX1t@6/ ”AQ\fxu~HπkSYO(X,gGi Dbq,?%Y{r[[,T}O1&韃eZ@IPQy IDAT(|S?r[=p ҏڡ[M~7C֌/ ϳk3^/25e#w(2 {/2byٽ/!b{3Gg1(0ẍ(Jll=OhԨ>6=#%>,sMos>yG}㕯|n2p򤛿sscHR=g= N8,Z>PUkpPe`#\HXಣ*Y EX(eȫFpNBgِ1+I zM5Xn欙9:[^̩u$xV:C# UVW=qC,:FFhb$w{{`ZJk9a#<c5@HNY B;|­HX:R8RuL|k#w&b* zBv"Xi"5M9ގFzs,@ 'X V,XܵIX-gň؅'7>XX$LQo0QkMkzaN; _T0s왹c2R fBfΔWW _(A'@xe~C5,EtE!2 V q8PL5&U6O`z ׿$/(poBaoE*"G>W͎ygd4w%$)LnZ(p去ةn3 14\awP.F}'E=yGez! ħ_1oLQhN#6RάGF1yqW\y{ [dRQ( JNn,PvFLV/8wh(r猠|WIC!qs=AMDym*LO4Y]^FxabqBae/Y%1#ĝ5l԰Vz3HBngn|c!ʀR{'tt"0Ø IRA I"b??ہ %C̳1*Ɂ#hmE=rX#I⮻{Rlauu;#^iG#=C-zo23scjcؿV|Kկ~׽uxWUfypښ;c2x p2HQ7ϋ&ݩZh!HZ&beVik64&4<&!dA|7ʂ!D j LHs:Vܮ]!0@--VIHA '?Ӟ zVbFc 6z4LQ¤; HS>Z2X vHm9B(['?c&pbօ% )¸XNtm$ KSzݢ,ϛo{*Wj T ƐFEE4' #|gR1ZY!5!ѱAxhDG]0Ư( ~"'GBJ1kT*s#Nz}oS BK3%<[c 5eLZrEő=ƅm0) Ic,(1cF9+&&TSfa*[~H ZL8q!t땶8} fIɓm9O}f:h7j~&cCĦlzyyvMLMMQHM< LLL8fccnG78jV4ku#sxa9Á&Jyvz˱fCK:B+ꄞ%6 LIZT*o­"N2 tV: !ŨP]xwH_VQ6B5:,tSދLn eOABEmAPW:2n&`OE<#o?ù2|n3|((_C]Ng\̱K:ONTy$|[ʔ JO)/' +Cq u~Tzafn/dǖI\bjjv' ߺc'WRaWUqqj*V&0FP Sn4NLmSz4߲n m2+k` Z$1-:f"Z/Rcm~+&'h`6]gcX?R8p{=4 ~~<9|/&Giʯ <>9 Z?AN^2oO~Sy5\36F|_V .8Zm`p]ws3;;ϳo^;7RK/A) s>|;wo8NسgW^Y]][ocϞ=۷ sCl6ϥ^@8pk-'N`u }|UUgJa?ݰ!Id /&F9!h j*uBëpZ LǏ-1R) cdnD׏sUwݟW?qiBq>O-Fe(9`6dނsLE]UJ02畮|Τ !Zu rƖ2^^ےJ_n(mD]3@d ;K2mR4كP,,36cmQR`SIۧr^+e9CͥAds%eS1n4}D.Ё̦ hPZl̮<>ɇ"Пi^E۾b~q(QL˙Om1H;q>)hZs cC_~?7#ߟRӳJ@۱B QKѠ9=K'̀ c s3S1b[fj ozϧr|;o|#Oh4|__ys=?Tlj'x}k}g^y 7 o}[?38˿K~./ⱒ℔'20p]wٙ>H1hm(gQL :}$#ZBihVrriFF{4eYs.撜c$kQώ8wo W!׾a" MFTcl;! WSE i&j03Ѩi|U|a\xW;e‚o6I7bm#;ac?XK܅"۬Q ܎nn"\e: .7=X; Wh' ==;n(g+Wqa8b$GmJz a`b8M?sg})bkaamiLfԃ#0H_.Ӟ}<w=k qX"JGgm Dx XcPOF4*:ad<°A01Aguɩ F a,.m@1լҜhMؽk]h-8rtE8 ECVH&%&X vQ $jYZdjpgm ?wj$}O$޽xӛ)%~?w>9#}cwo⢋k_Z*O-|%s//{:.?_"}s>Ad޽t:]׼LZOغu oxH~\wubO%\v3ᵯ} W^y%z+xӞƳ}u~ EAV&V$Iķm9ݻ瞻t:hٽl.rJ򒗼9(&}k_n&seq5<o{|?> ;%\ӕ@eٱq@Dq4)6lG$ UH؄c6F偵AùH;i%29k' DX?JbV"WЬ"嬭rOI:'AlMnY-%& +aEftzll F9p||L'?G"Qvɞ/Z嗲ۙڑ[Ftw<-bF?в M-] ,XXWh| x} :a FaH% CVyh48q”l7QO]lB߿7*TΌ>cf5L齁:[A]wDHzg}6_s6- !Ϝx`& f bѣc>LJ^Lz$'R!4$ZDc OJCyjxMR_%-$;}xы^ĶmؽnFc]5[O>fggغu+Gro^z>\tE<\uU4 * {W^| _ȑ#yI͞-1/i} ";n:=NAt2xKHQF!ۧgsY*.솎F) *8tOYKfJB`ZS\D).@++Υhշl QD`rSB#5iq4IfW-ffNrqKVi}Š/;X2$:Ғ蘓ǏR;u]x\r)XcN=9Lg=҂[d` x5SMO(El &Tk :;{^ĞFw4B^ P4kuBZ,DX/| LUv()KxZpr@"qLamm]g =_}ٺɣ)} IDATh9=z-UXse=WS %A~C<&8QK(NYLBP!&#" rhxtF?>9G |Yj#FX&c9- |MP%hv@ <1S % c#65["*Y!ĉ"g=Qb:&w28OdJ;?;X[[$yTR)زe RJ `ϞsGseeܙ4y5?@$w07z"Z-5wy߿>|;3F۷m<|>OsAA9XkY^^afffggT*ϋ^Kq|byyo)wʙw}8N;ZO|2i!9~|VkchL4w}7hyhq<y^vg^;w9[z9d KY]AV,|h}_ l~ܮS=E1HEc񍤪'fA-rBXV! 9/~Jvۧػ~e_މHS e4V*D;,3Ǻ(L}f&<]\/o$NzF8zo`LfDť(ָ9Sծd: ,[V(dk54-9xgW?S ce;}S #\Zgku#q4+iY:=F6b|`;Ph+-R+YTDxhF]͎xni?;*Qd>w79t !n><  7j][GȟےҗP}=? ½7oij:FmȌ_ ?OarC>5>,{Su+-JfGyy$i՟~A?ڂt5~"8D~p{~hR`} Lƛ߹0(8&ݘzvIpG?g ]kFD FbJ쵏tH.Z6rM|L(?4f=E{Qt{nlaB@athc'0NrR}B+Ư4Z>%cX[[_\|ż/lwo(W{ZJHHv>{MK{h4ڵ/&7Z ؾ}A 5~$43-^ 1lqb>2̳ f A1(О̨ AC`\!$Xb7vBfzzml۶á~<ʟc߸雨{Ǧb$.Dn*PRghwWI'Z$OHkP.:Kr~L_Ke'&9rdȒLAdg3Pcrw$}>)'B6ǏЃՆٹ RgkX]^YY$m&<͎m3Zɹv:>|s[8kV:T+zJXJN[df;w!nP7KTUYg͹i9uvgǖi%n=^=f=@JA;!֖[23TFz」hi0n}r]Y*ϓbI)V|KpmLwz*dž6K.oI͕HFПI@G;}!T-Nc!1m1.z*w>΁lٲ4Q R١M!@c  e c ZgGnlyFQҭFDh*yDJ-)t"NaA~d͂Ȣ(@wEXiЊzB|Sh2 qNL )u 80/%?7623M'"$km B,e_P$HI#DV#=$.1x""ĺcF:u P# Vt Xw2DbԤQOFyEEnZYNblNP=w 7C8!Qc}1M ^|o9pQQV,tgx3v7tvZH >Er 7|bjjO~\r3p- rرk-V~;t\ȹbnn:W5 T*|-!җgsh|N8A檫bffv͡C'Y6B."nnTwyeA?waȵ׾]v1Ї9]l27@ I]?)SG v . .43\~;5Kg pQ@7b{lm6H=rv*$gyЗA 60i$'-~%0-xǨaZ"WH[EBP:J | JIa3YtF4֕T~FXqS.g% +Aٮ0^@Q4\P -pf̛YYP K tPjN D<)H ' ORF)mY,Q f*Ҏ&GE_XDݧZsB LT-̹o[&sb?M+~tWi`eێ)pj68ւd̀x(`\sdw;j(Dy2juD;0-x*SO?OJsTU0H1~P3@_\$FGMٴ@{=BA=?Z?}?g ng}ZR_ =yF_G䂮/vu`v,,ʝRK/+=uٿVKy _Ȼw4u>/WzNZRqjj Wwq='I|ߧٟ۶s5|f֚~c\qw|P!!s뭷ru 1㢔brr v._?S*ʀo̯2?яػw@VT恐Y о=ha-#>aR)}d0kN(5 4dI[-yfvPdz +I,//HwmX+`"_vfCA-={B?K^0ό&wڕ$sws<',w94>EE/1?H,Ǔj? k;7 i#؊p1'C?J?lH5?Z<ڭ6E0C͵5H)\4+ h)#pI()"1255N[̐0N^Jj^"4_hwiPYbUK4c=6BJkbfy`lO/XV8}7H6{x6R*|嫔JE>RQ"ή]2 iT ^Z7M^ݻA|oM>sp%xk^CR/9BO}DQč7썸ժ\z饉ۿͭwٳ?O}Xk/} )+-BW'Oc G\Rי_`rrR88p믿_pylnn2;;W\?97_z>Oo v뮻nbԩR*8t GKyh={`o?w( T*iWJQVӝH_K w ntAZ/O'R, 1ľ~UD!AMD[ H>ЁȵAyevNM#ģSLW1^$',[pqɘpfyc~f ML9ץdH~-02VJ.~8,%"dbĎ9 Ybx613)8zI-: bBC cXt(# UyGS7((o@">7bE<2&{:5NujH Ӯ6EpZ:Sae{ҹ=HO!}_ )IXE]p]RXؠnQmx$i4.#!%RMK$<_KrfM< + LK82!5lMu]8)'@lb9BЉr`cccoT+lJ)ɟI^8B!;'!SSSʯ2FZJ^ʼk9rQ155=k18[6j}3Lo~ ÐGy1fff2!۶)7s 7={011RK.9ğRV"v?9RM7(B~~9۷o^ᵯyǸK].1__e/i؟Ͽp!GaկTJ8i;dm'I{/ò恋(arGwē< ^aن6IGH-8XPl3 Ra@ 9UBp\V7 C[P  ձq\))Q`(r@h m+-F#b!Tv>'#,qo7G B)mk>,#RoAE% PP& DRSP'pE5ľ*"0& @}edbRkl_C nEpg`'FCx]Daͥ9{ ,Q̗PV&7dl{ЄzFKFv |9 C;<G\Ξ={h>QuEf{hNJ)`nh&RJfggq0 3S;k-&i-r=D9%OHEiЊH[+qJ;rls#""6=R" &t%I v!+u@ ل1炌8fBZ2t;ܴ2BĚ V_ IDATfə3g_W1][j5Ӭ4\nzAu :e9oMyױ077oDAJ8'N"'K?iskٹ'mM?;bsnԿE{R$/k&@ dlW޿!')w=6^hs jOrPOTo3NsVw] iR@šc+ }nП<}v:?-VmbVjxRlvuJt\V&F)!o.[ 5ZG,391NѢRPA099 IcF?Y,Q3$4VWR5b,/}vvgbyd?8CVV<9jl @^Ϯ+2^ݻeSSS199Rb׽1.첾 1m=ˀ!sgf.v:j;wdvv6<82]s5DQyu8uTcҧ;t -ҵ[ _bPFOAA݀$!lfAGq.J(%PA0Vb& <)#,k4֬7r0{LL`mh5[,7ZȺhG0D`8"`ak8A JabpA8Mb+XT᫗KL0_ (@J0Br(-%^r(\ "m#>KȘR (h$ "kѫRsJ8(d"I!¢H`bB<ǥVb]\E*TqYbA:\HD'eY@(LR%{!`ovqر8YDx_?uZkN<Zq kVi}?#A #R J: hodC<~aufggپ};jbHE1b,JJ 4Pr6͏%>,ԬO.ߍ\|$REkq屹56 *=O4g:rnq&Ǯrs+;ofA`W{=SFgNC`;Õol?:9*yAt&`g؜ِ:Fl?w8ÐJ B'&'Z&RH|z5FQXc(6J"XaiiZr& L洱$&xܿmr0u5AQUpZ!./dVR*$\=ڷwt^/}/)%e"4K>/tao1Ld]2z,:2ԏF/hѡ7~pNT  &! 5ϑ X]_MĎaTԏA/) Tj%/c=Pl[AD+r uDbo0Uj0] taĤ]@VgU R+j, ħѩV$!V! :{Ƣ-\$pW!'q(Jqěլcm&GqJ"h`\1%b!@HY ZDd$Th:4Ia-68[(p*>R#mQBa\O"U,Ii0" -JfZ(Ȅo|vөI67X^^iZh,,,y}fzHO)a nFѠ\.S &BJ&<r2ՌѶHOTJ(67i>U^3k([rXwd)t(a[SinޘRfkv&[E[W(s᾽>x h4#V46܂bsfYkYX\geII(ll{'8}8m+(lE,-ohD<*d=;(MmJS>BcmIJڧD@ 'p] 'W|m;sŬ6BE*NyG$Zǧ@`>:6EE<O "~W(P((˔e}QLOO#jqb ɂCxl*A>tmEkmmc+,,SF"2j!+Vh-0R-066uF)Io()vPH*&kkkA/QKB5aZUH m3ⴹrSDFSv49z[Z.+L,`dr?DϊeS(V<+ VO =rT P,Vٽs+k+5ARLT:"l0Rb u D~ g$+2b}ZDv̉Rl۶5VWW9R,P-]*U2?Xk&~ƳOLszI(eanm8%cSl=Pt%F`:لbZ-,,,dxק-,oړό0E}OoL@XiH`]tn ]z9mꝢ^QI\w݂۟gz,{dw|T۞}>v{;h=I3=}/#Wn |癵`"B (ZTet&hM0xҢ %ٻ}*>!'qD^&"Oc5kk) % 6Q ,&> BYZR*֣kmϜ>?@o5iy{K^=ogF~g~n3(GToh4(ra z[V7m>6it^'Ò: iΛ[]fvیdxn-TCcnLPbz?am(  nҠęE.q lDa }ˬ}O8&ķ>@-bM9Xc1E,P*)*X k`3rRnAj7QR4E;f5BϢ!777ZSպ5Ӥ@IMTEln(Z u)T*b.-طo_&@GF v+&=K Z)AYeNOb/O R2qhXcQÅ>UlRcƑK/Z:IDXh\{:0&_\)㱳niHJ)%m V`bj _#H#lhڜ9=G195DHE5߇[ƆmUIFTer3R4>~?KZ-677QJgJ2Vf'\d1~^ n#ԚEJ>OgfnƧfCC񅗱W(5V)\ʵ:mFF(V&,<۟qS!Z0$(M 2 >VCxէS ^{G~&?YzD*A>UGW}f@ߟwO]R143 A]NZۤsliS²6G{qc r4=qzpTȷI;GÐv@V~C>t$G<}TO{b3j(!hZ(WxydS/ Q~ *`\EJHS+]*T5+vM>xJ<Di_Z"<:ށ@Y06?l0wOYIO?lTBt %=_h`GeqqYlgu}?_GzfoرZNXOZk>}??y^Pllld\^1R(>vI=vKRR(0&lc21߿v6?y8ۛ?כgP?z`BnRqjbBN@X\7MLu\\'޿ZHE'@ĠNƈ΋ MHd @kMm|gzzZF^֕OJRɱ>9S#eX%txJd8w~&P%#je(J%bITڕ٠wz6臞,_;5>sN| M&oBl8kqtӏppcf&(:Fﯓ޾tЏ|2HW .$9A=eVgnsD&& F?l?l6w-΁TBӻo ~MDզOݦ<G&Jrgq+bH)b -?Q29{5;y/VJ [Z!|BVkt u B)@&Jn6/ S؄L9mu?yƴB,nfGs׍F10::uh4c bB(gՋbSJOS= C "uA\mPtĵOٔ3?O]|~v9pL7sO+++:u(1& fmVOEZh\,U.8ϥ sPaJhQFRTx]렬@Dڈ2V)7611L =g]C D8|K` hk 2i#6^I8m LFǚFذmڑGu~;0g 쏠ǩƩ9pJh@XHE]C:Bs%qc"rbV#w6cS"VK6s]4ԶM;{R`6t wz9 ooI۔^1y/{?a u~߭{SY *cX9A~6M{1N8!jsXe1={2{GImvM u1dI Q wgLϧsϼ'?;6H21밼Ztt7$md¸[(|_΁%}De:鳶g΍^` H_]&3is͠[IwڡHl|m۶d>CT*?m돊nYYYajj u1ư8J0qr'd||<3xWb'pf9tL:( 2H0 i6!:\uUalR"LLY ?gu2Ǐ>('O]>HMN44|͚)[Gԟ{v& c1$R`!B"2σߏ!/{ٵ|_]]Te5ူ>%Hi@J&Z±!.P\xN=feef6#m~RHs LEVjh0)RoH1T,sHFS+z\x}4ZmpcDt͵6V񩼐/DD\UbJ1IU)`l02HF@*iEaA̎{("J haij-EAy(qsU$('@bgRHMlr$ 6C߁2 IDAThBk"B#tmJ0 oWPfJq+@e6I<  e *7?ai5pH ܤJvO۪mQonم|z=%}0+[]Α>/>SUFv =}~؇ځ#z[=ySfJ6^t:u慟b!5}hsS~LvMϵw{Gx7>Yzz03[տ}wEtت{3'+#VlH`rH[ ̭c[VXo<2[xPR"Kd-R (%Q*Jr)>iwȁs+ޓd]ȍ{Ggl9ݛצ|c:~zFÓM>r ^Cq-py/3z׻W{OTWi||`׮A>yξ}>·>!15̵׾ǏK:J"|z-<ʇ?aa~~;n۩T*\s5=>=\/crr;ؽ{/| ?CXj/3۷W .c F/WΝ;y/~ՔJo9 xwW_́: c6667ӧ9tALV=QqEe!e)-̙3DQk\ CHO|ﳼ87w|hl dGBrBF k/߻ gO6 M P\0HB xͫ~K.|?xai]EcBXY E  E$|aS{e-B !#x;Y_ y씡a0UWB8uʰgˋ?V $xp'S!B"iШ9Uݠ! & Z>񏳶[9sf[o+|>]<_y^ s]w122‘#Gۿ[>/p5נxp7O++~{c;/\|s=|`ǎ\~&677?|'N "ow\r%q?~7MXkym}J%6ڹsjZ{x{ZM>oorwc]z/}Y[[uwq_җ0p]a M?QiN}fK<bX|3ydvE(y%%]^U&M#]Ed]Zbl.&-o`exКDC]MK:9#gU!!$4FDVVW;_>ɕ/;ƀLFk8# V,h6hꞱM1\Yyop*xtXllX$p@#j@[~xH0EccscV(m/rfNpa).b?2("UK a:Md!#cZa"$)RIe #+B@Mc-X R׏dƟ>Adk,۷o35,\/R DXQ*Za䁊fR*sPEanfGIj0y^#-3LrHTX,fBxT5z^|H~o 'i^0~u/]4tL{ sJ{S=B?,cq?- bL4yPyBΤ 8:V{H irt?r̖/toMqoMKMvFZdjӘAR.OO~&jFk~>;<1[^:lB}߃<}+>2Y okDrC[nwӛ1V(7&q]PRRt7 KJ9Vao @\|S@G!AJ5V76VcdanJcrf;ssX<%Q rf+JhV{#7k,#n(X$`ɺQH> :9OhOÒ֬y㌍Q.y[~(X]]yϻqR/? c-oy GS>̮]LOOsa˘䳟,ss|T*O}? HA)m0_Cih: 0ӓ4u^CK DS.u &ZK4c L(E¡! XFa #ZĦmZF(ah>6 ?} rm;;F>zUf#NlrT{w%n+ S& 6xab3 _K %#FhR?h̩S6^S-uZ,ZgZcccYThLVRJ|ߧT*ep`ZkwO]9fW]?צ>P9j[tR:tƿps.^u IG8䝺r\[NEepLTt`҆tͫXѧ@~|z;Ҥ9׭y( 2AaB"[R.'0Ui1(HXXK\Z* J(A#4W$Z[1qVc0 -6 c`tr]'nϞzV+y]t> ZkzXD$tQr N>,..reXkK_w{iZA 8 j3$ 6V+ > ""XbNb,3X]_8r:AITdjSH9ou fD6t2?Aa6"ejS~ =p~N󘞞@oM{  ( Q1 XXXȜ59s!1ǎhdZ"ϳHlݺ3Mn:'Nlf1vMLLL|>}G<^x!ƘLezzLǥv̓>H$H)9y$mƞ={2QEGpǕ[0:sLDQ۳?5SJc, I Av=4ԺTi1 )m/Ph9s+?_BgS7B=`Epr]=x90 UaS~!8z#F&AjyGjyo01ƞHUY^ gL)395 -,,(*y8OU-o}-³_!r0)ϧ +0I JĄp0@k2+X9L ?nAaXjI' $&f(_`0R2u.kD|D~EDbaHb Jzą0 /^ ykS,ll 2>?/ޱ}f߾KB)Yò})s<ƶ=˿Kj0;{k^ñc;3< |L81R${_~'=]«^*nfv5MOOekd'RNlS;wnUJBPKZDHxos}ff+y衇w Ð!quV>Lرcz=j!]vYvh4JL֚Ǐțپ};\Ǿt&N>IR2Z^9\_TͫrZ{|m?T;HfiVԼ&CBGx+EK2\8Ŕ0đfid@"' Mz&:7&svO6!ZA*Kŀ9\ߦmceR !EyZc B A(4h3:4 &WH <  <q^gmH+yS$D'5 F io)@h. -x43$"{x*fd)e9Dc eD ۬1SMjRbrV!r mk2*Pg'&&@&'mpX*jZf2W5kptzz: MҁP;raG9 uN˝Jqm}{l6袋JiZl:f%`A'SazLMMe'&&2MQS'j8 iSTȀ )%kkk;NMMerL3drr2tСgbbVqquNw ~QײQJ1==]2\f(GKKKc袋FUP:QēAVrf|qGSlkA>[Jt6O4П x7</JBx͑OmrnqL4W72r ctĵm~} ʍJ@P]#; '1GT ]i(jWuavK}\*2o&PuC ҉BkwBxyS7DkLbYuֶͫ5<6>=ٳ,Axz oϲ<뒐Ui\yw9r^ok PJjOCYo6FZ_Qe3jf'Dou$#=_"`('mN˵;KKK<~.i)1~>pӟm_|1x}}o~.?rsy\qŁ$غuar=cּ=W_+_J8a׮4 Ⱦ}䪫#C."Zw zNd~~Çsq|gDQ}}1E{OOٿ?7x#??1pwfv go~+}񒗼}Cw}bob~~pBfiii$Lj1U' !N !iޥ0 ysstN`ǽ[u,&G3jR cTCՕYSTLn\m~@MI_k MlOGHyR蘙~})IG,`m5MH5$~  n s[.`u(lDzFǫxCĚS#I R' }[{]9thkպOv!Q~^ BA#$ ַFBFG^ $LpFQ) l^$(- #HD1p#+hY]y5B od:"W(R[\ N2 k73# yJ; q՜ }8k=я[F, >XpFy~NC>5 Gm5wf r-vw寂#Q(laͬ-3BұjDHJ_{&SȳL(QgB'Uߣ4cސ~d4.U7Kvyͦ}nH%Jܷ06<=zjq_%a?#\r%|-{WA)YwPRU LMMh4h4-oᓟ$M$\wLOOs\}U:t(Zr }u6>djw&|?Ao>v>1 LMYw7%\p8رcd\}/|np#|K_ /dyy;khyH-5>O׾(뮻2qi3ߏRg?jx?~۷׿~߈C4}51y??٨uX9RH#@C A"e@K h!bDžu a5|iO8*6/Y'~od4Xzu_˕63^GO2`ČﰒL_r@ G6N_ʆ2oR }I097s_n lT6oEdYVF! 5M39D bamM8xWanŲ&t8:aw;{-@y^@sj QH*L.d6܂RL5~#Тt-&c8SvZ 5{d*dٍ9`K5m㧑RƿQ8'Xm?) C<-fffx ^@b==ȝwމ֚nzW^y?7ַSy^ ןA)ŻNj?S?G>s).nz^155E^~7}{yӛތ1/nV_~~W} .ŻT4Ov[nϸ뮻H}l6ٲe ???a=J oxsss4L%KW~,--߱wޱc3N e}nF;~{{pz½_t07*\ӟ4}k}:(Ũ'vFїF]GúZ bF*o9ZuCED@yx jd0hBW>ۓ!; 5+<[teiR>Ha!Q o FK0_7f&ZbOR`R?8 :!燄NX]weﮝ gVhw{~d3d ^Ak8bfvvot3њ^cjDaP$ H!Q2u58W0޹xT|oe{X8ݮZ]{x$,+=8p`կ~u5^RA1/Ͼ5/xMt]>sewN?#<,<Fn:_|q)4޽{O?կ~8ꪫ袋}k!sUW[5 1==̓>M7\dU ge~~4M^ry{^f,`zznfggɟcޯr <رaǎwNj5R Ð0 9x9r-|ooa޽HiAznܝzAgOm  G~~>m/2516zSS#pO g;NQK%䧏]K' KɐЗWÏ]i>v}l X=9'h%YחAzQ$&A&C:%Z|v5?tJr GWb\3x14 1O]w(:}kV541&.0npa" n0)DVNt1j7`&bLjNBTz‚.RCNP к.H>Zx TsXkhȢ d,X@((7; ÐiR8qnFq[S֙8s.{-4(-{^RNSt(Smƕ ϕr;Ɓ7ç!T1UzzF9SLy#'v+vx~,Xɨ<=-+ד7#>y.>/℁N/K\-Fo6A)큎 \ޕ"yһIZ%z1S:ͣ3gEz72HFFҏh(d;˙^Gߧ2;;yY,lWhit]mFVI"RPI!DQL$x^ޟKߺ;1G=TlACv*RZ)ӑ$d+3:!Ԗs1\b>T:F$BoڶBE'R.عS g@it]z>{N0 !SHēz$"oc)}Q-Ϣ&ԑKHGFڼ<՚@*[Ȥ@'l')¢!T6O52@^;dMR h`34CUV Phmk iWDƩBYOGzK_JE C:qtkN$cVWW1.ܵ9tiVVVv=^hg+lNQ[]Wֻ_@R.:qeWiy0K.@ӧOs}qsl֓?(W7#yҏ9|rO_}7IoƼ۸9蟀鹸lUq&epuOyүS؈wקۍ7Bdmh-OU8gqK"]$nEQv<4OkR3gΔN,{Vsum!ޠO #.~M}BȐH5D <|áդF$LMM(%F,"u|$B R B)IC~5Il(6 Q#Xkwh6[H4nԐ&F~EB=YXY (I1ІUI>:i5W0QQR de1)Y ʩSj\q<p}y{p\y\rLLLo& o>G _Q#Vh>UqEVAw-K 4 Izvlgzr!& tb ęYc!{4uVWIA+Ù-ȴKDUɂfbz:SqkH%YZcsX 7n.>q]]:vX,oRt-Н$Bj,V"!Zxz9$aaa)(fyy Z f}[nEkApq b3wPL*;Ӏzς `׮]رGԩSYܪjګ_jw0;;iu]Zt/ƿY|(*X>lYR Q% һ=ۿ}vLW4*pӮ67cXr/w~Q?ʃ2T lDӸIݫ~L>rY"]k6Ԇ44X{N,;@J@#$&4#xdBx:˔IgƛדL|܊ҵv:>z.H {Pd~f;.` RݛF2)hQr5N;ԭD:ASoURV?R  pHaU.8q.kU>1N~3-Rm IDAT/1N~;\>L,>KNh_ĺ}31nw1'O>rHf'6r^Z'aH T8N*&1㿤''}'u2]صkv.i>i.ls~֭0 'cΜ9C\o*&''ٹcW]yAZ?sc֒|8;vXz6ҏ,˻=W4eySΛ+_q|<)Fg§PUQPx%a\}p;ğЏ6XI]c[/?j#.s?_/UQjφʝ,8tPFAغ{r~VڈyUpuc";JEbhT2D*EQG `Ri.ݻ /RS0"|w~RO|N!:Î^bbL5i]C>X31Q[{s:&1/ }-Bv?٨3\[qL'Hc"  趗hnc0Jh4hBU2(Q ! OE_0&;v}2:7=?h,s9E<.4j  ;vl/9't԰8\s5\}lV[9>O㏥~yR<9E/#5yӛ5\s͆'Of*jj;u}rl: WylˏҗքJcΒDcBx>O(DYt9L51P >K j-MBۻ&OI{k?_.dByF |Щ@t.VKeNQ6,ylZx;/?a(t0Ja nB) ctqWr>Hѧ,ZtI2J- %`dI c;ŅPlׁ3.21^WsIjD WGy5O:>0}Ay PD'{8s Ck!qg.}Xs$h'ps?<6)+j9S4_+ky;ɅNknNe ܧP>;z;oZQp8}Giv~W  xr>H)`l.z)|_yx=;8p.ۖbϓ;_/zI/)O o%{/d?jPD^L# |S'Lz3TءeAU_'>6Efqi=\ ^ ÒsNݮ vEu7mBwm^[8]xVZulፋ;"{AiZt;]|ߣl O'ܾ HyDH0J 56 >рPx“u8 RyX'92+$R FCQ$tL1wV@@P+ S`$BdSq>~C?,"eb l(s*V ]E^c`SN^|S޽lToR277m[VVVVhZjߩTk^ȇ|t,a+h,fy.ӗSl R`Ck 'g1:aLj5@Kkb$H4N7ٳ=5XeYF4fFh!aA/rзmxROšxX͈l/4^*{MDZ16i\˸i?l4: z0~Nq/6c~ZB938"m6_*0LkUd)/`_Ȇrad=T0).H}edLɍš ݇K2\xA8 9 H۶̰:dbj#a!Z5 (% ΜvbvӚ &"1qBFr 9ˎqcK; :LlxhvAkvuټ E3 x5o봸:,@v]^@S-:mXıkt/@<TQek3hR^Δܐ.\x!qԸw3==~Vs;~ږ rMa{W*Ts=7)-d/|q^_bҥBދe:h%򓮅ig$w_fk BdD H!iqs*KwS<B >V̱s)2 4,*KKKh4$ISX*"qF CF8[:k5NI0q1 ]4z`I~[߮ O"+ lNu4_:pX 2I0BQpa=젽0ᰍn/cs;.%ܶcH9D_:D#Dz 2C0!H3M0]2`24# BdàSAÍkwRAiMR "g#"0k0m2$ D OFX@#W p r8Jbl[ie0$H&(".B 9j@DJbAaa3t1 Ƥϡ>ԅZ9AO#I`ngoLLLT8N- bmmH?2DV]&gIQ6ߗ7֧ϵ3 +9+G^fYC?jlWO\Z-1V%q8ՌqLX^A@y,JJw@O(7 B>]*{_.5$ۻR`3P ߺ,ק;Km+Y[ދ/cPBns>wg+-TӤ2|wny߯r)j#)8O(%K "31@)4v\O@~D1qh4%퍪^.9G?ϩ~-g|B$`1z/_6|ϧUv ï#<٘dfv2=)rZҪg bdH&IE:G){h ƞܹvɓ'kkk}:Ng3$&Y^3YHCj@r29QBm~nl5QR[@y qJb-[)Ҭ =LB<>~)6QaUv!=jM0}DF)tqUͿ6a(+& !2n,o[~bZ=mx&Nç?i>t>>}|'w̙nFZЇ>"۶mԩSڵ`WUn_ΩSWʃ>Hn`Ϟ=O31}3\bELQʿ_S*&*ǯՔ!eB*IQ=xny_,C3hi>O$k+=V{pB]C%1Ho Jzx[BFjHX|Փ-# <6o{(Y\R,XVoNkHW=*F & &^ NKuta XX/XvߴIҚhDH R1Z^*cMnפ\ˆ;J3)jYRg"j(6k$i"(/7/=38~NSM3ҼƤ1N:tqLNoR;[jrbQ JX6|tm1V tj%uIc Dsɥ?q{.v[:VRȴTڭӾ6(O:nX;>)Tyy ˜|Њ%wܽMW?½MW4&z~Ӛ~gk?Br]({Ѝ](6 ]ӗW=Ei(j pko7b.-xG瀮a ju-#=f1IR j::BZ{ 4t:K$lDƺ< ³N?%)՚㔢?0FZ&(z]0p3?d;9Ѥ*mX^f_Ѫ(OuD IAC%D 4(ϣIF kX h>f )Nһ':=Ł]޺b54b, z=1nnxRE_}WQ젼r3>|( UU[bs[ҳSZVitQ(qh" =o=DQT}ӄR;pGƼ!nVC,gHt]>o\88}-88,.ޒg5F3ԚO!i6iHoHd<4lMejz o-{ %&{i6ԛqjؐ/x != VK$tgbbcE;dkA]~Vq4f3\Bez돲e'>j;n/} ]w=??_b|$| wq?k^mo_@t ^ѻ> d+3zEF$=3,4a%$IE#gb,;Yb[ޛKUeku7{)Ri$J5H-ch<ǀ䁭11ccy$fl 5G$(Q)Rl]յdUͼK,?8q̮n|'NϷt\~`1y Ճ/~_aAhy{—ynVD 9@!Cےb|8 )AR;/GQ?h`sB pW;`-D JX'R2C*JrĂr%CJ$8  M)pVUq%m  hb }P;:֨4]FXBT%ΛENW_]{p4:Ghuݵmhk1"\jz &q['ͬ6bm3)Ծ~%|Qi6W-ŏo3CoC)yds ͻ`8\ wtKۆqÿlĹ}^}72/ xu)r*_}_}s.Zۢ9qj^hO\sm`}V/\/,w$ý*oG/^6:r 7G[?撋c5"Ze{M-:ǟHB8w=\ehA82ɤ:w%Ò`<_|='+ Z,>}߾99_Ȯ"J>@VWTVzC([/KL+dvFh Rk!:9+,ZڷaMW-#~_(K[OD(%pa5'U*9:'*JIő"׆ m-8͑ZPXA^0̈dsJìp$1,6?"MS6)̦Gpm֑soPz]֨^6Cn/NZpƔlAhׂrm^{P~}ggC=}=7¯@Gq[.׺DM^[޷ :9.w\^DIIiO=jdeG!э=|c/_ƙ9XDY_ȧ\{rPNѿt/`,dK|wQz0)PNb DiDɜKWRGgtRƈġqsz!NVX PtTQX\ €|w[hJDWViɒEu>Y_8&[ g{k z^n{4hB▁u@6cv4K4OhYj뢬\sVVuϢGt;crKo^v{{w} _^CuF xu {Ld|וzJIl7o|saʒҔ|_fwoej%z5ˊZ_1bC'~hX/vv_o6=@_. xW&V.s*}kᎎ/_|FxG.ƦDgQ/|{@U IDATV<]^iWkh n"X̯/~k_o)%yY.S1(/$Q-:-nmV}<\gf6IK 5p} JW%vBuD3ԿSO9&)ɧ??YX[.Ϊ6~xxJ)4GYxW9 fx3z3)/R*1|O,(LВmme96(V([-1sZ?Qxy+$~BG~%,J$8 邵]̵#!QM4_?e6SdJiJ"bk]`wKP8K^\~L䲺[TC(WP}Uk@Y8'(ph=$%R5C0XPl1AQN4*y"/CnF^9fzDMA~4t`YvA^Rr[zWPkpjAan▱spI*iK FKg" T_N՞{ןK 4*p<샐b񹫜6"bڍwMHRl([{Ȇ|q>w5#9>Os@IG1:PJREY"?:j1%EQ&O*[&|^њgi F  {pµZڠs%gous<$Dz "0\¶Ŕv/[-ُK[/+ Ir. *@nh?}Ni_[k5%gJq/ze4Pٕ={_A)ɶD֢sz-XS!v[tUmmJnmsm9^ofp_,nW_+\SH:ܧRʺI.TJIE> fE9nx__(=,N_ŏ^8/(0}Hj|iqK!ΐX)OM(%֊N'II; J'1!/2,CG4M:B%}s( C 0WM\s~\-?4R)LE5 M Yki=]oٯ~{"Nߗ1 ܶjS M N&}Y4VVÙfm +~,"@(ns~1ϐ4EL/@GI{WnAPqJ.[{#ʲtkE +ئ. u}Zanmj|rl~ ic׿G Ů<EkLi1 Ɩ(SmWB]-Oa'x[xp9OQw|~ֹ0N 4V!<1yN2cu`wW0y)˒$IPJq>ystt۷1ư'^x & __qڵB6779:*=@L ^Ae)-I,'cB4a'm >gG{:erwd3nl#ΈNS1(6cDs'~W_΍I#%Cʃfʽ[ SrsQ"2t3 R%)B^EVB'@| 8^jb/́swQH{ejc܇}J~@y1*&+,:}W8` -Zꚲ,?2.e3yxG՞Wg-5r#ZZ ZZ9  U9VXOO2FiPsX郷 )QZ/XhWQn/o+ F6e` t1eZLfRZlzmv^f3^ýs̺`6n!Fw0&&X^Ks Lsȕdd&}=6noGΈYVpww$n7!Ib ", 8GJ) IJa%2/,3=BZh$MgY69J!&4( |焅n(KKQz M}y^*8yg$4a|tql6pmv:^vtc'" 5[|h{5'm oA8[àR"9͈>Ky.>s; )WQESJ*>O9+QJu\ >+nI4(K'ME/(b-# l/ >'>ewmc܇:(iJWFkR5:V$?PZ)˺<) Li0YGQ~GiJli*ZOT,甦| ^>A8wkoaUp}<)%Xk?8?(lnn1ԧ>͛7BpF=gҗĵkWJq%}'xxE|3HOg/Z:ȿg(εscB,y=zyU[W@J/̏QG^fB1*gd{(SK AˬR$)+qfN~ Q\z[/*xs c;8`)y?@)vD2F !<CAlj*U9C#_1Z5zNߧNڸ;mܠPR~x3=n` 8>MF]=0_t)ڼXgm㽱tjۉf!a=Pi?Ta%+X \k.)'BX&%$ٿwč =~%clmmQ4٢$>l2^?:has!4>ٜN"Š(y#%eqM4Vp|3"b`G\oL\ "b%p(bJv4"c9$ޠIzHbt7tDQd:xSX42HQIvx:!{|^*KdSX#AA9l|:%(`H0DE ӌiVƒ ek#%t{DqB x|_|_Opxxȹs爪(˗/#?#oWϓen#ų'Pz)|w;3!y@W8IWl}?()4%eig!Y>hw? zvn Ey1IHN!aqx@&;{#]^(sDݔ;l Q:XTCzNG& OJz/G'3 p%Mp{]V os*8v/ZH$sVW1</ؿmM);Vb\RkJ:X(}Zb [ڜK.3-a+t[^ HXydI/`GӡTd ɋ9K6#:9C3q;!/՗CmCy׳&_{nG}2g1HrB+ M/` R\,h4DuZ+De@M:m#jZ G Jz Ԉ{P4NalAIعpPHbt=C9uلሹ֤*g\XryQ+7##W@'cx+ۺFjSha_.{FU% [k"_ Frs•w_}-S;Wι*Ny B$9,T6p-jp{W7/O my:}.]/ `scս sle0Sϡ# #/K Sb(&;ezal>gzt.1B VDQT-X awxY0/ tKj.e:頼,ڼVۊgp;8?(_H**q_&)$Ӂ ._I8k/tF~s/| 'xn4*ƈv xٗA@z+Xc,eS9B dY?l ^eA6R1g'f?`7=!2Y7'tQ tZ߾MZkN<)??X$|??+>տ/\//?(Vx;@=n-mZFF_m݌}!Êso=l" -ћDa_Kߏ`L.ra.5"\bTsZAQ.xd5ýsdyK3ȊL͑es#qFxOZ$i3D\{>~CY ]R^"ڂq{8?Fsy}L9rXUO(骼a\ARt>Q&GwU~/V߉oo) Q\2 GPM( 9G㌢d3+'9BPcX@8!;Q'P) =5)-{BOFC;Cg,t;hLou/)=>B#E.1qĠzqquLbnc6+׹KJpy#H ,/[0r SR U$ -ol>e>BU[i_ ?đ&4Z+tZSGa|HI";u(ĩ"T;0aO&'Sʼ Iz=seY6V\Br﷦/@ha~u1dyxp3o'_”eԄ}˞6mFJY]3Vu%09CNu D2m9xRrRB_~{J_^~w }޷߃(ܼM Nc3˯߸Ew.j<'qTaw^_fA߯>B"c |dmJ;J᭠@mTZNs}`5eZPOBlypv (ھV('gtFPj{eCov(ϧ IDATC2µwj]3xjFTE1|,s 8FDcthipDa!s/N"H I$)Xc}iF 9}y:JV:Ⲗ_^mu@ ÓSՊOxU8g%@jisa?;Y( <񮈲T_gVu[ }SW&=\|bFoX!Zü<֌ud Vp}Wm[B\1U-UA 8ۛLLR>r~whcD$\P`#8&YѴ`|n&Q[o8w5k$ZpJ}ly*)һ:)o}sDwܠ ..]ʲd%tJj8D"7eY~_@ԏ'55׺yt~W'UUSրXW8QW{}9/}}Xb: .~OjqXp;UZ̨a r[/"j.vm0Å"jەZ术nww6IT WU"yY1G]2}bB˒^O@]yXԅ:)t!DQ5U2;rY-K2hi*F"2)Ya)|3:NIY W DjB63ZG' C KCQ:V8$0?P,,#--y<ˑJ1 EApsƢ#M_Z)IP{G`ASR,CXKA ˬdFvS8"DI'(E)Ji+㊂.詒%⃯һ8N]FܱXP,WT MsW y7~OzUo+EmpUutoh\E(Mv?}7AHjKlGqCi_'xVt:]zOgEA?,  vR)8yt!K'sGܺ}ã [[#'N>}MQ JbiֹsX)#xr izuVs|h*.%QQfLi8Mk_>CסythZWʾwuZ{5L$w vaB7 DU-e??3z'S;e/%9k/{'Tt`n0EuON~-ZJ*`mWDŠ1D)]CdbQ|TyG!dL9ˉMD\<4Y|o]__hX|kd'qA+{˗ܻ h+(`πnK9AV*-D8f-/wut_`L")l20K(9,qU$Ivt:)L&Ο? FC1ldfrR3'3&SUG1 z>*)CLi31dL؊sₑƊdY(E B dYɝ{foo]8;߭jGv2Bsklۃ?Vvn[VxN5N[XoSC)THrO?F}]mmrasH/,\C{|A%RU{JK$bM)&G#M'>.j%ĴE)NЇ-V))xE7MXz.V(PQ_5JX$/ Qr&G1qIbƳQ6{K(EՑb:c lmmw!GcH:~ M5ycTƫr 628G^V e | Wym]_ ?mu__r։5ޯoRp J8:iG"//0G\5'+>VVXX PUЪO!%5Q9:닚 ]_kYPsp?`"SY"Dn~<\-e1(N(cFiQfp '!Z/@ܾþ߁B%rB7EX #D-Hq\+&}dYs(x"Qy$G&fneVP9qT%{>F)} [kK5kA_":x7:sb&jbjJld^uDoRyٯ F]}ۯ+BkWJIi,).*~^q߃kۛM<'V2Q~a !8wNf ._^`|NEll!*񥘜H)QJ#$#z>V(Pل,e,Qv67;0;F7!5nߢpn"7o`69b4Q1c8>w3CI:3~/@%nQ% I8hnMKsO>zŻU4"/ؒ$!*HSjMV"u".Gc6vzarv  L0%R"$1Vh yi<039—sHk-xd2cA'X$Bx0FJBloowc˺նVn5c~hl팾hay#OfRyh pUIج `ƺ:G K%#"B+qY(7R̒"x$Ku J)p2g؅+l q9X $boWuE-#a^A|ӐSҗJ {_HQtl yڐ~Q%$NZ'CE\Pp @-I-/! tl# Fi _Jt/*hM$z=:w)t4/,;*'M?)?~T B`:OWBކvbɢ( &ct5(%}Ws Q@o! zq0ɿeu%ˀIrw}OE7@?T- 4mo_o[gݒ@ǵ7Je E'sKV:<̑*b`W} }O M~K iYm~wk-8C^usWBzO $]nYBKXƷT^47BԌ6G$I&QUHÔEIgU4x”UTdc62>yDؗiQ۷PqNwUICl@?Ō6HLUY8ftn8B}e5H(0㻞u`csUU/2̋-IT!:x1&G<,-H}: L㑇.1ҡq~?%q~"w}knTx"Tk>''/ iAOp2߱$N(_QE^`z% 6NBw,[P+Ͽ@ANoh!ۂu?oz./ !DŽNJ"Ԝ {?4_~_!"i_ȊF ^sЏbV/'5pYo&G \U^v]߾Gq*|RKR(<Í>WsyOH}?H.R<"BcD%'=~T@x] Ajft[WF{(FV=CFW~_ﰘ  >1fؐRC8W1F#677',Kn<{eYVH #Z jHrks49v0XFwkغcxӾkomi_ !QZ"IZ/utsj*Ku6g֪In/o}KymԱo1[̿| %5QTS bI"%EQP%YW!'~B29W' +S0H!bgg;t{ g"&yUs; Um JV~gRCXk0elCP$ Z%)% <Ô>!- tp4=ƫ7Rvc=wG*;1#$\x搃1 K.BlBgđ&I%Β$x<LiH҄NGaB)HJՓ1Y/KejZJAeN(S*cPZAϱIMG#Jߪ9u"29j- I3P{aieܹ{h}P|*P(r9ӬI9FW~^*:a>1(rG$RX)0yC~ܾum\fRs񽻸rN>9BKCvB[.s`xL1:O, ȃ@ESx_, OCٿW& y [A 1,{-(2aWK) D!( ¢BDZ'(@wp%+K,I&̃ G5ȟ%I BN}&U@<`JK|ӟ7ͻc]`<}O_ѫ ̏WKO5bs4:UO_3?*!1&qV[3?{$uMWg2^+ITB*$JrVG)h$AoHP:$(`1cWu̼{p"**2okιFFF( ^@y^l+WپJ*tR& b)%L&lgHLBjF !b!ͶEVD6]]]ضpQq9<2#0qPc^̈9*,bpp!,ˊ"DeٕxHWW===1a6SשVqJZQ=]YR@^E)3<Þ={_e^.oʏ/e˕N#Cr%;S*&e#͒# ɱQV>)'eJ_7A%IQ 4*W2Q 6.F*BQt5MZV.ԬQ֓$ZH!Ky|(%ҪbDKD|ZQZvR2B[H,#ڀ I8b@ bYLw0d :#c-`6gȳOc;)VX-\^x /?(4}}d9vTdiR)'B1 Fô7DFa 2L$Sqp& FA!ce>MavIsMb@f ,25dRβZkze I28ֶCb<V |ۏ?̺ud2i">zfxC:3?'X$m0n4X IDATXI|fſLx 5+Ѡ G@YƷ ]'eXy1ХE}JS,VhTN| ?~^@H xeq?x EJ""UMb Rc=2ID 5auL{J(}f\umjPAV2C$Z;".J\fB 2fE|4a#-7E'R!0- '32Zg(6ۘs{<êUcj5neYȑ}OS{觷;O&e5x0rAjyfp}0f*Yϡˋ4e.^rȋ ~WiJ룻@i1 WZN9X!we9A",2XNgbc>~vN'JrIF8D_{W$ؐ|Ѿ"$x'*($(%&pj6.d]"0Ipѵr5,|Ν;AqIp'JQ(RR(fqKR~\3DD/RL:/f7Nyxe ?zRyu"ju pAr \LGLvΎ'@ uWHbBD!Hȓ!@JRaX!%B mP & !pg!|d 'ϳmF=`[O^@u|1_s90 cTanfn8z O-W]Ů]7o>f9w~f-}N: VnƷn0LlՌ2jbddM[51ԙ9|YzwШVX,3%&'/r}lj6l S,5|>_kגͤyzٹyj tuf`U]E>[V\.377tE*_3g8{"k i-lL&h<_hzx*pYiɔα)itffYt|6N@J#ɒN[\& ,$ȑ5fr9!FDPO2(׹cFe~w*oc>,#:A:qzzzBb'D2>St)iDU,GKYqu< #!Id@(LSxdq>]IcJDZ٨TnMHfS0_q~it(5f@xjHiN vBYJ+Iyr5Jj,1#ǒ^U_R+jȉ'Rr=K_fIX$͒JPJQ*-ejJ&AA٤\.z.6^h}fp pM7100жnJ^sqևKٌL&KxYʳ<>L`24󳜿TE2)=`pSZ,˭7,֚ԕ^'aj`'˩yqdoFJPξp_vK< 0q5/:c0=0\/j?sB92;E!{:z:5ϣaY9~jSOo|۸;s LLs178-@00m>֎@ *Ne\rÜ=s{5iz{{7sY^C  qy.^yc> r0]]\y9Y6o\G9{hM͛Q)s@6+VrJ[kV)/.rjr3r[VͤI96@Te:ǼӜӗ~2.wF`H4 R8!Gg \^nė9*vu* K$}I|\ٖoRiL\f\\D5c!$Bbz.r.0HC8P2:-~~F~~]%'ZyYCuuJ ,_B۱7|ffK<br1#RbH88)AQJl6iE44`&!+0$ϓ%>zuAAi&zqA|_4Eʬ(v>chSw?g?aS8nG˖w nB }B"EZU0BPCL(-/tїFf," ƶl JrX\daԥYT%Js4mda?4 Tvcro??Ϗ jeOڶ=O rD}FyZ lX\ɪ1]8be۞dQenaA {p 0㹊K (W`j$+lڞrsvKAV9utCr;?s'zDk |Rc4Ai@۶h!JlmۯH*CHIRT}Yu4锅0H9 ;p]|!%Z[4тX\=׶( DnS,B7+F:g󶷲zDMJɺM[QliJ^* 24>AO!CoWBF}7}Fj^zzXft([nExiR<׍6ͱi&Ld۰y#G{gN38Wo0ǩӧY_Eo`&`5kדge.>/Q'E]If/N凿CqnulٲC3)d,p哒rh+-nTv(I?NpM^/eu8p 04uLa맃B(_ Bno#H&fM%0 00li!Dp_)  2kPRP,r<~:Zuzc:Xl7A*c`(=[x4EfJC e sEE& }Zf++44=\ΑuSMIeVo #F81 CFjZLBJѻi$I1S' D{ۢX5n"R ~=V&;ggkV<ٶT$Ͳef~i֭[Kg?w;z !h4|Mfg>W_ ?c=繘>n-T*w}\u|]n[o%ɠҥK۷j¶mWy&,ˢhp%rrT* QtzYb(*lbYV D urG ohGMRyY6Wvp?K!|rmu뻭|tAꀘ030A=DVةZLM^-Soi*Ɣi@ӕXaR WA&gҰQҠ滤|_5jiظe/;ũP>xOR^o$)$>l&FmlKJq&# 6pktt. Sh_!h=aDKѐR`[W 45Rd ~JAgXxBFRsTZJO+ >Tz4:b+"ʤ`=fToBC}UE I>NVU a.ml3{穧/ҿAkEww7mVN8A:fÆ|U9x (zڵ pwSؽi>>\+_yniIEUlܸ?? _"ŋ?S񶷽'x/|lܸ 6b}-T1fff'{׾|3o;ǎxy24Ї{gvvZ~~CCKXb~]۶ػw/l2c1_ZXj\jG$]ub%J Ν;ŶlO[h|6e?ƘoN٧Ö\%ZGfkh#UDX)qqX IDATEʕ*rxa`)UŹ Gr | tƢT,ip0)tA۴_vI߱| B* s0 bCZk) OHbDC$$tVhH:OB#Yt+2k2;¶,ljBP GJ5=|M.¶$i6e\蹆3yE~;Zda~~3昚X0m,&βf֭PhrRDRlS* 0*pKSfviS_LfiĶmK:|熝?:6lڌa*N۶IRtuufzjtl6iYs㮛PYL+isϻjf.sAtytН$x~rh C+غ}LhҨ8F}%DeKX׋.t:\$Jx!KGCqi %Cy|t(b4.y%/w,VzbPSיj8Nm *f (a B}і4L>`znO |CzMabe(%qlC(?8 5ԕǢJt ch`T7s^B>cgta?dZ}/A,19?$=4J&!K[R\`EJEMͳEL\z^ӧVSU(l@J>()KП._8C(2i'0[fCl(\:4=hz WN8!&ЇȌD"PP_h0ҦqyhWn˴eD$5Nk:fj5:{axx{" syc4Mpsq9=ѣGٳg/o{۝tuu1==ͣ~}Kpv0 ƙT*sQ*غukۚHRٶG6n1M|%Z,;o&|ra{9_FGGټyG[6k֬iSNXs|祗NO'}kRSO= /W_RӧO_Vk׍8p~Wg_n݆Rx衇8~Oftt|{[[1Oȁ8}41M__''Z5 ys뭷2<ei`N-:U4WT44W4LrgQ":~QkϏD}4ovzjG&"]`fv?OX*c }1- i9{s|{J#-#\m##fU[ǎq4Y]7smwՅ)$%yVK DFaؖE!h,'h=uRWg"W_I~Aʛ+| IJ85ˑdbXR_~5;8;疢x o}tK'+?ayt6IeYdY) 4uT9ᄞH!`J3y giP//P"j< 0hf’%)i&BXhJcH߰(K OhST񰴤j[l榛n7~0 Gh4>6lٳ|+f͚6PCkMZȑ#o6~xQӟ4wv~z7?;vu]x UWmccc9s~ٷo/"/XHkd.?gvVY!45i.]y'ZXEj,7~GGR ~~:$}rLR xJ*% IhH $|-)fl"N{BBF16ewq+Wԛg-l\ɳؼnNl|^_=.bV dw06QӨ(Us>v$ s ]"mkõ6ޮx)̿t|.ĞpH7QZK4.Fpm($pBhBtw7˿'~EG/EYN^i˕o5@њT':O>'ɶ B lSNhsLi[T(!&c;YR5+EjYlajҤiD[C L.D& Sh:8fK"_U:ŋ38@ZZx;R"T$, WM2\.lHa`peb96] r65ئeH{ d+$R^#EΨm1ԝ!p,+q}uʧ%4њ MC:/1 4*DDH0J 'NТsD~_^u]"R;aժU1]w$]mo&j1mݻwy6ȑ# {Zs}qQ 011>ƙ3gfcM=,4&)T+ +"rgضRJ¶mXP߮4M8jqxGXdllUdժQ6lXϱcغu+!ټyxÇYv  rw裏277GOO;0o= xD?ķm>c&Z??ҥlڴ9nV\elٲ)%?y׻G>a\峟 u۩T*?ux"_J9o~9ᓟ$>U~;1Mݻwۿg\&J#jg/7$LKAђ~Ƹvt}||$M%ƔZ y$^ܥi -a%xuxJK0@ ;xt*e?4X$=HZj "AJ Ӷ,2ql/LWX[S?!ϞC:"륫H<gpEws+GY52?d=}9< /Q",OshߧyE*2miHmVuݘ;!bד/]:35vcOh.! Ja7˿1'+.UsQ!I[@xZl\6uA@&OFMA!m9=n۠M 0@(AWqZ!uO!HbHІOݯ*Q9J}h֨TJ>lz,.zXNX | !2JE&_:alexl=ttFJBZ4BJҩ0M ˀc,)tH(: C*d;)!4J5r=@(.@!fEOk L!8" i4< 8D56é%OOO+WdǎOJ9TUJeEB|j"˲TZ S13<6毨T*d2uٰaCR(ɓ4Mlڴ,}}}9jL[g:b|t:M`vv5k׮cΝѣ| kTSS<*Of&JygK\s'.UħXVqN`C*6 |MWcgRhe#a`6&R,IQwDj0QSQn4ZHi D@5Dmw*f)l?w,AahL,JJIkO(&l_2x)RxJδ/>B1oeBji`뀌s=aZ-lt8b„,iQZQ{̗6RȧpiWE:$p FB)BOwiMk%V\Ud|lkư,)mQxd˃>\^tm?fϞ=!JX'=FV>|-+)WiFKjgd2xbONBvu]RAjB.[vݲ֚\./Rʐd&b|>PI 7NiFxj333LOϰy>O?ͭ;nur%ɹ>>=t-t)?~Qq! ylI5Z#">y;C#3L| 0vmFlTs=dML?i֚tu?4ɡ}{P^m!T)Xi%Wu;Cĝe4")SqQRA\SveS]^e7^T Je{@ f1h TN/xND{{lT:Zwo8'Na뺗 pTJh۶i$l/⾯>1!ab19QrOm1 ڴ(6!~{(CRM6E$L-iJE+-=M Jm0 y[F/DMSHoGPtwS P  4~V3zVCG$ {}\aH2,-̳o^YBy~GgyE^r ؤϩ|k^VcG< ?*JZ)BUfff&MXkI$)Znޓ$Iݫ6>?GwMAײ݀ݾ]fh9a\vW'|>>QD![o~3Ƙ 1)%{77*K޽{O,-EJ |[o3L% .Rn!e9r=7-».O)>?sob~~n4ƽ|cȑ#}_sq⮻?o{~?╯|$kOgZo>}1666h6>}|[n'ClR,..ogffc OassB59zqW@;R 1?+++ݻ):qs]o_un'^{}ZdR_|9${ߍHs~Ua>kݮ͹㪰,OwqT^6%Ѱ,9g7k;Odcjca<3dzTȨ5RqI8Ю_%"-5p x }ׯfǣ s$ ly>;_/ m4v*ln1 LyQr8Qt8 u`!NS{ ]¨FD!B?uح8i6h bo/N(L\ %5 <8굈KmZS9pK^E\o7.;}OEW~.ǂ- O֞ݎ9WQpjTVmfn vZ`,2i^ ~oW24%#5'RZB'33= IDAT J=5t .$yCi%dK'@9JO yF#Px'tqBP~Ī^*XG~?Yl~72b<,Z}8.lrWVfggM'" .y^)]tvY(ȑ#`ii/Għ>Eʋ0{~7߼-Wꪫxoc{/E][VW~NO} c \r }kwX8^4qOXHW}W'pqY^VDVR^λ{1=Ji~7kWV{*β?K_]S 7sO|<Ϲ꫙@q|S~7̭2ȕ3`0=w}8xJ p6[qN` XDcl vBxYs?VO9VXk #; @R'X+T Fjsgs◌KD/:x}G.F8CoD͙iZO%l"/ְz_pPJ]KbONz* qFⷝk˹&2YOt X85aJ#DYw҃ct>P'd rxZ2Ր떆 k2KI KÒ3 &m jzZ szE*w!޽?k捬nβ@G4Y\X䂋. W-^e^2>x5׍էس K\Wp̴@ɹm!IRIBfyEGR !J"DdwufA..dz9FsjgFsGQF{^vw/c.q獎i(Tpܰ}~!9v[YW$Ka [s햗dೌȣe \̩3P0?{`k@jYhj@! ۹oqvdpL79-0ϲW!)yJqXci0&#R6*Ll!NXX2̏gE(A]UbmRyF ID Muޓ[&m$o`]Nn=&&Q &7(g106G㈲!AT#-hFu,@i\B(aS!ea}%cn3}w[2&j):җ19ؕnqseV\wu\qxZh4vp>4 ~W~=~͜;w.S7./+۷nH]k_طoRJ^{- %iyyVE^oYq V !~8z(NhTCE/ӟ'~'{|mZ`MY/>~_Ç??~廦4+K9\s-}]LOpwh 0g~㕯|gϞX]]ޫeΝ[cA]%jM2-(<؜ `CgDsgeX&U%UVkƖkgR*-,zBp1,IXc_xf3*͇-P sKqRn,0&4: 3s\tJ7B2᭩*lQnq.G=z_[G}sB}$Ckǡo } N_ú/%"a3q|;R |лq >"J0$xnʕ,ZzN ֚زfYl@C Vxa*/PA fY{6xT޹iT8*P\,?eX`3Okl4uSMǚ8 md Ѽ!uȖVùA%!RRoϰD͙;k»"(%|H(UzH>sǏX][e}cWR+THJtZ{xJ~^+k*$Qq.0",u>  ) cR z; p1t8<~,y觳AMzL*x,_㜧`c Vyǘk9++=9zt#wh5'\K a,`'#PŸfSk \oWZs|Pk$E9KJRHacR.&\48U7<\+4Zb!r$z{A`du ,M|(Zsb5}`ŻZHЊυ;uz; TMa(Τy!XYʱG譝æq`}@"i%Ib߾tFC :+ǎ׿I4?kx/:BD-zAךL5j#3Bx{27 h>WK)ﶡ C+w}7o~9xS^OJ9ၰXu_(ҰN! ~FYYZK~n;Lժn8eӟ'Μ95\_NfaaȑЅ_w5w}7o|yvJY.b.> mo{+]wƘ*S6QU$q񒗼??!k\yŹ-h4tޥR%|scϞ=oP"(#GҪ2aV ǼX+CؘW2v{醬XETXx2)@HIP(Uy8#p:Y%RdX<^H́a}k3d!DX%=xkuTeW/s Jf,@4퓧[J:H)qΑ݅㧻? Jj@:)>;PEiw! 2L$A`4RLv(E*Y(䳆'b({ڈzZ{ MX7|艇(Oa@Eنb!@DziXwCDRnԉbd s \{J@1mʙS= I94!&- '`qq2daf6FDrna/{hM7s;S$~/c] rRNaDJ17U#dP`qAn_Q9eIQ=~TktިcL~,7 aa-[  w991D0h8x;VFHXj2@/O)QFIQQGkQ_!GIqrm 獁._FQ3:^+9Z5#7R Ci$sǜTǓ].zEHi]A_±^~4`:-q%a!cekfNE$.ic{q{T̿cJIg;']d;4nĶ\Y# u(,O.`3N,b}7PK2c}O&!CɠG%K ynpR"2X"GIE&dy@RkhS)OsV1LjFTHdbDz d2)IG;+ UÒCk'8XXafɺ,#37`&~ZK#Iv jz뭜%/VUfsW>²%X1}޽wyߗORJffyk~ !&=[ >Bh;|53moxӛD^Vt*"7M_k.^w$I>$!n0&JK"'6x#x/03!tI!;/=UxwE]P![dRNcl`'_|]Rd| nq{#lnZc6=<Y7gx &/l5XRtf|ZAɆaxrCCJ %X*G)$~o?t?ǟxͣY/f}%طo,wlm3a2YXeaa% I2CQo7H8qvT]14j-)[jf ˌg-coXރWM8O!̬<" 'W\?%(Iy.$)4XJ ɟFbM=lV B^+<d]HʐWY=/UFPO{b U@QȐΨ "MSz9֚n1PըqǛY\\`ya9H!>)¡"]pN}a)kdp>烂8U BFx΂8[^DiQ~o@Lłd8<.BN+<4g欯 惧asY4: .Ys_= u>iK/gkpf`u _x).jQWXamuH mɾ{g=o49sv?wp`yXlF {eqqvzM= 3Qv̏*ҤKQqOT uGT ƸFdS*ی@ OA=!H |zU@,YZ'"0y _FѾ8H&l+KN F@4R~H N8Pdi_tњHGh=IꪔLHF!_cEB*ux D~yQjT}=zc@;yD?2qBߥFJA֊"++2n۬]Iil3>g>w.Ϝd{O{_)e)ӫa JyZ*)$IsαtM?p8Z[ulx ڭQEQz=>OpM?6Q7ˏ#:x =r*{qsCH)8v$JYOMJrc()»KO W CJ7P% $ o lB94CH^<7HEX,t/ ח~7|$Y!P(jEܵڀ1"y_b{X=y/! C)ܫ_zXA{Hn %G`A8BQR aZrY)y %JA$R+.J%aL13DnRgag 6IIqU % qDj4:NZvd58[*.`\B✠O8%žz}_s'ȍWgISgɍA!>zAr *1u΢rsZ3=]ި1٩:/>2s6W]X{ٜ>co;hY^hYckp=i"[ 假ט^hP>~s& L.1/'kgOd)qeWa\NLg'F_ `j1Cyde_?(г=_Q%#@H$.QtȘߝ %KxlaPmHq4>B4&7b6ieYi>WpDUz)&PQţ H  s!Sy{̉{jLwv05:> byۮ-#y?;O$%{7ƅQQA>TP@4~ODI^c~qF9ޢi79?)ARqMb=NZNh#i҅~iIN25oXsӫ) f9y.R j 9-5tCrbEmNo'1CֳgQh"ufuHx#w6wr?I)|o-"]C R8(C" ZŵX 'Zx)x,3fsstghnxzxtglumqly_Xgcb6bl4S ?p{}sWȲE=zFAlllpV:+<9~8RJh4\~\r%sp1uE#IZ:y>P~]w8|OU~9󙞞tJ ;:϶)LHy[J)ܻ,ϜBxȬ"]Jj=B8%BIY>X6cmR}ĐReA50.;HaA 1.G\k,U&PE4YXhu_p kysǹ+˯fadƁQ4 IDAT!D?՘/-A tz 9(IދY%@)FiSM(%W:5PRZ*%Ku1"kcoȬ#dzײRCK3v7Rޕ,*)\qw'`=G',ԙoɌ.rsghe~a/Uorcߺl+i$5^V]ڍVXi, [e\N([T^H67YY"3D\KwPP({MX ,YfȌB 饤 ;C L}+ g=T4(B!ȉ]27W}"g .Owe/!q tt-gطo)7@͖"$F٠h+`2d:GlT>opcZce1űmcwBd+񢜯8wN Ȍ8?s!پFpr(ï3j >ڧ'G_7a.-G ĸx~5\rAVVV>e/_ײ}ǫ^*i cd -RZBO]c &)cQ]gWg?mƁ<lSaą^X=-!sKȑ#o}0C|l)ކ_12BsE޷?0QO`!BePLTxo,*\@zb-:w!{!{Gfs, `&!03Z`M;ȡ L{-AvaF^fC*Cy9?E# ›a2$ +eb>wOgOܯ>H<!^"傋瑑cmujWz2[.3H9FLғR[G6#+ $d{%|d;[/>(bLU6N\N!K{:왯{3'3nƍYZ갢r8~lKG8fplOXulSV6cLI^'#QXA =<\M9v$5)_z^~ fu{G[+CDu,<ۆ_#g985cκ/ ּlicg"jZGYf+D`P#wcSzQ挦!tNj"<)¤XOm(Kc`8ɭUևCx+h5);mf>aJn,Xw@#@K Rш4R& kl=ByM֡6a:1d3K{L%.7B(Ъ8xVc c>"C:+6n'TPPXD]ѵ=^H 2Id}>#P__s#z&oXt,(e3Y]=ǟٟj'>>:@;~-oy 'x?l6Ї>q )?GLMuou{o/Җ5K/WEQwfY4ess￟M8ȕW^iv4 VWWsqկ~O}_U:t-!v;#pO9_:VkK CR0G).- ip/Zd XgI3R D,yI&K 8s /`^lW %ɧ@H36(Mõ-C曜|D<^➽ qN³ǘ4I`s}ͭM666{QxHX/JzRx d!Z.I~ )lp>8e6# B$t) A?k:gϬ3|| Y6dwzNY‰M?f,ͩsmڝ:H Q>bBEEkwH!hhE;ıFD7𤟳hD9C[lΞiԣݎjfa1?3k,8zI'Nqf$Q 7"\P*E;4u╄En<^  Yzہ60Vp<].錿PGǏѣr-8<# {(y^>y*#2K_R 5_fnn|#[a0я~n1?~S>({ԩiooy< ׿Ng\}vm,//v{d9H;C m.CT92e X,פB 7ɍC1Ƒ% / M =E:@[57CÝT:R>cA*1RfH2h 25C'ׂ-$&'5^^u5& abLy{}{>x֗xxB/8FiFnM`fiMH=* ƔRHo=Rx(r!AJc+Z?(@(`>c*>0I8B$DR-i4Zҙa~v2?Hˤt>l~nHc)xﶈv\KY'dO)о*je=VN$֠&xeWPoiY۠eY qb>?xq%Ъ ]4gm}\Ġ`X864ޯ=K-sf5ڧݨsέ#'Y^r>.d/g'#[o0;bh^ƹӛ8W^sfkA߰طpӚa7aڪMflJ#`uop,{Mq6ﰺrXjљ_$n4Q/rq-HIRw!tK*5ɁI\Ufr'H1 alFC'sH[,# ..>T~sݣ(W~-VU n*195<ޖr @]ͥ!B{5<? ##G%@(,|j>xAR~YhV}9GX Z-(%QNXky:{4~R0]Q.ѕ>_S첒=Ao?^掞ihŎab9" $lFEzdo;#5H1?7E: ֌ϝg~*B+MmgӖƂ`ơA 9`4yX|RH#Y,vq#-0x2BJ2o1>WN z1 ]kО4h ISTG)bޛ{vTw̼o{E @44m@HcC4ئmq;zl1c[۴i0Khoc$BBVJUm.9dݷfG(͛9sxfhB1][?"IӤNPҒf)QƱUR26Z liҙe@jgG8`kȯ_[[Gy[Te}voABl6_77!ysAq{XYYeyyp+_JZF7< g.8kzqUW]?AΜ9,j8rZ3.QvjeYe?3nO}CtӍ8[Y]]-v~җ?c q3UJ nv=cSz^$"ZXsc\Zjc*W FQ<]#M^3hQ99fIX^1Na6A;m`yQJgBmqkcNnUUǁVLNkǎ0t#w•v5FO"K8Ο_CƸ* G嵡N>y 'Ȩ@JNtiݲ=EqM"DV%"Wt ,PL6dCΜ<$#ƣ!pe]4y0Hk| D\n*8 #@ҭii=Q{@x}SZn Z9Ϡ'h9t0}tGUZ0PCq`cq9d#6Vhm6Q"SؑbRbG1b1pq^ hW\igŐ4Y;scɓgc8)9fk#RGe 2q$Im5%h-dڲ {)g-[pHOYRNݢ˙'Ng;F*ae,85(8ur5 9=rOQ /YQYGOٳ=|"?a34{)xeƋ6?=Ld /& U%Ttֶg1v|?W{63zPc{6 H~wsڱ;>g*o].[ChDh eih#Xn; 4p*I%h ɵ֌2%$l96CzCj1-zBaiF#I8(37K4%QdR #Anш,c<1e6@ V m%I"hb1,-)`a\?#XHbemH(4 ڑij`Ea16fk 0 5,!U + $RvzVH6!y SGXJi1|8v4uXsz癲OJІQ_Նx7H~z??ū_*nvsN?صkv}C|wO0 X^^殻iZ|?_cuufɍ7OZ?AVVV?ct:(XǾ}hDkPX.9qŐh@`s&%Xv2dSO ɖz :tچC6|'9ufTWfϾ6Fi!sU9ͨ`2|OmrcOmX~|.>dd%ǟMW**p)ɨjbӐ-UkDX<AAUHzE" vk՜Zχ,4RPh(L}Uz`czHx6zw_ݿ)f|Mh6fm0blɰPQvBLB#ݮ0duqk1ZcR  Ìp$8M, C(.'RY>EVқiSk JČ JB .yZyiqB0Bx pxa2GEA%ll :oԖBƂl+lD BR2J6ZJPRD `u52׎{&8:o1TuC66N)q!\ ÎasxtU2) 66ȻaZ C@)߹9i?K3ưC=_W_'?)q7;'9l6(Gչب>F#>Oۿ;޽җ^?s y޽{?޽{yW>+E_|1w}<u]UG+.a eEQ[\qq^<x'1sϽ }?KKKo/kaqq_9~W>1~/yK;>駟faa|;U\}?Or Njj-?sNq^m>gg_Hl\*4 m1ic. Jo{`{᳠M`b<.hl4r{ _?C)I 5 FKQ(t†\wjAڵ+p} F}줤'G'=Ŋ@]N[2KxC٪AΆ>z lr@<`j..sBiYkXӦ{sUȍv_6oT'κ)1(\9#tW7v4զӔpGVDnVp9J\S]YkkEQQ,֦TLXl9jן.FK r|6j\;tIm6Cx^B8bdk( _w0dJI]K vb-(#0BZ`"nPiN"FkrRƌI3?Gce 3Zʺf$ t]f+3.]mxHLX,<'8҉"!n+&MTEh~B*Ea)JhBw1ɦ^*Uڜ7Cua)@a T.0>]^WXs;+@[ה乀s);?fO4'̡CːR;ka4SO3?F/^ʲ䳟,/7p="nfnnnyyg^_wݻRr%T%bwjYqTl6i410cemmjm[YcO~#t:xk-^z)b~~ /}c-oaaar)ΜY쥔eٳ+_}o#~'jnvdلZ{]u~ZO1TsM@ZYK]bXC)Jm@pyMFhRS m4J%it!SeV GXy#@ @W 0kOi|)Sjr1틛NbFhzMKUʥI`Fp ]cJxWLOU}Sc}?+1++`чZ[.?Jiw ms`cϵWgb֏X DT]!KOV^Im΄["lܤvhtf|uڲ,X_]##ff{{/cq8ߚJQ I,]TB%J)fz=fz]NEhZiL{XSPy^1w'('EVb0Z!*#L؃B`n6(8s!W-ci!X)@E.D ?nΝ͢~#^|_o*; b:Qsz}Ԑ_8e>1I^F+N5Hj%6&%TzEN{4jБʍÌk儵l,IiZI[: K05 W8q;O =sͪn[ \Ň8M8 =Ln$/hg()"(MZ6Ku&DJL$BҺ0/!߆Ly+aU )JT`e'L4VDu]`!0K@ 2Nw& eQ9eQiƐ'XY]-Kj+`v%o7[6o&d\}U{emmopM7{ϑ$)yk^,_|1GO~ RѐD$}FP[! 7G?1x *zBfnAllV ^{j1jƯhh40ƒe9fH)I:>p1$IBө*c83Tc2!Tx?SoWE$KNO'ΰ7ÿޡF%u,㷖|i0k&kD9>ָD[]\_2DRe@[ɃMLXW5|$6͘t&^Y-Lt_QPSH5̫c9S! aKuOrK4 l'.z[LWK?1 JJPf}ھzsT?;t?NBMj>w;-H~n,P.Q%ڣeK攥!JBo5ב(Adk]ĽY]>OڐaʤN{סP%Q\ҕeIZ#!1RҐ 83OqO3S9.F( zu8|+_Sd$\tcL1T#|3 ƥf:D~wwqN+^q/ˉ;s} dvvpSUbvu͏l6)˒dBf~~aS9жs6 :Ɣuqq(* YλϽ" F[5m}N,Sy.j ОELj bL)Oړ j JIsL2̄)&"(8T)֢Ƙ1gL bZ;FסR.5[S<0bMOݟE7,*(}E0UdLO 㟝iwӍ ?5? ~Jɑ= xFYЈMv?Y35ܟ4 4|3a /力7 &hk:AyGO 7ʿ#+O;XWD vjAhj1`.Bmi]ڝʢFlrr5T]xWpHbiix| }^sx󛿇n{1oÇ7L fɅ^TG)W1cJ|IJw__{&P#MS:̽~z c,Qcܮ_ׅ\qw}v>OV$MS߰~Z}$IygvoI k-s{pΓU}oW*9~ ZGPL<<0Ǯ cb M"aaޛ( /g(-``ȉǞ>>̰d\ Z&få"(@A &Y( /ӥ qȂKFBו>vnJ)Z6v٢koFQ=Q?EyPPK]C`[/h#_P*^x9!R?"B`E]N#*ej}UQ/=[X!ud Tї W}2 j9D3]l$"$@sTͮψCiyg<vSEZW DB`2Ӝi;#R3J">x931]t1gϮOfee__e/{v&$IK ۷G},ٵk~_?Y4n(h4K$FJB`F sz2 V !%I%c"eHJk\ŔHRhMK[):d#;2DuyYQYC2/)u|* &(N r+ĭ+ XrХHk< oG84x➛qqsRlak~w_?ӽ uBHK*([Ȩsɯod ?aA'mSEK0CRKCD)Q`! -J%ʐBcK^?Wu ߝ/7jx IDATk·Wl"'lԈ^A1(u7=8n 4]㒕\4Ҕi4]T%fNg;DQjRI.]j肳>()3Y0 -+tt1'Ϻ*%QHEYBj-|—طo/hUW_<8Ï?M>mDؽw7moZKQjw/Eʹ2_hT)^y!>bۢ ù#jE_ԇ!"Na/_˚ 3-VEl?՘=?MQ&bOE~[ؚ|K%J(4qڳ^7~Ut߳m>4lKlp6 χiz̳޾ouʭ.K.(i"4\y)ee(YkIMz\s4|шpx2f02 LR`B2dfEADh!dTk5f.今sŪJFZ3gWO:XEXC$W8!&O1DA9e%@HTӊcH(nFvMin\f !, qo*B*EYdKR&Nn'_yA;Gbbc+`娗(9eri#Z^im4z&M>$Tc0EdtOGkX;WJ"JmT#mJKRv_^FoXж-1M E $V,=3?(; ihl9JEy.E4:f$rB'-.1ӛК5&$i$ x2'Ϭs^͈€R){;;1yuj`ċJ{& axQ:6*Ε+O!kjU~%O 5R*cpY^޻>RE%ݩOp8+y r)<:QbO.,(!1R'ȸpJ jg_~;D6M,K]5Ґ喼t.7?fHuCr;ϣ[۳EEѧn9&fi)uI1q6H$ XX1 H^)+a%RQ\NB[!ƣ Q. >Qx3MlsÂɤ`8Ȳrjx"I)'}Vi,)#8(J'4DhGZN!Fe;+ I0/ȼ|趏BMƇ h$Y$"F.s=zfB+eɠ?XM3Mi4 _In)(Uw`˶i]Yj:fX[[q֚Wo(q\~e?x`w)%Z[o嵯}-)K෨nˏ菲~4)o~r$ ^{-NRl8W_U=wl2;;;N~~??ZK)?%EeCXNS#A$fBA@%%7U>8C`>I.༫.Хt:gĹrnZ$j3-)8\" JFDqȈ HJPhki&qcJ)İfge*l'S@imimʺ4 @}טK/Q: , FpjO')'֢34(9k?etr:*j9׺Dof !ԎGj}?)$&HB+ih%b D 4a#7!o}>TgATgSʠz{ƺvYGVh[v~(IPqB& HgyT,ȳ$VF NYfue5 ѐIi0S&r/eC( .#荂2(tf ւY!Bљ[IK̵RIu3'ę1<gN<,gwn.&]bΜ:ͣw=^KnNQ|Cy<8g6xĐ= !nvt[*EffPP^4q侍VvV)j͠.u, w陖7PqI SCPCNsehxgyy74M]PMӣݙ$ dd[djV?l!bӫ l!pSX :uرKOMjF@}s ! &xN7wEXMi^I~}LگxZOs| A.<|7e}mxcpٵg7No݋K&͍>i bʢ$3& y^0O#M&eAONJ^k7ݹ~G\pI9,ϹUudϞy$qyCXٵ5,1YƖ'6+LddFfv8&s)$62Q B@jy׿:l Wާ5/gl3I\~gc$C)E Pyrp͠heK9z1=hM5EQRpVQ3&ykJL3g䓂$(tz 8YJssgImwY]Jf==J#Q(!8`r~a-) EQ<ɋ E9qa]@ǘ<2D{3.e('@B* 2Փ9HgF[A&dp^X]z FX0vټ@<˭$M+os<_l/˸ ٻwﶈF`|8(R_uj[ܭ6^^[}n4\wu繹9_ɛ]Yu+>hZƔ)-}ԩgԽ6,1U1;c~T+ :az c%nCK Hm 1"(c.]x'hN4^2K=t(3Dz)j?)EߋG৬|×7@zpC0C ѫŃq{zp*[, lory/}ˬr󢗼ťeA'HRAi%n\Qm|^׿41}v ŮL@gң#QsLKMj+b hFk<ߣ7فiIyx]MxA^<_o7ޅoS 8g5 t=]*!$n(_v8R~ݺ7p~cﶚU1.1 -\9S)rju0d{y+)InwAʡ"2!G CJM$IRL""Ng6y9q|J1Ic|9!P#,JGʧ(˜( F5H,n)̕^sKklUBVyb~9Tijsj_$+yc"_=7M=o \rcǎvsE 9~A u *( R)4NI4s:ApYvnwJ񡛎h`!Gc0(xXƐzQ)&(ALi90C@^ !mSMUԇ 3ݯ<*,(J;tl!%ӴR8{(B3(u6ґZ+8}R˲Z1,jRk!.zjRC,9XG6oD ÿ߾5)_(޳)a0ZCpߡ\gx6s'(a0e%ј;{lm;NG2ȳ O>4IHw}a} )Q$%RFF8VH%$EIk3b1ns}hc=}I@ɧQ"nEl^*K&e;?SheF ΡFސ󗈛  64rI 2{R}%E'mۯ? K~R^85rC @/ھ!N)˔k3d]KugP-;;l]'p"/]a{{,pΚG{^ݠl6JJ~JٚdGբ x;&ğNNJ+pTLԣ NƒS%}9}E VBQ85.C.yE(N&_P;<tzHj} uҋ[ s9_X.zG$R-|IrOATI~ך9.lT cR*pEBȈI%I$ɋ$H<(8Vah.#~@]:k뫤icFR3(l6i6:H)i=RטLƾ31,,)/&L&#/u;(2&1yecRڋ,&NRib-k}}uQ +p@n04n~jyse~/^ĉ|;x̹s|2^3gnC$Ih4"sRF#zfs=EQo% 0>|G~GM~__[Om^sEIKMG, D4N)q[S$R *ώaA1`%U>x pħ 4"e/u)XKYRJnHA פIF@h#ʛ_MEHE>I+"vف,$X tAݽzi)he,ر ̄[,תse@Sz&{>uyOoA Gnjt[Jl`؈0" Z;MVҒ `L#UH",>bj<T׷y0tJ|8n^ga|_f<ɘ nj#8CӆqwiVV M!nN3(6$SnpiE^!nb$&dؽ'4Vhtz$RJMCj:#2l>`<r#O M֠`c/c}E)I@H8}_H|K^mNb,I:Apdx6斫:I^Ē(FPp`b`J7 %򛾱VƗCǗhTR(r9RyBP)̱)2] tʧ5. %1xs׳FF2*. G~Ԡ5ځRJ z ZRk%ԴBa#D(+u$>x]}yk-v,/Qĭ+<Ԉ:a }2k^;x{:4JWnU8'6̻LXV䘤D432ă B;P.)- D"~%SQ/օWWS_AxIiw.,Fwi2pLe {\}{͕n}+Ő'`&,Q`ҰQq@ߢHEk%2J0\M# |~~aZJH$S\t-lZp8yʛN sN7y"}a 7Uky܃\p"/ɋܝ[ "9kOEjRKK,,XE-4M}-"jOü5UL5RVr"QiE5kNŤ sH s!4=׊*gۀ@9'ppwWcF-lRd8Xk㘥*m!̓$M9v$ v}^F8 AYdTu IlY\u gc܆ra"oX>N5ږYFOP3o!~~-Ʉ??~?!`}}/ŷ~뷢~ʕ+=z[OO|sO|1 1N*Teϥ6Eh#`\d"ISp@9M4J(p+H+t\Ӄ҃CZmӤQL$ /=A5J0[XYH e*ԎIXXղ*`RWg𚩵4Sj֩uimVK{a*5=^@k[sJ!?Rq~PGI&}S%kwٳ#\s2bb*-X?תtA rRh)v0&Fɲ 0—ײ5 <ĺZ(QЀPƕ-.E?))}Rv)VVY[[ȑ[X?tU& ^ xslo\#dyӄ$X_Y-)A$% C^dQ jfd2:(~Gu\5qRDIAVGY6ٸ6JbFjqo•=FO||{ᐼ(ܻ5'ͮ#%\ӊ"g b {D9'.s#z|~!v/_b3gx_Jݑfshh+8=nYnъ%X$ գDqRɈYzd1 P+o8gA``hBY=]~WTUNJ>NWщr_Tg|bƧH U{t\~@ѰW\bgg(@EX~GqvtڴMZ-:noNSWXY?Dӡ6rn@]vHH1׿lx %cptq7ANY+m[i:8aݴz2 ^ AK^hd(-SoOE85fB7goBp9xrO\FA-RVKY&W[}2)2ˤ4f0(AJ4",kloܼ`0x^ IZBF&v gvEh4"MS 7:13s 'An|%ɀ1bޔ 4HKN okP%!z j@MZ'DumHFg8QJT9~yj yef|ΛBZi4>}Vʼn_PJrEΞ=1k׮kk؏EQOOh9'>ɻns?:u}|I/O9x;8q8g~?viyk_wG}×|>(?o{[9wA~7> Xo]z|??fqq7υ~[-g``Ohy^RΈ21P E,Nb!/,q+ K:p(5EW9)!`.ɥ@p]T[S"LND Lq^yg:ZK^d._?JqvZ!+OR9oioL"(Zdu] i-Q4W7 #53V]KF2U}* n5wAF59cUrU ROif5O"@H%y]*􋈥XY! 3< +w Xs s_ȟFeck\u92oH%z,,.n}\E*K$nIp3TUDV>[ڤ=XP"Q͑a|dO6DZˋjA`&)5k-{{{ZjN&]ŽKY8q“&,//E@9s+ݮ챸d25:wA;ԧ+~ct]7s>//~Gqwoo{=y;;;C|#]z'XOʯ ɟ)GA.~w~%4-~5>@_ȢK !Ȋ1iRҐs;I|4u $UqwhڀY"7E-lh )RxPieh+|րfh=LC* AvF* #(E8`%lڋE|x#i"wOwzU,ҋ * Y4Ȱ^v^B<˝Ge-ET`HTr]׼NCVhr _^h~/KF~9h߭(¸a# M5)6<`kŁw ъ ҧXa1NZ^} &~lʪofE4^^CNX]ewcK/M40Z\| +=&ֲY6\I')xbq5t)KQXbN%X !/)RPȱ;qp`kľBF9*10`D^@gd@w8NT䑋!.k ]:%neeIwyk<hl$˩`˫] \aazKpfm$ۻЋsP P4ӎHfU2殪H$3xd $N%Zm̝KSC;\ڦ&R LiyNY`ed<k4QcE38ԋ9m#UGJFeYi( wj2QiJ4ӘNkJKGh.aiy dss S֢JPJU@G8 i>"y3RFsx*$WQ y}7l`zx_D={;??αcG}I%666g cȲvo?:}{|ϹR tb0F)mMkVm)s^}J^i).u#rJHk,DĴ*UЂ*>;cyn-XmAy B0VͅVE2T(P:BJO jجW`b<%' A)KWHk"BWy`}aC$A Ѝ@‘!]F`"AHl cm%wD Ǥ+%L8qV3"&Q +)N("’G%Cv}6wy2ˡ¨EDHE r9rUollw)˒$4ՍU]|zY#4GT(@:("B cy"M:.qWg@=H|uK!yqN? pmQy^Pxo{%QUmyW)Xn)! l0gYcpDaqqmn)%^7MXk9w\u ۿ[66nx8<;;lll--m8替y,vbIIrшJ &YV?0Hkep /Ma9X7jp%l .!I'K.WVetJ-K%VCЪ֑oZc!/*I?fPR(%0VRB4Н\4(s(q6E yp.') h W\e!iKΟ/8vK`=("UE8*<LJ6JS1Ls% "1(㉢ĥv35=~}IQHa1RȂ2c.e Oҡ8/sot}&p{+ք 9Ƨr_O _,3?ӭ rD?;@$0clRe2=G0+=T!{$m׮}2>6DQu!" Q*Ƣ( yb%Ӽz'A5XMY*ū<c5ʈ1,EQM.N"AI}52+k8G(Be$I1߼Lꐶ8EE1(L{eJQ-rܧІzK_rΞT BXWXkC^hvge<Ȳ),qܠԚXŜ=s+YMNog)w D[ d^[0lUծ`QS9fߥ`LB+~&*{zr˙(*p{B*.@zwtÔXl\aD'Lla&{m.)uNkFiUȈљ޽>$ 5f[no`0?xw"-N;9XCw;}^֢p|E}+?VtdsmBOzۯHHj77=Ƨ$Ԇ!g@ IDAT@j)+c Xdy9Ei>1`hI32%4%I jܑMYC(: &2Mh-tQRݧmJTGGeX!i yd\9'Cq/Sb3Ӽ 3dx!fA_A`ʡRq)ΞUgBhMwaŅE8"MS֏h5$qD#IHH)8!] Z#u#zy.f?Ug?7fɩSԧ>ŷG>_:go&ʲ,//3 ma.--|+??p1%>pa9: 1C3F1?8{{{E.N`4qQpFNUznT+IDLRP%YUd\ºn3w}|J(VVW<ߌ7Jg= 'GDbp|FP Beb|^2^Y-i6!m('ɣr^J5H#YH8q ~4Bbon9~KG AJ]u!DEJTk)(X[ kW:r]׾^wRÉ[N41fփ aڧ%e "F6ǚyޥF{-vN8ϥ;%Q Ѹ7j u+Ȭ,1ՕfA!/fk=mwoPq>!/ $D5BsmsPG4Wа}(3 0ߖypkk"Ftr)H*Nhۤ"H`w_ coZpše.lpE9~m_5xc)beeܣ|cWhFCGy^E#Dq6uƻL{<|gi'Oeumg,hu GZorud: V|Jt^k=y[_e>1oFF(J$y+'&!ZPo|׽/~n1?~˗/7zi>O{{{|cSEQha9BF#& V8)bf_IŠg4< XBH)aOSRVeZq))Jς0)l-l-h^ys03#Eɥc!\(Tx4 \)R mM%ʨۏ\S)hWp1D+ @׮Ӵ.]z0RܐgJ8Y|$ARLך..'O#4l)xWFe1gWJs|R3(n`?qL~>4HK$H6mmI h+E@t3ONvQ7 +}^j}mׁpjP 5T9s7J5D~Mۃ\@& yi(&/ .jŇ.y~[;4&f8t)ihkbK@7bՑ]h$"n6YZ]뒤nO#Iᢕm^.xYlrq6,,qA+JM#6^[X\YeayR4ˉSY\۸B*.&uF8w= ڎуtSA2h>÷a[| ^⳴ o,z$I=?Ǎ"Mo8}&RUG[M9]D8`~"`*sDuVck {+l=|RhM^*T(@+QffD/mьb|IX(EYyuHX)Q2P*i"Td>A! [nOnxu<[e]=r[훈 PVit"cLY>Ab1Q,IIT؟/G[EgBPQp!Y&b12f?S}&kV. ?[B]:(,yaY5NZShy!ryt֐e,BIPәg&SO1 F\rF[l8r[`yBXkn]+Jz6RE77kmEh4x;P%fo|;g@m={Nݱcx+^NĜ>}{+_y(ַ_?ҥK,,,7+Wᕯ|%z->1hZ9s|+t]/͙Ȓgűc. MQGW{:4iX1.D%Taǒk4n@I`"Ɩ.2@E*&nY>!n%X2.tı̯*>(Ԩ)64H!1:+WPO /S=Jjm _J0=#uFY()a4X>ٻxի_OX3/c2ei~PDՍWM,"WEBH {[ VqiǡEꚟ׷Jp͉*YW`3(6_9$gIGJg]x*qzy26RS 8ʅ2r\!bD P!|L&H:] +4 tRWn=;bq)UHH,c4Y=|,iDX EQ | ƲWϦB`N&#cV8KoCHAKhmiuZ_fc{mhӧq9 W9V5iD0\kkn?bjeL5/k^jqg QOs!*#w/~YPTU9TF F:DBad:X Mpdhx69<-ZID(# 3#5KFBӧub=>#n:Kc'(_Ig+]O4( MenRj'Uڍ$KglpQ2?Ϸ}F*=On ZkE(/()rh#Dl&D$J NF:+|(6q)J ϔo!ry‘{`KKU{>+g IdPDBDY ɡ0#([RRZlG#tâH3`S%!$E 3=z QRةk ,!vؚͥ"eJXJL)WVHmbLdocl1bc2 t9D Rs+WFF%ĂOIsf|c<_~ АD~q4Eݙ. Xݘޤ뀄 Jx6|ުήY(w>aղX-+Ip_|lU}L]kI4-s $c4ѰT@;༧ 4wQkƐHYꝻvjj5#)_{%fLv.]'"]ؘ6\vtF]UJ 㲵99v@+=C!$u7^G.Z -YPa) Ucc%ƄK;/XgA^Yh\CNgAUU_͒0 (JV2F I9J̤9ہR3oG5HB.Oqds T2r$Ŗw:ś![M{)&̈́zX#V%QPNPFb *+)QuzmiHYA$gI3HOaЄ*׏)]:}zoV}U?t~;x0ߠ!+Ë6312?ߐݒ{ܘx(tjX;F D͸^J*Ɣꋼyr=LUclA\]+9*l@`rgr^Zsv!<#Ӄ1ke:79AYŠnyĢ;>[SՋpbs?'ڎ'-^x>>^}.}*Km`{gp]|3elh^>_M3k0=ٟ\rletH^ h) 庌l'm9/ym0 Ɇ:i]F'iS͉609Ҡ{p&Tf7A’eh{ܛﱈ-.syzjjؘnV/"#KU1>?ŮySWxN<ћ*5l:?&1E.5E{viuFU7hI՗7cȉ_ۣ>=?뗸Rba߰ Ӊ`JaTNF_"*90IHIF}@;\LÅs;xא&bXn]+Kji&aIxBUR{i$ftXthvz9p>DC&(SCdOcʌɱS`#*_ IDATMK91qx]y͠fʻ$R,i[:BmLl_ [ryPayf ptpHh[S# tc勄>1tr+7|LJ/}g}7; ܽw#AucLX1.ιC~uO >~`V8QtlbP9b$t bĨCBBQS tQDa!f0 +9%}t`rW>ȩWcŠ&:;m Jz$]3<ɼ5$([t 0XH x_WEVѬ+pu!C"e7r$M'aVUNR6Xm 1bWﻢ DəLD)`Ma( 0m}R :,5B,]R(@Hϖiŕ{`Lsmd9s( O0SW8Z$;T.gĴ10&S7O^fD-&>knua^_׋{e޲~lcۢ`  +AUafm!!(X q^ fX3cL%p"O(D&~2b"=_q$`CsչVUi ss␽^b{"~{s/KO=AuE4>r}s6__U^wO}/":B%$4Mʹi*7WUiL{eoUz,#X~o.c7c_[Iќdl]06Nh3kcGd> { 0в8d=doyļ]]!%]ąfUCS,[ KÁKc]#>>[2d"1H$XӶKP>aM=FV&Ĩ\bFh[ BNГz /7/%ht#>~s~]-h}9xkxڎeN &*5lX ptbp4ֱPD*cͤB1i6YZ|äbY*Wc0iuR e$lm++!v꾙}vγZC%eZ9&#K5]5Eb9!ɭ/p8m9ń3r\ c%߫ɤ ,Uҥ-$b29hiXHh;*]21F\}O>6a%^`Ո38EM0D Åoc{GWx{$b1AX"V4UžD~U;n2v[I"YO'v^CI!HivQh%,LCG1 FCHb^!HI. X5L1eQ2XS+dWk/?KX`'}%O<==!=ڍgx֓|糗Ż{C9[\ymͨΝ㍯}^yq~t{|Dsn"ʫw4.pk1ƒ/7<ǞW^ۇmyy޼Ʊ4ܹv1ܺ~ 緙M*MJς{?0zF+=;g ~eѮXu-!gϊQe[,]i/qVg0 Fxa<5}moOed lȡrSG,69nyb 93 d){_٧t=iB :2G]wdOp`Ã\PfL6yk۱io)"x3 UJ#YG4.ڼa3 j!ƟDZ-hDOM.j2{Geb9wx !R1q%R2<ܵ-phX*!bl` "^2QhQ'+땘t+Du gnyIglBrUDT~N67GC {B3zL>LRhY2iZQ ƺʼB:;`0I2g'Y;bTeˈ˘)1TUe(+eER pRRa7O|BE Jnh=iv&c2ڞ $E%q3no2UCǜ!ES )BJXSL&m3cC yS^A Fڠ)[c>&( gmY8gm7owo~Uύ4[3 1bq M\;hH7}>pLSd cRMk:E? ^C[N/#b}_e^5;9=z:j=92x($`XC%!r #qXGMLkZYq)bO G \SH!1yqmL2PAL%ɊtՒ.L2Ln* .1$('\e1QMAY=]:S@LXZ|1Glub^6WFW›sb8l&4ВDȠFJF'8!(хHB'6@R/$b&u)ώAmNW*IAp*C85@VK>'3 $PTze4!;zilr {UVSY $/)eXH5 JYVB%ˆVնxp8ě4 ɀ@(QOB] ^:k; EqjSmb|nK(pH$ŎrjMjTeg'>&:;AIt"G$wAӡTX,vcj9D\ ||A2uGLIb,Ѵ9!I8c܏^i5h;Ct7K lc;0ݤTO QA} 3ot]&W0Ӫ+=OKʲ$ R]~|}/m˅ۜJ]SM=PM>[\~#sB.2zJ&,!$>Ch;ߣLM۶,p%n|co+dk W'DwZD)=̧^Z ܗ6O˭)3Ah/ga!%[`6S;z4eks;qK`S@KƳ)Hԓ)ەS/Ba-2Ȧ3T^3  9$˾c_֞ ݵk0z aǒk$-'Ӄ27F0$t1bR"&[ sKA1LNs nOkNMWvjԵIM7Ifs[ ~Q6{(1|"b d%;&%7s3L`%qw b&&eEˆsL:";dXukRH,֑9,\.rxx^~]VuSKr*_U0W?ʤ(x2JaBQcJCͧAdՀNHTPyOU+Vdv [OH8|,n vsC:Gs$^/׿ y>85Q{r~{_T0t>ar%y Ġ]i@f FO^5s'!'u2Y4@'+)bshC/ c-!iܳM]%f? nI gr;#jX(|Bd9R<)%%Nc1`P`$ *Tc !rLJ;>TGP>-*;!b$!~Q%$bN9~1b'Y6CDAA=rBl@Rj0&DQ*x|xpJ潳+ RռA'$LT֡t>g=[2+ۏ|~B +j[q Dh*8 :01eģQƨO9])Ak9ˠSʹPFsX3~eFzU*zHHX5j,<!eD8&ItԵ㱧v|>?>ǿ/..?ޝWX?'kՒ-!FBNى"㫊ǟf|iW_`w>.]ڍ;$m1.]<Q7IªI!hU娼|iAbk ]ɝ . #{X:[e#7y=<[Y@{.rm4Jw~3HzC*|SyCtL VziəZ5:6Rn+L%*~uA#1d xyƯpP{+]]TO_Fz狘2'޸3ױuN? 6lmzT)h[uIarq-1=^P(A];di"B CBD:db6nҰs E=]π3e^ԟbcBGBan̖Bp rAPmsTQc-%%tS F:Jf>IIG ydFa41 4RΥBLH9ZkM􇯻'`w9Z D& >:Vt6CuR=| KMٚ,xl򞌠_7fd1codU'm`_)k U]Q7 M0LndB4W%6ɜ7?cTZ\%@4 P)x%Ї7hmÓ0ǩby/2O߸in+,_"uj9ǃGG- w|?׸pntۯfy%/ݾOpe6|/+ Dqe+fp'x :.g\ LgoPCe>Pw)gk Z񬃜EKMѯ={[v1.%zֆo76: zM5^UOM (蝒zueIЌKcf ڔc#ݽt hGzהx|X<_%3Xl(ЃWJb;j]ř*[s1b J;@f=v~onr&/2Xv MV]Er2'x9q*\[-җŖOΊlmMG/NsD6k5v{8 z QMcOHS<M=\%~>@,b>"2! rBի\[818 l3NW_Eaο[cOg1qǨFO<Ԩ_wߡnj&!u]S7z.n~CSHfĥ74cR+PpՃWY@%6'{6?Ky>-̦>?/sq믿bqIJ,f{a6Y7w—-AH/,D̪fokp3/gfЅsn|O.=+{/e#K&bcy-v!gRO3V m2F ^d.}-6Ġu%)>/ܹؔfemMiKV}5k2Qs(Xy6{YWYO1⵶ 2[:߽_[We/d\V]pٲ qt0&ׁ Džs Ν}u IDAT즬T wXp׳{eKLtC.Lqˈ4 )!`;!C茆zt:!,$F%I$FH5@ 4SH-=f`]>LX(ʂ&4 C;[1_.8Z9m&WHƯW- HtQڈ*Ceuro=e;gLMJZX]\vx㨌%ŖKT1i2M ւ${Z~0hN G^VSTNyWݽG?QR 0(GBu ܧRVRT̀Ha"g#1܄AX3WbPd%78눢+<: (dnUzJ eˀ"A #(2R@rʗ27֪g^)F*IvXLvIH=9sۣ` gXQ2N )0I)Dؾn(ʪ6DAJj,wl1-^"WCKʽ2/?wB2$[ɯGrFsͽ+t$h1^qH" u& L?y<*p~eREVɩ:y;#:X7߯w,@~'@;ח^|YקլgdC6?? ĭn=4ay#IÕSuISSU5qg˼p'WU8o9:^q'Z;\q׮0My+/꽇v,W:w'3n;s|ן};/q+\YY~h]>>u;[|&O})&)_14uCU7\qǟW_{ 5H`%yxxa[מj­1p~˕[C!m^j1 Տr8J ϟu`$7@9 8QRxOgdez>wS78Ss٤15GUlY1aab.bW5FZks&ZIJGWPBzj91cA_8 ~ymAIoK$KDG{"yR(eSDC+hO+oƾ_ݭ?VX5M_#"ynqvb٩N~^WgM EJ̧iMK!'Hnh1#t{|+wpƌ)L9t.Bzq)kns8_jO墦=Lmd1 ,p~GlcYuiJRd.;HhEZte ̶Y/Y}MtIq0iO1 #'Q%g[Bwkt-HFxuQYKBcrɠ:H!ێ6ttf3sU)DhYgN9887XV/?-5G>f#[.mƷ Y9?S3/H,3wRIC.bLC Jv[2C^'! NUBOQaDSj.S%>$%&jr5yjV$ &9:g8xq@,Ӎٔ>}8d%x~B]K̅ZD3ނ}(PQ5L 1Oo;5u0 oi]ۏ+NW?w}г 1~P]l|_ݯ?.G+GgimNt,{6bdqi;XK\<_a7'HYl06.a-xEdz1Hғ2qG{KZnIy j nd2+#"gq{ě%%B2.lG^Q9 zNi!Y^swo:0t\iglY.;q"I“]iL,Ȉ* ԂMM٦V7gs+xwT9UHC,J&ѳEe^$iv{sr 'h(5l+׺|ˁ Iût^S'1k]'ʫJuȏ>'dggg#!z: BGUUޱ믿75n߾ͯʯ?loog*1QM'H^)3'J+HԠEVD(6L*ZUğen䒆5dP,X.8O~.l%1+4@1Gר1r{޾.juڸu'fo Bʿޛڵ{X|f?2Պ?`H׃#v{V-eM=W7O2}?(S׸MYy_{@Ⱥ>asi?#1Dn޺YC76/pȸsW4uIfMPU]U7L!'ρo7U9"I|7u=*咐S~/miQUGüZaF{Ek#%1VE:٦jd?=$b>'gdSDj|qrP}22S H׌lFtuqkH8?FR烗EDS165"$8ysk~ꟽ_ZWt=hT2,>mg)lFq9*w[f@EF ٙA> ΫZVvoyƒ#%he~rkf3*ԓFZSBOE 8=3l@Ae0Jq$땍lh֙.j:*B bH6+ڛ;jpl2IHjv1@C :О#GL$JNϫIO% xbq5(Rh4q%uYlg7͛("oկr|~~ckk(ָ쑠5#%*i.scG !YH! >ϛm ٰ4:kXp $QKs7@I@AvQe֩d/BK=HZ&۬rЅ.+`#) 42Tl6z))Un75gKW"31+=)\H%{GRbLh;,o5Ɛz(j\+]X|n{9 K)ڨ1Z$b̠}>mL#\Pay9U~ɉbNW f!dޟկG!J(ɑ3tYI w`d\F&$+: 4N{ @Ff]2g?=WHmzU~i@wg)@\F[Kh {|'~W2Na͇L=1tq1_O8/#Ւ jj"l׾[82QWa`|b~rYBE4ح@{.àw*)k&hmb ͤj$O}dm玴msNSS?&`dDwbt3C{v{J6Ja5o Ú^xc1?fX.?{oQy~۽]&V He%AigmבG{WD{nQF[h7Ň%A  vΩSU|MHgw۩Suj,,L'#rJ^y!}EɈxx4bsk!Oe0 $8nUusFy2y^w;NW?yՍ>% "(:<{$7:%(8-jйF'4t8Bset>505!,% CsY{ѵ/ N6,5Hij~MV=Z=)~@~W0c9ŗ}3q죙cS(XLJW _|8=*7Slm "*m$gԋ/ M4eYsLFlP.o1nM8ue9pE 0n||@{TѦ5AF,TM0^@mL ^Zt^.d(|GւNX[P@kSh"xFHk"QiQ%6<ؖ|R2=e1X[RG+ *UYTg&ù1+{_pH=붑pOjF  1EvS9+pvx9v 1=J7OOq뭷?w[or]wqƷ~pN>Rӧϰ>Ns(b&Ç.n2cZi_pIq;KVZ\(6c'{/j8 -xo@0v[ uqZNtlmʠ3J⒡Id:GIEpJ4YȲBh pLP+w\aG|+[*!:'r ;JˬXɺAx;e9'@)_.P>"JpPC{O-gsK \Mܒxŭ)&rɌ+GUEWu# k0L,T$s]l&C:TߦQ ;#W$%@!NJW#+./Jy%$W-0HV$?Иb+9j\GbOP$u˞vEYַT " iv[&m9꜁~Êb\ ^ BT:rIN? EI[gPM+:b://vJuȻ]6L&?~N+mY`$v_Џ(x?eZNN@dZJ̑tt2 `X/A&i-`$c]Hqvwvlgj׿{Xۢ9( dCOZ+K󪸨TPDDvSΝ8q',Y X_ρX[[c4ag{])ӲD)- ue Fd9Z E ;chJY]<`4ͷC fL&:6 |$Z)Mhi0#ȡdZPf-Ϧ띙tkq = :X_O\}Ӻi]>UZ)%hW7DOE9;-KShQYP<ދchzy+nZ- _X0q%>x@J(\ejTkՁ0+8+ΝO5Nj1IM[aT&mBb+ڐLܽF+15&:h&Mv``.+8Q` ; )Ĺ꠼8&~qNOmŨ "yUJ!jٷ*kObܡLa$zxr* Q#Du dzlYQ7w—Vken>FW1ޚ0*WCp:WʩS+{<7g>lllk<窫;`kkM> 7܀s}<9K_ :uwݼȑ#|/~z^=}yo?Rp7_ZZJq7F񘵵5.\@Q 39J&{n-ΟQ[\8Wx-Q4<`uăW1ވglL Jd_E厊\͠ Cviho6_]P~ʰ#E~3!a-.fz^&qj0fnfs*7@fc N<7eT:6wlY`&'&3()Unqyv.jAk] 1 =V}N9.kK=VWzdY"_ҳ!~w11/z/(SUI91H$)jf!,H<kb ږSҶDcV@땯uf4U HـKC@:͈f{w>%|J2??*Xo@ZFTU)%wTD.pb]-@UUlf.lpS= UE^giХ)2h?&;~zKk,'W:֚mNTkTʅ[ *-nK#m@f9]4y(rE-' k_Efgq9,*UOOG]a狀!$PG_P.q/h&b3̒HX rYb%~oGWQ[DqRUTӒs'5f{&3NY 0ZƬkhym0!1zjbΝMi]"bkhZI$WZu C1j_ d-Kp\): !XnB5ݡ0,-E^Qȋe*d=DA,ů.;./pzꪢd1I 6ifU@ dΉmVb,ɥDh֝WqMiAOPآ)j JK@0s_6KJ#J_.O~quIQ⠟ɄnpwqK| txӞΟqΟ?Oqp'NK'|#^J^ײſ73Μ9{nfVI]|3gxM!Z,_<<7pw?Ez1/˒{oCCp"&.G @\ SzΜ[aᅤ='OKCkDcUiHQj*'>(}-&t4:MQ;xWy "b :k (*܌0(})HTM'8U b;1EB y:aks'ii-l{f |S]ǩ:?^w_x71A?`(Aƌ*saqrT_*QwzGPf}V~ktR}t@gQ/S]|v,eIX͢;E0FRdψ2aY´Ԓ:$Z+){K!Ig8Ie(m}4"Lڝ VX('ILgN Y$AdJ2D 1Fk+ )Q|^o4~VJJ&.qVemJ:`A񲗽ooכݣш{'OCw7t#w~~< f\QΝ;OOo>Μ9C^llxLQ/gee{w/~w)~7?}nQ mJ{rʡuPڣkC)P*gkTsӣȟbWaJ c|&<%Uam$_Df6|on^|Rs-L9{,eYe  8td\3rƪ9+bױStnGdy,brKdΆx?.$ZS<ݎbeGK',+0y iw('^͓]r5U%0m+"}8"}v/vOoF) YdAgN)&Ɍȴ2LMxL_W~qM7eYڃvjZ]3ɂ<6x"ZD2Z|v!梾Mw$FxS8 ̫6@N Yz ci9Fep,ѐ6]UVQWWTwuQp#\y>| K+K.a5߇n7&rEx ht¡@kF@%Ҷ$6kÅ9jI"_{SJ"o2zLJomdNopރR_6P2h }w"Lo ClǾƥN\iq"1 .b _<7ʲ4DKؿٿ IOSRLkd^.D-/sPN!\֊ig3ܵ]Τ 8ɋL2ɘr:N[ C+1=WYh7)'#A4=6=]+ ˻!EckE5&n/3>fgdnT"w "Gfyy n6DjukBCUd?;G*nI,\2}5nVh [y?XQ(.lCCq7s/|O|۷`ccysa& :} c +bssč76VVVN|~3hyы^'=zָ{9x g9z(\s Zkn Y hc$h-|YF08/^*wh׵EPi| t; ܹ#Ʒr b<᝜@9'T .>}._8&FG$9$-o:&/dNG2 h`+E`/tKE:FȐۆ@'E08XO4>\bYR$vɜY$kաd|Q.N:$.ĪYGUJԐ(e)l]:&erUy8D$4:]r)_wuz2. (_b$pH"Xx1paasºkgJlU~LA-ko}"Ǝj՟i1d"X.8yJneLGHT2!T:d4wBeW~yA0mΝ9޲oچ̵s.3VLS\ }NA|0o20uM97ʾ2Nd׎228=q1@cFٜ+m{+c϶\Ӷx?$Iq JuM.+++џg,~FdUKjJ*nr!R+ FJ{*~P- At[F>țqw-^mkʺf,c:6,Sق CC'8qfNf5S+2O(b48{nrѫ؟! πzLQ ?l9L-7UL "L$ΕVp }3 ȡc Mm!1!Fcs{6Yylԫ_Cl'DqjS5wLH˴+|tcx=>o3WW5XFCt;MZ x,`mqgg6`@#su:;8uOyS'Zm(,3-?t:xn.9OySؿ?UUq%p5Ex;ԧoo9|}گ/| ~=%~?/擟$ _o9v|/>=ncu@Bhuu= D: D'>'b`>m>GK0,MbIདྷ1u".}ꕜJfi\p\,HdHe["JCxگjN6q-P ̉sKDܬa;q(e4`8Y]]p8L~ueae8yUOrt.{~|ǾeV֥J1{9<O9q_y1;\p+iz.+<& miPL J\DuYC%V؅A)w3kJVMf#>̓g:u2Sߏk4O|ၗfA([ELOn?*{H~jF"JLWX"EŕߢC/V?2ؼpL'%S_3ϧZS3}*Y+Q!"{rvV:0-KQ3U 9D%Z"Rfg *FUdT5ʩf{$ < FCkpŸY6Hkxw(q:ۻC\Yb  qKN/Eg . 9{,AGUӞ syT5F=d8|n',}^t1TU5LsE~7޶h{^mכ=o({QJSUU&6J*}iv8iH2z2 t]d"7N6nϛ:K2yfՕBZQL5zP#dv+\%9jjI0ӮhM9*@yvE{ޤwѮF롻jäU2&WE/0t8= 55<]Ymf\$gNz*i{9/AB5Hs8.X 4`sG0Vя~@]R%x_Aߟ|7}SѣWccc gǟMCo?xG>\s5)>4DkŁtӍ?w]UJ`>{?;v0xAʲdww=K13Nx`W\AeEdOロ/|;]v~E_~tf^җ8u]|nQuv J̻,'Tu Ц!g{8hӷ)yO:MB fgBb*'sb#~,cL%Ev5 cgM yNK?(}삒kd3 ox,(#E~VA>||Kt]D@}R˲D׵\s(sEy"9h-,n.֢ LnsY{ZʪJ nbZmlA,]g!Zc .?σQUᐭ-a:0t^2mvbY׿p%i_ Aoy4|q}^5p@5Xk#^%$m$(_ggQn_hb&]NbۡJsJ9Oσ3A.fyGQ"AuF:6/x5_b2RAAgurQnacX_x^ֆUj[2m1ﰳv;ln㡯Kwdmc{x 'y(O)g@$"Jl0j*db!3 ϛ!+{J{\pډ__5&Vݽst D\x<۸jLMZ𾇧KM4)2gG{.yX0gk[ :xB6B *k9=N!JwbZiιܹs Cۗv0}BZ O:56#V%1@|_Dn4Y+ 4> BSʫ:RTF{U[xsTR?f#Z-3<݀Kbڠ;G\֧zދU BύW:GςцZH9̓ihv\ ..QMC 4FR^="M 4ܭ?^>?-P E# B%K8QG~G'>-2^=;^͌Ae"nGm0VCk3J5]h-&E?AOxm<vj,0o6)LKS{ _ 96j @6X4uõ[ 1Xi$0"ܹs=w]Dt(+г2(+6{4vG Zx/s\zY3aoPƳct]N9{ 6/pvwO9s,Ϟuw)ՐaͅM]81:M3JfKv"sӭOdTD(0~J LQ(2IC Q8$xYjJ}8}&RgRqm&FLZ;RX|F"'Cs)ASTvA y77 +ǛtsA~K.9=b2k/{Kn谾,8v/}KG>7<j{O+ΝѣhX^^&x%]J%1kץ( ]b?1,--%S| _X 2 ʺkBVH!"vE>ФlI5G|qmovVNRA9wo `Q 3"gY@I҆ಢ [P鬪5ZgA G <@a :j]Mj@-VY0C+bkI+.D+dINPuJ{<>O]OD9F8!n$^cXڥXIpJ' d*hE%w^~YοzWdZrpdLPͱY*>B"yef)pd╀T1߬9Ru07ۇxq~#yK1nF[[[L&:,--Q%.\`ss3O`eii)eY9yϸDD Kd Eymtx$ E 3"iEKK-zۿ?^~N%wO&BÊ[;CΟ=+^e:.ir!4|@V ,0ybD+Қu%-&-CVZdYF]?qm`ӻyݗ7 t"IS3{:j*u;'1U_GH1w9mSfL{r:KNnȤȵu) Q-.)NCוC9& e[O٬Co4>AHs@{m!]OR74inTp]#EZv϶"0[f-2S=;_Kc@uŒ fIͶ4 Hʷߌ.Xg{VJ5B͏k? )J k6^MٻQh^E%7s&cr#L [{ldE>r)2\uW;%WQt|]׌SvvFx!wG+JMEQpȑyuug=릙kVWWy^sr3q񒗼p̘>ě{ oﰻ;s`.;Bet=02|!i{=j|?Gec@G3]w?S& k8?yn&R × <@,(CaB3Z \*Z` AH0|9K I+W^KP,<t4$*[;TI-P@Z'EJ6oj!*(ΊIL(渚*'4;Yx3G7+An&<l0EYQypIp[x* (Yq\t`jt>ͺ`e&&ѠT{,_!pf~dF4UDN06ԱEh?[;gk9FygԾVMPuSc*X{lF}^iŀ"Ojdqx]z.E./$t:ʲdkk ɓ'y衇 Ί5۷5*677QJ%K 7_IڀtsJ-Y}"d>|J %.L&8pG2N)=b:c29vm=S8l=^+0m_@3[B |g\k*)ɗ82w!fpbm [#UR8,Vj(q-n.JK I]o|̯ġw3uF'. )Ґ^\k|Z4@beٱg8ZZD)*@GTXY2>F`H&)FV/YV!' $6xו6 Xy$5y9wO|7'6z|'}\tE G}W{TXq t~đׇ lj}&M}Z M hDʴfJgnQimƈ '}Q9u#W\:M])e)e9b e:u `QEDx1afth#svvvDMy HhsgYZZbuu51굵U.O(.'.S#&1u5,Tj:k1Y1Kc.dD]mW9V006ČW9BmBaf;VEؠX5įUVB@)uܳ ZTf,5Rbeh*Zkz.^w\2fvcc׽u%\[G^[VVWW9~:ַ,*x _e]7Zk gΜ~^W y%\ﱱ>}}C<9ѣx!7x#\s 7] .Ǐ__߄T^,B``QS1ŀJBXI֎GhLqq:pL0# B5P6|ߜO;,XqՉB-+2%t.Ǝ d }cȲCj2d\QUePpz%iž5 .$A{qʈUE:ږ \ԑ6D>4?:g9S5Fge.`\gb!w>LP9$9)s Gc|Ƚ~= + VssGV|R`"n- .;EQ7QǫhQ ~S0V7<{?Rdr潭kʪ(  #*{PZǏO|briiԴJ| UUYDۥkN>ӧ,R|￟h =C$f2fyyY@63LR@KJHʼ%Ȍ3}G+&q!dpWJer/ 9>G/GU;Ξ9(:u]1,2XjYt0Ρ h^gssͱ'p$)zhL xMyآf|G!Z#QJ*r894A $ʲ5t8ceF;qTk h9r's>X8Yև^sBZ2A1t͸ydŧ%}0F/܇Ofn_>3* >r7"Ř=IhSO$[V_W~J\ZъB֦o*.0%(- knzS}Z@hp/47H{5?EL1\ż'eW >QPG'>k])s(eEEl10$`0ŗ&e<yN)v:\uUx 녓JW˩s x(r:JR"?vUBbi$-D")mOg<) ckk{﹇zTV`+ z + :+KEҠO!/ :SNL;WMLT!v-GT1iΖ[9EFk"dX6?Ô 3 LAT2`AX Hݺle8%HpD+E5Y3y>5;/ےeawfoUWuuui-!@h Br/aP 9l -"ڶd#$%{;{{Zk )hm6m[,te_# IDAT'0dkk 1X|ׯcwwD޹1n>52}hr+$wQgOt.RdE!/d pQAs~ 0nʯmin:Ou20}27}NBjZoM[JE`ұ>exHOlV_Kx"1%Ôrx1/ M^2灱Q@Dh,G@ <n4FE. ;=7y wT%˸|}lJjH l@ֵؑ'x'qIACZPhߒ_s` rgM?=Īed˜t|Yo P I#DU JI^'TFA &%OVgm04jhpLn:kElV({{uPʐb/5>/agwprr_S׈1,G(G?JTDYUQrCEW^`RFeDF() -UW_NTГnO.9a[o'b\bXaQט6q6;dT`<cp`7탱rt׷1QVDY,O{jJx\aX$$UN'SLSU:" € + O˅N듟dqA{?=03>Oi|ӟƛog>*ܺu |W/YFt;kw`1HVq.f"\(CP9Q0 A$Һ8N24 wA nqtpme5& B4E?(| .@R9/r@YJ!G$74Hn&ݽϡm@TȀNYԬ, Iy)8 k" YH]+\fWAqР  (2ǥw"=?K"6@Oa&Lpp^S:@Q"B\ Br}F Cu 'W6&`c`~MD6}^FB$O&mۢk;;I=*K|L85b@9a_u^H'2"Gf'&s}ӿO|۷/~gC\`nk2w/Q2031m3yP0x簵EO=|0_E,2n .[U&CtW! 6j-T-VmYjd5Zm@ 4Rk'*ce EQ`TU(GFH2!GFL_~%@r^N#jVKu-y-1 <mRzmk)iK)@ BOMXV/mB{X NOg%>WW?kmeY,+ce}??;wqt'Ǹwxp|rӳI]6aRU8<.[eafpۧOh6?~ޟhNu6ˇNFj԰AO_)S*lrYۢpkץ ( *  110*{ | oͧ8: 8>9 7&LƄءr8[b$x8ԡŬmPZ'C[H{柳&klvbho;*uRl, f`z͐Z58> 6SuP. cC"CDY(P 9`ӀN )((wym귕^~:RA[X0 A5$2 q0z kdm :هooD4ڍSzPXZ_R[| )~?ٻ*\=[gX/ V+,KMdxTdx1Nu!rѳnQ]a Z2?ll1)м2Kt\'FYxb!BAQO5L^xT,= _`2*1?=; g8{z.qxtG8p|rrNa"6%D ޴΂L^y~ YGGGyO8nݺEY)J>AsX#v[ $Y-섒U2\н=Y{?הa2 fUCwQMtʗޗmR(O"[؇e;'8Q6Ep 8Dn lBhDa9xp ZKh2Lnj5FdRR5EVQ(xB>*"sblO7~7]'~'p^)5f `CL=nS'-΅L%mjTuN,2|;r Q]ͩ[d qk7f* ,`1fձHGƥ`|Ԫ"öm-e!YD4ېZw@c\c/B4e u$<ګJ/&cOZk i\c+65JA=yx>۞ѝN]RĿ$"XPP[qK~%AQ%#`66¾WF- j8E|5Ų#Gikmz&q^W>;?CQ~="eD,ND5`B$ ODxgaI^E'&ϥM:׭#^Bhla𬏰=FBi}C;)O^w6iH}9)hqUr0rxF7]6cw8>a"ۑ=%#͵̴:/Z*@4.=ϱƟwaKuҁ%\J-Ny`G)t3K Jtf Bu+A?Zבl[kJn6z-?hiO^u`ʃ2?B̌?CjC~񗰻wg}ۛ(? 1b~>uSyS]V6|vc Jn2!tb_߂;]ʲ+|x[w5G>Lӵ+d+3-ŅĬ(bbƸufTAHSU9ꔵIJcM!jYB$ͭSS$h4E0SvȄV'EQ#U+}>YJTq'S [z,42 HvREDPI|Q CypT DLt$[2J_F7fk[k0 ֽȭ*D:8fz=kҵrSFKGfN7CʾX&ѣF1aDhlYف)]?h޷$jdr?fRzĵҿ?iOnD.㍧o:{hSx#༘=@|B$Aܞz)ܼy!^:؋tL ۉ=7_0@d@;V9Bg2٩v`l !xs!!Gl5y YLSiqk5[QP q$) Dt% @k6*Ȍ"C8ua{ <Ģ@ۮo:Ș%i1=Q-x S$]K8WhbBՈe±,&A{,YcXAb>c뎀`! WOQZv'p{` e')9g lp0fK69Ь&A.{T`ZpL7Szп'Dn}l#kI#yw|~/} #ܽ@|=\v'qkn`8ػ9 sX,htѨLN>Yߦo@ޝa/K;{2YVϹH@&UUׯ`>NZ> t SM=Uȡ;}w1r\(O]$0CMqGT=0H3;;E'1wΉWiCYؚL0JxO؟v{ی'"0+v¼jAɢun$(BY 4K8@GxPNOs6-sDo2&hjpwX :(0K{I2! ͎A@AhPS?ď/)3QCbUDwco'T@bp0 vV5kvl$W9/J!ꍶԤ`ٛH8 UZh6_,4qϯm!}sD<Gސ osWߏs 4-Ъ;XSu4 1Qƣ1n2b8[U<*@))2ijԫ%ï&$?\G~z1<#++21U [UUJBA@*;Qv|SV2HAM{7@1l(|^XX|e#lβ+ăGb]Kd?1Q@ĽYCEXL4!)o[53sgAfwOBKj*+b4!=r޷3&"A*Ch(@&SN111S ~m'(4- {ӳYھKe4x/Fp mh7-~6vv1]D[[ΰXP%1_ppv6bS\58=K{(K߳}Hǜ?FP7., L-—%$/9k 205JA ҽ6!,Иҋx)؂ll a|hN[*]p8Gh8[; kaAX --x!) X5rw" `'^b~;(mӭYN,;$#8d9D]_`Ht^R"2ԶkaDʣ*qՐIlBePG IDAT*:gZkU4xƼij}*g3t#WBeAXA95E~ NLA׃j 85^>7b֟O`~/\M_/}M"pVF34hޗ)QTsUi /,H{hF[ iU]WB2_0yܐI2L)5P#ϒ!Yp̜m}n>ݬ}5Rd~~f6>!̽;\LXc:!y *:» M5cJgMt'ƪ% t]nGL+ pb$0Db!wEqIH^Z#+$}t`U h6U\L<)n(VϿF;N.Vsx}Dá E"/D#hR wߥ5f~J.>{?`|qF`&lmo|dh7a2c z&Ditm 9?ә塌^E'#+N`l AIQЛ[ZìFŹ߇a@I_S>M}T&~wq=#_3\\p&@a뿴0'tyG?S&_?o0NOO CR"£(Je(PV|1F(xŗpcQdAb\FhUK?rGzXrC}P?kl}cCZ hp:R D\BjmSa7!?ol(!3{$ؙGdtH໾O"1J@p: H2H0X@SAaVC\,Ev 1D- Jzgfj|3˄œܝ͛%4h", < d4b90Gɉs$"Grk#s6A SQa]^tŶ^,a(~ ?Azv&L[,N]0< y[B0Z"{C\Ⱥ(xF0NHTWO B(U%ynx nHgvwqSin| Ky]}t}2dlwc1_`8;;GUU$9F=loO 00XG1| fF]M+VleYsk@_NuKmjdgE,?%p +;c`RExO ,kyxĝU@4hBL-X^"-ph18hzU+=Ue^/{ɩ7}@BY[4})twritJ9lŊeլMۅASCU8#aAfFq@t).O|βWz=p%JP1X\G!6q{y:po[_=zFگcgw7c5GM =ʪDY( UY`dUUPK q_TCNb J M>乧"3s'efqiڴnZ?qB8A u1ܖJ>&Wu?P!;kqLxӈL1HޅE'ZزDw rW"~ Y2d^A-*!SE!h[idi.Z"Q]fIJ)3░A">,n 0w"34=[#'9"$ K^1́-]Qqp.80bӉ[ e Uǡ*c-1?;zz"2Rg/^kQ8s48){-M!` 8ȺLsM$e#=um𮔓ӞS7 J_nj4MݝttؚnAUU~`[.9g.OFq}!2&n<yﱳ3Eq6[୷=e9ԓ('x! EUab>|>rr9bkָb{7~$A5,Z|8q3@zc}FSRE zոJM?S}o{UN2~C<-\2`K"v`X?Mf="{q T%!ϫ?Ej33ջ.qgݛHMKX^og0(OqQ/rmM'֗ @_yfMgnߞGO@B*_nσr)}NJWDfA9/j?kǷbE6rrҴ?ǿ)`GQ(KA Qʲ UrTXtrr۸q!`T6瑝"6/şo(n1H@HA-GRY{N8[Jb `> |Nw|G.:I$,݅%,m)ؔq XHm+K|qbsXwRIӛB[!l_ҟ:XV/3%A)`1P+DLMCaZL$YjdRmDN͟`QV1* .t`9 yv=S`_ qns.޿8?^uo4  #-PT/1X5v;KGp0wwӀE- ;տî]}~p Fh'㔧QN9`T",sjrt{&)Fq ( q#R\ Jy?өŬ&βW^ NON0;;ё,O[(FL[◾gn 6Sԡ]?>GjU6U//=\\@d()sL1^h5rf dB2.IL+ .YW0L;T(x;ܶXYnT@E$Gi/\ʺ^6`=,`iF H hP1Fi$) .lYS9UP!,rJF\PbL,Wb$vESp 0B@tVYHOTW+Hj90XSߪ(8"DHAДl8mI3n^ ,CFG'<"_yXwƈTI#iWDa9>e4xW0K 1Y bB -e o& ڻ~A07KwTU%kCԆe)YL&ZS -82͞1*TX)@Y}bNrWuIUS;QU,+LSc[ژL1 a4 6ːx iPN(;{71;c6;G:ɚ#{'Xݡ޽{89>)6^ jUnVj;sdN"O[MӈQ@" b8&BQ\Y~!%p}bŨ]+i@O>IW܂Ѹ0Z8_JE4CNMQS3(b?qG;Pt7St9kX\Ʞzl\(g-]EVz~[O]]0ƛ~_^(n+ON_:Ws?\ozTy}^afoǷ~GQVGUVXV8{GGWqb/l\ b03o~ARb ŨfLhBN1&Elkdy4j`Kc LBl}&U瀢E8n+HYCtlI|r̺insu4u.,Дt}ӛlugŠ\,:5i32,d sٿ|g+_Bokli Z[D!wϫ=܀Zl[?7Y\W_o^k|\*=oW߾˭S w}weY"-*UyZU_ * $glP%\DIJ(R,E~j,4)=:mS 6(r ЂĪAӃ)erEe]z'Rv  !PyG0B Miq6kZ|Y݁`.%,6,3w4͡&X@gmuA몤XB>6Ȁ0HGtCҮupm$OYqUDhĘs|p7CN7Ŵx .15`*@XH4 ^:ln~刯f~_$|-kE+Awpл>P= x*+,`3жM怦^a>?+78 тc}yL+ WreJb<5-d599ODd8\Q^۶h%|soXk sġ(JJǨJ nnbQM[:,?:4783{NE:0%+N/kDRaw=rKH@i&a4i?m<5}^ڗ^M]JyZ$$3 y.P;C(v,#Tè@Y0${еrS$3"5Boz5]Te4=}M&HiBUJ~m0s1j@_T kuEBz/ ׿C _mA.nRa20h !FN1P%5A*Th'NtyANm Y|ÎmyC  z òx6Y;N,*4Mm@@QQ{S,SW F2WĂUĻssDU]I'+fдjm!'s#$urN M|%|a`~_#?u ( QǓHQԬ)ꆒ،1z=yA[9@+ #^>KE;`^갋1 8˰3_SmjO|oGYKpZmۊz\JmpR*p9T%E/?!Kh04Ph`){TqM{5x'r]ݻ{w;8<<)b _1a \ۉxZscTJR)r88+swoe9&,fԍꏤvAg2pFc{<ZM}+ 8sm4'LK9aH(.Yd?˜Y/"_sN.eknZ?lu+H¤AD>Uo90f8֏̞I 5Shr!XNy.ks{B(7n?qzUlwCA_ ˊE@ EJ*ϲ brEwGX$: =Bq"4B^ 9pڦ]u(EYcL.ޣE%Ո2AUOV bi$!DAJ9[ 5ۍ!K+H&0BℐFytFՔLBگPB@9P EAbz$PdBsf;asGxNz8;½gW IDAT>^ hn,[%\ ϴxXz?"(3hE c8J y~7ɿC")vtܷ3D }>~{ӂ#5&]3S=\$Skڽ}ry UI."b7)_.=_ )A!ퟏT%p/92qp#vw񸋚_Wo~7as5U(uFD/+*C6LD k c5'P8V^ -;'YLto6D@@A|.8iOd{+lbۊ+@33)&<'IQǒ=Q3Q4 Eΐ&u'1s'GTas=S *'G'@$f (LSFD$GrZj;:dŁ6vCyn}6ܢnc ޚ` SDV@Yao5of&da&j\MJXަL|oD'^fTַ5%;5F{"wo!_%?8kcg};1TcmYn@Ak~:=ZRRJ2|4͛c{pzQaipcA}Fl%\n 1M$p ,k;'3 G5!JpiJ?$cwpuLGcx",/ {qYL@1( |/K %}ړn J3@?jMж  $hP%u^ɞ'ЇҼ P?б)(JZk"n2Gk2zzo~1\-/}D#{^Cڳߩ? }o_mRO= /X\2$۰(s Ō/įK+>׿O|DžmyJ(Q;LIAUO;$|f )(꺉\R ғE]|*9bm2boSY=78$fiK78=  `2=GN%@9ci{}:t!tcd(bAxN=LʘE͞ uNywb-`'"G@ 1@щU/){Ox͔!/>0$ԫ@}i UXƈkL π-"@%+ċC< <Q|?l|}rvQaXhIv jHB6YlD"&ҡ@7ɤ^(d~}j1Sғ%3NZG)3XOS`h,KZ=f 5dA]?9p2N߉l-)Cwl<ЫC֭=h1_.`fmOzrûk|l?VNNN=l+@r7<*`A/f`T)7HU0L ;Q b=U9i#wIA헑Ҍ#%n̝_#*`(NIsق[ OICC@—kL!O]*?B#:sТ91"IqsB'M dXƂt~{@]Lc! wm \d0" L9 9"?!_jNBbw߭J΄\>>CdVra[aՈfѢՔh}\p0N7sl6ƛ!E6(8r X̗(KU@=m=Ăbw$+kQӪȨuB۴(*8WifN]@ඓ9u>jZs_<9 #\'\ƅ>"͜1Meu%hp}} =O\P[߇W8 %p<<ܓ86 Cu’O fC?|/ gB- _D{_˒{8ffefueuUu7mIqe|`ejM[<<`llE>0()SD?ʪx=D,?9)+:Y@esٱck}ַ*埗Ec_%@{t^Cbo&lo1Jm :!ji핽vu !X,h&٬sWᄎԆ*v\ l"Omu,UB q×t?nȏ$*h!JwEP^߉kMTMMUnF}(O1K摠 n8|e&o[$u Mk$Т/[9rw`;7 ЦYC|m[|$^4)@=$qrHn1k4GtIo L>ԊGh(qMP|>g>2/ϦNTlN51͙MO/z";Gb%}~3[ Bhh`Fo[2&o>mnm '9J-ylfw?gj0keV{^)r/:=~[7n0hǏspxH]UkL&L&łx̝;wx:8 TDcڦakkw#s[[[l0gӿDt>g?ZkVD.O"@Ӯ*,IQȱ$w'$7XLTX8, SrRC,sH _+1s`k wTXk<4cGOo/h "TcowWn;ess,q.#slB۪0.K>[|=>x>Ɵo -3l#6[2ikXy=0 dhm}P)DOB@5uK4MCS4mCb2޵VaE\$FhKc2UC꜖傶ڌ]g vyU;F}]^ry=k[K_k/|y_ >~"h/Ϟ ~~Ni?O~~륏OJh6)\ ιipK|9y~K ˜_o-vϹ|/э.-_XVh! 49ӓ9Gm-,f {#\om3ʌ݌,8'ݛN|+X'8g1Fΰ9$'"g6ϙΦg3 69bbtʢZi|Dzqy]{& bUޘwg~}EFo)N fEZZ50Kj9e=F2A_sZs=;W83͙tzx]B˭7+%FIpo$%)O<% sxtt6Yݻw١( wv!2,[z*8aQK2iN߇V",Ӝ~?ٙ 3~RqViԿ}[h| LO}iMt!676؜(XRާ[r'd.8bԒ&iWy j%hSA 'x Z^Ĥ}WJ(,(##޹ͫeccC:&wHuMO1PN&JbÏ>b1-Ʉ,/~mЃu}8>0ݹ-'˰!F•U!ߎ(KmR1m0ta\1(ϩt&{wƄd(_;+Y ȦZ2hoflr/n_dR5 V cUy yxO/϶f,msuw=>"kIuQ3 >Z\,/X.*& ڿRq埗(?Cd:􄻯{AY΍MQ-7Lx42Zob{k#'*$ny !O,98hIUU'bNO}c4R$wIJs{1*Xk:`Sj!DO9 )x&8tbHrI|4Z%}MsyVvBsM^0 ן1'> u'Pߓ0O zJt\> VJ&xg"D1##![''dyAjސ,Sf͝\(D8z8d2 S|GG m CSofȱpm>|s ?xm89# UK@"IPuHADbxJYZKM 9pt|3(A@ѵCI—Ś"%S+vX>:C M` |c(2 v-Ϲ6xmt5KZPREYt<3`ߑJԢuӚb|E>&/"!O plDQڣ,GYv5Dܶm7ͨ>ժ+[e&>9y"!u{b6CR w,7w0*"d18 =hqmO۪O>v<:2<£UW]$KgUmkꅉ(JmF 2D`5hnxeo=ƫe "VZQk趚4f6(=9u&\@b7Ȋ [ 2ǒLvn:|+B燄,=EyGBZ5%+ϬuMsໜsu)|"/ l=/qwg7_@0:OI_H/:ռ缠uJy;']SA=Sw\˿Bʿ(gO*s| 35@"LׁPdۛ#v+֓g꾠yܰ_WC`w?[loWRAƭ yn)JƭoUyKܨs QKK;\tIRZ&] OcxؤV QyT $ +jo:|eY4*GYkx9)T!DRSD#KDY`2 ÷. ӂ䡃O8 iL¯D7 &tѢ$Q5(VE+^7k># xcX4Z3gԙ@nXn^/!豽ʺl㱨jq6(Exix lO hA 18Zc0d\u{Q}T/|maEk m /blX͵ AA?y E$^xז䶒\뺦߶<~d- ibbXRk-[[[];Ched#xp@x:54 N* ]T6װk6m5֪5Qn>xGI: c5&`CBP  1ף;aX%Ǵvh]RPbD3Gg:7qEIV%%@EڃH| ϳ{ܲu3_(=s<ɿ.ϧ*,¶>޷Ҟg9^@%˺1}G> _9Ҫ2@8'ogO[վ*?J͕uk5-mqM`YF1 vc`6F- ߼4r2bl>=FM,Eo}~7Ko7Dֈ蕿+7v`##蝧$]S_ & T'#iD:u[, aqs߿/u‰J5G4`3`)r ` H"joy2`3$Ax2G@ h&uzb"Q%Hџ~kUWҺgDJ3aI42͵TPС-Mʼ>O"VY8Qpʂx.;a0kHۍ0sB`3mm+j|CFSsہ͛iDo%U mj=uNh%buKy{嵿vR nmV $FJkߧ_s1Y< x<^o8?I Cc8>>t H ,q4rTUᅬ0Lmf>whW^ݻܼq7aVNd{gheYֵ}(IH۶ W?`{k0?NLu6+,FNk lùПJ7>:}cEWC ~,n ;[be626PhCw/TQ/[5>#B7%3,ڱ:k32Zfx2m`ME0Yj2]\q9vScvvv[CVDP!u8ky֭m9vAXg]w1ewaVLʢ`2%fyΨ,L&KĪY*uPo0 f>^}{{a1=RLé/wcZ8G'85osnl6';c:<|@80._ \0]} \aăIH(q?HoKdq@MF|-*&wEhDE2+\͌Zǀ%qIRzYG1ea-z64+#yuE$dY׈dU4uhfsV>8G^P$2H/c 겚>g%?szsrUbjMrE:0d5y K D]+_Taʿ|r7Tد4~?nz֪s )2 `]h6ZRPT`l("M=I"@&ҽV]NY1Yg7hȋ6- g~5|-=+ Ch$-oe1"8#-GkaTux?G"HHy<cM$V?u ;SqsMõdpeMplujui@x 4>P55 TkB=U Hn[꘧eÇQ9}S?o1tPAXLouI4&S!3C%DTNO30MYg!SY,jF9`$9.#s\u<5e2S s<=kfShۖшbAjc#gM< x$ , R:B'^>(E($>~+rB"|RWv }ֶ[-G'n?Jkm€3A/ 0tID ((7.m ܬF]z  &>8m&2U8L |uGm-R~xh))xhBʡ2)F.ş3*O8<:fccal$Bׯͫ2w+ʯ O_N :%K5?;ɗϞ9'Yw"W~Glf?$Z~7X}FRٲ~(wʑYW .˿ ^u'nR?=uec42_9CCd.$ò _b@,GNyHx BPxlTU"vkd&m푑( _ +5>t "Ò9uIs_eha6 jUa`$YEdjJDR=1F8lf[G$˙^Zy/e(Ļhjbմ&Gn,׈m +6'EPh6>-]O"~v`G"W3>W# j2w)^^Ɠk?;=Rp露}Y7i^į@H->ф[$S/ˑ}~7,yC7k+GHjfq=;+y"EΤ,h7Gf:j6Oiꆓ>zG6#&'Xn6lu5\0V<8縹`飶XgGy }SQ%{666Z,iBZVz^R$C,Eq4i能uxY|iKm/"&eyH\BRt$AC1T5|t,|~`o#pwvEƥzüZ÷krbM6Uj ]LVLU ]07PBmaGhyFDQlOй`CdvFX5#-z uKۨ5!/#e9eQb9>=e6Ӵ .3c4|le42>$?VuieZҧ2J¢C-_;.˟ǫgET~Y+_zGWJ)) kWc;$vq?V3-Y}?<1|ޙ֦G\Vn+:GoM=1i ^:w2\LTp.&r(L{2L;%jbU&Ay0Ŀh.|hȀTr1tuR}UP6-u5e4}jsMF}@o1 Jg 5MzB0$Oqc6%Si1dv2$I-&Α"AVH)^U(4NC >GBEi _PQxiy4==¹ tmB9#t_w88ʬXBޫшcX waccG]{1&,!f:Lǘn2 $MuP7#i2 ɘmL^iH+|USW^p&y9"<1V bZ Āp a6s)O?5"A9<Tz9 ]MW?{Pc8jFg\krP){Ϛ6]),vq5<+_zL(tZu{Y'6+0]%E ŵy_2uZyV1W_\|,ϐg9O$cM$)sͲ3Mdiwպc8VoNvHC# JI}yB =i+@9Feg]WU,&OBeO`Ia" NcAP.6)q6H:5*!:mbD~@?IL:$nc/QKyFbwן%.^y6:*\~F%en9!'S2ᬣ 7ɜs^s.ZcwՔ,ƂGgoE 7KU[5Bŷo6.q_qnݾ>ۮDBI`#s,/Ȋns SmM3{H5]PM=V` lmrlnn⬃lkʁJ<=%`۬egg7|{0$5dĵ: 6@@"o:K?ÐmZsf ;xCAuF!(a,x&P75'$KgYh7_{fEl*#c̻.B:~d t4gJV޿dt|,.tJ>m=q$^QA 2R,΀3 sS*n) v࢚o $ߴsVa?&tx$)D 5aQ5̦X4͜Cig,&*Y E[Y@"bꆪjhF˰e.yFQfpDI˲!~DEfE~$W/e8!Oe=_>n@|N|,\K./ 8\_U:/GdPUfmy iO׹2i躜?o|AHfږex2f4[x/R$q$IQn[>xx _< H%#%tA/J$NDEW-&(%^JNF9[[q[z;*(_Wh~0bpBÇh,F`aDps߇(li2JKL5^Ur#V cF\I!Nv݉%yxX3F.7>+L5MH (k &ĺđb_:㓟i)߁i tA9Ws8Y ݸ8>Cl%~,g'E z^)cF|7XvwwI^9&c\ln49Y{KE ݊I<3 26m u'wJنt6eY*<"sۻYΤpu۰4MnKֲ5[EY Ú= D~Rb3GY6@CJXS*Zo4159y9BL _Ɵ{PWYˤO??~mLv7w{Pbkp:Р`bmFp.==1-l^ aÔ. v$~n}N$ dwI}hkbܲ[3NO9xtvI>tmuz-İGmy }.FέE#ä1S߈ӻJ譓jQ$:E:n7k>VR&ӷ+1>"ZxrB|o/GJW7ZO*=`h,F%y^QIck3%(X"O#,OZyPj{4~d[|,u0OyxlƱ5 2wxrtç1[,ֲ*x'[1=97Ԣi{>ߺ [~;cբ۳Z|L$UxCJ3 C: 4 K؀[7$66Y 0r ]m04A󨷢 Ak;7/!EsS=y$8u.1эx߱mMV7j5.˱10߸m놺n$KJC.$kفORK#4Ⱥྡ,<UY'V0I=[F17-w1?V"N [}UH[wٽg;/Y|RwC`.? #vv㳯{mikKߓVD ldw¹ȽQP[%шxx4a#[(,9F0HdMHt'eP/9=8̾Eur/630ɚ"ۀľ`M#&w oZ 5MH"wV!hۆ,/-ZUf \ATѤ5GOYD4" 64IVŲ F@Eq)@|@qn~3VD]3XoS1ptCZ/ЇL]Y}7}u}cf1l}>n1?/fعɏg?gnd>H83cT#*vv<ڡȊN)+w9:}u& {[LO#[D:]ۭ9dTm1Gdrc"x?pb()"х ;L:? Т.*JyD$bF"%}&3R}og3«#;۹z>e8(،J02k/__<dUIźZWާ6|b'TY_geݽ__^jXI_7&t<_/}N ϻvt(rouk(3?}nVo?dwg}^wmh[|,ZzC"$%()ʲ .R#Fe$주. oj +)I8 (ģ43UX~LOc}i?xgN0Js@XcYMEJGt%#h+ Z4U@'@I`V@F5( FRNAl}{fċhG'$(ZjDeпzP&[+q!x.FIhvY$u0Ӝg?W)q^!6{5]8~DF}AA/O$.Zn1J1ͭkWGɓLj&1ǧOad½Ͼw08H~Px4rogbɳ;X,SW5Ӄ)4mK6̫cNg3fՂ)7wnpce1ŌGjὧjf=, ym;$oж_x-nܠ,n(*g"뀨UKHk0l!ع!̦XmmqwwWoݤJd۟&2tu6 /Z{o?ylν{|釾agk-64,*e:ލܲ9v~slL1kh[S" uXp|tᓧ||޻<~lvά92Tu1s\`4E%AC0ܘʝW朞2iF<:0&qjMް]!`h=̽F/Q JkK|t\,2Kd)(R!큱h( <V$Y޲/hl3a,݋&W靅Hw="B\''sJZ܇t:Ɠ шdbAԤ;.J+{x:gϩn]]S_.9|OE곖/_ri< }ޟ7W\PЃp,ȝw @rQ׆ Z5i2m_?$\Teٟ+}}v]oh%fjOV<_^SĒWZhp*ငea VSᩙ17B"DbhA"ВH@}u"2Ur[@G~o`foc,y1 4**6I6R?1dܝ%B s2#Wsp$*4@V]u♛DR3p#Đz$h1 %B*u|%wA矞$s&b̅<@0ViKuyw:(˒,/YZv܉%-E`T$c (acgH\Aq9&3"i%$'ēY(r`  lx6Lކb.6i[OqsT'' Of.㹧nWagpD)qAIIcm+6,KS)n`C{G}j3 ynw`Rƕ\sb@t=*]4ihtM6rlQKg v݈(z"g)'U ⶪGbeInIu @RYXkqU ElXJ;jL)ZJYZR[)޿~hۿbуey"+y}!vur.׿fni0vEˑ [i͙gjzI|aa_쳽o~i ڦUCTdH'I16D+ C0$n3WAIZ>;/1B?1Gt8MG0Im h!QH qԊ<ќ׈*޷J$c=Qc`{ hQ GUP ڌ#w,Z,'C:XX2"" Zg(\_֟YBc0g^j,6#Uis$δ <3u[yz_Ka /&= I*Q 娤!0_TLã#Fѵ۶)j1#:ps7&"Yu1*Jʼ`kAY.g{;Mr2ģC`TlM6 jNb6,a2\OQ.ݱazzēOi]n3"/ F,{cգ&-~v^&~?z[{{[Nk,Elu[p 4-vn+JL٘82.327$~aУKvSR5u/G=nӓc=zć?kBFyȉ@[7̛٘L8;._֒[d!@FDcEn!l!WH|Kb ,1f*KQ?^eӠZvV)؉84ՃX>Ur?kw>f$s |ͣc_ŤƝ76ZWi=w1\ﺩcCjɺx(E<|r1>x՚(dh Nۧwx ٌhk iR1D$4OUr&IhrE`õ4MO<1MZ9><;ܺ}O?aM /=<9OA}~׾Dqz ;5g^Rن>OjQy"v זNy5!8Tu$/9w1өgZr1F Yd!89YYJ_L6]+-JmQFR*4uKp'ۧ"Yr`L G9ɴ$ -eI3F*WG dx8 (EJohsS**O!t )+:ߕz! m+Σ~JmbZd;yF 5m&)L$φJ;`7ּxb_,?x|}- gno{!qhD; ]ȮВgm 拒YɫA#bx`P%CCP],>E0)Q* owdEQP%Y i&SRQs!4FL /2zeRv!F zLк:Kq9=>nūXKR˨`P%!yM| Rz;WA\doڠf.x_ә r-uW"t]Tl!R*~lnFJ8OL_AOo~)1?? cFѨKcmYFeɛ7pztB!kRN8qm61DűX-/mK֬2/Ȭ &{WzbNUW(rњ>z͇q>;'r=njnܤsO';7Rr\~B0SG#WXjœG-$zrwzՆ&PRxOv"l> ꦦqʐEp>+rj:WVTFǽO1A#%Ny-ZjoߌioЋ#M#m@&\ >Zu7/yF`y!L"hxiHM\x#D·8C'?9>>fAz]qvqzb^`/K.qa D7ZRNu1IaA]G dT04xջ8 !q>)γZ(N-.׮e3a$N56 [iv߬k>hP+IvhD{_`Zm!сQL}(U™R9%ID|,p~&x^3/sC⾏+,v7~7789W*?~c<N u 4VeK}(pK{@wf\ҸrZѺ DyuCYdY|90O"˹swotOu5xؽ.WҶy^3{9nQu՚uq o+V+b ujtvi$uzm@;!`Eѳ%Zɖ[I)*iC.BڱCwOHPӶKT,#(O6ڱ\,K9 8{B"P.m+W*P2x3DZx`@al 5ř!#C[+Q3~@iM%:H**7KZ|Tq\<I뽢v&(*;␩|4K)MA8Z^E^zB(@)I<Ã}(˱R Doq5v)W}O_YmEx^hnʍI>Mj ;gQF?d#)o*ҹR!S֗d`IWnå.]{E9)J]w%H%koL?PDzƐJ7R4|R G~m(Y ӿ}_Ʌ_N𘺩sv|4-w.3ט#Ɇн_q# &$PYl,Eyz/ΛoQ7 7׬7 ,ŋ ȻPṶO^+_hsJ"xr|IXtB<\ۿ0"`e䣒QE77tߩ,+ vxAbx !:6˒b4b)O99<(8*nrtx9<ѣǑJ(@=sBzf\\.fg3A\H7?wHҔA%$ZA 8Nu5k L]83$6lצ.j P-!.y"CЁ=rBx1LVodN:M&tRa)+va})V7_oa.L~NJs@vO}y+.T H"CŽ C~prFwϒY6tEPE$B+@ 3)K]'?5њ(5>nae,(I@E2Q85wmH664*Fe\⪣¬%+tp˜%,J%(e@B]+B‚*_*("YPj_#KﺟB'iL9/\(qcATHfO|}#jjt`}޸g-xxmoʿ  !;Һ[oݿ7/v4UKh<)u+s, (˒x޵CO Gel9ۿ1Z3*FmCYNys|p[iFx1_BrAF 7XHո! !pzxB&_ǺҼ-3L%(I3 7) ?ftbOGO>|QLJ}XhDb | 5V`f~olŸv%dys>~0e!w޼K>pͷ()ӽ:f8=:`o'^H!.޻Ӆk[sY{1k%{ZB7 *bJ0Hk/[E ؂p: "R~׭߃^rxЊ@a S +q:Iut0+L^<4< OKBDv`%|`2k3KqF Xp mPƢq6e mbpγZ_0;83&QioSv#lB>QYڿC_PwWn}B* ֯WV>FoD7.rgF.y'g|\}m?y̼,u6_:_׸_\Y5F{{{dq bt1Jn*Uc o_pbG b`Z7Lx\Kf3Fp~M͓3޼q;(S1xv<@Eqtt@gM'͚58'i]"L-Փ{~} Vqf)&֔X윢i$+[UܹdB%n[VM`,| .;n{ӃBn&Z)4~өF^;;דijL8==e]P2i1xl+ ·1*KXWٌg\\X+\]k|-ںRi5y:z/:jF)E:ŻukEj %|A2t0B:ܭbVC8tm愓biVie0P ($|EE/рF ƉWI2BGEkJ;bVxA i@ ‹eXb4Qsmg8ޮ,/ p9ׅM#ƕ5.<Ž۲W)WɼrᅗU+~?wCK-_߾"e0?Ǧ|H`0[.?;%%ʣªħ ]E1Aʒ9 VR.bM@rYcTgB`h( ^EOkC@ɆX_)ڔ@)D#"eo` 1S$ZHQ !0ы!{_M`'59 ! Xy\ Kyjޖ;xN%с:hau,e?O.j5lR]R|0Z&#gǮk n|eR>\-rn y?mG~Yo>M̖ ,#s5b$8W95+2+ 3zMRFwws>'~Op}r{6(<4Ќc c3b\xl5M⽣i /,+&ňq9&rs̖spՒ|Q(e!?'w}&jA썧XZpOo1*.]u5xguw/1gYAEG$mUy^Gn}B]3emG̼fIhމ<ٞ~>`Քã7(9qNCt?|Jƹ?] )?,Z/f~Iۋƭ-K\lX6O\>YvߵV6m. *ZiTK.D֞paya6TZ1RHF^U@IL XiKb:f@ l$\%FlZamy[bhjEZ gZ75bҰ\91.Gek~+%s+ێ\C 5X`Խ BhG@8޵i<.4M`{T՚bjd9_2)dCaVGPXMadGf3yB֒CΦ!>wl5fl^ =A~\PkX75LsӴE ùH\zν-0!vogC_<ۅvROb(ux~X%o^2INyb #(N JŅa딂?^) {N_!HlR4PR$D :o {5SP|$BbHHZ?kntEyy`HF֝#79 E"&R]jb.>JQIFۧ1ضB|˳5 mɧP5xlSrݒ7y}zn4"`,N#n9~Fw YA;'cʡUFgX(tnqX\kjr ؑOPJx1_Qzd_fohã1{Gܽ6E!5mBzJ"4G V2kw[_%aoOHnպu*-Ro?¯1<,ۤB@8Knz#_HڬGT(-*z (k6r. RHz0DN 4Fscǔ,4ł]6ܮ ^賄c#Ȇ]G/ zQm8v'YTQEyKEg݊)H \<1Y$StTVDJX&rF1EQPJnݾgh@u">/G΋%&^ P#|m7RXl흡Vze{b5ܔlM,LG|,o~]bZO0uELhc;u(fk22eԌE:}&)ɴd<1L&<'2n|.RJR>#Vw ddyqgP<y1MH mQsKQd:G#>ْclaȋ|<۷x7o2cP<7GuQQ,Ξ?̟' ?ͣERx "~!PeyЦOY^#Ɠ ۖiiNyGۆz`,oɫ3]cҿBrRˇk~ņg|B^@B^p_˿xy*^vUGƟJY Y`@T 5 OvFN^%iT_à^wKو$Ŧ嶕`RA`.fc[ AQy>xt[P5>BA7* A\vNtTU" (|pd&#K|tWNR!|81 *CRB<κ#7t!7;<o"ԟu62YAfs)Z57NOy!UµkP=8wOLs?|os!ӑ!,˻ !Ya1_ydg .kzdXд5reӛwxKr @YeIeXk?q?SV[c2Y%Uƹln˒urQ1=_>z22C7bmǷS\pSa*jm .Hsibӑ!vWq] = i>][eI/di5몢+ꪦ,*x 죈r)o1g^ZX9#{r(LP w>eFrPm$lq P#KuJWIW'cOҥ%J:8Be';/ϲ^˿)Wϯb7M.kkF_ב9ZkP9PFdhڰE˥ܦTZ6tSAIKF#a@謌*HfpAdp M5:{p 'AZ#D*_ŘmbXV*fn B/<Jٮ-N*Z"ūCͬt&6ziuOuʁ+eJ>1sbw-m뾟8C~("B 7QʠCRbhUSZ wJ|0|+ ;~ss x_Z/vw)'gk m?ǙQ{Ͽ[ su`>?xϯ}__4 fKs|u izW st`b\SZY]㛆x#frq]x.n"OSp(fqQFz5Zf\KR;  d9#LSg9(ZWX5gOV4`w7ߠ^/8<>iNqʣ#W& wQumbՍ}PP\A<ϲ C 2&ɥBw3fK9łٌlN^kj-jbfXV5UEӶ0^B$CҘ:]p ]kS$/ Cq!e.-L5eI_Itߏ^>SrNYi+ Fy)|_>Q'=]f[ IDAT'msR~[O)i-Zk.,C^|箒~SIBl:^2sp ꕊX!еtκ ?nH]pV+ku,D*5gb4CVT@ܓT"׋WKPfuΡu"$%tUP:zh@DzuxA픣C1J\f@N^c;hm'a>߄X,Vuc!Wcw`FL(Kɰ]uϾ*c׵B7>m_|~])1!-LFV|c~|ݣ)8 !|t6㽇oopz4~|+wx!QIYY6aT'(%p YsLǜW &`LfzS<(s|8.Ii_V4n_ʙ(F-rc-(Pf^k|ېH_SZr>}9mtڗZ>|!o./T n]߹Htk/pr隄J?i~VmmKrL{k{I)]{0TF+_d@]dEjCzRS('lZChQdcU) ]WG^85 DPDʗ*H-כ 9V,§@V&DnzTt ;7ҟoGbeT?hZY(v S`UG#! ֿ]]Y,=K$o{aִ9n^-h |и|·|HXrc4d2RոfoZnew/_?6N&|o'+92ed֠U 0o&󌛧Ȣמ%1iaٛL&#& nyTUl6kIy5m$<::"˲m|8A8ohmZr4ZQKõd7xih{%:m&Fǹreg()cQ`<<`=u-MݠuRゐ9kE۶,fk#i91b,DqKA&w?%@wʢ <,gѽ~d{SN9><M]CyS#ʲ$/ <,KQAg4.a(G#ONt[!~_,,˝!ٌsf]o^Z~zh@7"R];d1E>] o[~>f$)uLpC[:w}ۓhZPVjjkk|vPT4l~8Fyݜ]/+}iR%UI'-!',_ueVkk/X>cp}bd]Ȇ )C]/C4·Ny3B{_MK_ ʾV)&h>l-VkLy6 (7'HʺYlG%3yvbZ. DrՠL~ʃ'g[MOȋ G{FL'%B92dyIL ` L6dQIYFR=Rhtjb! ! rqqrd^WHBukĵɗ)yc ֗ꁈtm;>LuI;!UmFDR0y[ gR85a#lcͣ.桶y)_P^p@U?Q^I_kO#p%`Cm^{-Vp&KgY&/q+wpϾc?'-FA3QxC5g<T ( սjZPJtRt φ&0Zi1Qf8ѡEiB8@d290< %*)' DR.ؒ6]k*J ?cBxqxDc@twO)D]{+=9Gzš}K^WU*,7&,co`G۶A9?=C|Q6'/,m .hYPe5&gƻSϠZ%㜓7O)tL9.k;K}cٻ*$ˬR%J)s, u]Ãx}1u.ш}6ZfEQqǕA@Oy|[WKhp%KBōӛx<[g3V6qSg̀o(EƓN ޺c9{wa:X(cF8lJv9,Fnףs=Y1OX+f=^UGH8ΡGbrWEɭ*j9ђuUU5^eθ(Z}xG|V3,6g4?e2Ӽa<QL=m`4q|pd2i{cVAleYrxxx iΊԽY,GD...X\rd\RUuY Aj5G5mHiPMT:4zg JQaCe!ж[P%.F0%gQ W6Kw'`=/\>\}s.‹*C|_z._}ZkzysKZ 8'sUJ-$cs/$!*>n%<5٫2VPBBW`T0 ΀0G϶SbcULUhѴkPFH<V^5xxS85"CcNg e/"f b8 $+!5n:j]F4$gHBl䪫&y\*4F.a mX4*+0ob;ؕ| {\ހ>]]& qOW5ONڥ G(5ɪqJ@yq SJ565'Gc@ ִˏu3˚ dTI Qi)JKiK>m\g2ch<˸}VёGk!oܹC4m1>^s||h4b<s7pvvњx GGЕ 5(6)?3 i[ںJIpGc yfKG䙉8RRl (=Mh(16+}-Sy W PZEKXrea7f}B3Teؔ;dOa +q襤 4夜LF!%|LlS% ty/Z՜jflG@P%y:\<8q &pd19GdrO8m,Y%yV`"ϙK2Y=>B %0  ł| AVDL"M+!gADHTO-@jlGN gR!l:;CPd;0y{{iWWBA`/p5sC'(./{-ZK#Uh>|J ǻtȹȻ_p7$H0׺[0Mdv_iS[G.Q:P_ ]Fメ DTFvT\280%Wi!pDp!_:mp ABc, SVt D Fv)J׆u61L <:+yOZ 2 v2=U>f8YUQ>M.}8:xlWn+go?.UǶB6Rd0YNnІrŒZS4"˱ڠCbmtZrodQy*穝k0e]8ܛptXOY,6ma S֋5ѠEKQV0-'%]RK|aӧ|;!x>s&1Ѩ{{{"o[o}O1#2<|GG6m-IRc d1vڼ;݅">hhmh crZC-JIcnV`O &yyG0{1'GsV)V3[2mɨ NGDf,T+<@kC߯ux!=Aȼ=6g\Z2) Q8,,!Ӟ^ugӆULaR(ޏ~ºlcB4aRje(1Vdl1) eh4"/ ֶ4 PK@텱 TU|> #2\D٬RxL]ĩ5Mt kk d&AbC@AO&KZ{S$/JUk4'/n˧{(t[fx5~ˇ/nr"./UWl-Z m"׼w?' Uh6дD;hz%,uWRÊ }sic,1at:|Ū=Z\L)>zE$f~I^Sv}gQ$Z`NC,ω]٠'1uq3:>D%ҎRO5>zɠ$h OImklDܩPhQʀhEz -sYtf1* <?M6oȬaLNj3,c ql|)mNqh]zm+Rq>{oPL00[{֕ȍLB%e٪=/jJ u:f̖uh]|ͨx~Yrc4WErX֚V[Tay舽GLe~2`}ܑi[aL&b۶ܻwlƍ78:><.E!tk,hiNeف (Iޥz>Q}Z-L6B&YE/΃{ڶn[ꦡIk9rL&9'AѶiYU'HPꩫ3 Oi[\!PكkָnM4D^~|vvF4t;72I=ꪇuF[cd8ehhJg+{gKYϽyv~JWWÒL # D<bfp`d xb #ل% YUۯ{#3燕U{ӧuBOォjUfeeUw}ie9e(Õu#Ϡ@;Kk '֒+,ػ=صho82,"cVfʒ|b)VUɑ*Y9KY:zG9z,Y+ﯱ۞@w dQ,vv9i W?]3+YM]W̪6HU&2yS{#]JUuzvtoLS A8舓#cu|zuBߵ͚jE3kZ^iH|(uM]qKa1UşmxXݥǗQ~J~w6WZ*]WWWYؘ+ ӟ B xXP^@ agshUt@H38햬S VLah'JgEᬏyvΡh-:#)[u Y<. +49Je@Xy^srB$M;wp|6쌾)aBJPk9:>fyz[oMuTU͛7ik<(8>>_`d 1gN)Sx"k39wQ%3pt|wi>+ELBOugd׿y;of;33-PX2gh{Kk3Jtm0}Go 6?S# B802 yV@~S_3AtXau9T,]ӻ T6q9Z(X"΋:2ϔ#Sp߁ƒ5={-ή΃ Ƃ5d2;bo9(p!ukƭ0ݒ;v'8娪|: l 7$g8HHkE^X  Fxïן[˲Ờ P&E!넱TF8mOsJ UJͪtL*ͯ*@C|[zR!QvPr8cᚩ}• bƸqfsuzȥvACiP1}vHmas*p V*I{Cײ^z{[=Sedư@_5 ymhCTagP¼UE (k {f~YN6ϫ<8>=_^xCheg%>5s'.6Z,x@WqivSUℭV+syb>,Z[\~,9>>;mf+z IDATKQ,KڶewgOrxx5ek4eSW@g3ϰF2urf ֢nz#lNiCdEIellb`ooݝ9e)YuUP9UU{z=S\F:׃O$e''t0NOՏ?C6cȿ~fJL_Y,w0vګǴ____;>8yy2-}&V2KfݭM5}/,!H[j_4b>!vhT VZO+e2>E:U br+TW6*A XO֡~^v'Bq yZeU"a9AݎIВ$s__Y"~( SHgw̘ji \W짡S6Y/X8kd5-:<|} _ӛƮ%f4(FP̘wVЊ3œUɓ7`zI)r͵ks~*˹yxvp>}_{|1xJ垮X9EVT,vw09#7E_yYTBɬ\~f?Oc(Ckڶe\R%]s|||kX'ib/ jK۶ ZrmɀS޾}AkfggG8EI^"sFzGeUsN ş=i]:AC uGcs4]&:f Ng&C9Ze. Pd W洕e[LS-f\?ɕsz3-u8=m ,u!,KM>ȋE.l7]'iUmiۖӓn߾e\cmAv -zP-±SâdYsN?:X,s4yAY>4 DD4JKe9{k%+r)jbׇB~{7-)]g &ϲyWݥ!nK*߽'C+uSy]оwtO{߯1|3Xc= uTTz5//u4AM?3 9( W:d3gAsx!KQhyy@@ԃ jC}u9l=2hRz1Q)?[4ʅpFi#3kp_t| CJ~;xXkѹF j?6T6I7c{2|k] 5]#KZ)V} Ƕ -g:0-2S#S%7o>Oqn˯~\iW4͚Uo8o,[z.\;2:ǯ|[:}?x Dd6몪N7 H2MC,K>3E|i łB[ڥby*N3=eY #|J\%2w=8" S6#3f f51[]Vkus/\KKFdD9 q(F㬢k;L{{!yꙚ ΋ZFnfPRuL^΃UC偔3dڧYdHyZqZ zAKxt$J1 8B9zY"䇀 =[9,r Z+DMЍ84iYeTPCs(~ %fZgdj,1v:5tN8#Z>9x0S?6@вam ZaֆḾd:6L U"e<Yg<}&O]AoBݴ-mu uCӗZ0k\. Uy^QgF+p7ؾ=]_] WwiéPr0yN"_ |5<{,u 6*y}ֶt}ʾ H  8=2p ?| />eYߤ pg5UU p7*)Xv.ntُ)Ϙ˹7B:)b"?َoxw`HV8K<󌊳ek gSWB헶I׵8 s(k!5E@KAhɊ,qhNOp|rcVUP;2~fQhHs uq(E!DsP~\fW\ǃ6l+ 8s Z 7ʋ!i⏡@**%tkpgo1(S|Xkg<[kP,#_P/`ڟCa=!hJzᮓTZx] yqz ێlm{~hgR>/tE6@YL{GZMOvhiq (ks(yGz5Gq{Q:8tW;1߾CZQW9e=.n{20P3"zuQP 8Jo=eYnlF]הel67b>g-6z\t O0k6x]'l;[:+Np:4hE<}ffgZƀO~?&.RZX59tN5[%bbUxv BX6-_rxpH۴7%v/C s%p̧L{f3^ze)'Gr%倣{Hg63eZ@ߛ$( oa]>G*LAƚX)h~m۶-Mӌʞ~##f S'4A02û8svꂽ(s7{g^w-0' &xp~!S;=r}{Ph:ض}ۺw~i?r#@c(?%`lrky0ݞ犾g$8~^Y뻬W ]=cPhLJ? dTRɤ>*o%Nq =W1^{#)`}"ٚ|*6ӋYӔj%Pk<0- " OQZ L8n2D;'T^Ϡbn@*CtҠ'EC'|h~L@DJθY˟+Y\ K9&26Y&,!IW+&l] Bt~QH bb}f60+(NOOXUUEjLgWߧN1L{CwPiYt}5s(uAO©$Eg1[6-O=?bg|`wwCb֠h$02tTeI^Ygsjԛ'7bIʈ χqpދO#a[jL*>=0 kmiXVܻ{'u9K,;rh*yW#~ ۥwkG(US>\c~/`\V___ghٚ3Z/C.GwY-M;s:Κ( JscXB \%"ΰsQHTaAi &=Dg"FBh xPr\,ʩ8Ez?Lѱ, b-ַ#M1 ep8 `xgϟil;ŀ'%%f{8$%d3?dJ|c;/!ru~yLfƞ}nQH=ߓ9f:EfRZi Si\__[`c>/%mk(X{q p? ^GڿG:{ XC` \kMdIn99=]q=V]KvhuǤ/hr(u-N[RӬVGܽSU ƚg E^m0d =p8熔>?']>w?l`a@|aL/laCm3y3u%eeE={gĿo[s/!dJ)2HyƁgdhHi \N!gsiXJ$ {Q{*alcfеi,?9eBpd 25K0shD":FdYw]j!0 ?e'o___gbO8H3~G31nU m%Ru3!qTRUa=!ǰ]+5^)EJ4^\SG%(RWVfg6*O#h~ *M/2!'EE+ G203G ݃'O؇D`NlrX(P~PcN+*12˔iqFX(EG gq 1-g=7gXN`g ZSr÷&)"0899޽{#y u~O=V,GNm̏aJץY5@kHu" 㬄/p_%G+ 4UVD,S,%e8ڶHySf9]g:K+^x5fnG!@4V[$;z#C:RH TxN9k0]:zy&5͈ur)Uwh(-VQL}ahC =z J$ݵ:zX*;9]qt\j{e)੊ `>m꿏o?c}|g>|>g>a^.^jڶ{wAe,#U]ה!u=( JzFUWWF!4$?ϳE,zz޽{ܺu^wZKe~fS|l ? }8|Ow]ja BX}{T{#____gnB8gL Iw"tqpR;\.轫U K/jJ8oGQ"B0X΀,YOUo)"2]^fֆڳ[8;$,' A43c$>#s0o"]?Q24oSO=<#9x:Q2ru,Rkn`#ƿYc,Cv乎R3ϧUf+,6ƆŃaZMɽ.}9N랊 Ƭt5]Їa@G>cY6}cYcuh4 qbL+}fMٷ :|iKD] ΞmEi oZb ZX.ޱ͖5ʠѶEӂm|nȲ 5zkYw=&ѨPdEb>cyrn}kS;,1]OVtԋ]Y+2劣;^E]TEM:&45ئ!8 CMuw}?rl3?3 f]]Ӭ,K޹#aE T,J@|Z*$/sURf5<\.R`CB9}[n֧U7sO^@cL|ޤ©0< ~H!㤟S=~:u]RxvAx&=oA"[}G >g@\R.hu/h; IfX:#/lMyF"e n.}Sfw|}q'R q|560jq,Y.}spu3}APJɬ)B7Y BVASC.@4)h%V3(n 2B=͌Ũ>z+qXV#Mi=cƚ~/;ó{x29Kߙp7g_O)zAt1r~ee\~ d:amۜ@3\.{C5|GCR?~MY,c1 mGSp0{ΆyYEQxxLY %p6ȑ:RRuN@os=5=MѴ 0PYݭUtv2Ԕ(SINg eÓ7w낮)plV)Lk" \2(}G5t͊fYt-۷I_ IDAT5EQ晿G%Dɛ׸{tS޺w%J)d>sI^kz29Yޣ=V͚fѬT]ꝆL+2tsrz4y) tnKp==]9 ?^kEo@YPJR`EȲ΄=a`#? h gP>qף|x`-1R!Uc[ NrbK*~8A h`daUӾ?evp$dCZCȒ>czk/wYr NBI]{B?3|Iכ\? kGm4O:Sr 7GH=4/U[fM^u-O=7eEEѦ'3XЬ׬+u>z>ED1D`Nl˺!JQxY)$ ˔prrrsՎ"/SN\ewpt51!,rBu1PRkej`zUGK[rΒksu^~-9e]P;H Ca}ЮWm3^?ryʽyݹŬ,w9:(ꪠ*2ۿw?s/79^usR}Q0+UE>SPӃcH u}qy򭰟2 e 1_gww'Y/Ef-¨Y^xq^vEU ++Q$S> !&'/2\J=K0:xxuOhl ޼9b_x^ c☮ Pf c#]㾺45mFMڻK./ vy i T](>lWW߁ֈk mBv?qCh ik; Cj" AW ,Űa0Pa h-.u(_D&rG'Y)M .<LCzS Iu.{1h6xN؁z*,*8I{< ALrT@PA cx8::찁T- h6ZtK2nXާ bes f%viݶ_}\bwwI>جxg? JHcCD7{OUm]D[o'}k|%^Pˢkd6FNgB,7ѬX7 G LgOd vlc H`l?ؑ a_W^eŲ^X.j4MrXXN2d̒ٞiEfh'ДeN],Jrz gycib>/qݶ(5NM ]{g_n\rttUUbcj-<ttmz8=r3>:SOo|{ǧڞ]srli{<h]ŗ"h,?cA8KX H?oul / _>g/30-gW_}Ys|ȴ0"2˳(__#Dt8Y|ZRf57|2^)$Nr8_oCb}\#~?O&?tdlY5}vu]730 qVըv'$}]rę*Xq',ݴ>Wg`M^ `Ftl:~P (_6[Y8PP~w hrF@ 輰0"$K%;䣔2HH9ṭ6RI23(""*yfn3J և6UF #DEoxf{;;opg@Ϣq^<Ess>D! /p0 B]㙔470$h3ثwjؚ>5?17Goclc~햰} ˔sMѸNfX f*,'Y_q6TjJbٌ,9^~5Ǣ1JcuE ͺaP.sZL*>MFg R޼7X%㔶a@NX,OV9zLUUEfYja <{59L3Zzcdh9:nhZiEEUf6 R~p:}Ͳ Py^%kLYW<38%ܠaۭ;'>8DE& Zg /5*2_5), 5 m7HjQ tzpd[`4ʍʴEk0tUkȲ<\2r[eЄO@'"AXY X+9 }IYHLn:!٦p֬?<R_|Wiږ__YhVwj3y f{^R>}oh֞ZxLfV0Oi,`#ܦaFkܼycءXV\X.OtBEg9I5 ]&W(Zd͝K^Xuu>ݭ32m~U|VplX.[:{,Ә޲X%0SKO/o'>=o߶UOߟ1O?S6kzBbr0ݗo: -v^c">nC(/w Pu`oub:],{8azP ,!"DZeų=A؈ST6 a\S3σLٶФP 0/ltK)?yy]RWWWWWk4{`|/aA.e 8S?Xw,Jg؉'J Rlz5J2< scX,}5 3[UúL?ϧ¦>yL H4 B (Ls!S%s9==eb!zjim vA])fuAUܿ-]^7~YaXT:l!4;7 7y=g6F]e%q~_mݒrҦA\2?x# ٌÃC޺74f,wvi~|_>Tc ~ń eB#R@%9R#O"{\v!: 2A7k;GAYJa^$a@8K-]Yv*mkT[HS9& c"by6Eam//kޟ_Xߺ'lT4 ?qѷo~zchg>B1Lx_ YzVQYK/O?EUn?ؼ'4h|h{[c\Bee޴jۭWW&#Qoq1f*+ iHEǹ"ή a^݃G<+J;yD@ l%̝BV)'ASL*PfY_1Ȁ0UP|qGj쐣x jJW 뤈uS:j7;0>yvvәpdJ+;"T(fZO20 & D O`i cpP-1ٮSOOMĉ@=ӟaX_t𘄻D6G8dن? 3*d?8x!k1cK?,c<3;, ^ 4ii5mӰZ 6Rcr dl=mmk)2-Df> @BbZMc0ƲZX-W\.wys}˥X{ts>9ii,%<{kl;O2pENuF3?|`>Cu 3ib*᝛Ag7dyN]D$ ^6Sgfc?n~uʌz.++++pýMc`#QX0Val!/ CzQ4,Y;{|ю1i1V 9%hc%B 9Zkd/BB;-!t_ud:ZYhKp 3N4~ mLgҝ3a #AgD1!ѱ5BiLtI.@j2$  9Np*>RBtQ s(̀[xg߀Jp?xJڄ2{cV;&q>p$aLn[g' Ч>ZܦDK`없τGuI.^+aG:L?5>^/iuPUg,g#&H=_LF ?~hc4;nJE)U4֥ݝ!0 urjjDic`z|C㬣0,yYK a $h9zcp^) sC9v8]oӶ}w}?0j_/βwg:.V?aM[X/, ]~'>5c|h |vL2Ac?n Rˏr%Ă3*~>JXnpa+/& 8IᩘZfSꯂׅd,ItJy V9%hE*l n\$ /jBWuA\S"U*5О <r^*u@c h4I#YdNjBF `yNSƽ*hX\ Ettw0 !=)gjl?I6?8~rSa "cX>"R.YoX?mߓ1C5 SBW՟~h6}i'?{xY (360>xJ~wvמ:}/Ҵ-m2_#QffsꙤƭXkXִmC۬=Gi =K5it F`z̏s@RdYA7:i$Գ@֬V4Q}oX.d)ri^cPc(-$ ˤ}6a y:oyܴo)Ow 4 =ϳ]̟Sk,} mCe@ 1tqBZt,XǪ0A-mC2vT#G>5P,, 6N=s9_Gr'_?Iex୦K ':7q[ZAwJIQj4ꠧ![Fjul9S.bqӝv x~qJvOoؙ|NDy@q FiP{9Δ4IIۀ_EAiHJ` t1vf13dFö"s!׮믿J۵|si[pN@Z2fbƛoH1Xc͐iՒLP_AR vl@,&H@# RyO.ntmu[ϻQB^Ӂ:gƺ-C>]DZlǣem?veee!{=z c a|pFufmtx]Zw_QMӉSւ؁ՁӒ NHG&Q5M߷E&D}ArqȲXzkȕ+1p'nn.H,+ZG; YsN0Lhbg 1%Й(My6sL~_\%ć2(B[ ĝVFFa4q㯥^4(uс47*9V ̖TWB Q*=WA>lrcn/_+xz8a0lxaܤ1 sϑojm IDATB|3}eOspTr]]fG)G%'tR?z8kןm[ڶ~u-Z뺦ͨ3H[aCHMY7|}oLb`z!ΉzݔD@# yI @>YvmC5[nq->rk.o1oߴG,)Xs!{ہ' :kQr^i`>l<ښ> zz,FHB2Ixql۬&Xe/,l!-hbHItOw{]g떾wTׯvQ+k2~k챣P`oOL|{||jk_ృ˦o~M/K_iIZn1 ;r.Oo.JdBgDU<~6]PЃ(Ec B%Dm TJ$ , AHLzr9p6ps/Dݢ C/QB`J ZVN!ƈiB&X+&N39gyϰ%{{¸_[[BDF .hg{թ%nF|f-PI`v>7p7uo |{nH:&h /#;+|<¿S^VlvSE_ԏCKOB P'3>joL^(_W~{w?wqDD=?; G}FAc+wVl6B(m&v6ttڶŽ{%Drjlm'1D9dҟ_3mHs.;.gTL5E_'|$Xc|Ll/O=6 Ӿ@-_fKT? }dmsR'1L! tc(By`31~(xzq^]’s_:P 67G,c i/5in)EE=G ~ol72kpZp{r>p`.}k_[ZѶ+c1FhUH:86*B i_*3cf|O߼au[Oyy1*oћ6NR_Fzکa-P7hzիd9SiuoS/~O?QT.lMt-&0''kWk9w^"7fp~a9Ǽ% 0[C<ϷkUVxD(g) \G_fF# m<N|v`#&bs1D ( h10O2r"5(E՚?3߿s4jgʼn[#I*LxƳHac/}I]Y%׼eENt_&Wm2<}v-}8ox#y7?Wwamo:XN5''h Cjqv>@e[ zg2M?۟Yѻ<(?7?DdQoϵA?vGᏥ_.y~q?@* ~/I&D:D5uH3p:;ƣFj%>$S=޻7?ʯGz&X" "&DFvHMDT WBSbnKCy"FH 3酻H6%~,'j_?g==Zt;184 ejX4"H>Ө53gy'OAtRz"e1Ϸ\屍'5_I³'}4܆#4UۀSH E#|3 oz{'^S^>i2 u$ !Gaը:Wg]ׁ@XXEa}?Ľwmv]e]BmÏ|@V1xf~@ _`ZpAHB)tä4O EU&'>iJgm_)K@wү&co~xOy4oeGo%B{NƕF>Kjڴ+G48Kos>p ϴA_FiZjL}~a|~sTw_ ~?6op`R|/N+I d-ZRjCOA?(U=p VZO?}C๯zTTX8DM2-D|U4"8 ""b1! a'f'ŒA#ȴ 2?%ٜAd55{="Gd>9,rb𹤂,xp=ܿ0ZprrA=~H,zF% 4y(ڨaaah"=ͥy#>+mA\2_EjmfrWaFB CzIv[/Uʯ'/6f?'RN'F*>']7_L|_Z.wT]B +t7XY࿣w.x>lHwUѻ ,ԘgTk~_sw<>@Dto\_{cvb 1+ =&:jR@'<3Ʀ?dy>ALG@@ zEwý{4-<^_`HFD4F$P VD4$B8@ 4"#Ը 侷(RI6[9i_&@1yl0E8V1%Ĕ$ 8;;ó3 m[6Gų~du@K+B4[̇pQպAoeH=&TN?A> z?D1*Ge~Ȁ48u̳$ySWB#'׼eI9d~V;Lρj=2܃CyE4_okÉ?v^N{st^9L렿o?>}n) ~"<@ n5 #&dƴLgPL` $}BlҸ`V+Gcϊ>qx!IGn>4| ~?l_.s9bCCʶND hYH_6 aPDmqrrIAx}.Z(mXa#ЯIP' @Ȗ#"D09dLH»ÀJgLT q9p fڢH]vw޽{6]i^^c4hB@h0SGg[Ѵtv$଍a~]bȻ6L6k3FIw-_2CFkoj"Qz% IDATQ`$z-E yb8S]dzyTHt=,46.l-Ps) ?蜇P?}ĨJˇƾ/ ,o_ ~.᎜C2C|jXOfw.X.$Sm} l!&`^#i(̌ ޻׿ _$|-=!@UI8DMԻzcn ԀU4#g WG|qOH|&Nk$Ս(f0&#m"aGдk~ <|4MժM&'M#K`>CyY+,~}$[3A&}{OF4iLA5ƒE?*`CMR7>;_{NgsM{/i"B%f2ab~e Ia O?E H$M (ύ񧘴)߸Oxy @}9X ǧʼGXL N8(d.'_}*Caqf2'P;uZc>"u3cuNfC"SB_ \xfRqY r6K)½ ||ݗҀ1?)gg;-Х{<ɗDu7Q|_7]*[`$~3(m@0д-V*'}$5GD?DVM[BFIk{RA7`uY((C QЬq!6`m44vQN )紁my!v6 &zkF۠h0pMQjH~s*g~͑x9'‘h)5$\!1oL#|STCϨ5^3EhCS'`ZOPJ,r;^;秿o?$ڗH-vt9^}K˹cfFrtfTWLh*͛4 F|϶?R߶Ɵ5v-e|s\1I [~ 6-m| E 0PBoD a{]MsBfS㵕- 7k&D#;w0Ĉcć>k;$2O~ X5 ">!( "FK!VPnL&bT !@2F8Sh\yD]EN$"$C+'ݿ{w'''sVMӀEq "ֳ?]'U )OVMM㤷p(0t-(Ȃ2FWp3pDWcfh }ߟjAu~k39t47!djބ{?%(k؄mbo30{MUB렿_ x'7,2?)uNξ ^[.wKr:1ЖƻW7dw<4}MOHHGOf˭OmOKџ]% ~lY6-1CrdphY|HD=}aRgAsCaD"@XJ 8ݏ1'7x0KC0pNb `"1XL4$Ō> A}d UB0Ɉ4I@ oԦ6=y@DٟܿmwNOZѶ-'+VN|5@&NpF4j@v/Gɢ/?Qy?&X-2?U߃d+}GȮlLB>?y1ӟ/8o̻F9kc*f;ւ-Bq$R,f盿?[x,Kn]i;ϤJG:%S]>}D[_ 6'z/ b2?1GlF^(;~*ZS[T.pH/-j%OO"G?8;;Çuݻ{_ 0tD~0|9yȳQC9:Ĥ:b\g4i[Wh,dki}l> vONEۦ2l[.r1[̧n|>܋sVb80NO(3]KF:a$k@lD;(]5X?rJ3#])5BM@+-\Q4I4*g`$CëdkW^OeTUv?9 nҳ~- *T1U HR}*+mn ( r/+SmLo1v'RM;jJt6̥Y!_ټ;VN4!:/yhƨ4?Sy/_Hݯ,~"\,ޮҿ%xXM ~?boߎ//$E:gd@.R+?YDU}d9go-hNv dFoJN ,;)z ]q9KM 86ȇ?"ZE2vD3 *F`C۶-s)6KK$)U@ E0Çs5+M1@ i5hO-3Bκ'mщCq X=(Ю^[ 7Q?C9 +]?\^K=7;oFnlS/}cppmVw]$6JeGlة*Vۣi<\:J[WĦV>MI#hsL4f0C,UЮ0?N 3#iUknRɮc˽E3ueS),a\'WHo}S# 1&Eo o$O|Ĩ3AB57 (elS lBH1I>\`<6mȧ@&A|bPh->1aC |1bzt}=~~1$AЍ.$mZ씜k>Q "&|!@/IK R:#tB;xSOa^qvvasx m[4ME1a.vJ#EO q{FyXM[X8H9l6ԯƐuHxr\Fȶo^HaGV J~oV\寯I|ubKRᇾ7YKћוcc>OճsenuޛL -m332lyo~g u}K'ő?jaWXvuf2.w>Gk7=m[#[}h\g5GC+iapM=-y$t&GqH)oZ8HkJ8?z"?Ms1O`\-gD0fфhVX!|Ä4ӓlQ:@v5^eΜ3%|䩈P6 O#2a^"$"vYSﮪ~'x}Baua@}1F@$PH/Qa԰?qB둹oZOV=<? b-kĊڵCϓ I1|Yjǒm[iUhE6%mc.\5N*|4f`P$3) xix|~@~5,aYG϶iokӎ+?Sxly|څ⍯x/黗d?o`®}?)<}"C1lk}y c㿐PIY:܋[aŚ{'Kg<]'HVV (n-//`?y$5=+Gr줔ft쐤<2r@\_hP$>p9 B_$^[TgY 6+((1C4mm;^r0|[uh7 ‰D hmd2FQڶ?z-9&gf`ն]BK=юhB򄦑z`Cjﺮ\4% iB ''A*cÐ#E>A҂5o7_>D!D4M/,ɐ5k8|Q`2P귕*˲үO.<;S~f'L7vTi<| t?}Z]|P _/>_O%It;Cଯ<50n+6}nj F#3 ?PL18L.5W}o~机?_8u[Sxd4_ ~/i%veM\AN,#Tp(GČi>N"s_?!Fh"4/3TMf_CS}~~oMɟFYp`GNTa i| Upc Gљ_019ڌ@b❎6mVC.1FVpTO TـkM_l6[MVHxӺ! !|Ht2 _o 3S%uYx1%ꖴ0~:kzy4Ł2_$w_pKˠH}-kGS/Sab۵8νa\޲Ƽ :j㧞dwM瓓롿;:_WM/.2'S} BO='X(!Fѐ=a@h"mc~D?f~$$I!o!d_1@<#$~AS8 b"BYe&h=Dvi1G41`ūq[{/QDFULۅ&'Zf Ѯ̷-FBTUDU=~@l[PCV3Cs@!FkK~|).ZoZ^.S3 nyw_i]{~~ Z2Rd+W{_?=}rMwE?vK7vڙTrS2i'omċ_2[i5XF~>^N<_#}:,[o# ~<]x>Pe1r6 '颱(7DџLDIt@8·ӰD5 4VmwJ"~4 &G܊ &ܰF@0ALRg(g!!Jb(No`iO P $QL1b#U4AE/V ¯+??43*0u6\Fمx MԶ1r/alO~!vR&!'&?ӷ}Y^(O /ANyWS[Vt] g_?ڠJQS7R<{5{܅w_<@ ~ 3ɦ4svVSql_-$ߋocgᾫ3 f>{\~>|ً=ޮ[߫~7Ox_ {g|a_wuo"!;C| 0j60ȟxſJ8(DYDDC6?!4hh4M׶ Тihb Nl QQ!C zJB,MhlFCd>&igdH< YMWXFRdjCI$IOjW0.j*Ìg?sy̤jܹP)$l=a8tУ; {gC6=I:=C;V _5_ cFȱ]f*fhdB$/; ]dH[,f0fg(ARkhE}46bmc1 =0]3a@z 8Rsϊ/Θff'hsyɮ/5/_ Hg)<8Rޟ {^]L랹abT&Q -'Z)|ܡx7Nω ۋO>pFg/o^EiK[ooq(p] (bG?ճ|u ZqA7]>F *N>4T ƈ8Xkh!؆:5I^m8Yd}S^UCU]pR7F:f#mQiZm@´ 8B۪PB$)Dl`YJXꋃĉ*&L4&mTS}h2&/G*n#fKeORĮB]a6tvOK53~q\n겦Aie >߅o4ϋ? Z#mТ>{Y'IH'mg[UCu߂ {~~۾qx IDATo/[5 O7tp$5Gu"ޖk؃жF8qcW5-#rа#bZ?iZcs<`<%āxX=2^R! 3n٭*!s $}S{c ߮"m7ҿ͕k?;w:o%^]q&P~LNΉ?N\_~E_vEO׏A867uS!Z V>$p(^KcծZɿ)NNd}4Dxl )G> ('.-sըID(vFJHR^82K6ӎq{ZE YNh?\ &31)@@퐌buu/ Cߋf#!P03hpe$L6~gZ9 $ Ikc"75M]vf*rm=2* LL/fe%QzI3?~_$\cR|ꃫo.sބv3&{,ɥ6fO|emux]wf>7n4:n# ~_:\C_:>X 7gx FA! =(M pori \OW~ߍkr8//x6iAG@L)H"q9Hȩly"B{Li=!mGiQI~=Bf. pV^H< YD&`f"-Ɂ U)Ybꋤyaei&O#1aŒ_o4 _o#4`R),!u9"R/X?as^4,V3Fs! +`U+J/k 5{f!bT*#xѭ+P c?x\}>1_s'~Ђ$cqV-3A,}<_ ~/-M%EӴM~1Ctm'DZT #ǚWk|; q2f ßt "&3# XH4Sh'XYlL_LH$XCڊ8&!4AG)|FHIEXƂ+5 i:/ xg[>Һol쑲Pvál?/Eڌsk^󳢑FuY¸B̜h ?߼SUiL}I'nH4o4GߴzJO%os#ʦ[B;*\ҋddY߿)*} ዾ*޴In@f89ҿxZJx[߂y\ ߃w(Kb*9FcDKMc? xft o/vW] 4v w9.".BwVn7~|33ӿ.'LÓVnE 頼@ )lT.њ0Gʾ6|` *5\jj[|B]¦ drG~DktBǀ6i "$ yќ8H9NYR[$!q}l]DQ 3ˑsE p=,̨S;A(k}ysO߆ŸD#c㶴8Zi=pcΗisE !Z4҈ŏ?Mz~;,[O.8'8GhΧ-ۋs55ANI8/X{ku^GS5_׌ς_𗊟L^}ٌ7hC @LB  foۑ|3?HI~Fn DP0WMIˎU-]K4iHú*$tpu`dFbi+Y<$qN:03ڦ #9,-o&'?@:awZ 0` nw xn:^˟y;Yњs M>9AEEG}ǧs<О 5~?Jz}x}I%/9Ł+d  p@䛆's~D"-&Ls"p?Dx'0 E~/鉠o8)7d~d *_E$Fi ~CdtFCvM2G9ۜ  |oI )9FvA 6fSF/4n V 6lril"`˼S}BҜ,['~/- }ڂtakKbpo*k?oB*_;AyG0M+mٛJ0|δ&bR~t8U\-֊af/o9:'~DH&*dA>\,hC=^[MCݼ2&^+< y. uO+ _N5su8v SK0uJ ]wGxI.d.Ht#i9H-_ @td#ZR4 X'prY D ME$7x*/\֨!1_}t6W^FbgҀp9xP$48Wy}T.|@][J+㲋״< jٟv?`Y<$RVh3S`{tR 0EsV༁g ՀeH7BeWVLҘ俣jiTkٺ$IE%\ ϸc:o6})4!POt}Ma3{ xBa&W[3mWM^TmS.SHU_PU1}2OI5J D̼4@`D0|+޳7C/U DÄ+"p 2Vc"#bVa`BMO,0USU!x!T#31À b`$$"߃o:3[ NubZ`C U>26];k^viͦ]w-fz_*]}黷~mOӯ0ҐȗOavU~BI8f}I%ԝz'P/jA<“g*TCҿx,n@g&SɂxY>8DyߊKo|msYnZ-ۉg<$p()>_V}yonm/kOÇg%tki#9b/Bu>'LD}  z/"CN˅yIQ*5(Ӵ8E$I3A;z_Iih(VGمuemʎv;450=ƵgwsDjsi6=mRݙ~߮7߃~ /9]9^v'Ze=QcUz1"@ oc+ʛ<  Hퟚѽ{Wu9_?x._}xI'ߗJ67s ďC:mOIo7?%83 ].6sob/= _}w{x?BןuRͨ€_Zg {/wa#3OVH(߈Ar4OC&lc1 J UJ? @ze9J4ǢL7 ]Hex$IKNRI`bnF Dzcj?,F`E'2OFG]Onfs ێM!}զ7>A(&1Զ4]Z:>h_ *v0SuIP:2ťb&oO_ < | 4) 'H}LE/`t?} &4Oh|Ÿz{y.u߂tߚ"̳}3xt̀?[w躈?w Bͧa'Ƥ AAOB`󥡕dr6@Yhꜰ%* a9×)~ED#/ч\Gd>8HP#AD˃Yc$2'_uhWhXF%XVa1)iȼFɜ"cMN/>E~QYu?J_>P%w`'}T|-xMhO=vę+d>^p*?Mԟ{tȒeǘU mmxL#ҿx K/|*,I|sOBI)s[\'2mӖg_&~ 3%L}q>xK7퐩L5AWW6 4!]5+&Il$kJ`0SX: 9|P -[*SB^̸6HUȄ(zZlZ*M Q$9a^|I0ɹL־DmӀP̂uz$_?M;{ИyFmO-]_o6{/' фL@2q-zr(X7''Jxcܾs QU,E㯻W߰q.=f.uٻ[;V-|v珦mфM#BiuCoyt0{Xʑx'&\gyf_r@D!^a'Ȧ+vMK8 Ib17AaF)4ANd@ $R fpυu\F7K(ՅFQ4MZ`%ۻG?7kSFg KHF~JCV0D$!`wѷi}濹ȣ?SxytcvԀ)q\<.,G{s>D!iXviiճauWM>}Noh-x>h\;e܄[W?:LE!mZj[iĩ^TtmspaQ|LD9$V`\5$l1DUpBϑO-04^Ba|KC3YUou%KÙ۸% G!)ڦ_!ߙ:X&iw}~DޑKӼe&D^4w4g~rO47m9ui8O޹_+6 E5xZQ^]cr dUo *\to^s[_~vmr $Ȩv}jD$zs)>NaȪ]4@A'mUBhbdIB5ꇙ@7R᳀b4,HNQD6iװ-4mU0ٔE*kA֐Chذ6 YkilMP:j g+\??ӟo:_}܁ZK{/B!ݗBp79 ?Z0G 5Aߏ1yz=ɿj-;Ii\>}T&xj_ W\ w +VoWLdzt 'Ɋ}/_0~?ϲ7W{Fo[/v24ޠbkѿioIϿ6Ϛӈqǿ_[׻ua}_>4 C]- wIDATF z>|o!bp@Q8~g$I;d<@v"BڑoY Y!R]I;1e.\IK\)$+dL=c%I$#go JrJ,:N%],]H{;! Y޿ /mck2 ٖWп]um=O 6w+b4wo7]9boGZB'_cE$bx/_0~?O"W1~k^`۲KO>R*`+@5Rcaa!95ƺwN4Ξ=ϟ?3h6Oh:t({x6qWRcff&<Ǐطo_d?'r_8@Xwƛo/^o6n7ވKO4HNǫf3z+ uԘSN+U({Ń>>ly/^x|ɓ'ܹsgx={vOlq̙駟>Wz?x#M8uTDD|l6cϞ=qرXXXO>$.]G{'^c۶msÇjEDDwCVq뭷y'x"}݈xgbrr2vG}4>馛b۶mq7߾|t+25fffVtڹsgDDLMMŎ;Ji4EZºVjDDK;w~8xOUxG瞋xꩧ$Ibbb"""9[w}dzz:ʱWg\+nK.ERPh?;v-@]d O`ϝŌwܱcc]UqřU} P%YJ `Kl)25-4S㣏>rرYZ_|qS'p5J35&''cdd$Ǽ>7??sss;tgҕ]v@ݎ .n/ػwoNHՊ(] %fjTAYJ `K*@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+25JԊL dj"S4@*MP+kfjiz-ХvQzIݎܙv]4S/ jj+5v͝!@v.\(^wM @Vå~lIUPVRؒJ35@P+25JԊL dj"S4@*MP+25JԊL djfFr>]jv;bdddsgP`nn.vLzhS'Ѹ뮻djҕq8edvv6XZPuV+""i7PsJsIENDB`pdfrenderer-0.9.0/www/screenshots/PDF-Renderer.thumb.jpg0000644000175000017500000006025610727576075023170 0ustar twernertwernerJFIFPhotoshop 3.08BIMC     C  ," }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?ϋ08~@3(ҿ"|eofm|%pM6Cx$+[0Q'p@3(ҿ"|mgu%χdsCl%) $R ]ݱ-3?ŽWĖ%mzw9܉byى G&ҿ"W4O5O-@3(- S[O˨|)`OE}gwU=IgIW6إzfYǙ}k#LD ?i@&Oisg\44I'>GfO7mp4:475|>'_ZU)g]ILH#}+g'Q#LD M#z?4?iG>@3(4?ׯPҿ"W4O/?ףH ^CJFc_??€<H ^M#z}+g'Q#LD M#z?4?iG>@3(4>op >^#LD ?i@0_%Noŵn $ Ab+_^iB\K$v+TH[;]\~MtkFU%EȒ:@<{ix?R[I g{ROM<,ۜdҲaQk}3M8ԣ-SQm5妧׺5&sZwn 'Qn@?壳!P/LWi x?ƿ tj֑FiYWdav ~ M},??4ד$Z38E@Ԁ>UQ! h` fp?z:Լ#鿈vѼsX[$i5e+\Ex_^I46ez]], x8zM|'6/5#k5, PApbuH&UK31aٕq|}cg9 Z|O_}O#' hisNveC$%X+?4߅ 7T]׺%$o53" [Slg붚n_ѓ#Gs\rm+5?MvMvµ7 :7 Vѓ./Q./V#>&G4~F|MCi? 'G]_G]_oF|MCi?,FO&@^C]R:Nqm%[4p/Č!$_D3otIw.m|codLU S+J2fuM-5s/K^|Eʂ~Ubh n+뛩xP=-o˵KMq'__xV+mNQ-o",chEzWq? ? 0}l%MgmEF&@G&@Z?7 :? X.MvMvµ7 :? 3otI]?ؚ??ؚ??k3otIg0&`24߅ Avµ7 :? 3otI]*:_<iך\wR9]fKb V%r0}DtyXn"8Y@? xVݞ9;Yk~գӭJr\iRogG-N\f1}隔/tX̹Cga46r33V`mݭ=hɾvo%FVY<ͼ2?%BX[[t+2nD. 6;zjr]f?u 5 XPb@)A8#ye(IEp5iSShAI6_4/ o>#q0N^I%ƭ7,M2aL1+}PZl=^̫q}_~ ־*[492f;ko+񯆟l~QǏ6h1/o޿'36t~(Ӈ[]JǟmP[5K֊x.@Y>8ě7Kd0xk-7<׶si7sw0v7p1& Go?ͨs?keҭi!$"H,7ҫmNoqu+7-%e%cs#?+YNbm7Iy{_u%iA='[YrxW\r3 p?x_*`5?%Z.BwaFԬ1}zV?:WPeMs$ǹ{v_z_V4[B/ wg e32U?Y&G:WPeMGc3A "~K]C?._ !U~åu._I$?Y&Gc0 '%+?1WG:WPeM]Cm4a?A "~K]C?._ !U~åu._I$?Y&Gc0 '%+?1WG:WPeM]Cm4a?A "~K]C?._ !U~åu._I$?Y&Gc0 '%+?1WG:WPeM]Cm4a?A "~K]C?._ !U~åu._I$?Y&Gc0 '%+?1WG:WPeM]Cm4a?A "~K]C?._ !U~åu._I$åu.?I$'?(p/ {#㯆># hi\4YH$lđ +dG߲OُC.˟YDX[@r Aj%^^#G__J|j8X®~cV`tJoʍȚFApKKm韧5Vޭ"p9FK:[@끓+oxc׈fuio4idCxr+mIFut)$H+``?3^ԥzY]Z%WUi UCg` )$}Xϝ*2tAZ෕|7L0gIu_^Zf'R[͓o^1SҼ+h.m yv #1GB NX5(*>ͥ=ą/q@ ։~1MVokѴδ:kj<^!:ocJ[oPt)P+3/v]k &9>[[o^nqgP.&^+?LWAUps/vG&^+?˸{t}G^)#G__JNJ|GyH.綒,ax4i_ |.]>VjtH7@_/m2FkM~;zcIhG 2G s3_?c u-Z,/vYO E!yQ< aFܵ&SF3 ӄi֕9?qmJGq%l v¼c/„¼ӿ5}vF`^KgUWw[`&6h1>lciR30J_& y/2?ޟ p;؞5QO9>zu2=KͿHpkd%P81ڻM;:v=2 PńP'?^?_OhxjmŨȑ*0cLѿy< Q)?iJѿR6ưOׅ[1 h>ѓn+T;嶰^̧׿kz=k'|;oþuجY.'OkyYFYxeRʰ]7[kY]LT+I.Y_m;Y79w;k-ŦDM~L0 y{@qּ;V~437 o۽#I[HZK..4*I?PZ'Xү5d"4H J `nF9e<mHuȵ-3'%{Dxn;YN4 2Fס-Mu_6ׯd[I6f@fx@˂J U~[[|Am=`q:kZ-%X>$x>5ִSlj-e%9h 8|HswzjslU2<'QK)H$\nBӸ|nd?kMxi5Oo{emΛw*!B er'ӎ=G z\zd=q:"K^ & 61^ޛM SQJC"ANd,r#c!Mi|PkM`|1vo`i wɶX\7Lb)1zw֓|w~it;fu_[v*. iEacx[ޙʳ Ϝ4|#>K](0Gd zP^ծ{6n80 rEC9FwGW?xfXT)zJaQ&Eh2wF(V?H?Tdr^ǤiqB.xzu]yűkz!i4C`61#U$5z~.u+ QʲZ1M(burw1Sj7o}#PDXvWQ5Ų[ckKwQ=z=X6^}f:ީaIh-!BGA8`JgAJYxŚe+n`-Ț5[Fkpخz8,0 k>LffkdTGuoY+' ׼Dž-dQ52]F[G@%3 eF,x˸|?KXw$vB>1P03X_VTHI:$(餱]8½? ӠkiVbI7/PpT=OxH:֟Y/$C}2=U,5HOzms\?_TL]͗ og6勊sZ"]Oyby^y^"(\򽨸G*GE@@#Jzs5ڴ_|E=G> 𝯉timeִE2l\p,?#é(dR[hoUv/xcQmau;[(m帕n)C^=m.ܕ`Wwm|C.sbc.,itӧAy0P0xMj)A=}c>\^A3'J=F?RiDЮ/6wPjROq\}Ir?vh\]v 3k[ii6R}ix{ K 2"Ry6+ZK˭_Whu+UUKA~># Mv˪[Wp-[s"A9E$)xm)>I| Gkk'd $d-ԮFlUk]|3𦣥GkP\D`0[YD#VٽHMDZҍҩ$Oaa;ȧQU͇ҍҋOaa "FW6J6J.E=ҍҮl>l>\,{\}(}(Y>\|B?Vď-9+/I'+SGljz46>fl-.|FmFK{LĘ!-Pܣ/Ȭ(σ_x{k}wpFsqg^^Z[hK['Ekn탑]L D{ʤ61۷^-,&:yZNU،ӆrkߵqMt9lA08?J3{.- W ƽ/ڛ]'H|'>SI|Qw!DCY" :QʂNj[BQ_)>|9mBBo ;~E|==ԈGf`3x&Xg^@񖲬i4Me>%+ȥm+Y,"62H׷o݁t}'A ]džLr~z;}a3Nos_O7J]Zt봭~jOuyҶu$'7[xz1_kkm$W/&-GyĦVFÚi7wj@3h$n+52Co$fRzk< J􄿓ON}ib[g9UW"/.KЩB2Z2~ў]&7Ŷwwֲiқ7V #f3( v6w?_ZǦjZA 푣Vn avV<2nȩ|! M ^SNGμ1{) hA*@vv֭ͮ3c RDRL"J< ;uAxjSm|=ⷚ?ڭ - 2 ǛЄ#Ł:[º{5yd$u̹봑ӊ|חRx_ATd8s31RIe i,:Y*mUeñgIst4K)>l>saapOaa J6JxlZYT~U= J6JQQpOaa |l6HpU-A/_sݖyyC{B潔&pq_1<1WAgj59.DEi31>ɮ2(?m5;ku;dM9#,lC]bku0XnBa~C+cU?xkFu CVSL.xn8G<8|Cgžm{z͖.N 'ƷƁF%YB8(1Ĺ J]rr_RLuO 0I?no 1Y|'=\U1ӍJOh׶4Z{yvUNjsqedy>xh/}s@)M{i Q<?0<f-oǨk15Ta'^û|B^3JM;x:Wi?_λ|d:%[lxx|2is6޷՞K~/O7~kαvq-V|><%;Ya|QOm0_~}ΥUOՃ7+&i-w]^_X[:-yiu:dUG# &a5Oz\77.즶A I Ib_9!t ?xޛhMՖ;FMxdRWW''=+2BTG&O̼rt_{$Կ_ xJ}N6WW1ZYFX[yPJ q* 3;o,~V?Q7o<2ʹ4J \'4l 2Z̖[eeu+#}Cr U#PUiv1O X|Yͤvij :&'Ļ #ɂiRϷ(եly,<*gzH$~h;BԳ,죵/P`hh Q5#3h`C8ū?٫KZh屓lZ:)) @}K# 7H|[G_| qx {}rYtK-B1Xn[ jg>A샡xO}}{iڝз+fd&dTIw,TT.Sݜ(WXx_:ᶫxXxzI{j$vJKSjmoAZ= W16)l+|B|O2YxMwK0-Um,،l {.h= |A#64 \  g$Pw!wjǣx"?:],(3r3CFhhxm~(M# WՑv ls~!>[itOg, owy^+vC^E} h_L˯OqD-|m$gΊg`LɸSr2Ww|ikdvz]$$w_43wẒF`X kݴ |Bljuigcga$p*3HU?4^|NݯOm6q$R%*eb=5Sc0n7mG>}¼SC>źjr{Ym?Uy[#>:<4Zcqqk~$k^+_o^ lu+qگmLqbW'%<9;bWㄨ6\?iscVr}&~2UŞ)iXj1D$Rwsj,TOe-S? $0xTB ă^!:7M{%˫:c,YD''ZO7byT8AzўQO4{ w03GR  ~5EhōL̨Y6 y$_?,p~oh#Gum}om#\,G'X7A|_QrCܲV4߳σD^LFe g|@#o_]L9m??Uӭa-m|e[Ivim.Gk3 活]j6gOA|1gv @/}K/ ֤أFyjx^=KZ;I5F!ʎ+TBZi9 k[_Oº <HŠh-Kk{,"#fHZCqY/|) O7|5礯ݳ nw3sV49ntmcgqw9\3{>$,wThoMfmA.ȏ#ʁ@K4OjZeu-W\eԃn- *m?Ai8%*p\vG:eY^:}۔#XՈ.G:N4yv'I$I;WǯxP6gm;ARE~%ǜW{YPMzïX|$O.䷚rޙVX;W*bjEdw`5xpIabj݅ggmg(Ķ0*_,f[[YkimK(`" U}*m/EëΚ"{}B 03{L`1q1iYu6cֺ\1q5;L;};/W?g-u;;K=SqL~roQ^5 օLt%[WΉF~&]:+_G`5w4y~ƽ-Ѱzfl8ɤn[[_\HM.mOH/\D;-Y b>eڹܮUsoHD^Riwao MPp2+Lma( FwEjf_˺Zƶ:7ʷYQl]ͦlB1;cW O¿+izz%܏:f5dɵ-Gڃ)0So#P>.!Zݯ$ tтT,|W1My,<=g">]wk˽a QIK1.,]wς3x[|EGHMs,$0LcK1xUW|A4wR^]Lcfʼ\=w2G_ Vዠ.;K$0FmtHX`^'wImLL"?c%-ّwC|bVg~ J@o|b`+&6kK{ffmno' …׬ke|1-9g-:DԤӯ&T!#u ){rJWoXսLJl฾Mmtu-ʒծ[qe s/ðx;FK9bU9HspDG;JYK4R7q7t 2I  NAhn$@:$z@IuxB|1Z]h3Ze复`GlQX2q6$>9"^>eijԵkҶ>`jeܞkN;KO]%|$bSm"|]8;;g~t~? ~=|\:nFJ'QAs#e*ddFFB5fpҋrz++EӅާm5W\My;s)i}}5@[i>w83_9 6p{{[۟[xgܗ-=o.oEj|fmW=E7FW b0wGG$^ǎ/V<5kWl<F9f۫cpW_M{d/ejTѺinՕ}zW? <76ƨYcG9!5^w~/OS_k,1ڿ*38pITh> /??Q[+I/to_;؛~Ԯ93P܅b_Di?_λ|Č@n4Yi_kbG>|M5 ~7#^[~b8+j|]'~(R].KiOd"s"GoOgM+Ul uq}:Kp\5iFF9-"wd#Z-<w?f].'d3")0J< 0ЛA]FZ~hhԡYI*@#6VB66+][߉Ԙ^r(dwހ!«b7mWchZj~ԾzSuGqn*!k/(վW~.5M:Dot 8$ۇ gDbH ٍavQsmpkHg\Ee;#/kOiw,dW 7?ye`[dM2$&Wtc|¤v3!kxKMJΎ.r \,dmF i6dt#[jWͪ \A24Ac30D' c&OB&iKA=Ŷ4{3ݢ-7 G 0zOO&?EyǹKIzA),IW+)(U'=K6׏o9]x[=ݭbMT;grA.ڗKq=$X좿,VuQ5PEX ~7?{藶:D +"n'u”-ꥆ2+pޭv>վ>|MxoW|#wc(Ttei nI 6[z]|5Ȋ %[2MZ;]IYQwtߝoV #5_jK=+w3%6i$`<( Fk߼W与gX젲lg/ڟ0QϽY__b}Ͻ^ |G}GG0Xz~^:sv`xsCQr.um>L᳐<1tSZWBԾZUlזϝAf#?&:<="""%Q ;ےfG @Ɓ-i\2 AxjOhfJʃfuv>#jrǩפi?_μѦ#I:μ#slf\pR>7v$⪈Wg֡ nd),3 tHVSpAIQm=/2O*xgðK Z)wvi2C~_̱Z]"0~ؐr#0oFg5zOuחošifhu_I,y ksT6ٍ}2߾&[3[($((((()p@ XkYa}$BAdf2d*NpkS}CÚ\5ۼ"u\)g#\J%䅙e $І ‘ӝVt̷(Fjk"㯌*?-sžlt5]H6,(2dp>#ŧx%Iq𔥭6-֒r,PmXYؙJOxo[ijԖw?W?(lhe\ELI$,OsVr p=(e1~u?7*I]4}~n?ᢊ>u?7(UGڮ(W_q jh]4}~n?ᢊ>u?7(UGڮ(W_q jh]4}~n?ᢊ>u?7(UGڮ(W_q jh]4}~n?ᢊWgR܂N8-mO4tQM pdfrenderer-0.9.0/www/common.css0000644000175000017500000000116310737520157016614 0ustar twernertwerner/* Document : common Created on : Jan 4, 2008, 1:04:36 PM Author : joshy Description: Purpose of the stylesheet follows. */ /* TODO customize this sample style Syntax recommendation http://www.w3.org/TR/REC-CSS2/ */ .screenshot { float: left; } .screenshot img { border: 1px solid black; background-color: white; padding: 10px; margin: 5px; } .screenshot_container { clear: both; } .code-highlight { color: red; } .code-sample { border: 1px dotted #cccc88; background: #ffffcc; padding: 0.5em; } pdfrenderer-0.9.0/www/demos/0000755000175000017500000000000011622545107015714 5ustar twernertwernerpdfrenderer-0.9.0/www/demos/latest/0000755000175000017500000000000011622545441017211 5ustar twernertwernerpdfrenderer-0.9.0/www/demos/latest/README.TXT0000644000175000017500000000265110725115175020553 0ustar twernertwerner======================== BUILD OUTPUT DESCRIPTION ======================== When you build an Java application project that has a main class, the IDE automatically copies all of the JAR files on the projects classpath to your projects dist/lib folder. The IDE also adds each of the JAR files to the Class-Path element in the application JAR files manifest file (MANIFEST.MF). To run the project from the command line, go to the dist folder and type the following: java -jar "PDFRenderer.jar" To distribute this project, zip up the dist folder (including the lib folder) and distribute the ZIP file. Notes: * If two JAR files on the project classpath have the same name, only the first JAR file is copied to the lib folder. * Only JAR files are copied to the lib folder. If the classpath contains other types of files or folders, none of the classpath elements are copied to the lib folder. In such a case, you need to copy the classpath elements to the lib folder manually after the build. * If a library on the projects classpath also has a Class-Path element specified in the manifest,the content of the Class-Path element has to be on the projects runtime path. * To set a main class in a standard Java project, right-click the project node in the Projects window and choose Properties. Then click Run and enter the class name in the Main Class field. Alternatively, you can manually type the class name in the manifest Main-Class element. pdfrenderer-0.9.0/www/demos/latest/launch.html0000644000175000017500000000050010725115175021344 0ustar twernertwerner Test page for launching the application via JNLP

    Test page for launching the application via JNLP

    Launch the application pdfrenderer-0.9.0/www/demos/latest/launch.jnlp0000644000175000017500000000126311150063427021345 0ustar twernertwerner PDFRenderer joshy PDFRenderer PDFRenderer -noThumb pdfrenderer-0.9.0/www/demos/latest/javadoc/0000755000175000017500000000000011622545107020617 5ustar twernertwernerpdfrenderer-0.9.0/www/examples.html0000644000175000017500000001350510737520276017323 0ustar twernertwerner

    Examples

    How do I show a PDF in my Swing Application

    Here is some simple code adapted from the viewer demo which will show a PDF in a JFrame. This uses the PagePanel class from the viewer demo, which handles all of the details of repainting the pdf in a JPanel.

    package pdfpaneltest;
    
    import com.sun.pdfview.PDFFile;
    import com.sun.pdfview.PDFPage;
    import com.sun.pdfview.PagePanel;
    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import javax.swing.*;
    
    /**
     * An example of using the PagePanel class to show PDFs. For more advanced
     * usage including navigation and zooming, look ad the 
     * com.sun.pdfview.PDFViewer class.
     *
     * @author joshua.marinacci@sun.com
     */
    public class Main {
    
        public static void setup() throws IOException {
        
            //set up the frame and panel
            JFrame frame = new JFrame("PDF Test");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            PagePanel panel = new PagePanel();
            frame.add(panel);
            frame.pack();
            frame.setVisible(true);
    
            //load a pdf from a byte buffer
            File file = new File("test.pdf");
            RandomAccessFile raf = new RandomAccessFile(file, "r");
            FileChannel channel = raf.getChannel();
            ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY,
                0, channel.size());
            PDFFile pdffile = new PDFFile(buf);
    
            // show the first page
            PDFPage page = pdffile.getPage(0);
            panel.showPage(page);
            
        }
    
        public static void main(final String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    try {
                        Main.setup();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
    }
        
        

    How do I draw a PDF into an Image?

    Here is some sample code to draw a PDF into an image.

    package pdfpaneltest;
    
    import com.sun.pdfview.PDFFile;
    import com.sun.pdfview.PDFPage;
    import java.awt.Image;
    import java.awt.Rectangle;
    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import javax.swing.*;
    
    /**
     * An example of drawing a PDF to an image.
     *
     * @author joshua.marinacci@sun.com
     */
    public class ImageMain {
    
        public static void setup() throws IOException {
    
            //load a pdf from a byte buffer
            File file = new File("test.pdf");
            RandomAccessFile raf = new RandomAccessFile(file, "r");
            FileChannel channel = raf.getChannel();
            ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
            PDFFile pdffile = new PDFFile(buf);
    
            // draw the first page to an image
            PDFPage page = pdffile.getPage(0);
            
            //get the width and height for the doc at the default zoom 
            Rectangle rect = new Rectangle(0,0,
                    (int)page.getBBox().getWidth(),
                    (int)page.getBBox().getHeight());
            
            //generate the image
            Image img = page.getImage(
                    rect.width, rect.height, //width & height
                    rect, // clip rect
                    null, // null for the ImageObserver
                    true, // fill background with white
                    true  // block until drawing is done
                    );
            
            //show the image in a frame
            JFrame frame = new JFrame("PDF Test");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new JLabel(new ImageIcon(img)));
            frame.pack();
            frame.setVisible(true);
        }
    
        public static void main(final String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    try {
                        ImageMain.setup();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });
        }
    }
    
      

    How do I draw a PDF directly to my own Graphics2D object?

    Sometimes you may need to draw directly to some other Graphics2D object instead of directly to an image. A common example is printing. The PDFRenderer lets you draw directly to a Graphics2D object rather than returning an image.

    The following code draws a pdf into the Graphics2D from a BufferedImage

    
    File file = new File("/Users/joshy/splats.pdf");
    
    // set up the PDF reading
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    FileChannel channel = raf.getChannel();
    ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
    PDFFile pdffile = new PDFFile(buf);
    
    // get the first page
    PDFPage page = pdffile.getPage(0);
    
    
    // create and configure a graphics object
    BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = img.createGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
    // do the actual drawing
    PDFRenderer renderer = new PDFRenderer(page, g2, 
        new Rectangle(0, 0, 500, 500), null, Color.RED);
    page.waitForFinish();
    renderer.run();
    
    pdfrenderer-0.9.0/master.jnlp0000644000175000017500000000134210725114532016136 0ustar twernertwerner ${APPLICATION.TITLE} ${APPLICATION.VENDOR} ${APPLICATION.DESC} ${APPLICATION.DESC.SHORT}